@kalyx/react 1.0.0-rc.0 → 1.0.0-rc.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @kalyx/react
2
2
 
3
+ ## 1.0.0-rc.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 3afb15b: Fix popover styling regression that broke documentation live previews.
8
+ - `DatePicker.Popover` and `RangePicker.Popover` now merge user-provided `style` props _under_ Floating UI's positioning instead of being overwritten by it. Previously, passing `style={{...}}` to a Popover stripped away `position: absolute`, `top`, `left`, and `transform`, causing the popover to render as a static block at full container width.
9
+ - The popover is now hidden until Floating UI computes its position, eliminating an unpositioned first-frame flash on every open.
10
+ - The shared `usePopover` hook also wires the floating element's reference synchronously in the ref callback, so positioning is resolved before paint in most cases.
11
+
3
12
  ## 1.0.0-rc.0
4
13
 
5
14
  ### Major Changes
@@ -9,14 +18,12 @@
9
18
  Kalyx v1.0 declares the public API stable. This is a milestone release bundling the v0.5 surface additions (MonthPicker, YearPicker, WeekPicker, DatePicker.Presets, `onOpenChange`/`onCalendarNavigate` event callbacks) with an explicit commitment to semantic versioning going forward.
10
19
 
11
20
  ### What v1.0 commits to
12
-
13
21
  - **Public API surface** — exports from `@kalyx/react` and `@kalyx/core` listed in their `index.ts` files. Any breaking change requires a major bump.
14
22
  - **Compositional structure** — Root + subcomponent names (`DatePicker.Input`, `DatePicker.Calendar`, …) are stable. Removal or renaming requires a major bump.
15
23
  - **Value semantics** — ISO 8601 UTC strings for single dates, `DateRange` `{start, end}` for ranges. `displayTimezone` behavior (civil-midnight-in-tz for date selection) is stable.
16
24
  - **Accessibility contracts** — role/aria-\* attributes emitted by each component are stable.
17
25
 
18
26
  ### What v1.0 does NOT freeze
19
-
20
27
  - Internal implementation details (non-exported functions, component file layout).
21
28
  - CSS class name strings on elements — no classes are applied by default; only when a consumer passes them via `classNames` props.
22
29
  - Error message text.
@@ -39,9 +46,7 @@
39
46
  <DatePicker.Presets>
40
47
  <DatePicker.Preset value="today">Today</DatePicker.Preset>
41
48
  <DatePicker.Preset value="tomorrow">Tomorrow</DatePicker.Preset>
42
- <DatePicker.Preset date="2026-12-25T00:00:00.000Z">
43
- Christmas
44
- </DatePicker.Preset>
49
+ <DatePicker.Preset date="2026-12-25T00:00:00.000Z">Christmas</DatePicker.Preset>
45
50
  </DatePicker.Presets>
46
51
  <DatePicker.Calendar />
47
52
  </DatePicker.Popover>
@@ -53,7 +58,6 @@
53
58
  - `displayTimezone` is honored when resolving "today"-relative presets.
54
59
 
55
60
  - 56e1ce9: feat: add `onOpenChange` and `onCalendarNavigate` callbacks on `DatePicker`, `RangePicker`, and `DateTimePicker` Root components.
56
-
57
61
  - `onOpenChange(isOpen: boolean)` fires whenever the popover opens or closes (regardless of trigger — click, keyboard, outside click, selection).
58
62
  - `onCalendarNavigate(viewMonth: ISODateString)` fires when the calendar view moves to a different month. The emitted value is the first day of the newly-visible month in UTC.
59
63
 
@@ -139,7 +143,6 @@
139
143
  When set, the value stored via `onChange` is the **civil midnight of the selected day in the target timezone** (in UTC-ISO form), eliminating the classic "day off by one" bug that affects picker libraries bound to `new Date()`. Input formatting, calendar highlighting, and the time-of-day controls all follow the display timezone — including DST-aware offsets for zones like `America/New_York` and `Europe/London`.
140
144
 
141
145
  `DateFnsAdapter` now honors the `timezone` argument on `format`, `isSameDay`, `startOfDay`, and `today` (previously declared-but-ignored). Core also exposes new helpers:
142
-
143
146
  - `civilMidnightFromUtcDay(iso, tz)`
144
147
  - `getTimeInTimezone(iso, tz)`
145
148
  - `setTimeInTimezone(iso, partial, tz)`
@@ -157,7 +160,6 @@
157
160
  ### Minor Changes
158
161
 
159
162
  - 669391b: Improve code quality, performance, and stability
160
-
161
163
  - Enforce UTC timezone suffix in ISO regex
162
164
  - Extract shared usePopover and useListboxNavigation hooks
163
165
  - Add Intl.DateTimeFormat caching for locale/timezone utilities
@@ -196,7 +198,6 @@
196
198
  - e9bb9e8: Initial release of Kalyx — headless, SSR-safe React DatePicker library.
197
199
 
198
200
  Features:
199
-
200
201
  - DatePicker: single date selection with Calendar, Input, Trigger, Popover
201
202
  - RangePicker: date range selection with auto-swap and hover preview
202
203
  - TimePicker: 12h/24h mode, minute step, HourList/MinuteList/AmPmToggle
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  > The headless React DatePicker, finally complete. Zero CSS · SSR-safe · under 12 KB gzip.
4
4
 
5
5
  [![npm](https://img.shields.io/npm/v/@kalyx/react?color=5b4fe1)](https://www.npmjs.com/package/@kalyx/react)
6
- [![Bundle](https://img.shields.io/badge/gzip-9.2KB-brightgreen)](https://kalyx-docs.vercel.app/docs/api/react#bundle-size)
6
+ [![Bundle](https://img.shields.io/badge/gzip-11.36KB-brightgreen)](https://kalyx-docs.vercel.app/docs/api/react#bundle-size)
7
7
  [![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue)](https://www.typescriptlang.org/)
8
8
  [![License](https://img.shields.io/badge/license-MIT-green)](https://github.com/jiji-hoon96/kalyx/blob/main/LICENSE)
9
9
 
@@ -51,6 +51,9 @@ import {
51
51
  RangePicker, // date range + presets
52
52
  TimePicker, // hour + minute (+ seconds)
53
53
  DateTimePicker, // date + time combined
54
+ MonthPicker, // month-only selection
55
+ YearPicker, // year-only selection
56
+ WeekPicker, // full-week range selection
54
57
  useDatePicker, // hook for custom UIs
55
58
  useRangePicker,
56
59
  useTimePicker,
@@ -90,6 +93,8 @@ Full recipes: [Tailwind](https://kalyx-docs.vercel.app/docs/recipes/tailwind), [
90
93
  - [Quick Start](https://kalyx-docs.vercel.app/docs/getting-started/quick-start)
91
94
  - [Components](https://kalyx-docs.vercel.app/docs/components/datepicker)
92
95
  - [Hooks](https://kalyx-docs.vercel.app/docs/hooks/use-date-picker)
96
+ - [Testing](https://kalyx-docs.vercel.app/docs/recipes/testing)
97
+ - [Troubleshooting](https://kalyx-docs.vercel.app/docs/troubleshooting)
93
98
  - [Migration from react-datepicker / react-day-picker / React Aria](https://kalyx-docs.vercel.app/docs/migration)
94
99
 
95
100
  ## License
package/dist/index.cjs CHANGED
@@ -302,10 +302,15 @@ var DatePickerTrigger = react.forwardRef(
302
302
  );
303
303
  }
304
304
  );
305
- function usePopover({ isOpen, close, referenceRef, placement = "bottom-start" }) {
305
+ function usePopover({
306
+ isOpen,
307
+ close,
308
+ referenceRef,
309
+ placement = "bottom-start"
310
+ }) {
306
311
  const floatingRef = react.useRef(null);
307
312
  const previousFocusRef = react.useRef(null);
308
- const { refs, floatingStyles } = react$1.useFloating({
313
+ const { refs, floatingStyles, isPositioned } = react$1.useFloating({
309
314
  open: isOpen,
310
315
  placement,
311
316
  middleware: [react$1.offset(4), react$1.flip(), react$1.shift({ padding: 8 })],
@@ -355,21 +360,28 @@ function usePopover({ isOpen, close, referenceRef, placement = "bottom-start" })
355
360
  document.addEventListener("keydown", handleKeyDown);
356
361
  return () => document.removeEventListener("keydown", handleKeyDown);
357
362
  }, [isOpen, close]);
358
- const setFloatingRef = (node) => {
359
- floatingRef.current = node;
360
- refs.setFloating(node);
361
- };
362
- return { floatingStyles, setFloatingRef };
363
+ const setFloatingRef = react.useCallback(
364
+ (node) => {
365
+ floatingRef.current = node;
366
+ refs.setFloating(node);
367
+ if (node && referenceRef.current) {
368
+ refs.setReference(referenceRef.current);
369
+ }
370
+ },
371
+ [refs, referenceRef]
372
+ );
373
+ return { floatingStyles, setFloatingRef, isPositioned };
363
374
  }
364
375
  function DatePickerPopover({ children, ...props }) {
365
376
  const ctx = useDatePickerContext("DatePicker.Popover");
366
377
  const calendarId = `${ctx.pickerId}-calendar`;
367
- const { floatingStyles, setFloatingRef } = usePopover({
378
+ const { floatingStyles, setFloatingRef, isPositioned } = usePopover({
368
379
  isOpen: ctx.isOpen,
369
380
  close: ctx.close,
370
381
  referenceRef: ctx.referenceRef
371
382
  });
372
383
  if (!ctx.isOpen) return null;
384
+ const { style: userStyle, ...rest } = props;
373
385
  return /* @__PURE__ */ jsxRuntime.jsx(
374
386
  "div",
375
387
  {
@@ -378,8 +390,12 @@ function DatePickerPopover({ children, ...props }) {
378
390
  role: "dialog",
379
391
  "aria-label": ctx.labels.popoverLabel,
380
392
  "aria-modal": "false",
381
- style: floatingStyles,
382
- ...props,
393
+ ...rest,
394
+ style: {
395
+ ...userStyle,
396
+ ...floatingStyles,
397
+ visibility: isPositioned ? void 0 : "hidden"
398
+ },
383
399
  children
384
400
  }
385
401
  );
@@ -402,7 +418,11 @@ var srOnly = {
402
418
  whiteSpace: "nowrap",
403
419
  border: 0
404
420
  };
405
- function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
421
+ function DatePickerCalendar({
422
+ classNames,
423
+ onTitleClick,
424
+ ...props
425
+ }) {
406
426
  const ctx = useDatePickerContext("DatePicker.Calendar");
407
427
  const gridRef = react.useRef(null);
408
428
  const [announcement, setAnnouncement] = react.useState("");
@@ -420,9 +440,7 @@ function DatePickerCalendar({ classNames, onTitleClick, ...props }) {
420
440
  const title = core.formatMonthYear(year, month, locale);
421
441
  react.useEffect(() => {
422
442
  if (!ctx.isOpen || !gridRef.current) return;
423
- const focusedButton = gridRef.current.querySelector(
424
- '[data-focused="true"]'
425
- );
443
+ const focusedButton = gridRef.current.querySelector('[data-focused="true"]');
426
444
  focusedButton?.focus({ preventScroll: true });
427
445
  }, [focusedDate, ctx.isOpen]);
428
446
  const navigateMonth = react.useCallback(
@@ -645,15 +663,7 @@ function DatePickerMonthGrid({
645
663
  children: "<"
646
664
  }
647
665
  ),
648
- onTitleClick ? /* @__PURE__ */ jsxRuntime.jsx(
649
- "button",
650
- {
651
- type: "button",
652
- className: classNames?.title,
653
- onClick: onTitleClick,
654
- children: currentYear
655
- }
656
- ) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: classNames?.title, children: currentYear }),
666
+ onTitleClick ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: classNames?.title, onClick: onTitleClick, children: currentYear }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: classNames?.title, children: currentYear }),
657
667
  /* @__PURE__ */ jsxRuntime.jsx(
658
668
  "button",
659
669
  {
@@ -698,11 +708,7 @@ function DatePickerMonthGrid({
698
708
  )
699
709
  ] });
700
710
  }
701
- function DatePickerYearGrid({
702
- classNames,
703
- onSelect,
704
- ...props
705
- }) {
711
+ function DatePickerYearGrid({ classNames, onSelect, ...props }) {
706
712
  const ctx = useDatePickerContext("DatePicker.YearGrid");
707
713
  const { adapter, viewMonth } = ctx;
708
714
  const currentYear = adapter.getYear(viewMonth);
@@ -796,16 +802,7 @@ function DatePickerYearGrid({
796
802
  }
797
803
  function DatePickerPresets({ classNames, children, ...props }) {
798
804
  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
- );
805
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "group", "aria-label": ctx.labels.popoverLabel, className: classNames?.root, ...props, children });
809
806
  }
810
807
  function resolveDatePreset(key, today, adapter) {
811
808
  switch (key) {
@@ -859,11 +856,7 @@ function DatePickerPreset({
859
856
  if (directDate) {
860
857
  target = directDate;
861
858
  } else if (presetKey) {
862
- target = resolveDatePreset(
863
- presetKey,
864
- ctx.adapter.today(ctx.displayTimezone),
865
- ctx.adapter
866
- );
859
+ target = resolveDatePreset(presetKey, ctx.adapter.today(ctx.displayTimezone), ctx.adapter);
867
860
  } else {
868
861
  return false;
869
862
  }
@@ -1130,12 +1123,13 @@ var RangePickerInput = react.forwardRef(
1130
1123
  function RangePickerPopover({ children, ...props }) {
1131
1124
  const ctx = useRangePickerContext("RangePicker.Popover");
1132
1125
  const calendarId = `${ctx.pickerId}-calendar`;
1133
- const { floatingStyles, setFloatingRef } = usePopover({
1126
+ const { floatingStyles, setFloatingRef, isPositioned } = usePopover({
1134
1127
  isOpen: ctx.isOpen,
1135
1128
  close: ctx.close,
1136
1129
  referenceRef: ctx.referenceRef
1137
1130
  });
1138
1131
  if (!ctx.isOpen) return null;
1132
+ const { style: userStyle, ...rest } = props;
1139
1133
  return /* @__PURE__ */ jsxRuntime.jsx(
1140
1134
  "div",
1141
1135
  {
@@ -1144,8 +1138,12 @@ function RangePickerPopover({ children, ...props }) {
1144
1138
  role: "dialog",
1145
1139
  "aria-label": ctx.labels.popoverLabel,
1146
1140
  "aria-modal": "false",
1147
- style: floatingStyles,
1148
- ...props,
1141
+ ...rest,
1142
+ style: {
1143
+ ...userStyle,
1144
+ ...floatingStyles,
1145
+ visibility: isPositioned ? void 0 : "hidden"
1146
+ },
1149
1147
  children
1150
1148
  }
1151
1149
  );
@@ -1202,9 +1200,7 @@ function RangePickerCalendar({
1202
1200
  const title = core.formatMonthYear(year, month, locale);
1203
1201
  react.useEffect(() => {
1204
1202
  if (!ctx.isOpen || !gridRef.current) return;
1205
- const focusedButton = gridRef.current.querySelector(
1206
- '[data-focused="true"]'
1207
- );
1203
+ const focusedButton = gridRef.current.querySelector('[data-focused="true"]');
1208
1204
  focusedButton?.focus({ preventScroll: true });
1209
1205
  }, [focusedDate, ctx.isOpen]);
1210
1206
  const navigateMonth = react.useCallback(
@@ -1307,7 +1303,18 @@ function RangePickerCalendar({
1307
1303
  }
1308
1304
  }
1309
1305
  },
1310
- [adapter, focusedDate, viewMonth, weekStartsOn, disabled, ctx, selectionMode, selectingTarget, value.start, commitDay]
1306
+ [
1307
+ adapter,
1308
+ focusedDate,
1309
+ viewMonth,
1310
+ weekStartsOn,
1311
+ disabled,
1312
+ ctx,
1313
+ selectionMode,
1314
+ selectingTarget,
1315
+ value.start,
1316
+ commitDay
1317
+ ]
1311
1318
  );
1312
1319
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.root, ...props, onMouseLeave: handleMouseLeave, children: [
1313
1320
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.header, children: [
@@ -1444,9 +1451,7 @@ function resolvePreset(key, today, adapter) {
1444
1451
  }
1445
1452
  case "thisYear": {
1446
1453
  const currentMonth = new Date(today).getUTCMonth();
1447
- const yearStart = adapter.startOfMonth(
1448
- adapter.addMonths(today, -currentMonth)
1449
- );
1454
+ const yearStart = adapter.startOfMonth(adapter.addMonths(today, -currentMonth));
1450
1455
  return { start: yearStart, end: today };
1451
1456
  }
1452
1457
  }
@@ -1582,7 +1587,19 @@ function TimePickerRoot({
1582
1587
  pickerId,
1583
1588
  labels: mergedLabels
1584
1589
  }),
1585
- [currentValue, setTime, format, step, withSeconds, displayTimezone, disabled, readOnly, currentTime, pickerId, mergedLabels]
1590
+ [
1591
+ currentValue,
1592
+ setTime,
1593
+ format,
1594
+ step,
1595
+ withSeconds,
1596
+ displayTimezone,
1597
+ disabled,
1598
+ readOnly,
1599
+ currentTime,
1600
+ pickerId,
1601
+ mergedLabels
1602
+ ]
1586
1603
  );
1587
1604
  return /* @__PURE__ */ jsxRuntime.jsx(TimePickerContext.Provider, { value: contextValue, children });
1588
1605
  }
@@ -1599,12 +1616,9 @@ var TimePickerInput = react.forwardRef(
1599
1616
  }
1600
1617
  setInputText(null);
1601
1618
  }, [inputText, ctx]);
1602
- const handleChange = react.useCallback(
1603
- (e) => {
1604
- setInputText(e.target.value);
1605
- },
1606
- []
1607
- );
1619
+ const handleChange = react.useCallback((e) => {
1620
+ setInputText(e.target.value);
1621
+ }, []);
1608
1622
  const handleBlur = react.useCallback(
1609
1623
  (e) => {
1610
1624
  commitInput();
@@ -1677,9 +1691,7 @@ function useListboxNavigation({
1677
1691
  onSelect(target);
1678
1692
  cancelAnimationFrame(rafIdRef.current);
1679
1693
  rafIdRef.current = requestAnimationFrame(() => {
1680
- const next = listRef.current?.querySelector(
1681
- '[data-selected="true"]'
1682
- );
1694
+ const next = listRef.current?.querySelector('[data-selected="true"]');
1683
1695
  next?.focus();
1684
1696
  });
1685
1697
  }
@@ -1816,10 +1828,19 @@ function TimePickerAmPmToggle({ classNames, ...props }) {
1816
1828
  }
1817
1829
  );
1818
1830
  };
1819
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "radiogroup", "aria-label": ctx.labels.amPmToggle, className: classNames?.root, ...props, children: [
1820
- renderButton("AM"),
1821
- renderButton("PM")
1822
- ] });
1831
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1832
+ "div",
1833
+ {
1834
+ role: "radiogroup",
1835
+ "aria-label": ctx.labels.amPmToggle,
1836
+ className: classNames?.root,
1837
+ ...props,
1838
+ children: [
1839
+ renderButton("AM"),
1840
+ renderButton("PM")
1841
+ ]
1842
+ }
1843
+ );
1823
1844
  }
1824
1845
 
1825
1846
  // src/components/TimePicker/index.ts
@@ -1989,7 +2010,18 @@ function DateTimePickerRoot({
1989
2010
  pickerId,
1990
2011
  labels: mergedTimeLabels
1991
2012
  }),
1992
- [currentValue, setTime, format, step, displayTimezone, isDisabled, readOnly, currentTime, pickerId, mergedTimeLabels]
2013
+ [
2014
+ currentValue,
2015
+ setTime,
2016
+ format,
2017
+ step,
2018
+ displayTimezone,
2019
+ isDisabled,
2020
+ readOnly,
2021
+ currentTime,
2022
+ pickerId,
2023
+ mergedTimeLabels
2024
+ ]
1993
2025
  );
1994
2026
  return /* @__PURE__ */ jsxRuntime.jsx(DatePickerContext.Provider, { value: dateContext, children: /* @__PURE__ */ jsxRuntime.jsx(TimePickerContext.Provider, { value: timeContext, children }) });
1995
2027
  }
@@ -2068,10 +2100,7 @@ function MonthPickerRoot(props) {
2068
2100
  const displayFormat = props.displayFormat ?? "yyyy-MM";
2069
2101
  return /* @__PURE__ */ jsxRuntime.jsx(DatePickerRoot, { ...props, displayFormat });
2070
2102
  }
2071
- function MonthPickerGrid({
2072
- classNames,
2073
- ...props
2074
- }) {
2103
+ function MonthPickerGrid({ classNames, ...props }) {
2075
2104
  const ctx = useDatePickerContext("MonthPicker.Grid");
2076
2105
  const { adapter, viewMonth, locale, value, displayTimezone, labels } = ctx;
2077
2106
  const currentYear = adapter.getYear(viewMonth);
@@ -2095,9 +2124,7 @@ function MonthPickerGrid({
2095
2124
  );
2096
2125
  const handleMonthSelect = react.useCallback(
2097
2126
  (monthIndex) => {
2098
- const target = new Date(
2099
- Date.UTC(currentYear, monthIndex, 1)
2100
- ).toISOString();
2127
+ const target = new Date(Date.UTC(currentYear, monthIndex, 1)).toISOString();
2101
2128
  ctx.selectDate(target);
2102
2129
  },
2103
2130
  [currentYear, ctx]
@@ -2132,45 +2159,37 @@ function MonthPickerGrid({
2132
2159
  }
2133
2160
  )
2134
2161
  ] }),
2135
- /* @__PURE__ */ jsxRuntime.jsx(
2162
+ /* @__PURE__ */ jsxRuntime.jsx("div", { role: "grid", "aria-label": `${currentYear} months`, className: classNames?.grid, children: Array.from({ length: 4 }, (_, rowIndex) => /* @__PURE__ */ jsxRuntime.jsx(
2136
2163
  "div",
2137
2164
  {
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
- )
2165
+ role: "row",
2166
+ className: classNames?.gridRow,
2167
+ style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)" },
2168
+ children: months.slice(rowIndex * 3, rowIndex * 3 + 3).map((m) => {
2169
+ const monthClass = [
2170
+ classNames?.month,
2171
+ m.isSelected && classNames?.monthSelected,
2172
+ m.isCurrent && classNames?.monthCurrent
2173
+ ].filter(Boolean).join(" ") || void 0;
2174
+ return /* @__PURE__ */ jsxRuntime.jsx(
2175
+ "button",
2176
+ {
2177
+ type: "button",
2178
+ role: "gridcell",
2179
+ "aria-selected": m.isSelected || void 0,
2180
+ "aria-current": m.isCurrent ? "date" : void 0,
2181
+ "data-selected": m.isSelected || void 0,
2182
+ "data-current": m.isCurrent || void 0,
2183
+ className: monthClass,
2184
+ onClick: () => handleMonthSelect(m.index),
2185
+ children: m.name
2186
+ },
2187
+ m.index
2188
+ );
2189
+ })
2190
+ },
2191
+ rowIndex
2192
+ )) })
2174
2193
  ] });
2175
2194
  }
2176
2195
 
@@ -2245,45 +2264,37 @@ function YearPickerGrid({ classNames, ...props }) {
2245
2264
  }
2246
2265
  )
2247
2266
  ] }),
2248
- /* @__PURE__ */ jsxRuntime.jsx(
2267
+ /* @__PURE__ */ jsxRuntime.jsx("div", { role: "grid", "aria-label": rangeLabel, className: classNames?.grid, children: Array.from({ length: 4 }, (_, rowIndex) => /* @__PURE__ */ jsxRuntime.jsx(
2249
2268
  "div",
2250
2269
  {
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
- )
2270
+ role: "row",
2271
+ className: classNames?.gridRow,
2272
+ style: { display: "grid", gridTemplateColumns: "repeat(3, 1fr)" },
2273
+ children: years.slice(rowIndex * 3, rowIndex * 3 + 3).map((y) => {
2274
+ const yearClass = [
2275
+ classNames?.year,
2276
+ y.isSelected && classNames?.yearSelected,
2277
+ y.isCurrent && classNames?.yearCurrent
2278
+ ].filter(Boolean).join(" ") || void 0;
2279
+ return /* @__PURE__ */ jsxRuntime.jsx(
2280
+ "button",
2281
+ {
2282
+ type: "button",
2283
+ role: "gridcell",
2284
+ "aria-selected": y.isSelected || void 0,
2285
+ "aria-current": y.isCurrent ? "date" : void 0,
2286
+ "data-selected": y.isSelected || void 0,
2287
+ "data-current": y.isCurrent || void 0,
2288
+ className: yearClass,
2289
+ onClick: () => handleYearSelect(y.value),
2290
+ children: y.value
2291
+ },
2292
+ y.value
2293
+ );
2294
+ })
2295
+ },
2296
+ rowIndex
2297
+ )) })
2287
2298
  ] });
2288
2299
  }
2289
2300
 
@@ -2546,14 +2557,8 @@ function useTimePicker(options = {}) {
2546
2557
  },
2547
2558
  [format, period, setTime]
2548
2559
  );
2549
- const setMinute = react.useCallback(
2550
- (minute) => setTime({ minutes: minute }),
2551
- [setTime]
2552
- );
2553
- const setSecond = react.useCallback(
2554
- (second) => setTime({ seconds: second }),
2555
- [setTime]
2556
- );
2560
+ const setMinute = react.useCallback((minute) => setTime({ minutes: minute }), [setTime]);
2561
+ const setSecond = react.useCallback((second) => setTime({ seconds: second }), [setTime]);
2557
2562
  const setPeriod = react.useCallback(
2558
2563
  (newPeriod) => {
2559
2564
  if (format !== "12h") return;