@signal9/era-ui 2.26.0 → 2.27.1
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/dist/dev/audit/audits/collapsed-text-trim.js +44 -16
- package/dist/docs/button.md +1 -0
- package/dist/docs/css-utilities.d.ts +21 -0
- package/dist/docs/css-utilities.js +124 -0
- package/dist/docs/generated-docs.d.ts +2 -0
- package/dist/docs/generated-docs.js +7 -0
- package/dist/docs/index.js +4 -0
- package/dist/docs/llms-txt.js +17 -1
- package/dist/docs/scroll-area.md +7 -0
- package/dist/docs/utilities.d.ts +4 -0
- package/dist/docs/utilities.js +15 -0
- package/dist/era-ui.css +1 -1
- package/dist/generated-docs/button.md +1 -0
- package/dist/generated-docs/llms-full.txt +224 -1
- package/dist/generated-docs/llms.txt +15 -1
- package/dist/generated-docs/manifest.json +72 -3
- package/dist/generated-docs/scroll-area.md +8 -0
- package/dist/generated-docs/utilities.json +53 -0
- package/dist/generated-docs/utilities.md +195 -0
- package/dist/styles/index.css +44 -15
- package/dist/styles/surfaces/glass.css +5 -1
- package/dist/ui/input/input.svelte +5 -1
- package/package.json +3 -2
- package/skill/SKILL.md +17 -0
|
@@ -29,7 +29,21 @@ Every component has a passive markdown doc at `/<slug>.md`.
|
|
|
29
29
|
Examples: `/button.md`, `/select.md`, `/table.md`.
|
|
30
30
|
Full concatenated reference: `/llms-full.txt`.
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
## CSS utilities
|
|
33
|
+
|
|
34
|
+
Classes, not components — they need no import beyond the stylesheet. Reach for one of these before hand-rolling the same styling or bending a component into the role.
|
|
35
|
+
|
|
36
|
+
- `era-interactive` — the focus/disabled recipe every era control carries — put it on a custom interactive element instead of hand-writing focus/disabled variants.
|
|
37
|
+
- `era-link` — understated, motion-aware inline text link — the canonical style for a link in body copy or prose; prefer it over a hand-rolled underline or `Button variant="link"` (which is a control, not running text).
|
|
38
|
+
- `scrollbar-none` — hide the scrollbar on an overflowing strip or rail while keeping it scrollable — for a scroll region that should show its bar, use ScrollArea.
|
|
39
|
+
- `era-text-trim` — vertically center single-line control text (a label beside an icon, an input's own text) without a translateY nudge — fixed-height elements only; see era-text-trim-caps for ALL-CAPS strings.
|
|
40
|
+
- `era-text-trim-caps` — the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never use it for mixed-case text.
|
|
41
|
+
- `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.
|
|
42
|
+
- `glass-blur` — the backdrop blur for a floating panel (popover, dialog, taskbar) — it applies only inside a data-surface="glass" subtree and is inert elsewhere, so it is safe to leave on a panel that renders under every surface.
|
|
43
|
+
|
|
44
|
+
Full reference (what each emits, when to use it): `/utilities.md`. Machine-readable list: `/utilities.json`.
|
|
45
|
+
|
|
46
|
+
<!-- Full component documentation, concatenated. The utilities page below carries the CSS each utility emits. -->
|
|
33
47
|
|
|
34
48
|
<!-- begin: about -->
|
|
35
49
|
|
|
@@ -71,6 +85,206 @@ Copy-paste text styling — headings, prose, emphasis, and motion-aware links.
|
|
|
71
85
|
|
|
72
86
|
<!-- end: text -->
|
|
73
87
|
|
|
88
|
+
<!-- begin: utilities -->
|
|
89
|
+
|
|
90
|
+
# Utilities
|
|
91
|
+
|
|
92
|
+
The CSS classes era ships alongside the components — links, ink-centred text, shimmer, hidden scrollbars.
|
|
93
|
+
|
|
94
|
+
## Overview
|
|
95
|
+
|
|
96
|
+
era ships a handful of Tailwind v4 `@utility` classes for the patterns that are
|
|
97
|
+
styling, not components — an inline link, ink-centred control text, a hidden
|
|
98
|
+
scrollbar. They need no import: they ride along with the stylesheet.
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import "@sig-nine/era-ui/css";
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```svelte
|
|
105
|
+
<a class="era-link" href="/spacing">the spacing ladder</a>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
| Utility | Use it for |
|
|
109
|
+
|---|---|
|
|
110
|
+
| `era-interactive` | the focus/disabled recipe every era control carries — put it on a custom interactive element instead of hand-writing focus/disabled variants. |
|
|
111
|
+
| `era-link` | understated, motion-aware inline text link — the canonical style for a link in body copy or prose; prefer it over a hand-rolled underline or `Button variant="link"` (which is a control, not running text). |
|
|
112
|
+
| `scrollbar-none` | hide the scrollbar on an overflowing strip or rail while keeping it scrollable — for a scroll region that should show its bar, use ScrollArea. |
|
|
113
|
+
| `era-text-trim` | vertically center single-line control text (a label beside an icon, an input's own text) without a translateY nudge — fixed-height elements only; see era-text-trim-caps for ALL-CAPS strings. |
|
|
114
|
+
| `era-text-trim-caps` | the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never use it for mixed-case text. |
|
|
115
|
+
| `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. |
|
|
116
|
+
| `glass-blur` | the backdrop blur for a floating panel (popover, dialog, taskbar) — it applies only inside a data-surface="glass" subtree and is inert elsewhere, so it is safe to leave on a panel that renders under every surface. |
|
|
117
|
+
|
|
118
|
+
## era-interactive
|
|
119
|
+
|
|
120
|
+
**Use it for:** the focus/disabled recipe every era control carries — put it on a custom interactive element instead of hand-writing focus/disabled variants.
|
|
121
|
+
|
|
122
|
+
Shared interactive-state recipe: quiet focus, disabled affordance.
|
|
123
|
+
Equivalent to `focus:outline-none disabled:cursor-not-allowed disabled:opacity-50`.
|
|
124
|
+
|
|
125
|
+
Declared in `index.css`.
|
|
126
|
+
|
|
127
|
+
```css
|
|
128
|
+
@utility era-interactive {
|
|
129
|
+
&:focus {
|
|
130
|
+
outline: none;
|
|
131
|
+
}
|
|
132
|
+
&:disabled {
|
|
133
|
+
cursor: not-allowed;
|
|
134
|
+
opacity: 0.5;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## era-link
|
|
140
|
+
|
|
141
|
+
**Use it for:** understated, motion-aware inline text link — the canonical style for a link in body copy or prose; prefer it over a hand-rolled underline or `Button variant="link"` (which is a control, not running text).
|
|
142
|
+
|
|
143
|
+
Inline text link. An understated, permanent underline that darkens from
|
|
144
|
+
muted to the text colour on hover — no layout shift, no appearing/vanishing
|
|
145
|
+
underline. The colour fade rides the MOTION axis (--era-duration/-ease), so
|
|
146
|
+
it snaps at data-motion="instant", eases at "normal", and sweeps longer at
|
|
147
|
+
"extra" — matching every other era transition. Font-agnostic: it styles
|
|
148
|
+
decoration + colour only, so it reads correctly in mono, sans, or serif, and
|
|
149
|
+
the 0.2em offset scales with the type size. Keyboard focus mirrors hover so
|
|
150
|
+
the affordance is reachable without a pointer.
|
|
151
|
+
|
|
152
|
+
Declared in `index.css`.
|
|
153
|
+
|
|
154
|
+
```css
|
|
155
|
+
@utility era-link {
|
|
156
|
+
/* The text is bright at rest and never changes — the link reads as a link
|
|
157
|
+
* before you touch it. Only the UNDERLINE reacts: a faint half-strength-muted
|
|
158
|
+
* hint at rest that resolves to the full text colour on hover. */
|
|
159
|
+
color: var(--color-bright);
|
|
160
|
+
text-decoration-line: underline;
|
|
161
|
+
text-decoration-color: color-mix(in oklch, var(--color-muted) 50%, transparent);
|
|
162
|
+
text-underline-offset: 0.2em;
|
|
163
|
+
transition: text-decoration-color var(--era-duration) var(--era-ease);
|
|
164
|
+
&:hover,
|
|
165
|
+
&:focus-visible {
|
|
166
|
+
text-decoration-color: var(--color-fg);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## scrollbar-none
|
|
172
|
+
|
|
173
|
+
**Use it for:** hide the scrollbar on an overflowing strip or rail while keeping it scrollable — for a scroll region that should show its bar, use ScrollArea.
|
|
174
|
+
|
|
175
|
+
Scrollable but chromeless — hides the scrollbar while keeping wheel / touch /
|
|
176
|
+
drag scrolling (e.g. an overflowing tab strip in a small pane handle).
|
|
177
|
+
|
|
178
|
+
Declared in `index.css`.
|
|
179
|
+
|
|
180
|
+
```css
|
|
181
|
+
@utility scrollbar-none {
|
|
182
|
+
scrollbar-width: none;
|
|
183
|
+
&::-webkit-scrollbar {
|
|
184
|
+
display: none;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## era-text-trim
|
|
190
|
+
|
|
191
|
+
**Use it for:** vertically center single-line control text (a label beside an icon, an input's own text) without a translateY nudge — fixed-height elements only; see era-text-trim-caps for ALL-CAPS strings.
|
|
192
|
+
|
|
193
|
+
Font-agnostic vertical ink-centering for single-line control text.
|
|
194
|
+
Measured verdict (4 fonts x 2 dpr, ink from device-pixel screenshots):
|
|
195
|
+
the offset has TWO causes — a fractional line box (14px x 1.5lh = 21px in
|
|
196
|
+
a 24px row places ink on a half pixel, ~1px error) and font ascent/descent
|
|
197
|
+
asymmetry (+-1px, sign flips per font). line-height: 1 fixes the first and
|
|
198
|
+
is the Firefox fallback; text-box ex/alphabetic fixes the second by
|
|
199
|
+
centering the x-height band — the visual mass of MIXED-CASE text (caps and
|
|
200
|
+
descenders cancel above/below). cap alphabetic is the spec-example recipe
|
|
201
|
+
but is descender-blind (reads high; CSSWG #9148) — measured 4x worse here.
|
|
202
|
+
Where text-box is supported it fully determines the box, so the two
|
|
203
|
+
declarations never fight. Worst-case residual: 0.44px.
|
|
204
|
+
|
|
205
|
+
The one hard rule concerns overflow clipping, and it is HEIGHT-conditional.
|
|
206
|
+
On an AUTO-height element that also clips — a `truncate` child, a
|
|
207
|
+
<textarea>, an auto-height <input> — trim-both collapses the box to the
|
|
208
|
+
x-height band (~7.5px at 14px) and the clip slices off every ascender, cap,
|
|
209
|
+
and descender (text renders as a chopped middle stripe): NEVER do that.
|
|
210
|
+
A FIXED-height control is the intended home, and is safe: the explicit
|
|
211
|
+
`h-(--era-*)` overrides the collapse, so a single-line <input> (Input,
|
|
212
|
+
command-input) and clipping display tokens (KV) correctly carry it. For
|
|
213
|
+
truncating text, put the trim on the fixed-height ROW and let the child
|
|
214
|
+
center via the row's items-center.
|
|
215
|
+
|
|
216
|
+
Declared in `index.css`.
|
|
217
|
+
|
|
218
|
+
```css
|
|
219
|
+
@utility era-text-trim {
|
|
220
|
+
line-height: 1;
|
|
221
|
+
text-box: trim-both ex alphabetic;
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## era-text-trim-caps
|
|
226
|
+
|
|
227
|
+
**Use it for:** the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never use it for mixed-case text.
|
|
228
|
+
|
|
229
|
+
ALL-CAPS single-line text (kbd hints, acronym badges): the x-height band
|
|
230
|
+
misjudges caps-only strings — cap/alphabetic edges are the right box.
|
|
231
|
+
|
|
232
|
+
Declared in `index.css`.
|
|
233
|
+
|
|
234
|
+
```css
|
|
235
|
+
@utility era-text-trim-caps {
|
|
236
|
+
line-height: 1;
|
|
237
|
+
text-box: trim-both cap alphabetic;
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## era-shimmer
|
|
242
|
+
|
|
243
|
+
**Use it for:** the in-progress text treatment — put it on a "working…" / "thinking…" label while a task streams, instead of a spinner beside the text.
|
|
244
|
+
|
|
245
|
+
In-progress text shimmer — a bright sweep through muted text (the standard
|
|
246
|
+
"working…" label treatment in streaming UIs). Timing derives from the motion
|
|
247
|
+
axis (10× --era-duration ≈ 1.5s at normal, 2.6s at extra); at instant the
|
|
248
|
+
duration is 0s and the sweep freezes on its base frame — plain muted text —
|
|
249
|
+
so reduced-motion and data-motion="instant" both kill it for free.
|
|
250
|
+
|
|
251
|
+
Declared in `index.css`.
|
|
252
|
+
|
|
253
|
+
```css
|
|
254
|
+
@utility era-shimmer {
|
|
255
|
+
background: linear-gradient(
|
|
256
|
+
110deg,
|
|
257
|
+
var(--color-muted) 0% 43%,
|
|
258
|
+
var(--color-bright) 50%,
|
|
259
|
+
var(--color-muted) 57% 100%
|
|
260
|
+
);
|
|
261
|
+
background-size: 200% 100%;
|
|
262
|
+
background-clip: text;
|
|
263
|
+
-webkit-text-fill-color: transparent;
|
|
264
|
+
animation: era-shimmer calc(var(--era-duration) * 10) cubic-bezier(0.7, 0, 1, 0.4) infinite;
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## glass-blur
|
|
269
|
+
|
|
270
|
+
**Use it for:** the backdrop blur for a floating panel (popover, dialog, taskbar) — it applies only inside a data-surface="glass" subtree and is inert elsewhere, so it is safe to leave on a panel that renders under every surface.
|
|
271
|
+
|
|
272
|
+
Tailwind v4 cannot resolve var() inside backdrop-blur-[], so the filter
|
|
273
|
+
is a registered utility, gated to glass subtrees.
|
|
274
|
+
|
|
275
|
+
Declared in `surfaces/glass.css`.
|
|
276
|
+
|
|
277
|
+
```css
|
|
278
|
+
@utility glass-blur {
|
|
279
|
+
[data-surface='glass'] & {
|
|
280
|
+
backdrop-filter: blur(var(--era-blur)) saturate(var(--era-saturate));
|
|
281
|
+
-webkit-backdrop-filter: blur(var(--era-blur)) saturate(var(--era-saturate));
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
<!-- end: utilities -->
|
|
287
|
+
|
|
74
288
|
<!-- begin: draggable -->
|
|
75
289
|
|
|
76
290
|
# Draggable
|
|
@@ -275,6 +489,7 @@ and screen-reader accessible names don't change shape mid-flight. |
|
|
|
275
489
|
|
|
276
490
|
- Heights, radii, paddings, and gaps come from density tokens — never hard-code px.
|
|
277
491
|
- `link` variant intentionally does not change color on hover (underline only) so it reads as static prose until confirmed interactive.
|
|
492
|
+
- `variant="link"` is for a _control_ that should look like a link (a button that reveals a panel, a destructive action in a row). For a link in body copy or prose, use the `era-link` CSS utility on an `<a>` instead — see [Utilities](/utilities.md).
|
|
278
493
|
- For a segmented row of buttons, use `ButtonGroup`.
|
|
279
494
|
|
|
280
495
|
<!-- end: button -->
|
|
@@ -2137,6 +2352,14 @@ Inherits all props from `ScrollArea.CornerProps`.
|
|
|
2137
2352
|
|------|------|---------|-------|
|
|
2138
2353
|
| `ref?` | `(forwarded)` | `null` | bindable |
|
|
2139
2354
|
|
|
2355
|
+
## Notes
|
|
2356
|
+
|
|
2357
|
+
- For a region that should scroll but show no scrollbar at all — an overflowing
|
|
2358
|
+
tab strip, a chip rail, a small pane handle — you don't need ScrollArea: put
|
|
2359
|
+
the `scrollbar-none` CSS utility on the overflowing element. See
|
|
2360
|
+
[Utilities](/utilities.md). ScrollArea is for the case where the bar itself is
|
|
2361
|
+
part of the design.
|
|
2362
|
+
|
|
2140
2363
|
<!-- end: scroll-area -->
|
|
2141
2364
|
|
|
2142
2365
|
<!-- begin: input -->
|
|
@@ -31,4 +31,18 @@ Full concatenated reference: `{{ORIGIN}}/llms-full.txt`.
|
|
|
31
31
|
|
|
32
32
|
## Components
|
|
33
33
|
|
|
34
|
-
about, spacing, surfaces, measurements, text, draggable, llm-shell, os, aspect-ratio, badge, avatar, bar, button, button-group, pane, card, chip, code-block, copy-button, cycle, kv, separator, sheet, skeleton, switch, toggle, accordion, alert-dialog, calendar, checkbox, collapsible, combobox, command, command-bar, step, context-menu, date-field, date-picker, date-range-field, date-range-picker, dialog, dropdown-menu, file-upload, scroll-area, input, link-preview, label, menu, menubar, meter, navigation-menu, mode, pagination, pin-input, popover, progress, range-calendar, radio-group, rating-group, select, slider, table, tabs, time-field, time-range-field, toggle-group, toolbar, video-player, tooltip
|
|
34
|
+
about, spacing, surfaces, measurements, text, utilities, draggable, llm-shell, os, aspect-ratio, badge, avatar, bar, button, button-group, pane, card, chip, code-block, copy-button, cycle, kv, separator, sheet, skeleton, switch, toggle, accordion, alert-dialog, calendar, checkbox, collapsible, combobox, command, command-bar, step, context-menu, date-field, date-picker, date-range-field, date-range-picker, dialog, dropdown-menu, file-upload, scroll-area, input, link-preview, label, menu, menubar, meter, navigation-menu, mode, pagination, pin-input, popover, progress, range-calendar, radio-group, rating-group, select, slider, table, tabs, time-field, time-range-field, toggle-group, toolbar, video-player, tooltip
|
|
35
|
+
|
|
36
|
+
## CSS utilities
|
|
37
|
+
|
|
38
|
+
Classes, not components — they need no import beyond the stylesheet. Reach for one of these before hand-rolling the same styling or bending a component into the role.
|
|
39
|
+
|
|
40
|
+
- `era-interactive` — the focus/disabled recipe every era control carries — put it on a custom interactive element instead of hand-writing focus/disabled variants.
|
|
41
|
+
- `era-link` — understated, motion-aware inline text link — the canonical style for a link in body copy or prose; prefer it over a hand-rolled underline or `Button variant="link"` (which is a control, not running text).
|
|
42
|
+
- `scrollbar-none` — hide the scrollbar on an overflowing strip or rail while keeping it scrollable — for a scroll region that should show its bar, use ScrollArea.
|
|
43
|
+
- `era-text-trim` — vertically center single-line control text (a label beside an icon, an input's own text) without a translateY nudge — fixed-height elements only; see era-text-trim-caps for ALL-CAPS strings.
|
|
44
|
+
- `era-text-trim-caps` — the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never use it for mixed-case text.
|
|
45
|
+
- `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.
|
|
46
|
+
- `glass-blur` — the backdrop blur for a floating panel (popover, dialog, taskbar) — it applies only inside a data-surface="glass" subtree and is inert elsewhere, so it is safe to leave on a panel that renders under every surface.
|
|
47
|
+
|
|
48
|
+
Full reference (what each emits, when to use it): `{{ORIGIN}}/utilities.md`. Machine-readable list: `{{ORIGIN}}/utilities.json`.
|
|
@@ -40,6 +40,23 @@
|
|
|
40
40
|
"sections": [],
|
|
41
41
|
"file": "text.md"
|
|
42
42
|
},
|
|
43
|
+
{
|
|
44
|
+
"slug": "utilities",
|
|
45
|
+
"title": "Utilities",
|
|
46
|
+
"summary": "The CSS classes era ships alongside the components — links, ink-centred text, shimmer, hidden scrollbars.",
|
|
47
|
+
"tokenEstimate": 1989,
|
|
48
|
+
"sections": [
|
|
49
|
+
"Overview",
|
|
50
|
+
"era-interactive",
|
|
51
|
+
"era-link",
|
|
52
|
+
"scrollbar-none",
|
|
53
|
+
"era-text-trim",
|
|
54
|
+
"era-text-trim-caps",
|
|
55
|
+
"era-shimmer",
|
|
56
|
+
"glass-blur"
|
|
57
|
+
],
|
|
58
|
+
"file": "utilities.md"
|
|
59
|
+
},
|
|
43
60
|
{
|
|
44
61
|
"slug": "draggable",
|
|
45
62
|
"title": "Draggable",
|
|
@@ -116,7 +133,7 @@
|
|
|
116
133
|
"slug": "button",
|
|
117
134
|
"title": "Button",
|
|
118
135
|
"summary": "A flexible button or link element.",
|
|
119
|
-
"tokenEstimate":
|
|
136
|
+
"tokenEstimate": 453,
|
|
120
137
|
"sections": [
|
|
121
138
|
"Import",
|
|
122
139
|
"Props",
|
|
@@ -564,14 +581,15 @@
|
|
|
564
581
|
"slug": "scroll-area",
|
|
565
582
|
"title": "Scroll Area",
|
|
566
583
|
"summary": "A cross-platform scroll container.",
|
|
567
|
-
"tokenEstimate":
|
|
584
|
+
"tokenEstimate": 399,
|
|
568
585
|
"sections": [
|
|
569
586
|
"Import",
|
|
570
587
|
"ScrollArea.Root",
|
|
571
588
|
"ScrollArea.Viewport",
|
|
572
589
|
"ScrollArea.Scrollbar",
|
|
573
590
|
"ScrollArea.Thumb",
|
|
574
|
-
"ScrollArea.Corner"
|
|
591
|
+
"ScrollArea.Corner",
|
|
592
|
+
"Notes"
|
|
575
593
|
],
|
|
576
594
|
"file": "scroll-area.md"
|
|
577
595
|
},
|
|
@@ -892,5 +910,56 @@
|
|
|
892
910
|
],
|
|
893
911
|
"file": "tooltip.md"
|
|
894
912
|
}
|
|
913
|
+
],
|
|
914
|
+
"utilities": [
|
|
915
|
+
{
|
|
916
|
+
"name": "era-interactive",
|
|
917
|
+
"file": "index.css",
|
|
918
|
+
"useCase": "the focus/disabled recipe every era control carries — put it on a custom interactive element instead of hand-writing focus/disabled variants.",
|
|
919
|
+
"description": "Shared interactive-state recipe: quiet focus, disabled affordance.\nEquivalent to `focus:outline-none disabled:cursor-not-allowed disabled:opacity-50`.",
|
|
920
|
+
"css": "@utility era-interactive {\n\t&:focus {\n\t\toutline: none;\n\t}\n\t&:disabled {\n\t\tcursor: not-allowed;\n\t\topacity: 0.5;\n\t}\n}"
|
|
921
|
+
},
|
|
922
|
+
{
|
|
923
|
+
"name": "era-link",
|
|
924
|
+
"file": "index.css",
|
|
925
|
+
"useCase": "understated, motion-aware inline text link — the canonical style for a link in body copy or prose; prefer it over a hand-rolled underline or `Button variant=\"link\"` (which is a control, not running text).",
|
|
926
|
+
"description": "Inline text link. An understated, permanent underline that darkens from\nmuted to the text colour on hover — no layout shift, no appearing/vanishing\nunderline. The colour fade rides the MOTION axis (--era-duration/-ease), so\nit snaps at data-motion=\"instant\", eases at \"normal\", and sweeps longer at\n\"extra\" — matching every other era transition. Font-agnostic: it styles\ndecoration + colour only, so it reads correctly in mono, sans, or serif, and\nthe 0.2em offset scales with the type size. Keyboard focus mirrors hover so\nthe affordance is reachable without a pointer.",
|
|
927
|
+
"css": "@utility era-link {\n\t/* The text is bright at rest and never changes — the link reads as a link\n\t * before you touch it. Only the UNDERLINE reacts: a faint half-strength-muted\n\t * hint at rest that resolves to the full text colour on hover. */\n\tcolor: var(--color-bright);\n\ttext-decoration-line: underline;\n\ttext-decoration-color: color-mix(in oklch, var(--color-muted) 50%, transparent);\n\ttext-underline-offset: 0.2em;\n\ttransition: text-decoration-color var(--era-duration) var(--era-ease);\n\t&:hover,\n\t&:focus-visible {\n\t\ttext-decoration-color: var(--color-fg);\n\t}\n}"
|
|
928
|
+
},
|
|
929
|
+
{
|
|
930
|
+
"name": "scrollbar-none",
|
|
931
|
+
"file": "index.css",
|
|
932
|
+
"useCase": "hide the scrollbar on an overflowing strip or rail while keeping it scrollable — for a scroll region that should show its bar, use ScrollArea.",
|
|
933
|
+
"description": "Scrollable but chromeless — hides the scrollbar while keeping wheel / touch /\ndrag scrolling (e.g. an overflowing tab strip in a small pane handle).",
|
|
934
|
+
"css": "@utility scrollbar-none {\n\tscrollbar-width: none;\n\t&::-webkit-scrollbar {\n\t\tdisplay: none;\n\t}\n}"
|
|
935
|
+
},
|
|
936
|
+
{
|
|
937
|
+
"name": "era-text-trim",
|
|
938
|
+
"file": "index.css",
|
|
939
|
+
"useCase": "vertically center single-line control text (a label beside an icon, an input's own text) without a translateY nudge — fixed-height elements only; see era-text-trim-caps for ALL-CAPS strings.",
|
|
940
|
+
"description": "Font-agnostic vertical ink-centering for single-line control text.\nMeasured verdict (4 fonts x 2 dpr, ink from device-pixel screenshots):\nthe offset has TWO causes — a fractional line box (14px x 1.5lh = 21px in\na 24px row places ink on a half pixel, ~1px error) and font ascent/descent\nasymmetry (+-1px, sign flips per font). line-height: 1 fixes the first and\nis the Firefox fallback; text-box ex/alphabetic fixes the second by\ncentering the x-height band — the visual mass of MIXED-CASE text (caps and\ndescenders cancel above/below). cap alphabetic is the spec-example recipe\nbut is descender-blind (reads high; CSSWG #9148) — measured 4x worse here.\nWhere text-box is supported it fully determines the box, so the two\ndeclarations never fight. Worst-case residual: 0.44px.\n\nThe one hard rule concerns overflow clipping, and it is HEIGHT-conditional.\nOn an AUTO-height element that also clips — a `truncate` child, a\n<textarea>, an auto-height <input> — trim-both collapses the box to the\nx-height band (~7.5px at 14px) and the clip slices off every ascender, cap,\nand descender (text renders as a chopped middle stripe): NEVER do that.\nA FIXED-height control is the intended home, and is safe: the explicit\n`h-(--era-*)` overrides the collapse, so a single-line <input> (Input,\ncommand-input) and clipping display tokens (KV) correctly carry it. For\ntruncating text, put the trim on the fixed-height ROW and let the child\ncenter via the row's items-center.",
|
|
941
|
+
"css": "@utility era-text-trim {\n\tline-height: 1;\n\ttext-box: trim-both ex alphabetic;\n}"
|
|
942
|
+
},
|
|
943
|
+
{
|
|
944
|
+
"name": "era-text-trim-caps",
|
|
945
|
+
"file": "index.css",
|
|
946
|
+
"useCase": "the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never use it for mixed-case text.",
|
|
947
|
+
"description": "ALL-CAPS single-line text (kbd hints, acronym badges): the x-height band\nmisjudges caps-only strings — cap/alphabetic edges are the right box.",
|
|
948
|
+
"css": "@utility era-text-trim-caps {\n\tline-height: 1;\n\ttext-box: trim-both cap alphabetic;\n}"
|
|
949
|
+
},
|
|
950
|
+
{
|
|
951
|
+
"name": "era-shimmer",
|
|
952
|
+
"file": "index.css",
|
|
953
|
+
"useCase": "the in-progress text treatment — put it on a \"working…\" / \"thinking…\" label while a task streams, instead of a spinner beside the text.",
|
|
954
|
+
"description": "In-progress text shimmer — a bright sweep through muted text (the standard\n\"working…\" label treatment in streaming UIs). Timing derives from the motion\naxis (10× --era-duration ≈ 1.5s at normal, 2.6s at extra); at instant the\nduration is 0s and the sweep freezes on its base frame — plain muted text —\nso reduced-motion and data-motion=\"instant\" both kill it for free.",
|
|
955
|
+
"css": "@utility era-shimmer {\n\tbackground: linear-gradient(\n\t\t110deg,\n\t\tvar(--color-muted) 0% 43%,\n\t\tvar(--color-bright) 50%,\n\t\tvar(--color-muted) 57% 100%\n\t);\n\tbackground-size: 200% 100%;\n\tbackground-clip: text;\n\t-webkit-text-fill-color: transparent;\n\tanimation: era-shimmer calc(var(--era-duration) * 10) cubic-bezier(0.7, 0, 1, 0.4) infinite;\n}"
|
|
956
|
+
},
|
|
957
|
+
{
|
|
958
|
+
"name": "glass-blur",
|
|
959
|
+
"file": "surfaces/glass.css",
|
|
960
|
+
"useCase": "the backdrop blur for a floating panel (popover, dialog, taskbar) — it applies only inside a data-surface=\"glass\" subtree and is inert elsewhere, so it is safe to leave on a panel that renders under every surface.",
|
|
961
|
+
"description": "Tailwind v4 cannot resolve var() inside backdrop-blur-[], so the filter\nis a registered utility, gated to glass subtrees.",
|
|
962
|
+
"css": "@utility glass-blur {\n\t[data-surface='glass'] & {\n\t\tbackdrop-filter: blur(var(--era-blur)) saturate(var(--era-saturate));\n\t\t-webkit-backdrop-filter: blur(var(--era-blur)) saturate(var(--era-saturate));\n\t}\n}"
|
|
963
|
+
}
|
|
895
964
|
]
|
|
896
965
|
}
|
|
@@ -55,3 +55,11 @@ Inherits all props from `ScrollArea.CornerProps`.
|
|
|
55
55
|
| Prop | Type | Default | Notes |
|
|
56
56
|
|------|------|---------|-------|
|
|
57
57
|
| `ref?` | `(forwarded)` | `null` | bindable |
|
|
58
|
+
|
|
59
|
+
## Notes
|
|
60
|
+
|
|
61
|
+
- For a region that should scroll but show no scrollbar at all — an overflowing
|
|
62
|
+
tab strip, a chip rail, a small pane handle — you don't need ScrollArea: put
|
|
63
|
+
the `scrollbar-none` CSS utility on the overflowing element. See
|
|
64
|
+
[Utilities](/utilities.md). ScrollArea is for the case where the bar itself is
|
|
65
|
+
part of the design.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"utilities": [
|
|
3
|
+
{
|
|
4
|
+
"name": "era-interactive",
|
|
5
|
+
"file": "index.css",
|
|
6
|
+
"useCase": "the focus/disabled recipe every era control carries — put it on a custom interactive element instead of hand-writing focus/disabled variants.",
|
|
7
|
+
"description": "Shared interactive-state recipe: quiet focus, disabled affordance.\nEquivalent to `focus:outline-none disabled:cursor-not-allowed disabled:opacity-50`.",
|
|
8
|
+
"css": "@utility era-interactive {\n\t&:focus {\n\t\toutline: none;\n\t}\n\t&:disabled {\n\t\tcursor: not-allowed;\n\t\topacity: 0.5;\n\t}\n}"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"name": "era-link",
|
|
12
|
+
"file": "index.css",
|
|
13
|
+
"useCase": "understated, motion-aware inline text link — the canonical style for a link in body copy or prose; prefer it over a hand-rolled underline or `Button variant=\"link\"` (which is a control, not running text).",
|
|
14
|
+
"description": "Inline text link. An understated, permanent underline that darkens from\nmuted to the text colour on hover — no layout shift, no appearing/vanishing\nunderline. The colour fade rides the MOTION axis (--era-duration/-ease), so\nit snaps at data-motion=\"instant\", eases at \"normal\", and sweeps longer at\n\"extra\" — matching every other era transition. Font-agnostic: it styles\ndecoration + colour only, so it reads correctly in mono, sans, or serif, and\nthe 0.2em offset scales with the type size. Keyboard focus mirrors hover so\nthe affordance is reachable without a pointer.",
|
|
15
|
+
"css": "@utility era-link {\n\t/* The text is bright at rest and never changes — the link reads as a link\n\t * before you touch it. Only the UNDERLINE reacts: a faint half-strength-muted\n\t * hint at rest that resolves to the full text colour on hover. */\n\tcolor: var(--color-bright);\n\ttext-decoration-line: underline;\n\ttext-decoration-color: color-mix(in oklch, var(--color-muted) 50%, transparent);\n\ttext-underline-offset: 0.2em;\n\ttransition: text-decoration-color var(--era-duration) var(--era-ease);\n\t&:hover,\n\t&:focus-visible {\n\t\ttext-decoration-color: var(--color-fg);\n\t}\n}"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "scrollbar-none",
|
|
19
|
+
"file": "index.css",
|
|
20
|
+
"useCase": "hide the scrollbar on an overflowing strip or rail while keeping it scrollable — for a scroll region that should show its bar, use ScrollArea.",
|
|
21
|
+
"description": "Scrollable but chromeless — hides the scrollbar while keeping wheel / touch /\ndrag scrolling (e.g. an overflowing tab strip in a small pane handle).",
|
|
22
|
+
"css": "@utility scrollbar-none {\n\tscrollbar-width: none;\n\t&::-webkit-scrollbar {\n\t\tdisplay: none;\n\t}\n}"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"name": "era-text-trim",
|
|
26
|
+
"file": "index.css",
|
|
27
|
+
"useCase": "vertically center single-line control text (a label beside an icon, an input's own text) without a translateY nudge — fixed-height elements only; see era-text-trim-caps for ALL-CAPS strings.",
|
|
28
|
+
"description": "Font-agnostic vertical ink-centering for single-line control text.\nMeasured verdict (4 fonts x 2 dpr, ink from device-pixel screenshots):\nthe offset has TWO causes — a fractional line box (14px x 1.5lh = 21px in\na 24px row places ink on a half pixel, ~1px error) and font ascent/descent\nasymmetry (+-1px, sign flips per font). line-height: 1 fixes the first and\nis the Firefox fallback; text-box ex/alphabetic fixes the second by\ncentering the x-height band — the visual mass of MIXED-CASE text (caps and\ndescenders cancel above/below). cap alphabetic is the spec-example recipe\nbut is descender-blind (reads high; CSSWG #9148) — measured 4x worse here.\nWhere text-box is supported it fully determines the box, so the two\ndeclarations never fight. Worst-case residual: 0.44px.\n\nThe one hard rule concerns overflow clipping, and it is HEIGHT-conditional.\nOn an AUTO-height element that also clips — a `truncate` child, a\n<textarea>, an auto-height <input> — trim-both collapses the box to the\nx-height band (~7.5px at 14px) and the clip slices off every ascender, cap,\nand descender (text renders as a chopped middle stripe): NEVER do that.\nA FIXED-height control is the intended home, and is safe: the explicit\n`h-(--era-*)` overrides the collapse, so a single-line <input> (Input,\ncommand-input) and clipping display tokens (KV) correctly carry it. For\ntruncating text, put the trim on the fixed-height ROW and let the child\ncenter via the row's items-center.",
|
|
29
|
+
"css": "@utility era-text-trim {\n\tline-height: 1;\n\ttext-box: trim-both ex alphabetic;\n}"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"name": "era-text-trim-caps",
|
|
33
|
+
"file": "index.css",
|
|
34
|
+
"useCase": "the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never use it for mixed-case text.",
|
|
35
|
+
"description": "ALL-CAPS single-line text (kbd hints, acronym badges): the x-height band\nmisjudges caps-only strings — cap/alphabetic edges are the right box.",
|
|
36
|
+
"css": "@utility era-text-trim-caps {\n\tline-height: 1;\n\ttext-box: trim-both cap alphabetic;\n}"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"name": "era-shimmer",
|
|
40
|
+
"file": "index.css",
|
|
41
|
+
"useCase": "the in-progress text treatment — put it on a \"working…\" / \"thinking…\" label while a task streams, instead of a spinner beside the text.",
|
|
42
|
+
"description": "In-progress text shimmer — a bright sweep through muted text (the standard\n\"working…\" label treatment in streaming UIs). Timing derives from the motion\naxis (10× --era-duration ≈ 1.5s at normal, 2.6s at extra); at instant the\nduration is 0s and the sweep freezes on its base frame — plain muted text —\nso reduced-motion and data-motion=\"instant\" both kill it for free.",
|
|
43
|
+
"css": "@utility era-shimmer {\n\tbackground: linear-gradient(\n\t\t110deg,\n\t\tvar(--color-muted) 0% 43%,\n\t\tvar(--color-bright) 50%,\n\t\tvar(--color-muted) 57% 100%\n\t);\n\tbackground-size: 200% 100%;\n\tbackground-clip: text;\n\t-webkit-text-fill-color: transparent;\n\tanimation: era-shimmer calc(var(--era-duration) * 10) cubic-bezier(0.7, 0, 1, 0.4) infinite;\n}"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "glass-blur",
|
|
47
|
+
"file": "surfaces/glass.css",
|
|
48
|
+
"useCase": "the backdrop blur for a floating panel (popover, dialog, taskbar) — it applies only inside a data-surface=\"glass\" subtree and is inert elsewhere, so it is safe to leave on a panel that renders under every surface.",
|
|
49
|
+
"description": "Tailwind v4 cannot resolve var() inside backdrop-blur-[], so the filter\nis a registered utility, gated to glass subtrees.",
|
|
50
|
+
"css": "@utility glass-blur {\n\t[data-surface='glass'] & {\n\t\tbackdrop-filter: blur(var(--era-blur)) saturate(var(--era-saturate));\n\t\t-webkit-backdrop-filter: blur(var(--era-blur)) saturate(var(--era-saturate));\n\t}\n}"
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Utilities
|
|
2
|
+
|
|
3
|
+
The CSS classes era ships alongside the components — links, ink-centred text, shimmer, hidden scrollbars.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
era ships a handful of Tailwind v4 `@utility` classes for the patterns that are
|
|
8
|
+
styling, not components — an inline link, ink-centred control text, a hidden
|
|
9
|
+
scrollbar. They need no import: they ride along with the stylesheet.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import "@sig-nine/era-ui/css";
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```svelte
|
|
16
|
+
<a class="era-link" href="/spacing">the spacing ladder</a>
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
| Utility | Use it for |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `era-interactive` | the focus/disabled recipe every era control carries — put it on a custom interactive element instead of hand-writing focus/disabled variants. |
|
|
22
|
+
| `era-link` | understated, motion-aware inline text link — the canonical style for a link in body copy or prose; prefer it over a hand-rolled underline or `Button variant="link"` (which is a control, not running text). |
|
|
23
|
+
| `scrollbar-none` | hide the scrollbar on an overflowing strip or rail while keeping it scrollable — for a scroll region that should show its bar, use ScrollArea. |
|
|
24
|
+
| `era-text-trim` | vertically center single-line control text (a label beside an icon, an input's own text) without a translateY nudge — fixed-height elements only; see era-text-trim-caps for ALL-CAPS strings. |
|
|
25
|
+
| `era-text-trim-caps` | the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never use it for mixed-case text. |
|
|
26
|
+
| `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. |
|
|
27
|
+
| `glass-blur` | the backdrop blur for a floating panel (popover, dialog, taskbar) — it applies only inside a data-surface="glass" subtree and is inert elsewhere, so it is safe to leave on a panel that renders under every surface. |
|
|
28
|
+
|
|
29
|
+
## era-interactive
|
|
30
|
+
|
|
31
|
+
**Use it for:** the focus/disabled recipe every era control carries — put it on a custom interactive element instead of hand-writing focus/disabled variants.
|
|
32
|
+
|
|
33
|
+
Shared interactive-state recipe: quiet focus, disabled affordance.
|
|
34
|
+
Equivalent to `focus:outline-none disabled:cursor-not-allowed disabled:opacity-50`.
|
|
35
|
+
|
|
36
|
+
Declared in `index.css`.
|
|
37
|
+
|
|
38
|
+
```css
|
|
39
|
+
@utility era-interactive {
|
|
40
|
+
&:focus {
|
|
41
|
+
outline: none;
|
|
42
|
+
}
|
|
43
|
+
&:disabled {
|
|
44
|
+
cursor: not-allowed;
|
|
45
|
+
opacity: 0.5;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## era-link
|
|
51
|
+
|
|
52
|
+
**Use it for:** understated, motion-aware inline text link — the canonical style for a link in body copy or prose; prefer it over a hand-rolled underline or `Button variant="link"` (which is a control, not running text).
|
|
53
|
+
|
|
54
|
+
Inline text link. An understated, permanent underline that darkens from
|
|
55
|
+
muted to the text colour on hover — no layout shift, no appearing/vanishing
|
|
56
|
+
underline. The colour fade rides the MOTION axis (--era-duration/-ease), so
|
|
57
|
+
it snaps at data-motion="instant", eases at "normal", and sweeps longer at
|
|
58
|
+
"extra" — matching every other era transition. Font-agnostic: it styles
|
|
59
|
+
decoration + colour only, so it reads correctly in mono, sans, or serif, and
|
|
60
|
+
the 0.2em offset scales with the type size. Keyboard focus mirrors hover so
|
|
61
|
+
the affordance is reachable without a pointer.
|
|
62
|
+
|
|
63
|
+
Declared in `index.css`.
|
|
64
|
+
|
|
65
|
+
```css
|
|
66
|
+
@utility era-link {
|
|
67
|
+
/* The text is bright at rest and never changes — the link reads as a link
|
|
68
|
+
* before you touch it. Only the UNDERLINE reacts: a faint half-strength-muted
|
|
69
|
+
* hint at rest that resolves to the full text colour on hover. */
|
|
70
|
+
color: var(--color-bright);
|
|
71
|
+
text-decoration-line: underline;
|
|
72
|
+
text-decoration-color: color-mix(in oklch, var(--color-muted) 50%, transparent);
|
|
73
|
+
text-underline-offset: 0.2em;
|
|
74
|
+
transition: text-decoration-color var(--era-duration) var(--era-ease);
|
|
75
|
+
&:hover,
|
|
76
|
+
&:focus-visible {
|
|
77
|
+
text-decoration-color: var(--color-fg);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## scrollbar-none
|
|
83
|
+
|
|
84
|
+
**Use it for:** hide the scrollbar on an overflowing strip or rail while keeping it scrollable — for a scroll region that should show its bar, use ScrollArea.
|
|
85
|
+
|
|
86
|
+
Scrollable but chromeless — hides the scrollbar while keeping wheel / touch /
|
|
87
|
+
drag scrolling (e.g. an overflowing tab strip in a small pane handle).
|
|
88
|
+
|
|
89
|
+
Declared in `index.css`.
|
|
90
|
+
|
|
91
|
+
```css
|
|
92
|
+
@utility scrollbar-none {
|
|
93
|
+
scrollbar-width: none;
|
|
94
|
+
&::-webkit-scrollbar {
|
|
95
|
+
display: none;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## era-text-trim
|
|
101
|
+
|
|
102
|
+
**Use it for:** vertically center single-line control text (a label beside an icon, an input's own text) without a translateY nudge — fixed-height elements only; see era-text-trim-caps for ALL-CAPS strings.
|
|
103
|
+
|
|
104
|
+
Font-agnostic vertical ink-centering for single-line control text.
|
|
105
|
+
Measured verdict (4 fonts x 2 dpr, ink from device-pixel screenshots):
|
|
106
|
+
the offset has TWO causes — a fractional line box (14px x 1.5lh = 21px in
|
|
107
|
+
a 24px row places ink on a half pixel, ~1px error) and font ascent/descent
|
|
108
|
+
asymmetry (+-1px, sign flips per font). line-height: 1 fixes the first and
|
|
109
|
+
is the Firefox fallback; text-box ex/alphabetic fixes the second by
|
|
110
|
+
centering the x-height band — the visual mass of MIXED-CASE text (caps and
|
|
111
|
+
descenders cancel above/below). cap alphabetic is the spec-example recipe
|
|
112
|
+
but is descender-blind (reads high; CSSWG #9148) — measured 4x worse here.
|
|
113
|
+
Where text-box is supported it fully determines the box, so the two
|
|
114
|
+
declarations never fight. Worst-case residual: 0.44px.
|
|
115
|
+
|
|
116
|
+
The one hard rule concerns overflow clipping, and it is HEIGHT-conditional.
|
|
117
|
+
On an AUTO-height element that also clips — a `truncate` child, a
|
|
118
|
+
<textarea>, an auto-height <input> — trim-both collapses the box to the
|
|
119
|
+
x-height band (~7.5px at 14px) and the clip slices off every ascender, cap,
|
|
120
|
+
and descender (text renders as a chopped middle stripe): NEVER do that.
|
|
121
|
+
A FIXED-height control is the intended home, and is safe: the explicit
|
|
122
|
+
`h-(--era-*)` overrides the collapse, so a single-line <input> (Input,
|
|
123
|
+
command-input) and clipping display tokens (KV) correctly carry it. For
|
|
124
|
+
truncating text, put the trim on the fixed-height ROW and let the child
|
|
125
|
+
center via the row's items-center.
|
|
126
|
+
|
|
127
|
+
Declared in `index.css`.
|
|
128
|
+
|
|
129
|
+
```css
|
|
130
|
+
@utility era-text-trim {
|
|
131
|
+
line-height: 1;
|
|
132
|
+
text-box: trim-both ex alphabetic;
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## era-text-trim-caps
|
|
137
|
+
|
|
138
|
+
**Use it for:** the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never use it for mixed-case text.
|
|
139
|
+
|
|
140
|
+
ALL-CAPS single-line text (kbd hints, acronym badges): the x-height band
|
|
141
|
+
misjudges caps-only strings — cap/alphabetic edges are the right box.
|
|
142
|
+
|
|
143
|
+
Declared in `index.css`.
|
|
144
|
+
|
|
145
|
+
```css
|
|
146
|
+
@utility era-text-trim-caps {
|
|
147
|
+
line-height: 1;
|
|
148
|
+
text-box: trim-both cap alphabetic;
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## era-shimmer
|
|
153
|
+
|
|
154
|
+
**Use it for:** the in-progress text treatment — put it on a "working…" / "thinking…" label while a task streams, instead of a spinner beside the text.
|
|
155
|
+
|
|
156
|
+
In-progress text shimmer — a bright sweep through muted text (the standard
|
|
157
|
+
"working…" label treatment in streaming UIs). Timing derives from the motion
|
|
158
|
+
axis (10× --era-duration ≈ 1.5s at normal, 2.6s at extra); at instant the
|
|
159
|
+
duration is 0s and the sweep freezes on its base frame — plain muted text —
|
|
160
|
+
so reduced-motion and data-motion="instant" both kill it for free.
|
|
161
|
+
|
|
162
|
+
Declared in `index.css`.
|
|
163
|
+
|
|
164
|
+
```css
|
|
165
|
+
@utility era-shimmer {
|
|
166
|
+
background: linear-gradient(
|
|
167
|
+
110deg,
|
|
168
|
+
var(--color-muted) 0% 43%,
|
|
169
|
+
var(--color-bright) 50%,
|
|
170
|
+
var(--color-muted) 57% 100%
|
|
171
|
+
);
|
|
172
|
+
background-size: 200% 100%;
|
|
173
|
+
background-clip: text;
|
|
174
|
+
-webkit-text-fill-color: transparent;
|
|
175
|
+
animation: era-shimmer calc(var(--era-duration) * 10) cubic-bezier(0.7, 0, 1, 0.4) infinite;
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## glass-blur
|
|
180
|
+
|
|
181
|
+
**Use it for:** the backdrop blur for a floating panel (popover, dialog, taskbar) — it applies only inside a data-surface="glass" subtree and is inert elsewhere, so it is safe to leave on a panel that renders under every surface.
|
|
182
|
+
|
|
183
|
+
Tailwind v4 cannot resolve var() inside backdrop-blur-[], so the filter
|
|
184
|
+
is a registered utility, gated to glass subtrees.
|
|
185
|
+
|
|
186
|
+
Declared in `surfaces/glass.css`.
|
|
187
|
+
|
|
188
|
+
```css
|
|
189
|
+
@utility glass-blur {
|
|
190
|
+
[data-surface='glass'] & {
|
|
191
|
+
backdrop-filter: blur(var(--era-blur)) saturate(var(--era-saturate));
|
|
192
|
+
-webkit-backdrop-filter: blur(var(--era-blur)) saturate(var(--era-saturate));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|