@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
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* A technical string cut in the middle, so its start and its end both stay readable.
|
|
4
|
+
*
|
|
5
|
+
* @family Data
|
|
6
|
+
* @when “Use Middle Truncate for strings whose head and tail both carry information: file paths (`apps/…/page.tsx`), URLs, deployment IDs (`dpl_…abc123`), commit hashes, branch names with prefixes.” (https://vercel.com/geist/middle-truncate)
|
|
7
|
+
* Ours: an environment variable is one of these too.
|
|
8
|
+
* @instead “For prose, descriptions, and headings, use end-truncation with `…` instead; cutting the middle of a sentence destroys meaning.” (https://vercel.com/geist/middle-truncate)
|
|
9
|
+
* “For any truncated value the user might need verbatim, pair with a `Tooltip` showing the full string or a copy-on-click affordance.” (https://vercel.com/geist/middle-truncate)
|
|
10
|
+
* Ours: a value someone may need exactly is `TextWithCopyButton` or sits beside a `CopyButton`; while
|
|
11
|
+
* the middle is cut, the whole value is also the element's `title`.
|
|
12
|
+
* @behaviour “Middle Truncate renders a single ellipsis glyph (`…`) rather than three periods. This keeps monospace values, including environment variable keys, IDs, hashes, and paths, from reserving three character cells for the truncation marker.” (https://vercel.com/geist/middle-truncate)
|
|
13
|
+
* “The component listens to its container width, so layouts that change width on hover (expanding cards, animated rows) cause the truncation point to jitter. Lock the width during interaction.” (https://vercel.com/geist/middle-truncate)
|
|
14
|
+
* “Copying truncated text yields the full original string from the underlying value, not the visible ellipsis form. Confirm this stays true if wrapping with custom `onCopy`.” (https://vercel.com/geist/middle-truncate)
|
|
15
|
+
* “Don’t wrap Middle Truncate in another `text-overflow: ellipsis` container; the two strategies fight each other and the inner ellipsis wins inconsistently.” (https://vercel.com/geist/middle-truncate)
|
|
16
|
+
* “Keep the visible string long enough on small viewports that the head still identifies the resource (path segment, ID prefix).” (https://vercel.com/geist/middle-truncate)
|
|
17
|
+
* Ours: it fills the width its parent gives and shows the whole value when it fits. Too narrow, the
|
|
18
|
+
* last third of the value, at most 16 characters, stays whole. While the middle is cut, copying a
|
|
19
|
+
* selection made inside it puts the whole value on the clipboard; a value shown in full copies only
|
|
20
|
+
* what is selected. A custom `onCopy` runs first, and `preventDefault` in it keeps the value as
|
|
21
|
+
* selected.
|
|
22
|
+
* @words Ours: the value as the system writes it, unchanged; the ellipsis comes from the layout, never from
|
|
23
|
+
* the text.
|
|
24
|
+
* @access “Expose the full string to assistive tech via the wrapping element’s accessible name (the component already keeps the full value in the DOM for copy).” (https://vercel.com/geist/middle-truncate)
|
|
25
|
+
* “Avoid Middle Truncate inside focusable controls without an explicit `aria-label`; the ellipsis on its own gives screen readers nothing to announce.” (https://vercel.com/geist/middle-truncate)
|
|
26
|
+
* Ours: the whole value is the element's text, read in full; inside a link or a button, the control
|
|
27
|
+
* carries the `aria-label` that names the target.
|
|
28
|
+
*/
|
|
29
|
+
declare function MiddleTruncate({ className, onCopy, value, ...props }: Omit<React.ComponentProps<"span">, "children"> & {
|
|
30
|
+
value: string;
|
|
31
|
+
}): React.JSX.Element;
|
|
32
|
+
export { MiddleTruncate };
|
|
33
|
+
//# sourceMappingURL=middle-truncate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middle-truncate.d.ts","sourceRoot":"","sources":["../../src/components/middle-truncate.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAmC/B;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,iBAAS,cAAc,CAAC,EACtB,SAAS,EACT,MAAM,EACN,KAAK,EACL,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,UAAU,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,qBA0BpE;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "../lib/utils.js";
|
|
5
|
+
const TAIL_SHARE = 3;
|
|
6
|
+
const TAIL_MAX = 16;
|
|
7
|
+
function copiesWholeValue(root) {
|
|
8
|
+
const head = root.firstElementChild;
|
|
9
|
+
const selection = window.getSelection();
|
|
10
|
+
return (head !== null &&
|
|
11
|
+
head.scrollWidth > head.clientWidth &&
|
|
12
|
+
selection !== null &&
|
|
13
|
+
!selection.isCollapsed &&
|
|
14
|
+
root.contains(selection.anchorNode) &&
|
|
15
|
+
root.contains(selection.focusNode));
|
|
16
|
+
}
|
|
17
|
+
function useIsCut(root, value) {
|
|
18
|
+
const [cut, setCut] = React.useState(false);
|
|
19
|
+
React.useEffect(() => {
|
|
20
|
+
const element = root.current;
|
|
21
|
+
const head = element?.firstElementChild;
|
|
22
|
+
if (!element || !head || typeof ResizeObserver === "undefined")
|
|
23
|
+
return;
|
|
24
|
+
const measure = () => setCut(head.scrollWidth > head.clientWidth);
|
|
25
|
+
measure();
|
|
26
|
+
const observer = new ResizeObserver(measure);
|
|
27
|
+
observer.observe(element);
|
|
28
|
+
return () => observer.disconnect();
|
|
29
|
+
}, [root, value]);
|
|
30
|
+
return cut;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A technical string cut in the middle, so its start and its end both stay readable.
|
|
34
|
+
*
|
|
35
|
+
* @family Data
|
|
36
|
+
* @when “Use Middle Truncate for strings whose head and tail both carry information: file paths (`apps/…/page.tsx`), URLs, deployment IDs (`dpl_…abc123`), commit hashes, branch names with prefixes.” (https://vercel.com/geist/middle-truncate)
|
|
37
|
+
* Ours: an environment variable is one of these too.
|
|
38
|
+
* @instead “For prose, descriptions, and headings, use end-truncation with `…` instead; cutting the middle of a sentence destroys meaning.” (https://vercel.com/geist/middle-truncate)
|
|
39
|
+
* “For any truncated value the user might need verbatim, pair with a `Tooltip` showing the full string or a copy-on-click affordance.” (https://vercel.com/geist/middle-truncate)
|
|
40
|
+
* Ours: a value someone may need exactly is `TextWithCopyButton` or sits beside a `CopyButton`; while
|
|
41
|
+
* the middle is cut, the whole value is also the element's `title`.
|
|
42
|
+
* @behaviour “Middle Truncate renders a single ellipsis glyph (`…`) rather than three periods. This keeps monospace values, including environment variable keys, IDs, hashes, and paths, from reserving three character cells for the truncation marker.” (https://vercel.com/geist/middle-truncate)
|
|
43
|
+
* “The component listens to its container width, so layouts that change width on hover (expanding cards, animated rows) cause the truncation point to jitter. Lock the width during interaction.” (https://vercel.com/geist/middle-truncate)
|
|
44
|
+
* “Copying truncated text yields the full original string from the underlying value, not the visible ellipsis form. Confirm this stays true if wrapping with custom `onCopy`.” (https://vercel.com/geist/middle-truncate)
|
|
45
|
+
* “Don’t wrap Middle Truncate in another `text-overflow: ellipsis` container; the two strategies fight each other and the inner ellipsis wins inconsistently.” (https://vercel.com/geist/middle-truncate)
|
|
46
|
+
* “Keep the visible string long enough on small viewports that the head still identifies the resource (path segment, ID prefix).” (https://vercel.com/geist/middle-truncate)
|
|
47
|
+
* Ours: it fills the width its parent gives and shows the whole value when it fits. Too narrow, the
|
|
48
|
+
* last third of the value, at most 16 characters, stays whole. While the middle is cut, copying a
|
|
49
|
+
* selection made inside it puts the whole value on the clipboard; a value shown in full copies only
|
|
50
|
+
* what is selected. A custom `onCopy` runs first, and `preventDefault` in it keeps the value as
|
|
51
|
+
* selected.
|
|
52
|
+
* @words Ours: the value as the system writes it, unchanged; the ellipsis comes from the layout, never from
|
|
53
|
+
* the text.
|
|
54
|
+
* @access “Expose the full string to assistive tech via the wrapping element’s accessible name (the component already keeps the full value in the DOM for copy).” (https://vercel.com/geist/middle-truncate)
|
|
55
|
+
* “Avoid Middle Truncate inside focusable controls without an explicit `aria-label`; the ellipsis on its own gives screen readers nothing to announce.” (https://vercel.com/geist/middle-truncate)
|
|
56
|
+
* Ours: the whole value is the element's text, read in full; inside a link or a button, the control
|
|
57
|
+
* carries the `aria-label` that names the target.
|
|
58
|
+
*/
|
|
59
|
+
function MiddleTruncate({ className, onCopy, value, ...props }) {
|
|
60
|
+
const root = React.useRef(null);
|
|
61
|
+
const cut = useIsCut(root, value);
|
|
62
|
+
const characters = Array.from(value);
|
|
63
|
+
const tailStart = characters.length - Math.min(Math.ceil(characters.length / TAIL_SHARE), TAIL_MAX);
|
|
64
|
+
return (_jsxs("span", { ref: root, "data-slot": "middle-truncate", title: cut ? value : undefined, className: cn("inline-flex max-w-full min-w-0 overflow-hidden", className), onCopy: (event) => {
|
|
65
|
+
onCopy?.(event);
|
|
66
|
+
if (event.defaultPrevented || !copiesWholeValue(event.currentTarget))
|
|
67
|
+
return;
|
|
68
|
+
event.clipboardData.setData("text/plain", value);
|
|
69
|
+
event.preventDefault();
|
|
70
|
+
}, ...props, children: [_jsx("span", { className: "min-w-0 overflow-hidden text-ellipsis whitespace-pre", children: characters.slice(0, tailStart).join("") }), _jsx("span", { className: "shrink-0 whitespace-pre", children: characters.slice(tailStart).join("") })] }));
|
|
71
|
+
}
|
|
72
|
+
export { MiddleTruncate };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type FieldName } from "../internal/field-frame.js";
|
|
3
|
+
import { type FieldSize } from "../internal/input-box.js";
|
|
4
|
+
import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
|
|
5
|
+
type MultiSelectContextValue = {
|
|
6
|
+
selectedCount: number;
|
|
7
|
+
totalCount: number;
|
|
8
|
+
onSelectAll: () => void;
|
|
9
|
+
selectOnlyLabel: string;
|
|
10
|
+
selectAllLabel: string;
|
|
11
|
+
};
|
|
12
|
+
type MultiSelectProps = React.ComponentProps<typeof Popover> & MultiSelectContextValue;
|
|
13
|
+
/**
|
|
14
|
+
* A menu of checkbox rows that chooses several values from a known list, with the count in its
|
|
15
|
+
* trigger.
|
|
16
|
+
*
|
|
17
|
+
* @family Choices
|
|
18
|
+
* @when "A keyboard-navigable dropdown for selecting multiple items with advanced focus management."
|
|
19
|
+
* (https://vercel.com/geist/multi-select) "Pick `<MultiSelect>` when users pick more than one value
|
|
20
|
+
* from a known list (regions, scopes, tags)." (https://vercel.com/geist/multi-select) Ours: also the facets of a collection.
|
|
21
|
+
* @instead "For a single value from a short list, use `Select`."
|
|
22
|
+
* (https://vercel.com/geist/multi-select) "When typing to filter is more important than seeing
|
|
23
|
+
* every option at once, use `Combobox`." (https://vercel.com/geist/multi-select) "Skip
|
|
24
|
+
* `<MultiSelect>` for boolean settings; `Toggle` handles those."
|
|
25
|
+
* (https://vercel.com/geist/multi-select) Ours: `Combobox` takes several values with `multiple`; a
|
|
26
|
+
* yes-or-no setting is a `Switch`, never a one-row multi-select.
|
|
27
|
+
* @behaviour "Use controlled mode when state lives in the URL or syncs to the server so the trigger
|
|
28
|
+
* label and stored value stay in lockstep." (https://vercel.com/geist/multi-select) "Use controlled
|
|
29
|
+
* state to manage selections programmatically." (https://vercel.com/geist/multi-select) Ours: the
|
|
30
|
+
* caller always owns the selection and passes it back through each row, so the trigger and the
|
|
31
|
+
* stored value (the URL, the server) never disagree; the root takes the same `selectedCount` and
|
|
32
|
+
* `totalCount` the trigger's summary is built from. "Show the selected count in the trigger (`3
|
|
33
|
+
* regions selected`); show the single name when only one is picked."
|
|
34
|
+
* (https://vercel.com/geist/multi-select) The trigger is `Input`'s box at its default size, in
|
|
35
|
+
* regular weight, with the chevron at the end (it turns up while the list is open); it keeps the
|
|
36
|
+
* hover edge while the list is open and takes the page's outline for keyboard focus, as a button
|
|
37
|
+
* does. Everything is neutral: a checked box is ink, never blue, and an error turns only the
|
|
38
|
+
* trigger's ring red. `label` and `error` go on `MultiSelectTrigger`, and a string `label` requires
|
|
39
|
+
* `id`; a trigger with no name does not compile. The list opens 8 px under the trigger at least as
|
|
40
|
+
* wide as it, in an 8 px inset, with rows 28 px tall and no gap, and stops 16 px short of the
|
|
41
|
+
* screen's edge (at most 24rem tall, then it scrolls). A row is the checkbox in a 28 px square that
|
|
42
|
+
* fills on hover, then a button holding the row's name; pressing the name runs the button, pressing
|
|
43
|
+
* the box toggles the row. "**Checkbox focus + Enter/Space**: Toggle individual item"
|
|
44
|
+
* (https://vercel.com/geist/multi-select) "**Button focus + Enter/Space**: Smart selection (Select
|
|
45
|
+
* Only, Select All, or Toggle based on context)" (https://vercel.com/geist/multi-select) "**Hidden
|
|
46
|
+
* action labels**: Appear on hover/focus to show available actions"
|
|
47
|
+
* (https://vercel.com/geist/multi-select) Ours: the button's label reads *Select all* on a chosen
|
|
48
|
+
* row while some rows are unchosen, and *Select only* on every other row; it shows on hover and
|
|
49
|
+
* focus of the row, and always on touch. "Keep checkbox focus and button focus distinct so Up/Down
|
|
50
|
+
* navigates rows and Left/Right toggles between the row’s checkbox and action button."
|
|
51
|
+
* (https://vercel.com/geist/multi-select) "**Up/Down arrows**: Navigate between rows while
|
|
52
|
+
* maintaining checkbox/button focus state" (https://vercel.com/geist/multi-select) "**Left/Right
|
|
53
|
+
* arrows**: Switch between checkbox and button focus within the current row"
|
|
54
|
+
* (https://vercel.com/geist/multi-select) "**Tab**: Focus away from the menu (natural tab
|
|
55
|
+
* behavior)" (https://vercel.com/geist/multi-select) "**Enter/Space**: Execute actions based on
|
|
56
|
+
* current focus (checkbox toggle or button click)" (https://vercel.com/geist/multi-select) "Trap
|
|
57
|
+
* focus inside the menu while it’s open and return focus to the trigger on close."
|
|
58
|
+
* (https://vercel.com/geist/multi-select) Ours: focus moves into the list when it opens; Tab leaves
|
|
59
|
+
* it in order. "For empty filters, render `No {items} match "{query}"` rather than `No results`."
|
|
60
|
+
* (https://vercel.com/geist/multi-select) Ours: there is no filter box, so a list that needs one is
|
|
61
|
+
* a `Combobox` with `multiple`.
|
|
62
|
+
* @words The trigger says how many are chosen in the product's words: the name when exactly one is
|
|
63
|
+
* chosen, *No regions selected* when none. It is never empty. Rows are sentence case names.
|
|
64
|
+
* "Announce bulk actions (`Select All`, `Select Only`) through the visible button label so the
|
|
65
|
+
* action matches what the screen reader speaks." (https://vercel.com/geist/multi-select) Ours: the
|
|
66
|
+
* two button labels come from the caller, in sentence case.
|
|
67
|
+
* @access "Each row checkbox needs an `aria-label` that names the item (`Select us-east-1`); a bare
|
|
68
|
+
* `Select` is unanchored for screen readers." (https://vercel.com/geist/multi-select) Ours: each
|
|
69
|
+
* row's checkbox is named by the row's name; each button is named by its label and the row (*Select
|
|
70
|
+
* only us-east-1*). "The trigger button needs a stable accessible name even when zero items are
|
|
71
|
+
* selected; don’t rely on the placeholder alone." (https://vercel.com/geist/multi-select) Ours: the
|
|
72
|
+
* trigger is a button with `aria-expanded`, named by its visible label tied by `id`, or by
|
|
73
|
+
* `aria-label` or `aria-labelledby`; the summary describes it.
|
|
74
|
+
*/
|
|
75
|
+
declare function MultiSelect({ selectedCount, totalCount, onSelectAll, selectOnlyLabel, selectAllLabel, ...props }: MultiSelectProps): React.JSX.Element;
|
|
76
|
+
declare function MultiSelectTrigger({ className, children, size, label, error, ...props }: Omit<React.ComponentProps<typeof PopoverTrigger>, "children"> & {
|
|
77
|
+
/** The summary of the choice: a count, a name, or that nothing is chosen. It describes the trigger. */
|
|
78
|
+
children: string;
|
|
79
|
+
size?: FieldSize;
|
|
80
|
+
/** The message under the box, in the product's words; it also marks the box invalid. */
|
|
81
|
+
error?: string;
|
|
82
|
+
} & FieldName): React.JSX.Element;
|
|
83
|
+
declare function MultiSelectContent({ className, align, sideOffset, onKeyDown, ...props }: React.ComponentProps<typeof PopoverContent>): React.JSX.Element;
|
|
84
|
+
declare function MultiSelectRow({ name, checked, onCheckedChange, onSelectOnly, disabled, className, }: {
|
|
85
|
+
name: string;
|
|
86
|
+
checked: boolean;
|
|
87
|
+
onCheckedChange: (checked: boolean) => void;
|
|
88
|
+
/** Chooses this row and clears the rest. */
|
|
89
|
+
onSelectOnly: () => void;
|
|
90
|
+
disabled?: boolean;
|
|
91
|
+
className?: string;
|
|
92
|
+
}): React.JSX.Element;
|
|
93
|
+
export { MultiSelect, MultiSelectContent, MultiSelectRow, MultiSelectTrigger };
|
|
94
|
+
//# sourceMappingURL=multi-select.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-select.d.ts","sourceRoot":"","sources":["../../src/components/multi-select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAE1E,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG/E,KAAK,uBAAuB,GAAG;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAUF,KAAK,gBAAgB,GAAG,KAAK,CAAC,cAAc,CAAC,OAAO,OAAO,CAAC,GAAG,uBAAuB,CAAC;AAEvF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,iBAAS,WAAW,CAAC,EACnB,aAAa,EACb,UAAU,EACV,WAAW,EACX,eAAe,EACf,cAAc,EACd,GAAG,KAAK,EACT,EAAE,gBAAgB,qBAUlB;AAED,iBAAS,kBAAkB,CAAC,EAC1B,SAAS,EACT,QAAQ,EACR,IAAgB,EAChB,KAAK,EACL,KAAK,EACL,GAAG,KAAK,EACT,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,EAAE,UAAU,CAAC,GAAG;IACjE,uGAAuG;IACvG,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,wFAAwF;IACxF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,SAAS,qBAmCZ;AAwBD,iBAAS,kBAAkB,CAAC,EAC1B,SAAS,EACT,KAAe,EACf,UAAc,EACd,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,OAAO,cAAc,CAAC,qBAiB7C;AAED,iBAAS,cAAc,CAAC,EACtB,IAAI,EACJ,OAAO,EACP,eAAe,EACf,YAAY,EACZ,QAAQ,EACR,SAAS,GACV,EAAE;IACD,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5C,4CAA4C;IAC5C,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,qBAuDA;AAED,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { ChevronDownIcon, ChevronUpIcon } from "lucide-react";
|
|
5
|
+
import { cn } from "../lib/utils.js";
|
|
6
|
+
import { Button } from "./button.js";
|
|
7
|
+
import { Checkbox } from "./checkbox.js";
|
|
8
|
+
import { FieldFrame } from "../internal/field-frame.js";
|
|
9
|
+
import { fieldTriggerStates } from "../internal/input-box.js";
|
|
10
|
+
import { Label } from "./label.js";
|
|
11
|
+
import { Popover, PopoverContent, PopoverTrigger } from "./popover.js";
|
|
12
|
+
import { selectTriggerVariants } from "./select.js";
|
|
13
|
+
const MultiSelectContext = React.createContext(null);
|
|
14
|
+
function useMultiSelect() {
|
|
15
|
+
const context = React.useContext(MultiSelectContext);
|
|
16
|
+
if (!context)
|
|
17
|
+
throw new Error("MultiSelectRow must be inside <MultiSelect>");
|
|
18
|
+
return context;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A menu of checkbox rows that chooses several values from a known list, with the count in its
|
|
22
|
+
* trigger.
|
|
23
|
+
*
|
|
24
|
+
* @family Choices
|
|
25
|
+
* @when "A keyboard-navigable dropdown for selecting multiple items with advanced focus management."
|
|
26
|
+
* (https://vercel.com/geist/multi-select) "Pick `<MultiSelect>` when users pick more than one value
|
|
27
|
+
* from a known list (regions, scopes, tags)." (https://vercel.com/geist/multi-select) Ours: also the facets of a collection.
|
|
28
|
+
* @instead "For a single value from a short list, use `Select`."
|
|
29
|
+
* (https://vercel.com/geist/multi-select) "When typing to filter is more important than seeing
|
|
30
|
+
* every option at once, use `Combobox`." (https://vercel.com/geist/multi-select) "Skip
|
|
31
|
+
* `<MultiSelect>` for boolean settings; `Toggle` handles those."
|
|
32
|
+
* (https://vercel.com/geist/multi-select) Ours: `Combobox` takes several values with `multiple`; a
|
|
33
|
+
* yes-or-no setting is a `Switch`, never a one-row multi-select.
|
|
34
|
+
* @behaviour "Use controlled mode when state lives in the URL or syncs to the server so the trigger
|
|
35
|
+
* label and stored value stay in lockstep." (https://vercel.com/geist/multi-select) "Use controlled
|
|
36
|
+
* state to manage selections programmatically." (https://vercel.com/geist/multi-select) Ours: the
|
|
37
|
+
* caller always owns the selection and passes it back through each row, so the trigger and the
|
|
38
|
+
* stored value (the URL, the server) never disagree; the root takes the same `selectedCount` and
|
|
39
|
+
* `totalCount` the trigger's summary is built from. "Show the selected count in the trigger (`3
|
|
40
|
+
* regions selected`); show the single name when only one is picked."
|
|
41
|
+
* (https://vercel.com/geist/multi-select) The trigger is `Input`'s box at its default size, in
|
|
42
|
+
* regular weight, with the chevron at the end (it turns up while the list is open); it keeps the
|
|
43
|
+
* hover edge while the list is open and takes the page's outline for keyboard focus, as a button
|
|
44
|
+
* does. Everything is neutral: a checked box is ink, never blue, and an error turns only the
|
|
45
|
+
* trigger's ring red. `label` and `error` go on `MultiSelectTrigger`, and a string `label` requires
|
|
46
|
+
* `id`; a trigger with no name does not compile. The list opens 8 px under the trigger at least as
|
|
47
|
+
* wide as it, in an 8 px inset, with rows 28 px tall and no gap, and stops 16 px short of the
|
|
48
|
+
* screen's edge (at most 24rem tall, then it scrolls). A row is the checkbox in a 28 px square that
|
|
49
|
+
* fills on hover, then a button holding the row's name; pressing the name runs the button, pressing
|
|
50
|
+
* the box toggles the row. "**Checkbox focus + Enter/Space**: Toggle individual item"
|
|
51
|
+
* (https://vercel.com/geist/multi-select) "**Button focus + Enter/Space**: Smart selection (Select
|
|
52
|
+
* Only, Select All, or Toggle based on context)" (https://vercel.com/geist/multi-select) "**Hidden
|
|
53
|
+
* action labels**: Appear on hover/focus to show available actions"
|
|
54
|
+
* (https://vercel.com/geist/multi-select) Ours: the button's label reads *Select all* on a chosen
|
|
55
|
+
* row while some rows are unchosen, and *Select only* on every other row; it shows on hover and
|
|
56
|
+
* focus of the row, and always on touch. "Keep checkbox focus and button focus distinct so Up/Down
|
|
57
|
+
* navigates rows and Left/Right toggles between the row’s checkbox and action button."
|
|
58
|
+
* (https://vercel.com/geist/multi-select) "**Up/Down arrows**: Navigate between rows while
|
|
59
|
+
* maintaining checkbox/button focus state" (https://vercel.com/geist/multi-select) "**Left/Right
|
|
60
|
+
* arrows**: Switch between checkbox and button focus within the current row"
|
|
61
|
+
* (https://vercel.com/geist/multi-select) "**Tab**: Focus away from the menu (natural tab
|
|
62
|
+
* behavior)" (https://vercel.com/geist/multi-select) "**Enter/Space**: Execute actions based on
|
|
63
|
+
* current focus (checkbox toggle or button click)" (https://vercel.com/geist/multi-select) "Trap
|
|
64
|
+
* focus inside the menu while it’s open and return focus to the trigger on close."
|
|
65
|
+
* (https://vercel.com/geist/multi-select) Ours: focus moves into the list when it opens; Tab leaves
|
|
66
|
+
* it in order. "For empty filters, render `No {items} match "{query}"` rather than `No results`."
|
|
67
|
+
* (https://vercel.com/geist/multi-select) Ours: there is no filter box, so a list that needs one is
|
|
68
|
+
* a `Combobox` with `multiple`.
|
|
69
|
+
* @words The trigger says how many are chosen in the product's words: the name when exactly one is
|
|
70
|
+
* chosen, *No regions selected* when none. It is never empty. Rows are sentence case names.
|
|
71
|
+
* "Announce bulk actions (`Select All`, `Select Only`) through the visible button label so the
|
|
72
|
+
* action matches what the screen reader speaks." (https://vercel.com/geist/multi-select) Ours: the
|
|
73
|
+
* two button labels come from the caller, in sentence case.
|
|
74
|
+
* @access "Each row checkbox needs an `aria-label` that names the item (`Select us-east-1`); a bare
|
|
75
|
+
* `Select` is unanchored for screen readers." (https://vercel.com/geist/multi-select) Ours: each
|
|
76
|
+
* row's checkbox is named by the row's name; each button is named by its label and the row (*Select
|
|
77
|
+
* only us-east-1*). "The trigger button needs a stable accessible name even when zero items are
|
|
78
|
+
* selected; don’t rely on the placeholder alone." (https://vercel.com/geist/multi-select) Ours: the
|
|
79
|
+
* trigger is a button with `aria-expanded`, named by its visible label tied by `id`, or by
|
|
80
|
+
* `aria-label` or `aria-labelledby`; the summary describes it.
|
|
81
|
+
*/
|
|
82
|
+
function MultiSelect({ selectedCount, totalCount, onSelectAll, selectOnlyLabel, selectAllLabel, ...props }) {
|
|
83
|
+
const value = React.useMemo(() => ({ selectedCount, totalCount, onSelectAll, selectOnlyLabel, selectAllLabel }), [selectedCount, totalCount, onSelectAll, selectOnlyLabel, selectAllLabel]);
|
|
84
|
+
return (_jsx(MultiSelectContext.Provider, { value: value, children: _jsx(Popover, { ...props }) }));
|
|
85
|
+
}
|
|
86
|
+
function MultiSelectTrigger({ className, children, size = "default", label, error, ...props }) {
|
|
87
|
+
const summaryId = React.useId();
|
|
88
|
+
return (_jsx(FieldFrame, { label: label, error: error, size: size, control: props, children: (aria) => (_jsxs(PopoverTrigger, { "data-slot": "multi-select-trigger", "data-size": size, "data-field-frame": "", className: cn(selectTriggerVariants({ size }), fieldTriggerStates, "group/multi-select-trigger pr-3.25 pl-2.5", size !== "lg" && "leading-5.25", className), ...props, ...aria, "aria-describedby": [aria["aria-describedby"], summaryId].filter(Boolean).join(" "), children: [_jsx("span", { id: summaryId, className: "flex-1 truncate px-1.5 text-left", children: children }), _jsx(ChevronDownIcon, { "aria-hidden": "true", className: "size-3.5 text-muted-foreground group-data-popup-open/multi-select-trigger:hidden" }), _jsx(ChevronUpIcon, { "aria-hidden": "true", className: "hidden size-3.5 text-muted-foreground group-data-popup-open/multi-select-trigger:block" })] })) }));
|
|
89
|
+
}
|
|
90
|
+
const ROW = "[data-slot=multi-select-row]";
|
|
91
|
+
function moveFocus(event) {
|
|
92
|
+
const target = event.target;
|
|
93
|
+
if (!(target instanceof HTMLElement))
|
|
94
|
+
return;
|
|
95
|
+
const column = target.closest("[data-multi-select]")?.dataset.multiSelect;
|
|
96
|
+
const row = target.closest(ROW);
|
|
97
|
+
if (!column || !row)
|
|
98
|
+
return;
|
|
99
|
+
const rows = [...event.currentTarget.querySelectorAll(ROW)];
|
|
100
|
+
const index = rows.indexOf(row);
|
|
101
|
+
const focusIn = (next, name) => {
|
|
102
|
+
const control = next?.querySelector(`[data-multi-select=${name}]`);
|
|
103
|
+
if (!control)
|
|
104
|
+
return;
|
|
105
|
+
event.preventDefault();
|
|
106
|
+
control.focus();
|
|
107
|
+
};
|
|
108
|
+
if (event.key === "ArrowDown")
|
|
109
|
+
focusIn(rows[index + 1], column);
|
|
110
|
+
else if (event.key === "ArrowUp")
|
|
111
|
+
focusIn(rows[index - 1], column);
|
|
112
|
+
else if (event.key === "ArrowRight" && column === "check")
|
|
113
|
+
focusIn(row, "action");
|
|
114
|
+
else if (event.key === "ArrowLeft" && column === "action")
|
|
115
|
+
focusIn(row, "check");
|
|
116
|
+
}
|
|
117
|
+
function MultiSelectContent({ className, align = "start", sideOffset = 8, onKeyDown, ...props }) {
|
|
118
|
+
return (_jsx(PopoverContent, { "data-slot": "multi-select-content", align: align, sideOffset: sideOffset, className: cn("max-h-[min(calc(var(--available-height)---spacing(4)),24rem)] w-auto min-w-(--anchor-width) gap-0 overflow-y-auto p-2", className), onKeyDown: (event) => {
|
|
119
|
+
onKeyDown?.(event);
|
|
120
|
+
if (!event.defaultPrevented)
|
|
121
|
+
moveFocus(event);
|
|
122
|
+
}, ...props }));
|
|
123
|
+
}
|
|
124
|
+
function MultiSelectRow({ name, checked, onCheckedChange, onSelectOnly, disabled, className, }) {
|
|
125
|
+
const { selectedCount, totalCount, onSelectAll, selectOnlyLabel, selectAllLabel } = useMultiSelect();
|
|
126
|
+
const id = React.useId();
|
|
127
|
+
const actionId = `${id}-action`;
|
|
128
|
+
const nameId = `${id}-name`;
|
|
129
|
+
const selectsAll = checked && selectedCount < totalCount;
|
|
130
|
+
return (_jsxs("div", { "data-slot": "multi-select-row", className: cn("group/multi-select-row flex min-h-touch-target items-center text-sm [@media(hover:hover)_and_(pointer:fine)]:min-h-7", className), children: [_jsx(Label, { className: "size-7 shrink-0 justify-center gap-0 rounded-xs-plus hover:bg-accent active:bg-border has-data-disabled:pointer-events-none", htmlFor: id, children: _jsx(Checkbox, { id: id, "aria-labelledby": nameId, checked: checked, "data-multi-select": "check", disabled: disabled, onCheckedChange: onCheckedChange }) }), totalCount > 1 ? (_jsxs(Button, { "aria-labelledby": `${actionId} ${nameId}`, className: "h-7 flex-1 justify-between gap-0 rounded-xs-plus p-1 text-sm font-normal hover:bg-accent focus-visible:bg-accent active:bg-border disabled:text-placeholder disabled:opacity-100", "data-multi-select": "action", disabled: disabled, onClick: selectsAll ? onSelectAll : onSelectOnly, size: "xs", variant: "ghost", children: [_jsx("span", { className: "min-w-0 truncate text-left", id: nameId, children: name }), _jsx("span", { className: "min-w-16 rounded-xs-plus px-1 py-0.5 text-right text-xs font-normal text-muted-foreground opacity-0 group-focus-within/multi-select-row:opacity-100 group-hover/multi-select-row:opacity-100 [@media(hover:none)]:opacity-100", id: actionId, children: selectsAll ? selectAllLabel : selectOnlyLabel })] })) : (_jsx(Label, { className: "flex-1 truncate px-1 text-sm leading-5", htmlFor: id, id: nameId, children: name }))] }));
|
|
131
|
+
}
|
|
132
|
+
export { MultiSelect, MultiSelectContent, MultiSelectRow, MultiSelectTrigger };
|
|
@@ -1,24 +1,48 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
type
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { type FieldName } from "../internal/field-frame.js";
|
|
3
|
+
import { type FieldSize } from "../internal/input-box.js";
|
|
4
|
+
type NativeSelectProps = Omit<React.ComponentProps<"select">, "prefix" | "size"> & {
|
|
5
|
+
size?: FieldSize;
|
|
6
|
+
/** A mark before the value, such as an icon. */
|
|
7
|
+
prefix?: React.ReactNode;
|
|
8
|
+
/** A mark at the end, in place of the chevron. */
|
|
9
|
+
suffix?: React.ReactNode;
|
|
10
|
+
/** One muted sentence under the box that says what to enter, read with the box. */
|
|
11
|
+
description?: string;
|
|
12
|
+
/** The message under the box, in the product's words; it also marks the box invalid. */
|
|
13
|
+
error?: string;
|
|
14
|
+
} & FieldName;
|
|
5
15
|
/**
|
|
6
16
|
* The platform's own select, drawn as our input box.
|
|
7
17
|
*
|
|
8
18
|
* @family Inputs
|
|
9
19
|
* @when A long fixed list inside a native form, where the platform's own picker serves best: a time
|
|
10
20
|
* zone, a country.
|
|
11
|
-
* @instead Two or three options are radios or a segmented control.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
21
|
+
* @instead Two or three options are radios or a segmented control. "Pick `<Select>` for short,
|
|
22
|
+
* fixed lists (under ~10 items) where typing adds nothing; switch to `Combobox` once filtering
|
|
23
|
+
* helps." (https://vercel.com/geist/select) Ours: `Select` draws the short list in our style.
|
|
24
|
+
* @behaviour Same box, sizes, ring, hover, focus halo and disabled as `Input`, filling its
|
|
25
|
+
* container, the chevron in the muted grey with room reserved for it, after an optional `prefix`
|
|
26
|
+
* mark (a `suffix` mark takes the chevron's place). Colour sits in one place: an error turns the
|
|
27
|
+
* ring red and fills the halo, and colours the message; the fill, the value and the label stay
|
|
28
|
+
* neutral. `label` and `error` draw the `Field` parts around the box, and a string `label` requires
|
|
29
|
+
* `id`; a box with no name does not compile. It opens the system's list, with native keyboard and
|
|
30
|
+
* typing. As an uncontrolled field it keeps a saved value instead of snapping back to the page's
|
|
31
|
+
* first default. "Validate on blur and pass a string to `error`; messages name the field and end in
|
|
32
|
+
* a period (`Select a framework.`)." (https://vercel.com/geist/select) Other form rules are
|
|
33
|
+
* `Field`'s.
|
|
34
|
+
* @words "Label is a short Title Case noun (`Framework`, `Region`); accept the prop directly on
|
|
35
|
+
* `<Select>`." (https://vercel.com/geist/select) "Options are Title Case when short and match
|
|
36
|
+
* canonical branding (`Next.js`, not `NextJS`); keep the same register across the list."
|
|
37
|
+
* (https://vercel.com/geist/select) Ours: the label names the thing chosen (*Time zone*) and
|
|
38
|
+
* options are sentence case. A placeholder option is distinct from a real one and never preselected
|
|
39
|
+
* as if chosen.
|
|
40
|
+
* @access A real `select` with a visible label tied by `id`, or `aria-label`. "Group options past
|
|
41
|
+
* ~10 items with native `<optgroup>`; Geist `<Select>` has no `.Group` static."
|
|
42
|
+
* (https://vercel.com/geist/select) Ours: option groups are `optgroup`. The chevron, the prefix and
|
|
43
|
+
* the suffix are decorative.
|
|
20
44
|
*/
|
|
21
|
-
declare function NativeSelect({ className, size, ref, ...props }: NativeSelectProps): React.JSX.Element;
|
|
45
|
+
declare function NativeSelect({ className, size, prefix, suffix, label, description, error, ref, ...props }: NativeSelectProps): React.JSX.Element;
|
|
22
46
|
declare function NativeSelectOption({ className, ...props }: React.ComponentProps<"option">): React.JSX.Element;
|
|
23
47
|
declare function NativeSelectOptGroup({ className, ...props }: React.ComponentProps<"optgroup">): React.JSX.Element;
|
|
24
48
|
export { NativeSelect, NativeSelectOptGroup, NativeSelectOption };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-select.d.ts","sourceRoot":"","sources":["../../src/components/native-select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"native-select.d.ts","sourceRoot":"","sources":["../../src/components/native-select.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAyC,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAG7F,KAAK,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC,GAAG;IACjF,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,gDAAgD;IAChD,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,kDAAkD;IAClD,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,mFAAmF;IACnF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wFAAwF;IACxF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,SAAS,CAAC;AAEd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,iBAAS,YAAY,CAAC,EACpB,SAAS,EACT,IAAgB,EAChB,MAAM,EACN,MAAM,EACN,KAAK,EACL,WAAW,EACX,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,iBAAiB,qBA6FnB;AAED,iBAAS,kBAAkB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,QAAQ,CAAC,qBAQlF;AAED,iBAAS,oBAAoB,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,qBAQtF;AAED,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,CAAC"}
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { cn } from "../lib/utils.js";
|
|
5
|
+
import { FieldFrame } from "../internal/field-frame.js";
|
|
6
|
+
import { fieldDisabled, fieldRing, fieldStates } from "../internal/input-box.js";
|
|
5
7
|
import { ChevronDownIcon } from "lucide-react";
|
|
6
8
|
/**
|
|
7
9
|
* The platform's own select, drawn as our input box.
|
|
@@ -9,17 +11,31 @@ import { ChevronDownIcon } from "lucide-react";
|
|
|
9
11
|
* @family Inputs
|
|
10
12
|
* @when A long fixed list inside a native form, where the platform's own picker serves best: a time
|
|
11
13
|
* zone, a country.
|
|
12
|
-
* @instead Two or three options are radios or a segmented control.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
14
|
+
* @instead Two or three options are radios or a segmented control. "Pick `<Select>` for short,
|
|
15
|
+
* fixed lists (under ~10 items) where typing adds nothing; switch to `Combobox` once filtering
|
|
16
|
+
* helps." (https://vercel.com/geist/select) Ours: `Select` draws the short list in our style.
|
|
17
|
+
* @behaviour Same box, sizes, ring, hover, focus halo and disabled as `Input`, filling its
|
|
18
|
+
* container, the chevron in the muted grey with room reserved for it, after an optional `prefix`
|
|
19
|
+
* mark (a `suffix` mark takes the chevron's place). Colour sits in one place: an error turns the
|
|
20
|
+
* ring red and fills the halo, and colours the message; the fill, the value and the label stay
|
|
21
|
+
* neutral. `label` and `error` draw the `Field` parts around the box, and a string `label` requires
|
|
22
|
+
* `id`; a box with no name does not compile. It opens the system's list, with native keyboard and
|
|
23
|
+
* typing. As an uncontrolled field it keeps a saved value instead of snapping back to the page's
|
|
24
|
+
* first default. "Validate on blur and pass a string to `error`; messages name the field and end in
|
|
25
|
+
* a period (`Select a framework.`)." (https://vercel.com/geist/select) Other form rules are
|
|
26
|
+
* `Field`'s.
|
|
27
|
+
* @words "Label is a short Title Case noun (`Framework`, `Region`); accept the prop directly on
|
|
28
|
+
* `<Select>`." (https://vercel.com/geist/select) "Options are Title Case when short and match
|
|
29
|
+
* canonical branding (`Next.js`, not `NextJS`); keep the same register across the list."
|
|
30
|
+
* (https://vercel.com/geist/select) Ours: the label names the thing chosen (*Time zone*) and
|
|
31
|
+
* options are sentence case. A placeholder option is distinct from a real one and never preselected
|
|
32
|
+
* as if chosen.
|
|
33
|
+
* @access A real `select` with a visible label tied by `id`, or `aria-label`. "Group options past
|
|
34
|
+
* ~10 items with native `<optgroup>`; Geist `<Select>` has no `.Group` static."
|
|
35
|
+
* (https://vercel.com/geist/select) Ours: option groups are `optgroup`. The chevron, the prefix and
|
|
36
|
+
* the suffix are decorative.
|
|
21
37
|
*/
|
|
22
|
-
function NativeSelect({ className, size = "default", ref, ...props }) {
|
|
38
|
+
function NativeSelect({ className, size = "default", prefix, suffix, label, description, error, ref, ...props }) {
|
|
23
39
|
const select = React.useRef(null);
|
|
24
40
|
const setRef = React.useCallback((node) => {
|
|
25
41
|
select.current = node;
|
|
@@ -63,7 +79,7 @@ function NativeSelect({ className, size = "default", ref, ...props }) {
|
|
|
63
79
|
option.selected = shown.includes(option.value);
|
|
64
80
|
appliedDefault.current = defaultKey;
|
|
65
81
|
}, [defaultKey]);
|
|
66
|
-
return (_jsxs("div", { className: cn("group/native-select relative w-
|
|
82
|
+
return (_jsx(FieldFrame, { label: label, description: description, error: error, size: size, control: props, children: (aria) => (_jsxs("div", { className: cn("group/native-select relative w-full", className), "data-slot": "native-select-wrapper", "data-size": size, children: [prefix ? (_jsx("span", { "data-slot": "native-select-prefix", "aria-hidden": "true", className: "pointer-events-none absolute top-1/2 left-control-padding-inline flex -translate-y-1/2 items-center text-muted-foreground [&_svg:not([class*='size-'])]:size-4", children: prefix })) : null, _jsx("select", { ref: setRef, "data-slot": "native-select", "data-size": size, "data-field-frame": "", className: cn("h-control-height min-h-touch-target w-full min-w-0 cursor-pointer appearance-none rounded-sm bg-(--nc-field,var(--background)) py-0 pr-9 pl-control-padding-inline text-sm select-none selection:bg-primary selection:text-primary-foreground data-[size=lg]:h-nadicode-control-height-lg data-[size=lg]:rounded-md data-[size=lg]:text-base data-[size=sm]:h-nadicode-control-height-sm [@media(hover:hover)_and_(pointer:fine)]:min-h-0", fieldRing, fieldStates, fieldDisabled, prefix ? "pl-10" : undefined), ...props, ...aria }), suffix ? (_jsx("span", { "data-slot": "native-select-suffix", "aria-hidden": "true", className: "pointer-events-none absolute top-1/2 right-3 flex -translate-y-1/2 items-center text-muted-foreground select-none [&_svg:not([class*='size-'])]:size-4", children: suffix })) : (_jsx(ChevronDownIcon, { className: "pointer-events-none absolute top-1/2 right-3 size-3.5 -translate-y-1/2 text-muted-foreground select-none", "aria-hidden": "true", "data-slot": "native-select-icon" }))] })) }));
|
|
67
83
|
}
|
|
68
84
|
function NativeSelectOption({ className, ...props }) {
|
|
69
85
|
return (_jsx("option", { "data-slot": "native-select-option", className: cn("bg-[Canvas] text-[CanvasText]", className), ...props }));
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
import type { ComponentProps,
|
|
2
|
-
|
|
1
|
+
import type { ComponentProps, ReactNode } from "react";
|
|
2
|
+
import type { LucideIcon } from "lucide-react";
|
|
3
|
+
import { type NoticeTone } from "../internal/notice.js";
|
|
4
|
+
import type { PageCommand } from "./page-actions.js";
|
|
5
|
+
export type NoticeBannerTone = NoticeTone;
|
|
3
6
|
export type NoticeBannerLiveRegion = "off" | "polite";
|
|
4
7
|
export type NoticeBannerProps = {
|
|
5
|
-
/** The fix the page offers, as
|
|
6
|
-
action:
|
|
8
|
+
/** The one fix the page offers, drawn as an underlined link. Required: a condition is shown with its fix. */
|
|
9
|
+
action: PageCommand;
|
|
7
10
|
className?: string;
|
|
8
11
|
description?: ReactNode;
|
|
9
12
|
detail?: ReactNode;
|
|
13
|
+
/** Replaces the tone's mark with another lucide icon. */
|
|
14
|
+
icon?: LucideIcon;
|
|
15
|
+
/** One or two words naming the topic, leading the title: "Billing", "Slack". */
|
|
16
|
+
label?: string;
|
|
10
17
|
liveRegion: NoticeBannerLiveRegion;
|
|
11
18
|
title: ReactNode;
|
|
12
19
|
tone: NoticeBannerTone;
|
|
@@ -15,11 +22,11 @@ export type NoticeBannerProps = {
|
|
|
15
22
|
* A condition of the whole page, the account or the service, with its fix.
|
|
16
23
|
*
|
|
17
24
|
* @family Feedback
|
|
18
|
-
* @when A condition of the whole page, the account or the service that the page itself can resolve, with that resolving action on the banner.
|
|
19
|
-
* @instead
|
|
20
|
-
* @behaviour
|
|
21
|
-
* @words Title names the condition, description what
|
|
22
|
-
* @access `liveRegion="polite"` gives `role="status"`, announced once when it appears; `"off"` gives `role="note"` for one already there at load. The mark is hidden.
|
|
25
|
+
* @when "A prominent message that spans the full width of its container to announce important information." (https://vercel.com/geist/banner) "Used for temporary, project-wide notifications that require resolution" (https://vercel.com/geist/project-banner) "Use Project Banner for project-wide states that need resolution: overdue billing, an active rollback, attack mitigation, an expiring trial blocking deploys." (https://vercel.com/geist/project-banner) "Match `variant` to severity: `error` for critical downtime or payment-blocking states, `warning` for an exceptional state with non-immediate action, `success` for a positive temporary mitigation, `gray` for routine project-wide notices." (https://vercel.com/geist/project-banner) Ours: a condition of the whole page, the account or the service that the page itself can resolve, with that resolving action on the banner. The `tone` is the `variant`: `destructive` is `error`, `warning` is `warning`, `info` is `success` and `neutral` is `gray`. One sits above the page's content, under its title.
|
|
26
|
+
* @instead "Pick `Note` for inline contextual messages tied to a single field or card, `Toast` for transient acknowledgments, `Modal` for confirmations." (https://vercel.com/geist/project-banner) Ours: `Note` is `MessageNotice` (`placement="section"`), `Toast` is `showMessageToast` and `Modal` is `ConfirmDialog`. For a measured level use a `KpiCard` with its tone; crossing a threshold is a notification in the inbox, not a banner.
|
|
27
|
+
* @behaviour "Project Banner is non-dismissible by design. If the message can be dismissed without resolving the underlying state, it isn’t banner-worthy; move it to a `Note`." (https://vercel.com/geist/project-banner) "Show one Project Banner at a time. Stacking competing banners drowns the most urgent state." (https://vercel.com/geist/project-banner) "Always pass a `callToAction` that resolves the state. A banner with no route is a dead end." (https://vercel.com/geist/project-banner) Ours: a strip as wide as its container: a filled ground with a line on its top and bottom edge only, no corners, 40 px high and centred, with the mark, the sentence and the fix on one row; under 768 px the fix drops under the sentence, aligned with its text. Colour sits on the whole strip (ground, both lines, mark and text); the fix is an underlined link in the darkest step of the same hue (neutral: `text-foreground`) and returns to the strip's text on hover. Neutral and info take the Info mark, warning and destructive the TriangleAlert. `action` is the `callToAction`: one command, never two, never a ready-made button, and there is no close button. Required: `action`, `title`, `tone` and `liveRegion`; the mark is always drawn.
|
|
28
|
+
* @words "`label` is one sentence in sentence case that names the impact: `Your Pro trial expires in 3 days.` Don’t open with `Heads up` or apologetic preambles." (https://vercel.com/geist/project-banner) "`callToAction.label` is Title Case `Verb + Noun` and points at the resolver: `Update Payment Method`, `Reactivate Project`, `Review Tokens`." (https://vercel.com/geist/project-banner) "Name the affected entity when the project context isn’t obvious from the surrounding chrome (`Production deployments are paused on my-project`)." (https://vercel.com/geist/project-banner) "Don’t encode severity in the copy with emoji or interjections; the variant carries that signal." (https://vercel.com/geist/project-banner) "`NoteLabel` is a 1–2 word Title Case prefix that names the topic: `Region Change`, `Rate Limit`, `Plan Limit`. Cut hedges like `Heads Up`, `FYI`, and `Note`." (https://vercel.com/geist/note) Ours: the `title` is the `label`: the one sentence, naming the condition, its impact and the object. A `description` only adds what the title leaves out, in one more sentence. Our `label` is the `NoteLabel` topic prefix. The action is sentence case, verb and noun, pointing at the resolver: "Open Slack settings", "Update card". No "Please". The words come from the product's catalogue code.
|
|
29
|
+
* @access `liveRegion="polite"` gives `role="status"`, announced once when it appears; `"off"` gives `role="note"` for one already there at load. The mark, given or not, is hidden.
|
|
23
30
|
*/
|
|
24
|
-
export declare function NoticeBanner({ action, className, description, detail, liveRegion, title, tone, ...props }: NoticeBannerProps): import("react").JSX.Element;
|
|
31
|
+
export declare function NoticeBanner({ action, className, description, detail, icon, label, liveRegion, title, tone, ...props }: NoticeBannerProps): import("react").JSX.Element;
|
|
25
32
|
//# sourceMappingURL=notice-banner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"notice-banner.d.ts","sourceRoot":"","sources":["../../src/components/notice-banner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,
|
|
1
|
+
{"version":3,"file":"notice-banner.d.ts","sourceRoot":"","sources":["../../src/components/notice-banner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/C,OAAO,EAAuC,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEzF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,MAAM,gBAAgB,GAAG,UAAU,CAAC;AAC1C,MAAM,MAAM,sBAAsB,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEtD,MAAM,MAAM,iBAAiB,GAAG;IAC9B,6GAA6G;IAC7G,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,SAAS,CAAC;IACxB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,yDAAyD;IACzD,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,sBAAsB,CAAC;IACnC,KAAK,EAAE,SAAS,CAAC;IACjB,IAAI,EAAE,gBAAgB,CAAC;CACxB,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC;AAGtD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,EAC3B,MAAM,EACN,SAAS,EACT,WAAW,EACX,MAAM,EACN,IAAI,EACJ,KAAK,EACL,UAAU,EACV,KAAK,EACL,IAAI,EACJ,GAAG,KAAK,EACT,EAAE,iBAAiB,+BA4CnB"}
|