@vamos-ui/react 0.0.0-stage → 0.2.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 -0
- package/README.md +27 -2
- package/dist/blocks/block-heading.d.ts +29 -0
- package/dist/blocks/block-heading.js +39 -0
- package/dist/blocks/block-image.d.ts +52 -0
- package/dist/blocks/block-image.js +48 -0
- package/dist/blocks/block-link.d.ts +30 -0
- package/dist/blocks/block-link.js +36 -0
- package/dist/blocks/create-blocks.d.ts +54 -0
- package/dist/blocks/create-blocks.js +52 -0
- package/dist/blocks/index.d.ts +55 -0
- package/dist/blocks/index.js +59 -0
- package/dist/blocks/json-ld.d.ts +18 -0
- package/dist/blocks/json-ld.js +44 -0
- package/dist/blocks/labels.d.ts +20 -0
- package/dist/blocks/labels.js +43 -0
- package/dist/blocks/rich-text.d.ts +36 -0
- package/dist/blocks/rich-text.js +106 -0
- package/dist/blocks/schema/define-block.d.ts +151 -0
- package/dist/blocks/schema/define-block.js +120 -0
- package/dist/blocks/schema/emphasis.d.ts +17 -0
- package/dist/blocks/schema/emphasis.js +69 -0
- package/dist/blocks/schema/fields.d.ts +497 -0
- package/dist/blocks/schema/fields.js +240 -0
- package/dist/blocks/schema/icons.d.ts +2 -0
- package/dist/blocks/schema/icons.js +26 -0
- package/dist/blocks/schema/index.d.ts +18 -0
- package/dist/blocks/schema/index.js +21 -0
- package/dist/blocks/schema/lint-types.d.ts +16 -0
- package/dist/blocks/schema/lint-types.js +2 -0
- package/dist/blocks/schema/lint.d.ts +32 -0
- package/dist/blocks/schema/lint.js +164 -0
- package/dist/blocks/schema/localize.d.ts +20 -0
- package/dist/blocks/schema/localize.js +29 -0
- package/dist/blocks/schema/localized.d.ts +25 -0
- package/dist/blocks/schema/localized.js +53 -0
- package/dist/blocks/schema/migrate.d.ts +24 -0
- package/dist/blocks/schema/migrate.js +75 -0
- package/dist/blocks/schema/nodes.d.ts +196 -0
- package/dist/blocks/schema/nodes.js +78 -0
- package/dist/blocks/schema/rich-doc-schema.d.ts +32 -0
- package/dist/blocks/schema/rich-doc-schema.js +66 -0
- package/dist/blocks/schema/rich-doc.d.ts +90 -0
- package/dist/blocks/schema/rich-doc.js +62 -0
- package/dist/blocks/schema/safety.d.ts +20 -0
- package/dist/blocks/schema/safety.js +49 -0
- package/dist/blocks/schema/types.d.ts +172 -0
- package/dist/blocks/schema/types.js +3 -0
- package/dist/blocks/schema/validate.d.ts +17 -0
- package/dist/blocks/schema/validate.js +32 -0
- package/dist/blocks/schema/walk.d.ts +22 -0
- package/dist/blocks/schema/walk.js +60 -0
- package/dist/blocks/section-header.d.ts +38 -0
- package/dist/blocks/section-header.js +22 -0
- package/dist/blocks/section.d.ts +59 -0
- package/dist/blocks/section.js +66 -0
- package/dist/blocks/site/_kit-1.d.ts +100 -0
- package/dist/blocks/site/_kit-1.js +135 -0
- package/dist/blocks/site/_site-icon-1.d.ts +6 -0
- package/dist/blocks/site/_site-icon-1.js +15 -0
- package/dist/blocks/site/announcement-bar.d.ts +42 -0
- package/dist/blocks/site/announcement-bar.js +38 -0
- package/dist/blocks/site/announcement-dismiss.d.ts +18 -0
- package/dist/blocks/site/announcement-dismiss.js +28 -0
- package/dist/blocks/site/article-layout.d.ts +65 -0
- package/dist/blocks/site/article-layout.js +88 -0
- package/dist/blocks/site/blog-list.d.ts +79 -0
- package/dist/blocks/site/blog-list.js +78 -0
- package/dist/blocks/site/comparison-table.d.ts +54 -0
- package/dist/blocks/site/comparison-table.js +38 -0
- package/dist/blocks/site/consent-banner.d.ts +52 -0
- package/dist/blocks/site/consent-banner.js +33 -0
- package/dist/blocks/site/contact-dock.d.ts +52 -0
- package/dist/blocks/site/contact-dock.js +55 -0
- package/dist/blocks/site/contact-form.d.ts +60 -0
- package/dist/blocks/site/contact-form.js +45 -0
- package/dist/blocks/site/cta-booking.d.ts +43 -0
- package/dist/blocks/site/cta-booking.js +69 -0
- package/dist/blocks/site/cta.d.ts +74 -0
- package/dist/blocks/site/cta.js +112 -0
- package/dist/blocks/site/embed-facade.d.ts +20 -0
- package/dist/blocks/site/embed-facade.js +21 -0
- package/dist/blocks/site/faq.d.ts +48 -0
- package/dist/blocks/site/faq.js +51 -0
- package/dist/blocks/site/feature-grid.d.ts +46 -0
- package/dist/blocks/site/feature-grid.js +49 -0
- package/dist/blocks/site/feature-tabs.d.ts +22 -0
- package/dist/blocks/site/feature-tabs.js +11 -0
- package/dist/blocks/site/footer.d.ts +68 -0
- package/dist/blocks/site/footer.js +61 -0
- package/dist/blocks/site/gallery-section.d.ts +42 -0
- package/dist/blocks/site/gallery-section.js +47 -0
- package/dist/blocks/site/hero-video.d.ts +15 -0
- package/dist/blocks/site/hero-video.js +31 -0
- package/dist/blocks/site/hero.d.ts +64 -0
- package/dist/blocks/site/hero.js +67 -0
- package/dist/blocks/site/logo-strip.d.ts +42 -0
- package/dist/blocks/site/logo-strip.js +26 -0
- package/dist/blocks/site/map-hours.d.ts +83 -0
- package/dist/blocks/site/map-hours.js +125 -0
- package/dist/blocks/site/media-text.d.ts +45 -0
- package/dist/blocks/site/media-text.js +55 -0
- package/dist/blocks/site/menu-list.d.ts +74 -0
- package/dist/blocks/site/menu-list.js +84 -0
- package/dist/blocks/site/navbar-submenu.d.ts +18 -0
- package/dist/blocks/site/navbar-submenu.js +51 -0
- package/dist/blocks/site/navbar.d.ts +67 -0
- package/dist/blocks/site/navbar.js +64 -0
- package/dist/blocks/site/not-found.d.ts +40 -0
- package/dist/blocks/site/not-found.js +38 -0
- package/dist/blocks/site/page-intro.d.ts +46 -0
- package/dist/blocks/site/page-intro.js +44 -0
- package/dist/blocks/site/pricing-table.d.ts +67 -0
- package/dist/blocks/site/pricing-table.js +82 -0
- package/dist/blocks/site/process.d.ts +36 -0
- package/dist/blocks/site/process.js +41 -0
- package/dist/blocks/site/registry-1.d.ts +720 -0
- package/dist/blocks/site/registry-1.js +783 -0
- package/dist/blocks/site/registry-2.d.ts +914 -0
- package/dist/blocks/site/registry-2.js +563 -0
- package/dist/blocks/site/rich-text-section.d.ts +34 -0
- package/dist/blocks/site/rich-text-section.js +32 -0
- package/dist/blocks/site/shared/brand-icons.d.ts +21 -0
- package/dist/blocks/site/shared/brand-icons.js +56 -0
- package/dist/blocks/site/shared/consent-gate.d.ts +41 -0
- package/dist/blocks/site/shared/consent-gate.js +43 -0
- package/dist/blocks/site/shared/consent-island.d.ts +38 -0
- package/dist/blocks/site/shared/consent-island.js +63 -0
- package/dist/blocks/site/shared/consent.d.ts +49 -0
- package/dist/blocks/site/shared/consent.js +130 -0
- package/dist/blocks/site/shared/contact-form-island.d.ts +41 -0
- package/dist/blocks/site/shared/contact-form-island.js +100 -0
- package/dist/blocks/site/shared/copy-link.d.ts +10 -0
- package/dist/blocks/site/shared/copy-link.js +25 -0
- package/dist/blocks/site/shared/dock-avoid.d.ts +15 -0
- package/dist/blocks/site/shared/dock-avoid.js +107 -0
- package/dist/blocks/site/shared/dock-hours.d.ts +13 -0
- package/dist/blocks/site/shared/dock-hours.js +25 -0
- package/dist/blocks/site/shared/gallery-lightbox.d.ts +12 -0
- package/dist/blocks/site/shared/gallery-lightbox.js +10 -0
- package/dist/blocks/site/shared/island-keys.d.ts +10 -0
- package/dist/blocks/site/shared/island-keys.js +44 -0
- package/dist/blocks/site/shared/kit-2.d.ts +55 -0
- package/dist/blocks/site/shared/kit-2.js +84 -0
- package/dist/blocks/site/shared/labels-2.d.ts +209 -0
- package/dist/blocks/site/shared/labels-2.js +427 -0
- package/dist/blocks/site/shared/open-now.d.ts +22 -0
- package/dist/blocks/site/shared/open-now.js +27 -0
- package/dist/blocks/site/shared/opening-hours.d.ts +117 -0
- package/dist/blocks/site/shared/opening-hours.js +245 -0
- package/dist/blocks/site/shared/site-accent.d.ts +48 -0
- package/dist/blocks/site/shared/site-accent.js +249 -0
- package/dist/blocks/site/shared/site-form.d.ts +79 -0
- package/dist/blocks/site/shared/site-form.js +111 -0
- package/dist/blocks/site/shared/site-routing.d.ts +54 -0
- package/dist/blocks/site/shared/site-routing.js +86 -0
- package/dist/blocks/site/shared/testimonials-carousel.d.ts +17 -0
- package/dist/blocks/site/shared/testimonials-carousel.js +64 -0
- package/dist/blocks/site/site-shell.d.ts +97 -0
- package/dist/blocks/site/site-shell.js +227 -0
- package/dist/blocks/site/stats-band.d.ts +40 -0
- package/dist/blocks/site/stats-band.js +41 -0
- package/dist/blocks/site/team.d.ts +44 -0
- package/dist/blocks/site/team.js +48 -0
- package/dist/blocks/site/testimonials.d.ts +68 -0
- package/dist/blocks/site/testimonials.js +65 -0
- package/dist/blocks/types.d.ts +63 -0
- package/dist/blocks/types.js +2 -0
- package/dist/business/approval-flow.d.ts +152 -0
- package/dist/business/approval-flow.js +221 -0
- package/dist/business/export-core.d.ts +55 -0
- package/dist/business/export-core.js +101 -0
- package/dist/business/export.d.ts +148 -0
- package/dist/business/export.js +264 -0
- package/dist/business/import-core.d.ts +104 -0
- package/dist/business/import-core.js +281 -0
- package/dist/business/import-wizard.d.ts +186 -0
- package/dist/business/import-wizard.js +401 -0
- package/dist/business/index.d.ts +11 -0
- package/dist/business/index.js +20 -0
- package/dist/business/line-items-core.d.ts +129 -0
- package/dist/business/line-items-core.js +183 -0
- package/dist/business/line-items.d.ts +119 -0
- package/dist/business/line-items.js +299 -0
- package/dist/business/multi-step-form.d.ts +131 -0
- package/dist/business/multi-step-form.js +337 -0
- package/dist/business/permission-core.d.ts +59 -0
- package/dist/business/permission-core.js +99 -0
- package/dist/business/permission-matrix.d.ts +158 -0
- package/dist/business/permission-matrix.js +341 -0
- package/dist/business/setup-checklist.d.ts +80 -0
- package/dist/business/setup-checklist.js +92 -0
- package/dist/charts/area-chart.d.ts +35 -0
- package/dist/charts/area-chart.js +33 -0
- package/dist/charts/bar-chart.d.ts +27 -0
- package/dist/charts/bar-chart.js +42 -0
- package/dist/charts/bar-list.d.ts +47 -0
- package/dist/charts/bar-list.js +60 -0
- package/dist/charts/chart-shell.d.ts +173 -0
- package/dist/charts/chart-shell.js +205 -0
- package/dist/charts/chart.d.ts +73 -0
- package/dist/charts/chart.js +106 -0
- package/dist/charts/combo-chart.d.ts +29 -0
- package/dist/charts/combo-chart.js +47 -0
- package/dist/charts/donut-chart.d.ts +33 -0
- package/dist/charts/donut-chart.js +113 -0
- package/dist/charts/funnel.d.ts +51 -0
- package/dist/charts/funnel.js +69 -0
- package/dist/charts/gauge.d.ts +62 -0
- package/dist/charts/gauge.js +104 -0
- package/dist/charts/heatmap.d.ts +81 -0
- package/dist/charts/heatmap.js +338 -0
- package/dist/charts/index.d.ts +12 -0
- package/dist/charts/index.js +14 -0
- package/dist/charts/line-chart.d.ts +21 -0
- package/dist/charts/line-chart.js +36 -0
- package/dist/charts/test-utils.d.ts +2 -0
- package/dist/charts/test-utils.js +38 -0
- package/dist/charts/utils.d.ts +130 -0
- package/dist/charts/utils.js +262 -0
- package/dist/components/accordion.d.ts +47 -0
- package/dist/components/accordion.js +70 -0
- package/dist/components/activity-timeline.d.ts +149 -0
- package/dist/components/activity-timeline.js +122 -0
- package/dist/components/address-field.d.ts +116 -0
- package/dist/components/address-field.js +219 -0
- package/dist/components/alert-dialog.d.ts +99 -0
- package/dist/components/alert-dialog.js +192 -0
- package/dist/components/alert.d.ts +42 -0
- package/dist/components/alert.js +82 -0
- package/dist/components/app-shell.d.ts +159 -0
- package/dist/components/app-shell.js +289 -0
- package/dist/components/attachment-list.d.ts +96 -0
- package/dist/components/attachment-list.js +196 -0
- package/dist/components/audit-log.d.ts +150 -0
- package/dist/components/audit-log.js +205 -0
- package/dist/components/avatar.d.ts +87 -0
- package/dist/components/avatar.js +126 -0
- package/dist/components/badge.d.ts +41 -0
- package/dist/components/badge.js +68 -0
- package/dist/components/breadcrumb.d.ts +78 -0
- package/dist/components/breadcrumb.js +106 -0
- package/dist/components/button-group.d.ts +52 -0
- package/dist/components/button-group.js +77 -0
- package/dist/components/button.d.ts +58 -0
- package/dist/components/button.js +107 -0
- package/dist/components/calendar.d.ts +240 -0
- package/dist/components/calendar.js +483 -0
- package/dist/components/card.d.ts +66 -0
- package/dist/components/card.js +76 -0
- package/dist/components/carousel.d.ts +170 -0
- package/dist/components/carousel.js +348 -0
- package/dist/components/checkbox.d.ts +78 -0
- package/dist/components/checkbox.js +138 -0
- package/dist/components/color-picker.d.ts +112 -0
- package/dist/components/color-picker.js +235 -0
- package/dist/components/combobox.d.ts +136 -0
- package/dist/components/combobox.js +294 -0
- package/dist/components/command.d.ts +275 -0
- package/dist/components/command.js +493 -0
- package/dist/components/comment-thread.d.ts +252 -0
- package/dist/components/comment-thread.js +449 -0
- package/dist/components/context-menu.d.ts +77 -0
- package/dist/components/context-menu.js +82 -0
- package/dist/components/currency-input.d.ts +43 -0
- package/dist/components/currency-input.js +85 -0
- package/dist/components/date-picker.d.ts +141 -0
- package/dist/components/date-picker.js +241 -0
- package/dist/components/date-range-picker.d.ts +91 -0
- package/dist/components/date-range-picker.js +251 -0
- package/dist/components/description-list.d.ts +92 -0
- package/dist/components/description-list.js +42 -0
- package/dist/components/dialog.d.ts +139 -0
- package/dist/components/dialog.js +185 -0
- package/dist/components/dropdown-menu.d.ts +100 -0
- package/dist/components/dropdown-menu.js +102 -0
- package/dist/components/editor-layout.d.ts +166 -0
- package/dist/components/editor-layout.js +237 -0
- package/dist/components/empty-state.d.ts +49 -0
- package/dist/components/empty-state.js +68 -0
- package/dist/components/entity-card.d.ts +83 -0
- package/dist/components/entity-card.js +92 -0
- package/dist/components/file-upload.d.ts +256 -0
- package/dist/components/file-upload.js +490 -0
- package/dist/components/formatted-input.d.ts +177 -0
- package/dist/components/formatted-input.js +399 -0
- package/dist/components/hierarchy-chart.d.ts +190 -0
- package/dist/components/hierarchy-chart.js +890 -0
- package/dist/components/hover-card.d.ts +21 -0
- package/dist/components/hover-card.js +32 -0
- package/dist/components/iban-input.d.ts +38 -0
- package/dist/components/iban-input.js +112 -0
- package/dist/components/id-input.d.ts +65 -0
- package/dist/components/id-input.js +130 -0
- package/dist/components/image.d.ts +130 -0
- package/dist/components/image.js +168 -0
- package/dist/components/input-otp.d.ts +62 -0
- package/dist/components/input-otp.js +73 -0
- package/dist/components/input.d.ts +141 -0
- package/dist/components/input.js +187 -0
- package/dist/components/item.d.ts +96 -0
- package/dist/components/item.js +113 -0
- package/dist/components/kbd.d.ts +64 -0
- package/dist/components/kbd.js +119 -0
- package/dist/components/list-layout.d.ts +144 -0
- package/dist/components/list-layout.js +210 -0
- package/dist/components/native-select.d.ts +33 -0
- package/dist/components/native-select.js +48 -0
- package/dist/components/navigation-menu.d.ts +127 -0
- package/dist/components/navigation-menu.js +129 -0
- package/dist/components/notification-center.d.ts +164 -0
- package/dist/components/notification-center.js +399 -0
- package/dist/components/page-header.d.ts +60 -0
- package/dist/components/page-header.js +60 -0
- package/dist/components/pagination.d.ts +121 -0
- package/dist/components/pagination.js +174 -0
- package/dist/components/phone-input.d.ts +49 -0
- package/dist/components/phone-input.js +266 -0
- package/dist/components/popover.d.ts +38 -0
- package/dist/components/popover.js +69 -0
- package/dist/components/progress.d.ts +79 -0
- package/dist/components/progress.js +97 -0
- package/dist/components/radio-group.d.ts +43 -0
- package/dist/components/radio-group.js +81 -0
- package/dist/components/record-detail-layout.d.ts +167 -0
- package/dist/components/record-detail-layout.js +233 -0
- package/dist/components/record-picker.d.ts +199 -0
- package/dist/components/record-picker.js +650 -0
- package/dist/components/resizable.d.ts +50 -0
- package/dist/components/resizable.js +88 -0
- package/dist/components/scroll-area.d.ts +40 -0
- package/dist/components/scroll-area.js +56 -0
- package/dist/components/select.d.ts +126 -0
- package/dist/components/select.js +137 -0
- package/dist/components/separator.d.ts +31 -0
- package/dist/components/separator.js +41 -0
- package/dist/components/settings-layout.d.ts +134 -0
- package/dist/components/settings-layout.js +180 -0
- package/dist/components/sheet.d.ts +103 -0
- package/dist/components/sheet.js +165 -0
- package/dist/components/sidebar.d.ts +171 -0
- package/dist/components/sidebar.js +421 -0
- package/dist/components/signature-pad.d.ts +85 -0
- package/dist/components/signature-pad.js +283 -0
- package/dist/components/skeleton.d.ts +64 -0
- package/dist/components/skeleton.js +53 -0
- package/dist/components/slider.d.ts +57 -0
- package/dist/components/slider.js +133 -0
- package/dist/components/slug-input.d.ts +69 -0
- package/dist/components/slug-input.js +201 -0
- package/dist/components/sparkline.d.ts +54 -0
- package/dist/components/sparkline.js +122 -0
- package/dist/components/spinner.d.ts +34 -0
- package/dist/components/spinner.js +34 -0
- package/dist/components/stat.d.ts +135 -0
- package/dist/components/stat.js +130 -0
- package/dist/components/status-picker.d.ts +107 -0
- package/dist/components/status-picker.js +175 -0
- package/dist/components/stepper.d.ts +86 -0
- package/dist/components/stepper.js +103 -0
- package/dist/components/switch.d.ts +34 -0
- package/dist/components/switch.js +70 -0
- package/dist/components/table.d.ts +101 -0
- package/dist/components/table.js +72 -0
- package/dist/components/tabs.d.ts +103 -0
- package/dist/components/tabs.js +173 -0
- package/dist/components/tag-input.d.ts +77 -0
- package/dist/components/tag-input.js +305 -0
- package/dist/components/task-list.d.ts +89 -0
- package/dist/components/task-list.js +238 -0
- package/dist/components/time-picker.d.ts +119 -0
- package/dist/components/time-picker.js +399 -0
- package/dist/components/toast.d.ts +87 -0
- package/dist/components/toast.js +142 -0
- package/dist/components/toggle.d.ts +77 -0
- package/dist/components/toggle.js +109 -0
- package/dist/components/tooltip.d.ts +69 -0
- package/dist/components/tooltip.js +105 -0
- package/dist/components/top-bar.d.ts +87 -0
- package/dist/components/top-bar.js +99 -0
- package/dist/components/tree-select.d.ts +89 -0
- package/dist/components/tree-select.js +243 -0
- package/dist/components/tree-view.d.ts +109 -0
- package/dist/components/tree-view.js +170 -0
- package/dist/components/typography.d.ts +107 -0
- package/dist/components/typography.js +128 -0
- package/dist/components/user-picker.d.ts +89 -0
- package/dist/components/user-picker.js +162 -0
- package/dist/components/version-history.d.ts +191 -0
- package/dist/components/version-history.js +431 -0
- package/dist/data-table/csv.d.ts +27 -0
- package/dist/data-table/csv.js +68 -0
- package/dist/data-table/data-table.d.ts +423 -0
- package/dist/data-table/data-table.js +1259 -0
- package/dist/data-table/filter-bar.d.ts +146 -0
- package/dist/data-table/filter-bar.js +569 -0
- package/dist/data-table/filter-fns.d.ts +65 -0
- package/dist/data-table/filter-fns.js +382 -0
- package/dist/data-table/index.d.ts +8 -0
- package/dist/data-table/index.js +9 -0
- package/dist/data-table/saved-views.d.ts +100 -0
- package/dist/data-table/saved-views.js +251 -0
- package/dist/data-table/types.d.ts +168 -0
- package/dist/data-table/types.js +87 -0
- package/dist/data-table/url-state.d.ts +94 -0
- package/dist/data-table/url-state.js +303 -0
- package/dist/data-table/view-state.d.ts +16 -0
- package/dist/data-table/view-state.js +81 -0
- package/dist/editor/_test-setup.d.ts +1 -0
- package/dist/editor/_test-setup.js +33 -0
- package/dist/editor/block-editor.d.ts +137 -0
- package/dist/editor/block-editor.js +280 -0
- package/dist/editor/commands.d.ts +31 -0
- package/dist/editor/commands.js +150 -0
- package/dist/editor/context.d.ts +108 -0
- package/dist/editor/context.js +30 -0
- package/dist/editor/convert.d.ts +66 -0
- package/dist/editor/convert.js +567 -0
- package/dist/editor/drag-handle.d.ts +10 -0
- package/dist/editor/drag-handle.js +69 -0
- package/dist/editor/extensions.d.ts +34 -0
- package/dist/editor/extensions.js +239 -0
- package/dist/editor/index.d.ts +14 -0
- package/dist/editor/index.js +17 -0
- package/dist/editor/inserter.d.ts +12 -0
- package/dist/editor/inserter.js +88 -0
- package/dist/editor/inspector.d.ts +17 -0
- package/dist/editor/inspector.js +65 -0
- package/dist/editor/items.d.ts +62 -0
- package/dist/editor/items.js +195 -0
- package/dist/editor/labels.d.ts +119 -0
- package/dist/editor/labels.js +130 -0
- package/dist/editor/markdown.d.ts +14 -0
- package/dist/editor/markdown.js +209 -0
- package/dist/editor/menus.d.ts +20 -0
- package/dist/editor/menus.js +236 -0
- package/dist/editor/nodes.d.ts +14 -0
- package/dist/editor/nodes.js +201 -0
- package/dist/editor/outline.d.ts +11 -0
- package/dist/editor/outline.js +52 -0
- package/dist/editor/schema-form.d.ts +64 -0
- package/dist/editor/schema-form.js +290 -0
- package/dist/editor/slash-menu.d.ts +15 -0
- package/dist/editor/slash-menu.js +119 -0
- package/dist/fonts/catalog.d.ts +53 -0
- package/dist/fonts/catalog.js +121 -0
- package/dist/fonts/font-picker.d.ts +70 -0
- package/dist/fonts/font-picker.js +225 -0
- package/dist/fonts/index.d.ts +6 -0
- package/dist/fonts/index.js +7 -0
- package/dist/fonts/loader.d.ts +66 -0
- package/dist/fonts/loader.js +161 -0
- package/dist/fonts/pairing-picker.d.ts +31 -0
- package/dist/fonts/pairing-picker.js +81 -0
- package/dist/fonts/pairings.d.ts +84 -0
- package/dist/fonts/pairings.js +149 -0
- package/dist/fonts/provider.d.ts +34 -0
- package/dist/fonts/provider.js +51 -0
- package/dist/form/index.d.ts +1 -0
- package/dist/form/index.js +1 -0
- package/dist/format/core.d.ts +149 -0
- package/dist/format/core.js +357 -0
- package/dist/format/index.d.ts +4 -0
- package/dist/format/index.js +5 -0
- package/dist/format/use-format.d.ts +1 -0
- package/dist/format/use-format.js +3 -0
- package/dist/index.d.ts +86 -0
- package/dist/index.js +87 -0
- package/dist/lib/cn.d.ts +3 -0
- package/dist/lib/cn.js +16 -0
- package/dist/lib/color.d.ts +64 -0
- package/dist/lib/color.js +177 -0
- package/dist/lib/compose-refs.d.ts +24 -0
- package/dist/lib/compose-refs.js +45 -0
- package/dist/lib/data-islands.d.ts +194 -0
- package/dist/lib/data-islands.js +368 -0
- package/dist/lib/date.d.ts +129 -0
- package/dist/lib/date.js +386 -0
- package/dist/lib/field-context.d.ts +64 -0
- package/dist/lib/field-context.js +62 -0
- package/dist/lib/floating-arrow.d.ts +18 -0
- package/dist/lib/floating-arrow.js +15 -0
- package/dist/lib/islands.d.ts +38 -0
- package/dist/lib/islands.js +40 -0
- package/dist/lib/labels.d.ts +51 -0
- package/dist/lib/labels.js +56 -0
- package/dist/lib/layer.d.ts +36 -0
- package/dist/lib/layer.js +42 -0
- package/dist/lib/locale.d.ts +85 -0
- package/dist/lib/locale.js +105 -0
- package/dist/lib/menu.d.ts +58 -0
- package/dist/lib/menu.js +99 -0
- package/dist/lib/message-format.d.ts +20 -0
- package/dist/lib/message-format.js +116 -0
- package/dist/lib/nav.d.ts +132 -0
- package/dist/lib/nav.js +178 -0
- package/dist/lib/provider.d.ts +100 -0
- package/dist/lib/provider.js +105 -0
- package/dist/lib/public.d.ts +22 -0
- package/dist/lib/public.js +33 -0
- package/dist/lib/sr-name.d.ts +18 -0
- package/dist/lib/sr-name.js +17 -0
- package/dist/lib/text.d.ts +100 -0
- package/dist/lib/text.js +233 -0
- package/dist/lib/theme-scope.d.ts +58 -0
- package/dist/lib/theme-scope.js +59 -0
- package/dist/lib/use-async-list.d.ts +60 -0
- package/dist/lib/use-async-list.js +119 -0
- package/dist/lib/use-container-width.d.ts +19 -0
- package/dist/lib/use-container-width.js +39 -0
- package/dist/lib/use-controllable-state.d.ts +33 -0
- package/dist/lib/use-controllable-state.js +56 -0
- package/dist/lib/use-edge-fade.d.ts +13 -0
- package/dist/lib/use-edge-fade.js +43 -0
- package/dist/lib/use-formatted-input.d.ts +69 -0
- package/dist/lib/use-formatted-input.js +152 -0
- package/dist/lib/use-hotkeys.d.ts +80 -0
- package/dist/lib/use-hotkeys.js +221 -0
- package/dist/lib/use-hover-intent.d.ts +44 -0
- package/dist/lib/use-hover-intent.js +119 -0
- package/dist/lib/use-media-query.d.ts +21 -0
- package/dist/lib/use-media-query.js +28 -0
- package/dist/lib/use-reduced-motion.d.ts +8 -0
- package/dist/lib/use-reduced-motion.js +13 -0
- package/dist/lib/use-tree.d.ts +153 -0
- package/dist/lib/use-tree.js +534 -0
- package/dist/lib/value-format.d.ts +25 -0
- package/dist/lib/value-format.js +56 -0
- package/dist/lib/variants.d.ts +131 -0
- package/dist/lib/variants.js +109 -0
- package/dist/locale-data/core/date.d.ts +24 -0
- package/dist/locale-data/core/date.js +68 -0
- package/dist/locale-data/core/decimal.d.ts +19 -0
- package/dist/locale-data/core/decimal.js +79 -0
- package/dist/locale-data/core/holidays.d.ts +30 -0
- package/dist/locale-data/core/holidays.js +79 -0
- package/dist/locale-data/core/iban.d.ts +29 -0
- package/dist/locale-data/core/iban.js +74 -0
- package/dist/locale-data/core/index.d.ts +7 -0
- package/dist/locale-data/core/index.js +6 -0
- package/dist/locale-data/core/types.d.ts +173 -0
- package/dist/locale-data/core/types.js +6 -0
- package/dist/locale-data/core/week-info.d.ts +23 -0
- package/dist/locale-data/core/week-info.js +85 -0
- package/dist/locale-data/core/working-days.d.ts +27 -0
- package/dist/locale-data/core/working-days.js +133 -0
- package/dist/locale-data/index.d.ts +2 -0
- package/dist/locale-data/index.js +4 -0
- package/dist/locale-data/tr/address-tr.json +1 -0
- package/dist/locale-data/tr/address.d.ts +23 -0
- package/dist/locale-data/tr/address.js +52 -0
- package/dist/locale-data/tr/holidays.d.ts +31 -0
- package/dist/locale-data/tr/holidays.js +81 -0
- package/dist/locale-data/tr/iban.d.ts +21 -0
- package/dist/locale-data/tr/iban.js +45 -0
- package/dist/locale-data/tr/id.d.ts +36 -0
- package/dist/locale-data/tr/id.js +120 -0
- package/dist/locale-data/tr/index.d.ts +12 -0
- package/dist/locale-data/tr/index.js +33 -0
- package/dist/locale-data/tr/kdv.d.ts +91 -0
- package/dist/locale-data/tr/kdv.js +222 -0
- package/dist/locales/en.d.ts +2102 -0
- package/dist/locales/en.js +2088 -0
- package/dist/locales/tr.d.ts +2086 -0
- package/dist/locales/tr.js +2087 -0
- package/dist/media/focal-point.d.ts +42 -0
- package/dist/media/focal-point.js +96 -0
- package/dist/media/gallery-layout.d.ts +19 -0
- package/dist/media/gallery-layout.js +61 -0
- package/dist/media/gallery.d.ts +64 -0
- package/dist/media/gallery.js +138 -0
- package/dist/media/image-cropper.d.ts +86 -0
- package/dist/media/image-cropper.js +170 -0
- package/dist/media/image-field.d.ts +115 -0
- package/dist/media/image-field.js +212 -0
- package/dist/media/index.d.ts +19 -0
- package/dist/media/index.js +23 -0
- package/dist/media/lightbox.d.ts +82 -0
- package/dist/media/lightbox.js +171 -0
- package/dist/media/link-preview.d.ts +97 -0
- package/dist/media/link-preview.js +177 -0
- package/dist/media/media-library.d.ts +244 -0
- package/dist/media/media-library.js +776 -0
- package/dist/media/media-picker.d.ts +96 -0
- package/dist/media/media-picker.js +209 -0
- package/dist/media/media-provider.d.ts +23 -0
- package/dist/media/media-provider.js +44 -0
- package/dist/media/media-utils.d.ts +39 -0
- package/dist/media/media-utils.js +145 -0
- package/dist/media/memory-adapter.d.ts +22 -0
- package/dist/media/memory-adapter.js +162 -0
- package/dist/media/rest-adapter.d.ts +90 -0
- package/dist/media/rest-adapter.js +208 -0
- package/dist/media/serp.d.ts +62 -0
- package/dist/media/serp.js +108 -0
- package/dist/media/test-fixtures.d.ts +3 -0
- package/dist/media/test-fixtures.js +37 -0
- package/dist/media/types.d.ts +183 -0
- package/dist/media/types.js +3 -0
- package/dist/media/use-pan-zoom.d.ts +51 -0
- package/dist/media/use-pan-zoom.js +156 -0
- package/dist/media/use-upload-queue.d.ts +64 -0
- package/dist/media/use-upload-queue.js +115 -0
- package/dist/media/video-player.d.ts +135 -0
- package/dist/media/video-player.js +319 -0
- package/dist/next/index.d.ts +42 -0
- package/dist/next/index.js +36 -0
- package/dist/render/block-renderer.d.ts +56 -0
- package/dist/render/block-renderer.js +137 -0
- package/dist/render/index.d.ts +6 -0
- package/dist/render/index.js +7 -0
- package/dist/render/prepare.d.ts +61 -0
- package/dist/render/prepare.js +119 -0
- package/dist/scheduler/core/duration.d.ts +83 -0
- package/dist/scheduler/core/duration.js +174 -0
- package/dist/scheduler/core/gantt.d.ts +63 -0
- package/dist/scheduler/core/gantt.js +226 -0
- package/dist/scheduler/core/index.d.ts +6 -0
- package/dist/scheduler/core/index.js +7 -0
- package/dist/scheduler/core/layout.d.ts +97 -0
- package/dist/scheduler/core/layout.js +249 -0
- package/dist/scheduler/core/time-scale.d.ts +89 -0
- package/dist/scheduler/core/time-scale.js +173 -0
- package/dist/scheduler/gantt.d.ts +125 -0
- package/dist/scheduler/gantt.js +532 -0
- package/dist/scheduler/index.d.ts +6 -0
- package/dist/scheduler/index.js +7 -0
- package/dist/scheduler/resource-calendar.d.ts +218 -0
- package/dist/scheduler/resource-calendar.js +661 -0
- package/dist/scheduler/scheduler.d.ts +168 -0
- package/dist/scheduler/scheduler.js +768 -0
- package/dist/scheduler/shared.d.ts +63 -0
- package/dist/scheduler/shared.js +145 -0
- package/dist/scheduler/time-tracker.d.ts +138 -0
- package/dist/scheduler/time-tracker.js +403 -0
- package/dist/sortable/core.d.ts +67 -0
- package/dist/sortable/core.js +167 -0
- package/dist/sortable/index.d.ts +8 -0
- package/dist/sortable/index.js +10 -0
- package/dist/sortable/kanban-core.d.ts +70 -0
- package/dist/sortable/kanban-core.js +67 -0
- package/dist/sortable/kanban.d.ts +147 -0
- package/dist/sortable/kanban.js +472 -0
- package/dist/sortable/sortable-list.d.ts +71 -0
- package/dist/sortable/sortable-list.js +76 -0
- package/dist/sortable/sortable-tree.d.ts +101 -0
- package/dist/sortable/sortable-tree.js +450 -0
- package/dist/sortable/sortable.d.ts +188 -0
- package/dist/sortable/sortable.js +485 -0
- package/dist/sortable/use-pointer-drag.d.ts +75 -0
- package/dist/sortable/use-pointer-drag.js +173 -0
- package/dist/sortable/use-time-scale.d.ts +11 -0
- package/dist/sortable/use-time-scale.js +19 -0
- package/dist/styles/base.css +51 -0
- package/dist/styles/blocks.css +949 -0
- package/dist/styles/calendar.css +642 -0
- package/dist/styles/charts.css +264 -0
- package/dist/styles/data.css +474 -0
- package/dist/styles/editors.css +1022 -0
- package/dist/styles/forms.css +406 -0
- package/dist/styles/media.css +515 -0
- package/dist/styles/navigation.css +293 -0
- package/dist/styles/overlays.css +244 -0
- package/dist/styles.css +742 -0
- package/package.json +156 -4
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cva } from "class-variance-authority";
|
|
4
|
+
import { cn } from "../lib/cn.js";
|
|
5
|
+
const SIZES = { xs: 12, sm: 16, md: 20, lg: 28 };
|
|
6
|
+
const STROKE = { xs: 3, sm: 2.75, md: 2.5, lg: 2.25 };
|
|
7
|
+
export const spinnerVariants = cva("ui-spinner inline-block shrink-0 align-middle", {
|
|
8
|
+
variants: {
|
|
9
|
+
tone: {
|
|
10
|
+
/** Inherits the text colour — the default inside buttons. */
|
|
11
|
+
current: "text-current",
|
|
12
|
+
accent: "text-accent-ink",
|
|
13
|
+
muted: "text-fg-muted",
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
defaultVariants: { tone: "current" },
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Indeterminate loading indicator: a thin track with a rotating, breathing arc.
|
|
20
|
+
* Server-compatible. Under `prefers-reduced-motion` it pulses slowly instead of spinning.
|
|
21
|
+
*
|
|
22
|
+
* ```tsx
|
|
23
|
+
* <Spinner label="Loading orders" />
|
|
24
|
+
* <Button loading>Save</Button> // uses a decorative Spinner
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export const Spinner = React.forwardRef(function Spinner({ size = "sm", tone, label, delay, className, style, ...props }, ref) {
|
|
28
|
+
const px = typeof size === "number" ? size : SIZES[size];
|
|
29
|
+
const stroke = typeof size === "number" ? (size <= 14 ? 3 : size >= 26 ? 2.25 : 2.5) : STROKE[size];
|
|
30
|
+
const svg = (_jsxs("svg", { ref: ref, "data-slot": "spinner", viewBox: "0 0 24 24", width: px, height: px, fill: "none", "aria-hidden": true, focusable: "false", className: cn(spinnerVariants({ tone }), delay ? "ui-spinner-delayed" : undefined, className), style: delay ? { ...style, "--spinner-delay": `${delay}ms` } : style, ...props, children: [_jsx("circle", { cx: "12", cy: "12", r: "9.25", stroke: "currentColor", strokeOpacity: 0.18, strokeWidth: stroke }), _jsx("circle", { className: "ui-spinner-arc", cx: "12", cy: "12", r: "9.25", stroke: "currentColor", strokeWidth: stroke, strokeLinecap: "round", transform: "rotate(-90 12 12)" })] }));
|
|
31
|
+
if (!label)
|
|
32
|
+
return svg;
|
|
33
|
+
return (_jsxs("span", { role: "status", "aria-live": "polite", "data-slot": "spinner-status", className: "inline-flex items-center", children: [svg, _jsx("span", { className: "sr-only", children: label })] }));
|
|
34
|
+
});
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type LucideIcon } from "lucide-react";
|
|
3
|
+
import type { statLabels } from "../lib/data-islands.js";
|
|
4
|
+
import type { ValueFormat } from "../lib/value-format.js";
|
|
5
|
+
export type { ValueFormat } from "../lib/value-format.js";
|
|
6
|
+
/** Which direction is good news. Decides the delta colour, never the arrow. */
|
|
7
|
+
export type StatIntent = "higher-is-better" | "lower-is-better" | "neutral";
|
|
8
|
+
export type StatLabels = Partial<typeof statLabels>;
|
|
9
|
+
export interface DeltaProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, "children"> {
|
|
10
|
+
/** The change. `kind="percent"` takes a ratio: `0.124` → "+12.4%". `null` → "—". */
|
|
11
|
+
value: number | null | undefined;
|
|
12
|
+
/** Default `"percent"`. */
|
|
13
|
+
kind?: "percent" | "number" | "currency";
|
|
14
|
+
/** ISO 4217 code for `kind="currency"`. Default: the LocaleProvider currency. */
|
|
15
|
+
currency?: string;
|
|
16
|
+
/** Default `"higher-is-better"`. With `"lower-is-better"` a drop is green (response time, churn). */
|
|
17
|
+
intent?: StatIntent;
|
|
18
|
+
/** `"text"` (default) or a soft `"badge"`. */
|
|
19
|
+
variant?: "text" | "badge";
|
|
20
|
+
/** Max fraction digits. */
|
|
21
|
+
precision?: number;
|
|
22
|
+
/** Full screen-reader sentence. Default "Up 12.4%" / "Down 4.1%" / "No change". */
|
|
23
|
+
srLabel?: string;
|
|
24
|
+
/** Appended to the spoken text, e.g. "vs last month". */
|
|
25
|
+
comparison?: string;
|
|
26
|
+
labels?: StatLabels;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A signed change with an arrow and a semantic colour. Arrow + sign carry the meaning, colour
|
|
30
|
+
* only reinforces it. Server-component compatible; also used in table cells and list rows.
|
|
31
|
+
*
|
|
32
|
+
* ```tsx
|
|
33
|
+
* <Delta value={0.124} /> // ↗ +12.4% (green)
|
|
34
|
+
* <Delta value={-0.18} intent="lower-is-better" /> // ↘ −18% (green: faster replies)
|
|
35
|
+
* <Delta value={1250} kind="currency" variant="badge" />
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare const Delta: React.ForwardRefExoticComponent<DeltaProps & React.RefAttributes<HTMLSpanElement>>;
|
|
39
|
+
export interface StatProps extends Omit<React.HTMLAttributes<HTMLElement>, "title"> {
|
|
40
|
+
/** What is measured ("Visitors"). */
|
|
41
|
+
label?: React.ReactNode;
|
|
42
|
+
/** Numbers are formatted with `format`; strings are shown as they are ("2:47"); `null` → "—" + "No data". */
|
|
43
|
+
value?: number | string | null;
|
|
44
|
+
/** How a numeric value is formatted. Default `"number"`. */
|
|
45
|
+
format?: ValueFormat;
|
|
46
|
+
/** Change vs the comparison period. See `Delta` (`deltaKind="percent"` takes a ratio). */
|
|
47
|
+
delta?: number | null;
|
|
48
|
+
deltaKind?: DeltaProps["kind"];
|
|
49
|
+
/** Delta as text or soft badge. Default `"text"`. */
|
|
50
|
+
deltaVariant?: DeltaProps["variant"];
|
|
51
|
+
/** Which direction is good. Default `"higher-is-better"`. */
|
|
52
|
+
intent?: StatIntent;
|
|
53
|
+
/** "vs previous 30 days" — shown in the footer and appended to the spoken delta (when a string). */
|
|
54
|
+
comparison?: React.ReactNode;
|
|
55
|
+
/** Mini trend, oldest first. */
|
|
56
|
+
trend?: ReadonlyArray<number | null>;
|
|
57
|
+
/** Default `"line"`. */
|
|
58
|
+
trendVariant?: "line" | "area" | "bars";
|
|
59
|
+
/** Progress-to-goal bar. */
|
|
60
|
+
target?: {
|
|
61
|
+
value: number;
|
|
62
|
+
label?: React.ReactNode;
|
|
63
|
+
};
|
|
64
|
+
/** Small icon next to the label (a Lucide icon component). */
|
|
65
|
+
icon?: LucideIcon;
|
|
66
|
+
/** Makes the whole stat a link (drill-down). */
|
|
67
|
+
href?: string;
|
|
68
|
+
/** Skeleton sized to label + value; sets `aria-busy`. */
|
|
69
|
+
loading?: boolean;
|
|
70
|
+
/** Error message in place of the value. */
|
|
71
|
+
error?: React.ReactNode;
|
|
72
|
+
/** Slot next to the error (e.g. a Retry button — only when the Stat is not a link). */
|
|
73
|
+
errorAction?: React.ReactNode;
|
|
74
|
+
/** `card` (own surface), `plain` (a cell inside StatGroup/Card) or `inline` (no padding). Default `"card"`. */
|
|
75
|
+
variant?: "card" | "plain" | "inline";
|
|
76
|
+
/** Value size 20 / 28 / 40px. Default `"md"`. */
|
|
77
|
+
size?: "sm" | "md" | "lg";
|
|
78
|
+
labels?: StatLabels;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* One metric: label, value, change and a mini trend. Renders a `<dl>` (label = `dt`, value and
|
|
82
|
+
* change = `dd`); the sparkline is decorative and summarised for screen readers. Server-component
|
|
83
|
+
* compatible — no chart library, no count-up animation.
|
|
84
|
+
*
|
|
85
|
+
* ```tsx
|
|
86
|
+
* <Stat label="Visitors" value={28412} delta={0.124} trend={[4, 6, 5, 8, 7, 9, 12, 11, 14]} comparison="vs previous 30 days" />
|
|
87
|
+
* <Stat label="Avg. response" value={4320} format="duration" delta={-0.18} intent="lower-is-better" />
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* Compose for custom layouts: `<Stat><StatLabel/><StatValue/><StatDelta/><StatTrend/><StatFooter/></Stat>`.
|
|
91
|
+
*/
|
|
92
|
+
export declare const Stat: React.ForwardRefExoticComponent<StatProps & React.RefAttributes<HTMLElement>>;
|
|
93
|
+
/** The metric name (`<dt>`). */
|
|
94
|
+
export declare function StatLabel({ className, ...props }: React.HTMLAttributes<HTMLElement>): React.JSX.Element;
|
|
95
|
+
export interface StatValueProps extends Omit<React.HTMLAttributes<HTMLElement>, "children"> {
|
|
96
|
+
value?: number | string | null;
|
|
97
|
+
format?: ValueFormat;
|
|
98
|
+
/** Id of a text that describes the value (the trend summary). */
|
|
99
|
+
describedBy?: string;
|
|
100
|
+
labels?: StatLabels;
|
|
101
|
+
children?: React.ReactNode;
|
|
102
|
+
}
|
|
103
|
+
/** The big number (`<dd>`): mono, tabular, sized by the Stat `size`. */
|
|
104
|
+
export declare function StatValue({ value, format, describedBy, labels, className, children, ...props }: StatValueProps): React.JSX.Element;
|
|
105
|
+
/** Wrapper (`<dd>`) for a Delta at the top end. */
|
|
106
|
+
export declare function StatDelta({ className, ...props }: React.HTMLAttributes<HTMLElement>): React.JSX.Element;
|
|
107
|
+
/** Wrapper (`<dd>`) for the mini trend at the bottom end. */
|
|
108
|
+
export declare function StatTrend({ className, ...props }: React.HTMLAttributes<HTMLElement>): React.JSX.Element;
|
|
109
|
+
/** Secondary line under the value ("vs previous 30 days"). */
|
|
110
|
+
export declare function StatFooter({ className, ...props }: React.HTMLAttributes<HTMLElement>): React.JSX.Element;
|
|
111
|
+
export interface StatTargetProps {
|
|
112
|
+
value: number;
|
|
113
|
+
target: number;
|
|
114
|
+
/** Caption override; default "Goal $46,800" + percent. */
|
|
115
|
+
label?: React.ReactNode;
|
|
116
|
+
format?: ValueFormat;
|
|
117
|
+
labels?: StatLabels;
|
|
118
|
+
className?: string;
|
|
119
|
+
}
|
|
120
|
+
/** Progress-to-goal bar under the value. Turns success-coloured once the goal is reached. */
|
|
121
|
+
export declare function StatTarget({ value, target, label, format, labels, className }: StatTargetProps): React.JSX.Element;
|
|
122
|
+
export interface StatGroupProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
123
|
+
/** Max columns; fewer on narrow containers (container queries). Default 4. */
|
|
124
|
+
columns?: 2 | 3 | 4;
|
|
125
|
+
/**
|
|
126
|
+
* `"cards"` (default): separate Stat cards with a gap.
|
|
127
|
+
* `"plain"`: one surface with hairline dividers — put `variant="plain"` Stats inside.
|
|
128
|
+
*/
|
|
129
|
+
variant?: "cards" | "plain";
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* A responsive row of Stats. Columns follow the container width, not the viewport, so the same
|
|
133
|
+
* row works in a page, a sheet or a dashboard widget.
|
|
134
|
+
*/
|
|
135
|
+
export declare const StatGroup: React.ForwardRefExoticComponent<StatGroupProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { ArrowDownRight, ArrowUpRight, Minus } from "lucide-react";
|
|
4
|
+
import { cva } from "class-variance-authority";
|
|
5
|
+
import { cn } from "../lib/cn.js";
|
|
6
|
+
import { DataLabel, DeltaText, StatGoalText, ValueText } from "../lib/data-islands.js";
|
|
7
|
+
import { cardVariants } from "./card.js";
|
|
8
|
+
import { Skeleton } from "./skeleton.js";
|
|
9
|
+
import { Sparkline, sparklineDirection } from "./sparkline.js";
|
|
10
|
+
/* ------------------------------------------------------------------ */
|
|
11
|
+
/* Delta */
|
|
12
|
+
/* ------------------------------------------------------------------ */
|
|
13
|
+
const deltaVariants = cva("inline-flex shrink-0 items-center gap-0.5 whitespace-nowrap font-medium leading-none [&_svg]:shrink-0", {
|
|
14
|
+
variants: {
|
|
15
|
+
variant: {
|
|
16
|
+
text: "text-xs [&_svg]:size-3.5",
|
|
17
|
+
badge: "h-5 rounded-full px-1.5 text-[11px] [--tone-mix:16%] glass:[--tone-mix:20%] tone-soft [&_svg]:size-3",
|
|
18
|
+
},
|
|
19
|
+
tone: {
|
|
20
|
+
positive: "tone-success text-success",
|
|
21
|
+
negative: "tone-danger text-danger",
|
|
22
|
+
neutral: "tone-neutral text-fg-muted",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
defaultVariants: { variant: "text", tone: "neutral" },
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* A signed change with an arrow and a semantic colour. Arrow + sign carry the meaning, colour
|
|
29
|
+
* only reinforces it. Server-component compatible; also used in table cells and list rows.
|
|
30
|
+
*
|
|
31
|
+
* ```tsx
|
|
32
|
+
* <Delta value={0.124} /> // ↗ +12.4% (green)
|
|
33
|
+
* <Delta value={-0.18} intent="lower-is-better" /> // ↘ −18% (green: faster replies)
|
|
34
|
+
* <Delta value={1250} kind="currency" variant="badge" />
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export const Delta = React.forwardRef(function Delta({ value, kind = "percent", currency, intent = "higher-is-better", variant, precision, srLabel, comparison, labels, className, ...props }, ref) {
|
|
38
|
+
const has = typeof value === "number" && Number.isFinite(value);
|
|
39
|
+
const dir = has ? Math.sign(value) : 0;
|
|
40
|
+
const good = intent === "neutral" || dir === 0 ? 0 : intent === "higher-is-better" ? dir : -dir;
|
|
41
|
+
const tone = good > 0 ? "positive" : good < 0 ? "negative" : "neutral";
|
|
42
|
+
const Icon = dir > 0 ? ArrowUpRight : dir < 0 ? ArrowDownRight : Minus;
|
|
43
|
+
return (_jsx("span", { ref: ref, "data-slot": "delta", "data-trend": dir > 0 ? "up" : dir < 0 ? "down" : "flat", "data-tone": tone, className: cn(deltaVariants({ variant, tone }), className), ...props, children: has ? (_jsxs(_Fragment, { children: [_jsx(Icon, { "aria-hidden": true, strokeWidth: 2.25 }), _jsx(DeltaText, { value: value, kind: kind, currency: currency, precision: precision, srLabel: srLabel, srSuffix: comparison, labels: labels })] })) : (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": true, children: "\u2014" }), _jsx("span", { className: "sr-only", children: _jsx(DataLabel, { ns: "stat", id: "noData", override: labels }) })] })) }));
|
|
44
|
+
});
|
|
45
|
+
/* ------------------------------------------------------------------ */
|
|
46
|
+
/* Stat parts */
|
|
47
|
+
/* ------------------------------------------------------------------ */
|
|
48
|
+
const statVariants = cva("group/stat relative grid min-w-0 grid-cols-[minmax(0,1fr)_auto] content-start items-start gap-x-3 [grid-template-areas:'label_delta'_'value_trend'_'target_target'_'foot_foot']" +
|
|
49
|
+
// without a sparkline the value may use the full width (a wide delta must not squeeze "$3,815,400.00")
|
|
50
|
+
" [&:not(:has([data-slot=stat-trend]))_[data-slot=stat-value]]:[grid-column:1/-1]", {
|
|
51
|
+
variants: {
|
|
52
|
+
variant: {
|
|
53
|
+
card: "p-(--stat-p)",
|
|
54
|
+
plain: "p-(--stat-p)",
|
|
55
|
+
inline: "gap-y-0.5",
|
|
56
|
+
},
|
|
57
|
+
size: {
|
|
58
|
+
sm: "[--stat-p:calc(var(--gap)*0.8)] [--stat-value:1.25rem]",
|
|
59
|
+
md: "[--stat-p:var(--gap)] [--stat-value:1.75rem]",
|
|
60
|
+
lg: "[--stat-p:calc(var(--gap)*1.2)] [--stat-value:2.5rem]",
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
defaultVariants: { variant: "card", size: "md" },
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* One metric: label, value, change and a mini trend. Renders a `<dl>` (label = `dt`, value and
|
|
67
|
+
* change = `dd`); the sparkline is decorative and summarised for screen readers. Server-component
|
|
68
|
+
* compatible — no chart library, no count-up animation.
|
|
69
|
+
*
|
|
70
|
+
* ```tsx
|
|
71
|
+
* <Stat label="Visitors" value={28412} delta={0.124} trend={[4, 6, 5, 8, 7, 9, 12, 11, 14]} comparison="vs previous 30 days" />
|
|
72
|
+
* <Stat label="Avg. response" value={4320} format="duration" delta={-0.18} intent="lower-is-better" />
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* Compose for custom layouts: `<Stat><StatLabel/><StatValue/><StatDelta/><StatTrend/><StatFooter/></Stat>`.
|
|
76
|
+
*/
|
|
77
|
+
export const Stat = React.forwardRef(function Stat({ label, value, format, delta, deltaKind = "percent", deltaVariant, intent = "higher-is-better", comparison, trend, trendVariant = "line", target, icon: Icon, href, loading, error, errorAction, variant = "card", size = "md", labels, className, children, ...props }, ref) {
|
|
78
|
+
const trendId = React.useId();
|
|
79
|
+
const dir = trend ? sparklineDirection(trend) : 0;
|
|
80
|
+
const good = intent === "neutral" || dir === 0 ? 0 : intent === "higher-is-better" ? dir : -dir;
|
|
81
|
+
const count = trend ? trend.filter((v) => typeof v === "number").length : 0;
|
|
82
|
+
let content = children;
|
|
83
|
+
if (children === undefined) {
|
|
84
|
+
content = loading ? (_jsxs(_Fragment, { children: [_jsxs("dt", { className: "[grid-area:label]", children: [_jsx(Skeleton, { shape: "text", className: "h-3 w-24" }), _jsx("span", { className: "sr-only", children: label })] }), _jsxs("dd", { className: "mt-3 [grid-area:value]", children: [_jsx(Skeleton, { className: "h-(--stat-value) w-28" }), _jsx("span", { className: "sr-only", children: _jsx(DataLabel, { ns: "stat", id: "noData", override: labels }) })] })] })) : (_jsxs(_Fragment, { children: [_jsxs(StatLabel, { children: [Icon ? _jsx(Icon, { "aria-hidden": true, className: "size-3.5 shrink-0 text-fg-subtle" }) : null, label] }), error ? (_jsxs("dd", { "data-slot": "stat-error", className: "mt-3 flex flex-wrap items-center gap-2 text-[13px] text-danger [grid-column:1/-1] [grid-row:2]", children: [_jsx("span", { children: error }), errorAction] })) : (_jsx(StatValue, { value: value, format: format, labels: labels, describedBy: trend && count > 1 ? trendId : undefined })), !error && delta !== undefined ? (_jsx(StatDelta, { children: _jsx(Delta, { value: delta, kind: deltaKind, intent: intent, variant: deltaVariant, labels: labels, comparison: typeof comparison === "string" ? comparison : undefined }) })) : null, !error && trend && count > 0 ? (_jsxs(StatTrend, { children: [_jsx(Sparkline, { values: trend, variant: trendVariant, className: good > 0 || (intent === "neutral" && dir !== 0) ? "text-accent-ink" : "text-fg-subtle", showLast: trendVariant === "bars" }), _jsx("span", { id: trendId, className: "sr-only", children: _jsx(DataLabel, { ns: "stat", id: dir > 0 ? "trendUp" : dir < 0 ? "trendDown" : "trendFlat", override: labels, vars: { count } }) })] })) : null, !error && target && typeof value === "number" ? _jsx(StatTarget, { value: value, target: target.value, label: target.label, format: format, labels: labels }) : null, comparison && !error ? _jsx(StatFooter, { children: comparison }) : null] }));
|
|
85
|
+
}
|
|
86
|
+
const classes = cn(statVariants({ variant, size }), variant === "card" && !href && "surface rounded-ui-lg", className);
|
|
87
|
+
if (href) {
|
|
88
|
+
return (_jsx("a", { ref: ref, href: href, "data-slot": "stat-link", className: cn("block min-w-0 rounded-ui-lg", variant === "card" ? cardVariants({ variant: "surface", interactive: true }) : "transition-colors hover:bg-hover focus-ring"), children: _jsx("dl", { "data-slot": "stat", "data-variant": variant, "aria-busy": loading || undefined, className: classes, ...props, children: content }) }));
|
|
89
|
+
}
|
|
90
|
+
return (_jsx("dl", { ref: ref, "data-slot": "stat", "data-variant": variant, "aria-busy": loading || undefined, className: classes, ...props, children: content }));
|
|
91
|
+
});
|
|
92
|
+
/** The metric name (`<dt>`). */
|
|
93
|
+
export function StatLabel({ className, ...props }) {
|
|
94
|
+
return _jsx("dt", { "data-slot": "stat-label", className: cn("flex min-w-0 items-center gap-1.5 text-[13px] leading-5 text-fg-muted [grid-area:label]", className), ...props });
|
|
95
|
+
}
|
|
96
|
+
/** The big number (`<dd>`): mono, tabular, sized by the Stat `size`. */
|
|
97
|
+
export function StatValue({ value, format, describedBy, labels, className, children, ...props }) {
|
|
98
|
+
const empty = children === undefined && (value === null || value === undefined || value === "");
|
|
99
|
+
return (_jsx("dd", { "data-slot": "stat-value", "aria-describedby": describedBy, className: cn("mt-3 min-w-0 self-end truncate font-mono text-(length:--stat-value) leading-none font-medium tracking-[-0.03em] text-fg tabular [grid-area:value]", empty && "text-fg-subtle", className), ...props, children: children ?? (empty ? (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": true, children: "\u2014" }), _jsx("span", { className: "sr-only", children: _jsx(DataLabel, { ns: "stat", id: "noData", override: labels }) })] })) : typeof value === "number" || (format && typeof value === "string" && /^-?\d+(\.\d+)?$/.test(value)) ? (_jsx(ValueText, { value: value, format: format })) : (value)) }));
|
|
100
|
+
}
|
|
101
|
+
/** Wrapper (`<dd>`) for a Delta at the top end. */
|
|
102
|
+
export function StatDelta({ className, ...props }) {
|
|
103
|
+
return _jsx("dd", { "data-slot": "stat-delta", className: cn("flex justify-end leading-5 [grid-area:delta]", className), ...props });
|
|
104
|
+
}
|
|
105
|
+
/** Wrapper (`<dd>`) for the mini trend at the bottom end. */
|
|
106
|
+
export function StatTrend({ className, ...props }) {
|
|
107
|
+
return _jsx("dd", { "data-slot": "stat-trend", className: cn("mt-3 flex items-end justify-end self-end [grid-area:trend]", className), ...props });
|
|
108
|
+
}
|
|
109
|
+
/** Secondary line under the value ("vs previous 30 days"). */
|
|
110
|
+
export function StatFooter({ className, ...props }) {
|
|
111
|
+
return _jsx("dd", { "data-slot": "stat-footer", className: cn("mt-3 text-xs text-fg-subtle [grid-area:foot]", className), ...props });
|
|
112
|
+
}
|
|
113
|
+
/** Progress-to-goal bar under the value. Turns success-coloured once the goal is reached. */
|
|
114
|
+
export function StatTarget({ value, target, label, format, labels, className }) {
|
|
115
|
+
const ratio = target > 0 ? Math.max(0, value / target) : 0;
|
|
116
|
+
const reached = ratio >= 1;
|
|
117
|
+
return (_jsxs("dd", { "data-slot": "stat-target", "data-reached": reached ? "" : undefined, className: cn("mt-4 [grid-area:target]", className), children: [_jsx("div", { "aria-hidden": true, className: "h-1.5 overflow-hidden rounded-full bg-track", children: _jsx("div", { className: cn("h-full rounded-full transition-[width] duration-500 motion-reduce:transition-none", reached ? "bg-success" : "bg-accent"), style: { width: `${Math.min(100, ratio * 100)}%` } }) }), _jsx("div", { className: "mt-2 flex justify-between gap-3 text-xs text-fg-subtle", children: label ? (_jsxs(_Fragment, { children: [_jsx("span", { children: label }), _jsxs("span", { className: "tabular", children: [Math.round(ratio * 100), "%"] })] })) : (_jsx(StatGoalText, { value: value, target: target, format: format, labels: labels })) })] }));
|
|
118
|
+
}
|
|
119
|
+
const columnClasses = {
|
|
120
|
+
2: "@md:grid-cols-2",
|
|
121
|
+
3: "@md:grid-cols-2 @3xl:grid-cols-3",
|
|
122
|
+
4: "@md:grid-cols-2 @4xl:grid-cols-4",
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* A responsive row of Stats. Columns follow the container width, not the viewport, so the same
|
|
126
|
+
* row works in a page, a sheet or a dashboard widget.
|
|
127
|
+
*/
|
|
128
|
+
export const StatGroup = React.forwardRef(function StatGroup({ columns = 4, variant = "cards", className, children, ...props }, ref) {
|
|
129
|
+
return (_jsx("div", { ref: ref, "data-slot": "stat-group", className: cn("@container", className), ...props, children: _jsx("div", { className: cn("grid grid-cols-1", columnClasses[columns], variant === "cards" ? "gap-(--gap)" : "surface overflow-hidden rounded-ui-lg [&>*]:shadow-[-1px_-1px_0_0_var(--line)]"), children: children }) }));
|
|
130
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type StatusCategory = "todo" | "active" | "done" | "cancelled";
|
|
3
|
+
export type StatusTone = "neutral" | "accent" | "success" | "warning" | "danger" | "info";
|
|
4
|
+
/** One status of a workflow. Labels are your data (localise them in the app). */
|
|
5
|
+
export interface StatusDef {
|
|
6
|
+
value: string;
|
|
7
|
+
label: string;
|
|
8
|
+
/** Drives the default icon, tone and grouping. */
|
|
9
|
+
category: StatusCategory;
|
|
10
|
+
/** Semantic colour. Default from the category (todo neutral, active info, done success, cancelled neutral). */
|
|
11
|
+
tone?: StatusTone;
|
|
12
|
+
/** Any CSS colour (user-defined pipeline stages). Overrides `tone`. */
|
|
13
|
+
color?: string;
|
|
14
|
+
/** Replace the category icon. */
|
|
15
|
+
icon?: React.ReactNode;
|
|
16
|
+
description?: string;
|
|
17
|
+
}
|
|
18
|
+
/** What `confirm` returns to ask before a transition. */
|
|
19
|
+
export interface StatusConfirm {
|
|
20
|
+
title: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
/** Ask for a note (a rejection reason). Passed to `onValueChange` as `meta.note`. */
|
|
23
|
+
requireNote?: boolean;
|
|
24
|
+
/** Note field label. Default "Note". */
|
|
25
|
+
noteLabel?: string;
|
|
26
|
+
confirmLabel?: string;
|
|
27
|
+
/** `"danger"` for destructive transitions (reject, cancel). */
|
|
28
|
+
tone?: "default" | "danger";
|
|
29
|
+
}
|
|
30
|
+
declare const statusPickerLabels: {
|
|
31
|
+
change: string;
|
|
32
|
+
status: string;
|
|
33
|
+
notAllowed: string;
|
|
34
|
+
note: string;
|
|
35
|
+
notePlaceholder: string;
|
|
36
|
+
saving: string;
|
|
37
|
+
saved: string;
|
|
38
|
+
failed: string;
|
|
39
|
+
placeholder: string;
|
|
40
|
+
todo: string;
|
|
41
|
+
active: string;
|
|
42
|
+
done: string;
|
|
43
|
+
cancelled: string;
|
|
44
|
+
confirm: string;
|
|
45
|
+
};
|
|
46
|
+
export type StatusPickerLabels = typeof statusPickerLabels;
|
|
47
|
+
export interface StatusPickerProps {
|
|
48
|
+
statuses: StatusDef[];
|
|
49
|
+
value?: string | null;
|
|
50
|
+
defaultValue?: string | null;
|
|
51
|
+
/** Return a promise for an optimistic save: the badge switches at once, shows a spinner and reverts if it rejects. */
|
|
52
|
+
onValueChange?: (value: string, previous: string | null, meta: {
|
|
53
|
+
note?: string;
|
|
54
|
+
}) => void | Promise<unknown>;
|
|
55
|
+
/** Allowed next statuses per status. Others stay visible but disabled with the reason. */
|
|
56
|
+
transitions?: Record<string, string[]>;
|
|
57
|
+
/** Ask before moving to `next` (return `false` to skip). */
|
|
58
|
+
confirm?: (next: StatusDef, current: StatusDef | null) => false | StatusConfirm;
|
|
59
|
+
/** Called after an async save failed and the value reverted (show a toast). */
|
|
60
|
+
onError?: (error: unknown, attempted: StatusDef) => void;
|
|
61
|
+
/** `"badge"` (inline in tables, record headers) or `"field"` (forms). Default `"badge"`. */
|
|
62
|
+
trigger?: "badge" | "field";
|
|
63
|
+
/** Group options under category headings. Default `true` when there are more than 5 statuses. */
|
|
64
|
+
groupByCategory?: boolean;
|
|
65
|
+
/** Hidden native select for form posts. */
|
|
66
|
+
name?: string;
|
|
67
|
+
size?: "sm" | "md";
|
|
68
|
+
disabled?: boolean;
|
|
69
|
+
/** Shows the badge, can't be changed. */
|
|
70
|
+
readOnly?: boolean;
|
|
71
|
+
/** External busy state (a save you run yourself). */
|
|
72
|
+
loading?: boolean;
|
|
73
|
+
/** What is being set, for the accessible name ("Stage: Proposal. Change"). Default "Status". */
|
|
74
|
+
fieldLabel?: string;
|
|
75
|
+
labels?: Partial<StatusPickerLabels>;
|
|
76
|
+
id?: string;
|
|
77
|
+
className?: string;
|
|
78
|
+
"aria-label"?: string;
|
|
79
|
+
"aria-labelledby"?: string;
|
|
80
|
+
"aria-describedby"?: string;
|
|
81
|
+
"aria-invalid"?: boolean | "true" | "false";
|
|
82
|
+
}
|
|
83
|
+
/** Default category icons — shape, not only colour, carries the meaning. */
|
|
84
|
+
export declare function StatusIcon({ category, className }: {
|
|
85
|
+
category: StatusCategory;
|
|
86
|
+
className?: string;
|
|
87
|
+
}): React.JSX.Element;
|
|
88
|
+
/** A status rendered as a badge (no picker) — table cells, read-only views, activity entries. */
|
|
89
|
+
export declare function StatusBadge({ status, size, className }: {
|
|
90
|
+
status: StatusDef;
|
|
91
|
+
size?: "sm" | "md";
|
|
92
|
+
className?: string;
|
|
93
|
+
}): React.JSX.Element;
|
|
94
|
+
/**
|
|
95
|
+
* Change a record's status inside a workflow: task To do → In progress → Done, deal stages,
|
|
96
|
+
* content Draft → Review → Published, leave Pending → Approved / Rejected. The trigger is the
|
|
97
|
+
* status badge itself; transitions not allowed from the current status stay visible with the
|
|
98
|
+
* reason; a transition can ask for confirmation (and a note); async saves are optimistic and revert.
|
|
99
|
+
*
|
|
100
|
+
* ```tsx
|
|
101
|
+
* <StatusPicker statuses={taskStatuses} value={task.status} onValueChange={(v) => save({ status: v })} />
|
|
102
|
+
* <StatusPicker statuses={leave} transitions={{ pending: ["approved", "rejected"] }}
|
|
103
|
+
* confirm={(s) => s.value === "rejected" && { title: "Reject request?", requireNote: true, tone: "danger" }} />
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export declare const StatusPicker: React.ForwardRefExoticComponent<StatusPickerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
107
|
+
export {};
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Select as SelectPrimitive } from "radix-ui";
|
|
5
|
+
import { Check, ChevronDown } from "lucide-react";
|
|
6
|
+
import { cn } from "../lib/cn.js";
|
|
7
|
+
import { useFieldControl } from "../lib/field-context.js";
|
|
8
|
+
import { useLabels } from "../lib/labels.js";
|
|
9
|
+
import { Layer } from "../lib/layer.js";
|
|
10
|
+
import { usePortalContainer } from "../lib/theme-scope.js";
|
|
11
|
+
import { useControllableState, useLatest } from "../lib/use-controllable-state.js";
|
|
12
|
+
import { controlVariants, itemSlots, itemVariants } from "../lib/variants.js";
|
|
13
|
+
import { badgeVariants } from "./badge.js";
|
|
14
|
+
import { Spinner } from "./spinner.js";
|
|
15
|
+
import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogFooter, AlertDialogHeader, AlertDialogBody } from "./alert-dialog.js";
|
|
16
|
+
import { Textarea } from "./input.js";
|
|
17
|
+
const statusPickerLabels = {
|
|
18
|
+
change: "{label}: {status}. Change",
|
|
19
|
+
status: "Status",
|
|
20
|
+
notAllowed: "Not allowed from {status}",
|
|
21
|
+
note: "Note",
|
|
22
|
+
notePlaceholder: "Add a short reason the requester will see",
|
|
23
|
+
saving: "Saving…",
|
|
24
|
+
saved: "Status changed to {status}",
|
|
25
|
+
failed: "Couldn't change the status. It's back to {status}.",
|
|
26
|
+
placeholder: "Set status",
|
|
27
|
+
todo: "To do",
|
|
28
|
+
active: "In progress",
|
|
29
|
+
done: "Done",
|
|
30
|
+
cancelled: "Cancelled",
|
|
31
|
+
confirm: "Confirm",
|
|
32
|
+
};
|
|
33
|
+
const CATEGORY_TONE = { todo: "neutral", active: "info", done: "success", cancelled: "neutral" };
|
|
34
|
+
const CATEGORY_ORDER = ["todo", "active", "done", "cancelled"];
|
|
35
|
+
/** Default category icons — shape, not only colour, carries the meaning. */
|
|
36
|
+
export function StatusIcon({ category, className }) {
|
|
37
|
+
const cls = cn("size-3.5 shrink-0", className);
|
|
38
|
+
switch (category) {
|
|
39
|
+
case "todo":
|
|
40
|
+
return (_jsx("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, focusable: "false", className: cls, "data-category": "todo", children: _jsx("circle", { cx: "8", cy: "8", r: "5.75", stroke: "currentColor", strokeWidth: "1.6", strokeDasharray: "2.6 2.1" }) }));
|
|
41
|
+
case "active":
|
|
42
|
+
return (_jsxs("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, focusable: "false", className: cls, "data-category": "active", children: [_jsx("circle", { cx: "8", cy: "8", r: "5.75", stroke: "currentColor", strokeWidth: "1.6" }), _jsx("path", { d: "M8 4.25a3.75 3.75 0 0 1 0 7.5z", fill: "currentColor" })] }));
|
|
43
|
+
case "done":
|
|
44
|
+
return (_jsxs("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, focusable: "false", className: cls, "data-category": "done", children: [_jsx("circle", { cx: "8", cy: "8", r: "6.5", fill: "currentColor" }), _jsx("path", { d: "M5.2 8.2 7.1 10l3.7-4", stroke: "var(--surface-solid, #fff)", strokeWidth: "1.7", strokeLinecap: "round", strokeLinejoin: "round" })] }));
|
|
45
|
+
default:
|
|
46
|
+
return (_jsxs("svg", { viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, focusable: "false", className: cls, "data-category": "cancelled", children: [_jsx("circle", { cx: "8", cy: "8", r: "5.75", stroke: "currentColor", strokeWidth: "1.6" }), _jsx("path", { d: "m5.6 10.4 4.8-4.8", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round" })] }));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Badge tone of a status. Passed into the single `badgeVariants` call so the neutral default never overrides it. */
|
|
50
|
+
function toneStyle(s) {
|
|
51
|
+
if (!s)
|
|
52
|
+
return { tone: "outline" };
|
|
53
|
+
if (s.color)
|
|
54
|
+
return { tone: "custom", style: { ["--tone"]: s.color } };
|
|
55
|
+
return { tone: s.tone ?? CATEGORY_TONE[s.category] };
|
|
56
|
+
}
|
|
57
|
+
const TONE_COLOR = {
|
|
58
|
+
neutral: "var(--fg-muted)",
|
|
59
|
+
accent: "var(--accent-ink)",
|
|
60
|
+
success: "var(--success)",
|
|
61
|
+
warning: "var(--warning)",
|
|
62
|
+
danger: "var(--danger)",
|
|
63
|
+
info: "var(--info)",
|
|
64
|
+
};
|
|
65
|
+
/** The ink colour of a status (icon in field triggers and menus). */
|
|
66
|
+
function toneColor(s) {
|
|
67
|
+
return s.color ?? TONE_COLOR[s.tone ?? CATEGORY_TONE[s.category]];
|
|
68
|
+
}
|
|
69
|
+
/** A status rendered as a badge (no picker) — table cells, read-only views, activity entries. */
|
|
70
|
+
export function StatusBadge({ status, size = "md", className }) {
|
|
71
|
+
const tone = toneStyle(status);
|
|
72
|
+
return (_jsxs("span", { "data-slot": "status-badge", "data-category": status.category, className: cn(badgeVariants({ size: size === "sm" ? "sm" : "md", tone: tone.tone }), "gap-1.5", status.category === "cancelled" && "text-fg-muted", className), style: tone.style, children: [status.icon ?? _jsx(StatusIcon, { category: status.category }), status.label] }));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Change a record's status inside a workflow: task To do → In progress → Done, deal stages,
|
|
76
|
+
* content Draft → Review → Published, leave Pending → Approved / Rejected. The trigger is the
|
|
77
|
+
* status badge itself; transitions not allowed from the current status stay visible with the
|
|
78
|
+
* reason; a transition can ask for confirmation (and a note); async saves are optimistic and revert.
|
|
79
|
+
*
|
|
80
|
+
* ```tsx
|
|
81
|
+
* <StatusPicker statuses={taskStatuses} value={task.status} onValueChange={(v) => save({ status: v })} />
|
|
82
|
+
* <StatusPicker statuses={leave} transitions={{ pending: ["approved", "rejected"] }}
|
|
83
|
+
* confirm={(s) => s.value === "rejected" && { title: "Reject request?", requireNote: true, tone: "danger" }} />
|
|
84
|
+
* ```
|
|
85
|
+
*/
|
|
86
|
+
export const StatusPicker = React.forwardRef(function StatusPicker({ statuses, value: valueProp, defaultValue, onValueChange, transitions, confirm, onError, trigger = "badge", groupByCategory, name, size = "md", disabled: disabledProp, readOnly: readOnlyProp, loading, fieldLabel, labels, className, ...rest }, ref) {
|
|
87
|
+
const t = useLabels("statusPicker", statusPickerLabels, labels);
|
|
88
|
+
const control = useFieldControl({
|
|
89
|
+
id: rest.id,
|
|
90
|
+
name,
|
|
91
|
+
disabled: disabledProp,
|
|
92
|
+
readOnly: readOnlyProp,
|
|
93
|
+
"aria-describedby": rest["aria-describedby"],
|
|
94
|
+
"aria-labelledby": rest["aria-labelledby"],
|
|
95
|
+
"aria-invalid": rest["aria-invalid"],
|
|
96
|
+
});
|
|
97
|
+
const container = usePortalContainer();
|
|
98
|
+
const [committed, setCommitted] = useControllableState({ value: valueProp, defaultValue: defaultValue ?? null, name: "StatusPicker" });
|
|
99
|
+
const [optimistic, setOptimistic] = React.useState(null);
|
|
100
|
+
const [saving, setSaving] = React.useState(false);
|
|
101
|
+
const [announce, setAnnounce] = React.useState("");
|
|
102
|
+
const [pendingConfirm, setPendingConfirm] = React.useState(null);
|
|
103
|
+
const [note, setNote] = React.useState("");
|
|
104
|
+
const onChangeRef = useLatest(onValueChange);
|
|
105
|
+
const noteId = React.useId();
|
|
106
|
+
const shown = optimistic ?? committed;
|
|
107
|
+
const byValue = React.useMemo(() => new Map(statuses.map((s) => [s.value, s])), [statuses]);
|
|
108
|
+
const current = shown ? byValue.get(shown) : undefined;
|
|
109
|
+
const committedDef = committed ? byValue.get(committed) : undefined;
|
|
110
|
+
const allowed = committed && transitions ? new Set([committed, ...(transitions[committed] ?? [])]) : null;
|
|
111
|
+
const disabled = Boolean(control.disabled);
|
|
112
|
+
const readOnly = Boolean(control.readOnly);
|
|
113
|
+
const busy = saving || Boolean(loading);
|
|
114
|
+
const grouped = groupByCategory ?? statuses.length > 5;
|
|
115
|
+
const commit = async (next, meta) => {
|
|
116
|
+
const prev = committed;
|
|
117
|
+
const result = onChangeRef.current?.(next.value, prev, meta);
|
|
118
|
+
if (result && typeof result.then === "function") {
|
|
119
|
+
setOptimistic(next.value);
|
|
120
|
+
setSaving(true);
|
|
121
|
+
try {
|
|
122
|
+
await result;
|
|
123
|
+
setCommitted(next.value);
|
|
124
|
+
setAnnounce(t("saved", { status: next.label }));
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
setAnnounce(t("failed", { status: committedDef?.label ?? t("placeholder") }));
|
|
128
|
+
onError?.(err, next);
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
setOptimistic(null);
|
|
132
|
+
setSaving(false);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
setCommitted(next.value);
|
|
137
|
+
setAnnounce(t("saved", { status: next.label }));
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
const handleChange = (v) => {
|
|
141
|
+
const next = byValue.get(v);
|
|
142
|
+
if (!next || v === committed)
|
|
143
|
+
return;
|
|
144
|
+
const config = confirm?.(next, committedDef ?? null);
|
|
145
|
+
if (config) {
|
|
146
|
+
setNote("");
|
|
147
|
+
setPendingConfirm({ next, config });
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
void commit(next, {});
|
|
151
|
+
};
|
|
152
|
+
const label = fieldLabel ?? t("status");
|
|
153
|
+
const accessibleName = rest["aria-label"] ?? (control["aria-labelledby"] ? undefined : t("change", { label, status: current?.label ?? t("placeholder") }));
|
|
154
|
+
const tone = toneStyle(current);
|
|
155
|
+
const triggerClass = trigger === "field"
|
|
156
|
+
? cn(controlVariants({ size: size === "sm" ? "sm" : "md" }), "justify-start text-start", className)
|
|
157
|
+
: cn(badgeVariants({ size: size === "sm" ? "sm" : "md", tone: tone.tone }), "gap-1.5 pe-1.5 outline-none transition-[filter,box-shadow] focus-ring", !readOnly && !disabled && "cursor-pointer hover:brightness-95", current?.category === "cancelled" && "text-fg-muted", disabled && "opacity-50", className);
|
|
158
|
+
const triggerInner = (_jsxs(_Fragment, { children: [busy ? (_jsx(Spinner, { size: "xs", className: trigger === "field" ? "text-fg-muted" : undefined })) : current ? (_jsx("span", { className: "inline-flex", style: trigger === "field" ? { color: toneColor(current) } : undefined, children: current.icon ?? _jsx(StatusIcon, { category: current.category }) })) : null, _jsx("span", { className: cn("truncate", trigger === "field" && "flex-1", !current && "text-fg-subtle"), children: current?.label ?? t("placeholder") }), busy ? _jsx("span", { className: "sr-only", children: t("saving") }) : null, !readOnly ? _jsx(ChevronDown, { "aria-hidden": true, className: cn("shrink-0 opacity-60", trigger === "field" ? "ms-auto size-4" : "size-3") }) : null] }));
|
|
159
|
+
if (readOnly) {
|
|
160
|
+
return current ? (_jsx(StatusBadge, { status: current, size: size, className: className })) : (_jsx("span", { className: cn(badgeVariants({ tone: "outline", size: size === "sm" ? "sm" : "md" }), className), children: t("placeholder") }));
|
|
161
|
+
}
|
|
162
|
+
const groups = grouped
|
|
163
|
+
? CATEGORY_ORDER.map((c) => ({ category: c, items: statuses.filter((s) => s.category === c) })).filter((g) => g.items.length)
|
|
164
|
+
: [{ category: null, items: statuses }];
|
|
165
|
+
const renderItem = (s) => {
|
|
166
|
+
const notAllowed = allowed ? !allowed.has(s.value) : false;
|
|
167
|
+
const reasonId = `${noteId}-${s.value}`;
|
|
168
|
+
return (_jsxs(SelectPrimitive.Item, { value: s.value, disabled: notAllowed, "aria-describedby": notAllowed ? reasonId : undefined, className: cn(itemVariants({ size: "md", inset: true }), "items-start py-2"), children: [_jsx("span", { className: cn(itemSlots.indicator, "top-2.5"), children: _jsx(SelectPrimitive.ItemIndicator, { children: _jsx(Check, { className: "size-3.5", strokeWidth: 2.5 }) }) }), _jsx("span", { "aria-hidden": true, className: "mt-0.5 inline-flex [&_svg]:size-4", style: { color: toneColor(s) }, children: s.icon ?? _jsx(StatusIcon, { category: s.category, className: "size-4" }) }), _jsxs("span", { className: "min-w-0 flex-1", children: [_jsx(SelectPrimitive.ItemText, { children: s.label }), notAllowed ? (_jsx("span", { id: reasonId, className: itemSlots.description, children: t("notAllowed", { status: committedDef?.label ?? "" }) })) : s.description ? (_jsx("span", { className: itemSlots.description, children: s.description })) : null] })] }, s.value));
|
|
169
|
+
};
|
|
170
|
+
return (_jsxs(_Fragment, { children: [_jsxs(SelectPrimitive.Root, { value: shown ?? "", onValueChange: handleChange, disabled: disabled || busy, name: control.name, children: [_jsx(SelectPrimitive.Trigger, { ref: ref, id: control.id, "data-slot": "status-picker", "data-trigger": trigger, "data-category": current?.category, "aria-label": accessibleName, "aria-labelledby": control["aria-labelledby"], "aria-describedby": control["aria-describedby"], "aria-invalid": control["aria-invalid"], "aria-busy": busy || undefined, className: triggerClass, style: trigger === "badge" ? tone.style : undefined, children: triggerInner }), _jsx(SelectPrimitive.Portal, { container: container, children: _jsx(Layer, { asChild: true, children: _jsx(SelectPrimitive.Content, { position: "popper", sideOffset: 6, collisionPadding: 12, align: "start", "data-slot": "status-picker-content", className: "surface-popover ui-pop z-(--z-popover) max-h-(--radix-select-content-available-height) min-w-56 overflow-hidden rounded-ui-lg", children: _jsx(SelectPrimitive.Viewport, { className: "p-1", children: groups.map((g, i) => g.category ? (_jsxs(SelectPrimitive.Group, { children: [i > 0 ? _jsx(SelectPrimitive.Separator, { className: itemSlots.separator }) : null, _jsx(SelectPrimitive.Label, { className: itemSlots.groupLabel, children: t(g.category) }), g.items.map(renderItem)] }, g.category)) : (_jsx(React.Fragment, { children: g.items.map(renderItem) }, "all"))) }) }) }) })] }), _jsx("span", { role: "status", "aria-live": "polite", className: "sr-only", children: announce }), _jsx(AlertDialog, { open: pendingConfirm !== null, onOpenChange: (o) => !o && setPendingConfirm(null), children: pendingConfirm ? (_jsxs(AlertDialogContent, { tone: pendingConfirm.config.tone ?? "default", children: [_jsx(AlertDialogHeader, { title: pendingConfirm.config.title, description: pendingConfirm.config.description }), pendingConfirm.config.requireNote ? (_jsxs(AlertDialogBody, { className: "grid gap-1.5", children: [_jsx("label", { htmlFor: `${noteId}-note`, className: "text-[13px] font-medium text-fg", children: pendingConfirm.config.noteLabel ?? t("note") }), _jsx(Textarea, { id: `${noteId}-note`, rows: 3, value: note, onChange: (e) => setNote(e.target.value), placeholder: t("notePlaceholder"), required: true, "aria-required": true })] })) : null, _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, {}), _jsx(AlertDialogAction, { disabled: Boolean(pendingConfirm.config.requireNote) && note.trim() === "", onClick: () => {
|
|
171
|
+
const p = pendingConfirm;
|
|
172
|
+
setPendingConfirm(null);
|
|
173
|
+
void commit(p.next, { note: p.config.requireNote ? note.trim() : undefined });
|
|
174
|
+
}, children: pendingConfirm.config.confirmLabel ?? t("confirm") })] })] })) : null })] }));
|
|
175
|
+
});
|