@signal9/era-ui 9.0.0 → 10.1.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/artifact/artifact-close.svelte +2 -2
- package/dist/ai/checkpoint.svelte +1 -1
- package/dist/ai/context/context.svelte +1 -1
- package/dist/ai/conversation/conversation-scroll-button.svelte +1 -1
- package/dist/ai/conversations/conversations-item.svelte +3 -3
- package/dist/ai/index.js +1 -1
- package/dist/ai/message/message-branch-selector.svelte +2 -2
- package/dist/ai/message/message-usage.svelte +1 -1
- package/dist/ai/prompt-input/prompt-input-add-attachments.svelte +1 -1
- package/dist/ai/prompt-input/prompt-input-attachments.svelte +1 -1
- package/dist/ai/prompt-input/prompt-input-submit.svelte +1 -1
- package/dist/ai/run-status/run-status.svelte +4 -3
- package/dist/ai/suggestion/suggestion.svelte +1 -1
- package/dist/ai/swarm/swarm-actions.svelte +2 -2
- package/dist/ai/swarm/swarm-agent.svelte +2 -2
- package/dist/ai/swarm/swarm-artifact.svelte +1 -1
- package/dist/ai/swarm/swarm-barrier.svelte +1 -1
- package/dist/ai/swarm/swarm-footer.svelte +3 -2
- package/dist/ai/swarm/swarm-header.svelte +1 -1
- package/dist/ai/swarm/swarm-node.svelte +1 -1
- package/dist/ai/swarm/swarm-role.svelte +5 -2
- package/dist/ai/tool/tool-chip.svelte +1 -1
- package/dist/ai/web-preview/web-preview.svelte +2 -2
- package/dist/apps/index.d.ts +3 -3
- package/dist/apps/index.js +3 -3
- package/dist/apps/notes/editor/bubble-toolbar.svelte +3 -3
- package/dist/apps/notes/editor/slash-menu.svelte +2 -4
- package/dist/apps/notes/notes.svelte +12 -12
- package/dist/dev/audit/audits/anonymous-text.d.ts +2 -0
- package/dist/dev/audit/audits/anonymous-text.js +73 -0
- package/dist/dev/audit/audits/index.d.ts +2 -1
- package/dist/dev/audit/audits/index.js +3 -1
- package/dist/dev/audit/types.d.ts +1 -1
- package/dist/docs/css-utilities.js +1 -1
- package/dist/docs/llms-txt.js +2 -2
- package/dist/docs/notes.md +3 -3
- package/dist/era-ui.css +1 -1
- package/dist/generated-docs/bar.md +2 -2
- package/dist/generated-docs/button.md +1 -1
- package/dist/generated-docs/chip.md +1 -1
- package/dist/generated-docs/input.md +1 -1
- package/dist/generated-docs/llms-full.txt +101 -21
- package/dist/generated-docs/llms.txt +11 -7
- package/dist/generated-docs/manifest.json +32 -11
- package/dist/generated-docs/notes.md +3 -3
- package/dist/generated-docs/utilities.json +23 -4
- package/dist/generated-docs/utilities.md +82 -6
- package/dist/os/notification-center.svelte +1 -1
- package/dist/os/pane.svelte +2 -2
- package/dist/os/taskbar.svelte +4 -4
- package/dist/os/toast.svelte +2 -2
- package/dist/styles/index.css +43 -5
- package/dist/ui/bar/bar.svelte +13 -13
- package/dist/ui/bar/bar.svelte.d.ts +15 -15
- package/dist/ui/button/button.svelte +15 -4
- package/dist/ui/button/button.svelte.d.ts +1 -1
- package/dist/ui/button/index.d.ts +1 -1
- package/dist/ui/button/variants.d.ts +10 -13
- package/dist/ui/button/variants.js +13 -15
- package/dist/ui/chip/chip.svelte +25 -15
- package/dist/ui/chip/chip.svelte.d.ts +8 -8
- package/dist/ui/command/command-item.svelte +1 -1
- package/dist/ui/command/command-link-item.svelte +1 -1
- package/dist/ui/command-bar/command-bar.svelte +1 -1
- package/dist/ui/copy-button/copy-button.svelte +1 -1
- package/dist/ui/dialog/dialog-header.svelte +7 -2
- package/dist/ui/index.js +1 -1
- package/dist/ui/input/input.svelte +3 -3
- package/dist/ui/input/input.svelte.d.ts +1 -1
- package/dist/ui/input/variants.d.ts +6 -6
- package/dist/ui/input/variants.js +3 -3
- package/dist/ui/kv/kv.svelte +1 -1
- package/dist/ui/pane/pane-close.svelte +2 -2
- package/dist/ui/pane/pane-handle.svelte +3 -3
- package/dist/ui/select/select-trigger.svelte +1 -1
- package/dist/ui/select/select-value.svelte +1 -1
- package/dist/ui/step/step-summary.svelte +1 -1
- package/package.json +1 -1
|
@@ -4,18 +4,20 @@
|
|
|
4
4
|
|
|
5
5
|
## Using the library
|
|
6
6
|
|
|
7
|
+
This package is published to two registries under two names: `@signal9/era-ui` on npm (used throughout these docs) and `@sig-nine/era-ui` on GitHub Packages, where the scope must match the repo owner. Same code, same versions — pick the one your registry serves and keep the scope consistent.
|
|
8
|
+
|
|
7
9
|
**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
10
|
|
|
9
11
|
```ts
|
|
10
|
-
import { Button } from "@
|
|
11
|
-
import * as Select from "@
|
|
12
|
-
import * as Table from "@
|
|
12
|
+
import { Button } from "@signal9/era-ui/button";
|
|
13
|
+
import * as Select from "@signal9/era-ui/select";
|
|
14
|
+
import * as Table from "@signal9/era-ui/table";
|
|
13
15
|
|
|
14
16
|
// The root is the SYSTEM layer only: cn/tv, keybindings, the axis
|
|
15
17
|
// registry, and Mode. It imports no component.
|
|
16
|
-
import { cn, ModeProvider } from "@
|
|
18
|
+
import { cn, ModeProvider } from "@signal9/era-ui";
|
|
17
19
|
|
|
18
|
-
import "@
|
|
20
|
+
import "@signal9/era-ui/styles"; // source CSS, scanned by your Tailwind
|
|
19
21
|
```
|
|
20
22
|
|
|
21
23
|
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`.
|
|
@@ -24,7 +26,7 @@ Named exports wrap a single primitive (`Button`, `Badge`, `Chip`, `Input`, …).
|
|
|
24
26
|
|
|
25
27
|
### Stylesheets
|
|
26
28
|
|
|
27
|
-
`@
|
|
29
|
+
`@signal9/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. `@signal9/era-ui/css` is the prebuilt alternative for a project without Tailwind. Three more are opt-in, each single-purpose: `/styles/video-player` (vidstack's vendor CSS, needed only with `VideoPlayer`), `/styles/prose` (document typography for a TipTap editor — put `era-notes-prose` on your editor element; `NoteEditor` imports it already), and `/styles/themes` (the raw theme tokens).
|
|
28
30
|
|
|
29
31
|
### Optional peers
|
|
30
32
|
|
|
@@ -58,7 +60,9 @@ Classes, not components — they need no import beyond the stylesheet. Reach for
|
|
|
58
60
|
- `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.
|
|
59
61
|
- `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.
|
|
60
62
|
- `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`.
|
|
61
|
-
- `era-
|
|
63
|
+
- `era-ink-center` — on a native single-line <input> (or the text layer that must mirror one) inside a fixed-height field — never alongside era-text-trim.
|
|
64
|
+
- `era-token-ink` — the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box, CENTRED horizontally and with no icon sibling. For a left-aligned sentence-case label use era-label-ink; when an icon really must sit beside the text, see the note there.
|
|
65
|
+
- `era-label-ink` — the ink centring for a fixed-height control holding ONE line of sentence-case text and no icon — a menu item, a nav trigger, a button label. Never alongside `truncate` (the trimmed box becomes the clip).
|
|
62
66
|
- `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.
|
|
63
67
|
- `era-collapse` — the height sweep for a bits-ui Collapsible.Content — put it on the Content element itself (it carries its own overflow: hidden).
|
|
64
68
|
- `h-icon · h-pill · h-chip · h-control · h-bar` — the tier-height ladder — h-icon (icon) · h-pill (nested pill) · h-chip (standalone pill) · h-control (control) · h-bar (bar); the named form of h-(--era-h-*).
|
|
@@ -131,7 +135,7 @@ never the `h-(--era-h-control)` var-class spelling. Everything below rides along
|
|
|
131
135
|
with the stylesheet and needs no import:
|
|
132
136
|
|
|
133
137
|
```ts
|
|
134
|
-
import "@
|
|
138
|
+
import "@signal9/era-ui/css";
|
|
135
139
|
```
|
|
136
140
|
|
|
137
141
|
```svelte
|
|
@@ -166,7 +170,9 @@ enough to stay var-form — `min-w-(--era-h-control)` etc. remain the escape hat
|
|
|
166
170
|
| `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. |
|
|
167
171
|
| `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. |
|
|
168
172
|
| `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`. |
|
|
169
|
-
| `era-
|
|
173
|
+
| `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. |
|
|
174
|
+
| `era-token-ink` | the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box, CENTRED horizontally and with no icon sibling. For a left-aligned sentence-case label use era-label-ink; when an icon really must sit beside the text, see the note there. |
|
|
175
|
+
| `era-label-ink` | the ink centring for a fixed-height control holding ONE line of sentence-case text and no icon — a menu item, a nav trigger, a button label. Never alongside `truncate` (the trimmed box becomes the clip). |
|
|
170
176
|
| `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. |
|
|
171
177
|
| `era-collapse` | the height sweep for a bits-ui Collapsible.Content — put it on the Content element itself (it carries its own overflow: hidden). |
|
|
172
178
|
| `h-icon` `h-pill` `h-chip` `h-control` `h-bar` | the tier-height ladder — h-icon (icon) · h-pill (nested pill) · h-chip (standalone pill) · h-control (control) · h-bar (bar); the named form of h-(--era-h-*). |
|
|
@@ -357,9 +363,47 @@ Declared in `index.css`.
|
|
|
357
363
|
}
|
|
358
364
|
```
|
|
359
365
|
|
|
360
|
-
## era-
|
|
366
|
+
## era-ink-center
|
|
367
|
+
|
|
368
|
+
**Use it for:** on a native single-line <input> (or the text layer that must mirror one) inside a fixed-height field — never alongside era-text-trim.
|
|
369
|
+
|
|
370
|
+
The EDITABLE counterpart of era-text-trim — for native <input>s, which the
|
|
371
|
+
trim is forbidden on (it collapses the UA's inner editor box and slices the
|
|
372
|
+
glyphs; see typography/collapsed-text-trim).
|
|
373
|
+
|
|
374
|
+
Without help, a tier-height input centres its text by FONT BOX, and the ui
|
|
375
|
+
stacks' font box is deeply asymmetric: ascent ≈1.07em against descent
|
|
376
|
+
≈0.29em. Centring that box parks the visible band (caps, x-height) ~0.115em
|
|
377
|
+
LOW — so a field's text sat visibly below the trimmed label beside it.
|
|
378
|
+
|
|
379
|
+
The value is OPTICAL, not the derivation's: pure x-band centring computes
|
|
380
|
+
to ~0.23em of padding, but pixel-measured against real Title-Case text it
|
|
381
|
+
over-lifts — the eye weighs the cap-to-baseline mass, which x-band
|
|
382
|
+
centring parks ~2px high (caps 2.75px off the top against 5.7px of air
|
|
383
|
+
under the baseline, measured at dense). 0.08em splits the difference
|
|
384
|
+
between the x-band ideal and the cap-band ideal, landing caps ~3.7px in an
|
|
385
|
+
18px field with ~4.7px under the baseline — the reading where neither
|
|
386
|
+
band's partisans win and neither complains.
|
|
387
|
+
|
|
388
|
+
The lift is padding, not a translateY: an icon-less Input paints the field
|
|
389
|
+
chrome itself, and a transform would drag the field along with the ink.
|
|
390
|
+
padding-bottom shrinks the content box from below, and a single-line input
|
|
391
|
+
re-centres its line box in what remains — the ink rises by exactly half the
|
|
392
|
+
padding, the chrome doesn't move, and the caret and selection follow the
|
|
393
|
+
text. In em on purpose: the correction is a fraction of the type, so it
|
|
394
|
+
holds across every density and text size with one value.
|
|
395
|
+
|
|
396
|
+
Declared in `index.css`.
|
|
397
|
+
|
|
398
|
+
```css
|
|
399
|
+
@utility era-ink-center {
|
|
400
|
+
padding-bottom: 0.08em;
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
## era-token-ink
|
|
361
405
|
|
|
362
|
-
**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
|
|
406
|
+
**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, CENTRED horizontally and with no icon sibling. For a left-aligned sentence-case label use era-label-ink; when an icon really must sit beside the text, see the note there.
|
|
363
407
|
|
|
364
408
|
TOKEN INK — the ink centring for a pill whose content is a TOKEN: an id, a
|
|
365
409
|
count, a status, a tag. Font-independent, unlike everything it replaces.
|
|
@@ -398,9 +442,45 @@ Declared in `index.css`.
|
|
|
398
442
|
line-height: 1;
|
|
399
443
|
text-box: trim-both cap alphabetic;
|
|
400
444
|
}
|
|
445
|
+
```
|
|
401
446
|
|
|
402
|
-
|
|
403
|
-
|
|
447
|
+
## era-label-ink
|
|
448
|
+
|
|
449
|
+
**Use it for:** the ink centring for a fixed-height control holding ONE line of sentence-case text and no icon — a menu item, a nav trigger, a button label. Never alongside `truncate` (the trimmed box becomes the clip).
|
|
450
|
+
|
|
451
|
+
LABEL INK — era-token-ink's mixed-case sibling, and the general answer to
|
|
452
|
+
"this fixed-height control holds one line of text".
|
|
453
|
+
|
|
454
|
+
Same mechanism, same reason: `text-box-trim` needs a BLOCK box, so the row
|
|
455
|
+
becomes one and `align-content` (block-container alignment) does the
|
|
456
|
+
centring. What differs is the band and the alignment, because the content
|
|
457
|
+
class differs — a label is sentence case, so the x-height band is the visual
|
|
458
|
+
mass to centre (cap-band reads low on "System"), and it is laid out against
|
|
459
|
+
the row's padding rather than centred in it.
|
|
460
|
+
|
|
461
|
+
WHY IT EXISTS AT ALL: era's controls are flex, and a flex container's bare
|
|
462
|
+
text is an ANONYMOUS flex item — a box no selector reaches and no
|
|
463
|
+
non-inherited property touches. So `era-text-trim` on a flex row is inert,
|
|
464
|
+
contributing only its `line-height: 1`, and the ink falls back to line-box
|
|
465
|
+
centring by font metrics. era-token-ink already fixed that for centred
|
|
466
|
+
tokens; this fixes it for everything else.
|
|
467
|
+
|
|
468
|
+
THE ICON CASE IS NOT SOLVED, and cannot be from CSS: an icon beside the text
|
|
469
|
+
needs the box to stay flex, which re-creates the anonymous item. A component
|
|
470
|
+
whose children are an opaque slot therefore guards it —
|
|
471
|
+
`not-has-[svg]:era-label-ink` — and ink-centres the text-only case while
|
|
472
|
+
leaving the icon case on line-box centring. Splitting icon and label into
|
|
473
|
+
separate slots is what would close it; typography/inert-trim reports every
|
|
474
|
+
site still on the fallback.
|
|
475
|
+
|
|
476
|
+
Declared in `index.css`.
|
|
477
|
+
|
|
478
|
+
```css
|
|
479
|
+
@utility era-label-ink {
|
|
480
|
+
display: block;
|
|
481
|
+
align-content: center;
|
|
482
|
+
line-height: 1;
|
|
483
|
+
text-box: trim-both ex alphabetic;
|
|
404
484
|
}
|
|
405
485
|
```
|
|
406
486
|
|
|
@@ -755,13 +835,13 @@ A complete notes app — rich-text editor, slash commands, local persistence.
|
|
|
755
835
|
|
|
756
836
|
## Usage
|
|
757
837
|
|
|
758
|
-
Apps ship on their own subpath and are **not** re-exported from `@
|
|
838
|
+
Apps ship on their own subpath and are **not** re-exported from `@signal9/era-ui`.
|
|
759
839
|
Notes carries TipTap, and a consumer who never imports an app should never pay
|
|
760
840
|
for it.
|
|
761
841
|
|
|
762
842
|
```svelte
|
|
763
843
|
<script>
|
|
764
|
-
import { Notes } from '@
|
|
844
|
+
import { Notes } from '@signal9/era-ui/apps';
|
|
765
845
|
</script>
|
|
766
846
|
|
|
767
847
|
<Notes />
|
|
@@ -801,7 +881,7 @@ Persistence is one small interface, so server-backed hosting is a drop-in swap
|
|
|
801
881
|
`load`/`save` may be sync or async:
|
|
802
882
|
|
|
803
883
|
```ts
|
|
804
|
-
import { Notes, NotesStore } from '@
|
|
884
|
+
import { Notes, NotesStore } from '@signal9/era-ui/apps';
|
|
805
885
|
|
|
806
886
|
const store = new NotesStore({
|
|
807
887
|
adapter: {
|
|
@@ -966,8 +1046,8 @@ Inherits all props from `HTMLAttributes<HTMLDivElement>`.
|
|
|
966
1046
|
| Prop | Type | Default | Notes |
|
|
967
1047
|
|------|------|---------|-------|
|
|
968
1048
|
| `ref?` | `HTMLDivElement \| null` | `null` | bindable |
|
|
969
|
-
| `size?` | `'
|
|
970
|
-
| `content?` | `'tier' \| '
|
|
1049
|
+
| `size?` | `'chip' \| 'control' \| 'bar'` | `'bar'` | Height tier (scales with density). Default `lg` — a full toolbar. |
|
|
1050
|
+
| `content?` | `'tier' \| 'pill'` | `'tier'` | Tier of the controls inside — drives the bar's padding and gap so they
|
|
971
1051
|
stay concentric to them. `tier` (default) is one tier smaller; `pill` is
|
|
972
1052
|
the compact pairing (pills/fields in an sm or md bar). |
|
|
973
1053
|
| `divider?` | `boolean` | `false` | The flush cap-a-panel chrome: outset divider below, bottom rd-md. |
|
|
@@ -994,7 +1074,7 @@ Inherits all props from `Button.RootProps`.
|
|
|
994
1074
|
| Prop | Type | Default | Notes |
|
|
995
1075
|
|------|------|---------|-------|
|
|
996
1076
|
| `tone?` | `'default' \| 'accent' \| 'destructive' \| 'success' \| 'warning'` | `'default'` | — |
|
|
997
|
-
| `size?` | `'
|
|
1077
|
+
| `size?` | `'control' \| 'chip' \| 'pill' \| 'icon'` | `'control'` | — |
|
|
998
1078
|
| `variant?` | `'filled' \| 'link'` | `'filled'` | — |
|
|
999
1079
|
| `active?` | `boolean` | `false` | — |
|
|
1000
1080
|
| `icon?` | `boolean` | `false` | — |
|
|
@@ -1142,7 +1222,7 @@ Inherits all props from `HTMLAttributes<HTMLDivElement>`.
|
|
|
1142
1222
|
| Prop | Type | Default | Notes |
|
|
1143
1223
|
|------|------|---------|-------|
|
|
1144
1224
|
| `ref?` | `HTMLDivElement \| null` | `null` | bindable |
|
|
1145
|
-
| `size?` | `'
|
|
1225
|
+
| `size?` | `'chip' \| 'pill'` | `'chip'` | `sm` (default) is the standalone free chip; `pill` is the smaller pill
|
|
1146
1226
|
that nests inside an md container (a select trigger, a button). |
|
|
1147
1227
|
| `ondismiss?` | `() => void` | — | — |
|
|
1148
1228
|
| `children?` | `Snippet` | — | — |
|
|
@@ -2933,7 +3013,7 @@ Inherits all props from `Omit<HTMLInputAttributes, 'size'>`.
|
|
|
2933
3013
|
|------|------|---------|-------|
|
|
2934
3014
|
| `ref?` | `HTMLInputElement \| null` | `null` | bindable |
|
|
2935
3015
|
| `icon?` | `Component<IconProps> \| null` | `null` | Lucide glyph rendered inside the field, left of the text. |
|
|
2936
|
-
| `size?` | `'
|
|
3016
|
+
| `size?` | `'control' \| 'pill'` | `'control'` | Field tier. `pill` is badge height — for compact chrome where the field
|
|
2937
3017
|
sits level with xxs buttons. See inputVariants. |
|
|
2938
3018
|
| `bare?` | `boolean` | `false` | Drop the field chrome — for an input inside a container that is already the field. |
|
|
2939
3019
|
| `reveal?` | `boolean` | `false` | Hold the field chrome back until hover — for a title or label that IS the content. |
|
|
@@ -38,18 +38,20 @@ Full derivations: `{{ORIGIN}}/spacing.md` (the ladder and every token), `{{ORIGI
|
|
|
38
38
|
|
|
39
39
|
## Using the library
|
|
40
40
|
|
|
41
|
+
This package is published to two registries under two names: `@signal9/era-ui` on npm (used throughout these docs) and `@sig-nine/era-ui` on GitHub Packages, where the scope must match the repo owner. Same code, same versions — pick the one your registry serves and keep the scope consistent.
|
|
42
|
+
|
|
41
43
|
**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
44
|
|
|
43
45
|
```ts
|
|
44
|
-
import { Button } from "@
|
|
45
|
-
import * as Select from "@
|
|
46
|
-
import * as Table from "@
|
|
46
|
+
import { Button } from "@signal9/era-ui/button";
|
|
47
|
+
import * as Select from "@signal9/era-ui/select";
|
|
48
|
+
import * as Table from "@signal9/era-ui/table";
|
|
47
49
|
|
|
48
50
|
// The root is the SYSTEM layer only: cn/tv, keybindings, the axis
|
|
49
51
|
// registry, and Mode. It imports no component.
|
|
50
|
-
import { cn, ModeProvider } from "@
|
|
52
|
+
import { cn, ModeProvider } from "@signal9/era-ui";
|
|
51
53
|
|
|
52
|
-
import "@
|
|
54
|
+
import "@signal9/era-ui/styles"; // source CSS, scanned by your Tailwind
|
|
53
55
|
```
|
|
54
56
|
|
|
55
57
|
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`.
|
|
@@ -58,7 +60,7 @@ Named exports wrap a single primitive (`Button`, `Badge`, `Chip`, `Input`, …).
|
|
|
58
60
|
|
|
59
61
|
### Stylesheets
|
|
60
62
|
|
|
61
|
-
`@
|
|
63
|
+
`@signal9/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. `@signal9/era-ui/css` is the prebuilt alternative for a project without Tailwind. Three more are opt-in, each single-purpose: `/styles/video-player` (vidstack's vendor CSS, needed only with `VideoPlayer`), `/styles/prose` (document typography for a TipTap editor — put `era-notes-prose` on your editor element; `NoteEditor` imports it already), and `/styles/themes` (the raw theme tokens).
|
|
62
64
|
|
|
63
65
|
### Optional peers
|
|
64
66
|
|
|
@@ -96,7 +98,9 @@ Classes, not components — they need no import beyond the stylesheet. Reach for
|
|
|
96
98
|
- `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.
|
|
97
99
|
- `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.
|
|
98
100
|
- `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`.
|
|
99
|
-
- `era-
|
|
101
|
+
- `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.
|
|
102
|
+
- `era-token-ink` — the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box, CENTRED horizontally and with no icon sibling. For a left-aligned sentence-case label use era-label-ink; when an icon really must sit beside the text, see the note there.
|
|
103
|
+
- `era-label-ink` — the ink centring for a fixed-height control holding ONE line of sentence-case text and no icon — a menu item, a nav trigger, a button label. Never alongside `truncate` (the trimmed box becomes the clip).
|
|
100
104
|
- `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.
|
|
101
105
|
- `era-collapse` — the height sweep for a bits-ui Collapsible.Content — put it on the Content element itself (it carries its own overflow: hidden).
|
|
102
106
|
- `h-icon · h-pill · h-chip · h-control · h-bar` — the tier-height ladder — h-icon (icon) · h-pill (nested pill) · h-chip (standalone pill) · h-control (control) · h-bar (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": 7162,
|
|
48
48
|
"sections": [
|
|
49
49
|
"Overview",
|
|
50
50
|
"era-interactive",
|
|
@@ -53,7 +53,9 @@
|
|
|
53
53
|
"era-text-trim",
|
|
54
54
|
"truncate",
|
|
55
55
|
"era-text-trim-caps",
|
|
56
|
-
"era-
|
|
56
|
+
"era-ink-center",
|
|
57
|
+
"era-token-ink",
|
|
58
|
+
"era-label-ink",
|
|
57
59
|
"era-shimmer",
|
|
58
60
|
"era-collapse",
|
|
59
61
|
"h-icon · h-pill · h-chip · h-control · h-bar",
|
|
@@ -107,7 +109,7 @@
|
|
|
107
109
|
"slug": "notes",
|
|
108
110
|
"title": "Notes",
|
|
109
111
|
"summary": "A complete notes app — rich-text editor, slash commands, local persistence.",
|
|
110
|
-
"tokenEstimate":
|
|
112
|
+
"tokenEstimate": 884,
|
|
111
113
|
"sections": [
|
|
112
114
|
"Usage",
|
|
113
115
|
"Peer dependencies",
|
|
@@ -159,7 +161,7 @@
|
|
|
159
161
|
"slug": "bar",
|
|
160
162
|
"title": "Bar",
|
|
161
163
|
"summary": "A flex container for toolbars and headers, in three heights.",
|
|
162
|
-
"tokenEstimate":
|
|
164
|
+
"tokenEstimate": 209,
|
|
163
165
|
"sections": [
|
|
164
166
|
"Import",
|
|
165
167
|
"Props"
|
|
@@ -170,7 +172,7 @@
|
|
|
170
172
|
"slug": "button",
|
|
171
173
|
"title": "Button",
|
|
172
174
|
"summary": "A flexible button or link element.",
|
|
173
|
-
"tokenEstimate":
|
|
175
|
+
"tokenEstimate": 451,
|
|
174
176
|
"sections": [
|
|
175
177
|
"Import",
|
|
176
178
|
"Props",
|
|
@@ -216,7 +218,7 @@
|
|
|
216
218
|
"slug": "chip",
|
|
217
219
|
"title": "Chip",
|
|
218
220
|
"summary": "An interactive, optionally dismissible token.",
|
|
219
|
-
"tokenEstimate":
|
|
221
|
+
"tokenEstimate": 272,
|
|
220
222
|
"sections": [
|
|
221
223
|
"Import",
|
|
222
224
|
"Props",
|
|
@@ -635,7 +637,7 @@
|
|
|
635
637
|
"slug": "input",
|
|
636
638
|
"title": "Input",
|
|
637
639
|
"summary": "A text input field, with textarea variant.",
|
|
638
|
-
"tokenEstimate":
|
|
640
|
+
"tokenEstimate": 222,
|
|
639
641
|
"sections": [
|
|
640
642
|
"Import",
|
|
641
643
|
"Props"
|
|
@@ -1022,15 +1024,34 @@
|
|
|
1022
1024
|
"css": "@utility era-text-trim-caps {\n\tline-height: 1;\n\ttext-box: trim-both cap alphabetic;\n}"
|
|
1023
1025
|
},
|
|
1024
1026
|
{
|
|
1025
|
-
"name": "era-
|
|
1027
|
+
"name": "era-ink-center",
|
|
1026
1028
|
"names": [
|
|
1027
|
-
"era-token-ink",
|
|
1028
1029
|
"era-ink-center"
|
|
1029
1030
|
],
|
|
1030
1031
|
"file": "index.css",
|
|
1031
|
-
"useCase": "
|
|
1032
|
+
"useCase": "on a native single-line <input> (or the text layer that must mirror one) inside a fixed-height field — never alongside era-text-trim.",
|
|
1033
|
+
"description": "The EDITABLE counterpart of era-text-trim — for native <input>s, which the\ntrim is forbidden on (it collapses the UA's inner editor box and slices the\nglyphs; see typography/collapsed-text-trim).\n\nWithout help, a tier-height input centres its text by FONT BOX, and the ui\nstacks' font box is deeply asymmetric: ascent ≈1.07em against descent\n≈0.29em. Centring that box parks the visible band (caps, x-height) ~0.115em\nLOW — so a field's text sat visibly below the trimmed label beside it.\n\nThe value is OPTICAL, not the derivation's: pure x-band centring computes\nto ~0.23em of padding, but pixel-measured against real Title-Case text it\nover-lifts — the eye weighs the cap-to-baseline mass, which x-band\ncentring parks ~2px high (caps 2.75px off the top against 5.7px of air\nunder the baseline, measured at dense). 0.08em splits the difference\nbetween the x-band ideal and the cap-band ideal, landing caps ~3.7px in an\n18px field with ~4.7px under the baseline — the reading where neither\nband's partisans win and neither complains.\n\nThe lift is padding, not a translateY: an icon-less Input paints the field\nchrome itself, and a transform would drag the field along with the ink.\npadding-bottom shrinks the content box from below, and a single-line input\nre-centres its line box in what remains — the ink rises by exactly half the\npadding, the chrome doesn't move, and the caret and selection follow the\ntext. In em on purpose: the correction is a fraction of the type, so it\nholds across every density and text size with one value.",
|
|
1034
|
+
"css": "@utility era-ink-center {\n\tpadding-bottom: 0.08em;\n}"
|
|
1035
|
+
},
|
|
1036
|
+
{
|
|
1037
|
+
"name": "era-token-ink",
|
|
1038
|
+
"names": [
|
|
1039
|
+
"era-token-ink"
|
|
1040
|
+
],
|
|
1041
|
+
"file": "index.css",
|
|
1042
|
+
"useCase": "the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box, CENTRED horizontally and with no icon sibling. For a left-aligned sentence-case label use era-label-ink; when an icon really must sit beside the text, see the note there.",
|
|
1032
1043
|
"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.",
|
|
1033
|
-
"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}
|
|
1044
|
+
"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}"
|
|
1045
|
+
},
|
|
1046
|
+
{
|
|
1047
|
+
"name": "era-label-ink",
|
|
1048
|
+
"names": [
|
|
1049
|
+
"era-label-ink"
|
|
1050
|
+
],
|
|
1051
|
+
"file": "index.css",
|
|
1052
|
+
"useCase": "the ink centring for a fixed-height control holding ONE line of sentence-case text and no icon — a menu item, a nav trigger, a button label. Never alongside `truncate` (the trimmed box becomes the clip).",
|
|
1053
|
+
"description": "LABEL INK — era-token-ink's mixed-case sibling, and the general answer to\n\"this fixed-height control holds one line of text\".\n\nSame mechanism, same reason: `text-box-trim` needs a BLOCK box, so the row\nbecomes one and `align-content` (block-container alignment) does the\ncentring. What differs is the band and the alignment, because the content\nclass differs — a label is sentence case, so the x-height band is the visual\nmass to centre (cap-band reads low on \"System\"), and it is laid out against\nthe row's padding rather than centred in it.\n\nWHY IT EXISTS AT ALL: era's controls are flex, and a flex container's bare\ntext is an ANONYMOUS flex item — a box no selector reaches and no\nnon-inherited property touches. So `era-text-trim` on a flex row is inert,\ncontributing only its `line-height: 1`, and the ink falls back to line-box\ncentring by font metrics. era-token-ink already fixed that for centred\ntokens; this fixes it for everything else.\n\nTHE ICON CASE IS NOT SOLVED, and cannot be from CSS: an icon beside the text\nneeds the box to stay flex, which re-creates the anonymous item. A component\nwhose children are an opaque slot therefore guards it —\n`not-has-[svg]:era-label-ink` — and ink-centres the text-only case while\nleaving the icon case on line-box centring. Splitting icon and label into\nseparate slots is what would close it; typography/inert-trim reports every\nsite still on the fallback.",
|
|
1054
|
+
"css": "@utility era-label-ink {\n\tdisplay: block;\n\talign-content: center;\n\tline-height: 1;\n\ttext-box: trim-both ex alphabetic;\n}"
|
|
1034
1055
|
},
|
|
1035
1056
|
{
|
|
1036
1057
|
"name": "era-shimmer",
|
|
@@ -4,13 +4,13 @@ A complete notes app — rich-text editor, slash commands, local persistence.
|
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
7
|
-
Apps ship on their own subpath and are **not** re-exported from `@
|
|
7
|
+
Apps ship on their own subpath and are **not** re-exported from `@signal9/era-ui`.
|
|
8
8
|
Notes carries TipTap, and a consumer who never imports an app should never pay
|
|
9
9
|
for it.
|
|
10
10
|
|
|
11
11
|
```svelte
|
|
12
12
|
<script>
|
|
13
|
-
import { Notes } from '@
|
|
13
|
+
import { Notes } from '@signal9/era-ui/apps';
|
|
14
14
|
</script>
|
|
15
15
|
|
|
16
16
|
<Notes />
|
|
@@ -50,7 +50,7 @@ Persistence is one small interface, so server-backed hosting is a drop-in swap
|
|
|
50
50
|
`load`/`save` may be sync or async:
|
|
51
51
|
|
|
52
52
|
```ts
|
|
53
|
-
import { Notes, NotesStore } from '@
|
|
53
|
+
import { Notes, NotesStore } from '@signal9/era-ui/apps';
|
|
54
54
|
|
|
55
55
|
const store = new NotesStore({
|
|
56
56
|
adapter: {
|
|
@@ -61,15 +61,34 @@
|
|
|
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-
|
|
64
|
+
"name": "era-ink-center",
|
|
65
65
|
"names": [
|
|
66
|
-
"era-token-ink",
|
|
67
66
|
"era-ink-center"
|
|
68
67
|
],
|
|
69
68
|
"file": "index.css",
|
|
70
|
-
"useCase": "
|
|
69
|
+
"useCase": "on a native single-line <input> (or the text layer that must mirror one) inside a fixed-height field — never alongside era-text-trim.",
|
|
70
|
+
"description": "The EDITABLE counterpart of era-text-trim — for native <input>s, which the\ntrim is forbidden on (it collapses the UA's inner editor box and slices the\nglyphs; see typography/collapsed-text-trim).\n\nWithout help, a tier-height input centres its text by FONT BOX, and the ui\nstacks' font box is deeply asymmetric: ascent ≈1.07em against descent\n≈0.29em. Centring that box parks the visible band (caps, x-height) ~0.115em\nLOW — so a field's text sat visibly below the trimmed label beside it.\n\nThe value is OPTICAL, not the derivation's: pure x-band centring computes\nto ~0.23em of padding, but pixel-measured against real Title-Case text it\nover-lifts — the eye weighs the cap-to-baseline mass, which x-band\ncentring parks ~2px high (caps 2.75px off the top against 5.7px of air\nunder the baseline, measured at dense). 0.08em splits the difference\nbetween the x-band ideal and the cap-band ideal, landing caps ~3.7px in an\n18px field with ~4.7px under the baseline — the reading where neither\nband's partisans win and neither complains.\n\nThe lift is padding, not a translateY: an icon-less Input paints the field\nchrome itself, and a transform would drag the field along with the ink.\npadding-bottom shrinks the content box from below, and a single-line input\nre-centres its line box in what remains — the ink rises by exactly half the\npadding, the chrome doesn't move, and the caret and selection follow the\ntext. In em on purpose: the correction is a fraction of the type, so it\nholds across every density and text size with one value.",
|
|
71
|
+
"css": "@utility era-ink-center {\n\tpadding-bottom: 0.08em;\n}"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "era-token-ink",
|
|
75
|
+
"names": [
|
|
76
|
+
"era-token-ink"
|
|
77
|
+
],
|
|
78
|
+
"file": "index.css",
|
|
79
|
+
"useCase": "the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box, CENTRED horizontally and with no icon sibling. For a left-aligned sentence-case label use era-label-ink; when an icon really must sit beside the text, see the note there.",
|
|
71
80
|
"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}
|
|
81
|
+
"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}"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"name": "era-label-ink",
|
|
85
|
+
"names": [
|
|
86
|
+
"era-label-ink"
|
|
87
|
+
],
|
|
88
|
+
"file": "index.css",
|
|
89
|
+
"useCase": "the ink centring for a fixed-height control holding ONE line of sentence-case text and no icon — a menu item, a nav trigger, a button label. Never alongside `truncate` (the trimmed box becomes the clip).",
|
|
90
|
+
"description": "LABEL INK — era-token-ink's mixed-case sibling, and the general answer to\n\"this fixed-height control holds one line of text\".\n\nSame mechanism, same reason: `text-box-trim` needs a BLOCK box, so the row\nbecomes one and `align-content` (block-container alignment) does the\ncentring. What differs is the band and the alignment, because the content\nclass differs — a label is sentence case, so the x-height band is the visual\nmass to centre (cap-band reads low on \"System\"), and it is laid out against\nthe row's padding rather than centred in it.\n\nWHY IT EXISTS AT ALL: era's controls are flex, and a flex container's bare\ntext is an ANONYMOUS flex item — a box no selector reaches and no\nnon-inherited property touches. So `era-text-trim` on a flex row is inert,\ncontributing only its `line-height: 1`, and the ink falls back to line-box\ncentring by font metrics. era-token-ink already fixed that for centred\ntokens; this fixes it for everything else.\n\nTHE ICON CASE IS NOT SOLVED, and cannot be from CSS: an icon beside the text\nneeds the box to stay flex, which re-creates the anonymous item. A component\nwhose children are an opaque slot therefore guards it —\n`not-has-[svg]:era-label-ink` — and ink-centres the text-only case while\nleaving the icon case on line-box centring. Splitting icon and label into\nseparate slots is what would close it; typography/inert-trim reports every\nsite still on the fallback.",
|
|
91
|
+
"css": "@utility era-label-ink {\n\tdisplay: block;\n\talign-content: center;\n\tline-height: 1;\n\ttext-box: trim-both ex alphabetic;\n}"
|
|
73
92
|
},
|
|
74
93
|
{
|
|
75
94
|
"name": "era-shimmer",
|
|
@@ -9,7 +9,7 @@ never the `h-(--era-h-control)` var-class spelling. Everything below rides along
|
|
|
9
9
|
with the stylesheet and needs no import:
|
|
10
10
|
|
|
11
11
|
```ts
|
|
12
|
-
import "@
|
|
12
|
+
import "@signal9/era-ui/css";
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
```svelte
|
|
@@ -44,7 +44,9 @@ enough to stay var-form — `min-w-(--era-h-control)` etc. remain the escape hat
|
|
|
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-
|
|
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
|
+
| `era-token-ink` | the ink centring for a token pill — a badge, a KV value, any short caps-or-digits label in a fixed-height box, CENTRED horizontally and with no icon sibling. For a left-aligned sentence-case label use era-label-ink; when an icon really must sit beside the text, see the note there. |
|
|
49
|
+
| `era-label-ink` | the ink centring for a fixed-height control holding ONE line of sentence-case text and no icon — a menu item, a nav trigger, a button label. Never alongside `truncate` (the trimmed box becomes the clip). |
|
|
48
50
|
| `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
51
|
| `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
52
|
| `h-icon` `h-pill` `h-chip` `h-control` `h-bar` | the tier-height ladder — h-icon (icon) · h-pill (nested pill) · h-chip (standalone pill) · h-control (control) · h-bar (bar); the named form of h-(--era-h-*). |
|
|
@@ -235,9 +237,47 @@ Declared in `index.css`.
|
|
|
235
237
|
}
|
|
236
238
|
```
|
|
237
239
|
|
|
238
|
-
## era-
|
|
240
|
+
## era-ink-center
|
|
239
241
|
|
|
240
|
-
**Use it for:**
|
|
242
|
+
**Use it for:** on a native single-line <input> (or the text layer that must mirror one) inside a fixed-height field — never alongside era-text-trim.
|
|
243
|
+
|
|
244
|
+
The EDITABLE counterpart of era-text-trim — for native <input>s, which the
|
|
245
|
+
trim is forbidden on (it collapses the UA's inner editor box and slices the
|
|
246
|
+
glyphs; see typography/collapsed-text-trim).
|
|
247
|
+
|
|
248
|
+
Without help, a tier-height input centres its text by FONT BOX, and the ui
|
|
249
|
+
stacks' font box is deeply asymmetric: ascent ≈1.07em against descent
|
|
250
|
+
≈0.29em. Centring that box parks the visible band (caps, x-height) ~0.115em
|
|
251
|
+
LOW — so a field's text sat visibly below the trimmed label beside it.
|
|
252
|
+
|
|
253
|
+
The value is OPTICAL, not the derivation's: pure x-band centring computes
|
|
254
|
+
to ~0.23em of padding, but pixel-measured against real Title-Case text it
|
|
255
|
+
over-lifts — the eye weighs the cap-to-baseline mass, which x-band
|
|
256
|
+
centring parks ~2px high (caps 2.75px off the top against 5.7px of air
|
|
257
|
+
under the baseline, measured at dense). 0.08em splits the difference
|
|
258
|
+
between the x-band ideal and the cap-band ideal, landing caps ~3.7px in an
|
|
259
|
+
18px field with ~4.7px under the baseline — the reading where neither
|
|
260
|
+
band's partisans win and neither complains.
|
|
261
|
+
|
|
262
|
+
The lift is padding, not a translateY: an icon-less Input paints the field
|
|
263
|
+
chrome itself, and a transform would drag the field along with the ink.
|
|
264
|
+
padding-bottom shrinks the content box from below, and a single-line input
|
|
265
|
+
re-centres its line box in what remains — the ink rises by exactly half the
|
|
266
|
+
padding, the chrome doesn't move, and the caret and selection follow the
|
|
267
|
+
text. In em on purpose: the correction is a fraction of the type, so it
|
|
268
|
+
holds across every density and text size with one value.
|
|
269
|
+
|
|
270
|
+
Declared in `index.css`.
|
|
271
|
+
|
|
272
|
+
```css
|
|
273
|
+
@utility era-ink-center {
|
|
274
|
+
padding-bottom: 0.08em;
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## era-token-ink
|
|
279
|
+
|
|
280
|
+
**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, CENTRED horizontally and with no icon sibling. For a left-aligned sentence-case label use era-label-ink; when an icon really must sit beside the text, see the note there.
|
|
241
281
|
|
|
242
282
|
TOKEN INK — the ink centring for a pill whose content is a TOKEN: an id, a
|
|
243
283
|
count, a status, a tag. Font-independent, unlike everything it replaces.
|
|
@@ -276,9 +316,45 @@ Declared in `index.css`.
|
|
|
276
316
|
line-height: 1;
|
|
277
317
|
text-box: trim-both cap alphabetic;
|
|
278
318
|
}
|
|
319
|
+
```
|
|
279
320
|
|
|
280
|
-
|
|
281
|
-
|
|
321
|
+
## era-label-ink
|
|
322
|
+
|
|
323
|
+
**Use it for:** the ink centring for a fixed-height control holding ONE line of sentence-case text and no icon — a menu item, a nav trigger, a button label. Never alongside `truncate` (the trimmed box becomes the clip).
|
|
324
|
+
|
|
325
|
+
LABEL INK — era-token-ink's mixed-case sibling, and the general answer to
|
|
326
|
+
"this fixed-height control holds one line of text".
|
|
327
|
+
|
|
328
|
+
Same mechanism, same reason: `text-box-trim` needs a BLOCK box, so the row
|
|
329
|
+
becomes one and `align-content` (block-container alignment) does the
|
|
330
|
+
centring. What differs is the band and the alignment, because the content
|
|
331
|
+
class differs — a label is sentence case, so the x-height band is the visual
|
|
332
|
+
mass to centre (cap-band reads low on "System"), and it is laid out against
|
|
333
|
+
the row's padding rather than centred in it.
|
|
334
|
+
|
|
335
|
+
WHY IT EXISTS AT ALL: era's controls are flex, and a flex container's bare
|
|
336
|
+
text is an ANONYMOUS flex item — a box no selector reaches and no
|
|
337
|
+
non-inherited property touches. So `era-text-trim` on a flex row is inert,
|
|
338
|
+
contributing only its `line-height: 1`, and the ink falls back to line-box
|
|
339
|
+
centring by font metrics. era-token-ink already fixed that for centred
|
|
340
|
+
tokens; this fixes it for everything else.
|
|
341
|
+
|
|
342
|
+
THE ICON CASE IS NOT SOLVED, and cannot be from CSS: an icon beside the text
|
|
343
|
+
needs the box to stay flex, which re-creates the anonymous item. A component
|
|
344
|
+
whose children are an opaque slot therefore guards it —
|
|
345
|
+
`not-has-[svg]:era-label-ink` — and ink-centres the text-only case while
|
|
346
|
+
leaving the icon case on line-box centring. Splitting icon and label into
|
|
347
|
+
separate slots is what would close it; typography/inert-trim reports every
|
|
348
|
+
site still on the fallback.
|
|
349
|
+
|
|
350
|
+
Declared in `index.css`.
|
|
351
|
+
|
|
352
|
+
```css
|
|
353
|
+
@utility era-label-ink {
|
|
354
|
+
display: block;
|
|
355
|
+
align-content: center;
|
|
356
|
+
line-height: 1;
|
|
357
|
+
text-box: trim-both ex alphabetic;
|
|
282
358
|
}
|
|
283
359
|
```
|
|
284
360
|
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
|
|
96
96
|
{#if notif.items.length}
|
|
97
97
|
<footer class="shrink-0 border-t border-divider-faded p-(--era-inset-chip)">
|
|
98
|
-
<Button variant="link" size="
|
|
98
|
+
<Button variant="link" size="chip" class="w-full" onclick={() => notif.clear()}>
|
|
99
99
|
Clear all
|
|
100
100
|
</Button>
|
|
101
101
|
</footer>
|
package/dist/os/pane.svelte
CHANGED
|
@@ -124,7 +124,7 @@
|
|
|
124
124
|
held preview recolours to the action it will commit — yellow for
|
|
125
125
|
minimize, green for maximize — so the tone and glyph agree on what
|
|
126
126
|
the release does. -->
|
|
127
|
-
<!-- size="
|
|
127
|
+
<!-- size="pill" is the handle's content tier (see Pane.Handle), and the glyph
|
|
128
128
|
matches Pane.Close exactly — sp+5, off the sub-tier ladder for the
|
|
129
129
|
reason documented there. The two close affordances have to read as one
|
|
130
130
|
weight, so whatever that one is, both take it.
|
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
plain size-* on the <svg> loses to it. -->
|
|
139
139
|
<Button
|
|
140
140
|
icon
|
|
141
|
-
size="
|
|
141
|
+
size="pill"
|
|
142
142
|
tone={armed === 'minimize' ? 'warning' : armed === 'maximize' ? 'success' : 'destructive'}
|
|
143
143
|
class={armed === 'maximize'
|
|
144
144
|
? '[&_svg]:size-(--era-glyph-pill)'
|