@kalyx/react 0.2.2 → 0.4.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
@@ -30,7 +30,9 @@ function DatePickerRoot({
30
30
  weekStartsOn = 0,
31
31
  displayFormat = "yyyy-MM-dd",
32
32
  locale = "en-US",
33
+ displayTimezone,
33
34
  adapter = core.DateFnsAdapter,
35
+ labels: labelsProp,
34
36
  children
35
37
  }) {
36
38
  const pickerId = react.useId();
@@ -42,31 +44,39 @@ function DatePickerRoot({
42
44
  const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
43
45
  const [isOpen, setIsOpen] = react.useState(false);
44
46
  const [viewMonth, setViewMonth] = react.useState(
45
- currentValue ?? adapter.today()
47
+ currentValue ?? adapter.today(displayTimezone)
46
48
  );
47
49
  const [focusedDate, setFocusedDate] = react.useState(
48
- currentValue ?? adapter.today()
50
+ currentValue ?? adapter.today(displayTimezone)
51
+ );
52
+ const mergedLabels = react.useMemo(
53
+ () => ({ ...core.DEFAULT_DATEPICKER_LABELS, ...labelsProp }),
54
+ [labelsProp]
49
55
  );
50
56
  const isDisabled = typeof disabled === "boolean" ? disabled : false;
51
- const disabledRules = Array.isArray(disabled) ? disabled : [];
57
+ const disabledRules = react.useMemo(
58
+ () => Array.isArray(disabled) ? disabled : [],
59
+ [disabled]
60
+ );
52
61
  const selectDate = react.useCallback(
53
62
  (iso) => {
54
63
  if (isDisabled || readOnly) return;
64
+ const normalized = iso && displayTimezone ? core.civilMidnightFromUtcDay(iso, displayTimezone) : iso;
55
65
  if (!isControlled) {
56
- setUncontrolledValue(iso);
66
+ setUncontrolledValue(normalized);
57
67
  }
58
- onChange?.(iso);
68
+ onChange?.(normalized);
59
69
  setIsOpen(false);
60
70
  },
61
- [isControlled, isDisabled, readOnly, onChange]
71
+ [isControlled, isDisabled, readOnly, onChange, displayTimezone]
62
72
  );
63
73
  const open = react.useCallback(() => {
64
74
  if (isDisabled || readOnly) return;
65
75
  setIsOpen(true);
66
- const target = currentValue ?? adapter.today();
76
+ const target = currentValue ?? adapter.today(displayTimezone);
67
77
  setViewMonth(target);
68
78
  setFocusedDate(target);
69
- }, [isDisabled, readOnly, currentValue, adapter]);
79
+ }, [isDisabled, readOnly, currentValue, adapter, displayTimezone]);
70
80
  const close = react.useCallback(() => {
71
81
  setIsOpen(false);
72
82
  }, []);
@@ -95,9 +105,11 @@ function DatePickerRoot({
95
105
  weekStartsOn,
96
106
  displayFormat,
97
107
  locale,
108
+ displayTimezone,
98
109
  isDisabled,
99
110
  isReadOnly: readOnly,
100
- pickerId
111
+ pickerId,
112
+ labels: mergedLabels
101
113
  }),
102
114
  [
103
115
  currentValue,
@@ -113,30 +125,40 @@ function DatePickerRoot({
113
125
  weekStartsOn,
114
126
  displayFormat,
115
127
  locale,
128
+ displayTimezone,
116
129
  isDisabled,
117
130
  readOnly,
118
- pickerId
131
+ pickerId,
132
+ mergedLabels
119
133
  ]
120
134
  );
121
135
  return /* @__PURE__ */ jsxRuntime.jsx(DatePickerContext.Provider, { value: contextValue, children });
122
136
  }
123
137
  var DatePickerInput = react.forwardRef(
124
- function DatePickerInput2({ format: formatProp, onFocus, onBlur, onKeyDown, ...props }, ref) {
138
+ function DatePickerInput2({ format: formatProp, onClick, onBlur, onKeyDown, ...props }, ref) {
125
139
  const ctx = useDatePickerContext("DatePicker.Input");
126
140
  const displayFormat = formatProp ?? ctx.displayFormat;
127
141
  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(
142
+ let formattedValue = "";
143
+ if (ctx.value) {
144
+ try {
145
+ formattedValue = ctx.adapter.format(ctx.value, displayFormat, ctx.displayTimezone);
146
+ } catch {
147
+ formattedValue = ctx.value;
148
+ }
149
+ }
150
+ const displayValue = inputText !== null ? inputText : formattedValue;
151
+ const handleClick = react.useCallback(
130
152
  (e) => {
131
- ctx.open();
132
- onFocus?.(e);
153
+ if (!ctx.isOpen) ctx.open();
154
+ onClick?.(e);
133
155
  },
134
- [ctx, onFocus]
156
+ [ctx, onClick]
135
157
  );
136
158
  const handleBlur = react.useCallback(
137
159
  (e) => {
138
160
  if (inputText !== null) {
139
- const parsed = core.parseInputValue(inputText, displayFormat, ctx.adapter);
161
+ const parsed = core.parseInputValue(inputText, ctx.adapter);
140
162
  if (parsed) {
141
163
  ctx.selectDate(parsed);
142
164
  }
@@ -155,7 +177,7 @@ var DatePickerInput = react.forwardRef(
155
177
  setInputText(null);
156
178
  return;
157
179
  }
158
- const parsed = core.parseInputValue(text, displayFormat, ctx.adapter);
180
+ const parsed = core.parseInputValue(text, ctx.adapter);
159
181
  if (parsed) {
160
182
  ctx.selectDate(parsed);
161
183
  setInputText(null);
@@ -169,7 +191,7 @@ var DatePickerInput = react.forwardRef(
169
191
  ctx.close();
170
192
  } else if (e.key === "Enter") {
171
193
  if (inputText !== null) {
172
- const parsed = core.parseInputValue(inputText, displayFormat, ctx.adapter);
194
+ const parsed = core.parseInputValue(inputText, ctx.adapter);
173
195
  if (parsed) {
174
196
  ctx.selectDate(parsed);
175
197
  setInputText(null);
@@ -203,7 +225,7 @@ var DatePickerInput = react.forwardRef(
203
225
  disabled: ctx.isDisabled || props.disabled,
204
226
  readOnly: ctx.isReadOnly,
205
227
  onChange: handleChange,
206
- onFocus: handleFocus,
228
+ onClick: handleClick,
207
229
  onBlur: handleBlur,
208
230
  onKeyDown: handleKeyDown,
209
231
  ...props
@@ -232,7 +254,7 @@ var DatePickerTrigger = react.forwardRef(
232
254
  },
233
255
  type: "button",
234
256
  tabIndex: 0,
235
- "aria-label": ctx.isOpen ? "\uCE98\uB9B0\uB354 \uB2EB\uAE30" : "\uCE98\uB9B0\uB354 \uC5F4\uAE30",
257
+ "aria-label": ctx.isOpen ? ctx.labels.triggerClose : ctx.labels.triggerOpen,
236
258
  "aria-expanded": ctx.isOpen,
237
259
  "aria-controls": ctx.isOpen ? calendarId : void 0,
238
260
  disabled: ctx.isDisabled || props.disabled,
@@ -264,38 +286,39 @@ var DatePickerTrigger = react.forwardRef(
264
286
  );
265
287
  }
266
288
  );
267
- function DatePickerPopover({ children, ...props }) {
268
- const ctx = useDatePickerContext("DatePicker.Popover");
269
- const calendarId = `${ctx.pickerId}-calendar`;
289
+ function usePopover({ isOpen, close, referenceRef, placement = "bottom-start" }) {
270
290
  const floatingRef = react.useRef(null);
291
+ const previousFocusRef = react.useRef(null);
271
292
  const { refs, floatingStyles } = react$1.useFloating({
272
- open: ctx.isOpen,
273
- placement: "bottom-start",
293
+ open: isOpen,
294
+ placement,
274
295
  middleware: [react$1.offset(4), react$1.flip(), react$1.shift({ padding: 8 })],
275
296
  whileElementsMounted: react$1.autoUpdate
276
297
  });
277
298
  react.useEffect(() => {
278
- if (ctx.referenceRef.current) {
279
- refs.setReference(ctx.referenceRef.current);
299
+ if (referenceRef.current) {
300
+ refs.setReference(referenceRef.current);
280
301
  }
281
- }, [ctx.referenceRef, refs, ctx.isOpen]);
282
- const previousFocusRef = react.useRef(null);
302
+ }, [referenceRef, refs, isOpen]);
283
303
  react.useEffect(() => {
284
- if (ctx.isOpen) {
304
+ if (isOpen) {
285
305
  previousFocusRef.current = document.activeElement;
286
306
  } else if (previousFocusRef.current) {
287
- previousFocusRef.current.focus();
307
+ const el = previousFocusRef.current;
288
308
  previousFocusRef.current = null;
309
+ if (el !== referenceRef.current && typeof el.focus === "function") {
310
+ el.focus({ preventScroll: true });
311
+ }
289
312
  }
290
- }, [ctx.isOpen]);
313
+ }, [isOpen, referenceRef]);
291
314
  react.useEffect(() => {
292
- if (!ctx.isOpen) return;
315
+ if (!isOpen) return;
293
316
  function handleClickOutside(e) {
294
317
  const floating = floatingRef.current;
295
- const reference = ctx.referenceRef.current;
318
+ const reference = referenceRef.current;
296
319
  const target = e.target;
297
320
  if (floating && !floating.contains(target) && (!reference || !reference.contains(target))) {
298
- ctx.close();
321
+ close();
299
322
  }
300
323
  }
301
324
  const timer = setTimeout(() => {
@@ -305,28 +328,39 @@ function DatePickerPopover({ children, ...props }) {
305
328
  clearTimeout(timer);
306
329
  document.removeEventListener("mousedown", handleClickOutside);
307
330
  };
308
- }, [ctx.isOpen, ctx]);
331
+ }, [isOpen, close, referenceRef]);
309
332
  react.useEffect(() => {
310
- if (!ctx.isOpen) return;
333
+ if (!isOpen) return;
311
334
  function handleKeyDown(e) {
312
335
  if (e.key === "Escape") {
313
- ctx.close();
336
+ close();
314
337
  }
315
338
  }
316
339
  document.addEventListener("keydown", handleKeyDown);
317
340
  return () => document.removeEventListener("keydown", handleKeyDown);
318
- }, [ctx.isOpen, ctx]);
341
+ }, [isOpen, close]);
342
+ const setFloatingRef = (node) => {
343
+ floatingRef.current = node;
344
+ refs.setFloating(node);
345
+ };
346
+ return { floatingStyles, setFloatingRef };
347
+ }
348
+ function DatePickerPopover({ children, ...props }) {
349
+ const ctx = useDatePickerContext("DatePicker.Popover");
350
+ const calendarId = `${ctx.pickerId}-calendar`;
351
+ const { floatingStyles, setFloatingRef } = usePopover({
352
+ isOpen: ctx.isOpen,
353
+ close: ctx.close,
354
+ referenceRef: ctx.referenceRef
355
+ });
319
356
  if (!ctx.isOpen) return null;
320
357
  return /* @__PURE__ */ jsxRuntime.jsx(
321
358
  "div",
322
359
  {
323
- ref: (node) => {
324
- floatingRef.current = node;
325
- refs.setFloating(node);
326
- },
360
+ ref: setFloatingRef,
327
361
  id: calendarId,
328
362
  role: "dialog",
329
- "aria-label": "\uB0A0\uC9DC \uC120\uD0DD",
363
+ "aria-label": ctx.labels.popoverLabel,
330
364
  "aria-modal": "false",
331
365
  style: floatingStyles,
332
366
  ...props,
@@ -334,6 +368,13 @@ function DatePickerPopover({ children, ...props }) {
334
368
  }
335
369
  );
336
370
  }
371
+ function safeFormatFullDate(iso, locale) {
372
+ try {
373
+ return core.formatFullDate(iso, locale);
374
+ } catch {
375
+ return iso;
376
+ }
377
+ }
337
378
  var srOnly = {
338
379
  position: "absolute",
339
380
  width: "1px",
@@ -349,13 +390,14 @@ function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
349
390
  const ctx = useDatePickerContext("DatePicker.Calendar");
350
391
  const gridRef = react.useRef(null);
351
392
  const [announcement, setAnnouncement] = react.useState("");
352
- const { adapter, viewMonth, focusedDate, weekStartsOn, disabled, locale } = ctx;
393
+ const { adapter, viewMonth, focusedDate, weekStartsOn, disabled, locale, displayTimezone } = ctx;
353
394
  const weekdays = core.getWeekdayNames(locale, weekStartsOn);
354
395
  const weeks = core.getCalendarDays(viewMonth, adapter, {
355
396
  weekStartsOn,
356
397
  selected: ctx.value,
357
398
  focusedDate,
358
- disabled
399
+ disabled,
400
+ timezone: displayTimezone
359
401
  });
360
402
  const year = adapter.getYear(viewMonth);
361
403
  const month = adapter.getMonth(viewMonth);
@@ -365,7 +407,7 @@ function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
365
407
  const focusedButton = gridRef.current.querySelector(
366
408
  '[data-focused="true"]'
367
409
  );
368
- focusedButton?.focus();
410
+ focusedButton?.focus({ preventScroll: true });
369
411
  }, [focusedDate, ctx.isOpen]);
370
412
  const navigateMonth = react.useCallback(
371
413
  (direction) => {
@@ -382,7 +424,7 @@ function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
382
424
  (day) => {
383
425
  if (day.isDisabled) return;
384
426
  ctx.selectDate(day.isoString);
385
- setAnnouncement(core.formatFullDate(day.isoString, locale));
427
+ setAnnouncement(safeFormatFullDate(day.isoString, locale));
386
428
  },
387
429
  [ctx, locale]
388
430
  );
@@ -454,7 +496,7 @@ function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
454
496
  type: "button",
455
497
  className: classNames?.navButton,
456
498
  onClick: () => navigateMonth(-1),
457
- "aria-label": "\uC774\uC804 \uB2EC",
499
+ "aria-label": ctx.labels.prevMonth,
458
500
  children: "<"
459
501
  }
460
502
  ),
@@ -474,7 +516,7 @@ function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
474
516
  type: "button",
475
517
  className: classNames?.navButton,
476
518
  onClick: () => navigateMonth(1),
477
- "aria-label": "\uB2E4\uC74C \uB2EC",
519
+ "aria-label": ctx.labels.nextMonth,
478
520
  children: ">"
479
521
  }
480
522
  )
@@ -527,7 +569,7 @@ function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
527
569
  "data-outside-month": !day.isCurrentMonth || void 0,
528
570
  className: dayClasses,
529
571
  onClick: () => handleDayClick(day),
530
- "aria-label": core.formatFullDate(day.isoString, locale),
572
+ "aria-label": safeFormatFullDate(day.isoString, locale),
531
573
  children: day.dayNumber
532
574
  }
533
575
  )
@@ -583,7 +625,7 @@ function DatePickerMonthGrid({
583
625
  type: "button",
584
626
  className: classNames?.navButton,
585
627
  onClick: () => navigateYear(-1),
586
- "aria-label": "\uC774\uC804 \uB144",
628
+ "aria-label": ctx.labels.prevYear,
587
629
  children: "<"
588
630
  }
589
631
  ),
@@ -602,7 +644,7 @@ function DatePickerMonthGrid({
602
644
  type: "button",
603
645
  className: classNames?.navButton,
604
646
  onClick: () => navigateYear(1),
605
- "aria-label": "\uB2E4\uC74C \uB144",
647
+ "aria-label": ctx.labels.nextYear,
606
648
  children: ">"
607
649
  }
608
650
  )
@@ -687,7 +729,7 @@ function DatePickerYearGrid({
687
729
  type: "button",
688
730
  className: classNames?.navButton,
689
731
  onClick: () => navigateDecade(-1),
690
- "aria-label": "\uC774\uC804 12\uB144",
732
+ "aria-label": ctx.labels.prevDecade,
691
733
  children: "<"
692
734
  }
693
735
  ),
@@ -698,7 +740,7 @@ function DatePickerYearGrid({
698
740
  type: "button",
699
741
  className: classNames?.navButton,
700
742
  onClick: () => navigateDecade(1),
701
- "aria-label": "\uB2E4\uC74C 12\uB144",
743
+ "aria-label": ctx.labels.nextDecade,
702
744
  children: ">"
703
745
  }
704
746
  )
@@ -771,7 +813,9 @@ function RangePickerRoot({
771
813
  weekStartsOn = 0,
772
814
  displayFormat = "yyyy-MM-dd",
773
815
  locale = "en-US",
816
+ displayTimezone,
774
817
  adapter = core.DateFnsAdapter,
818
+ labels: labelsProp,
775
819
  children
776
820
  }) {
777
821
  const pickerId = react.useId();
@@ -785,13 +829,20 @@ function RangePickerRoot({
785
829
  const [selectingTarget, setSelectingTarget] = react.useState("start");
786
830
  const [hoverDate, setHoverDate] = react.useState(null);
787
831
  const [viewMonth, setViewMonth] = react.useState(
788
- currentValue.start ?? adapter.today()
832
+ currentValue.start ?? adapter.today(displayTimezone)
789
833
  );
790
834
  const [focusedDate, setFocusedDate] = react.useState(
791
- currentValue.start ?? adapter.today()
835
+ currentValue.start ?? adapter.today(displayTimezone)
836
+ );
837
+ const mergedLabels = react.useMemo(
838
+ () => ({ ...core.DEFAULT_RANGEPICKER_LABELS, ...labelsProp }),
839
+ [labelsProp]
792
840
  );
793
841
  const isDisabled = typeof disabled === "boolean" ? disabled : false;
794
- const disabledRules = Array.isArray(disabled) ? disabled : [];
842
+ const disabledRules = react.useMemo(
843
+ () => Array.isArray(disabled) ? disabled : [],
844
+ [disabled]
845
+ );
795
846
  const setRange = react.useCallback(
796
847
  (range) => {
797
848
  if (isDisabled || readOnly) return;
@@ -805,23 +856,24 @@ function RangePickerRoot({
805
856
  const selectDate = react.useCallback(
806
857
  (iso) => {
807
858
  if (isDisabled || readOnly) return;
859
+ const normalized = displayTimezone ? core.civilMidnightFromUtcDay(iso, displayTimezone) : iso;
808
860
  if (selectingTarget === "start") {
809
- const newRange = { start: iso, end: null };
861
+ const newRange = { start: normalized, end: null };
810
862
  setRange(newRange);
811
863
  setSelectingTarget("end");
812
864
  setHoverDate(null);
813
865
  } else {
814
866
  const start = currentValue.start;
815
867
  if (!start) {
816
- setRange({ start: iso, end: null });
868
+ setRange({ start: normalized, end: null });
817
869
  setSelectingTarget("end");
818
870
  return;
819
871
  }
820
872
  let newRange;
821
- if (adapter.isBefore(iso, start)) {
822
- newRange = { start: iso, end: start };
873
+ if (adapter.isBefore(normalized, start)) {
874
+ newRange = { start: normalized, end: start };
823
875
  } else {
824
- newRange = { start, end: iso };
876
+ newRange = { start, end: normalized };
825
877
  }
826
878
  setRange(newRange);
827
879
  setSelectingTarget("start");
@@ -829,18 +881,18 @@ function RangePickerRoot({
829
881
  setIsOpen(false);
830
882
  }
831
883
  },
832
- [isDisabled, readOnly, selectingTarget, currentValue.start, adapter, setRange]
884
+ [isDisabled, readOnly, selectingTarget, currentValue.start, adapter, setRange, displayTimezone]
833
885
  );
834
886
  const open = react.useCallback(() => {
835
887
  if (isDisabled || readOnly) return;
836
888
  setIsOpen(true);
837
- const target = currentValue.start ?? adapter.today();
889
+ const target = currentValue.start ?? adapter.today(displayTimezone);
838
890
  setViewMonth(target);
839
891
  setFocusedDate(target);
840
892
  if (currentValue.start && currentValue.end) {
841
893
  setSelectingTarget("start");
842
894
  }
843
- }, [isDisabled, readOnly, currentValue, adapter]);
895
+ }, [isDisabled, readOnly, currentValue, adapter, displayTimezone]);
844
896
  const close = react.useCallback(() => {
845
897
  setIsOpen(false);
846
898
  setHoverDate(null);
@@ -871,9 +923,11 @@ function RangePickerRoot({
871
923
  weekStartsOn,
872
924
  displayFormat,
873
925
  locale,
926
+ displayTimezone,
874
927
  isDisabled,
875
928
  isReadOnly: readOnly,
876
- pickerId
929
+ pickerId,
930
+ labels: mergedLabels
877
931
  }),
878
932
  [
879
933
  currentValue,
@@ -892,25 +946,34 @@ function RangePickerRoot({
892
946
  weekStartsOn,
893
947
  displayFormat,
894
948
  locale,
949
+ displayTimezone,
895
950
  isDisabled,
896
951
  readOnly,
897
- pickerId
952
+ pickerId,
953
+ mergedLabels
898
954
  ]
899
955
  );
900
956
  return /* @__PURE__ */ jsxRuntime.jsx(RangePickerContext.Provider, { value: contextValue, children });
901
957
  }
902
958
  var RangePickerInput = react.forwardRef(
903
- function RangePickerInput2({ part, format: formatProp, onFocus, onKeyDown, ...props }, ref) {
959
+ function RangePickerInput2({ part, format: formatProp, onClick, onKeyDown, ...props }, ref) {
904
960
  const ctx = useRangePickerContext("RangePicker.Input");
905
961
  const displayFormat = formatProp ?? ctx.displayFormat;
906
962
  const value = ctx.value[part];
907
- const displayValue = value ? ctx.adapter.format(value, displayFormat) : "";
908
- const handleFocus = react.useCallback(
963
+ let displayValue = "";
964
+ if (value) {
965
+ try {
966
+ displayValue = ctx.adapter.format(value, displayFormat, ctx.displayTimezone);
967
+ } catch {
968
+ displayValue = value;
969
+ }
970
+ }
971
+ const handleClick = react.useCallback(
909
972
  (e) => {
910
- ctx.open();
911
- onFocus?.(e);
973
+ if (!ctx.isOpen) ctx.open();
974
+ onClick?.(e);
912
975
  },
913
- [ctx, onFocus]
976
+ [ctx, onClick]
914
977
  );
915
978
  const handleKeyDown = react.useCallback(
916
979
  (e) => {
@@ -940,11 +1003,11 @@ var RangePickerInput = react.forwardRef(
940
1003
  "aria-haspopup": "dialog",
941
1004
  "aria-controls": ctx.isOpen ? calendarId : void 0,
942
1005
  "aria-autocomplete": "none",
943
- "aria-label": part === "start" ? "\uC2DC\uC791\uC77C" : "\uC885\uB8CC\uC77C",
1006
+ "aria-label": part === "start" ? ctx.labels.startInput : ctx.labels.endInput,
944
1007
  autoComplete: "off",
945
1008
  value: displayValue,
946
1009
  disabled: ctx.isDisabled || props.disabled,
947
- onFocus: handleFocus,
1010
+ onClick: handleClick,
948
1011
  onKeyDown: handleKeyDown,
949
1012
  "data-part": part,
950
1013
  ...props
@@ -955,66 +1018,19 @@ var RangePickerInput = react.forwardRef(
955
1018
  function RangePickerPopover({ children, ...props }) {
956
1019
  const ctx = useRangePickerContext("RangePicker.Popover");
957
1020
  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
1021
+ const { floatingStyles, setFloatingRef } = usePopover({
1022
+ isOpen: ctx.isOpen,
1023
+ close: ctx.close,
1024
+ referenceRef: ctx.referenceRef
964
1025
  });
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
1026
  if (!ctx.isOpen) return null;
1008
1027
  return /* @__PURE__ */ jsxRuntime.jsx(
1009
1028
  "div",
1010
1029
  {
1011
- ref: (node) => {
1012
- floatingRef.current = node;
1013
- refs.setFloating(node);
1014
- },
1030
+ ref: setFloatingRef,
1015
1031
  id: calendarId,
1016
1032
  role: "dialog",
1017
- "aria-label": "\uB0A0\uC9DC \uBC94\uC704 \uC120\uD0DD",
1033
+ "aria-label": ctx.labels.popoverLabel,
1018
1034
  "aria-modal": "false",
1019
1035
  style: floatingStyles,
1020
1036
  ...props,
@@ -1022,6 +1038,13 @@ function RangePickerPopover({ children, ...props }) {
1022
1038
  }
1023
1039
  );
1024
1040
  }
1041
+ function safeFormatFullDate2(iso, locale) {
1042
+ try {
1043
+ return core.formatFullDate(iso, locale);
1044
+ } catch {
1045
+ return iso;
1046
+ }
1047
+ }
1025
1048
  var srOnly2 = {
1026
1049
  position: "absolute",
1027
1050
  width: "1px",
@@ -1045,7 +1068,8 @@ function RangePickerCalendar({ classNames, ...props }) {
1045
1068
  disabled,
1046
1069
  value,
1047
1070
  hoverDate,
1048
- selectingTarget
1071
+ selectingTarget,
1072
+ displayTimezone
1049
1073
  } = ctx;
1050
1074
  const { locale } = ctx;
1051
1075
  const weekdays = core.getWeekdayNames(locale, weekStartsOn);
@@ -1054,7 +1078,8 @@ function RangePickerCalendar({ classNames, ...props }) {
1054
1078
  focusedDate,
1055
1079
  disabled,
1056
1080
  range: value,
1057
- rangeHover: hoverDate
1081
+ rangeHover: hoverDate,
1082
+ timezone: displayTimezone
1058
1083
  });
1059
1084
  const year = adapter.getYear(viewMonth);
1060
1085
  const month = adapter.getMonth(viewMonth);
@@ -1064,7 +1089,7 @@ function RangePickerCalendar({ classNames, ...props }) {
1064
1089
  const focusedButton = gridRef.current.querySelector(
1065
1090
  '[data-focused="true"]'
1066
1091
  );
1067
- focusedButton?.focus();
1092
+ focusedButton?.focus({ preventScroll: true });
1068
1093
  }, [focusedDate, ctx.isOpen]);
1069
1094
  const navigateMonth = react.useCallback(
1070
1095
  (direction) => {
@@ -1081,7 +1106,7 @@ function RangePickerCalendar({ classNames, ...props }) {
1081
1106
  (day) => {
1082
1107
  if (day.isDisabled) return;
1083
1108
  ctx.selectDate(day.isoString);
1084
- setAnnouncement(core.formatFullDate(day.isoString, locale));
1109
+ setAnnouncement(safeFormatFullDate2(day.isoString, locale));
1085
1110
  },
1086
1111
  [ctx, locale]
1087
1112
  );
@@ -1158,7 +1183,7 @@ function RangePickerCalendar({ classNames, ...props }) {
1158
1183
  type: "button",
1159
1184
  className: classNames?.navButton,
1160
1185
  onClick: () => navigateMonth(-1),
1161
- "aria-label": "\uC774\uC804 \uB2EC",
1186
+ "aria-label": ctx.labels.prevMonth,
1162
1187
  children: "<"
1163
1188
  }
1164
1189
  ),
@@ -1169,7 +1194,7 @@ function RangePickerCalendar({ classNames, ...props }) {
1169
1194
  type: "button",
1170
1195
  className: classNames?.navButton,
1171
1196
  onClick: () => navigateMonth(1),
1172
- "aria-label": "\uB2E4\uC74C \uB2EC",
1197
+ "aria-label": ctx.labels.nextMonth,
1173
1198
  children: ">"
1174
1199
  }
1175
1200
  )
@@ -1229,7 +1254,7 @@ function RangePickerCalendar({ classNames, ...props }) {
1229
1254
  className: dayClasses,
1230
1255
  onClick: () => handleDayClick(day),
1231
1256
  onMouseEnter: () => handleDayMouseEnter(day),
1232
- "aria-label": core.formatFullDate(day.isoString, locale),
1257
+ "aria-label": safeFormatFullDate2(day.isoString, locale),
1233
1258
  children: day.dayNumber
1234
1259
  }
1235
1260
  )
@@ -1244,7 +1269,8 @@ function RangePickerCalendar({ classNames, ...props }) {
1244
1269
  ] });
1245
1270
  }
1246
1271
  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 });
1272
+ const ctx = useRangePickerContext("RangePicker.Presets");
1273
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "group", "aria-label": ctx.labels.presetsGroup, className: classNames?.root, ...props, children });
1248
1274
  }
1249
1275
  function resolvePreset(key, today, adapter) {
1250
1276
  switch (key) {
@@ -1283,8 +1309,9 @@ function resolvePreset(key, today, adapter) {
1283
1309
  };
1284
1310
  }
1285
1311
  case "thisYear": {
1312
+ const currentMonth = new Date(today).getUTCMonth();
1286
1313
  const yearStart = adapter.startOfMonth(
1287
- adapter.addMonths(today, -new Date(today).getUTCMonth())
1314
+ adapter.addMonths(today, -currentMonth)
1288
1315
  );
1289
1316
  return { start: yearStart, end: today };
1290
1317
  }
@@ -1366,10 +1393,7 @@ function useTimePickerContext(componentName) {
1366
1393
  return context;
1367
1394
  }
1368
1395
  function getDefaultIso() {
1369
- const now = /* @__PURE__ */ new Date();
1370
- return new Date(
1371
- Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
1372
- ).toISOString();
1396
+ return core.DateFnsAdapter.today();
1373
1397
  }
1374
1398
  function TimePickerRoot({
1375
1399
  value: controlledValue,
@@ -1378,28 +1402,37 @@ function TimePickerRoot({
1378
1402
  format = "24h",
1379
1403
  step = 1,
1380
1404
  withSeconds = false,
1405
+ displayTimezone,
1381
1406
  disabled = false,
1382
1407
  readOnly = false,
1408
+ labels: labelsProp,
1383
1409
  children
1384
1410
  }) {
1385
1411
  const pickerId = react.useId();
1412
+ const mergedLabels = react.useMemo(
1413
+ () => ({ ...core.DEFAULT_TIMEPICKER_LABELS, ...labelsProp }),
1414
+ [labelsProp]
1415
+ );
1386
1416
  const isControlled = react.useRef(controlledValue !== void 0).current;
1387
1417
  const [uncontrolledValue, setUncontrolledValue] = react.useState(
1388
1418
  defaultValue ?? null
1389
1419
  );
1390
1420
  const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
1391
1421
  const baseIso = currentValue ?? getDefaultIso();
1392
- const currentTime = react.useMemo(() => core.getTime(baseIso), [baseIso]);
1422
+ const currentTime = react.useMemo(
1423
+ () => displayTimezone ? core.getTimeInTimezone(baseIso, displayTimezone) : core.getTime(baseIso),
1424
+ [baseIso, displayTimezone]
1425
+ );
1393
1426
  const setTime = react.useCallback(
1394
1427
  (partial) => {
1395
1428
  if (disabled || readOnly) return;
1396
- const newIso = core.setTime(baseIso, partial);
1429
+ const newIso = displayTimezone ? core.setTimeInTimezone(baseIso, partial, displayTimezone) : core.setTime(baseIso, partial);
1397
1430
  if (!isControlled) {
1398
1431
  setUncontrolledValue(newIso);
1399
1432
  }
1400
1433
  onChange?.(newIso);
1401
1434
  },
1402
- [disabled, readOnly, baseIso, isControlled, onChange]
1435
+ [disabled, readOnly, baseIso, isControlled, onChange, displayTimezone]
1403
1436
  );
1404
1437
  const contextValue = react.useMemo(
1405
1438
  () => ({
@@ -1408,12 +1441,14 @@ function TimePickerRoot({
1408
1441
  format,
1409
1442
  step,
1410
1443
  withSeconds,
1444
+ displayTimezone,
1411
1445
  isDisabled: disabled,
1412
1446
  isReadOnly: readOnly,
1413
1447
  currentTime,
1414
- pickerId
1448
+ pickerId,
1449
+ labels: mergedLabels
1415
1450
  }),
1416
- [currentValue, setTime, format, step, withSeconds, disabled, readOnly, currentTime, pickerId]
1451
+ [currentValue, setTime, format, step, withSeconds, displayTimezone, disabled, readOnly, currentTime, pickerId, mergedLabels]
1417
1452
  );
1418
1453
  return /* @__PURE__ */ jsxRuntime.jsx(TimePickerContext.Provider, { value: contextValue, children });
1419
1454
  }
@@ -1459,7 +1494,7 @@ var TimePickerInput = react.forwardRef(
1459
1494
  type: "text",
1460
1495
  inputMode: "numeric",
1461
1496
  autoComplete: "off",
1462
- "aria-label": "\uC2DC\uAC04 \uC785\uB825",
1497
+ "aria-label": ctx.labels.timeInput,
1463
1498
  placeholder: ctx.withSeconds ? "HH:MM:SS" : "HH:MM",
1464
1499
  value: displayValue,
1465
1500
  disabled: ctx.isDisabled || props.disabled,
@@ -1472,46 +1507,42 @@ var TimePickerInput = react.forwardRef(
1472
1507
  );
1473
1508
  }
1474
1509
  );
1475
- function TimePickerHourList({ classNames, ...props }) {
1476
- const ctx = useTimePickerContext("TimePicker.HourList");
1477
- const { format, currentTime, isDisabled, isReadOnly } = ctx;
1510
+ function useListboxNavigation({
1511
+ items,
1512
+ onSelect,
1513
+ disabled = false
1514
+ }) {
1478
1515
  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
- );
1516
+ const rafIdRef = react.useRef(0);
1517
+ react.useEffect(() => {
1518
+ return () => cancelAnimationFrame(rafIdRef.current);
1519
+ }, []);
1490
1520
  const handleKeyDown = react.useCallback(
1491
- (e, hour) => {
1492
- if (isDisabled || isReadOnly) return;
1493
- const currentIndex = hours.indexOf(hour);
1521
+ (e, item) => {
1522
+ if (disabled) return;
1523
+ const currentIndex = items.indexOf(item);
1494
1524
  let newIndex = -1;
1495
1525
  if (e.key === "ArrowDown") {
1496
- newIndex = Math.min(currentIndex + 1, hours.length - 1);
1526
+ newIndex = Math.min(currentIndex + 1, items.length - 1);
1497
1527
  } else if (e.key === "ArrowUp") {
1498
1528
  newIndex = Math.max(currentIndex - 1, 0);
1499
1529
  } else if (e.key === "Home") {
1500
1530
  newIndex = 0;
1501
1531
  } else if (e.key === "End") {
1502
- newIndex = hours.length - 1;
1532
+ newIndex = items.length - 1;
1503
1533
  } else if (e.key === "Enter" || e.key === " ") {
1504
1534
  e.preventDefault();
1505
- handleSelect(hour);
1535
+ onSelect(item);
1506
1536
  return;
1507
1537
  } else {
1508
1538
  return;
1509
1539
  }
1510
1540
  e.preventDefault();
1511
- const targetHour = hours[newIndex];
1512
- if (targetHour !== void 0) {
1513
- handleSelect(targetHour);
1514
- requestAnimationFrame(() => {
1541
+ const target = items[newIndex];
1542
+ if (target !== void 0) {
1543
+ onSelect(target);
1544
+ cancelAnimationFrame(rafIdRef.current);
1545
+ rafIdRef.current = requestAnimationFrame(() => {
1515
1546
  const next = listRef.current?.querySelector(
1516
1547
  '[data-selected="true"]'
1517
1548
  );
@@ -1519,14 +1550,35 @@ function TimePickerHourList({ classNames, ...props }) {
1519
1550
  });
1520
1551
  }
1521
1552
  },
1522
- [hours, handleSelect, isDisabled, isReadOnly]
1553
+ [items, onSelect, disabled]
1554
+ );
1555
+ return { listRef, handleKeyDown };
1556
+ }
1557
+ function TimePickerHourList({ classNames, ...props }) {
1558
+ const ctx = useTimePickerContext("TimePicker.HourList");
1559
+ const { format, currentTime, isDisabled, isReadOnly } = ctx;
1560
+ const hours = core.generateHours(format);
1561
+ const selectedHourDisplay = format === "12h" ? core.to12Hour(currentTime.hours).hours12 : currentTime.hours;
1562
+ const currentPeriod = format === "12h" ? core.to12Hour(currentTime.hours).period : null;
1563
+ const handleSelect = react.useCallback(
1564
+ (hourDisplay) => {
1565
+ if (isDisabled || isReadOnly) return;
1566
+ const hours24 = format === "12h" && currentPeriod ? core.to24Hour(hourDisplay, currentPeriod) : hourDisplay;
1567
+ ctx.setTime({ hours: hours24 });
1568
+ },
1569
+ [format, currentPeriod, ctx, isDisabled, isReadOnly]
1523
1570
  );
1571
+ const { listRef, handleKeyDown } = useListboxNavigation({
1572
+ items: hours,
1573
+ onSelect: handleSelect,
1574
+ disabled: isDisabled || isReadOnly
1575
+ });
1524
1576
  return /* @__PURE__ */ jsxRuntime.jsx(
1525
1577
  "ul",
1526
1578
  {
1527
1579
  ref: listRef,
1528
1580
  role: "listbox",
1529
- "aria-label": "\uC2DC",
1581
+ "aria-label": ctx.labels.hourList,
1530
1582
  "aria-disabled": isDisabled || void 0,
1531
1583
  className: classNames?.root,
1532
1584
  ...props,
@@ -1539,7 +1591,7 @@ function TimePickerHourList({ classNames, ...props }) {
1539
1591
  role: "option",
1540
1592
  "aria-selected": isSelected,
1541
1593
  "aria-disabled": isDisabled || void 0,
1542
- "aria-label": `${hour}\uC2DC`,
1594
+ "aria-label": ctx.labels.hourOption(hour),
1543
1595
  "data-selected": isSelected || void 0,
1544
1596
  tabIndex: isSelected ? 0 : -1,
1545
1597
  className: optionClass,
@@ -1556,7 +1608,6 @@ function TimePickerHourList({ classNames, ...props }) {
1556
1608
  function TimePickerMinuteList({ classNames, ...props }) {
1557
1609
  const ctx = useTimePickerContext("TimePicker.MinuteList");
1558
1610
  const { step, currentTime, isDisabled, isReadOnly } = ctx;
1559
- const listRef = react.useRef(null);
1560
1611
  const minutes = core.generateMinutes(step);
1561
1612
  const handleSelect = react.useCallback(
1562
1613
  (minute) => {
@@ -1565,46 +1616,17 @@ function TimePickerMinuteList({ classNames, ...props }) {
1565
1616
  },
1566
1617
  [ctx, isDisabled, isReadOnly]
1567
1618
  );
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
- );
1619
+ const { listRef, handleKeyDown } = useListboxNavigation({
1620
+ items: minutes,
1621
+ onSelect: handleSelect,
1622
+ disabled: isDisabled || isReadOnly
1623
+ });
1602
1624
  return /* @__PURE__ */ jsxRuntime.jsx(
1603
1625
  "ul",
1604
1626
  {
1605
1627
  ref: listRef,
1606
1628
  role: "listbox",
1607
- "aria-label": "\uBD84",
1629
+ "aria-label": ctx.labels.minuteList,
1608
1630
  "aria-disabled": isDisabled || void 0,
1609
1631
  className: classNames?.root,
1610
1632
  ...props,
@@ -1617,7 +1639,7 @@ function TimePickerMinuteList({ classNames, ...props }) {
1617
1639
  role: "option",
1618
1640
  "aria-selected": isSelected,
1619
1641
  "aria-disabled": isDisabled || void 0,
1620
- "aria-label": `${minute}\uBD84`,
1642
+ "aria-label": ctx.labels.minuteOption(minute),
1621
1643
  "data-selected": isSelected || void 0,
1622
1644
  tabIndex: isSelected ? 0 : -1,
1623
1645
  className: optionClass,
@@ -1660,7 +1682,7 @@ function TimePickerAmPmToggle({ classNames, ...props }) {
1660
1682
  }
1661
1683
  );
1662
1684
  };
1663
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "radiogroup", "aria-label": "\uC624\uC804/\uC624\uD6C4", className: classNames?.root, ...props, children: [
1685
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "radiogroup", "aria-label": ctx.labels.amPmToggle, className: classNames?.root, ...props, children: [
1664
1686
  renderButton("AM"),
1665
1687
  renderButton("PM")
1666
1688
  ] });
@@ -1674,10 +1696,7 @@ var TimePicker = Object.assign(TimePickerRoot, {
1674
1696
  AmPmToggle: TimePickerAmPmToggle
1675
1697
  });
1676
1698
  function getDefaultIso2() {
1677
- const now = /* @__PURE__ */ new Date();
1678
- return new Date(
1679
- Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
1680
- ).toISOString();
1699
+ return core.DateFnsAdapter.today();
1681
1700
  }
1682
1701
  function DateTimePickerRoot({
1683
1702
  value: controlledValue,
@@ -1690,10 +1709,20 @@ function DateTimePickerRoot({
1690
1709
  weekStartsOn = 0,
1691
1710
  displayFormat = "yyyy-MM-dd HH:mm",
1692
1711
  locale = "en-US",
1712
+ displayTimezone,
1693
1713
  adapter = core.DateFnsAdapter,
1714
+ labels: labelsProp,
1694
1715
  children
1695
1716
  }) {
1696
1717
  const pickerId = react.useId();
1718
+ const mergedDateLabels = react.useMemo(
1719
+ () => ({ ...core.DEFAULT_DATEPICKER_LABELS, ...labelsProp }),
1720
+ [labelsProp]
1721
+ );
1722
+ const mergedTimeLabels = react.useMemo(
1723
+ () => ({ ...core.DEFAULT_TIMEPICKER_LABELS, ...labelsProp }),
1724
+ [labelsProp]
1725
+ );
1697
1726
  const isControlled = react.useRef(controlledValue !== void 0).current;
1698
1727
  const referenceRef = react.useRef(null);
1699
1728
  const [uncontrolledValue, setUncontrolledValue] = react.useState(
@@ -1702,15 +1731,21 @@ function DateTimePickerRoot({
1702
1731
  const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
1703
1732
  const [isOpen, setIsOpen] = react.useState(false);
1704
1733
  const [viewMonth, setViewMonth] = react.useState(
1705
- currentValue ?? adapter.today()
1734
+ currentValue ?? adapter.today(displayTimezone)
1706
1735
  );
1707
1736
  const [focusedDate, setFocusedDate] = react.useState(
1708
- currentValue ?? adapter.today()
1737
+ currentValue ?? adapter.today(displayTimezone)
1709
1738
  );
1710
1739
  const isDisabled = typeof disabled === "boolean" ? disabled : false;
1711
- const disabledRules = Array.isArray(disabled) ? disabled : [];
1740
+ const disabledRules = react.useMemo(
1741
+ () => Array.isArray(disabled) ? disabled : [],
1742
+ [disabled]
1743
+ );
1712
1744
  const baseIso = currentValue ?? getDefaultIso2();
1713
- const currentTime = react.useMemo(() => core.getTime(baseIso), [baseIso]);
1745
+ const currentTime = react.useMemo(
1746
+ () => displayTimezone ? core.getTimeInTimezone(baseIso, displayTimezone) : core.getTime(baseIso),
1747
+ [baseIso, displayTimezone]
1748
+ );
1714
1749
  const updateValue = react.useCallback(
1715
1750
  (next) => {
1716
1751
  if (isDisabled || readOnly) return;
@@ -1727,27 +1762,28 @@ function DateTimePickerRoot({
1727
1762
  updateValue(null);
1728
1763
  return;
1729
1764
  }
1730
- const time = currentValue ? core.getTime(currentValue) : currentTime;
1731
- const merged = core.setTime(newDateIso, time);
1765
+ const normalizedDate = displayTimezone ? core.civilMidnightFromUtcDay(newDateIso, displayTimezone) : newDateIso;
1766
+ const time = currentValue ? displayTimezone ? core.getTimeInTimezone(currentValue, displayTimezone) : core.getTime(currentValue) : currentTime;
1767
+ const merged = displayTimezone ? core.setTimeInTimezone(normalizedDate, time, displayTimezone) : core.setTime(normalizedDate, time);
1732
1768
  updateValue(merged);
1733
1769
  },
1734
- [currentValue, currentTime, updateValue]
1770
+ [currentValue, currentTime, updateValue, displayTimezone]
1735
1771
  );
1736
1772
  const setTime = react.useCallback(
1737
1773
  (partial) => {
1738
1774
  const base = currentValue ?? getDefaultIso2();
1739
- const merged = core.setTime(base, partial);
1775
+ const merged = displayTimezone ? core.setTimeInTimezone(base, partial, displayTimezone) : core.setTime(base, partial);
1740
1776
  updateValue(merged);
1741
1777
  },
1742
- [currentValue, updateValue]
1778
+ [currentValue, updateValue, displayTimezone]
1743
1779
  );
1744
1780
  const open = react.useCallback(() => {
1745
1781
  if (isDisabled || readOnly) return;
1746
1782
  setIsOpen(true);
1747
- const target = currentValue ?? adapter.today();
1783
+ const target = currentValue ?? adapter.today(displayTimezone);
1748
1784
  setViewMonth(target);
1749
1785
  setFocusedDate(target);
1750
- }, [isDisabled, readOnly, currentValue, adapter]);
1786
+ }, [isDisabled, readOnly, currentValue, adapter, displayTimezone]);
1751
1787
  const close = react.useCallback(() => {
1752
1788
  setIsOpen(false);
1753
1789
  }, []);
@@ -1773,9 +1809,11 @@ function DateTimePickerRoot({
1773
1809
  weekStartsOn,
1774
1810
  displayFormat,
1775
1811
  locale,
1812
+ displayTimezone,
1776
1813
  isDisabled,
1777
1814
  isReadOnly: readOnly,
1778
- pickerId
1815
+ pickerId,
1816
+ labels: mergedDateLabels
1779
1817
  }),
1780
1818
  [
1781
1819
  currentValue,
@@ -1791,9 +1829,11 @@ function DateTimePickerRoot({
1791
1829
  weekStartsOn,
1792
1830
  displayFormat,
1793
1831
  locale,
1832
+ displayTimezone,
1794
1833
  isDisabled,
1795
1834
  readOnly,
1796
- pickerId
1835
+ pickerId,
1836
+ mergedDateLabels
1797
1837
  ]
1798
1838
  );
1799
1839
  const timeContext = react.useMemo(
@@ -1803,25 +1843,36 @@ function DateTimePickerRoot({
1803
1843
  format,
1804
1844
  step,
1805
1845
  withSeconds: false,
1846
+ displayTimezone,
1806
1847
  isDisabled,
1807
1848
  isReadOnly: readOnly,
1808
1849
  currentTime,
1809
- pickerId
1850
+ pickerId,
1851
+ labels: mergedTimeLabels
1810
1852
  }),
1811
- [currentValue, setTime, format, step, isDisabled, readOnly, currentTime, pickerId]
1853
+ [currentValue, setTime, format, step, displayTimezone, isDisabled, readOnly, currentTime, pickerId, mergedTimeLabels]
1812
1854
  );
1813
1855
  return /* @__PURE__ */ jsxRuntime.jsx(DatePickerContext.Provider, { value: dateContext, children: /* @__PURE__ */ jsxRuntime.jsx(TimePickerContext.Provider, { value: timeContext, children }) });
1814
1856
  }
1815
1857
  var DateTimePickerInput = react.forwardRef(
1816
- function DateTimePickerInput2({ onFocus, onKeyDown, ...props }, ref) {
1858
+ function DateTimePickerInput2({ onClick, onKeyDown, ...props }, ref) {
1817
1859
  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(
1860
+ let displayValue = "";
1861
+ if (ctx.value) {
1862
+ try {
1863
+ const datePart = ctx.adapter.format(ctx.value, "yyyy-MM-dd", ctx.displayTimezone);
1864
+ const time = ctx.displayTimezone ? core.getTimeInTimezone(ctx.value, ctx.displayTimezone) : core.getTime(ctx.value);
1865
+ displayValue = `${datePart} ${core.formatTimeString(time)}`;
1866
+ } catch {
1867
+ displayValue = ctx.value;
1868
+ }
1869
+ }
1870
+ const handleClick = react.useCallback(
1820
1871
  (e) => {
1821
- ctx.open();
1822
- onFocus?.(e);
1872
+ if (!ctx.isOpen) ctx.open();
1873
+ onClick?.(e);
1823
1874
  },
1824
- [ctx, onFocus]
1875
+ [ctx, onClick]
1825
1876
  );
1826
1877
  const handleKeyDown = react.useCallback(
1827
1878
  (e) => {
@@ -1847,7 +1898,7 @@ var DateTimePickerInput = react.forwardRef(
1847
1898
  type: "text",
1848
1899
  role: "combobox",
1849
1900
  readOnly: true,
1850
- "aria-label": "\uB0A0\uC9DC \uBC0F \uC2DC\uAC04",
1901
+ "aria-label": ctx.labels.dateTimeInput ?? "Date and time",
1851
1902
  "aria-expanded": ctx.isOpen,
1852
1903
  "aria-haspopup": "dialog",
1853
1904
  "aria-controls": ctx.isOpen ? calendarId : void 0,
@@ -1855,7 +1906,7 @@ var DateTimePickerInput = react.forwardRef(
1855
1906
  autoComplete: "off",
1856
1907
  value: displayValue,
1857
1908
  disabled: ctx.isDisabled || props.disabled,
1858
- onFocus: handleFocus,
1909
+ onClick: handleClick,
1859
1910
  onKeyDown: handleKeyDown,
1860
1911
  ...props
1861
1912
  }
@@ -1881,7 +1932,8 @@ function useDatePicker(options = {}) {
1881
1932
  onChange,
1882
1933
  disabled = [],
1883
1934
  weekStartsOn = 0,
1884
- adapter = core.DateFnsAdapter
1935
+ adapter = core.DateFnsAdapter,
1936
+ displayTimezone
1885
1937
  } = options;
1886
1938
  const pickerId = react.useId();
1887
1939
  const isControlled = react.useRef(controlledValue !== void 0).current;
@@ -1890,24 +1942,29 @@ function useDatePicker(options = {}) {
1890
1942
  );
1891
1943
  const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
1892
1944
  const [isOpen, setIsOpen] = react.useState(false);
1893
- const [viewMonth, setViewMonth] = react.useState(currentValue ?? adapter.today());
1894
- const [focusedDate, setFocusedDate] = react.useState(currentValue ?? adapter.today());
1945
+ const [viewMonth, setViewMonth] = react.useState(
1946
+ currentValue ?? adapter.today(displayTimezone)
1947
+ );
1948
+ const [focusedDate, setFocusedDate] = react.useState(
1949
+ currentValue ?? adapter.today(displayTimezone)
1950
+ );
1895
1951
  const selectDate = react.useCallback(
1896
1952
  (iso) => {
1953
+ const normalized = iso && displayTimezone ? core.civilMidnightFromUtcDay(iso, displayTimezone) : iso;
1897
1954
  if (!isControlled) {
1898
- setUncontrolledValue(iso);
1955
+ setUncontrolledValue(normalized);
1899
1956
  }
1900
- onChange?.(iso);
1957
+ onChange?.(normalized);
1901
1958
  setIsOpen(false);
1902
1959
  },
1903
- [isControlled, onChange]
1960
+ [isControlled, onChange, displayTimezone]
1904
1961
  );
1905
1962
  const open = react.useCallback(() => {
1906
1963
  setIsOpen(true);
1907
- const target = currentValue ?? adapter.today();
1964
+ const target = currentValue ?? adapter.today(displayTimezone);
1908
1965
  setViewMonth(target);
1909
1966
  setFocusedDate(target);
1910
- }, [currentValue, adapter]);
1967
+ }, [currentValue, adapter, displayTimezone]);
1911
1968
  const close = react.useCallback(() => {
1912
1969
  setIsOpen(false);
1913
1970
  }, []);
@@ -1929,7 +1986,8 @@ function useDatePicker(options = {}) {
1929
1986
  weekStartsOn,
1930
1987
  selected: currentValue,
1931
1988
  focusedDate,
1932
- disabled
1989
+ disabled,
1990
+ timezone: displayTimezone
1933
1991
  });
1934
1992
  return {
1935
1993
  value: currentValue,
@@ -1957,7 +2015,8 @@ function useRangePicker(options = {}) {
1957
2015
  onChange,
1958
2016
  disabled = [],
1959
2017
  weekStartsOn = 0,
1960
- adapter = core.DateFnsAdapter
2018
+ adapter = core.DateFnsAdapter,
2019
+ displayTimezone
1961
2020
  } = options;
1962
2021
  const pickerId = react.useId();
1963
2022
  const isControlled = react.useRef(controlledValue !== void 0).current;
@@ -1969,10 +2028,10 @@ function useRangePicker(options = {}) {
1969
2028
  const [selectingTarget, setSelectingTarget] = react.useState("start");
1970
2029
  const [hoverDate, setHoverDate] = react.useState(null);
1971
2030
  const [viewMonth, setViewMonth] = react.useState(
1972
- currentValue.start ?? adapter.today()
2031
+ currentValue.start ?? adapter.today(displayTimezone)
1973
2032
  );
1974
2033
  const [focusedDate, setFocusedDate] = react.useState(
1975
- currentValue.start ?? adapter.today()
2034
+ currentValue.start ?? adapter.today(displayTimezone)
1976
2035
  );
1977
2036
  const setRange = react.useCallback(
1978
2037
  (range) => {
@@ -1985,35 +2044,36 @@ function useRangePicker(options = {}) {
1985
2044
  );
1986
2045
  const selectDate = react.useCallback(
1987
2046
  (iso) => {
2047
+ const normalized = displayTimezone ? core.civilMidnightFromUtcDay(iso, displayTimezone) : iso;
1988
2048
  if (selectingTarget === "start") {
1989
- setRange({ start: iso, end: null });
2049
+ setRange({ start: normalized, end: null });
1990
2050
  setSelectingTarget("end");
1991
2051
  setHoverDate(null);
1992
2052
  } else {
1993
2053
  const start = currentValue.start;
1994
2054
  if (!start) {
1995
- setRange({ start: iso, end: null });
2055
+ setRange({ start: normalized, end: null });
1996
2056
  setSelectingTarget("end");
1997
2057
  return;
1998
2058
  }
1999
- const newRange = adapter.isBefore(iso, start) ? { start: iso, end: start } : { start, end: iso };
2059
+ const newRange = adapter.isBefore(normalized, start) ? { start: normalized, end: start } : { start, end: normalized };
2000
2060
  setRange(newRange);
2001
2061
  setSelectingTarget("start");
2002
2062
  setHoverDate(null);
2003
2063
  setIsOpen(false);
2004
2064
  }
2005
2065
  },
2006
- [selectingTarget, currentValue.start, adapter, setRange]
2066
+ [selectingTarget, currentValue.start, adapter, setRange, displayTimezone]
2007
2067
  );
2008
2068
  const open = react.useCallback(() => {
2009
2069
  setIsOpen(true);
2010
- const target = currentValue.start ?? adapter.today();
2070
+ const target = currentValue.start ?? adapter.today(displayTimezone);
2011
2071
  setViewMonth(target);
2012
2072
  setFocusedDate(target);
2013
2073
  if (currentValue.start && currentValue.end) {
2014
2074
  setSelectingTarget("start");
2015
2075
  }
2016
- }, [currentValue, adapter]);
2076
+ }, [currentValue, adapter, displayTimezone]);
2017
2077
  const close = react.useCallback(() => {
2018
2078
  setIsOpen(false);
2019
2079
  setHoverDate(null);
@@ -2037,7 +2097,8 @@ function useRangePicker(options = {}) {
2037
2097
  focusedDate,
2038
2098
  disabled,
2039
2099
  range: currentValue,
2040
- rangeHover: hoverDate
2100
+ rangeHover: hoverDate,
2101
+ timezone: displayTimezone
2041
2102
  });
2042
2103
  return {
2043
2104
  value: currentValue,
@@ -2062,10 +2123,7 @@ function useRangePicker(options = {}) {
2062
2123
  };
2063
2124
  }
2064
2125
  function getDefaultIso3() {
2065
- const now = /* @__PURE__ */ new Date();
2066
- return new Date(
2067
- Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())
2068
- ).toISOString();
2126
+ return core.DateFnsAdapter.today();
2069
2127
  }
2070
2128
  function useTimePicker(options = {}) {
2071
2129
  const {
@@ -2073,7 +2131,8 @@ function useTimePicker(options = {}) {
2073
2131
  defaultValue,
2074
2132
  onChange,
2075
2133
  format = "24h",
2076
- step = 1
2134
+ step = 1,
2135
+ displayTimezone
2077
2136
  } = options;
2078
2137
  const pickerId = react.useId();
2079
2138
  const isControlled = react.useRef(controlledValue !== void 0).current;
@@ -2082,16 +2141,19 @@ function useTimePicker(options = {}) {
2082
2141
  );
2083
2142
  const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
2084
2143
  const baseIso = currentValue ?? getDefaultIso3();
2085
- const currentTime = react.useMemo(() => core.getTime(baseIso), [baseIso]);
2144
+ const currentTime = react.useMemo(
2145
+ () => displayTimezone ? core.getTimeInTimezone(baseIso, displayTimezone) : core.getTime(baseIso),
2146
+ [baseIso, displayTimezone]
2147
+ );
2086
2148
  const setTime = react.useCallback(
2087
2149
  (partial) => {
2088
- const newIso = core.setTime(baseIso, partial);
2150
+ const newIso = displayTimezone ? core.setTimeInTimezone(baseIso, partial, displayTimezone) : core.setTime(baseIso, partial);
2089
2151
  if (!isControlled) {
2090
2152
  setUncontrolledValue(newIso);
2091
2153
  }
2092
2154
  onChange?.(newIso);
2093
2155
  },
2094
- [baseIso, isControlled, onChange]
2156
+ [baseIso, isControlled, onChange, displayTimezone]
2095
2157
  );
2096
2158
  const period = format === "12h" ? core.to12Hour(currentTime.hours).period : null;
2097
2159
  const displayHour = format === "12h" ? core.to12Hour(currentTime.hours).hours12 : currentTime.hours;