@dxos/ui-theme 0.10.0 → 0.11.1
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/lib/browser/index.mjs +0 -62
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +0 -62
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/plugin/node-cjs/main.css +311 -189
- package/dist/plugin/node-cjs/main.css.map +3 -3
- package/dist/plugin/node-cjs/meta.json +1 -1
- package/dist/plugin/node-cjs/plugins/ThemePlugin.cjs +2 -1
- package/dist/plugin/node-cjs/plugins/ThemePlugin.cjs.map +3 -3
- package/dist/plugin/node-esm/main.css +311 -189
- package/dist/plugin/node-esm/main.css.map +3 -3
- package/dist/plugin/node-esm/meta.json +1 -1
- package/dist/plugin/node-esm/plugins/ThemePlugin.mjs +2 -1
- package/dist/plugin/node-esm/plugins/ThemePlugin.mjs.map +3 -3
- package/dist/types/src/Theme.stories.d.ts.map +1 -1
- package/dist/types/src/defs.d.ts +0 -5
- package/dist/types/src/defs.d.ts.map +1 -1
- package/dist/types/src/fragments/hover.d.ts +0 -2
- package/dist/types/src/fragments/hover.d.ts.map +1 -1
- package/dist/types/src/fragments/index.d.ts +0 -1
- package/dist/types/src/fragments/index.d.ts.map +1 -1
- package/dist/types/src/plugins/ThemePlugin.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +11 -6
- package/src/Theme.stories.tsx +3 -1
- package/src/css/DESIGN_SYSTEM.md +89 -51
- package/src/css/base/base.css +39 -0
- package/src/css/components/button.css +21 -16
- package/src/css/components/callout.css +140 -0
- package/src/css/components/input.css +36 -0
- package/src/css/components/state.css +1 -11
- package/src/css/components/state.md +1 -1
- package/src/css/components/surface.css +165 -58
- package/src/css/components/tag.css +13 -1
- package/src/css/integrations/codemirror.css +15 -0
- package/src/css/layout/main.css +26 -2
- package/src/css/layout/native.css +1 -0
- package/src/css/theme/roles.css +92 -0
- package/src/css/theme/spacing.css +63 -54
- package/src/css/theme/surfaces.css +215 -0
- package/src/css/theme/text.css +6 -2
- package/src/css/utilities.css +13 -9
- package/src/defs.ts +0 -25
- package/src/fragments/hover.ts +0 -3
- package/src/fragments/index.ts +0 -1
- package/src/main.css +8 -10
- package/src/plugins/ThemePlugin.ts +50 -40
- package/src/plugins/main.css +1 -1
- package/src/tokens.css +22 -0
- package/dist/types/src/fragments/density.d.ts +0 -4
- package/dist/types/src/fragments/density.d.ts.map +0 -1
- package/src/css/components/panel.css +0 -117
- package/src/css/theme/semantic.css +0 -244
- package/src/fragments/AUDIT.md +0 -55
- package/src/fragments/density.ts +0 -43
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/ui-theme",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.1",
|
|
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",
|
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
"types": "./dist/types/src/index.d.ts",
|
|
21
21
|
"default": "./dist/lib/browser/index.mjs"
|
|
22
22
|
},
|
|
23
|
+
"./tokens.css": {
|
|
24
|
+
"style": "./src/tokens.css",
|
|
25
|
+
"default": "./src/tokens.css"
|
|
26
|
+
},
|
|
23
27
|
"./plugin": {
|
|
24
28
|
"source": "./src/plugins/ThemePlugin.ts",
|
|
25
29
|
"types": "./dist/types/src/plugins/ThemePlugin.d.ts",
|
|
@@ -34,6 +38,7 @@
|
|
|
34
38
|
"dependencies": {
|
|
35
39
|
"@fontsource-variable/inter": "5.2.8",
|
|
36
40
|
"@fontsource-variable/jetbrains-mono": "5.0.21",
|
|
41
|
+
"@fontsource-variable/nunito": "5.2.7",
|
|
37
42
|
"@fontsource/poiret-one": "^5.0.20",
|
|
38
43
|
"@radix-ui/react-slot": "1.1.2",
|
|
39
44
|
"@tailwindcss/forms": "^0.5.9",
|
|
@@ -51,16 +56,16 @@
|
|
|
51
56
|
"tailwind-variants": "^3.2.2",
|
|
52
57
|
"tailwindcss": "^4.3.0",
|
|
53
58
|
"tailwindcss-radix": "^4.0.2",
|
|
54
|
-
"@dxos/log": "0.
|
|
55
|
-
"@dxos/node-std": "0.
|
|
56
|
-
"@dxos/util": "0.
|
|
59
|
+
"@dxos/log": "0.11.1",
|
|
60
|
+
"@dxos/node-std": "0.11.1",
|
|
61
|
+
"@dxos/util": "0.11.1"
|
|
57
62
|
},
|
|
58
63
|
"devDependencies": {
|
|
59
64
|
"@types/lodash.merge": "^4.6.6",
|
|
60
65
|
"@types/postcss-import": "^14.0.3",
|
|
61
66
|
"esbuild": "0.28.1",
|
|
62
|
-
"vite": "^8.
|
|
63
|
-
"@dxos/ui-types": "0.
|
|
67
|
+
"vite": "^8.1.4",
|
|
68
|
+
"@dxos/ui-types": "0.11.1"
|
|
64
69
|
},
|
|
65
70
|
"peerDependencies": {
|
|
66
71
|
"react": "~19.2.7"
|
package/src/Theme.stories.tsx
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
import { type Meta } from '@storybook/react-vite';
|
|
6
6
|
import React, { useLayoutEffect, useRef, useState } from 'react';
|
|
7
7
|
|
|
8
|
-
import { hues
|
|
8
|
+
import { hues } from '@dxos/ui-types';
|
|
9
|
+
|
|
10
|
+
import { hueShades } from './defs';
|
|
9
11
|
import { mx } from './util';
|
|
10
12
|
|
|
11
13
|
// prettier-ignore
|
package/src/css/DESIGN_SYSTEM.md
CHANGED
|
@@ -6,11 +6,11 @@ This document describes how color tokens are organized in `ui-theme`, the naming
|
|
|
6
6
|
|
|
7
7
|
Three layers, each consuming the one below:
|
|
8
8
|
|
|
9
|
-
| Tier | File
|
|
10
|
-
| ----------- |
|
|
11
|
-
| 1. Scale | [`theme/palette.css`](./theme/palette.css)
|
|
12
|
-
| 2. Hue role | [`theme/styles.css`](./theme/styles.css)
|
|
13
|
-
| 3. Semantic | [`theme/
|
|
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 for every Tailwind hue plus `neutral`. Six roles each: `bg`, `bg-hover`, `surface`, `fg`, `text`, `border`. Light/dark resolved via `light-dark()`. | `--color-red-surface`, `--color-neutral-border` |
|
|
13
|
+
| 3. Semantic | [`theme/surfaces.css`](./theme/surfaces.css) + [`theme/roles.css`](./theme/roles.css) | Named UI surfaces/aspects, and the non-surface roles. 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
14
|
|
|
15
15
|
A consumer should reach for the highest tier that fits. Use `bg-card-surface`, not `bg-neutral-825`. Use `text-error-text`, not `text-rose-700`.
|
|
16
16
|
|
|
@@ -38,76 +38,114 @@ Token names follow `--color-{name}-{part}[-{state}]`:
|
|
|
38
38
|
## Surfaces
|
|
39
39
|
|
|
40
40
|
Surfaces are governed by a strict elevation ladder: **lighter = higher = closer to the viewer** in dark
|
|
41
|
-
mode; inverted toward white in light mode.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
41
|
+
mode; inverted toward white in light mode. Chrome sits **below** the document canvas and content
|
|
42
|
+
surfaces sit **above** it, so the app reads as paper on a desk rather than paper in a well.
|
|
43
|
+
|
|
44
|
+
There are exactly six **levels**. Every named surface token is an alias of exactly one of them —
|
|
45
|
+
never set a surface to a raw scale value. This table mirrors the assignments in `surfaces.css`,
|
|
46
|
+
which is the source of truth; update both together.
|
|
47
|
+
|
|
48
|
+
| Level | Dark | Light | Named surfaces |
|
|
49
|
+
| --------- | ------- | ------- | ---------------------------------------------------------- |
|
|
50
|
+
| `sunken` | `n-950` | `n-300` | `deck-surface`, scrim base |
|
|
51
|
+
| `chrome` | `n-925` | `n-250` | `sidebar-surface`, `header-surface`, `l0/l1/r0/r1-surface` |
|
|
52
|
+
| `base` | `n-900` | `n-200` | `base-surface`, `attention-surface` |
|
|
53
|
+
| `raised` | `n-850` | `n-125` | `card-surface` |
|
|
54
|
+
| `overlay` | `n-800` | `n-75` | `modal-surface` (dialogs, sheets, drawers) |
|
|
55
|
+
| `popup` | `n-775` | `n-50` | `popover-surface` (menus, popovers, toasts, tooltips) |
|
|
56
|
+
|
|
57
|
+
The primitive `--dx-surface-{sunken…popup}` is defined in `surfaces.css` using `light-dark()`. Raw
|
|
58
|
+
scale values (`n-*`) are in `palette.css` — the table above is for human reference only.
|
|
59
|
+
|
|
60
|
+
### Aspects — derived, not levels
|
|
61
|
+
|
|
62
|
+
Toolbars, groups and inputs are **not** levels. They are _aspects_: a step off whichever surface
|
|
63
|
+
hosts them, computed with relative oklch from `--surface-bg` and stepped by `--dx-lift` (`+1` dark,
|
|
64
|
+
`-1` light, set in `base.css`). That is what makes nesting work — a toolbar in a card and a toolbar
|
|
65
|
+
on the canvas each read as a bar on their own host instead of jumping to one global tone.
|
|
66
|
+
|
|
67
|
+
| Aspect | Offset | Tokens |
|
|
68
|
+
| ------------- | ------- | ------------------------------------------------- |
|
|
69
|
+
| bar | `0.025` | `toolbar-surface` |
|
|
70
|
+
| well | `0.05` | `group-surface`, `input-surface`, `focus-surface` |
|
|
71
|
+
| hover-subtle | `0.02` | `hover-surface-subtle` |
|
|
72
|
+
| hover | `0.08` | `hover-surface`, `group-alt-surface` |
|
|
73
|
+
| current | `0.10` | `current-surface`, `selected-surface` |
|
|
74
|
+
| current-hover | `0.12` | `current-surface-hover`, `selected-surface-hover` |
|
|
75
|
+
|
|
76
|
+
**Entering a zone.** A zone paints the level _and_ publishes `--surface-bg`, from which the aspects
|
|
77
|
+
re-derive for that subtree. Use `data-surface="<level>"` or the equivalent `dx-*-surface` class — a
|
|
78
|
+
bare `bg-*-surface` utility paints the colour but publishes nothing, so every aspect inside it
|
|
79
|
+
collapses onto the base-surface fallback.
|
|
80
|
+
|
|
81
|
+
Two mechanical rules govern the derivation blocks in `components/surface.css`:
|
|
82
|
+
|
|
83
|
+
- **Aliases must be re-declared per zone.** A `--color-x: var(--color-y)` alias substitutes at the
|
|
84
|
+
scope that _declares_ it, so an alias written only at `:root` freezes to the root value.
|
|
85
|
+
- **Bar and well re-derive only in level zones.** An aspect zone defines its own `--surface-bg`
|
|
86
|
+
_from_ those tokens, so re-deriving them there would be circular.
|
|
58
87
|
|
|
59
88
|
### Visual hierarchy (dark)
|
|
60
89
|
|
|
61
90
|
```text
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
rail/L0 n-900
|
|
69
|
-
void n-950 ↓ lowest
|
|
91
|
+
popup n-775 ↑ highest / closest to viewer
|
|
92
|
+
overlay n-800
|
|
93
|
+
raised / card n-850
|
|
94
|
+
base / canvas n-900
|
|
95
|
+
chrome/sidebar n-925
|
|
96
|
+
sunken / deck n-950 ↓ lowest
|
|
70
97
|
```
|
|
71
98
|
|
|
72
|
-
Each surface that hosts text declares a matching `*-fg` (defaulting to `n-950 / n-
|
|
99
|
+
Each surface that hosts text declares a matching `*-fg` (defaulting to `n-950 / n-150`).
|
|
73
100
|
|
|
74
101
|
## Elevation primitive
|
|
75
102
|
|
|
76
|
-
The `--dx-
|
|
103
|
+
The `--dx-surface-*` custom properties in `surfaces.css` are the single source of truth for the
|
|
77
104
|
surface ladder. They are private (`--dx-*` prefix) — never use them directly in component CSS; use the
|
|
78
105
|
named surface tokens (`bg-card-surface`, `dx-modal-surface`, etc.) instead.
|
|
79
106
|
|
|
80
107
|
When adding a new surface:
|
|
81
108
|
|
|
82
|
-
1. Decide
|
|
83
|
-
|
|
109
|
+
1. Decide whether it is a **level** or an **aspect**. If it should shift with whatever hosts it
|
|
110
|
+
(a bar, a well, a state), it is an aspect — add it to the aspect block, not the ladder.
|
|
111
|
+
2. For a level, add `--color-<name>-surface: var(--dx-surface-<level>);` in `surfaces.css`.
|
|
84
112
|
3. Add a matching `--color-<name>-fg` if text/icons sit on it.
|
|
85
|
-
4.
|
|
113
|
+
4. Add the zone to `surface.css` so it publishes `--surface-bg` and re-derives the aspects.
|
|
86
114
|
|
|
87
115
|
## State tokens (rationalized)
|
|
88
116
|
|
|
89
117
|
The system has three orthogonal states. Pick by what the ARIA / markup is saying.
|
|
90
118
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
|
98
|
-
|
|
|
99
|
-
|
|
|
100
|
-
|
|
|
119
|
+
State surfaces are **derived from the host surface**, not fixed scale values: each token is a
|
|
120
|
+
relative-oklch lightness offset from `--surface-bg` (published by the enclosing `dx-*-surface` zone
|
|
121
|
+
class — see `components/surface.css`), darker in light mode and lighter in dark mode, so a highlight
|
|
122
|
+
stays visible at any elevation. Offsets (L): hover-subtle ∓0.02, hover ∓0.08, current ∓0.10,
|
|
123
|
+
current-hover ∓0.12; `selected-*` aliases `current-*`.
|
|
124
|
+
|
|
125
|
+
| State | Token | When |
|
|
126
|
+
| -------------------------- | ------------------------ | ---------------------------------------------------------------- |
|
|
127
|
+
| Active item, one-of-N | `current-surface` | `aria-current=true` (nav cursor, current row, current path) |
|
|
128
|
+
| Hovering on current item | `current-surface-hover` | pointer-over on a `current` element |
|
|
129
|
+
| Text on a current surface | `current-fg` | text/icon color paired with `current-surface` |
|
|
130
|
+
| Selected / checked | `selected-surface` | `aria-selected=true` (multi-select, listbox option, checked row) |
|
|
131
|
+
| Hovering on selected | `selected-surface-hover` | pointer-over on a `selected` element |
|
|
132
|
+
| Text on a selected surface | `selected-fg` | text/icon color paired with `selected-surface` |
|
|
133
|
+
| Transient pointer-over | `hover-surface` | `:hover`, Radix `data-highlighted` (keyboard cursor in menus) |
|
|
134
|
+
| Subtle region hover | `hover-surface-subtle` | large targets (rows, tiles) via `dx-hover` |
|
|
135
|
+
| Text on a transient hover | `hover-fg` | text/icon color paired with `hover-surface` |
|
|
101
136
|
|
|
102
137
|
**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.
|
|
103
138
|
|
|
104
139
|
### Visual hierarchy (state, dark)
|
|
105
140
|
|
|
141
|
+
Relative to the host surface `S` (= `--surface-bg`), in oklch lightness:
|
|
142
|
+
|
|
106
143
|
```text
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
144
|
+
S resting
|
|
145
|
+
S + 0.02 subtle region hover (hover-surface-subtle)
|
|
146
|
+
S + 0.08 transient pointer-over (hover-surface)
|
|
147
|
+
S + 0.10 "I am the active one" (current-surface / selected-surface)
|
|
148
|
+
S + 0.12 hovering the active one (current-surface-hover)
|
|
111
149
|
```
|
|
112
150
|
|
|
113
151
|
## Consolidation: tokens that go away
|
|
@@ -180,8 +218,8 @@ Each provides `bg`, `bg-hover`, `surface`, `fg`, `text`, `border`.
|
|
|
180
218
|
|
|
181
219
|
## Adding a new token
|
|
182
220
|
|
|
183
|
-
1. Does an existing semantic token already cover it? For a new named surface, check the elevation ladder first — the new surface probably fits an existing level and should alias `--dx-
|
|
184
|
-
2. Does it represent a new named surface, state, or status? Add it to `
|
|
221
|
+
1. Does an existing semantic token already cover it? For a new named surface, check the elevation ladder first — the new surface probably fits an existing level and should alias `--dx-surface-<level>` rather than a raw scale value.
|
|
222
|
+
2. Does it represent a new named surface, state, or status? Add it to `surfaces.css` (surfaces/aspects) or `roles.css` (everything else), referencing scale or hue-role tokens — never raw hex.
|
|
185
223
|
3. Follow the suffix order: `{name}-{part}[-{state}]`.
|
|
186
224
|
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).
|
|
187
225
|
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
|
@@ -5,6 +5,36 @@
|
|
|
5
5
|
@layer dx-base {
|
|
6
6
|
:root {
|
|
7
7
|
color-scheme: light;
|
|
8
|
+
/* Direction an aspect moves off its host surface: away from the canvas in either theme.
|
|
9
|
+
* Aspects multiply their offset by this instead of branching on light-dark(), which resolves
|
|
10
|
+
* unreliably when nested inside a relative-color expression. */
|
|
11
|
+
--dx-lift: -1;
|
|
12
|
+
/*
|
|
13
|
+
* Light attenuation.
|
|
14
|
+
*
|
|
15
|
+
* Lightness is not perceptually symmetric: subtracting 0.10 L from a near-white surface reads
|
|
16
|
+
* far heavier than adding 0.10 to a near-black one. Every aspect family therefore multiplies
|
|
17
|
+
* its offset by a factor declared here — dark sets them all to 1, so the dark appearance is the
|
|
18
|
+
* reference and light is tuned against it. One family, one factor, one place.
|
|
19
|
+
*
|
|
20
|
+
* Family Offsets (dark) Light Light dL on the canvas
|
|
21
|
+
* state .02 / .08 / .10 / .12 0.5 hover .04, selected .05
|
|
22
|
+
* well .05 0.5 input fill .025
|
|
23
|
+
* separator .089 / .115 / .064 0.75 subdued .067, input .086
|
|
24
|
+
* sep-line .166 0.45 .075 — near the floor; subdued is .067
|
|
25
|
+
* bar .025 1 toolbars read correctly as-is
|
|
26
|
+
* placeholder .30 1 ink, not a surface; wants the contrast
|
|
27
|
+
* scrollbar .23 / .30 / .34 1 was invisible in light before deriving
|
|
28
|
+
*
|
|
29
|
+
* Adjust a family by changing its factor, not by editing offsets — those are the dark contract.
|
|
30
|
+
*/
|
|
31
|
+
--dx-attenuate-state: 0.5;
|
|
32
|
+
--dx-attenuate-well: 0.5;
|
|
33
|
+
--dx-attenuate-separator: 0.75;
|
|
34
|
+
--dx-attenuate-separator-line: 0.45;
|
|
35
|
+
--dx-attenuate-bar: 1;
|
|
36
|
+
--dx-attenuate-placeholder: 1;
|
|
37
|
+
--dx-attenuate-scrollbar: 1;
|
|
8
38
|
touch-action: pan-x pan-y;
|
|
9
39
|
font-synthesis: none;
|
|
10
40
|
font-variation-settings:
|
|
@@ -17,6 +47,15 @@
|
|
|
17
47
|
|
|
18
48
|
.dark {
|
|
19
49
|
color-scheme: dark;
|
|
50
|
+
--dx-lift: 1;
|
|
51
|
+
/* Dark is the reference: every family runs at full strength. */
|
|
52
|
+
--dx-attenuate-state: 1;
|
|
53
|
+
--dx-attenuate-well: 1;
|
|
54
|
+
--dx-attenuate-separator: 1;
|
|
55
|
+
--dx-attenuate-separator-line: 1;
|
|
56
|
+
--dx-attenuate-bar: 1;
|
|
57
|
+
--dx-attenuate-placeholder: 1;
|
|
58
|
+
--dx-attenuate-scrollbar: 1;
|
|
20
59
|
}
|
|
21
60
|
|
|
22
61
|
button {
|
|
@@ -10,12 +10,16 @@
|
|
|
10
10
|
|
|
11
11
|
/* Base styles */
|
|
12
12
|
.dx-button {
|
|
13
|
-
@apply shrink-0 inline-flex select-none items-center justify-center overflow-hidden
|
|
13
|
+
@apply shrink-0 inline-flex select-none items-center justify-center overflow-hidden;
|
|
14
|
+
/* Geometry comes from the density knobs, not from utilities in the class list: `utilities` is
|
|
15
|
+
* the last cascade layer, so any `px-*`/`h-*` a theme emits would silently beat a rule here. */
|
|
16
|
+
min-block-size: var(--dx-control);
|
|
17
|
+
padding-inline: var(--dx-control-pad);
|
|
14
18
|
@apply font-medium transition-colors duration-100 ease-linear bg-input-bg;
|
|
15
19
|
/* The default variant inherits ambient valence colors when rendered inside a valence surface
|
|
16
20
|
* (e.g. Message.Root, which sets --dx-valence-*); otherwise it falls back to the base input styling. */
|
|
17
21
|
&[data-variant='default'] {
|
|
18
|
-
color: var(--dx-valence-text, inherit);
|
|
22
|
+
/* color: var(--dx-valence-text, inherit); */
|
|
19
23
|
background: var(--dx-valence-bg, var(--color-input-bg));
|
|
20
24
|
}
|
|
21
25
|
/* Toggle / tab group: the selected item reads as standard text on a surface-relative fill (selected-surface
|
|
@@ -64,8 +68,17 @@
|
|
|
64
68
|
@apply bg-hover-surface;
|
|
65
69
|
}
|
|
66
70
|
|
|
71
|
+
/*
|
|
72
|
+
* Light moves the button's OWN fill: the host-derived hover sits above the fill here, so it
|
|
73
|
+
* lightened on hover and landed on `--color-selected-surface`. Dark keeps the host tint — the
|
|
74
|
+
* dark ladder puts it clear of the fill already, and the token cannot carry it: declared at
|
|
75
|
+
* `:root`, `var(--color-hover-surface)` would freeze there and stop tracking the zone.
|
|
76
|
+
*/
|
|
67
77
|
&[data-variant='default']:hover {
|
|
68
78
|
color: var(--dx-valence-text);
|
|
79
|
+
background-color: var(--dx-valence-bg-hover, var(--color-input-bg-hover));
|
|
80
|
+
}
|
|
81
|
+
.dark &[data-variant='default']:hover {
|
|
69
82
|
background-color: var(--dx-valence-bg-hover, var(--color-hover-surface));
|
|
70
83
|
}
|
|
71
84
|
|
|
@@ -116,21 +129,13 @@
|
|
|
116
129
|
.dx-button:not([data-props~='wrap']) {
|
|
117
130
|
@apply truncate;
|
|
118
131
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
132
|
+
/* `data-density` is handled by the shared density rule in theme/spacing.css, which sets
|
|
133
|
+
* --dx-control / --dx-control-pad; only the type-scale tweak is button-specific. */
|
|
122
134
|
.dx-button[data-density='sm'] {
|
|
123
|
-
@apply
|
|
135
|
+
@apply text-xs;
|
|
124
136
|
}
|
|
125
|
-
.dx-button
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
.dx-button[data-density='xs'].aspect-square {
|
|
129
|
-
@apply size-6 px-0;
|
|
130
|
-
}
|
|
131
|
-
@media (pointer: fine) {
|
|
132
|
-
.dx-button[data-density='md'] {
|
|
133
|
-
@apply min-h-[2rem] px-2.5;
|
|
134
|
-
}
|
|
137
|
+
.dx-button.aspect-square {
|
|
138
|
+
padding-inline: 0;
|
|
139
|
+
inline-size: var(--dx-control);
|
|
135
140
|
}
|
|
136
141
|
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Callout — hue-tinted panel: applies bg-{hue}-surface / border-{hue}-border / text-{hue}-fg via a
|
|
3
|
+
* data-hue attribute (on the element itself or an ancestor) or a BEM modifier.
|
|
4
|
+
* Example: <div className='dx-callout' data-hue='blue'>...</div>
|
|
5
|
+
* Example: <div className='dx-callout dx-callout--blue'>...</div>
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
@layer dx-components {
|
|
9
|
+
.dx-callout[data-hue='neutral'],
|
|
10
|
+
:where([data-hue='neutral']) .dx-callout,
|
|
11
|
+
.dx-callout--neutral {
|
|
12
|
+
@apply bg-neutral-surface border-neutral-border text-neutral-fg;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.dx-callout[data-hue='red'],
|
|
16
|
+
:where([data-hue='red']) .dx-callout,
|
|
17
|
+
.dx-callout--red {
|
|
18
|
+
@apply bg-red-surface border-red-border text-red-fg;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.dx-callout[data-hue='orange'],
|
|
22
|
+
:where([data-hue='orange']) .dx-callout,
|
|
23
|
+
.dx-callout--orange {
|
|
24
|
+
@apply bg-orange-surface border-orange-border text-orange-fg;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.dx-callout[data-hue='amber'],
|
|
28
|
+
:where([data-hue='amber']) .dx-callout,
|
|
29
|
+
.dx-callout--amber {
|
|
30
|
+
@apply bg-amber-surface border-amber-border text-amber-fg;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.dx-callout[data-hue='yellow'],
|
|
34
|
+
:where([data-hue='yellow']) .dx-callout,
|
|
35
|
+
.dx-callout--yellow {
|
|
36
|
+
@apply bg-yellow-surface border-yellow-border text-yellow-fg;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.dx-callout[data-hue='lime'],
|
|
40
|
+
:where([data-hue='lime']) .dx-callout,
|
|
41
|
+
.dx-callout--lime {
|
|
42
|
+
@apply bg-lime-surface border-lime-border text-lime-fg;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.dx-callout[data-hue='green'],
|
|
46
|
+
:where([data-hue='green']) .dx-callout,
|
|
47
|
+
.dx-callout--green {
|
|
48
|
+
@apply bg-green-surface border-green-border text-green-fg;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.dx-callout[data-hue='emerald'],
|
|
52
|
+
:where([data-hue='emerald']) .dx-callout,
|
|
53
|
+
.dx-callout--emerald {
|
|
54
|
+
@apply bg-emerald-surface border-emerald-border text-emerald-fg;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.dx-callout[data-hue='teal'],
|
|
58
|
+
:where([data-hue='teal']) .dx-callout,
|
|
59
|
+
.dx-callout--teal {
|
|
60
|
+
@apply bg-teal-surface border-teal-border text-teal-fg;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.dx-callout[data-hue='cyan'],
|
|
64
|
+
:where([data-hue='cyan']) .dx-callout,
|
|
65
|
+
.dx-callout--cyan {
|
|
66
|
+
@apply bg-cyan-surface border-cyan-border text-cyan-fg;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.dx-callout[data-hue='sky'],
|
|
70
|
+
:where([data-hue='sky']) .dx-callout,
|
|
71
|
+
.dx-callout--sky {
|
|
72
|
+
@apply bg-sky-surface border-sky-border text-sky-fg;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.dx-callout[data-hue='blue'],
|
|
76
|
+
:where([data-hue='blue']) .dx-callout,
|
|
77
|
+
.dx-callout--blue {
|
|
78
|
+
@apply bg-blue-surface border-blue-border text-blue-fg;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.dx-callout[data-hue='indigo'],
|
|
82
|
+
:where([data-hue='indigo']) .dx-callout,
|
|
83
|
+
.dx-callout--indigo {
|
|
84
|
+
@apply bg-indigo-surface border-indigo-border text-indigo-fg;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.dx-callout[data-hue='violet'],
|
|
88
|
+
:where([data-hue='violet']) .dx-callout,
|
|
89
|
+
.dx-callout--violet {
|
|
90
|
+
@apply bg-violet-surface border-violet-border text-violet-fg;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.dx-callout[data-hue='purple'],
|
|
94
|
+
:where([data-hue='purple']) .dx-callout,
|
|
95
|
+
.dx-callout--purple {
|
|
96
|
+
@apply bg-purple-surface border-purple-border text-purple-fg;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.dx-callout[data-hue='fuchsia'],
|
|
100
|
+
:where([data-hue='fuchsia']) .dx-callout,
|
|
101
|
+
.dx-callout--fuchsia {
|
|
102
|
+
@apply bg-fuchsia-surface border-fuchsia-border text-fuchsia-fg;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.dx-callout[data-hue='pink'],
|
|
106
|
+
:where([data-hue='pink']) .dx-callout,
|
|
107
|
+
.dx-callout--pink {
|
|
108
|
+
@apply bg-pink-surface border-pink-border text-pink-fg;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.dx-callout[data-hue='rose'],
|
|
112
|
+
:where([data-hue='rose']) .dx-callout,
|
|
113
|
+
.dx-callout--rose {
|
|
114
|
+
@apply bg-rose-surface border-rose-border text-rose-fg;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.dx-callout[data-hue='info'],
|
|
118
|
+
:where([data-hue='info']) .dx-callout,
|
|
119
|
+
.dx-callout--info {
|
|
120
|
+
@apply bg-info-surface border-info-border text-info-fg;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.dx-callout[data-hue='success'],
|
|
124
|
+
:where([data-hue='success']) .dx-callout,
|
|
125
|
+
.dx-callout--success {
|
|
126
|
+
@apply bg-success-surface border-success-border text-success-fg;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.dx-callout[data-hue='warning'],
|
|
130
|
+
:where([data-hue='warning']) .dx-callout,
|
|
131
|
+
.dx-callout--warning {
|
|
132
|
+
@apply bg-warning-surface border-warning-border text-warning-fg;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.dx-callout[data-hue='error'],
|
|
136
|
+
:where([data-hue='error']) .dx-callout,
|
|
137
|
+
.dx-callout--error {
|
|
138
|
+
@apply bg-error-surface border-error-border text-error-fg;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
@layer dx-components {
|
|
2
|
+
/*
|
|
3
|
+
* Shared input-box treatment — the hairline-bordered surface used by text inputs and by CodeMirror
|
|
4
|
+
* editors styled to match them (`Input` default variant, `MarkdownField`, `RefEditor`, the inbox
|
|
5
|
+
* composer `Editor`). Single source for the whole chrome: surface + border + radius + padding,
|
|
6
|
+
* the focus-within colour shift, and the subtle focus ring (mirrors `dx-focus-ring`) — applied
|
|
7
|
+
* whether the box itself is the focusable or it wraps an inner focusable (CodeMirror
|
|
8
|
+
* contenteditable, adorned field). Callers add only sizing (height/min-height) and layout;
|
|
9
|
+
* element paddings from density utilities (`px-*`/`py-0`) still win over the defaults here.
|
|
10
|
+
*/
|
|
11
|
+
.dx-input {
|
|
12
|
+
@apply transition-colors border border-input-separator rounded-xs p-1 px-2;
|
|
13
|
+
|
|
14
|
+
/*
|
|
15
|
+
* A zone, not a bare fill: the input publishes its own surface so what sits on it — the
|
|
16
|
+
* placeholder above all — derives from the input's colour rather than from the host behind it.
|
|
17
|
+
* `@apply` cannot take a zone class, hence the two lines rather than `dx-input-surface`.
|
|
18
|
+
*/
|
|
19
|
+
--surface-bg: var(--color-input-surface);
|
|
20
|
+
background-color: var(--surface-bg);
|
|
21
|
+
|
|
22
|
+
&:focus {
|
|
23
|
+
@apply outline-hidden;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
&:focus-within {
|
|
27
|
+
@apply bg-focus-surface border-separator;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Border matches the ring while it shows, so the focus treatment reads as one band (no inner line). */
|
|
31
|
+
&:not([disabled]):focus-visible,
|
|
32
|
+
&:not([disabled]):has(:focus-visible) {
|
|
33
|
+
@apply ring-focus-line ring-offset-focus-offset z-[1] ring-[var(--color-focus-ring-subtle)] border-[color:var(--color-focus-ring-subtle)];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Selected / Current / Highlighted state utilities.
|
|
3
3
|
*
|
|
4
|
-
* See `./
|
|
4
|
+
* See `./state.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
|
|
|
@@ -23,13 +23,6 @@
|
|
|
23
23
|
hover:aria-selected:bg-selected-surface-hover hover:aria-selected:text-selected-fg
|
|
24
24
|
hover:aria-[current=true]:bg-current-surface-hover hover:aria-[current=true]:text-current-fg;
|
|
25
25
|
}
|
|
26
|
-
.dx-hover-row {
|
|
27
|
-
@apply group-hover/row:bg-hover-surface-subtle! group-hover/row:text-hover-fg!
|
|
28
|
-
group-hover/row:group-aria-selected/row:bg-selected-surface-hover!
|
|
29
|
-
group-hover/row:group-aria-selected/row:text-selected-fg!
|
|
30
|
-
group-hover/row:group-aria-[current=true]/row:bg-current-surface-hover!
|
|
31
|
-
group-hover/row:group-aria-[current=true]/row:text-current-fg!;
|
|
32
|
-
}
|
|
33
26
|
|
|
34
27
|
/*
|
|
35
28
|
* Pairs with `aria-selected`. Use for listbox/option selection (master/detail).
|
|
@@ -61,9 +54,6 @@
|
|
|
61
54
|
aria-[current=true]:bg-current-surface! aria-[current=true]:text-current-fg!
|
|
62
55
|
aria-[current=true]:after:ring-focus-ring-subtle!;
|
|
63
56
|
}
|
|
64
|
-
.dx-current-row {
|
|
65
|
-
@apply group-aria-[current=true]/row:bg-current-surface! group-aria-[current=true]/row:text-current-fg!;
|
|
66
|
-
}
|
|
67
57
|
|
|
68
58
|
/*
|
|
69
59
|
* Pairs with Radix-managed `data-highlighted`. Don't set the attribute manually.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# `dx-*` selection / navigation grammar
|
|
2
2
|
|
|
3
|
-
Companion to `
|
|
3
|
+
Companion to `state.css`. The four selection-state utilities below are
|
|
4
4
|
each bound to a specific ARIA attribute (or `data-*`) selector. **The
|
|
5
5
|
class only fires when the matching ARIA attribute is set on the same
|
|
6
6
|
element.** Mismatches (e.g. `dx-current` paired with `aria-selected`)
|