@kalyx/react 1.0.0-rc.5 → 1.0.0-rc.7

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.d.cts CHANGED
@@ -82,13 +82,28 @@ interface DatePickerCalendarClassNames {
82
82
  dayDisabled?: string;
83
83
  dayOutsideMonth?: string;
84
84
  weekdayHeader?: string;
85
+ /** Header cell at the top of the week-number column. Rendered only when `showWeekNumber` is set. */
86
+ weekNumberHeader?: string;
87
+ /** Each row's week-number cell. Rendered only when `showWeekNumber` is set. */
88
+ weekNumber?: string;
85
89
  }
86
90
  interface DatePickerCalendarProps extends Omit<HTMLAttributes<HTMLDivElement>, 'role'> {
87
91
  classNames?: DatePickerCalendarClassNames;
88
92
  /** Called when the title ("January 2026") is clicked. Useful for switching to Month/Year views. */
89
93
  onTitleClick?: () => void;
94
+ /**
95
+ * Render an ISO 8601 week-number column on the left of the grid (1–53).
96
+ * The column is a `<th scope="row">`; it doesn't participate in the WAI-ARIA grid
97
+ * data region, so keyboard navigation across the date cells is unaffected.
98
+ */
99
+ showWeekNumber?: boolean;
100
+ /**
101
+ * Always render 6 weeks (42 cells), even when the month fits in 4 or 5 rows. Useful for
102
+ * popover layouts that need a fixed height across month navigation.
103
+ */
104
+ fixedWeeks?: boolean;
90
105
  }
91
- declare function DatePickerCalendar({ classNames, onTitleClick, ...props }: DatePickerCalendarProps): react_jsx_runtime.JSX.Element;
106
+ declare function DatePickerCalendar({ classNames, onTitleClick, showWeekNumber, fixedWeeks, ...props }: DatePickerCalendarProps): react_jsx_runtime.JSX.Element;
92
107
 
93
108
  interface DatePickerMonthGridClassNames {
94
109
  root?: string;
@@ -322,6 +337,10 @@ interface RangePickerCalendarClassNames {
322
337
  dayRangeEnd?: string;
323
338
  dayInRange?: string;
324
339
  weekdayHeader?: string;
340
+ /** Header cell at the top of the week-number column. Rendered only when `showWeekNumber` is set. */
341
+ weekNumberHeader?: string;
342
+ /** Each row's week-number cell. Rendered only when `showWeekNumber` is set. */
343
+ weekNumber?: string;
325
344
  }
326
345
  /**
327
346
  * Selection mode for the calendar grid.
@@ -333,8 +352,18 @@ interface RangePickerCalendarProps extends Omit<HTMLAttributes<HTMLDivElement>,
333
352
  classNames?: RangePickerCalendarClassNames;
334
353
  /** @default 'range' */
335
354
  selectionMode?: RangePickerCalendarSelectionMode;
355
+ /**
356
+ * Render an ISO 8601 week-number column on the left of the grid (1–53).
357
+ * The column is a `<th scope="row">`; it doesn't participate in the WAI-ARIA grid
358
+ * data region, so keyboard navigation across the date cells is unaffected.
359
+ */
360
+ showWeekNumber?: boolean;
361
+ /**
362
+ * Always render 6 weeks (42 cells), even when the month fits in 4 or 5 rows.
363
+ */
364
+ fixedWeeks?: boolean;
336
365
  }
337
- declare function RangePickerCalendar({ classNames, selectionMode, ...props }: RangePickerCalendarProps): react_jsx_runtime.JSX.Element;
366
+ declare function RangePickerCalendar({ classNames, selectionMode, showWeekNumber, fixedWeeks, ...props }: RangePickerCalendarProps): react_jsx_runtime.JSX.Element;
338
367
 
339
368
  /** Predefined preset keys. Custom ranges are also supported. */
340
369
  type PresetKey = 'today' | 'yesterday' | 'last7days' | 'last30days' | 'thisWeek' | 'lastWeek' | 'thisMonth' | 'lastMonth' | 'thisYear';
package/dist/index.d.ts CHANGED
@@ -82,13 +82,28 @@ interface DatePickerCalendarClassNames {
82
82
  dayDisabled?: string;
83
83
  dayOutsideMonth?: string;
84
84
  weekdayHeader?: string;
85
+ /** Header cell at the top of the week-number column. Rendered only when `showWeekNumber` is set. */
86
+ weekNumberHeader?: string;
87
+ /** Each row's week-number cell. Rendered only when `showWeekNumber` is set. */
88
+ weekNumber?: string;
85
89
  }
86
90
  interface DatePickerCalendarProps extends Omit<HTMLAttributes<HTMLDivElement>, 'role'> {
87
91
  classNames?: DatePickerCalendarClassNames;
88
92
  /** Called when the title ("January 2026") is clicked. Useful for switching to Month/Year views. */
89
93
  onTitleClick?: () => void;
94
+ /**
95
+ * Render an ISO 8601 week-number column on the left of the grid (1–53).
96
+ * The column is a `<th scope="row">`; it doesn't participate in the WAI-ARIA grid
97
+ * data region, so keyboard navigation across the date cells is unaffected.
98
+ */
99
+ showWeekNumber?: boolean;
100
+ /**
101
+ * Always render 6 weeks (42 cells), even when the month fits in 4 or 5 rows. Useful for
102
+ * popover layouts that need a fixed height across month navigation.
103
+ */
104
+ fixedWeeks?: boolean;
90
105
  }
91
- declare function DatePickerCalendar({ classNames, onTitleClick, ...props }: DatePickerCalendarProps): react_jsx_runtime.JSX.Element;
106
+ declare function DatePickerCalendar({ classNames, onTitleClick, showWeekNumber, fixedWeeks, ...props }: DatePickerCalendarProps): react_jsx_runtime.JSX.Element;
92
107
 
93
108
  interface DatePickerMonthGridClassNames {
94
109
  root?: string;
@@ -322,6 +337,10 @@ interface RangePickerCalendarClassNames {
322
337
  dayRangeEnd?: string;
323
338
  dayInRange?: string;
324
339
  weekdayHeader?: string;
340
+ /** Header cell at the top of the week-number column. Rendered only when `showWeekNumber` is set. */
341
+ weekNumberHeader?: string;
342
+ /** Each row's week-number cell. Rendered only when `showWeekNumber` is set. */
343
+ weekNumber?: string;
325
344
  }
326
345
  /**
327
346
  * Selection mode for the calendar grid.
@@ -333,8 +352,18 @@ interface RangePickerCalendarProps extends Omit<HTMLAttributes<HTMLDivElement>,
333
352
  classNames?: RangePickerCalendarClassNames;
334
353
  /** @default 'range' */
335
354
  selectionMode?: RangePickerCalendarSelectionMode;
355
+ /**
356
+ * Render an ISO 8601 week-number column on the left of the grid (1–53).
357
+ * The column is a `<th scope="row">`; it doesn't participate in the WAI-ARIA grid
358
+ * data region, so keyboard navigation across the date cells is unaffected.
359
+ */
360
+ showWeekNumber?: boolean;
361
+ /**
362
+ * Always render 6 weeks (42 cells), even when the month fits in 4 or 5 rows.
363
+ */
364
+ fixedWeeks?: boolean;
336
365
  }
337
- declare function RangePickerCalendar({ classNames, selectionMode, ...props }: RangePickerCalendarProps): react_jsx_runtime.JSX.Element;
366
+ declare function RangePickerCalendar({ classNames, selectionMode, showWeekNumber, fixedWeeks, ...props }: RangePickerCalendarProps): react_jsx_runtime.JSX.Element;
338
367
 
339
368
  /** Predefined preset keys. Custom ranges are also supported. */
340
369
  type PresetKey = 'today' | 'yesterday' | 'last7days' | 'last30days' | 'thisWeek' | 'lastWeek' | 'thisMonth' | 'lastMonth' | 'thisYear';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { createContext, forwardRef, useState, useRef, useCallback, useContext, useId, useMemo, useEffect } from 'react';
3
- import { parseInputValue, formatTimeString, parseTimeString, getTimeInTimezone, getTime, DateFnsAdapter, DEFAULT_DATEPICKER_LABELS, civilMidnightFromUtcDay, getMonthName, getWeekdayNames, getCalendarDays, formatMonthYear, isDateDisabled, DEFAULT_RANGEPICKER_LABELS, DEFAULT_TIMEPICKER_LABELS, setTimeInTimezone, setTime, to12Hour, to24Hour, generateMinutes, generateHours, formatFullDate } from '@kalyx/core';
3
+ import { parseInputValue, formatTimeString, parseTimeString, getTimeInTimezone, getTime, DateFnsAdapter, DEFAULT_DATEPICKER_LABELS, civilMidnightFromUtcDay, getMonthName, getWeekdayNames, getCalendarDays, formatMonthYear, isDateDisabled, getISOWeekNumber, DEFAULT_RANGEPICKER_LABELS, DEFAULT_TIMEPICKER_LABELS, setTimeInTimezone, setTime, to12Hour, to24Hour, generateMinutes, generateHours, formatFullDate } from '@kalyx/core';
4
4
  export { DateFnsAdapter } from '@kalyx/core';
5
5
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
6
6
  import { offset, flip, shift, useFloating, autoUpdate } from '@floating-ui/react';
@@ -464,6 +464,8 @@ var srOnly = {
464
464
  function DatePickerCalendar({
465
465
  classNames,
466
466
  onTitleClick,
467
+ showWeekNumber = false,
468
+ fixedWeeks = false,
467
469
  ...props
468
470
  }) {
469
471
  const ctx = useDatePickerContext("DatePicker.Calendar");
@@ -477,10 +479,21 @@ function DatePickerCalendar({
477
479
  selected: ctx.value,
478
480
  focusedDate,
479
481
  disabled,
480
- timezone: displayTimezone
482
+ timezone: displayTimezone,
483
+ fixedWeeks
481
484
  }),
482
- [viewMonth, adapter, weekStartsOn, ctx.value, focusedDate, disabled, displayTimezone]
485
+ [
486
+ viewMonth,
487
+ adapter,
488
+ weekStartsOn,
489
+ ctx.value,
490
+ focusedDate,
491
+ disabled,
492
+ displayTimezone,
493
+ fixedWeeks
494
+ ]
483
495
  );
496
+ const thursdayIndex = weekStartsOn === 0 ? 4 : 3;
484
497
  const year = adapter.getYear(viewMonth);
485
498
  const month = adapter.getMonth(viewMonth);
486
499
  const title = formatMonthYear(year, month, locale);
@@ -621,61 +634,76 @@ function DatePickerCalendar({
621
634
  className: classNames?.grid,
622
635
  onKeyDown: handleKeyDown,
623
636
  children: [
624
- /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { role: "row", "aria-rowindex": 1, children: weekdays.map((day, colIndex) => /* @__PURE__ */ jsx(
625
- "th",
626
- {
627
- role: "columnheader",
628
- abbr: day.full,
629
- scope: "col",
630
- "aria-colindex": colIndex + 1,
631
- className: classNames?.weekdayHeader,
632
- children: day.short
633
- },
634
- day.short
635
- )) }) }),
636
- /* @__PURE__ */ jsx("tbody", { children: weeks.map((week, weekIndex) => /* @__PURE__ */ jsx(
637
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { role: "row", "aria-rowindex": 1, children: [
638
+ showWeekNumber ? /* @__PURE__ */ jsx("th", { scope: "col", "aria-hidden": "true", className: classNames?.weekNumberHeader, children: "#" }) : null,
639
+ weekdays.map((day, colIndex) => /* @__PURE__ */ jsx(
640
+ "th",
641
+ {
642
+ role: "columnheader",
643
+ abbr: day.full,
644
+ scope: "col",
645
+ "aria-colindex": colIndex + 1,
646
+ className: classNames?.weekdayHeader,
647
+ children: day.short
648
+ },
649
+ day.short
650
+ ))
651
+ ] }) }),
652
+ /* @__PURE__ */ jsx("tbody", { children: weeks.map((week, weekIndex) => /* @__PURE__ */ jsxs(
637
653
  "tr",
638
654
  {
639
655
  role: "row",
640
656
  "aria-rowindex": weekIndex + 2,
641
657
  className: classNames?.gridRow,
642
- children: week.map((day, colIndex) => {
643
- const dayClasses = [
644
- classNames?.day,
645
- day.isSelected && classNames?.daySelected,
646
- day.isToday && classNames?.dayToday,
647
- day.isDisabled && classNames?.dayDisabled,
648
- !day.isCurrentMonth && classNames?.dayOutsideMonth
649
- ].filter(Boolean).join(" ") || void 0;
650
- return /* @__PURE__ */ jsx(
651
- "td",
658
+ children: [
659
+ showWeekNumber ? /* @__PURE__ */ jsx(
660
+ "th",
652
661
  {
653
- role: "gridcell",
654
- "aria-colindex": colIndex + 1,
655
- "aria-selected": day.isSelected || void 0,
656
- "aria-disabled": day.isDisabled || void 0,
657
- "aria-current": day.isToday ? "date" : void 0,
658
- className: classNames?.gridCell,
659
- children: /* @__PURE__ */ jsx(
660
- "button",
661
- {
662
- type: "button",
663
- tabIndex: day.isFocused ? 0 : -1,
664
- disabled: day.isDisabled,
665
- "data-focused": day.isFocused || void 0,
666
- "data-selected": day.isSelected || void 0,
667
- "data-today": day.isToday || void 0,
668
- "data-outside-month": !day.isCurrentMonth || void 0,
669
- className: dayClasses,
670
- onClick: () => handleDayClick(day),
671
- "aria-label": safeFormatFullDate(day.isoString, locale),
672
- children: day.dayNumber
673
- }
674
- )
675
- },
676
- day.isoString
677
- );
678
- })
662
+ scope: "row",
663
+ "aria-hidden": "true",
664
+ className: classNames?.weekNumber,
665
+ "data-week-number": true,
666
+ children: getISOWeekNumber(week[thursdayIndex].isoString)
667
+ }
668
+ ) : null,
669
+ week.map((day, colIndex) => {
670
+ const dayClasses = [
671
+ classNames?.day,
672
+ day.isSelected && classNames?.daySelected,
673
+ day.isToday && classNames?.dayToday,
674
+ day.isDisabled && classNames?.dayDisabled,
675
+ !day.isCurrentMonth && classNames?.dayOutsideMonth
676
+ ].filter(Boolean).join(" ") || void 0;
677
+ return /* @__PURE__ */ jsx(
678
+ "td",
679
+ {
680
+ role: "gridcell",
681
+ "aria-colindex": colIndex + 1,
682
+ "aria-selected": day.isSelected || void 0,
683
+ "aria-disabled": day.isDisabled || void 0,
684
+ "aria-current": day.isToday ? "date" : void 0,
685
+ className: classNames?.gridCell,
686
+ children: /* @__PURE__ */ jsx(
687
+ "button",
688
+ {
689
+ type: "button",
690
+ tabIndex: day.isFocused ? 0 : -1,
691
+ disabled: day.isDisabled,
692
+ "data-focused": day.isFocused || void 0,
693
+ "data-selected": day.isSelected || void 0,
694
+ "data-today": day.isToday || void 0,
695
+ "data-outside-month": !day.isCurrentMonth || void 0,
696
+ className: dayClasses,
697
+ onClick: () => handleDayClick(day),
698
+ "aria-label": safeFormatFullDate(day.isoString, locale),
699
+ children: day.dayNumber
700
+ }
701
+ )
702
+ },
703
+ day.isoString
704
+ );
705
+ })
706
+ ]
679
707
  },
680
708
  weekIndex
681
709
  )) })
@@ -1338,6 +1366,8 @@ var srOnly2 = {
1338
1366
  function RangePickerCalendar({
1339
1367
  classNames,
1340
1368
  selectionMode = "range",
1369
+ showWeekNumber = false,
1370
+ fixedWeeks = false,
1341
1371
  ...props
1342
1372
  }) {
1343
1373
  const ctx = useRangePickerContext("RangePicker.Calendar");
@@ -1363,10 +1393,22 @@ function RangePickerCalendar({
1363
1393
  disabled,
1364
1394
  range: value,
1365
1395
  rangeHover: hoverDate,
1366
- timezone: displayTimezone
1396
+ timezone: displayTimezone,
1397
+ fixedWeeks
1367
1398
  }),
1368
- [viewMonth, adapter, weekStartsOn, focusedDate, disabled, value, hoverDate, displayTimezone]
1399
+ [
1400
+ viewMonth,
1401
+ adapter,
1402
+ weekStartsOn,
1403
+ focusedDate,
1404
+ disabled,
1405
+ value,
1406
+ hoverDate,
1407
+ displayTimezone,
1408
+ fixedWeeks
1409
+ ]
1369
1410
  );
1411
+ const thursdayIndex = weekStartsOn === 0 ? 4 : 3;
1370
1412
  const year = adapter.getYear(viewMonth);
1371
1413
  const month = adapter.getMonth(viewMonth);
1372
1414
  const title = formatMonthYear(year, month, locale);
@@ -1530,67 +1572,82 @@ function RangePickerCalendar({
1530
1572
  className: classNames?.grid,
1531
1573
  onKeyDown: handleKeyDown,
1532
1574
  children: [
1533
- /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { role: "row", "aria-rowindex": 1, children: weekdays.map((day, colIndex) => /* @__PURE__ */ jsx(
1534
- "th",
1535
- {
1536
- role: "columnheader",
1537
- abbr: day.full,
1538
- scope: "col",
1539
- "aria-colindex": colIndex + 1,
1540
- className: classNames?.weekdayHeader,
1541
- children: day.short
1542
- },
1543
- day.short
1544
- )) }) }),
1545
- /* @__PURE__ */ jsx("tbody", { children: weeks.map((week, weekIndex) => /* @__PURE__ */ jsx(
1575
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { role: "row", "aria-rowindex": 1, children: [
1576
+ showWeekNumber ? /* @__PURE__ */ jsx("th", { scope: "col", "aria-hidden": "true", className: classNames?.weekNumberHeader, children: "#" }) : null,
1577
+ weekdays.map((day, colIndex) => /* @__PURE__ */ jsx(
1578
+ "th",
1579
+ {
1580
+ role: "columnheader",
1581
+ abbr: day.full,
1582
+ scope: "col",
1583
+ "aria-colindex": colIndex + 1,
1584
+ className: classNames?.weekdayHeader,
1585
+ children: day.short
1586
+ },
1587
+ day.short
1588
+ ))
1589
+ ] }) }),
1590
+ /* @__PURE__ */ jsx("tbody", { children: weeks.map((week, weekIndex) => /* @__PURE__ */ jsxs(
1546
1591
  "tr",
1547
1592
  {
1548
1593
  role: "row",
1549
1594
  "aria-rowindex": weekIndex + 2,
1550
1595
  className: classNames?.gridRow,
1551
- children: week.map((day, colIndex) => {
1552
- const dayClasses = [
1553
- classNames?.day,
1554
- day.isRangeStart && classNames?.dayRangeStart,
1555
- day.isRangeEnd && classNames?.dayRangeEnd,
1556
- day.isInRange && classNames?.dayInRange,
1557
- day.isToday && classNames?.dayToday,
1558
- day.isDisabled && classNames?.dayDisabled,
1559
- !day.isCurrentMonth && classNames?.dayOutsideMonth
1560
- ].filter(Boolean).join(" ") || void 0;
1561
- const isSelected = selectionMode === "week" ? day.isRangeStart || day.isRangeEnd || day.isInRange : day.isRangeStart || day.isRangeEnd;
1562
- return /* @__PURE__ */ jsx(
1563
- "td",
1596
+ children: [
1597
+ showWeekNumber ? /* @__PURE__ */ jsx(
1598
+ "th",
1564
1599
  {
1565
- role: "gridcell",
1566
- "aria-colindex": colIndex + 1,
1567
- "aria-selected": isSelected || void 0,
1568
- "aria-disabled": day.isDisabled || void 0,
1569
- "aria-current": day.isToday ? "date" : void 0,
1570
- className: classNames?.gridCell,
1571
- children: /* @__PURE__ */ jsx(
1572
- "button",
1573
- {
1574
- type: "button",
1575
- tabIndex: day.isFocused ? 0 : -1,
1576
- disabled: day.isDisabled,
1577
- "data-focused": day.isFocused || void 0,
1578
- "data-range-start": day.isRangeStart || void 0,
1579
- "data-range-end": day.isRangeEnd || void 0,
1580
- "data-in-range": day.isInRange || void 0,
1581
- "data-today": day.isToday || void 0,
1582
- "data-outside-month": !day.isCurrentMonth || void 0,
1583
- className: dayClasses,
1584
- onClick: () => handleDayClick(day),
1585
- onMouseEnter: () => handleDayMouseEnter(day),
1586
- "aria-label": safeFormatFullDate2(day.isoString, locale),
1587
- children: day.dayNumber
1588
- }
1589
- )
1590
- },
1591
- day.isoString
1592
- );
1593
- })
1600
+ scope: "row",
1601
+ "aria-hidden": "true",
1602
+ className: classNames?.weekNumber,
1603
+ "data-week-number": true,
1604
+ children: getISOWeekNumber(week[thursdayIndex].isoString)
1605
+ }
1606
+ ) : null,
1607
+ week.map((day, colIndex) => {
1608
+ const dayClasses = [
1609
+ classNames?.day,
1610
+ day.isRangeStart && classNames?.dayRangeStart,
1611
+ day.isRangeEnd && classNames?.dayRangeEnd,
1612
+ day.isInRange && classNames?.dayInRange,
1613
+ day.isToday && classNames?.dayToday,
1614
+ day.isDisabled && classNames?.dayDisabled,
1615
+ !day.isCurrentMonth && classNames?.dayOutsideMonth
1616
+ ].filter(Boolean).join(" ") || void 0;
1617
+ const isSelected = selectionMode === "week" ? day.isRangeStart || day.isRangeEnd || day.isInRange : day.isRangeStart || day.isRangeEnd;
1618
+ return /* @__PURE__ */ jsx(
1619
+ "td",
1620
+ {
1621
+ role: "gridcell",
1622
+ "aria-colindex": colIndex + 1,
1623
+ "aria-selected": isSelected || void 0,
1624
+ "aria-disabled": day.isDisabled || void 0,
1625
+ "aria-current": day.isToday ? "date" : void 0,
1626
+ className: classNames?.gridCell,
1627
+ children: /* @__PURE__ */ jsx(
1628
+ "button",
1629
+ {
1630
+ type: "button",
1631
+ tabIndex: day.isFocused ? 0 : -1,
1632
+ disabled: day.isDisabled,
1633
+ "data-focused": day.isFocused || void 0,
1634
+ "data-range-start": day.isRangeStart || void 0,
1635
+ "data-range-end": day.isRangeEnd || void 0,
1636
+ "data-in-range": day.isInRange || void 0,
1637
+ "data-today": day.isToday || void 0,
1638
+ "data-outside-month": !day.isCurrentMonth || void 0,
1639
+ className: dayClasses,
1640
+ onClick: () => handleDayClick(day),
1641
+ onMouseEnter: () => handleDayMouseEnter(day),
1642
+ "aria-label": safeFormatFullDate2(day.isoString, locale),
1643
+ children: day.dayNumber
1644
+ }
1645
+ )
1646
+ },
1647
+ day.isoString
1648
+ );
1649
+ })
1650
+ ]
1594
1651
  },
1595
1652
  weekIndex
1596
1653
  )) })