@gntik-ai/blocks 0.7.0 → 0.9.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 (29) hide show
  1. package/dist/index.d.ts +34 -7
  2. package/dist/index.js +283 -109
  3. package/dist/index.js.map +1 -1
  4. package/package.json +2 -2
  5. package/src/builders/LogViewer/LogViewer.test.tsx +11 -0
  6. package/src/builders/LogViewer/LogViewer.tsx +28 -22
  7. package/src/forms/CredentialDisclosureDialog/CredentialDisclosureDialog.additional.test.tsx +467 -0
  8. package/src/forms/CredentialDisclosureDialog/CredentialDisclosureDialog.tsx +175 -106
  9. package/src/forms/CredentialDisclosureDialog/IssueOnClick.test.tsx +56 -0
  10. package/src/forms/CredentialDisclosureDialog/SecretCopy.tsx +83 -0
  11. package/src/forms/CredentialDisclosureDialog/block.meta.ts +1 -1
  12. package/src/forms/CredentialDisclosureDialog/examples/Inline.tsx +19 -0
  13. package/src/forms/CredentialDisclosureDialog/examples/IssueOnClick.tsx +87 -0
  14. package/src/forms/CredentialDisclosureDialog/examples/MultiSecret.tsx +29 -0
  15. package/src/forms/CredentialDisclosureDialog/focus.ts +18 -0
  16. package/src/forms/CredentialDisclosureDialog/types.ts +5 -0
  17. package/src/page-chrome/PageHeader/PageHeader.test.tsx +18 -0
  18. package/src/page-chrome/PageHeader/PageHeader.tsx +3 -1
  19. package/src/page-chrome/PageHeader/block.meta.ts +1 -1
  20. package/src/page-chrome/PageHeader/examples/Spanish.tsx +11 -0
  21. package/src/tables/DataTable/DataTable.labels.test.tsx +2 -0
  22. package/src/tables/DataTable/DataTable.locale.test.tsx +153 -0
  23. package/src/tables/DataTable/DataTable.server-pagination.test.tsx +1 -1
  24. package/src/tables/DataTable/DataTable.test.tsx +16 -0
  25. package/src/tables/DataTable/block.meta.ts +2 -0
  26. package/src/tables/DataTable/data-table-row.tsx +18 -2
  27. package/src/tables/DataTable/data-table-utils.ts +18 -4
  28. package/src/tables/DataTable/labels.ts +2 -0
  29. package/src/test/CredentialDisclosureDialog.compatibility.tsx +30 -0
package/dist/index.d.ts CHANGED
@@ -1815,6 +1815,13 @@ export declare function CreateApiKeyDialog({ scopes, expiries, defaultExpiry, on
1815
1815
  //#region src/forms/CreateApiKeyDialog/block.meta.d.ts
1816
1816
  declare const meta$13: BlockMeta;
1817
1817
  //#endregion
1818
+ //#region src/forms/CredentialDisclosureDialog/types.d.ts
1819
+ interface CredentialSecret {
1820
+ id: string;
1821
+ label: string;
1822
+ value: string;
1823
+ }
1824
+ //#endregion
1818
1825
  //#region src/forms/CredentialDisclosureDialog/CredentialDisclosureDialog.d.ts
1819
1826
  export interface CredentialDisclosure {
1820
1827
  variant: 'stored' | 'fresh';
@@ -1824,9 +1831,21 @@ export interface CredentialDisclosure {
1824
1831
  secret: string;
1825
1832
  }
1826
1833
  export interface CredentialDisclosureDialogProps {
1834
+ /** Additional masked values; ids must be unique, non-empty and not "secret". */
1835
+ additionalSecrets?: readonly CredentialSecret[];
1836
+ /** Mask a fresh primary secret; read at the start of each session. */
1837
+ maskFresh?: boolean;
1838
+ /** Redacted content below the secrets; clear secret-bearing content on close. */
1839
+ revealContent?: ReactNode;
1840
+ /** Presentation fixed for each non-null opening. Defaults to a modal dialog. */
1841
+ presentation?: 'dialog' | 'inline';
1842
+ /** Called after copying with the secret id (primary: "secret"), never its value. */
1843
+ onCopy?: (id: string) => void;
1844
+ /** Label-only success announcement override, used only in multi-secret mode. */
1845
+ copiedAnnouncementFor?: (label: string) => string;
1827
1846
  /** Set only after a successful response. Leave null while pending or on failure. */
1828
1847
  disclosure: CredentialDisclosure | null;
1829
- /** Clear disclosure to null on dismissal, dropping the secret in the consumer. */
1848
+ /** Clear disclosure, additionalSecrets and secret-bearing revealContent on dismissal. */
1830
1849
  onClose: () => void;
1831
1850
  /** Resolve the current row action at close time, including after list reloads. */
1832
1851
  resolveReturnFocus?: () => HTMLElement | null;
@@ -1848,9 +1867,10 @@ export interface CredentialDisclosureDialogProps {
1848
1867
  closeLabel?: string;
1849
1868
  }
1850
1869
  /**
1851
- * Discloses an existing credential only after a successful response. Consumers keep disclosure
1852
- * null while pending or on failure, and clear it on close. No pending/error state or internal
1853
- * secret retention. A fresh secret requires a new successful response to be shown again.
1870
+ * Render only successful responses. Keep disclosure null while pending or on failure.
1871
+ * On close, clear disclosure, additionalSecrets and any secret-bearing revealContent.
1872
+ * No pending/error state or internal secret retention. Retained dismissed sessions stay closed;
1873
+ * a changed credential/value or a null-to-value opening starts a new session.
1854
1874
  */
1855
1875
  export declare function CredentialDisclosureDialog(props: CredentialDisclosureDialogProps): import("react").JSX.Element | null;
1856
1876
  //#endregion
@@ -2904,8 +2924,13 @@ export declare function selectionState(visibleIds: readonly string[], selected:
2904
2924
  /** Selects all of `ids` when not all are selected; otherwise clears them. Other selections are kept. */
2905
2925
  export declare function toggleAll(ids: readonly string[], selected: ReadonlySet<string>): Set<string>;
2906
2926
  export declare function toggleOne(id: string, selected: ReadonlySet<string>): Set<string>;
2907
- /** Default cell text for a raw value. */
2908
- export declare function formatCell(value: CellValue): ReactNode;
2927
+ /** Optional locale and boolean text for default cells. */
2928
+ export interface DataTableCellFormatOptions {
2929
+ locale?: string;
2930
+ booleanLabels?: [trueLabel: string, falseLabel: string];
2931
+ }
2932
+ /** Default cell text for a raw value. Omitting options preserves the legacy output. */
2933
+ export declare function formatCell(value: CellValue, options?: DataTableCellFormatOptions): ReactNode;
2909
2934
  /** Groups rows by a field key or by a function returning the group key. */
2910
2935
  export type DataTableGroupBy<T> = Extract<keyof T, string> | ((row: T) => string | number | null | undefined);
2911
2936
  /** One group of rows, in display order. */
@@ -2978,6 +3003,8 @@ export declare function PaginationFooter({ total, page: pageProp, defaultPage, o
2978
3003
  //#region src/tables/DataTable/labels.d.ts
2979
3004
  /** Per-instance table chrome, including the composed PaginationFooter. Caller data stays caller-owned. */
2980
3005
  interface DataTableLabels extends PaginationFooterLabels {
3006
+ booleanTrue: string;
3007
+ booleanFalse: string;
2981
3008
  /** Non-virtual table overflow region; virtualized regions keep the caller caption. */
2982
3009
  scrollRegion: string;
2983
3010
  selectionCount: (count: number) => string;
@@ -3730,5 +3757,5 @@ export declare function SessionsDevices({ sessions, onRevoke, onRevokeOthers, ti
3730
3757
  //#region src/team/SessionsDevices/block.meta.d.ts
3731
3758
  declare const meta$60: BlockMeta;
3732
3759
  //#endregion
3733
- export { type ApiKeyExpiry, type ApiKeyScope, type Assistant, type AssistantStatus, type AuthFormAccessibilityProps, type AuthHeaderProps, type AuthIdentifierConfig, type AuthSignUpField, type AuthSignUpValidationMessages, type AuthUnavailableState, type AuthValidationMessages, type BlockMeta, type CodeFile, type CodePanelMarker, type CodeProblem, type ColumnResizeHandleProps, type ColumnVisibilityMenuProps, type ColumnWidths, type ConfirmDestructiveDialogProps, type ConsoleEntry, type CostPoint, type DangerZoneAction, type DataTableCellEdit, type DataTableCellEditHandler, type DataTableCellEditResult, type DataTableLabels, type DataTableProps, type DataTableView, type DataTableViewState, ViewSwitcher as DataTableViewSwitcher, type ViewSwitcherProps as DataTableViewSwitcherProps, type DensityToggleProps, type DeploymentRow, type DeviceKind, type DeviceSession, type EditableMember, type EvalMetric, type EvalRow, type EventKind, type EventTone, type FeedbackAction, type FlowConnection, type FlowConnectionRejection, type FlowEdge, type FlowHandle, type FlowNode, type FlowNodeData, type FlowNodeKind, type FlowNodeRenderProps, type FlowNodeRenderer, type FlowTone, type FlowValidationIssue, type Invitation, type LogLevel, type LogLine, type MarketingAction, type Member, type ModelKey, type ModelKeyStatus, type MonacoReady, type NodeInspectorProps, type NodePaletteProps, type NotificationChannel, type NotificationEvent, type NotificationMatrixValue, type PageChromeAction, type PaletteItem, type PanelHeading, type PinSide, type PinnedColumns, type PlanSummaryProps, type ProblemSeverity, type Profile, type ProfileMetaItem, type RoleOption, type RunConsoleProps, type ScheduleEvent, type SpanDetailsProps, type SpanKind, type SsoProvider, type SummaryPlan, type TokenUsagePeriod, type TraceSpan, type TrafficRow, type UploadItem, type UploadStatus, type ValidationIssue, meta$1 as activityFeedMeta, meta$2 as agendaListMeta, meta$3 as appSidebarMeta, meta$4 as appTopbarMeta, meta$5 as assistantCardGridMeta, meta$6 as bulkActionBarMeta, meta$7 as chartCardMeta, meta$8 as codePanelMeta, meta$9 as commentThreadMeta, meta$10 as comparisonTableMeta, meta$11 as confirmDestructiveMeta, meta$12 as costBreakdownMeta, meta$13 as createApiKeyDialogMeta, meta$14 as credentialDisclosureDialogMeta, meta$15 as cursorPagerFooterMeta, meta$16 as dangerZoneMeta, meta$17 as dataTableMeta, meta$18 as dateRangeFilterMeta, meta$19 as descriptionListCardMeta, meta$20 as dialogWizardMeta, meta$21 as emptyStatesMeta, meta$22 as environmentBadgeMeta, meta$23 as errorPanelMeta, meta$24 as evaluationScorecardMeta, meta$25 as faqMeta, meta$26 as featureGridMeta, meta$27 as fileUploadPanelMeta, meta$28 as filterBarMeta, meta$29 as flowBuilderMeta, meta$30 as forgotPasswordFormMeta, meta$31 as formSectionMeta, meta$32 as globalSearchMeta, meta$33 as heroMeta, meta$34 as inlineCalloutMeta, meta$35 as inlineEditRowMeta, meta$36 as inviteMembersDialogMeta, meta$37 as invoiceTableMeta, meta$38 as kpiRowMeta, meta$39 as loadMoreFooterMeta, meta$40 as logViewerMeta, meta$41 as membersTableMeta, meta$42 as mfaChallengeMeta, meta$43 as modelKeysListMeta, meta$44 as monthCalendarMeta, meta$45 as notificationMatrixMeta, meta$46 as pageHeaderMeta, meta$47 as pageToolbarMeta, meta$48 as paginationFooterMeta, meta$49 as paymentMethodCardMeta, meta$50 as pendingInvitationsMeta, meta$51 as planCardMeta, meta$52 as planDefinitionCardMeta, meta$53 as pricingTableMeta, meta$54 as profileHeaderMeta, meta$55 as promptEditorMeta, meta$56 as quotaMetersMeta, meta$57 as resetPasswordFormMeta, meta$58 as resourceCardGridMeta, deviceSessions as sampleDeviceSessions, invitations$1 as sampleInvitations, members$1 as sampleMembers, profile$1 as sampleProfile, sampleEvents as sampleScheduleEvents, sampleToday as sampleScheduleToday, meta$59 as sectionHeaderMeta, meta$60 as sessionsDevicesMeta, meta$61 as settingsRowMeta, meta$62 as signInFormMeta, meta$63 as signUpFormMeta, meta$64 as skeletonsMeta, meta$65 as spendVsBudgetMeta, meta$66 as ssoButtonsMeta, meta$67 as statCardMeta, meta$68 as statusTimelineMeta, meta$69 as stickyActionBarMeta, meta$70 as subordinateListMeta, meta$71 as systemBannerMeta, meta$72 as timeSlotPickerMeta, meta$73 as tokenCostCardMeta, meta$74 as traceWaterfallMeta, meta$75 as truncatedCollectionFooterMeta, validationIssues$1 as validationIssues, meta$76 as validationSummaryMeta, meta$77 as weekCalendarMeta };
3760
+ export { type ApiKeyExpiry, type ApiKeyScope, type Assistant, type AssistantStatus, type AuthFormAccessibilityProps, type AuthHeaderProps, type AuthIdentifierConfig, type AuthSignUpField, type AuthSignUpValidationMessages, type AuthUnavailableState, type AuthValidationMessages, type BlockMeta, type CodeFile, type CodePanelMarker, type CodeProblem, type ColumnResizeHandleProps, type ColumnVisibilityMenuProps, type ColumnWidths, type ConfirmDestructiveDialogProps, type ConsoleEntry, type CostPoint, type CredentialSecret, type DangerZoneAction, type DataTableCellEdit, type DataTableCellEditHandler, type DataTableCellEditResult, type DataTableLabels, type DataTableProps, type DataTableView, type DataTableViewState, ViewSwitcher as DataTableViewSwitcher, type ViewSwitcherProps as DataTableViewSwitcherProps, type DensityToggleProps, type DeploymentRow, type DeviceKind, type DeviceSession, type EditableMember, type EvalMetric, type EvalRow, type EventKind, type EventTone, type FeedbackAction, type FlowConnection, type FlowConnectionRejection, type FlowEdge, type FlowHandle, type FlowNode, type FlowNodeData, type FlowNodeKind, type FlowNodeRenderProps, type FlowNodeRenderer, type FlowTone, type FlowValidationIssue, type Invitation, type LogLevel, type LogLine, type MarketingAction, type Member, type ModelKey, type ModelKeyStatus, type MonacoReady, type NodeInspectorProps, type NodePaletteProps, type NotificationChannel, type NotificationEvent, type NotificationMatrixValue, type PageChromeAction, type PaletteItem, type PanelHeading, type PinSide, type PinnedColumns, type PlanSummaryProps, type ProblemSeverity, type Profile, type ProfileMetaItem, type RoleOption, type RunConsoleProps, type ScheduleEvent, type SpanDetailsProps, type SpanKind, type SsoProvider, type SummaryPlan, type TokenUsagePeriod, type TraceSpan, type TrafficRow, type UploadItem, type UploadStatus, type ValidationIssue, meta$1 as activityFeedMeta, meta$2 as agendaListMeta, meta$3 as appSidebarMeta, meta$4 as appTopbarMeta, meta$5 as assistantCardGridMeta, meta$6 as bulkActionBarMeta, meta$7 as chartCardMeta, meta$8 as codePanelMeta, meta$9 as commentThreadMeta, meta$10 as comparisonTableMeta, meta$11 as confirmDestructiveMeta, meta$12 as costBreakdownMeta, meta$13 as createApiKeyDialogMeta, meta$14 as credentialDisclosureDialogMeta, meta$15 as cursorPagerFooterMeta, meta$16 as dangerZoneMeta, meta$17 as dataTableMeta, meta$18 as dateRangeFilterMeta, meta$19 as descriptionListCardMeta, meta$20 as dialogWizardMeta, meta$21 as emptyStatesMeta, meta$22 as environmentBadgeMeta, meta$23 as errorPanelMeta, meta$24 as evaluationScorecardMeta, meta$25 as faqMeta, meta$26 as featureGridMeta, meta$27 as fileUploadPanelMeta, meta$28 as filterBarMeta, meta$29 as flowBuilderMeta, meta$30 as forgotPasswordFormMeta, meta$31 as formSectionMeta, meta$32 as globalSearchMeta, meta$33 as heroMeta, meta$34 as inlineCalloutMeta, meta$35 as inlineEditRowMeta, meta$36 as inviteMembersDialogMeta, meta$37 as invoiceTableMeta, meta$38 as kpiRowMeta, meta$39 as loadMoreFooterMeta, meta$40 as logViewerMeta, meta$41 as membersTableMeta, meta$42 as mfaChallengeMeta, meta$43 as modelKeysListMeta, meta$44 as monthCalendarMeta, meta$45 as notificationMatrixMeta, meta$46 as pageHeaderMeta, meta$47 as pageToolbarMeta, meta$48 as paginationFooterMeta, meta$49 as paymentMethodCardMeta, meta$50 as pendingInvitationsMeta, meta$51 as planCardMeta, meta$52 as planDefinitionCardMeta, meta$53 as pricingTableMeta, meta$54 as profileHeaderMeta, meta$55 as promptEditorMeta, meta$56 as quotaMetersMeta, meta$57 as resetPasswordFormMeta, meta$58 as resourceCardGridMeta, deviceSessions as sampleDeviceSessions, invitations$1 as sampleInvitations, members$1 as sampleMembers, profile$1 as sampleProfile, sampleEvents as sampleScheduleEvents, sampleToday as sampleScheduleToday, meta$59 as sectionHeaderMeta, meta$60 as sessionsDevicesMeta, meta$61 as settingsRowMeta, meta$62 as signInFormMeta, meta$63 as signUpFormMeta, meta$64 as skeletonsMeta, meta$65 as spendVsBudgetMeta, meta$66 as ssoButtonsMeta, meta$67 as statCardMeta, meta$68 as statusTimelineMeta, meta$69 as stickyActionBarMeta, meta$70 as subordinateListMeta, meta$71 as systemBannerMeta, meta$72 as timeSlotPickerMeta, meta$73 as tokenCostCardMeta, meta$74 as traceWaterfallMeta, meta$75 as truncatedCollectionFooterMeta, validationIssues$1 as validationIssues, meta$76 as validationSummaryMeta, meta$77 as weekCalendarMeta };
3734
3761
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use client';
2
- import { Fragment, createElement, useCallback, useEffect, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
2
+ import { Fragment, createElement, useCallback, useEffect, useEffectEvent, useId, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
3
3
  import { Activity, Archive, ArrowDown, ArrowLeft, ArrowRight, ArrowUp, BarChart3, Bookmark, Bot, Boxes, Braces, Building2, CalendarCheck, CalendarDays, Camera, Check, ChevronDown, ChevronLeft, ChevronRight, ChevronsUpDown, CircleAlert, CircleCheck, CircleHelp, CircleX, Clock, Cog, Columns3, Copy, CreditCard, Database, Download, ExternalLink, Eye, FileCode, FileText, FolderKanban, FolderPlus, Gauge, GitBranch, Globe, HardDrive, Home, Inbox, Info, KeyRound, Layers, LayoutGrid, List, ListFilter, Lock, LogOut, Mail, MailCheck, MapPin, Minus, Monitor, MousePointerClick, Pencil, Play, PlugZap, Plus, RefreshCw, Rocket, RotateCcw, RotateCw, Rows2, Rows3, Search, SearchX, Server, ServerCrash, Settings, ShieldCheck, SlidersHorizontal, Smartphone, Sparkles, Table2, Tablet, Trash2, TriangleAlert, Upload, User, UserMinus, UserPlus, Users, Workflow, Wrench, X, Zap } from "@gntik-ai/icons";
4
- import { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, Alert, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, Avatar, Badge, Breadcrumbs, Button, Card, CardAction, CardBody, CardDescription, CardHeader, CardTitle, Checkbox, CheckboxGroup, ClickableCard, CodeBlock, Collapsible, CollapsiblePanel, CollapsibleTrigger, CommandPalette, CommandPaletteTrigger, CopyButton, 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";
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, foldText, matchRanges, nextSortDirection, tableVariants, toDate, useAnnounce, useDensity, useHasLiveAnnouncer, useI18n, useOptionalI18n } 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";
@@ -5130,23 +5130,18 @@ const LEVEL_STYLE = {
5130
5130
  }
5131
5131
  };
5132
5132
  /** Wraps case-insensitive matches of `query` in <mark>. */
5133
- function highlight(text, query) {
5134
- if (!query) return text;
5135
- const lower = text.toLowerCase();
5136
- const q = query.toLowerCase();
5133
+ function highlight(text, query, locale) {
5137
5134
  const parts = [];
5138
5135
  let from = 0;
5139
- let at = lower.indexOf(q, from);
5140
- while (at !== -1) {
5141
- if (at > from) parts.push(text.slice(from, at));
5136
+ for (const [start, end] of matchRanges(text, query, { locale })) {
5137
+ parts.push(text.slice(from, start));
5142
5138
  parts.push(/* @__PURE__ */ jsx("mark", {
5143
5139
  className: "rounded-sm bg-warning/30 text-foreground",
5144
- children: text.slice(at, at + q.length)
5145
- }, at));
5146
- from = at + q.length;
5147
- at = lower.indexOf(q, from);
5140
+ children: text.slice(start, end)
5141
+ }, start));
5142
+ from = end;
5148
5143
  }
5149
- if (from < text.length) parts.push(text.slice(from));
5144
+ parts.push(text.slice(from));
5150
5145
  return parts;
5151
5146
  }
5152
5147
  function lineText(line) {
@@ -5158,6 +5153,7 @@ function lineText(line) {
5158
5153
  * follow-tail and per-line copy.
5159
5154
  */
5160
5155
  function LogViewer({ lines = logLines, title = "Logs", height = 360, rowHeight = 24, overscan = 8, defaultLevels = LOG_LEVELS, defaultFollow = true, onCopyLine, onSelectLine, selectedLineId, announceLines = true, titleAs: TitleTag = "h3", className }) {
5156
+ const { locale } = useI18n();
5161
5157
  const titleId = useId();
5162
5158
  const viewport = useRef(null);
5163
5159
  const copyTimer = useRef(void 0);
@@ -5176,13 +5172,19 @@ function LogViewer({ lines = logLines, title = "Logs", height = 360, rowHeight =
5176
5172
  for (const l of lines) c[l.level] += 1;
5177
5173
  return c;
5178
5174
  }, [lines]);
5175
+ const foldedLines = useMemo(() => lines.map((line) => ({
5176
+ line,
5177
+ message: foldText(line.message, locale),
5178
+ source: foldText(line.source ?? "", locale)
5179
+ })), [lines, locale]);
5179
5180
  const visible = useMemo(() => {
5180
- const q = query.trim().toLowerCase();
5181
- return lines.filter((l) => levels.includes(l.level) && (!q || l.message.toLowerCase().includes(q) || (l.source ?? "").toLowerCase().includes(q)));
5181
+ const q = foldText(query.trim(), locale);
5182
+ return foldedLines.filter(({ line, message, source }) => levels.includes(line.level) && (!q || message.indexOf(q) !== -1 || source.indexOf(q) !== -1)).map(({ line }) => line);
5182
5183
  }, [
5183
- lines,
5184
+ foldedLines,
5184
5185
  levels,
5185
- query
5186
+ query,
5187
+ locale
5186
5188
  ]);
5187
5189
  const total = visible.length * rowHeight;
5188
5190
  const maxScroll = Math.max(0, total - height);
@@ -5298,13 +5300,13 @@ function LogViewer({ lines = logLines, title = "Logs", height = 360, rowHeight =
5298
5300
  className: "hidden shrink-0 text-muted-foreground sm:inline",
5299
5301
  children: [
5300
5302
  "[",
5301
- highlight(line.source, query.trim()),
5303
+ highlight(line.source, query, locale),
5302
5304
  "]"
5303
5305
  ]
5304
5306
  }),
5305
5307
  /* @__PURE__ */ jsx("span", {
5306
5308
  className: "min-w-0 flex-1 truncate text-foreground",
5307
- children: highlight(line.message, query.trim())
5309
+ children: highlight(line.message, query, locale)
5308
5310
  }),
5309
5311
  onSelectLine && /* @__PURE__ */ jsx(IconButton, {
5310
5312
  size: "sm",
@@ -8056,11 +8058,78 @@ const meta$12 = {
8056
8058
  ]
8057
8059
  };
8058
8060
  //#endregion
8061
+ //#region src/forms/CredentialDisclosureDialog/SecretCopy.tsx
8062
+ /** Each secret owns feedback so simultaneous settlements cannot overwrite each other. */
8063
+ function SecretCopy({ secret, options, grouped = false, masked = true, warning }) {
8064
+ const { t } = useI18n();
8065
+ const [pending, setPending] = useState(false);
8066
+ const copied = options.copiedLabel ?? t("credentialDisclosure.copied");
8067
+ const content = /* @__PURE__ */ jsxs(LiveAnnouncer, { children: [
8068
+ warning,
8069
+ /* @__PURE__ */ jsx("div", {
8070
+ "data-kit-redact": true,
8071
+ children: masked ? /* @__PURE__ */ jsx(SecretField, {
8072
+ value: secret.value,
8073
+ copyable: false,
8074
+ "aria-label": secret.label,
8075
+ showLabel: options.showLabel ?? t("credentialDisclosure.show"),
8076
+ hideLabel: options.hideLabel ?? t("credentialDisclosure.hide")
8077
+ }) : /* @__PURE__ */ jsx(CodeBlock, {
8078
+ code: secret.value,
8079
+ copyable: false,
8080
+ label: secret.label,
8081
+ wrapToggle: false,
8082
+ defaultWrap: true
8083
+ })
8084
+ }),
8085
+ /* @__PURE__ */ jsx(CopyButton, {
8086
+ value: () => {
8087
+ if (grouped) setPending(true);
8088
+ return secret.value;
8089
+ },
8090
+ loading: grouped && pending,
8091
+ display: "label",
8092
+ label: options.copyLabel ?? t("credentialDisclosure.copy"),
8093
+ copiedLabel: copied,
8094
+ announcement: grouped ? options.copiedAnnouncementFor?.(secret.label) ?? `${secret.label}: ${copied}` : options.successAnnouncement ?? t("credentialDisclosure.success"),
8095
+ failureLabel: options.failureAnnouncement ?? t("credentialDisclosure.failure"),
8096
+ failureAnnouncement: options.failureAnnouncement ?? t("credentialDisclosure.failure"),
8097
+ failurePoliteness: "polite",
8098
+ onCopy: () => {
8099
+ if (grouped) setPending(false);
8100
+ options.onCopy?.(secret.id);
8101
+ },
8102
+ onCopyError: () => {
8103
+ if (grouped) setPending(false);
8104
+ }
8105
+ })
8106
+ ] });
8107
+ return grouped ? /* @__PURE__ */ jsx("div", {
8108
+ role: "group",
8109
+ "aria-label": secret.label,
8110
+ children: content
8111
+ }) : content;
8112
+ }
8113
+ //#endregion
8114
+ //#region src/forms/CredentialDisclosureDialog/focus.ts
8115
+ /** Programmatic focus permits negative tabIndex, but never hidden, inert or disabled targets. */
8116
+ function usableFocusTarget(element) {
8117
+ if (!(element instanceof HTMLElement) || !element.isConnected || element === document.body) return false;
8118
+ if (element.matches(":disabled, [disabled], [aria-disabled=\"true\"], input[type=\"hidden\"]")) return false;
8119
+ for (let ancestor = element; ancestor; ancestor = ancestor.parentElement) {
8120
+ if (ancestor.hidden || ancestor.hasAttribute("inert") || ancestor.getAttribute("aria-disabled") === "true") return false;
8121
+ const style = getComputedStyle(ancestor);
8122
+ if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse" || style.contentVisibility === "hidden") return false;
8123
+ }
8124
+ return element.tabIndex >= 0 || element.hasAttribute("tabindex") || element.isContentEditable;
8125
+ }
8126
+ //#endregion
8059
8127
  //#region src/forms/CredentialDisclosureDialog/CredentialDisclosureDialog.tsx
8060
8128
  /**
8061
- * Discloses an existing credential only after a successful response. Consumers keep disclosure
8062
- * null while pending or on failure, and clear it on close. No pending/error state or internal
8063
- * secret retention. A fresh secret requires a new successful response to be shown again.
8129
+ * Render only successful responses. Keep disclosure null while pending or on failure.
8130
+ * On close, clear disclosure, additionalSecrets and any secret-bearing revealContent.
8131
+ * No pending/error state or internal secret retention. Retained dismissed sessions stay closed;
8132
+ * a changed credential/value or a null-to-value opening starts a new session.
8064
8133
  */
8065
8134
  function CredentialDisclosureDialog(props) {
8066
8135
  if (!props.disclosure) return null;
@@ -8071,93 +8140,182 @@ function CredentialDisclosureDialog(props) {
8071
8140
  }
8072
8141
  function DisclosureOpening(props) {
8073
8142
  const [opener] = useState(() => typeof document === "undefined" ? null : document.activeElement);
8143
+ const [presentation] = useState(props.presentation ?? "dialog");
8144
+ const root = useRef(null);
8145
+ const target = useRef(null);
8146
+ const active = useRef(opener);
8147
+ const started = useRef(false);
8148
+ const activeWasInside = useRef(false);
8149
+ const returnFocus = () => {
8150
+ const current = props.resolveReturnFocus?.();
8151
+ if (usableFocusTarget(current)) return current;
8152
+ const fallback = props.fallbackFocus?.();
8153
+ if (usableFocusTarget(fallback)) return fallback;
8154
+ return usableFocusTarget(opener) ? opener : false;
8155
+ };
8156
+ const restore = useEffectEvent(() => {
8157
+ if (root.current?.contains(document.activeElement)) {
8158
+ const element = returnFocus();
8159
+ if (element) element.focus();
8160
+ }
8161
+ });
8162
+ useLayoutEffect(() => {
8163
+ const track = () => {
8164
+ if (document.activeElement !== document.body) {
8165
+ active.current = document.activeElement;
8166
+ activeWasInside.current = root.current?.contains(document.activeElement) ?? false;
8167
+ }
8168
+ };
8169
+ document.addEventListener("focusin", track);
8170
+ return () => {
8171
+ document.removeEventListener("focusin", track);
8172
+ restore();
8173
+ };
8174
+ }, [presentation]);
8175
+ useLayoutEffect(() => {
8176
+ if (activeWasInside.current && active.current && !active.current.isConnected) target.current?.focus();
8177
+ });
8178
+ const seen = /* @__PURE__ */ new Set(["secret", ""]);
8179
+ const additionalSecrets = (props.additionalSecrets ?? []).filter(({ id }) => {
8180
+ if (seen.has(id)) return false;
8181
+ seen.add(id);
8182
+ return true;
8183
+ });
8074
8184
  const { variant, credentialId, secret } = props.disclosure;
8075
8185
  return /* @__PURE__ */ jsx(DisclosureSession, {
8076
8186
  ...props,
8077
- opener
8187
+ presentation,
8188
+ additionalSecrets,
8189
+ onRootRef: (node) => {
8190
+ root.current = node;
8191
+ },
8192
+ onTargetRef: (node) => {
8193
+ target.current = node;
8194
+ },
8195
+ onPopupRef: (node) => {
8196
+ root.current = node;
8197
+ target.current = node;
8198
+ },
8199
+ containsFocus: () => root.current?.contains(document.activeElement) ?? false,
8200
+ initialFocus: () => {
8201
+ const shouldFocus = !started.current || activeWasInside.current && !active.current?.isConnected;
8202
+ started.current = true;
8203
+ return shouldFocus ? root.current : false;
8204
+ },
8205
+ returnFocus
8078
8206
  }, JSON.stringify([
8079
8207
  variant,
8080
8208
  credentialId,
8081
- secret
8209
+ secret,
8210
+ ...additionalSecrets.map(({ id, value }) => [id, value])
8082
8211
  ]));
8083
8212
  }
8084
- function DisclosureSession({ disclosure, onClose, resolveReturnFocus, fallbackFocus, opener, ...labels }) {
8213
+ function DisclosureSession(props) {
8085
8214
  const { t } = useI18n();
8215
+ const { disclosure, onRootRef, onTargetRef, onPopupRef, initialFocus, containsFocus, presentation, additionalSecrets = [] } = props;
8086
8216
  const [open, setOpen] = useState(true);
8087
- const popup = useRef(null);
8217
+ const [maskFresh] = useState(props.maskFresh ?? false);
8088
8218
  const dismissed = useRef(false);
8089
- const returnFocus = () => {
8090
- const target = resolveReturnFocus?.();
8091
- if (usableFocusTarget(target)) return target;
8092
- const fallback = fallbackFocus?.();
8093
- if (usableFocusTarget(fallback)) return fallback;
8094
- return usableFocusTarget(opener) ? opener : false;
8095
- };
8096
- const closeLabel = labels.closeLabel ?? t("credentialDisclosure.close");
8097
- const secretLabel = labels.secretLabel ?? t("credentialDisclosure.secret");
8219
+ const headingId = useId();
8220
+ const close = () => {
8221
+ if (dismissed.current) return;
8222
+ dismissed.current = true;
8223
+ if (presentation === "inline" && containsFocus()) {
8224
+ const element = props.returnFocus();
8225
+ if (element) element.focus();
8226
+ }
8227
+ setOpen(false);
8228
+ props.onClose();
8229
+ };
8230
+ const closeLabel = props.closeLabel ?? t("credentialDisclosure.close");
8231
+ const title = props.title ?? t("credentialDisclosure.title");
8232
+ const description = props.description ?? t("credentialDisclosure.description");
8233
+ const secretLabel = props.secretLabel ?? t("credentialDisclosure.secret");
8234
+ const warning = disclosure.variant === "fresh" ? /* @__PURE__ */ jsx(Alert, {
8235
+ role: presentation === "inline" ? "note" : "alert",
8236
+ tone: "warning",
8237
+ title: props.warningTitle ?? t("credentialDisclosure.warningTitle"),
8238
+ description: props.warningText ?? t("credentialDisclosure.warningText")
8239
+ }) : null;
8240
+ const body = /* @__PURE__ */ jsxs(Fragment$1, { children: [
8241
+ /* @__PURE__ */ jsxs("dl", {
8242
+ className: "grid grid-cols-2 gap-2 text-sm",
8243
+ children: [
8244
+ /* @__PURE__ */ jsx("dt", {
8245
+ className: "text-muted-foreground",
8246
+ children: props.credentialIdLabel ?? t("credentialDisclosure.credentialId")
8247
+ }),
8248
+ /* @__PURE__ */ jsx("dd", {
8249
+ className: "break-all font-mono",
8250
+ children: disclosure.credentialId
8251
+ }),
8252
+ /* @__PURE__ */ jsx("dt", {
8253
+ className: "text-muted-foreground",
8254
+ children: props.expiryLabel ?? t("credentialDisclosure.expiry")
8255
+ }),
8256
+ /* @__PURE__ */ jsx("dd", { children: disclosure.expiresAt })
8257
+ ]
8258
+ }),
8259
+ /* @__PURE__ */ jsx(SecretCopy, {
8260
+ secret: {
8261
+ id: "secret",
8262
+ label: secretLabel,
8263
+ value: disclosure.secret
8264
+ },
8265
+ options: props,
8266
+ grouped: additionalSecrets.length > 0,
8267
+ masked: disclosure.variant === "stored" || maskFresh,
8268
+ warning
8269
+ }),
8270
+ additionalSecrets.map((secret) => /* @__PURE__ */ jsx(SecretCopy, {
8271
+ secret,
8272
+ options: props,
8273
+ grouped: true
8274
+ }, secret.id)),
8275
+ props.revealContent != null && /* @__PURE__ */ jsx("div", {
8276
+ "data-kit-redact": true,
8277
+ children: props.revealContent
8278
+ })
8279
+ ] });
8280
+ if (presentation === "inline") {
8281
+ if (!open) return null;
8282
+ return /* @__PURE__ */ jsxs("section", {
8283
+ ref: onRootRef,
8284
+ "aria-labelledby": headingId,
8285
+ className: "grid gap-4",
8286
+ children: [
8287
+ /* @__PURE__ */ jsx("h2", {
8288
+ id: headingId,
8289
+ tabIndex: -1,
8290
+ ref: onTargetRef,
8291
+ children: title
8292
+ }),
8293
+ /* @__PURE__ */ jsx("p", { children: description }),
8294
+ body,
8295
+ /* @__PURE__ */ jsx(Button, {
8296
+ variant: "secondary",
8297
+ onClick: close,
8298
+ children: closeLabel
8299
+ })
8300
+ ]
8301
+ });
8302
+ }
8098
8303
  return /* @__PURE__ */ jsx(Dialog, {
8099
8304
  open,
8100
8305
  onOpenChange: (next) => {
8101
- if (!next && !dismissed.current) {
8102
- dismissed.current = true;
8103
- setOpen(false);
8104
- onClose();
8105
- }
8306
+ if (!next) close();
8106
8307
  },
8107
8308
  children: /* @__PURE__ */ jsx(DialogContent, {
8108
- ref: popup,
8109
- initialFocus: popup,
8110
- finalFocus: returnFocus,
8309
+ ref: onPopupRef,
8310
+ initialFocus,
8311
+ finalFocus: () => dismissed.current ? props.returnFocus() : false,
8111
8312
  showClose: false,
8112
8313
  closeLabel,
8113
8314
  children: open && /* @__PURE__ */ jsxs(Fragment$1, { children: [
8114
- /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: labels.title ?? t("credentialDisclosure.title") }), /* @__PURE__ */ jsx(DialogDescription, { children: labels.description ?? t("credentialDisclosure.description") })] }),
8115
- /* @__PURE__ */ jsxs(DialogBody, {
8315
+ /* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: title }), /* @__PURE__ */ jsx(DialogDescription, { children: description })] }),
8316
+ /* @__PURE__ */ jsx(DialogBody, {
8116
8317
  className: "grid gap-4",
8117
- children: [/* @__PURE__ */ jsxs("dl", {
8118
- className: "grid grid-cols-2 gap-2 text-sm",
8119
- children: [
8120
- /* @__PURE__ */ jsx("dt", {
8121
- className: "text-muted-foreground",
8122
- children: labels.credentialIdLabel ?? t("credentialDisclosure.credentialId")
8123
- }),
8124
- /* @__PURE__ */ jsx("dd", {
8125
- className: "break-all font-mono",
8126
- children: disclosure.credentialId
8127
- }),
8128
- /* @__PURE__ */ jsx("dt", {
8129
- className: "text-muted-foreground",
8130
- children: labels.expiryLabel ?? t("credentialDisclosure.expiry")
8131
- }),
8132
- /* @__PURE__ */ jsx("dd", { children: disclosure.expiresAt })
8133
- ]
8134
- }), /* @__PURE__ */ jsxs(LiveAnnouncer, { children: [disclosure.variant === "stored" ? /* @__PURE__ */ jsx(SecretField, {
8135
- value: disclosure.secret,
8136
- copyable: false,
8137
- "aria-label": secretLabel,
8138
- showLabel: labels.showLabel ?? t("credentialDisclosure.show"),
8139
- hideLabel: labels.hideLabel ?? t("credentialDisclosure.hide")
8140
- }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Alert, {
8141
- role: "alert",
8142
- tone: "warning",
8143
- title: labels.warningTitle ?? t("credentialDisclosure.warningTitle"),
8144
- description: labels.warningText ?? t("credentialDisclosure.warningText")
8145
- }), /* @__PURE__ */ jsx(CodeBlock, {
8146
- code: disclosure.secret,
8147
- copyable: false,
8148
- label: secretLabel,
8149
- wrapToggle: false,
8150
- defaultWrap: true
8151
- })] }), /* @__PURE__ */ jsx(CopyButton, {
8152
- value: () => disclosure.secret,
8153
- display: "label",
8154
- label: labels.copyLabel ?? t("credentialDisclosure.copy"),
8155
- copiedLabel: labels.copiedLabel ?? t("credentialDisclosure.copied"),
8156
- announcement: labels.successAnnouncement ?? t("credentialDisclosure.success"),
8157
- failureLabel: labels.failureAnnouncement ?? t("credentialDisclosure.failure"),
8158
- failureAnnouncement: labels.failureAnnouncement ?? t("credentialDisclosure.failure"),
8159
- failurePoliteness: "polite"
8160
- })] })]
8318
+ children: body
8161
8319
  }),
8162
8320
  /* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(DialogClose, {
8163
8321
  render: /* @__PURE__ */ jsx(Button, { variant: "secondary" }),
@@ -8167,24 +8325,13 @@ function DisclosureSession({ disclosure, onClose, resolveReturnFocus, fallbackFo
8167
8325
  })
8168
8326
  });
8169
8327
  }
8170
- /** Programmatic focus permits negative tabIndex, but never hidden, inert or disabled targets. */
8171
- function usableFocusTarget(element) {
8172
- if (!(element instanceof HTMLElement) || !element.isConnected || element === document.body) return false;
8173
- if (element.matches(":disabled, [disabled], [aria-disabled=\"true\"], input[type=\"hidden\"]")) return false;
8174
- for (let ancestor = element; ancestor; ancestor = ancestor.parentElement) {
8175
- if (ancestor.hidden || ancestor.hasAttribute("inert") || ancestor.getAttribute("aria-disabled") === "true") return false;
8176
- const style = getComputedStyle(ancestor);
8177
- if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse" || style.contentVisibility === "hidden") return false;
8178
- }
8179
- return element.tabIndex >= 0 || element.hasAttribute("tabindex") || element.isContentEditable;
8180
- }
8181
8328
  //#endregion
8182
8329
  //#region src/forms/CredentialDisclosureDialog/block.meta.ts
8183
8330
  const meta$13 = {
8184
8331
  name: "Credential disclosure dialog",
8185
8332
  family: "forms",
8186
8333
  status: "beta",
8187
- description: "Controlled disclosure for an existing credential. Set disclosure ({variant: stored | fresh, credentialId, expiresAt: caller-formatted ReactNode, secret}) only after a successful response; null renders nothing while pending or on failure. Clear disclosure to null in onClose to drop the secret; a fresh secret requires a new successful response before showing it again. No pending/error state or internal secret retention. Stored values start masked; each null-to-value opening or changed credentialId/secret resets masking and copy feedback. Fresh values use a non-copyable CodeBlock with a kit CopyButton and a replacement warning. Optional English defaults through en/es i18n for title, description, credentialIdLabel, expiryLabel, secretLabel, showLabel, hideLabel, copyLabel, copiedLabel, successAnnouncement, failureAnnouncement, warningTitle, warningText and closeLabel. Copy results are announced politely, including manual-selection fallback. Popup initial focus and focus trapping use Base UI; at close, resolveReturnFocus() is validated for connection, visibility, enabled state and focusability, then fallbackFocus(), then the original opener. Synthetic fixtures only; the default Stored preview is masked and the Fresh preview starts closed.",
8334
+ description: "Controlled disclosure for an existing credential. Set disclosure ({variant: stored | fresh, credentialId, expiresAt: caller-formatted ReactNode, secret}) only after a successful response; null renders nothing while pending or on failure. Clear disclosure, additionalSecrets and secret-bearing revealContent in onClose to drop every secret; a fresh secret requires a new successful response before showing it again. No pending/error state or internal secret retention. Stored values start masked; each null-to-value opening or changed credentialId/secret resets masking and copy feedback. Fresh values use a non-copyable CodeBlock with a kit CopyButton and a replacement warning, or a masked SecretField when maskFresh is set at session start. Optional additionalSecrets ({id, label, value}) are always masked and use independent toggles and serialized copy actions; ids must be non-empty, unique and not secret, with the first duplicate winning. Multi-secret groups announce label plus copiedLabel, or copiedAnnouncementFor(label); onCopy(id) never receives a value. Every secret and the optional revealContent slot have data-kit-redact. The session key includes additional ids and values. presentation is dialog by default or inline, fixed until the next opening: inline is a named section, never traps focus or handles Escape, and its warning is a non-live note. Surviving focus stays; removing the focused slot or session control focuses the popup or inline heading. Focused inline unmounts return focus through the same resolvers. Dismissed retained props stay hidden; clear and re-set or change a session value to reopen. Optional English defaults through en/es i18n for title, description, credentialIdLabel, expiryLabel, secretLabel, showLabel, hideLabel, copyLabel, copiedLabel, successAnnouncement, failureAnnouncement, warningTitle, warningText and closeLabel. Copy results are announced politely, including manual-selection fallback. Popup initial focus and focus trapping use Base UI; at close, resolveReturnFocus() is validated for connection, visibility, enabled state and focusability, then fallbackFocus(), then the original opener. Synthetic fixtures only; the default Stored preview is masked and the Fresh preview starts closed.",
8188
8335
  uses: [
8189
8336
  "Dialog",
8190
8337
  "SecretField",
@@ -9927,6 +10074,7 @@ const pageHeaderTabs = [
9927
10074
  //#region src/page-chrome/PageHeader/PageHeader.tsx
9928
10075
  /** Screen header: breadcrumb, title + status, description, meta row, actions and optional tabs. */
9929
10076
  function PageHeader({ as: Root = "header", breadcrumbs = pageHeaderBreadcrumbs, title = "Deployments", titleRef, description = "Every build and release of this project across its environments.", status = "active", statuses, meta = pageHeaderMeta, actions = pageHeaderActions, tabs = pageHeaderTabs, tab, defaultTab, onTabChange, className }) {
10077
+ const { t } = useI18n();
9930
10078
  const explicitPrimary = actions.findIndex((a) => a.variant === "primary");
9931
10079
  const primaryIndex = explicitPrimary >= 0 ? explicitPrimary : actions.length - 1;
9932
10080
  const primary = actions[primaryIndex];
@@ -10005,7 +10153,7 @@ function PageHeader({ as: Root = "header", breadcrumbs = pageHeaderBreadcrumbs,
10005
10153
  onValueChange: (value) => onTabChange?.(String(value)),
10006
10154
  className: "mt-5",
10007
10155
  children: /* @__PURE__ */ jsx(TabsList, {
10008
- "aria-label": "Page sections",
10156
+ "aria-label": t("pageHeader.sections"),
10009
10157
  className: "overflow-x-auto",
10010
10158
  children: tabs.map((t) => /* @__PURE__ */ jsx(TabsTab, {
10011
10159
  value: t.value,
@@ -10023,7 +10171,7 @@ const meta$45 = {
10023
10171
  name: "Page header",
10024
10172
  family: "page-chrome",
10025
10173
  status: "beta",
10026
- description: "Screen header with breadcrumb, title and status, description, meta row, actions that fold into a MoreMenu on small screens, and optional navigation tabs. titleRef targets the h1 for titleRef.current.focus(), adding tabIndex=-1 only when supplied so the title stays outside the Tab order. In a StatusLayout heading slot use as=\"div\" and disable breadcrumb, meta, tabs, actions, status and description fixtures; the slot supplies the page’s only h1.",
10174
+ description: "Screen header with breadcrumb, title and status, description, meta row, actions that fold into a MoreMenu on small screens, and optional navigation tabs. titleRef targets the h1 for titleRef.current.focus(), adding tabIndex=-1 only when supplied so the title stays outside the Tab order. In a StatusLayout heading slot use as=\"div\" and disable breadcrumb, meta, tabs, actions, status and description fixtures; the slot supplies the page’s only h1. The tablist name follows I18nProvider (en/es); the Spanish preview keeps caller content unchanged.",
10027
10175
  uses: [
10028
10176
  "Breadcrumbs",
10029
10177
  "Button",
@@ -12275,11 +12423,23 @@ function toggleOne(id, selected) {
12275
12423
  else next.add(id);
12276
12424
  return next;
12277
12425
  }
12278
- /** Default cell text for a raw value. */
12279
- function formatCell(value) {
12426
+ /** Default cell text for a raw value. Omitting options preserves the legacy output. */
12427
+ function formatCell(value, options) {
12280
12428
  if (value == null) return "—";
12281
- if (value instanceof Date) return value.toLocaleDateString();
12282
- if (typeof value === "boolean") return value ? "Yes" : "No";
12429
+ if (value instanceof Date) {
12430
+ if (!options) return value.toLocaleDateString();
12431
+ if (Number.isNaN(value.getTime())) return "—";
12432
+ return new Intl.DateTimeFormat(options.locale, {
12433
+ year: "numeric",
12434
+ month: "numeric",
12435
+ day: "numeric"
12436
+ }).format(value);
12437
+ }
12438
+ if (typeof value === "boolean") return (options?.booleanLabels ?? ["Yes", "No"])[value ? 0 : 1];
12439
+ if (typeof value === "number" && Number.isFinite(value) && options?.locale !== void 0) {
12440
+ const decimal = new Intl.NumberFormat(options.locale).formatToParts(1.1).find((part) => part.type === "decimal");
12441
+ return String(value).replace(".", decimal?.value ?? ".");
12442
+ }
12283
12443
  return value;
12284
12444
  }
12285
12445
  /** Group key of a row (`''` when the value is null or undefined). */
@@ -12522,6 +12682,7 @@ function isCellEditable(column, row) {
12522
12682
  //#region src/tables/DataTable/data-table-row.tsx
12523
12683
  function DataTableRow({ labels, row, columns, getRowId, getRowLabel, selectable, selected, singleSelection, onToggleRow, rowActions, layout, onCellEdit, editHintId, ariaRowIndex, style }) {
12524
12684
  const { t } = useI18n();
12685
+ const locale = useOptionalI18n()?.locale;
12525
12686
  const id = getRowId(row);
12526
12687
  const selectionColumn = selectable || singleSelection != null;
12527
12688
  const isSelected = singleSelection ? singleSelection.selectedId === id : selected.has(id);
@@ -12551,7 +12712,10 @@ function DataTableRow({ labels, row, columns, getRowId, getRowLabel, selectable,
12551
12712
  }),
12552
12713
  columns.map((c) => {
12553
12714
  const cl = layout?.columns.get(c.id);
12554
- const content = c.cell ? c.cell(row) : formatCell(c.accessor?.(row));
12715
+ const content = c.cell ? c.cell(row) : formatCell(c.accessor?.(row), {
12716
+ locale,
12717
+ booleanLabels: [labels?.booleanTrue ?? t("common.yes"), labels?.booleanFalse ?? t("common.no")]
12718
+ });
12555
12719
  const editable = onCellEdit && editHintId && isCellEditable(c, row);
12556
12720
  return /* @__PURE__ */ jsx(TableCell, {
12557
12721
  align: columnAlign(c),
@@ -13777,6 +13941,16 @@ const meta$16 = {
13777
13941
  status: "beta",
13778
13942
  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
13943
  labels: [
13944
+ {
13945
+ key: "booleanTrue",
13946
+ type: "string",
13947
+ state: "Default cell text for a true boolean value"
13948
+ },
13949
+ {
13950
+ key: "booleanFalse",
13951
+ type: "string",
13952
+ state: "Default cell text for a false boolean value"
13953
+ },
13780
13954
  {
13781
13955
  key: "scrollRegion",
13782
13956
  type: "string",