tembro 2.0.5 → 2.1.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/dist/components/calendar/calendar.cjs +1 -1
- package/dist/components/calendar/calendar.d.ts +2 -1
- package/dist/components/calendar/calendar.js +126 -122
- package/dist/components/calendar/date-range-picker.cjs +1 -1
- package/dist/components/calendar/date-range-picker.d.ts +2 -1
- package/dist/components/calendar/date-range-picker.js +39 -39
- package/dist/components/charts/charts.cjs +1 -1
- package/dist/components/charts/charts.d.ts +13 -4
- package/dist/components/charts/charts.js +76 -46
- package/dist/components/charts/progress-ring.cjs +1 -1
- package/dist/components/charts/progress-ring.d.ts +3 -1
- package/dist/components/charts/progress-ring.js +11 -10
- package/dist/components/data-table/data-table-column-visibility-menu.cjs +1 -1
- package/dist/components/data-table/data-table-column-visibility-menu.d.ts +4 -1
- package/dist/components/data-table/data-table-column-visibility-menu.js +36 -8
- package/dist/components/data-table/data-table-pagination.cjs +1 -1
- package/dist/components/data-table/data-table-pagination.js +4 -4
- package/dist/components/data-table/data-table-toolbar.cjs +1 -1
- package/dist/components/data-table/data-table-toolbar.js +12 -13
- package/dist/components/data-table/data-table.cjs +1 -1
- package/dist/components/data-table/data-table.d.ts +2 -2
- package/dist/components/data-table/data-table.js +2 -1
- package/dist/components/display/carousel.cjs +1 -1
- package/dist/components/display/carousel.d.ts +15 -1
- package/dist/components/display/carousel.js +128 -86
- package/dist/components/display/code-block.cjs +2 -2
- package/dist/components/display/code-block.d.ts +2 -1
- package/dist/components/display/code-block.js +17 -12
- package/dist/components/display/delta-badge.cjs +1 -1
- package/dist/components/display/delta-badge.d.ts +2 -1
- package/dist/components/display/delta-badge.js +11 -7
- package/dist/components/display/kanban.cjs +1 -1
- package/dist/components/display/kanban.d.ts +4 -1
- package/dist/components/display/kanban.js +60 -33
- package/dist/components/display/metric-grid.cjs +1 -1
- package/dist/components/display/metric-grid.d.ts +1 -0
- package/dist/components/display/metric-grid.js +1 -1
- package/dist/components/display/qr-code.cjs +1 -1
- package/dist/components/display/qr-code.d.ts +2 -1
- package/dist/components/display/qr-code.js +19 -16
- package/dist/components/display/smart-card.d.ts +1 -1
- package/dist/components/display/status-legend.d.ts +1 -1
- package/dist/components/display/tag.cjs +1 -1
- package/dist/components/display/tag.d.ts +2 -1
- package/dist/components/display/tag.js +28 -22
- package/dist/components/display/tree-view.cjs +1 -1
- package/dist/components/display/tree-view.d.ts +9 -1
- package/dist/components/display/tree-view.js +104 -40
- package/dist/components/display/trend-card.cjs +1 -1
- package/dist/components/display/trend-card.js +27 -41
- package/dist/components/feedback/alert.cjs +1 -1
- package/dist/components/feedback/alert.d.ts +2 -1
- package/dist/components/feedback/alert.js +6 -6
- package/dist/components/feedback/loading-state.cjs +1 -1
- package/dist/components/feedback/loading-state.d.ts +3 -1
- package/dist/components/feedback/loading-state.js +23 -10
- package/dist/components/feedback/page-state.cjs +1 -1
- package/dist/components/feedback/page-state.d.ts +2 -1
- package/dist/components/feedback/page-state.js +7 -4
- package/dist/components/form/form-field-shell.cjs +1 -1
- package/dist/components/form/form-field-shell.d.ts +4 -2
- package/dist/components/form/form-field-shell.js +57 -41
- package/dist/components/form/form-input.cjs +1 -1
- package/dist/components/form/form-input.d.ts +3 -4
- package/dist/components/form/form-input.js +259 -257
- package/dist/components/form/form-select.cjs +1 -1
- package/dist/components/form/form-select.d.ts +2 -2
- package/dist/components/form/form-select.js +8 -6
- package/dist/components/form/form-switch.cjs +1 -1
- package/dist/components/form/form-switch.d.ts +1 -1
- package/dist/components/form/form-switch.js +58 -54
- package/dist/components/form/form-textarea.cjs +1 -1
- package/dist/components/form/form-textarea.d.ts +1 -1
- package/dist/components/form/form-textarea.js +29 -27
- package/dist/components/inputs/async-select.d.ts +3 -0
- package/dist/components/inputs/search-input.d.ts +3 -0
- package/dist/components/inputs/simple-select.cjs +1 -1
- package/dist/components/inputs/simple-select.d.ts +10 -32
- package/dist/components/inputs/simple-select.js +5 -101
- package/dist/components/layout/app-sidebar.cjs +1 -1
- package/dist/components/layout/app-sidebar.d.ts +1 -0
- package/dist/components/layout/app-sidebar.js +36 -36
- package/dist/components/layout/breadcrumbs.cjs +1 -1
- package/dist/components/layout/breadcrumbs.d.ts +2 -1
- package/dist/components/layout/breadcrumbs.js +7 -7
- package/dist/components/modern/calendar-scheduler.cjs +1 -1
- package/dist/components/modern/calendar-scheduler.d.ts +5 -1
- package/dist/components/modern/calendar-scheduler.js +47 -28
- package/dist/components/modern/dual-list-picker.cjs +1 -1
- package/dist/components/modern/dual-list-picker.d.ts +5 -1
- package/dist/components/modern/dual-list-picker.js +81 -23
- package/dist/components/modern/rich-text-editor.cjs +1 -1
- package/dist/components/modern/rich-text-editor.d.ts +3 -1
- package/dist/components/modern/rich-text-editor.js +12 -9
- package/dist/components/modern/tour.cjs +1 -1
- package/dist/components/modern/tour.d.ts +5 -1
- package/dist/components/modern/tour.js +57 -35
- package/dist/components/navigation/command-bar.cjs +1 -1
- package/dist/components/navigation/command-bar.d.ts +3 -1
- package/dist/components/navigation/command-bar.js +10 -7
- package/dist/components/navigation/demo.cjs +1 -1
- package/dist/components/navigation/demo.js +0 -1
- package/dist/components/navigation/nav-tabs.cjs +1 -1
- package/dist/components/navigation/nav-tabs.js +39 -27
- package/dist/components/navigation/page-tabs.cjs +1 -1
- package/dist/components/navigation/page-tabs.js +41 -30
- package/dist/components/navigation/pagination.cjs +1 -1
- package/dist/components/navigation/pagination.d.ts +7 -1
- package/dist/components/navigation/pagination.js +48 -25
- package/dist/components/notifications/notification-center.cjs +1 -1
- package/dist/components/notifications/notification-center.d.ts +3 -1
- package/dist/components/notifications/notification-center.js +56 -38
- package/dist/components/notifications/toast.cjs +1 -1
- package/dist/components/notifications/toast.d.ts +1 -0
- package/dist/components/notifications/toast.js +4 -0
- package/dist/components/overlay/alert-dialog.cjs +1 -1
- package/dist/components/overlay/alert-dialog.js +1 -1
- package/dist/components/overlay/confirm-dialog.cjs +1 -1
- package/dist/components/overlay/confirm-dialog.d.ts +4 -2
- package/dist/components/overlay/confirm-dialog.js +31 -22
- package/dist/components/overlay/drawer.cjs +1 -1
- package/dist/components/overlay/drawer.d.ts +3 -1
- package/dist/components/overlay/drawer.js +24 -16
- package/dist/components/ui/accordion/index.d.ts +4 -0
- package/dist/components/ui/badge/index.cjs +1 -1
- package/dist/components/ui/badge/index.d.ts +1 -1
- package/dist/components/ui/badge/index.js +2 -1
- package/dist/components/ui/button/index.cjs +1 -1
- package/dist/components/ui/button/index.d.ts +2 -1
- package/dist/components/ui/button/index.js +13 -10
- package/dist/components/ui/card/index.cjs +1 -1
- package/dist/components/ui/card/index.d.ts +13 -2
- package/dist/components/ui/card/index.js +74 -49
- package/dist/components/ui/dialog/index.cjs +1 -1
- package/dist/components/ui/dialog/index.js +2 -1
- package/dist/components/ui/hover-card.cjs +1 -1
- package/dist/components/ui/hover-card.d.ts +11 -3
- package/dist/components/ui/hover-card.js +29 -24
- package/dist/components/ui/input/index.cjs +1 -1
- package/dist/components/ui/input/index.d.ts +9 -1
- package/dist/components/ui/input/index.js +63 -30
- package/dist/components/ui/popover/index.cjs +1 -1
- package/dist/components/ui/popover/index.d.ts +2 -2
- package/dist/components/ui/popover/index.js +6 -5
- package/dist/components/ui/radio-group/index.cjs +1 -1
- package/dist/components/ui/radio-group/index.d.ts +5 -1
- package/dist/components/ui/radio-group/index.js +50 -16
- package/dist/components/ui/right-click-menu/index.cjs +1 -1
- package/dist/components/ui/right-click-menu/index.d.ts +5 -1
- package/dist/components/ui/right-click-menu/index.js +77 -23
- package/dist/components/ui/segmented-control/index.cjs +1 -1
- package/dist/components/ui/segmented-control/index.d.ts +2 -1
- package/dist/components/ui/segmented-control/index.js +23 -11
- package/dist/components/ui/select/index.cjs +1 -1
- package/dist/components/ui/select/index.d.ts +40 -1
- package/dist/components/ui/select/index.js +159 -48
- package/dist/components/ui/switch/index.cjs +1 -1
- package/dist/components/ui/switch/index.d.ts +18 -0
- package/dist/components/ui/switch/index.js +47 -17
- package/dist/components/ui/tabs/index.cjs +1 -1
- package/dist/components/ui/tabs/index.d.ts +14 -4
- package/dist/components/ui/tabs/index.js +11 -8
- package/dist/components/ui/textarea/index.cjs +1 -1
- package/dist/components/ui/textarea/index.d.ts +10 -2
- package/dist/components/ui/textarea/index.js +37 -8
- package/dist/components/ui/textarea.cjs +1 -0
- package/dist/components/ui/textarea.d.ts +1 -0
- package/dist/components/ui/textarea.js +2 -0
- package/dist/components/ui/tooltip/index.cjs +1 -1
- package/dist/components/ui/tooltip/index.d.ts +11 -3
- package/dist/components/ui/tooltip/index.js +41 -20
- package/dist/components/upload/file-upload.cjs +1 -1
- package/dist/components/upload/file-upload.d.ts +8 -1
- package/dist/components/upload/file-upload.js +132 -100
- package/dist/components/upload/image-upload.cjs +1 -1
- package/dist/components/upload/image-upload.d.ts +5 -1
- package/dist/components/upload/image-upload.js +34 -9
- package/dist/index.cjs +1 -1
- package/dist/index.js +31 -31
- package/dist/public-component-surface.cjs +1 -1
- package/dist/public-component-surface.js +15 -0
- package/dist/showcase/component-api-schema.cjs +1 -1
- package/dist/showcase/component-api-schema.js +187 -10
- package/dist/showcase/create-demo.cjs +5 -4
- package/dist/showcase/create-demo.js +2 -2
- package/dist/showcase/fallback.cjs +3 -3
- package/dist/showcase/fallback.js +221 -243
- package/dist/showcase/premium/alert/showcase.cjs +1 -1
- package/dist/showcase/premium/alert/showcase.js +1 -0
- package/dist/showcase/premium/app-sidebar/showcase.cjs +1 -1
- package/dist/showcase/premium/app-sidebar/showcase.js +1 -0
- package/dist/showcase/premium/badge/showcase.cjs +1 -1
- package/dist/showcase/premium/badge/showcase.js +7 -0
- package/dist/showcase/premium/badge/types.d.ts +1 -1
- package/dist/showcase/premium/breadcrumbs/showcase.cjs +1 -1
- package/dist/showcase/premium/breadcrumbs/showcase.js +12 -1
- package/dist/showcase/premium/button/mock.cjs +1 -4
- package/dist/showcase/premium/button/mock.js +1 -1
- package/dist/showcase/premium/button/showcase.cjs +1 -1
- package/dist/showcase/premium/button/showcase.js +2 -2
- package/dist/showcase/premium/card/showcase.cjs +1 -1
- package/dist/showcase/premium/card/showcase.js +96 -47
- package/dist/showcase/premium/carousel/showcase.cjs +1 -1
- package/dist/showcase/premium/carousel/showcase.js +76 -49
- package/dist/showcase/premium/command-bar/showcase.cjs +1 -1
- package/dist/showcase/premium/command-bar/showcase.js +2 -0
- package/dist/showcase/premium/data-table/mock.cjs +12 -11
- package/dist/showcase/premium/data-table/mock.js +1 -1
- package/dist/showcase/premium/data-table/showcase.cjs +1 -1
- package/dist/showcase/premium/data-table/showcase.js +1 -1
- package/dist/showcase/premium/data-table-parts/showcase.cjs +1 -1
- package/dist/showcase/premium/data-table-parts/showcase.js +3 -1
- package/dist/showcase/premium/file-upload/showcase.cjs +1 -1
- package/dist/showcase/premium/file-upload/showcase.js +25 -4
- package/dist/showcase/premium/image-upload/showcase.cjs +1 -1
- package/dist/showcase/premium/image-upload/showcase.js +4 -1
- package/dist/showcase/premium/index.cjs +1 -1
- package/dist/showcase/premium/index.js +396 -402
- package/dist/showcase/premium/loading-state/showcase.cjs +1 -1
- package/dist/showcase/premium/loading-state/showcase.js +3 -1
- package/dist/showcase/premium/metric-grid/showcase.cjs +1 -1
- package/dist/showcase/premium/metric-grid/showcase.js +96 -28
- package/dist/showcase/premium/notification-center/showcase.cjs +1 -1
- package/dist/showcase/premium/notification-center/showcase.js +7 -3
- package/dist/showcase/premium/page-state/showcase.cjs +1 -1
- package/dist/showcase/premium/page-state/showcase.js +5 -1
- package/dist/showcase/premium/pagination/showcase.cjs +1 -1
- package/dist/showcase/premium/pagination/showcase.js +15 -2
- package/dist/showcase/premium/popover/showcase.cjs +1 -1
- package/dist/showcase/premium/popover/showcase.js +85 -50
- package/dist/showcase/premium/radio-group/showcase.cjs +1 -1
- package/dist/showcase/premium/radio-group/showcase.js +27 -4
- package/dist/showcase/premium/right-click-menu/showcase.cjs +1 -1
- package/dist/showcase/premium/right-click-menu/showcase.js +56 -43
- package/dist/showcase/premium/segmented-control/showcase.cjs +1 -1
- package/dist/showcase/premium/segmented-control/showcase.js +1 -0
- package/dist/showcase/premium/select/data.cjs +1 -1
- package/dist/showcase/premium/select/data.js +69 -34
- package/dist/showcase/premium/select/mock.cjs +20 -8
- package/dist/showcase/premium/select/mock.js +3 -2
- package/dist/showcase/premium/select/showcase.cjs +1 -1
- package/dist/showcase/premium/select/showcase.js +101 -86
- package/dist/showcase/premium/select/types.d.ts +3 -0
- package/dist/showcase/premium/statistic/showcase.cjs +1 -1
- package/dist/showcase/premium/statistic/showcase.js +57 -25
- package/dist/showcase/premium/switch/showcase.cjs +1 -1
- package/dist/showcase/premium/switch/showcase.js +25 -14
- package/dist/showcase/premium/tabs/showcase.cjs +1 -1
- package/dist/showcase/premium/tabs/showcase.js +171 -48
- package/dist/showcase/premium/textarea/mock.cjs +12 -4
- package/dist/showcase/premium/textarea/mock.js +1 -1
- package/dist/showcase/premium/textarea/showcase.cjs +1 -1
- package/dist/showcase/premium/textarea/showcase.js +8 -3
- package/dist/showcase/premium/toast/showcase.cjs +1 -1
- package/dist/showcase/premium/toast/showcase.js +32 -6
- package/dist/showcase/premium/types.d.ts +1 -1
- package/dist/showcase/registry-quality.cjs +1 -1
- package/dist/showcase/registry-quality.js +1 -0
- package/dist/showcase/registry-specific.cjs +1 -1
- package/dist/showcase/registry-specific.js +78 -74
- package/dist/showcase/render-registry-preview.cjs +1 -1
- package/dist/showcase/render-registry-preview.js +90 -108
- package/dist/showcase/site-data.cjs +1 -1
- package/dist/showcase/site-data.js +60 -21
- package/dist/showcase/tembro-registry.json.cjs +1 -1
- package/dist/showcase/tembro-registry.json.js +34 -20
- package/dist/showcase/types.d.ts +1 -1
- package/package.json +1 -1
- package/packages/cli/dist/index.cjs +31 -31
- package/packages/cli/vendor/src/components/calendar/calendar.tsx +59 -50
- package/packages/cli/vendor/src/components/calendar/date-range-picker.tsx +7 -4
- package/packages/cli/vendor/src/components/charts/charts.tsx +109 -66
- package/packages/cli/vendor/src/components/charts/progress-ring.tsx +37 -26
- package/packages/cli/vendor/src/components/data-table/data-table-column-visibility-menu.tsx +41 -22
- package/packages/cli/vendor/src/components/data-table/data-table-pagination.tsx +7 -7
- package/packages/cli/vendor/src/components/data-table/data-table-toolbar.tsx +8 -6
- package/packages/cli/vendor/src/components/data-table/data-table.tsx +21 -20
- package/packages/cli/vendor/src/components/display/carousel.tsx +102 -9
- package/packages/cli/vendor/src/components/display/code-block.tsx +22 -2
- package/packages/cli/vendor/src/components/display/delta-badge.tsx +11 -11
- package/packages/cli/vendor/src/components/display/kanban.tsx +103 -57
- package/packages/cli/vendor/src/components/display/metric-grid.tsx +16 -13
- package/packages/cli/vendor/src/components/display/qr-code.tsx +17 -15
- package/packages/cli/vendor/src/components/display/smart-card.tsx +1 -1
- package/packages/cli/vendor/src/components/display/status-legend.tsx +1 -1
- package/packages/cli/vendor/src/components/display/tag.tsx +39 -21
- package/packages/cli/vendor/src/components/display/tree-view.tsx +221 -84
- package/packages/cli/vendor/src/components/display/trend-card.tsx +6 -40
- package/packages/cli/vendor/src/components/feedback/alert.tsx +3 -1
- package/packages/cli/vendor/src/components/feedback/loading-state.tsx +33 -17
- package/packages/cli/vendor/src/components/feedback/page-state.tsx +8 -7
- package/packages/cli/vendor/src/components/form/form-field-shell.tsx +37 -8
- package/packages/cli/vendor/src/components/form/form-input.tsx +11 -12
- package/packages/cli/vendor/src/components/form/form-select.tsx +6 -4
- package/packages/cli/vendor/src/components/form/form-switch.tsx +9 -3
- package/packages/cli/vendor/src/components/form/form-textarea.tsx +6 -2
- package/packages/cli/vendor/src/components/inputs/async-select.tsx +11 -8
- package/packages/cli/vendor/src/components/inputs/search-input.tsx +5 -2
- package/packages/cli/vendor/src/components/inputs/simple-select.tsx +20 -190
- package/packages/cli/vendor/src/components/layout/app-sidebar.tsx +3 -1
- package/packages/cli/vendor/src/components/layout/breadcrumbs.tsx +3 -1
- package/packages/cli/vendor/src/components/modern/calendar-scheduler.tsx +28 -13
- package/packages/cli/vendor/src/components/modern/dual-list-picker.tsx +103 -35
- package/packages/cli/vendor/src/components/modern/rich-text-editor.tsx +25 -22
- package/packages/cli/vendor/src/components/modern/tour.tsx +47 -29
- package/packages/cli/vendor/src/components/navigation/command-bar.tsx +6 -0
- package/packages/cli/vendor/src/components/navigation/demo.tsx +0 -1
- package/packages/cli/vendor/src/components/navigation/nav-tabs.tsx +38 -29
- package/packages/cli/vendor/src/components/navigation/page-tabs.tsx +35 -23
- package/packages/cli/vendor/src/components/navigation/pagination.tsx +65 -31
- package/packages/cli/vendor/src/components/notifications/notification-center.tsx +64 -39
- package/packages/cli/vendor/src/components/notifications/toast.tsx +23 -21
- package/packages/cli/vendor/src/components/overlay/alert-dialog.tsx +1 -1
- package/packages/cli/vendor/src/components/overlay/confirm-dialog.tsx +45 -22
- package/packages/cli/vendor/src/components/overlay/drawer.tsx +18 -5
- package/packages/cli/vendor/src/components/ui/accordion/index.tsx +4 -0
- package/packages/cli/vendor/src/components/ui/badge/index.tsx +2 -1
- package/packages/cli/vendor/src/components/ui/button/index.tsx +11 -5
- package/packages/cli/vendor/src/components/ui/card/index.tsx +95 -25
- package/packages/cli/vendor/src/components/ui/dialog/index.tsx +2 -1
- package/packages/cli/vendor/src/components/ui/hover-card.tsx +54 -28
- package/packages/cli/vendor/src/components/ui/input/index.tsx +98 -0
- package/packages/cli/vendor/src/components/ui/popover/index.tsx +10 -8
- package/packages/cli/vendor/src/components/ui/radio-group/index.tsx +55 -6
- package/packages/cli/vendor/src/components/ui/right-click-menu/index.tsx +120 -9
- package/packages/cli/vendor/src/components/ui/segmented-control/index.tsx +29 -3
- package/packages/cli/vendor/src/components/ui/select/index.tsx +260 -34
- package/packages/cli/vendor/src/components/ui/switch/index.tsx +71 -6
- package/packages/cli/vendor/src/components/ui/tabs/index.tsx +22 -6
- package/packages/cli/vendor/src/components/ui/textarea/index.tsx +105 -15
- package/packages/cli/vendor/src/components/ui/textarea.tsx +2 -0
- package/packages/cli/vendor/src/components/ui/tooltip/index.tsx +67 -22
- package/packages/cli/vendor/src/components/upload/file-upload.tsx +120 -57
- package/packages/cli/vendor/src/components/upload/image-upload.tsx +71 -24
- package/packages/cli/vendor/src/public-component-surface.ts +3 -0
- package/packages/cli/vendor/src/showcase/component-api-schema.ts +79 -41
- package/packages/cli/vendor/src/showcase/create-demo.tsx +16 -15
- package/packages/cli/vendor/src/showcase/fallback.tsx +4 -19
- package/packages/cli/vendor/src/showcase/premium/alert/showcase.tsx +1 -0
- package/packages/cli/vendor/src/showcase/premium/app-sidebar/showcase.tsx +1 -0
- package/packages/cli/vendor/src/showcase/premium/badge/showcase.tsx +4 -2
- package/packages/cli/vendor/src/showcase/premium/badge/types.ts +1 -1
- package/packages/cli/vendor/src/showcase/premium/breadcrumbs/showcase.tsx +3 -1
- package/packages/cli/vendor/src/showcase/premium/button/mock.ts +2 -5
- package/packages/cli/vendor/src/showcase/premium/button/showcase.tsx +2 -2
- package/packages/cli/vendor/src/showcase/premium/card/showcase.tsx +26 -1
- package/packages/cli/vendor/src/showcase/premium/carousel/showcase.tsx +19 -3
- package/packages/cli/vendor/src/showcase/premium/command-bar/showcase.tsx +1 -1
- package/packages/cli/vendor/src/showcase/premium/data-table/mock.ts +26 -25
- package/packages/cli/vendor/src/showcase/premium/data-table/showcase.tsx +3 -3
- package/packages/cli/vendor/src/showcase/premium/data-table-parts/showcase.tsx +3 -3
- package/packages/cli/vendor/src/showcase/premium/file-upload/showcase.tsx +21 -1
- package/packages/cli/vendor/src/showcase/premium/image-upload/showcase.tsx +4 -1
- package/packages/cli/vendor/src/showcase/premium/index.ts +0 -2
- package/packages/cli/vendor/src/showcase/premium/loading-state/showcase.tsx +1 -1
- package/packages/cli/vendor/src/showcase/premium/metric-grid/showcase.tsx +36 -4
- package/packages/cli/vendor/src/showcase/premium/notification-center/showcase.tsx +4 -3
- package/packages/cli/vendor/src/showcase/premium/page-state/showcase.tsx +1 -0
- package/packages/cli/vendor/src/showcase/premium/pagination/showcase.tsx +13 -1
- package/packages/cli/vendor/src/showcase/premium/popover/showcase.tsx +27 -11
- package/packages/cli/vendor/src/showcase/premium/radio-group/showcase.tsx +13 -1
- package/packages/cli/vendor/src/showcase/premium/right-click-menu/showcase.tsx +8 -5
- package/packages/cli/vendor/src/showcase/premium/segmented-control/showcase.tsx +1 -0
- package/packages/cli/vendor/src/showcase/premium/select/data.ts +12 -3
- package/packages/cli/vendor/src/showcase/premium/select/mock.ts +4 -4
- package/packages/cli/vendor/src/showcase/premium/select/showcase.tsx +35 -22
- package/packages/cli/vendor/src/showcase/premium/select/types.ts +3 -0
- package/packages/cli/vendor/src/showcase/premium/statistic/showcase.tsx +10 -1
- package/packages/cli/vendor/src/showcase/premium/switch/showcase.tsx +15 -6
- package/packages/cli/vendor/src/showcase/premium/tabs/showcase.tsx +48 -1
- package/packages/cli/vendor/src/showcase/premium/textarea/mock.ts +12 -4
- package/packages/cli/vendor/src/showcase/premium/textarea/showcase.tsx +5 -0
- package/packages/cli/vendor/src/showcase/premium/toast/showcase.tsx +17 -1
- package/packages/cli/vendor/src/showcase/premium/types.ts +1 -1
- package/packages/cli/vendor/src/showcase/registry-quality.ts +3 -2
- package/packages/cli/vendor/src/showcase/registry-specific.tsx +7 -8
- package/packages/cli/vendor/src/showcase/render-registry-preview.tsx +5 -21
- package/packages/cli/vendor/src/showcase/site-data.tsx +21 -15
- package/packages/cli/vendor/src/showcase/tembro-registry.json +42 -20
- package/packages/cli/vendor/src/showcase/types.ts +1 -1
- package/registry.json +18 -6
|
@@ -4,7 +4,8 @@ import { FileIcon, UploadCloudIcon, XIcon } from "lucide-react"
|
|
|
4
4
|
import { Button } from "@/components/ui/button"
|
|
5
5
|
import { cn, stopInteractivePropagation } from "@/lib/utils"
|
|
6
6
|
|
|
7
|
-
export type FileUploadRejectReason = "max-files" | "max-size" | "type"
|
|
7
|
+
export type FileUploadRejectReason = "max-files" | "max-size" | "type"
|
|
8
|
+
export type FileUploadItemStatus = "idle" | "uploading" | "success" | "error"
|
|
8
9
|
|
|
9
10
|
export type FileUploadRejectedFile = {
|
|
10
11
|
file: File
|
|
@@ -24,13 +25,15 @@ export type FileUploadRejectionMessages = Partial<
|
|
|
24
25
|
Record<FileUploadRejectReason, string | ((context: FileUploadRejectionMessageContext) => string)>
|
|
25
26
|
>
|
|
26
27
|
|
|
27
|
-
export type FileUploadRenderFileState = {
|
|
28
|
-
file: File
|
|
29
|
-
index: number
|
|
30
|
-
progress?: number
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
28
|
+
export type FileUploadRenderFileState = {
|
|
29
|
+
file: File
|
|
30
|
+
index: number
|
|
31
|
+
progress?: number
|
|
32
|
+
status: FileUploadItemStatus
|
|
33
|
+
remove: () => void
|
|
34
|
+
retry?: () => void
|
|
35
|
+
removeLabel?: string
|
|
36
|
+
}
|
|
34
37
|
|
|
35
38
|
export type FileUploadRenderRejectedFileState = {
|
|
36
39
|
rejectedFile: FileUploadRejectedFile
|
|
@@ -70,13 +73,17 @@ export type FileUploadProps = NativeFileInputProps & {
|
|
|
70
73
|
rejectionMessages?: FileUploadRejectionMessages
|
|
71
74
|
maxFiles?: number
|
|
72
75
|
maxSize?: number
|
|
73
|
-
appendFiles?: boolean
|
|
74
|
-
showFileList?: boolean
|
|
75
|
-
showClearButton?: boolean
|
|
76
|
-
loading?: boolean
|
|
77
|
-
progress?: number | Record<string, number>
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
appendFiles?: boolean
|
|
77
|
+
showFileList?: boolean
|
|
78
|
+
showClearButton?: boolean
|
|
79
|
+
loading?: boolean
|
|
80
|
+
progress?: number | Record<string, number>
|
|
81
|
+
status?: FileUploadItemStatus | Record<string, FileUploadItemStatus>
|
|
82
|
+
validateFile?: (file: File) => string | null | Promise<string | null>
|
|
83
|
+
onRetryFile?: (file: File, index: number) => void
|
|
84
|
+
fileTriggerLabel?: string
|
|
85
|
+
renderFile?: (state: FileUploadRenderFileState) => React.ReactNode
|
|
86
|
+
renderRejectedFile?: (state: FileUploadRenderRejectedFileState) => React.ReactNode
|
|
80
87
|
renderActions?: (state: { openFileDialog: () => void; clearFiles: () => void; files: File[] }) => React.ReactNode
|
|
81
88
|
className?: string
|
|
82
89
|
inputClassName?: string
|
|
@@ -122,10 +129,15 @@ function getFileKey(file: File) {
|
|
|
122
129
|
return `${file.name}-${file.size}-${file.lastModified}`
|
|
123
130
|
}
|
|
124
131
|
|
|
125
|
-
function getProgressForFile(progress: FileUploadProps["progress"], file: File) {
|
|
126
|
-
if (typeof progress === "number") return progress
|
|
127
|
-
return progress?.[getFileKey(file)] ?? progress?.[file.name]
|
|
128
|
-
}
|
|
132
|
+
function getProgressForFile(progress: FileUploadProps["progress"], file: File) {
|
|
133
|
+
if (typeof progress === "number") return progress
|
|
134
|
+
return progress?.[getFileKey(file)] ?? progress?.[file.name]
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function getStatusForFile(status: FileUploadProps["status"], file: File): FileUploadItemStatus {
|
|
138
|
+
if (typeof status === "string") return status
|
|
139
|
+
return status?.[getFileKey(file)] ?? status?.[file.name] ?? "idle"
|
|
140
|
+
}
|
|
129
141
|
|
|
130
142
|
function resolveRejectionMessage(
|
|
131
143
|
reason: FileUploadRejectReason,
|
|
@@ -148,29 +160,31 @@ function resolveRejectionMessage(
|
|
|
148
160
|
}
|
|
149
161
|
}
|
|
150
162
|
|
|
151
|
-
function validateIncomingFiles({
|
|
163
|
+
function validateIncomingFiles({
|
|
152
164
|
currentFiles,
|
|
153
165
|
incomingFiles,
|
|
154
166
|
accept,
|
|
155
167
|
maxFiles,
|
|
156
|
-
maxSize,
|
|
157
|
-
appendFiles,
|
|
158
|
-
rejectionMessages,
|
|
159
|
-
|
|
168
|
+
maxSize,
|
|
169
|
+
appendFiles,
|
|
170
|
+
rejectionMessages,
|
|
171
|
+
validateFile,
|
|
172
|
+
}: {
|
|
160
173
|
currentFiles: File[]
|
|
161
174
|
incomingFiles: File[]
|
|
162
175
|
accept?: string
|
|
163
176
|
maxFiles?: number
|
|
164
177
|
maxSize?: number
|
|
165
|
-
appendFiles: boolean
|
|
166
|
-
rejectionMessages?: FileUploadRejectionMessages
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
const
|
|
178
|
+
appendFiles: boolean
|
|
179
|
+
rejectionMessages?: FileUploadRejectionMessages
|
|
180
|
+
validateFile?: FileUploadProps["validateFile"]
|
|
181
|
+
}) {
|
|
182
|
+
const accepted: File[] = []
|
|
183
|
+
const rejected: FileUploadRejectedFile[] = []
|
|
170
184
|
const nextBase = appendFiles ? currentFiles : []
|
|
171
185
|
const effectiveMaxFiles = maxFiles ?? (appendFiles ? undefined : incomingFiles.length)
|
|
172
186
|
|
|
173
|
-
for (const file of incomingFiles) {
|
|
187
|
+
for (const file of incomingFiles) {
|
|
174
188
|
if (effectiveMaxFiles !== undefined && nextBase.length + accepted.length >= effectiveMaxFiles) {
|
|
175
189
|
rejected.push({
|
|
176
190
|
file,
|
|
@@ -189,17 +203,27 @@ function validateIncomingFiles({
|
|
|
189
203
|
continue
|
|
190
204
|
}
|
|
191
205
|
|
|
192
|
-
if (!fileMatchesAccept(file, accept)) {
|
|
206
|
+
if (!fileMatchesAccept(file, accept)) {
|
|
193
207
|
rejected.push({
|
|
194
208
|
file,
|
|
195
209
|
reason: "type",
|
|
196
210
|
message: resolveRejectionMessage("type", { file, maxFiles: effectiveMaxFiles, maxSize, accept }, rejectionMessages),
|
|
197
211
|
})
|
|
198
|
-
continue
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
212
|
+
continue
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const customMessage = validateFile?.(file)
|
|
216
|
+
if (typeof customMessage === "string" && customMessage) {
|
|
217
|
+
rejected.push({
|
|
218
|
+
file,
|
|
219
|
+
reason: "type",
|
|
220
|
+
message: customMessage,
|
|
221
|
+
})
|
|
222
|
+
continue
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
accepted.push(file)
|
|
226
|
+
}
|
|
203
227
|
|
|
204
228
|
return {
|
|
205
229
|
accepted,
|
|
@@ -208,14 +232,25 @@ function validateIncomingFiles({
|
|
|
208
232
|
}
|
|
209
233
|
}
|
|
210
234
|
|
|
211
|
-
function defaultRenderFile({ file, progress, remove, removeLabel = "Remove file" }: FileUploadRenderFileState) {
|
|
235
|
+
function defaultRenderFile({ file, progress, status, remove, retry, removeLabel = "Remove file" }: FileUploadRenderFileState) {
|
|
212
236
|
return (
|
|
213
237
|
<div className="flex min-w-0 items-center gap-3">
|
|
214
238
|
<span className="flex size-9 shrink-0 items-center justify-center rounded-full border border-border/70 bg-background/90 shadow-sm">
|
|
215
239
|
<FileIcon className="size-4 text-muted-foreground" />
|
|
216
240
|
</span>
|
|
217
241
|
<div className="min-w-0 flex-1">
|
|
218
|
-
<div className="
|
|
242
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
243
|
+
<div className="truncate text-sm font-medium text-foreground">{file.name}</div>
|
|
244
|
+
<span className={cn(
|
|
245
|
+
"rounded-full px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.16em]",
|
|
246
|
+
status === "uploading" && "bg-primary/10 text-primary",
|
|
247
|
+
status === "success" && "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400",
|
|
248
|
+
status === "error" && "bg-destructive/10 text-destructive",
|
|
249
|
+
status === "idle" && "bg-muted text-muted-foreground"
|
|
250
|
+
)}>
|
|
251
|
+
{status}
|
|
252
|
+
</span>
|
|
253
|
+
</div>
|
|
219
254
|
<div className="text-xs text-muted-foreground">{formatBytes(file.size)}</div>
|
|
220
255
|
{typeof progress === "number" && (
|
|
221
256
|
<div className="mt-2 h-1.5 overflow-hidden rounded-full bg-muted/80">
|
|
@@ -226,6 +261,11 @@ function defaultRenderFile({ file, progress, remove, removeLabel = "Remove file"
|
|
|
226
261
|
</div>
|
|
227
262
|
)}
|
|
228
263
|
</div>
|
|
264
|
+
{status === "error" && retry ? (
|
|
265
|
+
<Button type="button" variant="outline" size="sm" className="rounded-full" onClick={retry}>
|
|
266
|
+
Retry
|
|
267
|
+
</Button>
|
|
268
|
+
) : null}
|
|
229
269
|
<Button
|
|
230
270
|
type="button"
|
|
231
271
|
variant="ghost"
|
|
@@ -245,7 +285,7 @@ function defaultRenderFile({ file, progress, remove, removeLabel = "Remove file"
|
|
|
245
285
|
)
|
|
246
286
|
}
|
|
247
287
|
|
|
248
|
-
function FileUpload({
|
|
288
|
+
function FileUpload({
|
|
249
289
|
files = [],
|
|
250
290
|
onFilesChange,
|
|
251
291
|
rejectedFiles,
|
|
@@ -264,9 +304,13 @@ function FileUpload({
|
|
|
264
304
|
appendFiles = true,
|
|
265
305
|
showFileList = true,
|
|
266
306
|
showClearButton = true,
|
|
267
|
-
loading = false,
|
|
268
|
-
progress,
|
|
269
|
-
|
|
307
|
+
loading = false,
|
|
308
|
+
progress,
|
|
309
|
+
status,
|
|
310
|
+
validateFile,
|
|
311
|
+
onRetryFile,
|
|
312
|
+
fileTriggerLabel = "Open file picker",
|
|
313
|
+
renderFile,
|
|
270
314
|
renderRejectedFile,
|
|
271
315
|
renderActions,
|
|
272
316
|
className,
|
|
@@ -316,13 +360,22 @@ function FileUpload({
|
|
|
316
360
|
}, [onFilesChange, setRejectedFiles])
|
|
317
361
|
|
|
318
362
|
const processFiles = React.useCallback(
|
|
319
|
-
(incomingFiles: File[]) => {
|
|
320
|
-
const result = validateIncomingFiles({
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
363
|
+
(incomingFiles: File[]) => {
|
|
364
|
+
const result = validateIncomingFiles({
|
|
365
|
+
currentFiles: files,
|
|
366
|
+
incomingFiles,
|
|
367
|
+
accept,
|
|
368
|
+
maxFiles,
|
|
369
|
+
maxSize,
|
|
370
|
+
appendFiles,
|
|
371
|
+
rejectionMessages,
|
|
372
|
+
validateFile,
|
|
373
|
+
})
|
|
374
|
+
onFilesChange?.(result.nextFiles)
|
|
375
|
+
setRejectedFiles(result.rejected)
|
|
376
|
+
},
|
|
377
|
+
[accept, appendFiles, files, maxFiles, maxSize, onFilesChange, rejectionMessages, setRejectedFiles, validateFile]
|
|
378
|
+
)
|
|
326
379
|
|
|
327
380
|
const removeFile = React.useCallback(
|
|
328
381
|
(fileIndex: number) => {
|
|
@@ -333,7 +386,7 @@ function FileUpload({
|
|
|
333
386
|
|
|
334
387
|
const handleChange: React.ChangeEventHandler<HTMLInputElement> = (event) => {
|
|
335
388
|
if (isDisabled) return
|
|
336
|
-
processFiles(Array.from(event.target.files ?? []))
|
|
389
|
+
processFiles(Array.from(event.target.files ?? []))
|
|
337
390
|
event.target.value = ""
|
|
338
391
|
}
|
|
339
392
|
|
|
@@ -371,8 +424,8 @@ function FileUpload({
|
|
|
371
424
|
event.preventDefault()
|
|
372
425
|
dragDepthRef.current = 0
|
|
373
426
|
setIsDragging(false)
|
|
374
|
-
processFiles(Array.from(event.dataTransfer.files ?? []))
|
|
375
|
-
}
|
|
427
|
+
processFiles(Array.from(event.dataTransfer.files ?? []))
|
|
428
|
+
}
|
|
376
429
|
|
|
377
430
|
return (
|
|
378
431
|
<div data-slot="file-upload" className={cn("grid gap-3", className)}>
|
|
@@ -391,9 +444,9 @@ function FileUpload({
|
|
|
391
444
|
data-slot="file-upload-dropzone"
|
|
392
445
|
data-dragging={isDragging || undefined}
|
|
393
446
|
data-disabled={isDisabled || undefined}
|
|
394
|
-
role="button"
|
|
395
|
-
aria-disabled={isDisabled || undefined}
|
|
396
|
-
aria-label={dropzoneAriaLabel}
|
|
447
|
+
role="button"
|
|
448
|
+
aria-disabled={isDisabled || undefined}
|
|
449
|
+
aria-label={dropzoneAriaLabel ?? fileTriggerLabel}
|
|
397
450
|
tabIndex={isDisabled ? -1 : 0}
|
|
398
451
|
className={cn(
|
|
399
452
|
"grid cursor-pointer gap-4 rounded-[var(--radius-2xl)] border border-dashed border-border/80 bg-[linear-gradient(180deg,color-mix(in_oklch,var(--card),white_12%),var(--card))] p-6 text-center shadow-sm ring-1 ring-foreground/5 outline-none transition-[background-color,border-color,box-shadow,transform] hover:-translate-y-px hover:border-primary/35 hover:bg-muted/25 hover:shadow-[0_14px_36px_rgba(15,23,42,0.08)] focus-visible:ring-2 focus-visible:ring-ring data-[dragging=true]:border-primary data-[dragging=true]:bg-primary/6 data-[dragging=true]:shadow-[0_18px_50px_color-mix(in_oklch,var(--primary),transparent_84%)] data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-60",
|
|
@@ -432,6 +485,7 @@ function FileUpload({
|
|
|
432
485
|
variant="outline"
|
|
433
486
|
size="sm"
|
|
434
487
|
disabled={isDisabled}
|
|
488
|
+
aria-label={typeof buttonLabel === "string" ? buttonLabel : fileTriggerLabel}
|
|
435
489
|
onClick={(event) => {
|
|
436
490
|
stopInteractivePropagation(event)
|
|
437
491
|
openFileDialog()
|
|
@@ -463,13 +517,22 @@ function FileUpload({
|
|
|
463
517
|
|
|
464
518
|
{showFileList && files.length > 0 && (
|
|
465
519
|
<div data-slot="file-upload-list" className={cn("grid gap-2", fileListClassName)}>
|
|
466
|
-
{files.map((file, index) => {
|
|
467
|
-
const state = {
|
|
520
|
+
{files.map((file, index) => {
|
|
521
|
+
const state = {
|
|
522
|
+
file,
|
|
523
|
+
index,
|
|
524
|
+
progress: getProgressForFile(progress, file),
|
|
525
|
+
status: getStatusForFile(status, file),
|
|
526
|
+
remove: () => removeFile(index),
|
|
527
|
+
retry: onRetryFile ? () => onRetryFile(file, index) : undefined,
|
|
528
|
+
removeLabel,
|
|
529
|
+
}
|
|
468
530
|
|
|
469
531
|
return (
|
|
470
532
|
<div
|
|
471
533
|
key={`${file.name}-${file.lastModified}-${index}`}
|
|
472
534
|
data-slot="file-upload-item"
|
|
535
|
+
data-status={state.status}
|
|
473
536
|
className={cn("rounded-[min(var(--radius-xl),18px)] border border-border/80 bg-[linear-gradient(180deg,color-mix(in_oklch,var(--card),white_10%),var(--card))] p-3.5 shadow-sm ring-1 ring-foreground/5", fileItemClassName)}
|
|
474
537
|
>
|
|
475
538
|
{renderFile?.(state) ?? defaultRenderFile(state)}
|
|
@@ -11,13 +11,33 @@ import {
|
|
|
11
11
|
import { Button } from "@/components/ui/button"
|
|
12
12
|
import { cn, stopInteractivePropagation } from "@/lib/utils"
|
|
13
13
|
|
|
14
|
-
export type ImageUploadProps = Omit<FileUploadProps, "accept" | "renderFile"> & {
|
|
15
|
-
accept?: string
|
|
16
|
-
preview?: boolean
|
|
17
|
-
previewClassName?: string
|
|
18
|
-
imageClassName?: string
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
export type ImageUploadProps = Omit<FileUploadProps, "accept" | "renderFile"> & {
|
|
15
|
+
accept?: string
|
|
16
|
+
preview?: boolean
|
|
17
|
+
previewClassName?: string
|
|
18
|
+
imageClassName?: string
|
|
19
|
+
minImageWidth?: number
|
|
20
|
+
minImageHeight?: number
|
|
21
|
+
aspectRatio?: number
|
|
22
|
+
aspectRatioTolerance?: number
|
|
23
|
+
renderImageFile?: (state: FileUploadRenderFileState & { previewUrl?: string }) => React.ReactNode
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function readImageMeta(file: File) {
|
|
27
|
+
return new Promise<{ width: number; height: number }>((resolve, reject) => {
|
|
28
|
+
const url = URL.createObjectURL(file)
|
|
29
|
+
const image = new Image()
|
|
30
|
+
image.onload = () => {
|
|
31
|
+
resolve({ width: image.width, height: image.height })
|
|
32
|
+
URL.revokeObjectURL(url)
|
|
33
|
+
}
|
|
34
|
+
image.onerror = () => {
|
|
35
|
+
URL.revokeObjectURL(url)
|
|
36
|
+
reject(new Error("Image metadata could not be read"))
|
|
37
|
+
}
|
|
38
|
+
image.src = url
|
|
39
|
+
})
|
|
40
|
+
}
|
|
21
41
|
|
|
22
42
|
function useImagePreviewUrls(files: File[], enabled = true) {
|
|
23
43
|
const [urls, setUrls] = React.useState<Record<string, string>>({})
|
|
@@ -104,22 +124,49 @@ function ImageUpload({
|
|
|
104
124
|
buttonLabel = "Choose image",
|
|
105
125
|
dropzoneLabel = "Drop images here or click to upload",
|
|
106
126
|
preview = true,
|
|
107
|
-
previewClassName,
|
|
108
|
-
imageClassName,
|
|
109
|
-
files = [],
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
127
|
+
previewClassName,
|
|
128
|
+
imageClassName,
|
|
129
|
+
files = [],
|
|
130
|
+
minImageWidth,
|
|
131
|
+
minImageHeight,
|
|
132
|
+
aspectRatio,
|
|
133
|
+
aspectRatioTolerance = 0.04,
|
|
134
|
+
renderImageFile,
|
|
135
|
+
...props
|
|
136
|
+
}: ImageUploadProps) {
|
|
137
|
+
const previewUrls = useImagePreviewUrls(files, preview)
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<FileUpload
|
|
141
|
+
accept={accept}
|
|
142
|
+
buttonLabel={buttonLabel}
|
|
143
|
+
dropzoneLabel={dropzoneLabel}
|
|
144
|
+
files={files}
|
|
145
|
+
validateFile={async (file) => {
|
|
146
|
+
if (!file.type.startsWith("image/")) return "Only image files are allowed."
|
|
147
|
+
if (!minImageWidth && !minImageHeight && !aspectRatio) return null
|
|
148
|
+
|
|
149
|
+
const { width, height } = await readImageMeta(file)
|
|
150
|
+
|
|
151
|
+
if (minImageWidth && width < minImageWidth) {
|
|
152
|
+
return `Image width must be at least ${minImageWidth}px.`
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (minImageHeight && height < minImageHeight) {
|
|
156
|
+
return `Image height must be at least ${minImageHeight}px.`
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (aspectRatio) {
|
|
160
|
+
const ratio = width / height
|
|
161
|
+
if (Math.abs(ratio - aspectRatio) > aspectRatioTolerance) {
|
|
162
|
+
return `Image ratio must be close to ${aspectRatio.toFixed(2)}:1.`
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return null
|
|
167
|
+
}}
|
|
168
|
+
renderFile={(state) => {
|
|
169
|
+
const previewUrl = previewUrls[getFileKey(state.file)]
|
|
123
170
|
|
|
124
171
|
return renderImageFile?.({ ...state, previewUrl }) ??
|
|
125
172
|
defaultRenderImageFile({ ...state, previewUrl, previewClassName, imageClassName })
|
|
@@ -129,4 +176,4 @@ function ImageUpload({
|
|
|
129
176
|
)
|
|
130
177
|
}
|
|
131
178
|
|
|
132
|
-
export { ImageUpload, useImagePreviewUrls }
|
|
179
|
+
export { ImageUpload, useImagePreviewUrls }
|
|
@@ -14,6 +14,9 @@ export const documentedPublicComponentSurfaces: readonly PublicComponentSurfaceE
|
|
|
14
14
|
{ slug: "overlay", registryName: "dialog", surface: "documented" },
|
|
15
15
|
{ slug: "form-field", registryName: "form-field-shell", surface: "documented" },
|
|
16
16
|
{ slug: "data-table", registryName: "data-table", surface: "documented" },
|
|
17
|
+
{ slug: "calendar", registryName: "calendar", surface: "documented" },
|
|
18
|
+
{ slug: "date-picker", registryName: "date-picker", surface: "documented" },
|
|
19
|
+
{ slug: "date-range-picker", registryName: "date-range-picker", surface: "documented" },
|
|
17
20
|
{ slug: "alert", registryName: "alert", surface: "documented" },
|
|
18
21
|
{ slug: "bar-chart", registryName: "charts", surface: "documented" },
|
|
19
22
|
{ slug: "sidebar", registryName: "sidebar", surface: "documented" },
|
|
@@ -29,14 +29,16 @@ export const componentApiSchemas: Record<string, ComponentApiSchema> = {
|
|
|
29
29
|
{ name: "variant", type: "'default' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'warning' | 'link'", defaultValue: "'default'", description: "Controls visual hierarchy and action tone.", example: "variant=\"destructive\"" },
|
|
30
30
|
{ name: "size", type: "'xs' | 'sm' | 'default' | 'md' | 'lg' | 'xl' | 'icon' | 'icon-xs' | 'icon-sm' | 'icon-lg'", defaultValue: "'default'", description: "Controls height, spacing and icon-only sizing.", example: "size=\"icon-sm\"" },
|
|
31
31
|
{ name: "loading", type: "boolean", defaultValue: "false", description: "Shows the spinner, disables interaction and communicates pending state.", example: "loading={isSaving}" },
|
|
32
|
-
{ name: "loadingLabel", type: "string", defaultValue: "'Loading'", description: "Accessible label displayed while the button is loading.", example: "loadingLabel=\"Saving\"" },
|
|
33
|
-
{ name: "disabled", type: "boolean", defaultValue: "false", description: "Disables the action and removes it from normal interaction.", example: "disabled={!canSubmit}" },
|
|
34
|
-
{ name: "leftIcon", type: "ReactNode", defaultValue: "-", description: "Icon rendered before the label. Use for primary verbs and scan-friendly actions." },
|
|
35
|
-
{ name: "rightIcon", type: "ReactNode", defaultValue: "-", description: "Icon rendered after the label. Use for forward navigation or external transitions." },
|
|
36
|
-
{ name: "
|
|
37
|
-
{ name: "
|
|
38
|
-
{ name: "
|
|
39
|
-
{ name: "
|
|
32
|
+
{ name: "loadingLabel", type: "string", defaultValue: "'Loading'", description: "Accessible label displayed while the button is loading.", example: "loadingLabel=\"Saving\"" },
|
|
33
|
+
{ name: "disabled", type: "boolean", defaultValue: "false", description: "Disables the action and removes it from normal interaction.", example: "disabled={!canSubmit}" },
|
|
34
|
+
{ name: "leftIcon", type: "ReactNode", defaultValue: "-", description: "Icon rendered before the label. Use for primary verbs and scan-friendly actions." },
|
|
35
|
+
{ name: "rightIcon", type: "ReactNode", defaultValue: "-", description: "Icon rendered after the label. Use for forward navigation or external transitions." },
|
|
36
|
+
{ name: "iconOnly", type: "boolean", defaultValue: "false", description: "Switches default sizing to the icon button size while keeping Button semantics.", example: "iconOnly aria-label=\"Download\"" },
|
|
37
|
+
{ name: "fullWidth", type: "boolean", defaultValue: "false", description: "Expands the button to fill its parent width.", example: "fullWidth" },
|
|
38
|
+
{ name: "pressed", type: "boolean", defaultValue: "false", description: "Marks toggle-like button state with aria-pressed and selected styling.", example: "pressed={active}" },
|
|
39
|
+
{ name: "className", type: "string", defaultValue: "-", description: "Optional class override for spacing or layout composition." },
|
|
40
|
+
{ name: "children", type: "ReactNode", defaultValue: "-", required: true, description: "Button label or icon content. Icon-only buttons must still provide an accessible name." },
|
|
41
|
+
{ name: "aria-label", type: "string", defaultValue: "-", description: "Required for icon-only buttons so the action is announced correctly.", notes: "Use when children are only icons." },
|
|
40
42
|
],
|
|
41
43
|
examples: [
|
|
42
44
|
{ title: "Primary action", code: "<Button>Save changes</Button>" },
|
|
@@ -51,18 +53,24 @@ export const componentApiSchemas: Record<string, ComponentApiSchema> = {
|
|
|
51
53
|
source: "metadata",
|
|
52
54
|
summary: "Primary typed-value surface. Start with Input and move into presets only when behavior requires it.",
|
|
53
55
|
props: [
|
|
54
|
-
{ name: "value", type: "string | number", defaultValue: "-", description: "Controlled input value.", example: "value={name}" },
|
|
55
|
-
{ name: "defaultValue", type: "string | number", defaultValue: "-", description: "Uncontrolled initial value." },
|
|
56
|
-
{ name: "
|
|
57
|
-
{ name: "
|
|
58
|
-
{ name: "
|
|
59
|
-
{ name: "
|
|
60
|
-
{ name: "
|
|
61
|
-
{ name: "
|
|
62
|
-
{ name: "
|
|
63
|
-
{ name: "
|
|
64
|
-
{ name: "
|
|
65
|
-
{ name: "
|
|
56
|
+
{ name: "value", type: "string | number", defaultValue: "-", description: "Controlled input value.", example: "value={name}" },
|
|
57
|
+
{ name: "defaultValue", type: "string | number", defaultValue: "-", description: "Uncontrolled initial value." },
|
|
58
|
+
{ name: "kind", type: "'text' | 'search' | 'password' | 'number' | 'phone' | 'money' | 'quantity' | 'masked' | 'date' | 'date-range'", defaultValue: "'text'", description: "Routes Input into a supported preset without teaching a new public component name first.", example: "kind=\"search\"" },
|
|
59
|
+
{ name: "onChange", type: "ChangeEventHandler<HTMLInputElement>", defaultValue: "-", description: "Native change handler for value updates.", example: "onChange={(event) => setValue(event.target.value)}" },
|
|
60
|
+
{ name: "onValueChange", type: "(value: string) => void", defaultValue: "-", description: "Direct text callback for controlled string flows.", example: "onValueChange={setQuery}" },
|
|
61
|
+
{ name: "type", type: "HTMLInputTypeAttribute", defaultValue: "'text'", description: "Native input type. Prefer presets only when formatting or masking is required." },
|
|
62
|
+
{ name: "placeholder", type: "string", defaultValue: "-", description: "Short hint for empty input state." },
|
|
63
|
+
{ name: "leading", type: "ReactNode", defaultValue: "-", description: "Non-interactive leading slot for icons, prefixes, or labels." },
|
|
64
|
+
{ name: "trailing", type: "ReactNode", defaultValue: "-", description: "Passive trailing slot for units, counts, or status copy." },
|
|
65
|
+
{ name: "clearable", type: "boolean", defaultValue: "false", description: "Shows the built-in clear action when a value exists.", example: "clearable" },
|
|
66
|
+
{ name: "onClear", type: "() => void", defaultValue: "-", description: "Called after the built-in clear action resets the field." },
|
|
67
|
+
{ name: "trailingAction", type: "ReactNode", defaultValue: "-", description: "Interactive trailing slot for counters, shortcuts, or toggle actions.", example: "trailingAction={<span>12 results</span>}" },
|
|
68
|
+
{ name: "replaceTrailingWhenClear", type: "boolean", defaultValue: "true", description: "Controls whether clear replaces trailing content or sits beside it." },
|
|
69
|
+
{ name: "clearOnEscape", type: "boolean", defaultValue: "false", description: "Clears the value on Escape when clearable mode is active." },
|
|
70
|
+
{ name: "helperText", type: "ReactNode", defaultValue: "-", description: "Support copy rendered below the field." },
|
|
71
|
+
{ name: "errorText", type: "ReactNode", defaultValue: "-", description: "Validation copy rendered below the field and connected to danger styling." },
|
|
72
|
+
{ name: "showCharacterCount", type: "boolean", defaultValue: "false", description: "Shows current length and maxLength when available." },
|
|
73
|
+
{ name: "disabled", type: "boolean", defaultValue: "false", description: "Disables editing and interaction." },
|
|
66
74
|
{ name: "required", type: "boolean", defaultValue: "false", description: "Marks the input as required for native validation." },
|
|
67
75
|
{ name: "name", type: "string", defaultValue: "-", description: "Form field name used during submission." },
|
|
68
76
|
{ name: "id", type: "string", defaultValue: "-", description: "Connects input to label and help text." },
|
|
@@ -75,27 +83,57 @@ export const componentApiSchemas: Record<string, ComponentApiSchema> = {
|
|
|
75
83
|
],
|
|
76
84
|
accessibility: ["Always pair form inputs with labels.", "Use aria-describedby for helper/error text.", "Keep disabled and read-only states visually distinct."],
|
|
77
85
|
},
|
|
78
|
-
select: {
|
|
79
|
-
slug: "select",
|
|
80
|
-
source: "metadata",
|
|
81
|
-
summary: "Primary selection surface. Start with Select
|
|
82
|
-
props: [
|
|
83
|
-
{ name: "value", type: "string |
|
|
84
|
-
{ name: "defaultValue", type: "string |
|
|
85
|
-
{ name: "onValueChange", type: "(value: string |
|
|
86
|
-
{ name: "options", type: "Array<{ label: string; value: string; disabled?: boolean }>", defaultValue: "[]", required: true, description: "Selectable option list." },
|
|
87
|
-
{ name: "
|
|
88
|
-
{ name: "
|
|
89
|
-
{ name: "
|
|
90
|
-
{ name: "
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
{
|
|
94
|
-
{
|
|
95
|
-
{
|
|
96
|
-
],
|
|
97
|
-
|
|
98
|
-
|
|
86
|
+
select: {
|
|
87
|
+
slug: "select",
|
|
88
|
+
source: "metadata",
|
|
89
|
+
summary: "Primary single-selection surface. Start with Select for finite option sets, then use AsyncSelect with isMulti only when remote loading or multi-value behavior is required.",
|
|
90
|
+
props: [
|
|
91
|
+
{ name: "value", type: "string | null", defaultValue: "-", description: "Controlled selected value." },
|
|
92
|
+
{ name: "defaultValue", type: "string | null", defaultValue: "-", description: "Uncontrolled initial selected value." },
|
|
93
|
+
{ name: "onValueChange", type: "(value: string | undefined) => void", defaultValue: "-", description: "Called when the selected value changes.", example: "onValueChange={setStatus}" },
|
|
94
|
+
{ name: "options", type: "Array<{ label: string; value: string; disabled?: boolean }>", defaultValue: "[]", required: true, description: "Selectable option list." },
|
|
95
|
+
{ name: "groups", type: "Array<{ label?: ReactNode; options: SelectOption[] }>", defaultValue: "-", description: "Grouped selectable options for longer finite lists." },
|
|
96
|
+
{ name: "placeholder", type: "string", defaultValue: "-", description: "Text shown when no value is selected." },
|
|
97
|
+
{ name: "disabled", type: "boolean", defaultValue: "false", description: "Disables the control and option selection." },
|
|
98
|
+
{ name: "searchable", type: "boolean", defaultValue: "false", description: "Enables local filtering on the main Select surface." },
|
|
99
|
+
{ name: "clearable", type: "boolean", defaultValue: "false", description: "Shows a clear action when a value is selected." },
|
|
100
|
+
{ name: "loading", type: "boolean", defaultValue: "false", description: "Disables selection and renders a loading state." },
|
|
101
|
+
{ name: "emptyLabel", type: "ReactNode", defaultValue: "'No options found'", description: "Empty state content for local filtering." },
|
|
102
|
+
{ name: "emptyMessage", type: "ReactNode", defaultValue: "-", description: "Alias for empty state content used by newer docs." },
|
|
103
|
+
{ name: "renderOption", type: "(option, state) => ReactNode", defaultValue: "-", description: "Custom option renderer for richer rows." },
|
|
104
|
+
],
|
|
105
|
+
examples: [
|
|
106
|
+
{ title: "Primary select", code: "<Select value={status} onValueChange={setStatus} options={statusOptions} />" },
|
|
107
|
+
{ title: "Searchable primary select", code: "<Select value={owner} onValueChange={setOwner} searchable options={ownerOptions} />" },
|
|
108
|
+
{ title: "Grouped select", code: "<Select value={region} onValueChange={setRegion} groups={regionGroups} searchable />" },
|
|
109
|
+
{ title: "Async member direction", code: "// Prefer Select first; use AsyncSelect only when remote loading is required." },
|
|
110
|
+
],
|
|
111
|
+
accessibility: ["Use clear option labels.", "Keep disabled options visible but not selectable.", "Do not replace long forms with hidden select menus."],
|
|
112
|
+
},
|
|
113
|
+
textarea: {
|
|
114
|
+
slug: "textarea",
|
|
115
|
+
source: "metadata",
|
|
116
|
+
summary: "Multi-line text entry surface with helper, error, read-only, disabled and character-count support.",
|
|
117
|
+
props: [
|
|
118
|
+
{ name: "value", type: "string", defaultValue: "-", description: "Controlled textarea value." },
|
|
119
|
+
{ name: "defaultValue", type: "string", defaultValue: "-", description: "Uncontrolled initial value." },
|
|
120
|
+
{ name: "onChange", type: "ChangeEventHandler<HTMLTextAreaElement>", defaultValue: "-", description: "Native change handler." },
|
|
121
|
+
{ name: "onValueChange", type: "(value: string) => void", defaultValue: "-", description: "Direct text callback for controlled flows." },
|
|
122
|
+
{ name: "rows", type: "number", defaultValue: "-", description: "Initial visible row count." },
|
|
123
|
+
{ name: "maxLength", type: "number", defaultValue: "-", description: "Native maximum character length." },
|
|
124
|
+
{ name: "helperText", type: "ReactNode", defaultValue: "-", description: "Support copy rendered below the field." },
|
|
125
|
+
{ name: "errorText", type: "ReactNode", defaultValue: "-", description: "Validation copy rendered below the field and danger styling." },
|
|
126
|
+
{ name: "showCharacterCount", type: "boolean", defaultValue: "false", description: "Shows current length and maxLength when available." },
|
|
127
|
+
{ name: "disabled", type: "boolean", defaultValue: "false", description: "Disables editing." },
|
|
128
|
+
{ name: "readOnly", type: "boolean", defaultValue: "false", description: "Keeps content copyable while preventing edits." },
|
|
129
|
+
],
|
|
130
|
+
examples: [
|
|
131
|
+
{ title: "Controlled note", code: "<Textarea value={note} onValueChange={setNote} helperText=\"Internal note\" />" },
|
|
132
|
+
{ title: "Limited feedback", code: "<Textarea maxLength={240} showCharacterCount />" },
|
|
133
|
+
{ title: "Error state", code: "<Textarea errorText=\"Please add at least 10 characters.\" />" },
|
|
134
|
+
],
|
|
135
|
+
accessibility: ["Pair textareas with visible labels.", "Use helper and error copy instead of placeholder-only instructions.", "Keep read-only distinct from disabled."],
|
|
136
|
+
},
|
|
99
137
|
"data-table": {
|
|
100
138
|
slug: "data-table",
|
|
101
139
|
source: "metadata",
|
|
@@ -63,16 +63,17 @@ function createCodeSnippet(definition: ShowcaseDemoDefinition) {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
const exactCodeSnippets: Record<string, string> = {
|
|
66
|
-
"search-input": `import {
|
|
67
|
-
|
|
68
|
-
export function Demo() {
|
|
69
|
-
return (
|
|
70
|
-
<
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
66
|
+
"search-input": `import { Input } from "tembro"
|
|
67
|
+
|
|
68
|
+
export function Demo() {
|
|
69
|
+
return (
|
|
70
|
+
<Input
|
|
71
|
+
type="search"
|
|
72
|
+
value="invoice"
|
|
73
|
+
onValueChange={(value) => console.log(value)}
|
|
74
|
+
placeholder="Search invoices..."
|
|
75
|
+
resultCount={12}
|
|
76
|
+
shortcut="Ctrl K"
|
|
76
77
|
/>
|
|
77
78
|
)
|
|
78
79
|
}`,
|
|
@@ -133,12 +134,12 @@ export function Demo() {
|
|
|
133
134
|
/>
|
|
134
135
|
)
|
|
135
136
|
}`,
|
|
136
|
-
"filter-bar": `import { Button, FilterBar,
|
|
137
|
-
|
|
138
|
-
export function Demo() {
|
|
139
|
-
return (
|
|
137
|
+
"filter-bar": `import { Button, FilterBar, Input } from "tembro"
|
|
138
|
+
|
|
139
|
+
export function Demo() {
|
|
140
|
+
return (
|
|
140
141
|
<FilterBar
|
|
141
|
-
search={<
|
|
142
|
+
search={<Input type="search" value="" placeholder="Search rows..." readOnly />}
|
|
142
143
|
chips={[
|
|
143
144
|
{ key: "status", label: "Status", value: "Active", tone: "success" },
|
|
144
145
|
{ key: "owner", label: "Owner", value: "Azamat" },
|