@kalyx/react 0.2.1 → 0.3.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.
package/dist/index.cjs CHANGED
@@ -31,6 +31,7 @@ function DatePickerRoot({
31
31
  displayFormat = "yyyy-MM-dd",
32
32
  locale = "en-US",
33
33
  adapter = core.DateFnsAdapter,
34
+ labels: labelsProp,
34
35
  children
35
36
  }) {
36
37
  const pickerId = react.useId();
@@ -47,8 +48,15 @@ function DatePickerRoot({
47
48
  const [focusedDate, setFocusedDate] = react.useState(
48
49
  currentValue ?? adapter.today()
49
50
  );
51
+ const mergedLabels = react.useMemo(
52
+ () => ({ ...core.DEFAULT_DATEPICKER_LABELS, ...labelsProp }),
53
+ [labelsProp]
54
+ );
50
55
  const isDisabled = typeof disabled === "boolean" ? disabled : false;
51
- const disabledRules = Array.isArray(disabled) ? disabled : [];
56
+ const disabledRules = react.useMemo(
57
+ () => Array.isArray(disabled) ? disabled : [],
58
+ [disabled]
59
+ );
52
60
  const selectDate = react.useCallback(
53
61
  (iso) => {
54
62
  if (isDisabled || readOnly) return;
@@ -97,7 +105,8 @@ function DatePickerRoot({
97
105
  locale,
98
106
  isDisabled,
99
107
  isReadOnly: readOnly,
100
- pickerId
108
+ pickerId,
109
+ labels: mergedLabels
101
110
  }),
102
111
  [
103
112
  currentValue,
@@ -115,28 +124,37 @@ function DatePickerRoot({
115
124
  locale,
116
125
  isDisabled,
117
126
  readOnly,
118
- pickerId
127
+ pickerId,
128
+ mergedLabels
119
129
  ]
120
130
  );
121
131
  return /* @__PURE__ */ jsxRuntime.jsx(DatePickerContext.Provider, { value: contextValue, children });
122
132
  }
123
133
  var DatePickerInput = react.forwardRef(
124
- function DatePickerInput2({ format: formatProp, onFocus, onBlur, onKeyDown, ...props }, ref) {
134
+ function DatePickerInput2({ format: formatProp, onClick, onBlur, onKeyDown, ...props }, ref) {
125
135
  const ctx = useDatePickerContext("DatePicker.Input");
126
136
  const displayFormat = formatProp ?? ctx.displayFormat;
127
137
  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(
138
+ let formattedValue = "";
139
+ if (ctx.value) {
140
+ try {
141
+ formattedValue = ctx.adapter.format(ctx.value, displayFormat);
142
+ } catch {
143
+ formattedValue = ctx.value;
144
+ }
145
+ }
146
+ const displayValue = inputText !== null ? inputText : formattedValue;
147
+ const handleClick = react.useCallback(
130
148
  (e) => {
131
- ctx.open();
132
- onFocus?.(e);
149
+ if (!ctx.isOpen) ctx.open();
150
+ onClick?.(e);
133
151
  },
134
- [ctx, onFocus]
152
+ [ctx, onClick]
135
153
  );
136
154
  const handleBlur = react.useCallback(
137
155
  (e) => {
138
156
  if (inputText !== null) {
139
- const parsed = core.parseInputValue(inputText, displayFormat, ctx.adapter);
157
+ const parsed = core.parseInputValue(inputText, ctx.adapter);
140
158
  if (parsed) {
141
159
  ctx.selectDate(parsed);
142
160
  }
@@ -155,7 +173,7 @@ var DatePickerInput = react.forwardRef(
155
173
  setInputText(null);
156
174
  return;
157
175
  }
158
- const parsed = core.parseInputValue(text, displayFormat, ctx.adapter);
176
+ const parsed = core.parseInputValue(text, ctx.adapter);
159
177
  if (parsed) {
160
178
  ctx.selectDate(parsed);
161
179
  setInputText(null);
@@ -169,7 +187,7 @@ var DatePickerInput = react.forwardRef(
169
187
  ctx.close();
170
188
  } else if (e.key === "Enter") {
171
189
  if (inputText !== null) {
172
- const parsed = core.parseInputValue(inputText, displayFormat, ctx.adapter);
190
+ const parsed = core.parseInputValue(inputText, ctx.adapter);
173
191
  if (parsed) {
174
192
  ctx.selectDate(parsed);
175
193
  setInputText(null);
@@ -203,7 +221,7 @@ var DatePickerInput = react.forwardRef(
203
221
  disabled: ctx.isDisabled || props.disabled,
204
222
  readOnly: ctx.isReadOnly,
205
223
  onChange: handleChange,
206
- onFocus: handleFocus,
224
+ onClick: handleClick,
207
225
  onBlur: handleBlur,
208
226
  onKeyDown: handleKeyDown,
209
227
  ...props
@@ -232,7 +250,7 @@ var DatePickerTrigger = react.forwardRef(
232
250
  },
233
251
  type: "button",
234
252
  tabIndex: 0,
235
- "aria-label": ctx.isOpen ? "\uCE98\uB9B0\uB354 \uB2EB\uAE30" : "\uCE98\uB9B0\uB354 \uC5F4\uAE30",
253
+ "aria-label": ctx.isOpen ? ctx.labels.triggerClose : ctx.labels.triggerOpen,
236
254
  "aria-expanded": ctx.isOpen,
237
255
  "aria-controls": ctx.isOpen ? calendarId : void 0,
238
256
  disabled: ctx.isDisabled || props.disabled,
@@ -264,38 +282,39 @@ var DatePickerTrigger = react.forwardRef(
264
282
  );
265
283
  }
266
284
  );
267
- function DatePickerPopover({ children, ...props }) {
268
- const ctx = useDatePickerContext("DatePicker.Popover");
269
- const calendarId = `${ctx.pickerId}-calendar`;
285
+ function usePopover({ isOpen, close, referenceRef, placement = "bottom-start" }) {
270
286
  const floatingRef = react.useRef(null);
287
+ const previousFocusRef = react.useRef(null);
271
288
  const { refs, floatingStyles } = react$1.useFloating({
272
- open: ctx.isOpen,
273
- placement: "bottom-start",
289
+ open: isOpen,
290
+ placement,
274
291
  middleware: [react$1.offset(4), react$1.flip(), react$1.shift({ padding: 8 })],
275
292
  whileElementsMounted: react$1.autoUpdate
276
293
  });
277
294
  react.useEffect(() => {
278
- if (ctx.referenceRef.current) {
279
- refs.setReference(ctx.referenceRef.current);
295
+ if (referenceRef.current) {
296
+ refs.setReference(referenceRef.current);
280
297
  }
281
- }, [ctx.referenceRef, refs, ctx.isOpen]);
282
- const previousFocusRef = react.useRef(null);
298
+ }, [referenceRef, refs, isOpen]);
283
299
  react.useEffect(() => {
284
- if (ctx.isOpen) {
300
+ if (isOpen) {
285
301
  previousFocusRef.current = document.activeElement;
286
302
  } else if (previousFocusRef.current) {
287
- previousFocusRef.current.focus();
303
+ const el = previousFocusRef.current;
288
304
  previousFocusRef.current = null;
305
+ if (el !== referenceRef.current && typeof el.focus === "function") {
306
+ el.focus({ preventScroll: true });
307
+ }
289
308
  }
290
- }, [ctx.isOpen]);
309
+ }, [isOpen, referenceRef]);
291
310
  react.useEffect(() => {
292
- if (!ctx.isOpen) return;
311
+ if (!isOpen) return;
293
312
  function handleClickOutside(e) {
294
313
  const floating = floatingRef.current;
295
- const reference = ctx.referenceRef.current;
314
+ const reference = referenceRef.current;
296
315
  const target = e.target;
297
316
  if (floating && !floating.contains(target) && (!reference || !reference.contains(target))) {
298
- ctx.close();
317
+ close();
299
318
  }
300
319
  }
301
320
  const timer = setTimeout(() => {
@@ -305,28 +324,39 @@ function DatePickerPopover({ children, ...props }) {
305
324
  clearTimeout(timer);
306
325
  document.removeEventListener("mousedown", handleClickOutside);
307
326
  };
308
- }, [ctx.isOpen, ctx]);
327
+ }, [isOpen, close, referenceRef]);
309
328
  react.useEffect(() => {
310
- if (!ctx.isOpen) return;
329
+ if (!isOpen) return;
311
330
  function handleKeyDown(e) {
312
331
  if (e.key === "Escape") {
313
- ctx.close();
332
+ close();
314
333
  }
315
334
  }
316
335
  document.addEventListener("keydown", handleKeyDown);
317
336
  return () => document.removeEventListener("keydown", handleKeyDown);
318
- }, [ctx.isOpen, ctx]);
337
+ }, [isOpen, close]);
338
+ const setFloatingRef = (node) => {
339
+ floatingRef.current = node;
340
+ refs.setFloating(node);
341
+ };
342
+ return { floatingStyles, setFloatingRef };
343
+ }
344
+ function DatePickerPopover({ children, ...props }) {
345
+ const ctx = useDatePickerContext("DatePicker.Popover");
346
+ const calendarId = `${ctx.pickerId}-calendar`;
347
+ const { floatingStyles, setFloatingRef } = usePopover({
348
+ isOpen: ctx.isOpen,
349
+ close: ctx.close,
350
+ referenceRef: ctx.referenceRef
351
+ });
319
352
  if (!ctx.isOpen) return null;
320
353
  return /* @__PURE__ */ jsxRuntime.jsx(
321
354
  "div",
322
355
  {
323
- ref: (node) => {
324
- floatingRef.current = node;
325
- refs.setFloating(node);
326
- },
356
+ ref: setFloatingRef,
327
357
  id: calendarId,
328
358
  role: "dialog",
329
- "aria-label": "\uB0A0\uC9DC \uC120\uD0DD",
359
+ "aria-label": ctx.labels.popoverLabel,
330
360
  "aria-modal": "false",
331
361
  style: floatingStyles,
332
362
  ...props,
@@ -334,6 +364,13 @@ function DatePickerPopover({ children, ...props }) {
334
364
  }
335
365
  );
336
366
  }
367
+ function safeFormatFullDate(iso, locale) {
368
+ try {
369
+ return core.formatFullDate(iso, locale);
370
+ } catch {
371
+ return iso;
372
+ }
373
+ }
337
374
  var srOnly = {
338
375
  position: "absolute",
339
376
  width: "1px",
@@ -365,7 +402,7 @@ function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
365
402
  const focusedButton = gridRef.current.querySelector(
366
403
  '[data-focused="true"]'
367
404
  );
368
- focusedButton?.focus();
405
+ focusedButton?.focus({ preventScroll: true });
369
406
  }, [focusedDate, ctx.isOpen]);
370
407
  const navigateMonth = react.useCallback(
371
408
  (direction) => {
@@ -382,7 +419,7 @@ function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
382
419
  (day) => {
383
420
  if (day.isDisabled) return;
384
421
  ctx.selectDate(day.isoString);
385
- setAnnouncement(core.formatFullDate(day.isoString, locale));
422
+ setAnnouncement(safeFormatFullDate(day.isoString, locale));
386
423
  },
387
424
  [ctx, locale]
388
425
  );
@@ -454,7 +491,7 @@ function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
454
491
  type: "button",
455
492
  className: classNames?.navButton,
456
493
  onClick: () => navigateMonth(-1),
457
- "aria-label": "\uC774\uC804 \uB2EC",
494
+ "aria-label": ctx.labels.prevMonth,
458
495
  children: "<"
459
496
  }
460
497
  ),
@@ -474,7 +511,7 @@ function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
474
511
  type: "button",
475
512
  className: classNames?.navButton,
476
513
  onClick: () => navigateMonth(1),
477
- "aria-label": "\uB2E4\uC74C \uB2EC",
514
+ "aria-label": ctx.labels.nextMonth,
478
515
  children: ">"
479
516
  }
480
517
  )
@@ -527,7 +564,7 @@ function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
527
564
  "data-outside-month": !day.isCurrentMonth || void 0,
528
565
  className: dayClasses,
529
566
  onClick: () => handleDayClick(day),
530
- "aria-label": core.formatFullDate(day.isoString, locale),
567
+ "aria-label": safeFormatFullDate(day.isoString, locale),
531
568
  children: day.dayNumber
532
569
  }
533
570
  )
@@ -583,7 +620,7 @@ function DatePickerMonthGrid({
583
620
  type: "button",
584
621
  className: classNames?.navButton,
585
622
  onClick: () => navigateYear(-1),
586
- "aria-label": "\uC774\uC804 \uB144",
623
+ "aria-label": ctx.labels.prevYear,
587
624
  children: "<"
588
625
  }
589
626
  ),
@@ -602,7 +639,7 @@ function DatePickerMonthGrid({
602
639
  type: "button",
603
640
  className: classNames?.navButton,
604
641
  onClick: () => navigateYear(1),
605
- "aria-label": "\uB2E4\uC74C \uB144",
642
+ "aria-label": ctx.labels.nextYear,
606
643
  children: ">"
607
644
  }
608
645
  )
@@ -687,7 +724,7 @@ function DatePickerYearGrid({
687
724
  type: "button",
688
725
  className: classNames?.navButton,
689
726
  onClick: () => navigateDecade(-1),
690
- "aria-label": "\uC774\uC804 12\uB144",
727
+ "aria-label": ctx.labels.prevDecade,
691
728
  children: "<"
692
729
  }
693
730
  ),
@@ -698,7 +735,7 @@ function DatePickerYearGrid({
698
735
  type: "button",
699
736
  className: classNames?.navButton,
700
737
  onClick: () => navigateDecade(1),
701
- "aria-label": "\uB2E4\uC74C 12\uB144",
738
+ "aria-label": ctx.labels.nextDecade,
702
739
  children: ">"
703
740
  }
704
741
  )
@@ -772,6 +809,7 @@ function RangePickerRoot({
772
809
  displayFormat = "yyyy-MM-dd",
773
810
  locale = "en-US",
774
811
  adapter = core.DateFnsAdapter,
812
+ labels: labelsProp,
775
813
  children
776
814
  }) {
777
815
  const pickerId = react.useId();
@@ -790,8 +828,15 @@ function RangePickerRoot({
790
828
  const [focusedDate, setFocusedDate] = react.useState(
791
829
  currentValue.start ?? adapter.today()
792
830
  );
831
+ const mergedLabels = react.useMemo(
832
+ () => ({ ...core.DEFAULT_RANGEPICKER_LABELS, ...labelsProp }),
833
+ [labelsProp]
834
+ );
793
835
  const isDisabled = typeof disabled === "boolean" ? disabled : false;
794
- const disabledRules = Array.isArray(disabled) ? disabled : [];
836
+ const disabledRules = react.useMemo(
837
+ () => Array.isArray(disabled) ? disabled : [],
838
+ [disabled]
839
+ );
795
840
  const setRange = react.useCallback(
796
841
  (range) => {
797
842
  if (isDisabled || readOnly) return;
@@ -873,7 +918,8 @@ function RangePickerRoot({
873
918
  locale,
874
919
  isDisabled,
875
920
  isReadOnly: readOnly,
876
- pickerId
921
+ pickerId,
922
+ labels: mergedLabels
877
923
  }),
878
924
  [
879
925
  currentValue,
@@ -894,23 +940,31 @@ function RangePickerRoot({
894
940
  locale,
895
941
  isDisabled,
896
942
  readOnly,
897
- pickerId
943
+ pickerId,
944
+ mergedLabels
898
945
  ]
899
946
  );
900
947
  return /* @__PURE__ */ jsxRuntime.jsx(RangePickerContext.Provider, { value: contextValue, children });
901
948
  }
902
949
  var RangePickerInput = react.forwardRef(
903
- function RangePickerInput2({ part, format: formatProp, onFocus, onKeyDown, ...props }, ref) {
950
+ function RangePickerInput2({ part, format: formatProp, onClick, onKeyDown, ...props }, ref) {
904
951
  const ctx = useRangePickerContext("RangePicker.Input");
905
952
  const displayFormat = formatProp ?? ctx.displayFormat;
906
953
  const value = ctx.value[part];
907
- const displayValue = value ? ctx.adapter.format(value, displayFormat) : "";
908
- const handleFocus = react.useCallback(
954
+ let displayValue = "";
955
+ if (value) {
956
+ try {
957
+ displayValue = ctx.adapter.format(value, displayFormat);
958
+ } catch {
959
+ displayValue = value;
960
+ }
961
+ }
962
+ const handleClick = react.useCallback(
909
963
  (e) => {
910
- ctx.open();
911
- onFocus?.(e);
964
+ if (!ctx.isOpen) ctx.open();
965
+ onClick?.(e);
912
966
  },
913
- [ctx, onFocus]
967
+ [ctx, onClick]
914
968
  );
915
969
  const handleKeyDown = react.useCallback(
916
970
  (e) => {
@@ -940,11 +994,11 @@ var RangePickerInput = react.forwardRef(
940
994
  "aria-haspopup": "dialog",
941
995
  "aria-controls": ctx.isOpen ? calendarId : void 0,
942
996
  "aria-autocomplete": "none",
943
- "aria-label": part === "start" ? "\uC2DC\uC791\uC77C" : "\uC885\uB8CC\uC77C",
997
+ "aria-label": part === "start" ? ctx.labels.startInput : ctx.labels.endInput,
944
998
  autoComplete: "off",
945
999
  value: displayValue,
946
1000
  disabled: ctx.isDisabled || props.disabled,
947
- onFocus: handleFocus,
1001
+ onClick: handleClick,
948
1002
  onKeyDown: handleKeyDown,
949
1003
  "data-part": part,
950
1004
  ...props
@@ -955,66 +1009,19 @@ var RangePickerInput = react.forwardRef(
955
1009
  function RangePickerPopover({ children, ...props }) {
956
1010
  const ctx = useRangePickerContext("RangePicker.Popover");
957
1011
  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
1012
+ const { floatingStyles, setFloatingRef } = usePopover({
1013
+ isOpen: ctx.isOpen,
1014
+ close: ctx.close,
1015
+ referenceRef: ctx.referenceRef
964
1016
  });
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
1017
  if (!ctx.isOpen) return null;
1008
1018
  return /* @__PURE__ */ jsxRuntime.jsx(
1009
1019
  "div",
1010
1020
  {
1011
- ref: (node) => {
1012
- floatingRef.current = node;
1013
- refs.setFloating(node);
1014
- },
1021
+ ref: setFloatingRef,
1015
1022
  id: calendarId,
1016
1023
  role: "dialog",
1017
- "aria-label": "\uB0A0\uC9DC \uBC94\uC704 \uC120\uD0DD",
1024
+ "aria-label": ctx.labels.popoverLabel,
1018
1025
  "aria-modal": "false",
1019
1026
  style: floatingStyles,
1020
1027
  ...props,
@@ -1022,6 +1029,13 @@ function RangePickerPopover({ children, ...props }) {
1022
1029
  }
1023
1030
  );
1024
1031
  }
1032
+ function safeFormatFullDate2(iso, locale) {
1033
+ try {
1034
+ return core.formatFullDate(iso, locale);
1035
+ } catch {
1036
+ return iso;
1037
+ }
1038
+ }
1025
1039
  var srOnly2 = {
1026
1040
  position: "absolute",
1027
1041
  width: "1px",
@@ -1064,7 +1078,7 @@ function RangePickerCalendar({ classNames, ...props }) {
1064
1078
  const focusedButton = gridRef.current.querySelector(
1065
1079
  '[data-focused="true"]'
1066
1080
  );
1067
- focusedButton?.focus();
1081
+ focusedButton?.focus({ preventScroll: true });
1068
1082
  }, [focusedDate, ctx.isOpen]);
1069
1083
  const navigateMonth = react.useCallback(
1070
1084
  (direction) => {
@@ -1081,7 +1095,7 @@ function RangePickerCalendar({ classNames, ...props }) {
1081
1095
  (day) => {
1082
1096
  if (day.isDisabled) return;
1083
1097
  ctx.selectDate(day.isoString);
1084
- setAnnouncement(core.formatFullDate(day.isoString, locale));
1098
+ setAnnouncement(safeFormatFullDate2(day.isoString, locale));
1085
1099
  },
1086
1100
  [ctx, locale]
1087
1101
  );
@@ -1158,7 +1172,7 @@ function RangePickerCalendar({ classNames, ...props }) {
1158
1172
  type: "button",
1159
1173
  className: classNames?.navButton,
1160
1174
  onClick: () => navigateMonth(-1),
1161
- "aria-label": "\uC774\uC804 \uB2EC",
1175
+ "aria-label": ctx.labels.prevMonth,
1162
1176
  children: "<"
1163
1177
  }
1164
1178
  ),
@@ -1169,7 +1183,7 @@ function RangePickerCalendar({ classNames, ...props }) {
1169
1183
  type: "button",
1170
1184
  className: classNames?.navButton,
1171
1185
  onClick: () => navigateMonth(1),
1172
- "aria-label": "\uB2E4\uC74C \uB2EC",
1186
+ "aria-label": ctx.labels.nextMonth,
1173
1187
  children: ">"
1174
1188
  }
1175
1189
  )
@@ -1229,7 +1243,7 @@ function RangePickerCalendar({ classNames, ...props }) {
1229
1243
  className: dayClasses,
1230
1244
  onClick: () => handleDayClick(day),
1231
1245
  onMouseEnter: () => handleDayMouseEnter(day),
1232
- "aria-label": core.formatFullDate(day.isoString, locale),
1246
+ "aria-label": safeFormatFullDate2(day.isoString, locale),
1233
1247
  children: day.dayNumber
1234
1248
  }
1235
1249
  )
@@ -1244,7 +1258,8 @@ function RangePickerCalendar({ classNames, ...props }) {
1244
1258
  ] });
1245
1259
  }
1246
1260
  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 });
1261
+ const ctx = useRangePickerContext("RangePicker.Presets");
1262
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "group", "aria-label": ctx.labels.presetsGroup, className: classNames?.root, ...props, children });
1248
1263
  }
1249
1264
  function resolvePreset(key, today, adapter) {
1250
1265
  switch (key) {
@@ -1283,8 +1298,9 @@ function resolvePreset(key, today, adapter) {
1283
1298
  };
1284
1299
  }
1285
1300
  case "thisYear": {
1301
+ const currentMonth = new Date(today).getUTCMonth();
1286
1302
  const yearStart = adapter.startOfMonth(
1287
- adapter.addMonths(today, -new Date(today).getUTCMonth())
1303
+ adapter.addMonths(today, -currentMonth)
1288
1304
  );
1289
1305
  return { start: yearStart, end: today };
1290
1306
  }
@@ -1366,10 +1382,7 @@ function useTimePickerContext(componentName) {
1366
1382
  return context;
1367
1383
  }
1368
1384
  function getDefaultIso() {
1369
- const now = /* @__PURE__ */ new Date();
1370
- return new Date(
1371
- Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
1372
- ).toISOString();
1385
+ return core.DateFnsAdapter.today();
1373
1386
  }
1374
1387
  function TimePickerRoot({
1375
1388
  value: controlledValue,
@@ -1380,9 +1393,14 @@ function TimePickerRoot({
1380
1393
  withSeconds = false,
1381
1394
  disabled = false,
1382
1395
  readOnly = false,
1396
+ labels: labelsProp,
1383
1397
  children
1384
1398
  }) {
1385
1399
  const pickerId = react.useId();
1400
+ const mergedLabels = react.useMemo(
1401
+ () => ({ ...core.DEFAULT_TIMEPICKER_LABELS, ...labelsProp }),
1402
+ [labelsProp]
1403
+ );
1386
1404
  const isControlled = react.useRef(controlledValue !== void 0).current;
1387
1405
  const [uncontrolledValue, setUncontrolledValue] = react.useState(
1388
1406
  defaultValue ?? null
@@ -1411,9 +1429,10 @@ function TimePickerRoot({
1411
1429
  isDisabled: disabled,
1412
1430
  isReadOnly: readOnly,
1413
1431
  currentTime,
1414
- pickerId
1432
+ pickerId,
1433
+ labels: mergedLabels
1415
1434
  }),
1416
- [currentValue, setTime, format, step, withSeconds, disabled, readOnly, currentTime, pickerId]
1435
+ [currentValue, setTime, format, step, withSeconds, disabled, readOnly, currentTime, pickerId, mergedLabels]
1417
1436
  );
1418
1437
  return /* @__PURE__ */ jsxRuntime.jsx(TimePickerContext.Provider, { value: contextValue, children });
1419
1438
  }
@@ -1459,7 +1478,7 @@ var TimePickerInput = react.forwardRef(
1459
1478
  type: "text",
1460
1479
  inputMode: "numeric",
1461
1480
  autoComplete: "off",
1462
- "aria-label": "\uC2DC\uAC04 \uC785\uB825",
1481
+ "aria-label": ctx.labels.timeInput,
1463
1482
  placeholder: ctx.withSeconds ? "HH:MM:SS" : "HH:MM",
1464
1483
  value: displayValue,
1465
1484
  disabled: ctx.isDisabled || props.disabled,
@@ -1472,46 +1491,42 @@ var TimePickerInput = react.forwardRef(
1472
1491
  );
1473
1492
  }
1474
1493
  );
1475
- function TimePickerHourList({ classNames, ...props }) {
1476
- const ctx = useTimePickerContext("TimePicker.HourList");
1477
- const { format, currentTime, isDisabled, isReadOnly } = ctx;
1494
+ function useListboxNavigation({
1495
+ items,
1496
+ onSelect,
1497
+ disabled = false
1498
+ }) {
1478
1499
  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
- );
1500
+ const rafIdRef = react.useRef(0);
1501
+ react.useEffect(() => {
1502
+ return () => cancelAnimationFrame(rafIdRef.current);
1503
+ }, []);
1490
1504
  const handleKeyDown = react.useCallback(
1491
- (e, hour) => {
1492
- if (isDisabled || isReadOnly) return;
1493
- const currentIndex = hours.indexOf(hour);
1505
+ (e, item) => {
1506
+ if (disabled) return;
1507
+ const currentIndex = items.indexOf(item);
1494
1508
  let newIndex = -1;
1495
1509
  if (e.key === "ArrowDown") {
1496
- newIndex = Math.min(currentIndex + 1, hours.length - 1);
1510
+ newIndex = Math.min(currentIndex + 1, items.length - 1);
1497
1511
  } else if (e.key === "ArrowUp") {
1498
1512
  newIndex = Math.max(currentIndex - 1, 0);
1499
1513
  } else if (e.key === "Home") {
1500
1514
  newIndex = 0;
1501
1515
  } else if (e.key === "End") {
1502
- newIndex = hours.length - 1;
1516
+ newIndex = items.length - 1;
1503
1517
  } else if (e.key === "Enter" || e.key === " ") {
1504
1518
  e.preventDefault();
1505
- handleSelect(hour);
1519
+ onSelect(item);
1506
1520
  return;
1507
1521
  } else {
1508
1522
  return;
1509
1523
  }
1510
1524
  e.preventDefault();
1511
- const targetHour = hours[newIndex];
1512
- if (targetHour !== void 0) {
1513
- handleSelect(targetHour);
1514
- requestAnimationFrame(() => {
1525
+ const target = items[newIndex];
1526
+ if (target !== void 0) {
1527
+ onSelect(target);
1528
+ cancelAnimationFrame(rafIdRef.current);
1529
+ rafIdRef.current = requestAnimationFrame(() => {
1515
1530
  const next = listRef.current?.querySelector(
1516
1531
  '[data-selected="true"]'
1517
1532
  );
@@ -1519,14 +1534,35 @@ function TimePickerHourList({ classNames, ...props }) {
1519
1534
  });
1520
1535
  }
1521
1536
  },
1522
- [hours, handleSelect, isDisabled, isReadOnly]
1537
+ [items, onSelect, disabled]
1523
1538
  );
1539
+ return { listRef, handleKeyDown };
1540
+ }
1541
+ function TimePickerHourList({ classNames, ...props }) {
1542
+ const ctx = useTimePickerContext("TimePicker.HourList");
1543
+ const { format, currentTime, isDisabled, isReadOnly } = ctx;
1544
+ const hours = core.generateHours(format);
1545
+ const selectedHourDisplay = format === "12h" ? core.to12Hour(currentTime.hours).hours12 : currentTime.hours;
1546
+ const currentPeriod = format === "12h" ? core.to12Hour(currentTime.hours).period : null;
1547
+ const handleSelect = react.useCallback(
1548
+ (hourDisplay) => {
1549
+ if (isDisabled || isReadOnly) return;
1550
+ const hours24 = format === "12h" && currentPeriod ? core.to24Hour(hourDisplay, currentPeriod) : hourDisplay;
1551
+ ctx.setTime({ hours: hours24 });
1552
+ },
1553
+ [format, currentPeriod, ctx, isDisabled, isReadOnly]
1554
+ );
1555
+ const { listRef, handleKeyDown } = useListboxNavigation({
1556
+ items: hours,
1557
+ onSelect: handleSelect,
1558
+ disabled: isDisabled || isReadOnly
1559
+ });
1524
1560
  return /* @__PURE__ */ jsxRuntime.jsx(
1525
1561
  "ul",
1526
1562
  {
1527
1563
  ref: listRef,
1528
1564
  role: "listbox",
1529
- "aria-label": "\uC2DC",
1565
+ "aria-label": ctx.labels.hourList,
1530
1566
  "aria-disabled": isDisabled || void 0,
1531
1567
  className: classNames?.root,
1532
1568
  ...props,
@@ -1539,7 +1575,7 @@ function TimePickerHourList({ classNames, ...props }) {
1539
1575
  role: "option",
1540
1576
  "aria-selected": isSelected,
1541
1577
  "aria-disabled": isDisabled || void 0,
1542
- "aria-label": `${hour}\uC2DC`,
1578
+ "aria-label": ctx.labels.hourOption(hour),
1543
1579
  "data-selected": isSelected || void 0,
1544
1580
  tabIndex: isSelected ? 0 : -1,
1545
1581
  className: optionClass,
@@ -1556,7 +1592,6 @@ function TimePickerHourList({ classNames, ...props }) {
1556
1592
  function TimePickerMinuteList({ classNames, ...props }) {
1557
1593
  const ctx = useTimePickerContext("TimePicker.MinuteList");
1558
1594
  const { step, currentTime, isDisabled, isReadOnly } = ctx;
1559
- const listRef = react.useRef(null);
1560
1595
  const minutes = core.generateMinutes(step);
1561
1596
  const handleSelect = react.useCallback(
1562
1597
  (minute) => {
@@ -1565,46 +1600,17 @@ function TimePickerMinuteList({ classNames, ...props }) {
1565
1600
  },
1566
1601
  [ctx, isDisabled, isReadOnly]
1567
1602
  );
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
- );
1603
+ const { listRef, handleKeyDown } = useListboxNavigation({
1604
+ items: minutes,
1605
+ onSelect: handleSelect,
1606
+ disabled: isDisabled || isReadOnly
1607
+ });
1602
1608
  return /* @__PURE__ */ jsxRuntime.jsx(
1603
1609
  "ul",
1604
1610
  {
1605
1611
  ref: listRef,
1606
1612
  role: "listbox",
1607
- "aria-label": "\uBD84",
1613
+ "aria-label": ctx.labels.minuteList,
1608
1614
  "aria-disabled": isDisabled || void 0,
1609
1615
  className: classNames?.root,
1610
1616
  ...props,
@@ -1617,7 +1623,7 @@ function TimePickerMinuteList({ classNames, ...props }) {
1617
1623
  role: "option",
1618
1624
  "aria-selected": isSelected,
1619
1625
  "aria-disabled": isDisabled || void 0,
1620
- "aria-label": `${minute}\uBD84`,
1626
+ "aria-label": ctx.labels.minuteOption(minute),
1621
1627
  "data-selected": isSelected || void 0,
1622
1628
  tabIndex: isSelected ? 0 : -1,
1623
1629
  className: optionClass,
@@ -1660,7 +1666,7 @@ function TimePickerAmPmToggle({ classNames, ...props }) {
1660
1666
  }
1661
1667
  );
1662
1668
  };
1663
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "radiogroup", "aria-label": "\uC624\uC804/\uC624\uD6C4", className: classNames?.root, ...props, children: [
1669
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "radiogroup", "aria-label": ctx.labels.amPmToggle, className: classNames?.root, ...props, children: [
1664
1670
  renderButton("AM"),
1665
1671
  renderButton("PM")
1666
1672
  ] });
@@ -1674,10 +1680,7 @@ var TimePicker = Object.assign(TimePickerRoot, {
1674
1680
  AmPmToggle: TimePickerAmPmToggle
1675
1681
  });
1676
1682
  function getDefaultIso2() {
1677
- const now = /* @__PURE__ */ new Date();
1678
- return new Date(
1679
- Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
1680
- ).toISOString();
1683
+ return core.DateFnsAdapter.today();
1681
1684
  }
1682
1685
  function DateTimePickerRoot({
1683
1686
  value: controlledValue,
@@ -1691,9 +1694,18 @@ function DateTimePickerRoot({
1691
1694
  displayFormat = "yyyy-MM-dd HH:mm",
1692
1695
  locale = "en-US",
1693
1696
  adapter = core.DateFnsAdapter,
1697
+ labels: labelsProp,
1694
1698
  children
1695
1699
  }) {
1696
1700
  const pickerId = react.useId();
1701
+ const mergedDateLabels = react.useMemo(
1702
+ () => ({ ...core.DEFAULT_DATEPICKER_LABELS, ...labelsProp }),
1703
+ [labelsProp]
1704
+ );
1705
+ const mergedTimeLabels = react.useMemo(
1706
+ () => ({ ...core.DEFAULT_TIMEPICKER_LABELS, ...labelsProp }),
1707
+ [labelsProp]
1708
+ );
1697
1709
  const isControlled = react.useRef(controlledValue !== void 0).current;
1698
1710
  const referenceRef = react.useRef(null);
1699
1711
  const [uncontrolledValue, setUncontrolledValue] = react.useState(
@@ -1708,7 +1720,10 @@ function DateTimePickerRoot({
1708
1720
  currentValue ?? adapter.today()
1709
1721
  );
1710
1722
  const isDisabled = typeof disabled === "boolean" ? disabled : false;
1711
- const disabledRules = Array.isArray(disabled) ? disabled : [];
1723
+ const disabledRules = react.useMemo(
1724
+ () => Array.isArray(disabled) ? disabled : [],
1725
+ [disabled]
1726
+ );
1712
1727
  const baseIso = currentValue ?? getDefaultIso2();
1713
1728
  const currentTime = react.useMemo(() => core.getTime(baseIso), [baseIso]);
1714
1729
  const updateValue = react.useCallback(
@@ -1775,7 +1790,8 @@ function DateTimePickerRoot({
1775
1790
  locale,
1776
1791
  isDisabled,
1777
1792
  isReadOnly: readOnly,
1778
- pickerId
1793
+ pickerId,
1794
+ labels: mergedDateLabels
1779
1795
  }),
1780
1796
  [
1781
1797
  currentValue,
@@ -1793,7 +1809,8 @@ function DateTimePickerRoot({
1793
1809
  locale,
1794
1810
  isDisabled,
1795
1811
  readOnly,
1796
- pickerId
1812
+ pickerId,
1813
+ mergedDateLabels
1797
1814
  ]
1798
1815
  );
1799
1816
  const timeContext = react.useMemo(
@@ -1806,22 +1823,30 @@ function DateTimePickerRoot({
1806
1823
  isDisabled,
1807
1824
  isReadOnly: readOnly,
1808
1825
  currentTime,
1809
- pickerId
1826
+ pickerId,
1827
+ labels: mergedTimeLabels
1810
1828
  }),
1811
- [currentValue, setTime, format, step, isDisabled, readOnly, currentTime, pickerId]
1829
+ [currentValue, setTime, format, step, isDisabled, readOnly, currentTime, pickerId, mergedTimeLabels]
1812
1830
  );
1813
1831
  return /* @__PURE__ */ jsxRuntime.jsx(DatePickerContext.Provider, { value: dateContext, children: /* @__PURE__ */ jsxRuntime.jsx(TimePickerContext.Provider, { value: timeContext, children }) });
1814
1832
  }
1815
1833
  var DateTimePickerInput = react.forwardRef(
1816
- function DateTimePickerInput2({ onFocus, onKeyDown, ...props }, ref) {
1834
+ function DateTimePickerInput2({ onClick, onKeyDown, ...props }, ref) {
1817
1835
  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(
1836
+ let displayValue = "";
1837
+ if (ctx.value) {
1838
+ try {
1839
+ displayValue = `${ctx.adapter.format(ctx.value, "yyyy-MM-dd")} ${core.formatTimeString(core.getTime(ctx.value))}`;
1840
+ } catch {
1841
+ displayValue = ctx.value;
1842
+ }
1843
+ }
1844
+ const handleClick = react.useCallback(
1820
1845
  (e) => {
1821
- ctx.open();
1822
- onFocus?.(e);
1846
+ if (!ctx.isOpen) ctx.open();
1847
+ onClick?.(e);
1823
1848
  },
1824
- [ctx, onFocus]
1849
+ [ctx, onClick]
1825
1850
  );
1826
1851
  const handleKeyDown = react.useCallback(
1827
1852
  (e) => {
@@ -1847,7 +1872,7 @@ var DateTimePickerInput = react.forwardRef(
1847
1872
  type: "text",
1848
1873
  role: "combobox",
1849
1874
  readOnly: true,
1850
- "aria-label": "\uB0A0\uC9DC \uBC0F \uC2DC\uAC04",
1875
+ "aria-label": ctx.labels.dateTimeInput ?? "Date and time",
1851
1876
  "aria-expanded": ctx.isOpen,
1852
1877
  "aria-haspopup": "dialog",
1853
1878
  "aria-controls": ctx.isOpen ? calendarId : void 0,
@@ -1855,7 +1880,7 @@ var DateTimePickerInput = react.forwardRef(
1855
1880
  autoComplete: "off",
1856
1881
  value: displayValue,
1857
1882
  disabled: ctx.isDisabled || props.disabled,
1858
- onFocus: handleFocus,
1883
+ onClick: handleClick,
1859
1884
  onKeyDown: handleKeyDown,
1860
1885
  ...props
1861
1886
  }
@@ -2062,10 +2087,7 @@ function useRangePicker(options = {}) {
2062
2087
  };
2063
2088
  }
2064
2089
  function getDefaultIso3() {
2065
- const now = /* @__PURE__ */ new Date();
2066
- return new Date(
2067
- Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
2068
- ).toISOString();
2090
+ return core.DateFnsAdapter.today();
2069
2091
  }
2070
2092
  function useTimePicker(options = {}) {
2071
2093
  const {