@hideyukimori/nene2-ui 0.3.0 → 0.6.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 (51) hide show
  1. package/README.md +16 -2
  2. package/dist/data/DetailList.d.ts +3 -1
  3. package/dist/data/DetailList.js +3 -2
  4. package/dist/data/DetailList.js.map +1 -1
  5. package/dist/data/Pagination.d.ts +44 -13
  6. package/dist/data/Pagination.js +20 -8
  7. package/dist/data/Pagination.js.map +1 -1
  8. package/dist/feedback/InlineAlert.d.ts +6 -1
  9. package/dist/feedback/InlineAlert.js +8 -2
  10. package/dist/feedback/InlineAlert.js.map +1 -1
  11. package/dist/feedback/ToastProvider.js +2 -2
  12. package/dist/feedback/ToastProvider.js.map +1 -1
  13. package/dist/forms/FormField.js +1 -1
  14. package/dist/forms/FormField.js.map +1 -1
  15. package/dist/index.d.ts +1 -1
  16. package/dist/index.js +1 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/layout/PageHeader.d.ts +3 -1
  19. package/dist/layout/PageHeader.js +3 -2
  20. package/dist/layout/PageHeader.js.map +1 -1
  21. package/dist/lib/states.d.ts +15 -0
  22. package/dist/lib/states.js +15 -0
  23. package/dist/lib/states.js.map +1 -1
  24. package/dist/primitives/Button.d.ts +9 -2
  25. package/dist/primitives/Button.js +17 -5
  26. package/dist/primitives/Button.js.map +1 -1
  27. package/dist/primitives/Checkbox.d.ts +7 -0
  28. package/dist/primitives/Checkbox.js +9 -2
  29. package/dist/primitives/Checkbox.js.map +1 -1
  30. package/dist/primitives/Radio.d.ts +4 -0
  31. package/dist/primitives/Radio.js +6 -2
  32. package/dist/primitives/Radio.js.map +1 -1
  33. package/dist/primitives/Spinner.d.ts +3 -1
  34. package/dist/primitives/Spinner.js +3 -2
  35. package/dist/primitives/Spinner.js.map +1 -1
  36. package/dist/primitives/Switch.js +2 -2
  37. package/dist/primitives/Switch.js.map +1 -1
  38. package/dist/primitives/Text.d.ts +3 -1
  39. package/dist/primitives/Text.js +4 -3
  40. package/dist/primitives/Text.js.map +1 -1
  41. package/dist/states/EmptyState.d.ts +11 -1
  42. package/dist/states/EmptyState.js +3 -2
  43. package/dist/states/EmptyState.js.map +1 -1
  44. package/dist/states/ErrorState.d.ts +3 -1
  45. package/dist/states/ErrorState.js +3 -2
  46. package/dist/states/ErrorState.js.map +1 -1
  47. package/dist/states/LoadingState.d.ts +3 -1
  48. package/dist/states/LoadingState.js +3 -2
  49. package/dist/states/LoadingState.js.map +1 -1
  50. package/package.json +1 -1
  51. package/themes/default.css +55 -2
package/README.md CHANGED
@@ -191,8 +191,22 @@ A slot can hold several steps — four-sided padding is just CSS:
191
191
  🔴 **There is no shorthand for this, on purpose.** The kit's tokens are written by tooling,
192
192
  not typed by hand, so brevity buys nothing — and a shorthand would need an expander, which is
193
193
  one more layer that can quietly drop meaning. Plain `var()` composition has no such layer, and
194
- it can be checked with a regular expression exactly as written: **every value in a slot is a
195
- `var(--spacing-*)` or `var(--radius-*)`, and nothing else.**
194
+ it can be checked with a regular expression exactly as written.
195
+
196
+ ### What the rule covers
197
+
198
+ | namespace | slot values | why |
199
+ | ------------------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
200
+ | `--spacing-*` `--radius-*` `--text-*` | 🔒 **scale references only** | each has a scale, so a literal here is a step the product invented |
201
+ | `--color-*` | scale (palette) references | same |
202
+ | `--brightness-*` `--opacity-*` | literals are fine | **there is no scale to reference.** A hover darkening of 95% is not a step in a series; inventing a "brightness scale" so the rule could cover it would be a scale with one real user |
203
+
204
+ 🔴 **Check the three namespaces that have scales, not every slot.** Until 0.6.0 this section
205
+ said "and nothing else", while the kit's own theme held `--text-x-slot-field-label-size:
206
+ 0.75rem` and `--brightness-x-slot-hover: 95%` — so a product implementing the rule as written
207
+ built a check that failed the kit (nene-vault did exactly that, 2026-08-23). The type scale
208
+ now exists and the text slots reference it; brightness is stated as the exception it always
209
+ was.
196
210
 
197
211
  That check is what keeps the scale from leaking. `--spacing-x-slot-field-gap: 0.5625rem`
198
212
  compiles, looks reasonable, and reintroduces the drift the scale exists to stop — so it fails
@@ -5,10 +5,12 @@ export interface DetailRow {
5
5
  value: ReactNode;
6
6
  }
7
7
  export interface DetailListProps {
8
+ /** Composed after the kit's own classes (design principle 2). */
9
+ className?: string;
8
10
  rows: DetailRow[];
9
11
  }
10
12
  /**
11
13
  * Read-only key/value display for detail screens. Uses a description list so the
12
14
  * label/value relationship is conveyed to assistive technology.
13
15
  */
14
- export declare function DetailList({ rows }: DetailListProps): import("react").JSX.Element;
16
+ export declare function DetailList({ rows, className }: DetailListProps): import("react").JSX.Element;
@@ -1,9 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cx } from '../lib/cx.js';
2
3
  /**
3
4
  * Read-only key/value display for detail screens. Uses a description list so the
4
5
  * label/value relationship is conveyed to assistive technology.
5
6
  */
6
- export function DetailList({ rows }) {
7
- return (_jsx("dl", { className: "flex flex-col gap-x-slot-detail-gap", children: rows.map((row) => (_jsxs("div", { className: "flex flex-col gap-x-slot-detail-row-gap border-b border-border py-x-slot-detail-row-pad-y", children: [_jsx("dt", { className: "font-sans font-medium text-text-muted", children: row.label }), _jsx("dd", { className: "font-sans text-text-primary", children: row.value })] }, row.label))) }));
7
+ export function DetailList({ rows, className }) {
8
+ return (_jsx("dl", { className: cx('flex flex-col gap-x-slot-detail-gap', className), children: rows.map((row) => (_jsxs("div", { className: "flex flex-col gap-x-slot-detail-row-gap border-b border-border py-x-slot-detail-row-pad-y", children: [_jsx("dt", { className: "font-sans font-medium text-text-muted", children: row.label }), _jsx("dd", { className: "font-sans text-text-primary", children: row.value })] }, row.label))) }));
8
9
  }
9
10
  //# sourceMappingURL=DetailList.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DetailList.js","sourceRoot":"","sources":["../../src/data/DetailList.tsx"],"names":[],"mappings":";AAYA;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,EAAE,IAAI,EAAmB;IAClD,OAAO,CACL,aAAI,SAAS,EAAC,qCAAqC,YAChD,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACjB,eAEE,SAAS,EAAC,2FAA2F,aAErG,aAAI,SAAS,EAAC,uCAAuC,YAAE,GAAG,CAAC,KAAK,GAAM,EACtE,aAAI,SAAS,EAAC,6BAA6B,YAAE,GAAG,CAAC,KAAK,GAAM,KAJvD,GAAG,CAAC,KAAK,CAKV,CACP,CAAC,GACC,CACN,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"DetailList.js","sourceRoot":"","sources":["../../src/data/DetailList.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAclC;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,EAAE,IAAI,EAAE,SAAS,EAAmB;IAC7D,OAAO,CACL,aAAI,SAAS,EAAE,EAAE,CAAC,qCAAqC,EAAE,SAAS,CAAC,YAChE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACjB,eAEE,SAAS,EAAC,2FAA2F,aAErG,aAAI,SAAS,EAAC,uCAAuC,YAAE,GAAG,CAAC,KAAK,GAAM,EACtE,aAAI,SAAS,EAAC,6BAA6B,YAAE,GAAG,CAAC,KAAK,GAAM,KAJvD,GAAG,CAAC,KAAK,CAKV,CACP,CAAC,GACC,CACN,CAAC;AACJ,CAAC"}
@@ -1,26 +1,57 @@
1
- export interface PaginationProps {
2
- /** 1-based. */
3
- page: number;
4
- pageCount: number;
5
- onPageChange: (page: number) => void;
1
+ interface PaginationBase {
6
2
  /** Localized name for the navigation region, e.g. "Invoice pages". */
7
3
  label: string;
8
4
  previousLabel: string;
9
5
  nextLabel: string;
10
- /** Localized current position, e.g. "Page 2 of 9". The kit ships no strings. */
6
+ /**
7
+ * Localized statement of where the reader is: "Page 2 of 9", or "Showing 21–40 of 384".
8
+ *
9
+ * 🔴 Composed by the caller, and it has to be. Across nene-vault's three paginated screens
10
+ * the sentence is a *range of items*, not a page number — and a range cannot be recovered
11
+ * from `page` and `pageCount` once the last page is short (measured 2026-08-23). A
12
+ * component that only knew about pages could not produce the sentence the product needs.
13
+ */
11
14
  status: string;
12
15
  }
16
+ interface PagePagination extends PaginationBase {
17
+ /** 1-based. */
18
+ page: number;
19
+ pageCount: number;
20
+ onPageChange: (page: number) => void;
21
+ canPrev?: never;
22
+ canNext?: never;
23
+ onPrev?: never;
24
+ onNext?: never;
25
+ }
26
+ interface OffsetPagination extends PaginationBase {
27
+ canPrev: boolean;
28
+ canNext: boolean;
29
+ onPrev: () => void;
30
+ onNext: () => void;
31
+ page?: never;
32
+ pageCount?: never;
33
+ onPageChange?: never;
34
+ }
35
+ export type PaginationProps = PagePagination | OffsetPagination;
13
36
  /**
14
37
  * Page-by-page navigation for a list.
15
38
  *
39
+ * 🔴 Two models, because products keep the position in two different ways. All three of
40
+ * nene-vault's paginated screens hold an **offset**, and none of them holds a page number
41
+ * (measured 2026-08-23). Converting offset to a page is arithmetic; converting the sentence
42
+ * "21–40 of 384" back out of a page number is not. So the component takes whichever the
43
+ * caller already has, rather than making two thirds of the fleet keep a second copy of its
44
+ * own position.
45
+ *
46
+ * A finite choice between two arrangements, which is structure — not a design value that a
47
+ * caller could invent (design principle 3).
48
+ *
16
49
  * 🔴 The current position is text, and the region is a named `<nav>`. Four ships wrote this
17
- * component and the recurring shape marks the current page by colour alone — which is
18
- * invisible to a screen reader and to anyone who cannot distinguish the two shades. The
19
- * `status` string is required for the same reason: "you are here" has to be readable, not
20
- * merely visible.
50
+ * component and the recurring shape marks the current page by colour alone — invisible to a
51
+ * screen reader and to anyone who cannot distinguish the two shades.
21
52
  *
22
53
  * The ends are disabled rather than hidden. A control that disappears at the boundary makes
23
- * the row of controls jump, and moves the next-page button under the cursor that just
24
- * clicked it.
54
+ * the row jump, and moves the next-page button under the cursor that just clicked it.
25
55
  */
26
- export declare function Pagination({ page, pageCount, onPageChange, label, previousLabel, nextLabel, status, }: PaginationProps): import("react").JSX.Element;
56
+ export declare function Pagination(props: PaginationProps): import("react").JSX.Element;
57
+ export {};
@@ -4,17 +4,29 @@ import { Stack } from '../layout/Stack.js';
4
4
  /**
5
5
  * Page-by-page navigation for a list.
6
6
  *
7
+ * 🔴 Two models, because products keep the position in two different ways. All three of
8
+ * nene-vault's paginated screens hold an **offset**, and none of them holds a page number
9
+ * (measured 2026-08-23). Converting offset to a page is arithmetic; converting the sentence
10
+ * "21–40 of 384" back out of a page number is not. So the component takes whichever the
11
+ * caller already has, rather than making two thirds of the fleet keep a second copy of its
12
+ * own position.
13
+ *
14
+ * A finite choice between two arrangements, which is structure — not a design value that a
15
+ * caller could invent (design principle 3).
16
+ *
7
17
  * 🔴 The current position is text, and the region is a named `<nav>`. Four ships wrote this
8
- * component and the recurring shape marks the current page by colour alone — which is
9
- * invisible to a screen reader and to anyone who cannot distinguish the two shades. The
10
- * `status` string is required for the same reason: "you are here" has to be readable, not
11
- * merely visible.
18
+ * component and the recurring shape marks the current page by colour alone — invisible to a
19
+ * screen reader and to anyone who cannot distinguish the two shades.
12
20
  *
13
21
  * The ends are disabled rather than hidden. A control that disappears at the boundary makes
14
- * the row of controls jump, and moves the next-page button under the cursor that just
15
- * clicked it.
22
+ * the row jump, and moves the next-page button under the cursor that just clicked it.
16
23
  */
17
- export function Pagination({ page, pageCount, onPageChange, label, previousLabel, nextLabel, status, }) {
18
- return (_jsx("nav", { "aria-label": label, children: _jsxs(Stack, { direction: "horizontal", gap: "2xs", align: "center", children: [_jsx(Button, { variant: "secondary", disabled: page <= 1, onClick: () => onPageChange(page - 1), "aria-label": previousLabel, children: previousLabel }), _jsx("span", { "aria-current": "page", className: "font-sans text-text-muted", children: status }), _jsx(Button, { variant: "secondary", disabled: page >= pageCount, onClick: () => onPageChange(page + 1), "aria-label": nextLabel, children: nextLabel })] }) }));
24
+ export function Pagination(props) {
25
+ const { label, previousLabel, nextLabel, status } = props;
26
+ const atStart = props.page === undefined ? !props.canPrev : props.page <= 1;
27
+ const atEnd = props.page === undefined ? !props.canNext : props.page >= props.pageCount;
28
+ const goPrev = () => props.page === undefined ? props.onPrev() : props.onPageChange(props.page - 1);
29
+ const goNext = () => props.page === undefined ? props.onNext() : props.onPageChange(props.page + 1);
30
+ return (_jsx("nav", { "aria-label": label, children: _jsxs(Stack, { direction: "horizontal", gap: "2xs", align: "center", children: [_jsx(Button, { variant: "secondary", disabled: atStart, onClick: goPrev, "aria-label": previousLabel, children: previousLabel }), _jsx("span", { "aria-current": "page", className: "font-sans text-text-muted", children: status }), _jsx(Button, { variant: "secondary", disabled: atEnd, onClick: goNext, "aria-label": nextLabel, children: nextLabel })] }) }));
19
31
  }
20
32
  //# sourceMappingURL=Pagination.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Pagination.js","sourceRoot":"","sources":["../../src/data/Pagination.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAe3C;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,UAAU,CAAC,EACzB,IAAI,EACJ,SAAS,EACT,YAAY,EACZ,KAAK,EACL,aAAa,EACb,SAAS,EACT,MAAM,GACU;IAChB,OAAO,CACL,4BAAiB,KAAK,YACpB,MAAC,KAAK,IAAC,SAAS,EAAC,YAAY,EAAC,GAAG,EAAC,KAAK,EAAC,KAAK,EAAC,QAAQ,aACpD,KAAC,MAAM,IACL,OAAO,EAAC,WAAW,EACnB,QAAQ,EAAE,IAAI,IAAI,CAAC,EACnB,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,CAAC,gBACzB,aAAa,YAExB,aAAa,GACP,EACT,+BAAmB,MAAM,EAAC,SAAS,EAAC,2BAA2B,YAC5D,MAAM,GACF,EACP,KAAC,MAAM,IACL,OAAO,EAAC,WAAW,EACnB,QAAQ,EAAE,IAAI,IAAI,SAAS,EAC3B,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,CAAC,gBACzB,SAAS,YAEpB,SAAS,GACH,IACH,GACJ,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"Pagination.js","sourceRoot":"","sources":["../../src/data/Pagination.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAyC3C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC;IAE1D,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;IAC5E,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,SAAS,CAAC;IAExF,MAAM,MAAM,GAAG,GAAG,EAAE,CAClB,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IACjF,MAAM,MAAM,GAAG,GAAG,EAAE,CAClB,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IAEjF,OAAO,CACL,4BAAiB,KAAK,YACpB,MAAC,KAAK,IAAC,SAAS,EAAC,YAAY,EAAC,GAAG,EAAC,KAAK,EAAC,KAAK,EAAC,QAAQ,aACpD,KAAC,MAAM,IAAC,OAAO,EAAC,WAAW,EAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAc,aAAa,YACtF,aAAa,GACP,EACT,+BAAmB,MAAM,EAAC,SAAS,EAAC,2BAA2B,YAC5D,MAAM,GACF,EACP,KAAC,MAAM,IAAC,OAAO,EAAC,WAAW,EAAC,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAc,SAAS,YAChF,SAAS,GACH,IACH,GACJ,CACP,CAAC;AACJ,CAAC"}
@@ -1,12 +1,17 @@
1
1
  import type { ReactNode } from 'react';
2
2
  export interface InlineAlertProps {
3
3
  /** What the message means. `danger` is announced assertively; `info` politely. */
4
- tone?: 'info' | 'danger';
4
+ tone?: 'info' | 'warn' | 'danger';
5
5
  children: ReactNode;
6
6
  }
7
7
  /**
8
8
  * A message attached to the thing it is about, rather than to the page.
9
9
  *
10
+ * 🔴 Each tone reads its colours from the theme, so a product can tell "warning" from
11
+ * "failure" by sight. Until it sets them, `warn` and `danger` share this palette's single
12
+ * alert hue and only the announced urgency differs — and as nene-vault put it, that
13
+ * difference reaches someone listening and no one looking.
14
+ *
10
15
  * 🔴 The tone decides the ARIA role, not just the colour. `danger` becomes `role="alert"`,
11
16
  * which interrupts a screen reader; `info` becomes `role="status"`, which waits its turn.
12
17
  * Six ships wrote this component (three as `InlineAlert`, three as `Alert`) and the choice
@@ -1,12 +1,18 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { cx } from '../lib/cx.js';
3
3
  const TONE_CLASS = {
4
- info: 'bg-surface text-text-primary border-border',
5
- danger: 'bg-surface text-danger border-danger',
4
+ info: 'bg-x-slot-alert-info-bg text-x-slot-alert-info-fg border-x-slot-alert-info-border',
5
+ warn: 'bg-x-slot-alert-warn-bg text-x-slot-alert-warn-fg border-x-slot-alert-warn-border',
6
+ danger: 'bg-x-slot-alert-danger-bg text-x-slot-alert-danger-fg border-x-slot-alert-danger-border',
6
7
  };
7
8
  /**
8
9
  * A message attached to the thing it is about, rather than to the page.
9
10
  *
11
+ * 🔴 Each tone reads its colours from the theme, so a product can tell "warning" from
12
+ * "failure" by sight. Until it sets them, `warn` and `danger` share this palette's single
13
+ * alert hue and only the announced urgency differs — and as nene-vault put it, that
14
+ * difference reaches someone listening and no one looking.
15
+ *
10
16
  * 🔴 The tone decides the ARIA role, not just the colour. `danger` becomes `role="alert"`,
11
17
  * which interrupts a screen reader; `info` becomes `role="status"`, which waits its turn.
12
18
  * Six ships wrote this component (three as `InlineAlert`, three as `Alert`) and the choice
@@ -1 +1 @@
1
- {"version":3,"file":"InlineAlert.js","sourceRoot":"","sources":["../../src/feedback/InlineAlert.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAQlC,MAAM,UAAU,GAA0D;IACxE,IAAI,EAAE,4CAA4C;IAClD,MAAM,EAAE,sCAAsC;CAC/C,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,EAAE,IAAI,GAAG,MAAM,EAAE,QAAQ,EAAoB;IACvE,OAAO,CACL,cACE,IAAI,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAC5C,SAAS,EAAE,EAAE,CAAC,0DAA0D,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,YAE1F,QAAQ,GACL,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"InlineAlert.js","sourceRoot":"","sources":["../../src/feedback/InlineAlert.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAQlC,MAAM,UAAU,GAA0D;IACxE,IAAI,EAAE,mFAAmF;IACzF,IAAI,EAAE,mFAAmF;IACzF,MAAM,EAAE,yFAAyF;CAClG,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,WAAW,CAAC,EAAE,IAAI,GAAG,MAAM,EAAE,QAAQ,EAAoB;IACvE,OAAO,CACL,cACE,IAAI,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAC5C,SAAS,EAAE,EAAE,CAAC,0DAA0D,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,YAE1F,QAAQ,GACL,CACP,CAAC;AACJ,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
3
3
  import { cx } from '../lib/cx.js';
4
- import { CONTROL_CLASS } from '../lib/states.js';
4
+ import { CLICKABLE_CLASS } from '../lib/states.js';
5
5
  import { ToastContext } from './toast-context.js';
6
6
  const TONE_CLASS = {
7
7
  info: 'bg-surface-raised text-text-primary border-border',
@@ -50,7 +50,7 @@ export function ToastProvider({ regionLabel, dismissLabel, defaultDurationMs = 5
50
50
  const api = useMemo(() => ({ show, dismiss }), [show, dismiss]);
51
51
  const region = (tone, live) => (_jsx("div", { "aria-live": live, "aria-label": regionLabel, role: "region", className: "flex flex-col gap-x-slot-toast-gap", children: toasts
52
52
  .filter((toast) => toast.tone === tone)
53
- .map((toast) => (_jsxs("div", { className: cx('flex items-start gap-x-slot-toast-gap rounded-x-slot-toast border p-x-slot-toast-pad font-sans shadow-sm', TONE_CLASS[toast.tone]), children: [_jsx("span", { children: toast.message }), _jsx("button", { type: "button", "aria-label": dismissLabel, onClick: () => dismiss(toast.id), className: cx('rounded-x-slot-toast px-x-slot-toast-dismiss-pad-x', CONTROL_CLASS), children: dismissLabel })] }, toast.id))) }));
53
+ .map((toast) => (_jsxs("div", { className: cx('flex items-start gap-x-slot-toast-gap rounded-x-slot-toast border p-x-slot-toast-pad font-sans shadow-sm', TONE_CLASS[toast.tone]), children: [_jsx("span", { children: toast.message }), _jsx("button", { type: "button", "aria-label": dismissLabel, onClick: () => dismiss(toast.id), className: cx('rounded-x-slot-toast px-x-slot-toast-dismiss-pad-x', CLICKABLE_CLASS), children: dismissLabel })] }, toast.id))) }));
54
54
  return (_jsxs(ToastContext.Provider, { value: api, children: [children, region('info', 'polite'), region('danger', 'assertive')] }));
55
55
  }
56
56
  //# sourceMappingURL=ToastProvider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToastProvider.js","sourceRoot":"","sources":["../../src/feedback/ToastProvider.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ToastProvider.js","sourceRoot":"","sources":["../../src/feedback/ToastProvider.tsx"],"names":[],"mappings":"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"}
@@ -20,6 +20,6 @@ export function FormField({ id, label, error = null, hint, labelAdornment, requi
20
20
  const errorId = error === null ? null : `${id}-error`;
21
21
  const hintId = hint === undefined || hint === null ? null : `${id}-hint`;
22
22
  const value = useMemo(() => ({ id, errorId, hintId, required }), [id, errorId, hintId, required]);
23
- return (_jsx(FieldContext.Provider, { value: value, children: _jsxs("div", { className: "flex flex-col gap-x-slot-field-gap", children: [_jsxs("label", { htmlFor: id, className: "font-sans font-x-slot-field-label text-x-slot-field-label-size text-x-slot-field-label", children: [label, required && requiredMarker !== undefined && requiredMarker !== null ? (_jsx("span", { className: "text-danger", children: requiredMarker })) : null, labelAdornment] }), children, hintId === null ? null : (_jsx("span", { id: hintId, className: "font-sans text-text-muted", children: hint })), errorId === null ? null : (_jsx("p", { id: errorId, role: "alert", className: "font-sans text-danger", children: error }))] }) }));
23
+ return (_jsx(FieldContext.Provider, { value: value, children: _jsxs("div", { className: "flex flex-col gap-x-slot-field-gap", children: [_jsxs("label", { htmlFor: id, className: "font-sans font-x-slot-field-label text-x-slot-field-label-size text-x-slot-field-label", children: [label, required && requiredMarker !== undefined && requiredMarker !== null ? (_jsx("span", { className: "text-danger", children: requiredMarker })) : null, labelAdornment] }), children, hintId === null ? null : (_jsx("span", { id: hintId, className: "font-sans text-x-slot-field-hint-size text-x-slot-field-hint", children: hint })), errorId === null ? null : (_jsx("p", { id: errorId, role: "alert", className: "font-sans text-x-slot-field-error-size text-x-slot-field-error", children: error }))] }) }));
24
24
  }
25
25
  //# sourceMappingURL=FormField.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FormField.js","sourceRoot":"","sources":["../../src/forms/FormField.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAkB,MAAM,OAAO,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAiClD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,SAAS,CAAC,EACxB,EAAE,EACF,KAAK,EACL,KAAK,GAAG,IAAI,EACZ,IAAI,EACJ,cAAc,EACd,QAAQ,GAAG,KAAK,EAChB,cAAc,EACd,QAAQ,GACO;IACf,MAAM,OAAO,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC;IACtD,MAAM,MAAM,GAAG,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC;IACzE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAElG,OAAO,CACL,KAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YACjC,eAAK,SAAS,EAAC,oCAAoC,aACjD,iBACE,OAAO,EAAE,EAAE,EACX,SAAS,EAAC,wFAAwF,aAEjG,KAAK,EACL,QAAQ,IAAI,cAAc,KAAK,SAAS,IAAI,cAAc,KAAK,IAAI,CAAC,CAAC,CAAC,CACrE,eAAM,SAAS,EAAC,aAAa,YAAE,cAAc,GAAQ,CACtD,CAAC,CAAC,CAAC,IAAI,EACP,cAAc,IACT,EACP,QAAQ,EACR,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACxB,eAAM,EAAE,EAAE,MAAM,EAAE,SAAS,EAAC,2BAA2B,YACpD,IAAI,GACA,CACR,EACA,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACzB,YAAG,EAAE,EAAE,OAAO,EAAE,IAAI,EAAC,OAAO,EAAC,SAAS,EAAC,uBAAuB,YAC3D,KAAK,GACJ,CACL,IACG,GACgB,CACzB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"FormField.js","sourceRoot":"","sources":["../../src/forms/FormField.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAkB,MAAM,OAAO,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAiClD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,SAAS,CAAC,EACxB,EAAE,EACF,KAAK,EACL,KAAK,GAAG,IAAI,EACZ,IAAI,EACJ,cAAc,EACd,QAAQ,GAAG,KAAK,EAChB,cAAc,EACd,QAAQ,GACO;IACf,MAAM,OAAO,GAAG,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,QAAQ,CAAC;IACtD,MAAM,MAAM,GAAG,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC;IACzE,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAElG,OAAO,CACL,KAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YACjC,eAAK,SAAS,EAAC,oCAAoC,aACjD,iBACE,OAAO,EAAE,EAAE,EACX,SAAS,EAAC,wFAAwF,aAEjG,KAAK,EACL,QAAQ,IAAI,cAAc,KAAK,SAAS,IAAI,cAAc,KAAK,IAAI,CAAC,CAAC,CAAC,CACrE,eAAM,SAAS,EAAC,aAAa,YAAE,cAAc,GAAQ,CACtD,CAAC,CAAC,CAAC,IAAI,EACP,cAAc,IACT,EACP,QAAQ,EACR,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACxB,eACE,EAAE,EAAE,MAAM,EACV,SAAS,EAAC,8DAA8D,YAEvE,IAAI,GACA,CACR,EACA,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACzB,YACE,EAAE,EAAE,OAAO,EACX,IAAI,EAAC,OAAO,EACZ,SAAS,EAAC,gEAAgE,YAEzE,KAAK,GACJ,CACL,IACG,GACgB,CACzB,CAAC;AACJ,CAAC"}
package/dist/index.d.ts CHANGED
@@ -30,5 +30,5 @@ export { DataTable, type DataTableProps, type DataColumn } from './data/DataTabl
30
30
  export { Pagination, type PaginationProps } from './data/Pagination.js';
31
31
  export { tokens } from './theme/tokens.js';
32
32
  export { cx } from './lib/cx.js';
33
- export { CONTROL_CLASS, DISABLED_CLASS, FOCUS_CLASS } from './lib/states.js';
33
+ export { CLICKABLE_CLASS, CONTROL_CLASS, DISABLED_CLASS, FOCUS_CLASS, HOVER_CLASS, } from './lib/states.js';
34
34
  export { SOURCE_PROBE_CLASS } from './lib/source-probe.js';
package/dist/index.js CHANGED
@@ -41,7 +41,7 @@ export { tokens } from './theme/tokens.js';
41
41
  export { cx } from './lib/cx.js';
42
42
  // Controls the kit does not ship yet (Textarea has 7 independent implementations in the
43
43
  // fleet) can at least carry the same focus and disabled behaviour instead of inventing it.
44
- export { CONTROL_CLASS, DISABLED_CLASS, FOCUS_CLASS } from './lib/states.js';
44
+ export { CLICKABLE_CLASS, CONTROL_CLASS, DISABLED_CLASS, FOCUS_CLASS, HOVER_CLASS, } from './lib/states.js';
45
45
  // Lets a consumer's build prove the kit is in its Tailwind `@source` (#316).
46
46
  export { SOURCE_PROBE_CLASS } from './lib/source-probe.js';
47
47
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,OAAO,EAAE,MAAM,EAAoB,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,KAAK,EAAmB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAoB,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,EAAqB,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,IAAI,EAAkB,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAsB,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,IAAI,EAAkB,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAsB,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,KAAK,EAAmB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAoB,MAAM,wBAAwB,CAAC;AAElE,SAAS;AACT,OAAO,EAAE,UAAU,EAAwB,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,KAAK,EAAmB,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAkB,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,GAAG,EAAiB,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAqB,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,IAAI,EAAkB,MAAM,kBAAkB,CAAC;AAKxD,QAAQ;AACR,OAAO,EAAE,SAAS,EAAuB,MAAM,sBAAsB,CAAC;AAEtE,sFAAsF;AACtF,sDAAsD;AACtD,OAAO,EAAE,YAAY,EAA0B,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,UAAU,EAAwB,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAwB,MAAM,wBAAwB,CAAC;AAE1E,UAAU;AACV,OAAO,EAAE,KAAK,EAAmB,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAA2B,MAAM,4BAA4B,CAAC;AAEpF,WAAW;AACX,OAAO,EAAE,KAAK,EAAmB,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAyB,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,aAAa,EAA2B,MAAM,6BAA6B,CAAC;AACrF,OAAO,EACL,QAAQ,GAIT,MAAM,6BAA6B,CAAC;AAErC,OAAO;AACP,OAAO,EAAE,UAAU,EAAwC,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAAE,SAAS,EAAwC,MAAM,qBAAqB,CAAC;AACtF,OAAO,EAAE,UAAU,EAAwB,MAAM,sBAAsB,CAAC;AAExE,QAAQ;AACR,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,gFAAgF;AAChF,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,wFAAwF;AACxF,2FAA2F;AAC3F,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC7E,6EAA6E;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,aAAa;AACb,OAAO,EAAE,MAAM,EAAoB,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,KAAK,EAAmB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAoB,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,EAAqB,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,IAAI,EAAkB,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAsB,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,IAAI,EAAkB,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAsB,MAAM,0BAA0B,CAAC;AACxE,OAAO,EAAE,KAAK,EAAmB,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,MAAM,EAAoB,MAAM,wBAAwB,CAAC;AAElE,SAAS;AACT,OAAO,EAAE,UAAU,EAAwB,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,KAAK,EAAmB,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,IAAI,EAAkB,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,GAAG,EAAiB,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,OAAO,EAAqB,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,IAAI,EAAkB,MAAM,kBAAkB,CAAC;AAKxD,QAAQ;AACR,OAAO,EAAE,SAAS,EAAuB,MAAM,sBAAsB,CAAC;AAEtE,sFAAsF;AACtF,sDAAsD;AACtD,OAAO,EAAE,YAAY,EAA0B,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,UAAU,EAAwB,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAwB,MAAM,wBAAwB,CAAC;AAE1E,UAAU;AACV,OAAO,EAAE,KAAK,EAAmB,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAA2B,MAAM,4BAA4B,CAAC;AAEpF,WAAW;AACX,OAAO,EAAE,KAAK,EAAmB,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAyB,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,aAAa,EAA2B,MAAM,6BAA6B,CAAC;AACrF,OAAO,EACL,QAAQ,GAIT,MAAM,6BAA6B,CAAC;AAErC,OAAO;AACP,OAAO,EAAE,UAAU,EAAwC,MAAM,sBAAsB,CAAC;AACxF,OAAO,EAAE,SAAS,EAAwC,MAAM,qBAAqB,CAAC;AACtF,OAAO,EAAE,UAAU,EAAwB,MAAM,sBAAsB,CAAC;AAExE,QAAQ;AACR,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAE3C,gFAAgF;AAChF,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,wFAAwF;AACxF,2FAA2F;AAC3F,OAAO,EACL,eAAe,EACf,aAAa,EACb,cAAc,EACd,WAAW,EACX,WAAW,GACZ,MAAM,iBAAiB,CAAC;AACzB,6EAA6E;AAC7E,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC"}
@@ -1,7 +1,9 @@
1
1
  import type { ReactNode } from 'react';
2
2
  export interface PageHeaderProps {
3
+ /** Composed after the kit's own classes (design principle 2). */
4
+ className?: string;
3
5
  /** Localized page title. */
4
6
  title: string;
5
7
  actions?: ReactNode;
6
8
  }
7
- export declare function PageHeader({ title, actions }: PageHeaderProps): import("react").JSX.Element;
9
+ export declare function PageHeader({ title, actions, className }: PageHeaderProps): import("react").JSX.Element;
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- export function PageHeader({ title, actions }) {
3
- return (_jsxs("header", { className: "flex items-center justify-between py-x-slot-page-header-pad-y", children: [_jsx("h1", { className: "font-sans font-medium text-text-primary", children: title }), actions] }));
2
+ import { cx } from '../lib/cx.js';
3
+ export function PageHeader({ title, actions, className }) {
4
+ return (_jsxs("header", { className: cx('flex items-center justify-between py-x-slot-page-header-pad-y', className), children: [_jsx("h1", { className: "font-sans font-medium text-text-primary", children: title }), actions] }));
4
5
  }
5
6
  //# sourceMappingURL=PageHeader.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PageHeader.js","sourceRoot":"","sources":["../../src/layout/PageHeader.tsx"],"names":[],"mappings":";AAQA,MAAM,UAAU,UAAU,CAAC,EAAE,KAAK,EAAE,OAAO,EAAmB;IAC5D,OAAO,CACL,kBAAQ,SAAS,EAAC,+DAA+D,aAC/E,aAAI,SAAS,EAAC,yCAAyC,YAAE,KAAK,GAAM,EACnE,OAAO,IACD,CACV,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"PageHeader.js","sourceRoot":"","sources":["../../src/layout/PageHeader.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAUlC,MAAM,UAAU,UAAU,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAmB;IACvE,OAAO,CACL,kBACE,SAAS,EAAE,EAAE,CAAC,+DAA+D,EAAE,SAAS,CAAC,aAEzF,aAAI,SAAS,EAAC,yCAAyC,YAAE,KAAK,GAAM,EACnE,OAAO,IACD,CACV,CAAC;AACJ,CAAC"}
@@ -50,5 +50,20 @@ export declare const FOCUS_CLASS = "focus-visible:outline-2 focus-visible:outlin
50
50
  * literal here would be a design value living outside themes/default.css.
51
51
  */
52
52
  export declare const DISABLED_CLASS = "disabled:opacity-x-disabled disabled:cursor-not-allowed";
53
+ /**
54
+ * Pointer feedback for anything clickable.
55
+ *
56
+ * 🔴 The third hole of the same shape. v0.1 shipped with no disabled and no focus styling;
57
+ * 0.4.0 is where the kit stops shipping without hover and press. The fleet writes them
58
+ * anyway — measured 2026-08-23 across seven products, though only three of them show up if
59
+ * you grep for Tailwind classes: nene-invoice, nene-deal, nene-profile and nene-serve
60
+ * declare theirs in CSS (`background` 55 times, `color` 42, `border-color` 17). Counting one
61
+ * spelling of a thing that has two is how the first two holes stayed open.
62
+ *
63
+ * `disabled:` is excluded on purpose: a disabled control must not react to the pointer.
64
+ */
65
+ export declare const HOVER_CLASS = "hover:brightness-x-slot-hover active:brightness-x-slot-press disabled:hover:brightness-100 disabled:active:brightness-100";
53
66
  /** Controls that can be focused and disabled — every interactive primitive in the kit. */
54
67
  export declare const CONTROL_CLASS = "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-text-primary disabled:opacity-x-disabled disabled:cursor-not-allowed";
68
+ /** Controls that are also clicked: buttons, switches, the toast dismiss. */
69
+ export declare const CLICKABLE_CLASS = "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-text-primary disabled:opacity-x-disabled disabled:cursor-not-allowed hover:brightness-x-slot-hover active:brightness-x-slot-press disabled:hover:brightness-100 disabled:active:brightness-100";
@@ -50,6 +50,21 @@ export const FOCUS_CLASS = 'focus-visible:outline-2 focus-visible:outline-offset
50
50
  * literal here would be a design value living outside themes/default.css.
51
51
  */
52
52
  export const DISABLED_CLASS = 'disabled:opacity-x-disabled disabled:cursor-not-allowed';
53
+ /**
54
+ * Pointer feedback for anything clickable.
55
+ *
56
+ * 🔴 The third hole of the same shape. v0.1 shipped with no disabled and no focus styling;
57
+ * 0.4.0 is where the kit stops shipping without hover and press. The fleet writes them
58
+ * anyway — measured 2026-08-23 across seven products, though only three of them show up if
59
+ * you grep for Tailwind classes: nene-invoice, nene-deal, nene-profile and nene-serve
60
+ * declare theirs in CSS (`background` 55 times, `color` 42, `border-color` 17). Counting one
61
+ * spelling of a thing that has two is how the first two holes stayed open.
62
+ *
63
+ * `disabled:` is excluded on purpose: a disabled control must not react to the pointer.
64
+ */
65
+ export const HOVER_CLASS = 'hover:brightness-x-slot-hover active:brightness-x-slot-press disabled:hover:brightness-100 disabled:active:brightness-100';
53
66
  /** Controls that can be focused and disabled — every interactive primitive in the kit. */
54
67
  export const CONTROL_CLASS = `${FOCUS_CLASS} ${DISABLED_CLASS}`;
68
+ /** Controls that are also clicked: buttons, switches, the toast dismiss. */
69
+ export const CLICKABLE_CLASS = `${CONTROL_CLASS} ${HOVER_CLASS}`;
55
70
  //# sourceMappingURL=states.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"states.js","sourceRoot":"","sources":["../../src/lib/states.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,kFAAkF;AAClF,MAAM,CAAC,MAAM,WAAW,GACtB,2FAA2F,CAAC;AAE9F;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,yDAAyD,CAAC;AAExF,0FAA0F;AAC1F,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,WAAW,IAAI,cAAc,EAAE,CAAC"}
1
+ {"version":3,"file":"states.js","sourceRoot":"","sources":["../../src/lib/states.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,kFAAkF;AAClF,MAAM,CAAC,MAAM,WAAW,GACtB,2FAA2F,CAAC;AAE9F;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,yDAAyD,CAAC;AAExF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,WAAW,GACtB,2HAA2H,CAAC;AAE9H,0FAA0F;AAC1F,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,WAAW,IAAI,cAAc,EAAE,CAAC;AAEhE,4EAA4E;AAC5E,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,aAAa,IAAI,WAAW,EAAE,CAAC"}
@@ -1,6 +1,13 @@
1
1
  import type { ButtonHTMLAttributes, ReactNode } from 'react';
2
2
  export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
3
- variant?: 'primary' | 'secondary' | 'danger';
3
+ variant?: 'primary' | 'secondary' | 'danger' | 'ghost';
4
+ /**
5
+ * Two sizes, not a length. `sm` for dense rows and toolbars.
6
+ *
7
+ * Structure, not a design value: the caller picks one of two arrangements and cannot
8
+ * write a padding of its own (design principle 3).
9
+ */
10
+ size?: 'md' | 'sm';
4
11
  children: ReactNode;
5
12
  }
6
- export declare function Button({ variant, children, type, className, ...rest }: ButtonProps): import("react").JSX.Element;
13
+ export declare function Button({ variant, size, children, type, className, ...rest }: ButtonProps): import("react").JSX.Element;
@@ -1,13 +1,25 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { cx } from '../lib/cx.js';
3
- import { CONTROL_CLASS } from '../lib/states.js';
3
+ import { CLICKABLE_CLASS } from '../lib/states.js';
4
4
  const VARIANT_CLASS = {
5
5
  primary: 'bg-accent text-on-accent',
6
- secondary: 'bg-surface-raised text-text-primary border border-border',
6
+ secondary: 'bg-surface-raised text-text-primary border-border',
7
7
  danger: 'bg-danger text-on-accent',
8
+ // No fill and no border: for the third action in a row, where two framed buttons would
9
+ // compete with each other. nene-vault ships this variant already.
10
+ ghost: 'bg-transparent text-text-primary',
8
11
  };
9
- const BASE_CLASS = `rounded-x-slot-button px-x-slot-button-pad-x py-x-slot-button-pad-y font-sans font-medium ${CONTROL_CLASS}`;
10
- export function Button({ variant = 'primary', children, type = 'button', className, ...rest }) {
11
- return (_jsx("button", { type: type, className: cx(BASE_CLASS, VARIANT_CLASS[variant], className), ...rest, children: children }));
12
+ const SIZE_CLASS = {
13
+ md: 'px-x-slot-button-pad-x py-x-slot-button-pad-y',
14
+ sm: 'px-x-slot-button-sm-pad-x py-x-slot-button-sm-pad-y',
15
+ };
16
+ // 🔴 `border border-transparent` is load-bearing. Height comes from the padding, so the
17
+ // `secondary` variant — the only one with a visible border — would otherwise stand 2px
18
+ // taller than the others. nene-vault puts a primary and a secondary side by side in seven
19
+ // modal footers, where that shows up as a step (measured 2026-08-23); its own Button carries
20
+ // the same transparent border for the same reason.
21
+ const BASE_CLASS = `rounded-x-slot-button border border-transparent font-sans font-medium ${CLICKABLE_CLASS}`;
22
+ export function Button({ variant = 'primary', size = 'md', children, type = 'button', className, ...rest }) {
23
+ return (_jsx("button", { type: type, className: cx(BASE_CLASS, SIZE_CLASS[size], VARIANT_CLASS[variant], className), ...rest, children: children }));
12
24
  }
13
25
  //# sourceMappingURL=Button.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Button.js","sourceRoot":"","sources":["../../src/primitives/Button.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAOjD,MAAM,aAAa,GAAwD;IACzE,OAAO,EAAE,0BAA0B;IACnC,SAAS,EAAE,0DAA0D;IACrE,MAAM,EAAE,0BAA0B;CACnC,CAAC;AAEF,MAAM,UAAU,GAAG,6FAA6F,aAAa,EAAE,CAAC;AAEhI,MAAM,UAAU,MAAM,CAAC,EACrB,OAAO,GAAG,SAAS,EACnB,QAAQ,EACR,IAAI,GAAG,QAAQ,EACf,SAAS,EACT,GAAG,IAAI,EACK;IACZ,OAAO,CACL,iBAAQ,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,KAAM,IAAI,YACvF,QAAQ,GACF,CACV,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"Button.js","sourceRoot":"","sources":["../../src/primitives/Button.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAcnD,MAAM,aAAa,GAAwD;IACzE,OAAO,EAAE,0BAA0B;IACnC,SAAS,EAAE,mDAAmD;IAC9D,MAAM,EAAE,0BAA0B;IAClC,uFAAuF;IACvF,kEAAkE;IAClE,KAAK,EAAE,kCAAkC;CAC1C,CAAC;AAEF,MAAM,UAAU,GAAqD;IACnE,EAAE,EAAE,+CAA+C;IACnD,EAAE,EAAE,qDAAqD;CAC1D,CAAC;AAEF,wFAAwF;AACxF,uFAAuF;AACvF,0FAA0F;AAC1F,6FAA6F;AAC7F,mDAAmD;AACnD,MAAM,UAAU,GAAG,yEAAyE,eAAe,EAAE,CAAC;AAE9G,MAAM,UAAU,MAAM,CAAC,EACrB,OAAO,GAAG,SAAS,EACnB,IAAI,GAAG,IAAI,EACX,QAAQ,EACR,IAAI,GAAG,QAAQ,EACf,SAAS,EACT,GAAG,IAAI,EACK;IACZ,OAAO,CACL,iBACE,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,KAC1E,IAAI,YAEP,QAAQ,GACF,CACV,CAAC;AACJ,CAAC"}
@@ -10,5 +10,12 @@ export interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement
10
10
  * `<input>` next to a `<label>` whose `htmlFor` is missing or stale — which loses nothing
11
11
  * visible, and loses the ability to click the text to toggle the box, plus the name the
12
12
  * control is announced by. Making the label a prop means it cannot be forgotten.
13
+ *
14
+ * 🔴 `cursor-pointer` and the gap live here rather than being left to the caller, because
15
+ * the caller cannot reach them: `className` is forwarded to the `<input>`, and both belong
16
+ * to the `<label>` that wraps it. nene-vault carries them on the label in its own
17
+ * implementation (measured 2026-08-23, checking Tailwind classes and CSS both), so a
18
+ * migration that could not set them would lose the pointer cursor on every choice in the
19
+ * product — visible to a mouse user, invisible in a diff.
13
20
  */
14
21
  export declare const Checkbox: import("react").ForwardRefExoticComponent<CheckboxProps & import("react").RefAttributes<HTMLInputElement>>;
@@ -3,7 +3,7 @@ import { forwardRef } from 'react';
3
3
  import { cx } from '../lib/cx.js';
4
4
  import { CONTROL_CLASS } from '../lib/states.js';
5
5
  import { useFieldWiring } from '../forms/field-context.js';
6
- const BOX_CLASS = `rounded-x-slot-control border border-border accent-accent ${CONTROL_CLASS}`;
6
+ const BOX_CLASS = `size-x-slot-choice-box shrink-0 rounded-x-slot-control border border-border accent-x-slot-choice-accent ${CONTROL_CLASS}`;
7
7
  /**
8
8
  * A checkbox and its label, as one part.
9
9
  *
@@ -11,9 +11,16 @@ const BOX_CLASS = `rounded-x-slot-control border border-border accent-accent ${C
11
11
  * `<input>` next to a `<label>` whose `htmlFor` is missing or stale — which loses nothing
12
12
  * visible, and loses the ability to click the text to toggle the box, plus the name the
13
13
  * control is announced by. Making the label a prop means it cannot be forgotten.
14
+ *
15
+ * 🔴 `cursor-pointer` and the gap live here rather than being left to the caller, because
16
+ * the caller cannot reach them: `className` is forwarded to the `<input>`, and both belong
17
+ * to the `<label>` that wraps it. nene-vault carries them on the label in its own
18
+ * implementation (measured 2026-08-23, checking Tailwind classes and CSS both), so a
19
+ * migration that could not set them would lose the pointer cursor on every choice in the
20
+ * product — visible to a mouse user, invisible in a diff.
14
21
  */
15
22
  export const Checkbox = forwardRef(function Checkbox({ label, className, id, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, 'aria-required': ariaRequired, ...rest }, ref) {
16
23
  const wiring = useFieldWiring({ id, ariaInvalid, ariaDescribedBy, ariaRequired });
17
- return (_jsxs("label", { className: "inline-flex items-center gap-x-slot-choice-gap font-sans text-text-primary", children: [_jsx("input", { ref: ref, type: "checkbox", className: cx(BOX_CLASS, className), ...wiring, ...rest }), label] }));
24
+ return (_jsxs("label", { className: "inline-flex cursor-pointer items-center gap-x-slot-choice-gap font-sans text-text-primary", children: [_jsx("input", { ref: ref, type: "checkbox", className: cx(BOX_CLASS, className), ...wiring, ...rest }), label] }));
18
25
  });
19
26
  //# sourceMappingURL=Checkbox.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Checkbox.js","sourceRoot":"","sources":["../../src/primitives/Checkbox.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA4C,MAAM,OAAO,CAAC;AAC7E,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAO3D,MAAM,SAAS,GAAG,6DAA6D,aAAa,EAAE,CAAC;AAE/F;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAkC,SAAS,QAAQ,CACnF,EACE,KAAK,EACL,SAAS,EACT,EAAE,EACF,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,EACnC,eAAe,EAAE,YAAY,EAC7B,GAAG,IAAI,EACR,EACD,GAAG;IAEH,MAAM,MAAM,GAAG,cAAc,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC,CAAC;IAElF,OAAO,CACL,iBAAO,SAAS,EAAC,4EAA4E,aAC3F,gBAAO,GAAG,EAAE,GAAG,EAAE,IAAI,EAAC,UAAU,EAAC,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,KAAM,MAAM,KAAM,IAAI,GAAI,EAC7F,KAAK,IACA,CACT,CAAC;AACJ,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"Checkbox.js","sourceRoot":"","sources":["../../src/primitives/Checkbox.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA4C,MAAM,OAAO,CAAC;AAC7E,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAO3D,MAAM,SAAS,GAAG,2GAA2G,aAAa,EAAE,CAAC;AAE7I;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAkC,SAAS,QAAQ,CACnF,EACE,KAAK,EACL,SAAS,EACT,EAAE,EACF,cAAc,EAAE,WAAW,EAC3B,kBAAkB,EAAE,eAAe,EACnC,eAAe,EAAE,YAAY,EAC7B,GAAG,IAAI,EACR,EACD,GAAG;IAEH,MAAM,MAAM,GAAG,cAAc,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC,CAAC;IAElF,OAAO,CACL,iBAAO,SAAS,EAAC,2FAA2F,aAC1G,gBAAO,GAAG,EAAE,GAAG,EAAE,IAAI,EAAC,UAAU,EAAC,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,KAAM,MAAM,KAAM,IAAI,GAAI,EAC7F,KAAK,IACA,CACT,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -12,6 +12,10 @@ export interface RadioProps extends Omit<InputHTMLAttributes<HTMLInputElement>,
12
12
  * its own group of one: it can be checked but never unchecked, and arrow keys do not move
13
13
  * between the options. Nothing about the rendered page shows this, so it survives review.
14
14
  *
15
+ * 🔴 `cursor-pointer`, the gap and the box size are the component's, for the same reason as
16
+ * on `Checkbox`: `className` reaches the `<input>`, and those belong to the `<label>`.
17
+ * nene-vault's radios share one label style with its checkboxes, so the same hole was here.
18
+ *
15
19
  * 🔴 This does not take the `FormField` wiring. A group of radios shares one label and one
16
20
  * error, so the id and `aria-describedby` belong on a `<fieldset>` around the group, not on
17
21
  * each option — putting them here would give every option the same id.
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { forwardRef } from 'react';
3
3
  import { cx } from '../lib/cx.js';
4
4
  import { CONTROL_CLASS } from '../lib/states.js';
5
- const DOT_CLASS = `border border-border accent-accent ${CONTROL_CLASS}`;
5
+ const DOT_CLASS = `size-x-slot-choice-box shrink-0 border border-border accent-x-slot-choice-accent ${CONTROL_CLASS}`;
6
6
  /**
7
7
  * One option in a radio group, with its label.
8
8
  *
@@ -10,11 +10,15 @@ const DOT_CLASS = `border border-border accent-accent ${CONTROL_CLASS}`;
10
10
  * its own group of one: it can be checked but never unchecked, and arrow keys do not move
11
11
  * between the options. Nothing about the rendered page shows this, so it survives review.
12
12
  *
13
+ * 🔴 `cursor-pointer`, the gap and the box size are the component's, for the same reason as
14
+ * on `Checkbox`: `className` reaches the `<input>`, and those belong to the `<label>`.
15
+ * nene-vault's radios share one label style with its checkboxes, so the same hole was here.
16
+ *
13
17
  * 🔴 This does not take the `FormField` wiring. A group of radios shares one label and one
14
18
  * error, so the id and `aria-describedby` belong on a `<fieldset>` around the group, not on
15
19
  * each option — putting them here would give every option the same id.
16
20
  */
17
21
  export const Radio = forwardRef(function Radio({ label, name, className, ...rest }, ref) {
18
- return (_jsxs("label", { className: "inline-flex items-center gap-x-slot-choice-gap font-sans text-text-primary", children: [_jsx("input", { ref: ref, type: "radio", name: name, className: cx(DOT_CLASS, className), ...rest }), label] }));
22
+ return (_jsxs("label", { className: "inline-flex cursor-pointer items-center gap-x-slot-choice-gap font-sans text-text-primary", children: [_jsx("input", { ref: ref, type: "radio", name: name, className: cx(DOT_CLASS, className), ...rest }), label] }));
19
23
  });
20
24
  //# sourceMappingURL=Radio.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Radio.js","sourceRoot":"","sources":["../../src/primitives/Radio.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA4C,MAAM,OAAO,CAAC;AAC7E,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AASjD,MAAM,SAAS,GAAG,sCAAsC,aAAa,EAAE,CAAC;AAExE;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAA+B,SAAS,KAAK,CAC1E,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EACnC,GAAG;IAEH,OAAO,CACL,iBAAO,SAAS,EAAC,4EAA4E,aAC3F,gBAAO,GAAG,EAAE,GAAG,EAAE,IAAI,EAAC,OAAO,EAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,KAAM,IAAI,GAAI,EAC1F,KAAK,IACA,CACT,CAAC;AACJ,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"Radio.js","sourceRoot":"","sources":["../../src/primitives/Radio.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA4C,MAAM,OAAO,CAAC;AAC7E,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AASjD,MAAM,SAAS,GAAG,oFAAoF,aAAa,EAAE,CAAC;AAEtH;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAA+B,SAAS,KAAK,CAC1E,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EACnC,GAAG;IAEH,OAAO,CACL,iBAAO,SAAS,EAAC,2FAA2F,aAC1G,gBAAO,GAAG,EAAE,GAAG,EAAE,IAAI,EAAC,OAAO,EAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,KAAM,IAAI,GAAI,EAC1F,KAAK,IACA,CACT,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -1,5 +1,7 @@
1
1
  export interface SpinnerProps {
2
+ /** Composed after the kit's own classes (design principle 2). */
3
+ className?: string;
2
4
  /** Localized loading text. The kit never ships strings — see README. */
3
5
  label: string;
4
6
  }
5
- export declare function Spinner({ label }: SpinnerProps): import("react").JSX.Element;
7
+ export declare function Spinner({ label, className }: SpinnerProps): import("react").JSX.Element;
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- export function Spinner({ label }) {
3
- return (_jsx("output", { className: "font-sans text-text-muted", "aria-live": "polite", children: label }));
2
+ import { cx } from '../lib/cx.js';
3
+ export function Spinner({ label, className }) {
4
+ return (_jsx("output", { className: cx('font-sans text-text-muted', className), "aria-live": "polite", children: label }));
4
5
  }
5
6
  //# sourceMappingURL=Spinner.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Spinner.js","sourceRoot":"","sources":["../../src/primitives/Spinner.tsx"],"names":[],"mappings":";AAKA,MAAM,UAAU,OAAO,CAAC,EAAE,KAAK,EAAgB;IAC7C,OAAO,CACL,iBAAQ,SAAS,EAAC,2BAA2B,eAAW,QAAQ,YAC7D,KAAK,GACC,CACV,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"Spinner.js","sourceRoot":"","sources":["../../src/primitives/Spinner.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAQlC,MAAM,UAAU,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,EAAgB;IACxD,OAAO,CACL,iBAAQ,SAAS,EAAE,EAAE,CAAC,2BAA2B,EAAE,SAAS,CAAC,eAAY,QAAQ,YAC9E,KAAK,GACC,CACV,CAAC;AACJ,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { forwardRef } from 'react';
3
3
  import { cx } from '../lib/cx.js';
4
- import { CONTROL_CLASS } from '../lib/states.js';
4
+ import { CLICKABLE_CLASS } from '../lib/states.js';
5
5
  /**
6
6
  * An on/off control that takes effect immediately.
7
7
  *
@@ -14,6 +14,6 @@ import { CONTROL_CLASS } from '../lib/states.js';
14
14
  * `aria-checked` carries the state; the visible track is decoration on top of it.
15
15
  */
16
16
  export const Switch = forwardRef(function Switch({ checked, onCheckedChange, label, className, ...rest }, ref) {
17
- return (_jsx("button", { ref: ref, type: "button", role: "switch", "aria-checked": checked, "aria-label": label, onClick: () => onCheckedChange(!checked), className: cx('inline-flex items-center rounded-x-slot-switch border border-border px-x-slot-switch-pad-x py-x-slot-switch-pad-y font-sans', checked ? 'bg-accent text-on-accent' : 'bg-surface text-text-muted', CONTROL_CLASS, className), ...rest, children: label }));
17
+ return (_jsx("button", { ref: ref, type: "button", role: "switch", "aria-checked": checked, "aria-label": label, onClick: () => onCheckedChange(!checked), className: cx('inline-flex items-center rounded-x-slot-switch border border-border px-x-slot-switch-pad-x py-x-slot-switch-pad-y font-sans', checked ? 'bg-accent text-on-accent' : 'bg-surface text-text-muted', CLICKABLE_CLASS, className), ...rest, children: label }));
18
18
  });
19
19
  //# sourceMappingURL=Switch.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Switch.js","sourceRoot":"","sources":["../../src/primitives/Switch.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA6B,MAAM,OAAO,CAAC;AAC9D,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAUjD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAAiC,SAAS,MAAM,CAC9E,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EACvD,GAAG;IAEH,OAAO,CACL,iBACE,GAAG,EAAE,GAAG,EACR,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,QAAQ,kBACC,OAAO,gBACT,KAAK,EACjB,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EACxC,SAAS,EAAE,EAAE,CACX,6HAA6H,EAC7H,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,4BAA4B,EACnE,aAAa,EACb,SAAS,CACV,KACG,IAAI,YAEP,KAAK,GACC,CACV,CAAC;AACJ,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"Switch.js","sourceRoot":"","sources":["../../src/primitives/Switch.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA6B,MAAM,OAAO,CAAC;AAC9D,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAUnD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAAiC,SAAS,MAAM,CAC9E,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,IAAI,EAAE,EACvD,GAAG;IAEH,OAAO,CACL,iBACE,GAAG,EAAE,GAAG,EACR,IAAI,EAAC,QAAQ,EACb,IAAI,EAAC,QAAQ,kBACC,OAAO,gBACT,KAAK,EACjB,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,EACxC,SAAS,EAAE,EAAE,CACX,6HAA6H,EAC7H,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,4BAA4B,EACnE,eAAe,EACf,SAAS,CACV,KACG,IAAI,YAEP,KAAK,GACC,CACV,CAAC;AACJ,CAAC,CAAC,CAAC"}
@@ -1,7 +1,9 @@
1
1
  import type { ReactNode } from 'react';
2
2
  export interface TextProps {
3
+ /** Composed after the kit's own classes (design principle 2). */
4
+ className?: string;
3
5
  as?: 'p' | 'span';
4
6
  tone?: 'primary' | 'muted';
5
7
  children: ReactNode;
6
8
  }
7
- export declare function Text({ as, tone, children }: TextProps): import("react").JSX.Element;
9
+ export declare function Text({ as, tone, children, className }: TextProps): import("react").JSX.Element;
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- export function Text({ as = 'p', tone = 'primary', children }) {
3
- const className = `font-sans ${tone === 'muted' ? 'text-text-muted' : 'text-text-primary'}`;
4
- return as === 'span' ? (_jsx("span", { className: className, children: children })) : (_jsx("p", { className: className, children: children }));
2
+ import { cx } from '../lib/cx.js';
3
+ export function Text({ as = 'p', tone = 'primary', children, className }) {
4
+ const merged = cx('font-sans', tone === 'muted' ? 'text-text-muted' : 'text-text-primary', className);
5
+ return as === 'span' ? (_jsx("span", { className: merged, children: children })) : (_jsx("p", { className: merged, children: children }));
5
6
  }
6
7
  //# sourceMappingURL=Text.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Text.js","sourceRoot":"","sources":["../../src/primitives/Text.tsx"],"names":[],"mappings":";AAQA,MAAM,UAAU,IAAI,CAAC,EAAE,EAAE,GAAG,GAAG,EAAE,IAAI,GAAG,SAAS,EAAE,QAAQ,EAAa;IACtE,MAAM,SAAS,GAAG,aAAa,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,mBAAmB,EAAE,CAAC;IAE5F,OAAO,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,CACrB,eAAM,SAAS,EAAE,SAAS,YAAG,QAAQ,GAAQ,CAC9C,CAAC,CAAC,CAAC,CACF,YAAG,SAAS,EAAE,SAAS,YAAG,QAAQ,GAAK,CACxC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"Text.js","sourceRoot":"","sources":["../../src/primitives/Text.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAUlC,MAAM,UAAU,IAAI,CAAC,EAAE,EAAE,GAAG,GAAG,EAAE,IAAI,GAAG,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAa;IACjF,MAAM,MAAM,GAAG,EAAE,CACf,WAAW,EACX,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,mBAAmB,EAC1D,SAAS,CACV,CAAC;IAEF,OAAO,EAAE,KAAK,MAAM,CAAC,CAAC,CAAC,CACrB,eAAM,SAAS,EAAE,MAAM,YAAG,QAAQ,GAAQ,CAC3C,CAAC,CAAC,CAAC,CACF,YAAG,SAAS,EAAE,MAAM,YAAG,QAAQ,GAAK,CACrC,CAAC;AACJ,CAAC"}
@@ -1,5 +1,15 @@
1
1
  export interface EmptyStateProps {
2
+ /** Composed after the kit's own classes (design principle 2). */
3
+ className?: string;
4
+ /**
5
+ * Horizontal alignment. Centre by default — measured across the fleet on 2026-08-23,
6
+ * five of the six products that ship an EmptyState centre it.
7
+ *
8
+ * A choice between two arrangements, not a value: `align="start"` is structure, and
9
+ * design principle 3 bars design *values* from props, not structural options.
10
+ */
11
+ align?: 'center' | 'start';
2
12
  /** Localized message. The kit never ships strings — see README. */
3
13
  message: string;
4
14
  }
5
- export declare function EmptyState({ message }: EmptyStateProps): import("react").JSX.Element;
15
+ export declare function EmptyState({ message, align, className }: EmptyStateProps): import("react").JSX.Element;
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- export function EmptyState({ message }) {
3
- return (_jsx("div", { className: "py-x-slot-state-pad-y font-sans text-text-muted", role: "status", children: message }));
2
+ import { cx } from '../lib/cx.js';
3
+ export function EmptyState({ message, align = 'center', className }) {
4
+ return (_jsx("div", { className: cx('py-x-slot-state-pad-y font-sans text-text-muted', align === 'center' && 'text-center', className), role: "status", children: message }));
4
5
  }
5
6
  //# sourceMappingURL=EmptyState.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"EmptyState.js","sourceRoot":"","sources":["../../src/states/EmptyState.tsx"],"names":[],"mappings":";AAKA,MAAM,UAAU,UAAU,CAAC,EAAE,OAAO,EAAmB;IACrD,OAAO,CACL,cAAK,SAAS,EAAC,iDAAiD,EAAC,IAAI,EAAC,QAAQ,YAC3E,OAAO,GACJ,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"EmptyState.js","sourceRoot":"","sources":["../../src/states/EmptyState.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAgBlC,MAAM,UAAU,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,GAAG,QAAQ,EAAE,SAAS,EAAmB;IAClF,OAAO,CACL,cACE,SAAS,EAAE,EAAE,CACX,iDAAiD,EACjD,KAAK,KAAK,QAAQ,IAAI,aAAa,EACnC,SAAS,CACV,EACD,IAAI,EAAC,QAAQ,YAEZ,OAAO,GACJ,CACP,CAAC;AACJ,CAAC"}
@@ -1,8 +1,10 @@
1
1
  export interface ErrorStateProps {
2
+ /** Composed after the kit's own classes (design principle 2). */
3
+ className?: string;
2
4
  /** Localized message. */
3
5
  message: string;
4
6
  /** Localized label for the retry control. */
5
7
  retryLabel: string;
6
8
  onRetry: () => void;
7
9
  }
8
- export declare function ErrorState({ message, retryLabel, onRetry }: ErrorStateProps): import("react").JSX.Element;
10
+ export declare function ErrorState({ message, retryLabel, onRetry, className }: ErrorStateProps): import("react").JSX.Element;
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Button } from '../primitives/Button.js';
3
- export function ErrorState({ message, retryLabel, onRetry }) {
4
- return (_jsxs("div", { className: "py-x-slot-state-pad-y", role: "alert", children: [_jsx("p", { className: "font-sans text-danger", children: message }), _jsx("div", { className: "py-x-slot-state-action-pad-y", children: _jsx(Button, { variant: "secondary", onClick: onRetry, children: retryLabel }) })] }));
3
+ import { cx } from '../lib/cx.js';
4
+ export function ErrorState({ message, retryLabel, onRetry, className }) {
5
+ return (_jsxs("div", { className: cx('py-x-slot-state-pad-y', className), role: "alert", children: [_jsx("p", { className: "font-sans text-danger", children: message }), _jsx("div", { className: "py-x-slot-state-action-pad-y", children: _jsx(Button, { variant: "secondary", onClick: onRetry, children: retryLabel }) })] }));
5
6
  }
6
7
  //# sourceMappingURL=ErrorState.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ErrorState.js","sourceRoot":"","sources":["../../src/states/ErrorState.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAUjD,MAAM,UAAU,UAAU,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAmB;IAC1E,OAAO,CACL,eAAK,SAAS,EAAC,uBAAuB,EAAC,IAAI,EAAC,OAAO,aACjD,YAAG,SAAS,EAAC,uBAAuB,YAAE,OAAO,GAAK,EAClD,cAAK,SAAS,EAAC,8BAA8B,YAC3C,KAAC,MAAM,IAAC,OAAO,EAAC,WAAW,EAAC,OAAO,EAAE,OAAO,YACzC,UAAU,GACJ,GACL,IACF,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"ErrorState.js","sourceRoot":"","sources":["../../src/states/ErrorState.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAYlC,MAAM,UAAU,UAAU,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAmB;IACrF,OAAO,CACL,eAAK,SAAS,EAAE,EAAE,CAAC,uBAAuB,EAAE,SAAS,CAAC,EAAE,IAAI,EAAC,OAAO,aAClE,YAAG,SAAS,EAAC,uBAAuB,YAAE,OAAO,GAAK,EAClD,cAAK,SAAS,EAAC,8BAA8B,YAC3C,KAAC,MAAM,IAAC,OAAO,EAAC,WAAW,EAAC,OAAO,EAAE,OAAO,YACzC,UAAU,GACJ,GACL,IACF,CACP,CAAC;AACJ,CAAC"}
@@ -1,4 +1,6 @@
1
1
  export interface LoadingStateProps {
2
+ /** Composed after the kit's own classes (design principle 2). */
3
+ className?: string;
2
4
  /** Localized message announced while the work is in flight. */
3
5
  label: string;
4
6
  }
@@ -15,4 +17,4 @@ export interface LoadingStateProps {
15
17
  * and a live region wrapped in another live region is announced twice. `aria-busy` marks
16
18
  * the region as in-flight without adding a second announcer.
17
19
  */
18
- export declare function LoadingState({ label }: LoadingStateProps): import("react").JSX.Element;
20
+ export declare function LoadingState({ label, className }: LoadingStateProps): import("react").JSX.Element;
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { Spinner } from '../primitives/Spinner.js';
3
+ import { cx } from '../lib/cx.js';
3
4
  /**
4
5
  * The third of the three states.
5
6
  *
@@ -13,7 +14,7 @@ import { Spinner } from '../primitives/Spinner.js';
13
14
  * and a live region wrapped in another live region is announced twice. `aria-busy` marks
14
15
  * the region as in-flight without adding a second announcer.
15
16
  */
16
- export function LoadingState({ label }) {
17
- return (_jsx("div", { className: "py-x-slot-state-pad-y", "aria-busy": "true", children: _jsx(Spinner, { label: label }) }));
17
+ export function LoadingState({ label, className }) {
18
+ return (_jsx("div", { className: cx('py-x-slot-state-pad-y', className), "aria-busy": "true", children: _jsx(Spinner, { label: label }) }));
18
19
  }
19
20
  //# sourceMappingURL=LoadingState.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LoadingState.js","sourceRoot":"","sources":["../../src/states/LoadingState.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAOnD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,YAAY,CAAC,EAAE,KAAK,EAAqB;IACvD,OAAO,CACL,cAAK,SAAS,EAAC,uBAAuB,eAAW,MAAM,YACrD,KAAC,OAAO,IAAC,KAAK,EAAE,KAAK,GAAI,GACrB,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"LoadingState.js","sourceRoot":"","sources":["../../src/states/LoadingState.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AASlC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,YAAY,CAAC,EAAE,KAAK,EAAE,SAAS,EAAqB;IAClE,OAAO,CACL,cAAK,SAAS,EAAE,EAAE,CAAC,uBAAuB,EAAE,SAAS,CAAC,eAAY,MAAM,YACtE,KAAC,OAAO,IAAC,KAAK,EAAE,KAAK,GAAI,GACrB,CACP,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hideyukimori/nene2-ui",
3
- "version": "0.3.0",
3
+ "version": "0.6.0",
4
4
  "description": "NeNe fleet shared React UI kit — token-driven primitives on Tailwind v4 @theme. Components carry no design of their own; themes do.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -38,6 +38,22 @@
38
38
  * focused input is under 16px, and a product whose body text is 14px would inherit that.
39
39
  * Keeping a control readable is the control's job, not the product's. */
40
40
 
41
+ /* The type scale. Six steps, from what the fleet actually writes (measured 2026-08-23):
42
+ * nene-records uses `sm` 65 times and `xs` 40, nene-field `sm` 59 / `xs` 57 / `base` 21 /
43
+ * `lg` 13, nene-vault `2xs` 33. Nothing above `xl` recurs.
44
+ *
45
+ * 🔴 `--text-x-ios-floor` is not a design step and products should not use it as one. It
46
+ * is here because iOS Safari zooms the page when a focused control is under 16px, which is
47
+ * a fact about the device rather than a decision about the product. Slots reference it so
48
+ * that the rule "a slot contains only scale references" stays true. */
49
+ --text-x-2xs: 0.6875rem;
50
+ --text-x-xs: 0.75rem;
51
+ --text-x-sm: 0.875rem;
52
+ --text-x-md: 1rem;
53
+ --text-x-lg: 1.125rem;
54
+ --text-x-xl: 1.5rem;
55
+ --text-x-ios-floor: 16px;
56
+
41
57
  /* ─────────────────────────────────────────────────────────────────────────
42
58
  * ② SLOTS — a product may redefine these.
43
59
  *
@@ -52,10 +68,16 @@
52
68
  * ───────────────────────────────────────────────────────────────────────── */
53
69
  --spacing-x-slot-button-pad-x: var(--spacing-x-sm);
54
70
  --spacing-x-slot-button-pad-y: var(--spacing-x-xs);
71
+ --spacing-x-slot-button-sm-pad-x: var(--spacing-x-xs);
72
+ --spacing-x-slot-button-sm-pad-y: var(--spacing-x-3xs);
55
73
  --spacing-x-slot-control-pad-x: var(--spacing-x-2xs);
56
74
  --spacing-x-slot-control-pad-y: var(--spacing-x-xs);
57
75
  --spacing-x-slot-field-gap: var(--spacing-x-2xs);
58
76
  --spacing-x-slot-choice-gap: var(--spacing-x-2xs);
77
+ /* The box itself. 1rem = 16px, which is what every product that ships a checkbox uses
78
+ * (measured 2026-08-23). Sized from the scale so a product that wants a larger hit area
79
+ * moves a step rather than inventing a length. */
80
+ --spacing-x-slot-choice-box: var(--spacing-x-sm);
59
81
  --spacing-x-slot-badge-pad-x: var(--spacing-x-2xs);
60
82
  --spacing-x-slot-badge-pad-y: var(--spacing-x-3xs);
61
83
  --spacing-x-slot-switch-pad-x: var(--spacing-x-2xs);
@@ -83,10 +105,41 @@
83
105
  --radius-x-slot-modal: var(--radius-x-md);
84
106
  --radius-x-slot-card: var(--radius-x-md);
85
107
 
108
+ /* Pointer feedback. One rule for every variant, rather than a hover colour per fill:
109
+ * the kit's buttons are filled with three different colours, and a palette entry for each
110
+ * hover state would be three more values a product has to keep in step. Darkening works on
111
+ * all of them — including the white `secondary` fill, where the fleet's own
112
+ * `hover:brightness-105` does nothing at all.
113
+ *
114
+ * Tailwind wraps `hover:` in `@media (hover: hover)`, so this does not stick on touch. */
115
+ --brightness-x-slot-hover: 95%;
116
+ --brightness-x-slot-press: 90%;
117
+
118
+ --color-x-slot-choice-accent: var(--color-accent);
119
+
120
+ /* Alert colours. `warn` defaults to the same hue as `danger` because this palette has one
121
+ * alert colour — a second one is a decision a product makes, not something the kit can
122
+ * invent. Until a product sets these, "warning" and "failure" look alike, and only the
123
+ * announced urgency differs: role="status" against role="alert". That difference reaches
124
+ * someone listening and no one looking (nene-vault, 2026-08-23), which is why the slots
125
+ * exist rather than the tones being hard-coded. */
126
+ --color-x-slot-alert-info-bg: var(--color-surface);
127
+ --color-x-slot-alert-info-fg: var(--color-text-primary);
128
+ --color-x-slot-alert-info-border: var(--color-border);
129
+ --color-x-slot-alert-warn-bg: var(--color-surface);
130
+ --color-x-slot-alert-warn-fg: var(--color-danger);
131
+ --color-x-slot-alert-warn-border: var(--color-danger);
132
+ --color-x-slot-alert-danger-bg: var(--color-surface);
133
+ --color-x-slot-alert-danger-fg: var(--color-danger);
134
+ --color-x-slot-alert-danger-border: var(--color-danger);
86
135
  --color-x-slot-field-label: var(--color-text-muted);
87
- --text-x-slot-field-label-size: 0.75rem;
136
+ --color-x-slot-field-hint: var(--color-text-muted);
137
+ --text-x-slot-field-hint-size: var(--text-x-2xs);
138
+ --color-x-slot-field-error: var(--color-danger);
139
+ --text-x-slot-field-error-size: var(--text-x-2xs);
140
+ --text-x-slot-field-label-size: var(--text-x-xs);
88
141
  --font-weight-x-slot-field-label: 500;
89
- --text-x-slot-control-size: max(1rem, 16px);
142
+ --text-x-slot-control-size: max(var(--text-x-md), var(--text-x-ios-floor));
90
143
 
91
144
  /* Sentinel for the consumer's build (#316). Zero-width, so applying it does nothing.
92
145
  * Its only job is to exist: `p-x-source-probe` appears nowhere except this kit's `dist`,