@aircall/blocks 0.17.0 → 0.18.1

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,15 +1,15 @@
1
- import { Anchor, Badge, Button, CounterBadge, DropdownMenu, DropdownMenuAddon, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, Field, FieldContent, FieldDescription, FieldError, FieldLabel, FieldLabelAside, FieldLabelInfo, FieldLabelRow, HoverCard, HoverCardContent, HoverCardTrigger, InputGroup, InputGroupButton, InputGroupTextarea, Item, ItemActions, ItemContent, ItemGroup, ItemMedia, ItemTitle, Popover, PopoverContent, PopoverTrigger, Separator, Sidebar, SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuAction, SidebarMenuButton, SidebarMenuItem, SidebarProvider, Spinner, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, TabsList, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipTrigger, cn, registerI18nNamespace, useDsLocale, useDsTranslation, useSidebar } from "@aircall/ds";
1
+ import { Anchor, Badge, Button, Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle, CounterBadge, DropdownMenu, DropdownMenuAddon, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, Field, FieldContent, FieldDescription, FieldError, FieldLabel, FieldLabelAside, FieldLabelInfo, FieldLabelRow, HoverCard, HoverCardContent, HoverCardTrigger, InputGroup, InputGroupButton, InputGroupTextarea, Item, ItemActions, ItemContent, ItemGroup, ItemMedia, ItemTitle, Popover, PopoverContent, PopoverTrigger, Separator, Sidebar, SidebarGroup, SidebarGroupLabel, SidebarMenu, SidebarMenuAction, SidebarMenuButton, SidebarMenuItem, SidebarProvider, Skeleton, Spinner, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, TabsList, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipTrigger, cn, registerI18nNamespace, useDsLocale, useDsTranslation, useSidebar } from "@aircall/ds";
2
2
  import * as React from "react";
3
3
  import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
4
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
- import { AircallLoader, AircallLogo, AircallMark, ArrowUp, Check, ChevronDown, ChevronLeft, ChevronRight, Copy, Ellipsis, ExternalLink, FileText, Frown, History, LockKeyhole, Meh, Menu, MessageSquare, Minus, PanelLeft, PanelLeftClose, PanelLeftOpen, Plus, Search, Settings, Smile, Sprout, Square, SquareArrowOutUpRight, ThumbsDown, ThumbsDownFilled, ThumbsUp, ThumbsUpFilled, TriangleAlert } from "@aircall/react-icons";
5
+ import { AircallLoader, AircallLogo, AircallMark, ArrowDownRight, ArrowUp, ArrowUpRight, Check, ChevronDown, ChevronLeft, ChevronRight, Copy, Ellipsis, ExternalLink, FileText, Frown, History, LockKeyhole, Meh, Menu, MessageSquare, Minus, PanelLeft, PanelLeftClose, PanelLeftOpen, Plus, Search, Settings, Smile, 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";
9
9
  import { cva } from "class-variance-authority";
10
- import { createFormHook, createFormHookContexts } from "@tanstack/react-form";
11
10
  import { mergeProps } from "@base-ui/react/merge-props";
12
11
  import { useRender } from "@base-ui/react/use-render";
12
+ import { createFormHook, createFormHookContexts } from "@tanstack/react-form";
13
13
 
14
14
  //#region src/i18n/locales/de.ts
15
15
  const de = {
@@ -360,6 +360,7 @@ const EmptyStateMedia = React.forwardRef((componentProps, forwardRef) => {
360
360
  });
361
361
  });
362
362
  EmptyStateMedia.displayName = "EmptyStateMedia";
363
+ /** Title line of an empty state. Wraps the DS `EmptyTitle`. */
363
364
  const EmptyStateTitle = React.forwardRef((componentProps, forwardRef) => {
364
365
  return /* @__PURE__ */ jsx(EmptyTitle, {
365
366
  ref: forwardRef,
@@ -367,6 +368,7 @@ const EmptyStateTitle = React.forwardRef((componentProps, forwardRef) => {
367
368
  });
368
369
  });
369
370
  EmptyStateTitle.displayName = "EmptyStateTitle";
371
+ /** Supporting description text of an empty state. Wraps the DS `EmptyDescription`. */
370
372
  const EmptyStateDescription = React.forwardRef((componentProps, forwardRef) => {
371
373
  return /* @__PURE__ */ jsx(EmptyDescription, {
372
374
  ref: forwardRef,
@@ -388,6 +390,11 @@ const EmptyStateActions = React.forwardRef((componentProps, forwardRef) => {
388
390
  });
389
391
  });
390
392
  EmptyStateActions.displayName = "EmptyStateActions";
393
+ /**
394
+ * Action button for an empty state — the only button allowed inside one. Wraps
395
+ * the DS `Button` with `size` locked to `default` for visual consistency across
396
+ * empty states; consumers still choose the `variant`.
397
+ */
391
398
  const EmptyStateButton = React.forwardRef((componentProps, forwardRef) => {
392
399
  return /* @__PURE__ */ jsx(Button, {
393
400
  ref: forwardRef,
@@ -396,6 +403,13 @@ const EmptyStateButton = React.forwardRef((componentProps, forwardRef) => {
396
403
  });
397
404
  });
398
405
  EmptyStateButton.displayName = "EmptyStateButton";
406
+ /**
407
+ * External "Learn more"-style link for an empty state. Renders a real `<a>` (via
408
+ * `EmptyStateButton` with `variant="link"`) that opens in a new tab. Pass
409
+ * `children` to override the default "Learn more" label, including any icon.
410
+ *
411
+ * @default children "Learn more"
412
+ */
399
413
  const EmptyStateExternalLink = React.forwardRef((componentProps, forwardRef) => {
400
414
  const { href, children = "Learn more", ...props } = componentProps;
401
415
  return /* @__PURE__ */ jsx(EmptyStateButton, {
@@ -411,6 +425,11 @@ const EmptyStateExternalLink = React.forwardRef((componentProps, forwardRef) =>
411
425
  });
412
426
  });
413
427
  EmptyStateExternalLink.displayName = "EmptyStateExternalLink";
428
+ /**
429
+ * Builds one preset's per-variant parts (`Root`, `Media`, `Title`, `Description`)
430
+ * from its icon, default copy, and a11y role. Returns an object of `forwardRef`
431
+ * components that reuse the shared empty-state parts; renders no DOM itself.
432
+ */
414
433
  function createEmptyStateVariant(config) {
415
434
  const Root = React.forwardRef((componentProps, forwardRef) => /* @__PURE__ */ jsx(EmptyState, {
416
435
  ref: forwardRef,
@@ -452,10 +471,18 @@ function createEmptyStateVariant(config) {
452
471
 
453
472
  //#endregion
454
473
  //#region src/components/coming-soon.tsx
474
+ const ComingSoon = createEmptyStateVariant({
475
+ name: "ComingSoon",
476
+ icon: /* @__PURE__ */ jsx(Sprout, {}),
477
+ titleKey: "emptyState.comingSoon.title",
478
+ descriptionKey: "emptyState.comingSoon.description"
479
+ });
455
480
  /**
456
- * ComingSoon empty state shown when a feature exists in the UI but is not yet
457
- * available. Compose it from its parts:
481
+ * Root of the "Coming soon" empty state shown when a feature exists in the UI
482
+ * but is not yet available. Renders a `<div>` (the DS `Empty` container); compose
483
+ * it from its parts.
458
484
  *
485
+ * @example
459
486
  * ```tsx
460
487
  * <ComingSoonEmptyState>
461
488
  * <EmptyStateHeader>
@@ -469,62 +496,87 @@ function createEmptyStateVariant(config) {
469
496
  * </EmptyStateActions>
470
497
  * </ComingSoonEmptyState>
471
498
  * ```
472
- *
473
- * `ComingSoonTitle` / `ComingSoonDescription` render the design copy by default;
474
- * pass children to override (e.g. for i18n).
475
499
  */
476
- const ComingSoon = createEmptyStateVariant({
477
- name: "ComingSoon",
478
- icon: /* @__PURE__ */ jsx(Sprout, {}),
479
- titleKey: "emptyState.comingSoon.title",
480
- descriptionKey: "emptyState.comingSoon.description"
481
- });
482
500
  const ComingSoonEmptyState = ComingSoon.Root;
501
+ /** Decorative media slot of the "Coming soon" empty state (a sprout icon). Renders a `<div>`, hidden from assistive tech. */
483
502
  const ComingSoonMedia = ComingSoon.Media;
503
+ /** Title line of the "Coming soon" empty state. Renders a `<div>` with the design copy by default; pass children to override. */
484
504
  const ComingSoonTitle = ComingSoon.Title;
505
+ /** Supporting description text of the "Coming soon" empty state. Renders a `<div>` with the design copy by default; pass children to override. */
485
506
  const ComingSoonDescription = ComingSoon.Description;
486
507
 
487
508
  //#endregion
488
509
  //#region src/components/restricted-access.tsx
489
- /**
490
- * RestrictedAccess — shown when the user lacks permission to view a page.
491
- * Pair it with an `EmptyStateExternalLink` for the "Learn more" action.
492
- */
493
510
  const RestrictedAccess = createEmptyStateVariant({
494
511
  name: "RestrictedAccess",
495
512
  icon: /* @__PURE__ */ jsx(LockKeyhole, {}),
496
513
  titleKey: "emptyState.restrictedAccess.title",
497
514
  descriptionKey: "emptyState.restrictedAccess.description"
498
515
  });
516
+ /**
517
+ * Root of the "Restricted access" empty state — shown when the user lacks
518
+ * permission to view a page. Renders a `<div>` (the DS `Empty` container); pair
519
+ * it with an `EmptyStateExternalLink` for the "Learn more" action.
520
+ *
521
+ * @example
522
+ * ```tsx
523
+ * <RestrictedAccessEmptyState>
524
+ * <EmptyStateHeader>
525
+ * <RestrictedAccessMedia />
526
+ * <RestrictedAccessTitle />
527
+ * <RestrictedAccessDescription />
528
+ * </EmptyStateHeader>
529
+ * <EmptyStateActions>
530
+ * <EmptyStateExternalLink href={docsUrl} />
531
+ * </EmptyStateActions>
532
+ * </RestrictedAccessEmptyState>
533
+ * ```
534
+ */
499
535
  const RestrictedAccessEmptyState = RestrictedAccess.Root;
536
+ /** Decorative media slot of the "Restricted access" empty state (a locked padlock icon). Renders a `<div>`, hidden from assistive tech. */
500
537
  const RestrictedAccessMedia = RestrictedAccess.Media;
538
+ /** Title line of the "Restricted access" empty state. Renders a `<div>` with the design copy by default; pass children to override. */
501
539
  const RestrictedAccessTitle = RestrictedAccess.Title;
540
+ /** Supporting description text of the "Restricted access" empty state. Renders a `<div>` with the design copy by default; pass children to override. */
502
541
  const RestrictedAccessDescription = RestrictedAccess.Description;
503
542
 
504
543
  //#endregion
505
544
  //#region src/components/not-found.tsx
506
- /**
507
- * NotFound — shown when a page/route cannot be found. Pair it with an
508
- * `EmptyStateButton` for the navigation action (e.g. "Go to inbox").
509
- */
510
545
  const NotFound = createEmptyStateVariant({
511
546
  name: "NotFound",
512
547
  icon: /* @__PURE__ */ jsx(Search, {}),
513
548
  titleKey: "emptyState.notFound.title",
514
549
  descriptionKey: "emptyState.notFound.description"
515
550
  });
551
+ /**
552
+ * Root of the "Not found" empty state — shown when a page or route cannot be
553
+ * found. Renders a `<div>` (the DS `Empty` container); pair it with an
554
+ * `EmptyStateButton` for the navigation action (e.g. "Go to inbox").
555
+ *
556
+ * @example
557
+ * ```tsx
558
+ * <NotFoundEmptyState>
559
+ * <EmptyStateHeader>
560
+ * <NotFoundMedia />
561
+ * <NotFoundTitle />
562
+ * <NotFoundDescription />
563
+ * </EmptyStateHeader>
564
+ * <EmptyStateActions>
565
+ * <EmptyStateButton onClick={goToInbox}>Go to inbox</EmptyStateButton>
566
+ * </EmptyStateActions>
567
+ * </NotFoundEmptyState>
568
+ * ```
569
+ */
516
570
  const NotFoundEmptyState = NotFound.Root;
571
+ /** Decorative media slot of the "Not found" empty state (a search icon). Renders a `<div>`, hidden from assistive tech. */
517
572
  const NotFoundMedia = NotFound.Media;
573
+ /** Title line of the "Not found" empty state. Renders a `<div>` with the design copy by default; pass children to override. */
518
574
  const NotFoundTitle = NotFound.Title;
575
+ /** Supporting description text of the "Not found" empty state. Renders a `<div>` with the design copy by default; pass children to override. */
519
576
  const NotFoundDescription = NotFound.Description;
520
577
 
521
578
  //#endregion
522
579
  //#region src/components/no-data.tsx
523
- /**
524
- * NoData — shown when a search or filter returns no results. Pair it with an
525
- * `EmptyStateButton` for the "Reset" action. Appears in response to a user
526
- * action, so it announces politely via `role="status"`.
527
- */
528
580
  const NoData = createEmptyStateVariant({
529
581
  name: "NoData",
530
582
  icon: /* @__PURE__ */ jsx(Search, {}),
@@ -532,35 +584,71 @@ const NoData = createEmptyStateVariant({
532
584
  descriptionKey: "emptyState.noData.description",
533
585
  role: "status"
534
586
  });
587
+ /**
588
+ * Root of the "No data" empty state — shown when a search or filter returns no
589
+ * results. Renders a `<div>` (the DS `Empty` container) with `role="status"` so
590
+ * it announces politely after a user action; pair it with an `EmptyStateButton`
591
+ * for the "Reset" action.
592
+ *
593
+ * @example
594
+ * ```tsx
595
+ * <NoDataEmptyState>
596
+ * <EmptyStateHeader>
597
+ * <NoDataMedia />
598
+ * <NoDataTitle />
599
+ * <NoDataDescription />
600
+ * </EmptyStateHeader>
601
+ * <EmptyStateActions>
602
+ * <EmptyStateButton variant="outline" onClick={resetFilters}>Reset</EmptyStateButton>
603
+ * </EmptyStateActions>
604
+ * </NoDataEmptyState>
605
+ * ```
606
+ */
535
607
  const NoDataEmptyState = NoData.Root;
608
+ /** Decorative media slot of the "No data" empty state (a search icon). Renders a `<div>`, hidden from assistive tech. */
536
609
  const NoDataMedia = NoData.Media;
610
+ /** Title line of the "No data" empty state. Renders a `<div>` with the design copy by default; pass children to override. */
537
611
  const NoDataTitle = NoData.Title;
612
+ /** Supporting description text of the "No data" empty state. Renders a `<div>` with the design copy by default; pass children to override. */
538
613
  const NoDataDescription = NoData.Description;
539
614
 
540
615
  //#endregion
541
616
  //#region src/components/no-support.tsx
542
- /**
543
- * NoSupport — shown when the current browser can't render a page. Pair it with
544
- * an `EmptyStateExternalLink` for the "Learn more" action.
545
- */
546
617
  const NoSupport = createEmptyStateVariant({
547
618
  name: "NoSupport",
548
619
  icon: /* @__PURE__ */ jsx(Settings, {}),
549
620
  titleKey: "emptyState.noSupport.title",
550
621
  descriptionKey: "emptyState.noSupport.description"
551
622
  });
623
+ /**
624
+ * Root of the "No support" empty state — shown when the current browser can't
625
+ * render a page. Renders a `<div>` (the DS `Empty` container); pair it with an
626
+ * `EmptyStateExternalLink` for the "Learn more" action.
627
+ *
628
+ * @example
629
+ * ```tsx
630
+ * <NoSupportEmptyState>
631
+ * <EmptyStateHeader>
632
+ * <NoSupportMedia />
633
+ * <NoSupportTitle />
634
+ * <NoSupportDescription />
635
+ * </EmptyStateHeader>
636
+ * <EmptyStateActions>
637
+ * <EmptyStateExternalLink href={docsUrl} />
638
+ * </EmptyStateActions>
639
+ * </NoSupportEmptyState>
640
+ * ```
641
+ */
552
642
  const NoSupportEmptyState = NoSupport.Root;
643
+ /** Decorative media slot of the "No support" empty state (a settings icon). Renders a `<div>`, hidden from assistive tech. */
553
644
  const NoSupportMedia = NoSupport.Media;
645
+ /** Title line of the "No support" empty state. Renders a `<div>` with the design copy by default; pass children to override. */
554
646
  const NoSupportTitle = NoSupport.Title;
647
+ /** Supporting description text of the "No support" empty state. Renders a `<div>` with the design copy by default; pass children to override. */
555
648
  const NoSupportDescription = NoSupport.Description;
556
649
 
557
650
  //#endregion
558
651
  //#region src/components/unknown-error.tsx
559
- /**
560
- * UnknownError — shown when content fails to load unexpectedly. Pair it with an
561
- * `EmptyStateButton` (primary) for the "Try again" action. As an error state it
562
- * announces assertively via `role="alert"`.
563
- */
564
652
  const UnknownError = createEmptyStateVariant({
565
653
  name: "UnknownError",
566
654
  icon: /* @__PURE__ */ jsx(TriangleAlert, {}),
@@ -568,9 +656,32 @@ const UnknownError = createEmptyStateVariant({
568
656
  descriptionKey: "emptyState.unknownError.description",
569
657
  role: "alert"
570
658
  });
659
+ /**
660
+ * Root of the "Unknown error" empty state — shown when content fails to load
661
+ * unexpectedly. Renders a `<div>` (the DS `Empty` container) with `role="alert"`
662
+ * so it announces assertively; pair it with a primary `EmptyStateButton` for the
663
+ * "Try again" action.
664
+ *
665
+ * @example
666
+ * ```tsx
667
+ * <UnknownErrorEmptyState>
668
+ * <EmptyStateHeader>
669
+ * <UnknownErrorMedia />
670
+ * <UnknownErrorTitle />
671
+ * <UnknownErrorDescription />
672
+ * </EmptyStateHeader>
673
+ * <EmptyStateActions>
674
+ * <EmptyStateButton onClick={retry}>Try again</EmptyStateButton>
675
+ * </EmptyStateActions>
676
+ * </UnknownErrorEmptyState>
677
+ * ```
678
+ */
571
679
  const UnknownErrorEmptyState = UnknownError.Root;
680
+ /** Decorative media slot of the "Unknown error" empty state (a warning triangle icon). Renders a `<div>`, hidden from assistive tech. */
572
681
  const UnknownErrorMedia = UnknownError.Media;
682
+ /** Title line of the "Unknown error" empty state. Renders a `<div>` with the design copy by default; pass children to override. */
573
683
  const UnknownErrorTitle = UnknownError.Title;
684
+ /** Supporting description text of the "Unknown error" empty state. Renders a `<div>` with the design copy by default; pass children to override. */
574
685
  const UnknownErrorDescription = UnknownError.Description;
575
686
 
576
687
  //#endregion
@@ -904,6 +1015,19 @@ function useCopyButtonContext() {
904
1015
  if (ctx === null) throw new Error("CopyButtonIcon and CopyButtonLabel must be rendered inside a CopyButton.");
905
1016
  return ctx;
906
1017
  }
1018
+ /**
1019
+ * Copy-to-clipboard button. Composes DS `Button`; copies `value` on click and
1020
+ * exposes a `copied` state (auto-reset after `timeout`) to its `CopyButtonIcon`
1021
+ * and `CopyButtonLabel` children via context. Renders a `<button>`.
1022
+ *
1023
+ * @example
1024
+ * ```tsx
1025
+ * <CopyButton value="npm i @aircall/ds">
1026
+ * <CopyButtonIcon />
1027
+ * <CopyButtonLabel />
1028
+ * </CopyButton>
1029
+ * ```
1030
+ */
907
1031
  const CopyButton = React.forwardRef((componentProps, forwardRef) => {
908
1032
  const { value, timeout, onCopied, variant = "outline", children, ...buttonProps } = componentProps;
909
1033
  const { copy, copied } = useCopyToClipboard(value, {
@@ -924,6 +1048,10 @@ const CopyButton = React.forwardRef((componentProps, forwardRef) => {
924
1048
  });
925
1049
  });
926
1050
  CopyButton.displayName = "CopyButton";
1051
+ /**
1052
+ * Icon for `CopyButton` that swaps between a copy glyph and a check glyph based on
1053
+ * the parent's copied state. Renders an `<svg>`. Must be used inside a `CopyButton`.
1054
+ */
927
1055
  const CopyButtonIcon = React.forwardRef((componentProps, forwardRef) => {
928
1056
  const { className } = componentProps;
929
1057
  const { copied } = useCopyButtonContext();
@@ -933,6 +1061,10 @@ const CopyButtonIcon = React.forwardRef((componentProps, forwardRef) => {
933
1061
  });
934
1062
  });
935
1063
  CopyButtonIcon.displayName = "CopyButtonIcon";
1064
+ /**
1065
+ * Text label for `CopyButton` that shows `label` normally and `copiedLabel` after a
1066
+ * successful copy. Renders a `<span>`. Must be used inside a `CopyButton`.
1067
+ */
936
1068
  const CopyButtonLabel = React.forwardRef((componentProps, forwardRef) => {
937
1069
  const { label = "Copy", copiedLabel = "Copied", className } = componentProps;
938
1070
  const { copied } = useCopyButtonContext();
@@ -1039,6 +1171,22 @@ const MARKDOWN_COMPONENTS = {
1039
1171
  ...props
1040
1172
  })
1041
1173
  };
1174
+ /**
1175
+ * Renders a chatbot response from markdown, splitting it into markdown text and
1176
+ * embedded component blocks (table, audio, transcript, loading), with a sources
1177
+ * hover card and copy / thumbs-up / thumbs-down feedback controls. Renders a
1178
+ * `<div>` (`data-slot="chatbot-response-block"`).
1179
+ *
1180
+ * @example
1181
+ * ```tsx
1182
+ * <ChatbotResponseBlock
1183
+ * messageId="msg-1"
1184
+ * markdown="**Hello** from the assistant"
1185
+ * sources={[{ title: 'Help center', url: 'https://help.aircall.io' }]}
1186
+ * onFeedback={value => console.log(value)}
1187
+ * />
1188
+ * ```
1189
+ */
1042
1190
  function ChatbotResponseBlock({ messageId, markdown, streaming = false, sources, onFeedback, className }) {
1043
1191
  const t = useDsTranslation("blocks");
1044
1192
  const [feedback, setFeedback] = useState(null);
@@ -1156,6 +1304,26 @@ function ChatbotResponseLoading({ text, className }) {
1156
1304
 
1157
1305
  //#endregion
1158
1306
  //#region src/components/chatbot-page.tsx
1307
+ /**
1308
+ * Root layout shell for the AI chatbot experience; provides the `SidebarProvider`
1309
+ * context required by `ChatbotSidebar` and lays out the sidebar and content
1310
+ * columns. Renders a `SidebarProvider` (a `<div>` wrapper) with the sidebar width
1311
+ * preset and full-height overrides for panel/modal contexts.
1312
+ *
1313
+ * @example
1314
+ * ```tsx
1315
+ * <ChatbotPage>
1316
+ * <ChatbotSidebar conversations={[...]} />
1317
+ * <ChatbotPageContent>
1318
+ * <ChatbotPageBody>
1319
+ * <ChatbotPageHeading>Need help?</ChatbotPageHeading>
1320
+ * <ChatbotInput />
1321
+ * </ChatbotPageBody>
1322
+ * <ChatbotPageFooter betaTermsHref="https://legal.aircall.io/..." />
1323
+ * </ChatbotPageContent>
1324
+ * </ChatbotPage>
1325
+ * ```
1326
+ */
1159
1327
  const ChatbotPage = React.forwardRef((componentProps, forwardRef) => {
1160
1328
  const { children, className } = componentProps;
1161
1329
  return /* @__PURE__ */ jsx(SidebarProvider, {
@@ -1474,6 +1642,19 @@ function ChatbotPanelHeader({ title = "Ask Aircall", onMenu, menuContent, menuOp
1474
1642
  //#region src/components/chatbot-sidebar.tsx
1475
1643
  const SIDEBAR_MIN_WIDTH = 140;
1476
1644
  const SIDEBAR_MAX_WIDTH = 480;
1645
+ /**
1646
+ * Conversation-history sidebar: an optional "New Chat" entry plus a scrollable,
1647
+ * resizable list of recent conversations, each with an optional trailing ⋯ menu.
1648
+ * Renders the DS `Sidebar` (a `<div>`), or a plain `<div>` when `popup`. Must be
1649
+ * rendered inside a `SidebarProvider`.
1650
+ *
1651
+ * @example
1652
+ * ```tsx
1653
+ * <SidebarProvider>
1654
+ * <ChatbotSidebar conversations={items} onSelectConversation={open} />
1655
+ * </SidebarProvider>
1656
+ * ```
1657
+ */
1477
1658
  const ChatbotSidebar = React.forwardRef((componentProps, forwardRef) => {
1478
1659
  const { conversations, activeConversationId, onNewChat, onSelectConversation, renderConversationMenuContent, recentLabel = "Recent", showNewChat = true, popup = false, className } = componentProps;
1479
1660
  const t = useDsTranslation("blocks");
@@ -1565,6 +1746,17 @@ ChatbotSidebar.displayName = "ChatbotSidebar";
1565
1746
 
1566
1747
  //#endregion
1567
1748
  //#region src/components/chatbot-panel-suggestion.tsx
1749
+ /**
1750
+ * Pill-shaped prompt suggestion shown in the chatbot panel; a preset styling of
1751
+ * `Button` with a green border and surface background. Renders a `<button>`.
1752
+ *
1753
+ * @example
1754
+ * ```tsx
1755
+ * <ChatbotPanelSuggestion onClick={() => ask('How do I set my phone line?')}>
1756
+ * How do I set my phone line?
1757
+ * </ChatbotPanelSuggestion>
1758
+ * ```
1759
+ */
1568
1760
  function ChatbotPanelSuggestion({ className, ...props }) {
1569
1761
  return /* @__PURE__ */ jsx(Button, {
1570
1762
  "data-slot": "chatbot-panel-suggestion",
@@ -1597,6 +1789,18 @@ const textareaVariants = cva([
1597
1789
  expanded: false
1598
1790
  }
1599
1791
  });
1792
+ /**
1793
+ * Chatbot message composer: an auto-growing `InputGroup` textarea with a send/stop
1794
+ * button, plus optional suggestion pills and a conversation-history popover. Works
1795
+ * controlled (`value` + `onValueChange`) or uncontrolled. Enter submits;
1796
+ * Shift+Enter inserts a newline. Renders the DS `InputGroup` (a `<div>`) wrapping a
1797
+ * `<textarea>`.
1798
+ *
1799
+ * @example
1800
+ * ```tsx
1801
+ * <ChatbotInput value={text} onValueChange={setText} onSubmit={send} />
1802
+ * ```
1803
+ */
1600
1804
  function ChatbotInput({ className, value, onValueChange, onSubmit, onStop, placeholder, loading = false, size = "default", expanded = false, disabled, suggestions, onSuggestionClick, conversations, activeConversationId, onSelectConversation, ...textareaProps }) {
1601
1805
  const t = useDsTranslation("blocks");
1602
1806
  const [currentValue = "", setCurrentValue] = useControllableState({
@@ -1715,6 +1919,16 @@ function ChatbotInput({ className, value, onValueChange, onSubmit, onStop, place
1715
1919
 
1716
1920
  //#endregion
1717
1921
  //#region src/components/chatbot-user-message.tsx
1922
+ /**
1923
+ * Right-aligned chat bubble for a user's message; clamps long content to six
1924
+ * lines with a "Show more" / "Show less" toggle. Renders a `<div>`
1925
+ * (`data-slot="chatbot-user-message"`).
1926
+ *
1927
+ * @example
1928
+ * ```tsx
1929
+ * <ChatbotUserMessage>How do I set up my phone number?</ChatbotUserMessage>
1930
+ * ```
1931
+ */
1718
1932
  function ChatbotUserMessage({ className, children, ...props }) {
1719
1933
  const [expanded, setExpanded] = useState(false);
1720
1934
  const [showToggle, setShowToggle] = useState(false);
@@ -1744,6 +1958,25 @@ function ChatbotUserMessage({ className, children, ...props }) {
1744
1958
 
1745
1959
  //#endregion
1746
1960
  //#region src/components/dashboard-standalone-page.tsx
1961
+ /**
1962
+ * Full-screen takeover shell for focused, sidebar-less flows; renders a flex-row `<div>`
1963
+ * holding one or more `DashboardStandalonePageContent` panels side by side.
1964
+ *
1965
+ * @example
1966
+ * ```tsx
1967
+ * <DashboardStandalonePage>
1968
+ * <DashboardStandalonePageContent>
1969
+ * <DashboardStandalonePageHeader>
1970
+ * <DashboardStandalonePageTitle>Create user</DashboardStandalonePageTitle>
1971
+ * <DashboardStandalonePageActions side="start">
1972
+ * <DashboardStandalonePageAction>Cancel</DashboardStandalonePageAction>
1973
+ * </DashboardStandalonePageActions>
1974
+ * </DashboardStandalonePageHeader>
1975
+ * <DashboardStandalonePageMain>…</DashboardStandalonePageMain>
1976
+ * </DashboardStandalonePageContent>
1977
+ * </DashboardStandalonePage>
1978
+ * ```
1979
+ */
1747
1980
  const DashboardStandalonePage = React.forwardRef((componentProps, forwardRef) => {
1748
1981
  const { className, ...props } = componentProps;
1749
1982
  return /* @__PURE__ */ jsx("div", {
@@ -1754,6 +1987,10 @@ const DashboardStandalonePage = React.forwardRef((componentProps, forwardRef) =>
1754
1987
  });
1755
1988
  });
1756
1989
  DashboardStandalonePage.displayName = "DashboardStandalonePage";
1990
+ /**
1991
+ * Rounded, bordered content panel that fills the shell; renders a `<div>`.
1992
+ * Typically wraps a `DashboardStandalonePageHeader` above a `DashboardStandalonePageMain`.
1993
+ */
1757
1994
  const DashboardStandalonePageContent = React.forwardRef((componentProps, forwardRef) => {
1758
1995
  const { className, ...props } = componentProps;
1759
1996
  return /* @__PURE__ */ jsx("div", {
@@ -1764,6 +2001,10 @@ const DashboardStandalonePageContent = React.forwardRef((componentProps, forward
1764
2001
  });
1765
2002
  });
1766
2003
  DashboardStandalonePageContent.displayName = "DashboardStandalonePageContent";
2004
+ /**
2005
+ * Fixed-height (64px) header bar with an optically centered title and absolutely
2006
+ * positioned action slots; renders a `<header>`.
2007
+ */
1767
2008
  const DashboardStandalonePageHeader = React.forwardRef((componentProps, forwardRef) => {
1768
2009
  const { className, ...props } = componentProps;
1769
2010
  return /* @__PURE__ */ jsx("header", {
@@ -1774,6 +2015,9 @@ const DashboardStandalonePageHeader = React.forwardRef((componentProps, forwardR
1774
2015
  });
1775
2016
  });
1776
2017
  DashboardStandalonePageHeader.displayName = "DashboardStandalonePageHeader";
2018
+ /**
2019
+ * Centered, truncated page title in the header; renders an `<h1>`.
2020
+ */
1777
2021
  const DashboardStandalonePageTitle = React.forwardRef((componentProps, forwardRef) => {
1778
2022
  const { className, ...props } = componentProps;
1779
2023
  return /* @__PURE__ */ jsx("h1", {
@@ -1784,6 +2028,9 @@ const DashboardStandalonePageTitle = React.forwardRef((componentProps, forwardRe
1784
2028
  });
1785
2029
  });
1786
2030
  DashboardStandalonePageTitle.displayName = "DashboardStandalonePageTitle";
2031
+ /**
2032
+ * Optional subtitle stacked beneath the title in the header; renders a `<p>`.
2033
+ */
1787
2034
  const DashboardStandalonePageDescription = React.forwardRef((componentProps, forwardRef) => {
1788
2035
  const { className, ...props } = componentProps;
1789
2036
  return /* @__PURE__ */ jsx("p", {
@@ -1794,6 +2041,10 @@ const DashboardStandalonePageDescription = React.forwardRef((componentProps, for
1794
2041
  });
1795
2042
  });
1796
2043
  DashboardStandalonePageDescription.displayName = "DashboardStandalonePageDescription";
2044
+ /**
2045
+ * Action slot absolutely pinned to the header's left or right edge; renders a `<div>`.
2046
+ * Sitting outside the flow, it never shifts the centered title.
2047
+ */
1797
2048
  const DashboardStandalonePageActions = React.forwardRef((componentProps, forwardRef) => {
1798
2049
  const { side = "end", className, ...props } = componentProps;
1799
2050
  return /* @__PURE__ */ jsx("div", {
@@ -1805,6 +2056,9 @@ const DashboardStandalonePageActions = React.forwardRef((componentProps, forward
1805
2056
  });
1806
2057
  });
1807
2058
  DashboardStandalonePageActions.displayName = "DashboardStandalonePageActions";
2059
+ /**
2060
+ * Header action button rendering a ds `Button` (ghost, `lg` by default); renders a `<button>`.
2061
+ */
1808
2062
  const DashboardStandalonePageAction = React.forwardRef((componentProps, forwardRef) => {
1809
2063
  const { variant = "ghost", ...props } = componentProps;
1810
2064
  return /* @__PURE__ */ jsx(Button, {
@@ -1815,6 +2069,9 @@ const DashboardStandalonePageAction = React.forwardRef((componentProps, forwardR
1815
2069
  });
1816
2070
  });
1817
2071
  DashboardStandalonePageAction.displayName = "DashboardStandalonePageAction";
2072
+ /**
2073
+ * Scrollable, transparent content area below the header inside the panel; renders a `<main>`.
2074
+ */
1818
2075
  const DashboardStandalonePageMain = React.forwardRef((componentProps, forwardRef) => {
1819
2076
  const { className, ...props } = componentProps;
1820
2077
  return /* @__PURE__ */ jsx("main", {
@@ -1828,6 +2085,21 @@ DashboardStandalonePageMain.displayName = "DashboardStandalonePageMain";
1828
2085
 
1829
2086
  //#endregion
1830
2087
  //#region src/components/dashboard-page.tsx
2088
+ /**
2089
+ * Full-screen outer shell for a dashboard view; renders a `<div>`.
2090
+ * Stacks an optional `DashboardPageBanner` above a `DashboardSidebarProvider`
2091
+ * that holds the sidebar and a `DashboardPageContent`.
2092
+ *
2093
+ * @example
2094
+ * ```tsx
2095
+ * <DashboardPage>
2096
+ * <DashboardSidebarProvider>
2097
+ * <DashboardSidebar>…</DashboardSidebar>
2098
+ * <DashboardPageContent>…</DashboardPageContent>
2099
+ * </DashboardSidebarProvider>
2100
+ * </DashboardPage>
2101
+ * ```
2102
+ */
1831
2103
  const DashboardPage = React.forwardRef((componentProps, forwardRef) => {
1832
2104
  const { className, ...props } = componentProps;
1833
2105
  return /* @__PURE__ */ jsx("div", {
@@ -1838,6 +2110,10 @@ const DashboardPage = React.forwardRef((componentProps, forwardRef) => {
1838
2110
  });
1839
2111
  });
1840
2112
  DashboardPage.displayName = "DashboardPage";
2113
+ /**
2114
+ * Full-width top row that sits flush above the sidebar/content row; renders a `<div>`.
2115
+ * Use to host trial notices, announcements, or any ds `Banner`.
2116
+ */
1841
2117
  const DashboardPageBanner = React.forwardRef((componentProps, forwardRef) => {
1842
2118
  const { className, ...props } = componentProps;
1843
2119
  return /* @__PURE__ */ jsx("div", {
@@ -1848,16 +2124,22 @@ const DashboardPageBanner = React.forwardRef((componentProps, forwardRef) => {
1848
2124
  });
1849
2125
  });
1850
2126
  DashboardPageBanner.displayName = "DashboardPageBanner";
2127
+ /**
2128
+ * White content card filling the right column beside the sidebar; renders a `<div>`.
2129
+ */
1851
2130
  const DashboardPageContent = React.forwardRef((componentProps, forwardRef) => {
1852
2131
  const { className, ...props } = componentProps;
1853
2132
  return /* @__PURE__ */ jsx("div", {
1854
2133
  ref: forwardRef,
1855
2134
  "data-slot": "dashboard-page-content",
1856
- className: cn("flex-1 min-w-0 flex flex-col bg-background rounded-xl border border-border overflow-hidden", "[&:has([data-slot=dph-tabs])>[data-slot=dph]]:border-b-0", className),
2135
+ className: cn("flex-1 min-w-0 h-full flex flex-col bg-background rounded-xl border border-border overflow-hidden", "[&:has([data-slot=dph-tabs])>[data-slot=dph]]:border-b-0", className),
1857
2136
  ...props
1858
2137
  });
1859
2138
  });
1860
2139
  DashboardPageContent.displayName = "DashboardPageContent";
2140
+ /**
2141
+ * Scrollable content area inside `DashboardPageContent`; renders a `<main>`.
2142
+ */
1861
2143
  const DashboardPageMain = React.forwardRef((componentProps, forwardRef) => {
1862
2144
  const { className, ...props } = componentProps;
1863
2145
  return /* @__PURE__ */ jsx("main", {
@@ -1868,6 +2150,9 @@ const DashboardPageMain = React.forwardRef((componentProps, forwardRef) => {
1868
2150
  });
1869
2151
  });
1870
2152
  DashboardPageMain.displayName = "DashboardPageMain";
2153
+ /**
2154
+ * Left-aligned tab bar placed as a sibling of `DashboardPageHeader`; renders a ds `TabsList`.
2155
+ */
1871
2156
  const DashboardPageTabs = React.forwardRef((componentProps, forwardRef) => {
1872
2157
  const { className, ...props } = componentProps;
1873
2158
  return /* @__PURE__ */ jsx(TabsList, {
@@ -1881,6 +2166,20 @@ DashboardPageTabs.displayName = "DashboardPageTabs";
1881
2166
 
1882
2167
  //#endregion
1883
2168
  //#region src/components/dashboard-page-header.tsx
2169
+ /**
2170
+ * Header for a `DashboardPageContent`; renders a `<div>` that establishes a
2171
+ * `@container` context with an inner CSS-grid its sub-components self-place into.
2172
+ *
2173
+ * @example
2174
+ * ```tsx
2175
+ * <DashboardPageHeader>
2176
+ * <DashboardPageHeaderTitle>Team</DashboardPageHeaderTitle>
2177
+ * <DashboardPageHeaderActions>
2178
+ * <DashboardPageHeaderAction>Invite</DashboardPageHeaderAction>
2179
+ * </DashboardPageHeaderActions>
2180
+ * </DashboardPageHeader>
2181
+ * ```
2182
+ */
1884
2183
  const DashboardPageHeader = React.forwardRef((componentProps, forwardRef) => {
1885
2184
  const { className, children, ...props } = componentProps;
1886
2185
  return /* @__PURE__ */ jsx("div", {
@@ -1896,6 +2195,9 @@ const DashboardPageHeader = React.forwardRef((componentProps, forwardRef) => {
1896
2195
  });
1897
2196
  });
1898
2197
  DashboardPageHeader.displayName = "DashboardPageHeader";
2198
+ /**
2199
+ * Back-navigation row for Level 2 headers; renders a `<div>` in the grid `nav` area.
2200
+ */
1899
2201
  const DashboardPageHeaderNav = React.forwardRef((componentProps, forwardRef) => {
1900
2202
  const { className, children, ...props } = componentProps;
1901
2203
  return /* @__PURE__ */ jsx("div", {
@@ -1907,6 +2209,10 @@ const DashboardPageHeaderNav = React.forwardRef((componentProps, forwardRef) =>
1907
2209
  });
1908
2210
  });
1909
2211
  DashboardPageHeaderNav.displayName = "DashboardPageHeaderNav";
2212
+ /**
2213
+ * Back button rendering a ghost, small ds `Button` with a leading chevron icon.
2214
+ * Accepts a render prop so it can become an `<a>` or router `<Link>`.
2215
+ */
1910
2216
  const DashboardPageHeaderNavBack = React.forwardRef((componentProps, forwardRef) => {
1911
2217
  const { children, ...props } = componentProps;
1912
2218
  return /* @__PURE__ */ jsxs(Button, {
@@ -1919,6 +2225,9 @@ const DashboardPageHeaderNavBack = React.forwardRef((componentProps, forwardRef)
1919
2225
  });
1920
2226
  });
1921
2227
  DashboardPageHeaderNavBack.displayName = "DashboardPageHeaderNavBack";
2228
+ /**
2229
+ * Icon/flag slot shown left of the title; renders a `<div>` in the grid `prefix` area.
2230
+ */
1922
2231
  const DashboardPageHeaderPrefix = React.forwardRef((componentProps, forwardRef) => {
1923
2232
  const { className, children, ...props } = componentProps;
1924
2233
  return /* @__PURE__ */ jsx("div", {
@@ -1930,6 +2239,9 @@ const DashboardPageHeaderPrefix = React.forwardRef((componentProps, forwardRef)
1930
2239
  });
1931
2240
  });
1932
2241
  DashboardPageHeaderPrefix.displayName = "DashboardPageHeaderPrefix";
2242
+ /**
2243
+ * Wrapper that stacks the title and subtitle; renders a `<div>` in the grid `info` area.
2244
+ */
1933
2245
  const DashboardPageHeaderTitleGroup = React.forwardRef((componentProps, forwardRef) => {
1934
2246
  const { className, children, ...props } = componentProps;
1935
2247
  return /* @__PURE__ */ jsx("div", {
@@ -1941,6 +2253,10 @@ const DashboardPageHeaderTitleGroup = React.forwardRef((componentProps, forwardR
1941
2253
  });
1942
2254
  });
1943
2255
  DashboardPageHeaderTitleGroup.displayName = "DashboardPageHeaderTitleGroup";
2256
+ /**
2257
+ * Page title; renders an `<h1>`, self-placing in the grid `info` area or deferring
2258
+ * layout to `DashboardPageHeaderTitleGroup` when nested inside one.
2259
+ */
1944
2260
  const DashboardPageHeaderTitle = React.forwardRef((componentProps, forwardRef) => {
1945
2261
  const { size = "lg", className, children, ...props } = componentProps;
1946
2262
  return /* @__PURE__ */ jsx("h1", {
@@ -1952,6 +2268,9 @@ const DashboardPageHeaderTitle = React.forwardRef((componentProps, forwardRef) =
1952
2268
  });
1953
2269
  });
1954
2270
  DashboardPageHeaderTitle.displayName = "DashboardPageHeaderTitle";
2271
+ /**
2272
+ * Optional subtitle line/block placed beneath the title; renders a `<div>`.
2273
+ */
1955
2274
  const DashboardPageHeaderSubtitle = React.forwardRef((componentProps, forwardRef) => {
1956
2275
  const { className, children, ...props } = componentProps;
1957
2276
  return /* @__PURE__ */ jsx("div", {
@@ -1963,6 +2282,9 @@ const DashboardPageHeaderSubtitle = React.forwardRef((componentProps, forwardRef
1963
2282
  });
1964
2283
  });
1965
2284
  DashboardPageHeaderSubtitle.displayName = "DashboardPageHeaderSubtitle";
2285
+ /**
2286
+ * Muted, clamped description text under the title; renders a `<div>`.
2287
+ */
1966
2288
  const DashboardPageHeaderDescription = React.forwardRef((componentProps, forwardRef) => {
1967
2289
  const { className, children, ...props } = componentProps;
1968
2290
  return /* @__PURE__ */ jsx("div", {
@@ -1974,6 +2296,9 @@ const DashboardPageHeaderDescription = React.forwardRef((componentProps, forward
1974
2296
  });
1975
2297
  });
1976
2298
  DashboardPageHeaderDescription.displayName = "DashboardPageHeaderDescription";
2299
+ /**
2300
+ * Flex container for header actions; renders a `<div>` in the grid `actions` area.
2301
+ */
1977
2302
  const DashboardPageHeaderActions = React.forwardRef((componentProps, forwardRef) => {
1978
2303
  const { className, children, ...props } = componentProps;
1979
2304
  return /* @__PURE__ */ jsx("div", {
@@ -1985,6 +2310,10 @@ const DashboardPageHeaderActions = React.forwardRef((componentProps, forwardRef)
1985
2310
  });
1986
2311
  });
1987
2312
  DashboardPageHeaderActions.displayName = "DashboardPageHeaderActions";
2313
+ /**
2314
+ * Header action button rendering a ds `Button` locked to the actions area sizes;
2315
+ * renders a `<button>` (defaults to a labeled `lg` CTA, or `icon-lg` for icon-only triggers).
2316
+ */
1988
2317
  const DashboardPageHeaderAction = React.forwardRef((componentProps, forwardRef) => {
1989
2318
  const { size = "lg", ...props } = componentProps;
1990
2319
  return /* @__PURE__ */ jsx(Button, {
@@ -2194,6 +2523,380 @@ const ScoreBadge = React.forwardRef((componentProps, forwardRef) => {
2194
2523
  });
2195
2524
  ScoreBadge.displayName = "ScoreBadge";
2196
2525
 
2526
+ //#endregion
2527
+ //#region src/helpers/format-kpi.ts
2528
+ /** Empty KPI placeholder matching Figma empty tiles and ScoreBadge. */
2529
+ const KPI_EMPTY = "--";
2530
+ /** Default secondary unit for clock durations. */
2531
+ function clockDurationUnit(scale) {
2532
+ return scale === "hours" ? "hr/min" : "min/sec";
2533
+ }
2534
+ /**
2535
+ * Locale decimal separator (e.g. `.` for `en-US`, `,` for `fr-FR`).
2536
+ */
2537
+ function getDecimalSeparator(locale) {
2538
+ return new Intl.NumberFormat(locale).formatToParts(1.1).find((p) => p.type === "decimal")?.value ?? ".";
2539
+ }
2540
+ /**
2541
+ * Split a locale-formatted number on its decimal separator so the integer group
2542
+ * can use primary typography and the fraction (+ unit) secondary typography.
2543
+ */
2544
+ function splitFormattedNumber(formatted, locale) {
2545
+ const dec = getDecimalSeparator(locale);
2546
+ const idx = formatted.indexOf(dec);
2547
+ if (idx === -1) return {
2548
+ primary: formatted,
2549
+ secondary: ""
2550
+ };
2551
+ return {
2552
+ primary: formatted.slice(0, idx),
2553
+ secondary: formatted.slice(idx)
2554
+ };
2555
+ }
2556
+ /**
2557
+ * Split a duration string on the leading digit run (`"1h 2min 3s"` → `"1"` + `"h 2min 3s"`).
2558
+ */
2559
+ function splitLeadingDigits(text) {
2560
+ const match = /^(\d+)([\s\S]*)$/.exec(text);
2561
+ if (!match) return null;
2562
+ return {
2563
+ primary: match[1],
2564
+ secondary: match[2]
2565
+ };
2566
+ }
2567
+ /**
2568
+ * Format seconds into a readable duration (e.g. `1h 2min 3s`).
2569
+ * Implemented without `date-fns`.
2570
+ *
2571
+ * @example
2572
+ * formatSecondsToDuration(0) // => "0s"
2573
+ * formatSecondsToDuration(60) // => "1min 0s"
2574
+ * formatSecondsToDuration(3600) // => "1h 0min 0s"
2575
+ */
2576
+ function formatSecondsToDuration(totalSeconds) {
2577
+ const s = Math.max(0, Math.floor(totalSeconds));
2578
+ const days = Math.floor(s / 86400);
2579
+ const hours = Math.floor(s % 86400 / 3600);
2580
+ const minutes = Math.floor(s % 3600 / 60);
2581
+ const seconds = s % 60;
2582
+ if (days) return `${days}d ${hours}h ${minutes}min ${seconds}s`;
2583
+ if (hours) return `${hours}h ${minutes}min ${seconds}s`;
2584
+ if (minutes) return `${minutes}min ${seconds}s`;
2585
+ return `${seconds}s`;
2586
+ }
2587
+ /**
2588
+ * Format seconds as a zero-padded clock duration (`HH:MM` / `MM:SS`).
2589
+ * The full clock string is primary typography; the unit is appended separately.
2590
+ *
2591
+ * @example
2592
+ * formatSecondsToClock(75180, 'hours') // => { primary: "20:53", secondary: "" }
2593
+ * formatSecondsToClock(304, 'minutes') // => { primary: "05:04", secondary: "" }
2594
+ */
2595
+ function formatSecondsToClock(totalSeconds, scale) {
2596
+ const s = Math.max(0, Math.floor(totalSeconds));
2597
+ if (scale === "hours") {
2598
+ const hours = Math.floor(s / 3600);
2599
+ const minutes$1 = Math.floor(s % 3600 / 60);
2600
+ return {
2601
+ primary: `${String(hours).padStart(2, "0")}:${String(minutes$1).padStart(2, "0")}`,
2602
+ secondary: ""
2603
+ };
2604
+ }
2605
+ const minutes = Math.floor(s / 60);
2606
+ const seconds = s % 60;
2607
+ return {
2608
+ primary: `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`,
2609
+ secondary: ""
2610
+ };
2611
+ }
2612
+ /**
2613
+ * Format a KPI `value` for split typography display.
2614
+ * Returns `null` for empty / non-finite values (caller renders {@link KPI_EMPTY}).
2615
+ *
2616
+ * Contract:
2617
+ * - `string` is always opaque text (`kind` is ignored). Coerce at the call site
2618
+ * if the API sent a numeric string and you need `number` / `percent` / `duration`.
2619
+ * - `number` / `percent` / `duration` require a finite `number`.
2620
+ */
2621
+ function formatKpiValue(value, kind, locale, { formatOptions, durationStyle = "long", durationScale = "minutes" } = {}) {
2622
+ if (kind === "text" || typeof value === "string") {
2623
+ const text = String(value);
2624
+ if (text === "") return null;
2625
+ return {
2626
+ primary: text,
2627
+ secondary: ""
2628
+ };
2629
+ }
2630
+ if (!Number.isFinite(value)) return null;
2631
+ if (kind === "duration") {
2632
+ if (durationStyle === "clock") return formatSecondsToClock(value, durationScale);
2633
+ const formatted = formatSecondsToDuration(value);
2634
+ return splitLeadingDigits(formatted) ?? {
2635
+ primary: formatted,
2636
+ secondary: ""
2637
+ };
2638
+ }
2639
+ const options = kind === "percent" ? {
2640
+ style: "percent",
2641
+ maximumFractionDigits: 1,
2642
+ ...formatOptions
2643
+ } : {
2644
+ maximumFractionDigits: 1,
2645
+ minimumFractionDigits: 0,
2646
+ ...formatOptions
2647
+ };
2648
+ return splitFormattedNumber(new Intl.NumberFormat(locale, options).format(kind === "percent" ? value / 100 : value), locale);
2649
+ }
2650
+
2651
+ //#endregion
2652
+ //#region src/components/kpi.tsx
2653
+ const TREND_ICON = {
2654
+ up: ArrowUpRight,
2655
+ down: ArrowDownRight,
2656
+ neutral: Minus
2657
+ };
2658
+ const TONE_CLASS = {
2659
+ positive: "text-chart-1",
2660
+ negative: "text-destructive",
2661
+ neutral: "text-muted-foreground"
2662
+ };
2663
+ const KpiCardContext = React.createContext(null);
2664
+ function useKpiCardDisabled() {
2665
+ return React.useContext(KpiCardContext)?.disabled ?? false;
2666
+ }
2667
+ function resolveKind(value, kind) {
2668
+ if (typeof value === "string") return "text";
2669
+ if (kind) return kind;
2670
+ return "number";
2671
+ }
2672
+ function TrendGlyph({ trend, tone, className }) {
2673
+ const Icon = TREND_ICON[trend];
2674
+ return /* @__PURE__ */ jsx(Icon, {
2675
+ "aria-hidden": "true",
2676
+ className: cn("shrink-0", TONE_CLASS[tone], className)
2677
+ });
2678
+ }
2679
+ /**
2680
+ * KPI tile container. Thin wrapper around DS `Card` (`size="sm"` by default)
2681
+ * that provides a `disabled` context for nested {@link KpiValue}s.
2682
+ * When `disabled`, applies `opacity-50` and `cursor-not-allowed`, and blocks
2683
+ * activation of nested interactive values.
2684
+ * Compose with DS `CardHeader` / `CardTitle` / `CardContent` / `CardAction`,
2685
+ * {@link KpiValue}, and {@link KpiDescription}.
2686
+ *
2687
+ * @example
2688
+ * ```tsx
2689
+ * import { CardHeader, CardTitle, CardContent } from '@aircall/ds';
2690
+ * import { KpiCard, KpiValue, KpiDescription } from '@aircall/blocks';
2691
+ *
2692
+ * <KpiCard>
2693
+ * <CardHeader>
2694
+ * <CardTitle>Answered</CardTitle>
2695
+ * </CardHeader>
2696
+ * <CardContent className="flex flex-col gap-1">
2697
+ * <KpiValue value={123.1} kind="percent" trend="up" tone="positive" />
2698
+ * <KpiDescription trend="up" tone="positive">+2.48% vs previous period</KpiDescription>
2699
+ * </CardContent>
2700
+ * </KpiCard>
2701
+ * ```
2702
+ */
2703
+ const KpiCard = React.forwardRef((componentProps, forwardRef) => {
2704
+ const { className, size = "sm", disabled = false, children, ...props } = componentProps;
2705
+ return /* @__PURE__ */ jsx(KpiCardContext.Provider, {
2706
+ value: { disabled },
2707
+ children: /* @__PURE__ */ jsx(Card, {
2708
+ ref: forwardRef,
2709
+ "data-slot": "kpi-card",
2710
+ "data-disabled": disabled || void 0,
2711
+ "aria-disabled": disabled || void 0,
2712
+ size,
2713
+ className: cn("gap-2 data-[size=sm]:gap-2", disabled && "cursor-not-allowed opacity-50", className),
2714
+ ...props,
2715
+ children
2716
+ })
2717
+ });
2718
+ });
2719
+ KpiCard.displayName = "KpiCard";
2720
+ /**
2721
+ * KPI metric value. Formats via `useDsLocale` and renders primary (and optional
2722
+ * secondary) typography, with trend variants. Passing `onClick` makes the value
2723
+ * interactive (button + dotted underline). Prefer {@link KpiCard}`s `disabled`
2724
+ * for tile-level muting; a local `disabled` still works for standalone use.
2725
+ * Compose inside DS `CardContent` with {@link KpiDescription}.
2726
+ *
2727
+ * Prop naming: `kind` + `formatOptions` for formatting; `trend` is direction
2728
+ * (icon); `tone` is meaning (color) — "up" is not always good.
2729
+ *
2730
+ * @example
2731
+ * ```tsx
2732
+ * <KpiValue value={123.1} kind="percent" trend="up" tone="positive" />
2733
+ * ```
2734
+ */
2735
+ const KpiValue = React.forwardRef((componentProps, forwardRef) => {
2736
+ const { className, value, kind: kindProp, formatOptions, durationStyle = "long", durationScale = "minutes", unit, trend, tone = "neutral", active = false, disabled: disabledProp = false, children, onClick, render, ...props } = componentProps;
2737
+ const locale = useDsLocale();
2738
+ const cardDisabled = useKpiCardDisabled();
2739
+ const isDisabled = Boolean(disabledProp || cardDisabled);
2740
+ const isInteractive = typeof onClick === "function";
2741
+ const kind = resolveKind(value, kindProp);
2742
+ let content;
2743
+ const valueUnderlineClassName = cn(isInteractive && "border-b border-current", isInteractive && !active && "border-dotted", isInteractive && active && "border-solid");
2744
+ const trendGlyph = trend ? /* @__PURE__ */ jsx(TrendGlyph, {
2745
+ trend,
2746
+ tone: disabledProp && !cardDisabled ? "neutral" : tone,
2747
+ className: "size-6"
2748
+ }) : null;
2749
+ if (children != null) content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("span", {
2750
+ className: cn("inline-flex items-baseline gap-0.5", valueUnderlineClassName),
2751
+ children: [/* @__PURE__ */ jsx("span", {
2752
+ className: "text-3xl font-bold",
2753
+ children
2754
+ }), unit != null && unit !== "" && /* @__PURE__ */ jsx("span", {
2755
+ className: "pt-2 text-xl leading-none font-semibold",
2756
+ children: unit
2757
+ })]
2758
+ }), trendGlyph] });
2759
+ else {
2760
+ const formatted = value == null || typeof value === "number" && !Number.isFinite(value) ? null : formatKpiValue(value, kind, locale, {
2761
+ formatOptions,
2762
+ durationStyle,
2763
+ durationScale
2764
+ });
2765
+ const resolvedUnit = unit !== void 0 ? unit : kind === "duration" && durationStyle === "clock" ? clockDurationUnit(durationScale) : void 0;
2766
+ const unitNode = resolvedUnit != null && resolvedUnit !== "" ? resolvedUnit : null;
2767
+ if (!formatted) content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
2768
+ className: cn("text-3xl font-bold", valueUnderlineClassName),
2769
+ children: KPI_EMPTY
2770
+ }), trendGlyph] });
2771
+ else {
2772
+ const hasSecondary = formatted.secondary !== "" || unitNode != null;
2773
+ content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("span", {
2774
+ className: cn("inline-flex items-baseline gap-0.5", valueUnderlineClassName),
2775
+ children: [/* @__PURE__ */ jsx("span", {
2776
+ className: "text-3xl font-bold",
2777
+ children: formatted.primary
2778
+ }), hasSecondary && /* @__PURE__ */ jsxs("span", {
2779
+ className: "pt-2 text-xl leading-none font-semibold",
2780
+ children: [
2781
+ formatted.secondary,
2782
+ formatted.secondary !== "" && unitNode != null ? " " : null,
2783
+ unitNode
2784
+ ]
2785
+ })]
2786
+ }), trendGlyph] });
2787
+ }
2788
+ }
2789
+ const rootClassName = cn("inline-flex w-fit items-center gap-0.5 font-sans", disabledProp && !cardDisabled ? "text-muted-foreground" : active && isInteractive && !isDisabled ? "text-primary" : "text-foreground", isInteractive && !isDisabled && cn("cursor-pointer border-0 bg-transparent p-0 transition-colors active:opacity-60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50", active ? "hover:text-primary/80" : "hover:text-muted-foreground"), isInteractive && isDisabled && "cursor-not-allowed border-0 bg-transparent p-0", className);
2790
+ return useRender({
2791
+ defaultTagName: isInteractive ? "button" : "div",
2792
+ props: mergeProps({
2793
+ ref: forwardRef,
2794
+ className: rootClassName,
2795
+ children: content,
2796
+ ...isInteractive ? {
2797
+ type: "button",
2798
+ onClick,
2799
+ disabled: isDisabled,
2800
+ "aria-pressed": active
2801
+ } : isDisabled ? { "aria-disabled": true } : {}
2802
+ }, props),
2803
+ render,
2804
+ state: {
2805
+ slot: "kpi-value",
2806
+ active,
2807
+ disabled: isDisabled,
2808
+ interactive: isInteractive,
2809
+ trend,
2810
+ tone
2811
+ }
2812
+ });
2813
+ });
2814
+ KpiValue.displayName = "KpiValue";
2815
+ /**
2816
+ * Supporting comparison / context line under a {@link KpiValue}. Compose as a
2817
+ * sibling inside DS `CardContent` — not the metric title (`CardTitle` owns that).
2818
+ *
2819
+ * Text stays foreground; `trend` / `tone` only color the trailing icon so an
2820
+ * upward change that is bad uses `trend="up" tone="negative"`.
2821
+ *
2822
+ * @example
2823
+ * ```tsx
2824
+ * <KpiDescription trend="up" tone="positive">+2.48% vs previous period</KpiDescription>
2825
+ * <KpiDescription trend="up" tone="negative">+12% abandoned</KpiDescription>
2826
+ * ```
2827
+ */
2828
+ const KpiDescription = React.forwardRef(function KpiDescription(componentProps, forwardRef) {
2829
+ const { className, trend, tone = "neutral", children, ...props } = componentProps;
2830
+ return /* @__PURE__ */ jsxs("div", {
2831
+ ref: forwardRef,
2832
+ "data-slot": "kpi-description",
2833
+ "data-trend": trend,
2834
+ "data-tone": tone,
2835
+ className: cn("inline-flex items-center gap-0.5 font-sans text-xs font-medium text-foreground", className),
2836
+ ...props,
2837
+ children: [children, trend ? /* @__PURE__ */ jsx(TrendGlyph, {
2838
+ trend,
2839
+ tone,
2840
+ className: "size-3"
2841
+ }) : null]
2842
+ });
2843
+ });
2844
+ KpiDescription.displayName = "KpiDescription";
2845
+ /**
2846
+ * Loading placeholder sized for a {@link KpiValue} row. Thin wrapper around
2847
+ * DS `Skeleton` (`h-4 w-[45px]` with vertical margin to match the value row).
2848
+ * Swap in place of {@link KpiValue} while data loads.
2849
+ *
2850
+ * @example
2851
+ * ```tsx
2852
+ * <CardContent>
2853
+ * {loading ? <KpiValueSkeleton /> : <KpiValue value={123} />}
2854
+ * </CardContent>
2855
+ * ```
2856
+ */
2857
+ const KpiValueSkeleton = React.forwardRef((componentProps, forwardRef) => {
2858
+ const { className, ...props } = componentProps;
2859
+ return /* @__PURE__ */ jsx(Skeleton, {
2860
+ ref: forwardRef,
2861
+ "data-slot": "kpi-value-skeleton",
2862
+ className: cn("my-[9px] h-4 w-[45px]", className),
2863
+ ...props
2864
+ });
2865
+ });
2866
+ KpiValueSkeleton.displayName = "KpiValueSkeleton";
2867
+ /**
2868
+ * Loading placeholder sized for a {@link KpiDescription} row. Thin wrapper
2869
+ * around DS `Skeleton` (`12×144`, matching `text-xs` comparison copy).
2870
+ * Swap in place of {@link KpiDescription} while data loads.
2871
+ *
2872
+ * @example
2873
+ * ```tsx
2874
+ * <CardContent className="flex flex-col gap-1">
2875
+ * {loading ? (
2876
+ * <>
2877
+ * <KpiValueSkeleton />
2878
+ * <KpiDescriptionSkeleton />
2879
+ * </>
2880
+ * ) : (
2881
+ * <>
2882
+ * <KpiValue value={123} />
2883
+ * <KpiDescription>+2.48% vs previous period</KpiDescription>
2884
+ * </>
2885
+ * )}
2886
+ * </CardContent>
2887
+ * ```
2888
+ */
2889
+ const KpiDescriptionSkeleton = React.forwardRef((componentProps, forwardRef) => {
2890
+ const { className, ...props } = componentProps;
2891
+ return /* @__PURE__ */ jsx(Skeleton, {
2892
+ ref: forwardRef,
2893
+ "data-slot": "kpi-description-skeleton",
2894
+ className: cn("h-3 w-36", className),
2895
+ ...props
2896
+ });
2897
+ });
2898
+ KpiDescriptionSkeleton.displayName = "KpiDescriptionSkeleton";
2899
+
2197
2900
  //#endregion
2198
2901
  //#region src/components/sentiment-badge.tsx
2199
2902
  const SENTIMENT_BADGE = {
@@ -2275,6 +2978,20 @@ function ChatbotPanelTrigger({ children = "Ask anything", icon = /* @__PURE__ */
2275
2978
 
2276
2979
  //#endregion
2277
2980
  //#region src/components/chatbot-expand-suggestion.tsx
2981
+ /**
2982
+ * Displays category filter pills and a list of clickable suggestion rows for the
2983
+ * chatbot idle state. Renders a `<div>` wrapping an optional `ToggleGroup` of
2984
+ * category pills and a list of `Item` rows separated by `Separator`.
2985
+ *
2986
+ * @example
2987
+ * ```tsx
2988
+ * <ChatbotExpandSuggestion
2989
+ * categories={[{ value: 'billing', label: 'Billing' }]}
2990
+ * suggestions={[{ id: '1', text: 'How do I reset my password?' }]}
2991
+ * onSuggestionClick={suggestion => console.log(suggestion.text)}
2992
+ * />
2993
+ * ```
2994
+ */
2278
2995
  const ChatbotExpandSuggestion = React.forwardRef((componentProps, forwardRef) => {
2279
2996
  const { categories, selectedCategory: selectedCategoryProp, onCategoryChange, label = "Suggestions", suggestions, onSuggestionClick, className, ...props } = componentProps;
2280
2997
  const [selectedCategory, setSelectedCategory] = useControllableState({
@@ -2327,6 +3044,21 @@ const MAX_WIDTH = 768;
2327
3044
  const KEYBOARD_RESIZE_STEP = 16;
2328
3045
  const DISCLAIMER_LINK_HREF = "https://legal.aircall.io/#template-9jw4r0usl";
2329
3046
  const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
3047
+ /**
3048
+ * Presentational chatbot surface — header, scrollable conversation area (or a
3049
+ * built-in empty state), composer, and disclaimer — in a width-resizable shell.
3050
+ * Owns no visibility state (the consumer controls show/hide); pass the conversation
3051
+ * as `children`, and no children renders the empty state. Renders a `<div>`
3052
+ * container.
3053
+ *
3054
+ * @example
3055
+ * ```tsx
3056
+ * <ChatbotPanel onClose={close} onSubmit={send}>
3057
+ * <ChatbotUserMessage>Hi</ChatbotUserMessage>
3058
+ * <ChatbotResponseBlock>Hello!</ChatbotResponseBlock>
3059
+ * </ChatbotPanel>
3060
+ * ```
3061
+ */
2330
3062
  function ChatbotPanel({ title, onMenu, conversations, activeConversationId, onNewChat, onSelectConversation, renderConversationMenuContent, onExpand, onClose, emptyTitle, emptyDescription, suggestions = [], onSuggestionSelect, inputValue, onInputValueChange, onSubmit, onStop, loading = false, loadingText, placeholder, autoFocus, disclaimer, resizable = true, defaultWidth = DEFAULT_WIDTH, minWidth = MIN_WIDTH, maxWidth = MAX_WIDTH, onWidthChange, className, style, children, ...props }) {
2331
3063
  const t = useDsTranslation("blocks");
2332
3064
  const [menuOpen, setMenuOpen] = React.useState(false);
@@ -2538,9 +3270,49 @@ function ChatbotPanel({ title, onMenu, conversations, activeConversationId, onNe
2538
3270
  */
2539
3271
  const { fieldContext, formContext, useFieldContext, useFormContext } = createFormHookContexts();
2540
3272
 
3273
+ //#endregion
3274
+ //#region src/components/save-bar.tsx
3275
+ function SaveBar({ isDirty, isSubmitting, canSubmit, onReset, submitLabel = "Save changes", savingLabel = "Saving…", resetLabel = "Discard", className }) {
3276
+ return /* @__PURE__ */ jsx("div", {
3277
+ "data-slot": "card-footer",
3278
+ className: cn("grid transition-[grid-template-rows] duration-300 ease-in-out", isDirty ? "grid-rows-[1fr]" : "grid-rows-[0fr]", className),
3279
+ children: /* @__PURE__ */ jsx("div", {
3280
+ className: "overflow-hidden",
3281
+ children: /* @__PURE__ */ jsxs("div", {
3282
+ className: "flex items-center justify-end gap-2 border-t p-4",
3283
+ children: [/* @__PURE__ */ jsx(Button, {
3284
+ type: "button",
3285
+ variant: "ghost",
3286
+ onClick: onReset,
3287
+ disabled: !isDirty || isSubmitting,
3288
+ children: resetLabel
3289
+ }), /* @__PURE__ */ jsx(Button, {
3290
+ type: "submit",
3291
+ disabled: !isDirty || !canSubmit || isSubmitting,
3292
+ children: isSubmitting ? savingLabel : submitLabel
3293
+ })]
3294
+ })
3295
+ })
3296
+ });
3297
+ }
3298
+
2541
3299
  //#endregion
2542
3300
  //#region src/components/card-save-bar.tsx
2543
- function CardSaveBar({ submitLabel = "Save changes", savingLabel = "Saving…", resetLabel = "Discard" }) {
3301
+ /**
3302
+ * Save/discard bar for card-layout forms — the TanStack Form adapter around
3303
+ * `SaveBar`. Reads `isDirty`, `isSubmitting`, and `canSubmit` from form context
3304
+ * and renders `SaveBar` (which owns the animation, buttons, and the
3305
+ * `data-slot="card-footer"` that flushes it to the card edge).
3306
+ *
3307
+ * Must be placed **inside** the `<form>` element and wrapped by `form.AppForm`
3308
+ * (or any `formContext` provider).
3309
+ *
3310
+ * @example
3311
+ * <form.AppForm>
3312
+ * <form.CardSaveBar submitLabel="Save" resetLabel="Discard" />
3313
+ * </form.AppForm>
3314
+ */
3315
+ function CardSaveBar({ submitLabel, savingLabel, resetLabel }) {
2544
3316
  const form = useFormContext();
2545
3317
  return /* @__PURE__ */ jsx(form.Subscribe, {
2546
3318
  selector: (s) => ({
@@ -2548,31 +3320,34 @@ function CardSaveBar({ submitLabel = "Save changes", savingLabel = "Saving…",
2548
3320
  isSubmitting: s.isSubmitting,
2549
3321
  canSubmit: s.canSubmit
2550
3322
  }),
2551
- children: ({ isDirty, isSubmitting, canSubmit }) => /* @__PURE__ */ jsx("div", {
2552
- className: cn("grid transition-[grid-template-rows] duration-300 ease-in-out", isDirty ? "grid-rows-[1fr]" : "grid-rows-[0fr]"),
2553
- children: /* @__PURE__ */ jsx("div", {
2554
- className: "overflow-hidden",
2555
- children: /* @__PURE__ */ jsxs("div", {
2556
- className: "flex items-center justify-end gap-2 border-t px-6 py-3",
2557
- children: [/* @__PURE__ */ jsx(Button, {
2558
- type: "button",
2559
- variant: "ghost",
2560
- onClick: () => form.reset(),
2561
- disabled: !isDirty || isSubmitting,
2562
- children: resetLabel
2563
- }), /* @__PURE__ */ jsx(Button, {
2564
- type: "submit",
2565
- disabled: !isDirty || !canSubmit || isSubmitting,
2566
- children: isSubmitting ? savingLabel : submitLabel
2567
- })]
2568
- })
2569
- })
3323
+ children: ({ isDirty, isSubmitting, canSubmit }) => /* @__PURE__ */ jsx(SaveBar, {
3324
+ isDirty,
3325
+ isSubmitting,
3326
+ canSubmit,
3327
+ onReset: () => form.reset(),
3328
+ submitLabel,
3329
+ savingLabel,
3330
+ resetLabel
2570
3331
  })
2571
3332
  });
2572
3333
  }
2573
3334
 
2574
3335
  //#endregion
2575
3336
  //#region src/components/submit-button.tsx
3337
+ /**
3338
+ * Context-aware submit button. Disables itself when the form cannot be submitted or is submitting.
3339
+ * Shows `loadingLabel` (default `"Saving…"`) while submitting.
3340
+ *
3341
+ * Renders a DS `<Button type="submit">` (a `<button>` element).
3342
+ * Must be a descendant of `form.AppForm` (or any `formContext` provider).
3343
+ * Use for inline/flat layouts where `CardSaveBar` is not needed.
3344
+ * Accepts all `Button` props except `type` and `disabled` (managed internally).
3345
+ *
3346
+ * @example
3347
+ * <form.AppForm>
3348
+ * <form.SubmitButton loadingLabel="Saving…">Save</form.SubmitButton>
3349
+ * </form.AppForm>
3350
+ */
2576
3351
  function SubmitButton({ children = "Submit", loadingLabel, className, ...buttonProps }) {
2577
3352
  return /* @__PURE__ */ jsx(useFormContext().Subscribe, {
2578
3353
  selector: (s) => ({
@@ -2636,6 +3411,13 @@ function toFieldErrors(errors) {
2636
3411
 
2637
3412
  //#endregion
2638
3413
  //#region src/components/form-field.tsx
3414
+ /**
3415
+ * Internal layout shell shared by every `Form*Field` wrapper. Normalizes the
3416
+ * `label` / `description` props, lays out the `Field → label row → description →
3417
+ * control → error` skeleton per `orientation` / `controlVariant`, and applies the
3418
+ * error-display policy plus `data-invalid`. Reads the bound field from context,
3419
+ * so it must render inside `form.AppField`. Renders a DS `Field`.
3420
+ */
2639
3421
  function FormFieldShell({ label, description, necessityIndicator, id, children, orientation = "vertical", controlPosition = "end", controlVariant = "fill" }) {
2640
3422
  const errors = useFieldContext().state.meta.errors;
2641
3423
  const labelContent = typeof label === "string" ? label : label?.content;
@@ -3131,34 +3913,147 @@ function FormToggleGroupField(props) {
3131
3913
  }
3132
3914
 
3133
3915
  //#endregion
3134
- //#region src/components/save-bar.tsx
3135
- function SaveBar({ isDirty, isSubmitting, canSubmit, onReset, submitLabel = "Save changes", savingLabel = "Saving…", resetLabel = "Discard", className }) {
3136
- return /* @__PURE__ */ jsx("div", {
3137
- className: cn("grid transition-[grid-template-rows] duration-300 ease-in-out", isDirty ? "grid-rows-[1fr]" : "grid-rows-[0fr]", className),
3138
- children: /* @__PURE__ */ jsx("div", {
3139
- className: "overflow-hidden",
3140
- children: /* @__PURE__ */ jsxs("div", {
3141
- className: "flex items-center justify-end gap-2 border-t px-4 py-2",
3142
- children: [/* @__PURE__ */ jsx(Button, {
3143
- type: "button",
3144
- variant: "ghost",
3145
- size: "sm",
3146
- onClick: onReset,
3147
- disabled: !isDirty || isSubmitting,
3148
- children: resetLabel
3149
- }), /* @__PURE__ */ jsx(Button, {
3150
- type: "submit",
3151
- size: "sm",
3152
- disabled: !isDirty || !canSubmit || isSubmitting,
3153
- children: isSubmitting ? savingLabel : submitLabel
3154
- })]
3155
- })
3156
- })
3916
+ //#region src/components/setting-card.tsx
3917
+ /**
3918
+ * Root container for a setting card. Renders the DS `Card`.
3919
+ *
3920
+ * By default the level (and therefore the background) is detected automatically:
3921
+ * a top-level card is level 1 (muted background, borderless); a card nested
3922
+ * inside another card's `SettingCardContent` becomes level 2 (white background,
3923
+ * border). Pass `level` to force a specific level — needed for the rare third
3924
+ * nesting level, which reuses the level-1 look (`level={1}`).
3925
+ *
3926
+ * @example
3927
+ * ```tsx
3928
+ * <SettingCard>
3929
+ * <SettingCardHeader>
3930
+ * <SettingCardTitle>Call recording</SettingCardTitle>
3931
+ * <SettingCardDescription>Record inbound and outbound calls.</SettingCardDescription>
3932
+ * <SettingCardAction>
3933
+ * <Switch checked={enabled} onCheckedChange={setEnabled} />
3934
+ * </SettingCardAction>
3935
+ * </SettingCardHeader>
3936
+ * {enabled && <SettingCardContent>…</SettingCardContent>}
3937
+ * </SettingCard>
3938
+ * ```
3939
+ *
3940
+ * @example
3941
+ * ```tsx
3942
+ * // With a save/discard bar: put the form on the OUTER level and drop
3943
+ * // `form.CardSaveBar` in as the last child. It reads dirty/submitting/canSubmit
3944
+ * // from form context, slides in when dirty, and carries `data-slot="card-footer"`
3945
+ * // so the card flushes it to the edge automatically. No `className` needed.
3946
+ * <form onSubmit={e => { e.preventDefault(); void form.handleSubmit(); }}>
3947
+ * <SettingCard>
3948
+ * <SettingCardHeader>
3949
+ * <SettingCardTitle>Profile</SettingCardTitle>
3950
+ * <SettingCardDescription>Update your display name.</SettingCardDescription>
3951
+ * </SettingCardHeader>
3952
+ * <SettingCardContent>…</SettingCardContent>
3953
+ * <form.AppForm>
3954
+ * <form.CardSaveBar resetLabel="Undo" />
3955
+ * </form.AppForm>
3956
+ * </SettingCard>
3957
+ * </form>
3958
+ * ```
3959
+ */
3960
+ const SettingCard = React.forwardRef((componentProps, forwardRef) => {
3961
+ const { className, level, ...props } = componentProps;
3962
+ const isAuto = level === void 0;
3963
+ return /* @__PURE__ */ jsx(Card, {
3964
+ ref: forwardRef,
3965
+ "data-level": level,
3966
+ className: cn(isAuto && "bg-accent border-transparent [[data-setting-card-content]_&]:border-border [[data-setting-card-content]_&]:bg-card", level === 1 && "bg-accent border-transparent", level === 2 && "border-border bg-card", className),
3967
+ ...props
3157
3968
  });
3158
- }
3969
+ });
3970
+ SettingCard.displayName = "SettingCard";
3971
+ /**
3972
+ * Header row of a setting card. Wraps DS `CardHeader`, which lays out the
3973
+ * title/description on the left and the `SettingCardAction` on the right.
3974
+ */
3975
+ const SettingCardHeader = React.forwardRef((componentProps, forwardRef) => /* @__PURE__ */ jsx(CardHeader, {
3976
+ ref: forwardRef,
3977
+ ...componentProps
3978
+ }));
3979
+ SettingCardHeader.displayName = "SettingCardHeader";
3980
+ /**
3981
+ * Title of a setting card. Wraps DS `CardTitle`, overriding its type ramp so
3982
+ * weight and size follow the card's level (auto-detected from nesting, like the
3983
+ * background): level 1 is 18px bold, level 2 (nested) is 16px medium. A forced
3984
+ * level-1 card that is still nested (the rare 3rd level) keeps the 16px-medium
3985
+ * title, matching the design guidance for that case.
3986
+ */
3987
+ const SettingCardTitle = React.forwardRef((componentProps, forwardRef) => {
3988
+ const { className, ...props } = componentProps;
3989
+ return /* @__PURE__ */ jsx(CardTitle, {
3990
+ ref: forwardRef,
3991
+ "data-slot": "setting-card-title",
3992
+ className: cn("text-lg font-bold", "[[data-setting-card-content]_&]:text-base [[data-setting-card-content]_&]:font-medium", className),
3993
+ ...props
3994
+ });
3995
+ });
3996
+ SettingCardTitle.displayName = "SettingCardTitle";
3997
+ /**
3998
+ * Supporting description under the title. Wraps DS `CardDescription` (14px muted).
3999
+ * Inline links (e.g. "Learn more") can be placed inside its children.
4000
+ */
4001
+ const SettingCardDescription = React.forwardRef((componentProps, forwardRef) => /* @__PURE__ */ jsx(CardDescription, {
4002
+ ref: forwardRef,
4003
+ ...componentProps
4004
+ }));
4005
+ SettingCardDescription.displayName = "SettingCardDescription";
4006
+ /**
4007
+ * Top-right control slot of the header — holds a single control, either a
4008
+ * `<Switch>` (toggle card) or a `<Button>` (action card). Wraps DS `CardAction`.
4009
+ * The two never co-occur, so this is one slot, not two.
4010
+ */
4011
+ const SettingCardAction = React.forwardRef((componentProps, forwardRef) => /* @__PURE__ */ jsx(CardAction, {
4012
+ ref: forwardRef,
4013
+ ...componentProps
4014
+ }));
4015
+ SettingCardAction.displayName = "SettingCardAction";
4016
+ /**
4017
+ * Body of a setting card. Wraps DS `CardContent` and carries the
4018
+ * `data-setting-card-content` marker that drives nesting detection: any
4019
+ * `SettingCard` rendered inside here auto-detects level 2.
4020
+ *
4021
+ * For progressive disclosure, render this conditionally — mount it only when
4022
+ * the header's toggle is on — so gated fields never mount while disabled.
4023
+ */
4024
+ const SettingCardContent = React.forwardRef((componentProps, forwardRef) => {
4025
+ const { className, ...props } = componentProps;
4026
+ return /* @__PURE__ */ jsx(CardContent, {
4027
+ ref: forwardRef,
4028
+ "data-setting-card-content": "",
4029
+ className: cn("flex flex-col gap-4", className),
4030
+ ...props
4031
+ });
4032
+ });
4033
+ SettingCardContent.displayName = "SettingCardContent";
3159
4034
 
3160
4035
  //#endregion
3161
4036
  //#region src/components/dashboard-sidebar.tsx
4037
+ /**
4038
+ * Context provider and flex-row layout wrapping the sidebar and page content;
4039
+ * renders a ds `SidebarProvider`. Provides the state consumed by `useDashboardSidebar`.
4040
+ *
4041
+ * @example
4042
+ * ```tsx
4043
+ * <DashboardSidebarProvider>
4044
+ * <DashboardSidebar>
4045
+ * <DashboardSidebarContent>
4046
+ * <DashboardSidebarMenu>
4047
+ * <DashboardSidebarMenuItem>
4048
+ * <DashboardSidebarMenuButton icon={<Home />}>Home</DashboardSidebarMenuButton>
4049
+ * </DashboardSidebarMenuItem>
4050
+ * </DashboardSidebarMenu>
4051
+ * </DashboardSidebarContent>
4052
+ * </DashboardSidebar>
4053
+ * <DashboardPageContent>…</DashboardPageContent>
4054
+ * </DashboardSidebarProvider>
4055
+ * ```
4056
+ */
3162
4057
  const DashboardSidebarProvider = React.forwardRef((componentProps, forwardRef) => {
3163
4058
  const { className, style, ...props } = componentProps;
3164
4059
  return /* @__PURE__ */ jsx(SidebarProvider, {
@@ -3173,6 +4068,10 @@ const DashboardSidebarProvider = React.forwardRef((componentProps, forwardRef) =
3173
4068
  });
3174
4069
  });
3175
4070
  DashboardSidebarProvider.displayName = "DashboardSidebarProvider";
4071
+ /**
4072
+ * Root sidebar column that grows/shrinks with the collapse state; renders a `<div>`.
4073
+ * Holds `DashboardSidebarHeader`, `DashboardSidebarContent`, and `DashboardSidebarFooter`.
4074
+ */
3176
4075
  const DashboardSidebar = React.forwardRef((componentProps, forwardRef) => {
3177
4076
  const { className, children, ...props } = componentProps;
3178
4077
  const { state } = useSidebar();
@@ -3187,6 +4086,9 @@ const DashboardSidebar = React.forwardRef((componentProps, forwardRef) => {
3187
4086
  });
3188
4087
  });
3189
4088
  DashboardSidebar.displayName = "DashboardSidebar";
4089
+ /**
4090
+ * Top bar of the sidebar that houses the collapse toggle; renders a `<div>`.
4091
+ */
3190
4092
  const DashboardSidebarHeader = React.forwardRef((componentProps, forwardRef) => {
3191
4093
  const { className, children, ...props } = componentProps;
3192
4094
  return /* @__PURE__ */ jsx("div", {
@@ -3198,6 +4100,10 @@ const DashboardSidebarHeader = React.forwardRef((componentProps, forwardRef) =>
3198
4100
  });
3199
4101
  });
3200
4102
  DashboardSidebarHeader.displayName = "DashboardSidebarHeader";
4103
+ /**
4104
+ * Collapse/expand toggle rendering a ghost, icon ds `Button`; renders a `<button>`.
4105
+ * Swaps its icon and aria-label based on the sidebar state.
4106
+ */
3201
4107
  const DashboardSidebarTrigger = React.forwardRef((componentProps, forwardRef) => {
3202
4108
  const { className, onClick, ...props } = componentProps;
3203
4109
  const { toggleSidebar, state } = useSidebar();
@@ -3217,6 +4123,9 @@ const DashboardSidebarTrigger = React.forwardRef((componentProps, forwardRef) =>
3217
4123
  });
3218
4124
  });
3219
4125
  DashboardSidebarTrigger.displayName = "DashboardSidebarTrigger";
4126
+ /**
4127
+ * Scrollable middle section of the sidebar (scrollbar hidden); renders a `<div>`.
4128
+ */
3220
4129
  const DashboardSidebarContent = React.forwardRef((componentProps, forwardRef) => {
3221
4130
  const { className, ...props } = componentProps;
3222
4131
  return /* @__PURE__ */ jsx("div", {
@@ -3227,6 +4136,9 @@ const DashboardSidebarContent = React.forwardRef((componentProps, forwardRef) =>
3227
4136
  });
3228
4137
  });
3229
4138
  DashboardSidebarContent.displayName = "DashboardSidebarContent";
4139
+ /**
4140
+ * Frosted-glass bottom section of the sidebar; renders a `<div>`.
4141
+ */
3230
4142
  const DashboardSidebarFooter = React.forwardRef((componentProps, forwardRef) => {
3231
4143
  const { className, ...props } = componentProps;
3232
4144
  return /* @__PURE__ */ jsx("div", {
@@ -3237,6 +4149,9 @@ const DashboardSidebarFooter = React.forwardRef((componentProps, forwardRef) =>
3237
4149
  });
3238
4150
  });
3239
4151
  DashboardSidebarFooter.displayName = "DashboardSidebarFooter";
4152
+ /**
4153
+ * Groups a set of menu items (optionally labelled); renders a `<div>`.
4154
+ */
3240
4155
  const DashboardSidebarGroup = React.forwardRef((componentProps, forwardRef) => {
3241
4156
  const { className, ...props } = componentProps;
3242
4157
  return /* @__PURE__ */ jsx("div", {
@@ -3247,6 +4162,10 @@ const DashboardSidebarGroup = React.forwardRef((componentProps, forwardRef) => {
3247
4162
  });
3248
4163
  });
3249
4164
  DashboardSidebarGroup.displayName = "DashboardSidebarGroup";
4165
+ /**
4166
+ * Section heading for a group, hidden when the sidebar is collapsed; renders a `<div>`
4167
+ * by default, overridable via the `render` prop.
4168
+ */
3250
4169
  const DashboardSidebarGroupLabel = React.forwardRef((componentProps, forwardRef) => {
3251
4170
  const { className, render, ...props } = componentProps;
3252
4171
  return useRender({
@@ -3260,6 +4179,9 @@ const DashboardSidebarGroupLabel = React.forwardRef((componentProps, forwardRef)
3260
4179
  });
3261
4180
  });
3262
4181
  DashboardSidebarGroupLabel.displayName = "DashboardSidebarGroupLabel";
4182
+ /**
4183
+ * List container for menu items; renders a `<ul>`.
4184
+ */
3263
4185
  const DashboardSidebarMenu = React.forwardRef((componentProps, forwardRef) => {
3264
4186
  const { className, ...props } = componentProps;
3265
4187
  return /* @__PURE__ */ jsx("ul", {
@@ -3270,6 +4192,9 @@ const DashboardSidebarMenu = React.forwardRef((componentProps, forwardRef) => {
3270
4192
  });
3271
4193
  });
3272
4194
  DashboardSidebarMenu.displayName = "DashboardSidebarMenu";
4195
+ /**
4196
+ * Wrapper for a single menu row; renders a `<li>` (relative, for badge positioning).
4197
+ */
3273
4198
  const DashboardSidebarMenuItem = React.forwardRef((componentProps, forwardRef) => {
3274
4199
  const { className, ...props } = componentProps;
3275
4200
  return /* @__PURE__ */ jsx("li", {
@@ -3280,6 +4205,10 @@ const DashboardSidebarMenuItem = React.forwardRef((componentProps, forwardRef) =
3280
4205
  });
3281
4206
  });
3282
4207
  DashboardSidebarMenuItem.displayName = "DashboardSidebarMenuItem";
4208
+ /**
4209
+ * Pill-shaped navigation item with a leading icon circle and optional trailing action;
4210
+ * renders a `<button>` by default, overridable via the `render` prop (e.g. a router `<Link>`).
4211
+ */
3283
4212
  const DashboardSidebarMenuButton = React.forwardRef((componentProps, forwardRef) => {
3284
4213
  const { className, render, isActive = false, disabled = false, icon, action, children, ...props } = componentProps;
3285
4214
  const buttonContent = /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -3313,6 +4242,9 @@ const DashboardSidebarMenuButton = React.forwardRef((componentProps, forwardRef)
3313
4242
  });
3314
4243
  });
3315
4244
  DashboardSidebarMenuButton.displayName = "DashboardSidebarMenuButton";
4245
+ /**
4246
+ * Right-aligned slot (ml-auto) for trailing content inside a menu row; renders a `<div>`.
4247
+ */
3316
4248
  const DashboardSidebarMenuAddon = React.forwardRef((componentProps, forwardRef) => {
3317
4249
  const { className, ...props } = componentProps;
3318
4250
  return /* @__PURE__ */ jsx("div", {
@@ -3323,6 +4255,11 @@ const DashboardSidebarMenuAddon = React.forwardRef((componentProps, forwardRef)
3323
4255
  });
3324
4256
  });
3325
4257
  DashboardSidebarMenuAddon.displayName = "DashboardSidebarMenuAddon";
4258
+ /**
4259
+ * Notification count badge for a menu item; renders a ds `CounterBadge` positioned
4260
+ * absolutely at the row's right edge (moves to the icon corner when collapsed).
4261
+ * Place it inside `DashboardSidebarMenuItem`, as a sibling of the button.
4262
+ */
3326
4263
  const DashboardSidebarMenuBadge = React.forwardRef((componentProps, forwardRef) => {
3327
4264
  const { className, ...props } = componentProps;
3328
4265
  return /* @__PURE__ */ jsx(CounterBadge, {
@@ -3333,6 +4270,10 @@ const DashboardSidebarMenuBadge = React.forwardRef((componentProps, forwardRef)
3333
4270
  });
3334
4271
  });
3335
4272
  DashboardSidebarMenuBadge.displayName = "DashboardSidebarMenuBadge";
4273
+ /**
4274
+ * Popover-style panel (white card with border and shadow) opening beside a trigger;
4275
+ * renders a `<div>`. Hosts `DashboardSidebarSubmenuItem` and `DashboardSidebarSubmenuSeparator`.
4276
+ */
3336
4277
  const DashboardSidebarSubmenu = React.forwardRef((componentProps, forwardRef) => {
3337
4278
  const { className, ...props } = componentProps;
3338
4279
  return /* @__PURE__ */ jsx("div", {
@@ -3343,6 +4284,10 @@ const DashboardSidebarSubmenu = React.forwardRef((componentProps, forwardRef) =>
3343
4284
  });
3344
4285
  });
3345
4286
  DashboardSidebarSubmenu.displayName = "DashboardSidebarSubmenu";
4287
+ /**
4288
+ * One row inside a submenu; renders a `<div>` by default, overridable via the `render`
4289
+ * prop (e.g. an `<a>` or router `<Link>` for navigation).
4290
+ */
3346
4291
  const DashboardSidebarSubmenuItem = React.forwardRef((componentProps, forwardRef) => {
3347
4292
  const { className, render, isActive = false, ...props } = componentProps;
3348
4293
  return useRender({
@@ -3359,6 +4304,9 @@ const DashboardSidebarSubmenuItem = React.forwardRef((componentProps, forwardRef
3359
4304
  });
3360
4305
  });
3361
4306
  DashboardSidebarSubmenuItem.displayName = "DashboardSidebarSubmenuItem";
4307
+ /**
4308
+ * Thin horizontal divider between submenu items; renders a `<div>`.
4309
+ */
3362
4310
  const DashboardSidebarSubmenuSeparator = React.forwardRef((componentProps, forwardRef) => {
3363
4311
  const { className } = componentProps;
3364
4312
  return /* @__PURE__ */ jsx("div", {
@@ -3455,6 +4403,20 @@ function NavItem({ item, renderLink }) {
3455
4403
  })] }), countBadge] });
3456
4404
  return /* @__PURE__ */ jsxs(DashboardSidebarMenuItem, { children: [React.cloneElement(buttonEl, {}, item.label, trailing), countBadge] });
3457
4405
  }
4406
+ /**
4407
+ * Data-driven sidebar navigation. Maps a `groups` array into the
4408
+ * `DashboardSidebar` primitives, rendering each item as a link, a dropdown
4409
+ * submenu, or an action button (with optional badges, counts, and tooltips).
4410
+ *
4411
+ * Renders a fragment of `DashboardSidebarGroup` sections — it has no wrapper
4412
+ * element of its own, so place it inside a `DashboardSidebarContent`.
4413
+ *
4414
+ * @example
4415
+ * <DashboardSidebarNav
4416
+ * groups={groups}
4417
+ * renderLink={href => <Link to={href} />}
4418
+ * />
4419
+ */
3458
4420
  function DashboardSidebarNav({ groups, renderLink }) {
3459
4421
  return /* @__PURE__ */ jsx(Fragment, { children: groups.map((group) => /* @__PURE__ */ jsxs(DashboardSidebarGroup, { children: [group.label && /* @__PURE__ */ jsx(DashboardSidebarGroupLabel, { children: group.label }), /* @__PURE__ */ jsx(DashboardSidebarMenu, { children: group.items.map((item) => /* @__PURE__ */ jsx(NavItem, {
3460
4422
  item,
@@ -3463,4 +4425,4 @@ function DashboardSidebarNav({ groups, renderLink }) {
3463
4425
  }
3464
4426
 
3465
4427
  //#endregion
3466
- export { BetaBadge, CardSaveBar, ChatbotExpandSuggestion, ChatbotInput, ChatbotPage, ChatbotPageBody, ChatbotPageContent, ChatbotPageConversation, ChatbotPageFooter, ChatbotPageHeading, ChatbotPageInputBar, ChatbotPanel, ChatbotPanelHeader, ChatbotPanelSuggestion, ChatbotPanelTrigger, ChatbotResponseBlock, ChatbotResponseLoading, 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, DashboardStandalonePageDescription, DashboardStandalonePageHeader, DashboardStandalonePageMain, DashboardStandalonePageTitle, DeprecatedBadge, EmptyState, EmptyStateActions, EmptyStateButton, EmptyStateDescription, EmptyStateExternalLink, EmptyStateHeader, EmptyStateMedia, EmptyStateTitle, FormArrayField, FormComboboxField, FormFieldBase, FormFieldShell, FormInputField, FormMultiComboboxField, FormNumericField, FormOTPField, FormRadioGroupField, FormSelectField, FormSliderField, FormSwitchField, FormTextareaField, FormToggleGroupField, NewBadge, NoDataDescription, NoDataEmptyState, NoDataMedia, NoDataTitle, NoSupportDescription, NoSupportEmptyState, NoSupportMedia, NoSupportTitle, NotFoundDescription, NotFoundEmptyState, NotFoundMedia, NotFoundTitle, PERCENTAGE_THRESHOLDS, ProfessionalBadge, RestrictedAccessDescription, RestrictedAccessEmptyState, RestrictedAccessMedia, RestrictedAccessTitle, RoleBadge, SaveBar, ScoreBadge, SentimentBadge, SubmitButton, TrialBadge, UnknownErrorDescription, UnknownErrorEmptyState, UnknownErrorMedia, UnknownErrorTitle, fieldContext, formContext, toFieldErrors, useCopyToClipboard, useSidebar as useDashboardSidebar, useFieldContext, useForm, useFormContext, withFieldGroup, withForm };
4428
+ export { BetaBadge, CardSaveBar, ChatbotExpandSuggestion, ChatbotInput, ChatbotPage, ChatbotPageBody, ChatbotPageContent, ChatbotPageConversation, ChatbotPageFooter, ChatbotPageHeading, ChatbotPageInputBar, ChatbotPanel, ChatbotPanelHeader, ChatbotPanelSuggestion, ChatbotPanelTrigger, ChatbotResponseBlock, ChatbotResponseLoading, 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, DashboardStandalonePageDescription, DashboardStandalonePageHeader, DashboardStandalonePageMain, DashboardStandalonePageTitle, DeprecatedBadge, EmptyState, EmptyStateActions, EmptyStateButton, EmptyStateDescription, EmptyStateExternalLink, EmptyStateHeader, EmptyStateMedia, EmptyStateTitle, FormArrayField, FormComboboxField, FormFieldBase, FormFieldShell, FormInputField, FormMultiComboboxField, FormNumericField, FormOTPField, FormRadioGroupField, FormSelectField, FormSliderField, FormSwitchField, FormTextareaField, FormToggleGroupField, KpiCard, KpiDescription, KpiDescriptionSkeleton, KpiValue, KpiValueSkeleton, NewBadge, NoDataDescription, NoDataEmptyState, NoDataMedia, NoDataTitle, NoSupportDescription, NoSupportEmptyState, NoSupportMedia, NoSupportTitle, NotFoundDescription, NotFoundEmptyState, NotFoundMedia, NotFoundTitle, PERCENTAGE_THRESHOLDS, ProfessionalBadge, RestrictedAccessDescription, RestrictedAccessEmptyState, RestrictedAccessMedia, RestrictedAccessTitle, RoleBadge, SaveBar, ScoreBadge, SentimentBadge, SettingCard, SettingCardAction, SettingCardContent, SettingCardDescription, SettingCardHeader, SettingCardTitle, SubmitButton, TrialBadge, UnknownErrorDescription, UnknownErrorEmptyState, UnknownErrorMedia, UnknownErrorTitle, fieldContext, formContext, toFieldErrors, useCopyToClipboard, useSidebar as useDashboardSidebar, useFieldContext, useForm, useFormContext, withFieldGroup, withForm };