@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/globals.css +1 -1
- package/dist/index.d.ts +862 -18
- package/dist/index.js +1044 -82
- package/package.json +2 -2
- package/skills/aircall-blocks/migrate-dashboard/SKILL.md +20 -3
- package/skills/aircall-blocks/migrate-dashboard/card/SKILL.md +43 -71
- package/skills/aircall-blocks/migrate-dashboard/catch-up-checklist/SKILL.md +109 -0
- package/skills/aircall-blocks/migrate-dashboard/combobox/SKILL.md +0 -1
- package/skills/aircall-blocks/migrate-dashboard/copy-button/SKILL.md +0 -1
- package/skills/aircall-blocks/migrate-dashboard/dashboard-page/SKILL.md +39 -1
- package/skills/aircall-blocks/migrate-dashboard/data-table/SKILL.md +10 -1
- package/skills/aircall-blocks/migrate-dashboard/empty-states/SKILL.md +0 -1
- package/skills/aircall-blocks/migrate-dashboard/form-wizard/SKILL.md +40 -1
- package/skills/aircall-blocks/migrate-dashboard/info-popup/SKILL.md +0 -1
- package/skills/aircall-blocks/migrate-dashboard/layout/SKILL.md +0 -1
- package/skills/aircall-blocks/migrate-dashboard/list/SKILL.md +0 -1
- package/skills/aircall-blocks/migrate-dashboard/loading/SKILL.md +0 -1
- package/skills/aircall-blocks/migrate-dashboard/page-header/SKILL.md +0 -1
- package/skills/aircall-blocks/migrate-dashboard/setting-card/SKILL.md +258 -0
- package/skills/aircall-blocks/migrate-dashboard/tile/SKILL.md +211 -161
- package/skills/aircall-blocks/migrate-dashboard/toggle-row/SKILL.md +0 -1
- package/skills/aircall-blocks/setup/SKILL.md +22 -1
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
|
-
*
|
|
457
|
-
* available.
|
|
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
|
-
|
|
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(
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
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/
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
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 };
|