@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,102 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import * as React from "react";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { Field } from "@base-ui/react/field";
6
+ //#region src/forms/field.tsx
7
+ /**
8
+ * The labelling and validation wrapper every form control belongs in.
9
+ *
10
+ * Wraps Base UI's `Field.Root`, which generates the ids that tie
11
+ * {@link FieldLabel}, {@link FieldDescription} and {@link FieldError} to the
12
+ * control inside it — so `<FieldLabel>Cue name</FieldLabel>` names an
13
+ * {@link Input} with no `htmlFor`/`id` bookkeeping from the caller. Base UI also
14
+ * stamps `data-invalid` / `data-disabled` down the subtree, which is what the
15
+ * chassis' danger rim keys off.
16
+ *
17
+ * @example
18
+ * <Field name="cue">
19
+ * <FieldLabel>Cue name</FieldLabel>
20
+ * <Input placeholder="e.g. Blackout" />
21
+ * <FieldDescription>Shown in the cue list.</FieldDescription>
22
+ * <FieldError issues={result.issues} />
23
+ * </Field>
24
+ */
25
+ const Field$1 = React.forwardRef(function Field$2({ className, ...elementProps }, ref) {
26
+ return /* @__PURE__ */ jsx(Field.Root, {
27
+ ref,
28
+ "data-slot": "field",
29
+ className: cn("flex w-full flex-col gap-(--cue-space-2)", className),
30
+ ...elementProps
31
+ });
32
+ });
33
+ /**
34
+ * The name of a field: mono, uppercase, tracked out, one rung below body text.
35
+ *
36
+ * Renders a real `<label>` wired to the field's control, so clicking it focuses
37
+ * (or toggles) that control.
38
+ *
39
+ * @example
40
+ * <FieldLabel>Universe</FieldLabel>
41
+ */
42
+ const FieldLabel = React.forwardRef(function FieldLabel({ className, ...elementProps }, ref) {
43
+ return /* @__PURE__ */ jsx(Field.Label, {
44
+ ref,
45
+ "data-slot": "field-label",
46
+ className: cn("font-mono text-(length:--cue-text-label) leading-none tracking-[0.1em] text-fg-muted uppercase select-none data-[disabled]:opacity-40", className),
47
+ ...elementProps
48
+ });
49
+ });
50
+ /**
51
+ * Quiet helper text under a control, published to assistive tech as the
52
+ * control's `aria-describedby` target.
53
+ *
54
+ * @example
55
+ * <FieldDescription>1–512</FieldDescription>
56
+ */
57
+ const FieldDescription = React.forwardRef(function FieldDescription({ className, ...elementProps }, ref) {
58
+ return /* @__PURE__ */ jsx(Field.Description, {
59
+ ref,
60
+ "data-slot": "field-description",
61
+ className: cn("font-mono text-(length:--cue-text-micro) text-fg-subtle", className),
62
+ ...elementProps
63
+ });
64
+ });
65
+ /**
66
+ * The error line under a control.
67
+ *
68
+ * Two ways to drive it, and they are mutually exclusive by design:
69
+ * pass `issues` from a Standard Schema parse (`schema.safeParse(x).issues`) and
70
+ * the component owns visibility, or pass `match` + `children` and let Base UI
71
+ * key off the native `ValidityState`.
72
+ *
73
+ * @example
74
+ * <FieldError issues={result.issues} />
75
+ * @example
76
+ * <FieldError match="valueMissing">Please name the cue</FieldError>
77
+ */
78
+ const FieldError = React.forwardRef(function FieldError({ className, issues, match, children, ...elementProps }, ref) {
79
+ if (issues !== void 0 && issues.length === 0) return null;
80
+ const classes = cn("font-mono text-(length:--cue-text-micro) text-danger", className);
81
+ if (issues === void 0) return /* @__PURE__ */ jsx(Field.Error, {
82
+ ref,
83
+ "data-slot": "field-error",
84
+ match,
85
+ className: classes,
86
+ ...elementProps,
87
+ children
88
+ });
89
+ return /* @__PURE__ */ jsx(Field.Error, {
90
+ ref,
91
+ "data-slot": "field-error",
92
+ match: true,
93
+ className: classes,
94
+ ...elementProps,
95
+ children: issues.length === 1 ? issues[0]?.message : /* @__PURE__ */ jsx("ul", {
96
+ className: "flex flex-col gap-(--cue-space-1)",
97
+ children: issues.map((issue, index) => /* @__PURE__ */ jsx("li", { children: issue.message }, `${index}:${issue.message}`))
98
+ })
99
+ });
100
+ });
101
+ //#endregion
102
+ export { Field$1 as Field, FieldDescription, FieldError, FieldLabel };
@@ -0,0 +1,113 @@
1
+ import * as React from "react";
2
+ //#region src/forms/file-upload.d.ts
3
+ /** Why a dropped file did not make it into the list. */
4
+ type FileRejectReason = "type" | "size" | "count";
5
+ interface FileRejection {
6
+ /** The file that was turned away. */
7
+ file: File;
8
+ /** Which rule turned it away. */
9
+ reason: FileRejectReason;
10
+ }
11
+ interface FilePartitionOptions {
12
+ /** An `accept` string: extensions, exact mime types, `image/*` wildcards. */
13
+ accept?: string;
14
+ /** Largest accepted file, in bytes. */
15
+ maxSize?: number;
16
+ /** How many files may be accepted in total. */
17
+ maxFiles?: number;
18
+ }
19
+ interface FilePartition {
20
+ /** Files that passed every rule, in the order they arrived. */
21
+ accepted: File[];
22
+ /** Files that failed one, each with the reason. */
23
+ rejected: FileRejection[];
24
+ }
25
+ /** Where a file is in its journey. Drives the row's readout. */
26
+ type UploadStatus = "pending" | "uploading" | "done" | "error";
27
+ interface UploadFile {
28
+ /** Stable identity — what `onRemove` reports. */
29
+ id: string;
30
+ /** File name, shown verbatim. */
31
+ name: string;
32
+ /** Size in bytes; rendered in SI units. */
33
+ size?: number;
34
+ /** Completion 0–100. Drawn as a bar while `status` is `"uploading"`. */
35
+ progress?: number;
36
+ /** Defaults to `"pending"`. */
37
+ status?: UploadStatus;
38
+ /** Why it failed. Shown in the danger tone under the name. */
39
+ error?: string;
40
+ }
41
+ /**
42
+ * Split a drop into the files that pass the rules and the ones that do not,
43
+ * each with the reason it was turned away.
44
+ *
45
+ * Exported and pure because "why was my file rejected?" is the question a drop
46
+ * zone most often has to answer, and a caller filtering by hand would answer it
47
+ * differently from the component. Order is preserved, and the count ceiling
48
+ * keeps the *first* files rather than an arbitrary subset.
49
+ *
50
+ * @param files - Everything the drop or the file dialog produced.
51
+ * @param options - The rules to apply.
52
+ * @returns The accepted files and the reasoned rejections.
53
+ * @example
54
+ * partitionFiles(files, { accept: "image/*", maxSize: 2_000_000 })
55
+ */
56
+ declare function partitionFiles(files: readonly File[], { accept, maxSize, maxFiles }: FilePartitionOptions): FilePartition;
57
+ interface FileUploadProps extends Omit<React.ComponentPropsWithoutRef<"div">, "onDrop" | "children"> {
58
+ /** The zone's own copy, and its accessible name. Defaults to `"Drop files"`. */
59
+ label?: React.ReactNode;
60
+ /** A second line under the label — the rules, in plain words. */
61
+ hint?: React.ReactNode;
62
+ /** `accept` string forwarded to the input and used for rejection. */
63
+ accept?: string;
64
+ /** Allow more than one file per drop. */
65
+ multiple?: boolean;
66
+ /** Largest accepted file, in bytes. */
67
+ maxSize?: number;
68
+ /** How many files may be accepted per drop. */
69
+ maxFiles?: number;
70
+ /** Refuse drops and grey the zone out. */
71
+ disabled?: boolean;
72
+ /** Rows to render under the zone. The caller owns upload state. */
73
+ files?: readonly UploadFile[];
74
+ /** Called with the files that passed the rules. */
75
+ onFilesAccepted?: (files: File[]) => void;
76
+ /** Called with the files that did not, each with its reason. */
77
+ onFilesRejected?: (rejections: FileRejection[]) => void;
78
+ /** Called with a row's `id` when its remove control is pressed. */
79
+ onRemove?: (id: string) => void;
80
+ /** Spoken name of a row's remove control. Defaults to `Remove <name>`. */
81
+ removeLabel?: (file: UploadFile) => string;
82
+ /** Extra classes for the drop zone. */
83
+ zoneClassName?: string;
84
+ }
85
+ /**
86
+ * A drop zone with a file list under it.
87
+ *
88
+ * The zone is a real `<button>`, not a div with a drop handler: dropping is the
89
+ * mouse affordance, and pressing Enter on a focused button to open the file
90
+ * dialog is the keyboard one. A zone that only accepts drops is unusable
91
+ * without a pointer (WCAG 2.1.1), and it is the single most common defect in
92
+ * hand-rolled uploaders.
93
+ *
94
+ * State is the caller's. This component turns drops into `File[]` (plus
95
+ * reasoned rejections, via {@link partitionFiles}) and renders whatever rows it
96
+ * is handed — it never holds an upload queue, because the transport, the
97
+ * retries and the progress belong to the app.
98
+ *
99
+ * @example
100
+ * <FileUpload
101
+ * label="Drop show files"
102
+ * hint="CSV or QLab bundle, up to 20 MB"
103
+ * accept=".csv,.qlab"
104
+ * maxSize={20_000_000}
105
+ * files={rows}
106
+ * onFilesAccepted={enqueue}
107
+ * onFilesRejected={explain}
108
+ * onRemove={cancel}
109
+ * />
110
+ */
111
+ declare const FileUpload: React.ForwardRefExoticComponent<FileUploadProps & React.RefAttributes<HTMLDivElement>>;
112
+ //#endregion
113
+ export { FilePartition, FilePartitionOptions, FileRejectReason, FileRejection, FileUpload, FileUploadProps, UploadFile, UploadStatus, partitionFiles };
@@ -0,0 +1,232 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { CrossGlyph } from "./_glyphs.js";
4
+ import * as React from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/forms/file-upload.tsx
7
+ /** Does `file` satisfy one clause of an `accept` string? */
8
+ function matchesAcceptClause(file, clause) {
9
+ const rule = clause.trim().toLowerCase();
10
+ if (rule === "") return true;
11
+ if (rule.startsWith(".")) return file.name.toLowerCase().endsWith(rule);
12
+ if (rule.endsWith("/*")) return file.type.toLowerCase().startsWith(rule.slice(0, -1));
13
+ return file.type.toLowerCase() === rule;
14
+ }
15
+ /**
16
+ * Split a drop into the files that pass the rules and the ones that do not,
17
+ * each with the reason it was turned away.
18
+ *
19
+ * Exported and pure because "why was my file rejected?" is the question a drop
20
+ * zone most often has to answer, and a caller filtering by hand would answer it
21
+ * differently from the component. Order is preserved, and the count ceiling
22
+ * keeps the *first* files rather than an arbitrary subset.
23
+ *
24
+ * @param files - Everything the drop or the file dialog produced.
25
+ * @param options - The rules to apply.
26
+ * @returns The accepted files and the reasoned rejections.
27
+ * @example
28
+ * partitionFiles(files, { accept: "image/*", maxSize: 2_000_000 })
29
+ */
30
+ function partitionFiles(files, { accept, maxSize, maxFiles }) {
31
+ const clauses = accept === void 0 ? [] : accept.split(",").filter((part) => part.trim() !== "");
32
+ const accepted = [];
33
+ const rejected = [];
34
+ for (const file of files) if (clauses.length > 0 && !clauses.some((clause) => matchesAcceptClause(file, clause))) rejected.push({
35
+ file,
36
+ reason: "type"
37
+ });
38
+ else if (maxSize !== void 0 && file.size > maxSize) rejected.push({
39
+ file,
40
+ reason: "size"
41
+ });
42
+ else if (maxFiles !== void 0 && accepted.length >= maxFiles) rejected.push({
43
+ file,
44
+ reason: "count"
45
+ });
46
+ else accepted.push(file);
47
+ return {
48
+ accepted,
49
+ rejected
50
+ };
51
+ }
52
+ /** SI units, one decimal — `1536` reads as `1.5 kB`, not `1.5 KiB`. */
53
+ function formatBytes(bytes) {
54
+ if (bytes < 1e3) return `${bytes} B`;
55
+ const units = [
56
+ "kB",
57
+ "MB",
58
+ "GB",
59
+ "TB"
60
+ ];
61
+ let value = bytes / 1e3;
62
+ let unit = 0;
63
+ while (value >= 1e3 && unit < units.length - 1) {
64
+ value /= 1e3;
65
+ unit += 1;
66
+ }
67
+ return `${value.toFixed(1)} ${units[unit]}`;
68
+ }
69
+ /**
70
+ * A drop zone with a file list under it.
71
+ *
72
+ * The zone is a real `<button>`, not a div with a drop handler: dropping is the
73
+ * mouse affordance, and pressing Enter on a focused button to open the file
74
+ * dialog is the keyboard one. A zone that only accepts drops is unusable
75
+ * without a pointer (WCAG 2.1.1), and it is the single most common defect in
76
+ * hand-rolled uploaders.
77
+ *
78
+ * State is the caller's. This component turns drops into `File[]` (plus
79
+ * reasoned rejections, via {@link partitionFiles}) and renders whatever rows it
80
+ * is handed — it never holds an upload queue, because the transport, the
81
+ * retries and the progress belong to the app.
82
+ *
83
+ * @example
84
+ * <FileUpload
85
+ * label="Drop show files"
86
+ * hint="CSV or QLab bundle, up to 20 MB"
87
+ * accept=".csv,.qlab"
88
+ * maxSize={20_000_000}
89
+ * files={rows}
90
+ * onFilesAccepted={enqueue}
91
+ * onFilesRejected={explain}
92
+ * onRemove={cancel}
93
+ * />
94
+ */
95
+ const FileUpload = React.forwardRef(function FileUpload({ className, zoneClassName, label = "Drop files", hint, accept, multiple = false, maxSize, maxFiles, disabled = false, files, onFilesAccepted, onFilesRejected, onRemove, removeLabel = (file) => `Remove ${file.name}`, ...elementProps }, ref) {
96
+ const inputRef = React.useRef(null);
97
+ const [dragging, setDragging] = React.useState(false);
98
+ const depth = React.useRef(0);
99
+ const intake = (incoming) => {
100
+ if (disabled || incoming === null || incoming.length === 0) return;
101
+ const { accepted, rejected } = partitionFiles(Array.from(incoming), {
102
+ accept,
103
+ maxSize,
104
+ maxFiles: maxFiles ?? (multiple ? void 0 : 1)
105
+ });
106
+ if (accepted.length > 0) onFilesAccepted?.(accepted);
107
+ if (rejected.length > 0) onFilesRejected?.(rejected);
108
+ };
109
+ return /* @__PURE__ */ jsxs("div", {
110
+ ref,
111
+ "data-slot": "file-upload",
112
+ className: cn("flex w-full flex-col gap-(--cue-space-2)", className),
113
+ ...elementProps,
114
+ children: [
115
+ /* @__PURE__ */ jsxs("button", {
116
+ type: "button",
117
+ "data-slot": "file-upload-zone",
118
+ "data-dragging": dragging ? "true" : void 0,
119
+ disabled,
120
+ onClick: () => inputRef.current?.click(),
121
+ onDragEnter: (event) => {
122
+ if (disabled) return;
123
+ event.preventDefault();
124
+ depth.current += 1;
125
+ setDragging(true);
126
+ },
127
+ onDragOver: (event) => {
128
+ if (disabled) return;
129
+ event.preventDefault();
130
+ },
131
+ onDragLeave: (event) => {
132
+ if (disabled) return;
133
+ event.preventDefault();
134
+ depth.current -= 1;
135
+ if (depth.current <= 0) {
136
+ depth.current = 0;
137
+ setDragging(false);
138
+ }
139
+ },
140
+ onDrop: (event) => {
141
+ event.preventDefault();
142
+ depth.current = 0;
143
+ setDragging(false);
144
+ intake(event.dataTransfer?.files ?? null);
145
+ },
146
+ className: cn("flex w-full cursor-pointer flex-col items-center justify-center gap-(--cue-space-1) rounded-(--radius-control) border border-dashed border-border bg-sunken px-(--cue-space-4) py-(--cue-space-5) font-mono text-(length:--cue-text-ui) text-fg-muted outline-none transition-colors duration-150 hover:border-border-strong hover:text-fg 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-[dragging=true]:border-accent data-[dragging=true]:bg-accent-soft data-[dragging=true]:text-fg motion-reduce:transition-none", zoneClassName),
147
+ children: [/* @__PURE__ */ jsx("span", { children: label }), hint === void 0 ? null : /* @__PURE__ */ jsx("span", {
148
+ className: "text-(length:--cue-text-label) text-fg-subtle",
149
+ children: hint
150
+ })]
151
+ }),
152
+ /* @__PURE__ */ jsx("input", {
153
+ ref: inputRef,
154
+ type: "file",
155
+ hidden: true,
156
+ tabIndex: -1,
157
+ accept,
158
+ multiple,
159
+ disabled,
160
+ "data-slot": "file-upload-input",
161
+ onChange: (event) => {
162
+ intake(event.target.files);
163
+ event.target.value = "";
164
+ }
165
+ }),
166
+ files === void 0 || files.length === 0 ? null : /* @__PURE__ */ jsx("ul", {
167
+ "data-slot": "file-upload-list",
168
+ className: "flex flex-col gap-px",
169
+ children: files.map((file) => /* @__PURE__ */ jsx(FileUploadRow, {
170
+ file,
171
+ onRemove,
172
+ removeLabel
173
+ }, file.id))
174
+ })
175
+ ]
176
+ });
177
+ });
178
+ /** One file: name, size, progress or reason, and a way out. */
179
+ function FileUploadRow({ file, onRemove, removeLabel }) {
180
+ const status = file.status ?? "pending";
181
+ const showProgress = status === "uploading" && file.progress !== void 0;
182
+ return /* @__PURE__ */ jsxs("li", {
183
+ "data-slot": "file-upload-row",
184
+ "data-status": status,
185
+ className: "flex min-h-control-sm items-center gap-(--cue-space-3) bg-surface-2 px-(--cue-space-3) py-(--cue-space-1) font-mono text-(length:--cue-text-label)",
186
+ children: [
187
+ /* @__PURE__ */ jsxs("div", {
188
+ className: "flex min-w-0 flex-1 flex-col gap-px",
189
+ children: [/* @__PURE__ */ jsx("span", {
190
+ className: "truncate text-fg",
191
+ children: file.name
192
+ }), file.error === void 0 ? null : /* @__PURE__ */ jsx("span", {
193
+ "data-slot": "file-upload-error",
194
+ className: "truncate text-danger",
195
+ children: file.error
196
+ })]
197
+ }),
198
+ file.size === void 0 ? null : /* @__PURE__ */ jsx("span", {
199
+ className: "shrink-0 tabular-nums text-fg-subtle",
200
+ children: formatBytes(file.size)
201
+ }),
202
+ showProgress ? /* @__PURE__ */ jsx("div", {
203
+ role: "progressbar",
204
+ "aria-label": `Uploading ${file.name}`,
205
+ "aria-valuenow": file.progress,
206
+ "aria-valuemin": 0,
207
+ "aria-valuemax": 100,
208
+ "data-slot": "file-upload-progress",
209
+ className: "h-px w-[4rem] shrink-0 overflow-hidden bg-surface-3",
210
+ children: /* @__PURE__ */ jsx("div", {
211
+ className: "h-full bg-accent transition-[width] duration-[120ms] ease-linear motion-reduce:transition-none",
212
+ style: { width: `${file.progress}%` }
213
+ })
214
+ }) : null,
215
+ status === "done" ? /* @__PURE__ */ jsx("span", {
216
+ className: "shrink-0 text-ok",
217
+ "aria-hidden": "true",
218
+ children: "✓"
219
+ }) : null,
220
+ onRemove === void 0 ? null : /* @__PURE__ */ jsx("button", {
221
+ type: "button",
222
+ "aria-label": removeLabel(file),
223
+ "data-slot": "file-upload-remove",
224
+ onClick: () => onRemove(file.id),
225
+ className: "flex size-icon-sm shrink-0 cursor-pointer items-center justify-center rounded-(--radius-control) border-0 bg-transparent p-0 text-fg-subtle outline-none transition-colors hover:text-fg focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-1 focus-visible:outline-accent motion-reduce:transition-none",
226
+ children: /* @__PURE__ */ jsx(CrossGlyph, { className: "size-full" })
227
+ })
228
+ ]
229
+ });
230
+ }
231
+ //#endregion
232
+ export { FileUpload, partitionFiles };
@@ -0,0 +1,26 @@
1
+ import { ControlVariantProps, FormControlSize, bareControlClasses, controlClasses, controlGroupFocusClasses, controlSurface, controlVariants } from "./_chassis.js";
2
+ import { Autocomplete, AutocompleteProps } from "./autocomplete.js";
3
+ import { ButtonGroup, ButtonGroupOrientation, ButtonGroupProps } from "./button-group.js";
4
+ import { Checkbox, CheckboxGroup, CheckboxGroupProps, CheckboxProps } from "./checkbox.js";
5
+ import { Combobox, ComboboxOption, ComboboxProps } from "./combobox.js";
6
+ import { EnvVarInput, EnvVarInputProps, envReference, parseEnvReference } from "./env-var-input.js";
7
+ import { Field, FieldDescription, FieldDescriptionProps, FieldError, FieldErrorProps, FieldIssue, FieldLabel, FieldLabelProps, FieldProps } from "./field.js";
8
+ import { FilePartition, FilePartitionOptions, FileRejectReason, FileRejection, FileUpload, FileUploadProps, UploadFile, UploadStatus, partitionFiles } from "./file-upload.js";
9
+ import { Input, InputProps } from "./input.js";
10
+ import { InputGroup, InputGroupProps } from "./input-group.js";
11
+ import { MultiSelect, MultiSelectProps } from "./multi-select.js";
12
+ import { NumberField, NumberFieldProps } from "./number-field.js";
13
+ import { OTPField, OTPFieldProps } from "./otp-field.js";
14
+ import { PasswordInput, PasswordInputProps } from "./password-input.js";
15
+ import { Radio, RadioGroup, RadioGroupProps, RadioProps } from "./radio-group.js";
16
+ import { Rating, RatingProps, RatingSize } from "./rating.js";
17
+ import { ScrubInput, ScrubInputProps } from "./scrub-input.js";
18
+ import { SearchInput, SearchInputProps } from "./search-input.js";
19
+ import { Select, SelectOption, SelectProps } from "./select.js";
20
+ import { Slider, SliderProps } from "./slider.js";
21
+ import { Switch, SwitchProps } from "./switch.js";
22
+ import { TagsInput, TagsInputProps } from "./tags-input.js";
23
+ import { Textarea, TextareaProps } from "./textarea.js";
24
+ import { Toggle, ToggleProps } from "./toggle.js";
25
+ import { ToggleGroup, ToggleGroupProps } from "./toggle-group.js";
26
+ export { Autocomplete, type AutocompleteProps, ButtonGroup, type ButtonGroupOrientation, type ButtonGroupProps, Checkbox, CheckboxGroup, type CheckboxGroupProps, type CheckboxProps, Combobox, type ComboboxOption, type ComboboxProps, type ControlVariantProps, EnvVarInput, type EnvVarInputProps, Field, FieldDescription, type FieldDescriptionProps, FieldError, type FieldErrorProps, type FieldIssue, FieldLabel, type FieldLabelProps, type FieldProps, type FilePartition, type FilePartitionOptions, type FileRejectReason, type FileRejection, FileUpload, type FileUploadProps, type FormControlSize, Input, InputGroup, type InputGroupProps, type InputProps, MultiSelect, type MultiSelectProps, NumberField, type NumberFieldProps, OTPField, type OTPFieldProps, PasswordInput, type PasswordInputProps, Radio, RadioGroup, type RadioGroupProps, type RadioProps, Rating, type RatingProps, type RatingSize, ScrubInput, type ScrubInputProps, SearchInput, type SearchInputProps, Select, type SelectOption, type SelectProps, Slider, type SliderProps, Switch, type SwitchProps, TagsInput, type TagsInputProps, Textarea, type TextareaProps, Toggle, ToggleGroup, type ToggleGroupProps, type ToggleProps, type UploadFile, type UploadStatus, bareControlClasses, controlClasses, controlGroupFocusClasses, controlSurface, controlVariants, envReference, parseEnvReference, partitionFiles };
@@ -0,0 +1,26 @@
1
+ import { Checkbox, CheckboxGroup } from "./checkbox.js";
2
+ import { bareControlClasses, controlClasses, controlGroupFocusClasses, controlSurface, controlVariants } from "./_chassis.js";
3
+ import { InputGroup } from "./input-group.js";
4
+ import { Input } from "./input.js";
5
+ import { NumberField } from "./number-field.js";
6
+ import { Radio, RadioGroup } from "./radio-group.js";
7
+ import { Autocomplete } from "./autocomplete.js";
8
+ import { ButtonGroup } from "./button-group.js";
9
+ import { Combobox } from "./combobox.js";
10
+ import { PasswordInput } from "./password-input.js";
11
+ import { EnvVarInput, envReference, parseEnvReference } from "./env-var-input.js";
12
+ import { Field, FieldDescription, FieldError, FieldLabel } from "./field.js";
13
+ import { FileUpload, partitionFiles } from "./file-upload.js";
14
+ import { MultiSelect } from "./multi-select.js";
15
+ import { OTPField } from "./otp-field.js";
16
+ import { Rating } from "./rating.js";
17
+ import { ScrubInput } from "./scrub-input.js";
18
+ import { SearchInput } from "./search-input.js";
19
+ import { Select } from "./select.js";
20
+ import { Slider } from "./slider.js";
21
+ import { Switch } from "./switch.js";
22
+ import { TagsInput } from "./tags-input.js";
23
+ import { Textarea } from "./textarea.js";
24
+ import { ToggleGroup } from "./toggle-group.js";
25
+ import { Toggle } from "./toggle.js";
26
+ export { Autocomplete, ButtonGroup, Checkbox, CheckboxGroup, Combobox, EnvVarInput, Field, FieldDescription, FieldError, FieldLabel, FileUpload, Input, InputGroup, MultiSelect, NumberField, OTPField, PasswordInput, Radio, RadioGroup, Rating, ScrubInput, SearchInput, Select, Slider, Switch, TagsInput, Textarea, Toggle, ToggleGroup, bareControlClasses, controlClasses, controlGroupFocusClasses, controlSurface, controlVariants, envReference, parseEnvReference, partitionFiles };
@@ -0,0 +1,31 @@
1
+ import { FormControlSize } from "./_chassis.js";
2
+ import * as React from "react";
3
+ //#region src/forms/input-group.d.ts
4
+ interface InputGroupProps extends React.ComponentPropsWithoutRef<"div"> {
5
+ /** Content pinned to the left gutter — a glyph, a unit prefix, a protocol. */
6
+ leading?: React.ReactNode;
7
+ /** Content pinned to the right gutter — a unit suffix, a `Kbd`, a clear button. */
8
+ trailing?: React.ReactNode;
9
+ /** Rung of the control ladder for the whole cluster. Defaults to `"md"`. */
10
+ size?: FormControlSize;
11
+ /** The control. An {@link Input} here renders bare and fills the middle. */
12
+ children: React.ReactNode;
13
+ }
14
+ /**
15
+ * A control and its adornments, drawn as a single field.
16
+ *
17
+ * The group — not the input — owns the chassis, so there is exactly one rim and
18
+ * one fill however many affordances are bolted on. It publishes that fact
19
+ * through context: an {@link Input} rendered inside strips its own border,
20
+ * background, height and padding and inherits the group's font size. Focus
21
+ * feedback moves to `focus-within`, since a `<div>` never matches
22
+ * `:focus-visible`.
23
+ *
24
+ * @example
25
+ * <InputGroup leading={<Search />} trailing={<Kbd>⌘K</Kbd>}>
26
+ * <Input aria-label="Search cues" />
27
+ * </InputGroup>
28
+ */
29
+ declare const InputGroup: React.ForwardRefExoticComponent<InputGroupProps & React.RefAttributes<HTMLDivElement>>;
30
+ //#endregion
31
+ export { InputGroup, InputGroupProps };
@@ -0,0 +1,54 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { controlGroupFocusClasses, controlVariants } from "./_chassis.js";
4
+ import * as React from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/forms/input-group.tsx
7
+ /**
8
+ * `true` inside an {@link InputGroup}: tells a nested control to render bare
9
+ * because the group already paints the rim, the fill and the height.
10
+ *
11
+ * @internal Not part of the public API; read by `input.tsx`.
12
+ */
13
+ const InputGroupContext = React.createContext(false);
14
+ /**
15
+ * A control and its adornments, drawn as a single field.
16
+ *
17
+ * The group — not the input — owns the chassis, so there is exactly one rim and
18
+ * one fill however many affordances are bolted on. It publishes that fact
19
+ * through context: an {@link Input} rendered inside strips its own border,
20
+ * background, height and padding and inherits the group's font size. Focus
21
+ * feedback moves to `focus-within`, since a `<div>` never matches
22
+ * `:focus-visible`.
23
+ *
24
+ * @example
25
+ * <InputGroup leading={<Search />} trailing={<Kbd>⌘K</Kbd>}>
26
+ * <Input aria-label="Search cues" />
27
+ * </InputGroup>
28
+ */
29
+ const InputGroup = React.forwardRef(function InputGroup({ className, leading, trailing, size, children, ...elementProps }, ref) {
30
+ return /* @__PURE__ */ jsxs("div", {
31
+ ref,
32
+ "data-slot": "input-group",
33
+ className: cn(controlVariants({ size }), "flex items-center gap-(--cue-space-2)", controlGroupFocusClasses, className),
34
+ ...elementProps,
35
+ children: [
36
+ leading === void 0 ? null : /* @__PURE__ */ jsx("span", {
37
+ "data-slot": "input-group-leading",
38
+ className: "flex shrink-0 items-center text-fg-subtle",
39
+ children: leading
40
+ }),
41
+ /* @__PURE__ */ jsx(InputGroupContext.Provider, {
42
+ value: true,
43
+ children
44
+ }),
45
+ trailing === void 0 ? null : /* @__PURE__ */ jsx("span", {
46
+ "data-slot": "input-group-trailing",
47
+ className: "flex shrink-0 items-center text-fg-subtle",
48
+ children: trailing
49
+ })
50
+ ]
51
+ });
52
+ });
53
+ //#endregion
54
+ export { InputGroup, InputGroupContext };
@@ -0,0 +1,33 @@
1
+ import { FormControlSize } from "./_chassis.js";
2
+ import * as React from "react";
3
+ import { Input } from "@base-ui/react/input";
4
+ //#region src/forms/input.d.ts
5
+ interface InputProps extends Omit<Input.Props, "className" | "size"> {
6
+ /** Extra classes, merged over the chassis. */
7
+ className?: string;
8
+ /**
9
+ * Rung of the control ladder. Defaults to `"md"`. Shadows the native `size`
10
+ * attribute (a character count), which nothing in a token-driven layout wants.
11
+ */
12
+ size?: FormControlSize;
13
+ }
14
+ /**
15
+ * The single-line text control.
16
+ *
17
+ * Wraps Base UI's `Input`, so dropping one inside a {@link Field} wires up the
18
+ * label, the description and the validity state with no `id` plumbing. Rides
19
+ * the recessed chassis: `bg-sunken` sets it into the panel rather than raising
20
+ * it off, which is how this system distinguishes "you type here" from "you
21
+ * press here".
22
+ *
23
+ * Inside an {@link InputGroup} it renders bare — the group owns the rim — so the
24
+ * two compose without a doubled border.
25
+ *
26
+ * @example
27
+ * <Input placeholder="e.g. Blackout" />
28
+ * @example
29
+ * <Input type="number" size="sm" defaultValue={512} />
30
+ */
31
+ declare const Input$1: React.ForwardRefExoticComponent<Omit<InputProps, "ref"> & React.RefAttributes<HTMLInputElement>>;
32
+ //#endregion
33
+ export { Input$1 as Input, InputProps };
@@ -0,0 +1,36 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { bareControlClasses, controlVariants } from "./_chassis.js";
4
+ import { InputGroupContext } from "./input-group.js";
5
+ import * as React from "react";
6
+ import { jsx } from "react/jsx-runtime";
7
+ import { Input } from "@base-ui/react/input";
8
+ //#region src/forms/input.tsx
9
+ /**
10
+ * The single-line text control.
11
+ *
12
+ * Wraps Base UI's `Input`, so dropping one inside a {@link Field} wires up the
13
+ * label, the description and the validity state with no `id` plumbing. Rides
14
+ * the recessed chassis: `bg-sunken` sets it into the panel rather than raising
15
+ * it off, which is how this system distinguishes "you type here" from "you
16
+ * press here".
17
+ *
18
+ * Inside an {@link InputGroup} it renders bare — the group owns the rim — so the
19
+ * two compose without a doubled border.
20
+ *
21
+ * @example
22
+ * <Input placeholder="e.g. Blackout" />
23
+ * @example
24
+ * <Input type="number" size="sm" defaultValue={512} />
25
+ */
26
+ const Input$1 = React.forwardRef(function Input$2({ className, size, ...elementProps }, ref) {
27
+ const inGroup = React.useContext(InputGroupContext);
28
+ return /* @__PURE__ */ jsx(Input, {
29
+ ref,
30
+ "data-slot": "input",
31
+ className: cn(inGroup ? bareControlClasses : controlVariants({ size }), className),
32
+ ...elementProps
33
+ });
34
+ });
35
+ //#endregion
36
+ export { Input$1 as Input };