@kalyx/react 1.0.0-rc.7 → 1.0.0-rc.9
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 +35 -0
- package/dist/index.cjs +45 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +45 -8
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# @kalyx/react
|
|
2
2
|
|
|
3
|
+
## 1.0.0-rc.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 1a77283: docs: clarify `TimePicker.filterTime` polarity. The predicate returns `true` to mark a slot **unselectable** — same polarity as MUI X's `shouldDisableTime`, and the **inverse** of react-datepicker's `filterTime` (which returns `true` to _keep_ a slot). Earlier JSDoc/changelog called it "equivalent to react-datepicker's `filterTime`", which is misleading because the polarity is reversed; react-datepicker migrators must invert their predicate. No runtime behavior change — JSDoc, the published package description (≤16 KB), and docs only.
|
|
8
|
+
|
|
9
|
+
## 1.0.0-rc.8
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 0d3b845: `TimePicker.Root` gains a programmatic **`filterTime`** prop — `(hours: number, minutes: number) => boolean` returning `true` for any slot that should be unselectable. Equivalent to `react-datepicker`'s `filterTime` and MUI X's `shouldDisableTime`, covering use cases the static `step` prop can't (business-hours-only, lunch breaks, blackout slots, per-day variations).
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
<TimePicker
|
|
17
|
+
value={time}
|
|
18
|
+
onChange={setTime}
|
|
19
|
+
step={15}
|
|
20
|
+
// Business hours only: 09:00–11:45 and 13:00–17:45 (no lunch slot)
|
|
21
|
+
filterTime={(h, m) => h < 9 || h >= 18 || h === 12}
|
|
22
|
+
>
|
|
23
|
+
<TimePicker.Input />
|
|
24
|
+
<TimePicker.HourList />
|
|
25
|
+
<TimePicker.MinuteList />
|
|
26
|
+
</TimePicker>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Behavior:
|
|
30
|
+
- **`MinuteList`** — minutes for which `filterTime(currentHour, minute)` returns `true` get `aria-disabled="true"` and reject click/Enter.
|
|
31
|
+
- **`HourList`** — an hour is marked `aria-disabled="true"` only when `filterTime` returns `true` for **every** step minute within it. Hours with at least one open minute remain selectable.
|
|
32
|
+
- 12-hour mode — the predicate always receives 24-hour values (`0`–`23`) regardless of the picker's display format.
|
|
33
|
+
|
|
34
|
+
**Note**: `DateTimePicker` does not yet wire this through — combine `DatePicker.Root` + `TimePicker.Root` manually if you need both date and time-slot filtering in the same picker.
|
|
35
|
+
|
|
36
|
+
Bundle ceiling raised 15 → 16 KB (PR #N follows the 12→13→14→15 cadence — each raise tied to a documented feature; CLAUDE.md §2 records the chain). Measured 15.01 KB ESM / 15.16 KB CJS at this commit, ~4× smaller than react-datepicker.
|
|
37
|
+
|
|
3
38
|
## 1.0.0-rc.7
|
|
4
39
|
|
|
5
40
|
### Minor Changes
|
package/dist/index.cjs
CHANGED
|
@@ -1792,6 +1792,7 @@ function TimePickerRoot({
|
|
|
1792
1792
|
displayTimezone,
|
|
1793
1793
|
disabled = false,
|
|
1794
1794
|
readOnly = false,
|
|
1795
|
+
filterTime,
|
|
1795
1796
|
labels: labelsProp,
|
|
1796
1797
|
children
|
|
1797
1798
|
}) {
|
|
@@ -1833,7 +1834,8 @@ function TimePickerRoot({
|
|
|
1833
1834
|
isReadOnly: readOnly,
|
|
1834
1835
|
currentTime,
|
|
1835
1836
|
pickerId,
|
|
1836
|
-
labels: mergedLabels
|
|
1837
|
+
labels: mergedLabels,
|
|
1838
|
+
filterTime
|
|
1837
1839
|
}),
|
|
1838
1840
|
[
|
|
1839
1841
|
currentValue,
|
|
@@ -1846,7 +1848,8 @@ function TimePickerRoot({
|
|
|
1846
1848
|
readOnly,
|
|
1847
1849
|
currentTime,
|
|
1848
1850
|
pickerId,
|
|
1849
|
-
mergedLabels
|
|
1851
|
+
mergedLabels,
|
|
1852
|
+
filterTime
|
|
1850
1853
|
]
|
|
1851
1854
|
);
|
|
1852
1855
|
return /* @__PURE__ */ jsxRuntime.jsx(TimePickerContext.Provider, { value: contextValue, children });
|
|
@@ -1951,17 +1954,41 @@ function useListboxNavigation({
|
|
|
1951
1954
|
}
|
|
1952
1955
|
function TimePickerHourList({ classNames, ...props }) {
|
|
1953
1956
|
const ctx = useTimePickerContext("TimePicker.HourList");
|
|
1954
|
-
const { format, currentTime, isDisabled, isReadOnly } = ctx;
|
|
1957
|
+
const { format, step, currentTime, isDisabled, isReadOnly, filterTime } = ctx;
|
|
1955
1958
|
const hours = react.useMemo(() => core.generateHours(format), [format]);
|
|
1956
1959
|
const selectedHourDisplay = format === "12h" ? core.to12Hour(currentTime.hours).hours12 : currentTime.hours;
|
|
1957
1960
|
const currentPeriod = format === "12h" ? core.to12Hour(currentTime.hours).period : null;
|
|
1961
|
+
const fullyDisabledHours24 = react.useMemo(() => {
|
|
1962
|
+
if (!filterTime) return null;
|
|
1963
|
+
const disabled = /* @__PURE__ */ new Set();
|
|
1964
|
+
for (let h = 0; h < 24; h++) {
|
|
1965
|
+
let allRejected = true;
|
|
1966
|
+
for (let m = 0; m < 60; m += step) {
|
|
1967
|
+
if (!filterTime(h, m)) {
|
|
1968
|
+
allRejected = false;
|
|
1969
|
+
break;
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
if (allRejected) disabled.add(h);
|
|
1973
|
+
}
|
|
1974
|
+
return disabled;
|
|
1975
|
+
}, [filterTime, step]);
|
|
1976
|
+
const isHourDisabled = react.useCallback(
|
|
1977
|
+
(hourDisplay) => {
|
|
1978
|
+
if (!fullyDisabledHours24) return false;
|
|
1979
|
+
const hours24 = format === "12h" && currentPeriod ? core.to24Hour(hourDisplay, currentPeriod) : hourDisplay;
|
|
1980
|
+
return fullyDisabledHours24.has(hours24);
|
|
1981
|
+
},
|
|
1982
|
+
[fullyDisabledHours24, format, currentPeriod]
|
|
1983
|
+
);
|
|
1958
1984
|
const handleSelect = react.useCallback(
|
|
1959
1985
|
(hourDisplay) => {
|
|
1960
1986
|
if (isDisabled || isReadOnly) return;
|
|
1987
|
+
if (isHourDisabled(hourDisplay)) return;
|
|
1961
1988
|
const hours24 = format === "12h" && currentPeriod ? core.to24Hour(hourDisplay, currentPeriod) : hourDisplay;
|
|
1962
1989
|
ctx.setTime({ hours: hours24 });
|
|
1963
1990
|
},
|
|
1964
|
-
[format, currentPeriod, ctx, isDisabled, isReadOnly]
|
|
1991
|
+
[format, currentPeriod, ctx, isDisabled, isReadOnly, isHourDisabled]
|
|
1965
1992
|
);
|
|
1966
1993
|
const { listRef, handleKeyDown } = useListboxNavigation({
|
|
1967
1994
|
items: hours,
|
|
@@ -1979,13 +2006,14 @@ function TimePickerHourList({ classNames, ...props }) {
|
|
|
1979
2006
|
...props,
|
|
1980
2007
|
children: hours.map((hour) => {
|
|
1981
2008
|
const isSelected = hour === selectedHourDisplay;
|
|
2009
|
+
const isHourFullyDisabled = isHourDisabled(hour);
|
|
1982
2010
|
const optionClass = [classNames?.option, isSelected && classNames?.optionSelected].filter(Boolean).join(" ") || void 0;
|
|
1983
2011
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1984
2012
|
"li",
|
|
1985
2013
|
{
|
|
1986
2014
|
role: "option",
|
|
1987
2015
|
"aria-selected": isSelected,
|
|
1988
|
-
"aria-disabled": isDisabled || void 0,
|
|
2016
|
+
"aria-disabled": isDisabled || isHourFullyDisabled || void 0,
|
|
1989
2017
|
"aria-label": ctx.labels.hourOption(hour),
|
|
1990
2018
|
"data-selected": isSelected || void 0,
|
|
1991
2019
|
tabIndex: isSelected ? 0 : -1,
|
|
@@ -2002,14 +2030,22 @@ function TimePickerHourList({ classNames, ...props }) {
|
|
|
2002
2030
|
}
|
|
2003
2031
|
function TimePickerMinuteList({ classNames, ...props }) {
|
|
2004
2032
|
const ctx = useTimePickerContext("TimePicker.MinuteList");
|
|
2005
|
-
const { step, currentTime, isDisabled, isReadOnly } = ctx;
|
|
2033
|
+
const { step, currentTime, isDisabled, isReadOnly, filterTime } = ctx;
|
|
2006
2034
|
const minutes = react.useMemo(() => core.generateMinutes(step), [step]);
|
|
2035
|
+
const isMinuteDisabled = react.useCallback(
|
|
2036
|
+
(minute) => {
|
|
2037
|
+
if (!filterTime) return false;
|
|
2038
|
+
return filterTime(currentTime.hours, minute);
|
|
2039
|
+
},
|
|
2040
|
+
[filterTime, currentTime.hours]
|
|
2041
|
+
);
|
|
2007
2042
|
const handleSelect = react.useCallback(
|
|
2008
2043
|
(minute) => {
|
|
2009
2044
|
if (isDisabled || isReadOnly) return;
|
|
2045
|
+
if (isMinuteDisabled(minute)) return;
|
|
2010
2046
|
ctx.setTime({ minutes: minute });
|
|
2011
2047
|
},
|
|
2012
|
-
[ctx, isDisabled, isReadOnly]
|
|
2048
|
+
[ctx, isDisabled, isReadOnly, isMinuteDisabled]
|
|
2013
2049
|
);
|
|
2014
2050
|
const { listRef, handleKeyDown } = useListboxNavigation({
|
|
2015
2051
|
items: minutes,
|
|
@@ -2027,13 +2063,14 @@ function TimePickerMinuteList({ classNames, ...props }) {
|
|
|
2027
2063
|
...props,
|
|
2028
2064
|
children: minutes.map((minute) => {
|
|
2029
2065
|
const isSelected = minute === currentTime.minutes;
|
|
2066
|
+
const isMinuteFullyDisabled = isMinuteDisabled(minute);
|
|
2030
2067
|
const optionClass = [classNames?.option, isSelected && classNames?.optionSelected].filter(Boolean).join(" ") || void 0;
|
|
2031
2068
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2032
2069
|
"li",
|
|
2033
2070
|
{
|
|
2034
2071
|
role: "option",
|
|
2035
2072
|
"aria-selected": isSelected,
|
|
2036
|
-
"aria-disabled": isDisabled || void 0,
|
|
2073
|
+
"aria-disabled": isDisabled || isMinuteFullyDisabled || void 0,
|
|
2037
2074
|
"aria-label": ctx.labels.minuteOption(minute),
|
|
2038
2075
|
"data-selected": isSelected || void 0,
|
|
2039
2076
|
tabIndex: isSelected ? 0 : -1,
|