@kalyx/react 0.2.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 (127) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/LICENSE +21 -0
  3. package/README.md +88 -0
  4. package/dist/components/DatePicker/Calendar.d.ts +23 -0
  5. package/dist/components/DatePicker/Calendar.d.ts.map +1 -0
  6. package/dist/components/DatePicker/Calendar.js +127 -0
  7. package/dist/components/DatePicker/Calendar.js.map +1 -0
  8. package/dist/components/DatePicker/Input.d.ts +7 -0
  9. package/dist/components/DatePicker/Input.d.ts.map +1 -0
  10. package/dist/components/DatePicker/Input.js +73 -0
  11. package/dist/components/DatePicker/Input.js.map +1 -0
  12. package/dist/components/DatePicker/MonthGrid.d.ts +34 -0
  13. package/dist/components/DatePicker/MonthGrid.d.ts.map +1 -0
  14. package/dist/components/DatePicker/MonthGrid.js +54 -0
  15. package/dist/components/DatePicker/MonthGrid.js.map +1 -0
  16. package/dist/components/DatePicker/Popover.d.ts +6 -0
  17. package/dist/components/DatePicker/Popover.d.ts.map +1 -0
  18. package/dist/components/DatePicker/Popover.js +72 -0
  19. package/dist/components/DatePicker/Popover.js.map +1 -0
  20. package/dist/components/DatePicker/Root.d.ts +46 -0
  21. package/dist/components/DatePicker/Root.d.ts.map +1 -0
  22. package/dist/components/DatePicker/Root.js +90 -0
  23. package/dist/components/DatePicker/Root.js.map +1 -0
  24. package/dist/components/DatePicker/Trigger.d.ts +6 -0
  25. package/dist/components/DatePicker/Trigger.d.ts.map +1 -0
  26. package/dist/components/DatePicker/Trigger.js +21 -0
  27. package/dist/components/DatePicker/Trigger.js.map +1 -0
  28. package/dist/components/DatePicker/YearGrid.d.ts +29 -0
  29. package/dist/components/DatePicker/YearGrid.d.ts.map +1 -0
  30. package/dist/components/DatePicker/YearGrid.js +53 -0
  31. package/dist/components/DatePicker/YearGrid.js.map +1 -0
  32. package/dist/components/DatePicker/index.d.ts +48 -0
  33. package/dist/components/DatePicker/index.d.ts.map +1 -0
  34. package/dist/components/DatePicker/index.js +42 -0
  35. package/dist/components/DatePicker/index.js.map +1 -0
  36. package/dist/components/DateTimePicker/Input.d.ts +12 -0
  37. package/dist/components/DateTimePicker/Input.d.ts.map +1 -0
  38. package/dist/components/DateTimePicker/Input.js +41 -0
  39. package/dist/components/DateTimePicker/Input.js.map +1 -0
  40. package/dist/components/DateTimePicker/Root.d.ts +60 -0
  41. package/dist/components/DateTimePicker/Root.d.ts.map +1 -0
  42. package/dist/components/DateTimePicker/Root.js +140 -0
  43. package/dist/components/DateTimePicker/Root.js.map +1 -0
  44. package/dist/components/DateTimePicker/index.d.ts +55 -0
  45. package/dist/components/DateTimePicker/index.d.ts.map +1 -0
  46. package/dist/components/DateTimePicker/index.js +55 -0
  47. package/dist/components/DateTimePicker/index.js.map +1 -0
  48. package/dist/components/RangePicker/Calendar.d.ts +24 -0
  49. package/dist/components/RangePicker/Calendar.d.ts.map +1 -0
  50. package/dist/components/RangePicker/Calendar.js +134 -0
  51. package/dist/components/RangePicker/Calendar.js.map +1 -0
  52. package/dist/components/RangePicker/Input.d.ts +14 -0
  53. package/dist/components/RangePicker/Input.d.ts.map +1 -0
  54. package/dist/components/RangePicker/Input.js +38 -0
  55. package/dist/components/RangePicker/Input.js.map +1 -0
  56. package/dist/components/RangePicker/Popover.d.ts +6 -0
  57. package/dist/components/RangePicker/Popover.d.ts.map +1 -0
  58. package/dist/components/RangePicker/Popover.js +71 -0
  59. package/dist/components/RangePicker/Popover.js.map +1 -0
  60. package/dist/components/RangePicker/Presets.d.ts +49 -0
  61. package/dist/components/RangePicker/Presets.d.ts.map +1 -0
  62. package/dist/components/RangePicker/Presets.js +117 -0
  63. package/dist/components/RangePicker/Presets.js.map +1 -0
  64. package/dist/components/RangePicker/Root.d.ts +40 -0
  65. package/dist/components/RangePicker/Root.d.ts.map +1 -0
  66. package/dist/components/RangePicker/Root.js +138 -0
  67. package/dist/components/RangePicker/Root.js.map +1 -0
  68. package/dist/components/RangePicker/index.d.ts +48 -0
  69. package/dist/components/RangePicker/index.d.ts.map +1 -0
  70. package/dist/components/RangePicker/index.js +43 -0
  71. package/dist/components/RangePicker/index.js.map +1 -0
  72. package/dist/components/TimePicker/AmPmToggle.d.ts +15 -0
  73. package/dist/components/TimePicker/AmPmToggle.d.ts.map +1 -0
  74. package/dist/components/TimePicker/AmPmToggle.js +29 -0
  75. package/dist/components/TimePicker/AmPmToggle.js.map +1 -0
  76. package/dist/components/TimePicker/HourList.d.ts +18 -0
  77. package/dist/components/TimePicker/HourList.d.ts.map +1 -0
  78. package/dist/components/TimePicker/HourList.js +71 -0
  79. package/dist/components/TimePicker/HourList.js.map +1 -0
  80. package/dist/components/TimePicker/Input.d.ts +9 -0
  81. package/dist/components/TimePicker/Input.d.ts.map +1 -0
  82. package/dist/components/TimePicker/Input.js +37 -0
  83. package/dist/components/TimePicker/Input.js.map +1 -0
  84. package/dist/components/TimePicker/MinuteList.d.ts +15 -0
  85. package/dist/components/TimePicker/MinuteList.d.ts.map +1 -0
  86. package/dist/components/TimePicker/MinuteList.js +62 -0
  87. package/dist/components/TimePicker/MinuteList.js.map +1 -0
  88. package/dist/components/TimePicker/Root.d.ts +38 -0
  89. package/dist/components/TimePicker/Root.d.ts.map +1 -0
  90. package/dist/components/TimePicker/Root.js +40 -0
  91. package/dist/components/TimePicker/Root.js.map +1 -0
  92. package/dist/components/TimePicker/index.d.ts +32 -0
  93. package/dist/components/TimePicker/index.d.ts.map +1 -0
  94. package/dist/components/TimePicker/index.js +27 -0
  95. package/dist/components/TimePicker/index.js.map +1 -0
  96. package/dist/context/DatePickerContext.d.ts +49 -0
  97. package/dist/context/DatePickerContext.d.ts.map +1 -0
  98. package/dist/context/DatePickerContext.js +18 -0
  99. package/dist/context/DatePickerContext.js.map +1 -0
  100. package/dist/context/RangePickerContext.d.ts +53 -0
  101. package/dist/context/RangePickerContext.d.ts.map +1 -0
  102. package/dist/context/RangePickerContext.js +18 -0
  103. package/dist/context/RangePickerContext.js.map +1 -0
  104. package/dist/context/TimePickerContext.d.ts +29 -0
  105. package/dist/context/TimePickerContext.d.ts.map +1 -0
  106. package/dist/context/TimePickerContext.js +18 -0
  107. package/dist/context/TimePickerContext.js.map +1 -0
  108. package/dist/hooks/useDatePicker.d.ts +63 -0
  109. package/dist/hooks/useDatePicker.d.ts.map +1 -0
  110. package/dist/hooks/useDatePicker.js +82 -0
  111. package/dist/hooks/useDatePicker.js.map +1 -0
  112. package/dist/hooks/useRangePicker.d.ts +67 -0
  113. package/dist/hooks/useRangePicker.d.ts.map +1 -0
  114. package/dist/hooks/useRangePicker.js +116 -0
  115. package/dist/hooks/useRangePicker.js.map +1 -0
  116. package/dist/hooks/useTimePicker.d.ts +63 -0
  117. package/dist/hooks/useTimePicker.d.ts.map +1 -0
  118. package/dist/hooks/useTimePicker.js +69 -0
  119. package/dist/hooks/useTimePicker.js.map +1 -0
  120. package/dist/index.cjs +2150 -0
  121. package/dist/index.cjs.map +1 -0
  122. package/dist/index.d.cts +744 -0
  123. package/dist/index.d.ts +17 -0
  124. package/dist/index.d.ts.map +1 -0
  125. package/dist/index.js +13 -0
  126. package/dist/index.js.map +1 -0
  127. package/package.json +67 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,2150 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var core = require('@kalyx/core');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+ var react$1 = require('@floating-ui/react');
7
+
8
+ // src/components/DatePicker/Root.tsx
9
+ var DatePickerContext = react.createContext(null);
10
+ function useDatePickerContext(componentName) {
11
+ const context = react.useContext(DatePickerContext);
12
+ if (!context) {
13
+ throw new Error(
14
+ `[${componentName}] DatePicker.Root \uB0B4\uBD80\uC5D0\uC11C \uC0AC\uC6A9\uD574\uC57C \uD569\uB2C8\uB2E4.
15
+
16
+ \uC62C\uBC14\uB978 \uC0AC\uC6A9\uBC95:
17
+ <DatePicker>
18
+ <DatePicker.${componentName.replace("DatePicker.", "")} />
19
+ </DatePicker>`
20
+ );
21
+ }
22
+ return context;
23
+ }
24
+ function DatePickerRoot({
25
+ value: controlledValue,
26
+ defaultValue,
27
+ onChange,
28
+ disabled = false,
29
+ readOnly = false,
30
+ weekStartsOn = 0,
31
+ displayFormat = "yyyy-MM-dd",
32
+ locale = "en-US",
33
+ adapter = core.DateFnsAdapter,
34
+ children
35
+ }) {
36
+ const pickerId = react.useId();
37
+ const isControlled = react.useRef(controlledValue !== void 0).current;
38
+ const referenceRef = react.useRef(null);
39
+ const [uncontrolledValue, setUncontrolledValue] = react.useState(
40
+ defaultValue ?? null
41
+ );
42
+ const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
43
+ const [isOpen, setIsOpen] = react.useState(false);
44
+ const [viewMonth, setViewMonth] = react.useState(
45
+ currentValue ?? adapter.today()
46
+ );
47
+ const [focusedDate, setFocusedDate] = react.useState(
48
+ currentValue ?? adapter.today()
49
+ );
50
+ const isDisabled = typeof disabled === "boolean" ? disabled : false;
51
+ const disabledRules = Array.isArray(disabled) ? disabled : [];
52
+ const selectDate = react.useCallback(
53
+ (iso) => {
54
+ if (isDisabled || readOnly) return;
55
+ if (!isControlled) {
56
+ setUncontrolledValue(iso);
57
+ }
58
+ onChange?.(iso);
59
+ setIsOpen(false);
60
+ },
61
+ [isControlled, isDisabled, readOnly, onChange]
62
+ );
63
+ const open = react.useCallback(() => {
64
+ if (isDisabled || readOnly) return;
65
+ setIsOpen(true);
66
+ const target = currentValue ?? adapter.today();
67
+ setViewMonth(target);
68
+ setFocusedDate(target);
69
+ }, [isDisabled, readOnly, currentValue, adapter]);
70
+ const close = react.useCallback(() => {
71
+ setIsOpen(false);
72
+ }, []);
73
+ const toggle = react.useCallback(() => {
74
+ if (isOpen) {
75
+ close();
76
+ } else {
77
+ open();
78
+ }
79
+ }, [isOpen, open, close]);
80
+ const contextValue = react.useMemo(
81
+ () => ({
82
+ referenceRef,
83
+ value: currentValue,
84
+ selectDate,
85
+ isOpen,
86
+ open,
87
+ close,
88
+ toggle,
89
+ viewMonth,
90
+ setViewMonth,
91
+ focusedDate,
92
+ setFocusedDate,
93
+ adapter,
94
+ disabled: disabledRules,
95
+ weekStartsOn,
96
+ displayFormat,
97
+ locale,
98
+ isDisabled,
99
+ isReadOnly: readOnly,
100
+ pickerId
101
+ }),
102
+ [
103
+ currentValue,
104
+ selectDate,
105
+ isOpen,
106
+ open,
107
+ close,
108
+ toggle,
109
+ viewMonth,
110
+ focusedDate,
111
+ adapter,
112
+ disabledRules,
113
+ weekStartsOn,
114
+ displayFormat,
115
+ locale,
116
+ isDisabled,
117
+ readOnly,
118
+ pickerId
119
+ ]
120
+ );
121
+ return /* @__PURE__ */ jsxRuntime.jsx(DatePickerContext.Provider, { value: contextValue, children });
122
+ }
123
+ var DatePickerInput = react.forwardRef(
124
+ function DatePickerInput2({ format: formatProp, onFocus, onBlur, onKeyDown, ...props }, ref) {
125
+ const ctx = useDatePickerContext("DatePicker.Input");
126
+ const displayFormat = formatProp ?? ctx.displayFormat;
127
+ const [inputText, setInputText] = react.useState(null);
128
+ const displayValue = inputText !== null ? inputText : ctx.value ? ctx.adapter.format(ctx.value, displayFormat) : "";
129
+ const handleFocus = react.useCallback(
130
+ (e) => {
131
+ ctx.open();
132
+ onFocus?.(e);
133
+ },
134
+ [ctx, onFocus]
135
+ );
136
+ const handleBlur = react.useCallback(
137
+ (e) => {
138
+ if (inputText !== null) {
139
+ const parsed = core.parseInputValue(inputText, displayFormat, ctx.adapter);
140
+ if (parsed) {
141
+ ctx.selectDate(parsed);
142
+ }
143
+ setInputText(null);
144
+ }
145
+ onBlur?.(e);
146
+ },
147
+ [inputText, displayFormat, ctx, onBlur]
148
+ );
149
+ const handleChange = react.useCallback(
150
+ (e) => {
151
+ const text = e.target.value;
152
+ setInputText(text);
153
+ if (!text) {
154
+ ctx.selectDate(null);
155
+ setInputText(null);
156
+ return;
157
+ }
158
+ const parsed = core.parseInputValue(text, displayFormat, ctx.adapter);
159
+ if (parsed) {
160
+ ctx.selectDate(parsed);
161
+ setInputText(null);
162
+ }
163
+ },
164
+ [displayFormat, ctx]
165
+ );
166
+ const handleKeyDown = react.useCallback(
167
+ (e) => {
168
+ if (e.key === "Escape") {
169
+ ctx.close();
170
+ } else if (e.key === "Enter") {
171
+ if (inputText !== null) {
172
+ const parsed = core.parseInputValue(inputText, displayFormat, ctx.adapter);
173
+ if (parsed) {
174
+ ctx.selectDate(parsed);
175
+ setInputText(null);
176
+ }
177
+ }
178
+ } else if (e.key === "ArrowDown" && !ctx.isOpen) {
179
+ e.preventDefault();
180
+ ctx.open();
181
+ }
182
+ onKeyDown?.(e);
183
+ },
184
+ [ctx, inputText, displayFormat, onKeyDown]
185
+ );
186
+ const calendarId = `${ctx.pickerId}-calendar`;
187
+ return /* @__PURE__ */ jsxRuntime.jsx(
188
+ "input",
189
+ {
190
+ ref: (node) => {
191
+ ctx.referenceRef.current = node;
192
+ if (typeof ref === "function") ref(node);
193
+ else if (ref) ref.current = node;
194
+ },
195
+ type: "text",
196
+ role: "combobox",
197
+ "aria-expanded": ctx.isOpen,
198
+ "aria-haspopup": "dialog",
199
+ "aria-controls": ctx.isOpen ? calendarId : void 0,
200
+ "aria-autocomplete": "none",
201
+ autoComplete: "off",
202
+ value: displayValue,
203
+ disabled: ctx.isDisabled || props.disabled,
204
+ readOnly: ctx.isReadOnly,
205
+ onChange: handleChange,
206
+ onFocus: handleFocus,
207
+ onBlur: handleBlur,
208
+ onKeyDown: handleKeyDown,
209
+ ...props
210
+ }
211
+ );
212
+ }
213
+ );
214
+ var DatePickerTrigger = react.forwardRef(
215
+ function DatePickerTrigger2({ onClick, children, ...props }, ref) {
216
+ const ctx = useDatePickerContext("DatePicker.Trigger");
217
+ const handleClick = react.useCallback(
218
+ (e) => {
219
+ ctx.toggle();
220
+ onClick?.(e);
221
+ },
222
+ [ctx, onClick]
223
+ );
224
+ const calendarId = `${ctx.pickerId}-calendar`;
225
+ return /* @__PURE__ */ jsxRuntime.jsx(
226
+ "button",
227
+ {
228
+ ref: (node) => {
229
+ if (!ctx.referenceRef.current) ctx.referenceRef.current = node;
230
+ if (typeof ref === "function") ref(node);
231
+ else if (ref) ref.current = node;
232
+ },
233
+ type: "button",
234
+ tabIndex: 0,
235
+ "aria-label": ctx.isOpen ? "\uCE98\uB9B0\uB354 \uB2EB\uAE30" : "\uCE98\uB9B0\uB354 \uC5F4\uAE30",
236
+ "aria-expanded": ctx.isOpen,
237
+ "aria-controls": ctx.isOpen ? calendarId : void 0,
238
+ disabled: ctx.isDisabled || props.disabled,
239
+ onClick: handleClick,
240
+ ...props,
241
+ children: children ?? /* @__PURE__ */ jsxRuntime.jsx(
242
+ "svg",
243
+ {
244
+ "aria-hidden": "true",
245
+ focusable: "false",
246
+ width: "16",
247
+ height: "16",
248
+ viewBox: "0 0 16 16",
249
+ fill: "none",
250
+ xmlns: "http://www.w3.org/2000/svg",
251
+ children: /* @__PURE__ */ jsxRuntime.jsx(
252
+ "path",
253
+ {
254
+ d: "M5 1v2M11 1v2M1 6h14M3 3h10a2 2 0 012 2v8a2 2 0 01-2 2H3a2 2 0 01-2-2V5a2 2 0 012-2z",
255
+ stroke: "currentColor",
256
+ strokeWidth: "1.5",
257
+ strokeLinecap: "round",
258
+ strokeLinejoin: "round"
259
+ }
260
+ )
261
+ }
262
+ )
263
+ }
264
+ );
265
+ }
266
+ );
267
+ function DatePickerPopover({ children, ...props }) {
268
+ const ctx = useDatePickerContext("DatePicker.Popover");
269
+ const calendarId = `${ctx.pickerId}-calendar`;
270
+ const floatingRef = react.useRef(null);
271
+ const { refs, floatingStyles } = react$1.useFloating({
272
+ open: ctx.isOpen,
273
+ placement: "bottom-start",
274
+ middleware: [react$1.offset(4), react$1.flip(), react$1.shift({ padding: 8 })],
275
+ whileElementsMounted: react$1.autoUpdate
276
+ });
277
+ react.useEffect(() => {
278
+ if (ctx.referenceRef.current) {
279
+ refs.setReference(ctx.referenceRef.current);
280
+ }
281
+ }, [ctx.referenceRef, refs, ctx.isOpen]);
282
+ const previousFocusRef = react.useRef(null);
283
+ react.useEffect(() => {
284
+ if (ctx.isOpen) {
285
+ previousFocusRef.current = document.activeElement;
286
+ } else if (previousFocusRef.current) {
287
+ previousFocusRef.current.focus();
288
+ previousFocusRef.current = null;
289
+ }
290
+ }, [ctx.isOpen]);
291
+ react.useEffect(() => {
292
+ if (!ctx.isOpen) return;
293
+ function handleClickOutside(e) {
294
+ const floating = floatingRef.current;
295
+ const reference = ctx.referenceRef.current;
296
+ const target = e.target;
297
+ if (floating && !floating.contains(target) && (!reference || !reference.contains(target))) {
298
+ ctx.close();
299
+ }
300
+ }
301
+ const timer = setTimeout(() => {
302
+ document.addEventListener("mousedown", handleClickOutside);
303
+ }, 0);
304
+ return () => {
305
+ clearTimeout(timer);
306
+ document.removeEventListener("mousedown", handleClickOutside);
307
+ };
308
+ }, [ctx.isOpen, ctx]);
309
+ react.useEffect(() => {
310
+ if (!ctx.isOpen) return;
311
+ function handleKeyDown(e) {
312
+ if (e.key === "Escape") {
313
+ ctx.close();
314
+ }
315
+ }
316
+ document.addEventListener("keydown", handleKeyDown);
317
+ return () => document.removeEventListener("keydown", handleKeyDown);
318
+ }, [ctx.isOpen, ctx]);
319
+ if (!ctx.isOpen) return null;
320
+ return /* @__PURE__ */ jsxRuntime.jsx(
321
+ "div",
322
+ {
323
+ ref: (node) => {
324
+ floatingRef.current = node;
325
+ refs.setFloating(node);
326
+ },
327
+ id: calendarId,
328
+ role: "dialog",
329
+ "aria-label": "\uB0A0\uC9DC \uC120\uD0DD",
330
+ "aria-modal": "false",
331
+ style: floatingStyles,
332
+ ...props,
333
+ children
334
+ }
335
+ );
336
+ }
337
+ var srOnly = {
338
+ position: "absolute",
339
+ width: "1px",
340
+ height: "1px",
341
+ padding: 0,
342
+ margin: "-1px",
343
+ overflow: "hidden",
344
+ clip: "rect(0, 0, 0, 0)",
345
+ whiteSpace: "nowrap",
346
+ border: 0
347
+ };
348
+ function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
349
+ const ctx = useDatePickerContext("DatePicker.Calendar");
350
+ const gridRef = react.useRef(null);
351
+ const [announcement, setAnnouncement] = react.useState("");
352
+ const { adapter, viewMonth, focusedDate, weekStartsOn, disabled, locale } = ctx;
353
+ const weekdays = core.getWeekdayNames(locale, weekStartsOn);
354
+ const weeks = core.getCalendarDays(viewMonth, adapter, {
355
+ weekStartsOn,
356
+ selected: ctx.value,
357
+ focusedDate,
358
+ disabled
359
+ });
360
+ const year = adapter.getYear(viewMonth);
361
+ const month = adapter.getMonth(viewMonth);
362
+ const title = core.formatMonthYear(year, month, locale);
363
+ react.useEffect(() => {
364
+ if (!ctx.isOpen || !gridRef.current) return;
365
+ const focusedButton = gridRef.current.querySelector(
366
+ '[data-focused="true"]'
367
+ );
368
+ focusedButton?.focus();
369
+ }, [focusedDate, ctx.isOpen]);
370
+ const navigateMonth = react.useCallback(
371
+ (direction) => {
372
+ const newMonth = adapter.addMonths(viewMonth, direction);
373
+ ctx.setViewMonth(newMonth);
374
+ ctx.setFocusedDate(adapter.startOfMonth(newMonth));
375
+ const y = adapter.getYear(newMonth);
376
+ const m = adapter.getMonth(newMonth);
377
+ setAnnouncement(core.formatMonthYear(y, m, locale));
378
+ },
379
+ [adapter, viewMonth, ctx, locale]
380
+ );
381
+ const handleDayClick = react.useCallback(
382
+ (day) => {
383
+ if (day.isDisabled) return;
384
+ ctx.selectDate(day.isoString);
385
+ setAnnouncement(core.formatFullDate(day.isoString, locale));
386
+ },
387
+ [ctx, locale]
388
+ );
389
+ const handleKeyDown = react.useCallback(
390
+ (e) => {
391
+ let newFocused = null;
392
+ switch (e.key) {
393
+ case "ArrowLeft":
394
+ newFocused = adapter.addDays(focusedDate, -1);
395
+ break;
396
+ case "ArrowRight":
397
+ newFocused = adapter.addDays(focusedDate, 1);
398
+ break;
399
+ case "ArrowUp":
400
+ newFocused = adapter.addDays(focusedDate, -7);
401
+ break;
402
+ case "ArrowDown":
403
+ newFocused = adapter.addDays(focusedDate, 7);
404
+ break;
405
+ case "PageUp":
406
+ if (e.shiftKey) {
407
+ newFocused = adapter.addYears(focusedDate, -1);
408
+ } else {
409
+ newFocused = adapter.addMonths(focusedDate, -1);
410
+ }
411
+ break;
412
+ case "PageDown":
413
+ if (e.shiftKey) {
414
+ newFocused = adapter.addYears(focusedDate, 1);
415
+ } else {
416
+ newFocused = adapter.addMonths(focusedDate, 1);
417
+ }
418
+ break;
419
+ case "Home":
420
+ newFocused = adapter.startOfWeek(focusedDate, weekStartsOn);
421
+ break;
422
+ case "End":
423
+ newFocused = adapter.endOfWeek(focusedDate, weekStartsOn);
424
+ newFocused = adapter.startOfDay(newFocused);
425
+ break;
426
+ case "Enter":
427
+ case " ":
428
+ e.preventDefault();
429
+ if (!core.isDateDisabled(focusedDate, disabled, adapter)) {
430
+ ctx.selectDate(focusedDate);
431
+ }
432
+ return;
433
+ case "Escape":
434
+ ctx.close();
435
+ return;
436
+ default:
437
+ return;
438
+ }
439
+ if (newFocused) {
440
+ e.preventDefault();
441
+ ctx.setFocusedDate(newFocused);
442
+ if (!adapter.isSameMonth(newFocused, viewMonth)) {
443
+ ctx.setViewMonth(newFocused);
444
+ }
445
+ }
446
+ },
447
+ [adapter, focusedDate, viewMonth, weekStartsOn, disabled, ctx]
448
+ );
449
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.root, ...props, children: [
450
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.header, children: [
451
+ /* @__PURE__ */ jsxRuntime.jsx(
452
+ "button",
453
+ {
454
+ type: "button",
455
+ className: classNames?.navButton,
456
+ onClick: () => navigateMonth(-1),
457
+ "aria-label": "\uC774\uC804 \uB2EC",
458
+ children: "<"
459
+ }
460
+ ),
461
+ onTitleClick ? /* @__PURE__ */ jsxRuntime.jsx(
462
+ "button",
463
+ {
464
+ type: "button",
465
+ className: classNames?.title,
466
+ onClick: onTitleClick,
467
+ "aria-live": "polite",
468
+ children: title
469
+ }
470
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: classNames?.title, "aria-live": "polite", children: title }),
471
+ /* @__PURE__ */ jsxRuntime.jsx(
472
+ "button",
473
+ {
474
+ type: "button",
475
+ className: classNames?.navButton,
476
+ onClick: () => navigateMonth(1),
477
+ "aria-label": "\uB2E4\uC74C \uB2EC",
478
+ children: ">"
479
+ }
480
+ )
481
+ ] }),
482
+ /* @__PURE__ */ jsxRuntime.jsxs(
483
+ "table",
484
+ {
485
+ ref: gridRef,
486
+ role: "grid",
487
+ "aria-label": title,
488
+ className: classNames?.grid,
489
+ onKeyDown: handleKeyDown,
490
+ children: [
491
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsx("tr", { role: "row", children: weekdays.map((day) => /* @__PURE__ */ jsxRuntime.jsx(
492
+ "th",
493
+ {
494
+ role: "columnheader",
495
+ abbr: day.full,
496
+ scope: "col",
497
+ className: classNames?.weekdayHeader,
498
+ children: day.short
499
+ },
500
+ day.short
501
+ )) }) }),
502
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: weeks.map((week, weekIndex) => /* @__PURE__ */ jsxRuntime.jsx("tr", { role: "row", className: classNames?.gridRow, children: week.map((day) => {
503
+ const dayClasses = [
504
+ classNames?.day,
505
+ day.isSelected && classNames?.daySelected,
506
+ day.isToday && classNames?.dayToday,
507
+ day.isDisabled && classNames?.dayDisabled,
508
+ !day.isCurrentMonth && classNames?.dayOutsideMonth
509
+ ].filter(Boolean).join(" ") || void 0;
510
+ return /* @__PURE__ */ jsxRuntime.jsx(
511
+ "td",
512
+ {
513
+ role: "gridcell",
514
+ "aria-selected": day.isSelected || void 0,
515
+ "aria-disabled": day.isDisabled || void 0,
516
+ "aria-current": day.isToday ? "date" : void 0,
517
+ className: classNames?.gridCell,
518
+ children: /* @__PURE__ */ jsxRuntime.jsx(
519
+ "button",
520
+ {
521
+ type: "button",
522
+ tabIndex: day.isFocused ? 0 : -1,
523
+ disabled: day.isDisabled,
524
+ "data-focused": day.isFocused || void 0,
525
+ "data-selected": day.isSelected || void 0,
526
+ "data-today": day.isToday || void 0,
527
+ "data-outside-month": !day.isCurrentMonth || void 0,
528
+ className: dayClasses,
529
+ onClick: () => handleDayClick(day),
530
+ "aria-label": core.formatFullDate(day.isoString, locale),
531
+ children: day.dayNumber
532
+ }
533
+ )
534
+ },
535
+ day.isoString
536
+ );
537
+ }) }, weekIndex)) })
538
+ ]
539
+ }
540
+ ),
541
+ /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", "aria-live": "polite", "aria-atomic": "true", style: srOnly, children: announcement })
542
+ ] });
543
+ }
544
+ function DatePickerMonthGrid({
545
+ classNames,
546
+ onSelect,
547
+ onTitleClick,
548
+ ...props
549
+ }) {
550
+ const ctx = useDatePickerContext("DatePicker.MonthGrid");
551
+ const { adapter, viewMonth, locale } = ctx;
552
+ const currentYear = adapter.getYear(viewMonth);
553
+ const currentMonth = adapter.getMonth(viewMonth);
554
+ const todayMonth = adapter.getMonth(adapter.today());
555
+ const todayYear = adapter.getYear(adapter.today());
556
+ const navigateYear = react.useCallback(
557
+ (direction) => {
558
+ const newDate = adapter.addYears(viewMonth, direction);
559
+ ctx.setViewMonth(newDate);
560
+ },
561
+ [adapter, viewMonth, ctx]
562
+ );
563
+ const handleMonthSelect = react.useCallback(
564
+ (monthIndex) => {
565
+ const target = new Date(Date.UTC(currentYear, monthIndex, 1)).toISOString();
566
+ ctx.setViewMonth(target);
567
+ ctx.setFocusedDate(target);
568
+ onSelect?.();
569
+ },
570
+ [currentYear, ctx, onSelect]
571
+ );
572
+ const months = Array.from({ length: 12 }, (_, i) => ({
573
+ index: i,
574
+ name: core.getMonthName(i, locale),
575
+ isSelected: i === currentMonth,
576
+ isCurrent: i === todayMonth && currentYear === todayYear
577
+ }));
578
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.root, ...props, children: [
579
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.header, children: [
580
+ /* @__PURE__ */ jsxRuntime.jsx(
581
+ "button",
582
+ {
583
+ type: "button",
584
+ className: classNames?.navButton,
585
+ onClick: () => navigateYear(-1),
586
+ "aria-label": "\uC774\uC804 \uB144",
587
+ children: "<"
588
+ }
589
+ ),
590
+ onTitleClick ? /* @__PURE__ */ jsxRuntime.jsx(
591
+ "button",
592
+ {
593
+ type: "button",
594
+ className: classNames?.title,
595
+ onClick: onTitleClick,
596
+ children: currentYear
597
+ }
598
+ ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: classNames?.title, children: currentYear }),
599
+ /* @__PURE__ */ jsxRuntime.jsx(
600
+ "button",
601
+ {
602
+ type: "button",
603
+ className: classNames?.navButton,
604
+ onClick: () => navigateYear(1),
605
+ "aria-label": "\uB2E4\uC74C \uB144",
606
+ children: ">"
607
+ }
608
+ )
609
+ ] }),
610
+ /* @__PURE__ */ jsxRuntime.jsx(
611
+ "div",
612
+ {
613
+ role: "grid",
614
+ "aria-label": `${currentYear} months`,
615
+ className: classNames?.grid,
616
+ style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)" },
617
+ children: months.map((m) => {
618
+ const monthClass = [
619
+ classNames?.month,
620
+ m.isSelected && classNames?.monthSelected,
621
+ m.isCurrent && classNames?.monthCurrent
622
+ ].filter(Boolean).join(" ") || void 0;
623
+ return /* @__PURE__ */ jsxRuntime.jsx(
624
+ "button",
625
+ {
626
+ type: "button",
627
+ role: "gridcell",
628
+ "aria-selected": m.isSelected || void 0,
629
+ "aria-current": m.isCurrent ? "date" : void 0,
630
+ "data-selected": m.isSelected || void 0,
631
+ "data-current": m.isCurrent || void 0,
632
+ className: monthClass,
633
+ onClick: () => handleMonthSelect(m.index),
634
+ children: m.name
635
+ },
636
+ m.index
637
+ );
638
+ })
639
+ }
640
+ )
641
+ ] });
642
+ }
643
+ function DatePickerYearGrid({
644
+ classNames,
645
+ onSelect,
646
+ ...props
647
+ }) {
648
+ const ctx = useDatePickerContext("DatePicker.YearGrid");
649
+ const { adapter, viewMonth } = ctx;
650
+ const currentYear = adapter.getYear(viewMonth);
651
+ const todayYear = adapter.getYear(adapter.today());
652
+ const decadeStart = currentYear - currentYear % 12;
653
+ const navigateDecade = react.useCallback(
654
+ (direction) => {
655
+ const newDate = adapter.addYears(viewMonth, direction * 12);
656
+ ctx.setViewMonth(newDate);
657
+ },
658
+ [adapter, viewMonth, ctx]
659
+ );
660
+ const handleYearSelect = react.useCallback(
661
+ (year) => {
662
+ const currentMonth = adapter.getMonth(viewMonth);
663
+ const target = new Date(Date.UTC(year, currentMonth, 1)).toISOString();
664
+ ctx.setViewMonth(target);
665
+ ctx.setFocusedDate(target);
666
+ onSelect?.();
667
+ },
668
+ [adapter, viewMonth, ctx, onSelect]
669
+ );
670
+ const years = react.useMemo(
671
+ () => Array.from({ length: 12 }, (_, i) => {
672
+ const year = decadeStart + i;
673
+ return {
674
+ value: year,
675
+ isSelected: year === currentYear,
676
+ isCurrent: year === todayYear
677
+ };
678
+ }),
679
+ [decadeStart, currentYear, todayYear]
680
+ );
681
+ const rangeLabel = `${decadeStart}\u2013${decadeStart + 11}`;
682
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.root, ...props, children: [
683
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.header, children: [
684
+ /* @__PURE__ */ jsxRuntime.jsx(
685
+ "button",
686
+ {
687
+ type: "button",
688
+ className: classNames?.navButton,
689
+ onClick: () => navigateDecade(-1),
690
+ "aria-label": "\uC774\uC804 12\uB144",
691
+ children: "<"
692
+ }
693
+ ),
694
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: classNames?.title, children: rangeLabel }),
695
+ /* @__PURE__ */ jsxRuntime.jsx(
696
+ "button",
697
+ {
698
+ type: "button",
699
+ className: classNames?.navButton,
700
+ onClick: () => navigateDecade(1),
701
+ "aria-label": "\uB2E4\uC74C 12\uB144",
702
+ children: ">"
703
+ }
704
+ )
705
+ ] }),
706
+ /* @__PURE__ */ jsxRuntime.jsx(
707
+ "div",
708
+ {
709
+ role: "grid",
710
+ "aria-label": rangeLabel,
711
+ className: classNames?.grid,
712
+ style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)" },
713
+ children: years.map((y) => {
714
+ const yearClass = [
715
+ classNames?.year,
716
+ y.isSelected && classNames?.yearSelected,
717
+ y.isCurrent && classNames?.yearCurrent
718
+ ].filter(Boolean).join(" ") || void 0;
719
+ return /* @__PURE__ */ jsxRuntime.jsx(
720
+ "button",
721
+ {
722
+ type: "button",
723
+ role: "gridcell",
724
+ "aria-selected": y.isSelected || void 0,
725
+ "aria-current": y.isCurrent ? "date" : void 0,
726
+ "data-selected": y.isSelected || void 0,
727
+ "data-current": y.isCurrent || void 0,
728
+ className: yearClass,
729
+ onClick: () => handleYearSelect(y.value),
730
+ children: y.value
731
+ },
732
+ y.value
733
+ );
734
+ })
735
+ }
736
+ )
737
+ ] });
738
+ }
739
+
740
+ // src/components/DatePicker/index.ts
741
+ var DatePicker = Object.assign(DatePickerRoot, {
742
+ Input: DatePickerInput,
743
+ Trigger: DatePickerTrigger,
744
+ Popover: DatePickerPopover,
745
+ Calendar: DatePickerCalendar,
746
+ MonthGrid: DatePickerMonthGrid,
747
+ YearGrid: DatePickerYearGrid
748
+ });
749
+ var RangePickerContext = react.createContext(null);
750
+ function useRangePickerContext(componentName) {
751
+ const context = react.useContext(RangePickerContext);
752
+ if (!context) {
753
+ throw new Error(
754
+ `[${componentName}] RangePicker.Root \uB0B4\uBD80\uC5D0\uC11C \uC0AC\uC6A9\uD574\uC57C \uD569\uB2C8\uB2E4.
755
+
756
+ \uC62C\uBC14\uB978 \uC0AC\uC6A9\uBC95:
757
+ <RangePicker>
758
+ <RangePicker.${componentName.replace("RangePicker.", "")} />
759
+ </RangePicker>`
760
+ );
761
+ }
762
+ return context;
763
+ }
764
+ var EMPTY_RANGE = { start: null, end: null };
765
+ function RangePickerRoot({
766
+ value: controlledValue,
767
+ defaultValue,
768
+ onChange,
769
+ disabled = false,
770
+ readOnly = false,
771
+ weekStartsOn = 0,
772
+ displayFormat = "yyyy-MM-dd",
773
+ locale = "en-US",
774
+ adapter = core.DateFnsAdapter,
775
+ children
776
+ }) {
777
+ const pickerId = react.useId();
778
+ const isControlled = react.useRef(controlledValue !== void 0).current;
779
+ const referenceRef = react.useRef(null);
780
+ const [uncontrolledValue, setUncontrolledValue] = react.useState(
781
+ defaultValue ?? EMPTY_RANGE
782
+ );
783
+ const currentValue = isControlled ? controlledValue ?? EMPTY_RANGE : uncontrolledValue;
784
+ const [isOpen, setIsOpen] = react.useState(false);
785
+ const [selectingTarget, setSelectingTarget] = react.useState("start");
786
+ const [hoverDate, setHoverDate] = react.useState(null);
787
+ const [viewMonth, setViewMonth] = react.useState(
788
+ currentValue.start ?? adapter.today()
789
+ );
790
+ const [focusedDate, setFocusedDate] = react.useState(
791
+ currentValue.start ?? adapter.today()
792
+ );
793
+ const isDisabled = typeof disabled === "boolean" ? disabled : false;
794
+ const disabledRules = Array.isArray(disabled) ? disabled : [];
795
+ const setRange = react.useCallback(
796
+ (range) => {
797
+ if (isDisabled || readOnly) return;
798
+ if (!isControlled) {
799
+ setUncontrolledValue(range);
800
+ }
801
+ onChange?.(range);
802
+ },
803
+ [isControlled, isDisabled, readOnly, onChange]
804
+ );
805
+ const selectDate = react.useCallback(
806
+ (iso) => {
807
+ if (isDisabled || readOnly) return;
808
+ if (selectingTarget === "start") {
809
+ const newRange = { start: iso, end: null };
810
+ setRange(newRange);
811
+ setSelectingTarget("end");
812
+ setHoverDate(null);
813
+ } else {
814
+ const start = currentValue.start;
815
+ if (!start) {
816
+ setRange({ start: iso, end: null });
817
+ setSelectingTarget("end");
818
+ return;
819
+ }
820
+ let newRange;
821
+ if (adapter.isBefore(iso, start)) {
822
+ newRange = { start: iso, end: start };
823
+ } else {
824
+ newRange = { start, end: iso };
825
+ }
826
+ setRange(newRange);
827
+ setSelectingTarget("start");
828
+ setHoverDate(null);
829
+ setIsOpen(false);
830
+ }
831
+ },
832
+ [isDisabled, readOnly, selectingTarget, currentValue.start, adapter, setRange]
833
+ );
834
+ const open = react.useCallback(() => {
835
+ if (isDisabled || readOnly) return;
836
+ setIsOpen(true);
837
+ const target = currentValue.start ?? adapter.today();
838
+ setViewMonth(target);
839
+ setFocusedDate(target);
840
+ if (currentValue.start && currentValue.end) {
841
+ setSelectingTarget("start");
842
+ }
843
+ }, [isDisabled, readOnly, currentValue, adapter]);
844
+ const close = react.useCallback(() => {
845
+ setIsOpen(false);
846
+ setHoverDate(null);
847
+ }, []);
848
+ const toggle = react.useCallback(() => {
849
+ if (isOpen) close();
850
+ else open();
851
+ }, [isOpen, open, close]);
852
+ const contextValue = react.useMemo(
853
+ () => ({
854
+ referenceRef,
855
+ value: currentValue,
856
+ setRange,
857
+ selectDate,
858
+ selectingTarget,
859
+ hoverDate,
860
+ setHoverDate,
861
+ isOpen,
862
+ open,
863
+ close,
864
+ toggle,
865
+ viewMonth,
866
+ setViewMonth,
867
+ focusedDate,
868
+ setFocusedDate,
869
+ adapter,
870
+ disabled: disabledRules,
871
+ weekStartsOn,
872
+ displayFormat,
873
+ locale,
874
+ isDisabled,
875
+ isReadOnly: readOnly,
876
+ pickerId
877
+ }),
878
+ [
879
+ currentValue,
880
+ setRange,
881
+ selectDate,
882
+ selectingTarget,
883
+ hoverDate,
884
+ isOpen,
885
+ open,
886
+ close,
887
+ toggle,
888
+ viewMonth,
889
+ focusedDate,
890
+ adapter,
891
+ disabledRules,
892
+ weekStartsOn,
893
+ displayFormat,
894
+ locale,
895
+ isDisabled,
896
+ readOnly,
897
+ pickerId
898
+ ]
899
+ );
900
+ return /* @__PURE__ */ jsxRuntime.jsx(RangePickerContext.Provider, { value: contextValue, children });
901
+ }
902
+ var RangePickerInput = react.forwardRef(
903
+ function RangePickerInput2({ part, format: formatProp, onFocus, onKeyDown, ...props }, ref) {
904
+ const ctx = useRangePickerContext("RangePicker.Input");
905
+ const displayFormat = formatProp ?? ctx.displayFormat;
906
+ const value = ctx.value[part];
907
+ const displayValue = value ? ctx.adapter.format(value, displayFormat) : "";
908
+ const handleFocus = react.useCallback(
909
+ (e) => {
910
+ ctx.open();
911
+ onFocus?.(e);
912
+ },
913
+ [ctx, onFocus]
914
+ );
915
+ const handleKeyDown = react.useCallback(
916
+ (e) => {
917
+ if (e.key === "Escape") {
918
+ ctx.close();
919
+ } else if (e.key === "ArrowDown" && !ctx.isOpen) {
920
+ e.preventDefault();
921
+ ctx.open();
922
+ }
923
+ onKeyDown?.(e);
924
+ },
925
+ [ctx, onKeyDown]
926
+ );
927
+ const calendarId = `${ctx.pickerId}-calendar`;
928
+ return /* @__PURE__ */ jsxRuntime.jsx(
929
+ "input",
930
+ {
931
+ ref: (node) => {
932
+ if (part === "start" && node) ctx.referenceRef.current = node;
933
+ if (typeof ref === "function") ref(node);
934
+ else if (ref) ref.current = node;
935
+ },
936
+ type: "text",
937
+ role: "combobox",
938
+ readOnly: true,
939
+ "aria-expanded": ctx.isOpen,
940
+ "aria-haspopup": "dialog",
941
+ "aria-controls": ctx.isOpen ? calendarId : void 0,
942
+ "aria-autocomplete": "none",
943
+ "aria-label": part === "start" ? "\uC2DC\uC791\uC77C" : "\uC885\uB8CC\uC77C",
944
+ autoComplete: "off",
945
+ value: displayValue,
946
+ disabled: ctx.isDisabled || props.disabled,
947
+ onFocus: handleFocus,
948
+ onKeyDown: handleKeyDown,
949
+ "data-part": part,
950
+ ...props
951
+ }
952
+ );
953
+ }
954
+ );
955
+ function RangePickerPopover({ children, ...props }) {
956
+ const ctx = useRangePickerContext("RangePicker.Popover");
957
+ const calendarId = `${ctx.pickerId}-calendar`;
958
+ const floatingRef = react.useRef(null);
959
+ const { refs, floatingStyles } = react$1.useFloating({
960
+ open: ctx.isOpen,
961
+ placement: "bottom-start",
962
+ middleware: [react$1.offset(4), react$1.flip(), react$1.shift({ padding: 8 })],
963
+ whileElementsMounted: react$1.autoUpdate
964
+ });
965
+ react.useEffect(() => {
966
+ if (ctx.referenceRef.current) {
967
+ refs.setReference(ctx.referenceRef.current);
968
+ }
969
+ }, [ctx.referenceRef, refs, ctx.isOpen]);
970
+ const previousFocusRef = react.useRef(null);
971
+ react.useEffect(() => {
972
+ if (ctx.isOpen) {
973
+ previousFocusRef.current = document.activeElement;
974
+ } else if (previousFocusRef.current) {
975
+ previousFocusRef.current.focus();
976
+ previousFocusRef.current = null;
977
+ }
978
+ }, [ctx.isOpen]);
979
+ react.useEffect(() => {
980
+ if (!ctx.isOpen) return;
981
+ function handleClickOutside(e) {
982
+ const floating = floatingRef.current;
983
+ const reference = ctx.referenceRef.current;
984
+ const target = e.target;
985
+ if (floating && !floating.contains(target) && (!reference || !reference.contains(target))) {
986
+ ctx.close();
987
+ }
988
+ }
989
+ const timer = setTimeout(() => {
990
+ document.addEventListener("mousedown", handleClickOutside);
991
+ }, 0);
992
+ return () => {
993
+ clearTimeout(timer);
994
+ document.removeEventListener("mousedown", handleClickOutside);
995
+ };
996
+ }, [ctx.isOpen, ctx]);
997
+ react.useEffect(() => {
998
+ if (!ctx.isOpen) return;
999
+ function handleKeyDown(e) {
1000
+ if (e.key === "Escape") {
1001
+ ctx.close();
1002
+ }
1003
+ }
1004
+ document.addEventListener("keydown", handleKeyDown);
1005
+ return () => document.removeEventListener("keydown", handleKeyDown);
1006
+ }, [ctx.isOpen, ctx]);
1007
+ if (!ctx.isOpen) return null;
1008
+ return /* @__PURE__ */ jsxRuntime.jsx(
1009
+ "div",
1010
+ {
1011
+ ref: (node) => {
1012
+ floatingRef.current = node;
1013
+ refs.setFloating(node);
1014
+ },
1015
+ id: calendarId,
1016
+ role: "dialog",
1017
+ "aria-label": "\uB0A0\uC9DC \uBC94\uC704 \uC120\uD0DD",
1018
+ "aria-modal": "false",
1019
+ style: floatingStyles,
1020
+ ...props,
1021
+ children
1022
+ }
1023
+ );
1024
+ }
1025
+ var srOnly2 = {
1026
+ position: "absolute",
1027
+ width: "1px",
1028
+ height: "1px",
1029
+ padding: 0,
1030
+ margin: "-1px",
1031
+ overflow: "hidden",
1032
+ clip: "rect(0, 0, 0, 0)",
1033
+ whiteSpace: "nowrap",
1034
+ border: 0
1035
+ };
1036
+ function RangePickerCalendar({ classNames, ...props }) {
1037
+ const ctx = useRangePickerContext("RangePicker.Calendar");
1038
+ const gridRef = react.useRef(null);
1039
+ const [announcement, setAnnouncement] = react.useState("");
1040
+ const {
1041
+ adapter,
1042
+ viewMonth,
1043
+ focusedDate,
1044
+ weekStartsOn,
1045
+ disabled,
1046
+ value,
1047
+ hoverDate,
1048
+ selectingTarget
1049
+ } = ctx;
1050
+ const { locale } = ctx;
1051
+ const weekdays = core.getWeekdayNames(locale, weekStartsOn);
1052
+ const weeks = core.getCalendarDays(viewMonth, adapter, {
1053
+ weekStartsOn,
1054
+ focusedDate,
1055
+ disabled,
1056
+ range: value,
1057
+ rangeHover: hoverDate
1058
+ });
1059
+ const year = adapter.getYear(viewMonth);
1060
+ const month = adapter.getMonth(viewMonth);
1061
+ const title = core.formatMonthYear(year, month, locale);
1062
+ react.useEffect(() => {
1063
+ if (!ctx.isOpen || !gridRef.current) return;
1064
+ const focusedButton = gridRef.current.querySelector(
1065
+ '[data-focused="true"]'
1066
+ );
1067
+ focusedButton?.focus();
1068
+ }, [focusedDate, ctx.isOpen]);
1069
+ const navigateMonth = react.useCallback(
1070
+ (direction) => {
1071
+ const newMonth = adapter.addMonths(viewMonth, direction);
1072
+ ctx.setViewMonth(newMonth);
1073
+ ctx.setFocusedDate(adapter.startOfMonth(newMonth));
1074
+ const y = adapter.getYear(newMonth);
1075
+ const m = adapter.getMonth(newMonth);
1076
+ setAnnouncement(core.formatMonthYear(y, m, locale));
1077
+ },
1078
+ [adapter, viewMonth, ctx, locale]
1079
+ );
1080
+ const handleDayClick = react.useCallback(
1081
+ (day) => {
1082
+ if (day.isDisabled) return;
1083
+ ctx.selectDate(day.isoString);
1084
+ setAnnouncement(core.formatFullDate(day.isoString, locale));
1085
+ },
1086
+ [ctx, locale]
1087
+ );
1088
+ const handleDayMouseEnter = react.useCallback(
1089
+ (day) => {
1090
+ if (selectingTarget === "end" && value.start && !day.isDisabled) {
1091
+ ctx.setHoverDate(day.isoString);
1092
+ }
1093
+ },
1094
+ [selectingTarget, value.start, ctx]
1095
+ );
1096
+ const handleMouseLeave = react.useCallback(() => {
1097
+ ctx.setHoverDate(null);
1098
+ }, [ctx]);
1099
+ const handleKeyDown = react.useCallback(
1100
+ (e) => {
1101
+ let newFocused = null;
1102
+ switch (e.key) {
1103
+ case "ArrowLeft":
1104
+ newFocused = adapter.addDays(focusedDate, -1);
1105
+ break;
1106
+ case "ArrowRight":
1107
+ newFocused = adapter.addDays(focusedDate, 1);
1108
+ break;
1109
+ case "ArrowUp":
1110
+ newFocused = adapter.addDays(focusedDate, -7);
1111
+ break;
1112
+ case "ArrowDown":
1113
+ newFocused = adapter.addDays(focusedDate, 7);
1114
+ break;
1115
+ case "PageUp":
1116
+ newFocused = e.shiftKey ? adapter.addYears(focusedDate, -1) : adapter.addMonths(focusedDate, -1);
1117
+ break;
1118
+ case "PageDown":
1119
+ newFocused = e.shiftKey ? adapter.addYears(focusedDate, 1) : adapter.addMonths(focusedDate, 1);
1120
+ break;
1121
+ case "Home":
1122
+ newFocused = adapter.startOfWeek(focusedDate, weekStartsOn);
1123
+ break;
1124
+ case "End":
1125
+ newFocused = adapter.startOfDay(adapter.endOfWeek(focusedDate, weekStartsOn));
1126
+ break;
1127
+ case "Enter":
1128
+ case " ":
1129
+ e.preventDefault();
1130
+ if (!core.isDateDisabled(focusedDate, disabled, adapter)) {
1131
+ ctx.selectDate(focusedDate);
1132
+ }
1133
+ return;
1134
+ case "Escape":
1135
+ ctx.close();
1136
+ return;
1137
+ default:
1138
+ return;
1139
+ }
1140
+ if (newFocused) {
1141
+ e.preventDefault();
1142
+ ctx.setFocusedDate(newFocused);
1143
+ if (!adapter.isSameMonth(newFocused, viewMonth)) {
1144
+ ctx.setViewMonth(newFocused);
1145
+ }
1146
+ if (selectingTarget === "end" && value.start) {
1147
+ ctx.setHoverDate(newFocused);
1148
+ }
1149
+ }
1150
+ },
1151
+ [adapter, focusedDate, viewMonth, weekStartsOn, disabled, ctx, selectingTarget, value.start]
1152
+ );
1153
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.root, ...props, onMouseLeave: handleMouseLeave, children: [
1154
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.header, children: [
1155
+ /* @__PURE__ */ jsxRuntime.jsx(
1156
+ "button",
1157
+ {
1158
+ type: "button",
1159
+ className: classNames?.navButton,
1160
+ onClick: () => navigateMonth(-1),
1161
+ "aria-label": "\uC774\uC804 \uB2EC",
1162
+ children: "<"
1163
+ }
1164
+ ),
1165
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: classNames?.title, "aria-live": "polite", children: title }),
1166
+ /* @__PURE__ */ jsxRuntime.jsx(
1167
+ "button",
1168
+ {
1169
+ type: "button",
1170
+ className: classNames?.navButton,
1171
+ onClick: () => navigateMonth(1),
1172
+ "aria-label": "\uB2E4\uC74C \uB2EC",
1173
+ children: ">"
1174
+ }
1175
+ )
1176
+ ] }),
1177
+ /* @__PURE__ */ jsxRuntime.jsxs(
1178
+ "table",
1179
+ {
1180
+ ref: gridRef,
1181
+ role: "grid",
1182
+ "aria-label": title,
1183
+ "aria-multiselectable": "true",
1184
+ className: classNames?.grid,
1185
+ onKeyDown: handleKeyDown,
1186
+ children: [
1187
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsx("tr", { role: "row", children: weekdays.map((day) => /* @__PURE__ */ jsxRuntime.jsx(
1188
+ "th",
1189
+ {
1190
+ role: "columnheader",
1191
+ abbr: day.full,
1192
+ scope: "col",
1193
+ className: classNames?.weekdayHeader,
1194
+ children: day.short
1195
+ },
1196
+ day.short
1197
+ )) }) }),
1198
+ /* @__PURE__ */ jsxRuntime.jsx("tbody", { children: weeks.map((week, weekIndex) => /* @__PURE__ */ jsxRuntime.jsx("tr", { role: "row", className: classNames?.gridRow, children: week.map((day) => {
1199
+ const dayClasses = [
1200
+ classNames?.day,
1201
+ day.isRangeStart && classNames?.dayRangeStart,
1202
+ day.isRangeEnd && classNames?.dayRangeEnd,
1203
+ day.isInRange && classNames?.dayInRange,
1204
+ day.isToday && classNames?.dayToday,
1205
+ day.isDisabled && classNames?.dayDisabled,
1206
+ !day.isCurrentMonth && classNames?.dayOutsideMonth
1207
+ ].filter(Boolean).join(" ") || void 0;
1208
+ const isSelected = day.isRangeStart || day.isRangeEnd;
1209
+ return /* @__PURE__ */ jsxRuntime.jsx(
1210
+ "td",
1211
+ {
1212
+ role: "gridcell",
1213
+ "aria-selected": isSelected || void 0,
1214
+ "aria-disabled": day.isDisabled || void 0,
1215
+ "aria-current": day.isToday ? "date" : void 0,
1216
+ className: classNames?.gridCell,
1217
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1218
+ "button",
1219
+ {
1220
+ type: "button",
1221
+ tabIndex: day.isFocused ? 0 : -1,
1222
+ disabled: day.isDisabled,
1223
+ "data-focused": day.isFocused || void 0,
1224
+ "data-range-start": day.isRangeStart || void 0,
1225
+ "data-range-end": day.isRangeEnd || void 0,
1226
+ "data-in-range": day.isInRange || void 0,
1227
+ "data-today": day.isToday || void 0,
1228
+ "data-outside-month": !day.isCurrentMonth || void 0,
1229
+ className: dayClasses,
1230
+ onClick: () => handleDayClick(day),
1231
+ onMouseEnter: () => handleDayMouseEnter(day),
1232
+ "aria-label": core.formatFullDate(day.isoString, locale),
1233
+ children: day.dayNumber
1234
+ }
1235
+ )
1236
+ },
1237
+ day.isoString
1238
+ );
1239
+ }) }, weekIndex)) })
1240
+ ]
1241
+ }
1242
+ ),
1243
+ /* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", "aria-live": "polite", "aria-atomic": "true", style: srOnly2, children: announcement })
1244
+ ] });
1245
+ }
1246
+ function RangePickerPresets({ classNames, children, ...props }) {
1247
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "group", "aria-label": "\uB0A0\uC9DC \uBC94\uC704 \uD504\uB9AC\uC14B", className: classNames?.root, ...props, children });
1248
+ }
1249
+ function resolvePreset(key, today, adapter) {
1250
+ switch (key) {
1251
+ case "today":
1252
+ return { start: today, end: today };
1253
+ case "yesterday": {
1254
+ const yesterday = adapter.addDays(today, -1);
1255
+ return { start: yesterday, end: yesterday };
1256
+ }
1257
+ case "last7days":
1258
+ return { start: adapter.addDays(today, -6), end: today };
1259
+ case "last30days":
1260
+ return { start: adapter.addDays(today, -29), end: today };
1261
+ case "thisWeek":
1262
+ return {
1263
+ start: adapter.startOfDay(adapter.startOfWeek(today)),
1264
+ end: adapter.startOfDay(adapter.endOfWeek(today))
1265
+ };
1266
+ case "lastWeek": {
1267
+ const prevWeek = adapter.addDays(today, -7);
1268
+ return {
1269
+ start: adapter.startOfDay(adapter.startOfWeek(prevWeek)),
1270
+ end: adapter.startOfDay(adapter.endOfWeek(prevWeek))
1271
+ };
1272
+ }
1273
+ case "thisMonth":
1274
+ return {
1275
+ start: adapter.startOfMonth(today),
1276
+ end: adapter.startOfDay(adapter.endOfMonth(today))
1277
+ };
1278
+ case "lastMonth": {
1279
+ const prevMonth = adapter.addMonths(today, -1);
1280
+ return {
1281
+ start: adapter.startOfMonth(prevMonth),
1282
+ end: adapter.startOfDay(adapter.endOfMonth(prevMonth))
1283
+ };
1284
+ }
1285
+ case "thisYear": {
1286
+ const yearStart = adapter.startOfMonth(
1287
+ adapter.addMonths(today, -new Date(today).getUTCMonth())
1288
+ );
1289
+ return { start: yearStart, end: today };
1290
+ }
1291
+ }
1292
+ }
1293
+ function RangePickerPreset({
1294
+ value: presetKey,
1295
+ range: directRange,
1296
+ children,
1297
+ onClick,
1298
+ ...props
1299
+ }) {
1300
+ const ctx = useRangePickerContext("RangePicker.Preset");
1301
+ const handleClick = react.useCallback(
1302
+ (e) => {
1303
+ if (ctx.isDisabled || ctx.isReadOnly) return;
1304
+ let resolved;
1305
+ if (directRange) {
1306
+ resolved = directRange;
1307
+ } else if (presetKey) {
1308
+ resolved = resolvePreset(presetKey, ctx.adapter.today(), ctx.adapter);
1309
+ } else {
1310
+ return;
1311
+ }
1312
+ ctx.setRange(resolved);
1313
+ ctx.close();
1314
+ onClick?.(e);
1315
+ },
1316
+ [ctx, presetKey, directRange, onClick]
1317
+ );
1318
+ const isActive = (() => {
1319
+ if (!ctx.value.start || !ctx.value.end) return false;
1320
+ let target;
1321
+ if (directRange) {
1322
+ target = directRange;
1323
+ } else if (presetKey) {
1324
+ target = resolvePreset(presetKey, ctx.adapter.today(), ctx.adapter);
1325
+ } else {
1326
+ return false;
1327
+ }
1328
+ return target.start !== null && target.end !== null && ctx.adapter.isSameDay(ctx.value.start, target.start) && ctx.adapter.isSameDay(ctx.value.end, target.end);
1329
+ })();
1330
+ return /* @__PURE__ */ jsxRuntime.jsx(
1331
+ "button",
1332
+ {
1333
+ type: "button",
1334
+ role: "option",
1335
+ "aria-selected": isActive,
1336
+ "data-active": isActive || void 0,
1337
+ disabled: ctx.isDisabled,
1338
+ onClick: handleClick,
1339
+ ...props,
1340
+ children
1341
+ }
1342
+ );
1343
+ }
1344
+
1345
+ // src/components/RangePicker/index.ts
1346
+ var RangePicker = Object.assign(RangePickerRoot, {
1347
+ Input: RangePickerInput,
1348
+ Popover: RangePickerPopover,
1349
+ Calendar: RangePickerCalendar,
1350
+ Presets: RangePickerPresets,
1351
+ Preset: RangePickerPreset
1352
+ });
1353
+ var TimePickerContext = react.createContext(null);
1354
+ function useTimePickerContext(componentName) {
1355
+ const context = react.useContext(TimePickerContext);
1356
+ if (!context) {
1357
+ throw new Error(
1358
+ `[${componentName}] TimePicker.Root \uB0B4\uBD80\uC5D0\uC11C \uC0AC\uC6A9\uD574\uC57C \uD569\uB2C8\uB2E4.
1359
+
1360
+ \uC62C\uBC14\uB978 \uC0AC\uC6A9\uBC95:
1361
+ <TimePicker>
1362
+ <TimePicker.${componentName.replace("TimePicker.", "")} />
1363
+ </TimePicker>`
1364
+ );
1365
+ }
1366
+ return context;
1367
+ }
1368
+ function getDefaultIso() {
1369
+ const now = /* @__PURE__ */ new Date();
1370
+ return new Date(
1371
+ Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
1372
+ ).toISOString();
1373
+ }
1374
+ function TimePickerRoot({
1375
+ value: controlledValue,
1376
+ defaultValue,
1377
+ onChange,
1378
+ format = "24h",
1379
+ step = 1,
1380
+ withSeconds = false,
1381
+ disabled = false,
1382
+ readOnly = false,
1383
+ children
1384
+ }) {
1385
+ const pickerId = react.useId();
1386
+ const isControlled = react.useRef(controlledValue !== void 0).current;
1387
+ const [uncontrolledValue, setUncontrolledValue] = react.useState(
1388
+ defaultValue ?? null
1389
+ );
1390
+ const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
1391
+ const baseIso = currentValue ?? getDefaultIso();
1392
+ const currentTime = react.useMemo(() => core.getTime(baseIso), [baseIso]);
1393
+ const setTime = react.useCallback(
1394
+ (partial) => {
1395
+ if (disabled || readOnly) return;
1396
+ const newIso = core.setTime(baseIso, partial);
1397
+ if (!isControlled) {
1398
+ setUncontrolledValue(newIso);
1399
+ }
1400
+ onChange?.(newIso);
1401
+ },
1402
+ [disabled, readOnly, baseIso, isControlled, onChange]
1403
+ );
1404
+ const contextValue = react.useMemo(
1405
+ () => ({
1406
+ value: currentValue,
1407
+ setTime,
1408
+ format,
1409
+ step,
1410
+ withSeconds,
1411
+ isDisabled: disabled,
1412
+ isReadOnly: readOnly,
1413
+ currentTime,
1414
+ pickerId
1415
+ }),
1416
+ [currentValue, setTime, format, step, withSeconds, disabled, readOnly, currentTime, pickerId]
1417
+ );
1418
+ return /* @__PURE__ */ jsxRuntime.jsx(TimePickerContext.Provider, { value: contextValue, children });
1419
+ }
1420
+ var TimePickerInput = react.forwardRef(
1421
+ function TimePickerInput2({ onBlur, onKeyDown, ...props }, ref) {
1422
+ const ctx = useTimePickerContext("TimePicker.Input");
1423
+ const [inputText, setInputText] = react.useState(null);
1424
+ const displayValue = inputText !== null ? inputText : core.formatTimeString(ctx.currentTime, ctx.withSeconds);
1425
+ const commitInput = react.useCallback(() => {
1426
+ if (inputText === null) return;
1427
+ const parsed = core.parseTimeString(inputText);
1428
+ if (parsed) {
1429
+ ctx.setTime(parsed);
1430
+ }
1431
+ setInputText(null);
1432
+ }, [inputText, ctx]);
1433
+ const handleChange = react.useCallback(
1434
+ (e) => {
1435
+ setInputText(e.target.value);
1436
+ },
1437
+ []
1438
+ );
1439
+ const handleBlur = react.useCallback(
1440
+ (e) => {
1441
+ commitInput();
1442
+ onBlur?.(e);
1443
+ },
1444
+ [commitInput, onBlur]
1445
+ );
1446
+ const handleKeyDown = react.useCallback(
1447
+ (e) => {
1448
+ if (e.key === "Enter") {
1449
+ commitInput();
1450
+ }
1451
+ onKeyDown?.(e);
1452
+ },
1453
+ [commitInput, onKeyDown]
1454
+ );
1455
+ return /* @__PURE__ */ jsxRuntime.jsx(
1456
+ "input",
1457
+ {
1458
+ ref,
1459
+ type: "text",
1460
+ inputMode: "numeric",
1461
+ autoComplete: "off",
1462
+ "aria-label": "\uC2DC\uAC04 \uC785\uB825",
1463
+ placeholder: ctx.withSeconds ? "HH:MM:SS" : "HH:MM",
1464
+ value: displayValue,
1465
+ disabled: ctx.isDisabled || props.disabled,
1466
+ readOnly: ctx.isReadOnly,
1467
+ onChange: handleChange,
1468
+ onBlur: handleBlur,
1469
+ onKeyDown: handleKeyDown,
1470
+ ...props
1471
+ }
1472
+ );
1473
+ }
1474
+ );
1475
+ function TimePickerHourList({ classNames, ...props }) {
1476
+ const ctx = useTimePickerContext("TimePicker.HourList");
1477
+ const { format, currentTime, isDisabled, isReadOnly } = ctx;
1478
+ const listRef = react.useRef(null);
1479
+ const hours = core.generateHours(format);
1480
+ const selectedHourDisplay = format === "12h" ? core.to12Hour(currentTime.hours).hours12 : currentTime.hours;
1481
+ const currentPeriod = format === "12h" ? core.to12Hour(currentTime.hours).period : null;
1482
+ const handleSelect = react.useCallback(
1483
+ (hourDisplay) => {
1484
+ if (isDisabled || isReadOnly) return;
1485
+ const hours24 = format === "12h" && currentPeriod ? core.to24Hour(hourDisplay, currentPeriod) : hourDisplay;
1486
+ ctx.setTime({ hours: hours24 });
1487
+ },
1488
+ [format, currentPeriod, ctx, isDisabled, isReadOnly]
1489
+ );
1490
+ const handleKeyDown = react.useCallback(
1491
+ (e, hour) => {
1492
+ if (isDisabled || isReadOnly) return;
1493
+ const currentIndex = hours.indexOf(hour);
1494
+ let newIndex = -1;
1495
+ if (e.key === "ArrowDown") {
1496
+ newIndex = Math.min(currentIndex + 1, hours.length - 1);
1497
+ } else if (e.key === "ArrowUp") {
1498
+ newIndex = Math.max(currentIndex - 1, 0);
1499
+ } else if (e.key === "Home") {
1500
+ newIndex = 0;
1501
+ } else if (e.key === "End") {
1502
+ newIndex = hours.length - 1;
1503
+ } else if (e.key === "Enter" || e.key === " ") {
1504
+ e.preventDefault();
1505
+ handleSelect(hour);
1506
+ return;
1507
+ } else {
1508
+ return;
1509
+ }
1510
+ e.preventDefault();
1511
+ const targetHour = hours[newIndex];
1512
+ if (targetHour !== void 0) {
1513
+ handleSelect(targetHour);
1514
+ requestAnimationFrame(() => {
1515
+ const next = listRef.current?.querySelector(
1516
+ '[data-selected="true"]'
1517
+ );
1518
+ next?.focus();
1519
+ });
1520
+ }
1521
+ },
1522
+ [hours, handleSelect, isDisabled, isReadOnly]
1523
+ );
1524
+ return /* @__PURE__ */ jsxRuntime.jsx(
1525
+ "ul",
1526
+ {
1527
+ ref: listRef,
1528
+ role: "listbox",
1529
+ "aria-label": "\uC2DC",
1530
+ "aria-disabled": isDisabled || void 0,
1531
+ className: classNames?.root,
1532
+ ...props,
1533
+ children: hours.map((hour) => {
1534
+ const isSelected = hour === selectedHourDisplay;
1535
+ const optionClass = [classNames?.option, isSelected && classNames?.optionSelected].filter(Boolean).join(" ") || void 0;
1536
+ return /* @__PURE__ */ jsxRuntime.jsx(
1537
+ "li",
1538
+ {
1539
+ role: "option",
1540
+ "aria-selected": isSelected,
1541
+ "aria-disabled": isDisabled || void 0,
1542
+ "aria-label": `${hour}\uC2DC`,
1543
+ "data-selected": isSelected || void 0,
1544
+ tabIndex: isSelected ? 0 : -1,
1545
+ className: optionClass,
1546
+ onClick: () => handleSelect(hour),
1547
+ onKeyDown: (e) => handleKeyDown(e, hour),
1548
+ children: String(hour).padStart(2, "0")
1549
+ },
1550
+ hour
1551
+ );
1552
+ })
1553
+ }
1554
+ );
1555
+ }
1556
+ function TimePickerMinuteList({ classNames, ...props }) {
1557
+ const ctx = useTimePickerContext("TimePicker.MinuteList");
1558
+ const { step, currentTime, isDisabled, isReadOnly } = ctx;
1559
+ const listRef = react.useRef(null);
1560
+ const minutes = core.generateMinutes(step);
1561
+ const handleSelect = react.useCallback(
1562
+ (minute) => {
1563
+ if (isDisabled || isReadOnly) return;
1564
+ ctx.setTime({ minutes: minute });
1565
+ },
1566
+ [ctx, isDisabled, isReadOnly]
1567
+ );
1568
+ const handleKeyDown = react.useCallback(
1569
+ (e, minute) => {
1570
+ if (isDisabled || isReadOnly) return;
1571
+ const currentIndex = minutes.indexOf(minute);
1572
+ let newIndex = -1;
1573
+ if (e.key === "ArrowDown") {
1574
+ newIndex = Math.min(currentIndex + 1, minutes.length - 1);
1575
+ } else if (e.key === "ArrowUp") {
1576
+ newIndex = Math.max(currentIndex - 1, 0);
1577
+ } else if (e.key === "Home") {
1578
+ newIndex = 0;
1579
+ } else if (e.key === "End") {
1580
+ newIndex = minutes.length - 1;
1581
+ } else if (e.key === "Enter" || e.key === " ") {
1582
+ e.preventDefault();
1583
+ handleSelect(minute);
1584
+ return;
1585
+ } else {
1586
+ return;
1587
+ }
1588
+ e.preventDefault();
1589
+ const target = minutes[newIndex];
1590
+ if (target !== void 0) {
1591
+ handleSelect(target);
1592
+ requestAnimationFrame(() => {
1593
+ const next = listRef.current?.querySelector(
1594
+ '[data-selected="true"]'
1595
+ );
1596
+ next?.focus();
1597
+ });
1598
+ }
1599
+ },
1600
+ [minutes, handleSelect, isDisabled, isReadOnly]
1601
+ );
1602
+ return /* @__PURE__ */ jsxRuntime.jsx(
1603
+ "ul",
1604
+ {
1605
+ ref: listRef,
1606
+ role: "listbox",
1607
+ "aria-label": "\uBD84",
1608
+ "aria-disabled": isDisabled || void 0,
1609
+ className: classNames?.root,
1610
+ ...props,
1611
+ children: minutes.map((minute) => {
1612
+ const isSelected = minute === currentTime.minutes;
1613
+ const optionClass = [classNames?.option, isSelected && classNames?.optionSelected].filter(Boolean).join(" ") || void 0;
1614
+ return /* @__PURE__ */ jsxRuntime.jsx(
1615
+ "li",
1616
+ {
1617
+ role: "option",
1618
+ "aria-selected": isSelected,
1619
+ "aria-disabled": isDisabled || void 0,
1620
+ "aria-label": `${minute}\uBD84`,
1621
+ "data-selected": isSelected || void 0,
1622
+ tabIndex: isSelected ? 0 : -1,
1623
+ className: optionClass,
1624
+ onClick: () => handleSelect(minute),
1625
+ onKeyDown: (e) => handleKeyDown(e, minute),
1626
+ children: String(minute).padStart(2, "0")
1627
+ },
1628
+ minute
1629
+ );
1630
+ })
1631
+ }
1632
+ );
1633
+ }
1634
+ function TimePickerAmPmToggle({ classNames, ...props }) {
1635
+ const ctx = useTimePickerContext("TimePicker.AmPmToggle");
1636
+ if (ctx.format !== "12h") return null;
1637
+ const { period, hours12 } = core.to12Hour(ctx.currentTime.hours);
1638
+ const setPeriod = react.useCallback(
1639
+ (newPeriod) => {
1640
+ if (ctx.isDisabled || ctx.isReadOnly) return;
1641
+ const newHours24 = core.to24Hour(hours12, newPeriod);
1642
+ ctx.setTime({ hours: newHours24 });
1643
+ },
1644
+ [hours12, ctx]
1645
+ );
1646
+ const renderButton = (target) => {
1647
+ const isSelected = period === target;
1648
+ const optionClass = [classNames?.option, isSelected && classNames?.optionSelected].filter(Boolean).join(" ") || void 0;
1649
+ return /* @__PURE__ */ jsxRuntime.jsx(
1650
+ "button",
1651
+ {
1652
+ type: "button",
1653
+ role: "radio",
1654
+ "aria-checked": isSelected,
1655
+ "data-selected": isSelected || void 0,
1656
+ disabled: ctx.isDisabled,
1657
+ className: optionClass,
1658
+ onClick: () => setPeriod(target),
1659
+ children: target
1660
+ }
1661
+ );
1662
+ };
1663
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "radiogroup", "aria-label": "\uC624\uC804/\uC624\uD6C4", className: classNames?.root, ...props, children: [
1664
+ renderButton("AM"),
1665
+ renderButton("PM")
1666
+ ] });
1667
+ }
1668
+
1669
+ // src/components/TimePicker/index.ts
1670
+ var TimePicker = Object.assign(TimePickerRoot, {
1671
+ Input: TimePickerInput,
1672
+ HourList: TimePickerHourList,
1673
+ MinuteList: TimePickerMinuteList,
1674
+ AmPmToggle: TimePickerAmPmToggle
1675
+ });
1676
+ function getDefaultIso2() {
1677
+ const now = /* @__PURE__ */ new Date();
1678
+ return new Date(
1679
+ Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
1680
+ ).toISOString();
1681
+ }
1682
+ function DateTimePickerRoot({
1683
+ value: controlledValue,
1684
+ defaultValue,
1685
+ onChange,
1686
+ format = "24h",
1687
+ step = 1,
1688
+ disabled = false,
1689
+ readOnly = false,
1690
+ weekStartsOn = 0,
1691
+ displayFormat = "yyyy-MM-dd HH:mm",
1692
+ locale = "en-US",
1693
+ adapter = core.DateFnsAdapter,
1694
+ children
1695
+ }) {
1696
+ const pickerId = react.useId();
1697
+ const isControlled = react.useRef(controlledValue !== void 0).current;
1698
+ const referenceRef = react.useRef(null);
1699
+ const [uncontrolledValue, setUncontrolledValue] = react.useState(
1700
+ defaultValue ?? null
1701
+ );
1702
+ const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
1703
+ const [isOpen, setIsOpen] = react.useState(false);
1704
+ const [viewMonth, setViewMonth] = react.useState(
1705
+ currentValue ?? adapter.today()
1706
+ );
1707
+ const [focusedDate, setFocusedDate] = react.useState(
1708
+ currentValue ?? adapter.today()
1709
+ );
1710
+ const isDisabled = typeof disabled === "boolean" ? disabled : false;
1711
+ const disabledRules = Array.isArray(disabled) ? disabled : [];
1712
+ const baseIso = currentValue ?? getDefaultIso2();
1713
+ const currentTime = react.useMemo(() => core.getTime(baseIso), [baseIso]);
1714
+ const updateValue = react.useCallback(
1715
+ (next) => {
1716
+ if (isDisabled || readOnly) return;
1717
+ if (!isControlled) {
1718
+ setUncontrolledValue(next);
1719
+ }
1720
+ onChange?.(next);
1721
+ },
1722
+ [isControlled, isDisabled, readOnly, onChange]
1723
+ );
1724
+ const selectDate = react.useCallback(
1725
+ (newDateIso) => {
1726
+ if (newDateIso === null) {
1727
+ updateValue(null);
1728
+ return;
1729
+ }
1730
+ const time = currentValue ? core.getTime(currentValue) : currentTime;
1731
+ const merged = core.setTime(newDateIso, time);
1732
+ updateValue(merged);
1733
+ },
1734
+ [currentValue, currentTime, updateValue]
1735
+ );
1736
+ const setTime = react.useCallback(
1737
+ (partial) => {
1738
+ const base = currentValue ?? getDefaultIso2();
1739
+ const merged = core.setTime(base, partial);
1740
+ updateValue(merged);
1741
+ },
1742
+ [currentValue, updateValue]
1743
+ );
1744
+ const open = react.useCallback(() => {
1745
+ if (isDisabled || readOnly) return;
1746
+ setIsOpen(true);
1747
+ const target = currentValue ?? adapter.today();
1748
+ setViewMonth(target);
1749
+ setFocusedDate(target);
1750
+ }, [isDisabled, readOnly, currentValue, adapter]);
1751
+ const close = react.useCallback(() => {
1752
+ setIsOpen(false);
1753
+ }, []);
1754
+ const toggle = react.useCallback(() => {
1755
+ if (isOpen) close();
1756
+ else open();
1757
+ }, [isOpen, open, close]);
1758
+ const dateContext = react.useMemo(
1759
+ () => ({
1760
+ referenceRef,
1761
+ value: currentValue,
1762
+ selectDate,
1763
+ isOpen,
1764
+ open,
1765
+ close,
1766
+ toggle,
1767
+ viewMonth,
1768
+ setViewMonth,
1769
+ focusedDate,
1770
+ setFocusedDate,
1771
+ adapter,
1772
+ disabled: disabledRules,
1773
+ weekStartsOn,
1774
+ displayFormat,
1775
+ locale,
1776
+ isDisabled,
1777
+ isReadOnly: readOnly,
1778
+ pickerId
1779
+ }),
1780
+ [
1781
+ currentValue,
1782
+ selectDate,
1783
+ isOpen,
1784
+ open,
1785
+ close,
1786
+ toggle,
1787
+ viewMonth,
1788
+ focusedDate,
1789
+ adapter,
1790
+ disabledRules,
1791
+ weekStartsOn,
1792
+ displayFormat,
1793
+ locale,
1794
+ isDisabled,
1795
+ readOnly,
1796
+ pickerId
1797
+ ]
1798
+ );
1799
+ const timeContext = react.useMemo(
1800
+ () => ({
1801
+ value: currentValue,
1802
+ setTime,
1803
+ format,
1804
+ step,
1805
+ withSeconds: false,
1806
+ isDisabled,
1807
+ isReadOnly: readOnly,
1808
+ currentTime,
1809
+ pickerId
1810
+ }),
1811
+ [currentValue, setTime, format, step, isDisabled, readOnly, currentTime, pickerId]
1812
+ );
1813
+ return /* @__PURE__ */ jsxRuntime.jsx(DatePickerContext.Provider, { value: dateContext, children: /* @__PURE__ */ jsxRuntime.jsx(TimePickerContext.Provider, { value: timeContext, children }) });
1814
+ }
1815
+ var DateTimePickerInput = react.forwardRef(
1816
+ function DateTimePickerInput2({ onFocus, onKeyDown, ...props }, ref) {
1817
+ const ctx = useDatePickerContext("DateTimePicker.Input");
1818
+ const displayValue = ctx.value ? `${ctx.adapter.format(ctx.value, "yyyy-MM-dd")} ${core.formatTimeString(core.getTime(ctx.value))}` : "";
1819
+ const handleFocus = react.useCallback(
1820
+ (e) => {
1821
+ ctx.open();
1822
+ onFocus?.(e);
1823
+ },
1824
+ [ctx, onFocus]
1825
+ );
1826
+ const handleKeyDown = react.useCallback(
1827
+ (e) => {
1828
+ if (e.key === "Escape") {
1829
+ ctx.close();
1830
+ } else if (e.key === "ArrowDown" && !ctx.isOpen) {
1831
+ e.preventDefault();
1832
+ ctx.open();
1833
+ }
1834
+ onKeyDown?.(e);
1835
+ },
1836
+ [ctx, onKeyDown]
1837
+ );
1838
+ const calendarId = `${ctx.pickerId}-calendar`;
1839
+ return /* @__PURE__ */ jsxRuntime.jsx(
1840
+ "input",
1841
+ {
1842
+ ref: (node) => {
1843
+ ctx.referenceRef.current = node;
1844
+ if (typeof ref === "function") ref(node);
1845
+ else if (ref) ref.current = node;
1846
+ },
1847
+ type: "text",
1848
+ role: "combobox",
1849
+ readOnly: true,
1850
+ "aria-label": "\uB0A0\uC9DC \uBC0F \uC2DC\uAC04",
1851
+ "aria-expanded": ctx.isOpen,
1852
+ "aria-haspopup": "dialog",
1853
+ "aria-controls": ctx.isOpen ? calendarId : void 0,
1854
+ "aria-autocomplete": "none",
1855
+ autoComplete: "off",
1856
+ value: displayValue,
1857
+ disabled: ctx.isDisabled || props.disabled,
1858
+ onFocus: handleFocus,
1859
+ onKeyDown: handleKeyDown,
1860
+ ...props
1861
+ }
1862
+ );
1863
+ }
1864
+ );
1865
+
1866
+ // src/components/DateTimePicker/index.ts
1867
+ var DateTimePicker = Object.assign(DateTimePickerRoot, {
1868
+ Input: DateTimePickerInput,
1869
+ Popover: DatePickerPopover,
1870
+ Calendar: DatePickerCalendar,
1871
+ MonthGrid: DatePickerMonthGrid,
1872
+ YearGrid: DatePickerYearGrid,
1873
+ HourList: TimePickerHourList,
1874
+ MinuteList: TimePickerMinuteList,
1875
+ AmPmToggle: TimePickerAmPmToggle
1876
+ });
1877
+ function useDatePicker(options = {}) {
1878
+ const {
1879
+ value: controlledValue,
1880
+ defaultValue,
1881
+ onChange,
1882
+ disabled = [],
1883
+ weekStartsOn = 0,
1884
+ adapter = core.DateFnsAdapter
1885
+ } = options;
1886
+ const pickerId = react.useId();
1887
+ const isControlled = react.useRef(controlledValue !== void 0).current;
1888
+ const [uncontrolledValue, setUncontrolledValue] = react.useState(
1889
+ defaultValue ?? null
1890
+ );
1891
+ const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
1892
+ const [isOpen, setIsOpen] = react.useState(false);
1893
+ const [viewMonth, setViewMonth] = react.useState(currentValue ?? adapter.today());
1894
+ const [focusedDate, setFocusedDate] = react.useState(currentValue ?? adapter.today());
1895
+ const selectDate = react.useCallback(
1896
+ (iso) => {
1897
+ if (!isControlled) {
1898
+ setUncontrolledValue(iso);
1899
+ }
1900
+ onChange?.(iso);
1901
+ setIsOpen(false);
1902
+ },
1903
+ [isControlled, onChange]
1904
+ );
1905
+ const open = react.useCallback(() => {
1906
+ setIsOpen(true);
1907
+ const target = currentValue ?? adapter.today();
1908
+ setViewMonth(target);
1909
+ setFocusedDate(target);
1910
+ }, [currentValue, adapter]);
1911
+ const close = react.useCallback(() => {
1912
+ setIsOpen(false);
1913
+ }, []);
1914
+ const toggle = react.useCallback(() => {
1915
+ if (isOpen) close();
1916
+ else open();
1917
+ }, [isOpen, open, close]);
1918
+ const previousMonth = react.useCallback(() => {
1919
+ const newMonth = adapter.addMonths(viewMonth, -1);
1920
+ setViewMonth(newMonth);
1921
+ setFocusedDate(adapter.startOfMonth(newMonth));
1922
+ }, [adapter, viewMonth]);
1923
+ const nextMonth = react.useCallback(() => {
1924
+ const newMonth = adapter.addMonths(viewMonth, 1);
1925
+ setViewMonth(newMonth);
1926
+ setFocusedDate(adapter.startOfMonth(newMonth));
1927
+ }, [adapter, viewMonth]);
1928
+ const calendar = core.getCalendarDays(viewMonth, adapter, {
1929
+ weekStartsOn,
1930
+ selected: currentValue,
1931
+ focusedDate,
1932
+ disabled
1933
+ });
1934
+ return {
1935
+ value: currentValue,
1936
+ isOpen,
1937
+ open,
1938
+ close,
1939
+ toggle,
1940
+ selectDate,
1941
+ viewMonth,
1942
+ setViewMonth,
1943
+ calendar,
1944
+ focusedDate,
1945
+ setFocusedDate,
1946
+ previousMonth,
1947
+ nextMonth,
1948
+ pickerId,
1949
+ adapter
1950
+ };
1951
+ }
1952
+ var EMPTY_RANGE2 = { start: null, end: null };
1953
+ function useRangePicker(options = {}) {
1954
+ const {
1955
+ value: controlledValue,
1956
+ defaultValue,
1957
+ onChange,
1958
+ disabled = [],
1959
+ weekStartsOn = 0,
1960
+ adapter = core.DateFnsAdapter
1961
+ } = options;
1962
+ const pickerId = react.useId();
1963
+ const isControlled = react.useRef(controlledValue !== void 0).current;
1964
+ const [uncontrolledValue, setUncontrolledValue] = react.useState(
1965
+ defaultValue ?? EMPTY_RANGE2
1966
+ );
1967
+ const currentValue = isControlled ? controlledValue ?? EMPTY_RANGE2 : uncontrolledValue;
1968
+ const [isOpen, setIsOpen] = react.useState(false);
1969
+ const [selectingTarget, setSelectingTarget] = react.useState("start");
1970
+ const [hoverDate, setHoverDate] = react.useState(null);
1971
+ const [viewMonth, setViewMonth] = react.useState(
1972
+ currentValue.start ?? adapter.today()
1973
+ );
1974
+ const [focusedDate, setFocusedDate] = react.useState(
1975
+ currentValue.start ?? adapter.today()
1976
+ );
1977
+ const setRange = react.useCallback(
1978
+ (range) => {
1979
+ if (!isControlled) {
1980
+ setUncontrolledValue(range);
1981
+ }
1982
+ onChange?.(range);
1983
+ },
1984
+ [isControlled, onChange]
1985
+ );
1986
+ const selectDate = react.useCallback(
1987
+ (iso) => {
1988
+ if (selectingTarget === "start") {
1989
+ setRange({ start: iso, end: null });
1990
+ setSelectingTarget("end");
1991
+ setHoverDate(null);
1992
+ } else {
1993
+ const start = currentValue.start;
1994
+ if (!start) {
1995
+ setRange({ start: iso, end: null });
1996
+ setSelectingTarget("end");
1997
+ return;
1998
+ }
1999
+ const newRange = adapter.isBefore(iso, start) ? { start: iso, end: start } : { start, end: iso };
2000
+ setRange(newRange);
2001
+ setSelectingTarget("start");
2002
+ setHoverDate(null);
2003
+ setIsOpen(false);
2004
+ }
2005
+ },
2006
+ [selectingTarget, currentValue.start, adapter, setRange]
2007
+ );
2008
+ const open = react.useCallback(() => {
2009
+ setIsOpen(true);
2010
+ const target = currentValue.start ?? adapter.today();
2011
+ setViewMonth(target);
2012
+ setFocusedDate(target);
2013
+ if (currentValue.start && currentValue.end) {
2014
+ setSelectingTarget("start");
2015
+ }
2016
+ }, [currentValue, adapter]);
2017
+ const close = react.useCallback(() => {
2018
+ setIsOpen(false);
2019
+ setHoverDate(null);
2020
+ }, []);
2021
+ const toggle = react.useCallback(() => {
2022
+ if (isOpen) close();
2023
+ else open();
2024
+ }, [isOpen, open, close]);
2025
+ const previousMonth = react.useCallback(() => {
2026
+ const newMonth = adapter.addMonths(viewMonth, -1);
2027
+ setViewMonth(newMonth);
2028
+ setFocusedDate(adapter.startOfMonth(newMonth));
2029
+ }, [adapter, viewMonth]);
2030
+ const nextMonth = react.useCallback(() => {
2031
+ const newMonth = adapter.addMonths(viewMonth, 1);
2032
+ setViewMonth(newMonth);
2033
+ setFocusedDate(adapter.startOfMonth(newMonth));
2034
+ }, [adapter, viewMonth]);
2035
+ const calendar = core.getCalendarDays(viewMonth, adapter, {
2036
+ weekStartsOn,
2037
+ focusedDate,
2038
+ disabled,
2039
+ range: currentValue,
2040
+ rangeHover: hoverDate
2041
+ });
2042
+ return {
2043
+ value: currentValue,
2044
+ selectingTarget,
2045
+ selectDate,
2046
+ setRange,
2047
+ isOpen,
2048
+ open,
2049
+ close,
2050
+ toggle,
2051
+ hoverDate,
2052
+ setHoverDate,
2053
+ viewMonth,
2054
+ setViewMonth,
2055
+ calendar,
2056
+ focusedDate,
2057
+ setFocusedDate,
2058
+ previousMonth,
2059
+ nextMonth,
2060
+ pickerId,
2061
+ adapter
2062
+ };
2063
+ }
2064
+ function getDefaultIso3() {
2065
+ const now = /* @__PURE__ */ new Date();
2066
+ return new Date(
2067
+ Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
2068
+ ).toISOString();
2069
+ }
2070
+ function useTimePicker(options = {}) {
2071
+ const {
2072
+ value: controlledValue,
2073
+ defaultValue,
2074
+ onChange,
2075
+ format = "24h",
2076
+ step = 1
2077
+ } = options;
2078
+ const pickerId = react.useId();
2079
+ const isControlled = react.useRef(controlledValue !== void 0).current;
2080
+ const [uncontrolledValue, setUncontrolledValue] = react.useState(
2081
+ defaultValue ?? null
2082
+ );
2083
+ const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
2084
+ const baseIso = currentValue ?? getDefaultIso3();
2085
+ const currentTime = react.useMemo(() => core.getTime(baseIso), [baseIso]);
2086
+ const setTime = react.useCallback(
2087
+ (partial) => {
2088
+ const newIso = core.setTime(baseIso, partial);
2089
+ if (!isControlled) {
2090
+ setUncontrolledValue(newIso);
2091
+ }
2092
+ onChange?.(newIso);
2093
+ },
2094
+ [baseIso, isControlled, onChange]
2095
+ );
2096
+ const period = format === "12h" ? core.to12Hour(currentTime.hours).period : null;
2097
+ const displayHour = format === "12h" ? core.to12Hour(currentTime.hours).hours12 : currentTime.hours;
2098
+ const setHour = react.useCallback(
2099
+ (hour) => {
2100
+ const hours24 = format === "12h" && period ? core.to24Hour(hour, period) : hour;
2101
+ setTime({ hours: hours24 });
2102
+ },
2103
+ [format, period, setTime]
2104
+ );
2105
+ const setMinute = react.useCallback(
2106
+ (minute) => setTime({ minutes: minute }),
2107
+ [setTime]
2108
+ );
2109
+ const setSecond = react.useCallback(
2110
+ (second) => setTime({ seconds: second }),
2111
+ [setTime]
2112
+ );
2113
+ const setPeriod = react.useCallback(
2114
+ (newPeriod) => {
2115
+ if (format !== "12h") return;
2116
+ const newHours24 = core.to24Hour(displayHour, newPeriod);
2117
+ setTime({ hours: newHours24 });
2118
+ },
2119
+ [format, displayHour, setTime]
2120
+ );
2121
+ return {
2122
+ value: currentValue,
2123
+ currentTime,
2124
+ setTime,
2125
+ setHour,
2126
+ setMinute,
2127
+ setSecond,
2128
+ setPeriod,
2129
+ availableHours: core.generateHours(format),
2130
+ availableMinutes: core.generateMinutes(step),
2131
+ format,
2132
+ displayHour,
2133
+ period,
2134
+ pickerId
2135
+ };
2136
+ }
2137
+
2138
+ Object.defineProperty(exports, "DateFnsAdapter", {
2139
+ enumerable: true,
2140
+ get: function () { return core.DateFnsAdapter; }
2141
+ });
2142
+ exports.DatePicker = DatePicker;
2143
+ exports.DateTimePicker = DateTimePicker;
2144
+ exports.RangePicker = RangePicker;
2145
+ exports.TimePicker = TimePicker;
2146
+ exports.useDatePicker = useDatePicker;
2147
+ exports.useRangePicker = useRangePicker;
2148
+ exports.useTimePicker = useTimePicker;
2149
+ //# sourceMappingURL=index.cjs.map
2150
+ //# sourceMappingURL=index.cjs.map