@godxjp/ui 31.31.8 → 32.0.1
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/README.md +102 -121
- package/agent/START-HERE.md +10 -10
- package/agent/components/Accordion.json +2 -2
- package/agent/components/AccountChip.json +1 -1
- package/agent/components/Actions.json +1 -1
- package/agent/components/Activity.json +2 -2
- package/agent/components/Affix.json +1 -1
- package/agent/components/Alert.json +22 -6
- package/agent/components/AlertDialog.json +8 -1
- package/agent/components/Anchor.json +4 -3
- package/agent/components/AppLauncher.json +2 -2
- package/agent/components/AppProvider.json +19 -11
- package/agent/components/AppSettingPicker.json +18 -2
- package/agent/components/AppShell.json +4 -5
- package/agent/components/AreaChart.json +0 -1
- package/agent/components/AspectRatio.json +2 -2
- package/agent/components/Attachments.json +3 -3
- package/agent/components/AuthAccountSummary.json +1 -1
- package/agent/components/AuthDivider.json +1 -1
- package/agent/components/AuthExpiryProvider.json +0 -1
- package/agent/components/AuthFooter.json +2 -2
- package/agent/components/AuthIdentity.json +3 -3
- package/agent/components/AuthStack.json +1 -1
- package/agent/components/Avatar.json +2 -12
- package/agent/components/Badge.json +1 -1
- package/agent/components/BarChart.json +0 -1
- package/agent/components/BranchScopePicker.json +1 -1
- package/agent/components/Breadcrumb.json +1 -1
- package/agent/components/Button.json +3 -3
- package/agent/components/Calendar.json +1 -1
- package/agent/components/Card.json +2 -2
- package/agent/components/CardBar.json +0 -1
- package/agent/components/CardContent.json +0 -1
- package/agent/components/Carousel.json +4 -3
- package/agent/components/Cascader.json +1 -1
- package/agent/components/CenteredShell.json +78 -17
- package/agent/components/ChatBubble.json +3 -3
- package/agent/components/ChatBubbleList.json +3 -3
- package/agent/components/ChatComposer.json +3 -3
- package/agent/components/ChatSuggestion.json +3 -3
- package/agent/components/Checkbox.json +1 -1
- package/agent/components/CheckboxGroup.json +0 -1
- package/agent/components/CodeBlock.json +1 -1
- package/agent/components/Collapsible.json +4 -4
- package/agent/components/ColorPicker.json +1 -1
- package/agent/components/Command.json +5 -5
- package/agent/components/CommandPalette.json +1 -1
- package/agent/components/CompactBarTrend.json +1 -1
- package/agent/components/Conversations.json +3 -3
- package/agent/components/CredentialReveal.json +1 -1
- package/agent/components/DataState.json +2 -2
- package/agent/components/DataTable.json +1 -1
- package/agent/components/DatePicker.json +1 -1
- package/agent/components/Descriptions.json +1 -1
- package/agent/components/Dialog.json +2 -2
- package/agent/components/DraggablePanel.json +5 -4
- package/agent/components/DropdownMenu.json +1 -1
- package/agent/components/EmojiPicker.json +3 -2
- package/agent/components/EmptyState.json +1 -1
- package/agent/components/ErrorSurface.json +3 -3
- package/agent/components/FeatureList.json +1 -1
- package/agent/components/Field.json +0 -1
- package/agent/components/Flex.json +34 -4
- package/agent/components/FloatButton.json +6 -5
- package/agent/components/Form.json +1 -1
- package/agent/components/FormErrors.json +0 -1
- package/agent/components/FormField.json +6 -6
- package/agent/components/FormFieldArray.json +0 -1
- package/agent/components/FormFieldControl.json +0 -1
- package/agent/components/FormRoot.json +1 -1
- package/agent/components/Heading.json +3 -0
- package/agent/components/Icon.json +1 -1
- package/agent/components/Image.json +7 -4
- package/agent/components/InfiniteQueryState.json +1 -1
- package/agent/components/Input.json +1 -1
- package/agent/components/InputOTP.json +2 -2
- package/agent/components/Label.json +3 -3
- package/agent/components/LegalDocumentShell.json +5 -4
- package/agent/components/Legend.json +1 -1
- package/agent/components/LineChart.json +0 -1
- package/agent/components/Link.json +0 -1
- package/agent/components/ListRow.json +1 -1
- package/agent/components/Logo.json +5 -4
- package/agent/components/Marquee.json +4 -3
- package/agent/components/Masonry.json +4 -3
- package/agent/components/MasterDetail.json +1 -1
- package/agent/components/MegaMenu.json +4 -3
- package/agent/components/MobileShell.json +4 -4
- package/agent/components/NavList.json +1 -1
- package/agent/components/NumberInput.json +1 -1
- package/agent/components/OrgChart.json +4 -3
- package/agent/components/OrgSwitcher.json +1 -1
- package/agent/components/OverlayPortalProvider.json +0 -1
- package/agent/components/PageContainer.json +3 -3
- package/agent/components/PageCover.json +3 -2
- package/agent/components/Pagination.json +1 -1
- package/agent/components/PasswordInput.json +1 -1
- package/agent/components/PasswordStrength.json +1 -1
- package/agent/components/PermissionMatrix.json +1 -1
- package/agent/components/PieChart.json +0 -1
- package/agent/components/Popover.json +31 -6
- package/agent/components/PrefetchLink.json +1 -1
- package/agent/components/Progress.json +1 -1
- package/agent/components/Prose.json +1 -1
- package/agent/components/QrCode.json +1 -1
- package/agent/components/Radio.json +0 -1
- package/agent/components/RadioGroup.json +2 -2
- package/agent/components/RangeTimeline.json +2 -1
- package/agent/components/Rating.json +1 -1
- package/agent/components/RecordPicker.json +1 -1
- package/agent/components/ResizablePanel.json +1 -1
- package/agent/components/ResponsiveGrid.json +2 -2
- package/agent/components/Reveal.json +3 -3
- package/agent/components/ScrollArea.json +2 -2
- package/agent/components/SearchInput.json +1 -1
- package/agent/components/Segmented.json +1 -1
- package/agent/components/Select.json +7 -5
- package/agent/components/Separator.json +1 -1
- package/agent/components/ServiceCatalogCta.json +0 -1
- package/agent/components/ServiceLauncherCard.json +1 -1
- package/agent/components/ServiceRolePanel.json +1 -1
- package/agent/components/Sheet.json +5 -5
- package/agent/components/Sidebar.json +1 -1
- package/agent/components/Skeleton.json +26 -12
- package/agent/components/Slider.json +2 -2
- package/agent/components/SortableList.json +3 -2
- package/agent/components/SplitPane.json +1 -1
- package/agent/components/StatCard.json +1 -1
- package/agent/components/Steps.json +1 -1
- package/agent/components/Swatch.json +1 -1
- package/agent/components/Switch.json +1 -1
- package/agent/components/Table.json +1 -1
- package/agent/components/Tabs.json +3 -3
- package/agent/components/Text.json +5 -1
- package/agent/components/TextDiff.json +5 -4
- package/agent/components/Textarea.json +1 -1
- package/agent/components/ThemeScope.json +1 -1
- package/agent/components/ThoughtChain.json +3 -3
- package/agent/components/TimePicker.json +1 -1
- package/agent/components/Timeline.json +1 -1
- package/agent/components/TimelineGrid.json +5 -4
- package/agent/components/Toaster.json +0 -1
- package/agent/components/Toggle.json +3 -3
- package/agent/components/ToggleGroup.json +1 -1
- package/agent/components/Toolbar.json +10 -3
- package/agent/components/Tooltip.json +9 -9
- package/agent/components/Topbar.json +1 -1
- package/agent/components/TopbarItem.json +1 -1
- package/agent/components/Transfer.json +2 -2
- package/agent/components/Tree.json +1 -1
- package/agent/components/TreeSelect.json +1 -1
- package/agent/components/TwoFactorSetup.json +1 -1
- package/agent/components/Upload.json +1 -1
- package/agent/components/UploadCropDialog.json +1 -1
- package/agent/components/Welcome.json +3 -3
- package/agent/components/formatDate.json +2 -2
- package/agent/components/inertiaUpload.json +0 -1
- package/agent/components/useZodForm.json +0 -1
- package/agent/components-index.json +80 -154
- package/agent/components.json +541 -1737
- package/agent/index.json +10 -10
- package/agent/llms.txt +9 -9
- package/agent/patterns/account-recovery-settings.json +1 -1
- package/agent/patterns/auth-recovery-panels.json +2 -2
- package/agent/patterns/error-pages.json +1 -1
- package/agent/patterns/pricing-plans.json +17 -0
- package/agent/patterns-index.json +17 -1
- package/agent/patterns.json +21 -4
- package/agent/rules.json +30 -65
- package/agent/tokens.json +27 -57
- package/agent/vocabulary.json +3 -3
- package/dist/app/app-provider.d.ts +5 -3
- package/dist/app/app-provider.js +47 -12
- package/dist/app/date-format-labels.d.ts +3 -1
- package/dist/app/date-format-labels.js +2 -4
- package/dist/app/date-formats.d.ts +21 -2
- package/dist/app/date-formats.js +51 -2
- package/dist/app/index.d.ts +3 -1
- package/dist/app/index.js +5 -0
- package/dist/app/locales.d.ts +58 -3
- package/dist/app/locales.js +134 -8
- package/dist/app/preset.d.ts +25 -0
- package/dist/app/preset.js +10 -0
- package/dist/app/request-headers.d.ts +3 -3
- package/dist/app/request-headers.js +19 -10
- package/dist/app/settings-scope.d.ts +54 -0
- package/dist/app/settings-scope.js +46 -0
- package/dist/app/tenant-theme.js +8 -3
- package/dist/app/time-format-labels.d.ts +4 -1
- package/dist/app/time-format-labels.js +7 -1
- package/dist/app/types.d.ts +10 -2
- package/dist/app/use-formatting.d.ts +1 -1
- package/dist/components/admin/index.d.ts +1 -1
- package/dist/components/admin/index.js +1 -1
- package/dist/components/data-display/accordion.d.ts +51 -1
- package/dist/components/data-display/accordion.js +247 -1
- package/dist/components/data-display/avatar.d.ts +16 -1
- package/dist/components/data-display/avatar.js +109 -1
- package/dist/components/data-display/credential-reveal.d.ts +9 -2
- package/dist/components/data-display/credential-reveal.js +156 -1
- package/dist/components/data-display/image.js +5 -3
- package/dist/components/data-display/index.d.ts +0 -21
- package/dist/components/data-display/index.js +1 -43
- package/dist/components/data-display/popover.d.ts +15 -3
- package/dist/components/data-display/popover.js +168 -2
- package/dist/components/data-entry/branch-scope-picker.d.ts +1 -1
- package/dist/components/data-entry/index.d.ts +5 -12
- package/dist/components/data-entry/index.js +11 -12
- package/dist/components/data-entry/input-otp.d.ts +48 -2
- package/dist/components/data-entry/input-otp.js +94 -1
- package/dist/components/data-entry/number-input.d.ts +1 -1
- package/dist/components/data-entry/password-input.d.ts +38 -2
- package/dist/components/data-entry/password-input.js +56 -1
- package/dist/components/data-entry/rating.d.ts +38 -2
- package/dist/components/data-entry/rating.js +127 -1
- package/dist/components/data-entry/segmented.d.ts +94 -2
- package/dist/components/data-entry/segmented.js +104 -1
- package/dist/components/{ui/tag-input.d.ts → data-entry/select-tags-inline.d.ts} +7 -4
- package/dist/components/{ui/tag-input.js → data-entry/select-tags-inline.js} +4 -4
- package/dist/components/data-entry/select.js +4 -0
- package/dist/components/data-entry/toggle-group.d.ts +108 -2
- package/dist/components/data-entry/toggle-group.js +189 -1
- package/dist/components/data-entry/toggle.d.ts +86 -2
- package/dist/components/data-entry/toggle.js +153 -2
- package/dist/components/feedback/alert.d.ts +5 -3
- package/dist/components/feedback/alert.js +14 -2
- package/dist/components/feedback/index.d.ts +2 -6
- package/dist/components/feedback/index.js +1 -13
- package/dist/components/feedback/skeleton.d.ts +4 -17
- package/dist/components/feedback/skeleton.js +3 -40
- package/dist/components/general/index.d.ts +2 -4
- package/dist/components/general/index.js +1 -6
- package/dist/components/general/typography.d.ts +4 -58
- package/dist/components/general/typography.js +7 -141
- package/dist/components/layout/aspect-ratio.d.ts +24 -1
- package/dist/components/layout/aspect-ratio.js +18 -1
- package/dist/components/layout/auth-divider.js +1 -1
- package/dist/components/layout/auth-identity.js +6 -2
- package/dist/components/layout/centered-shell.d.ts +13 -8
- package/dist/components/layout/centered-shell.js +43 -1
- package/dist/components/layout/flex.d.ts +1 -1
- package/dist/components/layout/flex.js +73 -1
- package/dist/components/layout/index.d.ts +1 -13
- package/dist/components/layout/index.js +0 -12
- package/dist/components/layout/separator.d.ts +25 -2
- package/dist/components/layout/separator.js +71 -1
- package/dist/components/navigation/{app-setting-toggle.d.ts → app-setting-cycle.d.ts} +3 -4
- package/dist/components/navigation/{app-setting-toggle.js → app-setting-cycle.js} +3 -3
- package/dist/components/navigation/app-setting-picker.d.ts +6 -2
- package/dist/components/navigation/app-setting-picker.js +20 -2
- package/dist/components/navigation/index.d.ts +3 -11
- package/dist/components/navigation/index.js +1 -9
- package/dist/components/navigation/tabs.js +1 -1
- package/dist/components/ui/carousel.d.ts +1 -1
- package/dist/components/ui/carousel.js +1 -1
- package/dist/components/ui/index.d.ts +11 -5
- package/dist/components/ui/index.js +5 -5
- package/dist/contracts/measurement.json +2 -2
- package/dist/email/brand-mark.d.ts +3 -2
- package/dist/email/brand-mark.js +1 -1
- package/dist/email/color.d.ts +7 -0
- package/dist/email/color.js +14 -1
- package/dist/email/index.d.ts +10 -2
- package/dist/email/index.js +23 -2
- package/dist/email/tokens.generated.d.ts +120 -2
- package/dist/email/tokens.generated.js +119 -1
- package/dist/i18n/locale-tags.d.ts +25 -0
- package/dist/i18n/locale-tags.js +59 -0
- package/dist/i18n/translate.d.ts +20 -3
- package/dist/i18n/translate.js +25 -14
- package/dist/i18n/use-translation.d.ts +3 -3
- package/dist/i18n/use-translation.js +4 -2
- package/dist/{components/navigation → lab}/anchor.d.ts +2 -2
- package/dist/{components/navigation → lab}/anchor.js +5 -5
- package/dist/{components/data-display → lab}/carousel.js +2 -2
- package/dist/{components/layout → lab}/draggable-panel.d.ts +8 -8
- package/dist/{components/layout → lab}/draggable-panel.js +2 -2
- package/dist/{components/data-entry → lab}/emoji-picker.d.ts +2 -2
- package/dist/{components/data-entry → lab}/emoji-picker.js +6 -6
- package/dist/{components/general → lab}/float-button.d.ts +8 -8
- package/dist/{components/general → lab}/float-button.js +7 -7
- package/dist/lab/index.d.ts +39 -0
- package/dist/lab/index.js +48 -0
- package/dist/{components/layout → lab}/legal-document-shell.d.ts +2 -2
- package/dist/{components/layout → lab}/legal-document-shell.js +4 -4
- package/dist/{components/data-display → lab}/marquee.d.ts +5 -5
- package/dist/{components/data-display → lab}/marquee.js +5 -5
- package/dist/{components/layout → lab}/masonry.d.ts +2 -2
- package/dist/{components/layout → lab}/masonry.js +3 -3
- package/dist/{components/navigation → lab}/mega-menu.d.ts +4 -4
- package/dist/{components/navigation → lab}/mega-menu.js +2 -2
- package/dist/{components/data-display → lab}/org-chart.d.ts +2 -2
- package/dist/{components/data-display → lab}/org-chart.js +4 -4
- package/dist/{components/layout → lab}/page-cover.d.ts +2 -2
- package/dist/{components/layout → lab}/page-cover.js +2 -2
- package/dist/{components/data-display → lab}/range-timeline.d.ts +1 -1
- package/dist/{components/data-display → lab}/range-timeline.js +6 -6
- package/dist/{components/data-entry → lab}/sortable-list.d.ts +2 -2
- package/dist/{components/data-entry → lab}/sortable-list.js +3 -3
- package/dist/{components/data-display → lab}/text-diff.d.ts +3 -3
- package/dist/{components/data-display → lab}/text-diff.js +4 -4
- package/dist/{components/data-display → lab}/timeline-grid.d.ts +2 -2
- package/dist/{components/data-display → lab}/timeline-grid.js +1 -1
- package/dist/lib/control-styles.js +1 -1
- package/dist/lib/datetime/format.js +20 -6
- package/dist/lib/datetime/sync.d.ts +6 -2
- package/dist/lib/datetime/sync.js +14 -18
- package/dist/lib/platform.d.ts +1 -1
- package/dist/props/components/app.prop.d.ts +28 -13
- package/dist/props/components/data-display.prop.d.ts +19 -29
- package/dist/props/components/feedback.prop.d.ts +15 -44
- package/dist/props/components/general.prop.d.ts +2 -64
- package/dist/props/components/index.d.ts +9 -1
- package/dist/props/components/layout.prop.d.ts +41 -57
- package/dist/props/registry.d.ts +48 -101
- package/dist/props/registry.js +45 -129
- package/dist/props/vocabulary/index.d.ts +1 -1
- package/dist/props/vocabulary/interaction.prop.d.ts +3 -12
- package/dist/styles/alert-layout.css +0 -29
- package/dist/styles/data-display-layout.css +14 -22
- package/dist/styles/fonts/OFL.txt +93 -0
- package/dist/styles/form-layout.css +4 -0
- package/dist/styles/index.css +0 -2
- package/dist/styles/layers.json +44 -179
- package/dist/styles/text-layout.css +0 -15
- package/dist/styles.css +2 -0
- package/dist/themes/godx-tokens.css +41 -0
- package/dist/themes/godx.css +3 -0
- package/dist/themes/godx.d.ts +16 -0
- package/dist/themes/godx.js +12 -0
- package/dist/tokens/components/feedback.css +0 -6
- package/dist/tokens/derived.css +23 -22
- package/dist/tokens/foundation.css +4 -6
- package/docs/COMPOSITION-VS-COMPONENT.md +58 -33
- package/docs/CONSUMER-RULES.md +1 -1
- package/docs/CUSTOMER-THEMING.md +17 -53
- package/docs/migrations/v32.md +105 -0
- package/package.json +59 -19
- package/scripts/_agent-setup.mjs +54 -3
- package/scripts/brand-accent.generated.mjs +15 -2
- package/scripts/cli.mjs +36 -11
- package/scripts/codemod.mjs +542 -0
- package/scripts/consumer-rule.md +21 -43
- package/scripts/postinstall.mjs +10 -47
- package/scripts/prune-css.mjs +1 -1
- package/scripts/ui-audit.mjs +5 -2
- package/dist/components/data-display/chat-bubble.d.ts +0 -30
- package/dist/components/data-display/chat-bubble.js +0 -229
- package/dist/components/data-display/hover-card.d.ts +0 -1
- package/dist/components/data-display/hover-card.js +0 -7
- package/dist/components/data-display/thought-chain.d.ts +0 -42
- package/dist/components/data-display/thought-chain.js +0 -177
- package/dist/components/data-display/thumbnail.d.ts +0 -37
- package/dist/components/data-display/thumbnail.js +0 -20
- package/dist/components/data-display/welcome.d.ts +0 -26
- package/dist/components/data-display/welcome.js +0 -37
- package/dist/components/data-entry/attachments.d.ts +0 -19
- package/dist/components/data-entry/attachments.js +0 -366
- package/dist/components/data-entry/chat-composer.d.ts +0 -51
- package/dist/components/data-entry/chat-composer.js +0 -200
- package/dist/components/data-entry/chat-suggestion.d.ts +0 -28
- package/dist/components/data-entry/chat-suggestion.js +0 -309
- package/dist/components/data-entry/tag-input.d.ts +0 -2
- package/dist/components/data-entry/tag-input.js +0 -5
- package/dist/components/feedback/banner.d.ts +0 -21
- package/dist/components/feedback/banner.js +0 -19
- package/dist/components/feedback/callout.d.ts +0 -23
- package/dist/components/feedback/callout.js +0 -42
- package/dist/components/layout/auth-shell.d.ts +0 -10
- package/dist/components/layout/auth-shell.js +0 -42
- package/dist/components/layout/space-compact.d.ts +0 -65
- package/dist/components/layout/space-compact.js +0 -52
- package/dist/components/navigation/conversations.d.ts +0 -39
- package/dist/components/navigation/conversations.js +0 -371
- package/dist/components/ui/accordion.d.ts +0 -51
- package/dist/components/ui/accordion.js +0 -254
- package/dist/components/ui/aspect-ratio.d.ts +0 -24
- package/dist/components/ui/aspect-ratio.js +0 -21
- package/dist/components/ui/avatar.d.ts +0 -16
- package/dist/components/ui/avatar.js +0 -115
- package/dist/components/ui/credential-reveal.d.ts +0 -9
- package/dist/components/ui/credential-reveal.js +0 -160
- package/dist/components/ui/hover-card.d.ts +0 -47
- package/dist/components/ui/hover-card.js +0 -205
- package/dist/components/ui/input-otp.d.ts +0 -48
- package/dist/components/ui/input-otp.js +0 -101
- package/dist/components/ui/password-input.d.ts +0 -38
- package/dist/components/ui/password-input.js +0 -60
- package/dist/components/ui/rating.d.ts +0 -38
- package/dist/components/ui/rating.js +0 -131
- package/dist/components/ui/segmented.d.ts +0 -94
- package/dist/components/ui/segmented.js +0 -108
- package/dist/components/ui/separator.d.ts +0 -25
- package/dist/components/ui/separator.js +0 -74
- package/dist/components/ui/toggle-group.d.ts +0 -108
- package/dist/components/ui/toggle-group.js +0 -194
- package/dist/components/ui/toggle.d.ts +0 -86
- package/dist/components/ui/toggle.js +0 -156
- package/docs/CANONICAL-CONTRACTS.md +0 -206
- package/docs/COMPONENTS.md +0 -163
- package/docs/DATETIME.md +0 -78
- package/docs/DEVELOPMENT.md +0 -269
- package/docs/FRAME-A11Y-CI.md +0 -287
- package/docs/FRAME-COVERAGE-LEDGER.md +0 -123
- package/docs/FRAME-COVERAGE-REPORT.md +0 -228
- package/docs/FRAME-COVERAGE-STANDARD.md +0 -65
- package/docs/FRAME-COVERAGE.md +0 -29
- package/docs/MEASUREMENT-CONTRACT.md +0 -109
- package/docs/PROPS-REGISTRY.md +0 -61
- package/docs/PROPS-VOCABULARY.md +0 -100
- package/docs/REGISTRY.md +0 -70
- package/docs/TESTING.md +0 -107
- package/docs/THEME-API-COVERAGE.md +0 -538
- package/docs/WHAT-BELONGS-HERE.md +0 -179
- package/docs/asset-modules.d.ts +0 -53
- package/docs/assets/cover-terrain.svg +0 -6
- package/docs/assets/portrait-amber.svg +0 -5
- package/docs/assets/portrait-clay.svg +0 -5
- package/docs/assets/portrait-indigo.svg +0 -5
- package/docs/assets/portrait-iris.svg +0 -5
- package/docs/assets/portrait-moss.svg +0 -5
- package/docs/assets/portrait-plum.svg +0 -5
- package/docs/assets/portrait-slate.svg +0 -5
- package/docs/assets/service-mark-rose.svg +0 -6
- package/docs/assets/service-mark-teal.svg +0 -5
- package/docs/assets/shot-landscape.svg +0 -12
- package/docs/assets/shot-portrait.svg +0 -10
- package/docs/assets/tcgm/card-1.svg +0 -1
- package/docs/assets/tcgm/card-2.svg +0 -1
- package/docs/assets/tcgm/card-3.svg +0 -1
- package/docs/assets/tcgm/card-4.svg +0 -1
- package/docs/assets/tcgm/card-5.svg +0 -1
- package/docs/assets/tcgm/card-6.svg +0 -1
- package/docs/assets/tcgm/hero-prism.svg +0 -1
- package/docs/assets/tcgm/scene-1.svg +0 -1
- package/docs/assets/tcgm/scene-2.svg +0 -1
- package/docs/assets/tcgm/scene-3.svg +0 -1
- package/docs/assets/tcgm/scene-4.svg +0 -1
- package/docs/assets/tcgm/scene-5.svg +0 -1
- package/docs/assets/tcgm/tcgm-lockup-color.svg +0 -1
- package/docs/assets/tcgm/tcgm-symbol-color.svg +0 -1
- package/docs/charts/cjk-category-axis.tsx +0 -81
- package/docs/charts/compact-bar-trend.tsx +0 -327
- package/docs/charts/size-tiers.tsx +0 -192
- package/docs/data-display/accordion.tsx +0 -99
- package/docs/data-display/avatar.tsx +0 -502
- package/docs/data-display/badge.tsx +0 -335
- package/docs/data-display/card/examples/detail-panel.tsx +0 -106
- package/docs/data-display/card/examples/tab-list.tsx +0 -97
- package/docs/data-display/card/index.md +0 -3
- package/docs/data-display/card/index.tsx +0 -390
- package/docs/data-display/carousel.tsx +0 -160
- package/docs/data-display/charts.tsx +0 -278
- package/docs/data-display/chat-bubble.tsx +0 -397
- package/docs/data-display/code-block.tsx +0 -188
- package/docs/data-display/collapsible.tsx +0 -162
- package/docs/data-display/credential-reveal.tsx +0 -148
- package/docs/data-display/data-table/examples/antd-parity.tsx +0 -257
- package/docs/data-display/data-table/examples/approval-queue.tsx +0 -212
- package/docs/data-display/data-table/examples/grid-features.tsx +0 -158
- package/docs/data-display/data-table/examples/list-page.tsx +0 -175
- package/docs/data-display/data-table/examples/selectable-inbox.tsx +0 -113
- package/docs/data-display/data-table/examples/server-paged.tsx +0 -179
- package/docs/data-display/data-table/examples/striped-list.tsx +0 -173
- package/docs/data-display/data-table/index.md +0 -9
- package/docs/data-display/data-table/index.tsx +0 -407
- package/docs/data-display/descriptions.tsx +0 -263
- package/docs/data-display/empty-state.tsx +0 -164
- package/docs/data-display/feature-list.tsx +0 -159
- package/docs/data-display/hover-card.tsx +0 -181
- package/docs/data-display/image.tsx +0 -170
- package/docs/data-display/legend.tsx +0 -158
- package/docs/data-display/list-row.tsx +0 -441
- package/docs/data-display/markdown.tsx +0 -86
- package/docs/data-display/marquee.tsx +0 -254
- package/docs/data-display/org-chart.tsx +0 -165
- package/docs/data-display/permission-matrix.tsx +0 -188
- package/docs/data-display/popover-touch.tsx +0 -27
- package/docs/data-display/popover.tsx +0 -331
- package/docs/data-display/progress.tsx +0 -162
- package/docs/data-display/prose.tsx +0 -169
- package/docs/data-display/qr-code.tsx +0 -68
- package/docs/data-display/scroll-area.tsx +0 -420
- package/docs/data-display/service-launcher-card.tsx +0 -445
- package/docs/data-display/stat-card.tsx +0 -354
- package/docs/data-display/swatch.tsx +0 -107
- package/docs/data-display/table.tsx +0 -362
- package/docs/data-display/text-diff.tsx +0 -89
- package/docs/data-display/thought-chain.tsx +0 -176
- package/docs/data-display/thumbnail.tsx +0 -128
- package/docs/data-display/timeline-grid.tsx +0 -119
- package/docs/data-display/timeline.tsx +0 -671
- package/docs/data-display/touch-actions.tsx +0 -36
- package/docs/data-display/tree.tsx +0 -724
- package/docs/data-display/welcome.tsx +0 -115
- package/docs/data-entry/attachments.tsx +0 -160
- package/docs/data-entry/block-editor.tsx +0 -105
- package/docs/data-entry/branch-scope-picker.tsx +0 -128
- package/docs/data-entry/calendar.tsx +0 -226
- package/docs/data-entry/cascader.tsx +0 -380
- package/docs/data-entry/chat-composer.tsx +0 -619
- package/docs/data-entry/chat-suggestion.tsx +0 -301
- package/docs/data-entry/checkbox.tsx +0 -256
- package/docs/data-entry/color-picker.tsx +0 -189
- package/docs/data-entry/command-palette.tsx +0 -179
- package/docs/data-entry/command.tsx +0 -341
- package/docs/data-entry/country-picker-recipe.tsx +0 -175
- package/docs/data-entry/date-picker.tsx +0 -452
- package/docs/data-entry/emoji-picker.tsx +0 -35
- package/docs/data-entry/form/examples/employee-settings.tsx +0 -267
- package/docs/data-entry/form/examples/invoice-form.tsx +0 -387
- package/docs/data-entry/form-dynamic-fields.tsx +0 -199
- package/docs/data-entry/form-field/examples/a11y-contract.tsx +0 -242
- package/docs/data-entry/form-field/examples/create-form.tsx +0 -107
- package/docs/data-entry/form-field/index.md +0 -8
- package/docs/data-entry/form-field/index.tsx +0 -337
- package/docs/data-entry/form-inertia.tsx +0 -80
- package/docs/data-entry/form-root.tsx +0 -112
- package/docs/data-entry/form.tsx +0 -1498
- package/docs/data-entry/input-otp.tsx +0 -258
- package/docs/data-entry/input.tsx +0 -796
- package/docs/data-entry/label.tsx +0 -102
- package/docs/data-entry/markdown-editor.tsx +0 -69
- package/docs/data-entry/number-input.tsx +0 -279
- package/docs/data-entry/password-input.tsx +0 -102
- package/docs/data-entry/password-strength.tsx +0 -99
- package/docs/data-entry/radio-group.tsx +0 -316
- package/docs/data-entry/rating.tsx +0 -91
- package/docs/data-entry/record-picker.tsx +0 -209
- package/docs/data-entry/search-input.tsx +0 -121
- package/docs/data-entry/segmented-in-filter-row.tsx +0 -60
- package/docs/data-entry/segmented.tsx +0 -300
- package/docs/data-entry/select-async-contracts.tsx +0 -108
- package/docs/data-entry/select-matrix.tsx +0 -209
- package/docs/data-entry/select.tsx +0 -547
- package/docs/data-entry/slider.tsx +0 -212
- package/docs/data-entry/sortable-list.tsx +0 -76
- package/docs/data-entry/switch.tsx +0 -314
- package/docs/data-entry/tag-input.tsx +0 -145
- package/docs/data-entry/textarea.tsx +0 -249
- package/docs/data-entry/time-picker.tsx +0 -187
- package/docs/data-entry/time-range-picker.tsx +0 -55
- package/docs/data-entry/toggle-count.tsx +0 -348
- package/docs/data-entry/toggle-group.tsx +0 -438
- package/docs/data-entry/toggle.tsx +0 -217
- package/docs/data-entry/transfer.tsx +0 -115
- package/docs/data-entry/tree-select.tsx +0 -204
- package/docs/data-entry/upload-crop-dialog.tsx +0 -109
- package/docs/data-entry/upload.tsx +0 -310
- package/docs/feedback/alert-dialog.tsx +0 -270
- package/docs/feedback/alert.tsx +0 -248
- package/docs/feedback/auth-expiry.tsx +0 -104
- package/docs/feedback/banner.tsx +0 -183
- package/docs/feedback/callout.tsx +0 -220
- package/docs/feedback/danger-confirm.tsx +0 -91
- package/docs/feedback/dialog-touch.tsx +0 -24
- package/docs/feedback/dialog.tsx +0 -373
- package/docs/feedback/sheet.tsx +0 -510
- package/docs/feedback/skeleton.tsx +0 -168
- package/docs/feedback/toast.tsx +0 -135
- package/docs/feedback/tooltip.tsx +0 -171
- package/docs/feedback/two-factor-setup.tsx +0 -68
- package/docs/foundation/_email-specimen.ts +0 -274
- package/docs/foundation/_theme-editor-scope.ts +0 -222
- package/docs/foundation/colors.tsx +0 -207
- package/docs/foundation/density.tsx +0 -242
- package/docs/foundation/email-tokens.tsx +0 -323
- package/docs/foundation/radius-shadow.tsx +0 -154
- package/docs/foundation/spacing.tsx +0 -216
- package/docs/foundation/theme-editor.tsx +0 -654
- package/docs/foundation/typography.tsx +0 -147
- package/docs/general/actions.tsx +0 -175
- package/docs/general/activity.tsx +0 -289
- package/docs/general/button/examples/destructive-confirm.tsx +0 -90
- package/docs/general/button/examples/form-actions.tsx +0 -87
- package/docs/general/button/examples/toolbar.tsx +0 -160
- package/docs/general/button/index.md +0 -16
- package/docs/general/button/index.tsx +0 -236
- package/docs/general/float-button.tsx +0 -133
- package/docs/general/icon.tsx +0 -217
- package/docs/general/logo.tsx +0 -194
- package/docs/general/reveal.tsx +0 -309
- package/docs/general/typography.tsx +0 -542
- package/docs/i18n/messages/en.json +0 -1715
- package/docs/i18n/messages/ja.json +0 -1708
- package/docs/i18n/messages/vi.json +0 -1708
- package/docs/layout/account-chip.tsx +0 -72
- package/docs/layout/admin-collection.tsx +0 -122
- package/docs/layout/affix.tsx +0 -209
- package/docs/layout/app-launcher.tsx +0 -211
- package/docs/layout/app-shell-arrangements.tsx +0 -225
- package/docs/layout/app-shell-narrow-bar.tsx +0 -205
- package/docs/layout/app-shell-states.tsx +0 -171
- package/docs/layout/app-shell.tsx +0 -395
- package/docs/layout/aspect-ratio.tsx +0 -135
- package/docs/layout/auth-account-summary.tsx +0 -103
- package/docs/layout/auth-divider.tsx +0 -28
- package/docs/layout/auth-footer.tsx +0 -37
- package/docs/layout/auth-identity.tsx +0 -70
- package/docs/layout/auth-recovery/examples/mfa-challenge.md +0 -41
- package/docs/layout/auth-recovery/examples/mfa-challenge.tsx +0 -254
- package/docs/layout/auth-recovery/examples/mobile-390.md +0 -25
- package/docs/layout/auth-recovery/examples/mobile-390.tsx +0 -82
- package/docs/layout/auth-recovery/examples/password-recovery.md +0 -24
- package/docs/layout/auth-recovery/examples/password-recovery.tsx +0 -197
- package/docs/layout/auth-recovery/examples/wrapping-ja-en-vi.md +0 -27
- package/docs/layout/auth-recovery/examples/wrapping-ja-en-vi.tsx +0 -156
- package/docs/layout/auth-recovery/index.md +0 -140
- package/docs/layout/auth-recovery/index.tsx +0 -96
- package/docs/layout/auth-shell-context.tsx +0 -103
- package/docs/layout/auth-shell-device.tsx +0 -112
- package/docs/layout/auth-shell-registration.tsx +0 -338
- package/docs/layout/auth-shell-variants.tsx +0 -143
- package/docs/layout/auth-shell.tsx +0 -59
- package/docs/layout/auth-stack.tsx +0 -40
- package/docs/layout/centered-shell.tsx +0 -102
- package/docs/layout/draggable-panel.tsx +0 -127
- package/docs/layout/error-surface/examples/application-403.tsx +0 -84
- package/docs/layout/error-surface/examples/application-404.tsx +0 -77
- package/docs/layout/error-surface/examples/system-500.tsx +0 -47
- package/docs/layout/error-surface/examples/system-503.tsx +0 -48
- package/docs/layout/error-surface/index.md +0 -153
- package/docs/layout/error-surface/index.tsx +0 -239
- package/docs/layout/flex.tsx +0 -444
- package/docs/layout/legal-document-shell/_data.ts +0 -110
- package/docs/layout/legal-document-shell/examples/desktop-1440.md +0 -12
- package/docs/layout/legal-document-shell/examples/desktop-1440.tsx +0 -83
- package/docs/layout/legal-document-shell/examples/mobile-390.md +0 -22
- package/docs/layout/legal-document-shell/examples/mobile-390.tsx +0 -70
- package/docs/layout/legal-document-shell/examples/tablet-1024.md +0 -3
- package/docs/layout/legal-document-shell/examples/tablet-1024.tsx +0 -84
- package/docs/layout/legal-document-shell/examples/wrapping-ja-en-vi.md +0 -18
- package/docs/layout/legal-document-shell/examples/wrapping-ja-en-vi.tsx +0 -61
- package/docs/layout/legal-document-shell/index.md +0 -51
- package/docs/layout/legal-document-shell/index.tsx +0 -101
- package/docs/layout/masonry.tsx +0 -291
- package/docs/layout/master-detail.tsx +0 -390
- package/docs/layout/mobile-shell.tsx +0 -106
- package/docs/layout/nav-list.tsx +0 -584
- package/docs/layout/org-switcher.tsx +0 -131
- package/docs/layout/page-container.tsx +0 -1020
- package/docs/layout/page-cover.tsx +0 -56
- package/docs/layout/resizable-panel.tsx +0 -419
- package/docs/layout/responsive-grid.tsx +0 -403
- package/docs/layout/separator.tsx +0 -327
- package/docs/layout/service-role-panel.tsx +0 -144
- package/docs/layout/sidebar.tsx +0 -689
- package/docs/layout/space-compact.tsx +0 -202
- package/docs/layout/split-pane.tsx +0 -532
- package/docs/layout/topbar-item.tsx +0 -233
- package/docs/layout/topbar.tsx +0 -360
- package/docs/navigation/anchor.tsx +0 -295
- package/docs/navigation/app-setting-picker.tsx +0 -178
- package/docs/navigation/app-setting-toggle.tsx +0 -111
- package/docs/navigation/breadcrumb.tsx +0 -207
- package/docs/navigation/card-tabs.tsx +0 -344
- package/docs/navigation/conversations.tsx +0 -176
- package/docs/navigation/dropdown-menu.tsx +0 -345
- package/docs/navigation/filter-bar.tsx +0 -247
- package/docs/navigation/mega-menu-panel.tsx +0 -86
- package/docs/navigation/mega-menu.tsx +0 -254
- package/docs/navigation/pagination.tsx +0 -293
- package/docs/navigation/steps.tsx +0 -315
- package/docs/navigation/tabs-rtl.tsx +0 -28
- package/docs/navigation/tabs.tsx +0 -755
- package/docs/navigation/toolbar.tsx +0 -347
- package/docs/providers/app-provider.tsx +0 -191
- package/docs/providers/format-date.tsx +0 -230
- package/docs/providers/theme-scope.tsx +0 -186
- package/docs/query/button-refetch.tsx +0 -161
- package/docs/query/data-state.tsx +0 -262
- package/docs/query/infinite-query-state.tsx +0 -97
- package/docs/query/mutation-feedback.tsx +0 -128
- package/docs/query/touch-actions.tsx +0 -68
- package/docs/react-router/prefetch-link.tsx +0 -262
- package/docs/roadmap/ai-chat-components.md +0 -206
- package/docs/roadmap/antd-parity.md +0 -155
- package/docs/roadmap/badge-tag-chip-count.md +0 -172
- package/docs/roadmap/list-masonry.md +0 -159
- package/docs/roadmap/parity-audit-data-display-feedback.md +0 -567
- package/docs/roadmap/parity-audit-data-entry.md +0 -368
- package/docs/roadmap/parity-audit-layout-navigation-general.md +0 -459
- package/docs/roadmap/parity-backlog.md +0 -77
- package/docs/roadmap/tree-components.md +0 -151
- package/docs/roadmap/website-components.md +0 -813
- package/docs/showcase/acme-portal.tsx +0 -461
- package/docs/showcase/acme-website.tsx +0 -499
- package/docs/showcase/caimono-price-comparison.tsx +0 -919
- package/docs/showcase/case1-warehouse-dashboard.tsx +0 -358
- package/docs/showcase/case2-employee-me.tsx +0 -438
- package/docs/showcase/case3-approval-workflow.tsx +0 -531
- package/docs/showcase/case4-login.tsx +0 -312
- package/docs/showcase/case5-shift-calendar.tsx +0 -702
- package/docs/showcase/case6-agency-handy.tsx +0 -1120
- package/docs/showcase/futurelastic-web.tsx +0 -441
- package/docs/showcase/marketing-page.tsx +0 -895
- package/docs/showcase/org-switcher.tsx +0 -320
- package/docs/showcase/permission-matrix.tsx +0 -354
- package/docs/showcase/public-landing.tsx +0 -210
- package/docs/showcase/settings-account-sections.tsx +0 -559
- package/docs/showcase/settings-security-mfa.tsx +0 -145
- package/docs/showcase/table-approval-queue.tsx +0 -199
- package/docs/showcase/table-bulk-actions.tsx +0 -468
- package/docs/showcase/table-compact-kintone.tsx +0 -438
- package/docs/showcase/table-conditional-format.tsx +0 -367
- package/docs/showcase/table-crud-list.tsx +0 -544
- package/docs/showcase/table-density.tsx +0 -349
- package/docs/showcase/table-expandable-rows.tsx +0 -496
- package/docs/showcase/table-filter-chips.tsx +0 -468
- package/docs/showcase/table-footer-totals.tsx +0 -328
- package/docs/showcase/table-grouped-subtotals.tsx +0 -398
- package/docs/showcase/table-master-detail.tsx +0 -482
- package/docs/showcase/table-pagination.tsx +0 -409
- package/docs/showcase/table-states.tsx +0 -371
- package/docs/showcase/table-sticky-columns.tsx +0 -377
- package/docs/showcase/table-tree-rows.tsx +0 -451
- package/docs/showcase/table-view-tabs.tsx +0 -488
- package/docs/showcase/tcgm-website.tsx +0 -1047
- package/docs/showcase/tenant-brand-color.tsx +0 -338
- package/docs/showcase/theme-customization.tsx +0 -1292
- package/docs/showcase/theme-lab.tsx +0 -2125
- package/docs/themes/flat.css +0 -466
- package/docs/themes/glassmorphism.css +0 -960
- package/docs/themes/index.ts +0 -219
- package/docs/themes/neubrutalism.css +0 -481
- /package/dist/components/navigation/{filter-bar.d.ts → toolbar.d.ts} +0 -0
- /package/dist/components/navigation/{filter-bar.js → toolbar.js} +0 -0
- /package/dist/{components/data-display → lab}/carousel.d.ts +0 -0
- /package/dist/{components/data-entry → lab}/emoji-data.d.ts +0 -0
- /package/dist/{components/data-entry → lab}/emoji-data.js +0 -0
- /package/dist/{components/data-display → lab}/marquee-reveal.d.ts +0 -0
- /package/dist/{components/data-display → lab}/marquee-reveal.js +0 -0
|
@@ -1,2125 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Showcase · theme-lab — CAN THIS COMPONENT SET WEAR A COMPLEX THEME? One page, every component
|
|
3
|
-
* that can be rendered, several themes, several seeds, switchable, measured.
|
|
4
|
-
*
|
|
5
|
-
* It replaces `/showcase/glassmorphism`, which gh#882 diagnosed correctly: that page proved ONE
|
|
6
|
-
* theme against a DOZEN components, and the question is neither "does glassmorphism work" nor
|
|
7
|
-
* "does Card survive it". A single theme cannot answer the question, and twelve components cannot
|
|
8
|
-
* either — three defects that week were found only because something happened to be on the page
|
|
9
|
-
* (an opaque Tabs strip inside a glass Card, a table header that kept `--muted`, a Sidebar over
|
|
10
|
-
* the wrong canvas). **Coverage is the instrument.**
|
|
11
|
-
*
|
|
12
|
-
* ── THE RULES THIS PAGE IS MEASURED UNDER ────────────────────────────────────────────────────
|
|
13
|
-
* 1. `docs/themes/*.css` may contain NOTHING but `--custom-property` declarations. No
|
|
14
|
-
* `backdrop-filter:`, no `background:`, no selector into a `.ui-*` class.
|
|
15
|
-
* 2. This page carries no `className` and no inline `style` for theming. The ONE inline style is
|
|
16
|
-
* `tenantTheme(hex).vars` on the scope — the library's own published channel for a seed, and
|
|
17
|
-
* the thing gh#882 asks to be used "rather than hand-picking".
|
|
18
|
-
* 3. `ThemeScope`, never a bare wrapper. `src/styles/base.css` sets `color: hsl(var(--foreground))`
|
|
19
|
-
* on `body`, above every scope a page can make, so that `var()` substitutes against the ROOT
|
|
20
|
-
* once and every descendant inherits the RESOLVED colour. A plain `<div>` therefore retints
|
|
21
|
-
* every surface and no text — measured at 1.34:1 before gh#881. `ThemeScope` re-states `color`
|
|
22
|
-
* on itself AND on the body-level overlay host it creates, which is also what carries the
|
|
23
|
-
* theme to the portalled panels: Dialog, Sheet, Select, DropdownMenu, Popover, Tooltip and
|
|
24
|
-
* Toast all portal out of this subtree, and a custom property only inherits through the DOM.
|
|
25
|
-
* The previous page re-declared `data-theme-style` on each `*Content` by hand; that is no
|
|
26
|
-
* longer needed and its absence here is part of what this page checks.
|
|
27
|
-
* 4. Where something cannot be expressed, the RESULT is written down — on the page, in the
|
|
28
|
-
* "could not be rendered" table at the bottom and the "could not be reached" notes in each
|
|
29
|
-
* theme file — never worked around.
|
|
30
|
-
*
|
|
31
|
-
* ── ADDRESSING, FOR THE INSTRUMENT ───────────────────────────────────────────────────────────
|
|
32
|
-
* `?theme=<id>&seed=<id>` drives both switches, so `scripts/measure-glass.mjs` navigates straight
|
|
33
|
-
* to a cell of the matrix instead of clicking through a Segmented whose labels are localised (the
|
|
34
|
-
* preview's default locale is `vi`). Overlay triggers carry `data-probe="…"`, because the
|
|
35
|
-
* instrument has had four of its own selectors wrong — `[data-slot="table"]` when the blur is on
|
|
36
|
-
* `.ui-data-table-surface`, `[role="listbox"]` instead of `.ui-select-content`, `borderTopWidth`
|
|
37
|
-
* alone, and a backdrop sampled inside the Sidebar — every one of them making the library look
|
|
38
|
-
* worse than it was. A `data-*` hook is not styling and not a theme; it is an address.
|
|
39
|
-
*
|
|
40
|
-
* ── WHAT IS NOT HERE, AND WHY ────────────────────────────────────────────────────────────────
|
|
41
|
-
* See `ABSENT` at the bottom of this file: it is rendered on the page as a real table, because an
|
|
42
|
-
* absence nobody can see is an absence nobody accounts for. Every row is about RENDERING — a
|
|
43
|
-
* provider, a hook, a shell that owns the document — never about whether a token exists.
|
|
44
|
-
*
|
|
45
|
-
* ── AND THE ONE THING THIS PAGE DELIBERATELY DOES NOT SAY ────────────────────────────────────
|
|
46
|
-
* **No sentence here asserts that a surface is unreachable by a token.** The page it replaces
|
|
47
|
-
* carried a per-component gap table, and that table rotted twice — most recently inside the Sheet
|
|
48
|
-
* itself, whose body text read "sheet.tsx bakes `bg-background` into its className, there is no
|
|
49
|
-
* `--sheet-background` to set" while the panel it was printed on rendered `rgba(29, 33, 53, 0.92)`
|
|
50
|
-
* through the `--sheet-surface-background` gh#880 had added hours earlier. A reachability claim is
|
|
51
|
-
* true on the day it is written, false the day someone adds a knob, and worst of all in a page
|
|
52
|
-
* whose entire claim is to be a measurement.
|
|
53
|
-
*
|
|
54
|
-
* A derived table was considered and rejected, and the reason is small but decisive: the only
|
|
55
|
-
* honest source is `agent/tokens.json`, `docs/**` may not import it (`check:example-imports`
|
|
56
|
-
* allows relative `.ts` data modules and committed assets, not a JSON reach outside the tree), and
|
|
57
|
-
* a generated snapshot committed beside the page is the same rot with an extra step. So the prose
|
|
58
|
-
* here is limited to what the theme files DEMONSTRATE by setting a token, and the authority on
|
|
59
|
-
* reachability is `scripts/measure-glass.mjs`, which reads the computed value of every surface and
|
|
60
|
-
* every opened overlay across the whole theme × seed matrix. Run it; do not trust a paragraph.
|
|
61
|
-
*/
|
|
62
|
-
import * as React from "react";
|
|
63
|
-
import {
|
|
64
|
-
Activity as ActivityIcon,
|
|
65
|
-
BarChart3,
|
|
66
|
-
Bell,
|
|
67
|
-
Bot,
|
|
68
|
-
Building2,
|
|
69
|
-
Check,
|
|
70
|
-
ChevronDown,
|
|
71
|
-
Clock,
|
|
72
|
-
CreditCard,
|
|
73
|
-
FileText,
|
|
74
|
-
LayoutGrid,
|
|
75
|
-
LogOut,
|
|
76
|
-
Palette,
|
|
77
|
-
RefreshCw,
|
|
78
|
-
Search,
|
|
79
|
-
Settings,
|
|
80
|
-
Share2,
|
|
81
|
-
Shield,
|
|
82
|
-
Smartphone,
|
|
83
|
-
Users,
|
|
84
|
-
} from "lucide-react";
|
|
85
|
-
|
|
86
|
-
import { ThemeScope, tenantTheme, useOptionalAppContext } from "@godxjp/ui/app";
|
|
87
|
-
import { AreaChart, BarChart, LineChart, PieChart } from "@godxjp/ui/charts";
|
|
88
|
-
import { CompactBarTrend } from "@godxjp/ui/charts/compact-bar-trend";
|
|
89
|
-
import {
|
|
90
|
-
Accordion,
|
|
91
|
-
AccordionContent,
|
|
92
|
-
AccordionItem,
|
|
93
|
-
AccordionTrigger,
|
|
94
|
-
Avatar,
|
|
95
|
-
AvatarFallback,
|
|
96
|
-
Badge,
|
|
97
|
-
Card,
|
|
98
|
-
CardAction,
|
|
99
|
-
CardBar,
|
|
100
|
-
CardContent,
|
|
101
|
-
CardDescription,
|
|
102
|
-
CardFooter,
|
|
103
|
-
CardHeader,
|
|
104
|
-
CardTitle,
|
|
105
|
-
Carousel,
|
|
106
|
-
CarouselContent,
|
|
107
|
-
CarouselDots,
|
|
108
|
-
CarouselItem,
|
|
109
|
-
CarouselNext,
|
|
110
|
-
CarouselPrevious,
|
|
111
|
-
ChatBubble,
|
|
112
|
-
ChatBubbleList,
|
|
113
|
-
CodeBlock,
|
|
114
|
-
Collapsible,
|
|
115
|
-
CollapsibleContent,
|
|
116
|
-
CollapsibleTrigger,
|
|
117
|
-
CredentialReveal,
|
|
118
|
-
DataTable,
|
|
119
|
-
Descriptions,
|
|
120
|
-
EmptyState,
|
|
121
|
-
FeatureList,
|
|
122
|
-
HoverCard,
|
|
123
|
-
HoverCardContent,
|
|
124
|
-
HoverCardTrigger,
|
|
125
|
-
Legend,
|
|
126
|
-
ListRow,
|
|
127
|
-
Marquee,
|
|
128
|
-
PermissionMatrix,
|
|
129
|
-
Popover,
|
|
130
|
-
PopoverContent,
|
|
131
|
-
PopoverDescription,
|
|
132
|
-
PopoverHeader,
|
|
133
|
-
PopoverTitle,
|
|
134
|
-
PopoverTrigger,
|
|
135
|
-
Progress,
|
|
136
|
-
Prose,
|
|
137
|
-
QrCode,
|
|
138
|
-
RangeTimeline,
|
|
139
|
-
ScrollArea,
|
|
140
|
-
ServiceCatalogCta,
|
|
141
|
-
ServiceLauncherCard,
|
|
142
|
-
StatCard,
|
|
143
|
-
StatusBadge,
|
|
144
|
-
Swatch,
|
|
145
|
-
Table,
|
|
146
|
-
TableBody,
|
|
147
|
-
TableCell,
|
|
148
|
-
TableHead,
|
|
149
|
-
TableHeader,
|
|
150
|
-
TableRow,
|
|
151
|
-
ThoughtChain,
|
|
152
|
-
Thumbnail,
|
|
153
|
-
Timeline,
|
|
154
|
-
TimelineGrid,
|
|
155
|
-
Tree,
|
|
156
|
-
Welcome,
|
|
157
|
-
type ChatMessageProp,
|
|
158
|
-
type ColumnDef,
|
|
159
|
-
} from "@godxjp/ui/data-display";
|
|
160
|
-
import {
|
|
161
|
-
Attachments,
|
|
162
|
-
Calendar,
|
|
163
|
-
Cascader,
|
|
164
|
-
ChatComposer,
|
|
165
|
-
ChatSuggestion,
|
|
166
|
-
Checkbox,
|
|
167
|
-
CheckboxGroup,
|
|
168
|
-
ColorPicker,
|
|
169
|
-
Command,
|
|
170
|
-
CommandEmpty,
|
|
171
|
-
CommandGroup,
|
|
172
|
-
CommandInput,
|
|
173
|
-
CommandItem,
|
|
174
|
-
CommandList,
|
|
175
|
-
CommandPalette,
|
|
176
|
-
DatePicker,
|
|
177
|
-
BranchScopePicker,
|
|
178
|
-
Field,
|
|
179
|
-
Form,
|
|
180
|
-
FormErrors,
|
|
181
|
-
FormField,
|
|
182
|
-
Input,
|
|
183
|
-
InputOTP,
|
|
184
|
-
InputOTPGroup,
|
|
185
|
-
InputOTPSlot,
|
|
186
|
-
Label,
|
|
187
|
-
NumberInput,
|
|
188
|
-
PasswordInput,
|
|
189
|
-
PasswordStrength,
|
|
190
|
-
Radio,
|
|
191
|
-
RadioGroup,
|
|
192
|
-
Rating,
|
|
193
|
-
SearchInput,
|
|
194
|
-
Segmented,
|
|
195
|
-
Select,
|
|
196
|
-
Slider,
|
|
197
|
-
Switch,
|
|
198
|
-
TagInput,
|
|
199
|
-
Textarea,
|
|
200
|
-
TimePicker,
|
|
201
|
-
TimeRangePicker,
|
|
202
|
-
Toggle,
|
|
203
|
-
ToggleGroup,
|
|
204
|
-
ToggleGroupItem,
|
|
205
|
-
Transfer,
|
|
206
|
-
TreeSelect,
|
|
207
|
-
Upload,
|
|
208
|
-
type UploadFileItem,
|
|
209
|
-
} from "@godxjp/ui/data-entry";
|
|
210
|
-
import {
|
|
211
|
-
Alert,
|
|
212
|
-
AlertActions,
|
|
213
|
-
AlertDescription,
|
|
214
|
-
AlertDialog,
|
|
215
|
-
AlertTitle,
|
|
216
|
-
Banner,
|
|
217
|
-
Callout,
|
|
218
|
-
Dialog,
|
|
219
|
-
DialogBody,
|
|
220
|
-
DialogClose,
|
|
221
|
-
DialogContent,
|
|
222
|
-
DialogDescription,
|
|
223
|
-
DialogFooter,
|
|
224
|
-
DialogHeader,
|
|
225
|
-
DialogTitle,
|
|
226
|
-
Sheet,
|
|
227
|
-
SheetBody,
|
|
228
|
-
SheetClose,
|
|
229
|
-
SheetContent,
|
|
230
|
-
SheetDescription,
|
|
231
|
-
SheetFooter,
|
|
232
|
-
SheetHeader,
|
|
233
|
-
SheetTitle,
|
|
234
|
-
Skeleton,
|
|
235
|
-
SkeletonArticle,
|
|
236
|
-
SkeletonAvatar,
|
|
237
|
-
SkeletonButton,
|
|
238
|
-
SkeletonForm,
|
|
239
|
-
SkeletonImage,
|
|
240
|
-
SkeletonInput,
|
|
241
|
-
SkeletonNode,
|
|
242
|
-
SkeletonRows,
|
|
243
|
-
SkeletonTable,
|
|
244
|
-
Toaster,
|
|
245
|
-
Tooltip,
|
|
246
|
-
TooltipContent,
|
|
247
|
-
TooltipTrigger,
|
|
248
|
-
TwoFactorSetup,
|
|
249
|
-
toast,
|
|
250
|
-
} from "@godxjp/ui/feedback";
|
|
251
|
-
import {
|
|
252
|
-
Actions,
|
|
253
|
-
ActionsCopy,
|
|
254
|
-
ActionsFeedback,
|
|
255
|
-
Activity,
|
|
256
|
-
Button,
|
|
257
|
-
FloatButton,
|
|
258
|
-
Heading,
|
|
259
|
-
Icon,
|
|
260
|
-
Link,
|
|
261
|
-
Logo,
|
|
262
|
-
Paragraph,
|
|
263
|
-
Reveal,
|
|
264
|
-
Text,
|
|
265
|
-
Title,
|
|
266
|
-
Typography,
|
|
267
|
-
VisuallyHidden,
|
|
268
|
-
} from "@godxjp/ui/general";
|
|
269
|
-
import {
|
|
270
|
-
AccountChip,
|
|
271
|
-
Affix,
|
|
272
|
-
AppLauncher,
|
|
273
|
-
AppShell,
|
|
274
|
-
AspectRatio,
|
|
275
|
-
AuthAccountSummary,
|
|
276
|
-
AuthDivider,
|
|
277
|
-
AuthFooter,
|
|
278
|
-
AuthIdentity,
|
|
279
|
-
AuthStack,
|
|
280
|
-
Breadcrumb,
|
|
281
|
-
DraggablePanel,
|
|
282
|
-
ErrorSurface,
|
|
283
|
-
Flex,
|
|
284
|
-
Masonry,
|
|
285
|
-
MasterDetail,
|
|
286
|
-
NavList,
|
|
287
|
-
OrgSwitcher,
|
|
288
|
-
PageContainer,
|
|
289
|
-
ResizableHandle,
|
|
290
|
-
ResizablePanel,
|
|
291
|
-
ResizablePanelGroup,
|
|
292
|
-
ResponsiveGrid,
|
|
293
|
-
Separator,
|
|
294
|
-
ServiceRolePanel,
|
|
295
|
-
Sidebar,
|
|
296
|
-
SplitPane,
|
|
297
|
-
Topbar,
|
|
298
|
-
TopbarItem,
|
|
299
|
-
} from "@godxjp/ui/layout";
|
|
300
|
-
import {
|
|
301
|
-
Anchor,
|
|
302
|
-
AppSettingPicker,
|
|
303
|
-
AppSettingToggle,
|
|
304
|
-
Conversations,
|
|
305
|
-
DropdownMenu,
|
|
306
|
-
DropdownMenuContent,
|
|
307
|
-
DropdownMenuItem,
|
|
308
|
-
DropdownMenuLabel,
|
|
309
|
-
DropdownMenuSeparator,
|
|
310
|
-
DropdownMenuTrigger,
|
|
311
|
-
FilterBar,
|
|
312
|
-
MegaMenu,
|
|
313
|
-
Pagination,
|
|
314
|
-
Steps,
|
|
315
|
-
Tabs,
|
|
316
|
-
Toolbar,
|
|
317
|
-
ToolbarGroup,
|
|
318
|
-
} from "@godxjp/ui/navigation";
|
|
319
|
-
import { useTranslation } from "@godxjp/ui/i18n";
|
|
320
|
-
|
|
321
|
-
import shotLandscape from "../assets/shot-landscape.svg";
|
|
322
|
-
import {
|
|
323
|
-
MODES,
|
|
324
|
-
SEEDS,
|
|
325
|
-
THEMES,
|
|
326
|
-
modeFromQuery,
|
|
327
|
-
seedFromQuery,
|
|
328
|
-
themeFromQuery,
|
|
329
|
-
themeQueryValue,
|
|
330
|
-
type ModeRow,
|
|
331
|
-
type SeedRow,
|
|
332
|
-
type ThemeRow,
|
|
333
|
-
} from "../themes";
|
|
334
|
-
|
|
335
|
-
/* ── The components that CANNOT appear here, and the reason for each ─────────────────────────
|
|
336
|
-
* Rendered on the page as a table. An absence nobody can see is an absence nobody accounts for,
|
|
337
|
-
* and gh#882 asks for the reason in the page itself, not in a commit message. */
|
|
338
|
-
const ABSENT: ReadonlyArray<{ name: string; reasonKey: string }> = [
|
|
339
|
-
{ name: "AppProvider", reasonKey: "themeLab.absent.provider" },
|
|
340
|
-
{ name: "OverlayPortalProvider", reasonKey: "themeLab.absent.overlayPortal" },
|
|
341
|
-
{ name: "ThemeScope", reasonKey: "themeLab.absent.themeScope" },
|
|
342
|
-
{ name: "AuthShell", reasonKey: "themeLab.absent.ownsPage" },
|
|
343
|
-
{ name: "CenteredShell", reasonKey: "themeLab.absent.ownsPage" },
|
|
344
|
-
{ name: "MobileShell", reasonKey: "themeLab.absent.ownsPage" },
|
|
345
|
-
{ name: "LegalDocumentShell", reasonKey: "themeLab.absent.ownsPage" },
|
|
346
|
-
{ name: "useZodForm", reasonKey: "themeLab.absent.needsSchema" },
|
|
347
|
-
{ name: "FormRoot", reasonKey: "themeLab.absent.needsSchema" },
|
|
348
|
-
{ name: "FormFieldControl", reasonKey: "themeLab.absent.needsSchema" },
|
|
349
|
-
{ name: "FormFieldArray", reasonKey: "themeLab.absent.needsSchema" },
|
|
350
|
-
{ name: "AlertDialogRoot", reasonKey: "themeLab.absent.sameSurface" },
|
|
351
|
-
{ name: "useFormAdapter", reasonKey: "themeLab.absent.hook" },
|
|
352
|
-
{ name: "useCarousel", reasonKey: "themeLab.absent.hook" },
|
|
353
|
-
{ name: "usePasswordStrength", reasonKey: "themeLab.absent.hook" },
|
|
354
|
-
{ name: "useUploadDraft", reasonKey: "themeLab.absent.hook" },
|
|
355
|
-
{ name: "formatDate", reasonKey: "themeLab.absent.function" },
|
|
356
|
-
{ name: "flexRender", reasonKey: "themeLab.absent.function" },
|
|
357
|
-
{ name: "buttonVariants", reasonKey: "themeLab.absent.function" },
|
|
358
|
-
{ name: "collectUploadCommitActions", reasonKey: "themeLab.absent.function" },
|
|
359
|
-
{ name: "createSidebarLink", reasonKey: "themeLab.absent.function" },
|
|
360
|
-
{ name: "inertiaUpload", reasonKey: "themeLab.absent.inertia" },
|
|
361
|
-
{ name: "UploadCropDialog", reasonKey: "themeLab.absent.needsFile" },
|
|
362
|
-
{ name: "AvatarImage", reasonKey: "themeLab.absent.needsNetwork" },
|
|
363
|
-
{ name: "PrefetchLink", reasonKey: "themeLab.absent.needsRouter" },
|
|
364
|
-
{ name: "DataState", reasonKey: "themeLab.absent.needsQuery" },
|
|
365
|
-
{ name: "InfiniteQueryState", reasonKey: "themeLab.absent.needsQuery" },
|
|
366
|
-
{ name: "AlertQueryError", reasonKey: "themeLab.absent.needsQuery" },
|
|
367
|
-
{ name: "ButtonRefetch", reasonKey: "themeLab.absent.needsQuery" },
|
|
368
|
-
{ name: "VisuallyHidden", reasonKey: "themeLab.absent.invisible" },
|
|
369
|
-
];
|
|
370
|
-
|
|
371
|
-
const UNBREAKABLE = "Betriebsstaettengewinnabgrenzungsaufzeichnungsverordnung-2026-A";
|
|
372
|
-
|
|
373
|
-
type Row = {
|
|
374
|
-
id: string;
|
|
375
|
-
nameKey: string;
|
|
376
|
-
ownerKey: string;
|
|
377
|
-
tone: "success" | "warning" | "destructive";
|
|
378
|
-
};
|
|
379
|
-
|
|
380
|
-
const ROWS: Row[] = [
|
|
381
|
-
{ id: "r1", nameKey: "alpha", ownerKey: "one", tone: "success" },
|
|
382
|
-
{ id: "r2", nameKey: "beta", ownerKey: "two", tone: "warning" },
|
|
383
|
-
{ id: "r3", nameKey: "gamma", ownerKey: "three", tone: "destructive" },
|
|
384
|
-
];
|
|
385
|
-
|
|
386
|
-
const TREND = [
|
|
387
|
-
{ date: "2026-09-16", count: 4 },
|
|
388
|
-
{ date: "2026-09-17", count: 9 },
|
|
389
|
-
{ date: "2026-09-18", count: 6 },
|
|
390
|
-
{ date: "2026-09-19", count: 12 },
|
|
391
|
-
{ date: "2026-09-20", count: 8 },
|
|
392
|
-
{ date: "2026-09-21", count: 15 },
|
|
393
|
-
{ date: "2026-09-22", count: 11 },
|
|
394
|
-
];
|
|
395
|
-
|
|
396
|
-
const SERIES = [
|
|
397
|
-
{ month: "2026-04", plan: 120, actual: 98 },
|
|
398
|
-
{ month: "2026-05", plan: 130, actual: 141 },
|
|
399
|
-
{ month: "2026-06", plan: 128, actual: 119 },
|
|
400
|
-
{ month: "2026-07", plan: 150, actual: 162 },
|
|
401
|
-
];
|
|
402
|
-
|
|
403
|
-
/** A titled block. Local composition, not a component: it owns no behaviour a Card does not. */
|
|
404
|
-
function Section({
|
|
405
|
-
id,
|
|
406
|
-
title,
|
|
407
|
-
note,
|
|
408
|
-
children,
|
|
409
|
-
}: {
|
|
410
|
-
id: string;
|
|
411
|
-
title: string;
|
|
412
|
-
note?: string;
|
|
413
|
-
children: React.ReactNode;
|
|
414
|
-
}) {
|
|
415
|
-
return (
|
|
416
|
-
<Card id={id}>
|
|
417
|
-
<CardHeader>
|
|
418
|
-
<CardTitle level={2}>{title}</CardTitle>
|
|
419
|
-
{note ? <CardDescription>{note}</CardDescription> : null}
|
|
420
|
-
</CardHeader>
|
|
421
|
-
<CardContent>
|
|
422
|
-
<Flex direction="col" gap="lg">
|
|
423
|
-
{children}
|
|
424
|
-
</Flex>
|
|
425
|
-
</CardContent>
|
|
426
|
-
</Card>
|
|
427
|
-
);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/** A labelled row of specimens. */
|
|
431
|
-
function Row2({ label, children }: { label: string; children: React.ReactNode }) {
|
|
432
|
-
return (
|
|
433
|
-
<Flex direction="col" gap="xs">
|
|
434
|
-
<Text size="xs" tone="muted">
|
|
435
|
-
{label}
|
|
436
|
-
</Text>
|
|
437
|
-
<Flex direction="row" gap="sm" wrap align="center">
|
|
438
|
-
{children}
|
|
439
|
-
</Flex>
|
|
440
|
-
</Flex>
|
|
441
|
-
);
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
export default function ThemeLabShowcase() {
|
|
445
|
-
const { t } = useTranslation();
|
|
446
|
-
|
|
447
|
-
const initial = React.useMemo(() => {
|
|
448
|
-
const params = new URLSearchParams(typeof window === "undefined" ? "" : window.location.search);
|
|
449
|
-
return {
|
|
450
|
-
theme: themeFromQuery(params.get("theme")),
|
|
451
|
-
seed: seedFromQuery(params.get("seed")),
|
|
452
|
-
mode: modeFromQuery(params.get("mode")),
|
|
453
|
-
};
|
|
454
|
-
}, []);
|
|
455
|
-
|
|
456
|
-
// The bounded scroller Affix and Anchor pin against — see the note at their call site.
|
|
457
|
-
const affixScrollerRef = React.useRef<HTMLDivElement>(null);
|
|
458
|
-
const [theme, setTheme] = React.useState<ThemeRow>(initial.theme);
|
|
459
|
-
const [seed, setSeed] = React.useState<SeedRow>(initial.seed);
|
|
460
|
-
const [mode, setMode] = React.useState<ModeRow>(initial.mode);
|
|
461
|
-
|
|
462
|
-
/*
|
|
463
|
-
* The URL is the page's own state, so a measurement or a screenshot can address one cell of the
|
|
464
|
-
* matrix directly. `replaceState` rather than `pushState`: flipping a switch is not navigation,
|
|
465
|
-
* and a back button that walks a colour history is the kind of cleverness nobody asked for.
|
|
466
|
-
*/
|
|
467
|
-
React.useEffect(() => {
|
|
468
|
-
if (typeof window === "undefined") return;
|
|
469
|
-
const params = new URLSearchParams(window.location.search);
|
|
470
|
-
params.set("theme", themeQueryValue(theme));
|
|
471
|
-
params.set("seed", seed.id);
|
|
472
|
-
params.set("mode", mode.id);
|
|
473
|
-
window.history.replaceState(null, "", `${window.location.pathname}?${params.toString()}`);
|
|
474
|
-
}, [theme, seed, mode]);
|
|
475
|
-
|
|
476
|
-
/*
|
|
477
|
-
* Polarity, applied THE WAY THE LIBRARY ITSELF APPLIES IT: through `AppProvider`'s own `theme`
|
|
478
|
-
* axis (`src/app/theme-axes.ts`'s `applyThemeAxes`, which is what `AppProvider` calls on
|
|
479
|
-
* `<html data-theme>`), never by writing `document.documentElement` from this page. Going
|
|
480
|
-
* through `ctx.setTheme` — the exact setter `AppSettingToggle kind="theme"` already uses above —
|
|
481
|
-
* sets `AppProvider`'s OWN state, so ITS OWN effect is what reaches the DOM; this page never
|
|
482
|
-
* touches `document.documentElement` for polarity.
|
|
483
|
-
*
|
|
484
|
-
* `mounted`, not a plain effect on `[mode.id]` — MEASURED, not assumed. `AppProvider` re-derives
|
|
485
|
-
* `theme` from `persist`/storage on ITS OWN mount effect (`app-provider.tsx`'s "hydrate stored
|
|
486
|
-
* preferences" effect), unconditionally, from `initialTheme` when nothing is stored — and the
|
|
487
|
-
* preview harness resolves `?theme=` (base/glass/flat here) as a SEPARATE polarity switch, so
|
|
488
|
-
* that initial value is always "light" on this page. Calling `ctx.setTheme("dark")` from a plain
|
|
489
|
-
* mount effect here was overwritten a moment later: React commits a descendant's passive effects
|
|
490
|
-
* before its ancestor's, so `AppProvider`'s own hydration effect always runs AFTER this page's —
|
|
491
|
-
* confirmed with a `MutationObserver` on `data-theme`, which recorded ZERO mutations and settled
|
|
492
|
-
* on "light" for `?mode=dark`. Deferring our own call by one render pass (`setMounted(true)` in
|
|
493
|
-
* an effect, then applying `mode` only once `mounted`) pushes it into a SECOND commit, which
|
|
494
|
-
* starts only after the FIRST commit's entire effect list — `AppProvider`'s hydration effect
|
|
495
|
-
* included — has already run and settled; reconfirmed with the same observer, now showing
|
|
496
|
-
* `data-theme` reaching "dark" reliably.
|
|
497
|
-
*
|
|
498
|
-
* `ctx` is read via a ref kept fresh every render, and the apply effect depends only on
|
|
499
|
-
* `[mounted, mode.id]`, so it does not re-fire every time some OTHER axis (locale, density, …)
|
|
500
|
-
* changes the context's identity — only once mounted, and again when this switch changes. The
|
|
501
|
-
* cleanup restores whatever the axis was immediately before this effect's own change, so leaving
|
|
502
|
-
* the page (or flipping the switch back) does not leak a forced polarity into the rest of the
|
|
503
|
-
* showcase.
|
|
504
|
-
*/
|
|
505
|
-
const appContext = useOptionalAppContext();
|
|
506
|
-
const appContextRef = React.useRef(appContext);
|
|
507
|
-
appContextRef.current = appContext;
|
|
508
|
-
const [mounted, setMounted] = React.useState(false);
|
|
509
|
-
React.useEffect(() => setMounted(true), []);
|
|
510
|
-
React.useEffect(() => {
|
|
511
|
-
if (!mounted) return;
|
|
512
|
-
const ctx = appContextRef.current;
|
|
513
|
-
if (!ctx) return;
|
|
514
|
-
const previous = ctx.theme;
|
|
515
|
-
ctx.setTheme(mode.id);
|
|
516
|
-
return () => {
|
|
517
|
-
ctx.setTheme(previous);
|
|
518
|
-
};
|
|
519
|
-
}, [mounted, mode.id]);
|
|
520
|
-
|
|
521
|
-
/* The seed is walked against THIS THEME's surface for THIS POLARITY, not the package's (see
|
|
522
|
-
* `inkSurface`). A theme declares its own `--text-link`, but `tenantTheme` returns the brand
|
|
523
|
-
* inks as literals in `style`, and an inline literal outranks any selector — so the theme's
|
|
524
|
-
* declaration is only reachable if the value handed to it was computed on the right ground. */
|
|
525
|
-
const brand = React.useMemo(
|
|
526
|
-
() => tenantTheme(seed.hex, { surface: theme.inkSurface[mode.id] }),
|
|
527
|
-
[seed.hex, theme.inkSurface, mode.id],
|
|
528
|
-
);
|
|
529
|
-
|
|
530
|
-
const [dialogOpen, setDialogOpen] = React.useState(false);
|
|
531
|
-
const [sheetOpen, setSheetOpen] = React.useState(false);
|
|
532
|
-
const [alertOpen, setAlertOpen] = React.useState(false);
|
|
533
|
-
const [twoFactorOpen, setTwoFactorOpen] = React.useState(false);
|
|
534
|
-
const [role, setRole] = React.useState("viewer");
|
|
535
|
-
const [checked, setChecked] = React.useState(true);
|
|
536
|
-
const [switched, setSwitched] = React.useState(true);
|
|
537
|
-
const [volume, setVolume] = React.useState(64);
|
|
538
|
-
const [colour, setColour] = React.useState("#2563EB");
|
|
539
|
-
const [tags, setTags] = React.useState<string[]>(["a11y", "rtl"]);
|
|
540
|
-
const [password, setPassword] = React.useState("Glass-2026!");
|
|
541
|
-
const [query, setQuery] = React.useState("");
|
|
542
|
-
const [page, setPage] = React.useState(1);
|
|
543
|
-
const [step] = React.useState(1);
|
|
544
|
-
const [date, setDate] = React.useState<Date | undefined>(new Date(2026, 8, 23));
|
|
545
|
-
const [time, setTime] = React.useState("09:30");
|
|
546
|
-
const [uploads, setUploads] = React.useState<UploadFileItem[]>([]);
|
|
547
|
-
const [draft, setDraft] = React.useState("");
|
|
548
|
-
const [otp, setOtp] = React.useState("");
|
|
549
|
-
const [conversation, setConversation] = React.useState("c1");
|
|
550
|
-
const [route, setRoute] = React.useState("products");
|
|
551
|
-
const [org, setOrg] = React.useState("dxs");
|
|
552
|
-
const [panelPosition, setPanelPosition] = React.useState({ x: 0, y: 0 });
|
|
553
|
-
const [treeChecked, setTreeChecked] = React.useState<string[]>(["billing.read"]);
|
|
554
|
-
const [transferred, setTransferred] = React.useState<string[]>(["1010"]);
|
|
555
|
-
const [cascade, setCascade] = React.useState<string[]>([]);
|
|
556
|
-
const [account, setAccount] = React.useState<string | undefined>(undefined);
|
|
557
|
-
const [selectedRole, setSelectedRole] = React.useState("admin");
|
|
558
|
-
const [scope, setScope] = React.useState<{
|
|
559
|
-
mode: "all" | "selected";
|
|
560
|
-
branchIds?: readonly string[];
|
|
561
|
-
}>({ mode: "selected", branchIds: ["b1"] });
|
|
562
|
-
|
|
563
|
-
const toneLabel = React.useCallback((tone: Row["tone"]) => t(`themeLab.tone.${tone}`), [t]);
|
|
564
|
-
|
|
565
|
-
const columns: ColumnDef<Row>[] = [
|
|
566
|
-
{
|
|
567
|
-
key: "nameKey",
|
|
568
|
-
header: t("themeLab.table.name"),
|
|
569
|
-
render: (row) => <Text as="span">{t(`themeLab.sample.${row.nameKey}`)}</Text>,
|
|
570
|
-
},
|
|
571
|
-
{
|
|
572
|
-
key: "ownerKey",
|
|
573
|
-
header: t("themeLab.table.owner"),
|
|
574
|
-
hiddenOnMobile: true,
|
|
575
|
-
render: (row) => <Text as="span">{t(`themeLab.sample.${row.ownerKey}`)}</Text>,
|
|
576
|
-
},
|
|
577
|
-
{
|
|
578
|
-
key: "tone",
|
|
579
|
-
header: t("themeLab.table.status"),
|
|
580
|
-
align: "right",
|
|
581
|
-
render: (row) => <Badge tone={row.tone}>{toneLabel(row.tone)}</Badge>,
|
|
582
|
-
},
|
|
583
|
-
];
|
|
584
|
-
|
|
585
|
-
const chat: ChatMessageProp[] = [
|
|
586
|
-
{ id: "m1", role: "assistant", content: t("themeLab.chat.assistant") },
|
|
587
|
-
{ id: "m2", role: "user", content: t("themeLab.chat.user") },
|
|
588
|
-
];
|
|
589
|
-
|
|
590
|
-
const sidebar = (
|
|
591
|
-
<Sidebar
|
|
592
|
-
activeId="overview"
|
|
593
|
-
onSelect={() => {}}
|
|
594
|
-
sections={[
|
|
595
|
-
{
|
|
596
|
-
label: t("themeLab.nav.section"),
|
|
597
|
-
items: [
|
|
598
|
-
{ id: "overview", label: t("themeLab.nav.overview"), icon: LayoutGrid },
|
|
599
|
-
{ id: "reports", label: t("themeLab.nav.reports"), icon: BarChart3 },
|
|
600
|
-
{ id: "people", label: t("themeLab.nav.people"), icon: Users },
|
|
601
|
-
{ id: "settings", label: t("themeLab.nav.settings"), icon: Settings },
|
|
602
|
-
],
|
|
603
|
-
},
|
|
604
|
-
]}
|
|
605
|
-
product={{ name: t("themeLab.product"), role: t("themeLab.nav.role") }}
|
|
606
|
-
footer={
|
|
607
|
-
<Text size="xs" tone="muted">
|
|
608
|
-
{t("themeLab.nav.footer")}
|
|
609
|
-
</Text>
|
|
610
|
-
}
|
|
611
|
-
/>
|
|
612
|
-
);
|
|
613
|
-
|
|
614
|
-
const topbar = (
|
|
615
|
-
<Topbar
|
|
616
|
-
start={
|
|
617
|
-
<>
|
|
618
|
-
{/* `Logo`, not `TopbarItem asChild` + `Text`: `Text` does not forward a ref to a DOM
|
|
619
|
-
node, and the bar's `Focusable` wrapper warned about exactly that at runtime. The
|
|
620
|
-
brand cell is a lockup, not a control, so `Logo` is also the right component. */}
|
|
621
|
-
<Logo glyph="g" wordmark={t("themeLab.product")} />
|
|
622
|
-
<AppLauncher
|
|
623
|
-
apps={[
|
|
624
|
-
{
|
|
625
|
-
id: "console",
|
|
626
|
-
name: t("themeLab.app.console"),
|
|
627
|
-
href: "#console",
|
|
628
|
-
icon: <BarChart3 aria-hidden="true" />,
|
|
629
|
-
current: true,
|
|
630
|
-
},
|
|
631
|
-
{
|
|
632
|
-
id: "billing",
|
|
633
|
-
name: t("themeLab.app.billing"),
|
|
634
|
-
href: "#billing",
|
|
635
|
-
icon: <CreditCard aria-hidden="true" />,
|
|
636
|
-
},
|
|
637
|
-
]}
|
|
638
|
-
labels={{
|
|
639
|
-
trigger: t("themeLab.launcher.trigger"),
|
|
640
|
-
title: t("themeLab.launcher.title"),
|
|
641
|
-
empty: t("themeLab.label.noResults"),
|
|
642
|
-
loading: t("themeLab.label.loading"),
|
|
643
|
-
}}
|
|
644
|
-
/>
|
|
645
|
-
</>
|
|
646
|
-
}
|
|
647
|
-
end={
|
|
648
|
-
<Flex direction="row" gap="sm" align="center">
|
|
649
|
-
<AppSettingPicker kind="locale" appearance="bar" />
|
|
650
|
-
<AppSettingToggle kind="theme" />
|
|
651
|
-
<Popover>
|
|
652
|
-
<PopoverTrigger asChild>
|
|
653
|
-
<TopbarItem
|
|
654
|
-
data-probe="popover"
|
|
655
|
-
icon={<Bell aria-hidden="true" />}
|
|
656
|
-
aria-label={t("themeLab.topbar.notifications")}
|
|
657
|
-
/>
|
|
658
|
-
</PopoverTrigger>
|
|
659
|
-
<PopoverContent align="end">
|
|
660
|
-
<PopoverHeader>
|
|
661
|
-
<PopoverTitle>{t("themeLab.popover.title")}</PopoverTitle>
|
|
662
|
-
<PopoverDescription>{t("themeLab.popover.body")}</PopoverDescription>
|
|
663
|
-
</PopoverHeader>
|
|
664
|
-
<Button size="sm" variant="outline">
|
|
665
|
-
<Check aria-hidden="true" />
|
|
666
|
-
{t("themeLab.popover.action")}
|
|
667
|
-
</Button>
|
|
668
|
-
</PopoverContent>
|
|
669
|
-
</Popover>
|
|
670
|
-
<DropdownMenu>
|
|
671
|
-
<DropdownMenuTrigger asChild>
|
|
672
|
-
<TopbarItem
|
|
673
|
-
data-probe="dropdown"
|
|
674
|
-
aria-label={t("themeLab.topbar.account")}
|
|
675
|
-
icon={
|
|
676
|
-
<Avatar>
|
|
677
|
-
<AvatarFallback>DP</AvatarFallback>
|
|
678
|
-
</Avatar>
|
|
679
|
-
}
|
|
680
|
-
/>
|
|
681
|
-
</DropdownMenuTrigger>
|
|
682
|
-
<DropdownMenuContent align="end">
|
|
683
|
-
<DropdownMenuLabel>{t("themeLab.product")}</DropdownMenuLabel>
|
|
684
|
-
<DropdownMenuSeparator />
|
|
685
|
-
<DropdownMenuItem>{t("themeLab.menu.profile")}</DropdownMenuItem>
|
|
686
|
-
<DropdownMenuItem>{t("themeLab.menu.billing")}</DropdownMenuItem>
|
|
687
|
-
<DropdownMenuSeparator />
|
|
688
|
-
<DropdownMenuItem>
|
|
689
|
-
<LogOut aria-hidden="true" />
|
|
690
|
-
{t("themeLab.menu.logout")}
|
|
691
|
-
</DropdownMenuItem>
|
|
692
|
-
</DropdownMenuContent>
|
|
693
|
-
</DropdownMenu>
|
|
694
|
-
</Flex>
|
|
695
|
-
}
|
|
696
|
-
/>
|
|
697
|
-
);
|
|
698
|
-
|
|
699
|
-
return (
|
|
700
|
-
/*
|
|
701
|
-
* The attribute is ALWAYS written, "base" included. `docs/themes/` has no `base.css`, so
|
|
702
|
-
* `[data-theme-style="base"]` matches no rule and the region keeps the library's own theme —
|
|
703
|
-
* but the scope stays ADDRESSABLE, and that is not cosmetic: `measure-glass.mjs` scopes its
|
|
704
|
-
* contrast walk to `[data-theme-style]`, and with the attribute omitted the default theme
|
|
705
|
-
* measured 22 strings instead of 530 while reporting a clean sweep.
|
|
706
|
-
*/
|
|
707
|
-
<ThemeScope data-theme-style={themeQueryValue(theme)} style={brand.vars}>
|
|
708
|
-
<AppShell sidebar={sidebar} topbar={topbar}>
|
|
709
|
-
<PageContainer
|
|
710
|
-
title={t("themeLab.page.title")}
|
|
711
|
-
subtitle={t("themeLab.page.subtitle")}
|
|
712
|
-
breadcrumb={[
|
|
713
|
-
{ label: t("themeLab.nav.overview"), to: "#overview" },
|
|
714
|
-
{ label: t("themeLab.page.title") },
|
|
715
|
-
]}
|
|
716
|
-
extra={
|
|
717
|
-
<AccountChip
|
|
718
|
-
name={t("themeLab.sample.one")}
|
|
719
|
-
email="duong@example.test"
|
|
720
|
-
actionLabel={t("themeLab.menu.logout")}
|
|
721
|
-
onAction={() => {}}
|
|
722
|
-
/>
|
|
723
|
-
}
|
|
724
|
-
>
|
|
725
|
-
<Flex direction="col" gap="lg">
|
|
726
|
-
{/* ── 1 · the switches themselves ───────────────────────────────────────────── */}
|
|
727
|
-
<Card accent="primary">
|
|
728
|
-
<CardHeader>
|
|
729
|
-
<CardTitle level={2}>{t("themeLab.switch.title")}</CardTitle>
|
|
730
|
-
<CardDescription>{t("themeLab.switch.note")}</CardDescription>
|
|
731
|
-
<CardAction>
|
|
732
|
-
<Legend
|
|
733
|
-
items={[
|
|
734
|
-
{ tone: "success", label: t("themeLab.switch.legendPass") },
|
|
735
|
-
{ tone: "destructive", label: t("themeLab.switch.legendFail") },
|
|
736
|
-
]}
|
|
737
|
-
/>
|
|
738
|
-
</CardAction>
|
|
739
|
-
</CardHeader>
|
|
740
|
-
<CardContent>
|
|
741
|
-
<Flex direction="col" gap="md">
|
|
742
|
-
<Field id="theme-switch" label={t("themeLab.switch.themeLabel")}>
|
|
743
|
-
<Segmented
|
|
744
|
-
id="theme-switch"
|
|
745
|
-
aria-label={t("themeLab.switch.themeLabel")}
|
|
746
|
-
value={themeQueryValue(theme)}
|
|
747
|
-
onValueChange={(next) => setTheme(themeFromQuery(next))}
|
|
748
|
-
options={THEMES.map((row) => ({
|
|
749
|
-
value: themeQueryValue(row),
|
|
750
|
-
label: t(row.nameKey),
|
|
751
|
-
}))}
|
|
752
|
-
/>
|
|
753
|
-
</Field>
|
|
754
|
-
<Text size="sm" tone="muted">
|
|
755
|
-
{t(theme.noteKey)}
|
|
756
|
-
</Text>
|
|
757
|
-
<Field id="seed-switch" label={t("themeLab.switch.seedLabel")}>
|
|
758
|
-
<Segmented
|
|
759
|
-
id="seed-switch"
|
|
760
|
-
aria-label={t("themeLab.switch.seedLabel")}
|
|
761
|
-
value={seed.id}
|
|
762
|
-
onValueChange={(next) => setSeed(seedFromQuery(next))}
|
|
763
|
-
options={SEEDS.map((row) => ({
|
|
764
|
-
value: row.id,
|
|
765
|
-
label: t(row.nameKey),
|
|
766
|
-
}))}
|
|
767
|
-
/>
|
|
768
|
-
</Field>
|
|
769
|
-
<Field id="mode-switch" label={t("themeLab.switch.modeLabel")}>
|
|
770
|
-
<Segmented
|
|
771
|
-
id="mode-switch"
|
|
772
|
-
aria-label={t("themeLab.switch.modeLabel")}
|
|
773
|
-
value={mode.id}
|
|
774
|
-
onValueChange={(next) => setMode(modeFromQuery(next))}
|
|
775
|
-
options={MODES.map((row) => ({
|
|
776
|
-
value: row.id,
|
|
777
|
-
label: t(row.nameKey),
|
|
778
|
-
}))}
|
|
779
|
-
/>
|
|
780
|
-
</Field>
|
|
781
|
-
<Flex direction="row" gap="sm" wrap align="center">
|
|
782
|
-
{SEEDS.map((row) => (
|
|
783
|
-
<Swatch
|
|
784
|
-
key={row.id}
|
|
785
|
-
color={row.hex}
|
|
786
|
-
aria-label={`${t(row.nameKey)} ${row.hex}`}
|
|
787
|
-
/>
|
|
788
|
-
))}
|
|
789
|
-
</Flex>
|
|
790
|
-
<Descriptions columns={2}>
|
|
791
|
-
<Descriptions.Item label={t("themeLab.switch.seedHex")} mono>
|
|
792
|
-
{brand.primary ?? "—"}
|
|
793
|
-
</Descriptions.Item>
|
|
794
|
-
<Descriptions.Item label={t("themeLab.switch.seedInk")} mono>
|
|
795
|
-
{brand.foreground ?? "—"}
|
|
796
|
-
</Descriptions.Item>
|
|
797
|
-
<Descriptions.Item label={t("themeLab.switch.seedContrast")} span={2}>
|
|
798
|
-
<Badge tone={brand.meetsAA ? "success" : "destructive"}>
|
|
799
|
-
{brand.contrast.toFixed(2)}:1
|
|
800
|
-
</Badge>
|
|
801
|
-
</Descriptions.Item>
|
|
802
|
-
</Descriptions>
|
|
803
|
-
</Flex>
|
|
804
|
-
</CardContent>
|
|
805
|
-
</Card>
|
|
806
|
-
|
|
807
|
-
{/* ── 2 · type ─────────────────────────────────────────────────────────────── */}
|
|
808
|
-
<Section
|
|
809
|
-
id="type"
|
|
810
|
-
title={t("themeLab.section.type")}
|
|
811
|
-
note={t("themeLab.section.typeNote")}
|
|
812
|
-
>
|
|
813
|
-
<Flex direction="col" gap="sm">
|
|
814
|
-
<Heading level={3}>{t("themeLab.sample.headline")}</Heading>
|
|
815
|
-
<Title level={4}>{t("themeLab.sample.alpha")}</Title>
|
|
816
|
-
<Paragraph>{t("themeLab.sample.long")}</Paragraph>
|
|
817
|
-
<Text size="sm" tone="muted">
|
|
818
|
-
{t("themeLab.sample.short")}
|
|
819
|
-
</Text>
|
|
820
|
-
<Text size="xs" mono tone="muted">
|
|
821
|
-
{UNBREAKABLE}
|
|
822
|
-
</Text>
|
|
823
|
-
<Text weight="medium" tabular>
|
|
824
|
-
{new Intl.NumberFormat(undefined, { notation: "standard" }).format(1240000)}
|
|
825
|
-
</Text>
|
|
826
|
-
<Link href="#type">{t("themeLab.sample.linkLabel")}</Link>
|
|
827
|
-
<Typography>
|
|
828
|
-
<Typography.Title level={5}>{t("themeLab.sample.beta")}</Typography.Title>
|
|
829
|
-
<Typography.Paragraph>{t("themeLab.sample.short")}</Typography.Paragraph>
|
|
830
|
-
</Typography>
|
|
831
|
-
<Prose size="sm">
|
|
832
|
-
<Typography.Paragraph>{t("themeLab.sample.long")}</Typography.Paragraph>
|
|
833
|
-
</Prose>
|
|
834
|
-
<CodeBlock size="xs" maxHeight="sm" aria-label={t("themeLab.sample.codeLabel")}>
|
|
835
|
-
{`[data-theme-style="flat"] {\n --card-radius: 0;\n}`}
|
|
836
|
-
</CodeBlock>
|
|
837
|
-
<Flex direction="row" gap="sm" align="center" wrap>
|
|
838
|
-
<Logo glyph="g" wordmark={t("themeLab.product")} />
|
|
839
|
-
<Icon as={Shield} size="md" tone="success" label={t("themeLab.sample.secure")} />
|
|
840
|
-
<Icon as={Clock} size="sm" tone="muted" />
|
|
841
|
-
<Activity label={t("themeLab.sample.syncing")} />
|
|
842
|
-
<Activity variant="bar" tone="info" label={t("themeLab.sample.syncing")} />
|
|
843
|
-
</Flex>
|
|
844
|
-
<Separator label={t("themeLab.sample.short")} labelAlign="start" />
|
|
845
|
-
<Marquee fade pauseOnHover label={t("themeLab.sample.marqueeLabel")}>
|
|
846
|
-
{["alpha", "beta", "gamma", "delta", "epsilon"].map((key) => (
|
|
847
|
-
<Text key={key} size="sm" tone="muted">
|
|
848
|
-
{t(`themeLab.sample.${key}`)}
|
|
849
|
-
</Text>
|
|
850
|
-
))}
|
|
851
|
-
</Marquee>
|
|
852
|
-
<AspectRatio ratio={16 / 5}>
|
|
853
|
-
<EmptyState
|
|
854
|
-
title={t("themeLab.sample.aspectTitle")}
|
|
855
|
-
description={t("themeLab.sample.short")}
|
|
856
|
-
/>
|
|
857
|
-
</AspectRatio>
|
|
858
|
-
<VisuallyHidden>{t("themeLab.sample.short")}</VisuallyHidden>
|
|
859
|
-
</Flex>
|
|
860
|
-
</Section>
|
|
861
|
-
|
|
862
|
-
{/* ── 3 · actions ──────────────────────────────────────────────────────────── */}
|
|
863
|
-
<Section id="actions" title={t("themeLab.section.actions")}>
|
|
864
|
-
<Row2 label={t("themeLab.label.variants")}>
|
|
865
|
-
<Button>{t("themeLab.action.save")}</Button>
|
|
866
|
-
<Button variant="secondary">{t("themeLab.action.secondary")}</Button>
|
|
867
|
-
<Button variant="outline">{t("themeLab.action.outline")}</Button>
|
|
868
|
-
<Button variant="ghost">{t("themeLab.action.ghost")}</Button>
|
|
869
|
-
<Button variant="dashed">{t("themeLab.action.dashed")}</Button>
|
|
870
|
-
<Button variant="destructive">{t("themeLab.action.destructive")}</Button>
|
|
871
|
-
<Button variant="link">{t("themeLab.action.link")}</Button>
|
|
872
|
-
<Button disabled>{t("themeLab.action.disabled")}</Button>
|
|
873
|
-
</Row2>
|
|
874
|
-
<Row2 label={t("themeLab.label.sizes")}>
|
|
875
|
-
<Button size="xs">xs</Button>
|
|
876
|
-
<Button size="sm">sm</Button>
|
|
877
|
-
<Button size="md">md</Button>
|
|
878
|
-
<Button size="lg">lg</Button>
|
|
879
|
-
<Button size="icon" aria-label={t("themeLab.action.search")}>
|
|
880
|
-
<Search aria-hidden="true" />
|
|
881
|
-
</Button>
|
|
882
|
-
</Row2>
|
|
883
|
-
<Row2 label={t("themeLab.label.toggles")}>
|
|
884
|
-
<Toggle aria-label={t("themeLab.action.bold")}>B</Toggle>
|
|
885
|
-
<Toggle
|
|
886
|
-
variant="soft"
|
|
887
|
-
shape="pill"
|
|
888
|
-
count={12}
|
|
889
|
-
countLabel={t("themeLab.label.items")}
|
|
890
|
-
>
|
|
891
|
-
{t("themeLab.action.unread")}
|
|
892
|
-
</Toggle>
|
|
893
|
-
<ToggleGroup
|
|
894
|
-
type="single"
|
|
895
|
-
defaultValue="left"
|
|
896
|
-
aria-label={t("themeLab.label.align")}
|
|
897
|
-
>
|
|
898
|
-
<ToggleGroupItem value="left">{t("themeLab.align.start")}</ToggleGroupItem>
|
|
899
|
-
<ToggleGroupItem value="center">{t("themeLab.align.center")}</ToggleGroupItem>
|
|
900
|
-
<ToggleGroupItem value="right">{t("themeLab.align.end")}</ToggleGroupItem>
|
|
901
|
-
</ToggleGroup>
|
|
902
|
-
<Rating name="score" aria-label={t("themeLab.label.rating")} defaultValue={4} />
|
|
903
|
-
</Row2>
|
|
904
|
-
<Row2 label={t("themeLab.label.actionsBar")}>
|
|
905
|
-
<Actions
|
|
906
|
-
label={t("themeLab.label.actionsBar")}
|
|
907
|
-
items={[
|
|
908
|
-
{ key: "retry", label: t("themeLab.action.retry"), icon: <RefreshCw /> },
|
|
909
|
-
{
|
|
910
|
-
key: "more",
|
|
911
|
-
label: t("themeLab.action.more"),
|
|
912
|
-
subItems: [
|
|
913
|
-
{ key: "share", label: t("themeLab.action.share"), icon: <Share2 /> },
|
|
914
|
-
],
|
|
915
|
-
},
|
|
916
|
-
{ key: "copy", actionRender: <ActionsCopy text={UNBREAKABLE} /> },
|
|
917
|
-
{ key: "feedback", actionRender: <ActionsFeedback /> },
|
|
918
|
-
]}
|
|
919
|
-
/>
|
|
920
|
-
</Row2>
|
|
921
|
-
</Section>
|
|
922
|
-
|
|
923
|
-
{/* ── 4 · status and data display ──────────────────────────────────────────── */}
|
|
924
|
-
<Section id="display" title={t("themeLab.section.display")}>
|
|
925
|
-
<Row2 label={t("themeLab.label.badges")}>
|
|
926
|
-
<Badge>{t("themeLab.tone.neutral")}</Badge>
|
|
927
|
-
<Badge tone="success">{t("themeLab.tone.success")}</Badge>
|
|
928
|
-
<Badge tone="warning">{t("themeLab.tone.warning")}</Badge>
|
|
929
|
-
<Badge tone="destructive">{t("themeLab.tone.destructive")}</Badge>
|
|
930
|
-
<Badge tone="info">{t("themeLab.tone.info")}</Badge>
|
|
931
|
-
<Badge variant="secondary">{t("themeLab.tone.neutral")}</Badge>
|
|
932
|
-
<StatusBadge status="active">{t("themeLab.tone.success")}</StatusBadge>
|
|
933
|
-
<Swatch color={seed.hex} aria-label={t(seed.nameKey)} />
|
|
934
|
-
</Row2>
|
|
935
|
-
<ResponsiveGrid columns={{ sm: 1, md: 2, lg: 4 }}>
|
|
936
|
-
<StatCard
|
|
937
|
-
label={t("themeLab.stat.members")}
|
|
938
|
-
value="12,450"
|
|
939
|
-
hint={t("themeLab.stat.hint")}
|
|
940
|
-
/>
|
|
941
|
-
<StatCard label={t("themeLab.stat.revenue")} value="8.2M" delta="+12%" />
|
|
942
|
-
<StatCard label={t("themeLab.stat.usage")} value="68.4%" />
|
|
943
|
-
<StatCard label={t("themeLab.stat.open")} value="3" />
|
|
944
|
-
</ResponsiveGrid>
|
|
945
|
-
<Flex direction="col" gap="sm">
|
|
946
|
-
<Progress value={68} label={t("themeLab.label.progress")} />
|
|
947
|
-
<Progress value={92} tone="warning" label={t("themeLab.label.progress")} />
|
|
948
|
-
<Flex direction="row" gap="xs" aria-label={t("themeLab.label.people")}>
|
|
949
|
-
<Avatar>
|
|
950
|
-
<AvatarFallback>MS</AvatarFallback>
|
|
951
|
-
</Avatar>
|
|
952
|
-
<Avatar>
|
|
953
|
-
<AvatarFallback>DC</AvatarFallback>
|
|
954
|
-
</Avatar>
|
|
955
|
-
<Avatar>
|
|
956
|
-
<AvatarFallback>PN</AvatarFallback>
|
|
957
|
-
</Avatar>
|
|
958
|
-
</Flex>
|
|
959
|
-
</Flex>
|
|
960
|
-
<ResponsiveGrid columns={{ sm: 1, md: 2 }}>
|
|
961
|
-
<Card>
|
|
962
|
-
<CardBar border="block-end">{t("themeLab.label.tools")}</CardBar>
|
|
963
|
-
<CardContent flush>
|
|
964
|
-
<ListRow
|
|
965
|
-
leading={<Smartphone aria-hidden="true" />}
|
|
966
|
-
title={t("themeLab.sample.alpha")}
|
|
967
|
-
description={t("themeLab.sample.short")}
|
|
968
|
-
trailing={<Badge tone="success">{t("themeLab.tone.success")}</Badge>}
|
|
969
|
-
/>
|
|
970
|
-
<ListRow
|
|
971
|
-
unread
|
|
972
|
-
overflow="wrap"
|
|
973
|
-
title={t("themeLab.sample.long")}
|
|
974
|
-
description={t("themeLab.sample.short")}
|
|
975
|
-
trailing={
|
|
976
|
-
<Button size="xs" variant="ghost">
|
|
977
|
-
{t("themeLab.action.more")}
|
|
978
|
-
</Button>
|
|
979
|
-
}
|
|
980
|
-
/>
|
|
981
|
-
</CardContent>
|
|
982
|
-
<CardFooter>
|
|
983
|
-
<Text size="xs" tone="muted">
|
|
984
|
-
{t("themeLab.sample.short")}
|
|
985
|
-
</Text>
|
|
986
|
-
</CardFooter>
|
|
987
|
-
</Card>
|
|
988
|
-
<Flex direction="col" gap="md">
|
|
989
|
-
<FeatureList
|
|
990
|
-
items={[
|
|
991
|
-
{ state: "included", label: "SSO", description: t("themeLab.sample.short") },
|
|
992
|
-
{ state: "limited", label: "API", description: t("themeLab.sample.short") },
|
|
993
|
-
{ state: "excluded", label: t("themeLab.sample.gamma") },
|
|
994
|
-
]}
|
|
995
|
-
/>
|
|
996
|
-
<Descriptions columns={2}>
|
|
997
|
-
<Descriptions.Item label={t("themeLab.table.name")} mono>
|
|
998
|
-
{UNBREAKABLE}
|
|
999
|
-
</Descriptions.Item>
|
|
1000
|
-
<Descriptions.Item label={t("themeLab.table.owner")}>
|
|
1001
|
-
{t("themeLab.sample.one")}
|
|
1002
|
-
</Descriptions.Item>
|
|
1003
|
-
<Descriptions.Item label={t("themeLab.table.status")} span={2}>
|
|
1004
|
-
{t("themeLab.sample.long")}
|
|
1005
|
-
</Descriptions.Item>
|
|
1006
|
-
</Descriptions>
|
|
1007
|
-
</Flex>
|
|
1008
|
-
</ResponsiveGrid>
|
|
1009
|
-
<ResponsiveGrid columns={{ sm: 1, md: 2 }}>
|
|
1010
|
-
<Timeline
|
|
1011
|
-
items={[
|
|
1012
|
-
{ title: t("themeLab.sample.alpha"), time: "2026-09-21 10:00" },
|
|
1013
|
-
{ title: t("themeLab.sample.beta"), time: "2026-09-22 14:00" },
|
|
1014
|
-
{ title: t("themeLab.sample.gamma"), current: true },
|
|
1015
|
-
]}
|
|
1016
|
-
/>
|
|
1017
|
-
<RangeTimeline
|
|
1018
|
-
label={t("themeLab.label.schedule")}
|
|
1019
|
-
columns={[{ label: t("themeLab.label.week"), units: 7 }]}
|
|
1020
|
-
rows={[
|
|
1021
|
-
{
|
|
1022
|
-
id: "task",
|
|
1023
|
-
label: t("themeLab.sample.alpha"),
|
|
1024
|
-
start: 0,
|
|
1025
|
-
end: 4,
|
|
1026
|
-
startLabel: t("themeLab.label.start"),
|
|
1027
|
-
endLabel: t("themeLab.label.end"),
|
|
1028
|
-
},
|
|
1029
|
-
]}
|
|
1030
|
-
/>
|
|
1031
|
-
</ResponsiveGrid>
|
|
1032
|
-
<TimelineGrid
|
|
1033
|
-
label={t("themeLab.label.schedule")}
|
|
1034
|
-
start="08:00"
|
|
1035
|
-
end="20:00"
|
|
1036
|
-
interval={2}
|
|
1037
|
-
now="14:35"
|
|
1038
|
-
columns={[
|
|
1039
|
-
{ id: "d1", label: t("themeLab.sample.alpha") },
|
|
1040
|
-
{ id: "d2", label: t("themeLab.sample.beta"), current: true },
|
|
1041
|
-
]}
|
|
1042
|
-
events={[
|
|
1043
|
-
{
|
|
1044
|
-
id: "e1",
|
|
1045
|
-
columnId: "d2",
|
|
1046
|
-
start: "09:00",
|
|
1047
|
-
end: "17:30",
|
|
1048
|
-
title: t("themeLab.sample.gamma"),
|
|
1049
|
-
description: t("themeLab.sample.one"),
|
|
1050
|
-
},
|
|
1051
|
-
]}
|
|
1052
|
-
/>
|
|
1053
|
-
<ResponsiveGrid columns={{ sm: 1, md: 2 }}>
|
|
1054
|
-
<Accordion type="single" collapsible>
|
|
1055
|
-
<AccordionItem value="a">
|
|
1056
|
-
<AccordionTrigger>{t("themeLab.sample.alpha")}</AccordionTrigger>
|
|
1057
|
-
<AccordionContent>{t("themeLab.sample.long")}</AccordionContent>
|
|
1058
|
-
</AccordionItem>
|
|
1059
|
-
<AccordionItem value="b">
|
|
1060
|
-
<AccordionTrigger>{t("themeLab.sample.beta")}</AccordionTrigger>
|
|
1061
|
-
<AccordionContent>{t("themeLab.sample.short")}</AccordionContent>
|
|
1062
|
-
</AccordionItem>
|
|
1063
|
-
</Accordion>
|
|
1064
|
-
<Flex direction="col" gap="sm" align="start">
|
|
1065
|
-
<Collapsible>
|
|
1066
|
-
<Flex direction="col" align="start" gap="sm">
|
|
1067
|
-
<CollapsibleTrigger asChild>
|
|
1068
|
-
<Button variant="ghost" size="sm">
|
|
1069
|
-
<ChevronDown aria-hidden="true" />
|
|
1070
|
-
{t("themeLab.action.more")}
|
|
1071
|
-
</Button>
|
|
1072
|
-
</CollapsibleTrigger>
|
|
1073
|
-
<CollapsibleContent>
|
|
1074
|
-
<Text size="sm">{t("themeLab.sample.long")}</Text>
|
|
1075
|
-
</CollapsibleContent>
|
|
1076
|
-
</Flex>
|
|
1077
|
-
</Collapsible>
|
|
1078
|
-
{/* No `asChild`. HoverCardTrigger is a react-aria `Focusable`, and a `Button`
|
|
1079
|
-
handed to it through `asChild` warned "<Focusable> child must forward its ref
|
|
1080
|
-
to a DOM element" on every render. The catalogue's own example is a bare
|
|
1081
|
-
trigger, and that is what this uses. */}
|
|
1082
|
-
<HoverCard>
|
|
1083
|
-
<HoverCardTrigger>{t("themeLab.sample.one")}</HoverCardTrigger>
|
|
1084
|
-
<HoverCardContent>{t("themeLab.sample.short")}</HoverCardContent>
|
|
1085
|
-
</HoverCard>
|
|
1086
|
-
</Flex>
|
|
1087
|
-
</ResponsiveGrid>
|
|
1088
|
-
<Card>
|
|
1089
|
-
<CardContent flush>
|
|
1090
|
-
<ScrollArea>
|
|
1091
|
-
<Flex direction="col" gap="sm">
|
|
1092
|
-
{["alpha", "beta", "gamma", "delta", "epsilon"].map((key) => (
|
|
1093
|
-
<Text key={key} size="sm">
|
|
1094
|
-
{t(`themeLab.sample.${key}`)}
|
|
1095
|
-
</Text>
|
|
1096
|
-
))}
|
|
1097
|
-
</Flex>
|
|
1098
|
-
</ScrollArea>
|
|
1099
|
-
</CardContent>
|
|
1100
|
-
</Card>
|
|
1101
|
-
<Tree
|
|
1102
|
-
aria-label={t("themeLab.label.permissions")}
|
|
1103
|
-
treeData={[
|
|
1104
|
-
{
|
|
1105
|
-
value: "billing",
|
|
1106
|
-
label: t("themeLab.sample.alpha"),
|
|
1107
|
-
children: [
|
|
1108
|
-
{ value: "billing.read", label: t("themeLab.sample.beta") },
|
|
1109
|
-
{ value: "billing.write", label: t("themeLab.sample.gamma") },
|
|
1110
|
-
],
|
|
1111
|
-
},
|
|
1112
|
-
]}
|
|
1113
|
-
checkable
|
|
1114
|
-
defaultExpandAll
|
|
1115
|
-
checkedValues={treeChecked}
|
|
1116
|
-
onCheckedValuesChange={setTreeChecked}
|
|
1117
|
-
/>
|
|
1118
|
-
<Carousel opts={{ loop: true }}>
|
|
1119
|
-
<CarouselContent>
|
|
1120
|
-
{["alpha", "beta", "gamma"].map((key) => (
|
|
1121
|
-
<CarouselItem key={key}>
|
|
1122
|
-
<Card>
|
|
1123
|
-
<CardContent>
|
|
1124
|
-
<Text>{t(`themeLab.sample.${key}`)}</Text>
|
|
1125
|
-
</CardContent>
|
|
1126
|
-
</Card>
|
|
1127
|
-
</CarouselItem>
|
|
1128
|
-
))}
|
|
1129
|
-
</CarouselContent>
|
|
1130
|
-
<CarouselPrevious />
|
|
1131
|
-
<CarouselNext />
|
|
1132
|
-
<CarouselDots />
|
|
1133
|
-
</Carousel>
|
|
1134
|
-
<Masonry
|
|
1135
|
-
columns={{ base: 1, sm: 2, lg: 3 }}
|
|
1136
|
-
gap="md"
|
|
1137
|
-
items={["alpha", "beta", "gamma", "delta"].map((key) => ({ key, data: key }))}
|
|
1138
|
-
itemRender={({ data }) => (
|
|
1139
|
-
<Card>
|
|
1140
|
-
<CardContent>
|
|
1141
|
-
<Text>{t(`themeLab.sample.${data}`)}</Text>
|
|
1142
|
-
</CardContent>
|
|
1143
|
-
</Card>
|
|
1144
|
-
)}
|
|
1145
|
-
/>
|
|
1146
|
-
<Flex direction="row" gap="md" wrap align="start">
|
|
1147
|
-
<QrCode
|
|
1148
|
-
value="https://example.test/enrol"
|
|
1149
|
-
label={t("themeLab.label.qr")}
|
|
1150
|
-
size="md"
|
|
1151
|
-
/>
|
|
1152
|
-
<Thumbnail
|
|
1153
|
-
src={shotLandscape}
|
|
1154
|
-
width={960}
|
|
1155
|
-
height={540}
|
|
1156
|
-
alt={t("themeLab.label.thumbnail")}
|
|
1157
|
-
size="lg"
|
|
1158
|
-
/>
|
|
1159
|
-
<CredentialReveal
|
|
1160
|
-
label={t("themeLab.label.credential")}
|
|
1161
|
-
secret="gxp_live_8Fh2kQ9wR7nZ1xV4bT6mL0cD"
|
|
1162
|
-
defaultRevealed
|
|
1163
|
-
/>
|
|
1164
|
-
</Flex>
|
|
1165
|
-
</Section>
|
|
1166
|
-
|
|
1167
|
-
{/* ── 5 · tables ───────────────────────────────────────────────────────────── */}
|
|
1168
|
-
<Section id="tables" title={t("themeLab.section.tables")}>
|
|
1169
|
-
<Card>
|
|
1170
|
-
<CardContent flush>
|
|
1171
|
-
<DataTable
|
|
1172
|
-
columns={columns}
|
|
1173
|
-
data={ROWS}
|
|
1174
|
-
getRowId={(row) => row.id}
|
|
1175
|
-
label={t("themeLab.section.tables")}
|
|
1176
|
-
/>
|
|
1177
|
-
</CardContent>
|
|
1178
|
-
</Card>
|
|
1179
|
-
<Table>
|
|
1180
|
-
<TableHeader>
|
|
1181
|
-
<TableRow>
|
|
1182
|
-
<TableHead>{t("themeLab.table.name")}</TableHead>
|
|
1183
|
-
<TableHead numeric>{t("themeLab.table.amount")}</TableHead>
|
|
1184
|
-
</TableRow>
|
|
1185
|
-
</TableHeader>
|
|
1186
|
-
<TableBody>
|
|
1187
|
-
<TableRow>
|
|
1188
|
-
<TableCell>{t("themeLab.sample.alpha")}</TableCell>
|
|
1189
|
-
<TableCell numeric>1,200</TableCell>
|
|
1190
|
-
</TableRow>
|
|
1191
|
-
<TableRow>
|
|
1192
|
-
<TableCell>{t("themeLab.sample.beta")}</TableCell>
|
|
1193
|
-
<TableCell numeric>860</TableCell>
|
|
1194
|
-
</TableRow>
|
|
1195
|
-
</TableBody>
|
|
1196
|
-
</Table>
|
|
1197
|
-
<Card>
|
|
1198
|
-
<CardContent flush>
|
|
1199
|
-
<PermissionMatrix
|
|
1200
|
-
roles={[
|
|
1201
|
-
{ id: "admin", name: t("themeLab.role.admin") },
|
|
1202
|
-
{ id: "viewer", name: t("themeLab.role.viewer") },
|
|
1203
|
-
]}
|
|
1204
|
-
permissions={[
|
|
1205
|
-
{ id: "read", name: t("themeLab.perm.read") },
|
|
1206
|
-
{ id: "write", name: t("themeLab.perm.write") },
|
|
1207
|
-
]}
|
|
1208
|
-
grants={new Set(["admin:read", "admin:write", "viewer:read"])}
|
|
1209
|
-
readOnly
|
|
1210
|
-
/>
|
|
1211
|
-
</CardContent>
|
|
1212
|
-
</Card>
|
|
1213
|
-
<SkeletonTable rows={3} columns={4} />
|
|
1214
|
-
<SkeletonRows rows={2} columns={3} />
|
|
1215
|
-
</Section>
|
|
1216
|
-
|
|
1217
|
-
{/* ── 6 · charts ───────────────────────────────────────────────────────────── */}
|
|
1218
|
-
<Section id="charts" title={t("themeLab.section.charts")}>
|
|
1219
|
-
<ResponsiveGrid columns={{ sm: 1, lg: 2 }}>
|
|
1220
|
-
<LineChart
|
|
1221
|
-
label={t("themeLab.chart.trend")}
|
|
1222
|
-
data={SERIES}
|
|
1223
|
-
categoryKey="month"
|
|
1224
|
-
series={[
|
|
1225
|
-
{ dataKey: "plan", label: t("themeLab.chart.plan") },
|
|
1226
|
-
{ dataKey: "actual", label: t("themeLab.chart.actual") },
|
|
1227
|
-
]}
|
|
1228
|
-
/>
|
|
1229
|
-
<BarChart
|
|
1230
|
-
label={t("themeLab.chart.byMonth")}
|
|
1231
|
-
data={SERIES}
|
|
1232
|
-
categoryKey="month"
|
|
1233
|
-
series={[{ dataKey: "actual", label: t("themeLab.chart.actual") }]}
|
|
1234
|
-
/>
|
|
1235
|
-
<AreaChart
|
|
1236
|
-
label={t("themeLab.chart.stacked")}
|
|
1237
|
-
data={SERIES}
|
|
1238
|
-
categoryKey="month"
|
|
1239
|
-
series={[
|
|
1240
|
-
{ dataKey: "plan", label: t("themeLab.chart.plan") },
|
|
1241
|
-
{ dataKey: "actual", label: t("themeLab.chart.actual") },
|
|
1242
|
-
]}
|
|
1243
|
-
stacked
|
|
1244
|
-
/>
|
|
1245
|
-
<PieChart
|
|
1246
|
-
label={t("themeLab.chart.split")}
|
|
1247
|
-
data={[
|
|
1248
|
-
{ category: t("themeLab.sample.alpha"), amount: 42 },
|
|
1249
|
-
{ category: t("themeLab.sample.beta"), amount: 31 },
|
|
1250
|
-
{ category: t("themeLab.sample.gamma"), amount: 27 },
|
|
1251
|
-
]}
|
|
1252
|
-
dataKey="amount"
|
|
1253
|
-
nameKey="category"
|
|
1254
|
-
donut
|
|
1255
|
-
/>
|
|
1256
|
-
</ResponsiveGrid>
|
|
1257
|
-
<CompactBarTrend
|
|
1258
|
-
label={t("themeLab.chart.weekly")}
|
|
1259
|
-
description={t("themeLab.sample.short")}
|
|
1260
|
-
data={TREND}
|
|
1261
|
-
categoryKey="date"
|
|
1262
|
-
valueKey="count"
|
|
1263
|
-
size="xs"
|
|
1264
|
-
/>
|
|
1265
|
-
</Section>
|
|
1266
|
-
|
|
1267
|
-
{/* ── 7 · form controls ────────────────────────────────────────────────────── */}
|
|
1268
|
-
<Section
|
|
1269
|
-
id="fields"
|
|
1270
|
-
title={t("themeLab.section.fields")}
|
|
1271
|
-
note={t("themeLab.section.fieldsNote")}
|
|
1272
|
-
>
|
|
1273
|
-
<Form
|
|
1274
|
-
layout="vertical"
|
|
1275
|
-
columns={2}
|
|
1276
|
-
/* A server error map, so `FormErrors` has something to summarise: with none it
|
|
1277
|
-
renders nothing at all, which on a coverage page reads as a missing component
|
|
1278
|
-
rather than as an empty state. */
|
|
1279
|
-
errors={{ email: t("themeLab.field.emailError") }}
|
|
1280
|
-
>
|
|
1281
|
-
<FormErrors />
|
|
1282
|
-
<FormField
|
|
1283
|
-
id="f-name"
|
|
1284
|
-
label={t("themeLab.field.name")}
|
|
1285
|
-
required
|
|
1286
|
-
helper={t("themeLab.sample.short")}
|
|
1287
|
-
>
|
|
1288
|
-
<Input
|
|
1289
|
-
id="f-name"
|
|
1290
|
-
name="name"
|
|
1291
|
-
placeholder={t("themeLab.field.namePlaceholder")}
|
|
1292
|
-
/>
|
|
1293
|
-
</FormField>
|
|
1294
|
-
<FormField
|
|
1295
|
-
id="f-error"
|
|
1296
|
-
label={t("themeLab.field.email")}
|
|
1297
|
-
error={t("themeLab.field.emailError")}
|
|
1298
|
-
>
|
|
1299
|
-
<Input id="f-error" name="email" defaultValue="not-an-email" />
|
|
1300
|
-
</FormField>
|
|
1301
|
-
<FormField id="f-search" label={t("themeLab.field.search")}>
|
|
1302
|
-
<SearchInput
|
|
1303
|
-
id="f-search"
|
|
1304
|
-
value={query}
|
|
1305
|
-
onSearch={setQuery}
|
|
1306
|
-
placeholder={t("themeLab.field.searchPlaceholder")}
|
|
1307
|
-
/>
|
|
1308
|
-
</FormField>
|
|
1309
|
-
<FormField id="f-qty" label={t("themeLab.field.quantity")}>
|
|
1310
|
-
<NumberInput
|
|
1311
|
-
id="f-qty"
|
|
1312
|
-
aria-label={t("themeLab.field.quantity")}
|
|
1313
|
-
defaultValue={3}
|
|
1314
|
-
min={0}
|
|
1315
|
-
max={99}
|
|
1316
|
-
/>
|
|
1317
|
-
</FormField>
|
|
1318
|
-
<FormField id="f-pw" label={t("themeLab.field.password")}>
|
|
1319
|
-
<PasswordInput
|
|
1320
|
-
id="f-pw"
|
|
1321
|
-
value={password}
|
|
1322
|
-
onChange={(event) => setPassword(event.target.value)}
|
|
1323
|
-
autoComplete="new-password"
|
|
1324
|
-
/>
|
|
1325
|
-
</FormField>
|
|
1326
|
-
<FormField id="f-notes" label={t("themeLab.field.notes")} colSpan={2}>
|
|
1327
|
-
<Textarea id="f-notes" rows={3} placeholder={t("themeLab.sample.short")} />
|
|
1328
|
-
</FormField>
|
|
1329
|
-
<FormField id="f-tags" label={t("themeLab.field.tags")}>
|
|
1330
|
-
<TagInput
|
|
1331
|
-
id="f-tags"
|
|
1332
|
-
aria-label={t("themeLab.field.tags")}
|
|
1333
|
-
value={tags}
|
|
1334
|
-
onValueChange={setTags}
|
|
1335
|
-
/>
|
|
1336
|
-
</FormField>
|
|
1337
|
-
<FormField id="f-role" label={t("themeLab.field.role")}>
|
|
1338
|
-
<Select
|
|
1339
|
-
id="f-role"
|
|
1340
|
-
value={role}
|
|
1341
|
-
onValueChange={setRole}
|
|
1342
|
-
options={[
|
|
1343
|
-
{ value: "viewer", label: t("themeLab.role.viewer") },
|
|
1344
|
-
{ value: "editor", label: t("themeLab.role.editor") },
|
|
1345
|
-
{ value: "admin", label: t("themeLab.role.admin") },
|
|
1346
|
-
]}
|
|
1347
|
-
/>
|
|
1348
|
-
</FormField>
|
|
1349
|
-
<FormField id="f-date" label={t("themeLab.field.date")}>
|
|
1350
|
-
<DatePicker id="f-date" value={date} onValueChange={setDate} />
|
|
1351
|
-
</FormField>
|
|
1352
|
-
<FormField id="f-time" label={t("themeLab.field.time")}>
|
|
1353
|
-
<TimePicker id="f-time" value={time} onValueChange={setTime} minuteStep={15} />
|
|
1354
|
-
</FormField>
|
|
1355
|
-
<FormField id="f-range" label={t("themeLab.field.timeRange")}>
|
|
1356
|
-
<TimeRangePicker
|
|
1357
|
-
aria-label={t("themeLab.field.timeRange")}
|
|
1358
|
-
defaultValue={["09:00", "18:00"]}
|
|
1359
|
-
/>
|
|
1360
|
-
</FormField>
|
|
1361
|
-
<FormField id="f-colour" label={t("themeLab.field.colour")}>
|
|
1362
|
-
<ColorPicker
|
|
1363
|
-
id="f-colour"
|
|
1364
|
-
aria-label={t("themeLab.field.colour")}
|
|
1365
|
-
value={colour}
|
|
1366
|
-
onValueChange={setColour}
|
|
1367
|
-
/>
|
|
1368
|
-
</FormField>
|
|
1369
|
-
<FormField id="f-volume" label={t("themeLab.field.volume")}>
|
|
1370
|
-
<Slider
|
|
1371
|
-
id="f-volume"
|
|
1372
|
-
aria-label={t("themeLab.field.volume")}
|
|
1373
|
-
value={volume}
|
|
1374
|
-
onChange={(next) => setVolume(next as number)}
|
|
1375
|
-
/>
|
|
1376
|
-
</FormField>
|
|
1377
|
-
<FormField id="f-cascade" label={t("themeLab.field.region")}>
|
|
1378
|
-
<Cascader
|
|
1379
|
-
id="f-cascade"
|
|
1380
|
-
options={[
|
|
1381
|
-
{
|
|
1382
|
-
value: "north",
|
|
1383
|
-
label: t("themeLab.sample.alpha"),
|
|
1384
|
-
children: [
|
|
1385
|
-
{ value: "n1", label: t("themeLab.sample.beta") },
|
|
1386
|
-
{ value: "n2", label: t("themeLab.sample.gamma") },
|
|
1387
|
-
],
|
|
1388
|
-
},
|
|
1389
|
-
]}
|
|
1390
|
-
value={cascade}
|
|
1391
|
-
onValueChange={(next) => setCascade(next as string[])}
|
|
1392
|
-
showSearch
|
|
1393
|
-
/>
|
|
1394
|
-
</FormField>
|
|
1395
|
-
<FormField id="f-scope" label={t("themeLab.field.scope")} colSpan={2}>
|
|
1396
|
-
<BranchScopePicker
|
|
1397
|
-
id="f-scope"
|
|
1398
|
-
branches={[
|
|
1399
|
-
{ id: "b1", name: t("themeLab.sample.alpha") },
|
|
1400
|
-
{
|
|
1401
|
-
id: "b2",
|
|
1402
|
-
name: t("themeLab.sample.beta"),
|
|
1403
|
-
description: t("themeLab.sample.short"),
|
|
1404
|
-
},
|
|
1405
|
-
{ id: "b3", name: t("themeLab.sample.gamma"), disabled: true },
|
|
1406
|
-
]}
|
|
1407
|
-
value={scope}
|
|
1408
|
-
onValueChange={setScope}
|
|
1409
|
-
searchable
|
|
1410
|
-
/>
|
|
1411
|
-
</FormField>
|
|
1412
|
-
<FormField id="f-account" label={t("themeLab.field.account")}>
|
|
1413
|
-
<TreeSelect
|
|
1414
|
-
id="f-account"
|
|
1415
|
-
/* `children`, not `content`: Cascader's option type nests through `content`
|
|
1416
|
-
* and TreeSelect's `TreeOptionProp` through `children`. The MCP catalogue's
|
|
1417
|
-
* own TreeSelect example writes `content` and does not typecheck — recorded
|
|
1418
|
-
* here rather than quietly corrected, because the catalogue is what a
|
|
1419
|
-
* consumer copies. */
|
|
1420
|
-
treeData={[
|
|
1421
|
-
{
|
|
1422
|
-
value: "assets",
|
|
1423
|
-
label: t("themeLab.sample.alpha"),
|
|
1424
|
-
children: [
|
|
1425
|
-
{ value: "cash", label: t("themeLab.sample.beta") },
|
|
1426
|
-
{ value: "ar", label: t("themeLab.sample.gamma") },
|
|
1427
|
-
],
|
|
1428
|
-
},
|
|
1429
|
-
]}
|
|
1430
|
-
value={account}
|
|
1431
|
-
onValueChange={(next) => setAccount(next as string | undefined)}
|
|
1432
|
-
showSearch
|
|
1433
|
-
treeDefaultExpandAll
|
|
1434
|
-
allowClear
|
|
1435
|
-
/>
|
|
1436
|
-
</FormField>
|
|
1437
|
-
</Form>
|
|
1438
|
-
<Flex direction="col" gap="md">
|
|
1439
|
-
<Field
|
|
1440
|
-
id="f-switch"
|
|
1441
|
-
label={t("themeLab.field.notify")}
|
|
1442
|
-
description={t("themeLab.sample.short")}
|
|
1443
|
-
>
|
|
1444
|
-
<Switch
|
|
1445
|
-
id="f-switch"
|
|
1446
|
-
aria-label={t("themeLab.field.notify")}
|
|
1447
|
-
checked={switched}
|
|
1448
|
-
onCheckedChange={setSwitched}
|
|
1449
|
-
/>
|
|
1450
|
-
</Field>
|
|
1451
|
-
<Label htmlFor="f-agree">{t("themeLab.field.agree")}</Label>
|
|
1452
|
-
<Checkbox
|
|
1453
|
-
id="f-agree"
|
|
1454
|
-
checked={checked}
|
|
1455
|
-
onCheckedChange={(next) => setChecked(next === true)}
|
|
1456
|
-
>
|
|
1457
|
-
{t("themeLab.field.agree")}
|
|
1458
|
-
</Checkbox>
|
|
1459
|
-
<CheckboxGroup
|
|
1460
|
-
name="perms"
|
|
1461
|
-
aria-label={t("themeLab.label.permissions")}
|
|
1462
|
-
options={[
|
|
1463
|
-
{ label: t("themeLab.perm.read"), value: "read" },
|
|
1464
|
-
{
|
|
1465
|
-
label: t("themeLab.perm.write"),
|
|
1466
|
-
value: "write",
|
|
1467
|
-
description: t("themeLab.sample.short"),
|
|
1468
|
-
},
|
|
1469
|
-
{ label: t("themeLab.perm.admin"), value: "admin", disabled: true },
|
|
1470
|
-
]}
|
|
1471
|
-
defaultValue={["read"]}
|
|
1472
|
-
orientation="vertical"
|
|
1473
|
-
/>
|
|
1474
|
-
<RadioGroup
|
|
1475
|
-
name="tier"
|
|
1476
|
-
aria-label={t("themeLab.label.variants")}
|
|
1477
|
-
defaultValue="a"
|
|
1478
|
-
orientation="horizontal"
|
|
1479
|
-
options={[
|
|
1480
|
-
{ label: t("themeLab.sample.alpha"), value: "a" },
|
|
1481
|
-
{ label: t("themeLab.sample.beta"), value: "b" },
|
|
1482
|
-
]}
|
|
1483
|
-
/>
|
|
1484
|
-
<Radio.Group
|
|
1485
|
-
name="method"
|
|
1486
|
-
aria-label={t("themeLab.label.sizes")}
|
|
1487
|
-
defaultValue="card"
|
|
1488
|
-
orientation="vertical"
|
|
1489
|
-
options={[
|
|
1490
|
-
{
|
|
1491
|
-
label: t("themeLab.sample.gamma"),
|
|
1492
|
-
value: "card",
|
|
1493
|
-
description: t("themeLab.sample.short"),
|
|
1494
|
-
},
|
|
1495
|
-
{ label: t("themeLab.sample.delta"), value: "bank" },
|
|
1496
|
-
]}
|
|
1497
|
-
/>
|
|
1498
|
-
<PasswordStrength value={password} />
|
|
1499
|
-
<InputOTP maxLength={6} value={otp} onChange={setOtp}>
|
|
1500
|
-
<InputOTPGroup>
|
|
1501
|
-
{[0, 1, 2, 3, 4, 5].map((index) => (
|
|
1502
|
-
<InputOTPSlot key={index} index={index} />
|
|
1503
|
-
))}
|
|
1504
|
-
</InputOTPGroup>
|
|
1505
|
-
</InputOTP>
|
|
1506
|
-
<Upload variant="dropzone" value={uploads} onValueChange={setUploads} />
|
|
1507
|
-
<Attachments items={[]} overflow="scrollX" />
|
|
1508
|
-
<Command label={t("themeLab.label.quickPick")} loop>
|
|
1509
|
-
<CommandInput placeholder={t("themeLab.field.searchPlaceholder")} />
|
|
1510
|
-
<CommandList>
|
|
1511
|
-
<CommandEmpty>{t("themeLab.label.noResults")}</CommandEmpty>
|
|
1512
|
-
<CommandGroup heading={t("themeLab.sample.alpha")}>
|
|
1513
|
-
<CommandItem value="one">{t("themeLab.sample.one")}</CommandItem>
|
|
1514
|
-
<CommandItem value="two">{t("themeLab.sample.two")}</CommandItem>
|
|
1515
|
-
</CommandGroup>
|
|
1516
|
-
</CommandList>
|
|
1517
|
-
</Command>
|
|
1518
|
-
<Transfer
|
|
1519
|
-
/* `key`, not `value` — the MCP catalogue's Transfer example writes `value` and
|
|
1520
|
-
* does not typecheck either. Same note as TreeSelect above. */
|
|
1521
|
-
dataSource={[
|
|
1522
|
-
{ key: "1010", title: t("themeLab.sample.alpha") },
|
|
1523
|
-
{ key: "1020", title: t("themeLab.sample.beta") },
|
|
1524
|
-
{ key: "2010", title: t("themeLab.sample.gamma") },
|
|
1525
|
-
]}
|
|
1526
|
-
targetKeys={transferred}
|
|
1527
|
-
onValueChange={setTransferred}
|
|
1528
|
-
titles={[t("themeLab.label.available"), t("themeLab.label.selected")]}
|
|
1529
|
-
showSearch
|
|
1530
|
-
/>
|
|
1531
|
-
<Calendar
|
|
1532
|
-
mode="single"
|
|
1533
|
-
selected={date}
|
|
1534
|
-
onSelect={setDate}
|
|
1535
|
-
aria-label={t("themeLab.field.date")}
|
|
1536
|
-
/>
|
|
1537
|
-
</Flex>
|
|
1538
|
-
</Section>
|
|
1539
|
-
|
|
1540
|
-
{/* ── 8 · navigation ───────────────────────────────────────────────────────── */}
|
|
1541
|
-
<Section id="nav" title={t("themeLab.section.nav")}>
|
|
1542
|
-
<Breadcrumb
|
|
1543
|
-
items={[
|
|
1544
|
-
/* Distinct hrefs, because Breadcrumb keys its rows by `to` and two "#" rows
|
|
1545
|
-
* produced a duplicate-key error in React. */
|
|
1546
|
-
{ label: t("themeLab.nav.overview"), to: "#overview" },
|
|
1547
|
-
{ label: t("themeLab.nav.reports"), to: "#nav" },
|
|
1548
|
-
{ label: t("themeLab.sample.alpha") },
|
|
1549
|
-
]}
|
|
1550
|
-
/>
|
|
1551
|
-
<Tabs
|
|
1552
|
-
defaultValue="overview"
|
|
1553
|
-
items={[
|
|
1554
|
-
{
|
|
1555
|
-
value: "overview",
|
|
1556
|
-
label: t("themeLab.nav.overview"),
|
|
1557
|
-
content: t("themeLab.sample.long"),
|
|
1558
|
-
},
|
|
1559
|
-
{
|
|
1560
|
-
value: "reports",
|
|
1561
|
-
label: t("themeLab.nav.reports"),
|
|
1562
|
-
content: t("themeLab.sample.short"),
|
|
1563
|
-
},
|
|
1564
|
-
]}
|
|
1565
|
-
/>
|
|
1566
|
-
<Steps
|
|
1567
|
-
value={step}
|
|
1568
|
-
items={[
|
|
1569
|
-
{ title: t("themeLab.sample.alpha") },
|
|
1570
|
-
{ title: t("themeLab.sample.beta") },
|
|
1571
|
-
{ title: t("themeLab.sample.gamma") },
|
|
1572
|
-
]}
|
|
1573
|
-
/>
|
|
1574
|
-
<Pagination value={page} total={96} pageSize={10} showTotal onValueChange={setPage} />
|
|
1575
|
-
<Toolbar hasActiveFilters onClear={() => setQuery("")}>
|
|
1576
|
-
<SearchInput
|
|
1577
|
-
value={query}
|
|
1578
|
-
onSearch={setQuery}
|
|
1579
|
-
placeholder={t("themeLab.field.searchPlaceholder")}
|
|
1580
|
-
/>
|
|
1581
|
-
<ToolbarGroup label={t("themeLab.table.status")}>
|
|
1582
|
-
<Select
|
|
1583
|
-
aria-label={t("themeLab.table.status")}
|
|
1584
|
-
value={role}
|
|
1585
|
-
onValueChange={setRole}
|
|
1586
|
-
options={[
|
|
1587
|
-
{ value: "viewer", label: t("themeLab.role.viewer") },
|
|
1588
|
-
{ value: "admin", label: t("themeLab.role.admin") },
|
|
1589
|
-
]}
|
|
1590
|
-
/>
|
|
1591
|
-
</ToolbarGroup>
|
|
1592
|
-
</Toolbar>
|
|
1593
|
-
<FilterBar
|
|
1594
|
-
search={{
|
|
1595
|
-
value: query,
|
|
1596
|
-
onValueChange: setQuery,
|
|
1597
|
-
placeholder: t("themeLab.field.searchPlaceholder"),
|
|
1598
|
-
}}
|
|
1599
|
-
resultCount={ROWS.length}
|
|
1600
|
-
actions={<Button size="sm">{t("themeLab.action.save")}</Button>}
|
|
1601
|
-
/>
|
|
1602
|
-
<MegaMenu
|
|
1603
|
-
label={t("themeLab.label.mainNav")}
|
|
1604
|
-
value={route}
|
|
1605
|
-
onValueChange={setRoute}
|
|
1606
|
-
items={[
|
|
1607
|
-
{
|
|
1608
|
-
key: "products",
|
|
1609
|
-
label: t("themeLab.sample.alpha"),
|
|
1610
|
-
panel: {
|
|
1611
|
-
groups: [
|
|
1612
|
-
{
|
|
1613
|
-
key: "core",
|
|
1614
|
-
label: t("themeLab.sample.beta"),
|
|
1615
|
-
links: [
|
|
1616
|
-
{ key: "hr", label: t("themeLab.sample.gamma"), href: "#hr" },
|
|
1617
|
-
{ key: "pay", label: t("themeLab.sample.delta"), href: "#pay" },
|
|
1618
|
-
],
|
|
1619
|
-
},
|
|
1620
|
-
],
|
|
1621
|
-
},
|
|
1622
|
-
},
|
|
1623
|
-
{ key: "pricing", label: t("themeLab.sample.epsilon"), href: "#pricing" },
|
|
1624
|
-
]}
|
|
1625
|
-
/>
|
|
1626
|
-
<NavList
|
|
1627
|
-
label={t("themeLab.nav.section")}
|
|
1628
|
-
activeId="overview"
|
|
1629
|
-
items={[
|
|
1630
|
-
{
|
|
1631
|
-
id: "account",
|
|
1632
|
-
label: t("themeLab.sample.alpha"),
|
|
1633
|
-
icon: Users,
|
|
1634
|
-
children: [
|
|
1635
|
-
{ id: "overview", label: t("themeLab.nav.overview"), href: "#overview" },
|
|
1636
|
-
{ id: "people", label: t("themeLab.nav.people"), href: "#people" },
|
|
1637
|
-
],
|
|
1638
|
-
},
|
|
1639
|
-
{
|
|
1640
|
-
id: "appearance",
|
|
1641
|
-
label: t("themeLab.nav.settings"),
|
|
1642
|
-
icon: Palette,
|
|
1643
|
-
href: "#settings",
|
|
1644
|
-
},
|
|
1645
|
-
]}
|
|
1646
|
-
/>
|
|
1647
|
-
{/*
|
|
1648
|
-
* `affix={false}`, because Anchor has NO `target` prop — unlike Affix, which does.
|
|
1649
|
-
* So an affixed Anchor can only pin to the viewport, and on this page that put it
|
|
1650
|
-
* on top of the PageContainer header alongside the Affix. Turning the pinning off
|
|
1651
|
-
* is the only thing the API offers here; that asymmetry between two components
|
|
1652
|
-
* whose whole job is the same behaviour is filed as its own issue.
|
|
1653
|
-
*/}
|
|
1654
|
-
<Anchor
|
|
1655
|
-
affix={false}
|
|
1656
|
-
label={t("themeLab.label.onThisPage")}
|
|
1657
|
-
items={[
|
|
1658
|
-
{ key: "type", href: "#type", title: t("themeLab.section.type") },
|
|
1659
|
-
{ key: "actions", href: "#actions", title: t("themeLab.section.actions") },
|
|
1660
|
-
{ key: "tables", href: "#tables", title: t("themeLab.section.tables") },
|
|
1661
|
-
]}
|
|
1662
|
-
/>
|
|
1663
|
-
{/*
|
|
1664
|
-
* Affix AND Anchor pin to their SCROLL TARGET, and without one that target is the
|
|
1665
|
-
* viewport — so on this page both landed on top of the PageContainer header, three
|
|
1666
|
-
* `position: fixed` bars stacked over the title. Measured: `.ui-affix-content` at
|
|
1667
|
-
* `inset-block-start: 0` and `64px`, `z-index: 20`, over a header at z-index 0.
|
|
1668
|
-
*
|
|
1669
|
-
* That is the components doing exactly what they were told, which is why it is the
|
|
1670
|
-
* PAGE that is wrong: a demo of a pinning component has no business pinning to the
|
|
1671
|
-
* document it is being demonstrated in. Each gets its own bounded scroller, which is
|
|
1672
|
-
* also the only way to SHOW the behaviour — a bar pinned to a viewport you are not
|
|
1673
|
-
* scrolling never moves, so the old version demonstrated nothing while breaking the
|
|
1674
|
-
* page it sat on.
|
|
1675
|
-
*/}
|
|
1676
|
-
<div
|
|
1677
|
-
ref={affixScrollerRef}
|
|
1678
|
-
className="ui-scroll-area"
|
|
1679
|
-
style={{ blockSize: "12rem", overflowY: "auto" }}
|
|
1680
|
-
>
|
|
1681
|
-
<div style={{ blockSize: "30rem" }}>
|
|
1682
|
-
<Affix offsetBlockStart={8} target={() => affixScrollerRef.current}>
|
|
1683
|
-
<Flex align="center" justify="between" gap="sm">
|
|
1684
|
-
<Text weight="medium">{t("themeLab.label.pinned")}</Text>
|
|
1685
|
-
<Button size="sm">{t("themeLab.action.save")}</Button>
|
|
1686
|
-
</Flex>
|
|
1687
|
-
</Affix>
|
|
1688
|
-
</div>
|
|
1689
|
-
</div>
|
|
1690
|
-
</Section>
|
|
1691
|
-
|
|
1692
|
-
{/* ── 9 · feedback ─────────────────────────────────────────────────────────── */}
|
|
1693
|
-
<Section id="feedback" title={t("themeLab.section.feedback")}>
|
|
1694
|
-
<Alert>
|
|
1695
|
-
<AlertTitle>{t("themeLab.tone.neutral")}</AlertTitle>
|
|
1696
|
-
<AlertDescription>{t("themeLab.sample.long")}</AlertDescription>
|
|
1697
|
-
</Alert>
|
|
1698
|
-
<Alert tone="info">
|
|
1699
|
-
<AlertTitle>{t("themeLab.tone.info")}</AlertTitle>
|
|
1700
|
-
<AlertDescription>{t("themeLab.sample.short")}</AlertDescription>
|
|
1701
|
-
<AlertActions>
|
|
1702
|
-
<Button size="xs" variant="outline">
|
|
1703
|
-
{t("themeLab.action.more")}
|
|
1704
|
-
</Button>
|
|
1705
|
-
</AlertActions>
|
|
1706
|
-
</Alert>
|
|
1707
|
-
<Alert tone="success">
|
|
1708
|
-
<AlertTitle>{t("themeLab.tone.success")}</AlertTitle>
|
|
1709
|
-
<AlertDescription>{t("themeLab.sample.short")}</AlertDescription>
|
|
1710
|
-
</Alert>
|
|
1711
|
-
<Alert tone="warning">
|
|
1712
|
-
<AlertTitle>{t("themeLab.tone.warning")}</AlertTitle>
|
|
1713
|
-
<AlertDescription>{t("themeLab.sample.short")}</AlertDescription>
|
|
1714
|
-
</Alert>
|
|
1715
|
-
<Alert tone="destructive">
|
|
1716
|
-
<AlertTitle>{t("themeLab.tone.destructive")}</AlertTitle>
|
|
1717
|
-
<AlertDescription>{t("themeLab.sample.short")}</AlertDescription>
|
|
1718
|
-
</Alert>
|
|
1719
|
-
<Banner tone="warning">
|
|
1720
|
-
<Banner.Content>
|
|
1721
|
-
<Banner.Title>{t("themeLab.tone.warning")}</Banner.Title>
|
|
1722
|
-
<Banner.Description>{t("themeLab.sample.short")}</Banner.Description>
|
|
1723
|
-
</Banner.Content>
|
|
1724
|
-
</Banner>
|
|
1725
|
-
<Callout kind="warning">
|
|
1726
|
-
<Callout.Title>{t("themeLab.tone.warning")}</Callout.Title>
|
|
1727
|
-
<Callout.Description>{t("themeLab.sample.long")}</Callout.Description>
|
|
1728
|
-
</Callout>
|
|
1729
|
-
<EmptyState
|
|
1730
|
-
title={t("themeLab.label.noResults")}
|
|
1731
|
-
description={t("themeLab.sample.short")}
|
|
1732
|
-
/>
|
|
1733
|
-
<ErrorSurface
|
|
1734
|
-
mode="application"
|
|
1735
|
-
status={403}
|
|
1736
|
-
title={t("themeLab.error.title")}
|
|
1737
|
-
description={t("themeLab.sample.long")}
|
|
1738
|
-
action={<Button>{t("themeLab.action.retry")}</Button>}
|
|
1739
|
-
/>
|
|
1740
|
-
<Row2 label={t("themeLab.label.skeletons")}>
|
|
1741
|
-
<Skeleton />
|
|
1742
|
-
<SkeletonAvatar size="lg" />
|
|
1743
|
-
<SkeletonButton size="sm" />
|
|
1744
|
-
<SkeletonInput />
|
|
1745
|
-
<SkeletonNode />
|
|
1746
|
-
<SkeletonImage active />
|
|
1747
|
-
</Row2>
|
|
1748
|
-
<SkeletonArticle avatar active paragraph={{ rows: 2 }} />
|
|
1749
|
-
<SkeletonForm columns={2} fields={4} />
|
|
1750
|
-
</Section>
|
|
1751
|
-
|
|
1752
|
-
{/* ── 10 · overlays. OPENED by the instrument, not merely present. ──────────── */}
|
|
1753
|
-
<Section
|
|
1754
|
-
id="overlays"
|
|
1755
|
-
title={t("themeLab.section.overlays")}
|
|
1756
|
-
note={t("themeLab.section.overlaysNote")}
|
|
1757
|
-
>
|
|
1758
|
-
<Flex direction="row" gap="sm" wrap align="center">
|
|
1759
|
-
<Button data-probe="dialog" onClick={() => setDialogOpen(true)}>
|
|
1760
|
-
{t("themeLab.overlay.dialog")}
|
|
1761
|
-
</Button>
|
|
1762
|
-
<Button data-probe="sheet" variant="outline" onClick={() => setSheetOpen(true)}>
|
|
1763
|
-
{t("themeLab.overlay.sheet")}
|
|
1764
|
-
</Button>
|
|
1765
|
-
<Button
|
|
1766
|
-
data-probe="alert-dialog"
|
|
1767
|
-
variant="destructive"
|
|
1768
|
-
onClick={() => setAlertOpen(true)}
|
|
1769
|
-
>
|
|
1770
|
-
{t("themeLab.overlay.alertDialog")}
|
|
1771
|
-
</Button>
|
|
1772
|
-
<Tooltip>
|
|
1773
|
-
<TooltipTrigger asChild>
|
|
1774
|
-
<Button data-probe="tooltip" variant="outline">
|
|
1775
|
-
{t("themeLab.overlay.tooltip")}
|
|
1776
|
-
</Button>
|
|
1777
|
-
</TooltipTrigger>
|
|
1778
|
-
<TooltipContent>{t("themeLab.sample.short")}</TooltipContent>
|
|
1779
|
-
</Tooltip>
|
|
1780
|
-
<Button
|
|
1781
|
-
data-probe="toast"
|
|
1782
|
-
variant="secondary"
|
|
1783
|
-
onClick={() => toast(t("themeLab.overlay.toastMessage"))}
|
|
1784
|
-
>
|
|
1785
|
-
{t("themeLab.overlay.toast")}
|
|
1786
|
-
</Button>
|
|
1787
|
-
<Button
|
|
1788
|
-
data-probe="two-factor"
|
|
1789
|
-
variant="outline"
|
|
1790
|
-
onClick={() => setTwoFactorOpen(true)}
|
|
1791
|
-
>
|
|
1792
|
-
{t("themeLab.overlay.twoFactor")}
|
|
1793
|
-
</Button>
|
|
1794
|
-
<CommandPalette
|
|
1795
|
-
groups={[
|
|
1796
|
-
{
|
|
1797
|
-
id: "pages",
|
|
1798
|
-
label: t("themeLab.nav.section"),
|
|
1799
|
-
items: [
|
|
1800
|
-
{ id: "overview", label: t("themeLab.nav.overview") },
|
|
1801
|
-
{ id: "reports", label: t("themeLab.nav.reports") },
|
|
1802
|
-
],
|
|
1803
|
-
},
|
|
1804
|
-
]}
|
|
1805
|
-
labels={{
|
|
1806
|
-
open: t("themeLab.label.quickPick"),
|
|
1807
|
-
title: t("themeLab.label.quickPick"),
|
|
1808
|
-
description: t("themeLab.sample.short"),
|
|
1809
|
-
placeholder: t("themeLab.field.searchPlaceholder"),
|
|
1810
|
-
empty: t("themeLab.label.noResults"),
|
|
1811
|
-
}}
|
|
1812
|
-
onSelect={() => {}}
|
|
1813
|
-
/>
|
|
1814
|
-
</Flex>
|
|
1815
|
-
<Flex direction="col" gap="sm" align="start">
|
|
1816
|
-
<Text size="xs" tone="muted">
|
|
1817
|
-
{t("themeLab.overlay.inlineNote")}
|
|
1818
|
-
</Text>
|
|
1819
|
-
{/* `id`, not `data-probe`: Select is a closed component and does not spread
|
|
1820
|
-
arbitrary `data-*` onto its trigger — measured, the attribute never reached the
|
|
1821
|
-
DOM. The instrument addresses this one by id. */}
|
|
1822
|
-
<Select
|
|
1823
|
-
id="overlay-select"
|
|
1824
|
-
aria-label={t("themeLab.field.role")}
|
|
1825
|
-
value={role}
|
|
1826
|
-
onValueChange={setRole}
|
|
1827
|
-
options={[
|
|
1828
|
-
{ value: "viewer", label: t("themeLab.role.viewer") },
|
|
1829
|
-
{ value: "editor", label: t("themeLab.role.editor") },
|
|
1830
|
-
{ value: "admin", label: t("themeLab.role.admin") },
|
|
1831
|
-
]}
|
|
1832
|
-
/>
|
|
1833
|
-
</Flex>
|
|
1834
|
-
</Section>
|
|
1835
|
-
|
|
1836
|
-
{/* ── 11 · regions and shells that nest ────────────────────────────────────── */}
|
|
1837
|
-
<Section id="regions" title={t("themeLab.section.regions")}>
|
|
1838
|
-
<SplitPane
|
|
1839
|
-
asideLabel={t("themeLab.label.detail")}
|
|
1840
|
-
aside={<Text size="sm">{t("themeLab.sample.short")}</Text>}
|
|
1841
|
-
>
|
|
1842
|
-
<Text size="sm">{t("themeLab.sample.long")}</Text>
|
|
1843
|
-
</SplitPane>
|
|
1844
|
-
<MasterDetail
|
|
1845
|
-
masterLabel={t("themeLab.label.master")}
|
|
1846
|
-
detailLabel={t("themeLab.label.detail")}
|
|
1847
|
-
master={<Text size="sm">{t("themeLab.sample.alpha")}</Text>}
|
|
1848
|
-
>
|
|
1849
|
-
<Text size="sm">{t("themeLab.sample.beta")}</Text>
|
|
1850
|
-
</MasterDetail>
|
|
1851
|
-
<ResizablePanelGroup orientation="horizontal">
|
|
1852
|
-
<ResizablePanel id="list" defaultSize="40%" minSize="20%">
|
|
1853
|
-
<Text size="sm">{t("themeLab.sample.alpha")}</Text>
|
|
1854
|
-
</ResizablePanel>
|
|
1855
|
-
<ResizableHandle />
|
|
1856
|
-
<ResizablePanel id="detail" defaultSize="60%" minSize="30%">
|
|
1857
|
-
<Text size="sm">{t("themeLab.sample.beta")}</Text>
|
|
1858
|
-
</ResizablePanel>
|
|
1859
|
-
</ResizablePanelGroup>
|
|
1860
|
-
<ResponsiveGrid columns={{ sm: 1, md: 2, lg: 3 }}>
|
|
1861
|
-
<ServiceLauncherCard
|
|
1862
|
-
icon={Clock}
|
|
1863
|
-
title={t("themeLab.sample.alpha")}
|
|
1864
|
-
statusLabel={t("themeLab.tone.success")}
|
|
1865
|
-
statusTone="success"
|
|
1866
|
-
description={t("themeLab.sample.short")}
|
|
1867
|
-
action={<Button>{t("themeLab.action.open")}</Button>}
|
|
1868
|
-
/>
|
|
1869
|
-
<ServiceLauncherCard
|
|
1870
|
-
icon={Building2}
|
|
1871
|
-
title={t("themeLab.sample.beta")}
|
|
1872
|
-
statusLabel={t("themeLab.tone.warning")}
|
|
1873
|
-
statusTone="warning"
|
|
1874
|
-
description={t("themeLab.sample.short")}
|
|
1875
|
-
disabledReason={t("themeLab.sample.short")}
|
|
1876
|
-
action={<Button disabled>{t("themeLab.action.open")}</Button>}
|
|
1877
|
-
/>
|
|
1878
|
-
<ServiceCatalogCta
|
|
1879
|
-
title={t("themeLab.label.catalog")}
|
|
1880
|
-
action={<Button variant="outline">{t("themeLab.action.more")}</Button>}
|
|
1881
|
-
/>
|
|
1882
|
-
</ResponsiveGrid>
|
|
1883
|
-
<ServiceRolePanel
|
|
1884
|
-
roles={[
|
|
1885
|
-
{ id: "admin", name: t("themeLab.role.admin") },
|
|
1886
|
-
{ id: "viewer", name: t("themeLab.role.viewer") },
|
|
1887
|
-
]}
|
|
1888
|
-
value={selectedRole}
|
|
1889
|
-
onValueChange={setSelectedRole}
|
|
1890
|
-
>
|
|
1891
|
-
{(selected) => (
|
|
1892
|
-
<Text size="sm">{selected ? selected.name : t("themeLab.label.noResults")}</Text>
|
|
1893
|
-
)}
|
|
1894
|
-
</ServiceRolePanel>
|
|
1895
|
-
<OrgSwitcher
|
|
1896
|
-
organizations={[
|
|
1897
|
-
{ id: "dxs", name: t("themeLab.sample.alpha"), meta: t("themeLab.role.admin") },
|
|
1898
|
-
{ id: "acme", name: t("themeLab.sample.beta"), meta: t("themeLab.role.viewer") },
|
|
1899
|
-
]}
|
|
1900
|
-
value={org}
|
|
1901
|
-
onValueChange={setOrg}
|
|
1902
|
-
labels={{
|
|
1903
|
-
trigger: (name) => `${t("themeLab.org.trigger")}: ${name}`,
|
|
1904
|
-
title: t("themeLab.org.trigger"),
|
|
1905
|
-
search: t("themeLab.field.searchPlaceholder"),
|
|
1906
|
-
empty: t("themeLab.label.noResults"),
|
|
1907
|
-
loading: t("themeLab.label.loading"),
|
|
1908
|
-
}}
|
|
1909
|
-
/>
|
|
1910
|
-
<AuthStack>
|
|
1911
|
-
<AuthIdentity
|
|
1912
|
-
title={t("themeLab.auth.title")}
|
|
1913
|
-
requester={t("themeLab.auth.requester")}
|
|
1914
|
-
/>
|
|
1915
|
-
<AuthAccountSummary
|
|
1916
|
-
email="duong@example.test"
|
|
1917
|
-
actionLabel={t("themeLab.auth.switch")}
|
|
1918
|
-
onAction={() => {}}
|
|
1919
|
-
/>
|
|
1920
|
-
<AuthDivider label={t("themeLab.auth.or")} />
|
|
1921
|
-
<AuthFooter
|
|
1922
|
-
product={t("themeLab.product")}
|
|
1923
|
-
terms={t("themeLab.auth.terms")}
|
|
1924
|
-
privacy={t("themeLab.auth.privacy")}
|
|
1925
|
-
/>
|
|
1926
|
-
</AuthStack>
|
|
1927
|
-
</Section>
|
|
1928
|
-
|
|
1929
|
-
{/* ── 12 · conversational ──────────────────────────────────────────────────── */}
|
|
1930
|
-
<Section id="chat" title={t("themeLab.section.chat")}>
|
|
1931
|
-
<Welcome
|
|
1932
|
-
icon={<Bot aria-hidden="true" />}
|
|
1933
|
-
title={t("themeLab.chat.welcomeTitle")}
|
|
1934
|
-
description={t("themeLab.chat.welcomeBody")}
|
|
1935
|
-
/>
|
|
1936
|
-
<ChatBubbleList
|
|
1937
|
-
label={t("themeLab.section.chat")}
|
|
1938
|
-
items={chat}
|
|
1939
|
-
roles={{
|
|
1940
|
-
assistant: { placement: "start", variant: "filled" },
|
|
1941
|
-
user: { placement: "end", variant: "outlined" },
|
|
1942
|
-
}}
|
|
1943
|
-
/>
|
|
1944
|
-
<ChatBubble placement="start" header={t("themeLab.chat.assistantName")} loading />
|
|
1945
|
-
<ChatBubble placement="end" tone="destructive" header={t("themeLab.chat.userName")}>
|
|
1946
|
-
{t("themeLab.sample.short")}
|
|
1947
|
-
</ChatBubble>
|
|
1948
|
-
<ThoughtChain
|
|
1949
|
-
label={t("themeLab.chat.thoughts")}
|
|
1950
|
-
defaultExpandedKeys={["search"]}
|
|
1951
|
-
items={[
|
|
1952
|
-
{ key: "read", title: t("themeLab.sample.alpha"), status: "success" },
|
|
1953
|
-
{
|
|
1954
|
-
key: "search",
|
|
1955
|
-
title: t("themeLab.sample.beta"),
|
|
1956
|
-
status: "loading",
|
|
1957
|
-
collapsible: true,
|
|
1958
|
-
},
|
|
1959
|
-
{ key: "write", title: t("themeLab.sample.gamma"), status: "abort" },
|
|
1960
|
-
]}
|
|
1961
|
-
/>
|
|
1962
|
-
<Conversations
|
|
1963
|
-
activeKey={conversation}
|
|
1964
|
-
onActiveChange={setConversation}
|
|
1965
|
-
items={[
|
|
1966
|
-
{ key: "c1", label: t("themeLab.sample.alpha") },
|
|
1967
|
-
{ key: "c2", label: t("themeLab.sample.beta") },
|
|
1968
|
-
]}
|
|
1969
|
-
/>
|
|
1970
|
-
<ChatSuggestion
|
|
1971
|
-
items={[
|
|
1972
|
-
{ value: "summarize", label: t("themeLab.sample.gamma") },
|
|
1973
|
-
{ value: "translate", label: t("themeLab.sample.delta") },
|
|
1974
|
-
]}
|
|
1975
|
-
>
|
|
1976
|
-
{({ onTrigger, onKeyDown }) => (
|
|
1977
|
-
<ChatComposer
|
|
1978
|
-
value={draft}
|
|
1979
|
-
onValueChange={(next) => {
|
|
1980
|
-
setDraft(next);
|
|
1981
|
-
onTrigger(next);
|
|
1982
|
-
}}
|
|
1983
|
-
onKeyDown={onKeyDown}
|
|
1984
|
-
onSubmit={() => setDraft("")}
|
|
1985
|
-
placeholder={t("themeLab.chat.placeholder")}
|
|
1986
|
-
/>
|
|
1987
|
-
)}
|
|
1988
|
-
</ChatSuggestion>
|
|
1989
|
-
</Section>
|
|
1990
|
-
|
|
1991
|
-
{/* ── 13 · what could NOT be rendered, and why ──────────────────────────────── */}
|
|
1992
|
-
<Section
|
|
1993
|
-
id="absent"
|
|
1994
|
-
title={t("themeLab.section.absent")}
|
|
1995
|
-
note={t("themeLab.section.absentNote")}
|
|
1996
|
-
>
|
|
1997
|
-
<Table>
|
|
1998
|
-
<TableHeader>
|
|
1999
|
-
<TableRow>
|
|
2000
|
-
<TableHead>{t("themeLab.absent.export")}</TableHead>
|
|
2001
|
-
<TableHead>{t("themeLab.absent.reason")}</TableHead>
|
|
2002
|
-
</TableRow>
|
|
2003
|
-
</TableHeader>
|
|
2004
|
-
<TableBody>
|
|
2005
|
-
{ABSENT.map((entry) => (
|
|
2006
|
-
<TableRow key={`${entry.name}-${entry.reasonKey}`}>
|
|
2007
|
-
<TableCell>
|
|
2008
|
-
<Text as="span" size="sm" mono>
|
|
2009
|
-
{entry.name}
|
|
2010
|
-
</Text>
|
|
2011
|
-
</TableCell>
|
|
2012
|
-
<TableCell>
|
|
2013
|
-
<Text as="span" size="sm">
|
|
2014
|
-
{t(entry.reasonKey)}
|
|
2015
|
-
</Text>
|
|
2016
|
-
</TableCell>
|
|
2017
|
-
</TableRow>
|
|
2018
|
-
))}
|
|
2019
|
-
</TableBody>
|
|
2020
|
-
</Table>
|
|
2021
|
-
</Section>
|
|
2022
|
-
|
|
2023
|
-
<Reveal>
|
|
2024
|
-
<Text size="xs" tone="muted">
|
|
2025
|
-
{t("themeLab.page.footer")}
|
|
2026
|
-
</Text>
|
|
2027
|
-
</Reveal>
|
|
2028
|
-
</Flex>
|
|
2029
|
-
</PageContainer>
|
|
2030
|
-
</AppShell>
|
|
2031
|
-
|
|
2032
|
-
<Dialog open={dialogOpen} onOpenChange={setDialogOpen}>
|
|
2033
|
-
<DialogContent>
|
|
2034
|
-
<DialogHeader>
|
|
2035
|
-
<DialogTitle>{t("themeLab.overlay.dialog")}</DialogTitle>
|
|
2036
|
-
<DialogDescription>{t("themeLab.sample.short")}</DialogDescription>
|
|
2037
|
-
</DialogHeader>
|
|
2038
|
-
<DialogBody>
|
|
2039
|
-
<Text as="p" size="sm">
|
|
2040
|
-
{t("themeLab.sample.long")}
|
|
2041
|
-
</Text>
|
|
2042
|
-
</DialogBody>
|
|
2043
|
-
<DialogFooter>
|
|
2044
|
-
<DialogClose asChild>
|
|
2045
|
-
<Button variant="outline">{t("themeLab.action.cancel")}</Button>
|
|
2046
|
-
</DialogClose>
|
|
2047
|
-
<Button onClick={() => setDialogOpen(false)}>{t("themeLab.action.save")}</Button>
|
|
2048
|
-
</DialogFooter>
|
|
2049
|
-
</DialogContent>
|
|
2050
|
-
</Dialog>
|
|
2051
|
-
|
|
2052
|
-
<Sheet open={sheetOpen} onOpenChange={setSheetOpen}>
|
|
2053
|
-
<SheetContent>
|
|
2054
|
-
<SheetHeader>
|
|
2055
|
-
<SheetTitle>{t("themeLab.overlay.sheet")}</SheetTitle>
|
|
2056
|
-
<SheetDescription>{t("themeLab.sample.short")}</SheetDescription>
|
|
2057
|
-
</SheetHeader>
|
|
2058
|
-
<SheetBody>
|
|
2059
|
-
<Text as="p" size="sm">
|
|
2060
|
-
{t("themeLab.sample.long")}
|
|
2061
|
-
</Text>
|
|
2062
|
-
</SheetBody>
|
|
2063
|
-
<SheetFooter>
|
|
2064
|
-
<SheetClose asChild>
|
|
2065
|
-
<Button variant="outline">{t("themeLab.action.cancel")}</Button>
|
|
2066
|
-
</SheetClose>
|
|
2067
|
-
</SheetFooter>
|
|
2068
|
-
</SheetContent>
|
|
2069
|
-
</Sheet>
|
|
2070
|
-
|
|
2071
|
-
<AlertDialog
|
|
2072
|
-
open={alertOpen}
|
|
2073
|
-
onOpenChange={setAlertOpen}
|
|
2074
|
-
title={t("themeLab.overlay.alertDialog")}
|
|
2075
|
-
description={t("themeLab.sample.long")}
|
|
2076
|
-
confirmLabel={t("themeLab.action.save")}
|
|
2077
|
-
cancelLabel={t("themeLab.action.cancel")}
|
|
2078
|
-
onConfirm={() => setAlertOpen(false)}
|
|
2079
|
-
/>
|
|
2080
|
-
|
|
2081
|
-
<TwoFactorSetup
|
|
2082
|
-
open={twoFactorOpen}
|
|
2083
|
-
onOpenChange={setTwoFactorOpen}
|
|
2084
|
-
qrValue="otpauth://totp/theme-lab?secret=JBSWY3DPEHPK3PXP"
|
|
2085
|
-
manualKey="JBSWY3DPEHPK3PXP"
|
|
2086
|
-
code={otp}
|
|
2087
|
-
onCodeChange={setOtp}
|
|
2088
|
-
onConfirm={() => setTwoFactorOpen(false)}
|
|
2089
|
-
onAcknowledge={() => setTwoFactorOpen(false)}
|
|
2090
|
-
labels={{
|
|
2091
|
-
title: t("themeLab.twoFactor.title"),
|
|
2092
|
-
description: t("themeLab.twoFactor.description"),
|
|
2093
|
-
qrLabel: t("themeLab.label.qr"),
|
|
2094
|
-
manualKeyLabel: t("themeLab.twoFactor.manualKey"),
|
|
2095
|
-
codeLabel: t("themeLab.twoFactor.code"),
|
|
2096
|
-
recoveryNotice: t("themeLab.twoFactor.recovery"),
|
|
2097
|
-
cancel: t("themeLab.action.cancel"),
|
|
2098
|
-
confirm: t("themeLab.action.save"),
|
|
2099
|
-
acknowledge: t("themeLab.twoFactor.acknowledge"),
|
|
2100
|
-
}}
|
|
2101
|
-
/>
|
|
2102
|
-
|
|
2103
|
-
<DraggablePanel
|
|
2104
|
-
title={t("themeLab.label.assistant")}
|
|
2105
|
-
placement="bottom-end"
|
|
2106
|
-
position={panelPosition}
|
|
2107
|
-
onPositionChange={setPanelPosition}
|
|
2108
|
-
>
|
|
2109
|
-
<Text size="sm">{t("themeLab.sample.short")}</Text>
|
|
2110
|
-
</DraggablePanel>
|
|
2111
|
-
|
|
2112
|
-
<FloatButton.Group
|
|
2113
|
-
trigger="click"
|
|
2114
|
-
icon={<ActivityIcon />}
|
|
2115
|
-
aria-label={t("themeLab.label.assistant")}
|
|
2116
|
-
>
|
|
2117
|
-
<FloatButton tooltip={t("themeLab.action.share")} icon={<Share2 />} />
|
|
2118
|
-
<FloatButton tooltip={t("themeLab.action.more")} icon={<FileText />} />
|
|
2119
|
-
<FloatButton.BackTop />
|
|
2120
|
-
</FloatButton.Group>
|
|
2121
|
-
|
|
2122
|
-
<Toaster />
|
|
2123
|
-
</ThemeScope>
|
|
2124
|
-
);
|
|
2125
|
-
}
|