@uniai-fe/uds-primitives 0.6.4 → 0.6.5
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/dist/styles.css +179 -4
- package/package.json +1 -1
- package/src/components/calendar/index.tsx +1 -0
- package/src/components/calendar/markup/Core.tsx +13 -2
- package/src/components/calendar/markup/index.tsx +5 -0
- package/src/components/calendar/markup/range/Core.tsx +92 -0
- package/src/components/calendar/markup/range/Root.tsx +133 -0
- package/src/components/calendar/markup/range/index.tsx +15 -0
- package/src/components/calendar/styles/mantine-calendar.scss +162 -4
- package/src/components/calendar/types/calendar.ts +150 -0
- package/src/components/calendar/utils/value-mapper.ts +37 -4
- package/src/components/input/markup/date/Template.tsx +1 -4
- package/src/components/input/markup/date/index.tsx +11 -0
- package/src/components/input/markup/date/range/Template.tsx +261 -0
- package/src/components/input/styles/date.scss +44 -0
- package/src/components/input/types/date.ts +114 -3
- package/src/components/input/utils/date.ts +41 -1
|
@@ -21,6 +21,18 @@
|
|
|
21
21
|
z-index: 30;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
.calendar-range-root,
|
|
25
|
+
.calendar-range-grid {
|
|
26
|
+
// 변경: range는 Figma 2 calendar 기준으로 두 month column을 같은 panel에 고정한다.
|
|
27
|
+
--calendar-range-column-width: 322px;
|
|
28
|
+
--calendar-range-column-gap: var(--spacing-gap-6);
|
|
29
|
+
--calendar-width: calc(
|
|
30
|
+
(var(--calendar-range-column-width) * 2) +
|
|
31
|
+
var(--calendar-range-column-gap) + (var(--calendar-inline-padding) * 2)
|
|
32
|
+
);
|
|
33
|
+
max-width: min(100vw - (var(--spacing-padding-5) * 2), 720px);
|
|
34
|
+
}
|
|
35
|
+
|
|
24
36
|
.calendar-header {
|
|
25
37
|
margin-bottom: var(--spacing-gap-2);
|
|
26
38
|
}
|
|
@@ -34,6 +46,10 @@
|
|
|
34
46
|
width: var(--calendar-body-width);
|
|
35
47
|
}
|
|
36
48
|
|
|
49
|
+
.calendar-range-grid {
|
|
50
|
+
width: var(--calendar-body-width);
|
|
51
|
+
}
|
|
52
|
+
|
|
37
53
|
.calendar-grid table {
|
|
38
54
|
width: auto;
|
|
39
55
|
}
|
|
@@ -48,6 +64,17 @@
|
|
|
48
64
|
width: 100%;
|
|
49
65
|
}
|
|
50
66
|
|
|
67
|
+
.calendar-range-grid .calendar-month-level {
|
|
68
|
+
display: grid;
|
|
69
|
+
grid-template-columns: repeat(2, var(--calendar-range-column-width));
|
|
70
|
+
column-gap: var(--calendar-range-column-gap);
|
|
71
|
+
align-items: start;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.calendar-range-grid .calendar-month-level > [data-month-level="true"] {
|
|
75
|
+
width: var(--calendar-range-column-width);
|
|
76
|
+
}
|
|
77
|
+
|
|
51
78
|
.calendar-header-row {
|
|
52
79
|
display: grid;
|
|
53
80
|
grid-template-columns: 44px 1fr 44px;
|
|
@@ -55,7 +82,8 @@
|
|
|
55
82
|
width: 100%;
|
|
56
83
|
max-width: none;
|
|
57
84
|
column-gap: var(--spacing-gap-5);
|
|
58
|
-
|
|
85
|
+
// 변경: page navigation arrow는 Figma처럼 calendar header row 양 끝에 붙인다.
|
|
86
|
+
padding: 0;
|
|
59
87
|
margin-bottom: var(--spacing-gap-5);
|
|
60
88
|
--dch-fz: var(--font-heading-small-size) !important;
|
|
61
89
|
}
|
|
@@ -64,7 +92,7 @@
|
|
|
64
92
|
width: 44px;
|
|
65
93
|
height: 44px;
|
|
66
94
|
border-radius: 999px;
|
|
67
|
-
display:
|
|
95
|
+
display: flex;
|
|
68
96
|
align-items: center;
|
|
69
97
|
justify-content: center;
|
|
70
98
|
color: var(--color-label-alternative);
|
|
@@ -74,15 +102,26 @@
|
|
|
74
102
|
}
|
|
75
103
|
|
|
76
104
|
.calendar-header-control[data-direction="previous"] {
|
|
105
|
+
grid-column: 1;
|
|
106
|
+
grid-row: 1;
|
|
77
107
|
justify-self: start;
|
|
78
108
|
}
|
|
79
109
|
|
|
80
110
|
.calendar-header-control[data-direction="next"] {
|
|
111
|
+
grid-column: 3;
|
|
112
|
+
grid-row: 1;
|
|
81
113
|
justify-self: end;
|
|
82
114
|
}
|
|
83
115
|
|
|
84
116
|
.calendar-header-level {
|
|
117
|
+
// 변경: range 두 번째 month처럼 이전 버튼이 없는 header에서도 level을 중앙 column에 고정한다.
|
|
118
|
+
grid-column: 2;
|
|
119
|
+
grid-row: 1;
|
|
85
120
|
justify-self: center;
|
|
121
|
+
display: flex;
|
|
122
|
+
align-items: center;
|
|
123
|
+
justify-content: center;
|
|
124
|
+
gap: var(--spacing-gap-4);
|
|
86
125
|
font-size: var(--font-heading-small-size);
|
|
87
126
|
font-weight: var(--font-heading-small-weight);
|
|
88
127
|
text-align: center;
|
|
@@ -93,6 +132,18 @@
|
|
|
93
132
|
color: var(--color-label-strong);
|
|
94
133
|
}
|
|
95
134
|
|
|
135
|
+
.calendar-header-level::after {
|
|
136
|
+
// 변경: Mantine header level button에 Figma의 연/월 선택 up-down 표시를 CSS layer에서 보강한다.
|
|
137
|
+
content: "";
|
|
138
|
+
flex: 0 0 auto;
|
|
139
|
+
width: 20px;
|
|
140
|
+
height: 20px;
|
|
141
|
+
background-image: url("data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 20 20' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M6.66675 8.33333L10.0001 5L13.3334 8.33333' stroke='%2394989E' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M6.66675 11.6667L10.0001 15L13.3334 11.6667' stroke='%2394989E' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
|
142
|
+
background-repeat: no-repeat;
|
|
143
|
+
background-position: center;
|
|
144
|
+
background-size: 20px 20px;
|
|
145
|
+
}
|
|
146
|
+
|
|
96
147
|
.calendar-header-control:where(:not([data-disabled="true"])):hover {
|
|
97
148
|
background-color: var(--color-tertiary-default);
|
|
98
149
|
color: var(--color-label-standard);
|
|
@@ -215,18 +266,105 @@
|
|
|
215
266
|
padding: 0;
|
|
216
267
|
border: none;
|
|
217
268
|
border-radius: var(--theme-radius-large-1);
|
|
269
|
+
box-sizing: border-box;
|
|
270
|
+
display: flex;
|
|
271
|
+
align-items: center;
|
|
272
|
+
justify-content: center;
|
|
218
273
|
font-size: var(--font-body-medium-size);
|
|
219
274
|
color: var(--color-label-standard);
|
|
220
275
|
}
|
|
221
276
|
|
|
277
|
+
.calendar-day-label {
|
|
278
|
+
width: 44px;
|
|
279
|
+
height: 44px;
|
|
280
|
+
box-sizing: border-box;
|
|
281
|
+
display: flex;
|
|
282
|
+
align-items: center;
|
|
283
|
+
justify-content: center;
|
|
284
|
+
position: relative;
|
|
285
|
+
color: inherit;
|
|
286
|
+
}
|
|
287
|
+
|
|
222
288
|
.calendar-day[data-outside="true"] {
|
|
223
289
|
color: var(--color-label-alternative);
|
|
224
290
|
}
|
|
225
291
|
|
|
226
292
|
.calendar-day[data-selected="true"],
|
|
227
293
|
.calendar-day[data-focused="true"] {
|
|
294
|
+
color: var(--color-common-100);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.calendar-day:where([data-in-range]) {
|
|
298
|
+
// 변경: button은 period surface만 담당해 selected blue layer와 range bridge를 분리한다.
|
|
299
|
+
background-color: var(--color-surface-static-blue);
|
|
300
|
+
color: var(--color-label-standard);
|
|
301
|
+
border-radius: 0;
|
|
302
|
+
box-shadow:
|
|
303
|
+
-1px 0 0 var(--color-surface-static-blue),
|
|
304
|
+
1px 0 0 var(--color-surface-static-blue);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.calendar-day:where([data-first-in-range]) {
|
|
308
|
+
border-start-start-radius: var(--theme-radius-medium-3);
|
|
309
|
+
border-end-start-radius: var(--theme-radius-medium-3);
|
|
310
|
+
box-shadow: 1px 0 0 var(--color-surface-static-blue);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.calendar-day:where([data-last-in-range]) {
|
|
314
|
+
border-start-end-radius: var(--theme-radius-medium-3);
|
|
315
|
+
border-end-end-radius: var(--theme-radius-medium-3);
|
|
316
|
+
box-shadow: -1px 0 0 var(--color-surface-static-blue);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.calendar-day:where([data-first-in-range][data-last-in-range]) {
|
|
320
|
+
box-shadow: none;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.calendar-day:where([data-selected="true"], [data-focused="true"]) {
|
|
324
|
+
background-color: transparent;
|
|
325
|
+
color: var(--color-common-100);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.calendar-day:where([data-in-range][data-selected="true"]) {
|
|
329
|
+
background-color: var(--color-surface-static-blue);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.calendar-day:where([data-selected="true"], [data-focused="true"])
|
|
333
|
+
.calendar-day-label {
|
|
228
334
|
background-color: var(--color-primary-default);
|
|
229
335
|
color: var(--color-common-100);
|
|
336
|
+
border-radius: var(--theme-radius-medium-3);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.calendar-day:where(
|
|
340
|
+
[data-today][data-highlight-today]:not(
|
|
341
|
+
[data-selected="true"],
|
|
342
|
+
[data-in-range],
|
|
343
|
+
[data-disabled="true"]
|
|
344
|
+
)
|
|
345
|
+
) {
|
|
346
|
+
// 변경: today는 Figma node처럼 selected와 별개인 border/dot 레이어로 표현한다.
|
|
347
|
+
border: 1px solid var(--color-primary-default);
|
|
348
|
+
color: var(--color-label-standard);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.calendar-day:where(
|
|
352
|
+
[data-today][data-highlight-today]:not(
|
|
353
|
+
[data-selected="true"],
|
|
354
|
+
[data-in-range],
|
|
355
|
+
[data-disabled="true"]
|
|
356
|
+
)
|
|
357
|
+
)
|
|
358
|
+
.calendar-day-label::after {
|
|
359
|
+
content: "";
|
|
360
|
+
width: 4px;
|
|
361
|
+
height: 4px;
|
|
362
|
+
border-radius: 999px;
|
|
363
|
+
background-color: var(--color-primary-default);
|
|
364
|
+
position: absolute;
|
|
365
|
+
bottom: 7px;
|
|
366
|
+
left: 50%;
|
|
367
|
+
transform: translateX(-50%);
|
|
230
368
|
}
|
|
231
369
|
|
|
232
370
|
.calendar-day:where(:disabled, [data-disabled="true"]) {
|
|
@@ -234,10 +372,30 @@
|
|
|
234
372
|
color: var(--color-label-disabled);
|
|
235
373
|
}
|
|
236
374
|
|
|
237
|
-
.calendar-day:where(
|
|
375
|
+
.calendar-day:where(
|
|
376
|
+
:not(
|
|
377
|
+
[data-disabled="true"],
|
|
378
|
+
[data-selected="true"],
|
|
379
|
+
[data-focused="true"],
|
|
380
|
+
[data-in-range]
|
|
381
|
+
)
|
|
382
|
+
):hover {
|
|
238
383
|
background-color: var(--color-secondary-default);
|
|
239
384
|
color: var(--color-label-standard);
|
|
240
|
-
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.calendar-day:where([data-selected="true"]):hover {
|
|
388
|
+
background-color: transparent;
|
|
389
|
+
color: var(--color-common-100);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.calendar-day:where([data-in-range][data-selected="true"]):hover {
|
|
393
|
+
background-color: var(--color-surface-static-blue);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.calendar-day:where([data-selected="true"]):hover .calendar-day-label {
|
|
397
|
+
background-color: var(--color-primary-default);
|
|
398
|
+
color: var(--color-common-100);
|
|
241
399
|
}
|
|
242
400
|
|
|
243
401
|
.calendar-footer {
|
|
@@ -22,6 +22,23 @@ export type CalendarColumns = 1 | 2;
|
|
|
22
22
|
*/
|
|
23
23
|
export type CalendarValue = string | null;
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Calendar range value 직렬화 타입.
|
|
27
|
+
* @property {CalendarValue} start 시작 날짜 YYYY-MM-DD 문자열 또는 null
|
|
28
|
+
* @property {CalendarValue} end 종료 날짜 YYYY-MM-DD 문자열 또는 null
|
|
29
|
+
*/
|
|
30
|
+
export type CalendarRangeValue = [CalendarValue, CalendarValue];
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Calendar range DatePicker 내부 값 타입.
|
|
34
|
+
* @property {Date | string | null} start DatePicker 시작 날짜 값
|
|
35
|
+
* @property {Date | string | null} end DatePicker 종료 날짜 값
|
|
36
|
+
*/
|
|
37
|
+
export type CalendarRangePickerValue = [
|
|
38
|
+
Date | string | null,
|
|
39
|
+
Date | string | null,
|
|
40
|
+
];
|
|
41
|
+
|
|
25
42
|
/**
|
|
26
43
|
* Calendar 값 변경 핸들러.
|
|
27
44
|
* @param {CalendarValue} value 선택된 직렬화 값
|
|
@@ -32,6 +49,16 @@ export type CalendarValue = string | null;
|
|
|
32
49
|
*/
|
|
33
50
|
export type CalendarOnChange = (value: CalendarValue) => void;
|
|
34
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Calendar range 값 변경 핸들러.
|
|
54
|
+
* @param {CalendarRangeValue} value 선택된 range 직렬화 tuple
|
|
55
|
+
* @example
|
|
56
|
+
* const onChange = (value: CalendarRangeValue) => {
|
|
57
|
+
* console.log(value);
|
|
58
|
+
* };
|
|
59
|
+
*/
|
|
60
|
+
export type CalendarRangeOnChange = (value: CalendarRangeValue) => void;
|
|
61
|
+
|
|
35
62
|
/**
|
|
36
63
|
* Mantine DatePicker 공개 옵션.
|
|
37
64
|
* @property {Partial<Record<DatePickerStylesNames, string>>} [classNames] Mantine 내부 스타일 클래스 매핑
|
|
@@ -54,6 +81,28 @@ export type CalendarDatePickerProps = Partial<
|
|
|
54
81
|
classNames?: Partial<Record<DatePickerStylesNames, string>>;
|
|
55
82
|
};
|
|
56
83
|
|
|
84
|
+
/**
|
|
85
|
+
* Mantine range DatePicker 공개 옵션.
|
|
86
|
+
* @property {Partial<Record<DatePickerStylesNames, string>>} [classNames] Mantine range 내부 스타일 클래스 매핑
|
|
87
|
+
*/
|
|
88
|
+
export type CalendarRangeDatePickerProps = Partial<
|
|
89
|
+
Omit<
|
|
90
|
+
MantineDatePickerProps<"range">,
|
|
91
|
+
| "value"
|
|
92
|
+
| "defaultValue"
|
|
93
|
+
| "onChange"
|
|
94
|
+
| "type"
|
|
95
|
+
| "numberOfColumns"
|
|
96
|
+
| "classNames"
|
|
97
|
+
| "styles"
|
|
98
|
+
>
|
|
99
|
+
> & {
|
|
100
|
+
/**
|
|
101
|
+
* Mantine range 내부 스타일 classNames override.
|
|
102
|
+
*/
|
|
103
|
+
classNames?: Partial<Record<DatePickerStylesNames, string>>;
|
|
104
|
+
};
|
|
105
|
+
|
|
57
106
|
/**
|
|
58
107
|
* Calendar Grid props.
|
|
59
108
|
* @property {CalendarValue} value 현재 선택 값
|
|
@@ -75,6 +124,27 @@ export interface CalendarGridProps {
|
|
|
75
124
|
datePickerProps?: CalendarDatePickerProps;
|
|
76
125
|
}
|
|
77
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Calendar Range Grid props.
|
|
129
|
+
* @property {CalendarRangeValue} value 현재 range 선택 값
|
|
130
|
+
* @property {CalendarRangeOnChange} onChange range 값 변경 핸들러
|
|
131
|
+
* @property {CalendarRangeDatePickerProps} [datePickerProps] Mantine range DatePicker 옵션
|
|
132
|
+
*/
|
|
133
|
+
export interface CalendarRangeGridProps {
|
|
134
|
+
/**
|
|
135
|
+
* 현재 range 선택 값
|
|
136
|
+
*/
|
|
137
|
+
value: CalendarRangeValue;
|
|
138
|
+
/**
|
|
139
|
+
* range 값 변경 핸들러
|
|
140
|
+
*/
|
|
141
|
+
onChange: CalendarRangeOnChange;
|
|
142
|
+
/**
|
|
143
|
+
* Mantine range DatePicker 옵션
|
|
144
|
+
*/
|
|
145
|
+
datePickerProps?: CalendarRangeDatePickerProps;
|
|
146
|
+
}
|
|
147
|
+
|
|
78
148
|
/**
|
|
79
149
|
* Calendar Layout Container props.
|
|
80
150
|
* @property {ReactNode} [header] 상단 콘텐츠
|
|
@@ -196,6 +266,86 @@ export interface CalendarRootProps extends Omit<
|
|
|
196
266
|
portalContainer?: HTMLElement | null;
|
|
197
267
|
}
|
|
198
268
|
|
|
269
|
+
/**
|
|
270
|
+
* Calendar Range Root props.
|
|
271
|
+
* @extends CalendarContainerProps
|
|
272
|
+
* @property {string} [className] Trigger element className override
|
|
273
|
+
* @property {CalendarRangeValue} value 현재 range 선택 값
|
|
274
|
+
* @property {CalendarRangeOnChange} onChange range 값 변경 핸들러
|
|
275
|
+
* @property {CalendarRangeDatePickerProps} [datePickerProps] Mantine range DatePicker 옵션
|
|
276
|
+
* @property {ReactNode} children Trigger 슬롯(children)
|
|
277
|
+
* @property {boolean} [open] 제어형 open 상태
|
|
278
|
+
* @property {boolean} [defaultOpen] 비제어 초기 open 상태
|
|
279
|
+
* @property {(open: boolean) => void} [onOpenChange] open 상태 변경 핸들러
|
|
280
|
+
* @property {"top" | "right" | "bottom" | "left"} [side="bottom"] content 배치 방향
|
|
281
|
+
* @property {"start" | "center" | "end"} [align="start"] content 정렬 기준
|
|
282
|
+
* @property {number} [sideOffset=4] trigger와 content 간격
|
|
283
|
+
* @property {number} [alignOffset] 정렬 보정값
|
|
284
|
+
* @property {boolean} [withPortal=true] Portal 사용 여부
|
|
285
|
+
* @property {HTMLElement | null} [portalContainer] Portal 컨테이너
|
|
286
|
+
*/
|
|
287
|
+
export interface CalendarRangeRootProps extends Omit<
|
|
288
|
+
CalendarContainerProps,
|
|
289
|
+
"body" | "columns"
|
|
290
|
+
> {
|
|
291
|
+
/**
|
|
292
|
+
* Trigger element className override
|
|
293
|
+
*/
|
|
294
|
+
className?: string;
|
|
295
|
+
/**
|
|
296
|
+
* 현재 range 선택 값
|
|
297
|
+
*/
|
|
298
|
+
value: CalendarRangeValue;
|
|
299
|
+
/**
|
|
300
|
+
* range 값 변경 핸들러
|
|
301
|
+
*/
|
|
302
|
+
onChange: CalendarRangeOnChange;
|
|
303
|
+
/**
|
|
304
|
+
* Mantine range DatePicker 옵션
|
|
305
|
+
*/
|
|
306
|
+
datePickerProps?: CalendarRangeDatePickerProps;
|
|
307
|
+
/**
|
|
308
|
+
* Trigger 슬롯(children)
|
|
309
|
+
*/
|
|
310
|
+
children: ReactNode;
|
|
311
|
+
/**
|
|
312
|
+
* 제어형 open 상태
|
|
313
|
+
*/
|
|
314
|
+
open?: boolean;
|
|
315
|
+
/**
|
|
316
|
+
* 비제어 초기 open 상태
|
|
317
|
+
*/
|
|
318
|
+
defaultOpen?: boolean;
|
|
319
|
+
/**
|
|
320
|
+
* open 상태 변경 핸들러
|
|
321
|
+
*/
|
|
322
|
+
onOpenChange?: (open: boolean) => void;
|
|
323
|
+
/**
|
|
324
|
+
* content 배치 방향
|
|
325
|
+
*/
|
|
326
|
+
side?: "top" | "right" | "bottom" | "left";
|
|
327
|
+
/**
|
|
328
|
+
* content 정렬 기준
|
|
329
|
+
*/
|
|
330
|
+
align?: "start" | "center" | "end";
|
|
331
|
+
/**
|
|
332
|
+
* trigger와 content 간격
|
|
333
|
+
*/
|
|
334
|
+
sideOffset?: number;
|
|
335
|
+
/**
|
|
336
|
+
* 정렬 보정값
|
|
337
|
+
*/
|
|
338
|
+
alignOffset?: number;
|
|
339
|
+
/**
|
|
340
|
+
* Portal 사용 여부
|
|
341
|
+
*/
|
|
342
|
+
withPortal?: boolean;
|
|
343
|
+
/**
|
|
344
|
+
* Portal 컨테이너
|
|
345
|
+
*/
|
|
346
|
+
portalContainer?: HTMLElement | null;
|
|
347
|
+
}
|
|
348
|
+
|
|
199
349
|
/**
|
|
200
350
|
* Calendar 섹션 공용 props.
|
|
201
351
|
* @property {ReactNode} [children] 섹션 내부 콘텐츠
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { dayjs } from "../../../init/dayjs";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
CalendarRangePickerValue,
|
|
4
|
+
CalendarRangeValue,
|
|
5
|
+
CalendarValue,
|
|
6
|
+
} from "../types";
|
|
3
7
|
|
|
4
8
|
const DATE_FORMAT = "YYYY-MM-DD";
|
|
5
9
|
|
|
@@ -15,10 +19,39 @@ export const mapValueToPicker = (value: CalendarValue) =>
|
|
|
15
19
|
|
|
16
20
|
/**
|
|
17
21
|
* DatePicker value를 Calendar 직렬화 값으로 변환한다.
|
|
18
|
-
* @param {Date | null} value DatePicker value
|
|
22
|
+
* @param {Date | string | null} value DatePicker value
|
|
19
23
|
* @returns {CalendarValue} YYYY-MM-DD 직렬화 값
|
|
20
24
|
* @example
|
|
21
25
|
* parseValueFromPicker(new Date("2026-02-13"));
|
|
22
26
|
*/
|
|
23
|
-
export const parseValueFromPicker = (
|
|
24
|
-
value
|
|
27
|
+
export const parseValueFromPicker = (
|
|
28
|
+
value: Date | string | null,
|
|
29
|
+
): CalendarValue => (value ? dayjs(value).format(DATE_FORMAT) : null);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Calendar range value를 DatePicker range value로 변환한다.
|
|
33
|
+
* @param {CalendarRangeValue} value YYYY-MM-DD range tuple
|
|
34
|
+
* @returns {[Date | null, Date | null]} DatePicker range value
|
|
35
|
+
* @example
|
|
36
|
+
* mapRangeValueToPicker(["2026-02-13", "2026-02-20"]);
|
|
37
|
+
*/
|
|
38
|
+
export const mapRangeValueToPicker = (
|
|
39
|
+
value: CalendarRangeValue,
|
|
40
|
+
): [Date | null, Date | null] => [
|
|
41
|
+
mapValueToPicker(value[0]),
|
|
42
|
+
mapValueToPicker(value[1]),
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* DatePicker range value를 Calendar range 직렬화 값으로 변환한다.
|
|
47
|
+
* @param {CalendarRangePickerValue} value DatePicker range value
|
|
48
|
+
* @returns {CalendarRangeValue} YYYY-MM-DD range 직렬화 tuple
|
|
49
|
+
* @example
|
|
50
|
+
* parseRangeValueFromPicker([new Date("2026-02-13"), new Date("2026-02-20")]);
|
|
51
|
+
*/
|
|
52
|
+
export const parseRangeValueFromPicker = (
|
|
53
|
+
value: CalendarRangePickerValue,
|
|
54
|
+
): CalendarRangeValue => [
|
|
55
|
+
parseValueFromPicker(value[0]),
|
|
56
|
+
parseValueFromPicker(value[1]),
|
|
57
|
+
];
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import type { ChangeEvent, MouseEvent as ReactMouseEvent } from "react";
|
|
4
4
|
import { forwardRef, useCallback, useMemo, useState } from "react";
|
|
5
5
|
import { useUncontrolled } from "@mantine/hooks";
|
|
6
|
-
import clsx from "clsx";
|
|
7
6
|
import { Calendar } from "../../../calendar";
|
|
8
7
|
import type {
|
|
9
8
|
InputCalendarProps,
|
|
@@ -46,7 +45,6 @@ const INPUT_DATE_TABLE_FORMAT = "YY-MM-DD";
|
|
|
46
45
|
* @param {unknown} [props.timePicker] TimePicker 확장용 예약 슬롯(현재 미구현)
|
|
47
46
|
* @param {boolean} [props.calendarOpened] calendar 열림 제어 상태
|
|
48
47
|
* @param {(event: MouseEvent<Element>) => void} [props.onClick] trigger 클릭 핸들러
|
|
49
|
-
* @param {string} [props.className] root className
|
|
50
48
|
* @param {string} [props.id] trigger id
|
|
51
49
|
* @param {ReactNode} [props.trigger] 커스텀 trigger 슬롯
|
|
52
50
|
* @param {(props: InputCalendarTriggerRenderProps) => ReactNode} [props.renderTrigger] 커스텀 trigger 렌더 함수
|
|
@@ -68,7 +66,6 @@ const InputDateTemplate = forwardRef<HTMLDivElement, InputCalendarProps>(
|
|
|
68
66
|
placeholder = "YYYY-MM-DD",
|
|
69
67
|
priority = "primary",
|
|
70
68
|
state = "default",
|
|
71
|
-
className,
|
|
72
69
|
header,
|
|
73
70
|
footer,
|
|
74
71
|
calendarOpened,
|
|
@@ -182,7 +179,7 @@ const InputDateTemplate = forwardRef<HTMLDivElement, InputCalendarProps>(
|
|
|
182
179
|
<>
|
|
183
180
|
<Calendar.Root
|
|
184
181
|
ref={ref}
|
|
185
|
-
className=
|
|
182
|
+
className="input-date-field"
|
|
186
183
|
mode={mode}
|
|
187
184
|
columns={columns}
|
|
188
185
|
disabled={disabled}
|
|
@@ -4,15 +4,26 @@ import InputDateTrigger from "./Trigger";
|
|
|
4
4
|
import InputDateApplyButton from "./button/ApplyButton";
|
|
5
5
|
import InputDateClearButton from "./button/ClearButton";
|
|
6
6
|
import InputDateTodayButton from "./button/TodayButton";
|
|
7
|
+
import InputDateRangeTemplate from "./range/Template";
|
|
7
8
|
import {
|
|
8
9
|
InputDateFooterTemplate,
|
|
9
10
|
InputDateFooterTemplateContainer,
|
|
10
11
|
InputDateFooterUtilContainer,
|
|
11
12
|
} from "./footer";
|
|
12
13
|
|
|
14
|
+
export const InputDateDefault = {
|
|
15
|
+
Template: InputDateTemplate,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const InputDateRange = {
|
|
19
|
+
Template: InputDateRangeTemplate,
|
|
20
|
+
};
|
|
21
|
+
|
|
13
22
|
// Input.Date 네임스페이스: template/foundation 구성요소 집합
|
|
14
23
|
export const InputDate = {
|
|
15
24
|
Template: InputDateTemplate,
|
|
25
|
+
Default: InputDateDefault,
|
|
26
|
+
Range: InputDateRange,
|
|
16
27
|
Trigger: InputDateTrigger,
|
|
17
28
|
Button: {
|
|
18
29
|
Apply: InputDateApplyButton,
|