@cueplusplus/ui 0.1.0 → 0.3.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 (246) hide show
  1. package/CHANGELOG.md +705 -0
  2. package/dist/brand/_chassis.d.ts +54 -0
  3. package/dist/brand/_chassis.js +81 -0
  4. package/dist/brand/_geometry.js +41 -0
  5. package/dist/brand/cue-logotype.d.ts +29 -0
  6. package/dist/brand/cue-logotype.js +60 -0
  7. package/dist/brand/cue-mark.d.ts +30 -0
  8. package/dist/brand/cue-mark.js +61 -0
  9. package/dist/brand/index.d.ts +5 -0
  10. package/dist/brand/plussie.d.ts +67 -0
  11. package/dist/brand/plussie.js +125 -0
  12. package/dist/chat/agent-pile.js +1 -1
  13. package/dist/chat/ask-box.js +2 -2
  14. package/dist/chat/delegation-card.js +1 -1
  15. package/dist/chat/message.js +2 -2
  16. package/dist/chrome/_edge-scroller.d.ts +45 -0
  17. package/dist/chrome/_edge-scroller.js +149 -0
  18. package/dist/chrome/_glyphs.js +19 -1
  19. package/dist/chrome/_tabs-scroll.d.ts +13 -8
  20. package/dist/chrome/_tabs-scroll.js +13 -8
  21. package/dist/chrome/app-bar.d.ts +103 -0
  22. package/dist/chrome/app-bar.js +175 -0
  23. package/dist/chrome/app-shell.d.ts +125 -0
  24. package/dist/chrome/app-shell.js +167 -0
  25. package/dist/chrome/footer.d.ts +75 -0
  26. package/dist/chrome/footer.js +68 -0
  27. package/dist/chrome/index.d.ts +5 -1
  28. package/dist/chrome/index.js +4 -1
  29. package/dist/chrome/navigation-menu.js +1 -1
  30. package/dist/chrome/page-shell.d.ts +1 -1
  31. package/dist/chrome/page-shell.js +15 -5
  32. package/dist/chrome/segmented-control.d.ts +19 -0
  33. package/dist/chrome/segmented-control.js +40 -21
  34. package/dist/chrome/tabs.js +21 -65
  35. package/dist/chrome/toolbar.d.ts +22 -0
  36. package/dist/chrome/toolbar.js +26 -5
  37. package/dist/configurator/_overrides.js +22 -8
  38. package/dist/configurator/configurator.js +1 -1
  39. package/dist/configurator/panel-sections.js +10 -4
  40. package/dist/dmx/channel-matrix.js +1 -1
  41. package/dist/forms/otp-field.js +1 -1
  42. package/dist/index.d.ts +18 -9
  43. package/dist/index.js +16 -10
  44. package/dist/instruments/data-table.js +1 -1
  45. package/dist/instruments/index.d.ts +2 -2
  46. package/dist/instruments/index.js +2 -2
  47. package/dist/instruments/table.d.ts +14 -1
  48. package/dist/instruments/table.js +20 -1
  49. package/dist/layout/carousel.js +1 -1
  50. package/dist/layout/container.d.ts +1 -1
  51. package/dist/layout/container.js +6 -3
  52. package/dist/layout/index.d.ts +3 -3
  53. package/dist/layout/index.js +3 -3
  54. package/dist/layout/pagination.js +1 -1
  55. package/dist/layout/sidebar.d.ts +23 -3
  56. package/dist/layout/sidebar.js +18 -7
  57. package/dist/midi/spectrum-visualizer.js +1 -1
  58. package/dist/midi/timeline-ruler.js +1 -1
  59. package/dist/overlays/command-palette.js +1 -1
  60. package/dist/overlays/dialog.js +1 -1
  61. package/dist/overlays/dropdown-menu.js +2 -2
  62. package/dist/overlays/hover-card.js +1 -1
  63. package/dist/overlays/index.js +1 -1
  64. package/dist/overlays/popover.js +1 -1
  65. package/dist/overlays/sheet.js +1 -1
  66. package/dist/overlays/toast.js +1 -1
  67. package/dist/primitives/chip.d.ts +1 -1
  68. package/dist/primitives/index.d.ts +1 -1
  69. package/dist/primitives/index.js +1 -1
  70. package/dist/primitives/status-dot.d.ts +7 -0
  71. package/dist/primitives/status-dot.js +8 -1
  72. package/dist/styles.css +58 -2
  73. package/dist/system/density.d.ts +4 -1
  74. package/dist/system/density.js +12 -4
  75. package/dist/system/index.d.ts +4 -4
  76. package/dist/system/portal.d.ts +5 -5
  77. package/dist/system/portal.js +30 -11
  78. package/dist/system/prepaint.d.ts +34 -9
  79. package/dist/system/prepaint.js +48 -25
  80. package/dist/system/theme-provider.d.ts +48 -11
  81. package/dist/system/theme-provider.js +109 -35
  82. package/dist/system/use-density.d.ts +3 -3
  83. package/dist/system/use-density.js +16 -6
  84. package/dist/system/use-theme.d.ts +4 -2
  85. package/dist/system/use-theme.js +4 -2
  86. package/dist/theming/_presets.js +133 -5
  87. package/dist/theming/create-theme.d.ts +2 -2
  88. package/dist/theming/create-theme.js +37 -19
  89. package/dist/theming/serialize.d.ts +1 -1
  90. package/dist/theming/serialize.js +25 -1
  91. package/manifest/components/accordion.json +154 -0
  92. package/manifest/components/agent-pile.json +116 -0
  93. package/manifest/components/alert-dialog.json +190 -0
  94. package/manifest/components/app-bar.json +244 -0
  95. package/manifest/components/app-shell.json +291 -0
  96. package/manifest/components/app-window-frame.json +102 -0
  97. package/manifest/components/ask-box.json +209 -0
  98. package/manifest/components/autocomplete.json +197 -0
  99. package/manifest/components/avatar-group.json +72 -0
  100. package/manifest/components/avatar.json +95 -0
  101. package/manifest/components/breadcrumb.json +74 -0
  102. package/manifest/components/button-group.json +74 -0
  103. package/manifest/components/button.json +125 -0
  104. package/manifest/components/calendar.json +65 -0
  105. package/manifest/components/card.json +140 -0
  106. package/manifest/components/carousel.json +200 -0
  107. package/manifest/components/channel-matrix.json +173 -0
  108. package/manifest/components/chart-container.json +111 -0
  109. package/manifest/components/chart-ramp.json +72 -0
  110. package/manifest/components/chart-swatch.json +65 -0
  111. package/manifest/components/chart-tooltip-content.json +114 -0
  112. package/manifest/components/checkbox-group.json +68 -0
  113. package/manifest/components/checkbox.json +93 -0
  114. package/manifest/components/chip.json +132 -0
  115. package/manifest/components/collapsible.json +120 -0
  116. package/manifest/components/color-area.json +59 -0
  117. package/manifest/components/color-field.json +79 -0
  118. package/manifest/components/color-picker.json +175 -0
  119. package/manifest/components/color-slider.json +75 -0
  120. package/manifest/components/color-swatch.json +68 -0
  121. package/manifest/components/colors-section.json +66 -0
  122. package/manifest/components/combobox.json +198 -0
  123. package/manifest/components/command-palette.json +177 -0
  124. package/manifest/components/composer.json +176 -0
  125. package/manifest/components/container.json +60 -0
  126. package/manifest/components/context-menu.json +121 -0
  127. package/manifest/components/copy-button.json +93 -0
  128. package/manifest/components/cue-logotype.json +96 -0
  129. package/manifest/components/cue-mark.json +97 -0
  130. package/manifest/components/cue-portal-frame.json +55 -0
  131. package/manifest/components/data-table-pagination.json +83 -0
  132. package/manifest/components/data-table-toolbar.json +104 -0
  133. package/manifest/components/date-field.json +80 -0
  134. package/manifest/components/date-picker.json +191 -0
  135. package/manifest/components/date-range-picker.json +191 -0
  136. package/manifest/components/delegation-card.json +144 -0
  137. package/manifest/components/density.json +58 -0
  138. package/manifest/components/description-list.json +84 -0
  139. package/manifest/components/dialog.json +198 -0
  140. package/manifest/components/disclosure.json +109 -0
  141. package/manifest/components/dmx-bar.json +94 -0
  142. package/manifest/components/dmx-strip.json +101 -0
  143. package/manifest/components/drawer.json +179 -0
  144. package/manifest/components/dropdown-menu.json +229 -0
  145. package/manifest/components/empty-state.json +90 -0
  146. package/manifest/components/env-var-input.json +150 -0
  147. package/manifest/components/export-dialog.json +84 -0
  148. package/manifest/components/eyebrow.json +56 -0
  149. package/manifest/components/field-description.json +63 -0
  150. package/manifest/components/field-error.json +77 -0
  151. package/manifest/components/field-label.json +63 -0
  152. package/manifest/components/field.json +79 -0
  153. package/manifest/components/file-upload.json +159 -0
  154. package/manifest/components/flow-background.json +50 -0
  155. package/manifest/components/flow-controls.json +50 -0
  156. package/manifest/components/footer.json +112 -0
  157. package/manifest/components/grid.json +81 -0
  158. package/manifest/components/group-bar.json +102 -0
  159. package/manifest/components/hover-card.json +151 -0
  160. package/manifest/components/icon-button.json +88 -0
  161. package/manifest/components/info-tip.json +98 -0
  162. package/manifest/components/input-group.json +91 -0
  163. package/manifest/components/input.json +89 -0
  164. package/manifest/components/item.json +129 -0
  165. package/manifest/components/kbd.json +52 -0
  166. package/manifest/components/link.json +81 -0
  167. package/manifest/components/log-viewer.json +139 -0
  168. package/manifest/components/menubar.json +157 -0
  169. package/manifest/components/message-list.json +100 -0
  170. package/manifest/components/message.json +116 -0
  171. package/manifest/components/meter.json +114 -0
  172. package/manifest/components/multi-select.json +190 -0
  173. package/manifest/components/musical-time-input.json +113 -0
  174. package/manifest/components/navigation-menu.json +226 -0
  175. package/manifest/components/node-card.json +109 -0
  176. package/manifest/components/node-handle.json +69 -0
  177. package/manifest/components/number-field.json +107 -0
  178. package/manifest/components/otp-field.json +128 -0
  179. package/manifest/components/page-shell.json +96 -0
  180. package/manifest/components/pagination.json +92 -0
  181. package/manifest/components/panel-header.json +77 -0
  182. package/manifest/components/panel.json +71 -0
  183. package/manifest/components/password-input.json +119 -0
  184. package/manifest/components/piano-keyboard.json +120 -0
  185. package/manifest/components/plussie.json +111 -0
  186. package/manifest/components/popover.json +193 -0
  187. package/manifest/components/preset-section.json +73 -0
  188. package/manifest/components/progress.json +95 -0
  189. package/manifest/components/radio-group.json +73 -0
  190. package/manifest/components/radio.json +80 -0
  191. package/manifest/components/rating.json +141 -0
  192. package/manifest/components/resizable.json +88 -0
  193. package/manifest/components/row.json +109 -0
  194. package/manifest/components/scroll-area.json +91 -0
  195. package/manifest/components/scrollable-tabs-list.json +83 -0
  196. package/manifest/components/scrub-input.json +200 -0
  197. package/manifest/components/seam-cell.json +75 -0
  198. package/manifest/components/seam-grid.json +75 -0
  199. package/manifest/components/seam-list.json +56 -0
  200. package/manifest/components/search-input.json +134 -0
  201. package/manifest/components/section-header.json +112 -0
  202. package/manifest/components/segmented-control.json +138 -0
  203. package/manifest/components/select.json +194 -0
  204. package/manifest/components/separator.json +53 -0
  205. package/manifest/components/shape-section.json +66 -0
  206. package/manifest/components/sheet.json +186 -0
  207. package/manifest/components/sidebar.json +198 -0
  208. package/manifest/components/signal-edge.json +56 -0
  209. package/manifest/components/skeleton.json +46 -0
  210. package/manifest/components/slider.json +89 -0
  211. package/manifest/components/sparkline.json +76 -0
  212. package/manifest/components/spectrum-visualizer.json +115 -0
  213. package/manifest/components/spinner.json +61 -0
  214. package/manifest/components/stack.json +96 -0
  215. package/manifest/components/stat.json +87 -0
  216. package/manifest/components/status-bar.json +58 -0
  217. package/manifest/components/status-dot.json +78 -0
  218. package/manifest/components/stepper.json +89 -0
  219. package/manifest/components/switch.json +87 -0
  220. package/manifest/components/table-scroll-region.json +69 -0
  221. package/manifest/components/table.json +155 -0
  222. package/manifest/components/tabs.json +145 -0
  223. package/manifest/components/tags-input.json +190 -0
  224. package/manifest/components/terminal-frame.json +119 -0
  225. package/manifest/components/textarea.json +76 -0
  226. package/manifest/components/theme-configurator.json +124 -0
  227. package/manifest/components/theme-provider.json +134 -0
  228. package/manifest/components/threshold-rail.json +160 -0
  229. package/manifest/components/time-field.json +80 -0
  230. package/manifest/components/timeline-ruler.json +139 -0
  231. package/manifest/components/timeline.json +115 -0
  232. package/manifest/components/title-bar.json +82 -0
  233. package/manifest/components/toast.json +130 -0
  234. package/manifest/components/toggle-group.json +106 -0
  235. package/manifest/components/toggle.json +109 -0
  236. package/manifest/components/token-editor.json +90 -0
  237. package/manifest/components/toolbar.json +163 -0
  238. package/manifest/components/tooltip.json +164 -0
  239. package/manifest/components/tree-visibility-toggle.json +84 -0
  240. package/manifest/components/tree.json +140 -0
  241. package/manifest/components/two-step-button.json +113 -0
  242. package/manifest/components/universe-grid.json +127 -0
  243. package/manifest/components/usage-chart.json +124 -0
  244. package/manifest/manifest.json +2142 -0
  245. package/manifest/tokens.json +138 -0
  246. package/package.json +13 -5
@@ -453,6 +453,112 @@ const THEME_PRESETS = {
453
453
  "scrim": "rgba(0,0,0,0.35)"
454
454
  },
455
455
  fonts: { "font-mono": "\"JetBrains Mono\", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" }
456
+ },
457
+ requestport: {
458
+ dark: {
459
+ "bg": "#0a0d0e",
460
+ "sunken": "#07090a",
461
+ "surface-1": "#101416",
462
+ "surface-2": "#151a1d",
463
+ "surface-3": "#1a2024",
464
+ "fg": "#f0eee9",
465
+ "fg-muted": "#a3a6a8",
466
+ "fg-subtle": "#81868a",
467
+ "border": "#293034",
468
+ "border-strong": "#61686d",
469
+ "border-overlay": "#3f484e",
470
+ "accent": "#e66a45",
471
+ "accent-hover": "#f07a53",
472
+ "accent-fg": "#160d09",
473
+ "ok": "#63b482",
474
+ "busy": "#9a8cdb",
475
+ "warn": "#d6a65a",
476
+ "danger": "#dc6d69",
477
+ "info": "#6eb7d9",
478
+ "selection": "rgba(230,106,69,0.18)",
479
+ "focus": "#e66a45",
480
+ "data-ground": "#000000",
481
+ "scrim": "rgba(0,0,0,0.72)"
482
+ },
483
+ light: {
484
+ "bg": "#f4f3ef",
485
+ "sunken": "#e7e6e1",
486
+ "surface-1": "#faf9f6",
487
+ "surface-2": "#ffffff",
488
+ "surface-3": "#deddd8",
489
+ "fg": "#1a1d1e",
490
+ "fg-muted": "#53595c",
491
+ "fg-subtle": "#62696d",
492
+ "border": "#d0d2cf",
493
+ "border-strong": "#7f8689",
494
+ "border-overlay": "#aeb4b5",
495
+ "accent": "#b8492b",
496
+ "accent-hover": "#963b23",
497
+ "accent-fg": "#ffffff",
498
+ "ok": "#247746",
499
+ "busy": "#604aaa",
500
+ "warn": "#8a5b00",
501
+ "danger": "#aa2f2b",
502
+ "info": "#1d6587",
503
+ "selection": "rgba(184,73,43,0.18)",
504
+ "focus": "#b8492b",
505
+ "data-ground": "#000000",
506
+ "scrim": "rgba(20,18,15,0.45)"
507
+ },
508
+ fonts: { "font-mono": "\"Geist Mono\", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace" }
509
+ },
510
+ quotamate: {
511
+ dark: {
512
+ "bg": "#0e0e12",
513
+ "sunken": "#09090c",
514
+ "surface-1": "#15151a",
515
+ "surface-2": "#212127",
516
+ "surface-3": "#2b2b31",
517
+ "fg": "#f4f4f6",
518
+ "fg-muted": "#8b8b95",
519
+ "fg-subtle": "#62626b",
520
+ "border": "#2b2b31",
521
+ "border-strong": "#3d3d45",
522
+ "border-overlay": "#3d3d45",
523
+ "accent": "#00e5e5",
524
+ "accent-hover": "#33ffff",
525
+ "accent-fg": "#0e0e12",
526
+ "ok": "#22d967",
527
+ "busy": "#00e5e5",
528
+ "warn": "#ffab1a",
529
+ "danger": "#e13d3d",
530
+ "info": "#4a9eff",
531
+ "selection": "rgba(0,229,229,0.18)",
532
+ "focus": "#00e5e5",
533
+ "data-ground": "#000000",
534
+ "scrim": "rgba(0,0,0,0.55)"
535
+ },
536
+ light: {
537
+ "bg": "#fcfcfd",
538
+ "sunken": "#f1f1f4",
539
+ "surface-1": "#ffffff",
540
+ "surface-2": "#f4f4f6",
541
+ "surface-3": "#e7e7ec",
542
+ "fg": "#18181b",
543
+ "fg-muted": "#6e6e78",
544
+ "fg-subtle": "#9a9aa4",
545
+ "border": "#e2e2e8",
546
+ "border-strong": "#c9c9d2",
547
+ "border-overlay": "#c9c9d2",
548
+ "accent": "#0d7d7d",
549
+ "accent-hover": "#0a6767",
550
+ "accent-fg": "#ffffff",
551
+ "ok": "#17914a",
552
+ "busy": "#0d7d7d",
553
+ "warn": "#b46a00",
554
+ "danger": "#c22d2d",
555
+ "info": "#1f6fd4",
556
+ "selection": "rgba(13,125,125,0.16)",
557
+ "focus": "#0d7d7d",
558
+ "data-ground": "#ffffff",
559
+ "scrim": "rgba(0,0,0,0.55)"
560
+ },
561
+ fonts: { "font-mono": "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace" }
456
562
  }
457
563
  };
458
564
  /**
@@ -461,11 +567,16 @@ const THEME_PRESETS = {
461
567
  * has to beat, and `:root` carries the *default* theme's font override. A silent
462
568
  * theme would inherit cue's JetBrains Mono instead of the base stack, so every
463
569
  * block says what it owns. Mirrors `build.mjs`'s `THEME_FONTS` handling.
570
+ *
571
+ * Every entry is a generic or a face the platform ships. The sans stack named
572
+ * `Geist` until 2026-08-19 and no webfont was ever loaded to make it resolve, so
573
+ * it was a name most visitors silently fell straight past; Geist is now the head
574
+ * of the `geist` font pairing, which an app can actually deliver.
464
575
  */
465
576
  const BASE_FONT_STACKS = {
466
- "font-sans": "Geist, ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", \"Helvetica Neue\", sans-serif",
577
+ "font-sans": "ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", \"Helvetica Neue\", sans-serif",
467
578
  "font-mono": "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
468
- "font-display": "Geist, ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif"
579
+ "font-display": "ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif"
469
580
  };
470
581
  /**
471
582
  * The radius multiplier each density level contributes.
@@ -478,10 +589,27 @@ const BASE_FONT_STACKS = {
478
589
  */
479
590
  const DENSITY_RADIUS_SCALE = {
480
591
  "ultra-compact": .75,
592
+ "compact": 1,
481
593
  "normal": 1,
482
- "large": 1
594
+ "large": 1,
595
+ "ultra-large": 1
483
596
  };
484
597
  /** The default density, whose radius scale the uncrossed theme block carries. */
485
- const DEFAULT_DENSITY_LEVEL = "normal";
598
+ const DEFAULT_DENSITY_LEVEL = "compact";
599
+ /**
600
+ * What every theme block sets `--cue-font-mono` to.
601
+ *
602
+ * Neither the theme axis nor the font axis writes the shared token: each
603
+ * publishes its own half (`--cue-font-theme-mono` and `--cue-font-pairing-mono`)
604
+ * and this is the resolution, pairing first. It has to be a `var()` chain rather
605
+ * than a value because the two attributes land on different elements — a
606
+ * provider stamps `data-theme` on a `<div>` inside the `<html>` the pre-paint
607
+ * script stamped `data-font` on, and for an inherited property the nearer
608
+ * declaration would otherwise win whatever the stylesheet's order is.
609
+ *
610
+ * Mirrors `packages/tokens/build.mjs`'s `RESOLVED_MONO`, and
611
+ * `test/theming/presets.test.ts` fails when the two drift.
612
+ */
613
+ const RESOLVED_MONO = "var(--cue-font-pairing-mono, var(--cue-font-theme-mono))";
486
614
  //#endregion
487
- export { BASE_FONT_STACKS, DEFAULT_DENSITY_LEVEL, DENSITY_RADIUS_SCALE, THEME_COLOR_TOKENS, THEME_PRESETS };
615
+ export { BASE_FONT_STACKS, DEFAULT_DENSITY_LEVEL, DENSITY_RADIUS_SCALE, RESOLVED_MONO, THEME_COLOR_TOKENS, THEME_PRESETS };
@@ -30,7 +30,7 @@ declare const DEFAULT_THEME_BASE: ThemeName;
30
30
  /**
31
31
  * How far the sunken ground sits below the page, in oklch lightness.
32
32
  *
33
- * Small on purpose: sunken is a well, not a second theme. Across the eight
33
+ * Small on purpose: sunken is a well, not a second theme. Across the ten
34
34
  * shipped presets the authored gap runs −0.011 to −0.031.
35
35
  */
36
36
  declare const SUNKEN_LIGHTNESS_STEP = -0.02;
@@ -75,7 +75,7 @@ declare const ACCENT_FG_MINIMUM = 4.5;
75
75
  * extreme rather than to the arithmetic mirror: `1 − L` of a 0.16 near-black is a
76
76
  * 0.84 mid-grey, which is not a page. Compressing instead maps the ladder of
77
77
  * dark grounds onto a narrow paper band — a deeper dark theme gets a cleaner
78
- * white page — and lands within 0.01 of all eight authored light presets.
78
+ * white page — and lands within 0.01 of all ten authored light presets.
79
79
  */
80
80
  declare const LIGHT_GROUND_COMPRESSION = 0.1;
81
81
  interface ThemeAnchors {
@@ -1,7 +1,7 @@
1
1
  import { formatColorString } from "../color/_convert.js";
2
- import { BASE_FONT_STACKS, DEFAULT_DENSITY_LEVEL, DENSITY_RADIUS_SCALE, THEME_COLOR_TOKENS, THEME_PRESETS } from "./_presets.js";
2
+ import { BASE_FONT_STACKS, DEFAULT_DENSITY_LEVEL, DENSITY_RADIUS_SCALE, RESOLVED_MONO, THEME_COLOR_TOKENS, THEME_PRESETS } from "./_presets.js";
3
3
  import { WCAG_AA_TEXT, contrastRatio, contrastReport } from "./contrast.js";
4
- import { assertCssValue, assertThemeName, derivedTokens, serializeThemeCss, themeSelector, tokenProperty } from "./serialize.js";
4
+ import { assertCssValue, assertThemeName, derivedTokens, serializeSystemModeAliases, serializeThemeCss, themeSelector, tokenProperty } from "./serialize.js";
5
5
  import { clampChroma, converter, formatHex, inGamut, parse } from "culori";
6
6
  //#region src/theming/create-theme.ts
7
7
  /**
@@ -32,7 +32,7 @@ const DEFAULT_THEME_BASE = "cue";
32
32
  /**
33
33
  * How far the sunken ground sits below the page, in oklch lightness.
34
34
  *
35
- * Small on purpose: sunken is a well, not a second theme. Across the eight
35
+ * Small on purpose: sunken is a well, not a second theme. Across the ten
36
36
  * shipped presets the authored gap runs −0.011 to −0.031.
37
37
  */
38
38
  const SUNKEN_LIGHTNESS_STEP = -.02;
@@ -81,7 +81,7 @@ const ACCENT_FG_MINIMUM = WCAG_AA_TEXT;
81
81
  * extreme rather than to the arithmetic mirror: `1 − L` of a 0.16 near-black is a
82
82
  * 0.84 mid-grey, which is not a page. Compressing instead maps the ladder of
83
83
  * dark grounds onto a narrow paper band — a deeper dark theme gets a cleaner
84
- * white page — and lands within 0.01 of all eight authored light presets.
84
+ * white page — and lands within 0.01 of all ten authored light presets.
85
85
  */
86
86
  const LIGHT_GROUND_COMPRESSION = .1;
87
87
  /** Lightness a derived light colour steps down by while hunting for contrast. */
@@ -321,14 +321,23 @@ function resolveLight(dark, preset) {
321
321
  provisional
322
322
  };
323
323
  }
324
- /** The font declarations a theme block carries. */
324
+ /**
325
+ * The font declarations a theme block carries.
326
+ *
327
+ * The monospace lands on `--cue-font-theme-mono`, not on `--cue-font-mono`, and
328
+ * the shared token is restated as the resolution of the two axes' halves —
329
+ * exactly what a shipped preset's block does. A generated theme that wrote the
330
+ * shared token directly would beat a `[data-font]` pairing stamped on any
331
+ * ancestor, purely by sitting nearer to the text, and a consumer's own preset
332
+ * would be the one preset in the system the typeface picker could not move.
333
+ */
325
334
  function resolveFonts(anchors, preset) {
326
335
  const fonts = anchors.fonts ?? {};
327
336
  const declared = [];
328
337
  if (fonts.sans !== void 0) declared.push(["font-sans", fonts.sans]);
329
- declared.push(["font-mono", fonts.mono ?? lookup(preset, "font-mono") ?? BASE_FONT_STACKS["font-mono"]]);
338
+ declared.push(["font-theme-mono", fonts.mono ?? lookup(preset, "font-mono") ?? BASE_FONT_STACKS["font-mono"]]);
330
339
  if (fonts.display !== void 0) declared.push(["font-display", fonts.display]);
331
- return declared.map(([name, value]) => [tokenProperty(name), assertCssValue(name, value)]);
340
+ return [...declared.map(([name, value]) => [tokenProperty(name), assertCssValue(name, value)]), [tokenProperty("font-mono"), RESOLVED_MONO]];
332
341
  }
333
342
  /** Round a product of two scales to something a stylesheet can print. */
334
343
  const scaled = (a, b) => String(Number((a * b).toFixed(4)));
@@ -391,7 +400,7 @@ function createTheme(anchors) {
391
400
  const derived = Object.entries(derivedTokens());
392
401
  const fonts = resolveFonts(anchors, preset.fonts);
393
402
  const radius = anchors.radiusScale === void 0 ? null : radiusBlocks(name, anchors.radiusScale);
394
- const darkSections = [
403
+ const darkPaletteSections = [
395
404
  { declarations: colorDeclarations(dark.colors) },
396
405
  {
397
406
  comment: DERIVED_COMMENT,
@@ -400,25 +409,26 @@ function createTheme(anchors) {
400
409
  {
401
410
  comment: FONT_COMMENT,
402
411
  declarations: fonts
403
- },
404
- ...radius === null ? [] : [{
405
- comment: SHAPE_COMMENT,
406
- declarations: radius.base
407
- }]
412
+ }
408
413
  ];
414
+ const darkSections = [...darkPaletteSections, ...radius === null ? [] : [{
415
+ comment: SHAPE_COMMENT,
416
+ declarations: radius.base
417
+ }]];
418
+ const lightSections = light === null ? null : [{ declarations: colorDeclarations(light.colors) }, {
419
+ comment: DERIVED_COMMENT,
420
+ declarations: derived
421
+ }];
409
422
  const blocks = [
410
423
  {
411
424
  selector: themeSelector(name),
412
425
  colorScheme: "dark",
413
426
  sections: darkSections
414
427
  },
415
- ...light === null ? [] : [{
428
+ ...lightSections === null ? [] : [{
416
429
  selector: themeSelector(name, { mode: "light" }),
417
430
  colorScheme: "light",
418
- sections: [{ declarations: colorDeclarations(light.colors) }, {
419
- comment: DERIVED_COMMENT,
420
- declarations: derived
421
- }]
431
+ sections: lightSections
422
432
  }],
423
433
  ...radius?.blocks ?? []
424
434
  ];
@@ -432,7 +442,15 @@ function createTheme(anchors) {
432
442
  }]];
433
443
  return {
434
444
  name,
435
- css: serializeThemeCss(blocks, { banner: `@cueplusplus/ui — theme "${name}"` }),
445
+ css: `${serializeThemeCss(blocks, { banner: `@cueplusplus/ui — theme "${name}"` }).trimEnd()}\n\n${serializeSystemModeAliases(name, [{
446
+ mode: "dark",
447
+ colorScheme: "light dark",
448
+ sections: darkPaletteSections
449
+ }, {
450
+ mode: "light",
451
+ colorScheme: "light dark",
452
+ sections: lightSections ?? darkPaletteSections
453
+ }])}\n`,
436
454
  tokens: Object.fromEntries(darkSections.flatMap((section) => section.declarations)),
437
455
  light: light === null ? null : Object.fromEntries([...colorDeclarations(light.colors), ...derived]),
438
456
  report: contrastReport(inputs)
@@ -110,7 +110,7 @@ interface ThemeBlock {
110
110
  /** The selector the rule declares under. */
111
111
  selector: string;
112
112
  /** Emitted as `color-scheme`, ahead of the custom properties. Omit to skip it. */
113
- colorScheme?: "dark" | "light";
113
+ colorScheme?: "dark" | "light" | "light dark";
114
114
  /** The declarations, grouped into commented sections. */
115
115
  sections: readonly ThemeBlockSection[];
116
116
  }
@@ -148,6 +148,30 @@ function serializeThemeBlock(block) {
148
148
  }
149
149
  return `${block.selector} {\n${lines.join("\n")}\n}`;
150
150
  }
151
+ /** Indent a complete rule once so it can live inside an at-rule. */
152
+ function indentRule(rule) {
153
+ return rule.split("\n").map((line) => ` ${line}`).join("\n");
154
+ }
155
+ /**
156
+ * Alias resolved dark/light palettes onto the preserved logical `system` mode.
157
+ *
158
+ * Both `createTheme()` and the configurator call this function. Keeping the
159
+ * selector and media-query spelling here prevents exported overrides from
160
+ * drifting away from generated custom themes.
161
+ *
162
+ * @internal Used by package-owned theme serializers; not part of the public
163
+ * `@cueplusplus/ui/theming` barrel.
164
+ */
165
+ function serializeSystemModeAliases(theme, aliases) {
166
+ const name = assertThemeName(theme);
167
+ return aliases.map(({ mode, colorScheme, sections }) => {
168
+ return `@media (prefers-color-scheme: ${mode}) {\n${indentRule(serializeThemeBlock({
169
+ selector: `[data-theme="${name}"][data-mode="system"]`,
170
+ colorScheme,
171
+ sections
172
+ }))}\n}`;
173
+ }).join("\n\n");
174
+ }
151
175
  /**
152
176
  * A whole generated stylesheet: banner, then one rule per block.
153
177
  *
@@ -162,4 +186,4 @@ function serializeThemeCss(blocks, options = {}) {
162
186
  return `${[...options.banner === void 0 ? [] : [`/*! ${options.banner}\n * Generated by createTheme(). Do not edit by hand.\n */`], ...rules].join("\n\n")}\n`;
163
187
  }
164
188
  //#endregion
165
- export { CUE_TOKEN_PREFIX, DERIVED_TOKEN_TEMPLATES, THEME_NAME_PATTERN, assertCssValue, assertThemeName, derivedTokens, serializeThemeBlock, serializeThemeCss, themeSelector, tokenProperty };
189
+ export { CUE_TOKEN_PREFIX, DERIVED_TOKEN_TEMPLATES, THEME_NAME_PATTERN, assertCssValue, assertThemeName, derivedTokens, serializeSystemModeAliases, serializeThemeBlock, serializeThemeCss, themeSelector, tokenProperty };
@@ -0,0 +1,154 @@
1
+ {
2
+ "name": "Accordion",
3
+ "slug": "accordion",
4
+ "group": "layout",
5
+ "importPath": "@cueplusplus/ui",
6
+ "peerDependencies": [],
7
+ "clientOnly": true,
8
+ "description": "A stack of sections, one (or several) open at a time.\n\nWraps Base UI's `Accordion`, so the disclosure ARIA, keyboard handling and\nopen-state bookkeeping are the primitive's. This layer adds the console skin:\nhairline separation, mono summary rows on the control ladder, and a height\ntransition that respects `prefers-reduced-motion`.",
9
+ "props": [],
10
+ "typeReferences": [],
11
+ "subcomponents": [
12
+ "Root",
13
+ "Item",
14
+ "Header",
15
+ "Trigger",
16
+ "Panel"
17
+ ],
18
+ "parts": [
19
+ {
20
+ "name": "Root",
21
+ "usage": "Accordion.Root",
22
+ "description": "Groups the sections and owns which of them are open.",
23
+ "props": [
24
+ {
25
+ "name": "className",
26
+ "type": "string",
27
+ "required": false,
28
+ "defaultValue": null,
29
+ "description": "Extra classes for the accordion frame."
30
+ }
31
+ ],
32
+ "typeReferences": [
33
+ "Omit<BaseAccordion.Root.Props, \"className\">"
34
+ ]
35
+ },
36
+ {
37
+ "name": "Item",
38
+ "usage": "Accordion.Item",
39
+ "description": "One section.\n\nSeparation is a hairline the section draws above itself, dropped on the first\none — so a stack shows rules *between* sections and none against the rim of\nwhatever contains them. Same rule as `Row`, for the same reason.",
40
+ "props": [
41
+ {
42
+ "name": "className",
43
+ "type": "string",
44
+ "required": false,
45
+ "defaultValue": null,
46
+ "description": "Extra classes for the section."
47
+ }
48
+ ],
49
+ "typeReferences": [
50
+ "Omit<BaseAccordion.Item.Props, \"className\">"
51
+ ]
52
+ },
53
+ {
54
+ "name": "Header",
55
+ "usage": "Accordion.Header",
56
+ "description": "The heading that labels a section's panel. An `<h3>` with no type of its own.",
57
+ "props": [
58
+ {
59
+ "name": "className",
60
+ "type": "string",
61
+ "required": false,
62
+ "defaultValue": null,
63
+ "description": "Extra classes for the heading."
64
+ }
65
+ ],
66
+ "typeReferences": [
67
+ "Omit<BaseAccordion.Header.Props, \"className\">"
68
+ ]
69
+ },
70
+ {
71
+ "name": "Trigger",
72
+ "usage": "Accordion.Trigger",
73
+ "description": "The summary row that opens a section.\n\nA mono row on the control ladder, padded to the same gutters as a `Row`, with\na caret that rotates off the trigger's own `data-panel-open` — nothing in\nReact has to know the section is open for the arrow to turn.",
74
+ "props": [
75
+ {
76
+ "name": "className",
77
+ "type": "string",
78
+ "required": false,
79
+ "defaultValue": null,
80
+ "description": "Extra classes for the summary row."
81
+ }
82
+ ],
83
+ "typeReferences": [
84
+ "Omit<BaseAccordion.Trigger.Props, \"className\">"
85
+ ]
86
+ },
87
+ {
88
+ "name": "Panel",
89
+ "usage": "Accordion.Panel",
90
+ "description": "A section's body.\n\nHeight is animated from `--accordion-panel-height`, which Base UI measures.\nThe animating element carries no padding — padding is part of the box height,\nso it would be counted into the `0 → measured` transition and make the panel\njump at both ends — hence the inner body element.",
91
+ "props": [
92
+ {
93
+ "name": "className",
94
+ "type": "string",
95
+ "required": false,
96
+ "defaultValue": null,
97
+ "description": "Extra classes for the animating box. Padding belongs on `bodyClassName`."
98
+ },
99
+ {
100
+ "name": "bodyClassName",
101
+ "type": "string",
102
+ "required": false,
103
+ "defaultValue": null,
104
+ "description": "Extra classes for the padded body inside it."
105
+ }
106
+ ],
107
+ "typeReferences": [
108
+ "Omit<BaseAccordion.Panel.Props, \"className\">"
109
+ ]
110
+ }
111
+ ],
112
+ "variants": {},
113
+ "defaultVariants": {},
114
+ "tokensUsed": [
115
+ "--cue-accent",
116
+ "--cue-border",
117
+ "--cue-control-md",
118
+ "--cue-fg",
119
+ "--cue-fg-muted",
120
+ "--cue-fg-subtle",
121
+ "--cue-font-mono",
122
+ "--cue-icon-sm",
123
+ "--cue-pad-row-x",
124
+ "--cue-space-1",
125
+ "--cue-space-3",
126
+ "--cue-space-4",
127
+ "--cue-text-ui"
128
+ ],
129
+ "summary": "A stack of sections, one (or several) open at a time.",
130
+ "examples": [
131
+ {
132
+ "title": "Usage",
133
+ "code": "<Accordion.Root>\n <Accordion.Item value=\"routing\">\n <Accordion.Header><Accordion.Trigger>routing</Accordion.Trigger></Accordion.Header>\n <Accordion.Panel>…</Accordion.Panel>\n </Accordion.Item>\n</Accordion.Root>\n<Accordion.Root multiple defaultValue={[\"routing\"]}>…</Accordion.Root>",
134
+ "language": "tsx"
135
+ }
136
+ ],
137
+ "status": "todo-docs",
138
+ "url": "/docs/components/accordion",
139
+ "mdUrl": "/docs/components/accordion.md",
140
+ "jsonUrl": "/r/components/accordion.json",
141
+ "specimens": [
142
+ {
143
+ "title": "Accordion",
144
+ "group": "layout",
145
+ "components": [
146
+ "Accordion"
147
+ ],
148
+ "code": "<Accordion.Root className=\"w-full max-w-[36rem]\" defaultValue={[\"patch\"]}>\n <Accordion.Item value=\"patch\">\n <Accordion.Header>\n <Accordion.Trigger>Patch</Accordion.Trigger>\n </Accordion.Header>\n <Accordion.Panel>48 fixtures across 4 universes.</Accordion.Panel>\n </Accordion.Item>\n <Accordion.Item value=\"cues\">\n <Accordion.Header>\n <Accordion.Trigger>Cues</Accordion.Trigger>\n </Accordion.Header>\n <Accordion.Panel>12 cues, last edited 4 minutes ago.</Accordion.Panel>\n </Accordion.Item>\n <Accordion.Item value=\"network\" disabled>\n <Accordion.Header>\n <Accordion.Trigger>Network</Accordion.Trigger>\n </Accordion.Header>\n <Accordion.Panel>Art-Net on 10.0.0.42.</Accordion.Panel>\n </Accordion.Item>\n</Accordion.Root>",
149
+ "note": "Hairline-separated items with mono summary rows. Several can be open at once.",
150
+ "interaction": "the whole header row is the trigger; the panel animates its height and stills under prefers-reduced-motion."
151
+ }
152
+ ],
153
+ "todo": true
154
+ }
@@ -0,0 +1,116 @@
1
+ {
2
+ "name": "AgentPile",
3
+ "slug": "agent-pile",
4
+ "group": "chat",
5
+ "importPath": "@cueplusplus/ui",
6
+ "peerDependencies": [],
7
+ "clientOnly": true,
8
+ "description": "The roster of agents working on a thread, stacked into one object.\n\nThree states ride on each avatar, and none of them is colour-only: the\norchestrator wears a crown, a working agent gets a spinning arc, and an agent\nwaiting on the user gets a `?` badge — each of them also spelled into the\navatar's accessible name, so a screen reader hears \"Researcher · working\"\nrather than nothing at all.\n\nAvatars are outlined in the agent's colour rather than filled with it. A fill\nwould put arbitrary-hue ink on an arbitrary-hue ground at 20px; the outline\ntreatment is the same tinted-chip recipe the rest of the system uses and\nstays legible on every theme.",
9
+ "props": [
10
+ {
11
+ "name": "agents",
12
+ "type": "readonly AgentPileEntry[]",
13
+ "required": true,
14
+ "defaultValue": null,
15
+ "description": "The roster, in the order it should read. Renders nothing when empty."
16
+ },
17
+ {
18
+ "name": "root",
19
+ "type": "string",
20
+ "required": false,
21
+ "defaultValue": null,
22
+ "description": "Slug of the orchestrator: takes the theme accent and wears the crown."
23
+ },
24
+ {
25
+ "name": "selected",
26
+ "type": "string",
27
+ "required": false,
28
+ "defaultValue": null,
29
+ "description": "Slug of the lane currently open — that avatar gets a ring."
30
+ },
31
+ {
32
+ "name": "onSelect",
33
+ "type": "((slug: string) => void)",
34
+ "required": false,
35
+ "defaultValue": null,
36
+ "description": "Called with a slug when an avatar is pressed. Omit for a read-only pile."
37
+ },
38
+ {
39
+ "name": "max",
40
+ "type": "number",
41
+ "required": false,
42
+ "defaultValue": null,
43
+ "description": "Show at most this many; the rest collapse into a `+N` chip."
44
+ },
45
+ {
46
+ "name": "fanned",
47
+ "type": "boolean",
48
+ "required": false,
49
+ "defaultValue": null,
50
+ "description": "Force the fan open or shut. Omit to let hover and focus decide."
51
+ },
52
+ {
53
+ "name": "size",
54
+ "type": "\"sm\" | \"md\" | \"lg\"",
55
+ "required": false,
56
+ "defaultValue": "md",
57
+ "description": "Rung of the control ladder. Defaults to `\"md\"`."
58
+ },
59
+ {
60
+ "name": "aria-label",
61
+ "type": "string",
62
+ "required": false,
63
+ "defaultValue": null,
64
+ "description": "Accessible name for the group. Required in practice — name the roster."
65
+ }
66
+ ],
67
+ "typeReferences": [
68
+ "Omit<React.ComponentPropsWithoutRef<\"div\">, \"onSelect\">"
69
+ ],
70
+ "subcomponents": [],
71
+ "parts": [],
72
+ "variants": {},
73
+ "defaultVariants": {},
74
+ "tokensUsed": [
75
+ "--cue-accent",
76
+ "--cue-accent-fg",
77
+ "--cue-bg",
78
+ "--cue-border",
79
+ "--cue-control-lg",
80
+ "--cue-control-md",
81
+ "--cue-control-sm",
82
+ "--cue-fg-muted",
83
+ "--cue-font-mono",
84
+ "--cue-icon-sm",
85
+ "--cue-surface-2",
86
+ "--cue-surface-3",
87
+ "--cue-text-label",
88
+ "--cue-text-micro",
89
+ "--cue-text-ui"
90
+ ],
91
+ "summary": "The roster of agents working on a thread, stacked into one object.",
92
+ "examples": [
93
+ {
94
+ "title": "Usage",
95
+ "code": "<AgentPile aria-label=\"Agents\" agents={roster} root=\"chief\" onSelect={openLane} />\n<AgentPile aria-label=\"Agents\" agents={roster} max={5} fanned />",
96
+ "language": "tsx"
97
+ }
98
+ ],
99
+ "status": "todo-docs",
100
+ "url": "/docs/components/agent-pile",
101
+ "mdUrl": "/docs/components/agent-pile.md",
102
+ "jsonUrl": "/r/components/agent-pile.json",
103
+ "specimens": [
104
+ {
105
+ "title": "AgentPile",
106
+ "group": "chat",
107
+ "components": [
108
+ "AgentPile"
109
+ ],
110
+ "code": "<Specimens>\n {([\"sm\", \"md\", \"lg\"] as const).map((size) => (\n <Specimen key={size} label={size}>\n <AgentPile agents={AGENTS} root=\"orchestrator\" size={size} />\n </Specimen>\n ))}\n <Specimen label=\"max 4\">\n <AgentPile agents={AGENTS} root=\"orchestrator\" max={4} />\n </Specimen>\n <Specimen label=\"not fanned\">\n <AgentPile agents={AGENTS} root=\"orchestrator\" fanned={false} />\n </Specimen>\n <Specimen label=\"selected\">\n <AgentPile agents={AGENTS} root=\"orchestrator\" selected=\"patcher\" />\n </Specimen>\n</Specimens>",
111
+ "note": "Faces at −12px overlap, fanning to +4px on hover. The crown marks the orchestrator, an arc marks work in flight and a `?` marks an agent waiting on an answer.",
112
+ "interaction": "every face is a button with the agent's name; the pile is one tab stop and arrow keys move inside it."
113
+ }
114
+ ],
115
+ "todo": true
116
+ }