@gntik-ai/blocks 0.6.0 → 0.7.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 (47) hide show
  1. package/dist/index.d.ts +178 -70
  2. package/dist/index.js +621 -200
  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/tables/CursorPagerFooter/CursorPagerFooter.examples.test.tsx +33 -0
  20. package/src/tables/CursorPagerFooter/CursorPagerFooter.test.tsx +51 -0
  21. package/src/tables/CursorPagerFooter/CursorPagerFooter.tsx +10 -0
  22. package/src/tables/CursorPagerFooter/block.meta.ts +23 -0
  23. package/src/tables/CursorPagerFooter/examples/Busy.tsx +7 -0
  24. package/src/tables/CursorPagerFooter/examples/CursorStack.tsx +40 -0
  25. package/src/tables/CursorPagerFooter/examples/Hidden.tsx +16 -0
  26. package/src/tables/CursorPagerFooter/examples/RowsPerPage.tsx +21 -0
  27. package/src/tables/CursorPagerFooter/fixtures.ts +13 -0
  28. package/src/tables/DataTable/DataTable.server-pagination.test.tsx +173 -0
  29. package/src/tables/DataTable/DataTable.tsx +20 -12
  30. package/src/tables/DataTable/block.meta.ts +2 -1
  31. package/src/tables/DataTable/data-table-props.ts +27 -4
  32. package/src/tables/DataTable/examples/server-pagination.tsx +68 -0
  33. package/src/tables/LoadMoreFooter/LoadMoreFooter.announcements.test.tsx +106 -0
  34. package/src/tables/LoadMoreFooter/LoadMoreFooter.examples.test.tsx +36 -0
  35. package/src/tables/LoadMoreFooter/LoadMoreFooter.labels.test.tsx +71 -0
  36. package/src/tables/LoadMoreFooter/LoadMoreFooter.test.tsx +184 -0
  37. package/src/tables/LoadMoreFooter/LoadMoreFooter.tsx +151 -0
  38. package/src/tables/LoadMoreFooter/block.meta.ts +28 -0
  39. package/src/tables/LoadMoreFooter/examples/cards.tsx +22 -0
  40. package/src/tables/LoadMoreFooter/examples/cursor.tsx +25 -0
  41. package/src/tables/LoadMoreFooter/examples/exhausted.tsx +6 -0
  42. package/src/tables/LoadMoreFooter/examples/failed.tsx +13 -0
  43. package/src/tables/LoadMoreFooter/examples/flag.tsx +33 -0
  44. package/src/tables/LoadMoreFooter/examples/useMockCursor.ts +30 -0
  45. package/src/tables/LoadMoreFooter/fixtures.ts +9 -0
  46. package/src/tables/LoadMoreFooter/useLoadMoreFooter.ts +56 -0
  47. package/src/tables/index.ts +4 -0
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { Fragment, createElement, useCallback, useEffect, 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",
@@ -8081,7 +8240,7 @@ function DateRangeFilter({ value, defaultValue, onValueChange, presets = DEFAULT
8081
8240
  }
8082
8241
  //#endregion
8083
8242
  //#region src/forms/DateRangeFilter/block.meta.ts
8084
- const meta$16 = {
8243
+ const meta$17 = {
8085
8244
  name: "Date range filter",
8086
8245
  family: "forms",
8087
8246
  status: "stable",
@@ -8370,7 +8529,7 @@ function FileRow({ item, onRemove, onRetry }) {
8370
8529
  }
8371
8530
  //#endregion
8372
8531
  //#region src/forms/FileUploadPanel/block.meta.ts
8373
- const meta$25 = {
8532
+ const meta$26 = {
8374
8533
  name: "File upload panel",
8375
8534
  family: "forms",
8376
8535
  status: "stable",
@@ -8433,7 +8592,7 @@ function FormSection({ title = "General", description = "Basic details shown to
8433
8592
  }
8434
8593
  //#endregion
8435
8594
  //#region src/forms/FormSection/block.meta.ts
8436
- const meta$29 = {
8595
+ const meta$30 = {
8437
8596
  name: "Form section",
8438
8597
  family: "forms",
8439
8598
  status: "stable",
@@ -8600,7 +8759,7 @@ function InviteMembersDialog({ roles = memberRoles, defaultRole = "member", onIn
8600
8759
  }
8601
8760
  //#endregion
8602
8761
  //#region src/forms/InviteMembersDialog/block.meta.ts
8603
- const meta$34 = {
8762
+ const meta$35 = {
8604
8763
  name: "Invite members dialog",
8605
8764
  family: "forms",
8606
8765
  status: "stable",
@@ -8658,7 +8817,7 @@ function SettingsRow({ label = "Deployment notifications", description = "Email
8658
8817
  }
8659
8818
  //#endregion
8660
8819
  //#region src/forms/SettingsRow/block.meta.ts
8661
- const meta$58 = {
8820
+ const meta$60 = {
8662
8821
  name: "Settings row",
8663
8822
  family: "forms",
8664
8823
  status: "stable",
@@ -8683,7 +8842,7 @@ function DialogWizard({ steps, current = 0, size = "dialog", stepError, reviewSt
8683
8842
  }
8684
8843
  //#endregion
8685
8844
  //#region src/forms/DialogWizard/block.meta.ts
8686
- const meta$18 = {
8845
+ const meta$19 = {
8687
8846
  name: "Dialog wizard",
8688
8847
  family: "forms",
8689
8848
  status: "beta",
@@ -8722,7 +8881,7 @@ const dialogWizardCopy = {
8722
8881
  };
8723
8882
  //#endregion
8724
8883
  //#region src/forms/ValidationSummary/block.meta.ts
8725
- const meta$73 = {
8884
+ const meta$75 = {
8726
8885
  name: "Validation summary",
8727
8886
  family: "forms",
8728
8887
  status: "stable",
@@ -8868,7 +9027,7 @@ function Hero({ variant = "centered", eyebrow = "New · Usage-based billing", ti
8868
9027
  }
8869
9028
  //#endregion
8870
9029
  //#region src/marketing/Hero/block.meta.ts
8871
- const meta$31 = {
9030
+ const meta$32 = {
8872
9031
  name: "Hero",
8873
9032
  family: "marketing",
8874
9033
  status: "beta",
@@ -8973,7 +9132,7 @@ function FeatureGrid({ features = sampleFeatures, eyebrow = "Everything included
8973
9132
  }
8974
9133
  //#endregion
8975
9134
  //#region src/marketing/FeatureGrid/block.meta.ts
8976
- const meta$24 = {
9135
+ const meta$25 = {
8977
9136
  name: "Feature grid",
8978
9137
  family: "marketing",
8979
9138
  status: "beta",
@@ -9252,7 +9411,7 @@ function TierBody({ tier, tierId, cycle, money, TierHeading, currentTierId, curr
9252
9411
  }
9253
9412
  //#endregion
9254
9413
  //#region src/marketing/PricingTable/block.meta.ts
9255
- const meta$50 = {
9414
+ const meta$52 = {
9256
9415
  name: "Pricing table",
9257
9416
  family: "marketing",
9258
9417
  status: "beta",
@@ -9332,7 +9491,7 @@ function Faq({ items = sampleFaqs, title = "Frequently asked questions", descrip
9332
9491
  }
9333
9492
  //#endregion
9334
9493
  //#region src/marketing/Faq/block.meta.ts
9335
- const meta$23 = {
9494
+ const meta$24 = {
9336
9495
  name: "FAQ",
9337
9496
  family: "marketing",
9338
9497
  status: "beta",
@@ -9860,7 +10019,7 @@ function PageHeader({ as: Root = "header", breadcrumbs = pageHeaderBreadcrumbs,
9860
10019
  }
9861
10020
  //#endregion
9862
10021
  //#region src/page-chrome/PageHeader/block.meta.ts
9863
- const meta$43 = {
10022
+ const meta$45 = {
9864
10023
  name: "Page header",
9865
10024
  family: "page-chrome",
9866
10025
  status: "beta",
@@ -9914,7 +10073,7 @@ function SectionHeader({ title = "Policies", description = "Guardrails applied t
9914
10073
  }
9915
10074
  //#endregion
9916
10075
  //#region src/page-chrome/SectionHeader/block.meta.ts
9917
- const meta$56 = {
10076
+ const meta$58 = {
9918
10077
  name: "Section header",
9919
10078
  family: "page-chrome",
9920
10079
  status: "beta",
@@ -10007,7 +10166,7 @@ function PageToolbar({ search, defaultSearch = "", onSearchChange, searchLabel:
10007
10166
  }
10008
10167
  //#endregion
10009
10168
  //#region src/page-chrome/PageToolbar/block.meta.ts
10010
- const meta$44 = {
10169
+ const meta$46 = {
10011
10170
  name: "Page toolbar",
10012
10171
  family: "page-chrome",
10013
10172
  status: "beta",
@@ -10063,7 +10222,7 @@ function StickyActionBar({ dirty = true, saving = false, onSave, onCancel, dirty
10063
10222
  }
10064
10223
  //#endregion
10065
10224
  //#region src/page-chrome/StickyActionBar/block.meta.ts
10066
- const meta$66 = {
10225
+ const meta$68 = {
10067
10226
  name: "Sticky action bar",
10068
10227
  family: "page-chrome",
10069
10228
  status: "beta",
@@ -10791,7 +10950,7 @@ function MonthCalendar({ events = sampleEvents, today = sampleToday, defaultMont
10791
10950
  }
10792
10951
  //#endregion
10793
10952
  //#region src/scheduling/MonthCalendar/block.meta.ts
10794
- const meta$41 = {
10953
+ const meta$43 = {
10795
10954
  name: "Month calendar",
10796
10955
  family: "scheduling",
10797
10956
  status: "beta",
@@ -10985,7 +11144,7 @@ function WeekCalendar({ events = sampleEvents, today = sampleToday, now, default
10985
11144
  }
10986
11145
  //#endregion
10987
11146
  //#region src/scheduling/WeekCalendar/block.meta.ts
10988
- const meta$74 = {
11147
+ const meta$76 = {
10989
11148
  name: "Week calendar",
10990
11149
  family: "scheduling",
10991
11150
  status: "beta",
@@ -11217,7 +11376,7 @@ function TimeSlotPicker({ slots = sampleTimeSlots, value, defaultValue = null, o
11217
11376
  }
11218
11377
  //#endregion
11219
11378
  //#region src/scheduling/TimeSlotPicker/block.meta.ts
11220
- const meta$69 = {
11379
+ const meta$71 = {
11221
11380
  name: "Time slot picker",
11222
11381
  family: "scheduling",
11223
11382
  status: "beta",
@@ -11743,7 +11902,7 @@ const meta$3 = {
11743
11902
  };
11744
11903
  //#endregion
11745
11904
  //#region src/shell/EnvironmentBadge/block.meta.ts
11746
- const meta$20 = {
11905
+ const meta$21 = {
11747
11906
  name: "Environment badge",
11748
11907
  family: "shell",
11749
11908
  status: "beta",
@@ -11752,7 +11911,7 @@ const meta$20 = {
11752
11911
  };
11753
11912
  //#endregion
11754
11913
  //#region src/shell/GlobalSearch/block.meta.ts
11755
- const meta$30 = {
11914
+ const meta$31 = {
11756
11915
  name: "Global search",
11757
11916
  family: "shell",
11758
11917
  status: "beta",
@@ -13271,13 +13430,14 @@ const ROW_HEIGHT = {
13271
13430
  * and empty states, client-side sort + pagination, optional collapsible row groups (`groupBy`),
13272
13431
  * column resize and pinning, row virtualization, inline cell editing and saved views.
13273
13432
  */
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 = [
13433
+ 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
13434
  10,
13276
13435
  25,
13277
13436
  50
13278
13437
  ], 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
13438
  const { t } = useI18n();
13280
13439
  const singleMode = selectionMode === "single";
13440
+ const serverMode = paginationMode === "server";
13281
13441
  const selectable = selectionMode === void 0 ? selectableProp : selectionMode === "multiple";
13282
13442
  const selectionColumn = selectable || singleMode;
13283
13443
  const paginated = !singleMode && (paginatedProp ?? true);
@@ -13309,10 +13469,10 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13309
13469
  });
13310
13470
  const [innerCollapsed, setInnerCollapsed] = useState(() => new Set(defaultCollapsedGroups));
13311
13471
  const collapsed = collapsedProp ? new Set(collapsedProp) : innerCollapsed;
13312
- const sortedRows = manualSorting ? [...rows] : sortRows(rows, columns, sort);
13472
+ const sortedRows = serverMode ? rows : manualSorting ? [...rows] : sortRows(rows, columns, sort);
13313
13473
  const allGroups = effectiveGroupBy ? groupRows(sortedRows, effectiveGroupBy, rows) : null;
13314
13474
  const sorted = allGroups ? allGroups.flatMap((g) => g.rows) : sortedRows;
13315
- const pageRows = paginated ? paginate(sorted, page, pageSize) : sorted;
13475
+ const pageRows = serverMode ? rows : paginated ? paginate(sorted, page, pageSize) : sorted;
13316
13476
  const pageIds = (effectiveGroupBy ? pageRows.filter((row) => !collapsed.has(groupKeyOf(row, effectiveGroupBy))) : pageRows).map(getRowId);
13317
13477
  const header = selectionState(pageIds, selected);
13318
13478
  const selectedList = rows.map(getRowId).filter((id) => selected.has(id));
@@ -13321,6 +13481,7 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13321
13481
  onSelectionChange?.(rows.map(getRowId).filter((id) => next.has(id)));
13322
13482
  };
13323
13483
  const changeSort = (columnId, direction) => {
13484
+ if (serverMode) return;
13324
13485
  const next = {
13325
13486
  columnId,
13326
13487
  direction: sort?.columnId === columnId ? direction : "ascending"
@@ -13390,7 +13551,7 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13390
13551
  const applyState = (state) => {
13391
13552
  const nextSort = state.sort ?? null;
13392
13553
  setInnerSort(nextSort);
13393
- if (nextSort) onSortChange?.(nextSort);
13554
+ if (nextSort && !serverMode) onSortChange?.(nextSort);
13394
13555
  setHiddenList(state.hiddenColumns ?? defaultHidden);
13395
13556
  setWidths(state.columnWidths ?? defaultColumnWidths);
13396
13557
  setPinned(state.pinnedColumns ?? defaultPinnedColumns);
@@ -13398,7 +13559,7 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13398
13559
  setGroupOverride(nextGroup === groupName(groupBy) && typeof groupBy !== "function" ? void 0 : nextGroup);
13399
13560
  if (nextGroup !== currentState.groupBy) onGroupByChange?.(nextGroup);
13400
13561
  if (state.filters !== filters) onFiltersChange?.(state.filters);
13401
- setPage(1);
13562
+ if (!serverMode) setPage(1);
13402
13563
  };
13403
13564
  const viewsApi = useTableViews({
13404
13565
  views: viewsProp,
@@ -13532,9 +13693,12 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13532
13693
  const bounds = widthBounds(c);
13533
13694
  return /* @__PURE__ */ jsx(DataTableHeadCell, {
13534
13695
  labels,
13535
- column: c,
13696
+ column: serverMode ? {
13697
+ ...c,
13698
+ sortable: false
13699
+ } : c,
13536
13700
  layout: layout.columns.get(c.id),
13537
- sortDirection: sort?.columnId === c.id ? sort.direction : "none",
13701
+ sortDirection: !serverMode && sort?.columnId === c.id ? sort.direction : "none",
13538
13702
  onSortChange: (dir) => changeSort(c.id, dir),
13539
13703
  resize: resizable && c.resizable !== false ? {
13540
13704
  width: columnWidthOf(c, widths),
@@ -13591,14 +13755,14 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13591
13755
  "…"
13592
13756
  ] })
13593
13757
  }),
13594
- paginated && !loading && rows.length > 0 && /* @__PURE__ */ jsx(PaginationFooter, {
13758
+ paginated && !loading && (serverMode || rows.length > 0) && /* @__PURE__ */ jsx(PaginationFooter, {
13595
13759
  labels,
13596
13760
  className: "border-t border-border px-4 py-3",
13597
- total: rows.length,
13598
- page,
13599
- onPageChange: setPage,
13600
- pageSize,
13601
- onPageSizeChange: setPageSize,
13761
+ total: serverMode ? rowCount : rows.length,
13762
+ page: serverMode ? controlledPage : page,
13763
+ onPageChange: serverMode ? onPageChange : setPage,
13764
+ pageSize: serverMode ? controlledPageSize : pageSize,
13765
+ onPageSizeChange: serverMode ? onPageSizeChange : setPageSize,
13602
13766
  pageSizeOptions,
13603
13767
  noun: caption
13604
13768
  })
@@ -13607,11 +13771,11 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13607
13771
  }
13608
13772
  //#endregion
13609
13773
  //#region src/tables/DataTable/block.meta.ts
13610
- const meta$15 = {
13774
+ const meta$16 = {
13611
13775
  name: "Data table",
13612
13776
  family: "tables",
13613
13777
  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.",
13778
+ 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
13779
  labels: [
13616
13780
  {
13617
13781
  key: "scrollRegion",
@@ -14120,7 +14284,7 @@ function FilterBar({ fields = DEPLOYMENT_FILTER_FIELDS, query: queryProp, defaul
14120
14284
  }
14121
14285
  //#endregion
14122
14286
  //#region src/tables/FilterBar/block.meta.ts
14123
- const meta$26 = {
14287
+ const meta$27 = {
14124
14288
  name: "Filter bar",
14125
14289
  family: "tables",
14126
14290
  status: "beta",
@@ -14192,8 +14356,73 @@ const meta$26 = {
14192
14356
  ]
14193
14357
  };
14194
14358
  //#endregion
14359
+ //#region src/tables/CursorPagerFooter/fixtures.ts
14360
+ const CURSOR_PAGER_PREVIEW = {
14361
+ hasPrevious: false,
14362
+ hasNext: true,
14363
+ onPrevious: () => {},
14364
+ onNext: () => {},
14365
+ shownCount: 25,
14366
+ labels: {
14367
+ shownSummary: (shownCount) => `${shownCount} records shown`,
14368
+ totalSummary: (total) => `${total} records in total`
14369
+ }
14370
+ };
14371
+ //#endregion
14372
+ //#region src/tables/CursorPagerFooter/CursorPagerFooter.tsx
14373
+ /** Responsive table footer. Forwards every cursor-pagination prop without storing cursor state. */
14374
+ function CursorPagerFooter(props = {}) {
14375
+ return /* @__PURE__ */ jsx(CursorPagination, { ...props.hasPrevious === void 0 ? CURSOR_PAGER_PREVIEW : props });
14376
+ }
14377
+ //#endregion
14378
+ //#region src/tables/CursorPagerFooter/block.meta.ts
14379
+ const meta$14 = {
14380
+ name: "Cursor pager footer",
14381
+ family: "tables",
14382
+ status: "beta",
14383
+ 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.",
14384
+ labels: [
14385
+ {
14386
+ key: "previous",
14387
+ type: "string",
14388
+ state: "Previous name, below previousLabel and above catalog defaults"
14389
+ },
14390
+ {
14391
+ key: "next",
14392
+ type: "string",
14393
+ state: "Next name, below nextLabel and above catalog defaults"
14394
+ },
14395
+ {
14396
+ key: "navLabel",
14397
+ type: "string",
14398
+ state: "Navigation name, below ariaLabel and above catalog defaults"
14399
+ },
14400
+ {
14401
+ key: "shownSummary",
14402
+ type: "(shownCount: number) => string",
14403
+ state: "Required in count form: no positive exact total"
14404
+ },
14405
+ {
14406
+ key: "totalSummary",
14407
+ type: "(total: number) => string",
14408
+ state: "Required in count form: positive exact total"
14409
+ },
14410
+ {
14411
+ key: "rowsPerPage",
14412
+ type: "string",
14413
+ state: "Required with pageSizeOptions: visible select label"
14414
+ },
14415
+ {
14416
+ key: "rowsPerPageLabel",
14417
+ type: "string",
14418
+ state: "Required with pageSizeOptions: select accessible name"
14419
+ }
14420
+ ],
14421
+ uses: ["CursorPagination"]
14422
+ };
14423
+ //#endregion
14195
14424
  //#region src/tables/PaginationFooter/block.meta.ts
14196
- const meta$45 = {
14425
+ const meta$47 = {
14197
14426
  name: "Pagination footer",
14198
14427
  family: "tables",
14199
14428
  status: "beta",
@@ -14238,6 +14467,198 @@ const meta$45 = {
14238
14467
  uses: ["SimpleSelect", "Pagination"]
14239
14468
  };
14240
14469
  //#endregion
14470
+ //#region src/tables/LoadMoreFooter/useLoadMoreFooter.ts
14471
+ /** Capture focus before React removes the control, then restore it after the replacement commits. */
14472
+ function useLoadMoreFooter(control, target, loading, error) {
14473
+ const rootRef = useRef(null);
14474
+ const summaryRef = useRef(null);
14475
+ const currentControl = useRef(null);
14476
+ const moveFocus = useRef(false);
14477
+ const inFlightCursorRef = useRef(void 0);
14478
+ useEffect(() => {
14479
+ if (!loading && !error) inFlightCursorRef.current = void 0;
14480
+ }, [loading, error]);
14481
+ const controlRef = useCallback((node) => {
14482
+ if (!node && currentControl.current?.contains(document.activeElement)) moveFocus.current = true;
14483
+ currentControl.current = node;
14484
+ }, []);
14485
+ useLayoutEffect(() => {
14486
+ if (!moveFocus.current) return;
14487
+ moveFocus.current = false;
14488
+ const nextControl = currentControl.current;
14489
+ ((nextControl?.matches("button") ? nextControl : nextControl?.querySelector("button")) ?? (target === "root" ? rootRef.current : summaryRef.current))?.focus();
14490
+ }, [control, target]);
14491
+ return {
14492
+ rootRef,
14493
+ summaryRef,
14494
+ controlRef,
14495
+ inFlightCursorRef
14496
+ };
14497
+ }
14498
+ /** Track committed results; mounting and intermediate loading states remain silent. */
14499
+ function useLoadMoreAnnouncements(loading, error, lastAppend, loadedAnnouncement) {
14500
+ const announce = useAnnounce();
14501
+ const previous = useRef({
14502
+ loading,
14503
+ error
14504
+ });
14505
+ const lastSeq = useRef(lastAppend?.seq);
14506
+ useEffect(() => {
14507
+ const before = previous.current;
14508
+ previous.current = {
14509
+ loading,
14510
+ error
14511
+ };
14512
+ if (!loading && error && (before.loading || before.error !== error)) announce(error, "assertive");
14513
+ }, [
14514
+ loading,
14515
+ error,
14516
+ announce
14517
+ ]);
14518
+ useEffect(() => {
14519
+ if (!lastAppend || lastSeq.current !== void 0 && lastAppend.seq <= lastSeq.current) return;
14520
+ lastSeq.current = lastAppend.seq;
14521
+ if (lastAppend.count > 0) announce(loadedAnnouncement(lastAppend.count), "polite");
14522
+ }, [
14523
+ lastAppend,
14524
+ loadedAnnouncement,
14525
+ announce
14526
+ ]);
14527
+ }
14528
+ //#endregion
14529
+ //#region src/tables/LoadMoreFooter/fixtures.ts
14530
+ /** Meaningful defaults for the no-props catalogue preview. */
14531
+ const LOAD_MORE_PREVIEW = {
14532
+ nextCursor: "page-2",
14533
+ loadedCount: 20
14534
+ };
14535
+ //#endregion
14536
+ //#region src/tables/LoadMoreFooter/LoadMoreFooter.tsx
14537
+ /**
14538
+ * Load more for appended lists without a total or page count. The consumer owns rows and requests.
14539
+ * With no props, renders a static catalogue preview using fixture data. Supplying any prop selects
14540
+ * the consumer contract: undefined nextCursor means flag mode and requires hasMore=true.
14541
+ * loadedCount defaults to the preview fixture; consumers should pass their actual loaded count.
14542
+ */
14543
+ function LoadMoreFooter(props = {}) {
14544
+ return useHasLiveAnnouncer() ? /* @__PURE__ */ jsx(LoadMoreFooterContent, { ...props }) : /* @__PURE__ */ jsx(LiveAnnouncer, { children: /* @__PURE__ */ jsx(LoadMoreFooterContent, { ...props }) });
14545
+ }
14546
+ function LoadMoreFooterContent(props) {
14547
+ const { t } = useI18n();
14548
+ const { nextCursor, hasMore, loading = false, error = "", exhaustedFocusTarget = "summary", loadedCount = LOAD_MORE_PREVIEW.loadedCount, labels, className } = props;
14549
+ const cursor = Object.keys(props).length === 0 ? LOAD_MORE_PREVIEW.nextCursor : nextCursor;
14550
+ const available = cursor === void 0 ? hasMore === true : typeof cursor === "string" && cursor.length > 0 && hasMore !== false;
14551
+ const failed = error.length > 0;
14552
+ const cursorMode = cursor !== void 0;
14553
+ const panel = cursorMode && failed;
14554
+ const { rootRef, summaryRef, controlRef, inFlightCursorRef } = useLoadMoreFooter(!available ? "none" : panel ? "retry" : "button", exhaustedFocusTarget, loading, error);
14555
+ const errorId = useId();
14556
+ useLoadMoreAnnouncements(loading, error, props.lastAppend, labels?.loadedAnnouncement ?? ((count) => t("table.loadedAnnouncement", { count })));
14557
+ const load = () => {
14558
+ if (loading || !available) return;
14559
+ inFlightCursorRef.current = cursor ?? void 0;
14560
+ if (cursor === void 0) props.onLoadMore?.();
14561
+ else props.onLoadMore?.(cursor ?? void 0);
14562
+ };
14563
+ const retry = () => {
14564
+ if (loading || !available) return;
14565
+ const handler = props.onRetry ?? props.onLoadMore;
14566
+ if (cursorMode) handler?.(inFlightCursorRef.current ?? cursor ?? void 0);
14567
+ else handler?.();
14568
+ };
14569
+ return /* @__PURE__ */ jsxs("div", {
14570
+ ref: rootRef,
14571
+ role: "group",
14572
+ "aria-label": labels?.group ?? t("table.loadMoreGroup"),
14573
+ tabIndex: -1,
14574
+ "aria-busy": loading,
14575
+ className: cn("flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", className),
14576
+ children: [/* @__PURE__ */ jsxs("p", {
14577
+ ref: summaryRef,
14578
+ tabIndex: -1,
14579
+ className: "text-sm text-muted-foreground tabular-nums",
14580
+ children: [
14581
+ labels?.summary?.(loadedCount) ?? t("table.loadedSummary", { count: loadedCount }),
14582
+ " ",
14583
+ available && /* @__PURE__ */ jsx("span", { children: labels?.moreAvailable ?? t("table.moreAvailable") })
14584
+ ]
14585
+ }), panel ? /* @__PURE__ */ jsx("div", {
14586
+ ref: available ? controlRef : void 0,
14587
+ children: /* @__PURE__ */ jsx(ErrorPanel, {
14588
+ title: error,
14589
+ message: null,
14590
+ code: null,
14591
+ requestId: "",
14592
+ details: "",
14593
+ secondaryAction: null,
14594
+ onRetry: available ? retry : void 0,
14595
+ retrying: loading,
14596
+ retryLabel: labels?.retry ?? t("error.retry")
14597
+ })
14598
+ }, available ? "retry" : "exhausted") : /* @__PURE__ */ jsxs(Fragment$1, { children: [failed && /* @__PURE__ */ jsx("p", {
14599
+ id: errorId,
14600
+ className: "text-sm text-destructive-text",
14601
+ children: error
14602
+ }), available && /* @__PURE__ */ jsx(Button, {
14603
+ ref: controlRef,
14604
+ loading,
14605
+ onClick: failed ? retry : load,
14606
+ "aria-describedby": failed ? errorId : void 0,
14607
+ children: loading ? labels?.loading ?? t("table.loadingMore") : failed ? labels?.retry ?? t("error.retry") : labels?.loadMore ?? t("table.loadMore")
14608
+ })] })]
14609
+ });
14610
+ }
14611
+ //#endregion
14612
+ //#region src/tables/LoadMoreFooter/block.meta.ts
14613
+ const meta$38 = {
14614
+ name: "Load more footer",
14615
+ family: "tables",
14616
+ status: "beta",
14617
+ 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.",
14618
+ labels: [
14619
+ {
14620
+ key: "loadMore",
14621
+ type: "string",
14622
+ state: "Available and idle: button name"
14623
+ },
14624
+ {
14625
+ key: "loading",
14626
+ type: "string",
14627
+ state: "Loading: button name; ErrorPanel uses its own translated busy text"
14628
+ },
14629
+ {
14630
+ key: "retry",
14631
+ type: "string",
14632
+ state: "Failed and available: retry button name"
14633
+ },
14634
+ {
14635
+ key: "group",
14636
+ type: "string",
14637
+ state: "Always: root group accessible name"
14638
+ },
14639
+ {
14640
+ key: "moreAvailable",
14641
+ type: "string",
14642
+ state: "Available: visible summary note"
14643
+ },
14644
+ {
14645
+ key: "summary",
14646
+ type: "(count: number) => string",
14647
+ state: "Always: loaded-count summary and default exhaustion focus target"
14648
+ },
14649
+ {
14650
+ key: "loadedAnnouncement",
14651
+ type: "(count: number) => string",
14652
+ state: "New lastAppend.seq with positive count: polite announcement"
14653
+ }
14654
+ ],
14655
+ uses: [
14656
+ "Button",
14657
+ "ErrorPanel",
14658
+ "LiveAnnouncer"
14659
+ ]
14660
+ };
14661
+ //#endregion
14241
14662
  //#region src/tables/TruncatedCollectionFooter/fixtures.ts
14242
14663
  /** Meaningful runtime defaults for the JavaScript catalogue preview. */
14243
14664
  const TRUNCATED_COLLECTION_PREVIEW = {
@@ -14277,7 +14698,7 @@ function TruncatedCollectionFooter({ visibleCount = TRUNCATED_COLLECTION_PREVIEW
14277
14698
  }
14278
14699
  //#endregion
14279
14700
  //#region src/tables/TruncatedCollectionFooter/block.meta.ts
14280
- const meta$72 = {
14701
+ const meta$74 = {
14281
14702
  name: "Truncated collection footer",
14282
14703
  family: "tables",
14283
14704
  status: "beta",
@@ -14484,7 +14905,7 @@ function InlineEditTable({ rows: initialRows = EDITABLE_MEMBERS, fields = EDITAB
14484
14905
  }
14485
14906
  //#endregion
14486
14907
  //#region src/tables/InlineEditRow/block.meta.ts
14487
- const meta$33 = {
14908
+ const meta$34 = {
14488
14909
  name: "Inline edit row",
14489
14910
  family: "tables",
14490
14911
  status: "beta",
@@ -14583,7 +15004,7 @@ function SubordinateList({ title, headingLevel, count, columns, rows, getRowId,
14583
15004
  }
14584
15005
  //#endregion
14585
15006
  //#region src/tables/SubordinateList/block.meta.ts
14586
- const meta$67 = {
15007
+ const meta$69 = {
14587
15008
  name: "Subordinate list",
14588
15009
  family: "tables",
14589
15010
  status: "beta",
@@ -14760,7 +15181,7 @@ function MembersTable({ members: members$1 = members, roles = memberRoles, curre
14760
15181
  }
14761
15182
  //#endregion
14762
15183
  //#region src/team/MembersTable/block.meta.ts
14763
- const meta$38 = {
15184
+ const meta$40 = {
14764
15185
  name: "Members table",
14765
15186
  family: "team",
14766
15187
  status: "stable",
@@ -14938,7 +15359,7 @@ function NotificationMatrix({ channels = notificationChannels, events = notifica
14938
15359
  }
14939
15360
  //#endregion
14940
15361
  //#region src/team/NotificationMatrix/block.meta.ts
14941
- const meta$42 = {
15362
+ const meta$44 = {
14942
15363
  name: "Notification matrix",
14943
15364
  family: "team",
14944
15365
  status: "stable",
@@ -15100,7 +15521,7 @@ function PendingInvitations({ invitations: invitations$1 = invitations, onResend
15100
15521
  }
15101
15522
  //#endregion
15102
15523
  //#region src/team/PendingInvitations/block.meta.ts
15103
- const meta$47 = {
15524
+ const meta$49 = {
15104
15525
  name: "Pending invitations",
15105
15526
  family: "team",
15106
15527
  status: "stable",
@@ -15225,7 +15646,7 @@ function ProfileHeader({ profile: profile$1 = profile, onAvatarChange = () => {}
15225
15646
  }
15226
15647
  //#endregion
15227
15648
  //#region src/team/ProfileHeader/block.meta.ts
15228
- const meta$51 = {
15649
+ const meta$53 = {
15229
15650
  name: "Profile header",
15230
15651
  family: "team",
15231
15652
  status: "stable",
@@ -15400,7 +15821,7 @@ function SessionsDevices({ sessions = deviceSessions, onRevoke, onRevokeOthers,
15400
15821
  }
15401
15822
  //#endregion
15402
15823
  //#region src/team/SessionsDevices/block.meta.ts
15403
- const meta$57 = {
15824
+ const meta$59 = {
15404
15825
  name: "Sessions and devices",
15405
15826
  family: "team",
15406
15827
  status: "stable",
@@ -15412,6 +15833,6 @@ const meta$57 = {
15412
15833
  ]
15413
15834
  };
15414
15835
  //#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 };
15836
+ 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
15837
 
15417
15838
  //# sourceMappingURL=index.js.map