sherick-ui 2.7.1 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/dist/cjs/components/Accordion.cjs +1 -1
  2. package/dist/cjs/components/Accordion.cjs.map +1 -1
  3. package/dist/cjs/components/Alert.cjs +8 -4
  4. package/dist/cjs/components/Alert.cjs.map +1 -1
  5. package/dist/cjs/components/Badge.cjs +2 -2
  6. package/dist/cjs/components/Badge.cjs.map +1 -1
  7. package/dist/cjs/components/Breadcrumb.cjs +2 -2
  8. package/dist/cjs/components/Breadcrumb.cjs.map +1 -1
  9. package/dist/cjs/components/Calendar.cjs +1 -1
  10. package/dist/cjs/components/Calendar.cjs.map +1 -1
  11. package/dist/cjs/components/Card.cjs +10 -2
  12. package/dist/cjs/components/Card.cjs.map +1 -1
  13. package/dist/cjs/components/Checkbox.cjs +1 -1
  14. package/dist/cjs/components/Checkbox.cjs.map +1 -1
  15. package/dist/cjs/components/CheckboxGroup.cjs +2 -2
  16. package/dist/cjs/components/CheckboxGroup.cjs.map +1 -1
  17. package/dist/cjs/components/Chip.cjs +1 -1
  18. package/dist/cjs/components/Chip.cjs.map +1 -1
  19. package/dist/cjs/components/Collapsible.cjs +1 -1
  20. package/dist/cjs/components/Collapsible.cjs.map +1 -1
  21. package/dist/cjs/components/Combobox.cjs +4 -4
  22. package/dist/cjs/components/Combobox.cjs.map +1 -1
  23. package/dist/cjs/components/Command.cjs +2 -2
  24. package/dist/cjs/components/Command.cjs.map +1 -1
  25. package/dist/cjs/components/DateRangePicker.cjs +1 -1
  26. package/dist/cjs/components/DateRangePicker.cjs.map +1 -1
  27. package/dist/cjs/components/DateTimePicker.cjs +1 -1
  28. package/dist/cjs/components/DateTimePicker.cjs.map +1 -1
  29. package/dist/cjs/components/DialogContent.cjs +1 -1
  30. package/dist/cjs/components/DialogContent.cjs.map +1 -1
  31. package/dist/cjs/components/DialogDescription.cjs +1 -1
  32. package/dist/cjs/components/DialogDescription.cjs.map +1 -1
  33. package/dist/cjs/components/DialogSurface.cjs +1 -1
  34. package/dist/cjs/components/DialogSurface.cjs.map +1 -1
  35. package/dist/cjs/components/Drawer.cjs +6 -3
  36. package/dist/cjs/components/Drawer.cjs.map +1 -1
  37. package/dist/cjs/components/Field.cjs +1 -1
  38. package/dist/cjs/components/Field.cjs.map +1 -1
  39. package/dist/cjs/components/FileUpload.cjs +4 -4
  40. package/dist/cjs/components/FileUpload.cjs.map +1 -1
  41. package/dist/cjs/components/IconButton.cjs +5 -1
  42. package/dist/cjs/components/IconButton.cjs.map +1 -1
  43. package/dist/cjs/components/Input.cjs +2 -2
  44. package/dist/cjs/components/Input.cjs.map +1 -1
  45. package/dist/cjs/components/Menu.cjs +1 -1
  46. package/dist/cjs/components/Menu.cjs.map +1 -1
  47. package/dist/cjs/components/NavGroup.cjs +1 -1
  48. package/dist/cjs/components/NavGroup.cjs.map +1 -1
  49. package/dist/cjs/components/NavItem.cjs +1 -1
  50. package/dist/cjs/components/NavItem.cjs.map +1 -1
  51. package/dist/cjs/components/NumberField.cjs +2 -2
  52. package/dist/cjs/components/NumberField.cjs.map +1 -1
  53. package/dist/cjs/components/Pagination.cjs +5 -4
  54. package/dist/cjs/components/Pagination.cjs.map +1 -1
  55. package/dist/cjs/components/Popover.cjs +6 -0
  56. package/dist/cjs/components/Popover.cjs.map +1 -1
  57. package/dist/cjs/components/Progress.cjs +1 -1
  58. package/dist/cjs/components/Progress.cjs.map +1 -1
  59. package/dist/cjs/components/RadioGroup.cjs +1 -1
  60. package/dist/cjs/components/RadioGroup.cjs.map +1 -1
  61. package/dist/cjs/components/Search.cjs +1 -1
  62. package/dist/cjs/components/Search.cjs.map +1 -1
  63. package/dist/cjs/components/Select.cjs +2 -2
  64. package/dist/cjs/components/Select.cjs.map +1 -1
  65. package/dist/cjs/components/Slider.cjs +1 -1
  66. package/dist/cjs/components/Slider.cjs.map +1 -1
  67. package/dist/cjs/components/Spinner.cjs +2 -1
  68. package/dist/cjs/components/Spinner.cjs.map +1 -1
  69. package/dist/cjs/components/Stepper.cjs +7 -4
  70. package/dist/cjs/components/Stepper.cjs.map +1 -1
  71. package/dist/cjs/components/Table.cjs +1 -1
  72. package/dist/cjs/components/Table.cjs.map +1 -1
  73. package/dist/cjs/components/Textarea.cjs +2 -2
  74. package/dist/cjs/components/Textarea.cjs.map +1 -1
  75. package/dist/cjs/components/Toast.cjs +5 -5
  76. package/dist/cjs/components/Toast.cjs.map +1 -1
  77. package/dist/cjs/components/TreeView.cjs +1 -1
  78. package/dist/cjs/components/TreeView.cjs.map +1 -1
  79. package/dist/cjs/components/choice-row.cjs +1 -1
  80. package/dist/cjs/components/choice-row.cjs.map +1 -1
  81. package/dist/cjs/components/date-field.cjs +1 -1
  82. package/dist/cjs/components/date-field.cjs.map +1 -1
  83. package/dist/cjs/components/time-panel.cjs +1 -1
  84. package/dist/cjs/components/time-panel.cjs.map +1 -1
  85. package/dist/cjs/components/ui.common.cjs +131 -70
  86. package/dist/cjs/components/ui.common.cjs.map +1 -1
  87. package/dist/cjs/components/ui.motion.cjs +7 -2
  88. package/dist/cjs/components/ui.motion.cjs.map +1 -1
  89. package/dist/cjs/dev.cjs +4 -0
  90. package/dist/cjs/dev.cjs.map +1 -1
  91. package/dist/esm/components/Accordion.js +2 -2
  92. package/dist/esm/components/Accordion.js.map +1 -1
  93. package/dist/esm/components/Alert.js +10 -6
  94. package/dist/esm/components/Alert.js.map +1 -1
  95. package/dist/esm/components/Badge.js +3 -3
  96. package/dist/esm/components/Badge.js.map +1 -1
  97. package/dist/esm/components/Breadcrumb.js +3 -3
  98. package/dist/esm/components/Breadcrumb.js.map +1 -1
  99. package/dist/esm/components/Calendar.js +3 -3
  100. package/dist/esm/components/Calendar.js.map +1 -1
  101. package/dist/esm/components/Card.js +11 -3
  102. package/dist/esm/components/Card.js.map +1 -1
  103. package/dist/esm/components/Checkbox.js +2 -2
  104. package/dist/esm/components/Checkbox.js.map +1 -1
  105. package/dist/esm/components/CheckboxGroup.js +3 -3
  106. package/dist/esm/components/CheckboxGroup.js.map +1 -1
  107. package/dist/esm/components/Chip.js +2 -2
  108. package/dist/esm/components/Chip.js.map +1 -1
  109. package/dist/esm/components/CodeBlock.js +3 -3
  110. package/dist/esm/components/CodeBlock.js.map +1 -1
  111. package/dist/esm/components/Collapsible.js +2 -2
  112. package/dist/esm/components/Collapsible.js.map +1 -1
  113. package/dist/esm/components/Combobox.js +5 -5
  114. package/dist/esm/components/Combobox.js.map +1 -1
  115. package/dist/esm/components/Command.js +3 -3
  116. package/dist/esm/components/Command.js.map +1 -1
  117. package/dist/esm/components/DateRangePicker.js +2 -2
  118. package/dist/esm/components/DateRangePicker.js.map +1 -1
  119. package/dist/esm/components/DateTimePicker.js +2 -2
  120. package/dist/esm/components/DateTimePicker.js.map +1 -1
  121. package/dist/esm/components/DialogContent.js +2 -2
  122. package/dist/esm/components/DialogContent.js.map +1 -1
  123. package/dist/esm/components/DialogDescription.js +2 -2
  124. package/dist/esm/components/DialogDescription.js.map +1 -1
  125. package/dist/esm/components/DialogSurface.js +2 -2
  126. package/dist/esm/components/DialogSurface.js.map +1 -1
  127. package/dist/esm/components/Drawer.js +6 -3
  128. package/dist/esm/components/Drawer.js.map +1 -1
  129. package/dist/esm/components/Field.js +2 -2
  130. package/dist/esm/components/Field.js.map +1 -1
  131. package/dist/esm/components/FileUpload.js +5 -5
  132. package/dist/esm/components/FileUpload.js.map +1 -1
  133. package/dist/esm/components/IconButton.js +6 -2
  134. package/dist/esm/components/IconButton.js.map +1 -1
  135. package/dist/esm/components/Input.js +3 -3
  136. package/dist/esm/components/Input.js.map +1 -1
  137. package/dist/esm/components/Markdown.js +3 -3
  138. package/dist/esm/components/Markdown.js.map +1 -1
  139. package/dist/esm/components/Menu.js +1 -1
  140. package/dist/esm/components/Menu.js.map +1 -1
  141. package/dist/esm/components/NavGroup.js +2 -2
  142. package/dist/esm/components/NavGroup.js.map +1 -1
  143. package/dist/esm/components/NavItem.js +1 -1
  144. package/dist/esm/components/NavItem.js.map +1 -1
  145. package/dist/esm/components/NumberField.js +3 -3
  146. package/dist/esm/components/NumberField.js.map +1 -1
  147. package/dist/esm/components/Pagination.js +7 -6
  148. package/dist/esm/components/Pagination.js.map +1 -1
  149. package/dist/esm/components/Popover.js +7 -1
  150. package/dist/esm/components/Popover.js.map +1 -1
  151. package/dist/esm/components/Progress.js +2 -2
  152. package/dist/esm/components/Progress.js.map +1 -1
  153. package/dist/esm/components/RadioGroup.js +2 -2
  154. package/dist/esm/components/RadioGroup.js.map +1 -1
  155. package/dist/esm/components/Search.js +2 -2
  156. package/dist/esm/components/Search.js.map +1 -1
  157. package/dist/esm/components/Select.js +3 -3
  158. package/dist/esm/components/Select.js.map +1 -1
  159. package/dist/esm/components/Slider.js +2 -2
  160. package/dist/esm/components/Slider.js.map +1 -1
  161. package/dist/esm/components/Spinner.js +2 -1
  162. package/dist/esm/components/Spinner.js.map +1 -1
  163. package/dist/esm/components/Stepper.js +8 -5
  164. package/dist/esm/components/Stepper.js.map +1 -1
  165. package/dist/esm/components/Table.js +2 -2
  166. package/dist/esm/components/Table.js.map +1 -1
  167. package/dist/esm/components/Textarea.js +3 -3
  168. package/dist/esm/components/Textarea.js.map +1 -1
  169. package/dist/esm/components/Toast.js +6 -6
  170. package/dist/esm/components/Toast.js.map +1 -1
  171. package/dist/esm/components/TreeView.js +2 -2
  172. package/dist/esm/components/TreeView.js.map +1 -1
  173. package/dist/esm/components/choice-row.js +1 -1
  174. package/dist/esm/components/choice-row.js.map +1 -1
  175. package/dist/esm/components/date-field.js +2 -2
  176. package/dist/esm/components/date-field.js.map +1 -1
  177. package/dist/esm/components/time-panel.js +1 -1
  178. package/dist/esm/components/time-panel.js.map +1 -1
  179. package/dist/esm/components/ui.common.js +128 -71
  180. package/dist/esm/components/ui.common.js.map +1 -1
  181. package/dist/esm/components/ui.motion.js +7 -2
  182. package/dist/esm/components/ui.motion.js.map +1 -1
  183. package/dist/esm/dev.js +1 -1
  184. package/dist/styles.css +53 -67
  185. package/dist/theme.css +3 -0
  186. package/dist/types/dev.d.cts +33 -19
  187. package/dist/types/dev.d.ts +33 -19
  188. package/dist/types/index.d.cts +24 -2
  189. package/dist/types/index.d.ts +24 -2
  190. package/package.json +1 -1
@@ -11,16 +11,18 @@ var ui_motion = require('./ui.motion.cjs');
11
11
 
12
12
  material what a surface is made of (canvas, matte, control, acrylic)
13
13
  elevation how far it sits off the page (flat, raised, floating, control, recessed)
14
- shape its corner role (control, prominent, surface, expressive, pill, circle)
14
+ shape its corner role (mark, row, control, prominent, surface, sheet, expressive, pill, circle)
15
15
  edge the hairline between stacked parts (row, header, rule)
16
16
  state how it responds (rest, hover, pressed, selected, disabled, focus)
17
- stateLayer the composited hover/press overlay (quiet, tonal, filled, track, activeRow)
17
+ stateLayer the composited hover/press overlay (quiet, tonal, filled, track, mark, activeRow, fieldPart)
18
18
  disclosure one expandable region and its row (trigger, panel)
19
19
  tone its color role (text, soft, tonal, selected, strong)
20
20
  text the readable emphasis ladder (high, medium)
21
- density how tightly it is packed (compact, normal, prominent, target)
21
+ type the recurring kinds of copy (control, label, body, supporting, caption, title, heading, numeric)
22
+ density how tightly it is packed (compact, normal, prominent, target, part)
23
+ iconStroke the one rendered stroke of a glyph (glyph, mark)
22
24
  overlay floating shells (menu, tooltip, popup, toast, sheet, dialog)
23
- focusRing the one focus language (focusRing, focusRingInset, focusRingHeld, focusRingWithin, groupFocusRing)
25
+ focusRing the one focus language (focusRing, focusRingInset, focusRingHeld, focusRingWithin, groupFocusRing)
24
26
 
25
27
  Temporal behavior is deliberately not here: `ui.motion.ts` owns every transition,
26
28
  duration, curve and reduced-motion rule, and a recipe below names one of its recipes
@@ -127,8 +129,8 @@ const recessedTop = "shadow-sherick-recessed-top";
127
129
  an almost-button beside a real one. Nested roles stay concentric: an inner corner is the outer
128
130
  corner minus the inset between them (a 16px track around a 12px indicator at 4px, a 20px list
129
131
  sheet around 12px options at 8px).
130
- - control: ordinary controls and dense data regions — fields, rows, options,
131
- chips, tables.
132
+ - control: ordinary containers and dense data regions — fields, alerts, tables, segment
133
+ tracks and full-width option rows. Chips and badges are capsules (`pill`).
132
134
  - mark: a compact square selection mark — a 20px checkbox box. `control` is a role
133
135
  for objects the size of a field; its radius exceeds the half-extent of a
134
136
  20px square, so a mark needs a step of its own — a corner under a third of
@@ -177,27 +179,27 @@ const edgeTone = {
177
179
  header: "border-sherick-edge/[0.10]",
178
180
  rule: "border-sherick-edge/[0.075]",
179
181
  };
180
- /* Rim — the boundary of a *hollow* control: a text field, or an empty checkbox or radio. Nothing
181
- inside such a control says what it is — an empty field holds at most a placeholder, an empty mark
182
- holds nothing — and it still has to be identifiable at 3:1, which no neutral fill step and no
182
+ /* Rim — the boundary of a *hollow* control: the file drop target, or an empty checkbox or radio.
183
+ Nothing inside such a control says what it is — an empty mark holds nothing, a drop target only
184
+ an invitation — and it still has to be identifiable at 3:1, which no neutral fill step and no
183
185
  depth the light model can draw achieves on its own. So a hollow control carries one rim in the
184
186
  `rim` tone, tuned to clear 3:1 by a small margin and no more, and that rim is the only border a
185
187
  control has. A filled control — a button, a chip, a selected mark — is identified by its fill and
186
188
  never carries one.
187
- A text field's rim is its **baseline**: a line along the bottom edge only, which is the one part
188
- of a field's boundary WCAG needs to see at 3:1 — the line the text is written on. The other three
189
- sides are transparent, so the field reads as a quiet tray rather than a drawn box, and the
190
- field's `control` corner bends the baseline up into a soft lip at each end. The rim is a real
191
- border on all four sides: forced colors repaints even a transparent border in a system colour, so
192
- a field there keeps its whole outline, and the scoped baseline sizes boxes by their border edge,
193
- so the rim never changes a field's footprint. Its states ride on the field ladder in `state.field`.
189
+ A text field is not hollow: its label names it, and its value or placeholder and its parts — a
190
+ chevron, a calendar glyph, a stepper — show what it is and where it is, which is how WCAG 1.4.11
191
+ lets a control be identified without a 3:1 edge. Its tray says "something goes here", and its
192
+ states ride on the tray and the focus ring (`state.field`). `rim.field` is therefore no visible
193
+ line: it is a transparent border on all four sides, because forced colors repaints even a
194
+ transparent border in a system colour, so a field there keeps its whole outline where the tray is
195
+ discarded; the scoped baseline sizes boxes by their border edge, so it never changes a field's
196
+ footprint. An invalid field takes the same transparent border.
194
197
  A drop target's rim is dashed, and the dashes are a mask over an overlay rather than the native
195
198
  `dashed` style, whose dash length and corner joins the platform decides: the mask fixes the dash
196
199
  rhythm and follows the `control` corner exactly. The mask is authored in `tokens.ts`. */
197
200
  const dashedRimMask = "after:[mask-image:var(--sui-rim-dashed)] after:[mask-size:100%_100%] after:[mask-repeat:no-repeat]";
198
201
  const rim = {
199
- field: "border-[1.5px] border-transparent border-b-sherick-rim",
200
- fieldError: "border-[1.5px] border-transparent border-b-sherick-danger",
202
+ field: "border-[1.5px] border-transparent",
201
203
  dashed: /* @__PURE__ */ utils.cx("after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:content-['']", "after:bg-sherick-rim", dashedRimMask, ui_motion.motionRim),
202
204
  /* The dashes step up under the pointer and take the primary tone while a file is held over them. */
203
205
  dashedHover: "hover:after:bg-sherick-ink-muted",
@@ -252,34 +254,35 @@ const state = {
252
254
  text: "cursor-text",
253
255
  /* Quiet scan feedback for non-interactive data rows: tonality only. */
254
256
  rowHover: "hover:bg-sherick-ink/[0.05]",
255
- /* The matte field family — one tonality ladder, four triggers, no rims. A field
256
- steps its surface up once on hover and once more while it is engaged; a
257
- composite field focuses its outer surface while the input inside stays
258
- borderless; an expanded control holds the engaged step while its popup is
259
- open. Tonality carries the state, so no border appears and disappears. */
260
- /* A field is a tray: the `matteHigh` tone a groove holds, so it reads as a quiet recess in light
261
- and a quiet step up in dark, exactly as a segmented control's track does. Engaging it deepens
262
- the tray and steps its baseline up to `ink-muted`. An invalid field is the danger tray — the
263
- role's soft surface with a danger baseline — because a baseline alone is a thin signal to carry
264
- an error on; the tray, the danger placeholder and the field's message carry it together. The
265
- soft surface is laid at about half strength, so an error reads as a warm tray rather than a
266
- red block, and it holds still under the pointer: its colour is already what it has to say. */
257
+ /* The field family — one tray, one deeper step, no visible rims. Hover and engagement share the
258
+ deep step; a composite field engages its outer surface while the input inside stays borderless;
259
+ an expanded control holds the engaged step while its popup is open. Tonality and the focus ring
260
+ carry the state, so no border appears and disappears. */
261
+ /* A field is a tray in the `surface-high` tone, so it reads as a quiet recess in light and a
262
+ quiet step up in dark. It draws no line: its label and content identify it (see `rim`), so the
263
+ tray is laid at full strength to say "something goes here" on a card and on the page alike.
264
+ The pointer sinks it to the deep tray, and so does engagement — focus or an open popup — where
265
+ the focus ring is what says "this one is engaged"; an engaged field never falls back under the
266
+ pointer, because both states share the step. An invalid field is the danger tray — the role's
267
+ soft surface, at full strength like the neutral tray — and it holds still under the pointer:
268
+ its colour is already what it has to say, and the danger placeholder and the field's message
269
+ carry the error in words. */
267
270
  field: {
268
- hover: "hover:bg-sherick-surface-high/[0.82] hover:border-b-sherick-ink-muted",
269
- focus: "focus:bg-sherick-surface-high focus:border-b-sherick-ink-muted",
271
+ hover: "hover:bg-sherick-tray-deep",
272
+ focus: "focus:bg-sherick-tray-deep",
270
273
  /* A composite's engaged tone outranks hover, independent of variant emission order. */
271
- focusWithin: "[&&]:focus-within:bg-sherick-surface-high [&&]:focus-within:border-b-sherick-ink-muted",
272
- engaged: "bg-sherick-surface-high border-b-sherick-ink-muted",
273
- errorHover: "hover:bg-sherick-danger-soft/[0.55]",
274
- errorFocus: "focus:bg-sherick-danger-soft/[0.55]",
275
- errorEngaged: "bg-sherick-danger-soft/[0.55]",
274
+ focusWithin: "[&&]:focus-within:bg-sherick-tray-deep",
275
+ engaged: "bg-sherick-tray-deep",
276
+ errorHover: "hover:bg-sherick-danger-soft",
277
+ errorFocus: "focus:bg-sherick-danger-soft",
278
+ errorEngaged: "bg-sherick-danger-soft",
276
279
  /* The error ladder again, keyed on Base UI's validity attribute for a part that learns its
277
280
  validity from the field it sits in. Two variants outrank the single-variant ladder above,
278
281
  so neither ladder has to be conditional. */
279
- invalid: "data-[invalid]:bg-sherick-danger-soft/[0.55] data-[invalid]:border-b-sherick-danger",
280
- invalidHover: "data-[invalid]:hover:bg-sherick-danger-soft/[0.55] data-[invalid]:hover:border-b-sherick-danger",
281
- invalidEngaged: "data-[invalid]:bg-sherick-danger-soft/[0.55] data-[invalid]:border-b-sherick-danger",
282
- invalidFocusWithin: "[&&]:data-[invalid]:focus-within:bg-sherick-danger-soft/[0.55] [&&]:data-[invalid]:focus-within:border-b-sherick-danger",
282
+ invalid: "data-[invalid]:bg-sherick-danger-soft",
283
+ invalidHover: "data-[invalid]:hover:bg-sherick-danger-soft",
284
+ invalidEngaged: "data-[invalid]:bg-sherick-danger-soft",
285
+ invalidFocusWithin: "[&&]:data-[invalid]:focus-within:bg-sherick-danger-soft",
283
286
  },
284
287
  };
285
288
  /* State layers.
@@ -387,10 +390,9 @@ const hitArea = "relative after:pointer-events-auto after:absolute after:inset-[
387
390
  - matteHigh: the second matte step, for nesting inside another matte surface.
388
391
  - matteInset: a passive sheet tucked under a stronger control; subdued without
389
392
  blending into the canvas or needing a drawn rim.
390
- - control: the fill every text control shares, plus its placeholder tone. It is a tray in
391
- the `matteHigh` tone a groove holds, so a field and a track are one family. The
392
- tray says "something goes here"; its baseline, not its fill, is what carries the
393
- 3:1 boundary (see `rim`).
393
+ - control: the fill every text control shares, plus its placeholder tone: an opaque tray
394
+ in the `surface-high` tone. The tray says "something goes here"; the field's
395
+ label and content, not a drawn edge, are what identify it (see `rim`).
394
396
  - handle: the fill of a small part the user has to find — a value control's handle.
395
397
  Surface steps sit within a few percent of their neighbours, so this role
396
398
  takes the mid-emphasis tone, which inverts with the theme and separates in
@@ -423,15 +425,15 @@ const material = {
423
425
  matteQuiet: "bg-sherick-surface/[0.42] text-sherick-ink",
424
426
  matte: "bg-sherick-surface/[0.78] text-sherick-ink",
425
427
  matteHigh: "bg-sherick-surface-high/[0.72] text-sherick-ink",
426
- control: "bg-sherick-surface-high/[0.6] text-sherick-ink placeholder:text-sherick-ink-muted",
428
+ control: "bg-sherick-surface-high text-sherick-ink placeholder:text-sherick-ink-muted",
427
429
  /* The invalid fill carries its placeholder at the *full* danger tone, not at a fraction of it. A
428
430
  placeholder is text, so it answers to the same 4.5:1 the copy beside it does, and a partial
429
431
  opacity of an accent is a different colour from the accent: the 72%-opacity placeholder
430
- measured 2.8–3.0:1 light and 3.4–3.9:1 dark on this fill, while the token it was mixed from
432
+ measured 2.8–3.0:1 light and 3.4–3.9:1 dark on the half-strength danger tray, while the token it was mixed from
431
433
  measures 4.1–4.7:1 light and 5.2–6.2:1 dark on it. There is no dimmer step of a semantic tone
432
434
  that is still readable, and a normal field's placeholder is `ink-muted` at full strength
433
435
  already — so the error form is the same rule, in the tone the field is in. */
434
- controlError: "bg-sherick-danger-soft/[0.55] text-sherick-ink placeholder:text-sherick-danger",
436
+ controlError: "bg-sherick-danger-soft text-sherick-ink placeholder:text-sherick-danger",
435
437
  handle: "bg-sherick-ink-muted text-sherick-canvas",
436
438
  acrylic: "bg-sherick-surface-float/[var(--sui-glass-fill)] bg-[image:var(--sui-glass-gradient)] text-sherick-ink backdrop-blur-[var(--sui-glass-blur)] backdrop-saturate-[var(--sui-glass-saturation)] backdrop-brightness-[var(--sui-glass-brightness)]",
437
439
  acrylicDense: "bg-sherick-surface-float/[var(--sui-glass-dense-fill)] bg-[image:var(--sui-glass-gradient-dense)] text-sherick-ink backdrop-blur-[var(--sui-glass-dense-blur)] backdrop-saturate-[var(--sui-glass-dense-saturation)] backdrop-brightness-[var(--sui-glass-dense-brightness)]",
@@ -445,9 +447,17 @@ const matteInset = "bg-sherick-surface-high/[0.35] text-sherick-ink";
445
447
  where the role owns it, one weight. A component still owns copy that only it renders; these are
446
448
  the roles that recur across families and have to agree wherever they appear:
447
449
  - control: the type step of a control, owned through `density` below.
450
+ - label: the name above a control — a field's label, a progress label, a column header. It is
451
+ the medium weight of the compact step, so a label leads the value beneath it without
452
+ being as large as it.
453
+ - body: a sentence or a paragraph set inside a component — an alert, a toast's description, a
454
+ dialog's description and content, an open disclosure panel. Long-form Markdown keeps
455
+ its own reading rhythm; this is the rhythm of copy *in* an interface.
448
456
  - supporting: a field's description, hint and error, and the secondary line under a row's label.
449
457
  - caption: compact labels — a badge, a tooltip, a group label, a calendar weekday.
450
- - title: the heading of a compact surface — a popover, a toast, a command palette.
458
+ - title: the heading of a compact surface — a card, a popover, a toast, a command palette. It
459
+ is one step above the 15px control text it usually sits over, so a heading reads as a
460
+ heading by size and not by weight alone.
451
461
  - heading: the title of a surface that owns the viewport — a dialog, an alert dialog, a drawer.
452
462
  - numeric: figures that are compared down a column or updated in place.
453
463
  Every size lands on a whole-pixel line box, so stacked rows keep one rhythm. */
@@ -457,9 +467,11 @@ const type = {
457
467
  normal: "text-[0.9375rem] leading-[1.375rem]",
458
468
  prominent: "text-lg",
459
469
  },
470
+ label: "text-sm leading-5 font-medium",
471
+ body: "text-sm leading-6",
460
472
  supporting: "text-[0.8125rem] leading-5",
461
473
  caption: "text-xs leading-4",
462
- title: "text-[0.9375rem] leading-[1.375rem] font-semibold tracking-[-0.011em]",
474
+ title: "text-base leading-6 font-semibold tracking-[-0.011em]",
463
475
  heading: "text-xl leading-7 font-semibold tracking-[-0.02em]",
464
476
  numeric: "tabular-nums",
465
477
  };
@@ -498,6 +510,19 @@ const iconSlot = {
498
510
  normal: "inline-flex size-5 shrink-0 items-center justify-center [&>svg]:size-5",
499
511
  prominent: "inline-flex size-6 shrink-0 items-center justify-center [&>svg]:size-6",
500
512
  };
513
+ /* Icon stroke — the one rendered weight of a library glyph. The artwork is drawn on a 24-unit grid,
514
+ so a stroke written in the artwork's own units renders thinner at 16px and thicker at 24px: the
515
+ same set read 1.0px in a dismiss and 1.75px in a tick. A glyph the library draws holds its stroke
516
+ in screen pixels instead, so a 14px chevron and a 20px close mark have one weight, close to the
517
+ stem of the medium label beside them. A selection mark — the tick or minus inside a filled
518
+ checkbox — is the one deliberately heavier glyph: it sits on the strong accent and has to read as
519
+ the mark itself, not as a hairline drawn on it.
520
+ Apply it to the `svg` a component renders. It is not applied to artwork a consumer hands into a
521
+ slot: that artwork's weight is the consumer's choice. */
522
+ const iconStroke = {
523
+ glyph: "[&_*]:[vector-effect:non-scaling-stroke] [&_*]:[stroke-width:1.5px]",
524
+ mark: "[&_*]:[vector-effect:non-scaling-stroke] [&_*]:[stroke-width:1.75px]",
525
+ };
501
526
  /* Stacking level — where anything that floats sits relative to the application.
502
527
 
503
528
  One interaction level, deliberately. Base UI nests a popup's portal *inside* the portal of the surface it
@@ -613,14 +638,17 @@ const list = {
613
638
  both, a selected row keeps its selection tint under the ring, and a disabled-but-navigable
614
639
  row still shows where the navigation is while saying it cannot be used. The ring is inset
615
640
  because the row lives inside the sheet it belongs to, as a segment does in its track. */
616
- option: /* @__PURE__ */ utils.cx("flex w-full items-center justify-between gap-4 px-4 py-3 text-start outline-none", type.control.normal, shape.control, ui_motion.motionFeedback, focusRingInset, text.high, stateLayer.quiet, stateLayer.activeRow, ui_motion.motionRowLayer, state.effectiveDisabled),
641
+ /* The option's start inset is the field's: a sheet's 8px inset plus the row's 12px puts every
642
+ option label on the same 20px edge as the value in the trigger that opened it, so the list
643
+ reads as the field opening rather than a second surface beside it. */
644
+ option: /* @__PURE__ */ utils.cx("flex w-full items-center justify-between gap-4 px-3 py-3 text-start outline-none", type.control.normal, shape.control, ui_motion.motionFeedback, focusRingInset, text.high, stateLayer.quiet, stateLayer.activeRow, ui_motion.motionRowLayer, state.effectiveDisabled),
617
645
  /* The heading of a group of options — a category above the channels filed under it. It is a
618
646
  caption, not a row: it takes no state layer, no highlight and no focus, because the reader never
619
647
  lands on it; the primitive names the group from it, so a screen reader hears the category as it
620
648
  enters the group. Its inline padding is the option's, so a heading and the labels beneath it
621
649
  share one start edge, and the space above it is what separates one group from the last: a
622
650
  group inside a sheet is grouped by spacing and a type role, never by a rule or a nested card. */
623
- groupLabel: /* @__PURE__ */ utils.cx("px-4 pb-1 pt-3 font-medium", type.caption, text.medium),
651
+ groupLabel: /* @__PURE__ */ utils.cx("px-3 pb-1 pt-3 font-medium", type.caption, text.medium),
624
652
  /* The same object at the density a list of short actions wants, where the row is scanned
625
653
  rather than read and the list is a control rather than a page. `shape.row` keeps the
626
654
  command's corner proportional to its own height, so its highlight nests in the tighter
@@ -634,13 +662,15 @@ const list = {
634
662
  component maps its own primitive's panel variable onto, because the measured geometry is
635
663
  anatomy and only the interpolation is temporal. */
636
664
  const disclosure = {
637
- /* The row: a full-width row in a stacked group, activated like a selectable row. Its own focus
665
+ /* The row: a full-width row in a stacked group, activated like a selectable row. It is an option
666
+ row at the 16px inset of the surface it usually sits on directly — no sheet inset precedes it —
667
+ so its label shares an edge with the panel copy beneath it. Its own focus
638
668
  indicator is the shared inset ring, because an offset one drawn outside the row would land on
639
669
  the divider or the panel beside it rather than around the row it belongs to — which is the same
640
670
  reason a segment inside a track takes the inset form. The chevron the component puts in the
641
671
  row is the disclosure's own affordance and turns in place under `motionOrient`. */
642
- trigger: /* @__PURE__ */ utils.cx("group [overflow-wrap:anywhere]", list.option, state.enabled),
643
- panel: /* @__PURE__ */ utils.cx("h-[var(--sui-disclose-height)] overflow-hidden text-sm leading-7 [overflow-wrap:anywhere]", text.medium, ui_motion.motionDisclose),
672
+ trigger: /* @__PURE__ */ utils.cx("group flex w-full items-center justify-between gap-4 px-4 py-3 text-start outline-none [overflow-wrap:anywhere]", type.control.normal, shape.control, ui_motion.motionFeedback, focusRingInset, text.high, stateLayer.quiet, stateLayer.activeRow, ui_motion.motionRowLayer, state.effectiveDisabled, state.enabled),
673
+ panel: /* @__PURE__ */ utils.cx("h-[var(--sui-disclose-height)] overflow-hidden [overflow-wrap:anywhere]", type.body, text.medium, ui_motion.motionDisclose),
644
674
  };
645
675
  /* Tone hierarchy — the color roles a surface can take, in rising strength:
646
676
  text foreground only, for quiet rows and links.
@@ -703,11 +733,17 @@ const tone = {
703
733
  success: "group-data-[checked]:bg-sherick-success group-data-[checked]:text-sherick-on-success",
704
734
  },
705
735
  };
706
- /* Current location — where the reader is, as opposed to a value they chose. A navigation row, the
707
- current page of a pagination and any other `aria-current` destination hold the role's soft
708
- container, full ink and a touch of weight, and stay flat: depth and the stronger selected step
709
- belong to held values (`tone.selected` with `elevation.control`). */
710
- const currentDestination = "bg-sherick-primary-soft text-sherick-ink font-medium";
736
+ /* Current location — where the reader is, as opposed to a value they chose. Both forms stay flat:
737
+ depth belongs to held values (`tone.selected` with `elevation.control`).
738
+ - row: a navigation row on a sheet — the role's soft container, full ink and a touch of weight.
739
+ - inTrack: a destination inside a recessed track, or the mark of a track's current stage — a
740
+ pagination's current page, a Stepper's current step. The soft step is the groove's own
741
+ lightness (1.00:1 in light), so there the fill steps up to `selected` and the label
742
+ takes the accent: the label, not the fill, says "you are here". */
743
+ const currentDestination = {
744
+ row: "bg-sherick-primary-soft text-sherick-ink font-medium",
745
+ inTrack: "bg-sherick-primary-selected text-sherick-primary font-semibold",
746
+ };
711
747
  /* Selectable surface — the recessed surface of a control that fills once it is selected: a
712
748
  switch track, a checkbox box, a radio circle, a slider groove. Selection is keyed on the
713
749
  primitive's own `data-checked` / `data-indeterminate`, so an uncontrolled control is styled
@@ -723,12 +759,18 @@ const currentDestination = "bg-sherick-primary-soft text-sherick-ink font-medium
723
759
  an option, a tree row, a date — keeps `tone.selected`, because a list sheet is already the
724
760
  brightest surface and a white row on it would vanish. */
725
761
  const puck = "bg-sherick-puck";
726
- /* A choice row that holds the selection — an opt-in `surface` row in a RadioGroup or CheckboxGroup —
727
- takes the role's *soft* surface and stays flat. The row is a large surface and its mark already
728
- carries the strong accent edge to edge, so the row only has to say "this one" quietly: the
729
- selected step and a lift turned a whole card into an accent block, which outshouted the
730
- priority action on the same view. */
731
- const selectableRowSurface = "has-[[data-checked]]:bg-sherick-primary-soft has-[[data-checked]]:text-sherick-ink";
762
+ /* A choice row — an opt-in `surface` row in a RadioGroup or CheckboxGroup — rests on the
763
+ `matteHigh` tray, so every choice in the group reads as a target before any is chosen; it stays
764
+ light enough that the empty mark's rim still clears 3:1 against it. The row that holds the
765
+ selection takes the role's *soft* surface and the accent **selection rim**, and stays flat. The
766
+ soft surface is lighter than the resting tray, so the tint alone would make the chosen row the
767
+ quieter of the two; the rim is what says "this one". It is the row's selection mark, not an
768
+ outline drawn to separate a surface, and it belongs to the selected state only. Like an empty
769
+ mark's rim it is an overlay rather than a border, so the fill and the hover layer reach the row's
770
+ real edge, and it is transparent rather than absent at rest, so forced colors keeps every row's
771
+ outline. The selected step and a lift turned a whole card into an accent block, which outshouted
772
+ the priority action on the same view. */
773
+ const selectableRowSurface = /* @__PURE__ */ utils.cx("has-[[data-checked]]:bg-sherick-primary-soft has-[[data-checked]]:text-sherick-ink", "after:pointer-events-none after:absolute after:inset-0 after:box-border after:rounded-[inherit] after:border-[1.5px] after:border-transparent after:content-['']", "has-[[data-checked]]:after:border-sherick-primary", ui_motion.motionRim);
732
774
  /* Supporting copy inside such a row — a choice's description. `text.medium` clears 4.5:1 on the
733
775
  soft step at rest (5.7:1 light, 6.2:1 dark), but the row's press layer composites toward the label
734
776
  and takes that margin away, so while the row holds the selection its supporting line takes full
@@ -790,8 +832,11 @@ const toneAlpha = (tone) => (recipe, label) => {
790
832
  throw new Error(`recipe alpha missing for ${label}`);
791
833
  return match[1] === undefined ? 1 : Number(match[1]);
792
834
  };
793
- /* A field tray's `surface-high` step, and the canvas step an empty mark's interior holds. */
835
+ /* A field tray's `surface-high` step, its deep step, its danger step, and the canvas step an empty
836
+ mark's interior holds. */
794
837
  const trayAlpha = toneAlpha("surface-high");
838
+ const deepTrayAlpha = toneAlpha("tray-deep");
839
+ const dangerTrayAlpha = toneAlpha("danger-soft");
795
840
  const markAlpha = toneAlpha("canvas");
796
841
  const recipeAlphas = {
797
842
  state: {
@@ -810,10 +855,10 @@ const recipeAlphas = {
810
855
  card: fillAlpha(material.matte, "field.card"),
811
856
  groove: fillAlpha(material.matteHigh, "field.groove"),
812
857
  control: trayAlpha(material.control, "field.control"),
813
- hover: trayAlpha(state.field.hover, "field.hover"),
814
- engaged: trayAlpha(state.field.engaged, "field.engaged"),
858
+ hover: deepTrayAlpha(state.field.hover, "field.hover"),
859
+ engaged: deepTrayAlpha(state.field.engaged, "field.engaged"),
815
860
  mark: markAlpha(markWellFill, "field.mark"),
816
- error: fillAlpha(material.controlError, "field.error"),
861
+ error: dangerTrayAlpha(material.controlError, "field.error"),
817
862
  },
818
863
  };
819
864
  /* A labelled field is a shrinkable column. Its explanatory copy wraps, including identifiers;
@@ -821,11 +866,24 @@ const recipeAlphas = {
821
866
  const fieldLayout = "flex min-w-0 w-full flex-col [overflow-wrap:anywhere]";
822
867
  /* The messages under a field: its description or hint, and its error. One role for every field in
823
868
  the family, so a hint reads the same under a text field, a date range and a file chooser. */
869
+ /* The label above a field: the `label` role at full ink, with the one gap every field family keeps
870
+ between its name and its control. */
871
+ const fieldLabel = /* @__PURE__ */ utils.cx("mb-2", type.label, text.high);
824
872
  const fieldMessage = {
825
873
  description: /* @__PURE__ */ utils.cx("mt-2", type.supporting, text.medium),
826
874
  error: /* @__PURE__ */ utils.cx("mt-2", type.supporting, tone.text.danger),
827
875
  };
876
+ /* The code well — the quiet recess a code block's lines sit in. It is the canvas showing through the
877
+ block's own matte shell, so a well reads as sunk into the block on a card and on the page alike. */
878
+ const codeWell = "bg-sherick-canvas/[0.28]";
879
+ /* Rich-text accents — content-level emphasis in rendered prose, not structural edges: a quote's rule
880
+ on its start edge, and a link's underline at rest and under the pointer. */
881
+ const richText = {
882
+ quoteRule: "border-sherick-primary/[0.45]",
883
+ linkUnderline: "decoration-sherick-primary/[0.35] hover:decoration-sherick-primary",
884
+ };
828
885
 
886
+ exports.codeWell = codeWell;
829
887
  exports.currentDestination = currentDestination;
830
888
  exports.density = density;
831
889
  exports.detail = detail;
@@ -833,6 +891,7 @@ exports.disclosure = disclosure;
833
891
  exports.edge = edge;
834
892
  exports.edgeTone = edgeTone;
835
893
  exports.elevation = elevation;
894
+ exports.fieldLabel = fieldLabel;
836
895
  exports.fieldLayout = fieldLayout;
837
896
  exports.fieldMessage = fieldMessage;
838
897
  exports.focusRing = focusRing;
@@ -843,6 +902,7 @@ exports.focusRingWithin = focusRingWithin;
843
902
  exports.groupFocusRing = groupFocusRing;
844
903
  exports.hitArea = hitArea;
845
904
  exports.iconSlot = iconSlot;
905
+ exports.iconStroke = iconStroke;
846
906
  exports.list = list;
847
907
  exports.material = material;
848
908
  exports.matteInset = matteInset;
@@ -852,6 +912,7 @@ exports.parentFocusRingInset = parentFocusRingInset;
852
912
  exports.puck = puck;
853
913
  exports.recessedTop = recessedTop;
854
914
  exports.recipeAlphas = recipeAlphas;
915
+ exports.richText = richText;
855
916
  exports.rim = rim;
856
917
  exports.selectable = selectable;
857
918
  exports.selectableRowSupporting = selectableRowSupporting;