@hideyukimori/nene2-ui 0.2.0 → 0.4.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 (63) hide show
  1. package/README.md +76 -0
  2. package/dist/data/DataTable.js +1 -1
  3. package/dist/data/DataTable.js.map +1 -1
  4. package/dist/data/DetailList.d.ts +3 -1
  5. package/dist/data/DetailList.js +3 -2
  6. package/dist/data/DetailList.js.map +1 -1
  7. package/dist/feedback/Badge.js +1 -1
  8. package/dist/feedback/Badge.js.map +1 -1
  9. package/dist/feedback/InlineAlert.d.ts +1 -1
  10. package/dist/feedback/InlineAlert.js +5 -1
  11. package/dist/feedback/InlineAlert.js.map +1 -1
  12. package/dist/feedback/ToastProvider.js +3 -3
  13. package/dist/feedback/ToastProvider.js.map +1 -1
  14. package/dist/forms/FormField.js +1 -1
  15. package/dist/forms/FormField.js.map +1 -1
  16. package/dist/index.d.ts +1 -1
  17. package/dist/index.js +1 -1
  18. package/dist/index.js.map +1 -1
  19. package/dist/layout/Card.js +1 -1
  20. package/dist/layout/Card.js.map +1 -1
  21. package/dist/layout/PageHeader.d.ts +3 -1
  22. package/dist/layout/PageHeader.js +3 -2
  23. package/dist/layout/PageHeader.js.map +1 -1
  24. package/dist/lib/states.d.ts +29 -4
  25. package/dist/lib/states.js +29 -4
  26. package/dist/lib/states.js.map +1 -1
  27. package/dist/overlay/Modal.js +1 -1
  28. package/dist/overlay/Modal.js.map +1 -1
  29. package/dist/primitives/Button.d.ts +9 -2
  30. package/dist/primitives/Button.js +11 -4
  31. package/dist/primitives/Button.js.map +1 -1
  32. package/dist/primitives/Checkbox.js +2 -2
  33. package/dist/primitives/Checkbox.js.map +1 -1
  34. package/dist/primitives/Icon.d.ts +9 -3
  35. package/dist/primitives/Icon.js +9 -3
  36. package/dist/primitives/Icon.js.map +1 -1
  37. package/dist/primitives/Input.js +1 -1
  38. package/dist/primitives/Input.js.map +1 -1
  39. package/dist/primitives/Radio.js +1 -1
  40. package/dist/primitives/Radio.js.map +1 -1
  41. package/dist/primitives/Select.js +1 -1
  42. package/dist/primitives/Select.js.map +1 -1
  43. package/dist/primitives/Spinner.d.ts +3 -1
  44. package/dist/primitives/Spinner.js +3 -2
  45. package/dist/primitives/Spinner.js.map +1 -1
  46. package/dist/primitives/Switch.js +2 -2
  47. package/dist/primitives/Switch.js.map +1 -1
  48. package/dist/primitives/Text.d.ts +3 -1
  49. package/dist/primitives/Text.js +4 -3
  50. package/dist/primitives/Text.js.map +1 -1
  51. package/dist/primitives/Textarea.js +1 -1
  52. package/dist/primitives/Textarea.js.map +1 -1
  53. package/dist/states/EmptyState.d.ts +11 -1
  54. package/dist/states/EmptyState.js +3 -2
  55. package/dist/states/EmptyState.js.map +1 -1
  56. package/dist/states/ErrorState.d.ts +3 -1
  57. package/dist/states/ErrorState.js +3 -2
  58. package/dist/states/ErrorState.js.map +1 -1
  59. package/dist/states/LoadingState.d.ts +3 -1
  60. package/dist/states/LoadingState.js +3 -2
  61. package/dist/states/LoadingState.js.map +1 -1
  62. package/package.json +1 -1
  63. package/themes/default.css +79 -0
package/README.md CHANGED
@@ -131,6 +131,82 @@ Regenerate a theme from the token contract with:
131
131
  npx @hideyukimori/nene2-tokens themegen
132
132
  ```
133
133
 
134
+ ## 🔴 What a product may redefine, and what it may not
135
+
136
+ The theme has two layers, and the line between them is the point.
137
+
138
+ ### ② Slots — 🟢 redefine these
139
+
140
+ Every design value a component uses comes from a slot, and slots are named per component:
141
+
142
+ ```css
143
+ /* your product's theme, loaded after the kit's */
144
+ @theme {
145
+ --spacing-x-slot-card-pad: var(--spacing-x-lg); /* roomier cards, everywhere */
146
+ --color-x-slot-field-label: var(--color-text-primary); /* darker field labels */
147
+ --radius-x-slot-control: var(--radius-x-md);
148
+ }
149
+ ```
150
+
151
+ This is where your product decides how it looks. Change a slot and every instance of that
152
+ component follows.
153
+
154
+ ### ① The scale — 🔒 do not redefine
155
+
156
+ `--spacing-x-3xs` … `--spacing-x-2xl`, and the radius and colour tokens they point at.
157
+
158
+ ```css
159
+ --spacing-x-slot-card-pad: 1.375rem; /* 🔴 no */
160
+ --spacing-x-md: 1.375rem; /* 🔴 no */
161
+ ```
162
+
163
+ **A slot chooses a step; it may not invent one.** That is the whole mechanism: a product can
164
+ make its cards roomier, and cannot end up with `2.25` again.
165
+
166
+ ### Why the scale is locked
167
+
168
+ Measured in nene-vault before its migration: **128 spacing utilities using 19 distinct
169
+ values**, five of which appeared exactly once. That is drift, not design. Retuning the scale
170
+ to match it also fits _worse_, not better:
171
+
172
+ | scale | exact match | within 2px | worst case |
173
+ | ------------------------------- | ----------: | ---------: | ----------: |
174
+ | **the kit's nine** | 47% | **99%** | **4px** |
175
+ | nine chosen to fit this product | 84% | 95% | 🔴 **24px** |
176
+
177
+ More exact matches, five times the worst error — a scale bent toward one histogram drops its
178
+ own ends.
179
+
180
+ 🔑 **The scale is the set you keep to. The slots are what your brand looks like.**
181
+
182
+ ### Composing a slot
183
+
184
+ A slot can hold several steps — four-sided padding is just CSS:
185
+
186
+ ```css
187
+ --spacing-x-slot-login-form-pad: var(--spacing-x-xl) var(--spacing-x-md) var(--spacing-x-lg)
188
+ var(--spacing-x-md);
189
+ ```
190
+
191
+ 🔴 **There is no shorthand for this, on purpose.** The kit's tokens are written by tooling,
192
+ not typed by hand, so brevity buys nothing — and a shorthand would need an expander, which is
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.**
196
+
197
+ That check is what keeps the scale from leaking. `--spacing-x-slot-field-gap: 0.5625rem`
198
+ compiles, looks reasonable, and reintroduces the drift the scale exists to stop — so it fails
199
+ here, including when it is hidden among three legitimate references in a composition.
200
+
201
+ ### Both halves are enforced
202
+
203
+ A slot whose default contains a literal, or a component that reaches past the slots into the
204
+ scale, fails the test suite. If a screen cannot be expressed this way, it is a missing slot or
205
+ a missing component — open an issue, so every product gets the answer.
206
+
207
+ **Products: apply the same check to your own theme.** The kit can only police its own file;
208
+ the rule is the same one, and the regular expression above is the whole implementation.
209
+
134
210
  ## What is in scope
135
211
 
136
212
  **In:** admin console and business-screen UI, page layout scaffolding, form field structure, the
@@ -12,6 +12,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
12
12
  * page. It is visually hidden, not absent.
13
13
  */
14
14
  export function DataTable({ columns, rows, rowKey, caption }) {
15
- return (_jsxs("table", { className: "w-full border-collapse font-sans text-text-primary", children: [_jsx("caption", { className: "sr-only", children: caption }), _jsx("thead", { children: _jsx("tr", { children: columns.map((col) => (_jsx("th", { scope: "col", className: `border-b border-border px-x-2xs py-x-3xs font-medium text-text-muted ${col.align === 'end' ? 'text-right' : 'text-left'}`, children: col.header }, col.key))) }) }), _jsx("tbody", { children: rows.map((row) => (_jsx("tr", { children: columns.map((col) => (_jsx("td", { className: `border-b border-border px-x-2xs py-x-3xs ${col.align === 'end' ? 'text-right' : 'text-left'}`, children: col.cell(row) }, col.key))) }, rowKey(row)))) })] }));
15
+ return (_jsxs("table", { className: "w-full border-collapse font-sans text-text-primary", children: [_jsx("caption", { className: "sr-only", children: caption }), _jsx("thead", { children: _jsx("tr", { children: columns.map((col) => (_jsx("th", { scope: "col", className: `border-b border-border px-x-slot-table-cell-pad-x py-x-slot-table-cell-pad-y font-medium text-text-muted ${col.align === 'end' ? 'text-right' : 'text-left'}`, children: col.header }, col.key))) }) }), _jsx("tbody", { children: rows.map((row) => (_jsx("tr", { children: columns.map((col) => (_jsx("td", { className: `border-b border-border px-x-slot-table-cell-pad-x py-x-slot-table-cell-pad-y ${col.align === 'end' ? 'text-right' : 'text-left'}`, children: col.cell(row) }, col.key))) }, rowKey(row)))) })] }));
16
16
  }
17
17
  //# sourceMappingURL=DataTable.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DataTable.js","sourceRoot":"","sources":["../../src/data/DataTable.tsx"],"names":[],"mappings":";AAsBA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,SAAS,CAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAuB;IACpF,OAAO,CACL,iBAAO,SAAS,EAAC,oDAAoD,aACnE,kBAAS,SAAS,EAAC,SAAS,YAAE,OAAO,GAAW,EAChD,0BACE,uBACG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACpB,aAEE,KAAK,EAAC,KAAK,EACX,SAAS,EAAE,wEACT,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WACvC,EAAE,YAED,GAAG,CAAC,MAAM,IANN,GAAG,CAAC,GAAG,CAOT,CACN,CAAC,GACC,GACC,EACR,0BACG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACjB,uBACG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACpB,aAEE,SAAS,EAAE,4CACT,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WACvC,EAAE,YAED,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IALT,GAAG,CAAC,GAAG,CAMT,CACN,CAAC,IAVK,MAAM,CAAC,GAAG,CAAC,CAWf,CACN,CAAC,GACI,IACF,CACT,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"DataTable.js","sourceRoot":"","sources":["../../src/data/DataTable.tsx"],"names":[],"mappings":";AAsBA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,SAAS,CAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAuB;IACpF,OAAO,CACL,iBAAO,SAAS,EAAC,oDAAoD,aACnE,kBAAS,SAAS,EAAC,SAAS,YAAE,OAAO,GAAW,EAChD,0BACE,uBACG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACpB,aAEE,KAAK,EAAC,KAAK,EACX,SAAS,EAAE,4GACT,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WACvC,EAAE,YAED,GAAG,CAAC,MAAM,IANN,GAAG,CAAC,GAAG,CAOT,CACN,CAAC,GACC,GACC,EACR,0BACG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACjB,uBACG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACpB,aAEE,SAAS,EAAE,gFACT,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,WACvC,EAAE,YAED,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IALT,GAAG,CAAC,GAAG,CAMT,CACN,CAAC,IAVK,MAAM,CAAC,GAAG,CAAC,CAWf,CACN,CAAC,GACI,IACF,CACT,CAAC;AACJ,CAAC"}
@@ -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-stack-sm", children: rows.map((row) => (_jsxs("div", { className: "flex flex-col gap-x-inline-sm border-b border-border py-x-stack-sm", 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,8BAA8B,YACzC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CACjB,eAEE,SAAS,EAAC,oEAAoE,aAE9E,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"}
@@ -13,6 +13,6 @@ const TONE_CLASS = {
13
13
  * find every such lie afterwards except by reading every screen.
14
14
  */
15
15
  export function Badge({ tone = 'neutral', children }) {
16
- return (_jsx("span", { className: cx('inline-flex items-center rounded-x-md border px-x-2xs py-x-3xs font-sans', TONE_CLASS[tone]), children: children }));
16
+ return (_jsx("span", { className: cx('inline-flex items-center rounded-x-slot-badge border px-x-slot-badge-pad-x py-x-slot-badge-pad-y font-sans', TONE_CLASS[tone]), children: children }));
17
17
  }
18
18
  //# sourceMappingURL=Badge.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Badge.js","sourceRoot":"","sources":["../../src/feedback/Badge.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAQlC,MAAM,UAAU,GAAoD;IAClE,OAAO,EAAE,0CAA0C;IACnD,MAAM,EAAE,wCAAwC;IAChD,MAAM,EAAE,wCAAwC;CACjD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,KAAK,CAAC,EAAE,IAAI,GAAG,SAAS,EAAE,QAAQ,EAAc;IAC9D,OAAO,CACL,eACE,SAAS,EAAE,EAAE,CACX,0EAA0E,EAC1E,UAAU,CAAC,IAAI,CAAC,CACjB,YAEA,QAAQ,GACJ,CACR,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"Badge.js","sourceRoot":"","sources":["../../src/feedback/Badge.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAQlC,MAAM,UAAU,GAAoD;IAClE,OAAO,EAAE,0CAA0C;IACnD,MAAM,EAAE,wCAAwC;IAChD,MAAM,EAAE,wCAAwC;CACjD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,KAAK,CAAC,EAAE,IAAI,GAAG,SAAS,EAAE,QAAQ,EAAc;IAC9D,OAAO,CACL,eACE,SAAS,EAAE,EAAE,CACX,4GAA4G,EAC5G,UAAU,CAAC,IAAI,CAAC,CACjB,YAEA,QAAQ,GACJ,CACR,CAAC;AACJ,CAAC"}
@@ -1,7 +1,7 @@
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
  /**
@@ -2,6 +2,10 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { cx } from '../lib/cx.js';
3
3
  const TONE_CLASS = {
4
4
  info: 'bg-surface text-text-primary border-border',
5
+ // `warn` reuses the danger colour deliberately: the kit's palette has one alert hue, and
6
+ // inventing a second here would be a design value living outside themes/default.css. What
7
+ // differs is the urgency it is announced with, which is the part that matters.
8
+ warn: 'bg-surface text-danger border-danger',
5
9
  danger: 'bg-surface text-danger border-danger',
6
10
  };
7
11
  /**
@@ -13,6 +17,6 @@ const TONE_CLASS = {
13
17
  * of role is precisely the part that is easy to get wrong and invisible when you do.
14
18
  */
15
19
  export function InlineAlert({ tone = 'info', children }) {
16
- return (_jsx("div", { role: tone === 'danger' ? 'alert' : 'status', className: cx('rounded-x-md border p-x-2xs font-sans', TONE_CLASS[tone]), children: children }));
20
+ return (_jsx("div", { role: tone === 'danger' ? 'alert' : 'status', className: cx('rounded-x-slot-alert border p-x-slot-alert-pad font-sans', TONE_CLASS[tone]), children: children }));
17
21
  }
18
22
  //# sourceMappingURL=InlineAlert.js.map
@@ -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,uCAAuC,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC,YAEvE,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,4CAA4C;IAClD,yFAAyF;IACzF,0FAA0F;IAC1F,+EAA+E;IAC/E,IAAI,EAAE,sCAAsC;IAC5C,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,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',
@@ -48,9 +48,9 @@ export function ToastProvider({ regionLabel, dismissLabel, defaultDurationMs = 5
48
48
  };
49
49
  }, []);
50
50
  const api = useMemo(() => ({ show, dismiss }), [show, dismiss]);
51
- const region = (tone, live) => (_jsx("div", { "aria-live": live, "aria-label": regionLabel, role: "region", className: "flex flex-col gap-x-2xs", children: toasts
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-2xs rounded-x-md border p-x-2xs 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-md px-x-3xs', 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-inline-sm", children: [_jsxs("label", { htmlFor: id, className: "font-sans font-medium text-text-primary", 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-text-muted", children: hint })), errorId === null ? null : (_jsx("p", { id: errorId, role: "alert", className: "font-sans text-danger", 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,+BAA+B,aAC5C,iBAAO,OAAO,EAAE,EAAE,EAAE,SAAS,EAAC,yCAAyC,aACpE,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,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"}
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"}
@@ -8,6 +8,6 @@ import { GAP, PAD, resolve } from '../lib/spacing.js';
8
8
  * given its own colour would be a `div` with extra steps.
9
9
  */
10
10
  export function Card({ pad = 'sm', gap, raised = false, children, className, ...rest }) {
11
- return (_jsx("div", { className: cx('flex flex-col bg-surface-raised border border-border rounded-x-md', raised && 'shadow-sm', resolve(pad, PAD), resolve(gap, GAP), className), ...rest, children: children }));
11
+ return (_jsx("div", { className: cx('flex flex-col bg-surface-raised border border-border rounded-x-slot-card', raised && 'shadow-sm', resolve(pad, PAD), resolve(gap, GAP), className), ...rest, children: children }));
12
12
  }
13
13
  //# sourceMappingURL=Card.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Card.js","sourceRoot":"","sources":["../../src/layout/Card.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAA+B,MAAM,mBAAmB,CAAC;AAUnF;;;;;GAKG;AACH,MAAM,UAAU,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAa;IAC/F,OAAO,CACL,cACE,SAAS,EAAE,EAAE,CACX,mEAAmE,EACnE,MAAM,IAAI,WAAW,EACrB,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EACjB,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EACjB,SAAS,CACV,KACG,IAAI,YAEP,QAAQ,GACL,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"Card.js","sourceRoot":"","sources":["../../src/layout/Card.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAA+B,MAAM,mBAAmB,CAAC;AAUnF;;;;;GAKG;AACH,MAAM,UAAU,IAAI,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,IAAI,EAAa;IAC/F,OAAO,CACL,cACE,SAAS,EAAE,EAAE,CACX,0EAA0E,EAC1E,MAAM,IAAI,WAAW,EACrB,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EACjB,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EACjB,SAAS,CACV,KACG,IAAI,YAEP,QAAQ,GACL,CACP,CAAC;AACJ,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-stack-md", 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,iDAAiD,aACjE,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"}
@@ -13,10 +13,20 @@
13
13
  * that only shows the ring to keyboard users.
14
14
  *
15
15
  * 🔴 `outline`, not `ring`. Tailwind's `ring-*` is a box-shadow, so a parent with
16
- * `overflow-hidden` clips it away entirely. This kit's own `Card` does not clip — but the
17
- * products' existing containers do: `overflow-hidden` appears 12 times in nene-records and
18
- * twice each in nene-vault and nene-deal, which are the first two ships to be migrated
19
- * (measured 2026-08-23). `outline` is not clipped and carries its own offset.
16
+ * `overflow: hidden` clips it away entirely. This kit's own `Card` does not clip — the
17
+ * products' existing containers do, and what they clip decides how much this matters.
18
+ * In nene-vault, the first ship to migrate (measured 2026-08-23, counting CSS rules as well
19
+ * as Tailwind classes):
20
+ *
21
+ * .center-card the whole login form — two inputs and a button
22
+ * .seg the diff/json toggle on the audit screen
23
+ * .rail-link the mobile side-nav buttons
24
+ *
25
+ * A `ring` would have lost the focus indicator on all three, and the login form is the one
26
+ * screen an unauthenticated user can reach. nene-records clips in 12 places, which is more
27
+ * places but softer targets — the count is the weaker argument.
28
+ *
29
+ * `outline` is not clipped and carries its own offset.
20
30
  *
21
31
  * 🔴 The ring is `text-primary`, not `accent`. An accent ring is *the same colour as a
22
32
  * primary button* — contrast 1.00:1 against its own fill, and 1.11:1 against a danger
@@ -40,5 +50,20 @@ export declare const FOCUS_CLASS = "focus-visible:outline-2 focus-visible:outlin
40
50
  * literal here would be a design value living outside themes/default.css.
41
51
  */
42
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";
43
66
  /** Controls that can be focused and disabled — every interactive primitive in the kit. */
44
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";
@@ -13,10 +13,20 @@
13
13
  * that only shows the ring to keyboard users.
14
14
  *
15
15
  * 🔴 `outline`, not `ring`. Tailwind's `ring-*` is a box-shadow, so a parent with
16
- * `overflow-hidden` clips it away entirely. This kit's own `Card` does not clip — but the
17
- * products' existing containers do: `overflow-hidden` appears 12 times in nene-records and
18
- * twice each in nene-vault and nene-deal, which are the first two ships to be migrated
19
- * (measured 2026-08-23). `outline` is not clipped and carries its own offset.
16
+ * `overflow: hidden` clips it away entirely. This kit's own `Card` does not clip — the
17
+ * products' existing containers do, and what they clip decides how much this matters.
18
+ * In nene-vault, the first ship to migrate (measured 2026-08-23, counting CSS rules as well
19
+ * as Tailwind classes):
20
+ *
21
+ * .center-card the whole login form — two inputs and a button
22
+ * .seg the diff/json toggle on the audit screen
23
+ * .rail-link the mobile side-nav buttons
24
+ *
25
+ * A `ring` would have lost the focus indicator on all three, and the login form is the one
26
+ * screen an unauthenticated user can reach. nene-records clips in 12 places, which is more
27
+ * places but softer targets — the count is the weaker argument.
28
+ *
29
+ * `outline` is not clipped and carries its own offset.
20
30
  *
21
31
  * 🔴 The ring is `text-primary`, not `accent`. An accent ring is *the same colour as a
22
32
  * primary button* — contrast 1.00:1 against its own fill, and 1.11:1 against a danger
@@ -40,6 +50,21 @@ export const FOCUS_CLASS = 'focus-visible:outline-2 focus-visible:outline-offset
40
50
  * literal here would be a design value living outside themes/default.css.
41
51
  */
42
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';
43
66
  /** Controls that can be focused and disabled — every interactive primitive in the kit. */
44
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}`;
45
70
  //# sourceMappingURL=states.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"states.js","sourceRoot":"","sources":["../../src/lib/states.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;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"}
@@ -42,6 +42,6 @@ export function Modal({ open, onClose, title, children }) {
42
42
  return (_jsx("dialog", { ref: ref, "aria-label": title,
43
43
  // The browser fires `close` for Esc as well as for close(); routing both through the
44
44
  // caller keeps `open` from drifting out of sync with what is on screen.
45
- onClose: onClose, onCancel: onClose, className: cx('bg-surface-raised text-text-primary border border-border rounded-x-md', 'p-x-sm font-sans backdrop:bg-text-primary/50'), children: children }));
45
+ onClose: onClose, onCancel: onClose, className: cx('bg-surface-raised text-text-primary border border-border rounded-x-slot-modal', 'p-x-slot-modal-pad font-sans backdrop:bg-text-primary/50'), children: children }));
46
46
  }
47
47
  //# sourceMappingURL=Modal.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Modal.js","sourceRoot":"","sources":["../../src/overlay/Modal.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAkB,MAAM,OAAO,CAAC;AAC1D,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAWlC;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,KAAK,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAc;IAClE,MAAM,GAAG,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAE5C,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC;QACvB,IAAI,EAAE,KAAK,IAAI;YAAE,OAAO;QAExB,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,OAAO,EAAE,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;gBACvC,IAAI,CAAC,EAAE,CAAC,IAAI;oBAAE,EAAE,CAAC,SAAS,EAAE,CAAC;YAC/B,CAAC;iBAAM,CAAC;gBACN,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAC9B,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,OAAO,EAAE,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;YACnC,IAAI,EAAE,CAAC,IAAI;gBAAE,EAAE,CAAC,KAAK,EAAE,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,OAAO,CACL,iBACE,GAAG,EAAE,GAAG,gBACI,KAAK;QACjB,qFAAqF;QACrF,wEAAwE;QACxE,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,OAAO,EACjB,SAAS,EAAE,EAAE,CACX,uEAAuE,EACvE,8CAA8C,CAC/C,YAEA,QAAQ,GACF,CACV,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"Modal.js","sourceRoot":"","sources":["../../src/overlay/Modal.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAkB,MAAM,OAAO,CAAC;AAC1D,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAWlC;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,KAAK,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAc;IAClE,MAAM,GAAG,GAAG,MAAM,CAAoB,IAAI,CAAC,CAAC;IAE5C,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC;QACvB,IAAI,EAAE,KAAK,IAAI;YAAE,OAAO;QAExB,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,OAAO,EAAE,CAAC,SAAS,KAAK,UAAU,EAAE,CAAC;gBACvC,IAAI,CAAC,EAAE,CAAC,IAAI;oBAAE,EAAE,CAAC,SAAS,EAAE,CAAC;YAC/B,CAAC;iBAAM,CAAC;gBACN,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;YAC9B,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,OAAO,EAAE,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;YACnC,IAAI,EAAE,CAAC,IAAI;gBAAE,EAAE,CAAC,KAAK,EAAE,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,OAAO,CACL,iBACE,GAAG,EAAE,GAAG,gBACI,KAAK;QACjB,qFAAqF;QACrF,wEAAwE;QACxE,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,OAAO,EACjB,SAAS,EAAE,EAAE,CACX,+EAA+E,EAC/E,0DAA0D,CAC3D,YAEA,QAAQ,GACF,CACV,CAAC;AACJ,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,20 @@
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
6
  secondary: 'bg-surface-raised text-text-primary border 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-md px-x-inline-md py-x-stack-sm 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
+ const BASE_CLASS = `rounded-x-slot-button font-sans font-medium ${CLICKABLE_CLASS}`;
17
+ export function Button({ variant = 'primary', size = 'md', children, type = 'button', className, ...rest }) {
18
+ return (_jsx("button", { type: type, className: cx(BASE_CLASS, SIZE_CLASS[size], VARIANT_CLASS[variant], className), ...rest, children: children }));
12
19
  }
13
20
  //# 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,mEAAmE,aAAa,EAAE,CAAC;AAEtG,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,0DAA0D;IACrE,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,MAAM,UAAU,GAAG,+CAA+C,eAAe,EAAE,CAAC;AAEpF,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"}
@@ -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-md border border-border accent-accent ${CONTROL_CLASS}`;
6
+ const BOX_CLASS = `rounded-x-slot-control border border-border accent-accent ${CONTROL_CLASS}`;
7
7
  /**
8
8
  * A checkbox and its label, as one part.
9
9
  *
@@ -14,6 +14,6 @@ const BOX_CLASS = `rounded-x-md border border-border accent-accent ${CONTROL_CLA
14
14
  */
15
15
  export const Checkbox = forwardRef(function Checkbox({ label, className, id, 'aria-invalid': ariaInvalid, 'aria-describedby': ariaDescribedBy, 'aria-required': ariaRequired, ...rest }, ref) {
16
16
  const wiring = useFieldWiring({ id, ariaInvalid, ariaDescribedBy, ariaRequired });
17
- return (_jsxs("label", { className: "inline-flex items-center gap-x-2xs font-sans text-text-primary", children: [_jsx("input", { ref: ref, type: "checkbox", className: cx(BOX_CLASS, className), ...wiring, ...rest }), label] }));
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] }));
18
18
  });
19
19
  //# 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,mDAAmD,aAAa,EAAE,CAAC;AAErF;;;;;;;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,gEAAgE,aAC/E,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,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"}
@@ -21,9 +21,15 @@ export type IconProps = MeaningfulIcon | DecorativeIcon;
21
21
  *
22
22
  * 🔴 The kit ships no artwork and takes on no icon library, because the fleet has none:
23
23
  * across all ten products the dependency count for lucide / heroicons / feather / phosphor
24
- * / tabler is zero, and every icon is an inline `<svg>` (222 of them, measured 2026-08-23).
25
- * Choosing a set would mean adding a dependency to seventeen ships to solve a problem they
26
- * do not have.
24
+ * / tabler is zero, and the icons are drawn inline: **222 `<svg>` elements** across eight
25
+ * products (measured 2026-08-23). Choosing a set would mean adding a dependency to
26
+ * seventeen ships to solve a problem they do not have.
27
+ *
28
+ * (Scope: that count is `<svg>` elements only. Icons can also be drawn as CSS backgrounds,
29
+ * and one is — the `select` chevron in nene-vault, a data-URI background. Searching for one
30
+ * spelling of a thing that has several always undercounts, so the form being counted is
31
+ * written down. A background-drawn icon has no element to announce either way, so it does
32
+ * not move the number below.)
27
33
  *
28
34
  * 🔴 What is not consistent is the meaning. Of those 222, **101 declare neither
29
35
  * `aria-hidden` nor `role="img"`** — they do not say whether they are decoration or
@@ -10,9 +10,15 @@ const SIZE_CLASS = {
10
10
  *
11
11
  * 🔴 The kit ships no artwork and takes on no icon library, because the fleet has none:
12
12
  * across all ten products the dependency count for lucide / heroicons / feather / phosphor
13
- * / tabler is zero, and every icon is an inline `<svg>` (222 of them, measured 2026-08-23).
14
- * Choosing a set would mean adding a dependency to seventeen ships to solve a problem they
15
- * do not have.
13
+ * / tabler is zero, and the icons are drawn inline: **222 `<svg>` elements** across eight
14
+ * products (measured 2026-08-23). Choosing a set would mean adding a dependency to
15
+ * seventeen ships to solve a problem they do not have.
16
+ *
17
+ * (Scope: that count is `<svg>` elements only. Icons can also be drawn as CSS backgrounds,
18
+ * and one is — the `select` chevron in nene-vault, a data-URI background. Searching for one
19
+ * spelling of a thing that has several always undercounts, so the form being counted is
20
+ * written down. A background-drawn icon has no element to announce either way, so it does
21
+ * not move the number below.)
16
22
  *
17
23
  * 🔴 What is not consistent is the meaning. Of those 222, **101 declare neither
18
24
  * `aria-hidden` nor `role="img"`** — they do not say whether they are decoration or
@@ -1 +1 @@
1
- {"version":3,"file":"Icon.js","sourceRoot":"","sources":["../../src/primitives/Icon.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAwBlC,MAAM,UAAU,GAA6B;IAC3C,EAAE,EAAE,SAAS;IACb,EAAE,EAAE,SAAS;IACb,EAAE,EAAE,SAAS;CACd,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,GAAG,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,EAAa;IAC3E,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,GAAG,IAEJ,CAAC;IAC5B,OAAQ,QAAqC,CAAC,UAAU,CAAC;IAEzD,2FAA2F;IAC3F,uFAAuF;IACvF,0FAA0F;IAC1F,4DAA4D;IAC5D,MAAM,UAAU,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,CAAC;IAEvD,OAAO,CACL,cACE,OAAO,EAAC,WAAW,EACnB,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,cAAc,EACrB,WAAW,EAAE,GAAG,EAChB,SAAS,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,KAClD,CAAC,UAAU;YACb,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE;YAC3C,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,KACrC,QAAQ,YAEX,QAAQ,GACL,CACP,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"Icon.js","sourceRoot":"","sources":["../../src/primitives/Icon.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAwBlC,MAAM,UAAU,GAA6B;IAC3C,EAAE,EAAE,SAAS;IACb,EAAE,EAAE,SAAS;IACb,EAAE,EAAE,SAAS;CACd,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,GAAG,IAAI,EAAE,SAAS,EAAE,GAAG,IAAI,EAAa;IAC3E,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,GAAG,IAEJ,CAAC;IAC5B,OAAQ,QAAqC,CAAC,UAAU,CAAC;IAEzD,2FAA2F;IAC3F,uFAAuF;IACvF,0FAA0F;IAC1F,4DAA4D;IAC5D,MAAM,UAAU,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,CAAC;IAEvD,OAAO,CACL,cACE,OAAO,EAAC,WAAW,EACnB,IAAI,EAAC,MAAM,EACX,MAAM,EAAC,cAAc,EACrB,WAAW,EAAE,GAAG,EAChB,SAAS,EAAE,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,SAAS,CAAC,KAClD,CAAC,UAAU;YACb,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE;YAC3C,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC,KACrC,QAAQ,YAEX,QAAQ,GACL,CACP,CAAC;AACJ,CAAC"}
@@ -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 BASE_CLASS = `w-full rounded-x-md border border-border bg-surface-raised px-x-inline-sm py-x-stack-sm font-sans text-text-primary placeholder:text-text-muted ${CONTROL_CLASS}`;
6
+ const BASE_CLASS = `w-full rounded-x-slot-control border border-border bg-surface-raised px-x-slot-control-pad-x py-x-slot-control-pad-y font-sans text-x-slot-control-size text-text-primary placeholder:text-text-muted ${CONTROL_CLASS}`;
7
7
  /**
8
8
  * Text input primitive. forwardRef so it works directly with react-hook-form `register`.
9
9
  * Visual values come from theme tokens only.
@@ -1 +1 @@
1
- {"version":3,"file":"Input.js","sourceRoot":"","sources":["../../src/primitives/Input.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA4B,MAAM,OAAO,CAAC;AAC7D,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAI3D,MAAM,UAAU,GAAG,mJAAmJ,aAAa,EAAE,CAAC;AAEtL;;;GAGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAA+B,SAAS,KAAK,CAC1E,EACE,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,gBAAO,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,KAAM,MAAM,KAAM,IAAI,GAAI,CAAC;AACzF,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"Input.js","sourceRoot":"","sources":["../../src/primitives/Input.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA4B,MAAM,OAAO,CAAC;AAC7D,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAI3D,MAAM,UAAU,GAAG,yMAAyM,aAAa,EAAE,CAAC;AAE5O;;;GAGG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,UAAU,CAA+B,SAAS,KAAK,CAC1E,EACE,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,gBAAO,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,KAAM,MAAM,KAAM,IAAI,GAAI,CAAC;AACzF,CAAC,CAAC,CAAC"}
@@ -15,6 +15,6 @@ const DOT_CLASS = `border border-border accent-accent ${CONTROL_CLASS}`;
15
15
  * each option — putting them here would give every option the same id.
16
16
  */
17
17
  export const Radio = forwardRef(function Radio({ label, name, className, ...rest }, ref) {
18
- return (_jsxs("label", { className: "inline-flex items-center gap-x-2xs font-sans text-text-primary", children: [_jsx("input", { ref: ref, type: "radio", name: name, className: cx(DOT_CLASS, className), ...rest }), label] }));
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] }));
19
19
  });
20
20
  //# 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,gEAAgE,aAC/E,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,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"}
@@ -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 BASE_CLASS = `w-full rounded-x-md border border-border bg-surface-raised px-x-inline-sm py-x-stack-sm font-sans text-text-primary ${CONTROL_CLASS}`;
6
+ const BASE_CLASS = `w-full rounded-x-slot-control border border-border bg-surface-raised px-x-slot-control-pad-x py-x-slot-control-pad-y font-sans text-x-slot-control-size text-text-primary ${CONTROL_CLASS}`;
7
7
  /**
8
8
  * Select primitive. forwardRef so it works directly with react-hook-form `register`.
9
9
  * Visual values come from theme tokens only.
@@ -1 +1 @@
1
- {"version":3,"file":"Select.js","sourceRoot":"","sources":["../../src/primitives/Select.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA6C,MAAM,OAAO,CAAC;AAC9E,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAM3D,MAAM,UAAU,GAAG,uHAAuH,aAAa,EAAE,CAAC;AAE1J;;;GAGG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAAiC,SAAS,MAAM,CAC9E,EACE,QAAQ,EACR,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,iBAAQ,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,KAAM,MAAM,KAAM,IAAI,YACzE,QAAQ,GACF,CACV,CAAC;AACJ,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"Select.js","sourceRoot":"","sources":["../../src/primitives/Select.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA6C,MAAM,OAAO,CAAC;AAC9E,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAM3D,MAAM,UAAU,GAAG,6KAA6K,aAAa,EAAE,CAAC;AAEhN;;;GAGG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,UAAU,CAAiC,SAAS,MAAM,CAC9E,EACE,QAAQ,EACR,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,iBAAQ,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,KAAM,MAAM,KAAM,IAAI,YACzE,QAAQ,GACF,CACV,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-md border border-border px-x-2xs py-x-3xs 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,wFAAwF,EACxF,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"}
@@ -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 BASE_CLASS = `w-full rounded-x-md border border-border bg-surface-raised px-x-inline-sm py-x-stack-sm font-sans text-text-primary placeholder:text-text-muted ${CONTROL_CLASS}`;
6
+ const BASE_CLASS = `w-full rounded-x-slot-control border border-border bg-surface-raised px-x-slot-control-pad-x py-x-slot-control-pad-y font-sans text-x-slot-control-size text-text-primary placeholder:text-text-muted ${CONTROL_CLASS}`;
7
7
  /**
8
8
  * Multi-line text input. Deliberately identical to `Input` apart from the element, so the
9
9
  * two never drift: five ships wrote their own `Textarea.tsx` and the kit shipped without
@@ -1 +1 @@
1
- {"version":3,"file":"Textarea.js","sourceRoot":"","sources":["../../src/primitives/Textarea.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA+B,MAAM,OAAO,CAAC;AAChE,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAI3D,MAAM,UAAU,GAAG,mJAAmJ,aAAa,EAAE,CAAC;AAEtL;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAqC,SAAS,QAAQ,CACtF,EACE,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,mBAAU,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,KAAM,MAAM,KAAM,IAAI,GAAI,CAAC;AAC5F,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"Textarea.js","sourceRoot":"","sources":["../../src/primitives/Textarea.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,UAAU,EAA+B,MAAM,OAAO,CAAC;AAChE,OAAO,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAI3D,MAAM,UAAU,GAAG,yMAAyM,aAAa,EAAE,CAAC;AAE5O;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAqC,SAAS,QAAQ,CACtF,EACE,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,mBAAU,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,KAAM,MAAM,KAAM,IAAI,GAAI,CAAC;AAC5F,CAAC,CAAC,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-stack-lg 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,yCAAyC,EAAC,IAAI,EAAC,QAAQ,YACnE,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-stack-lg", role: "alert", children: [_jsx("p", { className: "font-sans text-danger", children: message }), _jsx("div", { className: "py-x-stack-sm", 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,eAAe,EAAC,IAAI,EAAC,OAAO,aACzC,YAAG,SAAS,EAAC,uBAAuB,YAAE,OAAO,GAAK,EAClD,cAAK,SAAS,EAAC,eAAe,YAC5B,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-stack-lg", "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,eAAe,eAAW,MAAM,YAC7C,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.2.0",
3
+ "version": "0.4.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",
@@ -21,6 +21,85 @@
21
21
 
22
22
  --shadow-sm: 0 1px 2px oklch(0% 0 0 / 0.06);
23
23
 
24
+ /* Typography. Until 0.3.0 the kit had none of these and the components carried
25
+ * `font-medium` and a colour choice inline — which is a design value living outside this
26
+ * file, the one thing the rule at the top forbids. It showed up the first time a product
27
+ * migrated: nene-vault's field labels went from small-and-muted to body-size-and-dark,
28
+ * silently, because the kit had no opening to say otherwise (found by hide on a real
29
+ * screen, 2026-08-23). The old value came from `.field-label`, regenerated during that
30
+ * product's design pass — so the migration overwrote a decision, not an accident.
31
+ *
32
+ * 🔴 Colour and size must not share a suffix. Tailwind resolves `text-<name>` against
33
+ * `--color-*` first, so defining `--color-x-label` and `--text-x-label` together makes the
34
+ * size unreachable while everything still compiles (verified against tailwindcss 4.3.2).
35
+ * Hence `-size`. Same family as the `gap-x-2` collision noted below. */
36
+
37
+ /* Form controls. `max(1rem, 16px)` rather than `1rem`: iOS Safari zooms the page when a
38
+ * focused input is under 16px, and a product whose body text is 14px would inherit that.
39
+ * Keeping a control readable is the control's job, not the product's. */
40
+
41
+ /* ─────────────────────────────────────────────────────────────────────────
42
+ * ② SLOTS — a product may redefine these.
43
+ *
44
+ * Every design value a component uses comes from here, and every slot's default points
45
+ * back at the scale above. That split is the whole idea: a product decides **which step
46
+ * a part uses**, and cannot invent a step. Change `--spacing-x-slot-card-pad` to
47
+ * `var(--spacing-x-lg)` and cards get roomier everywhere; you still cannot write `2.25`.
48
+ *
49
+ * Named per component rather than per role (hide's ruling, 2026-08-23): sharing one slot
50
+ * between `Modal` and `Card` can be arranged later by pointing both at the same value,
51
+ * but splitting a shared slot afterwards changes every product at once.
52
+ * ───────────────────────────────────────────────────────────────────────── */
53
+ --spacing-x-slot-button-pad-x: var(--spacing-x-sm);
54
+ --spacing-x-slot-button-pad-y: var(--spacing-x-xs);
55
+ --spacing-x-slot-button-sm-pad-x: var(--spacing-x-xs);
56
+ --spacing-x-slot-button-sm-pad-y: var(--spacing-x-3xs);
57
+ --spacing-x-slot-control-pad-x: var(--spacing-x-2xs);
58
+ --spacing-x-slot-control-pad-y: var(--spacing-x-xs);
59
+ --spacing-x-slot-field-gap: var(--spacing-x-2xs);
60
+ --spacing-x-slot-choice-gap: var(--spacing-x-2xs);
61
+ --spacing-x-slot-badge-pad-x: var(--spacing-x-2xs);
62
+ --spacing-x-slot-badge-pad-y: var(--spacing-x-3xs);
63
+ --spacing-x-slot-switch-pad-x: var(--spacing-x-2xs);
64
+ --spacing-x-slot-switch-pad-y: var(--spacing-x-3xs);
65
+ --spacing-x-slot-alert-pad: var(--spacing-x-2xs);
66
+ --spacing-x-slot-toast-pad: var(--spacing-x-2xs);
67
+ --spacing-x-slot-toast-gap: var(--spacing-x-2xs);
68
+ --spacing-x-slot-toast-dismiss-pad-x: var(--spacing-x-3xs);
69
+ --spacing-x-slot-modal-pad: var(--spacing-x-sm);
70
+ --spacing-x-slot-table-cell-pad-x: var(--spacing-x-2xs);
71
+ --spacing-x-slot-table-cell-pad-y: var(--spacing-x-3xs);
72
+ --spacing-x-slot-detail-gap: var(--spacing-x-xs);
73
+ --spacing-x-slot-detail-row-gap: var(--spacing-x-2xs);
74
+ --spacing-x-slot-detail-row-pad-y: var(--spacing-x-xs);
75
+ --spacing-x-slot-state-pad-y: var(--spacing-x-xl);
76
+ --spacing-x-slot-state-action-pad-y: var(--spacing-x-xs);
77
+ --spacing-x-slot-page-header-pad-y: var(--spacing-x-md);
78
+
79
+ --radius-x-slot-button: var(--radius-x-md);
80
+ --radius-x-slot-control: var(--radius-x-md);
81
+ --radius-x-slot-badge: var(--radius-x-md);
82
+ --radius-x-slot-switch: var(--radius-x-md);
83
+ --radius-x-slot-alert: var(--radius-x-md);
84
+ --radius-x-slot-toast: var(--radius-x-md);
85
+ --radius-x-slot-modal: var(--radius-x-md);
86
+ --radius-x-slot-card: var(--radius-x-md);
87
+
88
+ /* Pointer feedback. One rule for every variant, rather than a hover colour per fill:
89
+ * the kit's buttons are filled with three different colours, and a palette entry for each
90
+ * hover state would be three more values a product has to keep in step. Darkening works on
91
+ * all of them — including the white `secondary` fill, where the fleet's own
92
+ * `hover:brightness-105` does nothing at all.
93
+ *
94
+ * Tailwind wraps `hover:` in `@media (hover: hover)`, so this does not stick on touch. */
95
+ --brightness-x-slot-hover: 95%;
96
+ --brightness-x-slot-press: 90%;
97
+
98
+ --color-x-slot-field-label: var(--color-text-muted);
99
+ --text-x-slot-field-label-size: 0.75rem;
100
+ --font-weight-x-slot-field-label: 500;
101
+ --text-x-slot-control-size: max(1rem, 16px);
102
+
24
103
  /* Sentinel for the consumer's build (#316). Zero-width, so applying it does nothing.
25
104
  * Its only job is to exist: `p-x-source-probe` appears nowhere except this kit's `dist`,
26
105
  * so a build that generates it has the kit in its `@source`, and a build that does not