@signal9/era-ui 5.0.0 → 7.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/ai/prompt-input/prompt-input-textarea.svelte +1 -2
- package/dist/ai/reasoning/reasoning.svelte +4 -0
- package/dist/era-ui.css +1 -1
- package/dist/generated-docs/llms-full.txt +56 -28
- package/dist/generated-docs/llms.txt +22 -3
- 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/index.d.ts +34 -5
- package/dist/index.js +42 -8
- package/dist/os/workspace-storage.svelte.js +1 -1
- package/dist/styles/index.css +61 -13
- package/dist/styles/typography.css +28 -11
- package/dist/styles/video-player.css +27 -0
- package/dist/ui/badge/badge.svelte +9 -1
- package/dist/ui/badge/badge.svelte.d.ts +1 -1
- package/dist/ui/calendar/calendar-root.svelte.d.ts +1 -1
- package/dist/ui/date-field/date-field-root.svelte.d.ts +1 -1
- package/dist/ui/date-picker/date-picker-root.svelte.d.ts +1 -1
- package/dist/ui/date-range-field/date-range-field-root.svelte.d.ts +1 -1
- package/dist/ui/date-range-picker/date-range-picker-root.svelte.d.ts +1 -1
- package/dist/ui/input/textarea.svelte +1 -2
- package/dist/ui/kv/kv.svelte +6 -1
- package/dist/ui/time-field/time-field-root.svelte.d.ts +1 -1
- package/dist/ui/time-range-field/time-range-field-root.svelte.d.ts +1 -1
- package/dist/ui/video-player/video-player.svelte +3 -1
- package/package.json +136 -53
|
@@ -4,13 +4,32 @@
|
|
|
4
4
|
|
|
5
5
|
## Using the library
|
|
6
6
|
|
|
7
|
+
**One entry point per component.** There is no barrel that re-exports everything — importing a component can never drag in another one, or another one's dependencies.
|
|
8
|
+
|
|
7
9
|
```ts
|
|
8
|
-
import { Button
|
|
9
|
-
import "@sig-nine/era-ui/
|
|
10
|
+
import { Button } from "@sig-nine/era-ui/button";
|
|
11
|
+
import * as Select from "@sig-nine/era-ui/select";
|
|
12
|
+
import * as Table from "@sig-nine/era-ui/table";
|
|
13
|
+
|
|
14
|
+
// The root is the SYSTEM layer only: cn/tv, keybindings, the axis
|
|
15
|
+
// registry, and Mode. It imports no component.
|
|
16
|
+
import { cn, ModeProvider } from "@sig-nine/era-ui";
|
|
17
|
+
|
|
18
|
+
import "@sig-nine/era-ui/styles"; // source CSS, scanned by your Tailwind
|
|
10
19
|
```
|
|
11
20
|
|
|
21
|
+
The path is always the component's own kebab-case name — `/button`, `/dropdown-menu`, `/date-range-picker` — and the other layers are namespaced: `/ai` and `/ai/<part>`, `/apps/<app>`, `/os`, `/audit`.
|
|
22
|
+
|
|
12
23
|
Named exports wrap a single primitive (`Button`, `Badge`, `Chip`, `Input`, …). Namespace exports compose primitives via sub-components (`Table.Root`, `Table.Row`, `Select.Trigger`, `Dialog.Content`, …). Every wrapper forwards unknown props to its underlying element or bits-ui primitive, so standard HTML attributes (`class`, `style`, event handlers, `aria-*`, `data-*`) work without ceremony.
|
|
13
24
|
|
|
25
|
+
### Stylesheets
|
|
26
|
+
|
|
27
|
+
`@sig-nine/era-ui/styles` is the source CSS — import it once and your own Tailwind build scans era's components and emits only the utilities they use. `@sig-nine/era-ui/css` is the prebuilt alternative for a project without Tailwind. Two stylesheets are opt-in because they are heavy and single-purpose: `/styles/video-player` (vidstack's vendor CSS, needed only with `VideoPlayer`) and `/styles/themes` (the raw theme tokens).
|
|
28
|
+
|
|
29
|
+
### Optional peers
|
|
30
|
+
|
|
31
|
+
era depends on five packages. Anything needed by ONE component is an optional peer you install only if you import that component: `vidstack` (VideoPlayer), `@neodrag/svelte` (Pane, and the `/os` shell), `marked` + `dompurify` (`/ai/response`), and the tiptap set (`/apps/notes`).
|
|
32
|
+
|
|
14
33
|
## Scoped overrides
|
|
15
34
|
|
|
16
35
|
Five orthogonal axes are exposed as HTML attributes on any ancestor. The entire subtree re-tiers through CSS inheritance — no JS, no context provider.
|
|
@@ -39,7 +58,7 @@ Classes, not components — they need no import beyond the stylesheet. Reach for
|
|
|
39
58
|
- `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
59
|
- `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
60
|
- `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` —
|
|
61
|
+
- `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
62
|
- `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
63
|
- `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
64
|
- `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 +167,7 @@ enough to stay var-form — `min-w-(--era-h-md)` etc. remain the escape hatch.
|
|
|
148
167
|
| `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
168
|
| `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
169
|
| `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` |
|
|
170
|
+
| `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
171
|
| `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
172
|
| `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
173
|
| `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 +359,48 @@ Declared in `index.css`.
|
|
|
340
359
|
}
|
|
341
360
|
```
|
|
342
361
|
|
|
343
|
-
## era-ink-center
|
|
362
|
+
## era-token-ink · era-ink-center
|
|
344
363
|
|
|
345
|
-
**Use it for:**
|
|
364
|
+
**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
365
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
glyphs; see typography/collapsed-text-trim).
|
|
366
|
+
TOKEN INK — the ink centring for a pill whose content is a TOKEN: an id, a
|
|
367
|
+
count, a status, a tag. Font-independent, unlike everything it replaces.
|
|
350
368
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
369
|
+
THE BUG IT FIXES, which had been shipping library-wide and invisibly:
|
|
370
|
+
`text-box-trim` DOES NOTHING ON A FLEX CONTAINER. Era's controls are all
|
|
371
|
+
flex, and a flex container's bare text becomes an ANONYMOUS flex item — a box
|
|
372
|
+
no selector can reach and no non-inherited property can touch. So
|
|
373
|
+
`era-text-trim` on a Badge, a Chip, a Button or a Bar contributed exactly one
|
|
374
|
+
thing: `line-height: 1`. The ink was then centred by `align-items: center`
|
|
375
|
+
on the LINE BOX, which is precisely the font-metric-dependent centring the
|
|
376
|
+
trim exists to eliminate. Measured on the shipped mono stack: a badge reading
|
|
377
|
+
"AC-2.1" sat 2px high in an 18px pill, and no amount of tuning the trim's
|
|
378
|
+
BAND changed it, because the trim was never running.
|
|
355
379
|
|
|
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.
|
|
380
|
+
The mechanism here restores it: a BLOCK box (where text-box-trim does apply)
|
|
381
|
+
whose trimmed line box is then centred by `align-content` — block-container
|
|
382
|
+
alignment, so no flex formatting context and no anonymous item. The browser
|
|
383
|
+
computes the band from the font's own metrics, which is what makes it hold
|
|
384
|
+
across ui-monospace, system-ui and ui-serif instead of needing a constant
|
|
385
|
+
per stack.
|
|
364
386
|
|
|
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.
|
|
387
|
+
CAP band, not the x-height band the general trim uses, because the content
|
|
388
|
+
class is different: a token is caps and digits (both cap-height), and
|
|
389
|
+
centring the x-band parks them high by (cap − x)/2. Measured on the shipped
|
|
390
|
+
stacks, cap-band centring takes an id/count/status from −2.0px to 0.0.
|
|
391
|
+
Prose and sentence-case labels keep era-text-trim; this is for tokens.
|
|
372
392
|
|
|
373
393
|
Declared in `index.css`.
|
|
374
394
|
|
|
375
395
|
```css
|
|
396
|
+
@utility era-token-ink {
|
|
397
|
+
display: block;
|
|
398
|
+
align-content: center;
|
|
399
|
+
text-align: center;
|
|
400
|
+
line-height: 1;
|
|
401
|
+
text-box: trim-both cap alphabetic;
|
|
402
|
+
}
|
|
403
|
+
|
|
376
404
|
@utility era-ink-center {
|
|
377
405
|
padding-bottom: 0.08em;
|
|
378
406
|
}
|
|
@@ -38,13 +38,32 @@ Full derivations: `{{ORIGIN}}/spacing.md` (the ladder and every token), `{{ORIGI
|
|
|
38
38
|
|
|
39
39
|
## Using the library
|
|
40
40
|
|
|
41
|
+
**One entry point per component.** There is no barrel that re-exports everything — importing a component can never drag in another one, or another one's dependencies.
|
|
42
|
+
|
|
41
43
|
```ts
|
|
42
|
-
import { Button
|
|
43
|
-
import "@sig-nine/era-ui/
|
|
44
|
+
import { Button } from "@sig-nine/era-ui/button";
|
|
45
|
+
import * as Select from "@sig-nine/era-ui/select";
|
|
46
|
+
import * as Table from "@sig-nine/era-ui/table";
|
|
47
|
+
|
|
48
|
+
// The root is the SYSTEM layer only: cn/tv, keybindings, the axis
|
|
49
|
+
// registry, and Mode. It imports no component.
|
|
50
|
+
import { cn, ModeProvider } from "@sig-nine/era-ui";
|
|
51
|
+
|
|
52
|
+
import "@sig-nine/era-ui/styles"; // source CSS, scanned by your Tailwind
|
|
44
53
|
```
|
|
45
54
|
|
|
55
|
+
The path is always the component's own kebab-case name — `/button`, `/dropdown-menu`, `/date-range-picker` — and the other layers are namespaced: `/ai` and `/ai/<part>`, `/apps/<app>`, `/os`, `/audit`.
|
|
56
|
+
|
|
46
57
|
Named exports wrap a single primitive (`Button`, `Badge`, `Chip`, `Input`, …). Namespace exports compose primitives via sub-components (`Table.Root`, `Table.Row`, `Select.Trigger`, `Dialog.Content`, …). Every wrapper forwards unknown props to its underlying element or bits-ui primitive, so standard HTML attributes (`class`, `style`, event handlers, `aria-*`, `data-*`) work without ceremony.
|
|
47
58
|
|
|
59
|
+
### Stylesheets
|
|
60
|
+
|
|
61
|
+
`@sig-nine/era-ui/styles` is the source CSS — import it once and your own Tailwind build scans era's components and emits only the utilities they use. `@sig-nine/era-ui/css` is the prebuilt alternative for a project without Tailwind. Two stylesheets are opt-in because they are heavy and single-purpose: `/styles/video-player` (vidstack's vendor CSS, needed only with `VideoPlayer`) and `/styles/themes` (the raw theme tokens).
|
|
62
|
+
|
|
63
|
+
### Optional peers
|
|
64
|
+
|
|
65
|
+
era depends on five packages. Anything needed by ONE component is an optional peer you install only if you import that component: `vidstack` (VideoPlayer), `@neodrag/svelte` (Pane, and the `/os` shell), `marked` + `dompurify` (`/ai/response`), and the tiptap set (`/apps/notes`).
|
|
66
|
+
|
|
48
67
|
## Scoped overrides
|
|
49
68
|
|
|
50
69
|
Five orthogonal axes are exposed as HTML attributes on any ancestor. The entire subtree re-tiers through CSS inheritance — no JS, no context provider.
|
|
@@ -77,7 +96,7 @@ Classes, not components — they need no import beyond the stylesheet. Reach for
|
|
|
77
96
|
- `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.
|
|
78
97
|
- `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.
|
|
79
98
|
- `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`.
|
|
80
|
-
- `era-ink-center` —
|
|
99
|
+
- `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).
|
|
81
100
|
- `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.
|
|
82
101
|
- `era-collapse` — the height sweep for a bits-ui Collapsible.Content — put it on the Content element itself (it carries its own overflow: hidden).
|
|
83
102
|
- `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/index.d.ts
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The SYSTEM layer — and deliberately nothing else.
|
|
3
|
+
*
|
|
4
|
+
* This used to be `export * from './ui/index.js'` plus the OS and AI
|
|
5
|
+
* namespaces: one import that could reach every component in the library. A
|
|
6
|
+
* barrel like that is a guarantee that the whole graph is reachable, and
|
|
7
|
+
* reachable is what matters — `import { Button } from '@signal9/era-ui'` put
|
|
8
|
+
* vidstack (4MB, needed by exactly one component nobody was rendering) into the
|
|
9
|
+
* module graph, where a production bundler MIGHT prove it away and a dev server
|
|
10
|
+
* pre-bundles it regardless. Selectivity that depends on a bundler proving
|
|
11
|
+
* purity is not selectivity; it is luck with good tooling.
|
|
12
|
+
*
|
|
13
|
+
* So the root now carries only what is genuinely cross-cutting and weightless:
|
|
14
|
+
* the class utilities every consumer composes with, the keybinding helpers, and
|
|
15
|
+
* the AXIS REGISTRY plus `Mode` — the design system's own contract, the thing
|
|
16
|
+
* you reach for to set up density/surface/corners/font/motion for a subtree.
|
|
17
|
+
* None of it imports a component; none of it imports a third-party runtime
|
|
18
|
+
* beyond clsx / tailwind-merge / tailwind-variants.
|
|
19
|
+
*
|
|
20
|
+
* Everything else is one import away, at its own entry point:
|
|
21
|
+
*
|
|
22
|
+
* import { Button } from '@signal9/era-ui/button';
|
|
23
|
+
* import * as Select from '@signal9/era-ui/select';
|
|
24
|
+
* import { Swarm } from '@signal9/era-ui/ai/swarm';
|
|
25
|
+
* import { Desktop } from '@signal9/era-ui/os';
|
|
26
|
+
* import { Notes } from '@signal9/era-ui/apps/notes';
|
|
27
|
+
* import { runAudit } from '@signal9/era-ui/audit';
|
|
28
|
+
*
|
|
29
|
+
* The `./*` wildcard in package.json means a new component is importable the
|
|
30
|
+
* moment it exists, with no export map to maintain — and it means no component
|
|
31
|
+
* can ever be pulled in by accident, because nothing re-exports them together.
|
|
32
|
+
*/
|
|
6
33
|
export { cn, tv, hotkeys, keys, parseKeybinding, matchKeyBindingPress, createKeybindingsHandler, formatKeybinding, isApplePlatform, modKey, type KeyBindingMap, type KeyBindingPress, type KeyBindingOptions, type PartProps, type VariantProps } from './utils/index.js';
|
|
34
|
+
export { modes, defaultMode, surfaces, defaultSurface, surfaceRegistry, corners, defaultCorners, fonts, defaultFont, motions, defaultMotion, axisRegistry, axisKeys, type Mode, type Surface, type SurfaceMeta, type Corners, type Font, type Motion, type AxisKey, type AxisMeta, type AxisLevel } from './ui/provider/index.js';
|
|
35
|
+
export { Mode as ModeProvider } from './ui/mode/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
/**
|
|
2
|
+
* The SYSTEM layer — and deliberately nothing else.
|
|
3
|
+
*
|
|
4
|
+
* This used to be `export * from './ui/index.js'` plus the OS and AI
|
|
5
|
+
* namespaces: one import that could reach every component in the library. A
|
|
6
|
+
* barrel like that is a guarantee that the whole graph is reachable, and
|
|
7
|
+
* reachable is what matters — `import { Button } from '@signal9/era-ui'` put
|
|
8
|
+
* vidstack (4MB, needed by exactly one component nobody was rendering) into the
|
|
9
|
+
* module graph, where a production bundler MIGHT prove it away and a dev server
|
|
10
|
+
* pre-bundles it regardless. Selectivity that depends on a bundler proving
|
|
11
|
+
* purity is not selectivity; it is luck with good tooling.
|
|
12
|
+
*
|
|
13
|
+
* So the root now carries only what is genuinely cross-cutting and weightless:
|
|
14
|
+
* the class utilities every consumer composes with, the keybinding helpers, and
|
|
15
|
+
* the AXIS REGISTRY plus `Mode` — the design system's own contract, the thing
|
|
16
|
+
* you reach for to set up density/surface/corners/font/motion for a subtree.
|
|
17
|
+
* None of it imports a component; none of it imports a third-party runtime
|
|
18
|
+
* beyond clsx / tailwind-merge / tailwind-variants.
|
|
19
|
+
*
|
|
20
|
+
* Everything else is one import away, at its own entry point:
|
|
21
|
+
*
|
|
22
|
+
* import { Button } from '@signal9/era-ui/button';
|
|
23
|
+
* import * as Select from '@signal9/era-ui/select';
|
|
24
|
+
* import { Swarm } from '@signal9/era-ui/ai/swarm';
|
|
25
|
+
* import { Desktop } from '@signal9/era-ui/os';
|
|
26
|
+
* import { Notes } from '@signal9/era-ui/apps/notes';
|
|
27
|
+
* import { runAudit } from '@signal9/era-ui/audit';
|
|
28
|
+
*
|
|
29
|
+
* The `./*` wildcard in package.json means a new component is importable the
|
|
30
|
+
* moment it exists, with no export map to maintain — and it means no component
|
|
31
|
+
* can ever be pulled in by accident, because nothing re-exports them together.
|
|
32
|
+
*/
|
|
33
|
+
/* The composition utilities: `cn` for class merging (era-aware — it knows the
|
|
34
|
+
* tier/radius/shadow scales), `tv` for variants, and the keybinding layer. */
|
|
9
35
|
export { cn, tv, hotkeys, keys, parseKeybinding, matchKeyBindingPress, createKeybindingsHandler, formatKeybinding, isApplePlatform, modKey } from './utils/index.js';
|
|
36
|
+
/* The axis contract — the five orthogonal display axes, their levels, their
|
|
37
|
+
* defaults, and the registry that drives every picker built on top of them.
|
|
38
|
+
* Pure data: no component, no DOM, no dependency. */
|
|
39
|
+
export { modes, defaultMode, surfaces, defaultSurface, surfaceRegistry, corners, defaultCorners, fonts, defaultFont, motions, defaultMotion, axisRegistry, axisKeys } from './ui/provider/index.js';
|
|
40
|
+
/* `Mode` applies those axes (plus optional accent overrides) to a subtree. It
|
|
41
|
+
* is the one component that belongs here: it configures the system rather than
|
|
42
|
+
* being a piece of UI, and it imports nothing but types. */
|
|
43
|
+
export { Mode as ModeProvider } from './ui/mode/index.js';
|
package/dist/styles/index.css
CHANGED
|
@@ -11,21 +11,31 @@
|
|
|
11
11
|
@import './surfaces/bevel.css';
|
|
12
12
|
@import './typography.css';
|
|
13
13
|
|
|
14
|
-
/*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
/* WHAT IS NOT HERE: vidstack's stylesheets, which the VideoPlayer needs and
|
|
15
|
+
* nothing else does. They were imported right here, so every consumer of this
|
|
16
|
+
* file paid 46KB — 37% of the built stylesheet — for a component almost none of
|
|
17
|
+
* them render. They now live in ./video-player.css, published as
|
|
18
|
+
* `@signal9/era-ui/styles/video-player`, and only a consumer using the player
|
|
19
|
+
* imports them.
|
|
20
|
+
*
|
|
21
|
+
* The split is by DEPENDENCY WEIGHT, not by layer, and that is deliberate.
|
|
22
|
+
* Tailwind utilities DEDUPE — 60-odd components share one small vocabulary of
|
|
23
|
+
* flex/h-md/items-center, so scanning every layer below costs almost nothing
|
|
24
|
+
* and cannot be forgotten. Third-party CSS is the opposite: it is unshared,
|
|
25
|
+
* heavy, and belongs to exactly one component. Split what is unshared; keep
|
|
26
|
+
* what is shared whole. */
|
|
26
27
|
|
|
27
|
-
/*
|
|
28
|
+
/* Scan every SHIPPED layer for utility classes, not just ui.
|
|
29
|
+
*
|
|
30
|
+
* This read `@source '../ui'` alone, so a consumer on the source-CSS path got
|
|
31
|
+
* no utilities generated for any ai/, os/ or apps/ component — those rendered
|
|
32
|
+
* structurally correct and completely unstyled, silently. The scan follows the
|
|
33
|
+
* package's layers so that adding a layer means adding a line here, and
|
|
34
|
+
* nothing else. */
|
|
28
35
|
@source '../ui';
|
|
36
|
+
@source '../ai';
|
|
37
|
+
@source '../os';
|
|
38
|
+
@source '../apps';
|
|
29
39
|
|
|
30
40
|
/* Lucide icons use an SVG presentation attribute for stroke width by default.
|
|
31
41
|
* Set it from an Era token globally so every imported Lucide component tracks
|
|
@@ -261,6 +271,44 @@
|
|
|
261
271
|
*
|
|
262
272
|
* @use on a native single-line <input> (or the text layer that must mirror
|
|
263
273
|
* one) inside a fixed-height field — never alongside era-text-trim. */
|
|
274
|
+
/* TOKEN INK — the ink centring for a pill whose content is a TOKEN: an id, a
|
|
275
|
+
* count, a status, a tag. Font-independent, unlike everything it replaces.
|
|
276
|
+
*
|
|
277
|
+
* THE BUG IT FIXES, which had been shipping library-wide and invisibly:
|
|
278
|
+
* `text-box-trim` DOES NOTHING ON A FLEX CONTAINER. Era's controls are all
|
|
279
|
+
* flex, and a flex container's bare text becomes an ANONYMOUS flex item — a box
|
|
280
|
+
* no selector can reach and no non-inherited property can touch. So
|
|
281
|
+
* `era-text-trim` on a Badge, a Chip, a Button or a Bar contributed exactly one
|
|
282
|
+
* thing: `line-height: 1`. The ink was then centred by `align-items: center`
|
|
283
|
+
* on the LINE BOX, which is precisely the font-metric-dependent centring the
|
|
284
|
+
* trim exists to eliminate. Measured on the shipped mono stack: a badge reading
|
|
285
|
+
* "AC-2.1" sat 2px high in an 18px pill, and no amount of tuning the trim's
|
|
286
|
+
* BAND changed it, because the trim was never running.
|
|
287
|
+
*
|
|
288
|
+
* The mechanism here restores it: a BLOCK box (where text-box-trim does apply)
|
|
289
|
+
* whose trimmed line box is then centred by `align-content` — block-container
|
|
290
|
+
* alignment, so no flex formatting context and no anonymous item. The browser
|
|
291
|
+
* computes the band from the font's own metrics, which is what makes it hold
|
|
292
|
+
* across ui-monospace, system-ui and ui-serif instead of needing a constant
|
|
293
|
+
* per stack.
|
|
294
|
+
*
|
|
295
|
+
* CAP band, not the x-height band the general trim uses, because the content
|
|
296
|
+
* class is different: a token is caps and digits (both cap-height), and
|
|
297
|
+
* centring the x-band parks them high by (cap − x)/2. Measured on the shipped
|
|
298
|
+
* stacks, cap-band centring takes an id/count/status from −2.0px to 0.0.
|
|
299
|
+
* Prose and sentence-case labels keep era-text-trim; this is for tokens.
|
|
300
|
+
*
|
|
301
|
+
* @use the ink centring for a token pill — a badge, a KV value, any short
|
|
302
|
+
* caps-or-digits label in a fixed-height box; it needs no icon sibling (with
|
|
303
|
+
* one the box must stay flex, and the general trim applies). */
|
|
304
|
+
@utility era-token-ink {
|
|
305
|
+
display: block;
|
|
306
|
+
align-content: center;
|
|
307
|
+
text-align: center;
|
|
308
|
+
line-height: 1;
|
|
309
|
+
text-box: trim-both cap alphabetic;
|
|
310
|
+
}
|
|
311
|
+
|
|
264
312
|
@utility era-ink-center {
|
|
265
313
|
padding-bottom: 0.08em;
|
|
266
314
|
}
|