@jonmilner/ui 0.8.1 → 0.9.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.
Files changed (82) hide show
  1. package/dist/Avatar/Avatar.css +1 -1
  2. package/dist/Avatar/index.d.mts +1 -1
  3. package/dist/Avatar/index.mjs +1 -1
  4. package/dist/Badge/Badge.css +1 -1
  5. package/dist/Badge/index.d.mts +1 -1
  6. package/dist/Badge/index.mjs +1 -1
  7. package/dist/Box/Box.css +1 -1
  8. package/dist/Box/ResponsiveCheck.mjs +17 -0
  9. package/dist/Box/base.d.mts +8 -0
  10. package/dist/Box/base.mjs +17 -0
  11. package/dist/Box/index.d.mts +4 -7
  12. package/dist/Box/index.mjs +4 -13
  13. package/dist/Button/Button.css +1 -1
  14. package/dist/Button/index.d.mts +1 -1
  15. package/dist/Button/index.mjs +1 -1
  16. package/dist/Checkbox/Checkbox.css +1 -1
  17. package/dist/Checkbox/index.mjs +1 -1
  18. package/dist/Chip/Chip.css +1 -1
  19. package/dist/Chip/index.mjs +1 -1
  20. package/dist/Clickable/Clickable.css +1 -1
  21. package/dist/Clickable/index.d.mts +1 -1
  22. package/dist/Clickable/index.mjs +1 -1
  23. package/dist/ColorField/ColorField.css +1 -1
  24. package/dist/ColorField/client.mjs +8 -8
  25. package/dist/ColorField/index.d.mts +1 -1
  26. package/dist/Dialog/Dialog.css +1 -1
  27. package/dist/Dialog/client.d.mts +1 -1
  28. package/dist/Dialog/client.mjs +1 -1
  29. package/dist/Dialog/index.d.mts +1 -1
  30. package/dist/Dialog/index.mjs +1 -1
  31. package/dist/Field/Field.css +1 -1
  32. package/dist/Field/client.mjs +1 -1
  33. package/dist/Field/index.mjs +18 -18
  34. package/dist/Heading/Heading.css +1 -1
  35. package/dist/Icon/Icon.css +1 -1
  36. package/dist/IconButton/IconButton.css +1 -1
  37. package/dist/IconButton/index.d.mts +1 -1
  38. package/dist/Inline/Inline.css +1 -1
  39. package/dist/Inline/index.d.mts +2 -1
  40. package/dist/Menu/Menu.css +2 -2
  41. package/dist/Menu/Menu.css.mjs +2 -2
  42. package/dist/Menu/client.d.mts +17 -2
  43. package/dist/Menu/client.mjs +71 -28
  44. package/dist/Menu/index.d.mts +8 -5
  45. package/dist/Menu/index.mjs +75 -63
  46. package/dist/MultiSelect/MultiSelect.css +1 -1
  47. package/dist/MultiSelect/client.mjs +25 -25
  48. package/dist/MultiSelect/index.d.mts +1 -1
  49. package/dist/MultiSelect/index.mjs +1 -1
  50. package/dist/SearchField/SearchField.css +1 -1
  51. package/dist/SearchField/client.mjs +9 -9
  52. package/dist/SearchField/index.d.mts +1 -1
  53. package/dist/Stack/Stack.css +1 -1
  54. package/dist/Stack/index.d.mts +2 -1
  55. package/dist/Tabs/Tabs.css +1 -1
  56. package/dist/Tabs/index.mjs +1 -1
  57. package/dist/Tag/Tag.css +1 -1
  58. package/dist/Tag/index.d.mts +1 -1
  59. package/dist/Tag/index.mjs +1 -1
  60. package/dist/Text/Text.css +1 -1
  61. package/dist/Text/index.d.mts +1 -1
  62. package/dist/Text/index.mjs +1 -1
  63. package/dist/TextField/TextField.css +1 -1
  64. package/dist/TextField/index.d.mts +1 -1
  65. package/dist/Toast/Toast.css +1 -1
  66. package/dist/Toast/client.mjs +42 -42
  67. package/dist/VisuallyHidden/VisuallyHidden.css +1 -1
  68. package/dist/base.css +1 -1
  69. package/dist/docs/Menu.md +41 -5
  70. package/dist/docs/manifest.json +33 -1
  71. package/dist/docs/migrations/0.9.0.md +27 -0
  72. package/dist/index.d.mts +2 -1
  73. package/dist/index.mjs +11 -11
  74. package/dist/popup/client.mjs +24 -24
  75. package/dist/styles/atoms.css +2 -2
  76. package/dist/styles/atoms.css.d.mts +31 -31
  77. package/dist/styles/atoms.css.mjs +1500 -1500
  78. package/dist/styles/layers.css +2 -2
  79. package/dist/styles/part-props.d.mts +1 -1
  80. package/dist/styles/responsive.css +2 -0
  81. package/dist/styles/responsive.css.mjs +6 -0
  82. package/package.json +5 -3
package/dist/Tag/Tag.css CHANGED
@@ -1,2 +1,2 @@
1
- @layer tokens, reset, atoms, components.box, components.checkbox, components.clickable, components.icon, components.icon-button, components.inline, components.stack, components.text, components.avatar, components.badge, components.button, components.chip, components.field, components.color-field, components.heading, components.dialog, components.alert-dialog, components.menu, components.multiselect, components.search-field, components.tabs, components.tag, components.text-field, components.toast, components.visually-hidden;
1
+ @layer tokens, reset, atoms.base, atoms.sm, atoms.med, atoms.lg, atoms.xl, components.box, components.checkbox, components.clickable, components.icon, components.icon-button, components.inline, components.stack, components.text, components.avatar, components.badge, components.button, components.chip, components.field, components.color-field, components.heading, components.dialog, components.alert-dialog, components.menu, components.multiselect, components.search-field, components.tabs, components.tag, components.text-field, components.toast, components.visually-hidden;
2
2
  @layer components.tag{._1jsyd8s0{border-width:var(--space-1);border-style:solid;border-color:#0000}._1jsyd8s1{overflow-wrap:anywhere}._1jsyd8s0:hover ._1jsyd8s1,._1jsyd8s0:focus-within ._1jsyd8s1{padding-block:var(--space-4);margin-block:0}._1jsyd8s2{text-decoration:underline}._1jsyd8s3:hover{background-color:var(--color-bg)}@media (forced-colors:active){._1jsyd8s0{color:canvastext;background-color:canvas;border-color:canvastext}}}
@@ -1,5 +1,5 @@
1
1
  import { OmitEach } from "../types.mjs";
2
- import { StyleProps } from "../Box/index.mjs";
2
+ import { StyleProps } from "../Box/base.mjs";
3
3
  import { Tone } from "../styles/subtle-fills.mjs";
4
4
  import { ComponentPropsWithRef } from "react";
5
5
  //#region src/Tag/index.d.ts
@@ -1,5 +1,5 @@
1
1
  import { join as e } from "../styles/join.mjs";
2
- import { Box as t } from "../Box/index.mjs";
2
+ import { Box as t } from "../Box/base.mjs";
3
3
  import { Clickable as n } from "../Clickable/index.mjs";
4
4
  import { Text as r } from "../Text/index.mjs";
5
5
  import { subtleFills as i } from "../styles/subtle-fills.mjs";
@@ -1,2 +1,2 @@
1
- @layer tokens, reset, atoms, components.box, components.checkbox, components.clickable, components.icon, components.icon-button, components.inline, components.stack, components.text, components.avatar, components.badge, components.button, components.chip, components.field, components.color-field, components.heading, components.dialog, components.alert-dialog, components.menu, components.multiselect, components.search-field, components.tabs, components.tag, components.text-field, components.toast, components.visually-hidden;
1
+ @layer tokens, reset, atoms.base, atoms.sm, atoms.med, atoms.lg, atoms.xl, components.box, components.checkbox, components.clickable, components.icon, components.icon-button, components.inline, components.stack, components.text, components.avatar, components.badge, components.button, components.chip, components.field, components.color-field, components.heading, components.dialog, components.alert-dialog, components.menu, components.multiselect, components.search-field, components.tabs, components.tag, components.text-field, components.toast, components.visually-hidden;
2
2
  @layer components.text{._1mgdisq3{--_1mgdisq0:var(--line-height-med);--_1mgdisq1:calc((var(--font-trim-body-cap) - var(--_1mgdisq0) / 2) * 1em);--_1mgdisq2:calc((var(--font-trim-body-baseline) - var(--_1mgdisq0) / 2) * 1em);font-family:var(--font-body);font-size:var(--font-size-med);font-weight:var(--font-weight-regular);line-height:var(--_1mgdisq0)}._1mgdisq3:before{content:"";margin-block-end:var(--_1mgdisq1);display:table}._1mgdisq3:after{content:"";margin-block-start:var(--_1mgdisq2);display:table}:where(._1mgdisq3)>._1mgdisq3:where(a,abbr,b,bdi,bdo,cite,code,data,del,dfn,em,i,ins,kbd,label,mark,output,q,s,samp,small,span,strong,sub,sup,time,u,var){--_1mgdisq0:inherit;--_1mgdisq1:inherit;--_1mgdisq2:inherit;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;display:inline}:where(._1mgdisq3)>._1mgdisq3:where(a,abbr,b,bdi,bdo,cite,code,data,del,dfn,em,i,ins,kbd,label,mark,output,q,s,samp,small,span,strong,sub,sup,time,u,var):before,:where(._1mgdisq3)>._1mgdisq3:where(a,abbr,b,bdi,bdo,cite,code,data,del,dfn,em,i,ins,kbd,label,mark,output,q,s,samp,small,span,strong,sub,sup,time,u,var):after{content:none}._1mgdisq4{--_1mgdisq0:inherit;--_1mgdisq1:inherit;--_1mgdisq2:inherit;text-overflow:ellipsis;white-space:nowrap;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit}._1mgdisq4:before,._1mgdisq4:after{content:none}._1mgdisq5{--_1mgdisq1:calc((var(--font-trim-body-cap) - var(--_1mgdisq0) / 2) * 1em);--_1mgdisq2:calc((var(--font-trim-body-baseline) - var(--_1mgdisq0) / 2) * 1em);font-family:var(--font-body)}._1mgdisq6{--_1mgdisq1:calc((var(--font-trim-heading-cap) - var(--_1mgdisq0) / 2) * 1em);--_1mgdisq2:calc((var(--font-trim-heading-baseline) - var(--_1mgdisq0) / 2) * 1em);font-family:var(--font-heading)}._1mgdisq7{--_1mgdisq1:calc((var(--font-trim-display-cap) - var(--_1mgdisq0) / 2) * 1em);--_1mgdisq2:calc((var(--font-trim-display-baseline) - var(--_1mgdisq0) / 2) * 1em);font-family:var(--font-display)}._1mgdisq8{--_1mgdisq1:calc((var(--font-trim-label-cap) - var(--_1mgdisq0) / 2) * 1em);--_1mgdisq2:calc((var(--font-trim-label-baseline) - var(--_1mgdisq0) / 2) * 1em);font-family:var(--font-label)}._1mgdisq9{--_1mgdisq1:calc((var(--font-trim-mono-cap) - var(--_1mgdisq0) / 2) * 1em);--_1mgdisq2:calc((var(--font-trim-mono-baseline) - var(--_1mgdisq0) / 2) * 1em);font-family:var(--font-mono)}._1mgdisqa{font-size:var(--font-size-xs)}._1mgdisqb{font-size:var(--font-size-sm)}._1mgdisqc{font-size:var(--font-size-med)}._1mgdisqd{font-size:var(--font-size-lg)}._1mgdisqe{font-size:var(--font-size-xl)}._1mgdisqf{font-size:var(--font-size-2xl)}._1mgdisqg{font-size:var(--font-size-3xl)}._1mgdisqh{font-size:var(--font-size-4xl)}._1mgdisqi{font-weight:var(--font-weight-regular)}._1mgdisqj{font-weight:var(--font-weight-medium)}._1mgdisqk{font-weight:var(--font-weight-semibold)}._1mgdisql{font-weight:var(--font-weight-bold)}._1mgdisqm{--_1mgdisq0:var(--line-height-sm);line-height:var(--_1mgdisq0)}._1mgdisqn{--_1mgdisq0:var(--line-height-med);line-height:var(--_1mgdisq0)}._1mgdisqo{--_1mgdisq0:var(--line-height-lg);line-height:var(--_1mgdisq0)}._1mgdisqp{white-space:nowrap}._1mgdisqq{text-overflow:ellipsis;white-space:nowrap;margin-block-start:var(--_1mgdisq1);margin-block-end:var(--_1mgdisq2);padding-block-start:calc(-1 * var(--_1mgdisq1));padding-block-end:calc(-1 * var(--_1mgdisq2))}:where([data-text-reveal]:hover,[data-text-reveal]:focus-within) ._1mgdisqq{white-space:normal;text-overflow:clip}}
@@ -1,5 +1,5 @@
1
1
  import { PolymorphicProps } from "../types.mjs";
2
- import { StyleProps } from "../Box/index.mjs";
2
+ import { StyleProps } from "../Box/base.mjs";
3
3
  import { tokens } from "../tokens/scales.mjs";
4
4
  import { FontRole } from "../tokens/roles.mjs";
5
5
  import { ElementType } from "react";
@@ -1,5 +1,5 @@
1
1
  import { join as e } from "../styles/join.mjs";
2
- import { Box as t } from "../Box/index.mjs";
2
+ import { Box as t } from "../Box/base.mjs";
3
3
  import { font as n, leading as r, root as i, size as a, weight as o, wrap as s } from "./Text.css.mjs";
4
4
  import { jsx as c } from "react/jsx-runtime";
5
5
  //#region src/Text/index.tsx
@@ -1,2 +1,2 @@
1
- @layer tokens, reset, atoms, components.box, components.checkbox, components.clickable, components.icon, components.icon-button, components.inline, components.stack, components.text, components.avatar, components.badge, components.button, components.chip, components.field, components.color-field, components.heading, components.dialog, components.alert-dialog, components.menu, components.multiselect, components.search-field, components.tabs, components.tag, components.text-field, components.toast, components.visually-hidden;
1
+ @layer tokens, reset, atoms.base, atoms.sm, atoms.med, atoms.lg, atoms.xl, components.box, components.checkbox, components.clickable, components.icon, components.icon-button, components.inline, components.stack, components.text, components.avatar, components.badge, components.button, components.chip, components.field, components.color-field, components.heading, components.dialog, components.alert-dialog, components.menu, components.multiselect, components.search-field, components.tabs, components.tag, components.text-field, components.toast, components.visually-hidden;
2
2
  @layer components.text-field{._20at410{clip-path:inset(50%);white-space:nowrap;border:0;block-size:1px;inline-size:1px;margin:0;padding:0;position:absolute;overflow:hidden}._20at411{appearance:none;border-width:var(--space-1);border-style:solid;border-color:var(--color-border-strong);border-radius:var(--radius-med);background-color:var(--color-bg);inline-size:100%;min-inline-size:0;color:var(--color-fg);padding-block:0}._20at411::placeholder{color:var(--color-fg-muted);opacity:1}._20at411:focus-visible{outline:var(--space-2) solid var(--color-focus);outline-offset:var(--space-2)}._20at411:disabled{background-color:var(--color-bg-muted);color:var(--color-fg-muted);cursor:not-allowed;border-style:dashed}._20at411[aria-invalid=true]{border-color:var(--color-danger)}._20at412{block-size:var(--size-sm);padding-inline:var(--space-8)}._20at413{block-size:var(--size-med);padding-inline:var(--space-12)}._20at414{block-size:var(--size-lg);padding-inline:var(--space-16)}@media (forced-colors:active){._20at411:disabled{color:graytext;border-color:graytext}}}
@@ -1,4 +1,4 @@
1
- import { StyleProps } from "../Box/index.mjs";
1
+ import { StyleProps } from "../Box/base.mjs";
2
2
  import { SearchFieldInputProps } from "../SearchField/client.mjs";
3
3
  import "../SearchField/index.mjs";
4
4
  import { CSSProperties, ComponentPropsWithRef, ReactNode } from "react";
@@ -1,2 +1,2 @@
1
- @layer tokens, reset, atoms, components.box, components.checkbox, components.clickable, components.icon, components.icon-button, components.inline, components.stack, components.text, components.avatar, components.badge, components.button, components.chip, components.field, components.color-field, components.heading, components.dialog, components.alert-dialog, components.menu, components.multiselect, components.search-field, components.tabs, components.tag, components.text-field, components.toast, components.visually-hidden;
1
+ @layer tokens, reset, atoms.base, atoms.sm, atoms.med, atoms.lg, atoms.xl, components.box, components.checkbox, components.clickable, components.icon, components.icon-button, components.inline, components.stack, components.text, components.avatar, components.badge, components.button, components.chip, components.field, components.color-field, components.heading, components.dialog, components.alert-dialog, components.menu, components.multiselect, components.search-field, components.tabs, components.tag, components.text-field, components.toast, components.visually-hidden;
2
2
  @layer components.toast{.hcnvsc1{inline-size:min(100% - 2 * var(--space-16), 6 * var(--space-64));inset-block-end:var(--space-16);inset-inline-end:var(--space-16);container:hcnvsc0/inline-size}.hcnvsc1:focus-visible{outline:var(--space-2) solid var(--color-focus);outline-offset:var(--space-2)}.hcnvsc2{gap:var(--space-8);margin:calc(-1 * var(--space-16));padding:var(--space-16);overscroll-behavior:contain;flex-direction:column;max-block-size:100dvh;margin-inline-start:calc(-1 * var(--space-24));padding-inline-start:var(--space-24);display:flex;overflow:hidden auto}.hcnvsc2:empty{padding:0}.hcnvsc2:has([data-swiping],[data-swipe-direction=down]){overflow-y:hidden}.hcnvsc3{border:var(--space-1) solid var(--color-border);transform:translate(var(--toast-swipe-movement-x,0), var(--toast-swipe-movement-y,0));transition:opacity var(--duration-med) var(--easing-standard), translate var(--duration-med) var(--easing-enter), transform var(--duration-med) var(--easing-enter)}.hcnvsc3:focus-visible{outline:var(--space-2) solid var(--color-focus);outline-offset:var(--space-2)}.hcnvsc3[data-starting-style],.hcnvsc3[data-ending-style]{opacity:0;translate:0 var(--distance-med)}.hcnvsc3[data-swiping]{transition:none}.hcnvsc3[data-limited]{display:none}.hcnvsc4{overflow-wrap:anywhere}.hcnvsca{clip-path:inset(50%);white-space:nowrap;border:0;block-size:1px;inline-size:1px;margin:0;padding:0;position:absolute;inset-block-start:0;inset-inline-start:0;overflow:hidden}@container hcnvsc0 (inline-size<16rem){.hcnvsc3{flex-wrap:wrap}.hcnvsc4{flex-basis:100%;order:1}.hcnvsc5{margin-inline-start:auto}}}
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { join as e } from "../styles/join.mjs";
3
- import { Box as t } from "../Box/index.mjs";
3
+ import { Box as t } from "../Box/base.mjs";
4
4
  import { Clickable as n } from "../Clickable/index.mjs";
5
5
  import { Text as r } from "../Text/index.mjs";
6
6
  import { Button as i } from "../Button/index.mjs";
@@ -10,8 +10,8 @@ import { XIcon as s } from "../icons/XIcon.mjs";
10
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
- import { jsx as _, jsxs as v } from "react/jsx-runtime";
14
- import { createContext as y, use as b, useCallback as x, useEffect as S, useLayoutEffect as C, useMemo as w, useRef as T, useState as E } from "react";
13
+ import { createContext as _, use as v, useCallback as y, useEffect as b, useLayoutEffect as x, useMemo as S, useRef as C, useState as w } from "react";
14
+ import { jsx as T, jsxs as E } from "react/jsx-runtime";
15
15
  import { Toast as D } from "@base-ui/react/toast";
16
16
  //#region src/Toast/client.tsx
17
17
  var O = {
@@ -27,29 +27,29 @@ var O = {
27
27
  Icon: o,
28
28
  color: "danger"
29
29
  }
30
- }, k = y(null), A = y(null), j = (e) => e !== void 0 && Object.hasOwn(O, e);
30
+ }, k = _(null), A = _(null), j = (e) => e !== void 0 && Object.hasOwn(O, e);
31
31
  function M({ limit: e = 3, closeLabel: n = "Dismiss", regionLabel: r = "Notifications", className: i, style: o, children: s }) {
32
- let { container: c, ref: l } = a(), [u] = E(D.createToastManager);
33
- return /* @__PURE__ */ _(D.Provider, {
32
+ let { container: c, ref: l } = a(), [u] = w(D.createToastManager);
33
+ return /* @__PURE__ */ T(D.Provider, {
34
34
  limit: e,
35
35
  toastManager: u,
36
- children: /* @__PURE__ */ v(k, {
36
+ children: /* @__PURE__ */ E(k, {
37
37
  value: u,
38
38
  children: [
39
- /* @__PURE__ */ _(t, {
39
+ /* @__PURE__ */ T(t, {
40
40
  as: "span",
41
41
  hidden: !0,
42
42
  ref: l
43
43
  }),
44
44
  s,
45
- /* @__PURE__ */ _(P, {}),
46
- /* @__PURE__ */ _(D.Portal, {
45
+ /* @__PURE__ */ T(P, {}),
46
+ /* @__PURE__ */ T(D.Portal, {
47
47
  container: c,
48
- children: /* @__PURE__ */ _(N, {
48
+ children: /* @__PURE__ */ T(N, {
49
49
  className: i,
50
50
  regionLabel: r,
51
51
  style: o,
52
- children: /* @__PURE__ */ _(F, { closeLabel: n })
52
+ children: /* @__PURE__ */ T(F, { closeLabel: n })
53
53
  })
54
54
  })
55
55
  ]
@@ -57,8 +57,8 @@ function M({ limit: e = 3, closeLabel: n = "Dismiss", regionLabel: r = "Notifica
57
57
  });
58
58
  }
59
59
  function N({ regionLabel: n, className: r, style: i, children: a }) {
60
- let o = T(null), s = T(null);
61
- return S(() => {
60
+ let o = C(null), s = C(null);
61
+ return b(() => {
62
62
  let e = s.current;
63
63
  if (!e) return;
64
64
  let t = e.ownerDocument, n = !1, r = (t) => {
@@ -73,7 +73,7 @@ function N({ regionLabel: n, className: r, style: i, children: a }) {
73
73
  return t.addEventListener("mouseover", r), t.addEventListener("mouseout", i), () => {
74
74
  t.removeEventListener("mouseover", r), t.removeEventListener("mouseout", i);
75
75
  };
76
- }, []), /* @__PURE__ */ _(D.Viewport, {
76
+ }, []), /* @__PURE__ */ T(D.Viewport, {
77
77
  "aria-atomic": void 0,
78
78
  "aria-label": n,
79
79
  "aria-live": "off",
@@ -83,15 +83,15 @@ function N({ regionLabel: n, className: r, style: i, children: a }) {
83
83
  t && !e.currentTarget.contains(t) && (o.current = t);
84
84
  },
85
85
  ref: s,
86
- render: /* @__PURE__ */ _(t, {
86
+ render: /* @__PURE__ */ T(t, {
87
87
  className: e(g, r),
88
88
  position: "fixed",
89
89
  style: i,
90
90
  zIndex: "toast"
91
91
  }),
92
- children: /* @__PURE__ */ _("div", {
92
+ children: /* @__PURE__ */ T("div", {
93
93
  className: p,
94
- children: /* @__PURE__ */ _(A, {
94
+ children: /* @__PURE__ */ T(A, {
95
95
  value: o,
96
96
  children: a
97
97
  })
@@ -99,19 +99,19 @@ function N({ regionLabel: n, className: r, style: i, children: a }) {
99
99
  });
100
100
  }
101
101
  function P() {
102
- let { toasts: e } = D.useToastManager(), t = (t) => e.filter((e) => e.type === "error" === t).map((e) => /* @__PURE__ */ v("div", { children: [
102
+ let { toasts: e } = D.useToastManager(), t = (t) => e.filter((e) => e.type === "error" === t).map((e) => /* @__PURE__ */ E("div", { children: [
103
103
  e.title,
104
104
  " ",
105
105
  e.description
106
106
  ] }, e.id));
107
- return /* @__PURE__ */ v("div", {
107
+ return /* @__PURE__ */ E("div", {
108
108
  className: u,
109
- children: [/* @__PURE__ */ _("div", {
109
+ children: [/* @__PURE__ */ T("div", {
110
110
  "aria-atomic": !1,
111
111
  "aria-live": "polite",
112
112
  role: "status",
113
113
  children: t(!1)
114
- }), /* @__PURE__ */ _("div", {
114
+ }), /* @__PURE__ */ T("div", {
115
115
  "aria-atomic": !1,
116
116
  "aria-live": "assertive",
117
117
  role: "alert",
@@ -121,16 +121,16 @@ function P() {
121
121
  }
122
122
  function F({ closeLabel: e }) {
123
123
  let { toasts: t } = D.useToastManager();
124
- return t.map((t) => /* @__PURE__ */ _(I, {
124
+ return t.map((t) => /* @__PURE__ */ T(I, {
125
125
  closeLabel: e,
126
126
  toast: t
127
127
  }, t.id));
128
128
  }
129
129
  function I({ toast: a, closeLabel: o }) {
130
- let c = j(a.type) ? a.type : "info", { Icon: l, color: u } = O[c], p = b(k), g = b(A), [y, S] = E(!1), w = x((e) => {
131
- e && S(getComputedStyle(e).direction === "rtl");
132
- }, []), M = T(!1), N = a.transitionStatus === "ending";
133
- return C(() => {
130
+ let c = j(a.type) ? a.type : "info", { Icon: l, color: u } = O[c], p = v(k), g = v(A), [_, b] = w(!1), S = y((e) => {
131
+ e && b(getComputedStyle(e).direction === "rtl");
132
+ }, []), M = C(!1), N = a.transitionStatus === "ending";
133
+ return x(() => {
134
134
  let e = a.ref?.current, t = e?.ownerDocument.activeElement;
135
135
  if (!N || M.current || !t || !e.contains(t)) return;
136
136
  let n = g?.current;
@@ -139,10 +139,10 @@ function I({ toast: a, closeLabel: o }) {
139
139
  N,
140
140
  g,
141
141
  a.ref
142
- ]), /* @__PURE__ */ v(D.Root, {
142
+ ]), /* @__PURE__ */ E(D.Root, {
143
143
  "aria-modal": void 0,
144
- ref: w,
145
- render: /* @__PURE__ */ _(t, {
144
+ ref: S,
145
+ render: /* @__PURE__ */ T(t, {
146
146
  alignItems: "start",
147
147
  backgroundColor: "bgRaised",
148
148
  borderRadius: "med",
@@ -153,16 +153,16 @@ function I({ toast: a, closeLabel: o }) {
153
153
  padding: "12"
154
154
  }),
155
155
  role: "group",
156
- swipeDirection: ["down", y ? "left" : "right"],
156
+ swipeDirection: ["down", _ ? "left" : "right"],
157
157
  toast: a,
158
158
  children: [
159
- /* @__PURE__ */ _(t, {
159
+ /* @__PURE__ */ T(t, {
160
160
  display: "flex",
161
161
  flexShrink: 0,
162
162
  paddingBlock: "2",
163
- children: /* @__PURE__ */ _(l, { color: u })
163
+ children: /* @__PURE__ */ T(l, { color: u })
164
164
  }),
165
- /* @__PURE__ */ v(t, {
165
+ /* @__PURE__ */ E(t, {
166
166
  alignItems: "start",
167
167
  className: f,
168
168
  display: "flex",
@@ -170,22 +170,22 @@ function I({ toast: a, closeLabel: o }) {
170
170
  flexGrow: 1,
171
171
  gap: "8",
172
172
  children: [
173
- /* @__PURE__ */ _(D.Title, { render: /* @__PURE__ */ _(r, {
173
+ /* @__PURE__ */ T(D.Title, { render: /* @__PURE__ */ T(r, {
174
174
  as: "div",
175
175
  weight: "medium"
176
176
  }) }),
177
- /* @__PURE__ */ _(D.Description, { render: /* @__PURE__ */ _(r, {
177
+ /* @__PURE__ */ T(D.Description, { render: /* @__PURE__ */ T(r, {
178
178
  as: "div",
179
179
  color: "fgMuted",
180
180
  size: "sm"
181
181
  }) }),
182
- /* @__PURE__ */ _(D.Action, { render: /* @__PURE__ */ _(i, {
182
+ /* @__PURE__ */ T(D.Action, { render: /* @__PURE__ */ T(i, {
183
183
  size: "sm",
184
184
  variant: "secondary"
185
185
  }) })
186
186
  ]
187
187
  }),
188
- /* @__PURE__ */ _(D.Close, {
188
+ /* @__PURE__ */ T(D.Close, {
189
189
  "aria-hidden": !1,
190
190
  "aria-label": o,
191
191
  onClick: (e) => {
@@ -195,13 +195,13 @@ function I({ toast: a, closeLabel: o }) {
195
195
  n.isConnected && n.focus();
196
196
  }));
197
197
  },
198
- render: /* @__PURE__ */ _(n, {
198
+ render: /* @__PURE__ */ T(n, {
199
199
  borderRadius: "sm",
200
200
  className: d,
201
201
  flexShrink: 0,
202
202
  padding: "4"
203
203
  }),
204
- children: /* @__PURE__ */ _(s, {})
204
+ children: /* @__PURE__ */ T(s, {})
205
205
  })
206
206
  ]
207
207
  });
@@ -211,9 +211,9 @@ function L(e) {
211
211
  return (t(e.nextElementSibling, !0) ?? t(e.previousElementSibling, !1))?.querySelector(`.${d}`);
212
212
  }
213
213
  function R() {
214
- let e = b(k);
214
+ let e = v(k);
215
215
  if (!e) throw Error("useToast must be called under Toast.Provider.");
216
- return w(() => {
216
+ return S(() => {
217
217
  let t = (t) => e.close(t);
218
218
  return {
219
219
  add: ({ title: n, description: r, variant: i = "info", duration: a = i === "error" ? 0 : 5e3, action: o }) => {
@@ -1,2 +1,2 @@
1
- @layer tokens, reset, atoms, components.box, components.checkbox, components.clickable, components.icon, components.icon-button, components.inline, components.stack, components.text, components.avatar, components.badge, components.button, components.chip, components.field, components.color-field, components.heading, components.dialog, components.alert-dialog, components.menu, components.multiselect, components.search-field, components.tabs, components.tag, components.text-field, components.toast, components.visually-hidden;
1
+ @layer tokens, reset, atoms.base, atoms.sm, atoms.med, atoms.lg, atoms.xl, components.box, components.checkbox, components.clickable, components.icon, components.icon-button, components.inline, components.stack, components.text, components.avatar, components.badge, components.button, components.chip, components.field, components.color-field, components.heading, components.dialog, components.alert-dialog, components.menu, components.multiselect, components.search-field, components.tabs, components.tag, components.text-field, components.toast, components.visually-hidden;
2
2
  @layer components.visually-hidden{._1qk18b30{clip-path:inset(50%);white-space:nowrap;border:0;block-size:1px;inline-size:1px;margin:0;padding:0;position:absolute;overflow:hidden}}
package/dist/base.css CHANGED
@@ -1,4 +1,4 @@
1
- @layer tokens, reset, atoms, components.box, components.checkbox, components.clickable, components.icon, components.icon-button, components.inline, components.stack, components.text, components.avatar, components.badge, components.button, components.chip, components.field, components.color-field, components.heading, components.dialog, components.alert-dialog, components.menu, components.multiselect, components.search-field, components.tabs, components.tag, components.text-field, components.toast, components.visually-hidden;
1
+ @layer tokens, reset, atoms.base, atoms.sm, atoms.med, atoms.lg, atoms.xl, components.box, components.checkbox, components.clickable, components.icon, components.icon-button, components.inline, components.stack, components.text, components.avatar, components.badge, components.button, components.chip, components.field, components.color-field, components.heading, components.dialog, components.alert-dialog, components.menu, components.multiselect, components.search-field, components.tabs, components.tag, components.text-field, components.toast, components.visually-hidden;
2
2
  @layer tokens{:root{--space-0:0rem;--space-1:.0625rem;--space-2:.125rem;--space-4:.25rem;--space-6:.375rem;--space-8:.5rem;--space-12:.75rem;--space-16:1rem;--space-20:1.25rem;--space-24:1.5rem;--space-32:2rem;--space-40:2.5rem;--space-48:3rem;--space-64:4rem;--space-80:5rem;--space-96:6rem;--size-xs:1.5rem;--size-sm:2rem;--size-med:2.5rem;--size-lg:3rem;--size-xl:3.5rem;--container-prose:40rem;--container-page:64rem;--container-wide:80rem;--radius-none:0;--radius-sm:.25rem;--radius-med:.5rem;--radius-lg:.75rem;--radius-xl:1rem;--radius-full:9999px;--font-size-xs:.75rem;--font-size-sm:.875rem;--font-size-med:1rem;--font-size-lg:1.125rem;--font-size-xl:1.25rem;--font-size-2xl:1.5rem;--font-size-3xl:1.875rem;--font-size-4xl:2.25rem;--font-weight-regular:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--line-height-sm:1.25;--line-height-med:1.5;--line-height-lg:1.75;--z-index-base:0;--z-index-raised:1;--z-index-dropdown:1000;--z-index-sticky:1100;--z-index-overlay:1200;--z-index-modal:1300;--z-index-popover:1400;--z-index-toast:1500;--z-index-tooltip:1600;--duration-fast:.12s;--duration-med:.2s;--duration-slow:.32s;--easing-standard:cubic-bezier(.2, 0, 0, 1);--easing-enter:cubic-bezier(0, 0, 0, 1);--easing-exit:cubic-bezier(.3, 0, 1, 1);--distance-sm:.25rem;--distance-med:.5rem;--distance-lg:1rem;--scale-sm:.02;--scale-med:.05;--scale-lg:.1}[data-brand]{--shadow-sm:0 1px 2px color-mix(in srgb, var(--color-shadow) 12%, transparent);--shadow-med:0 2px 8px color-mix(in srgb, var(--color-shadow) 14%, transparent), 0 1px 2px color-mix(in srgb, var(--color-shadow) 8%, transparent);--shadow-lg:0 8px 24px color-mix(in srgb, var(--color-shadow) 16%, transparent), 0 2px 6px color-mix(in srgb, var(--color-shadow) 8%, transparent)}[data-brand][data-mode=light]{color-scheme:light}[data-brand][data-mode=dark]{--shadow-sm:0 0 0 1px color-mix(in srgb, var(--color-fg) 10%, transparent), 0 1px 2px color-mix(in srgb, var(--color-shadow) 40%, transparent);--shadow-med:0 0 0 1px color-mix(in srgb, var(--color-fg) 10%, transparent), 0 2px 8px color-mix(in srgb, var(--color-shadow) 48%, transparent), 0 1px 2px color-mix(in srgb, var(--color-shadow) 32%, transparent);--shadow-lg:0 0 0 1px color-mix(in srgb, var(--color-fg) 10%, transparent), 0 8px 24px color-mix(in srgb, var(--color-shadow) 56%, transparent), 0 2px 6px color-mix(in srgb, var(--color-shadow) 32%, transparent);color-scheme:dark}[data-brand][data-mode=system]{color-scheme:light dark}:dir(ltr){--dir:1}:dir(rtl){--dir:-1}@media (prefers-color-scheme:dark){[data-brand][data-mode=system]{--shadow-sm:0 0 0 1px color-mix(in srgb, var(--color-fg) 10%, transparent), 0 1px 2px color-mix(in srgb, var(--color-shadow) 40%, transparent);--shadow-med:0 0 0 1px color-mix(in srgb, var(--color-fg) 10%, transparent), 0 2px 8px color-mix(in srgb, var(--color-shadow) 48%, transparent), 0 1px 2px color-mix(in srgb, var(--color-shadow) 32%, transparent);--shadow-lg:0 0 0 1px color-mix(in srgb, var(--color-fg) 10%, transparent), 0 8px 24px color-mix(in srgb, var(--color-shadow) 56%, transparent), 0 2px 6px color-mix(in srgb, var(--color-shadow) 32%, transparent)}}@media (prefers-reduced-motion:reduce){:root{--distance-sm:0rem;--distance-med:0rem;--distance-lg:0rem;--scale-sm:0;--scale-med:0;--scale-lg:0;--duration-fast:.12s;--duration-med:.12s;--duration-slow:.12s}}}
3
3
 
4
4
  @font-face{src:local(Arial),local(ArialMT);font-weight:400;font-style:normal;size-adjust:101.568%;ascent-override:95.3892%;descent-override:23.7511%;line-gap-override:0%;font-family:Inter Fallback Arial}@font-face{src:local(Arial Bold),local(Arial-BoldMT);font-weight:700;font-style:normal;size-adjust:101.637%;ascent-override:95.3241%;descent-override:23.7349%;line-gap-override:0%;font-family:Inter Fallback Arial}@font-face{src:local(Arial Italic),local(Arial-ItalicMT);font-weight:400;font-style:italic;size-adjust:101.637%;ascent-override:95.3241%;descent-override:23.7349%;line-gap-override:0%;font-family:Inter Fallback Arial}@font-face{src:local(Arial Bold Italic),local(Arial-BoldItalicMT);font-weight:700;font-style:italic;size-adjust:101.706%;ascent-override:95.2591%;descent-override:23.7187%;line-gap-override:0%;font-family:Inter Fallback Arial}@font-face{src:local(Menlo Regular),local(Menlo-Regular);font-weight:400;font-style:normal;size-adjust:100.137%;ascent-override:101.871%;descent-override:29.9621%;line-gap-override:0%;font-family:JetBrains Mono Fallback Menlo}@font-face{src:local(Menlo Bold),local(Menlo-Bold);font-weight:700;font-style:normal;size-adjust:100.003%;ascent-override:102.007%;descent-override:30.0022%;line-gap-override:0%;font-family:JetBrains Mono Fallback Menlo}@font-face{src:local(Menlo Italic),local(Menlo-Italic);font-weight:400;font-style:italic;size-adjust:100.137%;ascent-override:101.871%;descent-override:29.9621%;line-gap-override:0%;font-family:JetBrains Mono Fallback Menlo}@font-face{src:local(Menlo Bold Italic),local(Menlo-BoldItalic);font-weight:700;font-style:italic;size-adjust:100.003%;ascent-override:102.007%;descent-override:30.0022%;line-gap-override:0%;font-family:JetBrains Mono Fallback Menlo}@font-face{src:local(Consolas);font-weight:400;font-style:normal;size-adjust:114.387%;ascent-override:89.1798%;descent-override:26.2293%;line-gap-override:0%;font-family:JetBrains Mono Fallback Consolas}@font-face{src:local(Consolas Bold),local(Consolas-Bold);font-weight:700;font-style:normal;size-adjust:114.387%;ascent-override:89.1798%;descent-override:26.2293%;line-gap-override:0%;font-family:JetBrains Mono Fallback Consolas}@font-face{src:local(Consolas Italic),local(Consolas-Italic);font-weight:400;font-style:italic;size-adjust:114.387%;ascent-override:89.1798%;descent-override:26.2293%;line-gap-override:0%;font-family:JetBrains Mono Fallback Consolas}@font-face{src:local(Consolas Bold Italic),local(Consolas-BoldItalic);font-weight:700;font-style:italic;size-adjust:114.387%;ascent-override:89.1798%;descent-override:26.2293%;line-gap-override:0%;font-family:JetBrains Mono Fallback Consolas}@font-face{src:local(Courier New),local(CourierNewPSMT);font-weight:400;font-style:normal;size-adjust:127.781%;ascent-override:79.8319%;descent-override:23.48%;line-gap-override:0%;font-family:JetBrains Mono Fallback Courier New}@font-face{src:local(Courier New Bold),local(CourierNewPS-BoldMT);font-weight:700;font-style:normal;size-adjust:123.353%;ascent-override:82.6977%;descent-override:24.3229%;line-gap-override:0%;font-family:JetBrains Mono Fallback Courier New}@font-face{src:local(Courier New Italic),local(CourierNewPS-ItalicMT);font-weight:400;font-style:italic;size-adjust:127.781%;ascent-override:79.8319%;descent-override:23.48%;line-gap-override:0%;font-family:JetBrains Mono Fallback Courier New}@font-face{src:local(Courier New Bold Italic),local(CourierNewPS-BoldItalicMT);font-weight:700;font-style:italic;size-adjust:123.353%;ascent-override:82.6977%;descent-override:24.3229%;line-gap-override:0%;font-family:JetBrains Mono Fallback Courier New}@layer tokens{[data-brand=default]{--color-bg:light-dark(oklch(100% 0 0),oklch(14.5% .006 265));--color-bg-muted:light-dark(oklch(96.8% .004 265),oklch(27% .01 265));--color-bg-raised:light-dark(oklch(100% 0 0),oklch(20.5% .008 265));--color-fg:light-dark(oklch(14.5% .006 265),oklch(98.5% .002 265));--color-fg-muted:light-dark(oklch(44.5% .014 265),oklch(71% .012 265));--color-border:light-dark(oklch(92.5% .006 265),oklch(27% .01 265));--color-border-strong:oklch(55.5% .014 265);--color-accent:light-dark(oklch(54.6% .19 258),oklch(70.7% .14 258));--color-accent-fg:light-dark(oklch(100% 0 0),oklch(14.5% .006 265));--color-accent-fill:light-dark(oklch(54.6% .19 258),oklch(48.8% .18 258));--color-accent-fill-fg:oklch(100% 0 0);--color-danger:light-dark(oklch(56% .2 25),oklch(70.4% .17 25));--color-danger-fg:light-dark(oklch(100% 0 0),oklch(14.5% .006 265));--color-success:light-dark(oklch(52% .135 150),oklch(76% .15 150));--color-success-fg:light-dark(oklch(100% 0 0),oklch(14.5% .006 265));--color-warning:light-dark(oklch(53% .11 75),oklch(81% .145 75));--color-warning-fg:light-dark(oklch(100% 0 0),oklch(14.5% .006 265));--color-done:light-dark(oklch(55% .2 295),oklch(72% .15 295));--color-done-fg:light-dark(oklch(100% 0 0),oklch(14.5% .006 265));--color-neutral-subtle:light-dark(oklch(96.8% .004 265),oklch(27% .01 265));--color-neutral-subtle-fg:light-dark(oklch(37% .013 265),oklch(92.5% .006 265));--color-accent-subtle:light-dark(oklch(93.2% .032 258),oklch(28.2% .09 258));--color-accent-subtle-fg:light-dark(oklch(48.8% .18 258),oklch(80.9% .095 258));--color-success-subtle:light-dark(oklch(94.5% .04 150),oklch(26% .06 150));--color-success-subtle-fg:light-dark(oklch(46.5% .12 150),oklch(84% .115 150));--color-warning-subtle:light-dark(oklch(95.5% .03 75),oklch(27% .05 75));--color-warning-subtle-fg:light-dark(oklch(47.5% .1 75),oklch(86% .105 75));--color-danger-subtle:light-dark(oklch(93.6% .032 25),oklch(25.8% .085 25));--color-danger-subtle-fg:light-dark(oklch(50.5% .19 25),oklch(80.8% .105 25));--color-done-subtle:light-dark(oklch(93.8% .032 295),oklch(28% .095 295));--color-done-subtle-fg:light-dark(oklch(49% .19 295),oklch(81.5% .1 295));--color-focus:light-dark(oklch(54.6% .19 258),oklch(70.7% .14 258));--color-shadow:light-dark(oklch(14.5% .006 265),oklch(0% 0 0));--font-body:"Inter", "Inter Fallback Arial", sans-serif;--font-heading:"Inter", "Inter Fallback Arial", sans-serif;--font-display:"Inter", "Inter Fallback Arial", sans-serif;--font-label:"Inter", "Inter Fallback Arial", sans-serif;--font-mono:"JetBrains Mono", "JetBrains Mono Fallback Menlo", "JetBrains Mono Fallback Consolas", "JetBrains Mono Fallback Courier New", monospace;--font-trim-body-cap:.36377;--font-trim-body-baseline:.36377;--font-trim-heading-cap:.36377;--font-trim-heading-baseline:.36377;--font-trim-display-cap:.36377;--font-trim-display-baseline:.36377;--font-trim-label-cap:.36377;--font-trim-label-baseline:.36377;--font-trim-mono-cap:.37;--font-trim-mono-baseline:.36}@media (forced-colors:active){[data-brand][data-brand]{--color-bg:Canvas;--color-bg-muted:Canvas;--color-bg-raised:Canvas;--color-fg:CanvasText;--color-fg-muted:CanvasText;--color-border:CanvasText;--color-border-strong:CanvasText;--color-accent:LinkText;--color-accent-fg:Canvas;--color-accent-fill:LinkText;--color-accent-fill-fg:Canvas;--color-danger:CanvasText;--color-danger-fg:Canvas;--color-success:CanvasText;--color-success-fg:Canvas;--color-warning:CanvasText;--color-warning-fg:Canvas;--color-done:CanvasText;--color-done-fg:Canvas;--color-neutral-subtle:Canvas;--color-neutral-subtle-fg:CanvasText;--color-accent-subtle:Canvas;--color-accent-subtle-fg:CanvasText;--color-success-subtle:Canvas;--color-success-subtle-fg:CanvasText;--color-warning-subtle:Canvas;--color-warning-subtle-fg:CanvasText;--color-danger-subtle:Canvas;--color-danger-subtle-fg:CanvasText;--color-done-subtle:Canvas;--color-done-subtle-fg:CanvasText;--color-focus:Highlight;--color-shadow:CanvasText}}}
package/dist/docs/Menu.md CHANGED
@@ -20,12 +20,14 @@ A list of actions that opens from a button: a row's "Edit, Duplicate, Delete", a
20
20
  ## Rules
21
21
 
22
22
  - Compose the parts: `Menu` > `Menu.Trigger` + `Menu.Popup` > `Menu.Item`, `Menu.LinkItem`, `Menu.Separator`, `Menu.Group`. `Menu` holds the open state and renders no element, so it takes no `className` or `style`; every other part does, plus style props.
23
- - `Menu.Trigger` is a bare `Clickable`: give it its look with style props (or your own class), and an accessible name. An icon-only trigger needs `aria-label`.
23
+ - `Menu.Trigger` is a bare `Clickable`: give it its look with style props (or your own class), and an accessible name.
24
+ - For an icon-only trigger ("More actions"), pass `icon` and `label`: it renders an `IconButton`, the same square as one at each `size` (`sm`, `med`, `lg`; `med` by default), named by `label`, with IconButton's `variant` (`secondary` by default) and the open look below. It takes no children, `iconStart`, `iconEnd` or `aria-label` (ADR 0123). Never build one from `iconStart` and `aria-label`: Button's padding makes it wider than the IconButtons beside it.
24
25
  - For a trigger that reads as a button ("Actions", "New"), pass Button's `variant`, `size`, `iconStart` or `iconEnd` (a `ChevronDownIcon` for "Actions ▾"): it renders a `Button`, with its fill, border and height, and keeps the trigger's behavior and `aria-disabled`. While the menu is open it shows Button's open look, a held tint and an inset ring (ADR 0063); a bare trigger has none, so style it yourself off `aria-expanded`. Style props still override the defaults.
25
26
  - `Menu.Item` runs its `onClick` on click, Enter and Space, then the menu closes. Pass `closeOnClick={false}` to keep it open.
26
27
  - `Menu.LinkItem` is a real `<a role="menuitem">` for an entry that goes somewhere. `href` is required; `target`, `rel` and `download` pass through. Hover shows the URL, Cmd/Ctrl-click and middle-click open a new tab, and a click, Enter or Space follows it and closes the menu. Never navigate from a `Menu.Item`'s `onClick` (`location.assign`, a router's `navigate`): it loses all of that. Router-aware (client-side) links are not offered. It takes no `variant`.
27
28
  - `variant="danger"` marks a destructive item. It still runs on one click, so open a confirm dialog from it (Cancel focused first) before anything irreversible happens.
28
29
  - `disabled` on an item renders `aria-disabled`: it stays announced and reachable with the arrow keys, and does nothing. A disabled `Menu.LinkItem` also drops its `href`, so no click or context menu reaches the URL. On the trigger it keeps the button focusable and stops it opening.
30
+ - `description` on `Menu.Item` or `Menu.LinkItem` puts a short line of muted text below the label, such as why a disabled item cannot act ("Already running"). The item grows to fit both lines. Put secondary text there, never as a second line in the children, which overlaps the label and joins its name.
29
31
  - `Menu.Group` takes a `label` that is shown and names the group. Separate groups with `Menu.Separator`.
30
32
  - `Menu.Separator` draws a line inside its own padding (`paddingBlock="4"`, `paddingInline="8"`) and sets no margin. Change its spacing with `paddingBlock` and `paddingInline` (the `padding` shorthand loses to these defaults, decision 0065); a `margin*` prop adds space outside the padding. `style={{ borderBlockStartColor }}` recolours the line.
31
33
  - The popup portals into the trigger's nearest `ThemeProvider`, so it keeps the brand and mode. That provider must not clip or stack its content: wrap the app root, and keep a nested provider off elements with `overflow: hidden`, a `transform` or their own `z-index`, or the popup is clipped or drawn under siblings. It sits on `zIndex` `popover`. A menu opened only through `open`, with no `Menu.Trigger`, has no provider to find and portals to `<body>`.
@@ -38,9 +40,7 @@ A list of actions that opens from a button: a row's "Edit, Duplicate, Delete", a
38
40
 
39
41
  ```tsx
40
42
  <Menu>
41
- <Menu.Trigger aria-label="Actions for Invoice 42" paddingInline="8" borderRadius="sm">
42
- <MoreIcon />
43
- </Menu.Trigger>
43
+ <Menu.Trigger icon={EllipsisIcon} label="Actions for Invoice 42" />
44
44
  <Menu.Popup>
45
45
  <Menu.Item onClick={edit}>Edit</Menu.Item>
46
46
  <Menu.Item onClick={duplicate}>Duplicate</Menu.Item>
@@ -61,6 +61,20 @@ A list of actions that opens from a button: a row's "Edit, Duplicate, Delete", a
61
61
  </Menu.Popup>
62
62
  ```
63
63
 
64
+ ```tsx
65
+ <Menu>
66
+ <Menu.Trigger icon={EllipsisIcon} label="More actions" size="sm" />
67
+ <Menu.Popup>
68
+ <Menu.Item onClick={retry} description="Runs it again from the start">
69
+ Retry
70
+ </Menu.Item>
71
+ <Menu.Item disabled description="Already running">
72
+ Unqueue
73
+ </Menu.Item>
74
+ </Menu.Popup>
75
+ </Menu>
76
+ ```
77
+
64
78
  ```tsx
65
79
  <Menu>
66
80
  <Menu.Trigger variant="secondary" size="sm">
@@ -93,6 +107,19 @@ A list of actions that opens from a button: a row's "Edit, Duplicate, Delete", a
93
107
  </Menu.Item>
94
108
  ```
95
109
 
110
+ ```tsx
111
+ // Button's padding makes this wider than an IconButton. Use icon={EllipsisIcon} label="More actions".
112
+ <Menu.Trigger iconStart={EllipsisIcon} aria-label="More actions" size="sm" />
113
+ ```
114
+
115
+ ```tsx
116
+ // The second line overlaps the label and joins the item's name. Use description="Already running".
117
+ <Menu.Item disabled>
118
+ Unqueue
119
+ <Text size="xs">Already running</Text>
120
+ </Menu.Item>
121
+ ```
122
+
96
123
  ```tsx
97
124
  // Base UI already moves focus with the arrow keys; this fights it.
98
125
  <Menu.Item onKeyDown={(event) => event.key === "ArrowDown" && next()}>Edit</Menu.Item>
@@ -116,7 +143,10 @@ A list of actions that opens from a button: a row's "Edit, Duplicate, Delete", a
116
143
  - The trigger has `aria-haspopup="menu"` and `aria-expanded`; the popup is `role="menu"` labelled by the trigger, items and link items are `role="menuitem"` (a link item is an `<a>` with an `href`, so the browser treats it as a link), groups are `role="group"` named by their label.
117
144
  - Opening from the keyboard focuses the first item; from the pointer, the popup. Focus stays in the menu until it closes. Closed by Esc, an item or `open={false}`, focus returns at once to the trigger that opened it, so a Tab pressed while it fades goes on to the control after the trigger. A press outside, a Tab out, a hover menu the pointer left, or a popup with `finalFocus` leaves focus to Base UI, which places it when the fade ends.
118
145
  - A closed menu stays on the page while it fades out, but is `inert` and `aria-hidden` from the moment it closes, so a menu opened during the fade (the next row's) is the only one a screen reader or a role query finds, and nothing in the fading one takes focus or a click.
119
- - The highlighted item gets a fill (`bgMuted` in light mode; in dark mode `bgRaised` with 10% `fg` mixed in, since `bgMuted` sits too close to the popup there), and the shared focus ring when reached from the keyboard. Under forced colors it is `Highlight` with `HighlightText`, disabled items are `GrayText` on the page's fill even when highlighted (`GrayText` pairs with `Canvas` only), and the popup keeps its border.
146
+ - The icon trigger's name is its `label`, as `aria-label`.
147
+ - An item's `description` is its accessible description (`aria-describedby`), read after its name; the name stays the label alone. An `aria-describedby` of the item's own is kept, read after the description. With plain-text children, typeahead matches the label alone, not the description; otherwise pass `label`.
148
+ - The popup is never wider than the viewport beside its trigger, so at 320 px and 200% text a long item wraps inside it (WCAG 1.4.10).
149
+ - The highlighted item gets a fill (`bgMuted` in light mode; in dark mode `bgRaised` with 10% `fg` mixed in, since `bgMuted` sits too close to the popup there), the same from the pointer and the keyboard. From the keyboard it also gets the shared focus ring, drawn inside the item so it never meets the popup's edge; the fill alone is under 3:1 on the popup, the ring passes 3:1 on the fill (`Menu.test.tsx` checks it). Under forced colors it is `Highlight` with `HighlightText`; from the keyboard the fill drops to `Canvas` so the `Highlight` ring alone marks the item; disabled items are `GrayText` on the page's fill even when highlighted (`GrayText` pairs with `Canvas` only) and marked by the ring, and the popup keeps its border.
120
150
  - The danger item's `danger` color passes 4.5:1 on the popup and on the highlight fill in every preset (`Menu.test.tsx` checks it, with `fg` and `fgMuted`); the word ("Delete") carries the meaning, not the color.
121
151
 
122
152
  ## Props
@@ -152,6 +182,7 @@ Also accepts the style props (see `manifest.json` `styleProps`).
152
182
  | --- | --- | --- | --- |
153
183
  | `className` | `string` | no | |
154
184
  | `closeOnClick` | `boolean` | no | Whether to close the menu when the item is clicked. |
185
+ | `description` | `ReactNode` | no | |
155
186
  | `disabled` | `boolean` | no | Whether the component should ignore user interaction. |
156
187
  | `id` | `string` | no | |
157
188
  | `label` | `string` | no | Overrides the text used for keyboard text navigation and filtering. Falls back to the rendered text when not provided. |
@@ -168,6 +199,7 @@ Also accepts the style props (see `manifest.json` `styleProps`).
168
199
  | --- | --- | --- | --- |
169
200
  | `className` | `string` | no | |
170
201
  | `closeOnClick` | `boolean` | no | Whether to close the menu when the item is clicked. |
202
+ | `description` | `ReactNode` | no | |
171
203
  | `disabled` | `boolean` | no | |
172
204
  | `href` | `string` | yes | |
173
205
  | `id` | `string` | no | |
@@ -204,13 +236,17 @@ Also accepts the style props (see `manifest.json` `styleProps`).
204
236
 
205
237
  | Prop | Type | Required | Description |
206
238
  | --- | --- | --- | --- |
239
+ | `aria-label` | `string` | no | Defines a string value that labels the current element. |
240
+ | `aria-labelledby` | `string` | no | Identifies the element (or elements) that labels the current element. |
207
241
  | `children` | `ReactNode` | no | |
208
242
  | `closeDelay` | `number` | no | How long to wait before closing the menu that was opened on hover. Specified in milliseconds. Requires the `openOnHover` prop. |
209
243
  | `delay` | `number` | no | How long to wait before the menu may be opened on hover. Specified in milliseconds. Requires the `openOnHover` prop. |
210
244
  | `disabled` | `boolean` | no | Whether the component should ignore user interaction. |
211
245
  | `handle` | `MenuHandle<unknown>` | no | A handle to associate the trigger with a menu. |
246
+ | `icon` | `ComponentType` | no | |
212
247
  | `iconEnd` | `ComponentType` | no | |
213
248
  | `iconStart` | `ComponentType` | no | |
249
+ | `label` | `string` | no | |
214
250
  | `openOnHover` | `boolean` | no | Whether the menu should also open when the trigger is hovered. |
215
251
  | `payload` | `unknown` | no | A payload to pass to the menu when it is opened. |
216
252
  | `size` | `"lg" \| "med" \| "sm"` | no | |
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "./manifest.schema.json",
3
3
  "package": "@jonmilner/ui",
4
- "version": "0.8.1",
4
+ "version": "0.9.0",
5
5
  "components": [
6
6
  {
7
7
  "name": "AlertDialog",
@@ -1301,6 +1301,11 @@
1301
1301
  "required": false,
1302
1302
  "description": "Whether to close the menu when the item is clicked."
1303
1303
  },
1304
+ {
1305
+ "name": "description",
1306
+ "type": "ReactNode",
1307
+ "required": false
1308
+ },
1304
1309
  {
1305
1310
  "name": "disabled",
1306
1311
  "type": "boolean",
@@ -1361,6 +1366,11 @@
1361
1366
  "required": false,
1362
1367
  "description": "Whether to close the menu when the item is clicked."
1363
1368
  },
1369
+ {
1370
+ "name": "description",
1371
+ "type": "ReactNode",
1372
+ "required": false
1373
+ },
1364
1374
  {
1365
1375
  "name": "disabled",
1366
1376
  "type": "boolean",
@@ -1476,6 +1486,18 @@
1476
1486
  "name": "Menu.Trigger",
1477
1487
  "styleProps": true,
1478
1488
  "props": [
1489
+ {
1490
+ "name": "aria-label",
1491
+ "type": "string",
1492
+ "required": false,
1493
+ "description": "Defines a string value that labels the current element."
1494
+ },
1495
+ {
1496
+ "name": "aria-labelledby",
1497
+ "type": "string",
1498
+ "required": false,
1499
+ "description": "Identifies the element (or elements) that labels the current element."
1500
+ },
1479
1501
  {
1480
1502
  "name": "children",
1481
1503
  "type": "ReactNode",
@@ -1505,6 +1527,11 @@
1505
1527
  "required": false,
1506
1528
  "description": "A handle to associate the trigger with a menu."
1507
1529
  },
1530
+ {
1531
+ "name": "icon",
1532
+ "type": "ComponentType",
1533
+ "required": false
1534
+ },
1508
1535
  {
1509
1536
  "name": "iconEnd",
1510
1537
  "type": "ComponentType",
@@ -1515,6 +1542,11 @@
1515
1542
  "type": "ComponentType",
1516
1543
  "required": false
1517
1544
  },
1545
+ {
1546
+ "name": "label",
1547
+ "type": "string",
1548
+ "required": false
1549
+ },
1518
1550
  {
1519
1551
  "name": "openOnHover",
1520
1552
  "type": "boolean",
@@ -0,0 +1,27 @@
1
+ # 0.9.0
2
+
3
+ The style-prop atoms are split by breakpoint (decision 0111): `atoms.css` keeps the base rules, and the `sm`, `med`, `lg` and `xl` rules move to `@jonmilner/ui/responsive.css`, which only Box, Stack and Inline import. A responsive style prop on any other component (`<Button marginBlock={{ base: "8", med: "16" }}>`) keeps only its `base` value unless `responsive.css` is on the page. No prop, value, breakpoint or existing import path changes.
4
+
5
+ ## Find
6
+
7
+ In the app's source (`*.tsx`), every responsive style-prop value: regex `=\{\{\s*(base|sm|med|lg|xl)\s*:`. A match on an element other than `Box`, `Stack` or `Inline` needs the import below, unless every page that renders it also renders a Box, Stack or Inline from `@jonmilner/ui`. Values built elsewhere and spread in (`{...layout}`) are not found by the regex; search for the breakpoint keys `\b(sm|med|lg|xl)\s*:` near style props too.
8
+
9
+ In development, the browser console also shows `@jonmilner/ui: a responsive style prop rendered without the breakpoint rules` on any page that misses it.
10
+
11
+ ## Replace
12
+
13
+ Import the breakpoint rules once, as a JS import, in the app's root module (the root layout or entry), beside any `@jonmilner/ui/base.css` import. A CSS `@import` may be inlined into a second copy, so use the JS form.
14
+
15
+ ```ts
16
+ // before
17
+ import "@jonmilner/ui/base.css";
18
+ // after
19
+ import "@jonmilner/ui/base.css";
20
+ import "@jonmilner/ui/responsive.css";
21
+ ```
22
+
23
+ An app with no responsive value outside Box, Stack and Inline needs no change; the import is still safe, since it is the same file those three load.
24
+
25
+ ## Verify
26
+
27
+ Run the app in development and load each page that has a responsive value outside Box, Stack and Inline; the console shows no `@jonmilner/ui: a responsive style prop rendered without the breakpoint rules` warning, and at a viewport of 48em or wider a `med` value applies (for example, the computed `margin-block` of the Button above is 16px).
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { Box, BoxProps, StyleProps } from "./Box/index.mjs";
1
+ import { BoxProps, StyleProps } from "./Box/base.mjs";
2
2
  import { Clickable, ClickableProps } from "./Clickable/index.mjs";
3
3
  import { Icon, IconProps } from "./Icon/index.mjs";
4
4
  import { Button, ButtonProps } from "./Button/index.mjs";
@@ -7,6 +7,7 @@ import { DialogCloseProps, DialogTriggerProps } from "./Dialog/client.mjs";
7
7
  import { AlertDialog, AlertDialogProps, AlertDialogTriggerProps } from "./AlertDialog/index.mjs";
8
8
  import { Avatar, AvatarProps } from "./Avatar/index.mjs";
9
9
  import { Badge, BadgeProps } from "./Badge/index.mjs";
10
+ import { Box } from "./Box/index.mjs";
10
11
  import { Checkbox, CheckboxProps } from "./Checkbox/index.mjs";
11
12
  import { Chip, ChipGroup, ChipGroupProps, ChipProps } from "./Chip/index.mjs";
12
13
  import { SearchFieldInputProps } from "./SearchField/client.mjs";
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
- import { Box as e } from "./Box/index.mjs";
2
- import { Clickable as t } from "./Clickable/index.mjs";
3
- import { Icon as n } from "./Icon/index.mjs";
4
- import { Text as r } from "./Text/index.mjs";
5
- import { Button as i } from "./Button/index.mjs";
6
- import { Heading as a } from "./Heading/index.mjs";
7
- import { Dialog as o } from "./Dialog/index.mjs";
8
- import { AlertDialog as s } from "./AlertDialog/index.mjs";
9
- import { Avatar as c } from "./Avatar/index.mjs";
10
- import { Badge as l } from "./Badge/index.mjs";
1
+ import { Clickable as e } from "./Clickable/index.mjs";
2
+ import { Icon as t } from "./Icon/index.mjs";
3
+ import { Text as n } from "./Text/index.mjs";
4
+ import { Button as r } from "./Button/index.mjs";
5
+ import { Heading as i } from "./Heading/index.mjs";
6
+ import { Dialog as a } from "./Dialog/index.mjs";
7
+ import { AlertDialog as o } from "./AlertDialog/index.mjs";
8
+ import { Avatar as s } from "./Avatar/index.mjs";
9
+ import { Badge as c } from "./Badge/index.mjs";
10
+ import { Box as l } from "./Box/index.mjs";
11
11
  import { Checkbox as u } from "./Checkbox/index.mjs";
12
12
  import { Chip as d, ChipGroup as f } from "./Chip/index.mjs";
13
13
  import { Field as p } from "./Field/index.mjs";
@@ -26,4 +26,4 @@ import { ThemeProvider as T } from "./theme/ThemeProvider.mjs";
26
26
  import { useToast as E } from "./Toast/client.mjs";
27
27
  import { Toast as D } from "./Toast/index.mjs";
28
28
  import { VisuallyHidden as O } from "./VisuallyHidden/index.mjs";
29
- export { s as AlertDialog, c as Avatar, l as Badge, e as Box, i as Button, u as Checkbox, d as Chip, f as ChipGroup, t as Clickable, m as ColorField, o as Dialog, p as Field, a as Heading, n as Icon, h as IconButton, g as Inline, _ as Menu, v as MultiSelect, y as SearchField, b as Stack, x as Tabs, S as Tag, r as Text, C as TextField, T as ThemeProvider, D as Toast, O as VisuallyHidden, w as defineTheme, E as useToast };
29
+ export { o as AlertDialog, s as Avatar, c as Badge, l as Box, r as Button, u as Checkbox, d as Chip, f as ChipGroup, e as Clickable, m as ColorField, a as Dialog, p as Field, i as Heading, t as Icon, h as IconButton, g as Inline, _ as Menu, v as MultiSelect, y as SearchField, b as Stack, x as Tabs, S as Tag, n as Text, C as TextField, T as ThemeProvider, D as Toast, O as VisuallyHidden, w as defineTheme, E as useToast };