@aircall/blocks 0.6.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,10 +1,12 @@
1
- import { Badge, Button, CounterBadge, DropdownMenu, DropdownMenuAddon, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, Field, FieldDescription, FieldError, FieldLabel, InputGroup, InputGroupButton, InputGroupTextarea, Sidebar, SidebarContent, SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuAction, SidebarMenuButton, SidebarMenuItem, SidebarProvider, TabsList, Tooltip, TooltipContent, TooltipTrigger, cn, registerI18nNamespace, useDsTranslation, useSidebar } from "@aircall/ds";
1
+ import { Anchor, Badge, Button, CounterBadge, DropdownMenu, DropdownMenuAddon, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, Field, FieldDescription, FieldError, FieldLabel, HoverCard, HoverCardContent, HoverCardTrigger, InputGroup, InputGroupButton, InputGroupTextarea, Item, ItemActions, ItemContent, ItemGroup, ItemMedia, ItemTitle, Popover, PopoverContent, PopoverTrigger, Separator, Sidebar, SidebarContent, SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuAction, SidebarMenuButton, SidebarMenuItem, SidebarProvider, TabsList, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipTrigger, cn, registerI18nNamespace, useDsTranslation, useSidebar } from "@aircall/ds";
2
2
  import * as React from "react";
3
3
  import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
4
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
- import { AircallLogo, ArrowUp, Check, ChevronLeft, ChevronRight, Copy, Ellipsis, LockKeyhole, PanelLeftClose, PanelLeftOpen, Plus, Search, Settings, Sprout, Square, TriangleAlert } from "@aircall/react-icons";
6
- import { cva } from "class-variance-authority";
5
+ import { AircallLogo, AircallMark, ArrowUp, Check, ChevronDown, ChevronLeft, ChevronRight, Copy, Ellipsis, ExternalLink, FileText, LockKeyhole, Menu, MessageSquare, Minus, PanelLeft, PanelLeftClose, PanelLeftOpen, Plus, Search, Settings, Sprout, Square, SquareArrowOutUpRight, ThumbsDown, ThumbsDownFilled, ThumbsUp, ThumbsUpFilled, TriangleAlert } from "@aircall/react-icons";
6
+ import ReactMarkdown from "react-markdown";
7
+ import remarkGfm from "remark-gfm";
7
8
  import { useCallbackRef, useControllableState, useIsMounted, useUnmount } from "@aircall/hooks";
9
+ import { cva } from "class-variance-authority";
8
10
  import { createFormHook, createFormHookContexts } from "@tanstack/react-form";
9
11
  import { mergeProps } from "@base-ui/react/merge-props";
10
12
  import { useRender } from "@base-ui/react/use-render";
@@ -26,7 +28,39 @@ const de = {
26
28
  "chatbotInput.placeholder": "Stellen Sie eine Frage...",
27
29
  "chatbotInput.messageLabel": "Nachricht",
28
30
  "chatbotInput.stopGenerating": "Generierung stoppen",
29
- "chatbotInput.sendMessage": "Nachricht senden"
31
+ "chatbotInput.sendMessage": "Nachricht senden",
32
+ "productBadge.beta": "Beta",
33
+ "productBadge.new": "Neu",
34
+ "productBadge.deprecated": "Veraltet",
35
+ "productBadge.trial": "Testversion",
36
+ "productBadge.professional": "Professional",
37
+ "roleBadge.agent": "Agent",
38
+ "roleBadge.supervisor": "Supervisor",
39
+ "roleBadge.admin": "Admin",
40
+ "roleBadge.owner": "Inhaber",
41
+ "chatbotResponse.copy": "Kopieren",
42
+ "chatbotResponse.helpful": "Hilfreich",
43
+ "chatbotResponse.notHelpful": "Nicht hilfreich",
44
+ "chatbotResponse.sourceCount_one": "{{count}} Quelle",
45
+ "chatbotResponse.sourceCount_other": "{{count}} Quellen",
46
+ "chatbotResponse.openSource": "{{title}} öffnen",
47
+ "chatbotPanel.sendFeedback": "Feedback senden",
48
+ "chatbotPanel.collapsePanel": "Panel einklappen",
49
+ "chatbotPanel.expandPanel": "Panel ausklappen",
50
+ "chatbotPanel.closePanel": "Panel schließen",
51
+ "chatbotSidebar.newChat": "Neuer Chat",
52
+ "chatbotSidebar.optionsFor": "Optionen für {{title}}",
53
+ "chatbotPage.footerBeforeLink": "Sie interagieren mit einem KI-Assistenten (Beta). Durch die Nutzung dieser Funktion akzeptieren Sie die ",
54
+ "chatbotPage.betaTermsLink": "Beta-Bedingungen",
55
+ "chatbotPage.footerAfterLink": " von Aircall. Die Antworten können ungenau oder unvollständig sein. Bitte überprüfen Sie diese bevor Sie sich darauf verlassen.",
56
+ "chatbotPage.scrollToBottom": "Nach unten scrollen",
57
+ "chatbotPanel.title": "Aircall fragen",
58
+ "chatbotPanel.emptyTitle": "Brauchen Sie Hilfe mit Aircall?",
59
+ "chatbotPanel.emptyDescription": "Finden Sie Antworten, entdecken Sie Funktionen und erhalten Sie Hilfe beim Verständnis von Aircall",
60
+ "chatbotPanel.disclaimerBefore": "Sie interagieren mit einem KI-Assistenten (Beta). Durch die Nutzung dieser Funktion akzeptieren Sie die ",
61
+ "chatbotPanel.disclaimerLink": "Beta-Bedingungen",
62
+ "chatbotPanel.disclaimerAfter": " von Aircall. Antworten können ungenau oder unvollständig sein. Bitte überprüfen Sie sie, bevor Sie sich darauf verlassen.",
63
+ "chatbotPanel.resizeHandle": "Panel-Größe ändern"
30
64
  };
31
65
  var de_default = de;
32
66
 
@@ -48,7 +82,39 @@ const en = {
48
82
  "chatbotInput.placeholder": "Ask anything...",
49
83
  "chatbotInput.messageLabel": "Message",
50
84
  "chatbotInput.stopGenerating": "Stop generating",
51
- "chatbotInput.sendMessage": "Send message"
85
+ "chatbotInput.sendMessage": "Send message",
86
+ "productBadge.beta": "Beta",
87
+ "productBadge.new": "New",
88
+ "productBadge.deprecated": "Deprecated",
89
+ "productBadge.trial": "Trial",
90
+ "productBadge.professional": "Professional",
91
+ "roleBadge.agent": "Agent",
92
+ "roleBadge.supervisor": "Supervisor",
93
+ "roleBadge.admin": "Admin",
94
+ "roleBadge.owner": "Owner",
95
+ "chatbotResponse.copy": "Copy",
96
+ "chatbotResponse.helpful": "Helpful",
97
+ "chatbotResponse.notHelpful": "Not helpful",
98
+ "chatbotResponse.sourceCount_one": "{{count}} Source",
99
+ "chatbotResponse.sourceCount_other": "{{count}} Sources",
100
+ "chatbotResponse.openSource": "Open {{title}}",
101
+ "chatbotPanel.sendFeedback": "Send feedback",
102
+ "chatbotPanel.collapsePanel": "Collapse panel",
103
+ "chatbotPanel.expandPanel": "Expand panel",
104
+ "chatbotPanel.closePanel": "Close panel",
105
+ "chatbotSidebar.newChat": "New chat",
106
+ "chatbotSidebar.optionsFor": "Options for {{title}}",
107
+ "chatbotPage.footerBeforeLink": "You are interacting with an AI assistant (Beta). By using this feature you accept Aircall's ",
108
+ "chatbotPage.betaTermsLink": "Beta terms",
109
+ "chatbotPage.footerAfterLink": ". Responses may be inaccurate or incomplete. Please verify before relying on them.",
110
+ "chatbotPage.scrollToBottom": "Scroll to bottom",
111
+ "chatbotPanel.title": "Ask Aircall",
112
+ "chatbotPanel.emptyTitle": "Need help with Aircall?",
113
+ "chatbotPanel.emptyDescription": "Find answers, explore features, and get help understanding Aircall",
114
+ "chatbotPanel.disclaimerBefore": "You are interacting with an AI assistant (Beta). By using this feature you accept Aircall's ",
115
+ "chatbotPanel.disclaimerLink": "Beta terms",
116
+ "chatbotPanel.disclaimerAfter": ". Responses may be inaccurate or incomplete. Please verify before relying on them.",
117
+ "chatbotPanel.resizeHandle": "Resize panel"
52
118
  };
53
119
  var en_default = en;
54
120
 
@@ -70,7 +136,39 @@ const es = {
70
136
  "chatbotInput.placeholder": "Pregunta lo que quieras...",
71
137
  "chatbotInput.messageLabel": "Mensaje",
72
138
  "chatbotInput.stopGenerating": "Detener la generación",
73
- "chatbotInput.sendMessage": "Enviar mensaje"
139
+ "chatbotInput.sendMessage": "Enviar mensaje",
140
+ "productBadge.beta": "Beta",
141
+ "productBadge.new": "Nuevo",
142
+ "productBadge.deprecated": "Obsoleto",
143
+ "productBadge.trial": "Prueba",
144
+ "productBadge.professional": "Profesional",
145
+ "roleBadge.agent": "Agente",
146
+ "roleBadge.supervisor": "Supervisor",
147
+ "roleBadge.admin": "Administrador",
148
+ "roleBadge.owner": "Propietario",
149
+ "chatbotResponse.copy": "Copiar",
150
+ "chatbotResponse.helpful": "Útil",
151
+ "chatbotResponse.notHelpful": "No útil",
152
+ "chatbotResponse.sourceCount_one": "{{count}} Fuente",
153
+ "chatbotResponse.sourceCount_other": "{{count}} Fuentes",
154
+ "chatbotResponse.openSource": "Abrir {{title}}",
155
+ "chatbotPanel.sendFeedback": "Enviar comentarios",
156
+ "chatbotPanel.collapsePanel": "Contraer panel",
157
+ "chatbotPanel.expandPanel": "Expandir panel",
158
+ "chatbotPanel.closePanel": "Cerrar panel",
159
+ "chatbotSidebar.newChat": "Nueva conversación",
160
+ "chatbotSidebar.optionsFor": "Opciones para {{title}}",
161
+ "chatbotPage.footerBeforeLink": "Estás interactuando con un asistente de IA (Beta). Al usar esta función, aceptas los ",
162
+ "chatbotPage.betaTermsLink": "términos Beta",
163
+ "chatbotPage.footerAfterLink": " de Aircall. Las respuestas pueden ser inexactas o incompletas. Por favor verifica antes de confiar en ellas.",
164
+ "chatbotPage.scrollToBottom": "Desplazarse hacia abajo",
165
+ "chatbotPanel.title": "Preguntar a Aircall",
166
+ "chatbotPanel.emptyTitle": "¿Necesitas ayuda con Aircall?",
167
+ "chatbotPanel.emptyDescription": "Encuentra respuestas, explora funciones y obtén ayuda para entender Aircall",
168
+ "chatbotPanel.disclaimerBefore": "Estás interactuando con un asistente de IA (Beta). Al usar esta función, aceptas los ",
169
+ "chatbotPanel.disclaimerLink": "términos de la Beta",
170
+ "chatbotPanel.disclaimerAfter": " de Aircall. Las respuestas pueden ser inexactas o incompletas. Verifícalas antes de confiar en ellas.",
171
+ "chatbotPanel.resizeHandle": "Redimensionar el panel"
74
172
  };
75
173
  var es_default = es;
76
174
 
@@ -92,7 +190,39 @@ const fr = {
92
190
  "chatbotInput.placeholder": "Posez votre question...",
93
191
  "chatbotInput.messageLabel": "Message",
94
192
  "chatbotInput.stopGenerating": "Arrêter la génération",
95
- "chatbotInput.sendMessage": "Envoyer un message"
193
+ "chatbotInput.sendMessage": "Envoyer un message",
194
+ "productBadge.beta": "Bêta",
195
+ "productBadge.new": "Nouveau",
196
+ "productBadge.deprecated": "Obsolète",
197
+ "productBadge.trial": "Essai",
198
+ "productBadge.professional": "Professionnel",
199
+ "roleBadge.agent": "Agent",
200
+ "roleBadge.supervisor": "Superviseur",
201
+ "roleBadge.admin": "Admin",
202
+ "roleBadge.owner": "Propriétaire",
203
+ "chatbotResponse.copy": "Copier",
204
+ "chatbotResponse.helpful": "Utile",
205
+ "chatbotResponse.notHelpful": "Pas utile",
206
+ "chatbotResponse.sourceCount_one": "{{count}} Source",
207
+ "chatbotResponse.sourceCount_other": "{{count}} Sources",
208
+ "chatbotResponse.openSource": "Ouvrir {{title}}",
209
+ "chatbotPanel.sendFeedback": "Envoyer un commentaire",
210
+ "chatbotPanel.collapsePanel": "Réduire le panneau",
211
+ "chatbotPanel.expandPanel": "Développer le panneau",
212
+ "chatbotPanel.closePanel": "Fermer le panneau",
213
+ "chatbotSidebar.newChat": "Nouvelle conversation",
214
+ "chatbotSidebar.optionsFor": "Options pour {{title}}",
215
+ "chatbotPage.footerBeforeLink": "Vous interagissez avec un assistant IA (Bêta). En utilisant cette fonctionnalité, vous acceptez les ",
216
+ "chatbotPage.betaTermsLink": "conditions Bêta",
217
+ "chatbotPage.footerAfterLink": " d'Aircall. Les réponses peuvent être inexactes ou incomplètes. Veuillez vérifier avant de vous y fier.",
218
+ "chatbotPage.scrollToBottom": "Défiler vers le bas",
219
+ "chatbotPanel.title": "Demander à Aircall",
220
+ "chatbotPanel.emptyTitle": "Besoin d'aide avec Aircall ?",
221
+ "chatbotPanel.emptyDescription": "Trouvez des réponses, explorez les fonctionnalités et obtenez de l’aide pour comprendre Aircall",
222
+ "chatbotPanel.disclaimerBefore": "Vous interagissez avec un assistant IA (bêta). En utilisant cette fonctionnalité, vous acceptez les ",
223
+ "chatbotPanel.disclaimerLink": "conditions de la bêta",
224
+ "chatbotPanel.disclaimerAfter": " d’Aircall. Les réponses peuvent être inexactes ou incomplètes. Veuillez les vérifier avant de vous y fier.",
225
+ "chatbotPanel.resizeHandle": "Redimensionner le panneau"
96
226
  };
97
227
  var fr_default = fr;
98
228
 
@@ -114,7 +244,39 @@ const it = {
114
244
  "chatbotInput.placeholder": "Chiedi qualsiasi cosa...",
115
245
  "chatbotInput.messageLabel": "Messaggio",
116
246
  "chatbotInput.stopGenerating": "Interrompi la generazione",
117
- "chatbotInput.sendMessage": "Invia messaggio"
247
+ "chatbotInput.sendMessage": "Invia messaggio",
248
+ "productBadge.beta": "Beta",
249
+ "productBadge.new": "Nuovo",
250
+ "productBadge.deprecated": "Obsoleto",
251
+ "productBadge.trial": "Prova",
252
+ "productBadge.professional": "Professional",
253
+ "roleBadge.agent": "Agente",
254
+ "roleBadge.supervisor": "Supervisore",
255
+ "roleBadge.admin": "Admin",
256
+ "roleBadge.owner": "Proprietario",
257
+ "chatbotResponse.copy": "Copia",
258
+ "chatbotResponse.helpful": "Utile",
259
+ "chatbotResponse.notHelpful": "Non utile",
260
+ "chatbotResponse.sourceCount_one": "{{count}} Fonte",
261
+ "chatbotResponse.sourceCount_other": "{{count}} Fonti",
262
+ "chatbotResponse.openSource": "Apri {{title}}",
263
+ "chatbotPanel.sendFeedback": "Invia feedback",
264
+ "chatbotPanel.collapsePanel": "Comprimi pannello",
265
+ "chatbotPanel.expandPanel": "Espandi pannello",
266
+ "chatbotPanel.closePanel": "Chiudi pannello",
267
+ "chatbotSidebar.newChat": "Nuova chat",
268
+ "chatbotSidebar.optionsFor": "Opzioni per {{title}}",
269
+ "chatbotPage.footerBeforeLink": "Stai interagendo con un assistente IA (Beta). Usando questa funzione, accetti i ",
270
+ "chatbotPage.betaTermsLink": "termini Beta",
271
+ "chatbotPage.footerAfterLink": " di Aircall. Le risposte potrebbero essere inesatte o incomplete. Si prega di verificare prima di affidarsi ad esse.",
272
+ "chatbotPage.scrollToBottom": "Scorri verso il basso",
273
+ "chatbotPanel.title": "Chiedi ad Aircall",
274
+ "chatbotPanel.emptyTitle": "Hai bisogno di aiuto con Aircall?",
275
+ "chatbotPanel.emptyDescription": "Trova risposte, esplora le funzionalità e ottieni aiuto per comprendere Aircall",
276
+ "chatbotPanel.disclaimerBefore": "Stai interagendo con un assistente IA (Beta). Utilizzando questa funzionalità accetti i ",
277
+ "chatbotPanel.disclaimerLink": "termini della Beta",
278
+ "chatbotPanel.disclaimerAfter": " di Aircall. Le risposte possono essere inesatte o incomplete. Verificale prima di farne affidamento.",
279
+ "chatbotPanel.resizeHandle": "Ridimensiona il pannello"
118
280
  };
119
281
  var it_default = it;
120
282
 
@@ -371,6 +533,255 @@ const UnknownErrorMedia = UnknownError.Media;
371
533
  const UnknownErrorTitle = UnknownError.Title;
372
534
  const UnknownErrorDescription = UnknownError.Description;
373
535
 
536
+ //#endregion
537
+ //#region src/hooks/use-copy-to-clipboard.ts
538
+ function useCopyToClipboard(value, { timeout = 5e3, onCopied } = {}) {
539
+ const [copied, setCopied] = useState(false);
540
+ const timerRef = useRef(void 0);
541
+ const getIsMounted = useIsMounted();
542
+ const onCopiedRef = useCallbackRef(onCopied);
543
+ useUnmount(() => clearTimeout(timerRef.current));
544
+ useEffect(() => {
545
+ clearTimeout(timerRef.current);
546
+ setCopied(false);
547
+ }, [value]);
548
+ return {
549
+ copy: useCallback(async () => {
550
+ try {
551
+ await navigator.clipboard.writeText(value);
552
+ if (!getIsMounted()) return;
553
+ setCopied(true);
554
+ onCopiedRef();
555
+ clearTimeout(timerRef.current);
556
+ timerRef.current = setTimeout(() => {
557
+ if (getIsMounted()) setCopied(false);
558
+ }, timeout);
559
+ } catch {}
560
+ }, [
561
+ value,
562
+ timeout,
563
+ getIsMounted,
564
+ onCopiedRef
565
+ ]),
566
+ copied
567
+ };
568
+ }
569
+
570
+ //#endregion
571
+ //#region src/components/copy-button.tsx
572
+ const CopyButtonContext = createContext(null);
573
+ function useCopyButtonContext() {
574
+ const ctx = useContext(CopyButtonContext);
575
+ if (ctx === null) throw new Error("CopyButtonIcon and CopyButtonLabel must be rendered inside a CopyButton.");
576
+ return ctx;
577
+ }
578
+ const CopyButton = React.forwardRef((componentProps, forwardRef) => {
579
+ const { value, timeout, onCopied, variant = "outline", children, ...buttonProps } = componentProps;
580
+ const { copy, copied } = useCopyToClipboard(value, {
581
+ timeout,
582
+ onCopied
583
+ });
584
+ return /* @__PURE__ */ jsx(CopyButtonContext.Provider, {
585
+ value: { copied },
586
+ children: /* @__PURE__ */ jsx(Button, {
587
+ ref: forwardRef,
588
+ onClick: () => {
589
+ copy();
590
+ },
591
+ variant,
592
+ ...buttonProps,
593
+ children
594
+ })
595
+ });
596
+ });
597
+ CopyButton.displayName = "CopyButton";
598
+ const CopyButtonIcon = React.forwardRef((componentProps, forwardRef) => {
599
+ const { className } = componentProps;
600
+ const { copied } = useCopyButtonContext();
601
+ return /* @__PURE__ */ jsx(copied ? Check : Copy, {
602
+ ref: forwardRef,
603
+ className
604
+ });
605
+ });
606
+ CopyButtonIcon.displayName = "CopyButtonIcon";
607
+ const CopyButtonLabel = React.forwardRef((componentProps, forwardRef) => {
608
+ const { label = "Copy", copiedLabel = "Copied", className } = componentProps;
609
+ const { copied } = useCopyButtonContext();
610
+ return /* @__PURE__ */ jsx("span", {
611
+ ref: forwardRef,
612
+ className: cn(className),
613
+ children: copied ? copiedLabel : label
614
+ });
615
+ });
616
+ CopyButtonLabel.displayName = "CopyButtonLabel";
617
+
618
+ //#endregion
619
+ //#region src/components/chatbot-response-block.tsx
620
+ function SourcesBadge({ sources }) {
621
+ const t = useDsTranslation("blocks");
622
+ return /* @__PURE__ */ jsxs(HoverCard, { children: [/* @__PURE__ */ jsx(HoverCardTrigger, {
623
+ render: /* @__PURE__ */ jsx(Button, {
624
+ variant: "secondary",
625
+ size: "sm"
626
+ }),
627
+ children: t("chatbotResponse.sourceCount", { count: sources.length })
628
+ }), /* @__PURE__ */ jsx(HoverCardContent, {
629
+ side: "top",
630
+ align: "start",
631
+ className: "w-80 p-1",
632
+ children: /* @__PURE__ */ jsx(ItemGroup, { children: sources.map((source) => /* @__PURE__ */ jsx("div", {
633
+ role: "listitem",
634
+ children: /* @__PURE__ */ jsxs(Item, {
635
+ size: "xs",
636
+ render: /* @__PURE__ */ jsx("a", {
637
+ href: source.url,
638
+ target: "_blank",
639
+ rel: "noreferrer noopener",
640
+ "aria-label": t("chatbotResponse.openSource", { title: source.title })
641
+ }),
642
+ children: [
643
+ /* @__PURE__ */ jsx(ItemMedia, {
644
+ variant: "icon",
645
+ children: /* @__PURE__ */ jsx(FileText, {})
646
+ }),
647
+ /* @__PURE__ */ jsx(ItemContent, { children: /* @__PURE__ */ jsx(ItemTitle, { children: source.title }) }),
648
+ /* @__PURE__ */ jsx(ItemActions, { children: /* @__PURE__ */ jsx(ExternalLink, { className: "size-4" }) })
649
+ ]
650
+ })
651
+ }, source.url)) })
652
+ })] });
653
+ }
654
+ function ChatbotResponseBlock({ messageId, markdown, streaming = false, sources, onFeedback, className }) {
655
+ const t = useDsTranslation("blocks");
656
+ const [feedback, setFeedback] = useState(null);
657
+ const onFeedbackRef = useCallbackRef(onFeedback);
658
+ const isMounted = useRef(false);
659
+ const feedbackRef = useRef(feedback);
660
+ feedbackRef.current = feedback;
661
+ useEffect(() => {
662
+ if (!isMounted.current) {
663
+ isMounted.current = true;
664
+ return;
665
+ }
666
+ if (feedbackRef.current === null) return;
667
+ setFeedback(null);
668
+ onFeedbackRef(null);
669
+ }, [
670
+ messageId,
671
+ markdown,
672
+ onFeedbackRef
673
+ ]);
674
+ function handleFeedback(value) {
675
+ const next = feedback === value ? null : value;
676
+ setFeedback(next);
677
+ onFeedback?.(next);
678
+ }
679
+ return /* @__PURE__ */ jsxs("div", {
680
+ "data-slot": "chatbot-response-block",
681
+ className: cn("flex flex-col gap-2", className),
682
+ children: [/* @__PURE__ */ jsx(ReactMarkdown, {
683
+ remarkPlugins: [remarkGfm],
684
+ components: {
685
+ h1: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("h1", {
686
+ className: "mt-10 text-4xl font-semibold first:mt-0",
687
+ ...props
688
+ }),
689
+ h2: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("h2", {
690
+ className: "mt-11 border-b border-border pb-2 text-3xl font-semibold leading-9 first:mt-0",
691
+ ...props
692
+ }),
693
+ h3: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("h3", {
694
+ className: "mt-10 text-2xl font-semibold leading-8 first:mt-0",
695
+ ...props
696
+ }),
697
+ p: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("p", {
698
+ className: "mt-4 text-base leading-6 text-foreground first:mt-0",
699
+ ...props
700
+ }),
701
+ blockquote: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("blockquote", {
702
+ className: "mt-4 border-l-2 border-border pl-6 first:mt-0",
703
+ ...props
704
+ }),
705
+ ul: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("ul", {
706
+ className: "mt-4 list-disc pl-6 text-base leading-6 text-foreground first:mt-0",
707
+ ...props
708
+ }),
709
+ ol: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("ol", {
710
+ className: "mt-4 list-decimal pl-6 text-base leading-6 text-foreground first:mt-0",
711
+ ...props
712
+ }),
713
+ li: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("li", {
714
+ className: "mb-2 last:mb-0",
715
+ ...props
716
+ }),
717
+ a: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("a", {
718
+ className: "text-green-700 underline underline-offset-2 hover:text-green-700/80",
719
+ ...props
720
+ }),
721
+ table: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("div", {
722
+ className: "mt-4 overflow-x-auto rounded border border-border first:mt-0",
723
+ children: /* @__PURE__ */ jsx("table", {
724
+ className: "w-full text-base leading-6",
725
+ ...props
726
+ })
727
+ }),
728
+ th: ({ node: _n, style, ...props }) => /* @__PURE__ */ jsx("th", {
729
+ className: "border-t border-border px-4 py-2 text-left font-bold text-foreground",
730
+ style,
731
+ ...props
732
+ }),
733
+ td: ({ node: _n, style, ...props }) => /* @__PURE__ */ jsx("td", {
734
+ className: "border-t border-border px-4 py-2 text-foreground",
735
+ style,
736
+ ...props
737
+ }),
738
+ tr: ({ node: _n, ...props }) => /* @__PURE__ */ jsx("tr", {
739
+ className: "even:bg-muted",
740
+ ...props
741
+ })
742
+ },
743
+ children: markdown
744
+ }), !streaming && /* @__PURE__ */ jsxs("div", {
745
+ className: "flex items-center gap-1",
746
+ children: [sources && sources.length > 0 && /* @__PURE__ */ jsx("div", {
747
+ className: "flex flex-1",
748
+ children: /* @__PURE__ */ jsx(SourcesBadge, { sources })
749
+ }), /* @__PURE__ */ jsxs("div", {
750
+ className: "ml-auto flex items-center gap-1",
751
+ children: [
752
+ /* @__PURE__ */ jsx(CopyButton, {
753
+ value: markdown,
754
+ variant: "ghost",
755
+ size: "icon-sm",
756
+ "aria-label": t("chatbotResponse.copy"),
757
+ children: /* @__PURE__ */ jsx(CopyButtonIcon, {})
758
+ }),
759
+ /* @__PURE__ */ jsx(Button, {
760
+ type: "button",
761
+ variant: "ghost",
762
+ size: "icon-sm",
763
+ "aria-pressed": feedback === "up",
764
+ "aria-label": t("chatbotResponse.helpful"),
765
+ onClick: () => handleFeedback("up"),
766
+ className: cn(feedback === "up" && "text-primary"),
767
+ children: feedback === "up" ? /* @__PURE__ */ jsx(ThumbsUpFilled, {}) : /* @__PURE__ */ jsx(ThumbsUp, {})
768
+ }),
769
+ /* @__PURE__ */ jsx(Button, {
770
+ type: "button",
771
+ variant: "ghost",
772
+ size: "icon-sm",
773
+ "aria-pressed": feedback === "down",
774
+ "aria-label": t("chatbotResponse.notHelpful"),
775
+ onClick: () => handleFeedback("down"),
776
+ className: cn(feedback === "down" && "text-primary"),
777
+ children: feedback === "down" ? /* @__PURE__ */ jsx(ThumbsDownFilled, {}) : /* @__PURE__ */ jsx(ThumbsDown, {})
778
+ })
779
+ ]
780
+ })]
781
+ })]
782
+ });
783
+ }
784
+
374
785
  //#endregion
375
786
  //#region src/components/chatbot-page.tsx
376
787
  const ChatbotPage = React.forwardRef((componentProps, forwardRef) => {
@@ -383,49 +794,326 @@ const ChatbotPage = React.forwardRef((componentProps, forwardRef) => {
383
794
  });
384
795
  });
385
796
  ChatbotPage.displayName = "ChatbotPage";
797
+ /**
798
+ * Content area that fills the right side of `ChatbotPage`. Use alongside
799
+ * `ChatbotSidebar` as a direct child of `ChatbotPage`.
800
+ *
801
+ * In the **idle state** place `ChatbotPageBody`, then `ChatbotPageFooter`.
802
+ * In the **active conversation state** place `ChatbotPageConversation`,
803
+ * `ChatbotPageInputBar`, then `ChatbotPageFooter`.
804
+ *
805
+ * @example
806
+ * ```tsx
807
+ * <ChatbotPage>
808
+ * <ChatbotSidebar conversations={[...]} />
809
+ * <ChatbotPageContent>
810
+ * <ChatbotPageBody>
811
+ * <ChatbotPageHeading>Need help with Aircall?</ChatbotPageHeading>
812
+ * <ChatbotInput />
813
+ * <ChatbotExpandSuggestion categories={[...]} suggestions={[...]} />
814
+ * </ChatbotPageBody>
815
+ * <ChatbotPageFooter betaTermsHref="https://legal.aircall.io/..." />
816
+ * </ChatbotPageContent>
817
+ * </ChatbotPage>
818
+ * ```
819
+ */
820
+ const ChatbotPageContent = React.forwardRef((componentProps, forwardRef) => {
821
+ const { className, ...props } = componentProps;
822
+ return /* @__PURE__ */ jsx("div", {
823
+ ref: forwardRef,
824
+ "data-slot": "chatbot-page-content",
825
+ className: cn("flex flex-1 flex-col items-center bg-background px-4", className),
826
+ ...props
827
+ });
828
+ });
829
+ ChatbotPageContent.displayName = "ChatbotPageContent";
830
+ /**
831
+ * Centered content area for the idle/empty state inside `ChatbotPageContent`.
832
+ * Constrains children to a max-width of 896px and vertically centers them.
833
+ * Place `ChatbotPageHeading`, `ChatbotInput`, and `ChatbotExpandSuggestion`
834
+ * as children.
835
+ */
836
+ const ChatbotPageBody = React.forwardRef((componentProps, forwardRef) => {
837
+ const { className, ...props } = componentProps;
838
+ return /* @__PURE__ */ jsx("div", {
839
+ ref: forwardRef,
840
+ "data-slot": "chatbot-page-body",
841
+ className: cn("relative z-[2] flex w-full max-w-[896px] flex-1 flex-col items-center justify-center gap-6", className),
842
+ ...props
843
+ });
844
+ });
845
+ ChatbotPageBody.displayName = "ChatbotPageBody";
846
+ /**
847
+ * Centered heading displayed above the input area in the idle state.
848
+ * Renders an `<h2>` element styled at 24px / medium weight.
849
+ *
850
+ * @example
851
+ * ```tsx
852
+ * <ChatbotPageHeading>Need help with Aircall?</ChatbotPageHeading>
853
+ * ```
854
+ */
855
+ const ChatbotPageHeading = React.forwardRef((componentProps, forwardRef) => {
856
+ const { className, ...props } = componentProps;
857
+ return /* @__PURE__ */ jsx("h2", {
858
+ ref: forwardRef,
859
+ "data-slot": "chatbot-page-heading",
860
+ className: cn("min-w-full text-center text-2xl font-medium text-foreground", className),
861
+ ...props
862
+ });
863
+ });
864
+ ChatbotPageHeading.displayName = "ChatbotPageHeading";
865
+ /**
866
+ * Footer bar showing the AI beta disclaimer. The "Beta terms" phrase is
867
+ * rendered as an external `Anchor` link pointing to `betaTermsHref`.
868
+ *
869
+ * @example
870
+ * ```tsx
871
+ * <ChatbotPageFooter betaTermsHref="https://legal.aircall.io/#template-9jw4r0usl" />
872
+ * ```
873
+ */
874
+ const ChatbotPageFooter = React.forwardRef((componentProps, forwardRef) => {
875
+ const { className, betaTermsHref, ...props } = componentProps;
876
+ const t = useDsTranslation("blocks");
877
+ return /* @__PURE__ */ jsx("div", {
878
+ ref: forwardRef,
879
+ "data-slot": "chatbot-page-footer",
880
+ className: cn("relative z-[1] flex w-full shrink-0 flex-col items-center justify-center pb-4", className),
881
+ ...props,
882
+ children: /* @__PURE__ */ jsxs("p", {
883
+ className: "text-center text-xs text-muted-foreground",
884
+ children: [
885
+ t("chatbotPage.footerBeforeLink"),
886
+ /* @__PURE__ */ jsx(Anchor, {
887
+ href: betaTermsHref,
888
+ target: "_blank",
889
+ rel: "noopener noreferrer",
890
+ children: t("chatbotPage.betaTermsLink")
891
+ }),
892
+ t("chatbotPage.footerAfterLink")
893
+ ]
894
+ })
895
+ });
896
+ });
897
+ ChatbotPageFooter.displayName = "ChatbotPageFooter";
898
+ /**
899
+ * Scrollable conversation thread for the active chatbot state. Place
900
+ * `ChatbotUserMessage` and `ChatbotResponseBlock` as alternating children.
901
+ * Use alongside `ChatbotPageInputBar` and `ChatbotPageFooter` inside
902
+ * `ChatbotPageContent`.
903
+ *
904
+ * The component is `relative` so consumers can absolutely-position a
905
+ * scroll-to-bottom FAB inside it.
906
+ *
907
+ * @example
908
+ * ```tsx
909
+ * <ChatbotPageContent>
910
+ * <ChatbotPageConversation>
911
+ * <ChatbotUserMessage>How do I set my phone line?</ChatbotUserMessage>
912
+ * <ChatbotResponseBlock messageId="1" markdown="..." />
913
+ * </ChatbotPageConversation>
914
+ * <ChatbotPageInputBar>
915
+ * <ChatbotInput size="large" />
916
+ * </ChatbotPageInputBar>
917
+ * <ChatbotPageFooter betaTermsHref="https://legal.aircall.io/..." />
918
+ * </ChatbotPageContent>
919
+ * ```
920
+ */
921
+ const ChatbotPageConversation = React.forwardRef((componentProps, forwardRef) => {
922
+ const { className, children, ...props } = componentProps;
923
+ const innerRef = React.useRef(null);
924
+ const [atBottom, setAtBottom] = React.useState(true);
925
+ const t = useDsTranslation("blocks");
926
+ const handleScroll = React.useCallback(() => {
927
+ const el = innerRef.current;
928
+ if (!el) return;
929
+ setAtBottom(el.scrollHeight - el.scrollTop - el.clientHeight < 8);
930
+ }, []);
931
+ React.useEffect(() => {
932
+ const el = innerRef.current;
933
+ if (!el) return;
934
+ el.addEventListener("scroll", handleScroll, { passive: true });
935
+ return () => el.removeEventListener("scroll", handleScroll);
936
+ }, [handleScroll]);
937
+ const scrollToBottom = React.useCallback(() => {
938
+ innerRef.current?.scrollTo({
939
+ top: innerRef.current.scrollHeight,
940
+ behavior: "smooth"
941
+ });
942
+ }, []);
943
+ const mergedRef = React.useCallback((node) => {
944
+ innerRef.current = node;
945
+ if (typeof forwardRef === "function") forwardRef(node);
946
+ else if (forwardRef) forwardRef.current = node;
947
+ }, [forwardRef]);
948
+ return /* @__PURE__ */ jsxs("div", {
949
+ "data-slot": "chatbot-page-conversation",
950
+ className: cn("relative z-[2] flex flex-col overflow-hidden w-full max-w-[896px] flex-1", className),
951
+ ...props,
952
+ children: [/* @__PURE__ */ jsx("div", {
953
+ ref: mergedRef,
954
+ className: cn("flex flex-1 flex-col gap-6 overflow-y-auto px-6 py-4", "[scrollbar-width:thin] [scrollbar-color:transparent_transparent] hover:[scrollbar-color:rgba(0,0,0,0.15)_transparent]", "[&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-transparent [&:hover::-webkit-scrollbar-thumb]:bg-black/20"),
955
+ children
956
+ }), !atBottom && /* @__PURE__ */ jsx("div", {
957
+ className: "absolute bottom-4 right-6 z-10",
958
+ children: /* @__PURE__ */ jsx(Button, {
959
+ variant: "outline",
960
+ size: "icon-lg",
961
+ className: "shadow-lg",
962
+ "aria-label": t("chatbotPage.scrollToBottom"),
963
+ onClick: scrollToBottom,
964
+ children: /* @__PURE__ */ jsx(ChevronDown, {})
965
+ })
966
+ })]
967
+ });
968
+ });
969
+ ChatbotPageConversation.displayName = "ChatbotPageConversation";
970
+ /**
971
+ * Wrapper that anchors `ChatbotInput` to the bottom of `ChatbotPageContent`
972
+ * at the correct max-width. Place between `ChatbotPageConversation` and
973
+ * `ChatbotPageFooter`.
974
+ *
975
+ * @example
976
+ * ```tsx
977
+ * <ChatbotPageInputBar>
978
+ * <ChatbotInput size="large" />
979
+ * </ChatbotPageInputBar>
980
+ * ```
981
+ */
982
+ const ChatbotPageInputBar = React.forwardRef((componentProps, forwardRef) => {
983
+ const { className, ...props } = componentProps;
984
+ return /* @__PURE__ */ jsx("div", {
985
+ ref: forwardRef,
986
+ "data-slot": "chatbot-page-input-bar",
987
+ className: cn("relative z-[1] flex w-full max-w-[896px] shrink-0 flex-col pb-4", className),
988
+ ...props
989
+ });
990
+ });
991
+ ChatbotPageInputBar.displayName = "ChatbotPageInputBar";
992
+
993
+ //#endregion
994
+ //#region src/components/chatbot-panel-header.tsx
995
+ /**
996
+ * Header bar for the chatbot panel. Each control renders only when its handler is
997
+ * provided. The leading ☰ opens a Popover (conversation history) when
998
+ * `menuContent` is set, otherwise fires `onMenu`; with no menu handler it falls
999
+ * back to a non-interactive panel indicator. Title is optional — pass an empty
1000
+ * string to hide it.
1001
+ */
1002
+ function ChatbotPanelHeader({ title = "Ask Aircall", onMenu, menuContent, menuOpen, onMenuOpenChange, onFeedback, onExpand, open = false, onOpenChange, onClose, className, ...props }) {
1003
+ const t = useDsTranslation("blocks");
1004
+ const menuButton = /* @__PURE__ */ jsx(Button, {
1005
+ variant: "ghost",
1006
+ size: "icon",
1007
+ "aria-label": "Open menu",
1008
+ onClick: onMenu,
1009
+ children: /* @__PURE__ */ jsx(Menu, { className: "size-4" })
1010
+ });
1011
+ return /* @__PURE__ */ jsxs("div", {
1012
+ "data-slot": "chatbot-panel-header",
1013
+ "data-state": open ? "open" : "closed",
1014
+ className: cn("flex w-full items-center gap-2 border-b border-border bg-background p-2", className),
1015
+ ...props,
1016
+ children: [
1017
+ menuContent != null ? /* @__PURE__ */ jsxs(Popover, {
1018
+ open: menuOpen,
1019
+ onOpenChange: onMenuOpenChange,
1020
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, { render: menuButton }), /* @__PURE__ */ jsx(PopoverContent, {
1021
+ align: "start",
1022
+ alignOffset: 6,
1023
+ sideOffset: 4,
1024
+ className: "h-[404px] w-80 gap-0 p-0",
1025
+ children: menuContent
1026
+ })]
1027
+ }) : onMenu != null ? menuButton : /* @__PURE__ */ jsx("span", {
1028
+ "aria-hidden": "true",
1029
+ className: "flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground",
1030
+ children: /* @__PURE__ */ jsx(PanelLeft, { className: "size-4" })
1031
+ }),
1032
+ /* @__PURE__ */ jsx("span", {
1033
+ className: "min-w-0 flex-1 truncate text-base font-bold leading-none text-foreground",
1034
+ children: title
1035
+ }),
1036
+ onFeedback != null && /* @__PURE__ */ jsx(Button, {
1037
+ variant: "ghost",
1038
+ size: "icon",
1039
+ "aria-label": t("chatbotPanel.sendFeedback"),
1040
+ onClick: onFeedback,
1041
+ children: /* @__PURE__ */ jsx(MessageSquare, { className: "size-4" })
1042
+ }),
1043
+ onExpand != null && /* @__PURE__ */ jsx(Button, {
1044
+ variant: "ghost",
1045
+ size: "icon",
1046
+ "aria-label": "Expand to fullscreen",
1047
+ onClick: onExpand,
1048
+ children: /* @__PURE__ */ jsx(SquareArrowOutUpRight, { className: "size-4" })
1049
+ }),
1050
+ onOpenChange != null && /* @__PURE__ */ jsx(Button, {
1051
+ variant: "ghost",
1052
+ size: "icon",
1053
+ "aria-label": open ? t("chatbotPanel.collapsePanel") : t("chatbotPanel.expandPanel"),
1054
+ onClick: () => onOpenChange(!open),
1055
+ children: open ? /* @__PURE__ */ jsx(Minus, { className: "size-4" }) : /* @__PURE__ */ jsx(Plus, { className: "size-4" })
1056
+ }),
1057
+ onClose != null && /* @__PURE__ */ jsx(Button, {
1058
+ variant: "ghost",
1059
+ size: "icon",
1060
+ "aria-label": t("chatbotPanel.closePanel"),
1061
+ onClick: onClose,
1062
+ children: /* @__PURE__ */ jsx(Minus, { className: "size-4" })
1063
+ })
1064
+ ]
1065
+ });
1066
+ }
386
1067
 
387
1068
  //#endregion
388
1069
  //#region src/components/chatbot-sidebar.tsx
389
1070
  const ChatbotSidebar = React.forwardRef((componentProps, forwardRef) => {
390
- const { conversations, activeConversationId, onNewChat, onSelectConversation, renderConversationMenuContent, recentLabel = "Recent", className } = componentProps;
391
- return /* @__PURE__ */ jsx(Sidebar, {
392
- ref: forwardRef,
393
- collapsible: "none",
394
- className,
395
- children: /* @__PURE__ */ jsxs(SidebarContent, { children: [/* @__PURE__ */ jsx(SidebarGroup, { children: /* @__PURE__ */ jsx(SidebarMenu, { children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(SidebarMenuButton, {
396
- isActive: !activeConversationId || !conversations.some((c) => c.id === activeConversationId),
397
- onClick: onNewChat,
398
- children: [/* @__PURE__ */ jsx(Plus, {}), /* @__PURE__ */ jsx("span", { children: "New chat" })]
399
- }) }) }) }), conversations.length > 0 && /* @__PURE__ */ jsxs(SidebarGroup, { children: [/* @__PURE__ */ jsx(SidebarGroupLabel, { children: recentLabel }), /* @__PURE__ */ jsx(SidebarMenu, { children: conversations.map((conversation) => {
400
- const isActive = conversation.id === activeConversationId;
401
- return /* @__PURE__ */ jsx(SidebarMenuItem, { children: renderConversationMenuContent ? /* @__PURE__ */ jsxs(DropdownMenu, { children: [
402
- /* @__PURE__ */ jsx(SidebarMenuButton, {
403
- isActive,
404
- onClick: () => onSelectConversation?.(conversation.id),
405
- children: /* @__PURE__ */ jsx("span", {
406
- className: "min-w-0 truncate",
407
- children: conversation.title
408
- })
409
- }),
410
- /* @__PURE__ */ jsx(SidebarMenuAction, {
411
- showOnHover: true,
412
- render: /* @__PURE__ */ jsx(DropdownMenuTrigger, {}),
413
- "aria-label": `Options for ${conversation.title}`,
414
- children: /* @__PURE__ */ jsx(Ellipsis, {})
415
- }),
416
- /* @__PURE__ */ jsx(DropdownMenuContent, {
417
- side: "right",
418
- children: renderConversationMenuContent(conversation)
419
- })
420
- ] }) : /* @__PURE__ */ jsx(SidebarMenuButton, {
1071
+ const { conversations, activeConversationId, onNewChat, onSelectConversation, renderConversationMenuContent, recentLabel = "Recent", popup = false, className } = componentProps;
1072
+ const t = useDsTranslation("blocks");
1073
+ const content = /* @__PURE__ */ jsxs(SidebarContent, { children: [/* @__PURE__ */ jsx(SidebarGroup, { children: /* @__PURE__ */ jsx(SidebarMenu, { children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(SidebarMenuButton, {
1074
+ isActive: !activeConversationId || !conversations.some((c) => c.id === activeConversationId),
1075
+ onClick: onNewChat,
1076
+ children: [/* @__PURE__ */ jsx(Plus, {}), /* @__PURE__ */ jsx("span", { children: t("chatbotSidebar.newChat") })]
1077
+ }) }) }) }), conversations.length > 0 && /* @__PURE__ */ jsxs(SidebarGroup, { children: [/* @__PURE__ */ jsx(SidebarGroupLabel, { children: recentLabel }), /* @__PURE__ */ jsx(SidebarMenu, { children: conversations.map((conversation) => {
1078
+ const isActive = conversation.id === activeConversationId;
1079
+ return /* @__PURE__ */ jsx(SidebarMenuItem, { children: renderConversationMenuContent ? /* @__PURE__ */ jsxs(DropdownMenu, { children: [
1080
+ /* @__PURE__ */ jsx(SidebarMenuButton, {
421
1081
  isActive,
422
1082
  onClick: () => onSelectConversation?.(conversation.id),
423
1083
  children: /* @__PURE__ */ jsx("span", {
424
1084
  className: "min-w-0 truncate",
425
1085
  children: conversation.title
426
1086
  })
427
- }) }, conversation.id);
428
- }) })] })] })
1087
+ }),
1088
+ /* @__PURE__ */ jsx(SidebarMenuAction, {
1089
+ showOnHover: true,
1090
+ render: /* @__PURE__ */ jsx(DropdownMenuTrigger, {}),
1091
+ "aria-label": t("chatbotSidebar.optionsFor", { title: conversation.title }),
1092
+ children: /* @__PURE__ */ jsx(Ellipsis, {})
1093
+ }),
1094
+ /* @__PURE__ */ jsx(DropdownMenuContent, {
1095
+ side: "right",
1096
+ children: renderConversationMenuContent(conversation)
1097
+ })
1098
+ ] }) : /* @__PURE__ */ jsx(SidebarMenuButton, {
1099
+ isActive,
1100
+ onClick: () => onSelectConversation?.(conversation.id),
1101
+ children: /* @__PURE__ */ jsx("span", {
1102
+ className: "min-w-0 truncate",
1103
+ children: conversation.title
1104
+ })
1105
+ }) }, conversation.id);
1106
+ }) })] })] });
1107
+ if (popup) return /* @__PURE__ */ jsx("div", {
1108
+ ref: forwardRef,
1109
+ className: cn("flex h-full w-full flex-col", className),
1110
+ children: content
1111
+ });
1112
+ return /* @__PURE__ */ jsx(Sidebar, {
1113
+ ref: forwardRef,
1114
+ collapsible: "none",
1115
+ className,
1116
+ children: content
429
1117
  });
430
1118
  });
431
1119
  ChatbotSidebar.displayName = "ChatbotSidebar";
@@ -438,13 +1126,22 @@ const textareaVariants = cva([
438
1126
  "disabled:bg-transparent dark:disabled:bg-transparent disabled:opacity-100",
439
1127
  "[scrollbar-color:rgba(0,0,0,0.1)_transparent] [scrollbar-width:thin] [&::-webkit-scrollbar]:w-2 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-black/10 [&::-webkit-scrollbar-track]:bg-transparent"
440
1128
  ], {
441
- variants: { size: {
442
- default: "max-h-20",
443
- large: "max-h-32 min-h-20"
444
- } },
445
- defaultVariants: { size: "default" }
1129
+ variants: {
1130
+ size: {
1131
+ default: "max-h-20",
1132
+ large: "max-h-32"
1133
+ },
1134
+ expanded: {
1135
+ true: "min-h-20",
1136
+ false: ""
1137
+ }
1138
+ },
1139
+ defaultVariants: {
1140
+ size: "default",
1141
+ expanded: false
1142
+ }
446
1143
  });
447
- function ChatbotInput({ className, value, onValueChange, onSubmit, onStop, placeholder, loading = false, size = "default", disabled, ...textareaProps }) {
1144
+ function ChatbotInput({ className, value, onValueChange, onSubmit, onStop, placeholder, loading = false, size = "default", expanded = false, disabled, ...textareaProps }) {
448
1145
  const t = useDsTranslation("blocks");
449
1146
  const [currentValue = "", setCurrentValue] = useControllableState({
450
1147
  prop: value,
@@ -481,7 +1178,10 @@ function ChatbotInput({ className, value, onValueChange, onSubmit, onStop, place
481
1178
  disabled,
482
1179
  onChange: handleChange,
483
1180
  onKeyDown: handleKeyDown,
484
- className: cn(textareaVariants({ size }))
1181
+ className: cn(textareaVariants({
1182
+ size,
1183
+ expanded
1184
+ }))
485
1185
  }), /* @__PURE__ */ jsx("div", {
486
1186
  className: "flex shrink-0 items-center gap-2",
487
1187
  children: loading ? /* @__PURE__ */ jsx(InputGroupButton, {
@@ -505,88 +1205,6 @@ function ChatbotInput({ className, value, onValueChange, onSubmit, onStop, place
505
1205
  });
506
1206
  }
507
1207
 
508
- //#endregion
509
- //#region src/hooks/use-copy-to-clipboard.ts
510
- function useCopyToClipboard(value, { timeout = 5e3, onCopied } = {}) {
511
- const [copied, setCopied] = useState(false);
512
- const timerRef = useRef(void 0);
513
- const getIsMounted = useIsMounted();
514
- const onCopiedRef = useCallbackRef(onCopied);
515
- useUnmount(() => clearTimeout(timerRef.current));
516
- useEffect(() => {
517
- clearTimeout(timerRef.current);
518
- setCopied(false);
519
- }, [value]);
520
- return {
521
- copy: useCallback(async () => {
522
- try {
523
- await navigator.clipboard.writeText(value);
524
- if (!getIsMounted()) return;
525
- setCopied(true);
526
- onCopiedRef();
527
- clearTimeout(timerRef.current);
528
- timerRef.current = setTimeout(() => {
529
- if (getIsMounted()) setCopied(false);
530
- }, timeout);
531
- } catch {}
532
- }, [
533
- value,
534
- timeout,
535
- getIsMounted,
536
- onCopiedRef
537
- ]),
538
- copied
539
- };
540
- }
541
-
542
- //#endregion
543
- //#region src/components/copy-button.tsx
544
- const CopyButtonContext = createContext(null);
545
- function useCopyButtonContext() {
546
- const ctx = useContext(CopyButtonContext);
547
- if (ctx === null) throw new Error("CopyButtonIcon and CopyButtonLabel must be rendered inside a CopyButton.");
548
- return ctx;
549
- }
550
- const CopyButton = React.forwardRef((componentProps, forwardRef) => {
551
- const { value, timeout, onCopied, variant = "outline", children, ...buttonProps } = componentProps;
552
- const { copy, copied } = useCopyToClipboard(value, {
553
- timeout,
554
- onCopied
555
- });
556
- return /* @__PURE__ */ jsx(CopyButtonContext.Provider, {
557
- value: { copied },
558
- children: /* @__PURE__ */ jsx(Button, {
559
- ref: forwardRef,
560
- onClick: () => {
561
- copy();
562
- },
563
- variant,
564
- ...buttonProps,
565
- children
566
- })
567
- });
568
- });
569
- CopyButton.displayName = "CopyButton";
570
- const CopyButtonIcon = React.forwardRef((componentProps, forwardRef) => {
571
- const { className } = componentProps;
572
- const { copied } = useCopyButtonContext();
573
- return /* @__PURE__ */ jsx(copied ? Check : Copy, {
574
- ref: forwardRef,
575
- className
576
- });
577
- });
578
- CopyButtonIcon.displayName = "CopyButtonIcon";
579
- const CopyButtonLabel = React.forwardRef((componentProps, forwardRef) => {
580
- const { label = "Copy", copiedLabel = "Copied", className } = componentProps;
581
- const { copied } = useCopyButtonContext();
582
- return /* @__PURE__ */ jsx("span", {
583
- ref: forwardRef,
584
- className: cn(className),
585
- children: copied ? copiedLabel : label
586
- });
587
- });
588
- CopyButtonLabel.displayName = "CopyButtonLabel";
589
-
590
1208
  //#endregion
591
1209
  //#region src/components/chatbot-panel-suggestion.tsx
592
1210
  function ChatbotPanelSuggestion({ className, ...props }) {
@@ -862,32 +1480,35 @@ DashboardPageHeaderAction.displayName = "DashboardPageHeaderAction";
862
1480
 
863
1481
  //#endregion
864
1482
  //#region src/components/product-badges.tsx
865
- const GRADIENT_BASE = cn("border-transparent text-foreground", "bg-[image:linear-gradient(90deg,var(--badge-overlay),var(--badge-overlay)),linear-gradient(90deg,var(--badge-accent),var(--badge-accent))]");
1483
+ const GRADIENT_BASE = cn("border-transparent bg-transparent text-foreground", "bg-[image:linear-gradient(90deg,var(--badge-overlay),var(--badge-overlay)),linear-gradient(90deg,var(--badge-accent),var(--badge-accent))]");
866
1484
  const productBadgeVariants = cva(GRADIENT_BASE, { variants: { type: {
867
1485
  beta: "[--badge-accent:var(--color-blue-300)]",
868
1486
  new: "[--badge-accent:var(--color-green-300)]",
869
1487
  deprecated: "[--badge-accent:var(--color-yellow-300)]",
870
1488
  trial: "[--badge-accent:var(--color-blue-300)]"
871
1489
  } } });
872
- const PRODUCT_BADGE_LABEL = {
873
- beta: "Beta",
874
- new: "New",
875
- deprecated: "Deprecated",
876
- trial: "Trial"
1490
+ const PRODUCT_BADGE_KEY = {
1491
+ beta: "productBadge.beta",
1492
+ new: "productBadge.new",
1493
+ deprecated: "productBadge.deprecated",
1494
+ trial: "productBadge.trial"
877
1495
  };
878
1496
  function createProductBadge(type) {
879
- const label = PRODUCT_BADGE_LABEL[type];
1497
+ const labelKey = PRODUCT_BADGE_KEY[type];
880
1498
  const ProductBadge = React.forwardRef((componentProps, forwardRef) => {
881
1499
  const { className, ...props } = componentProps;
1500
+ const t = useDsTranslation("blocks");
882
1501
  return /* @__PURE__ */ jsx(Badge, {
883
1502
  ref: forwardRef,
884
1503
  "data-slot": `badge-${type}`,
1504
+ color: "charcoal",
1505
+ tone: "dark",
885
1506
  className: cn(productBadgeVariants({ type }), className),
886
1507
  ...props,
887
- children: label
1508
+ children: t(labelKey)
888
1509
  });
889
1510
  });
890
- ProductBadge.displayName = label.replace(/\s+/g, "") + "Badge";
1511
+ ProductBadge.displayName = `${type.charAt(0).toUpperCase()}${type.slice(1)}Badge`;
891
1512
  return ProductBadge;
892
1513
  }
893
1514
  /** Blue pill — feature in beta, not yet GA */
@@ -901,13 +1522,14 @@ const TrialBadge = createProductBadge("trial");
901
1522
  /** Charcoal pill — Professional tier (no gradient; solid secondary Badge) */
902
1523
  const ProfessionalBadge = React.forwardRef((componentProps, forwardRef) => {
903
1524
  const { className, ...props } = componentProps;
1525
+ const t = useDsTranslation("blocks");
904
1526
  return /* @__PURE__ */ jsx(Badge, {
905
1527
  ref: forwardRef,
906
1528
  "data-slot": "badge-professional",
907
1529
  tone: "dark",
908
1530
  color: "charcoal",
909
1531
  ...props,
910
- children: "Professional"
1532
+ children: t("productBadge.professional")
911
1533
  });
912
1534
  });
913
1535
  ProfessionalBadge.displayName = "ProfessionalBadge";
@@ -917,20 +1539,23 @@ const roleBadgeVariants = cva(GRADIENT_BASE, { variants: { role: {
917
1539
  admin: "[--badge-accent:var(--color-purple-500)]",
918
1540
  owner: "[--badge-accent:var(--color-green-400)]"
919
1541
  } } });
920
- const ROLE_BADGE_LABEL = {
921
- agent: "Agent",
922
- supervisor: "Supervisor",
923
- admin: "Admin",
924
- owner: "Owner"
1542
+ const ROLE_BADGE_KEY = {
1543
+ agent: "roleBadge.agent",
1544
+ supervisor: "roleBadge.supervisor",
1545
+ admin: "roleBadge.admin",
1546
+ owner: "roleBadge.owner"
925
1547
  };
926
1548
  const RoleBadge = React.forwardRef((componentProps, forwardRef) => {
927
1549
  const { role, className, ...props } = componentProps;
1550
+ const t = useDsTranslation("blocks");
928
1551
  return /* @__PURE__ */ jsx(Badge, {
929
1552
  ref: forwardRef,
930
1553
  "data-slot": `badge-${role}`,
1554
+ color: "charcoal",
1555
+ tone: "dark",
931
1556
  className: cn(roleBadgeVariants({ role }), className),
932
1557
  ...props,
933
- children: ROLE_BADGE_LABEL[role]
1558
+ children: t(ROLE_BADGE_KEY[role])
934
1559
  });
935
1560
  });
936
1561
  RoleBadge.displayName = "RoleBadge";
@@ -963,6 +1588,255 @@ function ChatbotPanelTrigger({ children = "Ask anything", icon = /* @__PURE__ */
963
1588
  });
964
1589
  }
965
1590
 
1591
+ //#endregion
1592
+ //#region src/components/chatbot-expand-suggestion.tsx
1593
+ const ChatbotExpandSuggestion = React.forwardRef((componentProps, forwardRef) => {
1594
+ const { categories, selectedCategory: selectedCategoryProp, onCategoryChange, label = "Suggestions", suggestions, onSuggestionClick, className, ...props } = componentProps;
1595
+ const [selectedCategory, setSelectedCategory] = useControllableState({
1596
+ prop: selectedCategoryProp,
1597
+ onChange: onCategoryChange
1598
+ });
1599
+ const hasCategories = categories != null && categories.length > 0;
1600
+ const hasSuggestions = suggestions != null && suggestions.length > 0;
1601
+ return /* @__PURE__ */ jsxs("div", {
1602
+ ref: forwardRef,
1603
+ className: cn("flex w-full flex-col items-center gap-6", className),
1604
+ ...props,
1605
+ children: [hasCategories && /* @__PURE__ */ jsx(ToggleGroup, {
1606
+ variant: "outline",
1607
+ spacing: 2,
1608
+ value: selectedCategory != null ? [selectedCategory] : [],
1609
+ onValueChange: (vals) => setSelectedCategory(vals.at(-1)),
1610
+ children: categories.map((cat) => /* @__PURE__ */ jsx(ToggleGroupItem, {
1611
+ value: cat.value,
1612
+ className: "data-pressed:bg-secondary data-pressed:text-secondary-foreground data-pressed:border-secondary",
1613
+ children: cat.label
1614
+ }, cat.value))
1615
+ }), hasSuggestions && /* @__PURE__ */ jsxs("div", {
1616
+ className: "flex w-full flex-col gap-2",
1617
+ children: [/* @__PURE__ */ jsx("div", {
1618
+ className: "px-3 py-2",
1619
+ children: /* @__PURE__ */ jsx("p", {
1620
+ className: "text-sm font-semibold text-foreground leading-none",
1621
+ children: label
1622
+ })
1623
+ }), suggestions.map((suggestion, index) => /* @__PURE__ */ jsxs(React.Fragment, { children: [/* @__PURE__ */ jsx(Item, {
1624
+ render: /* @__PURE__ */ jsx("button", { type: "button" }),
1625
+ size: "sm",
1626
+ className: "cursor-pointer",
1627
+ onClick: () => onSuggestionClick?.(suggestion),
1628
+ children: /* @__PURE__ */ jsx(ItemContent, { children: /* @__PURE__ */ jsx(ItemTitle, { children: suggestion.text }) })
1629
+ }), index < suggestions.length - 1 && /* @__PURE__ */ jsx(Separator, {})] }, suggestion.id))]
1630
+ })]
1631
+ });
1632
+ });
1633
+ ChatbotExpandSuggestion.displayName = "ChatbotExpandSuggestion";
1634
+
1635
+ //#endregion
1636
+ //#region src/components/chatbot-panel.tsx
1637
+ /** Resize bounds (px), from Figma: min 320 / max 768 / default 400. */
1638
+ const DEFAULT_WIDTH = 400;
1639
+ const MIN_WIDTH = 320;
1640
+ const MAX_WIDTH = 768;
1641
+ /** Width delta applied per Arrow key press on the resize handle. */
1642
+ const KEYBOARD_RESIZE_STEP = 16;
1643
+ const DISCLAIMER_LINK_HREF = "https://legal.aircall.io/#template-9jw4r0usl";
1644
+ const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
1645
+ function ChatbotPanel({ title, onMenu, conversations, activeConversationId, onNewChat, onSelectConversation, renderConversationMenuContent, onExpand, onClose, emptyTitle, emptyDescription, suggestions = [], onSuggestionSelect, inputValue, onInputValueChange, onSubmit, onStop, loading = false, placeholder, autoFocus, disclaimer, resizable = true, defaultWidth = DEFAULT_WIDTH, minWidth = MIN_WIDTH, maxWidth = MAX_WIDTH, onWidthChange, className, style, children, ...props }) {
1646
+ const t = useDsTranslation("blocks");
1647
+ const [menuOpen, setMenuOpen] = React.useState(false);
1648
+ const [width, setWidth] = React.useState(() => clamp(defaultWidth, minWidth, maxWidth));
1649
+ const applyWidth = React.useCallback((next) => {
1650
+ const clamped = clamp(next, minWidth, maxWidth);
1651
+ setWidth(clamped);
1652
+ onWidthChange?.(clamped);
1653
+ }, [
1654
+ minWidth,
1655
+ maxWidth,
1656
+ onWidthChange
1657
+ ]);
1658
+ const dragRef = React.useRef(null);
1659
+ React.useEffect(() => {
1660
+ if (!resizable) return void 0;
1661
+ const handlePointerMove = (event) => {
1662
+ const drag = dragRef.current;
1663
+ if (!drag) return;
1664
+ applyWidth(drag.startWidth - (event.clientX - drag.startX));
1665
+ };
1666
+ const handlePointerUp = () => {
1667
+ dragRef.current = null;
1668
+ };
1669
+ window.addEventListener("pointermove", handlePointerMove);
1670
+ window.addEventListener("pointerup", handlePointerUp);
1671
+ window.addEventListener("pointercancel", handlePointerUp);
1672
+ return () => {
1673
+ window.removeEventListener("pointermove", handlePointerMove);
1674
+ window.removeEventListener("pointerup", handlePointerUp);
1675
+ window.removeEventListener("pointercancel", handlePointerUp);
1676
+ };
1677
+ }, [resizable, applyWidth]);
1678
+ const handleResizeKeyDown = (event) => {
1679
+ if (event.key === "ArrowLeft") {
1680
+ event.preventDefault();
1681
+ applyWidth(width + KEYBOARD_RESIZE_STEP);
1682
+ } else if (event.key === "ArrowRight") {
1683
+ event.preventDefault();
1684
+ applyWidth(width - KEYBOARD_RESIZE_STEP);
1685
+ }
1686
+ };
1687
+ const hasConversation = React.Children.toArray(children).length > 0;
1688
+ const bodyRef = React.useRef(null);
1689
+ const [showScrollDown, setShowScrollDown] = React.useState(false);
1690
+ const updateScrollState = React.useCallback(() => {
1691
+ const el = bodyRef.current;
1692
+ if (!el) return;
1693
+ setShowScrollDown(el.scrollHeight - el.scrollTop - el.clientHeight > 8);
1694
+ }, []);
1695
+ React.useLayoutEffect(() => {
1696
+ updateScrollState();
1697
+ }, [
1698
+ children,
1699
+ width,
1700
+ updateScrollState
1701
+ ]);
1702
+ const scrollToBottom = () => {
1703
+ bodyRef.current?.scrollTo({
1704
+ top: bodyRef.current.scrollHeight,
1705
+ behavior: "smooth"
1706
+ });
1707
+ };
1708
+ const resolvedDisclaimer = disclaimer === void 0 ? /* @__PURE__ */ jsxs("p", {
1709
+ className: "text-xs text-muted-foreground",
1710
+ children: [
1711
+ t("chatbotPanel.disclaimerBefore"),
1712
+ /* @__PURE__ */ jsx("a", {
1713
+ href: DISCLAIMER_LINK_HREF,
1714
+ target: "_blank",
1715
+ rel: "noreferrer",
1716
+ className: "text-primary underline",
1717
+ children: t("chatbotPanel.disclaimerLink")
1718
+ }),
1719
+ t("chatbotPanel.disclaimerAfter")
1720
+ ]
1721
+ }) : disclaimer;
1722
+ const menuContent = conversations != null ? /* @__PURE__ */ jsx(SidebarProvider, {
1723
+ className: "!min-h-0 flex-1",
1724
+ style: { "--sidebar-width": "20rem" },
1725
+ children: /* @__PURE__ */ jsx(ChatbotSidebar, {
1726
+ popup: true,
1727
+ className: "[&_[data-slot=sidebar-content]]:gap-0",
1728
+ conversations,
1729
+ activeConversationId,
1730
+ onNewChat: onNewChat && (() => {
1731
+ onNewChat();
1732
+ setMenuOpen(false);
1733
+ }),
1734
+ onSelectConversation: onSelectConversation && ((id) => {
1735
+ onSelectConversation(id);
1736
+ setMenuOpen(false);
1737
+ }),
1738
+ renderConversationMenuContent
1739
+ })
1740
+ }) : void 0;
1741
+ return /* @__PURE__ */ jsxs("div", {
1742
+ "data-slot": "chatbot-panel",
1743
+ className: cn("relative flex h-full flex-col overflow-clip rounded-xl border border-border bg-background", className),
1744
+ style: {
1745
+ width,
1746
+ ...style
1747
+ },
1748
+ ...props,
1749
+ children: [
1750
+ resizable && /* @__PURE__ */ jsx("div", {
1751
+ role: "separator",
1752
+ "aria-orientation": "vertical",
1753
+ "aria-label": t("chatbotPanel.resizeHandle"),
1754
+ "aria-valuenow": width,
1755
+ "aria-valuemin": minWidth,
1756
+ "aria-valuemax": maxWidth,
1757
+ tabIndex: 0,
1758
+ onPointerDown: (event) => {
1759
+ dragRef.current = {
1760
+ startX: event.clientX,
1761
+ startWidth: width
1762
+ };
1763
+ },
1764
+ onKeyDown: handleResizeKeyDown,
1765
+ className: cn("absolute inset-y-0 left-0 z-10 w-1.5 cursor-ew-resize touch-none select-none", "hover:bg-border/60 focus-visible:bg-border/60 focus-visible:outline-none")
1766
+ }),
1767
+ /* @__PURE__ */ jsx(ChatbotPanelHeader, {
1768
+ title: title ?? t("chatbotPanel.title"),
1769
+ onMenu,
1770
+ menuContent,
1771
+ menuOpen: conversations != null ? menuOpen : void 0,
1772
+ onMenuOpenChange: setMenuOpen,
1773
+ onExpand,
1774
+ onClose
1775
+ }),
1776
+ /* @__PURE__ */ jsxs("div", {
1777
+ className: "relative flex min-h-0 flex-1 flex-col",
1778
+ children: [/* @__PURE__ */ jsx("div", {
1779
+ ref: bodyRef,
1780
+ "data-slot": "chatbot-panel-body",
1781
+ onScroll: updateScrollState,
1782
+ className: "flex min-h-0 flex-1 flex-col overflow-y-auto px-6 py-4",
1783
+ children: hasConversation ? /* @__PURE__ */ jsx("div", {
1784
+ className: "flex flex-col gap-6",
1785
+ children
1786
+ }) : /* @__PURE__ */ jsxs("div", {
1787
+ "data-slot": "chatbot-panel-empty",
1788
+ className: "flex flex-1 flex-col items-center",
1789
+ children: [/* @__PURE__ */ jsxs("div", {
1790
+ className: "flex flex-1 flex-col items-center justify-center gap-2 text-center",
1791
+ children: [
1792
+ /* @__PURE__ */ jsx("span", {
1793
+ "aria-hidden": "true",
1794
+ className: "grid size-12 place-items-center rounded-full border border-green-400 bg-[#00bd82] shadow-[0px_0px_8px_0px_var(--color-green-300)] [&_path]:fill-current [&_svg]:size-7 text-white dark:text-[#101820]",
1795
+ children: /* @__PURE__ */ jsx(AircallMark, {})
1796
+ }),
1797
+ /* @__PURE__ */ jsx("h2", {
1798
+ className: "text-sm font-medium text-foreground",
1799
+ children: emptyTitle ?? t("chatbotPanel.emptyTitle")
1800
+ }),
1801
+ /* @__PURE__ */ jsx("p", {
1802
+ className: "max-w-[280px] text-sm text-muted-foreground",
1803
+ children: emptyDescription ?? t("chatbotPanel.emptyDescription")
1804
+ })
1805
+ ]
1806
+ }), suggestions.length > 0 && /* @__PURE__ */ jsx("div", {
1807
+ className: "flex w-full flex-col items-center gap-2 py-4",
1808
+ children: suggestions.map((suggestion) => /* @__PURE__ */ jsx(ChatbotPanelSuggestion, {
1809
+ onClick: () => onSuggestionSelect?.(suggestion),
1810
+ children: suggestion.label
1811
+ }, suggestion.id ?? suggestion.label))
1812
+ })]
1813
+ })
1814
+ }), hasConversation && showScrollDown && /* @__PURE__ */ jsx(Button, {
1815
+ variant: "outline",
1816
+ size: "icon",
1817
+ "aria-label": "Scroll to bottom",
1818
+ onClick: scrollToBottom,
1819
+ className: "absolute right-4 bottom-4 size-10 rounded-md shadow-lg",
1820
+ children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-6" })
1821
+ })]
1822
+ }),
1823
+ /* @__PURE__ */ jsxs("div", {
1824
+ "data-slot": "chatbot-panel-footer",
1825
+ className: "flex flex-col gap-2.5 bg-gradient-to-b from-background/10 to-background px-4 pt-0 pb-4",
1826
+ children: [/* @__PURE__ */ jsx(ChatbotInput, {
1827
+ value: inputValue,
1828
+ onValueChange: onInputValueChange,
1829
+ onSubmit,
1830
+ onStop,
1831
+ loading,
1832
+ placeholder,
1833
+ autoFocus
1834
+ }), resolvedDisclaimer]
1835
+ })
1836
+ ]
1837
+ });
1838
+ }
1839
+
966
1840
  //#endregion
967
1841
  //#region src/form/form-context.ts
968
1842
  /**
@@ -1777,4 +2651,4 @@ function DashboardSidebarNav({ groups, renderLink }) {
1777
2651
  }
1778
2652
 
1779
2653
  //#endregion
1780
- export { BetaBadge, CardSaveBar, ChatbotInput, ChatbotPage, ChatbotPanelSuggestion, ChatbotPanelTrigger, ChatbotSidebar, ChatbotUserMessage, ComingSoonDescription, ComingSoonEmptyState, ComingSoonMedia, ComingSoonTitle, CommonForm, CopyButton, CopyButtonIcon, CopyButtonLabel, DashboardPage, DashboardPageBanner, DashboardPageContent, DashboardPageHeader, DashboardPageHeaderAction, DashboardPageHeaderActions, DashboardPageHeaderDescription, DashboardPageHeaderNav, DashboardPageHeaderNavBack, DashboardPageHeaderPrefix, DashboardPageHeaderSubtitle, DashboardPageHeaderTitle, DashboardPageHeaderTitleGroup, DashboardPageMain, DashboardPageTabs, DashboardSidebar, DashboardSidebarContent, DashboardSidebarFooter, DashboardSidebarGroup, DashboardSidebarGroupLabel, DashboardSidebarHeader, DashboardSidebarMenu, DashboardSidebarMenuBadge, DashboardSidebarMenuButton, DashboardSidebarMenuItem, DashboardSidebarNav, DashboardSidebarProvider, DashboardSidebarSubmenu, DashboardSidebarSubmenuItem, DashboardSidebarSubmenuSeparator, DashboardSidebarTrigger, DashboardStandalonePage, DashboardStandalonePageAction, DashboardStandalonePageActions, DashboardStandalonePageContent, DashboardStandalonePageHeader, DashboardStandalonePageTitle, DeprecatedBadge, EmptyState, EmptyStateActions, EmptyStateButton, EmptyStateDescription, EmptyStateExternalLink, EmptyStateHeader, EmptyStateMedia, EmptyStateTitle, FormComboboxField, FormFieldBase, FormInputField, FormMultiComboboxField, FormNumberField, FormOTPField, FormRadioGroupField, FormSelectField, FormSliderField, FormSwitchField, FormTextareaField, FormToggleGroupField, NewBadge, NoDataDescription, NoDataEmptyState, NoDataMedia, NoDataTitle, NoSupportDescription, NoSupportEmptyState, NoSupportMedia, NoSupportTitle, NotFoundDescription, NotFoundEmptyState, NotFoundMedia, NotFoundTitle, ProfessionalBadge, RestrictedAccessDescription, RestrictedAccessEmptyState, RestrictedAccessMedia, RestrictedAccessTitle, RoleBadge, SaveBar, SubmitButton, TrialBadge, UnknownErrorDescription, UnknownErrorEmptyState, UnknownErrorMedia, UnknownErrorTitle, fieldContext, formContext, toFieldErrors, useCopyToClipboard, useSidebar as useDashboardSidebar, useFieldContext, useForm, useFormContext, withForm };
2654
+ export { BetaBadge, CardSaveBar, ChatbotExpandSuggestion, ChatbotInput, ChatbotPage, ChatbotPageBody, ChatbotPageContent, ChatbotPageConversation, ChatbotPageFooter, ChatbotPageHeading, ChatbotPageInputBar, ChatbotPanel, ChatbotPanelHeader, ChatbotPanelSuggestion, ChatbotPanelTrigger, ChatbotResponseBlock, ChatbotSidebar, ChatbotUserMessage, ComingSoonDescription, ComingSoonEmptyState, ComingSoonMedia, ComingSoonTitle, CommonForm, CopyButton, CopyButtonIcon, CopyButtonLabel, DashboardPage, DashboardPageBanner, DashboardPageContent, DashboardPageHeader, DashboardPageHeaderAction, DashboardPageHeaderActions, DashboardPageHeaderDescription, DashboardPageHeaderNav, DashboardPageHeaderNavBack, DashboardPageHeaderPrefix, DashboardPageHeaderSubtitle, DashboardPageHeaderTitle, DashboardPageHeaderTitleGroup, DashboardPageMain, DashboardPageTabs, DashboardSidebar, DashboardSidebarContent, DashboardSidebarFooter, DashboardSidebarGroup, DashboardSidebarGroupLabel, DashboardSidebarHeader, DashboardSidebarMenu, DashboardSidebarMenuBadge, DashboardSidebarMenuButton, DashboardSidebarMenuItem, DashboardSidebarNav, DashboardSidebarProvider, DashboardSidebarSubmenu, DashboardSidebarSubmenuItem, DashboardSidebarSubmenuSeparator, DashboardSidebarTrigger, DashboardStandalonePage, DashboardStandalonePageAction, DashboardStandalonePageActions, DashboardStandalonePageContent, DashboardStandalonePageHeader, DashboardStandalonePageTitle, DeprecatedBadge, EmptyState, EmptyStateActions, EmptyStateButton, EmptyStateDescription, EmptyStateExternalLink, EmptyStateHeader, EmptyStateMedia, EmptyStateTitle, FormComboboxField, FormFieldBase, FormInputField, FormMultiComboboxField, FormNumberField, FormOTPField, FormRadioGroupField, FormSelectField, FormSliderField, FormSwitchField, FormTextareaField, FormToggleGroupField, NewBadge, NoDataDescription, NoDataEmptyState, NoDataMedia, NoDataTitle, NoSupportDescription, NoSupportEmptyState, NoSupportMedia, NoSupportTitle, NotFoundDescription, NotFoundEmptyState, NotFoundMedia, NotFoundTitle, ProfessionalBadge, RestrictedAccessDescription, RestrictedAccessEmptyState, RestrictedAccessMedia, RestrictedAccessTitle, RoleBadge, SaveBar, SubmitButton, TrialBadge, UnknownErrorDescription, UnknownErrorEmptyState, UnknownErrorMedia, UnknownErrorTitle, fieldContext, formContext, toFieldErrors, useCopyToClipboard, useSidebar as useDashboardSidebar, useFieldContext, useForm, useFormContext, withForm };