@cueplusplus/ui 0.8.0 → 0.10.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.
Files changed (352) hide show
  1. package/CHANGELOG.md +457 -0
  2. package/README.md +131 -0
  3. package/dist/chat/message-list.js +2 -1
  4. package/dist/configurator/_export.d.ts +1 -1
  5. package/dist/configurator/_export.js +53 -13
  6. package/dist/configurator/_overrides.d.ts +25 -6
  7. package/dist/configurator/_overrides.js +30 -17
  8. package/dist/configurator/configurator.js +8 -3
  9. package/dist/configurator/panel-sections.js +43 -13
  10. package/dist/elements/command-palette.js +1 -1
  11. package/dist/elements/flow-graph.js +2 -2
  12. package/dist/elements/markdown.js +1 -1
  13. package/dist/elements/surfaces.js +4 -3
  14. package/dist/index.d.ts +7 -3
  15. package/dist/index.js +5 -2
  16. package/dist/instruments/meter.d.ts +5 -1
  17. package/dist/layout/bento.d.ts +144 -0
  18. package/dist/layout/bento.js +266 -0
  19. package/dist/layout/index.d.ts +3 -2
  20. package/dist/layout/index.js +3 -2
  21. package/dist/midi/piano-keyboard.js +5 -1
  22. package/dist/primitives/button.d.ts +12 -0
  23. package/dist/styles.css +23 -1
  24. package/dist/system/density.d.ts +17 -8
  25. package/dist/system/density.js +39 -16
  26. package/dist/system/index.d.ts +5 -2
  27. package/dist/system/index.js +3 -1
  28. package/dist/system/overrides.d.ts +80 -0
  29. package/dist/system/overrides.js +277 -0
  30. package/dist/system/portal.d.ts +4 -2
  31. package/dist/system/portal.js +34 -3
  32. package/dist/system/prepaint.d.ts +58 -7
  33. package/dist/system/prepaint.js +72 -20
  34. package/dist/system/theme-provider.d.ts +133 -8
  35. package/dist/system/theme-provider.js +203 -72
  36. package/dist/system/theme-registry.d.ts +53 -0
  37. package/dist/system/theme-registry.js +66 -0
  38. package/dist/system/use-density.d.ts +13 -5
  39. package/dist/system/use-density.js +142 -13
  40. package/dist/system/use-theme.d.ts +5 -3
  41. package/dist/system/use-theme.js +5 -3
  42. package/dist/system/vocabulary.d.ts +15 -0
  43. package/dist/system/vocabulary.js +111 -0
  44. package/dist/theming/contrast.d.ts +2 -122
  45. package/dist/theming/contrast.js +2 -194
  46. package/dist/theming/create-theme.d.ts +37 -11
  47. package/dist/theming/create-theme.js +54 -17
  48. package/dist/theming/index.d.ts +3 -4
  49. package/dist/theming/index.js +3 -4
  50. package/dist/theming/serialize.d.ts +24 -11
  51. package/dist/theming/serialize.js +16 -18
  52. package/manifest/components/accordion.json +24 -6
  53. package/manifest/components/activity-graph.json +20 -5
  54. package/manifest/components/agent-card.json +37 -9
  55. package/manifest/components/agent-handoff.json +21 -5
  56. package/manifest/components/agent-mode-badge.json +22 -4
  57. package/manifest/components/agent-pile.json +38 -8
  58. package/manifest/components/agent-plan.json +9 -2
  59. package/manifest/components/agent-status.json +17 -3
  60. package/manifest/components/agent-surface.json +26 -11
  61. package/manifest/components/alert-dialog.json +29 -5
  62. package/manifest/components/animated-number.json +14 -6
  63. package/manifest/components/app-bar.json +66 -13
  64. package/manifest/components/app-shell.json +133 -31
  65. package/manifest/components/app-window-frame.json +28 -6
  66. package/manifest/components/approval-card.json +37 -7
  67. package/manifest/components/artifact-card.json +16 -4
  68. package/manifest/components/ask-box.json +99 -21
  69. package/manifest/components/audience-icon.json +1 -7
  70. package/manifest/components/autocomplete.json +80 -18
  71. package/manifest/components/avatar-group.json +13 -2
  72. package/manifest/components/avatar.json +22 -4
  73. package/manifest/components/background-inbox.json +9 -2
  74. package/manifest/components/bento.json +306 -0
  75. package/manifest/components/branch-picker.json +29 -7
  76. package/manifest/components/breadcrumb.json +13 -3
  77. package/manifest/components/button-group.json +21 -4
  78. package/manifest/components/button.json +41 -4
  79. package/manifest/components/canvas-split-body.json +4 -1
  80. package/manifest/components/canvas-split-header.json +17 -4
  81. package/manifest/components/canvas-split-line.json +4 -1
  82. package/manifest/components/canvas-split-message.json +8 -1
  83. package/manifest/components/card.json +14 -3
  84. package/manifest/components/carousel.json +54 -12
  85. package/manifest/components/catalogue-icon.json +1 -7
  86. package/manifest/components/channel-beta-icon.json +1 -7
  87. package/manifest/components/channel-matrix.json +80 -15
  88. package/manifest/components/channel-released-icon.json +1 -7
  89. package/manifest/components/chart-container.json +26 -10
  90. package/manifest/components/chart-ramp.json +13 -3
  91. package/manifest/components/chart-swatch.json +9 -2
  92. package/manifest/components/chart-tooltip-content.json +31 -7
  93. package/manifest/components/chart.json +30 -6
  94. package/manifest/components/chat-panel-composer.json +9 -2
  95. package/manifest/components/checkbox-group.json +4 -2
  96. package/manifest/components/checkbox.json +17 -4
  97. package/manifest/components/checkpoint-history.json +13 -3
  98. package/manifest/components/chip.json +35 -5
  99. package/manifest/components/clamp.json +30 -7
  100. package/manifest/components/cli-tool-icon.json +1 -7
  101. package/manifest/components/code-diff.json +20 -5
  102. package/manifest/components/code-runner.json +32 -6
  103. package/manifest/components/collapsible.json +16 -4
  104. package/manifest/components/color-area.json +4 -1
  105. package/manifest/components/color-field.json +13 -3
  106. package/manifest/components/color-picker.json +75 -17
  107. package/manifest/components/color-slider.json +12 -3
  108. package/manifest/components/color-swatch.json +13 -2
  109. package/manifest/components/colors-section.json +10 -7
  110. package/manifest/components/combobox.json +81 -18
  111. package/manifest/components/command-palette.json +57 -13
  112. package/manifest/components/compaction-row.json +35 -7
  113. package/manifest/components/comparison-card.json +17 -4
  114. package/manifest/components/composer-attachment-chip.json +9 -2
  115. package/manifest/components/composer-bar.json +4 -1
  116. package/manifest/components/composer-command-item.json +8 -2
  117. package/manifest/components/composer-context.json +4 -1
  118. package/manifest/components/composer-input.json +5 -1
  119. package/manifest/components/composer-menu-item.json +4 -1
  120. package/manifest/components/composer-menu.json +12 -2
  121. package/manifest/components/composer-model-item.json +8 -2
  122. package/manifest/components/composer-model-trigger.json +8 -2
  123. package/manifest/components/composer-person-item.json +8 -2
  124. package/manifest/components/composer-send.json +8 -2
  125. package/manifest/components/composer-voice-button.json +4 -1
  126. package/manifest/components/composer-voice.json +8 -2
  127. package/manifest/components/composer.json +76 -17
  128. package/manifest/components/computer-use.json +17 -4
  129. package/manifest/components/confidence-marker.json +13 -3
  130. package/manifest/components/connection-state.json +23 -4
  131. package/manifest/components/container.json +14 -2
  132. package/manifest/components/context-breakdown.json +8 -2
  133. package/manifest/components/context-menu.json +16 -4
  134. package/manifest/components/context-usage.json +16 -4
  135. package/manifest/components/conversation-search.json +22 -5
  136. package/manifest/components/copy-button.json +32 -7
  137. package/manifest/components/cost-meter.json +12 -3
  138. package/manifest/components/cue-logotype.json +17 -3
  139. package/manifest/components/cue-mark.json +17 -3
  140. package/manifest/components/cue-portal-frame.json +14 -4
  141. package/manifest/components/data-row.json +21 -7
  142. package/manifest/components/data-table-pagination.json +18 -4
  143. package/manifest/components/data-table-toolbar.json +30 -7
  144. package/manifest/components/data-tree.json +42 -9
  145. package/manifest/components/date-field.json +13 -2
  146. package/manifest/components/date-picker.json +81 -19
  147. package/manifest/components/date-range-picker.json +81 -19
  148. package/manifest/components/day-separator.json +4 -1
  149. package/manifest/components/delegation-card.json +64 -12
  150. package/manifest/components/density.json +25 -5
  151. package/manifest/components/description-list.json +8 -1
  152. package/manifest/components/diagram.json +33 -7
  153. package/manifest/components/dialog.json +29 -6
  154. package/manifest/components/disclosure.json +31 -7
  155. package/manifest/components/dmx-bar.json +16 -4
  156. package/manifest/components/dmx-strip.json +20 -5
  157. package/manifest/components/document-reference.json +21 -5
  158. package/manifest/components/draft-restore.json +18 -4
  159. package/manifest/components/drawer.json +30 -6
  160. package/manifest/components/dropdown-menu.json +55 -10
  161. package/manifest/components/edit-message.json +32 -7
  162. package/manifest/components/elements-command-palette.json +27 -6
  163. package/manifest/components/elements-data-table.json +9 -2
  164. package/manifest/components/elements-timeline.json +8 -2
  165. package/manifest/components/elicitation-form.json +31 -6
  166. package/manifest/components/empty-state-composer.json +9 -2
  167. package/manifest/components/empty-state-suggestion.json +4 -1
  168. package/manifest/components/empty-state.json +25 -5
  169. package/manifest/components/end-of-turn-summary.json +16 -4
  170. package/manifest/components/env-var-input.json +54 -12
  171. package/manifest/components/error-state.json +17 -4
  172. package/manifest/components/export-dialog.json +27 -11
  173. package/manifest/components/eyebrow.json +4 -1
  174. package/manifest/components/feedback-dialog.json +33 -7
  175. package/manifest/components/field-description.json +4 -1
  176. package/manifest/components/field-error.json +13 -3
  177. package/manifest/components/field-label.json +4 -1
  178. package/manifest/components/field.json +4 -1
  179. package/manifest/components/file-tree.json +16 -4
  180. package/manifest/components/file-upload.json +58 -13
  181. package/manifest/components/flow-graph.json +12 -3
  182. package/manifest/components/folder-icon.json +1 -7
  183. package/manifest/components/footer.json +24 -4
  184. package/manifest/components/frac.json +10 -2
  185. package/manifest/components/generation-loader.json +17 -3
  186. package/manifest/components/generative-ui.json +39 -7
  187. package/manifest/components/grid.json +56 -5
  188. package/manifest/components/group-bar.json +25 -6
  189. package/manifest/components/guardrail-notice.json +22 -5
  190. package/manifest/components/hover-card.json +45 -8
  191. package/manifest/components/icon-button.json +22 -4
  192. package/manifest/components/image-generation.json +8 -2
  193. package/manifest/components/info-tip.json +42 -7
  194. package/manifest/components/inline-citation.json +14 -3
  195. package/manifest/components/input-group.json +24 -5
  196. package/manifest/components/input.json +13 -3
  197. package/manifest/components/item.json +42 -8
  198. package/manifest/components/job-progress.json +25 -6
  199. package/manifest/components/launcher-bubble.json +32 -7
  200. package/manifest/components/ledger.json +87 -19
  201. package/manifest/components/link.json +16 -3
  202. package/manifest/components/live-region-announcer.json +21 -5
  203. package/manifest/components/log-viewer.json +42 -10
  204. package/manifest/components/map-answer.json +17 -4
  205. package/manifest/components/markdown-text.json +36 -5
  206. package/manifest/components/math-block.json +12 -3
  207. package/manifest/components/mcp-server-icon.json +1 -7
  208. package/manifest/components/mcp-server-panel.json +18 -4
  209. package/manifest/components/memory-chips.json +9 -2
  210. package/manifest/components/menubar.json +33 -7
  211. package/manifest/components/message-actions.json +32 -7
  212. package/manifest/components/message-attachments.json +9 -2
  213. package/manifest/components/message-branches.json +14 -3
  214. package/manifest/components/message-list.json +27 -6
  215. package/manifest/components/message-pair.json +25 -5
  216. package/manifest/components/message-queue.json +13 -3
  217. package/manifest/components/message-timing.json +8 -2
  218. package/manifest/components/message.json +41 -9
  219. package/manifest/components/meter.json +43 -7
  220. package/manifest/components/mobile-composer.json +47 -10
  221. package/manifest/components/model-picker.json +13 -3
  222. package/manifest/components/multi-select.json +78 -17
  223. package/manifest/components/musical-time-input.json +34 -8
  224. package/manifest/components/navigation-menu.json +54 -12
  225. package/manifest/components/node-card.json +42 -7
  226. package/manifest/components/node-handle.json +17 -2
  227. package/manifest/components/number-field.json +28 -6
  228. package/manifest/components/number-ticker.json +8 -2
  229. package/manifest/components/onboarding.json +18 -4
  230. package/manifest/components/otp-field.json +43 -10
  231. package/manifest/components/page-shell.json +35 -6
  232. package/manifest/components/pagination.json +21 -5
  233. package/manifest/components/panel-header.json +15 -3
  234. package/manifest/components/password-input.json +38 -8
  235. package/manifest/components/permission-grant.json +28 -5
  236. package/manifest/components/permission-scopes.json +57 -12
  237. package/manifest/components/piano-keyboard.json +38 -9
  238. package/manifest/components/plussie.json +34 -5
  239. package/manifest/components/popover.json +45 -8
  240. package/manifest/components/preset-section.json +14 -8
  241. package/manifest/components/progress.json +25 -6
  242. package/manifest/components/prompt-library.json +27 -6
  243. package/manifest/components/queue-dock.json +36 -8
  244. package/manifest/components/quota-banner.json +25 -6
  245. package/manifest/components/quote-reply.json +29 -7
  246. package/manifest/components/radio-group.json +12 -2
  247. package/manifest/components/radio.json +17 -3
  248. package/manifest/components/rating.json +60 -13
  249. package/manifest/components/read-aloud.json +35 -8
  250. package/manifest/components/reasoning-effort.json +17 -4
  251. package/manifest/components/reasoning-panel.json +33 -8
  252. package/manifest/components/recommendation-card.json +35 -10
  253. package/manifest/components/regenerate-menu.json +22 -5
  254. package/manifest/components/replay-player.json +29 -7
  255. package/manifest/components/research-report.json +12 -3
  256. package/manifest/components/resizable.json +4 -1
  257. package/manifest/components/retrieval-chunks.json +16 -4
  258. package/manifest/components/revert-dock.json +61 -14
  259. package/manifest/components/reviewable-diff.json +23 -5
  260. package/manifest/components/risk-badge.json +18 -3
  261. package/manifest/components/row.json +17 -4
  262. package/manifest/components/schedule-card.json +25 -6
  263. package/manifest/components/score-breakdown.json +20 -5
  264. package/manifest/components/scroll-anchor.json +13 -3
  265. package/manifest/components/scroll-area.json +31 -8
  266. package/manifest/components/scrollable-tabs-list.json +12 -4
  267. package/manifest/components/scrub-input.json +84 -18
  268. package/manifest/components/seam-cell.json +19 -3
  269. package/manifest/components/seam-grid.json +12 -3
  270. package/manifest/components/search-input.json +49 -10
  271. package/manifest/components/section-header.json +36 -8
  272. package/manifest/components/segmented-control.json +50 -11
  273. package/manifest/components/select.json +74 -16
  274. package/manifest/components/separator.json +4 -1
  275. package/manifest/components/settings-panel.json +41 -9
  276. package/manifest/components/shape-section.json +10 -7
  277. package/manifest/components/shared-conversation.json +21 -5
  278. package/manifest/components/sheet.json +29 -6
  279. package/manifest/components/shimmer-label.json +4 -2
  280. package/manifest/components/sidebar.json +60 -13
  281. package/manifest/components/skill-icon.json +1 -7
  282. package/manifest/components/slider.json +22 -5
  283. package/manifest/components/sources.json +17 -4
  284. package/manifest/components/sparkline.json +17 -4
  285. package/manifest/components/speaker-identity.json +4 -1
  286. package/manifest/components/spec-sheet.json +16 -4
  287. package/manifest/components/spectrum-visualizer.json +41 -10
  288. package/manifest/components/spinner.json +12 -2
  289. package/manifest/components/stack-icon.json +1 -7
  290. package/manifest/components/stack.json +54 -7
  291. package/manifest/components/stacks-matrix-icon.json +1 -7
  292. package/manifest/components/stat.json +28 -4
  293. package/manifest/components/status-bar.json +50 -9
  294. package/manifest/components/status-dot.json +23 -4
  295. package/manifest/components/stepper.json +22 -5
  296. package/manifest/components/stopped-run.json +19 -4
  297. package/manifest/components/streaming-text.json +12 -3
  298. package/manifest/components/subagent-list.json +21 -5
  299. package/manifest/components/suggestions.json +27 -5
  300. package/manifest/components/swap-label.json +18 -4
  301. package/manifest/components/switch.json +18 -3
  302. package/manifest/components/table-scroll-region.json +4 -1
  303. package/manifest/components/table.json +54 -11
  304. package/manifest/components/tabs.json +16 -5
  305. package/manifest/components/tags-input.json +79 -17
  306. package/manifest/components/tail-status.json +37 -8
  307. package/manifest/components/terminal-block.json +25 -5
  308. package/manifest/components/terminal-frame.json +34 -8
  309. package/manifest/components/textarea.json +8 -3
  310. package/manifest/components/theme-configurator.json +47 -14
  311. package/manifest/components/theme-provider.json +97 -18
  312. package/manifest/components/thinking-indicator.json +8 -2
  313. package/manifest/components/thread-list.json +13 -3
  314. package/manifest/components/thread-search.json +22 -5
  315. package/manifest/components/threshold-rail.json +77 -14
  316. package/manifest/components/time-boundary.json +8 -2
  317. package/manifest/components/time-field.json +13 -2
  318. package/manifest/components/timeline-ruler.json +51 -12
  319. package/manifest/components/timeline.json +19 -3
  320. package/manifest/components/title-bar.json +19 -4
  321. package/manifest/components/toast.json +12 -3
  322. package/manifest/components/todo-list.json +8 -2
  323. package/manifest/components/toggle-group.json +33 -7
  324. package/manifest/components/toggle.json +23 -4
  325. package/manifest/components/token-editor.json +26 -10
  326. package/manifest/components/tool-call-card.json +83 -16
  327. package/manifest/components/tool-call.json +37 -9
  328. package/manifest/components/tool-error.json +34 -8
  329. package/manifest/components/tool-group.json +17 -4
  330. package/manifest/components/tool-timeline.json +37 -9
  331. package/manifest/components/toolbar.json +37 -8
  332. package/manifest/components/tooltip.json +41 -7
  333. package/manifest/components/trace-waterfall.json +12 -3
  334. package/manifest/components/tree-visibility-toggle.json +18 -3
  335. package/manifest/components/tree.json +52 -11
  336. package/manifest/components/turn-footer.json +36 -8
  337. package/manifest/components/two-step-button.json +46 -9
  338. package/manifest/components/typing-indicator.json +8 -1
  339. package/manifest/components/universe-grid.json +37 -10
  340. package/manifest/components/unread-divider.json +4 -1
  341. package/manifest/components/usage-chart.json +46 -9
  342. package/manifest/components/verdict-row.json +20 -5
  343. package/manifest/components/voice-conversation.json +37 -7
  344. package/manifest/components/web-preview.json +23 -5
  345. package/manifest/components/web-search.json +20 -5
  346. package/manifest/components/work-collapse.json +30 -7
  347. package/manifest/fixtures.json +106 -0
  348. package/manifest/manifest.json +449 -310
  349. package/manifest/tokens.json +122 -12
  350. package/package.json +16 -6
  351. package/dist/theming/_presets.d.ts +0 -11
  352. package/dist/theming/_presets.js +0 -678
@@ -0,0 +1,144 @@
1
+ import { SpaceStep } from "./stack.js";
2
+ import * as React from "react";
3
+ //#region src/layout/bento.d.ts
4
+ /** How many columns the bento resolves to at `lg`. */
5
+ type BentoColumns = 2 | 3 | 4;
6
+ /** How many rows to declare, so a tall tile spans a track that exists. */
7
+ type BentoRows = 1 | 2 | 3 | 4;
8
+ /** How many columns one tile covers, before the container clamps it. */
9
+ type BentoSpan = 1 | 2 | 3 | 4;
10
+ /** How many rows one tile covers. */
11
+ type BentoRowSpan = 1 | 2;
12
+ /** How much height a tile reserves before its content arrives. */
13
+ type BentoMinHeight = "none" | "half" | "hero";
14
+ interface BentoRootProps extends React.ComponentPropsWithoutRef<"div"> {
15
+ /** How many columns at `lg`. Defaults to `3`. Two from `sm`, one below it. */
16
+ cols?: BentoColumns;
17
+ /**
18
+ * How many rows to declare from `sm` up.
19
+ *
20
+ * Only worth setting where a tile spans rows: a `rowSpan` over implicit
21
+ * tracks sizes itself to the tile's own content, which is not a span.
22
+ */
23
+ rows?: BentoRows;
24
+ /** Pack later tiles into earlier holes instead of leaving them empty. */
25
+ dense?: boolean;
26
+ /** Which rung of the density space ladder to spend between tiles. Defaults to `4`. */
27
+ gap?: SpaceStep;
28
+ /** The tiles. Declared, so the manifest files it as a documented prop. */
29
+ children?: React.ReactNode;
30
+ }
31
+ /**
32
+ * What both tile variants share: the geometry, the four slots and the body.
33
+ *
34
+ * An `interface … extends Omit<…>` rather than a type alias over an
35
+ * intersection, for the same reason `PanelHeaderProps` and `ItemProps` are:
36
+ * `children` is a documented prop only where a component *declares* it, and a
37
+ * member of an intersection's object half is attributed to React's own
38
+ * declaration rather than to this file — so the alias form files every other
39
+ * slot and silently drops the body.
40
+ */
41
+ interface BentoTileBase extends Omit<React.ComponentPropsWithoutRef<"div">, "title"> {
42
+ /** How many columns to cover. Clamped by the container to its own `cols`. */
43
+ span?: BentoSpan;
44
+ /** How many rows to cover. Needs a container that declares them. */
45
+ rowSpan?: BentoRowSpan;
46
+ /** How much height to hold before the content arrives. Defaults to `"none"`. */
47
+ minHeight?: BentoMinHeight;
48
+ /** The qualifier above the name: an import specifier, a family, a device. */
49
+ eyebrow?: React.ReactNode;
50
+ /** The tile's name. Rendered as a `<span>`, never as a heading. */
51
+ title?: React.ReactNode;
52
+ /** The count beside the name — by convention a `<Chip variant="outline">`. */
53
+ meta?: React.ReactNode;
54
+ /** The summary and anything below it. */
55
+ children?: React.ReactNode;
56
+ }
57
+ /**
58
+ * A tile whose whole surface is one `<a>`.
59
+ *
60
+ * Its content is static: no control, no second link. HTML's content model for
61
+ * `<a>` is transparent *but* admits no interactive descendant and no `<a>`
62
+ * descendant, and `inert` changes focus, hit-testing and the accessibility tree
63
+ * while changing that content model not at all.
64
+ */
65
+ type BentoLinkTileProps = BentoTileBase & {
66
+ /** Where the tile goes. Its presence is what makes the tile a link. */
67
+ href: string;
68
+ /**
69
+ * A router's own link element, cloned to carry the tile's classes and slots.
70
+ *
71
+ * The **element** form only, and never a render function: a function would
72
+ * buy a second calling convention at the price of this component's
73
+ * server-safety, because the hook that reads one is a hook. The element keeps
74
+ * its own `href` — `next/link` declares that prop required, so passing the
75
+ * tile's would make the tile the silent owner of a value the element has to
76
+ * declare anyway. Its own `className` is **merged** with the tile's rather
77
+ * than replaced by it, which is the other half of the same bargain: `href` is
78
+ * a value the element owns outright, and a class is one it adds to.
79
+ */
80
+ render?: React.ReactElement;
81
+ /** Never on a link tile: an `<a>` may not contain a control. */
82
+ action?: never;
83
+ };
84
+ /** A surface that may hold live children; its link or control is a visible sibling. */
85
+ type BentoPanelTileProps = BentoTileBase & {
86
+ /** Never on a panel tile: `href` is what selects the link variant. */
87
+ href?: never;
88
+ /** Never on a panel tile: `render` belongs to the link variant. */
89
+ render?: never;
90
+ /** The tile's own link or control, rendered beside the count rather than around it. */
91
+ action?: React.ReactNode;
92
+ };
93
+ /** Props for {@link Bento.Tile}: a link tile, or a panel tile with an `action`. */
94
+ type BentoTileProps = BentoLinkTileProps | BentoPanelTileProps;
95
+ /**
96
+ * A grid of unequal tiles: per-item spans, clamped to the container's columns.
97
+ *
98
+ * Where `Grid` lays out cells it never touches, a bento's whole content is
99
+ * per-item — so the span is a prop on the tile, from a closed set, and the
100
+ * container clamps it on the way past. One column below `sm`, two from `sm`,
101
+ * the asked-for count from `lg`; the clamp is per breakpoint and not per
102
+ * `cols`, because every container is two tracks wide in between whatever it
103
+ * was asked for.
104
+ *
105
+ * **Static markup — no hooks, no `"use client"`, and it must stay that way.**
106
+ * A directive is per *module*, so a `Bento` built on `useRender` would open a
107
+ * client boundary in every server page that draws one. That is why the router
108
+ * escape hatch is `render`, an *element* that is cloned, rather than a render
109
+ * function; and why {@link Bento.Tile} is a discriminated union rather than a
110
+ * tile that decides at runtime what it is.
111
+ *
112
+ * `BentoTileProps` omits the native `title` from its `<div>` props, the same
113
+ * omission `PanelHeader` and `Item` make: `React.ComponentPropsWithoutRef<"div">`
114
+ * already declares `title?: string`, and narrowing it to a `ReactNode` without
115
+ * the `Omit` is TS2430.
116
+ *
117
+ * @example
118
+ * <Bento.Root cols={3} rows={2} gap={5}>
119
+ * <Bento.Tile span={2} rowSpan={2} minHeight="hero" title="Kitchen sink">
120
+ * Every component, on one page.
121
+ * </Bento.Tile>
122
+ * <Bento.Tile title="Themes" meta={<Chip variant="outline">10</Chip>} />
123
+ * <Bento.Tile title="Density" meta={<Chip variant="outline">5</Chip>} />
124
+ * </Bento.Root>
125
+ * @example
126
+ * <Bento.Tile
127
+ * href="/docs/components/grid"
128
+ * render={<NextLink href="/docs/components/grid" />}
129
+ * eyebrow="@cueplusplus/ui"
130
+ * title="Grid"
131
+ * >
132
+ * Equal columns, or as many as fit.
133
+ * </Bento.Tile>
134
+ * @example
135
+ * <Bento.Tile title="Signal" action={<Button onClick={apply}>Apply</Button>}>
136
+ * <ThemeSwatches theme="signal" />
137
+ * </Bento.Tile>
138
+ */
139
+ declare const Bento: {
140
+ Root: React.ForwardRefExoticComponent<BentoRootProps & React.RefAttributes<HTMLDivElement>>;
141
+ Tile: React.ForwardRefExoticComponent<BentoTileProps & React.RefAttributes<HTMLElement>>;
142
+ };
143
+ //#endregion
144
+ export { Bento, BentoColumns, BentoMinHeight, BentoRootProps, BentoRowSpan, BentoRows, BentoSpan, BentoTileProps };
@@ -0,0 +1,266 @@
1
+ import { cn } from "../lib/cn.js";
2
+ import { GAP_CLASSES } from "./stack.js";
3
+ import * as React from "react";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/layout/bento.tsx
6
+ /**
7
+ * Static class per count — Tailwind scans source text, not computed strings.
8
+ *
9
+ * One column below `sm`, two from `sm`, the asked-for count only from `lg`:
10
+ * three fixed columns at 640 px would be ~200 px per tile, narrower than the
11
+ * `18rem` minimum measure every grid this replaces already declares.
12
+ */
13
+ const COLUMN_CLASSES = {
14
+ 2: "grid-cols-1 sm:grid-cols-2",
15
+ 3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
16
+ 4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"
17
+ };
18
+ /** Static class per row count, from `sm` up — below it the bento is one column. */
19
+ const ROW_CLASSES = {
20
+ 1: "sm:grid-rows-1",
21
+ 2: "sm:grid-rows-2",
22
+ 3: "sm:grid-rows-3",
23
+ 4: "sm:grid-rows-4"
24
+ };
25
+ /**
26
+ * Static class per span, clamped at `sm` because every container is two tracks
27
+ * wide between 640 px and 1024 px whatever its `cols`.
28
+ *
29
+ * So there is no `sm:col-span-3` and no `sm:col-span-4` in this table at all,
30
+ * and no unprefixed `col-span-*` either: an unprefixed span in the one-track
31
+ * base grid grows an implicit second column, which is the same defect one
32
+ * breakpoint down. A span of 1 or 2 carries through from `sm` and needs no
33
+ * `lg:` rung.
34
+ */
35
+ const SPAN_CLASSES = {
36
+ 1: "sm:col-span-1",
37
+ 2: "sm:col-span-2",
38
+ 3: "sm:col-span-2 lg:col-span-3",
39
+ 4: "sm:col-span-2 lg:col-span-4"
40
+ };
41
+ /** Static class per row span, from `sm` up for the same reason as the columns. */
42
+ const ROW_SPAN_CLASSES = {
43
+ 1: "sm:row-span-1",
44
+ 2: "sm:row-span-2"
45
+ };
46
+ /**
47
+ * Static class per reserved height, spent off the space ladder's top rung so a
48
+ * hero tile shrinks with the rest of the console at ultra-compact.
49
+ */
50
+ const MIN_HEIGHT_CLASSES = {
51
+ none: "",
52
+ half: "min-h-[calc(var(--cue-space-8)*4)]",
53
+ hero: "min-h-[calc(var(--cue-space-8)*8)]"
54
+ };
55
+ /** The tile surface, shared by both variants so a link tile is not a second look. */
56
+ const TILE_CLASS = "flex flex-col gap-(--cue-space-3) overflow-hidden rounded-(--radius-surface) border border-border bg-surface-1 p-(--cue-space-5)";
57
+ /** What a link tile adds: the hover tint and the focus ring the whole surface takes. */
58
+ const LINK_TILE_CLASS = "no-underline transition-colors duration-150 outline-none hover:bg-surface-2 focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-accent";
59
+ /** The host elements a link tile may not contain, plus anything carrying `tabIndex`. */
60
+ const INTERACTIVE_TAGS = /* @__PURE__ */ new Set([
61
+ "a",
62
+ "button",
63
+ "input",
64
+ "select",
65
+ "textarea"
66
+ ]);
67
+ /**
68
+ * The first interactive child a link tile was given, named, or `undefined`.
69
+ *
70
+ * Shallow by design — it walks `React.Children` and not the rendered tree,
71
+ * because it must run in a server render as well as a client one and a hook is
72
+ * not available in either. What it cannot see (a control behind a component
73
+ * boundary) is what each converted grid's own DOM assertion catches.
74
+ */
75
+ function interactiveChild(children) {
76
+ let found;
77
+ React.Children.forEach(children, (child) => {
78
+ if (found !== void 0 || !React.isValidElement(child)) return;
79
+ const { tabIndex } = child.props;
80
+ if (typeof child.type === "string" && INTERACTIVE_TAGS.has(child.type)) found = child.type;
81
+ else if (tabIndex !== void 0) found = typeof child.type === "string" ? child.type : "child";
82
+ });
83
+ return found;
84
+ }
85
+ /** The tile's name as a log line can carry it, for a `title` that is not a string. */
86
+ function tileLabel(title) {
87
+ return typeof title === "string" || typeof title === "number" ? String(title) : "an untitled tile";
88
+ }
89
+ /**
90
+ * The bento container: a responsive grid that clamps the spans of its tiles.
91
+ *
92
+ * It maps `React.Children` and clones every child whose type is the tile,
93
+ * narrowing that tile's `span` to its own `cols`; anything else passes through
94
+ * with its props untouched, so a `<section>` or a bare `<div>` may sit in a
95
+ * band beside the tiles.
96
+ *
97
+ * **The clamp reaches direct children only, and that is a contract rather than
98
+ * an oversight.** `React.Children` does not descend into a component element,
99
+ * so a tile rendered by a child — `<Bento.Root><MyTiles /></Bento.Root>` — is
100
+ * whatever `span` it declared, and an over-wide one grows an implicit column
101
+ * exactly as an unclamped tile would. Reading through a component would mean
102
+ * rendering it, which a container may not do. So: **keep a tile a child
103
+ * component renders at `span={1}`, or clamp it in that component.** The same
104
+ * hazard in fragment form is why an authored `node` fixture of tiles is an
105
+ * array and not a `<>…</>`.
106
+ *
107
+ * Static markup — no `"use client"`.
108
+ */
109
+ const BentoRoot = React.forwardRef(function BentoRoot({ className, cols = 3, rows, dense = false, gap = 4, children, ...elementProps }, ref) {
110
+ return /* @__PURE__ */ jsx("div", {
111
+ ref,
112
+ "data-slot": "bento",
113
+ className: cn("grid", COLUMN_CLASSES[cols], rows === void 0 ? null : ROW_CLASSES[rows], dense ? "grid-flow-row-dense" : null, GAP_CLASSES[gap], className),
114
+ ...elementProps,
115
+ children: React.Children.map(children, (child) => clampTile(child, cols, rows))
116
+ });
117
+ });
118
+ /**
119
+ * Clamp one child's spans to the container's tracks, and leave everything else
120
+ * exactly as it was written.
121
+ *
122
+ * CSS Grid does not clamp: auto-placement grows the implicit grid to fit the
123
+ * largest definite span, so one `span={4}` in a `cols={3}` bento silently adds
124
+ * a fourth column and shifts every row. The tile cannot do this for itself —
125
+ * reading its container would need a hook, and this component is static markup
126
+ * on purpose — so the container does it, on the way past.
127
+ *
128
+ * **Both axes, and the row axis only where there is something to clamp to.**
129
+ * The column clamp always applies because `cols` always has a value; `rows` is
130
+ * optional, and a container that declares none is one whose rows are all
131
+ * implicit — there is no track count for `rowSpan` to be too large for, and the
132
+ * tile's own docblock already says that spanning rows there sizes the span to
133
+ * the tile's own content. So an undeclared `rows` leaves `rowSpan` alone, and a
134
+ * declared one is a promise the tile is held to.
135
+ */
136
+ function clampTile(child, cols, rows) {
137
+ if (!React.isValidElement(child) || child.type !== BentoTile) return child;
138
+ const tile = child;
139
+ const span = tile.props.span ?? 1;
140
+ const rowSpan = tile.props.rowSpan ?? 1;
141
+ return React.cloneElement(tile, {
142
+ span: Math.min(span, cols),
143
+ ...rows === void 0 ? {} : { rowSpan: Math.min(rowSpan, rows) }
144
+ });
145
+ }
146
+ /**
147
+ * One cell of a bento: a link, or a surface with an `action`.
148
+ *
149
+ * The two are a discriminated union rather than one shape with a runtime
150
+ * branch, because half of the rule is something a compiler can hold: `href`
151
+ * and `action` are mutually exclusive in the type. The other half — that a
152
+ * link tile's content is static — is held by a dev-time check here and by a
153
+ * DOM assertion in each grid that draws one.
154
+ *
155
+ * Static markup — no `"use client"`.
156
+ */
157
+ const BentoTile = React.forwardRef(function BentoTile(props, ref) {
158
+ const { className, span = 1, rowSpan = 1, minHeight = "none", eyebrow, title, meta, action, href, render, children, ...elementProps } = props;
159
+ if (process.env.NODE_ENV !== "production" && href !== void 0) {
160
+ if (render !== void 0 && render.props.href === void 0) console.error(`Bento.Tile (${tileLabel(title)}): \`render\` was given an element with no \`href\` of its own. The clone does not pass the tile's, so the link would go nowhere — put the href on the element, as \`next/link\` requires anyway.`);
161
+ const offender = interactiveChild(children) ?? interactiveChild(action);
162
+ if (offender !== void 0) console.error(`Bento.Tile (${tileLabel(title)}): a link tile contains an interactive <${offender}>. An <a> admits no interactive descendant, so use a panel tile and put the control in \`action\` instead of nesting it here.`);
163
+ }
164
+ const head = eyebrow !== void 0 || title !== void 0;
165
+ const tail = meta !== void 0 || action !== void 0;
166
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [head || tail ? /* @__PURE__ */ jsxs("div", {
167
+ className: "flex items-start justify-between gap-(--cue-space-3)",
168
+ children: [head ? /* @__PURE__ */ jsxs("div", {
169
+ className: "flex min-w-0 flex-col gap-(--cue-space-1)",
170
+ children: [eyebrow === void 0 ? null : /* @__PURE__ */ jsx("span", {
171
+ "data-slot": "bento-tile-eyebrow",
172
+ className: "font-mono text-(length:--cue-text-meta) text-fg-muted",
173
+ children: eyebrow
174
+ }), title === void 0 ? null : /* @__PURE__ */ jsx("span", {
175
+ "data-slot": "bento-tile-title",
176
+ className: "font-mono text-(length:--cue-text-emphasis) font-medium text-fg",
177
+ children: title
178
+ })]
179
+ }) : null, tail ? /* @__PURE__ */ jsxs("div", {
180
+ className: "flex shrink-0 items-center gap-(--cue-space-2)",
181
+ children: [meta === void 0 ? null : /* @__PURE__ */ jsx("span", {
182
+ "data-slot": "bento-tile-meta",
183
+ children: meta
184
+ }), action === void 0 ? null : /* @__PURE__ */ jsx("span", {
185
+ "data-slot": "bento-tile-action",
186
+ children: action
187
+ })]
188
+ }) : null]
189
+ }) : null, children] });
190
+ const surface = {
191
+ "data-slot": "bento-tile",
192
+ "data-span": String(span),
193
+ className: cn(TILE_CLASS, href === void 0 ? null : LINK_TILE_CLASS, SPAN_CLASSES[span], ROW_SPAN_CLASSES[rowSpan], MIN_HEIGHT_CLASSES[minHeight], className),
194
+ ...elementProps
195
+ };
196
+ if (href === void 0) return /* @__PURE__ */ jsx("div", {
197
+ ...surface,
198
+ ref,
199
+ children: content
200
+ });
201
+ const anchorSurface = surface;
202
+ if (render !== void 0) {
203
+ const routerLink = render;
204
+ return React.cloneElement(routerLink, {
205
+ ...anchorSurface,
206
+ className: cn(routerLink.props.className, anchorSurface.className),
207
+ ref
208
+ }, content);
209
+ }
210
+ return /* @__PURE__ */ jsx("a", {
211
+ ...anchorSurface,
212
+ href,
213
+ ref,
214
+ children: content
215
+ });
216
+ });
217
+ /**
218
+ * A grid of unequal tiles: per-item spans, clamped to the container's columns.
219
+ *
220
+ * Where `Grid` lays out cells it never touches, a bento's whole content is
221
+ * per-item — so the span is a prop on the tile, from a closed set, and the
222
+ * container clamps it on the way past. One column below `sm`, two from `sm`,
223
+ * the asked-for count from `lg`; the clamp is per breakpoint and not per
224
+ * `cols`, because every container is two tracks wide in between whatever it
225
+ * was asked for.
226
+ *
227
+ * **Static markup — no hooks, no `"use client"`, and it must stay that way.**
228
+ * A directive is per *module*, so a `Bento` built on `useRender` would open a
229
+ * client boundary in every server page that draws one. That is why the router
230
+ * escape hatch is `render`, an *element* that is cloned, rather than a render
231
+ * function; and why {@link Bento.Tile} is a discriminated union rather than a
232
+ * tile that decides at runtime what it is.
233
+ *
234
+ * `BentoTileProps` omits the native `title` from its `<div>` props, the same
235
+ * omission `PanelHeader` and `Item` make: `React.ComponentPropsWithoutRef<"div">`
236
+ * already declares `title?: string`, and narrowing it to a `ReactNode` without
237
+ * the `Omit` is TS2430.
238
+ *
239
+ * @example
240
+ * <Bento.Root cols={3} rows={2} gap={5}>
241
+ * <Bento.Tile span={2} rowSpan={2} minHeight="hero" title="Kitchen sink">
242
+ * Every component, on one page.
243
+ * </Bento.Tile>
244
+ * <Bento.Tile title="Themes" meta={<Chip variant="outline">10</Chip>} />
245
+ * <Bento.Tile title="Density" meta={<Chip variant="outline">5</Chip>} />
246
+ * </Bento.Root>
247
+ * @example
248
+ * <Bento.Tile
249
+ * href="/docs/components/grid"
250
+ * render={<NextLink href="/docs/components/grid" />}
251
+ * eyebrow="@cueplusplus/ui"
252
+ * title="Grid"
253
+ * >
254
+ * Equal columns, or as many as fit.
255
+ * </Bento.Tile>
256
+ * @example
257
+ * <Bento.Tile title="Signal" action={<Button onClick={apply}>Apply</Button>}>
258
+ * <ThemeSwatches theme="signal" />
259
+ * </Bento.Tile>
260
+ */
261
+ const Bento = {
262
+ Root: BentoRoot,
263
+ Tile: BentoTile
264
+ };
265
+ //#endregion
266
+ export { Bento };
@@ -2,14 +2,15 @@ import { Link, LinkProps, linkVariants } from "./link.js";
2
2
  import { Sidebar, SidebarItemProps, SidebarRailProps, SidebarRootProps, SidebarSectionProps, useSidebar } from "./sidebar.js";
3
3
  import { Container, ContainerProps, ContainerWidth } from "./container.js";
4
4
  import { Accordion, AccordionHeaderProps, AccordionItemProps, AccordionPanelProps, AccordionRootProps, AccordionTriggerProps } from "./accordion.js";
5
+ import { SpaceStep, Stack, StackAlign, StackJustify, StackProps } from "./stack.js";
6
+ import { Bento, BentoColumns, BentoMinHeight, BentoRootProps, BentoRowSpan, BentoRows, BentoSpan, BentoTileProps } from "./bento.js";
5
7
  import { Breadcrumb, BreadcrumbItem, BreadcrumbProps } from "./breadcrumb.js";
6
8
  import { Card, CardContentProps, CardDescriptionProps, CardFooterProps, CardHeaderProps, CardRootProps, CardTitleProps } from "./card.js";
7
9
  import { Collapsible, CollapsiblePanelProps, CollapsibleRootProps, CollapsibleTriggerProps, Disclosure, DisclosureProps } from "./collapsible.js";
8
10
  import { DescriptionList, DescriptionListDetailProps, DescriptionListLayout, DescriptionListRootProps, DescriptionListTermProps } from "./description-list.js";
9
- import { SpaceStep, Stack, StackAlign, StackJustify, StackProps } from "./stack.js";
10
11
  import { Grid, GridColumns, GridProps } from "./grid.js";
11
12
  import { Item, ItemProps, itemVariants } from "./item.js";
12
13
  import { Pagination, PaginationEntry, PaginationProps, paginationRange } from "./pagination.js";
13
14
  import { Stepper, StepperProps, StepperState, StepperStep } from "./stepper.js";
14
15
  import { Timeline, TimelineContentProps, TimelineItemProps, TimelineMarkerProps, TimelineRootProps } from "./timeline.js";
15
- export { Accordion, type AccordionHeaderProps, type AccordionItemProps, type AccordionPanelProps, type AccordionRootProps, type AccordionTriggerProps, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Card, type CardContentProps, type CardDescriptionProps, type CardFooterProps, type CardHeaderProps, type CardRootProps, type CardTitleProps, Collapsible, type CollapsiblePanelProps, type CollapsibleRootProps, type CollapsibleTriggerProps, Container, type ContainerProps, type ContainerWidth, DescriptionList, type DescriptionListDetailProps, type DescriptionListLayout, type DescriptionListRootProps, type DescriptionListTermProps, Disclosure, type DisclosureProps, Grid, type GridColumns, type GridProps, Item, type ItemProps, Link, type LinkProps, Pagination, type PaginationEntry, type PaginationProps, Sidebar, type SidebarItemProps, type SidebarRailProps, type SidebarRootProps, type SidebarSectionProps, type SpaceStep, Stack, type StackAlign, type StackJustify, type StackProps, Stepper, type StepperProps, type StepperState, type StepperStep, Timeline, type TimelineContentProps, type TimelineItemProps, type TimelineMarkerProps, type TimelineRootProps, itemVariants, linkVariants, paginationRange, useSidebar };
16
+ export { Accordion, type AccordionHeaderProps, type AccordionItemProps, type AccordionPanelProps, type AccordionRootProps, type AccordionTriggerProps, Bento, type BentoColumns, type BentoMinHeight, type BentoRootProps, type BentoRowSpan, type BentoRows, type BentoSpan, type BentoTileProps, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Card, type CardContentProps, type CardDescriptionProps, type CardFooterProps, type CardHeaderProps, type CardRootProps, type CardTitleProps, Collapsible, type CollapsiblePanelProps, type CollapsibleRootProps, type CollapsibleTriggerProps, Container, type ContainerProps, type ContainerWidth, DescriptionList, type DescriptionListDetailProps, type DescriptionListLayout, type DescriptionListRootProps, type DescriptionListTermProps, Disclosure, type DisclosureProps, Grid, type GridColumns, type GridProps, Item, type ItemProps, Link, type LinkProps, Pagination, type PaginationEntry, type PaginationProps, Sidebar, type SidebarItemProps, type SidebarRailProps, type SidebarRootProps, type SidebarSectionProps, type SpaceStep, Stack, type StackAlign, type StackJustify, type StackProps, Stepper, type StepperProps, type StepperState, type StepperStep, Timeline, type TimelineContentProps, type TimelineItemProps, type TimelineMarkerProps, type TimelineRootProps, itemVariants, linkVariants, paginationRange, useSidebar };
@@ -2,14 +2,15 @@ import { Link, linkVariants } from "./link.js";
2
2
  import { Sidebar, useSidebar } from "./sidebar.js";
3
3
  import { Container } from "./container.js";
4
4
  import { Accordion } from "./accordion.js";
5
+ import { Stack } from "./stack.js";
6
+ import { Bento } from "./bento.js";
5
7
  import { Breadcrumb } from "./breadcrumb.js";
6
8
  import { Card } from "./card.js";
7
9
  import { Collapsible, Disclosure } from "./collapsible.js";
8
10
  import { DescriptionList } from "./description-list.js";
9
- import { Stack } from "./stack.js";
10
11
  import { Grid } from "./grid.js";
11
12
  import { Item, itemVariants } from "./item.js";
12
13
  import { Pagination, paginationRange } from "./pagination.js";
13
14
  import { Stepper } from "./stepper.js";
14
15
  import { Timeline } from "./timeline.js";
15
- export { Accordion, Breadcrumb, Card, Collapsible, Container, DescriptionList, Disclosure, Grid, Item, Link, Pagination, Sidebar, Stack, Stepper, Timeline, itemVariants, linkVariants, paginationRange, useSidebar };
16
+ export { Accordion, Bento, Breadcrumb, Card, Collapsible, Container, DescriptionList, Disclosure, Grid, Item, Link, Pagination, Sidebar, Stack, Stepper, Timeline, itemVariants, linkVariants, paginationRange, useSidebar };
@@ -49,7 +49,11 @@ const PianoKeyboard = React.forwardRef(function PianoKeyboard({ className, range
49
49
  const [drag, setDrag] = React.useState(null);
50
50
  const settled = React.useMemo(() => keyboardWindow(range, octaves), [range, octaves]);
51
51
  const view = drag?.window ?? settled;
52
- const layout = React.useMemo(() => keyboardLayout(view), [view.start, view.end]);
52
+ const { start: viewStart, end: viewEnd } = view;
53
+ const layout = React.useMemo(() => keyboardLayout({
54
+ start: viewStart,
55
+ end: viewEnd
56
+ }), [viewStart, viewEnd]);
53
57
  const lit = React.useMemo(() => new Set(highlight ?? []), [highlight]);
54
58
  const setEdge = (edge, note) => {
55
59
  const next = edge === "start" ? {
@@ -26,6 +26,18 @@ interface ButtonProps extends React.ComponentPropsWithoutRef<"button">, VariantP
26
26
  * level without the caller passing a pixel size.
27
27
  */
28
28
  icon?: React.ElementType;
29
+ /**
30
+ * The label. A button with no children and no other accessible name is a
31
+ * control a screen reader announces as nothing.
32
+ *
33
+ * Declared explicitly, although `React.ComponentPropsWithoutRef<"button">`
34
+ * already carries it, for the reason `Card.Header` and `Bento.Tile` declare
35
+ * theirs: docgen documents a prop only where the library *declares* it, so
36
+ * without this line the manifest files no `children` for the system's most
37
+ * used control — the props table omits it, and a propSet cannot name it,
38
+ * which is how `/play/button` came to preview an unlabelled `<button>`.
39
+ */
40
+ children?: React.ReactNode;
29
41
  }
30
42
  /**
31
43
  * The system's primary action control.
package/dist/styles.css CHANGED
@@ -3,13 +3,35 @@
3
3
  * Consumer app CSS:
4
4
  * @import "tailwindcss";
5
5
  * @import "@cueplusplus/ui/styles.css";
6
+ * @import "@cueplusplus/theme-cue/theme.css"; (or any theme package)
6
7
  *
7
8
  * Tailwind v4 does not scan node_modules, so the library registers its own
8
9
  * sources: `@source "./"` resolves relative to THIS file, i.e. the shipped
9
10
  * dist/, which is where the class strings live after the build.
10
11
  */
11
12
 
12
- @import "@cueplusplus/tokens/theme.css";
13
+ /* Two lines, and the first one is the release's whole behaviour change.
14
+ *
15
+ * It used to be `@cueplusplus/tokens/theme.css`, which carried ten palettes and
16
+ * painted `cue` on a bare `:root`. A palette is a package now, so what this
17
+ * library ships is the *blank* base: `theme-base/base.css` declares every colour
18
+ * token at a neutral default and imports `@cueplusplus/tokens/axes.css` for the
19
+ * geometry and type axes. That is why there is no third line — `base.css`
20
+ * carries the axes with it, and `tailwind.css` maps utilities onto token names
21
+ * and pulls nothing.
22
+ *
23
+ * An app that imports this and registers no theme therefore paints greys and one
24
+ * desaturated accent, rather than somebody's brand. To get a palette back:
25
+ * install a theme package, import its stylesheet after this one, and pass its
26
+ * manifest to the provider —
27
+ *
28
+ * @import "@cueplusplus/ui/styles.css";
29
+ * @import "@cueplusplus/theme-cue/theme.css";
30
+ *
31
+ * with `<ThemeProvider themes={[cue]} theme="cue">`. Order matters and is not an
32
+ * accident: `[data-theme]` and `:root` tie at (0,1,0), so a theme's block wins
33
+ * by being declared later. */
34
+ @import "@cueplusplus/theme-base/base.css";
13
35
  @import "@cueplusplus/tokens/tailwind.css";
14
36
 
15
37
  @source "./";
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { Density } from "@cueplusplus/tokens";
2
+ import { Density } from "@cueplusplus/theme-base";
3
3
  //#region src/system/density.d.ts
4
4
  interface DensityProps {
5
5
  /**
@@ -17,14 +17,23 @@ interface DensityProps {
17
17
  /**
18
18
  * Re-scope any subtree to a different density level.
19
19
  *
20
- * Renders a plain `<div data-density="…">`: the geometry custom properties are
21
- * re-declared by the attribute selector and inherit down, so nesting is free and
22
- * needs no JS. The matching React context is published alongside for the rare
23
- * JS reads (`useDensity()`, `useControlHeight()`, portal stamping) — the DOM
24
- * attribute, not the context, is what actually restyles the tree.
20
+ * Renders a plain `<div data-density="…" data-cue-theme="…">`: the geometry
21
+ * custom properties are re-declared by the attribute selector and inherit
22
+ * down, so nesting is free and needs no JS. The matching React context is
23
+ * published alongside for the rare JS reads (`useDensity()`,
24
+ * `useControlHeight()`, portal stamping) — the DOM attributes, not the
25
+ * context, are what actually restyle the tree.
25
26
  *
26
- * Theme and mode are deliberately *not* re-scoped here: density is the only axis
27
- * an island may override (spec §6).
27
+ * `data-cue-theme` carries the nearest `<ThemeProvider>`'s name, or is
28
+ * omitted where there is none. It is read by nothing this island does —
29
+ * theme and mode are deliberately *not* re-scoped here, density is the only
30
+ * axis an island may override (spec §6) — it exists so a theme's own
31
+ * generated CSS can address exactly this island regardless of how many
32
+ * *other* themed providers sit between it and the one it belongs to. A CSS
33
+ * ancestor selector can only ask "does some ancestor carry theme `x`", never
34
+ * "is `x` the *nearest* one"; this stamp answers that question the way
35
+ * `useContext` already does, at render time, and hands the answer to CSS as
36
+ * an attribute rather than leaving it unanswerable there.
28
37
  *
29
38
  * @example
30
39
  * <Density density="ultra-compact">
@@ -10,14 +10,6 @@ import { jsx } from "react/jsx-runtime";
10
10
  * but the level a screen gets when nobody chose is the dense one.
11
11
  */
12
12
  const DEFAULT_DENSITY = "compact";
13
- /** The five levels, as a runtime array for validating persisted input. */
14
- const DENSITY_LEVELS = [
15
- "ultra-compact",
16
- "compact",
17
- "normal",
18
- "large",
19
- "ultra-large"
20
- ];
21
13
  /**
22
14
  * Nearest ambient density. `null` means "nothing has stamped a level yet", which
23
15
  * `useDensity()` reports as {@link DEFAULT_DENSITY}.
@@ -26,16 +18,45 @@ const DENSITY_LEVELS = [
26
18
  */
27
19
  const DensityContext = React.createContext(null);
28
20
  /**
21
+ * Nearest ambient theme's name, published for exactly one reader: `Density`
22
+ * below, which stamps it onto its island as `data-cue-theme` so a theme's
23
+ * CSS can tell *nearest* theme from *any* theme in the ancestor chain (see
24
+ * `densityRules`/`themeSelector`'s comment). `use-density.ts`'s measuring
25
+ * probe stamps the same attribute from the identical value, read through
26
+ * `ThemeContext` there instead, because it already imports that module with
27
+ * no cycle.
28
+ *
29
+ * Defined here, not in `theme-provider.tsx`, and re-exported from nowhere
30
+ * else. `theme-provider.tsx` already imports `DensityContext` from this
31
+ * module; a context this small living over there and imported back here
32
+ * would cycle the two modules. `null` outside a provider, the same as
33
+ * `ThemeContext`'s own theme field would be if it existed with no provider
34
+ * to require — `Density` used bare, with nothing above it, stamps nothing.
35
+ *
36
+ * Internal: `Density` is the only reader. Not `useTheme()` — that throws
37
+ * outside a provider, and this island has no reason to.
38
+ */
39
+ const AmbientThemeContext = React.createContext(null);
40
+ /**
29
41
  * Re-scope any subtree to a different density level.
30
42
  *
31
- * Renders a plain `<div data-density="…">`: the geometry custom properties are
32
- * re-declared by the attribute selector and inherit down, so nesting is free and
33
- * needs no JS. The matching React context is published alongside for the rare
34
- * JS reads (`useDensity()`, `useControlHeight()`, portal stamping) — the DOM
35
- * attribute, not the context, is what actually restyles the tree.
43
+ * Renders a plain `<div data-density="…" data-cue-theme="…">`: the geometry
44
+ * custom properties are re-declared by the attribute selector and inherit
45
+ * down, so nesting is free and needs no JS. The matching React context is
46
+ * published alongside for the rare JS reads (`useDensity()`,
47
+ * `useControlHeight()`, portal stamping) — the DOM attributes, not the
48
+ * context, are what actually restyle the tree.
36
49
  *
37
- * Theme and mode are deliberately *not* re-scoped here: density is the only axis
38
- * an island may override (spec §6).
50
+ * `data-cue-theme` carries the nearest `<ThemeProvider>`'s name, or is
51
+ * omitted where there is none. It is read by nothing this island does —
52
+ * theme and mode are deliberately *not* re-scoped here, density is the only
53
+ * axis an island may override (spec §6) — it exists so a theme's own
54
+ * generated CSS can address exactly this island regardless of how many
55
+ * *other* themed providers sit between it and the one it belongs to. A CSS
56
+ * ancestor selector can only ask "does some ancestor carry theme `x`", never
57
+ * "is `x` the *nearest* one"; this stamp answers that question the way
58
+ * `useContext` already does, at render time, and hands the answer to CSS as
59
+ * an attribute rather than leaving it unanswerable there.
39
60
  *
40
61
  * @example
41
62
  * <Density density="ultra-compact">
@@ -43,10 +64,12 @@ const DensityContext = React.createContext(null);
43
64
  * </Density>
44
65
  */
45
66
  function Density({ density, children, className, style }) {
67
+ const theme = React.useContext(AmbientThemeContext);
46
68
  return /* @__PURE__ */ jsx(DensityContext.Provider, {
47
69
  value: density,
48
70
  children: /* @__PURE__ */ jsx("div", {
49
71
  "data-density": density,
72
+ "data-cue-theme": theme ?? void 0,
50
73
  className,
51
74
  style,
52
75
  children
@@ -54,4 +77,4 @@ function Density({ density, children, className, style }) {
54
77
  });
55
78
  }
56
79
  //#endregion
57
- export { DEFAULT_DENSITY, DENSITY_LEVELS, Density, DensityContext };
80
+ export { AmbientThemeContext, DEFAULT_DENSITY, Density, DensityContext };