@vegastack/design-tokens 0.4.0 → 0.5.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/base.css +79 -60
- package/dist/theme.css +106 -440
- package/dist/tokens.cjs +86 -526
- package/dist/tokens.d.cts +84 -524
- package/dist/tokens.d.ts +84 -524
- package/dist/tokens.js +86 -526
- package/dist/tokens.json +86 -526
- package/dist/utilities.css +87 -13
- package/package.json +1 -1
package/dist/base.css
CHANGED
|
@@ -1,27 +1,62 @@
|
|
|
1
|
-
/* @vegastack/design-tokens/base.css — opt-in base
|
|
1
|
+
/* @vegastack/design-tokens/base.css — the opt-in base layer (kept separate so consumers aren't
|
|
2
|
+
forced into it).
|
|
3
|
+
|
|
4
|
+
REBUILT BY THE SHADCN RESET (Batch 1, 2026-09-18). This file is now upstream's own base layer
|
|
5
|
+
plus exactly the decisions `docs/plans/2026-09-18-shadcn-reset/decisions.md` marks **ours**:
|
|
6
|
+
|
|
7
|
+
FOC-1 one global :focus-visible outline; components restate nothing
|
|
8
|
+
FOC-7 the forced-colours fallback for text entry
|
|
9
|
+
MOT-5 the reduced-motion reset (and the one sanctioned !important)
|
|
10
|
+
INT-1 the hand cursor, on a wider selector list than shadcn's --pointer rule
|
|
11
|
+
INT-7 touch-action: manipulation and no tap highlight
|
|
12
|
+
OVL-13 body { isolation: isolate } for the portal theme scope
|
|
13
|
+
|
|
14
|
+
Deleted with the reset: INT-2's `cursor: default` on disabled controls (INT-2 = shadcn, and
|
|
15
|
+
upstream has no such rule).
|
|
16
|
+
|
|
17
|
+
`color-scheme` (COL-22) is not here — it is emitted per theme into `:root` and `.dark` by the
|
|
18
|
+
token build, because it has to travel with the palette it describes. */
|
|
19
|
+
|
|
2
20
|
@layer base {
|
|
21
|
+
/* Upstream's own base layer, with one change. Upstream writes
|
|
22
|
+
`* { @apply border-border outline-ring/50 }`; the `outline-ring/50` half is a 50%-opacity
|
|
23
|
+
outline COLOUR on every element, which exists only to soften the focus glow this system
|
|
24
|
+
removes. FOC-1 below owns focus outright and paints the ring solid, so the `/50` is dropped —
|
|
25
|
+
keeping it would mean two rules describing the same affordance at two different opacities. */
|
|
3
26
|
* {
|
|
4
|
-
@apply border-border
|
|
27
|
+
@apply border-border;
|
|
5
28
|
}
|
|
6
29
|
body {
|
|
7
|
-
/* `isolate` creates a root stacking context so Base UI portaled popups (Dialog,
|
|
8
|
-
Tooltip, Select, menus, Sheet) reliably stack above page content — required by Base
|
|
9
|
-
Quick Start ("Set up portals"). Consumers importing base.css get this for free; if you
|
|
10
|
-
import base.css, add `isolation: isolate` to your app root yourself. */
|
|
30
|
+
/* `isolate` (OVL-13) creates a root stacking context so Base UI portaled popups (Dialog,
|
|
31
|
+
Popover, Tooltip, Select, menus, Sheet) reliably stack above page content — required by Base
|
|
32
|
+
UI's Quick Start ("Set up portals"). Consumers importing base.css get this for free; if you
|
|
33
|
+
don't import base.css, add `isolation: isolate` to your app root yourself. */
|
|
11
34
|
@apply bg-background text-foreground isolate;
|
|
12
35
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
36
|
+
html {
|
|
37
|
+
@apply font-sans;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/* FOC-1 — the SINGLE focus affordance in the system. 2px solid, offset 1, in `ring`, which
|
|
41
|
+
FOC-2 binds to the near-black / near-white ink rather than shadcn's mid-grey. Components carry
|
|
42
|
+
no focus ring of their own: upstream's `focus-visible:ring-3 focus-visible:ring-ring/50` glow
|
|
43
|
+
is stripped from every migrated component (FOC-6), and `design-lint`'s `no-focus-ring-glow`
|
|
44
|
+
rule is what stops it coming back through a later upstream pull. */
|
|
16
45
|
:focus-visible {
|
|
17
46
|
@apply outline-2 outline-offset-1 outline-ring;
|
|
18
47
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
48
|
+
|
|
49
|
+
/* INT-1 — the hand cursor. shadcn's `--pointer` flag writes
|
|
50
|
+
`button:not(:disabled), [role="button"]:not(:disabled) { cursor: pointer }`; ours is the same
|
|
51
|
+
rule over the full set of things a person clicks, so a menu row, a tab, a switch and a listbox
|
|
52
|
+
option all read as clickable. This is the SINGLE global source of truth — components must NOT
|
|
53
|
+
re-declare `cursor-pointer` locally; only genuinely non-standard clickables (a clickable table
|
|
54
|
+
row, a label tied to a control) or non-pointer cursors (`cursor-text`, the select scroll
|
|
55
|
+
arrows) set a cursor of their own.
|
|
56
|
+
|
|
57
|
+
INT-7 rides on the same selector list: keep touch controls responsive without disabling page
|
|
58
|
+
pan or pinch-zoom, and suppress the grey Android tap flash. Text-entry fields and document
|
|
59
|
+
links stay untouched. */
|
|
25
60
|
button,
|
|
26
61
|
[role="button"],
|
|
27
62
|
[role="tab"],
|
|
@@ -34,34 +69,24 @@
|
|
|
34
69
|
[role="option"],
|
|
35
70
|
summary {
|
|
36
71
|
cursor: pointer;
|
|
37
|
-
/* Keep touch controls responsive without disabling page pan/pinch zoom.
|
|
38
|
-
Text-entry fields and document links stay untouched. */
|
|
39
72
|
touch-action: manipulation;
|
|
40
73
|
-webkit-tap-highlight-color: transparent;
|
|
41
74
|
}
|
|
42
|
-
/* Disabled controls opt out (those that don't already set `pointer-events-none` /
|
|
43
|
-
`cursor-not-allowed`). Higher specificity than the element/role selectors above, so it wins;
|
|
44
|
-
a component's own `disabled:cursor-not-allowed` lives in the later utilities layer and still wins. */
|
|
45
|
-
:disabled,
|
|
46
|
-
[aria-disabled="true"],
|
|
47
|
-
[data-disabled] {
|
|
48
|
-
cursor: default;
|
|
49
|
-
}
|
|
50
75
|
}
|
|
51
76
|
|
|
52
|
-
/*
|
|
77
|
+
/* FOC-7 — preserve the focus contract when authored colours are replaced by a forced-colours
|
|
78
|
+
palette. */
|
|
53
79
|
@media (forced-colors: active) {
|
|
54
80
|
:focus-visible {
|
|
55
81
|
outline-color: Highlight;
|
|
56
82
|
}
|
|
57
83
|
|
|
58
|
-
/* Text-entry focus (
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
specificity, so the fallback is written ONCE here, never per component.
|
|
84
|
+
/* Text-entry focus (FOC-3). Every text-entry control signals focus with a border TINT and strips
|
|
85
|
+
the outline, because a raw text field cannot tell mouse from keyboard. Forced colours replaces
|
|
86
|
+
`border-color` outright, so the tint vanishes and `outline-style: none` stays in force — a
|
|
87
|
+
Windows High Contrast user had no caret location at all. This block is UNLAYERED on purpose:
|
|
88
|
+
it beats the component's `outline-none` (a layered utility) regardless of specificity, so the
|
|
89
|
+
fallback is written ONCE here, never per component.
|
|
65
90
|
- `input`/`textarea` at `:focus` (not `:focus-visible`, matching the tint's trigger);
|
|
66
91
|
- composite editors (TextEdit's contenteditable) at `:focus`;
|
|
67
92
|
- wrapper-tinted surfaces (`data-slot="text-edit"`, and every `data-field-group`) at
|
|
@@ -75,14 +100,13 @@
|
|
|
75
100
|
outline-offset: 1px;
|
|
76
101
|
}
|
|
77
102
|
|
|
78
|
-
/* …and only ONE of them paints
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
`fieldControlGroup` in `@vegastack/design` — the attribute IS the contract. */
|
|
103
|
+
/* …and only ONE of them paints. A bordered field GROUP — Input's prefix/suffix wrapper,
|
|
104
|
+
NumberField's stepper group, ChipInput, the Combobox input-group — clips with `overflow-hidden`
|
|
105
|
+
so its addons follow the rounded corner. The inner input's own outline is offset outward INTO
|
|
106
|
+
that clip, so it was drawn and then cut, which is how an addon field ended up with no visible
|
|
107
|
+
focus at all under the forced palette. The group carries the outline (it is the element whose
|
|
108
|
+
border the tint would have moved); the control inside it stands down, so the two never paint a
|
|
109
|
+
double ring. */
|
|
86
110
|
[data-field-group] input:focus,
|
|
87
111
|
[data-field-group] textarea:focus {
|
|
88
112
|
outline: none;
|
|
@@ -90,15 +114,13 @@
|
|
|
90
114
|
}
|
|
91
115
|
|
|
92
116
|
/* ───────────────────────────────────────────────────────────────────────────────────────────────
|
|
93
|
-
* THE ONE SANCTIONED `!important` EXCEPTION (WCAG 2.1
|
|
94
|
-
* Users who set `prefers-reduced-motion: reduce` MUST have animations
|
|
95
|
-
* over component-authored durations; `!important` is the standard, intentional mechanism for
|
|
96
|
-
* reset (it has to win against any animated rule, including ones defined later or with higher
|
|
97
|
-
* specificity). This is the SOLE place `!important` is permitted in shipped VegaStack CSS
|
|
98
|
-
* design-
|
|
99
|
-
*
|
|
100
|
-
* add `!important` to win a specificity fight elsewhere; restructure the selector or token instead.
|
|
101
|
-
* (requirements §7.5 / skills/design-audit.)
|
|
117
|
+
* MOT-5 — THE ONE SANCTIONED `!important` EXCEPTION (WCAG 2.1 reduced-motion override).
|
|
118
|
+
* Users who set `prefers-reduced-motion: reduce` MUST have animations and transitions neutralised
|
|
119
|
+
* even over component-authored durations; `!important` is the standard, intentional mechanism for
|
|
120
|
+
* this reset (it has to win against any animated rule, including ones defined later or with higher
|
|
121
|
+
* specificity). This is the SOLE place `!important` is permitted in shipped VegaStack CSS, and
|
|
122
|
+
* `design-lint --token-css` FAILS on any `!important` outside this block. Do not add `!important`
|
|
123
|
+
* to win a specificity fight elsewhere; restructure the selector or token instead.
|
|
102
124
|
* ──────────────────────────────────────────────────────────────────────────────────────────────*/
|
|
103
125
|
@media (prefers-reduced-motion: reduce) {
|
|
104
126
|
*,
|
|
@@ -106,22 +128,19 @@
|
|
|
106
128
|
::after {
|
|
107
129
|
animation-duration: 0.01ms !important;
|
|
108
130
|
animation-iteration-count: 1 !important;
|
|
109
|
-
/* A zeroed DURATION alone is not enough: a staggered entrance schedules its
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
* is why no component needs its own `motion-reduce:` restatement (audit
|
|
114
|
-
* batch Di1 / B2-06). */
|
|
131
|
+
/* A zeroed DURATION alone is not enough: a staggered entrance schedules its per-item
|
|
132
|
+
* `animation-delay` in real time, so the items would still appear one after another (each
|
|
133
|
+
* instantly) over the full stagger window. Zeroing the delay too is what makes "reduced motion"
|
|
134
|
+
* a static end state — and it is why no component needs its own `motion-reduce:` restatement. */
|
|
115
135
|
animation-delay: 0s !important;
|
|
116
136
|
transition-duration: 0.01ms !important;
|
|
117
137
|
transition-delay: 0s !important;
|
|
118
138
|
scroll-behavior: auto !important;
|
|
119
139
|
}
|
|
120
140
|
|
|
121
|
-
/* View Transitions
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
* own reduced-motion kill switch. */
|
|
141
|
+
/* View Transitions: the universal selector above never reaches the ::view-transition-* pseudo
|
|
142
|
+
* element tree (it lives on the root's snapshot layer, outside normal element matching), so
|
|
143
|
+
* route-change cross-fades and morphs need their own reduced-motion kill switch. */
|
|
125
144
|
::view-transition-group(*),
|
|
126
145
|
::view-transition-old(*),
|
|
127
146
|
::view-transition-new(*) {
|