@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,4 +1,5 @@
1
1
  import { ReactNode } from "react";
2
+ import "@base-ui/react/select";
2
3
  //#region src/MultiSelect/client.d.ts
3
4
  export type Option = {
4
5
  disabled?: boolean;
@@ -1,56 +1,57 @@
1
1
  "use client";
2
- import { Box as e } from "../Box/index.mjs";
3
- import { Text as t } from "../Text/index.mjs";
4
- import { PopupScope as n, triggerElement as r, usePopupScope as i } from "../popup/client.mjs";
5
- import { Field as a } from "../Field/index.mjs";
6
- import { ChevronDownIcon as o } from "../icons/ChevronDownIcon.mjs";
7
- import { labels as s, popup as c, summary as l, trigger as u, value as d } from "./MultiSelect.css.mjs";
8
- import { jsx as f, jsxs as p } from "react/jsx-runtime";
9
- import { createContext as m, use as h, useId as g, useLayoutEffect as _, useMemo as v, useRef as y, useState as b } from "react";
10
- import { Select as x } from "@base-ui/react/select";
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 S({ options: e, placeholder: t, countLabel: n, disabled: a }) {
13
- let { ref: s } = i(), c = v(() => new Map(e.map((e) => [e.value, e.label])), [e]);
14
- return /* @__PURE__ */ f(x.Trigger, {
15
- disabled: a,
16
- ref: s,
17
- render: r({
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: o,
20
- className: u,
21
- children: /* @__PURE__ */ f(x.Value, {
22
- className: d,
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__ */ f(C, {
25
+ children: (e) => e.length > 0 ? /* @__PURE__ */ h(E, {
25
26
  count: n.replaceAll("{count}", String(e.length)),
26
- labels: e.map((e) => c.get(e) ?? e)
27
+ labels: e.map((e) => s.get(e) ?? e)
27
28
  }) : t
28
29
  })
29
30
  })
30
31
  });
31
32
  }
32
- function C({ labels: n, count: r }) {
33
- let i = y(null), [a, o] = b(!0), c = n.join(", ");
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
- }, [c]);
42
- let u = !a && n.length > 1;
43
- return /* @__PURE__ */ p(e, {
42
+ }, [s]);
43
+ let c = !a && e.length > 1;
44
+ return /* @__PURE__ */ g(t, {
44
45
  as: "span",
45
- className: l,
46
- children: [/* @__PURE__ */ f(t, {
47
- "aria-hidden": u || void 0,
46
+ className: f,
47
+ children: [/* @__PURE__ */ h(n, {
48
+ "aria-hidden": c || void 0,
48
49
  as: "span",
49
- className: s,
50
+ className: u,
50
51
  ref: i,
51
52
  truncate: "box",
52
- children: c
53
- }), u && /* @__PURE__ */ f(t, {
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 w = m(void 0);
62
- function T({ children: e }) {
63
- return /* @__PURE__ */ f(n, { children: /* @__PURE__ */ f(w, {
64
- value: g(),
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 E({ children: e }) {
69
- return /* @__PURE__ */ f(a.Label, {
70
- id: h(w),
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 D({ children: t }) {
76
- return /* @__PURE__ */ f(x.Popup, {
77
- "aria-labelledby": h(w),
78
- render: /* @__PURE__ */ f(e, {
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: c,
90
+ className: d,
83
91
  padding: "4"
84
92
  }),
85
- children: t
93
+ children: e
86
94
  });
87
95
  }
88
- function O({ children: e }) {
89
- let { container: t } = i();
90
- return /* @__PURE__ */ f(x.Portal, {
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 { E as MultiSelectLabel, D as MultiSelectPopup, O as MultiSelectPortal, T as MultiSelectScope, S as MultiSelectTrigger };
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, MultiSelectScope as l, MultiSelectTrigger as u } from "./client.mjs";
7
- import { jsx as d, jsxs as f } from "react/jsx-runtime";
8
- import { Select as p } from "@base-ui/react/select";
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 m({ options: m, value: h, defaultValue: g, onValueChange: _, label: v, description: y, error: b, placeholder: x = "Select", countLabel: S = "{count} selected", disabled: C = !1, required: w = !1, name: T, className: E, style: D, ...O }) {
11
- return /* @__PURE__ */ f(r, {
12
- ...O,
13
- className: E,
14
- disabled: C,
15
- invalid: b != null && b !== !1 && b !== "",
16
- style: D,
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(l, { children: /* @__PURE__ */ f(p.Root, {
19
- defaultValue: g,
20
- disabled: C,
21
- multiple: !0,
22
- name: T,
23
- onValueChange: _,
24
- required: w,
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__ */ d(o, { children: v }),
28
- /* @__PURE__ */ d(u, {
29
- countLabel: S,
30
- disabled: C,
31
- options: m,
32
- placeholder: x
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__ */ d(c, { children: /* @__PURE__ */ d(p.Positioner, {
35
- align: "start",
36
- alignItemWithTrigger: !1,
37
- collisionPadding: 8,
38
- render: /* @__PURE__ */ d(e, { zIndex: "popover" }),
39
- side: "bottom",
40
- sideOffset: 4,
41
- children: /* @__PURE__ */ d(s, { children: m.map((r) => /* @__PURE__ */ f(p.Item, {
42
- disabled: r.disabled,
43
- label: r.label,
44
- render: /* @__PURE__ */ d(e, {
45
- alignItems: "center",
46
- borderRadius: "sm",
47
- className: a,
48
- display: "flex",
49
- gap: "8",
50
- minBlockSize: "sm",
51
- paddingInline: "12"
52
- }),
53
- value: r.value,
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
- }), /* @__PURE__ */ d(p.ItemText, {
58
- render: /* @__PURE__ */ d(t, {
59
- as: "span",
60
- font: "label",
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
- y != null && /* @__PURE__ */ d(r.Description, { children: y }),
70
- /* @__PURE__ */ d(r.Error, { children: b })
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 { m as MultiSelect };
66
+ export { g as MultiSelect };
@@ -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, then returns to the trigger. Choosing an option toggles it and leaves the list open, so several can be picked in one visit.
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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "./manifest.schema.json",
3
3
  "package": "@jonmilner/ui",
4
- "version": "0.5.0",
4
+ "version": "0.5.1",
5
5
  "components": [
6
6
  {
7
7
  "name": "AlertDialog",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jonmilner/ui",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "files": [
5
5
  "dist",
6
6
  "THIRD_PARTY_NOTICES.md"