@aircall/blocks 0.7.0 → 0.10.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,8 +1,8 @@
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, Popover, PopoverContent, PopoverTrigger, 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, ExternalLink, FileText, LockKeyhole, MessageSquare, Minus, PanelLeft, PanelLeftClose, PanelLeftOpen, Plus, Search, Settings, Sprout, Square, ThumbsDown, ThumbsDownFilled, ThumbsUp, ThumbsUpFilled, TriangleAlert, X } from "@aircall/react-icons";
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
6
  import ReactMarkdown from "react-markdown";
7
7
  import remarkGfm from "remark-gfm";
8
8
  import { useCallbackRef, useControllableState, useIsMounted, useUnmount } from "@aircall/hooks";
@@ -28,7 +28,39 @@ const de = {
28
28
  "chatbotInput.placeholder": "Stellen Sie eine Frage...",
29
29
  "chatbotInput.messageLabel": "Nachricht",
30
30
  "chatbotInput.stopGenerating": "Generierung stoppen",
31
- "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"
32
64
  };
33
65
  var de_default = de;
34
66
 
@@ -50,7 +82,39 @@ const en = {
50
82
  "chatbotInput.placeholder": "Ask anything...",
51
83
  "chatbotInput.messageLabel": "Message",
52
84
  "chatbotInput.stopGenerating": "Stop generating",
53
- "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"
54
118
  };
55
119
  var en_default = en;
56
120
 
@@ -72,7 +136,39 @@ const es = {
72
136
  "chatbotInput.placeholder": "Pregunta lo que quieras...",
73
137
  "chatbotInput.messageLabel": "Mensaje",
74
138
  "chatbotInput.stopGenerating": "Detener la generación",
75
- "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"
76
172
  };
77
173
  var es_default = es;
78
174
 
@@ -94,7 +190,39 @@ const fr = {
94
190
  "chatbotInput.placeholder": "Posez votre question...",
95
191
  "chatbotInput.messageLabel": "Message",
96
192
  "chatbotInput.stopGenerating": "Arrêter la génération",
97
- "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"
98
226
  };
99
227
  var fr_default = fr;
100
228
 
@@ -116,7 +244,39 @@ const it = {
116
244
  "chatbotInput.placeholder": "Chiedi qualsiasi cosa...",
117
245
  "chatbotInput.messageLabel": "Messaggio",
118
246
  "chatbotInput.stopGenerating": "Interrompi la generazione",
119
- "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"
120
280
  };
121
281
  var it_default = it;
122
282
 
@@ -458,76 +618,41 @@ CopyButtonLabel.displayName = "CopyButtonLabel";
458
618
  //#endregion
459
619
  //#region src/components/chatbot-response-block.tsx
460
620
  function SourcesBadge({ sources }) {
461
- const [open, setOpen] = useState(false);
462
- const closeTimerRef = useRef();
463
- const openedByHoverRef = useRef(false);
464
- useUnmount(() => clearTimeout(closeTimerRef.current));
465
- function handlePointerEnter(e) {
466
- if (e.pointerType !== "mouse") return;
467
- openedByHoverRef.current = true;
468
- clearTimeout(closeTimerRef.current);
469
- setOpen(true);
470
- }
471
- function handlePointerLeave(e) {
472
- if (e.pointerType !== "mouse") return;
473
- clearTimeout(closeTimerRef.current);
474
- closeTimerRef.current = setTimeout(() => {
475
- openedByHoverRef.current = false;
476
- setOpen(false);
477
- }, 150);
478
- }
479
- return /* @__PURE__ */ jsxs(Popover, {
480
- open,
481
- onOpenChange: (nextOpen, eventDetails) => {
482
- if (!nextOpen) {
483
- if (eventDetails.reason === "trigger-press" && openedByHoverRef.current) return;
484
- openedByHoverRef.current = false;
485
- clearTimeout(closeTimerRef.current);
486
- }
487
- setOpen(nextOpen);
488
- },
489
- children: [/* @__PURE__ */ jsx(PopoverTrigger, {
490
- className: "cursor-default rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
491
- onPointerEnter: handlePointerEnter,
492
- onPointerLeave: handlePointerLeave,
493
- children: /* @__PURE__ */ jsx(Badge, {
494
- className: "!rounded-full !bg-charcoal-400/20",
495
- children: `${sources.length} ${sources.length === 1 ? "Source" : "Sources"}`
496
- })
497
- }), /* @__PURE__ */ jsx(PopoverContent, {
498
- side: "top",
499
- align: "start",
500
- sideOffset: 8,
501
- className: "w-80",
502
- onPointerEnter: handlePointerEnter,
503
- onPointerLeave: handlePointerLeave,
504
- children: /* @__PURE__ */ jsx("div", {
505
- role: "list",
506
- className: "flex flex-col",
507
- children: sources.map((source) => /* @__PURE__ */ jsxs("div", {
508
- role: "listitem",
509
- className: "flex items-center gap-2 px-2 py-2",
510
- children: [
511
- /* @__PURE__ */ jsx(FileText, { className: "size-3.5 shrink-0 text-foreground" }),
512
- /* @__PURE__ */ jsx("span", {
513
- className: "min-w-0 flex-1 line-clamp-2 text-sm",
514
- children: source.title
515
- }),
516
- /* @__PURE__ */ jsx("a", {
517
- href: source.url,
518
- target: "_blank",
519
- rel: "noreferrer",
520
- "aria-label": `Open ${source.title}`,
521
- className: "shrink-0 text-foreground hover:text-primary",
522
- children: /* @__PURE__ */ jsx(ExternalLink, { className: "size-3.5" })
523
- })
524
- ]
525
- }, source.url))
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
+ ]
526
650
  })
527
- })]
528
- });
651
+ }, source.url)) })
652
+ })] });
529
653
  }
530
654
  function ChatbotResponseBlock({ messageId, markdown, streaming = false, sources, onFeedback, className }) {
655
+ const t = useDsTranslation("blocks");
531
656
  const [feedback, setFeedback] = useState(null);
532
657
  const onFeedbackRef = useCallbackRef(onFeedback);
533
658
  const isMounted = useRef(false);
@@ -628,7 +753,7 @@ function ChatbotResponseBlock({ messageId, markdown, streaming = false, sources,
628
753
  value: markdown,
629
754
  variant: "ghost",
630
755
  size: "icon-sm",
631
- "aria-label": "Copy",
756
+ "aria-label": t("chatbotResponse.copy"),
632
757
  children: /* @__PURE__ */ jsx(CopyButtonIcon, {})
633
758
  }),
634
759
  /* @__PURE__ */ jsx(Button, {
@@ -636,7 +761,7 @@ function ChatbotResponseBlock({ messageId, markdown, streaming = false, sources,
636
761
  variant: "ghost",
637
762
  size: "icon-sm",
638
763
  "aria-pressed": feedback === "up",
639
- "aria-label": "Helpful",
764
+ "aria-label": t("chatbotResponse.helpful"),
640
765
  onClick: () => handleFeedback("up"),
641
766
  className: cn(feedback === "up" && "text-primary"),
642
767
  children: feedback === "up" ? /* @__PURE__ */ jsx(ThumbsUpFilled, {}) : /* @__PURE__ */ jsx(ThumbsUp, {})
@@ -646,7 +771,7 @@ function ChatbotResponseBlock({ messageId, markdown, streaming = false, sources,
646
771
  variant: "ghost",
647
772
  size: "icon-sm",
648
773
  "aria-pressed": feedback === "down",
649
- "aria-label": "Not helpful",
774
+ "aria-label": t("chatbotResponse.notHelpful"),
650
775
  onClick: () => handleFeedback("down"),
651
776
  className: cn(feedback === "down" && "text-primary"),
652
777
  children: feedback === "down" ? /* @__PURE__ */ jsx(ThumbsDownFilled, {}) : /* @__PURE__ */ jsx(ThumbsDown, {})
@@ -669,23 +794,237 @@ const ChatbotPage = React.forwardRef((componentProps, forwardRef) => {
669
794
  });
670
795
  });
671
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";
672
992
 
673
993
  //#endregion
674
994
  //#region src/components/chatbot-panel-header.tsx
675
995
  /**
676
- * Header bar for the chatbot panel.
677
- *
678
- * Always visible the panel body collapses/expands below it. Controlled by
679
- * the parent via `open` + `onOpenChange`; pass `onClose` to show the dismiss (×) button.
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.
680
1001
  */
681
- function ChatbotPanelHeader({ title = "Ask Aircall", open, onOpenChange, onFeedback, onClose, className, ...props }) {
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
+ });
682
1011
  return /* @__PURE__ */ jsxs("div", {
683
1012
  "data-slot": "chatbot-panel-header",
684
1013
  "data-state": open ? "open" : "closed",
685
1014
  className: cn("flex w-full items-center gap-2 border-b border-border bg-background p-2", className),
686
1015
  ...props,
687
1016
  children: [
688
- /* @__PURE__ */ jsx("span", {
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", {
689
1028
  "aria-hidden": "true",
690
1029
  className: "flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground",
691
1030
  children: /* @__PURE__ */ jsx(PanelLeft, { className: "size-4" })
@@ -697,23 +1036,30 @@ function ChatbotPanelHeader({ title = "Ask Aircall", open, onOpenChange, onFeedb
697
1036
  onFeedback != null && /* @__PURE__ */ jsx(Button, {
698
1037
  variant: "ghost",
699
1038
  size: "icon",
700
- "aria-label": "Send feedback",
1039
+ "aria-label": t("chatbotPanel.sendFeedback"),
701
1040
  onClick: onFeedback,
702
1041
  children: /* @__PURE__ */ jsx(MessageSquare, { className: "size-4" })
703
1042
  }),
704
- /* @__PURE__ */ jsx(Button, {
1043
+ onExpand != null && /* @__PURE__ */ jsx(Button, {
705
1044
  variant: "ghost",
706
1045
  size: "icon",
707
- "aria-label": open ? "Collapse panel" : "Expand panel",
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"),
708
1054
  onClick: () => onOpenChange(!open),
709
1055
  children: open ? /* @__PURE__ */ jsx(Minus, { className: "size-4" }) : /* @__PURE__ */ jsx(Plus, { className: "size-4" })
710
1056
  }),
711
1057
  onClose != null && /* @__PURE__ */ jsx(Button, {
712
1058
  variant: "ghost",
713
1059
  size: "icon",
714
- "aria-label": "Close panel",
1060
+ "aria-label": t("chatbotPanel.closePanel"),
715
1061
  onClick: onClose,
716
- children: /* @__PURE__ */ jsx(X, { className: "size-4" })
1062
+ children: /* @__PURE__ */ jsx(Minus, { className: "size-4" })
717
1063
  })
718
1064
  ]
719
1065
  });
@@ -722,45 +1068,52 @@ function ChatbotPanelHeader({ title = "Ask Aircall", open, onOpenChange, onFeedb
722
1068
  //#endregion
723
1069
  //#region src/components/chatbot-sidebar.tsx
724
1070
  const ChatbotSidebar = React.forwardRef((componentProps, forwardRef) => {
725
- const { conversations, activeConversationId, onNewChat, onSelectConversation, renderConversationMenuContent, recentLabel = "Recent", className } = componentProps;
726
- return /* @__PURE__ */ jsx(Sidebar, {
727
- ref: forwardRef,
728
- collapsible: "none",
729
- className,
730
- children: /* @__PURE__ */ jsxs(SidebarContent, { children: [/* @__PURE__ */ jsx(SidebarGroup, { children: /* @__PURE__ */ jsx(SidebarMenu, { children: /* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(SidebarMenuButton, {
731
- isActive: !activeConversationId || !conversations.some((c) => c.id === activeConversationId),
732
- onClick: onNewChat,
733
- children: [/* @__PURE__ */ jsx(Plus, {}), /* @__PURE__ */ jsx("span", { children: "New chat" })]
734
- }) }) }) }), conversations.length > 0 && /* @__PURE__ */ jsxs(SidebarGroup, { children: [/* @__PURE__ */ jsx(SidebarGroupLabel, { children: recentLabel }), /* @__PURE__ */ jsx(SidebarMenu, { children: conversations.map((conversation) => {
735
- const isActive = conversation.id === activeConversationId;
736
- return /* @__PURE__ */ jsx(SidebarMenuItem, { children: renderConversationMenuContent ? /* @__PURE__ */ jsxs(DropdownMenu, { children: [
737
- /* @__PURE__ */ jsx(SidebarMenuButton, {
738
- isActive,
739
- onClick: () => onSelectConversation?.(conversation.id),
740
- children: /* @__PURE__ */ jsx("span", {
741
- className: "min-w-0 truncate",
742
- children: conversation.title
743
- })
744
- }),
745
- /* @__PURE__ */ jsx(SidebarMenuAction, {
746
- showOnHover: true,
747
- render: /* @__PURE__ */ jsx(DropdownMenuTrigger, {}),
748
- "aria-label": `Options for ${conversation.title}`,
749
- children: /* @__PURE__ */ jsx(Ellipsis, {})
750
- }),
751
- /* @__PURE__ */ jsx(DropdownMenuContent, {
752
- side: "right",
753
- children: renderConversationMenuContent(conversation)
754
- })
755
- ] }) : /* @__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, {
756
1081
  isActive,
757
1082
  onClick: () => onSelectConversation?.(conversation.id),
758
1083
  children: /* @__PURE__ */ jsx("span", {
759
1084
  className: "min-w-0 truncate",
760
1085
  children: conversation.title
761
1086
  })
762
- }) }, conversation.id);
763
- }) })] })] })
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
764
1117
  });
765
1118
  });
766
1119
  ChatbotSidebar.displayName = "ChatbotSidebar";
@@ -773,13 +1126,22 @@ const textareaVariants = cva([
773
1126
  "disabled:bg-transparent dark:disabled:bg-transparent disabled:opacity-100",
774
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"
775
1128
  ], {
776
- variants: { size: {
777
- default: "max-h-20",
778
- large: "max-h-32 min-h-20"
779
- } },
780
- 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
+ }
781
1143
  });
782
- 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 }) {
783
1145
  const t = useDsTranslation("blocks");
784
1146
  const [currentValue = "", setCurrentValue] = useControllableState({
785
1147
  prop: value,
@@ -816,7 +1178,10 @@ function ChatbotInput({ className, value, onValueChange, onSubmit, onStop, place
816
1178
  disabled,
817
1179
  onChange: handleChange,
818
1180
  onKeyDown: handleKeyDown,
819
- className: cn(textareaVariants({ size }))
1181
+ className: cn(textareaVariants({
1182
+ size,
1183
+ expanded
1184
+ }))
820
1185
  }), /* @__PURE__ */ jsx("div", {
821
1186
  className: "flex shrink-0 items-center gap-2",
822
1187
  children: loading ? /* @__PURE__ */ jsx(InputGroupButton, {
@@ -1115,32 +1480,35 @@ DashboardPageHeaderAction.displayName = "DashboardPageHeaderAction";
1115
1480
 
1116
1481
  //#endregion
1117
1482
  //#region src/components/product-badges.tsx
1118
- 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))]");
1119
1484
  const productBadgeVariants = cva(GRADIENT_BASE, { variants: { type: {
1120
1485
  beta: "[--badge-accent:var(--color-blue-300)]",
1121
1486
  new: "[--badge-accent:var(--color-green-300)]",
1122
1487
  deprecated: "[--badge-accent:var(--color-yellow-300)]",
1123
1488
  trial: "[--badge-accent:var(--color-blue-300)]"
1124
1489
  } } });
1125
- const PRODUCT_BADGE_LABEL = {
1126
- beta: "Beta",
1127
- new: "New",
1128
- deprecated: "Deprecated",
1129
- trial: "Trial"
1490
+ const PRODUCT_BADGE_KEY = {
1491
+ beta: "productBadge.beta",
1492
+ new: "productBadge.new",
1493
+ deprecated: "productBadge.deprecated",
1494
+ trial: "productBadge.trial"
1130
1495
  };
1131
1496
  function createProductBadge(type) {
1132
- const label = PRODUCT_BADGE_LABEL[type];
1497
+ const labelKey = PRODUCT_BADGE_KEY[type];
1133
1498
  const ProductBadge = React.forwardRef((componentProps, forwardRef) => {
1134
1499
  const { className, ...props } = componentProps;
1500
+ const t = useDsTranslation("blocks");
1135
1501
  return /* @__PURE__ */ jsx(Badge, {
1136
1502
  ref: forwardRef,
1137
1503
  "data-slot": `badge-${type}`,
1504
+ color: "charcoal",
1505
+ tone: "dark",
1138
1506
  className: cn(productBadgeVariants({ type }), className),
1139
1507
  ...props,
1140
- children: label
1508
+ children: t(labelKey)
1141
1509
  });
1142
1510
  });
1143
- ProductBadge.displayName = label.replace(/\s+/g, "") + "Badge";
1511
+ ProductBadge.displayName = `${type.charAt(0).toUpperCase()}${type.slice(1)}Badge`;
1144
1512
  return ProductBadge;
1145
1513
  }
1146
1514
  /** Blue pill — feature in beta, not yet GA */
@@ -1154,13 +1522,14 @@ const TrialBadge = createProductBadge("trial");
1154
1522
  /** Charcoal pill — Professional tier (no gradient; solid secondary Badge) */
1155
1523
  const ProfessionalBadge = React.forwardRef((componentProps, forwardRef) => {
1156
1524
  const { className, ...props } = componentProps;
1525
+ const t = useDsTranslation("blocks");
1157
1526
  return /* @__PURE__ */ jsx(Badge, {
1158
1527
  ref: forwardRef,
1159
1528
  "data-slot": "badge-professional",
1160
1529
  tone: "dark",
1161
1530
  color: "charcoal",
1162
1531
  ...props,
1163
- children: "Professional"
1532
+ children: t("productBadge.professional")
1164
1533
  });
1165
1534
  });
1166
1535
  ProfessionalBadge.displayName = "ProfessionalBadge";
@@ -1170,20 +1539,23 @@ const roleBadgeVariants = cva(GRADIENT_BASE, { variants: { role: {
1170
1539
  admin: "[--badge-accent:var(--color-purple-500)]",
1171
1540
  owner: "[--badge-accent:var(--color-green-400)]"
1172
1541
  } } });
1173
- const ROLE_BADGE_LABEL = {
1174
- agent: "Agent",
1175
- supervisor: "Supervisor",
1176
- admin: "Admin",
1177
- owner: "Owner"
1542
+ const ROLE_BADGE_KEY = {
1543
+ agent: "roleBadge.agent",
1544
+ supervisor: "roleBadge.supervisor",
1545
+ admin: "roleBadge.admin",
1546
+ owner: "roleBadge.owner"
1178
1547
  };
1179
1548
  const RoleBadge = React.forwardRef((componentProps, forwardRef) => {
1180
1549
  const { role, className, ...props } = componentProps;
1550
+ const t = useDsTranslation("blocks");
1181
1551
  return /* @__PURE__ */ jsx(Badge, {
1182
1552
  ref: forwardRef,
1183
1553
  "data-slot": `badge-${role}`,
1554
+ color: "charcoal",
1555
+ tone: "dark",
1184
1556
  className: cn(roleBadgeVariants({ role }), className),
1185
1557
  ...props,
1186
- children: ROLE_BADGE_LABEL[role]
1558
+ children: t(ROLE_BADGE_KEY[role])
1187
1559
  });
1188
1560
  });
1189
1561
  RoleBadge.displayName = "RoleBadge";
@@ -1216,6 +1588,255 @@ function ChatbotPanelTrigger({ children = "Ask anything", icon = /* @__PURE__ */
1216
1588
  });
1217
1589
  }
1218
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
+
1219
1840
  //#endregion
1220
1841
  //#region src/form/form-context.ts
1221
1842
  /**
@@ -1309,7 +1930,7 @@ const CommonForm = createFormHook({
1309
1930
  }
1310
1931
  });
1311
1932
  const useForm = CommonForm.useAppForm;
1312
- const { withForm } = CommonForm;
1933
+ const { withForm, withFieldGroup } = CommonForm;
1313
1934
 
1314
1935
  //#endregion
1315
1936
  //#region src/form/field-errors.ts
@@ -1329,12 +1950,16 @@ function toFieldErrors(errors) {
1329
1950
 
1330
1951
  //#endregion
1331
1952
  //#region src/components/form-field.tsx
1332
- function FormFieldShell({ label, description, children }) {
1953
+ function FormFieldShell({ label, description, required, necessityIndicator, children }) {
1333
1954
  const errors = useFieldContext().state.meta.errors;
1334
1955
  return /* @__PURE__ */ jsxs(Field, {
1335
1956
  "data-invalid": errors.length > 0 ? true : void 0,
1336
1957
  children: [
1337
- /* @__PURE__ */ jsx(FieldLabel, { children: label }),
1958
+ label && /* @__PURE__ */ jsx(FieldLabel, {
1959
+ required,
1960
+ necessityIndicator,
1961
+ children: label
1962
+ }),
1338
1963
  description && /* @__PURE__ */ jsx(FieldDescription, { children: description }),
1339
1964
  children,
1340
1965
  /* @__PURE__ */ jsx(FieldError, { errors: toFieldErrors(errors) })
@@ -1347,14 +1972,20 @@ function FormFieldShell({ label, description, children }) {
1347
1972
  * the AppField + shared shell. `TData`/`TControl` carry the precise field + bundle shapes through.
1348
1973
  */
1349
1974
  function FormFieldBase(props) {
1350
- const { form, name, validators, label, description, buildControl, children } = props;
1975
+ const { form, name, validators, listeners, defaultValue, asyncDebounceMs, asyncAlways, label, description, required, necessityIndicator, buildControl, children } = props;
1351
1976
  const AppField = form.AppField;
1352
1977
  return /* @__PURE__ */ jsx(AppField, {
1353
1978
  name,
1354
1979
  validators,
1980
+ listeners,
1981
+ defaultValue,
1982
+ asyncDebounceMs,
1983
+ asyncAlways,
1355
1984
  children: (field) => /* @__PURE__ */ jsx(FormFieldShell, {
1356
1985
  label,
1357
1986
  description,
1987
+ required,
1988
+ necessityIndicator,
1358
1989
  children: children(field, buildControl(field))
1359
1990
  })
1360
1991
  });
@@ -1614,29 +2245,29 @@ function FormSwitchField(props) {
1614
2245
  }
1615
2246
 
1616
2247
  //#endregion
1617
- //#region src/components/form-number-field.tsx
1618
- function numberControl(field) {
1619
- return { numberProps: {
2248
+ //#region src/components/form-numeric-field.tsx
2249
+ function numericControl(field) {
2250
+ return { numericProps: {
1620
2251
  value: field.state.value,
1621
- onChange: (event) => field.handleChange(event.target.value === "" ? 0 : event.target.valueAsNumber),
2252
+ onValueChange: (value) => field.handleChange(value ?? 0),
1622
2253
  onBlur: field.handleBlur,
1623
2254
  "aria-invalid": field.state.meta.errors.length > 0 ? true : void 0
1624
2255
  } };
1625
2256
  }
1626
2257
  /**
1627
- * Numeric-input field wrapper — same threaded-`form` typing and shared shell as `FormSelectField`,
1628
- * with a `numberProps` bundle. `name` is restricted to the form's **number** fields — a
1629
- * string/boolean `name` is a type error.
2258
+ * Numeric field wrapper — same threaded-`form` typing and shared shell as `FormSelectField`,
2259
+ * with a `numericProps` bundle for the DS `NumericInput` (prefer it over `Input type="number"`).
2260
+ * `name` is restricted to the form's **number** fields — a string/boolean `name` is a type error.
1630
2261
  *
1631
2262
  * @example
1632
- * <FormNumberField form={form} name="age" label="Age" validators={{ onChange }}>
1633
- * {(field, { numberProps }) => <Input type="number" {...numberProps} />}
1634
- * </FormNumberField>
2263
+ * <FormNumericField form={form} name="age" label="Age" validators={{ onChange }}>
2264
+ * {(field, { numericProps }) => <NumericInput {...numericProps} />}
2265
+ * </FormNumericField>
1635
2266
  */
1636
- function FormNumberField(props) {
2267
+ function FormNumericField(props) {
1637
2268
  return /* @__PURE__ */ jsx(FormFieldBase, {
1638
2269
  ...props,
1639
- buildControl: numberControl
2270
+ buildControl: numericControl
1640
2271
  });
1641
2272
  }
1642
2273
 
@@ -2030,4 +2661,4 @@ function DashboardSidebarNav({ groups, renderLink }) {
2030
2661
  }
2031
2662
 
2032
2663
  //#endregion
2033
- export { BetaBadge, CardSaveBar, ChatbotInput, ChatbotPage, 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 };
2664
+ 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, FormNumericField, 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, withFieldGroup, withForm };