@jonmilner/ui 0.2.5 → 0.2.7

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,2 +1,2 @@
1
1
  @layer tokens, reset, atoms, components.box, components.checkbox, components.clickable, components.icon, components.icon-button, components.inline, components.stack, components.text, components.badge, components.button, components.chip, components.field, components.heading, components.dialog, components.alert-dialog, components.menu, components.multiselect, components.search-field, components.tabs, components.tag, components.toast;
2
- @layer components.checkbox{._1tze2y80{cursor:pointer;touch-action:manipulation;-webkit-tap-highlight-color:transparent}._1tze2y80:focus-visible{outline:var(--space-2) solid var(--color-focus);outline-offset:var(--space-2)}._1tze2y80[aria-disabled=true]{cursor:not-allowed}._1tze2y80[aria-readonly=true]{cursor:default}._1tze2y81{inline-size:var(--space-16);block-size:var(--space-16);border:var(--space-1) solid var(--color-border-strong);border-radius:var(--radius-sm);background-color:var(--color-bg);color:var(--color-accent-fg);forced-color-adjust:none;place-items:center;display:grid}._1tze2y80:not([aria-checked=true],[aria-checked=mixed],[aria-invalid=true],[aria-disabled=true],[aria-readonly=true]):hover ._1tze2y81{border-color:var(--color-fg)}._1tze2y80:is([aria-checked=true],[aria-checked=mixed]) ._1tze2y81{background-color:var(--color-accent);border-color:var(--color-accent)}._1tze2y80[aria-disabled=true] ._1tze2y81{border-style:dashed;border-color:var(--color-border-strong);background-color:var(--color-bg-muted);color:var(--color-fg-muted)}._1tze2y80[aria-invalid=true] ._1tze2y81{border-width:var(--space-2);border-color:var(--color-danger)}._1tze2y82{fill:none;stroke:currentColor;stroke-width:2px;stroke-linecap:round;stroke-linejoin:round;block-size:100%;inline-size:100%}._1tze2y80[aria-checked=mixed] ._1tze2y83,._1tze2y80:not([aria-checked=mixed]) ._1tze2y84{display:none}}
2
+ @layer components.checkbox{._1tze2y80{cursor:pointer;touch-action:manipulation;-webkit-tap-highlight-color:transparent}._1tze2y80:focus-visible{outline:var(--space-2) solid var(--color-focus);outline-offset:var(--space-2)}._1tze2y80[aria-disabled=true]{cursor:not-allowed}._1tze2y80[aria-readonly=true]{cursor:default}._1tze2y81{inline-size:var(--space-16);block-size:var(--space-16);border:var(--space-1) solid var(--color-border-strong);border-radius:var(--radius-sm);background-color:var(--color-bg);color:var(--color-accent-fg);forced-color-adjust:none;place-items:center;display:grid}._1tze2y80:not([aria-checked=true],[aria-checked=mixed],[aria-invalid=true],[aria-disabled=true],[aria-readonly=true]):hover ._1tze2y81{border-color:var(--color-fg)}._1tze2y80:is([aria-checked=true],[aria-checked=mixed]) ._1tze2y81{background-color:var(--color-accent);border-color:var(--color-accent)}._1tze2y80[aria-readonly=true] ._1tze2y81{background-clip:padding-box;border-style:dotted}._1tze2y80[aria-disabled=true] ._1tze2y81{border-style:dashed;border-color:var(--color-border-strong);background-clip:border-box;background-color:var(--color-bg-muted);color:var(--color-fg-muted)}._1tze2y80[aria-invalid=true] ._1tze2y81{border-width:var(--space-2);border-color:var(--color-danger)}._1tze2y82{fill:none;stroke:currentColor;stroke-width:2px;stroke-linecap:round;stroke-linejoin:round;block-size:100%;inline-size:100%}._1tze2y80[aria-checked=mixed] ._1tze2y83,._1tze2y80:not([aria-checked=mixed]) ._1tze2y84{display:none}}
@@ -11,10 +11,10 @@ import { CircleCheckIcon as c } from "../icons/CircleCheckIcon.mjs";
11
11
  import { InfoIcon as l } from "../icons/InfoIcon.mjs";
12
12
  import { announcer as u, close as d, content as f, list as p, root as m, toast as h, viewport as g } from "./Toast.css.mjs";
13
13
  import { jsx as _, jsxs as v } from "react/jsx-runtime";
14
- import { createContext as y, use as b, useCallback as x, useMemo as S, useRef as C, useState as w } from "react";
15
- import { Toast as T } from "@base-ui/react/toast";
14
+ import { createContext as y, use as b, useCallback as x, useLayoutEffect as S, useMemo as C, useRef as w, useState as T } from "react";
15
+ import { Toast as E } from "@base-ui/react/toast";
16
16
  //#region src/Toast/client.tsx
17
- var E = {
17
+ var D = {
18
18
  info: {
19
19
  Icon: l,
20
20
  color: "fgMuted"
@@ -27,13 +27,13 @@ var E = {
27
27
  Icon: o,
28
28
  color: "danger"
29
29
  }
30
- }, D = y(null), O = y(null), k = (e) => e !== void 0 && Object.hasOwn(E, e);
31
- function A({ limit: e = 3, closeLabel: n = "Dismiss", regionLabel: r = "Notifications", className: i, style: o, children: s }) {
32
- let { container: c, ref: l } = a(), [u] = w(T.createToastManager);
33
- return /* @__PURE__ */ _(T.Provider, {
30
+ }, O = y(null), k = y(null), A = (e) => e !== void 0 && Object.hasOwn(D, e);
31
+ function j({ limit: e = 3, closeLabel: n = "Dismiss", regionLabel: r = "Notifications", className: i, style: o, children: s }) {
32
+ let { container: c, ref: l } = a(), [u] = T(E.createToastManager);
33
+ return /* @__PURE__ */ _(E.Provider, {
34
34
  limit: e,
35
35
  toastManager: u,
36
- children: /* @__PURE__ */ v(D, {
36
+ children: /* @__PURE__ */ v(O, {
37
37
  value: u,
38
38
  children: [
39
39
  /* @__PURE__ */ _(t, {
@@ -42,23 +42,23 @@ function A({ limit: e = 3, closeLabel: n = "Dismiss", regionLabel: r = "Notifica
42
42
  ref: l
43
43
  }),
44
44
  s,
45
- /* @__PURE__ */ _(M, {}),
46
- /* @__PURE__ */ _(T.Portal, {
45
+ /* @__PURE__ */ _(N, {}),
46
+ /* @__PURE__ */ _(E.Portal, {
47
47
  container: c,
48
- children: /* @__PURE__ */ _(j, {
48
+ children: /* @__PURE__ */ _(M, {
49
49
  className: i,
50
50
  regionLabel: r,
51
51
  style: o,
52
- children: /* @__PURE__ */ _(N, { closeLabel: n })
52
+ children: /* @__PURE__ */ _(P, { closeLabel: n })
53
53
  })
54
54
  })
55
55
  ]
56
56
  })
57
57
  });
58
58
  }
59
- function j({ regionLabel: n, className: r, style: i, children: a }) {
60
- let o = C(null);
61
- return /* @__PURE__ */ _(T.Viewport, {
59
+ function M({ regionLabel: n, className: r, style: i, children: a }) {
60
+ let o = w(null);
61
+ return /* @__PURE__ */ _(E.Viewport, {
62
62
  "aria-atomic": void 0,
63
63
  "aria-label": n,
64
64
  "aria-live": "off",
@@ -75,15 +75,15 @@ function j({ regionLabel: n, className: r, style: i, children: a }) {
75
75
  }),
76
76
  children: /* @__PURE__ */ _("div", {
77
77
  className: p,
78
- children: /* @__PURE__ */ _(O, {
78
+ children: /* @__PURE__ */ _(k, {
79
79
  value: o,
80
80
  children: a
81
81
  })
82
82
  })
83
83
  });
84
84
  }
85
- function M() {
86
- let { toasts: e } = T.useToastManager(), t = (t) => e.filter((e) => e.type === "error" === t).map((e) => /* @__PURE__ */ v("div", { children: [
85
+ function N() {
86
+ let { toasts: e } = E.useToastManager(), t = (t) => e.filter((e) => e.type === "error" === t).map((e) => /* @__PURE__ */ v("div", { children: [
87
87
  e.title,
88
88
  " ",
89
89
  e.description
@@ -103,20 +103,29 @@ function M() {
103
103
  })]
104
104
  });
105
105
  }
106
- function N({ closeLabel: e }) {
107
- let { toasts: t } = T.useToastManager();
108
- return t.map((t) => /* @__PURE__ */ _(P, {
106
+ function P({ closeLabel: e }) {
107
+ let { toasts: t } = E.useToastManager();
108
+ return t.map((t) => /* @__PURE__ */ _(F, {
109
109
  closeLabel: e,
110
110
  toast: t
111
111
  }, t.id));
112
112
  }
113
- function P({ toast: a, closeLabel: o }) {
114
- let c = k(a.type) ? a.type : "info", { Icon: l, color: u } = E[c], p = b(D), g = b(O), [y, S] = w(!1), C = x((e) => {
115
- e && S(getComputedStyle(e).direction === "rtl");
116
- }, []);
117
- return /* @__PURE__ */ v(T.Root, {
113
+ function F({ toast: a, closeLabel: o }) {
114
+ let c = A(a.type) ? a.type : "info", { Icon: l, color: u } = D[c], p = b(O), g = b(k), [y, C] = T(!1), j = x((e) => {
115
+ e && C(getComputedStyle(e).direction === "rtl");
116
+ }, []), M = w(!1), N = a.transitionStatus === "ending";
117
+ return S(() => {
118
+ let e = a.ref?.current, t = e?.ownerDocument.activeElement;
119
+ if (!N || M.current || !t || !e.contains(t)) return;
120
+ let n = g?.current;
121
+ n instanceof HTMLElement && n.isConnected && n.focus({ preventScroll: !0 });
122
+ }, [
123
+ N,
124
+ g,
125
+ a.ref
126
+ ]), /* @__PURE__ */ v(E.Root, {
118
127
  "aria-modal": void 0,
119
- ref: C,
128
+ ref: j,
120
129
  render: /* @__PURE__ */ _(t, {
121
130
  alignItems: "start",
122
131
  backgroundColor: "bgRaised",
@@ -145,28 +154,28 @@ function P({ toast: a, closeLabel: o }) {
145
154
  flexGrow: 1,
146
155
  gap: "8",
147
156
  children: [
148
- /* @__PURE__ */ _(T.Title, { render: /* @__PURE__ */ _(r, {
157
+ /* @__PURE__ */ _(E.Title, { render: /* @__PURE__ */ _(r, {
149
158
  as: "div",
150
159
  weight: "medium"
151
160
  }) }),
152
- /* @__PURE__ */ _(T.Description, { render: /* @__PURE__ */ _(r, {
161
+ /* @__PURE__ */ _(E.Description, { render: /* @__PURE__ */ _(r, {
153
162
  as: "div",
154
163
  color: "fgMuted",
155
164
  size: "sm"
156
165
  }) }),
157
- /* @__PURE__ */ _(T.Action, { render: /* @__PURE__ */ _(i, {
166
+ /* @__PURE__ */ _(E.Action, { render: /* @__PURE__ */ _(i, {
158
167
  size: "sm",
159
168
  variant: "secondary"
160
169
  }) })
161
170
  ]
162
171
  }),
163
- /* @__PURE__ */ _(T.Close, {
172
+ /* @__PURE__ */ _(E.Close, {
164
173
  "aria-hidden": !1,
165
174
  "aria-label": o,
166
175
  onClick: (e) => {
167
176
  if (e.detail !== 0 || !p) return;
168
- let t = a.ref?.current, n = (t && F(t)) ?? g?.current;
169
- n instanceof HTMLElement && (e.preventBaseUIHandler(), p.close(a.id), requestAnimationFrame(() => {
177
+ let t = a.ref?.current, n = (t && I(t)) ?? g?.current;
178
+ n instanceof HTMLElement && (e.preventBaseUIHandler(), M.current = !0, p.close(a.id), requestAnimationFrame(() => {
170
179
  n.isConnected && n.focus();
171
180
  }));
172
181
  },
@@ -181,14 +190,14 @@ function P({ toast: a, closeLabel: o }) {
181
190
  ]
182
191
  });
183
192
  }
184
- function F(e) {
193
+ function I(e) {
185
194
  let t = (e, n) => !e || !e.matches("[data-ending-style]") ? e : t(n ? e.nextElementSibling : e.previousElementSibling, n);
186
195
  return (t(e.nextElementSibling, !0) ?? t(e.previousElementSibling, !1))?.querySelector(`.${d}`);
187
196
  }
188
- function I() {
189
- let e = b(D);
197
+ function L() {
198
+ let e = b(O);
190
199
  if (!e) throw Error("useToast must be called under Toast.Provider.");
191
- return S(() => {
200
+ return C(() => {
192
201
  let t = (t) => e.close(t);
193
202
  return {
194
203
  add: ({ title: n, description: r, variant: i = "info", duration: a = i === "error" ? 0 : 5e3, action: o }) => {
@@ -216,4 +225,4 @@ function I() {
216
225
  }, [e]);
217
226
  }
218
227
  //#endregion
219
- export { M as ToastAnnouncer, P as ToastItem, A as ToastProvider, j as ToastStack, I as useToast };
228
+ export { N as ToastAnnouncer, F as ToastItem, j as ToastProvider, M as ToastStack, L as useToast };
@@ -22,13 +22,13 @@ A two-state choice, with a third mixed state for a "select all" over a partly se
22
22
  - Put `name` on the `Field` (or on the Checkbox outside one). A checked box submits `value` (default `"on"`); an unchecked one submits nothing unless you set `uncheckedValue`.
23
23
  - `checked` with `onCheckedChange` controls it; `defaultChecked` leaves it uncontrolled.
24
24
  - `indeterminate` shows the dash and sets `aria-checked="mixed"`, whatever `checked` is. Clear it yourself when the user clicks: Base UI toggles `checked` but leaves `indeterminate` as you pass it.
25
- - `disabled` takes it out of the tab order and dashes the border; `readOnly` keeps it focusable and announced (`aria-readonly`) but unchangeable; it looks like an editable one apart from the cursor and no hover, so say nearby why it cannot change. Set `disabled` on the `Field` to disable the checkbox and mute the label together.
25
+ - `disabled` takes it out of the tab order and dashes the border; `readOnly` keeps it focusable and announced (`aria-readonly`) but unchangeable, dots the border (disabled's dashes win when both are set) and drops the hover; still say nearby why it cannot change. Set `disabled` on the `Field` to disable the checkbox and mute the label together.
26
26
  - Space toggles it; Enter submits the form it is in, as on a native checkbox.
27
27
  - For an error, set `invalid` on the `Field` with the message in `Field.Error`; the box border thickens and turns `danger`, and the message says what is wrong.
28
28
  - Layout and the target are default style props (`display="inline-flex"`, centered, `flexShrink={0}`, `minInlineSize` and `minBlockSize` `"xs"`, 24px). Raise them freely; never set them below `"xs"`. The box is 16px; there are no sizes yet.
29
29
  - `className` is a string and `style` an object (not Base UI's state functions); they go to the span, after the defaults. `render` and `nativeButton` are not accepted.
30
30
  - The module has no hooks, so a server component can render it. `onCheckedChange` is a function: set it from a client component.
31
- - Style states off the ARIA attributes (`[aria-checked='true']`, `'mixed'`, `[aria-disabled='true']`, `[aria-invalid='true']`), not Base UI's `data-*` attributes.
31
+ - Style states off the ARIA attributes (`[aria-checked='true']`, `'mixed'`, `[aria-disabled='true']`, `[aria-readonly='true']`, `[aria-invalid='true']`), not Base UI's `data-*` attributes.
32
32
 
33
33
  ## Do
34
34
 
@@ -77,7 +77,7 @@ A two-state choice, with a third mixed state for a "select all" over a partly se
77
77
 
78
78
  - Role `checkbox` with `aria-checked` `"true"`, `"false"` or `"mixed"`; `aria-disabled`, `aria-readonly` and `aria-required` follow the props, and `aria-invalid` the `Field`.
79
79
  - The label, description and error reach it through `aria-labelledby` and `aria-describedby`, which Base UI adds after hydration; server HTML has the label's `for`.
80
- - Checked and mixed are a filled box with a tick or a dash, invalid a thicker border, disabled a dashed one, so no state is color alone. The box border is `borderStrong` (3:1 on every surface).
80
+ - Checked and mixed are a filled box with a tick or a dash, invalid a thicker border, disabled a dashed one, read-only a dotted one (the fill stops inside it, so the dots show when checked), so no state is color alone and each survives forced colors. The box border is `borderStrong` (3:1 on every surface).
81
81
  - Under forced colors the box keeps its role colors' system mappings: the fill is `LinkText` and the mark `Canvas` when checked, the border `CanvasText`, the focus ring `Highlight`.
82
82
  - The target is 24 by 24 CSS px; the focus ring wraps the target, not the box.
83
83
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "./manifest.schema.json",
3
3
  "package": "@jonmilner/ui",
4
- "version": "0.2.5",
4
+ "version": "0.2.7",
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.2.5",
3
+ "version": "0.2.7",
4
4
  "files": [
5
5
  "dist",
6
6
  "THIRD_PARTY_NOTICES.md"