@nadicodeai/ui 12.1.102 → 12.1.104
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/accordion.d.ts +38 -12
- package/dist/components/accordion.d.ts.map +1 -1
- package/dist/components/accordion.js +36 -15
- package/dist/components/account-menu.js +2 -2
- package/dist/components/action-menu.d.ts +20 -19
- package/dist/components/action-menu.d.ts.map +1 -1
- package/dist/components/action-menu.js +22 -15
- package/dist/components/action-status.d.ts +14 -10
- package/dist/components/action-status.d.ts.map +1 -1
- package/dist/components/action-status.js +14 -10
- package/dist/components/activity-calendar.d.ts +3 -1
- package/dist/components/activity-calendar.d.ts.map +1 -1
- package/dist/components/activity-calendar.js +16 -2
- package/dist/components/activity-feed.d.ts +2 -2
- package/dist/components/activity-feed.d.ts.map +1 -1
- package/dist/components/activity-feed.js +14 -5
- package/dist/components/agent-card.d.ts +11 -5
- package/dist/components/agent-card.d.ts.map +1 -1
- package/dist/components/agent-card.js +13 -7
- package/dist/components/agent-list-row.js +1 -1
- package/dist/components/agent-orb-appearance.d.ts +7 -1
- package/dist/components/agent-orb-appearance.d.ts.map +1 -1
- package/dist/components/agent-orb-appearance.js +26 -0
- package/dist/components/agent-profile.d.ts +8 -7
- package/dist/components/agent-profile.d.ts.map +1 -1
- package/dist/components/agent-profile.js +6 -6
- package/dist/components/alert-dialog.d.ts +25 -16
- package/dist/components/alert-dialog.d.ts.map +1 -1
- package/dist/components/alert-dialog.js +30 -18
- package/dist/components/alert.d.ts +1 -1
- package/dist/components/avatar.d.ts +83 -17
- package/dist/components/avatar.d.ts.map +1 -1
- package/dist/components/avatar.js +89 -23
- package/dist/components/badge.d.ts +59 -8
- package/dist/components/badge.d.ts.map +1 -1
- package/dist/components/badge.js +57 -14
- package/dist/components/breadcrumb.d.ts +18 -7
- package/dist/components/breadcrumb.d.ts.map +1 -1
- package/dist/components/breadcrumb.js +37 -13
- package/dist/components/button-group.d.ts +12 -15
- package/dist/components/button-group.d.ts.map +1 -1
- package/dist/components/button-group.js +13 -17
- package/dist/components/button.d.ts +126 -23
- package/dist/components/button.d.ts.map +1 -1
- package/dist/components/button.js +164 -39
- package/dist/components/calendar.d.ts +26 -15
- package/dist/components/calendar.d.ts.map +1 -1
- package/dist/components/calendar.js +60 -46
- package/dist/components/card-row.d.ts +13 -5
- package/dist/components/card-row.d.ts.map +1 -1
- package/dist/components/card-row.js +24 -10
- package/dist/components/card.d.ts +6 -12
- package/dist/components/card.d.ts.map +1 -1
- package/dist/components/card.js +11 -16
- package/dist/components/carousel.d.ts +3 -3
- package/dist/components/carousel.d.ts.map +1 -1
- package/dist/components/carousel.js +7 -7
- package/dist/components/catalog-drawer.d.ts +7 -7
- package/dist/components/catalog-drawer.d.ts.map +1 -1
- package/dist/components/catalog-drawer.js +6 -6
- package/dist/components/chart-area-stacked.d.ts +1 -1
- package/dist/components/chart-area-stacked.d.ts.map +1 -1
- package/dist/components/chart-area-stacked.js +4 -4
- package/dist/components/chart-axis.d.ts +14 -1
- package/dist/components/chart-axis.d.ts.map +1 -1
- package/dist/components/chart-axis.js +11 -1
- package/dist/components/chart-bar-horizontal.d.ts +2 -2
- package/dist/components/chart-bar-horizontal.d.ts.map +1 -1
- package/dist/components/chart-bar-horizontal.js +14 -5
- package/dist/components/chart-bar-multiple.d.ts +1 -1
- package/dist/components/chart-bar-multiple.d.ts.map +1 -1
- package/dist/components/chart-bar-multiple.js +3 -3
- package/dist/components/chart-bar-stacked.d.ts +1 -1
- package/dist/components/chart-bar-stacked.d.ts.map +1 -1
- package/dist/components/chart-bar-stacked.js +3 -3
- package/dist/components/chart-card.d.ts +17 -6
- package/dist/components/chart-card.d.ts.map +1 -1
- package/dist/components/chart-card.js +11 -4
- package/dist/components/chart-date-range-control.d.ts +18 -9
- package/dist/components/chart-date-range-control.d.ts.map +1 -1
- package/dist/components/chart-date-range-control.js +43 -47
- package/dist/components/chart-sparkline.d.ts +4 -3
- package/dist/components/chart-sparkline.d.ts.map +1 -1
- package/dist/components/chart-sparkline.js +6 -5
- package/dist/components/check-counts.d.ts +44 -0
- package/dist/components/check-counts.d.ts.map +1 -0
- package/dist/components/check-counts.js +51 -0
- package/dist/components/checkbox.d.ts +39 -11
- package/dist/components/checkbox.d.ts.map +1 -1
- package/dist/components/checkbox.js +38 -11
- package/dist/components/choicebox.d.ts +96 -0
- package/dist/components/choicebox.d.ts.map +1 -0
- package/dist/components/choicebox.js +113 -0
- package/dist/components/clearable-input.d.ts +57 -0
- package/dist/components/clearable-input.d.ts.map +1 -0
- package/dist/components/clearable-input.js +58 -0
- package/dist/components/code-block.d.ts +77 -17
- package/dist/components/code-block.d.ts.map +1 -1
- package/dist/components/code-block.js +85 -15
- package/dist/components/collapsible.d.ts +27 -10
- package/dist/components/collapsible.d.ts.map +1 -1
- package/dist/components/collapsible.js +24 -9
- package/dist/components/collection-filters.d.ts +3 -1
- package/dist/components/collection-filters.d.ts.map +1 -1
- package/dist/components/collection-filters.js +7 -9
- package/dist/components/collection-page.d.ts +31 -10
- package/dist/components/collection-page.d.ts.map +1 -1
- package/dist/components/collection-page.js +14 -13
- package/dist/components/collection-search.d.ts +32 -10
- package/dist/components/collection-search.d.ts.map +1 -1
- package/dist/components/collection-search.js +24 -13
- package/dist/components/collection-sort.d.ts.map +1 -1
- package/dist/components/collection-sort.js +2 -2
- package/dist/components/collection-toolbar.d.ts +5 -2
- package/dist/components/collection-toolbar.d.ts.map +1 -1
- package/dist/components/collection-toolbar.js +7 -4
- package/dist/components/combobox.d.ts +97 -22
- package/dist/components/combobox.d.ts.map +1 -1
- package/dist/components/combobox.js +80 -28
- package/dist/components/command.d.ts +34 -21
- package/dist/components/command.d.ts.map +1 -1
- package/dist/components/command.js +33 -25
- package/dist/components/confirm-dialog.d.ts +23 -6
- package/dist/components/confirm-dialog.d.ts.map +1 -1
- package/dist/components/confirm-dialog.js +32 -13
- package/dist/components/context-menu.d.ts +14 -10
- package/dist/components/context-menu.d.ts.map +1 -1
- package/dist/components/context-menu.js +17 -12
- package/dist/components/copy-button.d.ts +5 -2
- package/dist/components/copy-button.d.ts.map +1 -1
- package/dist/components/copy-button.js +16 -8
- package/dist/components/data-table.d.ts +120 -54
- package/dist/components/data-table.d.ts.map +1 -1
- package/dist/components/data-table.js +163 -92
- package/dist/components/desktop-shell.d.ts +4 -2
- package/dist/components/desktop-shell.d.ts.map +1 -1
- package/dist/components/desktop-shell.js +3 -3
- package/dist/components/dialog.d.ts +63 -24
- package/dist/components/dialog.d.ts.map +1 -1
- package/dist/components/dialog.js +52 -31
- package/dist/components/disclosure-row.d.ts +1 -2
- package/dist/components/disclosure-row.d.ts.map +1 -1
- package/dist/components/disclosure-row.js +1 -2
- package/dist/components/disclosure.d.ts +1 -1
- package/dist/components/disclosure.js +1 -1
- package/dist/components/drawer.d.ts +33 -12
- package/dist/components/drawer.d.ts.map +1 -1
- package/dist/components/drawer.js +47 -35
- package/dist/components/dropdown-menu.d.ts +59 -14
- package/dist/components/dropdown-menu.d.ts.map +1 -1
- package/dist/components/dropdown-menu.js +58 -26
- package/dist/components/empty-state.d.ts +35 -12
- package/dist/components/empty-state.d.ts.map +1 -1
- package/dist/components/empty-state.js +35 -17
- package/dist/components/entry-scene.d.ts +4 -4
- package/dist/components/entry-scene.d.ts.map +1 -1
- package/dist/components/entry-scene.js +2 -2
- package/dist/components/field.d.ts +44 -14
- package/dist/components/field.d.ts.map +1 -1
- package/dist/components/field.js +49 -20
- package/dist/components/file-diff.d.ts.map +1 -1
- package/dist/components/file-diff.js +3 -4
- package/dist/components/form-dialog.d.ts +7 -7
- package/dist/components/form-dialog.d.ts.map +1 -1
- package/dist/components/form-dialog.js +13 -11
- package/dist/components/form-drawer.d.ts +10 -7
- package/dist/components/form-drawer.d.ts.map +1 -1
- package/dist/components/form-drawer.js +11 -10
- package/dist/components/gauge.d.ts +64 -0
- package/dist/components/gauge.d.ts.map +1 -0
- package/dist/components/gauge.js +73 -0
- package/dist/components/hover-card.d.ts +72 -14
- package/dist/components/hover-card.d.ts.map +1 -1
- package/dist/components/hover-card.js +51 -17
- package/dist/components/identity-mark.d.ts +8 -1
- package/dist/components/identity-mark.d.ts.map +1 -1
- package/dist/components/identity-mark.js +31 -5
- package/dist/components/input-group.d.ts +44 -21
- package/dist/components/input-group.d.ts.map +1 -1
- package/dist/components/input-group.js +74 -27
- package/dist/components/input.d.ts +64 -12
- package/dist/components/input.d.ts.map +1 -1
- package/dist/components/input.js +51 -15
- package/dist/components/item.d.ts +37 -15
- package/dist/components/item.d.ts.map +1 -1
- package/dist/components/item.js +41 -22
- package/dist/components/kbd.d.ts +49 -13
- package/dist/components/kbd.d.ts.map +1 -1
- package/dist/components/kbd.js +115 -16
- package/dist/components/kpi-card.d.ts +12 -4
- package/dist/components/kpi-card.d.ts.map +1 -1
- package/dist/components/kpi-card.js +13 -4
- package/dist/components/label.d.ts +17 -10
- package/dist/components/label.d.ts.map +1 -1
- package/dist/components/label.js +18 -11
- package/dist/components/library-shelf.d.ts +6 -6
- package/dist/components/library-shelf.d.ts.map +1 -1
- package/dist/components/library-shelf.js +5 -5
- package/dist/components/load-more-button.d.ts +35 -0
- package/dist/components/load-more-button.d.ts.map +1 -0
- package/dist/components/load-more-button.js +26 -0
- package/dist/components/message-notice.d.ts +8 -13
- package/dist/components/message-notice.d.ts.map +1 -1
- package/dist/components/message-notice.js +25 -22
- package/dist/components/middle-truncate.d.ts +33 -0
- package/dist/components/middle-truncate.d.ts.map +1 -0
- package/dist/components/middle-truncate.js +72 -0
- package/dist/components/multi-select.d.ts +94 -0
- package/dist/components/multi-select.d.ts.map +1 -0
- package/dist/components/multi-select.js +132 -0
- package/dist/components/native-select.d.ts +37 -13
- package/dist/components/native-select.d.ts.map +1 -1
- package/dist/components/native-select.js +27 -11
- package/dist/components/notice-banner.d.ts +17 -10
- package/dist/components/notice-banner.d.ts.map +1 -1
- package/dist/components/notice-banner.js +12 -11
- package/dist/components/numbered-steps.d.ts +10 -4
- package/dist/components/numbered-steps.d.ts.map +1 -1
- package/dist/components/numbered-steps.js +9 -7
- package/dist/components/object-page.d.ts +40 -14
- package/dist/components/object-page.d.ts.map +1 -1
- package/dist/components/object-page.js +12 -10
- package/dist/components/object-workspace.d.ts +29 -10
- package/dist/components/object-workspace.d.ts.map +1 -1
- package/dist/components/object-workspace.js +18 -8
- package/dist/components/overview-page.d.ts +2 -2
- package/dist/components/overview-page.d.ts.map +1 -1
- package/dist/components/overview-page.js +8 -7
- package/dist/components/page-actions.d.ts +28 -8
- package/dist/components/page-actions.d.ts.map +1 -1
- package/dist/components/page-actions.js +22 -25
- package/dist/components/page-header.d.ts +11 -4
- package/dist/components/page-header.d.ts.map +1 -1
- package/dist/components/page-header.js +10 -5
- package/dist/components/pending-label.d.ts +6 -5
- package/dist/components/pending-label.d.ts.map +1 -1
- package/dist/components/pending-label.js +14 -6
- package/dist/components/picture-label.d.ts +2 -2
- package/dist/components/picture-label.d.ts.map +1 -1
- package/dist/components/picture-label.js +3 -3
- package/dist/components/portal-sidebar-frame.d.ts +9 -21
- package/dist/components/portal-sidebar-frame.d.ts.map +1 -1
- package/dist/components/portal-sidebar-frame.js +13 -27
- package/dist/components/progress-checklist.d.ts +46 -0
- package/dist/components/progress-checklist.d.ts.map +1 -0
- package/dist/components/progress-checklist.js +46 -0
- package/dist/components/progress.d.ts +48 -8
- package/dist/components/progress.d.ts.map +1 -1
- package/dist/components/progress.js +92 -16
- package/dist/components/prose.d.ts +19 -0
- package/dist/components/prose.d.ts.map +1 -0
- package/dist/components/prose.js +29 -0
- package/dist/components/radio-group.d.ts +51 -12
- package/dist/components/radio-group.d.ts.map +1 -1
- package/dist/components/radio-group.js +42 -12
- package/dist/components/reading-column.js +1 -1
- package/dist/components/record-identity.d.ts +6 -5
- package/dist/components/record-identity.d.ts.map +1 -1
- package/dist/components/record-identity.js +12 -3
- package/dist/components/record-list.d.ts +117 -27
- package/dist/components/record-list.d.ts.map +1 -1
- package/dist/components/record-list.js +185 -55
- package/dist/components/record-time.d.ts +20 -7
- package/dist/components/record-time.d.ts.map +1 -1
- package/dist/components/record-time.js +38 -19
- package/dist/components/resizable.d.ts +7 -5
- package/dist/components/resizable.d.ts.map +1 -1
- package/dist/components/resizable.js +6 -6
- package/dist/components/scope-switcher.d.ts +2 -0
- package/dist/components/scope-switcher.d.ts.map +1 -1
- package/dist/components/scope-switcher.js +2 -2
- package/dist/components/scroll-area.d.ts +47 -11
- package/dist/components/scroll-area.d.ts.map +1 -1
- package/dist/components/scroll-area.js +72 -14
- package/dist/components/segmented-control.d.ts +82 -0
- package/dist/components/segmented-control.d.ts.map +1 -0
- package/dist/components/segmented-control.js +90 -0
- package/dist/components/select.d.ts +55 -15
- package/dist/components/select.d.ts.map +1 -1
- package/dist/components/select.js +62 -19
- package/dist/components/separator.d.ts +12 -5
- package/dist/components/separator.d.ts.map +1 -1
- package/dist/components/separator.js +11 -6
- package/dist/components/settings-facts.d.ts +34 -14
- package/dist/components/settings-facts.d.ts.map +1 -1
- package/dist/components/settings-facts.js +21 -12
- package/dist/components/settings-page.d.ts +4 -4
- package/dist/components/settings-page.js +5 -5
- package/dist/components/settings-section.d.ts +160 -34
- package/dist/components/settings-section.d.ts.map +1 -1
- package/dist/components/settings-section.js +92 -39
- package/dist/components/sheet.d.ts +47 -16
- package/dist/components/sheet.d.ts.map +1 -1
- package/dist/components/sheet.js +40 -19
- package/dist/components/sidebar-sections.d.ts +16 -12
- package/dist/components/sidebar-sections.d.ts.map +1 -1
- package/dist/components/sidebar-sections.js +30 -15
- package/dist/components/sidebar.d.ts +117 -21
- package/dist/components/sidebar.d.ts.map +1 -1
- package/dist/components/sidebar.js +180 -55
- package/dist/components/skeleton.d.ts +54 -8
- package/dist/components/skeleton.d.ts.map +1 -1
- package/dist/components/skeleton.js +44 -9
- package/dist/components/slider.d.ts +53 -11
- package/dist/components/slider.d.ts.map +1 -1
- package/dist/components/slider.js +71 -17
- package/dist/components/snippet.d.ts +57 -0
- package/dist/components/snippet.d.ts.map +1 -0
- package/dist/components/snippet.js +60 -0
- package/dist/components/sonner.d.ts +13 -14
- package/dist/components/sonner.d.ts.map +1 -1
- package/dist/components/sonner.js +25 -22
- package/dist/components/status-badge.d.ts +37 -11
- package/dist/components/status-badge.d.ts.map +1 -1
- package/dist/components/status-badge.js +63 -15
- package/dist/components/status-dot.d.ts +42 -11
- package/dist/components/status-dot.d.ts.map +1 -1
- package/dist/components/status-dot.js +40 -11
- package/dist/components/switch.d.ts +43 -12
- package/dist/components/switch.d.ts.map +1 -1
- package/dist/components/switch.js +42 -12
- package/dist/components/table-card.d.ts +21 -12
- package/dist/components/table-card.d.ts.map +1 -1
- package/dist/components/table-card.js +17 -9
- package/dist/components/table-layouts.d.ts +40 -8
- package/dist/components/table-layouts.d.ts.map +1 -1
- package/dist/components/table-layouts.js +52 -8
- package/dist/components/table-value.d.ts +4 -3
- package/dist/components/table-value.d.ts.map +1 -1
- package/dist/components/table-value.js +6 -5
- package/dist/components/table.d.ts +62 -25
- package/dist/components/table.d.ts.map +1 -1
- package/dist/components/table.js +62 -26
- package/dist/components/tabs.d.ts +86 -17
- package/dist/components/tabs.d.ts.map +1 -1
- package/dist/components/tabs.js +93 -22
- package/dist/components/text-link.d.ts +4 -1
- package/dist/components/text-link.d.ts.map +1 -1
- package/dist/components/text-link.js +4 -1
- package/dist/components/text-with-copy-button.d.ts +30 -0
- package/dist/components/text-with-copy-button.d.ts.map +1 -0
- package/dist/components/text-with-copy-button.js +32 -0
- package/dist/components/textarea.d.ts +40 -10
- package/dist/components/textarea.d.ts.map +1 -1
- package/dist/components/textarea.js +50 -11
- package/dist/components/theme-mode-switcher.d.ts +18 -1
- package/dist/components/theme-mode-switcher.d.ts.map +1 -1
- package/dist/components/theme-mode-switcher.js +20 -2
- package/dist/components/toggle-group.d.ts +28 -8
- package/dist/components/toggle-group.d.ts.map +1 -1
- package/dist/components/toggle-group.js +12 -6
- package/dist/components/toggle.d.ts +6 -3
- package/dist/components/toggle.d.ts.map +1 -1
- package/dist/components/toggle.js +10 -7
- package/dist/components/tooltip.d.ts +43 -12
- package/dist/components/tooltip.d.ts.map +1 -1
- package/dist/components/tooltip.js +45 -16
- package/dist/components/trend-badge.js +1 -1
- package/dist/components/update-card.js +1 -1
- package/dist/eslint/index.js +82 -0
- package/dist/eslint/rules/badge-is-static-label.js +93 -0
- package/dist/eslint/rules/button-icon-slot.js +102 -0
- package/dist/eslint/rules/button-link-for-navigation.js +146 -0
- package/dist/eslint/rules/button-no-aria-label-with-text.js +75 -0
- package/dist/eslint/rules/button-type-roles-only-in-buttons.js +83 -0
- package/dist/eslint/rules/choice-control-has-a-name.js +98 -0
- package/dist/eslint/rules/choice-group-in-fieldset.js +86 -0
- package/dist/eslint/rules/command-shortcut-single-owner.js +118 -0
- package/dist/eslint/rules/confirm-dialog-words.js +63 -0
- package/dist/eslint/rules/data-table-one-unsized-column.js +96 -0
- package/dist/eslint/rules/destructive-action-placement.js +69 -0
- package/dist/eslint/rules/disabled-choice-says-why.js +71 -0
- package/dist/eslint/rules/ellipsis-opens-a-dialog.js +110 -0
- package/dist/eslint/rules/input-group-owners.js +155 -0
- package/dist/eslint/rules/kbd-children-no-modifier-text.js +128 -0
- package/dist/eslint/rules/literal-text.js +41 -0
- package/dist/eslint/rules/middle-truncate-placement.js +69 -0
- package/dist/eslint/rules/no-bare-button-label.js +55 -0
- package/dist/eslint/rules/no-control-in-read-only-surface.js +106 -0
- package/dist/eslint/rules/no-hand-built-busy.js +104 -0
- package/dist/eslint/rules/no-hand-built-theme-picker.js +144 -0
- package/dist/eslint/rules/no-hand-built-tile.js +41 -0
- package/dist/eslint/rules/no-hand-formatted-date.js +87 -0
- package/dist/eslint/rules/no-hand-stacked-avatars.js +67 -0
- package/dist/eslint/rules/no-nested-collapse.js +60 -0
- package/dist/eslint/rules/no-search-in-form.js +47 -0
- package/dist/eslint/rules/no-shadcn-appearance-override.js +2 -16
- package/dist/eslint/rules/no-shell-prompt-in-snippet.js +74 -0
- package/dist/eslint/rules/no-stock-error-words.js +56 -0
- package/dist/eslint/rules/no-tooltip-around-labelled-field.js +72 -0
- package/dist/eslint/rules/no-weight-class-on-strong-in-type-role.js +57 -0
- package/dist/eslint/rules/one-submenu-level.js +43 -0
- package/dist/eslint/rules/one-toast-per-flow.js +91 -0
- package/dist/eslint/rules/option-count.js +167 -0
- package/dist/eslint/rules/page-command-link-not-render.js +43 -0
- package/dist/eslint/rules/progress-needs-name.js +57 -0
- package/dist/eslint/rules/settings-limit-in-footer.js +94 -0
- package/dist/eslint/rules/skeleton-in-region.js +80 -0
- package/dist/eslint/rules/sortable-heading-uses-sort.js +79 -0
- package/dist/eslint/rules/table-cell-inset-owner.js +107 -0
- package/dist/eslint/rules/tabs-selection-is-controlled.js +47 -0
- package/dist/eslint/rules/tooltip-only-arrow.js +38 -0
- package/dist/eslint/rules/tooltip-trigger-accessible-name.js +114 -0
- package/dist/eslint/strict-design-system.js +21 -7
- package/dist/index.d.ts +13 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -13
- package/dist/internal/assistant-ui/attachment.d.ts.map +1 -1
- package/dist/internal/assistant-ui/attachment.js +2 -2
- package/dist/internal/assistant-ui/reasoning.d.ts +1 -1
- package/dist/internal/assistant-ui/reasoning.d.ts.map +1 -1
- package/dist/internal/assistant-ui/tool-fallback.js +1 -1
- package/dist/internal/assistant-ui/tool-group.d.ts +1 -1
- package/dist/internal/assistant-ui/tool-group.d.ts.map +1 -1
- package/dist/internal/assistant-ui/tooltip-icon-button.d.ts +2 -3
- package/dist/internal/assistant-ui/tooltip-icon-button.d.ts.map +1 -1
- package/dist/internal/assistant-ui/tooltip-icon-button.js +1 -1
- package/dist/internal/catalog-list.js +2 -2
- package/dist/internal/collection-note.d.ts +23 -0
- package/dist/internal/collection-note.d.ts.map +1 -0
- package/dist/internal/collection-note.js +17 -0
- package/dist/internal/collection-rail.d.ts +57 -0
- package/dist/internal/collection-rail.d.ts.map +1 -0
- package/dist/internal/collection-rail.js +33 -0
- package/dist/internal/company-logo.d.ts +18 -0
- package/dist/internal/company-logo.d.ts.map +1 -0
- package/dist/internal/company-logo.js +14 -0
- package/dist/internal/control-name.d.ts +12 -0
- package/dist/internal/control-name.d.ts.map +1 -0
- package/dist/internal/control-name.js +1 -0
- package/dist/internal/diff-line.d.ts +9 -0
- package/dist/internal/diff-line.d.ts.map +1 -0
- package/dist/internal/diff-line.js +8 -0
- package/dist/internal/empty.d.ts +8 -4
- package/dist/internal/empty.d.ts.map +1 -1
- package/dist/internal/empty.js +14 -8
- package/dist/internal/field-frame.d.ts +33 -0
- package/dist/internal/field-frame.d.ts.map +1 -0
- package/dist/internal/field-frame.js +20 -0
- package/dist/internal/final-focus.d.ts +8 -0
- package/dist/internal/final-focus.d.ts.map +1 -0
- package/dist/internal/final-focus.js +10 -0
- package/dist/internal/footer-strip.d.ts.map +1 -1
- package/dist/internal/footer-strip.js +3 -1
- package/dist/internal/form-submit.d.ts +9 -5
- package/dist/internal/form-submit.d.ts.map +1 -1
- package/dist/internal/form-submit.js +31 -2
- package/dist/internal/input-box.d.ts +26 -0
- package/dist/internal/input-box.d.ts.map +1 -0
- package/dist/internal/input-box.js +59 -0
- package/dist/internal/menu-surface.d.ts +10 -3
- package/dist/internal/menu-surface.d.ts.map +1 -1
- package/dist/internal/menu-surface.js +10 -3
- package/dist/internal/notice.d.ts +25 -0
- package/dist/internal/notice.d.ts.map +1 -0
- package/dist/internal/notice.js +33 -0
- package/dist/internal/overlay-stem.d.ts +5 -0
- package/dist/internal/overlay-stem.d.ts.map +1 -0
- package/dist/internal/overlay-stem.js +7 -0
- package/dist/internal/phone-sheet.d.ts +4 -0
- package/dist/internal/phone-sheet.d.ts.map +1 -0
- package/dist/internal/phone-sheet.js +2 -0
- package/dist/internal/present-content.d.ts +3 -0
- package/dist/internal/present-content.d.ts.map +1 -0
- package/dist/internal/present-content.js +1 -0
- package/dist/internal/record-menu-items.d.ts +4 -3
- package/dist/internal/record-menu-items.d.ts.map +1 -1
- package/dist/internal/record-menu-items.js +21 -6
- package/dist/internal/settings-save.d.ts +9 -2
- package/dist/internal/settings-save.d.ts.map +1 -1
- package/dist/internal/settings-save.js +19 -6
- package/dist/internal/table-compact-line.d.ts +38 -0
- package/dist/internal/table-compact-line.d.ts.map +1 -0
- package/dist/internal/table-compact-line.js +35 -0
- package/dist/internal/title-when-cut.d.ts +8 -0
- package/dist/internal/title-when-cut.d.ts.map +1 -0
- package/dist/internal/title-when-cut.js +22 -0
- package/dist/internal/unsaved-guard.d.ts +18 -0
- package/dist/internal/unsaved-guard.d.ts.map +1 -0
- package/dist/internal/unsaved-guard.js +31 -0
- package/dist/lib/merge-tokens.generated.js +2 -2
- package/dist/showcase/foundations.d.ts.map +1 -1
- package/dist/showcase/foundations.js +10 -2
- package/dist/showcase/specimens/actions.d.ts +2 -0
- package/dist/showcase/specimens/actions.d.ts.map +1 -1
- package/dist/showcase/specimens/actions.js +30 -5
- package/dist/showcase/specimens/charts.d.ts.map +1 -1
- package/dist/showcase/specimens/charts.js +22 -13
- package/dist/showcase/specimens/choices.d.ts +14 -3
- package/dist/showcase/specimens/choices.d.ts.map +1 -1
- package/dist/showcase/specimens/choices.js +93 -13
- package/dist/showcase/specimens/compositions.d.ts.map +1 -1
- package/dist/showcase/specimens/compositions.js +136 -23
- package/dist/showcase/specimens/data.d.ts +12 -7
- package/dist/showcase/specimens/data.d.ts.map +1 -1
- package/dist/showcase/specimens/data.js +139 -35
- package/dist/showcase/specimens/feedback.d.ts +2 -0
- package/dist/showcase/specimens/feedback.d.ts.map +1 -1
- package/dist/showcase/specimens/feedback.js +39 -15
- package/dist/showcase/specimens/index.d.ts +20 -12
- package/dist/showcase/specimens/index.d.ts.map +1 -1
- package/dist/showcase/specimens/inputs.d.ts +4 -2
- package/dist/showcase/specimens/inputs.d.ts.map +1 -1
- package/dist/showcase/specimens/inputs.js +62 -19
- package/dist/showcase/specimens/menus.d.ts +0 -1
- package/dist/showcase/specimens/menus.d.ts.map +1 -1
- package/dist/showcase/specimens/menus.js +47 -17
- package/dist/showcase/specimens/navigation.d.ts +6 -4
- package/dist/showcase/specimens/navigation.d.ts.map +1 -1
- package/dist/showcase/specimens/navigation.js +61 -32
- package/dist/showcase/specimens/other.d.ts +1 -3
- package/dist/showcase/specimens/other.d.ts.map +1 -1
- package/dist/showcase/specimens/other.js +17 -13
- package/dist/showcase/specimens/status.d.ts +4 -1
- package/dist/showcase/specimens/status.d.ts.map +1 -1
- package/dist/showcase/specimens/status.js +64 -11
- package/dist/showcase/usage.generated.d.ts +1 -1
- package/dist/showcase/usage.generated.d.ts.map +1 -1
- package/dist/showcase/usage.generated.js +632 -544
- package/dist/standalone/index.js +1 -1
- package/dist/styles/components.css +13 -13
- package/dist/styles/globals.css +25 -0
- package/package.json +2 -3
- package/dist/components/approval-row.d.ts +0 -34
- package/dist/components/approval-row.d.ts.map +0 -1
- package/dist/components/approval-row.js +0 -27
- package/dist/components/channel-view.d.ts +0 -112
- package/dist/components/channel-view.d.ts.map +0 -1
- package/dist/components/channel-view.js +0 -84
- package/dist/components/dashboard-shell.d.ts +0 -51
- package/dist/components/dashboard-shell.d.ts.map +0 -1
- package/dist/components/dashboard-shell.js +0 -89
- package/dist/components/direction.d.ts +0 -2
- package/dist/components/direction.d.ts.map +0 -1
- package/dist/components/direction.js +0 -1
- package/dist/components/expandable-block.d.ts +0 -20
- package/dist/components/expandable-block.d.ts.map +0 -1
- package/dist/components/expandable-block.js +0 -32
- package/dist/components/form.d.ts +0 -42
- package/dist/components/form.d.ts.map +0 -1
- package/dist/components/form.js +0 -91
- package/dist/components/label-system.d.ts +0 -17
- package/dist/components/label-system.d.ts.map +0 -1
- package/dist/components/label-system.js +0 -21
- package/dist/components/memory-item.d.ts +0 -21
- package/dist/components/memory-item.d.ts.map +0 -1
- package/dist/components/memory-item.js +0 -18
- package/dist/components/menubar.d.ts +0 -43
- package/dist/components/menubar.d.ts.map +0 -1
- package/dist/components/menubar.js +0 -69
- package/dist/components/navigation-menu.d.ts +0 -26
- package/dist/components/navigation-menu.d.ts.map +0 -1
- package/dist/components/navigation-menu.js +0 -45
- package/dist/components/pagination.d.ts +0 -33
- package/dist/components/pagination.d.ts.map +0 -1
- package/dist/components/pagination.js +0 -41
- package/dist/components/plugin-slot-boundary.d.ts +0 -42
- package/dist/components/plugin-slot-boundary.d.ts.map +0 -1
- package/dist/components/plugin-slot-boundary.js +0 -41
- package/dist/components/status-row.d.ts +0 -32
- package/dist/components/status-row.d.ts.map +0 -1
- package/dist/components/status-row.js +0 -35
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
type ChoiceboxGroupBase = {
|
|
3
|
+
/** Names the group for assistive technology; drawn above the tiles only with `showLabel`. */
|
|
4
|
+
label: string;
|
|
5
|
+
showLabel?: boolean;
|
|
6
|
+
/** Makes every tile unavailable and writes why under the legend. */
|
|
7
|
+
disabledReason?: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
orientation?: "vertical" | "horizontal";
|
|
10
|
+
className?: string;
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
};
|
|
13
|
+
export type ChoiceboxGroupProps = ChoiceboxGroupBase & ({
|
|
14
|
+
type: "radio";
|
|
15
|
+
required?: boolean;
|
|
16
|
+
value?: string | null;
|
|
17
|
+
defaultValue?: string;
|
|
18
|
+
onValueChange?: (value: string) => void;
|
|
19
|
+
} | {
|
|
20
|
+
type: "checkbox";
|
|
21
|
+
required?: undefined;
|
|
22
|
+
value?: string[];
|
|
23
|
+
defaultValue?: string[];
|
|
24
|
+
onValueChange?: (value: string[]) => void;
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* A group of larger tiles, each a radio or a checkbox with a title and a description.
|
|
28
|
+
*
|
|
29
|
+
* @family Choices
|
|
30
|
+
* @when "A choice that benefits from a larger tap target plus a description or icon, like a
|
|
31
|
+
* framework picker, plan comparison, or deployment region with latency."
|
|
32
|
+
* (https://vercel.com/geist/choicebox) "Single-select for mutually exclusive choices, multi-select
|
|
33
|
+
* for additive ones." (https://vercel.com/geist/choicebox) "Don’t mix the two within one group."
|
|
34
|
+
* (https://vercel.com/geist/choicebox) "Cap at 4–6 tiles." (https://vercel.com/geist/choicebox)
|
|
35
|
+
* Ours: where a Library entry applies, an API key's access level.
|
|
36
|
+
* @instead "Past that, switch to `Select` or `Combobox` so the page doesn’t scroll for a single
|
|
37
|
+
* field." (https://vercel.com/geist/choicebox) "For plain text labels with no description, use
|
|
38
|
+
* `Radio`." (https://vercel.com/geist/choicebox) Ours: Geist's `Radio` is our `RadioGroup`, or a
|
|
39
|
+
* `Checkbox` for several. Two or three views of one surface are a `SegmentedControl`.
|
|
40
|
+
* @behaviour "The whole tile is the click and focus target; tapping anywhere inside selects it."
|
|
41
|
+
* (https://vercel.com/geist/choicebox) "Don’t place nested buttons or links inside a tile that
|
|
42
|
+
* would steal the click." (https://vercel.com/geist/choicebox) "Selected state shows a check or
|
|
43
|
+
* filled dot in the corner." (https://vercel.com/geist/choicebox) "The border highlight alone isn’t
|
|
44
|
+
* enough on low-contrast screens." (https://vercel.com/geist/choicebox) "Disabled tiles need a
|
|
45
|
+
* Tooltip naming why (`Available on Pro`)." (https://vercel.com/geist/choicebox) "A faded tile with
|
|
46
|
+
* no reason reads as broken." (https://vercel.com/geist/choicebox) Ours: the group has a `label`
|
|
47
|
+
* and a `type`, and every tile a `title` and a `description`; a group or a tile without them does
|
|
48
|
+
* not compile. Tiles share one row and wrap to a column on a narrow screen;
|
|
49
|
+
* `orientation="vertical"` stacks them. They are 12 px apart, each with 12 px inside and 24 px
|
|
50
|
+
* between its words and its corner mark, the mark centred against the words. Colour: a selected,
|
|
51
|
+
* available tile is the one place blue sits on a choice, as a blue border, a blue tint behind the
|
|
52
|
+
* title and description, blue words, and a blue corner mark; a selected tile that is unavailable
|
|
53
|
+
* stays grey, never a faded blue. An unselected tile stays neutral and takes a grey fill on hover.
|
|
54
|
+
* `children` of a tile appear below its tinted row while it is selected. A tile, or the whole
|
|
55
|
+
* group, is unavailable only with a `disabledReason`, written under the tile's description or the
|
|
56
|
+
* legend, and only its title greys. A tile may carry `specs`, grey chips under its title, and one
|
|
57
|
+
* `badge` beside it for the option to prefer (*Recommended*); both are grey `secondary` badges,
|
|
58
|
+
* because blue marks only the selected tile.
|
|
59
|
+
* @words "Titles are parallel: one Title Case title plus one sentence-case description per tile,
|
|
60
|
+
* ending in a period." (https://vercel.com/geist/choicebox) "Don’t restate the title in the
|
|
61
|
+
* description." (https://vercel.com/geist/choicebox) "The description adds the differentiator
|
|
62
|
+
* (`$20/mo · 100 GB bandwidth`), not a synonym." (https://vercel.com/geist/choicebox) "Icons are
|
|
63
|
+
* decorative when paired with a title; if the icon is the only label, give the tile an `aria-label`
|
|
64
|
+
* naming the choice." (https://vercel.com/geist/choicebox) Ours: the title is a short noun phrase
|
|
65
|
+
* in sentence case: *Pro trial*; the description is *Free for two weeks.* The label names the
|
|
66
|
+
* choice: *Plan*.
|
|
67
|
+
* @access "Tiles render as radios or checkboxes under the hood, so keep them inside a `<fieldset>`
|
|
68
|
+
* with a `<legend>` so screen readers announce the group." (https://vercel.com/geist/choicebox)
|
|
69
|
+
* "Arrow keys move within a single-select group, Space toggles in multi-select."
|
|
70
|
+
* (https://vercel.com/geist/choicebox) "Don’t override those keys with custom handlers."
|
|
71
|
+
* (https://vercel.com/geist/choicebox) "Color is not the selection signal."
|
|
72
|
+
* (https://vercel.com/geist/choicebox) "Pair the highlight border with the corner check so
|
|
73
|
+
* colorblind users still see what’s active." (https://vercel.com/geist/choicebox) Ours: a
|
|
74
|
+
* `FieldSet` with the label as its legend, which names a group of checkboxes; a `role="radiogroup"`
|
|
75
|
+
* is labelled by the same legend. Each tile is named by its title and described by its description
|
|
76
|
+
* and reason. Keyboard focus outlines the whole tile, and the box in its corner draws no outline of
|
|
77
|
+
* its own.
|
|
78
|
+
*/
|
|
79
|
+
declare function ChoiceboxGroup(props: ChoiceboxGroupProps): React.JSX.Element;
|
|
80
|
+
export type ChoiceboxGroupItemProps = {
|
|
81
|
+
value: string;
|
|
82
|
+
title: string;
|
|
83
|
+
description: string;
|
|
84
|
+
/** Grey facts under the title that set the options apart: *4 vCPU*, *8 GB*. */
|
|
85
|
+
specs?: readonly string[];
|
|
86
|
+
/** One chip beside the title that singles the tile out: *Recommended*. */
|
|
87
|
+
badge?: string;
|
|
88
|
+
/** Makes the tile unavailable and writes why under its description. */
|
|
89
|
+
disabledReason?: string;
|
|
90
|
+
className?: string;
|
|
91
|
+
/** Read-only content shown while the tile is selected. */
|
|
92
|
+
children?: React.ReactNode;
|
|
93
|
+
};
|
|
94
|
+
declare function ChoiceboxGroupItem({ value, title, description, specs, badge, disabledReason, className, children, }: ChoiceboxGroupItemProps): React.JSX.Element;
|
|
95
|
+
export { ChoiceboxGroup, ChoiceboxGroupItem };
|
|
96
|
+
//# sourceMappingURL=choicebox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"choicebox.d.ts","sourceRoot":"","sources":["../../src/components/choicebox.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAkB/B,KAAK,kBAAkB,GAAG;IACxB,6FAA6F;IAC7F,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oEAAoE;IACpE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,UAAU,GAAG,YAAY,CAAC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,kBAAkB,GAClD,CACI;IACE,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC,GACD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CAC3C,CACJ,CAAC;AAQJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,iBAAS,cAAc,CAAC,KAAK,EAAE,mBAAmB,qBAwDjD;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B,CAAC;AAEF,iBAAS,kBAAkB,CAAC,EAC1B,KAAK,EACL,KAAK,EACL,WAAW,EACX,KAAK,EACL,KAAK,EACL,cAAc,EACd,SAAS,EACT,QAAQ,GACT,EAAE,uBAAuB,qBA0FzB;AAED,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { CheckboxGroup as CheckboxGroupPrimitive } from "@base-ui/react/checkbox-group";
|
|
5
|
+
import { Badge } from "./badge.js";
|
|
6
|
+
import { Checkbox } from "./checkbox.js";
|
|
7
|
+
import { FieldDescription, FieldLegend, FieldSet } from "./field.js";
|
|
8
|
+
import { RadioGroup, RadioGroupItem } from "./radio-group.js";
|
|
9
|
+
import { cn } from "../lib/utils.js";
|
|
10
|
+
const ChoiceboxSelectionContext = React.createContext(null);
|
|
11
|
+
function asList(value) {
|
|
12
|
+
if (value === undefined)
|
|
13
|
+
return undefined;
|
|
14
|
+
if (value === null)
|
|
15
|
+
return [];
|
|
16
|
+
return Array.isArray(value) ? value : [value];
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* A group of larger tiles, each a radio or a checkbox with a title and a description.
|
|
20
|
+
*
|
|
21
|
+
* @family Choices
|
|
22
|
+
* @when "A choice that benefits from a larger tap target plus a description or icon, like a
|
|
23
|
+
* framework picker, plan comparison, or deployment region with latency."
|
|
24
|
+
* (https://vercel.com/geist/choicebox) "Single-select for mutually exclusive choices, multi-select
|
|
25
|
+
* for additive ones." (https://vercel.com/geist/choicebox) "Don’t mix the two within one group."
|
|
26
|
+
* (https://vercel.com/geist/choicebox) "Cap at 4–6 tiles." (https://vercel.com/geist/choicebox)
|
|
27
|
+
* Ours: where a Library entry applies, an API key's access level.
|
|
28
|
+
* @instead "Past that, switch to `Select` or `Combobox` so the page doesn’t scroll for a single
|
|
29
|
+
* field." (https://vercel.com/geist/choicebox) "For plain text labels with no description, use
|
|
30
|
+
* `Radio`." (https://vercel.com/geist/choicebox) Ours: Geist's `Radio` is our `RadioGroup`, or a
|
|
31
|
+
* `Checkbox` for several. Two or three views of one surface are a `SegmentedControl`.
|
|
32
|
+
* @behaviour "The whole tile is the click and focus target; tapping anywhere inside selects it."
|
|
33
|
+
* (https://vercel.com/geist/choicebox) "Don’t place nested buttons or links inside a tile that
|
|
34
|
+
* would steal the click." (https://vercel.com/geist/choicebox) "Selected state shows a check or
|
|
35
|
+
* filled dot in the corner." (https://vercel.com/geist/choicebox) "The border highlight alone isn’t
|
|
36
|
+
* enough on low-contrast screens." (https://vercel.com/geist/choicebox) "Disabled tiles need a
|
|
37
|
+
* Tooltip naming why (`Available on Pro`)." (https://vercel.com/geist/choicebox) "A faded tile with
|
|
38
|
+
* no reason reads as broken." (https://vercel.com/geist/choicebox) Ours: the group has a `label`
|
|
39
|
+
* and a `type`, and every tile a `title` and a `description`; a group or a tile without them does
|
|
40
|
+
* not compile. Tiles share one row and wrap to a column on a narrow screen;
|
|
41
|
+
* `orientation="vertical"` stacks them. They are 12 px apart, each with 12 px inside and 24 px
|
|
42
|
+
* between its words and its corner mark, the mark centred against the words. Colour: a selected,
|
|
43
|
+
* available tile is the one place blue sits on a choice, as a blue border, a blue tint behind the
|
|
44
|
+
* title and description, blue words, and a blue corner mark; a selected tile that is unavailable
|
|
45
|
+
* stays grey, never a faded blue. An unselected tile stays neutral and takes a grey fill on hover.
|
|
46
|
+
* `children` of a tile appear below its tinted row while it is selected. A tile, or the whole
|
|
47
|
+
* group, is unavailable only with a `disabledReason`, written under the tile's description or the
|
|
48
|
+
* legend, and only its title greys. A tile may carry `specs`, grey chips under its title, and one
|
|
49
|
+
* `badge` beside it for the option to prefer (*Recommended*); both are grey `secondary` badges,
|
|
50
|
+
* because blue marks only the selected tile.
|
|
51
|
+
* @words "Titles are parallel: one Title Case title plus one sentence-case description per tile,
|
|
52
|
+
* ending in a period." (https://vercel.com/geist/choicebox) "Don’t restate the title in the
|
|
53
|
+
* description." (https://vercel.com/geist/choicebox) "The description adds the differentiator
|
|
54
|
+
* (`$20/mo · 100 GB bandwidth`), not a synonym." (https://vercel.com/geist/choicebox) "Icons are
|
|
55
|
+
* decorative when paired with a title; if the icon is the only label, give the tile an `aria-label`
|
|
56
|
+
* naming the choice." (https://vercel.com/geist/choicebox) Ours: the title is a short noun phrase
|
|
57
|
+
* in sentence case: *Pro trial*; the description is *Free for two weeks.* The label names the
|
|
58
|
+
* choice: *Plan*.
|
|
59
|
+
* @access "Tiles render as radios or checkboxes under the hood, so keep them inside a `<fieldset>`
|
|
60
|
+
* with a `<legend>` so screen readers announce the group." (https://vercel.com/geist/choicebox)
|
|
61
|
+
* "Arrow keys move within a single-select group, Space toggles in multi-select."
|
|
62
|
+
* (https://vercel.com/geist/choicebox) "Don’t override those keys with custom handlers."
|
|
63
|
+
* (https://vercel.com/geist/choicebox) "Color is not the selection signal."
|
|
64
|
+
* (https://vercel.com/geist/choicebox) "Pair the highlight border with the corner check so
|
|
65
|
+
* colorblind users still see what’s active." (https://vercel.com/geist/choicebox) Ours: a
|
|
66
|
+
* `FieldSet` with the label as its legend, which names a group of checkboxes; a `role="radiogroup"`
|
|
67
|
+
* is labelled by the same legend. Each tile is named by its title and described by its description
|
|
68
|
+
* and reason. Keyboard focus outlines the whole tile, and the box in its corner draws no outline of
|
|
69
|
+
* its own.
|
|
70
|
+
*/
|
|
71
|
+
function ChoiceboxGroup(props) {
|
|
72
|
+
const legendId = React.useId();
|
|
73
|
+
const reasonId = React.useId();
|
|
74
|
+
const { label, showLabel = false, disabledReason, name, orientation = "horizontal", className, } = props;
|
|
75
|
+
const groupReasonId = disabledReason ? reasonId : undefined;
|
|
76
|
+
const [internal, setInternal] = React.useState(asList(props.defaultValue) ?? []);
|
|
77
|
+
const selected = asList(props.value) ?? internal;
|
|
78
|
+
const list = cn("grid gap-3", orientation === "horizontal" && "sm:auto-cols-fr sm:grid-flow-col");
|
|
79
|
+
return (_jsx(ChoiceboxSelectionContext.Provider, { value: { type: props.type, name, selected, groupReasonId }, children: _jsxs(FieldSet, { className: className, "data-slot": "choicebox-group", children: [_jsx(FieldLegend, { className: showLabel ? "mb-2" : "sr-only", id: legendId, variant: "label", children: label }), disabledReason ? (_jsx(FieldDescription, { id: reasonId, children: disabledReason })) : null, props.type === "radio" ? (_jsx(RadioGroup, { "aria-labelledby": legendId, className: list, disabled: groupReasonId !== undefined, name: name, onValueChange: (next) => {
|
|
80
|
+
setInternal([next]);
|
|
81
|
+
props.onValueChange?.(next);
|
|
82
|
+
}, required: props.required, value: selected[0] ?? null, children: props.children })) : (_jsx(CheckboxGroupPrimitive, { className: list, disabled: groupReasonId !== undefined, onValueChange: (next) => {
|
|
83
|
+
setInternal(next);
|
|
84
|
+
props.onValueChange?.(next);
|
|
85
|
+
}, value: selected, children: props.children }))] }) }));
|
|
86
|
+
}
|
|
87
|
+
function ChoiceboxGroupItem({ value, title, description, specs, badge, disabledReason, className, children, }) {
|
|
88
|
+
const group = React.useContext(ChoiceboxSelectionContext);
|
|
89
|
+
const titleId = React.useId();
|
|
90
|
+
const descriptionId = React.useId();
|
|
91
|
+
const specsId = React.useId();
|
|
92
|
+
const badgeId = React.useId();
|
|
93
|
+
const reasonId = React.useId();
|
|
94
|
+
if (group === null) {
|
|
95
|
+
throw new Error("ChoiceboxGroupItem belongs inside a ChoiceboxGroup");
|
|
96
|
+
}
|
|
97
|
+
const control = {
|
|
98
|
+
"aria-describedby": [
|
|
99
|
+
descriptionId,
|
|
100
|
+
specs?.length ? specsId : undefined,
|
|
101
|
+
badge ? badgeId : undefined,
|
|
102
|
+
disabledReason ? reasonId : undefined,
|
|
103
|
+
group.groupReasonId,
|
|
104
|
+
]
|
|
105
|
+
.filter((id) => id !== undefined)
|
|
106
|
+
.join(" "),
|
|
107
|
+
"aria-labelledby": titleId,
|
|
108
|
+
disabled: Boolean(disabledReason) || group.groupReasonId !== undefined,
|
|
109
|
+
value,
|
|
110
|
+
};
|
|
111
|
+
return (_jsxs("div", { className: cn("group/choicebox flex flex-col overflow-hidden rounded-sm border bg-background nc-transition-paint not-has-data-disabled:hover:bg-accent has-focus-visible:nc-focus-outline has-focus-visible:outline-ring has-data-checked:not-has-data-disabled:border-info", className), "data-slot": "choicebox-item", children: [_jsxs("label", { className: "flex cursor-pointer items-center justify-between gap-6 p-3 nc-transition-paint has-data-checked:not-has-data-disabled:bg-info-soft has-data-disabled:cursor-not-allowed", children: [_jsxs("span", { className: "flex min-w-0 flex-col gap-1", children: [_jsxs("span", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-sm font-medium group-has-data-checked/choicebox:not-group-has-data-disabled/choicebox:text-info-soft-foreground group-has-data-disabled/choicebox:text-muted-foreground", id: titleId, children: title }), badge ? (_jsx(Badge, { id: badgeId, size: "sm", variant: "secondary", children: badge })) : null] }), specs?.length ? (_jsx("span", { className: "flex flex-wrap gap-1", id: specsId, children: specs.map((spec) => (_jsx(Badge, { size: "sm", variant: "secondary", children: spec }, spec))) })) : null, _jsx("span", { className: "text-sm text-muted-foreground group-has-data-checked/choicebox:not-group-has-data-disabled/choicebox:text-info-soft-foreground", id: descriptionId, children: description }), disabledReason ? (_jsx("span", { className: "text-sm text-muted-foreground", id: reasonId, children: disabledReason })) : null] }), group.type === "radio" ? (_jsx(RadioGroupItem, { ...control, className: "outline-none data-checked:not-data-disabled:border-info-soft-foreground data-checked:not-data-disabled:text-info-soft-foreground" })) : (_jsx(Checkbox, { ...control, className: "outline-none data-checked:not-data-disabled:border-info-soft-foreground data-checked:not-data-disabled:bg-info-soft-foreground data-checked:not-data-disabled:text-info-soft", name: group.name }))] }), children && group.selected.includes(value) ? (_jsx("div", { className: "p-2", "data-slot": "choicebox-content", children: children })) : null] }));
|
|
112
|
+
}
|
|
113
|
+
export { ChoiceboxGroup, ChoiceboxGroupItem };
|
|
@@ -0,0 +1,57 @@
|
|
|
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 { type KbdProps } from "./kbd.js";
|
|
5
|
+
/** The keys of a shortcut as `Kbd` takes them; `ClearableInput` draws them at the size of a field. */
|
|
6
|
+
export type ClearableInputShortcut = KbdProps extends infer Keys ? Keys extends unknown ? Omit<Keys, "size"> : never : never;
|
|
7
|
+
export type ClearableInputProps = Omit<React.ComponentProps<"input">, "defaultValue" | "onChange" | "prefix" | "ref" | "size" | "value"> & {
|
|
8
|
+
value: string;
|
|
9
|
+
onValueChange: (value: string) => void;
|
|
10
|
+
/** Runs after the value is emptied, so the caller can reset what depends on it. */
|
|
11
|
+
onClear?: () => void;
|
|
12
|
+
/** The clear button's name, in the product's words: "Clear search". */
|
|
13
|
+
clearLabel: string;
|
|
14
|
+
size?: FieldSize;
|
|
15
|
+
/** A mark before the text. Decorative; the input keeps its own name. */
|
|
16
|
+
prefix?: React.ReactNode;
|
|
17
|
+
/** The keys that open the command palette, shown while the box is empty. Esc replaces them once it has text. */
|
|
18
|
+
shortcut?: ClearableInputShortcut;
|
|
19
|
+
/** A query is running; the results stay on screen. */
|
|
20
|
+
loading?: boolean;
|
|
21
|
+
/** The message under the box, in the product's words; it also marks the box invalid. */
|
|
22
|
+
error?: string;
|
|
23
|
+
} & FieldName;
|
|
24
|
+
/**
|
|
25
|
+
* A text box that empties itself: a clear button once it has text, and Escape.
|
|
26
|
+
*
|
|
27
|
+
* @family Inputs
|
|
28
|
+
* @when "Text input with a clear button that resets the value on Escape."
|
|
29
|
+
* (https://vercel.com/geist/clearable-input) Ours: a single-line value a person may want to empty
|
|
30
|
+
* in one move: a filter, a search, a reference they paste and replace.
|
|
31
|
+
* @instead A collection's search is `CollectionSearch`. A value that is never emptied is `Input`. A
|
|
32
|
+
* box with a fixed prefix or suffix is `Input`; one with a copy button is `InputGroup`.
|
|
33
|
+
* @behaviour Same ring, halo, hover, disabled and error as `Input`; colour sits where it does there
|
|
34
|
+
* and nowhere else. The clear button shows only while the box has text and is enabled, as an Esc
|
|
35
|
+
* key cap flush against the end of the box that darkens on hover and keeps a transparent fill (a
|
|
36
|
+
* close mark on a touch screen, which has no Escape). Pressing it, or Escape inside the box,
|
|
37
|
+
* empties the value, calls `onClear` and puts focus back in the box. Escape on an empty box does
|
|
38
|
+
* nothing here, so it closes the dialog or drawer around it. "Automatically clears the input if
|
|
39
|
+
* escape is pressed." (https://vercel.com/geist/input) "Displays the <kbd>⌘</kbd> <kbd>K</kbd>
|
|
40
|
+
* shortcut to indicate that the input supports a command palette." (https://vercel.com/geist/input)
|
|
41
|
+
* "Transitions to showing <kbd>Esc</kbd> when the field is dirty." (https://vercel.com/geist/input)
|
|
42
|
+
* Ours: the `shortcut` keys are one cap per key (*⌘* then *K*, 4 px apart, 10 px from the edge),
|
|
43
|
+
* hidden on a touch screen. `loading` marks the box busy and, after a second, draws the waiting
|
|
44
|
+
* line along its bottom edge; nothing spins and the results stay. `label` and `error` draw the
|
|
45
|
+
* `Field` parts around the box as on `Input`, and a string `label` requires `id`; a box with no
|
|
46
|
+
* name does not compile. `className` lands on the box.
|
|
47
|
+
* @words The clear button is named for what it empties (*Clear search*, *Clear filter*).
|
|
48
|
+
* "Placeholders show an example value (`my-awesome-project`, `example.com`), never instructions
|
|
49
|
+
* like `Enter your project name`." (https://vercel.com/geist/input) Ours: the placeholder may also
|
|
50
|
+
* be the scope.
|
|
51
|
+
* @access A visible `label` or `aria-label` names the box. The clear button is a named button,
|
|
52
|
+
* `aria-keyshortcuts` Escape; the prefix and the keys are hidden from assistive technology.
|
|
53
|
+
* `aria-busy` while `loading`.
|
|
54
|
+
*/
|
|
55
|
+
declare function ClearableInput({ className, value, onValueChange, onClear, clearLabel, size, prefix, shortcut, loading, label, error, disabled, onKeyDown, ...props }: ClearableInputProps): React.JSX.Element;
|
|
56
|
+
export { ClearableInput };
|
|
57
|
+
//# sourceMappingURL=clearable-input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clearable-input.d.ts","sourceRoot":"","sources":["../../src/components/clearable-input.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAS/B,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAO,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGtD,sGAAsG;AACtG,MAAM,MAAM,sBAAsB,GAAG,QAAQ,SAAS,MAAM,IAAI,GAC5D,IAAI,SAAS,OAAO,GAClB,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,GAClB,KAAK,GACP,KAAK,CAAC;AAEV,MAAM,MAAM,mBAAmB,GAAG,IAAI,CACpC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,EAC7B,cAAc,GAAG,UAAU,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,CAClE,GAAG;IACF,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,uEAAuE;IACvE,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,wEAAwE;IACxE,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,gHAAgH;IAChH,QAAQ,CAAC,EAAE,sBAAsB,CAAC;IAClC,sDAAsD;IACtD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wFAAwF;IACxF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,SAAS,CAAC;AAEd;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,iBAAS,cAAc,CAAC,EACtB,SAAS,EACT,KAAK,EACL,aAAa,EACb,OAAO,EACP,UAAU,EACV,IAAI,EACJ,MAAM,EACN,QAAQ,EACR,OAAe,EACf,KAAK,EACL,KAAK,EACL,QAAQ,EACR,SAAS,EACT,GAAG,KAAK,EACT,EAAE,mBAAmB,qBAyErB;AAED,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { XIcon } from "lucide-react";
|
|
5
|
+
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupControl, } from "./input-group.js";
|
|
6
|
+
import { FieldFrame } from "../internal/field-frame.js";
|
|
7
|
+
import { Kbd } from "./kbd.js";
|
|
8
|
+
import { WaitingLine } from "./waiting-line.js";
|
|
9
|
+
/**
|
|
10
|
+
* A text box that empties itself: a clear button once it has text, and Escape.
|
|
11
|
+
*
|
|
12
|
+
* @family Inputs
|
|
13
|
+
* @when "Text input with a clear button that resets the value on Escape."
|
|
14
|
+
* (https://vercel.com/geist/clearable-input) Ours: a single-line value a person may want to empty
|
|
15
|
+
* in one move: a filter, a search, a reference they paste and replace.
|
|
16
|
+
* @instead A collection's search is `CollectionSearch`. A value that is never emptied is `Input`. A
|
|
17
|
+
* box with a fixed prefix or suffix is `Input`; one with a copy button is `InputGroup`.
|
|
18
|
+
* @behaviour Same ring, halo, hover, disabled and error as `Input`; colour sits where it does there
|
|
19
|
+
* and nowhere else. The clear button shows only while the box has text and is enabled, as an Esc
|
|
20
|
+
* key cap flush against the end of the box that darkens on hover and keeps a transparent fill (a
|
|
21
|
+
* close mark on a touch screen, which has no Escape). Pressing it, or Escape inside the box,
|
|
22
|
+
* empties the value, calls `onClear` and puts focus back in the box. Escape on an empty box does
|
|
23
|
+
* nothing here, so it closes the dialog or drawer around it. "Automatically clears the input if
|
|
24
|
+
* escape is pressed." (https://vercel.com/geist/input) "Displays the <kbd>⌘</kbd> <kbd>K</kbd>
|
|
25
|
+
* shortcut to indicate that the input supports a command palette." (https://vercel.com/geist/input)
|
|
26
|
+
* "Transitions to showing <kbd>Esc</kbd> when the field is dirty." (https://vercel.com/geist/input)
|
|
27
|
+
* Ours: the `shortcut` keys are one cap per key (*⌘* then *K*, 4 px apart, 10 px from the edge),
|
|
28
|
+
* hidden on a touch screen. `loading` marks the box busy and, after a second, draws the waiting
|
|
29
|
+
* line along its bottom edge; nothing spins and the results stay. `label` and `error` draw the
|
|
30
|
+
* `Field` parts around the box as on `Input`, and a string `label` requires `id`; a box with no
|
|
31
|
+
* name does not compile. `className` lands on the box.
|
|
32
|
+
* @words The clear button is named for what it empties (*Clear search*, *Clear filter*).
|
|
33
|
+
* "Placeholders show an example value (`my-awesome-project`, `example.com`), never instructions
|
|
34
|
+
* like `Enter your project name`." (https://vercel.com/geist/input) Ours: the placeholder may also
|
|
35
|
+
* be the scope.
|
|
36
|
+
* @access A visible `label` or `aria-label` names the box. The clear button is a named button,
|
|
37
|
+
* `aria-keyshortcuts` Escape; the prefix and the keys are hidden from assistive technology.
|
|
38
|
+
* `aria-busy` while `loading`.
|
|
39
|
+
*/
|
|
40
|
+
function ClearableInput({ className, value, onValueChange, onClear, clearLabel, size, prefix, shortcut, loading = false, label, error, disabled, onKeyDown, ...props }) {
|
|
41
|
+
const input = React.useRef(null);
|
|
42
|
+
const clearable = value !== "" && !disabled;
|
|
43
|
+
const shortcutHint = shortcut ? (_jsxs(InputGroupAddon, { align: "inline-end", "aria-hidden": "true", className: "gap-1 pr-2.5 pl-3 pointer-coarse:hidden", children: [shortcut.meta ? _jsx(Kbd, { size: "sm", meta: true }) : null, shortcut.shift ? _jsx(Kbd, { size: "sm", shift: true }) : null, shortcut.alt ? _jsx(Kbd, { size: "sm", alt: true }) : null, shortcut.ctrl ? _jsx(Kbd, { size: "sm", ctrl: true }) : null, shortcut.children ? _jsx(Kbd, { size: "sm", children: shortcut.children }) : null] })) : null;
|
|
44
|
+
function clear() {
|
|
45
|
+
input.current?.focus();
|
|
46
|
+
onValueChange("");
|
|
47
|
+
onClear?.();
|
|
48
|
+
}
|
|
49
|
+
return (_jsx(FieldFrame, { label: label, error: error, size: size, control: props, children: (aria) => (_jsxs(InputGroup, { size: size, className: className, children: [prefix ? _jsx(InputGroupAddon, { "aria-hidden": "true", children: prefix }) : null, _jsx(InputGroupControl, { ref: input, "aria-busy": loading || undefined, className: "[&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none", disabled: disabled, onChange: (event) => onValueChange(event.target.value), onKeyDown: (event) => {
|
|
50
|
+
onKeyDown?.(event);
|
|
51
|
+
if (event.key !== "Escape" || event.defaultPrevented || !clearable)
|
|
52
|
+
return;
|
|
53
|
+
event.preventDefault();
|
|
54
|
+
event.stopPropagation();
|
|
55
|
+
clear();
|
|
56
|
+
}, value: value, ...props, ...aria }), clearable ? (_jsx(InputGroupAddon, { align: "inline-end", className: "has-[>button]:pl-3", children: _jsxs(InputGroupButton, { "aria-keyshortcuts": "Escape", "aria-label": clearLabel, onClick: clear, size: "icon", children: [_jsx(Kbd, { "aria-hidden": "true", className: "pointer-coarse:hidden group-hover/button:text-foreground", size: "sm", children: "Esc" }), _jsx(XIcon, { "aria-hidden": "true", className: "hidden pointer-coarse:block" })] }) })) : (shortcutHint), loading ? (_jsx(WaitingLine, { className: "absolute inset-x-1.5 bottom-px w-auto", decorative: true })) : null] })) }));
|
|
57
|
+
}
|
|
58
|
+
export { ClearableInput };
|
|
@@ -1,23 +1,83 @@
|
|
|
1
1
|
import { type CopyButtonProps } from "./copy-button.js";
|
|
2
|
+
type MarkedState = "highlighted" | "added" | "removed";
|
|
3
|
+
type LanguageSwitch = {
|
|
4
|
+
label: string;
|
|
5
|
+
options: readonly {
|
|
6
|
+
label: string;
|
|
7
|
+
value: string;
|
|
8
|
+
}[];
|
|
9
|
+
value: string;
|
|
10
|
+
onChange: (value: string) => void;
|
|
11
|
+
};
|
|
12
|
+
type LanguageControl = {
|
|
13
|
+
switcher?: LanguageSwitch | undefined;
|
|
14
|
+
tabs?: undefined;
|
|
15
|
+
} | {
|
|
16
|
+
tabs?: LanguageSwitch | undefined;
|
|
17
|
+
switcher?: undefined;
|
|
18
|
+
};
|
|
19
|
+
/** A block that marks lines says each mark in words; a block that marks none has nothing to say. */
|
|
20
|
+
type MarkedLines = {
|
|
21
|
+
highlightedLinesNumbers?: readonly number[] | undefined;
|
|
22
|
+
addedLinesNumbers?: readonly number[] | undefined;
|
|
23
|
+
removedLinesNumbers?: readonly number[] | undefined;
|
|
24
|
+
lineLabel: (line: number, state: MarkedState) => string;
|
|
25
|
+
} | {
|
|
26
|
+
highlightedLinesNumbers?: undefined;
|
|
27
|
+
addedLinesNumbers?: undefined;
|
|
28
|
+
removedLinesNumbers?: undefined;
|
|
29
|
+
lineLabel?: undefined;
|
|
30
|
+
};
|
|
31
|
+
type CodeBlockProps = {
|
|
32
|
+
code: string;
|
|
33
|
+
label: string;
|
|
34
|
+
filename?: string | undefined;
|
|
35
|
+
className?: string | undefined;
|
|
36
|
+
hideLineNumbers?: boolean | undefined;
|
|
37
|
+
} & MarkedLines & LanguageControl & Pick<CopyButtonProps, "copyLabel" | "copiedLabel" | "copyFailedLabel">;
|
|
2
38
|
/**
|
|
3
|
-
* Several lines of exact text to read or
|
|
39
|
+
* Several lines of exact text to read, copy or point at line by line.
|
|
4
40
|
*
|
|
5
41
|
* @family Data
|
|
6
|
-
* @when
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
42
|
+
* @when “Use `<CodeBlock>` for multi-line, syntax-highlighted source the reader will scan or paste.” (https://vercel.com/geist/code-block)
|
|
43
|
+
* Ours: several lines a person reads or copies exactly: a configuration, static JSON, a command
|
|
44
|
+
* sequence, a file with the lines under discussion marked. There is no syntax colour yet.
|
|
45
|
+
* @instead “For a single inline token (env var, function name, file path), use `Inline Code`.” (https://vercel.com/geist/code-block)
|
|
46
|
+
* “Pick `Snippet` for a copy-to-clipboard shell command or one-line key reveal; it ships with the prompt glyph and copy affordance built in.” (https://vercel.com/geist/code-block)
|
|
47
|
+
* Ours: a token inside a sentence is inline code. One short value to copy is `TextWithCopyButton`. A
|
|
48
|
+
* before and after to compute is `FileDiff`. Code in a conversation is Nadia's `MarkdownText`.
|
|
49
|
+
* @behaviour “Highlight only the lines under discussion. A block where every line is highlighted reads the same as no highlight at all.” (https://vercel.com/geist/code-block)
|
|
50
|
+
* “Mark added or removed lines with the `diff` syntax or the dedicated added/removed props. Faking them with `// added` comments breaks copy-paste.” (https://vercel.com/geist/code-block)
|
|
51
|
+
* “Show the filename header when the snippet has a paste destination (`app/page.tsx`, `vercel.json`). Omit it for ephemeral examples.” (https://vercel.com/geist/code-block)
|
|
52
|
+
* “You can link to lines. Just press on any line number.” (https://vercel.com/geist/code-block)
|
|
53
|
+
* “Use the `tabs` prop for a tabbed language switcher instead of the default select.” (https://vercel.com/geist/code-block)
|
|
54
|
+
* “Always pass a `language`/`syntax` (`tsx`, `bash`, `json`, `diff`). Highlighting is the primary reason to choose `<CodeBlock>` over a plain `<pre>`.” (https://vercel.com/geist/code-block)
|
|
55
|
+
* Ours: read-only, no wrapping, 20 px rows, each line numbered with a number that links to it. Colour
|
|
56
|
+
* sits on the row and its 2 px bar at the start, never on the text or the numbers:
|
|
57
|
+
* `highlightedLinesNumbers` (info), `addedLinesNumbers` (success) and `removedLinesNumbers`
|
|
58
|
+
* (destructive); a line carries one mark, and the line a link points at takes the warning fill. A
|
|
59
|
+
* mark is fill and bar with no glyph, announced by the line's name. `hideLineNumbers` is for a few
|
|
60
|
+
* lines where numbers add nothing. The header (40 px, muted fill, the file's icon and name) exists
|
|
61
|
+
* only with a `filename`, a `switcher` or `tabs`. `tabs` draw as a row above the header, a
|
|
62
|
+
* `switcher` (a select) sits in the header before the copy button; never both. In the header the
|
|
63
|
+
* filename and the copy mark are muted; without a header the copy button floats 15 px from the top
|
|
64
|
+
* right corner in the full text colour and shows while the block is hovered or something in it has
|
|
65
|
+
* focus (always on a touch screen). A line number links to its line for a pointer and is out of the
|
|
66
|
+
* tab order. The file icon follows the filename's extension. There is no syntax colour and no
|
|
67
|
+
* `language` until a highlighter is adopted, and no Open in v0 action.
|
|
68
|
+
* @words “Snippets stay runnable. Don’t paraphrase real code into pseudo-syntax, and don’t prepend `$` to shell commands. `<Snippet>` already renders the prompt, so `text="$ vercel deploy"` doubles to `$ $ vercel deploy`.” (https://vercel.com/geist/code-block)
|
|
69
|
+
* “Keep prose around the block in sentence case and put backticks around CLI flags inline (`` `--prebuilt` ``).” (https://vercel.com/geist/code-block)
|
|
70
|
+
* Ours: the real filename, or none. A switcher's `label` names what it switches (*Language*), and
|
|
71
|
+
* its options are the languages by their common names (*JSON*). `label` names the code (*MCP
|
|
72
|
+
* configuration*). `lineLabel` says a marked line and its mark in the catalogue's words (*Line 3,
|
|
73
|
+
* added*, *Riga 3, aggiunta*); it is only called for a highlighted, added or removed line.
|
|
74
|
+
* `copyLabel` names what is copied (*Copy mcp.json*); `copiedLabel` (*Copied*); `copyFailedLabel`
|
|
75
|
+
* (*Couldn't copy*). `label` and the three copy words are required, and `lineLabel` with any marked line.
|
|
76
|
+
* @access Ours: the code is a focusable, scrollable region named by `label`. Line numbers are hidden from
|
|
77
|
+
* assistive technology and are not tab stops; a highlighted, added or removed line carries
|
|
78
|
+
* `lineLabel`'s words as hidden text, with the numbers shown or not. The copy button names its
|
|
79
|
+
* target and announces the result.
|
|
16
80
|
*/
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
label: string;
|
|
20
|
-
filename?: string;
|
|
21
|
-
language?: string;
|
|
22
|
-
} & Pick<CopyButtonProps, "copyLabel" | "copiedLabel" | "copyFailedLabel">): import("react").JSX.Element;
|
|
81
|
+
declare function CodeBlock({ addedLinesNumbers, className, code, copiedLabel, copyFailedLabel, copyLabel, filename, hideLineNumbers, highlightedLinesNumbers, label, lineLabel, removedLinesNumbers, switcher, tabs, }: CodeBlockProps): import("react").JSX.Element;
|
|
82
|
+
export { CodeBlock, type CodeBlockProps };
|
|
23
83
|
//# sourceMappingURL=code-block.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-block.d.ts","sourceRoot":"","sources":["../../src/components/code-block.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"code-block.d.ts","sourceRoot":"","sources":["../../src/components/code-block.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAc5E,KAAK,WAAW,GAAG,aAAa,GAAG,OAAO,GAAG,SAAS,CAAC;AAGvD,KAAK,cAAc,GAAG;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC,CAAC;AAEF,KAAK,eAAe,GAChB;IAAE,QAAQ,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,GAC3D;IAAE,IAAI,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;AAEhE,oGAAoG;AACpG,KAAK,WAAW,GACZ;IACE,uBAAuB,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACxD,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAClD,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACpD,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,KAAK,MAAM,CAAC;CACzD,GACD;IACE,uBAAuB,CAAC,EAAE,SAAS,CAAC;IACpC,iBAAiB,CAAC,EAAE,SAAS,CAAC;IAC9B,mBAAmB,CAAC,EAAE,SAAS,CAAC;IAChC,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB,CAAC;AAEN,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,eAAe,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACvC,GAAG,WAAW,GACb,eAAe,GACf,IAAI,CAAC,eAAe,EAAE,WAAW,GAAG,aAAa,GAAG,iBAAiB,CAAC,CAAC;AAyDzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,iBAAS,SAAS,CAAC,EACjB,iBAAiB,EACjB,SAAS,EACT,IAAI,EACJ,WAAW,EACX,eAAe,EACf,SAAS,EACT,QAAQ,EACR,eAAuB,EACvB,uBAAuB,EACvB,KAAK,EACL,SAAS,EACT,mBAAmB,EACnB,QAAQ,EACR,IAAI,GACL,EAAE,cAAc,+BA4FhB;AAED,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,CAAC"}
|
|
@@ -1,22 +1,92 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useId } from "react";
|
|
3
4
|
import { CopyButton } from "./copy-button.js";
|
|
4
|
-
import {
|
|
5
|
+
import { FileTypeIcon } from "./file-type-icon.js";
|
|
6
|
+
import { MiddleTruncate } from "./middle-truncate.js";
|
|
7
|
+
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, } from "./select.js";
|
|
8
|
+
import { Tabs, TabsList, TabsTrigger } from "./tabs.js";
|
|
9
|
+
import { cn } from "../lib/utils.js";
|
|
10
|
+
const ROW = {
|
|
11
|
+
plain: "",
|
|
12
|
+
highlighted: "bg-info-soft shadow-[inset_2px_0_0_0_var(--info)]",
|
|
13
|
+
added: "bg-success-soft shadow-[inset_2px_0_0_0_var(--success)]",
|
|
14
|
+
removed: "bg-destructive-soft shadow-[inset_2px_0_0_0_var(--destructive)]",
|
|
15
|
+
};
|
|
16
|
+
const LINKED_ROW = "target:bg-warning-soft target:shadow-[inset_2px_0_0_0_var(--warning-soft-foreground)]";
|
|
17
|
+
const SHOWN_ON_HOVER = "nc-transition-opacity [@media(hover:hover)_and_(pointer:fine)]:opacity-0 group-hover/code-block:opacity-100 group-focus-within/code-block:opacity-100";
|
|
18
|
+
function LanguageSwitcher({ label, onChange, options, value }) {
|
|
19
|
+
return (_jsxs(Select, { value: value, onValueChange: (next) => {
|
|
20
|
+
if (next !== null)
|
|
21
|
+
onChange(next);
|
|
22
|
+
}, children: [_jsx(SelectTrigger, { "aria-label": label, size: "sm", className: "w-auto bg-transparent pr-2 pl-2 text-label-sm text-muted-foreground shadow-none hover:bg-accent focus-visible:shadow-[0_0_0_2px_var(--ring)] data-popup-open:bg-accent [&_svg]:size-4", children: _jsx(SelectValue, { children: options.find((option) => option.value === value)?.label }) }), _jsx(SelectContent, { children: _jsx(SelectGroup, { children: options.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) }) })] }));
|
|
23
|
+
}
|
|
24
|
+
function LanguageTabs({ label, onChange, options, value }) {
|
|
25
|
+
return (_jsx(Tabs, { value: value, onValueChange: (next) => onChange(String(next)), className: "min-w-0", children: _jsx(TabsList, { "aria-label": label, children: options.map((option) => (_jsx(TabsTrigger, { value: option.value, children: option.label }, option.value))) }) }));
|
|
26
|
+
}
|
|
5
27
|
/**
|
|
6
|
-
* Several lines of exact text to read or
|
|
28
|
+
* Several lines of exact text to read, copy or point at line by line.
|
|
7
29
|
*
|
|
8
30
|
* @family Data
|
|
9
|
-
* @when
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
31
|
+
* @when “Use `<CodeBlock>` for multi-line, syntax-highlighted source the reader will scan or paste.” (https://vercel.com/geist/code-block)
|
|
32
|
+
* Ours: several lines a person reads or copies exactly: a configuration, static JSON, a command
|
|
33
|
+
* sequence, a file with the lines under discussion marked. There is no syntax colour yet.
|
|
34
|
+
* @instead “For a single inline token (env var, function name, file path), use `Inline Code`.” (https://vercel.com/geist/code-block)
|
|
35
|
+
* “Pick `Snippet` for a copy-to-clipboard shell command or one-line key reveal; it ships with the prompt glyph and copy affordance built in.” (https://vercel.com/geist/code-block)
|
|
36
|
+
* Ours: a token inside a sentence is inline code. One short value to copy is `TextWithCopyButton`. A
|
|
37
|
+
* before and after to compute is `FileDiff`. Code in a conversation is Nadia's `MarkdownText`.
|
|
38
|
+
* @behaviour “Highlight only the lines under discussion. A block where every line is highlighted reads the same as no highlight at all.” (https://vercel.com/geist/code-block)
|
|
39
|
+
* “Mark added or removed lines with the `diff` syntax or the dedicated added/removed props. Faking them with `// added` comments breaks copy-paste.” (https://vercel.com/geist/code-block)
|
|
40
|
+
* “Show the filename header when the snippet has a paste destination (`app/page.tsx`, `vercel.json`). Omit it for ephemeral examples.” (https://vercel.com/geist/code-block)
|
|
41
|
+
* “You can link to lines. Just press on any line number.” (https://vercel.com/geist/code-block)
|
|
42
|
+
* “Use the `tabs` prop for a tabbed language switcher instead of the default select.” (https://vercel.com/geist/code-block)
|
|
43
|
+
* “Always pass a `language`/`syntax` (`tsx`, `bash`, `json`, `diff`). Highlighting is the primary reason to choose `<CodeBlock>` over a plain `<pre>`.” (https://vercel.com/geist/code-block)
|
|
44
|
+
* Ours: read-only, no wrapping, 20 px rows, each line numbered with a number that links to it. Colour
|
|
45
|
+
* sits on the row and its 2 px bar at the start, never on the text or the numbers:
|
|
46
|
+
* `highlightedLinesNumbers` (info), `addedLinesNumbers` (success) and `removedLinesNumbers`
|
|
47
|
+
* (destructive); a line carries one mark, and the line a link points at takes the warning fill. A
|
|
48
|
+
* mark is fill and bar with no glyph, announced by the line's name. `hideLineNumbers` is for a few
|
|
49
|
+
* lines where numbers add nothing. The header (40 px, muted fill, the file's icon and name) exists
|
|
50
|
+
* only with a `filename`, a `switcher` or `tabs`. `tabs` draw as a row above the header, a
|
|
51
|
+
* `switcher` (a select) sits in the header before the copy button; never both. In the header the
|
|
52
|
+
* filename and the copy mark are muted; without a header the copy button floats 15 px from the top
|
|
53
|
+
* right corner in the full text colour and shows while the block is hovered or something in it has
|
|
54
|
+
* focus (always on a touch screen). A line number links to its line for a pointer and is out of the
|
|
55
|
+
* tab order. The file icon follows the filename's extension. There is no syntax colour and no
|
|
56
|
+
* `language` until a highlighter is adopted, and no Open in v0 action.
|
|
57
|
+
* @words “Snippets stay runnable. Don’t paraphrase real code into pseudo-syntax, and don’t prepend `$` to shell commands. `<Snippet>` already renders the prompt, so `text="$ vercel deploy"` doubles to `$ $ vercel deploy`.” (https://vercel.com/geist/code-block)
|
|
58
|
+
* “Keep prose around the block in sentence case and put backticks around CLI flags inline (`` `--prebuilt` ``).” (https://vercel.com/geist/code-block)
|
|
59
|
+
* Ours: the real filename, or none. A switcher's `label` names what it switches (*Language*), and
|
|
60
|
+
* its options are the languages by their common names (*JSON*). `label` names the code (*MCP
|
|
61
|
+
* configuration*). `lineLabel` says a marked line and its mark in the catalogue's words (*Line 3,
|
|
62
|
+
* added*, *Riga 3, aggiunta*); it is only called for a highlighted, added or removed line.
|
|
63
|
+
* `copyLabel` names what is copied (*Copy mcp.json*); `copiedLabel` (*Copied*); `copyFailedLabel`
|
|
64
|
+
* (*Couldn't copy*). `label` and the three copy words are required, and `lineLabel` with any marked line.
|
|
65
|
+
* @access Ours: the code is a focusable, scrollable region named by `label`. Line numbers are hidden from
|
|
66
|
+
* assistive technology and are not tab stops; a highlighted, added or removed line carries
|
|
67
|
+
* `lineLabel`'s words as hidden text, with the numbers shown or not. The copy button names its
|
|
68
|
+
* target and announces the result.
|
|
19
69
|
*/
|
|
20
|
-
|
|
21
|
-
|
|
70
|
+
function CodeBlock({ addedLinesNumbers, className, code, copiedLabel, copyFailedLabel, copyLabel, filename, hideLineNumbers = false, highlightedLinesNumbers, label, lineLabel, removedLinesNumbers, switcher, tabs, }) {
|
|
71
|
+
const id = useId();
|
|
72
|
+
const lines = (code.endsWith("\n") ? code.slice(0, -1) : code).split("\n");
|
|
73
|
+
const added = new Set(addedLinesNumbers);
|
|
74
|
+
const removed = new Set(removedLinesNumbers);
|
|
75
|
+
const highlighted = new Set(highlightedLinesNumbers);
|
|
76
|
+
const gutterWidth = `calc(${Math.max(String(lines.length).length, 2)}ch + 1rem)`;
|
|
77
|
+
const hasHeader = filename !== undefined || switcher !== undefined || tabs !== undefined;
|
|
78
|
+
const copyButton = (_jsx(CopyButton, { value: code, copyLabel: copyLabel, copiedLabel: copiedLabel, copyFailedLabel: copyFailedLabel, size: "icon-sm" }));
|
|
79
|
+
return (_jsxs("div", { "data-slot": "code-block", className: cn("flex min-w-0 flex-col gap-3", className), children: [tabs ? _jsx(LanguageTabs, { ...tabs }) : null, _jsxs("div", { className: "group/code-block relative min-w-0 overflow-hidden rounded-md border border-border bg-background", children: [hasHeader ? (_jsxs("div", { className: "flex h-10 items-center gap-1 border-b border-border bg-muted pr-0.75 pl-4 text-label-sm text-muted-foreground", children: [_jsx("div", { className: "flex min-w-0 flex-1 items-center gap-2", children: filename === undefined ? null : (_jsxs(_Fragment, { children: [_jsx(FileTypeIcon, { path: filename }), _jsx(MiddleTruncate, { value: filename })] })) }), switcher ? _jsx(LanguageSwitcher, { ...switcher }) : null, copyButton] })) : (_jsx("div", { className: cn("absolute top-3.75 right-3.75 z-10 rounded-sm bg-muted ring-1 ring-border", SHOWN_ON_HOVER), children: copyButton })), _jsx("pre", { "aria-label": label, className: "max-h-96 overflow-auto py-4 font-label-mono-md text-label-mono-md", role: "region", tabIndex: 0, children: _jsx("code", { className: "block min-w-max", children: lines.map((text, index) => {
|
|
80
|
+
const line = index + 1;
|
|
81
|
+
const state = removed.has(line)
|
|
82
|
+
? "removed"
|
|
83
|
+
: added.has(line)
|
|
84
|
+
? "added"
|
|
85
|
+
: highlighted.has(line)
|
|
86
|
+
? "highlighted"
|
|
87
|
+
: "plain";
|
|
88
|
+
const anchor = `${id}-L${line}`;
|
|
89
|
+
return (_jsxs("span", { className: cn("flex px-4", ROW[state], LINKED_ROW), "data-state": state, id: anchor, children: [state === "plain" ? null : (_jsx("span", { className: "sr-only", children: lineLabel?.(line, state) })), hideLineNumbers ? null : (_jsx("a", { "aria-hidden": "true", className: "nc-transition-paint shrink-0 pr-4 text-right text-muted-foreground tabular-nums select-none hover:text-foreground", href: `#${anchor}`, style: { minWidth: gutterWidth }, tabIndex: -1, children: line })), _jsx("span", { className: "whitespace-pre", children: text || " " })] }, anchor));
|
|
90
|
+
}) }) })] })] }));
|
|
22
91
|
}
|
|
92
|
+
export { CodeBlock };
|