@devalok/shilp-sutra 0.34.1 → 0.36.0
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/LICENSE +21 -21
- package/dist/_chunks/badge-group.js +95 -95
- package/dist/_chunks/badge-group.js.map +1 -0
- package/dist/_chunks/chat.js +7 -2
- package/dist/_chunks/chat.js.map +1 -0
- package/dist/_chunks/date-picker.js.map +1 -0
- package/dist/_chunks/document-preview.js.map +1 -0
- package/dist/_chunks/file-preview.js.map +1 -0
- package/dist/_chunks/framer.js +62 -62
- package/dist/_chunks/framer.js.map +1 -0
- package/dist/_chunks/image-preview.js +1 -1
- package/dist/_chunks/image-preview.js.map +1 -0
- package/dist/_chunks/keybinding.js.map +1 -0
- package/dist/_chunks/link-context.js.map +1 -0
- package/dist/_chunks/mention-suggestion.js.map +1 -0
- package/dist/_chunks/motion-provider.js.map +1 -0
- package/dist/_chunks/popover.js +32 -36
- package/dist/_chunks/popover.js.map +1 -0
- package/dist/_chunks/primitives.js +686 -686
- package/dist/_chunks/primitives.js.map +1 -0
- package/dist/_chunks/rich-chat-input.js +650 -649
- package/dist/_chunks/rich-chat-input.js.map +1 -0
- package/dist/_chunks/shared.js.map +1 -0
- package/dist/_chunks/sonner.js.map +1 -0
- package/dist/_chunks/stat-row.js +158 -158
- package/dist/_chunks/stat-row.js.map +1 -0
- package/dist/_chunks/tiptap.js +11 -11
- package/dist/_chunks/tiptap.js.map +1 -0
- package/dist/_chunks/tree-view.js +1 -1
- package/dist/_chunks/tree-view.js.map +1 -0
- package/dist/_chunks/use-calendar.js.map +1 -0
- package/dist/_chunks/vendor-client.js +1 -1
- package/dist/_chunks/vendor-client.js.map +1 -0
- package/dist/_chunks/vendor-utils.js.map +1 -0
- package/dist/ai/ai-command-provider.js.map +1 -0
- package/dist/ai/block-renderer.js.map +1 -0
- package/dist/ai/blocks/loading.d.ts.map +1 -1
- package/dist/ai/command-bar.js.map +1 -0
- package/dist/ai/conversation.js +76 -76
- package/dist/ai/conversation.js.map +1 -0
- package/dist/ai/devadoot-icon.d.ts.map +1 -1
- package/dist/ai/index.js.map +1 -0
- package/dist/composed/activity-feed.js.map +1 -0
- package/dist/composed/avatar-group.js +1 -1
- package/dist/composed/avatar-group.js.map +1 -0
- package/dist/composed/bulk-action-bar.js +13 -21
- package/dist/composed/bulk-action-bar.js.map +1 -0
- package/dist/composed/command-palette.js.map +1 -0
- package/dist/composed/confirm-dialog.js.map +1 -0
- package/dist/composed/content-card.js.map +1 -0
- package/dist/composed/deadline-indicator.js.map +1 -0
- package/dist/composed/emoji-picker.js.map +1 -0
- package/dist/composed/empty-state.d.ts.map +1 -1
- package/dist/composed/empty-state.js +30 -30
- package/dist/composed/empty-state.js.map +1 -0
- package/dist/composed/error-boundary.js.map +1 -0
- package/dist/composed/filter-bar.js.map +1 -0
- package/dist/composed/form-section.js.map +1 -0
- package/dist/composed/global-loading.js.map +1 -0
- package/dist/composed/inline-edit.js.map +1 -0
- package/dist/composed/lib/string-utils.js.map +1 -0
- package/dist/composed/loading-skeleton.js.map +1 -0
- package/dist/composed/markdown-viewer.js.map +1 -0
- package/dist/composed/master-detail.js.map +1 -0
- package/dist/composed/member-picker.js.map +1 -0
- package/dist/composed/multi-select-popover.d.ts.map +1 -1
- package/dist/composed/multi-select-popover.js +4 -0
- package/dist/composed/multi-select-popover.js.map +1 -0
- package/dist/composed/page-header.js.map +1 -0
- package/dist/composed/page-skeletons.js.map +1 -0
- package/dist/composed/priority-indicator.js.map +1 -0
- package/dist/composed/responsive-overlay.js.map +1 -0
- package/dist/composed/rich-chat-input/attachment-strip.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/reply-banner.d.ts.map +1 -1
- package/dist/composed/rich-chat-input/schedule-send.d.ts.map +1 -1
- package/dist/composed/rich-chat-input.d.ts.map +1 -1
- package/dist/composed/rich-text-editor.js.map +1 -0
- package/dist/composed/schedule-view.js.map +1 -0
- package/dist/composed/simple-tooltip.js.map +1 -0
- package/dist/composed/status-badge.d.ts.map +1 -1
- package/dist/composed/status-badge.js.map +1 -0
- package/dist/hooks/use-color-mode.js.map +1 -0
- package/dist/hooks/use-mobile.js.map +1 -0
- package/dist/hooks/use-touch-device.js.map +1 -0
- package/dist/hooks/use-viewport-height.js.map +1 -0
- package/dist/motion/check-motion-provider.d.ts +3 -0
- package/dist/motion/check-motion-provider.d.ts.map +1 -0
- package/dist/motion/index.js +14 -0
- package/dist/motion/index.js.map +1 -0
- package/dist/motion/primitives-index.js.map +1 -0
- package/dist/primitives/react-accordion.d.ts +114 -114
- package/dist/primitives/react-alert-dialog.d.ts +51 -51
- package/dist/primitives/react-aspect-ratio.d.ts +11 -11
- package/dist/primitives/react-avatar.d.ts +24 -24
- package/dist/primitives/react-checkbox.d.ts +50 -50
- package/dist/primitives/react-collapsible.d.ts +33 -33
- package/dist/primitives/react-context-menu.d.ts +96 -96
- package/dist/primitives/react-dialog.d.ts +103 -103
- package/dist/primitives/react-dropdown-menu.d.ts +97 -97
- package/dist/primitives/react-hover-card.d.ts +79 -79
- package/dist/primitives/react-label.d.ts +10 -10
- package/dist/primitives/react-menu.d.ts +169 -169
- package/dist/primitives/react-menubar.d.ts +115 -115
- package/dist/primitives/react-navigation-menu.d.ts +126 -126
- package/dist/primitives/react-popover.d.ts +85 -85
- package/dist/primitives/react-progress.d.ts +19 -19
- package/dist/primitives/react-radio-group.d.ts +58 -58
- package/dist/primitives/react-roving-focus.d.ts +49 -49
- package/dist/primitives/react-select.d.ts +137 -137
- package/dist/primitives/react-separator.d.ts +21 -21
- package/dist/primitives/react-slider.d.ts +75 -75
- package/dist/primitives/react-switch.d.ts +21 -21
- package/dist/primitives/react-tabs.d.ts +56 -56
- package/dist/primitives/react-toast.d.ts +120 -120
- package/dist/primitives/react-toggle-group.d.ts +75 -75
- package/dist/primitives/react-toggle.d.ts +24 -24
- package/dist/primitives/react-tooltip.d.ts +101 -101
- package/dist/primitives/react-visually-hidden.d.ts +22 -22
- package/dist/shell/app-command-palette.d.ts +2 -0
- package/dist/shell/app-command-palette.d.ts.map +1 -1
- package/dist/shell/app-command-palette.js +42 -155
- package/dist/shell/app-command-palette.js.map +1 -0
- package/dist/shell/bottom-navbar.js +1 -1
- package/dist/shell/bottom-navbar.js.map +1 -0
- package/dist/shell/command-registry.js.map +1 -0
- package/dist/shell/notification-center.d.ts.map +1 -1
- package/dist/shell/notification-center.js +194 -169
- package/dist/shell/notification-center.js.map +1 -0
- package/dist/shell/notification-preferences.js.map +1 -0
- package/dist/shell/sidebar.js.map +1 -0
- package/dist/shell/top-bar.js +1 -1
- package/dist/shell/top-bar.js.map +1 -0
- package/dist/tailwind/index.cjs +48 -1
- package/dist/tailwind/preset.d.ts.map +1 -1
- package/dist/tailwind/preset.js +48 -1
- package/dist/tailwind/preset.js.map +1 -0
- package/dist/tokens/index.css +4 -4
- package/dist/tokens/primitives.css +442 -442
- package/dist/tokens/semantic.css +742 -547
- package/dist/tokens/typography-semantic.css +123 -100
- package/dist/tokens/typography.css +422 -422
- package/dist/ui/accordion.js +13 -13
- package/dist/ui/accordion.js.map +1 -0
- package/dist/ui/alert-dialog.d.ts +6 -2
- package/dist/ui/alert-dialog.d.ts.map +1 -1
- package/dist/ui/alert-dialog.js +43 -42
- package/dist/ui/alert-dialog.js.map +1 -0
- package/dist/ui/alert.d.ts +3 -2
- package/dist/ui/alert.d.ts.map +1 -1
- package/dist/ui/alert.js +31 -5
- package/dist/ui/alert.js.map +1 -0
- package/dist/ui/aspect-ratio.js +1 -1
- package/dist/ui/aspect-ratio.js.map +1 -0
- package/dist/ui/autocomplete.d.ts.map +1 -1
- package/dist/ui/autocomplete.js +92 -67
- package/dist/ui/autocomplete.js.map +1 -0
- package/dist/ui/avatar.js +9 -9
- package/dist/ui/avatar.js.map +1 -0
- package/dist/ui/badge-indicator.js.map +1 -0
- package/dist/ui/banner.js.map +1 -0
- package/dist/ui/breadcrumb.js +1 -1
- package/dist/ui/breadcrumb.js.map +1 -0
- package/dist/ui/button-group.js.map +1 -0
- package/dist/ui/button-processing.d.ts.map +1 -1
- package/dist/ui/button-processing.js +61 -40
- package/dist/ui/button-processing.js.map +1 -0
- package/dist/ui/button.js +8 -8
- package/dist/ui/button.js.map +1 -0
- package/dist/ui/card.js.map +1 -0
- package/dist/ui/charts/bar-chart.d.ts.map +1 -1
- package/dist/ui/charts/chart-container.d.ts +2 -0
- package/dist/ui/charts/chart-container.d.ts.map +1 -1
- package/dist/ui/charts/index.js +88 -65
- package/dist/ui/charts/index.js.map +1 -0
- package/dist/ui/charts/line-chart.d.ts.map +1 -1
- package/dist/ui/chat/message-input.d.ts.map +1 -1
- package/dist/ui/chat/message-list.d.ts +1 -1
- package/dist/ui/chat/message-list.d.ts.map +1 -1
- package/dist/ui/chat/message.d.ts.map +1 -1
- package/dist/ui/chat/system-message.d.ts.map +1 -1
- package/dist/ui/checkbox.d.ts.map +1 -1
- package/dist/ui/checkbox.js +33 -28
- package/dist/ui/checkbox.js.map +1 -0
- package/dist/ui/code.js.map +1 -0
- package/dist/ui/collapsible.js +1 -1
- package/dist/ui/collapsible.js.map +1 -0
- package/dist/ui/color-input.d.ts.map +1 -1
- package/dist/ui/color-input.js +165 -163
- package/dist/ui/color-input.js.map +1 -0
- package/dist/ui/color-swatch.js.map +1 -0
- package/dist/ui/combobox.d.ts +7 -0
- package/dist/ui/combobox.d.ts.map +1 -1
- package/dist/ui/combobox.js +147 -113
- package/dist/ui/combobox.js.map +1 -0
- package/dist/ui/container.js +1 -1
- package/dist/ui/container.js.map +1 -0
- package/dist/ui/context-menu.js.map +1 -0
- package/dist/ui/data-table-body.js.map +1 -0
- package/dist/ui/data-table-bulk-actions.js +1 -1
- package/dist/ui/data-table-bulk-actions.js.map +1 -0
- package/dist/ui/data-table-card.js.map +1 -0
- package/dist/ui/data-table-context.js.map +1 -0
- package/dist/ui/data-table-header.js.map +1 -0
- package/dist/ui/data-table-pagination.js.map +1 -0
- package/dist/ui/data-table-toolbar.js.map +1 -0
- package/dist/ui/data-table.js +34 -31
- package/dist/ui/data-table.js.map +1 -0
- package/dist/ui/devalok-grain.js.map +1 -0
- package/dist/ui/dialog.js +31 -35
- package/dist/ui/dialog.js.map +1 -0
- package/dist/ui/dropdown-menu.js.map +1 -0
- package/dist/ui/file-upload.js +120 -120
- package/dist/ui/file-upload.js.map +1 -0
- package/dist/ui/form.d.ts +8 -0
- package/dist/ui/form.d.ts.map +1 -1
- package/dist/ui/form.js +14 -12
- package/dist/ui/form.js.map +1 -0
- package/dist/ui/hover-card.js.map +1 -0
- package/dist/ui/icon-button.js.map +1 -0
- package/dist/ui/icon-context.js.map +1 -0
- package/dist/ui/icon-group.js.map +1 -0
- package/dist/ui/icon.js.map +1 -0
- package/dist/ui/index.d.ts +4 -4
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +82 -66
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/input-otp.d.ts +12 -3
- package/dist/ui/input-otp.d.ts.map +1 -1
- package/dist/ui/input-otp.js +41 -27
- package/dist/ui/input-otp.js.map +1 -0
- package/dist/ui/input.d.ts.map +1 -1
- package/dist/ui/input.js +16 -15
- package/dist/ui/input.js.map +1 -0
- package/dist/ui/label.d.ts.map +1 -1
- package/dist/ui/label.js +19 -14
- package/dist/ui/label.js.map +1 -0
- package/dist/ui/lib/check-tokens.d.ts +3 -0
- package/dist/ui/lib/check-tokens.d.ts.map +1 -0
- package/dist/ui/lib/date-utils.js.map +1 -0
- package/dist/ui/lib/motion.d.ts +15 -4
- package/dist/ui/lib/motion.d.ts.map +1 -1
- package/dist/ui/lib/motion.js +18 -9
- package/dist/ui/lib/motion.js.map +1 -0
- package/dist/ui/lib/utils.js.map +1 -0
- package/dist/ui/link.js +2 -2
- package/dist/ui/link.js.map +1 -0
- package/dist/ui/menubar.js.map +1 -0
- package/dist/ui/navigation-menu.js.map +1 -0
- package/dist/ui/number-input.d.ts +16 -1
- package/dist/ui/number-input.d.ts.map +1 -1
- package/dist/ui/number-input.js +79 -49
- package/dist/ui/number-input.js.map +1 -0
- package/dist/ui/pagination.js +1 -1
- package/dist/ui/pagination.js.map +1 -0
- package/dist/ui/progress-ring.d.ts.map +1 -1
- package/dist/ui/progress-ring.js.map +1 -0
- package/dist/ui/progress.js.map +1 -0
- package/dist/ui/radio.d.ts.map +1 -1
- package/dist/ui/radio.js +27 -20
- package/dist/ui/radio.js.map +1 -0
- package/dist/ui/search-input.js.map +1 -0
- package/dist/ui/segmented-control.d.ts +1 -1
- package/dist/ui/segmented-control.d.ts.map +1 -1
- package/dist/ui/segmented-control.js +2 -0
- package/dist/ui/segmented-control.js.map +1 -0
- package/dist/ui/select.d.ts.map +1 -1
- package/dist/ui/select.js +54 -48
- package/dist/ui/select.js.map +1 -0
- package/dist/ui/separator.d.ts.map +1 -1
- package/dist/ui/separator.js +10 -7
- package/dist/ui/separator.js.map +1 -0
- package/dist/ui/sheet.js +29 -29
- package/dist/ui/sheet.js.map +1 -0
- package/dist/ui/sidebar.js +7 -7
- package/dist/ui/sidebar.js.map +1 -0
- package/dist/ui/skeleton.js.map +1 -0
- package/dist/ui/slider.d.ts +22 -3
- package/dist/ui/slider.d.ts.map +1 -1
- package/dist/ui/slider.js +57 -19
- package/dist/ui/slider.js.map +1 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/ui/split-button.d.ts.map +1 -1
- package/dist/ui/split-button.js +77 -76
- package/dist/ui/split-button.js.map +1 -0
- package/dist/ui/stack.js.map +1 -0
- package/dist/ui/stat-card.js.map +1 -0
- package/dist/ui/status-dot.js.map +1 -0
- package/dist/ui/stepper.d.ts +10 -0
- package/dist/ui/stepper.d.ts.map +1 -1
- package/dist/ui/stepper.js +80 -75
- package/dist/ui/stepper.js.map +1 -0
- package/dist/ui/switch.d.ts.map +1 -1
- package/dist/ui/switch.js +26 -22
- package/dist/ui/switch.js.map +1 -0
- package/dist/ui/table.js.map +1 -0
- package/dist/ui/tabs.d.ts +3 -1
- package/dist/ui/tabs.d.ts.map +1 -1
- package/dist/ui/tabs.js +68 -48
- package/dist/ui/tabs.js.map +1 -0
- package/dist/ui/text.d.ts +1 -1
- package/dist/ui/text.d.ts.map +1 -1
- package/dist/ui/text.js +10 -2
- package/dist/ui/text.js.map +1 -0
- package/dist/ui/textarea.js +1 -1
- package/dist/ui/textarea.js.map +1 -0
- package/dist/ui/toast-registry.d.ts +8 -0
- package/dist/ui/toast-registry.d.ts.map +1 -0
- package/dist/ui/toast-registry.js +13 -0
- package/dist/ui/toast-registry.js.map +1 -0
- package/dist/ui/toast.d.ts.map +1 -1
- package/dist/ui/toast.js +141 -136
- package/dist/ui/toast.js.map +1 -0
- package/dist/ui/toaster.d.ts.map +1 -1
- package/dist/ui/toaster.js +15 -14
- package/dist/ui/toaster.js.map +1 -0
- package/dist/ui/toggle-group.d.ts +2 -0
- package/dist/ui/toggle-group.d.ts.map +1 -1
- package/dist/ui/toggle-group.js +23 -16
- package/dist/ui/toggle-group.js.map +1 -0
- package/dist/ui/toggle.d.ts +2 -0
- package/dist/ui/toggle.d.ts.map +1 -1
- package/dist/ui/toggle.js +14 -6
- package/dist/ui/toggle.js.map +1 -0
- package/dist/ui/tooltip.js.map +1 -0
- package/dist/ui/visually-hidden.js.map +1 -0
- package/docs/components/_header.md +85 -85
- package/docs/components/composed/activity-feed.md +62 -62
- package/docs/components/composed/avatar-group.md +65 -65
- package/docs/components/composed/bulk-action-bar.md +40 -40
- package/docs/components/composed/command-palette.md +40 -40
- package/docs/components/composed/confirm-dialog.md +46 -46
- package/docs/components/composed/content-card.md +36 -36
- package/docs/components/composed/date-picker.md +130 -130
- package/docs/components/composed/deadline-indicator.md +27 -27
- package/docs/components/composed/emoji-picker.md +52 -52
- package/docs/components/composed/empty-state.md +53 -53
- package/docs/components/composed/error-boundary.md +29 -29
- package/docs/components/composed/file-preview.md +40 -40
- package/docs/components/composed/filter-bar.md +57 -57
- package/docs/components/composed/form-section.md +31 -31
- package/docs/components/composed/global-loading.md +27 -27
- package/docs/components/composed/inline-edit.md +35 -35
- package/docs/components/composed/loading-skeleton.md +51 -51
- package/docs/components/composed/markdown-viewer.md +27 -27
- package/docs/components/composed/master-detail.md +48 -48
- package/docs/components/composed/member-picker.md +35 -35
- package/docs/components/composed/multi-select-popover.md +62 -62
- package/docs/components/composed/page-header.md +41 -41
- package/docs/components/composed/page-skeletons.md +32 -32
- package/docs/components/composed/priority-indicator.md +32 -32
- package/docs/components/composed/responsive-overlay.md +34 -34
- package/docs/components/composed/rich-text-editor.md +82 -82
- package/docs/components/composed/schedule-view.md +39 -39
- package/docs/components/composed/simple-tooltip.md +33 -33
- package/docs/components/composed/status-badge.md +55 -55
- package/docs/components/shell/app-command-palette.md +44 -44
- package/docs/components/shell/bottom-navbar.md +52 -52
- package/docs/components/shell/command-registry.md +48 -48
- package/docs/components/shell/link-context.md +41 -41
- package/docs/components/shell/notification-center.md +63 -63
- package/docs/components/shell/notification-preferences.md +42 -42
- package/docs/components/shell/sidebar.md +92 -92
- package/docs/components/shell/top-bar.md +143 -143
- package/docs/components/ui/accordion.md +51 -51
- package/docs/components/ui/alert-dialog.md +61 -61
- package/docs/components/ui/alert.md +46 -46
- package/docs/components/ui/aspect-ratio.md +25 -25
- package/docs/components/ui/autocomplete.md +48 -48
- package/docs/components/ui/avatar.md +56 -56
- package/docs/components/ui/badge.md +83 -82
- package/docs/components/ui/banner.md +42 -42
- package/docs/components/ui/breadcrumb.md +37 -37
- package/docs/components/ui/button-group.md +41 -41
- package/docs/components/ui/button.md +94 -93
- package/docs/components/ui/card.md +52 -52
- package/docs/components/ui/charts.md +43 -43
- package/docs/components/ui/checkbox.md +36 -36
- package/docs/components/ui/chip.md +47 -47
- package/docs/components/ui/code.md +28 -28
- package/docs/components/ui/collapsible.md +40 -40
- package/docs/components/ui/color-input.md +91 -91
- package/docs/components/ui/color-swatch.md +25 -25
- package/docs/components/ui/combobox.md +54 -54
- package/docs/components/ui/container.md +26 -26
- package/docs/components/ui/context-menu.md +43 -43
- package/docs/components/ui/data-table-body.md +1 -1
- package/docs/components/ui/data-table-bulk-actions.md +1 -1
- package/docs/components/ui/data-table-card.md +1 -1
- package/docs/components/ui/data-table-context.md +1 -1
- package/docs/components/ui/data-table-header.md +1 -1
- package/docs/components/ui/data-table-pagination.md +1 -1
- package/docs/components/ui/data-table-toolbar.md +44 -44
- package/docs/components/ui/data-table.md +94 -94
- package/docs/components/ui/dialog.md +54 -54
- package/docs/components/ui/dropdown-menu.md +48 -48
- package/docs/components/ui/file-upload.md +41 -41
- package/docs/components/ui/form.md +51 -51
- package/docs/components/ui/hover-card.md +32 -32
- package/docs/components/ui/icon-button.md +40 -40
- package/docs/components/ui/input-otp.md +44 -44
- package/docs/components/ui/input.md +74 -74
- package/docs/components/ui/label.md +25 -25
- package/docs/components/ui/link.md +29 -29
- package/docs/components/ui/menubar.md +44 -44
- package/docs/components/ui/navigation-menu.md +46 -46
- package/docs/components/ui/number-input.md +44 -44
- package/docs/components/ui/pagination.md +48 -48
- package/docs/components/ui/popover.md +30 -30
- package/docs/components/ui/progress-ring.md +41 -41
- package/docs/components/ui/progress.md +34 -34
- package/docs/components/ui/radio.md +34 -34
- package/docs/components/ui/search-input.md +43 -43
- package/docs/components/ui/segmented-control.md +50 -50
- package/docs/components/ui/select.md +53 -53
- package/docs/components/ui/separator.md +32 -32
- package/docs/components/ui/sheet.md +47 -47
- package/docs/components/ui/sidebar.md +72 -72
- package/docs/components/ui/skeleton.md +77 -77
- package/docs/components/ui/slider.md +29 -29
- package/docs/components/ui/spinner.md +54 -54
- package/docs/components/ui/stack.md +39 -39
- package/docs/components/ui/stat-card.md +61 -61
- package/docs/components/ui/status-dot.md +26 -26
- package/docs/components/ui/stepper.md +49 -49
- package/docs/components/ui/switch.md +47 -47
- package/docs/components/ui/table.md +47 -47
- package/docs/components/ui/tabs.md +60 -60
- package/docs/components/ui/text.md +37 -37
- package/docs/components/ui/textarea.md +39 -39
- package/docs/components/ui/toast.md +65 -65
- package/docs/components/ui/toaster.md +47 -47
- package/docs/components/ui/toggle-group.md +43 -43
- package/docs/components/ui/toggle.md +37 -37
- package/docs/components/ui/tooltip.md +38 -38
- package/docs/components/ui/tree-view.md +65 -65
- package/docs/components/ui/visually-hidden.md +21 -21
- package/llms-full.txt +5266 -5264
- package/llms.txt +624 -580
- package/package.json +7 -8
package/dist/ui/combobox.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { VariantProps } from 'class-variance-authority';
|
|
2
3
|
import * as React from 'react';
|
|
4
|
+
export declare const comboboxTriggerVariants: (props?: ({
|
|
5
|
+
size?: "xs" | "sm" | "md" | "lg" | null | undefined;
|
|
6
|
+
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|
|
7
|
+
export type ComboboxSize = NonNullable<VariantProps<typeof comboboxTriggerVariants>['size']>;
|
|
3
8
|
/**
|
|
4
9
|
* Option shape for a Combobox dropdown item.
|
|
5
10
|
* `value` must be unique across all options — it is the key used in selection state.
|
|
@@ -75,6 +80,8 @@ interface ComboboxBaseProps extends Omit<React.HTMLAttributes<HTMLDivElement>, '
|
|
|
75
80
|
renderOption?: (option: ComboboxOption, selected: boolean) => React.ReactNode;
|
|
76
81
|
/** Accessible label for the trigger button. Falls back to `placeholder` if not provided. */
|
|
77
82
|
accessibleLabel?: string;
|
|
83
|
+
/** Size of the trigger. Controls height, text size, padding, and pill sizing. */
|
|
84
|
+
size?: ComboboxSize;
|
|
78
85
|
}
|
|
79
86
|
interface ComboboxSingleProps extends ComboboxBaseProps {
|
|
80
87
|
multiple?: false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../src/ui/combobox.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"combobox.d.ts","sourceRoot":"","sources":["../../src/ui/combobox.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAG9B,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AASjE,eAAO,MAAM,uBAAuB;;8EAmBnC,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,YAAY,CAAC,OAAO,uBAAuB,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;AA0B5F;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,UAAU,iBAAkB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IACxF,+CAA+C;IAC/C,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,4DAA4D;IAC5D,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,oGAAoG;IACpG,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,OAAO,KAAK,KAAK,CAAC,SAAS,CAAA;IAC7E,4FAA4F;IAC5F,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,iFAAiF;IACjF,IAAI,CAAC,EAAE,YAAY,CAAA;CACpB;AAED,UAAU,mBAAoB,SAAQ,iBAAiB;IACrD,QAAQ,CAAC,EAAE,KAAK,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACvC;AAED,UAAU,qBAAsB,SAAQ,iBAAiB;IACvD,QAAQ,EAAE,IAAI,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAA;CACzC;AAED,MAAM,MAAM,aAAa,GAAG,mBAAmB,GAAG,qBAAqB,CAAA;AAQvE,QAAA,MAAM,QAAQ,yFA+Yb,CAAA;AAGD,OAAO,EAAE,QAAQ,EAAE,CAAA"}
|
package/dist/ui/combobox.js
CHANGED
|
@@ -2,104 +2,135 @@
|
|
|
2
2
|
import { Jt as e, Kt as t, Yt as n, qt as r } from "../_chunks/primitives.js";
|
|
3
3
|
import { a as i } from "../_chunks/framer.js";
|
|
4
4
|
import { springs as a, tweens as o } from "./lib/motion.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
5
|
+
import { t as s } from "../_chunks/vendor-utils.js";
|
|
6
|
+
import { cn as c } from "./lib/utils.js";
|
|
7
|
+
import { Icon as l } from "./icon.js";
|
|
8
|
+
import { useFormField as u } from "./form.js";
|
|
9
|
+
import * as d from "react";
|
|
10
|
+
import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
|
|
11
|
+
import { IconCheck as h, IconChevronDown as ee, IconSearch as te, IconX as g } from "@tabler/icons-react";
|
|
10
12
|
//#region src/ui/combobox.tsx
|
|
11
|
-
var _ =
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
var _ = s([
|
|
14
|
+
"flex w-full items-center justify-between whitespace-nowrap rounded-ds-md",
|
|
15
|
+
"border border-surface-border-strong bg-surface-raised-hover",
|
|
16
|
+
"transition-colors duration-fast-01 ease-productive-standard",
|
|
17
|
+
"focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 focus-visible:border-accent-7",
|
|
18
|
+
"disabled:cursor-not-allowed disabled:opacity-action-disabled"
|
|
19
|
+
], {
|
|
20
|
+
variants: { size: {
|
|
21
|
+
xs: "h-ds-xs-plus text-ds-sm px-ds-02",
|
|
22
|
+
sm: "h-ds-sm text-ds-sm px-ds-03",
|
|
23
|
+
md: "h-ds-md text-ds-md px-ds-04",
|
|
24
|
+
lg: "h-ds-lg text-ds-md px-ds-05"
|
|
25
|
+
} },
|
|
26
|
+
defaultVariants: { size: "md" }
|
|
27
|
+
}), v = {
|
|
28
|
+
xs: "xs",
|
|
29
|
+
sm: "sm",
|
|
30
|
+
md: "sm",
|
|
31
|
+
lg: "md"
|
|
32
|
+
}, y = {
|
|
33
|
+
xs: "px-ds-02 py-0 text-ds-xs",
|
|
34
|
+
sm: "px-ds-02 py-0 text-ds-xs",
|
|
35
|
+
md: "px-ds-03 py-[1px] text-ds-sm",
|
|
36
|
+
lg: "px-ds-03 py-[2px] text-ds-sm"
|
|
37
|
+
}, b = {
|
|
38
|
+
xs: "text-ds-xs",
|
|
39
|
+
sm: "text-ds-xs",
|
|
40
|
+
md: "text-ds-sm",
|
|
41
|
+
lg: "text-ds-sm"
|
|
42
|
+
}, x = 2, S = 36, C = d.forwardRef(({ options: s, value: C, onValueChange: w, placeholder: T = "Select...", searchPlaceholder: E = "Search...", emptyMessage: D = "No results found", multiple: O = !1, disabled: k = !1, className: ne, triggerClassName: re, maxVisible: ie = 6, renderOption: A, accessibleLabel: j, size: M = "md", ...N }, P) => {
|
|
43
|
+
let F = M ?? "md", [I, L] = d.useState(!1), [R, z] = d.useState(""), [B, V] = d.useState(-1), H = d.useRef(null), U = d.useRef(null), W = d.useId(), G = d.useId(), K = d.useMemo(() => C == null ? [] : Array.isArray(C) ? C : [C], [C]), q = d.useMemo(() => R ? s.filter((e) => e.label.toLowerCase().includes(R.toLowerCase())) : s, [s, R]), J = d.useCallback((e) => K.includes(e), [K]), Y = d.useCallback((e) => {
|
|
44
|
+
O ? w(K.includes(e) ? K.filter((t) => t !== e) : [...K, e]) : (w(e), L(!1));
|
|
14
45
|
}, [
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
]),
|
|
19
|
-
e.stopPropagation(), e.preventDefault(),
|
|
20
|
-
}, [
|
|
21
|
-
|
|
22
|
-
}, [
|
|
23
|
-
|
|
24
|
-
if (
|
|
46
|
+
O,
|
|
47
|
+
K,
|
|
48
|
+
w
|
|
49
|
+
]), ae = d.useCallback((e, t) => {
|
|
50
|
+
e.stopPropagation(), e.preventDefault(), w(K.filter((e) => e !== t));
|
|
51
|
+
}, [K, w]), oe = d.useCallback((e) => {
|
|
52
|
+
k || (L(e), e || (z(""), V(-1)));
|
|
53
|
+
}, [k]);
|
|
54
|
+
d.useEffect(() => {
|
|
55
|
+
if (I) {
|
|
25
56
|
let e = setTimeout(() => {
|
|
26
|
-
|
|
57
|
+
H.current?.focus();
|
|
27
58
|
}, 0);
|
|
28
59
|
return () => clearTimeout(e);
|
|
29
60
|
}
|
|
30
|
-
}, [
|
|
31
|
-
let X =
|
|
32
|
-
let n =
|
|
61
|
+
}, [I]);
|
|
62
|
+
let X = d.useCallback((e, t) => {
|
|
63
|
+
let n = q.length;
|
|
33
64
|
if (n === 0) return -1;
|
|
34
65
|
let r = e + t;
|
|
35
66
|
for (; r >= 0 && r < n;) {
|
|
36
|
-
if (!
|
|
67
|
+
if (!q[r].disabled) return r;
|
|
37
68
|
r += t;
|
|
38
69
|
}
|
|
39
70
|
return e;
|
|
40
|
-
}, [
|
|
71
|
+
}, [q]), se = d.useCallback((e) => {
|
|
41
72
|
switch (e.key) {
|
|
42
73
|
case "ArrowDown":
|
|
43
|
-
e.preventDefault(),
|
|
74
|
+
e.preventDefault(), V(X(B, 1));
|
|
44
75
|
break;
|
|
45
76
|
case "ArrowUp":
|
|
46
|
-
e.preventDefault(),
|
|
77
|
+
e.preventDefault(), V(X(B, -1));
|
|
47
78
|
break;
|
|
48
79
|
case "Home":
|
|
49
|
-
e.preventDefault(),
|
|
80
|
+
e.preventDefault(), V(q.findIndex((e) => !e.disabled));
|
|
50
81
|
break;
|
|
51
82
|
case "End": {
|
|
52
83
|
e.preventDefault();
|
|
53
84
|
let t = -1;
|
|
54
|
-
for (let e =
|
|
85
|
+
for (let e = q.length - 1; e >= 0; e--) if (!q[e].disabled) {
|
|
55
86
|
t = e;
|
|
56
87
|
break;
|
|
57
88
|
}
|
|
58
|
-
|
|
89
|
+
V(t);
|
|
59
90
|
break;
|
|
60
91
|
}
|
|
61
92
|
case "Enter":
|
|
62
|
-
e.preventDefault(),
|
|
93
|
+
e.preventDefault(), B >= 0 && B < q.length && !q[B].disabled && Y(q[B].value);
|
|
63
94
|
break;
|
|
64
95
|
case "Escape":
|
|
65
|
-
e.preventDefault(),
|
|
96
|
+
e.preventDefault(), L(!1), z(""), V(-1);
|
|
66
97
|
break;
|
|
67
98
|
}
|
|
68
99
|
}, [
|
|
69
|
-
|
|
70
|
-
|
|
100
|
+
B,
|
|
101
|
+
q,
|
|
71
102
|
X,
|
|
72
|
-
|
|
103
|
+
Y
|
|
73
104
|
]);
|
|
74
|
-
|
|
75
|
-
if (
|
|
76
|
-
let e =
|
|
105
|
+
d.useEffect(() => {
|
|
106
|
+
if (B >= 0 && U.current) {
|
|
107
|
+
let e = U.current.children[B];
|
|
77
108
|
e && e.scrollIntoView?.({ block: "nearest" });
|
|
78
109
|
}
|
|
79
|
-
}, [
|
|
80
|
-
let
|
|
81
|
-
if (
|
|
82
|
-
let e =
|
|
83
|
-
return /* @__PURE__ */
|
|
110
|
+
}, [B]);
|
|
111
|
+
let ce = d.useCallback(() => K.length === 0 ? null : s.find((e) => e.value === K[0])?.label ?? null, [K, s]), Z = v[F], le = y[F], ue = b[F], Q = () => {
|
|
112
|
+
if (O && K.length > 0) {
|
|
113
|
+
let e = K.slice(0, x), t = K.length - x;
|
|
114
|
+
return /* @__PURE__ */ m("span", {
|
|
84
115
|
className: "flex flex-1 flex-wrap items-center gap-ds-02 overflow-hidden",
|
|
85
116
|
children: [e.map((e) => {
|
|
86
|
-
let t =
|
|
87
|
-
return t ? /* @__PURE__ */
|
|
88
|
-
className: "inline-flex items-center gap-ds-01 rounded-ds-md bg-accent-2
|
|
89
|
-
children: [t.label, /* @__PURE__ */
|
|
117
|
+
let t = s.find((t) => t.value === e);
|
|
118
|
+
return t ? /* @__PURE__ */ m("span", {
|
|
119
|
+
className: c("inline-flex items-center gap-ds-01 rounded-ds-md bg-accent-2", le),
|
|
120
|
+
children: [t.label, /* @__PURE__ */ p("button", {
|
|
90
121
|
type: "button",
|
|
91
122
|
className: "inline-flex items-center justify-center rounded-ds-full outline-hidden hover:scale-110 hover:bg-surface-raised-hover transition-transform duration-fast-01 ease-productive-standard",
|
|
92
|
-
onClick: (t) =>
|
|
123
|
+
onClick: (t) => ae(t, e),
|
|
93
124
|
"aria-label": `Remove ${t.label}`,
|
|
94
125
|
tabIndex: -1,
|
|
95
|
-
children: /* @__PURE__ */
|
|
126
|
+
children: /* @__PURE__ */ p(l, {
|
|
96
127
|
icon: g,
|
|
97
|
-
size:
|
|
128
|
+
size: Z
|
|
98
129
|
})
|
|
99
130
|
})]
|
|
100
131
|
}, e) : null;
|
|
101
|
-
}), t > 0 && /* @__PURE__ */
|
|
102
|
-
className: "text-
|
|
132
|
+
}), t > 0 && /* @__PURE__ */ m("span", {
|
|
133
|
+
className: c("text-surface-fg-muted", ue),
|
|
103
134
|
children: [
|
|
104
135
|
"+",
|
|
105
136
|
t,
|
|
@@ -108,51 +139,54 @@ var _ = 2, v = 36, y = l.forwardRef(({ options: y, value: b, onValueChange: x, p
|
|
|
108
139
|
})]
|
|
109
140
|
});
|
|
110
141
|
}
|
|
111
|
-
if (!
|
|
112
|
-
let e =
|
|
113
|
-
if (e) return /* @__PURE__ */
|
|
142
|
+
if (!O && K.length === 1) {
|
|
143
|
+
let e = ce();
|
|
144
|
+
if (e) return /* @__PURE__ */ p("span", {
|
|
114
145
|
className: "flex-1 truncate text-left",
|
|
115
146
|
children: e
|
|
116
147
|
});
|
|
117
148
|
}
|
|
118
|
-
return /* @__PURE__ */
|
|
149
|
+
return /* @__PURE__ */ p("span", {
|
|
119
150
|
className: "flex-1 truncate text-left text-surface-fg-subtle",
|
|
120
|
-
children:
|
|
151
|
+
children: T
|
|
121
152
|
});
|
|
122
|
-
};
|
|
123
|
-
return /* @__PURE__ */
|
|
124
|
-
open:
|
|
125
|
-
onOpenChange:
|
|
126
|
-
children: /* @__PURE__ */
|
|
127
|
-
className:
|
|
128
|
-
...
|
|
129
|
-
children: [/* @__PURE__ */
|
|
153
|
+
}, $ = u(), de = $.state === "error", fe = $.helperTextId, pe = $.required;
|
|
154
|
+
return /* @__PURE__ */ p(e, {
|
|
155
|
+
open: I,
|
|
156
|
+
onOpenChange: oe,
|
|
157
|
+
children: /* @__PURE__ */ m("div", {
|
|
158
|
+
className: c("relative", ne),
|
|
159
|
+
...N,
|
|
160
|
+
children: [/* @__PURE__ */ p(n, {
|
|
130
161
|
asChild: !0,
|
|
131
|
-
disabled:
|
|
132
|
-
children: /* @__PURE__ */
|
|
133
|
-
ref:
|
|
162
|
+
disabled: k,
|
|
163
|
+
children: /* @__PURE__ */ m("button", {
|
|
164
|
+
ref: P,
|
|
134
165
|
type: "button",
|
|
135
166
|
role: "combobox",
|
|
136
|
-
"aria-expanded":
|
|
137
|
-
"aria-controls":
|
|
167
|
+
"aria-expanded": I,
|
|
168
|
+
"aria-controls": G,
|
|
138
169
|
"aria-haspopup": "listbox",
|
|
139
|
-
"aria-label": j ??
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
170
|
+
"aria-label": j ?? T,
|
|
171
|
+
"aria-invalid": de || void 0,
|
|
172
|
+
"aria-describedby": fe,
|
|
173
|
+
"aria-required": pe || void 0,
|
|
174
|
+
disabled: k,
|
|
175
|
+
className: c(_({ size: F }), I && "border-accent-7", re),
|
|
176
|
+
children: [Q(), /* @__PURE__ */ p(l, {
|
|
177
|
+
icon: ee,
|
|
178
|
+
size: Z,
|
|
179
|
+
className: c("ml-ds-02 shrink-0 opacity-50 transition-transform duration-fast-01 ease-productive-standard", I && "rotate-180")
|
|
146
180
|
})]
|
|
147
181
|
})
|
|
148
|
-
}), /* @__PURE__ */
|
|
182
|
+
}), /* @__PURE__ */ p(r, { children: /* @__PURE__ */ p(t, {
|
|
149
183
|
asChild: !0,
|
|
150
184
|
sideOffset: 4,
|
|
151
185
|
align: "start",
|
|
152
186
|
onOpenAutoFocus: (e) => {
|
|
153
|
-
e.preventDefault(),
|
|
187
|
+
e.preventDefault(), H.current?.focus();
|
|
154
188
|
},
|
|
155
|
-
children: /* @__PURE__ */
|
|
189
|
+
children: /* @__PURE__ */ m(i.div, {
|
|
156
190
|
initial: {
|
|
157
191
|
opacity: 0,
|
|
158
192
|
scale: .95
|
|
@@ -165,69 +199,69 @@ var _ = 2, v = 36, y = l.forwardRef(({ options: y, value: b, onValueChange: x, p
|
|
|
165
199
|
...a.snappy,
|
|
166
200
|
opacity: o.fade
|
|
167
201
|
},
|
|
168
|
-
className:
|
|
169
|
-
children: [/* @__PURE__ */
|
|
202
|
+
className: c("z-popover w-[var(--radix-popover-trigger-width)] overflow-hidden rounded-ds-lg border border-surface-border bg-surface-overlay shadow-floating"),
|
|
203
|
+
children: [/* @__PURE__ */ m("div", {
|
|
170
204
|
className: "flex items-center gap-ds-02 border-b border-surface-border px-ds-04",
|
|
171
|
-
children: [/* @__PURE__ */
|
|
172
|
-
icon:
|
|
205
|
+
children: [/* @__PURE__ */ p(l, {
|
|
206
|
+
icon: te,
|
|
173
207
|
size: "sm",
|
|
174
208
|
className: "shrink-0 text-surface-fg-subtle"
|
|
175
|
-
}), /* @__PURE__ */
|
|
176
|
-
ref:
|
|
209
|
+
}), /* @__PURE__ */ p("input", {
|
|
210
|
+
ref: H,
|
|
177
211
|
type: "text",
|
|
178
212
|
className: "flex-1 bg-transparent py-ds-03 text-ds-md outline-hidden placeholder:text-surface-fg-subtle",
|
|
179
|
-
placeholder:
|
|
180
|
-
value:
|
|
213
|
+
placeholder: E,
|
|
214
|
+
value: R,
|
|
181
215
|
onChange: (e) => {
|
|
182
|
-
|
|
216
|
+
z(e.target.value), V(-1);
|
|
183
217
|
},
|
|
184
|
-
onKeyDown:
|
|
218
|
+
onKeyDown: se,
|
|
185
219
|
"aria-autocomplete": "list",
|
|
186
|
-
"aria-controls":
|
|
187
|
-
"aria-activedescendant":
|
|
220
|
+
"aria-controls": G,
|
|
221
|
+
"aria-activedescendant": B >= 0 ? `${W}-option-${B}` : void 0,
|
|
188
222
|
"aria-label": "Search options"
|
|
189
223
|
})]
|
|
190
|
-
}),
|
|
224
|
+
}), q.length === 0 ? /* @__PURE__ */ p("div", {
|
|
191
225
|
className: "px-ds-04 py-ds-05 text-center text-ds-md text-surface-fg-subtle",
|
|
192
|
-
children:
|
|
193
|
-
}) : /* @__PURE__ */
|
|
194
|
-
ref:
|
|
195
|
-
id:
|
|
226
|
+
children: D
|
|
227
|
+
}) : /* @__PURE__ */ p("ul", {
|
|
228
|
+
ref: U,
|
|
229
|
+
id: G,
|
|
196
230
|
role: "listbox",
|
|
197
|
-
"aria-multiselectable":
|
|
231
|
+
"aria-multiselectable": O || void 0,
|
|
198
232
|
className: "overflow-auto p-ds-02",
|
|
199
|
-
style: { maxHeight: `${
|
|
200
|
-
children:
|
|
201
|
-
let n =
|
|
202
|
-
return /* @__PURE__ */
|
|
203
|
-
id: `${
|
|
233
|
+
style: { maxHeight: `${ie * S}px` },
|
|
234
|
+
children: q.map((e, t) => {
|
|
235
|
+
let n = J(e.value);
|
|
236
|
+
return /* @__PURE__ */ m("li", {
|
|
237
|
+
id: `${W}-option-${t}`,
|
|
204
238
|
role: "option",
|
|
205
239
|
"aria-selected": n,
|
|
206
240
|
"aria-disabled": e.disabled || void 0,
|
|
207
|
-
className:
|
|
241
|
+
className: c("relative flex cursor-pointer select-none items-center gap-ds-03 rounded-ds-md px-ds-04 py-ds-03 text-ds-md outline-hidden", "transition-colors duration-fast-01 ease-productive-standard", B === t && "bg-accent-2", n && "text-accent-11", e.disabled && "pointer-events-none opacity-action-disabled"),
|
|
208
242
|
onClick: () => {
|
|
209
|
-
e.disabled ||
|
|
243
|
+
e.disabled || Y(e.value);
|
|
210
244
|
},
|
|
211
245
|
onKeyDown: (t) => {
|
|
212
|
-
!e.disabled && (t.key === "Enter" || t.key === " ") && (t.preventDefault(),
|
|
246
|
+
!e.disabled && (t.key === "Enter" || t.key === " ") && (t.preventDefault(), Y(e.value));
|
|
213
247
|
},
|
|
214
248
|
onMouseEnter: () => {
|
|
215
|
-
e.disabled ||
|
|
249
|
+
e.disabled || V(t);
|
|
216
250
|
},
|
|
217
251
|
children: [
|
|
218
|
-
e.icon && /* @__PURE__ */
|
|
252
|
+
e.icon && /* @__PURE__ */ p("span", {
|
|
219
253
|
className: "flex h-ico-sm w-ico-sm items-center justify-center shrink-0",
|
|
220
254
|
children: e.icon
|
|
221
255
|
}),
|
|
222
|
-
/* @__PURE__ */
|
|
256
|
+
/* @__PURE__ */ p("span", {
|
|
223
257
|
className: "flex flex-1 flex-col",
|
|
224
|
-
children: A ? A(e, n) : /* @__PURE__ */ f
|
|
258
|
+
children: A ? A(e, n) : /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("span", { children: e.label }), e.description && /* @__PURE__ */ p("span", {
|
|
225
259
|
className: "text-ds-sm text-surface-fg-muted",
|
|
226
260
|
children: e.description
|
|
227
261
|
})] })
|
|
228
262
|
}),
|
|
229
|
-
n && /* @__PURE__ */
|
|
230
|
-
icon:
|
|
263
|
+
n && /* @__PURE__ */ p(l, {
|
|
264
|
+
icon: h,
|
|
231
265
|
size: "sm",
|
|
232
266
|
className: "shrink-0"
|
|
233
267
|
})
|
|
@@ -240,6 +274,6 @@ var _ = 2, v = 36, y = l.forwardRef(({ options: y, value: b, onValueChange: x, p
|
|
|
240
274
|
})
|
|
241
275
|
});
|
|
242
276
|
});
|
|
243
|
-
|
|
277
|
+
C.displayName = "Combobox";
|
|
244
278
|
//#endregion
|
|
245
|
-
export {
|
|
279
|
+
export { C as Combobox, _ as comboboxTriggerVariants };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combobox.js","names":[],"sources":["../../src/ui/combobox.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as PopoverPrimitive from '@primitives/react-popover'\nimport { IconCheck, IconChevronDown, IconSearch, IconX } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { motion } from 'framer-motion'\n\nimport { cn } from './lib/utils'\nimport { springs, tweens } from './lib/motion'\nimport { Icon } from './icon'\nimport type { IconSize } from './icon-context'\nimport { useFormField } from './form'\n\nexport const comboboxTriggerVariants = cva(\n [\n 'flex w-full items-center justify-between whitespace-nowrap rounded-ds-md',\n 'border border-surface-border-strong bg-surface-raised-hover',\n 'transition-colors duration-fast-01 ease-productive-standard',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 focus-visible:border-accent-7',\n 'disabled:cursor-not-allowed disabled:opacity-action-disabled',\n ],\n {\n variants: {\n size: {\n xs: 'h-ds-xs-plus text-ds-sm px-ds-02',\n sm: 'h-ds-sm text-ds-sm px-ds-03',\n md: 'h-ds-md text-ds-md px-ds-04',\n lg: 'h-ds-lg text-ds-md px-ds-05',\n },\n },\n defaultVariants: { size: 'md' },\n },\n)\n\nexport type ComboboxSize = NonNullable<VariantProps<typeof comboboxTriggerVariants>['size']>\n\n/** Maps combobox size to Icon component size for chevron / check icons */\nconst iconSizeMap: Record<NonNullable<ComboboxSize>, IconSize> = {\n xs: 'xs',\n sm: 'sm',\n md: 'sm',\n lg: 'md',\n}\n\n/** Maps combobox size to pill text + padding classes */\nconst pillSizeMap: Record<NonNullable<ComboboxSize>, string> = {\n xs: 'px-ds-02 py-0 text-ds-xs',\n sm: 'px-ds-02 py-0 text-ds-xs',\n md: 'px-ds-03 py-[1px] text-ds-sm',\n lg: 'px-ds-03 py-[2px] text-ds-sm',\n}\n\n/** Maps combobox size to overflow text classes */\nconst overflowTextMap: Record<NonNullable<ComboboxSize>, string> = {\n xs: 'text-ds-xs',\n sm: 'text-ds-xs',\n md: 'text-ds-sm',\n lg: 'text-ds-sm',\n}\n\n/**\n * Option shape for a Combobox dropdown item.\n * `value` must be unique across all options — it is the key used in selection state.\n */\nexport interface ComboboxOption {\n value: string\n label: string\n description?: string\n icon?: React.ReactNode\n disabled?: boolean\n}\n\n/**\n * Props for Combobox — a searchable single or multi-select dropdown with built-in keyboard\n * navigation, pill overflow (\"+ N more\"), and an optional custom option renderer.\n *\n * **Single vs multi:** `multiple={false}` (default) — `value` is a `string` and `onValueChange`\n * receives a `string`. When `multiple={true}`, `value` is `string[]`, `onValueChange` receives\n * `string[]`, and selected items appear as dismissible pills in the trigger.\n *\n * The props form a **discriminated union** on `multiple` — TypeScript will narrow `value` and\n * `onValueChange` automatically, so no manual casts are needed.\n *\n * **Custom rendering:** Use `renderOption` to return custom JSX per option (e.g. avatars, badges).\n *\n * @example\n * // Single-select country picker:\n * <Combobox\n * options={[{ value: 'in', label: 'India' }, { value: 'us', label: 'United States' }]}\n * value={country}\n * onValueChange={(v) => setCountry(v)}\n * placeholder=\"Select country\"\n * />\n *\n * @example\n * // Multi-select tag picker with pill display:\n * <Combobox\n * multiple\n * options={tagOptions}\n * value={selectedTags}\n * onValueChange={(v) => setSelectedTags(v)}\n * placeholder=\"Select tags...\"\n * />\n *\n * @example\n * // Custom option renderer (user avatars in assignee picker):\n * <Combobox\n * options={users.map(u => ({ value: u.id, label: u.name }))}\n * value={assigneeId}\n * onValueChange={(v) => setAssigneeId(v)}\n * renderOption={(option, selected) => (\n * <span className=\"flex items-center gap-ds-03\">\n * <Avatar size=\"xs\"><AvatarFallback>{option.label[0]}</AvatarFallback></Avatar>\n * {option.label}\n * </span>\n * )}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\ninterface ComboboxBaseProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onChange'> {\n /** Available options shown in the dropdown. */\n options: ComboboxOption[]\n /** Placeholder shown in the trigger when no value is selected. */\n placeholder?: string\n /** Placeholder for the search input inside the dropdown. */\n searchPlaceholder?: string\n /** Message shown when the search yields no results. */\n emptyMessage?: string\n disabled?: boolean\n triggerClassName?: string\n /** Max visible items in the dropdown before scroll (default 6). */\n maxVisible?: number\n /** Custom renderer for each option row. Receives the option and whether it's currently selected. */\n renderOption?: (option: ComboboxOption, selected: boolean) => React.ReactNode\n /** Accessible label for the trigger button. Falls back to `placeholder` if not provided. */\n accessibleLabel?: string\n /** Size of the trigger. Controls height, text size, padding, and pill sizing. */\n size?: ComboboxSize\n}\n\ninterface ComboboxSingleProps extends ComboboxBaseProps {\n multiple?: false\n value?: string\n onValueChange: (value: string) => void\n}\n\ninterface ComboboxMultipleProps extends ComboboxBaseProps {\n multiple: true\n value?: string[]\n onValueChange: (value: string[]) => void\n}\n\nexport type ComboboxProps = ComboboxSingleProps | ComboboxMultipleProps\n\n/** Max pills shown in the trigger before \"+N more\" overflow */\nconst MAX_VISIBLE_PILLS = 2\n\n/** Approximate height of a single option item in px */\nconst ITEM_HEIGHT_PX = 36\n\nconst Combobox = React.forwardRef<HTMLButtonElement, ComboboxProps>(\n (\n {\n options,\n value,\n onValueChange,\n placeholder = 'Select...',\n searchPlaceholder = 'Search...',\n emptyMessage = 'No results found',\n multiple = false,\n disabled = false,\n className,\n triggerClassName,\n maxVisible = 6,\n renderOption,\n accessibleLabel,\n size: sizeProp = 'md',\n ...rest\n },\n ref,\n ) => {\n const size = sizeProp ?? 'md'\n const [open, setOpen] = React.useState(false)\n const [search, setSearch] = React.useState('')\n const [highlightedIndex, setHighlightedIndex] = React.useState(-1)\n const searchInputRef = React.useRef<HTMLInputElement>(null)\n const listRef = React.useRef<HTMLUListElement>(null)\n const optionIdPrefix = React.useId()\n const listboxId = React.useId()\n\n const selectedValues = React.useMemo<string[]>(() => {\n if (value === undefined || value === null) return []\n if (Array.isArray(value)) return value\n return [value]\n }, [value])\n\n const filteredOptions = React.useMemo(\n () =>\n search\n ? options.filter((o) =>\n o.label.toLowerCase().includes(search.toLowerCase()),\n )\n : options,\n [options, search],\n )\n\n const isSelected = React.useCallback(\n (optionValue: string) => selectedValues.includes(optionValue),\n [selectedValues],\n )\n\n const handleSelect = React.useCallback(\n (optionValue: string) => {\n if (multiple) {\n const newValue = selectedValues.includes(optionValue)\n ? selectedValues.filter((v) => v !== optionValue)\n : [...selectedValues, optionValue]\n ;(onValueChange as (value: string[]) => void)(newValue)\n } else {\n ;(onValueChange as (value: string) => void)(optionValue)\n setOpen(false)\n }\n },\n [multiple, selectedValues, onValueChange],\n )\n\n const handleRemovePill = React.useCallback(\n (e: React.SyntheticEvent, optionValue: string) => {\n e.stopPropagation()\n e.preventDefault()\n const newValue = selectedValues.filter((v) => v !== optionValue)\n ;(onValueChange as (value: string[]) => void)(newValue)\n },\n [selectedValues, onValueChange],\n )\n\n const handleOpenChange = React.useCallback(\n (nextOpen: boolean) => {\n if (disabled) return\n setOpen(nextOpen)\n if (!nextOpen) {\n setSearch('')\n setHighlightedIndex(-1)\n }\n },\n [disabled],\n )\n\n // Auto-focus search input when popover opens\n React.useEffect(() => {\n if (open) {\n // Use a small timeout to allow the popover to render\n const timer = setTimeout(() => {\n searchInputRef.current?.focus()\n }, 0)\n return () => clearTimeout(timer)\n }\n }, [open])\n\n const findNextEnabledIndex = React.useCallback(\n (currentIndex: number, direction: 1 | -1): number => {\n const len = filteredOptions.length\n if (len === 0) return -1\n\n let nextIndex = currentIndex + direction\n while (nextIndex >= 0 && nextIndex < len) {\n if (!filteredOptions[nextIndex].disabled) return nextIndex\n nextIndex += direction\n }\n return currentIndex\n },\n [filteredOptions],\n )\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent) => {\n switch (e.key) {\n case 'ArrowDown': {\n e.preventDefault()\n const nextIdx = findNextEnabledIndex(highlightedIndex, 1)\n setHighlightedIndex(nextIdx)\n break\n }\n case 'ArrowUp': {\n e.preventDefault()\n const prevIdx = findNextEnabledIndex(highlightedIndex, -1)\n setHighlightedIndex(prevIdx)\n break\n }\n case 'Home': {\n e.preventDefault()\n const firstEnabled = filteredOptions.findIndex((o) => !o.disabled)\n setHighlightedIndex(firstEnabled)\n break\n }\n case 'End': {\n e.preventDefault()\n let lastEnabled = -1\n for (let i = filteredOptions.length - 1; i >= 0; i--) {\n if (!filteredOptions[i].disabled) {\n lastEnabled = i\n break\n }\n }\n setHighlightedIndex(lastEnabled)\n break\n }\n case 'Enter': {\n e.preventDefault()\n if (\n highlightedIndex >= 0 &&\n highlightedIndex < filteredOptions.length &&\n !filteredOptions[highlightedIndex].disabled\n ) {\n handleSelect(filteredOptions[highlightedIndex].value)\n }\n break\n }\n case 'Escape': {\n e.preventDefault()\n setOpen(false)\n setSearch('')\n setHighlightedIndex(-1)\n break\n }\n }\n },\n [highlightedIndex, filteredOptions, findNextEnabledIndex, handleSelect],\n )\n\n // Scroll highlighted option into view\n React.useEffect(() => {\n if (highlightedIndex >= 0 && listRef.current) {\n const optionEl = listRef.current.children[highlightedIndex] as HTMLElement\n if (optionEl) {\n optionEl.scrollIntoView?.({ block: 'nearest' })\n }\n }\n }, [highlightedIndex])\n\n const getSelectedLabel = React.useCallback(() => {\n if (selectedValues.length === 0) return null\n const option = options.find((o) => o.value === selectedValues[0])\n return option?.label ?? null\n }, [selectedValues, options])\n\n const resolvedIconSize = iconSizeMap[size]\n const resolvedPillClasses = pillSizeMap[size]\n const resolvedOverflowText = overflowTextMap[size]\n\n const renderTriggerContent = () => {\n if (multiple && selectedValues.length > 0) {\n const visiblePills = selectedValues.slice(0, MAX_VISIBLE_PILLS)\n const remaining = selectedValues.length - MAX_VISIBLE_PILLS\n\n return (\n <span className=\"flex flex-1 flex-wrap items-center gap-ds-02 overflow-hidden\">\n {visiblePills.map((val) => {\n const option = options.find((o) => o.value === val)\n if (!option) return null\n return (\n <span\n key={val}\n className={cn('inline-flex items-center gap-ds-01 rounded-ds-md bg-accent-2', resolvedPillClasses)}\n >\n {option.label}\n <button\n type=\"button\"\n className=\"inline-flex items-center justify-center rounded-ds-full outline-hidden hover:scale-110 hover:bg-surface-raised-hover transition-transform duration-fast-01 ease-productive-standard\"\n onClick={(e) => handleRemovePill(e, val)}\n aria-label={`Remove ${option.label}`}\n tabIndex={-1}\n >\n <Icon icon={IconX} size={resolvedIconSize} />\n </button>\n </span>\n )\n })}\n {remaining > 0 && (\n <span className={cn('text-surface-fg-muted', resolvedOverflowText)}>\n +{remaining} more\n </span>\n )}\n </span>\n )\n }\n\n if (!multiple && selectedValues.length === 1) {\n const label = getSelectedLabel()\n if (label) {\n return <span className=\"flex-1 truncate text-left\">{label}</span>\n }\n }\n\n return (\n <span className=\"flex-1 truncate text-left text-surface-fg-subtle\">\n {placeholder}\n </span>\n )\n }\n\n const fieldCtx = useFormField()\n const isError = fieldCtx.state === 'error'\n const ariaDescribedBy = fieldCtx.helperTextId\n const ariaRequired = fieldCtx.required\n\n return (\n <PopoverPrimitive.Root open={open} onOpenChange={handleOpenChange}>\n <div className={cn('relative', className)} {...rest}>\n <PopoverPrimitive.Trigger asChild disabled={disabled}>\n <button\n ref={ref}\n type=\"button\"\n role=\"combobox\"\n aria-expanded={open}\n aria-controls={listboxId}\n aria-haspopup=\"listbox\"\n aria-label={accessibleLabel ?? placeholder}\n aria-invalid={isError || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n disabled={disabled}\n className={cn(\n comboboxTriggerVariants({ size }),\n open && 'border-accent-7',\n triggerClassName,\n )}\n >\n {renderTriggerContent()}\n <Icon icon={IconChevronDown} size={resolvedIconSize} className={cn(\"ml-ds-02 shrink-0 opacity-50 transition-transform duration-fast-01 ease-productive-standard\", open && 'rotate-180')} />\n </button>\n </PopoverPrimitive.Trigger>\n\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n asChild\n sideOffset={4}\n align=\"start\"\n onOpenAutoFocus={(e) => {\n e.preventDefault()\n searchInputRef.current?.focus()\n }}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n 'z-popover w-[var(--radix-popover-trigger-width)] overflow-hidden rounded-ds-lg border border-surface-border bg-surface-overlay shadow-floating',\n )}\n >\n {/* Search input */}\n <div className=\"flex items-center gap-ds-02 border-b border-surface-border px-ds-04\">\n <Icon icon={IconSearch} size=\"sm\" className=\"shrink-0 text-surface-fg-subtle\" />\n <input\n ref={searchInputRef}\n type=\"text\"\n className=\"flex-1 bg-transparent py-ds-03 text-ds-md outline-hidden placeholder:text-surface-fg-subtle\"\n placeholder={searchPlaceholder}\n value={search}\n onChange={(e) => {\n setSearch(e.target.value)\n setHighlightedIndex(-1)\n }}\n onKeyDown={handleKeyDown}\n aria-autocomplete=\"list\"\n aria-controls={listboxId}\n aria-activedescendant={\n highlightedIndex >= 0\n ? `${optionIdPrefix}-option-${highlightedIndex}`\n : undefined\n }\n aria-label=\"Search options\"\n />\n </div>\n\n {/* Options list */}\n {filteredOptions.length === 0 ? (\n <div className=\"px-ds-04 py-ds-05 text-center text-ds-md text-surface-fg-subtle\">\n {emptyMessage}\n </div>\n ) : (\n <ul\n ref={listRef}\n id={listboxId}\n role=\"listbox\"\n aria-multiselectable={multiple || undefined}\n className=\"overflow-auto p-ds-02\"\n style={{ maxHeight: `${maxVisible * ITEM_HEIGHT_PX}px` }}\n >\n {filteredOptions.map((option, index) => {\n const selected = isSelected(option.value)\n return (\n <li\n key={option.value}\n id={`${optionIdPrefix}-option-${index}`}\n role=\"option\"\n aria-selected={selected}\n aria-disabled={option.disabled || undefined}\n className={cn(\n 'relative flex cursor-pointer select-none items-center gap-ds-03 rounded-ds-md px-ds-04 py-ds-03 text-ds-md outline-hidden',\n 'transition-colors duration-fast-01 ease-productive-standard',\n highlightedIndex === index &&\n 'bg-accent-2',\n selected && 'text-accent-11',\n option.disabled &&\n 'pointer-events-none opacity-action-disabled',\n )}\n onClick={() => {\n if (!option.disabled) {\n handleSelect(option.value)\n }\n }}\n onKeyDown={(e) => {\n if (!option.disabled && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault()\n handleSelect(option.value)\n }\n }}\n onMouseEnter={() => {\n if (!option.disabled) {\n setHighlightedIndex(index)\n }\n }}\n >\n {option.icon && (\n <span className=\"flex h-ico-sm w-ico-sm items-center justify-center shrink-0\">\n {option.icon}\n </span>\n )}\n <span className=\"flex flex-1 flex-col\">\n {renderOption ? (\n renderOption(option, selected)\n ) : (\n <>\n <span>{option.label}</span>\n {option.description && (\n <span className=\"text-ds-sm text-surface-fg-muted\">\n {option.description}\n </span>\n )}\n </>\n )}\n </span>\n {selected && (\n <Icon icon={IconCheck} size=\"sm\" className=\"shrink-0\" />\n )}\n </li>\n )\n })}\n </ul>\n )}\n </motion.div>\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </div>\n </PopoverPrimitive.Root>\n )\n },\n)\nCombobox.displayName = 'Combobox'\n\nexport { Combobox }\n"],"mappings":"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"}
|
package/dist/ui/container.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container.js","names":[],"sources":["../../src/ui/container.tsx"],"sourcesContent":["// @server-safe\nimport * as React from 'react'\nimport { cn } from './lib/utils'\n\ntype ContainerProps<T extends React.ElementType = 'div'> = {\n as?: T\n maxWidth?: 'default' | 'body' | 'full'\n className?: string\n children?: React.ReactNode\n} & Omit<React.ComponentPropsWithRef<T>, 'as' | 'className' | 'children'>\n\nconst maxWidthMap = {\n default: 'max-w-layout',\n body: 'max-w-layout-body',\n full: 'max-w-full',\n} as const\n\nconst Container = React.forwardRef<HTMLElement, ContainerProps>(\n ({ as, maxWidth = 'default', className, children, ...props }, ref) => {\n const Component = as || 'div'\n return React.createElement(\n Component,\n {\n ref,\n className: cn('mx-auto w-full px-page-x', maxWidthMap[maxWidth], className),\n ...props,\n },\n children,\n )\n },\n)\nContainer.displayName = 'Container'\n\nexport { Container, type ContainerProps }\n"],"mappings":";;;AAWA,IAAM,IAAc;CAClB,SAAS;CACT,MAAM;CACN,MAAM;CACP,EAEK,IAAY,EAAM,YACrB,EAAE,OAAI,cAAW,WAAW,cAAW,aAAU,GAAG,KAAS,MAAQ;CACpE,IAAM,IAAY,KAAM;AACxB,QAAO,EAAM,cACX,GACA;EACE;EACA,WAAW,EAAG,4BAA4B,EAAY,IAAW,EAAU;EAC3E,GAAG;EACJ,EACD,EACD;EAEJ;AACD,EAAU,cAAc"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-menu.js","names":[],"sources":["../../src/ui/context-menu.tsx"],"sourcesContent":["'use client'\n\nimport * as React from \"react\"\nimport * as ContextMenuPrimitive from \"@primitives/react-context-menu\"\nimport { IconCheck, IconChevronRight, IconCircle } from '@tabler/icons-react'\nimport { motion, AnimatePresence } from 'framer-motion'\n\nimport { cn } from \"./lib/utils\"\nimport { springs, tweens } from './lib/motion'\nimport { Icon } from './icon'\n\n// ── Internal contexts to thread open state ──\n\nconst ContextMenuOpenContext = React.createContext(false)\nconst ContextMenuSubOpenContext = React.createContext(false)\n\nconst ContextMenu: React.FC<React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Root>> = ({\n onOpenChange,\n ...props\n}) => {\n const [open, setOpen] = React.useState(false)\n\n const handleOpenChange = React.useCallback(\n (value: boolean) => {\n setOpen(value)\n onOpenChange?.(value)\n },\n [onOpenChange],\n )\n\n return (\n <ContextMenuOpenContext.Provider value={open}>\n <ContextMenuPrimitive.Root onOpenChange={handleOpenChange} {...props} />\n </ContextMenuOpenContext.Provider>\n )\n}\nContextMenu.displayName = 'ContextMenu'\n\nconst ContextMenuTrigger = ContextMenuPrimitive.Trigger\n\nconst ContextMenuGroup = ContextMenuPrimitive.Group\n\nconst ContextMenuPortal = ContextMenuPrimitive.Portal\n\nconst ContextMenuSub: React.FC<React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Sub>> = ({\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n ...props\n}) => {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n const isControlled = controlledOpen !== undefined\n const open = isControlled ? controlledOpen : uncontrolledOpen\n\n const handleOpenChange = React.useCallback(\n (value: boolean) => {\n if (!isControlled) setUncontrolledOpen(value)\n onOpenChange?.(value)\n },\n [isControlled, onOpenChange],\n )\n\n return (\n <ContextMenuSubOpenContext.Provider value={open}>\n <ContextMenuPrimitive.Sub open={open} onOpenChange={handleOpenChange} {...props} />\n </ContextMenuSubOpenContext.Provider>\n )\n}\nContextMenuSub.displayName = 'ContextMenuSub'\n\nconst ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup\n\nconst ContextMenuSubTrigger = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {\n inset?: boolean\n }\n>(({ className, inset, children, ...props }, ref) => (\n <ContextMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n \"flex cursor-default select-none items-center rounded-ds-md px-ds-03 py-ds-02b text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[state=open]:bg-surface-raised data-[state=open]:text-surface-fg\",\n inset && \"pl-ds-07\",\n className\n )}\n {...props}\n >\n {children}\n <Icon icon={IconChevronRight} size=\"sm\" className=\"ml-auto\" />\n </ContextMenuPrimitive.SubTrigger>\n))\nContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName\n\nconst ContextMenuSubContent = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.SubContent>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>\n>(({ className, children, ...props }, ref) => {\n const open = React.useContext(ContextMenuSubOpenContext)\n\n return (\n <AnimatePresence>\n {open && (\n <ContextMenuPrimitive.SubContent\n ref={ref}\n forceMount\n asChild\n {...props}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.95 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n \"z-popover min-w-[8rem] overflow-hidden rounded-ds-lg border border-surface-border-strong bg-surface-overlay p-ds-02 text-surface-fg shadow-floating\",\n className\n )}\n >\n {children}\n </motion.div>\n </ContextMenuPrimitive.SubContent>\n )}\n </AnimatePresence>\n )\n})\nContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName\n\nconst ContextMenuContent = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>\n>(({ className, children, ...props }, ref) => {\n const open = React.useContext(ContextMenuOpenContext)\n\n return (\n <AnimatePresence>\n {open && (\n <ContextMenuPrimitive.Portal forceMount>\n <ContextMenuPrimitive.Content\n ref={ref}\n forceMount\n asChild\n {...props}\n >\n <motion.div\n initial={{ opacity: 0, scale: 0.95 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.95 }}\n transition={{ ...springs.snappy, opacity: tweens.fade }}\n className={cn(\n \"z-popover rounded-ds-lg border border-surface-border-strong bg-surface-overlay p-ds-02 text-surface-fg shadow-floating\",\n className\n )}\n >\n {children}\n </motion.div>\n </ContextMenuPrimitive.Content>\n </ContextMenuPrimitive.Portal>\n )}\n </AnimatePresence>\n )\n})\nContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName\n\nconst ContextMenuItem = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {\n inset?: boolean\n }\n>(({ className, inset, ...props }, ref) => (\n <ContextMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-ds-md px-ds-03 py-ds-02b text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled\",\n inset && \"pl-ds-07\",\n className\n )}\n {...props}\n />\n))\nContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName\n\nconst ContextMenuCheckboxItem = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <ContextMenuPrimitive.CheckboxItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-ds-md py-ds-02b pl-ds-07 pr-ds-03 text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled\",\n className\n )}\n checked={checked}\n {...props}\n >\n <span className=\"absolute left-ds-03 flex h-ico-sm w-ico-sm items-center justify-center\">\n <ContextMenuPrimitive.ItemIndicator>\n <Icon icon={IconCheck} size=\"sm\" />\n </ContextMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </ContextMenuPrimitive.CheckboxItem>\n))\nContextMenuCheckboxItem.displayName =\n ContextMenuPrimitive.CheckboxItem.displayName\n\nconst ContextMenuRadioItem = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <ContextMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-ds-md py-ds-02b pl-ds-07 pr-ds-03 text-ds-md outline-hidden focus:bg-surface-raised focus:text-surface-fg data-[disabled]:pointer-events-none data-[disabled]:opacity-action-disabled\",\n className\n )}\n {...props}\n >\n <span className=\"absolute left-ds-03 flex h-ico-sm w-ico-sm items-center justify-center\">\n <ContextMenuPrimitive.ItemIndicator>\n <Icon icon={IconCircle} size=\"sm\" className=\"fill-current\" />\n </ContextMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </ContextMenuPrimitive.RadioItem>\n))\nContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName\n\nconst ContextMenuLabel = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {\n inset?: boolean\n }\n>(({ className, inset, ...props }, ref) => (\n <ContextMenuPrimitive.Label\n ref={ref}\n className={cn(\n \"px-ds-03 py-ds-02b text-ds-md font-semibold text-surface-fg\",\n inset && \"pl-ds-07\",\n className\n )}\n {...props}\n />\n))\nContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName\n\nconst ContextMenuSeparator = React.forwardRef<\n React.ElementRef<typeof ContextMenuPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <ContextMenuPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-ds-01 my-ds-02 h-px bg-surface-border\", className)}\n {...props}\n />\n))\nContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName\n\nconst ContextMenuShortcut = ({\n className,\n ...props\n}: React.HTMLAttributes<HTMLSpanElement>) => {\n return (\n <span\n className={cn(\n \"ml-auto text-ds-sm text-surface-fg-subtle\",\n className\n )}\n {...props}\n />\n )\n}\nContextMenuShortcut.displayName = \"ContextMenuShortcut\"\n\nexport type ContextMenuContentProps = React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>\nexport type ContextMenuItemProps = React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item>\n\nexport {\n ContextMenu,\n ContextMenuTrigger,\n ContextMenuContent,\n ContextMenuItem,\n ContextMenuCheckboxItem,\n ContextMenuRadioItem,\n ContextMenuLabel,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuGroup,\n ContextMenuPortal,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuRadioGroup,\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-table-body.js","names":[],"sources":["../../src/ui/data-table-body.tsx"],"sourcesContent":["'use client'\n\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\nimport { type Row, flexRender } from '@tanstack/react-table'\nimport { type VirtualItem } from '@tanstack/react-virtual'\n\nimport { TableBody, TableCell, TableRow } from './table'\nimport { Skeleton } from './skeleton'\nimport { cn } from './lib/utils'\nimport {\n useDataTableContext,\n getColumnMetaClasses,\n getPinnedCellStyle,\n isColumnEditable,\n INTERACTIVE_SELECTOR,\n} from './data-table-context'\n\n// ── CellEditInput ───────────────────────────────────────────────\n\n/**\n * Inline edit input rendered inside a table cell.\n * Auto-focuses, saves on Enter/blur, cancels on Escape.\n */\nfunction CellEditInput({\n initialValue,\n onSave,\n onCancel,\n}: {\n initialValue: string\n onSave: (value: string) => void\n onCancel: () => void\n}) {\n const [value, setValue] = useState(initialValue)\n const inputRef = useRef<HTMLInputElement>(null)\n\n useEffect(() => {\n inputRef.current?.focus()\n inputRef.current?.select()\n }, [])\n\n const handleSave = useCallback(() => {\n onSave(value)\n }, [onSave, value])\n\n return (\n <input\n ref={inputRef}\n type=\"text\"\n value={value}\n onChange={(e) => setValue(e.target.value)}\n onBlur={handleSave}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault()\n handleSave()\n } else if (e.key === 'Escape') {\n e.preventDefault()\n onCancel()\n }\n }}\n className={cn(\n 'h-ds-xs-plus w-full rounded-ds-md',\n 'border border-accent-7 bg-surface-raised-hover',\n 'px-ds-02 text-ds-sm',\n 'text-surface-fg placeholder:text-surface-fg-subtle',\n 'outline-hidden focus:border-accent-7',\n )}\n aria-label=\"Edit cell value\"\n />\n )\n}\n\n// ── DataRow ─────────────────────────────────────────────────────\n\n/** Render a single data row (shared between virtual and non-virtual paths) */\nfunction DataTableRow<TData>({\n row,\n style,\n}: {\n row: Row<TData>\n style?: React.CSSProperties\n}) {\n const {\n table,\n cellPadding,\n columnPinningState,\n editable,\n editingCell,\n setEditingCell,\n onCellEdit,\n virtualRows,\n onRowClick,\n } = useDataTableContext<TData>()\n\n const handleRowClick = useCallback(\n (e: React.MouseEvent<HTMLTableRowElement>) => {\n if (!onRowClick) return\n const target = e.target as HTMLElement\n if (target.closest(INTERACTIVE_SELECTOR)) return\n onRowClick(row.original)\n },\n [onRowClick, row.original],\n )\n\n const visibleCells = row.getVisibleCells()\n\n return (\n <TableRow\n data-state={row.getIsSelected() && 'selected'}\n style={style}\n className={cn(\n virtualRows ? 'absolute w-full flex' : undefined,\n onRowClick && 'cursor-pointer',\n )}\n onClick={onRowClick ? handleRowClick : undefined}\n >\n {visibleCells.map((cell) => {\n const pinned = getPinnedCellStyle(cell.column.id, columnPinningState)\n const isEditing =\n editingCell?.rowIndex === row.index &&\n editingCell?.columnId === cell.column.id\n\n return (\n <TableCell\n key={cell.id}\n className={cn(\n cellPadding,\n pinned.className,\n virtualRows && 'flex-1',\n getColumnMetaClasses(\n cell.column.columnDef.meta as Record<string, unknown>,\n ),\n )}\n style={pinned.style}\n onDoubleClick={() => {\n if (isColumnEditable(cell.column.id, editable, table)) {\n setEditingCell({\n rowIndex: row.index,\n columnId: cell.column.id,\n })\n }\n }}\n >\n {isEditing ? (\n <CellEditInput\n initialValue={String(cell.getValue() ?? '')}\n onSave={(value) => {\n onCellEdit?.(row.index, cell.column.id, value)\n setEditingCell(null)\n }}\n onCancel={() => setEditingCell(null)}\n />\n ) : (\n flexRender(cell.column.columnDef.cell, cell.getContext())\n )}\n </TableCell>\n )\n })}\n </TableRow>\n )\n}\n\n// ── ExpandedRow ─────────────────────────────────────────────────\n\n/** Render expanded content row below the data row */\nfunction DataTableExpandedRow<TData>({\n row,\n style,\n}: {\n row: Row<TData>\n style?: React.CSSProperties\n}) {\n const { allColumns, expandable, renderExpanded, virtualRows } =\n useDataTableContext<TData>()\n\n if (!expandable || !row.getIsExpanded() || !renderExpanded) return null\n\n return (\n <TableRow\n style={style}\n className={virtualRows ? 'absolute w-full flex' : undefined}\n >\n <TableCell\n colSpan={allColumns.length}\n className={cn(\n 'bg-surface-raised p-ds-05',\n virtualRows && 'flex-1',\n )}\n >\n {renderExpanded(row.original)}\n </TableCell>\n </TableRow>\n )\n}\n\n// ── SkeletonRows ────────────────────────────────────────────────\n\nfunction DataTableSkeletonRows({\n rowCount,\n}: {\n rowCount: number\n}) {\n const { allColumns, cellPadding } = useDataTableContext()\n const visibleColumnCount = allColumns.length\n const skeletonWidths = ['w-3/4', 'w-1/2', 'w-2/3', 'w-full']\n\n return (\n <TableBody>\n {Array.from({ length: rowCount }, (_, rowIdx) => (\n <TableRow key={`skeleton-${rowIdx}`}>\n {Array.from({ length: visibleColumnCount }, (_, colIdx) => {\n const colId = allColumns[colIdx]?.id ?? allColumns[colIdx]?.header\n const isSelect = colId === '_select'\n return (\n <TableCell\n key={`skeleton-${rowIdx}-${colIdx}`}\n className={cellPadding}\n >\n {isSelect ? (\n <Skeleton\n variant=\"text\"\n className=\"h-4 w-4\"\n animation=\"pulse\"\n />\n ) : (\n <Skeleton\n variant=\"text\"\n className={cn(\n 'h-4',\n skeletonWidths[colIdx % skeletonWidths.length],\n )}\n animation=\"pulse\"\n />\n )}\n </TableCell>\n )\n })}\n </TableRow>\n ))}\n </TableBody>\n )\n}\n\n// ── DataTableBody (orchestrates all body rendering) ─────────────\n\nexport function DataTableBody<TData>({\n loading,\n skeletonRowCount,\n noResultsText,\n emptyState,\n virtualItems,\n totalVirtualSize,\n}: {\n loading?: boolean\n skeletonRowCount: number\n noResultsText?: string\n emptyState?: React.ReactNode\n virtualItems?: VirtualItem[]\n totalVirtualSize?: number\n}) {\n const { table, allColumns, virtualRows } = useDataTableContext<TData>()\n const rows = table.getRowModel().rows\n\n // Loading state: show skeleton rows\n if (loading) {\n return <DataTableSkeletonRows rowCount={skeletonRowCount} />\n }\n\n if (!rows.length) {\n return (\n <TableBody>\n <TableRow>\n <TableCell\n colSpan={allColumns.length}\n className={cn(\n 'h-24 text-center',\n !emptyState && 'text-surface-fg-subtle',\n )}\n >\n {emptyState || noResultsText || 'No results.'}\n </TableCell>\n </TableRow>\n </TableBody>\n )\n }\n\n if (virtualRows && virtualItems) {\n return (\n <TableBody\n style={{\n height: `${totalVirtualSize}px`,\n position: 'relative',\n }}\n >\n {virtualItems.map((virtualRow) => {\n const row = rows[virtualRow.index]\n return (\n <DataTableRow\n key={row.id}\n row={row}\n style={{\n position: 'absolute',\n top: 0,\n left: 0,\n width: '100%',\n height: `${virtualRow.size}px`,\n transform: `translateY(${virtualRow.start}px)`,\n }}\n />\n )\n })}\n </TableBody>\n )\n }\n\n // Standard (non-virtual) rendering\n return (\n <TableBody>\n {rows.map((row) => (\n <React.Fragment key={row.id}>\n <DataTableRow row={row} />\n <DataTableExpandedRow row={row} />\n </React.Fragment>\n ))}\n </TableBody>\n )\n}\n"],"mappings":";;;;;;;;;AAuBA,SAAS,EAAc,EACrB,iBACA,WACA,eAKC;CACD,IAAM,CAAC,GAAO,KAAY,EAAS,EAAa,EAC1C,IAAW,EAAyB,KAAK;AAE/C,SAAgB;AAEd,EADA,EAAS,SAAS,OAAO,EACzB,EAAS,SAAS,QAAQ;IACzB,EAAE,CAAC;CAEN,IAAM,IAAa,QAAkB;AACnC,IAAO,EAAM;IACZ,CAAC,GAAQ,EAAM,CAAC;AAEnB,QACE,kBAAC,SAAD;EACE,KAAK;EACL,MAAK;EACE;EACP,WAAW,MAAM,EAAS,EAAE,OAAO,MAAM;EACzC,QAAQ;EACR,YAAY,MAAM;AAChB,GAAI,EAAE,QAAQ,WACZ,EAAE,gBAAgB,EAClB,GAAY,IACH,EAAE,QAAQ,aACnB,EAAE,gBAAgB,EAClB,GAAU;;EAGd,WAAW,EACT,qCACA,kDACA,uBACA,sDACA,uCACD;EACD,cAAW;EACX,CAAA;;AAON,SAAS,EAAoB,EAC3B,QACA,YAIC;CACD,IAAM,EACJ,UACA,gBACA,uBACA,aACA,gBACA,mBACA,eACA,gBACA,kBACE,GAA4B,EAE1B,IAAiB,GACpB,MAA6C;AACvC,QACU,EAAE,OACN,QAAA,0DAA6B,IACxC,EAAW,EAAI,SAAS;IAE1B,CAAC,GAAY,EAAI,SAAS,CAC3B,EAEK,IAAe,EAAI,iBAAiB;AAE1C,QACE,kBAAC,GAAD;EACE,cAAY,EAAI,eAAe,IAAI;EAC5B;EACP,WAAW,EACT,IAAc,yBAAyB,KAAA,GACvC,KAAc,iBACf;EACD,SAAS,IAAa,IAAiB,KAAA;YAEtC,EAAa,KAAK,MAAS;GAC1B,IAAM,IAAS,EAAmB,EAAK,OAAO,IAAI,EAAmB,EAC/D,IACJ,GAAa,aAAa,EAAI,SAC9B,GAAa,aAAa,EAAK,OAAO;AAExC,UACE,kBAAC,GAAD;IAEE,WAAW,EACT,GACA,EAAO,WACP,KAAe,UACf,EACE,EAAK,OAAO,UAAU,KACvB,CACF;IACD,OAAO,EAAO;IACd,qBAAqB;AACnB,KAAI,EAAiB,EAAK,OAAO,IAAI,GAAU,EAAM,IACnD,EAAe;MACb,UAAU,EAAI;MACd,UAAU,EAAK,OAAO;MACvB,CAAC;;cAIL,IACC,kBAAC,GAAD;KACE,cAAc,OAAO,EAAK,UAAU,IAAI,GAAG;KAC3C,SAAS,MAAU;AAEjB,MADA,IAAa,EAAI,OAAO,EAAK,OAAO,IAAI,EAAM,EAC9C,EAAe,KAAK;;KAEtB,gBAAgB,EAAe,KAAK;KACpC,CAAA,GAEF,EAAW,EAAK,OAAO,UAAU,MAAM,EAAK,YAAY,CAAC;IAEjD,EA/BL,EAAK,GA+BA;IAEd;EACO,CAAA;;AAOf,SAAS,EAA4B,EACnC,QACA,YAIC;CACD,IAAM,EAAE,eAAY,eAAY,mBAAgB,mBAC9C,GAA4B;AAI9B,QAFI,CAAC,KAAc,CAAC,EAAI,eAAe,IAAI,CAAC,IAAuB,OAGjE,kBAAC,GAAD;EACS;EACP,WAAW,IAAc,yBAAyB,KAAA;YAElD,kBAAC,GAAD;GACE,SAAS,EAAW;GACpB,WAAW,EACT,6BACA,KAAe,SAChB;aAEA,EAAe,EAAI,SAAS;GACnB,CAAA;EACH,CAAA;;AAMf,SAAS,EAAsB,EAC7B,eAGC;CACD,IAAM,EAAE,eAAY,mBAAgB,GAAqB,EACnD,IAAqB,EAAW,QAChC,IAAiB;EAAC;EAAS;EAAS;EAAS;EAAS;AAE5D,QACE,kBAAC,GAAD,EAAA,UACG,MAAM,KAAK,EAAE,QAAQ,GAAU,GAAG,GAAG,MACpC,kBAAC,GAAD,EAAA,UACG,MAAM,KAAK,EAAE,QAAQ,GAAoB,GAAG,GAAG,MAI5C,kBAAC,GAAD;EAEE,WAAW;aALD,EAAW,IAAS,MAAM,EAAW,IAAS,YACjC,YAOrB,kBAAC,GAAD;GACE,SAAQ;GACR,WAAU;GACV,WAAU;GACV,CAAA,GAEF,kBAAC,GAAD;GACE,SAAQ;GACR,WAAW,EACT,OACA,EAAe,IAAS,EAAe,QACxC;GACD,WAAU;GACV,CAAA;EAEM,EAnBL,YAAY,EAAO,GAAG,IAmBjB,CAEd,EACO,EA5BI,YAAY,IA4BhB,CACX,EACQ,CAAA;;AAMhB,SAAgB,EAAqB,EACnC,YACA,qBACA,kBACA,eACA,iBACA,uBAQC;CACD,IAAM,EAAE,UAAO,eAAY,mBAAgB,GAA4B,EACjE,IAAO,EAAM,aAAa,CAAC;AAuDjC,QApDI,IACK,kBAAC,GAAD,EAAuB,UAAU,GAAoB,CAAA,GAGzD,EAAK,SAkBN,KAAe,IAEf,kBAAC,GAAD;EACE,OAAO;GACL,QAAQ,GAAG,EAAiB;GAC5B,UAAU;GACX;YAEA,EAAa,KAAK,MAAe;GAChC,IAAM,IAAM,EAAK,EAAW;AAC5B,UACE,kBAAC,GAAD;IAEO;IACL,OAAO;KACL,UAAU;KACV,KAAK;KACL,MAAM;KACN,OAAO;KACP,QAAQ,GAAG,EAAW,KAAK;KAC3B,WAAW,cAAc,EAAW,MAAM;KAC3C;IACD,EAVK,EAAI,GAUT;IAEJ;EACQ,CAAA,GAMd,kBAAC,GAAD,EAAA,UACG,EAAK,KAAK,MACT,kBAAC,EAAM,UAAP,EAAA,UAAA,CACE,kBAAC,GAAD,EAAmB,QAAO,CAAA,EAC1B,kBAAC,GAAD,EAA2B,QAAO,CAAA,CACnB,EAAA,EAHI,EAAI,GAGR,CACjB,EACQ,CAAA,GAtDV,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD,EAAA,UACE,kBAAC,GAAD;EACE,SAAS,EAAW;EACpB,WAAW,EACT,oBACA,CAAC,KAAc,yBAChB;YAEA,KAAc,KAAiB;EACtB,CAAA,EACH,CAAA,EACD,CAAA"}
|
|
@@ -8,7 +8,7 @@ import { IconX as a } from "@tabler/icons-react";
|
|
|
8
8
|
//#region src/ui/data-table-bulk-actions.tsx
|
|
9
9
|
function o({ table: o, selectedRows: s, bulkActions: c }) {
|
|
10
10
|
return /* @__PURE__ */ i("div", {
|
|
11
|
-
className: e("fixed bottom-6 left-1/2 -translate-x-1/2 z-
|
|
11
|
+
className: e("fixed bottom-6 left-1/2 -translate-x-1/2 z-sticky", "flex items-center gap-ds-04 px-ds-05 py-ds-03", "rounded-ds-lg border border-surface-border-strong bg-surface-overlay shadow-floating", "animate-in slide-in-from-bottom-2"),
|
|
12
12
|
role: "toolbar",
|
|
13
13
|
"aria-label": "Bulk actions",
|
|
14
14
|
children: [
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-table-bulk-actions.js","names":[],"sources":["../../src/ui/data-table-bulk-actions.tsx"],"sourcesContent":["'use client'\n\nimport React from 'react'\nimport { type Table } from '@tanstack/react-table'\nimport { IconX } from '@tabler/icons-react'\n\nimport { Icon } from './icon'\nimport { Button } from './button'\nimport { cn } from './lib/utils'\n\n/** Bulk action definition for the floating action bar */\nexport interface BulkAction<TData> {\n label: string\n onClick: (selectedRows: TData[]) => void\n color?: 'accent' | 'error'\n disabled?: boolean\n}\n\n/**\n * Floating action bar shown when rows are selected.\n * Internal — not exported to consumers.\n */\nexport function DataTableBulkActions<TData>({\n table,\n selectedRows,\n bulkActions,\n}: {\n table: Table<TData>\n selectedRows: TData[]\n bulkActions: BulkAction<TData>[]\n}) {\n return (\n <div\n className={cn(\n 'fixed bottom-6 left-1/2 -translate-x-1/2 z-sticky',\n 'flex items-center gap-ds-04 px-ds-05 py-ds-03',\n 'rounded-ds-lg border border-surface-border-strong bg-surface-overlay shadow-floating',\n 'animate-in slide-in-from-bottom-2',\n )}\n role=\"toolbar\"\n aria-label=\"Bulk actions\"\n >\n <span className=\"text-ds-sm font-medium text-surface-fg whitespace-nowrap\">\n {selectedRows.length} selected\n </span>\n <div className=\"h-5 w-px bg-surface-border\" aria-hidden=\"true\" />\n {bulkActions.map((action) => (\n <Button\n key={action.label}\n size=\"sm\"\n variant={action.color === 'error' ? 'solid' : 'outline'}\n color={action.color === 'error' ? 'error' : undefined}\n disabled={action.disabled}\n onClick={() => action.onClick(selectedRows)}\n >\n {action.label}\n </Button>\n ))}\n <button\n type=\"button\"\n onClick={() => table.resetRowSelection()}\n aria-label=\"Clear selection\"\n className={cn(\n 'flex items-center justify-center p-ds-01',\n 'rounded-ds-sm hover:bg-surface-raised transition-colors',\n 'text-surface-fg-muted hover:text-surface-fg',\n )}\n >\n <Icon icon={IconX} size=\"sm\" />\n </button>\n </div>\n )\n}\n"],"mappings":";;;;;;;;AAsBA,SAAgB,EAA4B,EAC1C,UACA,iBACA,kBAKC;AACD,QACE,kBAAC,OAAD;EACE,WAAW,EACT,qDACA,iDACA,wFACA,oCACD;EACD,MAAK;EACL,cAAW;YARb;GAUE,kBAAC,QAAD;IAAM,WAAU;cAAhB,CACG,EAAa,QAAO,YAChB;;GACP,kBAAC,OAAD;IAAK,WAAU;IAA6B,eAAY;IAAS,CAAA;GAChE,EAAY,KAAK,MAChB,kBAAC,GAAD;IAEE,MAAK;IACL,SAAS,EAAO,UAAU,UAAU,UAAU;IAC9C,OAAO,EAAO,UAAU,UAAU,UAAU,KAAA;IAC5C,UAAU,EAAO;IACjB,eAAe,EAAO,QAAQ,EAAa;cAE1C,EAAO;IACD,EARF,EAAO,MAQL,CACT;GACF,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAM,mBAAmB;IACxC,cAAW;IACX,WAAW,EACT,4CACA,2DACA,8CACD;cAED,kBAAC,GAAD;KAAM,MAAM;KAAO,MAAK;KAAO,CAAA;IACxB,CAAA;GACL"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"data-table-card.js","names":[],"sources":["../../src/ui/data-table-card.tsx"],"sourcesContent":["'use client'\n\nimport React from 'react'\nimport { flexRender } from '@tanstack/react-table'\n\nimport { Checkbox } from './checkbox'\nimport { Skeleton } from './skeleton'\nimport { cn } from './lib/utils'\nimport { useDataTableContext } from './data-table-context'\n\n// ── DataTableCards ─────────────────────────────────────────────\n// Renders rows as vertically stacked cards for small (< sm) viewports.\n// Consumes the same TanStack Table instance from context — sorting,\n// filtering, pagination, and selection all work identically.\n\nexport function DataTableCards<TData>({\n loading,\n skeletonRowCount,\n noResultsText,\n emptyState,\n}: {\n loading?: boolean\n skeletonRowCount: number\n noResultsText?: string\n emptyState?: React.ReactNode\n}) {\n const { table, selectable } = useDataTableContext<TData>()\n const rows = table.getRowModel().rows\n\n // Loading skeleton\n if (loading) {\n return (\n <div className=\"flex flex-col gap-ds-03\">\n {Array.from({ length: skeletonRowCount }, (_, i) => (\n <div\n key={`card-skeleton-${i}`}\n className=\"rounded-ds-lg border border-surface-border bg-surface-raised p-ds-04\"\n >\n <Skeleton variant=\"text\" className=\"mb-ds-03 h-5 w-2/3\" animation=\"pulse\" />\n <div className=\"flex flex-col gap-ds-02\">\n <Skeleton variant=\"text\" className=\"h-4 w-full\" animation=\"pulse\" />\n <Skeleton variant=\"text\" className=\"h-4 w-3/4\" animation=\"pulse\" />\n <Skeleton variant=\"text\" className=\"h-4 w-1/2\" animation=\"pulse\" />\n </div>\n </div>\n ))}\n </div>\n )\n }\n\n // Empty state\n if (!rows.length) {\n return (\n <div className={cn('py-ds-07 text-center', !emptyState && 'text-surface-fg-subtle')}>\n {emptyState || noResultsText || 'No results.'}\n </div>\n )\n }\n\n return (\n <div className=\"flex flex-col gap-ds-03\" role=\"list\">\n {rows.map((row) => {\n const cells = row.getVisibleCells()\n // Skip internal columns (_select, _expand) for card content\n const contentCells = cells.filter(\n (cell) => cell.column.id !== '_select' && cell.column.id !== '_expand',\n )\n const primaryCell = contentCells[0]\n const restCells = contentCells.slice(1)\n const isSelected = row.getIsSelected()\n\n return (\n <div\n key={row.id}\n role=\"listitem\"\n className={cn(\n 'rounded-ds-lg border border-surface-border bg-surface-raised p-ds-04',\n isSelected && 'ring-2 ring-accent-9',\n )}\n >\n {/* Header row: primary field + optional selection checkbox */}\n <div className=\"flex items-start justify-between gap-ds-03 mb-ds-02\">\n <div className=\"min-w-0 flex-1 font-medium text-surface-fg\">\n {primaryCell &&\n flexRender(primaryCell.column.columnDef.cell, primaryCell.getContext())}\n </div>\n {selectable && (\n <Checkbox\n size=\"sm\"\n checked={isSelected}\n disabled={!row.getCanSelect()}\n onCheckedChange={(v) => row.toggleSelected(!!v)}\n aria-label=\"Select row\"\n className=\"shrink-0\"\n />\n )}\n </div>\n\n {/* Label-value pairs for remaining columns */}\n {restCells.length > 0 && (\n <div className=\"flex flex-col gap-ds-01 border-t border-surface-border pt-ds-02\">\n {restCells.map((cell) => {\n // Respect hideBelow column meta — skip hidden columns\n const meta = cell.column.columnDef.meta as\n | { hideBelow?: string }\n | undefined\n // In card mode on mobile, hideBelow='sm' columns are still useful\n // since we're showing all data in a card layout. Only skip if\n // the column is explicitly hidden via visibility toggle.\n if (meta?.hideBelow === 'md' || meta?.hideBelow === 'lg') {\n // These would normally be hidden at this breakpoint in table\n // mode too, so skip them in cards for consistency\n }\n\n // Derive header label text\n const header =\n typeof cell.column.columnDef.header === 'string'\n ? cell.column.columnDef.header\n : cell.column.id\n\n return (\n <div key={cell.id} className=\"flex justify-between gap-ds-03 text-ds-sm\">\n <span className=\"shrink-0 text-surface-fg-muted\">{header}</span>\n <span className=\"min-w-0 text-right text-surface-fg\">\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </span>\n </div>\n )\n })}\n </div>\n )}\n </div>\n )\n })}\n </div>\n )\n}\n"],"mappings":";;;;;;;;;AAeA,SAAgB,EAAsB,EACpC,YACA,qBACA,kBACA,iBAMC;CACD,IAAM,EAAE,UAAO,kBAAe,GAA4B,EACpD,IAAO,EAAM,aAAa,CAAC;AAgCjC,QA7BI,IAEA,kBAAC,OAAD;EAAK,WAAU;YACZ,MAAM,KAAK,EAAE,QAAQ,GAAkB,GAAG,GAAG,MAC5C,kBAAC,OAAD;GAEE,WAAU;aAFZ,CAIE,kBAAC,GAAD;IAAU,SAAQ;IAAO,WAAU;IAAqB,WAAU;IAAU,CAAA,EAC5E,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,GAAD;MAAU,SAAQ;MAAO,WAAU;MAAa,WAAU;MAAU,CAAA;KACpE,kBAAC,GAAD;MAAU,SAAQ;MAAO,WAAU;MAAY,WAAU;MAAU,CAAA;KACnE,kBAAC,GAAD;MAAU,SAAQ;MAAO,WAAU;MAAY,WAAU;MAAU,CAAA;KAC/D;MACF;KATC,iBAAiB,IASlB,CACN;EACE,CAAA,GAKL,EAAK,SASR,kBAAC,OAAD;EAAK,WAAU;EAA0B,MAAK;YAC3C,EAAK,KAAK,MAAQ;GAGjB,IAAM,IAFQ,EAAI,iBAAiB,CAER,QACxB,MAAS,EAAK,OAAO,OAAO,aAAa,EAAK,OAAO,OAAO,UAC9D,EACK,IAAc,EAAa,IAC3B,IAAY,EAAa,MAAM,EAAE,EACjC,IAAa,EAAI,eAAe;AAEtC,UACE,kBAAC,OAAD;IAEE,MAAK;IACL,WAAW,EACT,wEACA,KAAc,uBACf;cANH,CASE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,OAAD;MAAK,WAAU;gBACZ,KACC,EAAW,EAAY,OAAO,UAAU,MAAM,EAAY,YAAY,CAAC;MACrE,CAAA,EACL,KACC,kBAAC,GAAD;MACE,MAAK;MACL,SAAS;MACT,UAAU,CAAC,EAAI,cAAc;MAC7B,kBAAkB,MAAM,EAAI,eAAe,CAAC,CAAC,EAAE;MAC/C,cAAW;MACX,WAAU;MACV,CAAA,CAEA;QAGL,EAAU,SAAS,KAClB,kBAAC,OAAD;KAAK,WAAU;eACZ,EAAU,KAAK,MAAS;MAEvB,IAAM,IAAO,EAAK,OAAO,UAAU;AAiBnC,aAXI,GAAM,cAAc,QAAQ,GAAM,WAYpC,kBAAC,OAAD;OAAmB,WAAU;iBAA7B,CACE,kBAAC,QAAD;QAAM,WAAU;kBANlB,OAAO,EAAK,OAAO,UAAU,UAAW,WACpC,EAAK,OAAO,UAAU,SACtB,EAAK,OAAO;QAIkD,CAAA,EAChE,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAW,EAAK,OAAO,UAAU,MAAM,EAAK,YAAY,CAAC;QACrD,CAAA,CACH;SALI,EAAK,GAKT;OAER;KACE,CAAA,CAEJ;MA1DC,EAAI,GA0DL;IAER;EACE,CAAA,GAjFJ,kBAAC,OAAD;EAAK,WAAW,EAAG,wBAAwB,CAAC,KAAc,yBAAyB;YAChF,KAAc,KAAiB;EAC5B,CAAA"}
|