@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/file-upload.js
CHANGED
|
@@ -1,127 +1,127 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { a as e, c as t } from "../_chunks/framer.js";
|
|
3
|
-
import {
|
|
4
|
-
import { cn as
|
|
5
|
-
import { Spinner as
|
|
6
|
-
import { Icon as
|
|
7
|
-
import * as
|
|
8
|
-
import { jsx as
|
|
9
|
-
import { IconCheck as
|
|
3
|
+
import { durations as n, springs as r, tweens as i } from "./lib/motion.js";
|
|
4
|
+
import { cn as a } from "./lib/utils.js";
|
|
5
|
+
import { Spinner as o } from "./spinner.js";
|
|
6
|
+
import { Icon as s } from "./icon.js";
|
|
7
|
+
import * as c from "react";
|
|
8
|
+
import { jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
9
|
+
import { IconCheck as d, IconPaperclip as f, IconUpload as p } from "@tabler/icons-react";
|
|
10
10
|
//#region src/ui/file-upload.tsx
|
|
11
|
-
var
|
|
12
|
-
function
|
|
11
|
+
var m = 10 * 1024 * 1024;
|
|
12
|
+
function h(e, t) {
|
|
13
13
|
return t.split(",").map((e) => e.trim()).some((t) => t.startsWith(".") ? e.name.toLowerCase().endsWith(t.toLowerCase()) : t.endsWith("/*") ? e.type.startsWith(t.slice(0, t.indexOf("/") + 1)) : e.type === t);
|
|
14
14
|
}
|
|
15
|
-
function
|
|
15
|
+
function g(e) {
|
|
16
16
|
return e < 1024 ? `${e} B` : e < 1024 * 1024 ? `${(e / 1024).toFixed(1)} KB` : `${(e / (1024 * 1024)).toFixed(1)} MB`;
|
|
17
17
|
}
|
|
18
|
-
var
|
|
19
|
-
let
|
|
20
|
-
|
|
21
|
-
}, [
|
|
22
|
-
|
|
18
|
+
var _ = c.forwardRef(({ accept: _, maxSize: v = m, multiple: y = !1, uploading: b = !1, progress: x = 0, onFiles: S, error: C, compact: w = !1, disabled: T = !1, className: E, label: D, sublabel: O, ...k }, A) => {
|
|
19
|
+
let j = c.useRef(null), [M, N] = c.useState(!1), [P, F] = c.useState(null), I = c.useRef(!1), L = c.useRef(!1), R = C || P, z = c.useCallback(() => {
|
|
20
|
+
T || b || j.current?.click();
|
|
21
|
+
}, [T, b]), B = c.useCallback((e) => {
|
|
22
|
+
F(null);
|
|
23
23
|
for (let t of e) {
|
|
24
|
-
if (t.size >
|
|
25
|
-
|
|
24
|
+
if (t.size > v) {
|
|
25
|
+
F(`File "${t.name}" exceeds the maximum size of ${g(v)}`);
|
|
26
26
|
return;
|
|
27
27
|
}
|
|
28
|
-
if (
|
|
29
|
-
|
|
28
|
+
if (_ && !h(t, _)) {
|
|
29
|
+
F(`File "${t.name}" is not an accepted file type`);
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
S(e);
|
|
34
34
|
}, [
|
|
35
|
+
v,
|
|
35
36
|
_,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
I.current = !0;
|
|
37
|
+
S
|
|
38
|
+
]), V = c.useCallback((e) => {
|
|
39
|
+
L.current = !0;
|
|
40
40
|
let t = e.target.files;
|
|
41
|
-
!t || t.length === 0 || (
|
|
42
|
-
}, [
|
|
43
|
-
|
|
44
|
-
}, []),
|
|
45
|
-
|
|
46
|
-
}, [
|
|
47
|
-
e.preventDefault(), e.stopPropagation(), !
|
|
48
|
-
}, [
|
|
49
|
-
e.preventDefault(), e.stopPropagation(), !
|
|
50
|
-
}, [
|
|
51
|
-
e.preventDefault(), e.stopPropagation(),
|
|
52
|
-
}, []),
|
|
53
|
-
if (e.preventDefault(), e.stopPropagation(),
|
|
41
|
+
!t || t.length === 0 || (B(Array.from(t)), e.target.value = "");
|
|
42
|
+
}, [B]), H = c.useCallback(() => {
|
|
43
|
+
I.current = !0, L.current = !1;
|
|
44
|
+
}, []), U = c.useCallback(() => {
|
|
45
|
+
I.current && !L.current && _ && F("File type is not accepted"), I.current = !1;
|
|
46
|
+
}, [_]), W = c.useCallback((e) => {
|
|
47
|
+
e.preventDefault(), e.stopPropagation(), !T && !b && N(!0);
|
|
48
|
+
}, [T, b]), G = c.useCallback((e) => {
|
|
49
|
+
e.preventDefault(), e.stopPropagation(), !T && !b && N(!0);
|
|
50
|
+
}, [T, b]), K = c.useCallback((e) => {
|
|
51
|
+
e.preventDefault(), e.stopPropagation(), N(!1);
|
|
52
|
+
}, []), q = c.useCallback((e) => {
|
|
53
|
+
if (e.preventDefault(), e.stopPropagation(), N(!1), T || b) return;
|
|
54
54
|
let t = e.dataTransfer.files;
|
|
55
|
-
!t || t.length === 0 ||
|
|
55
|
+
!t || t.length === 0 || B(Array.from(t));
|
|
56
56
|
}, [
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
]),
|
|
61
|
-
return
|
|
62
|
-
ref:
|
|
63
|
-
className:
|
|
64
|
-
...
|
|
57
|
+
T,
|
|
58
|
+
b,
|
|
59
|
+
B
|
|
60
|
+
]), J = D ?? "Drop files here or click to browse", Y = O ?? `Max file size: ${g(v)}`, X = c.useId();
|
|
61
|
+
return w ? /* @__PURE__ */ u("div", {
|
|
62
|
+
ref: A,
|
|
63
|
+
className: a("inline-flex flex-col", E),
|
|
64
|
+
...k,
|
|
65
65
|
children: [
|
|
66
|
-
/* @__PURE__ */
|
|
66
|
+
/* @__PURE__ */ u("button", {
|
|
67
67
|
type: "button",
|
|
68
|
-
onClick:
|
|
69
|
-
disabled:
|
|
70
|
-
className:
|
|
71
|
-
children: [
|
|
72
|
-
icon:
|
|
68
|
+
onClick: z,
|
|
69
|
+
disabled: T,
|
|
70
|
+
className: a("inline-flex items-center gap-ds-02 rounded-ds-md px-ds-03 py-ds-02", "text-ds-sm font-medium", "border border-surface-border-strong", "bg-surface-raised-hover text-surface-fg-muted", "hover:bg-accent-2", "disabled:opacity-action-disabled disabled:cursor-not-allowed", "transition-colors"),
|
|
71
|
+
children: [b ? /* @__PURE__ */ l(o, { size: "sm" }) : /* @__PURE__ */ l(s, {
|
|
72
|
+
icon: f,
|
|
73
73
|
size: "sm"
|
|
74
|
-
}),
|
|
74
|
+
}), D ?? "Attach files"]
|
|
75
75
|
}),
|
|
76
|
-
/* @__PURE__ */
|
|
77
|
-
ref:
|
|
78
|
-
id:
|
|
76
|
+
/* @__PURE__ */ l("input", {
|
|
77
|
+
ref: j,
|
|
78
|
+
id: X,
|
|
79
79
|
type: "file",
|
|
80
80
|
className: "sr-only",
|
|
81
81
|
style: { visibility: "hidden" },
|
|
82
82
|
"aria-hidden": "true",
|
|
83
|
-
"aria-label":
|
|
84
|
-
accept:
|
|
85
|
-
multiple:
|
|
86
|
-
disabled:
|
|
87
|
-
onChange:
|
|
88
|
-
onClick:
|
|
89
|
-
onFocus:
|
|
83
|
+
"aria-label": D ?? "Attach files",
|
|
84
|
+
accept: _,
|
|
85
|
+
multiple: y,
|
|
86
|
+
disabled: T,
|
|
87
|
+
onChange: V,
|
|
88
|
+
onClick: H,
|
|
89
|
+
onFocus: U,
|
|
90
90
|
tabIndex: -1
|
|
91
91
|
}),
|
|
92
|
-
|
|
92
|
+
R && /* @__PURE__ */ l("p", {
|
|
93
93
|
role: "alert",
|
|
94
94
|
"aria-live": "polite",
|
|
95
95
|
className: "mt-ds-02 text-ds-xs text-error-11",
|
|
96
|
-
children:
|
|
96
|
+
children: R
|
|
97
97
|
})
|
|
98
98
|
]
|
|
99
|
-
}) : /* @__PURE__ */
|
|
100
|
-
ref:
|
|
101
|
-
...
|
|
99
|
+
}) : /* @__PURE__ */ u("div", {
|
|
100
|
+
ref: A,
|
|
101
|
+
...k,
|
|
102
102
|
role: "presentation",
|
|
103
|
-
className:
|
|
104
|
-
"data-drag-active":
|
|
105
|
-
onDragEnter:
|
|
106
|
-
onDragOver:
|
|
107
|
-
onDragLeave:
|
|
108
|
-
onDrop:
|
|
103
|
+
className: a("flex flex-col", E),
|
|
104
|
+
"data-drag-active": M ? "true" : void 0,
|
|
105
|
+
onDragEnter: W,
|
|
106
|
+
onDragOver: G,
|
|
107
|
+
onDragLeave: K,
|
|
108
|
+
onDrop: q,
|
|
109
109
|
children: [
|
|
110
|
-
/* @__PURE__ */
|
|
110
|
+
/* @__PURE__ */ u(e.div, {
|
|
111
111
|
role: "button",
|
|
112
112
|
tabIndex: 0,
|
|
113
|
-
"aria-disabled":
|
|
114
|
-
onClick:
|
|
113
|
+
"aria-disabled": T || void 0,
|
|
114
|
+
onClick: T ? void 0 : z,
|
|
115
115
|
onKeyDown: (e) => {
|
|
116
|
-
!
|
|
116
|
+
!T && (e.key === "Enter" || e.key === " ") && (e.preventDefault(), z());
|
|
117
117
|
},
|
|
118
|
-
className:
|
|
119
|
-
animate: { scale:
|
|
120
|
-
transition:
|
|
118
|
+
className: a("flex flex-col items-center justify-center gap-ds-03 rounded-ds-lg", "border-2 border-dashed p-ds-08", "cursor-pointer", "border-surface-border-strong bg-surface-raised-hover", M && "border-accent-7 bg-accent-2", T && "opacity-action-disabled cursor-not-allowed"),
|
|
119
|
+
animate: { scale: M ? 1.02 : 1 },
|
|
120
|
+
transition: r.snappy,
|
|
121
121
|
children: [
|
|
122
|
-
/* @__PURE__ */
|
|
122
|
+
/* @__PURE__ */ l(t, {
|
|
123
123
|
mode: "wait",
|
|
124
|
-
children:
|
|
124
|
+
children: b ? /* @__PURE__ */ l(e.div, {
|
|
125
125
|
initial: {
|
|
126
126
|
opacity: 0,
|
|
127
127
|
scale: .5
|
|
@@ -134,9 +134,9 @@ var g = s.forwardRef(({ accept: g, maxSize: _ = p, multiple: v = !1, uploading:
|
|
|
134
134
|
opacity: 0,
|
|
135
135
|
scale: .5
|
|
136
136
|
},
|
|
137
|
-
transition:
|
|
138
|
-
children: /* @__PURE__ */
|
|
139
|
-
}, "spinner") :
|
|
137
|
+
transition: i.fade,
|
|
138
|
+
children: /* @__PURE__ */ l(o, { size: "md" })
|
|
139
|
+
}, "spinner") : x === 100 && !C ? /* @__PURE__ */ l(e.div, {
|
|
140
140
|
initial: {
|
|
141
141
|
opacity: 0,
|
|
142
142
|
scale: .5
|
|
@@ -149,66 +149,66 @@ var g = s.forwardRef(({ accept: g, maxSize: _ = p, multiple: v = !1, uploading:
|
|
|
149
149
|
opacity: 0,
|
|
150
150
|
scale: .5
|
|
151
151
|
},
|
|
152
|
-
transition:
|
|
153
|
-
children: /* @__PURE__ */
|
|
154
|
-
icon:
|
|
152
|
+
transition: r.bouncy,
|
|
153
|
+
children: /* @__PURE__ */ l(s, {
|
|
154
|
+
icon: d,
|
|
155
155
|
size: "2xl",
|
|
156
156
|
className: "text-success-11"
|
|
157
157
|
})
|
|
158
|
-
}, "complete") : /* @__PURE__ */
|
|
158
|
+
}, "complete") : /* @__PURE__ */ l(e.div, {
|
|
159
159
|
initial: { opacity: 0 },
|
|
160
160
|
animate: { opacity: 1 },
|
|
161
161
|
exit: { opacity: 0 },
|
|
162
|
-
transition:
|
|
163
|
-
children: /* @__PURE__ */
|
|
164
|
-
icon:
|
|
162
|
+
transition: i.fade,
|
|
163
|
+
children: /* @__PURE__ */ l(s, {
|
|
164
|
+
icon: p,
|
|
165
165
|
size: "2xl",
|
|
166
166
|
className: "text-surface-fg-subtle"
|
|
167
167
|
})
|
|
168
168
|
}, "upload")
|
|
169
169
|
}),
|
|
170
|
-
/* @__PURE__ */
|
|
171
|
-
id:
|
|
170
|
+
/* @__PURE__ */ l("span", {
|
|
171
|
+
id: X + "-label",
|
|
172
172
|
className: "text-ds-sm text-surface-fg-muted",
|
|
173
|
-
children:
|
|
173
|
+
children: J
|
|
174
174
|
}),
|
|
175
|
-
|
|
175
|
+
b ? /* @__PURE__ */ l("div", {
|
|
176
176
|
className: "w-full max-w-xs",
|
|
177
|
-
children: /* @__PURE__ */
|
|
177
|
+
children: /* @__PURE__ */ l("div", {
|
|
178
178
|
role: "progressbar",
|
|
179
|
-
"aria-valuenow":
|
|
179
|
+
"aria-valuenow": x,
|
|
180
180
|
"aria-valuemin": 0,
|
|
181
181
|
"aria-valuemax": 100,
|
|
182
182
|
className: "h-2 w-full overflow-hidden rounded-ds-full bg-surface-raised-hover",
|
|
183
|
-
children: /* @__PURE__ */
|
|
183
|
+
children: /* @__PURE__ */ l(e.div, {
|
|
184
184
|
className: "h-full rounded-ds-full bg-accent-9",
|
|
185
|
-
animate: { width: `${
|
|
186
|
-
transition:
|
|
185
|
+
animate: { width: `${x}%` },
|
|
186
|
+
transition: r.smooth
|
|
187
187
|
})
|
|
188
188
|
})
|
|
189
|
-
}) : /* @__PURE__ */
|
|
189
|
+
}) : /* @__PURE__ */ l("span", {
|
|
190
190
|
className: "text-ds-xs text-surface-fg-subtle",
|
|
191
|
-
children:
|
|
191
|
+
children: Y
|
|
192
192
|
})
|
|
193
193
|
]
|
|
194
194
|
}),
|
|
195
|
-
/* @__PURE__ */
|
|
196
|
-
ref:
|
|
197
|
-
id:
|
|
195
|
+
/* @__PURE__ */ l("input", {
|
|
196
|
+
ref: j,
|
|
197
|
+
id: X,
|
|
198
198
|
type: "file",
|
|
199
199
|
className: "sr-only",
|
|
200
200
|
style: { visibility: "hidden" },
|
|
201
201
|
"aria-hidden": "true",
|
|
202
|
-
"aria-label":
|
|
203
|
-
accept:
|
|
204
|
-
multiple:
|
|
205
|
-
disabled:
|
|
206
|
-
onChange:
|
|
207
|
-
onClick:
|
|
208
|
-
onFocus:
|
|
202
|
+
"aria-label": J,
|
|
203
|
+
accept: _,
|
|
204
|
+
multiple: y,
|
|
205
|
+
disabled: T,
|
|
206
|
+
onChange: V,
|
|
207
|
+
onClick: H,
|
|
208
|
+
onFocus: U,
|
|
209
209
|
tabIndex: -1
|
|
210
210
|
}),
|
|
211
|
-
/* @__PURE__ */
|
|
211
|
+
/* @__PURE__ */ l(t, { children: R && /* @__PURE__ */ l(e.p, {
|
|
212
212
|
role: "alert",
|
|
213
213
|
className: "mt-ds-02 text-ds-xs text-error-11",
|
|
214
214
|
initial: {
|
|
@@ -228,18 +228,18 @@ var g = s.forwardRef(({ accept: g, maxSize: _ = p, multiple: v = !1, uploading:
|
|
|
228
228
|
},
|
|
229
229
|
exit: { opacity: 0 },
|
|
230
230
|
transition: {
|
|
231
|
-
opacity:
|
|
231
|
+
opacity: i.fade,
|
|
232
232
|
x: {
|
|
233
233
|
type: "tween",
|
|
234
|
-
duration: .
|
|
234
|
+
duration: n.slow01,
|
|
235
235
|
ease: "easeOut"
|
|
236
236
|
}
|
|
237
237
|
},
|
|
238
|
-
children:
|
|
238
|
+
children: R
|
|
239
239
|
}) })
|
|
240
240
|
]
|
|
241
241
|
});
|
|
242
242
|
});
|
|
243
|
-
|
|
243
|
+
_.displayName = "FileUpload";
|
|
244
244
|
//#endregion
|
|
245
|
-
export {
|
|
245
|
+
export { _ as FileUpload };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-upload.js","names":[],"sources":["../../src/ui/file-upload.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { motion, AnimatePresence } from 'framer-motion'\nimport { IconUpload, IconPaperclip, IconCheck } from '@tabler/icons-react'\nimport { cn } from './lib/utils'\nimport { springs, tweens, durations } from './lib/motion'\nimport { Spinner } from './spinner'\nimport { Icon } from './icon'\n\n/**\n * Props for FileUpload — a drag-and-drop file picker with client-side validation (type + size),\n * an upload progress bar, and a compact inline mode.\n *\n * **Two modes:**\n * - Default: large drop zone with an upload icon, label, and sublabel — good for primary upload areas.\n * - `compact={true}`: a small inline button with an attachment icon — good for secondary/inline uploads.\n *\n * **Validation:** Pass `accept` (MIME or extension) and `maxSize` (bytes). Errors are shown inline.\n * The `onFiles` callback only fires with valid files — invalid files are rejected with an error message.\n *\n * **`onFiles` required:** This is the only required prop. Integrating with a real uploader means\n * calling your upload API from this callback and driving `uploading` + `progress` externally.\n *\n * @example\n * // Avatar upload with image-only restriction:\n * <FileUpload\n * accept=\"image/*\"\n * maxSize={2 * 1024 * 1024}\n * onFiles={(files) => uploadAvatar(files[0])}\n * label=\"Upload profile photo\"\n * sublabel=\"PNG, JPG up to 2MB\"\n * />\n *\n * @example\n * // Document multi-upload with progress:\n * <FileUpload\n * multiple\n * accept=\".pdf,.doc,.docx\"\n * uploading={isUploading}\n * progress={uploadPercent}\n * onFiles={handleFiles}\n * />\n *\n * @example\n * // Compact inline attachment button in a comment form:\n * <FileUpload compact onFiles={(files) => attachFiles(files)} label=\"Attach files\" />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface FileUploadProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onError'> {\n /** Accepted file types (e.g., \"image/*\", \".pdf,.doc\") */\n accept?: string\n /** Max file size in bytes (default: 10MB) */\n maxSize?: number\n /** Allow multiple files */\n multiple?: boolean\n /** Currently uploading */\n uploading?: boolean\n /** Upload progress (0-100) */\n progress?: number\n /** Callback when files are selected/dropped */\n onFiles: (files: File[]) => void\n /** Error message to display */\n error?: string\n /** Compact mode (inline button instead of drop zone) */\n compact?: boolean\n /** Disabled */\n disabled?: boolean\n /** Custom label */\n label?: string\n /** Custom sublabel */\n sublabel?: string\n}\n\nconst DEFAULT_MAX_SIZE = 10 * 1024 * 1024 // 10MB\n\nfunction fileMatchesAccept(file: File, accept: string): boolean {\n return accept\n .split(',')\n .map((t) => t.trim())\n .some((type) => {\n if (type.startsWith('.'))\n return file.name.toLowerCase().endsWith(type.toLowerCase())\n if (type.endsWith('/*'))\n return file.type.startsWith(type.slice(0, type.indexOf('/') + 1))\n return file.type === type\n })\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\nconst FileUpload = React.forwardRef<HTMLDivElement, FileUploadProps>(\n (\n {\n accept,\n maxSize = DEFAULT_MAX_SIZE,\n multiple = false,\n uploading = false,\n progress = 0,\n onFiles,\n error,\n compact = false,\n disabled = false,\n className,\n label,\n sublabel,\n ...props\n },\n ref,\n ) => {\n const inputRef = React.useRef<HTMLInputElement>(null)\n const [isDragActive, setIsDragActive] = React.useState(false)\n const [validationError, setValidationError] = React.useState<string | null>(\n null,\n )\n // Track whether a file dialog was opened, so we can detect when the\n // browser (or testing library) filters out all files via the accept attribute\n const dialogOpenRef = React.useRef(false)\n const filesAcceptedRef = React.useRef(false)\n\n const displayError = error || validationError\n\n const openPicker = React.useCallback(() => {\n if (disabled || uploading) return\n inputRef.current?.click()\n }, [disabled, uploading])\n\n const validateAndEmit = React.useCallback(\n (files: File[]) => {\n setValidationError(null)\n\n for (const file of files) {\n if (file.size > maxSize) {\n setValidationError(\n `File \"${file.name}\" exceeds the maximum size of ${formatBytes(maxSize)}`,\n )\n return\n }\n if (accept && !fileMatchesAccept(file, accept)) {\n setValidationError(\n `File \"${file.name}\" is not an accepted file type`,\n )\n return\n }\n }\n\n onFiles(files)\n },\n [maxSize, accept, onFiles],\n )\n\n const handleInputChange = React.useCallback(\n (e: React.ChangeEvent<HTMLInputElement>) => {\n filesAcceptedRef.current = true\n const fileList = e.target.files\n if (!fileList || fileList.length === 0) return\n validateAndEmit(Array.from(fileList))\n // Reset input value so the same file can be selected again\n e.target.value = ''\n },\n [validateAndEmit],\n )\n\n // When the file input is clicked, the browser opens a dialog and blurs the input.\n // We track this to detect when the dialog closes without selecting valid files.\n const handleInputClick = React.useCallback(() => {\n dialogOpenRef.current = true\n filesAcceptedRef.current = false\n }, [])\n\n // After the file dialog closes, the browser re-focuses the input.\n // If no files were accepted (e.g., the browser/test library filtered by accept),\n // and the accept prop is set, show a validation error.\n const handleInputFocus = React.useCallback(() => {\n if (dialogOpenRef.current && !filesAcceptedRef.current && accept) {\n setValidationError('File type is not accepted')\n }\n dialogOpenRef.current = false\n }, [accept])\n\n const handleDragEnter = React.useCallback(\n (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault()\n e.stopPropagation()\n if (!disabled && !uploading) {\n setIsDragActive(true)\n }\n },\n [disabled, uploading],\n )\n\n const handleDragOver = React.useCallback(\n (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault()\n e.stopPropagation()\n if (!disabled && !uploading) {\n setIsDragActive(true)\n }\n },\n [disabled, uploading],\n )\n\n const handleDragLeave = React.useCallback(\n (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault()\n e.stopPropagation()\n setIsDragActive(false)\n },\n [],\n )\n\n const handleDrop = React.useCallback(\n (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault()\n e.stopPropagation()\n setIsDragActive(false)\n\n if (disabled || uploading) return\n\n const fileList = e.dataTransfer.files\n if (!fileList || fileList.length === 0) return\n validateAndEmit(Array.from(fileList))\n },\n [disabled, uploading, validateAndEmit],\n )\n\n const defaultLabel = label ?? 'Drop files here or click to browse'\n const defaultSublabel = sublabel ?? `Max file size: ${formatBytes(maxSize)}`\n const inputId = React.useId()\n\n if (compact) {\n return (\n <div ref={ref} className={cn('inline-flex flex-col', className)} {...props}>\n <button\n type=\"button\"\n onClick={openPicker}\n disabled={disabled}\n className={cn(\n 'inline-flex items-center gap-ds-02 rounded-ds-md px-ds-03 py-ds-02',\n 'text-ds-sm font-medium',\n 'border border-surface-border-strong',\n 'bg-surface-raised-hover text-surface-fg-muted',\n 'hover:bg-accent-2',\n 'disabled:opacity-action-disabled disabled:cursor-not-allowed',\n 'transition-colors',\n )}\n >\n {uploading ? (\n <Spinner size=\"sm\" />\n ) : (\n <Icon icon={IconPaperclip} size=\"sm\" />\n )}\n {label ?? 'Attach files'}\n </button>\n <input\n ref={inputRef}\n id={inputId}\n type=\"file\"\n className=\"sr-only\"\n style={{ visibility: 'hidden' }}\n aria-hidden=\"true\"\n aria-label={label ?? 'Attach files'}\n accept={accept}\n multiple={multiple}\n disabled={disabled}\n onChange={handleInputChange}\n onClick={handleInputClick}\n onFocus={handleInputFocus}\n tabIndex={-1}\n />\n {displayError && (\n <p\n role=\"alert\"\n aria-live=\"polite\"\n className=\"mt-ds-02 text-ds-xs text-error-11\"\n >\n {displayError}\n </p>\n )}\n </div>\n )\n }\n\n return (\n <div\n ref={ref}\n {...props}\n role=\"presentation\"\n className={cn('flex flex-col', className)}\n data-drag-active={isDragActive ? 'true' : undefined}\n onDragEnter={handleDragEnter}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n >\n <motion.div\n role=\"button\"\n tabIndex={0}\n aria-disabled={disabled || undefined}\n onClick={disabled ? undefined : openPicker}\n onKeyDown={(e: React.KeyboardEvent<HTMLDivElement>) => {\n if (!disabled && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault()\n openPicker()\n }\n }}\n className={cn(\n 'flex flex-col items-center justify-center gap-ds-03 rounded-ds-lg',\n 'border-2 border-dashed p-ds-08',\n 'cursor-pointer',\n 'border-surface-border-strong bg-surface-raised-hover',\n isDragActive &&\n 'border-accent-7 bg-accent-2',\n disabled && 'opacity-action-disabled cursor-not-allowed',\n )}\n animate={{\n scale: isDragActive ? 1.02 : 1,\n }}\n transition={springs.snappy}\n >\n {/* Icon — animates between upload ↔ spinner ↔ checkmark */}\n <AnimatePresence mode=\"wait\">\n {uploading ? (\n <motion.div\n key=\"spinner\"\n initial={{ opacity: 0, scale: 0.5 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.5 }}\n transition={tweens.fade}\n >\n <Spinner size=\"md\" />\n </motion.div>\n ) : progress === 100 && !error ? (\n <motion.div\n key=\"complete\"\n initial={{ opacity: 0, scale: 0.5 }}\n animate={{ opacity: 1, scale: 1 }}\n exit={{ opacity: 0, scale: 0.5 }}\n transition={springs.bouncy}\n >\n <Icon icon={IconCheck} size=\"2xl\" className=\"text-success-11\" />\n </motion.div>\n ) : (\n <motion.div\n key=\"upload\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={tweens.fade}\n >\n <Icon icon={IconUpload} size=\"2xl\" className=\"text-surface-fg-subtle\" />\n </motion.div>\n )}\n </AnimatePresence>\n <span id={inputId + '-label'} className=\"text-ds-sm text-surface-fg-muted\">\n {defaultLabel}\n </span>\n {uploading ? (\n <div className=\"w-full max-w-xs\">\n <div\n role=\"progressbar\"\n aria-valuenow={progress}\n aria-valuemin={0}\n aria-valuemax={100}\n className=\"h-2 w-full overflow-hidden rounded-ds-full bg-surface-raised-hover\"\n >\n <motion.div\n className=\"h-full rounded-ds-full bg-accent-9\"\n animate={{ width: `${progress}%` }}\n transition={springs.smooth}\n />\n </div>\n </div>\n ) : (\n <span className=\"text-ds-xs text-surface-fg-subtle\">\n {defaultSublabel}\n </span>\n )}\n </motion.div>\n <input\n ref={inputRef}\n id={inputId}\n type=\"file\"\n className=\"sr-only\"\n style={{ visibility: 'hidden' }}\n aria-hidden=\"true\"\n aria-label={defaultLabel}\n accept={accept}\n multiple={multiple}\n disabled={disabled}\n onChange={handleInputChange}\n onClick={handleInputClick}\n onFocus={handleInputFocus}\n tabIndex={-1}\n />\n {/* Error message with shake animation */}\n <AnimatePresence>\n {displayError && (\n <motion.p\n role=\"alert\"\n className=\"mt-ds-02 text-ds-xs text-error-11\"\n initial={{ opacity: 0, x: 0 }}\n animate={{ opacity: 1, x: [0, -4, 4, -4, 4, 0] }}\n exit={{ opacity: 0 }}\n transition={{ opacity: tweens.fade, x: { type: 'tween', duration: durations.slow01, ease: 'easeOut' } }}\n >\n {displayError}\n </motion.p>\n )}\n </AnimatePresence>\n </div>\n )\n },\n)\nFileUpload.displayName = 'FileUpload'\n\nexport { FileUpload }\n"],"mappings":"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"}
|
package/dist/ui/form.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export type FormHelperState = 'helper' | 'error' | 'warning' | 'success';
|
|
|
4
4
|
interface FormFieldContextValue {
|
|
5
5
|
state?: FormHelperState;
|
|
6
6
|
helperTextId?: string;
|
|
7
|
+
/** Auto-generated id shared between Label (htmlFor) and the field input (id). */
|
|
8
|
+
inputId?: string;
|
|
7
9
|
required?: boolean;
|
|
8
10
|
}
|
|
9
11
|
declare const FormFieldContext: React.Context<FormFieldContextValue>;
|
|
@@ -28,6 +30,12 @@ export interface FormFieldProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
|
28
30
|
* Pass this to `useFormField()` consumers that need to set `aria-describedby`.
|
|
29
31
|
*/
|
|
30
32
|
helperTextId?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Custom ID for the field input element. If omitted, an auto-generated ID is used.
|
|
35
|
+
* Label (when inside FormField) reads this via `htmlFor`; Input reads it via `id`.
|
|
36
|
+
* Explicit `htmlFor` / `id` props on children always win.
|
|
37
|
+
*/
|
|
38
|
+
inputId?: string;
|
|
31
39
|
/** Current validation state — propagated to child `FormHelperText` via context */
|
|
32
40
|
state?: FormHelperState;
|
|
33
41
|
/** Whether the field is required — available to children via `useFormField()` */
|
package/dist/ui/form.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../src/ui/form.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAA;AAExE,UAAU,qBAAqB;IAC7B,KAAK,CAAC,EAAE,eAAe,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AACD,QAAA,MAAM,gBAAgB,sCAAiD,CAAA;AAEvE;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,cAAe,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC1E;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,kFAAkF;IAClF,KAAK,CAAC,EAAE,eAAe,CAAA;IACvB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,QAAA,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"form.d.ts","sourceRoot":"","sources":["../../src/ui/form.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAA;AAExE,UAAU,qBAAqB;IAC7B,KAAK,CAAC,EAAE,eAAe,CAAA;IACvB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iFAAiF;IACjF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AACD,QAAA,MAAM,gBAAgB,sCAAiD,CAAA;AAEvE;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,cAAe,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC1E;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,kFAAkF;IAClF,KAAK,CAAC,EAAE,eAAe,CAAA;IACvB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,QAAA,MAAM,SAAS,uFAsBd,CAAA;AAMD,MAAM,WAAW,mBAAoB,SAAQ,KAAK,CAAC,cAAc,CAAC,oBAAoB,CAAC;IACrF,KAAK,CAAC,EAAE,eAAe,CAAA;CACxB;AASD,QAAA,MAAM,cAAc,kGAoBnB,CAAA;AAGD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,YAAY,IAAI,qBAAqB,CAEpD;AAED,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,cAAc,EAAE,CAAA"}
|
package/dist/ui/form.js
CHANGED
|
@@ -5,23 +5,25 @@ import { cn as r } from "./lib/utils.js";
|
|
|
5
5
|
import * as i from "react";
|
|
6
6
|
import { jsx as a } from "react/jsx-runtime";
|
|
7
7
|
//#region src/ui/form.tsx
|
|
8
|
-
var o = i.createContext({}), s = i.forwardRef(({ className: e, helperTextId: t,
|
|
9
|
-
let
|
|
10
|
-
state:
|
|
11
|
-
helperTextId:
|
|
12
|
-
|
|
8
|
+
var o = i.createContext({}), s = i.forwardRef(({ className: e, helperTextId: t, inputId: n, state: s = "helper", required: c, children: l, ...u }, d) => {
|
|
9
|
+
let f = i.useId(), p = t || `${f}-helper`, m = n || `${f}-input`, h = i.useMemo(() => ({
|
|
10
|
+
state: s,
|
|
11
|
+
helperTextId: p,
|
|
12
|
+
inputId: m,
|
|
13
|
+
required: c
|
|
13
14
|
}), [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
s,
|
|
16
|
+
p,
|
|
17
|
+
m,
|
|
18
|
+
c
|
|
17
19
|
]);
|
|
18
20
|
return /* @__PURE__ */ a(o.Provider, {
|
|
19
|
-
value:
|
|
21
|
+
value: h,
|
|
20
22
|
children: /* @__PURE__ */ a("div", {
|
|
21
|
-
ref:
|
|
23
|
+
ref: d,
|
|
22
24
|
className: r("flex flex-col gap-ds-02", e),
|
|
23
|
-
...
|
|
24
|
-
children:
|
|
25
|
+
...u,
|
|
26
|
+
children: l
|
|
25
27
|
})
|
|
26
28
|
});
|
|
27
29
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.js","names":[],"sources":["../../src/ui/form.tsx"],"sourcesContent":["'use client'\n\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\nimport { motionProps, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\n\nexport type FormHelperState = 'helper' | 'error' | 'warning' | 'success'\n\ninterface FormFieldContextValue {\n state?: FormHelperState\n helperTextId?: string\n /** Auto-generated id shared between Label (htmlFor) and the field input (id). */\n inputId?: string\n required?: boolean\n}\nconst FormFieldContext = React.createContext<FormFieldContextValue>({})\n\n/**\n * FormField — vertical flex container that provides validation state and\n * aria-describedby wiring to children via React context.\n *\n * **Automatic a11y wiring:** FormField generates a stable ID (or uses a provided `helperTextId`)\n * and passes it to `FormHelperText` via context. Use the `useFormField()` hook in custom inputs\n * to read `{ state, helperTextId, required }` and spread onto your input element.\n *\n * @example\n * <FormField state=\"error\">\n * <Label htmlFor=\"email\">Email</Label>\n * <Input id=\"email\" state=\"error\" />\n * <FormHelperText>Please enter a valid email address.</FormHelperText>\n * </FormField>\n */\nexport interface FormFieldProps extends React.HTMLAttributes<HTMLDivElement> {\n /**\n * Custom ID for the helper text element. If omitted, an auto-generated ID is used.\n * Pass this to `useFormField()` consumers that need to set `aria-describedby`.\n */\n helperTextId?: string\n /**\n * Custom ID for the field input element. If omitted, an auto-generated ID is used.\n * Label (when inside FormField) reads this via `htmlFor`; Input reads it via `id`.\n * Explicit `htmlFor` / `id` props on children always win.\n */\n inputId?: string\n /** Current validation state — propagated to child `FormHelperText` via context */\n state?: FormHelperState\n /** Whether the field is required — available to children via `useFormField()` */\n required?: boolean\n}\n\nconst FormField = React.forwardRef<HTMLDivElement, FormFieldProps>(\n ({ className, helperTextId, inputId, state = 'helper', required, children, ...props }, ref) => {\n const autoId = React.useId()\n const resolvedHelperId = helperTextId || `${autoId}-helper`\n const resolvedInputId = inputId || `${autoId}-input`\n const contextValue = React.useMemo(\n () => ({ state, helperTextId: resolvedHelperId, inputId: resolvedInputId, required }),\n [state, resolvedHelperId, resolvedInputId, required],\n )\n\n return (\n <FormFieldContext.Provider value={contextValue}>\n <div\n ref={ref}\n className={cn('flex flex-col gap-ds-02', className)}\n {...props}\n >\n {children}\n </div>\n </FormFieldContext.Provider>\n )\n },\n)\nFormField.displayName = 'FormField'\n\n// FormHelperText — small helper/error/warning/success message under a field\n//\n// When used for errors, set an `id` matching the input's `aria-describedby`.\nexport interface FormHelperTextProps extends React.HTMLAttributes<HTMLParagraphElement> {\n state?: FormHelperState\n}\n\nconst helperStateClasses: Record<FormHelperState, string> = {\n helper: 'text-surface-fg-subtle',\n error: 'text-error-11',\n warning: 'text-warning-11',\n success: 'text-success-11',\n}\n\nconst FormHelperText = React.forwardRef<HTMLParagraphElement, FormHelperTextProps>(\n ({ className, id: idProp, state: stateProp, ...props }, ref) => {\n const context = React.useContext(FormFieldContext)\n const state = stateProp ?? context.state ?? 'helper'\n const id = idProp ?? context.helperTextId\n\n return (\n <motion.p\n ref={ref}\n id={id}\n role={state === 'error' ? 'alert' : undefined}\n className={cn('text-ds-sm', helperStateClasses[state], className)}\n initial={{ opacity: 0, y: -4 }}\n animate={{ opacity: 1, y: 0 }}\n exit={{ opacity: 0, y: -4 }}\n transition={tweens.fade}\n {...motionProps(props)}\n />\n )\n },\n)\nFormHelperText.displayName = 'FormHelperText'\n\n/**\n * Hook to read FormField context — returns `{ state, helperTextId, required }`.\n * Use in custom input components to auto-wire `aria-describedby` and `aria-invalid`.\n *\n * @example\n * function MyCustomInput(props) {\n * const { state, helperTextId, required } = useFormField()\n * return (\n * <input\n * aria-describedby={helperTextId}\n * aria-invalid={state === 'error' || undefined}\n * aria-required={required}\n * {...props}\n * />\n * )\n * }\n */\nexport function useFormField(): FormFieldContextValue {\n return React.useContext(FormFieldContext)\n}\n\nexport { FormField, FormFieldContext, FormHelperText }\n"],"mappings":";;;;;;;AAgBA,IAAM,IAAmB,EAAM,cAAqC,EAAE,CAAC,EAmCjE,IAAY,EAAM,YACrB,EAAE,cAAW,iBAAc,YAAS,WAAQ,UAAU,aAAU,aAAU,GAAG,KAAS,MAAQ;CAC7F,IAAM,IAAS,EAAM,OAAO,EACtB,IAAmB,KAAgB,GAAG,EAAO,UAC7C,IAAkB,KAAW,GAAG,EAAO,SACvC,IAAe,EAAM,eAClB;EAAE;EAAO,cAAc;EAAkB,SAAS;EAAiB;EAAU,GACpF;EAAC;EAAO;EAAkB;EAAiB;EAAS,CACrD;AAED,QACE,kBAAC,EAAiB,UAAlB;EAA2B,OAAO;YAChC,kBAAC,OAAD;GACO;GACL,WAAW,EAAG,2BAA2B,EAAU;GACnD,GAAI;GAEH;GACG,CAAA;EACoB,CAAA;EAGjC;AACD,EAAU,cAAc;AASxB,IAAM,IAAsD;CAC1D,QAAS;CACT,OAAS;CACT,SAAS;CACT,SAAS;CACV,EAEK,IAAiB,EAAM,YAC1B,EAAE,cAAW,IAAI,GAAQ,OAAO,GAAW,GAAG,KAAS,MAAQ;CAC9D,IAAM,IAAU,EAAM,WAAW,EAAiB,EAC5C,IAAQ,KAAa,EAAQ,SAAS,UACtC,IAAK,KAAU,EAAQ;AAE7B,QACE,kBAAC,EAAO,GAAR;EACO;EACD;EACJ,MAAM,MAAU,UAAU,UAAU,KAAA;EACpC,WAAW,EAAG,cAAc,EAAmB,IAAQ,EAAU;EACjE,SAAS;GAAE,SAAS;GAAG,GAAG;GAAI;EAC9B,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,MAAM;GAAE,SAAS;GAAG,GAAG;GAAI;EAC3B,YAAY,EAAO;EACnB,GAAI,EAAY,EAAM;EACtB,CAAA;EAGP;AACD,EAAe,cAAc;AAmB7B,SAAgB,IAAsC;AACpD,QAAO,EAAM,WAAW,EAAiB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hover-card.js","names":[],"sources":["../../src/ui/hover-card.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as HoverCardPrimitive from '@primitives/react-hover-card'\nimport { motion, AnimatePresence } from 'framer-motion'\n\nimport { cn } from './lib/utils'\nimport { springs, tweens } from './lib/motion'\n\n// ── Internal context to thread `open` state to animated children ──\n\nconst HoverCardOpenContext = React.createContext(false)\n\n/**\n * HoverCard displays supplementary content on pointer hover.\n *\n * **Accessibility note:** HoverCard is pointer-only by design (WAI-ARIA HoverCard has no APG pattern).\n * Do NOT use for essential content that keyboard users must access.\n * For essential content, use {@link Popover} instead which supports keyboard activation.\n */\nconst HoverCard: React.FC<React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Root>> = ({\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 <HoverCardOpenContext.Provider value={open}>\n <HoverCardPrimitive.Root open={open} onOpenChange={handleOpenChange} {...props} />\n </HoverCardOpenContext.Provider>\n )\n}\nHoverCard.displayName = 'HoverCard'\n\nconst HoverCardTrigger = HoverCardPrimitive.Trigger\n\nconst HoverCardContent = React.forwardRef<\n React.ElementRef<typeof HoverCardPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>\n>(({ className, align = 'center', sideOffset = 4, children, ...props }, ref) => {\n const open = React.useContext(HoverCardOpenContext)\n\n return (\n <AnimatePresence>\n {open && (\n <HoverCardPrimitive.Portal forceMount>\n <HoverCardPrimitive.Content\n ref={ref}\n align={align}\n sideOffset={sideOffset}\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 w-64 rounded-ds-lg border border-surface-border-strong bg-surface-overlay p-ds-05 shadow-floating outline-hidden',\n className,\n )}\n >\n {children}\n </motion.div>\n </HoverCardPrimitive.Content>\n </HoverCardPrimitive.Portal>\n )}\n </AnimatePresence>\n )\n})\nHoverCardContent.displayName = HoverCardPrimitive.Content.displayName\n\nexport type HoverCardContentProps = React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>\n\nexport { HoverCard, HoverCardTrigger, HoverCardContent }\n"],"mappings":";;;;;;;;AAWA,IAAM,IAAuB,EAAM,cAAc,GAAM,EASjD,KAAuF,EAC3F,MAAM,GACN,iBAAc,IACd,iBACA,GAAG,QACC;CACJ,IAAM,CAAC,GAAkB,KAAuB,EAAM,SAAS,EAAY,EACrE,IAAe,MAAmB,KAAA,GAClC,IAAO,IAAe,IAAiB,GAEvC,IAAmB,EAAM,aAC5B,MAAmB;AAElB,EADK,KAAc,EAAoB,EAAM,EAC7C,IAAe,EAAM;IAEvB,CAAC,GAAc,EAAa,CAC7B;AAED,QACE,kBAAC,EAAqB,UAAtB;EAA+B,OAAO;YACpC,kBAAC,GAAD;GAA+B;GAAM,cAAc;GAAkB,GAAI;GAAS,CAAA;EACpD,CAAA;;AAGpC,EAAU,cAAc;AAExB,IAAM,IAAmB,GAEnB,IAAmB,EAAM,YAG5B,EAAE,cAAW,WAAQ,UAAU,gBAAa,GAAG,aAAU,GAAG,KAAS,MAIpE,kBAAC,GAAD,EAAA,UAHW,EAAM,WAAW,EAAqB,IAK7C,kBAAC,GAAD;CAA2B,YAAA;WACzB,kBAAC,GAAD;EACO;EACE;EACK;EACZ,YAAA;EACA,SAAA;EACA,GAAI;YAEJ,kBAAC,EAAO,KAAR;GACE,SAAS;IAAE,SAAS;IAAG,OAAO;IAAM;GACpC,SAAS;IAAE,SAAS;IAAG,OAAO;IAAG;GACjC,MAAM;IAAE,SAAS;IAAG,OAAO;IAAM;GACjC,YAAY;IAAE,GAAG,EAAQ;IAAQ,SAAS,EAAO;IAAM;GACvD,WAAW,EACT,8HACA,EACD;GAEA;GACU,CAAA;EACc,CAAA;CACH,CAAA,EAEd,CAAA,CAEpB;AACF,EAAiB,cAAA,EAAyC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icon-button.js","names":[],"sources":["../../src/ui/icon-button.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { Button, type ButtonProps } from './button'\nimport { cn } from './lib/utils'\n\n/** Map friendly sizes to icon-* sizes for the underlying Button */\nconst sizeMap = {\n sm: 'icon-sm',\n md: 'icon-md',\n lg: 'icon-lg',\n} as const\n\ntype IconButtonSize = 'sm' | 'md' | 'lg'\n\n/**\n * Props for IconButton — a square or circular icon-only button built on top of `<Button>`,\n * with `aria-label` required for WCAG AA compliance.\n *\n * **`aria-label` is required** — icon-only buttons have no visible text, so a descriptive label\n * is mandatory for screen readers. TypeScript enforces this.\n *\n * **Shape:** `'square'` (default, rounded corners) | `'circle'` (fully round, great for avatar-adjacent actions)\n *\n * **Size:** `'sm'` | `'md'` (default) | `'lg'` — maps to `icon-sm/md/lg` sizes internally.\n *\n * **All `Button` variants** are supported: `solid`, `outline`, `ghost`, `link` x `default`, `error`.\n *\n * @example\n * // Ghost toolbar icon button:\n * <IconButton icon={<Icon icon={IconEdit} />} variant=\"ghost\" aria-label=\"Edit item\" />\n *\n * @example\n * // Circular close button (e.g. in a modal header):\n * <IconButton icon={<Icon icon={IconX} />} shape=\"circle\" variant=\"ghost\" size=\"sm\" aria-label=\"Close dialog\" />\n *\n * @example\n * // Solid floating action button:\n * <IconButton icon={<Icon icon={IconPlus} />} variant=\"solid\" size=\"lg\" aria-label=\"Create new project\" />\n *\n * @example\n * // Error icon button with loading state (e.g. confirm delete):\n * <IconButton icon={<Icon icon={IconTrash} />} variant=\"solid\" color=\"error\" loading={isDeleting} aria-label=\"Delete\" />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface IconButtonProps\n extends Omit<ButtonProps, 'startIcon' | 'endIcon' | 'fullWidth' | 'loadingPosition' | 'children' | 'size' | 'shape'> {\n /** The icon element to render — must be `<Icon icon={...} />` */\n icon: React.ReactElement\n /** Accessible label — required for icon-only buttons (WCAG AA) */\n 'aria-label': string\n /** Button shape. Default: 'square' */\n shape?: 'square' | 'circle'\n /** Button size. Default: 'md' */\n size?: IconButtonSize\n}\n\nconst IconButton = React.forwardRef<HTMLButtonElement, IconButtonProps>(\n ({ icon, shape = 'square', size = 'md', className, loading, ...props }, ref) => {\n return (\n <Button\n ref={ref}\n size={sizeMap[size]}\n className={cn(shape === 'circle' && 'rounded-ds-full', className)}\n loading={loading}\n loadingPosition=\"center\"\n {...props}\n >\n {icon}\n </Button>\n )\n },\n)\nIconButton.displayName = 'IconButton'\n\nexport { IconButton }\n"],"mappings":";;;;;;AAOA,IAAM,IAAU;CACd,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EA8CK,IAAa,EAAM,YACtB,EAAE,SAAM,WAAQ,UAAU,UAAO,MAAM,cAAW,YAAS,GAAG,KAAS,MAEpE,kBAAC,GAAD;CACO;CACL,MAAM,EAAQ;CACd,WAAW,EAAG,MAAU,YAAY,mBAAmB,EAAU;CACxD;CACT,iBAAgB;CAChB,GAAI;WAEH;CACM,CAAA,CAGd;AACD,EAAW,cAAc"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icon-context.js","names":[],"sources":["../../src/ui/icon-context.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\n\nexport type IconSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'\nexport type IconStroke = 'light' | 'regular' | 'bold'\n\nexport interface IconContextValue {\n size?: IconSize\n stroke?: IconStroke\n}\n\nconst IconContext = React.createContext<IconContextValue>({})\n\nexport function IconProvider({\n size,\n stroke,\n children,\n}: IconContextValue & { children: React.ReactNode }) {\n const value = React.useMemo(() => ({ size, stroke }), [size, stroke])\n return <IconContext.Provider value={value}>{children}</IconContext.Provider>\n}\n\nexport function useIconContext(): IconContextValue {\n return React.useContext(IconContext)\n}\n\nexport { IconContext }\n"],"mappings":";;;;AAYA,IAAM,IAAc,EAAM,cAAgC,EAAE,CAAC;AAE7D,SAAgB,EAAa,EAC3B,SACA,WACA,eACmD;CACnD,IAAM,IAAQ,EAAM,eAAe;EAAE;EAAM;EAAQ,GAAG,CAAC,GAAM,EAAO,CAAC;AACrE,QAAO,kBAAC,EAAY,UAAb;EAA6B;EAAQ;EAAgC,CAAA;;AAG9E,SAAgB,IAAmC;AACjD,QAAO,EAAM,WAAW,EAAY"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icon-group.js","names":[],"sources":["../../src/ui/icon-group.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cn } from './lib/utils'\nimport { IconProvider, type IconSize, type IconStroke } from './icon-context'\n\nconst gapClasses = {\n tight: 'gap-0.5',\n default: 'gap-1',\n loose: 'gap-2',\n} as const\n\nexport interface IconGroupProps {\n /** Icon size for all children */\n size?: IconSize\n /** Stroke weight for all children */\n stroke?: IconStroke\n /** Gap between icons. Default: 'default' (4px) */\n gap?: 'tight' | 'default' | 'loose'\n /** Accessible label — required when role is \"toolbar\" */\n label?: string\n /** Set to \"toolbar\" for formatting toolbars. Default: no role. */\n role?: 'toolbar'\n className?: string\n children: React.ReactNode\n}\n\nconst IconGroup = React.forwardRef<HTMLDivElement, IconGroupProps>(({\n size,\n stroke,\n gap = 'default',\n label,\n role: ariaRole,\n className,\n children,\n}, ref) => {\n return (\n <IconProvider size={size} stroke={stroke}>\n <div\n ref={ref}\n role={ariaRole}\n aria-label={ariaRole ? label : undefined}\n className={cn('inline-flex items-center', gapClasses[gap], className)}\n >\n {children}\n </div>\n </IconProvider>\n )\n})\nIconGroup.displayName = 'IconGroup'\n\nexport { IconGroup }\n"],"mappings":";;;;;;AAMA,IAAM,IAAa;CACjB,OAAO;CACP,SAAS;CACT,OAAO;CACR,EAiBK,IAAY,EAAM,YAA4C,EAClE,SACA,WACA,SAAM,WACN,UACA,MAAM,GACN,cACA,eACC,MAEC,kBAAC,GAAD;CAAoB;CAAc;WAChC,kBAAC,OAAD;EACO;EACL,MAAM;EACN,cAAY,IAAW,IAAQ,KAAA;EAC/B,WAAW,EAAG,4BAA4B,EAAW,IAAM,EAAU;EAEpE;EACG,CAAA;CACO,CAAA,CAEjB;AACF,EAAU,cAAc"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"icon.js","names":[],"sources":["../../src/ui/icon.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { motion, AnimatePresence, useReducedMotion } from 'framer-motion'\nimport { springs, tweens } from './lib/motion'\nimport { cn } from './lib/utils'\nimport { Spinner } from './spinner'\nimport { useIconContext, type IconSize, type IconStroke } from './icon-context'\n\n/** Icon size tier → pixel dimensions */\nconst SIZE_PX: Record<IconSize, number> = {\n xs: 14, sm: 16, md: 18, lg: 20, xl: 24, '2xl': 32,\n}\n\n/** Stroke weight → strokeWidth per size tier (lighter strokes on smaller icons) */\nconst STROKE_MAP: Record<IconStroke, Record<IconSize, number>> = {\n light: { xs: 1.25, sm: 1.5, md: 1.5, lg: 1.75, xl: 2, '2xl': 2 },\n regular: { xs: 1.5, sm: 2, md: 2, lg: 2, xl: 2, '2xl': 2.25 },\n bold: { xs: 2, sm: 2.5, md: 2.5, lg: 2.5, xl: 2.5, '2xl': 2.5 },\n}\n\n/** Props accepted by Tabler icon components (and most SVG icon libraries) */\ntype IconComponentProps = Partial<Omit<React.ComponentPropsWithoutRef<'svg'>, 'stroke'>> & {\n size?: string | number\n stroke?: string | number\n title?: string\n}\n\nconst ANIMATION_PRESETS = {\n spin: {\n animate: { rotate: 360 },\n transition: { duration: 1, repeat: Infinity, ease: 'linear' as const },\n },\n pulse: {\n animate: { scale: [1, 1.15, 1] },\n transition: { duration: 2, repeat: Infinity, ease: 'easeInOut' as const },\n },\n bounce: {\n animate: { y: [0, -4, 0] },\n transition: { duration: 1.5, repeat: Infinity, ease: 'easeInOut' as const },\n },\n}\n\nconst ICON_TO_SPINNER_SIZE: Record<IconSize, 'sm' | 'md' | 'lg'> = {\n xs: 'sm', sm: 'sm', md: 'md', lg: 'md', xl: 'lg', '2xl': 'lg',\n}\n\nexport interface IconProps {\n /** The Tabler icon component (or any ForwardRef SVG icon component) */\n icon: React.ForwardRefExoticComponent<IconComponentProps & React.RefAttributes<SVGSVGElement>>\n /** Size tier — reads from IconContext if not set */\n size?: IconSize\n /** Stroke weight — reads from IconContext if not set */\n stroke?: IconStroke\n /** Accessible label — renders <title> + sets aria-label. Without this, icon is aria-hidden. */\n label?: string\n /**\n * Preset animation or controlled motion. 'none' disables inherited animation.\n * 'draw' renders the icon as an SVG path that draws in like a pen stroke\n * (works with IconCheck and IconX — others fall back to fade-in).\n */\n animate?: 'spin' | 'pulse' | 'bounce' | 'draw' | 'none' | { rotate?: number; scale?: number }\n /**\n * State machine for loading→success/error transitions. Delegates to Spinner (bare variant).\n *\n * **Priority rule:** If both `state` and `animate` are set, `state` wins —\n * the state machine check runs first and short-circuits rendering.\n */\n state?: 'idle' | 'loading' | 'success' | 'error'\n className?: string\n}\n\n/**\n * Icon — context-aware wrapper for Tabler icons with standardized sizing,\n * stroke weights, accessibility, animation presets, and loading state machine.\n *\n * Reads size and stroke from IconContext (provided by Button, IconGroup, etc.).\n * Explicit props always override context.\n *\n * **Priority rule:** If both `state` and `animate` are set, `state` wins.\n *\n * @example\n * <Icon icon={IconPlus} /> // md size, regular stroke\n * <Icon icon={IconPlus} size=\"xs\" stroke=\"light\" /> // 14px, stroke 1.25\n * <Icon icon={IconPlus} label=\"Add item\" /> // accessible, not decorative\n * <Icon icon={IconPlus} animate=\"spin\" /> // continuous rotation\n * <Icon icon={IconPlus} animate=\"pulse\" /> // scale pulse\n * <Icon icon={IconPlus} state=\"loading\" /> // bare spinner\n * <Icon icon={IconPlus} state=\"success\" /> // animated checkmark\n */\nexport const Icon = React.forwardRef<SVGSVGElement, IconProps>(\n ({ icon: TablerIcon, size, stroke, label, animate, state, className }, ref) => {\n const ctx = useIconContext()\n const resolvedSize = size ?? ctx.size ?? 'md'\n const resolvedStroke = stroke ?? ctx.stroke ?? 'regular'\n const px = SIZE_PX[resolvedSize]\n const sw = STROKE_MAP[resolvedStroke][resolvedSize]\n const prefersReduced = useReducedMotion()\n\n // ── State machine (priority: state > animate) ──────────────────────\n if (state && state !== 'idle') {\n const spinnerSize = ICON_TO_SPINNER_SIZE[resolvedSize]\n const spinnerState = state === 'loading' ? 'spinning' : state\n return (\n <AnimatePresence mode=\"wait\">\n <motion.span\n key=\"spinner\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={tweens.fade}\n className=\"inline-flex\"\n >\n <Spinner size={spinnerSize} state={spinnerState} variant=\"bare\" />\n </motion.span>\n </AnimatePresence>\n )\n }\n\n // ── Draw animation (SVG pathLength) ─────────────────────────────────\n if (animate === 'draw' && !prefersReduced) {\n const drawProps = {\n initial: { pathLength: 0, opacity: 0 },\n animate: { pathLength: 1, opacity: 1 },\n transition: { pathLength: { duration: 0.35, ease: 'easeOut' as const }, opacity: { duration: 0.1 } },\n }\n // Check which icon this is to render the appropriate SVG path.\n // Tabler displayNames: IconCheck → \"Check\", IconX → \"X\"\n const name = TablerIcon.displayName ?? ''\n const isCheck = name === 'Check' || name === 'IconCheck' || name === 'CircleCheck'\n const isX = name === 'X' || name === 'IconX'\n\n if (isCheck || isX) {\n return (\n <svg\n ref={ref}\n width={px}\n height={px}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={sw}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className}\n aria-hidden={label ? undefined : 'true'}\n aria-label={label}\n role={label ? 'img' : undefined}\n >\n {isCheck ? (\n <motion.polyline points=\"4 12 10 18 20 6\" {...drawProps} />\n ) : (\n <>\n <motion.line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" {...drawProps} />\n <motion.line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"\n {...drawProps}\n transition={{\n pathLength: { duration: 0.25, ease: 'easeOut', delay: 0.1 },\n opacity: { duration: 0.1, delay: 0.1 },\n }}\n />\n </>\n )}\n </svg>\n )\n }\n // Unknown icon: fall through to fade-in via static render\n }\n\n // ── Determine animation ────────────────────────────────────────────\n const animatePreset =\n typeof animate === 'string' && animate !== 'none' && animate !== 'draw'\n ? ANIMATION_PRESETS[animate as keyof typeof ANIMATION_PRESETS]\n : null\n const animateObject =\n typeof animate === 'object' && animate !== null && (animate.rotate !== undefined || animate.scale !== undefined)\n ? animate\n : null\n\n if (prefersReduced || (!animatePreset && !animateObject)) {\n // Static render (no animation or reduced motion)\n return label ? (\n <TablerIcon ref={ref as any} size={px} stroke={sw} className={className} title={label} aria-label={label} role=\"img\" />\n ) : (\n <TablerIcon ref={ref as any} size={px} stroke={sw} className={className} aria-hidden=\"true\" />\n )\n }\n\n // ── Animated render ────────────────────────────────────────────────\n const motionProps = animatePreset ?? {\n animate: animateObject!,\n transition: springs.snappy,\n }\n\n const iconEl = label ? (\n <TablerIcon size={px} stroke={sw} title={label} aria-label={label} role=\"img\" />\n ) : (\n <TablerIcon size={px} stroke={sw} aria-hidden=\"true\" />\n )\n\n return (\n <motion.span\n ref={ref as any}\n className={cn('inline-flex', className)}\n {...motionProps}\n >\n {iconEl}\n </motion.span>\n )\n },\n)\nIcon.displayName = 'Icon'\n"],"mappings":"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"}
|
package/dist/ui/index.d.ts
CHANGED
|
@@ -29,18 +29,18 @@ export { Label, type LabelProps } from './label';
|
|
|
29
29
|
export { Separator, type SeparatorProps } from './separator';
|
|
30
30
|
export { VisuallyHidden, type VisuallyHiddenProps } from './visually-hidden';
|
|
31
31
|
export { Autocomplete, type AutocompleteProps, type AutocompleteOption } from './autocomplete';
|
|
32
|
-
export { Combobox, type ComboboxProps, type ComboboxOption } from './combobox';
|
|
32
|
+
export { Combobox, comboboxTriggerVariants, type ComboboxProps, type ComboboxOption, type ComboboxSize } from './combobox';
|
|
33
33
|
export { FileUpload, type FileUploadProps } from './file-upload';
|
|
34
34
|
export { Checkbox, type CheckboxProps } from './checkbox';
|
|
35
35
|
export { RadioGroup, RadioGroupItem, type RadioGroupProps, type RadioGroupItemProps } from './radio';
|
|
36
36
|
export { Switch, type SwitchProps } from './switch';
|
|
37
37
|
export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, SelectScrollUpButton, SelectScrollDownButton, type SelectTriggerProps, selectTriggerVariants, } from './select';
|
|
38
38
|
export { Textarea, textareaVariants, type TextareaProps } from './textarea';
|
|
39
|
-
export { NumberInput, type NumberInputProps } from './number-input';
|
|
39
|
+
export { NumberInput, numberInputWrapperVariants, type NumberInputProps, type NumberInputSize, type NumberInputState } from './number-input';
|
|
40
40
|
export { SearchInput, type SearchInputProps } from './search-input';
|
|
41
41
|
export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator, type InputOTPProps } from './input-otp';
|
|
42
42
|
export { FormField, FormHelperText, useFormField, type FormFieldProps, type FormHelperState, type FormHelperTextProps } from './form';
|
|
43
|
-
export { Slider, type SliderProps } from './slider';
|
|
43
|
+
export { Slider, sliderTrackVariants, sliderThumbVariants, type SliderProps, type SliderSize, type SliderColor } from './slider';
|
|
44
44
|
export { Toggle, toggleVariants, type ToggleProps } from './toggle';
|
|
45
45
|
export { ToggleGroup, ToggleGroupItem, type ToggleGroupProps, type ToggleGroupItemProps } from './toggle-group';
|
|
46
46
|
export { AlertDialog, AlertDialogPortal, AlertDialogOverlay, AlertDialogTrigger, AlertDialogContent, AlertDialogHeader, AlertDialogFooter, AlertDialogTitle, AlertDialogDescription, AlertDialogAction, AlertDialogCancel, type AlertDialogContentProps, type AlertDialogActionProps, type AlertDialogCancelProps, } from './alert-dialog';
|
|
@@ -70,7 +70,7 @@ export { ProgressRing, MultiProgressRing, type ProgressRingProps, type MultiProg
|
|
|
70
70
|
export { Code, type CodeProps } from './code';
|
|
71
71
|
export { AspectRatio } from './aspect-ratio';
|
|
72
72
|
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent, type AccordionItemProps, type AccordionTriggerProps, type AccordionContentProps } from './accordion';
|
|
73
|
-
export { Tabs, TabsList, TabsTrigger, TabsContent, type TabsProps, type TabsListProps, type TabsTriggerProps, type TabsContentProps } from './tabs';
|
|
73
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent, type TabsProps, type TabsListProps, type TabsTriggerProps, type TabsContentProps, type TabsSize, type TabsColor, type TabsOrientation } from './tabs';
|
|
74
74
|
export { Breadcrumb, BreadcrumbList, BreadcrumbItem, BreadcrumbLink, BreadcrumbPage, BreadcrumbSeparator, BreadcrumbEllipsis, type BreadcrumbProps, type BreadcrumbLinkProps, } from './breadcrumb';
|
|
75
75
|
export { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuGroup, DropdownMenuPortal, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuRadioGroup, type DropdownMenuContentProps, type DropdownMenuItemProps, } from './dropdown-menu';
|
|
76
76
|
export { ContextMenu, ContextMenuTrigger, ContextMenuContent, ContextMenuItem, ContextMenuCheckboxItem, ContextMenuRadioItem, ContextMenuLabel, ContextMenuSeparator, ContextMenuShortcut, ContextMenuGroup, ContextMenuPortal, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuRadioGroup, type ContextMenuContentProps, type ContextMenuItemProps, } from './context-menu';
|