@signal9/era-ui 30.8.0 → 32.0.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/CHANGELOG.md +28 -0
- package/dist/ai/artifact/artifact.svelte +1 -1
- package/dist/ai/conversations/conversations-item.svelte +1 -1
- package/dist/ai/plan/plan-header.svelte +1 -1
- package/dist/ai/prompt-input/prompt-input-attachments.svelte +2 -6
- package/dist/ai/swarm/swarm-node.svelte +1 -1
- package/dist/ai/todo/todo-header.svelte +1 -1
- package/dist/ai/todo/todo-item.svelte +1 -1
- package/dist/ai/tool/tool-chip.svelte +1 -1
- package/dist/ai/web-preview/web-preview.svelte +2 -2
- package/dist/ai/workflow/node.svelte +1 -1
- package/dist/dev/audit/audits/wall-is-isotropic.js +1 -1
- package/dist/docs/css-utilities.js +9 -5
- package/dist/era-ui.css +1 -1
- package/dist/generated-docs/badge.md +1 -1
- package/dist/generated-docs/bar.md +22 -4
- package/dist/generated-docs/button.md +38 -4
- package/dist/generated-docs/card.md +35 -5
- package/dist/generated-docs/chip.md +16 -0
- package/dist/generated-docs/llms-full.txt +370 -70
- package/dist/generated-docs/llms.txt +8 -4
- package/dist/generated-docs/manifest.json +85 -28
- package/dist/generated-docs/meter.md +79 -1
- package/dist/generated-docs/nav.md +8 -1
- package/dist/generated-docs/separator.md +18 -0
- package/dist/generated-docs/utilities.json +68 -15
- package/dist/generated-docs/utilities.md +145 -50
- package/dist/os/notification-center.svelte +1 -1
- package/dist/os/taskbar.svelte +1 -1
- package/dist/os/toast.svelte +1 -1
- package/dist/styles/density.css +15 -25
- package/dist/styles/index.css +74 -48
- package/dist/styles/motion.css +1 -1
- package/dist/styles/prose.css +1 -1
- package/dist/styles/surfaces/bevel.css +16 -19
- package/dist/styles/surfaces/contract.css +50 -0
- package/dist/styles/surfaces/flat.css +27 -0
- package/dist/styles/surfaces/glass.css +11 -8
- package/dist/ui/accordion/accordion-trigger.svelte +1 -1
- package/dist/ui/alert-dialog/alert-dialog-content.svelte +1 -1
- package/dist/ui/badge/badge.svelte +8 -2
- package/dist/ui/badge/badge.svelte.d.ts +1 -1
- package/dist/ui/bar/bar.svelte +95 -26
- package/dist/ui/bar/bar.svelte.d.ts +71 -31
- package/dist/ui/button/button.svelte +6 -0
- package/dist/ui/button/button.svelte.d.ts +2 -0
- package/dist/ui/button/variants.d.ts +3 -3
- package/dist/ui/button/variants.js +6 -11
- package/dist/ui/calendar/calendar-day.svelte +1 -1
- package/dist/ui/card/card.svelte +23 -10
- package/dist/ui/card/card.svelte.d.ts +19 -7
- package/dist/ui/chip/chip.svelte +5 -2
- package/dist/ui/chip/chip.svelte.d.ts +6 -6
- package/dist/ui/collapsible/collapsible-trigger.svelte +1 -1
- package/dist/ui/combobox/combobox-content.svelte +1 -1
- package/dist/ui/combobox/combobox-trigger.svelte +1 -1
- package/dist/ui/command/command-item.svelte +1 -1
- package/dist/ui/command/command-link-item.svelte +1 -1
- package/dist/ui/command/command-root.svelte +5 -7
- package/dist/ui/command-bar/command-bar.svelte +3 -3
- package/dist/ui/context-menu/context-menu-content.svelte +1 -4
- package/dist/ui/context-menu/context-menu-sub-content.svelte +1 -4
- package/dist/ui/date-field/date-field-segment.svelte +1 -1
- package/dist/ui/date-picker/date-picker-content.svelte +1 -1
- package/dist/ui/date-picker/date-picker-day.svelte +1 -1
- package/dist/ui/date-picker/date-picker-segment.svelte +1 -1
- package/dist/ui/date-picker/date-picker-trigger.svelte +1 -1
- package/dist/ui/date-range-field/date-range-field-segment.svelte +1 -1
- package/dist/ui/date-range-picker/date-range-picker-content.svelte +1 -1
- package/dist/ui/date-range-picker/date-range-picker-day.svelte +1 -1
- package/dist/ui/date-range-picker/date-range-picker-segment.svelte +1 -1
- package/dist/ui/date-range-picker/date-range-picker-trigger.svelte +1 -1
- package/dist/ui/dialog/dialog-content.svelte +20 -2
- package/dist/ui/dropdown-menu/dropdown-menu-content.svelte +1 -1
- package/dist/ui/dropdown-menu/dropdown-menu-sub-content.svelte +1 -4
- package/dist/ui/dropdown-menu/dropdown-menu-trigger.svelte +1 -1
- package/dist/ui/file-upload/file-upload.svelte +1 -1
- package/dist/ui/input/variants.d.ts +6 -6
- package/dist/ui/input/variants.js +2 -2
- package/dist/ui/kv/kv.svelte +1 -1
- package/dist/ui/link-preview/link-preview-content.svelte +1 -1
- package/dist/ui/menubar/menubar-content.svelte +1 -1
- package/dist/ui/menubar/menubar-root.svelte +1 -1
- package/dist/ui/menubar/menubar-sub-content.svelte +1 -4
- package/dist/ui/menubar/menubar-trigger.svelte +1 -1
- package/dist/ui/meter/meter.svelte +1 -2
- package/dist/ui/nav/nav-bar.svelte +9 -4
- package/dist/ui/nav/nav-bar.svelte.d.ts +2 -1
- package/dist/ui/nav/nav-item.svelte +1 -0
- package/dist/ui/pane/pane-root.svelte +3 -12
- package/dist/ui/pane/pane-tab.svelte +1 -1
- package/dist/ui/popover/popover-content.svelte +1 -1
- package/dist/ui/provider/surfaces.d.ts +1 -1
- package/dist/ui/provider/surfaces.js +1 -1
- package/dist/ui/select/select-content.svelte +1 -1
- package/dist/ui/select/select-trigger.svelte +1 -1
- package/dist/ui/sheet/sheet-content.svelte +1 -1
- package/dist/ui/sheet/sheet-content.svelte.d.ts +1 -1
- package/dist/ui/slider/slider-thumb.svelte +1 -1
- package/dist/ui/step/step-summary.svelte +1 -1
- package/dist/ui/switch/switch.svelte +3 -3
- package/dist/ui/time-field/time-field-segment.svelte +1 -1
- package/dist/ui/time-range-field/time-range-field-segment.svelte +1 -1
- package/dist/ui/timeline/timeline-step.svelte +1 -1
- package/dist/ui/toggle-group/toggle-group-item.svelte +2 -2
- package/dist/ui/toggle-group/toggle-group-item.svelte.d.ts +6 -6
- package/dist/ui/toggle-group/toggle-group-root.svelte +1 -2
- package/dist/ui/toggle-group/toggle-group-root.svelte.d.ts +3 -3
- package/dist/ui/tooltip/tooltip-content.svelte +1 -1
- package/dist/ui/tree/tree-item.svelte +1 -1
- package/dist/ui/video-player/video-player.svelte +2 -2
- package/dist/utils/tw-merge-config.d.ts +6 -1
- package/dist/utils/tw-merge-config.js +6 -2
- package/package.json +5 -3
- package/skill/SKILL.md +26 -21
- package/dist/styles/surfaces/base.css +0 -257
|
@@ -63,9 +63,13 @@ Classes, not components — they need no import beyond the stylesheet. Reach for
|
|
|
63
63
|
- `era-ink-center` — on a native single-line <input> (or the text layer that must mirror one) inside a fixed-height field — never alongside era-text-trim.
|
|
64
64
|
- `era-token-ink` — the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box, CENTRED horizontally and with no icon sibling. For a left-aligned sentence-case label use era-label-ink; when an icon really must sit beside the text, see the note there.
|
|
65
65
|
- `era-label-ink` — the ink centring for a fixed-height control holding ONE line of sentence-case text and no icon — a menu item, a nav trigger, a button label. Never alongside `truncate` (the trimmed box becomes the clip).
|
|
66
|
-
- `
|
|
67
|
-
- `
|
|
66
|
+
- `surface-backdrop` — the surface-aware backdrop treatment without choosing a fill or relief. Prefer material-popover/material-panel when the element is a complete surface.
|
|
67
|
+
- `material-popover` — a floating transient surface: menus, popovers, tooltips, pickers, toasts. Binds its raised fill, floating relief, and backdrop treatment atomically.
|
|
68
|
+
- `material-panel` — a floating persistent surface: dialogs, sheets, panes, inspectors. Binds its resting fill, floating relief, and backdrop treatment atomically.
|
|
69
|
+
- `pressable` — the physical press contract on a control whose direct content plane is marked data-era-press-content. The surface owns relief/travel; the component may scale travel with --era-press-scale.
|
|
70
|
+
- `tier-icon · tier-pill · tier-chip · tier-control · tier-bar` — BOUNDED GEOMETRY — height and radius are one decision.
|
|
68
71
|
- `h-line` — the height of one line of the element's own text — a skeleton standing in for a line, a spacer that must match a line box.
|
|
72
|
+
- `era-track-well` — instead of `shadow-well` on a track whose value is painted by a child that covers the box — a progress/meter/slider track, a custom gauge. For a well holding ordinary content, `shadow-well` is still right.
|
|
69
73
|
- `era-skeleton-pulse` — Skeleton's pulse, on the MOTION AXIS.
|
|
70
74
|
- `era-shimmer` — the in-progress text treatment — put it on a "working…" / "thinking…" label while a task streams, instead of a spinner beside the text.
|
|
71
75
|
- `era-collapse` — the height sweep for a bits-ui Collapsible.Content — put it on the Content element itself (it carries its own overflow: hidden).
|
|
@@ -86,12 +90,12 @@ Classes, not components — they need no import beyond the stylesheet. Reach for
|
|
|
86
90
|
- `bg-well · text-well · border-well · bg-elevated · text-elevated · border-elevated · bg-highlight · text-highlight · … (12 in all)` — Surface fills — bg-well is the surface's own resting fill (pairs with
|
|
87
91
|
- `p-gutter · px-gutter · py-gutter · gap-gutter · p-panel · px-panel · py-panel · gap-panel · … (24 in all)` — THE SPACING SCALE — one entry per token, from which Tailwind derives the
|
|
88
92
|
- `p-inset-pill · px-inset-pill · py-inset-pill · gap-inset-pill · p-inset-chip · px-inset-chip · py-inset-chip · gap-inset-chip · … (12 in all)` — text-symmetric content padding — (tier − text)/2, the inset that vertically centres body text in its tier; px-inset-control is a text button's side padding, p-inset-control a code block's.
|
|
89
|
-
- `p-icon-inset-pill · px-icon-inset-pill · py-icon-inset-pill · gap-icon-inset-pill · p-icon-inset-chip · px-icon-inset-chip · py-icon-inset-chip · gap-icon-inset-chip · … (
|
|
93
|
+
- `p-icon-inset-pill · px-icon-inset-pill · py-icon-inset-pill · gap-icon-inset-pill · p-icon-inset-chip · px-icon-inset-chip · py-icon-inset-chip · gap-icon-inset-chip · … (40 in all)` — the concentric inset for a nested pair — (h-container − h-child)/2, the gap that makes a child control sit evenly inside its container, and the radius step that keeps their corners concentric. Named for the pair it joins: gap-icon-inset-control seats an icon in a control.
|
|
90
94
|
- `p-glyph-icon · px-glyph-icon · py-glyph-icon · gap-glyph-icon · p-glyph-pill · px-glyph-pill · py-glyph-pill · gap-glyph-pill` — the glyph size for a tier — the INK inside the box, not the box (size-glyph-pill is the dismiss × in a pill, size-pill is the pill).
|
|
91
95
|
- `bg-field · text-field · border-field · bg-field-highlight · text-field-highlight · border-field-highlight` — the recessed field fill — bg-field is a text input's resting well, bg-field-highlight its focused/hovered face.
|
|
92
96
|
- `ease-base` — Motion — bare transition utilities default to the motion axis, so
|
|
93
97
|
- `bg-divider · text-divider · border-divider · bg-divider-faded · text-divider-faded · border-divider-faded · bg-background · text-background · … (66 in all)` — Surface divider colors: border-divider, bg-divider-faded, …
|
|
94
|
-
- `bg-fill · text-fill · border-fill · bg-link · text-link · border-link · bg-primary · text-primary · … (
|
|
98
|
+
- `bg-fill · text-fill · border-fill · bg-link · text-link · border-link · bg-primary · text-primary · … (39 in all)` — The standing pill fill — --era-fill, the latched counterpart of the
|
|
95
99
|
|
|
96
100
|
Full reference (what each emits, when to use it): `/utilities.md`. Machine-readable list: `/utilities.json`.
|
|
97
101
|
|
|
@@ -153,7 +157,7 @@ The CSS classes era ships alongside the components — links, ink-centred text,
|
|
|
153
157
|
|
|
154
158
|
## Overview
|
|
155
159
|
|
|
156
|
-
era's styling API is pure class names — write `
|
|
160
|
+
era's styling API is pure class names — write `tier-control px-gutter shadow`,
|
|
157
161
|
never the `h-(--era-h-control)` var-class spelling. Everything below rides along
|
|
158
162
|
with the stylesheet and needs no import:
|
|
159
163
|
|
|
@@ -162,7 +166,7 @@ import "@signal9/era-ui/css";
|
|
|
162
166
|
```
|
|
163
167
|
|
|
164
168
|
```svelte
|
|
165
|
-
<button class="
|
|
169
|
+
<button class="tier-control px-inset-control shadow text-body">era styled</button>
|
|
166
170
|
```
|
|
167
171
|
|
|
168
172
|
Alongside the `@utility` classes referenced below, era registers named theme
|
|
@@ -172,6 +176,7 @@ motion):
|
|
|
172
176
|
|
|
173
177
|
| Stock-looking class | What it resolves to |
|
|
174
178
|
|---|---|
|
|
179
|
+
| `tier-icon/pill/chip/control/bar` | indivisible bounded height + concentric radius |
|
|
175
180
|
| `rounded-icon/pill/chip/control/bar` | the concentric radius ladder (collapses on `data-corners="square"`) |
|
|
176
181
|
| `rounded-menu-item` | menu-row radius, concentric inside a `rounded-control` panel |
|
|
177
182
|
| `shadow` / `shadow-lg` | resting control edge / floating panel chrome, per surface |
|
|
@@ -197,10 +202,13 @@ The spacing names (`gutter`, `card`, `panel`, `content`, `menu`, `field`, the
|
|
|
197
202
|
`inset-*` and concentric `*-inset-*` insets, `glyph-*`) are registered as a
|
|
198
203
|
Tailwind spacing scale, so every prefix derives automatically: `p-`, `px-`,
|
|
199
204
|
`pt-`, `mt-`, `gap-`, `gap-x-`, `inset-`, `translate-`, and the rest. The TIER
|
|
200
|
-
names (`icon`, `pill`, `chip`, `control`, `bar`) are
|
|
205
|
+
names (`icon`, `pill`, `chip`, `control`, `bar`) are dimensions, not spacing, so
|
|
201
206
|
they are registered per prefix instead — `h-`, `w-`, `min-h-`, `min-w-` and
|
|
202
207
|
`size-` — and the two vocabularies deliberately share no word. Putting a tier
|
|
203
208
|
in the spacing scale would silently make `px-control` mean 24px of padding.
|
|
209
|
+
For chrome, use `tier-T`, which binds `h-T` and `rounded-T`; use the separate
|
|
210
|
+
dimension/radius names only for width, minimums, unbounded surfaces, or
|
|
211
|
+
asymmetric/docked corners.
|
|
204
212
|
|
|
205
213
|
The var form (`h-(--era-h-control)`) still works and is the escape hatch for a
|
|
206
214
|
token with no registered name — `--era-sp`, the press-sink offsets, anything
|
|
@@ -218,9 +226,13 @@ source uses it where a name exists.
|
|
|
218
226
|
| `era-ink-center` | on a native single-line <input> (or the text layer that must mirror one) inside a fixed-height field — never alongside era-text-trim. |
|
|
219
227
|
| `era-token-ink` | the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box, CENTRED horizontally and with no icon sibling. For a left-aligned sentence-case label use era-label-ink; when an icon really must sit beside the text, see the note there. |
|
|
220
228
|
| `era-label-ink` | the ink centring for a fixed-height control holding ONE line of sentence-case text and no icon — a menu item, a nav trigger, a button label. Never alongside `truncate` (the trimmed box becomes the clip). |
|
|
221
|
-
| `
|
|
222
|
-
| `
|
|
229
|
+
| `surface-backdrop` | the surface-aware backdrop treatment without choosing a fill or relief. Prefer material-popover/material-panel when the element is a complete surface. |
|
|
230
|
+
| `material-popover` | a floating transient surface: menus, popovers, tooltips, pickers, toasts. Binds its raised fill, floating relief, and backdrop treatment atomically. |
|
|
231
|
+
| `material-panel` | a floating persistent surface: dialogs, sheets, panes, inspectors. Binds its resting fill, floating relief, and backdrop treatment atomically. |
|
|
232
|
+
| `pressable` | the physical press contract on a control whose direct content plane is marked data-era-press-content. The surface owns relief/travel; the component may scale travel with --era-press-scale. |
|
|
233
|
+
| `tier-icon` `tier-pill` `tier-chip` `tier-control` `tier-bar` | — |
|
|
223
234
|
| `h-line` | the height of one line of the element's own text — a skeleton standing in for a line, a spacer that must match a line box. |
|
|
235
|
+
| `era-track-well` | instead of `shadow-well` on a track whose value is painted by a child that covers the box — a progress/meter/slider track, a custom gauge. For a well holding ordinary content, `shadow-well` is still right. |
|
|
224
236
|
| `era-skeleton-pulse` | — |
|
|
225
237
|
| `era-shimmer` | the in-progress text treatment — put it on a "working…" / "thinking…" label while a task streams, instead of a spinner beside the text. |
|
|
226
238
|
| `era-collapse` | the height sweep for a bits-ui Collapsible.Content — put it on the Content element itself (it carries its own overflow: hidden). |
|
|
@@ -241,12 +253,12 @@ source uses it where a name exists.
|
|
|
241
253
|
| `bg-well` `text-well` `border-well` `bg-elevated` `text-elevated` `border-elevated` `bg-highlight` `text-highlight` `border-highlight` `bg-overlay` `text-overlay` `border-overlay` | — |
|
|
242
254
|
| `p-gutter` `px-gutter` `py-gutter` `gap-gutter` `p-panel` `px-panel` `py-panel` `gap-panel` `p-card` `px-card` `py-card` `gap-card` `p-content` `px-content` `py-content` `gap-content` `p-menu` `px-menu` `py-menu` `gap-menu` `p-field` `px-field` `py-field` `gap-field` | — |
|
|
243
255
|
| `p-inset-pill` `px-inset-pill` `py-inset-pill` `gap-inset-pill` `p-inset-chip` `px-inset-chip` `py-inset-chip` `gap-inset-chip` `p-inset-control` `px-inset-control` `py-inset-control` `gap-inset-control` | text-symmetric content padding — (tier − text)/2, the inset that vertically centres body text in its tier; px-inset-control is a text button's side padding, p-inset-control a code block's. |
|
|
244
|
-
| `p-icon-inset-pill` `px-icon-inset-pill` `py-icon-inset-pill` `gap-icon-inset-pill` `p-icon-inset-chip` `px-icon-inset-chip` `py-icon-inset-chip` `gap-icon-inset-chip` `p-icon-inset-control` `px-icon-inset-control` `py-icon-inset-control` `gap-icon-inset-control` `p-icon-inset-bar` `px-icon-inset-bar` `py-icon-inset-bar` `gap-icon-inset-bar` `p-pill-inset-chip` `px-pill-inset-chip` `py-pill-inset-chip` `gap-pill-inset-chip` `p-pill-inset-control` `px-pill-inset-control` `py-pill-inset-control` `gap-pill-inset-control` `p-pill-inset-bar` `px-pill-inset-bar` `py-pill-inset-bar` `gap-pill-inset-bar` `p-chip-inset-control` `px-chip-inset-control` `py-chip-inset-control` `gap-chip-inset-control` `p-chip-inset-bar` `px-chip-inset-bar` `py-chip-inset-bar` `gap-chip-inset-bar` | the concentric inset for a nested pair — (h-container − h-child)/2, the gap that makes a child control sit evenly inside its container, and the radius step that keeps their corners concentric. Named for the pair it joins: gap-icon-inset-control seats an icon in a control. |
|
|
256
|
+
| `p-icon-inset-pill` `px-icon-inset-pill` `py-icon-inset-pill` `gap-icon-inset-pill` `p-icon-inset-chip` `px-icon-inset-chip` `py-icon-inset-chip` `gap-icon-inset-chip` `p-icon-inset-control` `px-icon-inset-control` `py-icon-inset-control` `gap-icon-inset-control` `p-icon-inset-bar` `px-icon-inset-bar` `py-icon-inset-bar` `gap-icon-inset-bar` `p-pill-inset-chip` `px-pill-inset-chip` `py-pill-inset-chip` `gap-pill-inset-chip` `p-pill-inset-control` `px-pill-inset-control` `py-pill-inset-control` `gap-pill-inset-control` `p-pill-inset-bar` `px-pill-inset-bar` `py-pill-inset-bar` `gap-pill-inset-bar` `p-chip-inset-control` `px-chip-inset-control` `py-chip-inset-control` `gap-chip-inset-control` `p-chip-inset-bar` `px-chip-inset-bar` `py-chip-inset-bar` `gap-chip-inset-bar` `p-control-inset-bar` `px-control-inset-bar` `py-control-inset-bar` `gap-control-inset-bar` | the concentric inset for a nested pair — (h-container − h-child)/2, the gap that makes a child control sit evenly inside its container, and the radius step that keeps their corners concentric. Named for the pair it joins: gap-icon-inset-control seats an icon in a control. |
|
|
245
257
|
| `p-glyph-icon` `px-glyph-icon` `py-glyph-icon` `gap-glyph-icon` `p-glyph-pill` `px-glyph-pill` `py-glyph-pill` `gap-glyph-pill` | the glyph size for a tier — the INK inside the box, not the box (size-glyph-pill is the dismiss × in a pill, size-pill is the pill). |
|
|
246
258
|
| `bg-field` `text-field` `border-field` `bg-field-highlight` `text-field-highlight` `border-field-highlight` | the recessed field fill — bg-field is a text input's resting well, bg-field-highlight its focused/hovered face. |
|
|
247
259
|
| `ease-base` | — |
|
|
248
260
|
| `bg-divider` `text-divider` `border-divider` `bg-divider-faded` `text-divider-faded` `border-divider-faded` `bg-background` `text-background` `border-background` `bg-foreground` `text-foreground` `border-foreground` `bg-1` `text-1` `border-1` `bg-2` `text-2` `border-2` `bg-3` `text-3` `border-3` `bg-4` `text-4` `border-4` `bg-5` `text-5` `border-5` `bg-6` `text-6` `border-6` `bg-7` `text-7` `border-7` `bg-8` `text-8` `border-8` `bg-9` `text-9` `border-9` `bg-10` `text-10` `border-10` `bg-11` `text-11` `border-11` `bg-12` `text-12` `border-12` `bg-border` `text-border` `border-border` `bg-surface` `text-surface` `border-surface` `bg-hover` `text-hover` `border-hover` `bg-fg` `text-fg` `border-fg` `bg-bright` `text-bright` `border-bright` `bg-muted` `text-muted` `border-muted` | — |
|
|
249
|
-
| `bg-fill` `text-fill` `border-fill` `bg-link` `text-link` `border-link` `bg-primary` `text-primary` `border-primary` `bg-primary-fg` `text-primary-fg` `border-primary-fg` `bg-primary-hover` `text-primary-hover` `border-primary-hover` `bg-destructive` `text-destructive` `border-destructive` `bg-destructive-fg` `text-destructive-fg` `border-destructive-fg` `bg-success` `text-success` `border-success` `bg-success-fg` `text-success-fg` `border-success-fg` `bg-warning` `text-warning` `border-warning` `bg-warning-fg` `text-warning-fg` `border-warning-fg` | — |
|
|
261
|
+
| `bg-fill` `text-fill` `border-fill` `bg-link` `text-link` `border-link` `bg-primary` `text-primary` `border-primary` `bg-primary-fg` `text-primary-fg` `border-primary-fg` `bg-primary-hover` `text-primary-hover` `border-primary-hover` `bg-destructive` `text-destructive` `border-destructive` `bg-destructive-fg` `text-destructive-fg` `border-destructive-fg` `bg-success` `text-success` `border-success` `bg-success-fg` `text-success-fg` `border-success-fg` `bg-warning` `text-warning` `border-warning` `bg-warning-fg` `text-warning-fg` `border-warning-fg` `bg-info` `text-info` `border-info` `bg-info-fg` `text-info-fg` `border-info-fg` | — |
|
|
250
262
|
|
|
251
263
|
## era-interactive
|
|
252
264
|
|
|
@@ -599,64 +611,104 @@ Declared in `index.css`.
|
|
|
599
611
|
}
|
|
600
612
|
```
|
|
601
613
|
|
|
602
|
-
##
|
|
614
|
+
## surface-backdrop
|
|
603
615
|
|
|
604
|
-
**Use it for:** the backdrop
|
|
616
|
+
**Use it for:** the surface-aware backdrop treatment without choosing a fill or relief. Prefer material-popover/material-panel when the element is a complete surface.
|
|
605
617
|
|
|
606
|
-
|
|
607
|
-
is a registered utility, gated to glass subtrees.
|
|
618
|
+
Declared in `index.css`.
|
|
608
619
|
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
620
|
+
```css
|
|
621
|
+
@utility surface-backdrop {
|
|
622
|
+
backdrop-filter: var(--era-backdrop-filter);
|
|
623
|
+
-webkit-backdrop-filter: var(--era-backdrop-filter);
|
|
624
|
+
}
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
## material-popover
|
|
628
|
+
|
|
629
|
+
**Use it for:** a floating transient surface: menus, popovers, tooltips, pickers, toasts. Binds its raised fill, floating relief, and backdrop treatment atomically.
|
|
613
630
|
|
|
614
631
|
Declared in `index.css`.
|
|
615
632
|
|
|
616
633
|
```css
|
|
617
|
-
@utility
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
* so it is safe to leave on a panel that renders under every surface. */
|
|
623
|
-
@utility glass-blur {
|
|
624
|
-
[data-surface='glass'] & {
|
|
625
|
-
backdrop-filter: blur(var(--era-blur)) saturate(var(--era-saturate));
|
|
626
|
-
-webkit-backdrop-filter: blur(var(--era-blur)) saturate(var(--era-saturate));
|
|
627
|
-
}
|
|
634
|
+
@utility material-popover {
|
|
635
|
+
background-color: var(--era-surface-bg-elevated);
|
|
636
|
+
box-shadow: var(--era-shadow-lg);
|
|
637
|
+
backdrop-filter: var(--era-backdrop-filter);
|
|
638
|
+
-webkit-backdrop-filter: var(--era-backdrop-filter);
|
|
628
639
|
}
|
|
629
640
|
```
|
|
630
641
|
|
|
631
|
-
##
|
|
642
|
+
## material-panel
|
|
632
643
|
|
|
633
|
-
**Use it for:**
|
|
644
|
+
**Use it for:** a floating persistent surface: dialogs, sheets, panes, inspectors. Binds its resting fill, floating relief, and backdrop treatment atomically.
|
|
634
645
|
|
|
635
|
-
|
|
646
|
+
Declared in `index.css`.
|
|
636
647
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
648
|
+
```css
|
|
649
|
+
@utility material-panel {
|
|
650
|
+
background-color: var(--era-surface-bg);
|
|
651
|
+
box-shadow: var(--era-shadow-lg);
|
|
652
|
+
backdrop-filter: var(--era-backdrop-filter);
|
|
653
|
+
-webkit-backdrop-filter: var(--era-backdrop-filter);
|
|
654
|
+
}
|
|
655
|
+
```
|
|
643
656
|
|
|
644
|
-
|
|
645
|
-
trade and was briefly shipped. The ladder exists so a gap and concentric
|
|
646
|
-
corners COEXIST; spending one to buy the other gives up the thing it is for.
|
|
657
|
+
## pressable
|
|
647
658
|
|
|
648
|
-
|
|
649
|
-
automatic: `--era-container-rd` is inherited, so a container that is not
|
|
650
|
-
control-radius publishes its own and every row inside re-derives. era's
|
|
651
|
-
command palette does exactly that — it is rd-bar, so its rows resolve to
|
|
652
|
-
rd-bar − gap, which IS rd-control (control-inset-bar is the gutter), and the
|
|
653
|
-
palette's geometry is unchanged by this.
|
|
659
|
+
**Use it for:** the physical press contract on a control whose direct content plane is marked data-era-press-content. The surface owns relief/travel; the component may scale travel with --era-press-scale.
|
|
654
660
|
|
|
655
661
|
Declared in `index.css`.
|
|
656
662
|
|
|
657
663
|
```css
|
|
658
|
-
@utility
|
|
659
|
-
|
|
664
|
+
@utility pressable {
|
|
665
|
+
&:active {
|
|
666
|
+
box-shadow: var(--era-shadow-pressed);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
&:active > [data-era-press-content] {
|
|
670
|
+
translate: var(--era-press-effective-x, var(--era-press-sink-x))
|
|
671
|
+
var(--era-press-effective-y, var(--era-press-sink-y));
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
## tier-icon · tier-pill · tier-chip · tier-control · tier-bar
|
|
677
|
+
|
|
678
|
+
BOUNDED GEOMETRY — height and radius are one decision.
|
|
679
|
+
|
|
680
|
+
A tier is a geometric type, not two classes a caller must remember to keep in
|
|
681
|
+
sync. `tier-control` establishes h-control AND rd-control; the radius ladder
|
|
682
|
+
then guarantees rd_outer − rd_inner = (h_outer − h_inner)/2 for every pair.
|
|
683
|
+
Width remains the component's decision: a row stretches, a button adds
|
|
684
|
+
min-w-control, and a square control adds w-control.
|
|
685
|
+
|
|
686
|
+
Declared in `index.css`.
|
|
687
|
+
|
|
688
|
+
```css
|
|
689
|
+
@utility tier-icon {
|
|
690
|
+
height: var(--era-h-icon);
|
|
691
|
+
border-radius: var(--era-rd-icon);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
@utility tier-pill {
|
|
695
|
+
height: var(--era-h-pill);
|
|
696
|
+
border-radius: var(--era-rd-pill);
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
@utility tier-chip {
|
|
700
|
+
height: var(--era-h-chip);
|
|
701
|
+
border-radius: var(--era-rd-chip);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
@utility tier-control {
|
|
705
|
+
height: var(--era-h-control);
|
|
706
|
+
border-radius: var(--era-rd-control);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
@utility tier-bar {
|
|
710
|
+
height: var(--era-h-bar);
|
|
711
|
+
border-radius: var(--era-rd-bar);
|
|
660
712
|
}
|
|
661
713
|
```
|
|
662
714
|
|
|
@@ -681,6 +733,50 @@ Declared in `index.css`.
|
|
|
681
733
|
}
|
|
682
734
|
```
|
|
683
735
|
|
|
736
|
+
## era-track-well
|
|
737
|
+
|
|
738
|
+
**Use it for:** instead of `shadow-well` on a track whose value is painted by a child that covers the box — a progress/meter/slider track, a custom gauge. For a well holding ordinary content, `shadow-well` is still right.
|
|
739
|
+
|
|
740
|
+
A WELL THAT SURVIVES BEING FILLED.
|
|
741
|
+
|
|
742
|
+
`shadow-well` is an INSET shadow, and an inset shadow belongs to the
|
|
743
|
+
element's background layer — it paints under the element's own descendants.
|
|
744
|
+
That is invisible on a well holding text (a checkbox, a code block: the
|
|
745
|
+
chrome runs around the content) and wrong the moment something paints the
|
|
746
|
+
whole box. Meter, Progress and the Slider track all do exactly that: an
|
|
747
|
+
opaque child, `translateX`-ed to the value. So the well survived only where
|
|
748
|
+
the track was EMPTY — a half-full meter on bevel had a chisel to the right
|
|
749
|
+
of the value and none to the left, which reads as a hole with a sticker
|
|
750
|
+
over it rather than a level inside a well.
|
|
751
|
+
|
|
752
|
+
The fix is painting order, not geometry: the same `--era-shadow-well` on a
|
|
753
|
+
pseudo-element that is the element's LAST child, so it lands above the fill.
|
|
754
|
+
The fill still spans the full box — nothing is inset, no radius is
|
|
755
|
+
re-derived, and 0% and 100% keep their exact ends. The `position: relative`
|
|
756
|
+
is load-bearing (the overlay resolves against this box) and `inherit` on the
|
|
757
|
+
radius keeps it honest under `data-corners="square"`.
|
|
758
|
+
|
|
759
|
+
Surface-agnostic on purpose. It reads the same token every well reads, so
|
|
760
|
+
glass's hairline rim is restored by the same line that restores bevel's
|
|
761
|
+
chisel, and flat — where the token is `none` — renders exactly as before.
|
|
762
|
+
Reported against bevel by a consumer; it was never a bevel bug.
|
|
763
|
+
|
|
764
|
+
Declared in `index.css`.
|
|
765
|
+
|
|
766
|
+
```css
|
|
767
|
+
@utility era-track-well {
|
|
768
|
+
position: relative;
|
|
769
|
+
&::after {
|
|
770
|
+
content: '';
|
|
771
|
+
position: absolute;
|
|
772
|
+
inset: 0;
|
|
773
|
+
border-radius: inherit;
|
|
774
|
+
box-shadow: var(--era-shadow-well);
|
|
775
|
+
pointer-events: none;
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
```
|
|
779
|
+
|
|
684
780
|
## era-skeleton-pulse
|
|
685
781
|
|
|
686
782
|
Skeleton's pulse, on the MOTION AXIS.
|
|
@@ -1106,8 +1202,8 @@ Declared in `index.css`.
|
|
|
1106
1202
|
## bg-well · text-well · border-well · bg-elevated · text-elevated · border-elevated · bg-highlight · text-highlight · … (12 in all)
|
|
1107
1203
|
|
|
1108
1204
|
Surface fills — bg-well is the surface's own resting fill (pairs with
|
|
1109
|
-
shadow-well for recessed chrome), bg-elevated the raised tier
|
|
1110
|
-
|
|
1205
|
+
shadow-well for recessed chrome), bg-elevated the raised tier,
|
|
1206
|
+
bg-highlight the transient
|
|
1111
1207
|
hover/focus/keyboard wash (pairs with shadow-highlight; latched states
|
|
1112
1208
|
stay on opaque bg-hover), bg-overlay the modal scrim.
|
|
1113
1209
|
|
|
@@ -1170,7 +1266,7 @@ Declared in `index.css`.
|
|
|
1170
1266
|
}
|
|
1171
1267
|
```
|
|
1172
1268
|
|
|
1173
|
-
## p-icon-inset-pill · px-icon-inset-pill · py-icon-inset-pill · gap-icon-inset-pill · p-icon-inset-chip · px-icon-inset-chip · py-icon-inset-chip · gap-icon-inset-chip · … (
|
|
1269
|
+
## p-icon-inset-pill · px-icon-inset-pill · py-icon-inset-pill · gap-icon-inset-pill · p-icon-inset-chip · px-icon-inset-chip · py-icon-inset-chip · gap-icon-inset-chip · … (40 in all)
|
|
1174
1270
|
|
|
1175
1271
|
**Use it for:** the concentric inset for a nested pair — (h-container − h-child)/2, the gap that makes a child control sit evenly inside its container, and the radius step that keeps their corners concentric. Named for the pair it joins: gap-icon-inset-control seats an icon in a control.
|
|
1176
1272
|
|
|
@@ -1187,6 +1283,7 @@ Declared in `index.css`.
|
|
|
1187
1283
|
--spacing-pill-inset-bar: var(--era-pill-inset-bar);
|
|
1188
1284
|
--spacing-chip-inset-control: var(--era-chip-inset-control);
|
|
1189
1285
|
--spacing-chip-inset-bar: var(--era-chip-inset-bar);
|
|
1286
|
+
--spacing-control-inset-bar: var(--era-control-inset-bar);
|
|
1190
1287
|
}
|
|
1191
1288
|
```
|
|
1192
1289
|
|
|
@@ -1265,7 +1362,7 @@ Declared in `index.css`.
|
|
|
1265
1362
|
}
|
|
1266
1363
|
```
|
|
1267
1364
|
|
|
1268
|
-
## bg-fill · text-fill · border-fill · bg-link · text-link · border-link · bg-primary · text-primary · … (
|
|
1365
|
+
## bg-fill · text-fill · border-fill · bg-link · text-link · border-link · bg-primary · text-primary · … (39 in all)
|
|
1269
1366
|
|
|
1270
1367
|
The standing pill fill — --era-fill, the latched counterpart of the
|
|
1271
1368
|
transient highlight. Surface-owned: a composing wash on flat/bevel, the
|
|
@@ -1286,6 +1383,8 @@ Declared in `index.css`.
|
|
|
1286
1383
|
--color-success-fg: var(--color-success-fg);
|
|
1287
1384
|
--color-warning: var(--color-warning);
|
|
1288
1385
|
--color-warning-fg: var(--color-warning-fg);
|
|
1386
|
+
--color-info: var(--color-info);
|
|
1387
|
+
--color-info-fg: var(--color-info-fg);
|
|
1289
1388
|
}
|
|
1290
1389
|
```
|
|
1291
1390
|
|
|
@@ -1456,7 +1555,7 @@ Inherits all props from `HTMLAttributes<HTMLSpanElement>`.
|
|
|
1456
1555
|
| Prop | Type | Default | Notes |
|
|
1457
1556
|
|------|------|---------|-------|
|
|
1458
1557
|
| `ref?` | `HTMLSpanElement \| null` | `null` | bindable |
|
|
1459
|
-
| `tone?` | `'default' \| 'accent' \| 'destructive' \| 'success' \| 'warning'` | `'default'` | — |
|
|
1558
|
+
| `tone?` | `'default' \| 'accent' \| 'destructive' \| 'success' \| 'warning' \| 'info'` | `'default'` | — |
|
|
1460
1559
|
| `lead?` | `Snippet` | — | Icon rendered BEFORE the label, outside it. Use this rather than putting
|
|
1461
1560
|
an icon in `children`: the label then gets its own box, which is the only
|
|
1462
1561
|
place era's ink centring can reach. |
|
|
@@ -1547,10 +1646,28 @@ Inherits all props from `HTMLAttributes<HTMLDivElement>`.
|
|
|
1547
1646
|
|------|------|---------|-------|
|
|
1548
1647
|
| `ref?` | `HTMLDivElement \| null` | `null` | bindable |
|
|
1549
1648
|
| `size?` | `'chip' \| 'control' \| 'bar'` | `'bar'` | Height tier (scales with density). Default `lg` — a full toolbar. |
|
|
1550
|
-
| `content?` | `
|
|
1551
|
-
stay concentric to them.
|
|
1552
|
-
the
|
|
1553
|
-
| `divider?` | `boolean` | `false` | The flush cap-a-panel chrome: outset
|
|
1649
|
+
| `content?` | `BarContent` | — | Tier of the controls inside — drives the bar's padding and gap so they
|
|
1650
|
+
stay concentric to them. Omit this for the next canonical rung, or name
|
|
1651
|
+
the actual tier when the contents are smaller. |
|
|
1652
|
+
| `divider?` | `boolean` | `false` | The flush cap-a-panel chrome: an outset rule below, and a rounded
|
|
1653
|
+
BOTTOM only — the top defers to the panel's own radius.
|
|
1654
|
+
THE BOTTOM RADIUS IS LOAD-BEARING FOR THE RULE. The divider is an
|
|
1655
|
+
outset `box-shadow`, so it follows the box's corners: the rounded
|
|
1656
|
+
bottom is what curves the line up at the ends and makes the bar read
|
|
1657
|
+
as a long pill. Overriding the radius therefore changes the RULE, not
|
|
1658
|
+
just the corners. Measured against `cn`:
|
|
1659
|
+
- `rounded-none` drops both — a square bar with a dead-straight rule.
|
|
1660
|
+
That is the intended square mode (an in-app Notes bar passes it).
|
|
1661
|
+
- `rounded-b-*` or `rounded-b-none` replaces the curve — this is the
|
|
1662
|
+
one that surprises, because the rule changes shape when the caller
|
|
1663
|
+
thought they were only squaring a corner.
|
|
1664
|
+
- `rounded-t-*` is SAFE: it wins against `rounded-t-none` and leaves
|
|
1665
|
+
`rounded-b-control` standing, so the curve survives.
|
|
1666
|
+
A consumer lost the curve this way. The coupling was already written
|
|
1667
|
+
down — on the variant, inside `<script module>`, where someone
|
|
1668
|
+
hovering this prop never reaches it. Docs are only as good as the
|
|
1669
|
+
place the reader is standing. |
|
|
1670
|
+
| `topology?` | `'nested' \| 'docked'` | `'nested'` | `docked` removes one or more exposed curves; strict radius nesting does not apply. |
|
|
1554
1671
|
| `children?` | `Snippet` | — | — |
|
|
1555
1672
|
|
|
1556
1673
|
<!-- end: bar -->
|
|
@@ -1580,7 +1697,7 @@ Inherits all props from `HTMLAttributes<HTMLElement>`.
|
|
|
1580
1697
|
|------|------|---------|-------|
|
|
1581
1698
|
| `ref?` | `HTMLElement \| null` | `null` | bindable |
|
|
1582
1699
|
| `size?` | `'chip' \| 'control' \| 'bar'` | `'bar'` | Height tier, exactly as Bar's — the geometry is Bar's, not a second copy. |
|
|
1583
|
-
| `content?` | `
|
|
1700
|
+
| `content?` | `BarContent` | — | Tier of the items inside, so the wall stays concentric to them. |
|
|
1584
1701
|
| `divider?` | `boolean` | `false` | Draw Bar's flush cap-a-panel rule beneath the bar. Off by default,
|
|
1585
1702
|
because a nav that sits in a page already has whatever separation the
|
|
1586
1703
|
layout gives it — and a link-variant nav in particular reads as text,
|
|
@@ -1605,6 +1722,13 @@ Inherits all props from `HTMLAnchorAttributes`.
|
|
|
1605
1722
|
drops the chrome entirely and renders running text, for a primary nav
|
|
1606
1723
|
that should read as links rather than a row of raised keycaps. Existing
|
|
1607
1724
|
bars are byte-identical. |
|
|
1725
|
+
| `currentCue?` | `'thickness' \| 'ink' \| 'none'` | `'thickness'` | WHAT MARKS THE CURRENT ITEM. `thickness` (default) is the three-state
|
|
1726
|
+
decoration — portable across every theme and font because it is one
|
|
1727
|
+
ink at three strengths. `ink` brightens the current item instead, and
|
|
1728
|
+
is theme-dependent by construction: era's default themes point
|
|
1729
|
+
--color-link at --color-bright, so its delta there is zero. `none`
|
|
1730
|
+
silences era's cue entirely, for a consumer painting their own.
|
|
1731
|
+
See navItemVariants above for the measurements behind each. |
|
|
1608
1732
|
| `current?` | `boolean` | `false` | Whether this item points at the page you are on.
|
|
1609
1733
|
There is deliberately no `active` prop beside this one. `active` would
|
|
1610
1734
|
be a second source of truth for one fact, and the two drift the moment
|
|
@@ -1644,14 +1768,47 @@ Inherits all props from `Button.RootProps`.
|
|
|
1644
1768
|
|
|
1645
1769
|
| Prop | Type | Default | Notes |
|
|
1646
1770
|
|------|------|---------|-------|
|
|
1647
|
-
| `tone?` | `'default' \| 'accent' \| 'destructive' \| 'success' \| 'warning'` | `'default'` | — |
|
|
1771
|
+
| `tone?` | `'default' \| 'accent' \| 'destructive' \| 'success' \| 'warning' \| 'info'` | `'default'` | — |
|
|
1648
1772
|
| `size?` | `'control' \| 'chip' \| 'pill' \| 'icon'` | `'control'` | — |
|
|
1649
1773
|
| `variant?` | `'filled' \| 'link'` | `'filled'` | — |
|
|
1650
1774
|
| `active?` | `boolean` | `false` | — |
|
|
1651
1775
|
| `icon?` | `boolean` | `false` | — |
|
|
1652
|
-
| `loading?` | `boolean` | `false` |
|
|
1653
|
-
|
|
1654
|
-
|
|
1776
|
+
| `loading?` | `boolean` | `false` | In flight: disables the button, sets `aria-busy`, and puts a spinner
|
|
1777
|
+
over the label.
|
|
1778
|
+
THE GEOMETRY DOES NOT MOVE. That is the requirement, not a detail. A
|
|
1779
|
+
button is loading because it was just CLICKED, so anything `loading`
|
|
1780
|
+
changes about the box moves the page under the pointer that is still
|
|
1781
|
+
on it — and a spinner PREPENDED to the label (what this used to do)
|
|
1782
|
+
costs an icon's width plus a gap, measured on a wrapping header row
|
|
1783
|
+
that reflowed everything beside it. A consumer hit exactly that and
|
|
1784
|
+
stopped using the prop, hand-rolling `disabled` + `aria-busy`
|
|
1785
|
+
instead, which is the report that produced this note.
|
|
1786
|
+
So the spinner is absolutely positioned and takes no part in the
|
|
1787
|
+
flex layout, and the label goes to `opacity-0` rather than being
|
|
1788
|
+
unmounted: the box that holds the width stays, and the text stays in
|
|
1789
|
+
the accessibility tree as the button's accessible name.
|
|
1790
|
+
The visible label is therefore HIDDEN in flight — the one thing this
|
|
1791
|
+
trades away, and the reason `loadingLabel` exists.
|
|
1792
|
+
IF YOU DO NOT WANT A SPINNER, use `busy`. Not showing one is a
|
|
1793
|
+
supported posture, not a legacy one — see that prop. |
|
|
1794
|
+
| `busy?` | `boolean` | `false` | In flight, WITHOUT a spinner: disables the button and sets `aria-busy`,
|
|
1795
|
+
and changes nothing else. The label stays visible and legible.
|
|
1796
|
+
This exists because "show a spinner" is a taste, not a requirement,
|
|
1797
|
+
and era had only one answer. A consumer whose house style is that
|
|
1798
|
+
spinners should not appear had to spell the posture out themselves —
|
|
1799
|
+
`disabled` plus a restated `aria-busy` — and rely on knowing that
|
|
1800
|
+
`restProps` spreads last, which is a real fact about this component
|
|
1801
|
+
that no reader should have to depend on. Two words for two postures
|
|
1802
|
+
is clearer than one word plus a workaround.
|
|
1803
|
+
`loading` implies this: it is `busy` plus the spinner and the hidden
|
|
1804
|
+
label. What you get from `busy` alone is a control that is visibly
|
|
1805
|
+
disabled (the era-interactive opacity) and announced as busy, with
|
|
1806
|
+
its geometry and its ink untouched — which is also why it needs no
|
|
1807
|
+
`loadingLabel`: nothing about the button changed except that you
|
|
1808
|
+
cannot press it.
|
|
1809
|
+
Reported by a consumer whose user asked for no spinners anywhere.
|
|
1810
|
+
They were right that a fix for the width shift did not answer it: a
|
|
1811
|
+
spinner that no longer moves its neighbours is still a spinner. |
|
|
1655
1812
|
| `loadingLabel?` | `string` | — | Screen-reader-only label announced while `loading` is true. |
|
|
1656
1813
|
| `lead?` | `Snippet` | — | Icon rendered BEFORE the label, outside it. Use this rather than putting
|
|
1657
1814
|
an icon in `children`: the label then gets its own box, which is the only
|
|
@@ -1689,6 +1846,7 @@ snippet's text cannot be read before it renders.
|
|
|
1689
1846
|
Only reaches the label when `lead`/`trail` give it its own box. Without
|
|
1690
1847
|
one the label is an anonymous flex item that no selector can address,
|
|
1691
1848
|
which is the whole reason those snippets exist. |
|
|
1849
|
+
| `topology?` | `'bounded' \| 'docked'` | `'bounded'` | `docked` joins this control to a neighbour and removes one or more curves. |
|
|
1692
1850
|
| `children?` | `Snippet` | — | — |
|
|
1693
1851
|
| `ref?` | `(forwarded)` | `null` | bindable |
|
|
1694
1852
|
|
|
@@ -1799,11 +1957,41 @@ Inherits all props from `ButtonBits`.
|
|
|
1799
1957
|
|------|------|---------|-------|
|
|
1800
1958
|
| `ref?` | `CardElement \| null` | `null` | bindable |
|
|
1801
1959
|
| `tone?` | `'elevated' \| 'surface' \| 'well' \| 'flat'` | `'elevated'` | Surface tier the card paints on.
|
|
1802
|
-
- `elevated` (default): the lifted surface
|
|
1803
|
-
|
|
1804
|
-
- `
|
|
1805
|
-
|
|
1806
|
-
- `
|
|
1960
|
+
- `elevated` (default): the lifted surface, with a resting shadow. Use
|
|
1961
|
+
on the page background.
|
|
1962
|
+
- `surface`: the base surface tier, no shadow. Use when nesting cards
|
|
1963
|
+
inside another elevated container.
|
|
1964
|
+
- `well`: recessed. For content the surrounding UI puts INTO the card —
|
|
1965
|
+
a tool's output pane, a transcript body — the container twin of a
|
|
1966
|
+
text field's fill.
|
|
1967
|
+
- `flat`: no background; only the rounded/padded shell. For grouping
|
|
1968
|
+
content visually without adding contrast.
|
|
1969
|
+
READ THE CLASSES AND THEY LOOK SWAPPED. They are not, and this is
|
|
1970
|
+
worth a sentence because a consumer read them, believed it, and
|
|
1971
|
+
shipped flat cards for months. `surface` paints `bg-well` and `well`
|
|
1972
|
+
paints `bg-field`, because era's utility names describe FILLS rather
|
|
1973
|
+
than tiers: `bg-well` is the surface's own resting fill (it is what a
|
|
1974
|
+
panel is painted with, and it pairs with `shadow-well` when you want
|
|
1975
|
+
recessed chrome), and `bg-field` is the recessed fill a text input
|
|
1976
|
+
sits in. The tone names are the tiers; the class names are the paints.
|
|
1977
|
+
A CARD THAT IS PRESSABLE SHOULD USUALLY BE `elevated`. Passing `href`
|
|
1978
|
+
or `onclick` turns on the interactive face — hover, focus, press — but
|
|
1979
|
+
it deliberately does NOT override the tier you asked for, so a
|
|
1980
|
+
`surface` link card does not get the raised tier's separation and can
|
|
1981
|
+
read flatter than the static cards around it. That combination was
|
|
1982
|
+
reported as a bug and it is a choice: a tone that silently changed
|
|
1983
|
+
under an event handler would be a worse one.
|
|
1984
|
+
HOW THE TIERS DIFFER IS SURFACE-DEPENDENT, so do not go looking for a
|
|
1985
|
+
fill difference on every surface. `base` mixes the elevated fill 6%
|
|
1986
|
+
toward `--color-bright` and adds a resting shadow, so there the tiers
|
|
1987
|
+
differ in COLOUR. `bevel` sets `--era-surface-bg-elevated` to
|
|
1988
|
+
`--era-surface-bg` outright — elevation is a chisel, not a tone, which
|
|
1989
|
+
is bevel's whole premise — so `surface` and `elevated` paint the
|
|
1990
|
+
IDENTICAL fill there and differ only in relief. A consumer measured
|
|
1991
|
+
exactly that on 30.8.0 bevel: both tones `oklch(0.195 0 none)` in dark,
|
|
1992
|
+
`0.863` in light, one variable, side by side. `glass` splits the tiers
|
|
1993
|
+
its own way again. So the tier is real on every surface; the thing
|
|
1994
|
+
carrying it is not always the fill. |
|
|
1807
1995
|
| `header?` | `Snippet` | — | Rendered above the body with a subtle divider. |
|
|
1808
1996
|
| `footer?` | `Snippet` | — | Rendered below the body with a subtle divider. |
|
|
1809
1997
|
| `children?` | `Snippet` | — | — |
|
|
@@ -1832,6 +2020,22 @@ Inherits all props from `HTMLAttributes<HTMLDivElement>`.
|
|
|
1832
2020
|
| `size?` | `'chip' \| 'pill'` | `'chip'` | `sm` (default) is the standalone free chip; `pill` is the smaller pill
|
|
1833
2021
|
that nests inside an md container (a select trigger, a button). |
|
|
1834
2022
|
| `ondismiss?` | `() => void` | — | — |
|
|
2023
|
+
| `dismissAs?` | `'button' \| 'span'` | `'button'` | What the dismiss control RENDERS AS. `button` (the default) is right
|
|
2024
|
+
for a free-standing chip. Use `span` when the chip lives inside
|
|
2025
|
+
another control.
|
|
2026
|
+
A <button> inside a <button> is not merely bad manners: it is invalid,
|
|
2027
|
+
and the HTML parser repairs it by CLOSING the outer control before the
|
|
2028
|
+
inner one. So the server's markup and the client's DOM disagree, Svelte
|
|
2029
|
+
discards the page's hydration and re-renders from scratch, and the
|
|
2030
|
+
chips briefly sit outside the trigger they belong to. era's own
|
|
2031
|
+
multi-select shipped exactly that (a Chip with `ondismiss` inside
|
|
2032
|
+
Select.Trigger) and logged node_invalid_placement_ssr on every load.
|
|
2033
|
+
`span` also drops the control from the accessibility tree rather than
|
|
2034
|
+
announcing a button inside a button — which is the honest description
|
|
2035
|
+
of what it is there: a pointer shortcut. The accessible way to remove
|
|
2036
|
+
a selection is the listbox itself, which is unaffected. Keyboard focus
|
|
2037
|
+
order is unchanged, because a nested button was never reachable in a
|
|
2038
|
+
sensible order anyway. |
|
|
1835
2039
|
| `lead?` | `Snippet` | — | Icon rendered BEFORE the label, outside it. Use this rather than putting
|
|
1836
2040
|
an icon in `children`: the label then gets its own box, which is the only
|
|
1837
2041
|
place era's ink centring can reach. |
|
|
@@ -1997,6 +2201,24 @@ Inherits all props from `Separator.RootProps`.
|
|
|
1997
2201
|
| Prop | Type | Default | Notes |
|
|
1998
2202
|
|------|------|---------|-------|
|
|
1999
2203
|
| `variant?` | `'line' \| 'slant'` | `'line'` | Use `slant` for inline dividers in breadcrumbs, titles, and compact metadata. |
|
|
2204
|
+
| `size?` | `keyof typeof SIZES` | — | Give a VERTICAL rule a height of its own, from the tier ladder, instead
|
|
2205
|
+
of stretching to whatever line it lands in. Ignored when horizontal.
|
|
2206
|
+
WHY YOU WOULD WANT IT. A stretched rule is a passenger: it has no
|
|
2207
|
+
intrinsic height, so it measures whatever its neighbours measure and
|
|
2208
|
+
contributes nothing back. That is right inside a Bar, whose height is
|
|
2209
|
+
already fixed — and it is why a rule in an auto-height row cannot hold
|
|
2210
|
+
that row's height steady. A consumer whose site header gained and lost
|
|
2211
|
+
a qualifier between pages watched the chrome resize, and pinned a
|
|
2212
|
+
`min-h-[calc(...)]` on the header to stop it. Sizing the rule removes
|
|
2213
|
+
that calc: it becomes the piece that stands the row up.
|
|
2214
|
+
(For the record, since the report named the wrong mechanism: a
|
|
2215
|
+
stretched rule does not GROW its row. Measured in an 18px auto-height
|
|
2216
|
+
row, adding one leaves the row at 18px and the rule resolves to 10px —
|
|
2217
|
+
the line minus its two gutter margins. It can only ever be shorter
|
|
2218
|
+
than the row it divides, which is the whole problem here.)
|
|
2219
|
+
A sized rule drops the gutter margins with the stretch: the height is
|
|
2220
|
+
now a deliberate number, and silently adding 2 x gutter to it would
|
|
2221
|
+
make it the one element on the page you cannot reason about. |
|
|
2000
2222
|
| `ref?` | `(forwarded)` | `null` | bindable |
|
|
2001
2223
|
|
|
2002
2224
|
## Usage
|
|
@@ -3910,12 +4132,90 @@ Inherits all props from `Meter.RootProps`.
|
|
|
3910
4132
|
|
|
3911
4133
|
| Prop | Type | Default | Notes |
|
|
3912
4134
|
|------|------|---------|-------|
|
|
3913
|
-
| `tone?` | `'default' \| 'accent' \| 'destructive' \| 'success' \| 'warning'` | `'default'` | The band this reading falls in. Tone is the fill's colour only — the
|
|
4135
|
+
| `tone?` | `'default' \| 'accent' \| 'destructive' \| 'success' \| 'warning' \| 'info'` | `'default'` | The band this reading falls in. Tone is the fill's colour only — the
|
|
3914
4136
|
track stays neutral, because the well belongs to the control and the
|
|
3915
4137
|
fill belongs to the value.
|
|
3916
4138
|
Tone carries no semantics on its own: a meter in the destructive band
|
|
3917
4139
|
still needs an accessible label saying what has run out. Pair it with
|
|
3918
4140
|
`aria-label` / a visible label, never rely on the hue alone. |
|
|
4141
|
+
| `threshold?` | `number` | — | A BOUNDARY INSIDE THE RANGE — in the same units as `value`, not a
|
|
4142
|
+
percentage. A quota with a soft limit before the hard one; a plan that
|
|
4143
|
+
includes 30 hours of the 50 it bills against; a temperature that is
|
|
4144
|
+
fine until it is not. The bar fills against `max`, and the mark says
|
|
4145
|
+
where the number the reader is actually deciding about sits.
|
|
4146
|
+
WHY THE MARK HAS NO COLOUR OF ITS OWN. It has to read against both
|
|
4147
|
+
sides of itself: over the empty track before the value reaches it, and
|
|
4148
|
+
over the fill afterwards. One token cannot do that — a colour tuned
|
|
4149
|
+
against the track disappears into the fill the moment the value
|
|
4150
|
+
crosses, which is exactly what a consumer hit hand-rolling this. So
|
|
4151
|
+
the mark is painted in the colour of the side it is NOT on: the fill's
|
|
4152
|
+
paint while the value is short of it, the track's fill once the value
|
|
4153
|
+
has passed. That contrast is not a new promise — it is the meter's
|
|
4154
|
+
own. A fill that did not stand out from its track would not be a
|
|
4155
|
+
meter, so borrowing the pair is the one choice that cannot be wrong in
|
|
4156
|
+
a theme, a tone, or a surface era has not seen.
|
|
4157
|
+
IT IS DECORATION, and silent on purpose. There is no `role` and
|
|
4158
|
+
nothing to announce: a screen reader gets `value`/`min`/`max` and the
|
|
4159
|
+
meter's own accessible name, and a boundary it cannot position adds
|
|
4160
|
+
nothing. If the threshold is part of the reading — it usually is —
|
|
4161
|
+
put the figure in `aria-label` and in a caption, where it is a number
|
|
4162
|
+
rather than a position.
|
|
4163
|
+
PASS `aria-valuetext` IF YOUR STORED UNIT IS NOT YOUR DISPLAYED ONE.
|
|
4164
|
+
`value`, `max` and `threshold` all have to sit in one unit for this
|
|
4165
|
+
arithmetic to work, and `aria-valuenow` is `value` verbatim — so a bar
|
|
4166
|
+
stored in minutes and read in hours announces "2640 of 3000", a figure
|
|
4167
|
+
the customer was never quoted. Converting the props is not available
|
|
4168
|
+
to you (it would move the mark), which makes `aria-valuetext` the only
|
|
4169
|
+
lever; it passes through `restProps` onto the same element. Reported
|
|
4170
|
+
by a consumer billing minutes and quoting hours.
|
|
4171
|
+
Outside `[min, max]` it renders NOTHING rather than clamping to an
|
|
4172
|
+
end, because a mark pinned to the edge of the bar would claim a
|
|
4173
|
+
boundary that is not in the range. |
|
|
4174
|
+
| `buffer?` | `number` | — | A REGION FROM `min` THAT IS A DIFFERENT KIND OF QUANTITY — painted
|
|
4175
|
+
under the fill, over the track, in the same units as `value`.
|
|
4176
|
+
The media player's buffered-progress shape, and the name is borrowed
|
|
4177
|
+
from it, but the reading is more general: some of the range is already
|
|
4178
|
+
accounted for. A plan whose first 30 of 50 hours are included in the
|
|
4179
|
+
monthly minimum is not "24 hours into a bill", it is "24 of 30 hours
|
|
4180
|
+
you have already paid for" — money spent against money that will be
|
|
4181
|
+
spent, which is a distinction the bar could not draw.
|
|
4182
|
+
NO COLOUR OF ITS OWN, for the reason `threshold` has none: it has to
|
|
4183
|
+
be legible over the track while never competing with the fill that
|
|
4184
|
+
crosses it, and a token tuned for one of those is wrong for the other.
|
|
4185
|
+
It is the fill's own paint at 30%, so it cannot be wrong in a theme,
|
|
4186
|
+
a tone or a surface era has not seen, and it is the same 30% Slider's
|
|
4187
|
+
`progress` has used for a seek bar's buffer since it shipped.
|
|
4188
|
+
UNDER the fill, so it disappears as the value consumes it. That is the
|
|
4189
|
+
reading, not a limitation: once you are past your included hours, the
|
|
4190
|
+
included region IS spent, and `threshold` is what goes on marking
|
|
4191
|
+
where it ended.
|
|
4192
|
+
CLAMPED to the range rather than dropped, which is where it differs
|
|
4193
|
+
from `threshold`. A region can be honestly truncated — a buffer past
|
|
4194
|
+
`max` means the whole visible bar is accounted for, and painting it
|
|
4195
|
+
all says exactly that. A point cannot: a mark pinned to the edge would
|
|
4196
|
+
claim a boundary that is not in the range, so an out-of-range
|
|
4197
|
+
`threshold` renders nothing instead.
|
|
4198
|
+
Silent, like the mark. `aria-valuetext` already carries the reading,
|
|
4199
|
+
and a second region a screen reader cannot position adds nothing.
|
|
4200
|
+
(Slider spells its equivalent `progress` and takes a 0–1 FRACTION.
|
|
4201
|
+
Here every positional prop is in the value's own units — `value`,
|
|
4202
|
+
`max`, `threshold`, `buffer` — because a component that mixed the two
|
|
4203
|
+
would be a bug generator. The names differ because on a Meter
|
|
4204
|
+
`progress` would be a synonym for `value`.) |
|
|
4205
|
+
| `start?` | `Snippet` | — | Captions under the two ends of the bar — what the range MEANS.
|
|
4206
|
+
A meter states a proportion and leaves the reader to work out what of.
|
|
4207
|
+
"0m used" on the left and "50h before approval" on the right is not
|
|
4208
|
+
decoration, it is the reading; every consumer of a bare meter ends up
|
|
4209
|
+
hand-rolling the same flex row underneath it, which is where this came
|
|
4210
|
+
from. `start` is left, `end` is right, either may stand alone.
|
|
4211
|
+
NOT ANNOUNCED. They are captions, so a screen reader gets the meter's
|
|
4212
|
+
value and its own `aria-label`, not these. If the range needs saying
|
|
4213
|
+
out loud, say it in the label too — the same rule `tone` carries.
|
|
4214
|
+
THE DOM IS UNCHANGED WITHOUT THEM. With neither snippet this renders
|
|
4215
|
+
exactly the element it always did, so `class` still lands on the track
|
|
4216
|
+
and the geometry audits still walk the same box. Passing one wraps the
|
|
4217
|
+
track in a column, and `class` still lands on the track. |
|
|
4218
|
+
| `end?` | `Snippet` | — | — |
|
|
3919
4219
|
| `ref?` | `(forwarded)` | `null` | bindable |
|
|
3920
4220
|
|
|
3921
4221
|
<!-- end: meter -->
|