@cueplusplus/ui 0.1.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 (372) hide show
  1. package/dist/charts/_token.js +39 -0
  2. package/dist/charts/container.d.ts +58 -0
  3. package/dist/charts/container.js +77 -0
  4. package/dist/charts/index.d.ts +5 -0
  5. package/dist/charts/index.js +5 -0
  6. package/dist/charts/ramps.d.ts +140 -0
  7. package/dist/charts/ramps.js +615 -0
  8. package/dist/charts/theme.d.ts +112 -0
  9. package/dist/charts/theme.js +165 -0
  10. package/dist/charts/tones.d.ts +111 -0
  11. package/dist/charts/tones.js +127 -0
  12. package/dist/chat/_glyphs.js +55 -0
  13. package/dist/chat/agent-color.d.ts +84 -0
  14. package/dist/chat/agent-color.js +101 -0
  15. package/dist/chat/agent-pile.d.ts +55 -0
  16. package/dist/chat/agent-pile.js +121 -0
  17. package/dist/chat/ask-box.d.ts +88 -0
  18. package/dist/chat/ask-box.js +341 -0
  19. package/dist/chat/composer.d.ts +66 -0
  20. package/dist/chat/composer.js +144 -0
  21. package/dist/chat/delegation-card.d.ts +60 -0
  22. package/dist/chat/delegation-card.js +129 -0
  23. package/dist/chat/index.d.ts +8 -0
  24. package/dist/chat/index.js +8 -0
  25. package/dist/chat/message-list.d.ts +39 -0
  26. package/dist/chat/message-list.js +105 -0
  27. package/dist/chat/message.d.ts +47 -0
  28. package/dist/chat/message.js +108 -0
  29. package/dist/chrome/_glyphs.js +101 -0
  30. package/dist/chrome/_tabs-scroll.d.ts +62 -0
  31. package/dist/chrome/_tabs-scroll.js +68 -0
  32. package/dist/chrome/_tree.d.ts +75 -0
  33. package/dist/chrome/_tree.js +49 -0
  34. package/dist/chrome/empty-state.d.ts +37 -0
  35. package/dist/chrome/empty-state.js +57 -0
  36. package/dist/chrome/eyebrow.d.ts +29 -0
  37. package/dist/chrome/eyebrow.js +36 -0
  38. package/dist/chrome/index.d.ts +17 -0
  39. package/dist/chrome/index.js +17 -0
  40. package/dist/chrome/navigation-menu.d.ts +80 -0
  41. package/dist/chrome/navigation-menu.js +121 -0
  42. package/dist/chrome/page-shell.d.ts +38 -0
  43. package/dist/chrome/page-shell.js +66 -0
  44. package/dist/chrome/panel.d.ts +55 -0
  45. package/dist/chrome/panel.js +67 -0
  46. package/dist/chrome/row.d.ts +82 -0
  47. package/dist/chrome/row.js +106 -0
  48. package/dist/chrome/scroll-area.d.ts +39 -0
  49. package/dist/chrome/scroll-area.js +70 -0
  50. package/dist/chrome/section-header.d.ts +42 -0
  51. package/dist/chrome/section-header.js +79 -0
  52. package/dist/chrome/segmented-control.d.ts +58 -0
  53. package/dist/chrome/segmented-control.js +76 -0
  54. package/dist/chrome/status-bar.d.ts +46 -0
  55. package/dist/chrome/status-bar.js +56 -0
  56. package/dist/chrome/tabs.d.ts +80 -0
  57. package/dist/chrome/tabs.js +176 -0
  58. package/dist/chrome/title-bar.d.ts +37 -0
  59. package/dist/chrome/title-bar.js +45 -0
  60. package/dist/chrome/toolbar.d.ts +46 -0
  61. package/dist/chrome/toolbar.js +62 -0
  62. package/dist/chrome/tree.d.ts +98 -0
  63. package/dist/chrome/tree.js +248 -0
  64. package/dist/color/_checker.js +14 -0
  65. package/dist/color/_convert.d.ts +52 -0
  66. package/dist/color/_convert.js +66 -0
  67. package/dist/color/_glyphs.js +28 -0
  68. package/dist/color/_thumb.js +15 -0
  69. package/dist/color/_value.js +28 -0
  70. package/dist/color/color-area.d.ts +27 -0
  71. package/dist/color/color-area.js +40 -0
  72. package/dist/color/color-field.d.ts +32 -0
  73. package/dist/color/color-field.js +43 -0
  74. package/dist/color/color-picker.d.ts +71 -0
  75. package/dist/color/color-picker.js +178 -0
  76. package/dist/color/color-slider.d.ts +31 -0
  77. package/dist/color/color-slider.js +51 -0
  78. package/dist/color/color-swatch.d.ts +32 -0
  79. package/dist/color/color-swatch.js +44 -0
  80. package/dist/color/index.d.ts +7 -0
  81. package/dist/color/index.js +7 -0
  82. package/dist/configurator/_export.d.ts +78 -0
  83. package/dist/configurator/_export.js +261 -0
  84. package/dist/configurator/_glyphs.js +92 -0
  85. package/dist/configurator/_overrides.d.ts +247 -0
  86. package/dist/configurator/_overrides.js +514 -0
  87. package/dist/configurator/configurator.d.ts +71 -0
  88. package/dist/configurator/configurator.js +279 -0
  89. package/dist/configurator/export-dialog.d.ts +30 -0
  90. package/dist/configurator/export-dialog.js +121 -0
  91. package/dist/configurator/index.d.ts +8 -0
  92. package/dist/configurator/index.js +8 -0
  93. package/dist/configurator/panel-sections.d.ts +86 -0
  94. package/dist/configurator/panel-sections.js +316 -0
  95. package/dist/configurator/token-editor.d.ts +74 -0
  96. package/dist/configurator/token-editor.js +149 -0
  97. package/dist/configurator/use-zoom.d.ts +87 -0
  98. package/dist/configurator/use-zoom.js +113 -0
  99. package/dist/date/_glyphs.js +34 -0
  100. package/dist/date/_segments.js +55 -0
  101. package/dist/date/_trigger.js +31 -0
  102. package/dist/date/calendar.d.ts +25 -0
  103. package/dist/date/calendar.js +125 -0
  104. package/dist/date/date-field.d.ts +34 -0
  105. package/dist/date/date-field.js +41 -0
  106. package/dist/date/date-picker.d.ts +69 -0
  107. package/dist/date/date-picker.js +89 -0
  108. package/dist/date/date-range-picker.d.ts +65 -0
  109. package/dist/date/date-range-picker.js +92 -0
  110. package/dist/date/index.d.ts +6 -0
  111. package/dist/date/index.js +6 -0
  112. package/dist/date/time-field.d.ts +29 -0
  113. package/dist/date/time-field.js +36 -0
  114. package/dist/dmx/_ramp.d.ts +77 -0
  115. package/dist/dmx/_ramp.js +169 -0
  116. package/dist/dmx/_readout.js +53 -0
  117. package/dist/dmx/_universe.d.ts +105 -0
  118. package/dist/dmx/_universe.js +112 -0
  119. package/dist/dmx/channel-matrix.d.ts +81 -0
  120. package/dist/dmx/channel-matrix.js +285 -0
  121. package/dist/dmx/dmx-bar.d.ts +50 -0
  122. package/dist/dmx/dmx-bar.js +107 -0
  123. package/dist/dmx/dmx-strip.d.ts +41 -0
  124. package/dist/dmx/dmx-strip.js +196 -0
  125. package/dist/dmx/index.d.ts +7 -0
  126. package/dist/dmx/index.js +7 -0
  127. package/dist/dmx/universe-grid.d.ts +61 -0
  128. package/dist/dmx/universe-grid.js +182 -0
  129. package/dist/flow/_frame.d.ts +52 -0
  130. package/dist/flow/_frame.js +38 -0
  131. package/dist/flow/controls.d.ts +41 -0
  132. package/dist/flow/controls.js +53 -0
  133. package/dist/flow/flow.css +121 -0
  134. package/dist/flow/handles.d.ts +40 -0
  135. package/dist/flow/handles.js +61 -0
  136. package/dist/flow/index.d.ts +7 -0
  137. package/dist/flow/index.js +7 -0
  138. package/dist/flow/node-card.d.ts +71 -0
  139. package/dist/flow/node-card.js +102 -0
  140. package/dist/flow/signal-edge.d.ts +60 -0
  141. package/dist/flow/signal-edge.js +108 -0
  142. package/dist/flow/use-flow-theme.d.ts +69 -0
  143. package/dist/flow/use-flow-theme.js +109 -0
  144. package/dist/forms/_chassis.d.ts +64 -0
  145. package/dist/forms/_chassis.js +59 -0
  146. package/dist/forms/_glyphs.js +143 -0
  147. package/dist/forms/_listbox.js +55 -0
  148. package/dist/forms/autocomplete.d.ts +61 -0
  149. package/dist/forms/autocomplete.js +88 -0
  150. package/dist/forms/button-group.d.ts +47 -0
  151. package/dist/forms/button-group.js +52 -0
  152. package/dist/forms/checkbox.d.ts +51 -0
  153. package/dist/forms/checkbox.js +98 -0
  154. package/dist/forms/combobox.d.ts +73 -0
  155. package/dist/forms/combobox.js +108 -0
  156. package/dist/forms/env-var-input.d.ts +74 -0
  157. package/dist/forms/env-var-input.js +116 -0
  158. package/dist/forms/field.d.ts +89 -0
  159. package/dist/forms/field.js +102 -0
  160. package/dist/forms/file-upload.d.ts +113 -0
  161. package/dist/forms/file-upload.js +232 -0
  162. package/dist/forms/index.d.ts +26 -0
  163. package/dist/forms/index.js +26 -0
  164. package/dist/forms/input-group.d.ts +31 -0
  165. package/dist/forms/input-group.js +54 -0
  166. package/dist/forms/input.d.ts +33 -0
  167. package/dist/forms/input.js +36 -0
  168. package/dist/forms/multi-select.d.ts +62 -0
  169. package/dist/forms/multi-select.js +107 -0
  170. package/dist/forms/number-field.d.ts +38 -0
  171. package/dist/forms/number-field.js +64 -0
  172. package/dist/forms/otp-field.d.ts +54 -0
  173. package/dist/forms/otp-field.js +59 -0
  174. package/dist/forms/password-input.d.ts +46 -0
  175. package/dist/forms/password-input.js +62 -0
  176. package/dist/forms/radio-group.d.ts +50 -0
  177. package/dist/forms/radio-group.js +64 -0
  178. package/dist/forms/rating.d.ts +69 -0
  179. package/dist/forms/rating.js +103 -0
  180. package/dist/forms/scrub-input.d.ts +81 -0
  181. package/dist/forms/scrub-input.js +249 -0
  182. package/dist/forms/search-input.d.ts +54 -0
  183. package/dist/forms/search-input.js +112 -0
  184. package/dist/forms/select.d.ts +75 -0
  185. package/dist/forms/select.js +91 -0
  186. package/dist/forms/slider.d.ts +44 -0
  187. package/dist/forms/slider.js +65 -0
  188. package/dist/forms/switch.d.ts +36 -0
  189. package/dist/forms/switch.js +71 -0
  190. package/dist/forms/tags-input.d.ts +69 -0
  191. package/dist/forms/tags-input.js +148 -0
  192. package/dist/forms/textarea.d.ts +27 -0
  193. package/dist/forms/textarea.js +37 -0
  194. package/dist/forms/toggle-group.d.ts +41 -0
  195. package/dist/forms/toggle-group.js +56 -0
  196. package/dist/forms/toggle.d.ts +41 -0
  197. package/dist/forms/toggle.js +100 -0
  198. package/dist/index.d.ts +112 -0
  199. package/dist/index.js +104 -0
  200. package/dist/instruments/_ansi.js +116 -0
  201. package/dist/instruments/_glyphs.js +90 -0
  202. package/dist/instruments/_motion.js +56 -0
  203. package/dist/instruments/_rem.js +21 -0
  204. package/dist/instruments/app-window-frame.d.ts +48 -0
  205. package/dist/instruments/app-window-frame.js +76 -0
  206. package/dist/instruments/copy-button.d.ts +41 -0
  207. package/dist/instruments/copy-button.js +112 -0
  208. package/dist/instruments/data-table.d.ts +168 -0
  209. package/dist/instruments/data-table.js +212 -0
  210. package/dist/instruments/group-bar.d.ts +63 -0
  211. package/dist/instruments/group-bar.js +122 -0
  212. package/dist/instruments/index.d.ts +13 -0
  213. package/dist/instruments/index.js +13 -0
  214. package/dist/instruments/log-viewer.d.ts +74 -0
  215. package/dist/instruments/log-viewer.js +215 -0
  216. package/dist/instruments/meter.d.ts +77 -0
  217. package/dist/instruments/meter.js +96 -0
  218. package/dist/instruments/progress.d.ts +45 -0
  219. package/dist/instruments/progress.js +61 -0
  220. package/dist/instruments/seam-grid.d.ts +66 -0
  221. package/dist/instruments/seam-grid.js +78 -0
  222. package/dist/instruments/sparkline.d.ts +39 -0
  223. package/dist/instruments/sparkline.js +85 -0
  224. package/dist/instruments/stat.d.ts +35 -0
  225. package/dist/instruments/stat.js +59 -0
  226. package/dist/instruments/table.d.ts +51 -0
  227. package/dist/instruments/table.js +92 -0
  228. package/dist/instruments/terminal-frame.d.ts +89 -0
  229. package/dist/instruments/terminal-frame.js +256 -0
  230. package/dist/instruments/two-step-button.d.ts +47 -0
  231. package/dist/instruments/two-step-button.js +147 -0
  232. package/dist/instruments/usage-chart.d.ts +55 -0
  233. package/dist/instruments/usage-chart.js +235 -0
  234. package/dist/layout/_collapse.js +46 -0
  235. package/dist/layout/_glyphs.js +45 -0
  236. package/dist/layout/accordion.d.ts +52 -0
  237. package/dist/layout/accordion.js +81 -0
  238. package/dist/layout/breadcrumb.d.ts +35 -0
  239. package/dist/layout/breadcrumb.js +67 -0
  240. package/dist/layout/card.d.ts +51 -0
  241. package/dist/layout/card.js +76 -0
  242. package/dist/layout/carousel.d.ts +96 -0
  243. package/dist/layout/carousel.js +211 -0
  244. package/dist/layout/collapsible.d.ts +74 -0
  245. package/dist/layout/collapsible.js +126 -0
  246. package/dist/layout/container.d.ts +27 -0
  247. package/dist/layout/container.js +40 -0
  248. package/dist/layout/description-list.d.ts +24 -0
  249. package/dist/layout/description-list.js +37 -0
  250. package/dist/layout/grid.d.ts +40 -0
  251. package/dist/layout/grid.js +48 -0
  252. package/dist/layout/index.d.ts +15 -0
  253. package/dist/layout/index.js +15 -0
  254. package/dist/layout/item.d.ts +65 -0
  255. package/dist/layout/item.js +100 -0
  256. package/dist/layout/link.d.ts +48 -0
  257. package/dist/layout/link.js +63 -0
  258. package/dist/layout/pagination.d.ts +54 -0
  259. package/dist/layout/pagination.js +121 -0
  260. package/dist/layout/resizable.d.ts +38 -0
  261. package/dist/layout/resizable.js +68 -0
  262. package/dist/layout/sidebar.d.ts +67 -0
  263. package/dist/layout/sidebar.js +129 -0
  264. package/dist/layout/stack.d.ts +46 -0
  265. package/dist/layout/stack.js +62 -0
  266. package/dist/layout/stepper.d.ts +49 -0
  267. package/dist/layout/stepper.js +81 -0
  268. package/dist/layout/timeline.d.ts +43 -0
  269. package/dist/layout/timeline.js +63 -0
  270. package/dist/lib/aria-class.js +24 -0
  271. package/dist/lib/cn.js +18 -0
  272. package/dist/lib/compose.js +38 -0
  273. package/dist/lib/cva.d.ts +18 -0
  274. package/dist/lib/cva.js +65 -0
  275. package/dist/midi/_notes.d.ts +101 -0
  276. package/dist/midi/_notes.js +183 -0
  277. package/dist/midi/_ruler.d.ts +100 -0
  278. package/dist/midi/_ruler.js +105 -0
  279. package/dist/midi/_time.d.ts +107 -0
  280. package/dist/midi/_time.js +130 -0
  281. package/dist/midi/index.d.ts +9 -0
  282. package/dist/midi/index.js +9 -0
  283. package/dist/midi/musical-time-input.d.ts +48 -0
  284. package/dist/midi/musical-time-input.js +154 -0
  285. package/dist/midi/piano-keyboard.d.ts +50 -0
  286. package/dist/midi/piano-keyboard.js +193 -0
  287. package/dist/midi/spectrum-visualizer.d.ts +65 -0
  288. package/dist/midi/spectrum-visualizer.js +213 -0
  289. package/dist/midi/threshold-rail.d.ts +72 -0
  290. package/dist/midi/threshold-rail.js +214 -0
  291. package/dist/midi/timeline-ruler.d.ts +83 -0
  292. package/dist/midi/timeline-ruler.js +152 -0
  293. package/dist/overlays/_debounce.js +34 -0
  294. package/dist/overlays/_glyphs.js +59 -0
  295. package/dist/overlays/_surface.d.ts +70 -0
  296. package/dist/overlays/_surface.js +70 -0
  297. package/dist/overlays/_wheel.js +42 -0
  298. package/dist/overlays/alert-dialog.d.ts +67 -0
  299. package/dist/overlays/alert-dialog.js +117 -0
  300. package/dist/overlays/command-palette.d.ts +93 -0
  301. package/dist/overlays/command-palette.js +193 -0
  302. package/dist/overlays/context-menu.d.ts +64 -0
  303. package/dist/overlays/context-menu.js +78 -0
  304. package/dist/overlays/dialog.d.ts +72 -0
  305. package/dist/overlays/dialog.js +124 -0
  306. package/dist/overlays/drawer.d.ts +75 -0
  307. package/dist/overlays/drawer.js +151 -0
  308. package/dist/overlays/dropdown-menu.d.ts +79 -0
  309. package/dist/overlays/dropdown-menu.js +156 -0
  310. package/dist/overlays/hover-card.d.ts +58 -0
  311. package/dist/overlays/hover-card.js +91 -0
  312. package/dist/overlays/index.d.ts +15 -0
  313. package/dist/overlays/index.js +15 -0
  314. package/dist/overlays/info-tip.d.ts +41 -0
  315. package/dist/overlays/info-tip.js +45 -0
  316. package/dist/overlays/menubar.d.ts +72 -0
  317. package/dist/overlays/menubar.js +100 -0
  318. package/dist/overlays/popover.d.ts +66 -0
  319. package/dist/overlays/popover.js +114 -0
  320. package/dist/overlays/sheet.d.ts +78 -0
  321. package/dist/overlays/sheet.js +131 -0
  322. package/dist/overlays/toast.d.ts +106 -0
  323. package/dist/overlays/toast.js +146 -0
  324. package/dist/overlays/tooltip.d.ts +57 -0
  325. package/dist/overlays/tooltip.js +95 -0
  326. package/dist/primitives/avatar.d.ts +51 -0
  327. package/dist/primitives/avatar.js +93 -0
  328. package/dist/primitives/button.d.ts +46 -0
  329. package/dist/primitives/button.js +94 -0
  330. package/dist/primitives/chip.d.ts +47 -0
  331. package/dist/primitives/chip.js +152 -0
  332. package/dist/primitives/icon-button.d.ts +41 -0
  333. package/dist/primitives/icon-button.js +59 -0
  334. package/dist/primitives/index.d.ts +10 -0
  335. package/dist/primitives/index.js +10 -0
  336. package/dist/primitives/kbd.d.ts +17 -0
  337. package/dist/primitives/kbd.js +24 -0
  338. package/dist/primitives/separator.d.ts +25 -0
  339. package/dist/primitives/separator.js +30 -0
  340. package/dist/primitives/skeleton.d.ts +20 -0
  341. package/dist/primitives/skeleton.js +27 -0
  342. package/dist/primitives/spinner.d.ts +26 -0
  343. package/dist/primitives/spinner.js +31 -0
  344. package/dist/primitives/status-dot.d.ts +44 -0
  345. package/dist/primitives/status-dot.js +50 -0
  346. package/dist/styles.css +19 -0
  347. package/dist/system/density.d.ts +33 -0
  348. package/dist/system/density.js +49 -0
  349. package/dist/system/index.d.ts +8 -0
  350. package/dist/system/index.js +7 -0
  351. package/dist/system/portal.d.ts +51 -0
  352. package/dist/system/portal.js +122 -0
  353. package/dist/system/prepaint.d.ts +38 -0
  354. package/dist/system/prepaint.js +37 -0
  355. package/dist/system/theme-provider.d.ts +72 -0
  356. package/dist/system/theme-provider.js +252 -0
  357. package/dist/system/use-density.d.ts +33 -0
  358. package/dist/system/use-density.js +84 -0
  359. package/dist/system/use-isomorphic-layout-effect.js +15 -0
  360. package/dist/system/use-theme.d.ts +19 -0
  361. package/dist/system/use-theme.js +25 -0
  362. package/dist/theming/_presets.d.ts +11 -0
  363. package/dist/theming/_presets.js +487 -0
  364. package/dist/theming/contrast.d.ts +110 -0
  365. package/dist/theming/contrast.js +167 -0
  366. package/dist/theming/create-theme.d.ts +165 -0
  367. package/dist/theming/create-theme.js +442 -0
  368. package/dist/theming/index.d.ts +5 -0
  369. package/dist/theming/index.js +5 -0
  370. package/dist/theming/serialize.d.ts +145 -0
  371. package/dist/theming/serialize.js +165 -0
  372. package/package.json +216 -0
@@ -0,0 +1,42 @@
1
+ import * as React from "react";
2
+ //#region src/chrome/section-header.d.ts
3
+ interface SectionHeaderProps extends Omit<React.ComponentPropsWithoutRef<"div">, "onToggle"> {
4
+ /** The group's name. Rendered uppercase in the smallest mono label type. */
5
+ label: React.ReactNode;
6
+ /** Optional count shown after the label — how many things are in the group. */
7
+ count?: number;
8
+ /**
9
+ * Right-hand slot. Rendered *outside* the collapse toggle so clicking an
10
+ * action never folds the section shut under the user's cursor.
11
+ */
12
+ action?: React.ReactNode;
13
+ /** Turn the label into a disclosure button that shows and hides `children`. */
14
+ collapsible?: boolean;
15
+ /** Initial open state when uncontrolled. Defaults to `true`. */
16
+ defaultOpen?: boolean;
17
+ /** Open state when controlled. Pass with `onOpenChange`. */
18
+ open?: boolean;
19
+ /** Called with the next open state whenever the toggle is pressed. */
20
+ onOpenChange?: (open: boolean) => void;
21
+ /** The section body. Hidden while a collapsible section is closed. */
22
+ children?: React.ReactNode;
23
+ }
24
+ /**
25
+ * A faint label with a rule running off it — the heading for a group of rows.
26
+ *
27
+ * A label and a hairline, deliberately, not a bordered box: a heading that is
28
+ * itself a panel competes with the panels underneath it and reads as another
29
+ * object rather than as their title (the quotamate `AccountGroup` ruling). The
30
+ * rule is a `flex-1` block, so it always fills exactly the space the label and
31
+ * the count leave behind.
32
+ *
33
+ * @example
34
+ * <SectionHeader label="Universes" count={4} />
35
+ * @example
36
+ * <SectionHeader label="Scenes" collapsible action={<IconButton aria-label="Add" icon={Plus} />}>
37
+ * <SeamList>{scenes.map((s) => <Row seam key={s.id}>{s.name}</Row>)}</SeamList>
38
+ * </SectionHeader>
39
+ */
40
+ declare const SectionHeader: React.ForwardRefExoticComponent<SectionHeaderProps & React.RefAttributes<HTMLDivElement>>;
41
+ //#endregion
42
+ export { SectionHeader, SectionHeaderProps };
@@ -0,0 +1,79 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { ChevronRightGlyph } from "./_glyphs.js";
4
+ import * as React from "react";
5
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/chrome/section-header.tsx
7
+ /**
8
+ * A faint label with a rule running off it — the heading for a group of rows.
9
+ *
10
+ * A label and a hairline, deliberately, not a bordered box: a heading that is
11
+ * itself a panel competes with the panels underneath it and reads as another
12
+ * object rather than as their title (the quotamate `AccountGroup` ruling). The
13
+ * rule is a `flex-1` block, so it always fills exactly the space the label and
14
+ * the count leave behind.
15
+ *
16
+ * @example
17
+ * <SectionHeader label="Universes" count={4} />
18
+ * @example
19
+ * <SectionHeader label="Scenes" collapsible action={<IconButton aria-label="Add" icon={Plus} />}>
20
+ * <SeamList>{scenes.map((s) => <Row seam key={s.id}>{s.name}</Row>)}</SeamList>
21
+ * </SectionHeader>
22
+ */
23
+ const SectionHeader = React.forwardRef(function SectionHeader({ className, label, count, action, collapsible = false, defaultOpen = true, open: openProp, onOpenChange, children, ...elementProps }, ref) {
24
+ const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen);
25
+ const open = openProp ?? uncontrolledOpen;
26
+ const toggle = () => {
27
+ const next = !open;
28
+ if (openProp === void 0) setUncontrolledOpen(next);
29
+ onOpenChange?.(next);
30
+ };
31
+ const headContent = /* @__PURE__ */ jsxs(Fragment, { children: [
32
+ collapsible ? /* @__PURE__ */ jsx(ChevronRightGlyph, {
33
+ "data-slot": "section-header-chevron",
34
+ className: cn("size-icon-sm shrink-0 text-fg-subtle transition-transform duration-150 motion-reduce:transition-none", open ? "rotate-90" : "rotate-0")
35
+ }) : null,
36
+ /* @__PURE__ */ jsx("span", {
37
+ "data-slot": "section-header-label",
38
+ className: "shrink-0 font-mono text-(length:--cue-text-label) tracking-[0.15em] text-fg-muted uppercase",
39
+ children: label
40
+ }),
41
+ count === void 0 ? null : /* @__PURE__ */ jsx("span", {
42
+ "data-slot": "section-header-count",
43
+ className: "shrink-0 font-mono text-(length:--cue-text-label) tabular-nums text-fg-subtle",
44
+ children: count
45
+ }),
46
+ /* @__PURE__ */ jsx("span", {
47
+ "data-slot": "section-header-rule",
48
+ "aria-hidden": "true",
49
+ className: "h-px min-w-(--cue-space-4) flex-1 bg-border"
50
+ })
51
+ ] });
52
+ const headClasses = "flex min-w-0 flex-1 items-center gap-(--cue-space-3)";
53
+ return /* @__PURE__ */ jsxs("div", {
54
+ ref,
55
+ "data-slot": "section-header",
56
+ className: cn("flex w-full flex-col gap-(--cue-space-3)", className),
57
+ ...elementProps,
58
+ children: [/* @__PURE__ */ jsxs("div", {
59
+ className: "flex items-center gap-(--cue-space-3)",
60
+ children: [collapsible ? /* @__PURE__ */ jsx("button", {
61
+ type: "button",
62
+ "aria-expanded": open,
63
+ onClick: toggle,
64
+ "data-slot": "section-header-toggle",
65
+ className: cn(headClasses, "cursor-pointer text-left outline-none hover:text-fg focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-accent"),
66
+ children: headContent
67
+ }) : /* @__PURE__ */ jsx("div", {
68
+ className: headClasses,
69
+ children: headContent
70
+ }), action === void 0 ? null : /* @__PURE__ */ jsx("div", {
71
+ "data-slot": "section-header-action",
72
+ className: "flex shrink-0 items-center gap-(--cue-space-2)",
73
+ children: action
74
+ })]
75
+ }), children !== void 0 && (!collapsible || open) ? children : null]
76
+ });
77
+ });
78
+ //#endregion
79
+ export { SectionHeader };
@@ -0,0 +1,58 @@
1
+ import * as React from "react";
2
+ import { ToggleGroup } from "@base-ui/react/toggle-group";
3
+ //#region src/chrome/segmented-control.d.ts
4
+ /** The rung of the density control ladder a segmented control sits on. */
5
+ type SegmentedControlSize = "sm" | "md" | "lg";
6
+ /** One segment of a {@link SegmentedControl}. */
7
+ interface SegmentedControlItem {
8
+ /** The value reported when this segment is picked. Must be unique. */
9
+ value: string;
10
+ /** What the segment says. Keep it to one word where possible. */
11
+ label: React.ReactNode;
12
+ /** Optional leading icon (e.g. a lucide icon), drawn `aria-hidden`. */
13
+ icon?: React.ElementType;
14
+ /** Grey this segment out and make it unpickable. */
15
+ disabled?: boolean;
16
+ }
17
+ interface SegmentedControlProps extends Omit<ToggleGroup.Props<string>, "value" | "defaultValue" | "onValueChange" | "multiple" | "className" | "children"> {
18
+ /** The segments, in display order. */
19
+ items: readonly SegmentedControlItem[];
20
+ /** The picked value when controlled. Pass with `onValueChange`. */
21
+ value?: string;
22
+ /** The initially picked value when uncontrolled. */
23
+ defaultValue?: string;
24
+ /** Called with the newly picked value. Never called with `undefined`. */
25
+ onValueChange?: (value: string) => void;
26
+ /** Which rung of the control ladder to sit on. Defaults to `"md"`. */
27
+ size?: SegmentedControlSize;
28
+ /** Extra classes for the group frame. */
29
+ className?: string;
30
+ /** Extra classes for every segment. */
31
+ itemClassName?: string;
32
+ }
33
+ /**
34
+ * A one-of-N switch drawn as a row of segments: the console's view picker.
35
+ *
36
+ * Built on Base UI's `ToggleGroup`, so arrow-key roving focus and the
37
+ * pressed-state ARIA come from the primitive. Two rules are added on top:
38
+ *
39
+ * 1. **It cannot be emptied.** A toggle group lets you unpress the pressed
40
+ * item; a segmented control is a choice between N things, so clicking the
41
+ * active segment is a no-op rather than a way to end up with nothing
42
+ * selected. This is why the underlying group is always controlled here, even
43
+ * when the wrapper is not.
44
+ * 2. **The active segment is tinted, not filled** — see {@link ITEM_CLASSES}.
45
+ *
46
+ * Give the group an `aria-label`: on its own it is an unnamed group of buttons.
47
+ *
48
+ * @example
49
+ * <SegmentedControl
50
+ * aria-label="View"
51
+ * value={view}
52
+ * onValueChange={setView}
53
+ * items={[{ value: "beams", label: "Beams" }, { value: "patch", label: "Patch" }]}
54
+ * />
55
+ */
56
+ declare const SegmentedControl: React.ForwardRefExoticComponent<Omit<SegmentedControlProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
57
+ //#endregion
58
+ export { SegmentedControl, SegmentedControlItem, SegmentedControlProps, SegmentedControlSize };
@@ -0,0 +1,76 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import * as React from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { Toggle } from "@base-ui/react/toggle";
6
+ import { ToggleGroup } from "@base-ui/react/toggle-group";
7
+ //#region src/chrome/segmented-control.tsx
8
+ const ITEM_SIZES = {
9
+ sm: "h-control-sm px-(--cue-space-3) text-(length:--cue-text-label)",
10
+ md: "h-control-md px-(--cue-space-4) text-(length:--cue-text-ui)",
11
+ lg: "h-control-lg px-(--cue-space-5) text-(length:--cue-text-body)"
12
+ };
13
+ /**
14
+ * The pressed segment is marked with `accent-soft` and accent ink — never a
15
+ * solid accent fill. A solid bar inside a small control reads as a second,
16
+ * louder button and drowns the labels around it (the luma defect ruling); the
17
+ * soft tint says "this one" at exactly the volume a view switcher deserves.
18
+ */
19
+ const ITEM_CLASSES = "inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-(--cue-space-2) whitespace-nowrap rounded-(--radius-control) font-mono text-fg-muted transition-colors duration-150 outline-none hover:text-fg data-[pressed]:bg-accent-soft data-[pressed]:text-accent focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-1 focus-visible:outline-accent disabled:pointer-events-none disabled:opacity-40 data-[disabled]:pointer-events-none data-[disabled]:opacity-40";
20
+ /**
21
+ * A one-of-N switch drawn as a row of segments: the console's view picker.
22
+ *
23
+ * Built on Base UI's `ToggleGroup`, so arrow-key roving focus and the
24
+ * pressed-state ARIA come from the primitive. Two rules are added on top:
25
+ *
26
+ * 1. **It cannot be emptied.** A toggle group lets you unpress the pressed
27
+ * item; a segmented control is a choice between N things, so clicking the
28
+ * active segment is a no-op rather than a way to end up with nothing
29
+ * selected. This is why the underlying group is always controlled here, even
30
+ * when the wrapper is not.
31
+ * 2. **The active segment is tinted, not filled** — see {@link ITEM_CLASSES}.
32
+ *
33
+ * Give the group an `aria-label`: on its own it is an unnamed group of buttons.
34
+ *
35
+ * @example
36
+ * <SegmentedControl
37
+ * aria-label="View"
38
+ * value={view}
39
+ * onValueChange={setView}
40
+ * items={[{ value: "beams", label: "Beams" }, { value: "patch", label: "Patch" }]}
41
+ * />
42
+ */
43
+ const SegmentedControl = React.forwardRef(function SegmentedControl({ items, value: valueProp, defaultValue, onValueChange, size = "md", className, itemClassName, ...groupProps }, ref) {
44
+ const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue);
45
+ const value = valueProp ?? uncontrolledValue;
46
+ const handleValueChange = (groupValue) => {
47
+ const next = groupValue[0];
48
+ if (next === void 0 || next === value) return;
49
+ if (valueProp === void 0) setUncontrolledValue(next);
50
+ onValueChange?.(next);
51
+ };
52
+ const iconSize = size === "sm" ? "size-icon-sm" : "size-icon-md";
53
+ return /* @__PURE__ */ jsx(ToggleGroup, {
54
+ ref,
55
+ value: value === void 0 ? [] : [value],
56
+ onValueChange: handleValueChange,
57
+ "data-slot": "segmented-control",
58
+ className: cn("inline-flex items-center gap-(--cue-space-1) rounded-(--radius-control) border border-border bg-surface-1 p-(--cue-space-1)", className),
59
+ ...groupProps,
60
+ children: items.map((item) => {
61
+ const Icon = item.icon;
62
+ return /* @__PURE__ */ jsxs(Toggle, {
63
+ value: item.value,
64
+ disabled: item.disabled,
65
+ "data-slot": "segmented-control-item",
66
+ className: cn(ITEM_CLASSES, ITEM_SIZES[size], itemClassName),
67
+ children: [Icon === void 0 ? null : /* @__PURE__ */ jsx(Icon, {
68
+ "aria-hidden": "true",
69
+ className: cn("shrink-0", iconSize)
70
+ }), item.label]
71
+ }, item.value);
72
+ })
73
+ });
74
+ });
75
+ //#endregion
76
+ export { SegmentedControl };
@@ -0,0 +1,46 @@
1
+ import * as React from "react";
2
+ //#region src/chrome/status-bar.d.ts
3
+ /**
4
+ * Ink for a status-bar item. `neutral` inherits the bar's own subtle grey; the
5
+ * rest are the shared status vocabulary, so "3 faults" in the status bar is the
6
+ * same red as the danger `Chip` that raised it.
7
+ */
8
+ type StatusBarTone = "neutral" | "accent" | "ok" | "busy" | "warn" | "danger" | "info";
9
+ /** Props for {@link StatusBar}: the native `<div>` surface plus `className`. */
10
+ type StatusBarProps = React.ComponentPropsWithoutRef<"div">;
11
+ interface StatusBarItemProps extends React.ComponentPropsWithoutRef<"div"> {
12
+ /** Ink for this item. Defaults to the bar's own subtle grey. */
13
+ tone?: StatusBarTone;
14
+ /**
15
+ * Start the trailing cluster here: pushes this item and everything after it
16
+ * to the far edge. Cheaper and more robust than a spacer element, which a
17
+ * caller has to remember to keep in the right place.
18
+ */
19
+ push?: boolean;
20
+ /** Optional leading icon (e.g. a lucide icon), drawn `aria-hidden`. */
21
+ icon?: React.ElementType;
22
+ }
23
+ /**
24
+ * The quiet strip along the bottom of a window.
25
+ *
26
+ * The smallest type in the system in the subtlest ink: a status bar is read
27
+ * when you go looking for it and ignored otherwise, so it must never compete
28
+ * with the work above it. Height comes from `--cue-chrome-statusbar`.
29
+ *
30
+ * Not a live region — a status bar changes constantly (frame counters, DMX
31
+ * output), and announcing every change would make the app unusable with a
32
+ * screen reader. Put anything that genuinely must be announced in a `Toast`.
33
+ *
34
+ * Static markup — no `"use client"`.
35
+ *
36
+ * @example
37
+ * <StatusBar>
38
+ * <StatusBar.Item icon={Plug} tone="ok">Art-Net connected</StatusBar.Item>
39
+ * <StatusBar.Item push>512 channels</StatusBar.Item>
40
+ * </StatusBar>
41
+ */
42
+ declare const StatusBar: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>> & {
43
+ Item: React.ForwardRefExoticComponent<StatusBarItemProps & React.RefAttributes<HTMLDivElement>>;
44
+ };
45
+ //#endregion
46
+ export { StatusBar, StatusBarItemProps, StatusBarProps, StatusBarTone };
@@ -0,0 +1,56 @@
1
+ import { cn } from "../lib/cn.js";
2
+ import * as React from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ //#region src/chrome/status-bar.tsx
5
+ const ITEM_TONES = {
6
+ neutral: "",
7
+ accent: "text-accent",
8
+ ok: "text-ok",
9
+ busy: "text-busy",
10
+ warn: "text-warn",
11
+ danger: "text-danger",
12
+ info: "text-info"
13
+ };
14
+ const StatusBarRoot = React.forwardRef(function StatusBar({ className, ...elementProps }, ref) {
15
+ return /* @__PURE__ */ jsx("div", {
16
+ ref,
17
+ "data-slot": "status-bar",
18
+ className: cn("flex h-(--cue-chrome-statusbar) w-full shrink-0 items-center gap-(--cue-space-4) border-t border-border bg-surface-1 px-(--cue-pad-row-x) font-mono text-(length:--cue-text-label) text-fg-subtle", className),
19
+ ...elementProps
20
+ });
21
+ });
22
+ /** One reading in the bar: a mode, a count, a connection state. */
23
+ const StatusBarItem = React.forwardRef(function StatusBarItem({ className, tone = "neutral", push = false, icon: Icon, children, ...elementProps }, ref) {
24
+ return /* @__PURE__ */ jsxs("div", {
25
+ ref,
26
+ "data-slot": "status-bar-item",
27
+ className: cn("inline-flex min-w-0 shrink-0 items-center gap-(--cue-space-2) whitespace-nowrap", ITEM_TONES[tone], push ? "ml-auto" : void 0, className),
28
+ ...elementProps,
29
+ children: [Icon === void 0 ? null : /* @__PURE__ */ jsx(Icon, {
30
+ "aria-hidden": "true",
31
+ className: "size-icon-sm shrink-0"
32
+ }), children]
33
+ });
34
+ });
35
+ /**
36
+ * The quiet strip along the bottom of a window.
37
+ *
38
+ * The smallest type in the system in the subtlest ink: a status bar is read
39
+ * when you go looking for it and ignored otherwise, so it must never compete
40
+ * with the work above it. Height comes from `--cue-chrome-statusbar`.
41
+ *
42
+ * Not a live region — a status bar changes constantly (frame counters, DMX
43
+ * output), and announcing every change would make the app unusable with a
44
+ * screen reader. Put anything that genuinely must be announced in a `Toast`.
45
+ *
46
+ * Static markup — no `"use client"`.
47
+ *
48
+ * @example
49
+ * <StatusBar>
50
+ * <StatusBar.Item icon={Plug} tone="ok">Art-Net connected</StatusBar.Item>
51
+ * <StatusBar.Item push>512 channels</StatusBar.Item>
52
+ * </StatusBar>
53
+ */
54
+ const StatusBar = Object.assign(StatusBarRoot, { Item: StatusBarItem });
55
+ //#endregion
56
+ export { StatusBar };
@@ -0,0 +1,80 @@
1
+ import * as React from "react";
2
+ import { Tabs } from "@base-ui/react/tabs";
3
+ //#region src/chrome/tabs.d.ts
4
+ interface TabsRootProps extends Omit<Tabs.Root.Props, "className"> {
5
+ /** Extra classes for the tabs frame. */
6
+ className?: string;
7
+ }
8
+ interface TabsListProps extends Omit<Tabs.List.Props, "className"> {
9
+ /** Extra classes for the strip. */
10
+ className?: string;
11
+ }
12
+ interface TabsTabProps extends Omit<Tabs.Tab.Props, "className"> {
13
+ /** Extra classes for the tab button. */
14
+ className?: string;
15
+ }
16
+ interface TabsPanelProps extends Omit<Tabs.Panel.Props, "className"> {
17
+ /** Extra classes for the panel. */
18
+ className?: string;
19
+ }
20
+ interface ScrollableTabsListProps extends TabsListProps {
21
+ /**
22
+ * Classes for the outer frame (background, rim). It spans the full width even
23
+ * while the strip inside it is scrolled.
24
+ */
25
+ containerClassName?: string;
26
+ /**
27
+ * The active tab's value. When it changes, that tab is scrolled into view — a
28
+ * tab selected in code (a deep link, a keyboard shortcut) can be off-screen.
29
+ */
30
+ activeValue?: Tabs.Tab.Value;
31
+ }
32
+ /**
33
+ * A {@link TabsList} that scrolls when its tabs do not fit, and says so.
34
+ *
35
+ * Use instead of `Tabs.List` wherever the tab count can outgrow the container:
36
+ * a plain flex row silently clips its labels ("SETTINGS" rendering as "INGS"),
37
+ * which reads as a layout bug rather than as "scroll me".
38
+ *
39
+ * The affordance is two things, and it needs both. The mask fades the content
40
+ * at whichever edge still hides tabs; the chevron buttons are the visible half,
41
+ * because what sits at an overflowing edge is usually the gap *between* two
42
+ * tabs and fading empty space produces nothing anyone can see. The chevrons
43
+ * double as the control for anyone without a horizontal-scroll device.
44
+ *
45
+ * @example
46
+ * <Tabs.Root defaultValue={view}>
47
+ * <ScrollableTabsList activeValue={view}>
48
+ * {views.map((v) => <Tabs.Tab key={v} value={v}>{v}</Tabs.Tab>)}
49
+ * </ScrollableTabsList>
50
+ * </Tabs.Root>
51
+ */
52
+ declare const ScrollableTabsList: React.ForwardRefExoticComponent<Omit<ScrollableTabsListProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
53
+ /**
54
+ * One surface, several views.
55
+ *
56
+ * Wraps Base UI's `Tabs`, so roving focus, `aria-controls` wiring and
57
+ * activation semantics are the primitive's. This layer adds the console skin:
58
+ * a hairline strip, mono labels and an accent underline for the active tab.
59
+ *
60
+ * Reach for {@link ScrollableTabsList} instead of `Tabs.List` when the number of
61
+ * tabs is data-driven and can outgrow its container.
62
+ *
63
+ * @example
64
+ * <Tabs.Root defaultValue="patch">
65
+ * <Tabs.List>
66
+ * <Tabs.Tab value="patch">Patch</Tabs.Tab>
67
+ * <Tabs.Tab value="cues">Cues</Tabs.Tab>
68
+ * </Tabs.List>
69
+ * <Tabs.Panel value="patch">…</Tabs.Panel>
70
+ * <Tabs.Panel value="cues">…</Tabs.Panel>
71
+ * </Tabs.Root>
72
+ */
73
+ declare const Tabs$1: {
74
+ Root: React.ForwardRefExoticComponent<Omit<TabsRootProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
75
+ List: React.ForwardRefExoticComponent<Omit<TabsListProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
76
+ Tab: React.ForwardRefExoticComponent<Omit<TabsTabProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
77
+ Panel: React.ForwardRefExoticComponent<Omit<TabsPanelProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
78
+ };
79
+ //#endregion
80
+ export { ScrollableTabsList, ScrollableTabsListProps, Tabs$1 as Tabs, TabsListProps, TabsPanelProps, TabsRootProps, TabsTabProps };
@@ -0,0 +1,176 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { computeScrollEdges, edgeFadeMask } from "./_tabs-scroll.js";
4
+ import { ChevronLeftGlyph, ChevronRightGlyph } from "./_glyphs.js";
5
+ import * as React from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { Tabs } from "@base-ui/react/tabs";
8
+ //#region src/chrome/tabs.tsx
9
+ /** Groups a tab list with its panels and owns the selected value. */
10
+ const TabsRoot = React.forwardRef(function TabsRoot({ className, ...elementProps }, ref) {
11
+ return /* @__PURE__ */ jsx(Tabs.Root, {
12
+ ref,
13
+ "data-slot": "tabs",
14
+ className: cn("flex min-w-0 flex-col gap-(--cue-space-4) data-[orientation=vertical]:flex-row", className),
15
+ ...elementProps
16
+ });
17
+ });
18
+ /**
19
+ * The strip of tabs, hung off a hairline.
20
+ *
21
+ * The rule belongs to the list rather than to the active tab so it spans the
22
+ * full width even when the tabs do not — which is what makes the selected tab's
23
+ * accent underline read as a mark *on* a rule rather than as a floating dash.
24
+ */
25
+ const TabsList = React.forwardRef(function TabsList({ className, ...elementProps }, ref) {
26
+ return /* @__PURE__ */ jsx(Tabs.List, {
27
+ ref,
28
+ "data-slot": "tabs-list",
29
+ className: cn("relative flex items-center gap-(--cue-space-1) border-b border-border data-[orientation=vertical]:flex-col data-[orientation=vertical]:items-stretch data-[orientation=vertical]:border-b-0 data-[orientation=vertical]:border-r", className),
30
+ ...elementProps
31
+ });
32
+ });
33
+ /**
34
+ * One tab. Selected state is an accent underline sitting on the list's rule —
35
+ * never a filled pill, which at console density turns a row of four tabs into a
36
+ * row of four buttons and loses the "one surface, several views" reading.
37
+ */
38
+ const TabsTab = React.forwardRef(function TabsTab({ className, ...elementProps }, ref) {
39
+ return /* @__PURE__ */ jsx(Tabs.Tab, {
40
+ ref,
41
+ "data-slot": "tabs-tab",
42
+ className: cn("relative inline-flex h-control-md shrink-0 cursor-pointer items-center justify-center gap-(--cue-space-2) rounded-t-(--radius-control) px-(--cue-space-4) font-mono text-(length:--cue-text-ui) whitespace-nowrap text-fg-muted transition-colors duration-150 outline-none select-none", "hover:text-fg focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-2 focus-visible:outline-accent", "data-[disabled]:pointer-events-none data-[disabled]:opacity-40", "after:absolute after:inset-x-0 after:-bottom-px after:h-px after:bg-transparent after:content-['']", "data-[active]:text-accent data-[active]:after:bg-accent", className),
43
+ ...elementProps
44
+ });
45
+ });
46
+ /** The body shown for the matching tab. Focusable, so keyboard users land in it. */
47
+ const TabsPanel = React.forwardRef(function TabsPanel({ className, ...elementProps }, ref) {
48
+ return /* @__PURE__ */ jsx(Tabs.Panel, {
49
+ ref,
50
+ "data-slot": "tabs-panel",
51
+ className: cn("min-w-0 outline-none focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-accent", className),
52
+ ...elementProps
53
+ });
54
+ });
55
+ /** Page the strip by most of a screenful, keeping a sliver of context. */
56
+ const NUDGE_FRACTION = .7;
57
+ /**
58
+ * A {@link TabsList} that scrolls when its tabs do not fit, and says so.
59
+ *
60
+ * Use instead of `Tabs.List` wherever the tab count can outgrow the container:
61
+ * a plain flex row silently clips its labels ("SETTINGS" rendering as "INGS"),
62
+ * which reads as a layout bug rather than as "scroll me".
63
+ *
64
+ * The affordance is two things, and it needs both. The mask fades the content
65
+ * at whichever edge still hides tabs; the chevron buttons are the visible half,
66
+ * because what sits at an overflowing edge is usually the gap *between* two
67
+ * tabs and fading empty space produces nothing anyone can see. The chevrons
68
+ * double as the control for anyone without a horizontal-scroll device.
69
+ *
70
+ * @example
71
+ * <Tabs.Root defaultValue={view}>
72
+ * <ScrollableTabsList activeValue={view}>
73
+ * {views.map((v) => <Tabs.Tab key={v} value={v}>{v}</Tabs.Tab>)}
74
+ * </ScrollableTabsList>
75
+ * </Tabs.Root>
76
+ */
77
+ const ScrollableTabsList = React.forwardRef(function ScrollableTabsList({ className, containerClassName, activeValue, children, ...listProps }, ref) {
78
+ const scrollerRef = React.useRef(null);
79
+ const [edges, setEdges] = React.useState({
80
+ start: false,
81
+ end: false
82
+ });
83
+ const sync = React.useCallback(() => {
84
+ const el = scrollerRef.current;
85
+ if (el === null) return;
86
+ setEdges(computeScrollEdges(el.scrollLeft, el.scrollWidth, el.clientWidth));
87
+ }, []);
88
+ React.useEffect(() => {
89
+ const el = scrollerRef.current;
90
+ if (el === null) return;
91
+ sync();
92
+ el.addEventListener("scroll", sync, { passive: true });
93
+ const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(() => sync());
94
+ observer?.observe(el);
95
+ if (el.firstElementChild !== null) observer?.observe(el.firstElementChild);
96
+ return () => {
97
+ el.removeEventListener("scroll", sync);
98
+ observer?.disconnect();
99
+ };
100
+ }, [sync]);
101
+ React.useEffect(() => {
102
+ scrollerRef.current?.querySelector("[data-slot='tabs-tab'][data-active]")?.scrollIntoView?.({
103
+ block: "nearest",
104
+ inline: "nearest"
105
+ });
106
+ }, [activeValue]);
107
+ const nudge = (direction) => {
108
+ const el = scrollerRef.current;
109
+ el?.scrollBy?.({
110
+ left: direction * el.clientWidth * NUDGE_FRACTION,
111
+ behavior: "smooth"
112
+ });
113
+ };
114
+ const mask = edgeFadeMask(edges);
115
+ const chevronClasses = "absolute inset-y-0 z-10 flex w-(--cue-space-5) cursor-pointer items-center justify-center bg-surface-2 text-fg-muted outline-none hover:text-fg focus-visible:outline-2 focus-visible:outline-solid focus-visible:-outline-offset-2 focus-visible:outline-accent";
116
+ return /* @__PURE__ */ jsxs("div", {
117
+ "data-slot": "tabs-scroll-frame",
118
+ className: cn("relative min-w-0", containerClassName),
119
+ children: [
120
+ /* @__PURE__ */ jsx("div", {
121
+ ref: scrollerRef,
122
+ "data-slot": "tabs-scroller",
123
+ className: "overflow-x-auto [mask-image:var(--cue-tabs-fade)] [-webkit-mask-image:var(--cue-tabs-fade)] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
124
+ style: mask === void 0 ? void 0 : { "--cue-tabs-fade": mask },
125
+ children: /* @__PURE__ */ jsx(TabsList, {
126
+ ref,
127
+ className: cn("w-max", className),
128
+ ...listProps,
129
+ children
130
+ })
131
+ }),
132
+ edges.start ? /* @__PURE__ */ jsx("button", {
133
+ type: "button",
134
+ "aria-label": "Show earlier tabs",
135
+ onClick: () => nudge(-1),
136
+ className: cn(chevronClasses, "left-0"),
137
+ children: /* @__PURE__ */ jsx(ChevronLeftGlyph, { className: "size-icon-sm" })
138
+ }) : null,
139
+ edges.end ? /* @__PURE__ */ jsx("button", {
140
+ type: "button",
141
+ "aria-label": "Show later tabs",
142
+ onClick: () => nudge(1),
143
+ className: cn(chevronClasses, "right-0"),
144
+ children: /* @__PURE__ */ jsx(ChevronRightGlyph, { className: "size-icon-sm" })
145
+ }) : null
146
+ ]
147
+ });
148
+ });
149
+ /**
150
+ * One surface, several views.
151
+ *
152
+ * Wraps Base UI's `Tabs`, so roving focus, `aria-controls` wiring and
153
+ * activation semantics are the primitive's. This layer adds the console skin:
154
+ * a hairline strip, mono labels and an accent underline for the active tab.
155
+ *
156
+ * Reach for {@link ScrollableTabsList} instead of `Tabs.List` when the number of
157
+ * tabs is data-driven and can outgrow its container.
158
+ *
159
+ * @example
160
+ * <Tabs.Root defaultValue="patch">
161
+ * <Tabs.List>
162
+ * <Tabs.Tab value="patch">Patch</Tabs.Tab>
163
+ * <Tabs.Tab value="cues">Cues</Tabs.Tab>
164
+ * </Tabs.List>
165
+ * <Tabs.Panel value="patch">…</Tabs.Panel>
166
+ * <Tabs.Panel value="cues">…</Tabs.Panel>
167
+ * </Tabs.Root>
168
+ */
169
+ const Tabs$1 = {
170
+ Root: TabsRoot,
171
+ List: TabsList,
172
+ Tab: TabsTab,
173
+ Panel: TabsPanel
174
+ };
175
+ //#endregion
176
+ export { ScrollableTabsList, Tabs$1 as Tabs };
@@ -0,0 +1,37 @@
1
+ import * as React from "react";
2
+ //#region src/chrome/title-bar.d.ts
3
+ interface TitleBarProps extends React.ComponentPropsWithoutRef<"div"> {
4
+ /**
5
+ * Make the bar a window drag handle.
6
+ *
7
+ * Emits `data-tauri-drag-region` (Tauri reads the attribute) *and* the
8
+ * `app-region: drag` CSS property (Electron and Chromium read that), because
9
+ * the same component ships into both shells and neither one recognises the
10
+ * other's contract. The interactive clusters are carved back out with
11
+ * `app-region: no-drag`, or the buttons in the bar would only ever move the
12
+ * window instead of firing.
13
+ */
14
+ platformDrag?: boolean;
15
+ /**
16
+ * Centre slot: the document name. Absolutely centred on the *bar*, not
17
+ * between the two clusters, so it does not shift sideways when a button
18
+ * appears on one side. `pointer-events-none`, so the dead space around a
19
+ * short title stays draggable.
20
+ */
21
+ center?: React.ReactNode;
22
+ /** Trailing slot: window controls, connection state, an overflow menu. */
23
+ actions?: React.ReactNode;
24
+ /** Leading slot: the app mark, a back button, the file menu. */
25
+ children?: React.ReactNode;
26
+ }
27
+ /**
28
+ * The window's own bar: app mark left, document name centred, controls right.
29
+ *
30
+ * @example
31
+ * <TitleBar platformDrag center="untitled.cue" actions={<WindowControls />}>
32
+ * <Eyebrow>CUE++</Eyebrow>
33
+ * </TitleBar>
34
+ */
35
+ declare const TitleBar: React.ForwardRefExoticComponent<TitleBarProps & React.RefAttributes<HTMLDivElement>>;
36
+ //#endregion
37
+ export { TitleBar, TitleBarProps };