@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/README.md +43 -0
- package/dist/globals.css +1 -1
- package/dist/index.d.ts +308 -3
- package/dist/index.js +1021 -147
- package/package.json +17 -3
- package/skills/aircall-blocks/migrate-dashboard/SKILL.md +127 -0
- package/skills/aircall-blocks/migrate-dashboard/card/SKILL.md +364 -0
- package/skills/aircall-blocks/migrate-dashboard/combobox/SKILL.md +487 -0
- package/skills/aircall-blocks/migrate-dashboard/copy-button/SKILL.md +138 -0
- package/skills/aircall-blocks/migrate-dashboard/dashboard-page/SKILL.md +198 -0
- package/skills/aircall-blocks/migrate-dashboard/data-table/SKILL.md +395 -0
- package/skills/aircall-blocks/migrate-dashboard/empty-states/SKILL.md +347 -0
- package/skills/aircall-blocks/migrate-dashboard/form-wizard/SKILL.md +271 -0
- package/skills/aircall-blocks/migrate-dashboard/info-popup/SKILL.md +179 -0
- package/skills/aircall-blocks/migrate-dashboard/layout/SKILL.md +328 -0
- package/skills/aircall-blocks/migrate-dashboard/list/SKILL.md +474 -0
- package/skills/aircall-blocks/migrate-dashboard/loading/SKILL.md +260 -0
- package/skills/aircall-blocks/migrate-dashboard/page-header/SKILL.md +394 -0
- package/skills/aircall-blocks/migrate-dashboard/tile/SKILL.md +429 -0
- package/skills/aircall-blocks/migrate-dashboard/toggle-row/SKILL.md +177 -0
- package/skills/aircall-blocks/setup/SKILL.md +127 -0
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
|
|
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
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
children:
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
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
|
-
})
|
|
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: {
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
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({
|
|
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
|
|
873
|
-
beta: "
|
|
874
|
-
new: "
|
|
875
|
-
deprecated: "
|
|
876
|
-
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
|
|
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:
|
|
1508
|
+
children: t(labelKey)
|
|
888
1509
|
});
|
|
889
1510
|
});
|
|
890
|
-
ProductBadge.displayName =
|
|
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: "
|
|
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
|
|
921
|
-
agent: "
|
|
922
|
-
supervisor: "
|
|
923
|
-
admin: "
|
|
924
|
-
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:
|
|
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 };
|