인풋 공통 컴포넌트 구현#15
Conversation
Summary of ChangesHello @jungwon123, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 이 PR은 애플리케이션의 인풋 필드에 대한 일관된 사용자 경험과 개발 효율성을 제공하기 위해 여러 공통 인풋 컴포넌트를 도입합니다. 컴포넌트 폴더 구조를 표준화하고, 재사용 가능한 모듈을 구축하여 코드의 응집도를 높이고 확장성을 개선하는 데 중점을 둡니다. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
| <div className={styles.field}> | ||
| <label className={styles.label}>새 비밀번호</label> | ||
| <Input | ||
| type="password" | ||
| placeholder="새 비밀번호를 입력해 주세요." | ||
| disabled={!isEditing} | ||
| {...newPasswordProps} | ||
| /> | ||
| </div> | ||
| <div className={styles.field}> | ||
| <label className={styles.label}>새 비밀번호 확인</label> | ||
| <Input | ||
| type="password" | ||
| placeholder="새 비밀번호를 다시 한 번 입력해 주세요." | ||
| disabled={!isEditing} | ||
| {...confirmPasswordProps} | ||
| /> | ||
| </div> |
There was a problem hiding this comment.
이 컴포넌트의 사용성과 접근성을 개선하기 위해 두 가지를 제안합니다:
- 접근성 향상:
label과 입력 필드를htmlFor와id속성으로 연결하여 스크린 리더 사용자들이 더 쉽게 양식을 탐색할 수 있도록 해야 합니다.React.useId()훅을 사용하면 고유 ID를 생성할 수 있습니다. - 사용성 향상:
Input대신PasswordInput컴포넌트를 사용하면 사용자가 입력한 비밀번호를 확인할 수 있는 토글 기능을 제공하여 사용자 경험을 개선할 수 있습니다.
이 변경을 적용하려면 Input 대신 PasswordInput을 import해야 합니다.
| <div className={styles.field}> | |
| <label className={styles.label}>새 비밀번호</label> | |
| <Input | |
| type="password" | |
| placeholder="새 비밀번호를 입력해 주세요." | |
| disabled={!isEditing} | |
| {...newPasswordProps} | |
| /> | |
| </div> | |
| <div className={styles.field}> | |
| <label className={styles.label}>새 비밀번호 확인</label> | |
| <Input | |
| type="password" | |
| placeholder="새 비밀번호를 다시 한 번 입력해 주세요." | |
| disabled={!isEditing} | |
| {...confirmPasswordProps} | |
| /> | |
| </div> | |
| <div className={styles.field}> | |
| <label htmlFor="new-password" className={styles.label}>새 비밀번호</label> | |
| <PasswordInput | |
| id="new-password" | |
| placeholder="새 비밀번호를 입력해 주세요." | |
| disabled={!isEditing} | |
| {...newPasswordProps} | |
| /> | |
| </div> | |
| <div className={styles.field}> | |
| <label htmlFor="confirm-password" className={styles.label}>새 비밀번호 확인</label> | |
| <PasswordInput | |
| id="confirm-password" | |
| placeholder="새 비밀번호를 다시 한 번 입력해 주세요." | |
| disabled={!isEditing} | |
| {...confirmPasswordProps} | |
| /> | |
| </div> |
There was a problem hiding this comment.
스크린 리더가 무엇인지 몰라 지피티 한테 물어보니 시각장애인 (전맹 / 저시력), 키보드만 사용하는 유저 등 일반적인 상황보다 좀 특수한 상황에서 웹을 사용할때 쓰는 장치같습니다. 그 부분의 디테일도 챙겨야 할지 의문이긴 합니다. 스크린리더 접근성도 챙긴다면 seo 도 자연스레 따라 온다라고 하기는 하는데 논의 해보아야 할거같습니다.
| outline: none; | ||
| } |
There was a problem hiding this comment.
outline: none;은 키보드 사용자를 위한 포커스 표시를 제거하므로 웹 접근성을 해칠 수 있습니다. 포커스 상태를 시각적으로 표시하는 것이 중요합니다. outline을 제거하는 대신, 커스텀 포커스 스타일을 :focus-visible 가상 클래스에 추가하는 것을 권장합니다.
| outline: none; | |
| } | |
| outline: none; | |
| } | |
| .input:focus-visible { | |
| border-color: #74A1FB; | |
| box-shadow: 0 0 0 2px rgba(116, 161, 251, 0.4); | |
| } |
| outline: none; | ||
| resize: none; | ||
| overflow-y: auto; |
There was a problem hiding this comment.
outline: none;은 키보드 사용자를 위한 포커스 표시를 제거하므로 웹 접근성을 해칠 수 있습니다. 포커스 상태를 시각적으로 표시하는 것이 중요합니다. outline을 제거하는 대신, 커스텀 포커스 스타일을 :focus-visible 가상 클래스에 추가하는 것을 권장합니다.
| outline: none; | |
| resize: none; | |
| overflow-y: auto; | |
| outline: none; | |
| resize: none; | |
| overflow-y: auto; | |
| } | |
| .textarea:focus-visible { | |
| border-color: #74A1FB; | |
| box-shadow: 0 0 0 2px rgba(116, 161, 251, 0.4); | |
| } |
| <div className={styles.field}> | ||
| <label className={styles.label}>이메일</label> | ||
| <Input type="email" value={email} disabled className={styles.readOnly} /> | ||
| </div> | ||
| <div className={styles.field}> | ||
| <label className={styles.label}>비밀번호</label> | ||
| <Input type="password" value="••••••••" disabled className={styles.readOnly} /> | ||
| </div> |
There was a problem hiding this comment.
label과 Input을 htmlFor와 id 속성으로 연결하면 웹 접근성을 향상시킬 수 있습니다. 스크린 리더 사용자가 각 입력 필드가 어떤 라벨에 해당하는지 명확히 알 수 있게 됩니다. React.useId 훅을 사용하면 고유한 ID를 쉽게 생성할 수 있습니다.
| <div className={styles.field}> | |
| <label className={styles.label}>이메일</label> | |
| <Input type="email" value={email} disabled className={styles.readOnly} /> | |
| </div> | |
| <div className={styles.field}> | |
| <label className={styles.label}>비밀번호</label> | |
| <Input type="password" value="••••••••" disabled className={styles.readOnly} /> | |
| </div> | |
| <div className={styles.field}> | |
| <label htmlFor="account-email" className={styles.label}>이메일</label> | |
| <Input id="account-email" type="email" value={email} disabled className={styles.readOnly} /> | |
| </div> | |
| <div className={styles.field}> | |
| <label htmlFor="account-password" className={styles.label}>비밀번호</label> | |
| <Input id="account-password" type="password" value="••••••••" disabled className={styles.readOnly} /> | |
| </div> |
| export default function TextArea({ className, ref, ...props }: TextAreaProps) { | ||
| return <textarea ref={ref} className={clsx(styles.textarea, className)} {...props} />; | ||
| } |
There was a problem hiding this comment.
ref를 일반 prop으로 전달하는 것은 React의 표준 패턴이 아니며 혼란을 야기할 수 있습니다. 컴포넌트가 ref를 받을 수 있도록 React.forwardRef를 사용하는 것이 좋습니다. 이렇게 하면 부모 컴포넌트에서 ref 어트리뷰트를 사용하여 DOM 노드에 직접 접근할 수 있습니다.
이를 위해 이 컴포넌트를 forwardRef로 감싸고, types/types.ts의 TextAreaProps에서 ref 속성을 제거해야 합니다:
export type TextAreaProps = ComponentPropsWithoutRef<'textarea'>;
| export type TextAreaProps = ComponentPropsWithoutRef<'textarea'> & { | ||
| ref?: Ref<HTMLTextAreaElement>; | ||
| }; |
There was a problem hiding this comment.
TextArea 컴포넌트에서 ref를 prop으로 직접 다루는 대신 React.forwardRef를 사용하는 것이 좋습니다. 이를 위해 TextAreaProps에서 ref 프로퍼티를 제거하고, TextArea 컴포넌트를 forwardRef로 감싸야 합니다. 이렇게 하면 React의 표준 ref 전달 메커니즘을 따르게 되어 코드의 일관성과 예측 가능성이 높아집니다. 이 변경 후에는 TextArea.tsx도 React.forwardRef를 사용하도록 수정해야 합니다.
export type TextAreaProps = ComponentPropsWithoutRef<'textarea'>;
Jieunsse
left a comment
There was a problem hiding this comment.
일부 스타일링 코드에 Var 적용 안된 부분이 있어서 그 부분확인해보시면 좋을 것 같습니다!
제미나이 리뷰도 확인해보시고 반영할 부분 반영해보면 좋을 것 같아요!
Approved 드렸습니다!
고생하셨어요 👍
| font-weight: 500; | ||
| font-size: 14px; | ||
| line-height: 17px; | ||
| color: #0f172a; |
There was a problem hiding this comment.
컬러 속성 var로 적용해주시면 좋을 것 같습니다!
| } | ||
|
|
||
| .readOnly { | ||
| background: #f1f5f9; |
|
|
||
| .errorMessage { | ||
| font-size: 12px; | ||
| color: #fc4b4b; |
Summary
atoms 와 molecules로 작업을 하다가 통일성이 안맞아서 처음 pull 해온 컴포넌트 폴더 형식에 맞추어 작업했습니다.


제가 정의했던 인풋 atom은 아래 이미지 2개이고 나머지는 아이콘, 버튼 조합의 molecule로 생각했습니다.
구현된 컴포넌트
Issue
#4