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.
- package/README.md +57 -3
- package/dist/cjs/components/CheckboxGroup.cjs +41 -0
- package/dist/cjs/components/CheckboxGroup.cjs.map +1 -0
- package/dist/cjs/components/Combobox.cjs +190 -14
- package/dist/cjs/components/Combobox.cjs.map +1 -1
- package/dist/cjs/components/Form.cjs +27 -0
- package/dist/cjs/components/Form.cjs.map +1 -0
- package/dist/cjs/components/Input.cjs +20 -2
- package/dist/cjs/components/Input.cjs.map +1 -1
- package/dist/cjs/components/NumberField.cjs +30 -4
- package/dist/cjs/components/NumberField.cjs.map +1 -1
- package/dist/cjs/components/RadioGroup.cjs +7 -3
- package/dist/cjs/components/RadioGroup.cjs.map +1 -1
- package/dist/cjs/components/Search.cjs +1 -1
- package/dist/cjs/components/Search.cjs.map +1 -1
- package/dist/cjs/components/Select.cjs +4 -2
- package/dist/cjs/components/Select.cjs.map +1 -1
- package/dist/cjs/components/Tabs.cjs +1 -1
- package/dist/cjs/components/Tabs.cjs.map +1 -1
- package/dist/cjs/components/Textarea.cjs +6 -1
- package/dist/cjs/components/Textarea.cjs.map +1 -1
- package/dist/cjs/components/ToggleGroup.cjs +1 -1
- package/dist/cjs/components/ToggleGroup.cjs.map +1 -1
- package/dist/cjs/components/choice-row.cjs +51 -0
- package/dist/cjs/components/choice-row.cjs.map +1 -0
- package/dist/cjs/components/date-field.cjs +3 -3
- package/dist/cjs/components/date-field.cjs.map +1 -1
- package/dist/cjs/components/option-groups.cjs +35 -0
- package/dist/cjs/components/option-groups.cjs.map +1 -0
- package/dist/cjs/components/ui.common.cjs +100 -50
- package/dist/cjs/components/ui.common.cjs.map +1 -1
- package/dist/cjs/dev.cjs +2 -0
- package/dist/cjs/dev.cjs.map +1 -1
- package/dist/cjs/index.cjs +4 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/esm/components/CheckboxGroup.js +36 -0
- package/dist/esm/components/CheckboxGroup.js.map +1 -0
- package/dist/esm/components/Combobox.js +195 -19
- package/dist/esm/components/Combobox.js.map +1 -1
- package/dist/esm/components/Form.js +22 -0
- package/dist/esm/components/Form.js.map +1 -0
- package/dist/esm/components/Input.js +21 -3
- package/dist/esm/components/Input.js.map +1 -1
- package/dist/esm/components/NumberField.js +31 -5
- package/dist/esm/components/NumberField.js.map +1 -1
- package/dist/esm/components/RadioGroup.js +10 -6
- package/dist/esm/components/RadioGroup.js.map +1 -1
- package/dist/esm/components/Search.js +1 -1
- package/dist/esm/components/Search.js.map +1 -1
- package/dist/esm/components/Select.js +6 -4
- package/dist/esm/components/Select.js.map +1 -1
- package/dist/esm/components/Tabs.js +2 -2
- package/dist/esm/components/Tabs.js.map +1 -1
- package/dist/esm/components/Textarea.js +6 -1
- package/dist/esm/components/Textarea.js.map +1 -1
- package/dist/esm/components/ToggleGroup.js +2 -2
- package/dist/esm/components/ToggleGroup.js.map +1 -1
- package/dist/esm/components/choice-row.js +46 -0
- package/dist/esm/components/choice-row.js.map +1 -0
- package/dist/esm/components/date-field.js +3 -3
- package/dist/esm/components/date-field.js.map +1 -1
- package/dist/esm/components/option-groups.js +30 -0
- package/dist/esm/components/option-groups.js.map +1 -0
- package/dist/esm/components/ui.common.js +100 -52
- package/dist/esm/components/ui.common.js.map +1 -1
- package/dist/esm/dev.js +1 -1
- package/dist/esm/index.js +2 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/styles.css +271 -205
- package/dist/theme.css +160 -157
- package/dist/types/dev.d.cts +31 -25
- package/dist/types/dev.d.ts +31 -25
- package/dist/types/index.d.cts +184 -20
- package/dist/types/index.d.ts +184 -20
- 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
|
|
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
|
|
129
|
-
sheet around
|
|
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-[
|
|
152
|
+
control: "rounded-[0.75rem]",
|
|
153
153
|
mark: "rounded-[0.375rem]",
|
|
154
|
-
row: "rounded-[0.
|
|
155
|
-
prominent: "rounded-[
|
|
156
|
-
surface: "rounded-[1.
|
|
157
|
-
sheet: "rounded-[
|
|
158
|
-
expressive: "rounded-[1.
|
|
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
|
|
185
|
-
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
|
|
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
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
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-
|
|
262
|
-
focus: "focus:bg-sherick-
|
|
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-
|
|
265
|
-
engaged: "bg-sherick-
|
|
266
|
-
errorHover: "hover:bg-sherick-
|
|
267
|
-
errorFocus: "focus:bg-sherick-
|
|
268
|
-
errorEngaged: "bg-sherick-
|
|
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
|
|
377
|
-
the
|
|
378
|
-
|
|
379
|
-
|
|
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-
|
|
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-
|
|
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
|
|
469
|
-
|
|
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-
|
|
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.
|
|
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
|
-
|
|
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(
|
|
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
|
|
744
|
-
const
|
|
745
|
-
const match = recipe.match(
|
|
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:
|
|
767
|
-
hover:
|
|
768
|
-
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;
|