@signal9/era-ui 4.16.9 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev/audit/audits/even-container-padding.d.ts +2 -0
- package/dist/dev/audit/audits/even-container-padding.js +62 -0
- package/dist/dev/audit/audits/index.d.ts +2 -1
- package/dist/dev/audit/audits/index.js +3 -1
- package/dist/era-ui.css +1 -1
- package/dist/generated-docs/llms-full.txt +35 -26
- package/dist/generated-docs/llms.txt +5 -1
- package/dist/generated-docs/manifest.json +7 -6
- package/dist/generated-docs/utilities.json +5 -4
- package/dist/generated-docs/utilities.md +39 -30
- package/dist/styles/index.css +38 -0
- package/dist/styles/typography.css +28 -11
- package/dist/ui/badge/badge.svelte +9 -1
- package/dist/ui/badge/badge.svelte.d.ts +1 -1
- package/dist/ui/card/card.svelte +16 -6
- package/dist/ui/card/card.svelte.d.ts +3 -3
- package/dist/ui/kv/kv.svelte +6 -1
- package/package.json +2 -1
|
@@ -39,7 +39,7 @@ Classes, not components — they need no import beyond the stylesheet. Reach for
|
|
|
39
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
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
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
|
-
- `era-ink-center` —
|
|
42
|
+
- `era-token-ink · era-ink-center` — the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box; it needs no icon sibling (with one the box must stay flex, and the general trim applies).
|
|
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).
|
|
45
45
|
- `h-xs · h-xxs · h-sm · h-md · h-lg` — the tier-height ladder — h-xs (icon) · h-xxs (nested pill) · h-sm (standalone pill) · h-md (control) · h-lg (bar); the named form of h-(--era-h-*).
|
|
@@ -148,7 +148,7 @@ enough to stay var-form — `min-w-(--era-h-md)` etc. remain the escape hatch.
|
|
|
148
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
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
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
|
-
| `era-ink-center` |
|
|
151
|
+
| `era-token-ink` `era-ink-center` | the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box; it needs no icon sibling (with one the box must stay flex, and the general trim applies). |
|
|
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). |
|
|
154
154
|
| `h-xs` `h-xxs` `h-sm` `h-md` `h-lg` | the tier-height ladder — h-xs (icon) · h-xxs (nested pill) · h-sm (standalone pill) · h-md (control) · h-lg (bar); the named form of h-(--era-h-*). |
|
|
@@ -340,39 +340,48 @@ Declared in `index.css`.
|
|
|
340
340
|
}
|
|
341
341
|
```
|
|
342
342
|
|
|
343
|
-
## era-ink-center
|
|
343
|
+
## era-token-ink · era-ink-center
|
|
344
344
|
|
|
345
|
-
**Use it for:**
|
|
345
|
+
**Use it for:** the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box; it needs no icon sibling (with one the box must stay flex, and the general trim applies).
|
|
346
346
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
glyphs; see typography/collapsed-text-trim).
|
|
347
|
+
TOKEN INK — the ink centring for a pill whose content is a TOKEN: an id, a
|
|
348
|
+
count, a status, a tag. Font-independent, unlike everything it replaces.
|
|
350
349
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
350
|
+
THE BUG IT FIXES, which had been shipping library-wide and invisibly:
|
|
351
|
+
`text-box-trim` DOES NOTHING ON A FLEX CONTAINER. Era's controls are all
|
|
352
|
+
flex, and a flex container's bare text becomes an ANONYMOUS flex item — a box
|
|
353
|
+
no selector can reach and no non-inherited property can touch. So
|
|
354
|
+
`era-text-trim` on a Badge, a Chip, a Button or a Bar contributed exactly one
|
|
355
|
+
thing: `line-height: 1`. The ink was then centred by `align-items: center`
|
|
356
|
+
on the LINE BOX, which is precisely the font-metric-dependent centring the
|
|
357
|
+
trim exists to eliminate. Measured on the shipped mono stack: a badge reading
|
|
358
|
+
"AC-2.1" sat 2px high in an 18px pill, and no amount of tuning the trim's
|
|
359
|
+
BAND changed it, because the trim was never running.
|
|
355
360
|
|
|
356
|
-
The
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
18px field with ~4.7px under the baseline — the reading where neither
|
|
363
|
-
band's partisans win and neither complains.
|
|
361
|
+
The mechanism here restores it: a BLOCK box (where text-box-trim does apply)
|
|
362
|
+
whose trimmed line box is then centred by `align-content` — block-container
|
|
363
|
+
alignment, so no flex formatting context and no anonymous item. The browser
|
|
364
|
+
computes the band from the font's own metrics, which is what makes it hold
|
|
365
|
+
across ui-monospace, system-ui and ui-serif instead of needing a constant
|
|
366
|
+
per stack.
|
|
364
367
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
text. In em on purpose: the correction is a fraction of the type, so it
|
|
371
|
-
holds across every density and text size with one value.
|
|
368
|
+
CAP band, not the x-height band the general trim uses, because the content
|
|
369
|
+
class is different: a token is caps and digits (both cap-height), and
|
|
370
|
+
centring the x-band parks them high by (cap − x)/2. Measured on the shipped
|
|
371
|
+
stacks, cap-band centring takes an id/count/status from −2.0px to 0.0.
|
|
372
|
+
Prose and sentence-case labels keep era-text-trim; this is for tokens.
|
|
372
373
|
|
|
373
374
|
Declared in `index.css`.
|
|
374
375
|
|
|
375
376
|
```css
|
|
377
|
+
@utility era-token-ink {
|
|
378
|
+
display: block;
|
|
379
|
+
align-content: center;
|
|
380
|
+
text-align: center;
|
|
381
|
+
line-height: 1;
|
|
382
|
+
text-box: trim-both cap alphabetic;
|
|
383
|
+
}
|
|
384
|
+
|
|
376
385
|
@utility era-ink-center {
|
|
377
386
|
padding-bottom: 0.08em;
|
|
378
387
|
}
|
|
@@ -14,6 +14,8 @@ A container with a BOUNDED tier height (bar, row, trigger, pill) takes geometric
|
|
|
14
14
|
|
|
15
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
16
|
|
|
17
|
+
The same law in its simplest form, for containers with no tier: **a box pads its content equally at top and bottom.** Horizontal asymmetry is often deliberate (a bar's leading side sits at the text inset while its trailing side keeps the concentric wall); vertical asymmetry is a bug — nothing should sit closer to its top edge than its bottom, and era audits for it.
|
|
18
|
+
|
|
17
19
|
**4. Radius follows the corner REGION's tier, not the box's size.**
|
|
18
20
|
`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
21
|
|
|
@@ -28,6 +30,8 @@ Text that WRAPS is the opposite regime: it needs leading, so it carries `leading
|
|
|
28
30
|
|
|
29
31
|
**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
32
|
|
|
33
|
+
**Nesting a pill in a card.** A pill at a card's corner is NOT governed by the concentric identity — that law needs a height term and a card has no tier. The card pads optically, the pill keeps its own tier radius; do not hand-tune padding to chase the corner. If a container genuinely IS tier-height chrome (a bar, a row, a trigger) then it is bounded and the concentric rule applies in full.
|
|
34
|
+
|
|
31
35
|
**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
36
|
|
|
33
37
|
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).
|
|
@@ -73,7 +77,7 @@ Classes, not components — they need no import beyond the stylesheet. Reach for
|
|
|
73
77
|
- `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
78
|
- `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
79
|
- `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`.
|
|
76
|
-
- `era-ink-center` —
|
|
80
|
+
- `era-token-ink · era-ink-center` — the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box; it needs no icon sibling (with one the box must stay flex, and the general trim applies).
|
|
77
81
|
- `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.
|
|
78
82
|
- `era-collapse` — the height sweep for a bits-ui Collapsible.Content — put it on the Content element itself (it carries its own overflow: hidden).
|
|
79
83
|
- `h-xs · h-xxs · h-sm · h-md · h-lg` — the tier-height ladder — h-xs (icon) · h-xxs (nested pill) · h-sm (standalone pill) · h-md (control) · h-lg (bar); the named form of h-(--era-h-*).
|
|
@@ -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": 6197,
|
|
48
48
|
"sections": [
|
|
49
49
|
"Overview",
|
|
50
50
|
"era-interactive",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"era-text-trim",
|
|
54
54
|
"truncate",
|
|
55
55
|
"era-text-trim-caps",
|
|
56
|
-
"era-ink-center",
|
|
56
|
+
"era-token-ink · era-ink-center",
|
|
57
57
|
"era-shimmer",
|
|
58
58
|
"era-collapse",
|
|
59
59
|
"h-xs · h-xxs · h-sm · h-md · h-lg",
|
|
@@ -1023,14 +1023,15 @@
|
|
|
1023
1023
|
"css": "@utility era-text-trim-caps {\n\tline-height: 1;\n\ttext-box: trim-both cap alphabetic;\n}"
|
|
1024
1024
|
},
|
|
1025
1025
|
{
|
|
1026
|
-
"name": "era-ink
|
|
1026
|
+
"name": "era-token-ink",
|
|
1027
1027
|
"names": [
|
|
1028
|
+
"era-token-ink",
|
|
1028
1029
|
"era-ink-center"
|
|
1029
1030
|
],
|
|
1030
1031
|
"file": "index.css",
|
|
1031
|
-
"useCase": "
|
|
1032
|
-
"description": "
|
|
1033
|
-
"css": "@utility era-ink-center {\n\tpadding-bottom: 0.08em;\n}"
|
|
1032
|
+
"useCase": "the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box; it needs no icon sibling (with one the box must stay flex, and the general trim applies).",
|
|
1033
|
+
"description": "TOKEN INK — the ink centring for a pill whose content is a TOKEN: an id, a\ncount, a status, a tag. Font-independent, unlike everything it replaces.\n\nTHE BUG IT FIXES, which had been shipping library-wide and invisibly:\n`text-box-trim` DOES NOTHING ON A FLEX CONTAINER. Era's controls are all\nflex, and a flex container's bare text becomes an ANONYMOUS flex item — a box\nno selector can reach and no non-inherited property can touch. So\n`era-text-trim` on a Badge, a Chip, a Button or a Bar contributed exactly one\nthing: `line-height: 1`. The ink was then centred by `align-items: center`\non the LINE BOX, which is precisely the font-metric-dependent centring the\ntrim exists to eliminate. Measured on the shipped mono stack: a badge reading\n\"AC-2.1\" sat 2px high in an 18px pill, and no amount of tuning the trim's\nBAND changed it, because the trim was never running.\n\nThe mechanism here restores it: a BLOCK box (where text-box-trim does apply)\nwhose trimmed line box is then centred by `align-content` — block-container\nalignment, so no flex formatting context and no anonymous item. The browser\ncomputes the band from the font's own metrics, which is what makes it hold\nacross ui-monospace, system-ui and ui-serif instead of needing a constant\nper stack.\n\nCAP band, not the x-height band the general trim uses, because the content\nclass is different: a token is caps and digits (both cap-height), and\ncentring the x-band parks them high by (cap − x)/2. Measured on the shipped\nstacks, cap-band centring takes an id/count/status from −2.0px to 0.0.\nProse and sentence-case labels keep era-text-trim; this is for tokens.",
|
|
1034
|
+
"css": "@utility era-token-ink {\n\tdisplay: block;\n\talign-content: center;\n\ttext-align: center;\n\tline-height: 1;\n\ttext-box: trim-both cap alphabetic;\n}\n\n@utility era-ink-center {\n\tpadding-bottom: 0.08em;\n}"
|
|
1034
1035
|
},
|
|
1035
1036
|
{
|
|
1036
1037
|
"name": "era-shimmer",
|
|
@@ -61,14 +61,15 @@
|
|
|
61
61
|
"css": "@utility era-text-trim-caps {\n\tline-height: 1;\n\ttext-box: trim-both cap alphabetic;\n}"
|
|
62
62
|
},
|
|
63
63
|
{
|
|
64
|
-
"name": "era-ink
|
|
64
|
+
"name": "era-token-ink",
|
|
65
65
|
"names": [
|
|
66
|
+
"era-token-ink",
|
|
66
67
|
"era-ink-center"
|
|
67
68
|
],
|
|
68
69
|
"file": "index.css",
|
|
69
|
-
"useCase": "
|
|
70
|
-
"description": "
|
|
71
|
-
"css": "@utility era-ink-center {\n\tpadding-bottom: 0.08em;\n}"
|
|
70
|
+
"useCase": "the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box; it needs no icon sibling (with one the box must stay flex, and the general trim applies).",
|
|
71
|
+
"description": "TOKEN INK — the ink centring for a pill whose content is a TOKEN: an id, a\ncount, a status, a tag. Font-independent, unlike everything it replaces.\n\nTHE BUG IT FIXES, which had been shipping library-wide and invisibly:\n`text-box-trim` DOES NOTHING ON A FLEX CONTAINER. Era's controls are all\nflex, and a flex container's bare text becomes an ANONYMOUS flex item — a box\nno selector can reach and no non-inherited property can touch. So\n`era-text-trim` on a Badge, a Chip, a Button or a Bar contributed exactly one\nthing: `line-height: 1`. The ink was then centred by `align-items: center`\non the LINE BOX, which is precisely the font-metric-dependent centring the\ntrim exists to eliminate. Measured on the shipped mono stack: a badge reading\n\"AC-2.1\" sat 2px high in an 18px pill, and no amount of tuning the trim's\nBAND changed it, because the trim was never running.\n\nThe mechanism here restores it: a BLOCK box (where text-box-trim does apply)\nwhose trimmed line box is then centred by `align-content` — block-container\nalignment, so no flex formatting context and no anonymous item. The browser\ncomputes the band from the font's own metrics, which is what makes it hold\nacross ui-monospace, system-ui and ui-serif instead of needing a constant\nper stack.\n\nCAP band, not the x-height band the general trim uses, because the content\nclass is different: a token is caps and digits (both cap-height), and\ncentring the x-band parks them high by (cap − x)/2. Measured on the shipped\nstacks, cap-band centring takes an id/count/status from −2.0px to 0.0.\nProse and sentence-case labels keep era-text-trim; this is for tokens.",
|
|
72
|
+
"css": "@utility era-token-ink {\n\tdisplay: block;\n\talign-content: center;\n\ttext-align: center;\n\tline-height: 1;\n\ttext-box: trim-both cap alphabetic;\n}\n\n@utility era-ink-center {\n\tpadding-bottom: 0.08em;\n}"
|
|
72
73
|
},
|
|
73
74
|
{
|
|
74
75
|
"name": "era-shimmer",
|
|
@@ -44,7 +44,7 @@ enough to stay var-form — `min-w-(--era-h-md)` etc. remain the escape hatch.
|
|
|
44
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
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
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
|
-
| `era-ink-center` |
|
|
47
|
+
| `era-token-ink` `era-ink-center` | the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box; it needs no icon sibling (with one the box must stay flex, and the general trim applies). |
|
|
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). |
|
|
50
50
|
| `h-xs` `h-xxs` `h-sm` `h-md` `h-lg` | the tier-height ladder — h-xs (icon) · h-xxs (nested pill) · h-sm (standalone pill) · h-md (control) · h-lg (bar); the named form of h-(--era-h-*). |
|
|
@@ -236,39 +236,48 @@ Declared in `index.css`.
|
|
|
236
236
|
}
|
|
237
237
|
```
|
|
238
238
|
|
|
239
|
-
## era-ink-center
|
|
240
|
-
|
|
241
|
-
**Use it for:**
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
to
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
239
|
+
## era-token-ink · era-ink-center
|
|
240
|
+
|
|
241
|
+
**Use it for:** the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box; it needs no icon sibling (with one the box must stay flex, and the general trim applies).
|
|
242
|
+
|
|
243
|
+
TOKEN INK — the ink centring for a pill whose content is a TOKEN: an id, a
|
|
244
|
+
count, a status, a tag. Font-independent, unlike everything it replaces.
|
|
245
|
+
|
|
246
|
+
THE BUG IT FIXES, which had been shipping library-wide and invisibly:
|
|
247
|
+
`text-box-trim` DOES NOTHING ON A FLEX CONTAINER. Era's controls are all
|
|
248
|
+
flex, and a flex container's bare text becomes an ANONYMOUS flex item — a box
|
|
249
|
+
no selector can reach and no non-inherited property can touch. So
|
|
250
|
+
`era-text-trim` on a Badge, a Chip, a Button or a Bar contributed exactly one
|
|
251
|
+
thing: `line-height: 1`. The ink was then centred by `align-items: center`
|
|
252
|
+
on the LINE BOX, which is precisely the font-metric-dependent centring the
|
|
253
|
+
trim exists to eliminate. Measured on the shipped mono stack: a badge reading
|
|
254
|
+
"AC-2.1" sat 2px high in an 18px pill, and no amount of tuning the trim's
|
|
255
|
+
BAND changed it, because the trim was never running.
|
|
256
|
+
|
|
257
|
+
The mechanism here restores it: a BLOCK box (where text-box-trim does apply)
|
|
258
|
+
whose trimmed line box is then centred by `align-content` — block-container
|
|
259
|
+
alignment, so no flex formatting context and no anonymous item. The browser
|
|
260
|
+
computes the band from the font's own metrics, which is what makes it hold
|
|
261
|
+
across ui-monospace, system-ui and ui-serif instead of needing a constant
|
|
262
|
+
per stack.
|
|
263
|
+
|
|
264
|
+
CAP band, not the x-height band the general trim uses, because the content
|
|
265
|
+
class is different: a token is caps and digits (both cap-height), and
|
|
266
|
+
centring the x-band parks them high by (cap − x)/2. Measured on the shipped
|
|
267
|
+
stacks, cap-band centring takes an id/count/status from −2.0px to 0.0.
|
|
268
|
+
Prose and sentence-case labels keep era-text-trim; this is for tokens.
|
|
268
269
|
|
|
269
270
|
Declared in `index.css`.
|
|
270
271
|
|
|
271
272
|
```css
|
|
273
|
+
@utility era-token-ink {
|
|
274
|
+
display: block;
|
|
275
|
+
align-content: center;
|
|
276
|
+
text-align: center;
|
|
277
|
+
line-height: 1;
|
|
278
|
+
text-box: trim-both cap alphabetic;
|
|
279
|
+
}
|
|
280
|
+
|
|
272
281
|
@utility era-ink-center {
|
|
273
282
|
padding-bottom: 0.08em;
|
|
274
283
|
}
|
package/dist/styles/index.css
CHANGED
|
@@ -261,6 +261,44 @@
|
|
|
261
261
|
*
|
|
262
262
|
* @use on a native single-line <input> (or the text layer that must mirror
|
|
263
263
|
* one) inside a fixed-height field — never alongside era-text-trim. */
|
|
264
|
+
/* TOKEN INK — the ink centring for a pill whose content is a TOKEN: an id, a
|
|
265
|
+
* count, a status, a tag. Font-independent, unlike everything it replaces.
|
|
266
|
+
*
|
|
267
|
+
* THE BUG IT FIXES, which had been shipping library-wide and invisibly:
|
|
268
|
+
* `text-box-trim` DOES NOTHING ON A FLEX CONTAINER. Era's controls are all
|
|
269
|
+
* flex, and a flex container's bare text becomes an ANONYMOUS flex item — a box
|
|
270
|
+
* no selector can reach and no non-inherited property can touch. So
|
|
271
|
+
* `era-text-trim` on a Badge, a Chip, a Button or a Bar contributed exactly one
|
|
272
|
+
* thing: `line-height: 1`. The ink was then centred by `align-items: center`
|
|
273
|
+
* on the LINE BOX, which is precisely the font-metric-dependent centring the
|
|
274
|
+
* trim exists to eliminate. Measured on the shipped mono stack: a badge reading
|
|
275
|
+
* "AC-2.1" sat 2px high in an 18px pill, and no amount of tuning the trim's
|
|
276
|
+
* BAND changed it, because the trim was never running.
|
|
277
|
+
*
|
|
278
|
+
* The mechanism here restores it: a BLOCK box (where text-box-trim does apply)
|
|
279
|
+
* whose trimmed line box is then centred by `align-content` — block-container
|
|
280
|
+
* alignment, so no flex formatting context and no anonymous item. The browser
|
|
281
|
+
* computes the band from the font's own metrics, which is what makes it hold
|
|
282
|
+
* across ui-monospace, system-ui and ui-serif instead of needing a constant
|
|
283
|
+
* per stack.
|
|
284
|
+
*
|
|
285
|
+
* CAP band, not the x-height band the general trim uses, because the content
|
|
286
|
+
* class is different: a token is caps and digits (both cap-height), and
|
|
287
|
+
* centring the x-band parks them high by (cap − x)/2. Measured on the shipped
|
|
288
|
+
* stacks, cap-band centring takes an id/count/status from −2.0px to 0.0.
|
|
289
|
+
* Prose and sentence-case labels keep era-text-trim; this is for tokens.
|
|
290
|
+
*
|
|
291
|
+
* @use the ink centring for a token pill — a badge, a KV value, any short
|
|
292
|
+
* caps-or-digits label in a fixed-height box; it needs no icon sibling (with
|
|
293
|
+
* one the box must stay flex, and the general trim applies). */
|
|
294
|
+
@utility era-token-ink {
|
|
295
|
+
display: block;
|
|
296
|
+
align-content: center;
|
|
297
|
+
text-align: center;
|
|
298
|
+
line-height: 1;
|
|
299
|
+
text-box: trim-both cap alphabetic;
|
|
300
|
+
}
|
|
301
|
+
|
|
264
302
|
@utility era-ink-center {
|
|
265
303
|
padding-bottom: 0.08em;
|
|
266
304
|
}
|
|
@@ -12,27 +12,44 @@
|
|
|
12
12
|
* absolute root size (e.g. `html { font-size: 16px }`); see the docs' layout.css.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
+
/*
|
|
16
|
+
* THE SHIPPED STACKS — named, and read directly.
|
|
17
|
+
*
|
|
18
|
+
* These rules used to say `var(--font-mono, <era's stack>)`, treating era's
|
|
19
|
+
* list as a fallback. It never once applied. Tailwind v4 ALWAYS defines
|
|
20
|
+
* --font-mono in its own base theme, so the fallback arm was unreachable and
|
|
21
|
+
* every consumer silently rendered TAILWIND's font stack — while era's docs,
|
|
22
|
+
* which pin --font-mono to generic `monospace` for taste, rendered a third
|
|
23
|
+
* thing. Three different fonts: one the library believed it shipped, one
|
|
24
|
+
* consumers actually got, one the maintainer verified against. Font metrics
|
|
25
|
+
* drive ink centring, so every alignment constant tuned in the docs was
|
|
26
|
+
* calibrated against a font nobody else renders — which is why the same
|
|
27
|
+
* "text isn't vertically centred" bug kept coming back from consumers and
|
|
28
|
+
* kept looking fine here.
|
|
29
|
+
*
|
|
30
|
+
* The axis now reads era's OWN namespaced token, which nothing upstream
|
|
31
|
+
* defines. A consumer (or these docs) re-points a stack by setting
|
|
32
|
+
* --era-font-mono / -sans / -serif; nothing can do it by accident.
|
|
33
|
+
*/
|
|
34
|
+
:root {
|
|
35
|
+
--era-font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;
|
|
36
|
+
--era-font-sans: system-ui, sans-serif;
|
|
37
|
+
--era-font-serif: ui-serif, Georgia, 'Times New Roman', serif;
|
|
38
|
+
}
|
|
39
|
+
|
|
15
40
|
[data-font='mono'],
|
|
16
41
|
[data-font='mono'] * {
|
|
17
|
-
font-family: var(
|
|
18
|
-
--font-mono,
|
|
19
|
-
ui-monospace,
|
|
20
|
-
'SF Mono',
|
|
21
|
-
Menlo,
|
|
22
|
-
Consolas,
|
|
23
|
-
'Liberation Mono',
|
|
24
|
-
monospace
|
|
25
|
-
) !important;
|
|
42
|
+
font-family: var(--era-font-mono) !important;
|
|
26
43
|
}
|
|
27
44
|
|
|
28
45
|
[data-font='sans'],
|
|
29
46
|
[data-font='sans'] * {
|
|
30
|
-
font-family: var(--font-sans
|
|
47
|
+
font-family: var(--era-font-sans) !important;
|
|
31
48
|
}
|
|
32
49
|
|
|
33
50
|
[data-font='serif'],
|
|
34
51
|
[data-font='serif'] * {
|
|
35
|
-
font-family: var(--font-serif
|
|
52
|
+
font-family: var(--era-font-serif) !important;
|
|
36
53
|
}
|
|
37
54
|
|
|
38
55
|
/*
|
|
@@ -11,7 +11,15 @@
|
|
|
11
11
|
// out from under the ink and the label bled past the fill. A pill that must
|
|
12
12
|
// fit a tight row does it the Tool.Chip way: the BOX holds and an inner
|
|
13
13
|
// min-w-0 span truncates. Enforced at runtime by layout/pill-holds-its-ink.
|
|
14
|
-
|
|
14
|
+
// not-has-[svg]: the ink mechanism switches with the content SHAPE.
|
|
15
|
+
//
|
|
16
|
+
// A badge holding only a token (the overwhelming case — an id, a count, a
|
|
17
|
+
// status) becomes a BLOCK box so text-box-trim can actually run; see
|
|
18
|
+
// era-token-ink for why the trim is inert on a flex container and what
|
|
19
|
+
// that cost. A badge holding an icon must stay flex to lay the icon out
|
|
20
|
+
// beside the text, and keeps the general trim — its line-height:1 plus
|
|
21
|
+
// flex centring, which is the best available when the text is anonymous.
|
|
22
|
+
base: 'inline-flex h-(--era-h-xxs) min-w-(--era-h-xxs) shrink-0 items-center justify-center gap-(--era-gap) rounded-(--era-rd-xxs) px-(--era-pill-xxs) font-mono text-body leading-none whitespace-nowrap has-[svg]:gap-(--era-inset-xxs) era-text-trim not-has-[svg]:era-token-ink',
|
|
15
23
|
variants: {
|
|
16
24
|
tone: {
|
|
17
25
|
default: 'bg-fill text-fg',
|
|
@@ -6,7 +6,7 @@ export declare const badgeVariants: import("tailwind-variants").TVReturnType<{
|
|
|
6
6
|
success: "bg-success text-success-fg";
|
|
7
7
|
warning: "bg-warning text-warning-fg";
|
|
8
8
|
};
|
|
9
|
-
}, undefined, "inline-flex h-(--era-h-xxs) min-w-(--era-h-xxs) shrink-0 items-center justify-center gap-(--era-gap) rounded-(--era-rd-xxs) px-(--era-pill-xxs) font-mono text-body leading-none whitespace-nowrap has-[svg]:gap-(--era-inset-xxs) era-text-trim", {
|
|
9
|
+
}, undefined, "inline-flex h-(--era-h-xxs) min-w-(--era-h-xxs) shrink-0 items-center justify-center gap-(--era-gap) rounded-(--era-rd-xxs) px-(--era-pill-xxs) font-mono text-body leading-none whitespace-nowrap has-[svg]:gap-(--era-inset-xxs) era-text-trim not-has-[svg]:era-token-ink", {
|
|
10
10
|
tone: {
|
|
11
11
|
default: "bg-fill text-fg";
|
|
12
12
|
accent: "bg-primary text-primary-fg";
|
package/dist/ui/card/card.svelte
CHANGED
|
@@ -19,7 +19,19 @@
|
|
|
19
19
|
// outer padding — each section pads itself so dividers run edge-to-edge.
|
|
20
20
|
// `p-0` (not just "no class") so a <button> card drops the browser's
|
|
21
21
|
// default button padding and lines up with the <div>/<a> variants.
|
|
22
|
-
|
|
22
|
+
//
|
|
23
|
+
// EVEN on all four sides. This carried a half-height top padding
|
|
24
|
+
// (pt-gutter against pb-pad-md) borrowed from `p-content`, whose
|
|
25
|
+
// asymmetry is earned: a content panel always follows a section heading
|
|
26
|
+
// ROW, and that row's own bar already contributes slack above the text,
|
|
27
|
+
// so padding evenly on top of it spends the space twice. A card has no
|
|
28
|
+
// row above it — its own top edge IS the boundary — so the borrowed
|
|
29
|
+
// rule had nothing to subtract and simply made every card top-heavy
|
|
30
|
+
// (4px above the content against 8px below it, at dense). A consumer
|
|
31
|
+
// reported it as "cards aren't evenly spaced", which is exactly what it
|
|
32
|
+
// was: the even-gap law, broken by default, in the component that
|
|
33
|
+
// bounds more consumer content than any other.
|
|
34
|
+
sectioned: { true: 'p-0', false: 'p-(--era-pad-md)' },
|
|
23
35
|
interactive: {
|
|
24
36
|
true: 'cursor-pointer hover:bg-(--era-highlight) hover:shadow-(--era-highlight-shadow) focus-visible:bg-(--era-highlight) era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50'
|
|
25
37
|
}
|
|
@@ -101,17 +113,15 @@
|
|
|
101
113
|
{#snippet body()}
|
|
102
114
|
{#if sectioned}
|
|
103
115
|
{#if header}
|
|
104
|
-
<div
|
|
105
|
-
class="border-b border-divider-faded px-(--era-pad-md) pt-(--era-gap) pb-(--era-pad-md) text-bright"
|
|
106
|
-
>
|
|
116
|
+
<div class="border-b border-divider-faded p-(--era-pad-md) text-bright">
|
|
107
117
|
{@render header()}
|
|
108
118
|
</div>
|
|
109
119
|
{/if}
|
|
110
|
-
<div class="
|
|
120
|
+
<div class="p-(--era-pad-md)">
|
|
111
121
|
{@render children?.()}
|
|
112
122
|
</div>
|
|
113
123
|
{#if footer}
|
|
114
|
-
<div class="border-t border-divider-faded
|
|
124
|
+
<div class="border-t border-divider-faded p-(--era-pad-md)">
|
|
115
125
|
{@render footer()}
|
|
116
126
|
</div>
|
|
117
127
|
{/if}
|
|
@@ -7,7 +7,7 @@ export declare const cardVariants: import("tailwind-variants").TVReturnType<{
|
|
|
7
7
|
};
|
|
8
8
|
sectioned: {
|
|
9
9
|
true: "p-0";
|
|
10
|
-
false: "
|
|
10
|
+
false: "p-(--era-pad-md)";
|
|
11
11
|
};
|
|
12
12
|
interactive: {
|
|
13
13
|
true: "cursor-pointer hover:bg-(--era-highlight) hover:shadow-(--era-highlight-shadow) focus-visible:bg-(--era-highlight) era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
|
|
@@ -21,7 +21,7 @@ export declare const cardVariants: import("tailwind-variants").TVReturnType<{
|
|
|
21
21
|
};
|
|
22
22
|
sectioned: {
|
|
23
23
|
true: "p-0";
|
|
24
|
-
false: "
|
|
24
|
+
false: "p-(--era-pad-md)";
|
|
25
25
|
};
|
|
26
26
|
interactive: {
|
|
27
27
|
true: "cursor-pointer hover:bg-(--era-highlight) hover:shadow-(--era-highlight-shadow) focus-visible:bg-(--era-highlight) era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
|
|
@@ -35,7 +35,7 @@ export declare const cardVariants: import("tailwind-variants").TVReturnType<{
|
|
|
35
35
|
};
|
|
36
36
|
sectioned: {
|
|
37
37
|
true: "p-0";
|
|
38
|
-
false: "
|
|
38
|
+
false: "p-(--era-pad-md)";
|
|
39
39
|
};
|
|
40
40
|
interactive: {
|
|
41
41
|
true: "cursor-pointer hover:bg-(--era-highlight) hover:shadow-(--era-highlight-shadow) focus-visible:bg-(--era-highlight) era-interactive aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
|
package/dist/ui/kv/kv.svelte
CHANGED
|
@@ -30,7 +30,12 @@
|
|
|
30
30
|
{...restProps}
|
|
31
31
|
>
|
|
32
32
|
<Badge {tone} class="h-full rounded-none border-r border-divider py-0">{key}</Badge>
|
|
33
|
-
|
|
33
|
+
<!-- self-stretch + era-token-ink: a KV value is a token (a number, an id, a
|
|
34
|
+
status), and the block mechanism is the only one where text-box-trim
|
|
35
|
+
actually runs — see era-token-ink. Stretching gives that block a full-
|
|
36
|
+
height box for align-content to centre the trimmed line in. -->
|
|
37
|
+
<span
|
|
38
|
+
class="era-token-ink min-w-(--era-h-xxs) self-stretch px-(--era-inset-sm) text-muted tabular-nums"
|
|
34
39
|
>{value}</span
|
|
35
40
|
>
|
|
36
41
|
</span>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signal9/era-ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "vite dev --host",
|
|
6
6
|
"build": "vite build && npm run prepack",
|
|
@@ -119,6 +119,7 @@
|
|
|
119
119
|
"@types/node": "^24.13.3",
|
|
120
120
|
"@types/three": "^0.184.1",
|
|
121
121
|
"@xyflow/svelte": "^1.6.2",
|
|
122
|
+
"conventional-changelog-conventionalcommits": "^10.2.1",
|
|
122
123
|
"eslint": "^9.39.5",
|
|
123
124
|
"eslint-config-prettier": "^10.1.8",
|
|
124
125
|
"eslint-plugin-better-tailwindcss": "^4.7.0",
|