@cueplusplus/ui 0.1.0 → 0.2.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/CHANGELOG.md +684 -0
- package/dist/brand/_chassis.d.ts +54 -0
- package/dist/brand/_chassis.js +81 -0
- package/dist/brand/_geometry.js +41 -0
- package/dist/brand/cue-logotype.d.ts +29 -0
- package/dist/brand/cue-logotype.js +60 -0
- package/dist/brand/cue-mark.d.ts +30 -0
- package/dist/brand/cue-mark.js +61 -0
- package/dist/brand/index.d.ts +5 -0
- package/dist/brand/plussie.d.ts +67 -0
- package/dist/brand/plussie.js +125 -0
- package/dist/chat/agent-pile.js +1 -1
- package/dist/chat/ask-box.js +2 -2
- package/dist/chat/delegation-card.js +1 -1
- package/dist/chat/message.js +2 -2
- package/dist/chrome/_edge-scroller.d.ts +45 -0
- package/dist/chrome/_edge-scroller.js +138 -0
- package/dist/chrome/_glyphs.js +19 -1
- package/dist/chrome/_tabs-scroll.d.ts +12 -7
- package/dist/chrome/_tabs-scroll.js +12 -7
- package/dist/chrome/app-bar.d.ts +103 -0
- package/dist/chrome/app-bar.js +175 -0
- package/dist/chrome/app-shell.d.ts +125 -0
- package/dist/chrome/app-shell.js +167 -0
- package/dist/chrome/footer.d.ts +75 -0
- package/dist/chrome/footer.js +68 -0
- package/dist/chrome/index.d.ts +5 -1
- package/dist/chrome/index.js +4 -1
- package/dist/chrome/navigation-menu.js +1 -1
- package/dist/chrome/page-shell.d.ts +1 -1
- package/dist/chrome/page-shell.js +15 -5
- package/dist/chrome/segmented-control.d.ts +19 -0
- package/dist/chrome/segmented-control.js +40 -21
- package/dist/chrome/tabs.js +21 -65
- package/dist/chrome/toolbar.d.ts +22 -0
- package/dist/chrome/toolbar.js +26 -5
- package/dist/configurator/_overrides.js +4 -2
- package/dist/configurator/configurator.js +1 -1
- package/dist/configurator/panel-sections.js +10 -4
- package/dist/dmx/channel-matrix.js +1 -1
- package/dist/forms/otp-field.js +1 -1
- package/dist/index.d.ts +15 -6
- package/dist/index.js +15 -9
- package/dist/instruments/data-table.js +1 -1
- package/dist/layout/carousel.js +1 -1
- package/dist/layout/container.d.ts +1 -1
- package/dist/layout/container.js +6 -3
- package/dist/layout/index.d.ts +3 -3
- package/dist/layout/index.js +3 -3
- package/dist/layout/pagination.js +1 -1
- package/dist/layout/sidebar.d.ts +23 -3
- package/dist/layout/sidebar.js +18 -7
- package/dist/midi/spectrum-visualizer.js +1 -1
- package/dist/midi/timeline-ruler.js +1 -1
- package/dist/overlays/command-palette.js +1 -1
- package/dist/overlays/dialog.js +1 -1
- package/dist/overlays/dropdown-menu.js +2 -2
- package/dist/overlays/hover-card.js +1 -1
- package/dist/overlays/index.js +1 -1
- package/dist/overlays/popover.js +1 -1
- package/dist/overlays/sheet.js +1 -1
- package/dist/overlays/toast.js +1 -1
- package/dist/primitives/index.d.ts +1 -1
- package/dist/primitives/index.js +1 -1
- package/dist/primitives/status-dot.d.ts +7 -0
- package/dist/primitives/status-dot.js +8 -1
- package/dist/styles.css +47 -1
- package/dist/system/density.d.ts +4 -1
- package/dist/system/density.js +12 -4
- package/dist/system/index.d.ts +2 -2
- package/dist/system/portal.d.ts +5 -5
- package/dist/system/portal.js +11 -6
- package/dist/system/prepaint.d.ts +15 -8
- package/dist/system/prepaint.js +26 -9
- package/dist/system/theme-provider.d.ts +36 -10
- package/dist/system/theme-provider.js +56 -18
- package/dist/system/use-density.d.ts +3 -3
- package/dist/system/use-density.js +16 -6
- package/dist/system/use-theme.d.ts +4 -2
- package/dist/system/use-theme.js +4 -2
- package/dist/theming/_presets.js +80 -5
- package/dist/theming/create-theme.js +13 -4
- package/package.json +4 -3
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
# @cueplusplus/ui
|
|
2
|
+
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 33a95c4: Typeface is a third axis, beside theme and density.
|
|
8
|
+
|
|
9
|
+
`data-font` selects one of eight font pairings — a sans and a monospace — the
|
|
10
|
+
same way `data-theme` selects a palette and `data-density` selects a geometry.
|
|
11
|
+
`<ThemeProvider font>`, `useTheme().font` / `setFont`, persistence beside the
|
|
12
|
+
other two, the pre-paint script, and every portal root carry it.
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
<ThemeProvider theme="cue" density="normal" font="plex">
|
|
16
|
+
<App />
|
|
17
|
+
</ThemeProvider>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
| id | sans | mono | what your app has to do |
|
|
21
|
+
| -------- | ---------------------- | ------------------- | ---------------------------------- |
|
|
22
|
+
| `system` | the platform's UI sans | **the theme's own** | nothing — this is the default |
|
|
23
|
+
| `geist` | Geist | JetBrains Mono | deliver two faces |
|
|
24
|
+
| `inter` | Inter | IBM Plex Mono | deliver two faces |
|
|
25
|
+
| `plex` | IBM Plex Sans | IBM Plex Mono | deliver two faces |
|
|
26
|
+
| `roboto` | Roboto | Roboto Mono | deliver two faces |
|
|
27
|
+
| `source` | Source Sans 3 | Source Code Pro | deliver two faces |
|
|
28
|
+
| `apple` | SF Pro Text | SF Mono | nothing — and nothing you _may_ do |
|
|
29
|
+
| `office` | Calibri (Carlito) | Cascadia Mono | nothing — and nothing you _may_ do |
|
|
30
|
+
|
|
31
|
+
New exports from `@cueplusplus/tokens`: `FONTS`, `FontName`, `DEFAULT_FONT`,
|
|
32
|
+
`FONT_PAIRINGS`, `FONT_FACES`, `FontDelivery`, `FontPairing`, `faceProperty`.
|
|
33
|
+
`prepaintScript()` takes a fourth argument, the default pairing.
|
|
34
|
+
|
|
35
|
+
## You have to load the fonts. We will not.
|
|
36
|
+
|
|
37
|
+
**This package ships no font file and no `@font-face`, and that is deliberate.**
|
|
38
|
+
A library that injected one would be choosing your network requests, your
|
|
39
|
+
content-security policy and your font licensing, in a stylesheet you imported
|
|
40
|
+
for its colours. What a pairing emits instead is a hook with the family name as
|
|
41
|
+
its fallback:
|
|
42
|
+
|
|
43
|
+
```css
|
|
44
|
+
[data-font="inter"] {
|
|
45
|
+
--cue-font-sans: var(--cue-face-inter, Inter), ui-sans-serif, system-ui, …;
|
|
46
|
+
--cue-font-mono:
|
|
47
|
+
var(--cue-face-ibm-plex-mono, "IBM Plex Mono"), ui-monospace, …;
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Assign nothing and the stack still resolves — a local install first, then the
|
|
52
|
+
platform — so no pairing ever renders as nothing. Assign the property and
|
|
53
|
+
everything painted from the token follows. With `next/font`, the property name
|
|
54
|
+
_is_ the option:
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
const inter = Inter({ subsets: ["latin"], display: "swap", preload: false, variable: "--cue-face-inter" });
|
|
58
|
+
<html className={inter.variable}>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`preload: false` matters: with preloading on, a site offering five webfont
|
|
62
|
+
pairings makes every visitor download all of them to render in one.
|
|
63
|
+
`FONT_PAIRINGS[name].faces` is the list of properties one pairing needs;
|
|
64
|
+
`FONT_FACES` is every face at once, as `property → family`.
|
|
65
|
+
|
|
66
|
+
**`apple` and `office` are stacks and must stay stacks.** SF Pro and SF Mono are
|
|
67
|
+
Apple-licensed and may not be served as webfonts; Calibri is Microsoft's and
|
|
68
|
+
ships with Windows and Office rather than with anybody's site (Carlito is its
|
|
69
|
+
metric-compatible libre twin, and is in the stack). They light up where
|
|
70
|
+
installed and fall through cleanly where they are not. Do not bundle them.
|
|
71
|
+
|
|
72
|
+
## A theme's monospace still applies — until somebody picks a pairing
|
|
73
|
+
|
|
74
|
+
Seven presets name a monospace of their own, and seven pairings name one, so
|
|
75
|
+
one token was claimed twice.
|
|
76
|
+
Neither axis writes it now: a theme publishes `--cue-font-theme-mono`, a pairing
|
|
77
|
+
publishes `--cue-font-pairing-mono`, and `--cue-font-mono` resolves the two,
|
|
78
|
+
pairing first. **A chosen pairing wins**, at whatever element each was stamped
|
|
79
|
+
on — a pairing is what a person picked out of a menu and a preset's mono is what
|
|
80
|
+
its author chose in the absence of a person. The default pairing, `system`,
|
|
81
|
+
declines the question, so an app that never touches the axis keeps exactly the
|
|
82
|
+
monospace it has today.
|
|
83
|
+
|
|
84
|
+
## Two things that change without you asking
|
|
85
|
+
|
|
86
|
+
**The base sans no longer names `Geist`.** It named a font this package has
|
|
87
|
+
never delivered, so for almost every visitor it resolved to the next entry
|
|
88
|
+
anyway. `--cue-font-sans` and `--cue-font-display` are now the platform stack;
|
|
89
|
+
Geist is the head of the `geist` pairing, which your app can actually deliver.
|
|
90
|
+
If you want it back, deliver it: `font="geist"` plus the two `--cue-face-*`
|
|
91
|
+
assignments.
|
|
92
|
+
|
|
93
|
+
**A generated theme's mono moves with it.** `createTheme({ fonts: { mono } })`
|
|
94
|
+
now writes `--cue-font-theme-mono`. Nothing to change unless you read the
|
|
95
|
+
generated `tokens` map by key.
|
|
96
|
+
|
|
97
|
+
## Migrating
|
|
98
|
+
|
|
99
|
+
Nothing is required. Two things are worth doing:
|
|
100
|
+
|
|
101
|
+
1. **Pass the pairing to the pre-paint script**, as its fourth argument, if your
|
|
102
|
+
app's default is not `system`:
|
|
103
|
+
`prepaintScript(DEFAULT_STORAGE_KEY, "cue", "normal", "geist")`. A theme that
|
|
104
|
+
arrives one frame late is a flash of the wrong colour; a _family_ that
|
|
105
|
+
arrives one frame late reflows every line under the reader.
|
|
106
|
+
2. **If your own CSS overrides `--cue-font-mono`** under a `[data-theme]` block
|
|
107
|
+
of your own, move it to `--cue-font-theme-mono` — otherwise your override
|
|
108
|
+
beats the typeface picker and yours is the one theme it cannot move.
|
|
109
|
+
|
|
110
|
+
`font` is a root-level prop: there is no font island, and a nested provider
|
|
111
|
+
forwards the axis (and `setFont`) to the root. A specimen that genuinely wants
|
|
112
|
+
one face beside another needs nothing from this library but `data-font` on a
|
|
113
|
+
`<div>`.
|
|
114
|
+
|
|
115
|
+
- 038837d: `AppShell`: the console frame, and the mobile navigation that goes with it.
|
|
116
|
+
|
|
117
|
+
Every console screen is the same five parts in the same arrangement — title bar,
|
|
118
|
+
navigation column, toolbar, one scrolling work area, status bar — and until now
|
|
119
|
+
each one arranged them by hand. `AppShell` is that arrangement, with the
|
|
120
|
+
arithmetic that actually holds it up: `h-dvh` rather than `min-h-dvh`, an
|
|
121
|
+
unbroken `min-h-0` chain from the frame down to the scroller, `min-w-0` on the
|
|
122
|
+
content column, and a scroller that is not the document, so the chrome stays put
|
|
123
|
+
with no `sticky` anywhere.
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
import {
|
|
127
|
+
AppShell,
|
|
128
|
+
Sidebar,
|
|
129
|
+
StatusBar,
|
|
130
|
+
TitleBar,
|
|
131
|
+
Toolbar,
|
|
132
|
+
} from "@cueplusplus/ui";
|
|
133
|
+
|
|
134
|
+
<AppShell.Root>
|
|
135
|
+
<TitleBar center="main-stage.cue">
|
|
136
|
+
<AppShell.NavTrigger />
|
|
137
|
+
</TitleBar>
|
|
138
|
+
<AppShell.Body>
|
|
139
|
+
<AppShell.Sidebar aria-label="Console" drawerTitle="Console">
|
|
140
|
+
<Sidebar.Section label="Show">
|
|
141
|
+
<Sidebar.Item icon={List} active>
|
|
142
|
+
Cues
|
|
143
|
+
</Sidebar.Item>
|
|
144
|
+
</Sidebar.Section>
|
|
145
|
+
</AppShell.Sidebar>
|
|
146
|
+
<AppShell.Content>
|
|
147
|
+
<Toolbar.Root aria-label="Playback">…</Toolbar.Root>
|
|
148
|
+
<AppShell.Scroller>…</AppShell.Scroller>
|
|
149
|
+
</AppShell.Content>
|
|
150
|
+
<AppShell.Aside aria-label="Inspector">…</AppShell.Aside>
|
|
151
|
+
</AppShell.Body>
|
|
152
|
+
<StatusBar>…</StatusBar>
|
|
153
|
+
</AppShell.Root>;
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Seven parts: `Root` (the frame), `Body` (the middle row), `Sidebar` (the
|
|
157
|
+
navigation), `NavTrigger` (the control that opens it on a phone), `Content` (the
|
|
158
|
+
`<main>` column — pass `main={false}` when the shell is embedded in a page that
|
|
159
|
+
already has one), `Scroller` (the only element that may scroll) and `Aside` (a
|
|
160
|
+
trailing column with a scroller of its own). `TitleBar` and `StatusBar` go in as
|
|
161
|
+
ordinary children: both are already `shrink-0`, so a wrapper would only repeat
|
|
162
|
+
that.
|
|
163
|
+
|
|
164
|
+
**`AppShell` is the one component in this library with a viewport breakpoint.**
|
|
165
|
+
`AppShell.Sidebar` renders the same children twice — as the 14rem column at
|
|
166
|
+
Tailwind's stock `md` (48rem) and up, and as a `Drawer` below it, opened by
|
|
167
|
+
`AppShell.NavTrigger` from the bar. It is a CSS-only dual render, both shapes in
|
|
168
|
+
the markup with one hidden per viewport: no `useMediaQuery`, nothing to measure,
|
|
169
|
+
and a first server-rendered frame that is already correct. The switch decides
|
|
170
|
+
navigation shape and nothing else; everything else in the library stays
|
|
171
|
+
intrinsically responsive, and a later component that wants a breakpoint is a new
|
|
172
|
+
decision rather than a precedent this one set.
|
|
173
|
+
|
|
174
|
+
`PageShell` and `Container` now offer the same four measures.
|
|
175
|
+
|
|
176
|
+
`narrow` (42rem) and `wide` (54rem) are unchanged. `broad` (84rem) is new on
|
|
177
|
+
both: the application measure, wide enough for a two-column documentation page
|
|
178
|
+
or a device frame. `full` is new on `PageShell`, which had no uncapped rung at
|
|
179
|
+
all while `Container` did. Nothing existing moves — `narrow` is still the
|
|
180
|
+
default on both.
|
|
181
|
+
|
|
182
|
+
```tsx
|
|
183
|
+
<PageShell width="broad" title="Components">…</PageShell>
|
|
184
|
+
<PageShell width="full" title="Gallery">…</PageShell>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
- 7eeb1c4: New component group, `brand`: the CUE++ marks, as components rather than files.
|
|
188
|
+
|
|
189
|
+
`CueMark` is the circular mark, `CueLogotype` is the wordmark and mark locked up
|
|
190
|
+
at 778:367, and `Plussie` is the character — the same circle and the same two
|
|
191
|
+
`+` glyphs the mark draws, out of the same geometry module, with the eyes in
|
|
192
|
+
their own groups so a pose can move them. All three come from the root barrel
|
|
193
|
+
(`@cueplusplus/ui`), pull no optional peer, and are static markup, so a
|
|
194
|
+
server-rendered header costs no client bundle.
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
import { CueLogotype, CueMark, Plussie } from "@cueplusplus/ui";
|
|
198
|
+
|
|
199
|
+
<CueMark size="sm" />
|
|
200
|
+
<CueLogotype size="lg" title="CUE++" />
|
|
201
|
+
<Plussie size={96} expression="wink" />
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Props on all three: `size` (`"sm" | "md" | "lg"`, or a height in px), which sets
|
|
205
|
+
the height and lets the artwork's ratio decide the width; `tone`
|
|
206
|
+
(`"inherit" | "fg" | "accent"`, default `"inherit"` = `currentColor`); and an
|
|
207
|
+
optional `title`, which turns a decorative `aria-hidden` mark into a labelled
|
|
208
|
+
`role="img"`. `Plussie` adds `expression` (`default`, `blink`, `wink`,
|
|
209
|
+
`look-left`, `look-right`, `look-up`, `look-down` — each one a still from the
|
|
210
|
+
character's own animations) and `idle`, a CSS-only blink that is off by default
|
|
211
|
+
and switched off again under `prefers-reduced-motion`.
|
|
212
|
+
|
|
213
|
+
There is no light/dark pair to choose between. `@cueplusplus/brand-tokens` still
|
|
214
|
+
ships the four source SVGs as files for the places that need a URL — a favicon,
|
|
215
|
+
an `<img>`, an email — and those hard-code `white`, `black` and `#1E1E1E`.
|
|
216
|
+
These components take their ink from the token layer instead, so one element is
|
|
217
|
+
correct in all eight presets and both modes. The path data is the same artwork,
|
|
218
|
+
copied verbatim.
|
|
219
|
+
|
|
220
|
+
- b86f482: The density ladder is five rungs, and the two names in the middle have moved.
|
|
221
|
+
|
|
222
|
+
`ultra-compact` · `normal` · `large` was never a ladder anyone could reason
|
|
223
|
+
about: the rung called `normal` is what every other design system calls
|
|
224
|
+
_compact_, the rung called `large` is what everyone else calls _normal_, and
|
|
225
|
+
above that there was nothing at all — no level for a touch panel, a stage
|
|
226
|
+
monitor, or a reader who needs the whole screen a size up. This renames the two
|
|
227
|
+
misnamed rungs to what they always were and adds the two that were missing.
|
|
228
|
+
|
|
229
|
+
**Minor rather than major because the package is pre-1.0** — 0.x's breaking rung
|
|
230
|
+
is the minor one, and this is breaking.
|
|
231
|
+
|
|
232
|
+
**Read the migration before you upgrade.** One of its four steps is a prop
|
|
233
|
+
rename a compiler catches. The other three are not: CSS of your own keyed on
|
|
234
|
+
`[data-density]`, a label map with one entry per level, and a persisted
|
|
235
|
+
preference all keep working after this release and quietly mean something else.
|
|
236
|
+
|
|
237
|
+
## The mapping
|
|
238
|
+
|
|
239
|
+
| you wrote | you now write | geometry |
|
|
240
|
+
| --------------- | ----------------- | ---------------------------------------------------- |
|
|
241
|
+
| `ultra-compact` | `ultra-compact` | unchanged |
|
|
242
|
+
| `normal` | **`compact`** | **unchanged** — the name moved, not a pixel |
|
|
243
|
+
| `large` | **`normal`** | **unchanged** — the name moved, not a pixel |
|
|
244
|
+
| — | **`large`** | new: a rung above what the ladder used to top out at |
|
|
245
|
+
| — | **`ultra-large`** | new: the top, and the mirror of `ultra-compact` |
|
|
246
|
+
|
|
247
|
+
Nothing that existed changed size. `<ThemeProvider density="normal">` used to
|
|
248
|
+
render 24px controls and now renders 32px ones — not because the geometry moved
|
|
249
|
+
but because `normal` now names the rung above the one it used to name.
|
|
250
|
+
|
|
251
|
+
## Migrating
|
|
252
|
+
|
|
253
|
+
Four things move. Only the first and the last are visible to a compiler; the two
|
|
254
|
+
in the middle are the ones that ship a wrong-looking screen with a green build.
|
|
255
|
+
|
|
256
|
+
### 1. Rename every level you name, one step down the ladder
|
|
257
|
+
|
|
258
|
+
Everywhere you write a density — the provider, a `<Density>` island, a prop you pass
|
|
259
|
+
through, a test:
|
|
260
|
+
|
|
261
|
+
```diff
|
|
262
|
+
-<ThemeProvider theme="cue" density="normal">
|
|
263
|
+
+<ThemeProvider theme="cue" density="compact">
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
```diff
|
|
267
|
+
-<Density density="large">
|
|
268
|
+
+<Density density="normal">
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
`ultra-compact` is unchanged and needs no edit. Do the two renames in that
|
|
272
|
+
order, or in one pass — `normal` → `compact` and `large` → `normal` — and your
|
|
273
|
+
screens render exactly as they did before.
|
|
274
|
+
|
|
275
|
+
**If you never passed a `density`, this step is a no-op.** The default moved
|
|
276
|
+
from `normal` to `compact`, which is the same geometry it always was: an app
|
|
277
|
+
that never chose a level renders identically before and after.
|
|
278
|
+
|
|
279
|
+
### 2. Rename your own `[data-density]` CSS — and add blocks for the two new rungs
|
|
280
|
+
|
|
281
|
+
**This is the half that fails silently.** If your app keys any of its own CSS on
|
|
282
|
+
`data-density` — a per-rung scalar you multiply your lengths by, a per-rung
|
|
283
|
+
override, anything — those selectors still match a valid attribute value after
|
|
284
|
+
this release. They just match a _different rung_. Nothing throws, nothing logs,
|
|
285
|
+
no build fails: your rows simply stop matching the controls inside them.
|
|
286
|
+
|
|
287
|
+
```diff
|
|
288
|
+
:root { --app-type: 1; --app-space: 1; }
|
|
289
|
+
-[data-density="normal"] { --app-type: 1; --app-space: 1; }
|
|
290
|
+
-[data-density="large"] { --app-type: 1.111; --app-space: 1.333; }
|
|
291
|
+
+[data-density="compact"] { --app-type: 1; --app-space: 1; }
|
|
292
|
+
+[data-density="normal"] { --app-type: 1.111; --app-space: 1.333; }
|
|
293
|
+
+/* and two blocks that did not exist before — continue your own step, or read
|
|
294
|
+
+ the ratio off the library's ladder: --cue-density is 0.85 / 1 / 1.3 / 1.6 / 1.9
|
|
295
|
+
+ and the spacing sequence shifts one place per rung. */
|
|
296
|
+
+[data-density="large"] { --app-type: …; --app-space: …; }
|
|
297
|
+
+[data-density="ultra-large"] { --app-type: …; --app-space: …; }
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
What each rung does if you rename the props and stop there:
|
|
301
|
+
|
|
302
|
+
| rung | if you only renamed the props | what the reader sees |
|
|
303
|
+
| --------------- | ----------------------------------------------- | ------------------------------------------------------------------------------- |
|
|
304
|
+
| `ultra-compact` | your `ultra-compact` block still matches | correct |
|
|
305
|
+
| `compact` | **no block matches** — falls through to `:root` | your scalars sit at their base values while the library's geometry is a rung up |
|
|
306
|
+
| `normal` | your old `normal` block matches | your scalars are a rung behind the library's |
|
|
307
|
+
| `large` | your old `large` block matches | your scalars are two rungs behind |
|
|
308
|
+
| `ultra-large` | **no block matches** — falls through to `:root` | base scalars against the largest geometry the ladder has |
|
|
309
|
+
|
|
310
|
+
A rung with no block of yours does not fall back to the nearest one. It falls
|
|
311
|
+
through to whatever `:root` declares, which is almost always the smallest value
|
|
312
|
+
you own. Grep your stylesheets for `data-density` before you upgrade:
|
|
313
|
+
|
|
314
|
+
```sh
|
|
315
|
+
rg 'data-density' --glob '!node_modules'
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### 3. Fix anything that enumerates the ladder
|
|
319
|
+
|
|
320
|
+
A label map, a switcher, a segmented control, a settings screen, a persisted
|
|
321
|
+
preference — anything with one entry per density level is now missing two and
|
|
322
|
+
mis-naming two. A map keyed by the old three names does not error; it returns
|
|
323
|
+
`undefined`, and most switchers render the raw slug:
|
|
324
|
+
|
|
325
|
+
```diff
|
|
326
|
+
const DENSITY_LABELS = {
|
|
327
|
+
"ultra-compact": "Ultra compact",
|
|
328
|
+
- normal: "Normal",
|
|
329
|
+
- large: "Large",
|
|
330
|
+
+ compact: "Compact",
|
|
331
|
+
+ normal: "Normal",
|
|
332
|
+
+ large: "Large",
|
|
333
|
+
+ "ultra-large": "Ultra large",
|
|
334
|
+
};
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
`DENSITIES` from `@cueplusplus/tokens` is the list to derive from rather than
|
|
338
|
+
restate — it is five entries now and it will be right next time too. If your map
|
|
339
|
+
is typed `Record<Density, string>` TypeScript will fail the build for you; if it
|
|
340
|
+
is a plain object literal, nothing will.
|
|
341
|
+
|
|
342
|
+
**A persisted preference that says `"normal"` is now a bigger screen.** The
|
|
343
|
+
provider stores the level under `localStorage` and validates it against the
|
|
344
|
+
ladder, so `"normal"` is still a valid value — it just means a different rung.
|
|
345
|
+
Migrate the stored value the same way you migrate the code, or accept that
|
|
346
|
+
returning users move up one rung once.
|
|
347
|
+
|
|
348
|
+
### 4. `density-ultra:` is now `density-ultra-compact:`
|
|
349
|
+
|
|
350
|
+
The stylesheet registers one Tailwind variant per rung, each named after the
|
|
351
|
+
rung it matches: `density-ultra-compact:`, `density-compact:`,
|
|
352
|
+
`density-normal:`, `density-large:`, `density-ultra-large:`. `density-ultra:` is
|
|
353
|
+
gone, because with an `ultra-large` rung on the ladder "ultra" names neither end
|
|
354
|
+
of it — and an unknown variant is a build error, so this one tells you.
|
|
355
|
+
`density-large:` keeps its name and changes meaning with its rung, which does
|
|
356
|
+
not.
|
|
357
|
+
|
|
358
|
+
## The two new rungs
|
|
359
|
+
|
|
360
|
+
Every axis continues the step the three existing rungs already walk, rather than
|
|
361
|
+
scaling anything by a factor:
|
|
362
|
+
|
|
363
|
+
| | ultra-compact | compact | normal | **large** | **ultra-large** |
|
|
364
|
+
| ---------------- | ------------- | ------- | -------- | ------------ | --------------- |
|
|
365
|
+
| `control-md` | 20px | 24px | 32px | **40px** | **48px** |
|
|
366
|
+
| `chip-h` | 16px | 18px | 22px | **26px** | **30px** |
|
|
367
|
+
| `icon-md` | 10px | 12px | 16px | **20px** | **24px** |
|
|
368
|
+
| `text-body` | 10px | 11px | 13px | **15px** | **17px** |
|
|
369
|
+
| `pad-row` | 2 × 6px | 4 × 8px | 6 × 12px | **8 × 16px** | **10 × 20px** |
|
|
370
|
+
| `chrome-toolbar` | 32px | 36px | 44px | **52px** | **60px** |
|
|
371
|
+
| `--cue-density` | 0.85 | 1 | 1.3 | **1.6** | **1.9** |
|
|
372
|
+
|
|
373
|
+
`large` is a touch and presentation rung: 40px controls clear the WCAG 2.2
|
|
374
|
+
SC 2.5.8 target floor with room to spare. `ultra-large` is for a wall display, a
|
|
375
|
+
kiosk, a stage monitor read from two metres, and for a low-vision reader who
|
|
376
|
+
wants the whole interface a size up rather than the browser's zoom.
|
|
377
|
+
|
|
378
|
+
The `@media (pointer: coarse)` re-raise still applies to `ultra-compact` alone,
|
|
379
|
+
and still raises it to exactly the same heights it always did — `compact`'s.
|
|
380
|
+
`compact` is the rung the raise lands on, so raising it too would mean promoting
|
|
381
|
+
it to `normal` and moving today's default geometry on every touch device.
|
|
382
|
+
|
|
383
|
+
## The type ladder got a top
|
|
384
|
+
|
|
385
|
+
`text-title` and `text-emphasis` are bigger at every rung. `text-micro`,
|
|
386
|
+
`text-label`, `text-ui` and `text-body` are untouched — consoles are built out
|
|
387
|
+
of those four and none of them moves.
|
|
388
|
+
|
|
389
|
+
| | ultra-compact | compact | normal | large | ultra-large |
|
|
390
|
+
| --------------- | ------------- | ------------- | ------------- | -------- | ----------- |
|
|
391
|
+
| `text-emphasis` | 11 → **13px** | 12 → **14px** | 14 → **17px** | **20px** | **23px** |
|
|
392
|
+
| `text-title` | 12 → **16px** | 13 → **18px** | 16 → **22px** | **26px** | **30px** |
|
|
393
|
+
|
|
394
|
+
A page heading was 1.18× a paragraph, which is not a hierarchy — it is six sizes
|
|
395
|
+
within four points of each other, and every screen built on it came out flat. It
|
|
396
|
+
is now 1.6–1.76×, and the whole ladder spans 2× to 2.7× from `micro` to `title`
|
|
397
|
+
depending on the rung. If you set a page title in `text-title` it will look like
|
|
398
|
+
one now; if you were compensating with a hand-written size, delete the
|
|
399
|
+
compensation.
|
|
400
|
+
|
|
401
|
+
## Also
|
|
402
|
+
|
|
403
|
+
`prepaintScript()` takes a third argument, `defaultDensity`, alongside
|
|
404
|
+
`defaultTheme`. An app whose provider names a level other than `compact` should
|
|
405
|
+
pass the same level here, or the first frame paints at one rung and every frame
|
|
406
|
+
after it at another:
|
|
407
|
+
|
|
408
|
+
```tsx
|
|
409
|
+
prepaintScript(DEFAULT_STORAGE_KEY, "cue", "normal");
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
- a382b68: A ninth theme preset, `quotamate`, with a light pair.
|
|
413
|
+
|
|
414
|
+
`THEMES` gains `"quotamate"` and `ThemeName` widens with it, so a consumer can write
|
|
415
|
+
`theme="quotamate"` without a cast. `dist/themes/quotamate.css` is built alongside the other
|
|
416
|
+
eight, and `THEME_PRESETS.quotamate` is available to `createTheme()` and the configurator.
|
|
417
|
+
|
|
418
|
+
```tsx
|
|
419
|
+
<ThemeProvider theme="quotamate" density="ultra-compact" mode="dark">
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
A blue-black ramp at hue 240 under a cyan accent (`#00e5e5`). Not a new design — quotamate is
|
|
423
|
+
a shipping product whose palette was already fixed in a private stylesheet, so the values are
|
|
424
|
+
the same colours in hex that it authored in HSL. Adopting the preset is a no-op for the
|
|
425
|
+
running product rather than a restyle, which is the only reason it can be adopted at all.
|
|
426
|
+
|
|
427
|
+
**Its status hues are deliberately not the accent**, which is where this preset differs from
|
|
428
|
+
`cue`. quotamate's whole job is to say whether an account is usable right now, so `ok`, `warn`
|
|
429
|
+
and `danger` have to stay separable at a glance from the colour that means "interactive" — a
|
|
430
|
+
dashboard where "healthy" and "clickable" are the same green cannot be read quickly.
|
|
431
|
+
|
|
432
|
+
Light drops the accent to a deepened teal (`#0d7d7d`) rather than the near-black the product
|
|
433
|
+
itself used. `#00e5e5` on `#fcfcfc` fails contrast for text and for a hairline rim alike, so
|
|
434
|
+
the product's instinct was right; an accent that is merely dark, though, loses the brand.
|
|
435
|
+
Same hue, enough chroma to read as the product's colour, dark enough to carry white text on a
|
|
436
|
+
filled control.
|
|
437
|
+
|
|
438
|
+
Two tests encoded "eight presets" and were corrected rather than bumped:
|
|
439
|
+
|
|
440
|
+
- `build.test.mjs` listed the theme names, which is the point of that assertion.
|
|
441
|
+
- `disjoint.test.mjs` asserted `sources === 16` as a stand-in for "each preset has a dark and
|
|
442
|
+
a light source". A count is a poor proxy — eight darks and eight lights is 16, and so is
|
|
443
|
+
nine darks and seven lights — and it failed a geometry test for a reason unrelated to
|
|
444
|
+
geometry. It now asserts the pairing directly and will not go stale on the tenth preset.
|
|
445
|
+
|
|
446
|
+
- 236d09b: The bars: `AppBar`, `Footer`, and one overflow behaviour for every strip that can
|
|
447
|
+
outgrow its box.
|
|
448
|
+
|
|
449
|
+
### One overflow behaviour, not three bespoke fixes
|
|
450
|
+
|
|
451
|
+
`Toolbar` had neither wrap nor scroll and its buttons are `shrink-0
|
|
452
|
+
whitespace-nowrap`, so a bar wider than its container ran off the edge with no
|
|
453
|
+
way to reach it. `SegmentedControl` did the same with five segments in a page
|
|
454
|
+
header. Both now scroll, from one module, with the affordance
|
|
455
|
+
`ScrollableTabsList` has shipped since the tab strip was written: a fade mask at
|
|
456
|
+
whichever edge still hides something, and a chevron there — because what sits at
|
|
457
|
+
an overflowing edge is usually the gap _between_ two controls, and fading empty
|
|
458
|
+
space produces nothing anyone can see.
|
|
459
|
+
|
|
460
|
+
```tsx
|
|
461
|
+
<Toolbar.Root aria-label="Playback" /> // scrolls by default
|
|
462
|
+
<Toolbar.Root aria-label="Playback" overflow="clip" /> // the old behaviour
|
|
463
|
+
<SegmentedControl aria-label="View" items={items} overflow="clip" />
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
Not wrapping: every bar here is one rung of the chrome ladder tall and sits in a
|
|
467
|
+
layout that has already subtracted that height, so a bar that quietly becomes
|
|
468
|
+
two rows steals it from the work area. Not a "more" menu: `Toolbar` takes
|
|
469
|
+
arbitrary children and there is no honest conversion from one into a menu item,
|
|
470
|
+
so it would need a parallel data model, a measuring pass on every resize, and it
|
|
471
|
+
would lift the surplus controls out of Base UI's roving-focus group. A bar whose
|
|
472
|
+
controls fit renders exactly as it did before — no mask, no chevrons, no
|
|
473
|
+
compositing layer.
|
|
474
|
+
|
|
475
|
+
`AppBar.Nav` and `ScrollableTabsList` use the same module, so the library has one
|
|
476
|
+
implementation of this and four consumers.
|
|
477
|
+
|
|
478
|
+
### `AppBar` — the horizontal bar
|
|
479
|
+
|
|
480
|
+
```tsx
|
|
481
|
+
<AppBar.Root>
|
|
482
|
+
<AppBar.Brand render={<NextLink href="/" />}>
|
|
483
|
+
<Eyebrow>@cueplusplus/ui</Eyebrow>
|
|
484
|
+
<Chip tone="accent" variant="outline">
|
|
485
|
+
0.1.0
|
|
486
|
+
</Chip>
|
|
487
|
+
</AppBar.Brand>
|
|
488
|
+
|
|
489
|
+
<AppBar.Nav aria-label="Sections">
|
|
490
|
+
<AppBar.Link render={<NextLink href="/docs" />}>
|
|
491
|
+
Getting started
|
|
492
|
+
</AppBar.Link>
|
|
493
|
+
<AppBar.Separator />
|
|
494
|
+
<AppBar.Link render={<NextLink href="/gallery" />} register="strong">
|
|
495
|
+
Gallery
|
|
496
|
+
</AppBar.Link>
|
|
497
|
+
<AppBar.Link
|
|
498
|
+
external
|
|
499
|
+
render={<a href="https://skills.cueplusplus.com" />}
|
|
500
|
+
>
|
|
501
|
+
Skills
|
|
502
|
+
</AppBar.Link>
|
|
503
|
+
</AppBar.Nav>
|
|
504
|
+
|
|
505
|
+
<AppBar.Actions>
|
|
506
|
+
<ThemePicker />
|
|
507
|
+
</AppBar.Actions>
|
|
508
|
+
</AppBar.Root>
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
Sticky, `--cue-chrome-toolbar` tall, brand and actions `shrink-0` with the
|
|
512
|
+
navigation between them giving up the width. `AppBar.Link` is set in one of two
|
|
513
|
+
registers — `muted` is furniture, `strong` is a destination — and `active` is a
|
|
514
|
+
third thing rather than a louder register: accent ink _and_ `aria-current="page"`.
|
|
515
|
+
|
|
516
|
+
This is a **bar**, not a menu: `NavigationMenu` goes inside `AppBar.Nav` when a
|
|
517
|
+
section has children. It is also not `TitleBar`, which is window furniture.
|
|
518
|
+
|
|
519
|
+
**It adds no viewport breakpoint.** `AppShell` still holds the library's only
|
|
520
|
+
one, for navigation shape. A horizontal bar never faces that question: at 390px
|
|
521
|
+
it is the same bar with a shorter window onto the same links.
|
|
522
|
+
|
|
523
|
+
`app-bar.tsx` carries no `"use client"` directive, so the bar renders from a
|
|
524
|
+
server component — which a site header has to, because that is where a framework
|
|
525
|
+
reads its data. The client boundary is around the navigation's scroller alone.
|
|
526
|
+
|
|
527
|
+
### `Footer` — the landmark, the hairline, the measure
|
|
528
|
+
|
|
529
|
+
```tsx
|
|
530
|
+
<Footer
|
|
531
|
+
meta={
|
|
532
|
+
<>
|
|
533
|
+
<span>© 2026 CUE++</span>
|
|
534
|
+
<Link href="/legal">Legal</Link>
|
|
535
|
+
</>
|
|
536
|
+
}
|
|
537
|
+
>
|
|
538
|
+
<Grid minItemWidth="12rem" gap={5}>
|
|
539
|
+
<Stack gap={2}>
|
|
540
|
+
<Eyebrow>Docs</Eyebrow>
|
|
541
|
+
<Link href="/docs">Getting started</Link>
|
|
542
|
+
</Stack>
|
|
543
|
+
</Grid>
|
|
544
|
+
</Footer>
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
The `contentinfo` landmark, a full-bleed hairline, a centred column on the same
|
|
548
|
+
four measures `Container` and `PageShell` offer (`broad` by default), and a
|
|
549
|
+
`meta` slot whose fine print hangs under a rule of its own.
|
|
550
|
+
|
|
551
|
+
Deliberately **not** a link-list component. A complex footer is `Grid` + `Stack`
|
|
552
|
+
- `Link` inside this one — components that already exist, already read the
|
|
553
|
+
density ladder, and already handle a column that is a paragraph rather than a
|
|
554
|
+
list. `Grid`'s `minItemWidth` collapses the columns on a phone with no breakpoint
|
|
555
|
+
and no prop for how many to draw. Static markup, no `"use client"`.
|
|
556
|
+
|
|
557
|
+
- 2c6aca1: `AppShell` and `Sidebar`: the four defects the shell's first independent consumer found, and the landmark it was announcing twice.
|
|
558
|
+
|
|
559
|
+
`AppShell` was drawn from the console specimens. The documentation site is the
|
|
560
|
+
first thing outside them to wear it, and putting a real 30-row navigation and a
|
|
561
|
+
few hundred visually-hidden labels through it turned up four things the
|
|
562
|
+
specimens never could. All four are fixed in the library rather than at the call
|
|
563
|
+
site, which is the whole point of a shell.
|
|
564
|
+
|
|
565
|
+
**Minor rather than major because the package is pre-1.0** — 0.x's breaking rung
|
|
566
|
+
is the minor one, and two of these changes are breaking. The migration is at the
|
|
567
|
+
bottom.
|
|
568
|
+
|
|
569
|
+
**`AppShell.Root` keeps its own `documentScrolls: false` promise.** The frame is
|
|
570
|
+
now `relative overflow-clip`. The flex arithmetic it already had only governs
|
|
571
|
+
boxes in the flow; an absolutely positioned descendant is laid out against its
|
|
572
|
+
containing block, and a frame that is neither positioned nor clipping is not
|
|
573
|
+
one — so the _initial_ containing block was, and the descendant's scrollable
|
|
574
|
+
overflow landed on `<html>`. `.sr-only` is `position: absolute`, so this was an
|
|
575
|
+
everyday case rather than an exotic one: a page carrying 308 hidden labels
|
|
576
|
+
measured a 7,068px document inside a 900px frame with every visible box on
|
|
577
|
+
screen, and a browser scrollbar that scrolled nothing. `clip` rather than
|
|
578
|
+
`hidden`, so the frame is not a scroll container something can shove sideways
|
|
579
|
+
with no scrollbar to put it back. The emitters are fixed too — `StatusDot`,
|
|
580
|
+
`OTPField`, `Message`, `AskBox` and `Sidebar.Item` now position the box their
|
|
581
|
+
hidden label is laid out against, so the leak stops at source as well as at the
|
|
582
|
+
frame.
|
|
583
|
+
|
|
584
|
+
**One navigation, one landmark.** `Sidebar.Root` rendered `<aside>` while
|
|
585
|
+
`AppShell.Sidebar`'s drawer half rendered `<nav>`, so the same navigation
|
|
586
|
+
announced as two different landmarks depending on the viewport — and a call site
|
|
587
|
+
whose column is the site's primary navigation had to hand-patch
|
|
588
|
+
`role="navigation"` over the part. Both halves now take one `landmark` prop:
|
|
589
|
+
|
|
590
|
+
```tsx
|
|
591
|
+
<AppShell.Sidebar aria-label="Console">…</AppShell.Sidebar> {/* <nav>, both shapes */}
|
|
592
|
+
<Sidebar.Root aria-label="Filters" landmark="complementary">…</Sidebar.Root> {/* <aside> */}
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
`"navigation"` is the default, because a column of `Sidebar.Item`s with one of
|
|
596
|
+
them marked `aria-current="page"` is primary navigation and not complementary.
|
|
597
|
+
|
|
598
|
+
**The column scrolls, and the rail does not scroll with it.** `Sidebar.Root` had
|
|
599
|
+
no scroller at all, so a navigation taller than the frame simply lost its last
|
|
600
|
+
rows; the fix is an inner scroller rather than `overflow-y-auto` on the root,
|
|
601
|
+
because `Sidebar.Rail` is `absolute inset-y-0` and would otherwise slide away
|
|
602
|
+
with the third screenful. Its containing block is the root and the scroller is
|
|
603
|
+
the element inside it, so the rail spans the whole column and holds its edge
|
|
604
|
+
however far the sections are scrolled. Measured: a 828px column of navigation in
|
|
605
|
+
a 318px frame, scrolled 400px, rail unmoved and unclipped.
|
|
606
|
+
|
|
607
|
+
**`AppShell.NavTrigger` is a target a finger can hit.** It defaulted to
|
|
608
|
+
`size="sm"` — 20px at normal density — on a control that renders _only_ below
|
|
609
|
+
the `md` breakpoint, which is to say only on a touch screen, under the 24×24
|
|
610
|
+
floor WCAG 2.2 SC 2.5.8 sets. The default is `size="md"` now: 24px at normal and
|
|
611
|
+
large, and 24px at ultra-compact too, where the token layer's
|
|
612
|
+
`@media (pointer: coarse)` rule already lifts the control ladder. It is also
|
|
613
|
+
`shrink-0`, because every other slot in `AppBar` is and this was the one that
|
|
614
|
+
gave — measured at 14px wide in a crowded 390px bar.
|
|
615
|
+
|
|
616
|
+
`Footer` gained no code, but its guidance was wrong in a way that cost a site its
|
|
617
|
+
footer: it listed "inside `AppShell`" under _when not to use_. Inside a shell a
|
|
618
|
+
footer belongs to the content scroller, at the end of the work area — bounded by
|
|
619
|
+
the content column, scrolling with the page. What does not belong is a footer as
|
|
620
|
+
a sibling of the navigation column. `Footer` and `StatusBar` are different
|
|
621
|
+
objects and a shell can carry both.
|
|
622
|
+
|
|
623
|
+
### Migrating
|
|
624
|
+
- **`Sidebar.Root` renders `<nav>`.** A stylesheet or a test selecting
|
|
625
|
+
`aside[data-slot="sidebar"]` needs `[data-slot="sidebar"]`, and a column that
|
|
626
|
+
really is complementary needs `landmark="complementary"`. A call site passing
|
|
627
|
+
`role="navigation"` to work around the old element can drop it.
|
|
628
|
+
- **`Sidebar.Root` has one more element inside it.** Its children are wrapped in
|
|
629
|
+
`[data-slot="sidebar-scroller"]`, which now carries the column's padding and
|
|
630
|
+
gap. A `> *` selector aimed at the sections needs re-aiming; `overflow-y-auto`
|
|
631
|
+
passed in at the call site can go.
|
|
632
|
+
- **`AppShell.NavTrigger` is 4px bigger.** Pass `size="sm"` back if a bar really
|
|
633
|
+
needs the old height, and read WCAG 2.5.8 first.
|
|
634
|
+
|
|
635
|
+
### Patch Changes
|
|
636
|
+
|
|
637
|
+
- 6ce0c7d: The release notes now ship inside the package.
|
|
638
|
+
|
|
639
|
+
`files` was `dist` alone, so the `CHANGELOG.md` this repository writes on every
|
|
640
|
+
release stayed in a private git repository and reached nobody: `npm pack` left it
|
|
641
|
+
out, and the tarball a consumer installs from GitHub Packages carried the code
|
|
642
|
+
with no record of what had changed in it. Anyone asking "what moved between the
|
|
643
|
+
version I have and the version I am upgrading to" had to have access to the
|
|
644
|
+
source repository to find out.
|
|
645
|
+
|
|
646
|
+
`CHANGELOG.md` is now on the `files` allowlist of all three published packages,
|
|
647
|
+
so it lands in `node_modules/@cueplusplus/<package>/CHANGELOG.md` beside the code
|
|
648
|
+
it describes. `packages/release` has the test that keeps it there.
|
|
649
|
+
|
|
650
|
+
No code changes and no API changes — the same `dist`, plus one file.
|
|
651
|
+
|
|
652
|
+
The same notes are published, alongside the CUE++ agent skills' own, at
|
|
653
|
+
<https://skills.cueplusplus.com/releases>.
|
|
654
|
+
|
|
655
|
+
- Updated dependencies [33a95c4]
|
|
656
|
+
- Updated dependencies [b86f482]
|
|
657
|
+
- Updated dependencies [a382b68]
|
|
658
|
+
- Updated dependencies [6ce0c7d]
|
|
659
|
+
- @cueplusplus/tokens@0.2.0
|
|
660
|
+
|
|
661
|
+
## 0.1.0
|
|
662
|
+
|
|
663
|
+
### Minor Changes
|
|
664
|
+
|
|
665
|
+
- First release of the CUE++ design system.
|
|
666
|
+
|
|
667
|
+
`@cueplusplus/tokens` ships eight theme presets (`cue`, `terminal`, `signal`, `venu`, `hivehub`,
|
|
668
|
+
`dusk`, `luma`, `snuffle`) in dark and light, three density levels (`ultra-compact`, `normal`,
|
|
669
|
+
`large`), and the Tailwind v4 `@theme inline` mapping — colour scoped to `[data-theme]`, geometry to
|
|
670
|
+
`[data-density]`, never mixed.
|
|
671
|
+
|
|
672
|
+
`@cueplusplus/ui` ships 146 components on Base UI: the core entry plus the `/layout`, `/forms`,
|
|
673
|
+
`/overlays`, `/chrome`, `/instruments`, `/chat`, `/theming`, `/configurator`, `/color`, `/date`
|
|
674
|
+
subpaths and the four opt-in ones (`/charts`, `/dmx`, `/midi`, `/flow`) whose heavy dependencies stay
|
|
675
|
+
optional peers. `ThemeProvider`, the density islands, `createTheme()` with its contrast report and the
|
|
676
|
+
floating `ThemeConfigurator` come with it.
|
|
677
|
+
|
|
678
|
+
`@cueplusplus/brand-tokens` ships the CUE++ brand layer — the white-alpha ramp, the mono stack, the
|
|
679
|
+
eyebrow and motion treatments, and the wordmark and Plussie marks.
|
|
680
|
+
|
|
681
|
+
### Patch Changes
|
|
682
|
+
|
|
683
|
+
- Updated dependencies
|
|
684
|
+
- @cueplusplus/tokens@0.1.0
|