@kalyx/react 0.3.0 → 1.0.0-rc.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
@@ -21,15 +21,29 @@ function useDatePickerContext(componentName) {
21
21
  }
22
22
  return context;
23
23
  }
24
+ function useChangeEffect(value, callback) {
25
+ const callbackRef = react.useRef(callback);
26
+ callbackRef.current = callback;
27
+ const prevRef = react.useRef(value);
28
+ react.useEffect(() => {
29
+ if (prevRef.current !== value) {
30
+ prevRef.current = value;
31
+ callbackRef.current?.(value);
32
+ }
33
+ }, [value]);
34
+ }
24
35
  function DatePickerRoot({
25
36
  value: controlledValue,
26
37
  defaultValue,
27
38
  onChange,
39
+ onOpenChange,
40
+ onCalendarNavigate,
28
41
  disabled = false,
29
42
  readOnly = false,
30
43
  weekStartsOn = 0,
31
44
  displayFormat = "yyyy-MM-dd",
32
45
  locale = "en-US",
46
+ displayTimezone,
33
47
  adapter = core.DateFnsAdapter,
34
48
  labels: labelsProp,
35
49
  children
@@ -43,11 +57,14 @@ function DatePickerRoot({
43
57
  const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
44
58
  const [isOpen, setIsOpen] = react.useState(false);
45
59
  const [viewMonth, setViewMonth] = react.useState(
46
- currentValue ?? adapter.today()
60
+ currentValue ?? adapter.today(displayTimezone)
47
61
  );
48
62
  const [focusedDate, setFocusedDate] = react.useState(
49
- currentValue ?? adapter.today()
63
+ currentValue ?? adapter.today(displayTimezone)
50
64
  );
65
+ useChangeEffect(isOpen, onOpenChange);
66
+ const viewMonthStart = react.useMemo(() => adapter.startOfMonth(viewMonth), [viewMonth, adapter]);
67
+ useChangeEffect(viewMonthStart, onCalendarNavigate);
51
68
  const mergedLabels = react.useMemo(
52
69
  () => ({ ...core.DEFAULT_DATEPICKER_LABELS, ...labelsProp }),
53
70
  [labelsProp]
@@ -60,21 +77,22 @@ function DatePickerRoot({
60
77
  const selectDate = react.useCallback(
61
78
  (iso) => {
62
79
  if (isDisabled || readOnly) return;
80
+ const normalized = iso && displayTimezone ? core.civilMidnightFromUtcDay(iso, displayTimezone) : iso;
63
81
  if (!isControlled) {
64
- setUncontrolledValue(iso);
82
+ setUncontrolledValue(normalized);
65
83
  }
66
- onChange?.(iso);
84
+ onChange?.(normalized);
67
85
  setIsOpen(false);
68
86
  },
69
- [isControlled, isDisabled, readOnly, onChange]
87
+ [isControlled, isDisabled, readOnly, onChange, displayTimezone]
70
88
  );
71
89
  const open = react.useCallback(() => {
72
90
  if (isDisabled || readOnly) return;
73
91
  setIsOpen(true);
74
- const target = currentValue ?? adapter.today();
92
+ const target = currentValue ?? adapter.today(displayTimezone);
75
93
  setViewMonth(target);
76
94
  setFocusedDate(target);
77
- }, [isDisabled, readOnly, currentValue, adapter]);
95
+ }, [isDisabled, readOnly, currentValue, adapter, displayTimezone]);
78
96
  const close = react.useCallback(() => {
79
97
  setIsOpen(false);
80
98
  }, []);
@@ -103,6 +121,7 @@ function DatePickerRoot({
103
121
  weekStartsOn,
104
122
  displayFormat,
105
123
  locale,
124
+ displayTimezone,
106
125
  isDisabled,
107
126
  isReadOnly: readOnly,
108
127
  pickerId,
@@ -122,6 +141,7 @@ function DatePickerRoot({
122
141
  weekStartsOn,
123
142
  displayFormat,
124
143
  locale,
144
+ displayTimezone,
125
145
  isDisabled,
126
146
  readOnly,
127
147
  pickerId,
@@ -138,7 +158,7 @@ var DatePickerInput = react.forwardRef(
138
158
  let formattedValue = "";
139
159
  if (ctx.value) {
140
160
  try {
141
- formattedValue = ctx.adapter.format(ctx.value, displayFormat);
161
+ formattedValue = ctx.adapter.format(ctx.value, displayFormat, ctx.displayTimezone);
142
162
  } catch {
143
163
  formattedValue = ctx.value;
144
164
  }
@@ -386,13 +406,14 @@ function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
386
406
  const ctx = useDatePickerContext("DatePicker.Calendar");
387
407
  const gridRef = react.useRef(null);
388
408
  const [announcement, setAnnouncement] = react.useState("");
389
- const { adapter, viewMonth, focusedDate, weekStartsOn, disabled, locale } = ctx;
409
+ const { adapter, viewMonth, focusedDate, weekStartsOn, disabled, locale, displayTimezone } = ctx;
390
410
  const weekdays = core.getWeekdayNames(locale, weekStartsOn);
391
411
  const weeks = core.getCalendarDays(viewMonth, adapter, {
392
412
  weekStartsOn,
393
413
  selected: ctx.value,
394
414
  focusedDate,
395
- disabled
415
+ disabled,
416
+ timezone: displayTimezone
396
417
  });
397
418
  const year = adapter.getYear(viewMonth);
398
419
  const month = adapter.getMonth(viewMonth);
@@ -773,6 +794,95 @@ function DatePickerYearGrid({
773
794
  )
774
795
  ] });
775
796
  }
797
+ function DatePickerPresets({ classNames, children, ...props }) {
798
+ const ctx = useDatePickerContext("DatePicker.Presets");
799
+ return /* @__PURE__ */ jsxRuntime.jsx(
800
+ "div",
801
+ {
802
+ role: "group",
803
+ "aria-label": ctx.labels.popoverLabel,
804
+ className: classNames?.root,
805
+ ...props,
806
+ children
807
+ }
808
+ );
809
+ }
810
+ function resolveDatePreset(key, today, adapter) {
811
+ switch (key) {
812
+ case "today":
813
+ return today;
814
+ case "tomorrow":
815
+ return adapter.addDays(today, 1);
816
+ case "yesterday":
817
+ return adapter.addDays(today, -1);
818
+ case "startOfMonth":
819
+ return adapter.startOfMonth(today);
820
+ case "endOfMonth":
821
+ return adapter.startOfDay(adapter.endOfMonth(today));
822
+ case "startOfYear": {
823
+ const currentMonth = adapter.getMonth(today);
824
+ return adapter.startOfMonth(adapter.addMonths(today, -currentMonth));
825
+ }
826
+ }
827
+ }
828
+ function DatePickerPreset({
829
+ value: presetKey,
830
+ date: directDate,
831
+ children,
832
+ onClick,
833
+ ...props
834
+ }) {
835
+ const ctx = useDatePickerContext("DatePicker.Preset");
836
+ const handleClick = react.useCallback(
837
+ (e) => {
838
+ if (ctx.isDisabled || ctx.isReadOnly) return;
839
+ let resolved;
840
+ if (directDate) {
841
+ resolved = directDate;
842
+ } else if (presetKey) {
843
+ resolved = resolveDatePreset(
844
+ presetKey,
845
+ ctx.adapter.today(ctx.displayTimezone),
846
+ ctx.adapter
847
+ );
848
+ } else {
849
+ return;
850
+ }
851
+ ctx.selectDate(resolved);
852
+ onClick?.(e);
853
+ },
854
+ [ctx, presetKey, directDate, onClick]
855
+ );
856
+ const isActive = (() => {
857
+ if (!ctx.value) return false;
858
+ let target;
859
+ if (directDate) {
860
+ target = directDate;
861
+ } else if (presetKey) {
862
+ target = resolveDatePreset(
863
+ presetKey,
864
+ ctx.adapter.today(ctx.displayTimezone),
865
+ ctx.adapter
866
+ );
867
+ } else {
868
+ return false;
869
+ }
870
+ return ctx.adapter.isSameDay(ctx.value, target, ctx.displayTimezone);
871
+ })();
872
+ return /* @__PURE__ */ jsxRuntime.jsx(
873
+ "button",
874
+ {
875
+ type: "button",
876
+ role: "option",
877
+ "aria-selected": isActive,
878
+ "data-active": isActive || void 0,
879
+ disabled: ctx.isDisabled,
880
+ onClick: handleClick,
881
+ ...props,
882
+ children
883
+ }
884
+ );
885
+ }
776
886
 
777
887
  // src/components/DatePicker/index.ts
778
888
  var DatePicker = Object.assign(DatePickerRoot, {
@@ -781,7 +891,9 @@ var DatePicker = Object.assign(DatePickerRoot, {
781
891
  Popover: DatePickerPopover,
782
892
  Calendar: DatePickerCalendar,
783
893
  MonthGrid: DatePickerMonthGrid,
784
- YearGrid: DatePickerYearGrid
894
+ YearGrid: DatePickerYearGrid,
895
+ Presets: DatePickerPresets,
896
+ Preset: DatePickerPreset
785
897
  });
786
898
  var RangePickerContext = react.createContext(null);
787
899
  function useRangePickerContext(componentName) {
@@ -803,11 +915,14 @@ function RangePickerRoot({
803
915
  value: controlledValue,
804
916
  defaultValue,
805
917
  onChange,
918
+ onOpenChange,
919
+ onCalendarNavigate,
806
920
  disabled = false,
807
921
  readOnly = false,
808
922
  weekStartsOn = 0,
809
923
  displayFormat = "yyyy-MM-dd",
810
924
  locale = "en-US",
925
+ displayTimezone,
811
926
  adapter = core.DateFnsAdapter,
812
927
  labels: labelsProp,
813
928
  children
@@ -823,11 +938,14 @@ function RangePickerRoot({
823
938
  const [selectingTarget, setSelectingTarget] = react.useState("start");
824
939
  const [hoverDate, setHoverDate] = react.useState(null);
825
940
  const [viewMonth, setViewMonth] = react.useState(
826
- currentValue.start ?? adapter.today()
941
+ currentValue.start ?? adapter.today(displayTimezone)
827
942
  );
828
943
  const [focusedDate, setFocusedDate] = react.useState(
829
- currentValue.start ?? adapter.today()
944
+ currentValue.start ?? adapter.today(displayTimezone)
830
945
  );
946
+ useChangeEffect(isOpen, onOpenChange);
947
+ const viewMonthStart = react.useMemo(() => adapter.startOfMonth(viewMonth), [viewMonth, adapter]);
948
+ useChangeEffect(viewMonthStart, onCalendarNavigate);
831
949
  const mergedLabels = react.useMemo(
832
950
  () => ({ ...core.DEFAULT_RANGEPICKER_LABELS, ...labelsProp }),
833
951
  [labelsProp]
@@ -850,23 +968,24 @@ function RangePickerRoot({
850
968
  const selectDate = react.useCallback(
851
969
  (iso) => {
852
970
  if (isDisabled || readOnly) return;
971
+ const normalized = displayTimezone ? core.civilMidnightFromUtcDay(iso, displayTimezone) : iso;
853
972
  if (selectingTarget === "start") {
854
- const newRange = { start: iso, end: null };
973
+ const newRange = { start: normalized, end: null };
855
974
  setRange(newRange);
856
975
  setSelectingTarget("end");
857
976
  setHoverDate(null);
858
977
  } else {
859
978
  const start = currentValue.start;
860
979
  if (!start) {
861
- setRange({ start: iso, end: null });
980
+ setRange({ start: normalized, end: null });
862
981
  setSelectingTarget("end");
863
982
  return;
864
983
  }
865
984
  let newRange;
866
- if (adapter.isBefore(iso, start)) {
867
- newRange = { start: iso, end: start };
985
+ if (adapter.isBefore(normalized, start)) {
986
+ newRange = { start: normalized, end: start };
868
987
  } else {
869
- newRange = { start, end: iso };
988
+ newRange = { start, end: normalized };
870
989
  }
871
990
  setRange(newRange);
872
991
  setSelectingTarget("start");
@@ -874,18 +993,18 @@ function RangePickerRoot({
874
993
  setIsOpen(false);
875
994
  }
876
995
  },
877
- [isDisabled, readOnly, selectingTarget, currentValue.start, adapter, setRange]
996
+ [isDisabled, readOnly, selectingTarget, currentValue.start, adapter, setRange, displayTimezone]
878
997
  );
879
998
  const open = react.useCallback(() => {
880
999
  if (isDisabled || readOnly) return;
881
1000
  setIsOpen(true);
882
- const target = currentValue.start ?? adapter.today();
1001
+ const target = currentValue.start ?? adapter.today(displayTimezone);
883
1002
  setViewMonth(target);
884
1003
  setFocusedDate(target);
885
1004
  if (currentValue.start && currentValue.end) {
886
1005
  setSelectingTarget("start");
887
1006
  }
888
- }, [isDisabled, readOnly, currentValue, adapter]);
1007
+ }, [isDisabled, readOnly, currentValue, adapter, displayTimezone]);
889
1008
  const close = react.useCallback(() => {
890
1009
  setIsOpen(false);
891
1010
  setHoverDate(null);
@@ -916,6 +1035,7 @@ function RangePickerRoot({
916
1035
  weekStartsOn,
917
1036
  displayFormat,
918
1037
  locale,
1038
+ displayTimezone,
919
1039
  isDisabled,
920
1040
  isReadOnly: readOnly,
921
1041
  pickerId,
@@ -938,6 +1058,7 @@ function RangePickerRoot({
938
1058
  weekStartsOn,
939
1059
  displayFormat,
940
1060
  locale,
1061
+ displayTimezone,
941
1062
  isDisabled,
942
1063
  readOnly,
943
1064
  pickerId,
@@ -954,7 +1075,7 @@ var RangePickerInput = react.forwardRef(
954
1075
  let displayValue = "";
955
1076
  if (value) {
956
1077
  try {
957
- displayValue = ctx.adapter.format(value, displayFormat);
1078
+ displayValue = ctx.adapter.format(value, displayFormat, ctx.displayTimezone);
958
1079
  } catch {
959
1080
  displayValue = value;
960
1081
  }
@@ -1047,7 +1168,11 @@ var srOnly2 = {
1047
1168
  whiteSpace: "nowrap",
1048
1169
  border: 0
1049
1170
  };
1050
- function RangePickerCalendar({ classNames, ...props }) {
1171
+ function RangePickerCalendar({
1172
+ classNames,
1173
+ selectionMode = "range",
1174
+ ...props
1175
+ }) {
1051
1176
  const ctx = useRangePickerContext("RangePicker.Calendar");
1052
1177
  const gridRef = react.useRef(null);
1053
1178
  const [announcement, setAnnouncement] = react.useState("");
@@ -1059,7 +1184,8 @@ function RangePickerCalendar({ classNames, ...props }) {
1059
1184
  disabled,
1060
1185
  value,
1061
1186
  hoverDate,
1062
- selectingTarget
1187
+ selectingTarget,
1188
+ displayTimezone
1063
1189
  } = ctx;
1064
1190
  const { locale } = ctx;
1065
1191
  const weekdays = core.getWeekdayNames(locale, weekStartsOn);
@@ -1068,7 +1194,8 @@ function RangePickerCalendar({ classNames, ...props }) {
1068
1194
  focusedDate,
1069
1195
  disabled,
1070
1196
  range: value,
1071
- rangeHover: hoverDate
1197
+ rangeHover: hoverDate,
1198
+ timezone: displayTimezone
1072
1199
  });
1073
1200
  const year = adapter.getYear(viewMonth);
1074
1201
  const month = adapter.getMonth(viewMonth);
@@ -1091,21 +1218,39 @@ function RangePickerCalendar({ classNames, ...props }) {
1091
1218
  },
1092
1219
  [adapter, viewMonth, ctx, locale]
1093
1220
  );
1221
+ const commitDay = react.useCallback(
1222
+ (iso) => {
1223
+ if (selectionMode === "week") {
1224
+ const weekStart = adapter.startOfWeek(iso, weekStartsOn);
1225
+ const weekEnd = adapter.startOfDay(adapter.endOfWeek(iso, weekStartsOn));
1226
+ const range = { start: weekStart, end: weekEnd };
1227
+ ctx.setRange(range);
1228
+ ctx.close();
1229
+ setAnnouncement(
1230
+ `${safeFormatFullDate2(weekStart, locale)} \u2013 ${safeFormatFullDate2(weekEnd, locale)}`
1231
+ );
1232
+ } else {
1233
+ ctx.selectDate(iso);
1234
+ setAnnouncement(safeFormatFullDate2(iso, locale));
1235
+ }
1236
+ },
1237
+ [selectionMode, adapter, weekStartsOn, ctx, locale]
1238
+ );
1094
1239
  const handleDayClick = react.useCallback(
1095
1240
  (day) => {
1096
1241
  if (day.isDisabled) return;
1097
- ctx.selectDate(day.isoString);
1098
- setAnnouncement(safeFormatFullDate2(day.isoString, locale));
1242
+ commitDay(day.isoString);
1099
1243
  },
1100
- [ctx, locale]
1244
+ [commitDay]
1101
1245
  );
1102
1246
  const handleDayMouseEnter = react.useCallback(
1103
1247
  (day) => {
1248
+ if (selectionMode === "week") return;
1104
1249
  if (selectingTarget === "end" && value.start && !day.isDisabled) {
1105
1250
  ctx.setHoverDate(day.isoString);
1106
1251
  }
1107
1252
  },
1108
- [selectingTarget, value.start, ctx]
1253
+ [selectionMode, selectingTarget, value.start, ctx]
1109
1254
  );
1110
1255
  const handleMouseLeave = react.useCallback(() => {
1111
1256
  ctx.setHoverDate(null);
@@ -1142,7 +1287,7 @@ function RangePickerCalendar({ classNames, ...props }) {
1142
1287
  case " ":
1143
1288
  e.preventDefault();
1144
1289
  if (!core.isDateDisabled(focusedDate, disabled, adapter)) {
1145
- ctx.selectDate(focusedDate);
1290
+ commitDay(focusedDate);
1146
1291
  }
1147
1292
  return;
1148
1293
  case "Escape":
@@ -1157,12 +1302,12 @@ function RangePickerCalendar({ classNames, ...props }) {
1157
1302
  if (!adapter.isSameMonth(newFocused, viewMonth)) {
1158
1303
  ctx.setViewMonth(newFocused);
1159
1304
  }
1160
- if (selectingTarget === "end" && value.start) {
1305
+ if (selectionMode === "range" && selectingTarget === "end" && value.start) {
1161
1306
  ctx.setHoverDate(newFocused);
1162
1307
  }
1163
1308
  }
1164
1309
  },
1165
- [adapter, focusedDate, viewMonth, weekStartsOn, disabled, ctx, selectingTarget, value.start]
1310
+ [adapter, focusedDate, viewMonth, weekStartsOn, disabled, ctx, selectionMode, selectingTarget, value.start, commitDay]
1166
1311
  );
1167
1312
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.root, ...props, onMouseLeave: handleMouseLeave, children: [
1168
1313
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.header, children: [
@@ -1219,7 +1364,7 @@ function RangePickerCalendar({ classNames, ...props }) {
1219
1364
  day.isDisabled && classNames?.dayDisabled,
1220
1365
  !day.isCurrentMonth && classNames?.dayOutsideMonth
1221
1366
  ].filter(Boolean).join(" ") || void 0;
1222
- const isSelected = day.isRangeStart || day.isRangeEnd;
1367
+ const isSelected = selectionMode === "week" ? day.isRangeStart || day.isRangeEnd || day.isInRange : day.isRangeStart || day.isRangeEnd;
1223
1368
  return /* @__PURE__ */ jsxRuntime.jsx(
1224
1369
  "td",
1225
1370
  {
@@ -1391,6 +1536,7 @@ function TimePickerRoot({
1391
1536
  format = "24h",
1392
1537
  step = 1,
1393
1538
  withSeconds = false,
1539
+ displayTimezone,
1394
1540
  disabled = false,
1395
1541
  readOnly = false,
1396
1542
  labels: labelsProp,
@@ -1407,17 +1553,20 @@ function TimePickerRoot({
1407
1553
  );
1408
1554
  const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
1409
1555
  const baseIso = currentValue ?? getDefaultIso();
1410
- const currentTime = react.useMemo(() => core.getTime(baseIso), [baseIso]);
1556
+ const currentTime = react.useMemo(
1557
+ () => displayTimezone ? core.getTimeInTimezone(baseIso, displayTimezone) : core.getTime(baseIso),
1558
+ [baseIso, displayTimezone]
1559
+ );
1411
1560
  const setTime = react.useCallback(
1412
1561
  (partial) => {
1413
1562
  if (disabled || readOnly) return;
1414
- const newIso = core.setTime(baseIso, partial);
1563
+ const newIso = displayTimezone ? core.setTimeInTimezone(baseIso, partial, displayTimezone) : core.setTime(baseIso, partial);
1415
1564
  if (!isControlled) {
1416
1565
  setUncontrolledValue(newIso);
1417
1566
  }
1418
1567
  onChange?.(newIso);
1419
1568
  },
1420
- [disabled, readOnly, baseIso, isControlled, onChange]
1569
+ [disabled, readOnly, baseIso, isControlled, onChange, displayTimezone]
1421
1570
  );
1422
1571
  const contextValue = react.useMemo(
1423
1572
  () => ({
@@ -1426,13 +1575,14 @@ function TimePickerRoot({
1426
1575
  format,
1427
1576
  step,
1428
1577
  withSeconds,
1578
+ displayTimezone,
1429
1579
  isDisabled: disabled,
1430
1580
  isReadOnly: readOnly,
1431
1581
  currentTime,
1432
1582
  pickerId,
1433
1583
  labels: mergedLabels
1434
1584
  }),
1435
- [currentValue, setTime, format, step, withSeconds, disabled, readOnly, currentTime, pickerId, mergedLabels]
1585
+ [currentValue, setTime, format, step, withSeconds, displayTimezone, disabled, readOnly, currentTime, pickerId, mergedLabels]
1436
1586
  );
1437
1587
  return /* @__PURE__ */ jsxRuntime.jsx(TimePickerContext.Provider, { value: contextValue, children });
1438
1588
  }
@@ -1686,6 +1836,8 @@ function DateTimePickerRoot({
1686
1836
  value: controlledValue,
1687
1837
  defaultValue,
1688
1838
  onChange,
1839
+ onOpenChange,
1840
+ onCalendarNavigate,
1689
1841
  format = "24h",
1690
1842
  step = 1,
1691
1843
  disabled = false,
@@ -1693,6 +1845,7 @@ function DateTimePickerRoot({
1693
1845
  weekStartsOn = 0,
1694
1846
  displayFormat = "yyyy-MM-dd HH:mm",
1695
1847
  locale = "en-US",
1848
+ displayTimezone,
1696
1849
  adapter = core.DateFnsAdapter,
1697
1850
  labels: labelsProp,
1698
1851
  children
@@ -1714,18 +1867,24 @@ function DateTimePickerRoot({
1714
1867
  const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
1715
1868
  const [isOpen, setIsOpen] = react.useState(false);
1716
1869
  const [viewMonth, setViewMonth] = react.useState(
1717
- currentValue ?? adapter.today()
1870
+ currentValue ?? adapter.today(displayTimezone)
1718
1871
  );
1719
1872
  const [focusedDate, setFocusedDate] = react.useState(
1720
- currentValue ?? adapter.today()
1873
+ currentValue ?? adapter.today(displayTimezone)
1721
1874
  );
1875
+ useChangeEffect(isOpen, onOpenChange);
1876
+ const viewMonthStart = react.useMemo(() => adapter.startOfMonth(viewMonth), [viewMonth, adapter]);
1877
+ useChangeEffect(viewMonthStart, onCalendarNavigate);
1722
1878
  const isDisabled = typeof disabled === "boolean" ? disabled : false;
1723
1879
  const disabledRules = react.useMemo(
1724
1880
  () => Array.isArray(disabled) ? disabled : [],
1725
1881
  [disabled]
1726
1882
  );
1727
1883
  const baseIso = currentValue ?? getDefaultIso2();
1728
- const currentTime = react.useMemo(() => core.getTime(baseIso), [baseIso]);
1884
+ const currentTime = react.useMemo(
1885
+ () => displayTimezone ? core.getTimeInTimezone(baseIso, displayTimezone) : core.getTime(baseIso),
1886
+ [baseIso, displayTimezone]
1887
+ );
1729
1888
  const updateValue = react.useCallback(
1730
1889
  (next) => {
1731
1890
  if (isDisabled || readOnly) return;
@@ -1742,27 +1901,28 @@ function DateTimePickerRoot({
1742
1901
  updateValue(null);
1743
1902
  return;
1744
1903
  }
1745
- const time = currentValue ? core.getTime(currentValue) : currentTime;
1746
- const merged = core.setTime(newDateIso, time);
1904
+ const normalizedDate = displayTimezone ? core.civilMidnightFromUtcDay(newDateIso, displayTimezone) : newDateIso;
1905
+ const time = currentValue ? displayTimezone ? core.getTimeInTimezone(currentValue, displayTimezone) : core.getTime(currentValue) : currentTime;
1906
+ const merged = displayTimezone ? core.setTimeInTimezone(normalizedDate, time, displayTimezone) : core.setTime(normalizedDate, time);
1747
1907
  updateValue(merged);
1748
1908
  },
1749
- [currentValue, currentTime, updateValue]
1909
+ [currentValue, currentTime, updateValue, displayTimezone]
1750
1910
  );
1751
1911
  const setTime = react.useCallback(
1752
1912
  (partial) => {
1753
1913
  const base = currentValue ?? getDefaultIso2();
1754
- const merged = core.setTime(base, partial);
1914
+ const merged = displayTimezone ? core.setTimeInTimezone(base, partial, displayTimezone) : core.setTime(base, partial);
1755
1915
  updateValue(merged);
1756
1916
  },
1757
- [currentValue, updateValue]
1917
+ [currentValue, updateValue, displayTimezone]
1758
1918
  );
1759
1919
  const open = react.useCallback(() => {
1760
1920
  if (isDisabled || readOnly) return;
1761
1921
  setIsOpen(true);
1762
- const target = currentValue ?? adapter.today();
1922
+ const target = currentValue ?? adapter.today(displayTimezone);
1763
1923
  setViewMonth(target);
1764
1924
  setFocusedDate(target);
1765
- }, [isDisabled, readOnly, currentValue, adapter]);
1925
+ }, [isDisabled, readOnly, currentValue, adapter, displayTimezone]);
1766
1926
  const close = react.useCallback(() => {
1767
1927
  setIsOpen(false);
1768
1928
  }, []);
@@ -1788,6 +1948,7 @@ function DateTimePickerRoot({
1788
1948
  weekStartsOn,
1789
1949
  displayFormat,
1790
1950
  locale,
1951
+ displayTimezone,
1791
1952
  isDisabled,
1792
1953
  isReadOnly: readOnly,
1793
1954
  pickerId,
@@ -1807,6 +1968,7 @@ function DateTimePickerRoot({
1807
1968
  weekStartsOn,
1808
1969
  displayFormat,
1809
1970
  locale,
1971
+ displayTimezone,
1810
1972
  isDisabled,
1811
1973
  readOnly,
1812
1974
  pickerId,
@@ -1820,13 +1982,14 @@ function DateTimePickerRoot({
1820
1982
  format,
1821
1983
  step,
1822
1984
  withSeconds: false,
1985
+ displayTimezone,
1823
1986
  isDisabled,
1824
1987
  isReadOnly: readOnly,
1825
1988
  currentTime,
1826
1989
  pickerId,
1827
1990
  labels: mergedTimeLabels
1828
1991
  }),
1829
- [currentValue, setTime, format, step, isDisabled, readOnly, currentTime, pickerId, mergedTimeLabels]
1992
+ [currentValue, setTime, format, step, displayTimezone, isDisabled, readOnly, currentTime, pickerId, mergedTimeLabels]
1830
1993
  );
1831
1994
  return /* @__PURE__ */ jsxRuntime.jsx(DatePickerContext.Provider, { value: dateContext, children: /* @__PURE__ */ jsxRuntime.jsx(TimePickerContext.Provider, { value: timeContext, children }) });
1832
1995
  }
@@ -1836,7 +1999,9 @@ var DateTimePickerInput = react.forwardRef(
1836
1999
  let displayValue = "";
1837
2000
  if (ctx.value) {
1838
2001
  try {
1839
- displayValue = `${ctx.adapter.format(ctx.value, "yyyy-MM-dd")} ${core.formatTimeString(core.getTime(ctx.value))}`;
2002
+ const datePart = ctx.adapter.format(ctx.value, "yyyy-MM-dd", ctx.displayTimezone);
2003
+ const time = ctx.displayTimezone ? core.getTimeInTimezone(ctx.value, ctx.displayTimezone) : core.getTime(ctx.value);
2004
+ displayValue = `${datePart} ${core.formatTimeString(time)}`;
1840
2005
  } catch {
1841
2006
  displayValue = ctx.value;
1842
2007
  }
@@ -1899,6 +2064,249 @@ var DateTimePicker = Object.assign(DateTimePickerRoot, {
1899
2064
  MinuteList: TimePickerMinuteList,
1900
2065
  AmPmToggle: TimePickerAmPmToggle
1901
2066
  });
2067
+ function MonthPickerRoot(props) {
2068
+ const displayFormat = props.displayFormat ?? "yyyy-MM";
2069
+ return /* @__PURE__ */ jsxRuntime.jsx(DatePickerRoot, { ...props, displayFormat });
2070
+ }
2071
+ function MonthPickerGrid({
2072
+ classNames,
2073
+ ...props
2074
+ }) {
2075
+ const ctx = useDatePickerContext("MonthPicker.Grid");
2076
+ const { adapter, viewMonth, locale, value, displayTimezone, labels } = ctx;
2077
+ const currentYear = adapter.getYear(viewMonth);
2078
+ const [valueYear, valueMonthZeroBased] = react.useMemo(() => {
2079
+ if (!value) return [null, null];
2080
+ try {
2081
+ const [y, m] = adapter.format(value, "yyyy-MM", displayTimezone).split("-").map(Number);
2082
+ return [y, m - 1];
2083
+ } catch {
2084
+ return [null, null];
2085
+ }
2086
+ }, [value, adapter, displayTimezone]);
2087
+ const today = adapter.today(displayTimezone);
2088
+ const todayYear = adapter.getYear(today);
2089
+ const todayMonth = adapter.getMonth(today);
2090
+ const navigateYear = react.useCallback(
2091
+ (direction) => {
2092
+ ctx.setViewMonth(adapter.addYears(viewMonth, direction));
2093
+ },
2094
+ [adapter, viewMonth, ctx]
2095
+ );
2096
+ const handleMonthSelect = react.useCallback(
2097
+ (monthIndex) => {
2098
+ const target = new Date(
2099
+ Date.UTC(currentYear, monthIndex, 1)
2100
+ ).toISOString();
2101
+ ctx.selectDate(target);
2102
+ },
2103
+ [currentYear, ctx]
2104
+ );
2105
+ const months = Array.from({ length: 12 }, (_, i) => ({
2106
+ index: i,
2107
+ name: core.getMonthName(i, locale),
2108
+ isSelected: valueYear === currentYear && valueMonthZeroBased === i,
2109
+ isCurrent: todayYear === currentYear && todayMonth === i
2110
+ }));
2111
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.root, ...props, children: [
2112
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.header, children: [
2113
+ /* @__PURE__ */ jsxRuntime.jsx(
2114
+ "button",
2115
+ {
2116
+ type: "button",
2117
+ className: classNames?.navButton,
2118
+ onClick: () => navigateYear(-1),
2119
+ "aria-label": labels.prevYear,
2120
+ children: "<"
2121
+ }
2122
+ ),
2123
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: classNames?.title, children: currentYear }),
2124
+ /* @__PURE__ */ jsxRuntime.jsx(
2125
+ "button",
2126
+ {
2127
+ type: "button",
2128
+ className: classNames?.navButton,
2129
+ onClick: () => navigateYear(1),
2130
+ "aria-label": labels.nextYear,
2131
+ children: ">"
2132
+ }
2133
+ )
2134
+ ] }),
2135
+ /* @__PURE__ */ jsxRuntime.jsx(
2136
+ "div",
2137
+ {
2138
+ role: "grid",
2139
+ "aria-label": `${currentYear} months`,
2140
+ className: classNames?.grid,
2141
+ children: Array.from({ length: 4 }, (_, rowIndex) => /* @__PURE__ */ jsxRuntime.jsx(
2142
+ "div",
2143
+ {
2144
+ role: "row",
2145
+ className: classNames?.gridRow,
2146
+ style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)" },
2147
+ children: months.slice(rowIndex * 3, rowIndex * 3 + 3).map((m) => {
2148
+ const monthClass = [
2149
+ classNames?.month,
2150
+ m.isSelected && classNames?.monthSelected,
2151
+ m.isCurrent && classNames?.monthCurrent
2152
+ ].filter(Boolean).join(" ") || void 0;
2153
+ return /* @__PURE__ */ jsxRuntime.jsx(
2154
+ "button",
2155
+ {
2156
+ type: "button",
2157
+ role: "gridcell",
2158
+ "aria-selected": m.isSelected || void 0,
2159
+ "aria-current": m.isCurrent ? "date" : void 0,
2160
+ "data-selected": m.isSelected || void 0,
2161
+ "data-current": m.isCurrent || void 0,
2162
+ className: monthClass,
2163
+ onClick: () => handleMonthSelect(m.index),
2164
+ children: m.name
2165
+ },
2166
+ m.index
2167
+ );
2168
+ })
2169
+ },
2170
+ rowIndex
2171
+ ))
2172
+ }
2173
+ )
2174
+ ] });
2175
+ }
2176
+
2177
+ // src/components/MonthPicker/index.ts
2178
+ var MonthPicker = Object.assign(MonthPickerRoot, {
2179
+ Input: DatePickerInput,
2180
+ Trigger: DatePickerTrigger,
2181
+ Popover: DatePickerPopover,
2182
+ Grid: MonthPickerGrid
2183
+ });
2184
+ function YearPickerRoot(props) {
2185
+ const displayFormat = props.displayFormat ?? "yyyy";
2186
+ return /* @__PURE__ */ jsxRuntime.jsx(DatePickerRoot, { ...props, displayFormat });
2187
+ }
2188
+ function YearPickerGrid({ classNames, ...props }) {
2189
+ const ctx = useDatePickerContext("YearPicker.Grid");
2190
+ const { adapter, viewMonth, value, displayTimezone, labels } = ctx;
2191
+ const currentYear = adapter.getYear(viewMonth);
2192
+ const decadeStart = currentYear - currentYear % 12;
2193
+ const valueYear = react.useMemo(() => {
2194
+ if (!value) return null;
2195
+ try {
2196
+ return Number(adapter.format(value, "yyyy", displayTimezone));
2197
+ } catch {
2198
+ return null;
2199
+ }
2200
+ }, [value, adapter, displayTimezone]);
2201
+ const todayYear = adapter.getYear(adapter.today(displayTimezone));
2202
+ const navigateDecade = react.useCallback(
2203
+ (direction) => {
2204
+ ctx.setViewMonth(adapter.addYears(viewMonth, direction * 12));
2205
+ },
2206
+ [adapter, viewMonth, ctx]
2207
+ );
2208
+ const handleYearSelect = react.useCallback(
2209
+ (year) => {
2210
+ const target = new Date(Date.UTC(year, 0, 1)).toISOString();
2211
+ ctx.selectDate(target);
2212
+ },
2213
+ [ctx]
2214
+ );
2215
+ const years = Array.from({ length: 12 }, (_, i) => {
2216
+ const year = decadeStart + i;
2217
+ return {
2218
+ value: year,
2219
+ isSelected: year === valueYear,
2220
+ isCurrent: year === todayYear
2221
+ };
2222
+ });
2223
+ const rangeLabel = `${decadeStart}\u2013${decadeStart + 11}`;
2224
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.root, ...props, children: [
2225
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.header, children: [
2226
+ /* @__PURE__ */ jsxRuntime.jsx(
2227
+ "button",
2228
+ {
2229
+ type: "button",
2230
+ className: classNames?.navButton,
2231
+ onClick: () => navigateDecade(-1),
2232
+ "aria-label": labels.prevDecade,
2233
+ children: "<"
2234
+ }
2235
+ ),
2236
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: classNames?.title, children: rangeLabel }),
2237
+ /* @__PURE__ */ jsxRuntime.jsx(
2238
+ "button",
2239
+ {
2240
+ type: "button",
2241
+ className: classNames?.navButton,
2242
+ onClick: () => navigateDecade(1),
2243
+ "aria-label": labels.nextDecade,
2244
+ children: ">"
2245
+ }
2246
+ )
2247
+ ] }),
2248
+ /* @__PURE__ */ jsxRuntime.jsx(
2249
+ "div",
2250
+ {
2251
+ role: "grid",
2252
+ "aria-label": rangeLabel,
2253
+ className: classNames?.grid,
2254
+ children: Array.from({ length: 4 }, (_, rowIndex) => /* @__PURE__ */ jsxRuntime.jsx(
2255
+ "div",
2256
+ {
2257
+ role: "row",
2258
+ className: classNames?.gridRow,
2259
+ style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)" },
2260
+ children: years.slice(rowIndex * 3, rowIndex * 3 + 3).map((y) => {
2261
+ const yearClass = [
2262
+ classNames?.year,
2263
+ y.isSelected && classNames?.yearSelected,
2264
+ y.isCurrent && classNames?.yearCurrent
2265
+ ].filter(Boolean).join(" ") || void 0;
2266
+ return /* @__PURE__ */ jsxRuntime.jsx(
2267
+ "button",
2268
+ {
2269
+ type: "button",
2270
+ role: "gridcell",
2271
+ "aria-selected": y.isSelected || void 0,
2272
+ "aria-current": y.isCurrent ? "date" : void 0,
2273
+ "data-selected": y.isSelected || void 0,
2274
+ "data-current": y.isCurrent || void 0,
2275
+ className: yearClass,
2276
+ onClick: () => handleYearSelect(y.value),
2277
+ children: y.value
2278
+ },
2279
+ y.value
2280
+ );
2281
+ })
2282
+ },
2283
+ rowIndex
2284
+ ))
2285
+ }
2286
+ )
2287
+ ] });
2288
+ }
2289
+
2290
+ // src/components/YearPicker/index.ts
2291
+ var YearPicker = Object.assign(YearPickerRoot, {
2292
+ Input: DatePickerInput,
2293
+ Trigger: DatePickerTrigger,
2294
+ Popover: DatePickerPopover,
2295
+ Grid: YearPickerGrid
2296
+ });
2297
+ function WeekPickerRoot(props) {
2298
+ return /* @__PURE__ */ jsxRuntime.jsx(RangePickerRoot, { ...props });
2299
+ }
2300
+ function WeekPickerCalendar(props) {
2301
+ return /* @__PURE__ */ jsxRuntime.jsx(RangePickerCalendar, { ...props, selectionMode: "week" });
2302
+ }
2303
+
2304
+ // src/components/WeekPicker/index.ts
2305
+ var WeekPicker = Object.assign(WeekPickerRoot, {
2306
+ Input: RangePickerInput,
2307
+ Popover: RangePickerPopover,
2308
+ Calendar: WeekPickerCalendar
2309
+ });
1902
2310
  function useDatePicker(options = {}) {
1903
2311
  const {
1904
2312
  value: controlledValue,
@@ -1906,7 +2314,8 @@ function useDatePicker(options = {}) {
1906
2314
  onChange,
1907
2315
  disabled = [],
1908
2316
  weekStartsOn = 0,
1909
- adapter = core.DateFnsAdapter
2317
+ adapter = core.DateFnsAdapter,
2318
+ displayTimezone
1910
2319
  } = options;
1911
2320
  const pickerId = react.useId();
1912
2321
  const isControlled = react.useRef(controlledValue !== void 0).current;
@@ -1915,24 +2324,29 @@ function useDatePicker(options = {}) {
1915
2324
  );
1916
2325
  const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
1917
2326
  const [isOpen, setIsOpen] = react.useState(false);
1918
- const [viewMonth, setViewMonth] = react.useState(currentValue ?? adapter.today());
1919
- const [focusedDate, setFocusedDate] = react.useState(currentValue ?? adapter.today());
2327
+ const [viewMonth, setViewMonth] = react.useState(
2328
+ currentValue ?? adapter.today(displayTimezone)
2329
+ );
2330
+ const [focusedDate, setFocusedDate] = react.useState(
2331
+ currentValue ?? adapter.today(displayTimezone)
2332
+ );
1920
2333
  const selectDate = react.useCallback(
1921
2334
  (iso) => {
2335
+ const normalized = iso && displayTimezone ? core.civilMidnightFromUtcDay(iso, displayTimezone) : iso;
1922
2336
  if (!isControlled) {
1923
- setUncontrolledValue(iso);
2337
+ setUncontrolledValue(normalized);
1924
2338
  }
1925
- onChange?.(iso);
2339
+ onChange?.(normalized);
1926
2340
  setIsOpen(false);
1927
2341
  },
1928
- [isControlled, onChange]
2342
+ [isControlled, onChange, displayTimezone]
1929
2343
  );
1930
2344
  const open = react.useCallback(() => {
1931
2345
  setIsOpen(true);
1932
- const target = currentValue ?? adapter.today();
2346
+ const target = currentValue ?? adapter.today(displayTimezone);
1933
2347
  setViewMonth(target);
1934
2348
  setFocusedDate(target);
1935
- }, [currentValue, adapter]);
2349
+ }, [currentValue, adapter, displayTimezone]);
1936
2350
  const close = react.useCallback(() => {
1937
2351
  setIsOpen(false);
1938
2352
  }, []);
@@ -1954,7 +2368,8 @@ function useDatePicker(options = {}) {
1954
2368
  weekStartsOn,
1955
2369
  selected: currentValue,
1956
2370
  focusedDate,
1957
- disabled
2371
+ disabled,
2372
+ timezone: displayTimezone
1958
2373
  });
1959
2374
  return {
1960
2375
  value: currentValue,
@@ -1982,7 +2397,8 @@ function useRangePicker(options = {}) {
1982
2397
  onChange,
1983
2398
  disabled = [],
1984
2399
  weekStartsOn = 0,
1985
- adapter = core.DateFnsAdapter
2400
+ adapter = core.DateFnsAdapter,
2401
+ displayTimezone
1986
2402
  } = options;
1987
2403
  const pickerId = react.useId();
1988
2404
  const isControlled = react.useRef(controlledValue !== void 0).current;
@@ -1994,10 +2410,10 @@ function useRangePicker(options = {}) {
1994
2410
  const [selectingTarget, setSelectingTarget] = react.useState("start");
1995
2411
  const [hoverDate, setHoverDate] = react.useState(null);
1996
2412
  const [viewMonth, setViewMonth] = react.useState(
1997
- currentValue.start ?? adapter.today()
2413
+ currentValue.start ?? adapter.today(displayTimezone)
1998
2414
  );
1999
2415
  const [focusedDate, setFocusedDate] = react.useState(
2000
- currentValue.start ?? adapter.today()
2416
+ currentValue.start ?? adapter.today(displayTimezone)
2001
2417
  );
2002
2418
  const setRange = react.useCallback(
2003
2419
  (range) => {
@@ -2010,35 +2426,36 @@ function useRangePicker(options = {}) {
2010
2426
  );
2011
2427
  const selectDate = react.useCallback(
2012
2428
  (iso) => {
2429
+ const normalized = displayTimezone ? core.civilMidnightFromUtcDay(iso, displayTimezone) : iso;
2013
2430
  if (selectingTarget === "start") {
2014
- setRange({ start: iso, end: null });
2431
+ setRange({ start: normalized, end: null });
2015
2432
  setSelectingTarget("end");
2016
2433
  setHoverDate(null);
2017
2434
  } else {
2018
2435
  const start = currentValue.start;
2019
2436
  if (!start) {
2020
- setRange({ start: iso, end: null });
2437
+ setRange({ start: normalized, end: null });
2021
2438
  setSelectingTarget("end");
2022
2439
  return;
2023
2440
  }
2024
- const newRange = adapter.isBefore(iso, start) ? { start: iso, end: start } : { start, end: iso };
2441
+ const newRange = adapter.isBefore(normalized, start) ? { start: normalized, end: start } : { start, end: normalized };
2025
2442
  setRange(newRange);
2026
2443
  setSelectingTarget("start");
2027
2444
  setHoverDate(null);
2028
2445
  setIsOpen(false);
2029
2446
  }
2030
2447
  },
2031
- [selectingTarget, currentValue.start, adapter, setRange]
2448
+ [selectingTarget, currentValue.start, adapter, setRange, displayTimezone]
2032
2449
  );
2033
2450
  const open = react.useCallback(() => {
2034
2451
  setIsOpen(true);
2035
- const target = currentValue.start ?? adapter.today();
2452
+ const target = currentValue.start ?? adapter.today(displayTimezone);
2036
2453
  setViewMonth(target);
2037
2454
  setFocusedDate(target);
2038
2455
  if (currentValue.start && currentValue.end) {
2039
2456
  setSelectingTarget("start");
2040
2457
  }
2041
- }, [currentValue, adapter]);
2458
+ }, [currentValue, adapter, displayTimezone]);
2042
2459
  const close = react.useCallback(() => {
2043
2460
  setIsOpen(false);
2044
2461
  setHoverDate(null);
@@ -2062,7 +2479,8 @@ function useRangePicker(options = {}) {
2062
2479
  focusedDate,
2063
2480
  disabled,
2064
2481
  range: currentValue,
2065
- rangeHover: hoverDate
2482
+ rangeHover: hoverDate,
2483
+ timezone: displayTimezone
2066
2484
  });
2067
2485
  return {
2068
2486
  value: currentValue,
@@ -2095,7 +2513,8 @@ function useTimePicker(options = {}) {
2095
2513
  defaultValue,
2096
2514
  onChange,
2097
2515
  format = "24h",
2098
- step = 1
2516
+ step = 1,
2517
+ displayTimezone
2099
2518
  } = options;
2100
2519
  const pickerId = react.useId();
2101
2520
  const isControlled = react.useRef(controlledValue !== void 0).current;
@@ -2104,16 +2523,19 @@ function useTimePicker(options = {}) {
2104
2523
  );
2105
2524
  const currentValue = isControlled ? controlledValue ?? null : uncontrolledValue;
2106
2525
  const baseIso = currentValue ?? getDefaultIso3();
2107
- const currentTime = react.useMemo(() => core.getTime(baseIso), [baseIso]);
2526
+ const currentTime = react.useMemo(
2527
+ () => displayTimezone ? core.getTimeInTimezone(baseIso, displayTimezone) : core.getTime(baseIso),
2528
+ [baseIso, displayTimezone]
2529
+ );
2108
2530
  const setTime = react.useCallback(
2109
2531
  (partial) => {
2110
- const newIso = core.setTime(baseIso, partial);
2532
+ const newIso = displayTimezone ? core.setTimeInTimezone(baseIso, partial, displayTimezone) : core.setTime(baseIso, partial);
2111
2533
  if (!isControlled) {
2112
2534
  setUncontrolledValue(newIso);
2113
2535
  }
2114
2536
  onChange?.(newIso);
2115
2537
  },
2116
- [baseIso, isControlled, onChange]
2538
+ [baseIso, isControlled, onChange, displayTimezone]
2117
2539
  );
2118
2540
  const period = format === "12h" ? core.to12Hour(currentTime.hours).period : null;
2119
2541
  const displayHour = format === "12h" ? core.to12Hour(currentTime.hours).hours12 : currentTime.hours;
@@ -2163,8 +2585,11 @@ Object.defineProperty(exports, "DateFnsAdapter", {
2163
2585
  });
2164
2586
  exports.DatePicker = DatePicker;
2165
2587
  exports.DateTimePicker = DateTimePicker;
2588
+ exports.MonthPicker = MonthPicker;
2166
2589
  exports.RangePicker = RangePicker;
2167
2590
  exports.TimePicker = TimePicker;
2591
+ exports.WeekPicker = WeekPicker;
2592
+ exports.YearPicker = YearPicker;
2168
2593
  exports.useDatePicker = useDatePicker;
2169
2594
  exports.useRangePicker = useRangePicker;
2170
2595
  exports.useTimePicker = useTimePicker;