@uniai-fe/uds-primitives 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +64 -5
  2. package/dist/styles.css +236 -279
  3. package/package.json +4 -4
  4. package/src/components/badge/markup/Badge.tsx +10 -0
  5. package/src/components/badge/styles/index.scss +2 -2
  6. package/src/components/badge/types/index.ts +1 -1
  7. package/src/components/button/index.scss +3 -1
  8. package/src/components/button/index.tsx +9 -1
  9. package/src/components/button/markup/ButtonDefault.tsx +162 -0
  10. package/src/components/button/markup/ButtonRounded.tsx +48 -0
  11. package/src/components/button/markup/ButtonText.tsx +49 -0
  12. package/src/components/button/markup/index.ts +3 -0
  13. package/src/components/button/styles/{index.scss → button.scss} +148 -362
  14. package/src/components/button/styles/round-button.scss +56 -0
  15. package/src/components/button/styles/text-button.scss +96 -0
  16. package/src/components/button/types/index.ts +110 -35
  17. package/src/components/button/types/templates.ts +33 -0
  18. package/src/components/button/utils/index.ts +19 -19
  19. package/src/components/checkbox/markup/Checkbox.tsx +20 -2
  20. package/src/components/checkbox/types/checkbox.ts +16 -0
  21. package/src/components/chip/markup/Chip.tsx +8 -0
  22. package/src/components/dialog/markup/{confirm-dialog.tsx → ConfirmDialog.tsx} +23 -0
  23. package/src/components/dialog/markup/{notice-dialog.tsx → NoticeDialog.tsx} +18 -0
  24. package/src/components/dialog/markup/index.tsx +2 -2
  25. package/src/components/dialog/types/index.ts +43 -0
  26. package/src/components/drawer/markup/{drawer.tsx → Drawer.tsx} +58 -0
  27. package/src/components/drawer/markup/index.tsx +1 -1
  28. package/src/components/drawer/types/index.ts +24 -0
  29. package/src/components/input/markup/text/Base.tsx +32 -3
  30. package/src/components/input/markup/text/Identification.tsx +15 -2
  31. package/src/components/input/markup/text/Password.tsx +35 -2
  32. package/src/components/input/markup/text/Phone.tsx +38 -2
  33. package/src/components/input/markup/text/Search.tsx +30 -1
  34. package/src/components/input/styles/index.scss +6 -6
  35. package/src/components/input/types/index.ts +22 -1
  36. package/src/components/input/utils/index.ts +6 -0
  37. package/src/components/navigation/markup/mobile/BottomNavigation.tsx +11 -0
  38. package/src/components/navigation/types/index.ts +22 -0
  39. package/src/components/pagination/markup/Carousel.tsx +1 -0
  40. package/src/components/pagination/markup/Count.tsx +1 -0
  41. package/src/components/pagination/markup/Pagination.tsx +2 -0
  42. package/src/components/radio/markup/Radio.tsx +16 -2
  43. package/src/components/radio/markup/RadioCard.tsx +8 -0
  44. package/src/components/radio/markup/RadioCardGroup.tsx +8 -0
  45. package/src/components/radio/types/radio.ts +39 -0
  46. package/src/components/segmented-control/markup/SegmentedControl.tsx +12 -0
  47. package/src/components/segmented-control/types/index.ts +16 -0
  48. package/src/components/tab/markup/TabContent.tsx +5 -0
  49. package/src/components/tab/markup/TabList.tsx +19 -2
  50. package/src/components/tab/markup/TabRoot.tsx +50 -4
  51. package/src/components/tab/markup/TabTrigger.tsx +9 -1
  52. package/src/components/tab/styles/index.scss +28 -10
  53. package/src/components/tab/types/index.ts +10 -0
  54. package/src/components/tab/utils/tab-context.ts +8 -2
  55. package/src/components/button/markup/Button.tsx +0 -175
  56. package/src/components/button/markup/index.tsx +0 -1
@@ -1,4 +1,4 @@
1
1
  "use client";
2
2
 
3
- export * from "./notice-dialog";
4
- export * from "./confirm-dialog";
3
+ export * from "./NoticeDialog";
4
+ export * from "./ConfirmDialog";
@@ -2,52 +2,95 @@ import type { ComponentPropsWithoutRef } from "react";
2
2
  import type * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
3
3
  import type * as DialogPrimitive from "@radix-ui/react-dialog";
4
4
 
5
+ /**
6
+ * NoticeDialog Root props. Radix Dialog Root 계약을 그대로 사용한다.
7
+ */
5
8
  type NoticeDialogRootProps = ComponentPropsWithoutRef<
6
9
  typeof DialogPrimitive.Root
7
10
  >;
11
+ /**
12
+ * NoticeDialog Overlay props. className/data attr만 확장한다.
13
+ */
8
14
  type NoticeDialogOverlayProps = ComponentPropsWithoutRef<
9
15
  typeof DialogPrimitive.Overlay
10
16
  >;
17
+ /**
18
+ * NoticeDialog Content props.
19
+ */
11
20
  type NoticeDialogContentProps = ComponentPropsWithoutRef<
12
21
  typeof DialogPrimitive.Content
13
22
  >;
23
+ /**
24
+ * NoticeDialog section(div) props.
25
+ */
14
26
  type NoticeDialogSectionProps = ComponentPropsWithoutRef<"div">;
27
+ /**
28
+ * NoticeDialog Title props. visuallyHidden 옵션으로 시각적 숨김 지원.
29
+ */
15
30
  type NoticeDialogTitleProps = ComponentPropsWithoutRef<
16
31
  typeof DialogPrimitive.Title
17
32
  > & {
18
33
  visuallyHidden?: boolean;
19
34
  };
35
+ /**
36
+ * NoticeDialog Description props. visuallyHidden 옵션 포함.
37
+ */
20
38
  type NoticeDialogDescriptionProps = ComponentPropsWithoutRef<
21
39
  typeof DialogPrimitive.Description
22
40
  > & {
23
41
  visuallyHidden?: boolean;
24
42
  };
25
43
 
44
+ /**
45
+ * ConfirmDialog Root props. Radix AlertDialog Root 계약.
46
+ */
26
47
  type ConfirmDialogRootProps = ComponentPropsWithoutRef<
27
48
  typeof AlertDialogPrimitive.Root
28
49
  >;
50
+ /**
51
+ * ConfirmDialog Overlay props. disableOutsideClose 확장 포함.
52
+ * @property {boolean} [disableOutsideClose=false] dim 클릭 시 닫힘 방지 여부.
53
+ */
29
54
  type ConfirmDialogOverlayProps = ComponentPropsWithoutRef<
30
55
  typeof AlertDialogPrimitive.Overlay
31
56
  > & {
32
57
  disableOutsideClose?: boolean;
33
58
  };
59
+ /**
60
+ * ConfirmDialog Content props.
61
+ */
34
62
  type ConfirmDialogContentProps = ComponentPropsWithoutRef<
35
63
  typeof AlertDialogPrimitive.Content
36
64
  >;
65
+ /**
66
+ * ConfirmDialog section props.
67
+ */
37
68
  type ConfirmDialogSectionProps = ComponentPropsWithoutRef<"div">;
69
+ /**
70
+ * ConfirmDialog Title props. visuallyHidden 옵션 포함.
71
+ */
38
72
  type ConfirmDialogTitleProps = ComponentPropsWithoutRef<
39
73
  typeof AlertDialogPrimitive.Title
40
74
  > & {
41
75
  visuallyHidden?: boolean;
42
76
  };
77
+ /**
78
+ * ConfirmDialog Description props. visuallyHidden 옵션 포함.
79
+ */
43
80
  type ConfirmDialogDescriptionProps = ComponentPropsWithoutRef<
44
81
  typeof AlertDialogPrimitive.Description
45
82
  > & {
46
83
  visuallyHidden?: boolean;
47
84
  };
85
+ /**
86
+ * ConfirmDialog Action button props.
87
+ */
48
88
  type ConfirmDialogActionProps = ComponentPropsWithoutRef<
49
89
  typeof AlertDialogPrimitive.Action
50
90
  >;
91
+ /**
92
+ * ConfirmDialog Cancel button props.
93
+ */
51
94
  type ConfirmDialogCancelProps = ComponentPropsWithoutRef<
52
95
  typeof AlertDialogPrimitive.Cancel
53
96
  >;
@@ -35,6 +35,15 @@ import {
35
35
 
36
36
  const ANIMATION_DURATION = 320;
37
37
 
38
+ /**
39
+ * DrawerRoot — open 상태/phase를 관리하는 컨텍스트 루트.
40
+ * @component
41
+ * @param {DrawerRootProps} props
42
+ * @param {boolean} [props.open] 제어형 open 상태.
43
+ * @param {boolean} [props.defaultOpen] 비제어 초기 open 상태.
44
+ * @param {(open: boolean) => void} [props.onOpenChange] open 변경 콜백.
45
+ * @param {React.ReactNode} props.children Drawer 하위 컴포넌트.
46
+ */
38
47
  const DrawerRoot = ({
39
48
  children,
40
49
  open: openProp,
@@ -122,6 +131,13 @@ const DrawerRoot = ({
122
131
  );
123
132
  };
124
133
 
134
+ /**
135
+ * DrawerTrigger — Drawer를 여는 button/asChild.
136
+ * @component
137
+ * @param {DrawerTriggerProps} props
138
+ * @param {boolean} [props.asChild=false] button 대신 children을 직접 렌더할지 여부.
139
+ * @param {React.ReactNode} [props.children] trigger 콘텐츠.
140
+ */
125
141
  const DrawerTrigger = forwardRef<HTMLButtonElement, DrawerTriggerProps>(
126
142
  ({ asChild, children, onClick, ...props }, forwardedRef) => {
127
143
  const { setOpen } = useDrawerContext();
@@ -137,6 +153,11 @@ const DrawerTrigger = forwardRef<HTMLButtonElement, DrawerTriggerProps>(
137
153
 
138
154
  DrawerTrigger.displayName = "DrawerTrigger";
139
155
 
156
+ /**
157
+ * DrawerPortal — Drawer overlay/content를 body로 포탈한다.
158
+ * @component
159
+ * @param {DrawerPortalProps} props
160
+ */
140
161
  const DrawerPortal = ({ children }: DrawerPortalProps) => {
141
162
  useDrawerContext();
142
163
  const [mounted, setMounted] = useState(false);
@@ -157,6 +178,8 @@ const DrawerPortal = ({ children }: DrawerPortalProps) => {
157
178
  * DrawerOverlay; 전체 dim
158
179
  * @component
159
180
  * @param {DrawerOverlayProps} props
181
+ * @param {string} [props.className] overlay className.
182
+ * @param {boolean} [props.onClick] dim 클릭 시 setOpen(false)와 함께 호출되는 핸들러.
160
183
  */
161
184
  const DrawerOverlay = forwardRef<HTMLDivElement, DrawerOverlayProps>(
162
185
  ({ className, onClick, ...props }, forwardedRef) => {
@@ -180,6 +203,9 @@ DrawerOverlay.displayName = "DrawerOverlay";
180
203
  * DrawerTitle; Drawer 제목
181
204
  * @component
182
205
  * @param {DrawerTitleProps} props
206
+ * @param {boolean} [props.visuallyHidden=false] 제목을 시각적으로 숨길지 여부.
207
+ * @param {string} [props.className] title className.
208
+ * @param {React.ReactNode} [props.children] 제목 콘텐츠.
183
209
  */
184
210
  const DrawerTitle = forwardRef<HTMLHeadingElement, DrawerTitleProps>(
185
211
  ({ visuallyHidden = false, className, children, ...props }, forwardedRef) => {
@@ -207,6 +233,9 @@ DrawerTitle.displayName = "DrawerTitle";
207
233
  * DrawerDescription; Drawer 본문 안내
208
234
  * @component
209
235
  * @param {DrawerDescriptionProps} props
236
+ * @param {boolean} [props.visuallyHidden=false] 설명을 시각적으로 숨길지 여부.
237
+ * @param {string} [props.className] description className.
238
+ * @param {React.ReactNode} [props.children] 설명 콘텐츠.
210
239
  */
211
240
  const DrawerDescription = forwardRef<
212
241
  HTMLParagraphElement,
@@ -235,6 +264,9 @@ DrawerDescription.displayName = "DrawerDescription";
235
264
  * DrawerSection; header/body/footer 레이아웃
236
265
  * @component
237
266
  * @param {DrawerSectionProps} props
267
+ * @param {"header" | "body" | "footer"} [props.section="body"] 섹션 variant.
268
+ * @param {string} [props.className] 섹션 className.
269
+ * @param {React.ReactNode} [props.children] 섹션 콘텐츠.
238
270
  */
239
271
  const DrawerSection = forwardRef<HTMLDivElement, DrawerSectionProps>(
240
272
  ({ className, section = "body", ...props }, forwardedRef) => (
@@ -249,6 +281,11 @@ const DrawerSection = forwardRef<HTMLDivElement, DrawerSectionProps>(
249
281
 
250
282
  DrawerSection.displayName = "DrawerSection";
251
283
 
284
+ /**
285
+ * DrawerHeader; header 섹션 helper.
286
+ * @component
287
+ * @param {DrawerSectionProps} props
288
+ */
252
289
  const DrawerHeader = forwardRef<HTMLDivElement, DrawerSectionProps>(
253
290
  ({ className, ...props }, forwardedRef) => (
254
291
  <DrawerSection
@@ -262,6 +299,11 @@ const DrawerHeader = forwardRef<HTMLDivElement, DrawerSectionProps>(
262
299
 
263
300
  DrawerHeader.displayName = "DrawerHeader";
264
301
 
302
+ /**
303
+ * DrawerBody; body 섹션 helper.
304
+ * @component
305
+ * @param {DrawerSectionProps} props
306
+ */
265
307
  const DrawerBody = forwardRef<HTMLDivElement, DrawerSectionProps>(
266
308
  ({ className, ...props }, forwardedRef) => (
267
309
  <DrawerSection
@@ -275,6 +317,11 @@ const DrawerBody = forwardRef<HTMLDivElement, DrawerSectionProps>(
275
317
 
276
318
  DrawerBody.displayName = "DrawerBody";
277
319
 
320
+ /**
321
+ * DrawerFooter; footer 섹션 helper.
322
+ * @component
323
+ * @param {DrawerSectionProps} props
324
+ */
278
325
  const DrawerFooter = forwardRef<HTMLDivElement, DrawerSectionProps>(
279
326
  ({ className, ...props }, forwardedRef) => (
280
327
  <DrawerSection
@@ -292,6 +339,10 @@ DrawerFooter.displayName = "DrawerFooter";
292
339
  * DrawerContent; handle/closeButton 제어
293
340
  * @component
294
341
  * @param {DrawerContentProps} props
342
+ * @param {boolean} [props.closeButton=false] 헤더에 닫기 버튼 표시 여부.
343
+ * @param {string} [props.closeButtonLabel="닫기"] 닫기 버튼 aria-label.
344
+ * @param {string} [props.className] content className.
345
+ * @param {React.CSSProperties} [props.style] inline style.
295
346
  */
296
347
  const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
297
348
  (
@@ -391,6 +442,13 @@ const DrawerContent = forwardRef<HTMLDivElement, DrawerContentProps>(
391
442
 
392
443
  DrawerContent.displayName = "DrawerContent";
393
444
 
445
+ /**
446
+ * DrawerClose — Drawer를 닫는 button/asChild helper.
447
+ * @component
448
+ * @param {DrawerCloseProps} props
449
+ * @param {boolean} [props.asChild=false] 버튼 대신 children을 직접 렌더할지 여부.
450
+ * @param {React.ReactNode} [props.children] close trigger.
451
+ */
394
452
  const DrawerClose = forwardRef<HTMLButtonElement, DrawerCloseProps>(
395
453
  ({ asChild, children, onClick, ...props }, forwardedRef) => {
396
454
  const { setOpen } = useDrawerContext();
@@ -1,3 +1,3 @@
1
1
  "use client";
2
2
 
3
- export * from "./drawer";
3
+ export * from "./Drawer";
@@ -8,6 +8,13 @@ export interface DrawerContextValue {
8
8
  phase: DrawerPhase;
9
9
  }
10
10
 
11
+ /**
12
+ * DrawerRoot props. open 제어 및 상태 콜백을 정의한다.
13
+ * @property {React.ReactNode} children Drawer 하위 구성 요소.
14
+ * @property {boolean} [open] 제어형 open 상태.
15
+ * @property {boolean} [defaultOpen] 비제어 초기 상태.
16
+ * @property {(open: boolean) => void} [onOpenChange] open 변경 콜백.
17
+ */
11
18
  export interface DrawerRootProps {
12
19
  children: ReactNode;
13
20
  open?: boolean;
@@ -15,11 +22,19 @@ export interface DrawerRootProps {
15
22
  onOpenChange?: (open: boolean) => void;
16
23
  }
17
24
 
25
+ /**
26
+ * DrawerTrigger props.
27
+ * @property {boolean} [asChild=false] children을 직접 버튼으로 사용할지 여부.
28
+ */
18
29
  export interface DrawerTriggerProps extends ComponentPropsWithoutRef<"button"> {
19
30
  asChild?: boolean;
20
31
  children?: ReactNode;
21
32
  }
22
33
 
34
+ /**
35
+ * DrawerClose props.
36
+ * @property {boolean} [asChild=false] children을 직접 버튼으로 사용할지 여부.
37
+ */
23
38
  export interface DrawerCloseProps extends ComponentPropsWithoutRef<"button"> {
24
39
  asChild?: boolean;
25
40
  children?: ReactNode;
@@ -41,10 +56,19 @@ export type DrawerDescriptionProps = ComponentPropsWithoutRef<"p"> & {
41
56
 
42
57
  export type DrawerSectionVariant = "header" | "body" | "footer";
43
58
 
59
+ /**
60
+ * DrawerSection props. section variant로 header/body/footer를 지정한다.
61
+ * @property {"header" | "body" | "footer"} [section="body"] 섹션 유형.
62
+ */
44
63
  export interface DrawerSectionProps extends ComponentPropsWithoutRef<"div"> {
45
64
  section?: DrawerSectionVariant;
46
65
  }
47
66
 
67
+ /**
68
+ * DrawerContent props.
69
+ * @property {boolean} [closeButton=false] close 버튼을 표시할지 여부.
70
+ * @property {string} [closeButtonLabel="닫기"] close 버튼 aria-label.
71
+ */
48
72
  export interface DrawerContentProps extends ComponentPropsWithoutRef<"div"> {
49
73
  closeButton?: boolean;
50
74
  closeButtonLabel?: string;
@@ -22,8 +22,37 @@ import SuccessIcon from "../../img/success.svg";
22
22
  import ResetIcon from "../../img/reset.svg";
23
23
 
24
24
  /**
25
- * Native `<input>` 기반 텍스트 필드. appearance/size/state 축과 label/helper 슬롯을 모두 제공한다.
26
- * README와 Button 컴포넌트와 동일하게 props를 forwardRef 인자로 직접 구조분해한다.
25
+ * Native `<input>` 기반 텍스트 필드. appearance/size/state 축, prefix/suffix/reset/status 슬롯,
26
+ * label/helperText 같은 피드백 슬롯을 모두 제공한다.
27
+ * @component
28
+ * @param {InputProps} props
29
+ * @param {"primary" | "secondary" | "tertiary"} [props.appearance="primary"] 토큰 세트.
30
+ * @param {"small" | "medium" | "large"} [props.size="medium"] 높이/spacing 세트.
31
+ * @param {"default" | "active" | "focused" | "success" | "error" | "disabled"} [props.state="default"] 시각 상태.
32
+ * @param {boolean} [props.block=false] true면 width 100%.
33
+ * @param {React.ReactNode} [props.prefix] 입력 왼쪽 추가 슬롯.
34
+ * @param {React.ReactNode} [props.suffix] 입력 오른쪽 추가 슬롯.
35
+ * @param {React.ReactElement} [props.resetSlot] 값 초기화 버튼 슬롯. 미지정 시 기본 reset 아이콘.
36
+ * @param {React.ReactNode} [props.successIcon] success 상태에서 사용할 아이콘.
37
+ * @param {React.ReactNode} [props.errorIcon] error 상태에서 사용할 아이콘.
38
+ * @param {React.ReactNode} [props.label] 상단/inset label 콘텐츠.
39
+ * @param {React.ReactNode} [props.helperText] helper 영역 텍스트.
40
+ * @param {boolean} [props.hideHelperText] true면 helper 영역 숨김.
41
+ * @param {string} [props.inputClassName] 실제 `<input>` 요소 className.
42
+ * @param {string} [props.wrapperClassName] `.input-box` wrapper className.
43
+ * @param {object} [props.labelProps] label attr 커스터마이즈.
44
+ * @param {object} [props.helperTextProps] helper 영역 attr.
45
+ * @param {boolean} [props.disabled] native disabled.
46
+ * @param {string} [props.id] external id. label htmlFor 와 공유한다.
47
+ * @param {string} [props.className] root `.input` className 합성용.
48
+ * @param {"default" | "active" | "focused" | "success" | "error" | "disabled"} [props.data-simulated-state]
49
+ * Storybook 등에서 강제 상태 표현.
50
+ * @param {string} [props.type="text"] native input type.
51
+ * @param {string | number | readonly string[]} [props.defaultValue] 비제어 초기값.
52
+ * @param {string | number | readonly string[]} [props.value] 제어형 값.
53
+ * @param {(event: ChangeEvent<HTMLInputElement>) => void} [props.onChange] 입력 변경 핸들러.
54
+ * @param {(event: FocusEvent<HTMLInputElement>) => void} [props.onFocus] focus 핸들러.
55
+ * @param {(event: FocusEvent<HTMLInputElement>) => void} [props.onBlur] blur 핸들러.
27
56
  */
28
57
  const Text = forwardRef<HTMLInputElement, InputProps>(
29
58
  (
@@ -159,7 +188,7 @@ const Text = forwardRef<HTMLInputElement, InputProps>(
159
188
  () => clsx("input-helper-text", helperTextProps?.className),
160
189
  [helperTextProps?.className],
161
190
  );
162
- const shouldRenderInlineLabel = appearance === "teritary" && Boolean(label);
191
+ const shouldRenderInlineLabel = appearance === "tertiary" && Boolean(label);
163
192
  const labelClassName = useMemo(
164
193
  () =>
165
194
  clsx(
@@ -11,6 +11,14 @@ import {
11
11
  } from "react";
12
12
  import type { InputProps } from "../../types";
13
13
 
14
+ /**
15
+ * IdentificationInput props. 고정 길이 숫자 코드 입력에 필요한 label/helper/state/onComplete를 제공한다.
16
+ * @property {number} [length=6] 입력칸 개수(4~8 사이로 자동 보정).
17
+ * @property {InputProps["label"]} [label] 상단 라벨.
18
+ * @property {InputProps["helperText"]} [helperText] helper 텍스트.
19
+ * @property {InputProps["state"]} [state="default"] 시각 상태.
20
+ * @property {(code: string) => void} [onComplete] 모든 셀이 채워졌을 때 호출.
21
+ */
14
22
  export interface IdentificationInputProps {
15
23
  length?: number;
16
24
  label?: InputProps["label"];
@@ -21,8 +29,13 @@ export interface IdentificationInputProps {
21
29
 
22
30
  /**
23
31
  * IdentificationInput — 인증번호 입력 UI. 개별 입력칸을 제공하고 focus 이동/붙여넣기 등을 처리한다.
24
- * @param props.length 입력 필드 길이 (4~8 사이).
25
- * @param props.onComplete 모든 셀이 채워졌을 때 호출.
32
+ * @component
33
+ * @param {IdentificationInputProps} props
34
+ * @param {number} [props.length=6] 입력 필드 길이. 4~8 범위로 자동 보정된다.
35
+ * @param {InputProps["label"]} [props.label] 상단 label 콘텐츠.
36
+ * @param {InputProps["helperText"]} [props.helperText] helper 텍스트.
37
+ * @param {InputProps["state"]} [props.state] 시각 상태.
38
+ * @param {(code: string) => void} [props.onComplete] 모든 셀이 채워졌을 때 호출되는 콜백.
26
39
  */
27
40
  const IdentificationInput = forwardRef<
28
41
  HTMLInputElement[],
@@ -4,6 +4,12 @@ import { Text } from "./Base";
4
4
  import HideOffIcon from "../../img/hide-off.svg";
5
5
  import HideOnIcon from "../../img/hide-on.svg";
6
6
 
7
+ /**
8
+ * PasswordInput 전용 props. Text Input props에서 type/defaultValue 제약을 재정의하고 toggle 옵션을 추가한다.
9
+ * @property {boolean} [defaultVisible=false] 초기 렌더 시 비밀번호를 드러낼지 여부.
10
+ * @property {{show: string; hide: string}} [toggleLabel] 토글 버튼에 사용할 라벨 텍스트 집합.
11
+ * @property {string} [defaultValue] 비제어 초기값.
12
+ */
7
13
  export interface PasswordInputProps extends Omit<
8
14
  InputProps,
9
15
  "type" | "defaultValue"
@@ -18,8 +24,35 @@ export interface PasswordInputProps extends Omit<
18
24
 
19
25
  /**
20
26
  * PasswordInput — 기본 Text 입력을 비밀번호 토글 UX로 확장.
21
- * @param props.defaultVisible 최초 노출 여부.
22
- * @param props.toggleLabel 토글 버튼의 라벨 텍스트.
27
+ * @component
28
+ * @param {PasswordInputProps} props
29
+ * @param {"primary" | "secondary" | "tertiary"} [props.appearance="primary"] 토큰 세트.
30
+ * @param {"small" | "medium" | "large"} [props.size="medium"] 높이/spacing.
31
+ * @param {"default" | "active" | "focused" | "success" | "error" | "disabled"} [props.state="default"] 시각 상태.
32
+ * @param {boolean} [props.block=false] true면 width 100%.
33
+ * @param {React.ReactNode} [props.prefix] prefix 슬롯(Password에서는 기본 제공하지 않음).
34
+ * @param {React.ReactNode} [props.suffix] suffix 슬롯. 미지정 시 보기/숨김 토글 버튼 자동 배치.
35
+ * @param {React.ReactNode} [props.successIcon] success 상태 아이콘.
36
+ * @param {React.ReactNode} [props.errorIcon] error 상태 아이콘.
37
+ * @param {React.ReactNode} [props.label] label 영역 콘텐츠.
38
+ * @param {React.ReactNode} [props.helperText] helper 영역 텍스트.
39
+ * @param {boolean} [props.hideHelperText] helper 숨김 여부.
40
+ * @param {string} [props.inputClassName] `<input>` className.
41
+ * @param {string} [props.wrapperClassName] `.input-box` className.
42
+ * @param {object} [props.labelProps] label attr.
43
+ * @param {object} [props.helperTextProps] helper attr.
44
+ * @param {boolean} [props.disabled] native disabled.
45
+ * @param {string} [props.id] 외부 id.
46
+ * @param {string} [props.className] root className.
47
+ * @param {"default" | "active" | "focused" | "success" | "error" | "disabled"} [props.data-simulated-state]
48
+ * Storybook 시각 상태 강제용.
49
+ * @param {string} [props.defaultValue] 비제어 초기값.
50
+ * @param {string | number | readonly string[]} [props.value] 제어형 값.
51
+ * @param {(event: React.ChangeEvent<HTMLInputElement>) => void} [props.onChange] 변경 핸들러.
52
+ * @param {(event: React.FocusEvent<HTMLInputElement>) => void} [props.onFocus] focus 핸들러.
53
+ * @param {(event: React.FocusEvent<HTMLInputElement>) => void} [props.onBlur] blur 핸들러.
54
+ * @param {boolean} [props.defaultVisible=false] 초기 노출 여부.
55
+ * @param {{show: string; hide: string}} [props.toggleLabel] 토글 버튼 라벨.
23
56
  */
24
57
  const PasswordInput = forwardRef<HTMLInputElement, PasswordInputProps>(
25
58
  (
@@ -4,6 +4,16 @@ import { forwardRef, useCallback, useMemo, useState } from "react";
4
4
  import type { InputProps } from "../../types";
5
5
  import { Text } from "./Base";
6
6
 
7
+ /**
8
+ * PhoneInput 전용 props. Text Input 중 전화번호 UX에 필요한 필드를 정의한다.
9
+ * @property {string} [value] 제어형 포맷팅 값.
10
+ * @property {string} [defaultValue] 비제어 초기값(숫자/포맷 모두 허용).
11
+ * @property {(value: string, digits: string) => void} [onValueChange] 포맷팅 값/숫자만 값을 함께 전달.
12
+ * @property {ComponentPropsWithoutRef<"input">["onChange"]} [onChange] native onChange override.
13
+ * @property {() => void} [onRequestCode] suffix 버튼 클릭 시 호출.
14
+ * @property {string} [requestButtonLabel="인증번호 요청"] suffix 버튼 라벨.
15
+ * @property {boolean} [requestButtonDisabled] suffix 버튼 disabled 여부.
16
+ */
7
17
  export interface PhoneInputProps extends Omit<
8
18
  InputProps,
9
19
  | "type"
@@ -32,8 +42,34 @@ const formatPhoneNumber = (digits: string) => maskPhone(digits);
32
42
 
33
43
  /**
34
44
  * PhoneInput — 휴대폰 번호 마스킹과 인증번호 요청 버튼을 제공하는 입력.
35
- * @param props.onValueChange 포맷팅된 값 + 숫자만 별도로 전달.
36
- * @param props.onRequestCode 인증번호 요청 버튼 클릭 핸들러.
45
+ * @component
46
+ * @param {PhoneInputProps} props
47
+ * @param {"primary" | "secondary" | "tertiary"} [props.appearance="primary"] 토큰 세트.
48
+ * @param {"small" | "medium" | "large"} [props.size="medium"] 높이/spacing.
49
+ * @param {"default" | "active" | "focused" | "success" | "error" | "disabled"} [props.state="default"] 시각 상태.
50
+ * @param {boolean} [props.block=false] true면 width 100%.
51
+ * @param {React.ReactNode} [props.suffix] suffix 슬롯. 미지정 시 인증 버튼 자동 배치.
52
+ * @param {React.ReactNode} [props.successIcon] success 상태 아이콘.
53
+ * @param {React.ReactNode} [props.errorIcon] error 상태 아이콘.
54
+ * @param {React.ReactNode} [props.label] label 콘텐츠.
55
+ * @param {React.ReactNode} [props.helperText] helper 텍스트.
56
+ * @param {boolean} [props.hideHelperText] helper 숨김 여부.
57
+ * @param {string} [props.inputClassName] `<input>` className.
58
+ * @param {string} [props.wrapperClassName] `.input-box` className.
59
+ * @param {object} [props.labelProps] label attr.
60
+ * @param {object} [props.helperTextProps] helper attr.
61
+ * @param {boolean} [props.disabled] native disabled.
62
+ * @param {string} [props.id] 외부 id.
63
+ * @param {string} [props.className] root className.
64
+ * @param {"default" | "active" | "focused" | "success" | "error" | "disabled"} [props.data-simulated-state]
65
+ * Storybook 시각 상태 강제용.
66
+ * @param {string} [props.value] 제어형 값(포맷팅).
67
+ * @param {string} [props.defaultValue] 비제어 초기값.
68
+ * @param {(value: string, digits: string) => void} [props.onValueChange] 포맷팅/숫자 값 동시 전달.
69
+ * @param {(event: ChangeEvent<HTMLInputElement>) => void} [props.onChange] native onChange override.
70
+ * @param {() => void} [props.onRequestCode] 인증번호 요청 버튼 핸들러.
71
+ * @param {string} [props.requestButtonLabel="인증번호 요청"] 버튼 라벨.
72
+ * @param {boolean} [props.requestButtonDisabled] 버튼 disabled.
37
73
  */
38
74
  const PhoneInput = forwardRef<HTMLInputElement, PhoneInputProps>(
39
75
  (
@@ -3,11 +3,40 @@ import type { InputProps } from "../../types";
3
3
  import { Text } from "./Base";
4
4
  import SearchIcon from "../../img/search.svg";
5
5
 
6
+ /**
7
+ * SearchInput 전용 props. type을 search로 강제하고 나머지는 Text 입력과 동일하다.
8
+ */
6
9
  export interface SearchInputProps extends Omit<InputProps, "type"> {}
7
10
 
8
11
  /**
9
12
  * SearchInput — 기본 Text 입력에 검색 아이콘 prefix를 제공한다.
10
- * @param props.prefix prefix slot. 정의하지 않으면 검색 아이콘이 자동 배치된다.
13
+ * @component
14
+ * @param {SearchInputProps} props
15
+ * @param {"primary" | "secondary" | "tertiary"} [props.appearance="primary"] 토큰 세트.
16
+ * @param {"small" | "medium" | "large"} [props.size="medium"] 높이/spacing.
17
+ * @param {"default" | "active" | "focused" | "success" | "error" | "disabled"} [props.state="default"] 시각 상태.
18
+ * @param {boolean} [props.block=false] true면 width 100%.
19
+ * @param {React.ReactNode} [props.prefix] prefix 슬롯. 미지정 시 돋보기 아이콘이 자동 배치된다.
20
+ * @param {React.ReactNode} [props.suffix] suffix 슬롯.
21
+ * @param {React.ReactNode} [props.successIcon] success 상태 아이콘.
22
+ * @param {React.ReactNode} [props.errorIcon] error 상태 아이콘.
23
+ * @param {React.ReactNode} [props.label] label 콘텐츠.
24
+ * @param {React.ReactNode} [props.helperText] helper 텍스트.
25
+ * @param {boolean} [props.hideHelperText] helper 숨김 여부.
26
+ * @param {string} [props.inputClassName] `<input>` className.
27
+ * @param {string} [props.wrapperClassName] `.input-box` className.
28
+ * @param {object} [props.labelProps] label attr.
29
+ * @param {object} [props.helperTextProps] helper attr.
30
+ * @param {boolean} [props.disabled] native disabled.
31
+ * @param {string} [props.id] 외부 id.
32
+ * @param {string} [props.className] root className.
33
+ * @param {"default" | "active" | "focused" | "success" | "error" | "disabled"} [props.data-simulated-state]
34
+ * Storybook 시각 상태 강제용.
35
+ * @param {string | number | readonly string[]} [props.defaultValue] 비제어 초기값.
36
+ * @param {string | number | readonly string[]} [props.value] 제어형 값.
37
+ * @param {(event: React.ChangeEvent<HTMLInputElement>) => void} [props.onChange] 입력 변경 핸들러.
38
+ * @param {(event: React.FocusEvent<HTMLInputElement>) => void} [props.onFocus] focus 핸들러.
39
+ * @param {(event: React.FocusEvent<HTMLInputElement>) => void} [props.onBlur] blur 핸들러.
11
40
  */
12
41
  const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>(
13
42
  ({ prefix, ...restProps }, forwardedRef) => {
@@ -4,12 +4,12 @@
4
4
  --theme-input-height-small: var(--theme-size-medium-1);
5
5
  --theme-input-height-medium: var(--theme-size-medium-2);
6
6
  --theme-input-height-large: var(--theme-size-medium-3);
7
- --theme-input-height-teritary: calc(var(--theme-size-medium-2) + 24px);
7
+ --theme-input-height-tertiary: calc(var(--theme-size-medium-2) + 24px);
8
8
  --theme-input-padding-x: var(--spacing-padding-6);
9
9
  --theme-input-padding-y: var(--spacing-padding-4);
10
10
  --theme-input-gap: var(--spacing-gap-4);
11
11
  --theme-input-radius-default: var(--theme-radius-large-1);
12
- --theme-input-radius-teritary: var(--theme-radius-large-2);
12
+ --theme-input-radius-tertiary: var(--theme-radius-large-2);
13
13
  --theme-input-label-color: var(--color-label-standard);
14
14
  --theme-input-helper-color: var(--color-label-neutral);
15
15
  --theme-input-helper-disabled-color: var(--color-label-disabled);
@@ -106,10 +106,10 @@
106
106
  background-color: transparent;
107
107
  }
108
108
 
109
- &[data-appearance="teritary"] {
110
- border-radius: var(--theme-input-radius-teritary);
109
+ &[data-appearance="tertiary"] {
110
+ border-radius: var(--theme-input-radius-tertiary);
111
111
  background-color: var(--theme-input-surface);
112
- min-height: var(--theme-input-height-teritary);
112
+ min-height: var(--theme-input-height-tertiary);
113
113
  flex-wrap: wrap;
114
114
  row-gap: var(--spacing-gap-1);
115
115
  column-gap: var(--theme-input-gap);
@@ -200,7 +200,7 @@
200
200
  padding-inline: 0;
201
201
  }
202
202
 
203
- .input-field[data-appearance="teritary"] .input-element {
203
+ .input-field[data-appearance="tertiary"] .input-element {
204
204
  min-height: var(--theme-size-medium-2);
205
205
  }
206
206
 
@@ -1,7 +1,16 @@
1
1
  import type { ComponentPropsWithoutRef, ReactElement, ReactNode } from "react";
2
2
 
3
- export const INPUT_APPEARANCES = ["primary", "secondary", "teritary"] as const;
3
+ /**
4
+ * appearance 축은 tokens 기반 테마 계층을 지정한다.
5
+ */
6
+ export const INPUT_APPEARANCES = ["primary", "secondary", "tertiary"] as const;
7
+ /**
8
+ * size 축은 높이/타이포/spacing을 결정한다.
9
+ */
4
10
  export const INPUT_SIZES = ["small", "medium", "large"] as const;
11
+ /**
12
+ * 시각 상태는 success/error/disabled 를 포함한다.
13
+ */
5
14
  export const INPUT_STATES = [
6
15
  "default",
7
16
  "active",
@@ -17,6 +26,9 @@ export type InputState = (typeof INPUT_STATES)[number];
17
26
 
18
27
  type NativeInputProps = ComponentPropsWithoutRef<"input">;
19
28
 
29
+ /**
30
+ * prefix/suffix와 status 아이콘 슬롯 정의.
31
+ */
20
32
  export interface InputAffix {
21
33
  prefix?: ReactNode;
22
34
  suffix?: ReactNode;
@@ -25,12 +37,18 @@ export interface InputAffix {
25
37
  errorIcon?: ReactNode;
26
38
  }
27
39
 
40
+ /**
41
+ * label/helperText 등 피드백 슬롯 정의.
42
+ */
28
43
  export interface InputFeedback {
29
44
  label?: ReactNode;
30
45
  helperText?: ReactNode;
31
46
  hideHelperText?: boolean;
32
47
  }
33
48
 
49
+ /**
50
+ * 텍스트 입력의 핵심 props. native input 속성에서 size/prefix/suffix는 제외하고 자체 슬롯으로 교체했다.
51
+ */
34
52
  export interface InputProps
35
53
  extends
36
54
  Omit<NativeInputProps, "prefix" | "suffix" | "size">,
@@ -47,6 +65,9 @@ export interface InputProps
47
65
  "data-simulated-state"?: InputState;
48
66
  }
49
67
 
68
+ /**
69
+ * className composer helper가 필요로 하는 파라미터 집합.
70
+ */
50
71
  export interface InputClassNameOptions {
51
72
  appearance: InputAppearance;
52
73
  size: InputSize;
@@ -7,6 +7,9 @@ const INPUT_FIELD_CLASSNAME = "input-field";
7
7
  const INPUT_ELEMENT_CLASSNAME = "input-element";
8
8
  const INPUT_AFFIX_CLASSNAME = "input-affix";
9
9
 
10
+ /**
11
+ * container `.input` element className을 조립한다.
12
+ */
10
13
  const composeInputClassName = ({
11
14
  appearance,
12
15
  size,
@@ -25,6 +28,9 @@ const composeInputClassName = ({
25
28
  className,
26
29
  );
27
30
 
31
+ /**
32
+ * 박스(wrapper) `.input-box` className을 조립한다.
33
+ */
28
34
  const composeInputBoxClassName = ({
29
35
  appearance,
30
36
  size,
@@ -10,6 +10,17 @@ import {
10
10
  isHrefNavigationItem,
11
11
  } from "../../utils";
12
12
 
13
+ /**
14
+ * BottomNavigation — 모바일 하단 내비게이션.
15
+ * @component
16
+ * @param {BottomNavigationProps} props
17
+ * @param {NavigationItem[]} props.items 렌더링할 항목 배열.
18
+ * @param {NavigationItemKey | null} props.activeKey 현재 활성 key.
19
+ * @param {(key: NavigationItemKey) => void} [props.onActiveChange] active 변경 콜백.
20
+ * @param {string} [props.ariaLabel] nav 라벨. 없으면 전달된 `aria-label` 속성을 사용한다.
21
+ * @param {boolean} [props.fixed=false] true면 뷰포트 하단 고정 스타일.
22
+ * @param {string} [props.className] root className.
23
+ */
13
24
  const BottomNavigation = forwardRef<HTMLElement, BottomNavigationProps>(
14
25
  (
15
26
  {