@uniai-fe/uds-primitives 0.10.4 → 0.12.0

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 (35) hide show
  1. package/README.md +38 -452
  2. package/dist/styles.css +1233 -508
  3. package/package.json +3 -3
  4. package/src/components/button/markup/Base.tsx +1 -1
  5. package/src/components/button/styles/button.scss +84 -1
  6. package/src/components/button/styles/variables.scss +73 -0
  7. package/src/components/button/types/options.ts +8 -0
  8. package/src/components/button/types/props.ts +30 -6
  9. package/src/components/input/markup/address/Button.tsx +1 -1
  10. package/src/components/input/markup/time/Template.tsx +423 -0
  11. package/src/components/input/markup/time/Trigger.tsx +289 -0
  12. package/src/components/input/markup/time/index.tsx +2 -2
  13. package/src/components/input/styles/time.scss +160 -317
  14. package/src/components/input/styles/variables.scss +9 -47
  15. package/src/components/input/types/time.ts +61 -120
  16. package/src/components/time-picker/img/minus.svg +3 -0
  17. package/src/components/time-picker/img/plus.svg +3 -0
  18. package/src/components/time-picker/index.scss +1 -0
  19. package/src/components/time-picker/index.tsx +11 -0
  20. package/src/components/time-picker/markup/Footer.tsx +71 -0
  21. package/src/components/time-picker/markup/HourSection.tsx +99 -0
  22. package/src/components/time-picker/markup/MinuteSection.tsx +86 -0
  23. package/src/components/time-picker/markup/Summary.tsx +24 -0
  24. package/src/components/time-picker/markup/Template.tsx +86 -0
  25. package/src/components/time-picker/markup/index.tsx +10 -0
  26. package/src/components/time-picker/styles/index.scss +2 -0
  27. package/src/components/time-picker/styles/template.scss +174 -0
  28. package/src/components/time-picker/styles/variables.scss +64 -0
  29. package/src/components/time-picker/types/index.ts +1 -0
  30. package/src/components/time-picker/types/time-picker.ts +94 -0
  31. package/src/components/time-picker/utils/index.ts +1 -0
  32. package/src/components/time-picker/utils/time.ts +110 -0
  33. package/src/index.scss +1 -0
  34. package/src/index.tsx +1 -0
  35. package/src/components/input/markup/time/Picker.tsx +0 -378
@@ -1,22 +1,17 @@
1
- import type { PopoverProps, ScrollAreaProps } from "@mantine/core";
2
- import type {
3
- TimePickerAmPmLabels,
4
- TimePickerFormat,
5
- TimePickerPasteSplit,
6
- TimePickerPresets,
7
- } from "@mantine/dates";
8
1
  import type { ComponentPropsWithoutRef, FocusEvent, ReactNode } from "react";
9
2
  import type { UseFormRegisterReturn } from "react-hook-form";
10
3
  import type { FormFieldWidth } from "../../form/types/props";
4
+ import type { TimePickerFormat } from "../../time-picker/types";
11
5
  import type { InputPriority, InputSize, InputState } from "./foundation";
12
6
 
13
7
  /**
14
- * Input Time icon position.
8
+ * Input Time icon 위치.
9
+ * @typedef {"left" | "right"} InputTimeIconPosition
15
10
  */
16
11
  export type InputTimeIconPosition = "left" | "right";
17
12
 
18
13
  /**
19
- * Input TimePicker hidden input props.
14
+ * Input Time hidden input props.
20
15
  */
21
16
  export type InputTimeHiddenInputProps = Omit<
22
17
  ComponentPropsWithoutRef<"input">,
@@ -24,7 +19,8 @@ export type InputTimeHiddenInputProps = Omit<
24
19
  >;
25
20
 
26
21
  /**
27
- * Input TimePicker props.
22
+ * Input Time Template props.
23
+ * 저장값은 24시간 `HH:mm` 또는 `HH:mm:ss` 문자열을 사용한다.
28
24
  * @property {string} [value] 제어형 시간 값
29
25
  * @property {string} [defaultValue] 비제어 초기 시간 값
30
26
  * @property {(value:string)=>void} [onChange] 값 변경 핸들러
@@ -32,234 +28,179 @@ export type InputTimeHiddenInputProps = Omit<
32
28
  * @property {string} [name] form name
33
29
  * @property {string} [form] form id
34
30
  * @property {UseFormRegisterReturn} [register] react-hook-form register 결과
35
- * @property {InputPriority} [priority] input priority
36
- * @property {InputSize} [size] input size
37
- * @property {InputState} [state] input state
31
+ * @property {"primary" | "secondary" | "tertiary" | "table"} [priority] input priority
32
+ * @property {"small" | "medium" | "large"} [size] input size
33
+ * @property {"default" | "active" | "focused" | "success" | "error" | "disabled" | "loading"} [state] input state
38
34
  * @property {boolean} [block] width 100% 여부
39
- * @property {"full" | "fit" | "fill" | "auto" | number | string} [width] width preset 옵션
35
+ * @property {"full" | "fit" | "fill" | "auto" | number | string} [width] width preset
40
36
  * @property {string} [className] root className
41
37
  * @property {boolean} [disabled] disabled 여부
42
38
  * @property {boolean} [readOnly] readOnly 여부
43
39
  * @property {boolean} [required] required 여부
44
40
  * @property {string} [id] root id
45
- * @property {"12h" | "24h"} [format] 표시/입력 시간 포맷
46
- * @property {boolean} [withSeconds] seconds 입력 노출 여부
47
- * @property {boolean} [withDropdown] dropdown 노출 여부
48
- * @property {boolean} [clearable] clear 버튼 노출 여부
49
- * @property {string} [min] 최소 시간
50
- * @property {string} [max] 최대 시간
51
- * @property {number} [hoursStep] hour step
52
- * @property {number} [minutesStep] minute step
53
- * @property {number} [secondsStep] second step
41
+ * @property {"12h" | "24h"} [format] 표시 형식
42
+ * @property {boolean} [withSeconds] field 노출 여부
43
+ * @property {boolean} [clearable] 삭제 액션 노출 여부
44
+ * @property {number} [hoursStep] 증감 단위
45
+ * @property {number} [minutesStep] 증감 단위
46
+ * @property {number} [secondsStep] 증감 단위
54
47
  * @property {ReactNode} [icon] clock icon override
55
48
  * @property {"left" | "right"} [iconPosition] clock icon 위치
56
49
  * @property {string} [iconLabel] clock icon 접근성 라벨
57
- * @property {string} [clearButtonLabel] clear 버튼 접근성 라벨
58
- * @property {PopoverProps} [popoverProps] Mantine Popover 옵션
59
- * @property {InputTimeHiddenInputProps} [hiddenInputProps] hidden input 옵션
60
- * @property {string} [hoursInputLabel] hour input aria-label
61
- * @property {string} [minutesInputLabel] minute input aria-label
62
- * @property {string} [secondsInputLabel] second input aria-label
63
- * @property {string} [amPmInputLabel] am/pm input aria-label
64
- * @property {TimePickerAmPmLabels} [amPmLabels] am/pm 라벨
65
- * @property {string} [hoursPlaceholder] hour placeholder
66
- * @property {string} [minutesPlaceholder] minute placeholder
67
- * @property {string} [secondsPlaceholder] second placeholder
68
- * @property {TimePickerPasteSplit} [pasteSplit] paste parser
69
- * @property {TimePickerPresets} [presets] dropdown preset
70
- * @property {number} [maxDropdownContentHeight] dropdown 최대 높이
71
- * @property {ScrollAreaProps} [scrollAreaProps] dropdown scroll area 옵션
72
- * @property {boolean} [reverseTimeControlsList] dropdown control 역순 여부
50
+ * @property {InputTimeHiddenInputProps} [hiddenInputProps] hidden input props
51
+ * @property {string} [hoursInputLabel] input 접근성 라벨
52
+ * @property {string} [minutesInputLabel] input 접근성 라벨
53
+ * @property {string} [secondsInputLabel] input 접근성 라벨
54
+ * @property {string} [amPmInputLabel] 오전/오후 접근성 라벨
55
+ * @property {string} [hoursPlaceholder] placeholder
56
+ * @property {string} [minutesPlaceholder] placeholder
57
+ * @property {string} [secondsPlaceholder] placeholder
73
58
  * @property {(event:FocusEvent<HTMLInputElement>)=>void} [onFocus] focus 핸들러
74
59
  * @property {(event:FocusEvent<HTMLDivElement>)=>void} [onBlur] blur 핸들러
75
60
  */
76
- export interface InputTimePickerProps {
61
+ export interface InputTimeTemplateProps {
77
62
  /**
78
- * 제어형 시간
63
+ * 제어형 시간 값.
79
64
  */
80
65
  value?: string;
81
66
  /**
82
- * 비제어 초기 시간
67
+ * 비제어 초기 시간 값.
83
68
  */
84
69
  defaultValue?: string;
85
70
  /**
86
- * 값 변경 핸들러
71
+ * 값 변경 핸들러.
87
72
  */
88
73
  onChange?: (value: string) => void;
89
74
  /**
90
- * 값 변경 별칭
75
+ * 값 변경 별칭.
91
76
  */
92
77
  onValueChange?: (value: string) => void;
93
78
  /**
94
- * form name
79
+ * form name.
95
80
  */
96
81
  name?: string;
97
82
  /**
98
- * form id
83
+ * form id.
99
84
  */
100
85
  form?: string;
101
86
  /**
102
- * react-hook-form register 결과
87
+ * react-hook-form register 결과.
103
88
  */
104
89
  register?: UseFormRegisterReturn;
105
90
  /**
106
- * input priority
91
+ * "primary" | "secondary" | "tertiary" | "table".
107
92
  */
108
93
  priority?: InputPriority;
109
94
  /**
110
- * input size
95
+ * "small" | "medium" | "large".
111
96
  */
112
97
  size?: InputSize;
113
98
  /**
114
- * input state
99
+ * "default" | "active" | "focused" | "success" | "error" | "disabled" | "loading".
115
100
  */
116
101
  state?: InputState;
117
102
  /**
118
- * width 100% 여부
103
+ * width 100% 여부.
119
104
  */
120
105
  block?: boolean;
121
106
  /**
122
- * width preset 옵션
107
+ * "full" | "fit" | "fill" | "auto" | number | string.
123
108
  */
124
109
  width?: FormFieldWidth;
125
110
  /**
126
- * root className
111
+ * root className.
127
112
  */
128
113
  className?: string;
129
114
  /**
130
- * disabled 여부
115
+ * disabled 여부.
131
116
  */
132
117
  disabled?: boolean;
133
118
  /**
134
- * readOnly 여부
119
+ * readOnly 여부.
135
120
  */
136
121
  readOnly?: boolean;
137
122
  /**
138
- * required 여부
123
+ * required 여부.
139
124
  */
140
125
  required?: boolean;
141
126
  /**
142
- * root id
127
+ * root id.
143
128
  */
144
129
  id?: string;
145
130
  /**
146
- * 표시/입력 시간 포맷
131
+ * "12h" | "24h".
147
132
  */
148
133
  format?: TimePickerFormat;
149
134
  /**
150
- * seconds 입력 노출 여부
135
+ * field 노출 여부.
151
136
  */
152
137
  withSeconds?: boolean;
153
138
  /**
154
- * dropdown 노출 여부
155
- */
156
- withDropdown?: boolean;
157
- /**
158
- * clear 버튼 노출 여부
139
+ * 삭제 액션 노출 여부.
159
140
  */
160
141
  clearable?: boolean;
161
142
  /**
162
- * 최소 시간
163
- */
164
- min?: string;
165
- /**
166
- * 최대 시간 값
167
- */
168
- max?: string;
169
- /**
170
- * hour step
143
+ * 증감 단위.
171
144
  */
172
145
  hoursStep?: number;
173
146
  /**
174
- * minute step
147
+ * 증감 단위.
175
148
  */
176
149
  minutesStep?: number;
177
150
  /**
178
- * second step
151
+ * 증감 단위.
179
152
  */
180
153
  secondsStep?: number;
181
154
  /**
182
- * clock icon override
155
+ * clock icon override.
183
156
  */
184
157
  icon?: ReactNode;
185
158
  /**
186
- * clock icon 위치
159
+ * "left" | "right".
187
160
  */
188
161
  iconPosition?: InputTimeIconPosition;
189
162
  /**
190
- * clock icon 접근성 라벨
163
+ * clock icon 접근성 라벨.
191
164
  */
192
165
  iconLabel?: string;
193
166
  /**
194
- * clear 버튼 접근성 라벨
195
- */
196
- clearButtonLabel?: string;
197
- /**
198
- * Mantine Popover 옵션
199
- */
200
- popoverProps?: PopoverProps;
201
- /**
202
- * hidden input 옵션
167
+ * hidden input props.
203
168
  */
204
169
  hiddenInputProps?: InputTimeHiddenInputProps;
205
170
  /**
206
- * hour input aria-label
171
+ * input 접근성 라벨.
207
172
  */
208
173
  hoursInputLabel?: string;
209
174
  /**
210
- * minute input aria-label
175
+ * input 접근성 라벨.
211
176
  */
212
177
  minutesInputLabel?: string;
213
178
  /**
214
- * second input aria-label
179
+ * input 접근성 라벨.
215
180
  */
216
181
  secondsInputLabel?: string;
217
182
  /**
218
- * am/pm input aria-label
183
+ * 오전/오후 접근성 라벨.
219
184
  */
220
185
  amPmInputLabel?: string;
221
186
  /**
222
- * am/pm 라벨
223
- */
224
- amPmLabels?: TimePickerAmPmLabels;
225
- /**
226
- * hour placeholder
187
+ * placeholder.
227
188
  */
228
189
  hoursPlaceholder?: string;
229
190
  /**
230
- * minute placeholder
191
+ * placeholder.
231
192
  */
232
193
  minutesPlaceholder?: string;
233
194
  /**
234
- * second placeholder
195
+ * placeholder.
235
196
  */
236
197
  secondsPlaceholder?: string;
237
198
  /**
238
- * paste parser
239
- */
240
- pasteSplit?: TimePickerPasteSplit;
241
- /**
242
- * dropdown preset
243
- */
244
- presets?: TimePickerPresets;
245
- /**
246
- * dropdown 최대 높이
247
- */
248
- maxDropdownContentHeight?: number;
249
- /**
250
- * dropdown scroll area 옵션
251
- */
252
- scrollAreaProps?: ScrollAreaProps;
253
- /**
254
- * dropdown control 역순 여부
255
- */
256
- reverseTimeControlsList?: boolean;
257
- /**
258
- * focus 핸들러
199
+ * focus 핸들러.
259
200
  */
260
201
  onFocus?: (event: FocusEvent<HTMLInputElement>) => void;
261
202
  /**
262
- * blur 핸들러
203
+ * blur 핸들러.
263
204
  */
264
205
  onBlur?: (event: FocusEvent<HTMLDivElement>) => void;
265
206
  }
@@ -0,0 +1,3 @@
1
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2ZM8 11.2002C7.55817 11.2002 7.2002 11.5582 7.2002 12C7.2002 12.4418 7.55817 12.7998 8 12.7998H16C16.4418 12.7998 16.7998 12.4418 16.7998 12C16.7998 11.5582 16.4418 11.2002 16 11.2002H8Z" fill="#3A3C46"/>
3
+ </svg>
@@ -0,0 +1,3 @@
1
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2ZM12 7.20508C11.5582 7.20508 11.2002 7.56306 11.2002 8.00488V11.2051H8C7.55817 11.2051 7.2002 11.5631 7.2002 12.0049C7.2002 12.4467 7.55817 12.8047 8 12.8047H11.2002V16.0049C11.2002 16.4467 11.5582 16.8047 12 16.8047C12.4418 16.8047 12.7998 16.4467 12.7998 16.0049V12.8047H16C16.4418 12.8047 16.7998 12.4467 16.7998 12.0049C16.7998 11.5631 16.4418 11.2051 16 11.2051H12.7998V8.00488C12.7998 7.56306 12.4418 7.20508 12 7.20508Z" fill="#3A3C46"/>
3
+ </svg>
@@ -0,0 +1 @@
1
+ @use "./styles/index.scss";
@@ -0,0 +1,11 @@
1
+ /**
2
+ * TimePicker; 시간 선택 패널 카테고리 배럴.
3
+ * @desc
4
+ * - `TimePicker.Template`: 시간·분 선택과 footer action을 제공한다.
5
+ * - `TimePickerUtils`: 시간 파싱·직렬화·증감 유틸리티다.
6
+ */
7
+ import "./index.scss";
8
+
9
+ export * from "./markup";
10
+ export * as TimePickerUtils from "./utils";
11
+ export type * from "./types";
@@ -0,0 +1,71 @@
1
+ import { Button } from "../../button";
2
+
3
+ interface TimePickerFooterProps {
4
+ /**
5
+ * 삭제 action 노출 여부.
6
+ */
7
+ clearable: boolean;
8
+ /**
9
+ * 비활성화 여부.
10
+ */
11
+ disabled: boolean;
12
+ /**
13
+ * 삭제 핸들러.
14
+ */
15
+ onClear: () => void;
16
+ /**
17
+ * 적용 핸들러.
18
+ */
19
+ onApply: () => void;
20
+ }
21
+
22
+ /**
23
+ * TimePicker Footer; 삭제와 적용 action을 렌더한다.
24
+ * @component
25
+ * @param {TimePickerFooterProps} props
26
+ * @param {boolean} props.clearable 삭제 action 노출 여부
27
+ * @param {boolean} props.disabled 비활성화 여부
28
+ * @param {() => void} props.onClear 삭제 핸들러
29
+ * @param {() => void} props.onApply 적용 핸들러
30
+ * @returns {ReactNode} TimePicker footer
31
+ * @example
32
+ * <TimePickerFooter
33
+ * clearable
34
+ * disabled={false}
35
+ * onClear={onClear}
36
+ * onApply={onApply}
37
+ * />
38
+ */
39
+ export default function TimePickerFooter({
40
+ clearable,
41
+ disabled,
42
+ onClear,
43
+ onApply,
44
+ }: TimePickerFooterProps) {
45
+ return (
46
+ <footer className="time-picker-template-footer">
47
+ {clearable ? (
48
+ <button
49
+ type="button"
50
+ className="time-picker-clear-action"
51
+ disabled={disabled}
52
+ onClick={onClear}
53
+ >
54
+ 삭제하기
55
+ </button>
56
+ ) : (
57
+ <span />
58
+ )}
59
+ <Button.Default
60
+ type="button"
61
+ priority="primary"
62
+ fill="solid"
63
+ size="large"
64
+ disabled={disabled}
65
+ onClick={onApply}
66
+ >
67
+ 적용하기
68
+ </Button.Default>
69
+ </footer>
70
+ );
71
+ }
@@ -0,0 +1,99 @@
1
+ import { SegmentedControl } from "../../segmented-control";
2
+ import type { TimePickerFormat, TimePickerPeriod } from "../types";
3
+
4
+ const HOURS_12 = Array.from({ length: 12 }, (_, index) => index + 1);
5
+ const HOURS_24 = Array.from({ length: 24 }, (_, index) => index);
6
+ const PERIOD_OPTIONS = [
7
+ { value: "am", label: "오전" },
8
+ { value: "pm", label: "오후" },
9
+ ];
10
+
11
+ interface TimePickerHourSectionProps {
12
+ /**
13
+ * "12h" | "24h".
14
+ */
15
+ format: TimePickerFormat;
16
+ /**
17
+ * 선택한 표시 시.
18
+ */
19
+ selectedHour: number | null;
20
+ /**
21
+ * "am" | "pm".
22
+ */
23
+ period: TimePickerPeriod;
24
+ /**
25
+ * 비활성화 여부.
26
+ */
27
+ disabled: boolean;
28
+ /**
29
+ * 시 선택 핸들러.
30
+ */
31
+ onHourSelect: (hours: number) => void;
32
+ /**
33
+ * 오전·오후 변경 핸들러.
34
+ */
35
+ onPeriodChange: (period: TimePickerPeriod) => void;
36
+ }
37
+
38
+ /**
39
+ * TimePicker Hour Section; 오전·오후와 시 선택 grid를 렌더한다.
40
+ * @component
41
+ * @param {TimePickerHourSectionProps} props
42
+ * @param {"12h" | "24h"} props.format 표시 형식
43
+ * @param {number | null} props.selectedHour 선택한 표시 시
44
+ * @param {"am" | "pm"} props.period 오전·오후
45
+ * @param {boolean} props.disabled 비활성화 여부
46
+ * @param {(hours: number) => void} props.onHourSelect 시 선택 핸들러
47
+ * @param {(period: "am" | "pm") => void} props.onPeriodChange 오전·오후 변경 핸들러
48
+ * @returns {ReactNode} 시간 선택 section
49
+ * @example
50
+ * <TimePickerHourSection
51
+ * format="12h"
52
+ * selectedHour={9}
53
+ * period="am"
54
+ * disabled={false}
55
+ * onHourSelect={onHourSelect}
56
+ * onPeriodChange={onPeriodChange}
57
+ * />
58
+ */
59
+ export default function TimePickerHourSection({
60
+ format,
61
+ selectedHour,
62
+ period,
63
+ disabled,
64
+ onHourSelect,
65
+ onPeriodChange,
66
+ }: TimePickerHourSectionProps) {
67
+ const hours = format === "12h" ? HOURS_12 : HOURS_24;
68
+
69
+ return (
70
+ <section className="time-picker-template-section">
71
+ <h3>시간 선택</h3>
72
+ {format === "12h" ? (
73
+ <SegmentedControl
74
+ className="time-picker-period-control"
75
+ options={PERIOD_OPTIONS}
76
+ ariaLabel="오전 또는 오후 선택"
77
+ value={period}
78
+ onValueChange={nextPeriod =>
79
+ onPeriodChange(nextPeriod === "pm" ? "pm" : "am")
80
+ }
81
+ />
82
+ ) : null}
83
+ <div className="time-picker-option-grid">
84
+ {hours.map(hour => (
85
+ <button
86
+ key={`time-picker/hour/${hour}`}
87
+ type="button"
88
+ className="time-picker-option"
89
+ aria-pressed={selectedHour === hour}
90
+ disabled={disabled}
91
+ onClick={() => onHourSelect(hour)}
92
+ >
93
+ {hour}:00
94
+ </button>
95
+ ))}
96
+ </div>
97
+ </section>
98
+ );
99
+ }
@@ -0,0 +1,86 @@
1
+ import MinusIcon from "../img/minus.svg";
2
+ import PlusIcon from "../img/plus.svg";
3
+
4
+ const MINUTES = Array.from({ length: 12 }, (_, index) => index * 5);
5
+
6
+ interface TimePickerMinuteSectionProps {
7
+ /**
8
+ * 선택한 분.
9
+ */
10
+ selectedMinute: number | null;
11
+ /**
12
+ * 비활성화 여부.
13
+ */
14
+ disabled: boolean;
15
+ /**
16
+ * 1분 증감 핸들러.
17
+ */
18
+ onMinuteStep: (amount: 1 | -1) => void;
19
+ /**
20
+ * 분 선택 핸들러.
21
+ */
22
+ onMinuteSelect: (minutes: number) => void;
23
+ }
24
+
25
+ /**
26
+ * TimePicker Minute Section; 1분 stepper와 5분 선택 grid를 렌더한다.
27
+ * @component
28
+ * @param {TimePickerMinuteSectionProps} props
29
+ * @param {number | null} props.selectedMinute 선택한 분
30
+ * @param {boolean} props.disabled 비활성화 여부
31
+ * @param {(amount: 1 | -1) => void} props.onMinuteStep 1분 증감 핸들러
32
+ * @param {(minutes: number) => void} props.onMinuteSelect 분 선택 핸들러
33
+ * @returns {ReactNode} 분 선택 section
34
+ * @example
35
+ * <TimePickerMinuteSection
36
+ * selectedMinute={30}
37
+ * disabled={false}
38
+ * onMinuteStep={onMinuteStep}
39
+ * onMinuteSelect={onMinuteSelect}
40
+ * />
41
+ */
42
+ export default function TimePickerMinuteSection({
43
+ selectedMinute,
44
+ disabled,
45
+ onMinuteStep,
46
+ onMinuteSelect,
47
+ }: TimePickerMinuteSectionProps) {
48
+ return (
49
+ <section className="time-picker-template-section">
50
+ <h3>분 선택</h3>
51
+ <div className="time-picker-minute-stepper">
52
+ <button
53
+ type="button"
54
+ aria-label="1분 증가"
55
+ disabled={disabled}
56
+ onClick={() => onMinuteStep(1)}
57
+ >
58
+ <PlusIcon aria-hidden="true" />
59
+ </button>
60
+ <strong>{String(selectedMinute ?? 0).padStart(2, "0")}분</strong>
61
+ <button
62
+ type="button"
63
+ aria-label="1분 감소"
64
+ disabled={disabled}
65
+ onClick={() => onMinuteStep(-1)}
66
+ >
67
+ <MinusIcon aria-hidden="true" />
68
+ </button>
69
+ </div>
70
+ <div className="time-picker-option-grid">
71
+ {MINUTES.map(minute => (
72
+ <button
73
+ key={`time-picker/minute/${minute}`}
74
+ type="button"
75
+ className="time-picker-option"
76
+ aria-pressed={selectedMinute === minute}
77
+ disabled={disabled}
78
+ onClick={() => onMinuteSelect(minute)}
79
+ >
80
+ {String(minute).padStart(2, "0")}
81
+ </button>
82
+ ))}
83
+ </div>
84
+ </section>
85
+ );
86
+ }
@@ -0,0 +1,24 @@
1
+ interface TimePickerSummaryProps {
2
+ /**
3
+ * 선택한 시간 표시값.
4
+ */
5
+ summary: string;
6
+ }
7
+
8
+ /**
9
+ * TimePicker Summary; 현재 선택한 시간을 표시한다.
10
+ * @component
11
+ * @param {TimePickerSummaryProps} props
12
+ * @param {string} props.summary 선택한 시간 표시값
13
+ * @returns {ReactNode} 선택 시간 요약
14
+ * @example
15
+ * <TimePickerSummary summary="09:30 오전" />
16
+ */
17
+ export default function TimePickerSummary({ summary }: TimePickerSummaryProps) {
18
+ return (
19
+ <div className="time-picker-summary">
20
+ <span>선택한 시간</span>
21
+ <strong>{summary}</strong>
22
+ </div>
23
+ );
24
+ }