@nebutra/ui 0.2.1 → 0.2.2

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 (55) hide show
  1. package/LICENSE +21 -676
  2. package/README.md +81 -86
  3. package/dist/agent/index.d.ts +119 -0
  4. package/dist/agent/index.js +135 -0
  5. package/dist/agent/index.js.map +1 -0
  6. package/dist/canonical-CrO71UPO.d.ts +4058 -0
  7. package/dist/components/index.d.ts +51 -56
  8. package/dist/components/index.js +1467 -1160
  9. package/dist/components/index.js.map +1 -1
  10. package/dist/hooks/index.d.ts +62 -15
  11. package/dist/hooks/index.js +56 -34
  12. package/dist/hooks/index.js.map +1 -1
  13. package/dist/index-CKLIGfiU.d.ts +19 -0
  14. package/dist/index-Dg4jRJV2.d.ts +57 -0
  15. package/dist/layout/index.d.ts +5 -1
  16. package/dist/layout/index.js +427 -533
  17. package/dist/layout/index.js.map +1 -1
  18. package/dist/layouts/index.js +11 -9
  19. package/dist/layouts/index.js.map +1 -1
  20. package/dist/patterns/index.d.ts +128 -2
  21. package/dist/patterns/index.js +1478 -786
  22. package/dist/patterns/index.js.map +1 -1
  23. package/dist/primitives/canonical.d.ts +25 -0
  24. package/dist/primitives/canonical.js +11903 -0
  25. package/dist/primitives/canonical.js.map +1 -0
  26. package/dist/primitives/index.d.ts +577 -3545
  27. package/dist/primitives/index.js +8002 -6159
  28. package/dist/primitives/index.js.map +1 -1
  29. package/dist/shared/animation/css/index.d.ts +1 -0
  30. package/dist/shared/animation/css/index.js +14 -0
  31. package/dist/shared/animation/css/index.js.map +1 -0
  32. package/dist/shared/animation/index.d.ts +6 -0
  33. package/dist/shared/animation/index.js +272 -0
  34. package/dist/shared/animation/index.js.map +1 -0
  35. package/dist/shared/animation/motion/index.d.ts +4 -0
  36. package/dist/shared/animation/motion/index.js +205 -0
  37. package/dist/shared/animation/motion/index.js.map +1 -0
  38. package/dist/styles/brand-override.css +11 -11
  39. package/dist/tailwind.preset.d.ts +10 -10
  40. package/dist/tailwind.preset.js +7 -4
  41. package/dist/tailwind.preset.js.map +1 -1
  42. package/dist/theme/index.d.ts +2 -2
  43. package/dist/tokens-EAC6uPem.d.ts +302 -0
  44. package/dist/typography/fonts.css +31 -12
  45. package/dist/typography/index.d.ts +27 -27
  46. package/dist/typography/index.js +24 -4
  47. package/dist/typography/index.js.map +1 -1
  48. package/dist/utils/index.d.ts +36 -14
  49. package/dist/utils/index.js +44 -10
  50. package/dist/utils/index.js.map +1 -1
  51. package/package.json +38 -12
  52. package/src/styles/brand-override.css +61 -0
  53. package/src/styles/preset.css +29 -0
  54. package/src/styles/sources.css +27 -0
  55. package/src/typography/fonts.css +129 -0
@@ -1,43 +1,529 @@
1
1
  "use client";
2
2
  import { Button as Button$1 } from '@lobehub/ui';
3
3
  export { ActionIcon, ActionIconGroup, Alert, Avatar, Button, Checkbox, DraggablePanel, DraggablePanelBody, DraggablePanelContainer, DraggablePanelFooter, DraggablePanelHeader, Flexbox, Form, FormGroup, FormItem, Highlighter, Image, Input, List, Markdown, Menu, Modal, SearchBar, Segmented, Select, SideNav, Tag, TextArea, Tooltip } from '@lobehub/ui';
4
- export { Spotlight } from '@lobehub/ui/awesome';
5
4
  export { ChatInputArea, ChatItem, ChatList, MessageInput, MessageModal } from '@lobehub/ui/chat';
6
- import { Cross, Paperclip, Globe, Brain, FolderClosed, StopCircle, ArrowUp, Microphone, LoaderCircle, EyeOff, Eye, Bell, ChevronRight, CrossSmall, CheckCircle, PlayCircle, Users, MoreHorizontal, DoubleCheck, Check, FacePlus, PaperAirplane } from '@nebutra/icons';
7
- import { Square } from '@phosphor-icons/react/dist/ssr';
8
- import { motion, AnimatePresence, useReducedMotion, LazyMotion, domAnimation, m } from 'framer-motion';
5
+ export { default as Spotlight } from '@lobehub/ui/es/awesome/Spotlight/Spotlight';
6
+ import { motion, AnimatePresence, useReducedMotion, m, LazyMotion, domAnimation } from 'framer-motion';
7
+ export { AnimatePresence, LayoutGroup, LazyMotion, MotionConfig, animate, domAnimation, m, motion, useAnimationFrame, useInView, useMotionTemplate, useMotionValue, useReducedMotion, useScroll, useSpring, useTransform, useVelocity } from 'framer-motion';
8
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
+ import { Cross, Bell, ChevronRight, CrossSmall, CheckCircle, PlayCircle, Users, MoreHorizontal, DoubleCheck, Check, FacePlus, PaperAirplane, Paperclip, StopFill, StopCircle, ArrowUp, Microphone, LoaderCircle, EyeOff, Eye, Globe, Brain, FolderClosed } from '@nebutra/icons';
9
10
  import Image from 'next/image';
10
- import * as React6 from 'react';
11
- import React6__default, { useId, useState, useMemo, useCallback } from 'react';
12
- import { cva } from 'class-variance-authority';
11
+ import { Dialog as Dialog$1 } from '@base-ui/react/dialog';
12
+ import * as React5 from 'react';
13
+ import React5__default, { useEffectEvent, useId, useState } from 'react';
14
+ import { colors, emerge, flow, brandSpring } from '@nebutra/brand';
13
15
  import { clsx } from 'clsx';
14
16
  import { twMerge } from 'tailwind-merge';
15
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
16
- import { Dialog as Dialog$1 } from '@base-ui/react/dialog';
17
- import { colors, flow, emerge, brandSpring } from '@nebutra/brand';
17
+ import { cva } from 'class-variance-authority';
18
18
  import { Tooltip as Tooltip$1 } from '@base-ui/react/tooltip';
19
19
  import { useAsciiText, slant } from 'react-ascii-text';
20
- import { Handle, Position, ReactFlowProvider, ReactFlow, Background, Controls, Panel } from '@xyflow/react';
20
+ import { ReactFlowProvider, ReactFlow, Background, Controls, Panel, Handle, Position } from '@xyflow/react';
21
21
  import '@xyflow/react/dist/style.css';
22
22
  import { wouldCreateCycle } from '@nebutra/graph-model';
23
23
  import { Input as Input$1 } from '@base-ui/react/input';
24
24
 
25
25
  // src/components/index.ts
26
+
27
+ // src/shared/animation/motion/tokens.ts
28
+ var animationDurations = {
29
+ instant: 0,
30
+ micro: 0.1,
31
+ fast: 0.16,
32
+ standard: 0.2,
33
+ reveal: 0.3,
34
+ page: 0.44
35
+ };
36
+ var animationEasings = {
37
+ linear: "linear",
38
+ enter: [0, 0, 0.2, 1],
39
+ exit: [0.4, 0, 1, 1],
40
+ standard: [0.4, 0, 0.2, 1],
41
+ emphasized: [0.16, 1, 0.3, 1]
42
+ };
43
+ var animationSprings = {
44
+ interactive: { type: "spring", stiffness: 380, damping: 34, mass: 0.8 },
45
+ layout: { type: "spring", stiffness: 480, damping: 42, mass: 1 },
46
+ panel: { type: "spring", stiffness: 320, damping: 36, mass: 1 }
47
+ };
48
+ var animationDistances = {
49
+ xs: 4,
50
+ sm: 8,
51
+ md: 16,
52
+ lg: 24,
53
+ panel: 32
54
+ };
55
+ var animationTransitions = {
56
+ instant: { duration: animationDurations.instant },
57
+ micro: { duration: animationDurations.micro, ease: animationEasings.enter },
58
+ standard: { duration: animationDurations.standard, ease: animationEasings.enter },
59
+ reveal: { duration: animationDurations.reveal, ease: animationEasings.emphasized },
60
+ page: { duration: animationDurations.page, ease: animationEasings.emphasized },
61
+ layout: animationSprings.layout,
62
+ panel: animationSprings.panel
63
+ };
64
+
65
+ // src/shared/animation/motion/variants.ts
66
+ var fadeIn = {
67
+ initial: { opacity: 0 },
68
+ animate: { opacity: 1, transition: animationTransitions.standard },
69
+ exit: { opacity: 0, transition: animationTransitions.micro }
70
+ };
71
+ var scaleIn = {
72
+ initial: { opacity: 0, scale: 0.96 },
73
+ animate: { opacity: 1, scale: 1, transition: animationTransitions.reveal },
74
+ exit: { opacity: 0, scale: 0.98, transition: animationTransitions.micro }
75
+ };
76
+ var slideIn = {
77
+ up: {
78
+ initial: { opacity: 0, y: animationDistances.md },
79
+ animate: { opacity: 1, y: 0, transition: animationTransitions.reveal },
80
+ exit: { opacity: 0, y: animationDistances.sm, transition: animationTransitions.micro }
81
+ },
82
+ down: {
83
+ initial: { opacity: 0, y: -animationDistances.md },
84
+ animate: { opacity: 1, y: 0, transition: animationTransitions.reveal },
85
+ exit: { opacity: 0, y: -animationDistances.sm, transition: animationTransitions.micro }
86
+ },
87
+ left: {
88
+ initial: { opacity: 0, x: animationDistances.md },
89
+ animate: { opacity: 1, x: 0, transition: animationTransitions.reveal },
90
+ exit: { opacity: 0, x: animationDistances.sm, transition: animationTransitions.micro }
91
+ },
92
+ right: {
93
+ initial: { opacity: 0, x: -animationDistances.md },
94
+ animate: { opacity: 1, x: 0, transition: animationTransitions.reveal },
95
+ exit: { opacity: 0, x: -animationDistances.sm, transition: animationTransitions.micro }
96
+ }
97
+ };
98
+ var animatedList = {
99
+ initial: {},
100
+ animate: { transition: { staggerChildren: 0.06, delayChildren: 0.02 } },
101
+ exit: { transition: { staggerChildren: 0.03, staggerDirection: -1 } }
102
+ };
103
+ var animatedListItem = {
104
+ initial: { opacity: 0, y: animationDistances.sm },
105
+ animate: { opacity: 1, y: 0, transition: animationTransitions.standard },
106
+ exit: { opacity: 0, y: animationDistances.xs, transition: animationTransitions.micro }
107
+ };
108
+ var modalSurface = {
109
+ initial: { opacity: 0, scale: 0.98, y: animationDistances.sm },
110
+ animate: { opacity: 1, scale: 1, y: 0, transition: animationTransitions.panel },
111
+ exit: {
112
+ opacity: 0,
113
+ scale: 0.98,
114
+ y: animationDistances.xs,
115
+ transition: animationTransitions.micro
116
+ }
117
+ };
118
+ var drawerSurface = {
119
+ left: {
120
+ initial: { opacity: 0, x: "-100%" },
121
+ animate: { opacity: 1, x: 0, transition: animationTransitions.panel },
122
+ exit: { opacity: 0, x: "-100%", transition: animationTransitions.micro }
123
+ },
124
+ right: {
125
+ initial: { opacity: 0, x: "100%" },
126
+ animate: { opacity: 1, x: 0, transition: animationTransitions.panel },
127
+ exit: { opacity: 0, x: "100%", transition: animationTransitions.micro }
128
+ },
129
+ top: {
130
+ initial: { opacity: 0, y: "-100%" },
131
+ animate: { opacity: 1, y: 0, transition: animationTransitions.panel },
132
+ exit: { opacity: 0, y: "-100%", transition: animationTransitions.micro }
133
+ },
134
+ bottom: {
135
+ initial: { opacity: 0, y: "100%" },
136
+ animate: { opacity: 1, y: 0, transition: animationTransitions.panel },
137
+ exit: { opacity: 0, y: "100%", transition: animationTransitions.micro }
138
+ }
139
+ };
140
+ var popoverSurface = {
141
+ initial: { opacity: 0, scale: 0.98, y: animationDistances.xs },
142
+ animate: { opacity: 1, scale: 1, y: 0, transition: animationTransitions.standard },
143
+ exit: {
144
+ opacity: 0,
145
+ scale: 0.98,
146
+ y: animationDistances.xs,
147
+ transition: animationTransitions.micro
148
+ }
149
+ };
150
+ var pageTransition = {
151
+ initial: { opacity: 0, y: animationDistances.sm },
152
+ animate: { opacity: 1, y: 0, transition: animationTransitions.page },
153
+ exit: { opacity: 0, y: -animationDistances.xs, transition: animationTransitions.standard }
154
+ };
155
+ var reducedMotionVariants = {
156
+ initial: { opacity: 0 },
157
+ animate: { opacity: 1, transition: animationTransitions.instant },
158
+ exit: { opacity: 0, transition: animationTransitions.instant }
159
+ };
160
+ function useAccessibleVariants(variants, allowTransform = false) {
161
+ const shouldReduceMotion = useReducedMotion();
162
+ return shouldReduceMotion && !allowTransform ? reducedMotionVariants : variants;
163
+ }
164
+ function FadeIn({ children, ...props }) {
165
+ const variants = useAccessibleVariants(fadeIn);
166
+ return /* @__PURE__ */ jsx(motion.div, { initial: "initial", animate: "animate", exit: "exit", variants, ...props, children });
167
+ }
168
+ function SlideIn({
169
+ children,
170
+ direction = "up",
171
+ ...props
172
+ }) {
173
+ const variants = useAccessibleVariants(slideIn[direction]);
174
+ return /* @__PURE__ */ jsx(motion.div, { initial: "initial", animate: "animate", exit: "exit", variants, ...props, children });
175
+ }
176
+ function ScaleIn({ children, ...props }) {
177
+ const variants = useAccessibleVariants(scaleIn);
178
+ return /* @__PURE__ */ jsx(motion.div, { initial: "initial", animate: "animate", exit: "exit", variants, ...props, children });
179
+ }
180
+ function AnimatedCard({ children, ...props }) {
181
+ return /* @__PURE__ */ jsx(ScaleIn, { whileHover: { y: -2 }, whileTap: { scale: 0.99 }, ...props, children });
182
+ }
183
+ function AnimatedList({ children, ...props }) {
184
+ const containerVariants2 = useAccessibleVariants(animatedList);
185
+ const itemVariants2 = useAccessibleVariants(animatedListItem);
186
+ return /* @__PURE__ */ jsx(
187
+ motion.div,
188
+ {
189
+ initial: "initial",
190
+ animate: "animate",
191
+ exit: "exit",
192
+ variants: containerVariants2,
193
+ ...props,
194
+ children: Array.isArray(children) ? children.map((child, index) => /* @__PURE__ */ jsx(motion.div, { variants: itemVariants2, children: child }, index)) : children
195
+ }
196
+ );
197
+ }
198
+ function AnimatedModal({ children, open, ...props }) {
199
+ const variants = useAccessibleVariants(modalSurface);
200
+ return /* @__PURE__ */ jsx(AnimatePresence, { children: open ? /* @__PURE__ */ jsx(motion.div, { initial: "initial", animate: "animate", exit: "exit", variants, ...props, children }) : null });
201
+ }
202
+ function AnimatedDrawer({
203
+ children,
204
+ open,
205
+ side = "right",
206
+ ...props
207
+ }) {
208
+ const variants = useAccessibleVariants(drawerSurface[side]);
209
+ return /* @__PURE__ */ jsx(AnimatePresence, { children: open ? /* @__PURE__ */ jsx(motion.div, { initial: "initial", animate: "animate", exit: "exit", variants, ...props, children }) : null });
210
+ }
211
+ function AnimatedPopover({
212
+ children,
213
+ open,
214
+ ...props
215
+ }) {
216
+ const variants = useAccessibleVariants(popoverSurface);
217
+ return /* @__PURE__ */ jsx(AnimatePresence, { children: open ? /* @__PURE__ */ jsx(motion.div, { initial: "initial", animate: "animate", exit: "exit", variants, ...props, children }) : null });
218
+ }
219
+ function PageTransition({ children, ...props }) {
220
+ const variants = useAccessibleVariants(pageTransition);
221
+ return /* @__PURE__ */ jsx(motion.div, { initial: "initial", animate: "animate", exit: "exit", variants, ...props, children });
222
+ }
223
+ ({
224
+ // Nebutra Blue (云毓蓝) — technology & trust — VI: #0033FE
225
+ blue50: colors.primary[50],
226
+ blue100: colors.primary[100],
227
+ blue200: colors.primary[200],
228
+ blue300: colors.primary[300],
229
+ blue400: colors.primary[400],
230
+ blue500: colors.primary[500],
231
+ // brand primary
232
+ blue600: colors.primary[600],
233
+ blue700: colors.primary[700],
234
+ blue800: colors.primary[800],
235
+ blue900: colors.primary[900],
236
+ blue950: colors.primary[950],
237
+ // Nebutra Cyan (云毓青) — data flow & intelligence — VI: #0BF1C3
238
+ cyan50: colors.accent[50],
239
+ cyan100: colors.accent[100],
240
+ cyan200: colors.accent[200],
241
+ cyan300: colors.accent[300],
242
+ cyan400: colors.accent[400],
243
+ cyan500: colors.accent[500],
244
+ // brand secondary
245
+ cyan600: colors.accent[600],
246
+ cyan700: colors.accent[700],
247
+ cyan800: colors.accent[800],
248
+ cyan900: colors.accent[900],
249
+ cyan950: colors.accent[950],
250
+ // Neutral (blue-undertone gray scale)
251
+ neutral50: colors.neutral[50],
252
+ neutral100: colors.neutral[100],
253
+ neutral200: colors.neutral[200],
254
+ neutral300: colors.neutral[300],
255
+ neutral400: colors.neutral[400],
256
+ neutral500: colors.neutral[500],
257
+ neutral600: colors.neutral[600],
258
+ neutral700: colors.neutral[700],
259
+ neutral800: colors.neutral[800],
260
+ neutral900: colors.neutral[900],
261
+ neutral950: colors.neutral[950],
262
+ white: colors.white,
263
+ black: colors.black
264
+ });
265
+ ({
266
+ /** Hero sections, primary CTA buttons, logo fills — VI signature gradient */
267
+ primary: colors.gradient.primary,
268
+ /** Hover states, secondary gradient elements */
269
+ reverse: colors.gradient.primaryReverse,
270
+ /** Vertical layout dividers, page section separators */
271
+ vertical: colors.gradient.primaryVertical,
272
+ /** Background halos, focus glow effects, radial emphasis */
273
+ radial: colors.gradient.primaryRadial});
274
+ var primitiveSpacing = {
275
+ 1: 4,
276
+ 2: 8,
277
+ 3: 12,
278
+ 4: 16,
279
+ 20: 80,
280
+ 24: 96
281
+ };
282
+ var primitiveSizing = {
283
+ xs: 20,
284
+ /** Geist button-specific size (24px). Larger than xs by design. */
285
+ tiny: 24,
286
+ sm: 32,
287
+ md: 40,
288
+ lg: 48};
289
+ var primitiveRadius = {
290
+ md: 6,
291
+ // Geist default — slightly more rounded than 4px
292
+ lg: 8};
293
+ var primitiveFontSize = {
294
+ xs: 12,
295
+ sm: 14,
296
+ base: 16};
297
+
298
+ // src/tokens/shadows.ts
299
+ var shadowClasses = {
300
+ md: "shadow-md",
301
+ "2xl": "shadow-2xl"};
302
+
303
+ // src/tokens/components/overlay.ts
304
+ var overlayFocusRingClassName = "outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2";
305
+ var overlayZIndex = {
306
+ backdrop: 1040,
307
+ modal: 1050,
308
+ tooltip: 1070
309
+ };
310
+ var overlayClassNames = {
311
+ backdrop: "fixed inset-0 bg-black/40 backdrop-blur-sm transition-[opacity,display] duration-[var(--motion-duration-flow)] ease-[var(--ease-out)] data-ending-style:opacity-0 data-starting-style:opacity-0 motion-reduce:transition-none",
312
+ modalSurface: [
313
+ "fixed left-1/2 top-1/2 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4",
314
+ "border border-border/60 bg-background/95 p-6 text-foreground backdrop-blur-xl",
315
+ "rounded-[var(--radius-xl)]",
316
+ shadowClasses["2xl"],
317
+ "outline-none",
318
+ "transition-[opacity,transform,display] duration-[var(--motion-duration-flow)] ease-[var(--ease-out)]",
319
+ "data-starting-style:scale-95 data-starting-style:opacity-0 data-ending-style:scale-95 data-ending-style:opacity-0",
320
+ "motion-reduce:transition-none motion-reduce:data-starting-style:transform-none motion-reduce:data-ending-style:transform-none"
321
+ ].join(" "),
322
+ tooltipSurface: [
323
+ "overflow-hidden rounded-[var(--radius-md)] border border-border/70 bg-popover/95 px-3 py-1.5 text-sm text-popover-foreground backdrop-blur-md",
324
+ shadowClasses.md,
325
+ "transition-[opacity,transform,display] duration-[var(--motion-duration-flow)] ease-[var(--ease-out)]",
326
+ "data-starting-style:scale-95 data-starting-style:opacity-0 data-ending-style:scale-95 data-ending-style:opacity-0",
327
+ "motion-reduce:transition-none motion-reduce:data-starting-style:transform-none motion-reduce:data-ending-style:transform-none"
328
+ ].join(" "),
329
+ closeButton: `absolute right-4 top-4 rounded-[var(--radius-sm)] opacity-70 ring-offset-background ${overlayFocusRingClassName} transition-opacity duration-[var(--motion-duration-micro)] ease-[var(--ease-out)] hover:opacity-100 disabled:pointer-events-none data-[open]:bg-accent data-[open]:text-muted-foreground motion-reduce:transition-none`
330
+ };
26
331
  function cn(...inputs) {
27
332
  return twMerge(clsx(inputs));
28
333
  }
29
- var Slot = React6.forwardRef(
334
+ var overlayPrimitiveClassNames = {
335
+ modalSurface: "rounded-[var(--radius-md)] border-border/70 bg-popover/95 text-popover-foreground shadow-xl"};
336
+ var Dialog = Dialog$1.Root;
337
+ var DialogPortal = Dialog$1.Portal;
338
+ var DialogTrigger = ({
339
+ asChild,
340
+ children,
341
+ ref,
342
+ ...props
343
+ }) => {
344
+ if (asChild && React5.isValidElement(children)) {
345
+ return /* @__PURE__ */ jsx(
346
+ Dialog$1.Trigger,
347
+ {
348
+ ref,
349
+ ...props,
350
+ render: children
351
+ }
352
+ );
353
+ }
354
+ return /* @__PURE__ */ jsx(Dialog$1.Trigger, { ref, ...props, children });
355
+ };
356
+ DialogTrigger.displayName = "DialogTrigger";
357
+ var DialogClose = ({
358
+ asChild,
359
+ children,
360
+ ref,
361
+ ...props
362
+ }) => {
363
+ if (asChild && React5.isValidElement(children)) {
364
+ return /* @__PURE__ */ jsx(
365
+ Dialog$1.Close,
366
+ {
367
+ ref,
368
+ ...props,
369
+ render: children
370
+ }
371
+ );
372
+ }
373
+ return /* @__PURE__ */ jsx(Dialog$1.Close, { ref, ...props, children });
374
+ };
375
+ DialogClose.displayName = "DialogClose";
376
+ var DialogOverlay = ({
377
+ className,
378
+ style,
379
+ ref,
380
+ ...props
381
+ }) => /* @__PURE__ */ jsx(
382
+ Dialog$1.Backdrop,
383
+ {
384
+ ref,
385
+ className: cn(overlayClassNames.backdrop, className),
386
+ style: { zIndex: overlayZIndex.backdrop, ...style },
387
+ ...props
388
+ }
389
+ );
390
+ DialogOverlay.displayName = "DialogOverlay";
391
+ var DialogContent = ({
392
+ className,
393
+ children,
394
+ style,
395
+ ref,
396
+ ...props
397
+ }) => /* @__PURE__ */ jsxs(DialogPortal, { children: [
398
+ /* @__PURE__ */ jsx(DialogOverlay, {}),
399
+ /* @__PURE__ */ jsxs(
400
+ Dialog$1.Popup,
401
+ {
402
+ ref,
403
+ className: cn(
404
+ overlayClassNames.modalSurface,
405
+ overlayPrimitiveClassNames.modalSurface,
406
+ className
407
+ ),
408
+ style: { zIndex: overlayZIndex.modal, ...style },
409
+ ...props,
410
+ children: [
411
+ children,
412
+ /* @__PURE__ */ jsxs(DialogClose, { className: overlayClassNames.closeButton, children: [
413
+ /* @__PURE__ */ jsx(Cross, { className: "h-4 w-4" }),
414
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
415
+ ] })
416
+ ]
417
+ }
418
+ )
419
+ ] });
420
+ DialogContent.displayName = "DialogContent";
421
+ var DialogTitle = ({
422
+ className,
423
+ ref,
424
+ ...props
425
+ }) => /* @__PURE__ */ jsx(
426
+ Dialog$1.Title,
427
+ {
428
+ ref,
429
+ className: cn("text-lg font-semibold leading-none tracking-tight", className),
430
+ ...props
431
+ }
432
+ );
433
+ DialogTitle.displayName = "DialogTitle";
434
+ var isImageFile = (file) => file.type.startsWith("image/");
435
+ var getFilePreviewKey = (file) => `${file.name}-${file.size}-${file.lastModified}`;
436
+ var preventDragDefaults = (e) => {
437
+ e.preventDefault();
438
+ e.stopPropagation();
439
+ };
440
+ var ImageViewDialog = ({ imageUrl, onClose }) => {
441
+ const shouldReduceMotion = useReducedMotion();
442
+ if (!imageUrl) return null;
443
+ return /* @__PURE__ */ jsx(Dialog, { open: !!imageUrl, onOpenChange: onClose, children: /* @__PURE__ */ jsxs(DialogContent, { className: "p-0 border-none bg-transparent shadow-none max-w-[90vw] md:max-w-[800px]", children: [
444
+ /* @__PURE__ */ jsx(DialogTitle, { className: "sr-only", children: "Image Preview" }),
445
+ /* @__PURE__ */ jsx(
446
+ m.div,
447
+ {
448
+ initial: shouldReduceMotion ? { opacity: 1 } : { opacity: 0, scale: 0.95 },
449
+ animate: { opacity: 1, ...shouldReduceMotion ? {} : { scale: 1 } },
450
+ exit: shouldReduceMotion ? { opacity: 0 } : { opacity: 0, scale: 0.95 },
451
+ transition: shouldReduceMotion ? { duration: 0 } : { duration: 0.2, ease: "easeOut" },
452
+ className: "relative bg-background rounded-[var(--radius-2xl)] overflow-hidden shadow-2xl",
453
+ children: /* @__PURE__ */ jsx(
454
+ Image,
455
+ {
456
+ src: imageUrl,
457
+ alt: "Full preview",
458
+ className: "w-full max-h-[80vh] object-contain rounded-[var(--radius-2xl)]",
459
+ fill: true,
460
+ sizes: "(max-width: 768px) 90vw, 800px"
461
+ }
462
+ )
463
+ }
464
+ )
465
+ ] }) });
466
+ };
467
+ ImageViewDialog.displayName = "ImageViewDialog";
468
+ function PromptAttachmentPreviews({
469
+ files,
470
+ filePreviews,
471
+ isRecording,
472
+ onPreview,
473
+ onRemove
474
+ }) {
475
+ if (files.length === 0 || isRecording) return null;
476
+ return /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 p-0 pb-1 transition-[background-color,border-color,box-shadow,color,opacity,transform] duration-300 motion-reduce:transition-none", children: files.map((file) => {
477
+ const previewKey = getFilePreviewKey(file);
478
+ const preview = filePreviews[previewKey];
479
+ return /* @__PURE__ */ jsx("div", { className: "relative group h-16 w-16", children: isImageFile(file) && preview && /* @__PURE__ */ jsxs(Fragment, { children: [
480
+ /* @__PURE__ */ jsx(
481
+ "button",
482
+ {
483
+ type: "button",
484
+ "aria-label": `Preview ${file.name}`,
485
+ className: "relative h-16 w-16 rounded-[var(--radius-xl)] overflow-hidden cursor-pointer transition-[background-color,border-color,box-shadow,color,opacity,transform] duration-300 motion-reduce:transition-none",
486
+ onClick: () => onPreview(preview),
487
+ children: /* @__PURE__ */ jsx(
488
+ Image,
489
+ {
490
+ src: preview,
491
+ alt: file.name,
492
+ className: "h-full w-full object-cover",
493
+ fill: true,
494
+ sizes: "64px"
495
+ }
496
+ )
497
+ }
498
+ ),
499
+ /* @__PURE__ */ jsx(
500
+ "button",
501
+ {
502
+ type: "button",
503
+ "aria-label": `Remove ${file.name}`,
504
+ onClick: (event) => {
505
+ event.stopPropagation();
506
+ onRemove(file);
507
+ },
508
+ className: "absolute top-1 right-1 rounded-full bg-black/70 p-0.5 opacity-100 transition-opacity motion-reduce:transition-none",
509
+ children: /* @__PURE__ */ jsx(Cross, { className: "h-3 w-3 text-white" })
510
+ }
511
+ )
512
+ ] }) }, previewKey);
513
+ }) });
514
+ }
515
+ var Slot = React5.forwardRef(
30
516
  ({ children, className, style, ...props }, ref) => {
31
- const childArray = React6.Children.toArray(children);
517
+ const childArray = React5.Children.toArray(children);
32
518
  const child = childArray.length === 1 ? childArray[0] : null;
33
- if (child == null || !React6.isValidElement(child)) {
519
+ if (child == null || !React5.isValidElement(child)) {
34
520
  return /* @__PURE__ */ jsx("span", { ref, className, style, ...props, children });
35
521
  }
36
522
  const childProps = child.props;
37
523
  const mergedRef = (node) => {
38
524
  if (typeof ref === "function") ref(node);
39
525
  else if (ref) ref.current = node;
40
- const childRef = child.ref;
526
+ const childRef = childProps.ref;
41
527
  if (typeof childRef === "function") childRef(node);
42
528
  else if (childRef && "current" in childRef) {
43
529
  childRef.current = node;
@@ -51,7 +537,7 @@ var Slot = React6.forwardRef(
51
537
  className: mergedClass,
52
538
  style: { ...childProps.style, ...style }
53
539
  };
54
- return React6.cloneElement(
540
+ return React5.cloneElement(
55
541
  child,
56
542
  merged
57
543
  );
@@ -61,8 +547,9 @@ Slot.displayName = "Slot";
61
547
  var buttonVariants = cva(
62
548
  [
63
549
  "inline-flex items-center justify-center gap-2 whitespace-nowrap",
64
- "rounded-[var(--radius-md)] text-sm font-medium",
65
- "transition-colors duration-150 ease-out",
550
+ "rounded-[var(--btn-default-radius,var(--radius-md))]",
551
+ "text-[length:var(--control-font-size-md,0.875rem)] font-[number:var(--font-weight-medium,500)]",
552
+ "transition-colors duration-micro ease-out",
66
553
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
67
554
  "disabled:pointer-events-none disabled:opacity-50",
68
555
  "aria-busy:cursor-wait"
@@ -70,8 +557,9 @@ var buttonVariants = cva(
70
557
  {
71
558
  variants: {
72
559
  variant: {
73
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
74
- ink: "bg-[var(--neutral-12)] text-[var(--neutral-1)] ring-1 ring-inset ring-white/[0.04] hover:bg-[var(--neutral-11)] hover:-translate-y-px active:translate-y-0 transition-[transform,background-color] duration-150",
560
+ // Recipe-driven via packages/design/tokens/recipe.css (.btn-brand-default)
561
+ default: "btn-brand-default",
562
+ ink: "bg-[var(--neutral-12)] text-[var(--neutral-1)] ring-1 ring-inset ring-[color:var(--neutral-1)]/5 hover:bg-[var(--neutral-11)] hover:-translate-y-px active:translate-y-0 transition-[transform,background-color] duration-micro",
75
563
  destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
76
564
  outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
77
565
  secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
@@ -81,16 +569,11 @@ var buttonVariants = cva(
81
569
  warning: "bg-warning text-warning-foreground hover:bg-warning/90"
82
570
  },
83
571
  size: {
84
- tiny: "h-6 rounded-[var(--radius-sm)] px-2 text-[11px]",
85
- // 24px
86
- sm: "h-8 rounded-[var(--radius-sm)] px-3 text-xs",
87
- // 32px
88
- default: "h-10 px-4 py-2",
89
- // 40px
90
- lg: "h-12 rounded-[var(--radius-lg)] px-5 text-base",
91
- // 48px
92
- icon: "h-10 w-10"
93
- // 40×40px (kept for backward compat)
572
+ tiny: "h-[var(--control-height-tiny,1.5rem)] rounded-[var(--radius-sm)] px-2 text-[length:var(--control-font-size-tiny,0.6875rem)]",
573
+ sm: "h-[var(--control-height-sm,2rem)] rounded-[var(--radius-sm)] px-3 text-[length:var(--control-font-size-sm,0.75rem)]",
574
+ default: "h-[var(--control-height-md,2.5rem)] px-[var(--btn-default-padding-x,1rem)] py-[var(--btn-default-padding-y,0.5rem)]",
575
+ lg: "h-[var(--control-height-lg,3rem)] rounded-[var(--radius-lg)] px-5 text-[length:var(--control-font-size-lg,1rem)]",
576
+ icon: "h-[var(--control-height-md,2.5rem)] w-[var(--control-height-md,2.5rem)]"
94
577
  },
95
578
  shape: {
96
579
  default: "",
@@ -99,16 +582,30 @@ var buttonVariants = cva(
99
582
  }
100
583
  },
101
584
  compoundVariants: [
102
- // shape="square" — width = height, no horizontal padding
103
- { shape: "square", size: "tiny", className: "w-6 px-0" },
104
- { shape: "square", size: "sm", className: "w-8 px-0" },
105
- { shape: "square", size: "default", className: "w-10 px-0" },
106
- { shape: "square", size: "lg", className: "w-12 px-0" },
107
- // shape="circle" — width = height + rounded-full
108
- { shape: "circle", size: "tiny", className: "w-6 px-0 rounded-full" },
109
- { shape: "circle", size: "sm", className: "w-8 px-0 rounded-full" },
110
- { shape: "circle", size: "default", className: "w-10 px-0 rounded-full" },
111
- { shape: "circle", size: "lg", className: "w-12 px-0 rounded-full" }
585
+ { shape: "square", size: "tiny", className: "w-[var(--control-height-tiny,1.5rem)] px-0" },
586
+ { shape: "square", size: "sm", className: "w-[var(--control-height-sm,2rem)] px-0" },
587
+ { shape: "square", size: "default", className: "w-[var(--control-height-md,2.5rem)] px-0" },
588
+ { shape: "square", size: "lg", className: "w-[var(--control-height-lg,3rem)] px-0" },
589
+ {
590
+ shape: "circle",
591
+ size: "tiny",
592
+ className: "w-[var(--control-height-tiny,1.5rem)] px-0 rounded-full"
593
+ },
594
+ {
595
+ shape: "circle",
596
+ size: "sm",
597
+ className: "w-[var(--control-height-sm,2rem)] px-0 rounded-full"
598
+ },
599
+ {
600
+ shape: "circle",
601
+ size: "default",
602
+ className: "w-[var(--control-height-md,2.5rem)] px-0 rounded-full"
603
+ },
604
+ {
605
+ shape: "circle",
606
+ size: "lg",
607
+ className: "w-[var(--control-height-lg,3rem)] px-0 rounded-full"
608
+ }
112
609
  ],
113
610
  defaultVariants: {
114
611
  variant: "default",
@@ -162,7 +659,7 @@ function getSpinnerSizeClass(size) {
162
659
  var SHADOW_CLASSES = {
163
660
  sm: "shadow-sm",
164
661
  md: "shadow-md",
165
- lg: "shadow-lg"
662
+ lg: "shadow-md"
166
663
  };
167
664
  function resolveShadowClass(shadow) {
168
665
  if (!shadow) return void 0;
@@ -178,253 +675,37 @@ function ButtonContent({ loading, prefix, suffix, size, children }) {
178
675
  suffix != null && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: cn("shrink-0", iconSizeClass), children: suffix })
179
676
  ] });
180
677
  }
181
- var Button = React6.forwardRef(
182
- ({
183
- className,
184
- variant,
185
- size,
186
- shape,
187
- asChild = false,
188
- loading = false,
189
- disabled,
190
- prefix,
191
- suffix,
192
- shadow,
193
- children,
194
- ...props
195
- }, ref) => {
196
- const Comp = asChild ? Slot : "button";
197
- const isDisabled = disabled ?? loading;
198
- const shadowClass = resolveShadowClass(shadow);
199
- return /* @__PURE__ */ jsx(
200
- Comp,
201
- {
202
- ref,
203
- className: cn(buttonVariants({ variant, size, shape }), shadowClass, className),
204
- disabled: isDisabled,
205
- "aria-busy": loading || void 0,
206
- ...props,
207
- children: asChild ? children : /* @__PURE__ */ jsx(ButtonContent, { loading, prefix, suffix, size, children })
208
- }
209
- );
210
- }
211
- );
212
- Button.displayName = "Button";
213
- var ButtonLink = React6.forwardRef(
214
- ({
215
- className,
216
- variant,
217
- size,
218
- shape,
219
- prefix,
220
- suffix,
221
- shadow,
222
- loading = false,
223
- children,
224
- ...props
225
- }, ref) => {
226
- const shadowClass = resolveShadowClass(shadow);
227
- const loadingProps = loading ? {
228
- "aria-busy": "true",
229
- "aria-disabled": "true",
230
- tabIndex: -1
231
- } : {};
232
- return /* @__PURE__ */ jsx(
233
- "a",
234
- {
235
- ref,
236
- className: cn(
237
- buttonVariants({ variant, size, shape }),
238
- shadowClass,
239
- loading && "pointer-events-none opacity-50",
240
- className
241
- ),
242
- ...loadingProps,
243
- ...props,
244
- children: /* @__PURE__ */ jsx(ButtonContent, { loading, prefix, suffix, size, children })
245
- }
246
- );
247
- }
248
- );
249
- ButtonLink.displayName = "ButtonLink";
250
- var Dialog = Dialog$1.Root;
251
- var DialogPortal = Dialog$1.Portal;
252
- var DialogTrigger = React6.forwardRef(({ asChild, children, ...props }, ref) => {
253
- if (asChild && React6.isValidElement(children)) {
254
- return /* @__PURE__ */ jsx(
255
- Dialog$1.Trigger,
256
- {
257
- ref,
258
- ...props,
259
- render: children
260
- }
261
- );
262
- }
263
- return /* @__PURE__ */ jsx(Dialog$1.Trigger, { ref, ...props, children });
264
- });
265
- DialogTrigger.displayName = "DialogTrigger";
266
- var DialogClose = React6.forwardRef(({ asChild, children, ...props }, ref) => {
267
- if (asChild && React6.isValidElement(children)) {
268
- return /* @__PURE__ */ jsx(
269
- Dialog$1.Close,
270
- {
271
- ref,
272
- ...props,
273
- render: children
274
- }
275
- );
276
- }
277
- return /* @__PURE__ */ jsx(Dialog$1.Close, { ref, ...props, children });
278
- });
279
- DialogClose.displayName = "DialogClose";
280
- var DialogOverlay = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
281
- Dialog$1.Backdrop,
282
- {
283
- ref,
284
- className: cn(
285
- "fixed inset-0 z-50 bg-black/40 backdrop-blur-sm data-ending-style:animate-out data-starting-style:animate-in data-ending-style:fade-out-0 data-starting-style:fade-in-0 duration-300 transition-[opacity,display]",
286
- className
287
- ),
288
- ...props
289
- }
290
- ));
291
- DialogOverlay.displayName = "DialogOverlay";
292
- var DialogContent = React6.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs(DialogPortal, { children: [
293
- /* @__PURE__ */ jsx(DialogOverlay, {}),
294
- /* @__PURE__ */ jsxs(
295
- Dialog$1.Popup,
678
+ var Button = ({
679
+ className,
680
+ variant,
681
+ size,
682
+ shape,
683
+ asChild = false,
684
+ loading = false,
685
+ disabled,
686
+ prefix,
687
+ suffix,
688
+ shadow,
689
+ children,
690
+ ref,
691
+ ...props
692
+ }) => {
693
+ const Comp = asChild ? Slot : "button";
694
+ const isDisabled = Boolean(disabled || loading);
695
+ const shadowClass = resolveShadowClass(shadow);
696
+ return /* @__PURE__ */ jsx(
697
+ Comp,
296
698
  {
297
699
  ref,
298
- className: cn(
299
- "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border border-border/50 bg-background/90 p-6 shadow-2xl backdrop-blur-xl duration-300 transition-[opacity,transform,display] data-starting-style:animate-in data-ending-style:animate-out data-ending-style:fade-out-0 data-starting-style:fade-in-0 data-ending-style:zoom-out-95 data-starting-style:zoom-in-95 sm:rounded-2xl",
300
- className
301
- ),
700
+ className: cn(buttonVariants({ variant, size, shape }), shadowClass, className),
701
+ disabled: isDisabled,
702
+ "aria-busy": loading || void 0,
302
703
  ...props,
303
- children: [
304
- children,
305
- /* @__PURE__ */ jsxs(DialogClose, { className: "absolute right-4 top-4 rounded-[var(--radius-sm)] opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[open]:bg-accent data-[open]:text-muted-foreground", children: [
306
- /* @__PURE__ */ jsx(Cross, { className: "h-4 w-4" }),
307
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Close" })
308
- ] })
309
- ]
310
- }
311
- )
312
- ] }));
313
- DialogContent.displayName = "DialogContent";
314
- var DialogHeader = React6.forwardRef(
315
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
316
- "div",
317
- {
318
- ref,
319
- className: cn("flex flex-col space-y-1.5 text-center sm:text-left", className),
320
- ...props
704
+ children: asChild ? children : /* @__PURE__ */ jsx(ButtonContent, { loading, prefix, suffix, size, children })
321
705
  }
322
- )
323
- );
324
- DialogHeader.displayName = "DialogHeader";
325
- var DialogFooter = React6.forwardRef(
326
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx(
327
- "div",
328
- {
329
- ref,
330
- className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className),
331
- ...props
332
- }
333
- )
334
- );
335
- DialogFooter.displayName = "DialogFooter";
336
- var DialogTitle = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
337
- Dialog$1.Title,
338
- {
339
- ref,
340
- className: cn("text-lg font-semibold leading-none tracking-tight", className),
341
- ...props
342
- }
343
- ));
344
- DialogTitle.displayName = "DialogTitle";
345
- var DialogDescription = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
346
- Dialog$1.Description,
347
- {
348
- ref,
349
- className: cn("text-sm text-muted-foreground", className),
350
- ...props
351
- }
352
- ));
353
- DialogDescription.displayName = "DialogDescription";
354
- ({
355
- // Nebutra Blue (云毓蓝) — technology & trust — VI: #0033FE
356
- blue50: colors.primary[50],
357
- blue100: colors.primary[100],
358
- blue200: colors.primary[200],
359
- blue300: colors.primary[300],
360
- blue400: colors.primary[400],
361
- blue500: colors.primary[500],
362
- // brand primary
363
- blue600: colors.primary[600],
364
- blue700: colors.primary[700],
365
- blue800: colors.primary[800],
366
- blue900: colors.primary[900],
367
- blue950: colors.primary[950],
368
- // Nebutra Cyan (云毓青) — data flow & intelligence — VI: #0BF1C3
369
- cyan50: colors.accent[50],
370
- cyan100: colors.accent[100],
371
- cyan200: colors.accent[200],
372
- cyan300: colors.accent[300],
373
- cyan400: colors.accent[400],
374
- cyan500: colors.accent[500],
375
- // brand secondary
376
- cyan600: colors.accent[600],
377
- cyan700: colors.accent[700],
378
- cyan800: colors.accent[800],
379
- cyan900: colors.accent[900],
380
- cyan950: colors.accent[950],
381
- // Neutral (blue-undertone gray scale)
382
- neutral50: colors.neutral[50],
383
- neutral100: colors.neutral[100],
384
- neutral200: colors.neutral[200],
385
- neutral300: colors.neutral[300],
386
- neutral400: colors.neutral[400],
387
- neutral500: colors.neutral[500],
388
- neutral600: colors.neutral[600],
389
- neutral700: colors.neutral[700],
390
- neutral800: colors.neutral[800],
391
- neutral900: colors.neutral[900],
392
- neutral950: colors.neutral[950],
393
- white: colors.white,
394
- black: colors.black
395
- });
396
- ({
397
- /** Hero sections, primary CTA buttons, logo fills — VI signature gradient */
398
- primary: colors.gradient.primary,
399
- /** Hover states, secondary gradient elements */
400
- reverse: colors.gradient.primaryReverse,
401
- /** Vertical layout dividers, page section separators */
402
- vertical: colors.gradient.primaryVertical,
403
- /** Background halos, focus glow effects, radial emphasis */
404
- radial: colors.gradient.primaryRadial});
405
- var primitiveSpacing = {
406
- 1: 4,
407
- 2: 8,
408
- 3: 12,
409
- 4: 16,
410
- 20: 80,
411
- 24: 96
706
+ );
412
707
  };
413
- var primitiveSizing = {
414
- xs: 20,
415
- /** Geist button-specific size (24px). Larger than xs by design. */
416
- tiny: 24,
417
- sm: 32,
418
- md: 40,
419
- lg: 48};
420
- var primitiveRadius = {
421
- md: 6,
422
- // Geist default — slightly more rounded than 4px
423
- lg: 8};
424
- var primitiveFontSize = {
425
- xs: 12,
426
- sm: 14,
427
- base: 16};
708
+ Button.displayName = "Button";
428
709
 
429
710
  // src/tokens/components/textarea.ts
430
711
  var textareaTokens = {
@@ -454,6 +735,14 @@ var textareaTokens = {
454
735
  labelSize: primitiveFontSize.sm,
455
736
  focusRingWidth: 3,
456
737
  fieldGap: primitiveSpacing[2] - primitiveSpacing[1] / 2};
738
+
739
+ // src/primitives/form-control.ts
740
+ var formControlFocusClassNames = {
741
+ input: "outline-none focus:border-ring focus:ring-[length:var(--input-focus-ring-width)] focus:ring-ring/30",
742
+ textarea: "outline-none focus:border-ring focus:ring-[length:var(--textarea-focus-ring-width)] focus:ring-ring/30"};
743
+ var formControlInvalidClassNames = {
744
+ input: "aria-invalid:border-destructive/60 aria-invalid:focus:border-destructive aria-invalid:focus:ring-destructive/20",
745
+ textarea: "aria-invalid:border-destructive/60 aria-invalid:focus:border-destructive aria-invalid:focus:ring-destructive/20"};
457
746
  var fieldMessageClassName = "text-xs text-muted-foreground";
458
747
  var fieldErrorClassName = "text-xs font-medium text-destructive";
459
748
  function getTextareaStyle(size, style) {
@@ -482,82 +771,81 @@ function joinDescriptionIds(...ids) {
482
771
  function isInvalid(error, ariaInvalid) {
483
772
  return error === true || typeof error === "string" || ariaInvalid === true || ariaInvalid === "true";
484
773
  }
485
- var Textarea = React6.forwardRef(
486
- ({
487
- className,
488
- style,
489
- size = "md",
490
- label,
491
- description,
492
- error,
493
- fieldClassName,
494
- id,
495
- onChange,
496
- onValueChange,
497
- "aria-describedby": ariaDescribedBy,
498
- "aria-invalid": ariaInvalid,
499
- ...props
500
- }, ref) => {
501
- const baseId = React6.useId();
502
- const textareaId = id ?? (label || description || typeof error === "string" ? baseId : void 0);
503
- const resolvedInvalid = isInvalid(error, ariaInvalid);
504
- const descriptionId = description && textareaId ? `${textareaId}-description` : void 0;
505
- const errorId = typeof error === "string" && textareaId ? `${textareaId}-error` : void 0;
506
- const describedBy = joinDescriptionIds(ariaDescribedBy, descriptionId, errorId);
507
- const handleChange = React6.useCallback(
508
- (event) => {
509
- onValueChange?.(event.currentTarget.value);
510
- onChange?.(event);
511
- },
512
- [onChange, onValueChange]
513
- );
514
- const control = /* @__PURE__ */ jsx(
515
- "textarea",
516
- {
517
- className: cn(
518
- "flex min-h-[var(--textarea-min-height)] w-full resize-y rounded-[var(--textarea-radius)] border border-input bg-background",
519
- "px-[var(--textarea-padding-x)] py-[var(--textarea-padding-y)] text-[length:var(--textarea-font-size)] text-foreground shadow-[var(--shadow-xs)]",
520
- "transition-[background-color,border-color,box-shadow,color] duration-micro ease-out placeholder:text-muted-foreground",
521
- "outline-none focus:border-ring focus:ring-[length:var(--textarea-focus-ring-width)] focus:ring-ring/30",
522
- "disabled:cursor-not-allowed disabled:opacity-50 read-only:cursor-default read-only:bg-muted/70",
523
- "aria-invalid:border-destructive/60 aria-invalid:focus:border-destructive aria-invalid:focus:ring-destructive/20",
524
- className
525
- ),
526
- ref,
527
- id: textareaId,
528
- "aria-invalid": resolvedInvalid || void 0,
529
- "aria-describedby": describedBy,
530
- style: getTextareaStyle(size, style),
531
- onChange: handleChange,
532
- ...props
533
- }
534
- );
535
- if (!label && !description && typeof error !== "string" && !fieldClassName) {
536
- return control;
774
+ var Textarea = ({
775
+ className,
776
+ style,
777
+ size = "md",
778
+ label,
779
+ description,
780
+ error,
781
+ fieldClassName,
782
+ id,
783
+ onChange,
784
+ onValueChange,
785
+ "aria-describedby": ariaDescribedBy,
786
+ "aria-invalid": ariaInvalid,
787
+ ref,
788
+ ...props
789
+ }) => {
790
+ const baseId = React5.useId();
791
+ const textareaId = id ?? (label || description || typeof error === "string" ? baseId : void 0);
792
+ const resolvedInvalid = isInvalid(error, ariaInvalid);
793
+ const descriptionId = description && textareaId ? `${textareaId}-description` : void 0;
794
+ const errorId = typeof error === "string" && textareaId ? `${textareaId}-error` : void 0;
795
+ const describedBy = joinDescriptionIds(ariaDescribedBy, descriptionId, errorId);
796
+ const handleChange = React5.useCallback(
797
+ (event) => {
798
+ onValueChange?.(event.currentTarget.value);
799
+ onChange?.(event);
800
+ },
801
+ [onChange, onValueChange]
802
+ );
803
+ const control = /* @__PURE__ */ jsx(
804
+ "textarea",
805
+ {
806
+ className: cn(
807
+ "flex min-h-[var(--textarea-min-height)] w-full resize-y rounded-[var(--textarea-radius)] border border-input bg-background",
808
+ "px-[var(--textarea-padding-x)] py-[var(--textarea-padding-y)] text-[length:var(--textarea-font-size)] text-foreground shadow-xs",
809
+ "transition-[background-color,border-color,box-shadow,color] duration-micro ease-out placeholder:text-muted-foreground",
810
+ formControlFocusClassNames.textarea,
811
+ "disabled:cursor-not-allowed disabled:opacity-50 read-only:cursor-default read-only:bg-muted/70",
812
+ formControlInvalidClassNames.textarea,
813
+ className
814
+ ),
815
+ ref,
816
+ id: textareaId,
817
+ "aria-invalid": resolvedInvalid || void 0,
818
+ "aria-describedby": describedBy,
819
+ style: getTextareaStyle(size, style),
820
+ onChange: handleChange,
821
+ ...props
537
822
  }
538
- return /* @__PURE__ */ jsxs(
539
- "div",
540
- {
541
- "data-slot": "textarea-field",
542
- className: cn("grid gap-[var(--textarea-field-gap)]", fieldClassName),
543
- style: getTextareaFieldStyle(),
544
- children: [
545
- label && /* @__PURE__ */ jsx(
546
- "label",
547
- {
548
- htmlFor: textareaId,
549
- className: "text-[length:var(--textarea-label-size)] font-medium text-foreground",
550
- children: label
551
- }
552
- ),
553
- control,
554
- description && !error && /* @__PURE__ */ jsx("p", { id: descriptionId, className: fieldMessageClassName, children: description }),
555
- typeof error === "string" && /* @__PURE__ */ jsx("p", { id: errorId, role: "alert", className: fieldErrorClassName, children: error })
556
- ]
557
- }
558
- );
823
+ );
824
+ if (!label && !description && typeof error !== "string" && !fieldClassName) {
825
+ return control;
559
826
  }
560
- );
827
+ return /* @__PURE__ */ jsxs(
828
+ "div",
829
+ {
830
+ "data-slot": "textarea-field",
831
+ className: cn("grid gap-[var(--textarea-field-gap)]", fieldClassName),
832
+ style: getTextareaFieldStyle(),
833
+ children: [
834
+ label && /* @__PURE__ */ jsx(
835
+ "label",
836
+ {
837
+ htmlFor: textareaId,
838
+ className: "text-[length:var(--textarea-label-size)] font-medium text-foreground",
839
+ children: label
840
+ }
841
+ ),
842
+ control,
843
+ description && !error && /* @__PURE__ */ jsx("p", { id: descriptionId, className: fieldMessageClassName, children: description }),
844
+ typeof error === "string" && /* @__PURE__ */ jsx("p", { id: errorId, role: "alert", className: fieldErrorClassName, children: error })
845
+ ]
846
+ }
847
+ );
848
+ };
561
849
  Textarea.displayName = "Textarea";
562
850
  var DEFAULT_TOOLTIP_DELAY_MS = 150;
563
851
  var TooltipProvider = ({
@@ -574,8 +862,13 @@ var Tooltip = ({
574
862
  const delay = delayDuration ?? DEFAULT_TOOLTIP_DELAY_MS;
575
863
  return /* @__PURE__ */ jsx(Tooltip$1.Provider, { delay, children: /* @__PURE__ */ jsx(Tooltip$1.Root, { ...props, children }) });
576
864
  };
577
- var TooltipTrigger = React6.forwardRef(({ asChild, children, ...props }, ref) => {
578
- if (asChild && React6.isValidElement(children)) {
865
+ var TooltipTrigger = ({
866
+ asChild,
867
+ children,
868
+ ref,
869
+ ...props
870
+ }) => {
871
+ if (asChild && React5.isValidElement(children)) {
579
872
  return /* @__PURE__ */ jsx(
580
873
  Tooltip$1.Trigger,
581
874
  {
@@ -586,183 +879,147 @@ var TooltipTrigger = React6.forwardRef(({ asChild, children, ...props }, ref) =>
586
879
  );
587
880
  }
588
881
  return /* @__PURE__ */ jsx(Tooltip$1.Trigger, { ref, ...props, children });
589
- });
882
+ };
590
883
  TooltipTrigger.displayName = "TooltipTrigger";
591
- var TooltipContent = React6.forwardRef(
592
- ({ className, side = "top", align = "center", sideOffset = 4, alignOffset = 0, ...props }, ref) => /* @__PURE__ */ jsx(Tooltip$1.Portal, { children: /* @__PURE__ */ jsx(
593
- Tooltip$1.Positioner,
594
- {
595
- side,
596
- align,
597
- sideOffset,
598
- alignOffset,
599
- className: "z-50",
600
- children: /* @__PURE__ */ jsx(
601
- Tooltip$1.Popup,
602
- {
603
- ref,
604
- className: cn(
605
- "z-50 overflow-hidden rounded-xl border bg-background/90 backdrop-blur-md px-3 py-1.5 text-sm text-popover-foreground shadow-xl transition-[opacity,transform,display] duration-200 data-starting-style:animate-in data-starting-style:fade-in-0 data-starting-style:zoom-in-95 data-ending-style:animate-out data-ending-style:fade-out-0 data-ending-style:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
606
- className
607
- ),
608
- ...props
609
- }
610
- )
611
- }
612
- ) })
613
- );
884
+ var TooltipContent = ({
885
+ className,
886
+ style,
887
+ side = "top",
888
+ align = "center",
889
+ sideOffset = 4,
890
+ alignOffset = 0,
891
+ ref,
892
+ ...props
893
+ }) => /* @__PURE__ */ jsx(Tooltip$1.Portal, { children: /* @__PURE__ */ jsx(
894
+ Tooltip$1.Positioner,
895
+ {
896
+ side,
897
+ align,
898
+ sideOffset,
899
+ alignOffset,
900
+ style: { zIndex: overlayZIndex.tooltip },
901
+ children: /* @__PURE__ */ jsx(
902
+ Tooltip$1.Popup,
903
+ {
904
+ ref,
905
+ className: cn(overlayClassNames.tooltipSurface, className),
906
+ style: { zIndex: overlayZIndex.tooltip, ...style },
907
+ ...props
908
+ }
909
+ )
910
+ }
911
+ ) });
614
912
  TooltipContent.displayName = "TooltipContent";
615
- var cn2 = (...classes) => classes.filter(Boolean).join(" ");
913
+ var MAX_VISUALIZER_BARS = 64;
914
+ var VISUALIZER_BAR_STYLES = Array.from({ length: MAX_VISUALIZER_BARS }, (_, index) => ({
915
+ id: `voice-bar-${index}`,
916
+ height: `${15 + index * 37 % 86}%`,
917
+ animationDelay: `${index * 0.05}s`,
918
+ animationDuration: `${0.5 + index * 17 % 6 / 10}s`
919
+ }));
920
+ var formatRecordingTime = (seconds) => {
921
+ const mins = Math.floor(seconds / 60);
922
+ const secs = seconds % 60;
923
+ return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
924
+ };
616
925
  var VoiceRecorder = ({
617
926
  isRecording,
618
- onStartRecording,
619
- onStopRecording,
927
+ time,
620
928
  visualizerBars = 32
621
929
  }) => {
622
- const [time, setTime] = React6__default.useState(0);
623
- const timerRef = React6__default.useRef(null);
624
- React6__default.useEffect(() => {
625
- if (isRecording) {
626
- onStartRecording();
627
- timerRef.current = setInterval(() => setTime((t) => t + 1), 1e3);
628
- } else {
629
- if (timerRef.current) {
630
- clearInterval(timerRef.current);
631
- timerRef.current = null;
632
- }
633
- onStopRecording(time);
634
- setTime(0);
635
- }
636
- return () => {
637
- if (timerRef.current) clearInterval(timerRef.current);
638
- };
639
- }, [isRecording, time, onStartRecording, onStopRecording]);
640
- const formatTime = (seconds) => {
641
- const mins = Math.floor(seconds / 60);
642
- const secs = seconds % 60;
643
- return `${mins.toString().padStart(2, "0")}:${secs.toString().padStart(2, "0")}`;
644
- };
930
+ const barStyles = VISUALIZER_BAR_STYLES.slice(
931
+ 0,
932
+ Math.min(visualizerBars, VISUALIZER_BAR_STYLES.length)
933
+ );
645
934
  return /* @__PURE__ */ jsxs(
646
935
  "div",
647
936
  {
648
- className: cn2(
649
- "flex flex-col items-center justify-center w-full transition-all duration-300 py-3",
937
+ className: cn(
938
+ "flex flex-col items-center justify-center w-full transition-[background-color,border-color,box-shadow,color,opacity,transform] duration-300 py-3",
650
939
  isRecording ? "opacity-100" : "opacity-0 h-0"
651
940
  ),
652
941
  children: [
653
942
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-3", children: [
654
943
  /* @__PURE__ */ jsx("div", { className: "h-2 w-2 rounded-full bg-red-500 animate-pulse" }),
655
- /* @__PURE__ */ jsx("span", { className: "font-mono text-sm text-white/80", children: formatTime(time) })
944
+ /* @__PURE__ */ jsx("span", { className: "font-mono text-sm text-white/80", children: formatRecordingTime(time) })
656
945
  ] }),
657
- /* @__PURE__ */ jsx("div", { className: "w-full h-10 flex items-center justify-center gap-0.5 px-4", children: [...Array(visualizerBars)].map((_, i) => /* @__PURE__ */ jsx(
946
+ /* @__PURE__ */ jsx("div", { className: "w-full h-10 flex items-center justify-center gap-0.5 px-4", children: barStyles.map((bar) => /* @__PURE__ */ jsx(
658
947
  "div",
659
948
  {
660
949
  className: "w-0.5 rounded-full bg-white/50 animate-pulse",
661
950
  style: {
662
- height: `${Math.max(15, Math.random() * 100)}%`,
663
- animationDelay: `${i * 0.05}s`,
664
- animationDuration: `${0.5 + Math.random() * 0.5}s`
951
+ height: bar.height,
952
+ animationDelay: bar.animationDelay,
953
+ animationDuration: bar.animationDuration
665
954
  }
666
955
  },
667
- i
956
+ bar.id
668
957
  )) })
669
958
  ]
670
959
  }
671
960
  );
672
961
  };
673
- var ImageViewDialog = ({ imageUrl, onClose }) => {
674
- if (!imageUrl) return null;
675
- return /* @__PURE__ */ jsx(Dialog, { open: !!imageUrl, onOpenChange: onClose, children: /* @__PURE__ */ jsxs(DialogContent, { className: "p-0 border-none bg-transparent shadow-none max-w-[90vw] md:max-w-[800px]", children: [
676
- /* @__PURE__ */ jsx(DialogTitle, { className: "sr-only", children: "Image Preview" }),
677
- /* @__PURE__ */ jsx(
678
- motion.div,
679
- {
680
- initial: { opacity: 0, scale: 0.95 },
681
- animate: { opacity: 1, scale: 1 },
682
- exit: { opacity: 0, scale: 0.95 },
683
- transition: { duration: 0.2, ease: "easeOut" },
684
- className: "relative bg-background rounded-2xl overflow-hidden shadow-2xl",
685
- children: /* @__PURE__ */ jsx(
686
- Image,
687
- {
688
- src: imageUrl,
689
- alt: "Full preview",
690
- className: "w-full max-h-[80vh] object-contain rounded-2xl",
691
- fill: true
692
- }
693
- )
694
- }
695
- )
696
- ] }) });
962
+ VoiceRecorder.displayName = "VoiceRecorder";
963
+ var noopSetPromptValue = (_value) => {
697
964
  };
698
- var PromptInputContext = React6__default.createContext({
699
- isLoading: false,
700
- value: "",
701
- setValue: () => {
702
- },
703
- maxHeight: 240,
704
- onSubmit: void 0,
705
- disabled: false
706
- });
965
+ var PromptInputIsLoadingContext = React5__default.createContext(false);
966
+ var PromptInputValueContext = React5__default.createContext("");
967
+ var PromptInputSetValueContext = React5__default.createContext(noopSetPromptValue);
968
+ var PromptInputMaxHeightContext = React5__default.createContext(240);
969
+ var PromptInputSubmitContext = React5__default.createContext(void 0);
970
+ var PromptInputDisabledContext = React5__default.createContext(false);
707
971
  function usePromptInput() {
708
- const context = React6__default.useContext(PromptInputContext);
709
- if (!context) throw new Error("usePromptInput must be used within a PromptInput");
710
- return context;
972
+ return {
973
+ isLoading: React5__default.use(PromptInputIsLoadingContext),
974
+ value: React5__default.use(PromptInputValueContext),
975
+ setValue: React5__default.use(PromptInputSetValueContext),
976
+ maxHeight: React5__default.use(PromptInputMaxHeightContext),
977
+ onSubmit: React5__default.use(PromptInputSubmitContext),
978
+ disabled: React5__default.use(PromptInputDisabledContext)
979
+ };
711
980
  }
712
- var PromptInput = React6__default.forwardRef(
713
- ({
714
- className,
715
- isLoading = false,
716
- maxHeight = 240,
717
- value,
718
- onValueChange,
719
- onSubmit,
720
- children,
721
- disabled = false,
722
- onDragOver,
723
- onDragLeave,
724
- onDrop
725
- }, ref) => {
726
- const [internalValue, setInternalValue] = React6__default.useState(value || "");
727
- const handleChange = (newValue) => {
728
- setInternalValue(newValue);
729
- onValueChange?.(newValue);
730
- };
731
- return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(
732
- PromptInputContext.Provider,
733
- {
734
- value: {
735
- isLoading,
736
- value: value ?? internalValue,
737
- setValue: onValueChange ?? handleChange,
738
- maxHeight,
739
- onSubmit,
740
- disabled
741
- },
742
- children: /* @__PURE__ */ jsx(
743
- "div",
744
- {
745
- ref,
746
- className: cn2(
747
- "rounded-3xl border border-input bg-background p-2 shadow-lg transition-all duration-300",
748
- isLoading && "border-destructive/70",
749
- className
750
- ),
751
- onDragOver,
752
- onDragLeave,
753
- onDrop,
754
- children
755
- }
756
- )
757
- }
758
- ) });
759
- }
760
- );
981
+ var PromptInput = ({
982
+ className,
983
+ isLoading = false,
984
+ maxHeight = 240,
985
+ value,
986
+ onValueChange,
987
+ onSubmit,
988
+ children,
989
+ disabled = false,
990
+ onDragOver,
991
+ onDragLeave,
992
+ onDrop,
993
+ ref
994
+ }) => {
995
+ const [internalValue, setInternalValue] = React5__default.useState(value || "");
996
+ const handleChange = (newValue) => {
997
+ setInternalValue(newValue);
998
+ onValueChange?.(newValue);
999
+ };
1000
+ const promptValue = value ?? internalValue;
1001
+ const setPromptValue = onValueChange ?? handleChange;
1002
+ return /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsx(PromptInputIsLoadingContext.Provider, { value: isLoading, children: /* @__PURE__ */ jsx(PromptInputValueContext.Provider, { value: promptValue, children: /* @__PURE__ */ jsx(PromptInputSetValueContext.Provider, { value: setPromptValue, children: /* @__PURE__ */ jsx(PromptInputMaxHeightContext.Provider, { value: maxHeight, children: /* @__PURE__ */ jsx(PromptInputSubmitContext.Provider, { value: onSubmit, children: /* @__PURE__ */ jsx(PromptInputDisabledContext.Provider, { value: disabled, children: /* @__PURE__ */ jsx(
1003
+ "div",
1004
+ {
1005
+ ref,
1006
+ className: cn(
1007
+ "rounded-[var(--radius-3xl)] border border-input bg-background p-2 shadow-lg transition-[background-color,border-color,box-shadow,color,opacity,transform] duration-300",
1008
+ isLoading && "border-destructive/70",
1009
+ className
1010
+ ),
1011
+ onDragOver,
1012
+ onDragLeave,
1013
+ onDrop,
1014
+ children
1015
+ }
1016
+ ) }) }) }) }) }) }) });
1017
+ };
761
1018
  PromptInput.displayName = "PromptInput";
762
1019
  var PromptInputTextarea = ({ className, onKeyDown, disableAutosize = false, placeholder, style, ...props }) => {
763
1020
  const { value, setValue, maxHeight, onSubmit, disabled } = usePromptInput();
764
- const textareaRef = React6__default.useRef(null);
765
- React6__default.useEffect(() => {
1021
+ const textareaRef = React5__default.useRef(null);
1022
+ React5__default.useEffect(() => {
766
1023
  if (disableAutosize || !textareaRef.current) return;
767
1024
  textareaRef.current.style.height = "auto";
768
1025
  textareaRef.current.style.height = typeof maxHeight === "number" ? `${Math.min(textareaRef.current.scrollHeight, maxHeight)}px` : `min(${textareaRef.current.scrollHeight}px, ${maxHeight})`;
@@ -772,461 +1029,490 @@ var PromptInputTextarea = ({ className, onKeyDown, disableAutosize = false, plac
772
1029
  e.preventDefault();
773
1030
  onSubmit?.();
774
1031
  }
775
- onKeyDown?.(e);
776
- };
1032
+ onKeyDown?.(e);
1033
+ };
1034
+ return /* @__PURE__ */ jsx(
1035
+ Textarea,
1036
+ {
1037
+ ref: textareaRef,
1038
+ value,
1039
+ onChange: (e) => setValue(e.target.value),
1040
+ onKeyDown: handleKeyDown,
1041
+ rows: 1,
1042
+ style: { "--textarea-min-height": "2rem", ...style },
1043
+ className: cn("resize-none border-0 shadow-none focus-visible:ring-0", className),
1044
+ disabled,
1045
+ placeholder,
1046
+ ...props
1047
+ }
1048
+ );
1049
+ };
1050
+ var PromptInputActions = ({
1051
+ children,
1052
+ className,
1053
+ ...props
1054
+ }) => /* @__PURE__ */ jsx("div", { className: cn("flex items-center gap-2", className), ...props, children });
1055
+ var PromptInputAction = ({
1056
+ tooltip,
1057
+ children,
1058
+ className,
1059
+ side = "top",
1060
+ ...props
1061
+ }) => {
1062
+ const { disabled } = usePromptInput();
1063
+ return /* @__PURE__ */ jsxs(Tooltip, { ...props, children: [
1064
+ /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, disabled, children }),
1065
+ /* @__PURE__ */ jsx(TooltipContent, { side, className: className || "", children: tooltip })
1066
+ ] });
1067
+ };
1068
+ var CustomDivider = () => /* @__PURE__ */ jsx("div", { className: "relative h-6 w-[1.5px] mx-1", children: /* @__PURE__ */ jsx(
1069
+ "div",
1070
+ {
1071
+ className: "absolute inset-0 bg-gradient-to-t from-transparent via-cyan/40 to-transparent rounded-full",
1072
+ style: {
1073
+ clipPath: "polygon(0% 0%, 100% 0%, 100% 40%, 140% 50%, 100% 60%, 100% 100%, 0% 100%, 0% 60%, -40% 50%, 0% 40%)"
1074
+ }
1075
+ }
1076
+ ) });
1077
+ var promptModeToneClassName = {
1078
+ search: {
1079
+ active: "bg-info/15 border-info text-info",
1080
+ icon: "text-info",
1081
+ label: "text-info"
1082
+ },
1083
+ think: {
1084
+ active: "bg-indigo-500/15 border-indigo-500 text-indigo-500",
1085
+ icon: "text-indigo-500",
1086
+ label: "text-indigo-500"
1087
+ },
1088
+ canvas: {
1089
+ active: "bg-warning/15 border-warning text-warning",
1090
+ icon: "text-warning",
1091
+ label: "text-warning"
1092
+ }
1093
+ };
1094
+ function PromptModeIcon({ tone, active }) {
1095
+ const className = cn("w-4 h-4", active ? promptModeToneClassName[tone].icon : "text-inherit");
1096
+ if (tone === "search") return /* @__PURE__ */ jsx(Globe, { className });
1097
+ if (tone === "think") return /* @__PURE__ */ jsx(Brain, { className });
1098
+ return /* @__PURE__ */ jsx(FolderClosed, { className });
1099
+ }
1100
+ function PromptModeButton({
1101
+ active,
1102
+ label,
1103
+ tone,
1104
+ onClick
1105
+ }) {
1106
+ const toneClassName = promptModeToneClassName[tone];
1107
+ const shouldReduceMotion = useReducedMotion();
1108
+ return /* @__PURE__ */ jsxs(
1109
+ "button",
1110
+ {
1111
+ type: "button",
1112
+ onClick,
1113
+ className: cn(
1114
+ "rounded-full transition-[background-color,border-color,box-shadow,color,opacity,transform] flex items-center gap-1 px-2 py-1 border h-8",
1115
+ active ? toneClassName.active : "bg-transparent border-transparent text-muted-foreground hover:text-foreground"
1116
+ ),
1117
+ children: [
1118
+ /* @__PURE__ */ jsx("div", { className: "w-5 h-5 flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsx(
1119
+ m.div,
1120
+ {
1121
+ animate: shouldReduceMotion ? { opacity: active ? 1 : 0.82 } : { rotate: active ? 360 : 0, scale: active ? 1.1 : 1 },
1122
+ whileHover: shouldReduceMotion ? { opacity: 1 } : {
1123
+ rotate: active ? 360 : 15,
1124
+ scale: 1.1,
1125
+ transition: { type: "spring", stiffness: 300, damping: 10 }
1126
+ },
1127
+ transition: shouldReduceMotion ? { duration: 0 } : { type: "spring", stiffness: 260, damping: 25 },
1128
+ children: /* @__PURE__ */ jsx(PromptModeIcon, { tone, active })
1129
+ }
1130
+ ) }),
1131
+ /* @__PURE__ */ jsx(AnimatePresence, { children: active && /* @__PURE__ */ jsx(
1132
+ m.span,
1133
+ {
1134
+ initial: shouldReduceMotion ? { opacity: 1 } : { width: 0, opacity: 0 },
1135
+ animate: { width: "auto", opacity: 1 },
1136
+ exit: shouldReduceMotion ? { opacity: 0 } : { width: 0, opacity: 0 },
1137
+ transition: shouldReduceMotion ? { duration: 0 } : { duration: 0.2 },
1138
+ className: cn(
1139
+ "text-xs overflow-hidden whitespace-nowrap flex-shrink-0",
1140
+ toneClassName.label
1141
+ ),
1142
+ children: label
1143
+ }
1144
+ ) })
1145
+ ]
1146
+ }
1147
+ );
1148
+ }
1149
+ function PromptModeActions({
1150
+ uploadInputRef,
1151
+ isRecording,
1152
+ modes,
1153
+ onToggleMode,
1154
+ onToggleCanvas,
1155
+ onProcessFile
1156
+ }) {
1157
+ return /* @__PURE__ */ jsxs(
1158
+ "div",
1159
+ {
1160
+ className: cn(
1161
+ "flex items-center gap-1 transition-opacity duration-300",
1162
+ isRecording ? "opacity-0 invisible h-0" : "opacity-100 visible"
1163
+ ),
1164
+ children: [
1165
+ /* @__PURE__ */ jsx(PromptInputAction, { tooltip: "Upload image", children: /* @__PURE__ */ jsx(
1166
+ "button",
1167
+ {
1168
+ type: "button",
1169
+ "aria-label": "Upload image",
1170
+ onClick: () => uploadInputRef.current?.click(),
1171
+ className: "flex h-8 w-8 text-muted-foreground cursor-pointer items-center justify-center rounded-full transition-colors hover:bg-accent hover:text-foreground",
1172
+ disabled: isRecording,
1173
+ children: /* @__PURE__ */ jsx(Paperclip, { className: "h-5 w-5 transition-colors" })
1174
+ }
1175
+ ) }),
1176
+ /* @__PURE__ */ jsx(
1177
+ "input",
1178
+ {
1179
+ ref: uploadInputRef,
1180
+ type: "file",
1181
+ className: "hidden",
1182
+ onChange: (event) => {
1183
+ const file = event.target.files?.[0];
1184
+ if (file) onProcessFile(file);
1185
+ if (event.target) event.target.value = "";
1186
+ },
1187
+ accept: "image/*",
1188
+ "aria-label": "Upload image"
1189
+ }
1190
+ ),
1191
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
1192
+ /* @__PURE__ */ jsx(
1193
+ PromptModeButton,
1194
+ {
1195
+ active: modes.search,
1196
+ label: "Search",
1197
+ tone: "search",
1198
+ onClick: () => onToggleMode("search")
1199
+ }
1200
+ ),
1201
+ /* @__PURE__ */ jsx(CustomDivider, {}),
1202
+ /* @__PURE__ */ jsx(
1203
+ PromptModeButton,
1204
+ {
1205
+ active: modes.think,
1206
+ label: "Think",
1207
+ tone: "think",
1208
+ onClick: () => onToggleMode("think")
1209
+ }
1210
+ ),
1211
+ /* @__PURE__ */ jsx(CustomDivider, {}),
1212
+ /* @__PURE__ */ jsx(
1213
+ PromptModeButton,
1214
+ {
1215
+ active: modes.canvas,
1216
+ label: "Canvas",
1217
+ tone: "canvas",
1218
+ onClick: onToggleCanvas
1219
+ }
1220
+ )
1221
+ ] })
1222
+ ]
1223
+ }
1224
+ );
1225
+ }
1226
+ function PromptSubmitAction({
1227
+ isLoading,
1228
+ isRecording,
1229
+ hasContent,
1230
+ onActivate
1231
+ }) {
1232
+ const shouldReduceMotion = useReducedMotion();
777
1233
  return /* @__PURE__ */ jsx(
778
- Textarea,
1234
+ PromptInputAction,
779
1235
  {
780
- ref: textareaRef,
781
- value,
782
- onChange: (e) => setValue(e.target.value),
783
- onKeyDown: handleKeyDown,
784
- rows: 1,
785
- style: { "--textarea-min-height": "2rem", ...style },
786
- className: cn2("resize-none border-0 shadow-none focus-visible:ring-0", className),
787
- disabled,
788
- placeholder,
789
- ...props
1236
+ tooltip: isLoading ? "Stop generation" : isRecording ? "Stop recording" : hasContent ? "Send message" : "Voice message",
1237
+ children: /* @__PURE__ */ jsx(
1238
+ Button,
1239
+ {
1240
+ variant: "default",
1241
+ size: "icon",
1242
+ className: cn(
1243
+ "h-8 w-8 rounded-full transition-[background-color,border-color,box-shadow,color,opacity,transform] duration-200",
1244
+ isRecording ? "bg-transparent hover:bg-accent text-destructive hover:text-destructive/80" : hasContent ? "bg-primary hover:bg-primary/90 text-primary-foreground" : "bg-transparent hover:bg-accent text-muted-foreground hover:text-foreground"
1245
+ ),
1246
+ onClick: onActivate,
1247
+ disabled: isLoading && !hasContent,
1248
+ children: isLoading ? /* @__PURE__ */ jsx(
1249
+ StopFill,
1250
+ {
1251
+ className: cn(
1252
+ "h-4 w-4 fill-primary-foreground",
1253
+ shouldReduceMotion ? "opacity-100" : "animate-pulse"
1254
+ )
1255
+ }
1256
+ ) : isRecording ? /* @__PURE__ */ jsx(StopCircle, { className: "h-5 w-5 text-destructive" }) : hasContent ? /* @__PURE__ */ jsx(ArrowUp, { className: "h-4 w-4 text-primary-foreground" }) : /* @__PURE__ */ jsx(Microphone, { className: "h-5 w-5 text-primary-foreground transition-colors" })
1257
+ }
1258
+ )
790
1259
  }
791
1260
  );
1261
+ }
1262
+ var promptInputBoxInitialState = {
1263
+ input: "",
1264
+ files: [],
1265
+ filePreviews: {},
1266
+ selectedImage: null,
1267
+ isRecording: false,
1268
+ recordingTime: 0,
1269
+ showSearch: false,
1270
+ showThink: false,
1271
+ showCanvas: false
792
1272
  };
793
- var PromptInputActions = ({
794
- children,
795
- className,
796
- ...props
797
- }) => /* @__PURE__ */ jsx("div", { className: cn2("flex items-center gap-2", className), ...props, children });
798
- var PromptInputAction = ({
799
- tooltip,
800
- children,
801
- className,
802
- side = "top",
803
- ...props
804
- }) => {
805
- const { disabled } = usePromptInput();
806
- return /* @__PURE__ */ jsxs(Tooltip, { ...props, children: [
807
- /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, disabled, children }),
808
- /* @__PURE__ */ jsx(TooltipContent, { side, className: className || "", children: tooltip })
809
- ] });
810
- };
811
- var CustomDivider = () => /* @__PURE__ */ jsx("div", { className: "relative h-6 w-[1.5px] mx-1", children: /* @__PURE__ */ jsx(
812
- "div",
813
- {
814
- className: "absolute inset-0 bg-gradient-to-t from-transparent via-cyan/40 to-transparent rounded-full",
815
- style: {
816
- clipPath: "polygon(0% 0%, 100% 0%, 100% 40%, 140% 50%, 100% 60%, 100% 100%, 0% 100%, 0% 60%, -40% 50%, 0% 40%)"
1273
+ function promptInputBoxReducer(state, action) {
1274
+ switch (action.type) {
1275
+ case "set-input":
1276
+ return { ...state, input: action.value };
1277
+ case "set-active-file":
1278
+ return { ...state, files: [action.file], filePreviews: {} };
1279
+ case "set-file-preview":
1280
+ return { ...state, filePreviews: { [action.previewKey]: action.preview } };
1281
+ case "remove-file": {
1282
+ const nextPreviews = { ...state.filePreviews };
1283
+ delete nextPreviews[action.previewKey];
1284
+ return {
1285
+ ...state,
1286
+ filePreviews: nextPreviews,
1287
+ files: state.files.filter((file) => getFilePreviewKey(file) !== action.previewKey)
1288
+ };
817
1289
  }
1290
+ case "set-selected-image":
1291
+ return { ...state, selectedImage: action.imageUrl };
1292
+ case "toggle-mode":
1293
+ if (action.mode === "search") {
1294
+ return { ...state, showSearch: !state.showSearch, showThink: false };
1295
+ }
1296
+ if (action.mode === "think") {
1297
+ return { ...state, showSearch: false, showThink: !state.showThink };
1298
+ }
1299
+ return { ...state, showCanvas: !state.showCanvas };
1300
+ case "start-recording":
1301
+ return { ...state, recordingTime: 0, isRecording: true };
1302
+ case "tick-recording":
1303
+ return { ...state, recordingTime: state.recordingTime + 1 };
1304
+ case "stop-recording":
1305
+ return { ...state, isRecording: false, recordingTime: 0 };
1306
+ case "reset-composer":
1307
+ return { ...state, input: "", files: [], filePreviews: {} };
818
1308
  }
819
- ) });
820
- var PromptInputBox = React6__default.forwardRef(
821
- (props, ref) => {
822
- const {
823
- onSend = () => {
824
- },
825
- isLoading = false,
826
- placeholder = "Type your message here...",
827
- className
828
- } = props;
829
- const [input, setInput] = React6__default.useState("");
830
- const [files, setFiles] = React6__default.useState([]);
831
- const [filePreviews, setFilePreviews] = React6__default.useState({});
832
- const [selectedImage, setSelectedImage] = React6__default.useState(null);
833
- const [isRecording, setIsRecording] = React6__default.useState(false);
834
- const [showSearch, setShowSearch] = React6__default.useState(false);
835
- const [showThink, setShowThink] = React6__default.useState(false);
836
- const [showCanvas, setShowCanvas] = React6__default.useState(false);
837
- const uploadInputRef = React6__default.useRef(null);
838
- const promptBoxRef = React6__default.useRef(null);
839
- const handleToggleChange = (value) => {
840
- if (value === "search") {
841
- setShowSearch((prev) => !prev);
842
- setShowThink(false);
843
- } else if (value === "think") {
844
- setShowThink((prev) => !prev);
845
- setShowSearch(false);
1309
+ }
1310
+ var PromptInputBox = (props) => {
1311
+ const {
1312
+ onSend = () => {
1313
+ },
1314
+ isLoading = false,
1315
+ placeholder = "Type your message here...",
1316
+ className,
1317
+ ref
1318
+ } = props;
1319
+ const [state, dispatch] = React5__default.useReducer(promptInputBoxReducer, promptInputBoxInitialState);
1320
+ const {
1321
+ input,
1322
+ files,
1323
+ filePreviews,
1324
+ selectedImage,
1325
+ isRecording,
1326
+ recordingTime,
1327
+ showSearch,
1328
+ showThink,
1329
+ showCanvas
1330
+ } = state;
1331
+ const uploadInputRef = React5__default.useRef(null);
1332
+ const promptBoxRef = React5__default.useRef(null);
1333
+ const handleToggleChange = (mode) => dispatch({ type: "toggle-mode", mode });
1334
+ const handleCanvasToggle = () => dispatch({ type: "toggle-mode", mode: "canvas" });
1335
+ const processFile = (file) => {
1336
+ if (!isImageFile(file)) {
1337
+ return;
1338
+ }
1339
+ if (file.size > 10 * 1024 * 1024) {
1340
+ return;
1341
+ }
1342
+ const previewKey = getFilePreviewKey(file);
1343
+ dispatch({ type: "set-active-file", file });
1344
+ const reader = new FileReader();
1345
+ reader.onload = (e) => {
1346
+ const preview = e.target?.result;
1347
+ if (typeof preview === "string") {
1348
+ dispatch({ type: "set-file-preview", previewKey, preview });
846
1349
  }
847
1350
  };
848
- const handleCanvasToggle = () => setShowCanvas((prev) => !prev);
849
- const isImageFile = React6__default.useCallback((file) => file.type.startsWith("image/"), []);
850
- const processFile = React6__default.useCallback(
851
- (file) => {
852
- if (!isImageFile(file)) {
853
- return;
854
- }
855
- if (file.size > 10 * 1024 * 1024) {
856
- return;
1351
+ reader.readAsDataURL(file);
1352
+ };
1353
+ const handleDrop = (e) => {
1354
+ preventDragDefaults(e);
1355
+ const droppedFiles = Array.from(e.dataTransfer.files);
1356
+ const firstFile = droppedFiles.find((file) => isImageFile(file));
1357
+ if (firstFile) processFile(firstFile);
1358
+ };
1359
+ const handleRemoveFile = (fileToRemove) => {
1360
+ const previewKey = getFilePreviewKey(fileToRemove);
1361
+ dispatch({ type: "remove-file", previewKey });
1362
+ };
1363
+ const openImageModal = (imageUrl) => dispatch({ type: "set-selected-image", imageUrl });
1364
+ const handlePasteEvent = useEffectEvent((e) => {
1365
+ const items = e.clipboardData?.items;
1366
+ if (!items) return;
1367
+ for (const item of Array.from(items)) {
1368
+ if (item.type.includes("image")) {
1369
+ const file = item.getAsFile();
1370
+ if (file) {
1371
+ e.preventDefault();
1372
+ processFile(file);
1373
+ break;
857
1374
  }
858
- setFiles([file]);
859
- const reader = new FileReader();
860
- reader.onload = (e) => setFilePreviews({ [file.name]: e.target?.result });
861
- reader.readAsDataURL(file);
862
- },
863
- [isImageFile]
864
- );
865
- const handleDragOver = React6__default.useCallback((e) => {
866
- e.preventDefault();
867
- e.stopPropagation();
868
- }, []);
869
- const handleDragLeave = React6__default.useCallback((e) => {
870
- e.preventDefault();
871
- e.stopPropagation();
872
- }, []);
873
- const handleDrop = React6__default.useCallback(
874
- (e) => {
875
- e.preventDefault();
876
- e.stopPropagation();
877
- const files2 = Array.from(e.dataTransfer.files);
878
- const imageFiles = files2.filter((file) => isImageFile(file));
879
- const firstFile = imageFiles[0];
880
- if (firstFile) processFile(firstFile);
881
- },
882
- [isImageFile, processFile]
883
- );
884
- const handleRemoveFile = (index) => {
885
- const fileToRemove = files[index];
886
- if (fileToRemove && filePreviews[fileToRemove.name]) {
887
- const newPreviews = { ...filePreviews };
888
- delete newPreviews[fileToRemove.name];
889
- setFilePreviews(newPreviews);
890
1375
  }
891
- setFiles([]);
892
- };
893
- const openImageModal = (imageUrl) => setSelectedImage(imageUrl);
894
- const handlePaste = React6__default.useCallback(
895
- (e) => {
896
- const items = e.clipboardData?.items;
897
- if (!items) return;
898
- for (let i = 0; i < items.length; i++) {
899
- const item = items[i];
900
- if (item && item.type.indexOf("image") !== -1) {
901
- const file = item.getAsFile();
902
- if (file) {
903
- e.preventDefault();
904
- processFile(file);
905
- break;
1376
+ }
1377
+ });
1378
+ React5__default.useEffect(() => {
1379
+ const handlePaste = (e) => handlePasteEvent(e);
1380
+ document.addEventListener("paste", handlePaste);
1381
+ return () => document.removeEventListener("paste", handlePaste);
1382
+ }, []);
1383
+ React5__default.useEffect(() => {
1384
+ if (!isRecording) return;
1385
+ const timer = window.setInterval(() => dispatch({ type: "tick-recording" }), 1e3);
1386
+ return () => window.clearInterval(timer);
1387
+ }, [isRecording]);
1388
+ const handleSubmit = () => {
1389
+ if (input.trim() || files.length > 0) {
1390
+ let messagePrefix = "";
1391
+ if (showSearch) messagePrefix = "[Search: ";
1392
+ else if (showThink) messagePrefix = "[Think: ";
1393
+ else if (showCanvas) messagePrefix = "[Canvas: ";
1394
+ const formattedInput = messagePrefix ? `${messagePrefix}${input}]` : input;
1395
+ onSend(formattedInput, files);
1396
+ dispatch({ type: "reset-composer" });
1397
+ }
1398
+ };
1399
+ const startRecording = () => dispatch({ type: "start-recording" });
1400
+ const stopRecording = () => {
1401
+ onSend(`[Voice message - ${recordingTime} seconds]`, []);
1402
+ dispatch({ type: "stop-recording" });
1403
+ };
1404
+ const hasContent = input.trim() !== "" || files.length > 0;
1405
+ return /* @__PURE__ */ jsxs(LazyMotion, { features: domAnimation, children: [
1406
+ /* @__PURE__ */ jsxs(
1407
+ PromptInput,
1408
+ {
1409
+ value: input,
1410
+ onValueChange: (value) => dispatch({ type: "set-input", value }),
1411
+ isLoading,
1412
+ onSubmit: handleSubmit,
1413
+ className: cn(
1414
+ "w-full bg-background border-input shadow-lg transition-[background-color,border-color,box-shadow,color,opacity,transform] duration-300 ease-in-out",
1415
+ isRecording && "border-destructive/70",
1416
+ className
1417
+ ),
1418
+ disabled: isLoading || isRecording,
1419
+ ref: ref || promptBoxRef,
1420
+ onDragOver: preventDragDefaults,
1421
+ onDragLeave: preventDragDefaults,
1422
+ onDrop: handleDrop,
1423
+ children: [
1424
+ /* @__PURE__ */ jsx(
1425
+ PromptAttachmentPreviews,
1426
+ {
1427
+ files,
1428
+ filePreviews,
1429
+ isRecording,
1430
+ onPreview: openImageModal,
1431
+ onRemove: handleRemoveFile
906
1432
  }
907
- }
908
- }
909
- },
910
- [processFile]
911
- );
912
- React6__default.useEffect(() => {
913
- document.addEventListener("paste", handlePaste);
914
- return () => document.removeEventListener("paste", handlePaste);
915
- }, [handlePaste]);
916
- const handleSubmit = () => {
917
- if (input.trim() || files.length > 0) {
918
- let messagePrefix = "";
919
- if (showSearch) messagePrefix = "[Search: ";
920
- else if (showThink) messagePrefix = "[Think: ";
921
- else if (showCanvas) messagePrefix = "[Canvas: ";
922
- const formattedInput = messagePrefix ? `${messagePrefix}${input}]` : input;
923
- onSend(formattedInput, files);
924
- setInput("");
925
- setFiles([]);
926
- setFilePreviews({});
927
- }
928
- };
929
- const handleStartRecording = () => {
930
- };
931
- const handleStopRecording = (duration) => {
932
- setIsRecording(false);
933
- onSend(`[Voice message - ${duration} seconds]`, []);
934
- };
935
- const hasContent = input.trim() !== "" || files.length > 0;
936
- return /* @__PURE__ */ jsxs(Fragment, { children: [
937
- /* @__PURE__ */ jsxs(
938
- PromptInput,
939
- {
940
- value: input,
941
- onValueChange: setInput,
942
- isLoading,
943
- onSubmit: handleSubmit,
944
- className: cn2(
945
- "w-full bg-background border-input shadow-lg transition-all duration-300 ease-in-out",
946
- isRecording && "border-destructive/70",
947
- className
948
1433
  ),
949
- disabled: isLoading || isRecording,
950
- ref: ref || promptBoxRef,
951
- onDragOver: handleDragOver,
952
- onDragLeave: handleDragLeave,
953
- onDrop: handleDrop,
954
- children: [
955
- files.length > 0 && !isRecording && /* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2 p-0 pb-1 transition-all duration-300", children: files.map((file, index) => /* @__PURE__ */ jsx("div", { className: "relative group", children: file.type.startsWith("image/") && filePreviews[file.name] && // biome-ignore lint/a11y/useSemanticElements: ARIA pattern
956
- /* @__PURE__ */ jsxs(
957
- "div",
958
- {
959
- role: "button",
960
- tabIndex: 0,
961
- onKeyDown: (e) => {
962
- if (e.key === "Enter" || e.key === " ") {
963
- e.preventDefault();
964
- const preview = filePreviews[file.name];
965
- if (preview) openImageModal(preview);
966
- }
967
- },
968
- className: "w-16 h-16 rounded-xl overflow-hidden cursor-pointer transition-all duration-300",
969
- onClick: () => {
970
- const preview = filePreviews[file.name];
971
- if (preview) openImageModal(preview);
972
- },
973
- children: [
974
- /* @__PURE__ */ jsx(
975
- Image,
976
- {
977
- src: filePreviews[file.name] ?? "",
978
- alt: file.name,
979
- className: "h-full w-full object-cover",
980
- fill: true
981
- }
982
- ),
983
- /* @__PURE__ */ jsx(
984
- "button",
985
- {
986
- type: "button",
987
- onClick: (e) => {
988
- e.stopPropagation();
989
- handleRemoveFile(index);
990
- },
991
- className: "absolute top-1 right-1 rounded-full bg-black/70 p-0.5 opacity-100 transition-opacity",
992
- children: /* @__PURE__ */ jsx(Cross, { className: "h-3 w-3 text-white" })
993
- }
994
- )
995
- ]
996
- }
997
- ) }, index)) }),
1434
+ /* @__PURE__ */ jsx(
1435
+ "div",
1436
+ {
1437
+ className: cn(
1438
+ "transition-[background-color,border-color,box-shadow,color,opacity,transform] duration-300",
1439
+ isRecording ? "h-0 overflow-hidden opacity-0" : "opacity-100"
1440
+ ),
1441
+ children: /* @__PURE__ */ jsx(
1442
+ PromptInputTextarea,
1443
+ {
1444
+ placeholder: showSearch ? "Search the web..." : showThink ? "Think deeply..." : showCanvas ? "Create on canvas..." : placeholder,
1445
+ className: "text-base"
1446
+ }
1447
+ )
1448
+ }
1449
+ ),
1450
+ isRecording && /* @__PURE__ */ jsx(VoiceRecorder, { isRecording, time: recordingTime }),
1451
+ /* @__PURE__ */ jsxs(PromptInputActions, { className: "flex items-center justify-between gap-2 p-0 pt-2", children: [
998
1452
  /* @__PURE__ */ jsx(
999
- "div",
1453
+ PromptModeActions,
1000
1454
  {
1001
- className: cn2(
1002
- "transition-all duration-300",
1003
- isRecording ? "h-0 overflow-hidden opacity-0" : "opacity-100"
1004
- ),
1005
- children: /* @__PURE__ */ jsx(
1006
- PromptInputTextarea,
1007
- {
1008
- placeholder: showSearch ? "Search the web..." : showThink ? "Think deeply..." : showCanvas ? "Create on canvas..." : placeholder,
1009
- className: "text-base"
1010
- }
1011
- )
1455
+ uploadInputRef,
1456
+ isRecording,
1457
+ modes: { search: showSearch, think: showThink, canvas: showCanvas },
1458
+ onToggleMode: handleToggleChange,
1459
+ onToggleCanvas: handleCanvasToggle,
1460
+ onProcessFile: processFile
1012
1461
  }
1013
1462
  ),
1014
- isRecording && /* @__PURE__ */ jsx(
1015
- VoiceRecorder,
1463
+ /* @__PURE__ */ jsx(
1464
+ PromptSubmitAction,
1016
1465
  {
1466
+ isLoading,
1017
1467
  isRecording,
1018
- onStartRecording: handleStartRecording,
1019
- onStopRecording: handleStopRecording
1020
- }
1021
- ),
1022
- /* @__PURE__ */ jsxs(PromptInputActions, { className: "flex items-center justify-between gap-2 p-0 pt-2", children: [
1023
- /* @__PURE__ */ jsxs(
1024
- "div",
1025
- {
1026
- className: cn2(
1027
- "flex items-center gap-1 transition-opacity duration-300",
1028
- isRecording ? "opacity-0 invisible h-0" : "opacity-100 visible"
1029
- ),
1030
- children: [
1031
- /* @__PURE__ */ jsx(PromptInputAction, { tooltip: "Upload image", children: /* @__PURE__ */ jsxs(
1032
- "button",
1033
- {
1034
- type: "button",
1035
- onClick: () => uploadInputRef.current?.click(),
1036
- className: "flex h-8 w-8 text-muted-foreground cursor-pointer items-center justify-center rounded-full transition-colors hover:bg-accent hover:text-foreground",
1037
- disabled: isRecording,
1038
- children: [
1039
- /* @__PURE__ */ jsx(Paperclip, { className: "h-5 w-5 transition-colors" }),
1040
- /* @__PURE__ */ jsx(
1041
- "input",
1042
- {
1043
- ref: uploadInputRef,
1044
- type: "file",
1045
- className: "hidden",
1046
- onChange: (e) => {
1047
- const file = e.target.files?.[0];
1048
- if (file) processFile(file);
1049
- if (e.target) e.target.value = "";
1050
- },
1051
- accept: "image/*"
1052
- }
1053
- )
1054
- ]
1055
- }
1056
- ) }),
1057
- /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
1058
- /* @__PURE__ */ jsxs(
1059
- "button",
1060
- {
1061
- type: "button",
1062
- onClick: () => handleToggleChange("search"),
1063
- className: cn2(
1064
- "rounded-full transition-all flex items-center gap-1 px-2 py-1 border h-8",
1065
- showSearch ? "bg-info/15 border-info text-info" : "bg-transparent border-transparent text-muted-foreground hover:text-foreground"
1066
- ),
1067
- children: [
1068
- /* @__PURE__ */ jsx("div", { className: "w-5 h-5 flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsx(
1069
- motion.div,
1070
- {
1071
- animate: { rotate: showSearch ? 360 : 0, scale: showSearch ? 1.1 : 1 },
1072
- whileHover: {
1073
- rotate: showSearch ? 360 : 15,
1074
- scale: 1.1,
1075
- transition: { type: "spring", stiffness: 300, damping: 10 }
1076
- },
1077
- transition: { type: "spring", stiffness: 260, damping: 25 },
1078
- children: /* @__PURE__ */ jsx(Globe, { className: cn2("w-4 h-4", showSearch ? "text-info" : "text-inherit") })
1079
- }
1080
- ) }),
1081
- /* @__PURE__ */ jsx(AnimatePresence, { children: showSearch && /* @__PURE__ */ jsx(
1082
- motion.span,
1083
- {
1084
- initial: { width: 0, opacity: 0 },
1085
- animate: { width: "auto", opacity: 1 },
1086
- exit: { width: 0, opacity: 0 },
1087
- transition: { duration: 0.2 },
1088
- className: "text-xs overflow-hidden whitespace-nowrap text-info flex-shrink-0",
1089
- children: "Search"
1090
- }
1091
- ) })
1092
- ]
1093
- }
1094
- ),
1095
- /* @__PURE__ */ jsx(CustomDivider, {}),
1096
- /* @__PURE__ */ jsxs(
1097
- "button",
1098
- {
1099
- type: "button",
1100
- onClick: () => handleToggleChange("think"),
1101
- className: cn2(
1102
- "rounded-full transition-all flex items-center gap-1 px-2 py-1 border h-8",
1103
- showThink ? "bg-indigo-500/15 border-indigo-500 text-indigo-500" : "bg-transparent border-transparent text-muted-foreground hover:text-foreground"
1104
- ),
1105
- children: [
1106
- /* @__PURE__ */ jsx("div", { className: "w-5 h-5 flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsx(
1107
- motion.div,
1108
- {
1109
- animate: { rotate: showThink ? 360 : 0, scale: showThink ? 1.1 : 1 },
1110
- whileHover: {
1111
- rotate: showThink ? 360 : 15,
1112
- scale: 1.1,
1113
- transition: { type: "spring", stiffness: 300, damping: 10 }
1114
- },
1115
- transition: { type: "spring", stiffness: 260, damping: 25 },
1116
- children: /* @__PURE__ */ jsx(
1117
- Brain,
1118
- {
1119
- className: cn2("w-4 h-4", showThink ? "text-indigo-500" : "text-inherit")
1120
- }
1121
- )
1122
- }
1123
- ) }),
1124
- /* @__PURE__ */ jsx(AnimatePresence, { children: showThink && /* @__PURE__ */ jsx(
1125
- motion.span,
1126
- {
1127
- initial: { width: 0, opacity: 0 },
1128
- animate: { width: "auto", opacity: 1 },
1129
- exit: { width: 0, opacity: 0 },
1130
- transition: { duration: 0.2 },
1131
- className: "text-xs overflow-hidden whitespace-nowrap text-indigo-500 flex-shrink-0",
1132
- children: "Think"
1133
- }
1134
- ) })
1135
- ]
1136
- }
1137
- ),
1138
- /* @__PURE__ */ jsx(CustomDivider, {}),
1139
- /* @__PURE__ */ jsxs(
1140
- "button",
1141
- {
1142
- type: "button",
1143
- onClick: handleCanvasToggle,
1144
- className: cn2(
1145
- "rounded-full transition-all flex items-center gap-1 px-2 py-1 border h-8",
1146
- showCanvas ? "bg-warning/15 border-warning text-warning" : "bg-transparent border-transparent text-muted-foreground hover:text-foreground"
1147
- ),
1148
- children: [
1149
- /* @__PURE__ */ jsx("div", { className: "w-5 h-5 flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsx(
1150
- motion.div,
1151
- {
1152
- animate: { rotate: showCanvas ? 360 : 0, scale: showCanvas ? 1.1 : 1 },
1153
- whileHover: {
1154
- rotate: showCanvas ? 360 : 15,
1155
- scale: 1.1,
1156
- transition: { type: "spring", stiffness: 300, damping: 10 }
1157
- },
1158
- transition: { type: "spring", stiffness: 260, damping: 25 },
1159
- children: /* @__PURE__ */ jsx(
1160
- FolderClosed,
1161
- {
1162
- className: cn2("w-4 h-4", showCanvas ? "text-warning" : "text-inherit")
1163
- }
1164
- )
1165
- }
1166
- ) }),
1167
- /* @__PURE__ */ jsx(AnimatePresence, { children: showCanvas && /* @__PURE__ */ jsx(
1168
- motion.span,
1169
- {
1170
- initial: { width: 0, opacity: 0 },
1171
- animate: { width: "auto", opacity: 1 },
1172
- exit: { width: 0, opacity: 0 },
1173
- transition: { duration: 0.2 },
1174
- className: "text-xs overflow-hidden whitespace-nowrap text-warning flex-shrink-0",
1175
- children: "Canvas"
1176
- }
1177
- ) })
1178
- ]
1179
- }
1180
- )
1181
- ] })
1182
- ]
1183
- }
1184
- ),
1185
- /* @__PURE__ */ jsx(
1186
- PromptInputAction,
1187
- {
1188
- tooltip: isLoading ? "Stop generation" : isRecording ? "Stop recording" : hasContent ? "Send message" : "Voice message",
1189
- children: /* @__PURE__ */ jsx(
1190
- Button,
1191
- {
1192
- variant: "default",
1193
- size: "icon",
1194
- className: cn2(
1195
- "h-8 w-8 rounded-full transition-all duration-200",
1196
- isRecording ? "bg-transparent hover:bg-accent text-destructive hover:text-destructive/80" : hasContent ? "bg-primary hover:bg-primary/90 text-primary-foreground" : "bg-transparent hover:bg-accent text-muted-foreground hover:text-foreground"
1197
- ),
1198
- onClick: () => {
1199
- if (isRecording) setIsRecording(false);
1200
- else if (hasContent) handleSubmit();
1201
- else setIsRecording(true);
1202
- },
1203
- disabled: isLoading && !hasContent,
1204
- children: isLoading ? /* @__PURE__ */ jsx(Square, { className: "h-4 w-4 fill-primary-foreground animate-pulse" }) : isRecording ? /* @__PURE__ */ jsx(StopCircle, { className: "h-5 w-5 text-destructive" }) : hasContent ? /* @__PURE__ */ jsx(ArrowUp, { className: "h-4 w-4 text-primary-foreground" }) : /* @__PURE__ */ jsx(Microphone, { className: "h-5 w-5 text-primary-foreground transition-colors" })
1205
- }
1206
- )
1468
+ hasContent,
1469
+ onActivate: () => {
1470
+ if (isRecording) stopRecording();
1471
+ else if (hasContent) handleSubmit();
1472
+ else startRecording();
1207
1473
  }
1208
- )
1209
- ] })
1210
- ]
1211
- }
1212
- ),
1213
- /* @__PURE__ */ jsx(ImageViewDialog, { imageUrl: selectedImage, onClose: () => setSelectedImage(null) })
1214
- ] });
1215
- }
1216
- );
1474
+ }
1475
+ )
1476
+ ] })
1477
+ ]
1478
+ }
1479
+ ),
1480
+ /* @__PURE__ */ jsx(
1481
+ ImageViewDialog,
1482
+ {
1483
+ imageUrl: selectedImage,
1484
+ onClose: () => dispatch({ type: "set-selected-image", imageUrl: null })
1485
+ }
1486
+ )
1487
+ ] });
1488
+ };
1217
1489
  PromptInputBox.displayName = "PromptInputBox";
1490
+ var emergeTransition = {
1491
+ duration: emerge.transition.duration,
1492
+ ease: [0.16, 1, 0.3, 1]
1493
+ };
1494
+ var flowTransition = {
1495
+ duration: flow.transition.duration,
1496
+ ease: [0, 0, 0.2, 1]
1497
+ };
1498
+ var defaultSpringTransition = {
1499
+ type: "spring",
1500
+ stiffness: brandSpring.default.stiffness,
1501
+ damping: brandSpring.default.damping,
1502
+ mass: brandSpring.default.mass
1503
+ };
1218
1504
  var PRESETS = {
1219
1505
  emerge: {
1220
1506
  initial: emerge.initial,
1221
1507
  animate: emerge.animate,
1222
1508
  exit: emerge.exit,
1223
- transition: emerge.transition
1509
+ transition: emergeTransition
1224
1510
  },
1225
1511
  flow: {
1226
1512
  initial: flow.initial,
1227
1513
  animate: flow.animate,
1228
1514
  exit: flow.exit,
1229
- transition: flow.transition
1515
+ transition: flowTransition
1230
1516
  },
1231
1517
  fade: {
1232
1518
  initial: { opacity: 0 },
@@ -1238,13 +1524,13 @@ var PRESETS = {
1238
1524
  initial: { opacity: 0, y: 16 },
1239
1525
  animate: { opacity: 1, y: 0 },
1240
1526
  exit: { opacity: 0, y: 16 },
1241
- transition: brandSpring
1527
+ transition: defaultSpringTransition
1242
1528
  },
1243
1529
  scale: {
1244
1530
  initial: { opacity: 0, scale: 0.95 },
1245
1531
  animate: { opacity: 1, scale: 1 },
1246
1532
  exit: { opacity: 0, scale: 0.95 },
1247
- transition: brandSpring
1533
+ transition: defaultSpringTransition
1248
1534
  }
1249
1535
  };
1250
1536
  var STAGGER = { fast: 0.05, normal: 0.1, slow: 0.2 };
@@ -1254,7 +1540,7 @@ function MotionDiv(props) {
1254
1540
  function AnimateIn(props) {
1255
1541
  const { children, preset = "emerge", delay = 0, duration, inView = false, className } = props;
1256
1542
  const shouldReduce = useReducedMotion();
1257
- const { initial, animate, exit, transition } = PRESETS[preset];
1543
+ const { initial, animate: animate2, exit, transition } = PRESETS[preset];
1258
1544
  const t = {
1259
1545
  ...transition,
1260
1546
  ...delay ? { delay } : {},
@@ -1267,7 +1553,7 @@ function AnimateIn(props) {
1267
1553
  {
1268
1554
  className,
1269
1555
  initial,
1270
- whileInView: animate,
1556
+ whileInView: animate2,
1271
1557
  exit,
1272
1558
  viewport: { once: true, margin: "-10%" },
1273
1559
  transition: t,
@@ -1275,7 +1561,7 @@ function AnimateIn(props) {
1275
1561
  }
1276
1562
  );
1277
1563
  }
1278
- return /* @__PURE__ */ jsx(MotionDiv, { className, initial, animate, exit, transition: t, children });
1564
+ return /* @__PURE__ */ jsx(MotionDiv, { className, initial, animate: animate2, exit, transition: t, children });
1279
1565
  }
1280
1566
  function AnimateInGroup(props) {
1281
1567
  const { children, stagger = "normal", inView = false, className } = props;
@@ -1314,55 +1600,57 @@ function AsciiText({ text, className = "", font = slant }) {
1314
1600
  );
1315
1601
  }
1316
1602
  var TAG_COLOR_MAP = {
1317
- feature: "bg-[var(--cyan-9)] text-white",
1603
+ feature: "bg-[hsl(var(--primary))] text-white",
1318
1604
  fix: "bg-[var(--status-success)] text-white",
1319
1605
  breaking: "bg-[var(--status-danger)] text-white",
1320
1606
  improvement: "bg-[var(--status-warning)] text-white",
1321
1607
  security: "bg-[var(--status-danger)] text-white",
1322
- experimental: "bg-[var(--neutral-8)] text-[var(--neutral-12)]"
1608
+ experimental: "bg-[var(--neutral-8)] text-foreground"
1609
+ };
1610
+ var getTagColor = (tag) => {
1611
+ if (!tag) return "bg-[var(--neutral-7)] text-foreground";
1612
+ return TAG_COLOR_MAP[tag.toLowerCase()] || TAG_COLOR_MAP.feature;
1613
+ };
1614
+ var getUnreadCount = (entries, lastSeenVersion) => {
1615
+ if (!lastSeenVersion) return entries.length;
1616
+ const lastSeenIndex = entries.findIndex((entry) => entry.version === lastSeenVersion);
1617
+ return lastSeenIndex === -1 ? entries.length : lastSeenIndex;
1323
1618
  };
1324
1619
  function ChangelogWidget({
1325
1620
  entries,
1326
1621
  changelogUrl = "/changelog",
1327
1622
  className
1328
1623
  }) {
1329
- const [isOpen, setIsOpen] = React6.useState(false);
1330
- const [lastSeenVersion, setLastSeenVersion] = React6.useState(null);
1331
- const dropdownRef = React6.useRef(null);
1332
- const unreadCount = React6.useMemo(() => {
1333
- if (!lastSeenVersion) return entries.length;
1334
- const lastSeenIndex = entries.findIndex((e) => e.version === lastSeenVersion);
1335
- return lastSeenIndex === -1 ? entries.length : lastSeenIndex;
1336
- }, [entries, lastSeenVersion]);
1624
+ const [isOpen, setIsOpen] = React5.useState(false);
1625
+ const [lastSeenVersion, setLastSeenVersion] = React5.useState(null);
1626
+ const dropdownRef = React5.useRef(null);
1627
+ const unreadCount = getUnreadCount(entries, lastSeenVersion);
1337
1628
  const recentEntries = entries.slice(0, 5);
1338
- const handleClose = React6.useCallback(() => {
1629
+ const latestVersion = recentEntries[0]?.version ?? null;
1630
+ const closeAndMarkSeen = () => {
1339
1631
  setIsOpen(false);
1340
- if (recentEntries.length > 0) {
1341
- setLastSeenVersion(recentEntries[0]?.version ?? null);
1342
- }
1343
- }, [recentEntries]);
1344
- React6.useEffect(() => {
1632
+ if (latestVersion) setLastSeenVersion(latestVersion);
1633
+ };
1634
+ const closeFromDocumentEvent = useEffectEvent(() => {
1635
+ closeAndMarkSeen();
1636
+ });
1637
+ React5.useEffect(() => {
1638
+ if (!isOpen) return;
1345
1639
  const handleEscape = (e) => {
1346
- if (e.key === "Escape") handleClose();
1640
+ if (e.key === "Escape") closeFromDocumentEvent();
1347
1641
  };
1348
1642
  const handleClickOutside = (e) => {
1349
1643
  if (dropdownRef.current && !dropdownRef.current.contains(e.target)) {
1350
- handleClose();
1644
+ closeFromDocumentEvent();
1351
1645
  }
1352
1646
  };
1353
- if (isOpen) {
1354
- document.addEventListener("keydown", handleEscape);
1355
- document.addEventListener("mousedown", handleClickOutside);
1356
- }
1647
+ document.addEventListener("keydown", handleEscape);
1648
+ document.addEventListener("mousedown", handleClickOutside);
1357
1649
  return () => {
1358
1650
  document.removeEventListener("keydown", handleEscape);
1359
1651
  document.removeEventListener("mousedown", handleClickOutside);
1360
1652
  };
1361
- }, [isOpen, handleClose]);
1362
- const getTagColor = (tag) => {
1363
- if (!tag) return "bg-[var(--neutral-7)] text-[var(--neutral-12)]";
1364
- return TAG_COLOR_MAP[tag.toLowerCase()] || TAG_COLOR_MAP.feature;
1365
- };
1653
+ }, [isOpen]);
1366
1654
  return /* @__PURE__ */ jsxs("div", { className: cn("relative", className), ref: dropdownRef, children: [
1367
1655
  /* @__PURE__ */ jsxs(
1368
1656
  "button",
@@ -1370,24 +1658,24 @@ function ChangelogWidget({
1370
1658
  type: "button",
1371
1659
  "aria-label": "View changelog",
1372
1660
  "aria-expanded": isOpen,
1373
- onClick: () => setIsOpen(!isOpen),
1374
- className: "relative inline-flex items-center justify-center rounded-lg p-2 transition-colors hover:bg-[var(--neutral-3)]",
1661
+ onClick: () => setIsOpen((open) => !open),
1662
+ className: "relative inline-flex items-center justify-center rounded-[var(--radius-lg)] p-2 transition-colors hover:bg-muted",
1375
1663
  children: [
1376
- /* @__PURE__ */ jsx(Bell, { className: "h-5 w-5 text-[var(--neutral-11)]" }),
1664
+ /* @__PURE__ */ jsx(Bell, { className: "h-5 w-5 text-muted-foreground" }),
1377
1665
  unreadCount > 0 && /* @__PURE__ */ jsx("span", { className: "absolute right-0 top-0 flex h-5 w-5 items-center justify-center rounded-full bg-[var(--status-danger)] text-xs font-bold text-white", children: unreadCount > 9 ? "9+" : unreadCount })
1378
1666
  ]
1379
1667
  }
1380
1668
  ),
1381
- isOpen && /* @__PURE__ */ jsxs("div", { className: "absolute right-0 top-full z-50 mt-2 w-80 overflow-hidden rounded-lg border border-[var(--neutral-7)] bg-white shadow-lg transition-all duration-200", children: [
1382
- /* @__PURE__ */ jsx("div", { className: "bg-gradient-to-r from-[var(--blue-3)] to-[var(--cyan-3)] px-4 py-3", children: /* @__PURE__ */ jsx("h3", { className: "font-semibold text-[var(--neutral-12)]", children: "What's New" }) }),
1383
- /* @__PURE__ */ jsx("div", { className: "max-h-96 overflow-y-auto", children: recentEntries.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-4 py-6 text-center text-sm text-[var(--neutral-11)]", children: "No updates available" }) : recentEntries.map((entry) => /* @__PURE__ */ jsxs(
1669
+ isOpen && /* @__PURE__ */ jsxs("div", { className: "absolute right-0 top-full z-50 mt-2 w-80 overflow-hidden rounded-[var(--radius-lg)] border border-border bg-white shadow-lg transition-[background-color,border-color,box-shadow,color,opacity,transform] duration-200", children: [
1670
+ /* @__PURE__ */ jsx("div", { className: "bg-gradient-to-r from-[var(--blue-3)] to-[var(--cyan-3)] px-4 py-3", children: /* @__PURE__ */ jsx("h3", { className: "font-semibold text-foreground", children: "What's New" }) }),
1671
+ /* @__PURE__ */ jsx("div", { className: "max-h-96 overflow-y-auto", children: recentEntries.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-4 py-6 text-center text-sm text-muted-foreground", children: "No updates available" }) : recentEntries.map((entry) => /* @__PURE__ */ jsxs(
1384
1672
  "a",
1385
1673
  {
1386
1674
  href: entry.url,
1387
- className: "block border-b border-[var(--neutral-6)] px-4 py-3 transition-colors hover:bg-[var(--neutral-2)]",
1675
+ className: "block border-b border-border px-4 py-3 transition-colors hover:bg-muted",
1388
1676
  children: [
1389
1677
  /* @__PURE__ */ jsx("div", { className: "mb-2 flex items-center justify-between gap-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1390
- /* @__PURE__ */ jsxs("span", { className: "font-mono text-xs font-bold text-[var(--blue-9)]", children: [
1678
+ /* @__PURE__ */ jsxs("span", { className: "font-mono text-xs font-bold text-primary", children: [
1391
1679
  "v",
1392
1680
  entry.version
1393
1681
  ] }),
@@ -1402,9 +1690,9 @@ function ChangelogWidget({
1402
1690
  }
1403
1691
  )
1404
1692
  ] }) }),
1405
- /* @__PURE__ */ jsx("p", { className: "mb-1 text-sm font-medium text-[var(--neutral-12)]", children: entry.title }),
1406
- /* @__PURE__ */ jsx("p", { className: "mb-2 line-clamp-2 text-xs text-[var(--neutral-11)]", children: entry.excerpt }),
1407
- /* @__PURE__ */ jsx("span", { className: "text-xs text-[var(--neutral-10)]", children: entry.date })
1693
+ /* @__PURE__ */ jsx("p", { className: "mb-1 text-sm font-medium text-foreground", children: entry.title }),
1694
+ /* @__PURE__ */ jsx("p", { className: "mb-2 line-clamp-2 text-xs text-muted-foreground", children: entry.excerpt }),
1695
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: entry.date })
1408
1696
  ]
1409
1697
  },
1410
1698
  entry.version
@@ -1413,8 +1701,8 @@ function ChangelogWidget({
1413
1701
  "a",
1414
1702
  {
1415
1703
  href: changelogUrl,
1416
- onClick: handleClose,
1417
- className: "flex items-center justify-between border-t border-[var(--neutral-6)] bg-[var(--neutral-1)] px-4 py-3 text-sm font-medium text-[var(--blue-9)] transition-colors hover:bg-[var(--neutral-2)]",
1704
+ onClick: closeAndMarkSeen,
1705
+ className: "flex items-center justify-between border-t border-border bg-background px-4 py-3 text-sm font-medium text-primary transition-colors hover:bg-muted",
1418
1706
  children: [
1419
1707
  /* @__PURE__ */ jsx("span", { children: "View all updates" }),
1420
1708
  /* @__PURE__ */ jsx(ChevronRight, { className: "h-4 w-4" })
@@ -1496,12 +1784,28 @@ var XYFLOW_TOKEN_THEME = {
1496
1784
  ["--xy-controls-button-color"]: "var(--neutral-11)"
1497
1785
  };
1498
1786
  var nodeCardVariants = cva(
1499
- "min-w-[160px] rounded-lg border bg-neutral-2 px-3 py-2 text-neutral-12 shadow-sm transition-colors",
1787
+ "min-w-[160px] rounded-[var(--radius-lg)] border bg-neutral-2 px-3 py-2 text-neutral-12 shadow-sm transition-colors",
1500
1788
  {
1501
1789
  variants: { ready: { true: "border-success", false: "border-neutral-7" } },
1502
1790
  defaultVariants: { ready: false }
1503
1791
  }
1504
1792
  );
1793
+ function GraphNodeCard({ data }) {
1794
+ const view = data.view;
1795
+ return /* @__PURE__ */ jsxs("div", { className: nodeCardVariants({ ready: view.ready ?? false }), children: [
1796
+ /* @__PURE__ */ jsx(Handle, { type: "target", position: Position.Left }),
1797
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-xs font-medium text-neutral-11 uppercase tracking-wide", children: [
1798
+ view.icon,
1799
+ view.label
1800
+ ] }),
1801
+ view.subtitle ? /* @__PURE__ */ jsx("div", { className: "mt-0.5 text-sm text-neutral-12", children: view.subtitle }) : null,
1802
+ /* @__PURE__ */ jsx(Handle, { type: "source", position: Position.Right })
1803
+ ] });
1804
+ }
1805
+ var NODE_TYPES = {
1806
+ [GRAPH_NODE_FLOW_TYPE]: GraphNodeCard
1807
+ };
1808
+ var REACT_FLOW_PRO_OPTIONS = { hideAttribution: true };
1505
1809
  function NodeGraphCanvas({
1506
1810
  graph,
1507
1811
  onChange,
@@ -1513,82 +1817,63 @@ function NodeGraphCanvas({
1513
1817
  }) {
1514
1818
  const statusId = useId();
1515
1819
  const [rejection, setRejection] = useState(null);
1516
- const { nodes, edges } = useMemo(() => graphToFlow(graph, edgeIdentity), [graph, edgeIdentity]);
1517
- const nodeTypes = useMemo(
1518
- () => ({
1519
- [GRAPH_NODE_FLOW_TYPE]: ({ data }) => {
1520
- const view = renderNode(data.node);
1521
- return /* @__PURE__ */ jsxs("div", { className: nodeCardVariants({ ready: view.ready ?? false }), children: [
1522
- /* @__PURE__ */ jsx(Handle, { type: "target", position: Position.Left }),
1523
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-xs font-medium text-neutral-11 uppercase tracking-wide", children: [
1524
- view.icon,
1525
- view.label
1526
- ] }),
1527
- view.subtitle ? /* @__PURE__ */ jsx("div", { className: "mt-0.5 text-sm text-neutral-12", children: view.subtitle }) : null,
1528
- /* @__PURE__ */ jsx(Handle, { type: "source", position: Position.Right })
1529
- ] });
1530
- }
1531
- }),
1532
- [renderNode]
1533
- );
1534
- const onNodesChange = useCallback(
1535
- (changes) => {
1536
- if (readOnly) return;
1537
- const removed = changes.filter(
1538
- (c) => c.type === "remove"
1539
- );
1540
- if (removed.length > 0) {
1541
- let next = graph;
1542
- for (const r of removed) next = removeNode(next, r.id);
1543
- onChange(next);
1544
- return;
1545
- }
1546
- const positional = changes.some((c) => c.type === "position" && c.dragging === false);
1547
- if (positional) {
1548
- const moved = nodes.map((n) => {
1549
- const change = changes.find((c) => c.type === "position" && c.id === n.id);
1550
- if (change && change.type === "position" && change.position) {
1551
- return { ...n, position: change.position };
1552
- }
1553
- return n;
1554
- });
1555
- onChange(applyNodePositions(graph, moved));
1556
- }
1557
- },
1558
- [graph, nodes, onChange, readOnly]
1559
- );
1560
- const onEdgesChange = useCallback(
1561
- (changes) => {
1562
- if (readOnly) return;
1563
- const removed = changes.filter(
1564
- (c) => c.type === "remove"
1565
- );
1566
- if (removed.length === 0) return;
1820
+ const { nodes: graphNodes, edges } = graphToFlow(graph, edgeIdentity);
1821
+ const nodes = graphNodes.map((node) => ({
1822
+ ...node,
1823
+ data: {
1824
+ ...node.data,
1825
+ view: renderNode(node.data.node)
1826
+ }
1827
+ }));
1828
+ const onNodesChange = (changes) => {
1829
+ if (readOnly) return;
1830
+ const removed = changes.filter(
1831
+ (c) => c.type === "remove"
1832
+ );
1833
+ if (removed.length > 0) {
1567
1834
  let next = graph;
1568
- for (const r of removed) next = removeFlowEdge(next, r.id, edgeIdentity);
1835
+ for (const r of removed) next = removeNode(next, r.id);
1569
1836
  onChange(next);
1570
- },
1571
- [graph, edgeIdentity, onChange, readOnly]
1572
- );
1573
- const onConnect = useCallback(
1574
- (connection) => {
1575
- if (readOnly) return;
1576
- const result = tryAddEdge(graph, connection, { makeEdge, edgeIdentity });
1577
- if (result.ok) {
1578
- setRejection(null);
1579
- onChange(result.graph);
1580
- } else {
1581
- setRejection(result.reason);
1582
- }
1583
- },
1584
- [graph, edgeIdentity, makeEdge, onChange, readOnly]
1585
- );
1837
+ return;
1838
+ }
1839
+ const positional = changes.some((c) => c.type === "position" && c.dragging === false);
1840
+ if (positional) {
1841
+ const moved = nodes.map((n) => {
1842
+ const change = changes.find((c) => c.type === "position" && c.id === n.id);
1843
+ if (change && change.type === "position" && change.position) {
1844
+ return { ...n, position: change.position };
1845
+ }
1846
+ return n;
1847
+ });
1848
+ onChange(applyNodePositions(graph, moved));
1849
+ }
1850
+ };
1851
+ const onEdgesChange = (changes) => {
1852
+ if (readOnly) return;
1853
+ const removed = changes.filter(
1854
+ (c) => c.type === "remove"
1855
+ );
1856
+ if (removed.length === 0) return;
1857
+ let next = graph;
1858
+ for (const r of removed) next = removeFlowEdge(next, r.id, edgeIdentity);
1859
+ onChange(next);
1860
+ };
1861
+ const onConnect = (connection) => {
1862
+ if (readOnly) return;
1863
+ const result = tryAddEdge(graph, connection, { makeEdge, edgeIdentity });
1864
+ if (result.ok) {
1865
+ setRejection(null);
1866
+ onChange(result.graph);
1867
+ } else {
1868
+ setRejection(result.reason);
1869
+ }
1870
+ };
1586
1871
  return /* @__PURE__ */ jsx(AnimateIn, { preset: "emerge", children: /* @__PURE__ */ jsx(
1587
1872
  "div",
1588
1873
  {
1589
1874
  style: XYFLOW_TOKEN_THEME,
1590
1875
  className: cn(
1591
- "relative h-[480px] w-full overflow-hidden rounded-xl border border-neutral-7 bg-neutral-1",
1876
+ "relative h-[480px] w-full overflow-hidden rounded-[var(--radius-xl)] border border-neutral-7 bg-neutral-1",
1592
1877
  className
1593
1878
  ),
1594
1879
  children: /* @__PURE__ */ jsx(ReactFlowProvider, { children: /* @__PURE__ */ jsxs(
@@ -1596,7 +1881,7 @@ function NodeGraphCanvas({
1596
1881
  {
1597
1882
  nodes,
1598
1883
  edges,
1599
- nodeTypes,
1884
+ nodeTypes: NODE_TYPES,
1600
1885
  onNodesChange,
1601
1886
  onEdgesChange,
1602
1887
  onConnect,
@@ -1604,7 +1889,7 @@ function NodeGraphCanvas({
1604
1889
  nodesConnectable: !readOnly,
1605
1890
  elementsSelectable: !readOnly,
1606
1891
  fitView: true,
1607
- proOptions: { hideAttribution: true },
1892
+ proOptions: REACT_FLOW_PRO_OPTIONS,
1608
1893
  children: [
1609
1894
  /* @__PURE__ */ jsx(Background, { color: "var(--neutral-6)" }),
1610
1895
  /* @__PURE__ */ jsx(Controls, { showInteractive: !readOnly }),
@@ -1614,7 +1899,7 @@ function NodeGraphCanvas({
1614
1899
  id: statusId,
1615
1900
  role: "alert",
1616
1901
  "aria-live": "assertive",
1617
- className: "flex items-center gap-2 rounded-md border border-destructive bg-destructive/10 px-3 py-2 text-sm text-destructive",
1902
+ className: "flex items-center gap-2 rounded-[var(--radius-md)] border border-destructive bg-destructive/10 px-3 py-2 text-sm text-destructive",
1618
1903
  children: [
1619
1904
  /* @__PURE__ */ jsx("span", { children: rejection }),
1620
1905
  /* @__PURE__ */ jsx(
@@ -1661,6 +1946,20 @@ var itemVariants = {
1661
1946
  }
1662
1947
  }
1663
1948
  };
1949
+ var reducedContainerVariants = {
1950
+ hidden: { opacity: 1 },
1951
+ visible: {
1952
+ opacity: 1,
1953
+ transition: { duration: 0 }
1954
+ }
1955
+ };
1956
+ var reducedItemVariants = {
1957
+ hidden: { opacity: 1 },
1958
+ visible: {
1959
+ opacity: 1,
1960
+ transition: { duration: 0 }
1961
+ }
1962
+ };
1664
1963
  function OnboardingChecklist({
1665
1964
  title,
1666
1965
  description,
@@ -1669,12 +1968,15 @@ function OnboardingChecklist({
1669
1968
  videoUrl,
1670
1969
  className
1671
1970
  }) {
1971
+ const shouldReduceMotion = useReducedMotion();
1972
+ const activeContainerVariants = shouldReduceMotion ? reducedContainerVariants : containerVariants;
1973
+ const activeItemVariants = shouldReduceMotion ? reducedItemVariants : itemVariants;
1672
1974
  return /* @__PURE__ */ jsx(
1673
1975
  motion.div,
1674
1976
  {
1675
1977
  initial: "hidden",
1676
1978
  animate: "visible",
1677
- variants: containerVariants,
1979
+ variants: activeContainerVariants,
1678
1980
  className: cn(
1679
1981
  "w-full max-w-4xl mx-auto bg-card text-card-foreground border rounded-[var(--radius-2xl)] shadow-sm p-8 overflow-hidden",
1680
1982
  className
@@ -1683,7 +1985,7 @@ function OnboardingChecklist({
1683
1985
  /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
1684
1986
  /* @__PURE__ */ jsx("h2", { className: "text-2xl font-bold tracking-tight", children: title }),
1685
1987
  /* @__PURE__ */ jsx("p", { className: "mt-2 text-muted-foreground", children: description }),
1686
- /* @__PURE__ */ jsx("ul", { className: "mt-6 grid grid-cols-1 sm:grid-cols-2 gap-x-8 gap-y-4", children: items.map((item) => /* @__PURE__ */ jsxs(motion.li, { variants: itemVariants, className: "flex flex-col", children: [
1988
+ /* @__PURE__ */ jsx("ul", { className: "mt-6 grid grid-cols-1 sm:grid-cols-2 gap-x-8 gap-y-4", children: items.map((item) => /* @__PURE__ */ jsxs(motion.li, { variants: activeItemVariants, className: "flex flex-col", children: [
1687
1989
  /* @__PURE__ */ jsxs("div", { className: "flex items-start", children: [
1688
1990
  /* @__PURE__ */ jsx(CheckCircle, { className: "h-5 w-5 text-green-500 mt-0.5 flex-shrink-0" }),
1689
1991
  /* @__PURE__ */ jsx("span", { className: "ml-3 text-sm font-medium", children: item.text })
@@ -1695,7 +1997,7 @@ function OnboardingChecklist({
1695
1997
  "a",
1696
1998
  {
1697
1999
  href: item.helperLink.href,
1698
- className: "text-primary underline-offset-4 hover:underline focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 rounded-[var(--radius-sm)]",
2000
+ className: "text-primary underline-offset-4 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-[var(--radius-sm)]",
1699
2001
  children: item.helperLink.text
1700
2002
  }
1701
2003
  )
@@ -1705,25 +2007,25 @@ function OnboardingChecklist({
1705
2007
  /* @__PURE__ */ jsx(
1706
2008
  motion.div,
1707
2009
  {
1708
- variants: itemVariants,
2010
+ variants: activeItemVariants,
1709
2011
  className: "relative group rounded-[var(--radius-lg)] overflow-hidden cursor-pointer w-full aspect-video",
1710
2012
  children: /* @__PURE__ */ jsxs(Dialog, { children: [
1711
2013
  /* @__PURE__ */ jsx(DialogTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
1712
2014
  "button",
1713
2015
  {
1714
2016
  type: "button",
1715
- className: "w-full h-full focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 rounded-[var(--radius-lg)]",
2017
+ className: "w-full h-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-[var(--radius-lg)]",
1716
2018
  children: [
1717
2019
  /* @__PURE__ */ jsx(
1718
2020
  Image,
1719
2021
  {
1720
2022
  src: videoThumbnailUrl,
1721
2023
  alt: "Video guide thumbnail",
1722
- className: "w-full h-full object-cover transition-transform duration-300 group-hover:scale-105",
2024
+ className: "w-full h-full object-cover transition-transform duration-300 group-hover:scale-105 motion-reduce:transition-none motion-reduce:group-hover:scale-100",
1723
2025
  fill: true
1724
2026
  }
1725
2027
  ),
1726
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/30 flex items-center justify-center", children: /* @__PURE__ */ jsx(PlayCircle, { className: "h-16 w-16 text-white/80 transform transition-all duration-300 group-hover:scale-110 group-hover:text-white" }) })
2028
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-black/30 flex items-center justify-center", children: /* @__PURE__ */ jsx(PlayCircle, { className: "h-16 w-16 text-white/80 transform transition-[background-color,border-color,box-shadow,color,opacity,transform] duration-300 group-hover:scale-110 group-hover:text-white motion-reduce:transition-none motion-reduce:group-hover:scale-100" }) })
1727
2029
  ]
1728
2030
  }
1729
2031
  ) }),
@@ -1817,7 +2119,7 @@ function subscribePlatform() {
1817
2119
  return () => void 0;
1818
2120
  }
1819
2121
  function usePlatform() {
1820
- return React6.useSyncExternalStore(subscribePlatform, getClientPlatform, () => "apple");
2122
+ return React5.useSyncExternalStore(subscribePlatform, getClientPlatform, () => "apple");
1821
2123
  }
1822
2124
  function normalizeKey(children) {
1823
2125
  if (typeof children !== "string") {
@@ -1832,54 +2134,63 @@ function normalizeKey(children) {
1832
2134
  function getModifierSymbols(platform) {
1833
2135
  return platform === "apple" ? appleModifierSymbols : otherModifierSymbols;
1834
2136
  }
1835
- var Kbd = React6.forwardRef(
1836
- ({ meta, shift, alt, ctrl, small, children, className, "aria-label": ariaLabel, ...props }, ref) => {
1837
- const platform = usePlatform();
1838
- const symbols = getModifierSymbols(platform);
1839
- const activeModifiers = modifierOrder.filter((modifier) => {
1840
- if (modifier === "meta") return meta;
1841
- if (modifier === "shift") return shift;
1842
- if (modifier === "alt") return alt;
1843
- return ctrl;
1844
- });
1845
- const normalizedKey = normalizeKey(children);
1846
- const visualParts = [
1847
- ...activeModifiers.map((modifier) => symbols[modifier]),
1848
- normalizedKey
1849
- ].filter(Boolean);
1850
- const accessibleName = ariaLabel ?? [
1851
- ...activeModifiers.map((modifier) => modifierLabels[modifier]),
1852
- typeof normalizedKey === "string" ? normalizedKey : void 0
1853
- ].filter(Boolean).join(" ");
1854
- return /* @__PURE__ */ jsx(
1855
- "kbd",
1856
- {
1857
- ref,
1858
- "aria-label": accessibleName || void 0,
1859
- className: cn(
1860
- "inline-flex select-none items-center justify-center gap-0.5 rounded-[var(--radius-sm)] border border-border bg-muted font-mono font-medium leading-none text-muted-foreground tabular-nums",
1861
- small ? "min-h-4 min-w-4 px-1 py-0 text-xs" : "min-h-5 min-w-5 px-1.5 py-0.5 text-xs",
1862
- className
1863
- ),
1864
- ...props,
1865
- children: visualParts.join("")
1866
- }
1867
- );
1868
- }
1869
- );
2137
+ var Kbd = ({
2138
+ meta,
2139
+ shift,
2140
+ alt,
2141
+ ctrl,
2142
+ small,
2143
+ children,
2144
+ className,
2145
+ "aria-label": ariaLabel,
2146
+ ref,
2147
+ ...props
2148
+ }) => {
2149
+ const platform = usePlatform();
2150
+ const symbols = getModifierSymbols(platform);
2151
+ const activeModifiers = modifierOrder.filter((modifier) => {
2152
+ if (modifier === "meta") return meta;
2153
+ if (modifier === "shift") return shift;
2154
+ if (modifier === "alt") return alt;
2155
+ return ctrl;
2156
+ });
2157
+ const normalizedKey = normalizeKey(children);
2158
+ const visualParts = [
2159
+ ...activeModifiers.map((modifier) => symbols[modifier]),
2160
+ normalizedKey
2161
+ ].filter(Boolean);
2162
+ const accessibleName = ariaLabel ?? [
2163
+ ...activeModifiers.map((modifier) => modifierLabels[modifier]),
2164
+ typeof normalizedKey === "string" ? normalizedKey : void 0
2165
+ ].filter(Boolean).join(" ");
2166
+ return /* @__PURE__ */ jsx(
2167
+ "kbd",
2168
+ {
2169
+ ref,
2170
+ "aria-label": accessibleName || void 0,
2171
+ className: cn(
2172
+ "inline-flex select-none items-center justify-center gap-0.5 rounded-[var(--radius-sm)] border border-border bg-muted font-mono font-medium leading-none text-muted-foreground tabular-nums",
2173
+ small ? "min-h-4 min-w-4 px-1 py-0 text-xs" : "min-h-5 min-w-5 px-1.5 py-0.5 text-xs",
2174
+ className
2175
+ ),
2176
+ ...props,
2177
+ children: visualParts.join("")
2178
+ }
2179
+ );
2180
+ };
1870
2181
  Kbd.displayName = "Kbd";
1871
2182
  var inputVariants = cva(
1872
2183
  [
1873
2184
  "flex h-[var(--input-height)] w-full rounded-[var(--input-radius)] border border-input bg-background",
1874
- "px-[var(--input-padding-x)] text-[length:var(--input-font-size)] text-foreground shadow-[var(--shadow-xs)]",
2185
+ "px-[var(--input-padding-x)] text-[length:var(--input-font-size)] text-foreground shadow-xs",
1875
2186
  "transition-[background-color,border-color,box-shadow,color] duration-micro ease-out",
1876
2187
  "placeholder:text-muted-foreground",
1877
- "outline-none focus:border-ring focus:ring-[length:var(--input-focus-ring-width)] focus:ring-ring/30",
2188
+ formControlFocusClassNames.input,
1878
2189
  "disabled:cursor-not-allowed disabled:opacity-50",
1879
2190
  "read-only:bg-muted/70 read-only:cursor-default",
1880
2191
  "file:h-full file:border-0 file:border-e file:border-solid file:border-input file:bg-transparent",
1881
2192
  "file:me-[var(--input-padding-x)] file:pe-[var(--input-padding-x)] file:text-[length:var(--input-font-size)] file:font-medium file:text-foreground",
1882
- "aria-invalid:border-destructive/60 aria-invalid:focus:border-destructive aria-invalid:focus:ring-destructive/20",
2193
+ formControlInvalidClassNames.input,
1883
2194
  "[&[type=search]::-webkit-search-cancel-button]:appearance-none",
1884
2195
  "[&[type=search]::-webkit-search-decoration]:appearance-none",
1885
2196
  "[&[type=search]::-webkit-search-results-button]:appearance-none",
@@ -1981,7 +2292,10 @@ function isTextAffix(value) {
1981
2292
  function joinDescriptionIds2(...ids) {
1982
2293
  return ids.filter(Boolean).join(" ") || void 0;
1983
2294
  }
1984
- var Input = React6.forwardRef((props, forwardedRef) => {
2295
+ var Input = ({
2296
+ ref: forwardedRef,
2297
+ ...props
2298
+ }) => {
1985
2299
  const {
1986
2300
  className,
1987
2301
  type = "text",
@@ -2014,16 +2328,16 @@ var Input = React6.forwardRef((props, forwardedRef) => {
2014
2328
  ...rest
2015
2329
  } = props;
2016
2330
  const isControlled = value !== void 0;
2017
- const baseId = React6.useId();
2018
- const inputRef = React6.useRef(null);
2331
+ const baseId = React5.useId();
2332
+ const inputRef = React5.useRef(null);
2019
2333
  const descriptionId = description && id ? `${id}-description` : void 0;
2020
2334
  const errorId = typeof error === "string" && id ? `${id}-error` : void 0;
2021
2335
  const prefixDescriptionId = isTextAffix(prefix) ? `${id ?? baseId}-prefix` : void 0;
2022
2336
  const suffixDescriptionId = isTextAffix(suffix) ? `${id ?? baseId}-suffix` : void 0;
2023
- const [internalValue, setInternalValue] = React6.useState(
2337
+ const [internalValue, setInternalValue] = React5.useState(
2024
2338
  typeof defaultValue === "string" || typeof defaultValue === "number" ? String(defaultValue) : ""
2025
2339
  );
2026
- const [passwordVisible, setPasswordVisible] = React6.useState(false);
2340
+ const [passwordVisible, setPasswordVisible] = React5.useState(false);
2027
2341
  const currentValue = isControlled ? String(value ?? "") : internalValue;
2028
2342
  const clearOnEscapeEnabled = clearOnEscape ?? type === "search";
2029
2343
  const canRevealPassword = Boolean(revealable && type === "password");
@@ -2043,7 +2357,7 @@ var Input = React6.forwardRef((props, forwardedRef) => {
2043
2357
  errorId
2044
2358
  );
2045
2359
  const valueProps = isControlled ? { value } : clearable || shortcut || clearOnEscapeEnabled ? { value: currentValue } : { defaultValue };
2046
- const setInputRef = React6.useCallback(
2360
+ const setInputRef = React5.useCallback(
2047
2361
  (node) => {
2048
2362
  const input = node instanceof HTMLInputElement ? node : null;
2049
2363
  inputRef.current = input;
@@ -2051,7 +2365,7 @@ var Input = React6.forwardRef((props, forwardedRef) => {
2051
2365
  },
2052
2366
  [forwardedRef]
2053
2367
  );
2054
- const emitNativeInput = React6.useCallback(
2368
+ const emitNativeInput = React5.useCallback(
2055
2369
  (nextValue) => {
2056
2370
  const input = inputRef.current;
2057
2371
  if (!input) {
@@ -2068,7 +2382,7 @@ var Input = React6.forwardRef((props, forwardedRef) => {
2068
2382
  },
2069
2383
  [isControlled, onValueChange]
2070
2384
  );
2071
- const syncInputValue = React6.useCallback(
2385
+ const syncInputValue = React5.useCallback(
2072
2386
  (event) => {
2073
2387
  if (!isControlled) setInternalValue(event.currentTarget.value);
2074
2388
  onValueChange?.(event.currentTarget.value);
@@ -2076,12 +2390,12 @@ var Input = React6.forwardRef((props, forwardedRef) => {
2076
2390
  },
2077
2391
  [isControlled, onChange, onValueChange]
2078
2392
  );
2079
- const handleClear = React6.useCallback(() => {
2393
+ const handleClear = React5.useCallback(() => {
2080
2394
  emitNativeInput("");
2081
2395
  onClear?.();
2082
2396
  inputRef.current?.focus();
2083
2397
  }, [emitNativeInput, onClear]);
2084
- const handleKeyDown = React6.useCallback(
2398
+ const handleKeyDown = React5.useCallback(
2085
2399
  (event) => {
2086
2400
  onKeyDown?.(event);
2087
2401
  if (event.defaultPrevented || event.key !== "Escape" || !clearOnEscapeEnabled || currentValue.length === 0 || disabled) {
@@ -2210,7 +2524,7 @@ var Input = React6.forwardRef((props, forwardedRef) => {
2210
2524
  ]
2211
2525
  }
2212
2526
  );
2213
- });
2527
+ };
2214
2528
  Input.displayName = "Input";
2215
2529
  function Avatar({ src, alt, isOnline, size = "md" }) {
2216
2530
  const sizeClasses = size === "sm" ? "w-10 h-10" : "w-10 h-10";
@@ -2271,16 +2585,16 @@ function TeamChat({
2271
2585
  "div",
2272
2586
  {
2273
2587
  className: cn(
2274
- "w-full max-w-5xl mx-auto p-6 bg-white dark:bg-black rounded-[var(--radius-3xl)] shadow-lg flex flex-col h-[550px] border border-[var(--neutral-7)]",
2588
+ "w-full max-w-5xl mx-auto p-6 bg-white dark:bg-black rounded-[var(--radius-3xl)] shadow-lg flex flex-col h-[550px] border border-border",
2275
2589
  className
2276
2590
  ),
2277
2591
  children: [
2278
- /* @__PURE__ */ jsxs("header", { className: "flex justify-between items-center border-b border-[var(--neutral-7)] pb-3 mb-6", children: [
2592
+ /* @__PURE__ */ jsxs("header", { className: "flex justify-between items-center border-b border-border pb-3 mb-6", children: [
2279
2593
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
2280
- /* @__PURE__ */ jsx(Users, { className: "w-8 h-8 text-black dark:text-white" }),
2594
+ /* @__PURE__ */ jsx(Users, { className: "w-8 h-8 text-black" }),
2281
2595
  /* @__PURE__ */ jsxs("div", { children: [
2282
- /* @__PURE__ */ jsx("h2", { className: "text-2xl font-semibold text-black dark:text-white", children: chatName }),
2283
- tagline && /* @__PURE__ */ jsx("p", { className: "italic text-sm text-[var(--neutral-10)]", children: tagline })
2596
+ /* @__PURE__ */ jsx("h2", { className: "text-2xl font-semibold text-black", children: chatName }),
2597
+ tagline && /* @__PURE__ */ jsx("p", { className: "italic text-sm text-muted-foreground", children: tagline })
2284
2598
  ] })
2285
2599
  ] }),
2286
2600
  /* @__PURE__ */ jsx(
@@ -2289,13 +2603,13 @@ function TeamChat({
2289
2603
  type: "button",
2290
2604
  "aria-label": "More options",
2291
2605
  onClick: onMoreOptions,
2292
- className: "p-2 rounded-[var(--radius-lg)] hover:bg-[var(--neutral-3)] transition",
2293
- children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "w-6 h-6 text-[var(--neutral-10)]" })
2606
+ className: "p-2 rounded-[var(--radius-lg)] hover:bg-muted transition",
2607
+ children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "w-6 h-6 text-muted-foreground" })
2294
2608
  }
2295
2609
  )
2296
2610
  ] }),
2297
- /* @__PURE__ */ jsxs("main", { className: "flex flex-1 overflow-hidden rounded-[var(--radius-xl)] border border-[var(--neutral-7)]", children: [
2298
- /* @__PURE__ */ jsx("aside", { className: "w-56 bg-[var(--neutral-2)] border-r border-[var(--neutral-7)] p-4 overflow-y-auto", children: uniqueSenders.map((sender) => {
2611
+ /* @__PURE__ */ jsxs("main", { className: "flex flex-1 overflow-hidden rounded-[var(--radius-xl)] border border-border", children: [
2612
+ /* @__PURE__ */ jsx("aside", { className: "w-56 bg-muted border-r border-border p-4 overflow-y-auto", children: uniqueSenders.map((sender) => {
2299
2613
  const isSelected = selectedSender === sender.name;
2300
2614
  return /* @__PURE__ */ jsxs(
2301
2615
  "button",
@@ -2304,7 +2618,7 @@ function TeamChat({
2304
2618
  onClick: () => setSelectedSender(isSelected ? null : sender.name),
2305
2619
  className: cn(
2306
2620
  "flex items-center gap-3 w-full p-3 mb-3 rounded-[var(--radius-lg)] transition-colors",
2307
- isSelected ? "bg-black dark:bg-white text-white dark:text-black" : "hover:bg-[var(--neutral-4)] text-[var(--neutral-12)]"
2621
+ isSelected ? "bg-black text-white dark:text-black" : "hover:bg-muted text-foreground"
2308
2622
  ),
2309
2623
  children: [
2310
2624
  /* @__PURE__ */ jsx(Avatar, { src: sender.avatar, alt: sender.name, isOnline: sender.isOnline }),
@@ -2314,57 +2628,50 @@ function TeamChat({
2314
2628
  sender.name
2315
2629
  );
2316
2630
  }) }),
2317
- /* @__PURE__ */ jsx("section", { className: "flex-1 p-6 overflow-y-auto bg-white dark:bg-black", children: filteredMessages.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-center text-[var(--neutral-9)]", children: "No messages to display." }) : filteredMessages.map((message) => /* @__PURE__ */ jsxs(
2318
- "div",
2319
- {
2320
- className: "mb-6 last:mb-0 group border-b border-[var(--neutral-6)] pb-4",
2321
- children: [
2322
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 mb-2", children: [
2323
- /* @__PURE__ */ jsx(Avatar, { src: message.sender.avatar, alt: message.sender.name }),
2324
- /* @__PURE__ */ jsxs("div", { children: [
2325
- /* @__PURE__ */ jsx("p", { className: "font-semibold text-black dark:text-white", children: message.sender.name }),
2326
- /* @__PURE__ */ jsx("span", { className: "text-xs text-[var(--neutral-9)]", children: message.timestamp })
2327
- ] })
2328
- ] }),
2329
- /* @__PURE__ */ jsx("p", { className: "text-[var(--neutral-12)] text-lg mb-1", children: message.content }),
2330
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm text-[var(--neutral-10)]", children: [
2331
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
2332
- message.status === "read" && /* @__PURE__ */ jsx(DoubleCheck, { className: "w-5 h-5 text-green-500" }),
2333
- message.status === "delivered" && /* @__PURE__ */ jsx(Check, { className: "w-5 h-5" }),
2334
- /* @__PURE__ */ jsx("span", { children: message.timestamp })
2335
- ] }),
2336
- /* @__PURE__ */ jsx("div", { className: "flex gap-2", children: message.reactions?.map((reaction) => /* @__PURE__ */ jsxs(
2337
- "button",
2338
- {
2339
- type: "button",
2340
- onClick: () => onReactionClick?.(message.id, reaction.emoji),
2341
- className: cn(
2342
- "px-2 py-1 rounded-[var(--radius-md)] text-sm transition-colors",
2343
- reaction.reacted ? "bg-[var(--neutral-5)] text-black dark:text-white" : "bg-[var(--neutral-3)] text-[var(--neutral-11)]",
2344
- "hover:bg-[var(--neutral-4)]"
2345
- ),
2346
- children: [
2347
- reaction.emoji,
2348
- " ",
2349
- reaction.count
2350
- ]
2351
- },
2352
- reaction.emoji
2353
- )) })
2354
- ] })
2355
- ]
2356
- },
2357
- message.id
2358
- )) })
2631
+ /* @__PURE__ */ jsx("section", { className: "flex-1 p-6 overflow-y-auto bg-white dark:bg-black", children: filteredMessages.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-center text-muted-foreground", children: "No messages to display." }) : filteredMessages.map((message) => /* @__PURE__ */ jsxs("div", { className: "mb-6 last:mb-0 group border-b border-border pb-4", children: [
2632
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 mb-2", children: [
2633
+ /* @__PURE__ */ jsx(Avatar, { src: message.sender.avatar, alt: message.sender.name }),
2634
+ /* @__PURE__ */ jsxs("div", { children: [
2635
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-black", children: message.sender.name }),
2636
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: message.timestamp })
2637
+ ] })
2638
+ ] }),
2639
+ /* @__PURE__ */ jsx("p", { className: "text-foreground text-lg mb-1", children: message.content }),
2640
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between text-sm text-muted-foreground", children: [
2641
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
2642
+ message.status === "read" && /* @__PURE__ */ jsx(DoubleCheck, { className: "w-5 h-5 text-green-500" }),
2643
+ message.status === "delivered" && /* @__PURE__ */ jsx(Check, { className: "w-5 h-5" }),
2644
+ /* @__PURE__ */ jsx("span", { children: message.timestamp })
2645
+ ] }),
2646
+ /* @__PURE__ */ jsx("div", { className: "flex gap-2", children: message.reactions?.map((reaction) => /* @__PURE__ */ jsxs(
2647
+ "button",
2648
+ {
2649
+ type: "button",
2650
+ onClick: () => onReactionClick?.(message.id, reaction.emoji),
2651
+ className: cn(
2652
+ "px-2 py-1 rounded-[var(--radius-md)] text-sm transition-colors",
2653
+ reaction.reacted ? "bg-[var(--neutral-5)] text-black" : "bg-muted text-muted-foreground",
2654
+ "hover:bg-muted"
2655
+ ),
2656
+ children: [
2657
+ reaction.emoji,
2658
+ " ",
2659
+ reaction.count
2660
+ ]
2661
+ },
2662
+ reaction.emoji
2663
+ )) })
2664
+ ] })
2665
+ ] }, message.id)) })
2359
2666
  ] }),
2360
- /* @__PURE__ */ jsxs("footer", { className: "mt-6 flex items-center gap-4 border-t border-[var(--neutral-7)] pt-4", children: [
2667
+ /* @__PURE__ */ jsxs("footer", { className: "mt-6 flex items-center gap-4 border-t border-border pt-4", children: [
2361
2668
  /* @__PURE__ */ jsx(
2362
2669
  "button",
2363
2670
  {
2364
2671
  type: "button",
2365
2672
  "aria-label": "Add emoji",
2366
- className: "p-3 rounded-full bg-[var(--neutral-3)] hover:bg-[var(--neutral-4)] transition",
2367
- children: /* @__PURE__ */ jsx(FacePlus, { className: "w-6 h-6 text-[var(--neutral-10)]" })
2673
+ className: "p-3 rounded-full bg-muted hover:bg-muted transition",
2674
+ children: /* @__PURE__ */ jsx(FacePlus, { className: "w-6 h-6 text-muted-foreground" })
2368
2675
  }
2369
2676
  ),
2370
2677
  /* @__PURE__ */ jsx(
@@ -2383,7 +2690,7 @@ function TeamChat({
2383
2690
  type: "button",
2384
2691
  "aria-label": "Send message",
2385
2692
  onClick: handleSend,
2386
- className: "p-3 rounded-full bg-black dark:bg-white text-white dark:text-black hover:brightness-90 transition",
2693
+ className: "p-3 rounded-full bg-black text-white dark:text-black hover:brightness-90 transition",
2387
2694
  children: /* @__PURE__ */ jsx(PaperAirplane, { className: "w-6 h-6" })
2388
2695
  }
2389
2696
  )
@@ -2393,6 +2700,6 @@ function TeamChat({
2393
2700
  );
2394
2701
  }
2395
2702
 
2396
- export { AnimateIn, AnimateInGroup, AsciiText, ChangelogWidget, NodeGraphCanvas, OnboardingChecklist, PromptInputBox, TeamChat };
2703
+ export { AnimateIn, AnimateInGroup, AnimatedCard, AnimatedDrawer, AnimatedList, AnimatedModal, AnimatedPopover, AsciiText, ChangelogWidget, FadeIn, ImageViewDialog, MAX_VISUALIZER_BARS, NodeGraphCanvas, OnboardingChecklist, PageTransition, PromptAttachmentPreviews, PromptInputBox, ScaleIn, SlideIn, TeamChat, VISUALIZER_BAR_STYLES, VoiceRecorder, animatedList, animatedListItem, animationDistances, animationDurations, animationEasings, animationSprings, animationTransitions, drawerSurface, fadeIn, formatRecordingTime, getFilePreviewKey, isImageFile, modalSurface, pageTransition, popoverSurface, preventDragDefaults, reducedMotionVariants, scaleIn, slideIn };
2397
2704
  //# sourceMappingURL=index.js.map
2398
2705
  //# sourceMappingURL=index.js.map