@cueplusplus/ui 0.19.0 → 0.20.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.
Files changed (79) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/dist/brand/index.d.ts +3 -1
  3. package/dist/brand/particle-logo.d.ts +50 -0
  4. package/dist/brand/particle-logo.js +445 -0
  5. package/dist/brand/text-scramble.d.ts +42 -0
  6. package/dist/brand/text-scramble.js +160 -0
  7. package/dist/chat/delegation-card.js +2 -1
  8. package/dist/chat/message.js +12 -13
  9. package/dist/color/color-area.js +2 -1
  10. package/dist/forms/_chassis.d.ts +1 -1
  11. package/dist/forms/_chassis.js +2 -2
  12. package/dist/forms/env-var-input.js +2 -1
  13. package/dist/forms/file-upload.js +2 -1
  14. package/dist/index.d.ts +5 -1
  15. package/dist/index.js +5 -1
  16. package/dist/instruments/data-table.js +3 -2
  17. package/dist/instruments/table.js +1 -1
  18. package/dist/layout/index.d.ts +2 -1
  19. package/dist/layout/index.js +2 -1
  20. package/dist/layout/reveal.d.ts +44 -0
  21. package/dist/layout/reveal.js +112 -0
  22. package/dist/lib/cn.js +23 -5
  23. package/dist/lib/particle-field-shaders.js +236 -0
  24. package/dist/lib/particle-field.js +210 -0
  25. package/dist/midi/spectrum-visualizer.js +2 -1
  26. package/dist/primitives/chip.js +4 -3
  27. package/dist/styles.css +12 -0
  28. package/dist/system/_style-field-chassis.js +14 -1
  29. package/dist/system/frame-clock.d.ts +33 -0
  30. package/dist/system/frame-clock.js +56 -0
  31. package/dist/system/index.d.ts +2 -1
  32. package/dist/system/index.js +2 -1
  33. package/dist/system/still.js +14 -1
  34. package/dist/system/theme-registry.d.ts +1 -1
  35. package/dist/system/theme-registry.js +1 -1
  36. package/manifest/components/autocomplete.json +1 -0
  37. package/manifest/components/bento.json +4 -4
  38. package/manifest/components/color-area.json +10 -0
  39. package/manifest/components/color-field.json +3 -0
  40. package/manifest/components/color-picker.json +3 -0
  41. package/manifest/components/combobox.json +1 -0
  42. package/manifest/components/composer.json +3 -0
  43. package/manifest/components/data-table-pagination.json +3 -0
  44. package/manifest/components/data-table-toolbar.json +3 -0
  45. package/manifest/components/date-field.json +3 -0
  46. package/manifest/components/date-picker.json +3 -0
  47. package/manifest/components/date-range-picker.json +3 -0
  48. package/manifest/components/delegation-card.json +6 -0
  49. package/manifest/components/env-var-input.json +3 -0
  50. package/manifest/components/file-upload.json +5 -0
  51. package/manifest/components/font-scope.json +3 -2
  52. package/manifest/components/grid.json +2 -2
  53. package/manifest/components/input-group.json +3 -0
  54. package/manifest/components/input.json +3 -0
  55. package/manifest/components/ledger.json +1 -1
  56. package/manifest/components/markdown-text.json +1 -1
  57. package/manifest/components/message.json +8 -0
  58. package/manifest/components/multi-select.json +1 -0
  59. package/manifest/components/musical-time-input.json +3 -0
  60. package/manifest/components/number-field.json +3 -0
  61. package/manifest/components/otp-field.json +3 -0
  62. package/manifest/components/particle-logo.json +140 -0
  63. package/manifest/components/password-input.json +3 -0
  64. package/manifest/components/preview.json +3 -2
  65. package/manifest/components/reveal.json +108 -0
  66. package/manifest/components/scrub-input.json +3 -0
  67. package/manifest/components/search-input.json +3 -0
  68. package/manifest/components/select.json +3 -0
  69. package/manifest/components/spectrum-visualizer.json +10 -0
  70. package/manifest/components/stack.json +1 -1
  71. package/manifest/components/table.json +1 -1
  72. package/manifest/components/tags-input.json +1 -0
  73. package/manifest/components/text-scramble.json +90 -0
  74. package/manifest/components/textarea.json +3 -0
  75. package/manifest/components/theme-provider.json +3 -2
  76. package/manifest/components/time-field.json +3 -0
  77. package/manifest/manifest.json +118 -42
  78. package/manifest/tokens.json +4 -2
  79. package/package.json +6 -4
@@ -136,6 +136,7 @@
136
136
  "--cue-paint-stroke-to",
137
137
  "--cue-paint-stroke-width",
138
138
  "--cue-radius-control",
139
+ "--cue-radius-scale",
139
140
  "--cue-space-1",
140
141
  "--cue-space-2",
141
142
  "--cue-space-3",
@@ -143,6 +144,7 @@
143
144
  "--cue-space-5",
144
145
  "--cue-style-body-weight",
145
146
  "--cue-style-check-edge",
147
+ "--cue-style-control-radius",
146
148
  "--cue-style-control-step-size",
147
149
  "--cue-style-disabled-edge",
148
150
  "--cue-style-disabled-fill",
@@ -151,6 +153,7 @@
151
153
  "--cue-style-field-focus-offset",
152
154
  "--cue-style-field-hover-edge",
153
155
  "--cue-style-field-pad",
156
+ "--cue-style-field-radius",
154
157
  "--cue-style-focus-edge",
155
158
  "--cue-style-focus-width",
156
159
  "--cue-style-input-face",
@@ -0,0 +1,140 @@
1
+ {
2
+ "name": "ParticleLogo",
3
+ "slug": "particle-logo",
4
+ "group": "brand",
5
+ "importPath": "@cueplusplus/ui",
6
+ "peerDependencies": [],
7
+ "clientOnly": true,
8
+ "description": "A mark drawn as a field of particles that wiggle, flip colour in sweeping waves and scatter\nfrom the pointer — cueplusplus.com's hero logo, ported from three.js to raw WebGL2 with its\nshaders unchanged (spec 2026-10-04-cue-site-verbatim §4.1).\n\nThe camera, the mesh scale, the textures, the blending and the wave and touch timings are the\nsource's, copied: a 50° camera at z = 300, the mark 26% of the canvas's height, a wave every\n4–8s that sweeps in 2s and fades to white over 3s, a pointer trail that ages over 80 rendered\nupdates. It renders at about 30fps and costs nothing off screen or in a hidden tab.\n\n**Without WebGL2, or held still** (a thumbnail, or a reader who prefers reduced motion), it\ndraws the source image itself, still, at the same fit — a picture of the mark rather than of\nthe particles, which the docs say. A lost context draws the still until it is restored.\n\nDecorative: the canvas is hidden from assistive technology; name the mark on the element\naround it.",
9
+ "props": [
10
+ {
11
+ "name": "src",
12
+ "type": "string",
13
+ "required": true,
14
+ "defaultValue": null,
15
+ "description": "The mark to draw in particles: an image URL, PNG or SVG, light on transparent or on black.",
16
+ "control": {
17
+ "kind": "string"
18
+ }
19
+ },
20
+ {
21
+ "name": "fit",
22
+ "type": "\"logo\" | \"contain\"",
23
+ "required": false,
24
+ "defaultValue": "logo",
25
+ "description": "`logo` (the default): the mark is 26% of the canvas's height, as cueplusplus.com's hero\ndraws it. `contain`: the mark fits inside the canvas, scaled by `containFill`.",
26
+ "control": {
27
+ "kind": "enum",
28
+ "members": [
29
+ "logo",
30
+ "contain"
31
+ ]
32
+ }
33
+ },
34
+ {
35
+ "name": "containFill",
36
+ "type": "number",
37
+ "required": false,
38
+ "defaultValue": "0.85",
39
+ "description": "How much of the canvas a `contain` mark fills. Defaults to `0.85`.",
40
+ "control": {
41
+ "kind": "number"
42
+ }
43
+ },
44
+ {
45
+ "name": "particleSize",
46
+ "type": "number",
47
+ "required": false,
48
+ "defaultValue": "0.5",
49
+ "description": "Each particle's size. Defaults to `0.5`.",
50
+ "control": {
51
+ "kind": "number"
52
+ }
53
+ },
54
+ {
55
+ "name": "randomSpread",
56
+ "type": "number",
57
+ "required": false,
58
+ "defaultValue": "2",
59
+ "description": "How far particles scatter from their pixel. Defaults to `2`.",
60
+ "control": {
61
+ "kind": "number"
62
+ }
63
+ },
64
+ {
65
+ "name": "skipRatio",
66
+ "type": "number",
67
+ "required": false,
68
+ "defaultValue": "36",
69
+ "description": "One particle every this many pixels of the 600px-wide raster. Defaults to `36`.",
70
+ "control": {
71
+ "kind": "number"
72
+ }
73
+ },
74
+ {
75
+ "name": "waveColors",
76
+ "type": "readonly string[]",
77
+ "required": false,
78
+ "defaultValue": null,
79
+ "description": "The colours a wave sweeps the mark into, as hex. Defaults to the Look's own accent and\nsignal colours, read off the element; cueplusplus.com passes its eight. A palette with\nnothing different to offer falls back to the default.",
80
+ "control": {
81
+ "kind": "array",
82
+ "fixture": "agent.transcript"
83
+ }
84
+ }
85
+ ],
86
+ "typeReferences": [
87
+ "Omit<React.ComponentPropsWithoutRef<\"div\">, \"children\">"
88
+ ],
89
+ "subcomponents": [],
90
+ "parts": [],
91
+ "variants": {},
92
+ "defaultVariants": {},
93
+ "tokensUsed": [
94
+ "--cue-accent",
95
+ "--cue-busy",
96
+ "--cue-danger",
97
+ "--cue-fg",
98
+ "--cue-info",
99
+ "--cue-ok",
100
+ "--cue-stream",
101
+ "--cue-warn"
102
+ ],
103
+ "summary": "A mark drawn as a field of particles that wiggle, flip colour in sweeping waves and scatter from the pointer — cueplusplus.com's hero logo, in WebGL2.",
104
+ "examples": [
105
+ {
106
+ "title": "Usage",
107
+ "code": "<div role=\"img\" aria-label=\"CUE++\" className=\"h-[460px]\">\n <ParticleLogo src=\"/logo.png\" />\n</div>",
108
+ "language": "tsx"
109
+ }
110
+ ],
111
+ "status": "stable",
112
+ "url": "/docs/components/particle-logo",
113
+ "mdUrl": "/docs/components/particle-logo.md",
114
+ "jsonUrl": "/r/components/particle-logo.json",
115
+ "whenToUse": [
116
+ "A product or studio site's hero, where the mark is the first thing a visitor sees and touches.",
117
+ "A brand moment that should answer the pointer, at about 30fps and nothing off screen."
118
+ ],
119
+ "whenNotToUse": [
120
+ "A logo in a header, a footer or a list: use the image itself. This is one canvas per page, sized to its container.",
121
+ "Anywhere the mark must be read by assistive technology: it is decorative. Name it on the element around it, as `role=\"img\" aria-label`."
122
+ ],
123
+ "commonMistakes": [
124
+ "Passing a dark mark on a transparent ground. It samples bright or opaque pixels, as the site does, so a light mark (white on transparent or on black) is what it draws.",
125
+ "Expecting particles in a thumbnail or for a reader who prefers reduced motion. Held still, or without WebGL2, it draws the source image instead.",
126
+ "Leaving `waveColors` unset and expecting cueplusplus.com's neon. By default the waves are the Look's own accent and signal colours; pass the eight hexes for the site's."
127
+ ],
128
+ "specimens": [
129
+ {
130
+ "title": "ParticleLogo",
131
+ "group": "brand",
132
+ "components": [
133
+ "ParticleLogo"
134
+ ],
135
+ "code": "<div role=\"img\" aria-label=\"CUE++\" className=\"h-48 w-full max-w-[32rem]\">\n <ParticleLogo src={CUE_LOGO_PNG} />\n</div>",
136
+ "note": "A mark as a field of particles that wiggle, flip colour in sweeping waves and scatter from the pointer — cueplusplus.com's hero logo, in WebGL2. Off screen or in a hidden tab it stops; held still, or without WebGL2, it draws the image itself.",
137
+ "interaction": "move the pointer over the mark to scatter it. Prefer reduced motion and it draws the still image."
138
+ }
139
+ ]
140
+ }
@@ -146,11 +146,13 @@
146
146
  "--cue-paint-stroke-to",
147
147
  "--cue-paint-stroke-width",
148
148
  "--cue-radius-control",
149
+ "--cue-radius-scale",
149
150
  "--cue-space-3",
150
151
  "--cue-space-4",
151
152
  "--cue-space-5",
152
153
  "--cue-style-body-weight",
153
154
  "--cue-style-check-edge",
155
+ "--cue-style-control-radius",
154
156
  "--cue-style-control-step-size",
155
157
  "--cue-style-disabled-edge",
156
158
  "--cue-style-disabled-fill",
@@ -159,6 +161,7 @@
159
161
  "--cue-style-field-focus-offset",
160
162
  "--cue-style-field-hover-edge",
161
163
  "--cue-style-field-pad",
164
+ "--cue-style-field-radius",
162
165
  "--cue-style-focus-edge",
163
166
  "--cue-style-focus-width",
164
167
  "--cue-style-input-face",
@@ -72,7 +72,7 @@
72
72
  },
73
73
  {
74
74
  "name": "font",
75
- "type": "\"source\" | \"system\" | \"geist\" | \"geist-mono\" | \"inter\" | \"plex\" | \"roboto\" | \"apple\" | \"office\" | \"inter-source\" | \"dm\" | \"calsans\" | \"fraunces-mono\"",
75
+ "type": "\"source\" | \"system\" | \"geist\" | \"geist-mono\" | \"inter\" | \"plex\" | \"roboto\" | \"apple\" | \"office\" | \"inter-source\" | \"dm\" | \"calsans\" | \"fraunces-mono\" | \"jetbrains-mono\"",
76
76
  "required": false,
77
77
  "defaultValue": null,
78
78
  "description": "A font pairing for the stage only, stamped as `data-font` and republished to\nReact, so an overlay opened on the stage wears the stage's pairing rather\nthan the page's, and `useTheme().font` read on the stage reports it. The\nstage also takes `font-sans` when a pairing is named: `data-font` re-declares\nthe family's custom properties, but `font-family` inherits as an already\ncomputed value, so unclassed text on the stage would otherwise keep the\nfamily it resolved above it. Unset, the stage inherits and adds neither.",
@@ -91,7 +91,8 @@
91
91
  "inter-source",
92
92
  "dm",
93
93
  "calsans",
94
- "fraunces-mono"
94
+ "fraunces-mono",
95
+ "jetbrains-mono"
95
96
  ]
96
97
  }
97
98
  },
@@ -0,0 +1,108 @@
1
+ {
2
+ "name": "Reveal",
3
+ "slug": "reveal",
4
+ "group": "layout",
5
+ "importPath": "@cueplusplus/ui",
6
+ "peerDependencies": [],
7
+ "clientOnly": true,
8
+ "description": "Content that rises into place the first time it scrolls into view —\ncueplusplus.com's section entrance, ported (spec 2026-10-04-cue-site-verbatim\n§4.3): framer-motion's `whileInView` with `viewport: { once: true }`, from\n`opacity: 0` and `distance` px down, over `duration` ms `easeOut`.\n\nNo motion library: an `IntersectionObserver` and two inline styles. It\nwatches once and lets go. Held still, or for a reader who prefers reduced\nmotion, the content is simply there and nothing is observed — as the site's\n`initial={reduce ? false : …}` does.",
9
+ "props": [
10
+ {
11
+ "name": "distance",
12
+ "type": "number",
13
+ "required": false,
14
+ "defaultValue": "28",
15
+ "description": "How far below its resting place the content starts, in px. Defaults to `28`, the site's services blocks.",
16
+ "control": {
17
+ "kind": "number"
18
+ }
19
+ },
20
+ {
21
+ "name": "rootMargin",
22
+ "type": "string",
23
+ "required": false,
24
+ "defaultValue": "-12% 0px",
25
+ "description": "How far inside the viewport the entry line sits, as an `IntersectionObserver`\nroot margin. Defaults to `\"-12% 0px\"`, the site's services blocks; its\nbeliefs use `\"-15% 0px\"`.",
26
+ "control": {
27
+ "kind": "string"
28
+ }
29
+ },
30
+ {
31
+ "name": "duration",
32
+ "type": "number",
33
+ "required": false,
34
+ "defaultValue": "500",
35
+ "description": "How long the entrance takes, in ms. Defaults to `500`.",
36
+ "control": {
37
+ "kind": "number"
38
+ }
39
+ },
40
+ {
41
+ "name": "stagger",
42
+ "type": "number",
43
+ "required": false,
44
+ "defaultValue": "0",
45
+ "description": "The delay between items, in ms. `0` (the default) moves the whole block as\none. Anything else leaves the block still and moves only the descendants\nmarked `data-reveal-item`, this many ms apart, in document order — the\nsite's beliefs stagger their two columns 80ms apart, and nothing inside\nthem.",
46
+ "control": {
47
+ "kind": "number"
48
+ }
49
+ },
50
+ {
51
+ "name": "children",
52
+ "type": "ReactNode",
53
+ "required": false,
54
+ "defaultValue": null,
55
+ "description": "What rises into place: the block itself, or the items in it marked `data-reveal-item`.",
56
+ "control": {
57
+ "kind": "node",
58
+ "fixture": "children.text"
59
+ }
60
+ }
61
+ ],
62
+ "typeReferences": [
63
+ "React.ComponentPropsWithoutRef<\"div\">"
64
+ ],
65
+ "subcomponents": [],
66
+ "parts": [],
67
+ "variants": {},
68
+ "defaultVariants": {},
69
+ "tokensUsed": [
70
+ "--cue-reveal-distance"
71
+ ],
72
+ "summary": "Content that rises into place the first time it scrolls into view, once — cueplusplus.com's section entrance, with an optional stagger over the items you mark.",
73
+ "examples": [
74
+ {
75
+ "title": "Usage",
76
+ "code": "<Reveal distance={22} rootMargin=\"-15% 0px\" stagger={80}>\n <div data-reveal-item>Stance</div>\n <div data-reveal-item>Reason</div>\n</Reveal>",
77
+ "language": "tsx"
78
+ }
79
+ ],
80
+ "status": "stable",
81
+ "url": "/docs/components/reveal",
82
+ "mdUrl": "/docs/components/reveal.md",
83
+ "jsonUrl": "/r/components/reveal.json",
84
+ "whenToUse": [
85
+ "Sections of a long marketing or product page that should arrive as the reader reaches them.",
86
+ "A pair of columns that should land one after the other: mark each with `data-reveal-item` and set `stagger`."
87
+ ],
88
+ "whenNotToUse": [
89
+ "Above the fold, where the content is already in view: it would only flicker in.",
90
+ "Application screens, forms and anything a reader returns to: motion that repeats on every visit is noise there, and Reveal plays once per mount."
91
+ ],
92
+ "commonMistakes": [
93
+ "Marking every descendant with `data-reveal-item`. The stagger is for a few large items; bullets and words should arrive with their block.",
94
+ "Leaving the default root margin on a short container. `-12% 0px` waits until the content is well inside the viewport; pass `0px` for content near the bottom of a page."
95
+ ],
96
+ "specimens": [
97
+ {
98
+ "title": "Reveal",
99
+ "group": "layout",
100
+ "components": [
101
+ "Reveal"
102
+ ],
103
+ "code": "<Reveal rootMargin=\"0px\" stagger={80} className=\"grid gap-(--cue-space-3) sm:grid-cols-2\">\n <Panel data-reveal-item=\"\" className=\"p-(--cue-space-4)\">Stance</Panel>\n <Panel data-reveal-item=\"\" className=\"p-(--cue-space-4)\">Reason</Panel>\n</Reveal>",
104
+ "note": "Content that rises into place the first time it scrolls into view, once — cueplusplus.com's section entrance. `stagger` moves only the items it marks.",
105
+ "interaction": "none. Prefer reduced motion, or hold it still, and the content is simply there."
106
+ }
107
+ ]
108
+ }
@@ -231,12 +231,14 @@
231
231
  "--cue-paint-stroke-to",
232
232
  "--cue-paint-stroke-width",
233
233
  "--cue-radius-control",
234
+ "--cue-radius-scale",
234
235
  "--cue-space-2",
235
236
  "--cue-space-3",
236
237
  "--cue-space-4",
237
238
  "--cue-space-5",
238
239
  "--cue-style-body-weight",
239
240
  "--cue-style-check-edge",
241
+ "--cue-style-control-radius",
240
242
  "--cue-style-control-step-size",
241
243
  "--cue-style-disabled-edge",
242
244
  "--cue-style-disabled-fill",
@@ -245,6 +247,7 @@
245
247
  "--cue-style-field-focus-offset",
246
248
  "--cue-style-field-hover-edge",
247
249
  "--cue-style-field-pad",
250
+ "--cue-style-field-radius",
248
251
  "--cue-style-focus-edge",
249
252
  "--cue-style-focus-width",
250
253
  "--cue-style-input-face",
@@ -170,11 +170,13 @@
170
170
  "--cue-paint-stroke-to",
171
171
  "--cue-paint-stroke-width",
172
172
  "--cue-radius-control",
173
+ "--cue-radius-scale",
173
174
  "--cue-space-3",
174
175
  "--cue-space-4",
175
176
  "--cue-space-5",
176
177
  "--cue-style-body-weight",
177
178
  "--cue-style-check-edge",
179
+ "--cue-style-control-radius",
178
180
  "--cue-style-control-step-size",
179
181
  "--cue-style-disabled-edge",
180
182
  "--cue-style-disabled-fill",
@@ -183,6 +185,7 @@
183
185
  "--cue-style-field-focus-offset",
184
186
  "--cue-style-field-hover-edge",
185
187
  "--cue-style-field-pad",
188
+ "--cue-style-field-radius",
186
189
  "--cue-style-focus-edge",
187
190
  "--cue-style-focus-width",
188
191
  "--cue-style-input-face",
@@ -220,6 +220,7 @@
220
220
  "--cue-paint-stroke-width",
221
221
  "--cue-radius-control",
222
222
  "--cue-radius-overlay",
223
+ "--cue-radius-scale",
223
224
  "--cue-space-1",
224
225
  "--cue-space-2",
225
226
  "--cue-space-3",
@@ -228,6 +229,7 @@
228
229
  "--cue-style-body-weight",
229
230
  "--cue-style-check-edge",
230
231
  "--cue-style-control-face",
232
+ "--cue-style-control-radius",
231
233
  "--cue-style-control-step-size",
232
234
  "--cue-style-disabled-edge",
233
235
  "--cue-style-disabled-fill",
@@ -236,6 +238,7 @@
236
238
  "--cue-style-field-focus-offset",
237
239
  "--cue-style-field-hover-edge",
238
240
  "--cue-style-field-pad",
241
+ "--cue-style-field-radius",
239
242
  "--cue-style-focus-edge",
240
243
  "--cue-style-focus-width",
241
244
  "--cue-style-glyph-ink",
@@ -113,10 +113,20 @@
113
113
  "defaultVariants": {},
114
114
  "tokensUsed": [
115
115
  "--cue-border",
116
+ "--cue-border-strong",
117
+ "--cue-danger",
116
118
  "--cue-data-ground",
117
119
  "--cue-font-mono",
118
120
  "--cue-radius-control",
121
+ "--cue-radius-scale",
119
122
  "--cue-space-1",
123
+ "--cue-space-3",
124
+ "--cue-space-4",
125
+ "--cue-space-5",
126
+ "--cue-style-control-radius",
127
+ "--cue-style-field-hover-edge",
128
+ "--cue-style-field-pad",
129
+ "--cue-style-field-radius",
120
130
  "--cue-text-micro"
121
131
  ],
122
132
  "summary": "The FFT, drawn: one bar per frequency band, or one line across all of them.",
@@ -23,7 +23,7 @@
23
23
  },
24
24
  {
25
25
  "name": "gap",
26
- "type": "0 | 1 | 4 | 8 | 2 | 3 | 5 | 6 | 7",
26
+ "type": "0 | 1 | 2 | 4 | 8 | 3 | 5 | 6 | 7",
27
27
  "required": false,
28
28
  "defaultValue": "4",
29
29
  "description": "Which rung of the density space ladder to spend between children. Defaults to `4`.",
@@ -104,7 +104,7 @@
104
104
  },
105
105
  {
106
106
  "name": "headingLevel",
107
- "type": "4 | 2 | 3 | 5 | 6",
107
+ "type": "2 | 4 | 3 | 5 | 6",
108
108
  "required": false,
109
109
  "defaultValue": null,
110
110
  "description": "Make the label slot a real heading element. Defaults to `undefined` — no\nheading, and the label stays the `<span>` it has always been.\n\n**Set this rather than passing a heading as `label`.** The label slot wraps\nwhatever it is given, so an `<h2>` handed in as `label` lands *inside* a\n`<span>` — which renders, and exposes the heading, and does not validate: a\n`<span>` is phrasing content and may not contain a heading. With this prop\nthe wrapper *is* the heading (`<h2 data-slot=\"table-group-label\">`), so\nthere is nothing to nest.\n\nA heading inside a `<th>` is valid — `<th>` takes flow content — and it is\nuseful: a screen-reader user navigates a long grouped table by heading, and\nwithout one the group names are reachable only by walking the rows. The\n`scope=\"rowgroup\"` association is untouched either way; this adds the\ndivider to the document outline, it does not change what the cell heads.\n\nLevels run `2`–`6` because the outline has to describe the real nesting of\nthe page the table sits in, not the table's own idea of itself — the same\nruling as {@link LedgerTierProps.headingLevel }. There is no `1`: a group\ndivider is never the title of the document.",
@@ -271,6 +271,7 @@
271
271
  "--cue-style-field-focus-offset",
272
272
  "--cue-style-field-hover-edge",
273
273
  "--cue-style-field-pad",
274
+ "--cue-style-field-radius",
274
275
  "--cue-style-focus-edge",
275
276
  "--cue-style-focus-width",
276
277
  "--cue-style-glyph-ink",
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "TextScramble",
3
+ "slug": "text-scramble",
4
+ "group": "brand",
5
+ "importPath": "@cueplusplus/ui",
6
+ "peerDependencies": [],
7
+ "clientOnly": true,
8
+ "description": "A line that cycles through phrases, scrambling each one in — cueplusplus.com's\n\"what we do\" cycler, ported verbatim (`what-we-do.tsx`; spec\n2026-10-04-cue-site-verbatim §4.2).\n\nEach frame, every character not yet locked shows a random glyph from the\neffect's set; spaces are never scrambled; characters lock left to right. A\nphrase holds for 1.8s once it has revealed, so a long phrase and a slow effect\nstill finish before the next begins: the next starts after\n`length × revealEvery × speed + 1800ms`.\n\n**Reduced motion** shows each phrase whole, one every 2.6s, as the site does.\n**Held still** (a gallery thumbnail, under a still `StillProvider`) shows the\nfirst phrase and schedules nothing, which is this library's departure from the\nsource: a thumbnail costs nothing at rest. The text is written straight into\nthe DOM node, as the source does, so thirty-five frames a second never\nre-render React.",
9
+ "props": [
10
+ {
11
+ "name": "phrases",
12
+ "type": "readonly string[]",
13
+ "required": true,
14
+ "defaultValue": null,
15
+ "description": "The phrases to cycle through, in order, looping. The first is what renders before any script runs.",
16
+ "control": {
17
+ "kind": "array",
18
+ "fixture": "agent.transcript"
19
+ }
20
+ },
21
+ {
22
+ "name": "label",
23
+ "type": "string",
24
+ "required": true,
25
+ "defaultValue": null,
26
+ "description": "What assistive technology reads instead of the animation: one sentence that\nnames the whole cycle. The animated text is hidden from it, because a\nscramble read aloud is noise.",
27
+ "control": {
28
+ "kind": "string"
29
+ }
30
+ },
31
+ {
32
+ "name": "effect",
33
+ "type": "\"matrix\" | \"flap\"",
34
+ "required": false,
35
+ "defaultValue": "matrix",
36
+ "description": "`matrix` (the default): letters, digits and symbols at 28ms a frame, one\ncharacter locking per frame. `flap`: upper-cased, a departure board's\nletters at 55ms a frame, one character locking every two frames.",
37
+ "control": {
38
+ "kind": "enum",
39
+ "members": [
40
+ "matrix",
41
+ "flap"
42
+ ]
43
+ }
44
+ }
45
+ ],
46
+ "typeReferences": [
47
+ "Omit<React.ComponentPropsWithoutRef<\"p\">, \"children\">"
48
+ ],
49
+ "subcomponents": [],
50
+ "parts": [],
51
+ "variants": {},
52
+ "defaultVariants": {},
53
+ "tokensUsed": [],
54
+ "summary": "A line that cycles through phrases, scrambling each one in — matrix glyphs at 28ms a frame, or a departure board's flap — with one sentence for assistive technology.",
55
+ "examples": [
56
+ {
57
+ "title": "Usage",
58
+ "code": "<TextScramble phrases={[\"we build software\", \"we design stages\"]} label=\"We build software and design stages.\" />",
59
+ "language": "tsx"
60
+ }
61
+ ],
62
+ "status": "stable",
63
+ "url": "/docs/components/text-scramble",
64
+ "mdUrl": "/docs/components/text-scramble.md",
65
+ "jsonUrl": "/r/components/text-scramble.json",
66
+ "whenToUse": [
67
+ "A hero's rotating value line: what you do, said several ways, under the headline.",
68
+ "A short status that changes on a slow cycle, where the change itself is part of the voice."
69
+ ],
70
+ "whenNotToUse": [
71
+ "Anything a reader must read at a given moment, such as an error, a price or a count: the text is unreadable while it scrambles.",
72
+ "Long sentences. A phrase holds for 1.8s after it settles, so a long one spends most of its turn scrambling."
73
+ ],
74
+ "commonMistakes": [
75
+ "Leaving `label` as one of the phrases. Assistive technology reads `label` instead of the animation, so it should name the whole cycle in one sentence.",
76
+ "Expecting it to scramble under reduced motion. Each phrase is shown whole, one every 2.6s; held still, the first phrase stays."
77
+ ],
78
+ "specimens": [
79
+ {
80
+ "title": "TextScramble",
81
+ "group": "brand",
82
+ "components": [
83
+ "TextScramble"
84
+ ],
85
+ "code": "<TextScramble\n phrases={[\"we build software // and run on it ourselves\", \"we design stages // in 3D, before they're real\"]}\n label=\"We build software and design stages.\"\n className=\"font-mono text-(length:--cue-text-ui) text-fg-muted\"\n/>",
86
+ "note": "A line that cycles through phrases, scrambling each one in: matrix glyphs at 28ms a frame, or a departure board's flap. Assistive technology reads the label instead.",
87
+ "interaction": "none. Prefer reduced motion and each phrase is shown whole; held still, the first phrase stays."
88
+ }
89
+ ]
90
+ }
@@ -80,11 +80,13 @@
80
80
  "--cue-paint-stroke-to",
81
81
  "--cue-paint-stroke-width",
82
82
  "--cue-radius-control",
83
+ "--cue-radius-scale",
83
84
  "--cue-space-3",
84
85
  "--cue-space-4",
85
86
  "--cue-space-5",
86
87
  "--cue-style-body-weight",
87
88
  "--cue-style-check-edge",
89
+ "--cue-style-control-radius",
88
90
  "--cue-style-control-step-size",
89
91
  "--cue-style-disabled-edge",
90
92
  "--cue-style-disabled-fill",
@@ -93,6 +95,7 @@
93
95
  "--cue-style-field-focus-offset",
94
96
  "--cue-style-field-hover-edge",
95
97
  "--cue-style-field-pad",
98
+ "--cue-style-field-radius",
96
99
  "--cue-style-focus-edge",
97
100
  "--cue-style-focus-width",
98
101
  "--cue-style-input-face",
@@ -61,7 +61,7 @@
61
61
  },
62
62
  {
63
63
  "name": "font",
64
- "type": "\"source\" | \"system\" | \"geist\" | \"geist-mono\" | \"inter\" | \"plex\" | \"roboto\" | \"apple\" | \"office\" | \"inter-source\" | \"dm\" | \"calsans\" | \"fraunces-mono\"",
64
+ "type": "\"source\" | \"system\" | \"geist\" | \"geist-mono\" | \"inter\" | \"plex\" | \"roboto\" | \"apple\" | \"office\" | \"inter-source\" | \"dm\" | \"calsans\" | \"fraunces-mono\" | \"jetbrains-mono\"",
65
65
  "required": false,
66
66
  "defaultValue": null,
67
67
  "description": "Initial font pairing.\n\nDefaults to the pairing the active theme's manifest names in\n`fontPairings.default` — §5's rule, the density prop's rule one axis over\n— and to `\"system\"` when it names none: the platform's own faces, nothing\ndownloaded, and the theme keeps whatever monospace it authored.\n\nA pairing that needs delivering is a set of *names*: this library ships no\nfont files, and a pairing nobody delivers falls through its stack to the\nplatform rather than failing. See `FONT_PAIRINGS[font].faces` for the\ncustom properties an app assigns to make one resolve.\n\n**Root-level only.** There is no font island: a nested provider forwards\nthis axis to the root, ignores this prop, and its `setFont` drives the root.\nA page that changed face halfway down is a page with a bug, and a specimen\nthat genuinely wants one — a picker row, a docs page showing all twelve —\nneeds nothing from this library but `data-font` on a `<div>`.",
@@ -80,7 +80,8 @@
80
80
  "inter-source",
81
81
  "dm",
82
82
  "calsans",
83
- "fraunces-mono"
83
+ "fraunces-mono",
84
+ "jetbrains-mono"
84
85
  ]
85
86
  }
86
87
  },
@@ -67,12 +67,14 @@
67
67
  "--cue-paint-stroke-to",
68
68
  "--cue-paint-stroke-width",
69
69
  "--cue-radius-control",
70
+ "--cue-radius-scale",
70
71
  "--cue-space-1",
71
72
  "--cue-space-3",
72
73
  "--cue-space-4",
73
74
  "--cue-space-5",
74
75
  "--cue-style-body-weight",
75
76
  "--cue-style-check-edge",
77
+ "--cue-style-control-radius",
76
78
  "--cue-style-control-step-size",
77
79
  "--cue-style-disabled-edge",
78
80
  "--cue-style-disabled-fill",
@@ -81,6 +83,7 @@
81
83
  "--cue-style-field-focus-offset",
82
84
  "--cue-style-field-hover-edge",
83
85
  "--cue-style-field-pad",
86
+ "--cue-style-field-radius",
84
87
  "--cue-style-focus-edge",
85
88
  "--cue-style-focus-width",
86
89
  "--cue-style-input-face",