@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.
- package/LICENSE +102 -5
- package/README.md +1 -1
- package/dist/lib/browser/index.mjs +29 -31
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +29 -31
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/plugin/node-cjs/main.css +85 -79
- package/dist/plugin/node-cjs/main.css.map +2 -2
- package/dist/plugin/node-cjs/meta.json +1 -1
- package/dist/plugin/node-esm/main.css +85 -79
- package/dist/plugin/node-esm/main.css.map +2 -2
- package/dist/plugin/node-esm/meta.json +1 -1
- package/dist/types/src/defs.d.ts +1 -1
- package/dist/types/src/defs.d.ts.map +1 -1
- package/dist/types/src/fragments/hover.d.ts +0 -1
- package/dist/types/src/fragments/hover.d.ts.map +1 -1
- package/dist/types/src/theme/components/button.d.ts +2 -2
- package/dist/types/src/theme/components/button.d.ts.map +1 -1
- package/dist/types/src/util/hash-styles.d.ts +1 -1
- package/dist/types/src/util/hash-styles.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -9
- package/src/Theme.stories.tsx +5 -5
- package/src/css/DESIGN_SYSTEM.md +159 -0
- package/src/css/base/base.css +2 -2
- package/src/css/components/button.css +3 -3
- package/src/css/components/checkbox.css +1 -1
- package/src/css/components/focus.css +12 -12
- package/src/css/components/panel.css +23 -23
- package/src/css/components/selected.css +58 -17
- package/src/css/components/surface.css +4 -4
- package/src/css/components/tag.css +23 -23
- package/src/css/theme/semantic.css +36 -40
- package/src/css/theme/spacing.css +1 -1
- package/src/css/theme/styles.css +22 -22
- package/src/defs.ts +1 -1
- package/src/fragments/AUDIT.md +0 -2
- package/src/fragments/hover.ts +0 -2
- package/src/main.css +3 -3
- package/src/theme/components/button.ts +2 -2
- package/src/theme/components/focus.ts +2 -2
- package/src/theme/components/icon-button.ts +1 -1
- package/src/theme/components/input.ts +5 -5
- package/src/theme/components/message.ts +1 -1
- package/src/theme/components/select.ts +1 -1
- package/src/theme/components/tooltip.ts +1 -1
- 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.
|
|
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": "
|
|
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.
|
|
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.
|
|
54
|
-
"@dxos/node-std": "0.8.4-main.
|
|
55
|
-
"@dxos/util": "0.8.4-main.
|
|
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.
|
|
62
|
-
"@dxos/ui-types": "0.8.4-main.
|
|
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"
|
package/src/Theme.stories.tsx
CHANGED
|
@@ -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-
|
|
166
|
+
{ className: 'bg-current-surface', label: 'current' },
|
|
167
167
|
{ className: 'bg-hover-surface', label: 'hover' },
|
|
168
|
-
{ className: 'bg-inverse-surface text-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.
|
package/src/css/base/base.css
CHANGED
|
@@ -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-
|
|
38
|
+
color: var(--color-base-foreground);
|
|
39
39
|
--surface-bg: var(--color-base-surface);
|
|
40
|
-
--
|
|
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-[
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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}-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
-
/*
|
|
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
|
|
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
|
-
/*
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
/*
|
|
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-
|
|
25
|
-
aria-[current=true]:after:ring-
|
|
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
|
-
/*
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
22
|
+
@apply bg-attention-surface text-base-foreground;
|
|
23
23
|
--surface-bg: var(--color-attention-surface);
|
|
24
24
|
}
|
|
25
25
|
}
|