@gntik-ai/blocks 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +25 -5
- package/dist/index.js +228 -83
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/forms/CredentialDisclosureDialog/CredentialDisclosureDialog.additional.test.tsx +467 -0
- package/src/forms/CredentialDisclosureDialog/CredentialDisclosureDialog.tsx +175 -106
- package/src/forms/CredentialDisclosureDialog/IssueOnClick.test.tsx +56 -0
- package/src/forms/CredentialDisclosureDialog/SecretCopy.tsx +83 -0
- package/src/forms/CredentialDisclosureDialog/block.meta.ts +1 -1
- package/src/forms/CredentialDisclosureDialog/examples/Inline.tsx +19 -0
- package/src/forms/CredentialDisclosureDialog/examples/IssueOnClick.tsx +87 -0
- package/src/forms/CredentialDisclosureDialog/examples/MultiSecret.tsx +29 -0
- package/src/forms/CredentialDisclosureDialog/focus.ts +18 -0
- package/src/forms/CredentialDisclosureDialog/types.ts +5 -0
- 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
|
|
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
|
-
*
|
|
1852
|
-
*
|
|
1853
|
-
*
|
|
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
|
|
@@ -3730,5 +3750,5 @@ export declare function SessionsDevices({ sessions, onRevoke, onRevokeOthers, ti
|
|
|
3730
3750
|
//#region src/team/SessionsDevices/block.meta.d.ts
|
|
3731
3751
|
declare const meta$60: BlockMeta;
|
|
3732
3752
|
//#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 };
|
|
3753
|
+
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
3754
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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
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";
|
|
@@ -8056,11 +8056,78 @@ const meta$12 = {
|
|
|
8056
8056
|
]
|
|
8057
8057
|
};
|
|
8058
8058
|
//#endregion
|
|
8059
|
+
//#region src/forms/CredentialDisclosureDialog/SecretCopy.tsx
|
|
8060
|
+
/** Each secret owns feedback so simultaneous settlements cannot overwrite each other. */
|
|
8061
|
+
function SecretCopy({ secret, options, grouped = false, masked = true, warning }) {
|
|
8062
|
+
const { t } = useI18n();
|
|
8063
|
+
const [pending, setPending] = useState(false);
|
|
8064
|
+
const copied = options.copiedLabel ?? t("credentialDisclosure.copied");
|
|
8065
|
+
const content = /* @__PURE__ */ jsxs(LiveAnnouncer, { children: [
|
|
8066
|
+
warning,
|
|
8067
|
+
/* @__PURE__ */ jsx("div", {
|
|
8068
|
+
"data-kit-redact": true,
|
|
8069
|
+
children: masked ? /* @__PURE__ */ jsx(SecretField, {
|
|
8070
|
+
value: secret.value,
|
|
8071
|
+
copyable: false,
|
|
8072
|
+
"aria-label": secret.label,
|
|
8073
|
+
showLabel: options.showLabel ?? t("credentialDisclosure.show"),
|
|
8074
|
+
hideLabel: options.hideLabel ?? t("credentialDisclosure.hide")
|
|
8075
|
+
}) : /* @__PURE__ */ jsx(CodeBlock, {
|
|
8076
|
+
code: secret.value,
|
|
8077
|
+
copyable: false,
|
|
8078
|
+
label: secret.label,
|
|
8079
|
+
wrapToggle: false,
|
|
8080
|
+
defaultWrap: true
|
|
8081
|
+
})
|
|
8082
|
+
}),
|
|
8083
|
+
/* @__PURE__ */ jsx(CopyButton, {
|
|
8084
|
+
value: () => {
|
|
8085
|
+
if (grouped) setPending(true);
|
|
8086
|
+
return secret.value;
|
|
8087
|
+
},
|
|
8088
|
+
loading: grouped && pending,
|
|
8089
|
+
display: "label",
|
|
8090
|
+
label: options.copyLabel ?? t("credentialDisclosure.copy"),
|
|
8091
|
+
copiedLabel: copied,
|
|
8092
|
+
announcement: grouped ? options.copiedAnnouncementFor?.(secret.label) ?? `${secret.label}: ${copied}` : options.successAnnouncement ?? t("credentialDisclosure.success"),
|
|
8093
|
+
failureLabel: options.failureAnnouncement ?? t("credentialDisclosure.failure"),
|
|
8094
|
+
failureAnnouncement: options.failureAnnouncement ?? t("credentialDisclosure.failure"),
|
|
8095
|
+
failurePoliteness: "polite",
|
|
8096
|
+
onCopy: () => {
|
|
8097
|
+
if (grouped) setPending(false);
|
|
8098
|
+
options.onCopy?.(secret.id);
|
|
8099
|
+
},
|
|
8100
|
+
onCopyError: () => {
|
|
8101
|
+
if (grouped) setPending(false);
|
|
8102
|
+
}
|
|
8103
|
+
})
|
|
8104
|
+
] });
|
|
8105
|
+
return grouped ? /* @__PURE__ */ jsx("div", {
|
|
8106
|
+
role: "group",
|
|
8107
|
+
"aria-label": secret.label,
|
|
8108
|
+
children: content
|
|
8109
|
+
}) : content;
|
|
8110
|
+
}
|
|
8111
|
+
//#endregion
|
|
8112
|
+
//#region src/forms/CredentialDisclosureDialog/focus.ts
|
|
8113
|
+
/** Programmatic focus permits negative tabIndex, but never hidden, inert or disabled targets. */
|
|
8114
|
+
function usableFocusTarget(element) {
|
|
8115
|
+
if (!(element instanceof HTMLElement) || !element.isConnected || element === document.body) return false;
|
|
8116
|
+
if (element.matches(":disabled, [disabled], [aria-disabled=\"true\"], input[type=\"hidden\"]")) return false;
|
|
8117
|
+
for (let ancestor = element; ancestor; ancestor = ancestor.parentElement) {
|
|
8118
|
+
if (ancestor.hidden || ancestor.hasAttribute("inert") || ancestor.getAttribute("aria-disabled") === "true") return false;
|
|
8119
|
+
const style = getComputedStyle(ancestor);
|
|
8120
|
+
if (style.display === "none" || style.visibility === "hidden" || style.visibility === "collapse" || style.contentVisibility === "hidden") return false;
|
|
8121
|
+
}
|
|
8122
|
+
return element.tabIndex >= 0 || element.hasAttribute("tabindex") || element.isContentEditable;
|
|
8123
|
+
}
|
|
8124
|
+
//#endregion
|
|
8059
8125
|
//#region src/forms/CredentialDisclosureDialog/CredentialDisclosureDialog.tsx
|
|
8060
8126
|
/**
|
|
8061
|
-
*
|
|
8062
|
-
*
|
|
8063
|
-
*
|
|
8127
|
+
* Render only successful responses. Keep disclosure null while pending or on failure.
|
|
8128
|
+
* On close, clear disclosure, additionalSecrets and any secret-bearing revealContent.
|
|
8129
|
+
* No pending/error state or internal secret retention. Retained dismissed sessions stay closed;
|
|
8130
|
+
* a changed credential/value or a null-to-value opening starts a new session.
|
|
8064
8131
|
*/
|
|
8065
8132
|
function CredentialDisclosureDialog(props) {
|
|
8066
8133
|
if (!props.disclosure) return null;
|
|
@@ -8071,93 +8138,182 @@ function CredentialDisclosureDialog(props) {
|
|
|
8071
8138
|
}
|
|
8072
8139
|
function DisclosureOpening(props) {
|
|
8073
8140
|
const [opener] = useState(() => typeof document === "undefined" ? null : document.activeElement);
|
|
8141
|
+
const [presentation] = useState(props.presentation ?? "dialog");
|
|
8142
|
+
const root = useRef(null);
|
|
8143
|
+
const target = useRef(null);
|
|
8144
|
+
const active = useRef(opener);
|
|
8145
|
+
const started = useRef(false);
|
|
8146
|
+
const activeWasInside = useRef(false);
|
|
8147
|
+
const returnFocus = () => {
|
|
8148
|
+
const current = props.resolveReturnFocus?.();
|
|
8149
|
+
if (usableFocusTarget(current)) return current;
|
|
8150
|
+
const fallback = props.fallbackFocus?.();
|
|
8151
|
+
if (usableFocusTarget(fallback)) return fallback;
|
|
8152
|
+
return usableFocusTarget(opener) ? opener : false;
|
|
8153
|
+
};
|
|
8154
|
+
const restore = useEffectEvent(() => {
|
|
8155
|
+
if (root.current?.contains(document.activeElement)) {
|
|
8156
|
+
const element = returnFocus();
|
|
8157
|
+
if (element) element.focus();
|
|
8158
|
+
}
|
|
8159
|
+
});
|
|
8160
|
+
useLayoutEffect(() => {
|
|
8161
|
+
const track = () => {
|
|
8162
|
+
if (document.activeElement !== document.body) {
|
|
8163
|
+
active.current = document.activeElement;
|
|
8164
|
+
activeWasInside.current = root.current?.contains(document.activeElement) ?? false;
|
|
8165
|
+
}
|
|
8166
|
+
};
|
|
8167
|
+
document.addEventListener("focusin", track);
|
|
8168
|
+
return () => {
|
|
8169
|
+
document.removeEventListener("focusin", track);
|
|
8170
|
+
restore();
|
|
8171
|
+
};
|
|
8172
|
+
}, [presentation]);
|
|
8173
|
+
useLayoutEffect(() => {
|
|
8174
|
+
if (activeWasInside.current && active.current && !active.current.isConnected) target.current?.focus();
|
|
8175
|
+
});
|
|
8176
|
+
const seen = /* @__PURE__ */ new Set(["secret", ""]);
|
|
8177
|
+
const additionalSecrets = (props.additionalSecrets ?? []).filter(({ id }) => {
|
|
8178
|
+
if (seen.has(id)) return false;
|
|
8179
|
+
seen.add(id);
|
|
8180
|
+
return true;
|
|
8181
|
+
});
|
|
8074
8182
|
const { variant, credentialId, secret } = props.disclosure;
|
|
8075
8183
|
return /* @__PURE__ */ jsx(DisclosureSession, {
|
|
8076
8184
|
...props,
|
|
8077
|
-
|
|
8185
|
+
presentation,
|
|
8186
|
+
additionalSecrets,
|
|
8187
|
+
onRootRef: (node) => {
|
|
8188
|
+
root.current = node;
|
|
8189
|
+
},
|
|
8190
|
+
onTargetRef: (node) => {
|
|
8191
|
+
target.current = node;
|
|
8192
|
+
},
|
|
8193
|
+
onPopupRef: (node) => {
|
|
8194
|
+
root.current = node;
|
|
8195
|
+
target.current = node;
|
|
8196
|
+
},
|
|
8197
|
+
containsFocus: () => root.current?.contains(document.activeElement) ?? false,
|
|
8198
|
+
initialFocus: () => {
|
|
8199
|
+
const shouldFocus = !started.current || activeWasInside.current && !active.current?.isConnected;
|
|
8200
|
+
started.current = true;
|
|
8201
|
+
return shouldFocus ? root.current : false;
|
|
8202
|
+
},
|
|
8203
|
+
returnFocus
|
|
8078
8204
|
}, JSON.stringify([
|
|
8079
8205
|
variant,
|
|
8080
8206
|
credentialId,
|
|
8081
|
-
secret
|
|
8207
|
+
secret,
|
|
8208
|
+
...additionalSecrets.map(({ id, value }) => [id, value])
|
|
8082
8209
|
]));
|
|
8083
8210
|
}
|
|
8084
|
-
function DisclosureSession(
|
|
8211
|
+
function DisclosureSession(props) {
|
|
8085
8212
|
const { t } = useI18n();
|
|
8213
|
+
const { disclosure, onRootRef, onTargetRef, onPopupRef, initialFocus, containsFocus, presentation, additionalSecrets = [] } = props;
|
|
8086
8214
|
const [open, setOpen] = useState(true);
|
|
8087
|
-
const
|
|
8215
|
+
const [maskFresh] = useState(props.maskFresh ?? false);
|
|
8088
8216
|
const dismissed = useRef(false);
|
|
8089
|
-
const
|
|
8090
|
-
|
|
8091
|
-
if (
|
|
8092
|
-
|
|
8093
|
-
if (
|
|
8094
|
-
|
|
8095
|
-
|
|
8096
|
-
|
|
8097
|
-
|
|
8217
|
+
const headingId = useId();
|
|
8218
|
+
const close = () => {
|
|
8219
|
+
if (dismissed.current) return;
|
|
8220
|
+
dismissed.current = true;
|
|
8221
|
+
if (presentation === "inline" && containsFocus()) {
|
|
8222
|
+
const element = props.returnFocus();
|
|
8223
|
+
if (element) element.focus();
|
|
8224
|
+
}
|
|
8225
|
+
setOpen(false);
|
|
8226
|
+
props.onClose();
|
|
8227
|
+
};
|
|
8228
|
+
const closeLabel = props.closeLabel ?? t("credentialDisclosure.close");
|
|
8229
|
+
const title = props.title ?? t("credentialDisclosure.title");
|
|
8230
|
+
const description = props.description ?? t("credentialDisclosure.description");
|
|
8231
|
+
const secretLabel = props.secretLabel ?? t("credentialDisclosure.secret");
|
|
8232
|
+
const warning = disclosure.variant === "fresh" ? /* @__PURE__ */ jsx(Alert, {
|
|
8233
|
+
role: presentation === "inline" ? "note" : "alert",
|
|
8234
|
+
tone: "warning",
|
|
8235
|
+
title: props.warningTitle ?? t("credentialDisclosure.warningTitle"),
|
|
8236
|
+
description: props.warningText ?? t("credentialDisclosure.warningText")
|
|
8237
|
+
}) : null;
|
|
8238
|
+
const body = /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
8239
|
+
/* @__PURE__ */ jsxs("dl", {
|
|
8240
|
+
className: "grid grid-cols-2 gap-2 text-sm",
|
|
8241
|
+
children: [
|
|
8242
|
+
/* @__PURE__ */ jsx("dt", {
|
|
8243
|
+
className: "text-muted-foreground",
|
|
8244
|
+
children: props.credentialIdLabel ?? t("credentialDisclosure.credentialId")
|
|
8245
|
+
}),
|
|
8246
|
+
/* @__PURE__ */ jsx("dd", {
|
|
8247
|
+
className: "break-all font-mono",
|
|
8248
|
+
children: disclosure.credentialId
|
|
8249
|
+
}),
|
|
8250
|
+
/* @__PURE__ */ jsx("dt", {
|
|
8251
|
+
className: "text-muted-foreground",
|
|
8252
|
+
children: props.expiryLabel ?? t("credentialDisclosure.expiry")
|
|
8253
|
+
}),
|
|
8254
|
+
/* @__PURE__ */ jsx("dd", { children: disclosure.expiresAt })
|
|
8255
|
+
]
|
|
8256
|
+
}),
|
|
8257
|
+
/* @__PURE__ */ jsx(SecretCopy, {
|
|
8258
|
+
secret: {
|
|
8259
|
+
id: "secret",
|
|
8260
|
+
label: secretLabel,
|
|
8261
|
+
value: disclosure.secret
|
|
8262
|
+
},
|
|
8263
|
+
options: props,
|
|
8264
|
+
grouped: additionalSecrets.length > 0,
|
|
8265
|
+
masked: disclosure.variant === "stored" || maskFresh,
|
|
8266
|
+
warning
|
|
8267
|
+
}),
|
|
8268
|
+
additionalSecrets.map((secret) => /* @__PURE__ */ jsx(SecretCopy, {
|
|
8269
|
+
secret,
|
|
8270
|
+
options: props,
|
|
8271
|
+
grouped: true
|
|
8272
|
+
}, secret.id)),
|
|
8273
|
+
props.revealContent != null && /* @__PURE__ */ jsx("div", {
|
|
8274
|
+
"data-kit-redact": true,
|
|
8275
|
+
children: props.revealContent
|
|
8276
|
+
})
|
|
8277
|
+
] });
|
|
8278
|
+
if (presentation === "inline") {
|
|
8279
|
+
if (!open) return null;
|
|
8280
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
8281
|
+
ref: onRootRef,
|
|
8282
|
+
"aria-labelledby": headingId,
|
|
8283
|
+
className: "grid gap-4",
|
|
8284
|
+
children: [
|
|
8285
|
+
/* @__PURE__ */ jsx("h2", {
|
|
8286
|
+
id: headingId,
|
|
8287
|
+
tabIndex: -1,
|
|
8288
|
+
ref: onTargetRef,
|
|
8289
|
+
children: title
|
|
8290
|
+
}),
|
|
8291
|
+
/* @__PURE__ */ jsx("p", { children: description }),
|
|
8292
|
+
body,
|
|
8293
|
+
/* @__PURE__ */ jsx(Button, {
|
|
8294
|
+
variant: "secondary",
|
|
8295
|
+
onClick: close,
|
|
8296
|
+
children: closeLabel
|
|
8297
|
+
})
|
|
8298
|
+
]
|
|
8299
|
+
});
|
|
8300
|
+
}
|
|
8098
8301
|
return /* @__PURE__ */ jsx(Dialog, {
|
|
8099
8302
|
open,
|
|
8100
8303
|
onOpenChange: (next) => {
|
|
8101
|
-
if (!next
|
|
8102
|
-
dismissed.current = true;
|
|
8103
|
-
setOpen(false);
|
|
8104
|
-
onClose();
|
|
8105
|
-
}
|
|
8304
|
+
if (!next) close();
|
|
8106
8305
|
},
|
|
8107
8306
|
children: /* @__PURE__ */ jsx(DialogContent, {
|
|
8108
|
-
ref:
|
|
8109
|
-
initialFocus
|
|
8110
|
-
finalFocus: returnFocus,
|
|
8307
|
+
ref: onPopupRef,
|
|
8308
|
+
initialFocus,
|
|
8309
|
+
finalFocus: () => dismissed.current ? props.returnFocus() : false,
|
|
8111
8310
|
showClose: false,
|
|
8112
8311
|
closeLabel,
|
|
8113
8312
|
children: open && /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
8114
|
-
/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children:
|
|
8115
|
-
/* @__PURE__ */
|
|
8313
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: title }), /* @__PURE__ */ jsx(DialogDescription, { children: description })] }),
|
|
8314
|
+
/* @__PURE__ */ jsx(DialogBody, {
|
|
8116
8315
|
className: "grid gap-4",
|
|
8117
|
-
children:
|
|
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
|
-
})] })]
|
|
8316
|
+
children: body
|
|
8161
8317
|
}),
|
|
8162
8318
|
/* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsx(DialogClose, {
|
|
8163
8319
|
render: /* @__PURE__ */ jsx(Button, { variant: "secondary" }),
|
|
@@ -8167,24 +8323,13 @@ function DisclosureSession({ disclosure, onClose, resolveReturnFocus, fallbackFo
|
|
|
8167
8323
|
})
|
|
8168
8324
|
});
|
|
8169
8325
|
}
|
|
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
8326
|
//#endregion
|
|
8182
8327
|
//#region src/forms/CredentialDisclosureDialog/block.meta.ts
|
|
8183
8328
|
const meta$13 = {
|
|
8184
8329
|
name: "Credential disclosure dialog",
|
|
8185
8330
|
family: "forms",
|
|
8186
8331
|
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
|
|
8332
|
+
description: "Controlled disclosure for an existing credential. Set disclosure ({variant: stored | fresh, credentialId, expiresAt: caller-formatted ReactNode, secret}) only after a successful response; null renders nothing while pending or on failure. Clear disclosure, additionalSecrets and secret-bearing revealContent in onClose to drop every secret; a fresh secret requires a new successful response before showing it again. No pending/error state or internal secret retention. Stored values start masked; each null-to-value opening or changed credentialId/secret resets masking and copy feedback. Fresh values use a non-copyable CodeBlock with a kit CopyButton and a replacement warning, or a masked SecretField when maskFresh is set at session start. Optional additionalSecrets ({id, label, value}) are always masked and use independent toggles and serialized copy actions; ids must be non-empty, unique and not secret, with the first duplicate winning. Multi-secret groups announce label plus copiedLabel, or copiedAnnouncementFor(label); onCopy(id) never receives a value. Every secret and the optional revealContent slot have data-kit-redact. The session key includes additional ids and values. presentation is dialog by default or inline, fixed until the next opening: inline is a named section, never traps focus or handles Escape, and its warning is a non-live note. Surviving focus stays; removing the focused slot or session control focuses the popup or inline heading. Focused inline unmounts return focus through the same resolvers. Dismissed retained props stay hidden; clear and re-set or change a session value to reopen. Optional English defaults through en/es i18n for title, description, credentialIdLabel, expiryLabel, secretLabel, showLabel, hideLabel, copyLabel, copiedLabel, successAnnouncement, failureAnnouncement, warningTitle, warningText and closeLabel. Copy results are announced politely, including manual-selection fallback. Popup initial focus and focus trapping use Base UI; at close, resolveReturnFocus() is validated for connection, visibility, enabled state and focusability, then fallbackFocus(), then the original opener. Synthetic fixtures only; the default Stored preview is masked and the Fresh preview starts closed.",
|
|
8188
8333
|
uses: [
|
|
8189
8334
|
"Dialog",
|
|
8190
8335
|
"SecretField",
|