@gntik-ai/blocks 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/index.d.ts +202 -74
  2. package/dist/index.js +849 -283
  3. package/dist/index.js.map +1 -1
  4. package/package.json +2 -2
  5. package/src/feedback/ConfirmDestructive/ConfirmDestructive.examples.test.tsx +25 -0
  6. package/src/feedback/ConfirmDestructive/ConfirmDestructive.extended.test.tsx +252 -0
  7. package/src/feedback/ConfirmDestructive/ConfirmDestructive.focus.test.tsx +178 -0
  8. package/src/feedback/ConfirmDestructive/ConfirmDestructive.tsx +219 -28
  9. package/src/feedback/ConfirmDestructive/block.meta.ts +2 -2
  10. package/src/feedback/ConfirmDestructive/examples/FailureStates.tsx +39 -0
  11. package/src/feedback/ConfirmDestructive/examples/PlainDeletion.tsx +6 -0
  12. package/src/feedback/ConfirmDestructive/examples/SecretRevocation.tsx +34 -0
  13. package/src/feedback/EmptyStates/EmptyStates.test.tsx +11 -1
  14. package/src/feedback/EmptyStates/EmptyStates.tsx +31 -1
  15. package/src/feedback/EmptyStates/block.meta.ts +1 -1
  16. package/src/feedback/EmptyStates/fixtures.ts +5 -0
  17. package/src/feedback/ErrorPanel/ErrorPanel.test.tsx +7 -0
  18. package/src/feedback/ErrorPanel/ErrorPanel.tsx +8 -3
  19. package/src/forms/CredentialDisclosureDialog/CredentialDisclosureDialog.additional.test.tsx +467 -0
  20. package/src/forms/CredentialDisclosureDialog/CredentialDisclosureDialog.tsx +175 -106
  21. package/src/forms/CredentialDisclosureDialog/IssueOnClick.test.tsx +56 -0
  22. package/src/forms/CredentialDisclosureDialog/SecretCopy.tsx +83 -0
  23. package/src/forms/CredentialDisclosureDialog/block.meta.ts +1 -1
  24. package/src/forms/CredentialDisclosureDialog/examples/Inline.tsx +19 -0
  25. package/src/forms/CredentialDisclosureDialog/examples/IssueOnClick.tsx +87 -0
  26. package/src/forms/CredentialDisclosureDialog/examples/MultiSecret.tsx +29 -0
  27. package/src/forms/CredentialDisclosureDialog/focus.ts +18 -0
  28. package/src/forms/CredentialDisclosureDialog/types.ts +5 -0
  29. package/src/tables/CursorPagerFooter/CursorPagerFooter.examples.test.tsx +33 -0
  30. package/src/tables/CursorPagerFooter/CursorPagerFooter.test.tsx +51 -0
  31. package/src/tables/CursorPagerFooter/CursorPagerFooter.tsx +10 -0
  32. package/src/tables/CursorPagerFooter/block.meta.ts +23 -0
  33. package/src/tables/CursorPagerFooter/examples/Busy.tsx +7 -0
  34. package/src/tables/CursorPagerFooter/examples/CursorStack.tsx +40 -0
  35. package/src/tables/CursorPagerFooter/examples/Hidden.tsx +16 -0
  36. package/src/tables/CursorPagerFooter/examples/RowsPerPage.tsx +21 -0
  37. package/src/tables/CursorPagerFooter/fixtures.ts +13 -0
  38. package/src/tables/DataTable/DataTable.server-pagination.test.tsx +173 -0
  39. package/src/tables/DataTable/DataTable.tsx +20 -12
  40. package/src/tables/DataTable/block.meta.ts +2 -1
  41. package/src/tables/DataTable/data-table-props.ts +27 -4
  42. package/src/tables/DataTable/examples/server-pagination.tsx +68 -0
  43. package/src/tables/LoadMoreFooter/LoadMoreFooter.announcements.test.tsx +106 -0
  44. package/src/tables/LoadMoreFooter/LoadMoreFooter.examples.test.tsx +36 -0
  45. package/src/tables/LoadMoreFooter/LoadMoreFooter.labels.test.tsx +71 -0
  46. package/src/tables/LoadMoreFooter/LoadMoreFooter.test.tsx +184 -0
  47. package/src/tables/LoadMoreFooter/LoadMoreFooter.tsx +151 -0
  48. package/src/tables/LoadMoreFooter/block.meta.ts +28 -0
  49. package/src/tables/LoadMoreFooter/examples/cards.tsx +22 -0
  50. package/src/tables/LoadMoreFooter/examples/cursor.tsx +25 -0
  51. package/src/tables/LoadMoreFooter/examples/exhausted.tsx +6 -0
  52. package/src/tables/LoadMoreFooter/examples/failed.tsx +13 -0
  53. package/src/tables/LoadMoreFooter/examples/flag.tsx +33 -0
  54. package/src/tables/LoadMoreFooter/examples/useMockCursor.ts +30 -0
  55. package/src/tables/LoadMoreFooter/fixtures.ts +9 -0
  56. package/src/tables/LoadMoreFooter/useLoadMoreFooter.ts +56 -0
  57. package/src/tables/index.ts +4 -0
  58. package/src/test/CredentialDisclosureDialog.compatibility.tsx +30 -0
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use client';
2
- import { Fragment, createElement, useCallback, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
2
+ import { Fragment, createElement, useCallback, useEffect, useEffectEvent, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
3
3
  import { Activity, Archive, ArrowDown, ArrowLeft, ArrowRight, ArrowUp, BarChart3, Bookmark, Bot, Boxes, Braces, Building2, CalendarCheck, CalendarDays, Camera, Check, ChevronDown, ChevronLeft, ChevronRight, ChevronsUpDown, CircleAlert, CircleCheck, CircleHelp, CircleX, Clock, Cog, Columns3, Copy, CreditCard, Database, Download, ExternalLink, Eye, FileCode, FileText, FolderKanban, FolderPlus, Gauge, GitBranch, Globe, HardDrive, Home, Inbox, Info, KeyRound, Layers, LayoutGrid, List, ListFilter, Lock, LogOut, Mail, MailCheck, MapPin, Minus, Monitor, MousePointerClick, Pencil, Play, PlugZap, Plus, RefreshCw, Rocket, RotateCcw, RotateCw, Rows2, Rows3, Search, SearchX, Server, ServerCrash, Settings, ShieldCheck, SlidersHorizontal, Smartphone, Sparkles, Table2, Tablet, Trash2, TriangleAlert, Upload, User, UserMinus, UserPlus, Users, Workflow, Wrench, X, Zap } from "@gntik-ai/icons";
4
- import { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, Alert, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, Avatar, Badge, Breadcrumbs, Button, Card, CardAction, CardBody, CardDescription, CardHeader, CardTitle, Checkbox, CheckboxGroup, ClickableCard, CodeBlock, Collapsible, CollapsiblePanel, CollapsibleTrigger, CommandPalette, CommandPaletteTrigger, CopyButton, DEFAULT_DATE_RANGE_PRESETS, DateRangePicker, DensityProvider, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, EmptyState, Field, FieldDescription, FieldError, FieldLabel, Fieldset, FieldsetLegend, IconButton, Input, Link, LiveAnnouncer, Logo, Menu, MenuCheckboxItem, MenuContent, MenuGroup, MenuGroupLabel, MenuItem, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuSub, MenuSubContent, MenuSubTrigger, MenuTrigger, Meter, MoreMenu, NavList, NotificationsPopover, OtpInput, Pagination, PasswordInput, Progress, Radio, RadioGroup, ResizablePanel, ResizablePanelGroup, ResizeHandle, SecretField, Select, SelectContent, SelectItem, SelectTrigger, SimpleSelect, Skeleton, Slider, Sparkline, Spinner, StatusDot, StatusTag, Switch, Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsList, TabsPanel, TabsTab, Textarea, ThemeCycleButton, ThemeSwitcher, Timestamp, Toggle, ToggleGroup, Token, TokenInput, Toolbar, ToolbarButton, ToolbarEnd, ToolbarInput, ToolbarSeparator, ToolbarStart, UserMenu, WizardLayout, WorkspaceSwitcher, buttonVariants, cn, nextSortDirection, tableVariants, toDate, useDensity, useI18n } from "@gntik-ai/ui";
4
+ import { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, Alert, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, Avatar, Badge, Breadcrumbs, Button, Card, CardAction, CardBody, CardDescription, CardHeader, CardTitle, Checkbox, CheckboxGroup, ClickableCard, CodeBlock, Collapsible, CollapsiblePanel, CollapsibleTrigger, CommandPalette, CommandPaletteTrigger, CopyButton, CursorPagination, DEFAULT_DATE_RANGE_PRESETS, DateRangePicker, DensityProvider, Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, EmptyState, Field, FieldDescription, FieldError, FieldLabel, Fieldset, FieldsetLegend, IconButton, Input, Link, LiveAnnouncer, Logo, Menu, MenuCheckboxItem, MenuContent, MenuGroup, MenuGroupLabel, MenuItem, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuSub, MenuSubContent, MenuSubTrigger, MenuTrigger, Meter, MoreMenu, NavList, NotificationsPopover, OtpInput, Pagination, PasswordInput, Progress, Radio, RadioGroup, ResizablePanel, ResizablePanelGroup, ResizeHandle, SecretField, Select, SelectContent, SelectItem, SelectTrigger, SimpleSelect, Skeleton, Slider, Sparkline, Spinner, StatusDot, StatusTag, Switch, Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow, Tabs, TabsList, TabsPanel, TabsTab, Textarea, ThemeCycleButton, ThemeSwitcher, Timestamp, Toggle, ToggleGroup, Token, TokenInput, Toolbar, ToolbarButton, ToolbarEnd, ToolbarInput, ToolbarSeparator, ToolbarStart, UserMenu, WizardLayout, WorkspaceSwitcher, buttonVariants, cn, nextSortDirection, tableVariants, toDate, useAnnounce, useDensity, useHasLiveAnnouncer, useI18n } from "@gntik-ai/ui";
5
5
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
6
6
  import { AreaChart, BarChart, CHART_COLORS, DonutChart, Heatmap, LineChart, chartFmt } from "@gntik-ai/charts";
7
7
  import { FLOW_TONES, FlowCanvas, KIND_CHIP, KindGlyph, useFlowState } from "@gntik-ai/flow";
@@ -628,7 +628,7 @@ function TraceWaterfall({ spans = traceSpans, title = "Trace", selectedId: selec
628
628
  }
629
629
  //#endregion
630
630
  //#region src/ai/TraceWaterfall/block.meta.ts
631
- const meta$71 = {
631
+ const meta$73 = {
632
632
  name: "Trace waterfall",
633
633
  family: "ai",
634
634
  status: "beta",
@@ -763,7 +763,7 @@ function TokenCostCard({ periods = tokenUsagePeriods, defaultPeriod, currency =
763
763
  }
764
764
  //#endregion
765
765
  //#region src/ai/TokenCostCard/block.meta.ts
766
- const meta$70 = {
766
+ const meta$72 = {
767
767
  name: "Token cost card",
768
768
  family: "ai",
769
769
  status: "beta",
@@ -976,7 +976,7 @@ function PromptEditor({ title = "Prompt", defaultSystem = promptDefaults.system,
976
976
  }
977
977
  //#endregion
978
978
  //#region src/ai/PromptEditor/block.meta.ts
979
- const meta$52 = {
979
+ const meta$54 = {
980
980
  name: "Prompt editor",
981
981
  family: "ai",
982
982
  status: "beta",
@@ -1355,7 +1355,7 @@ function EvaluationScorecard({ metrics = evalMetrics, rows = evalRows, title = "
1355
1355
  }
1356
1356
  //#endregion
1357
1357
  //#region src/ai/EvaluationScorecard/block.meta.ts
1358
- const meta$22 = {
1358
+ const meta$23 = {
1359
1359
  name: "Evaluation scorecard",
1360
1360
  family: "ai",
1361
1361
  status: "beta",
@@ -1586,7 +1586,7 @@ function ModelKeysList({ keys = modelKeys, title = "Model provider keys", onTest
1586
1586
  }
1587
1587
  //#endregion
1588
1588
  //#region src/ai/ModelKeysList/block.meta.ts
1589
- const meta$40 = {
1589
+ const meta$42 = {
1590
1590
  name: "Model keys list",
1591
1591
  family: "ai",
1592
1592
  status: "beta",
@@ -1844,7 +1844,7 @@ function ForgotPasswordForm({ identifier, messages, ref, fieldInvalid, feedbackI
1844
1844
  }
1845
1845
  //#endregion
1846
1846
  //#region src/auth/ForgotPasswordForm/block.meta.ts
1847
- const meta$28 = {
1847
+ const meta$29 = {
1848
1848
  name: "Forgot password form",
1849
1849
  family: "auth",
1850
1850
  status: "stable",
@@ -2008,7 +2008,7 @@ function MfaChallenge({ onVerify, onResend, resendCooldown = 30, initialCooldown
2008
2008
  }
2009
2009
  //#endregion
2010
2010
  //#region src/auth/MfaChallenge/block.meta.ts
2011
- const meta$39 = {
2011
+ const meta$41 = {
2012
2012
  name: "MFA challenge",
2013
2013
  family: "auth",
2014
2014
  status: "stable",
@@ -2135,7 +2135,7 @@ function ResetPasswordForm({ onSubmit, error: errorProp, minPasswordLength = 8,
2135
2135
  }
2136
2136
  //#endregion
2137
2137
  //#region src/auth/ResetPasswordForm/block.meta.ts
2138
- const meta$54 = {
2138
+ const meta$56 = {
2139
2139
  name: "Reset password form",
2140
2140
  family: "auth",
2141
2141
  status: "stable",
@@ -2337,7 +2337,7 @@ function SignInForm({ identifier, messages, passwordHelp, passwordHelpId, ref, f
2337
2337
  }
2338
2338
  //#endregion
2339
2339
  //#region src/auth/SignInForm/block.meta.ts
2340
- const meta$59 = {
2340
+ const meta$61 = {
2341
2341
  name: "Sign-in form",
2342
2342
  family: "auth",
2343
2343
  status: "stable",
@@ -2681,7 +2681,7 @@ function SignUpForm({ fields, messages, unavailable, policyLoading = false, onSu
2681
2681
  }
2682
2682
  //#endregion
2683
2683
  //#region src/auth/SignUpForm/block.meta.ts
2684
- const meta$60 = {
2684
+ const meta$62 = {
2685
2685
  name: "Sign-up form",
2686
2686
  family: "auth",
2687
2687
  status: "stable",
@@ -2702,7 +2702,7 @@ const meta$60 = {
2702
2702
  };
2703
2703
  //#endregion
2704
2704
  //#region src/auth/SsoButtons/block.meta.ts
2705
- const meta$63 = {
2705
+ const meta$65 = {
2706
2706
  name: "SSO buttons",
2707
2707
  family: "auth",
2708
2708
  status: "stable",
@@ -2999,7 +2999,7 @@ const documentation$1 = {
2999
2999
  "summary-actions-only"
3000
3000
  ]
3001
3001
  };
3002
- const meta$48 = {
3002
+ const meta$50 = {
3003
3003
  name: "Plan card",
3004
3004
  family: "billing",
3005
3005
  status: "beta",
@@ -3157,7 +3157,7 @@ const documentation = {
3157
3157
  ],
3158
3158
  examples: ["compact", "full"]
3159
3159
  };
3160
- const meta$49 = {
3160
+ const meta$51 = {
3161
3161
  name: "Plan definition card",
3162
3162
  family: "billing",
3163
3163
  status: "beta",
@@ -3271,7 +3271,7 @@ function QuotaMeters({ quotas = sampleQuotas, title = "Plan usage", thresholds,
3271
3271
  }
3272
3272
  //#endregion
3273
3273
  //#region src/billing/QuotaMeters/block.meta.ts
3274
- const meta$53 = {
3274
+ const meta$55 = {
3275
3275
  name: "Quota meters",
3276
3276
  family: "billing",
3277
3277
  status: "beta",
@@ -3386,7 +3386,7 @@ function SpendVsBudget({ data = sampleSpend, budget = sampleBudget, currency = "
3386
3386
  }
3387
3387
  //#endregion
3388
3388
  //#region src/billing/SpendVsBudget/block.meta.ts
3389
- const meta$62 = {
3389
+ const meta$64 = {
3390
3390
  name: "Spend vs budget",
3391
3391
  family: "billing",
3392
3392
  status: "beta",
@@ -3546,7 +3546,7 @@ function InvoiceTable({ invoices = sampleInvoices, caption = "Invoice history",
3546
3546
  }
3547
3547
  //#endregion
3548
3548
  //#region src/billing/InvoiceTable/block.meta.ts
3549
- const meta$35 = {
3549
+ const meta$36 = {
3550
3550
  name: "Invoice table",
3551
3551
  family: "billing",
3552
3552
  status: "beta",
@@ -3662,7 +3662,7 @@ function PaymentMethodCard({ method = samplePaymentMethod, title = "Payment meth
3662
3662
  }
3663
3663
  //#endregion
3664
3664
  //#region src/billing/PaymentMethodCard/block.meta.ts
3665
- const meta$46 = {
3665
+ const meta$48 = {
3666
3666
  name: "Payment method card",
3667
3667
  family: "billing",
3668
3668
  status: "beta",
@@ -4574,7 +4574,7 @@ function FlowBuilder({ title = "Untitled flow", nodes: initialNodes = builderNod
4574
4574
  }
4575
4575
  //#endregion
4576
4576
  //#region src/builders/FlowBuilder/block.meta.ts
4577
- const meta$27 = {
4577
+ const meta$28 = {
4578
4578
  name: "Flow builder",
4579
4579
  family: "builders",
4580
4580
  status: "beta",
@@ -5336,7 +5336,7 @@ function LogViewer({ lines = logLines, title = "Logs", height = 360, rowHeight =
5336
5336
  }
5337
5337
  //#endregion
5338
5338
  //#region src/builders/LogViewer/block.meta.ts
5339
- const meta$37 = {
5339
+ const meta$39 = {
5340
5340
  name: "Log viewer",
5341
5341
  family: "builders",
5342
5342
  status: "beta",
@@ -5554,7 +5554,7 @@ function KpiRow({ items = KPI_ITEMS, variant = "cards", showTrends = true, label
5554
5554
  }
5555
5555
  //#endregion
5556
5556
  //#region src/data-display/KpiRow/block.meta.ts
5557
- const meta$36 = {
5557
+ const meta$37 = {
5558
5558
  name: "KPI row",
5559
5559
  family: "data-display",
5560
5560
  status: "beta",
@@ -5728,7 +5728,7 @@ function StatCard({ label = "Requests", icon: IconCmp = Activity, ranges = STAT_
5728
5728
  }
5729
5729
  //#endregion
5730
5730
  //#region src/data-display/StatCard/block.meta.ts
5731
- const meta$64 = {
5731
+ const meta$66 = {
5732
5732
  name: "Stat card",
5733
5733
  family: "data-display",
5734
5734
  status: "beta",
@@ -6145,7 +6145,7 @@ function DescriptionListCard({ title = "Configuration", description = "Settings
6145
6145
  }
6146
6146
  //#endregion
6147
6147
  //#region src/data-display/DescriptionListCard/block.meta.ts
6148
- const meta$17 = {
6148
+ const meta$18 = {
6149
6149
  name: "Description list card",
6150
6150
  family: "data-display",
6151
6151
  status: "beta",
@@ -6341,7 +6341,7 @@ function ResourceCardGrid({ items = RESOURCE_CARDS, label = "Resources", onActio
6341
6341
  }
6342
6342
  //#endregion
6343
6343
  //#region src/data-display/ResourceCardGrid/block.meta.ts
6344
- const meta$55 = {
6344
+ const meta$57 = {
6345
6345
  name: "Resource card grid",
6346
6346
  family: "data-display",
6347
6347
  status: "beta",
@@ -6502,7 +6502,7 @@ function StatusTimeline({ events = DEPLOYMENT_EVENTS, label: labelProp, emptyLab
6502
6502
  }
6503
6503
  //#endregion
6504
6504
  //#region src/data-display/StatusTimeline/block.meta.ts
6505
- const meta$65 = {
6505
+ const meta$67 = {
6506
6506
  name: "Status timeline",
6507
6507
  family: "data-display",
6508
6508
  status: "beta",
@@ -6904,7 +6904,7 @@ function SystemBanner({ kind = "maintenance", title = "Scheduled maintenance.",
6904
6904
  }
6905
6905
  //#endregion
6906
6906
  //#region src/feedback/SystemBanner/block.meta.ts
6907
- const meta$68 = {
6907
+ const meta$70 = {
6908
6908
  name: "System banner",
6909
6909
  family: "feedback",
6910
6910
  status: "beta",
@@ -6950,7 +6950,7 @@ function InlineCallout({ tone = "warning", title = "You have used 92% of your bu
6950
6950
  }
6951
6951
  //#endregion
6952
6952
  //#region src/feedback/InlineCallout/block.meta.ts
6953
- const meta$32 = {
6953
+ const meta$33 = {
6954
6954
  name: "Inline callout",
6955
6955
  family: "feedback",
6956
6956
  status: "beta",
@@ -6978,8 +6978,24 @@ const noAccessSample = {
6978
6978
  resource: "Billing",
6979
6979
  owner: "an organization admin"
6980
6980
  };
6981
+ const notFoundSample = {
6982
+ title: "Resource not found",
6983
+ description: "This resource may have been deleted or moved."
6984
+ };
6981
6985
  //#endregion
6982
6986
  //#region src/feedback/EmptyStates/EmptyStates.tsx
6987
+ /** Missing resource state; consumers may supply an optional way back. */
6988
+ function NotFoundEmpty({ icon = SearchX, title = notFoundSample.title, description = notFoundSample.description, action, titleAs, bordered = true, className }) {
6989
+ return /* @__PURE__ */ jsx(EmptyState, {
6990
+ icon,
6991
+ title,
6992
+ description,
6993
+ primaryAction: action,
6994
+ titleAs,
6995
+ bordered,
6996
+ className: cn("mx-auto", className)
6997
+ });
6998
+ }
6983
6999
  /** First-run state: nothing created yet; explains the value and offers the first action. */
6984
7000
  function FirstRunEmpty({ icon = FolderPlus, title = "Create your first project", description = "Projects group your services, environments and deployments. Start one from a repository in a couple of minutes.", actionLabel = "New project", onAction, secondary = {
6985
7001
  label: "Read the guide",
@@ -7084,11 +7100,11 @@ function NoAccessEmpty({ resource = noAccessSample.resource, owner = noAccessSam
7084
7100
  }
7085
7101
  //#endregion
7086
7102
  //#region src/feedback/EmptyStates/block.meta.ts
7087
- const meta$19 = {
7103
+ const meta$20 = {
7088
7104
  name: "Empty states",
7089
7105
  family: "feedback",
7090
7106
  status: "beta",
7091
- description: "Three canonical empty states: first run (with checklist), no results (clear filters/search) and no access (request access).",
7107
+ description: "Four canonical empty states: first run (with checklist), no results (clear filters/search), no access (request access) and not found (optional action).",
7092
7108
  uses: [
7093
7109
  "EmptyState",
7094
7110
  "Button",
@@ -7232,7 +7248,7 @@ function PageSkeleton({ stats = 4, rows = 5, label: labelProp, className }) {
7232
7248
  }
7233
7249
  //#endregion
7234
7250
  //#region src/feedback/Skeletons/block.meta.ts
7235
- const meta$61 = {
7251
+ const meta$63 = {
7236
7252
  name: "Skeletons",
7237
7253
  family: "feedback",
7238
7254
  status: "beta",
@@ -7240,132 +7256,12 @@ const meta$61 = {
7240
7256
  uses: ["Skeleton"]
7241
7257
  };
7242
7258
  //#endregion
7243
- //#region src/feedback/ConfirmDestructive/ConfirmDestructive.tsx
7244
- /**
7245
- * Typed-confirmation for irreversible actions: an AlertDialog whose destructive button stays
7246
- * disabled until the resource name is typed exactly.
7247
- */
7248
- function ConfirmDestructive({ resourceName = "acme-web", resourceType = "project", title, description, consequences = [
7249
- "All deployments and preview URLs",
7250
- "Environment variables and secrets",
7251
- "The audit log for this project"
7252
- ], confirmLabel, triggerLabel, open, defaultOpen = false, onOpenChange, onConfirm }) {
7253
- const [innerOpen, setInnerOpen] = useState(defaultOpen);
7254
- const [typed, setTyped] = useState("");
7255
- const [pending, setPending] = useState(false);
7256
- const [error, setError] = useState(null);
7257
- const isOpen = open ?? innerOpen;
7258
- const label = confirmLabel ?? `Delete ${resourceType}`;
7259
- const matches = typed === resourceName;
7260
- const setOpen = (next) => {
7261
- if (!next) {
7262
- setTyped("");
7263
- setError(null);
7264
- }
7265
- setInnerOpen(next);
7266
- onOpenChange?.(next);
7267
- };
7268
- const confirm = async (event) => {
7269
- event.preventDefault();
7270
- if (!matches || pending) return;
7271
- setPending(true);
7272
- setError(null);
7273
- try {
7274
- await onConfirm?.();
7275
- setPending(false);
7276
- setOpen(false);
7277
- } catch (err) {
7278
- setPending(false);
7279
- setError(err instanceof Error ? err.message : "Something went wrong. Try again.");
7280
- }
7281
- };
7282
- return /* @__PURE__ */ jsxs(AlertDialog, {
7283
- open: isOpen,
7284
- onOpenChange: (next) => !pending && setOpen(next),
7285
- children: [triggerLabel !== null && /* @__PURE__ */ jsx(AlertDialogTrigger, {
7286
- render: /* @__PURE__ */ jsx(Button, {
7287
- variant: "destructive",
7288
- icon: Trash2
7289
- }),
7290
- children: triggerLabel ?? label
7291
- }), /* @__PURE__ */ jsxs(AlertDialogContent, { children: [
7292
- /* @__PURE__ */ jsxs(AlertDialogHeader, {
7293
- tone: "destructive",
7294
- children: [/* @__PURE__ */ jsx(AlertDialogTitle, { children: title ?? `Delete ${resourceType}?` }), /* @__PURE__ */ jsx(AlertDialogDescription, { children: description ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
7295
- "This permanently deletes ",
7296
- /* @__PURE__ */ jsx("span", {
7297
- className: "font-mono text-foreground",
7298
- children: resourceName
7299
- }),
7300
- ". This action cannot be undone."
7301
- ] }) })]
7302
- }),
7303
- consequences.length > 0 && /* @__PURE__ */ jsx("ul", {
7304
- className: "mt-4 list-disc space-y-1 rounded-md border border-destructive/25 bg-destructive/5 py-2.5 pe-3 ps-8 text-[12.5px] text-muted-foreground",
7305
- children: consequences.map((c) => /* @__PURE__ */ jsx("li", { children: c }, c))
7306
- }),
7307
- /* @__PURE__ */ jsxs("form", {
7308
- onSubmit: (e) => void confirm(e),
7309
- className: "mt-4",
7310
- children: [
7311
- /* @__PURE__ */ jsxs(Field, { children: [/* @__PURE__ */ jsxs(FieldLabel, { children: [
7312
- "Type ",
7313
- /* @__PURE__ */ jsx("span", {
7314
- className: "font-mono font-semibold text-foreground",
7315
- children: resourceName
7316
- }),
7317
- " to confirm"
7318
- ] }), /* @__PURE__ */ jsx(Input, {
7319
- value: typed,
7320
- onChange: (e) => setTyped(e.target.value),
7321
- autoComplete: "off",
7322
- spellCheck: false,
7323
- disabled: pending
7324
- })] }),
7325
- error && /* @__PURE__ */ jsx("p", {
7326
- role: "alert",
7327
- className: "mt-2 text-[12.5px] text-destructive-text",
7328
- children: error
7329
- }),
7330
- /* @__PURE__ */ jsxs(AlertDialogFooter, {
7331
- className: "mt-5",
7332
- children: [/* @__PURE__ */ jsx(AlertDialogCancel, {
7333
- disabled: pending,
7334
- children: "Cancel"
7335
- }), /* @__PURE__ */ jsx(Button, {
7336
- type: "submit",
7337
- variant: "destructive",
7338
- loading: pending,
7339
- disabled: !matches,
7340
- children: label
7341
- })]
7342
- })
7343
- ]
7344
- })
7345
- ] })]
7346
- });
7347
- }
7348
- //#endregion
7349
- //#region src/feedback/ConfirmDestructive/block.meta.ts
7350
- const meta$10 = {
7351
- name: "Confirm destructive",
7352
- family: "feedback",
7353
- status: "beta",
7354
- description: "AlertDialog for irreversible actions that requires typing the resource name, with async confirm and error display.",
7355
- uses: [
7356
- "AlertDialog",
7357
- "Button",
7358
- "Field",
7359
- "Input"
7360
- ]
7361
- };
7362
- //#endregion
7363
7259
  //#region src/feedback/ErrorPanel/ErrorPanel.tsx
7364
7260
  /** Error summary for a failed load or action: what happened, request id, retry and technical details. */
7365
7261
  function ErrorPanel({ icon: Icon = ServerCrash, title = "We couldn’t load deployments", message = "The service didn’t respond in time. Your data is safe; try again in a moment.", code = 503, requestId = "req_8f2c41d07a9b", details = "GET /v1/projects/acme-web/deployments\n503 Service Unavailable\nupstream timed out after 30000 ms (pool: api-eu-west-1)", onRetry, retrying, retryLabel: retryLabelProp, secondaryAction = {
7366
7262
  label: "Contact support",
7367
7263
  variant: "ghost"
7368
- }, titleAs: Heading = "h3", className }) {
7264
+ }, titleAs: Heading = "h3", className, announce = true }) {
7369
7265
  const { t } = useI18n();
7370
7266
  const retryLabel = retryLabelProp ?? t("error.retry");
7371
7267
  const id = useId();
@@ -7468,7 +7364,7 @@ function ErrorPanel({ icon: Icon = ServerCrash, title = "We couldn’t load depl
7468
7364
  children: details
7469
7365
  }) })]
7470
7366
  }),
7471
- /* @__PURE__ */ jsx("p", {
7367
+ announce && /* @__PURE__ */ jsx("p", {
7472
7368
  role: "status",
7473
7369
  className: "sr-only",
7474
7370
  children: busy ? t("error.retryingStatus") : copied ? t("error.requestIdCopied") : ""
@@ -7479,8 +7375,271 @@ function ErrorPanel({ icon: Icon = ServerCrash, title = "We couldn’t load depl
7479
7375
  });
7480
7376
  }
7481
7377
  //#endregion
7378
+ //#region src/feedback/ConfirmDestructive/ConfirmDestructive.tsx
7379
+ function normalizeFailure(value) {
7380
+ if (!value || typeof value !== "object" || !("kind" in value) || !("title" in value)) return null;
7381
+ if (typeof value.title !== "string" || !value.title.trim()) return null;
7382
+ const title = value.title;
7383
+ const message = "message" in value && typeof value.message === "string" ? value.message : void 0;
7384
+ if (value.kind === "server") return {
7385
+ kind: "server",
7386
+ title,
7387
+ message,
7388
+ status: "status" in value && typeof value.status === "number" && Number.isFinite(value.status) ? value.status : void 0,
7389
+ requestId: "requestId" in value && typeof value.requestId === "string" ? value.requestId : void 0
7390
+ };
7391
+ if (value.kind === "network") return {
7392
+ kind: "network",
7393
+ title,
7394
+ message
7395
+ };
7396
+ if (value.kind === "no-access" || value.kind === "not-found") return {
7397
+ kind: value.kind,
7398
+ title,
7399
+ description: "description" in value && typeof value.description === "string" ? value.description : void 0
7400
+ };
7401
+ return null;
7402
+ }
7403
+ /**
7404
+ * Typed-confirmation for irreversible actions: an AlertDialog whose destructive button stays
7405
+ * disabled until the resource name is typed exactly.
7406
+ */
7407
+ function ConfirmDestructive({ resourceName = "acme-web", resourceType = "project", title, description, consequences = [
7408
+ "All deployments and preview URLs",
7409
+ "Environment variables and secrets",
7410
+ "The audit log for this project"
7411
+ ], confirmLabel, triggerLabel, open, defaultOpen = false, onOpenChange, onConfirm, children, canConfirm = true, returnFocusRef }) {
7412
+ const { t } = useI18n();
7413
+ const [innerOpen, setInnerOpen] = useState(defaultOpen);
7414
+ const [typed, setTyped] = useState("");
7415
+ const [pending, setPending] = useState(false);
7416
+ const pendingRef = useRef(false);
7417
+ const inputRef = useRef(null);
7418
+ const popupRef = useRef(null);
7419
+ const panelRef = useRef(null);
7420
+ const cancelRef = useRef(null);
7421
+ const closeRef = useRef(null);
7422
+ const focusedControl = useRef(null);
7423
+ const triggerRef = useRef(null);
7424
+ const previousFocus = useRef(null);
7425
+ const [error, setError] = useState(null);
7426
+ const [announcementId, setAnnouncementId] = useState(0);
7427
+ const [failure, setFailure] = useState(null);
7428
+ const isOpen = open ?? innerOpen;
7429
+ const [previousOpen, setPreviousOpen] = useState(isOpen);
7430
+ const session = useRef(0);
7431
+ if (previousOpen !== isOpen) {
7432
+ setPreviousOpen(isOpen);
7433
+ if (!isOpen) {
7434
+ setTyped("");
7435
+ setError(null);
7436
+ setFailure(null);
7437
+ setPending(false);
7438
+ }
7439
+ }
7440
+ useLayoutEffect(() => {
7441
+ session.current = session.current + 1;
7442
+ pendingRef.current = false;
7443
+ focusedControl.current = null;
7444
+ if (isOpen && document.activeElement instanceof HTMLElement) previousFocus.current = document.activeElement;
7445
+ return () => {
7446
+ session.current++;
7447
+ };
7448
+ }, [isOpen]);
7449
+ const label = confirmLabel ?? `Delete ${resourceType}`;
7450
+ const matches = typed === resourceName;
7451
+ const terminal = failure?.kind === "no-access" || failure?.kind === "not-found" ? failure : null;
7452
+ useLayoutEffect(() => {
7453
+ if (!isOpen || !popupRef.current) return;
7454
+ const popup = popupRef.current;
7455
+ const available = (element, keepLoading = false) => element?.isConnected && popup.contains(element) && !element.closest("[hidden], [inert], [aria-hidden=\"true\"]") && (!element.matches(":disabled, [aria-disabled=\"true\"]") || keepLoading && element.getAttribute("aria-busy") === "true");
7456
+ const restore = () => {
7457
+ if (!focusedControl.current || available(focusedControl.current, true)) return;
7458
+ const retry = panelRef.current?.querySelectorAll("button");
7459
+ [
7460
+ retry?.item(retry.length - 1) ?? null,
7461
+ inputRef.current,
7462
+ cancelRef.current,
7463
+ closeRef.current
7464
+ ].find((element) => available(element))?.focus();
7465
+ };
7466
+ restore();
7467
+ const observer = new MutationObserver(restore);
7468
+ observer.observe(popup, {
7469
+ childList: true,
7470
+ subtree: true,
7471
+ attributes: true,
7472
+ attributeFilter: [
7473
+ "disabled",
7474
+ "aria-disabled",
7475
+ "hidden",
7476
+ "inert",
7477
+ "aria-hidden"
7478
+ ]
7479
+ });
7480
+ return () => observer.disconnect();
7481
+ });
7482
+ const setOpen = (next) => {
7483
+ if (!next) {
7484
+ session.current++;
7485
+ pendingRef.current = false;
7486
+ setPending(false);
7487
+ setTyped("");
7488
+ setError(null);
7489
+ setFailure(null);
7490
+ }
7491
+ setInnerOpen(next);
7492
+ onOpenChange?.(next);
7493
+ };
7494
+ const confirm = async () => {
7495
+ if (!isOpen || !matches || canConfirm === false || pendingRef.current || terminal) return;
7496
+ const attemptSession = session.current;
7497
+ pendingRef.current = true;
7498
+ setPending(true);
7499
+ setError(null);
7500
+ try {
7501
+ await onConfirm?.();
7502
+ if (session.current !== attemptSession) return;
7503
+ pendingRef.current = false;
7504
+ setPending(false);
7505
+ setOpen(false);
7506
+ } catch (err) {
7507
+ if (session.current !== attemptSession) return;
7508
+ pendingRef.current = false;
7509
+ setPending(false);
7510
+ const next = normalizeFailure(err);
7511
+ setAnnouncementId((id) => id + 1);
7512
+ setFailure(next);
7513
+ setError(next ? [next.title, "message" in next ? next.message : "description" in next ? next.description : void 0].filter(Boolean).join(" ") : err instanceof Error ? err.message : "Something went wrong. Try again.");
7514
+ }
7515
+ };
7516
+ return /* @__PURE__ */ jsxs(AlertDialog, {
7517
+ open: isOpen,
7518
+ onOpenChange: (next) => !pending && setOpen(next),
7519
+ children: [triggerLabel !== null && /* @__PURE__ */ jsx(AlertDialogTrigger, {
7520
+ ref: triggerRef,
7521
+ render: /* @__PURE__ */ jsx(Button, {
7522
+ variant: "destructive",
7523
+ icon: Trash2
7524
+ }),
7525
+ children: triggerLabel ?? label
7526
+ }), /* @__PURE__ */ jsxs(AlertDialogContent, {
7527
+ ref: popupRef,
7528
+ initialFocus: inputRef,
7529
+ finalFocus: () => triggerRef.current ?? returnFocusRef?.current ?? previousFocus.current ?? true,
7530
+ onFocusCapture: (event) => {
7531
+ if (event.target !== event.currentTarget) focusedControl.current = event.target;
7532
+ },
7533
+ children: [
7534
+ /* @__PURE__ */ jsxs(AlertDialogHeader, {
7535
+ tone: "destructive",
7536
+ children: [/* @__PURE__ */ jsx(AlertDialogTitle, { children: title ?? `Delete ${resourceType}?` }), /* @__PURE__ */ jsx(AlertDialogDescription, { children: description ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
7537
+ "This permanently deletes ",
7538
+ /* @__PURE__ */ jsx("span", {
7539
+ className: "font-mono text-foreground",
7540
+ children: resourceName
7541
+ }),
7542
+ ". This action cannot be undone."
7543
+ ] }) })]
7544
+ }),
7545
+ !terminal && consequences.length > 0 && /* @__PURE__ */ jsx("ul", {
7546
+ className: "mt-4 list-disc space-y-1 rounded-md border border-destructive/25 bg-destructive/5 py-2.5 pe-3 ps-8 text-[12.5px] text-muted-foreground",
7547
+ children: consequences.map((c) => /* @__PURE__ */ jsx("li", { children: c }, c))
7548
+ }),
7549
+ /* @__PURE__ */ jsxs("form", {
7550
+ onSubmit: (e) => {
7551
+ e.preventDefault();
7552
+ confirm();
7553
+ },
7554
+ className: "mt-4",
7555
+ children: [
7556
+ terminal ? terminal.kind === "no-access" ? /* @__PURE__ */ jsx(EmptyState, {
7557
+ icon: Lock,
7558
+ title: terminal.title,
7559
+ description: terminal.description ?? null
7560
+ }) : /* @__PURE__ */ jsx(NotFoundEmpty, {
7561
+ title: terminal.title,
7562
+ description: terminal.description ?? null
7563
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
7564
+ children,
7565
+ /* @__PURE__ */ jsxs(Field, { children: [/* @__PURE__ */ jsxs(FieldLabel, { children: [
7566
+ "Type ",
7567
+ /* @__PURE__ */ jsx("span", {
7568
+ className: "font-mono font-semibold text-foreground",
7569
+ children: resourceName
7570
+ }),
7571
+ " to confirm"
7572
+ ] }), /* @__PURE__ */ jsx(Input, {
7573
+ ref: inputRef,
7574
+ value: typed,
7575
+ onChange: (e) => setTyped(e.target.value),
7576
+ autoComplete: "off",
7577
+ spellCheck: false,
7578
+ readOnly: pending
7579
+ })] }),
7580
+ (failure?.kind === "server" || failure?.kind === "network") && /* @__PURE__ */ jsx("div", {
7581
+ ref: panelRef,
7582
+ children: /* @__PURE__ */ jsx(ErrorPanel, {
7583
+ title: failure.title,
7584
+ message: failure.message ?? null,
7585
+ code: failure.kind === "server" ? failure.status ?? null : null,
7586
+ requestId: failure.kind === "server" ? failure.requestId ?? "" : "",
7587
+ details: "",
7588
+ secondaryAction: null,
7589
+ retrying: pending,
7590
+ retryLabel: t("error.retry"),
7591
+ onRetry: () => confirm(),
7592
+ announce: false,
7593
+ className: "mt-4"
7594
+ })
7595
+ })
7596
+ ] }),
7597
+ error !== null && /* @__PURE__ */ jsx("p", {
7598
+ role: "alert",
7599
+ className: failure ? "sr-only" : "mt-2 text-[12.5px] text-destructive-text",
7600
+ children: error
7601
+ }, announcementId),
7602
+ /* @__PURE__ */ jsx(AlertDialogFooter, {
7603
+ className: "mt-5",
7604
+ children: terminal ? /* @__PURE__ */ jsx(AlertDialogCancel, {
7605
+ ref: closeRef,
7606
+ children: t("common.close")
7607
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(AlertDialogCancel, {
7608
+ ref: cancelRef,
7609
+ disabled: pending,
7610
+ children: t("common.cancel")
7611
+ }), /* @__PURE__ */ jsx(Button, {
7612
+ type: "submit",
7613
+ variant: "destructive",
7614
+ loading: pending,
7615
+ disabled: !matches || canConfirm === false,
7616
+ children: label
7617
+ })] })
7618
+ })
7619
+ ]
7620
+ })
7621
+ ]
7622
+ })]
7623
+ });
7624
+ }
7625
+ //#endregion
7626
+ //#region src/feedback/ConfirmDestructive/block.meta.ts
7627
+ const meta$10 = {
7628
+ name: "Confirm destructive",
7629
+ family: "feedback",
7630
+ status: "beta",
7631
+ description: "AlertDialog for irreversible actions with exact typed-name and optional canConfirm gating, extra form fields, typed failure states, guarded retry and focus return. See the plain deletion and secret revocation examples.",
7632
+ uses: [
7633
+ "AlertDialog",
7634
+ "Button",
7635
+ "Field",
7636
+ "Input",
7637
+ "EmptyState"
7638
+ ]
7639
+ };
7640
+ //#endregion
7482
7641
  //#region src/feedback/ErrorPanel/block.meta.ts
7483
- const meta$21 = {
7642
+ const meta$22 = {
7484
7643
  name: "Error panel",
7485
7644
  family: "feedback",
7486
7645
  status: "beta",
@@ -7660,7 +7819,7 @@ function DangerZone({ title = "Danger zone", description = "These actions affect
7660
7819
  }
7661
7820
  //#endregion
7662
7821
  //#region src/forms/DangerZone/block.meta.ts
7663
- const meta$14 = {
7822
+ const meta$15 = {
7664
7823
  name: "Danger zone",
7665
7824
  family: "forms",
7666
7825
  status: "stable",
@@ -7897,11 +8056,78 @@ const meta$12 = {
7897
8056
  ]
7898
8057
  };
7899
8058
  //#endregion
8059
+ //#region src/forms/CredentialDisclosureDialog/SecretCopy.tsx
8060
+ /** Each secret owns feedback so simultaneous settlements cannot overwrite each other. */
8061
+ function SecretCopy({ secret, options, grouped = false, masked = true, warning }) {
8062
+ const { t } = useI18n();
8063
+ const [pending, setPending] = useState(false);
8064
+ const copied = options.copiedLabel ?? t("credentialDisclosure.copied");
8065
+ const content = /* @__PURE__ */ jsxs(LiveAnnouncer, { children: [
8066
+ warning,
8067
+ /* @__PURE__ */ jsx("div", {
8068
+ "data-kit-redact": true,
8069
+ children: masked ? /* @__PURE__ */ jsx(SecretField, {
8070
+ value: secret.value,
8071
+ copyable: false,
8072
+ "aria-label": secret.label,
8073
+ showLabel: options.showLabel ?? t("credentialDisclosure.show"),
8074
+ hideLabel: options.hideLabel ?? t("credentialDisclosure.hide")
8075
+ }) : /* @__PURE__ */ jsx(CodeBlock, {
8076
+ code: secret.value,
8077
+ copyable: false,
8078
+ label: secret.label,
8079
+ wrapToggle: false,
8080
+ defaultWrap: true
8081
+ })
8082
+ }),
8083
+ /* @__PURE__ */ jsx(CopyButton, {
8084
+ value: () => {
8085
+ if (grouped) setPending(true);
8086
+ return secret.value;
8087
+ },
8088
+ loading: grouped && pending,
8089
+ display: "label",
8090
+ label: options.copyLabel ?? t("credentialDisclosure.copy"),
8091
+ copiedLabel: copied,
8092
+ announcement: grouped ? options.copiedAnnouncementFor?.(secret.label) ?? `${secret.label}: ${copied}` : options.successAnnouncement ?? t("credentialDisclosure.success"),
8093
+ failureLabel: options.failureAnnouncement ?? t("credentialDisclosure.failure"),
8094
+ failureAnnouncement: options.failureAnnouncement ?? t("credentialDisclosure.failure"),
8095
+ failurePoliteness: "polite",
8096
+ onCopy: () => {
8097
+ if (grouped) setPending(false);
8098
+ options.onCopy?.(secret.id);
8099
+ },
8100
+ onCopyError: () => {
8101
+ if (grouped) setPending(false);
8102
+ }
8103
+ })
8104
+ ] });
8105
+ return grouped ? /* @__PURE__ */ jsx("div", {
8106
+ role: "group",
8107
+ "aria-label": secret.label,
8108
+ children: content
8109
+ }) : content;
8110
+ }
8111
+ //#endregion
8112
+ //#region src/forms/CredentialDisclosureDialog/focus.ts
8113
+ /** Programmatic focus permits negative tabIndex, but never hidden, inert or disabled targets. */
8114
+ function usableFocusTarget(element) {
8115
+ if (!(element instanceof HTMLElement) || !element.isConnected || element === document.body) return false;
8116
+ if (element.matches(":disabled, [disabled], [aria-disabled=\"true\"], input[type=\"hidden\"]")) return false;
8117
+ for (let ancestor = element; ancestor; ancestor = ancestor.parentElement) {
8118
+ if (ancestor.hidden || ancestor.hasAttribute("inert") || ancestor.getAttribute("aria-disabled") === "true") return false;
8119
+ const style = getComputedStyle(ancestor);
8120
+ if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse" || style.contentVisibility === "hidden") return false;
8121
+ }
8122
+ return element.tabIndex >= 0 || element.hasAttribute("tabindex") || element.isContentEditable;
8123
+ }
8124
+ //#endregion
7900
8125
  //#region src/forms/CredentialDisclosureDialog/CredentialDisclosureDialog.tsx
7901
8126
  /**
7902
- * Discloses an existing credential only after a successful response. Consumers keep disclosure
7903
- * null while pending or on failure, and clear it on close. No pending/error state or internal
7904
- * secret retention. A fresh secret requires a new successful response to be shown again.
8127
+ * Render only successful responses. Keep disclosure null while pending or on failure.
8128
+ * On close, clear disclosure, additionalSecrets and any secret-bearing revealContent.
8129
+ * No pending/error state or internal secret retention. Retained dismissed sessions stay closed;
8130
+ * a changed credential/value or a null-to-value opening starts a new session.
7905
8131
  */
7906
8132
  function CredentialDisclosureDialog(props) {
7907
8133
  if (!props.disclosure) return null;
@@ -7912,93 +8138,182 @@ function CredentialDisclosureDialog(props) {
7912
8138
  }
7913
8139
  function DisclosureOpening(props) {
7914
8140
  const [opener] = useState(() => typeof document === "undefined" ? null : document.activeElement);
8141
+ const [presentation] = useState(props.presentation ?? "dialog");
8142
+ const root = useRef(null);
8143
+ const target = useRef(null);
8144
+ const active = useRef(opener);
8145
+ const started = useRef(false);
8146
+ const activeWasInside = useRef(false);
8147
+ const returnFocus = () => {
8148
+ const current = props.resolveReturnFocus?.();
8149
+ if (usableFocusTarget(current)) return current;
8150
+ const fallback = props.fallbackFocus?.();
8151
+ if (usableFocusTarget(fallback)) return fallback;
8152
+ return usableFocusTarget(opener) ? opener : false;
8153
+ };
8154
+ const restore = useEffectEvent(() => {
8155
+ if (root.current?.contains(document.activeElement)) {
8156
+ const element = returnFocus();
8157
+ if (element) element.focus();
8158
+ }
8159
+ });
8160
+ useLayoutEffect(() => {
8161
+ const track = () => {
8162
+ if (document.activeElement !== document.body) {
8163
+ active.current = document.activeElement;
8164
+ activeWasInside.current = root.current?.contains(document.activeElement) ?? false;
8165
+ }
8166
+ };
8167
+ document.addEventListener("focusin", track);
8168
+ return () => {
8169
+ document.removeEventListener("focusin", track);
8170
+ restore();
8171
+ };
8172
+ }, [presentation]);
8173
+ useLayoutEffect(() => {
8174
+ if (activeWasInside.current && active.current && !active.current.isConnected) target.current?.focus();
8175
+ });
8176
+ const seen = /* @__PURE__ */ new Set(["secret", ""]);
8177
+ const additionalSecrets = (props.additionalSecrets ?? []).filter(({ id }) => {
8178
+ if (seen.has(id)) return false;
8179
+ seen.add(id);
8180
+ return true;
8181
+ });
7915
8182
  const { variant, credentialId, secret } = props.disclosure;
7916
8183
  return /* @__PURE__ */ jsx(DisclosureSession, {
7917
8184
  ...props,
7918
- opener
8185
+ presentation,
8186
+ additionalSecrets,
8187
+ onRootRef: (node) => {
8188
+ root.current = node;
8189
+ },
8190
+ onTargetRef: (node) => {
8191
+ target.current = node;
8192
+ },
8193
+ onPopupRef: (node) => {
8194
+ root.current = node;
8195
+ target.current = node;
8196
+ },
8197
+ containsFocus: () => root.current?.contains(document.activeElement) ?? false,
8198
+ initialFocus: () => {
8199
+ const shouldFocus = !started.current || activeWasInside.current && !active.current?.isConnected;
8200
+ started.current = true;
8201
+ return shouldFocus ? root.current : false;
8202
+ },
8203
+ returnFocus
7919
8204
  }, JSON.stringify([
7920
8205
  variant,
7921
8206
  credentialId,
7922
- secret
8207
+ secret,
8208
+ ...additionalSecrets.map(({ id, value }) => [id, value])
7923
8209
  ]));
7924
8210
  }
7925
- function DisclosureSession({ disclosure, onClose, resolveReturnFocus, fallbackFocus, opener, ...labels }) {
8211
+ function DisclosureSession(props) {
7926
8212
  const { t } = useI18n();
8213
+ const { disclosure, onRootRef, onTargetRef, onPopupRef, initialFocus, containsFocus, presentation, additionalSecrets = [] } = props;
7927
8214
  const [open, setOpen] = useState(true);
7928
- const popup = useRef(null);
8215
+ const [maskFresh] = useState(props.maskFresh ?? false);
7929
8216
  const dismissed = useRef(false);
7930
- const returnFocus = () => {
7931
- const target = resolveReturnFocus?.();
7932
- if (usableFocusTarget(target)) return target;
7933
- const fallback = fallbackFocus?.();
7934
- if (usableFocusTarget(fallback)) return fallback;
7935
- return usableFocusTarget(opener) ? opener : false;
7936
- };
7937
- const closeLabel = labels.closeLabel ?? t("credentialDisclosure.close");
7938
- const secretLabel = labels.secretLabel ?? t("credentialDisclosure.secret");
8217
+ const headingId = useId();
8218
+ const close = () => {
8219
+ if (dismissed.current) return;
8220
+ dismissed.current = true;
8221
+ if (presentation === "inline" && containsFocus()) {
8222
+ const element = props.returnFocus();
8223
+ if (element) element.focus();
8224
+ }
8225
+ setOpen(false);
8226
+ props.onClose();
8227
+ };
8228
+ const closeLabel = props.closeLabel ?? t("credentialDisclosure.close");
8229
+ const title = props.title ?? t("credentialDisclosure.title");
8230
+ const description = props.description ?? t("credentialDisclosure.description");
8231
+ const secretLabel = props.secretLabel ?? t("credentialDisclosure.secret");
8232
+ const warning = disclosure.variant === "fresh" ? /* @__PURE__ */ jsx(Alert, {
8233
+ role: presentation === "inline" ? "note" : "alert",
8234
+ tone: "warning",
8235
+ title: props.warningTitle ?? t("credentialDisclosure.warningTitle"),
8236
+ description: props.warningText ?? t("credentialDisclosure.warningText")
8237
+ }) : null;
8238
+ const body = /* @__PURE__ */ jsxs(Fragment$1, { children: [
8239
+ /* @__PURE__ */ jsxs("dl", {
8240
+ className: "grid grid-cols-2 gap-2 text-sm",
8241
+ children: [
8242
+ /* @__PURE__ */ jsx("dt", {
8243
+ className: "text-muted-foreground",
8244
+ children: props.credentialIdLabel ?? t("credentialDisclosure.credentialId")
8245
+ }),
8246
+ /* @__PURE__ */ jsx("dd", {
8247
+ className: "break-all font-mono",
8248
+ children: disclosure.credentialId
8249
+ }),
8250
+ /* @__PURE__ */ jsx("dt", {
8251
+ className: "text-muted-foreground",
8252
+ children: props.expiryLabel ?? t("credentialDisclosure.expiry")
8253
+ }),
8254
+ /* @__PURE__ */ jsx("dd", { children: disclosure.expiresAt })
8255
+ ]
8256
+ }),
8257
+ /* @__PURE__ */ jsx(SecretCopy, {
8258
+ secret: {
8259
+ id: "secret",
8260
+ label: secretLabel,
8261
+ value: disclosure.secret
8262
+ },
8263
+ options: props,
8264
+ grouped: additionalSecrets.length > 0,
8265
+ masked: disclosure.variant === "stored" || maskFresh,
8266
+ warning
8267
+ }),
8268
+ additionalSecrets.map((secret) => /* @__PURE__ */ jsx(SecretCopy, {
8269
+ secret,
8270
+ options: props,
8271
+ grouped: true
8272
+ }, secret.id)),
8273
+ props.revealContent != null && /* @__PURE__ */ jsx("div", {
8274
+ "data-kit-redact": true,
8275
+ children: props.revealContent
8276
+ })
8277
+ ] });
8278
+ if (presentation === "inline") {
8279
+ if (!open) return null;
8280
+ return /* @__PURE__ */ jsxs("section", {
8281
+ ref: onRootRef,
8282
+ "aria-labelledby": headingId,
8283
+ className: "grid gap-4",
8284
+ children: [
8285
+ /* @__PURE__ */ jsx("h2", {
8286
+ id: headingId,
8287
+ tabIndex: -1,
8288
+ ref: onTargetRef,
8289
+ children: title
8290
+ }),
8291
+ /* @__PURE__ */ jsx("p", { children: description }),
8292
+ body,
8293
+ /* @__PURE__ */ jsx(Button, {
8294
+ variant: "secondary",
8295
+ onClick: close,
8296
+ children: closeLabel
8297
+ })
8298
+ ]
8299
+ });
8300
+ }
7939
8301
  return /* @__PURE__ */ jsx(Dialog, {
7940
8302
  open,
7941
8303
  onOpenChange: (next) => {
7942
- if (!next && !dismissed.current) {
7943
- dismissed.current = true;
7944
- setOpen(false);
7945
- onClose();
7946
- }
8304
+ if (!next) close();
7947
8305
  },
7948
8306
  children: /* @__PURE__ */ jsx(DialogContent, {
7949
- ref: popup,
7950
- initialFocus: popup,
7951
- finalFocus: returnFocus,
8307
+ ref: onPopupRef,
8308
+ initialFocus,
8309
+ finalFocus: () => dismissed.current ? props.returnFocus() : false,
7952
8310
  showClose: false,
7953
8311
  closeLabel,
7954
8312
  children: open && /* @__PURE__ */ jsxs(Fragment$1, { children: [
7955
- /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: labels.title ?? t("credentialDisclosure.title") }), /* @__PURE__ */ jsx(DialogDescription, { children: labels.description ?? t("credentialDisclosure.description") })] }),
7956
- /* @__PURE__ */ jsxs(DialogBody, {
8313
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: title }), /* @__PURE__ */ jsx(DialogDescription, { children: description })] }),
8314
+ /* @__PURE__ */ jsx(DialogBody, {
7957
8315
  className: "grid gap-4",
7958
- children: [/* @__PURE__ */ jsxs("dl", {
7959
- className: "grid grid-cols-2 gap-2 text-sm",
7960
- children: [
7961
- /* @__PURE__ */ jsx("dt", {
7962
- className: "text-muted-foreground",
7963
- children: labels.credentialIdLabel ?? t("credentialDisclosure.credentialId")
7964
- }),
7965
- /* @__PURE__ */ jsx("dd", {
7966
- className: "break-all font-mono",
7967
- children: disclosure.credentialId
7968
- }),
7969
- /* @__PURE__ */ jsx("dt", {
7970
- className: "text-muted-foreground",
7971
- children: labels.expiryLabel ?? t("credentialDisclosure.expiry")
7972
- }),
7973
- /* @__PURE__ */ jsx("dd", { children: disclosure.expiresAt })
7974
- ]
7975
- }), /* @__PURE__ */ jsxs(LiveAnnouncer, { children: [disclosure.variant === "stored" ? /* @__PURE__ */ jsx(SecretField, {
7976
- value: disclosure.secret,
7977
- copyable: false,
7978
- "aria-label": secretLabel,
7979
- showLabel: labels.showLabel ?? t("credentialDisclosure.show"),
7980
- hideLabel: labels.hideLabel ?? t("credentialDisclosure.hide")
7981
- }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Alert, {
7982
- role: "alert",
7983
- tone: "warning",
7984
- title: labels.warningTitle ?? t("credentialDisclosure.warningTitle"),
7985
- description: labels.warningText ?? t("credentialDisclosure.warningText")
7986
- }), /* @__PURE__ */ jsx(CodeBlock, {
7987
- code: disclosure.secret,
7988
- copyable: false,
7989
- label: secretLabel,
7990
- wrapToggle: false,
7991
- defaultWrap: true
7992
- })] }), /* @__PURE__ */ jsx(CopyButton, {
7993
- value: () => disclosure.secret,
7994
- display: "label",
7995
- label: labels.copyLabel ?? t("credentialDisclosure.copy"),
7996
- copiedLabel: labels.copiedLabel ?? t("credentialDisclosure.copied"),
7997
- announcement: labels.successAnnouncement ?? t("credentialDisclosure.success"),
7998
- failureLabel: labels.failureAnnouncement ?? t("credentialDisclosure.failure"),
7999
- failureAnnouncement: labels.failureAnnouncement ?? t("credentialDisclosure.failure"),
8000
- failurePoliteness: "polite"
8001
- })] })]
8316
+ children: body
8002
8317
  }),
8003
8318
  /* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(DialogClose, {
8004
8319
  render: /* @__PURE__ */ jsx(Button, { variant: "secondary" }),
@@ -8008,24 +8323,13 @@ function DisclosureSession({ disclosure, onClose, resolveReturnFocus, fallbackFo
8008
8323
  })
8009
8324
  });
8010
8325
  }
8011
- /** Programmatic focus permits negative tabIndex, but never hidden, inert or disabled targets. */
8012
- function usableFocusTarget(element) {
8013
- if (!(element instanceof HTMLElement) || !element.isConnected || element === document.body) return false;
8014
- if (element.matches(":disabled, [disabled], [aria-disabled=\"true\"], input[type=\"hidden\"]")) return false;
8015
- for (let ancestor = element; ancestor; ancestor = ancestor.parentElement) {
8016
- if (ancestor.hidden || ancestor.hasAttribute("inert") || ancestor.getAttribute("aria-disabled") === "true") return false;
8017
- const style = getComputedStyle(ancestor);
8018
- if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse" || style.contentVisibility === "hidden") return false;
8019
- }
8020
- return element.tabIndex >= 0 || element.hasAttribute("tabindex") || element.isContentEditable;
8021
- }
8022
8326
  //#endregion
8023
8327
  //#region src/forms/CredentialDisclosureDialog/block.meta.ts
8024
8328
  const meta$13 = {
8025
8329
  name: "Credential disclosure dialog",
8026
8330
  family: "forms",
8027
8331
  status: "beta",
8028
- description: "Controlled disclosure for an existing credential. Set disclosure ({variant: stored | fresh, credentialId, expiresAt: caller-formatted ReactNode, secret}) only after a successful response; null renders nothing while pending or on failure. Clear disclosure to null in onClose to drop the secret; a fresh secret requires a new successful response before showing it again. No pending/error state or internal secret retention. Stored values start masked; each null-to-value opening or changed credentialId/secret resets masking and copy feedback. Fresh values use a non-copyable CodeBlock with a kit CopyButton and a replacement warning. Optional English defaults through en/es i18n for title, description, credentialIdLabel, expiryLabel, secretLabel, showLabel, hideLabel, copyLabel, copiedLabel, successAnnouncement, failureAnnouncement, warningTitle, warningText and closeLabel. Copy results are announced politely, including manual-selection fallback. Popup initial focus and focus trapping use Base UI; at close, resolveReturnFocus() is validated for connection, visibility, enabled state and focusability, then fallbackFocus(), then the original opener. Synthetic fixtures only; the default Stored preview is masked and the Fresh preview starts closed.",
8332
+ description: "Controlled disclosure for an existing credential. Set disclosure ({variant: stored | fresh, credentialId, expiresAt: caller-formatted ReactNode, secret}) only after a successful response; null renders nothing while pending or on failure. Clear disclosure, additionalSecrets and secret-bearing revealContent in onClose to drop every secret; a fresh secret requires a new successful response before showing it again. No pending/error state or internal secret retention. Stored values start masked; each null-to-value opening or changed credentialId/secret resets masking and copy feedback. Fresh values use a non-copyable CodeBlock with a kit CopyButton and a replacement warning, or a masked SecretField when maskFresh is set at session start. Optional additionalSecrets ({id, label, value}) are always masked and use independent toggles and serialized copy actions; ids must be non-empty, unique and not secret, with the first duplicate winning. Multi-secret groups announce label plus copiedLabel, or copiedAnnouncementFor(label); onCopy(id) never receives a value. Every secret and the optional revealContent slot have data-kit-redact. The session key includes additional ids and values. presentation is dialog by default or inline, fixed until the next opening: inline is a named section, never traps focus or handles Escape, and its warning is a non-live note. Surviving focus stays; removing the focused slot or session control focuses the popup or inline heading. Focused inline unmounts return focus through the same resolvers. Dismissed retained props stay hidden; clear and re-set or change a session value to reopen. Optional English defaults through en/es i18n for title, description, credentialIdLabel, expiryLabel, secretLabel, showLabel, hideLabel, copyLabel, copiedLabel, successAnnouncement, failureAnnouncement, warningTitle, warningText and closeLabel. Copy results are announced politely, including manual-selection fallback. Popup initial focus and focus trapping use Base UI; at close, resolveReturnFocus() is validated for connection, visibility, enabled state and focusability, then fallbackFocus(), then the original opener. Synthetic fixtures only; the default Stored preview is masked and the Fresh preview starts closed.",
8029
8333
  uses: [
8030
8334
  "Dialog",
8031
8335
  "SecretField",
@@ -8081,7 +8385,7 @@ function DateRangeFilter({ value, defaultValue, onValueChange, presets = DEFAULT
8081
8385
  }
8082
8386
  //#endregion
8083
8387
  //#region src/forms/DateRangeFilter/block.meta.ts
8084
- const meta$16 = {
8388
+ const meta$17 = {
8085
8389
  name: "Date range filter",
8086
8390
  family: "forms",
8087
8391
  status: "stable",
@@ -8370,7 +8674,7 @@ function FileRow({ item, onRemove, onRetry }) {
8370
8674
  }
8371
8675
  //#endregion
8372
8676
  //#region src/forms/FileUploadPanel/block.meta.ts
8373
- const meta$25 = {
8677
+ const meta$26 = {
8374
8678
  name: "File upload panel",
8375
8679
  family: "forms",
8376
8680
  status: "stable",
@@ -8433,7 +8737,7 @@ function FormSection({ title = "General", description = "Basic details shown to
8433
8737
  }
8434
8738
  //#endregion
8435
8739
  //#region src/forms/FormSection/block.meta.ts
8436
- const meta$29 = {
8740
+ const meta$30 = {
8437
8741
  name: "Form section",
8438
8742
  family: "forms",
8439
8743
  status: "stable",
@@ -8600,7 +8904,7 @@ function InviteMembersDialog({ roles = memberRoles, defaultRole = "member", onIn
8600
8904
  }
8601
8905
  //#endregion
8602
8906
  //#region src/forms/InviteMembersDialog/block.meta.ts
8603
- const meta$34 = {
8907
+ const meta$35 = {
8604
8908
  name: "Invite members dialog",
8605
8909
  family: "forms",
8606
8910
  status: "stable",
@@ -8658,7 +8962,7 @@ function SettingsRow({ label = "Deployment notifications", description = "Email
8658
8962
  }
8659
8963
  //#endregion
8660
8964
  //#region src/forms/SettingsRow/block.meta.ts
8661
- const meta$58 = {
8965
+ const meta$60 = {
8662
8966
  name: "Settings row",
8663
8967
  family: "forms",
8664
8968
  status: "stable",
@@ -8683,7 +8987,7 @@ function DialogWizard({ steps, current = 0, size = "dialog", stepError, reviewSt
8683
8987
  }
8684
8988
  //#endregion
8685
8989
  //#region src/forms/DialogWizard/block.meta.ts
8686
- const meta$18 = {
8990
+ const meta$19 = {
8687
8991
  name: "Dialog wizard",
8688
8992
  family: "forms",
8689
8993
  status: "beta",
@@ -8722,7 +9026,7 @@ const dialogWizardCopy = {
8722
9026
  };
8723
9027
  //#endregion
8724
9028
  //#region src/forms/ValidationSummary/block.meta.ts
8725
- const meta$73 = {
9029
+ const meta$75 = {
8726
9030
  name: "Validation summary",
8727
9031
  family: "forms",
8728
9032
  status: "stable",
@@ -8868,7 +9172,7 @@ function Hero({ variant = "centered", eyebrow = "New · Usage-based billing", ti
8868
9172
  }
8869
9173
  //#endregion
8870
9174
  //#region src/marketing/Hero/block.meta.ts
8871
- const meta$31 = {
9175
+ const meta$32 = {
8872
9176
  name: "Hero",
8873
9177
  family: "marketing",
8874
9178
  status: "beta",
@@ -8973,7 +9277,7 @@ function FeatureGrid({ features = sampleFeatures, eyebrow = "Everything included
8973
9277
  }
8974
9278
  //#endregion
8975
9279
  //#region src/marketing/FeatureGrid/block.meta.ts
8976
- const meta$24 = {
9280
+ const meta$25 = {
8977
9281
  name: "Feature grid",
8978
9282
  family: "marketing",
8979
9283
  status: "beta",
@@ -9252,7 +9556,7 @@ function TierBody({ tier, tierId, cycle, money, TierHeading, currentTierId, curr
9252
9556
  }
9253
9557
  //#endregion
9254
9558
  //#region src/marketing/PricingTable/block.meta.ts
9255
- const meta$50 = {
9559
+ const meta$52 = {
9256
9560
  name: "Pricing table",
9257
9561
  family: "marketing",
9258
9562
  status: "beta",
@@ -9332,7 +9636,7 @@ function Faq({ items = sampleFaqs, title = "Frequently asked questions", descrip
9332
9636
  }
9333
9637
  //#endregion
9334
9638
  //#region src/marketing/Faq/block.meta.ts
9335
- const meta$23 = {
9639
+ const meta$24 = {
9336
9640
  name: "FAQ",
9337
9641
  family: "marketing",
9338
9642
  status: "beta",
@@ -9860,7 +10164,7 @@ function PageHeader({ as: Root = "header", breadcrumbs = pageHeaderBreadcrumbs,
9860
10164
  }
9861
10165
  //#endregion
9862
10166
  //#region src/page-chrome/PageHeader/block.meta.ts
9863
- const meta$43 = {
10167
+ const meta$45 = {
9864
10168
  name: "Page header",
9865
10169
  family: "page-chrome",
9866
10170
  status: "beta",
@@ -9914,7 +10218,7 @@ function SectionHeader({ title = "Policies", description = "Guardrails applied t
9914
10218
  }
9915
10219
  //#endregion
9916
10220
  //#region src/page-chrome/SectionHeader/block.meta.ts
9917
- const meta$56 = {
10221
+ const meta$58 = {
9918
10222
  name: "Section header",
9919
10223
  family: "page-chrome",
9920
10224
  status: "beta",
@@ -10007,7 +10311,7 @@ function PageToolbar({ search, defaultSearch = "", onSearchChange, searchLabel:
10007
10311
  }
10008
10312
  //#endregion
10009
10313
  //#region src/page-chrome/PageToolbar/block.meta.ts
10010
- const meta$44 = {
10314
+ const meta$46 = {
10011
10315
  name: "Page toolbar",
10012
10316
  family: "page-chrome",
10013
10317
  status: "beta",
@@ -10063,7 +10367,7 @@ function StickyActionBar({ dirty = true, saving = false, onSave, onCancel, dirty
10063
10367
  }
10064
10368
  //#endregion
10065
10369
  //#region src/page-chrome/StickyActionBar/block.meta.ts
10066
- const meta$66 = {
10370
+ const meta$68 = {
10067
10371
  name: "Sticky action bar",
10068
10372
  family: "page-chrome",
10069
10373
  status: "beta",
@@ -10791,7 +11095,7 @@ function MonthCalendar({ events = sampleEvents, today = sampleToday, defaultMont
10791
11095
  }
10792
11096
  //#endregion
10793
11097
  //#region src/scheduling/MonthCalendar/block.meta.ts
10794
- const meta$41 = {
11098
+ const meta$43 = {
10795
11099
  name: "Month calendar",
10796
11100
  family: "scheduling",
10797
11101
  status: "beta",
@@ -10985,7 +11289,7 @@ function WeekCalendar({ events = sampleEvents, today = sampleToday, now, default
10985
11289
  }
10986
11290
  //#endregion
10987
11291
  //#region src/scheduling/WeekCalendar/block.meta.ts
10988
- const meta$74 = {
11292
+ const meta$76 = {
10989
11293
  name: "Week calendar",
10990
11294
  family: "scheduling",
10991
11295
  status: "beta",
@@ -11217,7 +11521,7 @@ function TimeSlotPicker({ slots = sampleTimeSlots, value, defaultValue = null, o
11217
11521
  }
11218
11522
  //#endregion
11219
11523
  //#region src/scheduling/TimeSlotPicker/block.meta.ts
11220
- const meta$69 = {
11524
+ const meta$71 = {
11221
11525
  name: "Time slot picker",
11222
11526
  family: "scheduling",
11223
11527
  status: "beta",
@@ -11743,7 +12047,7 @@ const meta$3 = {
11743
12047
  };
11744
12048
  //#endregion
11745
12049
  //#region src/shell/EnvironmentBadge/block.meta.ts
11746
- const meta$20 = {
12050
+ const meta$21 = {
11747
12051
  name: "Environment badge",
11748
12052
  family: "shell",
11749
12053
  status: "beta",
@@ -11752,7 +12056,7 @@ const meta$20 = {
11752
12056
  };
11753
12057
  //#endregion
11754
12058
  //#region src/shell/GlobalSearch/block.meta.ts
11755
- const meta$30 = {
12059
+ const meta$31 = {
11756
12060
  name: "Global search",
11757
12061
  family: "shell",
11758
12062
  status: "beta",
@@ -13271,13 +13575,14 @@ const ROW_HEIGHT = {
13271
13575
  * and empty states, client-side sort + pagination, optional collapsible row groups (`groupBy`),
13272
13576
  * column resize and pinning, row virtualization, inline cell editing and saved views.
13273
13577
  */
13274
- function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRowId = defaultRowId, getRowLabel, caption = "Deployments", showCaption = false, selectable: selectableProp = true, selectionMode, selectionName, legend, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, selectedId, defaultSelectedId, onSelectedIdChange, isRowDisabled, selectedIds, defaultSelectedIds = [], onSelectionChange, bulkActions, selectionSummary = true, rowActions, sort: sortProp, defaultSort = null, onSortChange, manualSorting = false, paginated: paginatedProp, defaultPageSize = 10, pageSizeOptions = [
13578
+ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRowId = defaultRowId, getRowLabel, caption = "Deployments", showCaption = false, selectable: selectableProp = true, selectionMode, selectionName, legend, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, selectedId, defaultSelectedId, onSelectedIdChange, isRowDisabled, selectedIds, defaultSelectedIds = [], onSelectionChange, bulkActions, selectionSummary = true, rowActions, sort: sortProp, defaultSort = null, onSortChange, manualSorting = false, paginated: paginatedProp, paginationMode = "client", rowCount, page: controlledPage, pageSize: controlledPageSize, onPageChange, onPageSizeChange, defaultPageSize = 10, pageSizeOptions = [
13275
13579
  10,
13276
13580
  25,
13277
13581
  50
13278
13582
  ], density: densityProp, defaultDensity, onDensityChange, showDensityToggle = true, showColumnMenu = true, loading = false, loadingRows = 5, emptyState, groupBy, groupLabel, collapsibleGroups = true, collapsedGroups: collapsedProp, defaultCollapsedGroups = [], onCollapsedGroupsChange, onGroupByChange, hiddenColumns: hiddenProp, onHiddenColumnsChange, resizable = false, columnWidths: widthsProp, defaultColumnWidths = EMPTY_WIDTHS, onColumnWidthsChange, pinnedColumns: pinnedProp, defaultPinnedColumns = EMPTY_PINNED, onPinnedColumnsChange, showPinMenu, virtualize = "auto", virtualizeThreshold = 100, rowHeight: rowHeightProp, virtualContainerClassName = "max-h-[32rem]", onCellEdit, views: viewsProp, defaultViews, onViewsChange, activeViewId, defaultActiveViewId, onActiveViewChange, showViewSwitcher, filters, onFiltersChange, toolbar, className, labels }) {
13279
13583
  const { t } = useI18n();
13280
13584
  const singleMode = selectionMode === "single";
13585
+ const serverMode = paginationMode === "server";
13281
13586
  const selectable = selectionMode === void 0 ? selectableProp : selectionMode === "multiple";
13282
13587
  const selectionColumn = selectable || singleMode;
13283
13588
  const paginated = !singleMode && (paginatedProp ?? true);
@@ -13309,10 +13614,10 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13309
13614
  });
13310
13615
  const [innerCollapsed, setInnerCollapsed] = useState(() => new Set(defaultCollapsedGroups));
13311
13616
  const collapsed = collapsedProp ? new Set(collapsedProp) : innerCollapsed;
13312
- const sortedRows = manualSorting ? [...rows] : sortRows(rows, columns, sort);
13617
+ const sortedRows = serverMode ? rows : manualSorting ? [...rows] : sortRows(rows, columns, sort);
13313
13618
  const allGroups = effectiveGroupBy ? groupRows(sortedRows, effectiveGroupBy, rows) : null;
13314
13619
  const sorted = allGroups ? allGroups.flatMap((g) => g.rows) : sortedRows;
13315
- const pageRows = paginated ? paginate(sorted, page, pageSize) : sorted;
13620
+ const pageRows = serverMode ? rows : paginated ? paginate(sorted, page, pageSize) : sorted;
13316
13621
  const pageIds = (effectiveGroupBy ? pageRows.filter((row) => !collapsed.has(groupKeyOf(row, effectiveGroupBy))) : pageRows).map(getRowId);
13317
13622
  const header = selectionState(pageIds, selected);
13318
13623
  const selectedList = rows.map(getRowId).filter((id) => selected.has(id));
@@ -13321,6 +13626,7 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13321
13626
  onSelectionChange?.(rows.map(getRowId).filter((id) => next.has(id)));
13322
13627
  };
13323
13628
  const changeSort = (columnId, direction) => {
13629
+ if (serverMode) return;
13324
13630
  const next = {
13325
13631
  columnId,
13326
13632
  direction: sort?.columnId === columnId ? direction : "ascending"
@@ -13390,7 +13696,7 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13390
13696
  const applyState = (state) => {
13391
13697
  const nextSort = state.sort ?? null;
13392
13698
  setInnerSort(nextSort);
13393
- if (nextSort) onSortChange?.(nextSort);
13699
+ if (nextSort && !serverMode) onSortChange?.(nextSort);
13394
13700
  setHiddenList(state.hiddenColumns ?? defaultHidden);
13395
13701
  setWidths(state.columnWidths ?? defaultColumnWidths);
13396
13702
  setPinned(state.pinnedColumns ?? defaultPinnedColumns);
@@ -13398,7 +13704,7 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13398
13704
  setGroupOverride(nextGroup === groupName(groupBy) && typeof groupBy !== "function" ? void 0 : nextGroup);
13399
13705
  if (nextGroup !== currentState.groupBy) onGroupByChange?.(nextGroup);
13400
13706
  if (state.filters !== filters) onFiltersChange?.(state.filters);
13401
- setPage(1);
13707
+ if (!serverMode) setPage(1);
13402
13708
  };
13403
13709
  const viewsApi = useTableViews({
13404
13710
  views: viewsProp,
@@ -13532,9 +13838,12 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13532
13838
  const bounds = widthBounds(c);
13533
13839
  return /* @__PURE__ */ jsx(DataTableHeadCell, {
13534
13840
  labels,
13535
- column: c,
13841
+ column: serverMode ? {
13842
+ ...c,
13843
+ sortable: false
13844
+ } : c,
13536
13845
  layout: layout.columns.get(c.id),
13537
- sortDirection: sort?.columnId === c.id ? sort.direction : "none",
13846
+ sortDirection: !serverMode && sort?.columnId === c.id ? sort.direction : "none",
13538
13847
  onSortChange: (dir) => changeSort(c.id, dir),
13539
13848
  resize: resizable && c.resizable !== false ? {
13540
13849
  width: columnWidthOf(c, widths),
@@ -13591,14 +13900,14 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13591
13900
  "…"
13592
13901
  ] })
13593
13902
  }),
13594
- paginated && !loading && rows.length > 0 && /* @__PURE__ */ jsx(PaginationFooter, {
13903
+ paginated && !loading && (serverMode || rows.length > 0) && /* @__PURE__ */ jsx(PaginationFooter, {
13595
13904
  labels,
13596
13905
  className: "border-t border-border px-4 py-3",
13597
- total: rows.length,
13598
- page,
13599
- onPageChange: setPage,
13600
- pageSize,
13601
- onPageSizeChange: setPageSize,
13906
+ total: serverMode ? rowCount : rows.length,
13907
+ page: serverMode ? controlledPage : page,
13908
+ onPageChange: serverMode ? onPageChange : setPage,
13909
+ pageSize: serverMode ? controlledPageSize : pageSize,
13910
+ onPageSizeChange: serverMode ? onPageSizeChange : setPageSize,
13602
13911
  pageSizeOptions,
13603
13912
  noun: caption
13604
13913
  })
@@ -13607,11 +13916,11 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13607
13916
  }
13608
13917
  //#endregion
13609
13918
  //#region src/tables/DataTable/block.meta.ts
13610
- const meta$15 = {
13919
+ const meta$16 = {
13611
13920
  name: "Data table",
13612
13921
  family: "tables",
13613
13922
  status: "beta",
13614
- description: "Generic typed table: sortable headers with aria-sort, row selection with select-all and indeterminate by default (selectionMode=\"multiple\"), selectionMode=\"none\" to hide selection, column visibility menu, density toggle, row actions, loading and empty states, client-side sort and pagination, optional row groups (groupBy) with rowgroup header rows, counts, keyboard-accessible collapse buttons and group selection; column resize (pointer drag or a focusable role=\"separator\" handle with arrow keys, min/max widths, controlled columnWidths), column pinning to either edge with sticky cells (column menu or pinnedColumns), row virtualization for large datasets (aria-rowcount/aria-rowindex, works with selection and grouping), inline cell editing (text, number and select editors; Enter/F2 to edit, Enter/Tab to commit, Escape to cancel, onCellEdit can reject with an inline error) and saved views (filters, sort, visible columns, widths, pinning and grouping) with a view switcher to save as, rename, delete and reset. Opt-in selectionMode=\"single\" uses native radios in a labelled fieldset (never paginated or virtualized; paginated defaults to false and paginated=true is a type error). Single mode uses selectedId/onSelectedIdChange or defaultSelectedId; isRowDisabled skips unavailable rows and preserves a checked disabled choice without callbacks. Supply legend, aria-label or aria-labelledby for the group and getRowLabel for each radio (otherwise the first column labels it). selectionName is used verbatim and must be unique per page; omitted names use an instance-unique useId name, and duplicate supplied names or missing group labels warn in development. Tab enters once on the checked enabled row or first enabled row; arrows wrap and skip disabled rows, Space selects, Shift+Tab exits, and all-disabled groups have no tab stop. No select-all, group checkboxes, bulk actions or selection summary appear in single mode. Examples in examples/single-selection.tsx: an uncontrolled non-paginated list with legend=\"Available items\" and a controlled versions table with legend=\"Available versions\", selectedId=\"v2\" and a checked disabled version.",
13923
+ description: "Generic typed table: sortable headers with aria-sort, row selection with select-all and indeterminate by default (selectionMode=\"multiple\"), selectionMode=\"none\" to hide selection, column visibility menu, density toggle, row actions, loading and empty states, client-side sort and pagination, optional row groups (groupBy) with rowgroup header rows, counts, keyboard-accessible collapse buttons and group selection; column resize (pointer drag or a focusable role=\"separator\" handle with arrow keys, min/max widths, controlled columnWidths), column pinning to either edge with sticky cells (column menu or pinnedColumns), row virtualization for large datasets (aria-rowcount/aria-rowindex, works with selection and grouping), inline cell editing (text, number and select editors; Enter/F2 to edit, Enter/Tab to commit, Escape to cancel, onCellEdit can reject with an inline error) and saved views (filters, sort, visible columns, widths, pinning and grouping) with a view switcher to save as, rename, delete and reset. Opt-in selectionMode=\"single\" uses native radios in a labelled fieldset (never paginated or virtualized; paginated defaults to false and paginated=true is a type error). Single mode uses selectedId/onSelectedIdChange or defaultSelectedId; isRowDisabled skips unavailable rows and preserves a checked disabled choice without callbacks. Supply legend, aria-label or aria-labelledby for the group and getRowLabel for each radio (otherwise the first column labels it). selectionName is used verbatim and must be unique per page; omitted names use an instance-unique useId name, and duplicate supplied names or missing group labels warn in development. Tab enters once on the checked enabled row or first enabled row; arrows wrap and skip disabled rows, Space selects, Shift+Tab exits, and all-disabled groups have no tab stop. No select-all, group checkboxes, bulk actions or selection summary appear in single mode. Examples in examples/single-selection.tsx: an uncontrolled non-paginated list with legend=\"Available items\" and a controlled versions table with legend=\"Available versions\", selectedId=\"v2\" and a checked disabled version. Opt-in paginationMode=\"server\" accepts a controlled 1-based page, pageSize and required rowCount (known total), with onPageChange/onPageSizeChange requests. Supplied rows render in order without client sorting or slicing, and headers have no sort affordance. Single selection cannot use server mode. The footer stays visible for empty results, clamps stale pages for display without callbacks, and hides during loading. Page-size changes may also request a page to keep the first visible row on screen. The consumer owns fetching and reconciles stale pages. See examples/server-pagination.tsx for an items/total/page/pageSize envelope consumer that handles both callbacks.",
13615
13924
  labels: [
13616
13925
  {
13617
13926
  key: "scrollRegion",
@@ -14120,7 +14429,7 @@ function FilterBar({ fields = DEPLOYMENT_FILTER_FIELDS, query: queryProp, defaul
14120
14429
  }
14121
14430
  //#endregion
14122
14431
  //#region src/tables/FilterBar/block.meta.ts
14123
- const meta$26 = {
14432
+ const meta$27 = {
14124
14433
  name: "Filter bar",
14125
14434
  family: "tables",
14126
14435
  status: "beta",
@@ -14192,8 +14501,73 @@ const meta$26 = {
14192
14501
  ]
14193
14502
  };
14194
14503
  //#endregion
14504
+ //#region src/tables/CursorPagerFooter/fixtures.ts
14505
+ const CURSOR_PAGER_PREVIEW = {
14506
+ hasPrevious: false,
14507
+ hasNext: true,
14508
+ onPrevious: () => {},
14509
+ onNext: () => {},
14510
+ shownCount: 25,
14511
+ labels: {
14512
+ shownSummary: (shownCount) => `${shownCount} records shown`,
14513
+ totalSummary: (total) => `${total} records in total`
14514
+ }
14515
+ };
14516
+ //#endregion
14517
+ //#region src/tables/CursorPagerFooter/CursorPagerFooter.tsx
14518
+ /** Responsive table footer. Forwards every cursor-pagination prop without storing cursor state. */
14519
+ function CursorPagerFooter(props = {}) {
14520
+ return /* @__PURE__ */ jsx(CursorPagination, { ...props.hasPrevious === void 0 ? CURSOR_PAGER_PREVIEW : props });
14521
+ }
14522
+ //#endregion
14523
+ //#region src/tables/CursorPagerFooter/block.meta.ts
14524
+ const meta$14 = {
14525
+ name: "Cursor pager footer",
14526
+ family: "tables",
14527
+ status: "beta",
14528
+ description: "Responsive stateless cursor-pagination footer for data-table paginated={false}. Forwards CursorPaginationProps: hasPrevious, hasNext, onPrevious, onNext, loading, busy, summary, shownCount, total, unavailableBehaviour, pageSize, pageSizeOptions, onPageSizeChange, previousLabel, nextLabel, ariaLabel, loadingLabel, labels and className. Consumer-owned opaque cursors stay outside the kit. summary accepts plain text or null; the count form requires labels.shownSummary and labels.totalSummary; select options require labels.rowsPerPage and labels.rowsPerPageLabel. Flat names override labels.previous, labels.next and labels.navLabel, then catalog defaults. loadingLabel=null preserves the summary while busy. One persistent polite atomic status; buttons remain focusable when aria-disabled. Removal of a focused control moves focus to Next, Previous, select, then nav root, including while busy. No page numbers or ranges. No props renders fixtures.",
14529
+ labels: [
14530
+ {
14531
+ key: "previous",
14532
+ type: "string",
14533
+ state: "Previous name, below previousLabel and above catalog defaults"
14534
+ },
14535
+ {
14536
+ key: "next",
14537
+ type: "string",
14538
+ state: "Next name, below nextLabel and above catalog defaults"
14539
+ },
14540
+ {
14541
+ key: "navLabel",
14542
+ type: "string",
14543
+ state: "Navigation name, below ariaLabel and above catalog defaults"
14544
+ },
14545
+ {
14546
+ key: "shownSummary",
14547
+ type: "(shownCount: number) => string",
14548
+ state: "Required in count form: no positive exact total"
14549
+ },
14550
+ {
14551
+ key: "totalSummary",
14552
+ type: "(total: number) => string",
14553
+ state: "Required in count form: positive exact total"
14554
+ },
14555
+ {
14556
+ key: "rowsPerPage",
14557
+ type: "string",
14558
+ state: "Required with pageSizeOptions: visible select label"
14559
+ },
14560
+ {
14561
+ key: "rowsPerPageLabel",
14562
+ type: "string",
14563
+ state: "Required with pageSizeOptions: select accessible name"
14564
+ }
14565
+ ],
14566
+ uses: ["CursorPagination"]
14567
+ };
14568
+ //#endregion
14195
14569
  //#region src/tables/PaginationFooter/block.meta.ts
14196
- const meta$45 = {
14570
+ const meta$47 = {
14197
14571
  name: "Pagination footer",
14198
14572
  family: "tables",
14199
14573
  status: "beta",
@@ -14238,6 +14612,198 @@ const meta$45 = {
14238
14612
  uses: ["SimpleSelect", "Pagination"]
14239
14613
  };
14240
14614
  //#endregion
14615
+ //#region src/tables/LoadMoreFooter/useLoadMoreFooter.ts
14616
+ /** Capture focus before React removes the control, then restore it after the replacement commits. */
14617
+ function useLoadMoreFooter(control, target, loading, error) {
14618
+ const rootRef = useRef(null);
14619
+ const summaryRef = useRef(null);
14620
+ const currentControl = useRef(null);
14621
+ const moveFocus = useRef(false);
14622
+ const inFlightCursorRef = useRef(void 0);
14623
+ useEffect(() => {
14624
+ if (!loading && !error) inFlightCursorRef.current = void 0;
14625
+ }, [loading, error]);
14626
+ const controlRef = useCallback((node) => {
14627
+ if (!node && currentControl.current?.contains(document.activeElement)) moveFocus.current = true;
14628
+ currentControl.current = node;
14629
+ }, []);
14630
+ useLayoutEffect(() => {
14631
+ if (!moveFocus.current) return;
14632
+ moveFocus.current = false;
14633
+ const nextControl = currentControl.current;
14634
+ ((nextControl?.matches("button") ? nextControl : nextControl?.querySelector("button")) ?? (target === "root" ? rootRef.current : summaryRef.current))?.focus();
14635
+ }, [control, target]);
14636
+ return {
14637
+ rootRef,
14638
+ summaryRef,
14639
+ controlRef,
14640
+ inFlightCursorRef
14641
+ };
14642
+ }
14643
+ /** Track committed results; mounting and intermediate loading states remain silent. */
14644
+ function useLoadMoreAnnouncements(loading, error, lastAppend, loadedAnnouncement) {
14645
+ const announce = useAnnounce();
14646
+ const previous = useRef({
14647
+ loading,
14648
+ error
14649
+ });
14650
+ const lastSeq = useRef(lastAppend?.seq);
14651
+ useEffect(() => {
14652
+ const before = previous.current;
14653
+ previous.current = {
14654
+ loading,
14655
+ error
14656
+ };
14657
+ if (!loading && error && (before.loading || before.error !== error)) announce(error, "assertive");
14658
+ }, [
14659
+ loading,
14660
+ error,
14661
+ announce
14662
+ ]);
14663
+ useEffect(() => {
14664
+ if (!lastAppend || lastSeq.current !== void 0 && lastAppend.seq <= lastSeq.current) return;
14665
+ lastSeq.current = lastAppend.seq;
14666
+ if (lastAppend.count > 0) announce(loadedAnnouncement(lastAppend.count), "polite");
14667
+ }, [
14668
+ lastAppend,
14669
+ loadedAnnouncement,
14670
+ announce
14671
+ ]);
14672
+ }
14673
+ //#endregion
14674
+ //#region src/tables/LoadMoreFooter/fixtures.ts
14675
+ /** Meaningful defaults for the no-props catalogue preview. */
14676
+ const LOAD_MORE_PREVIEW = {
14677
+ nextCursor: "page-2",
14678
+ loadedCount: 20
14679
+ };
14680
+ //#endregion
14681
+ //#region src/tables/LoadMoreFooter/LoadMoreFooter.tsx
14682
+ /**
14683
+ * Load more for appended lists without a total or page count. The consumer owns rows and requests.
14684
+ * With no props, renders a static catalogue preview using fixture data. Supplying any prop selects
14685
+ * the consumer contract: undefined nextCursor means flag mode and requires hasMore=true.
14686
+ * loadedCount defaults to the preview fixture; consumers should pass their actual loaded count.
14687
+ */
14688
+ function LoadMoreFooter(props = {}) {
14689
+ return useHasLiveAnnouncer() ? /* @__PURE__ */ jsx(LoadMoreFooterContent, { ...props }) : /* @__PURE__ */ jsx(LiveAnnouncer, { children: /* @__PURE__ */ jsx(LoadMoreFooterContent, { ...props }) });
14690
+ }
14691
+ function LoadMoreFooterContent(props) {
14692
+ const { t } = useI18n();
14693
+ const { nextCursor, hasMore, loading = false, error = "", exhaustedFocusTarget = "summary", loadedCount = LOAD_MORE_PREVIEW.loadedCount, labels, className } = props;
14694
+ const cursor = Object.keys(props).length === 0 ? LOAD_MORE_PREVIEW.nextCursor : nextCursor;
14695
+ const available = cursor === void 0 ? hasMore === true : typeof cursor === "string" && cursor.length > 0 && hasMore !== false;
14696
+ const failed = error.length > 0;
14697
+ const cursorMode = cursor !== void 0;
14698
+ const panel = cursorMode && failed;
14699
+ const { rootRef, summaryRef, controlRef, inFlightCursorRef } = useLoadMoreFooter(!available ? "none" : panel ? "retry" : "button", exhaustedFocusTarget, loading, error);
14700
+ const errorId = useId();
14701
+ useLoadMoreAnnouncements(loading, error, props.lastAppend, labels?.loadedAnnouncement ?? ((count) => t("table.loadedAnnouncement", { count })));
14702
+ const load = () => {
14703
+ if (loading || !available) return;
14704
+ inFlightCursorRef.current = cursor ?? void 0;
14705
+ if (cursor === void 0) props.onLoadMore?.();
14706
+ else props.onLoadMore?.(cursor ?? void 0);
14707
+ };
14708
+ const retry = () => {
14709
+ if (loading || !available) return;
14710
+ const handler = props.onRetry ?? props.onLoadMore;
14711
+ if (cursorMode) handler?.(inFlightCursorRef.current ?? cursor ?? void 0);
14712
+ else handler?.();
14713
+ };
14714
+ return /* @__PURE__ */ jsxs("div", {
14715
+ ref: rootRef,
14716
+ role: "group",
14717
+ "aria-label": labels?.group ?? t("table.loadMoreGroup"),
14718
+ tabIndex: -1,
14719
+ "aria-busy": loading,
14720
+ className: cn("flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", className),
14721
+ children: [/* @__PURE__ */ jsxs("p", {
14722
+ ref: summaryRef,
14723
+ tabIndex: -1,
14724
+ className: "text-sm text-muted-foreground tabular-nums",
14725
+ children: [
14726
+ labels?.summary?.(loadedCount) ?? t("table.loadedSummary", { count: loadedCount }),
14727
+ " ",
14728
+ available && /* @__PURE__ */ jsx("span", { children: labels?.moreAvailable ?? t("table.moreAvailable") })
14729
+ ]
14730
+ }), panel ? /* @__PURE__ */ jsx("div", {
14731
+ ref: available ? controlRef : void 0,
14732
+ children: /* @__PURE__ */ jsx(ErrorPanel, {
14733
+ title: error,
14734
+ message: null,
14735
+ code: null,
14736
+ requestId: "",
14737
+ details: "",
14738
+ secondaryAction: null,
14739
+ onRetry: available ? retry : void 0,
14740
+ retrying: loading,
14741
+ retryLabel: labels?.retry ?? t("error.retry")
14742
+ })
14743
+ }, available ? "retry" : "exhausted") : /* @__PURE__ */ jsxs(Fragment$1, { children: [failed && /* @__PURE__ */ jsx("p", {
14744
+ id: errorId,
14745
+ className: "text-sm text-destructive-text",
14746
+ children: error
14747
+ }), available && /* @__PURE__ */ jsx(Button, {
14748
+ ref: controlRef,
14749
+ loading,
14750
+ onClick: failed ? retry : load,
14751
+ "aria-describedby": failed ? errorId : void 0,
14752
+ children: loading ? labels?.loading ?? t("table.loadingMore") : failed ? labels?.retry ?? t("error.retry") : labels?.loadMore ?? t("table.loadMore")
14753
+ })] })]
14754
+ });
14755
+ }
14756
+ //#endregion
14757
+ //#region src/tables/LoadMoreFooter/block.meta.ts
14758
+ const meta$38 = {
14759
+ name: "Load more footer",
14760
+ family: "tables",
14761
+ status: "beta",
14762
+ description: "A load more button and loaded-count summary for appended lists without a total or page count. Cursor mode uses nextCursor and optional hasMore; flag mode omits nextCursor and uses hasMore. Compose with DataTable paginated={false} or Collapsible and JsonViewer cards. The consumer owns rows, filters and cursor normalization. Each attempt must settle loading=false together with its result in one update; split settles are unsupported. Keep cursor, hasMore, counts and lastAppend unchanged on failure. Cursor failures replace the button with ErrorPanel; flag failures keep the same button. Exhaustion removes every control even on failure. Focus moves only when the focused control is removed, to its replacement or exhaustedFocusTarget (summary by default, root optionally). lastAppend uses increasing seq values for successful appends, never initial loads, replacements or failures. New appended counts are announced politely; settled errors assertively. Self-wraps in LiveAnnouncer when needed. Every label has translated defaults and per-key overrides.",
14763
+ labels: [
14764
+ {
14765
+ key: "loadMore",
14766
+ type: "string",
14767
+ state: "Available and idle: button name"
14768
+ },
14769
+ {
14770
+ key: "loading",
14771
+ type: "string",
14772
+ state: "Loading: button name; ErrorPanel uses its own translated busy text"
14773
+ },
14774
+ {
14775
+ key: "retry",
14776
+ type: "string",
14777
+ state: "Failed and available: retry button name"
14778
+ },
14779
+ {
14780
+ key: "group",
14781
+ type: "string",
14782
+ state: "Always: root group accessible name"
14783
+ },
14784
+ {
14785
+ key: "moreAvailable",
14786
+ type: "string",
14787
+ state: "Available: visible summary note"
14788
+ },
14789
+ {
14790
+ key: "summary",
14791
+ type: "(count: number) => string",
14792
+ state: "Always: loaded-count summary and default exhaustion focus target"
14793
+ },
14794
+ {
14795
+ key: "loadedAnnouncement",
14796
+ type: "(count: number) => string",
14797
+ state: "New lastAppend.seq with positive count: polite announcement"
14798
+ }
14799
+ ],
14800
+ uses: [
14801
+ "Button",
14802
+ "ErrorPanel",
14803
+ "LiveAnnouncer"
14804
+ ]
14805
+ };
14806
+ //#endregion
14241
14807
  //#region src/tables/TruncatedCollectionFooter/fixtures.ts
14242
14808
  /** Meaningful runtime defaults for the JavaScript catalogue preview. */
14243
14809
  const TRUNCATED_COLLECTION_PREVIEW = {
@@ -14277,7 +14843,7 @@ function TruncatedCollectionFooter({ visibleCount = TRUNCATED_COLLECTION_PREVIEW
14277
14843
  }
14278
14844
  //#endregion
14279
14845
  //#region src/tables/TruncatedCollectionFooter/block.meta.ts
14280
- const meta$72 = {
14846
+ const meta$74 = {
14281
14847
  name: "Truncated collection footer",
14282
14848
  family: "tables",
14283
14849
  status: "beta",
@@ -14484,7 +15050,7 @@ function InlineEditTable({ rows: initialRows = EDITABLE_MEMBERS, fields = EDITAB
14484
15050
  }
14485
15051
  //#endregion
14486
15052
  //#region src/tables/InlineEditRow/block.meta.ts
14487
- const meta$33 = {
15053
+ const meta$34 = {
14488
15054
  name: "Inline edit row",
14489
15055
  family: "tables",
14490
15056
  status: "beta",
@@ -14583,7 +15149,7 @@ function SubordinateList({ title, headingLevel, count, columns, rows, getRowId,
14583
15149
  }
14584
15150
  //#endregion
14585
15151
  //#region src/tables/SubordinateList/block.meta.ts
14586
- const meta$67 = {
15152
+ const meta$69 = {
14587
15153
  name: "Subordinate list",
14588
15154
  family: "tables",
14589
15155
  status: "beta",
@@ -14760,7 +15326,7 @@ function MembersTable({ members: members$1 = members, roles = memberRoles, curre
14760
15326
  }
14761
15327
  //#endregion
14762
15328
  //#region src/team/MembersTable/block.meta.ts
14763
- const meta$38 = {
15329
+ const meta$40 = {
14764
15330
  name: "Members table",
14765
15331
  family: "team",
14766
15332
  status: "stable",
@@ -14938,7 +15504,7 @@ function NotificationMatrix({ channels = notificationChannels, events = notifica
14938
15504
  }
14939
15505
  //#endregion
14940
15506
  //#region src/team/NotificationMatrix/block.meta.ts
14941
- const meta$42 = {
15507
+ const meta$44 = {
14942
15508
  name: "Notification matrix",
14943
15509
  family: "team",
14944
15510
  status: "stable",
@@ -15100,7 +15666,7 @@ function PendingInvitations({ invitations: invitations$1 = invitations, onResend
15100
15666
  }
15101
15667
  //#endregion
15102
15668
  //#region src/team/PendingInvitations/block.meta.ts
15103
- const meta$47 = {
15669
+ const meta$49 = {
15104
15670
  name: "Pending invitations",
15105
15671
  family: "team",
15106
15672
  status: "stable",
@@ -15225,7 +15791,7 @@ function ProfileHeader({ profile: profile$1 = profile, onAvatarChange = () => {}
15225
15791
  }
15226
15792
  //#endregion
15227
15793
  //#region src/team/ProfileHeader/block.meta.ts
15228
- const meta$51 = {
15794
+ const meta$53 = {
15229
15795
  name: "Profile header",
15230
15796
  family: "team",
15231
15797
  status: "stable",
@@ -15400,7 +15966,7 @@ function SessionsDevices({ sessions = deviceSessions, onRevoke, onRevokeOthers,
15400
15966
  }
15401
15967
  //#endregion
15402
15968
  //#region src/team/SessionsDevices/block.meta.ts
15403
- const meta$57 = {
15969
+ const meta$59 = {
15404
15970
  name: "Sessions and devices",
15405
15971
  family: "team",
15406
15972
  status: "stable",
@@ -15412,6 +15978,6 @@ const meta$57 = {
15412
15978
  ]
15413
15979
  };
15414
15980
  //#endregion
15415
- export { ASSISTANT_STATUSES, ActivityFeed, AgendaList, AppSidebar, AppSidebarFooter, AppSidebarHeader, AppSidebarNav, AppTopbar, AssistantCardGrid, AuthDivider, AuthHeader, BulkActionBar, COLUMN_VARIANT_CLASSES, COMMENT_AUTHOR, COST_BY_RANGE, COST_RANGES, ChartCard, CodePanel, ColumnResizeHandle, ColumnVisibilityMenu, CommentThread, ComparisonTable, ConfirmDestructive, ConfirmDestructiveDialog, CostBreakdown, CreateApiKeyDialog, CredentialDisclosureDialog, DEFAULT_COLUMN_WIDTH, DEPLOYMENT_COLUMNS, DEPLOYMENT_DEFAULT_FILTERS, DEPLOYMENT_DETAILS, DEPLOYMENT_EVENTS, DEPLOYMENT_FILTER_FIELDS, DEPLOYMENT_ROWS, DEPLOYMENT_SAVED_VIEWS, DangerZone, DataTable, ViewSwitcher as DataTableViewSwitcher, DateRangeFilter, DensityToggle, DescriptionListCard, DialogWizard, EDITABLE_MEMBERS, EDITABLE_MEMBER_FIELDS, EditableCell, EnvironmentBadge, ErrorPanel, EvaluationScorecard, Faq, FeatureGrid, FileUploadPanel, FilterBar, FirstRunEmpty, FlowBuilder, ForgotPasswordForm, FormSection, GlobalSearch, Hero, HeroScreenshotPlaceholder, InlineCallout, InlineEditRow, InlineEditTable, InviteMembersDialog, InvoiceTable, KPI_ITEMS, KpiRow, LOG_LEVELS, ListSkeleton, LogViewer, MAX_COLUMN_WIDTH, MIN_COLUMN_WIDTH, MODEL_KEY_STATUSES, MembersTable, MfaChallenge, ModelKeysList, MonthCalendar, NoAccessEmpty, NoResultsEmpty, NodeInspector, NodePalette, NotificationMatrix, PROJECT_ACTIVITY, PageHeader, PageSkeleton, PageToolbar, PaginationFooter, PaymentMethodCard, PendingInvitations, PlanCard, PlanDefinitionCard, PricingTable, ProfileHeader, PromptEditor, QuotaMeters, RESOURCE_CARDS, REVIEW_COMMENTS, ResetPasswordForm, ResourceCardGrid, RunConsole, SPAN_STATUSES, STAT_RANGES, SectionHeader, SessionsDevices, SettingsRow, SignInForm, SignUpForm, SpanDetails, SpendVsBudget, SsoButtons, StatCard, StatusTimeline, StickyActionBar, SubordinateList, SystemBanner, TRAFFIC_BUCKETS, TRAFFIC_BY_RANGE, TRAFFIC_RANGES, TableSkeleton, TimeSlotPicker, TokenCostCard, TraceWaterfall, TrendDelta, TruncatedCollectionFooter, ValidationSummary, WeekCalendar, meta as activityFeedMeta, meta$1 as agendaListMeta, apiKeyExpiries, apiKeyScopes, meta$2 as appSidebarMeta, appSidebarNavGroups, appSidebarUsage, appSidebarUser, appSidebarWorkspaces, appTopbarBreadcrumbs, meta$3 as appTopbarMeta, appTopbarNotifications, meta$4 as assistantCardGridMeta, meta$5 as bulkActionBarMeta, meta$6 as chartCardMeta, clampColumnWidth, meta$7 as codePanelMeta, columnAlign, columnWidthOf, meta$8 as commentThreadMeta, compareValues, meta$9 as comparisonTableMeta, meta$10 as confirmDestructiveMeta, meta$11 as costBreakdownMeta, meta$12 as createApiKeyDialogMeta, meta$13 as credentialDisclosureDialogMeta, dangerZoneActions, meta$14 as dangerZoneMeta, meta$15 as dataTableMeta, meta$16 as dateRangeFilterMeta, defaultEventKinds, meta$17 as descriptionListCardMeta, dialogWizardCopy, meta$18 as dialogWizardMeta, dialogWizardSteps, meta$19 as emptyStatesMeta, meta$20 as environmentBadgeMeta, environmentTones, meta$21 as errorPanelMeta, meta$22 as evaluationScorecardMeta, extractPromptVariables, meta$23 as faqMeta, meta$24 as featureGridMeta, meta$25 as fileUploadPanelMeta, meta$26 as filterBarMeta, firstRunSteps, meta$27 as flowBuilderMeta, meta$28 as forgotPasswordFormMeta, meta$29 as formSectionMeta, formatCell, formatSpanDuration, generateDemoSecret, generateDeployments, globalSearchActions, meta$30 as globalSearchMeta, globalSearchPages, globalSearchRecent, globalSearchRecords, groupActivityByDay, groupKeyOf, groupRows, meta$31 as heroMeta, meta$32 as inlineCalloutMeta, meta$33 as inlineEditRowMeta, meta$34 as inviteMembersDialogMeta, meta$35 as invoiceTableMeta, meta$36 as kpiRowMeta, meta$37 as logViewerMeta, memberRoles, meta$38 as membersTableMeta, meta$39 as mfaChallengeMeta, meta$40 as modelKeysListMeta, meta$41 as monthCalendarMeta, noAccessSample, noResultsSample, notificationChannels, notificationDefaults, notificationEvents, meta$42 as notificationMatrixMeta, orderColumns, pageCountOf, pageHeaderActions, pageHeaderBreadcrumbs, meta$43 as pageHeaderMeta, pageHeaderTabs, meta$44 as pageToolbarMeta, pageToolbarViews, paginate, meta$45 as paginationFooterMeta, meta$46 as paymentMethodCardMeta, meta$47 as pendingInvitationsMeta, meta$48 as planCardMeta, meta$49 as planDefinitionCardMeta, meta$50 as pricingTableMeta, meta$51 as profileHeaderMeta, meta$52 as promptEditorMeta, meta$53 as quotaMetersMeta, meta$54 as resetPasswordFormMeta, meta$55 as resourceCardGridMeta, runningTraceSpans, sameViewState, sampleBudget, sampleComparisonPlans, sampleComparisonSections, sampleCosts, deviceSessions as sampleDeviceSessions, sampleFaqs, sampleFeatures, invitations as sampleInvitations, sampleInvoices, members as sampleMembers, samplePaymentMethod, samplePlan, samplePlanDefinition, samplePricingTiers, profile as sampleProfile, sampleQuotas, sampleEvents as sampleScheduleEvents, sampleToday as sampleScheduleToday, sampleSpend, sampleTimeSlots, meta$56 as sectionHeaderMeta, selectionState, meta$57 as sessionsDevicesMeta, setColumnPin, meta$58 as settingsRowMeta, meta$59 as signInFormMeta, meta$60 as signUpFormMeta, simulateUpload, meta$61 as skeletonsMeta, sortRows, meta$62 as spendVsBudgetMeta, meta$63 as ssoButtonsMeta, ssoProviders, meta$64 as statCardMeta, meta$65 as statusTimelineMeta, meta$66 as stickyActionBarMeta, meta$67 as subordinateListMeta, meta$68 as systemBannerMeta, meta$69 as timeSlotPickerMeta, toggleAll, toggleOne, meta$70 as tokenCostCardMeta, traceSpans, meta$71 as traceWaterfallMeta, meta$72 as truncatedCollectionFooterMeta, uploadItems, validationIssues, meta$73 as validationSummaryMeta, meta$74 as weekCalendarMeta };
15981
+ export { ASSISTANT_STATUSES, ActivityFeed, AgendaList, AppSidebar, AppSidebarFooter, AppSidebarHeader, AppSidebarNav, AppTopbar, AssistantCardGrid, AuthDivider, AuthHeader, BulkActionBar, COLUMN_VARIANT_CLASSES, COMMENT_AUTHOR, COST_BY_RANGE, COST_RANGES, ChartCard, CodePanel, ColumnResizeHandle, ColumnVisibilityMenu, CommentThread, ComparisonTable, ConfirmDestructive, ConfirmDestructiveDialog, CostBreakdown, CreateApiKeyDialog, CredentialDisclosureDialog, CursorPagerFooter, DEFAULT_COLUMN_WIDTH, DEPLOYMENT_COLUMNS, DEPLOYMENT_DEFAULT_FILTERS, DEPLOYMENT_DETAILS, DEPLOYMENT_EVENTS, DEPLOYMENT_FILTER_FIELDS, DEPLOYMENT_ROWS, DEPLOYMENT_SAVED_VIEWS, DangerZone, DataTable, ViewSwitcher as DataTableViewSwitcher, DateRangeFilter, DensityToggle, DescriptionListCard, DialogWizard, EDITABLE_MEMBERS, EDITABLE_MEMBER_FIELDS, EditableCell, EnvironmentBadge, ErrorPanel, EvaluationScorecard, Faq, FeatureGrid, FileUploadPanel, FilterBar, FirstRunEmpty, FlowBuilder, ForgotPasswordForm, FormSection, GlobalSearch, Hero, HeroScreenshotPlaceholder, InlineCallout, InlineEditRow, InlineEditTable, InviteMembersDialog, InvoiceTable, KPI_ITEMS, KpiRow, LOG_LEVELS, ListSkeleton, LoadMoreFooter, LogViewer, MAX_COLUMN_WIDTH, MIN_COLUMN_WIDTH, MODEL_KEY_STATUSES, MembersTable, MfaChallenge, ModelKeysList, MonthCalendar, NoAccessEmpty, NoResultsEmpty, NodeInspector, NodePalette, NotFoundEmpty, NotificationMatrix, PROJECT_ACTIVITY, PageHeader, PageSkeleton, PageToolbar, PaginationFooter, PaymentMethodCard, PendingInvitations, PlanCard, PlanDefinitionCard, PricingTable, ProfileHeader, PromptEditor, QuotaMeters, RESOURCE_CARDS, REVIEW_COMMENTS, ResetPasswordForm, ResourceCardGrid, RunConsole, SPAN_STATUSES, STAT_RANGES, SectionHeader, SessionsDevices, SettingsRow, SignInForm, SignUpForm, SpanDetails, SpendVsBudget, SsoButtons, StatCard, StatusTimeline, StickyActionBar, SubordinateList, SystemBanner, TRAFFIC_BUCKETS, TRAFFIC_BY_RANGE, TRAFFIC_RANGES, TableSkeleton, TimeSlotPicker, TokenCostCard, TraceWaterfall, TrendDelta, TruncatedCollectionFooter, ValidationSummary, WeekCalendar, meta as activityFeedMeta, meta$1 as agendaListMeta, apiKeyExpiries, apiKeyScopes, meta$2 as appSidebarMeta, appSidebarNavGroups, appSidebarUsage, appSidebarUser, appSidebarWorkspaces, appTopbarBreadcrumbs, meta$3 as appTopbarMeta, appTopbarNotifications, meta$4 as assistantCardGridMeta, meta$5 as bulkActionBarMeta, meta$6 as chartCardMeta, clampColumnWidth, meta$7 as codePanelMeta, columnAlign, columnWidthOf, meta$8 as commentThreadMeta, compareValues, meta$9 as comparisonTableMeta, meta$10 as confirmDestructiveMeta, meta$11 as costBreakdownMeta, meta$12 as createApiKeyDialogMeta, meta$13 as credentialDisclosureDialogMeta, meta$14 as cursorPagerFooterMeta, dangerZoneActions, meta$15 as dangerZoneMeta, meta$16 as dataTableMeta, meta$17 as dateRangeFilterMeta, defaultEventKinds, meta$18 as descriptionListCardMeta, dialogWizardCopy, meta$19 as dialogWizardMeta, dialogWizardSteps, meta$20 as emptyStatesMeta, meta$21 as environmentBadgeMeta, environmentTones, meta$22 as errorPanelMeta, meta$23 as evaluationScorecardMeta, extractPromptVariables, meta$24 as faqMeta, meta$25 as featureGridMeta, meta$26 as fileUploadPanelMeta, meta$27 as filterBarMeta, firstRunSteps, meta$28 as flowBuilderMeta, meta$29 as forgotPasswordFormMeta, meta$30 as formSectionMeta, formatCell, formatSpanDuration, generateDemoSecret, generateDeployments, globalSearchActions, meta$31 as globalSearchMeta, globalSearchPages, globalSearchRecent, globalSearchRecords, groupActivityByDay, groupKeyOf, groupRows, meta$32 as heroMeta, meta$33 as inlineCalloutMeta, meta$34 as inlineEditRowMeta, meta$35 as inviteMembersDialogMeta, meta$36 as invoiceTableMeta, meta$37 as kpiRowMeta, meta$38 as loadMoreFooterMeta, meta$39 as logViewerMeta, memberRoles, meta$40 as membersTableMeta, meta$41 as mfaChallengeMeta, meta$42 as modelKeysListMeta, meta$43 as monthCalendarMeta, noAccessSample, noResultsSample, notFoundSample, notificationChannels, notificationDefaults, notificationEvents, meta$44 as notificationMatrixMeta, orderColumns, pageCountOf, pageHeaderActions, pageHeaderBreadcrumbs, meta$45 as pageHeaderMeta, pageHeaderTabs, meta$46 as pageToolbarMeta, pageToolbarViews, paginate, meta$47 as paginationFooterMeta, meta$48 as paymentMethodCardMeta, meta$49 as pendingInvitationsMeta, meta$50 as planCardMeta, meta$51 as planDefinitionCardMeta, meta$52 as pricingTableMeta, meta$53 as profileHeaderMeta, meta$54 as promptEditorMeta, meta$55 as quotaMetersMeta, meta$56 as resetPasswordFormMeta, meta$57 as resourceCardGridMeta, runningTraceSpans, sameViewState, sampleBudget, sampleComparisonPlans, sampleComparisonSections, sampleCosts, deviceSessions as sampleDeviceSessions, sampleFaqs, sampleFeatures, invitations as sampleInvitations, sampleInvoices, members as sampleMembers, samplePaymentMethod, samplePlan, samplePlanDefinition, samplePricingTiers, profile as sampleProfile, sampleQuotas, sampleEvents as sampleScheduleEvents, sampleToday as sampleScheduleToday, sampleSpend, sampleTimeSlots, meta$58 as sectionHeaderMeta, selectionState, meta$59 as sessionsDevicesMeta, setColumnPin, meta$60 as settingsRowMeta, meta$61 as signInFormMeta, meta$62 as signUpFormMeta, simulateUpload, meta$63 as skeletonsMeta, sortRows, meta$64 as spendVsBudgetMeta, meta$65 as ssoButtonsMeta, ssoProviders, meta$66 as statCardMeta, meta$67 as statusTimelineMeta, meta$68 as stickyActionBarMeta, meta$69 as subordinateListMeta, meta$70 as systemBannerMeta, meta$71 as timeSlotPickerMeta, toggleAll, toggleOne, meta$72 as tokenCostCardMeta, traceSpans, meta$73 as traceWaterfallMeta, meta$74 as truncatedCollectionFooterMeta, uploadItems, validationIssues, meta$75 as validationSummaryMeta, meta$76 as weekCalendarMeta };
15416
15982
 
15417
15983
  //# sourceMappingURL=index.js.map