@tulipfarm/sprout 0.0.0-stage → 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 (306) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +183 -2
  3. package/dist/components/accordion.d.ts +28 -0
  4. package/dist/components/accordion.js +26 -0
  5. package/dist/components/alert-dialog.d.ts +60 -0
  6. package/dist/components/alert-dialog.js +69 -0
  7. package/dist/components/alert.d.ts +30 -0
  8. package/dist/components/alert.js +35 -0
  9. package/dist/components/aspect-ratio.d.ts +7 -0
  10. package/dist/components/aspect-ratio.js +6 -0
  11. package/dist/components/attachment.d.ts +118 -0
  12. package/dist/components/attachment.js +285 -0
  13. package/dist/components/avatar.d.ts +32 -0
  14. package/dist/components/avatar.js +73 -0
  15. package/dist/components/badge.d.ts +21 -0
  16. package/dist/components/badge.js +27 -0
  17. package/dist/components/brand-icon.d.ts +28 -0
  18. package/dist/components/brand-icon.js +78 -0
  19. package/dist/components/breadcrumb.d.ts +29 -0
  20. package/dist/components/breadcrumb.js +44 -0
  21. package/dist/components/button-group.d.ts +28 -0
  22. package/dist/components/button-group.js +36 -0
  23. package/dist/components/button.d.ts +79 -0
  24. package/dist/components/button.js +93 -0
  25. package/dist/components/calendar.d.ts +27 -0
  26. package/dist/components/calendar.js +107 -0
  27. package/dist/components/canvas.d.ts +78 -0
  28. package/dist/components/canvas.js +180 -0
  29. package/dist/components/card.d.ts +43 -0
  30. package/dist/components/card.js +42 -0
  31. package/dist/components/carousel.d.ts +57 -0
  32. package/dist/components/carousel.js +422 -0
  33. package/dist/components/chart.d.ts +112 -0
  34. package/dist/components/chart.js +172 -0
  35. package/dist/components/chat-confirmation.d.ts +42 -0
  36. package/dist/components/chat-confirmation.js +62 -0
  37. package/dist/components/chat-plan.d.ts +21 -0
  38. package/dist/components/chat-plan.js +35 -0
  39. package/dist/components/chat-sources.d.ts +64 -0
  40. package/dist/components/chat-sources.js +66 -0
  41. package/dist/components/checkbox.d.ts +16 -0
  42. package/dist/components/checkbox.js +17 -0
  43. package/dist/components/choice-list.d.ts +53 -0
  44. package/dist/components/choice-list.js +36 -0
  45. package/dist/components/code-block.d.ts +35 -0
  46. package/dist/components/code-block.js +95 -0
  47. package/dist/components/collapsible.d.ts +24 -0
  48. package/dist/components/collapsible.js +27 -0
  49. package/dist/components/combobox.d.ts +95 -0
  50. package/dist/components/combobox.js +106 -0
  51. package/dist/components/command.d.ts +94 -0
  52. package/dist/components/command.js +414 -0
  53. package/dist/components/context-menu.d.ts +57 -0
  54. package/dist/components/context-menu.js +60 -0
  55. package/dist/components/dialog.d.ts +60 -0
  56. package/dist/components/dialog.js +79 -0
  57. package/dist/components/direction.d.ts +6 -0
  58. package/dist/components/direction.js +6 -0
  59. package/dist/components/dropdown-menu.d.ts +62 -0
  60. package/dist/components/dropdown-menu.js +59 -0
  61. package/dist/components/field.d.ts +117 -0
  62. package/dist/components/field.js +150 -0
  63. package/dist/components/file-viewer.d.ts +120 -0
  64. package/dist/components/file-viewer.js +373 -0
  65. package/dist/components/form.d.ts +87 -0
  66. package/dist/components/form.js +55 -0
  67. package/dist/components/glass-banner.d.ts +27 -0
  68. package/dist/components/glass-banner.js +116 -0
  69. package/dist/components/gradient-banner.d.ts +37 -0
  70. package/dist/components/gradient-banner.js +43 -0
  71. package/dist/components/hover-card.d.ts +27 -0
  72. package/dist/components/hover-card.js +26 -0
  73. package/dist/components/input-group.d.ts +68 -0
  74. package/dist/components/input-group.js +88 -0
  75. package/dist/components/input-otp.d.ts +38 -0
  76. package/dist/components/input-otp.js +43 -0
  77. package/dist/components/input.d.ts +16 -0
  78. package/dist/components/input.js +18 -0
  79. package/dist/components/kbd.d.ts +12 -0
  80. package/dist/components/kbd.js +11 -0
  81. package/dist/components/label.d.ts +8 -0
  82. package/dist/components/label.js +10 -0
  83. package/dist/components/mention-list.d.ts +54 -0
  84. package/dist/components/mention-list.js +31 -0
  85. package/dist/components/menubar.d.ts +64 -0
  86. package/dist/components/menubar.js +68 -0
  87. package/dist/components/message-actions.d.ts +34 -0
  88. package/dist/components/message-actions.js +68 -0
  89. package/dist/components/message-response.d.ts +20 -0
  90. package/dist/components/message-response.js +46 -0
  91. package/dist/components/message-scroller.d.ts +71 -0
  92. package/dist/components/message-scroller.js +217 -0
  93. package/dist/components/message.d.ts +49 -0
  94. package/dist/components/message.js +59 -0
  95. package/dist/components/navigation-menu.d.ts +45 -0
  96. package/dist/components/navigation-menu.js +54 -0
  97. package/dist/components/notice-banner.d.ts +14 -0
  98. package/dist/components/notice-banner.js +11 -0
  99. package/dist/components/page-content.d.ts +7 -0
  100. package/dist/components/page-content.js +9 -0
  101. package/dist/components/page-header.d.ts +37 -0
  102. package/dist/components/page-header.js +53 -0
  103. package/dist/components/pagination.d.ts +29 -0
  104. package/dist/components/pagination.js +29 -0
  105. package/dist/components/plan-outline.d.ts +60 -0
  106. package/dist/components/plan-outline.js +108 -0
  107. package/dist/components/popover.d.ts +34 -0
  108. package/dist/components/popover.js +35 -0
  109. package/dist/components/progress.d.ts +27 -0
  110. package/dist/components/progress.js +35 -0
  111. package/dist/components/prompt-list.d.ts +23 -0
  112. package/dist/components/prompt-list.js +11 -0
  113. package/dist/components/questionnaire.d.ts +148 -0
  114. package/dist/components/questionnaire.js +1001 -0
  115. package/dist/components/radio-group.d.ts +16 -0
  116. package/dist/components/radio-group.js +21 -0
  117. package/dist/components/reasoning-effort.d.ts +24 -0
  118. package/dist/components/reasoning-effort.js +269 -0
  119. package/dist/components/resizable.d.ts +67 -0
  120. package/dist/components/resizable.js +536 -0
  121. package/dist/components/result-card.d.ts +58 -0
  122. package/dist/components/result-card.js +88 -0
  123. package/dist/components/review-card.d.ts +62 -0
  124. package/dist/components/review-card.js +49 -0
  125. package/dist/components/rich-text-editor.d.ts +51 -0
  126. package/dist/components/rich-text-editor.js +248 -0
  127. package/dist/components/schema-diagram.d.ts +52 -0
  128. package/dist/components/schema-diagram.js +226 -0
  129. package/dist/components/scroll-area.d.ts +22 -0
  130. package/dist/components/scroll-area.js +19 -0
  131. package/dist/components/search-dialog.d.ts +103 -0
  132. package/dist/components/search-dialog.js +64 -0
  133. package/dist/components/search-field.d.ts +17 -0
  134. package/dist/components/search-field.js +27 -0
  135. package/dist/components/select.d.ts +57 -0
  136. package/dist/components/select.js +57 -0
  137. package/dist/components/selection-slot.d.ts +18 -0
  138. package/dist/components/selection-slot.js +53 -0
  139. package/dist/components/separator.d.ts +48 -0
  140. package/dist/components/separator.js +54 -0
  141. package/dist/components/settings-list.d.ts +26 -0
  142. package/dist/components/settings-list.js +17 -0
  143. package/dist/components/sheet.d.ts +70 -0
  144. package/dist/components/sheet.js +77 -0
  145. package/dist/components/sidebar.d.ts +70 -0
  146. package/dist/components/sidebar.js +187 -0
  147. package/dist/components/skeleton.d.ts +31 -0
  148. package/dist/components/skeleton.js +32 -0
  149. package/dist/components/slider.d.ts +17 -0
  150. package/dist/components/slider.js +24 -0
  151. package/dist/components/spinner.d.ts +37 -0
  152. package/dist/components/spinner.js +43 -0
  153. package/dist/components/state-panel-samples.d.ts +25 -0
  154. package/dist/components/state-panel-samples.js +423 -0
  155. package/dist/components/state-panel.d.ts +35 -0
  156. package/dist/components/state-panel.js +29 -0
  157. package/dist/components/state-sample.d.ts +63 -0
  158. package/dist/components/state-sample.js +42 -0
  159. package/dist/components/switch.d.ts +12 -0
  160. package/dist/components/switch.js +14 -0
  161. package/dist/components/table-nuqs.d.ts +16 -0
  162. package/dist/components/table-nuqs.js +59 -0
  163. package/dist/components/table.d.ts +120 -0
  164. package/dist/components/table.js +663 -0
  165. package/dist/components/tabs.d.ts +37 -0
  166. package/dist/components/tabs.js +36 -0
  167. package/dist/components/textarea.d.ts +18 -0
  168. package/dist/components/textarea.js +19 -0
  169. package/dist/components/toast.d.ts +45 -0
  170. package/dist/components/toast.js +83 -0
  171. package/dist/components/toggle-group.d.ts +30 -0
  172. package/dist/components/toggle-group.js +39 -0
  173. package/dist/components/toggle.d.ts +27 -0
  174. package/dist/components/toggle.js +21 -0
  175. package/dist/components/tool-activity.d.ts +79 -0
  176. package/dist/components/tool-activity.js +226 -0
  177. package/dist/components/toolbar-status.d.ts +21 -0
  178. package/dist/components/toolbar-status.js +14 -0
  179. package/dist/components/tooltip.d.ts +31 -0
  180. package/dist/components/tooltip.js +99 -0
  181. package/dist/components/typed-text.d.ts +17 -0
  182. package/dist/components/typed-text.js +56 -0
  183. package/dist/index.d.ts +88 -0
  184. package/dist/index.js +88 -0
  185. package/dist/internal/brand-glyphs.d.ts +342 -0
  186. package/dist/internal/brand-glyphs.js +238 -0
  187. package/dist/internal/classes.d.ts +3 -0
  188. package/dist/internal/classes.js +20 -0
  189. package/dist/internal/fieldset.d.ts +6 -0
  190. package/dist/internal/fieldset.js +38 -0
  191. package/dist/internal/file-kind.d.ts +4 -0
  192. package/dist/internal/file-kind.js +62 -0
  193. package/dist/internal/languages.d.ts +7 -0
  194. package/dist/internal/languages.js +1010 -0
  195. package/dist/internal/message-scroller.d.ts +102 -0
  196. package/dist/internal/message-scroller.js +637 -0
  197. package/dist/internal/pressable.d.ts +2 -0
  198. package/dist/internal/pressable.js +29 -0
  199. package/dist/internal/syntax.d.ts +14 -0
  200. package/dist/internal/syntax.js +137 -0
  201. package/dist/styles/accordion.css +102 -0
  202. package/dist/styles/alert-dialog.css +198 -0
  203. package/dist/styles/alert.css +149 -0
  204. package/dist/styles/aspect-ratio.css +8 -0
  205. package/dist/styles/attachment.css +720 -0
  206. package/dist/styles/avatar.css +186 -0
  207. package/dist/styles/badge.css +178 -0
  208. package/dist/styles/brand-icon.css +104 -0
  209. package/dist/styles/breadcrumb.css +121 -0
  210. package/dist/styles/button-group.css +113 -0
  211. package/dist/styles/button.css +380 -0
  212. package/dist/styles/calendar.css +295 -0
  213. package/dist/styles/canvas.css +327 -0
  214. package/dist/styles/card.css +146 -0
  215. package/dist/styles/carousel.css +107 -0
  216. package/dist/styles/chart.css +227 -0
  217. package/dist/styles/chat-confirmation.css +29 -0
  218. package/dist/styles/chat-plan.css +109 -0
  219. package/dist/styles/chat-sources.css +191 -0
  220. package/dist/styles/checkbox.css +123 -0
  221. package/dist/styles/choice-list.css +343 -0
  222. package/dist/styles/code-block.css +211 -0
  223. package/dist/styles/collapsible.css +72 -0
  224. package/dist/styles/combobox.css +347 -0
  225. package/dist/styles/command.css +233 -0
  226. package/dist/styles/context-menu.css +151 -0
  227. package/dist/styles/dialog.css +237 -0
  228. package/dist/styles/dropdown-menu.css +150 -0
  229. package/dist/styles/field.css +341 -0
  230. package/dist/styles/file-viewer.css +278 -0
  231. package/dist/styles/form.css +155 -0
  232. package/dist/styles/glass-banner.css +308 -0
  233. package/dist/styles/gradient-banner.css +256 -0
  234. package/dist/styles/hover-card.css +95 -0
  235. package/dist/styles/index.css +262 -0
  236. package/dist/styles/input-group.css +290 -0
  237. package/dist/styles/input-otp.css +138 -0
  238. package/dist/styles/input.css +99 -0
  239. package/dist/styles/kbd.css +59 -0
  240. package/dist/styles/label.css +89 -0
  241. package/dist/styles/mention-list.css +166 -0
  242. package/dist/styles/menubar.css +226 -0
  243. package/dist/styles/message-actions.css +83 -0
  244. package/dist/styles/message-response.css +176 -0
  245. package/dist/styles/message-scroller.css +136 -0
  246. package/dist/styles/message.css +310 -0
  247. package/dist/styles/navigation-menu.css +291 -0
  248. package/dist/styles/notice-banner.css +68 -0
  249. package/dist/styles/page-content.css +21 -0
  250. package/dist/styles/page-header.css +156 -0
  251. package/dist/styles/pagination.css +72 -0
  252. package/dist/styles/plan-outline.css +393 -0
  253. package/dist/styles/popover.css +140 -0
  254. package/dist/styles/progress.css +93 -0
  255. package/dist/styles/prompt-list.css +165 -0
  256. package/dist/styles/questionnaire.css +323 -0
  257. package/dist/styles/radio-group.css +120 -0
  258. package/dist/styles/reasoning-effort.css +157 -0
  259. package/dist/styles/resizable.css +108 -0
  260. package/dist/styles/result-card.css +215 -0
  261. package/dist/styles/review-card.css +235 -0
  262. package/dist/styles/rich-text-editor.css +169 -0
  263. package/dist/styles/schema-diagram.css +419 -0
  264. package/dist/styles/scroll-area.css +77 -0
  265. package/dist/styles/search-dialog.css +363 -0
  266. package/dist/styles/search-field.css +17 -0
  267. package/dist/styles/select.css +285 -0
  268. package/dist/styles/selection-slot.css +31 -0
  269. package/dist/styles/separator.css +206 -0
  270. package/dist/styles/settings-list.css +81 -0
  271. package/dist/styles/sheet.css +361 -0
  272. package/dist/styles/sidebar.css +363 -0
  273. package/dist/styles/skeleton.css +80 -0
  274. package/dist/styles/slider.css +142 -0
  275. package/dist/styles/spinner.css +39 -0
  276. package/dist/styles/state-panel-samples.css +41 -0
  277. package/dist/styles/state-panel.css +182 -0
  278. package/dist/styles/state-sample.css +285 -0
  279. package/dist/styles/switch.css +128 -0
  280. package/dist/styles/table.css +604 -0
  281. package/dist/styles/tabs.css +223 -0
  282. package/dist/styles/textarea.css +78 -0
  283. package/dist/styles/themes/chatgpt.css +125 -0
  284. package/dist/styles/themes/claude.css +125 -0
  285. package/dist/styles/themes/cloudflare.css +125 -0
  286. package/dist/styles/themes/discord.css +125 -0
  287. package/dist/styles/themes/github.css +125 -0
  288. package/dist/styles/themes/grok.css +125 -0
  289. package/dist/styles/themes/linear.css +126 -0
  290. package/dist/styles/themes/neutral.css +125 -0
  291. package/dist/styles/themes/notion.css +125 -0
  292. package/dist/styles/themes/perplexity.css +125 -0
  293. package/dist/styles/themes/raycast.css +125 -0
  294. package/dist/styles/themes/spotify.css +125 -0
  295. package/dist/styles/themes/stripe.css +125 -0
  296. package/dist/styles/themes/supabase.css +125 -0
  297. package/dist/styles/themes/tulipfarm.css +125 -0
  298. package/dist/styles/themes/vercel.css +126 -0
  299. package/dist/styles/toast.css +197 -0
  300. package/dist/styles/toggle-group.css +161 -0
  301. package/dist/styles/toggle.css +119 -0
  302. package/dist/styles/tool-activity.css +396 -0
  303. package/dist/styles/toolbar-status.css +52 -0
  304. package/dist/styles/tooltip.css +122 -0
  305. package/dist/styles/typed-text.css +17 -0
  306. package/package.json +443 -4
@@ -0,0 +1,79 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
4
+ import { mergeProps } from "@base-ui/react/merge-props";
5
+ import { useRender } from "@base-ui/react/use-render";
6
+ import { X } from "reicon-react/icons/X";
7
+ import { cn, stateClassName } from "../internal/classes.js";
8
+ import { Button } from "./button.js";
9
+ export const dialogSizeNames = [
10
+ "default",
11
+ "form",
12
+ "split",
13
+ "fullscreen",
14
+ ];
15
+ export const dialogPlacementNames = ["center", "top"];
16
+ export function Dialog(props) {
17
+ return _jsx(DialogPrimitive.Root, { ...props });
18
+ }
19
+ export function DialogTrigger(props) {
20
+ return _jsx(DialogPrimitive.Trigger, { "data-slot": "dialog-trigger", ...props });
21
+ }
22
+ export function DialogPortal(props) {
23
+ return _jsx(DialogPrimitive.Portal, { "data-slot": "dialog-portal", ...props });
24
+ }
25
+ export function DialogClose(props) {
26
+ return _jsx(DialogPrimitive.Close, { "data-slot": "dialog-close", ...props });
27
+ }
28
+ export function DialogOverlay({ className, ...props }) {
29
+ return (_jsx(DialogPrimitive.Backdrop, { "data-slot": "dialog-overlay", ...props, className: stateClassName("sprout-dialog-overlay", className) }));
30
+ }
31
+ /**
32
+ * The dialog surface. It renders its own portal and overlay, so place it
33
+ * directly inside `Dialog`.
34
+ */
35
+ export function DialogContent({ className, children, showCloseButton = true, closeLabel = "Close", size = "default", placement = "center", container, ...props }) {
36
+ return (_jsxs(DialogPortal, { container: container, children: [_jsx(DialogOverlay, {}), _jsxs(DialogPrimitive.Popup, { "data-slot": "dialog-content", "data-size": size, "data-placement": size === "fullscreen" ? undefined : placement, ...props, className: stateClassName(cn("sprout-dialog-content", `sprout-dialog-${size}`), className), children: [children, showCloseButton && (_jsx(DialogPrimitive.Close, { "data-slot": "dialog-close", className: "sprout-dialog-close", "aria-label": closeLabel, render: _jsx(Button, { variant: "ghost", size: "icon-sm" }), children: _jsx(X, { size: 16, "aria-hidden": "true" }) }))] })] }));
37
+ }
38
+ function part(slot, base) {
39
+ return function DialogPart({ className, render, ref, ...props }) {
40
+ return useRender({
41
+ defaultTagName: "div",
42
+ ref,
43
+ render,
44
+ props: mergeProps({ "data-slot": slot, className: cn(base, className) }, props),
45
+ state: { slot },
46
+ });
47
+ };
48
+ }
49
+ /** Stacks the title and description. */
50
+ export const DialogHeader = part("dialog-header", "sprout-dialog-header");
51
+ /**
52
+ * The scrolling middle of a `form` dialog. It bleeds to the dialog edges so
53
+ * scrollbars and focus rings are not clipped.
54
+ */
55
+ export const DialogBody = part("dialog-body", "sprout-dialog-body");
56
+ /**
57
+ * A tinted action bar pinned to the bottom edge. Actions stack in reverse
58
+ * order on narrow screens and align right from 640px. A leading `<p>` becomes
59
+ * a hint that sits at the start.
60
+ */
61
+ export function DialogFooter({ className, render, ref, showCloseButton = false, closeLabel = "Close", children, ...props }) {
62
+ return useRender({
63
+ defaultTagName: "div",
64
+ ref,
65
+ render,
66
+ props: mergeProps({
67
+ "data-slot": "dialog-footer",
68
+ className: cn("sprout-dialog-footer", className),
69
+ children: (_jsxs(_Fragment, { children: [children, showCloseButton && (_jsx(DialogPrimitive.Close, { render: _jsx(Button, { variant: "outline" }), children: closeLabel }))] })),
70
+ }, props),
71
+ state: { slot: "dialog-footer" },
72
+ });
73
+ }
74
+ export function DialogTitle({ className, ...props }) {
75
+ return (_jsx(DialogPrimitive.Title, { "data-slot": "dialog-title", ...props, className: stateClassName("sprout-dialog-title", className) }));
76
+ }
77
+ export function DialogDescription({ className, ...props }) {
78
+ return (_jsx(DialogPrimitive.Description, { "data-slot": "dialog-description", ...props, className: stateClassName("sprout-dialog-description", className) }));
79
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Tells Sprout's Base UI parts which way text reads, so arrow keys, sliding
3
+ * indicators, and popup sides follow it. It does not set the `dir` attribute;
4
+ * set `dir` on a wrapping element so CSS and the browser follow the same way.
5
+ */
6
+ export { DirectionProvider, useDirection, type DirectionProviderProps, type TextDirection, } from "@base-ui/react/direction-provider";
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Tells Sprout's Base UI parts which way text reads, so arrow keys, sliding
3
+ * indicators, and popup sides follow it. It does not set the `dir` attribute;
4
+ * set `dir` on a wrapping element so CSS and the browser follow the same way.
5
+ */
6
+ export { DirectionProvider, useDirection, } from "@base-ui/react/direction-provider";
@@ -0,0 +1,62 @@
1
+ import type { ComponentProps } from "react";
2
+ import { Menu as MenuPrimitive } from "@base-ui/react/menu";
3
+ export declare const dropdownMenuContentSizeNames: readonly ["anchor", "menu"];
4
+ export declare const dropdownMenuItemVariantNames: readonly ["default", "destructive"];
5
+ export type DropdownMenuContentSize = (typeof dropdownMenuContentSizeNames)[number];
6
+ export type DropdownMenuItemVariant = (typeof dropdownMenuItemVariantNames)[number];
7
+ export type DropdownMenuProps = MenuPrimitive.Root.Props;
8
+ export declare function DropdownMenu(props: DropdownMenuProps): import("react").JSX.Element;
9
+ export type DropdownMenuPortalProps = MenuPrimitive.Portal.Props;
10
+ export declare function DropdownMenuPortal(props: DropdownMenuPortalProps): import("react").JSX.Element;
11
+ export type DropdownMenuTriggerProps = MenuPrimitive.Trigger.Props;
12
+ export declare function DropdownMenuTrigger(props: DropdownMenuTriggerProps): import("react").JSX.Element;
13
+ type PositionerProps = Pick<MenuPrimitive.Positioner.Props, "align" | "alignOffset" | "side" | "sideOffset" | "collisionPadding" | "collisionAvoidance" | "sticky" | "positionMethod">;
14
+ export interface DropdownMenuContentProps extends MenuPrimitive.Popup.Props, PositionerProps {
15
+ /**
16
+ * `anchor` matches the trigger width (at least 8rem). `menu` is a fixed
17
+ * 16rem panel for icon triggers and longer labels.
18
+ */
19
+ size?: DropdownMenuContentSize;
20
+ /** Where the portal renders. Defaults to `document.body`. */
21
+ container?: MenuPrimitive.Portal.Props["container"];
22
+ }
23
+ /**
24
+ * The menu surface. It renders its own portal and positioner, so place it
25
+ * directly inside `DropdownMenu` or `DropdownMenuSub`.
26
+ */
27
+ export declare function DropdownMenuContent({ align, alignOffset, side, sideOffset, collisionPadding, collisionAvoidance, sticky, positionMethod, size, container, className, ...props }: DropdownMenuContentProps): import("react").JSX.Element;
28
+ export type DropdownMenuGroupProps = MenuPrimitive.Group.Props;
29
+ export declare function DropdownMenuGroup(props: DropdownMenuGroupProps): import("react").JSX.Element;
30
+ interface Inset {
31
+ /** Indents the text to line up with items that have a leading icon. */
32
+ inset?: boolean;
33
+ }
34
+ export interface DropdownMenuLabelProps extends MenuPrimitive.GroupLabel.Props, Inset {
35
+ }
36
+ export declare function DropdownMenuLabel({ className, inset, ...props }: DropdownMenuLabelProps): import("react").JSX.Element;
37
+ export interface DropdownMenuItemProps extends MenuPrimitive.Item.Props, Inset {
38
+ variant?: DropdownMenuItemVariant;
39
+ }
40
+ export declare function DropdownMenuItem({ className, inset, variant, ...props }: DropdownMenuItemProps): import("react").JSX.Element;
41
+ export type DropdownMenuSubProps = MenuPrimitive.SubmenuRoot.Props;
42
+ export declare function DropdownMenuSub(props: DropdownMenuSubProps): import("react").JSX.Element;
43
+ export interface DropdownMenuSubTriggerProps extends MenuPrimitive.SubmenuTrigger.Props, Inset {
44
+ }
45
+ export declare function DropdownMenuSubTrigger({ className, inset, children, ...props }: DropdownMenuSubTriggerProps): import("react").JSX.Element;
46
+ export type DropdownMenuSubContentProps = DropdownMenuContentProps;
47
+ /** A nested menu surface. It opens to the side and sizes to its content. */
48
+ export declare function DropdownMenuSubContent({ align, alignOffset, side, sideOffset, className, ...props }: DropdownMenuSubContentProps): import("react").JSX.Element;
49
+ export interface DropdownMenuCheckboxItemProps extends MenuPrimitive.CheckboxItem.Props, Inset {
50
+ }
51
+ export declare function DropdownMenuCheckboxItem({ className, inset, children, ...props }: DropdownMenuCheckboxItemProps): import("react").JSX.Element;
52
+ export type DropdownMenuRadioGroupProps = MenuPrimitive.RadioGroup.Props;
53
+ export declare function DropdownMenuRadioGroup(props: DropdownMenuRadioGroupProps): import("react").JSX.Element;
54
+ export interface DropdownMenuRadioItemProps extends MenuPrimitive.RadioItem.Props, Inset {
55
+ }
56
+ export declare function DropdownMenuRadioItem({ className, inset, children, ...props }: DropdownMenuRadioItemProps): import("react").JSX.Element;
57
+ export type DropdownMenuSeparatorProps = MenuPrimitive.Separator.Props;
58
+ export declare function DropdownMenuSeparator({ className, ...props }: DropdownMenuSeparatorProps): import("react").JSX.Element;
59
+ export type DropdownMenuShortcutProps = ComponentProps<"span">;
60
+ /** Right-aligned hint text, such as a keyboard shortcut. It does not bind keys. */
61
+ export declare function DropdownMenuShortcut({ className, ...props }: DropdownMenuShortcutProps): import("react").JSX.Element;
62
+ export {};
@@ -0,0 +1,59 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Menu as MenuPrimitive } from "@base-ui/react/menu";
4
+ import { Check } from "reicon-react/icons/Check";
5
+ import { ChevronRight } from "reicon-react/icons/ChevronRight";
6
+ import { cn, stateClassName } from "../internal/classes.js";
7
+ export const dropdownMenuContentSizeNames = ["anchor", "menu"];
8
+ export const dropdownMenuItemVariantNames = ["default", "destructive"];
9
+ export function DropdownMenu(props) {
10
+ return _jsx(MenuPrimitive.Root, { ...props });
11
+ }
12
+ export function DropdownMenuPortal(props) {
13
+ return _jsx(MenuPrimitive.Portal, { "data-slot": "dropdown-menu-portal", ...props });
14
+ }
15
+ export function DropdownMenuTrigger(props) {
16
+ return _jsx(MenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
17
+ }
18
+ /**
19
+ * The menu surface. It renders its own portal and positioner, so place it
20
+ * directly inside `DropdownMenu` or `DropdownMenuSub`.
21
+ */
22
+ export function DropdownMenuContent({ align = "start", alignOffset = 0, side = "bottom", sideOffset = 4, collisionPadding = 8, collisionAvoidance, sticky, positionMethod, size = "anchor", container, className, ...props }) {
23
+ return (_jsx(MenuPrimitive.Portal, { container: container, children: _jsx(MenuPrimitive.Positioner, { className: "sprout-dropdown-menu-positioner", align: align, alignOffset: alignOffset, side: side, sideOffset: sideOffset, collisionPadding: collisionPadding, collisionAvoidance: collisionAvoidance, sticky: sticky, positionMethod: positionMethod, children: _jsx(MenuPrimitive.Popup, { "data-slot": "dropdown-menu-content", "data-size": size, ...props, className: stateClassName(cn("sprout-dropdown-menu-content", `sprout-dropdown-menu-${size}`), className) }) }) }));
24
+ }
25
+ export function DropdownMenuGroup(props) {
26
+ return _jsx(MenuPrimitive.Group, { "data-slot": "dropdown-menu-group", ...props });
27
+ }
28
+ export function DropdownMenuLabel({ className, inset, ...props }) {
29
+ return (_jsx(MenuPrimitive.GroupLabel, { "data-slot": "dropdown-menu-label", "data-inset": inset || undefined, ...props, className: stateClassName("sprout-dropdown-menu-label", className) }));
30
+ }
31
+ export function DropdownMenuItem({ className, inset, variant = "default", ...props }) {
32
+ return (_jsx(MenuPrimitive.Item, { "data-slot": "dropdown-menu-item", "data-inset": inset || undefined, "data-variant": variant, ...props, className: stateClassName("sprout-dropdown-menu-item", className) }));
33
+ }
34
+ export function DropdownMenuSub(props) {
35
+ return _jsx(MenuPrimitive.SubmenuRoot, { ...props });
36
+ }
37
+ export function DropdownMenuSubTrigger({ className, inset, children, ...props }) {
38
+ return (_jsxs(MenuPrimitive.SubmenuTrigger, { "data-slot": "dropdown-menu-sub-trigger", "data-inset": inset || undefined, ...props, className: stateClassName("sprout-dropdown-menu-item sprout-dropdown-menu-sub-trigger", className), children: [children, _jsx(ChevronRight, { size: 16, "aria-hidden": "true", className: "sprout-dropdown-menu-sub-chevron" })] }));
39
+ }
40
+ /** A nested menu surface. It opens to the side and sizes to its content. */
41
+ export function DropdownMenuSubContent({ align = "start", alignOffset = -5, side = "right", sideOffset = 0, className, ...props }) {
42
+ return (_jsx(DropdownMenuContent, { "data-slot": "dropdown-menu-sub-content", align: align, alignOffset: alignOffset, side: side, sideOffset: sideOffset, ...props, className: stateClassName("sprout-dropdown-menu-sub-content", className) }));
43
+ }
44
+ export function DropdownMenuCheckboxItem({ className, inset, children, ...props }) {
45
+ return (_jsxs(MenuPrimitive.CheckboxItem, { "data-slot": "dropdown-menu-checkbox-item", "data-inset": inset || undefined, ...props, className: stateClassName("sprout-dropdown-menu-item sprout-dropdown-menu-choice", className), children: [_jsx("span", { className: "sprout-dropdown-menu-indicator", "data-slot": "dropdown-menu-checkbox-item-indicator", children: _jsx(MenuPrimitive.CheckboxItemIndicator, { children: _jsx(Check, { size: 16, "aria-hidden": "true" }) }) }), children] }));
46
+ }
47
+ export function DropdownMenuRadioGroup(props) {
48
+ return (_jsx(MenuPrimitive.RadioGroup, { "data-slot": "dropdown-menu-radio-group", ...props }));
49
+ }
50
+ export function DropdownMenuRadioItem({ className, inset, children, ...props }) {
51
+ return (_jsxs(MenuPrimitive.RadioItem, { "data-slot": "dropdown-menu-radio-item", "data-inset": inset || undefined, ...props, className: stateClassName("sprout-dropdown-menu-item sprout-dropdown-menu-choice", className), children: [_jsx("span", { className: "sprout-dropdown-menu-indicator", "data-slot": "dropdown-menu-radio-item-indicator", children: _jsx(MenuPrimitive.RadioItemIndicator, { children: _jsx(Check, { size: 16, "aria-hidden": "true" }) }) }), children] }));
52
+ }
53
+ export function DropdownMenuSeparator({ className, ...props }) {
54
+ return (_jsx(MenuPrimitive.Separator, { "data-slot": "dropdown-menu-separator", ...props, className: stateClassName("sprout-dropdown-menu-separator", className) }));
55
+ }
56
+ /** Right-aligned hint text, such as a keyboard shortcut. It does not bind keys. */
57
+ export function DropdownMenuShortcut({ className, ...props }) {
58
+ return (_jsx("span", { "data-slot": "dropdown-menu-shortcut", ...props, className: cn("sprout-dropdown-menu-shortcut", className) }));
59
+ }
@@ -0,0 +1,117 @@
1
+ import { type AriaAttributes, type ReactElement, type ReactNode } from "react";
2
+ import { type SeparatorLabelProps } from "./separator.js";
3
+ export declare const fieldLabelVisibilityNames: readonly ["visible", "screen-reader"];
4
+ export declare const choiceGroupTypeNames: readonly ["checkbox", "radio"];
5
+ export declare const choiceGroupLayoutNames: readonly ["list", "columns"];
6
+ export declare const checkboxFieldVariantNames: readonly ["default", "neutral"];
7
+ export type FieldLabelVisibility = (typeof fieldLabelVisibilityNames)[number];
8
+ export type ChoiceGroupType = (typeof choiceGroupTypeNames)[number];
9
+ export type ChoiceGroupLayout = (typeof choiceGroupLayoutNames)[number];
10
+ export type CheckboxFieldVariant = (typeof checkboxFieldVariantNames)[number];
11
+ /** Every field states whether it is required or optional; there is no default. */
12
+ export type Requirement = {
13
+ required: true;
14
+ optional?: never;
15
+ } | {
16
+ optional: true;
17
+ required?: never;
18
+ };
19
+ /**
20
+ * Locks every Field, ChoiceGroup, and CheckboxField below it. Render it as a
21
+ * provider: `<FieldsDisabled value={saving}>…</FieldsDisabled>`.
22
+ */
23
+ export declare const FieldsDisabled: import("react").Context<boolean>;
24
+ export interface FieldControlProps {
25
+ id?: string | undefined;
26
+ disabled?: boolean | undefined;
27
+ "aria-describedby"?: string | undefined;
28
+ "aria-invalid"?: AriaAttributes["aria-invalid"];
29
+ "aria-required"?: AriaAttributes["aria-required"];
30
+ "aria-label"?: string | undefined;
31
+ "aria-labelledby"?: string | undefined;
32
+ }
33
+ /**
34
+ * Connects a control to the Field around it. Pass the control's props; it
35
+ * returns them with the field's id, disabled state, description ids, and
36
+ * invalid and required flags merged in. Outside a Field, or when the control
37
+ * names itself with `aria-label` or `aria-labelledby`, props pass through.
38
+ */
39
+ export declare function useFieldControl<P extends FieldControlProps>(props: P): P;
40
+ export type FieldProps = Requirement & {
41
+ label: string;
42
+ /** `screen-reader` keeps the label, marker, and counter for assistive tech only. */
43
+ labelVisibility?: FieldLabelVisibility | undefined;
44
+ helper?: ReactNode;
45
+ /** Replaces the helper line and marks the control invalid. */
46
+ error?: string | undefined;
47
+ /** Short status at the end of the label row, such as `120 / 8,000`. */
48
+ counter?: string | undefined;
49
+ /** The control id. Generated when omitted. */
50
+ id?: string | undefined;
51
+ disabled?: boolean | undefined;
52
+ className?: string | undefined;
53
+ /** One control, or one element that contains it. The control reads the field with `useFieldControl`. */
54
+ children: ReactElement;
55
+ };
56
+ /**
57
+ * A labeled form row for one control: label, required or optional marker,
58
+ * optional counter, the control, and a helper or error line.
59
+ */
60
+ export declare function Field({ label, labelVisibility, helper, error, counter, id, disabled, required, className, children, }: FieldProps): import("react").JSX.Element;
61
+ export interface ChoiceOption<V extends string> {
62
+ value: V;
63
+ label: string;
64
+ description?: string | undefined;
65
+ disabled?: boolean | undefined;
66
+ }
67
+ export type ChoiceGroupProps<V extends string> = Requirement & {
68
+ legend: string;
69
+ legendVisibility?: FieldLabelVisibility | undefined;
70
+ helper?: ReactNode;
71
+ error?: string | undefined;
72
+ /** A warning badge after the legend, such as "Changes data". */
73
+ warning?: string | undefined;
74
+ options: readonly ChoiceOption<V>[];
75
+ /** `columns` splits options into two columns from 640px. */
76
+ layout?: ChoiceGroupLayout | undefined;
77
+ disabled?: boolean | undefined;
78
+ /** The group id. Generated when omitted. */
79
+ id?: string | undefined;
80
+ className?: string | undefined;
81
+ } & ({
82
+ type: "checkbox";
83
+ value: readonly V[];
84
+ onValueChange: (value: V[]) => void;
85
+ } | {
86
+ type: "radio";
87
+ value: V;
88
+ onValueChange: (value: V) => void;
89
+ });
90
+ /**
91
+ * A labeled set of checkboxes (many values) or radios (one value), with
92
+ * optional descriptions per option, a helper, a warning badge, and an error.
93
+ */
94
+ export declare function ChoiceGroup<V extends string>(props: ChoiceGroupProps<V>): import("react").JSX.Element;
95
+ export interface CheckboxFieldProps {
96
+ label: string;
97
+ helper?: ReactNode;
98
+ error?: string | undefined;
99
+ checked: boolean;
100
+ onCheckedChange: (checked: boolean) => void;
101
+ disabled?: boolean | undefined;
102
+ /** `neutral` fills with the text color instead of the brand primary, for filter lists. */
103
+ variant?: CheckboxFieldVariant | undefined;
104
+ /** Placed on the wrapper, so focusing the first control inside it focuses the checkbox. */
105
+ id?: string | undefined;
106
+ className?: string | undefined;
107
+ }
108
+ /** One checkbox with its label and a helper or error line, for consent and on/off settings. */
109
+ export declare function CheckboxField({ label, helper, error, checked, onCheckedChange, disabled, id, variant, className, }: CheckboxFieldProps): import("react").JSX.Element;
110
+ export type FieldSeparatorProps = Omit<SeparatorLabelProps, "variant" | "children"> & {
111
+ children?: SeparatorLabelProps["children"];
112
+ };
113
+ /**
114
+ * A labeled separator sized for a field stack: it pulls in the stack gap so
115
+ * the line sits evenly between fields. Text such as "or" is optional.
116
+ */
117
+ export declare function FieldSeparator({ className, children, ...props }: FieldSeparatorProps): import("react").JSX.Element;
@@ -0,0 +1,150 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { createContext, useContext, useId, } from "react";
4
+ import { Checkbox as BaseCheckbox } from "@base-ui/react/checkbox";
5
+ import { Check } from "reicon-react/icons/Check";
6
+ import { cn } from "../internal/classes.js";
7
+ import { Badge } from "./badge.js";
8
+ import { RadioGroup, RadioGroupItem } from "./radio-group.js";
9
+ import { Separator } from "./separator.js";
10
+ export const fieldLabelVisibilityNames = ["visible", "screen-reader"];
11
+ export const choiceGroupTypeNames = ["checkbox", "radio"];
12
+ export const choiceGroupLayoutNames = ["list", "columns"];
13
+ export const checkboxFieldVariantNames = ["default", "neutral"];
14
+ /**
15
+ * Locks every Field, ChoiceGroup, and CheckboxField below it. Render it as a
16
+ * provider: `<FieldsDisabled value={saving}>…</FieldsDisabled>`.
17
+ */
18
+ export const FieldsDisabled = createContext(false);
19
+ const FieldControlContext = createContext(null);
20
+ /**
21
+ * Connects a control to the Field around it. Pass the control's props; it
22
+ * returns them with the field's id, disabled state, description ids, and
23
+ * invalid and required flags merged in. Outside a Field, or when the control
24
+ * names itself with `aria-label` or `aria-labelledby`, props pass through.
25
+ */
26
+ export function useFieldControl(props) {
27
+ const field = useContext(FieldControlContext);
28
+ if (!field ||
29
+ props["aria-label"] !== undefined ||
30
+ props["aria-labelledby"] !== undefined)
31
+ return props;
32
+ return {
33
+ ...props,
34
+ id: field.id,
35
+ disabled: field.disabled || props.disabled,
36
+ "aria-describedby": ids(field.describedBy, props["aria-describedby"]),
37
+ "aria-invalid": field.invalid || props["aria-invalid"],
38
+ "aria-required": field.required || props["aria-required"],
39
+ };
40
+ }
41
+ // Deduped so a control that applies useFieldControl twice keeps one copy of each id.
42
+ function ids(...values) {
43
+ const tokens = values.flatMap((value) => (value ? value.split(/\s+/) : []));
44
+ return [...new Set(tokens.filter(Boolean))].join(" ") || undefined;
45
+ }
46
+ function RequirementMarker({ required, id, }) {
47
+ return (_jsx("span", { id: id, "aria-hidden": id ? undefined : true, "data-slot": "requirement", className: "sprout-field-requirement", children: required ? "Required" : "Optional" }));
48
+ }
49
+ /**
50
+ * A labeled form row for one control: label, required or optional marker,
51
+ * optional counter, the control, and a helper or error line.
52
+ */
53
+ export function Field({ label, labelVisibility = "visible", helper, error, counter, id, disabled, required, className, children, }) {
54
+ const generatedId = useId();
55
+ const controlId = id ?? generatedId;
56
+ const locked = useContext(FieldsDisabled) || disabled === true;
57
+ const lineId = error
58
+ ? `${controlId}-error`
59
+ : helper
60
+ ? `${controlId}-helper`
61
+ : undefined;
62
+ const markerId = required ? undefined : `${controlId}-requirement`;
63
+ const counterId = counter ? `${controlId}-counter` : undefined;
64
+ const control = {
65
+ id: controlId,
66
+ describedBy: ids(lineId, markerId, counterId),
67
+ invalid: Boolean(error),
68
+ required: required === true,
69
+ disabled: locked,
70
+ };
71
+ return (_jsxs("div", { "data-slot": "field", "data-disabled": locked || undefined, "data-invalid": error ? true : undefined, className: cn("sprout-field", className), children: [_jsxs("div", { "data-slot": "field-header", className: labelVisibility === "screen-reader"
72
+ ? "sprout-field-sr-only"
73
+ : "sprout-field-header", children: [_jsxs("div", { className: "sprout-field-heading", children: [_jsx("label", { "data-slot": "label", htmlFor: controlId, className: "sprout-field-label", children: label }), _jsx(RequirementMarker, { required: required === true, id: markerId })] }), counter && (_jsx("p", { id: counterId, "data-slot": "field-counter", className: "sprout-field-counter", children: counter }))] }), _jsx(FieldControlContext, { value: control, children: children }), error ? (_jsx("p", { id: lineId, "data-slot": "field-error", className: "sprout-field-message sprout-field-error", children: error })) : helper ? (_jsx("p", { id: lineId, "data-slot": "field-helper", className: "sprout-field-message", children: helper })) : null] }));
74
+ }
75
+ function FieldCheckbox({ variant = "default", className, ...props }) {
76
+ return (_jsx(BaseCheckbox.Root, { "data-slot": "checkbox", "data-variant": variant, className: cn("sprout-field-checkbox", className), ...props, children: _jsx(BaseCheckbox.Indicator, { "data-slot": "checkbox-indicator", className: "sprout-field-checkbox-indicator", children: _jsx(Check, { "aria-hidden": "true" }) }) }));
77
+ }
78
+ /**
79
+ * A labeled set of checkboxes (many values) or radios (one value), with
80
+ * optional descriptions per option, a helper, a warning badge, and an error.
81
+ */
82
+ export function ChoiceGroup(props) {
83
+ const { legend, legendVisibility = "visible", helper, error, warning, options, layout = "list", required, className, } = props;
84
+ const generatedId = useId();
85
+ const groupId = props.id ?? generatedId;
86
+ const locked = useContext(FieldsDisabled) || props.disabled === true;
87
+ const radio = props.type === "radio";
88
+ const legendId = `${groupId}-legend`;
89
+ const errorId = error ? `${groupId}-error` : undefined;
90
+ const helperId = helper ? `${groupId}-helper` : undefined;
91
+ // A radiogroup carries aria-required; a checkbox group cannot, so it describes its marker either way.
92
+ const markerId = radio && required ? undefined : `${groupId}-requirement`;
93
+ const labelling = {
94
+ id: groupId,
95
+ "aria-labelledby": legendId,
96
+ "aria-describedby": ids(errorId, helperId, markerId),
97
+ };
98
+ const rows = options.map((option, index) => {
99
+ const checked = props.type === "checkbox"
100
+ ? props.value.includes(option.value)
101
+ : props.value === option.value;
102
+ const disabled = locked || option.disabled === true;
103
+ const descriptionId = option.description
104
+ ? `${groupId}-option-${index}-description`
105
+ : undefined;
106
+ let control;
107
+ if (props.type === "checkbox") {
108
+ const { value, onValueChange } = props;
109
+ control = (_jsx(FieldCheckbox, { checked: checked, disabled: disabled, "aria-describedby": descriptionId, "aria-invalid": error ? true : undefined, onCheckedChange: (next) => onValueChange(next
110
+ ? [...value, option.value]
111
+ : value.filter((item) => item !== option.value)) }));
112
+ }
113
+ else {
114
+ control = (_jsx(RadioGroupItem, { className: "sprout-field-radio", value: option.value, disabled: disabled, "aria-describedby": descriptionId }));
115
+ }
116
+ return (_jsxs("div", { "data-slot": "choice-option", "data-checked": checked || undefined, "data-disabled": disabled || undefined, className: "sprout-choice-option", children: [_jsxs("label", { className: "sprout-choice-option-label", children: [control, _jsx("span", { className: "sprout-choice-option-text", children: option.label })] }), option.description && (_jsx("p", { id: descriptionId, className: "sprout-choice-option-description", children: option.description }))] }, option.value));
117
+ });
118
+ const content = (_jsxs(_Fragment, { children: [_jsxs("div", { className: legendVisibility === "screen-reader"
119
+ ? "sprout-field-sr-only"
120
+ : "sprout-choice-group-legend", children: [_jsx("p", { id: legendId, className: "sprout-choice-group-legend-text", children: legend }), _jsx(RequirementMarker, { required: required === true, id: markerId }), warning && _jsx(Badge, { variant: "warning", children: warning })] }), helper && (_jsx("p", { id: helperId, className: "sprout-field-message", children: helper })), _jsx("div", { "data-slot": "choice-group-options", "data-layout": layout, className: "sprout-choice-group-options", children: rows }), error && (_jsx("p", { id: errorId, className: "sprout-field-message sprout-field-error", children: error }))] }));
121
+ const classes = cn("sprout-choice-group", className);
122
+ if (props.type === "radio") {
123
+ const { onValueChange } = props;
124
+ return (_jsx(RadioGroup, { "data-slot": "choice-group", "data-type": "radio", className: classes, value: props.value, disabled: locked, "aria-required": required || undefined, "aria-invalid": error ? true : undefined, ...labelling, onValueChange: (next) => {
125
+ const option = options.find((item) => item.value === next);
126
+ if (option)
127
+ onValueChange(option.value);
128
+ }, children: content }));
129
+ }
130
+ return (_jsx("div", { role: "group", "data-slot": "choice-group", "data-type": "checkbox", "data-disabled": locked || undefined, className: classes, ...labelling, children: content }));
131
+ }
132
+ /** One checkbox with its label and a helper or error line, for consent and on/off settings. */
133
+ export function CheckboxField({ label, helper, error, checked, onCheckedChange, disabled, id, variant, className, }) {
134
+ const generatedId = useId();
135
+ const fieldId = id ?? generatedId;
136
+ const locked = useContext(FieldsDisabled) || disabled === true;
137
+ const lineId = error
138
+ ? `${fieldId}-error`
139
+ : helper
140
+ ? `${fieldId}-helper`
141
+ : undefined;
142
+ return (_jsxs("div", { id: fieldId, "data-slot": "checkbox-field", "data-disabled": locked || undefined, className: cn("sprout-checkbox-field", className), children: [_jsxs("label", { className: "sprout-checkbox-field-label", children: [_jsx(FieldCheckbox, { variant: variant, checked: checked, disabled: locked, "aria-describedby": lineId, "aria-invalid": error ? true : undefined, onCheckedChange: (next) => onCheckedChange(next) }), _jsx("span", { className: "sprout-checkbox-field-text", children: label })] }), error ? (_jsx("p", { id: lineId, className: "sprout-field-message sprout-field-error sprout-checkbox-field-message", children: error })) : helper ? (_jsx("p", { id: lineId, className: "sprout-field-message sprout-checkbox-field-message", children: helper })) : null] }));
143
+ }
144
+ /**
145
+ * A labeled separator sized for a field stack: it pulls in the stack gap so
146
+ * the line sits evenly between fields. Text such as "or" is optional.
147
+ */
148
+ export function FieldSeparator({ className, children = null, ...props }) {
149
+ return (_jsx(Separator, { "data-slot": "field-separator", className: cn("sprout-field-separator", className), ...props, children: children }));
150
+ }
@@ -0,0 +1,120 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ import { type FileKind } from "../internal/file-kind.js";
3
+ import { type DialogContentProps } from "./dialog.js";
4
+ export type ViewableFileSource = {
5
+ kind: "local";
6
+ file: File;
7
+ } | {
8
+ kind: "remote";
9
+ url: string;
10
+ };
11
+ export interface ViewableFile {
12
+ name: string;
13
+ mediaType: string;
14
+ source: ViewableFileSource;
15
+ }
16
+ export type ViewableFileKind = FileKind;
17
+ export interface FileSheetRendererProps {
18
+ name: string;
19
+ bytes: ArrayBuffer;
20
+ onRetry: () => void;
21
+ }
22
+ export interface FileOfficeRendererProps extends FileSheetRendererProps {
23
+ kind: "document" | "slides";
24
+ }
25
+ export interface FileMarkdownRendererProps {
26
+ text: string;
27
+ }
28
+ /**
29
+ * Renderers for formats that need a heavy parser. Without one, sheets and
30
+ * Office files show a download prompt and Markdown shows its plain text.
31
+ * Each renderer runs inside Suspense with `LoadingFile` as the fallback,
32
+ * so a lazy component works as is.
33
+ */
34
+ export interface FileRenderers {
35
+ markdown?: ((props: FileMarkdownRendererProps) => ReactNode) | undefined;
36
+ sheet?: ((props: FileSheetRendererProps) => ReactNode) | undefined;
37
+ office?: ((props: FileOfficeRendererProps) => ReactNode) | undefined;
38
+ }
39
+ export interface FileRenderersProviderProps {
40
+ renderers: FileRenderers;
41
+ children?: ReactNode;
42
+ }
43
+ /** Registers file renderers once for every viewer below it. */
44
+ export declare function FileRenderersProvider({ renderers, children, }: FileRenderersProviderProps): import("react").JSX.Element;
45
+ export declare const maxViewableFileBytes: number;
46
+ export declare function viewableFileKind(name: string, mediaType: string): ViewableFileKind;
47
+ export interface GoogleDocumentLink {
48
+ url: string;
49
+ embedUrl: string;
50
+ mediaType: string;
51
+ }
52
+ /** Recognizes a docs.google.com Docs, Sheets, or Slides link. */
53
+ export declare function googleDocument(url: string): GoogleDocumentLink | null;
54
+ /** Reads the document link from a .gdoc, .gsheet, or .gslides shortcut. */
55
+ export declare function googleShortcut(text: string): string;
56
+ /**
57
+ * The type to give a same-origin blob URL. Stored media types are
58
+ * untrusted, so anything a browser could run as a document, including SVG,
59
+ * becomes `application/octet-stream`.
60
+ */
61
+ export declare function renderableType(name: string, mediaType: string): string;
62
+ interface FileViewerBaseProps {
63
+ open: boolean;
64
+ onOpenChange: (open: boolean) => void;
65
+ renderers?: FileRenderers | undefined;
66
+ /** Where focus goes on close. Defaults to the element that had focus when the viewer opened. */
67
+ finalFocus?: DialogContentProps["finalFocus"];
68
+ }
69
+ interface SingleFileProps {
70
+ file: ViewableFile | null;
71
+ files?: undefined;
72
+ index?: undefined;
73
+ onIndexChange?: undefined;
74
+ }
75
+ interface FileSetProps {
76
+ file?: undefined;
77
+ /** Files to step through with Previous, Next, and the arrow keys. */
78
+ files: readonly ViewableFile[];
79
+ index: number;
80
+ onIndexChange: (index: number) => void;
81
+ }
82
+ export type FileViewerProps = FileViewerBaseProps & (SingleFileProps | FileSetProps);
83
+ /** A full-screen dialog that opens a local or linked file, or steps through several. */
84
+ export declare function FileViewer({ file, files, index, onIndexChange, open, onOpenChange, renderers, finalFocus, }: FileViewerProps): import("react").JSX.Element;
85
+ export interface ViewableFileContentProps extends HTMLAttributes<HTMLDivElement> {
86
+ file: ViewableFile;
87
+ renderers?: FileRenderers | undefined;
88
+ }
89
+ /** Loads a local or linked file and shows it inline, with reload and download. */
90
+ export declare function ViewableFileContent({ file, renderers, className, ...props }: ViewableFileContentProps): import("react").JSX.Element;
91
+ export interface FileContentProps {
92
+ name: string;
93
+ mediaType: string;
94
+ bytes: ArrayBuffer;
95
+ /** A blob URL for `bytes`, typed with `renderableType`. */
96
+ url: string;
97
+ onRetry: () => void;
98
+ renderers?: FileRenderers | undefined;
99
+ }
100
+ /** Shows bytes you already loaded: images, PDF, text, JSON, Markdown, Google shortcuts, and more. */
101
+ export declare function FileContent({ name, mediaType, bytes, url, onRetry, renderers: own, }: FileContentProps): import("react").JSX.Element;
102
+ export type LoadingFileProps = HTMLAttributes<HTMLDivElement>;
103
+ export declare function LoadingFile({ className, ...props }: LoadingFileProps): import("react").JSX.Element;
104
+ export interface FileErrorProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
105
+ message: ReactNode;
106
+ onRetry: () => void;
107
+ }
108
+ export declare function FileError({ message, onRetry, className, ...props }: FileErrorProps): import("react").JSX.Element;
109
+ /** Whether `FilePreview` can show this file: images, text, code, JSON, and Markdown, but not Google shortcuts. */
110
+ export declare function isPreviewableFile(file: ViewableFile): boolean;
111
+ export interface FilePreviewProps extends HTMLAttributes<HTMLDivElement> {
112
+ file: ViewableFile;
113
+ }
114
+ /**
115
+ * A small, non-interactive peek at a file: the image, or the first lines
116
+ * of text and code with syntax colors. Made for hover cards and thumbnails.
117
+ * Renders nothing for files `isPreviewableFile` rejects.
118
+ */
119
+ export declare function FilePreview({ file, className, ...props }: FilePreviewProps): import("react").JSX.Element | null;
120
+ export {};