@nadicodeai/ui 12.1.102 → 12.1.103
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 +9 -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
package/dist/components/field.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useMemo } from "react";
|
|
4
4
|
import { cva } from "class-variance-authority";
|
|
5
|
+
import { OctagonAlertIcon } from "lucide-react";
|
|
5
6
|
import { cn } from "../lib/utils.js";
|
|
6
7
|
import { Label } from "./label.js";
|
|
7
8
|
import { Separator } from "./separator.js";
|
|
@@ -9,12 +10,12 @@ function FieldSet({ className, ...props }) {
|
|
|
9
10
|
return (_jsx("fieldset", { "data-slot": "field-set", className: cn("flex flex-col gap-4 has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3", className), ...props }));
|
|
10
11
|
}
|
|
11
12
|
function FieldLegend({ className, variant = "legend", ...props }) {
|
|
12
|
-
return (_jsx("legend", { "data-slot": "field-legend", "data-variant": variant, className: cn("mb-1.5 data-[variant=label]:text-label data-[variant=label]:
|
|
13
|
+
return (_jsx("legend", { "data-slot": "field-legend", "data-variant": variant, className: cn("mb-1.5 data-[variant=label]:text-label-sm data-[variant=label]:leading-normal data-[variant=label]:text-muted-foreground data-[variant=legend]:text-heading-xs", className), ...props }));
|
|
13
14
|
}
|
|
14
15
|
function FieldGroup({ className, ...props }) {
|
|
15
|
-
return (_jsx("div", { "data-slot": "field-group", className: cn("group/field-group @container/field-group flex w-full flex-col gap-
|
|
16
|
+
return (_jsx("div", { "data-slot": "field-group", className: cn("group/field-group @container/field-group flex w-full flex-col gap-4 data-[slot=checkbox-group]:gap-3", className), ...props }));
|
|
16
17
|
}
|
|
17
|
-
const fieldVariants = cva("group/field flex w-full gap-2
|
|
18
|
+
const fieldVariants = cva("group/field flex w-full gap-2", {
|
|
18
19
|
variants: {
|
|
19
20
|
orientation: {
|
|
20
21
|
vertical: "flex-col *:w-full [&>.sr-only]:w-auto",
|
|
@@ -27,21 +28,49 @@ const fieldVariants = cva("group/field flex w-full gap-2 data-[invalid=true]:tex
|
|
|
27
28
|
},
|
|
28
29
|
});
|
|
29
30
|
/**
|
|
30
|
-
* A control with its label
|
|
31
|
+
* A control with its label and its error, tied together; a checkbox, a radio or a switch with the
|
|
32
|
+
* sentence beside it.
|
|
31
33
|
*
|
|
32
34
|
* @family Inputs
|
|
33
|
-
* @when
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* is `
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
35
|
+
* @when A checkbox, a radio or a switch with its sentence, or a group of such rows. Inside a
|
|
36
|
+
* settings section `SettingsField` does it and hands the control its `controlProps`.
|
|
37
|
+
* @instead A text box, a textarea, a select, a combobox or a multi-select takes `label` and `error`
|
|
38
|
+
* as props and draws these same parts: wrapping one in `Field` with a `FieldLabel` is the same job
|
|
39
|
+
* done twice. A bordered tile that holds a radio or checkbox and a sentence is `ChoiceboxGroup`. A
|
|
40
|
+
* whole save group is `SettingsSection`. A group of radios or checkboxes is a `FieldSet` with a
|
|
41
|
+
* `FieldLegend`:
|
|
42
|
+
* "Wrap related radios in `<fieldset>` + `<legend>` so screen readers announce the group name before each option." (https://vercel.com/geist/radio)
|
|
43
|
+
* "Wrap related checkboxes in `<fieldset>` with a `<legend>` so screen readers announce the group name before each option." (https://vercel.com/geist/checkbox)
|
|
44
|
+
* @behaviour "Accessible text label for form controls." (https://vercel.com/geist/label) Label,
|
|
45
|
+
* then the control, then the error under it, 8 px apart, at regular weight; the fields of a
|
|
46
|
+
* `FieldGroup` stand 16 px apart. The label stays neutral when the control is invalid: red sits on
|
|
47
|
+
* the control's edge and on the message, the message with an alert mark before it at 13 px (16 px
|
|
48
|
+
* beside a large control). A control fills its field.
|
|
49
|
+
* "Helper text is sentence case, one sentence with a trailing period, on a sibling element wired through `aria-describedby`." (https://vercel.com/geist/input)
|
|
50
|
+
* Ours: help is the one-line description of the card or the form that holds the field, not a line
|
|
51
|
+
* under each field; a `FieldDescription` is for the sentence beside a checkbox, a radio or a
|
|
52
|
+
* switch.
|
|
53
|
+
* "Validate on blur, not on every keystroke; surface the message by passing a string to `error`." (https://vercel.com/geist/input)
|
|
54
|
+
* "Validate on blur and pass a string to `error` to render the inline message; the validation replaces helper text on failure." (https://vercel.com/geist/textarea)
|
|
55
|
+
* Ours: the message updates as the value is corrected.
|
|
56
|
+
* "Keep the field focusable while saving; pair `disabled` with a spinner only when input is impossible." (https://vercel.com/geist/input)
|
|
57
|
+
* Ours: no spinner, the loading state stays still.
|
|
58
|
+
* "Trim leading and trailing whitespace before submit so ` example.com` and `example.com` resolve to one value." (https://vercel.com/geist/input)
|
|
59
|
+
* Ours: the save of `FormDialog`, `FormDrawer`, `RowEditForm` and `SettingsSection` trims the ends
|
|
60
|
+
* of every text value; a bare `<form>` does not.
|
|
61
|
+
* "The click target already extends to the label. Don’t override the `<label>`/`htmlFor` association with a custom wrapper that breaks the click region." (https://vercel.com/geist/checkbox)
|
|
62
|
+
* "Disabled checkboxes still need a Tooltip naming the reason; a greyed box with no explanation reads as a bug." (https://vercel.com/geist/checkbox)
|
|
63
|
+
* Ours: a disabled field says why in the card's footer, never in a tooltip around the control.
|
|
64
|
+
* @words
|
|
65
|
+
* "Labels are short Title Case nouns: `Project Name`, `Domain`, `Environment Variable Name`." (https://vercel.com/geist/input)
|
|
66
|
+
* Ours: sentence case, a short noun (*Display name*); a field that may stay empty says so in its
|
|
67
|
+
* label (*Address line 2 (optional)*), never in its placeholder.
|
|
68
|
+
* "Placeholders show an example value (`my-awesome-project`, `example.com`), never instructions like `Enter your project name`." (https://vercel.com/geist/input)
|
|
69
|
+
* "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)
|
|
70
|
+
* Ours: *Enter a full address, like name@company.it.*
|
|
43
71
|
* @access `FieldError` is `role="alert"`. The control carries `id`, `aria-invalid`,
|
|
44
|
-
* `aria-describedby` (
|
|
72
|
+
* `aria-describedby` (the error), `disabled` and `required`.
|
|
73
|
+
* "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)
|
|
45
74
|
*/
|
|
46
75
|
function Field({ className, orientation = "vertical", ...props }) {
|
|
47
76
|
return (_jsx("div", { role: "group", "data-slot": "field", "data-orientation": orientation, className: cn(fieldVariants({ orientation }), className), ...props }));
|
|
@@ -52,11 +81,11 @@ function Field({ className, orientation = "vertical", ...props }) {
|
|
|
52
81
|
function FieldContent({ className, ...props }) {
|
|
53
82
|
return (_jsx("div", { "data-slot": "field-content", className: cn("group/field-content flex flex-1 flex-col gap-1 *:data-[slot=field-label]:block *:data-[slot=field-label]:leading-snug", className), ...props }));
|
|
54
83
|
}
|
|
55
|
-
function FieldLabel({ className, ...props }) {
|
|
56
|
-
return (_jsx(Label, { "data-slot": "field-label", className: cn("group/field-label peer/field-label flex w-fit gap-2 group-data-[disabled=true]/field:
|
|
84
|
+
function FieldLabel({ className, htmlFor, ...props }) {
|
|
85
|
+
return (_jsx(Label, { "data-slot": "field-label", htmlFor: htmlFor, className: cn("group/field-label peer/field-label flex w-fit gap-2 group-data-[disabled=true]/field:text-placeholder", "group-has-[[role=checkbox]]/field:leading-5 group-has-[[role=checkbox]]/field:text-foreground group-has-[[role=radio]]/field:leading-5 group-has-[[role=radio]]/field:text-foreground", "group-has-[[role=switch]]/field:text-xs group-has-[[role=switch]]/field:font-medium group-has-[[role=switch]]/field:text-foreground", className), ...props }));
|
|
57
86
|
}
|
|
58
87
|
function FieldTitle({ className, ...props }) {
|
|
59
|
-
return (_jsx("div", { "data-slot": "field-label", className: cn("flex w-fit items-center gap-2 text-
|
|
88
|
+
return (_jsx("div", { "data-slot": "field-label", className: cn("flex w-fit items-center gap-2 text-label group-data-[disabled=true]/field:text-placeholder", className), ...props }));
|
|
60
89
|
}
|
|
61
90
|
function FieldDescription({ className, ...props }) {
|
|
62
91
|
return (_jsx("p", { "data-slot": "field-description", className: cn("text-left text-sm font-normal text-muted-foreground group-has-data-horizontal/field:text-balance [[data-variant=legend]+&]:-mt-1.5", "last:mt-0 nth-last-2:-mt-1", "[&>a]:text-(--nc-link) [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:decoration-2", className), ...props }));
|
|
@@ -64,7 +93,7 @@ function FieldDescription({ className, ...props }) {
|
|
|
64
93
|
function FieldSeparator({ children, className, ...props }) {
|
|
65
94
|
return (_jsxs("div", { "data-slot": "field-separator", "data-content": !!children, className: cn("relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2", className), ...props, children: [_jsx(Separator, { className: "absolute inset-0 top-1/2" }), children && (_jsx("span", { className: "relative mx-auto block w-fit bg-background px-2 text-muted-foreground", "data-slot": "field-separator-content", children: children }))] }));
|
|
66
95
|
}
|
|
67
|
-
function FieldError({ className, children, errors, ...props }) {
|
|
96
|
+
function FieldError({ className, children, errors, size = "default", ...props }) {
|
|
68
97
|
const content = useMemo(() => {
|
|
69
98
|
if (children) {
|
|
70
99
|
return children;
|
|
@@ -83,6 +112,6 @@ function FieldError({ className, children, errors, ...props }) {
|
|
|
83
112
|
if (!content) {
|
|
84
113
|
return null;
|
|
85
114
|
}
|
|
86
|
-
return (
|
|
115
|
+
return (_jsxs("div", { role: "alert", "aria-atomic": "true", "data-slot": "field-error", "data-size": size, className: cn("flex items-start gap-2 text-label-sm leading-5 font-normal text-destructive data-[size=lg]:text-base data-[size=lg]:leading-6", className), ...props, children: [_jsx(OctagonAlertIcon, { "aria-hidden": "true", className: "mt-0.5 size-4 shrink-0 in-data-[size=lg]:mt-1" }), _jsx("div", { className: "min-w-0", children: content })] }));
|
|
87
116
|
}
|
|
88
117
|
export { Field, FieldLabel, FieldDescription, FieldError, FieldGroup, FieldLegend, FieldSeparator, FieldSet, FieldContent, FieldTitle, };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-diff.d.ts","sourceRoot":"","sources":["../../src/components/file-diff.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"file-diff.d.ts","sourceRoot":"","sources":["../../src/components/file-diff.tsx"],"names":[],"mappings":"AAMA,UAAU,aAAc,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,CAAC;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,oFAAoF;IACpF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;CAC1C;AAYD;;;;;;;;;;;GAWG;AACH,iBAAS,QAAQ,CAAC,EAChB,UAAoB,EACpB,KAAK,EACL,MAAM,EACN,SAAS,EACT,OAAW,EACX,YAAwB,EACxB,YAAoD,EACpD,GAAG,KAAK,EACT,EAAE,aAAa,+BAkCf;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useMemo } from "react";
|
|
3
|
+
import { DIFF_MARK, DIFF_ROW } from "../internal/diff-line.js";
|
|
3
4
|
import { lineDiff } from "../lib/line-diff.js";
|
|
4
5
|
import { cn } from "../lib/utils.js";
|
|
5
6
|
const ROW = {
|
|
6
|
-
|
|
7
|
+
...DIFF_ROW,
|
|
7
8
|
context: "text-muted-foreground",
|
|
8
|
-
removed: "bg-destructive-soft text-destructive-soft-foreground",
|
|
9
9
|
};
|
|
10
10
|
const MARK = {
|
|
11
|
-
|
|
11
|
+
...DIFF_MARK,
|
|
12
12
|
context: "",
|
|
13
|
-
removed: "−",
|
|
14
13
|
};
|
|
15
14
|
/**
|
|
16
15
|
* A file's before and after, line by line.
|
|
@@ -5,15 +5,15 @@ export type FormDialogProps = FormSurfaceProps & {
|
|
|
5
5
|
pending?: boolean;
|
|
6
6
|
};
|
|
7
7
|
/**
|
|
8
|
-
* A new record, or one or two values from a command, in a
|
|
8
|
+
* A new record, or one or two values from a command, in a modal dialog.
|
|
9
9
|
*
|
|
10
10
|
* @family Compositions
|
|
11
|
-
* @when
|
|
12
|
-
* @instead
|
|
13
|
-
* @behaviour
|
|
14
|
-
* @words
|
|
15
|
-
* @access
|
|
11
|
+
* @when "Use Modal when a decision must block the rest of the page. For persistent associated context where the underlying page stays readable, use `Sheet` on desktop or `Drawer` on mobile." (https://vercel.com/geist/modal) Ours: a person adds a record through a few fields, or changes one or two values a command asks for: new customer, add a mailbox, add an MCP server.
|
|
12
|
+
* @instead "Skip Modal for routine create flows that have a dedicated page; route to the page instead." (https://vercel.com/geist/modal) "Confirm destructive actions in a Modal. `Drawer` and `Sheet` don’t fully dim the page, so they read as too soft for a delete or revoke." (https://vercel.com/geist/modal) Ours: a record already in a list edits in its row with `RowEditForm`; a choice from a catalogue is a `CatalogDrawer`; a setup in steps with a wait is a `FormDrawer` with `job="steps"`; a consequence is confirmed in a `ConfirmDialog`.
|
|
13
|
+
* @behaviour "Allow Escape and outside-click to dismiss non-destructive Modals; gate dismissal on destructive ones with unsaved input." (https://vercel.com/geist/modal) Ours: centred over a scrim without blur, 540 px wide, a bottom sheet on a phone: the title and its help, the fields in a 12 px column, then the footer, which stays at the bottom while a tall form scrolls, with Cancel at the leading edge and the primary at the trailing edge, in one row also on a phone. A refusal or a failed save sits above the footer and the fields keep what was typed. While its save runs it holds open, Cancel and the primary hold, and the waiting line runs under them. With `unsaved.dirty`, Escape and a press outside are held back and `unsaved.onDismissBlocked` runs so the caller can ask; Close and Cancel always close.
|
|
14
|
+
* @words "`Modal.Title` is a Title Case statement, never a question. `Transfer Project` is correct; `Transfer Project?` is wrong." (https://vercel.com/geist/modal) "Primary button is `Verb + Noun` and matches the title verb (`Transfer Project` title pairs with `Transfer Project` button). Never `Confirm`, `OK`, or a bare verb on a destructive primary." (https://vercel.com/geist/modal) "Cancel literal stays `Cancel`. Acknowledgment-only Modals (after a key reveal, after a one-time-show) use `Done`, never `OK` or `Close`." (https://vercel.com/geist/modal) Ours: the title and the primary are sentence case, where Geist writes Title Case: the title names the job and its object, "New customer", "Add a mailbox"; the primary repeats it, "Create customer", "Add mailbox".
|
|
15
|
+
* @access "Set `aria-labelledby` to the `Modal.Title` id so screen readers announce the title on open." (https://vercel.com/geist/modal) "Trap focus inside the Modal while it’s open and return focus to the trigger after close. Restore body scroll on the same tick the Modal unmounts." (https://vercel.com/geist/modal) "After an error inside the Modal, keep focus inside so the user can retry; after success, return focus to the trigger." (https://vercel.com/geist/modal) Ours: a modal dialog with a Close named by `closeLabel`; focus starts in its first field or `initialFocus` and returns to the opener or `finalFocus`. Escape and Close close it unless the save runs.
|
|
16
16
|
*/
|
|
17
|
-
export declare function FormDialog({ open, onOpenChange, onOpenChangeComplete, title, description, closeLabel, children, initialFocus, finalFocus, pending, }: FormDialogProps): import("react").JSX.Element;
|
|
17
|
+
export declare function FormDialog({ open, onOpenChange, onOpenChangeComplete, title, description, closeLabel, children, initialFocus, finalFocus, unsaved, pending, }: FormDialogProps): import("react").JSX.Element;
|
|
18
18
|
export declare function FormDialogForm({ cancelLabel, submit, notice, children, ...form }: FormProps): import("react").JSX.Element;
|
|
19
19
|
//# sourceMappingURL=form-dialog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-dialog.d.ts","sourceRoot":"","sources":["../../src/components/form-dialog.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,KAAK,SAAS,EAAoB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"form-dialog.d.ts","sourceRoot":"","sources":["../../src/components/form-dialog.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,KAAK,SAAS,EAAoB,MAAM,wBAAwB,CAAC;AAG1E,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG;IAC/C,0EAA0E;IAC1E,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,YAAY,EACZ,oBAAoB,EACpB,KAAK,EACL,WAAW,EACX,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,UAAiB,EACjB,OAAO,EACP,OAAe,GAChB,EAAE,eAAe,+BAmBjB;AAED,wBAAgB,cAAc,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,SAAS,+BAsB3F"}
|
|
@@ -4,23 +4,25 @@ import { Button } from "./button.js";
|
|
|
4
4
|
import { Dialog, DialogBody, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "./dialog.js";
|
|
5
5
|
import { WaitingLine } from "./waiting-line.js";
|
|
6
6
|
import { FormSubmitButton } from "../internal/form-submit.js";
|
|
7
|
+
import { guardUnsaved } from "../internal/unsaved-guard.js";
|
|
7
8
|
/**
|
|
8
|
-
* A new record, or one or two values from a command, in a
|
|
9
|
+
* A new record, or one or two values from a command, in a modal dialog.
|
|
9
10
|
*
|
|
10
11
|
* @family Compositions
|
|
11
|
-
* @when
|
|
12
|
-
* @instead
|
|
13
|
-
* @behaviour
|
|
14
|
-
* @words
|
|
15
|
-
* @access
|
|
12
|
+
* @when "Use Modal when a decision must block the rest of the page. For persistent associated context where the underlying page stays readable, use `Sheet` on desktop or `Drawer` on mobile." (https://vercel.com/geist/modal) Ours: a person adds a record through a few fields, or changes one or two values a command asks for: new customer, add a mailbox, add an MCP server.
|
|
13
|
+
* @instead "Skip Modal for routine create flows that have a dedicated page; route to the page instead." (https://vercel.com/geist/modal) "Confirm destructive actions in a Modal. `Drawer` and `Sheet` don’t fully dim the page, so they read as too soft for a delete or revoke." (https://vercel.com/geist/modal) Ours: a record already in a list edits in its row with `RowEditForm`; a choice from a catalogue is a `CatalogDrawer`; a setup in steps with a wait is a `FormDrawer` with `job="steps"`; a consequence is confirmed in a `ConfirmDialog`.
|
|
14
|
+
* @behaviour "Allow Escape and outside-click to dismiss non-destructive Modals; gate dismissal on destructive ones with unsaved input." (https://vercel.com/geist/modal) Ours: centred over a scrim without blur, 540 px wide, a bottom sheet on a phone: the title and its help, the fields in a 12 px column, then the footer, which stays at the bottom while a tall form scrolls, with Cancel at the leading edge and the primary at the trailing edge, in one row also on a phone. A refusal or a failed save sits above the footer and the fields keep what was typed. While its save runs it holds open, Cancel and the primary hold, and the waiting line runs under them. With `unsaved.dirty`, Escape and a press outside are held back and `unsaved.onDismissBlocked` runs so the caller can ask; Close and Cancel always close.
|
|
15
|
+
* @words "`Modal.Title` is a Title Case statement, never a question. `Transfer Project` is correct; `Transfer Project?` is wrong." (https://vercel.com/geist/modal) "Primary button is `Verb + Noun` and matches the title verb (`Transfer Project` title pairs with `Transfer Project` button). Never `Confirm`, `OK`, or a bare verb on a destructive primary." (https://vercel.com/geist/modal) "Cancel literal stays `Cancel`. Acknowledgment-only Modals (after a key reveal, after a one-time-show) use `Done`, never `OK` or `Close`." (https://vercel.com/geist/modal) Ours: the title and the primary are sentence case, where Geist writes Title Case: the title names the job and its object, "New customer", "Add a mailbox"; the primary repeats it, "Create customer", "Add mailbox".
|
|
16
|
+
* @access "Set `aria-labelledby` to the `Modal.Title` id so screen readers announce the title on open." (https://vercel.com/geist/modal) "Trap focus inside the Modal while it’s open and return focus to the trigger after close. Restore body scroll on the same tick the Modal unmounts." (https://vercel.com/geist/modal) "After an error inside the Modal, keep focus inside so the user can retry; after success, return focus to the trigger." (https://vercel.com/geist/modal) Ours: a modal dialog with a Close named by `closeLabel`; focus starts in its first field or `initialFocus` and returns to the opener or `finalFocus`. Escape and Close close it unless the save runs.
|
|
16
17
|
*/
|
|
17
|
-
export function FormDialog({ open, onOpenChange, onOpenChangeComplete, title, description, closeLabel, children, initialFocus, finalFocus, pending = false, }) {
|
|
18
|
-
|
|
18
|
+
export function FormDialog({ open, onOpenChange, onOpenChangeComplete, title, description, closeLabel, children, initialFocus, finalFocus = true, unsaved, pending = false, }) {
|
|
19
|
+
const requestOpenChange = guardUnsaved(onOpenChange, unsaved);
|
|
20
|
+
return (_jsx(Dialog, { open: open, onOpenChange: (next, details) => {
|
|
19
21
|
if (next || !pending)
|
|
20
|
-
|
|
21
|
-
}, onOpenChangeComplete: onOpenChangeComplete, children: _jsxs(DialogContent, {
|
|
22
|
+
requestOpenChange(next, details);
|
|
23
|
+
}, onOpenChangeComplete: onOpenChangeComplete, children: _jsxs(DialogContent, { closeLabel: closeLabel, initialFocus: initialFocus, finalFocus: finalFocus, children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: title }), description ? _jsx(DialogDescription, { children: description }) : null] }), children] }) }));
|
|
22
24
|
}
|
|
23
25
|
export function FormDialogForm({ cancelLabel, submit, notice, children, ...form }) {
|
|
24
26
|
const pending = submit.pending === true;
|
|
25
|
-
return (_jsxs("form", { className: "flex min-h-0 flex-col gap-
|
|
27
|
+
return (_jsxs("form", { className: "flex min-h-0 flex-col gap-(--dialog-gap)", "aria-busy": pending || undefined, "data-slot": "form-dialog-form", ...form, children: [_jsx(DialogBody, { children: children }), notice, _jsxs(DialogFooter, { className: "relative", children: [_jsx(DialogClose, { disabled: pending, render: _jsx(Button, { type: "button", variant: "outline" }), children: cancelLabel }), _jsx(FormSubmitButton, { submit: submit }), pending ? (_jsx(WaitingLine, { className: "absolute inset-x-nadicode-sm bottom-1 w-auto", decorative: true })) : null] })] }));
|
|
26
28
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ComponentProps, ReactNode } from "react";
|
|
2
2
|
import { SheetContent } from "./sheet.js";
|
|
3
3
|
import { type FormProps } from "../internal/form-submit.js";
|
|
4
|
+
import { type UnsavedGuard } from "../internal/unsaved-guard.js";
|
|
4
5
|
export type { FormProps, FormSubmit } from "../internal/form-submit.js";
|
|
5
6
|
/** What a form surface is told by its caller, whether it draws a drawer or a dialog. */
|
|
6
7
|
export type FormSurfaceProps = {
|
|
@@ -19,6 +20,8 @@ export type FormSurfaceProps = {
|
|
|
19
20
|
initialFocus?: ComponentProps<typeof SheetContent>["initialFocus"];
|
|
20
21
|
/** Where focus returns when the drawer closes, when its opener is gone. */
|
|
21
22
|
finalFocus?: ComponentProps<typeof SheetContent>["finalFocus"];
|
|
23
|
+
/** Typed input that Escape would lose: while `dirty` it is held back and `onDismissBlocked` runs. */
|
|
24
|
+
unsaved?: UnsavedGuard;
|
|
22
25
|
};
|
|
23
26
|
/**
|
|
24
27
|
* Why this is a drawer and not a dialog: "catalog" chooses from a list too long
|
|
@@ -34,14 +37,14 @@ export type FormDrawerProps = FormSurfaceProps & ({
|
|
|
34
37
|
progress: string;
|
|
35
38
|
});
|
|
36
39
|
/**
|
|
37
|
-
* The right-side
|
|
40
|
+
* The right-side sheet for a catalogue or a setup in steps, at one width.
|
|
38
41
|
*
|
|
39
42
|
* @family Compositions
|
|
40
|
-
* @when
|
|
41
|
-
* @instead
|
|
42
|
-
* @behaviour
|
|
43
|
-
* @words
|
|
44
|
-
* @access
|
|
43
|
+
* @when Ours: choosing from a catalogue too long for a dialog (through `CatalogDrawer`), or setting something up in several steps with a wait: connect a messaging channel, Telegram's code.
|
|
44
|
+
* @instead "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) Ours: a new record from a few fields is a `FormDialog`; a record already in a list edits in its row with `RowEditForm`; a fact on the record's own page changes in place in its section; a consequence is confirmed in a `ConfirmDialog`; a phone's short job is a `Drawer`.
|
|
45
|
+
* @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) "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) "Outside-click does not auto-close, so always render an explicit close affordance and honor Escape." (https://vercel.com/geist/sheet) Ours: a modal `Sheet` from the right edge over the scrim, because the drawer owns the screen, at the Sheet's one width that no caller sets. The header holds the step ("Step 2 of 3") over the title, the description and Close; the body scrolls between the header and a footer that stays, with no fill or rule of its own, Cancel then the primary at its trailing edge. A press outside does not close it; Escape does, unless `unsaved.dirty` holds it back. Cancel holds while a save runs.
|
|
46
|
+
* @words "Title is Title Case and names the entity (`Deployment Details`, `Member Profile`), not the page action." (https://vercel.com/geist/sheet) "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) Ours: the title is sentence case and names the job and its object: "Connect Telegram", "Add a skill". The step reads "Step N of M". The primary says what it does: "Connect", "Continue", never "OK".
|
|
47
|
+
* @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) "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) "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) Ours: a modal dialog named by its title; focus returns to the opener on close, or to `finalFocus` when the opener is gone. The step is read before the title.
|
|
45
48
|
*/
|
|
46
49
|
export declare function FormDrawer(props: FormDrawerProps): import("react").JSX.Element;
|
|
47
50
|
/** The part of the drawer that scrolls between its title and its footer. */
|
|
@@ -55,7 +58,7 @@ export type FormDrawerFooterProps = {
|
|
|
55
58
|
/** The step's own actions, the primary last so it sits rightmost. */
|
|
56
59
|
children?: ReactNode;
|
|
57
60
|
};
|
|
58
|
-
/** The footer that stays in place under the body: Cancel, then the actions,
|
|
61
|
+
/** The footer that stays in place under the body, on the sheet's own surface: Cancel, then the actions, at the trailing edge. */
|
|
59
62
|
export declare function FormDrawerFooter({ cancel, children }: FormDrawerFooterProps): import("react").JSX.Element;
|
|
60
63
|
/**
|
|
61
64
|
* The drawer's form: the fields in the body, a notice where the save button
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-drawer.d.ts","sourceRoot":"","sources":["../../src/components/form-drawer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvD,OAAO,EAGL,YAAY,EAKb,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,KAAK,SAAS,EAAoB,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"form-drawer.d.ts","sourceRoot":"","sources":["../../src/components/form-drawer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvD,OAAO,EAGL,YAAY,EAKb,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,KAAK,SAAS,EAAoB,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAG3E,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEpE,wFAAwF;AACxF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,qFAAqF;IACrF,oBAAoB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC/C,6FAA6F;IAC7F,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,2DAA2D;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,wGAAwG;IACxG,QAAQ,EAAE,SAAS,CAAC;IACpB,4EAA4E;IAC5E,YAAY,CAAC,EAAE,cAAc,CAAC,OAAO,YAAY,CAAC,CAAC,cAAc,CAAC,CAAC;IACnE,2EAA2E;IAC3E,UAAU,CAAC,EAAE,cAAc,CAAC,OAAO,YAAY,CAAC,CAAC,YAAY,CAAC,CAAC;IAC/D,qGAAqG;IACrG,OAAO,CAAC,EAAE,YAAY,CAAC;CACxB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAC5C,CACI;IAAE,GAAG,EAAE,SAAS,CAAA;CAAE,GAClB;IACE,GAAG,EAAE,OAAO,CAAC;IACb,8FAA8F;IAC9F,QAAQ,EAAE,MAAM,CAAC;CAClB,CACJ,CAAC;AAEJ;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,+BA0ChD;AAED,4EAA4E;AAC5E,wBAAgB,cAAc,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,cAAc,CAAC,KAAK,CAAC,+BAW5E;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,+DAA+D;IAC/D,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/C,qEAAqE;IACrE,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF,iIAAiI;AACjI,wBAAgB,gBAAgB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,qBAAqB,+BAW3E;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,EAAE,SAAS,+BAqB3F"}
|
|
@@ -4,28 +4,29 @@ import { Button } from "./button.js";
|
|
|
4
4
|
import { Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, } from "./sheet.js";
|
|
5
5
|
import { WaitingLine } from "./waiting-line.js";
|
|
6
6
|
import { FormSubmitButton } from "../internal/form-submit.js";
|
|
7
|
+
import { guardUnsaved } from "../internal/unsaved-guard.js";
|
|
7
8
|
import { cn } from "../lib/utils.js";
|
|
8
9
|
/**
|
|
9
|
-
* The right-side
|
|
10
|
+
* The right-side sheet for a catalogue or a setup in steps, at one width.
|
|
10
11
|
*
|
|
11
12
|
* @family Compositions
|
|
12
|
-
* @when
|
|
13
|
-
* @instead
|
|
14
|
-
* @behaviour
|
|
15
|
-
* @words
|
|
16
|
-
* @access
|
|
13
|
+
* @when Ours: choosing from a catalogue too long for a dialog (through `CatalogDrawer`), or setting something up in several steps with a wait: connect a messaging channel, Telegram's code.
|
|
14
|
+
* @instead "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) Ours: a new record from a few fields is a `FormDialog`; a record already in a list edits in its row with `RowEditForm`; a fact on the record's own page changes in place in its section; a consequence is confirmed in a `ConfirmDialog`; a phone's short job is a `Drawer`.
|
|
15
|
+
* @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) "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) "Outside-click does not auto-close, so always render an explicit close affordance and honor Escape." (https://vercel.com/geist/sheet) Ours: a modal `Sheet` from the right edge over the scrim, because the drawer owns the screen, at the Sheet's one width that no caller sets. The header holds the step ("Step 2 of 3") over the title, the description and Close; the body scrolls between the header and a footer that stays, with no fill or rule of its own, Cancel then the primary at its trailing edge. A press outside does not close it; Escape does, unless `unsaved.dirty` holds it back. Cancel holds while a save runs.
|
|
16
|
+
* @words "Title is Title Case and names the entity (`Deployment Details`, `Member Profile`), not the page action." (https://vercel.com/geist/sheet) "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) Ours: the title is sentence case and names the job and its object: "Connect Telegram", "Add a skill". The step reads "Step N of M". The primary says what it does: "Connect", "Continue", never "OK".
|
|
17
|
+
* @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) "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) "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) Ours: a modal dialog named by its title; focus returns to the opener on close, or to `finalFocus` when the opener is gone. The step is read before the title.
|
|
17
18
|
*/
|
|
18
19
|
export function FormDrawer(props) {
|
|
19
|
-
const { open, onOpenChange, onOpenChangeComplete, title, description, closeLabel, children, initialFocus, finalFocus, } = props;
|
|
20
|
-
return (_jsx(Sheet, { open: open, onOpenChange: onOpenChange, onOpenChangeComplete: onOpenChangeComplete, children: _jsxs(SheetContent, {
|
|
20
|
+
const { open, onOpenChange, onOpenChangeComplete, title, description, closeLabel, children, initialFocus, finalFocus = true, unsaved, } = props;
|
|
21
|
+
return (_jsx(Sheet, { modal: true, open: open, onOpenChange: guardUnsaved(onOpenChange, unsaved), onOpenChangeComplete: onOpenChangeComplete, children: _jsxs(SheetContent, { closeLabel: closeLabel, finalFocus: finalFocus, initialFocus: initialFocus, side: "right", children: [_jsxs(SheetHeader, { className: "pr-12", children: [props.job === "steps" ? (_jsx("p", { className: "font-label-mono text-label-mono text-muted-foreground", "data-slot": "form-drawer-progress", children: props.progress })) : null, _jsx(SheetTitle, { className: "break-words", children: title }), description ? _jsx(SheetDescription, { children: description }) : null] }), children] }) }));
|
|
21
22
|
}
|
|
22
23
|
/** The part of the drawer that scrolls between its title and its footer. */
|
|
23
24
|
export function FormDrawerBody({ className, ...props }) {
|
|
24
25
|
return (_jsx("div", { "data-slot": "form-drawer-body", className: cn("grid min-h-0 flex-1 grid-cols-[minmax(0,1fr)] content-start gap-4 overflow-y-auto px-nadicode-lg", className), ...props }));
|
|
25
26
|
}
|
|
26
|
-
/** The footer that stays in place under the body: Cancel, then the actions,
|
|
27
|
+
/** The footer that stays in place under the body, on the sheet's own surface: Cancel, then the actions, at the trailing edge. */
|
|
27
28
|
export function FormDrawerFooter({ cancel, children }) {
|
|
28
|
-
return (_jsxs(SheetFooter, { className: "flex-
|
|
29
|
+
return (_jsxs(SheetFooter, { className: "flex-wrap items-center", "data-slot": "form-drawer-footer", children: [cancel ? (_jsx(SheetClose, { disabled: cancel.disabled, render: _jsx(Button, { type: "button", variant: "outline" }), children: cancel.label })) : null, children] }));
|
|
29
30
|
}
|
|
30
31
|
/**
|
|
31
32
|
* The drawer's form: the fields in the body, a notice where the save button
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
import { Meter } from "@base-ui/react/meter";
|
|
3
|
+
import type { ProgressTone } from "./progress.js";
|
|
4
|
+
type GaugeSize = "xs" | "sm" | "md" | "lg";
|
|
5
|
+
type GaugeValueSize = Exclude<GaugeSize, "xs">;
|
|
6
|
+
type GaugeName = {
|
|
7
|
+
"aria-label": string;
|
|
8
|
+
"aria-labelledby"?: never;
|
|
9
|
+
} | {
|
|
10
|
+
"aria-labelledby": string;
|
|
11
|
+
"aria-label"?: never;
|
|
12
|
+
};
|
|
13
|
+
type GaugeFace = {
|
|
14
|
+
size?: GaugeValueSize;
|
|
15
|
+
showValue: true;
|
|
16
|
+
children?: never;
|
|
17
|
+
} | {
|
|
18
|
+
size?: GaugeSize;
|
|
19
|
+
showValue?: false;
|
|
20
|
+
children?: ReactElement;
|
|
21
|
+
};
|
|
22
|
+
type GaugeProps = Omit<Meter.Root.Props, "value" | "min" | "max" | "children" | "aria-label" | "aria-labelledby"> & {
|
|
23
|
+
/** The ratio, 0 to 100; a value outside it is drawn at the nearest end. */
|
|
24
|
+
value: number;
|
|
25
|
+
tone?: ProgressTone;
|
|
26
|
+
} & GaugeName & GaugeFace;
|
|
27
|
+
/**
|
|
28
|
+
* A ring that shows one ratio out of 100.
|
|
29
|
+
*
|
|
30
|
+
* @family Data
|
|
31
|
+
* @when "A 0–100 ratio against a fixed maximum where the comparison is the point, like quota usage, build cache hit rate, uptime, or billing-period consumption." (https://vercel.com/geist/gauge)
|
|
32
|
+
* Ours: `size` follows the weight of the figure beside it.
|
|
33
|
+
* @instead "For determinate task progress with a known total (uploads, multi-step setup), use `Progress`." (https://vercel.com/geist/gauge)
|
|
34
|
+
* "For binary or enumerated state, use `Status Dot` for deployments or `Badge` for everything else." (https://vercel.com/geist/gauge)
|
|
35
|
+
* Ours: those are `StatusDot` and `StatusBadge`. A single figure on its own is a `KpiCard`. A wait
|
|
36
|
+
* of unknown length is the waiting line; the gauge has no indeterminate form. Two shares of one
|
|
37
|
+
* whole are a chart.
|
|
38
|
+
* @behaviour "Use `arc="equal"` for true ratios so 50% reads as exactly half." (https://vercel.com/geist/gauge)
|
|
39
|
+
* "Use the default `primary` arc for single-percentage usage where the filled portion is the story." (https://vercel.com/geist/gauge)
|
|
40
|
+
* "When using the gauge to display a ratio, use the `equal` arc priority to make both arcs are equally sized." (https://vercel.com/geist/gauge)
|
|
41
|
+
* Ours: there is no `arc` prop; the gauge always draws the primary arc, from the top, clockwise,
|
|
42
|
+
* with round ends and a small gap before the neutral track; at 0 or 100 there is no gap. Colour
|
|
43
|
+
* sits on the arc alone: the track stays the neutral line colour, and the number and icon stay
|
|
44
|
+
* neutral.
|
|
45
|
+
* "Threshold colors should match the same numeric breakpoints used elsewhere in the product (`>=80%` warning, `>=95%` error). Don’t invent gauge-only thresholds." (https://vercel.com/geist/gauge)
|
|
46
|
+
* Ours: `tone` is that threshold, never derived from the value.
|
|
47
|
+
* "Pair `indeterminate` with explanatory copy nearby (`Calculating usage…`) so the user knows the value is loading, not zero." (https://vercel.com/geist/gauge)
|
|
48
|
+
* Ours: there is no `indeterminate`; a value still loading is the waiting line. The smallest size
|
|
49
|
+
* has room only for an icon. The arc moves on `open`, still under reduced motion.
|
|
50
|
+
* @words "Always pair the gauge with an adjacent label or `Tooltip` naming what the number represents (`Build Cache Hit Rate`). The gauge alone is not self-describing." (https://vercel.com/geist/gauge)
|
|
51
|
+
* "Don’t put units inside `children`; the label carries the unit (`Uptime · 99.97%`). `children` is reserved for an icon overlay." (https://vercel.com/geist/gauge)
|
|
52
|
+
* "When `showValue` is on, the rendered number is the value only. Never inject a `%` or unit string into the prop." (https://vercel.com/geist/gauge)
|
|
53
|
+
* Ours: sentence case, *Cache hit rate · 99.97%*. `showValue` prints the number; `children` is only
|
|
54
|
+
* an icon.
|
|
55
|
+
* @access "The component sets `role="progressbar"` with `aria-valuemin`, `aria-valuemax`, and `aria-valuenow`. Don’t override those." (https://vercel.com/geist/gauge)
|
|
56
|
+
* Ours: the role is `meter`, with the same three values.
|
|
57
|
+
* "The adjacent label is the gauge’s accessible name. Tie it with `aria-labelledby` on the gauge wrapper so screen readers read “Uptime, 99 percent.”" (https://vercel.com/geist/gauge)
|
|
58
|
+
* Ours: it always has a name, `aria-label` or `aria-labelledby` pointing at the adjacent label, and
|
|
59
|
+
* the type asks for one.
|
|
60
|
+
* "Don’t use color to encode the threshold without redundant text; pair the warning tint with copy below or in the Tooltip." (https://vercel.com/geist/gauge)
|
|
61
|
+
*/
|
|
62
|
+
declare function Gauge({ className, value, tone, size, showValue, children, ...props }: GaugeProps): import("react").JSX.Element;
|
|
63
|
+
export { Gauge };
|
|
64
|
+
//# sourceMappingURL=gauge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gauge.d.ts","sourceRoot":"","sources":["../../src/components/gauge.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAE7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAG1D,KAAK,SAAS,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAC3C,KAAK,cAAc,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;AAkC/C,KAAK,SAAS,GACV;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,KAAK,CAAA;CAAE,GACnD;IAAE,iBAAiB,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,KAAK,CAAA;CAAE,CAAC;AAExD,KAAK,SAAS,GACV;IAAE,IAAI,CAAC,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,CAAA;CAAE,GAC5D;IAAE,IAAI,CAAC,EAAE,SAAS,CAAC;IAAC,SAAS,CAAC,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,EAAE,YAAY,CAAA;CAAE,CAAC;AAErE,KAAK,UAAU,GAAG,IAAI,CACpB,KAAK,CAAC,IAAI,CAAC,KAAK,EAChB,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,UAAU,GAAG,YAAY,GAAG,iBAAiB,CACxE,GAAG;IACF,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,YAAY,CAAC;CACrB,GAAG,SAAS,GACX,SAAS,CAAC;AAEZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,iBAAS,KAAK,CAAC,EACb,SAAS,EACT,KAAK,EACL,IAAgB,EAChB,IAAW,EACX,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,UAAU,+BAuEZ;AAED,OAAO,EAAE,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Meter } from "@base-ui/react/meter";
|
|
4
|
+
import { cn } from "../lib/utils.js";
|
|
5
|
+
const GAUGE_BOX_CLASS = {
|
|
6
|
+
xs: "size-5",
|
|
7
|
+
sm: "size-8",
|
|
8
|
+
md: "size-16",
|
|
9
|
+
lg: "size-32",
|
|
10
|
+
};
|
|
11
|
+
const GAUGE_VALUE_CLASS = {
|
|
12
|
+
sm: "text-[11px] leading-5 font-medium",
|
|
13
|
+
md: "nc-type-label-lg font-medium",
|
|
14
|
+
lg: "text-[32px] leading-5 font-semibold",
|
|
15
|
+
};
|
|
16
|
+
const GAUGE_ARC_CLASS = {
|
|
17
|
+
default: "stroke-primary",
|
|
18
|
+
secondary: "stroke-muted-foreground",
|
|
19
|
+
success: "stroke-(--nc-state-complete)",
|
|
20
|
+
warning: "stroke-(--nc-state-review)",
|
|
21
|
+
critical: "stroke-(--nc-state-blocked)",
|
|
22
|
+
info: "stroke-info",
|
|
23
|
+
};
|
|
24
|
+
const GAUGE_RING = {
|
|
25
|
+
xs: { radius: 42.5, strokeWidth: 15, gap: 9 },
|
|
26
|
+
sm: { radius: 45, strokeWidth: 10, gap: 6 },
|
|
27
|
+
md: { radius: 45, strokeWidth: 10, gap: 5 },
|
|
28
|
+
lg: { radius: 45, strokeWidth: 10, gap: 5 },
|
|
29
|
+
};
|
|
30
|
+
const GAUGE_ARC_MOTION = "transition-[stroke-dasharray,stroke-dashoffset,stroke] duration-[var(--nc-duration-open)] ease-[var(--nc-ease-out-strong)] motion-reduce:transition-none";
|
|
31
|
+
/**
|
|
32
|
+
* A ring that shows one ratio out of 100.
|
|
33
|
+
*
|
|
34
|
+
* @family Data
|
|
35
|
+
* @when "A 0–100 ratio against a fixed maximum where the comparison is the point, like quota usage, build cache hit rate, uptime, or billing-period consumption." (https://vercel.com/geist/gauge)
|
|
36
|
+
* Ours: `size` follows the weight of the figure beside it.
|
|
37
|
+
* @instead "For determinate task progress with a known total (uploads, multi-step setup), use `Progress`." (https://vercel.com/geist/gauge)
|
|
38
|
+
* "For binary or enumerated state, use `Status Dot` for deployments or `Badge` for everything else." (https://vercel.com/geist/gauge)
|
|
39
|
+
* Ours: those are `StatusDot` and `StatusBadge`. A single figure on its own is a `KpiCard`. A wait
|
|
40
|
+
* of unknown length is the waiting line; the gauge has no indeterminate form. Two shares of one
|
|
41
|
+
* whole are a chart.
|
|
42
|
+
* @behaviour "Use `arc="equal"` for true ratios so 50% reads as exactly half." (https://vercel.com/geist/gauge)
|
|
43
|
+
* "Use the default `primary` arc for single-percentage usage where the filled portion is the story." (https://vercel.com/geist/gauge)
|
|
44
|
+
* "When using the gauge to display a ratio, use the `equal` arc priority to make both arcs are equally sized." (https://vercel.com/geist/gauge)
|
|
45
|
+
* Ours: there is no `arc` prop; the gauge always draws the primary arc, from the top, clockwise,
|
|
46
|
+
* with round ends and a small gap before the neutral track; at 0 or 100 there is no gap. Colour
|
|
47
|
+
* sits on the arc alone: the track stays the neutral line colour, and the number and icon stay
|
|
48
|
+
* neutral.
|
|
49
|
+
* "Threshold colors should match the same numeric breakpoints used elsewhere in the product (`>=80%` warning, `>=95%` error). Don’t invent gauge-only thresholds." (https://vercel.com/geist/gauge)
|
|
50
|
+
* Ours: `tone` is that threshold, never derived from the value.
|
|
51
|
+
* "Pair `indeterminate` with explanatory copy nearby (`Calculating usage…`) so the user knows the value is loading, not zero." (https://vercel.com/geist/gauge)
|
|
52
|
+
* Ours: there is no `indeterminate`; a value still loading is the waiting line. The smallest size
|
|
53
|
+
* has room only for an icon. The arc moves on `open`, still under reduced motion.
|
|
54
|
+
* @words "Always pair the gauge with an adjacent label or `Tooltip` naming what the number represents (`Build Cache Hit Rate`). The gauge alone is not self-describing." (https://vercel.com/geist/gauge)
|
|
55
|
+
* "Don’t put units inside `children`; the label carries the unit (`Uptime · 99.97%`). `children` is reserved for an icon overlay." (https://vercel.com/geist/gauge)
|
|
56
|
+
* "When `showValue` is on, the rendered number is the value only. Never inject a `%` or unit string into the prop." (https://vercel.com/geist/gauge)
|
|
57
|
+
* Ours: sentence case, *Cache hit rate · 99.97%*. `showValue` prints the number; `children` is only
|
|
58
|
+
* an icon.
|
|
59
|
+
* @access "The component sets `role="progressbar"` with `aria-valuemin`, `aria-valuemax`, and `aria-valuenow`. Don’t override those." (https://vercel.com/geist/gauge)
|
|
60
|
+
* Ours: the role is `meter`, with the same three values.
|
|
61
|
+
* "The adjacent label is the gauge’s accessible name. Tie it with `aria-labelledby` on the gauge wrapper so screen readers read “Uptime, 99 percent.”" (https://vercel.com/geist/gauge)
|
|
62
|
+
* Ours: it always has a name, `aria-label` or `aria-labelledby` pointing at the adjacent label, and
|
|
63
|
+
* the type asks for one.
|
|
64
|
+
* "Don’t use color to encode the threshold without redundant text; pair the warning tint with copy below or in the Tooltip." (https://vercel.com/geist/gauge)
|
|
65
|
+
*/
|
|
66
|
+
function Gauge({ className, value, tone = "default", size = "md", showValue, children, ...props }) {
|
|
67
|
+
const ratio = Math.min(100, Math.max(0, value));
|
|
68
|
+
const { radius, strokeWidth, gap } = GAUGE_RING[size];
|
|
69
|
+
const gapLength = ratio === 0 || ratio === 100 ? 0 : gap;
|
|
70
|
+
const trackLength = Math.max(0, 100 - ratio - 2 * gapLength);
|
|
71
|
+
return (_jsxs(Meter.Root, { className: cn("relative inline-flex shrink-0 items-center justify-center", GAUGE_BOX_CLASS[size], className), "data-size": size, "data-slot": "gauge", "data-tone": tone, max: 100, min: 0, value: ratio, ...props, children: [_jsxs("svg", { "aria-hidden": "true", className: "absolute inset-0 size-full -rotate-90", fill: "none", viewBox: "0 0 100 100", children: [_jsx("circle", { className: cn("stroke-border", GAUGE_ARC_MOTION), cx: "50", cy: "50", "data-slot": "gauge-track", opacity: trackLength === 0 ? 0 : 1, pathLength: 100, r: radius, strokeDasharray: `${trackLength} 100`, strokeDashoffset: -(ratio + gapLength), strokeLinecap: "round", strokeWidth: strokeWidth }), _jsx("circle", { className: cn(GAUGE_ARC_CLASS[tone], GAUGE_ARC_MOTION), cx: "50", cy: "50", "data-slot": "gauge-arc", opacity: ratio === 0 ? 0 : 1, pathLength: 100, r: radius, strokeDasharray: `${ratio} 100`, strokeLinecap: "round", strokeWidth: strokeWidth })] }), showValue && size !== "xs" ? (_jsx("span", { className: cn("relative tabular-nums", GAUGE_VALUE_CLASS[size]), "data-slot": "gauge-value", children: Math.round(ratio) })) : null, children ? (_jsx("span", { className: "absolute inset-0 flex items-center justify-center text-muted-foreground [&>svg]:size-1/2", "data-slot": "gauge-icon", children: children })) : null] }));
|
|
72
|
+
}
|
|
73
|
+
export { Gauge };
|