@tulipfarm/sprout 0.0.0-stage → 0.2.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 (314) 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 +82 -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-input.d.ts +94 -0
  38. package/dist/components/chat-input.js +279 -0
  39. package/dist/components/chat-plan.d.ts +21 -0
  40. package/dist/components/chat-plan.js +35 -0
  41. package/dist/components/chat-sources.d.ts +64 -0
  42. package/dist/components/chat-sources.js +66 -0
  43. package/dist/components/checkbox.d.ts +16 -0
  44. package/dist/components/checkbox.js +17 -0
  45. package/dist/components/choice-list.d.ts +53 -0
  46. package/dist/components/choice-list.js +36 -0
  47. package/dist/components/code-block.d.ts +35 -0
  48. package/dist/components/code-block.js +64 -0
  49. package/dist/components/collapsible.d.ts +24 -0
  50. package/dist/components/collapsible.js +27 -0
  51. package/dist/components/combobox.d.ts +95 -0
  52. package/dist/components/combobox.js +106 -0
  53. package/dist/components/command.d.ts +94 -0
  54. package/dist/components/command.js +414 -0
  55. package/dist/components/context-menu.d.ts +57 -0
  56. package/dist/components/context-menu.js +60 -0
  57. package/dist/components/dialog.d.ts +60 -0
  58. package/dist/components/dialog.js +79 -0
  59. package/dist/components/direction.d.ts +6 -0
  60. package/dist/components/direction.js +6 -0
  61. package/dist/components/dropdown-menu.d.ts +62 -0
  62. package/dist/components/dropdown-menu.js +59 -0
  63. package/dist/components/field.d.ts +117 -0
  64. package/dist/components/field.js +150 -0
  65. package/dist/components/file-explorer.d.ts +27 -0
  66. package/dist/components/file-explorer.js +300 -0
  67. package/dist/components/file-viewer.d.ts +137 -0
  68. package/dist/components/file-viewer.js +400 -0
  69. package/dist/components/form.d.ts +87 -0
  70. package/dist/components/form.js +55 -0
  71. package/dist/components/glass-banner.d.ts +27 -0
  72. package/dist/components/glass-banner.js +116 -0
  73. package/dist/components/gradient-banner.d.ts +37 -0
  74. package/dist/components/gradient-banner.js +43 -0
  75. package/dist/components/hover-card.d.ts +27 -0
  76. package/dist/components/hover-card.js +26 -0
  77. package/dist/components/input-group.d.ts +68 -0
  78. package/dist/components/input-group.js +88 -0
  79. package/dist/components/input-otp.d.ts +38 -0
  80. package/dist/components/input-otp.js +43 -0
  81. package/dist/components/input.d.ts +16 -0
  82. package/dist/components/input.js +18 -0
  83. package/dist/components/kbd.d.ts +12 -0
  84. package/dist/components/kbd.js +11 -0
  85. package/dist/components/label.d.ts +8 -0
  86. package/dist/components/label.js +10 -0
  87. package/dist/components/mention-list.d.ts +54 -0
  88. package/dist/components/mention-list.js +31 -0
  89. package/dist/components/menubar.d.ts +64 -0
  90. package/dist/components/menubar.js +68 -0
  91. package/dist/components/message-actions.d.ts +34 -0
  92. package/dist/components/message-actions.js +68 -0
  93. package/dist/components/message-response.d.ts +20 -0
  94. package/dist/components/message-response.js +46 -0
  95. package/dist/components/message-scroller.d.ts +71 -0
  96. package/dist/components/message-scroller.js +217 -0
  97. package/dist/components/message.d.ts +49 -0
  98. package/dist/components/message.js +59 -0
  99. package/dist/components/navigation-menu.d.ts +45 -0
  100. package/dist/components/navigation-menu.js +54 -0
  101. package/dist/components/notice-banner.d.ts +14 -0
  102. package/dist/components/notice-banner.js +11 -0
  103. package/dist/components/page-content.d.ts +7 -0
  104. package/dist/components/page-content.js +9 -0
  105. package/dist/components/page-header.d.ts +37 -0
  106. package/dist/components/page-header.js +53 -0
  107. package/dist/components/pagination.d.ts +29 -0
  108. package/dist/components/pagination.js +29 -0
  109. package/dist/components/plan-outline.d.ts +60 -0
  110. package/dist/components/plan-outline.js +108 -0
  111. package/dist/components/popover.d.ts +34 -0
  112. package/dist/components/popover.js +35 -0
  113. package/dist/components/progress.d.ts +27 -0
  114. package/dist/components/progress.js +35 -0
  115. package/dist/components/prompt-list.d.ts +23 -0
  116. package/dist/components/prompt-list.js +11 -0
  117. package/dist/components/questionnaire.d.ts +148 -0
  118. package/dist/components/questionnaire.js +1002 -0
  119. package/dist/components/radio-group.d.ts +16 -0
  120. package/dist/components/radio-group.js +21 -0
  121. package/dist/components/reasoning-effort.d.ts +24 -0
  122. package/dist/components/reasoning-effort.js +269 -0
  123. package/dist/components/resizable.d.ts +67 -0
  124. package/dist/components/resizable.js +536 -0
  125. package/dist/components/result-card.d.ts +58 -0
  126. package/dist/components/result-card.js +88 -0
  127. package/dist/components/review-card.d.ts +62 -0
  128. package/dist/components/review-card.js +49 -0
  129. package/dist/components/rich-text-editor.d.ts +51 -0
  130. package/dist/components/rich-text-editor.js +248 -0
  131. package/dist/components/schema-diagram.d.ts +52 -0
  132. package/dist/components/schema-diagram.js +226 -0
  133. package/dist/components/scroll-area.d.ts +22 -0
  134. package/dist/components/scroll-area.js +19 -0
  135. package/dist/components/search-dialog.d.ts +103 -0
  136. package/dist/components/search-dialog.js +65 -0
  137. package/dist/components/search-field.d.ts +17 -0
  138. package/dist/components/search-field.js +27 -0
  139. package/dist/components/select.d.ts +57 -0
  140. package/dist/components/select.js +57 -0
  141. package/dist/components/selection-slot.d.ts +18 -0
  142. package/dist/components/selection-slot.js +53 -0
  143. package/dist/components/separator.d.ts +48 -0
  144. package/dist/components/separator.js +54 -0
  145. package/dist/components/settings-list.d.ts +26 -0
  146. package/dist/components/settings-list.js +17 -0
  147. package/dist/components/sheet.d.ts +70 -0
  148. package/dist/components/sheet.js +77 -0
  149. package/dist/components/sidebar.d.ts +70 -0
  150. package/dist/components/sidebar.js +187 -0
  151. package/dist/components/skeleton.d.ts +31 -0
  152. package/dist/components/skeleton.js +32 -0
  153. package/dist/components/slider.d.ts +17 -0
  154. package/dist/components/slider.js +24 -0
  155. package/dist/components/spinner.d.ts +37 -0
  156. package/dist/components/spinner.js +43 -0
  157. package/dist/components/state-panel-samples.d.ts +25 -0
  158. package/dist/components/state-panel-samples.js +423 -0
  159. package/dist/components/state-panel.d.ts +35 -0
  160. package/dist/components/state-panel.js +29 -0
  161. package/dist/components/state-sample.d.ts +63 -0
  162. package/dist/components/state-sample.js +42 -0
  163. package/dist/components/switch.d.ts +12 -0
  164. package/dist/components/switch.js +14 -0
  165. package/dist/components/table-nuqs.d.ts +16 -0
  166. package/dist/components/table-nuqs.js +59 -0
  167. package/dist/components/table.d.ts +120 -0
  168. package/dist/components/table.js +663 -0
  169. package/dist/components/tabs.d.ts +37 -0
  170. package/dist/components/tabs.js +36 -0
  171. package/dist/components/textarea.d.ts +18 -0
  172. package/dist/components/textarea.js +19 -0
  173. package/dist/components/toast.d.ts +45 -0
  174. package/dist/components/toast.js +83 -0
  175. package/dist/components/toggle-group.d.ts +30 -0
  176. package/dist/components/toggle-group.js +39 -0
  177. package/dist/components/toggle.d.ts +27 -0
  178. package/dist/components/toggle.js +21 -0
  179. package/dist/components/tool-activity.d.ts +79 -0
  180. package/dist/components/tool-activity.js +226 -0
  181. package/dist/components/toolbar-status.d.ts +21 -0
  182. package/dist/components/toolbar-status.js +14 -0
  183. package/dist/components/tooltip.d.ts +31 -0
  184. package/dist/components/tooltip.js +99 -0
  185. package/dist/components/typed-text.d.ts +17 -0
  186. package/dist/components/typed-text.js +56 -0
  187. package/dist/index.d.ts +90 -0
  188. package/dist/index.js +90 -0
  189. package/dist/internal/brand-glyphs.d.ts +370 -0
  190. package/dist/internal/brand-glyphs.js +262 -0
  191. package/dist/internal/classes.d.ts +3 -0
  192. package/dist/internal/classes.js +20 -0
  193. package/dist/internal/code-tokens.d.ts +4 -0
  194. package/dist/internal/code-tokens.js +34 -0
  195. package/dist/internal/fieldset.d.ts +6 -0
  196. package/dist/internal/fieldset.js +38 -0
  197. package/dist/internal/file-kind.d.ts +4 -0
  198. package/dist/internal/file-kind.js +62 -0
  199. package/dist/internal/languages.d.ts +7 -0
  200. package/dist/internal/languages.js +1010 -0
  201. package/dist/internal/message-scroller.d.ts +102 -0
  202. package/dist/internal/message-scroller.js +637 -0
  203. package/dist/internal/pressable.d.ts +2 -0
  204. package/dist/internal/pressable.js +29 -0
  205. package/dist/internal/syntax.d.ts +14 -0
  206. package/dist/internal/syntax.js +137 -0
  207. package/dist/styles/accordion.css +102 -0
  208. package/dist/styles/alert-dialog.css +198 -0
  209. package/dist/styles/alert.css +149 -0
  210. package/dist/styles/aspect-ratio.css +8 -0
  211. package/dist/styles/attachment.css +700 -0
  212. package/dist/styles/avatar.css +186 -0
  213. package/dist/styles/badge.css +178 -0
  214. package/dist/styles/brand-icon.css +104 -0
  215. package/dist/styles/breadcrumb.css +121 -0
  216. package/dist/styles/button-group.css +113 -0
  217. package/dist/styles/button.css +380 -0
  218. package/dist/styles/calendar.css +295 -0
  219. package/dist/styles/canvas.css +313 -0
  220. package/dist/styles/card.css +146 -0
  221. package/dist/styles/carousel.css +107 -0
  222. package/dist/styles/chart.css +227 -0
  223. package/dist/styles/chat-confirmation.css +29 -0
  224. package/dist/styles/chat-input.css +240 -0
  225. package/dist/styles/chat-plan.css +109 -0
  226. package/dist/styles/chat-sources.css +191 -0
  227. package/dist/styles/checkbox.css +122 -0
  228. package/dist/styles/choice-list.css +343 -0
  229. package/dist/styles/code-block.css +211 -0
  230. package/dist/styles/collapsible.css +72 -0
  231. package/dist/styles/combobox.css +347 -0
  232. package/dist/styles/command.css +233 -0
  233. package/dist/styles/context-menu.css +151 -0
  234. package/dist/styles/dialog.css +237 -0
  235. package/dist/styles/dropdown-menu.css +150 -0
  236. package/dist/styles/field.css +340 -0
  237. package/dist/styles/file-explorer.css +517 -0
  238. package/dist/styles/file-viewer.css +375 -0
  239. package/dist/styles/form.css +155 -0
  240. package/dist/styles/glass-banner.css +308 -0
  241. package/dist/styles/gradient-banner.css +256 -0
  242. package/dist/styles/hover-card.css +95 -0
  243. package/dist/styles/index.css +268 -0
  244. package/dist/styles/input-group.css +285 -0
  245. package/dist/styles/input-otp.css +138 -0
  246. package/dist/styles/input.css +98 -0
  247. package/dist/styles/kbd.css +59 -0
  248. package/dist/styles/label.css +89 -0
  249. package/dist/styles/mention-list.css +166 -0
  250. package/dist/styles/menubar.css +226 -0
  251. package/dist/styles/message-actions.css +83 -0
  252. package/dist/styles/message-response.css +176 -0
  253. package/dist/styles/message-scroller.css +136 -0
  254. package/dist/styles/message.css +310 -0
  255. package/dist/styles/navigation-menu.css +291 -0
  256. package/dist/styles/notice-banner.css +68 -0
  257. package/dist/styles/page-content.css +21 -0
  258. package/dist/styles/page-header.css +156 -0
  259. package/dist/styles/pagination.css +72 -0
  260. package/dist/styles/plan-outline.css +393 -0
  261. package/dist/styles/popover.css +140 -0
  262. package/dist/styles/progress.css +93 -0
  263. package/dist/styles/prompt-list.css +165 -0
  264. package/dist/styles/questionnaire.css +308 -0
  265. package/dist/styles/radio-group.css +119 -0
  266. package/dist/styles/reasoning-effort.css +157 -0
  267. package/dist/styles/resizable.css +108 -0
  268. package/dist/styles/result-card.css +215 -0
  269. package/dist/styles/review-card.css +235 -0
  270. package/dist/styles/rich-text-editor.css +169 -0
  271. package/dist/styles/schema-diagram.css +419 -0
  272. package/dist/styles/scroll-area.css +77 -0
  273. package/dist/styles/search-dialog.css +280 -0
  274. package/dist/styles/search-field.css +17 -0
  275. package/dist/styles/select.css +285 -0
  276. package/dist/styles/selection-slot.css +31 -0
  277. package/dist/styles/separator.css +206 -0
  278. package/dist/styles/settings-list.css +81 -0
  279. package/dist/styles/sheet.css +361 -0
  280. package/dist/styles/sidebar.css +363 -0
  281. package/dist/styles/skeleton.css +80 -0
  282. package/dist/styles/slider.css +142 -0
  283. package/dist/styles/spinner.css +39 -0
  284. package/dist/styles/state-panel-samples.css +41 -0
  285. package/dist/styles/state-panel.css +173 -0
  286. package/dist/styles/state-sample.css +285 -0
  287. package/dist/styles/switch.css +128 -0
  288. package/dist/styles/table.css +604 -0
  289. package/dist/styles/tabs.css +223 -0
  290. package/dist/styles/textarea.css +77 -0
  291. package/dist/styles/themes/chatgpt.css +125 -0
  292. package/dist/styles/themes/claude.css +125 -0
  293. package/dist/styles/themes/cloudflare.css +125 -0
  294. package/dist/styles/themes/discord.css +125 -0
  295. package/dist/styles/themes/github.css +125 -0
  296. package/dist/styles/themes/grok.css +125 -0
  297. package/dist/styles/themes/linear.css +126 -0
  298. package/dist/styles/themes/neutral.css +125 -0
  299. package/dist/styles/themes/notion.css +125 -0
  300. package/dist/styles/themes/perplexity.css +125 -0
  301. package/dist/styles/themes/raycast.css +125 -0
  302. package/dist/styles/themes/spotify.css +125 -0
  303. package/dist/styles/themes/stripe.css +125 -0
  304. package/dist/styles/themes/supabase.css +125 -0
  305. package/dist/styles/themes/tulipfarm.css +115 -0
  306. package/dist/styles/themes/vercel.css +126 -0
  307. package/dist/styles/toast.css +197 -0
  308. package/dist/styles/toggle-group.css +161 -0
  309. package/dist/styles/toggle.css +119 -0
  310. package/dist/styles/tool-activity.css +396 -0
  311. package/dist/styles/toolbar-status.css +52 -0
  312. package/dist/styles/tooltip.css +122 -0
  313. package/dist/styles/typed-text.css +17 -0
  314. package/package.json +452 -4
@@ -0,0 +1,285 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { Children, createContext, useCallback, useContext, useEffect, useId, useMemo, useRef, useState, } from "react";
4
+ import { mergeProps } from "@base-ui/react/merge-props";
5
+ import { useRender } from "@base-ui/react/use-render";
6
+ import { ChevronLeft } from "reicon-react/icons/ChevronLeft";
7
+ import { ChevronRight } from "reicon-react/icons/ChevronRight";
8
+ import { Image } from "reicon-react/icons/Image";
9
+ import { Upload } from "reicon-react/icons/Upload";
10
+ import { X } from "reicon-react/icons/X";
11
+ import { cn } from "../internal/classes.js";
12
+ import { defaultFileAccept, fileKind, formatFileSize, } from "../internal/file-kind.js";
13
+ import { Button } from "./button.js";
14
+ import { FilePreview, FileViewer, isPreviewableFile, } from "./file-viewer.js";
15
+ import { HoverCard, HoverCardContent, HoverCardTrigger } from "./hover-card.js";
16
+ import { Spinner } from "./spinner.js";
17
+ export const attachmentStateNames = [
18
+ "idle",
19
+ "uploading",
20
+ "processing",
21
+ "error",
22
+ "done",
23
+ ];
24
+ export const attachmentSizeNames = ["default", "sm", "xs"];
25
+ export const attachmentOrientationNames = ["horizontal", "vertical"];
26
+ export const attachmentMediaVariantNames = ["icon", "image"];
27
+ export const attachmentGroupVariantNames = [
28
+ "carousel",
29
+ "grid",
30
+ "inline",
31
+ "list",
32
+ ];
33
+ export const fileAttachmentVariantNames = [
34
+ "list",
35
+ "grid",
36
+ "inline",
37
+ "chip",
38
+ ];
39
+ export const fileAttachmentStateNames = [
40
+ "ready",
41
+ "uploading",
42
+ "processing",
43
+ "error",
44
+ ];
45
+ export const fileTypeIconSizeNames = ["sm", "lg"];
46
+ /** A file card built from media, content, and actions. */
47
+ export function Attachment({ className, state = "done", size = "default", orientation = "horizontal", ...props }) {
48
+ return (_jsx("div", { "data-slot": "attachment", "data-state": state, "data-size": size, "data-orientation": orientation, className: cn("sprout-attachment", `sprout-attachment-size-${size}`, `sprout-attachment-${orientation}`, className), ...props }));
49
+ }
50
+ export function AttachmentMedia({ className, variant = "icon", ...props }) {
51
+ return (_jsx("div", { "data-slot": "attachment-media", "data-variant": variant, className: cn("sprout-attachment-media", className), ...props }));
52
+ }
53
+ export function AttachmentContent({ className, ...props }) {
54
+ return (_jsx("div", { "data-slot": "attachment-content", className: cn("sprout-attachment-content", className), ...props }));
55
+ }
56
+ /** A single-line name. It shimmers while the attachment uploads or processes. */
57
+ export function AttachmentTitle({ className, ...props }) {
58
+ return (_jsx("span", { "data-slot": "attachment-title", className: cn("sprout-attachment-title", className), ...props }));
59
+ }
60
+ export function AttachmentDescription({ className, ...props }) {
61
+ return (_jsx("span", { "data-slot": "attachment-description", className: cn("sprout-attachment-description", className), ...props }));
62
+ }
63
+ /** Sits above the trigger. Vertical attachments float it over the media corner. */
64
+ export function AttachmentActions({ className, ...props }) {
65
+ return (_jsx("div", { "data-slot": "attachment-actions", className: cn("sprout-attachment-actions", className), ...props }));
66
+ }
67
+ /** A ghost `icon-xs` Button. Give icon-only actions an `aria-label`. */
68
+ export function AttachmentAction({ variant, size = "icon-xs", ...props }) {
69
+ return (_jsx(Button, { "data-slot": "attachment-action", variant: variant ?? "ghost", size: size, ...props }));
70
+ }
71
+ /** Stretches over the whole attachment so a click anywhere opens it. Name it with `aria-label`. */
72
+ export function AttachmentTrigger({ className, render, type, ...props }) {
73
+ return useRender({
74
+ defaultTagName: "button",
75
+ render,
76
+ props: mergeProps({
77
+ type: render ? type : (type ?? "button"),
78
+ className: cn("sprout-attachment-trigger", className),
79
+ }, { "data-slot": "attachment-trigger" }, props),
80
+ });
81
+ }
82
+ const SharedViewerContext = createContext(null);
83
+ const byDocumentOrder = (a, b) => a.node &&
84
+ b.node &&
85
+ a.node.compareDocumentPosition(b.node) & Node.DOCUMENT_POSITION_PRECEDING
86
+ ? 1
87
+ : -1;
88
+ /** One FileViewer for every viewable attachment in a group, stepping through them in page order. */
89
+ function SharedFileViewer({ children }) {
90
+ const entries = useRef(new Map());
91
+ const [set, setSet] = useState(null);
92
+ const [open, setOpen] = useState(false);
93
+ const shared = useMemo(() => ({
94
+ register(id, entry) {
95
+ entries.current.set(id, entry);
96
+ return () => entries.current.delete(id);
97
+ },
98
+ open(id) {
99
+ const ordered = [...entries.current]
100
+ .map(([key, entry]) => ({
101
+ id: key,
102
+ file: entry.file(),
103
+ node: entry.node(),
104
+ }))
105
+ .filter((item) => item.file !== null)
106
+ .sort(byDocumentOrder);
107
+ const index = ordered.findIndex((item) => item.id === id);
108
+ if (index < 0)
109
+ return;
110
+ setSet({
111
+ ids: ordered.map((item) => item.id),
112
+ files: ordered.map((item) => item.file),
113
+ index,
114
+ });
115
+ setOpen(true);
116
+ },
117
+ }), []);
118
+ const current = set && entries.current.get(set.ids[set.index] ?? "");
119
+ return (_jsxs(SharedViewerContext.Provider, { value: shared, children: [children, set && (_jsx(FileViewer, { files: set.files, index: set.index, onIndexChange: (index) => setSet({ ...set, index }), open: open, onOpenChange: setOpen, finalFocus: () => current
120
+ ?.node()
121
+ ?.querySelector("button.sprout-file-attachment-open") ?? true }))] }));
122
+ }
123
+ export function AttachmentGroup(props) {
124
+ return (_jsx(SharedFileViewer, { children: _jsx(AttachmentGroupFrame, { ...props }) }));
125
+ }
126
+ function AttachmentGroupFrame({ className, variant = "carousel", children, ...props }) {
127
+ if (variant === "carousel")
128
+ return (_jsx(AttachmentCarousel, { className: className, ...props, children: children }));
129
+ return (_jsx("div", { "data-slot": "attachment-group", "data-variant": variant, role: props["aria-label"] || props["aria-labelledby"] ? "group" : undefined, className: cn("sprout-attachment-group", `sprout-attachment-group-${variant}`, className), ...props, children: children }));
130
+ }
131
+ const typing = 'input, textarea, select, [contenteditable="true"]';
132
+ function AttachmentCarousel({ className, children, onKeyDownCapture, ...props }) {
133
+ const viewport = useRef(null);
134
+ const [edges, setEdges] = useState({ start: false, end: false });
135
+ const measure = useCallback(() => {
136
+ const node = viewport.current;
137
+ if (!node)
138
+ return;
139
+ const max = node.scrollWidth - node.clientWidth;
140
+ const start = node.scrollLeft > 1;
141
+ const end = node.scrollLeft < max - 1;
142
+ setEdges((current) => current.start === start && current.end === end ? current : { start, end });
143
+ }, []);
144
+ useEffect(() => {
145
+ const node = viewport.current;
146
+ if (!node)
147
+ return;
148
+ measure();
149
+ const observer = new ResizeObserver(measure);
150
+ observer.observe(node);
151
+ if (node.firstElementChild)
152
+ observer.observe(node.firstElementChild);
153
+ return () => observer.disconnect();
154
+ }, [measure]);
155
+ const scroll = (direction) => {
156
+ const node = viewport.current;
157
+ if (node)
158
+ node.scrollBy({ left: direction * node.clientWidth * 0.8 });
159
+ };
160
+ const handleKeyDown = (event) => {
161
+ onKeyDownCapture?.(event);
162
+ if (event.defaultPrevented)
163
+ return;
164
+ if (event.target.closest(typing))
165
+ return;
166
+ if (event.key === "ArrowLeft" || event.key === "ArrowRight") {
167
+ event.preventDefault();
168
+ scroll(event.key === "ArrowLeft" ? -1 : 1);
169
+ }
170
+ };
171
+ return (_jsxs("div", { "data-slot": "attachment-group", "data-variant": "carousel", role: "region", "aria-roledescription": "carousel", className: cn("sprout-attachment-group", "sprout-attachment-group-carousel", className), onKeyDownCapture: handleKeyDown, ...props, children: [_jsx("div", { ref: viewport, className: "sprout-attachment-carousel-viewport", onScroll: measure, children: _jsx("div", { className: "sprout-attachment-carousel-track", children: Children.map(children, (child) => child == null || child === false ? null : (_jsx("div", { role: "group", "aria-roledescription": "slide", className: "sprout-attachment-carousel-item", children: child }))) }) }), edges.start && (_jsx("span", { className: "sprout-attachment-carousel-edge", "data-side": "start", children: _jsx(Button, { variant: "outline", size: "icon-xs", "aria-label": "Previous attachments", tabIndex: -1, className: "sprout-attachment-carousel-arrow", onClick: () => scroll(-1), children: _jsx(ChevronLeft, { "aria-hidden": "true" }) }) })), edges.end && (_jsx("span", { className: "sprout-attachment-carousel-edge", "data-side": "end", children: _jsx(Button, { variant: "outline", size: "icon-xs", "aria-label": "Next attachments", tabIndex: -1, className: "sprout-attachment-carousel-arrow", onClick: () => scroll(1), children: _jsx(ChevronRight, { "aria-hidden": "true" }) }) }))] }));
172
+ }
173
+ /** A paper glyph with a colored extension badge, such as PDF or XLSX. Decorative. */
174
+ export function FileTypeIcon({ name, mediaType, size = "sm", className, ...props }) {
175
+ const label = name.includes(".")
176
+ ? (name.split(".").at(-1) ?? "").toUpperCase().slice(0, 4)
177
+ : "";
178
+ const badgeWidth = label.length > 3 ? 13 : 11;
179
+ return (_jsxs("svg", { viewBox: "0 0 20 24", "aria-hidden": "true", focusable: "false", "data-slot": "file-type-icon", "data-size": size, "data-kind": fileKind(name, mediaType), className: cn("sprout-file-type-icon", `sprout-file-type-icon-size-${size}`, className), ...props, children: [_jsx("path", { d: "M3.5 1.5h9l4.5 4.5v16a.5.5 0 0 1-.5.5h-13a.5.5 0 0 1-.5-.5v-20a.5.5 0 0 1 .5-.5Z", className: "sprout-file-type-icon-paper", strokeLinejoin: "round" }), _jsx("path", { d: "M12.5 1.5v4a.5.5 0 0 0 .5.5h4", className: "sprout-file-type-icon-fold", strokeLinejoin: "round" }), _jsx("path", { d: "M6 15h8M6 17.5h8M6 20h5", className: "sprout-file-type-icon-lines", strokeLinecap: "round" }), label && (_jsxs(_Fragment, { children: [_jsx("rect", { x: "1", y: "6", width: badgeWidth, height: "6", rx: "1.5", className: "sprout-file-type-icon-badge" }), _jsx("text", { x: 1 + badgeWidth / 2, y: "10.4", textAnchor: "middle", fontSize: "4.2", fontWeight: "700", className: "sprout-file-type-icon-label", children: label })] }))] }));
180
+ }
181
+ function AttachmentImage({ src, name }) {
182
+ const [failed, setFailed] = useState(false);
183
+ return failed ? (_jsxs("span", { className: "sprout-attachment-image-failed", children: [_jsx(Image, { size: 16, "aria-hidden": "true" }), "Image unavailable"] })) : (_jsx("img", { src: src, alt: name, onError: () => setFailed(true), className: "sprout-attachment-image" }));
184
+ }
185
+ function viewableFile(file) {
186
+ const source = file.source ??
187
+ (file.url ? { kind: "remote", url: file.url } : null);
188
+ return source && { name: file.name, mediaType: file.mediaType, source };
189
+ }
190
+ function stateLabelFor(file) {
191
+ return file.state === "ready"
192
+ ? file.size
193
+ : file.state === "error"
194
+ ? "Upload failed"
195
+ : file.state === "uploading"
196
+ ? "Uploading…"
197
+ : "Processing…";
198
+ }
199
+ /** A ready-made file row, card, inline mention, or chip with upload states, retry, and remove. */
200
+ export function FileAttachment({ file, variant = "list", onRemove, onRetry, onOpen, viewable = false, preview = false, actionLabel = "Inspect", className, }) {
201
+ const [open, setOpen] = useState(false);
202
+ const shared = useContext(SharedViewerContext);
203
+ const id = useId();
204
+ const root = useRef(null);
205
+ const image = fileKind(file.name, file.mediaType) === "image";
206
+ const busy = file.state === "uploading" || file.state === "processing";
207
+ const stateLabel = stateLabelFor(file);
208
+ const target = viewable || preview ? viewableFile(file) : null;
209
+ const inViewer = !onOpen && viewable && target !== null;
210
+ const openable = !!onOpen || inViewer;
211
+ const peek = preview &&
212
+ target !== null &&
213
+ file.state !== "error" &&
214
+ isPreviewableFile(target);
215
+ const latest = useRef(target);
216
+ latest.current = inViewer ? target : null;
217
+ useEffect(() => shared && inViewer
218
+ ? shared.register(id, {
219
+ file: () => latest.current,
220
+ node: () => root.current,
221
+ })
222
+ : undefined, [shared, inViewer, id]);
223
+ const withPreview = (trigger) => peek ? (_jsxs(HoverCard, { children: [_jsx(HoverCardTrigger, { delay: 400, closeDelay: 150, render: trigger }), _jsx(HoverCardContent, { side: "top", align: "start", className: "sprout-file-attachment-peek", children: _jsx(FilePreview, { file: target }) })] })) : (trigger);
224
+ const openLabel = `${actionLabel} ${file.name}`;
225
+ const openProps = {
226
+ type: "button",
227
+ disabled: !!onOpen && busy,
228
+ onClick: () => onOpen ? onOpen() : shared ? shared.open(id) : setOpen(true),
229
+ };
230
+ const retry = file.state === "error" && onRetry && (_jsx(Button, { variant: "ghost", size: "sm", onClick: onRetry, "aria-label": `Retry ${file.name}`, children: "Retry" }));
231
+ const remove = (size) => onRemove && (_jsx(Button, { variant: "ghost", size: size, "aria-label": `Remove ${file.name}`, onClick: onRemove, children: _jsx(X, { size: 14, "aria-hidden": "true" }) }));
232
+ const viewer = inViewer && !shared && (_jsx(FileViewer, { file: target, open: open, onOpenChange: setOpen }));
233
+ if (variant === "chip") {
234
+ const inner = (_jsxs(_Fragment, { children: [image && file.url ? (_jsx("span", { className: "sprout-file-attachment-thumb", children: _jsx(AttachmentImage, { src: file.url, name: file.name }, file.url) })) : (_jsx(FileTypeIcon, { name: file.name, mediaType: file.mediaType })), _jsx("span", { className: "sprout-file-attachment-name", children: file.name })] }));
235
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { ref: root, "data-slot": "file-attachment", "data-variant": "chip", "data-state": file.state, "data-removable": onRemove ? "" : undefined, className: cn("sprout-file-attachment", className), title: openable ? undefined : `${file.name} · ${stateLabel}`, children: [withPreview(openable ? (_jsx("button", { ...openProps, "aria-label": openLabel, title: peek ? undefined : `${file.name} · ${stateLabel}`, className: "sprout-file-attachment-open", children: inner })) : (_jsx("span", { className: "sprout-file-attachment-open", children: inner }))), busy && _jsx(Spinner, { "aria-label": stateLabel }), retry, remove("icon-xs")] }), viewer] }));
236
+ }
237
+ const name = (_jsxs(_Fragment, { children: [_jsx("span", { className: "sprout-file-attachment-name", title: file.name, children: file.name }), variant !== "inline" && (_jsxs("span", { className: "sprout-file-attachment-status", children: [busy && _jsx(Spinner, { size: "sm", "aria-hidden": "true" }), stateLabel] }))] }));
238
+ const thumbnail = image && file.url ? (_jsx(AttachmentImage, { src: file.url, name: file.name }, file.url)) : (_jsx(FileTypeIcon, { name: file.name, mediaType: file.mediaType, size: "lg" }));
239
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { ref: root, "data-slot": "file-attachment", "data-variant": variant, "data-state": file.state, className: cn("sprout-file-attachment", className), children: [variant === "grid" &&
240
+ (openable ? (_jsx("button", { ...openProps, tabIndex: -1, "aria-hidden": "true", className: "sprout-file-attachment-preview", children: thumbnail })) : (_jsx("span", { className: "sprout-file-attachment-preview", children: thumbnail }))), variant !== "grid" && (_jsx("span", { className: "sprout-file-attachment-media", children: image && file.url && variant === "list" ? (_jsx(AttachmentImage, { src: file.url, name: file.name }, file.url)) : (_jsx(FileTypeIcon, { name: file.name, mediaType: file.mediaType })) })), withPreview(openable ? (_jsx("button", { ...openProps, "aria-label": openLabel, className: "sprout-file-attachment-open", children: name })) : (_jsx("span", { className: "sprout-file-attachment-open", children: name }))), variant === "inline" && busy && _jsx(Spinner, { "aria-label": stateLabel }), variant === "inline" && file.state === "error" && (_jsx("span", { className: "sprout-file-attachment-failed", children: "Failed" })), (retry || onRemove) && (_jsxs("div", { className: "sprout-file-attachment-actions", children: [retry, remove("icon-sm")] }))] }), viewer] }));
241
+ }
242
+ /** A dashed drop target with a “Choose files” button. Files are handed to `onFiles`; nothing is uploaded. */
243
+ export function AttachmentDropzone({ onFiles, disabled = false, accept = defaultFileAccept, className, }) {
244
+ const [dragging, setDragging] = useState(false);
245
+ const input = useRef(null);
246
+ const over = (event) => {
247
+ event.preventDefault();
248
+ event.dataTransfer.dropEffect = disabled ? "none" : "copy";
249
+ if (!disabled)
250
+ setDragging(true);
251
+ };
252
+ return (_jsxs("div", { "data-slot": "attachment-dropzone", "data-dragging": dragging ? "" : undefined, "data-disabled": disabled ? "" : undefined, className: cn("sprout-attachment-dropzone", className), onDragEnter: over, onDragOver: over, onDragLeave: (event) => {
253
+ if (!event.currentTarget.contains(event.relatedTarget))
254
+ setDragging(false);
255
+ }, onDrop: (event) => {
256
+ event.preventDefault();
257
+ setDragging(false);
258
+ if (!disabled)
259
+ onFiles(Array.from(event.dataTransfer.files));
260
+ }, children: [_jsx("input", { ref: input, type: "file", accept: accept, multiple: true, hidden: true, disabled: disabled, onChange: (event) => {
261
+ onFiles(Array.from(event.target.files ?? []));
262
+ event.target.value = "";
263
+ } }), _jsx(Upload, { size: 20, "aria-hidden": "true", className: "sprout-attachment-dropzone-icon" }), _jsx("p", { className: "sprout-attachment-dropzone-text", children: "Drop files here, or choose them from your device." }), _jsx(Button, { variant: "outline", disabled: disabled, onClick: () => input.current?.click(), children: "Choose files" })] }));
264
+ }
265
+ /** A chip for a `File` still in browser memory, with a live image preview. */
266
+ export function LocalFileAttachment({ file, onRemove, onOpen, viewable, preview, }) {
267
+ const [url, setUrl] = useState();
268
+ const source = useMemo(() => ({ kind: "local", file }), [file]);
269
+ useEffect(() => {
270
+ if (fileKind(file.name, file.type) !== "image")
271
+ return;
272
+ const next = URL.createObjectURL(file);
273
+ setUrl(next);
274
+ return () => URL.revokeObjectURL(next);
275
+ }, [file]);
276
+ return (_jsx(FileAttachment, { variant: "chip", file: {
277
+ id: `${file.name}-${file.lastModified}`,
278
+ name: file.name,
279
+ mediaType: file.type,
280
+ size: formatFileSize(file.size),
281
+ state: "ready",
282
+ source,
283
+ url,
284
+ }, onRemove: onRemove, onOpen: onOpen, viewable: viewable, preview: preview }));
285
+ }
@@ -0,0 +1,32 @@
1
+ import type { ComponentProps } from "react";
2
+ import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar";
3
+ export type AvatarSize = "xs" | "sm" | "default" | "lg";
4
+ export type EntityAvatarSize = AvatarSize | "xl";
5
+ export type EntityAvatarShape = "circle" | "square";
6
+ export interface AvatarProps extends AvatarPrimitive.Root.Props {
7
+ size?: AvatarSize;
8
+ }
9
+ export declare function Avatar({ className, size, ...props }: AvatarProps): import("react").JSX.Element;
10
+ export type AvatarImageProps = AvatarPrimitive.Image.Props;
11
+ export declare function AvatarImage({ className, ...props }: AvatarImageProps): import("react").JSX.Element;
12
+ export type AvatarFallbackProps = AvatarPrimitive.Fallback.Props;
13
+ export declare function AvatarFallback({ className, ...props }: AvatarFallbackProps): import("react").JSX.Element;
14
+ export declare function AvatarBadge({ className, ...props }: ComponentProps<"span">): import("react").JSX.Element;
15
+ export declare function AvatarGroup({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
16
+ export declare function AvatarGroupCount({ className, ...props }: ComponentProps<"div">): import("react").JSX.Element;
17
+ export declare function agentAvatarSrc(agentId: string, baseUrl?: string): string;
18
+ export interface AgentAvatarProps extends Omit<AvatarProps, "children"> {
19
+ agentId: string;
20
+ name: string;
21
+ /** Overrides the artwork derived from `agentId`. */
22
+ src?: string | undefined;
23
+ }
24
+ export declare function AgentAvatar({ agentId, name, src, ...props }: AgentAvatarProps): import("react").JSX.Element;
25
+ export interface EntityAvatarProps extends Omit<AvatarPrimitive.Root.Props, "children"> {
26
+ seed: string;
27
+ name: string;
28
+ image?: string | null | undefined;
29
+ size?: EntityAvatarSize;
30
+ shape?: EntityAvatarShape;
31
+ }
32
+ export declare function EntityAvatar({ seed, name, image, size, shape, className, ...props }: EntityAvatarProps): import("react").JSX.Element;
@@ -0,0 +1,73 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar";
4
+ import { cn, stateClassName } from "../internal/classes.js";
5
+ export function Avatar({ className, size = "default", ...props }) {
6
+ return (_jsx(AvatarPrimitive.Root, { "data-slot": "avatar", "data-size": size, ...props, className: stateClassName("sprout-avatar", className) }));
7
+ }
8
+ export function AvatarImage({ className, ...props }) {
9
+ return (_jsx(AvatarPrimitive.Image, { "data-slot": "avatar-image", ...props, className: stateClassName("sprout-avatar-image", className) }));
10
+ }
11
+ export function AvatarFallback({ className, ...props }) {
12
+ return (_jsx(AvatarPrimitive.Fallback, { "data-slot": "avatar-fallback", ...props, className: stateClassName("sprout-avatar-fallback", className) }));
13
+ }
14
+ export function AvatarBadge({ className, ...props }) {
15
+ return (_jsx("span", { "data-slot": "avatar-badge", ...props, className: cn("sprout-avatar-badge", className) }));
16
+ }
17
+ export function AvatarGroup({ className, ...props }) {
18
+ return (_jsx("div", { "data-slot": "avatar-group", ...props, className: cn("sprout-avatar-group", className) }));
19
+ }
20
+ export function AvatarGroupCount({ className, ...props }) {
21
+ return (_jsx("div", { "data-slot": "avatar-group-count", ...props, className: cn("sprout-avatar-group-count", className) }));
22
+ }
23
+ // FNV-1a: small, stable, and spreads similar ids apart.
24
+ function hash(value) {
25
+ let h = 0x811c9dc5;
26
+ for (let i = 0; i < value.length; i++) {
27
+ h ^= value.charCodeAt(i);
28
+ h = Math.imul(h, 0x01000193);
29
+ }
30
+ return h >>> 0;
31
+ }
32
+ // Frozen order: any edit, even appending, changes existing agent avatars.
33
+ // prettier-ignore
34
+ const agentObjects = [
35
+ "tulip", "tulip-bouquet", "cactus", "sunflower", "daisy", "sprout", "bonsai", "monstera", "fern",
36
+ "lavender", "rose", "poppy", "daffodil", "lily", "bellflower", "eucalyptus", "ivy", "succulent",
37
+ "acorn", "pinecone", "watering-can", "hand-trowel", "garden-fork", "pruning-shears",
38
+ "gardening-gloves", "rain-boots", "wheelbarrow", "seed-packet", "flower-pot", "plant-mister",
39
+ "spade", "rake", "hoe", "garden-hose", "seed-tray", "garden-apron", "plant-label", "twine-spool",
40
+ "compost-bin", "pruning-saw", "mushroom", "strawberry", "carrot", "pumpkin", "apple", "pear",
41
+ "lemon", "corn-cob", "honey-jar", "harvest-basket", "windmill", "barn", "tractor", "wheat",
42
+ "pea-pod", "beetroot", "radish", "eggplant", "cherries", "hay-bale", "umbrella", "mug", "teapot",
43
+ "moka-pot", "lantern", "candle", "picnic-basket", "straw-hat", "vase", "jam-jar", "birdhouse",
44
+ "rocking-chair", "kettle", "bread-loaf", "croissant", "milk-bottle", "cookie", "oven-mitt",
45
+ "thermos", "yarn-ball", "notebook", "pencil", "paintbrush", "paint-palette", "fountain-pen",
46
+ "camera", "headphones", "desk-lamp", "book-stack", "alarm-clock", "scissors", "ruler", "stapler",
47
+ "paperclip", "binder-clip", "tape-dispenser", "magnifying-glass", "envelope", "typewriter",
48
+ "globe",
49
+ ];
50
+ // prettier-ignore
51
+ const agentColors = ["pink", "coral", "orange", "yellow", "green", "teal", "blue", "purple"];
52
+ export function agentAvatarSrc(agentId, baseUrl = "https://avatars.tulipfarm.ai/avatar") {
53
+ const h = hash(agentId);
54
+ const object = agentObjects[h % agentObjects.length];
55
+ const color = agentColors[(h >>> 16) % agentColors.length];
56
+ return `${baseUrl}/${object}/${color}.svg`;
57
+ }
58
+ function initial(name) {
59
+ return name.trim().charAt(0).toUpperCase() || "?";
60
+ }
61
+ export function AgentAvatar({ agentId, name, src, ...props }) {
62
+ return (_jsxs(Avatar, { "data-agent-avatar": "", ...props, children: [_jsx(AvatarImage, { src: src ?? agentAvatarSrc(agentId), alt: "" }), _jsx(AvatarFallback, { children: initial(name) })] }));
63
+ }
64
+ // Same seed, same gradient: the fallback never changes between visits.
65
+ function gradientFor(seed) {
66
+ const h = hash(seed);
67
+ const from = h % 360;
68
+ const to = (from + 40 + ((h >>> 9) % 60)) % 360;
69
+ return `linear-gradient(135deg, oklch(0.62 0.15 ${from}), oklch(0.5 0.15 ${to}))`;
70
+ }
71
+ export function EntityAvatar({ seed, name, image, size = "default", shape = "circle", className, ...props }) {
72
+ return (_jsxs(AvatarPrimitive.Root, { "data-slot": "entity-avatar", "data-size": size, "data-shape": shape, ...props, className: stateClassName("sprout-entity-avatar", className), children: [image && (_jsx(AvatarPrimitive.Image, { src: image, alt: "", referrerPolicy: "no-referrer", className: "sprout-avatar-image" })), _jsx(AvatarPrimitive.Fallback, { className: "sprout-entity-avatar-fallback", style: { backgroundImage: gradientFor(seed) }, children: initial(name) })] }));
73
+ }
@@ -0,0 +1,21 @@
1
+ import { useRender } from "@base-ui/react/use-render";
2
+ export declare const badgeVariantNames: readonly ["default", "success", "warning", "info", "secondary", "destructive", "outline", "ghost", "link"];
3
+ export declare const badgeSizeNames: readonly ["default", "chip"];
4
+ export type BadgeVariant = (typeof badgeVariantNames)[number];
5
+ export type BadgeSize = (typeof badgeSizeNames)[number];
6
+ export interface BadgeVariantOptions {
7
+ variant?: BadgeVariant | null;
8
+ size?: BadgeSize | null;
9
+ className?: string;
10
+ }
11
+ export declare function badgeVariants({ variant, size, className, }?: BadgeVariantOptions): string;
12
+ export interface BadgeState extends Record<string, unknown> {
13
+ slot: "badge";
14
+ variant: BadgeVariant;
15
+ size: BadgeSize;
16
+ }
17
+ export interface BadgeProps extends useRender.ComponentProps<"span", BadgeState> {
18
+ variant?: BadgeVariant;
19
+ size?: BadgeSize;
20
+ }
21
+ export declare function Badge({ className, variant, size, render, ref, ...props }: BadgeProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
@@ -0,0 +1,27 @@
1
+ import { mergeProps } from "@base-ui/react/merge-props";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import { cn } from "../internal/classes.js";
4
+ export const badgeVariantNames = [
5
+ "default",
6
+ "success",
7
+ "warning",
8
+ "info",
9
+ "secondary",
10
+ "destructive",
11
+ "outline",
12
+ "ghost",
13
+ "link",
14
+ ];
15
+ export const badgeSizeNames = ["default", "chip"];
16
+ export function badgeVariants({ variant, size, className, } = {}) {
17
+ return cn("sprout-badge", `sprout-badge-${variant ?? "default"}`, size === "chip" && "sprout-badge-chip", className);
18
+ }
19
+ export function Badge({ className, variant = "default", size = "default", render, ref, ...props }) {
20
+ return useRender({
21
+ defaultTagName: "span",
22
+ ref,
23
+ render,
24
+ props: mergeProps({ className: badgeVariants({ variant, size, className }) }, props),
25
+ state: { slot: "badge", variant, size },
26
+ });
27
+ }
@@ -0,0 +1,28 @@
1
+ import type { ComponentProps } from "react";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import { brandGlyphs } from "../internal/brand-glyphs.js";
4
+ export type Brand = keyof typeof brandGlyphs;
5
+ export declare const brandNames: Record<Brand, string>;
6
+ export declare const brandTileSizeNames: readonly ["sm", "md", "lg", "xl", "action"];
7
+ export declare const brandIconSizeNames: readonly ["inline", "glyph", "fill", "sm", "md", "lg", "xl"];
8
+ export type BrandTileSize = (typeof brandTileSizeNames)[number];
9
+ export type BrandIconSize = (typeof brandIconSizeNames)[number];
10
+ export type BrandTileProps = useRender.ComponentProps<"span"> & {
11
+ size?: BrandTileSize;
12
+ };
13
+ export declare function BrandTile({ size, render, ref, className, ...props }: BrandTileProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
14
+ export interface BrandIconProps extends Omit<ComponentProps<"span">, "children"> {
15
+ brand: Brand;
16
+ size?: BrandIconSize;
17
+ }
18
+ export declare function BrandIcon({ brand, size, className, ...props }: BrandIconProps): import("react").JSX.Element;
19
+ export interface BrandStackItem {
20
+ brand: Brand;
21
+ name: string;
22
+ }
23
+ export interface BrandStackProps extends Omit<ComponentProps<"span">, "children" | "role"> {
24
+ brands: readonly BrandStackItem[];
25
+ /** Accessible name for the whole stack. Defaults to the brand names. */
26
+ label?: string;
27
+ }
28
+ export declare function BrandStack({ brands, label, className, ...props }: BrandStackProps): import("react").JSX.Element | null;
@@ -0,0 +1,82 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { mergeProps } from "@base-ui/react/merge-props";
4
+ import { useRender } from "@base-ui/react/use-render";
5
+ import { brandGlyphs } from "../internal/brand-glyphs.js";
6
+ import { cn } from "../internal/classes.js";
7
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "./tooltip.js";
8
+ export const brandNames = {
9
+ claude: "Claude",
10
+ openai: "OpenAI",
11
+ deepseek: "DeepSeek",
12
+ grok: "Grok",
13
+ kimi: "Kimi",
14
+ gemini: "Gemini",
15
+ mistral: "Mistral",
16
+ meta: "Meta",
17
+ qwen: "Qwen",
18
+ google: "Google Workspace",
19
+ gmail: "Gmail",
20
+ "google-calendar": "Google Calendar",
21
+ "google-drive": "Google Drive",
22
+ "google-sheets": "Google Sheets",
23
+ "google-docs": "Google Docs",
24
+ "google-slides": "Google Slides",
25
+ "google-forms": "Google Forms",
26
+ slack: "Slack",
27
+ github: "GitHub",
28
+ jira: "Jira",
29
+ confluence: "Confluence",
30
+ trello: "Trello",
31
+ notion: "Notion",
32
+ hubspot: "HubSpot",
33
+ figma: "Figma",
34
+ microsoft: "Microsoft",
35
+ linear: "Linear",
36
+ stripe: "Stripe",
37
+ airtable: "Airtable",
38
+ asana: "Asana",
39
+ clickup: "ClickUp",
40
+ discord: "Discord",
41
+ shopify: "Shopify",
42
+ zendesk: "Zendesk",
43
+ dropbox: "Dropbox",
44
+ gitlab: "GitLab",
45
+ calendly: "Calendly",
46
+ };
47
+ export const brandTileSizeNames = ["sm", "md", "lg", "xl", "action"];
48
+ export const brandIconSizeNames = [
49
+ "inline",
50
+ "glyph",
51
+ "fill",
52
+ "sm",
53
+ "md",
54
+ "lg",
55
+ "xl",
56
+ ];
57
+ function Glyph({ brand }) {
58
+ const glyph = brandGlyphs[brand];
59
+ return (_jsx("svg", { viewBox: glyph.viewBox, className: "sprout-brand-glyph", "aria-hidden": "true", focusable: "false", children: glyph.paths.map((path, index) => (_jsx("path", { d: path.d, fill: "fill" in path ? path.fill : "currentColor", fillRule: "evenOdd" in path ? "evenodd" : undefined, clipRule: "evenOdd" in path ? "evenodd" : undefined }, index))) }));
60
+ }
61
+ export function BrandTile({ size = "md", render, ref, className, ...props }) {
62
+ return useRender({
63
+ defaultTagName: "span",
64
+ render,
65
+ ref,
66
+ props: mergeProps({
67
+ "data-slot": "brand-tile",
68
+ "data-size": size,
69
+ className: cn("sprout-brand-tile", className),
70
+ }, props),
71
+ });
72
+ }
73
+ export function BrandIcon({ brand, size = "md", className, ...props }) {
74
+ if (size === "inline" || size === "glyph" || size === "fill")
75
+ return (_jsx("span", { "data-slot": "brand-icon", "data-brand": brand, "data-size": size, ...props, className: cn("sprout-brand-icon", className), children: _jsx(Glyph, { brand: brand }) }));
76
+ return (_jsx(BrandTile, { "data-brand": brand, size: size, ...props, className: className, children: _jsx(Glyph, { brand: brand }) }));
77
+ }
78
+ export function BrandStack({ brands, label, className, ...props }) {
79
+ if (brands.length === 0)
80
+ return null;
81
+ return (_jsx(TooltipProvider, { delay: 200, children: _jsx("span", { "data-slot": "brand-stack", ...props, role: "img", "aria-label": label ?? brands.map((item) => item.name).join(", "), className: cn("sprout-brand-stack", className), children: brands.map((item) => (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { render: _jsx(BrandTile, { size: "sm", "data-brand": item.brand }), children: _jsx(Glyph, { brand: item.brand }) }), _jsx(TooltipContent, { sideOffset: 6, className: "sprout-brand-tooltip", children: item.name })] }, item.brand))) }) }));
82
+ }
@@ -0,0 +1,29 @@
1
+ import type { ComponentProps } from "react";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ export type BreadcrumbProps = ComponentProps<"nav">;
4
+ export declare function Breadcrumb({ className, "aria-label": label, ...props }: BreadcrumbProps): import("react").JSX.Element;
5
+ export interface BreadcrumbListProps extends ComponentProps<"ol"> {
6
+ /** Wrap long paths onto more lines. Set `false` to keep one line and let the current page shrink. */
7
+ wrap?: boolean;
8
+ }
9
+ export declare function BreadcrumbList({ className, wrap, ...props }: BreadcrumbListProps): import("react").JSX.Element;
10
+ export type BreadcrumbItemProps = ComponentProps<"li">;
11
+ export declare function BreadcrumbItem({ className, ...props }: BreadcrumbItemProps): import("react").JSX.Element;
12
+ export interface BreadcrumbLinkState extends Record<string, unknown> {
13
+ slot: "breadcrumb-link";
14
+ }
15
+ export interface BreadcrumbLinkProps extends useRender.ComponentProps<"a", BreadcrumbLinkState> {
16
+ /** Cut a long name to one line with an ellipsis. String names also get a `title`. */
17
+ truncate?: boolean;
18
+ }
19
+ export declare function BreadcrumbLink({ className, render, ref, truncate, children, ...props }: BreadcrumbLinkProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
20
+ export interface BreadcrumbPageProps extends ComponentProps<"span"> {
21
+ /** Cut a long name to one line with an ellipsis. String names also get a `title`. */
22
+ truncate?: boolean;
23
+ }
24
+ export declare function BreadcrumbPage({ className, truncate, children, ...props }: BreadcrumbPageProps): import("react").JSX.Element;
25
+ export type BreadcrumbSeparatorProps = ComponentProps<"li">;
26
+ export declare function BreadcrumbSeparator({ children, className, ...props }: BreadcrumbSeparatorProps): import("react").JSX.Element;
27
+ export type BreadcrumbEllipsisProps = ComponentProps<"span">;
28
+ /** Marks hidden folders. It is hidden from screen readers, so put the reason in a visually hidden sibling. */
29
+ export declare function BreadcrumbEllipsis({ className, ...props }: BreadcrumbEllipsisProps): import("react").JSX.Element;
@@ -0,0 +1,44 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { mergeProps } from "@base-ui/react/merge-props";
3
+ import { useRender } from "@base-ui/react/use-render";
4
+ import { ChevronRight } from "reicon-react/icons/ChevronRight";
5
+ import { MoreH } from "reicon-react/icons/MoreH";
6
+ import { cn } from "../internal/classes.js";
7
+ export function Breadcrumb({ className, "aria-label": label = "Breadcrumb", ...props }) {
8
+ return (_jsx("nav", { "aria-label": label, "data-slot": "breadcrumb", className: cn("sprout-breadcrumb", className), ...props }));
9
+ }
10
+ export function BreadcrumbList({ className, wrap = true, ...props }) {
11
+ return (_jsx("ol", { "data-slot": "breadcrumb-list", "data-wrap": wrap ? "true" : "false", className: cn("sprout-breadcrumb-list", className), ...props }));
12
+ }
13
+ export function BreadcrumbItem({ className, ...props }) {
14
+ return (_jsx("li", { "data-slot": "breadcrumb-item", className: cn("sprout-breadcrumb-item", className), ...props }));
15
+ }
16
+ function label(children, truncate) {
17
+ if (!truncate)
18
+ return children;
19
+ return (_jsx("span", { "data-slot": "breadcrumb-label", className: "sprout-breadcrumb-label", title: typeof children === "string" || typeof children === "number"
20
+ ? String(children)
21
+ : undefined, children: children }));
22
+ }
23
+ export function BreadcrumbLink({ className, render, ref, truncate, children, ...props }) {
24
+ return useRender({
25
+ defaultTagName: "a",
26
+ ref,
27
+ render,
28
+ props: mergeProps({
29
+ className: cn("sprout-breadcrumb-link", className),
30
+ children: label(children, truncate),
31
+ }, props),
32
+ state: { slot: "breadcrumb-link" },
33
+ });
34
+ }
35
+ export function BreadcrumbPage({ className, truncate, children, ...props }) {
36
+ return (_jsx("span", { "data-slot": "breadcrumb-page", role: "link", "aria-disabled": "true", "aria-current": "page", className: cn("sprout-breadcrumb-page", className), ...props, children: label(children, truncate) }));
37
+ }
38
+ export function BreadcrumbSeparator({ children, className, ...props }) {
39
+ return (_jsx("li", { "data-slot": "breadcrumb-separator", role: "presentation", "aria-hidden": "true", className: cn("sprout-breadcrumb-separator", className), ...props, children: children ?? _jsx(ChevronRight, {}) }));
40
+ }
41
+ /** Marks hidden folders. It is hidden from screen readers, so put the reason in a visually hidden sibling. */
42
+ export function BreadcrumbEllipsis({ className, ...props }) {
43
+ return (_jsxs("span", { "data-slot": "breadcrumb-ellipsis", role: "presentation", "aria-hidden": "true", className: cn("sprout-breadcrumb-ellipsis", className), ...props, children: [_jsx(MoreH, {}), _jsx("span", { className: "sprout-breadcrumb-sr-only", children: "More" })] }));
44
+ }