@evinvest/uikit 0.17.1 → 0.19.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/README.md +204 -13
- package/dist/chunk-3IPB4QQJ.js +306 -0
- package/dist/chunk-3IPB4QQJ.js.map +1 -0
- package/dist/index.d.ts +102 -28
- package/dist/index.js +1569 -1387
- package/dist/index.js.map +1 -1
- package/dist/palette-cli.js +41 -0
- package/dist/palette-cli.js.map +1 -0
- package/dist/palette.d.ts +80 -0
- package/dist/palette.js +25 -0
- package/dist/palette.js.map +1 -0
- package/package.json +13 -4
- package/styles/ev.css +73 -0
- package/styles/theme.css +470 -0
- package/styles/tokens.css +133 -76
package/styles/tokens.css
CHANGED
|
@@ -1,39 +1,42 @@
|
|
|
1
1
|
/* AUTO-GENERATED by `nix run .#gen` from the repo-root tokens.css — do not edit. */
|
|
2
2
|
/*
|
|
3
|
-
* Shared design tokens
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* `styles/tokens.css` from its `prepare` script.
|
|
3
|
+
* Shared design tokens for the `ev_lib::uikit` (Rust) and `@evinvest/uikit`
|
|
4
|
+
* (TypeScript) components. Import this file from any Tailwind v4 entrypoint.
|
|
5
|
+
* Single source for both ports; `nix run .#gen` flattens it into each.
|
|
7
6
|
*
|
|
8
|
-
*
|
|
9
|
-
* same names; the class tables reference nothing else.
|
|
7
|
+
* Two halves, in this order:
|
|
10
8
|
*
|
|
11
|
-
*
|
|
9
|
+
* CONTRACT the names the class tables reference, the Tailwind mapping, the
|
|
10
|
+
* tokens derived from a palette, and the geometry. Brand-neutral.
|
|
11
|
+
* PALETTE EV's values for the contract's colour names. A non-EV consumer
|
|
12
|
+
* writes (or generates — `evinvest-palette`, see the uikit README)
|
|
13
|
+
* its own palette against the same names under `[data-brand="…"]`.
|
|
14
|
+
*
|
|
15
|
+
* SCOPE :root · [data-brand] — a theme root; .light · .dark — a polarity
|
|
12
16
|
* SURFACES background · card · popover · muted · hover
|
|
13
17
|
* INK ink · ink-mid · ink-soft
|
|
14
18
|
* LINES border · input · ring
|
|
15
19
|
* ROLES {role} and on-{role} for the ones that get filled:
|
|
16
20
|
* brand · primary · secondary · positive ·
|
|
17
21
|
* accent-trace · accent-debug · accent-info · accent-warn · accent-error
|
|
22
|
+
* primary-ink — the primary role as ink on a surface, where the
|
|
23
|
+
* fill and the readable value are different colours
|
|
18
24
|
* SCALARS radius · control-* · display-scale · page-* · shadows · fonts
|
|
19
25
|
* CHARTS chart-1 … chart-5
|
|
20
26
|
* MARK brand-mark · brand-aspect — supplied, never defined here
|
|
21
27
|
*
|
|
22
|
-
* Custom properties inherit, so a scope
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* single-polarity palette
|
|
28
|
+
* Custom properties inherit, so a scope on a `<section>` re-themes its subtree:
|
|
29
|
+
* `bg-card text-ink` is correct under any brand and either polarity with no
|
|
30
|
+
* prop. A brand's palette declares `.light` and `.dark` beneath its own
|
|
31
|
+
* `[data-brand]`, so a `<Section polarity="dark">` inside it takes that
|
|
32
|
+
* brand's dark values — never EV's. EV is single-polarity: its palette sits on
|
|
33
|
+
* the theme root alone and both polarity classes inherit it unchanged.
|
|
34
|
+
* Brand scopes do not nest: CSS has no "nearest ancestor", so a polarity class
|
|
35
|
+
* inside a brand inside another brand may match either.
|
|
27
36
|
*
|
|
28
37
|
* Accents are ordered by significance, not by meaning; see docs/spec/accents.md.
|
|
29
38
|
* Their values are read outside CSS (gitops mirrors them into Discord embed
|
|
30
39
|
* bars), so they stay plain hex — no color-mix.
|
|
31
|
-
*
|
|
32
|
-
* Surface ladder — dark UI reads as unfinished when every plane is the same
|
|
33
|
-
* value, so the steps below are deliberate and measured; keep them apart if you
|
|
34
|
-
* retune. background #070d18 → secondary #0d1526 (1.07:1) → card #16233c (1.24:1
|
|
35
|
-
* vs background) → popover #1d2c49 (1.13:1 vs card) → muted #26375c. Elevation
|
|
36
|
-
* rides the same ladder via --shadow-card / -elevated / -overlay.
|
|
37
40
|
*/
|
|
38
41
|
|
|
39
42
|
/*
|
|
@@ -343,6 +346,8 @@
|
|
|
343
346
|
}
|
|
344
347
|
}
|
|
345
348
|
|
|
349
|
+
/* ═══ CONTRACT ═══════════════════════════════════════════════════ */
|
|
350
|
+
|
|
346
351
|
@theme inline {
|
|
347
352
|
--radius-sm: calc(var(--radius) - 4px);
|
|
348
353
|
--radius-md: calc(var(--radius) - 2px);
|
|
@@ -359,15 +364,24 @@
|
|
|
359
364
|
0 2px 4px -2px rgb(0 0 0 / 0.30);
|
|
360
365
|
--shadow-overlay: 0 16px 48px -12px rgb(0 0 0 / 0.60);
|
|
361
366
|
|
|
362
|
-
/* The
|
|
363
|
-
* `--font-
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
*
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
367
|
+
/* The families are parameters: a brand scope sets `--brand-font-sans`,
|
|
368
|
+
* `--brand-font-display` and `--brand-font-mono` (evinvest-palette writes
|
|
369
|
+
* them from a brand file's [fonts]); `font-serif` is the display role under
|
|
370
|
+
* its older name. Unset, each falls through to EV: next/font (landing) sets
|
|
371
|
+
* `--font-inter` / `--font-playfair`, a Rust consumer `@font-face`s the same
|
|
372
|
+
* families itself. Every leading var() carries its own fallback — an
|
|
373
|
+
* undefined one would invalidate the whole `font-family` and drop the
|
|
374
|
+
* browser to its default, so it must never resolve to guaranteed-invalid.
|
|
375
|
+
* `inline` puts the var() chain in the utility itself, so it resolves on
|
|
376
|
+
* the element and a brand scope re-fonts its subtree. */
|
|
377
|
+
--font-sans: var(--brand-font-sans, var(--font-inter, "Inter")), ui-sans-serif, system-ui, sans-serif;
|
|
378
|
+
--font-serif: var(--brand-font-display, var(--font-playfair, "Playfair Display")), ui-serif, Georgia, serif;
|
|
379
|
+
--font-mono: var(--brand-font-mono, var(--font-inter, "Inter")), ui-monospace, monospace;
|
|
380
|
+
--font-display: var(--brand-font-display, var(--font-playfair, "Playfair Display")), ui-serif, Georgia, serif;
|
|
381
|
+
|
|
382
|
+
/* The colour contract: every `--color-X: var(--X)` below is a name a palette
|
|
383
|
+
* owes, except the derived ones in the next rule. `evinvest-palette` reads
|
|
384
|
+
* this block as the list, so there is no second copy of it to drift. */
|
|
371
385
|
|
|
372
386
|
/* surfaces */
|
|
373
387
|
--color-background: var(--background);
|
|
@@ -390,6 +404,7 @@
|
|
|
390
404
|
--color-brand: var(--brand);
|
|
391
405
|
--color-primary: var(--primary);
|
|
392
406
|
--color-on-primary: var(--on-primary);
|
|
407
|
+
--color-primary-ink: var(--primary-ink);
|
|
393
408
|
--color-secondary: var(--secondary);
|
|
394
409
|
--color-on-secondary: var(--on-secondary);
|
|
395
410
|
--color-positive: var(--positive);
|
|
@@ -413,60 +428,27 @@
|
|
|
413
428
|
--color-chart-5: var(--chart-5);
|
|
414
429
|
}
|
|
415
430
|
|
|
416
|
-
|
|
417
|
-
.
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
--muted: #26375c;
|
|
431
|
+
/* Derived from the palette, and redeclared on every scope a palette can be
|
|
432
|
+
* declared on. A var() inside a custom property is resolved where it is
|
|
433
|
+
* declared and the result is what inherits — declared on `:root` alone, a brand
|
|
434
|
+
* scope would change the text and keep EV's borders, hover and focus ring.
|
|
435
|
+
* Zero specificity, so a palette that sets one of these outright wins. */
|
|
436
|
+
:where(:root, .dark, .light, [data-brand]) {
|
|
423
437
|
/* the menu-item tint: a surface state, so it is named for the state */
|
|
424
438
|
--hover: color-mix(in srgb, var(--ink) 8%, transparent);
|
|
425
|
-
|
|
426
|
-
/* ── ink ─────────────────────────────────────────────────────── */
|
|
427
|
-
--ink: #e6e1d3;
|
|
428
439
|
--ink-mid: color-mix(in srgb, var(--ink) 82%, transparent);
|
|
429
440
|
/* the most-used secondary text token, so it has to clear AA on its own */
|
|
430
441
|
--ink-soft: color-mix(in srgb, var(--ink) 65%, transparent);
|
|
431
|
-
|
|
432
|
-
/* ── lines ───────────────────────────────────────────────────── */
|
|
433
442
|
--border: color-mix(in srgb, var(--ink) 14%, transparent);
|
|
434
443
|
--input: color-mix(in srgb, var(--ink) 20%, transparent);
|
|
435
|
-
--ring:
|
|
436
|
-
|
|
437
|
-
/* ── roles ───────────────────────────────────────────────────── */
|
|
438
|
-
--brand: #001e4e;
|
|
439
|
-
/* teal, not the brand navy: navy filled a Button/Switch at ~1.1:1 against
|
|
440
|
-
* these surfaces, i.e. an invisible control, and consumers hardcoded teal to
|
|
441
|
-
* get around it. The brand navy still lives in --brand. */
|
|
442
|
-
--primary: #2a9d8f;
|
|
443
|
-
--on-primary: #070d18;
|
|
444
|
-
--secondary: #0d1526;
|
|
445
|
-
--on-secondary: var(--ink);
|
|
446
|
-
/* valence, not significance: a success reads as good while staying quiet */
|
|
447
|
-
--positive: #2e9e5b;
|
|
448
|
-
--on-positive: #070d18;
|
|
449
|
-
--accent-trace: #6b7fa0;
|
|
450
|
-
--on-accent-trace: #070d18;
|
|
451
|
-
--accent-debug: #2a9d8f;
|
|
452
|
-
--on-accent-debug: #070d18;
|
|
453
|
-
--accent-info: #4a90d9;
|
|
454
|
-
--on-accent-info: #070d18;
|
|
455
|
-
--accent-warn: #f2c94c;
|
|
456
|
-
--on-accent-warn: #070d18;
|
|
457
|
-
/* lifted off the brand red #da251d, which failed AA on a card. This one value
|
|
458
|
-
* carries both the fill and the text; the vivid brand red is a gitops
|
|
459
|
-
* constant, not a UI token. */
|
|
460
|
-
--accent-error: #ef5b52;
|
|
461
|
-
--on-accent-error: #070d18;
|
|
462
|
-
|
|
463
|
-
--chart-1: #2a9d8f;
|
|
464
|
-
--chart-2: #2e9e5b;
|
|
465
|
-
--chart-3: #f2c94c;
|
|
466
|
-
--chart-4: #e58aae;
|
|
467
|
-
--chart-5: #4a90d9;
|
|
444
|
+
--ring: var(--primary-ink);
|
|
445
|
+
}
|
|
468
446
|
|
|
469
|
-
|
|
447
|
+
/* Geometry. A `[data-brand]` scope is a theme root of its own, so it restarts
|
|
448
|
+
* from these defaults (and from the scale-ups below) rather than inheriting
|
|
449
|
+
* whatever an ancestor computed — `--control-radius` in particular is derived
|
|
450
|
+
* from `--radius` and has to be recomputed wherever `--radius` may change. */
|
|
451
|
+
:where(:root, [data-brand]) {
|
|
470
452
|
--radius: 0.375rem; /* 6px on mobile; bumped to 8px ≥ sm (see @media below) */
|
|
471
453
|
/* control geometry, so a consumer reshapes every button/input at once */
|
|
472
454
|
--control-radius: calc(var(--radius) - 2px);
|
|
@@ -496,7 +478,9 @@
|
|
|
496
478
|
* --brand-mark: url("/assets/logo.svg");
|
|
497
479
|
* --brand-aspect: 387 / 335;
|
|
498
480
|
*/
|
|
481
|
+
}
|
|
499
482
|
|
|
483
|
+
:root {
|
|
500
484
|
/* shell offset — viewport space reserved by whatever shell hosts the app.
|
|
501
485
|
Standalone apps get 0; a hosting shell overrides on :root. Size
|
|
502
486
|
viewport-bound surfaces with calc(100dvh - var(--ev-shell-offset, 0px)). */
|
|
@@ -506,21 +490,94 @@
|
|
|
506
490
|
/* Mobile-first scale-ups: roomier gutters + slightly larger radii on bigger
|
|
507
491
|
viewports. Lives here (not per-component) so every consumer scales alike. */
|
|
508
492
|
@media (min-width: 640px) {
|
|
509
|
-
:root {
|
|
493
|
+
:where(:root, [data-brand]) {
|
|
510
494
|
--radius: 0.5rem;
|
|
511
495
|
--page-px: 1.5rem;
|
|
512
496
|
}
|
|
513
497
|
}
|
|
514
498
|
|
|
515
499
|
@media (min-width: 768px) {
|
|
516
|
-
:root {
|
|
500
|
+
:where(:root, [data-brand]) {
|
|
517
501
|
--band-py: 4rem;
|
|
518
502
|
--band-py-tight: 3.5rem;
|
|
519
503
|
}
|
|
520
504
|
}
|
|
521
505
|
|
|
522
506
|
@media (min-width: 1024px) {
|
|
523
|
-
:root {
|
|
507
|
+
:where(:root, [data-brand]) {
|
|
524
508
|
--page-px: 3rem;
|
|
525
509
|
}
|
|
526
510
|
}
|
|
511
|
+
|
|
512
|
+
/* ═══ PALETTE: EV ════════════════════════════════════════════════
|
|
513
|
+
*
|
|
514
|
+
* Zero specificity: EV is the default a brand scope overrides, whatever order
|
|
515
|
+
* the two sheets are imported in.
|
|
516
|
+
*
|
|
517
|
+
* Surface ladder — dark UI reads as unfinished when every plane is the same
|
|
518
|
+
* value, so the steps below are deliberate and measured; keep them apart if you
|
|
519
|
+
* retune. background #070d18 → secondary #0d1526 (1.07:1) → card #16233c (1.24:1
|
|
520
|
+
* vs background) → popover #1d2c49 (1.13:1 vs card) → muted #26375c. Elevation
|
|
521
|
+
* rides the same ladder via --shadow-card / -elevated / -overlay. Card is also
|
|
522
|
+
* pinned from above by a second floor: --primary has to clear 3:1 against it
|
|
523
|
+
* (3.39:1 today), so lifting card one step breaks the tokens test.
|
|
524
|
+
*/
|
|
525
|
+
:where(:root, [data-brand="ev"]) {
|
|
526
|
+
/* the polarity, for what the platform draws itself (a native <select>'s
|
|
527
|
+
* popup); a custom property so nothing but the kit's opt-ins reads it */
|
|
528
|
+
--scheme: dark;
|
|
529
|
+
|
|
530
|
+
/* ── surfaces ────────────────────────────────────────────────── */
|
|
531
|
+
--background: #070d18;
|
|
532
|
+
--card: #16233c;
|
|
533
|
+
--popover: #1d2c49;
|
|
534
|
+
--muted: #26375c;
|
|
535
|
+
|
|
536
|
+
/* ── ink ─────────────────────────────────────────────────────── */
|
|
537
|
+
--ink: #e6e1d3;
|
|
538
|
+
|
|
539
|
+
/* ── roles ───────────────────────────────────────────────────── */
|
|
540
|
+
--brand: #001e4e;
|
|
541
|
+
/* teal, not the brand navy: navy filled a Button/Switch at ~1.1:1 against
|
|
542
|
+
* these surfaces, i.e. an invisible control, and consumers hardcoded teal to
|
|
543
|
+
* get around it. The brand navy still lives in --brand.
|
|
544
|
+
*
|
|
545
|
+
* A fill and an ink are different jobs, so the primary role carries two
|
|
546
|
+
* values (docs/spec/accents.md). --primary-ink is the teal that reads on the
|
|
547
|
+
* surfaces: 5.85:1 on background, 4.72:1 on card. --primary is the same hue
|
|
548
|
+
* and chroma one step down in lightness — OKLCH L 0.550 C 0.094 H 183°
|
|
549
|
+
* against the ink's L 0.630 C 0.101 H 183° — so the CTA carries white:
|
|
550
|
+
* --on-primary reads on it at 4.63:1, and the fill clears the 3:1 non-text
|
|
551
|
+
* floor against background (4.20:1), secondary (3.94:1), card (3.39:1) and
|
|
552
|
+
* popover (3.01:1), so a checked Switch on a Card still reads as one. Muted
|
|
553
|
+
* is the one surface under the floor (2.54:1); the controls that fill there
|
|
554
|
+
* carry an on-primary mark, see the spec. Darkening the single value instead
|
|
555
|
+
* would have dropped every teal label below AA. */
|
|
556
|
+
--primary: #128377;
|
|
557
|
+
--on-primary: #ffffff;
|
|
558
|
+
--primary-ink: #2a9d8f;
|
|
559
|
+
--secondary: #0d1526;
|
|
560
|
+
--on-secondary: var(--ink);
|
|
561
|
+
/* valence, not significance: a success reads as good while staying quiet */
|
|
562
|
+
--positive: #2e9e5b;
|
|
563
|
+
--on-positive: #070d18;
|
|
564
|
+
--accent-trace: #6b7fa0;
|
|
565
|
+
--on-accent-trace: #070d18;
|
|
566
|
+
--accent-debug: #2a9d8f;
|
|
567
|
+
--on-accent-debug: #070d18;
|
|
568
|
+
--accent-info: #4a90d9;
|
|
569
|
+
--on-accent-info: #070d18;
|
|
570
|
+
--accent-warn: #f2c94c;
|
|
571
|
+
--on-accent-warn: #070d18;
|
|
572
|
+
/* lifted off the brand red #da251d, which failed AA on a card. This one value
|
|
573
|
+
* carries both the fill and the text; the vivid brand red is a gitops
|
|
574
|
+
* constant, not a UI token. */
|
|
575
|
+
--accent-error: #ef5b52;
|
|
576
|
+
--on-accent-error: #070d18;
|
|
577
|
+
|
|
578
|
+
--chart-1: #2a9d8f;
|
|
579
|
+
--chart-2: #2e9e5b;
|
|
580
|
+
--chart-3: #f2c94c;
|
|
581
|
+
--chart-4: #e58aae;
|
|
582
|
+
--chart-5: #4a90d9;
|
|
583
|
+
}
|