@nadicodeai/ui 12.1.102 → 12.1.104
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/accordion.d.ts +38 -12
- package/dist/components/accordion.d.ts.map +1 -1
- package/dist/components/accordion.js +36 -15
- package/dist/components/account-menu.js +2 -2
- package/dist/components/action-menu.d.ts +20 -19
- package/dist/components/action-menu.d.ts.map +1 -1
- package/dist/components/action-menu.js +22 -15
- package/dist/components/action-status.d.ts +14 -10
- package/dist/components/action-status.d.ts.map +1 -1
- package/dist/components/action-status.js +14 -10
- package/dist/components/activity-calendar.d.ts +3 -1
- package/dist/components/activity-calendar.d.ts.map +1 -1
- package/dist/components/activity-calendar.js +16 -2
- package/dist/components/activity-feed.d.ts +2 -2
- package/dist/components/activity-feed.d.ts.map +1 -1
- package/dist/components/activity-feed.js +14 -5
- package/dist/components/agent-card.d.ts +11 -5
- package/dist/components/agent-card.d.ts.map +1 -1
- package/dist/components/agent-card.js +13 -7
- package/dist/components/agent-list-row.js +1 -1
- package/dist/components/agent-orb-appearance.d.ts +7 -1
- package/dist/components/agent-orb-appearance.d.ts.map +1 -1
- package/dist/components/agent-orb-appearance.js +26 -0
- package/dist/components/agent-profile.d.ts +8 -7
- package/dist/components/agent-profile.d.ts.map +1 -1
- package/dist/components/agent-profile.js +6 -6
- package/dist/components/alert-dialog.d.ts +25 -16
- package/dist/components/alert-dialog.d.ts.map +1 -1
- package/dist/components/alert-dialog.js +30 -18
- package/dist/components/alert.d.ts +1 -1
- package/dist/components/avatar.d.ts +83 -17
- package/dist/components/avatar.d.ts.map +1 -1
- package/dist/components/avatar.js +89 -23
- package/dist/components/badge.d.ts +59 -8
- package/dist/components/badge.d.ts.map +1 -1
- package/dist/components/badge.js +57 -14
- package/dist/components/breadcrumb.d.ts +18 -7
- package/dist/components/breadcrumb.d.ts.map +1 -1
- package/dist/components/breadcrumb.js +37 -13
- package/dist/components/button-group.d.ts +12 -15
- package/dist/components/button-group.d.ts.map +1 -1
- package/dist/components/button-group.js +13 -17
- package/dist/components/button.d.ts +126 -23
- package/dist/components/button.d.ts.map +1 -1
- package/dist/components/button.js +164 -39
- package/dist/components/calendar.d.ts +26 -15
- package/dist/components/calendar.d.ts.map +1 -1
- package/dist/components/calendar.js +60 -46
- package/dist/components/card-row.d.ts +13 -5
- package/dist/components/card-row.d.ts.map +1 -1
- package/dist/components/card-row.js +24 -10
- package/dist/components/card.d.ts +6 -12
- package/dist/components/card.d.ts.map +1 -1
- package/dist/components/card.js +11 -16
- package/dist/components/carousel.d.ts +3 -3
- package/dist/components/carousel.d.ts.map +1 -1
- package/dist/components/carousel.js +7 -7
- package/dist/components/catalog-drawer.d.ts +7 -7
- package/dist/components/catalog-drawer.d.ts.map +1 -1
- package/dist/components/catalog-drawer.js +6 -6
- package/dist/components/chart-area-stacked.d.ts +1 -1
- package/dist/components/chart-area-stacked.d.ts.map +1 -1
- package/dist/components/chart-area-stacked.js +4 -4
- package/dist/components/chart-axis.d.ts +14 -1
- package/dist/components/chart-axis.d.ts.map +1 -1
- package/dist/components/chart-axis.js +11 -1
- package/dist/components/chart-bar-horizontal.d.ts +2 -2
- package/dist/components/chart-bar-horizontal.d.ts.map +1 -1
- package/dist/components/chart-bar-horizontal.js +14 -5
- package/dist/components/chart-bar-multiple.d.ts +1 -1
- package/dist/components/chart-bar-multiple.d.ts.map +1 -1
- package/dist/components/chart-bar-multiple.js +3 -3
- package/dist/components/chart-bar-stacked.d.ts +1 -1
- package/dist/components/chart-bar-stacked.d.ts.map +1 -1
- package/dist/components/chart-bar-stacked.js +3 -3
- package/dist/components/chart-card.d.ts +17 -6
- package/dist/components/chart-card.d.ts.map +1 -1
- package/dist/components/chart-card.js +11 -4
- package/dist/components/chart-date-range-control.d.ts +18 -9
- package/dist/components/chart-date-range-control.d.ts.map +1 -1
- package/dist/components/chart-date-range-control.js +43 -47
- package/dist/components/chart-sparkline.d.ts +4 -3
- package/dist/components/chart-sparkline.d.ts.map +1 -1
- package/dist/components/chart-sparkline.js +6 -5
- package/dist/components/check-counts.d.ts +44 -0
- package/dist/components/check-counts.d.ts.map +1 -0
- package/dist/components/check-counts.js +51 -0
- package/dist/components/checkbox.d.ts +39 -11
- package/dist/components/checkbox.d.ts.map +1 -1
- package/dist/components/checkbox.js +38 -11
- package/dist/components/choicebox.d.ts +96 -0
- package/dist/components/choicebox.d.ts.map +1 -0
- package/dist/components/choicebox.js +113 -0
- package/dist/components/clearable-input.d.ts +57 -0
- package/dist/components/clearable-input.d.ts.map +1 -0
- package/dist/components/clearable-input.js +58 -0
- package/dist/components/code-block.d.ts +77 -17
- package/dist/components/code-block.d.ts.map +1 -1
- package/dist/components/code-block.js +85 -15
- package/dist/components/collapsible.d.ts +27 -10
- package/dist/components/collapsible.d.ts.map +1 -1
- package/dist/components/collapsible.js +24 -9
- package/dist/components/collection-filters.d.ts +3 -1
- package/dist/components/collection-filters.d.ts.map +1 -1
- package/dist/components/collection-filters.js +7 -9
- package/dist/components/collection-page.d.ts +31 -10
- package/dist/components/collection-page.d.ts.map +1 -1
- package/dist/components/collection-page.js +14 -13
- package/dist/components/collection-search.d.ts +32 -10
- package/dist/components/collection-search.d.ts.map +1 -1
- package/dist/components/collection-search.js +24 -13
- package/dist/components/collection-sort.d.ts.map +1 -1
- package/dist/components/collection-sort.js +2 -2
- package/dist/components/collection-toolbar.d.ts +5 -2
- package/dist/components/collection-toolbar.d.ts.map +1 -1
- package/dist/components/collection-toolbar.js +7 -4
- package/dist/components/combobox.d.ts +97 -22
- package/dist/components/combobox.d.ts.map +1 -1
- package/dist/components/combobox.js +80 -28
- package/dist/components/command.d.ts +34 -21
- package/dist/components/command.d.ts.map +1 -1
- package/dist/components/command.js +33 -25
- package/dist/components/confirm-dialog.d.ts +23 -6
- package/dist/components/confirm-dialog.d.ts.map +1 -1
- package/dist/components/confirm-dialog.js +32 -13
- package/dist/components/context-menu.d.ts +14 -10
- package/dist/components/context-menu.d.ts.map +1 -1
- package/dist/components/context-menu.js +17 -12
- package/dist/components/copy-button.d.ts +5 -2
- package/dist/components/copy-button.d.ts.map +1 -1
- package/dist/components/copy-button.js +16 -8
- package/dist/components/data-table.d.ts +120 -54
- package/dist/components/data-table.d.ts.map +1 -1
- package/dist/components/data-table.js +163 -92
- package/dist/components/desktop-shell.d.ts +4 -2
- package/dist/components/desktop-shell.d.ts.map +1 -1
- package/dist/components/desktop-shell.js +3 -3
- package/dist/components/dialog.d.ts +63 -24
- package/dist/components/dialog.d.ts.map +1 -1
- package/dist/components/dialog.js +52 -31
- package/dist/components/disclosure-row.d.ts +1 -2
- package/dist/components/disclosure-row.d.ts.map +1 -1
- package/dist/components/disclosure-row.js +1 -2
- package/dist/components/disclosure.d.ts +1 -1
- package/dist/components/disclosure.js +1 -1
- package/dist/components/drawer.d.ts +33 -12
- package/dist/components/drawer.d.ts.map +1 -1
- package/dist/components/drawer.js +47 -35
- package/dist/components/dropdown-menu.d.ts +59 -14
- package/dist/components/dropdown-menu.d.ts.map +1 -1
- package/dist/components/dropdown-menu.js +58 -26
- package/dist/components/empty-state.d.ts +35 -12
- package/dist/components/empty-state.d.ts.map +1 -1
- package/dist/components/empty-state.js +35 -17
- package/dist/components/entry-scene.d.ts +4 -4
- package/dist/components/entry-scene.d.ts.map +1 -1
- package/dist/components/entry-scene.js +2 -2
- package/dist/components/field.d.ts +44 -14
- package/dist/components/field.d.ts.map +1 -1
- package/dist/components/field.js +49 -20
- package/dist/components/file-diff.d.ts.map +1 -1
- package/dist/components/file-diff.js +3 -4
- package/dist/components/form-dialog.d.ts +7 -7
- package/dist/components/form-dialog.d.ts.map +1 -1
- package/dist/components/form-dialog.js +13 -11
- package/dist/components/form-drawer.d.ts +10 -7
- package/dist/components/form-drawer.d.ts.map +1 -1
- package/dist/components/form-drawer.js +11 -10
- package/dist/components/gauge.d.ts +64 -0
- package/dist/components/gauge.d.ts.map +1 -0
- package/dist/components/gauge.js +73 -0
- package/dist/components/hover-card.d.ts +72 -14
- package/dist/components/hover-card.d.ts.map +1 -1
- package/dist/components/hover-card.js +51 -17
- package/dist/components/identity-mark.d.ts +8 -1
- package/dist/components/identity-mark.d.ts.map +1 -1
- package/dist/components/identity-mark.js +31 -5
- package/dist/components/input-group.d.ts +44 -21
- package/dist/components/input-group.d.ts.map +1 -1
- package/dist/components/input-group.js +74 -27
- package/dist/components/input.d.ts +64 -12
- package/dist/components/input.d.ts.map +1 -1
- package/dist/components/input.js +51 -15
- package/dist/components/item.d.ts +37 -15
- package/dist/components/item.d.ts.map +1 -1
- package/dist/components/item.js +41 -22
- package/dist/components/kbd.d.ts +49 -13
- package/dist/components/kbd.d.ts.map +1 -1
- package/dist/components/kbd.js +115 -16
- package/dist/components/kpi-card.d.ts +12 -4
- package/dist/components/kpi-card.d.ts.map +1 -1
- package/dist/components/kpi-card.js +13 -4
- package/dist/components/label.d.ts +17 -10
- package/dist/components/label.d.ts.map +1 -1
- package/dist/components/label.js +18 -11
- package/dist/components/library-shelf.d.ts +6 -6
- package/dist/components/library-shelf.d.ts.map +1 -1
- package/dist/components/library-shelf.js +5 -5
- package/dist/components/load-more-button.d.ts +35 -0
- package/dist/components/load-more-button.d.ts.map +1 -0
- package/dist/components/load-more-button.js +26 -0
- package/dist/components/message-notice.d.ts +8 -13
- package/dist/components/message-notice.d.ts.map +1 -1
- package/dist/components/message-notice.js +25 -22
- package/dist/components/middle-truncate.d.ts +33 -0
- package/dist/components/middle-truncate.d.ts.map +1 -0
- package/dist/components/middle-truncate.js +72 -0
- package/dist/components/multi-select.d.ts +94 -0
- package/dist/components/multi-select.d.ts.map +1 -0
- package/dist/components/multi-select.js +132 -0
- package/dist/components/native-select.d.ts +37 -13
- package/dist/components/native-select.d.ts.map +1 -1
- package/dist/components/native-select.js +27 -11
- package/dist/components/notice-banner.d.ts +17 -10
- package/dist/components/notice-banner.d.ts.map +1 -1
- package/dist/components/notice-banner.js +12 -11
- package/dist/components/numbered-steps.d.ts +10 -4
- package/dist/components/numbered-steps.d.ts.map +1 -1
- package/dist/components/numbered-steps.js +9 -7
- package/dist/components/object-page.d.ts +40 -14
- package/dist/components/object-page.d.ts.map +1 -1
- package/dist/components/object-page.js +12 -10
- package/dist/components/object-workspace.d.ts +29 -10
- package/dist/components/object-workspace.d.ts.map +1 -1
- package/dist/components/object-workspace.js +18 -8
- package/dist/components/overview-page.d.ts +2 -2
- package/dist/components/overview-page.d.ts.map +1 -1
- package/dist/components/overview-page.js +8 -7
- package/dist/components/page-actions.d.ts +28 -8
- package/dist/components/page-actions.d.ts.map +1 -1
- package/dist/components/page-actions.js +22 -25
- package/dist/components/page-header.d.ts +11 -4
- package/dist/components/page-header.d.ts.map +1 -1
- package/dist/components/page-header.js +10 -5
- package/dist/components/pending-label.d.ts +6 -5
- package/dist/components/pending-label.d.ts.map +1 -1
- package/dist/components/pending-label.js +14 -6
- package/dist/components/picture-label.d.ts +2 -2
- package/dist/components/picture-label.d.ts.map +1 -1
- package/dist/components/picture-label.js +3 -3
- package/dist/components/portal-sidebar-frame.d.ts +9 -21
- package/dist/components/portal-sidebar-frame.d.ts.map +1 -1
- package/dist/components/portal-sidebar-frame.js +13 -27
- package/dist/components/progress-checklist.d.ts +46 -0
- package/dist/components/progress-checklist.d.ts.map +1 -0
- package/dist/components/progress-checklist.js +46 -0
- package/dist/components/progress.d.ts +48 -8
- package/dist/components/progress.d.ts.map +1 -1
- package/dist/components/progress.js +92 -16
- package/dist/components/prose.d.ts +19 -0
- package/dist/components/prose.d.ts.map +1 -0
- package/dist/components/prose.js +29 -0
- package/dist/components/radio-group.d.ts +51 -12
- package/dist/components/radio-group.d.ts.map +1 -1
- package/dist/components/radio-group.js +42 -12
- package/dist/components/reading-column.js +1 -1
- package/dist/components/record-identity.d.ts +6 -5
- package/dist/components/record-identity.d.ts.map +1 -1
- package/dist/components/record-identity.js +12 -3
- package/dist/components/record-list.d.ts +117 -27
- package/dist/components/record-list.d.ts.map +1 -1
- package/dist/components/record-list.js +185 -55
- package/dist/components/record-time.d.ts +20 -7
- package/dist/components/record-time.d.ts.map +1 -1
- package/dist/components/record-time.js +38 -19
- package/dist/components/resizable.d.ts +7 -5
- package/dist/components/resizable.d.ts.map +1 -1
- package/dist/components/resizable.js +6 -6
- package/dist/components/scope-switcher.d.ts +2 -0
- package/dist/components/scope-switcher.d.ts.map +1 -1
- package/dist/components/scope-switcher.js +2 -2
- package/dist/components/scroll-area.d.ts +47 -11
- package/dist/components/scroll-area.d.ts.map +1 -1
- package/dist/components/scroll-area.js +72 -14
- package/dist/components/segmented-control.d.ts +82 -0
- package/dist/components/segmented-control.d.ts.map +1 -0
- package/dist/components/segmented-control.js +90 -0
- package/dist/components/select.d.ts +55 -15
- package/dist/components/select.d.ts.map +1 -1
- package/dist/components/select.js +62 -19
- package/dist/components/separator.d.ts +12 -5
- package/dist/components/separator.d.ts.map +1 -1
- package/dist/components/separator.js +11 -6
- package/dist/components/settings-facts.d.ts +34 -14
- package/dist/components/settings-facts.d.ts.map +1 -1
- package/dist/components/settings-facts.js +21 -12
- package/dist/components/settings-page.d.ts +4 -4
- package/dist/components/settings-page.js +5 -5
- package/dist/components/settings-section.d.ts +160 -34
- package/dist/components/settings-section.d.ts.map +1 -1
- package/dist/components/settings-section.js +92 -39
- package/dist/components/sheet.d.ts +47 -16
- package/dist/components/sheet.d.ts.map +1 -1
- package/dist/components/sheet.js +40 -19
- package/dist/components/sidebar-sections.d.ts +16 -12
- package/dist/components/sidebar-sections.d.ts.map +1 -1
- package/dist/components/sidebar-sections.js +30 -15
- package/dist/components/sidebar.d.ts +117 -21
- package/dist/components/sidebar.d.ts.map +1 -1
- package/dist/components/sidebar.js +180 -55
- package/dist/components/skeleton.d.ts +54 -8
- package/dist/components/skeleton.d.ts.map +1 -1
- package/dist/components/skeleton.js +44 -9
- package/dist/components/slider.d.ts +53 -11
- package/dist/components/slider.d.ts.map +1 -1
- package/dist/components/slider.js +71 -17
- package/dist/components/snippet.d.ts +57 -0
- package/dist/components/snippet.d.ts.map +1 -0
- package/dist/components/snippet.js +60 -0
- package/dist/components/sonner.d.ts +13 -14
- package/dist/components/sonner.d.ts.map +1 -1
- package/dist/components/sonner.js +25 -22
- package/dist/components/status-badge.d.ts +37 -11
- package/dist/components/status-badge.d.ts.map +1 -1
- package/dist/components/status-badge.js +63 -15
- package/dist/components/status-dot.d.ts +42 -11
- package/dist/components/status-dot.d.ts.map +1 -1
- package/dist/components/status-dot.js +40 -11
- package/dist/components/switch.d.ts +43 -12
- package/dist/components/switch.d.ts.map +1 -1
- package/dist/components/switch.js +42 -12
- package/dist/components/table-card.d.ts +21 -12
- package/dist/components/table-card.d.ts.map +1 -1
- package/dist/components/table-card.js +17 -9
- package/dist/components/table-layouts.d.ts +40 -8
- package/dist/components/table-layouts.d.ts.map +1 -1
- package/dist/components/table-layouts.js +52 -8
- package/dist/components/table-value.d.ts +4 -3
- package/dist/components/table-value.d.ts.map +1 -1
- package/dist/components/table-value.js +6 -5
- package/dist/components/table.d.ts +62 -25
- package/dist/components/table.d.ts.map +1 -1
- package/dist/components/table.js +62 -26
- package/dist/components/tabs.d.ts +86 -17
- package/dist/components/tabs.d.ts.map +1 -1
- package/dist/components/tabs.js +93 -22
- package/dist/components/text-link.d.ts +4 -1
- package/dist/components/text-link.d.ts.map +1 -1
- package/dist/components/text-link.js +4 -1
- package/dist/components/text-with-copy-button.d.ts +30 -0
- package/dist/components/text-with-copy-button.d.ts.map +1 -0
- package/dist/components/text-with-copy-button.js +32 -0
- package/dist/components/textarea.d.ts +40 -10
- package/dist/components/textarea.d.ts.map +1 -1
- package/dist/components/textarea.js +50 -11
- package/dist/components/theme-mode-switcher.d.ts +18 -1
- package/dist/components/theme-mode-switcher.d.ts.map +1 -1
- package/dist/components/theme-mode-switcher.js +20 -2
- package/dist/components/toggle-group.d.ts +28 -8
- package/dist/components/toggle-group.d.ts.map +1 -1
- package/dist/components/toggle-group.js +12 -6
- package/dist/components/toggle.d.ts +6 -3
- package/dist/components/toggle.d.ts.map +1 -1
- package/dist/components/toggle.js +10 -7
- package/dist/components/tooltip.d.ts +43 -12
- package/dist/components/tooltip.d.ts.map +1 -1
- package/dist/components/tooltip.js +45 -16
- package/dist/components/trend-badge.js +1 -1
- package/dist/components/update-card.js +1 -1
- package/dist/eslint/index.js +82 -0
- package/dist/eslint/rules/badge-is-static-label.js +93 -0
- package/dist/eslint/rules/button-icon-slot.js +102 -0
- package/dist/eslint/rules/button-link-for-navigation.js +146 -0
- package/dist/eslint/rules/button-no-aria-label-with-text.js +75 -0
- package/dist/eslint/rules/button-type-roles-only-in-buttons.js +83 -0
- package/dist/eslint/rules/choice-control-has-a-name.js +98 -0
- package/dist/eslint/rules/choice-group-in-fieldset.js +86 -0
- package/dist/eslint/rules/command-shortcut-single-owner.js +118 -0
- package/dist/eslint/rules/confirm-dialog-words.js +63 -0
- package/dist/eslint/rules/data-table-one-unsized-column.js +96 -0
- package/dist/eslint/rules/destructive-action-placement.js +69 -0
- package/dist/eslint/rules/disabled-choice-says-why.js +71 -0
- package/dist/eslint/rules/ellipsis-opens-a-dialog.js +110 -0
- package/dist/eslint/rules/input-group-owners.js +155 -0
- package/dist/eslint/rules/kbd-children-no-modifier-text.js +128 -0
- package/dist/eslint/rules/literal-text.js +41 -0
- package/dist/eslint/rules/middle-truncate-placement.js +69 -0
- package/dist/eslint/rules/no-bare-button-label.js +55 -0
- package/dist/eslint/rules/no-control-in-read-only-surface.js +106 -0
- package/dist/eslint/rules/no-hand-built-busy.js +104 -0
- package/dist/eslint/rules/no-hand-built-theme-picker.js +144 -0
- package/dist/eslint/rules/no-hand-built-tile.js +41 -0
- package/dist/eslint/rules/no-hand-formatted-date.js +87 -0
- package/dist/eslint/rules/no-hand-stacked-avatars.js +67 -0
- package/dist/eslint/rules/no-nested-collapse.js +60 -0
- package/dist/eslint/rules/no-search-in-form.js +47 -0
- package/dist/eslint/rules/no-shadcn-appearance-override.js +2 -16
- package/dist/eslint/rules/no-shell-prompt-in-snippet.js +74 -0
- package/dist/eslint/rules/no-stock-error-words.js +56 -0
- package/dist/eslint/rules/no-tooltip-around-labelled-field.js +72 -0
- package/dist/eslint/rules/no-weight-class-on-strong-in-type-role.js +57 -0
- package/dist/eslint/rules/one-submenu-level.js +43 -0
- package/dist/eslint/rules/one-toast-per-flow.js +91 -0
- package/dist/eslint/rules/option-count.js +167 -0
- package/dist/eslint/rules/page-command-link-not-render.js +43 -0
- package/dist/eslint/rules/progress-needs-name.js +57 -0
- package/dist/eslint/rules/settings-limit-in-footer.js +94 -0
- package/dist/eslint/rules/skeleton-in-region.js +80 -0
- package/dist/eslint/rules/sortable-heading-uses-sort.js +79 -0
- package/dist/eslint/rules/table-cell-inset-owner.js +107 -0
- package/dist/eslint/rules/tabs-selection-is-controlled.js +47 -0
- package/dist/eslint/rules/tooltip-only-arrow.js +38 -0
- package/dist/eslint/rules/tooltip-trigger-accessible-name.js +114 -0
- package/dist/eslint/strict-design-system.js +21 -7
- package/dist/index.d.ts +13 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -13
- package/dist/internal/assistant-ui/attachment.d.ts.map +1 -1
- package/dist/internal/assistant-ui/attachment.js +2 -2
- package/dist/internal/assistant-ui/reasoning.d.ts +1 -1
- package/dist/internal/assistant-ui/reasoning.d.ts.map +1 -1
- package/dist/internal/assistant-ui/tool-fallback.js +1 -1
- package/dist/internal/assistant-ui/tool-group.d.ts +1 -1
- package/dist/internal/assistant-ui/tool-group.d.ts.map +1 -1
- package/dist/internal/assistant-ui/tooltip-icon-button.d.ts +2 -3
- package/dist/internal/assistant-ui/tooltip-icon-button.d.ts.map +1 -1
- package/dist/internal/assistant-ui/tooltip-icon-button.js +1 -1
- package/dist/internal/catalog-list.js +2 -2
- package/dist/internal/collection-note.d.ts +23 -0
- package/dist/internal/collection-note.d.ts.map +1 -0
- package/dist/internal/collection-note.js +17 -0
- package/dist/internal/collection-rail.d.ts +57 -0
- package/dist/internal/collection-rail.d.ts.map +1 -0
- package/dist/internal/collection-rail.js +33 -0
- package/dist/internal/company-logo.d.ts +18 -0
- package/dist/internal/company-logo.d.ts.map +1 -0
- package/dist/internal/company-logo.js +14 -0
- package/dist/internal/control-name.d.ts +12 -0
- package/dist/internal/control-name.d.ts.map +1 -0
- package/dist/internal/control-name.js +1 -0
- package/dist/internal/diff-line.d.ts +9 -0
- package/dist/internal/diff-line.d.ts.map +1 -0
- package/dist/internal/diff-line.js +8 -0
- package/dist/internal/empty.d.ts +8 -4
- package/dist/internal/empty.d.ts.map +1 -1
- package/dist/internal/empty.js +14 -8
- package/dist/internal/field-frame.d.ts +33 -0
- package/dist/internal/field-frame.d.ts.map +1 -0
- package/dist/internal/field-frame.js +20 -0
- package/dist/internal/final-focus.d.ts +8 -0
- package/dist/internal/final-focus.d.ts.map +1 -0
- package/dist/internal/final-focus.js +10 -0
- package/dist/internal/footer-strip.d.ts.map +1 -1
- package/dist/internal/footer-strip.js +3 -1
- package/dist/internal/form-submit.d.ts +9 -5
- package/dist/internal/form-submit.d.ts.map +1 -1
- package/dist/internal/form-submit.js +31 -2
- package/dist/internal/input-box.d.ts +26 -0
- package/dist/internal/input-box.d.ts.map +1 -0
- package/dist/internal/input-box.js +59 -0
- package/dist/internal/menu-surface.d.ts +10 -3
- package/dist/internal/menu-surface.d.ts.map +1 -1
- package/dist/internal/menu-surface.js +10 -3
- package/dist/internal/notice.d.ts +25 -0
- package/dist/internal/notice.d.ts.map +1 -0
- package/dist/internal/notice.js +33 -0
- package/dist/internal/overlay-stem.d.ts +5 -0
- package/dist/internal/overlay-stem.d.ts.map +1 -0
- package/dist/internal/overlay-stem.js +7 -0
- package/dist/internal/phone-sheet.d.ts +4 -0
- package/dist/internal/phone-sheet.d.ts.map +1 -0
- package/dist/internal/phone-sheet.js +2 -0
- package/dist/internal/present-content.d.ts +3 -0
- package/dist/internal/present-content.d.ts.map +1 -0
- package/dist/internal/present-content.js +1 -0
- package/dist/internal/record-menu-items.d.ts +4 -3
- package/dist/internal/record-menu-items.d.ts.map +1 -1
- package/dist/internal/record-menu-items.js +21 -6
- package/dist/internal/settings-save.d.ts +9 -2
- package/dist/internal/settings-save.d.ts.map +1 -1
- package/dist/internal/settings-save.js +19 -6
- package/dist/internal/table-compact-line.d.ts +38 -0
- package/dist/internal/table-compact-line.d.ts.map +1 -0
- package/dist/internal/table-compact-line.js +35 -0
- package/dist/internal/title-when-cut.d.ts +8 -0
- package/dist/internal/title-when-cut.d.ts.map +1 -0
- package/dist/internal/title-when-cut.js +22 -0
- package/dist/internal/unsaved-guard.d.ts +18 -0
- package/dist/internal/unsaved-guard.d.ts.map +1 -0
- package/dist/internal/unsaved-guard.js +31 -0
- package/dist/lib/merge-tokens.generated.js +2 -2
- package/dist/showcase/foundations.d.ts.map +1 -1
- package/dist/showcase/foundations.js +10 -2
- package/dist/showcase/specimens/actions.d.ts +2 -0
- package/dist/showcase/specimens/actions.d.ts.map +1 -1
- package/dist/showcase/specimens/actions.js +30 -5
- package/dist/showcase/specimens/charts.d.ts.map +1 -1
- package/dist/showcase/specimens/charts.js +22 -13
- package/dist/showcase/specimens/choices.d.ts +14 -3
- package/dist/showcase/specimens/choices.d.ts.map +1 -1
- package/dist/showcase/specimens/choices.js +93 -13
- package/dist/showcase/specimens/compositions.d.ts.map +1 -1
- package/dist/showcase/specimens/compositions.js +136 -23
- package/dist/showcase/specimens/data.d.ts +12 -7
- package/dist/showcase/specimens/data.d.ts.map +1 -1
- package/dist/showcase/specimens/data.js +139 -35
- package/dist/showcase/specimens/feedback.d.ts +2 -0
- package/dist/showcase/specimens/feedback.d.ts.map +1 -1
- package/dist/showcase/specimens/feedback.js +39 -15
- package/dist/showcase/specimens/index.d.ts +20 -12
- package/dist/showcase/specimens/index.d.ts.map +1 -1
- package/dist/showcase/specimens/inputs.d.ts +4 -2
- package/dist/showcase/specimens/inputs.d.ts.map +1 -1
- package/dist/showcase/specimens/inputs.js +62 -19
- package/dist/showcase/specimens/menus.d.ts +0 -1
- package/dist/showcase/specimens/menus.d.ts.map +1 -1
- package/dist/showcase/specimens/menus.js +47 -17
- package/dist/showcase/specimens/navigation.d.ts +6 -4
- package/dist/showcase/specimens/navigation.d.ts.map +1 -1
- package/dist/showcase/specimens/navigation.js +61 -32
- package/dist/showcase/specimens/other.d.ts +1 -3
- package/dist/showcase/specimens/other.d.ts.map +1 -1
- package/dist/showcase/specimens/other.js +17 -13
- package/dist/showcase/specimens/status.d.ts +4 -1
- package/dist/showcase/specimens/status.d.ts.map +1 -1
- package/dist/showcase/specimens/status.js +64 -11
- package/dist/showcase/usage.generated.d.ts +1 -1
- package/dist/showcase/usage.generated.d.ts.map +1 -1
- package/dist/showcase/usage.generated.js +632 -544
- package/dist/standalone/index.js +1 -1
- package/dist/styles/components.css +13 -13
- package/dist/styles/globals.css +25 -0
- package/package.json +2 -3
- package/dist/components/approval-row.d.ts +0 -34
- package/dist/components/approval-row.d.ts.map +0 -1
- package/dist/components/approval-row.js +0 -27
- package/dist/components/channel-view.d.ts +0 -112
- package/dist/components/channel-view.d.ts.map +0 -1
- package/dist/components/channel-view.js +0 -84
- package/dist/components/dashboard-shell.d.ts +0 -51
- package/dist/components/dashboard-shell.d.ts.map +0 -1
- package/dist/components/dashboard-shell.js +0 -89
- package/dist/components/direction.d.ts +0 -2
- package/dist/components/direction.d.ts.map +0 -1
- package/dist/components/direction.js +0 -1
- package/dist/components/expandable-block.d.ts +0 -20
- package/dist/components/expandable-block.d.ts.map +0 -1
- package/dist/components/expandable-block.js +0 -32
- package/dist/components/form.d.ts +0 -42
- package/dist/components/form.d.ts.map +0 -1
- package/dist/components/form.js +0 -91
- package/dist/components/label-system.d.ts +0 -17
- package/dist/components/label-system.d.ts.map +0 -1
- package/dist/components/label-system.js +0 -21
- package/dist/components/memory-item.d.ts +0 -21
- package/dist/components/memory-item.d.ts.map +0 -1
- package/dist/components/memory-item.js +0 -18
- package/dist/components/menubar.d.ts +0 -43
- package/dist/components/menubar.d.ts.map +0 -1
- package/dist/components/menubar.js +0 -69
- package/dist/components/navigation-menu.d.ts +0 -26
- package/dist/components/navigation-menu.d.ts.map +0 -1
- package/dist/components/navigation-menu.js +0 -45
- package/dist/components/pagination.d.ts +0 -33
- package/dist/components/pagination.d.ts.map +0 -1
- package/dist/components/pagination.js +0 -41
- package/dist/components/plugin-slot-boundary.d.ts +0 -42
- package/dist/components/plugin-slot-boundary.d.ts.map +0 -1
- package/dist/components/plugin-slot-boundary.js +0 -41
- package/dist/components/status-row.d.ts +0 -32
- package/dist/components/status-row.d.ts.map +0 -1
- package/dist/components/status-row.js +0 -35
|
@@ -1,57 +1,113 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type SettingsSave } from "../internal/settings-save.js";
|
|
3
3
|
import { Field } from "./field.js";
|
|
4
|
+
import { Switch } from "./switch.js";
|
|
4
5
|
export type { SettingsSave, SettingsSaveFailure } from "../internal/settings-save.js";
|
|
5
6
|
export type SettingsFieldControlProps = {
|
|
6
7
|
id: string;
|
|
8
|
+
"aria-labelledby": string;
|
|
7
9
|
"aria-invalid"?: true;
|
|
8
10
|
"aria-describedby"?: string;
|
|
9
11
|
disabled?: boolean;
|
|
10
12
|
required?: boolean;
|
|
11
13
|
};
|
|
12
|
-
export type
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
export type SettingsSectionTone = "error" | "warning";
|
|
15
|
+
export type SettingsHeaderSwitch = Pick<React.ComponentProps<typeof Switch>, "checked" | "defaultChecked" | "onCheckedChange" | "disabled" | "name">;
|
|
16
|
+
type SettingsInfo = {
|
|
17
|
+
/** Names the (i) button: "About build command". */
|
|
18
|
+
label: string;
|
|
19
|
+
/** One sentence, shown in a tooltip and read with the control. */
|
|
20
|
+
text: string;
|
|
21
|
+
};
|
|
22
|
+
type SettingsSectionBase = Omit<React.ComponentProps<"section">, "title" | "children"> & {
|
|
23
|
+
/** One line saying what changing it does. It is the card's only help: no field carries its own. */
|
|
15
24
|
description: string;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
|
|
25
|
+
};
|
|
26
|
+
type Titled = {
|
|
27
|
+
/** The section's h2, on every card. */
|
|
28
|
+
title: string;
|
|
20
29
|
children?: React.ReactNode;
|
|
21
|
-
}
|
|
30
|
+
};
|
|
31
|
+
type SavingSection = Titled & {
|
|
22
32
|
save: SettingsSave;
|
|
23
33
|
footer?: never;
|
|
24
34
|
footerHint?: never;
|
|
25
|
-
|
|
35
|
+
tone?: never;
|
|
36
|
+
lockedReason?: never;
|
|
37
|
+
unlock?: never;
|
|
38
|
+
headerSwitch?: never;
|
|
39
|
+
/** A control on the section's own header: an avatar's upload. */
|
|
40
|
+
actions?: React.ReactNode;
|
|
41
|
+
};
|
|
42
|
+
type FooterSection = Titled & {
|
|
26
43
|
save?: never;
|
|
44
|
+
/** The buttons on the footer's right. */
|
|
27
45
|
footer?: React.ReactNode;
|
|
46
|
+
/** What is specific to this card, on the footer's left: a limit, what a value is for, a plan it needs, a link. Absent: nothing. */
|
|
28
47
|
footerHint?: React.ReactNode;
|
|
29
|
-
|
|
48
|
+
/** A condition of the whole card: 1px border, a tinted footer; the title, line, fields and buttons stay neutral. */
|
|
49
|
+
tone?: SettingsSectionTone;
|
|
50
|
+
lockedReason?: never;
|
|
51
|
+
unlock?: never;
|
|
52
|
+
headerSwitch?: never;
|
|
53
|
+
/** A button or a badge on the section's own header. A switch is `headerSwitch`. */
|
|
54
|
+
actions?: React.ReactNode;
|
|
55
|
+
};
|
|
56
|
+
type SwitchedSection = Titled & {
|
|
57
|
+
save?: never;
|
|
58
|
+
footer?: never;
|
|
59
|
+
/** What is specific to this card, on the footer's left: a limit, what a value is for, a plan it needs, a link. Absent: nothing. */
|
|
60
|
+
footerHint?: React.ReactNode;
|
|
61
|
+
tone?: never;
|
|
62
|
+
lockedReason?: never;
|
|
63
|
+
unlock?: never;
|
|
64
|
+
actions?: never;
|
|
65
|
+
/** The switch that is the whole card, at the title's right, named by the title; it applies at once. */
|
|
66
|
+
headerSwitch: SettingsHeaderSwitch;
|
|
67
|
+
};
|
|
68
|
+
type LockedSection = Titled & {
|
|
69
|
+
save?: never;
|
|
70
|
+
footer?: never;
|
|
71
|
+
footerHint?: never;
|
|
72
|
+
tone?: never;
|
|
73
|
+
/** Why the person may not change this section: the plan that has it, the role it needs. */
|
|
74
|
+
lockedReason: string | React.ReactElement;
|
|
75
|
+
/** The way to get access: an Upgrade button, a Contact sales link. Left out when nothing the person does unlocks it. */
|
|
76
|
+
unlock?: React.ReactNode;
|
|
77
|
+
headerSwitch?: never;
|
|
78
|
+
actions?: never;
|
|
79
|
+
};
|
|
80
|
+
type UntitledSection = {
|
|
81
|
+
/** Left out only on a card with no control, whose description then names it. */
|
|
82
|
+
title?: undefined;
|
|
83
|
+
children?: undefined;
|
|
84
|
+
save?: never;
|
|
85
|
+
footer?: never;
|
|
86
|
+
/** What is specific to this card, on the footer's left: a limit, what a value is for, a plan it needs, a link. Absent: nothing. */
|
|
87
|
+
footerHint?: React.ReactNode;
|
|
88
|
+
tone?: never;
|
|
89
|
+
lockedReason?: never;
|
|
90
|
+
unlock?: never;
|
|
91
|
+
headerSwitch?: never;
|
|
92
|
+
actions?: never;
|
|
93
|
+
};
|
|
94
|
+
export type SettingsSectionProps = SettingsSectionBase & (SavingSection | FooterSection | SwitchedSection | LockedSection | UntitledSection);
|
|
95
|
+
export type SavingSettingsSectionProps = SettingsSectionBase & SavingSection;
|
|
30
96
|
/**
|
|
31
|
-
* A card of
|
|
97
|
+
* A card of one setting that says what changing it does and ends in a footer.
|
|
32
98
|
*
|
|
33
99
|
* @family Compositions
|
|
34
|
-
* @when
|
|
35
|
-
* @instead Read-only
|
|
36
|
-
* @behaviour
|
|
37
|
-
* @words The title names the values ("Personal details"); the description says what changing them does, in one line; the
|
|
38
|
-
* @access
|
|
100
|
+
* @when One setting a person changes on a SettingsPage or as a section of an ObjectPage: Personal details, Company identity, Notifications. A typed value takes `save`; a switch or a short reversible choice applies at once through its own control's change, with no Save. Also a plan-gated feature, a delete card, one read-only value (an ID in a read-only mono InputGroup with its copy button, no Save), and a paid quantity (its stepper field, the price as the description, a two-fact summary under it).
|
|
101
|
+
* @instead Read-only facts of an object are a SettingsFactsSection; a table or a list of records is a TableCard; Theme and Language live in the account menu; a record's edit in a list is a RowEditForm.
|
|
102
|
+
* @behaviour "Groups related form controls inside a bordered card with optional footer actions." (https://vercel.com/geist/fieldset) Ours: one setting per card: a single SettingsField, the description its only help. One more shape exists, declared by a part and never by classes at the call site. A card of several settings holds SettingsRows, label left and control right, only when every row is a switch or every row is a select. "Use Toggle for a single boolean setting where ON takes effect immediately, like `Password Protection` or `Auto-Cancel Builds`." (https://vercel.com/geist/toggle) "Pair with a form footer only when the setting needs an explicit `Save` step." (https://vercel.com/geist/toggle) "Disable Toggle only when the action is impossible (missing plan, locked policy); pair with helper text or a `Tooltip` that names the resolver." (https://vercel.com/geist/toggle) Ours: that switch is `headerSwitch`: at the title's right, named by the title, the footer holding only its line, no Save; a switch blocked from above is shown off and disabled, the footer saying why and never a tooltip. Required: the title and the description. The header's actions stand at the title's right; on a card narrower than 28 rem they keep the title's row and the description runs under both, as Vercel's cards read on a phone. The footer's left line (`footerHint`, `save.hint`) is optional and specific to the card, never a generic line repeated on every card: a limit, what a value is for, a plan it needs, a link; absent, it is nothing, and a card with neither a line nor a button has no footer. Ours: `save`: a typed value, one card with Save. Save stays disabled until a field differs from what is saved and says `pendingLabel` while saving with Cancel beside it; a completed save calls `saved`, and the product raises one toast from its catalogue ("Completion toasts follow `{Noun} {past-participle}`: `Blob deleted`, `Domain added`, `Environment variable saved`. Never include `successfully`; the action name implies it." https://vercel.com/geist/toast), and Save returns to disabled. Ours: the section never raises a toast itself. A failed save keeps every value and shows under its field, or above the footer when no field owns it. `tone` marks a state with a command (a failed payment, a trial ending): a 1px border and a footer tinted in the hue with its line in it; title, line, fields and buttons stay neutral, an outline secondary then a default primary. A button takes the hue of its command, not of the card: `destructive` for a permanent loss, `warning` for a disruptive command that can be undone. A delete card is `tone="error"` with the object's summary as its body; an archive card is neutral with a `warning` button in the footer. "Use a Note for inline contextual feedback next to the field, card, or section it describes: a region change warning above a region picker, a rate-limit notice next to a usage gauge." (https://vercel.com/geist/note) "One Note per concept." (https://vercel.com/geist/note) Ours: a message about the fields inside is a MessageNotice in the body, the card staying neutral. "Disabled checkboxes still need a Tooltip naming the reason; a greyed box with no explanation reads as a bug." (https://vercel.com/geist/checkbox) Ours: `lockedReason` is the reason, in the card, not in a tooltip; it keeps the fields in view, inert with muted text, under a not-allowed cursor, the title and line unchanged; `unlock` is the way to get access, left out when nothing the person does unlocks it.
|
|
103
|
+
* @words "Helper text is sentence case, one sentence with a trailing period, on a sibling element wired through `aria-describedby`." (https://vercel.com/geist/input) Ours: the description is that helper text for the whole card, and no field has its own. "Render an optional one-sentence description as a sibling under the label that explains ON only. Don’t describe OFF; it’s the negation." (https://vercel.com/geist/toggle) Ours: a header-switch card's description says what turning it on does. The title names the values ("Personal details"); the description says what changing them does, in one line; the footer line is a Learn more link, a limit ("Use 32 characters at most."), what stays unaffected, or what is blocked and why ("Ask an owner to change this."); Save and Saving come from the product's catalogue, and so does the toast a `saved` callback raises; a delete card's description opens "Permanently delete".
|
|
104
|
+
* @access "Provide an accessible name through `children`, `aria-label`, or `aria-labelledby`." (https://vercel.com/geist/toggle) Ours: the title is the section's h2 and names the form that saves it, and the header switch. The footer's line is one status, announced politely; a failure under a field marks the control invalid and describes it. Locked fields are inert, so the section's title, description and reason are what a screen reader meets.
|
|
39
105
|
*/
|
|
40
|
-
declare function SettingsSection({ title, description, actions,
|
|
41
|
-
|
|
42
|
-
* One setting: its label and help above its control, and what went wrong under it.
|
|
43
|
-
*
|
|
44
|
-
* @family Inputs
|
|
45
|
-
* @when A value inside a SettingsSection: a name, an address, a choice, a switch.
|
|
46
|
-
* @instead A field of a drawer's or a dialog's form is a Field from the form's own owner; a read-only value is a fact in a SettingsFactsSection.
|
|
47
|
-
* @behaviour The control is 20rem wide under its label and help by default; a switch row passes `orientation="horizontal"` and sits at the end of its label's row at its own width. A validation `error`, or a failed save about this field, shows under the control and marks it invalid.
|
|
48
|
-
* @words The label is a noun for the value ("Display name"); the help is one line saying what it is for or where it shows; an error says what to do next.
|
|
49
|
-
* @access The control receives its id, `aria-invalid` and `aria-describedby` through `controlProps`, so the label, help and error are read with it.
|
|
50
|
-
*/
|
|
51
|
-
declare function SettingsField({ id, label, description, error, invalid, disabled, required, orientation, children, className, contentClassName, controlClassName, controlWidth, ...props }: Omit<React.ComponentProps<typeof Field>, "children"> & {
|
|
106
|
+
declare function SettingsSection({ title, description, actions, headerSwitch, tone, children, className, save, footer, footerHint, lockedReason, unlock, ...props }: SettingsSectionProps): React.JSX.Element;
|
|
107
|
+
type SettingsFieldBase = Omit<React.ComponentProps<typeof Field>, "children" | "orientation"> & {
|
|
52
108
|
id: string;
|
|
53
|
-
label: React.ReactNode
|
|
54
|
-
|
|
109
|
+
label: NonNullable<React.ReactNode>;
|
|
110
|
+
info?: SettingsInfo;
|
|
55
111
|
error?: React.ReactNode;
|
|
56
112
|
invalid?: boolean;
|
|
57
113
|
disabled?: boolean;
|
|
@@ -59,9 +115,79 @@ declare function SettingsField({ id, label, description, error, invalid, disable
|
|
|
59
115
|
children: (props: {
|
|
60
116
|
controlProps: SettingsFieldControlProps;
|
|
61
117
|
}) => React.ReactNode;
|
|
62
|
-
|
|
63
|
-
|
|
118
|
+
};
|
|
119
|
+
type SettingsFieldProps = SettingsFieldBase & ({
|
|
120
|
+
/** A text box, a textarea, a select or a combobox: the label above it. */
|
|
121
|
+
control?: "box";
|
|
64
122
|
controlWidth?: "natural" | "standard" | "full";
|
|
65
|
-
|
|
66
|
-
|
|
123
|
+
stateLabel?: never;
|
|
124
|
+
} | {
|
|
125
|
+
/** A checkbox or a radio with its sentence beside it. */
|
|
126
|
+
control: "choice";
|
|
127
|
+
controlWidth?: never;
|
|
128
|
+
stateLabel?: never;
|
|
129
|
+
} | {
|
|
130
|
+
/** A switch followed by the word for its state, as a draft the card's Save applies. */
|
|
131
|
+
control: "switch";
|
|
132
|
+
controlWidth?: never;
|
|
133
|
+
/** "Enabled" or "Disabled", whichever the switch shows now. */
|
|
134
|
+
stateLabel: string;
|
|
135
|
+
});
|
|
136
|
+
/**
|
|
137
|
+
* One setting: its label above its control, and what went wrong under it.
|
|
138
|
+
*
|
|
139
|
+
* @family Inputs
|
|
140
|
+
* @when The one value of a SettingsSection: a name, an address, a choice, a switch.
|
|
141
|
+
* @instead A field of a drawer's or a dialog's form is a Field from the form's own owner; a read-only fact is a SettingsFactsSection; several switches or selects in one card are SettingsRows; a switch that is the whole card and applies at once is the section's `headerSwitch`.
|
|
142
|
+
* @behaviour "Helper text is sentence case, one sentence with a trailing period, on a sibling element wired through `aria-describedby`." (https://vercel.com/geist/input) Ours: label required, no help line: the card's description helps, and the (i) `info` is for a part of a value that needs a sentence. The control is 20rem wide under its label (`controlWidth`: `full` for a textarea, `natural` for a segmented control). `control="choice"` puts a checkbox or radio before its sentence; `control="switch"` puts the word for the switch's state after it and requires `stateLabel`. "Validate on blur, not on every keystroke; surface the message by passing a string to `error`." (https://vercel.com/geist/input) Ours: a validation `error` updates as the value is corrected, and it or a failed save about this field shows under the control and marks it invalid; colour sits on the control's edge and the message, never the label.
|
|
143
|
+
* @words "Labels are short Title Case nouns: `Project Name`, `Domain`, `Environment Variable Name`." (https://vercel.com/geist/input) Ours: sentence case, a noun for the value ("Display name"). "Validation names the field and the constraint, ends in a period, and skips `please` (`Project name is required.`, `Code must be 6 digits.`)." (https://vercel.com/geist/input) Ours: an error says what to do next; `info.text` is one sentence and `info.label` names its button ("About display name"); a switch shows its state word ("Enabled", "Disabled") beside it.
|
|
144
|
+
* @access "Don’t wrap a labelled `<Input>` in a `Tooltip`; put the explainer on a sibling icon button so the label stays announced." (https://vercel.com/geist/input) Ours: that sibling button is the (i) `info`. The control receives its id, `aria-invalid` and `aria-describedby` through `controlProps`, so the label, the info and the error are read with it. The info button has its own name and opens on focus.
|
|
145
|
+
*/
|
|
146
|
+
declare function SettingsField({ id, label, info, error, invalid, disabled, required, control, controlWidth, stateLabel, children, className, ...props }: SettingsFieldProps): React.JSX.Element;
|
|
147
|
+
type SettingsRowBase = {
|
|
148
|
+
id: string;
|
|
149
|
+
label: string;
|
|
150
|
+
/** Every row has its (i): the card's description covers the group, the tooltip covers the row. */
|
|
151
|
+
info: SettingsInfo;
|
|
152
|
+
error?: React.ReactNode;
|
|
153
|
+
disabled?: boolean;
|
|
154
|
+
name?: string;
|
|
155
|
+
};
|
|
156
|
+
type SettingsSwitchRow = SettingsRowBase & {
|
|
157
|
+
checked: boolean;
|
|
158
|
+
onCheckedChange: (checked: boolean) => void;
|
|
159
|
+
};
|
|
160
|
+
type SettingsSelectRow = SettingsRowBase & {
|
|
161
|
+
value: string;
|
|
162
|
+
onValueChange: (value: string) => void;
|
|
163
|
+
options: readonly {
|
|
164
|
+
value: string;
|
|
165
|
+
label: string;
|
|
166
|
+
}[];
|
|
167
|
+
};
|
|
168
|
+
type SettingsRowsProps = {
|
|
169
|
+
kind: "switch";
|
|
170
|
+
/** The word beside each switch for its state: "Enabled" and "Disabled". */
|
|
171
|
+
stateLabels: {
|
|
172
|
+
on: string;
|
|
173
|
+
off: string;
|
|
174
|
+
};
|
|
175
|
+
rows: readonly SettingsSwitchRow[];
|
|
176
|
+
} | {
|
|
177
|
+
kind: "select";
|
|
178
|
+
stateLabels?: never;
|
|
179
|
+
rows: readonly SettingsSelectRow[];
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* Several switches, or several selects, in one card: each row its label on the left and its control on the right.
|
|
183
|
+
*
|
|
184
|
+
* @family Inputs
|
|
185
|
+
* @when A card of settings of one kind, all switches or all selects, that the card's one description covers: a project's Git switches, a team's notification channels, a set of defaults.
|
|
186
|
+
* @instead One setting is a SettingsField. Fields of different kinds, text boxes among them, are one card each. A switch that is the whole card and applies at once is the section's `headerSwitch`.
|
|
187
|
+
* @behaviour Declares `kind` once; every row is that kind, so a card cannot mix a switch with a select. Required on every row: the label and its `info` (an (i) with its sentence in a tooltip and on the control); no help line sits under a row. A switch row shows its state word beside the switch (`stateLabels`) and is controlled, so the word always follows the switch. Rows stand 16 px apart; below 28rem a row stacks its control under its label. "Pair with a form footer only when the setting needs an explicit `Save` step." (https://vercel.com/geist/toggle) Ours: a switch in a card with a Save is a draft the Save applies; in a card without one it applies at once through its `onCheckedChange`, and the card's footer holds only its line, if it has one.
|
|
188
|
+
* @words "Title Case noun phrase, 1–4 words, naming what is true when ON: `Password Protection`, not `Enable Password Protection`." (https://vercel.com/geist/toggle) Ours: sentence case, a noun for what it controls ("Pull request comments"), the same for a switch as for a select. "Render an optional one-sentence description as a sibling under the label that explains ON only. Don’t describe OFF; it’s the negation." (https://vercel.com/geist/toggle) Ours: that sentence is `info.text`. "Options are Title Case when short and match canonical branding (`Next.js`, not `NextJS`); keep the same register across the list." (https://vercel.com/geist/select) Ours: a select's options are sentence case.
|
|
189
|
+
* @access Each row's control is named by the row's label and described by its info and its error. The info button has its own name and opens on focus.
|
|
190
|
+
*/
|
|
191
|
+
declare function SettingsRows(props: SettingsRowsProps): React.JSX.Element;
|
|
192
|
+
export { SettingsField, SettingsRows, SettingsSection };
|
|
67
193
|
//# sourceMappingURL=settings-section.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-section.d.ts","sourceRoot":"","sources":["../../src/components/settings-section.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"settings-section.d.ts","sourceRoot":"","sources":["../../src/components/settings-section.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,56 +1,109 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Info } from "lucide-react";
|
|
2
3
|
import * as React from "react";
|
|
3
4
|
import { cn } from "../lib/utils.js";
|
|
4
5
|
import { FooterStrip } from "../internal/footer-strip.js";
|
|
5
6
|
import { SettingsFieldFailure, SettingsSaveForm, } from "../internal/settings-save.js";
|
|
7
|
+
import { Button } from "./button.js";
|
|
6
8
|
import { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle } from "./card.js";
|
|
7
|
-
import { Field, FieldContent,
|
|
9
|
+
import { Field, FieldContent, FieldError, FieldGroup, FieldLabel } from "./field.js";
|
|
10
|
+
import { NativeSelect, NativeSelectOption } from "./native-select.js";
|
|
11
|
+
import { Switch } from "./switch.js";
|
|
12
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "./tooltip.js";
|
|
13
|
+
const toneClassNames = {
|
|
14
|
+
error: "border border-destructive *:data-[slot=card-footer]:border-destructive *:data-[slot=card-footer]:bg-destructive-soft *:data-[slot=card-footer]:*:data-[slot=settings-section-hint]:text-destructive-soft-foreground",
|
|
15
|
+
warning: "border border-warning *:data-[slot=card-footer]:border-warning *:data-[slot=card-footer]:bg-warning-soft *:data-[slot=card-footer]:*:data-[slot=settings-section-hint]:text-warning-soft-foreground",
|
|
16
|
+
};
|
|
17
|
+
/** Below a 28 rem card the actions keep the title's row and the description takes the card's width under both. */
|
|
18
|
+
const ACTIONS_ON_TITLE_ROW_WHEN_NARROW = "@max-md/settings-section:[&>[data-slot=card-action]]:row-span-1 @max-md/settings-section:[&>[data-slot=card-action]]:row-start-1 @max-md/settings-section:[&>[data-slot=card-description]]:col-span-2 @max-md/settings-section:[&>[data-slot=card-description]]:col-start-1";
|
|
8
19
|
/**
|
|
9
|
-
* A card of
|
|
20
|
+
* A card of one setting that says what changing it does and ends in a footer.
|
|
10
21
|
*
|
|
11
22
|
* @family Compositions
|
|
12
|
-
* @when
|
|
13
|
-
* @instead Read-only
|
|
14
|
-
* @behaviour
|
|
15
|
-
* @words The title names the values ("Personal details"); the description says what changing them does, in one line; the
|
|
16
|
-
* @access
|
|
23
|
+
* @when One setting a person changes on a SettingsPage or as a section of an ObjectPage: Personal details, Company identity, Notifications. A typed value takes `save`; a switch or a short reversible choice applies at once through its own control's change, with no Save. Also a plan-gated feature, a delete card, one read-only value (an ID in a read-only mono InputGroup with its copy button, no Save), and a paid quantity (its stepper field, the price as the description, a two-fact summary under it).
|
|
24
|
+
* @instead Read-only facts of an object are a SettingsFactsSection; a table or a list of records is a TableCard; Theme and Language live in the account menu; a record's edit in a list is a RowEditForm.
|
|
25
|
+
* @behaviour "Groups related form controls inside a bordered card with optional footer actions." (https://vercel.com/geist/fieldset) Ours: one setting per card: a single SettingsField, the description its only help. One more shape exists, declared by a part and never by classes at the call site. A card of several settings holds SettingsRows, label left and control right, only when every row is a switch or every row is a select. "Use Toggle for a single boolean setting where ON takes effect immediately, like `Password Protection` or `Auto-Cancel Builds`." (https://vercel.com/geist/toggle) "Pair with a form footer only when the setting needs an explicit `Save` step." (https://vercel.com/geist/toggle) "Disable Toggle only when the action is impossible (missing plan, locked policy); pair with helper text or a `Tooltip` that names the resolver." (https://vercel.com/geist/toggle) Ours: that switch is `headerSwitch`: at the title's right, named by the title, the footer holding only its line, no Save; a switch blocked from above is shown off and disabled, the footer saying why and never a tooltip. Required: the title and the description. The header's actions stand at the title's right; on a card narrower than 28 rem they keep the title's row and the description runs under both, as Vercel's cards read on a phone. The footer's left line (`footerHint`, `save.hint`) is optional and specific to the card, never a generic line repeated on every card: a limit, what a value is for, a plan it needs, a link; absent, it is nothing, and a card with neither a line nor a button has no footer. Ours: `save`: a typed value, one card with Save. Save stays disabled until a field differs from what is saved and says `pendingLabel` while saving with Cancel beside it; a completed save calls `saved`, and the product raises one toast from its catalogue ("Completion toasts follow `{Noun} {past-participle}`: `Blob deleted`, `Domain added`, `Environment variable saved`. Never include `successfully`; the action name implies it." https://vercel.com/geist/toast), and Save returns to disabled. Ours: the section never raises a toast itself. A failed save keeps every value and shows under its field, or above the footer when no field owns it. `tone` marks a state with a command (a failed payment, a trial ending): a 1px border and a footer tinted in the hue with its line in it; title, line, fields and buttons stay neutral, an outline secondary then a default primary. A button takes the hue of its command, not of the card: `destructive` for a permanent loss, `warning` for a disruptive command that can be undone. A delete card is `tone="error"` with the object's summary as its body; an archive card is neutral with a `warning` button in the footer. "Use a Note for inline contextual feedback next to the field, card, or section it describes: a region change warning above a region picker, a rate-limit notice next to a usage gauge." (https://vercel.com/geist/note) "One Note per concept." (https://vercel.com/geist/note) Ours: a message about the fields inside is a MessageNotice in the body, the card staying neutral. "Disabled checkboxes still need a Tooltip naming the reason; a greyed box with no explanation reads as a bug." (https://vercel.com/geist/checkbox) Ours: `lockedReason` is the reason, in the card, not in a tooltip; it keeps the fields in view, inert with muted text, under a not-allowed cursor, the title and line unchanged; `unlock` is the way to get access, left out when nothing the person does unlocks it.
|
|
26
|
+
* @words "Helper text is sentence case, one sentence with a trailing period, on a sibling element wired through `aria-describedby`." (https://vercel.com/geist/input) Ours: the description is that helper text for the whole card, and no field has its own. "Render an optional one-sentence description as a sibling under the label that explains ON only. Don’t describe OFF; it’s the negation." (https://vercel.com/geist/toggle) Ours: a header-switch card's description says what turning it on does. The title names the values ("Personal details"); the description says what changing them does, in one line; the footer line is a Learn more link, a limit ("Use 32 characters at most."), what stays unaffected, or what is blocked and why ("Ask an owner to change this."); Save and Saving come from the product's catalogue, and so does the toast a `saved` callback raises; a delete card's description opens "Permanently delete".
|
|
27
|
+
* @access "Provide an accessible name through `children`, `aria-label`, or `aria-labelledby`." (https://vercel.com/geist/toggle) Ours: the title is the section's h2 and names the form that saves it, and the header switch. The footer's line is one status, announced politely; a failure under a field marks the control invalid and describes it. Locked fields are inert, so the section's title, description and reason are what a screen reader meets.
|
|
17
28
|
*/
|
|
18
|
-
function SettingsSection({ title, description, actions,
|
|
29
|
+
function SettingsSection({ title, description, actions, headerSwitch, tone, children, className, save, footer, footerHint, lockedReason, unlock, ...props }) {
|
|
19
30
|
const titleId = React.useId();
|
|
20
|
-
const
|
|
21
|
-
|
|
31
|
+
const locked = lockedReason !== undefined;
|
|
32
|
+
const fields = children != null ? (_jsx(CardContent, { children: _jsx(FieldGroup, { "data-slot": "settings-section-fields", inert: locked, className: cn(locked && "**:text-muted-foreground"), children: children }) })) : null;
|
|
33
|
+
return (_jsxs(Card, { render: _jsx("section", { ...props, "data-slot": "settings-section", "data-tone": tone, "data-locked": locked || undefined }), className: cn("@container/settings-section min-w-0", tone && toneClassNames[tone], locked && "cursor-not-allowed *:data-[slot=card-footer]:cursor-default", className), children: [_jsxs(CardHeader, { className: cn(ACTIONS_ON_TITLE_ROW_WHEN_NARROW, !title && "has-data-[slot=card-description]:grid-rows-none"), children: [title ? (_jsx(CardTitle, { children: _jsx("h2", { id: titleId, children: title }) })) : null, _jsx(CardDescription, { children: description }), actions ? _jsx(CardAction, { children: actions }) : null, headerSwitch ? (_jsx(CardAction, { className: "mt-0.75", children: _jsx(Switch, { ...headerSwitch, "aria-labelledby": titleId, size: "md" }) })) : null] }), save ? (_jsx(SettingsSaveForm, { save: save, titleId: titleId, children: fields })) : (_jsxs(_Fragment, { children: [fields, _jsx(FooterStrip, { hint: locked ? lockedReason : footerHint, hintSlot: "settings-section-hint", children: locked ? unlock : footer })] }))] }));
|
|
22
34
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
*
|
|
26
|
-
* @family Inputs
|
|
27
|
-
* @when A value inside a SettingsSection: a name, an address, a choice, a switch.
|
|
28
|
-
* @instead A field of a drawer's or a dialog's form is a Field from the form's own owner; a read-only value is a fact in a SettingsFactsSection.
|
|
29
|
-
* @behaviour The control is 20rem wide under its label and help by default; a switch row passes `orientation="horizontal"` and sits at the end of its label's row at its own width. A validation `error`, or a failed save about this field, shows under the control and marks it invalid.
|
|
30
|
-
* @words The label is a noun for the value ("Display name"); the help is one line saying what it is for or where it shows; an error says what to do next.
|
|
31
|
-
* @access The control receives its id, `aria-invalid` and `aria-describedby` through `controlProps`, so the label, help and error are read with it.
|
|
32
|
-
*/
|
|
33
|
-
function SettingsField({ id, label, description, error, invalid = Boolean(error), disabled, required, orientation = "vertical", children, className, contentClassName, controlClassName, controlWidth = orientation === "horizontal" ? "natural" : "standard", ...props }) {
|
|
34
|
-
const descriptionId = description ? `${id}-description` : undefined;
|
|
35
|
-
const errorId = error ? `${id}-error` : undefined;
|
|
36
|
-
const describedBy = [descriptionId, errorId].filter(Boolean).join(" ");
|
|
37
|
-
const controlProps = {
|
|
35
|
+
function controlPropsOf({ id, info, error, invalid, disabled, required, }) {
|
|
36
|
+
return {
|
|
38
37
|
id,
|
|
38
|
+
"aria-labelledby": `${id}-label`,
|
|
39
39
|
disabled,
|
|
40
40
|
required,
|
|
41
41
|
"aria-invalid": invalid ? true : undefined,
|
|
42
|
-
"aria-describedby":
|
|
42
|
+
"aria-describedby": [info ? `${id}-info` : undefined, error ? `${id}-error` : undefined]
|
|
43
|
+
.filter(Boolean)
|
|
44
|
+
.join(" ") || undefined,
|
|
43
45
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
}
|
|
47
|
+
function SettingsFieldLabel({ id, label, info, }) {
|
|
48
|
+
const fieldLabel = (_jsx(FieldLabel, { htmlFor: id, id: `${id}-label`, children: label }));
|
|
49
|
+
if (!info)
|
|
50
|
+
return fieldLabel;
|
|
51
|
+
return (_jsxs("div", { className: "flex items-center gap-1", children: [fieldLabel, _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { render: _jsx(Button, { "aria-label": info.label, size: "icon-xs", variant: "ghost" }), children: _jsx(Info, { "aria-hidden": "true" }) }), _jsx(TooltipContent, { children: info.text })] }), _jsx("span", { hidden: true, id: `${id}-info`, children: info.text })] }));
|
|
52
|
+
}
|
|
53
|
+
function SettingsFieldErrors({ id, error }) {
|
|
54
|
+
return (_jsxs(_Fragment, { children: [error ? _jsx(FieldError, { id: `${id}-error`, children: error }) : null, _jsx(SettingsFieldFailure, { id: id })] }));
|
|
55
|
+
}
|
|
56
|
+
const boxControl = "[&>:not([role=checkbox],[role=switch],[role=radio])]:w-full";
|
|
57
|
+
function controlCellClassName(control, controlWidth) {
|
|
58
|
+
if (control === "choice")
|
|
59
|
+
return "mt-0.5 shrink-0";
|
|
60
|
+
if (control === "switch")
|
|
61
|
+
return "items-center gap-2";
|
|
62
|
+
if (controlWidth === "standard")
|
|
63
|
+
return `w-full max-w-80 justify-start ${boxControl}`;
|
|
64
|
+
if (controlWidth === "full")
|
|
65
|
+
return `w-full justify-start ${boxControl}`;
|
|
66
|
+
return "w-full justify-start";
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* One setting: its label above its control, and what went wrong under it.
|
|
70
|
+
*
|
|
71
|
+
* @family Inputs
|
|
72
|
+
* @when The one value of a SettingsSection: a name, an address, a choice, a switch.
|
|
73
|
+
* @instead A field of a drawer's or a dialog's form is a Field from the form's own owner; a read-only fact is a SettingsFactsSection; several switches or selects in one card are SettingsRows; a switch that is the whole card and applies at once is the section's `headerSwitch`.
|
|
74
|
+
* @behaviour "Helper text is sentence case, one sentence with a trailing period, on a sibling element wired through `aria-describedby`." (https://vercel.com/geist/input) Ours: label required, no help line: the card's description helps, and the (i) `info` is for a part of a value that needs a sentence. The control is 20rem wide under its label (`controlWidth`: `full` for a textarea, `natural` for a segmented control). `control="choice"` puts a checkbox or radio before its sentence; `control="switch"` puts the word for the switch's state after it and requires `stateLabel`. "Validate on blur, not on every keystroke; surface the message by passing a string to `error`." (https://vercel.com/geist/input) Ours: a validation `error` updates as the value is corrected, and it or a failed save about this field shows under the control and marks it invalid; colour sits on the control's edge and the message, never the label.
|
|
75
|
+
* @words "Labels are short Title Case nouns: `Project Name`, `Domain`, `Environment Variable Name`." (https://vercel.com/geist/input) Ours: sentence case, a noun for the value ("Display name"). "Validation names the field and the constraint, ends in a period, and skips `please` (`Project name is required.`, `Code must be 6 digits.`)." (https://vercel.com/geist/input) Ours: an error says what to do next; `info.text` is one sentence and `info.label` names its button ("About display name"); a switch shows its state word ("Enabled", "Disabled") beside it.
|
|
76
|
+
* @access "Don’t wrap a labelled `<Input>` in a `Tooltip`; put the explainer on a sibling icon button so the label stays announced." (https://vercel.com/geist/input) Ours: that sibling button is the (i) `info`. The control receives its id, `aria-invalid` and `aria-describedby` through `controlProps`, so the label, the info and the error are read with it. The info button has its own name and opens on focus.
|
|
77
|
+
*/
|
|
78
|
+
function SettingsField({ id, label, info, error, invalid = Boolean(error), disabled, required, control = "box", controlWidth = "standard", stateLabel, children, className, ...props }) {
|
|
79
|
+
const controlProps = controlPropsOf({ id, info, error, invalid, disabled, required });
|
|
80
|
+
const errors = _jsx(SettingsFieldErrors, { id: id, error: error });
|
|
81
|
+
const beside = control === "choice";
|
|
82
|
+
const controlCell = (_jsxs("div", { "data-slot": "settings-field-control", className: cn("flex min-w-0", controlCellClassName(control, controlWidth)), children: [children({ controlProps }), control === "switch" ? _jsx("span", { className: "text-sm", children: stateLabel }) : null] }));
|
|
83
|
+
return (_jsx("div", { "data-slot": "settings-field", "data-invalid": invalid ? true : undefined, className: "contents", children: _jsxs(Field, { "data-invalid": invalid ? true : undefined, "data-disabled": disabled ? true : undefined, orientation: beside ? "horizontal" : "vertical", className: cn("items-start", className), ...props, children: [beside ? controlCell : null, _jsxs(FieldContent, { children: [_jsx(SettingsFieldLabel, { id: id, label: label, info: info }), beside ? errors : null] }), beside ? null : controlCell, beside ? null : errors] }) }));
|
|
84
|
+
}
|
|
85
|
+
function SettingsRow({ id, label, info, error, disabled, children, }) {
|
|
86
|
+
const invalid = Boolean(error);
|
|
87
|
+
const controlProps = controlPropsOf({ id, info, error, invalid, disabled });
|
|
88
|
+
return (_jsx("div", { "data-slot": "settings-row", "data-invalid": invalid ? true : undefined, className: "contents", children: _jsxs(Field, { "data-invalid": invalid ? true : undefined, "data-disabled": disabled ? true : undefined, orientation: "horizontal", className: "flex-wrap has-[>[data-slot=field-content]]:items-center", children: [_jsxs(FieldContent, { className: "flex-auto", children: [_jsx(SettingsFieldLabel, { id: id, label: label, info: info }), _jsx(SettingsFieldErrors, { id: id, error: error })] }), _jsx("div", { "data-slot": "settings-row-control", className: "flex items-center gap-2 group-data-[kind=select]/settings-rows:w-48 group-data-[kind=select]/settings-rows:max-w-full", children: children({ controlProps }) })] }) }));
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Several switches, or several selects, in one card: each row its label on the left and its control on the right.
|
|
92
|
+
*
|
|
93
|
+
* @family Inputs
|
|
94
|
+
* @when A card of settings of one kind, all switches or all selects, that the card's one description covers: a project's Git switches, a team's notification channels, a set of defaults.
|
|
95
|
+
* @instead One setting is a SettingsField. Fields of different kinds, text boxes among them, are one card each. A switch that is the whole card and applies at once is the section's `headerSwitch`.
|
|
96
|
+
* @behaviour Declares `kind` once; every row is that kind, so a card cannot mix a switch with a select. Required on every row: the label and its `info` (an (i) with its sentence in a tooltip and on the control); no help line sits under a row. A switch row shows its state word beside the switch (`stateLabels`) and is controlled, so the word always follows the switch. Rows stand 16 px apart; below 28rem a row stacks its control under its label. "Pair with a form footer only when the setting needs an explicit `Save` step." (https://vercel.com/geist/toggle) Ours: a switch in a card with a Save is a draft the Save applies; in a card without one it applies at once through its `onCheckedChange`, and the card's footer holds only its line, if it has one.
|
|
97
|
+
* @words "Title Case noun phrase, 1–4 words, naming what is true when ON: `Password Protection`, not `Enable Password Protection`." (https://vercel.com/geist/toggle) Ours: sentence case, a noun for what it controls ("Pull request comments"), the same for a switch as for a select. "Render an optional one-sentence description as a sibling under the label that explains ON only. Don’t describe OFF; it’s the negation." (https://vercel.com/geist/toggle) Ours: that sentence is `info.text`. "Options are Title Case when short and match canonical branding (`Next.js`, not `NextJS`); keep the same register across the list." (https://vercel.com/geist/select) Ours: a select's options are sentence case.
|
|
98
|
+
* @access Each row's control is named by the row's label and described by its info and its error. The info button has its own name and opens on focus.
|
|
99
|
+
*/
|
|
100
|
+
function SettingsRows(props) {
|
|
101
|
+
return (_jsx("div", { "data-slot": "settings-rows", "data-kind": props.kind, className: "group/settings-rows flex flex-col gap-4", children: props.kind === "switch" ? switchRows(props.rows, props.stateLabels) : selectRows(props.rows) }));
|
|
102
|
+
}
|
|
103
|
+
function switchRows(rows, stateLabels) {
|
|
104
|
+
return rows.map((row) => (_jsx(SettingsRow, { ...row, children: ({ controlProps }) => (_jsxs(_Fragment, { children: [_jsx(Switch, { ...controlProps, checked: row.checked, name: row.name, onCheckedChange: row.onCheckedChange, size: "md" }), _jsx("span", { className: "text-sm", children: row.checked ? stateLabels.on : stateLabels.off })] })) }, row.id)));
|
|
105
|
+
}
|
|
106
|
+
function selectRows(rows) {
|
|
107
|
+
return rows.map((row) => (_jsx(SettingsRow, { ...row, children: ({ controlProps }) => (_jsx(NativeSelect, { ...controlProps, name: row.name, onChange: (event) => row.onValueChange(event.target.value), value: row.value, children: row.options.map((option) => (_jsx(NativeSelectOption, { value: option.value, children: option.label }, option.value))) })) }, row.id)));
|
|
108
|
+
}
|
|
109
|
+
export { SettingsField, SettingsRows, SettingsSection };
|
|
@@ -1,30 +1,61 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { Dialog as SheetPrimitive } from "@base-ui/react/dialog";
|
|
3
|
+
type SheetProps = Omit<SheetPrimitive.Root.Props, "modal" | "disablePointerDismissal"> & {
|
|
4
|
+
/**
|
|
5
|
+
* The sheet owns the screen: the scrim dims the page and the page ignores the pointer. Without it
|
|
6
|
+
* the page behind stays usable and toasts stay reachable.
|
|
7
|
+
*/
|
|
8
|
+
modal?: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* A press on the scrim closes the sheet, for the navigation on a phone, which holds nothing a
|
|
11
|
+
* person could lose. Every other sheet stays open until Escape or Close.
|
|
12
|
+
*/
|
|
13
|
+
closesOnScrimPress?: boolean;
|
|
14
|
+
};
|
|
3
15
|
/**
|
|
4
|
-
* A panel
|
|
16
|
+
* A panel from the edge of the window, beside what it describes.
|
|
5
17
|
*
|
|
6
18
|
* @family Menus
|
|
7
|
-
* @when
|
|
8
|
-
* navigation when the window is too narrow for the sidebar.
|
|
9
|
-
* @instead For a
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
19
|
+
* @when "Use Sheet for persistent associated context like deployment details, log row inspection, or a member profile, where the underlying page stays useful." (https://vercel.com/geist/sheet)
|
|
20
|
+
* Ours: also the product's navigation when the window is too narrow for the sidebar.
|
|
21
|
+
* @instead "For a blocking decision, use `Modal`. For a mobile-only bottom sheet, use `Drawer`." (https://vercel.com/geist/sheet)
|
|
22
|
+
* "Don’t use Sheet to confirm destructive actions. The default `modal=false` keeps the page interactive, which weakens severity for a delete or revoke." (https://vercel.com/geist/sheet)
|
|
23
|
+
* Ours: a blocking decision is `ConfirmDialog` or `Dialog`. A catalogue or steps use `FormDrawer`
|
|
24
|
+
* (built on this). For editing use the row or the record's page.
|
|
25
|
+
* @behaviour "Sheet defaults to `modal=false` so toasts and other high-z elements stay reachable. Keep that default unless the sheet owns the screen." (https://vercel.com/geist/sheet)
|
|
26
|
+
* "Pick `side` from the trigger location: a row inspector slides from `right`, a global filter from `left`. Don’t change sides mid-session." (https://vercel.com/geist/sheet)
|
|
27
|
+
* "Outside-click does not auto-close, so always render an explicit close affordance and honor Escape." (https://vercel.com/geist/sheet)
|
|
28
|
+
* Ours: `modal` dims the page and blocks it, for a sheet that owns the screen, and `noOverlay` on
|
|
29
|
+
* its content drops the scrim again. An inset card with 16 px corners, 12 px from the window's
|
|
30
|
+
* edges; a side panel has one width that no caller sets. A given kind of sheet always opens on the
|
|
31
|
+
* same side. A press outside never closes it, Escape does, except the phone navigation, which
|
|
32
|
+
* `closesOnScrimPress` closes on a press on its scrim. The body scrolls between a header and a
|
|
33
|
+
* footer with its actions at the trailing edge, as Vercel's drawers (Production Checklist): the
|
|
34
|
+
* footer keeps the sheet's fill and stands under a 1 px rule, so its actions stay put while the
|
|
35
|
+
* body scrolls. Neutral only, with no hue but the focus ring; the primary is the only filled
|
|
36
|
+
* control. `closeLabel` is required.
|
|
37
|
+
* @words "Title is Title Case and names the entity (`Deployment Details`, `Member Profile`), not the page action." (https://vercel.com/geist/sheet)
|
|
38
|
+
* "Body is read-mostly: sentence case prose with Title Case sub-headings. Action buttons are optional; when present, follow `Verb + Noun`." (https://vercel.com/geist/sheet)
|
|
39
|
+
* "Don’t duplicate the page header inside the sheet; the sheet is the detail layer." (https://vercel.com/geist/sheet)
|
|
40
|
+
* Ours: titles and sub-headings are sentence case where Geist writes Title Case. A footer link names
|
|
41
|
+
* where it goes: *Open Rossi Ottica*.
|
|
42
|
+
* @access "Trap focus inside the sheet while it’s open and return focus to the trigger row on close so keyboard users keep their place in the list." (https://vercel.com/geist/sheet)
|
|
43
|
+
* "Provide a visible close button labeled `Close` (or an icon button with `aria-label="Close"`) since clicking outside doesn’t dismiss." (https://vercel.com/geist/sheet)
|
|
44
|
+
* "Announce the sheet with `aria-labelledby` pointing at the title; pair it with `aria-describedby` only when the body is short and load-bearing." (https://vercel.com/geist/sheet)
|
|
45
|
+
* Ours: a dialog named by its title, with a Close named in the product's words by `closeLabel`.
|
|
46
|
+
* Focus returns to the row or the navigation button that opened it.
|
|
18
47
|
*/
|
|
19
|
-
declare function Sheet({ ...props }:
|
|
48
|
+
declare function Sheet({ modal, closesOnScrimPress, ...props }: SheetProps): React.JSX.Element;
|
|
20
49
|
declare function SheetTrigger({ ...props }: SheetPrimitive.Trigger.Props): React.JSX.Element;
|
|
21
50
|
declare function SheetClose({ ...props }: SheetPrimitive.Close.Props): React.JSX.Element;
|
|
22
51
|
type SheetContentProps = SheetPrimitive.Popup.Props & {
|
|
23
52
|
side?: "top" | "right" | "bottom" | "left";
|
|
24
|
-
|
|
25
|
-
|
|
53
|
+
/** Draw no scrim although the sheet is `modal`. */
|
|
54
|
+
noOverlay?: boolean;
|
|
55
|
+
/** The Close control's accessible name, from the product's catalogue. */
|
|
56
|
+
closeLabel: string;
|
|
26
57
|
};
|
|
27
|
-
declare function SheetContent({ className, children, side,
|
|
58
|
+
declare function SheetContent({ className, children, side, noOverlay, closeLabel, finalFocus, ...props }: SheetContentProps): React.JSX.Element;
|
|
28
59
|
declare function SheetHeader({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
29
60
|
declare function SheetFooter({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
|
|
30
61
|
declare function SheetTitle({ className, ...props }: SheetPrimitive.Title.Props): React.JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sheet.d.ts","sourceRoot":"","sources":["../../src/components/sheet.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,MAAM,IAAI,cAAc,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"sheet.d.ts","sourceRoot":"","sources":["../../src/components/sheet.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,MAAM,IAAI,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAUjE,KAAK,UAAU,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,yBAAyB,CAAC,GAAG;IACvF;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,iBAAS,KAAK,CAAC,EAAE,KAAa,EAAE,kBAA0B,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,qBAWjF;AAED,iBAAS,YAAY,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,CAAC,OAAO,CAAC,KAAK,qBAE/D;AAED,iBAAS,UAAU,CAAC,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,KAAK,qBAE3D;AAqBD,KAAK,iBAAiB,GAAG,cAAc,CAAC,KAAK,CAAC,KAAK,GAAG;IACpD,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC3C,mDAAmD;IACnD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,iBAAS,YAAY,CAAC,EACpB,SAAS,EACT,QAAQ,EACR,IAAc,EACd,SAAiB,EACjB,UAAU,EACV,UAAqC,EACrC,GAAG,KAAK,EACT,EAAE,iBAAiB,qBAiCnB;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAQxE;AAED,iBAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,qBAWxE;AAED,iBAAS,UAAU,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,KAAK,qBAQtE;AAED,iBAAS,gBAAgB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,CAAC,WAAW,CAAC,KAAK,qBAQlF;AAED,OAAO,EACL,KAAK,EACL,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,WAAW,EACX,WAAW,EACX,UAAU,EACV,gBAAgB,GACjB,CAAC"}
|