@wealthx/shadcn 1.5.39 → 1.5.41

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 (30) hide show
  1. package/.turbo/turbo-build.log +118 -118
  2. package/CHANGELOG.md +12 -0
  3. package/dist/{chunk-MGIDYXOP.mjs → chunk-DWNLBUDC.mjs} +459 -67
  4. package/dist/{chunk-EFHPSKVF.mjs → chunk-EGM4DARZ.mjs} +110 -1
  5. package/dist/{chunk-R7M657QL.mjs → chunk-GIQGZFP6.mjs} +138 -46
  6. package/dist/{chunk-B5PSUONN.mjs → chunk-TF5TOVIM.mjs} +1 -1
  7. package/dist/{chunk-RRROLESJ.mjs → chunk-XHZONBL4.mjs} +1 -1
  8. package/dist/components/ui/ai-assistant-drawer.js +101 -0
  9. package/dist/components/ui/ai-assistant-drawer.mjs +2 -2
  10. package/dist/components/ui/ai-conversations/index.js +101 -0
  11. package/dist/components/ui/ai-conversations/index.mjs +2 -2
  12. package/dist/components/ui/chat-input-area.js +101 -0
  13. package/dist/components/ui/chat-input-area.mjs +1 -1
  14. package/dist/components/ui/policy-ai/index.js +818 -261
  15. package/dist/components/ui/policy-ai/index.mjs +11 -2
  16. package/dist/components/ui/support-agent/index.js +233 -45
  17. package/dist/components/ui/support-agent/index.mjs +2 -2
  18. package/dist/index.js +3521 -3330
  19. package/dist/index.mjs +5 -5
  20. package/dist/styles.css +1 -1
  21. package/package.json +1 -1
  22. package/src/components/ui/chat-input-area.tsx +181 -2
  23. package/src/components/ui/policy-ai/index.tsx +12 -0
  24. package/src/components/ui/policy-ai/policy-ai-context-sidebar.tsx +231 -0
  25. package/src/components/ui/policy-ai/policy-ai-history-panel.tsx +175 -0
  26. package/src/components/ui/policy-ai/policy-ai-page.tsx +243 -0
  27. package/src/components/ui/policy-ai/policy-ai-panel.tsx +64 -57
  28. package/src/components/ui/policy-ai/policy-ai-responses.tsx +8 -12
  29. package/src/components/ui/support-agent/support-agent-panel.tsx +170 -48
  30. package/src/styles/styles-css.ts +1 -1
@@ -10,9 +10,109 @@ import {
10
10
 
11
11
  // src/components/ui/chat-input-area.tsx
12
12
  import * as React from "react";
13
- import { ImagePlus, Paperclip, Send } from "lucide-react";
13
+ import { flushSync } from "react-dom";
14
+ import {
15
+ Bold,
16
+ Code,
17
+ Code2,
18
+ ImagePlus,
19
+ Italic,
20
+ Paperclip,
21
+ Send
22
+ } from "lucide-react";
14
23
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
15
24
  var DEFAULT_HINT = "Enter to send \xB7 Shift+Enter for new line";
25
+ var TOOLBAR_ITEMS = [
26
+ {
27
+ type: "button",
28
+ icon: Bold,
29
+ label: "Bold",
30
+ title: "Bold (Ctrl+B)",
31
+ before: "**",
32
+ after: "**",
33
+ placeholder: "bold text"
34
+ },
35
+ {
36
+ type: "button",
37
+ icon: Italic,
38
+ label: "Italic",
39
+ title: "Italic (Ctrl+I)",
40
+ before: "*",
41
+ after: "*",
42
+ placeholder: "italic text"
43
+ },
44
+ {
45
+ type: "button",
46
+ icon: Code,
47
+ label: "Inline code",
48
+ title: "Inline code",
49
+ before: "`",
50
+ after: "`",
51
+ placeholder: "code"
52
+ },
53
+ { type: "divider" },
54
+ {
55
+ type: "button",
56
+ icon: Code2,
57
+ label: "Code block",
58
+ title: "Code block",
59
+ before: "```\n",
60
+ after: "\n```",
61
+ placeholder: "code block"
62
+ }
63
+ ];
64
+ function applyMarkdown(textarea, before, after, placeholder, onChange) {
65
+ const start = textarea.selectionStart;
66
+ const end = textarea.selectionEnd;
67
+ const selected = textarea.value.slice(start, end);
68
+ const insertion = selected || placeholder;
69
+ const next = textarea.value.slice(0, start) + before + insertion + after + textarea.value.slice(end);
70
+ const newStart = start + before.length;
71
+ const newEnd = newStart + insertion.length;
72
+ flushSync(() => onChange(next));
73
+ textarea.focus();
74
+ textarea.setSelectionRange(newStart, newEnd);
75
+ }
76
+ var MarkdownToolbar = React.memo(function MarkdownToolbar2({
77
+ textareaRef,
78
+ onChange,
79
+ disabled
80
+ }) {
81
+ const handleFormat = React.useCallback(
82
+ (e) => {
83
+ if (!textareaRef.current) return;
84
+ const { before, after, placeholder } = e.currentTarget.dataset;
85
+ applyMarkdown(textareaRef.current, before, after, placeholder, onChange);
86
+ },
87
+ [textareaRef, onChange]
88
+ );
89
+ return /* @__PURE__ */ jsx("div", { className: "flex items-center gap-0.5 border-b border-border px-2 py-1", children: TOOLBAR_ITEMS.map(
90
+ (item, i) => item.type === "divider" ? /* @__PURE__ */ jsx(
91
+ "span",
92
+ {
93
+ className: "mx-0.5 h-3.5 w-px bg-border",
94
+ "aria-hidden": "true"
95
+ },
96
+ i
97
+ ) : /* @__PURE__ */ jsx(
98
+ Button,
99
+ {
100
+ variant: "ghost",
101
+ size: "icon-sm",
102
+ type: "button",
103
+ title: item.title,
104
+ "aria-label": item.label,
105
+ disabled,
106
+ "data-before": item.before,
107
+ "data-after": item.after,
108
+ "data-placeholder": item.placeholder,
109
+ onClick: handleFormat,
110
+ children: /* @__PURE__ */ jsx(item.icon, { className: "size-3.5", "aria-hidden": "true" })
111
+ },
112
+ item.label
113
+ )
114
+ ) });
115
+ });
16
116
  function ChatInputArea({
17
117
  value,
18
118
  onChange,
@@ -24,6 +124,7 @@ function ChatInputArea({
24
124
  hint = DEFAULT_HINT,
25
125
  maxHeight = 160,
26
126
  autoFocus = false,
127
+ showMarkdownToolbar = false,
27
128
  className
28
129
  }) {
29
130
  const textareaRef = React.useRef(null);
@@ -92,6 +193,14 @@ function ChatInputArea({
92
193
  className: cn("flex flex-col gap-1.5", className),
93
194
  children: [
94
195
  /* @__PURE__ */ jsxs("div", { className: "border border-border bg-background flex flex-col focus-within:ring-1 focus-within:ring-ring", children: [
196
+ showMarkdownToolbar && /* @__PURE__ */ jsx(
197
+ MarkdownToolbar,
198
+ {
199
+ textareaRef,
200
+ onChange,
201
+ disabled
202
+ }
203
+ ),
95
204
  /* @__PURE__ */ jsx(
96
205
  Textarea,
97
206
  {
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-GTAVSBDO.mjs";
4
4
  import {
5
5
  ChatInputArea
6
- } from "./chunk-EFHPSKVF.mjs";
6
+ } from "./chunk-EGM4DARZ.mjs";
7
7
  import {
8
8
  Sheet,
9
9
  SheetContent
@@ -17,6 +17,11 @@ import {
17
17
  import {
18
18
  cn
19
19
  } from "./chunk-AFML43VJ.mjs";
20
+ import {
21
+ __objRest,
22
+ __spreadProps,
23
+ __spreadValues
24
+ } from "./chunk-WNQUEZJF.mjs";
20
25
 
21
26
  // src/components/ui/support-agent/support-agent-primitives.tsx
22
27
  import * as React from "react";
@@ -285,6 +290,9 @@ function SupportAgentFAB({
285
290
 
286
291
  // src/components/ui/support-agent/support-agent-panel.tsx
287
292
  import * as React2 from "react";
293
+ import ReactMarkdown from "react-markdown";
294
+ import rehypeRaw from "rehype-raw";
295
+ import rehypeSanitize, { defaultSchema } from "rehype-sanitize";
288
296
  import { Bot, ChevronLeft, ChevronRight, SquarePen, X as X2 } from "lucide-react";
289
297
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
290
298
  function SupportTypingIndicator() {
@@ -306,6 +314,21 @@ function SupportTypingIndicator() {
306
314
  }
307
315
  );
308
316
  }
317
+ function StreamingStatus({ label }) {
318
+ if (!label) return /* @__PURE__ */ jsx3(SupportTypingIndicator, {});
319
+ return /* @__PURE__ */ jsxs3(
320
+ "span",
321
+ {
322
+ className: "flex items-center gap-1.5 text-sm text-muted-foreground",
323
+ role: "status",
324
+ "aria-label": `${label}\u2026`,
325
+ children: [
326
+ /* @__PURE__ */ jsx3("span", { children: label }),
327
+ /* @__PURE__ */ jsx3(SupportTypingIndicator, {})
328
+ ]
329
+ }
330
+ );
331
+ }
309
332
  function MessageBubble({ message }) {
310
333
  const isUser = message.role === "user";
311
334
  const isEmpty = !message.content.trim();
@@ -328,7 +351,19 @@ function MessageBubble({ message }) {
328
351
  "data-slot": "support-message-bubble",
329
352
  "data-role": message.role,
330
353
  children: [
331
- isEmpty && message.isStreaming ? /* @__PURE__ */ jsx3(SupportTypingIndicator, {}) : /* @__PURE__ */ jsx3("span", { className: "whitespace-pre-wrap break-words leading-relaxed", children: message.content }),
354
+ isEmpty && message.isStreaming ? /* @__PURE__ */ jsx3(StreamingStatus, { label: message.streamingLabel }) : isUser ? /* @__PURE__ */ jsx3("span", { className: "whitespace-pre-wrap break-words leading-relaxed", children: message.content }) : /* @__PURE__ */ jsx3("div", { className: "break-words text-sm leading-relaxed [&_a]:text-primary [&_a]:underline [&_p]:m-0 [&_p:not(:last-child)]:mb-2 [&_ul]:my-1 [&_ul]:list-disc [&_ul]:pl-4 [&_ol]:my-1 [&_ol]:list-decimal [&_ol]:pl-4 [&_li]:mb-0.5", children: /* @__PURE__ */ jsx3(
355
+ ReactMarkdown,
356
+ {
357
+ rehypePlugins: [rehypeRaw, [rehypeSanitize, defaultSchema]],
358
+ components: {
359
+ a: (_a) => {
360
+ var _b = _a, { node } = _b, props = __objRest(_b, ["node"]);
361
+ return /* @__PURE__ */ jsx3("a", __spreadProps(__spreadValues({}, props), { target: "_blank", rel: "noopener noreferrer" }));
362
+ }
363
+ },
364
+ children: message.content
365
+ }
366
+ ) }),
332
367
  message.isErrored && /* @__PURE__ */ jsx3("p", { className: "mt-1 text-xs opacity-70", children: "Failed to send. Please try again." })
333
368
  ]
334
369
  }
@@ -361,6 +396,49 @@ function RichContentRenderer({ richContent }) {
361
396
  }
362
397
  return null;
363
398
  }
399
+ function CloseButton({ onClick }) {
400
+ return /* @__PURE__ */ jsxs3(
401
+ Button,
402
+ {
403
+ variant: "ghost",
404
+ size: "icon",
405
+ className: "size-7 shrink-0",
406
+ onClick,
407
+ title: "Close",
408
+ children: [
409
+ /* @__PURE__ */ jsx3(X2, { className: "size-3.5" }),
410
+ /* @__PURE__ */ jsx3("span", { className: "sr-only", children: "Close" })
411
+ ]
412
+ }
413
+ );
414
+ }
415
+ function ConversationRow({
416
+ conv,
417
+ onClick,
418
+ className
419
+ }) {
420
+ return /* @__PURE__ */ jsxs3(
421
+ "button",
422
+ {
423
+ type: "button",
424
+ onClick,
425
+ className: cn(
426
+ "flex w-full items-center justify-between gap-2 text-left text-sm text-foreground hover:bg-muted/50",
427
+ className
428
+ ),
429
+ children: [
430
+ /* @__PURE__ */ jsx3("span", { className: "flex-1 truncate", children: conv.title }),
431
+ /* @__PURE__ */ jsx3(
432
+ ChevronRight,
433
+ {
434
+ className: "size-3.5 shrink-0 text-muted-foreground",
435
+ "aria-hidden": "true"
436
+ }
437
+ )
438
+ ]
439
+ }
440
+ );
441
+ }
364
442
  function SupportAgentPanel({
365
443
  open,
366
444
  onClose,
@@ -382,9 +460,13 @@ function SupportAgentPanel({
382
460
  }) {
383
461
  var _a;
384
462
  const [inputValue, setInputValue] = React2.useState("");
463
+ const [showAllConversations, setShowAllConversations] = React2.useState(false);
385
464
  const messagesEndRef = React2.useRef(null);
386
465
  const hasMessages = messages.length > 0;
387
466
  const isChatMode = hasMessages && !!conversationTitle;
467
+ React2.useEffect(() => {
468
+ if (!open) setShowAllConversations(false);
469
+ }, [open]);
388
470
  React2.useEffect(() => {
389
471
  if (!messagesEndRef.current) return;
390
472
  messagesEndRef.current.scrollIntoView({
@@ -406,6 +488,17 @@ function SupportAgentPanel({
406
488
  [onSendMessage]
407
489
  );
408
490
  const hasRecents = !!(recentConversations == null ? void 0 : recentConversations.length);
491
+ const recentsPreview = React2.useMemo(
492
+ () => {
493
+ var _a2;
494
+ return (_a2 = recentConversations == null ? void 0 : recentConversations.slice(0, 3)) != null ? _a2 : [];
495
+ },
496
+ [recentConversations]
497
+ );
498
+ const handleViewAll = React2.useCallback(() => {
499
+ setShowAllConversations(true);
500
+ onViewAllConversations == null ? void 0 : onViewAllConversations();
501
+ }, [onViewAllConversations]);
409
502
  return /* @__PURE__ */ jsx3(Sheet, { open, onOpenChange: (o) => !o && onClose(), children: /* @__PURE__ */ jsxs3(
410
503
  SheetContent,
411
504
  {
@@ -418,38 +511,45 @@ function SupportAgentPanel({
418
511
  "data-slot": "support-agent-panel",
419
512
  children: [
420
513
  /* @__PURE__ */ jsxs3("div", { className: "shrink-0 border-b border-border px-3 py-2.5", children: [
421
- isChatMode ? (
422
- /* Chat mode: [←] Conversation title [✕] */
514
+ showAllConversations ? (
515
+ /* All-conversations mode: [←] All conversations [✕] */
423
516
  /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-1", children: [
424
- onBack && /* @__PURE__ */ jsxs3(
517
+ /* @__PURE__ */ jsxs3(
425
518
  Button,
426
519
  {
427
520
  variant: "ghost",
428
521
  size: "icon",
429
522
  className: "size-7 shrink-0",
430
- onClick: onBack,
431
- title: "Back to conversations",
523
+ onClick: () => setShowAllConversations(false),
524
+ title: "Back",
432
525
  children: [
433
526
  /* @__PURE__ */ jsx3(ChevronLeft, { className: "size-3.5" }),
434
527
  /* @__PURE__ */ jsx3("span", { className: "sr-only", children: "Back" })
435
528
  ]
436
529
  }
437
530
  ),
438
- /* @__PURE__ */ jsx3("span", { className: "flex-1 truncate px-1 text-sm font-medium text-foreground", children: conversationTitle }),
439
- /* @__PURE__ */ jsxs3(
531
+ /* @__PURE__ */ jsx3("span", { className: "flex-1 truncate px-1 text-sm font-medium text-foreground", children: "All conversations" }),
532
+ /* @__PURE__ */ jsx3(CloseButton, { onClick: onClose })
533
+ ] })
534
+ ) : isChatMode ? (
535
+ /* Chat mode: [←] Conversation title [✕] */
536
+ /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-1", children: [
537
+ onBack && /* @__PURE__ */ jsxs3(
440
538
  Button,
441
539
  {
442
540
  variant: "ghost",
443
541
  size: "icon",
444
542
  className: "size-7 shrink-0",
445
- onClick: onClose,
446
- title: "Close",
543
+ onClick: onBack,
544
+ title: "Back to conversations",
447
545
  children: [
448
- /* @__PURE__ */ jsx3(X2, { className: "size-3.5" }),
449
- /* @__PURE__ */ jsx3("span", { className: "sr-only", children: "Close" })
546
+ /* @__PURE__ */ jsx3(ChevronLeft, { className: "size-3.5" }),
547
+ /* @__PURE__ */ jsx3("span", { className: "sr-only", children: "Back" })
450
548
  ]
451
549
  }
452
- )
550
+ ),
551
+ /* @__PURE__ */ jsx3("span", { className: "flex-1 truncate px-1 text-sm font-medium text-foreground", children: conversationTitle }),
552
+ /* @__PURE__ */ jsx3(CloseButton, { onClick: onClose })
453
553
  ] })
454
554
  ) : (
455
555
  /* Home mode: [Bot icon] Support Assistant [✕] */
@@ -464,23 +564,10 @@ function SupportAgentPanel({
464
564
  ) }),
465
565
  /* @__PURE__ */ jsx3("span", { className: "text-sm font-semibold text-foreground", children: "Support Assistant" })
466
566
  ] }),
467
- /* @__PURE__ */ jsxs3(
468
- Button,
469
- {
470
- variant: "ghost",
471
- size: "icon",
472
- className: "size-7",
473
- onClick: onClose,
474
- title: "Close",
475
- children: [
476
- /* @__PURE__ */ jsx3(X2, { className: "size-3.5" }),
477
- /* @__PURE__ */ jsx3("span", { className: "sr-only", children: "Close" })
478
- ]
479
- }
480
- )
567
+ /* @__PURE__ */ jsx3(CloseButton, { onClick: onClose })
481
568
  ] })
482
569
  ),
483
- context && /* @__PURE__ */ jsx3("div", { className: "mt-2", children: /* @__PURE__ */ jsx3(SupportContextChip, { context }) })
570
+ context && !showAllConversations && /* @__PURE__ */ jsx3("div", { className: "mt-2", children: /* @__PURE__ */ jsx3(SupportContextChip, { context }) })
484
571
  ] }),
485
572
  /* @__PURE__ */ jsx3("div", { className: "flex flex-1 flex-col overflow-y-auto", children: isLoading ? (
486
573
  /* Loading state */
@@ -488,6 +575,20 @@ function SupportAgentPanel({
488
575
  /* @__PURE__ */ jsx3(Spinner, { size: "lg", className: "text-muted-foreground" }),
489
576
  /* @__PURE__ */ jsx3("p", { className: "text-sm text-muted-foreground", children: "Loading\u2026" })
490
577
  ] }) })
578
+ ) : showAllConversations ? (
579
+ /* All conversations — full scrollable list (Jira Rovo pattern) */
580
+ /* @__PURE__ */ jsx3("div", { className: "flex flex-col", children: (recentConversations == null ? void 0 : recentConversations.length) ? recentConversations.map((conv) => /* @__PURE__ */ jsx3(
581
+ ConversationRow,
582
+ {
583
+ conv,
584
+ onClick: () => {
585
+ setShowAllConversations(false);
586
+ onOpenConversation == null ? void 0 : onOpenConversation(conv.id);
587
+ },
588
+ className: "border-b border-border px-4 py-3"
589
+ },
590
+ conv.id
591
+ )) : /* @__PURE__ */ jsx3("p", { className: "p-4 text-sm text-muted-foreground", children: "No conversations yet." }) })
491
592
  ) : !hasMessages ? (
492
593
  /* Home state — Rovo pattern: New Chat CTA + Recents + Suggested */
493
594
  /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-5 p-4", children: [
@@ -506,31 +607,21 @@ function SupportAgentPanel({
506
607
  ),
507
608
  hasRecents && /* @__PURE__ */ jsxs3("div", { className: "flex flex-col gap-1", children: [
508
609
  /* @__PURE__ */ jsx3("p", { className: "px-1 text-xs font-medium uppercase tracking-wide text-muted-foreground", children: "Recents" }),
509
- /* @__PURE__ */ jsx3("div", { className: "flex flex-col", children: recentConversations.map((conv) => /* @__PURE__ */ jsxs3(
510
- "button",
610
+ /* @__PURE__ */ jsx3("div", { className: "flex flex-col", children: recentsPreview.map((conv) => /* @__PURE__ */ jsx3(
611
+ ConversationRow,
511
612
  {
512
- type: "button",
613
+ conv,
513
614
  onClick: () => onOpenConversation == null ? void 0 : onOpenConversation(conv.id),
514
- className: "flex w-full items-center justify-between gap-2 px-1 py-2.5 text-left text-sm text-foreground hover:bg-muted/50",
515
- children: [
516
- /* @__PURE__ */ jsx3("span", { className: "flex-1 truncate", children: conv.title }),
517
- /* @__PURE__ */ jsx3(
518
- ChevronRight,
519
- {
520
- className: "size-3.5 shrink-0 text-muted-foreground",
521
- "aria-hidden": "true"
522
- }
523
- )
524
- ]
615
+ className: "px-1 py-2.5"
525
616
  },
526
617
  conv.id
527
618
  )) }),
528
- onViewAllConversations && /* @__PURE__ */ jsxs3(
619
+ /* @__PURE__ */ jsxs3(
529
620
  Button,
530
621
  {
531
622
  variant: "ghost",
532
623
  size: "sm",
533
- onClick: onViewAllConversations,
624
+ onClick: handleViewAll,
534
625
  className: "h-auto w-fit gap-0.5 px-1 py-1 text-xs text-muted-foreground hover:bg-transparent hover:text-foreground",
535
626
  children: [
536
627
  "View all conversations",
@@ -569,7 +660,8 @@ function SupportAgentPanel({
569
660
  onAttachFile,
570
661
  onAttachImage,
571
662
  disabled: isLoading || isStreaming,
572
- placeholder: "Ask anything\u2026"
663
+ placeholder: "Ask anything\u2026",
664
+ showMarkdownToolbar: true
573
665
  }
574
666
  ) })
575
667
  ]
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ChatInputArea
3
- } from "./chunk-EFHPSKVF.mjs";
3
+ } from "./chunk-EGM4DARZ.mjs";
4
4
  import {
5
5
  Sheet,
6
6
  SheetContent
@@ -33,7 +33,7 @@ import {
33
33
  } from "./chunk-2GIYVERS.mjs";
34
34
  import {
35
35
  ChatInputArea
36
- } from "./chunk-EFHPSKVF.mjs";
36
+ } from "./chunk-EGM4DARZ.mjs";
37
37
  import {
38
38
  Textarea
39
39
  } from "./chunk-BS75ICOO.mjs";
@@ -369,6 +369,7 @@ function Badge(_a) {
369
369
 
370
370
  // src/components/ui/chat-input-area.tsx
371
371
  var React3 = __toESM(require("react"));
372
+ var import_react_dom = require("react-dom");
372
373
  var import_lucide_react3 = require("lucide-react");
373
374
 
374
375
  // src/components/ui/textarea.tsx
@@ -391,6 +392,97 @@ function Textarea(_a) {
391
392
  // src/components/ui/chat-input-area.tsx
392
393
  var import_jsx_runtime6 = require("react/jsx-runtime");
393
394
  var DEFAULT_HINT = "Enter to send \xB7 Shift+Enter for new line";
395
+ var TOOLBAR_ITEMS = [
396
+ {
397
+ type: "button",
398
+ icon: import_lucide_react3.Bold,
399
+ label: "Bold",
400
+ title: "Bold (Ctrl+B)",
401
+ before: "**",
402
+ after: "**",
403
+ placeholder: "bold text"
404
+ },
405
+ {
406
+ type: "button",
407
+ icon: import_lucide_react3.Italic,
408
+ label: "Italic",
409
+ title: "Italic (Ctrl+I)",
410
+ before: "*",
411
+ after: "*",
412
+ placeholder: "italic text"
413
+ },
414
+ {
415
+ type: "button",
416
+ icon: import_lucide_react3.Code,
417
+ label: "Inline code",
418
+ title: "Inline code",
419
+ before: "`",
420
+ after: "`",
421
+ placeholder: "code"
422
+ },
423
+ { type: "divider" },
424
+ {
425
+ type: "button",
426
+ icon: import_lucide_react3.Code2,
427
+ label: "Code block",
428
+ title: "Code block",
429
+ before: "```\n",
430
+ after: "\n```",
431
+ placeholder: "code block"
432
+ }
433
+ ];
434
+ function applyMarkdown(textarea, before, after, placeholder, onChange) {
435
+ const start = textarea.selectionStart;
436
+ const end = textarea.selectionEnd;
437
+ const selected = textarea.value.slice(start, end);
438
+ const insertion = selected || placeholder;
439
+ const next = textarea.value.slice(0, start) + before + insertion + after + textarea.value.slice(end);
440
+ const newStart = start + before.length;
441
+ const newEnd = newStart + insertion.length;
442
+ (0, import_react_dom.flushSync)(() => onChange(next));
443
+ textarea.focus();
444
+ textarea.setSelectionRange(newStart, newEnd);
445
+ }
446
+ var MarkdownToolbar = React3.memo(function MarkdownToolbar2({
447
+ textareaRef,
448
+ onChange,
449
+ disabled
450
+ }) {
451
+ const handleFormat = React3.useCallback(
452
+ (e) => {
453
+ if (!textareaRef.current) return;
454
+ const { before, after, placeholder } = e.currentTarget.dataset;
455
+ applyMarkdown(textareaRef.current, before, after, placeholder, onChange);
456
+ },
457
+ [textareaRef, onChange]
458
+ );
459
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "flex items-center gap-0.5 border-b border-border px-2 py-1", children: TOOLBAR_ITEMS.map(
460
+ (item, i) => item.type === "divider" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
461
+ "span",
462
+ {
463
+ className: "mx-0.5 h-3.5 w-px bg-border",
464
+ "aria-hidden": "true"
465
+ },
466
+ i
467
+ ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
468
+ Button,
469
+ {
470
+ variant: "ghost",
471
+ size: "icon-sm",
472
+ type: "button",
473
+ title: item.title,
474
+ "aria-label": item.label,
475
+ disabled,
476
+ "data-before": item.before,
477
+ "data-after": item.after,
478
+ "data-placeholder": item.placeholder,
479
+ onClick: handleFormat,
480
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(item.icon, { className: "size-3.5", "aria-hidden": "true" })
481
+ },
482
+ item.label
483
+ )
484
+ ) });
485
+ });
394
486
  function ChatInputArea({
395
487
  value,
396
488
  onChange,
@@ -402,6 +494,7 @@ function ChatInputArea({
402
494
  hint = DEFAULT_HINT,
403
495
  maxHeight = 160,
404
496
  autoFocus = false,
497
+ showMarkdownToolbar = false,
405
498
  className
406
499
  }) {
407
500
  const textareaRef = React3.useRef(null);
@@ -470,6 +563,14 @@ function ChatInputArea({
470
563
  className: cn("flex flex-col gap-1.5", className),
471
564
  children: [
472
565
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "border border-border bg-background flex flex-col focus-within:ring-1 focus-within:ring-ring", children: [
566
+ showMarkdownToolbar && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
567
+ MarkdownToolbar,
568
+ {
569
+ textareaRef,
570
+ onChange,
571
+ disabled
572
+ }
573
+ ),
473
574
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
474
575
  Textarea,
475
576
  {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  AiAssistantDrawer
3
- } from "../../chunk-B5PSUONN.mjs";
4
- import "../../chunk-EFHPSKVF.mjs";
3
+ } from "../../chunk-TF5TOVIM.mjs";
4
+ import "../../chunk-EGM4DARZ.mjs";
5
5
  import "../../chunk-H3PTREG6.mjs";
6
6
  import "../../chunk-BS75ICOO.mjs";
7
7
  import "../../chunk-JVMXMFBB.mjs";