sherick-ui 2.5.0 → 2.7.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 (75) hide show
  1. package/README.md +57 -3
  2. package/dist/cjs/components/CheckboxGroup.cjs +41 -0
  3. package/dist/cjs/components/CheckboxGroup.cjs.map +1 -0
  4. package/dist/cjs/components/Combobox.cjs +190 -14
  5. package/dist/cjs/components/Combobox.cjs.map +1 -1
  6. package/dist/cjs/components/Form.cjs +27 -0
  7. package/dist/cjs/components/Form.cjs.map +1 -0
  8. package/dist/cjs/components/Input.cjs +20 -2
  9. package/dist/cjs/components/Input.cjs.map +1 -1
  10. package/dist/cjs/components/NumberField.cjs +30 -4
  11. package/dist/cjs/components/NumberField.cjs.map +1 -1
  12. package/dist/cjs/components/RadioGroup.cjs +7 -3
  13. package/dist/cjs/components/RadioGroup.cjs.map +1 -1
  14. package/dist/cjs/components/Search.cjs +1 -1
  15. package/dist/cjs/components/Search.cjs.map +1 -1
  16. package/dist/cjs/components/Select.cjs +4 -2
  17. package/dist/cjs/components/Select.cjs.map +1 -1
  18. package/dist/cjs/components/Tabs.cjs +1 -1
  19. package/dist/cjs/components/Tabs.cjs.map +1 -1
  20. package/dist/cjs/components/Textarea.cjs +6 -1
  21. package/dist/cjs/components/Textarea.cjs.map +1 -1
  22. package/dist/cjs/components/ToggleGroup.cjs +1 -1
  23. package/dist/cjs/components/ToggleGroup.cjs.map +1 -1
  24. package/dist/cjs/components/choice-row.cjs +51 -0
  25. package/dist/cjs/components/choice-row.cjs.map +1 -0
  26. package/dist/cjs/components/date-field.cjs +3 -3
  27. package/dist/cjs/components/date-field.cjs.map +1 -1
  28. package/dist/cjs/components/option-groups.cjs +35 -0
  29. package/dist/cjs/components/option-groups.cjs.map +1 -0
  30. package/dist/cjs/components/ui.common.cjs +100 -50
  31. package/dist/cjs/components/ui.common.cjs.map +1 -1
  32. package/dist/cjs/dev.cjs +2 -0
  33. package/dist/cjs/dev.cjs.map +1 -1
  34. package/dist/cjs/index.cjs +4 -0
  35. package/dist/cjs/index.cjs.map +1 -1
  36. package/dist/esm/components/CheckboxGroup.js +36 -0
  37. package/dist/esm/components/CheckboxGroup.js.map +1 -0
  38. package/dist/esm/components/Combobox.js +195 -19
  39. package/dist/esm/components/Combobox.js.map +1 -1
  40. package/dist/esm/components/Form.js +22 -0
  41. package/dist/esm/components/Form.js.map +1 -0
  42. package/dist/esm/components/Input.js +21 -3
  43. package/dist/esm/components/Input.js.map +1 -1
  44. package/dist/esm/components/NumberField.js +31 -5
  45. package/dist/esm/components/NumberField.js.map +1 -1
  46. package/dist/esm/components/RadioGroup.js +10 -6
  47. package/dist/esm/components/RadioGroup.js.map +1 -1
  48. package/dist/esm/components/Search.js +1 -1
  49. package/dist/esm/components/Search.js.map +1 -1
  50. package/dist/esm/components/Select.js +6 -4
  51. package/dist/esm/components/Select.js.map +1 -1
  52. package/dist/esm/components/Tabs.js +2 -2
  53. package/dist/esm/components/Tabs.js.map +1 -1
  54. package/dist/esm/components/Textarea.js +6 -1
  55. package/dist/esm/components/Textarea.js.map +1 -1
  56. package/dist/esm/components/ToggleGroup.js +2 -2
  57. package/dist/esm/components/ToggleGroup.js.map +1 -1
  58. package/dist/esm/components/choice-row.js +46 -0
  59. package/dist/esm/components/choice-row.js.map +1 -0
  60. package/dist/esm/components/date-field.js +3 -3
  61. package/dist/esm/components/date-field.js.map +1 -1
  62. package/dist/esm/components/option-groups.js +30 -0
  63. package/dist/esm/components/option-groups.js.map +1 -0
  64. package/dist/esm/components/ui.common.js +100 -52
  65. package/dist/esm/components/ui.common.js.map +1 -1
  66. package/dist/esm/dev.js +1 -1
  67. package/dist/esm/index.js +2 -0
  68. package/dist/esm/index.js.map +1 -1
  69. package/dist/styles.css +271 -205
  70. package/dist/theme.css +160 -157
  71. package/dist/types/dev.d.cts +31 -25
  72. package/dist/types/dev.d.ts +31 -25
  73. package/dist/types/index.d.cts +184 -20
  74. package/dist/types/index.d.ts +184 -20
  75. package/package.json +2 -2
@@ -123,10 +123,10 @@ const recessedTop = "shadow-sherick-recessed-top";
123
123
  the size of the object and the emphasis it carries, and silhouette says what an object does:
124
124
  a **capsule acts** (buttons, chips, badges, toggles are `pill`) and a **rounded rectangle
125
125
  holds** (fields, alerts, tables, sheets). Container roles therefore stay clearly short of a
126
- capsule at their own height — `control` is a third of a 48px field — so a field never reads as
126
+ capsule at their own height — `control` is a quarter of a 48px field — so a field never reads as
127
127
  an almost-button beside a real one. Nested roles stay concentric: an inner corner is the outer
128
- corner minus the inset between them (a 20px track around a 16px indicator at 4px, a 24px list
129
- sheet around 16px options at 8px).
128
+ corner minus the inset between them (a 16px track around a 12px indicator at 4px, a 20px list
129
+ sheet around 12px options at 8px).
130
130
  - control: ordinary controls and dense data regions — fields, rows, options,
131
131
  chips, tables.
132
132
  - mark: a compact square selection mark — a 20px checkbox box. `control` is a role
@@ -149,13 +149,13 @@ const recessedTop = "shadow-sherick-recessed-top";
149
149
  - pill: fully rounded controls whose width follows their content.
150
150
  - circle: fully rounded square targets. */
151
151
  const shape = {
152
- control: "rounded-[1rem]",
152
+ control: "rounded-[0.75rem]",
153
153
  mark: "rounded-[0.375rem]",
154
- row: "rounded-[0.75rem]",
155
- prominent: "rounded-[1.25rem]",
156
- surface: "rounded-[1.5rem]",
157
- sheet: "rounded-[1rem]",
158
- expressive: "rounded-[1.75rem]",
154
+ row: "rounded-[0.5rem]",
155
+ prominent: "rounded-[1rem]",
156
+ surface: "rounded-[1.25rem]",
157
+ sheet: "rounded-[0.75rem]",
158
+ expressive: "rounded-[1.5rem]",
159
159
  pill: "rounded-full",
160
160
  circle: "rounded-full",
161
161
  };
@@ -181,19 +181,23 @@ const edgeTone = {
181
181
  inside such a control says what it is — an empty field holds at most a placeholder, an empty mark
182
182
  holds nothing — and it still has to be identifiable at 3:1, which no neutral fill step and no
183
183
  depth the light model can draw achieves on its own. So a hollow control carries one rim in the
184
- `rim` tone, tuned to clear 3:1 on every surface by a small margin and no more, and that rim is
185
- the only border a control has. A filled control — a button, a chip, a selected mark — is identified by its fill and
184
+ `rim` tone, tuned to clear 3:1 by a small margin and no more, and that rim is the only border a
185
+ control has. A filled control — a button, a chip, a selected mark — is identified by its fill and
186
186
  never carries one.
187
- The field rim is a real border: forced colors repaints a border in a system colour, where it
188
- would remove an inset shadow, and the scoped baseline sizes boxes by their border edge, so the
189
- rim never changes a field's footprint. Its states ride on the field ladder in `state.field`.
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`.
190
194
  A drop target's rim is dashed, and the dashes are a mask over an overlay rather than the native
191
195
  `dashed` style, whose dash length and corner joins the platform decides: the mask fixes the dash
192
196
  rhythm and follows the `control` corner exactly. The mask is authored in `tokens.ts`. */
193
197
  const dashedRimMask = "after:[mask-image:var(--sui-rim-dashed)] after:[mask-size:100%_100%] after:[mask-repeat:no-repeat]";
194
198
  const rim = {
195
- field: "border-[1.5px] border-sherick-rim",
196
- fieldError: "border-[1.5px] border-sherick-danger",
199
+ field: "border-[1.5px] border-transparent border-b-sherick-rim",
200
+ fieldError: "border-[1.5px] border-transparent border-b-sherick-danger",
197
201
  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),
198
202
  /* The dashes step up under the pointer and take the primary tone while a file is held over them. */
199
203
  dashedHover: "hover:after:bg-sherick-ink-muted",
@@ -253,26 +257,29 @@ const state = {
253
257
  composite field focuses its outer surface while the input inside stays
254
258
  borderless; an expanded control holds the engaged step while its popup is
255
259
  open. Tonality carries the state, so no border appears and disappears. */
256
- /* A field is a well: its fill sits below the surface around it, and engaging it sinks it further
257
- while its rim steps up. An invalid field is the same well with a danger rim: the rim, the
258
- danger placeholder and the field's message carry the error, so the fill never trades its
259
- depth for a tinted wash. The error steps keep the well's depth ladder and leave the rim alone. */
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. */
260
267
  field: {
261
- hover: "hover:bg-sherick-canvas/[0.85] hover:border-sherick-ink-muted",
262
- focus: "focus:bg-sherick-canvas focus:border-sherick-ink-muted",
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",
263
270
  /* A composite's engaged tone outranks hover, independent of variant emission order. */
264
- focusWithin: "[&&]:focus-within:bg-sherick-canvas [&&]:focus-within:border-sherick-ink-muted",
265
- engaged: "bg-sherick-canvas border-sherick-ink-muted",
266
- errorHover: "hover:bg-sherick-canvas/[0.85]",
267
- errorFocus: "focus:bg-sherick-canvas",
268
- errorEngaged: "bg-sherick-canvas",
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]",
269
276
  /* The error ladder again, keyed on Base UI's validity attribute for a part that learns its
270
277
  validity from the field it sits in. Two variants outrank the single-variant ladder above,
271
278
  so neither ladder has to be conditional. */
272
- invalid: "data-[invalid]:border-sherick-danger",
273
- invalidHover: "data-[invalid]:hover:border-sherick-danger",
274
- invalidEngaged: "data-[invalid]:border-sherick-danger",
275
- invalidFocusWithin: "[&&]:data-[invalid]:focus-within:border-sherick-danger",
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",
276
283
  },
277
284
  };
278
285
  /* State layers.
@@ -356,6 +363,13 @@ const stateLayer = {
356
363
  keyboard so it can be discovered and announced as unavailable, and a reader still has to see
357
364
  which row the navigation is on when it lands there. */
358
365
  activeRow: "data-[highlighted]:before:opacity-[0.05]",
366
+ /* A control that is one part of a field — a combobox's clear and trigger, a number field's
367
+ steppers, a search field's submit, a date field's calendar glyph. Its target keeps the height
368
+ the field's row needs, but its surface does not: a hover layer that filled a 44px target painted
369
+ a column the full height of a 48px field. The layer is a 32px circle centred in whatever target
370
+ the part has, which leaves the field's own air above and below it and keeps every part in every
371
+ field the same size under the pointer. */
372
+ fieldPart: /* @__PURE__ */ utils.cx("relative", stateLayerBase, "before:m-auto before:size-8 before:rounded-full before:bg-current", hoverQuiet, pressQuiet),
359
373
  };
360
374
  /* Hit area — the interactive region of a control whose visible mark is smaller than a comfortable
361
375
  target, drawn outside the layout box so a column, a row gap and the space beside a label are all
@@ -373,10 +387,10 @@ const hitArea = "relative after:pointer-events-auto after:absolute after:inset-[
373
387
  - matteHigh: the second matte step, for nesting inside another matte surface.
374
388
  - matteInset: a passive sheet tucked under a stronger control; subdued without
375
389
  blending into the canvas or needing a drawn rim.
376
- - control: the fill every text control shares, plus its placeholder tone. It is a well:
377
- the canvas tone, which sits below a card in both themes, so a field reads as
378
- sunk into the surface rather than as a pad raised from it. Its rim, not its
379
- fill, is what separates it (see `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`).
380
394
  - handle: the fill of a small part the user has to find — a value control's handle.
381
395
  Surface steps sit within a few percent of their neighbours, so this role
382
396
  takes the mid-emphasis tone, which inverts with the theme and separates in
@@ -409,7 +423,7 @@ const material = {
409
423
  matteQuiet: "bg-sherick-surface/[0.42] text-sherick-ink",
410
424
  matte: "bg-sherick-surface/[0.78] text-sherick-ink",
411
425
  matteHigh: "bg-sherick-surface-high/[0.72] text-sherick-ink",
412
- control: "bg-sherick-canvas/[0.7] text-sherick-ink placeholder:text-sherick-ink-muted",
426
+ control: "bg-sherick-surface-high/[0.6] text-sherick-ink placeholder:text-sherick-ink-muted",
413
427
  /* The invalid fill carries its placeholder at the *full* danger tone, not at a fraction of it. A
414
428
  placeholder is text, so it answers to the same 4.5:1 the copy beside it does, and a partial
415
429
  opacity of an accent is a different colour from the accent: the 72%-opacity placeholder
@@ -417,7 +431,7 @@ const material = {
417
431
  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
418
432
  that is still readable, and a normal field's placeholder is `ink-muted` at full strength
419
433
  already — so the error form is the same rule, in the tone the field is in. */
420
- controlError: "bg-sherick-canvas/[0.7] text-sherick-ink placeholder:text-sherick-danger",
434
+ controlError: "bg-sherick-danger-soft/[0.55] text-sherick-ink placeholder:text-sherick-danger",
421
435
  handle: "bg-sherick-ink-muted text-sherick-canvas",
422
436
  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)]",
423
437
  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,7 +459,7 @@ const type = {
445
459
  },
446
460
  supporting: "text-[0.8125rem] leading-5",
447
461
  caption: "text-xs leading-4",
448
- title: "text-[0.9375rem] leading-[1.375rem] font-semibold",
462
+ title: "text-[0.9375rem] leading-[1.375rem] font-semibold tracking-[-0.011em]",
449
463
  heading: "text-xl leading-7 font-semibold tracking-[-0.02em]",
450
464
  numeric: "tabular-nums",
451
465
  };
@@ -465,12 +479,13 @@ const density = {
465
479
  target: "min-h-11 min-w-11",
466
480
  /* A control that is one part of a composite field — the trailing controls a Combobox owns. It
467
481
  keeps the floor's height, because it has to sit in the field's row, and takes only the width
468
- its glyph needs: the two of them are gripped as one cluster at the field's edge, and two full
469
- squares there read as two controls beside a field rather than as parts of it.
482
+ of its 32px hover surface (`stateLayer.fieldPart`): two parts side by side are gripped as one
483
+ cluster at the field's edge, their glyphs 12px apart, and any wider step spread a clear control
484
+ and a chevron into two controls beside a field rather than parts of it.
470
485
  The narrower step still clears the 24px pointer-target minimum WCAG AA asks for. It is below
471
486
  this system's own 44px floor on purpose: that floor belongs to a control that is the whole
472
487
  target of its own action, and this one is a part of a field the pointer is already in. */
473
- part: "min-h-11 min-w-9",
488
+ part: "min-h-11 min-w-8",
474
489
  };
475
490
  /* Icon slot — the fixed box a leading or trailing mark occupies, sized by the type step it sits
476
491
  beside so the icon-to-label ratio is the same at every size: a 14px label takes a 16px mark, a
@@ -509,7 +524,7 @@ const stacking = {
509
524
  alert dialog separate from the page identically. */
510
525
  const overlay = {
511
526
  /* The plane behind a surface that owns the viewport. */
512
- scrim: /* @__PURE__ */ utils.cx("fixed inset-0", stacking.float, "bg-sherick-scrim/[0.38] backdrop-blur-[var(--sui-scrim-blur)]"),
527
+ scrim: /* @__PURE__ */ utils.cx("fixed inset-0", stacking.float, "bg-sherick-scrim/[0.30] backdrop-blur-[var(--sui-scrim-blur)]"),
513
528
  /* An anchored surface with room to breathe: a selection list (Select, Combobox) or
514
529
  structured content (Popover). It grows out of its trigger and carries the softer
515
530
  surface corner, because what it holds is read rather than scanned.
@@ -599,6 +614,13 @@ const list = {
599
614
  row still shows where the navigation is while saying it cannot be used. The ring is inset
600
615
  because the row lives inside the sheet it belongs to, as a segment does in its track. */
601
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),
617
+ /* The heading of a group of options — a category above the channels filed under it. It is a
618
+ caption, not a row: it takes no state layer, no highlight and no focus, because the reader never
619
+ lands on it; the primitive names the group from it, so a screen reader hears the category as it
620
+ enters the group. Its inline padding is the option's, so a heading and the labels beneath it
621
+ share one start edge, and the space above it is what separates one group from the last: a
622
+ 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),
602
624
  /* The same object at the density a list of short actions wants, where the row is scanned
603
625
  rather than read and the list is a control rather than a page. `shape.row` keeps the
604
626
  command's corner proportional to its own height, so its highlight nests in the tighter
@@ -694,7 +716,28 @@ const currentDestination = "bg-sherick-primary-soft text-sherick-ink font-medium
694
716
  /* A radio's opt-in full row follows the Base control it labels. `:has` keeps uncontrolled
695
717
  selection authoritative at the primitive rather than mirroring it in component state.
696
718
  Keep this independent so unrelated consumers of the mark recipes can tree-shake it. */
697
- const selectableRowSurface = "has-[[data-checked]]:bg-sherick-primary-selected has-[[data-checked]]:text-sherick-ink has-[[data-checked]]:shadow-sherick-control";
719
+ /* The puck — a held choice that rides in a track: a selected segment, the tab indicator. A choice
720
+ held *in a groove* is a part lifted out of it, so it is the brightest surface in the view, raised
721
+ at `elevation.control`, and its label takes the role's text tone (`tone.text`): the lift says
722
+ "this one" and the label's colour says which family it belongs to. A held choice in a *sheet* —
723
+ an option, a tree row, a date — keeps `tone.selected`, because a list sheet is already the
724
+ brightest surface and a white row on it would vanish. */
725
+ 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";
732
+ /* Supporting copy inside such a row — a choice's description. `text.medium` clears 4.5:1 on the
733
+ soft step at rest (5.7:1 light, 6.2:1 dark), but the row's press layer composites toward the label
734
+ and takes that margin away, so while the row holds the selection its supporting line takes full
735
+ ink; the supporting type step keeps it subordinate to the label. Keyed on the same primitive
736
+ marker as the surface itself. */
737
+ const selectableRowSupporting = "group-has-[[data-checked]]:text-sherick-ink";
738
+ /* An empty mark's interior: a canvas-toned well. Named on its own so the contrast model can read it
739
+ without retaining the whole `selectable` table in bundles that never draw a mark. */
740
+ const markWellFill = "bg-sherick-canvas/[0.7]";
698
741
  const selectable = {
699
742
  surface: /* @__PURE__ */ utils.cx("relative", elevation.recessed, ui_motion.motionFeedback),
700
743
  /* A selection mark — a checkbox box, a radio socket — rests in the same groove a Switch track
@@ -717,7 +760,7 @@ const selectable = {
717
760
  recess all reach the mark's real edge: a border would leave a 1.5px frame of untinted fill
718
761
  around a hovered selected box. Hover steps the rim to the mid-emphasis tone — darker in light
719
762
  mode, lighter in dark — which is a visible answer on a 20px mark where a tint alone is not. */
720
- mark: /* @__PURE__ */ utils.cx("bg-sherick-canvas/[0.7]", text.medium, "after:pointer-events-none after:absolute after:inset-0 after:box-border after:rounded-[inherit] after:border-[1.5px] after:content-['']", "after:border-sherick-rim", "group-[:not([data-disabled]):not([data-readonly]):not(:disabled):hover]:after:border-sherick-ink-muted", ui_motion.motionRim),
763
+ mark: /* @__PURE__ */ utils.cx(markWellFill, text.medium, "after:pointer-events-none after:absolute after:inset-0 after:box-border after:rounded-[inherit] after:border-[1.5px] after:content-['']", "after:border-sherick-rim", "group-[:not([data-disabled]):not([data-readonly]):not(:disabled):hover]:after:border-sherick-ink-muted", ui_motion.motionRim),
721
764
  /* A selected mark is the strong accent, edge to edge, and it settles flat: it is identified by
722
765
  its fill and its glyph, and the rim fades out as the fill arrives. The rim fades by opacity
723
766
  rather than by colour, so forced colors cannot repaint a transparent rim as a visible one. */
@@ -740,13 +783,16 @@ const recipeAlpha = (recipe, pattern, label) => {
740
783
  };
741
784
  const stateAlpha = (recipe, label) => recipeAlpha(recipe, /opacity-\[(0?\.\d+)\]/, label);
742
785
  const fillAlpha = (recipe, label) => recipeAlpha(recipe, /\/\[(0?\.\d+)\]/, label);
743
- /* A field well's canvas step: written without an alpha, the step is the opaque canvas. */
744
- const wellAlpha = (recipe, label) => {
745
- const match = recipe.match(/bg-sherick-canvas(?:\/\[(0?\.\d+)\])?(?:\s|$)/);
786
+ /* A tone's step written with or without an alpha: without one, the step is the opaque tone. */
787
+ const toneAlpha = (tone) => (recipe, label) => {
788
+ const match = recipe.match(new RegExp(`bg-sherick-${tone}(?:\\/\\[(0?\\.\\d+)\\])?(?:\\s|$)`));
746
789
  if (!match)
747
790
  throw new Error(`recipe alpha missing for ${label}`);
748
791
  return match[1] === undefined ? 1 : Number(match[1]);
749
792
  };
793
+ /* A field tray's `surface-high` step, and the canvas step an empty mark's interior holds. */
794
+ const trayAlpha = toneAlpha("surface-high");
795
+ const markAlpha = toneAlpha("canvas");
750
796
  const recipeAlphas = {
751
797
  state: {
752
798
  quiet: { hover: stateAlpha(hoverQuiet, "state.quiet.hover"), press: stateAlpha(pressQuiet, "state.quiet.press") },
@@ -763,9 +809,11 @@ const recipeAlphas = {
763
809
  quiet: fillAlpha(material.matteQuiet, "field.quiet"),
764
810
  card: fillAlpha(material.matte, "field.card"),
765
811
  groove: fillAlpha(material.matteHigh, "field.groove"),
766
- control: wellAlpha(material.control, "field.control"),
767
- hover: wellAlpha(state.field.hover, "field.hover"),
768
- engaged: wellAlpha(state.field.engaged, "field.engaged"),
812
+ control: trayAlpha(material.control, "field.control"),
813
+ hover: trayAlpha(state.field.hover, "field.hover"),
814
+ engaged: trayAlpha(state.field.engaged, "field.engaged"),
815
+ mark: markAlpha(markWellFill, "field.mark"),
816
+ error: fillAlpha(material.controlError, "field.error"),
769
817
  },
770
818
  };
771
819
  /* A labelled field is a shrinkable column. Its explanatory copy wraps, including identifiers;
@@ -801,10 +849,12 @@ exports.matteInset = matteInset;
801
849
  exports.mediaCanvas = mediaCanvas;
802
850
  exports.overlay = overlay;
803
851
  exports.parentFocusRingInset = parentFocusRingInset;
852
+ exports.puck = puck;
804
853
  exports.recessedTop = recessedTop;
805
854
  exports.recipeAlphas = recipeAlphas;
806
855
  exports.rim = rim;
807
856
  exports.selectable = selectable;
857
+ exports.selectableRowSupporting = selectableRowSupporting;
808
858
  exports.selectableRowSurface = selectableRowSurface;
809
859
  exports.shape = shape;
810
860
  exports.stacking = stacking;