@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,16 @@
1
+ import { Radio as BaseRadio } from "@base-ui/react/radio";
2
+ import { RadioGroup as BaseRadioGroup } from "@base-ui/react/radio-group";
3
+ export type RadioGroupProps<Value = string> = BaseRadioGroup.Props<Value>;
4
+ export type RadioGroupItemProps<Value = string> = BaseRadio.Root.Props<Value>;
5
+ /**
6
+ * A set of radios where one value is chosen. Arrow keys move between items
7
+ * and select them. Name the group with `aria-label` or `aria-labelledby`.
8
+ * Children may include a legend, helper, or error next to the items.
9
+ */
10
+ export declare function RadioGroup<Value = string>({ className, ...props }: RadioGroupProps<Value>): import("react").JSX.Element;
11
+ /**
12
+ * A 16px radio with a larger hit area. Name it with a wrapping `Label`, a
13
+ * `Label htmlFor` pointing at its `id`, or `aria-label`. Set `aria-invalid`
14
+ * to draw a danger ring.
15
+ */
16
+ export declare function RadioGroupItem<Value = string>({ className, ...props }: RadioGroupItemProps<Value>): import("react").JSX.Element;
@@ -0,0 +1,21 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Radio as BaseRadio } from "@base-ui/react/radio";
4
+ import { RadioGroup as BaseRadioGroup } from "@base-ui/react/radio-group";
5
+ import { stateClassName } from "../internal/classes.js";
6
+ /**
7
+ * A set of radios where one value is chosen. Arrow keys move between items
8
+ * and select them. Name the group with `aria-label` or `aria-labelledby`.
9
+ * Children may include a legend, helper, or error next to the items.
10
+ */
11
+ export function RadioGroup({ className, ...props }) {
12
+ return (_jsx(BaseRadioGroup, { "data-slot": "radio-group", ...props, className: stateClassName("sprout-radio-group", className) }));
13
+ }
14
+ /**
15
+ * A 16px radio with a larger hit area. Name it with a wrapping `Label`, a
16
+ * `Label htmlFor` pointing at its `id`, or `aria-label`. Set `aria-invalid`
17
+ * to draw a danger ring.
18
+ */
19
+ export function RadioGroupItem({ className, ...props }) {
20
+ return (_jsx(BaseRadio.Root, { "data-slot": "radio-group-item", ...props, className: stateClassName("sprout-radio-group-item", className), children: _jsx(BaseRadio.Indicator, { "data-slot": "radio-group-indicator", className: "sprout-radio-group-indicator" }) }));
21
+ }
@@ -0,0 +1,24 @@
1
+ export interface ReasoningEffortProps {
2
+ /** Level names from lowest to highest effort. Each one gets a tick. */
3
+ levels: readonly string[];
4
+ /** Index of the chosen level in `levels`. */
5
+ value: number;
6
+ /** Called with the new index on drag, click, or key press. */
7
+ onValueChange: (index: number) => void;
8
+ /**
9
+ * Bold text before the level name in the bubble shown while dragging,
10
+ * such as the model name.
11
+ */
12
+ label?: string | undefined;
13
+ /** Names the slider. Defaults to "Reasoning effort". */
14
+ "aria-label"?: string | undefined;
15
+ /** Points at visible text that names the slider, instead of `aria-label`. */
16
+ "aria-labelledby"?: string | undefined;
17
+ className?: string | undefined;
18
+ }
19
+ /**
20
+ * A pill-shaped slider that picks one of a few effort levels. While dragging,
21
+ * a bubble grows out of the track and shows `label` and the level name.
22
+ * Release snaps the thumb to the nearest level.
23
+ */
24
+ export declare function ReasoningEffort({ levels, value, onValueChange, label, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, className, }: ReasoningEffortProps): import("react").JSX.Element;
@@ -0,0 +1,269 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useId, useLayoutEffect, useRef, useState, } from "react";
4
+ import { cn } from "../internal/classes.js";
5
+ const TRACK = 256;
6
+ const HEIGHT = 32;
7
+ const RADIUS = HEIGHT / 2;
8
+ const BUMP_H = 20;
9
+ const REST_W = 27.2;
10
+ const DRAG_W = 33.6;
11
+ const REST_H = 27.2;
12
+ const EDGE_PAD = (HEIGHT - REST_H) / 2;
13
+ const SHOULDER = 23.572;
14
+ /** Space from each label edge to the foot of the shoulder. */
15
+ const TEXT_SIDE = 20;
16
+ /** How far the outer foot walks down the end cap once it passes the crown. */
17
+ const PHI_MAX = 0.6;
18
+ const PHI_REACH = 36;
19
+ function clamp(n, min, max) {
20
+ return Math.min(max, Math.max(min, n));
21
+ }
22
+ function easeOut(t) {
23
+ return 1 - (1 - t) ** 3;
24
+ }
25
+ function smoothstep(t) {
26
+ const x = clamp(t, 0, 1);
27
+ return x * x * (3 - 2 * x);
28
+ }
29
+ function reducedMotion() {
30
+ return (typeof window !== "undefined" &&
31
+ window.matchMedia?.("(prefers-reduced-motion: reduce)").matches);
32
+ }
33
+ function plateauFor(textW) {
34
+ return Math.max(8, textW + TEXT_SIDE * 2 - SHOULDER * 2);
35
+ }
36
+ function capFoot(side, phi) {
37
+ const crown = side === -1 ? RADIUS : TRACK - RADIUS;
38
+ return {
39
+ x: crown + side * RADIUS * Math.sin(phi),
40
+ y: BUMP_H + RADIUS * (1 - Math.cos(phi)),
41
+ };
42
+ }
43
+ function shellGeom(cx, plateauW) {
44
+ const crownL = RADIUS;
45
+ const crownR = TRACK - RADIUS;
46
+ let topL = cx - plateauW / 2;
47
+ let topR = topL + plateauW;
48
+ let phiL = 0;
49
+ let phiR = 0;
50
+ const overflowL = crownL - (topL - SHOULDER);
51
+ if (overflowL > 0) {
52
+ phiL = PHI_MAX * smoothstep(overflowL / PHI_REACH);
53
+ const foot = capFoot(-1, phiL);
54
+ const minTopL = foot.x + SHOULDER * Math.cos(phiL);
55
+ if (topL < minTopL) {
56
+ topR += minTopL - topL;
57
+ topL = minTopL;
58
+ }
59
+ }
60
+ const overflowR = topR + SHOULDER - crownR;
61
+ if (overflowR > 0) {
62
+ phiR = PHI_MAX * smoothstep(overflowR / PHI_REACH);
63
+ const foot = capFoot(1, phiR);
64
+ const maxTopR = foot.x - SHOULDER * Math.cos(phiR);
65
+ if (topR > maxTopR) {
66
+ topL -= topR - maxTopR;
67
+ topR = maxTopR;
68
+ }
69
+ }
70
+ // A tilted shoulder is shorter in x, which would pull the label onto the
71
+ // outer edge. Grow the plateau inward by that loss and keep the label with it.
72
+ const insetL = phiL > 0 ? SHOULDER * (1 - Math.cos(phiL)) : 0;
73
+ const insetR = phiR > 0 ? SHOULDER * (1 - Math.cos(phiR)) : 0;
74
+ topR += insetL;
75
+ topL -= insetR;
76
+ return { topL, topR, phiL, phiR, insetL, insetR };
77
+ }
78
+ /** One shoulder curve. `phi` tilts the foot onto the cap tangent; 0 is flat. */
79
+ function shoulderCmds(footX, footY, platX, platY, phi, dir) {
80
+ const xScale = Math.abs(platX - footX) / SHOULDER;
81
+ const yScale = Math.max(0.001, (footY - platY) / 20);
82
+ const tangent = { x: dir * Math.cos(phi), y: -Math.sin(phi) };
83
+ const map = (lx, ly) => ({
84
+ x: footX + dir * lx * xScale,
85
+ y: footY + (ly - 20) * yScale,
86
+ });
87
+ const h1 = 5.398 * xScale;
88
+ const p0 = { x: footX, y: footY };
89
+ const c1 = { x: footX + tangent.x * h1, y: footY + tangent.y * h1 };
90
+ const c2 = map(10.012, 16.114);
91
+ const p1 = map(10.93, 10.794);
92
+ const c3 = map(11.916, 4.577);
93
+ const c4 = map(17.277, 0);
94
+ const p3 = { x: platX, y: platY };
95
+ const fmt = (p) => `${p.x.toFixed(2)} ${p.y.toFixed(2)}`;
96
+ if (dir === 1)
97
+ return `C${fmt(c1)} ${fmt(c2)} ${fmt(p1)}C${fmt(c3)} ${fmt(c4)} ${fmt(p3)}`;
98
+ return `C${fmt(c4)} ${fmt(c3)} ${fmt(p1)}C${fmt(c2)} ${fmt(c1)} ${fmt(p0)}`;
99
+ }
100
+ /** One outline: the pill, with the label bump grown out of its top edge. */
101
+ function shellPath(cx, open, plateauW) {
102
+ const trackTop = BUMP_H;
103
+ const trackBot = BUMP_H + HEIGHT;
104
+ const crownL = RADIUS;
105
+ const crownR = TRACK - RADIUS;
106
+ if (open < 0.012) {
107
+ return `M${crownL} ${trackTop}H${crownR}A${RADIUS} ${RADIUS} 0 0 1 ${crownR} ${trackBot}H${crownL}A${RADIUS} ${RADIUS} 0 0 1 ${crownL} ${trackTop}Z`;
108
+ }
109
+ const bumpTop = BUMP_H * (1 - open);
110
+ const { topL, topR, phiL, phiR } = shellGeom(cx, plateauW);
111
+ const cmds = [`M${crownL} ${trackBot}`];
112
+ if (phiL > 0.001) {
113
+ const foot = capFoot(-1, phiL);
114
+ cmds.push(`A${RADIUS} ${RADIUS} 0 0 1 ${foot.x.toFixed(2)} ${foot.y.toFixed(2)}`);
115
+ cmds.push(shoulderCmds(foot.x, foot.y, topL, bumpTop, phiL, 1));
116
+ }
117
+ else {
118
+ cmds.push(`A${RADIUS} ${RADIUS} 0 0 1 ${crownL} ${trackTop}`);
119
+ const footL = topL - SHOULDER;
120
+ if (footL > crownL + 0.4)
121
+ cmds.push(`H${footL.toFixed(2)}`);
122
+ cmds.push(shoulderCmds(footL, trackTop, topL, bumpTop, 0, 1));
123
+ }
124
+ if (topR > topL + 0.4)
125
+ cmds.push(`H${topR.toFixed(2)}`);
126
+ if (phiR > 0.001) {
127
+ const foot = capFoot(1, phiR);
128
+ cmds.push(shoulderCmds(foot.x, foot.y, topR, bumpTop, phiR, -1));
129
+ cmds.push(`A${RADIUS} ${RADIUS} 0 0 1 ${crownR} ${trackBot}`);
130
+ }
131
+ else {
132
+ const footR = topR + SHOULDER;
133
+ cmds.push(shoulderCmds(footR, trackTop, topR, bumpTop, 0, -1));
134
+ if (footR < crownR - 0.4)
135
+ cmds.push(`H${crownR}`);
136
+ cmds.push(`A${RADIUS} ${RADIUS} 0 0 1 ${crownR} ${trackBot}`);
137
+ }
138
+ cmds.push(`H${crownL}Z`);
139
+ return cmds.join("");
140
+ }
141
+ function useTween(target, duration, delay = 0) {
142
+ const ref = useRef(target);
143
+ const [value, setValue] = useState(target);
144
+ useEffect(() => {
145
+ const from = ref.current;
146
+ if (reducedMotion() || Math.abs(target - from) < 0.001) {
147
+ ref.current = target;
148
+ setValue(target);
149
+ return;
150
+ }
151
+ const start = performance.now();
152
+ let raf = 0;
153
+ const step = (now) => {
154
+ const elapsed = now - start - delay;
155
+ if (elapsed >= 0) {
156
+ const t = Math.min(1, elapsed / duration);
157
+ ref.current = from + (target - from) * easeOut(t);
158
+ setValue(ref.current);
159
+ if (t === 1)
160
+ return;
161
+ }
162
+ raf = requestAnimationFrame(step);
163
+ };
164
+ raf = requestAnimationFrame(step);
165
+ return () => cancelAnimationFrame(raf);
166
+ }, [target, duration, delay]);
167
+ return value;
168
+ }
169
+ /**
170
+ * A pill-shaped slider that picks one of a few effort levels. While dragging,
171
+ * a bubble grows out of the track and shows `label` and the level name.
172
+ * Release snaps the thumb to the nearest level.
173
+ */
174
+ export function ReasoningEffort({ levels, value, onValueChange, label, "aria-label": ariaLabel = "Reasoning effort", "aria-labelledby": ariaLabelledBy, className, }) {
175
+ const max = Math.max(0, levels.length - 1);
176
+ const current = clamp(Math.round(value), 0, max);
177
+ const trackRef = useRef(null);
178
+ const labelRef = useRef(null);
179
+ const [dragging, setDragging] = useState(false);
180
+ const [dragValue, setDragValue] = useState(current);
181
+ const [textW, setTextW] = useState(64);
182
+ const gradId = useId();
183
+ const settled = useTween(dragging ? dragValue : current, 220);
184
+ const display = dragging ? dragValue : settled;
185
+ const open = useTween(dragging ? 1 : 0, 220);
186
+ const reveal = useTween(dragging ? 1 : 0, dragging ? 132 : 90, dragging ? 85 : 0);
187
+ const plateauW = useTween(plateauFor(textW), 90);
188
+ const centerFor = (index) => RADIUS + (max === 0 ? 0 : index / max) * (TRACK - RADIUS * 2);
189
+ const valueFrom = (clientX) => {
190
+ const rect = trackRef.current?.getBoundingClientRect();
191
+ if (!rect || max === 0)
192
+ return current;
193
+ return clamp(((clientX - rect.left - RADIUS) / (rect.width - RADIUS * 2)) * max, 0, max);
194
+ };
195
+ const move = (next) => {
196
+ setDragValue(next);
197
+ if (Math.round(next) !== current)
198
+ onValueChange(Math.round(next));
199
+ };
200
+ const onPointerDown = (event) => {
201
+ if (event.button !== 0)
202
+ return;
203
+ event.currentTarget.setPointerCapture?.(event.pointerId);
204
+ setDragging(true);
205
+ move(valueFrom(event.clientX));
206
+ };
207
+ const onPointerMove = (event) => {
208
+ if (dragging)
209
+ move(valueFrom(event.clientX));
210
+ };
211
+ const onPointerUp = (event) => {
212
+ if (!dragging)
213
+ return;
214
+ if (event.currentTarget.hasPointerCapture?.(event.pointerId))
215
+ event.currentTarget.releasePointerCapture(event.pointerId);
216
+ setDragging(false);
217
+ };
218
+ const onKeyDown = (event) => {
219
+ const keys = {
220
+ ArrowRight: current + 1,
221
+ ArrowUp: current + 1,
222
+ ArrowLeft: current - 1,
223
+ ArrowDown: current - 1,
224
+ Home: 0,
225
+ End: max,
226
+ };
227
+ const next = keys[event.key];
228
+ if (next === undefined)
229
+ return;
230
+ event.preventDefault();
231
+ const clamped = clamp(next, 0, max);
232
+ if (clamped !== current)
233
+ onValueChange(clamped);
234
+ };
235
+ const center = centerFor(display);
236
+ const thumbW = REST_W + (DRAG_W - REST_W) * open;
237
+ const thumbLeft = clamp(center - thumbW / 2, EDGE_PAD, TRACK - EDGE_PAD - thumbW);
238
+ const thumbRight = thumbLeft + thumbW;
239
+ const fillW = Math.min(TRACK, thumbRight + EDGE_PAD);
240
+ const active = Math.round(display);
241
+ const level = levels[active];
242
+ const plateau = shellGeom(center, plateauW);
243
+ const labelX = (plateau.topL + plateau.topR) / 2 + (plateau.insetL - plateau.insetR) / 2;
244
+ useLayoutEffect(() => {
245
+ const w = labelRef.current?.getBoundingClientRect().width ?? 0;
246
+ if (w > 0 && Math.abs(w - textW) > 0.4)
247
+ setTextW(w);
248
+ }, [level, label, textW]);
249
+ return (_jsxs("div", { "data-slot": "reasoning-effort", "data-dragging": dragging, className: cn("sprout-reasoning-effort", className), children: [_jsxs("svg", { className: "sprout-reasoning-effort-shell", viewBox: `0 0 ${TRACK} ${BUMP_H + HEIGHT}`, "aria-hidden": "true", children: [_jsx("defs", { children: _jsxs("linearGradient", { id: gradId, x1: "0", y1: "0", x2: "0", y2: "1", children: [_jsx("stop", { offset: "0", className: "sprout-reasoning-effort-stop-top" }), _jsx("stop", { offset: "1", className: "sprout-reasoning-effort-stop-bottom" })] }) }), _jsx("path", { "data-slot": "reasoning-effort-shell", d: shellPath(center, open, plateauW), fill: `url(#${gradId})`, strokeWidth: "0.5", strokeLinejoin: "round", vectorEffect: "non-scaling-stroke" })] }), _jsx("div", { ref: labelRef, "data-slot": "reasoning-effort-bubble", "aria-hidden": "true", className: "sprout-reasoning-effort-bubble", style: {
250
+ left: labelX,
251
+ opacity: reveal,
252
+ filter: reveal > 0.98
253
+ ? undefined
254
+ : `blur(${((1 - reveal) * 3).toFixed(2)}px)`,
255
+ transform: `translate(-50%, ${3 * (1 - open)}px)`,
256
+ }, children: _jsxs("span", { className: "sprout-reasoning-effort-bubble-text", children: [label && (_jsx("span", { className: "sprout-reasoning-effort-bubble-label", children: label })), _jsx("span", { className: "sprout-reasoning-effort-bubble-level", children: level })] }, level) }), _jsxs("div", { ref: trackRef, role: "slider", tabIndex: 0, "data-slot": "reasoning-effort-track", "aria-label": ariaLabelledBy ? undefined : ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-orientation": "horizontal", "aria-valuemin": 0, "aria-valuemax": max, "aria-valuenow": current, "aria-valuetext": levels[current], className: "sprout-reasoning-effort-track", onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, onPointerCancel: onPointerUp, onKeyDown: onKeyDown, children: [_jsx("div", { "data-slot": "reasoning-effort-fill", className: "sprout-reasoning-effort-fill", style: { width: fillW } }), _jsx("div", { "data-slot": "reasoning-effort-thumb", className: "sprout-reasoning-effort-thumb", style: {
257
+ left: thumbLeft,
258
+ width: thumbW,
259
+ height: REST_H,
260
+ marginTop: -REST_H / 2,
261
+ } }), levels.map((name, index) => {
262
+ const x = centerFor(index);
263
+ const onThumb = x >= thumbLeft + 0.5 && x <= thumbRight - 0.5;
264
+ return (_jsx("span", { "data-slot": "reasoning-effort-tick", "data-on-thumb": onThumb, "data-active": index === active && !onThumb, className: "sprout-reasoning-effort-tick", style: {
265
+ left: x,
266
+ height: 4.8 + (max === 0 ? 0 : index / max) * 4.8,
267
+ } }, `${index}-${name}`));
268
+ })] })] }));
269
+ }
@@ -0,0 +1,67 @@
1
+ import { type ComponentProps } from "react";
2
+ export declare const resizableOrientationNames: readonly ["horizontal", "vertical"];
3
+ /** `"horizontal"` places panels side by side. `"vertical"` stacks them. */
4
+ export type ResizableOrientation = (typeof resizableOrientationNames)[number];
5
+ /**
6
+ * Numbers are pixels. Strings may end in `%`, `px`, `rem`, `em`, `vw`, or `vh`.
7
+ * A string without a unit is a percentage, so `"40"` is the same as `"40%"`.
8
+ */
9
+ export type ResizableSize = number | string;
10
+ /** Panel sizes in percent of the group, keyed by panel `id`. */
11
+ export type ResizableLayout = Record<string, number>;
12
+ export interface ResizableLayoutChangeDetails {
13
+ /** True for pointer and keyboard resizes. False for mount and container changes. */
14
+ isUserInteraction: boolean;
15
+ }
16
+ export interface ResizablePanelGroupProps extends ComponentProps<"div"> {
17
+ /** `"horizontal"` (default) places panels side by side. `"vertical"` stacks them. */
18
+ orientation?: ResizableOrientation;
19
+ /** Starting sizes by panel `id`, such as a layout saved by `useResizableLayout`. */
20
+ defaultLayout?: ResizableLayout | undefined;
21
+ /** Called on every change, including each pointer move while dragging. */
22
+ onLayoutChange?: ((layout: ResizableLayout) => void) | undefined;
23
+ /** Called once a change settles: on mount, after a drag ends, and after each key press. */
24
+ onLayoutChanged?: ((layout: ResizableLayout, details: ResizableLayoutChangeDetails) => void) | undefined;
25
+ }
26
+ /** A row or column of resizable panels separated by `ResizableHandle`s. */
27
+ export declare function ResizablePanelGroup({ orientation, defaultLayout, onLayoutChange, onLayoutChanged, className, children, ref, ...props }: ResizablePanelGroupProps): import("react").JSX.Element;
28
+ export interface ResizablePanelProps extends Omit<ComponentProps<"div">, "id"> {
29
+ /** Key for this panel in layouts. Set it when saving layouts or showing panels conditionally. */
30
+ id?: string;
31
+ /** Starting size. Panels without one share the space that is left. */
32
+ defaultSize?: ResizableSize | undefined;
33
+ /** Smallest size while resizing. Defaults to 0%. */
34
+ minSize?: ResizableSize | undefined;
35
+ /** Largest size while resizing. Defaults to 100%. */
36
+ maxSize?: ResizableSize | undefined;
37
+ }
38
+ /** One resizable region. It must be a direct child of `ResizablePanelGroup`. */
39
+ export declare function ResizablePanel({ id: idProp, defaultSize, minSize, maxSize, className, style, ref, ...props }: ResizablePanelProps): import("react").JSX.Element;
40
+ export interface ResizableHandleProps extends ComponentProps<"div"> {
41
+ /** Shows a small grip on the line, for splits people resize often. */
42
+ withHandle?: boolean;
43
+ }
44
+ /**
45
+ * The divider between two panels. Drag it, or focus it and use the arrow keys.
46
+ * Home and End move it to the first panel's minimum and maximum size.
47
+ */
48
+ export declare function ResizableHandle({ withHandle, className, children, onPointerDown, onKeyDown, ref, ...props }: ResizableHandleProps): import("react").JSX.Element;
49
+ export interface UseResizableLayoutOptions {
50
+ /** Storage key for this split. Use one per place the split appears. */
51
+ id: string;
52
+ /** Panel ids currently shown. Each set of panels keeps its own saved layout. */
53
+ panelIds?: readonly string[] | undefined;
54
+ /** Only save sizes the person chose, not the starting layout. */
55
+ onlySaveAfterUserInteractions?: boolean | undefined;
56
+ /** Where to save. Defaults to `localStorage`. */
57
+ storage?: Pick<Storage, "getItem" | "setItem"> | undefined;
58
+ }
59
+ export interface ResizableLayoutStore {
60
+ defaultLayout: ResizableLayout | undefined;
61
+ onLayoutChanged: (layout: ResizableLayout, details: ResizableLayoutChangeDetails) => void;
62
+ }
63
+ /**
64
+ * Remembers a group's layout between visits. Spread the result onto
65
+ * `ResizablePanelGroup` as `defaultLayout` and `onLayoutChanged`.
66
+ */
67
+ export declare function useResizableLayout({ id, panelIds, onlySaveAfterUserInteractions, storage, }: UseResizableLayoutOptions): ResizableLayoutStore;