@gntik-ai/blocks 0.5.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 (76) hide show
  1. package/dist/index.d.ts +337 -97
  2. package/dist/index.js +1311 -384
  3. package/dist/index.js.map +1 -1
  4. package/package.json +2 -2
  5. package/src/auth/SignUpForm/SignUpForm.configured.test.tsx +316 -0
  6. package/src/auth/SignUpForm/SignUpForm.tsx +194 -50
  7. package/src/auth/SignUpForm/block.meta.ts +15 -2
  8. package/src/auth/SignUpForm/examples/CustomFields.tsx +56 -0
  9. package/src/auth/SignUpForm/examples/Error.tsx +5 -0
  10. package/src/auth/SignUpForm/examples/Loading.tsx +6 -0
  11. package/src/auth/SignUpForm/examples/NoTerms.tsx +6 -0
  12. package/src/auth/SignUpForm/examples/Submitting.tsx +5 -0
  13. package/src/auth/SignUpForm/examples/Unavailable.tsx +15 -0
  14. package/src/auth/index.ts +1 -0
  15. package/src/auth/shared.tsx +34 -0
  16. package/src/feedback/ConfirmDestructive/ConfirmDestructive.examples.test.tsx +25 -0
  17. package/src/feedback/ConfirmDestructive/ConfirmDestructive.extended.test.tsx +252 -0
  18. package/src/feedback/ConfirmDestructive/ConfirmDestructive.focus.test.tsx +178 -0
  19. package/src/feedback/ConfirmDestructive/ConfirmDestructive.tsx +219 -28
  20. package/src/feedback/ConfirmDestructive/block.meta.ts +2 -2
  21. package/src/feedback/ConfirmDestructive/examples/FailureStates.tsx +39 -0
  22. package/src/feedback/ConfirmDestructive/examples/PlainDeletion.tsx +6 -0
  23. package/src/feedback/ConfirmDestructive/examples/SecretRevocation.tsx +34 -0
  24. package/src/feedback/EmptyStates/EmptyStates.test.tsx +11 -1
  25. package/src/feedback/EmptyStates/EmptyStates.tsx +31 -1
  26. package/src/feedback/EmptyStates/block.meta.ts +1 -1
  27. package/src/feedback/EmptyStates/fixtures.ts +5 -0
  28. package/src/feedback/ErrorPanel/ErrorPanel.test.tsx +7 -0
  29. package/src/feedback/ErrorPanel/ErrorPanel.tsx +8 -3
  30. package/src/meta.ts +2 -0
  31. package/src/tables/CursorPagerFooter/CursorPagerFooter.examples.test.tsx +33 -0
  32. package/src/tables/CursorPagerFooter/CursorPagerFooter.test.tsx +51 -0
  33. package/src/tables/CursorPagerFooter/CursorPagerFooter.tsx +10 -0
  34. package/src/tables/CursorPagerFooter/block.meta.ts +23 -0
  35. package/src/tables/CursorPagerFooter/examples/Busy.tsx +7 -0
  36. package/src/tables/CursorPagerFooter/examples/CursorStack.tsx +40 -0
  37. package/src/tables/CursorPagerFooter/examples/Hidden.tsx +16 -0
  38. package/src/tables/CursorPagerFooter/examples/RowsPerPage.tsx +21 -0
  39. package/src/tables/CursorPagerFooter/fixtures.ts +13 -0
  40. package/src/tables/DataTable/DataTable.labels.test.tsx +291 -0
  41. package/src/tables/DataTable/DataTable.overflow-labels.test.tsx +59 -0
  42. package/src/tables/DataTable/DataTable.server-pagination.test.tsx +173 -0
  43. package/src/tables/DataTable/DataTable.tsx +40 -21
  44. package/src/tables/DataTable/block.meta.ts +104 -1
  45. package/src/tables/DataTable/column-menu.tsx +10 -7
  46. package/src/tables/DataTable/data-table-body.tsx +3 -2
  47. package/src/tables/DataTable/data-table-props.ts +30 -4
  48. package/src/tables/DataTable/data-table-row.tsx +15 -4
  49. package/src/tables/DataTable/density-toggle.tsx +7 -4
  50. package/src/tables/DataTable/editable-cell.tsx +21 -8
  51. package/src/tables/DataTable/examples/server-pagination.tsx +68 -0
  52. package/src/tables/DataTable/header-cell.tsx +4 -0
  53. package/src/tables/DataTable/labels.ts +54 -0
  54. package/src/tables/DataTable/resize-handle.tsx +6 -3
  55. package/src/tables/DataTable/views.tsx +21 -14
  56. package/src/tables/FilterBar/FilterBar.labels.test.tsx +69 -0
  57. package/src/tables/FilterBar/FilterBar.tsx +45 -12
  58. package/src/tables/FilterBar/block.meta.ts +22 -0
  59. package/src/tables/LoadMoreFooter/LoadMoreFooter.announcements.test.tsx +106 -0
  60. package/src/tables/LoadMoreFooter/LoadMoreFooter.examples.test.tsx +36 -0
  61. package/src/tables/LoadMoreFooter/LoadMoreFooter.labels.test.tsx +71 -0
  62. package/src/tables/LoadMoreFooter/LoadMoreFooter.test.tsx +184 -0
  63. package/src/tables/LoadMoreFooter/LoadMoreFooter.tsx +151 -0
  64. package/src/tables/LoadMoreFooter/block.meta.ts +28 -0
  65. package/src/tables/LoadMoreFooter/examples/cards.tsx +22 -0
  66. package/src/tables/LoadMoreFooter/examples/cursor.tsx +25 -0
  67. package/src/tables/LoadMoreFooter/examples/exhausted.tsx +6 -0
  68. package/src/tables/LoadMoreFooter/examples/failed.tsx +13 -0
  69. package/src/tables/LoadMoreFooter/examples/flag.tsx +33 -0
  70. package/src/tables/LoadMoreFooter/examples/useMockCursor.ts +30 -0
  71. package/src/tables/LoadMoreFooter/fixtures.ts +9 -0
  72. package/src/tables/LoadMoreFooter/useLoadMoreFooter.ts +56 -0
  73. package/src/tables/PaginationFooter/PaginationFooter.labels.test.tsx +57 -0
  74. package/src/tables/PaginationFooter/PaginationFooter.tsx +31 -7
  75. package/src/tables/PaginationFooter/block.meta.ts +23 -0
  76. 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",
@@ -1671,6 +1671,12 @@ function authIdentifierError(value, config, messages) {
1671
1671
  if ((config?.type ?? "email") === "email" && !EMAIL_RE$1.test(trimmed) || config?.maxLength !== void 0 && trimmed.length > config.maxLength) return messages?.identifierInvalid ?? fallback;
1672
1672
  return null;
1673
1673
  }
1674
+ function authSignUpFieldError(value, field) {
1675
+ const trimmed = value.trim();
1676
+ if (!trimmed) return field.required ? field.messages?.required ?? `Enter ${field.label}.` : null;
1677
+ if (field.type === "email" && !EMAIL_RE$1.test(trimmed)) return field.messages?.invalid ?? "Enter a valid email address.";
1678
+ return null;
1679
+ }
1674
1680
  //#endregion
1675
1681
  //#region src/auth/ForgotPasswordForm/ForgotPasswordForm.tsx
1676
1682
  /** Request a reset link by email, then a "check your inbox" state with resend and a way back. */
@@ -1838,7 +1844,7 @@ function ForgotPasswordForm({ identifier, messages, ref, fieldInvalid, feedbackI
1838
1844
  }
1839
1845
  //#endregion
1840
1846
  //#region src/auth/ForgotPasswordForm/block.meta.ts
1841
- const meta$28 = {
1847
+ const meta$29 = {
1842
1848
  name: "Forgot password form",
1843
1849
  family: "auth",
1844
1850
  status: "stable",
@@ -2002,7 +2008,7 @@ function MfaChallenge({ onVerify, onResend, resendCooldown = 30, initialCooldown
2002
2008
  }
2003
2009
  //#endregion
2004
2010
  //#region src/auth/MfaChallenge/block.meta.ts
2005
- const meta$39 = {
2011
+ const meta$41 = {
2006
2012
  name: "MFA challenge",
2007
2013
  family: "auth",
2008
2014
  status: "stable",
@@ -2129,7 +2135,7 @@ function ResetPasswordForm({ onSubmit, error: errorProp, minPasswordLength = 8,
2129
2135
  }
2130
2136
  //#endregion
2131
2137
  //#region src/auth/ResetPasswordForm/block.meta.ts
2132
- const meta$54 = {
2138
+ const meta$56 = {
2133
2139
  name: "Reset password form",
2134
2140
  family: "auth",
2135
2141
  status: "stable",
@@ -2331,7 +2337,7 @@ function SignInForm({ identifier, messages, passwordHelp, passwordHelpId, ref, f
2331
2337
  }
2332
2338
  //#endregion
2333
2339
  //#region src/auth/SignInForm/block.meta.ts
2334
- const meta$59 = {
2340
+ const meta$61 = {
2335
2341
  name: "Sign-in form",
2336
2342
  family: "auth",
2337
2343
  status: "stable",
@@ -2351,10 +2357,85 @@ const meta$59 = {
2351
2357
  ]
2352
2358
  };
2353
2359
  //#endregion
2360
+ //#region src/forms/ValidationSummary/fixtures.ts
2361
+ const validationIssues = [
2362
+ {
2363
+ fieldId: "project-name",
2364
+ label: "Project name",
2365
+ message: "Enter a project name."
2366
+ },
2367
+ {
2368
+ fieldId: "billing-email",
2369
+ label: "Billing email",
2370
+ message: "Enter a valid email address, like name@company.com."
2371
+ },
2372
+ {
2373
+ fieldId: "region",
2374
+ label: "Region",
2375
+ message: "Choose a region."
2376
+ }
2377
+ ];
2378
+ //#endregion
2379
+ //#region src/forms/ValidationSummary/ValidationSummary.tsx
2380
+ const focusField = (fieldId) => {
2381
+ const el = document.getElementById(fieldId);
2382
+ if (!el) return;
2383
+ el.focus();
2384
+ el.scrollIntoView?.({ block: "center" });
2385
+ };
2386
+ /**
2387
+ * Error summary for long forms: lists every problem with a link that moves focus to the field.
2388
+ * After a failed submit it takes focus, so screen readers announce it.
2389
+ */
2390
+ function ValidationSummary({ errors = validationIssues, submitCount = 0, title, className }) {
2391
+ const ref = useRef(null);
2392
+ const hasErrors = errors.length > 0;
2393
+ useEffect(() => {
2394
+ if (submitCount > 0 && hasErrors) ref.current?.focus();
2395
+ }, [submitCount, hasErrors]);
2396
+ if (!hasErrors) return null;
2397
+ const heading = title ?? `There ${errors.length === 1 ? "is 1 problem" : `are ${errors.length} problems`} with this form`;
2398
+ return /* @__PURE__ */ jsx(Alert, {
2399
+ ref,
2400
+ tabIndex: -1,
2401
+ role: "region",
2402
+ tone: "destructive",
2403
+ title: heading,
2404
+ className: cn("focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-ring", className),
2405
+ children: /* @__PURE__ */ jsx("ul", {
2406
+ className: "mt-1 list-disc space-y-1 ps-4",
2407
+ children: errors.map((e) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Link, {
2408
+ href: `#${e.fieldId}`,
2409
+ tone: "inherit",
2410
+ underline: "always",
2411
+ onClick: (ev) => {
2412
+ ev.preventDefault();
2413
+ focusField(e.fieldId);
2414
+ },
2415
+ children: [e.label ? `${e.label}: ` : "", e.message]
2416
+ }) }, e.fieldId))
2417
+ })
2418
+ });
2419
+ }
2420
+ //#endregion
2354
2421
  //#region src/auth/SignUpForm/SignUpForm.tsx
2355
2422
  /** Account creation: name, work email, password with a strength meter and a required terms checkbox. */
2356
- function SignUpForm({ onSubmit, error: errorProp, loading: loadingProp, minPasswordLength = 8, termsHref = "#", privacyHref = "#", signInHref = "#", onSignIn, sso = /* @__PURE__ */ jsx(SsoButtons, {}), eyebrow = "Get started", title = "Create your account", description = "Set up a workspace for your team in a couple of minutes.", className }) {
2423
+ function SignUpForm({ fields, messages, unavailable, policyLoading = false, onSubmit, error: errorProp, loading: loadingProp, minPasswordLength = 8, passwordHelp, terms: termsProp, termsHref = "#", privacyHref = "#", signInHref = "#", onSignIn, sso = /* @__PURE__ */ jsx(SsoButtons, {}), eyebrow = "Get started", title = "Create your account", description = "Set up a workspace for your team in a couple of minutes.", className }) {
2357
2424
  const termsErrorId = useId();
2425
+ const fieldPrefix = useId();
2426
+ const passwordId = `${fieldPrefix}-password`;
2427
+ const termsId = `${fieldPrefix}-terms`;
2428
+ const [fieldValues, setFieldValues] = useState({});
2429
+ const [submitCount, setSubmitCount] = useState(0);
2430
+ const fieldValue = (id) => Object.hasOwn(fieldValues, id) ? fieldValues[id] ?? "" : "";
2431
+ const configuredErrors = (fields ?? []).flatMap((field) => {
2432
+ const message = authSignUpFieldError(fieldValue(field.id), field);
2433
+ return message ? [{
2434
+ fieldId: `${fieldPrefix}-field-${field.id}`,
2435
+ label: field.label,
2436
+ message
2437
+ }] : [];
2438
+ });
2358
2439
  const [name, setName] = useState("");
2359
2440
  const [email, setEmail] = useState("");
2360
2441
  const [password, setPassword] = useState("");
@@ -2365,8 +2446,62 @@ function SignUpForm({ onSubmit, error: errorProp, loading: loadingProp, minPassw
2365
2446
  const alert = errorProp ?? error;
2366
2447
  const nameInvalid = submitted && name.trim() === "";
2367
2448
  const emailInvalid = submitted && !EMAIL_RE$1.test(email.trim());
2368
- const passwordInvalid = submitted && password.length < minPasswordLength;
2369
- const termsInvalid = submitted && !terms;
2449
+ const passwordInvalid = (submitted || fields !== void 0 && password.length > 0) && password.length < minPasswordLength;
2450
+ const termsInvalid = submitted && termsProp !== false && !terms;
2451
+ const passwordError = messages?.passwordTooShort?.(minPasswordLength) ?? `Use at least ${minPasswordLength} characters.`;
2452
+ const termsError = messages?.termsRequired ?? "Accept the terms to continue.";
2453
+ const summaryErrors = [
2454
+ ...configuredErrors,
2455
+ ...password.length < minPasswordLength ? [{
2456
+ fieldId: passwordId,
2457
+ label: "Password",
2458
+ message: passwordError
2459
+ }] : [],
2460
+ ...termsProp !== false && !terms ? [{
2461
+ fieldId: termsId,
2462
+ label: "Terms",
2463
+ message: termsError
2464
+ }] : []
2465
+ ];
2466
+ if (unavailable) return /* @__PURE__ */ jsx("div", {
2467
+ className: cn(authFormClass, className),
2468
+ children: /* @__PURE__ */ jsx(Alert, {
2469
+ tone: "info",
2470
+ title: unavailable.title,
2471
+ description: unavailable.message,
2472
+ actions: unavailable.action
2473
+ })
2474
+ });
2475
+ if (policyLoading) return /* @__PURE__ */ jsxs("div", {
2476
+ className: cn(authFormClass, "flex flex-col gap-4", className),
2477
+ children: [
2478
+ /* @__PURE__ */ jsx("span", {
2479
+ role: "status",
2480
+ className: "sr-only",
2481
+ children: "Loading sign-up policy…"
2482
+ }),
2483
+ /* @__PURE__ */ jsx(Skeleton, {
2484
+ "aria-hidden": true,
2485
+ className: "h-8 w-3/4"
2486
+ }),
2487
+ /* @__PURE__ */ jsx(Skeleton, {
2488
+ "aria-hidden": true,
2489
+ className: "h-4 w-full"
2490
+ }),
2491
+ /* @__PURE__ */ jsx(Skeleton, {
2492
+ "aria-hidden": true,
2493
+ className: "h-12 w-full"
2494
+ }),
2495
+ /* @__PURE__ */ jsx(Skeleton, {
2496
+ "aria-hidden": true,
2497
+ className: "h-12 w-full"
2498
+ }),
2499
+ /* @__PURE__ */ jsx(Skeleton, {
2500
+ "aria-hidden": true,
2501
+ className: "h-12 w-full"
2502
+ })
2503
+ ]
2504
+ });
2370
2505
  return /* @__PURE__ */ jsxs("div", {
2371
2506
  className: cn(authFormClass, className),
2372
2507
  children: [
@@ -2382,7 +2517,19 @@ function SignUpForm({ onSubmit, error: errorProp, loading: loadingProp, minPassw
2382
2517
  onSubmit: (e) => {
2383
2518
  e.preventDefault();
2384
2519
  setSubmitted(true);
2385
- if (name.trim() === "" || !EMAIL_RE$1.test(email.trim()) || password.length < minPasswordLength || !terms) return;
2520
+ if (fields !== void 0) {
2521
+ setSubmitCount((count) => count + 1);
2522
+ if (summaryErrors.length > 0) return;
2523
+ const values = Object.fromEntries(fields.map((field) => [field.id, fieldValue(field.id).trim()]));
2524
+ run(() => onSubmit?.({
2525
+ name: values.name ?? "",
2526
+ email: values.email ?? "",
2527
+ password,
2528
+ fields: values
2529
+ }));
2530
+ return;
2531
+ }
2532
+ if (name.trim() === "" || !EMAIL_RE$1.test(email.trim()) || password.length < minPasswordLength || termsProp !== false && !terms) return;
2386
2533
  run(() => onSubmit?.({
2387
2534
  name: name.trim(),
2388
2535
  email: email.trim(),
@@ -2394,7 +2541,38 @@ function SignUpForm({ onSubmit, error: errorProp, loading: loadingProp, minPassw
2394
2541
  tone: "destructive",
2395
2542
  description: alert
2396
2543
  }),
2397
- /* @__PURE__ */ jsxs(Field, {
2544
+ fields !== void 0 && submitted && /* @__PURE__ */ jsx(ValidationSummary, {
2545
+ errors: summaryErrors,
2546
+ submitCount,
2547
+ className: "bg-background"
2548
+ }),
2549
+ fields !== void 0 ? fields.map((field) => {
2550
+ const message = authSignUpFieldError(fieldValue(field.id), field);
2551
+ const invalid = submitted && message !== null;
2552
+ return /* @__PURE__ */ jsxs(Field, {
2553
+ invalid,
2554
+ children: [
2555
+ /* @__PURE__ */ jsx(FieldLabel, { children: field.label }),
2556
+ /* @__PURE__ */ jsx(Input, {
2557
+ id: `${fieldPrefix}-field-${field.id}`,
2558
+ type: field.type ?? "text",
2559
+ autoComplete: field.autoComplete,
2560
+ placeholder: field.placeholder,
2561
+ required: field.required,
2562
+ value: fieldValue(field.id),
2563
+ onValueChange: (value) => setFieldValues((values) => ({
2564
+ ...values,
2565
+ [field.id]: value
2566
+ }))
2567
+ }),
2568
+ field.help != null && /* @__PURE__ */ jsx(FieldDescription, { children: field.help }),
2569
+ /* @__PURE__ */ jsx(FieldError, {
2570
+ match: invalid,
2571
+ children: message
2572
+ })
2573
+ ]
2574
+ }, field.id);
2575
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Field, {
2398
2576
  invalid: nameInvalid,
2399
2577
  children: [
2400
2578
  /* @__PURE__ */ jsx(FieldLabel, { children: "Full name" }),
@@ -2411,8 +2589,7 @@ function SignUpForm({ onSubmit, error: errorProp, loading: loadingProp, minPassw
2411
2589
  children: "Enter your name."
2412
2590
  })
2413
2591
  ]
2414
- }),
2415
- /* @__PURE__ */ jsxs(Field, {
2592
+ }), /* @__PURE__ */ jsxs(Field, {
2416
2593
  invalid: emailInvalid,
2417
2594
  children: [
2418
2595
  /* @__PURE__ */ jsx(FieldLabel, { children: "Work email" }),
@@ -2430,28 +2607,28 @@ function SignUpForm({ onSubmit, error: errorProp, loading: loadingProp, minPassw
2430
2607
  children: "Enter a valid email address."
2431
2608
  })
2432
2609
  ]
2433
- }),
2610
+ })] }),
2434
2611
  /* @__PURE__ */ jsxs(Field, {
2435
2612
  invalid: passwordInvalid,
2436
2613
  children: [
2437
2614
  /* @__PURE__ */ jsx(FieldLabel, { children: "Password" }),
2438
2615
  /* @__PURE__ */ jsx(PasswordInput, {
2616
+ id: fields !== void 0 ? passwordId : void 0,
2439
2617
  showStrength: true,
2618
+ strength: password.length > 0 && password.length < minPasswordLength ? 0 : void 0,
2440
2619
  value: password,
2441
2620
  onValueChange: setPassword,
2442
2621
  required: true
2443
2622
  }),
2444
- /* @__PURE__ */ jsxs(FieldError, {
2623
+ passwordHelp != null && /* @__PURE__ */ jsx(FieldDescription, { children: typeof passwordHelp === "function" ? passwordHelp(minPasswordLength) : passwordHelp }),
2624
+ /* @__PURE__ */ jsx(FieldError, {
2445
2625
  match: passwordInvalid,
2446
- children: [
2447
- "Use at least ",
2448
- minPasswordLength,
2449
- " characters."
2450
- ]
2626
+ children: passwordError
2451
2627
  })
2452
2628
  ]
2453
2629
  }),
2454
- /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Checkbox, {
2630
+ termsProp !== false && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(Checkbox, {
2631
+ render: fields !== void 0 ? /* @__PURE__ */ jsx("span", { id: termsId }) : void 0,
2455
2632
  checked: terms,
2456
2633
  onCheckedChange: setTerms,
2457
2634
  "aria-invalid": termsInvalid || void 0,
@@ -2472,7 +2649,7 @@ function SignUpForm({ onSubmit, error: errorProp, loading: loadingProp, minPassw
2472
2649
  }), termsInvalid && /* @__PURE__ */ jsx("p", {
2473
2650
  id: termsErrorId,
2474
2651
  className: "mt-1.5 text-[12.5px] text-destructive-text",
2475
- children: "Accept the terms to continue."
2652
+ children: termsError
2476
2653
  })] }),
2477
2654
  /* @__PURE__ */ jsx(Button, {
2478
2655
  type: "submit",
@@ -2504,11 +2681,11 @@ function SignUpForm({ onSubmit, error: errorProp, loading: loadingProp, minPassw
2504
2681
  }
2505
2682
  //#endregion
2506
2683
  //#region src/auth/SignUpForm/block.meta.ts
2507
- const meta$60 = {
2684
+ const meta$62 = {
2508
2685
  name: "Sign-up form",
2509
2686
  family: "auth",
2510
2687
  status: "stable",
2511
- description: "Account creation with name, email, a password strength meter and a required terms checkbox.",
2688
+ description: "Account creation with default name/email fields or ordered text/email fields (values.fields), a password strength meter and required consent (terms=false opts out). minPasswordLength defaults to 8 and drives length validation and the insufficient-length meter; optional passwordHelp can receive the minimum. Configured fields support help, required, autoComplete and validation messages, with a linked validation summary on invalid submit. policyLoading renders skeletons without a form; unavailable replaces the form with consumer title, message and optional action. loading remains submitting; error is form-level feedback. Examples: custom-fields, no-terms, unavailable, loading, submitting and error.",
2512
2689
  uses: [
2513
2690
  "Field",
2514
2691
  "Input",
@@ -2517,12 +2694,15 @@ const meta$60 = {
2517
2694
  "Button",
2518
2695
  "Alert",
2519
2696
  "Link",
2520
- "SsoButtons"
2697
+ "SsoButtons",
2698
+ "Skeleton",
2699
+ "FieldDescription",
2700
+ "ValidationSummary"
2521
2701
  ]
2522
2702
  };
2523
2703
  //#endregion
2524
2704
  //#region src/auth/SsoButtons/block.meta.ts
2525
- const meta$63 = {
2705
+ const meta$65 = {
2526
2706
  name: "SSO buttons",
2527
2707
  family: "auth",
2528
2708
  status: "stable",
@@ -2819,7 +2999,7 @@ const documentation$1 = {
2819
2999
  "summary-actions-only"
2820
3000
  ]
2821
3001
  };
2822
- const meta$48 = {
3002
+ const meta$50 = {
2823
3003
  name: "Plan card",
2824
3004
  family: "billing",
2825
3005
  status: "beta",
@@ -2977,7 +3157,7 @@ const documentation = {
2977
3157
  ],
2978
3158
  examples: ["compact", "full"]
2979
3159
  };
2980
- const meta$49 = {
3160
+ const meta$51 = {
2981
3161
  name: "Plan definition card",
2982
3162
  family: "billing",
2983
3163
  status: "beta",
@@ -3091,7 +3271,7 @@ function QuotaMeters({ quotas = sampleQuotas, title = "Plan usage", thresholds,
3091
3271
  }
3092
3272
  //#endregion
3093
3273
  //#region src/billing/QuotaMeters/block.meta.ts
3094
- const meta$53 = {
3274
+ const meta$55 = {
3095
3275
  name: "Quota meters",
3096
3276
  family: "billing",
3097
3277
  status: "beta",
@@ -3206,7 +3386,7 @@ function SpendVsBudget({ data = sampleSpend, budget = sampleBudget, currency = "
3206
3386
  }
3207
3387
  //#endregion
3208
3388
  //#region src/billing/SpendVsBudget/block.meta.ts
3209
- const meta$62 = {
3389
+ const meta$64 = {
3210
3390
  name: "Spend vs budget",
3211
3391
  family: "billing",
3212
3392
  status: "beta",
@@ -3366,7 +3546,7 @@ function InvoiceTable({ invoices = sampleInvoices, caption = "Invoice history",
3366
3546
  }
3367
3547
  //#endregion
3368
3548
  //#region src/billing/InvoiceTable/block.meta.ts
3369
- const meta$35 = {
3549
+ const meta$36 = {
3370
3550
  name: "Invoice table",
3371
3551
  family: "billing",
3372
3552
  status: "beta",
@@ -3482,7 +3662,7 @@ function PaymentMethodCard({ method = samplePaymentMethod, title = "Payment meth
3482
3662
  }
3483
3663
  //#endregion
3484
3664
  //#region src/billing/PaymentMethodCard/block.meta.ts
3485
- const meta$46 = {
3665
+ const meta$48 = {
3486
3666
  name: "Payment method card",
3487
3667
  family: "billing",
3488
3668
  status: "beta",
@@ -4394,7 +4574,7 @@ function FlowBuilder({ title = "Untitled flow", nodes: initialNodes = builderNod
4394
4574
  }
4395
4575
  //#endregion
4396
4576
  //#region src/builders/FlowBuilder/block.meta.ts
4397
- const meta$27 = {
4577
+ const meta$28 = {
4398
4578
  name: "Flow builder",
4399
4579
  family: "builders",
4400
4580
  status: "beta",
@@ -5156,7 +5336,7 @@ function LogViewer({ lines = logLines, title = "Logs", height = 360, rowHeight =
5156
5336
  }
5157
5337
  //#endregion
5158
5338
  //#region src/builders/LogViewer/block.meta.ts
5159
- const meta$37 = {
5339
+ const meta$39 = {
5160
5340
  name: "Log viewer",
5161
5341
  family: "builders",
5162
5342
  status: "beta",
@@ -5374,7 +5554,7 @@ function KpiRow({ items = KPI_ITEMS, variant = "cards", showTrends = true, label
5374
5554
  }
5375
5555
  //#endregion
5376
5556
  //#region src/data-display/KpiRow/block.meta.ts
5377
- const meta$36 = {
5557
+ const meta$37 = {
5378
5558
  name: "KPI row",
5379
5559
  family: "data-display",
5380
5560
  status: "beta",
@@ -5548,7 +5728,7 @@ function StatCard({ label = "Requests", icon: IconCmp = Activity, ranges = STAT_
5548
5728
  }
5549
5729
  //#endregion
5550
5730
  //#region src/data-display/StatCard/block.meta.ts
5551
- const meta$64 = {
5731
+ const meta$66 = {
5552
5732
  name: "Stat card",
5553
5733
  family: "data-display",
5554
5734
  status: "beta",
@@ -5965,7 +6145,7 @@ function DescriptionListCard({ title = "Configuration", description = "Settings
5965
6145
  }
5966
6146
  //#endregion
5967
6147
  //#region src/data-display/DescriptionListCard/block.meta.ts
5968
- const meta$17 = {
6148
+ const meta$18 = {
5969
6149
  name: "Description list card",
5970
6150
  family: "data-display",
5971
6151
  status: "beta",
@@ -6161,7 +6341,7 @@ function ResourceCardGrid({ items = RESOURCE_CARDS, label = "Resources", onActio
6161
6341
  }
6162
6342
  //#endregion
6163
6343
  //#region src/data-display/ResourceCardGrid/block.meta.ts
6164
- const meta$55 = {
6344
+ const meta$57 = {
6165
6345
  name: "Resource card grid",
6166
6346
  family: "data-display",
6167
6347
  status: "beta",
@@ -6322,7 +6502,7 @@ function StatusTimeline({ events = DEPLOYMENT_EVENTS, label: labelProp, emptyLab
6322
6502
  }
6323
6503
  //#endregion
6324
6504
  //#region src/data-display/StatusTimeline/block.meta.ts
6325
- const meta$65 = {
6505
+ const meta$67 = {
6326
6506
  name: "Status timeline",
6327
6507
  family: "data-display",
6328
6508
  status: "beta",
@@ -6724,7 +6904,7 @@ function SystemBanner({ kind = "maintenance", title = "Scheduled maintenance.",
6724
6904
  }
6725
6905
  //#endregion
6726
6906
  //#region src/feedback/SystemBanner/block.meta.ts
6727
- const meta$68 = {
6907
+ const meta$70 = {
6728
6908
  name: "System banner",
6729
6909
  family: "feedback",
6730
6910
  status: "beta",
@@ -6770,7 +6950,7 @@ function InlineCallout({ tone = "warning", title = "You have used 92% of your bu
6770
6950
  }
6771
6951
  //#endregion
6772
6952
  //#region src/feedback/InlineCallout/block.meta.ts
6773
- const meta$32 = {
6953
+ const meta$33 = {
6774
6954
  name: "Inline callout",
6775
6955
  family: "feedback",
6776
6956
  status: "beta",
@@ -6798,8 +6978,24 @@ const noAccessSample = {
6798
6978
  resource: "Billing",
6799
6979
  owner: "an organization admin"
6800
6980
  };
6981
+ const notFoundSample = {
6982
+ title: "Resource not found",
6983
+ description: "This resource may have been deleted or moved."
6984
+ };
6801
6985
  //#endregion
6802
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
+ }
6803
6999
  /** First-run state: nothing created yet; explains the value and offers the first action. */
6804
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 = {
6805
7001
  label: "Read the guide",
@@ -6904,11 +7100,11 @@ function NoAccessEmpty({ resource = noAccessSample.resource, owner = noAccessSam
6904
7100
  }
6905
7101
  //#endregion
6906
7102
  //#region src/feedback/EmptyStates/block.meta.ts
6907
- const meta$19 = {
7103
+ const meta$20 = {
6908
7104
  name: "Empty states",
6909
7105
  family: "feedback",
6910
7106
  status: "beta",
6911
- 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).",
6912
7108
  uses: [
6913
7109
  "EmptyState",
6914
7110
  "Button",
@@ -7052,7 +7248,7 @@ function PageSkeleton({ stats = 4, rows = 5, label: labelProp, className }) {
7052
7248
  }
7053
7249
  //#endregion
7054
7250
  //#region src/feedback/Skeletons/block.meta.ts
7055
- const meta$61 = {
7251
+ const meta$63 = {
7056
7252
  name: "Skeletons",
7057
7253
  family: "feedback",
7058
7254
  status: "beta",
@@ -7060,157 +7256,37 @@ const meta$61 = {
7060
7256
  uses: ["Skeleton"]
7061
7257
  };
7062
7258
  //#endregion
7063
- //#region src/feedback/ConfirmDestructive/ConfirmDestructive.tsx
7064
- /**
7065
- * Typed-confirmation for irreversible actions: an AlertDialog whose destructive button stays
7066
- * disabled until the resource name is typed exactly.
7067
- */
7068
- function ConfirmDestructive({ resourceName = "acme-web", resourceType = "project", title, description, consequences = [
7069
- "All deployments and preview URLs",
7070
- "Environment variables and secrets",
7071
- "The audit log for this project"
7072
- ], confirmLabel, triggerLabel, open, defaultOpen = false, onOpenChange, onConfirm }) {
7073
- const [innerOpen, setInnerOpen] = useState(defaultOpen);
7074
- const [typed, setTyped] = useState("");
7075
- const [pending, setPending] = useState(false);
7076
- const [error, setError] = useState(null);
7077
- const isOpen = open ?? innerOpen;
7078
- const label = confirmLabel ?? `Delete ${resourceType}`;
7079
- const matches = typed === resourceName;
7080
- const setOpen = (next) => {
7081
- if (!next) {
7082
- setTyped("");
7083
- setError(null);
7259
+ //#region src/feedback/ErrorPanel/ErrorPanel.tsx
7260
+ /** Error summary for a failed load or action: what happened, request id, retry and technical details. */
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 = {
7262
+ label: "Contact support",
7263
+ variant: "ghost"
7264
+ }, titleAs: Heading = "h3", className, announce = true }) {
7265
+ const { t } = useI18n();
7266
+ const retryLabel = retryLabelProp ?? t("error.retry");
7267
+ const id = useId();
7268
+ const [innerRetrying, setInnerRetrying] = useState(false);
7269
+ const [copied, setCopied] = useState(false);
7270
+ const copyTimer = useRef(void 0);
7271
+ const busy = retrying ?? innerRetrying;
7272
+ const retry = async () => {
7273
+ if (!onRetry || busy) return;
7274
+ setInnerRetrying(true);
7275
+ try {
7276
+ await onRetry();
7277
+ } finally {
7278
+ setInnerRetrying(false);
7084
7279
  }
7085
- setInnerOpen(next);
7086
- onOpenChange?.(next);
7087
7280
  };
7088
- const confirm = async (event) => {
7089
- event.preventDefault();
7090
- if (!matches || pending) return;
7091
- setPending(true);
7092
- setError(null);
7281
+ const copy = async () => {
7282
+ if (!requestId) return;
7093
7283
  try {
7094
- await onConfirm?.();
7095
- setPending(false);
7096
- setOpen(false);
7097
- } catch (err) {
7098
- setPending(false);
7099
- setError(err instanceof Error ? err.message : "Something went wrong. Try again.");
7100
- }
7101
- };
7102
- return /* @__PURE__ */ jsxs(AlertDialog, {
7103
- open: isOpen,
7104
- onOpenChange: (next) => !pending && setOpen(next),
7105
- children: [triggerLabel !== null && /* @__PURE__ */ jsx(AlertDialogTrigger, {
7106
- render: /* @__PURE__ */ jsx(Button, {
7107
- variant: "destructive",
7108
- icon: Trash2
7109
- }),
7110
- children: triggerLabel ?? label
7111
- }), /* @__PURE__ */ jsxs(AlertDialogContent, { children: [
7112
- /* @__PURE__ */ jsxs(AlertDialogHeader, {
7113
- tone: "destructive",
7114
- children: [/* @__PURE__ */ jsx(AlertDialogTitle, { children: title ?? `Delete ${resourceType}?` }), /* @__PURE__ */ jsx(AlertDialogDescription, { children: description ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
7115
- "This permanently deletes ",
7116
- /* @__PURE__ */ jsx("span", {
7117
- className: "font-mono text-foreground",
7118
- children: resourceName
7119
- }),
7120
- ". This action cannot be undone."
7121
- ] }) })]
7122
- }),
7123
- consequences.length > 0 && /* @__PURE__ */ jsx("ul", {
7124
- 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",
7125
- children: consequences.map((c) => /* @__PURE__ */ jsx("li", { children: c }, c))
7126
- }),
7127
- /* @__PURE__ */ jsxs("form", {
7128
- onSubmit: (e) => void confirm(e),
7129
- className: "mt-4",
7130
- children: [
7131
- /* @__PURE__ */ jsxs(Field, { children: [/* @__PURE__ */ jsxs(FieldLabel, { children: [
7132
- "Type ",
7133
- /* @__PURE__ */ jsx("span", {
7134
- className: "font-mono font-semibold text-foreground",
7135
- children: resourceName
7136
- }),
7137
- " to confirm"
7138
- ] }), /* @__PURE__ */ jsx(Input, {
7139
- value: typed,
7140
- onChange: (e) => setTyped(e.target.value),
7141
- autoComplete: "off",
7142
- spellCheck: false,
7143
- disabled: pending
7144
- })] }),
7145
- error && /* @__PURE__ */ jsx("p", {
7146
- role: "alert",
7147
- className: "mt-2 text-[12.5px] text-destructive-text",
7148
- children: error
7149
- }),
7150
- /* @__PURE__ */ jsxs(AlertDialogFooter, {
7151
- className: "mt-5",
7152
- children: [/* @__PURE__ */ jsx(AlertDialogCancel, {
7153
- disabled: pending,
7154
- children: "Cancel"
7155
- }), /* @__PURE__ */ jsx(Button, {
7156
- type: "submit",
7157
- variant: "destructive",
7158
- loading: pending,
7159
- disabled: !matches,
7160
- children: label
7161
- })]
7162
- })
7163
- ]
7164
- })
7165
- ] })]
7166
- });
7167
- }
7168
- //#endregion
7169
- //#region src/feedback/ConfirmDestructive/block.meta.ts
7170
- const meta$10 = {
7171
- name: "Confirm destructive",
7172
- family: "feedback",
7173
- status: "beta",
7174
- description: "AlertDialog for irreversible actions that requires typing the resource name, with async confirm and error display.",
7175
- uses: [
7176
- "AlertDialog",
7177
- "Button",
7178
- "Field",
7179
- "Input"
7180
- ]
7181
- };
7182
- //#endregion
7183
- //#region src/feedback/ErrorPanel/ErrorPanel.tsx
7184
- /** Error summary for a failed load or action: what happened, request id, retry and technical details. */
7185
- 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 = {
7186
- label: "Contact support",
7187
- variant: "ghost"
7188
- }, titleAs: Heading = "h3", className }) {
7189
- const { t } = useI18n();
7190
- const retryLabel = retryLabelProp ?? t("error.retry");
7191
- const id = useId();
7192
- const [innerRetrying, setInnerRetrying] = useState(false);
7193
- const [copied, setCopied] = useState(false);
7194
- const copyTimer = useRef(void 0);
7195
- const busy = retrying ?? innerRetrying;
7196
- const retry = async () => {
7197
- if (!onRetry || busy) return;
7198
- setInnerRetrying(true);
7199
- try {
7200
- await onRetry();
7201
- } finally {
7202
- setInnerRetrying(false);
7203
- }
7204
- };
7205
- const copy = async () => {
7206
- if (!requestId) return;
7207
- try {
7208
- await navigator.clipboard.writeText(requestId);
7209
- setCopied(true);
7210
- clearTimeout(copyTimer.current);
7211
- copyTimer.current = setTimeout(() => setCopied(false), 2e3);
7212
- } catch {
7213
- setCopied(false);
7284
+ await navigator.clipboard.writeText(requestId);
7285
+ setCopied(true);
7286
+ clearTimeout(copyTimer.current);
7287
+ copyTimer.current = setTimeout(() => setCopied(false), 2e3);
7288
+ } catch {
7289
+ setCopied(false);
7214
7290
  }
7215
7291
  };
7216
7292
  return /* @__PURE__ */ jsx("section", {
@@ -7288,7 +7364,7 @@ function ErrorPanel({ icon: Icon = ServerCrash, title = "We couldn’t load depl
7288
7364
  children: details
7289
7365
  }) })]
7290
7366
  }),
7291
- /* @__PURE__ */ jsx("p", {
7367
+ announce && /* @__PURE__ */ jsx("p", {
7292
7368
  role: "status",
7293
7369
  className: "sr-only",
7294
7370
  children: busy ? t("error.retryingStatus") : copied ? t("error.requestIdCopied") : ""
@@ -7299,8 +7375,271 @@ function ErrorPanel({ icon: Icon = ServerCrash, title = "We couldn’t load depl
7299
7375
  });
7300
7376
  }
7301
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
7302
7641
  //#region src/feedback/ErrorPanel/block.meta.ts
7303
- const meta$21 = {
7642
+ const meta$22 = {
7304
7643
  name: "Error panel",
7305
7644
  family: "feedback",
7306
7645
  status: "beta",
@@ -7480,7 +7819,7 @@ function DangerZone({ title = "Danger zone", description = "These actions affect
7480
7819
  }
7481
7820
  //#endregion
7482
7821
  //#region src/forms/DangerZone/block.meta.ts
7483
- const meta$14 = {
7822
+ const meta$15 = {
7484
7823
  name: "Danger zone",
7485
7824
  family: "forms",
7486
7825
  status: "stable",
@@ -7901,7 +8240,7 @@ function DateRangeFilter({ value, defaultValue, onValueChange, presets = DEFAULT
7901
8240
  }
7902
8241
  //#endregion
7903
8242
  //#region src/forms/DateRangeFilter/block.meta.ts
7904
- const meta$16 = {
8243
+ const meta$17 = {
7905
8244
  name: "Date range filter",
7906
8245
  family: "forms",
7907
8246
  status: "stable",
@@ -8190,7 +8529,7 @@ function FileRow({ item, onRemove, onRetry }) {
8190
8529
  }
8191
8530
  //#endregion
8192
8531
  //#region src/forms/FileUploadPanel/block.meta.ts
8193
- const meta$25 = {
8532
+ const meta$26 = {
8194
8533
  name: "File upload panel",
8195
8534
  family: "forms",
8196
8535
  status: "stable",
@@ -8253,7 +8592,7 @@ function FormSection({ title = "General", description = "Basic details shown to
8253
8592
  }
8254
8593
  //#endregion
8255
8594
  //#region src/forms/FormSection/block.meta.ts
8256
- const meta$29 = {
8595
+ const meta$30 = {
8257
8596
  name: "Form section",
8258
8597
  family: "forms",
8259
8598
  status: "stable",
@@ -8420,7 +8759,7 @@ function InviteMembersDialog({ roles = memberRoles, defaultRole = "member", onIn
8420
8759
  }
8421
8760
  //#endregion
8422
8761
  //#region src/forms/InviteMembersDialog/block.meta.ts
8423
- const meta$34 = {
8762
+ const meta$35 = {
8424
8763
  name: "Invite members dialog",
8425
8764
  family: "forms",
8426
8765
  status: "stable",
@@ -8478,7 +8817,7 @@ function SettingsRow({ label = "Deployment notifications", description = "Email
8478
8817
  }
8479
8818
  //#endregion
8480
8819
  //#region src/forms/SettingsRow/block.meta.ts
8481
- const meta$58 = {
8820
+ const meta$60 = {
8482
8821
  name: "Settings row",
8483
8822
  family: "forms",
8484
8823
  status: "stable",
@@ -8486,67 +8825,6 @@ const meta$58 = {
8486
8825
  uses: ["Switch"]
8487
8826
  };
8488
8827
  //#endregion
8489
- //#region src/forms/ValidationSummary/fixtures.ts
8490
- const validationIssues = [
8491
- {
8492
- fieldId: "project-name",
8493
- label: "Project name",
8494
- message: "Enter a project name."
8495
- },
8496
- {
8497
- fieldId: "billing-email",
8498
- label: "Billing email",
8499
- message: "Enter a valid email address, like name@company.com."
8500
- },
8501
- {
8502
- fieldId: "region",
8503
- label: "Region",
8504
- message: "Choose a region."
8505
- }
8506
- ];
8507
- //#endregion
8508
- //#region src/forms/ValidationSummary/ValidationSummary.tsx
8509
- const focusField = (fieldId) => {
8510
- const el = document.getElementById(fieldId);
8511
- if (!el) return;
8512
- el.focus();
8513
- el.scrollIntoView?.({ block: "center" });
8514
- };
8515
- /**
8516
- * Error summary for long forms: lists every problem with a link that moves focus to the field.
8517
- * After a failed submit it takes focus, so screen readers announce it.
8518
- */
8519
- function ValidationSummary({ errors = validationIssues, submitCount = 0, title, className }) {
8520
- const ref = useRef(null);
8521
- const hasErrors = errors.length > 0;
8522
- useEffect(() => {
8523
- if (submitCount > 0 && hasErrors) ref.current?.focus();
8524
- }, [submitCount, hasErrors]);
8525
- if (!hasErrors) return null;
8526
- const heading = title ?? `There ${errors.length === 1 ? "is 1 problem" : `are ${errors.length} problems`} with this form`;
8527
- return /* @__PURE__ */ jsx(Alert, {
8528
- ref,
8529
- tabIndex: -1,
8530
- role: "region",
8531
- tone: "destructive",
8532
- title: heading,
8533
- className: cn("focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-ring", className),
8534
- children: /* @__PURE__ */ jsx("ul", {
8535
- className: "mt-1 list-disc space-y-1 ps-4",
8536
- children: errors.map((e) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Link, {
8537
- href: `#${e.fieldId}`,
8538
- tone: "inherit",
8539
- underline: "always",
8540
- onClick: (ev) => {
8541
- ev.preventDefault();
8542
- focusField(e.fieldId);
8543
- },
8544
- children: [e.label ? `${e.label}: ` : "", e.message]
8545
- }) }, e.fieldId))
8546
- })
8547
- });
8548
- }
8549
- //#endregion
8550
8828
  //#region src/forms/DialogWizard/DialogWizard.tsx
8551
8829
  /** Modal variant of create-wizard for a flow over its parent page. State stays consumer-owned. */
8552
8830
  function DialogWizard({ steps, current = 0, size = "dialog", stepError, reviewStep, children, title, ...props }) {
@@ -8564,7 +8842,7 @@ function DialogWizard({ steps, current = 0, size = "dialog", stepError, reviewSt
8564
8842
  }
8565
8843
  //#endregion
8566
8844
  //#region src/forms/DialogWizard/block.meta.ts
8567
- const meta$18 = {
8845
+ const meta$19 = {
8568
8846
  name: "Dialog wizard",
8569
8847
  family: "forms",
8570
8848
  status: "beta",
@@ -8603,7 +8881,7 @@ const dialogWizardCopy = {
8603
8881
  };
8604
8882
  //#endregion
8605
8883
  //#region src/forms/ValidationSummary/block.meta.ts
8606
- const meta$73 = {
8884
+ const meta$75 = {
8607
8885
  name: "Validation summary",
8608
8886
  family: "forms",
8609
8887
  status: "stable",
@@ -8749,7 +9027,7 @@ function Hero({ variant = "centered", eyebrow = "New · Usage-based billing", ti
8749
9027
  }
8750
9028
  //#endregion
8751
9029
  //#region src/marketing/Hero/block.meta.ts
8752
- const meta$31 = {
9030
+ const meta$32 = {
8753
9031
  name: "Hero",
8754
9032
  family: "marketing",
8755
9033
  status: "beta",
@@ -8854,7 +9132,7 @@ function FeatureGrid({ features = sampleFeatures, eyebrow = "Everything included
8854
9132
  }
8855
9133
  //#endregion
8856
9134
  //#region src/marketing/FeatureGrid/block.meta.ts
8857
- const meta$24 = {
9135
+ const meta$25 = {
8858
9136
  name: "Feature grid",
8859
9137
  family: "marketing",
8860
9138
  status: "beta",
@@ -9133,7 +9411,7 @@ function TierBody({ tier, tierId, cycle, money, TierHeading, currentTierId, curr
9133
9411
  }
9134
9412
  //#endregion
9135
9413
  //#region src/marketing/PricingTable/block.meta.ts
9136
- const meta$50 = {
9414
+ const meta$52 = {
9137
9415
  name: "Pricing table",
9138
9416
  family: "marketing",
9139
9417
  status: "beta",
@@ -9213,7 +9491,7 @@ function Faq({ items = sampleFaqs, title = "Frequently asked questions", descrip
9213
9491
  }
9214
9492
  //#endregion
9215
9493
  //#region src/marketing/Faq/block.meta.ts
9216
- const meta$23 = {
9494
+ const meta$24 = {
9217
9495
  name: "FAQ",
9218
9496
  family: "marketing",
9219
9497
  status: "beta",
@@ -9741,7 +10019,7 @@ function PageHeader({ as: Root = "header", breadcrumbs = pageHeaderBreadcrumbs,
9741
10019
  }
9742
10020
  //#endregion
9743
10021
  //#region src/page-chrome/PageHeader/block.meta.ts
9744
- const meta$43 = {
10022
+ const meta$45 = {
9745
10023
  name: "Page header",
9746
10024
  family: "page-chrome",
9747
10025
  status: "beta",
@@ -9795,7 +10073,7 @@ function SectionHeader({ title = "Policies", description = "Guardrails applied t
9795
10073
  }
9796
10074
  //#endregion
9797
10075
  //#region src/page-chrome/SectionHeader/block.meta.ts
9798
- const meta$56 = {
10076
+ const meta$58 = {
9799
10077
  name: "Section header",
9800
10078
  family: "page-chrome",
9801
10079
  status: "beta",
@@ -9888,7 +10166,7 @@ function PageToolbar({ search, defaultSearch = "", onSearchChange, searchLabel:
9888
10166
  }
9889
10167
  //#endregion
9890
10168
  //#region src/page-chrome/PageToolbar/block.meta.ts
9891
- const meta$44 = {
10169
+ const meta$46 = {
9892
10170
  name: "Page toolbar",
9893
10171
  family: "page-chrome",
9894
10172
  status: "beta",
@@ -9944,7 +10222,7 @@ function StickyActionBar({ dirty = true, saving = false, onSave, onCancel, dirty
9944
10222
  }
9945
10223
  //#endregion
9946
10224
  //#region src/page-chrome/StickyActionBar/block.meta.ts
9947
- const meta$66 = {
10225
+ const meta$68 = {
9948
10226
  name: "Sticky action bar",
9949
10227
  family: "page-chrome",
9950
10228
  status: "beta",
@@ -10672,7 +10950,7 @@ function MonthCalendar({ events = sampleEvents, today = sampleToday, defaultMont
10672
10950
  }
10673
10951
  //#endregion
10674
10952
  //#region src/scheduling/MonthCalendar/block.meta.ts
10675
- const meta$41 = {
10953
+ const meta$43 = {
10676
10954
  name: "Month calendar",
10677
10955
  family: "scheduling",
10678
10956
  status: "beta",
@@ -10866,7 +11144,7 @@ function WeekCalendar({ events = sampleEvents, today = sampleToday, now, default
10866
11144
  }
10867
11145
  //#endregion
10868
11146
  //#region src/scheduling/WeekCalendar/block.meta.ts
10869
- const meta$74 = {
11147
+ const meta$76 = {
10870
11148
  name: "Week calendar",
10871
11149
  family: "scheduling",
10872
11150
  status: "beta",
@@ -11098,7 +11376,7 @@ function TimeSlotPicker({ slots = sampleTimeSlots, value, defaultValue = null, o
11098
11376
  }
11099
11377
  //#endregion
11100
11378
  //#region src/scheduling/TimeSlotPicker/block.meta.ts
11101
- const meta$69 = {
11379
+ const meta$71 = {
11102
11380
  name: "Time slot picker",
11103
11381
  family: "scheduling",
11104
11382
  status: "beta",
@@ -11624,7 +11902,7 @@ const meta$3 = {
11624
11902
  };
11625
11903
  //#endregion
11626
11904
  //#region src/shell/EnvironmentBadge/block.meta.ts
11627
- const meta$20 = {
11905
+ const meta$21 = {
11628
11906
  name: "Environment badge",
11629
11907
  family: "shell",
11630
11908
  status: "beta",
@@ -11633,7 +11911,7 @@ const meta$20 = {
11633
11911
  };
11634
11912
  //#endregion
11635
11913
  //#region src/shell/GlobalSearch/block.meta.ts
11636
- const meta$30 = {
11914
+ const meta$31 = {
11637
11915
  name: "Global search",
11638
11916
  family: "shell",
11639
11917
  status: "beta",
@@ -11652,7 +11930,7 @@ function PaginationFooter({ total = 97, page: pageProp, defaultPage = 1, onPageC
11652
11930
  25,
11653
11931
  50,
11654
11932
  100
11655
- ], noun: nounProp, locale: localeProp, className }) {
11933
+ ], noun: nounProp, locale: localeProp, className, labels }) {
11656
11934
  const { t, locale: providerLocale } = useI18n();
11657
11935
  const locale = localeProp ?? providerLocale;
11658
11936
  const noun = nounProp ?? t("table.rows");
@@ -11683,9 +11961,9 @@ function PaginationFooter({ total = 97, page: pageProp, defaultPage = 1, onPageC
11683
11961
  children: [/* @__PURE__ */ jsx("span", {
11684
11962
  className: "text-[12.5px] text-muted-foreground",
11685
11963
  "aria-hidden": true,
11686
- children: t("table.rowsPerPage")
11964
+ children: labels?.rowsPerPage ?? t("table.rowsPerPage")
11687
11965
  }), /* @__PURE__ */ jsx(SimpleSelect, {
11688
- "aria-label": t("table.rowsPerPage"),
11966
+ "aria-label": labels?.rowsPerPageLabel ?? t("table.rowsPerPage"),
11689
11967
  size: "sm",
11690
11968
  className: "w-[76px] font-mono",
11691
11969
  value: String(pageSize),
@@ -11697,10 +11975,10 @@ function PaginationFooter({ total = 97, page: pageProp, defaultPage = 1, onPageC
11697
11975
  })]
11698
11976
  }), /* @__PURE__ */ jsxs("div", {
11699
11977
  className: "flex flex-col gap-3 sm:flex-row sm:items-center",
11700
- children: [/* @__PURE__ */ jsxs("p", {
11978
+ children: [/* @__PURE__ */ jsx("p", {
11701
11979
  className: "text-[12.5px] text-muted-foreground tabular-nums",
11702
11980
  "aria-live": "polite",
11703
- children: [
11981
+ children: labels?.rangeSummary ? labels.rangeSummary(from, to, total) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
11704
11982
  /* @__PURE__ */ jsxs("span", {
11705
11983
  className: "font-mono text-foreground",
11706
11984
  children: [
@@ -11716,13 +11994,18 @@ function PaginationFooter({ total = 97, page: pageProp, defaultPage = 1, onPageC
11716
11994
  className: "font-mono text-foreground",
11717
11995
  children: fmt(total)
11718
11996
  })
11719
- ]
11997
+ ] })
11720
11998
  }), /* @__PURE__ */ jsx(Pagination, {
11721
11999
  page,
11722
12000
  pageCount,
11723
12001
  onPageChange: goTo,
11724
12002
  size: "sm",
11725
- labels: { nav: t("table.pagination", { noun }) }
12003
+ labels: {
12004
+ nav: labels?.paginationNav?.(noun) ?? t("table.pagination", { noun }),
12005
+ previous: labels?.previous,
12006
+ next: labels?.next,
12007
+ page: labels?.page
12008
+ }
11726
12009
  })]
11727
12010
  })]
11728
12011
  });
@@ -11734,9 +12017,9 @@ const PIN_NONE = "none";
11734
12017
  * "Columns" menu: one checkbox item per hideable column (the last visible column cannot be
11735
12018
  * hidden) and, when pinning is on, a submenu per visible column to pin it left, right or unpin it.
11736
12019
  */
11737
- function ColumnVisibilityMenu({ columns, hidden, onToggle, label: labelProp, pinOf, onPin }) {
12020
+ function ColumnVisibilityMenu({ columns, hidden, onToggle, label: labelProp, labels, pinOf, onPin }) {
11738
12021
  const { t } = useI18n();
11739
- const label = labelProp ?? t("table.columns");
12022
+ const label = labels?.columns ?? labelProp ?? t("table.columns");
11740
12023
  const visibleCount = columns.filter((c) => !hidden.has(c.id)).length;
11741
12024
  const pinnable = onPin && pinOf ? columns.filter((c) => c.pinnable !== false && !hidden.has(c.id)) : [];
11742
12025
  return /* @__PURE__ */ jsxs(Menu, { children: [/* @__PURE__ */ jsx(MenuTrigger, {
@@ -11750,7 +12033,7 @@ function ColumnVisibilityMenu({ columns, hidden, onToggle, label: labelProp, pin
11750
12033
  }), /* @__PURE__ */ jsxs(MenuContent, {
11751
12034
  align: "end",
11752
12035
  className: "min-w-[200px]",
11753
- children: [/* @__PURE__ */ jsxs(MenuGroup, { children: [/* @__PURE__ */ jsx(MenuGroupLabel, { children: t("table.visibleColumns") }), columns.filter((c) => c.hideable !== false).map((c) => {
12036
+ children: [/* @__PURE__ */ jsxs(MenuGroup, { children: [/* @__PURE__ */ jsx(MenuGroupLabel, { children: labels?.visibleColumns ?? t("table.visibleColumns") }), columns.filter((c) => c.hideable !== false).map((c) => {
11754
12037
  const visible = !hidden.has(c.id);
11755
12038
  return /* @__PURE__ */ jsx(MenuCheckboxItem, {
11756
12039
  checked: visible,
@@ -11758,26 +12041,26 @@ function ColumnVisibilityMenu({ columns, hidden, onToggle, label: labelProp, pin
11758
12041
  onCheckedChange: (on) => onToggle(c.id, on),
11759
12042
  children: c.header
11760
12043
  }, c.id);
11761
- })] }), pinnable.length > 0 && onPin && pinOf && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(MenuSeparator, {}), /* @__PURE__ */ jsxs(MenuGroup, { children: [/* @__PURE__ */ jsx(MenuGroupLabel, { children: "Pin columns" }), pinnable.map((c) => {
12044
+ })] }), pinnable.length > 0 && onPin && pinOf && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(MenuSeparator, {}), /* @__PURE__ */ jsxs(MenuGroup, { children: [/* @__PURE__ */ jsx(MenuGroupLabel, { children: labels?.pinColumns ?? "Pin columns" }), pinnable.map((c) => {
11762
12045
  const side = pinOf(c.id);
11763
12046
  return /* @__PURE__ */ jsxs(MenuSub, { children: [/* @__PURE__ */ jsxs(MenuSubTrigger, { children: [c.header, side && /* @__PURE__ */ jsx("span", {
11764
12047
  className: "ms-auto ps-3 text-[11.5px] text-muted-foreground",
11765
- children: side === "left" ? "Left" : "Right"
12048
+ children: side === "left" ? labels?.pinnedLeft ?? "Left" : labels?.pinnedRight ?? "Right"
11766
12049
  })] }), /* @__PURE__ */ jsx(MenuSubContent, { children: /* @__PURE__ */ jsxs(MenuRadioGroup, {
11767
12050
  value: side ?? PIN_NONE,
11768
12051
  onValueChange: (v) => onPin(c.id, v === "left" || v === "right" ? v : null),
11769
12052
  children: [
11770
12053
  /* @__PURE__ */ jsx(MenuRadioItem, {
11771
12054
  value: "left",
11772
- children: "Pin left"
12055
+ children: labels?.pinLeft ?? "Pin left"
11773
12056
  }),
11774
12057
  /* @__PURE__ */ jsx(MenuRadioItem, {
11775
12058
  value: "right",
11776
- children: "Pin right"
12059
+ children: labels?.pinRight ?? "Pin right"
11777
12060
  }),
11778
12061
  /* @__PURE__ */ jsx(MenuRadioItem, {
11779
12062
  value: PIN_NONE,
11780
- children: "Unpinned"
12063
+ children: labels?.unpinned ?? "Unpinned"
11781
12064
  })
11782
12065
  ]
11783
12066
  }) })] }, c.id);
@@ -12049,7 +12332,7 @@ function focusSibling(from, dir) {
12049
12332
  * edits); while editing, an input or a select: Enter or Tab commits, Escape cancels. `onCellEdit`
12050
12333
  * can reject the value with a message, shown inline under the editor.
12051
12334
  */
12052
- function EditableCell({ row, rowId, rowLabel, column, onCellEdit, hintId, children }) {
12335
+ function EditableCell({ row, rowId, rowLabel, column, onCellEdit, hintId, children, labels }) {
12053
12336
  const errorId = useId();
12054
12337
  const editor = column.editor ?? { type: "text" };
12055
12338
  const [editing, setEditing] = useState(false);
@@ -12097,15 +12380,15 @@ function EditableCell({ row, rowId, rowLabel, column, onCellEdit, hintId, childr
12097
12380
  const n = Number(text);
12098
12381
  if (!Number.isFinite(n)) return {
12099
12382
  ok: false,
12100
- message: "Enter a number."
12383
+ message: labels?.enterNumber ?? "Enter a number."
12101
12384
  };
12102
12385
  if (editor.min != null && n < editor.min) return {
12103
12386
  ok: false,
12104
- message: `Enter ${editor.min} or more.`
12387
+ message: labels?.minimumValue?.(editor.min) ?? `Enter ${editor.min} or more.`
12105
12388
  };
12106
12389
  if (editor.max != null && n > editor.max) return {
12107
12390
  ok: false,
12108
- message: `Enter ${editor.max} or less.`
12391
+ message: labels?.maximumValue?.(editor.max) ?? `Enter ${editor.max} or less.`
12109
12392
  };
12110
12393
  return {
12111
12394
  ok: true,
@@ -12139,11 +12422,11 @@ function EditableCell({ row, rowId, rowLabel, column, onCellEdit, hintId, childr
12139
12422
  previous
12140
12423
  });
12141
12424
  } catch (err) {
12142
- result = err instanceof Error && err.message ? err.message : GENERIC_ERROR;
12425
+ result = err instanceof Error && err.message ? err.message : labels?.editError ?? GENERIC_ERROR;
12143
12426
  }
12144
12427
  busy.current = false;
12145
12428
  setPending(false);
12146
- if (result === false) result = GENERIC_ERROR;
12429
+ if (result === false) result = labels?.editError ?? GENERIC_ERROR;
12147
12430
  if (typeof result === "string") {
12148
12431
  setError(result);
12149
12432
  if (after) field.current?.focus();
@@ -12186,7 +12469,7 @@ function EditableCell({ row, rowId, rowLabel, column, onCellEdit, hintId, childr
12186
12469
  children
12187
12470
  });
12188
12471
  const common = {
12189
- "aria-label": `${column.header} for ${rowLabel}`,
12472
+ "aria-label": labels?.editLabel?.(column.header, rowLabel) ?? `${column.header} for ${rowLabel}`,
12190
12473
  "aria-invalid": error ? true : void 0,
12191
12474
  "aria-describedby": error ? errorId : void 0,
12192
12475
  "aria-busy": pending || void 0,
@@ -12226,7 +12509,7 @@ function EditableCell({ row, rowId, rowLabel, column, onCellEdit, hintId, childr
12226
12509
  }), error && /* @__PURE__ */ jsx("p", {
12227
12510
  id: errorId,
12228
12511
  role: "alert",
12229
- className: "mt-1 text-start text-[11.5px] font-medium whitespace-normal text-destructive-text",
12512
+ className: "mt-1 rounded-sm border border-border bg-popover px-1.5 py-1 text-start text-[11.5px] font-medium whitespace-normal text-destructive-text",
12230
12513
  children: error
12231
12514
  })]
12232
12515
  });
@@ -12237,7 +12520,7 @@ function isCellEditable(column, row) {
12237
12520
  }
12238
12521
  //#endregion
12239
12522
  //#region src/tables/DataTable/data-table-row.tsx
12240
- function DataTableRow({ row, columns, getRowId, getRowLabel, selectable, selected, singleSelection, onToggleRow, rowActions, layout, onCellEdit, editHintId, ariaRowIndex, style }) {
12523
+ function DataTableRow({ labels, row, columns, getRowId, getRowLabel, selectable, selected, singleSelection, onToggleRow, rowActions, layout, onCellEdit, editHintId, ariaRowIndex, style }) {
12241
12524
  const { t } = useI18n();
12242
12525
  const id = getRowId(row);
12243
12526
  const selectionColumn = selectable || singleSelection != null;
@@ -12261,7 +12544,7 @@ function DataTableRow({ row, columns, getRowId, getRowLabel, selectable, selecte
12261
12544
  className: "size-4 accent-primary focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-focus-ring disabled:cursor-not-allowed"
12262
12545
  })
12263
12546
  }) : /* @__PURE__ */ jsx(Checkbox, {
12264
- "aria-label": t("table.selectRow", { label }),
12547
+ "aria-label": labels?.selectRow?.(label) ?? t("table.selectRow", { label }),
12265
12548
  checked: isSelected,
12266
12549
  onCheckedChange: () => onToggleRow(id)
12267
12550
  })
@@ -12275,6 +12558,7 @@ function DataTableRow({ row, columns, getRowId, getRowLabel, selectable, selecte
12275
12558
  style: cl?.style,
12276
12559
  className: cn("whitespace-nowrap", cl?.style && "overflow-hidden text-ellipsis", COLUMN_VARIANT_CLASSES[c.variant ?? "default"], c.className, cl?.className, tint(cl)),
12277
12560
  children: editable ? /* @__PURE__ */ jsx(EditableCell, {
12561
+ labels,
12278
12562
  row,
12279
12563
  rowId: id,
12280
12564
  rowLabel: label,
@@ -12291,7 +12575,7 @@ function DataTableRow({ row, columns, getRowId, getRowLabel, selectable, selecte
12291
12575
  style: layout?.trail.style,
12292
12576
  children: /* @__PURE__ */ jsx(MoreMenu, {
12293
12577
  items: rowActions(row),
12294
- label: t("table.rowActions", { label }),
12578
+ label: labels?.rowActions?.(label) ?? t("table.rowActions", { label }),
12295
12579
  variant: "ghost",
12296
12580
  size: "sm"
12297
12581
  })
@@ -12301,7 +12585,7 @@ function DataTableRow({ row, columns, getRowId, getRowLabel, selectable, selecte
12301
12585
  }
12302
12586
  const groupHeadClass = "h-9 bg-secondary/50 text-[12.5px] font-semibold tracking-normal normal-case text-foreground";
12303
12587
  /** The header row of a group: group checkbox, collapse button, label and count. */
12304
- function GroupHeaderRow({ group, open, selectable, selected, span, collapsible, onToggle, onToggleRows, ariaRowIndex, style }) {
12588
+ function GroupHeaderRow({ labels, group, open, selectable, selected, span, collapsible, onToggle, onToggleRows, ariaRowIndex, style }) {
12305
12589
  const { t } = useI18n();
12306
12590
  const state = selectionState(group.ids, selected);
12307
12591
  const count = group.ids.length;
@@ -12318,7 +12602,7 @@ function GroupHeaderRow({ group, open, selectable, selected, span, collapsible,
12318
12602
  " ",
12319
12603
  /* @__PURE__ */ jsx("span", {
12320
12604
  className: "sr-only",
12321
- children: count === 1 ? "row" : "rows"
12605
+ children: labels?.groupRows?.(count) ?? (count === 1 ? "row" : "rows")
12322
12606
  })
12323
12607
  ] });
12324
12608
  return /* @__PURE__ */ jsxs(TableRow, {
@@ -12329,7 +12613,7 @@ function GroupHeaderRow({ group, open, selectable, selected, span, collapsible,
12329
12613
  children: [selectable && /* @__PURE__ */ jsx(TableCell, {
12330
12614
  className: cn("w-10 pe-0", "h-9 bg-secondary/50 text-[12.5px] font-semibold tracking-normal normal-case text-foreground"),
12331
12615
  children: /* @__PURE__ */ jsx(Checkbox, {
12332
- "aria-label": t("table.selectRow", { label: `all in ${group.name}` }),
12616
+ "aria-label": labels?.selectGroup?.(group.name) ?? t("table.selectRow", { label: `all in ${group.name}` }),
12333
12617
  checked: state.checked,
12334
12618
  indeterminate: state.indeterminate,
12335
12619
  disabled: count === 0,
@@ -12423,8 +12707,8 @@ function DataTableBody(props) {
12423
12707
  children: emptyState ?? /* @__PURE__ */ jsx(EmptyState, {
12424
12708
  icon: Inbox,
12425
12709
  size: "sm",
12426
- title: t("common.noResults"),
12427
- description: t("table.emptyDescription")
12710
+ title: props.labels?.emptyTitle ?? t("common.noResults"),
12711
+ description: props.labels?.emptyDescription ?? t("table.emptyDescription")
12428
12712
  })
12429
12713
  })
12430
12714
  }) });
@@ -12436,6 +12720,7 @@ function DataTableBody(props) {
12436
12720
  }, props.getRowId(r));
12437
12721
  const header = (group, open, extra) => /* @__PURE__ */ jsx(GroupHeaderRow, {
12438
12722
  group,
12723
+ labels: props.labels,
12439
12724
  open,
12440
12725
  selectable,
12441
12726
  selected,
@@ -12501,10 +12786,10 @@ function DataTableBody(props) {
12501
12786
  //#endregion
12502
12787
  //#region src/tables/DataTable/density-toggle.tsx
12503
12788
  /** Two-icon segmented control: comfortable or compact rows. */
12504
- function DensityToggle({ value, onChange }) {
12789
+ function DensityToggle({ value, onChange, labels }) {
12505
12790
  const { t } = useI18n();
12506
12791
  return /* @__PURE__ */ jsxs(ToggleGroup, {
12507
- "aria-label": t("table.density"),
12792
+ "aria-label": labels?.density ?? t("table.density"),
12508
12793
  size: "sm",
12509
12794
  value: [value],
12510
12795
  onValueChange: (v) => {
@@ -12514,7 +12799,7 @@ function DensityToggle({ value, onChange }) {
12514
12799
  children: [/* @__PURE__ */ jsx(Toggle, {
12515
12800
  value: "comfortable",
12516
12801
  iconOnly: true,
12517
- "aria-label": t("table.comfortable"),
12802
+ "aria-label": labels?.comfortable ?? t("table.comfortable"),
12518
12803
  children: /* @__PURE__ */ jsx(Rows2, {
12519
12804
  size: 15,
12520
12805
  "aria-hidden": true
@@ -12522,7 +12807,7 @@ function DensityToggle({ value, onChange }) {
12522
12807
  }), /* @__PURE__ */ jsx(Toggle, {
12523
12808
  value: "compact",
12524
12809
  iconOnly: true,
12525
- "aria-label": t("table.compact"),
12810
+ "aria-label": labels?.compact ?? t("table.compact"),
12526
12811
  children: /* @__PURE__ */ jsx(Rows3, {
12527
12812
  size: 15,
12528
12813
  "aria-hidden": true
@@ -12657,7 +12942,7 @@ const BIG_STEP = 50;
12657
12942
  * aria-valuenow/min/max (the width in px). Drag it with a pointer; from the keyboard,
12658
12943
  * ArrowLeft/ArrowRight change the width by 10px (Shift: 50px), Home/End jump to the limits.
12659
12944
  */
12660
- function ColumnResizeHandle({ label, width, min, max, onResize, onResizeEnd }) {
12945
+ function ColumnResizeHandle({ label, width, min, max, onResize, onResizeEnd, labels }) {
12661
12946
  const drag = useRef(null);
12662
12947
  const clamp = (w) => Math.round(Math.min(max, Math.max(min, w)));
12663
12948
  const onPointerDown = (e) => {
@@ -12701,11 +12986,11 @@ function ColumnResizeHandle({ label, width, min, max, onResize, onResizeEnd }) {
12701
12986
  role: "separator",
12702
12987
  tabIndex: 0,
12703
12988
  "aria-orientation": "vertical",
12704
- "aria-label": `Resize ${label} column`,
12989
+ "aria-label": labels?.resizeColumn?.(label) ?? `Resize ${label} column`,
12705
12990
  "aria-valuenow": width,
12706
12991
  "aria-valuemin": min,
12707
12992
  "aria-valuemax": max,
12708
- "aria-valuetext": `${width} pixels`,
12993
+ "aria-valuetext": labels?.columnWidth?.(width) ?? `${width} pixels`,
12709
12994
  "data-column-resizer": "",
12710
12995
  onPointerDown,
12711
12996
  onPointerMove,
@@ -12725,7 +13010,7 @@ function ColumnResizeHandle({ label, width, min, max, onResize, onResizeEnd }) {
12725
13010
  * Column header of the DataTable. Without a resize handle it is the kit TableHead; with one, the
12726
13011
  * sort button and the handle sit side by side (the handle never nests inside the button).
12727
13012
  */
12728
- function DataTableHeadCell({ column, sortDirection, onSortChange, layout, resize }) {
13013
+ function DataTableHeadCell({ column, sortDirection, onSortChange, layout, resize, labels }) {
12729
13014
  const align = columnAlign(column);
12730
13015
  const pinnedClass = layout?.pinned ? cn(layout.className, "z-[11]", stickyTint(layout, { head: true }), "bg-card") : void 0;
12731
13016
  if (!resize) return /* @__PURE__ */ jsx(TableHead, {
@@ -12765,6 +13050,7 @@ function DataTableHeadCell({ column, sortDirection, onSortChange, layout, resize
12765
13050
  })]
12766
13051
  }) : column.header
12767
13052
  }), /* @__PURE__ */ jsx(ColumnResizeHandle, {
13053
+ labels,
12768
13054
  label: column.header,
12769
13055
  width: resize.width,
12770
13056
  min: resize.min,
@@ -12898,7 +13184,7 @@ function newViewId(name, views) {
12898
13184
  }
12899
13185
  const DEFAULT_VALUE = "__default__";
12900
13186
  /** "Views" menu: switch between saved views, save the current table as a view, rename, delete, reset. */
12901
- function ViewSwitcher({ views, activeId, dirty, onSelect, onSaveAs, onSave, onRename, onDelete, onReset }) {
13187
+ function ViewSwitcher({ labels, views, activeId, dirty, onSelect, onSaveAs, onSave, onRename, onDelete, onReset }) {
12902
13188
  const inputId = useId();
12903
13189
  const active = views.find((v) => v.id === activeId) ?? null;
12904
13190
  const [dialog, setDialog] = useState(null);
@@ -12923,7 +13209,7 @@ function ViewSwitcher({ views, activeId, dirty, onSelect, onSaveAs, onSave, onRe
12923
13209
  }),
12924
13210
  children: [/* @__PURE__ */ jsx("span", {
12925
13211
  className: "max-w-40 truncate",
12926
- children: active ? active.name : "Default view"
13212
+ children: active ? active.name : labels?.defaultView ?? "Default view"
12927
13213
  }), dirty && /* @__PURE__ */ jsxs(Fragment$1, { children: [
12928
13214
  " ",
12929
13215
  /* @__PURE__ */ jsx("span", {
@@ -12933,19 +13219,19 @@ function ViewSwitcher({ views, activeId, dirty, onSelect, onSaveAs, onSave, onRe
12933
13219
  " ",
12934
13220
  /* @__PURE__ */ jsx("span", {
12935
13221
  className: "sr-only",
12936
- children: "(modified)"
13222
+ children: labels?.modified ?? "(modified)"
12937
13223
  })
12938
13224
  ] })]
12939
13225
  }), /* @__PURE__ */ jsxs(MenuContent, {
12940
13226
  align: "end",
12941
13227
  className: "min-w-[220px]",
12942
13228
  children: [
12943
- /* @__PURE__ */ jsxs(MenuGroup, { children: [/* @__PURE__ */ jsx(MenuGroupLabel, { children: "Views" }), /* @__PURE__ */ jsxs(MenuRadioGroup, {
13229
+ /* @__PURE__ */ jsxs(MenuGroup, { children: [/* @__PURE__ */ jsx(MenuGroupLabel, { children: labels?.views ?? "Views" }), /* @__PURE__ */ jsxs(MenuRadioGroup, {
12944
13230
  value: activeId ?? DEFAULT_VALUE,
12945
13231
  onValueChange: (v) => onSelect(v === DEFAULT_VALUE ? null : String(v)),
12946
13232
  children: [/* @__PURE__ */ jsx(MenuRadioItem, {
12947
13233
  value: DEFAULT_VALUE,
12948
- children: "Default view"
13234
+ children: labels?.defaultViewOption ?? "Default view"
12949
13235
  }), views.map((v) => /* @__PURE__ */ jsx(MenuRadioItem, {
12950
13236
  value: v.id,
12951
13237
  children: v.name
@@ -12955,26 +13241,26 @@ function ViewSwitcher({ views, activeId, dirty, onSelect, onSaveAs, onSave, onRe
12955
13241
  /* @__PURE__ */ jsx(MenuItem, {
12956
13242
  disabled: !active || !dirty,
12957
13243
  onClick: onSave,
12958
- children: "Save changes"
13244
+ children: labels?.saveChanges ?? "Save changes"
12959
13245
  }),
12960
13246
  /* @__PURE__ */ jsx(MenuItem, {
12961
13247
  onClick: () => open("create"),
12962
- children: "Save as new view…"
13248
+ children: labels?.saveAs ?? "Save as new view…"
12963
13249
  }),
12964
13250
  /* @__PURE__ */ jsx(MenuItem, {
12965
13251
  disabled: !active,
12966
13252
  onClick: () => open("rename"),
12967
- children: "Rename view…"
13253
+ children: labels?.renameView ?? "Rename view…"
12968
13254
  }),
12969
13255
  /* @__PURE__ */ jsx(MenuItem, {
12970
13256
  disabled: !active,
12971
13257
  onClick: () => active && onDelete(active.id),
12972
- children: "Delete view"
13258
+ children: labels?.deleteView ?? "Delete view"
12973
13259
  }),
12974
13260
  /* @__PURE__ */ jsx(MenuItem, {
12975
13261
  disabled: !dirty,
12976
13262
  onClick: onReset,
12977
- children: "Reset changes"
13263
+ children: labels?.resetChanges ?? "Reset changes"
12978
13264
  })
12979
13265
  ]
12980
13266
  })] }), /* @__PURE__ */ jsx(Dialog, {
@@ -12982,17 +13268,18 @@ function ViewSwitcher({ views, activeId, dirty, onSelect, onSaveAs, onSave, onRe
12982
13268
  onOpenChange: (o) => !o && setDialog(null),
12983
13269
  children: /* @__PURE__ */ jsx(DialogContent, {
12984
13270
  size: "sm",
13271
+ closeLabel: labels?.closeDialog,
12985
13272
  children: /* @__PURE__ */ jsxs("form", {
12986
13273
  onSubmit: (e) => {
12987
13274
  e.preventDefault();
12988
13275
  submit();
12989
13276
  },
12990
13277
  children: [
12991
- /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: dialog === "rename" ? "Rename view" : "Save view" }) }),
13278
+ /* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: dialog === "rename" ? labels?.renameViewTitle ?? "Rename view" : labels?.saveViewTitle ?? "Save view" }) }),
12992
13279
  /* @__PURE__ */ jsxs(DialogBody, { children: [/* @__PURE__ */ jsx("label", {
12993
13280
  htmlFor: inputId,
12994
13281
  className: "mb-1.5 block text-[12.5px] font-medium text-foreground",
12995
- children: "View name"
13282
+ children: labels?.viewName ?? "View name"
12996
13283
  }), /* @__PURE__ */ jsx(Input, {
12997
13284
  id: inputId,
12998
13285
  value: name,
@@ -13002,11 +13289,11 @@ function ViewSwitcher({ views, activeId, dirty, onSelect, onSaveAs, onSave, onRe
13002
13289
  })] }),
13003
13290
  /* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(DialogClose, {
13004
13291
  render: /* @__PURE__ */ jsx(Button, { variant: "ghost" }),
13005
- children: "Cancel"
13292
+ children: labels?.cancel ?? "Cancel"
13006
13293
  }), /* @__PURE__ */ jsx(Button, {
13007
13294
  type: "submit",
13008
13295
  disabled: !name.trim(),
13009
- children: dialog === "rename" ? "Rename" : "Save view"
13296
+ children: dialog === "rename" ? labels?.rename ?? "Rename" : labels?.saveView ?? "Save view"
13010
13297
  })] })
13011
13298
  ]
13012
13299
  })
@@ -13143,13 +13430,14 @@ const ROW_HEIGHT = {
13143
13430
  * and empty states, client-side sort + pagination, optional collapsible row groups (`groupBy`),
13144
13431
  * column resize and pinning, row virtualization, inline cell editing and saved views.
13145
13432
  */
13146
- 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 = [
13147
13434
  10,
13148
13435
  25,
13149
13436
  50
13150
- ], 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 }) {
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 }) {
13151
13438
  const { t } = useI18n();
13152
13439
  const singleMode = selectionMode === "single";
13440
+ const serverMode = paginationMode === "server";
13153
13441
  const selectable = selectionMode === void 0 ? selectableProp : selectionMode === "multiple";
13154
13442
  const selectionColumn = selectable || singleMode;
13155
13443
  const paginated = !singleMode && (paginatedProp ?? true);
@@ -13181,10 +13469,10 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13181
13469
  });
13182
13470
  const [innerCollapsed, setInnerCollapsed] = useState(() => new Set(defaultCollapsedGroups));
13183
13471
  const collapsed = collapsedProp ? new Set(collapsedProp) : innerCollapsed;
13184
- const sortedRows = manualSorting ? [...rows] : sortRows(rows, columns, sort);
13472
+ const sortedRows = serverMode ? rows : manualSorting ? [...rows] : sortRows(rows, columns, sort);
13185
13473
  const allGroups = effectiveGroupBy ? groupRows(sortedRows, effectiveGroupBy, rows) : null;
13186
13474
  const sorted = allGroups ? allGroups.flatMap((g) => g.rows) : sortedRows;
13187
- const pageRows = paginated ? paginate(sorted, page, pageSize) : sorted;
13475
+ const pageRows = serverMode ? rows : paginated ? paginate(sorted, page, pageSize) : sorted;
13188
13476
  const pageIds = (effectiveGroupBy ? pageRows.filter((row) => !collapsed.has(groupKeyOf(row, effectiveGroupBy))) : pageRows).map(getRowId);
13189
13477
  const header = selectionState(pageIds, selected);
13190
13478
  const selectedList = rows.map(getRowId).filter((id) => selected.has(id));
@@ -13193,6 +13481,7 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13193
13481
  onSelectionChange?.(rows.map(getRowId).filter((id) => next.has(id)));
13194
13482
  };
13195
13483
  const changeSort = (columnId, direction) => {
13484
+ if (serverMode) return;
13196
13485
  const next = {
13197
13486
  columnId,
13198
13487
  direction: sort?.columnId === columnId ? direction : "ascending"
@@ -13208,7 +13497,7 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13208
13497
  setInnerCollapsed(next);
13209
13498
  onCollapsedGroupsChange?.([...next]);
13210
13499
  };
13211
- const nameOf = (key) => key || "No group";
13500
+ const nameOf = (key) => key || (labels?.noGroup ?? "No group");
13212
13501
  const bodyGroups = effectiveGroupBy && allGroups ? allGroups.map((g) => ({
13213
13502
  key: g.key,
13214
13503
  label: groupLabel ? groupLabel(g.key, g.rows) : nameOf(g.key),
@@ -13262,7 +13551,7 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13262
13551
  const applyState = (state) => {
13263
13552
  const nextSort = state.sort ?? null;
13264
13553
  setInnerSort(nextSort);
13265
- if (nextSort) onSortChange?.(nextSort);
13554
+ if (nextSort && !serverMode) onSortChange?.(nextSort);
13266
13555
  setHiddenList(state.hiddenColumns ?? defaultHidden);
13267
13556
  setWidths(state.columnWidths ?? defaultColumnWidths);
13268
13557
  setPinned(state.pinnedColumns ?? defaultPinnedColumns);
@@ -13270,7 +13559,7 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13270
13559
  setGroupOverride(nextGroup === groupName(groupBy) && typeof groupBy !== "function" ? void 0 : nextGroup);
13271
13560
  if (nextGroup !== currentState.groupBy) onGroupByChange?.(nextGroup);
13272
13561
  if (state.filters !== filters) onFiltersChange?.(state.filters);
13273
- setPage(1);
13562
+ if (!serverMode) setPage(1);
13274
13563
  };
13275
13564
  const viewsApi = useTableViews({
13276
13565
  views: viewsProp,
@@ -13313,10 +13602,10 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13313
13602
  children: [/* @__PURE__ */ jsx("div", {
13314
13603
  className: "flex min-w-0 flex-1 flex-wrap items-center gap-2",
13315
13604
  children: hasSelection ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
13316
- selectionSummary && /* @__PURE__ */ jsxs("span", {
13605
+ selectionSummary && /* @__PURE__ */ jsx("span", {
13317
13606
  className: "text-[12.5px] font-semibold text-foreground",
13318
13607
  "aria-live": "polite",
13319
- children: [selectedList.length, " selected"]
13608
+ children: labels?.selectionCount ? labels.selectionCount(selectedList.length) : /* @__PURE__ */ jsxs(Fragment$1, { children: [selectedList.length, " selected"] })
13320
13609
  }),
13321
13610
  selectionSummary && bulkActions && /* @__PURE__ */ jsx("span", {
13322
13611
  "aria-hidden": true,
@@ -13328,6 +13617,7 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13328
13617
  className: "flex items-center gap-2",
13329
13618
  children: [
13330
13619
  showViews && /* @__PURE__ */ jsx(ViewSwitcher, {
13620
+ labels,
13331
13621
  views: viewsApi.views,
13332
13622
  activeId: viewsApi.activeId,
13333
13623
  dirty: viewsApi.dirty,
@@ -13339,10 +13629,12 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13339
13629
  onReset: viewsApi.reset
13340
13630
  }),
13341
13631
  showDensityToggle && /* @__PURE__ */ jsx(DensityToggle, {
13632
+ labels,
13342
13633
  value: density,
13343
13634
  onChange: changeDensity
13344
13635
  }),
13345
13636
  showColumnMenu && /* @__PURE__ */ jsx(ColumnVisibilityMenu, {
13637
+ labels,
13346
13638
  columns,
13347
13639
  hidden,
13348
13640
  onToggle: toggleColumn,
@@ -13355,7 +13647,7 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13355
13647
  anyEditable && /* @__PURE__ */ jsx("span", {
13356
13648
  id: editHintId,
13357
13649
  className: "sr-only",
13358
- children: "Press Enter or F2 to edit."
13650
+ children: labels?.editHint ?? "Press Enter or F2 to edit."
13359
13651
  }),
13360
13652
  /* @__PURE__ */ jsx(SelectionGroup, {
13361
13653
  single: singleMode,
@@ -13370,7 +13662,7 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13370
13662
  "aria-rowcount": virtual ? items + 1 : void 0,
13371
13663
  stickyHeader: virtualOn,
13372
13664
  containerClassName: virtualOn ? virtualContainerClassName : void 0,
13373
- containerLabel: virtualOn ? caption : void 0,
13665
+ containerLabel: virtualOn ? caption : labels?.scrollRegion,
13374
13666
  className: cn(layout.tableClassName, singleMode && "[&_[data-column-resizer]]:end-0 [&_[data-column-resizer]]:justify-end"),
13375
13667
  style: layout.tableStyle,
13376
13668
  "data-virtualized": virtualOn || void 0,
@@ -13388,9 +13680,9 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13388
13680
  style: layout.lead.style,
13389
13681
  children: [singleMode && /* @__PURE__ */ jsx("span", {
13390
13682
  className: "sr-only",
13391
- children: t("table.selection")
13683
+ children: labels?.selection ?? t("table.selection")
13392
13684
  }), selectable && /* @__PURE__ */ jsx(Checkbox, {
13393
- "aria-label": t("table.selectAllPage"),
13685
+ "aria-label": labels?.selectAll ?? t("table.selectAllPage"),
13394
13686
  checked: header.checked,
13395
13687
  indeterminate: header.indeterminate,
13396
13688
  disabled: loading || pageIds.length === 0,
@@ -13400,9 +13692,13 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13400
13692
  visibleColumns.map((c) => {
13401
13693
  const bounds = widthBounds(c);
13402
13694
  return /* @__PURE__ */ jsx(DataTableHeadCell, {
13403
- column: c,
13695
+ labels,
13696
+ column: serverMode ? {
13697
+ ...c,
13698
+ sortable: false
13699
+ } : c,
13404
13700
  layout: layout.columns.get(c.id),
13405
- sortDirection: sort?.columnId === c.id ? sort.direction : "none",
13701
+ sortDirection: !serverMode && sort?.columnId === c.id ? sort.direction : "none",
13406
13702
  onSortChange: (dir) => changeSort(c.id, dir),
13407
13703
  resize: resizable && c.resizable !== false ? {
13408
13704
  width: columnWidthOf(c, widths),
@@ -13417,12 +13713,13 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13417
13713
  style: layout.trail.style,
13418
13714
  children: /* @__PURE__ */ jsx("span", {
13419
13715
  className: "sr-only",
13420
- children: t("table.actions")
13716
+ children: labels?.actions ?? t("table.actions")
13421
13717
  })
13422
13718
  })
13423
13719
  ]
13424
13720
  }) }),
13425
13721
  /* @__PURE__ */ jsx(DataTableBody, {
13722
+ labels,
13426
13723
  rows: pageRows,
13427
13724
  columns: visibleColumns,
13428
13725
  getRowId,
@@ -13449,22 +13746,23 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13449
13746
  })
13450
13747
  })
13451
13748
  }),
13452
- loading && /* @__PURE__ */ jsxs("p", {
13749
+ loading && /* @__PURE__ */ jsx("p", {
13453
13750
  role: "status",
13454
13751
  className: "sr-only",
13455
- children: [
13752
+ children: labels?.loading ? labels.loading(caption) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
13456
13753
  "Loading ",
13457
13754
  caption.toLowerCase(),
13458
13755
  "…"
13459
- ]
13756
+ ] })
13460
13757
  }),
13461
- paginated && !loading && rows.length > 0 && /* @__PURE__ */ jsx(PaginationFooter, {
13758
+ paginated && !loading && (serverMode || rows.length > 0) && /* @__PURE__ */ jsx(PaginationFooter, {
13759
+ labels,
13462
13760
  className: "border-t border-border px-4 py-3",
13463
- total: rows.length,
13464
- page,
13465
- onPageChange: setPage,
13466
- pageSize,
13467
- 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,
13468
13766
  pageSizeOptions,
13469
13767
  noun: caption
13470
13768
  })
@@ -13473,11 +13771,288 @@ function DataTable({ rows = DEPLOYMENT_ROWS, columns = DEPLOYMENT_COLUMNS, getRo
13473
13771
  }
13474
13772
  //#endregion
13475
13773
  //#region src/tables/DataTable/block.meta.ts
13476
- const meta$15 = {
13774
+ const meta$16 = {
13477
13775
  name: "Data table",
13478
13776
  family: "tables",
13479
13777
  status: "beta",
13480
- 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.",
13779
+ labels: [
13780
+ {
13781
+ key: "scrollRegion",
13782
+ type: "string",
13783
+ state: "Non-virtual table overflow: focusable scroll region name; virtualized regions use the caller caption"
13784
+ },
13785
+ {
13786
+ key: "selectionCount",
13787
+ type: "(count: number) => string",
13788
+ state: "Multiple selection: toolbar count and polite live region"
13789
+ },
13790
+ {
13791
+ key: "columns",
13792
+ type: "string",
13793
+ state: "Column visibility trigger text and name"
13794
+ },
13795
+ {
13796
+ key: "visibleColumns",
13797
+ type: "string",
13798
+ state: "Open column menu: visibility heading"
13799
+ },
13800
+ {
13801
+ key: "pinColumns",
13802
+ type: "string",
13803
+ state: "Open column menu with pinning: pin heading"
13804
+ },
13805
+ {
13806
+ key: "pinnedLeft",
13807
+ type: "string",
13808
+ state: "Open pin submenu trigger: left side suffix"
13809
+ },
13810
+ {
13811
+ key: "pinnedRight",
13812
+ type: "string",
13813
+ state: "Open pin submenu trigger: right side suffix"
13814
+ },
13815
+ {
13816
+ key: "pinLeft",
13817
+ type: "string",
13818
+ state: "Open pin submenu: left option"
13819
+ },
13820
+ {
13821
+ key: "pinRight",
13822
+ type: "string",
13823
+ state: "Open pin submenu: right option"
13824
+ },
13825
+ {
13826
+ key: "unpinned",
13827
+ type: "string",
13828
+ state: "Open pin submenu: unpinned option"
13829
+ },
13830
+ {
13831
+ key: "density",
13832
+ type: "string",
13833
+ state: "Density group accessible name"
13834
+ },
13835
+ {
13836
+ key: "comfortable",
13837
+ type: "string",
13838
+ state: "Comfortable density button name"
13839
+ },
13840
+ {
13841
+ key: "compact",
13842
+ type: "string",
13843
+ state: "Compact density button name"
13844
+ },
13845
+ {
13846
+ key: "resizeColumn",
13847
+ type: "(label: string) => string",
13848
+ state: "Resizable header: separator name; label is caller column header"
13849
+ },
13850
+ {
13851
+ key: "columnWidth",
13852
+ type: "(width: number) => string",
13853
+ state: "Resizable header: separator aria-valuetext in pixels"
13854
+ },
13855
+ {
13856
+ key: "defaultView",
13857
+ type: "string",
13858
+ state: "View trigger when no active view"
13859
+ },
13860
+ {
13861
+ key: "defaultViewOption",
13862
+ type: "string",
13863
+ state: "Open views menu: default option"
13864
+ },
13865
+ {
13866
+ key: "modified",
13867
+ type: "string",
13868
+ state: "Dirty view trigger: screen reader suffix"
13869
+ },
13870
+ {
13871
+ key: "views",
13872
+ type: "string",
13873
+ state: "Open views menu: heading"
13874
+ },
13875
+ {
13876
+ key: "saveChanges",
13877
+ type: "string",
13878
+ state: "Open views menu: save current view action"
13879
+ },
13880
+ {
13881
+ key: "saveAs",
13882
+ type: "string",
13883
+ state: "Open views menu: save as action"
13884
+ },
13885
+ {
13886
+ key: "renameView",
13887
+ type: "string",
13888
+ state: "Open views menu: rename action"
13889
+ },
13890
+ {
13891
+ key: "deleteView",
13892
+ type: "string",
13893
+ state: "Open views menu: immediate delete action; no confirmation dialog"
13894
+ },
13895
+ {
13896
+ key: "resetChanges",
13897
+ type: "string",
13898
+ state: "Open views menu: reset action"
13899
+ },
13900
+ {
13901
+ key: "saveViewTitle",
13902
+ type: "string",
13903
+ state: "Save as dialog: title and accessible name"
13904
+ },
13905
+ {
13906
+ key: "renameViewTitle",
13907
+ type: "string",
13908
+ state: "Rename dialog: title and accessible name"
13909
+ },
13910
+ {
13911
+ key: "viewName",
13912
+ type: "string",
13913
+ state: "Save as and Rename dialogs: input label"
13914
+ },
13915
+ {
13916
+ key: "cancel",
13917
+ type: "string",
13918
+ state: "Save as and Rename dialogs: cancel button"
13919
+ },
13920
+ {
13921
+ key: "saveView",
13922
+ type: "string",
13923
+ state: "Save as dialog: submit button"
13924
+ },
13925
+ {
13926
+ key: "rename",
13927
+ type: "string",
13928
+ state: "Rename dialog: submit button"
13929
+ },
13930
+ {
13931
+ key: "closeDialog",
13932
+ type: "string",
13933
+ state: "Save as and Rename dialogs: close button name"
13934
+ },
13935
+ {
13936
+ key: "selection",
13937
+ type: "string",
13938
+ state: "Single selection: screen reader column heading"
13939
+ },
13940
+ {
13941
+ key: "selectAll",
13942
+ type: "string",
13943
+ state: "Multiple selection: header checkbox name"
13944
+ },
13945
+ {
13946
+ key: "selectRow",
13947
+ type: "(label: string) => string",
13948
+ state: "Multiple selection: row checkbox name; label is caller row name"
13949
+ },
13950
+ {
13951
+ key: "selectGroup",
13952
+ type: "(group: string) => string",
13953
+ state: "Grouped multiple selection: group checkbox name"
13954
+ },
13955
+ {
13956
+ key: "groupRows",
13957
+ type: "(count: number) => string",
13958
+ state: "Grouped header: screen reader row-count unit; numeric count stays unchanged"
13959
+ },
13960
+ {
13961
+ key: "noGroup",
13962
+ type: "string",
13963
+ state: "Grouped header: fallback when group key is empty"
13964
+ },
13965
+ {
13966
+ key: "actions",
13967
+ type: "string",
13968
+ state: "Row actions present: screen reader column heading"
13969
+ },
13970
+ {
13971
+ key: "rowActions",
13972
+ type: "(label: string) => string",
13973
+ state: "Row action menu trigger name; label is caller row name"
13974
+ },
13975
+ {
13976
+ key: "emptyTitle",
13977
+ type: "string",
13978
+ state: "Empty rows: default empty-state title"
13979
+ },
13980
+ {
13981
+ key: "emptyDescription",
13982
+ type: "string",
13983
+ state: "Empty rows: default empty-state description"
13984
+ },
13985
+ {
13986
+ key: "loading",
13987
+ type: "(caption: string) => string",
13988
+ state: "Loading: status announcement; receives original caller caption"
13989
+ },
13990
+ {
13991
+ key: "editHint",
13992
+ type: "string",
13993
+ state: "Editable table: shared keyboard instruction description"
13994
+ },
13995
+ {
13996
+ key: "editLabel",
13997
+ type: "(column: string, row: string) => string",
13998
+ state: "Editing cell: input accessible name"
13999
+ },
14000
+ {
14001
+ key: "editError",
14002
+ type: "string",
14003
+ state: "Rejected cell edit without caller error message: alert"
14004
+ },
14005
+ {
14006
+ key: "enterNumber",
14007
+ type: "string",
14008
+ state: "Editing number: invalid numeric value alert"
14009
+ },
14010
+ {
14011
+ key: "minimumValue",
14012
+ type: "(min: number) => string",
14013
+ state: "Editing number below minimum: alert"
14014
+ },
14015
+ {
14016
+ key: "maximumValue",
14017
+ type: "(max: number) => string",
14018
+ state: "Editing number above maximum: alert"
14019
+ },
14020
+ {
14021
+ key: "rowsPerPage",
14022
+ type: "string",
14023
+ state: "Always: visible page-size text"
14024
+ },
14025
+ {
14026
+ key: "rowsPerPageLabel",
14027
+ type: "string",
14028
+ state: "Always: page-size Select accessible name"
14029
+ },
14030
+ {
14031
+ key: "rangeSummary",
14032
+ type: "(from: number, to: number, total: number) => string",
14033
+ state: "Every page and page-size change: visible summary and polite live region"
14034
+ },
14035
+ {
14036
+ key: "paginationNav",
14037
+ type: "(noun: string) => string",
14038
+ state: "Always: navigation accessible name; noun is the caller caption"
14039
+ },
14040
+ {
14041
+ key: "previous",
14042
+ type: "string",
14043
+ state: "Always: previous-page button name"
14044
+ },
14045
+ {
14046
+ key: "next",
14047
+ type: "string",
14048
+ state: "Always: next-page button name"
14049
+ },
14050
+ {
14051
+ key: "page",
14052
+ type: "(page: number) => string",
14053
+ state: "Always: numbered-page button name; number stays caller content"
14054
+ }
14055
+ ],
13481
14056
  uses: [
13482
14057
  "Table",
13483
14058
  "Checkbox",
@@ -13571,9 +14146,10 @@ const same = (a, b) => a.field === b.field && a.value === b.value;
13571
14146
  * Filter bar: search Input, saved views Select, an "Add filter" Menu (multi-select per field),
13572
14147
  * removable filter chips (Token) and Clear all.
13573
14148
  */
13574
- function FilterBar({ fields = DEPLOYMENT_FILTER_FIELDS, query: queryProp, defaultQuery = "", onQueryChange, filters: filtersProp, defaultFilters = DEPLOYMENT_DEFAULT_FILTERS, onFiltersChange, views = DEPLOYMENT_SAVED_VIEWS, defaultView = null, onViewChange, searchLabel: searchLabelProp, placeholder = "Search by name…", resultCount, className }) {
14149
+ function FilterBar({ fields = DEPLOYMENT_FILTER_FIELDS, query: queryProp, defaultQuery = "", onQueryChange, filters: filtersProp, defaultFilters = DEPLOYMENT_DEFAULT_FILTERS, onFiltersChange, views = DEPLOYMENT_SAVED_VIEWS, defaultView = null, onViewChange, searchLabel: searchLabelProp, placeholder: placeholderProp, resultCount, className, labels }) {
13575
14150
  const { t } = useI18n();
13576
- const searchLabel = searchLabelProp ?? t("common.search");
14151
+ const searchLabel = labels?.searchLabel ?? searchLabelProp ?? t("common.search");
14152
+ const placeholder = labels?.searchPlaceholder ?? placeholderProp ?? "Search by name…";
13577
14153
  const [innerQuery, setInnerQuery] = useState(defaultQuery);
13578
14154
  const [innerFilters, setInnerFilters] = useState(defaultFilters);
13579
14155
  const [view, setView] = useState(defaultView);
@@ -13605,7 +14181,7 @@ function FilterBar({ fields = DEPLOYMENT_FILTER_FIELDS, query: queryProp, defaul
13605
14181
  const hasAny = filters.length > 0 || query !== "";
13606
14182
  return /* @__PURE__ */ jsxs("div", {
13607
14183
  role: "search",
13608
- "aria-label": t("filters.label"),
14184
+ "aria-label": labels?.searchLandmark ?? t("filters.label"),
13609
14185
  className: cn("flex flex-col gap-3", className),
13610
14186
  children: [/* @__PURE__ */ jsxs("div", {
13611
14187
  className: "flex flex-col gap-2 sm:flex-row sm:items-center",
@@ -13623,9 +14199,9 @@ function FilterBar({ fields = DEPLOYMENT_FILTER_FIELDS, query: queryProp, defaul
13623
14199
  /* @__PURE__ */ jsxs("div", {
13624
14200
  className: "flex flex-wrap items-center gap-2",
13625
14201
  children: [views.length > 0 && /* @__PURE__ */ jsx(SimpleSelect, {
13626
- "aria-label": t("filters.savedView"),
14202
+ "aria-label": labels?.savedViewLabel ?? t("filters.savedView"),
13627
14203
  size: "sm",
13628
- placeholder: t("filters.savedViews"),
14204
+ placeholder: labels?.savedViewPlaceholder ?? t("filters.savedViews"),
13629
14205
  value: view,
13630
14206
  onValueChange: applyView,
13631
14207
  items: views.map((v) => ({
@@ -13639,7 +14215,7 @@ function FilterBar({ fields = DEPLOYMENT_FILTER_FIELDS, query: queryProp, defaul
13639
14215
  size: "sm",
13640
14216
  icon: Plus
13641
14217
  }),
13642
- children: t("filters.add")
14218
+ children: labels?.addFilter ?? t("filters.add")
13643
14219
  }), /* @__PURE__ */ jsx(MenuContent, {
13644
14220
  className: "max-h-80 min-w-[220px] overflow-y-auto",
13645
14221
  children: fields.map((field, i) => /* @__PURE__ */ jsxs(Fragment, { children: [i > 0 && /* @__PURE__ */ jsx(MenuSeparator, {}), /* @__PURE__ */ jsxs(MenuGroup, { children: [/* @__PURE__ */ jsx(MenuGroupLabel, { children: field.label }), field.options.map((option) => {
@@ -13655,17 +14231,17 @@ function FilterBar({ fields = DEPLOYMENT_FILTER_FIELDS, query: queryProp, defaul
13655
14231
  })] })] }, field.id))
13656
14232
  })] })]
13657
14233
  }),
13658
- resultCount !== void 0 && /* @__PURE__ */ jsxs("p", {
14234
+ resultCount !== void 0 && /* @__PURE__ */ jsx("p", {
13659
14235
  className: "text-[12.5px] text-muted-foreground sm:ms-auto",
13660
14236
  "aria-live": "polite",
13661
- children: [
14237
+ children: labels?.resultCount ? labels.resultCount(resultCount) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
13662
14238
  /* @__PURE__ */ jsx("span", {
13663
14239
  className: "font-mono text-foreground tabular-nums",
13664
14240
  children: resultCount.toLocaleString("en-US")
13665
14241
  }),
13666
14242
  " ",
13667
14243
  resultCount === 1 ? "result" : "results"
13668
- ]
14244
+ ] })
13669
14245
  })
13670
14246
  ]
13671
14247
  }), hasAny && /* @__PURE__ */ jsxs("div", {
@@ -13676,10 +14252,10 @@ function FilterBar({ fields = DEPLOYMENT_FILTER_FIELDS, query: queryProp, defaul
13676
14252
  children: [/* @__PURE__ */ jsx(ListFilter, {
13677
14253
  size: 12,
13678
14254
  "aria-hidden": true
13679
- }), "Filters"]
14255
+ }), labels?.filters ?? "Filters"]
13680
14256
  }),
13681
14257
  /* @__PURE__ */ jsx("ul", {
13682
- "aria-label": t("filters.active"),
14258
+ "aria-label": labels?.activeFilters ?? t("filters.active"),
13683
14259
  className: "flex flex-wrap items-center gap-2",
13684
14260
  children: filters.map((f) => /* @__PURE__ */ jsx("li", {
13685
14261
  className: "flex",
@@ -13687,7 +14263,7 @@ function FilterBar({ fields = DEPLOYMENT_FILTER_FIELDS, query: queryProp, defaul
13687
14263
  size: "sm",
13688
14264
  prefix: `${labelOf(f.field)}:`,
13689
14265
  label: f.value,
13690
- removeLabel: t("filters.remove", {
14266
+ removeLabel: labels?.removeFilter?.(labelOf(f.field), f.value) ?? t("filters.remove", {
13691
14267
  field: labelOf(f.field),
13692
14268
  value: f.value
13693
14269
  }),
@@ -13700,7 +14276,7 @@ function FilterBar({ fields = DEPLOYMENT_FILTER_FIELDS, query: queryProp, defaul
13700
14276
  size: "sm",
13701
14277
  className: "h-7 px-2 hover:text-destructive-text",
13702
14278
  onClick: clearAll,
13703
- children: "Clear all"
14279
+ children: labels?.clearAll ?? "Clear all"
13704
14280
  })
13705
14281
  ]
13706
14282
  })]
@@ -13708,11 +14284,68 @@ function FilterBar({ fields = DEPLOYMENT_FILTER_FIELDS, query: queryProp, defaul
13708
14284
  }
13709
14285
  //#endregion
13710
14286
  //#region src/tables/FilterBar/block.meta.ts
13711
- const meta$26 = {
14287
+ const meta$27 = {
13712
14288
  name: "Filter bar",
13713
14289
  family: "tables",
13714
14290
  status: "beta",
13715
14291
  description: "Search Input, saved views Select, an Add filter Menu with multi-select per field, removable filter chips and Clear all.",
14292
+ labels: [
14293
+ {
14294
+ key: "searchLandmark",
14295
+ type: "string",
14296
+ state: "Always: search landmark name"
14297
+ },
14298
+ {
14299
+ key: "searchLabel",
14300
+ type: "string",
14301
+ state: "Always: search input accessible name"
14302
+ },
14303
+ {
14304
+ key: "searchPlaceholder",
14305
+ type: "string",
14306
+ state: "Always: search input placeholder"
14307
+ },
14308
+ {
14309
+ key: "savedViewLabel",
14310
+ type: "string",
14311
+ state: "When views exist: Select accessible name"
14312
+ },
14313
+ {
14314
+ key: "savedViewPlaceholder",
14315
+ type: "string",
14316
+ state: "When no view selected: Select placeholder"
14317
+ },
14318
+ {
14319
+ key: "addFilter",
14320
+ type: "string",
14321
+ state: "Always: Add filter trigger text and name"
14322
+ },
14323
+ {
14324
+ key: "activeFilters",
14325
+ type: "string",
14326
+ state: "When filters or search exist: active-filters list name"
14327
+ },
14328
+ {
14329
+ key: "filters",
14330
+ type: "string",
14331
+ state: "When filters or search exist: chip section heading"
14332
+ },
14333
+ {
14334
+ key: "clearAll",
14335
+ type: "string",
14336
+ state: "When filters or search exist: clear button text and name"
14337
+ },
14338
+ {
14339
+ key: "removeFilter",
14340
+ type: "(field: string, value: string) => string",
14341
+ state: "When chip exists: remove button name; field and value are caller content"
14342
+ },
14343
+ {
14344
+ key: "resultCount",
14345
+ type: "(count: number) => string",
14346
+ state: "When resultCount supplied: visible count and polite live region"
14347
+ }
14348
+ ],
13716
14349
  uses: [
13717
14350
  "Input",
13718
14351
  "SimpleSelect",
@@ -13723,15 +14356,309 @@ const meta$26 = {
13723
14356
  ]
13724
14357
  };
13725
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
13726
14424
  //#region src/tables/PaginationFooter/block.meta.ts
13727
- const meta$45 = {
14425
+ const meta$47 = {
13728
14426
  name: "Pagination footer",
13729
14427
  family: "tables",
13730
14428
  status: "beta",
13731
14429
  description: "Table footer with a rows-per-page Select, a \"1–10 of 97\" summary and numbered Pagination; controlled or uncontrolled.",
14430
+ labels: [
14431
+ {
14432
+ key: "rowsPerPage",
14433
+ type: "string",
14434
+ state: "Always: visible page-size text"
14435
+ },
14436
+ {
14437
+ key: "rowsPerPageLabel",
14438
+ type: "string",
14439
+ state: "Always: page-size Select accessible name"
14440
+ },
14441
+ {
14442
+ key: "rangeSummary",
14443
+ type: "(from: number, to: number, total: number) => string",
14444
+ state: "Every page and page-size change: visible summary and polite live region"
14445
+ },
14446
+ {
14447
+ key: "paginationNav",
14448
+ type: "(noun: string) => string",
14449
+ state: "Always: navigation accessible name; noun is caller content or defaults to the provider translation of rows"
14450
+ },
14451
+ {
14452
+ key: "previous",
14453
+ type: "string",
14454
+ state: "Always: previous-page button name"
14455
+ },
14456
+ {
14457
+ key: "next",
14458
+ type: "string",
14459
+ state: "Always: next-page button name"
14460
+ },
14461
+ {
14462
+ key: "page",
14463
+ type: "(page: number) => string",
14464
+ state: "Always: numbered-page button name; number stays caller content"
14465
+ }
14466
+ ],
13732
14467
  uses: ["SimpleSelect", "Pagination"]
13733
14468
  };
13734
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
13735
14662
  //#region src/tables/TruncatedCollectionFooter/fixtures.ts
13736
14663
  /** Meaningful runtime defaults for the JavaScript catalogue preview. */
13737
14664
  const TRUNCATED_COLLECTION_PREVIEW = {
@@ -13771,7 +14698,7 @@ function TruncatedCollectionFooter({ visibleCount = TRUNCATED_COLLECTION_PREVIEW
13771
14698
  }
13772
14699
  //#endregion
13773
14700
  //#region src/tables/TruncatedCollectionFooter/block.meta.ts
13774
- const meta$72 = {
14701
+ const meta$74 = {
13775
14702
  name: "Truncated collection footer",
13776
14703
  family: "tables",
13777
14704
  status: "beta",
@@ -13978,7 +14905,7 @@ function InlineEditTable({ rows: initialRows = EDITABLE_MEMBERS, fields = EDITAB
13978
14905
  }
13979
14906
  //#endregion
13980
14907
  //#region src/tables/InlineEditRow/block.meta.ts
13981
- const meta$33 = {
14908
+ const meta$34 = {
13982
14909
  name: "Inline edit row",
13983
14910
  family: "tables",
13984
14911
  status: "beta",
@@ -14077,7 +15004,7 @@ function SubordinateList({ title, headingLevel, count, columns, rows, getRowId,
14077
15004
  }
14078
15005
  //#endregion
14079
15006
  //#region src/tables/SubordinateList/block.meta.ts
14080
- const meta$67 = {
15007
+ const meta$69 = {
14081
15008
  name: "Subordinate list",
14082
15009
  family: "tables",
14083
15010
  status: "beta",
@@ -14254,7 +15181,7 @@ function MembersTable({ members: members$1 = members, roles = memberRoles, curre
14254
15181
  }
14255
15182
  //#endregion
14256
15183
  //#region src/team/MembersTable/block.meta.ts
14257
- const meta$38 = {
15184
+ const meta$40 = {
14258
15185
  name: "Members table",
14259
15186
  family: "team",
14260
15187
  status: "stable",
@@ -14432,7 +15359,7 @@ function NotificationMatrix({ channels = notificationChannels, events = notifica
14432
15359
  }
14433
15360
  //#endregion
14434
15361
  //#region src/team/NotificationMatrix/block.meta.ts
14435
- const meta$42 = {
15362
+ const meta$44 = {
14436
15363
  name: "Notification matrix",
14437
15364
  family: "team",
14438
15365
  status: "stable",
@@ -14594,7 +15521,7 @@ function PendingInvitations({ invitations: invitations$1 = invitations, onResend
14594
15521
  }
14595
15522
  //#endregion
14596
15523
  //#region src/team/PendingInvitations/block.meta.ts
14597
- const meta$47 = {
15524
+ const meta$49 = {
14598
15525
  name: "Pending invitations",
14599
15526
  family: "team",
14600
15527
  status: "stable",
@@ -14719,7 +15646,7 @@ function ProfileHeader({ profile: profile$1 = profile, onAvatarChange = () => {}
14719
15646
  }
14720
15647
  //#endregion
14721
15648
  //#region src/team/ProfileHeader/block.meta.ts
14722
- const meta$51 = {
15649
+ const meta$53 = {
14723
15650
  name: "Profile header",
14724
15651
  family: "team",
14725
15652
  status: "stable",
@@ -14894,7 +15821,7 @@ function SessionsDevices({ sessions = deviceSessions, onRevoke, onRevokeOthers,
14894
15821
  }
14895
15822
  //#endregion
14896
15823
  //#region src/team/SessionsDevices/block.meta.ts
14897
- const meta$57 = {
15824
+ const meta$59 = {
14898
15825
  name: "Sessions and devices",
14899
15826
  family: "team",
14900
15827
  status: "stable",
@@ -14906,6 +15833,6 @@ const meta$57 = {
14906
15833
  ]
14907
15834
  };
14908
15835
  //#endregion
14909
- 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 };
14910
15837
 
14911
15838
  //# sourceMappingURL=index.js.map