@uniai-fe/uds-primitives 0.12.4 → 0.12.6

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 (55) hide show
  1. package/README.md +17 -0
  2. package/dist/styles.css +2 -2
  3. package/package.json +17 -17
  4. package/src/components/form/markup/Provider.tsx +7 -3
  5. package/src/components/form/markup/form-field/Body.tsx +1 -0
  6. package/src/components/form/markup/form-field/Container.tsx +3 -1
  7. package/src/components/form/markup/form-field/Footer.tsx +1 -0
  8. package/src/components/form/markup/form-field/Header.tsx +2 -0
  9. package/src/components/form/markup/form-field/Template.tsx +3 -2
  10. package/src/components/form/markup/form-field/index.tsx +1 -1
  11. package/src/components/form/markup/index.tsx +1 -0
  12. package/src/components/form/styles/form-field/variables.scss +2 -2
  13. package/src/components/form/types/props.ts +21 -19
  14. package/src/components/form/utils/form-field.ts +6 -4
  15. package/src/components/input/markup/date/Template.tsx +83 -33
  16. package/src/components/input/markup/date/Trigger.tsx +28 -12
  17. package/src/components/input/markup/date/range/Template.tsx +94 -35
  18. package/src/components/input/markup/time/Template.tsx +118 -5
  19. package/src/components/input/markup/time/Trigger.tsx +35 -2
  20. package/src/components/input/types/date.ts +176 -33
  21. package/src/components/input/types/time.ts +10 -4
  22. package/src/components/slot/index.tsx +3 -6
  23. package/src/components/slot/markup/Base.tsx +146 -9
  24. package/src/components/slot/markup/index.tsx +2 -4
  25. package/src/components/slot/types/props.ts +119 -23
  26. package/src/components/table/types/foundation.ts +9 -7
  27. package/src/components/time-picker/markup/Footer.tsx +5 -5
  28. package/src/components/time-picker/markup/HourSection.tsx +7 -7
  29. package/src/components/time-picker/markup/MinuteSection.tsx +5 -5
  30. package/src/components/time-picker/markup/Summary.tsx +2 -2
  31. package/src/components/time-picker/markup/Template.tsx +11 -11
  32. package/src/components/time-picker/types/time-picker.ts +6 -0
  33. package/src/components/time-picker/utils/time.ts +21 -9
  34. package/src/index.scss +0 -2
  35. package/src/index.tsx +8 -2
  36. package/src/types/index.ts +1 -4
  37. package/src/utils/index.ts +8 -4
  38. package/src/utils/selected-values.ts +20 -14
  39. package/src/components/scrollbar/hooks/index.ts +0 -4
  40. package/src/components/scrollbar/img/.gitkeep +0 -0
  41. package/src/components/scrollbar/index.scss +0 -1
  42. package/src/components/scrollbar/index.tsx +0 -4
  43. package/src/components/scrollbar/markup/index.tsx +0 -4
  44. package/src/components/scrollbar/styles/index.scss +0 -0
  45. package/src/components/scrollbar/types/index.ts +0 -4
  46. package/src/components/scrollbar/utils/index.ts +0 -4
  47. package/src/components/spinner/hooks/index.ts +0 -4
  48. package/src/components/spinner/img/.gitkeep +0 -0
  49. package/src/components/spinner/index.scss +0 -1
  50. package/src/components/spinner/index.tsx +0 -4
  51. package/src/components/spinner/markup/index.tsx +0 -4
  52. package/src/components/spinner/styles/index.scss +0 -0
  53. package/src/components/spinner/types/index.ts +0 -4
  54. package/src/components/spinner/utils/index.ts +0 -4
  55. package/src/hooks/index.ts +0 -4
@@ -1,25 +1,29 @@
1
1
  import type {
2
+ CSSProperties,
2
3
  ComponentPropsWithRef,
3
4
  ComponentPropsWithoutRef,
4
5
  ElementType,
6
+ HTMLAttributes,
7
+ ReactElement,
5
8
  ReactNode,
9
+ Ref,
6
10
  } from "react";
7
11
 
8
12
  /**
9
- * SlotComponentRestProps; as/children/className을 제외한 원본 요소 props.
13
+ * SlotComponentRestProps; as/asChild/children/className을 제외한 원본 요소 props.
10
14
  * @typedef SlotComponentRestProps
11
15
  * @template C
12
16
  * @desc
13
17
  * - HTML/React 공통 속성과 data-* 커스텀 속성을 그대로 포함한다.
14
- * - SlotComponent 내부에서 as/children/className을 재정의하기 위해 제외한다.
18
+ * - SlotComponent 내부에서 as/asChild/children/className을 재정의하기 위해 제외한다.
15
19
  */
16
20
  export type SlotComponentRestProps<C extends ElementType> = Omit<
17
21
  ComponentPropsWithoutRef<C>,
18
- "as" | "children" | "className"
22
+ "as" | "asChild" | "children" | "className"
19
23
  >;
20
24
 
21
25
  /**
22
- * PolymorphicRef; 전달된 as 요소의 ref 타입.
26
+ * PolymorphicRef; as 렌더링된 요소의 ref 타입.
23
27
  * @typedef PolymorphicRef
24
28
  * @template C
25
29
  */
@@ -27,40 +31,132 @@ export type PolymorphicRef<C extends ElementType> =
27
31
  ComponentPropsWithRef<C>["ref"];
28
32
 
29
33
  /**
30
- * SlotComponentProps; as 기반 슬롯 래퍼 공통 props.
31
- * @typedef SlotComponentProps
34
+ * SlotElementProps; asChild 병합에 사용하는 element props
35
+ * @property {string} [className] 병합할 className.
36
+ * @property {React.Ref<unknown>} [ref] 병합할 callback 또는 object ref.
37
+ * @property {React.CSSProperties} [style] 병합할 inline style.
38
+ * @desc Slot과 child의 임의 props를 보존하면서 className, ref와 style 병합 계약을 명시한다.
39
+ */
40
+ export type SlotElementProps = Record<string, unknown> & {
41
+ /**
42
+ * 병합할 className.
43
+ */
44
+ className?: string;
45
+ /**
46
+ * 병합할 callback 또는 object ref.
47
+ */
48
+ ref?: Ref<unknown>;
49
+ /**
50
+ * 병합할 inline style.
51
+ */
52
+ style?: CSSProperties;
53
+ };
54
+
55
+ /**
56
+ * SlotAsChildProps; 단일 child를 wrapper 없이 렌더링하는 Slot props
57
+ * @property {true} asChild wrapper 제거를 활성화하는 discriminator.
58
+ * @property {never} [as] asChild variant에서 허용하지 않는 렌더 요소 override.
59
+ * @property {React.ReactElement} children props와 ref를 병합할 단일 non-Fragment ReactElement.
60
+ * @property {string} [className] Slot className 다음에 child className을 합칠 값.
61
+ * @desc React.HTMLAttributes<HTMLElement>를 Slot-side 공통 속성으로 제공하고 element 전용 속성은 child가 소유한다.
62
+ */
63
+ export type SlotAsChildProps = Omit<
64
+ HTMLAttributes<HTMLElement>,
65
+ "children" | "className"
66
+ > & {
67
+ /**
68
+ * literal true이면 단일 ReactElement를 wrapper 없이 렌더링한다.
69
+ */
70
+ asChild: true;
71
+ /**
72
+ * asChild가 true이면 as를 함께 사용할 수 없다.
73
+ */
74
+ as?: never;
75
+ /**
76
+ * props를 병합할 단일 non-Fragment ReactElement. 그 외 입력은 runtime에서 예외를 던진다.
77
+ */
78
+ children: ReactElement;
79
+ /**
80
+ * Slot className 다음에 child className을 합친다.
81
+ */
82
+ className?: string;
83
+ };
84
+
85
+ /**
86
+ * SlotAsElementProps; as 요소를 렌더링하는 Slot props
32
87
  * @template C
33
- * @property {ElementType} [as] 렌더링할 요소. 기본값은 div.
34
- * @property {React.ReactNode} [children] 그대로 전달되는 children.
35
- * @property {string} [className] 추가 className.
36
- * @desc
37
- * - ComponentPropsWithoutRef<C>를 확장하므로 React/HTML 공통 속성과 사용자 정의 data 속성 모두 전달된다.
38
- * - as/children/className은 Slot에서 직접 제어하기 위해 재정의한다.
88
+ * @property {false} [asChild] as 기반 렌더링을 유지하는 discriminator.
89
+ * @property {C} [as="div"] 렌더링할 요소.
90
+ * @property {React.ReactNode} [children] 렌더링할 children.
91
+ * @property {string} [className] 렌더링한 요소에 전달할 className.
92
+ * @desc SlotComponentRestProps<C>를 확장해 as 요소의 native props를 보존한다.
39
93
  */
40
- export type SlotComponentProps<C extends ElementType> =
94
+ export type SlotAsElementProps<C extends ElementType> =
41
95
  SlotComponentRestProps<C> & {
42
96
  /**
43
- * 교체할 요소. 기본은 'div'.
97
+ * literal false 또는 생략이면 as 요소를 렌더링한다.
98
+ */
99
+ asChild?: false;
100
+ /**
101
+ * 교체할 요소. 기본은 div.
44
102
  */
45
103
  as?: C;
46
104
  /**
47
- * 전달할 children.
105
+ * 전달할 ReactNode.
48
106
  */
49
107
  children?: ReactNode;
50
108
  /**
51
- * 추가 className.
109
+ * 렌더링한 요소에 전달할 className.
52
110
  */
53
111
  className?: string;
54
112
  };
55
113
 
114
+ /**
115
+ * SlotComponentProps; as 또는 asChild 기반 슬롯 렌더링 props.
116
+ * @typedef SlotComponentProps
117
+ * @template C
118
+ * @property {ElementType} [as] asChild가 false일 때 렌더링할 요소. 기본값은 div이며 true variant에서는 허용하지 않는다.
119
+ * @property {true | false} [asChild] true이면 단일 ReactElement를 wrapper 없이 렌더링하고, false 또는 생략이면 as 요소를 렌더링한다.
120
+ * @property {React.ReactElement | React.ReactNode} [children] asChild가 true이면 필수인 단일 non-Fragment ReactElement, false 또는 생략이면 선택적인 ReactNode.
121
+ * @property {string} [className] 두 variant의 공통 className. asChild에서는 Slot className 다음에 child className을 합친다.
122
+ * @desc
123
+ * - asChild가 true이면 Slot-side props는 React.HTMLAttributes<HTMLElement>로 제한하고, anchor/button 같은 element 전용 props는 child에 둔다.
124
+ * - asChild가 false이면 ComponentPropsWithoutRef<C>를 확장하므로 as 요소의 React/HTML 속성을 전달한다.
125
+ * - as/asChild/children/className은 Slot에서 직접 제어하기 위해 재정의한다.
126
+ * - asChild와 as는 함께 사용할 수 없다.
127
+ * - asChild의 일반 props와 같은 style property는 child가 우선한다.
128
+ * - 같은 event handler는 모든 인자를 child, Slot 순서로 전달하고 child 반환값을 보존하며, 첫 번째 인자의 defaultPrevented가 true일 때만 Slot handler를 생략한다.
129
+ * - child ref와 전달된 ref를 합치며 React 19 callback cleanup이 있으면 cleanup 없는 나머지 ref는 null로 해제한다.
130
+ */
131
+ export type SlotComponentProps<C extends ElementType> =
132
+ SlotAsChildProps | SlotAsElementProps<C>;
133
+
56
134
  /**
57
135
  * SlotComponentType; SlotComponent의 forwardRef 타입 시그니처.
58
136
  * @typedef SlotComponentType
59
- * @template C
60
- * @param {SlotComponentProps<C>} props 공통 슬롯 props.
61
- * @param {PolymorphicRef<C>} [props.ref] 전달될 ref.
62
- * @returns {React.ReactNode} 렌더링된 노드.
137
+ * @desc asChild와 as variant의 public callable contract를 각각 제공한다.
63
138
  */
64
- export type SlotComponentType = <C extends ElementType = "div">(
65
- props: SlotComponentProps<C> & { ref?: PolymorphicRef<C> },
66
- ) => ReactNode;
139
+ export type SlotComponentType = {
140
+ /**
141
+ * SlotComponentType; asChild로 단일 HTML child를 렌더링하는 signature.
142
+ * @property {true} asChild wrapper 제거를 활성화한다.
143
+ * @property {React.ReactElement} children props와 ref를 병합할 단일 non-Fragment ReactElement.
144
+ * @property {React.Ref<HTMLElement>} [ref] 실제 HTML element까지 전달할 ref.
145
+ * @desc Slot-side props는 표준 HTMLAttributes로 제한하고 element 전용 props는 child가 소유한다.
146
+ * @return {React.ReactNode} 병합된 단일 child.
147
+ */
148
+ (props: SlotAsChildProps & { ref?: Ref<HTMLElement> }): ReactNode;
149
+ /**
150
+ * SlotComponentType; as로 렌더링 요소를 교체하는 signature.
151
+ * @template C
152
+ * @property {C} [as="div"] 렌더링할 요소.
153
+ * @property {false} [asChild=false] as 기반 렌더링을 유지한다.
154
+ * @property {React.ReactNode} [children] 렌더링할 children.
155
+ * @property {PolymorphicRef<C>} [ref] as 요소에 전달할 ref.
156
+ * @desc as 요소의 ComponentPropsWithoutRef<C>와 ref type을 보존한다.
157
+ * @return {React.ReactNode} as 요소로 렌더링된 노드.
158
+ */
159
+ <C extends ElementType = "div">(
160
+ props: SlotAsElementProps<C> & { ref?: PolymorphicRef<C> },
161
+ ): ReactNode;
162
+ };
@@ -1,5 +1,5 @@
1
1
  import type { ComponentPropsWithoutRef, ElementType } from "react";
2
- import type { SlotComponentProps, SlotTextProps } from "../../slot";
2
+ import type { SlotComponentRestProps, SlotTextProps } from "../../slot";
3
3
 
4
4
  export const TABLE_CELL_ALIGN_OPTIONS = ["left", "center", "right"] as const;
5
5
  export const TABLE_CELL_ALIGN_Y_OPTIONS = ["top", "center", "bottom"] as const;
@@ -155,7 +155,7 @@ export interface TableColumnData<
155
155
  * @property {boolean} [scrollable=false] true면 외부 스크롤 래퍼를 추가한다.
156
156
  * @property {"x" | "y" | "both"} [scrollAxis="x"] scrollable일 때 스크롤 축
157
157
  * @property {ElementType} [scrollAs="div"] scrollable wrapper element
158
- * @property {Omit<SlotComponentProps<ElementType>, "as" | "children" | "className">} [scrollProps] scrollable wrapper native props
158
+ * @property {SlotComponentRestProps<ElementType> & { asChild?: never }} [scrollProps] asChild를 허용하지 않아 wrapper element를 보존하는 scrollable wrapper native props
159
159
  * @property {string} [scrollClassName] 스크롤 래퍼 className
160
160
  * @property {React.ReactNode} [footer] footer 노드
161
161
  * @property {React.ReactNode} [children] body 콘텐츠
@@ -184,12 +184,14 @@ export interface TableContainerProps<
184
184
  */
185
185
  scrollAs?: ElementType;
186
186
  /**
187
- * scrollable wrapper native props
187
+ * asChild를 허용하지 않아 wrapper element를 보존하는 scrollable wrapper native props
188
188
  */
189
- scrollProps?: Omit<
190
- SlotComponentProps<ElementType>,
191
- "as" | "children" | "className"
192
- >;
189
+ scrollProps?: SlotComponentRestProps<ElementType> & {
190
+ /**
191
+ * Table scroll wrapper에서는 wrapper 제거를 허용하지 않는다.
192
+ */
193
+ asChild?: never;
194
+ };
193
195
  /**
194
196
  * 스크롤 래퍼 className
195
197
  */
@@ -5,11 +5,11 @@ import type { TimePickerFooterProps } from "../types";
5
5
  * TimePicker Footer; 삭제와 적용 action을 렌더한다.
6
6
  * @component
7
7
  * @param {TimePickerFooterProps} props
8
- * @param {boolean} props.clearable 삭제 action 노출 여부
9
- * @param {boolean} props.disabled 비활성화 여부
10
- * @param {() => void} props.onClear 삭제 핸들러
11
- * @param {() => void} props.onApply 적용 핸들러
12
- * @returns {ReactNode} TimePicker footer
8
+ * @property {boolean} props.clearable 삭제 action 노출 여부
9
+ * @property {boolean} props.disabled 비활성화 여부
10
+ * @property {() => void} props.onClear 삭제 핸들러
11
+ * @property {() => void} props.onApply 적용 핸들러
12
+ * @desc clearable 상태에 따라 삭제 action을 노출하고 적용 action을 유지한다.
13
13
  * @example
14
14
  * <TimePickerFooter
15
15
  * clearable
@@ -12,13 +12,13 @@ const PERIOD_OPTIONS = [
12
12
  * TimePicker Hour Section; 오전·오후와 시 선택 grid를 렌더한다.
13
13
  * @component
14
14
  * @param {TimePickerHourSectionProps} props
15
- * @param {"12h" | "24h"} props.format 표시 형식
16
- * @param {number | null} props.selectedHour 선택한 표시 시
17
- * @param {"am" | "pm"} props.period 오전·오후
18
- * @param {boolean} props.disabled 비활성화 여부
19
- * @param {(hours: number) => void} props.onHourSelect 시 선택 핸들러
20
- * @param {(period: "am" | "pm") => void} props.onPeriodChange 오전·오후 변경 핸들러
21
- * @returns {ReactNode} 시간 선택 section
15
+ * @property {"12h" | "24h"} props.format 표시 형식
16
+ * @property {number | null} props.selectedHour 선택한 표시 시
17
+ * @property {"am" | "pm"} props.period 오전·오후
18
+ * @property {boolean} props.disabled 비활성화 여부
19
+ * @property {(hours: number) => void} props.onHourSelect 시 선택 핸들러
20
+ * @property {(period: "am" | "pm") => void} props.onPeriodChange 오전·오후 변경 핸들러
21
+ * @desc 12시간제와 24시간제에 맞는 시 목록과 period control을 렌더한다.
22
22
  * @example
23
23
  * <TimePickerHourSection
24
24
  * format="12h"
@@ -8,11 +8,11 @@ const MINUTES = Array.from({ length: 12 }, (_, index) => index * 5);
8
8
  * TimePicker Minute Section; 1분 stepper와 5분 선택 grid를 렌더한다.
9
9
  * @component
10
10
  * @param {TimePickerMinuteSectionProps} props
11
- * @param {number | null} props.selectedMinute 선택한 분
12
- * @param {boolean} props.disabled 비활성화 여부
13
- * @param {(amount: 1 | -1) => void} props.onMinuteStep 1분 증감 핸들러
14
- * @param {(minutes: number) => void} props.onMinuteSelect 분 선택 핸들러
15
- * @returns {ReactNode}선택 section
11
+ * @property {number | null} props.selectedMinute 선택한 분
12
+ * @property {boolean} props.disabled 비활성화 여부
13
+ * @property {(amount: 1 | -1) => void} props.onMinuteStep 1분 증감 핸들러
14
+ * @property {(minutes: number) => void} props.onMinuteSelect 분 선택 핸들러
15
+ * @desc 5분 간격 빠른 선택과 1단위 미세 조정을 함께 제공한다.
16
16
  * @example
17
17
  * <TimePickerMinuteSection
18
18
  * selectedMinute={30}
@@ -4,8 +4,8 @@ import type { TimePickerSummaryProps } from "../types";
4
4
  * TimePicker Summary; 현재 선택한 시간을 표시한다.
5
5
  * @component
6
6
  * @param {TimePickerSummaryProps} props
7
- * @param {string} props.summary 선택한 시간 표시값
8
- * @returns {ReactNode} 선택 시간 요약
7
+ * @property {string} props.summary 선택한 시간 표시값
8
+ * @desc TimePicker panel 상단에 현재 선택값 또는 빈 상태를 표시한다.
9
9
  * @example
10
10
  * <TimePickerSummary summary="09:30 오전" />
11
11
  */
@@ -11,17 +11,17 @@ import TimePickerSummary from "./Summary";
11
11
  * TimePicker Template; Figma의 시간·분 선택과 footer action을 렌더한다.
12
12
  * @component
13
13
  * @param {TimePickerTemplateProps} props
14
- * @param {string} props.value 24시간 형식 시간 값
15
- * @param {"12h" | "24h"} props.format 표시 형식
16
- * @param {boolean} props.clearable 삭제 action 노출 여부
17
- * @param {boolean} props.disabled 비활성화 여부
18
- * @param {(hours: number) => void} props.onHourSelect 시 선택 핸들러
19
- * @param {(minutes: number) => void} props.onMinuteSelect 분 선택 핸들러
20
- * @param {(period: "am" | "pm") => void} props.onPeriodChange 오전·오후 변경 핸들러
21
- * @param {(amount: 1 | -1) => void} props.onMinuteStep 1분 증감 핸들러
22
- * @param {() => void} props.onClear 삭제 핸들러
23
- * @param {() => void} props.onApply 적용 핸들러
24
- * @returns {ReactNode} 시간 선택 panel
14
+ * @property {string} props.value 24시간 형식 시간 값
15
+ * @property {"12h" | "24h"} props.format 표시 형식
16
+ * @property {boolean} props.clearable 삭제 action 노출 여부
17
+ * @property {boolean} props.disabled 비활성화 여부
18
+ * @property {(hours: number) => void} props.onHourSelect 시 선택 핸들러
19
+ * @property {(minutes: number) => void} props.onMinuteSelect 분 선택 핸들러
20
+ * @property {(period: "am" | "pm") => void} props.onPeriodChange 오전·오후 변경 핸들러
21
+ * @property {(amount: 1 | -1) => void} props.onMinuteStep 1분 증감 핸들러
22
+ * @property {() => void} props.onClear 삭제 핸들러
23
+ * @property {() => void} props.onApply 적용 핸들러
24
+ * @desc 24시간 저장값을 표시 형식에 맞춰 시·분 선택 section과 action에 배분한다.
25
25
  * @example
26
26
  * <TimePicker.Template
27
27
  * value="09:30"
@@ -21,6 +21,7 @@ export type TimePickerUnit = "hours" | "minutes" | "seconds";
21
21
  * @property {number} hours 시
22
22
  * @property {number} minutes 분
23
23
  * @property {number} seconds 초
24
+ * @desc 24시간 저장값의 정규화된 시·분·초 숫자 구성
24
25
  */
25
26
  export interface TimePickerParts {
26
27
  /**
@@ -49,6 +50,7 @@ export interface TimePickerParts {
49
50
  * @property {(amount: 1 | -1) => void} onMinuteStep 1분 증감 핸들러
50
51
  * @property {() => void} onClear 삭제 핸들러
51
52
  * @property {() => void} onApply 적용 핸들러
53
+ * @desc TimePicker panel의 선택값, 표시 형식과 action 계약
52
54
  */
53
55
  export interface TimePickerTemplateProps {
54
56
  /**
@@ -96,6 +98,7 @@ export interface TimePickerTemplateProps {
96
98
  /**
97
99
  * TimePicker Summary props.
98
100
  * @property {string} summary 선택한 시간 표시값
101
+ * @desc panel 상단의 현재 선택값 표시 계약
99
102
  */
100
103
  export interface TimePickerSummaryProps {
101
104
  /**
@@ -112,6 +115,7 @@ export interface TimePickerSummaryProps {
112
115
  * @property {boolean} disabled 비활성화 여부
113
116
  * @property {(hours: number) => void} onHourSelect 시 선택 핸들러
114
117
  * @property {(period: "am" | "pm") => void} onPeriodChange 오전·오후 변경 핸들러
118
+ * @desc 표시 형식별 시 목록과 오전·오후 선택 계약
115
119
  */
116
120
  export interface TimePickerHourSectionProps {
117
121
  /**
@@ -146,6 +150,7 @@ export interface TimePickerHourSectionProps {
146
150
  * @property {boolean} disabled 비활성화 여부
147
151
  * @property {(amount: 1 | -1) => void} onMinuteStep 1분 증감 핸들러
148
152
  * @property {(minutes: number) => void} onMinuteSelect 분 선택 핸들러
153
+ * @desc 분 quick select와 1분 step action 계약
149
154
  */
150
155
  export interface TimePickerMinuteSectionProps {
151
156
  /**
@@ -172,6 +177,7 @@ export interface TimePickerMinuteSectionProps {
172
177
  * @property {boolean} disabled 비활성화 여부
173
178
  * @property {() => void} onClear 삭제 핸들러
174
179
  * @property {() => void} onApply 적용 핸들러
180
+ * @desc 삭제 노출 여부와 panel footer action 계약
175
181
  */
176
182
  export interface TimePickerFooterProps {
177
183
  /**
@@ -12,8 +12,10 @@ const wrapTimePart = (value: number, limit: number) =>
12
12
 
13
13
  /**
14
14
  * TimePicker Utility; 24시간 문자열을 시간 값으로 파싱한다.
15
+ * @utility
15
16
  * @param {string} value HH:mm 또는 HH:mm:ss 값
16
- * @returns {TimePickerParts | null} 파싱 결과
17
+ * @desc 형식 또는 시·분·초 범위가 유효하지 않으면 null 반환한다.
18
+ * @return {TimePickerParts | null} 파싱 결과
17
19
  */
18
20
  export const parseTimeValue = (value: string): TimePickerParts | null => {
19
21
  const match = /^(\d{2}):(\d{2})(?::(\d{2}))?$/.exec(value);
@@ -33,9 +35,11 @@ export const parseTimeValue = (value: string): TimePickerParts | null => {
33
35
 
34
36
  /**
35
37
  * TimePicker Utility; 시간 값을 24시간 문자열로 직렬화한다.
38
+ * @utility
36
39
  * @param {TimePickerParts} parts 시간 값
37
40
  * @param {boolean} withSeconds 초 포함 여부
38
- * @returns {string} HH:mm 또는 HH:mm:ss
41
+ * @desc 단위를 자리로 맞추고 withSeconds에 따라 초를 포함한다.
42
+ * @return {string} HH:mm 또는 HH:mm:ss 값
39
43
  */
40
44
  export const serializeTimeValue = (
41
45
  parts: TimePickerParts,
@@ -47,11 +51,13 @@ export const serializeTimeValue = (
47
51
 
48
52
  /**
49
53
  * TimePicker Utility; 지정 단위만 순환 증감한다.
54
+ * @utility
50
55
  * @param {string} value 시간 값
51
- * @param {TimePickerUnit} unit 증감 단위
56
+ * @param {"hours" | "minutes" | "seconds"} unit 증감 단위
52
57
  * @param {number} amount 증감량
53
58
  * @param {boolean} withSeconds 초 포함 여부
54
- * @returns {string} 증감한 시간
59
+ * @desc 값은 00:00 기준으로 시작하고 시는 24, 분·초는 60을 경계로 순환한다.
60
+ * @return {string} 증감한 시간 값
55
61
  */
56
62
  export const stepTimeValue = (
57
63
  value: string,
@@ -73,27 +79,33 @@ export const stepTimeValue = (
73
79
 
74
80
  /**
75
81
  * TimePicker Utility; 저장 시를 표시 시로 변환한다.
82
+ * @utility
76
83
  * @param {number} hours 24시간 시 값
77
- * @param {TimePickerFormat} format 표시 형식
78
- * @returns {number} 표시
84
+ * @param {"12h" | "24h"} format 표시 형식
85
+ * @desc 12시간제에서는 0시와 12시를 12로 표시한다.
86
+ * @return {number} 표시 시 값
79
87
  */
80
88
  export const toDisplayHour = (hours: number, format: TimePickerFormat) =>
81
89
  format === "12h" ? hours % 12 || 12 : hours;
82
90
 
83
91
  /**
84
92
  * TimePicker Utility; 24시간 시 값의 오전·오후를 반환한다.
93
+ * @utility
85
94
  * @param {number} hours 24시간 시 값
86
- * @returns {TimePickerPeriod} 오전·오후
95
+ * @desc 12시 이상을 pm, 그 미만을 am으로 분류한다.
96
+ * @return {"am" | "pm"} 오전·오후
87
97
  */
88
98
  export const getTimePeriod = (hours: number): TimePickerPeriod =>
89
99
  hours >= 12 ? "pm" : "am";
90
100
 
91
101
  /**
92
102
  * TimePicker Utility; 오전·오후를 24시간 저장값에 반영한다.
103
+ * @utility
93
104
  * @param {string} value 시간 값
94
- * @param {TimePickerPeriod} period 오전·오후
105
+ * @param {"am" | "pm"} period 오전·오후
95
106
  * @param {boolean} withSeconds 초 포함 여부
96
- * @returns {string} 변경한 시간
107
+ * @desc 기존 분·초를 보존하고 선택한 period에 맞춰 저장 시만 변환한다.
108
+ * @return {string} 변경한 시간 값
97
109
  */
98
110
  export const setTimePeriod = (
99
111
  value: string,
package/src/index.scss CHANGED
@@ -15,10 +15,8 @@
15
15
  @use "./components/pagination";
16
16
  @use "./components/pop-over";
17
17
  @use "./components/radio";
18
- @use "./components/scrollbar";
19
18
  @use "./components/segmented-control";
20
19
  @use "./components/select";
21
- @use "./components/spinner";
22
20
  @use "./components/switch";
23
21
  @use "./components/tab";
24
22
  @use "./components/table";
package/src/index.tsx CHANGED
@@ -20,15 +20,21 @@ export * from "./components/navigation";
20
20
  export * from "./components/pagination";
21
21
  export * from "./components/pop-over";
22
22
  export * from "./components/radio";
23
- export * from "./components/scrollbar";
24
23
  export * from "./components/segmented-control";
25
24
  export * from "./components/select";
26
25
  export * from "./components/slot";
27
- export * from "./components/spinner";
28
26
  export * from "./components/switch";
29
27
  export * from "./components/tab";
30
28
  export * from "./components/table";
31
29
  export * from "./components/time-picker";
32
30
  export * from "./components/toast";
33
31
  export * from "./components/tooltip";
32
+ export {
33
+ isSameSelectedValue,
34
+ isSameSelectedValueList,
35
+ normalizeSelectedValuesByMode,
36
+ normalizeSingleSelectedValue,
37
+ toSelectedValueKey,
38
+ } from "./utils";
34
39
  export type * from "./types";
40
+ export type { SelectedValue } from "./utils";
@@ -1,4 +1 @@
1
- /**
2
- * shared types placeholder: variant/slot 타입을 정의하고 각 카테고리에서 import한다.
3
- */
4
- export * from "./form-field";
1
+ export type * from "./form-field";
@@ -1,4 +1,8 @@
1
- /**
2
- * shared utils placeholder: 토큰 매핑 및 className 헬퍼를 정의한다.
3
- */
4
- export * from "./selected-values";
1
+ export {
2
+ isSameSelectedValue,
3
+ isSameSelectedValueList,
4
+ normalizeSelectedValuesByMode,
5
+ normalizeSingleSelectedValue,
6
+ toSelectedValueKey,
7
+ } from "./selected-values";
8
+ export type { SelectedValue } from "./selected-values";
@@ -1,25 +1,25 @@
1
- /**
2
- * Selected Values Utils; value 기반 선택 비교/정규화 유틸
3
- */
4
-
5
1
  /**
6
2
  * Select/Dropdown value 원시 타입
7
3
  */
8
4
  export type SelectedValue = string | number;
9
5
 
10
6
  /**
11
- * value를 비교 키 문자열로 정규화
7
+ * Selected Values; value를 비교 키 문자열로 정규화
8
+ * @function
12
9
  * @param {SelectedValue | undefined} value 비교 대상 value
13
- * @returns {string} 정규화된 문자열
10
+ * @desc Select와 Dropdown이 문자열·숫자 value를 같은 비교 축으로 다룰 수 있게 한다.
11
+ * @return {string} 정규화된 키 문자열
14
12
  */
15
13
  export const toSelectedValueKey = (value?: SelectedValue): string =>
16
14
  value === undefined ? "" : String(value);
17
15
 
18
16
  /**
19
- * 단일 value 동등성 비교
17
+ * Selected Values; 단일 value 동등성 비교
18
+ * @function
20
19
  * @param {SelectedValue | undefined} previousValue 이전 value
21
20
  * @param {SelectedValue | undefined} nextValue 다음 value
22
- * @returns {boolean} 동등 여부
21
+ * @desc 문자열·숫자 표현 차이를 정규화한 뒤 두 선택값의 동등성을 판정한다.
22
+ * @return {boolean} 동등 여부
23
23
  */
24
24
  export const isSameSelectedValue = (
25
25
  previousValue?: SelectedValue,
@@ -28,10 +28,12 @@ export const isSameSelectedValue = (
28
28
  toSelectedValueKey(previousValue) === toSelectedValueKey(nextValue);
29
29
 
30
30
  /**
31
- * value 배열 동등성 비교
31
+ * Selected Values; value 배열 동등성 비교
32
+ * @function
32
33
  * @param {SelectedValue[]} previousValues 이전 value 배열
33
34
  * @param {SelectedValue[]} nextValues 다음 value 배열
34
- * @returns {boolean} 동등 여부
35
+ * @desc 선택 순서를 포함해 두 value 배열이 같은지 판정한다.
36
+ * @return {boolean} 동등 여부
35
37
  */
36
38
  export const isSameSelectedValueList = (
37
39
  previousValues: SelectedValue[],
@@ -43,19 +45,23 @@ export const isSameSelectedValueList = (
43
45
  );
44
46
 
45
47
  /**
46
- * 단일 선택 value 정규화
48
+ * Selected Values; 단일 선택 value 정규화
49
+ * @function
47
50
  * @param {SelectedValue[]} selectedValues 선택 value 배열
48
- * @returns {SelectedValue | undefined} 단일 선택 결과
51
+ * @desc 선택 배열의 value를 단일 선택 결과로 사용한다.
52
+ * @return {SelectedValue | undefined} 단일 선택 결과
49
53
  */
50
54
  export const normalizeSingleSelectedValue = (
51
55
  selectedValues: SelectedValue[],
52
56
  ): SelectedValue | undefined => selectedValues[0];
53
57
 
54
58
  /**
55
- * 모드 기반 value 배열 정규화
59
+ * Selected Values; 모드 기반 value 배열 정규화
60
+ * @function
56
61
  * @param {SelectedValue[]} selectedValues 선택 value 배열
57
62
  * @param {boolean} multiple 다중 선택 모드 여부
58
- * @returns {SelectedValue[]} 모드 규칙 적용 결과
63
+ * @desc 다중 선택은 전체 배열을 유지하고 단일 선택은 첫 value만 유지한다.
64
+ * @return {SelectedValue[]} 모드 규칙 적용 결과
59
65
  */
60
66
  export const normalizeSelectedValuesByMode = (
61
67
  selectedValues: SelectedValue[],
@@ -1,4 +0,0 @@
1
- /**
2
- * Scrollbar Hooks; 현재 공개된 훅이 없는 placeholder 엔트리
3
- */
4
- export {};
File without changes
@@ -1 +0,0 @@
1
- @use "./styles/index.scss";
@@ -1,4 +0,0 @@
1
- /**
2
- * Scrollbar; 현재 public export가 없는 placeholder 카테고리 배럴
3
- */
4
- export * from "./markup";
@@ -1,4 +0,0 @@
1
- /**
2
- * Scrollbar Markup; 현재 공개된 컴포넌트가 없는 placeholder 엔트리
3
- */
4
- export {};
File without changes
@@ -1,4 +0,0 @@
1
- /**
2
- * Scrollbar Types; 현재 공개된 타입이 없는 placeholder 엔트리
3
- */
4
- export {};
@@ -1,4 +0,0 @@
1
- /**
2
- * Scrollbar Utils; 현재 공개된 유틸이 없는 placeholder 엔트리
3
- */
4
- export {};
@@ -1,4 +0,0 @@
1
- /**
2
- * Spinner Hooks; 현재 공개된 훅이 없는 placeholder 엔트리
3
- */
4
- export {};
File without changes
@@ -1 +0,0 @@
1
- @use "./styles/index.scss";
@@ -1,4 +0,0 @@
1
- /**
2
- * Spinner; 현재 public export가 없는 placeholder 카테고리 배럴
3
- */
4
- export * from "./markup";
@@ -1,4 +0,0 @@
1
- /**
2
- * Spinner Markup; 현재 공개된 컴포넌트가 없는 placeholder 엔트리
3
- */
4
- export {};
File without changes