@mortenbrudvik/waveui 0.8.0 → 0.10.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/README.md +634 -167
- package/dist/components/data-display/InfoButton.cjs +2 -0
- package/dist/components/data-display/InfoButton.cjs.map +1 -0
- package/dist/components/data-display/InfoButton.mjs +173 -0
- package/dist/components/data-display/InfoButton.mjs.map +1 -0
- package/dist/components/data-display/InfoLabel.cjs +1 -1
- package/dist/components/data-display/InfoLabel.cjs.map +1 -1
- package/dist/components/data-display/InfoLabel.mjs +39 -96
- package/dist/components/data-display/InfoLabel.mjs.map +1 -1
- package/dist/components/input/Calendar.cjs +2 -0
- package/dist/components/input/Calendar.cjs.map +1 -0
- package/dist/components/input/Calendar.mjs +352 -0
- package/dist/components/input/Calendar.mjs.map +1 -0
- package/dist/components/input/Calendar.views.cjs +2 -0
- package/dist/components/input/Calendar.views.cjs.map +1 -0
- package/dist/components/input/Calendar.views.mjs +194 -0
- package/dist/components/input/Calendar.views.mjs.map +1 -0
- package/dist/components/input/Checkbox.cjs +1 -1
- package/dist/components/input/Checkbox.cjs.map +1 -1
- package/dist/components/input/Checkbox.mjs +91 -75
- package/dist/components/input/Checkbox.mjs.map +1 -1
- package/dist/components/input/ColorArea.cjs +1 -1
- package/dist/components/input/ColorArea.cjs.map +1 -1
- package/dist/components/input/ColorArea.mjs +18 -18
- package/dist/components/input/ColorArea.mjs.map +1 -1
- package/dist/components/input/ColorPicker.parts.cjs +1 -1
- package/dist/components/input/ColorPicker.parts.cjs.map +1 -1
- package/dist/components/input/ColorPicker.parts.mjs +1 -1
- package/dist/components/input/ColorPicker.parts.mjs.map +1 -1
- package/dist/components/input/Combobox.cjs +1 -1
- package/dist/components/input/Combobox.cjs.map +1 -1
- package/dist/components/input/Combobox.expand.cjs +1 -1
- package/dist/components/input/Combobox.expand.cjs.map +1 -1
- package/dist/components/input/Combobox.expand.mjs +20 -20
- package/dist/components/input/Combobox.expand.mjs.map +1 -1
- package/dist/components/input/Combobox.mjs +219 -138
- package/dist/components/input/Combobox.mjs.map +1 -1
- package/dist/components/input/Combobox.text.cjs +2 -0
- package/dist/components/input/Combobox.text.cjs.map +1 -0
- package/dist/components/input/Combobox.text.mjs +24 -0
- package/dist/components/input/Combobox.text.mjs.map +1 -0
- package/dist/components/input/DatePicker.cjs +1 -1
- package/dist/components/input/DatePicker.cjs.map +1 -1
- package/dist/components/input/DatePicker.mjs +205 -286
- package/dist/components/input/DatePicker.mjs.map +1 -1
- package/dist/components/input/Dropdown.cjs +1 -1
- package/dist/components/input/Dropdown.cjs.map +1 -1
- package/dist/components/input/Dropdown.mjs +137 -105
- package/dist/components/input/Dropdown.mjs.map +1 -1
- package/dist/components/input/Field.cjs +1 -1
- package/dist/components/input/Field.cjs.map +1 -1
- package/dist/components/input/Field.mjs +99 -66
- package/dist/components/input/Field.mjs.map +1 -1
- package/dist/components/input/Input.cjs +1 -1
- package/dist/components/input/Input.cjs.map +1 -1
- package/dist/components/input/Input.mjs +79 -55
- package/dist/components/input/Input.mjs.map +1 -1
- package/dist/components/input/Label.cjs +1 -1
- package/dist/components/input/Label.cjs.map +1 -1
- package/dist/components/input/Label.mjs +19 -13
- package/dist/components/input/Label.mjs.map +1 -1
- package/dist/components/input/Listbox.cjs +2 -0
- package/dist/components/input/Listbox.cjs.map +1 -0
- package/dist/components/input/Listbox.mjs +134 -0
- package/dist/components/input/Listbox.mjs.map +1 -0
- package/dist/components/input/Option.cjs +1 -1
- package/dist/components/input/Option.cjs.map +1 -1
- package/dist/components/input/Option.mjs +158 -97
- package/dist/components/input/Option.mjs.map +1 -1
- package/dist/components/input/Rating.cjs +1 -1
- package/dist/components/input/Rating.cjs.map +1 -1
- package/dist/components/input/Rating.item.cjs +2 -0
- package/dist/components/input/Rating.item.cjs.map +1 -0
- package/dist/components/input/Rating.item.mjs +255 -0
- package/dist/components/input/Rating.item.mjs.map +1 -0
- package/dist/components/input/Rating.mjs +150 -151
- package/dist/components/input/Rating.mjs.map +1 -1
- package/dist/components/input/SearchBox.cjs +1 -1
- package/dist/components/input/SearchBox.cjs.map +1 -1
- package/dist/components/input/SearchBox.mjs +146 -115
- package/dist/components/input/SearchBox.mjs.map +1 -1
- package/dist/components/input/Select.cjs +1 -1
- package/dist/components/input/Select.cjs.map +1 -1
- package/dist/components/input/Select.mjs +34 -25
- package/dist/components/input/Select.mjs.map +1 -1
- package/dist/components/input/Slider.cjs +1 -1
- package/dist/components/input/Slider.cjs.map +1 -1
- package/dist/components/input/Slider.mjs +77 -54
- package/dist/components/input/Slider.mjs.map +1 -1
- package/dist/components/input/SpinButton.cjs +1 -1
- package/dist/components/input/SpinButton.cjs.map +1 -1
- package/dist/components/input/SpinButton.mjs +198 -96
- package/dist/components/input/SpinButton.mjs.map +1 -1
- package/dist/components/input/SwatchPicker.cjs +1 -1
- package/dist/components/input/SwatchPicker.cjs.map +1 -1
- package/dist/components/input/SwatchPicker.context.cjs +2 -0
- package/dist/components/input/SwatchPicker.context.cjs.map +1 -0
- package/dist/components/input/SwatchPicker.context.mjs +35 -0
- package/dist/components/input/SwatchPicker.context.mjs.map +1 -0
- package/dist/components/input/SwatchPicker.mjs +131 -103
- package/dist/components/input/SwatchPicker.mjs.map +1 -1
- package/dist/components/input/SwatchPicker.swatches.cjs +2 -0
- package/dist/components/input/SwatchPicker.swatches.cjs.map +1 -0
- package/dist/components/input/SwatchPicker.swatches.mjs +207 -0
- package/dist/components/input/SwatchPicker.swatches.mjs.map +1 -0
- package/dist/components/input/Switch.cjs +1 -1
- package/dist/components/input/Switch.cjs.map +1 -1
- package/dist/components/input/Switch.mjs +71 -55
- package/dist/components/input/Switch.mjs.map +1 -1
- package/dist/components/input/TagPicker.cjs +1 -1
- package/dist/components/input/TagPicker.cjs.map +1 -1
- package/dist/components/input/TagPicker.mjs +154 -123
- package/dist/components/input/TagPicker.mjs.map +1 -1
- package/dist/components/input/Textarea.cjs +1 -1
- package/dist/components/input/Textarea.cjs.map +1 -1
- package/dist/components/input/Textarea.mjs +28 -21
- package/dist/components/input/Textarea.mjs.map +1 -1
- package/dist/components/input/TimePicker.cjs +1 -1
- package/dist/components/input/TimePicker.cjs.map +1 -1
- package/dist/components/input/TimePicker.mjs +204 -199
- package/dist/components/input/TimePicker.mjs.map +1 -1
- package/dist/components/input/dateUtils.cjs +1 -1
- package/dist/components/input/dateUtils.cjs.map +1 -1
- package/dist/components/input/dateUtils.mjs +114 -96
- package/dist/components/input/dateUtils.mjs.map +1 -1
- package/dist/components/input/fieldLabel.cjs +2 -0
- package/dist/components/input/fieldLabel.cjs.map +1 -0
- package/dist/components/input/fieldLabel.mjs +17 -0
- package/dist/components/input/fieldLabel.mjs.map +1 -0
- package/dist/components/input/inputLook.cjs +2 -0
- package/dist/components/input/inputLook.cjs.map +1 -0
- package/dist/components/input/inputLook.mjs +28 -0
- package/dist/components/input/inputLook.mjs.map +1 -0
- package/dist/components/input/pickerLabels.cjs +2 -0
- package/dist/components/input/pickerLabels.cjs.map +1 -0
- package/dist/components/input/pickerLabels.mjs +16 -0
- package/dist/components/input/pickerLabels.mjs.map +1 -0
- package/dist/components/input/pickerStyles.cjs +1 -1
- package/dist/components/input/pickerStyles.cjs.map +1 -1
- package/dist/components/input/pickerStyles.mjs +42 -4
- package/dist/components/input/pickerStyles.mjs.map +1 -1
- package/dist/components/input/pickerValues.cjs +2 -0
- package/dist/components/input/pickerValues.cjs.map +1 -0
- package/dist/components/input/pickerValues.mjs +24 -0
- package/dist/components/input/pickerValues.mjs.map +1 -0
- package/dist/components/navigation/Menu.popover.cjs +1 -1
- package/dist/components/navigation/Menu.popover.cjs.map +1 -1
- package/dist/components/navigation/Menu.popover.mjs +10 -10
- package/dist/components/navigation/Menu.root.cjs +1 -1
- package/dist/components/navigation/Menu.root.cjs.map +1 -1
- package/dist/components/navigation/Menu.root.mjs +10 -10
- package/dist/components/overlays/Popover.cjs +1 -1
- package/dist/components/overlays/Popover.cjs.map +1 -1
- package/dist/components/overlays/Popover.mjs +203 -208
- package/dist/components/overlays/Popover.mjs.map +1 -1
- package/dist/components/overlays/Popover.shared.cjs +1 -1
- package/dist/components/overlays/Popover.shared.cjs.map +1 -1
- package/dist/components/overlays/Popover.shared.mjs +82 -77
- package/dist/components/overlays/Popover.shared.mjs.map +1 -1
- package/dist/components/provider/WaveProvider.cjs +1 -1
- package/dist/components/provider/WaveProvider.cjs.map +1 -1
- package/dist/components/provider/WaveProvider.mjs +25 -19
- package/dist/components/provider/WaveProvider.mjs.map +1 -1
- package/dist/components/table/useGridNavigation.cjs +1 -1
- package/dist/components/table/useGridNavigation.cjs.map +1 -1
- package/dist/components/table/useGridNavigation.mjs +67 -70
- package/dist/components/table/useGridNavigation.mjs.map +1 -1
- package/dist/hooks/useActiveDescendant.cjs +2 -0
- package/dist/hooks/useActiveDescendant.cjs.map +1 -0
- package/dist/hooks/useActiveDescendant.mjs +56 -0
- package/dist/hooks/useActiveDescendant.mjs.map +1 -0
- package/dist/hooks/useFieldControl.cjs.map +1 -1
- package/dist/hooks/useFieldControl.mjs.map +1 -1
- package/dist/hooks/useListbox.cjs +1 -1
- package/dist/hooks/useListbox.cjs.map +1 -1
- package/dist/hooks/useListbox.mjs +250 -210
- package/dist/hooks/useListbox.mjs.map +1 -1
- package/dist/hooks/useRovingGrid.cjs +2 -0
- package/dist/hooks/useRovingGrid.cjs.map +1 -0
- package/dist/hooks/useRovingGrid.mjs +69 -0
- package/dist/hooks/useRovingGrid.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2901 -203
- package/dist/index.d.ts +2901 -203
- package/dist/index.mjs +107 -99
- package/dist/lib/classNames.cjs +1 -1
- package/dist/lib/classNames.cjs.map +1 -1
- package/dist/lib/classNames.mjs +111 -67
- package/dist/lib/classNames.mjs.map +1 -1
- package/dist/lib/date.cjs +2 -0
- package/dist/lib/date.cjs.map +1 -0
- package/dist/lib/date.mjs +44 -0
- package/dist/lib/date.mjs.map +1 -0
- package/dist/lib/focus.cjs +1 -1
- package/dist/lib/focus.cjs.map +1 -1
- package/dist/lib/focus.mjs +5 -2
- package/dist/lib/focus.mjs.map +1 -1
- package/dist/lib/layers.cjs.map +1 -1
- package/dist/lib/layers.mjs.map +1 -1
- package/dist/lib/styles.cjs +1 -1
- package/dist/lib/styles.cjs.map +1 -1
- package/dist/lib/styles.mjs +21 -4
- package/dist/lib/styles.mjs.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/src/styles/tokens.css +13 -0
|
@@ -9,24 +9,48 @@ import { getArrowIntent as s, getDirection as ee } from "../../lib/direction.mjs
|
|
|
9
9
|
import { useMergedRefs as c } from "../../hooks/useMergedRefs.mjs";
|
|
10
10
|
import { useIsClient as te } from "../../hooks/useIsClient.mjs";
|
|
11
11
|
import { joinIds as ne } from "../../lib/aria.mjs";
|
|
12
|
-
import { useFieldContext as re, useFieldControl as
|
|
13
|
-
import { useAnnounce as
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
12
|
+
import { useFieldContext as re, useFieldControl as ie } from "../../hooks/useFieldControl.mjs";
|
|
13
|
+
import { useAnnounce as ae } from "../../hooks/useAnnounce.mjs";
|
|
14
|
+
import { useListbox as oe } from "../../hooks/useListbox.mjs";
|
|
15
|
+
import { focusRing as l, inputAppearanceClasses as se, inputFocusWithin as ce } from "../../lib/styles.mjs";
|
|
16
|
+
import { DismissIcon as u } from "../../lib/icons.mjs";
|
|
17
|
+
import { useInputLook as le } from "./inputLook.mjs";
|
|
18
|
+
import { isInvalidLook as ue } from "./Input.mjs";
|
|
19
|
+
import { useFormReset as de } from "../../hooks/useFormReset.mjs";
|
|
20
|
+
import { HiddenInput as fe } from "../internal/HiddenInput.mjs";
|
|
21
|
+
import { ListboxSurface as pe, Option as me, useListboxPopup as he } from "./Option.mjs";
|
|
22
|
+
import { announceToggle as d } from "./pickerLabels.mjs";
|
|
23
|
+
import { EMPTY_VALUES as f, sameValues as ge } from "./pickerValues.mjs";
|
|
21
24
|
import { usePreserveFocus as p } from "../../hooks/usePreserveFocus.mjs";
|
|
22
25
|
import * as m from "react";
|
|
23
26
|
import { jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
24
27
|
//#region src/components/input/TagPicker.tsx
|
|
25
|
-
var
|
|
26
|
-
function
|
|
27
|
-
return e.
|
|
28
|
+
var _e = (e) => `Remove ${e}`, ve = (e) => `Selected: ${e.join(", ")}`;
|
|
29
|
+
function ye(e, t) {
|
|
30
|
+
return e.label.toLowerCase().includes(t.toLowerCase());
|
|
28
31
|
}
|
|
29
|
-
|
|
32
|
+
var be = [
|
|
33
|
+
"medium",
|
|
34
|
+
"large",
|
|
35
|
+
"extra-large"
|
|
36
|
+
], xe = {
|
|
37
|
+
medium: {
|
|
38
|
+
control: "gap-1 px-2 py-1.5",
|
|
39
|
+
tag: "px-2 py-0.5 text-body-1",
|
|
40
|
+
input: "py-0.5 text-body-1"
|
|
41
|
+
},
|
|
42
|
+
large: {
|
|
43
|
+
control: "gap-1.5 px-2.5 py-2",
|
|
44
|
+
tag: "px-2 py-1 text-body-1",
|
|
45
|
+
input: "py-1 text-body-1"
|
|
46
|
+
},
|
|
47
|
+
"extra-large": {
|
|
48
|
+
control: "gap-1.5 px-3 py-2.5",
|
|
49
|
+
tag: "px-2.5 py-1 text-body-2",
|
|
50
|
+
input: "py-1 text-body-2"
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
function Se({ label: t, disabled: n, onClick: r, onKeyDown: a, getFallback: o }) {
|
|
30
54
|
let s = m.useRef(null);
|
|
31
55
|
return p(s, o), /* @__PURE__ */ h("button", {
|
|
32
56
|
ref: s,
|
|
@@ -34,90 +58,95 @@ function _e({ label: t, disabled: n, onClick: r, onKeyDown: a, getFallback: o })
|
|
|
34
58
|
"data-wave-tagpicker-remove": "",
|
|
35
59
|
disabled: n,
|
|
36
60
|
"aria-label": t,
|
|
37
|
-
className: e(i.removeButton, "ms-0.5 inline-flex rounded-sm bg-transparent p-0 text-muted-foreground not-disabled:not-aria-disabled:hover:text-foreground disabled:cursor-not-allowed",
|
|
61
|
+
className: e(i.removeButton, "ms-0.5 inline-flex rounded-sm bg-transparent p-0 text-muted-foreground not-disabled:not-aria-disabled:hover:text-foreground disabled:cursor-not-allowed", l),
|
|
38
62
|
onClick: r,
|
|
39
63
|
onKeyDown: a,
|
|
40
|
-
children: /* @__PURE__ */ h(
|
|
64
|
+
children: /* @__PURE__ */ h(u, { size: 12 })
|
|
41
65
|
});
|
|
42
66
|
}
|
|
43
|
-
var
|
|
44
|
-
let { options:
|
|
45
|
-
|
|
46
|
-
let
|
|
47
|
-
id:
|
|
48
|
-
"aria-label":
|
|
49
|
-
"aria-labelledby":
|
|
50
|
-
"aria-describedby":
|
|
51
|
-
"aria-invalid":
|
|
52
|
-
"aria-required":
|
|
53
|
-
}),
|
|
67
|
+
var _ = (l) => {
|
|
68
|
+
let { options: u, value: p, defaultValue: _, onValueChange: Ce, onChange: v, open: we, defaultOpen: Te, onOpenChange: Ee, placeholder: De = "Select...", filter: y, query: Oe, defaultQuery: ke, onQueryChange: Ae, disabled: b = !1, size: je, appearance: Me, name: Ne, form: x, required: S, autoComplete: Pe = "off", autoCapitalize: Fe, autoCorrect: Ie, maxLength: Le, readOnly: C, labels: w, inputMode: Re, spellCheck: ze, enterKeyHint: Be, autoFocus: Ve, tabIndex: He, id: Ue, "aria-label": We, "aria-labelledby": Ge, "aria-describedby": Ke, "aria-invalid": qe, "aria-required": Je, "aria-errormessage": Ye, "aria-details": Xe, onFocus: Ze, onBlur: Qe, onKeyDown: $e, onKeyUp: et, controlRef: tt, className: nt, ref: rt, ...it } = l;
|
|
69
|
+
v !== void 0 && t("TagPicker", "onChange", "onValueChange");
|
|
70
|
+
let T = re(), at = (S ?? T?.required ?? !1) && !C, E = ie({
|
|
71
|
+
id: Ue,
|
|
72
|
+
"aria-label": We,
|
|
73
|
+
"aria-labelledby": Ge,
|
|
74
|
+
"aria-describedby": Ke,
|
|
75
|
+
"aria-invalid": qe,
|
|
76
|
+
"aria-required": Je ?? S
|
|
77
|
+
}), ot = ue(!1, E["aria-invalid"]), { size: D, appearance: O } = le(je, Me, {
|
|
78
|
+
sizes: be,
|
|
79
|
+
defaultSize: "medium"
|
|
80
|
+
}), k = xe[D], [A, j] = a(p, _ ?? f, (e) => {
|
|
54
81
|
let t = [...e];
|
|
55
|
-
|
|
56
|
-
}),
|
|
57
|
-
|
|
58
|
-
|
|
82
|
+
Ce?.(t), v?.(t);
|
|
83
|
+
}), M = !b && !C, [N, P] = a(we, (Te ?? !1) && M, Ee), st = te(), F = N && M && st, [ct, I] = a(Oe, M ? ke ?? "" : "", Ae), L = M ? ct : "", [R, z] = m.useState(M ? "unlocked" : "mounted-locked");
|
|
84
|
+
M && R !== "unlocked" ? z("unlocked") : !M && R === "unlocked" && z("locked"), m.useEffect(() => {
|
|
85
|
+
R === "locked" && I("");
|
|
86
|
+
}, [R, I]);
|
|
87
|
+
let B = !M && N;
|
|
59
88
|
m.useEffect(() => {
|
|
60
|
-
|
|
61
|
-
}, [
|
|
62
|
-
let
|
|
89
|
+
B && P(!1);
|
|
90
|
+
}, [B, P]), ae();
|
|
91
|
+
let V = m.useRef(null), H = m.useRef(null), U = o("tagpicker-summary"), W = m.useMemo(() => {
|
|
63
92
|
let e = /* @__PURE__ */ new Map();
|
|
64
|
-
for (let t of
|
|
93
|
+
for (let t of u) e.has(t.value) || e.set(t.value, t.label);
|
|
65
94
|
return e;
|
|
66
|
-
}, [
|
|
67
|
-
let e = new Set(
|
|
68
|
-
return
|
|
95
|
+
}, [u]), G = (e) => W.get(e) ?? e, lt = m.useMemo(() => {
|
|
96
|
+
let e = new Set(A);
|
|
97
|
+
return u.filter((t) => !e.has(t.value)).map((e) => ({
|
|
69
98
|
value: e.value,
|
|
70
99
|
label: e.label
|
|
71
100
|
}));
|
|
72
|
-
}, [
|
|
101
|
+
}, [u, A]), ut = m.useMemo(() => L ? (e) => (y ?? ye)(e, L) : void 0, [L, y]), K = A.filter((e) => !W.has(e)).join("\0");
|
|
73
102
|
m.useEffect(() => {
|
|
74
103
|
K && n("TagPicker:unknown-value", `TagPicker: the selected value(s) ${K.split("\0").map((e) => `"${e}"`).join(", ")} match no option; the raw value is shown as the tag label.`);
|
|
75
104
|
}, [K]);
|
|
76
|
-
let
|
|
77
|
-
if (!
|
|
78
|
-
let t = [...
|
|
79
|
-
|
|
105
|
+
let dt = () => H.current, q = () => H.current?.focus(), ft = (e) => {
|
|
106
|
+
if (!M || A.includes(e)) return;
|
|
107
|
+
let t = [...A, e];
|
|
108
|
+
j(t), I(""), d(w, G(e), !0, t.length);
|
|
80
109
|
}, J = (e) => {
|
|
81
|
-
if (!
|
|
82
|
-
let t =
|
|
83
|
-
|
|
84
|
-
}, Y =
|
|
85
|
-
open:
|
|
86
|
-
onOpenChange: (e) =>
|
|
110
|
+
if (!M) return;
|
|
111
|
+
let t = A.filter((t) => t !== e);
|
|
112
|
+
j(t), d(w, G(e), !1, t.length), q();
|
|
113
|
+
}, Y = oe({
|
|
114
|
+
open: F,
|
|
115
|
+
onOpenChange: (e) => P(e),
|
|
87
116
|
mode: "editable",
|
|
88
|
-
|
|
89
|
-
selectedValues:
|
|
90
|
-
onSelect: (e) =>
|
|
91
|
-
items:
|
|
92
|
-
filter:
|
|
117
|
+
multiselect: !0,
|
|
118
|
+
selectedValues: A,
|
|
119
|
+
onSelect: (e) => ft(e),
|
|
120
|
+
items: lt,
|
|
121
|
+
filter: ut,
|
|
93
122
|
autoHighlight: L ? "first" : !1,
|
|
94
123
|
idPrefix: "tagpicker-listbox",
|
|
95
|
-
onClearDraft: L ? () =>
|
|
96
|
-
}), X =
|
|
97
|
-
open:
|
|
124
|
+
onClearDraft: L ? () => I("") : void 0
|
|
125
|
+
}), X = F && Y.items.length > 0, Z = w?.noMatches ?? "No matches", Q = F && (X || L !== ""), pt = Q && !X, { layerId: mt, setReference: ht, surfaceRef: gt, floatingProps: _t } = he({
|
|
126
|
+
open: F,
|
|
98
127
|
surfaceOpen: Q,
|
|
99
|
-
onDismiss: () =>
|
|
128
|
+
onDismiss: () => P(!1),
|
|
100
129
|
rootRef: V,
|
|
101
130
|
anchorRef: H
|
|
102
|
-
}),
|
|
103
|
-
|
|
104
|
-
let e =
|
|
105
|
-
|
|
131
|
+
}), vt = c(V, rt), yt = c(H, tt);
|
|
132
|
+
de(H, () => {
|
|
133
|
+
let e = _ ?? f;
|
|
134
|
+
j((t) => ge(t, e) ? t : [...e]), I("");
|
|
106
135
|
}, x);
|
|
107
|
-
let $ = (e) => Array.from(e.closest("[data-wave-tagpicker-control]")?.querySelectorAll("[data-wave-tagpicker-remove]") ?? []),
|
|
108
|
-
if (
|
|
109
|
-
if (e.key === "Escape" &&
|
|
110
|
-
|
|
136
|
+
let $ = (e) => Array.from(e.closest("[data-wave-tagpicker-control]")?.querySelectorAll("[data-wave-tagpicker-remove]") ?? []), bt = (e) => {
|
|
137
|
+
if (M) {
|
|
138
|
+
if (e.key === "Escape" && F && !Q && !e.nativeEvent.isComposing) {
|
|
139
|
+
P(!1);
|
|
111
140
|
return;
|
|
112
141
|
}
|
|
113
|
-
if (e.key === "Backspace" && L === "" &&
|
|
142
|
+
if (e.key === "Backspace" && L === "" && A.length > 0) {
|
|
114
143
|
e.preventDefault(), $(e.currentTarget).at(-1)?.focus();
|
|
115
144
|
return;
|
|
116
145
|
}
|
|
117
146
|
Y.onKeyDown(e);
|
|
118
147
|
}
|
|
119
|
-
},
|
|
120
|
-
if (!
|
|
148
|
+
}, xt = (e, t) => {
|
|
149
|
+
if (!M) return;
|
|
121
150
|
let n = $(e.currentTarget), r = n.indexOf(e.currentTarget);
|
|
122
151
|
if (e.key === "Backspace" || e.key === "Delete") {
|
|
123
152
|
e.preventDefault(), J(t);
|
|
@@ -132,122 +161,124 @@ var v = (d) => {
|
|
|
132
161
|
dir: ee(e.currentTarget)
|
|
133
162
|
});
|
|
134
163
|
i === "prev" && r > 0 ? (e.preventDefault(), n[r - 1].focus()) : i === "next" && (e.preventDefault(), r < n.length - 1 ? n[r + 1].focus() : q());
|
|
135
|
-
},
|
|
164
|
+
}, St = E["aria-label"] === void 0 ? E["aria-labelledby"] ?? T?.labelId : E["aria-labelledby"];
|
|
136
165
|
return /* @__PURE__ */ g("div", {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
166
|
+
"data-size": D,
|
|
167
|
+
"data-appearance": O,
|
|
168
|
+
...it,
|
|
169
|
+
ref: vt,
|
|
170
|
+
className: e(i.root, "relative", nt),
|
|
140
171
|
children: [
|
|
141
172
|
/* @__PURE__ */ g("div", {
|
|
142
|
-
ref:
|
|
173
|
+
ref: ht,
|
|
143
174
|
"data-wave-tagpicker-control": "",
|
|
144
175
|
role: "group",
|
|
145
176
|
"aria-disabled": b || void 0,
|
|
146
|
-
className: e(i.control, "flex flex-wrap items-center
|
|
177
|
+
className: e(i.control, "flex flex-wrap items-center", k.control, se[O], ce, ot && "border-destructive", b && "cursor-not-allowed opacity-50"),
|
|
147
178
|
onClick: (e) => {
|
|
148
|
-
b || e.target.closest("button") || (q(), !
|
|
179
|
+
b || e.target.closest("button") || (q(), !F && M && P(!0));
|
|
149
180
|
},
|
|
150
181
|
children: [
|
|
151
|
-
|
|
182
|
+
A.length > 0 && /* @__PURE__ */ h("div", {
|
|
152
183
|
role: "list",
|
|
153
|
-
"aria-label":
|
|
184
|
+
"aria-label": w?.selected ?? "Selected",
|
|
154
185
|
className: e(i.group, "flex flex-wrap items-center gap-1"),
|
|
155
|
-
children:
|
|
186
|
+
children: A.map((t) => {
|
|
156
187
|
let n = G(t);
|
|
157
188
|
return /* @__PURE__ */ g("div", {
|
|
158
189
|
role: "listitem",
|
|
159
|
-
className: e(i.tag, "inline-flex items-center gap-1 rounded bg-muted
|
|
160
|
-
children: [n, !
|
|
161
|
-
label: (
|
|
190
|
+
className: e(i.tag, "inline-flex items-center gap-1 rounded bg-muted text-foreground", k.tag),
|
|
191
|
+
children: [n, !C && /* @__PURE__ */ h(Se, {
|
|
192
|
+
label: (w?.remove ?? _e)(n),
|
|
162
193
|
disabled: b,
|
|
163
194
|
onClick: () => J(t),
|
|
164
|
-
onKeyDown: (e) =>
|
|
165
|
-
getFallback:
|
|
195
|
+
onKeyDown: (e) => xt(e, t),
|
|
196
|
+
getFallback: dt
|
|
166
197
|
})]
|
|
167
198
|
}, t);
|
|
168
199
|
})
|
|
169
200
|
}),
|
|
170
|
-
|
|
201
|
+
A.length > 0 && /* @__PURE__ */ h("span", {
|
|
171
202
|
id: U,
|
|
172
203
|
hidden: !0,
|
|
173
|
-
children: (
|
|
204
|
+
children: (w?.summary ?? ve)(A.map(G))
|
|
174
205
|
}),
|
|
175
206
|
/* @__PURE__ */ h("input", {
|
|
176
207
|
type: "text",
|
|
177
|
-
autoComplete:
|
|
178
|
-
...
|
|
208
|
+
autoComplete: Pe,
|
|
209
|
+
...E,
|
|
179
210
|
...Y.getComboboxProps(),
|
|
180
211
|
"aria-expanded": X,
|
|
181
|
-
"aria-describedby": ne(
|
|
182
|
-
"aria-errormessage":
|
|
183
|
-
"aria-details":
|
|
184
|
-
ref:
|
|
212
|
+
"aria-describedby": ne(E["aria-describedby"], A.length > 0 ? U : void 0),
|
|
213
|
+
"aria-errormessage": Ye,
|
|
214
|
+
"aria-details": Xe,
|
|
215
|
+
ref: yt,
|
|
185
216
|
disabled: b,
|
|
186
|
-
readOnly:
|
|
187
|
-
placeholder:
|
|
188
|
-
autoCapitalize:
|
|
189
|
-
autoCorrect:
|
|
190
|
-
maxLength:
|
|
191
|
-
inputMode:
|
|
192
|
-
spellCheck:
|
|
193
|
-
enterKeyHint:
|
|
194
|
-
autoFocus:
|
|
195
|
-
tabIndex:
|
|
217
|
+
readOnly: C,
|
|
218
|
+
placeholder: A.length === 0 ? De : "",
|
|
219
|
+
autoCapitalize: Fe,
|
|
220
|
+
autoCorrect: Ie,
|
|
221
|
+
maxLength: Le,
|
|
222
|
+
inputMode: Re,
|
|
223
|
+
spellCheck: ze,
|
|
224
|
+
enterKeyHint: Be,
|
|
225
|
+
autoFocus: Ve,
|
|
226
|
+
tabIndex: He,
|
|
196
227
|
value: L,
|
|
197
228
|
onChange: (e) => {
|
|
198
|
-
|
|
229
|
+
M && (I(e.target.value), F || P(!0));
|
|
199
230
|
},
|
|
200
|
-
onKeyDown: r(
|
|
201
|
-
onKeyUp: r(
|
|
202
|
-
onFocus:
|
|
203
|
-
onBlur:
|
|
204
|
-
className: e(i.input, "min-w-15 flex-1 bg-transparent
|
|
231
|
+
onKeyDown: r($e, bt),
|
|
232
|
+
onKeyUp: r(et, Y.onKeyUp),
|
|
233
|
+
onFocus: Ze,
|
|
234
|
+
onBlur: Qe,
|
|
235
|
+
className: e(i.input, "min-w-15 flex-1 bg-transparent text-foreground placeholder:text-muted-foreground focus:outline-hidden", k.input)
|
|
205
236
|
})
|
|
206
237
|
]
|
|
207
238
|
}),
|
|
208
239
|
/* @__PURE__ */ h("span", {
|
|
209
240
|
role: "status",
|
|
210
241
|
className: "sr-only",
|
|
211
|
-
children:
|
|
242
|
+
children: pt && Z
|
|
212
243
|
}),
|
|
213
|
-
/* @__PURE__ */ h(
|
|
244
|
+
/* @__PURE__ */ h(pe, {
|
|
214
245
|
listbox: Y,
|
|
215
|
-
layerId:
|
|
216
|
-
surfaceRef:
|
|
217
|
-
floatingProps:
|
|
218
|
-
open:
|
|
246
|
+
layerId: mt,
|
|
247
|
+
surfaceRef: gt,
|
|
248
|
+
floatingProps: _t,
|
|
249
|
+
open: F,
|
|
219
250
|
expanded: X,
|
|
220
251
|
showCheck: !1,
|
|
221
|
-
|
|
252
|
+
listClassName: i.listbox,
|
|
222
253
|
surfaceClassName: i.surface,
|
|
223
254
|
emptyContent: L === "" ? void 0 : /* @__PURE__ */ h("div", {
|
|
224
255
|
"aria-hidden": "true",
|
|
225
256
|
className: e(i.emptyMessage, "px-3 py-1.5 text-body-1 text-muted-foreground"),
|
|
226
257
|
children: Z
|
|
227
258
|
}),
|
|
228
|
-
"aria-label":
|
|
229
|
-
"aria-labelledby":
|
|
230
|
-
children: X && Y.items.map((e) => /* @__PURE__ */ h(
|
|
259
|
+
"aria-label": E["aria-label"],
|
|
260
|
+
"aria-labelledby": St,
|
|
261
|
+
children: X && Y.items.map((e) => /* @__PURE__ */ h(me, {
|
|
231
262
|
value: e.value,
|
|
232
263
|
label: e.label,
|
|
233
264
|
className: i.option,
|
|
234
265
|
children: e.label
|
|
235
266
|
}, e.value))
|
|
236
267
|
}),
|
|
237
|
-
/* @__PURE__ */ h(
|
|
238
|
-
name:
|
|
268
|
+
/* @__PURE__ */ h(fe, {
|
|
269
|
+
name: Ne,
|
|
239
270
|
form: x,
|
|
240
271
|
disabled: b,
|
|
241
|
-
value:
|
|
272
|
+
value: A,
|
|
242
273
|
type: "text",
|
|
243
|
-
required:
|
|
274
|
+
required: at,
|
|
244
275
|
onInvalid: q
|
|
245
276
|
})
|
|
246
277
|
]
|
|
247
278
|
});
|
|
248
279
|
};
|
|
249
|
-
|
|
280
|
+
_.displayName = "TagPicker";
|
|
250
281
|
//#endregion
|
|
251
|
-
export {
|
|
282
|
+
export { _ as TagPicker };
|
|
252
283
|
|
|
253
284
|
//# sourceMappingURL=TagPicker.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TagPicker.mjs","names":["useId","useId$1","React","defaultRemoveLabel","label","defaultSummaryLabel","labels","defaultAddedLabel","count","defaultRemovedLabel","EMPTY","sameTags","a","b","value","index","TagRemoveButton","ref","usePreserveFocus","getFallback","cn","tagPickerClassNames","focusRing","DismissIcon","TagPicker","valueProp","openProp","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","ariaErrorMessage","ariaDetails","rest","props","onChange","warnDeprecated","field","useFieldContext","validates","required","readOnly","fieldProps","useFieldControl","invalidLook","isInvalidLook","selected","setSelected","useControllable","defaultValue","list","next","onValueChange","interactive","disabled","openState","setOpen","defaultOpen","onOpenChange","isClient","useIsClient","open","query","setQuery","wasInteractive","setWasInteractive","lockedOpen","announce","useAnnounce","rootRef","inputRef","summaryId","labelByValue","map","option","options","labelOf","available","chosen","filter","item","unknownValues","warnOnce","v","getInput","focusInput","addTag","removeTag","listbox","useListbox","expanded","noMatchesText","surfaceOpen","noMatches","useListboxPopup","rootMergedRef","useMergedRefs","inputMergedRef","controlRef","initial","current","form","removeButtons","from","handleInputKeyDown","event","handleTagKeyDown","buttons","intent","getArrowIntent","getDirection","listLabelledBy","className","setReference","inputFocusWithin","joinIds","placeholder","composeEventHandlers","onKeyDown","onKeyUp","ListboxSurface","Option","HiddenInput"],"sources":["../../../src/components/input/TagPicker.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { joinIds } from '../../lib/aria';\nimport { tagPickerClassNames } from '../../lib/classNames';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { warnDeprecated, warnOnce } from '../../lib/dev';\nimport { getArrowIntent, getDirection } from '../../lib/direction';\nimport { DismissIcon } from '../../lib/icons';\nimport { focusRing, inputFocusWithin, inputInvalidWithin } from '../../lib/styles';\nimport { useAnnounce } from '../../hooks/useAnnounce';\nimport { useControllable } from '../../hooks/useControllable';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useId } from '../../hooks/useId';\nimport { useIsClient } from '../../hooks/useIsClient';\nimport { useListbox, type ListboxItem } from '../../hooks/useListbox';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { usePreserveFocus } from '../../hooks/usePreserveFocus';\nimport { HiddenInput } from '../internal/HiddenInput';\nimport { isInvalidLook } from './Input';\nimport { ListboxSurface, Option, useListboxPopup } from './Option';\nimport type { RoutedHandlers } from './routedHandlers';\n\n/** Represents a single selectable tag option. */\nexport interface TagPickerOption {\n /** Unique identifier for the option. */\n value: string;\n /** Display label for the option. */\n label: string;\n}\n\n/**\n * The TagPicker's built-in names, descriptions and announcements, for localization. Each member is\n * optional and falls back to its English default.\n */\nexport interface TagPickerLabels {\n /** Name of a tag's remove button.\n * @default (label) => `Remove ${label}`\n */\n remove?: (label: string) => string;\n /** Name of the list of selected tags.\n * @default 'Selected'\n */\n selected?: string;\n /** Description of the input that sums up the selected tags (their labels, in order).\n * @default (labels) => `Selected: ${labels.join(', ')}`\n */\n summary?: (labels: string[]) => string;\n /** Announcement when a tag is added; `count` is the number of tags after the change.\n * @default (label, count) => `${label} added, ${count} selected`\n */\n added?: (label: string, count: number) => string;\n /** Announcement when a tag is removed; `count` is the number of tags after the change.\n * @default (label, count) => `${label} removed, ${count} selected`\n */\n removed?: (label: string, count: number) => string;\n /** Status text (announced, and shown in the popup) when the typed text matches no option.\n * @default 'No matches'\n */\n noMatches?: string;\n}\n\nconst defaultRemoveLabel = (label: string) => `Remove ${label}`;\nconst defaultSummaryLabel = (labels: string[]) => `Selected: ${labels.join(', ')}`;\nconst defaultAddedLabel = (label: string, count: number) => `${label} added, ${count} selected`;\nconst defaultRemovedLabel = (label: string, count: number) => `${label} removed, ${count} selected`;\n\n/** Properties for the TagPicker component. */\nexport interface TagPickerProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'defaultValue' | RoutedHandlers\n> {\n /** Available options to choose from. */\n options: readonly TagPickerOption[];\n /** Controlled array of selected option values (`[]` for none). */\n value?: readonly string[];\n /**\n * Initial selected values for uncontrolled usage; a form reset restores them.\n * @default []\n */\n defaultValue?: readonly string[];\n /**\n * Called with the new selection when it changes: a tag is added or removed, or a form reset\n * restores different tags.\n */\n onValueChange?: (value: string[]) => void;\n /**\n * Called with the new selection when it changes: a tag is added or removed, or a form reset\n * restores different tags.\n * @deprecated Use `onValueChange`.\n */\n onChange?: (value: string[]) => void;\n /**\n * Controlled open state of the option list. The list renders only in the browser: an open\n * picker is closed in the server HTML and opens once it has hydrated.\n */\n open?: boolean;\n /**\n * Initial open state for uncontrolled usage. A picker that starts disabled or read-only starts\n * closed. The list renders only in the browser: it is closed in the server HTML and opens once\n * the picker has hydrated.\n * @default false\n */\n defaultOpen?: boolean;\n /** Called when the option list opens or closes. */\n onOpenChange?: (open: boolean) => void;\n /**\n * Placeholder text shown when no tags are selected.\n * @default 'Select...'\n */\n placeholder?: string;\n /**\n * Whether the tag picker is disabled: nothing can be added or removed, and the remove buttons\n * leave the tab order.\n * @default false\n */\n disabled?: boolean;\n /** Name of the values in form submissions (one hidden input per value). */\n name?: string;\n /** Id of the form the values belong to, when the TagPicker is outside it. */\n form?: string;\n /**\n * At least one tag is required to submit the form (native constraint validation). Like a native\n * readonly input, a `readOnly` TagPicker does not block submission.\n */\n required?: boolean;\n /**\n * The `autocomplete` attribute of the `<input role=\"combobox\">`. Browser autofill is off unless\n * you set it (for example `'on'`).\n * @default 'off'\n */\n autoComplete?: string;\n /** The maximum length of the typed text (`maxlength` of the `<input role=\"combobox\">`). */\n maxLength?: number;\n /**\n * The selection cannot be changed: the input is read-only, the tags have no remove buttons, and\n * the option list neither opens (click, keyboard, a controlled `open`) nor adds tags; Escape is\n * left to the page. Turning it (or `disabled`) on while the list is open closes it\n * (`onOpenChange(false)`); a focused remove button hands focus to the input.\n */\n readOnly?: boolean;\n /**\n * Names of the remove buttons and the tag list, the summary that describes the input, the\n * announcements and the \"No matches\" text, for localization. Unset members keep their English\n * defaults.\n */\n labels?: TagPickerLabels;\n /** Called when the `<input role=\"combobox\">` receives focus (the root keeps other handlers). */\n onFocus?: React.FocusEventHandler<HTMLInputElement>;\n /** Called when the `<input role=\"combobox\">` loses focus. */\n onBlur?: React.FocusEventHandler<HTMLInputElement>;\n /**\n * Called on a key press in the `<input role=\"combobox\">`, before the built-in listbox and tag\n * keys; `event.preventDefault()` skips them.\n */\n onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;\n /** Called when a key is released in the `<input role=\"combobox\">`. */\n onKeyUp?: React.KeyboardEventHandler<HTMLInputElement>;\n /** Ref to the `<input role=\"combobox\">` (the focusable element). */\n controlRef?: React.Ref<HTMLInputElement>;\n /** Ref to the root `<div>`. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\nconst EMPTY: readonly string[] = [];\n\n/** Whether two selections hold the same values in the same order. */\nfunction sameTags(a: readonly string[], b: readonly string[]): boolean {\n return a.length === b.length && a.every((value, index) => value === b[index]);\n}\n\ninterface TagRemoveButtonProps {\n /** The accessible name of the button. */\n label: string;\n disabled: boolean;\n onClick: () => void;\n onKeyDown: React.KeyboardEventHandler<HTMLButtonElement>;\n /** The element that receives focus when this button unmounts while focused (the input). */\n getFallback: () => HTMLElement | null;\n}\n\n/**\n * A tag's remove button. When it unmounts while focused (`readOnly` turned on, or a controlled\n * value dropped its tag), focus moves to the input instead of falling to `<body>` (C-DISABLED).\n */\nfunction TagRemoveButton({\n label,\n disabled,\n onClick,\n onKeyDown,\n getFallback,\n}: TagRemoveButtonProps) {\n const ref = React.useRef<HTMLButtonElement | null>(null);\n usePreserveFocus(ref, getFallback);\n return (\n <button\n ref={ref}\n type=\"button\"\n data-wave-tagpicker-remove=\"\"\n disabled={disabled}\n aria-label={label}\n className={cn(\n tagPickerClassNames.removeButton,\n // Padding and background set here (C-NATIVE), not left to an app-wide rule.\n 'ms-0.5 inline-flex rounded-sm bg-transparent p-0 text-muted-foreground not-disabled:not-aria-disabled:hover:text-foreground disabled:cursor-not-allowed',\n focusRing,\n )}\n onClick={onClick}\n onKeyDown={onKeyDown}\n >\n <DismissIcon size={12} />\n </button>\n );\n}\n\n/**\n * A multi-select combobox that shows the selected values as removable tags. Typing filters the\n * options and makes the first match active; ArrowDown/ArrowUp move the highlight\n * (`aria-activedescendant`), Enter adds the highlighted option and keeps the list open (with\n * nothing highlighted — no typed text, or text that matches no option — Enter is left to the\n * surrounding form), Escape closes the list (and then clears the typed text). Backspace in the\n * empty input moves focus to the last tag; Backspace or Delete there removes it. Additions and\n * removals are announced (\"Cherry removed, 2 selected\"), and so is \"No matches\" for text that\n * matches no option.\n *\n * The tags form a list named \"Selected\"; the input is described by a summary of the selected\n * labels (\"Selected: Apple, Banana\"). These built-in texts are English; `labels` localizes them.\n * The `<input>` receives `id`, `aria-label`, `aria-labelledby`, `aria-describedby`,\n * `aria-invalid`, `aria-required`, `aria-errormessage`, `aria-details`, `tabIndex`, `autoFocus`,\n * `onFocus`/`onBlur`/`onKeyDown`/`onKeyUp` and the text input attributes `autoComplete`,\n * `autoCapitalize`, `autoCorrect`, `maxLength`, `inputMode`, `spellCheck` and `enterKeyHint`.\n * `ref`, `className`, `style`, other `aria-*` attributes and the remaining props stay on the root\n * `<div>`. Inside a `Field` the input is labelled and described by it. The tag area shows the\n * error look whenever the input ends up `aria-invalid` (its own `aria-invalid` or a `Field`\n * error). With `name`/`required` the values take part in form submission, validation and reset.\n * Selected values without a matching option are shown with their raw value. The open list renders\n * only in the browser: an open list (`defaultOpen`, `open`) is closed in the server HTML and opens\n * once the picker has hydrated.\n */\nexport const TagPicker = (props: TagPickerProps) => {\n const {\n options,\n value: valueProp,\n defaultValue,\n onValueChange,\n onChange,\n open: openProp,\n defaultOpen,\n onOpenChange,\n placeholder = 'Select...',\n disabled = false,\n name,\n form,\n required,\n autoComplete = 'off',\n autoCapitalize,\n autoCorrect,\n maxLength,\n readOnly,\n labels,\n inputMode,\n spellCheck,\n enterKeyHint,\n autoFocus,\n tabIndex,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n 'aria-errormessage': ariaErrorMessage,\n 'aria-details': ariaDetails,\n onFocus,\n onBlur,\n onKeyDown,\n onKeyUp,\n controlRef,\n className,\n ref,\n ...rest\n } = props;\n\n if (onChange !== undefined) warnDeprecated('TagPicker', 'onChange', 'onValueChange');\n\n const field = useFieldContext();\n const isRequired = required ?? field?.required ?? false;\n // Like a native readonly input, a read-only TagPicker is barred from constraint validation (the\n // user could not fix it); its values are still submitted.\n const validates = isRequired && !readOnly;\n const fieldProps = useFieldControl({\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n // An explicit `required={false}` wins over a required Field, so aria-required matches\n // `isRequired`.\n 'aria-required': ariaRequired ?? required,\n });\n // The error look follows the resolved state: the consumer's `aria-invalid` or the Field's.\n const invalidLook = isInvalidLook(false, fieldProps['aria-invalid']);\n\n const [selected, setSelected] = useControllable<readonly string[]>(\n valueProp,\n defaultValue ?? EMPTY,\n (next) => {\n // The props are read only; the callbacks receive an array of their own.\n const list = [...next];\n onValueChange?.(list);\n onChange?.(list);\n },\n );\n const interactive = !disabled && !readOnly;\n // A picker that starts disabled or read-only never shows its list, so it starts closed (no close\n // to report later).\n const [openState, setOpen] = useControllable(\n openProp,\n (defaultOpen ?? false) && interactive,\n onOpenChange,\n );\n // The open list lives in a portal, which renders only in the browser: until then (the server\n // HTML, hydration) the picker shows the closed inline list and reports it closed, so\n // aria-controls and aria-activedescendant never name a missing element.\n const isClient = useIsClient();\n const open = openState && interactive && isClient;\n const [query, setQuery] = React.useState('');\n // Locking the control (readOnly/disabled) while typing drops the typed text (adjust-during-render\n // pattern, C-HOOKS).\n const [wasInteractive, setWasInteractive] = React.useState(interactive);\n if (wasInteractive !== interactive) {\n setWasInteractive(interactive);\n if (!interactive) setQuery('');\n }\n // Locking also closes the list itself, not only the derived `open`, so unlocking does not reopen\n // it without a user action. The close is reported through onOpenChange (a consumer callback from\n // an effect, C-HOOKS); a controlled `open` that stays true is still not shown while locked.\n const lockedOpen = !interactive && openState;\n React.useEffect(() => {\n if (lockedOpen) setOpen(false);\n }, [lockedOpen, setOpen]);\n const announce = useAnnounce();\n\n const rootRef = React.useRef<HTMLDivElement | null>(null);\n const inputRef = React.useRef<HTMLInputElement | null>(null);\n const summaryId = useId('tagpicker-summary');\n\n const labelByValue = React.useMemo(() => {\n const map = new Map<string, string>();\n for (const option of options) if (!map.has(option.value)) map.set(option.value, option.label);\n return map;\n }, [options]);\n const labelOf = (value: string) => labelByValue.get(value) ?? value;\n\n const available = React.useMemo<ListboxItem[]>(() => {\n const chosen = new Set(selected);\n return options\n .filter((option) => !chosen.has(option.value))\n .map((option) => ({ value: option.value, label: option.label }));\n }, [options, selected]);\n const filter = React.useMemo(\n () =>\n query\n ? (item: ListboxItem) => item.label.toLowerCase().includes(query.toLowerCase())\n : undefined,\n [query],\n );\n\n // Unknown values render as tags labelled by the raw value (input-pickers#22).\n const unknownValues = selected.filter((value) => !labelByValue.has(value)).join('\\u0000');\n React.useEffect(() => {\n if (!unknownValues) return;\n warnOnce(\n 'TagPicker:unknown-value',\n `TagPicker: the selected value(s) ${unknownValues\n .split('\\u0000')\n .map((v) => `\"${v}\"`)\n .join(', ')} match no option; the raw value is shown as the tag label.`,\n );\n }, [unknownValues]);\n\n const getInput = () => inputRef.current;\n const focusInput = () => inputRef.current?.focus();\n\n const addTag = (value: string) => {\n if (!interactive || selected.includes(value)) return;\n const next = [...selected, value];\n setSelected(next);\n setQuery('');\n announce((labels?.added ?? defaultAddedLabel)(labelOf(value), next.length));\n };\n\n const removeTag = (value: string) => {\n if (!interactive) return;\n const next = selected.filter((v) => v !== value);\n setSelected(next);\n announce((labels?.removed ?? defaultRemovedLabel)(labelOf(value), next.length));\n focusInput();\n };\n\n const listbox = useListbox({\n open,\n onOpenChange: (next) => setOpen(next),\n mode: 'editable',\n multiple: true,\n selectedValues: selected,\n onSelect: (value) => addTag(value),\n items: available,\n filter,\n // Typing a filter makes its first match active (as in Combobox), so Enter adds what the list\n // shows instead of submitting the form. Nothing is active on open or with the text cleared.\n autoHighlight: query ? 'first' : false,\n idPrefix: 'tagpicker-listbox',\n onClearDraft: query ? () => setQuery('') : undefined,\n });\n\n // aria-expanded only while a listbox with options is shown (input-pickers#21).\n const expanded = open && listbox.items.length > 0;\n const noMatchesText = labels?.noMatches ?? 'No matches';\n // The popup shows the options, or \"No matches\" for a query.\n const surfaceOpen = open && (expanded || query !== '');\n const noMatches = surfaceOpen && !expanded;\n const { layerId, setReference, surfaceRef, floatingProps } = useListboxPopup({\n open,\n surfaceOpen,\n onDismiss: () => setOpen(false),\n rootRef,\n anchorRef: inputRef,\n });\n\n const rootMergedRef = useMergedRefs<HTMLDivElement>(rootRef, ref);\n const inputMergedRef = useMergedRefs<HTMLInputElement>(inputRef, controlRef);\n\n useFormReset(\n inputRef,\n () => {\n // Compared by content (C-FORMS): an inline default is a new array on every render, and a\n // reset that keeps the same tags reports nothing.\n const initial = defaultValue ?? EMPTY;\n setSelected((current) => (sameTags(current, initial) ? current : [...initial]));\n setQuery('');\n },\n form,\n );\n\n /** The tags' remove buttons, found from an element inside the component (no ref read). */\n const removeButtons = (from: Element) =>\n Array.from(\n from\n .closest('[data-wave-tagpicker-control]')\n ?.querySelectorAll<HTMLButtonElement>('[data-wave-tagpicker-remove]') ?? [],\n );\n\n const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n // Read-only: no listbox keys at all (they would open the list, add or remove tags).\n if (!interactive) return;\n if (event.key === 'Escape' && open && !surfaceOpen && !event.nativeEvent.isComposing) {\n // Open with nothing shown (every option selected, no query): close, but leave Escape to an\n // enclosing layer (overlays#1) instead of consuming it for an invisible list.\n setOpen(false);\n return;\n }\n if (event.key === 'Backspace' && query === '' && selected.length > 0) {\n // First Backspace moves to the last tag; Backspace/Delete there removes it (input-pickers#14).\n event.preventDefault();\n removeButtons(event.currentTarget).at(-1)?.focus();\n return;\n }\n listbox.onKeyDown(event);\n };\n\n const handleTagKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>, value: string) => {\n if (!interactive) return;\n const buttons = removeButtons(event.currentTarget);\n const index = buttons.indexOf(event.currentTarget);\n if (event.key === 'Backspace' || event.key === 'Delete') {\n event.preventDefault();\n removeTag(value);\n return;\n }\n if (event.key === 'Escape') {\n // Consumed here, so an enclosing layer ignores it (spec §5.4).\n event.preventDefault();\n focusInput();\n return;\n }\n const intent = getArrowIntent(event.key, {\n orientation: 'horizontal',\n dir: getDirection(event.currentTarget),\n });\n if (intent === 'prev' && index > 0) {\n event.preventDefault();\n buttons[index - 1].focus();\n } else if (intent === 'next') {\n event.preventDefault();\n if (index < buttons.length - 1) buttons[index + 1].focus();\n else focusInput();\n }\n };\n\n const listLabelledBy =\n fieldProps['aria-label'] === undefined\n ? (fieldProps['aria-labelledby'] ?? field?.labelId)\n : fieldProps['aria-labelledby'];\n\n return (\n <div\n {...rest}\n ref={rootMergedRef}\n className={cn(tagPickerClassNames.root, 'relative', className)}\n >\n <div\n ref={setReference}\n data-wave-tagpicker-control=\"\"\n role=\"group\"\n aria-disabled={disabled || undefined}\n className={cn(\n tagPickerClassNames.control,\n 'flex flex-wrap items-center gap-1 rounded border border-input border-b-stroke-accessible bg-background px-2 py-1.5',\n inputFocusWithin,\n invalidLook && inputInvalidWithin,\n disabled && 'cursor-not-allowed opacity-50',\n )}\n onClick={(event) => {\n if (disabled || (event.target as Element).closest('button')) return;\n focusInput();\n if (!open && interactive) setOpen(true);\n }}\n >\n {selected.length > 0 && (\n <div\n role=\"list\"\n aria-label={labels?.selected ?? 'Selected'}\n className={cn(tagPickerClassNames.group, 'flex flex-wrap items-center gap-1')}\n >\n {selected.map((value) => {\n const label = labelOf(value);\n return (\n <div\n key={value}\n role=\"listitem\"\n className={cn(\n tagPickerClassNames.tag,\n 'inline-flex items-center gap-1 rounded bg-muted px-2 py-0.5 text-body-1 text-foreground',\n )}\n >\n {label}\n {!readOnly && (\n <TagRemoveButton\n label={(labels?.remove ?? defaultRemoveLabel)(label)}\n disabled={disabled}\n onClick={() => removeTag(value)}\n onKeyDown={(event) => handleTagKeyDown(event, value)}\n getFallback={getInput}\n />\n )}\n </div>\n );\n })}\n </div>\n )}\n {selected.length > 0 && (\n // Describes the input. The list itself would read every \"Remove …\" button name too.\n <span id={summaryId} hidden>\n {(labels?.summary ?? defaultSummaryLabel)(selected.map(labelOf))}\n </span>\n )}\n <input\n type=\"text\"\n autoComplete={autoComplete}\n {...fieldProps}\n {...listbox.getComboboxProps()}\n aria-expanded={expanded}\n aria-describedby={joinIds(\n fieldProps['aria-describedby'],\n selected.length > 0 ? summaryId : undefined,\n )}\n aria-errormessage={ariaErrorMessage}\n aria-details={ariaDetails}\n ref={inputMergedRef}\n disabled={disabled}\n readOnly={readOnly}\n placeholder={selected.length === 0 ? placeholder : ''}\n autoCapitalize={autoCapitalize}\n autoCorrect={autoCorrect}\n maxLength={maxLength}\n inputMode={inputMode}\n spellCheck={spellCheck}\n enterKeyHint={enterKeyHint}\n autoFocus={autoFocus}\n tabIndex={tabIndex}\n value={query}\n onChange={(event) => {\n if (!interactive) return;\n setQuery(event.target.value);\n if (!open) setOpen(true);\n }}\n onKeyDown={composeEventHandlers(onKeyDown, handleInputKeyDown)}\n onKeyUp={composeEventHandlers(onKeyUp, listbox.onKeyUp)}\n onFocus={onFocus}\n onBlur={onBlur}\n className={cn(\n tagPickerClassNames.input,\n 'min-w-15 flex-1 bg-transparent py-0.5 text-body-1 text-foreground placeholder:text-muted-foreground focus:outline-hidden',\n )}\n />\n </div>\n {/* Mounted before its text: a live region added together with its text is not announced by\n every screen reader. The row in the popup is the visible copy. */}\n <span role=\"status\" className=\"sr-only\">\n {noMatches && noMatchesText}\n </span>\n <ListboxSurface\n listbox={listbox}\n layerId={layerId}\n surfaceRef={surfaceRef}\n floatingProps={floatingProps}\n open={open}\n expanded={expanded}\n showCheck={false}\n listboxClassName={tagPickerClassNames.listbox}\n surfaceClassName={tagPickerClassNames.surface}\n emptyContent={\n query !== '' ? (\n <div\n aria-hidden=\"true\"\n className={cn(\n tagPickerClassNames.emptyMessage,\n 'px-3 py-1.5 text-body-1 text-muted-foreground',\n )}\n >\n {noMatchesText}\n </div>\n ) : undefined\n }\n aria-label={fieldProps['aria-label']}\n aria-labelledby={listLabelledBy}\n >\n {expanded &&\n listbox.items.map((item) => (\n <Option\n key={item.value}\n value={item.value}\n label={item.label}\n className={tagPickerClassNames.option}\n >\n {item.label}\n </Option>\n ))}\n </ListboxSurface>\n <HiddenInput\n name={name}\n form={form}\n disabled={disabled}\n value={selected}\n type=\"text\"\n required={validates}\n onInvalid={focusInput}\n />\n </div>\n );\n};\nTagPicker.displayName = 'TagPicker';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TagPicker.mjs","names":["useId","useId$1","React","defaultRemoveLabel","label","defaultSummaryLabel","labels","matchesText","item","text","TAG_PICKER_SIZES","TAG_PICKER_SIZE","TagRemoveButton","ref","usePreserveFocus","getFallback","cn","tagPickerClassNames","focusRing","DismissIcon","TagPicker","valueProp","openProp","queryProp","sizeProp","appearanceProp","ariaLabel","ariaLabelledBy","ariaDescribedBy","ariaInvalid","ariaRequired","ariaErrorMessage","ariaDetails","rest","props","onChange","warnDeprecated","field","useFieldContext","validates","required","readOnly","fieldProps","useFieldControl","invalidLook","isInvalidLook","useInputLook","sizeClasses","size","selected","setSelected","useControllable","defaultValue","EMPTY_VALUES","list","next","onValueChange","interactive","disabled","openState","setOpen","defaultOpen","onOpenChange","isClient","useIsClient","open","queryState","setQuery","defaultQuery","onQueryChange","query","lock","setLock","lockedOpen","useAnnounce","rootRef","inputRef","summaryId","labelByValue","map","option","options","labelOf","value","available","chosen","listFilter","filter","unknownValues","warnOnce","v","getInput","focusInput","addTag","announceToggle","removeTag","listbox","useListbox","expanded","noMatchesText","surfaceOpen","noMatches","useListboxPopup","rootMergedRef","useMergedRefs","inputMergedRef","controlRef","initial","sameValues","current","form","removeButtons","from","handleInputKeyDown","event","handleTagKeyDown","buttons","index","intent","getArrowIntent","getDirection","listLabelledBy","appearance","className","setReference","inputAppearanceClasses","inputFocusWithin","joinIds","placeholder","composeEventHandlers","onKeyDown","onKeyUp","ListboxSurface","Option","HiddenInput"],"sources":["../../../src/components/input/TagPicker.tsx"],"sourcesContent":["import * as React from 'react';\nimport { cn } from '../../lib/cn';\nimport { joinIds } from '../../lib/aria';\nimport { tagPickerClassNames } from '../../lib/classNames';\nimport { composeEventHandlers } from '../../lib/composeEventHandlers';\nimport { warnDeprecated, warnOnce } from '../../lib/dev';\nimport { getArrowIntent, getDirection } from '../../lib/direction';\nimport { DismissIcon } from '../../lib/icons';\nimport {\n focusRing,\n inputAppearanceClasses,\n inputFocusWithin,\n inputInvalidWithin,\n} from '../../lib/styles';\nimport type { InputAppearance, Size } from '../../lib/types';\nimport { useAnnounce } from '../../hooks/useAnnounce';\nimport { useControllable } from '../../hooks/useControllable';\nimport { useFieldContext, useFieldControl } from '../../hooks/useFieldControl';\nimport { useFormReset } from '../../hooks/useFormReset';\nimport { useId } from '../../hooks/useId';\nimport { useIsClient } from '../../hooks/useIsClient';\nimport { useListbox, type ListboxItem } from '../../hooks/useListbox';\nimport { useMergedRefs } from '../../hooks/useMergedRefs';\nimport { usePreserveFocus } from '../../hooks/usePreserveFocus';\nimport { HiddenInput } from '../internal/HiddenInput';\nimport { useInputLook } from './inputLook';\nimport { isInvalidLook } from './Input';\nimport { ListboxSurface, Option, useListboxPopup } from './Option';\nimport { announceToggle } from './pickerLabels';\nimport { EMPTY_VALUES, sameValues } from './pickerValues';\nimport type { RoutedHandlers } from './routedHandlers';\n\n/** Represents a single selectable tag option. */\nexport interface TagPickerOption {\n /** Unique identifier for the option. */\n value: string;\n /** Display label for the option. */\n label: string;\n}\n\n/**\n * The TagPicker's built-in names, descriptions and announcements, for localization. Each member is\n * optional and falls back to its English default.\n */\nexport interface TagPickerLabels {\n /** Name of a tag's remove button.\n * @default (label) => `Remove ${label}`\n */\n remove?: (label: string) => string;\n /** Name of the list of selected tags.\n * @default 'Selected'\n */\n selected?: string;\n /** Description of the input that sums up the selected tags (their labels, in order).\n * @default (labels) => `Selected: ${labels.join(', ')}`\n */\n summary?: (labels: string[]) => string;\n /** Announcement when a tag is added; `count` is the number of tags after the change.\n * @default (label, count) => `${label} added, ${count} selected`\n */\n added?: (label: string, count: number) => string;\n /** Announcement when a tag is removed; `count` is the number of tags after the change.\n * @default (label, count) => `${label} removed, ${count} selected`\n */\n removed?: (label: string, count: number) => string;\n /** Status text (announced, and shown in the popup) when the typed text matches no option.\n * @default 'No matches'\n */\n noMatches?: string;\n}\n\nconst defaultRemoveLabel = (label: string) => `Remove ${label}`;\nconst defaultSummaryLabel = (labels: string[]) => `Selected: ${labels.join(', ')}`;\n\n/**\n * How the picker came to be locked (`disabled` or `readOnly`): not at all, by a change while\n * mounted, or since it mounted.\n */\ntype LockState = 'unlocked' | 'locked' | 'mounted-locked';\n\n/** The default `filter` (0.7's match): a case-insensitive substring of the option's label. */\nfunction matchesText(item: ListboxItem, text: string): boolean {\n return item.label.toLowerCase().includes(text.toLowerCase());\n}\n\n/** Properties for the TagPicker component. */\nexport interface TagPickerProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n 'onChange' | 'defaultValue' | RoutedHandlers\n> {\n /** Available options to choose from. */\n options: readonly TagPickerOption[];\n /** Controlled array of selected option values (`[]` for none). */\n value?: readonly string[];\n /**\n * Initial selected values for uncontrolled usage; a form reset restores them.\n * @default []\n */\n defaultValue?: readonly string[];\n /**\n * Called with the new selection when it changes: a tag is added or removed, or a form reset\n * restores different tags.\n */\n onValueChange?: (value: string[]) => void;\n /**\n * Called with the new selection when it changes: a tag is added or removed, or a form reset\n * restores different tags.\n * @deprecated Use `onValueChange`.\n */\n onChange?: (value: string[]) => void;\n /**\n * Controlled open state of the option list. The list renders only in the browser: an open\n * picker is closed in the server HTML and opens once it has hydrated.\n */\n open?: boolean;\n /**\n * Initial open state for uncontrolled usage. A picker that starts disabled or read-only starts\n * closed. The list renders only in the browser: it is closed in the server HTML and opens once\n * the picker has hydrated.\n * @default false\n */\n defaultOpen?: boolean;\n /** Called when the option list opens or closes. */\n onOpenChange?: (open: boolean) => void;\n /**\n * Placeholder text shown when no tags are selected.\n * @default 'Select...'\n */\n placeholder?: string;\n /**\n * Whether an option matches the typed text (the query). Called with every listed option (its\n * `value` and `label`; selected options are not listed) and the text whenever the text is not\n * empty; an option it returns `false` for is filtered out. It may keep options that do not\n * contain the text: `filter={() => true}` with `query` and `onQueryChange` leaves the matching\n * to you (a server-side search that replaces `options`), and a filter that always keeps an\n * option of your own gives a \"Create …\" entry. With a server-side search, keep the selected\n * options in `options` (they are never listed): a selected value without an option shows its raw\n * value as the tag label, with a development warning (the \"Async search\" story does this).\n * @default a case-insensitive substring match on the option's `label`\n */\n filter?: (option: ListboxItem, query: string) => boolean;\n /**\n * Controlled query: the text typed since the last tag was added, which filters the options and\n * shows in the input (hidden while `disabled` or `readOnly`).\n */\n query?: string;\n /**\n * Initial query for uncontrolled usage. A TagPicker that starts disabled or read-only starts\n * without it (as it starts closed).\n * @default ''\n */\n defaultQuery?: string;\n /**\n * Called with the new query when it changes: as the user types, and with `''` when it resets (a\n * tag added, Escape on the closed list, a form reset, or `disabled` or `readOnly` turned on\n * while text is typed). A blur or a close keeps the text. A TagPicker that mounts disabled or\n * read-only reports nothing: it keeps a controlled query, which shows once it unlocks.\n */\n onQueryChange?: (query: string) => void;\n /**\n * Whether the tag picker is disabled: nothing can be added or removed, and the remove buttons\n * leave the tab order.\n * @default false\n */\n disabled?: boolean;\n /**\n * Size of the tags and the field: `medium` (the 0.7 look), `large` or `extra-large` (Fluent's\n * union; TagPicker has no `small`). Default: the surrounding Field's `size`, else `WaveProvider\n * inputDefaults.size`, else `'medium'`; a Field or provider `small` gives `'medium'` too. The\n * option list keeps its size.\n */\n size?: TagPickerSize;\n /**\n * Look of the field: `outline` (a full border), `underline` (a bottom stroke only),\n * `filled-darker` or `filled-lighter` (a fill without a visible stroke: give the field a visible\n * label). Default: `WaveProvider inputDefaults.appearance`, else `'outline'`.\n */\n appearance?: InputAppearance;\n /** Name of the values in form submissions (one hidden input per value). */\n name?: string;\n /** Id of the form the values belong to, when the TagPicker is outside it. */\n form?: string;\n /**\n * At least one tag is required to submit the form (native constraint validation). Like a native\n * readonly input, a `readOnly` TagPicker does not block submission.\n */\n required?: boolean;\n /**\n * The `autocomplete` attribute of the `<input role=\"combobox\">`. Browser autofill is off unless\n * you set it (for example `'on'`).\n * @default 'off'\n */\n autoComplete?: string;\n /** The maximum length of the typed text (`maxlength` of the `<input role=\"combobox\">`). */\n maxLength?: number;\n /**\n * The selection cannot be changed: the input is read-only, the tags have no remove buttons, and\n * the option list neither opens (click, keyboard, a controlled `open`) nor adds tags; Escape is\n * left to the page. Turning it (or `disabled`) on while the list is open closes it\n * (`onOpenChange(false)`); a focused remove button hands focus to the input.\n */\n readOnly?: boolean;\n /**\n * Names of the remove buttons and the tag list, the summary that describes the input, the\n * announcements and the \"No matches\" text, for localization. Unset members keep their English\n * defaults.\n */\n labels?: TagPickerLabels;\n /** Called when the `<input role=\"combobox\">` receives focus (the root keeps other handlers). */\n onFocus?: React.FocusEventHandler<HTMLInputElement>;\n /** Called when the `<input role=\"combobox\">` loses focus. */\n onBlur?: React.FocusEventHandler<HTMLInputElement>;\n /**\n * Called on a key press in the `<input role=\"combobox\">`, before the built-in listbox and tag\n * keys; `event.preventDefault()` skips them.\n */\n onKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;\n /** Called when a key is released in the `<input role=\"combobox\">`. */\n onKeyUp?: React.KeyboardEventHandler<HTMLInputElement>;\n /** Ref to the `<input role=\"combobox\">` (the focusable element). */\n controlRef?: React.Ref<HTMLInputElement>;\n /** Ref to the root `<div>`. */\n ref?: React.Ref<HTMLDivElement>;\n}\n\n/** Sizes of TagPicker (Fluent's): medium (the 0.7 look), large and extra-large. */\nexport type TagPickerSize = Extract<Size, 'medium' | 'large' | 'extra-large'>;\n\nconst TAG_PICKER_SIZES: readonly TagPickerSize[] = ['medium', 'large', 'extra-large'];\n\n/** Per-size classes of the control, the tags and the input (medium is the 0.7 look). */\nconst TAG_PICKER_SIZE: Readonly<\n Record<TagPickerSize, { control: string; tag: string; input: string }>\n> = {\n medium: {\n control: 'gap-1 px-2 py-1.5',\n tag: 'px-2 py-0.5 text-body-1',\n input: 'py-0.5 text-body-1',\n },\n large: {\n control: 'gap-1.5 px-2.5 py-2',\n tag: 'px-2 py-1 text-body-1',\n input: 'py-1 text-body-1',\n },\n 'extra-large': {\n control: 'gap-1.5 px-3 py-2.5',\n tag: 'px-2.5 py-1 text-body-2',\n input: 'py-1 text-body-2',\n },\n};\n\ninterface TagRemoveButtonProps {\n /** The accessible name of the button. */\n label: string;\n disabled: boolean;\n onClick: () => void;\n onKeyDown: React.KeyboardEventHandler<HTMLButtonElement>;\n /** The element that receives focus when this button unmounts while focused (the input). */\n getFallback: () => HTMLElement | null;\n}\n\n/**\n * A tag's remove button. When it unmounts while focused (`readOnly` turned on, or a controlled\n * value dropped its tag), focus moves to the input instead of falling to `<body>` (C-DISABLED).\n */\nfunction TagRemoveButton({\n label,\n disabled,\n onClick,\n onKeyDown,\n getFallback,\n}: TagRemoveButtonProps) {\n const ref = React.useRef<HTMLButtonElement | null>(null);\n usePreserveFocus(ref, getFallback);\n return (\n <button\n ref={ref}\n type=\"button\"\n data-wave-tagpicker-remove=\"\"\n disabled={disabled}\n aria-label={label}\n className={cn(\n tagPickerClassNames.removeButton,\n // Padding and background set here (C-NATIVE), not left to an app-wide rule.\n 'ms-0.5 inline-flex rounded-sm bg-transparent p-0 text-muted-foreground not-disabled:not-aria-disabled:hover:text-foreground disabled:cursor-not-allowed',\n focusRing,\n )}\n onClick={onClick}\n onKeyDown={onKeyDown}\n >\n <DismissIcon size={12} />\n </button>\n );\n}\n\n/**\n * A multi-select combobox that shows the selected values as removable tags. Typing filters the\n * options and makes the first match active; ArrowDown/ArrowUp move the highlight\n * (`aria-activedescendant`), Enter adds the highlighted option and keeps the list open (with\n * nothing highlighted — no typed text, or text that matches no option — Enter is left to the\n * surrounding form), Escape closes the list (and then clears the typed text). Backspace in the\n * empty input moves focus to the last tag; Backspace or Delete there removes it. Additions and\n * removals are announced (\"Cherry removed, 2 selected\"), and so is \"No matches\" for text that\n * matches no option. `filter` replaces the match (it may keep options that do not contain the\n * text, for a server-side search or a \"Create …\" entry), and `query`/`defaultQuery`/\n * `onQueryChange` control the typed text, which resets to `''` when a tag is added, on Escape and\n * on a form reset, and stays on a blur.\n *\n * The tags form a list named \"Selected\"; the input is described by a summary of the selected\n * labels (\"Selected: Apple, Banana\"). These built-in texts are English; `labels` localizes them.\n * The `<input>` receives `id`, `aria-label`, `aria-labelledby`, `aria-describedby`,\n * `aria-invalid`, `aria-required`, `aria-errormessage`, `aria-details`, `tabIndex`, `autoFocus`,\n * `onFocus`/`onBlur`/`onKeyDown`/`onKeyUp` and the text input attributes `autoComplete`,\n * `autoCapitalize`, `autoCorrect`, `maxLength`, `inputMode`, `spellCheck` and `enterKeyHint`.\n * `ref`, `className`, `style`, other `aria-*` attributes and the remaining props stay on the root\n * `<div>`. Inside a `Field` the input is labelled and described by it. The tag area shows the\n * error look whenever the input ends up `aria-invalid` (its own `aria-invalid` or a `Field`\n * error). With `name`/`required` the values take part in form submission, validation and reset.\n * Selected values without a matching option are shown with their raw value. The open list renders\n * only in the browser: an open list (`defaultOpen`, `open`) is closed in the server HTML and opens\n * once the picker has hydrated.\n *\n * **Size and appearance**: `size` resolves from its own prop, then the surrounding `Field`'s\n * `size`, then `WaveProvider inputDefaults.size`, else `'medium'` (a Field or provider `small`\n * gives `'medium'` too, since TagPicker has no `small`); `appearance` from its own prop, then\n * `WaveProvider inputDefaults.appearance`, else `'outline'`; both render as `data-size` and\n * `data-appearance` on the root `<div>`. The option list keeps its size.\n */\nexport const TagPicker = (props: TagPickerProps) => {\n const {\n options,\n value: valueProp,\n defaultValue,\n onValueChange,\n onChange,\n open: openProp,\n defaultOpen,\n onOpenChange,\n placeholder = 'Select...',\n filter,\n query: queryProp,\n defaultQuery,\n onQueryChange,\n disabled = false,\n size: sizeProp,\n appearance: appearanceProp,\n name,\n form,\n required,\n autoComplete = 'off',\n autoCapitalize,\n autoCorrect,\n maxLength,\n readOnly,\n labels,\n inputMode,\n spellCheck,\n enterKeyHint,\n autoFocus,\n tabIndex,\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n 'aria-required': ariaRequired,\n 'aria-errormessage': ariaErrorMessage,\n 'aria-details': ariaDetails,\n onFocus,\n onBlur,\n onKeyDown,\n onKeyUp,\n controlRef,\n className,\n ref,\n ...rest\n } = props;\n\n if (onChange !== undefined) warnDeprecated('TagPicker', 'onChange', 'onValueChange');\n\n const field = useFieldContext();\n const isRequired = required ?? field?.required ?? false;\n // Like a native readonly input, a read-only TagPicker is barred from constraint validation (the\n // user could not fix it); its values are still submitted.\n const validates = isRequired && !readOnly;\n const fieldProps = useFieldControl({\n id,\n 'aria-label': ariaLabel,\n 'aria-labelledby': ariaLabelledBy,\n 'aria-describedby': ariaDescribedBy,\n 'aria-invalid': ariaInvalid,\n // An explicit `required={false}` wins over a required Field, so aria-required matches\n // `isRequired`.\n 'aria-required': ariaRequired ?? required,\n });\n // The error look follows the resolved state: the consumer's `aria-invalid` or the Field's.\n const invalidLook = isInvalidLook(false, fieldProps['aria-invalid']);\n const { size, appearance } = useInputLook(sizeProp, appearanceProp, {\n sizes: TAG_PICKER_SIZES,\n defaultSize: 'medium',\n });\n // A size outside TAG_PICKER_SIZES (from untyped code) is skipped by useInputLook, so `size` is\n // always one of them and the data attribute carries the resolved value.\n const sizeClasses = TAG_PICKER_SIZE[size];\n\n const [selected, setSelected] = useControllable<readonly string[]>(\n valueProp,\n defaultValue ?? EMPTY_VALUES,\n (next) => {\n // The props are read only; the callbacks receive an array of their own.\n const list = [...next];\n onValueChange?.(list);\n onChange?.(list);\n },\n );\n const interactive = !disabled && !readOnly;\n // A picker that starts disabled or read-only never shows its list, so it starts closed (no close\n // to report later).\n const [openState, setOpen] = useControllable(\n openProp,\n (defaultOpen ?? false) && interactive,\n onOpenChange,\n );\n // The open list lives in a portal, which renders only in the browser: until then (the server\n // HTML, hydration) the picker shows the closed inline list and reports it closed, so\n // aria-controls and aria-activedescendant never name a missing element.\n const isClient = useIsClient();\n const open = openState && interactive && isClient;\n // The query (D12): the text typed since the last tag was added, which filters the options. A\n // picker that starts locked starts without a query, as it starts closed.\n const [queryState, setQuery] = useControllable(\n queryProp,\n interactive ? (defaultQuery ?? '') : '',\n onQueryChange,\n );\n // Locking the control (readOnly/disabled) while typing drops the typed text: hidden during\n // render here, and the reset reported from an effect, since `onQueryChange` never runs during\n // render (D12). `lock` is how the picker came to be locked (previous-value pattern, C-HOOKS):\n // `'locked'` by a change while mounted, whose reset is reported once, or `'mounted-locked'`\n // since it mounted, which reports nothing and keeps a controlled query, hidden until the picker\n // unlocks (R20).\n const query = interactive ? queryState : '';\n const [lock, setLock] = React.useState<LockState>(interactive ? 'unlocked' : 'mounted-locked');\n if (interactive && lock !== 'unlocked') setLock('unlocked');\n else if (!interactive && lock === 'unlocked') setLock('locked');\n React.useEffect(() => {\n if (lock === 'locked') setQuery('');\n }, [lock, setQuery]);\n // Locking also closes the list itself, not only the derived `open`, so unlocking does not reopen\n // it without a user action. The close is reported through onOpenChange (a consumer callback from\n // an effect, C-HOOKS); a controlled `open` that stays true is still not shown while locked.\n const lockedOpen = !interactive && openState;\n React.useEffect(() => {\n if (lockedOpen) setOpen(false);\n }, [lockedOpen, setOpen]);\n // Keeps the shared live regions alive while mounted: every addition and removal is announced\n // (`announceToggle`).\n useAnnounce();\n\n const rootRef = React.useRef<HTMLDivElement | null>(null);\n const inputRef = React.useRef<HTMLInputElement | null>(null);\n const summaryId = useId('tagpicker-summary');\n\n const labelByValue = React.useMemo(() => {\n const map = new Map<string, string>();\n for (const option of options) if (!map.has(option.value)) map.set(option.value, option.label);\n return map;\n }, [options]);\n const labelOf = (value: string) => labelByValue.get(value) ?? value;\n\n const available = React.useMemo<ListboxItem[]>(() => {\n const chosen = new Set(selected);\n return options\n .filter((option) => !chosen.has(option.value))\n .map((option) => ({ value: option.value, label: option.label }));\n }, [options, selected]);\n // useListbox's navigability predicate: `filter` (else the 0.7 match) bound to the typed text,\n // while there is any (D13).\n const listFilter = React.useMemo(\n () => (query ? (item: ListboxItem) => (filter ?? matchesText)(item, query) : undefined),\n [query, filter],\n );\n\n // Unknown values render as tags labelled by the raw value (input-pickers#22).\n const unknownValues = selected.filter((value) => !labelByValue.has(value)).join('\\u0000');\n React.useEffect(() => {\n if (!unknownValues) return;\n warnOnce(\n 'TagPicker:unknown-value',\n `TagPicker: the selected value(s) ${unknownValues\n .split('\\u0000')\n .map((v) => `\"${v}\"`)\n .join(', ')} match no option; the raw value is shown as the tag label.`,\n );\n }, [unknownValues]);\n\n const getInput = () => inputRef.current;\n const focusInput = () => inputRef.current?.focus();\n\n const addTag = (value: string) => {\n if (!interactive || selected.includes(value)) return;\n const next = [...selected, value];\n setSelected(next);\n setQuery('');\n announceToggle(labels, labelOf(value), true, next.length);\n };\n\n const removeTag = (value: string) => {\n if (!interactive) return;\n const next = selected.filter((v) => v !== value);\n setSelected(next);\n announceToggle(labels, labelOf(value), false, next.length);\n focusInput();\n };\n\n const listbox = useListbox({\n open,\n onOpenChange: (next) => setOpen(next),\n mode: 'editable',\n multiselect: true,\n selectedValues: selected,\n onSelect: (value) => addTag(value),\n items: available,\n filter: listFilter,\n // Typing a filter makes its first match active (as in Combobox), so Enter adds what the list\n // shows instead of submitting the form. Nothing is active on open or with the text cleared.\n autoHighlight: query ? 'first' : false,\n idPrefix: 'tagpicker-listbox',\n onClearDraft: query ? () => setQuery('') : undefined,\n });\n\n // aria-expanded only while a listbox with options is shown (input-pickers#21).\n const expanded = open && listbox.items.length > 0;\n const noMatchesText = labels?.noMatches ?? 'No matches';\n // The popup shows the options, or \"No matches\" for a query.\n const surfaceOpen = open && (expanded || query !== '');\n const noMatches = surfaceOpen && !expanded;\n const { layerId, setReference, surfaceRef, floatingProps } = useListboxPopup({\n open,\n surfaceOpen,\n onDismiss: () => setOpen(false),\n rootRef,\n anchorRef: inputRef,\n });\n\n const rootMergedRef = useMergedRefs<HTMLDivElement>(rootRef, ref);\n const inputMergedRef = useMergedRefs<HTMLInputElement>(inputRef, controlRef);\n\n useFormReset(\n inputRef,\n () => {\n // Compared by content (C-FORMS): an inline default is a new array on every render, and a\n // reset that keeps the same tags reports nothing.\n const initial = defaultValue ?? EMPTY_VALUES;\n setSelected((current) => (sameValues(current, initial) ? current : [...initial]));\n setQuery('');\n },\n form,\n );\n\n /** The tags' remove buttons, found from an element inside the component (no ref read). */\n const removeButtons = (from: Element) =>\n Array.from(\n from\n .closest('[data-wave-tagpicker-control]')\n ?.querySelectorAll<HTMLButtonElement>('[data-wave-tagpicker-remove]') ?? [],\n );\n\n const handleInputKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n // Read-only: no listbox keys at all (they would open the list, add or remove tags).\n if (!interactive) return;\n if (event.key === 'Escape' && open && !surfaceOpen && !event.nativeEvent.isComposing) {\n // Open with nothing shown (every option selected, no query): close, but leave Escape to an\n // enclosing layer (overlays#1) instead of consuming it for an invisible list.\n setOpen(false);\n return;\n }\n if (event.key === 'Backspace' && query === '' && selected.length > 0) {\n // First Backspace moves to the last tag; Backspace/Delete there removes it (input-pickers#14).\n event.preventDefault();\n removeButtons(event.currentTarget).at(-1)?.focus();\n return;\n }\n listbox.onKeyDown(event);\n };\n\n const handleTagKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>, value: string) => {\n if (!interactive) return;\n const buttons = removeButtons(event.currentTarget);\n const index = buttons.indexOf(event.currentTarget);\n if (event.key === 'Backspace' || event.key === 'Delete') {\n event.preventDefault();\n removeTag(value);\n return;\n }\n if (event.key === 'Escape') {\n // Consumed here, so an enclosing layer ignores it (spec §5.4).\n event.preventDefault();\n focusInput();\n return;\n }\n const intent = getArrowIntent(event.key, {\n orientation: 'horizontal',\n dir: getDirection(event.currentTarget),\n });\n if (intent === 'prev' && index > 0) {\n event.preventDefault();\n buttons[index - 1].focus();\n } else if (intent === 'next') {\n event.preventDefault();\n if (index < buttons.length - 1) buttons[index + 1].focus();\n else focusInput();\n }\n };\n\n const listLabelledBy =\n fieldProps['aria-label'] === undefined\n ? (fieldProps['aria-labelledby'] ?? field?.labelId)\n : fieldProps['aria-labelledby'];\n\n return (\n <div\n data-size={size}\n data-appearance={appearance}\n {...rest}\n ref={rootMergedRef}\n className={cn(tagPickerClassNames.root, 'relative', className)}\n >\n <div\n ref={setReference}\n data-wave-tagpicker-control=\"\"\n role=\"group\"\n aria-disabled={disabled || undefined}\n className={cn(\n tagPickerClassNames.control,\n 'flex flex-wrap items-center',\n sizeClasses.control,\n inputAppearanceClasses[appearance],\n inputFocusWithin,\n invalidLook && inputInvalidWithin,\n disabled && 'cursor-not-allowed opacity-50',\n )}\n onClick={(event) => {\n if (disabled || (event.target as Element).closest('button')) return;\n focusInput();\n if (!open && interactive) setOpen(true);\n }}\n >\n {selected.length > 0 && (\n <div\n role=\"list\"\n aria-label={labels?.selected ?? 'Selected'}\n className={cn(tagPickerClassNames.group, 'flex flex-wrap items-center gap-1')}\n >\n {selected.map((value) => {\n const label = labelOf(value);\n return (\n <div\n key={value}\n role=\"listitem\"\n className={cn(\n tagPickerClassNames.tag,\n 'inline-flex items-center gap-1 rounded bg-muted text-foreground',\n sizeClasses.tag,\n )}\n >\n {label}\n {!readOnly && (\n <TagRemoveButton\n label={(labels?.remove ?? defaultRemoveLabel)(label)}\n disabled={disabled}\n onClick={() => removeTag(value)}\n onKeyDown={(event) => handleTagKeyDown(event, value)}\n getFallback={getInput}\n />\n )}\n </div>\n );\n })}\n </div>\n )}\n {selected.length > 0 && (\n // Describes the input. The list itself would read every \"Remove …\" button name too.\n <span id={summaryId} hidden>\n {(labels?.summary ?? defaultSummaryLabel)(selected.map(labelOf))}\n </span>\n )}\n <input\n type=\"text\"\n autoComplete={autoComplete}\n {...fieldProps}\n {...listbox.getComboboxProps()}\n aria-expanded={expanded}\n aria-describedby={joinIds(\n fieldProps['aria-describedby'],\n selected.length > 0 ? summaryId : undefined,\n )}\n aria-errormessage={ariaErrorMessage}\n aria-details={ariaDetails}\n ref={inputMergedRef}\n disabled={disabled}\n readOnly={readOnly}\n placeholder={selected.length === 0 ? placeholder : ''}\n autoCapitalize={autoCapitalize}\n autoCorrect={autoCorrect}\n maxLength={maxLength}\n inputMode={inputMode}\n spellCheck={spellCheck}\n enterKeyHint={enterKeyHint}\n autoFocus={autoFocus}\n tabIndex={tabIndex}\n value={query}\n onChange={(event) => {\n if (!interactive) return;\n setQuery(event.target.value);\n if (!open) setOpen(true);\n }}\n onKeyDown={composeEventHandlers(onKeyDown, handleInputKeyDown)}\n onKeyUp={composeEventHandlers(onKeyUp, listbox.onKeyUp)}\n onFocus={onFocus}\n onBlur={onBlur}\n className={cn(\n tagPickerClassNames.input,\n 'min-w-15 flex-1 bg-transparent text-foreground placeholder:text-muted-foreground focus:outline-hidden',\n sizeClasses.input,\n )}\n />\n </div>\n {/* Mounted before its text: a live region added together with its text is not announced by\n every screen reader. The row in the popup is the visible copy. */}\n <span role=\"status\" className=\"sr-only\">\n {noMatches && noMatchesText}\n </span>\n <ListboxSurface\n listbox={listbox}\n layerId={layerId}\n surfaceRef={surfaceRef}\n floatingProps={floatingProps}\n open={open}\n expanded={expanded}\n showCheck={false}\n listClassName={tagPickerClassNames.listbox}\n surfaceClassName={tagPickerClassNames.surface}\n emptyContent={\n query !== '' ? (\n <div\n aria-hidden=\"true\"\n className={cn(\n tagPickerClassNames.emptyMessage,\n 'px-3 py-1.5 text-body-1 text-muted-foreground',\n )}\n >\n {noMatchesText}\n </div>\n ) : undefined\n }\n aria-label={fieldProps['aria-label']}\n aria-labelledby={listLabelledBy}\n >\n {expanded &&\n listbox.items.map((item) => (\n <Option\n key={item.value}\n value={item.value}\n label={item.label}\n className={tagPickerClassNames.option}\n >\n {item.label}\n </Option>\n ))}\n </ListboxSurface>\n <HiddenInput\n name={name}\n form={form}\n disabled={disabled}\n value={selected}\n type=\"text\"\n required={validates}\n onInvalid={focusInput}\n />\n </div>\n );\n};\nTagPicker.displayName = 'TagPicker';\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/classNames.cjs"),r=require("../../lib/aria.cjs"),i=require("../../hooks/useFieldControl.cjs"),a=require("../../lib/styles.cjs"),o=require("./Input.cjs");let
|
|
1
|
+
"use client";const e=require("../../_virtual/_rolldown/runtime.cjs"),t=require("../../lib/cn.cjs"),n=require("../../lib/classNames.cjs"),r=require("../../lib/aria.cjs"),i=require("../../hooks/useFieldControl.cjs"),a=require("../../lib/styles.cjs"),o=require("./inputLook.cjs"),s=require("./Input.cjs");let c=require("react");c=e.__toESM(c,1);let l=require("react/jsx-runtime");var u={small:`min-h-16 px-2 py-1 text-caption-1`,medium:`min-h-20 px-3 py-2 text-body-1`,large:`min-h-24 px-4 py-2.5 text-body-2`},d=({error:e,errorMessageProps:c,size:d,appearance:f,className:p,ref:m,id:h,"aria-label":g,"aria-labelledby":_,"aria-describedby":v,"aria-invalid":y,"aria-required":b,"aria-errormessage":x,required:S,...C})=>{let{invalid:w,messageId:T,message:E}=s.useControlErrorMessage(e,c,y,n.textareaClassNames.errorMessage),D=i.useFieldControl({id:h,"aria-label":g,"aria-labelledby":_,"aria-describedby":r.joinIds(v,T),"aria-invalid":y??(w||void 0),"aria-required":b,required:S},{nativeRequired:!0}),O=s.isInvalidLook(w,D[`aria-invalid`]),{size:k,appearance:A}=o.useInputLook(d,f),j=(0,l.jsx)(`textarea`,{ref:m,"data-size":k,"data-appearance":A,className:t.cn(n.textareaClassNames.root,`w-full resize-y`,u[k],a.inputAppearanceClasses[A],`text-foreground placeholder:text-muted-foreground`,a.inputFocus,`disabled:cursor-not-allowed disabled:opacity-50`,O&&`border-destructive`,p),...C,...D,"aria-errormessage":r.joinIds(x,T)});return E?(0,l.jsxs)(l.Fragment,{children:[j,E]}):j};d.displayName=`Textarea`,exports.Textarea=d;
|
|
2
2
|
//# sourceMappingURL=Textarea.cjs.map
|