@dxos/ui-theme 0.8.4-main.abd8ff62ef → 0.8.4-main.bc2380dfbc

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 (49) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +1 -1
  3. package/dist/lib/browser/index.mjs +29 -31
  4. package/dist/lib/browser/index.mjs.map +3 -3
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/node-esm/index.mjs +29 -31
  7. package/dist/lib/node-esm/index.mjs.map +3 -3
  8. package/dist/lib/node-esm/meta.json +1 -1
  9. package/dist/plugin/node-cjs/main.css +85 -79
  10. package/dist/plugin/node-cjs/main.css.map +2 -2
  11. package/dist/plugin/node-cjs/meta.json +1 -1
  12. package/dist/plugin/node-esm/main.css +85 -79
  13. package/dist/plugin/node-esm/main.css.map +2 -2
  14. package/dist/plugin/node-esm/meta.json +1 -1
  15. package/dist/types/src/defs.d.ts +1 -1
  16. package/dist/types/src/defs.d.ts.map +1 -1
  17. package/dist/types/src/fragments/hover.d.ts +0 -1
  18. package/dist/types/src/fragments/hover.d.ts.map +1 -1
  19. package/dist/types/src/theme/components/button.d.ts +2 -2
  20. package/dist/types/src/theme/components/button.d.ts.map +1 -1
  21. package/dist/types/src/util/hash-styles.d.ts +1 -1
  22. package/dist/types/src/util/hash-styles.d.ts.map +1 -1
  23. package/dist/types/tsconfig.tsbuildinfo +1 -1
  24. package/package.json +8 -9
  25. package/src/Theme.stories.tsx +5 -5
  26. package/src/css/DESIGN_SYSTEM.md +159 -0
  27. package/src/css/base/base.css +2 -2
  28. package/src/css/components/button.css +3 -3
  29. package/src/css/components/checkbox.css +1 -1
  30. package/src/css/components/focus.css +12 -12
  31. package/src/css/components/panel.css +23 -23
  32. package/src/css/components/selected.css +58 -17
  33. package/src/css/components/surface.css +4 -4
  34. package/src/css/components/tag.css +23 -23
  35. package/src/css/theme/semantic.css +36 -40
  36. package/src/css/theme/spacing.css +1 -1
  37. package/src/css/theme/styles.css +22 -22
  38. package/src/defs.ts +1 -1
  39. package/src/fragments/AUDIT.md +0 -2
  40. package/src/fragments/hover.ts +0 -2
  41. package/src/main.css +3 -3
  42. package/src/theme/components/button.ts +2 -2
  43. package/src/theme/components/focus.ts +2 -2
  44. package/src/theme/components/icon-button.ts +1 -1
  45. package/src/theme/components/input.ts +5 -5
  46. package/src/theme/components/message.ts +1 -1
  47. package/src/theme/components/select.ts +1 -1
  48. package/src/theme/components/tooltip.ts +1 -1
  49. package/src/util/hash-styles.ts +19 -19
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/ui-theme",
3
- "version": "0.8.4-main.abd8ff62ef",
3
+ "version": "0.8.4-main.bc2380dfbc",
4
4
  "description": "A set of design system tokens to use with DXOS UI.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -8,7 +8,7 @@
8
8
  "type": "git",
9
9
  "url": "https://github.com/dxos/dxos"
10
10
  },
11
- "license": "MIT",
11
+ "license": "FSL-1.1-Apache-2.0",
12
12
  "author": "DXOS.org",
13
13
  "sideEffects": [
14
14
  "*.css"
@@ -39,8 +39,7 @@
39
39
  "@tailwindcss/forms": "^0.5.9",
40
40
  "@tailwindcss/postcss": "^4.2.0",
41
41
  "autoprefixer": "^10.5.0",
42
- "esbuild-style-plugin": "^1.6.1",
43
- "glob": "^7.2.3",
42
+ "esbuild-style-plugin": "^1.6.3",
44
43
  "globby": "14.1.0",
45
44
  "lodash.merge": "^4.6.2",
46
45
  "postcss": "^8.5.12",
@@ -50,16 +49,16 @@
50
49
  "tailwind-scrollbar": "^4.0.0",
51
50
  "tailwindcss": "^4.2.0",
52
51
  "tailwindcss-radix": "^4.0.2",
53
- "@dxos/log": "0.8.4-main.abd8ff62ef",
54
- "@dxos/node-std": "0.8.4-main.abd8ff62ef",
55
- "@dxos/util": "0.8.4-main.abd8ff62ef"
52
+ "@dxos/log": "0.8.4-main.bc2380dfbc",
53
+ "@dxos/node-std": "0.8.4-main.bc2380dfbc",
54
+ "@dxos/util": "0.8.4-main.bc2380dfbc"
56
55
  },
57
56
  "devDependencies": {
58
57
  "@types/lodash.merge": "^4.6.6",
59
58
  "@types/postcss-import": "^14.0.3",
60
59
  "esbuild": "0.28.0",
61
- "vite": "^8.0.10",
62
- "@dxos/ui-types": "0.8.4-main.abd8ff62ef"
60
+ "vite": "^8.0.13",
61
+ "@dxos/ui-types": "0.8.4-main.bc2380dfbc"
63
62
  },
64
63
  "peerDependencies": {
65
64
  "react": "~19.2.3"
@@ -37,8 +37,8 @@ const ColorSwatch = ({ hue }: { hue: string }) => {
37
37
  >
38
38
  <div
39
39
  style={{
40
- color: `var(--color-${hue}-text)`,
41
40
  backgroundColor: `var(--color-base-surface)`,
41
+ color: `var(--color-${hue}-text)`,
42
42
  }}
43
43
  className='p-2 text-sm'
44
44
  >
@@ -46,8 +46,8 @@ const ColorSwatch = ({ hue }: { hue: string }) => {
46
46
  </div>
47
47
  <div
48
48
  style={{
49
- color: `var(--color-${hue}-text)`,
50
49
  backgroundColor: `var(--color-${hue}-fill)`,
50
+ color: `var(--color-${hue}-text)`,
51
51
  }}
52
52
  className='px-1 text-sm flex items-center'
53
53
  >
@@ -57,8 +57,8 @@ const ColorSwatch = ({ hue }: { hue: string }) => {
57
57
  </div>
58
58
  <div
59
59
  style={{
60
- color: `var(--color-${hue}-surface-text)`,
61
60
  backgroundColor: `var(--color-${hue}-surface)`,
61
+ color: `var(--color-${hue}-foreground)`,
62
62
  }}
63
63
  className='p-2 text-sm'
64
64
  >
@@ -163,9 +163,9 @@ export const Surfaces = {
163
163
  { className: 'bg-card-surface', label: 'card' },
164
164
  { className: 'bg-modal-surface', label: 'modal' },
165
165
  { className: 'bg-input-surface', label: 'input' },
166
- { className: 'bg-active-surface', label: 'active' },
166
+ { className: 'bg-current-surface', label: 'current' },
167
167
  { className: 'bg-hover-surface', label: 'hover' },
168
- { className: 'bg-inverse-surface text-inverse-surface-text', label: 'inverse' },
168
+ { className: 'bg-inverse-surface text-inverse-foreground', label: 'inverse' },
169
169
  ].map(({ className, label }) => (
170
170
  <div key={className} className={mx('shrink-0 p-2 aspect-square w-48 rounded-md', className)}>
171
171
  {label}
@@ -0,0 +1,159 @@
1
+ # Design System: Color Tokens
2
+
3
+ This document describes how color tokens are organized in `ui-theme`, the naming rules they follow, and the rationalization of overlapping state tokens (`current` / `active` / `highlight` / `selected` / `hover`) and text-on-surface tokens (`surface-text` → `foreground`).
4
+
5
+ ## Token tiers
6
+
7
+ Three layers, each consuming the one below:
8
+
9
+ | Tier | File | Purpose | Example |
10
+ | ----------- | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
11
+ | 1. Scale | [`theme/palette.css`](./theme/palette.css) | Raw color values. Extends Tailwind's neutral/blue scales with intermediate stops and aliases the `primary-*` ramp to `blue-*`. | `--color-neutral-150`, `--color-primary-500` |
12
+ | 2. Hue role | [`theme/styles.css`](./theme/styles.css) | Per-hue role tokens generated mechanically for every Tailwind hue plus `neutral`. Five roles each: `fill`, `surface`, `foreground`, `text`, `border`. Light/dark resolved via `light-dark()`. | `--color-red-surface`, `--color-neutral-border` |
13
+ | 3. Semantic | [`theme/semantic.css`](./theme/semantic.css) | Named UI surfaces and states. May reference hue-role tokens (e.g. `error-surface` → `rose-surface`) or compose directly from the scale. | `--color-card-surface`, `--color-current-surface`, `--color-error-text` |
14
+
15
+ A consumer should reach for the highest tier that fits. Use `bg-card-surface`, not `bg-neutral-75`. Use `text-error-text`, not `text-rose-700`.
16
+
17
+ ## Naming convention
18
+
19
+ Token names follow `--color-{name}-{part}[-{state}]`:
20
+
21
+ - **`name`** identifies the role or surface (`card`, `current`, `accent`, `error`, `red`).
22
+ - **`part`** is one of a fixed vocabulary:
23
+ - `surface` — the background fill of a thing.
24
+ - `foreground` — the text/icon color that sits on the surface (paired with `surface`).
25
+ - `border` — border color on the surface.
26
+ - `fill` — solid attention-grabbing fill (badges, dots, indicators); more saturated than `surface`.
27
+ - `text` — text color used standalone, on the base canvas (no enclosing surface).
28
+ - **`state`** is optional, appended last: `hover`, `active` (pressed). State always follows the part it modifies.
29
+
30
+ ### Pattern rules
31
+
32
+ - Suffix order is fixed: `{name}-{part}-{state}`. The part comes first, then the state.
33
+ - Pair rule: every `{name}-surface` that hosts text has a matching `{name}-foreground`. Don't invent new ink-suffix names — keep the vocabulary closed.
34
+ - A state token implies a base — `current-surface-hover` only makes sense if `current-surface` exists.
35
+ - The `-text` part (standalone) is reserved for text on the base canvas, with no enclosing surface (e.g. `accent-text` for a hyperlink in body copy). Text on any named surface uses `{name}-foreground`.
36
+
37
+ ## Surfaces
38
+
39
+ Layered fills, ordered from recessive to prominent:
40
+
41
+ ```
42
+ base-surface n-50 / n-950 the page canvas
43
+ deck-surface n-50 / n-950 deck panes
44
+ toolbar-surface n-75 / n-925 toolbars
45
+ card-surface n-75 / n-925 cards
46
+ group-surface n-100 / n-900 grouped containers
47
+ modal-surface n-100 / n-900 modals / dialogs
48
+ sidebar-surface n-100 / n-900 sidebars
49
+ header-surface n-100 / n-900 headers
50
+ input-surface n-200 / n-800 form controls
51
+ ```
52
+
53
+ Each surface that hosts text declares a matching `*-foreground` (defaulting to `n-950 / n-50`).
54
+
55
+ ## State tokens (rationalized)
56
+
57
+ The system has three orthogonal states. Pick by what the ARIA / markup is saying.
58
+
59
+ | State | Token | When | Value |
60
+ | -------------------------- | ------------------------ | ---------------------------------------------------------------- | ----------------- |
61
+ | Active item, one-of-N | `current-surface` | `aria-current=true` (nav cursor, current row, current path) | `n-100` / `n-900` |
62
+ | Hovering on current item | `current-surface-hover` | pointer-over on a `current` element | `n-200` / `n-800` |
63
+ | Text on a current surface | `current-foreground` | text/icon color paired with `current-surface` | `n-950` / `n-50` |
64
+ | Selected / checked | `selected-surface` | `aria-selected=true` (multi-select, listbox option, checked row) | `n-150` / `n-850` |
65
+ | Hovering on selected | `selected-surface-hover` | pointer-over on a `selected` element | `n-250` / `n-750` |
66
+ | Text on a selected surface | `selected-foreground` | text/icon color paired with `selected-surface` | `n-950` / `n-50` |
67
+ | Transient pointer-over | `hover-surface` | `:hover`, Radix `data-highlighted` (keyboard cursor in menus) | `n-250` / `n-750` |
68
+ | Text on a transient hover | `hover-foreground` | text/icon color paired with `hover-surface` | `n-950` / `n-50` |
69
+
70
+ **Why these three.** `current` describes one-of-N navigation/selection state ("you are here"); `selected` describes a checked item in a set (multi-select-able); `hover` is transient pointer feedback. Driving the distinction off ARIA keeps markup and tokens in sync.
71
+
72
+ ### Visual hierarchy
73
+
74
+ ```
75
+ card-surface n-75 / n-925 resting
76
+ current-surface n-100 / n-900 "I am the active one"
77
+ current-surface-hover n-200 / n-800 hovering the active one
78
+ hover-surface n-250 / n-750 transient pointer-over anywhere else
79
+ ```
80
+
81
+ ## Consolidation: tokens that go away
82
+
83
+ These are merged into the rationalized state vocabulary:
84
+
85
+ | Removed | Replaced by | Notes |
86
+ | ------------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
87
+ | `active-surface` | `current-surface` | Same concept ("the active one"). Same value already. |
88
+ | `active-text` | `current-foreground` | Renamed and reclassified — it was always foreground (text on the surface), not `text`. |
89
+ | `highlight-surface` | `current-surface` | `selected.css` used it for `aria-current=true`. |
90
+ | `highlight-surface-hover` | `current-surface-hover` | |
91
+ | `highlight-surface-text` | `current-foreground` | Rename to the new `-foreground` suffix. |
92
+ | `*-surface-text` (all) | `*-foreground` | Repository-wide rename for every hue, semantic, and named-surface token (e.g. `base-surface-text` → `base-foreground`, `red-surface-text` → `red-foreground`, `error-surface-text` → `error-foreground`). |
93
+
94
+ ### Visual change to expect
95
+
96
+ The 9 `bg-active-surface` call sites become one shade subtler (from `n-200/800` to `n-100/900`). This aligns them with the existing `selected.css` treatment of `aria-current=true` and produces the coherent layering shown above.
97
+
98
+ ### Out-of-scope drift to fix separately
99
+
100
+ Two sites use `bg-hover-surface` as a _resting_ fill (not a hover state):
101
+
102
+ - [packages/plugins/plugin-navtree/src/experimental/Tree.tsx:196](../../../../plugins/plugin-navtree/src/experimental/Tree.tsx)
103
+ - [packages/plugins/plugin-script/src/components/TestPanel/TestPanel.tsx:171](../../../../plugins/plugin-script/src/components/TestPanel/TestPanel.tsx)
104
+
105
+ These should probably move to `card-surface` or `current-surface` depending on intent. Tracked as a follow-up; not part of this rationalization.
106
+
107
+ ## Accent (primary)
108
+
109
+ `accent-*` is the project's primary brand color (blue). The token name is `accent`, not `primary`, to avoid colliding with the raw scale `--color-primary-*` (which is aliased to `blue-*` for Tailwind utility convenience).
110
+
111
+ | Token | Purpose |
112
+ | ---------------------- | --------------------------------------------------- |
113
+ | `accent-surface` | Fill for primary buttons / call-to-action surfaces. |
114
+ | `accent-surface-hover` | Hover state. |
115
+ | `accent-foreground` | Text/icon color on accent surfaces. |
116
+ | `accent-text` | Standalone accent-colored text (links, emphasis). |
117
+ | `accent-text-hover` | Hover state for accent text. |
118
+
119
+ This is the canonical illustration of the `foreground` vs `text` distinction: `accent-foreground` is the ink on an accent button; `accent-text` is the accent-colored body link.
120
+
121
+ Note: `accent-focus-indicator` is removed — focus rings are now global tokens (see [Focus rings](#focus-rings)).
122
+
123
+ ## Focus rings
124
+
125
+ Focus indicators are a global UI affordance, not a per-surface property. Every focusable element should pick from the same small set of ring colors so focus stays visually consistent and accessible.
126
+
127
+ | Token | Value | Used by |
128
+ | ------------------- | ----------------- | -------------------------------------------------------- |
129
+ | `focus-ring` | `blue-600` | Default focus ring (buttons, inputs, grid cells, links). |
130
+ | `focus-ring-subtle` | `n-400` / `n-600` | Subdued ring for low-emphasis focusable elements. |
131
+
132
+ Tokens removed in this rationalization:
133
+
134
+ | Removed | Replaced by | Notes |
135
+ | ------------------------- | ------------------- | -------------------------------------------------------------- |
136
+ | `accent-focus-indicator` | `focus-ring` | Was `blue-600`. Same value. |
137
+ | `grid-focus-indicator` | `focus-ring` | Was `primary-600` (= `blue-600`). Identical to accent variant. |
138
+ | `neutral-focus-indicator` | `focus-ring-subtle` | Was `n-400` / `n-600`. Same value. |
139
+
140
+ ## Semantic aliases
141
+
142
+ Status colors point at hue-role tokens:
143
+
144
+ | Token | Aliases |
145
+ | ----------- | ----------- |
146
+ | `info-*` | `cyan-*` |
147
+ | `success-*` | `emerald-*` |
148
+ | `warning-*` | `amber-*` |
149
+ | `error-*` | `rose-*` |
150
+
151
+ Each provides `fill`, `surface`, `foreground`, `text`, `border`.
152
+
153
+ ## Adding a new token
154
+
155
+ 1. Does an existing semantic token already cover it? If yes, use it.
156
+ 2. Does it represent a new named surface, state, or status? Add it to `semantic.css` referencing scale or hue-role tokens — never raw hex.
157
+ 3. Follow the suffix order: `{name}-{part}[-{state}]`.
158
+ 4. If the new token will be used through a Tailwind utility that the source-scan can't see (e.g. CSS file, dynamic class), add it to `@source inline(...)` in [`main.css`](./main.css).
159
+ 5. If it ships state variants (`-hover`, `-active`), declare them adjacent to the base in the same block.
@@ -35,9 +35,9 @@
35
35
  html .dark,
36
36
  .sb-show-main {
37
37
  background-color: var(--color-base-surface);
38
- color: var(--color-base-surface-text);
38
+ color: var(--color-base-foreground);
39
39
  --surface-bg: var(--color-base-surface);
40
- --surface-text: var(--color-base-surface-text);
40
+ --foreground: var(--color-base-foreground);
41
41
  --description-text: var(--color-description);
42
42
  }
43
43
  }
@@ -10,7 +10,7 @@
10
10
 
11
11
  /* Base styles */
12
12
  .dx-button {
13
- @apply shrink-0 inline-flex select-none items-center justify-center overflow-hidden min-h-[2.5rem] px-3;
13
+ @apply shrink-0 inline-flex select-none items-center justify-center overflow-hidden min-h-[2rem] px-3;
14
14
  @apply font-medium transition-colors duration-100 ease-linear bg-input-surface;
15
15
  &[aria-pressed='true'],
16
16
  &[aria-checked='true'] {
@@ -53,7 +53,7 @@
53
53
 
54
54
  /* Variants */
55
55
  &[data-variant='primary'] {
56
- @apply text-accent-surface-text bg-accent-surface;
56
+ @apply text-accent-foreground bg-accent-surface;
57
57
  &:hover,
58
58
  &[aria-pressed='true'],
59
59
  &[aria-checked='true'] &[data-state='open'] {
@@ -61,7 +61,7 @@
61
61
  }
62
62
  }
63
63
  &[data-variant='destructive'] {
64
- @apply text-accent-surface-text bg-rose-fill;
64
+ @apply text-accent-foreground bg-rose-fill;
65
65
  &:hover,
66
66
  &[aria-pressed='true'],
67
67
  &[aria-checked='true'] &[data-state='open'] {
@@ -27,7 +27,7 @@
27
27
  }
28
28
 
29
29
  .dx-checkbox {
30
- @apply w-4 h-4 overflow-hidden shadow-inner transition-colors bg-un-accent accent-un-accent text-accent-surface-text shrink-0 inline-grid place-items-center rounded-xs;
30
+ @apply w-4 h-4 overflow-hidden shadow-inner transition-colors bg-un-accent accent-un-accent text-accent-foreground shrink-0 inline-grid place-items-center rounded-xs;
31
31
  }
32
32
 
33
33
  /* TODO(ZaymonFC): Focus is handled by .dx-focus-ring, but should ideally be applied as part of this component.*/
@@ -12,10 +12,10 @@
12
12
  }
13
13
 
14
14
  &:focus-visible {
15
- @apply ring-focus-line ring-offset-focus-offset z-[1] ring-[var(--color-neutral-focus-indicator)];
15
+ @apply ring-focus-line ring-offset-focus-offset z-[1] ring-[var(--color-focus-ring-subtle)];
16
16
 
17
17
  &[data-variant='primary'] {
18
- @apply ring-[var(--color-accent-focus-indicator)];
18
+ @apply ring-[var(--color-focus-ring)];
19
19
  }
20
20
 
21
21
  &:hover {
@@ -45,10 +45,10 @@
45
45
  }
46
46
 
47
47
  &:focus {
48
- @apply ring-focus-line ring-offset-focus-offset z-[1] ring-[var(--color-neutral-focus-indicator)];
48
+ @apply ring-focus-line ring-offset-focus-offset z-[1] ring-[var(--color-focus-ring-subtle)];
49
49
 
50
50
  &[data-variant='primary'] {
51
- @apply ring-[var(--color-accent-focus-indicator)];
51
+ @apply ring-[var(--color-focus-ring)];
52
52
  }
53
53
 
54
54
  &:hover {
@@ -79,10 +79,10 @@
79
79
  .dx-focus-ring-group:focus-visible .dx-focus-ring-group-indicator,
80
80
  .dx-focus-ring-group-x:focus-visible .dx-focus-ring-group-x-indicator,
81
81
  .dx-focus-ring-group-y:focus-visible .dx-focus-ring-group-y-indicator {
82
- @apply ring-focus-line ring-offset-focus-offset ring-[var(--color-neutral-focus-indicator)];
82
+ @apply ring-focus-line ring-offset-focus-offset ring-[var(--color-focus-ring-subtle)];
83
83
 
84
84
  &[data-variant='primary'] {
85
- @apply ring-[var(--color-accent-focus-indicator)];
85
+ @apply ring-[var(--color-focus-ring)];
86
86
  }
87
87
 
88
88
  &:hover {
@@ -97,10 +97,10 @@
97
97
  .dx-focus-ring-group-always:focus .dx-focus-ring-group-indicator,
98
98
  .dx-focus-ring-group-x-always:focus .dx-focus-ring-group-x-indicator,
99
99
  .dx-focus-ring-group-y-always:focus .dx-focus-ring-group-y-indicator {
100
- @apply ring-focus-line ring-offset-focus-offset ring-[var(--color-neutral-focus-indicator)];
100
+ @apply ring-focus-line ring-offset-focus-offset ring-[var(--color-focus-ring-subtle)];
101
101
 
102
102
  &[data-variant='primary'] {
103
- @apply ring-[var(--color-accent-focus-indicator)];
103
+ @apply ring-[var(--color-focus-ring)];
104
104
  }
105
105
 
106
106
  &:hover {
@@ -145,11 +145,11 @@
145
145
 
146
146
  &:focus-visible {
147
147
  &::after {
148
- @apply ring-focus-line ring-offset-focus-offset ring-inset z-[1] ring-[var(--color-neutral-focus-indicator)];
148
+ @apply ring-focus-line ring-offset-focus-offset ring-inset z-[1] ring-[var(--color-focus-ring-subtle)];
149
149
  }
150
150
 
151
151
  &[data-variant='primary']::after {
152
- @apply ring-[var(--color-accent-focus-indicator)];
152
+ @apply ring-[var(--color-focus-ring)];
153
153
  }
154
154
 
155
155
  &:hover {
@@ -178,11 +178,11 @@
178
178
 
179
179
  &:focus {
180
180
  &::after {
181
- @apply ring-focus-line ring-offset-focus-offset ring-inset z-[1] ring-[var(--color-neutral-focus-indicator)];
181
+ @apply ring-focus-line ring-offset-focus-offset ring-inset z-[1] ring-[var(--color-focus-ring-subtle)];
182
182
  }
183
183
 
184
184
  &[data-variant='primary']::after {
185
- @apply ring-[var(--color-accent-focus-indicator)];
185
+ @apply ring-[var(--color-focus-ring)];
186
186
  }
187
187
 
188
188
  &:hover {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Panel — applies bg-{hue}-surface / text-{hue}-surface-text / border-{hue}-border tokens via data-hue attribute or BEM modifier.
2
+ * Panel — applies bg-{hue}-surface / text-{hue}-foreground / border-{hue}-border tokens via data-hue attribute or BEM modifier.
3
3
  * Example: <div className='dx-panel' data-hue='blue'>...</div>
4
4
  * Example: <div className='dx-panel dx-panel--blue'>...</div>
5
5
  */
@@ -7,111 +7,111 @@
7
7
  @layer dx-components {
8
8
  [data-hue='neutral'] .dx-panel,
9
9
  .dx-panel--neutral {
10
- @apply bg-neutral-surface text-neutral-surface-text border-neutral-border;
10
+ @apply bg-neutral-surface text-neutral-foreground border-neutral-border;
11
11
  }
12
12
 
13
13
  [data-hue='red'] .dx-panel,
14
14
  .dx-panel--red {
15
- @apply bg-red-surface text-red-surface-text border-red-border;
15
+ @apply bg-red-surface text-red-foreground border-red-border;
16
16
  }
17
17
 
18
18
  [data-hue='orange'] .dx-panel,
19
19
  .dx-panel--orange {
20
- @apply bg-orange-surface text-orange-surface-text border-orange-border;
20
+ @apply bg-orange-surface text-orange-foreground border-orange-border;
21
21
  }
22
22
 
23
23
  [data-hue='amber'] .dx-panel,
24
24
  .dx-panel--amber {
25
- @apply bg-amber-surface text-amber-surface-text border-amber-border;
25
+ @apply bg-amber-surface text-amber-foreground border-amber-border;
26
26
  }
27
27
 
28
28
  [data-hue='yellow'] .dx-panel,
29
29
  .dx-panel--yellow {
30
- @apply bg-yellow-surface text-yellow-surface-text border-yellow-border;
30
+ @apply bg-yellow-surface text-yellow-foreground border-yellow-border;
31
31
  }
32
32
 
33
33
  [data-hue='lime'] .dx-panel,
34
34
  .dx-panel--lime {
35
- @apply bg-lime-surface text-lime-surface-text border-lime-border;
35
+ @apply bg-lime-surface text-lime-foreground border-lime-border;
36
36
  }
37
37
 
38
38
  [data-hue='green'] .dx-panel,
39
39
  .dx-panel--green {
40
- @apply bg-green-surface text-green-surface-text border-green-border;
40
+ @apply bg-green-surface text-green-foreground border-green-border;
41
41
  }
42
42
 
43
43
  [data-hue='emerald'] .dx-panel,
44
44
  .dx-panel--emerald {
45
- @apply bg-emerald-surface text-emerald-surface-text border-emerald-border;
45
+ @apply bg-emerald-surface text-emerald-foreground border-emerald-border;
46
46
  }
47
47
 
48
48
  [data-hue='teal'] .dx-panel,
49
49
  .dx-panel--teal {
50
- @apply bg-teal-surface text-teal-surface-text border-teal-border;
50
+ @apply bg-teal-surface text-teal-foreground border-teal-border;
51
51
  }
52
52
 
53
53
  [data-hue='cyan'] .dx-panel,
54
54
  .dx-panel--cyan {
55
- @apply bg-cyan-surface text-cyan-surface-text border-cyan-border;
55
+ @apply bg-cyan-surface text-cyan-foreground border-cyan-border;
56
56
  }
57
57
 
58
58
  [data-hue='sky'] .dx-panel,
59
59
  .dx-panel--sky {
60
- @apply bg-sky-surface text-sky-surface-text border-sky-border;
60
+ @apply bg-sky-surface text-sky-foreground border-sky-border;
61
61
  }
62
62
 
63
63
  [data-hue='blue'] .dx-panel,
64
64
  .dx-panel--blue {
65
- @apply bg-blue-surface text-blue-surface-text border-blue-border;
65
+ @apply bg-blue-surface text-blue-foreground border-blue-border;
66
66
  }
67
67
 
68
68
  [data-hue='indigo'] .dx-panel,
69
69
  .dx-panel--indigo {
70
- @apply bg-indigo-surface text-indigo-surface-text border-indigo-border;
70
+ @apply bg-indigo-surface text-indigo-foreground border-indigo-border;
71
71
  }
72
72
 
73
73
  [data-hue='violet'] .dx-panel,
74
74
  .dx-panel--violet {
75
- @apply bg-violet-surface text-violet-surface-text border-violet-border;
75
+ @apply bg-violet-surface text-violet-foreground border-violet-border;
76
76
  }
77
77
 
78
78
  [data-hue='purple'] .dx-panel,
79
79
  .dx-panel--purple {
80
- @apply bg-purple-surface text-purple-surface-text border-purple-border;
80
+ @apply bg-purple-surface text-purple-foreground border-purple-border;
81
81
  }
82
82
 
83
83
  [data-hue='fuchsia'] .dx-panel,
84
84
  .dx-panel--fuchsia {
85
- @apply bg-fuchsia-surface text-fuchsia-surface-text border-fuchsia-border;
85
+ @apply bg-fuchsia-surface text-fuchsia-foreground border-fuchsia-border;
86
86
  }
87
87
 
88
88
  [data-hue='pink'] .dx-panel,
89
89
  .dx-panel--pink {
90
- @apply bg-pink-surface text-pink-surface-text border-pink-border;
90
+ @apply bg-pink-surface text-pink-foreground border-pink-border;
91
91
  }
92
92
 
93
93
  [data-hue='rose'] .dx-panel,
94
94
  .dx-panel--rose {
95
- @apply bg-rose-surface text-rose-surface-text border-rose-border;
95
+ @apply bg-rose-surface text-rose-foreground border-rose-border;
96
96
  }
97
97
 
98
98
  [data-hue='info'] .dx-panel,
99
99
  .dx-panel--info {
100
- @apply bg-info-surface text-info-surface-text border-info-border;
100
+ @apply bg-info-surface text-info-foreground border-info-border;
101
101
  }
102
102
 
103
103
  [data-hue='success'] .dx-panel,
104
104
  .dx-panel--success {
105
- @apply bg-success-surface text-success-surface-text border-success-border;
105
+ @apply bg-success-surface text-success-foreground border-success-border;
106
106
  }
107
107
 
108
108
  [data-hue='warning'] .dx-panel,
109
109
  .dx-panel--warning {
110
- @apply bg-warning-surface text-warning-surface-text border-warning-border;
110
+ @apply bg-warning-surface text-warning-foreground border-warning-border;
111
111
  }
112
112
 
113
113
  [data-hue='error'] .dx-panel,
114
114
  .dx-panel--error {
115
- @apply bg-error-surface text-error-surface-text border-error-border;
115
+ @apply bg-error-surface text-error-foreground border-error-border;
116
116
  }
117
117
  }
@@ -1,35 +1,76 @@
1
1
  /**
2
- * Selected / Highlighted state utilities.
2
+ * Selected / Current / Highlighted state utilities.
3
3
  *
4
4
  * See `./selected.md` for the ARIA pairing grammar — every class below
5
5
  * fires off a specific attribute and silently does nothing without it.
6
6
  */
7
7
 
8
8
  @layer dx-components {
9
- /* Pure visual affordance, no ARIA pair. Combine with dx-selected or dx-current. */
9
+ /*
10
+ * Pure visual affordance, no ARIA pair. Combine with dx-selected or dx-current.
11
+ *
12
+ * Picks the hover variant matching the element's underlying state:
13
+ * - neither aria-selected nor aria-current → hover-surface
14
+ * - aria-selected="true" → selected-surface-hover
15
+ * - aria-current="true" → current-surface-hover (wins if both)
16
+ *
17
+ * Higher-specificity rules (attribute selectors) override the plain :hover rule,
18
+ * and `aria-current` is listed last so it beats `aria-selected` at equal specificity.
19
+ */
10
20
  .dx-hover {
11
- @apply cursor-pointer hover:bg-highlight-surface! hover:text-highlight-surface-text!;
21
+ @apply cursor-pointer
22
+ hover:bg-hover-surface! hover:text-hover-foreground!
23
+ hover:aria-selected:bg-selected-surface-hover! hover:aria-selected:text-selected-foreground!
24
+ hover:aria-[current=true]:bg-current-surface-hover! hover:aria-[current=true]:text-current-foreground!;
25
+ }
26
+ .dx-hover-row {
27
+ @apply group-hover/row:bg-hover-surface! group-hover/row:text-hover-foreground!
28
+ group-hover/row:group-aria-selected/row:bg-selected-surface-hover!
29
+ group-hover/row:group-aria-selected/row:text-selected-foreground!
30
+ group-hover/row:group-aria-[current=true]/row:bg-current-surface-hover!
31
+ group-hover/row:group-aria-[current=true]/row:text-current-foreground!;
12
32
  }
13
33
 
14
- /* Pairs with Radix-managed `data-highlighted`. Don't set the attribute manually. */
15
- .dx-highlighted {
16
- @apply data-[highlighted]:bg-highlight-surface
17
- data-[highlighted]:text-highlight-surface-text
18
- hover:data-[highlighted]:bg-highlight-surface-hover;
34
+ /*
35
+ * Pairs with `aria-selected`. Use for listbox/option selection (master/detail).
36
+ * `!` is required: these utilities live in the `dx-components` layer, but
37
+ * background utilities like `bg-card-surface` live in Tailwind's
38
+ * `utilities` layer (declared later in the cascade), so without
39
+ * `!important` the card background would override the state colour.
40
+ *
41
+ * NOTE: Declared before `.dx-current` so that when an element has both
42
+ * `aria-selected="true"` and `aria-current="true"`, `dx-current` wins at
43
+ * equal specificity (consistent with how `dx-hover` resolves the same
44
+ * conflict).
45
+ */
46
+ .dx-selected {
47
+ @apply aria-selected:bg-selected-surface! aria-selected:text-selected-foreground!
48
+ aria-selected:font-semibold aria-selected:tracking-normal
49
+ transition-[color,font-variation-settings,letter-spacing];
19
50
  }
20
51
 
21
- /* Pairs with `aria-current="true|page|…"`. Use for "you are here" navigation. */
52
+ /*
53
+ * Pairs with `aria-current="true|page|…"`. Use for "you are here" navigation.
54
+ *
55
+ * The ring uses the subdued focus indicator (neutral) rather than the
56
+ * accent blue — `dx-current` marks position, not focus, so a saturated
57
+ * ring would compete with the actual keyboard focus ring.
58
+ */
22
59
  .dx-current {
23
60
  @apply dx-ring-pseudo
24
- aria-[current=true]:bg-highlight-surface aria-[current=true]:text-highlight-surface-text
25
- aria-[current=true]:after:ring-active-separator!;
61
+ aria-[current=true]:bg-current-surface! aria-[current=true]:text-current-foreground!
62
+ aria-[current=true]:after:ring-focus-ring-subtle!;
63
+ }
64
+ .dx-current-row {
65
+ @apply group-aria-[current=true]/row:bg-current-surface! group-aria-[current=true]/row:text-current-foreground!;
26
66
  }
27
67
 
28
- /* Pairs with `aria-selected`. Use for listbox/option selection (master/detail). */
29
- .dx-selected {
30
- @apply aria-selected:bg-selected-surface
31
- aria-selected:text-selected-surface-text hover:aria-selected:text-selected-surface-text
32
- aria-selected:font-semibold aria-selected:tracking-normal
33
- transition-[color,font-variation-settings,letter-spacing];
68
+ /*
69
+ * Pairs with Radix-managed `data-highlighted`. Don't set the attribute manually.
70
+ */
71
+ .dx-highlighted {
72
+ @apply data-[highlighted]:bg-current-surface
73
+ data-[highlighted]:text-current-foreground
74
+ hover:data-[highlighted]:bg-current-surface-hover;
34
75
  }
35
76
  }
@@ -4,22 +4,22 @@
4
4
 
5
5
  @layer dx-components {
6
6
  .dx-base-surface {
7
- @apply bg-base-surface text-base-surface-text;
7
+ @apply bg-base-surface text-base-foreground;
8
8
  --surface-bg: var(--color-base-surface);
9
9
  }
10
10
 
11
11
  .dx-sidebar-surface {
12
- @apply bg-sidebar-surface text-base-surface-text;
12
+ @apply bg-sidebar-surface text-base-foreground;
13
13
  --surface-bg: var(--color-sidebar-surface);
14
14
  }
15
15
 
16
16
  .dx-modal-surface {
17
- @apply bg-modal-surface text-base-surface-text backdrop-blur-md;
17
+ @apply bg-modal-surface text-base-foreground backdrop-blur-md;
18
18
  --surface-bg: var(--color-modal-surface);
19
19
  }
20
20
 
21
21
  .dx-attention-surface {
22
- @apply bg-attention-surface text-base-surface-text;
22
+ @apply bg-attention-surface text-base-foreground;
23
23
  --surface-bg: var(--color-attention-surface);
24
24
  }
25
25
  }