@signal9/era-ui 31.0.0 → 32.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.
Files changed (59) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/ai/artifact/artifact.svelte +1 -1
  3. package/dist/ai/web-preview/web-preview.svelte +1 -1
  4. package/dist/ai/workflow/node.svelte +1 -1
  5. package/dist/docs/css-utilities.js +2 -2
  6. package/dist/era-ui.css +1 -1
  7. package/dist/generated-docs/llms-full.txt +61 -22
  8. package/dist/generated-docs/llms.txt +4 -1
  9. package/dist/generated-docs/manifest.json +41 -8
  10. package/dist/generated-docs/utilities.json +36 -6
  11. package/dist/generated-docs/utilities.md +57 -21
  12. package/dist/os/notification-center.svelte +1 -1
  13. package/dist/os/taskbar.svelte +1 -1
  14. package/dist/os/toast.svelte +1 -1
  15. package/dist/styles/index.css +42 -21
  16. package/dist/styles/motion.css +1 -1
  17. package/dist/styles/prose.css +1 -1
  18. package/dist/styles/surfaces/bevel.css +16 -19
  19. package/dist/styles/surfaces/contract.css +50 -0
  20. package/dist/styles/surfaces/flat.css +27 -0
  21. package/dist/styles/surfaces/glass.css +11 -8
  22. package/dist/ui/alert-dialog/alert-dialog-content.svelte +1 -1
  23. package/dist/ui/button/button.svelte +1 -0
  24. package/dist/ui/button/variants.d.ts +3 -3
  25. package/dist/ui/button/variants.js +3 -3
  26. package/dist/ui/card/card.svelte +4 -4
  27. package/dist/ui/card/card.svelte.d.ts +3 -3
  28. package/dist/ui/combobox/combobox-content.svelte +1 -1
  29. package/dist/ui/command/command-root.svelte +3 -3
  30. package/dist/ui/command-bar/command-bar.svelte +3 -3
  31. package/dist/ui/context-menu/context-menu-content.svelte +1 -4
  32. package/dist/ui/context-menu/context-menu-sub-content.svelte +1 -4
  33. package/dist/ui/date-picker/date-picker-content.svelte +1 -1
  34. package/dist/ui/date-range-picker/date-range-picker-content.svelte +1 -1
  35. package/dist/ui/dialog/dialog-content.svelte +1 -1
  36. package/dist/ui/dropdown-menu/dropdown-menu-content.svelte +1 -1
  37. package/dist/ui/dropdown-menu/dropdown-menu-sub-content.svelte +1 -4
  38. package/dist/ui/link-preview/link-preview-content.svelte +1 -1
  39. package/dist/ui/menubar/menubar-content.svelte +1 -1
  40. package/dist/ui/menubar/menubar-sub-content.svelte +1 -4
  41. package/dist/ui/meter/meter.svelte +1 -2
  42. package/dist/ui/nav/nav-item.svelte +1 -0
  43. package/dist/ui/pane/pane-root.svelte +1 -1
  44. package/dist/ui/popover/popover-content.svelte +1 -1
  45. package/dist/ui/provider/surfaces.d.ts +1 -1
  46. package/dist/ui/provider/surfaces.js +1 -1
  47. package/dist/ui/select/select-content.svelte +1 -1
  48. package/dist/ui/sheet/sheet-content.svelte +1 -1
  49. package/dist/ui/sheet/sheet-content.svelte.d.ts +1 -1
  50. package/dist/ui/switch/switch.svelte +1 -1
  51. package/dist/ui/toggle-group/toggle-group-item.svelte +1 -1
  52. package/dist/ui/toggle-group/toggle-group-item.svelte.d.ts +3 -3
  53. package/dist/ui/tooltip/tooltip-content.svelte +1 -1
  54. package/dist/ui/video-player/video-player.svelte +2 -2
  55. package/dist/utils/tw-merge-config.d.ts +3 -1
  56. package/dist/utils/tw-merge-config.js +2 -2
  57. package/package.json +2 -1
  58. package/skill/SKILL.md +9 -4
  59. package/dist/styles/surfaces/base.css +0 -257
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@signal9/era-ui",
3
- "version": "31.0.0",
3
+ "version": "32.0.0",
4
4
  "scripts": {
5
5
  "dev": "vite dev --host",
6
6
  "build": "vite build && npm run prepack",
7
7
  "test:visual": "playwright test",
8
+ "test:visual:deep": "ERA_TEST_DEPTH=deep playwright test",
8
9
  "deploy": "npm run build && npx --yes wrangler@latest deploy",
9
10
  "preview": "wrangler dev .svelte-kit/cloudflare/_worker.js --port 4173",
10
11
  "prepare": "git config core.hooksPath .githooks 2>/dev/null || true; svelte-kit sync || echo ''",
package/skill/SKILL.md CHANGED
@@ -125,9 +125,11 @@ relationship with its own badge or chip depend on unrelated outer chrome.
125
125
  `bg-highlight` + `shadow-highlight` (surface-owned; translucent on glass).
126
126
  Held state (toggle on, current tab, active button) uses opaque `bg-hover`.
127
127
  Never swap.
128
- - Panels: resting fill `bg-well` (pairs with `shadow-well`), raised fill
129
- `bg-elevated` (pairs with `shadow-lg` + `glass-blur` on floating panels),
130
- modal scrim `bg-overlay`. Menu panels pad with `p-menu` and their rows take
128
+ - Panels: use `material-popover` for transient floating chrome and
129
+ `material-panel` for persistent floating chrome. These atomically bind fill,
130
+ relief, and backdrop without naming flat/glass/bevel. Use `surface-backdrop`
131
+ only when a custom surface must choose its own fill and relief. Modal scrims
132
+ use `bg-overlay`. Menu panels pad with `p-menu` and their rows take
131
133
  `rounded-menu-item` so the row highlight stays concentric inside the frame.
132
134
 
133
135
  ## Motion
@@ -177,7 +179,10 @@ a component into the role. Full reference (including every named scale above):
177
179
  | `era-text-trim-caps` | the same for ALL-CAPS strings (kbd hints, acronym badges) |
178
180
  | `era-shimmer` | a "working…" / streaming label — motion-aware, dies at `instant` and under reduced-motion |
179
181
  | `scrollbar-none` | an overflowing strip that scrolls with no visible bar (ScrollArea is for when the bar IS the design) |
180
- | `glass-blur` | backdrop blur on a floating panel; inert outside a `data-surface="glass"` subtree |
182
+ | `material-popover` | complete transient floating material: raised fill, floating relief, and surface-owned backdrop |
183
+ | `material-panel` | complete persistent floating material: resting fill, floating relief, and surface-owned backdrop |
184
+ | `surface-backdrop` | backdrop treatment only, for a custom surface whose fill and relief are deliberately separate |
185
+ | `pressable` | physical pressed face; moves its marked direct content plane by the surface-owned travel |
181
186
 
182
187
  ## Composing the library
183
188
 
@@ -1,257 +0,0 @@
1
- /*
2
- * Era UI — Surface Contract (base) + flat defaults
3
- *
4
- * A surface answers, through tokens alone: what do fills, edges, wells,
5
- * pressed faces, transient highlights, and menu geometry look like here?
6
- * Values are hand-authored per surface (design is sculpting); this file
7
- * centralizes the contract every surface answers against.
8
- *
9
- * ARCHITECTURE
10
- * ============
11
- *
12
- * The selector pairs :root (page default = flat) with [data-surface], so
13
- * every element that DECLARES a surface re-baselines the full contract —
14
- * a bevel subtree nested inside glass inherits nothing frosted, and a
15
- * surface file only writes its deltas.
16
- *
17
- * Same-element var() defaults: --era-shadow-well, --era-shadow-pressed, and
18
- * --era-highlight-shadow default to var(--era-shadow). Because a surface's own
19
- * block and this base block apply to the SAME element, the var() resolves
20
- * against that surface's shadow — no literal duplication, and a surface
21
- * only overrides these when its wells/press/shine genuinely differ.
22
- *
23
- * Colors use light-dark(<light>, <dark>) instead of duplicated
24
- * @media/.light blocks. Themes set color-scheme (including on scoped
25
- * .light/.dark subtrees), which drives resolution per element.
26
- *
27
- * TOKEN GLOSSARY
28
- * ==============
29
- *
30
- * --era-surface-bg / -elevated surface fills (resting / raised tier)
31
- * --era-field-bg the RECESSED tier — a text field's resting
32
- * fill, which is the theme's hover tone: a field
33
- * rests at the weight a control reaches on hover
34
- * --era-field-highlight a field's OWN transient fill — one step past
35
- * its resting fill, since that already sits where
36
- * --era-highlight does and could not show a hover
37
- * --era-shadow / --era-shadow-lg resting edge chrome (controls / floating)
38
- * --era-shadow-well recessed container (inputs, tracks, checks)
39
- * --era-shadow-pressed a control's :active or latched face
40
- * --era-press-sink-x / -y how far the CONTENT (icon/label) sinks on
41
- * press while the frame stays put — bevel nudges
42
- * it inward (down + right, Win95-style) so a
43
- * keycap depresses in place without the box moving.
44
- * --era-highlight TRANSIENT feedback fill (hover, focus,
45
- * keyboard, drag-over). LATCHED states
46
- * (toggled on, open trigger, active page,
47
- * pill fills) stay on opaque bg-hover — a
48
- * held state reads solid, a passing state
49
- * reads as light.
50
- * --era-highlight-shadow the material half of transient feedback;
51
- * paired as hover:shadow-(--era-highlight-shadow)
52
- * --era-panel-inset menu-panel padding so row highlights stay
53
- * inside the surface's frame
54
- * --era-divider-color / -faded separator lines
55
- * --era-overlay-bg modal scrim
56
- * --era-blur / --era-saturate backdrop-filter inputs (glass-blur utility)
57
- * --era-selection-bg / -fg ::selection highlight fill + glyph color
58
- * --era-selection-shadow text-shadow INSIDE a selection — the one
59
- * extra channel highlight pseudos allow (glass
60
- * glow; none elsewhere)
61
- */
62
- :root,
63
- [data-surface] {
64
- --era-border-color: transparent;
65
- --era-divider-color: var(--color-border);
66
- --era-divider-faded: color-mix(in oklch, var(--era-divider-color) 40%, transparent);
67
- --era-surface-bg: var(--color-2);
68
- /* THE RAISED TIER HAS ITS OWN TONE, which is how a floating panel is told
69
- * apart from what it covers now that flat draws no edge (see --era-shadow-lg
70
- * below). It used to track --era-surface-bg, so a Popover over a Card was
71
- * the same fill with nothing to separate it.
72
- *
73
- * Derived, not indexed. --color-3 is the obvious pick and it is the trap
74
- * --era-field-bg already fell into: the 12-step scale is not symmetric about
75
- * its ends, so --color-3 sits ΔL 0.09 from the page in dark and ΔL 0.21 in
76
- * light — a step that reads right on a dark page and as a heavy grey slab on
77
- * a light one. Mixing toward --color-bright inverts with the mode by
78
- * construction (bright is L 0.93 in dark, L 0.16 in light), which is the
79
- * same idiom --era-field-highlight uses one tier down.
80
- *
81
- * 6% measured to ΔL 0.044 in dark and 0.040 in light — symmetric, and both
82
- * larger than the ΔL 0.033 that already separates a card from the page. If
83
- * that step is enough to say "this is a card", it is enough to say "this is
84
- * on top of it". */
85
- --era-surface-bg-elevated: color-mix(in oklch, var(--era-surface-bg) 94%, var(--color-bright));
86
- /* The third fill tier, and the one that was missing. A field is RECESSED, so
87
- * it was reaching for -elevated (the RAISED tier) and relying on
88
- * --era-shadow-well to sell the depth — which works on a surface that has
89
- * shadows and does nothing at all on flat. Measured before this token
90
- * existed: a resting input sat at 1.06:1 against its backdrop on flat and
91
- * bevel dark, and at 1.00:1 on glass light. Invisible until you touched it.
92
- *
93
- * A field rests at the weight a control reaches on HOVER — the theme's own
94
- * --color-hover, not a value derived from the page.
95
- *
96
- * It was derived once: a fixed 16% of the foreground mixed into the page,
97
- * chosen because the 12-step scale is not symmetric about its ends (--color-3
98
- * sits ΔL 0.09 from the page in dark but ΔL 0.21 in light, so a scale index
99
- * that looked right on a dark page rendered a heavy grey slab on a light
100
- * one). The mix did hold ΔL ≈ 0.11 in both modes, but it landed just PAST the
101
- * hover tone in dark and just SHORT of it in light — the two crossing over
102
- * between themes. A resting field out-read a hovered button on a dark page,
103
- * and hovering a field moved it toward the page background while hovering a
104
- * button moved it away.
105
- *
106
- * Naming the hover tone directly is what makes the ladder read the same in
107
- * both modes — page → field (= a hovered control) → field under the pointer —
108
- * and it hands the value to the theme, which is where a palette that is not a
109
- * smooth gradient needs it to live. */
110
- --era-field-bg: var(--color-hover);
111
- /* One small step past the resting field, toward the theme's brightest ink —
112
- * "brighter" in dark, deeper in light, which is what emphasis means on each.
113
- * Expressed against --era-field-bg rather than a literal so a surface that
114
- * retints its field (glass) gets a matching hover for free: base and the
115
- * surface block apply to the SAME element, so the var() resolves against
116
- * that surface's own field. Same trick as --era-shadow-well above. */
117
- --era-field-highlight: color-mix(in oklch, var(--era-field-bg) 96%, var(--color-bright));
118
- --era-shadow: none;
119
- /* FLAT DRAWS NO EDGE, INCLUDING ON A FLOATING PANEL.
120
- *
121
- * This held `0 0 0 1px var(--era-divider-color)` for a while (f329475). The
122
- * reasoning was sound and the result was not: flat's fill tiers are not
123
- * split, so a Popover over a Card had the same fill AND no edge, and a hover
124
- * card's text interleaved with the prose underneath. A hairline fixed that,
125
- * and it is genuinely flat's own idiom — Pane, the Switch track and every
126
- * divider draw one.
127
- *
128
- * It is still an outline around every menu, dialog and popover on the
129
- * surface whose entire premise is that there is no chrome, and that is how
130
- * it read in use. Removed on the owner's call, twice asked for.
131
- *
132
- * WHAT THIS COSTS, stated rather than buried: a floating panel over content
133
- * at the SAME fill has no separation on flat again. That is f329475's bug
134
- * returning, and it is real — but it needs a panel over a same-fill card to
135
- * appear, not a menu over the page, which is the common case and reads fine
136
- * on the page's own tone step. If it bites, the fix is to split the fill
137
- * tiers (give --era-surface-bg-elevated its own tone) rather than to put the
138
- * ring back: separation by FILL is what "solid fills, no chrome" means, and
139
- * a raw scale index is the wrong tool for it — --color-3 sits ΔL 0.09 from
140
- * the page in dark and ΔL 0.21 in light, the asymmetry --era-field-bg was
141
- * derived from --color-hover to avoid.
142
- *
143
- * glass and bevel override this with a rim and a chisel and are untouched. */
144
- --era-shadow-lg: none;
145
- --era-shadow-well: var(--era-shadow);
146
- --era-shadow-pressed: var(--era-shadow);
147
- /* THE NESTING LAW: transient feedback is a translucent ink wash, never an
148
- * opaque swatch — because highlights CONTAIN things. A chip rides inside a
149
- * hovered select trigger; a pin button hovers inside a hovered list row.
150
- * With an opaque highlight equal to the pill fill (the old --color-hover),
151
- * the moment the container lit up, everything inside it dissolved into the
152
- * same colour. A wash composes instead: each nested layer stacks one more
153
- * step of ink on whatever is beneath it, so container-hover, pill fill and
154
- * control-hover are always three distinguishable values — at any depth,
155
- * with no per-component opt-in. Glass has worked this way all along (its
156
- * highlight is a bright wash by necessity); this gives flat and bevel the
157
- * same compositional property.
158
- *
159
- * Calibrated to be INVISIBLE at rest: over the standard surface the wash
160
- * resolves to the exact colour the opaque token painted. Dark — color-2
161
- * 0.195 + 8% of bright 0.925 = 0.253 ≈ the old hover 0.25. Light — color-2
162
- * 0.863 + 9% of bright 0.166 = 0.800 = the old hover 0.8 exactly. Nothing
163
- * moves except where two layers meet, which is the point. */
164
- --era-highlight: light-dark(
165
- color-mix(in oklch, var(--color-bright) 9%, transparent),
166
- color-mix(in oklch, var(--color-bright) 8%, transparent)
167
- );
168
- --era-highlight-shadow: var(--era-shadow);
169
- /* The standing pill fill (Chip, Badge, KV, an active tool chip) — the
170
- * LATCHED counterpart of --era-highlight, public name `bg-fill`. Follows
171
- * the highlight's wash here (so a pill on a lit container steps up with
172
- * it), while glass overrides it back to the opaque swatch: there the
173
- * latched-reads-solid / transient-reads-light distinction is the surface's
174
- * own grammar, and its highlight was already a wash so the collision this
175
- * solves never existed. */
176
- --era-fill: var(--era-highlight);
177
- --era-press-sink-x: 0px;
178
- --era-press-sink-y: 0px;
179
- --era-panel-inset: 0px;
180
- --era-overlay-bg: color-mix(in oklch, var(--color-1) 60%, transparent);
181
- --era-blur: 0px;
182
- --era-saturate: 100%;
183
- /* Flat's selection is inverse video: a solid maximum-contrast block, the
184
- * terminal's own idiom — no chrome, like everything else here. */
185
- --era-selection-bg: var(--color-bright);
186
- --era-selection-fg: var(--color-1);
187
- --era-selection-shadow: none;
188
- }
189
-
190
- /* Text selection — the one paint a surface gets INSIDE the glyphs. Highlight
191
- * pseudos only carry color / background-color / text-shadow / text-decoration
192
- * (no box-shadow, no backdrop-filter — a selection can't wear a chisel or
193
- * frost), so each surface expresses its material through these three tokens.
194
- * var() in ::selection resolves against the originating element, so a nested
195
- * surface re-baselines its selection exactly like every other contract token. */
196
- ::selection {
197
- background-color: var(--era-selection-bg);
198
- color: var(--era-selection-fg);
199
- text-shadow: var(--era-selection-shadow);
200
- }
201
-
202
- /* Concentric radius for a row inside a panel: the panel's radius minus its
203
- * inset. Declared on the universal selector (like the density ladder) so it
204
- * re-derives against each element's own --era-rd-control — density subtree
205
- * overrides stay correct.
206
- *
207
- * NO SURFACE GATE. This used to be multiplied by --era-item-rd-scale, which
208
- * flat set to 0 — so on the default surface a row was square no matter what
209
- * data-corners said, and a consumer who set corners globally got square rows
210
- * anyway. That is the surface axis overriding the CORNERS axis, and the axes
211
- * are meant to be orthogonal: surface owns fills, shadows and frames; corners
212
- * owns radii, globally, with no exceptions for a consumer to discover.
213
- *
214
- * The gate was also redundant. The formula already answers both axes on its
215
- * own: at data-corners="square" --era-rd-control collapses to 0, so this collapses
216
- * with it; on flat --era-panel-inset is 0, so a flush full-width row simply
217
- * takes the panel's own radius — which is the concentric answer for a row
218
- * whose panel has no frame to nest inside. Flat menus keep their flush,
219
- * full-width rows; only the highlight's corners now follow the axis. */
220
- * {
221
- --era-item-rd: max(0px, calc(var(--era-rd-control) - var(--era-panel-inset)));
222
- }
223
-
224
- /*
225
- * SURFACE-TAILORED ANIMATION — recipe
226
- * ===================================
227
- * Timing belongs to the MOTION axis (motion.css): components read
228
- * --era-duration and --era-ease, so speed and curve follow data-motion for
229
- * free — a surface never sets duration.
230
- *
231
- * A surface can shape motion two ways:
232
- * • FEEL — override --era-ease inside the surface's [data-surface] block.
233
- * motion.css is imported before surfaces, so a surface delta wins;
234
- * e.g. a surface could soften or sharpen every transition's curve.
235
- * • STRATEGY — for a genuinely different technique (a glass crossfade vs.
236
- * a bevel thumb sliding along a track), scope a rule to the surface and
237
- * target the component's stable part, e.g. in the surface's own file:
238
- * [data-surface='<name>'] [data-slot='switch-thumb'] { … }
239
- * Keyframes live in that surface's file. Surface-only UTILITIES cannot:
240
- * the surface files are imported into a cascade layer, and `@utility` may
241
- * not be nested inside one — so they live in styles/index.css alongside
242
- * the rest (precedent: `glass-blur`, which is gated to glass subtrees).
243
- *
244
- * Reduced-motion is handled centrally in motion.css — surfaces need not.
245
- */
246
-
247
- /* Reduced transparency: the washes go back to the solid swatch — the same
248
- * degradation glass.css applies to its own translucent tokens. Declared after
249
- * the defaults in THIS file so it wins over them; glass, declared later in
250
- * import order, keeps its own pair of declarations for glass elements. */
251
- @media (prefers-reduced-transparency: reduce) {
252
- :root,
253
- [data-surface] {
254
- --era-highlight: var(--color-hover);
255
- --era-fill: var(--color-hover);
256
- }
257
- }