@signal9/era-ui 3.0.1 → 3.2.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/docs/css-utilities.d.ts +8 -2
- package/dist/docs/css-utilities.js +45 -12
- package/dist/era-ui.css +1 -1
- package/dist/generated-docs/llms-full.txt +267 -4
- package/dist/generated-docs/llms.txt +11 -0
- package/dist/generated-docs/manifest.json +171 -1
- package/dist/generated-docs/utilities.json +159 -0
- package/dist/generated-docs/utilities.md +256 -4
- package/dist/os/taskbar.svelte +10 -2
- package/dist/os/taskbar.svelte.d.ts +5 -0
- package/dist/styles/index.css +234 -1
- package/dist/ui/pane/pane-root.svelte.d.ts +1 -1
- package/dist/ui/pane/pane.svelte.d.ts +1 -1
- package/dist/ui/toggle/toggle.svelte.d.ts +1 -1
- package/dist/utils/index.js +21 -1
- package/package.json +1 -1
- package/skill/SKILL.md +75 -51
package/dist/styles/index.css
CHANGED
|
@@ -169,10 +169,70 @@
|
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
/*
|
|
172
|
+
/* ------------------------------------------------------------------ */
|
|
173
|
+
/* THE PUBLIC CLASS API */
|
|
174
|
+
/* */
|
|
175
|
+
/* Era's consumer-facing styling surface is NAMED utilities — a user */
|
|
176
|
+
/* of the library writes `h-md rounded-md px-md shadow`, never */
|
|
177
|
+
/* `h-(--era-h-md)`-style var classes. Where Tailwind already has a */
|
|
178
|
+
/* name for the concept (rounded-md, shadow, ease) era OVERLOADS it */
|
|
179
|
+
/* so stock-looking markup renders on-design; where it doesn't, era */
|
|
180
|
+
/* registers its own (h-md, px-md, gap-gutter, p-card). */
|
|
181
|
+
/* */
|
|
182
|
+
/* The --era-* custom properties remain the internal contract (and */
|
|
183
|
+
/* the escape hatch for anything without a name — e.g. min-w-* tier */
|
|
184
|
+
/* names are NOT registered because Tailwind's container scale */
|
|
185
|
+
/* already owns min-w-md/lg; use min-w-(--era-h-md) there). */
|
|
186
|
+
/* */
|
|
187
|
+
/* Everything here is a thin name over a token, so the full axis */
|
|
188
|
+
/* system — density, surface, corners, motion — flows through */
|
|
189
|
+
/* untouched. @theme inline is load-bearing: it inlines the var() */
|
|
190
|
+
/* reference instead of snapshotting a value, so each USE re-resolves */
|
|
191
|
+
/* against the element's own inherited axes. */
|
|
192
|
+
/* ------------------------------------------------------------------ */
|
|
173
193
|
@theme inline {
|
|
174
194
|
/* Density-derived body size: `text-body` replaces text-[length:var(--era-text)] */
|
|
175
195
|
--text-body: var(--era-text);
|
|
196
|
+
/* Radius ladder — Tailwind's own rounded-* names now walk era's concentric
|
|
197
|
+
* ladder (rd-T = rd-xs + (h-T − h-xs)/2), ride the corners toggle, and
|
|
198
|
+
* collapse to 0 on square. rounded-item is the menu-row radius
|
|
199
|
+
* (rd-md − panel-inset) that keeps rows concentric inside a rounded-md
|
|
200
|
+
* panel on every surface. */
|
|
201
|
+
--radius-xs: var(--era-rd-xs);
|
|
202
|
+
--radius-xxs: var(--era-rd-xxs);
|
|
203
|
+
--radius-sm: var(--era-rd-sm);
|
|
204
|
+
--radius-md: var(--era-rd-md);
|
|
205
|
+
--radius-lg: var(--era-rd-lg);
|
|
206
|
+
--radius-item: var(--era-item-rd);
|
|
207
|
+
/* Surface chrome — bare `shadow` is the resting control edge, shadow-lg the
|
|
208
|
+
* floating panel, shadow-well the recessed container, shadow-pressed the
|
|
209
|
+
* active/latched face, shadow-highlight the material half of hover feedback.
|
|
210
|
+
* Flat renders them as none, bevel as chisels, glass as frosted rims — the
|
|
211
|
+
* class stays the same. */
|
|
212
|
+
--shadow: var(--era-shadow);
|
|
213
|
+
/* v4 marks bare `shadow` a deprecated spelling of shadow-sm, and lints
|
|
214
|
+
* auto-fix one to the other — alias both to the control edge so either
|
|
215
|
+
* spelling renders era chrome. */
|
|
216
|
+
--shadow-sm: var(--era-shadow);
|
|
217
|
+
--shadow-lg: var(--era-shadow-lg);
|
|
218
|
+
--shadow-well: var(--era-shadow-well);
|
|
219
|
+
--shadow-pressed: var(--era-shadow-pressed);
|
|
220
|
+
--shadow-highlight: var(--era-highlight-shadow);
|
|
221
|
+
/* Surface fills — bg-well is the surface's own resting fill (pairs with
|
|
222
|
+
* shadow-well for recessed chrome), bg-elevated the raised tier (pairs with
|
|
223
|
+
* shadow-lg + glass-blur for floating chrome), bg-highlight the transient
|
|
224
|
+
* hover/focus/keyboard wash (pairs with shadow-highlight; latched states
|
|
225
|
+
* stay on opaque bg-hover), bg-overlay the modal scrim. */
|
|
226
|
+
--color-well: var(--era-surface-bg);
|
|
227
|
+
--color-elevated: var(--era-surface-bg-elevated);
|
|
228
|
+
--color-highlight: var(--era-highlight);
|
|
229
|
+
--color-overlay: var(--era-overlay-bg);
|
|
230
|
+
/* Motion — bare transition utilities default to the motion axis, so
|
|
231
|
+
* `transition-colors` alone is on-design (0s at instant, longer at extra).
|
|
232
|
+
* ease-base/duration-base name the axis explicitly for overrides. */
|
|
233
|
+
--default-transition-duration: var(--era-duration);
|
|
234
|
+
--default-transition-timing-function: var(--era-ease);
|
|
235
|
+
--ease-base: var(--era-ease);
|
|
176
236
|
/* Surface divider colors: border-divider, bg-divider-faded, … */
|
|
177
237
|
--color-divider: var(--era-divider-color);
|
|
178
238
|
--color-divider-faded: var(--era-divider-faded);
|
|
@@ -206,3 +266,176 @@
|
|
|
206
266
|
--color-warning: var(--color-warning);
|
|
207
267
|
--color-warning-fg: var(--color-warning-fg);
|
|
208
268
|
}
|
|
269
|
+
|
|
270
|
+
/* ------------------------------------------------------------------ */
|
|
271
|
+
/* Named tier + spacing utilities */
|
|
272
|
+
/* */
|
|
273
|
+
/* Static utilities (not @theme) because Tailwind's spacing namespace */
|
|
274
|
+
/* is shared across h/w/p/m/gap — registering `md` there would give */
|
|
275
|
+
/* px-md and h-md the SAME value, and era's tiers and insets are */
|
|
276
|
+
/* different token families. Each name below maps to exactly one */
|
|
277
|
+
/* token. Kept terse; the ladder itself is documented in density.css */
|
|
278
|
+
/* and on the /spacing page. */
|
|
279
|
+
/* ------------------------------------------------------------------ */
|
|
280
|
+
|
|
281
|
+
/* @use the tier-height ladder — h-xs (icon) · h-xxs (nested pill) · h-sm
|
|
282
|
+
* (standalone pill) · h-md (control) · h-lg (bar); the named form of
|
|
283
|
+
* h-(--era-h-*). */
|
|
284
|
+
@utility h-xs {
|
|
285
|
+
height: var(--era-h-xs);
|
|
286
|
+
}
|
|
287
|
+
@utility h-xxs {
|
|
288
|
+
height: var(--era-h-xxs);
|
|
289
|
+
}
|
|
290
|
+
@utility h-sm {
|
|
291
|
+
height: var(--era-h-sm);
|
|
292
|
+
}
|
|
293
|
+
@utility h-md {
|
|
294
|
+
height: var(--era-h-md);
|
|
295
|
+
}
|
|
296
|
+
@utility h-lg {
|
|
297
|
+
height: var(--era-h-lg);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/* @use minimum tier height for containers that may grow — a bar that is at
|
|
301
|
+
* least lg-tier but can wrap (min-h-lg). */
|
|
302
|
+
@utility min-h-xs {
|
|
303
|
+
min-height: var(--era-h-xs);
|
|
304
|
+
}
|
|
305
|
+
@utility min-h-xxs {
|
|
306
|
+
min-height: var(--era-h-xxs);
|
|
307
|
+
}
|
|
308
|
+
@utility min-h-sm {
|
|
309
|
+
min-height: var(--era-h-sm);
|
|
310
|
+
}
|
|
311
|
+
@utility min-h-md {
|
|
312
|
+
min-height: var(--era-h-md);
|
|
313
|
+
}
|
|
314
|
+
@utility min-h-lg {
|
|
315
|
+
min-height: var(--era-h-lg);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/* @use a tier-sized square — size-xs is THE icon size (a Lucide glyph beside
|
|
319
|
+
* body text), size-md a square control face. */
|
|
320
|
+
@utility size-xs {
|
|
321
|
+
width: var(--era-h-xs);
|
|
322
|
+
height: var(--era-h-xs);
|
|
323
|
+
}
|
|
324
|
+
@utility size-xxs {
|
|
325
|
+
width: var(--era-h-xxs);
|
|
326
|
+
height: var(--era-h-xxs);
|
|
327
|
+
}
|
|
328
|
+
@utility size-sm {
|
|
329
|
+
width: var(--era-h-sm);
|
|
330
|
+
height: var(--era-h-sm);
|
|
331
|
+
}
|
|
332
|
+
@utility size-md {
|
|
333
|
+
width: var(--era-h-md);
|
|
334
|
+
height: var(--era-h-md);
|
|
335
|
+
}
|
|
336
|
+
@utility size-lg {
|
|
337
|
+
width: var(--era-h-lg);
|
|
338
|
+
height: var(--era-h-lg);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/* @use tier-to-tier nesting padding (sp/2) — the horizontal padding of a bar
|
|
342
|
+
* or row that holds tiered controls; the named form of px-(--era-px-*). */
|
|
343
|
+
@utility px-sm {
|
|
344
|
+
padding-inline: var(--era-px-sm);
|
|
345
|
+
}
|
|
346
|
+
@utility px-md {
|
|
347
|
+
padding-inline: var(--era-px-md);
|
|
348
|
+
}
|
|
349
|
+
@utility px-lg {
|
|
350
|
+
padding-inline: var(--era-px-lg);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/* @use the inter-element gap (sp/2) — flex/grid gap between sibling controls,
|
|
354
|
+
* and the matching gutter padding a scrollable list or rail owes its rows on
|
|
355
|
+
* all four sides (p-gutter on the rail = gap-gutter between its rows). */
|
|
356
|
+
@utility gap-gutter {
|
|
357
|
+
gap: var(--era-gap);
|
|
358
|
+
}
|
|
359
|
+
@utility p-gutter {
|
|
360
|
+
padding: var(--era-gap);
|
|
361
|
+
}
|
|
362
|
+
@utility px-gutter {
|
|
363
|
+
padding-inline: var(--era-gap);
|
|
364
|
+
}
|
|
365
|
+
@utility py-gutter {
|
|
366
|
+
padding-block: var(--era-gap);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/* @use text-symmetric content padding — (tier − text)/2, the inset that
|
|
370
|
+
* vertically centers body text in its tier; px-inset-md is a text button's
|
|
371
|
+
* side padding, p-inset-md a code block's. */
|
|
372
|
+
@utility p-inset-xxs {
|
|
373
|
+
padding: var(--era-inset-xxs);
|
|
374
|
+
}
|
|
375
|
+
@utility p-inset-sm {
|
|
376
|
+
padding: var(--era-inset-sm);
|
|
377
|
+
}
|
|
378
|
+
@utility p-inset-md {
|
|
379
|
+
padding: var(--era-inset-md);
|
|
380
|
+
}
|
|
381
|
+
@utility px-inset-xxs {
|
|
382
|
+
padding-inline: var(--era-inset-xxs);
|
|
383
|
+
}
|
|
384
|
+
@utility px-inset-sm {
|
|
385
|
+
padding-inline: var(--era-inset-sm);
|
|
386
|
+
}
|
|
387
|
+
@utility px-inset-md {
|
|
388
|
+
padding-inline: var(--era-inset-md);
|
|
389
|
+
}
|
|
390
|
+
@utility py-inset-xxs {
|
|
391
|
+
padding-block: var(--era-inset-xxs);
|
|
392
|
+
}
|
|
393
|
+
@utility py-inset-sm {
|
|
394
|
+
padding-block: var(--era-inset-sm);
|
|
395
|
+
}
|
|
396
|
+
@utility py-inset-md {
|
|
397
|
+
padding-block: var(--era-inset-md);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/* @use pill side padding — the wider-than-vertical horizontal breathing room
|
|
401
|
+
* badge/chip text wants (glyph-advance derived, ~2× the vertical inset). */
|
|
402
|
+
@utility px-pill-xxs {
|
|
403
|
+
padding-inline: var(--era-pill-xxs);
|
|
404
|
+
}
|
|
405
|
+
@utility px-pill-sm {
|
|
406
|
+
padding-inline: var(--era-pill-sm);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/* @use text-field side padding — where typed text starts in an md-tier input;
|
|
410
|
+
* the named form of px-(--era-field-px). */
|
|
411
|
+
@utility px-field {
|
|
412
|
+
padding-inline: var(--era-field-px);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/* @use optical padding for unbounded containers — p-panel for compact shells
|
|
416
|
+
* and menu-adjacent chrome, p-card for cards/dialogs/popovers, p-content for
|
|
417
|
+
* full content panels. Grows super-linearly with density so whitespace holds
|
|
418
|
+
* its perceived share as controls loosen. */
|
|
419
|
+
@utility p-panel {
|
|
420
|
+
padding: var(--era-pad-sm);
|
|
421
|
+
}
|
|
422
|
+
@utility p-card {
|
|
423
|
+
padding: var(--era-pad-md);
|
|
424
|
+
}
|
|
425
|
+
@utility p-content {
|
|
426
|
+
padding: var(--era-content-p);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/* @use menu-panel padding — the surface-owned inset (0 on flat, 2px on
|
|
430
|
+
* glass/bevel) that keeps row highlights inside a floating panel's frame;
|
|
431
|
+
* pairs with rounded-item on the rows. */
|
|
432
|
+
@utility p-menu {
|
|
433
|
+
padding: var(--era-panel-inset);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/* @use the motion axis as an explicit transition-duration — for the rare case
|
|
437
|
+
* a utility (not the transition-* default) needs to name it; 0s at
|
|
438
|
+
* data-motion="instant", longer at "extra". */
|
|
439
|
+
@utility duration-base {
|
|
440
|
+
transition-duration: var(--era-duration);
|
|
441
|
+
}
|
|
@@ -29,6 +29,6 @@ type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
|
|
|
29
29
|
onDragEnd?: (data: DragEventData) => void;
|
|
30
30
|
children?: Snippet;
|
|
31
31
|
};
|
|
32
|
-
declare const PaneRoot: import("svelte").Component<$$ComponentProps, {}, "
|
|
32
|
+
declare const PaneRoot: import("svelte").Component<$$ComponentProps, {}, "size" | "position" | "ref">;
|
|
33
33
|
type PaneRoot = ReturnType<typeof PaneRoot>;
|
|
34
34
|
export default PaneRoot;
|
|
@@ -35,6 +35,6 @@ type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
|
|
|
35
35
|
header?: Snippet;
|
|
36
36
|
children?: Snippet;
|
|
37
37
|
};
|
|
38
|
-
declare const Pane: Component<$$ComponentProps, {}, "
|
|
38
|
+
declare const Pane: Component<$$ComponentProps, {}, "size" | "position" | "ref">;
|
|
39
39
|
type Pane = ReturnType<typeof Pane>;
|
|
40
40
|
export default Pane;
|
|
@@ -4,6 +4,6 @@ import { type ButtonVariants } from '../button';
|
|
|
4
4
|
type $$ComponentProps = WithoutChildrenOrChild<Toggle.RootProps> & Omit<ButtonVariants, 'active'> & {
|
|
5
5
|
children?: Snippet;
|
|
6
6
|
};
|
|
7
|
-
declare const Toggle: import("svelte").Component<$$ComponentProps, {}, "
|
|
7
|
+
declare const Toggle: import("svelte").Component<$$ComponentProps, {}, "pressed" | "ref">;
|
|
8
8
|
type Toggle = ReturnType<typeof Toggle>;
|
|
9
9
|
export default Toggle;
|
package/dist/utils/index.js
CHANGED
|
@@ -4,11 +4,31 @@ import { createTV } from 'tailwind-variants';
|
|
|
4
4
|
// glass-blur is a custom @utility (styles/surfaces/glass.css) that sets backdrop-filter,
|
|
5
5
|
// so it must conflict-resolve against the backdrop-blur group. text-body is
|
|
6
6
|
// a registered font-size token — without this it would be misread as a color.
|
|
7
|
+
// The rest teaches tailwind-merge era's named class API (styles/index.css):
|
|
8
|
+
// values it can't know about (h-md, px-inset-md, gap-gutter, shadow-well, …)
|
|
9
|
+
// must land in their real class groups, or a consumer's `class="h-lg"` would
|
|
10
|
+
// fail to replace a component's h-(--era-h-md) and both would apply.
|
|
11
|
+
// Colors (bg-elevated, bg-highlight, …) need no entry — the bg group already
|
|
12
|
+
// accepts any name. rounded-xs/sm/md/lg and bare shadow/shadow-lg are stock
|
|
13
|
+
// names tailwind-merge knows; only era's additions to those scales are listed.
|
|
14
|
+
const TIERS = ['xs', 'xxs', 'sm', 'md', 'lg'];
|
|
15
|
+
const INSETS = ['inset-xxs', 'inset-sm', 'inset-md'];
|
|
7
16
|
const twMergeConfig = {
|
|
8
17
|
extend: {
|
|
9
18
|
classGroups: {
|
|
10
19
|
'backdrop-blur': ['glass-blur'],
|
|
11
|
-
'font-size': [{ text: ['body'] }]
|
|
20
|
+
'font-size': [{ text: ['body'] }],
|
|
21
|
+
h: [{ h: TIERS }],
|
|
22
|
+
'min-h': [{ 'min-h': TIERS }],
|
|
23
|
+
size: [{ size: TIERS }],
|
|
24
|
+
p: [{ p: ['gutter', 'panel', 'card', 'content', 'menu', ...INSETS] }],
|
|
25
|
+
px: [{ px: ['sm', 'md', 'lg', 'gutter', 'field', 'pill-xxs', 'pill-sm', ...INSETS] }],
|
|
26
|
+
py: [{ py: ['gutter', ...INSETS] }],
|
|
27
|
+
gap: [{ gap: ['gutter'] }],
|
|
28
|
+
rounded: [{ rounded: ['xxs', 'item'] }],
|
|
29
|
+
shadow: [{ shadow: ['well', 'pressed', 'highlight'] }],
|
|
30
|
+
ease: [{ ease: ['base'] }],
|
|
31
|
+
duration: [{ duration: ['base'] }]
|
|
12
32
|
}
|
|
13
33
|
}
|
|
14
34
|
};
|
package/package.json
CHANGED
package/skill/SKILL.md
CHANGED
|
@@ -4,20 +4,31 @@ description: |
|
|
|
4
4
|
Design-system methodology for building UIs with @sig-nine/era-ui (Svelte 5 +
|
|
5
5
|
Tailwind v4). Use when: writing or reviewing any component, layout, or page
|
|
6
6
|
in a project that uses era-ui — sizing controls, spacing/padding, radii,
|
|
7
|
-
surfaces, motion, or composing library components. Covers: the
|
|
8
|
-
tier ladder, the even-gap and concentricity laws,
|
|
9
|
-
padding, surface/shadow rules, motion
|
|
10
|
-
|
|
7
|
+
surfaces, motion, or composing library components. Covers: the named class
|
|
8
|
+
API, the sp-derived tier ladder, the even-gap and concentricity laws,
|
|
9
|
+
geometric vs optical padding, surface/shadow rules, motion, and the
|
|
10
|
+
mistakes agents make.
|
|
11
|
+
version: 1.1.0
|
|
11
12
|
---
|
|
12
13
|
|
|
13
14
|
# Building with era-ui
|
|
14
15
|
|
|
15
16
|
Every size, gap, and radius derives from ONE number per density mode: `sp`
|
|
16
17
|
(8/10/12/16 for dense/balanced/spacious/touch). Never write a hardcoded px,
|
|
17
|
-
rem, radius, duration, or color — there is a
|
|
18
|
+
rem, radius, duration, or color — there is a class for everything, and the
|
|
18
19
|
whole system re-derives per element, so any `data-*` axis override on any
|
|
19
20
|
subtree just works.
|
|
20
21
|
|
|
22
|
+
**Write named classes, not var classes.** Era's public styling API is pure
|
|
23
|
+
Tailwind-looking utilities: `h-md rounded-md px-md shadow`, never
|
|
24
|
+
`h-(--era-h-md)`-style var spellings. Where Tailwind already names the concept
|
|
25
|
+
era overloads it (`rounded-md` walks era's ladder, bare `shadow` is the
|
|
26
|
+
surface chrome, `transition-colors` rides the motion axis); where it doesn't,
|
|
27
|
+
era registers its own (`h-md`, `gap-gutter`, `p-card`). The `--era-*` custom
|
|
28
|
+
properties remain public as the escape hatch for the few things without a
|
|
29
|
+
name — noted inline below — but reaching for one when a named class exists is
|
|
30
|
+
a review finding.
|
|
31
|
+
|
|
21
32
|
## The five axes (data attributes, all orthogonal)
|
|
22
33
|
|
|
23
34
|
| Axis | Attribute | Values |
|
|
@@ -34,72 +45,80 @@ to ~13px, silently shrinking every rem-derived token).
|
|
|
34
45
|
|
|
35
46
|
## The tier ladder
|
|
36
47
|
|
|
37
|
-
| Tier | Height
|
|
38
|
-
| ----- |
|
|
39
|
-
| `xs` |
|
|
40
|
-
| `xxs` |
|
|
41
|
-
| `sm` |
|
|
42
|
-
| `md` |
|
|
43
|
-
| `lg` |
|
|
48
|
+
| Tier | Height | Square | Radius | Use for |
|
|
49
|
+
| ----- | ------- | ---------- | ------------- | ----------------------------------------------- |
|
|
50
|
+
| `xs` | `h-xs` | `size-xs` | `rounded-xs` | icons (THE icon size), switch thumbs |
|
|
51
|
+
| `xxs` | `h-xxs` | `size-xxs` | `rounded-xxs` | pills nested inside md (badge/chip in a button) |
|
|
52
|
+
| `sm` | `h-sm` | `size-sm` | `rounded-sm` | standalone pills, switch tracks, KV |
|
|
53
|
+
| `md` | `h-md` | `size-md` | `rounded-md` | buttons, inputs, selects, triggers |
|
|
54
|
+
| `lg` | `h-lg` | `size-lg` | `rounded-lg` | bars, containers, dialog headers |
|
|
44
55
|
|
|
45
|
-
|
|
46
|
-
|
|
56
|
+
`min-h-*` exists for containers that may grow. One escape hatch: the
|
|
57
|
+
single-glyph square floor is `min-w-(--era-h-md)` — `min-w-md` is Tailwind's
|
|
58
|
+
container scale (28rem), so era does not shadow it.
|
|
47
59
|
|
|
48
60
|
## The two laws
|
|
49
61
|
|
|
50
62
|
1. **Even gaps** — the padding between a container's edge and its children
|
|
51
|
-
must equal the gap between the children, on every side.
|
|
52
|
-
(= sp/2) is the universal inter-element gap
|
|
63
|
+
must equal the gap between the children, on every side. `gap-gutter`
|
|
64
|
+
(= sp/2) is the universal inter-element gap, and `p-gutter` (+ `px-`/`py-`)
|
|
65
|
+
is the matching gutter a scrollable list or rail owes its rows.
|
|
53
66
|
2. **Concentricity** — `rd-T − rd-U = (h-T − h-U)/2` for every tier pair. So:
|
|
54
67
|
give EVERY element the radius of its OWN height tier, center children with
|
|
55
|
-
the matching concentric
|
|
56
|
-
curvature automatically. The
|
|
57
|
-
`--era-xs-inset-sm` (xs inside sm, = sp/2), `--era-xxs-inset-md`,
|
|
68
|
+
the matching concentric inset, and nested corners share a center of
|
|
69
|
+
curvature automatically. The concentric insets are advanced enough to stay
|
|
70
|
+
token-form: `--era-xs-inset-sm` (xs inside sm, = sp/2), `--era-xxs-inset-md`,
|
|
58
71
|
`--era-xs-inset-md`, `--era-xs-inset-lg`, `--era-sm-inset-lg`.
|
|
59
72
|
|
|
60
73
|
**The trap**: a container's radius follows its corner REGION's tier, never its
|
|
61
74
|
overall bulk. A large panel whose corners are formed by an sm-tier handle bar
|
|
62
|
-
is `
|
|
63
|
-
#1 way concentricity breaks.
|
|
75
|
+
is `rounded-sm`, however big the panel. Choosing radius by visual importance
|
|
76
|
+
is the #1 way concentricity breaks.
|
|
64
77
|
|
|
65
78
|
## Padding: geometric vs optical
|
|
66
79
|
|
|
67
80
|
- **Bounded (tier-height) containers** — bars, triggers, pills: geometric.
|
|
68
|
-
Side padding
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
than vertical padding)
|
|
72
|
-
- **Unbounded containers** —
|
|
73
|
-
|
|
81
|
+
Side padding `px-sm`/`px-md`/`px-lg` (sp/2); text-symmetric vertical
|
|
82
|
+
centering `p`/`px`/`py-inset-{xxs,sm,md}` = (h-T − text)/2; pill side
|
|
83
|
+
breathing `px-pill-{xxs,sm}` = (h-T − 0.6·text)/2 (text wants ~2× more
|
|
84
|
+
horizontal than vertical padding); text-field side padding `px-field`.
|
|
85
|
+
- **Unbounded containers** — optical: `p-panel` (compact shells), `p-card`
|
|
86
|
+
(cards, dialogs, popovers), `p-content` (full content panels). Super-linear
|
|
74
87
|
across modes so whitespace keeps pace with growing controls while text
|
|
75
|
-
stays 14px
|
|
88
|
+
stays 14px. Never pad a card with `px-*` or ad-hoc `calc`.
|
|
76
89
|
|
|
77
90
|
## Surfaces and shadows
|
|
78
91
|
|
|
79
|
-
- Depth is **shadow, not border**: raised chrome takes `shadow
|
|
80
|
-
recessed content containers (inputs,
|
|
81
|
-
`shadow-
|
|
82
|
-
`shadow-
|
|
92
|
+
- Depth is **shadow, not border**: raised chrome takes bare `shadow`;
|
|
93
|
+
floating panels take `shadow-lg`; recessed content containers (inputs,
|
|
94
|
+
tracks, wells) take `shadow-well`; pressed/latched faces take
|
|
95
|
+
`shadow-pressed`. On press, bevel sinks the CONTENT via
|
|
96
|
+
`--era-press-sink-x`/`-y` while the box holds still.
|
|
83
97
|
- **Transient vs latched fills**: hover/focus/highlighted feedback uses
|
|
84
|
-
`bg-
|
|
85
|
-
(toggle on, current tab, active button) uses opaque `bg-hover`.
|
|
86
|
-
|
|
87
|
-
|
|
98
|
+
`bg-highlight` + `shadow-highlight` (surface-owned; translucent on glass).
|
|
99
|
+
Held state (toggle on, current tab, active button) uses opaque `bg-hover`.
|
|
100
|
+
Never swap.
|
|
101
|
+
- Panels: resting fill `bg-well` (pairs with `shadow-well`), raised fill
|
|
102
|
+
`bg-elevated` (pairs with `shadow-lg` + `glass-blur` on floating panels),
|
|
103
|
+
modal scrim `bg-overlay`. Menu panels pad with `p-menu` and their rows take
|
|
104
|
+
`rounded-item` so the row highlight stays concentric inside the frame.
|
|
88
105
|
|
|
89
106
|
## Motion
|
|
90
107
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
108
|
+
The bare `transition-*` utilities default to the motion axis — `transition-colors`
|
|
109
|
+
alone is on-design: 0s at `instant` (also forced by reduced-motion), longer at
|
|
110
|
+
`extra` with a gentle overshoot. Name the axis explicitly with `ease-base` /
|
|
111
|
+
`duration-base` when overriding; never `duration-150` or a literal bezier.
|
|
112
|
+
Deriving compound timings (shimmer loops, cursor pulses) as multiples of
|
|
113
|
+
`--era-duration` makes them motion-axis-aware for free.
|
|
96
114
|
|
|
97
115
|
## Text
|
|
98
116
|
|
|
99
117
|
- `text-body` for control/body text (density-aware size); `text-fg` default,
|
|
100
118
|
`text-bright` emphasis, `text-muted` secondary.
|
|
101
|
-
- Single-glyph elements carry
|
|
102
|
-
character renders square, never a skinny pill)
|
|
119
|
+
- Single-glyph elements carry a min-width equal to their tier height (a lone
|
|
120
|
+
character renders square, never a skinny pill) — `min-w-(--era-h-md)`, see
|
|
121
|
+
the ladder note.
|
|
103
122
|
- Single-line control text next to icons carries `era-text-trim`
|
|
104
123
|
(`line-height: 1` + `text-box: trim-both ex alphabetic`) — flexbox centers
|
|
105
124
|
the line box, not the ink; the utility centers the x-height band and holds
|
|
@@ -119,8 +138,9 @@ motion-axis-aware for free.
|
|
|
119
138
|
|
|
120
139
|
Not everything era exposes is a component — these ride along with the stylesheet
|
|
121
140
|
and need no import. Reach for one before hand-rolling the same styling or bending
|
|
122
|
-
a component into the role. Full reference
|
|
123
|
-
`/utilities.
|
|
141
|
+
a component into the role. Full reference (including every named scale above):
|
|
142
|
+
`/utilities.md`; machine-readable list: `/utilities.json` (or
|
|
143
|
+
`@sig-nine/era-ui/utilities.json`).
|
|
124
144
|
|
|
125
145
|
| Class | Use it for |
|
|
126
146
|
| -------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -142,7 +162,9 @@ a component into the role. Full reference: `/utilities.md`; machine-readable lis
|
|
|
142
162
|
```
|
|
143
163
|
|
|
144
164
|
- `ui` primitives are minimal bits-ui wrappers — all bits props/snippets pass
|
|
145
|
-
through; style via `class` (merged with tailwind-merge, consumer wins
|
|
165
|
+
through; style via `class` (merged with tailwind-merge, consumer wins — the
|
|
166
|
+
named classes conflict-resolve against internals, so `class="h-lg"` on an
|
|
167
|
+
md control just works).
|
|
146
168
|
- `OS` (or `@sig-nine/era-ui/os`): WindowManager + workspaces, Desktop,
|
|
147
169
|
Window, Taskbar (built-in command bar). `AI` (or `/ai`): Conversation,
|
|
148
170
|
Message, Response, PromptInput, Tool/Reasoning/Task over the Step primitive.
|
|
@@ -151,10 +173,12 @@ a component into the role. Full reference: `/utilities.md`; machine-readable lis
|
|
|
151
173
|
|
|
152
174
|
## Review checklist (the mistakes to catch)
|
|
153
175
|
|
|
154
|
-
1. Hardcoded px/rem/radius/duration/color → replace with
|
|
176
|
+
1. Hardcoded px/rem/radius/duration/color → replace with the named class.
|
|
155
177
|
2. Radius chosen by bulk instead of corner region.
|
|
156
178
|
3. Unequal edge padding vs inner gap at any nesting level.
|
|
157
|
-
4. `px-*`/geometric padding on an unbounded container (or `
|
|
158
|
-
5. `bg-hover` used for hover feedback, or
|
|
159
|
-
6. Icon not `size-
|
|
160
|
-
7.
|
|
179
|
+
4. `px-*`/geometric padding on an unbounded container (or `p-card` on a pill).
|
|
180
|
+
5. `bg-hover` used for hover feedback, or `bg-highlight` for latched state.
|
|
181
|
+
6. Icon not `size-xs`; single glyph without the min-w square floor.
|
|
182
|
+
7. A `-(--era-*)` var class where a named class exists (`h-(--era-h-md)` →
|
|
183
|
+
`h-md`); if the var form is genuinely needed, always the paren shorthand —
|
|
184
|
+
never `x-[var(--era-y)]`.
|