-
Notifications
You must be signed in to change notification settings - Fork 2
feat: 디자인 시스템 - Input 컴포넌트 구현 #248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- emotion의 as prop을 통해 다양한 HTML 요소로 렌더링 가능하도록 수정
- shouldForwardRef를 이용해서 스타일링에서만 사용되는 props는 드러나지 않도록 합니다.
- 기본형은 TextField - 버튼이 들어가 있는 구조는 TextFieldButton
- (추가) shouldForwardProp으로 검증하는 값은 최하위 컴포넌트 단위에서 수행하도록 변경
- children으로 Select 또는 이외의 자식 요소를 받음 - 이러한 처리로 인해 isOpen과 onClick 두 props로 같은 상태를 제어하는 문제 >> Select Context 안에 Select.Field 를 추가 생성
…ent into feat/240-input-design-system # Conflicts(참고용): # packages/jds/src/components/Badge/contentBadge/ContentBadge.tsx # packages/jds/src/components/Badge/numericBadge/NumericBadge.tsx # packages/jds/src/components/Image/Image.style.ts # packages/jds/src/components/Label/Label.style.ts # packages/jds/src/components/Label/Label.tsx # packages/jds/src/components/index.ts
rkdcodus
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
수정된 부분도 확인했습니다! 👍👍
의견은 코멘트 달아두었고 충돌 부분만 확인되면 될 것 같습니다 고생하셨습니다!
| resize: $hasFixedHeight ? 'none' : 'vertical', | ||
| overflow: 'auto', | ||
| boxSizing: 'border-box', | ||
| fieldSizing: 'content', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아하~ 이런 속성이 있었군요 자동 사이즈 확장 속성이네요!! 편리하네요 👍
아직 사파리나 firefox 같은 곳에서는 지원하진 않는 속성이라고 하네요 지원하지 않는 브라우저에는 대체 로직이 필요할 것 같아요! 일단 일정 상 TODO로 남겨두는 것도 괜찮을 것 같습니다
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fieldSizing은 말씀해주신 거처럼 experimental technology 입니다.
d249879 에 명시해두엇서요!
| export const DynamicHeight: Story = { | ||
| args: { | ||
| label: '동적 높이', | ||
| minHeight: 150, | ||
| helperText: '최소 150px이며, 내용에 따라 자동으로 늘어납니다', | ||
| maxLength: 1000, | ||
| value: '', | ||
| onChange: () => {}, | ||
| }, | ||
| render: function Render(args) { | ||
| const [value, setValue] = useState(''); | ||
| return ( | ||
| <div style={{ width: '560px' }}> | ||
| <InputArea | ||
| {...args} | ||
| value={value} | ||
| onChange={e => setValue(e.target.value)} | ||
| placeholder='여러 줄을 입력해보세요. 자동으로 높이가 늘어납니다.' | ||
| /> | ||
| </div> | ||
| ); | ||
| }, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아하~ 확인했습니다 fieldSizing이라는 속성이 있었군요 자동 사이즈 확장 속성이네요!! 편리하네요 👍
아직 사파리나 firefox 같은 곳에서는 지원하진 않는 속성이라고 하네요 지원하지 않는 브라우저에는 대체 로직이 필요할 것 같아요! 일단 일정 상 TODO로 남겨두는 것도 괜찮을 것 같습니다
| > | ||
| {label} | ||
| </StyledFieldLabel> | ||
| {labelIcon && <Icon name={labelIcon} size='2xs' />} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵! 네이밍은 자율로 가면 될 것 같아요!
그리고 아이콘 색상은 제가 확인한 바로 디자인에서 레이블과 아이콘이 색상이 다르더라구요 재확인 부탁드립니다!
|
|
||
| export type InputAreaStyle = 'outlined' | 'empty'; | ||
| export type InputAreaLayout = 'vertical' | 'horizontal'; | ||
| export type InputAreaValidation = 'none' | 'error'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아 이거 제가 field랑 헷갈렸네요 ㅜㅜ 확인했습니다!
| <StyledFieldContainer $layout={layout || 'vertical'}> | ||
| <FormFieldLabel /> | ||
| <FormFieldContent>{children}</FormFieldContent> | ||
| </StyledFieldContainer> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
폼 필드 분리해주니까 구분이 되어서 좋네요!! 이대로 가도 문제는 없을 것 같습니다!
그렇지만 ui 구조랑 폼필드 결합도가 좀 높아보여요. 폼 필드 안에 Lable이랑 Content랑 helpText 위치가 고정된 형태인데 FormField는 Context Provider만 담당하고 해당 Field 컴포넌트에서 조립식으로 할 수 있게끔 (슬롯 구조로) 바꾸는 것이 유연한 방식이라 생각합니다!
<FormField>
<StyledFieldContainer>
<FormField.Label />
<FormField.Content>
<SelectFieldInput />
</FormField.Content>
<FormField.HelperText />
</StyledFieldContainer>
</FormField>There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
f86c76b 저도 채연님 말씀에 동의합니다~
강한 결합도를 분리시키고, 기존 SelectField, TagField, TextField는 추상화 계층으로 사용하였습니다!
rkdcodus
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변경 사항 확인했습니다! 👍👍
* refactor: Label 컴포넌트의 태그를 label로 변경합니다. - emotion의 as prop을 통해 다양한 HTML 요소로 렌더링 가능하도록 수정 * refactor: theme이 컴포넌트가 아닌 스타일 단위에서 처리될 수 있도록 변경합니다. - shouldForwardRef를 이용해서 스타일링에서만 사용되는 props는 드러나지 않도록 합니다. * refactor: 수정된 Label 컴포넌트를 Badge에 적용합니다. * feat: Label props를 export할 수 있도록 선언합니다. * feat: Context를 사용하여 Select 컴포넌트를 구현합니다. * feat: Select 컴포넌트의 variant에 따라 분기되는 자식 요소를 구현합니다. * feat: Select와 자식 요소들을 스타일링합니다. * feat: 순수 함수 구조의 select 상태를 관리하는 핸들러를 생성합니다. * test: Select 컴포넌트의 스토리북 테스트 코드를 작성합니다. * feat: select 컴포넌트와 인터페이스를 export합니다. * feat: input 컴포넌트 중 TextField 컴포넌트를 작성합니다. - 기본형은 TextField - 버튼이 들어가 있는 구조는 TextFieldButton * feat: textField의 인터페이스를 선언합니다. * feat: textField의 스타일링 코드를 작성합니다. * feat: TextField의 구조를 최적화하기 위한 추가 wrapper를 생성합니다. * feat: TextField 스타일링 시 layout 값에 따라 다른 스타일링을 처리하도록 변경합니다. - (추가) shouldForwardProp으로 검증하는 값은 최하위 컴포넌트 단위에서 수행하도록 변경 * test: TextField의 스토리북을 작성합니다. * test: TextField의 요소들을 export 합니다. * feat: SelectField 컴포넌트를 구현합니다. - children으로 Select 또는 이외의 자식 요소를 받음 - 이러한 처리로 인해 isOpen과 onClick 두 props로 같은 상태를 제어하는 문제 >> Select Context 안에 Select.Field 를 추가 생성 * feat: SelectField를 스타일링 합니다. * feat: SelectField의 선택된 값을 추가 스타일링합니다. * test: SelectField의 스토리북 코드를 작성합니다. * feat: SelectField의 요소들을 export 합니다. * feat: 순환참조 문제가 발생할 수 있는 import문(경로가 축소된 import문)을 변경합니다. * feat: 순환참조 문제가 발생할 수 있는 스타일링 부분을 공용 부분과 공용이 아닌 부분으로 분할합니다. * feat: Input 컴포넌트에서 공통으로 사용되는 스타일링 부분을 추출합니다. * feat: TagField 컴포넌트를 구현합니다. * feat: TagField 컴포넌트를 구현합니다. * feat: Input 컴포넌트들의 공통되는 타입을 추출합니다. * feat: 공통 타입 추출에 영향을 받는 부분을 수정합니다. * feat: disabled와 readOnly를 interaction props로 추상화합니다. * feat: TagField의 스타일링 코드를 작성합니다. * test: TagField의 스토리북 코드를 작성합니다. * feat: input의 스타일 variant별로 interactionLayer의 매개변수를 분리합니다. * feat: input의 스타일 variant별로 interactionLayer의 매개변수를 분리합니다. * feat: empty style일 때 레이아웃을 조정합니다. * feat: empty 스타일일 때의 interactionLayer 매개변수를 명시적으로 분기합니다. * feat: SelectField에서 Button을 사용하는 확장 컴포넌트를 구현합니다. * test: SelectField의 스토리북을 Button이 있는 형태가 기본이 되도록 합니다. * feat: TagField에 버튼이 있는 확장형 컴포넌트를 구현합니다. * test: TagField의 스토리북에 버튼이 있는 버전을 추가합니다. * feat: Interaction props의 반환 값 네이밍을 변경합니다. * feat: Icon의 색상을 별도 함수로 관리합니다. * feat: 버튼형태가 추가된 Input 컴포넌트들을 export합니다. * feat: TagField에 사용되는 비즈니스 로직 중 순수함수로 분리할 수 있는 로직을 추출합니다. * feat: TagField의 상태를 커스텀 훅을 통해서 관리합니다. * refactor: TagField에 유틸리티 함수와 커스텀 훅을 적용시킵니다. * feat: InputArea 컴포넌트를 구현합니다. * feat: InputArea의 스타일링 코드를 작성합니다. * feat: InputArea의 높이를 props를 통해 조절하도록 변경합니다. * feat: InputArea 중 textarea의 스타일링 방식을 변경합니다. * test: InputArea의 스토리북 코드를 작성합니다. * feat: 구현한 InputArea 컴포넌트를 export합니다. * feat: Input 관련 컴포넌트를 한번에 export합니다. * feat: component 단위에서 구현한 컴포넌트를 export합니다. * feat: 수정된 토큰 네이밍에 맞춰서 스타일링 토큰 값을 변경합니다. * feat: 수정된 토큰 네이밍에 맞춰서 스타일링 토큰 값을 변경합니다. * feat: InputArea가 기본적으로 유동적인 height를 가지도록 변경합니다. - min-height는 최소한의 크기를 보장해줌 - 특정 높이가 필요할 경우 height props로 제어 * feat: props로 받는 height, min-height는 wrapper의 길이에만 영향을 주도록 변경합니다. - 내부 TextArea의 height는 100% 유지 * test: 변경된 inputArea에 스토리북을 사용해 테스트 케이스를 작성합니다. * docs: 중복 작성되는 InteractionLayer의 매핑 객체의 개선 방향성을 작성합니다. * feat: Icon에 색상이 적용되지 않는 문제를 container에 색상을 주입하여 해결합니다. * feat: 선택 필드에 대한 Aria-role을 combobox로 변경합니다. * refactor: 폼 입력 필드(Input)를 사용하는 컴포넌트들을 관리하기 위한 Context를 구현합니다. * refactor: TagField 에서 TagList와 TagItem을 별도의 presentation component로 분리합니다. * refactor: 각 Input에서 폼 입력 필드를 구독할수 있도록 변경합니다. - Context로 구성된 FormField의 소비자가 됨 * feat: 변경된 토큰 값을 기존 스타일에 반영합니다. * feat: 변경된 토큰 값을 기존 스타일에 반영합니다. * feat: Label 스타일에 HeroStyle을 import하고 있는 구간을 별도 선언으로 분리합니다. * feat: Icon 컴포넌트의 type을 import해서 props의 type을 명시합니다. * fix: deprecated된 토큰 타입을 주석 처리합니다. * refactor: FormField의 결합도를 낮추고, 네이밍된 Field들을 케이스별 프리셋으로 사용합니다. * feat: 레이블 내 아이콘 스타일링을 변경합니다. * feat: 레이블 내 아이콘 스타일링을 변경합니다. * docs: textArea의 개선점을 작성합니다.
💡 작업 내용
💡 자세한 설명
✅ Select
SelectField 및 다른 컴포넌트들의 기반이 되는 Select 컴포넌트를 구현하였습니다.
Context를 사용하여 구현하였으며, 자식 요소로는
SelectLabel,SelectCheckBox,SelectRadio를 가집니다. 따라서 Label, Radio, Checkbox는 모두 Consumer로 사용됩니다.단일 Select 컨테이너 + variant prop으로 동작 결정하며, Context는 Select.tsx에서만 제공합니다.
현재 Select는 checkbox와 radio가 구현 전이기에 SelectLabel 만 연동을 할 수 있는 상태입니다.
✅ Input 공통
디자인 에셋에서 Field 형태인
TextField,TagField,SelectField, Area 형태인InputArea로 구성됩니다.공통적인 스타일링은 shared를 통해 분리하였고, 인터페이스는 별도로 선언하였습니다. (인터페이스도 기본 >> 확장형으로 구현했다면 더 깔꼼했을 거 같네요.)
디자인 에셋에서는 BlockButton이 주입되어있는 형태가 기본형이지만,
TextField,TextFieldButton과 같이 버튼의 경우 기본형을 확장한 형태로 구현하였습니다.각 Input들을 최대한 controlled Pattern을 이용하여 구현하였습니다. 각 컴포넌트는 defaultValue를 가지지 않으며, 외부에서 onChange를 통해 사용자 액션을 감지하고, 업데이트 된 state에 따라 작동합니다.
✅ SelectField 관련
와 같이 Select 호출과 열림 상태를 관리할 때
isOpen그리고onClick두가지 상태로 관리합니다. 따라서 해당 방식은 완전한 Controlled Pattern이 아닙니다.✅ TagField
TagField의 경우 내부에서 처리되어야하는 키보드 액션 방식들이 존재합니다.
최대한 순수 함수를 이용해서 기본 동작들을 선언하였고, (TagField.utils) Tag관련 상태(순수한 상태, 비즈니스 로직 제외)는 커스텀 훅을 사용합니다. (useTagFieldState)
✅ Label 컴포넌트 변경점
Label의 경우
<label>외에도<span>등과 같은 다양한 스타일로 사용하는 케이스가 있습니다. 이러한 다형성 처리를 위해 Emotion의 as를 사용하였습니다.관련 설명은 주석 및 TsDocs로 기재해놓았습니다.
와 같이 as로 사용할 수 있는 메타 태그를 명시적으로 선언하였습니다.
ref={ref as Ref<HTMLLabelElement>}로 처리하였습니다.📗 참고 자료 (선택)
📢 리뷰 요구 사항 (선택)
✅ 셀프 체크리스트
closes #240