@uniai-fe/uds-primitives 0.0.7 → 0.0.9
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.
- package/README.md +64 -5
- package/dist/styles.css +220 -303
- package/package.json +4 -4
- package/src/components/badge/markup/Badge.tsx +10 -0
- package/src/components/badge/styles/index.scss +2 -2
- package/src/components/badge/types/index.ts +1 -1
- package/src/components/button/index.scss +3 -1
- package/src/components/button/index.tsx +9 -1
- package/src/components/button/markup/ButtonDefault.tsx +162 -0
- package/src/components/button/markup/ButtonRounded.tsx +48 -0
- package/src/components/button/markup/ButtonText.tsx +49 -0
- package/src/components/button/markup/index.ts +3 -0
- package/src/components/button/styles/{index.scss → button.scss} +202 -424
- package/src/components/button/styles/round-button.scss +56 -0
- package/src/components/button/styles/text-button.scss +96 -0
- package/src/components/button/types/index.ts +110 -35
- package/src/components/button/types/templates.ts +33 -0
- package/src/components/button/utils/index.ts +19 -19
- package/src/components/checkbox/markup/Checkbox.tsx +20 -2
- package/src/components/checkbox/types/checkbox.ts +16 -0
- package/src/components/chip/markup/Chip.tsx +8 -0
- package/src/components/dialog/markup/{confirm-dialog.tsx → ConfirmDialog.tsx} +23 -0
- package/src/components/dialog/markup/{notice-dialog.tsx → NoticeDialog.tsx} +18 -0
- package/src/components/dialog/markup/index.tsx +2 -2
- package/src/components/dialog/types/index.ts +43 -0
- package/src/components/drawer/markup/{drawer.tsx → Drawer.tsx} +58 -0
- package/src/components/drawer/markup/index.tsx +1 -1
- package/src/components/drawer/types/index.ts +24 -0
- package/src/components/input/markup/text/Base.tsx +32 -3
- package/src/components/input/markup/text/Identification.tsx +15 -2
- package/src/components/input/markup/text/Password.tsx +35 -2
- package/src/components/input/markup/text/Phone.tsx +38 -2
- package/src/components/input/markup/text/Search.tsx +30 -1
- package/src/components/input/styles/index.scss +6 -6
- package/src/components/input/types/index.ts +22 -1
- package/src/components/input/utils/index.ts +6 -0
- package/src/components/navigation/markup/mobile/BottomNavigation.tsx +11 -0
- package/src/components/navigation/types/index.ts +22 -0
- package/src/components/pagination/markup/Carousel.tsx +1 -0
- package/src/components/pagination/markup/Count.tsx +1 -0
- package/src/components/pagination/markup/Pagination.tsx +2 -0
- package/src/components/radio/markup/Radio.tsx +16 -2
- package/src/components/radio/markup/RadioCard.tsx +8 -0
- package/src/components/radio/markup/RadioCardGroup.tsx +8 -0
- package/src/components/radio/types/radio.ts +39 -0
- package/src/components/segmented-control/markup/SegmentedControl.tsx +12 -0
- package/src/components/segmented-control/types/index.ts +16 -0
- package/src/components/tab/markup/TabContent.tsx +5 -0
- package/src/components/tab/markup/TabList.tsx +19 -2
- package/src/components/tab/markup/TabRoot.tsx +50 -4
- package/src/components/tab/markup/TabTrigger.tsx +9 -1
- package/src/components/tab/styles/index.scss +28 -10
- package/src/components/tab/types/index.ts +10 -0
- package/src/components/tab/utils/tab-context.ts +8 -2
- package/src/components/button/markup/Button.tsx +0 -175
- package/src/components/button/markup/index.tsx +0 -1
|
@@ -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();
|
|
@@ -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
|
|
26
|
-
*
|
|
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 === "
|
|
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
|
-
* @
|
|
25
|
-
* @param props
|
|
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
|
-
* @
|
|
22
|
-
* @param props
|
|
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
|
-
* @
|
|
36
|
-
* @param props
|
|
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
|
-
* @
|
|
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-
|
|
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-
|
|
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="
|
|
110
|
-
border-radius: var(--theme-input-radius-
|
|
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-
|
|
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="
|
|
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
|
-
|
|
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
|
{
|