@signal9/era-ui 4.16.6 → 4.16.8
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/apps/notes/note-editor.svelte +2 -2
- package/dist/era-ui.css +1 -1
- package/dist/generated-docs/llms-full.txt +23 -15
- package/dist/generated-docs/llms.txt +33 -3
- package/dist/generated-docs/manifest.json +6 -6
- package/dist/generated-docs/pane.md +3 -2
- package/dist/generated-docs/utilities.json +4 -4
- package/dist/generated-docs/utilities.md +17 -10
- package/dist/os/pane.svelte +17 -15
- package/dist/styles/index.css +46 -9
- package/dist/ui/pane/pane-root.svelte +169 -92
- package/dist/ui/pane/pane-root.svelte.d.ts +20 -3
- package/dist/ui/pane/pane.svelte +5 -4
- package/dist/ui/pane/pane.svelte.d.ts +5 -4
- package/package.json +2 -2
|
@@ -36,9 +36,9 @@ Classes, not components — they need no import beyond the stylesheet. Reach for
|
|
|
36
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
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
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, a button's own text) without a translateY nudge
|
|
40
|
-
- `truncate` — single-line horizontal truncation with an ellipsis —
|
|
41
|
-
- `era-text-trim-caps` — the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never
|
|
39
|
+
- `era-text-trim` — vertically center single-line control text (a label beside an icon, a button's own text) without a translateY nudge. Fixed-height, non-editable elements ONLY: never on an <input>/<textarea>, and never on the same element as `truncate` or any overflow clip — put it on the fixed-height ROW and let the truncating child centre inside it. See era-text-trim-caps for ALL-CAPS.
|
|
40
|
+
- `truncate` — single-line horizontal truncation with an ellipsis — put it on the truncating CHILD inside a trimmed or leading-none row, never on the same element as era-text-trim; it will not clip ascenders or descenders.
|
|
41
|
+
- `era-text-trim-caps` — the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never for mixed-case text (a label like "System" reads high; use era-text-trim), and never on the same element as `truncate`.
|
|
42
42
|
- `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.
|
|
43
43
|
- `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.
|
|
44
44
|
- `era-collapse` — the height sweep for a bits-ui Collapsible.Content — put it on the Content element itself (it carries its own overflow: hidden).
|
|
@@ -145,9 +145,9 @@ enough to stay var-form — `min-w-(--era-h-md)` etc. remain the escape hatch.
|
|
|
145
145
|
| `era-interactive` | the focus/disabled recipe every era control carries — put it on a custom interactive element instead of hand-writing focus/disabled variants. |
|
|
146
146
|
| `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). |
|
|
147
147
|
| `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. |
|
|
148
|
-
| `era-text-trim` | vertically center single-line control text (a label beside an icon, a button's own text) without a translateY nudge
|
|
149
|
-
| `truncate` | single-line horizontal truncation with an ellipsis —
|
|
150
|
-
| `era-text-trim-caps` | the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never
|
|
148
|
+
| `era-text-trim` | vertically center single-line control text (a label beside an icon, a button's own text) without a translateY nudge. Fixed-height, non-editable elements ONLY: never on an <input>/<textarea>, and never on the same element as `truncate` or any overflow clip — put it on the fixed-height ROW and let the truncating child centre inside it. See era-text-trim-caps for ALL-CAPS. |
|
|
149
|
+
| `truncate` | single-line horizontal truncation with an ellipsis — put it on the truncating CHILD inside a trimmed or leading-none row, never on the same element as era-text-trim; it will not clip ascenders or descenders. |
|
|
150
|
+
| `era-text-trim-caps` | the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never for mixed-case text (a label like "System" reads high; use era-text-trim), and never on the same element as `truncate`. |
|
|
151
151
|
| `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. |
|
|
152
152
|
| `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. |
|
|
153
153
|
| `era-collapse` | the height sweep for a bits-ui Collapsible.Content — put it on the Content element itself (it carries its own overflow: hidden). |
|
|
@@ -205,16 +205,23 @@ Declared in `index.css`.
|
|
|
205
205
|
@utility era-link {
|
|
206
206
|
/* The text is bright at rest and never changes — the link reads as a link
|
|
207
207
|
* before you touch it. Only the UNDERLINE reacts: a faint hint at rest —
|
|
208
|
-
*
|
|
209
|
-
*
|
|
208
|
+
* the link's own ink knocked back to 30% so it barely whispers — that
|
|
209
|
+
* resolves to the full ink on hover.
|
|
210
|
+
*
|
|
211
|
+
* currentColor, not --color-muted/--color-fg: the underline belongs to the
|
|
212
|
+
* TEXT it underlines. On themes whose link ink is a colour (signalnine's
|
|
213
|
+
* navy, an accent-tinted bright), the neutral tokens drew a whitish line
|
|
214
|
+
* under coloured text — a second hue where there should be one. Derived
|
|
215
|
+
* from currentColor, the underline tracks whatever the link resolves to,
|
|
216
|
+
* in every theme, including a caller overriding `color` locally. */
|
|
210
217
|
color: var(--color-link);
|
|
211
218
|
text-decoration-line: underline;
|
|
212
|
-
text-decoration-color: color-mix(in oklch,
|
|
219
|
+
text-decoration-color: color-mix(in oklch, currentColor 30%, transparent);
|
|
213
220
|
text-underline-offset: 0.2em;
|
|
214
221
|
transition: text-decoration-color var(--era-duration) var(--era-ease);
|
|
215
222
|
&:hover,
|
|
216
223
|
&:focus-visible {
|
|
217
|
-
text-decoration-color:
|
|
224
|
+
text-decoration-color: currentColor;
|
|
218
225
|
}
|
|
219
226
|
}
|
|
220
227
|
```
|
|
@@ -239,7 +246,7 @@ Declared in `index.css`.
|
|
|
239
246
|
|
|
240
247
|
## era-text-trim
|
|
241
248
|
|
|
242
|
-
**Use it for:** vertically center single-line control text (a label beside an icon, a button's own text) without a translateY nudge
|
|
249
|
+
**Use it for:** vertically center single-line control text (a label beside an icon, a button's own text) without a translateY nudge. Fixed-height, non-editable elements ONLY: never on an <input>/<textarea>, and never on the same element as `truncate` or any overflow clip — put it on the fixed-height ROW and let the truncating child centre inside it. See era-text-trim-caps for ALL-CAPS.
|
|
243
250
|
|
|
244
251
|
Font-agnostic vertical ink-centering for single-line control text.
|
|
245
252
|
Measured verdict (4 fonts x 2 dpr, ink from device-pixel screenshots):
|
|
@@ -286,7 +293,7 @@ Declared in `index.css`.
|
|
|
286
293
|
|
|
287
294
|
## truncate
|
|
288
295
|
|
|
289
|
-
**Use it for:** single-line horizontal truncation with an ellipsis —
|
|
296
|
+
**Use it for:** single-line horizontal truncation with an ellipsis — put it on the truncating CHILD inside a trimmed or leading-none row, never on the same element as era-text-trim; it will not clip ascenders or descenders.
|
|
290
297
|
|
|
291
298
|
Tailwind's `truncate`, with the vertical clip fixed at the source.
|
|
292
299
|
|
|
@@ -319,7 +326,7 @@ Declared in `index.css`.
|
|
|
319
326
|
|
|
320
327
|
## era-text-trim-caps
|
|
321
328
|
|
|
322
|
-
**Use it for:** the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never
|
|
329
|
+
**Use it for:** the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never for mixed-case text (a label like "System" reads high; use era-text-trim), and never on the same element as `truncate`.
|
|
323
330
|
|
|
324
331
|
ALL-CAPS single-line text (kbd hints, acronym badges): the x-height band
|
|
325
332
|
misjudges caps-only strings — cap/alphabetic edges are the right box.
|
|
@@ -1062,8 +1069,9 @@ assign to move the pane programmatically (e.g. reset to 0,0). |
|
|
|
1062
1069
|
| `title?` | `string` | — | Text shown in the handle bar. For richer chrome use `header`. |
|
|
1063
1070
|
| `icon?` | `Component<IconProps> \| null` | `AppPane` | Lucide icon rendered left of the title. Pass `null` to omit. |
|
|
1064
1071
|
| `disabled?` | `boolean` | `false` | Disables dragging (reactive). |
|
|
1065
|
-
| `plugins?` | `
|
|
1066
|
-
|
|
1072
|
+
| `plugins?` | `DragPlugin[] \| (() => DragPlugin[])` | `[]` | Tier-2 neodrag plugins (`use`) appended to the drag. Tier-1 concerns
|
|
1073
|
+
(axis/bounds/grid/threshold) are Pane.Root props — spread through
|
|
1074
|
+
restProps or use Root directly for those. |
|
|
1067
1075
|
| `onDragStart?` | `(data: DragEventData) => void` | — | — |
|
|
1068
1076
|
| `onDrag?` | `(data: DragEventData) => void` | — | — |
|
|
1069
1077
|
| `onDragEnd?` | `(data: DragEventData) => void` | — | — |
|
|
@@ -2,6 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
> A Svelte 5 + Bits UI component library. Every surface — heights, paddings, radii, gaps — derives from a single spacing atom, so density is a one-attribute override at any scope.
|
|
4
4
|
|
|
5
|
+
## Sizing philosophy — read this before writing markup
|
|
6
|
+
|
|
7
|
+
Every measurement in era derives from one atom (`--era-sp`) through a fixed ladder. You never pick a number; you pick a TIER, and the number follows from the density axis. Markup that hardcodes `h-[34px]`, `text-[13px]`, `p-2` or `gap-1.5` is wrong even when it looks right at the default density — it stops tracking the axis the moment a subtree re-tiers.
|
|
8
|
+
|
|
9
|
+
**1. Height comes from the tier ladder, never from a pixel value.**
|
|
10
|
+
`h-xs` (icon, 14px @dense) · `h-xxs` (nested pill, 18) · `h-sm` (standalone pill, 22) · `h-md` (control/row, 24) · `h-lg` (bar/header, 32). A square is `size-*` on the same ladder; `size-xs` IS the icon size beside body text.
|
|
11
|
+
|
|
12
|
+
**2. Padding is geometric or optical — the container tells you which.**
|
|
13
|
+
A container with a BOUNDED tier height (bar, row, trigger, pill) takes geometric padding: `px-inset-md` / `px-sm` / `px-pill-sm`, all derived from `(tier − text)/2`. A container with UNBOUNDED height (card, dialog, panel, page section) takes optical padding: `p-panel` · `p-card` · `p-content`, which grow super-linearly so whitespace keeps pace as controls loosen. Never pad a card with a tier inset, and never pad a row with `p-card`.
|
|
14
|
+
|
|
15
|
+
**3. The even-gap law.** Inside any container, `(container_height − child_height) / 2` must equal the gap on ALL four sides. A `h-xxs` control in a `h-md` bar sits on a 3px wall at dense — so the bar's padding AND the gap between its children are that same value. `gap-gutter` / `p-gutter` is the standard inter-element gap (sp/2); the concentric insets (`p-inset-*`) are the text-symmetric ones.
|
|
16
|
+
|
|
17
|
+
**4. Radius follows the corner REGION's tier, not the box's size.**
|
|
18
|
+
`rounded-xs · xxs · sm · md · lg` walk the same ladder as the heights, and the ladder is built so that `rd_outer − rd_inner` equals the concentric gap — nested corners then share a centre of curvature automatically. A big panel whose corner is formed by an `h-md` bar takes `rounded-md`, not `rounded-lg`. Never hardcode a radius: `data-corners="square"` collapses the tokens to 0 and a literal value would survive it.
|
|
19
|
+
|
|
20
|
+
**5. Single-line control text carries `era-text-trim`; wrapping text carries `leading-body`.**
|
|
21
|
+
Flexbox centres the LINE BOX, not the ink, and misses by up to ~2px. `era-text-trim` fixes it — on FIXED-HEIGHT, NON-EDITABLE elements only. Two hard prohibitions, both of which produce silently chopped or mis-centred glyphs:
|
|
22
|
+
- NEVER on an `<input>`/`<textarea>`/`<select>` (the UA clips to the trimmed inner editor box, so typed text loses its ascenders — a "d" renders as an "o"). A tier-height field centres its own text; if you need the optical lift, that is `era-ink-center`.
|
|
23
|
+
- NEVER on the same element as `truncate` or any overflow clip. Put the trim on the fixed-height ROW and let the truncating CHILD centre inside it via `items-center`. (era guards this pairing so it degrades to a no-op instead of chopped text, but the row/child split is the correct authoring.)
|
|
24
|
+
|
|
25
|
+
Text that WRAPS is the opposite regime: it needs leading, so it carries `leading-body` (never a trim). `era-text-trim-caps` is for ALL-CAPS strings only — on mixed case it reads high.
|
|
26
|
+
|
|
27
|
+
**6. Type size is `text-body`.** It is the density-derived body/control size (12px at dense, 14px above). Reach for a Tailwind type step (`text-sm`, `text-xs`) only for genuine display type, never for control or body text.
|
|
28
|
+
|
|
29
|
+
**7. Colour comes from semantic tokens, not the ramp.** `text-fg` (controls/labels) · `text-bright` (emphasis, headings) · `text-muted` (body copy) · `text-destructive` / `-success` / `-warning`. Fills: `bg-hover` for a latched ROW, `bg-fill` for a standing pill, `bg-highlight` for transient hover. These compose across themes; a raw scale step does not.
|
|
30
|
+
|
|
31
|
+
**Verifying your own output.** era ships a runtime audit that measures these laws against rendered DOM — tier conformance, even gaps, concentric radii, chopped glyphs, wrapping text at control leading. If you are generating markup, render it and run the audit rather than eyeballing: it is the same instrument the library's own test suite asserts against.
|
|
32
|
+
|
|
33
|
+
Full derivations: `{{ORIGIN}}/spacing.md` (the ladder and every token), `{{ORIGIN}}/text.md` (type and trim), `{{ORIGIN}}/utilities.md` (every class, what it emits, when to use it).
|
|
34
|
+
|
|
5
35
|
## Using the library
|
|
6
36
|
|
|
7
37
|
```ts
|
|
@@ -40,9 +70,9 @@ Classes, not components — they need no import beyond the stylesheet. Reach for
|
|
|
40
70
|
- `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
71
|
- `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
72
|
- `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, a button's own text) without a translateY nudge
|
|
44
|
-
- `truncate` — single-line horizontal truncation with an ellipsis —
|
|
45
|
-
- `era-text-trim-caps` — the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never
|
|
73
|
+
- `era-text-trim` — vertically center single-line control text (a label beside an icon, a button's own text) without a translateY nudge. Fixed-height, non-editable elements ONLY: never on an <input>/<textarea>, and never on the same element as `truncate` or any overflow clip — put it on the fixed-height ROW and let the truncating child centre inside it. See era-text-trim-caps for ALL-CAPS.
|
|
74
|
+
- `truncate` — single-line horizontal truncation with an ellipsis — put it on the truncating CHILD inside a trimmed or leading-none row, never on the same element as era-text-trim; it will not clip ascenders or descenders.
|
|
75
|
+
- `era-text-trim-caps` — the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never for mixed-case text (a label like "System" reads high; use era-text-trim), and never on the same element as `truncate`.
|
|
46
76
|
- `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.
|
|
47
77
|
- `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.
|
|
48
78
|
- `era-collapse` — the height sweep for a bits-ui Collapsible.Content — put it on the Content element itself (it carries its own overflow: hidden).
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"slug": "utilities",
|
|
45
45
|
"title": "Utilities",
|
|
46
46
|
"summary": "The CSS classes era ships alongside the components — links, ink-centred text, shimmer, hidden scrollbars.",
|
|
47
|
-
"tokenEstimate":
|
|
47
|
+
"tokenEstimate": 6097,
|
|
48
48
|
"sections": [
|
|
49
49
|
"Overview",
|
|
50
50
|
"era-interactive",
|
|
@@ -195,7 +195,7 @@
|
|
|
195
195
|
"slug": "pane",
|
|
196
196
|
"title": "Pane",
|
|
197
197
|
"summary": "A draggable floating window with a handle bar.",
|
|
198
|
-
"tokenEstimate":
|
|
198
|
+
"tokenEstimate": 446,
|
|
199
199
|
"sections": [
|
|
200
200
|
"Import",
|
|
201
201
|
"Props"
|
|
@@ -980,7 +980,7 @@
|
|
|
980
980
|
"file": "index.css",
|
|
981
981
|
"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).",
|
|
982
982
|
"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.",
|
|
983
|
-
"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 hint at rest —\n\t *
|
|
983
|
+
"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 hint at rest —\n\t * the link's own ink knocked back to 30% so it barely whispers — that\n\t * resolves to the full ink on hover.\n\t *\n\t * currentColor, not --color-muted/--color-fg: the underline belongs to the\n\t * TEXT it underlines. On themes whose link ink is a colour (signalnine's\n\t * navy, an accent-tinted bright), the neutral tokens drew a whitish line\n\t * under coloured text — a second hue where there should be one. Derived\n\t * from currentColor, the underline tracks whatever the link resolves to,\n\t * in every theme, including a caller overriding `color` locally. */\n\tcolor: var(--color-link);\n\ttext-decoration-line: underline;\n\ttext-decoration-color: color-mix(in oklch, currentColor 30%, 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: currentColor;\n\t}\n}"
|
|
984
984
|
},
|
|
985
985
|
{
|
|
986
986
|
"name": "scrollbar-none",
|
|
@@ -998,7 +998,7 @@
|
|
|
998
998
|
"era-text-trim"
|
|
999
999
|
],
|
|
1000
1000
|
"file": "index.css",
|
|
1001
|
-
"useCase": "vertically center single-line control text (a label beside an icon, a button's own text) without a translateY nudge
|
|
1001
|
+
"useCase": "vertically center single-line control text (a label beside an icon, a button's own text) without a translateY nudge. Fixed-height, non-editable elements ONLY: never on an <input>/<textarea>, and never on the same element as `truncate` or any overflow clip — put it on the fixed-height ROW and let the truncating child centre inside it. See era-text-trim-caps for ALL-CAPS.",
|
|
1002
1002
|
"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 (measured at 14px; the\nmechanism is font-relative, so dense's 12px inherits the same guarantee with\na proportionally smaller residual).\n\nThe hard rules concern overflow clipping, and there are TWO of them.\n\n1. NEVER on a NATIVE EDITABLE — <input>, <textarea>, <select>. These clip to\n a UA-owned inner editor box that IS the trimmed line box, so a fixed\n height does NOT hold it open: whatever you type gets its ascenders and\n descenders sliced off (a \"d\" renders as an \"o\"). This rule used to read\n the other way round — it claimed a fixed-height <input> was the trim's\n intended home — and the Input component shipped chopped text as a result.\n A tier-height input centres its own text; it needs no trim.\n\n2. NEVER on an AUTO-height element that clips — a `truncate` child, an\n auto-height box with overflow-hidden. With no height to hold it open the\n box collapses to the x-height band (~7.5px at 14px) and the clip chops the\n glyphs into a middle stripe. Put the trim on the fixed-height ROW instead\n and let the child centre via the row's items-center.\n\nA fixed-height NON-editable element is the safe home: the ink overflows the\ntrimmed LINE box but stays inside the padding box, which is what actually\nclips. Both rules are enforced at runtime by typography/collapsed-text-trim.",
|
|
1003
1003
|
"css": "@utility era-text-trim {\n\tline-height: 1;\n\ttext-box: trim-both ex alphabetic;\n}"
|
|
1004
1004
|
},
|
|
@@ -1008,7 +1008,7 @@
|
|
|
1008
1008
|
"truncate"
|
|
1009
1009
|
],
|
|
1010
1010
|
"file": "index.css",
|
|
1011
|
-
"useCase": "single-line horizontal truncation with an ellipsis —
|
|
1011
|
+
"useCase": "single-line horizontal truncation with an ellipsis — put it on the truncating CHILD inside a trimmed or leading-none row, never on the same element as era-text-trim; it will not clip ascenders or descenders.",
|
|
1012
1012
|
"description": "Tailwind's `truncate`, with the vertical clip fixed at the source.\n\ntruncate is overflow:hidden, and overflow clips in BOTH axes — so whatever\nline box the element ends up with is also its ink clip. Era rows put\nera-text-trim on the fixed-height row (a Bar, a list row), and its\n`line-height: 1` INHERITS into the truncating child, which then has no fixed\nheight of its own: the child's box collapses to 1em while the font's real ink\nextent is ~1.15-1.2em, and the descenders (the \"g\" hook, the \"y\" tail) get\nsliced off at the box edge. Same bug on any `leading-none` + `truncate` pair.\n\nThe fix belongs here rather than at each call site: a horizontally-truncating\nelement must never be the thing that clips vertically. `line-height: normal`\nrestores the font's own ascent+descent box — exactly the ink extent — and\n`text-box: normal` cancels a trim if one is set alongside. Rows stay the same\nheight (they are tier-fixed and centre the child), and the child now has room\nfor its own glyphs.",
|
|
1013
1013
|
"css": "@utility truncate {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tline-height: normal;\n\ttext-box: normal;\n}"
|
|
1014
1014
|
},
|
|
@@ -1018,7 +1018,7 @@
|
|
|
1018
1018
|
"era-text-trim-caps"
|
|
1019
1019
|
],
|
|
1020
1020
|
"file": "index.css",
|
|
1021
|
-
"useCase": "the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never
|
|
1021
|
+
"useCase": "the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never for mixed-case text (a label like \"System\" reads high; use era-text-trim), and never on the same element as `truncate`.",
|
|
1022
1022
|
"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.",
|
|
1023
1023
|
"css": "@utility era-text-trim-caps {\n\tline-height: 1;\n\ttext-box: trim-both cap alphabetic;\n}"
|
|
1024
1024
|
},
|
|
@@ -22,8 +22,9 @@ assign to move the pane programmatically (e.g. reset to 0,0). |
|
|
|
22
22
|
| `title?` | `string` | — | Text shown in the handle bar. For richer chrome use `header`. |
|
|
23
23
|
| `icon?` | `Component<IconProps> \| null` | `AppPane` | Lucide icon rendered left of the title. Pass `null` to omit. |
|
|
24
24
|
| `disabled?` | `boolean` | `false` | Disables dragging (reactive). |
|
|
25
|
-
| `plugins?` | `
|
|
26
|
-
|
|
25
|
+
| `plugins?` | `DragPlugin[] \| (() => DragPlugin[])` | `[]` | Tier-2 neodrag plugins (`use`) appended to the drag. Tier-1 concerns
|
|
26
|
+
(axis/bounds/grid/threshold) are Pane.Root props — spread through
|
|
27
|
+
restProps or use Root directly for those. |
|
|
27
28
|
| `onDragStart?` | `(data: DragEventData) => void` | — | — |
|
|
28
29
|
| `onDrag?` | `(data: DragEventData) => void` | — | — |
|
|
29
30
|
| `onDragEnd?` | `(data: DragEventData) => void` | — | — |
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"file": "index.css",
|
|
19
19
|
"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).",
|
|
20
20
|
"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.",
|
|
21
|
-
"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 hint at rest —\n\t *
|
|
21
|
+
"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 hint at rest —\n\t * the link's own ink knocked back to 30% so it barely whispers — that\n\t * resolves to the full ink on hover.\n\t *\n\t * currentColor, not --color-muted/--color-fg: the underline belongs to the\n\t * TEXT it underlines. On themes whose link ink is a colour (signalnine's\n\t * navy, an accent-tinted bright), the neutral tokens drew a whitish line\n\t * under coloured text — a second hue where there should be one. Derived\n\t * from currentColor, the underline tracks whatever the link resolves to,\n\t * in every theme, including a caller overriding `color` locally. */\n\tcolor: var(--color-link);\n\ttext-decoration-line: underline;\n\ttext-decoration-color: color-mix(in oklch, currentColor 30%, 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: currentColor;\n\t}\n}"
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
"name": "scrollbar-none",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"era-text-trim"
|
|
37
37
|
],
|
|
38
38
|
"file": "index.css",
|
|
39
|
-
"useCase": "vertically center single-line control text (a label beside an icon, a button's own text) without a translateY nudge
|
|
39
|
+
"useCase": "vertically center single-line control text (a label beside an icon, a button's own text) without a translateY nudge. Fixed-height, non-editable elements ONLY: never on an <input>/<textarea>, and never on the same element as `truncate` or any overflow clip — put it on the fixed-height ROW and let the truncating child centre inside it. See era-text-trim-caps for ALL-CAPS.",
|
|
40
40
|
"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 (measured at 14px; the\nmechanism is font-relative, so dense's 12px inherits the same guarantee with\na proportionally smaller residual).\n\nThe hard rules concern overflow clipping, and there are TWO of them.\n\n1. NEVER on a NATIVE EDITABLE — <input>, <textarea>, <select>. These clip to\n a UA-owned inner editor box that IS the trimmed line box, so a fixed\n height does NOT hold it open: whatever you type gets its ascenders and\n descenders sliced off (a \"d\" renders as an \"o\"). This rule used to read\n the other way round — it claimed a fixed-height <input> was the trim's\n intended home — and the Input component shipped chopped text as a result.\n A tier-height input centres its own text; it needs no trim.\n\n2. NEVER on an AUTO-height element that clips — a `truncate` child, an\n auto-height box with overflow-hidden. With no height to hold it open the\n box collapses to the x-height band (~7.5px at 14px) and the clip chops the\n glyphs into a middle stripe. Put the trim on the fixed-height ROW instead\n and let the child centre via the row's items-center.\n\nA fixed-height NON-editable element is the safe home: the ink overflows the\ntrimmed LINE box but stays inside the padding box, which is what actually\nclips. Both rules are enforced at runtime by typography/collapsed-text-trim.",
|
|
41
41
|
"css": "@utility era-text-trim {\n\tline-height: 1;\n\ttext-box: trim-both ex alphabetic;\n}"
|
|
42
42
|
},
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"truncate"
|
|
47
47
|
],
|
|
48
48
|
"file": "index.css",
|
|
49
|
-
"useCase": "single-line horizontal truncation with an ellipsis —
|
|
49
|
+
"useCase": "single-line horizontal truncation with an ellipsis — put it on the truncating CHILD inside a trimmed or leading-none row, never on the same element as era-text-trim; it will not clip ascenders or descenders.",
|
|
50
50
|
"description": "Tailwind's `truncate`, with the vertical clip fixed at the source.\n\ntruncate is overflow:hidden, and overflow clips in BOTH axes — so whatever\nline box the element ends up with is also its ink clip. Era rows put\nera-text-trim on the fixed-height row (a Bar, a list row), and its\n`line-height: 1` INHERITS into the truncating child, which then has no fixed\nheight of its own: the child's box collapses to 1em while the font's real ink\nextent is ~1.15-1.2em, and the descenders (the \"g\" hook, the \"y\" tail) get\nsliced off at the box edge. Same bug on any `leading-none` + `truncate` pair.\n\nThe fix belongs here rather than at each call site: a horizontally-truncating\nelement must never be the thing that clips vertically. `line-height: normal`\nrestores the font's own ascent+descent box — exactly the ink extent — and\n`text-box: normal` cancels a trim if one is set alongside. Rows stay the same\nheight (they are tier-fixed and centre the child), and the child now has room\nfor its own glyphs.",
|
|
51
51
|
"css": "@utility truncate {\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n\twhite-space: nowrap;\n\tline-height: normal;\n\ttext-box: normal;\n}"
|
|
52
52
|
},
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"era-text-trim-caps"
|
|
57
57
|
],
|
|
58
58
|
"file": "index.css",
|
|
59
|
-
"useCase": "the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never
|
|
59
|
+
"useCase": "the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never for mixed-case text (a label like \"System\" reads high; use era-text-trim), and never on the same element as `truncate`.",
|
|
60
60
|
"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.",
|
|
61
61
|
"css": "@utility era-text-trim-caps {\n\tline-height: 1;\n\ttext-box: trim-both cap alphabetic;\n}"
|
|
62
62
|
},
|
|
@@ -41,9 +41,9 @@ enough to stay var-form — `min-w-(--era-h-md)` etc. remain the escape hatch.
|
|
|
41
41
|
| `era-interactive` | the focus/disabled recipe every era control carries — put it on a custom interactive element instead of hand-writing focus/disabled variants. |
|
|
42
42
|
| `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). |
|
|
43
43
|
| `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. |
|
|
44
|
-
| `era-text-trim` | vertically center single-line control text (a label beside an icon, a button's own text) without a translateY nudge
|
|
45
|
-
| `truncate` | single-line horizontal truncation with an ellipsis —
|
|
46
|
-
| `era-text-trim-caps` | the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never
|
|
44
|
+
| `era-text-trim` | vertically center single-line control text (a label beside an icon, a button's own text) without a translateY nudge. Fixed-height, non-editable elements ONLY: never on an <input>/<textarea>, and never on the same element as `truncate` or any overflow clip — put it on the fixed-height ROW and let the truncating child centre inside it. See era-text-trim-caps for ALL-CAPS. |
|
|
45
|
+
| `truncate` | single-line horizontal truncation with an ellipsis — put it on the truncating CHILD inside a trimmed or leading-none row, never on the same element as era-text-trim; it will not clip ascenders or descenders. |
|
|
46
|
+
| `era-text-trim-caps` | the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never for mixed-case text (a label like "System" reads high; use era-text-trim), and never on the same element as `truncate`. |
|
|
47
47
|
| `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. |
|
|
48
48
|
| `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. |
|
|
49
49
|
| `era-collapse` | the height sweep for a bits-ui Collapsible.Content — put it on the Content element itself (it carries its own overflow: hidden). |
|
|
@@ -101,16 +101,23 @@ Declared in `index.css`.
|
|
|
101
101
|
@utility era-link {
|
|
102
102
|
/* The text is bright at rest and never changes — the link reads as a link
|
|
103
103
|
* before you touch it. Only the UNDERLINE reacts: a faint hint at rest —
|
|
104
|
-
*
|
|
105
|
-
*
|
|
104
|
+
* the link's own ink knocked back to 30% so it barely whispers — that
|
|
105
|
+
* resolves to the full ink on hover.
|
|
106
|
+
*
|
|
107
|
+
* currentColor, not --color-muted/--color-fg: the underline belongs to the
|
|
108
|
+
* TEXT it underlines. On themes whose link ink is a colour (signalnine's
|
|
109
|
+
* navy, an accent-tinted bright), the neutral tokens drew a whitish line
|
|
110
|
+
* under coloured text — a second hue where there should be one. Derived
|
|
111
|
+
* from currentColor, the underline tracks whatever the link resolves to,
|
|
112
|
+
* in every theme, including a caller overriding `color` locally. */
|
|
106
113
|
color: var(--color-link);
|
|
107
114
|
text-decoration-line: underline;
|
|
108
|
-
text-decoration-color: color-mix(in oklch,
|
|
115
|
+
text-decoration-color: color-mix(in oklch, currentColor 30%, transparent);
|
|
109
116
|
text-underline-offset: 0.2em;
|
|
110
117
|
transition: text-decoration-color var(--era-duration) var(--era-ease);
|
|
111
118
|
&:hover,
|
|
112
119
|
&:focus-visible {
|
|
113
|
-
text-decoration-color:
|
|
120
|
+
text-decoration-color: currentColor;
|
|
114
121
|
}
|
|
115
122
|
}
|
|
116
123
|
```
|
|
@@ -135,7 +142,7 @@ Declared in `index.css`.
|
|
|
135
142
|
|
|
136
143
|
## era-text-trim
|
|
137
144
|
|
|
138
|
-
**Use it for:** vertically center single-line control text (a label beside an icon, a button's own text) without a translateY nudge
|
|
145
|
+
**Use it for:** vertically center single-line control text (a label beside an icon, a button's own text) without a translateY nudge. Fixed-height, non-editable elements ONLY: never on an <input>/<textarea>, and never on the same element as `truncate` or any overflow clip — put it on the fixed-height ROW and let the truncating child centre inside it. See era-text-trim-caps for ALL-CAPS.
|
|
139
146
|
|
|
140
147
|
Font-agnostic vertical ink-centering for single-line control text.
|
|
141
148
|
Measured verdict (4 fonts x 2 dpr, ink from device-pixel screenshots):
|
|
@@ -182,7 +189,7 @@ Declared in `index.css`.
|
|
|
182
189
|
|
|
183
190
|
## truncate
|
|
184
191
|
|
|
185
|
-
**Use it for:** single-line horizontal truncation with an ellipsis —
|
|
192
|
+
**Use it for:** single-line horizontal truncation with an ellipsis — put it on the truncating CHILD inside a trimmed or leading-none row, never on the same element as era-text-trim; it will not clip ascenders or descenders.
|
|
186
193
|
|
|
187
194
|
Tailwind's `truncate`, with the vertical clip fixed at the source.
|
|
188
195
|
|
|
@@ -215,7 +222,7 @@ Declared in `index.css`.
|
|
|
215
222
|
|
|
216
223
|
## era-text-trim-caps
|
|
217
224
|
|
|
218
|
-
**Use it for:** the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never
|
|
225
|
+
**Use it for:** the era-text-trim variant for ALL-CAPS single-line strings (kbd hints, acronym badges) — never for mixed-case text (a label like "System" reads high; use era-text-trim), and never on the same element as `truncate`.
|
|
219
226
|
|
|
220
227
|
ALL-CAPS single-line text (kbd hints, acronym badges): the x-height band
|
|
221
228
|
misjudges caps-only strings — cap/alphabetic edges are the right box.
|
package/dist/os/pane.svelte
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import Minus from '@lucide/svelte/icons/minus';
|
|
5
5
|
import Maximize from '@lucide/svelte/icons/maximize';
|
|
6
6
|
import X from '@lucide/svelte/icons/x';
|
|
7
|
-
import type {
|
|
7
|
+
import type { DragPlugin } from '@neodrag/svelte';
|
|
8
8
|
import { cn } from '../utils/index.js';
|
|
9
9
|
import { getPaneManager, type AppPane } from './pane-manager.svelte.js';
|
|
10
10
|
|
|
@@ -17,24 +17,26 @@
|
|
|
17
17
|
// not leave the TOP of the work area at all (y ≥ workArea.y), and on every
|
|
18
18
|
// other side at least pm.dragKeep px of the pane must stay inside the
|
|
19
19
|
// work area (which excludes chrome — a strip hidden behind the taskbar
|
|
20
|
-
// would be just as lost).
|
|
21
|
-
//
|
|
22
|
-
// so the
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
|
|
20
|
+
// would be just as lost). next.10's tier-2 seam hands `onMove` the PROPOSED
|
|
21
|
+
// absolute offset (constraints already applied); returning a point replaces
|
|
22
|
+
// it — so the clamp is a pure function of the proposal, the cursor simply
|
|
23
|
+
// stops pulling at the fence, and nothing rubber-bands on release. Width is
|
|
24
|
+
// read live off the node each move (a resize mid-session must re-fence).
|
|
25
|
+
// A STABLE plugin list — an inline array would change identity every render
|
|
26
|
+
// and push a needless options update through the drag.
|
|
27
|
+
const shellClamp: DragPlugin = {
|
|
27
28
|
name: 'era:shell-clamp',
|
|
28
|
-
|
|
29
|
+
onMove(ctx) {
|
|
29
30
|
const area = pm.workArea;
|
|
30
31
|
if (!area.width || !area.height) return;
|
|
31
32
|
const keep = pm.dragKeep;
|
|
32
|
-
const width = (ctx.
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
const width = (ctx.node as HTMLElement).offsetWidth;
|
|
34
|
+
const cx = Math.min(
|
|
35
|
+
Math.max(ctx.offset.x, area.x + keep - width),
|
|
36
|
+
area.x + area.width - keep
|
|
37
|
+
);
|
|
38
|
+
const cy = Math.min(Math.max(ctx.offset.y, area.y), area.y + area.height - keep);
|
|
39
|
+
if (cx !== ctx.offset.x || cy !== ctx.offset.y) return { x: cx, y: cy };
|
|
38
40
|
}
|
|
39
41
|
};
|
|
40
42
|
const panePlugins = [shellClamp];
|
package/dist/styles/index.css
CHANGED
|
@@ -91,16 +91,23 @@
|
|
|
91
91
|
@utility era-link {
|
|
92
92
|
/* The text is bright at rest and never changes — the link reads as a link
|
|
93
93
|
* before you touch it. Only the UNDERLINE reacts: a faint hint at rest —
|
|
94
|
-
*
|
|
95
|
-
*
|
|
94
|
+
* the link's own ink knocked back to 30% so it barely whispers — that
|
|
95
|
+
* resolves to the full ink on hover.
|
|
96
|
+
*
|
|
97
|
+
* currentColor, not --color-muted/--color-fg: the underline belongs to the
|
|
98
|
+
* TEXT it underlines. On themes whose link ink is a colour (signalnine's
|
|
99
|
+
* navy, an accent-tinted bright), the neutral tokens drew a whitish line
|
|
100
|
+
* under coloured text — a second hue where there should be one. Derived
|
|
101
|
+
* from currentColor, the underline tracks whatever the link resolves to,
|
|
102
|
+
* in every theme, including a caller overriding `color` locally. */
|
|
96
103
|
color: var(--color-link);
|
|
97
104
|
text-decoration-line: underline;
|
|
98
|
-
text-decoration-color: color-mix(in oklch,
|
|
105
|
+
text-decoration-color: color-mix(in oklch, currentColor 30%, transparent);
|
|
99
106
|
text-underline-offset: 0.2em;
|
|
100
107
|
transition: text-decoration-color var(--era-duration) var(--era-ease);
|
|
101
108
|
&:hover,
|
|
102
109
|
&:focus-visible {
|
|
103
|
-
text-decoration-color:
|
|
110
|
+
text-decoration-color: currentColor;
|
|
104
111
|
}
|
|
105
112
|
}
|
|
106
113
|
|
|
@@ -151,8 +158,10 @@
|
|
|
151
158
|
* clips. Both rules are enforced at runtime by typography/collapsed-text-trim.
|
|
152
159
|
*
|
|
153
160
|
* @use vertically center single-line control text (a label beside an icon, a
|
|
154
|
-
* button's own text) without a translateY nudge
|
|
155
|
-
* elements
|
|
161
|
+
* button's own text) without a translateY nudge. Fixed-height, non-editable
|
|
162
|
+
* elements ONLY: never on an <input>/<textarea>, and never on the same element
|
|
163
|
+
* as `truncate` or any overflow clip — put it on the fixed-height ROW and let
|
|
164
|
+
* the truncating child centre inside it. See era-text-trim-caps for ALL-CAPS.
|
|
156
165
|
*/
|
|
157
166
|
@utility era-text-trim {
|
|
158
167
|
line-height: 1;
|
|
@@ -176,8 +185,9 @@
|
|
|
176
185
|
* height (they are tier-fixed and centre the child), and the child now has room
|
|
177
186
|
* for its own glyphs.
|
|
178
187
|
*
|
|
179
|
-
* @use single-line horizontal truncation with an ellipsis —
|
|
180
|
-
* trimmed or leading-none row
|
|
188
|
+
* @use single-line horizontal truncation with an ellipsis — put it on the
|
|
189
|
+
* truncating CHILD inside a trimmed or leading-none row, never on the same
|
|
190
|
+
* element as era-text-trim; it will not clip ascenders or descenders. */
|
|
181
191
|
@utility truncate {
|
|
182
192
|
overflow: hidden;
|
|
183
193
|
text-overflow: ellipsis;
|
|
@@ -186,11 +196,38 @@
|
|
|
186
196
|
text-box: normal;
|
|
187
197
|
}
|
|
188
198
|
|
|
199
|
+
/* THE COLLISION GUARD — `truncate` and `era-text-trim` on the SAME element.
|
|
200
|
+
*
|
|
201
|
+
* Two utilities, same specificity, opposite intents: the trim collapses the box
|
|
202
|
+
* to the x-height band, and truncate clips to whatever box it lands on. Class
|
|
203
|
+
* ORDER in the attribute cannot break the tie — CSS resolves same-specificity
|
|
204
|
+
* conflicts by stylesheet order, and Tailwind emits era-text-trim last, so the
|
|
205
|
+
* trim silently won and the clip chopped the glyphs into a middle stripe
|
|
206
|
+
* (measured: an 8.58px box holding 16px of ink). Writing the classes the other
|
|
207
|
+
* way round changed nothing, which is what made it so hard to see.
|
|
208
|
+
*
|
|
209
|
+
* A real consumer hit exactly this. So the pairing is now DEFINED rather than
|
|
210
|
+
* accidental, with a compound selector that outranks both single-class
|
|
211
|
+
* utilities: truncate wins the vertical, the glyphs stay whole, and the
|
|
212
|
+
* element centres the way the docs say it should anyway — via its
|
|
213
|
+
* fixed-height parent's items-center.
|
|
214
|
+
*
|
|
215
|
+
* This is a safety net, not a blessing: the correct authoring is still trim on
|
|
216
|
+
* the ROW, truncate on the CHILD (typography/collapsed-text-trim still reports
|
|
217
|
+
* the pair so the runtime audit can point at it). It exists so the failure mode
|
|
218
|
+
* is a no-op instead of unreadable text. */
|
|
219
|
+
.era-text-trim.truncate,
|
|
220
|
+
.era-text-trim-caps.truncate {
|
|
221
|
+
line-height: normal;
|
|
222
|
+
text-box: normal;
|
|
223
|
+
}
|
|
224
|
+
|
|
189
225
|
/* ALL-CAPS single-line text (kbd hints, acronym badges): the x-height band
|
|
190
226
|
* misjudges caps-only strings — cap/alphabetic edges are the right box.
|
|
191
227
|
*
|
|
192
228
|
* @use the era-text-trim variant for ALL-CAPS single-line strings (kbd hints,
|
|
193
|
-
* acronym badges) — never
|
|
229
|
+
* acronym badges) — never for mixed-case text (a label like "System" reads
|
|
230
|
+
* high; use era-text-trim), and never on the same element as `truncate`. */
|
|
194
231
|
@utility era-text-trim-caps {
|
|
195
232
|
line-height: 1;
|
|
196
233
|
text-box: trim-both cap alphabetic;
|