@dxos/ui-theme 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Surfaces — the elevation ladder and the aspects derived from it.
|
|
3
|
+
*
|
|
4
|
+
* Two kinds of token live here, and the distinction is the whole design:
|
|
5
|
+
* - **Levels** are fixed stops on the neutral ramp. A named surface aliases exactly one level.
|
|
6
|
+
* - **Aspects** are NOT levels. They are computed from whichever surface hosts them
|
|
7
|
+
* (`--surface-bg`), so the same role reads correctly at any elevation.
|
|
8
|
+
*
|
|
9
|
+
* Everything else (text emphasis, accent, separators, scrollbar, grid paper) is in `roles.css`.
|
|
10
|
+
*
|
|
11
|
+
* Naming convention: --color-{name}-{part}[-{state}] — see DESIGN_SYSTEM.md.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
@theme {
|
|
15
|
+
/*
|
|
16
|
+
* Elevation ladder — six named levels, strictly monotonic, z-order low → high.
|
|
17
|
+
* Dark: lighter = higher. Light: inverted (lighter = higher, toward white).
|
|
18
|
+
*
|
|
19
|
+
* Chrome sits BELOW the document canvas and content surfaces sit ABOVE it, so the app reads as
|
|
20
|
+
* paper on a desk rather than paper in a well (see AUDIT.md D1/D2).
|
|
21
|
+
*
|
|
22
|
+
* Level Dark Light Roles
|
|
23
|
+
* sunken n-950 0.905 deck gaps, wells, scrim base, L0/R0 outer rails
|
|
24
|
+
* chrome n-925 0.935 sidebars, topbar, statusbar, L1/R1 sidebars
|
|
25
|
+
* base n-900 0.980 document canvas, attention zone
|
|
26
|
+
* raised n-850 0.990 cards, side panels
|
|
27
|
+
* overlay n-800 0.995 dialogs, sheets, drawers
|
|
28
|
+
* popup n-775 1.000 popover, menu, toast, tooltip
|
|
29
|
+
*
|
|
30
|
+
* Toolbars, groups and inputs are deliberately NOT levels: they are aspects derived from
|
|
31
|
+
* whichever surface hosts them (see "Aspects" below), so a toolbar in a card and a toolbar on the
|
|
32
|
+
* canvas each read as a bar on their own host instead of jumping to a fixed global tone.
|
|
33
|
+
*
|
|
34
|
+
* These are private (--dx-*) knobs — use named surface tokens in components, not these directly.
|
|
35
|
+
*/
|
|
36
|
+
--dx-surface-sunken: light-dark(var(--color-neutral-150), var(--color-neutral-950));
|
|
37
|
+
--dx-surface-chrome: light-dark(var(--color-neutral-100), var(--color-neutral-925));
|
|
38
|
+
--dx-surface-base: light-dark(oklch(0.98 0.001 190), var(--color-neutral-900));
|
|
39
|
+
--dx-surface-raised: light-dark(oklch(0.99 0.001 190), var(--color-neutral-850));
|
|
40
|
+
--dx-surface-overlay: light-dark(oklch(0.995 0.001 190), var(--color-neutral-800));
|
|
41
|
+
--dx-surface-popup: light-dark(oklch(1 0 0), var(--color-neutral-775));
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Level: sunken
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
--color-deck-surface: var(--dx-surface-sunken);
|
|
48
|
+
|
|
49
|
+
/*
|
|
50
|
+
* Outer rails frame the panels rather than belonging to them, so they read one step behind the
|
|
51
|
+
* L1/R1 sidebars they flank. They carry their own light-dark pair rather than aliasing a level:
|
|
52
|
+
* dark keeps the deck's depth, while light sits higher, because near white the same ladder step
|
|
53
|
+
* reads much heavier than it does near black.
|
|
54
|
+
*/
|
|
55
|
+
--color-l0-surface: light-dark(oklch(0.935 0.001 190), var(--dx-surface-sunken));
|
|
56
|
+
--color-r0-surface: light-dark(oklch(0.935 0.001 190), var(--dx-surface-sunken));
|
|
57
|
+
|
|
58
|
+
/* Translucent dimming layer; tracks the lowest level rather than a raw neutral. */
|
|
59
|
+
--color-scrim-surface: light-dark(
|
|
60
|
+
oklch(from var(--dx-surface-sunken) l c h / 0.5),
|
|
61
|
+
oklch(from var(--dx-surface-sunken) l c h / 0.25)
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Level: chrome
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
--color-sidebar-surface: var(--dx-surface-chrome);
|
|
69
|
+
--color-header-surface: var(--dx-surface-chrome);
|
|
70
|
+
--color-l1-surface: light-dark(oklch(0.955 0.001 190), var(--dx-surface-chrome));
|
|
71
|
+
--color-r1-surface: light-dark(oklch(0.955 0.001 190), var(--dx-surface-chrome));
|
|
72
|
+
|
|
73
|
+
/* Sidebar body text. Default sits one ramp stop below the current/selected emphasis. */
|
|
74
|
+
--color-sidebar-fg: light-dark(var(--color-neutral-700), var(--color-neutral-250));
|
|
75
|
+
--color-sidebar-current-fg: light-dark(var(--color-neutral-950), var(--color-neutral-75));
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Level: base
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
--color-base-surface: var(--dx-surface-base);
|
|
82
|
+
--color-base-fg: light-dark(var(--color-neutral-950), var(--color-neutral-150));
|
|
83
|
+
|
|
84
|
+
--color-attention-surface: var(--dx-surface-base);
|
|
85
|
+
--color-attention-contains: oklch(from var(--color-accent-bg) l c h / 0.3);
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Level: raised
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
--color-card-surface: var(--dx-surface-raised);
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Level: overlay
|
|
95
|
+
*/
|
|
96
|
+
|
|
97
|
+
--color-modal-surface: var(--dx-surface-overlay);
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Level: popup
|
|
101
|
+
*/
|
|
102
|
+
|
|
103
|
+
--color-popover-surface: var(--dx-surface-popup);
|
|
104
|
+
|
|
105
|
+
/*
|
|
106
|
+
* Aspects — surfaces and states derived from the HOST surface (`--surface-bg`) rather than pinned
|
|
107
|
+
* to a level, via relative oklch stepped by `--dx-lift` (+1 dark, -1 light; see base.css), so each
|
|
108
|
+
* stays visible at any elevation in either theme. The values here resolve against the root
|
|
109
|
+
* `--surface-bg` (= base-surface, set in base.css), which is the correct default for content
|
|
110
|
+
* outside any surface zone; every zone re-derives them for its own subtree in
|
|
111
|
+
* components/surface.css.
|
|
112
|
+
*
|
|
113
|
+
* Offsets (lightness): bar 0.025, well 0.05, hover-subtle 0.02, hover 0.08, current 0.10,
|
|
114
|
+
* current-hover 0.12. Keep these in sync with the re-derivation blocks in surface.css.
|
|
115
|
+
*/
|
|
116
|
+
|
|
117
|
+
/* Bar: a sticky strip on its host (toolbar, statusbar). */
|
|
118
|
+
--color-toolbar-surface: oklch(
|
|
119
|
+
from var(--surface-bg, var(--color-base-surface)) calc(l + var(--dx-lift) * var(--dx-attenuate-bar) * 0.025) c h
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
/* Well: an inset region on its host (group, input, focus). */
|
|
123
|
+
--color-group-surface: oklch(
|
|
124
|
+
from var(--surface-bg, var(--color-base-surface)) calc(l + var(--dx-lift) * var(--dx-attenuate-well) * 0.05) c h
|
|
125
|
+
);
|
|
126
|
+
--color-input-surface: var(--color-group-surface);
|
|
127
|
+
--color-focus-surface: var(--color-group-surface);
|
|
128
|
+
|
|
129
|
+
/* Subtle alternate of group-surface for zebra striping (e.g. calendar months). */
|
|
130
|
+
--color-group-alt-surface: oklch(
|
|
131
|
+
from var(--surface-bg, var(--color-base-surface)) calc(l + var(--dx-lift) * 0.08) c h
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
/* Placeholder ink is an aspect too: a fixed neutral reads correctly on one surface only, so it
|
|
135
|
+
* lifts away from the host like the state surfaces do (offset 0.30). */
|
|
136
|
+
--color-placeholder: oklch(
|
|
137
|
+
from var(--surface-bg, var(--color-base-surface)) calc(l + var(--dx-lift) * var(--dx-attenuate-placeholder) * 0.3) c
|
|
138
|
+
h
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
/*
|
|
142
|
+
* Scrollbar thumb. Fixed neutrals collided with the surface they scrolled over: in light mode the
|
|
143
|
+
* thumb was neutral-200, the same value as the base canvas, so it was invisible. Deriving it from
|
|
144
|
+
* the host keeps the same contrast on any surface, in either theme (offsets 0.23 / 0.30 / 0.34).
|
|
145
|
+
*/
|
|
146
|
+
--color-scrollbar-thumb: oklch(
|
|
147
|
+
from var(--surface-bg, var(--color-base-surface)) calc(l + var(--dx-lift) * var(--dx-attenuate-scrollbar) * 0.23) c
|
|
148
|
+
h
|
|
149
|
+
);
|
|
150
|
+
--color-scrollbar-thumb-hover: oklch(
|
|
151
|
+
from var(--surface-bg, var(--color-base-surface)) calc(l + var(--dx-lift) * var(--dx-attenuate-scrollbar) * 0.3) c h
|
|
152
|
+
);
|
|
153
|
+
--color-scrollbar-thumb-active: oklch(
|
|
154
|
+
from var(--surface-bg, var(--color-base-surface)) calc(l + var(--dx-lift) * var(--dx-attenuate-scrollbar) * 0.34) c
|
|
155
|
+
h
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
/*
|
|
159
|
+
* Separators. Fixed neutrals collided with the surfaces they divide once the ladder inverted:
|
|
160
|
+
* in light mode `separator` was neutral-200, the same value as the base canvas, and
|
|
161
|
+
* `subdued-separator` matched the sidebar exactly — both invisible. The offsets below reproduce
|
|
162
|
+
* the dark-mode appearance they had (0.166 / 0.115 / 0.089 / 0.064 above the base surface) and
|
|
163
|
+
* mirror it in light.
|
|
164
|
+
*/
|
|
165
|
+
--color-separator: oklch(
|
|
166
|
+
from var(--surface-bg, var(--color-base-surface))
|
|
167
|
+
calc(l + var(--dx-lift) * var(--dx-attenuate-separator-line) * 0.166) c h
|
|
168
|
+
);
|
|
169
|
+
--color-input-separator: oklch(
|
|
170
|
+
from var(--surface-bg, var(--color-base-surface)) calc(l + var(--dx-lift) * var(--dx-attenuate-separator) * 0.115) c
|
|
171
|
+
h
|
|
172
|
+
);
|
|
173
|
+
--color-subdued-separator: oklch(
|
|
174
|
+
from var(--surface-bg, var(--color-base-surface)) calc(l + var(--dx-lift) * var(--dx-attenuate-separator) * 0.089) c
|
|
175
|
+
h
|
|
176
|
+
);
|
|
177
|
+
--color-primary-separator: oklch(
|
|
178
|
+
from var(--surface-bg, var(--color-base-surface)) calc(l + var(--dx-lift) * var(--dx-attenuate-separator) * 0.064) c
|
|
179
|
+
h
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
/* State aspects — same host-derived mechanism; see the offsets above. */
|
|
183
|
+
--color-hover-surface: oklch(
|
|
184
|
+
from var(--surface-bg, var(--color-base-surface)) calc(l + var(--dx-lift) * var(--dx-attenuate-state) * 0.08) c h
|
|
185
|
+
);
|
|
186
|
+
--color-hover-fg: light-dark(var(--color-neutral-950), var(--color-neutral-150));
|
|
187
|
+
|
|
188
|
+
/*
|
|
189
|
+
* Subtle region hover for large highlight targets (list rows, tiles) where the full
|
|
190
|
+
* control-strength hover reads as too heavy. Consumed by `.dx-hover`;
|
|
191
|
+
* controls (buttons) keep --color-hover-surface.
|
|
192
|
+
*/
|
|
193
|
+
--color-hover-surface-subtle: oklch(
|
|
194
|
+
from var(--surface-bg, var(--color-base-surface)) calc(l + var(--dx-lift) * var(--dx-attenuate-state) * 0.02) c h
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
/* current (aria-current) */
|
|
198
|
+
--color-current-surface: oklch(
|
|
199
|
+
from var(--surface-bg, var(--color-base-surface)) calc(l + var(--dx-lift) * var(--dx-attenuate-state) * 0.1) c h
|
|
200
|
+
);
|
|
201
|
+
--color-current-surface-hover: oklch(
|
|
202
|
+
from var(--surface-bg, var(--color-base-surface)) calc(l + var(--dx-lift) * var(--dx-attenuate-state) * 0.12) c h
|
|
203
|
+
);
|
|
204
|
+
--color-current-fg: light-dark(var(--color-neutral-950), var(--color-neutral-50));
|
|
205
|
+
|
|
206
|
+
/* selected (aria-selected) tracks current */
|
|
207
|
+
--color-selected-surface: var(--color-current-surface);
|
|
208
|
+
--color-selected-surface-hover: var(--color-current-surface-hover);
|
|
209
|
+
--color-selected-fg: var(--color-current-fg);
|
|
210
|
+
|
|
211
|
+
/* Inverted surface (tooltips, snackbars) — a deliberate flip, not a level. */
|
|
212
|
+
--color-inverse-surface: light-dark(var(--color-neutral-800), var(--color-neutral-200));
|
|
213
|
+
--color-inverse-fg: light-dark(var(--color-neutral-50), var(--color-neutral-950));
|
|
214
|
+
--color-inverse-text: light-dark(var(--color-neutral-50), var(--color-neutral-950));
|
|
215
|
+
}
|
package/src/css/theme/text.css
CHANGED
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
@theme {
|
|
6
|
-
/*
|
|
7
|
-
|
|
6
|
+
/*
|
|
7
|
+
* Font families
|
|
8
|
+
* https://fonts.google.com/?preview.layout=grid&categoryFilters=Technology:%2FTechnology%2FVariable;Sans+Serif:%2FSans%2F*
|
|
9
|
+
* Nunito
|
|
10
|
+
*/
|
|
11
|
+
--font-body: 'Nunito Variable', 'Inter Variable', ui-sans-serif, system-ui, sans-serif;
|
|
8
12
|
--font-mono: 'JetBrains Mono Variable', ui-monospace, 'Cascadia Code', 'Source Code Pro', monospace;
|
|
9
13
|
|
|
10
14
|
/* Font size scale (Tailwind v4 defaults — clean rem/px values) */
|
package/src/css/utilities.css
CHANGED
|
@@ -37,13 +37,6 @@
|
|
|
37
37
|
@apply dx-expander overflow-hidden;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
/**
|
|
41
|
-
* Column that fills the available space (extends dx-expander with overflow clipping).
|
|
42
|
-
*/
|
|
43
|
-
@utility dx-column {
|
|
44
|
-
@apply flex-1 min-w-0 w-full;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
40
|
/**
|
|
48
41
|
* Fullscreen
|
|
49
42
|
*/
|
|
@@ -52,10 +45,21 @@
|
|
|
52
45
|
}
|
|
53
46
|
|
|
54
47
|
/**
|
|
55
|
-
* Visual warning to indicate incorrect usage of `slottable
|
|
48
|
+
* Visual warning to indicate incorrect usage of `slottable` — an `asChild` whose child is not
|
|
49
|
+
* composable, so Radix `Slot` silently drops the injected className and ref.
|
|
50
|
+
*
|
|
51
|
+
* An outline rather than a border: it is applied to the part's own element (not a wrapper), so it
|
|
52
|
+
* must not consume layout space or fight a border the part already has. Dev builds only.
|
|
56
53
|
*/
|
|
57
54
|
@utility dx-slot-warning {
|
|
58
|
-
|
|
55
|
+
/* No layout box of its own: these parts live in grids and subgrids, where an extra element
|
|
56
|
+
re-flows the layout — the diagnostic must not corrupt the thing it is diagnosing. */
|
|
57
|
+
display: contents;
|
|
58
|
+
|
|
59
|
+
& > * {
|
|
60
|
+
outline: 2px dashed var(--color-rose-500);
|
|
61
|
+
outline-offset: -2px;
|
|
62
|
+
}
|
|
59
63
|
}
|
|
60
64
|
|
|
61
65
|
/**
|
package/src/defs.ts
CHANGED
|
@@ -2,36 +2,11 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type ChromaticPalette } from '@dxos/ui-types';
|
|
6
|
-
|
|
7
5
|
/**
|
|
8
6
|
* Translation namespace for OS-level translations.
|
|
9
7
|
*/
|
|
10
8
|
export const osTranslations = 'org.dxos.i18n.os';
|
|
11
9
|
|
|
12
|
-
/**
|
|
13
|
-
* Available color hues for UI components.
|
|
14
|
-
*/
|
|
15
|
-
export const hues: ChromaticPalette[] = [
|
|
16
|
-
'red',
|
|
17
|
-
'orange',
|
|
18
|
-
'amber',
|
|
19
|
-
'yellow',
|
|
20
|
-
'lime',
|
|
21
|
-
'green',
|
|
22
|
-
'emerald',
|
|
23
|
-
'teal',
|
|
24
|
-
'cyan',
|
|
25
|
-
'sky',
|
|
26
|
-
'blue',
|
|
27
|
-
'indigo',
|
|
28
|
-
'violet',
|
|
29
|
-
'purple',
|
|
30
|
-
'fuchsia',
|
|
31
|
-
'pink',
|
|
32
|
-
'rose',
|
|
33
|
-
] as const;
|
|
34
|
-
|
|
35
10
|
export const hueShades = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950] as const;
|
|
36
11
|
|
|
37
12
|
// NOTE: These are the JS-side style-API role keys (see ColorStyles in util/hash-styles.ts), kept
|
package/src/fragments/hover.ts
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
export const ghostHover = 'hover:bg-hover-surface';
|
|
6
|
-
export const ghostFocusWithin = 'focus-within:bg-hover-surface';
|
|
7
|
-
|
|
8
5
|
export const hoverableControls =
|
|
9
6
|
'[--controls-opacity:1] hover-hover:[--controls-opacity:0] hover-hover:hover:[--controls-opacity:1]';
|
|
10
7
|
|
package/src/fragments/index.ts
CHANGED
package/src/main.css
CHANGED
|
@@ -23,14 +23,8 @@
|
|
|
23
23
|
*/
|
|
24
24
|
@import 'tailwindcss' source(none);
|
|
25
25
|
|
|
26
|
-
/*
|
|
27
|
-
@import './
|
|
28
|
-
@import './css/theme/border.css';
|
|
29
|
-
@import './css/theme/palette.css';
|
|
30
|
-
@import './css/theme/semantic.css';
|
|
31
|
-
@import './css/theme/spacing.css';
|
|
32
|
-
@import './css/theme/styles.css';
|
|
33
|
-
@import './css/theme/text.css';
|
|
26
|
+
/* Theme extensions; also exported as tokens.css for stylesheets built outside this repo. */
|
|
27
|
+
@import './tokens.css';
|
|
34
28
|
|
|
35
29
|
/* @layer dx-base, dx-tokens */
|
|
36
30
|
@import './css/base/base.css';
|
|
@@ -43,7 +37,8 @@
|
|
|
43
37
|
@import './css/components/dialog.css';
|
|
44
38
|
@import './css/components/focus.css';
|
|
45
39
|
@import './css/components/icon.css';
|
|
46
|
-
@import './css/components/
|
|
40
|
+
@import './css/components/input.css';
|
|
41
|
+
@import './css/components/callout.css';
|
|
47
42
|
@import './css/components/link.css';
|
|
48
43
|
@import './css/components/scrollbar.css';
|
|
49
44
|
@import './css/components/state.css';
|
|
@@ -134,13 +129,16 @@
|
|
|
134
129
|
* Class-based dark mode.
|
|
135
130
|
* The `.dark` class on an ancestor toggles `dark:` utilities.
|
|
136
131
|
*/
|
|
137
|
-
@variant dark (&:where(.dark, .dark *));
|
|
132
|
+
@custom-variant dark (&:where(.dark, .dark *));
|
|
138
133
|
|
|
139
134
|
/** Mobile */
|
|
140
135
|
@custom-variant pointer-coarse (@media (pointer: coarse));
|
|
136
|
+
|
|
141
137
|
/** Web */
|
|
142
138
|
@custom-variant pointer-fine (@media (pointer: fine));
|
|
139
|
+
|
|
143
140
|
/** Supports mouse/trackpad (Web) */
|
|
144
141
|
@custom-variant hover-hover (@media (hover: hover));
|
|
142
|
+
|
|
145
143
|
/** Active navigation */
|
|
146
144
|
@custom-variant is-current (&[aria-current]:not([aria-current='false']));
|
|
@@ -68,51 +68,61 @@ export const ThemePlugin = (options: ThemePluginOptions): Plugin[] => {
|
|
|
68
68
|
// Trailing-edge debounce handle for theme CSS reloads (see `handleHotUpdate`).
|
|
69
69
|
let themeReloadTimer: ReturnType<typeof setTimeout> | undefined;
|
|
70
70
|
|
|
71
|
+
// Under Vitest there is no HMR, and a live watcher leaks per-file `fs_event` handles: Tailwind's
|
|
72
|
+
// `@source` scan registers every scanned source file as a Vite watch dependency, and those handles
|
|
73
|
+
// are never released on close, hanging single-pass `vitest run` teardown. A non-null `server.watch`
|
|
74
|
+
// here also overrides the `watch: null` set by the test configs, so gate it: disable the watcher
|
|
75
|
+
// entirely under Vitest (`VITEST` is exported to the whole process tree), keep the HMR-ignore
|
|
76
|
+
// patterns for interactive `storybook dev` / `vite dev` (where `VITEST` is unset).
|
|
77
|
+
const isVitest = process.env.VITEST === 'true';
|
|
78
|
+
|
|
71
79
|
const themePlugin: Plugin = {
|
|
72
80
|
name: 'vite-plugin-dxos-ui-theme',
|
|
73
81
|
config: (): UserConfig => {
|
|
74
82
|
return {
|
|
75
83
|
server: {
|
|
76
|
-
watch:
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
84
|
+
watch: isVitest
|
|
85
|
+
? null
|
|
86
|
+
: {
|
|
87
|
+
// Stop build outputs from driving HMR — they are the root of the
|
|
88
|
+
// `main.css` HMR storm.
|
|
89
|
+
//
|
|
90
|
+
// Tailwind's `@source` scanning (see `src/main.css`) registers its
|
|
91
|
+
// scanned source files as Vite watch dependencies of the compiled
|
|
92
|
+
// theme CSS. Tailwind's own scanner respects `.gitignore` (and the
|
|
93
|
+
// `@source not` directives), so it never *scans* `dist/`. BUT the
|
|
94
|
+
// scanner hands Vite a coarse `dir-dependency` glob — e.g.
|
|
95
|
+
// `{**/*.html,**/*.ts,**/*.tsx}` — and Vite re-expands that glob
|
|
96
|
+
// itself, ignoring only `node_modules` (not `.gitignore`, not the
|
|
97
|
+
// `@source not` negations). The re-expansion therefore sweeps in
|
|
98
|
+
// every `packages/*/dist/**/*.d.ts` (`.d.ts` matches `**/*.ts`),
|
|
99
|
+
// making each emitted declaration file a watch-dependency of
|
|
100
|
+
// `main.css`. A single package rebuild emits dozens of `.d.ts` in a
|
|
101
|
+
// tight burst, and each write re-invalidates the theme — 40+ HMR
|
|
102
|
+
// pings for `main.css` in one second, repeating on every rebuild.
|
|
103
|
+
//
|
|
104
|
+
// Ignoring build outputs in the watcher is also semantically
|
|
105
|
+
// correct: in dev the workspace resolves `@dxos/*` via the `source`
|
|
106
|
+
// export condition (see `vite-plugin-import-source`), so `dist/`
|
|
107
|
+
// is never consumed at runtime and its churn should never trigger
|
|
108
|
+
// HMR. Vite concatenates these patterns with its built-in ignores
|
|
109
|
+
// (`**/node_modules/**`, `**/.git/**`, …), so this is purely
|
|
110
|
+
// additive.
|
|
111
|
+
//
|
|
112
|
+
// `<root>/.claude/**` covers agent worktrees checked out under the
|
|
113
|
+
// repo root (`.claude/worktrees/<name>/packages/**`): they are full
|
|
114
|
+
// source copies, so the glob re-expansion above sweeps them in and
|
|
115
|
+
// every agent-side edit burst or checkout invalidates the theme in
|
|
116
|
+
// the user's dev server. The pattern is anchored at the resolved
|
|
117
|
+
// repo root (not `**/.claude/**`) because chokidar matches against
|
|
118
|
+
// absolute paths — a bare pattern would match *everything* when the
|
|
119
|
+
// dev server itself runs from inside a worktree whose path contains
|
|
120
|
+
// a `.claude` segment. `*.log` covers runtime log sinks (e.g.
|
|
121
|
+
// vite-plugin-log's `app.log` in the app root), which are appended
|
|
122
|
+
// continuously at runtime and must never feed back into the
|
|
123
|
+
// watcher.
|
|
124
|
+
ignored: ['**/dist/**', '**/out/**', '**/*.log', `${resolve(import.meta.dirname, ROOT, '.claude')}/**`],
|
|
125
|
+
},
|
|
116
126
|
},
|
|
117
127
|
css: {
|
|
118
128
|
postcss: {
|
package/src/plugins/main.css
CHANGED
|
@@ -24,7 +24,7 @@ body {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/* Pre-CSS color fallbacks so text is readable before and during Vite HMR. */
|
|
27
|
-
/* Values are intentionally kept in sync with @theme tokens in
|
|
27
|
+
/* Values are intentionally kept in sync with @theme tokens in theme/surfaces.css:
|
|
28
28
|
* color ← --color-base-fg = light-dark(neutral-950, neutral-150)
|
|
29
29
|
* background-color ← --color-base-surface = elevation-3 = light-dark(neutral-125, neutral-850)
|
|
30
30
|
* The literals carry the ramp tint (chroma 0.001, hue 190) so first paint matches the loaded theme. */
|
package/src/tokens.css
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design tokens, for stylesheets compiled outside this repo.
|
|
3
|
+
*
|
|
4
|
+
* A plugin loaded from the registry is not scanned by the host's Tailwind build, so it compiles its
|
|
5
|
+
* own stylesheet and must be able to generate every utility it uses — including token-backed ones
|
|
6
|
+
* like `bg-base-surface`. Importing this registers the token names with Tailwind so those utilities
|
|
7
|
+
* resolve; the values themselves still come from the host at runtime, which is what keeps a plugin
|
|
8
|
+
* following the active theme.
|
|
9
|
+
*
|
|
10
|
+
* Tokens only — no base, component, or layout rules, which the host already applies.
|
|
11
|
+
*
|
|
12
|
+
* `main.css` imports this too, so the host and external plugins compile against one token set.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
@import './css/theme/animation.css';
|
|
16
|
+
@import './css/theme/border.css';
|
|
17
|
+
@import './css/theme/palette.css';
|
|
18
|
+
@import './css/theme/roles.css';
|
|
19
|
+
@import './css/theme/spacing.css';
|
|
20
|
+
@import './css/theme/styles.css';
|
|
21
|
+
@import './css/theme/surfaces.css';
|
|
22
|
+
@import './css/theme/text.css';
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { type Density } from '@dxos/ui-types';
|
|
2
|
-
export declare const densityDimensions: (density?: Density) => "min-h-[1.5rem] px-1" | "min-h-[1.75rem] px-1.5" | "min-h-[2.5rem] pointer-fine:min-h-[2rem] px-2" | "min-h-[2.5rem] px-3";
|
|
3
|
-
export declare const densityBlockSize: (density?: Density) => "min-h-[1.5rem]" | "min-h-[1.75rem]" | "min-h-[2.5rem]" | "min-h-[2.5rem] pointer-fine:min-h-[2rem]";
|
|
4
|
-
//# sourceMappingURL=density.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"density.d.ts","sourceRoot":"","sources":["../../../../src/fragments/density.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAY9C,eAAO,MAAM,iBAAiB,aAAa,OAAO,+HAYjD,CAAC;AAEF,eAAO,MAAM,gBAAgB,aAAa,OAAO,yGAYhD,CAAC"}
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Panel — applies bg-{hue}-surface / text-{hue}-fg / border-{hue}-border tokens via data-hue attribute or BEM modifier.
|
|
3
|
-
* Example: <div className='dx-panel' data-hue='blue'>...</div>
|
|
4
|
-
* Example: <div className='dx-panel dx-panel--blue'>...</div>
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
@layer dx-components {
|
|
8
|
-
[data-hue='neutral'] .dx-panel,
|
|
9
|
-
.dx-panel--neutral {
|
|
10
|
-
@apply bg-neutral-surface text-neutral-fg border-neutral-border;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
[data-hue='red'] .dx-panel,
|
|
14
|
-
.dx-panel--red {
|
|
15
|
-
@apply bg-red-surface text-red-fg border-red-border;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
[data-hue='orange'] .dx-panel,
|
|
19
|
-
.dx-panel--orange {
|
|
20
|
-
@apply bg-orange-surface text-orange-fg border-orange-border;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
[data-hue='amber'] .dx-panel,
|
|
24
|
-
.dx-panel--amber {
|
|
25
|
-
@apply bg-amber-surface text-amber-fg border-amber-border;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
[data-hue='yellow'] .dx-panel,
|
|
29
|
-
.dx-panel--yellow {
|
|
30
|
-
@apply bg-yellow-surface text-yellow-fg border-yellow-border;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
[data-hue='lime'] .dx-panel,
|
|
34
|
-
.dx-panel--lime {
|
|
35
|
-
@apply bg-lime-surface text-lime-fg border-lime-border;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
[data-hue='green'] .dx-panel,
|
|
39
|
-
.dx-panel--green {
|
|
40
|
-
@apply bg-green-surface text-green-fg border-green-border;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
[data-hue='emerald'] .dx-panel,
|
|
44
|
-
.dx-panel--emerald {
|
|
45
|
-
@apply bg-emerald-surface text-emerald-fg border-emerald-border;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
[data-hue='teal'] .dx-panel,
|
|
49
|
-
.dx-panel--teal {
|
|
50
|
-
@apply bg-teal-surface text-teal-fg border-teal-border;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
[data-hue='cyan'] .dx-panel,
|
|
54
|
-
.dx-panel--cyan {
|
|
55
|
-
@apply bg-cyan-surface text-cyan-fg border-cyan-border;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
[data-hue='sky'] .dx-panel,
|
|
59
|
-
.dx-panel--sky {
|
|
60
|
-
@apply bg-sky-surface text-sky-fg border-sky-border;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
[data-hue='blue'] .dx-panel,
|
|
64
|
-
.dx-panel--blue {
|
|
65
|
-
@apply bg-blue-surface text-blue-fg border-blue-border;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
[data-hue='indigo'] .dx-panel,
|
|
69
|
-
.dx-panel--indigo {
|
|
70
|
-
@apply bg-indigo-surface text-indigo-fg border-indigo-border;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
[data-hue='violet'] .dx-panel,
|
|
74
|
-
.dx-panel--violet {
|
|
75
|
-
@apply bg-violet-surface text-violet-fg border-violet-border;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
[data-hue='purple'] .dx-panel,
|
|
79
|
-
.dx-panel--purple {
|
|
80
|
-
@apply bg-purple-surface text-purple-fg border-purple-border;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
[data-hue='fuchsia'] .dx-panel,
|
|
84
|
-
.dx-panel--fuchsia {
|
|
85
|
-
@apply bg-fuchsia-surface text-fuchsia-fg border-fuchsia-border;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
[data-hue='pink'] .dx-panel,
|
|
89
|
-
.dx-panel--pink {
|
|
90
|
-
@apply bg-pink-surface text-pink-fg border-pink-border;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
[data-hue='rose'] .dx-panel,
|
|
94
|
-
.dx-panel--rose {
|
|
95
|
-
@apply bg-rose-surface text-rose-fg border-rose-border;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
[data-hue='info'] .dx-panel,
|
|
99
|
-
.dx-panel--info {
|
|
100
|
-
@apply bg-info-surface text-info-fg border-info-border;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
[data-hue='success'] .dx-panel,
|
|
104
|
-
.dx-panel--success {
|
|
105
|
-
@apply bg-success-surface text-success-fg border-success-border;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
[data-hue='warning'] .dx-panel,
|
|
109
|
-
.dx-panel--warning {
|
|
110
|
-
@apply bg-warning-surface text-warning-fg border-warning-border;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
[data-hue='error'] .dx-panel,
|
|
114
|
-
.dx-panel--error {
|
|
115
|
-
@apply bg-error-surface text-error-fg border-error-border;
|
|
116
|
-
}
|
|
117
|
-
}
|