@jonmilner/ui 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,56 +1,57 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
2
|
+
import { splitStyleProps as e } from "../styles/split-style-props.mjs";
|
|
3
|
+
import { Box as t } from "../Box/index.mjs";
|
|
4
|
+
import { Text as n } from "../Text/index.mjs";
|
|
5
|
+
import { PopupScope as r, triggerElement as i, useClosingRule as a, usePopupScope as o, useRecordOpenChange as s } from "../popup/client.mjs";
|
|
6
|
+
import { Field as c } from "../Field/index.mjs";
|
|
7
|
+
import { ChevronDownIcon as l } from "../icons/ChevronDownIcon.mjs";
|
|
8
|
+
import { labels as u, popup as d, summary as f, trigger as p, value as m } from "./MultiSelect.css.mjs";
|
|
9
|
+
import { jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
10
|
+
import { createContext as _, use as v, useId as y, useLayoutEffect as b, useMemo as x, useRef as S, useState as C } from "react";
|
|
11
|
+
import { Select as w } from "@base-ui/react/select";
|
|
11
12
|
//#region src/MultiSelect/client.tsx
|
|
12
|
-
function
|
|
13
|
-
let { ref:
|
|
14
|
-
return /* @__PURE__ */
|
|
15
|
-
disabled:
|
|
16
|
-
ref:
|
|
17
|
-
render:
|
|
13
|
+
function T({ options: e, placeholder: t, countLabel: n, disabled: r }) {
|
|
14
|
+
let { ref: a } = o(), s = x(() => new Map(e.map((e) => [e.value, e.label])), [e]);
|
|
15
|
+
return /* @__PURE__ */ h(w.Trigger, {
|
|
16
|
+
disabled: r,
|
|
17
|
+
ref: a,
|
|
18
|
+
render: i({
|
|
18
19
|
variant: "secondary",
|
|
19
|
-
iconEnd:
|
|
20
|
-
className:
|
|
21
|
-
children: /* @__PURE__ */
|
|
22
|
-
className:
|
|
20
|
+
iconEnd: l,
|
|
21
|
+
className: p,
|
|
22
|
+
children: /* @__PURE__ */ h(w.Value, {
|
|
23
|
+
className: m,
|
|
23
24
|
placeholder: t,
|
|
24
|
-
children: (e) => e.length > 0 ? /* @__PURE__ */
|
|
25
|
+
children: (e) => e.length > 0 ? /* @__PURE__ */ h(E, {
|
|
25
26
|
count: n.replaceAll("{count}", String(e.length)),
|
|
26
|
-
labels: e.map((e) =>
|
|
27
|
+
labels: e.map((e) => s.get(e) ?? e)
|
|
27
28
|
}) : t
|
|
28
29
|
})
|
|
29
30
|
})
|
|
30
31
|
});
|
|
31
32
|
}
|
|
32
|
-
function
|
|
33
|
-
let i =
|
|
34
|
-
|
|
33
|
+
function E({ labels: e, count: r }) {
|
|
34
|
+
let i = S(null), [a, o] = C(!0), s = e.join(", ");
|
|
35
|
+
b(() => {
|
|
35
36
|
let e = i.current;
|
|
36
37
|
if (!e) return;
|
|
37
38
|
let t = () => o(e.scrollWidth <= e.clientWidth);
|
|
38
39
|
t(), document.fonts?.ready.then(t);
|
|
39
40
|
let n = new ResizeObserver(t);
|
|
40
41
|
return n.observe(e), () => n.disconnect();
|
|
41
|
-
}, [
|
|
42
|
-
let
|
|
43
|
-
return /* @__PURE__ */
|
|
42
|
+
}, [s]);
|
|
43
|
+
let c = !a && e.length > 1;
|
|
44
|
+
return /* @__PURE__ */ g(t, {
|
|
44
45
|
as: "span",
|
|
45
|
-
className:
|
|
46
|
-
children: [/* @__PURE__ */
|
|
47
|
-
"aria-hidden":
|
|
46
|
+
className: f,
|
|
47
|
+
children: [/* @__PURE__ */ h(n, {
|
|
48
|
+
"aria-hidden": c || void 0,
|
|
48
49
|
as: "span",
|
|
49
|
-
className:
|
|
50
|
+
className: u,
|
|
50
51
|
ref: i,
|
|
51
52
|
truncate: "box",
|
|
52
|
-
children:
|
|
53
|
-
}),
|
|
53
|
+
children: s
|
|
54
|
+
}), c && /* @__PURE__ */ h(n, {
|
|
54
55
|
as: "span",
|
|
55
56
|
className: "_1seauxl4",
|
|
56
57
|
truncate: "box",
|
|
@@ -58,39 +59,73 @@ function C({ labels: n, count: r }) {
|
|
|
58
59
|
})]
|
|
59
60
|
});
|
|
60
61
|
}
|
|
61
|
-
var
|
|
62
|
-
function
|
|
63
|
-
return /* @__PURE__ */
|
|
64
|
-
value:
|
|
62
|
+
var D = _(void 0);
|
|
63
|
+
function O({ children: e }) {
|
|
64
|
+
return /* @__PURE__ */ h(r, { children: /* @__PURE__ */ h(D, {
|
|
65
|
+
value: y(),
|
|
65
66
|
children: e
|
|
66
67
|
}) });
|
|
67
68
|
}
|
|
68
|
-
function
|
|
69
|
-
return /* @__PURE__ */
|
|
70
|
-
|
|
69
|
+
function k(e) {
|
|
70
|
+
return /* @__PURE__ */ h(w.Root, {
|
|
71
|
+
...e,
|
|
72
|
+
multiple: !0,
|
|
73
|
+
onOpenChange: s()
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function A({ children: e }) {
|
|
77
|
+
return /* @__PURE__ */ h(c.Label, {
|
|
78
|
+
id: v(D),
|
|
71
79
|
nativeLabel: !1,
|
|
72
80
|
children: e
|
|
73
81
|
});
|
|
74
82
|
}
|
|
75
|
-
function
|
|
76
|
-
return /* @__PURE__ */
|
|
77
|
-
"aria-labelledby":
|
|
78
|
-
render: /* @__PURE__ */
|
|
83
|
+
function j({ children: e }) {
|
|
84
|
+
return /* @__PURE__ */ h(w.Popup, {
|
|
85
|
+
"aria-labelledby": v(D),
|
|
86
|
+
render: /* @__PURE__ */ h(t, {
|
|
79
87
|
backgroundColor: "bgRaised",
|
|
80
88
|
borderRadius: "med",
|
|
81
89
|
boxShadow: "med",
|
|
82
|
-
className:
|
|
90
|
+
className: d,
|
|
83
91
|
padding: "4"
|
|
84
92
|
}),
|
|
85
|
-
children:
|
|
93
|
+
children: e
|
|
86
94
|
});
|
|
87
95
|
}
|
|
88
|
-
function
|
|
89
|
-
let { container: t } =
|
|
90
|
-
return /* @__PURE__ */
|
|
96
|
+
function M({ children: e }) {
|
|
97
|
+
let { container: t } = o();
|
|
98
|
+
return /* @__PURE__ */ h(w.Portal, {
|
|
91
99
|
container: t,
|
|
92
100
|
children: e
|
|
93
101
|
});
|
|
94
102
|
}
|
|
103
|
+
function N({ children: t }) {
|
|
104
|
+
return /* @__PURE__ */ h(w.Positioner, {
|
|
105
|
+
align: "start",
|
|
106
|
+
alignItemWithTrigger: !1,
|
|
107
|
+
collisionPadding: 8,
|
|
108
|
+
render: (t, { open: n }) => {
|
|
109
|
+
let [, r] = e(t);
|
|
110
|
+
return /* @__PURE__ */ h(P, {
|
|
111
|
+
...r,
|
|
112
|
+
open: n
|
|
113
|
+
});
|
|
114
|
+
},
|
|
115
|
+
side: "bottom",
|
|
116
|
+
sideOffset: 4,
|
|
117
|
+
children: t
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
function P({ open: e, ref: n, ...r }) {
|
|
121
|
+
return /* @__PURE__ */ h(t, {
|
|
122
|
+
...r,
|
|
123
|
+
...a(n, {
|
|
124
|
+
finalFocus: !1,
|
|
125
|
+
open: e
|
|
126
|
+
}),
|
|
127
|
+
zIndex: "popover"
|
|
128
|
+
});
|
|
129
|
+
}
|
|
95
130
|
//#endregion
|
|
96
|
-
export {
|
|
131
|
+
export { A as MultiSelectLabel, j as MultiSelectPopup, M as MultiSelectPortal, N as MultiSelectPositioner, k as MultiSelectRoot, O as MultiSelectScope, T as MultiSelectTrigger };
|
|
@@ -3,73 +3,64 @@ import { Text as t } from "../Text/index.mjs";
|
|
|
3
3
|
import { CheckIcon as n } from "../icons/CheckIcon.mjs";
|
|
4
4
|
import { Field as r } from "../Field/index.mjs";
|
|
5
5
|
import { check as i, item as a } from "./MultiSelect.css.mjs";
|
|
6
|
-
import { MultiSelectLabel as o, MultiSelectPopup as s, MultiSelectPortal as c,
|
|
7
|
-
import { jsx as
|
|
8
|
-
import { Select as
|
|
6
|
+
import { MultiSelectLabel as o, MultiSelectPopup as s, MultiSelectPortal as c, MultiSelectPositioner as l, MultiSelectRoot as u, MultiSelectScope as d, MultiSelectTrigger as f } from "./client.mjs";
|
|
7
|
+
import { jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
8
|
+
import { Select as h } from "@base-ui/react/select";
|
|
9
9
|
//#region src/MultiSelect/index.tsx
|
|
10
|
-
function
|
|
11
|
-
return /* @__PURE__ */
|
|
12
|
-
...
|
|
13
|
-
className:
|
|
14
|
-
disabled:
|
|
15
|
-
invalid:
|
|
16
|
-
style:
|
|
10
|
+
function g({ options: g, value: _, defaultValue: v, onValueChange: y, label: b, description: x, error: S, placeholder: C = "Select", countLabel: w = "{count} selected", disabled: T = !1, required: E = !1, name: D, className: O, style: k, ...A }) {
|
|
11
|
+
return /* @__PURE__ */ m(r, {
|
|
12
|
+
...A,
|
|
13
|
+
className: O,
|
|
14
|
+
disabled: T,
|
|
15
|
+
invalid: S != null && S !== !1 && S !== "",
|
|
16
|
+
style: k,
|
|
17
17
|
children: [
|
|
18
|
-
/* @__PURE__ */ d
|
|
19
|
-
defaultValue:
|
|
20
|
-
disabled:
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
value: h,
|
|
18
|
+
/* @__PURE__ */ p(d, { children: /* @__PURE__ */ m(u, {
|
|
19
|
+
defaultValue: v,
|
|
20
|
+
disabled: T,
|
|
21
|
+
name: D,
|
|
22
|
+
onValueChange: y,
|
|
23
|
+
required: E,
|
|
24
|
+
value: _,
|
|
26
25
|
children: [
|
|
27
|
-
/* @__PURE__ */
|
|
28
|
-
/* @__PURE__ */
|
|
29
|
-
countLabel:
|
|
30
|
-
disabled:
|
|
31
|
-
options:
|
|
32
|
-
placeholder:
|
|
26
|
+
/* @__PURE__ */ p(o, { children: b }),
|
|
27
|
+
/* @__PURE__ */ p(f, {
|
|
28
|
+
countLabel: w,
|
|
29
|
+
disabled: T,
|
|
30
|
+
options: g,
|
|
31
|
+
placeholder: C
|
|
33
32
|
}),
|
|
34
|
-
/* @__PURE__ */
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
children: [/* @__PURE__ */ d(n, {
|
|
55
|
-
className: i,
|
|
33
|
+
/* @__PURE__ */ p(c, { children: /* @__PURE__ */ p(l, { children: /* @__PURE__ */ p(s, { children: g.map((r) => /* @__PURE__ */ m(h.Item, {
|
|
34
|
+
disabled: r.disabled,
|
|
35
|
+
label: r.label,
|
|
36
|
+
render: /* @__PURE__ */ p(e, {
|
|
37
|
+
alignItems: "center",
|
|
38
|
+
borderRadius: "sm",
|
|
39
|
+
className: a,
|
|
40
|
+
display: "flex",
|
|
41
|
+
gap: "8",
|
|
42
|
+
minBlockSize: "sm",
|
|
43
|
+
paddingInline: "12"
|
|
44
|
+
}),
|
|
45
|
+
value: r.value,
|
|
46
|
+
children: [/* @__PURE__ */ p(n, {
|
|
47
|
+
className: i,
|
|
48
|
+
size: "sm"
|
|
49
|
+
}), /* @__PURE__ */ p(h.ItemText, {
|
|
50
|
+
render: /* @__PURE__ */ p(t, {
|
|
51
|
+
as: "span",
|
|
52
|
+
font: "label",
|
|
56
53
|
size: "sm"
|
|
57
|
-
}),
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
size: "sm"
|
|
62
|
-
}),
|
|
63
|
-
children: r.label
|
|
64
|
-
})]
|
|
65
|
-
}, r.value)) })
|
|
66
|
-
}) })
|
|
54
|
+
}),
|
|
55
|
+
children: r.label
|
|
56
|
+
})]
|
|
57
|
+
}, r.value)) }) }) })
|
|
67
58
|
]
|
|
68
59
|
}) }),
|
|
69
|
-
|
|
70
|
-
/* @__PURE__ */
|
|
60
|
+
x != null && /* @__PURE__ */ p(r.Description, { children: x }),
|
|
61
|
+
/* @__PURE__ */ p(r.Error, { children: S })
|
|
71
62
|
]
|
|
72
63
|
});
|
|
73
64
|
}
|
|
74
65
|
//#endregion
|
|
75
|
-
export {
|
|
66
|
+
export { g as MultiSelect };
|
package/dist/docs/MultiSelect.md
CHANGED
|
@@ -89,7 +89,8 @@ A form field for picking any number of values from a list too long to show at on
|
|
|
89
89
|
## Accessibility
|
|
90
90
|
|
|
91
91
|
- The trigger is a button with `aria-haspopup="listbox"` and `aria-expanded`, labelled by the `Field` label and described by the description and error. The popup is `role="listbox"` with `aria-multiselectable="true"`, options are `role="option"` with `aria-selected`.
|
|
92
|
-
- Opening from the keyboard focuses an option; focus stays in the list until it closes
|
|
92
|
+
- Opening from the keyboard focuses an option; focus stays in the list until it closes. Choosing an option toggles it and leaves the list open, so several can be picked in one visit. Closed by Esc or the trigger, focus returns at once to the trigger, so a Tab pressed while the list fades goes on to the next control. A press outside or a Tab out leaves focus to Base UI.
|
|
93
|
+
- A closed list stays on the page while it fades out, but is `inert` and `aria-hidden` from the moment it closes, so a list opened during the fade (the next filter's) is the only one a screen reader or a role query finds, and nothing in the fading one takes focus or a click (ADR 0113).
|
|
93
94
|
- Selection is a check mark on the option as well as its highlight, so it is not color alone. The check's space is always in the row, so the text never shifts.
|
|
94
95
|
- The trigger summary is text: the joined labels, or the count. When the count replaces the labels, the labels are hidden from assistive technology so the count is read once.
|
|
95
96
|
- The shared focus ring shows on the trigger and, from the keyboard, on the highlighted option. Under forced colors the highlighted option is `Highlight` with `HighlightText`, and the popup keeps its border.
|
package/dist/docs/manifest.json
CHANGED