@nsaa/core 0.1.0-alpha.5 → 0.1.0-alpha.6
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.
|
@@ -5,9 +5,9 @@ import { Locale, Matcher } from "react-day-picker";
|
|
|
5
5
|
export type DateRangePickerLabels = {
|
|
6
6
|
/** Trigger text when there is no range. */
|
|
7
7
|
placeholder: string;
|
|
8
|
-
/** The
|
|
8
|
+
/** The radio for a range that matches no preset; in presetsOnly it opens the calendar. */
|
|
9
9
|
custom: string;
|
|
10
|
-
/** The presets
|
|
10
|
+
/** The presets radio group's name. */
|
|
11
11
|
presets: string;
|
|
12
12
|
/** The panel's name (Popover) and the Drawer's title. */
|
|
13
13
|
title: string;
|
|
@@ -10,11 +10,13 @@ import { localeWeekStart, matchPreset, presets, todayIn } from "./presets.js";
|
|
|
10
10
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11
11
|
import * as React from "react";
|
|
12
12
|
import { useReducedMotion, useReducedMotionConfig } from "motion/react";
|
|
13
|
+
import { Radio } from "@base-ui/react/radio";
|
|
14
|
+
import { RadioGroup } from "@base-ui/react/radio-group";
|
|
13
15
|
// src/date-range-picker/date-range-picker.tsx
|
|
14
16
|
const DEFAULT_LABELS = {
|
|
15
17
|
placeholder: "Pick a date range",
|
|
16
18
|
custom: "Custom…",
|
|
17
|
-
presets: "
|
|
19
|
+
presets: "Period",
|
|
18
20
|
title: "Date range"
|
|
19
21
|
};
|
|
20
22
|
const DEFAULT_PRESETS = Object.values(presets);
|
|
@@ -90,55 +92,28 @@ function useMedia(query) {
|
|
|
90
92
|
return () => list.removeEventListener("change", onChange);
|
|
91
93
|
}, () => window.matchMedia(query).matches, () => false);
|
|
92
94
|
}
|
|
93
|
-
/**
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
};
|
|
103
|
-
const onKeyDown = (event) => {
|
|
104
|
-
const rtl = event.currentTarget.closest("[dir]")?.getAttribute("dir") === "rtl";
|
|
105
|
-
const vertical = orientation === "vertical";
|
|
106
|
-
const next = vertical ? "ArrowDown" : rtl ? "ArrowLeft" : "ArrowRight";
|
|
107
|
-
const prev = vertical ? "ArrowUp" : rtl ? "ArrowRight" : "ArrowLeft";
|
|
108
|
-
const last = options.length - 1;
|
|
109
|
-
const option = options[active];
|
|
110
|
-
if (event.key === next) move(Math.min(active + 1, last));
|
|
111
|
-
else if (event.key === prev) move(Math.max(active - 1, 0));
|
|
112
|
-
else if (event.key === "Home") move(0);
|
|
113
|
-
else if (event.key === "End") move(last);
|
|
114
|
-
else if (event.key === "Enter" || event.key === " ") {
|
|
115
|
-
if (option && !option.disabled) onPick(option.id);
|
|
116
|
-
} else return;
|
|
117
|
-
event.preventDefault();
|
|
118
|
-
};
|
|
119
|
-
return /* @__PURE__ */ jsx("div", {
|
|
120
|
-
role: "listbox",
|
|
95
|
+
/**
|
|
96
|
+
* Presets on Base UI Radio Group (#159): one tab stop, arrows move the checked radio. The checked
|
|
97
|
+
* radio is only a draft (the calendar previews it); a click, Space (Base UI turns it into a click)
|
|
98
|
+
* or Enter applies it.
|
|
99
|
+
*/
|
|
100
|
+
function PresetList({ options, value, orientation, label, onDraft, onPick }) {
|
|
101
|
+
return /* @__PURE__ */ jsx(RadioGroup, {
|
|
102
|
+
value: value ?? null,
|
|
103
|
+
onValueChange: (next) => onDraft(next),
|
|
121
104
|
"aria-label": label,
|
|
122
|
-
"aria-orientation": orientation,
|
|
123
105
|
"data-slot": "date-range-picker-presets",
|
|
124
106
|
"data-orientation": orientation,
|
|
125
107
|
className: cn("flex gap-1 p-2", orientation === "vertical" ? "w-40 shrink-0 flex-col" : "overflow-x-auto border-b border-border"),
|
|
126
|
-
children: options.map((option
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
},
|
|
130
|
-
id: `${baseId}-${option.id}`,
|
|
131
|
-
role: "option",
|
|
132
|
-
tabIndex: index === active ? 0 : -1,
|
|
133
|
-
"aria-selected": option.id === selectedId,
|
|
134
|
-
"aria-disabled": option.disabled || void 0,
|
|
108
|
+
children: options.map((option) => /* @__PURE__ */ jsx(Radio.Root, {
|
|
109
|
+
value: option.id,
|
|
110
|
+
disabled: option.disabled,
|
|
135
111
|
"data-slot": "date-range-picker-preset",
|
|
136
|
-
|
|
137
|
-
onKeyDown
|
|
138
|
-
|
|
139
|
-
if (!option.disabled) onPick(option.id);
|
|
112
|
+
onClick: () => onPick(option.id),
|
|
113
|
+
onKeyDown: (event) => {
|
|
114
|
+
if (event.key === "Enter") onPick(option.id);
|
|
140
115
|
},
|
|
141
|
-
className: cn("flex cursor-default items-center rounded-md text-sm whitespace-nowrap text-foreground outline-hidden select-none hover:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50
|
|
116
|
+
className: cn("flex cursor-default items-center rounded-md text-start text-sm whitespace-nowrap text-foreground outline-hidden select-none hover:bg-muted focus-visible:ring-3 focus-visible:ring-ring/50 data-checked:bg-muted data-checked:font-medium data-disabled:pointer-events-none data-disabled:opacity-50", orientation === "vertical" ? "min-h-8 px-2 pointer-coarse:min-h-11" : "h-7 shrink-0 border border-border px-2.5 pointer-coarse:h-11"),
|
|
142
117
|
children: option.label
|
|
143
118
|
}, option.id))
|
|
144
119
|
});
|
|
@@ -154,6 +129,7 @@ function DateRangePicker({ value: valueProp, defaultValue = null, onValueChange,
|
|
|
154
129
|
const [open, setOpen] = React.useState(false);
|
|
155
130
|
const [view, setView] = React.useState("calendar");
|
|
156
131
|
const [draft, setDraft] = React.useState(null);
|
|
132
|
+
const [presetDraft, setPresetDraft] = React.useState();
|
|
157
133
|
const [axes, setAxes] = React.useState({});
|
|
158
134
|
const [announcement, setAnnouncement] = React.useState("");
|
|
159
135
|
const wide = useContainerWide(rootRef);
|
|
@@ -197,6 +173,7 @@ function DateRangePicker({ value: valueProp, defaultValue = null, onValueChange,
|
|
|
197
173
|
setView(presetsOnly ? "list" : "calendar");
|
|
198
174
|
}
|
|
199
175
|
setDraft(null);
|
|
176
|
+
setPresetDraft(next ? matched?.id ?? CUSTOM : void 0);
|
|
200
177
|
setOpen(next);
|
|
201
178
|
};
|
|
202
179
|
const apply = (range, picked) => {
|
|
@@ -214,6 +191,7 @@ function DateRangePicker({ value: valueProp, defaultValue = null, onValueChange,
|
|
|
214
191
|
};
|
|
215
192
|
const onDay = (_range, day) => {
|
|
216
193
|
clearTimeout(timer.current);
|
|
194
|
+
setPresetDraft(CUSTOM);
|
|
217
195
|
if (!draft || draft.to) {
|
|
218
196
|
setDraft({ from: day });
|
|
219
197
|
return;
|
|
@@ -239,10 +217,20 @@ function DateRangePicker({ value: valueProp, defaultValue = null, onValueChange,
|
|
|
239
217
|
};
|
|
240
218
|
});
|
|
241
219
|
const pickPreset = (presetId) => {
|
|
242
|
-
if (presetId === CUSTOM)
|
|
220
|
+
if (presetId === CUSTOM) {
|
|
221
|
+
if (presetsOnly) return setView("calendar");
|
|
222
|
+
panelRef.current?.querySelector("button[data-day][tabindex=\"0\"]")?.focus();
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
243
225
|
const preset = presetList.find((p) => p.id === presetId);
|
|
244
226
|
if (preset) apply(preset.range(today, options), preset);
|
|
245
227
|
};
|
|
228
|
+
const presetChoices = [...presetOptions, {
|
|
229
|
+
id: CUSTOM,
|
|
230
|
+
label: labels.custom
|
|
231
|
+
}];
|
|
232
|
+
const previewPreset = presetList.find((p) => p.id === presetDraft);
|
|
233
|
+
const previewed = previewPreset ? previewPreset.range(today, options) : void 0;
|
|
246
234
|
const matchers = [
|
|
247
235
|
...min ? [{ before: min }] : [],
|
|
248
236
|
...max ? [{ after: max }] : [],
|
|
@@ -252,13 +240,11 @@ function DateRangePicker({ value: valueProp, defaultValue = null, onValueChange,
|
|
|
252
240
|
const defaultMonth = months === 2 ? new Date(anchor.getFullYear(), anchor.getMonth() - 1, 1) : anchor;
|
|
253
241
|
const narrow = months === 1;
|
|
254
242
|
const panel = view === "list" ? /* @__PURE__ */ jsx(PresetList, {
|
|
255
|
-
options:
|
|
256
|
-
|
|
257
|
-
label: labels.custom
|
|
258
|
-
}],
|
|
259
|
-
selectedId: matched?.id ?? (value ? CUSTOM : void 0),
|
|
243
|
+
options: presetChoices,
|
|
244
|
+
value: presetDraft,
|
|
260
245
|
orientation: "vertical",
|
|
261
246
|
label: labels.presets,
|
|
247
|
+
onDraft: setPresetDraft,
|
|
262
248
|
onPick: pickPreset
|
|
263
249
|
}) : /* @__PURE__ */ jsxs("div", {
|
|
264
250
|
ref: panelRef,
|
|
@@ -267,16 +253,17 @@ function DateRangePicker({ value: valueProp, defaultValue = null, onValueChange,
|
|
|
267
253
|
children: [!presetsOnly && presetOptions.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
268
254
|
className: cn(!narrow && "border-e border-border"),
|
|
269
255
|
children: /* @__PURE__ */ jsx(PresetList, {
|
|
270
|
-
options:
|
|
271
|
-
|
|
256
|
+
options: presetChoices,
|
|
257
|
+
value: presetDraft,
|
|
272
258
|
orientation: narrow ? "horizontal" : "vertical",
|
|
273
259
|
label: labels.presets,
|
|
260
|
+
onDraft: setPresetDraft,
|
|
274
261
|
onPick: pickPreset
|
|
275
262
|
})
|
|
276
263
|
}), /* @__PURE__ */ jsx(Calendar, {
|
|
277
264
|
mode: "range",
|
|
278
265
|
locale: calendarLocale,
|
|
279
|
-
selected: draft ?? value ?? void 0,
|
|
266
|
+
selected: draft ?? previewed ?? value ?? void 0,
|
|
280
267
|
onSelect: onDay,
|
|
281
268
|
numberOfMonths: months,
|
|
282
269
|
showOutsideDays: months === 1,
|
|
@@ -22,7 +22,7 @@ function ProgressTrack({ className, ...props }) {
|
|
|
22
22
|
function ProgressIndicator({ className, ...props }) {
|
|
23
23
|
return /* @__PURE__ */ jsx(Progress.Indicator, {
|
|
24
24
|
"data-slot": "progress-indicator",
|
|
25
|
-
className: cn("h-full bg-
|
|
25
|
+
className: cn("h-full bg-(--nsaa-color-brand-foreground) transition-all", className),
|
|
26
26
|
...props
|
|
27
27
|
});
|
|
28
28
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nsaa/core",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.6",
|
|
4
4
|
"description": "Nsaa core components: accessible, token-driven, animated to the Nsaa feel spec.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"tailwind-merge": "^3.7.0",
|
|
54
54
|
"tailwind-variants": "^3.3.1",
|
|
55
55
|
"uisfx": "0.4.0",
|
|
56
|
-
"@nsaa/tokens": "^0.1.0-alpha.
|
|
56
|
+
"@nsaa/tokens": "^0.1.0-alpha.6"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@testing-library/jest-dom": "^7.0.1",
|