@vamos-ui/react 0.0.0-stage → 0.3.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 +101 -0
- package/dist/blocks/site/_kit-1.js +137 -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 +113 -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 +52 -0
- package/dist/blocks/site/feature-grid.d.ts +46 -0
- package/dist/blocks/site/feature-grid.js +50 -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 +48 -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 +73 -0
- package/dist/blocks/site/logo-strip.d.ts +44 -0
- package/dist/blocks/site/logo-strip.js +27 -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 +56 -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 +83 -0
- package/dist/blocks/site/process.d.ts +36 -0
- package/dist/blocks/site/process.js +42 -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 +108 -0
- package/dist/blocks/site/site-shell.js +254 -0
- package/dist/blocks/site/stats-band.d.ts +42 -0
- package/dist/blocks/site/stats-band.js +45 -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 +66 -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 +12 -0
- package/dist/business/index.js +22 -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/business/signer-status.d.ts +53 -0
- package/dist/business/signer-status.js +76 -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 +46 -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/_qr-core.d.ts +26 -0
- package/dist/components/_qr-core.js +376 -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/backup-codes.d.ts +42 -0
- package/dist/components/backup-codes.js +67 -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 +281 -0
- package/dist/components/command.js +498 -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/pin-map.d.ts +58 -0
- package/dist/components/pin-map.js +167 -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/qr-code.d.ts +36 -0
- package/dist/components/qr-code.js +27 -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/sla-timer.d.ts +75 -0
- package/dist/components/sla-timer.js +142 -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/tour.d.ts +60 -0
- package/dist/components/tour.js +139 -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 +91 -0
- package/dist/index.js +92 -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 +23 -0
- package/dist/lib/public.js +34 -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 +140 -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/motion/core.d.ts +32 -0
- package/dist/motion/core.js +77 -0
- package/dist/motion/count-up.d.ts +29 -0
- package/dist/motion/count-up.js +92 -0
- package/dist/motion/index.d.ts +11 -0
- package/dist/motion/index.js +13 -0
- package/dist/motion/motion-scope.d.ts +17 -0
- package/dist/motion/motion-scope.js +16 -0
- package/dist/motion/page-transition.d.ts +33 -0
- package/dist/motion/page-transition.js +61 -0
- package/dist/motion/parallax.d.ts +37 -0
- package/dist/motion/parallax.js +90 -0
- package/dist/motion/pointer.d.ts +38 -0
- package/dist/motion/pointer.js +117 -0
- package/dist/motion/reveal.d.ts +72 -0
- package/dist/motion/reveal.js +133 -0
- package/dist/motion/scroll-shrink.d.ts +18 -0
- package/dist/motion/scroll-shrink.js +47 -0
- package/dist/motion/skeleton-swap.d.ts +17 -0
- package/dist/motion/skeleton-swap.js +43 -0
- package/dist/motion/text-reveal.d.ts +30 -0
- package/dist/motion/text-reveal.js +29 -0
- package/dist/motion/ticker.d.ts +35 -0
- package/dist/motion/ticker.js +16 -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 +105 -0
- package/dist/sortable/sortable-tree.js +462 -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/motion.css +389 -0
- package/dist/styles/navigation.css +293 -0
- package/dist/styles/overlays.css +244 -0
- package/dist/styles.css +743 -0
- package/package.json +160 -4
|
@@ -0,0 +1,237 @@
|
|
|
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 { Collapsible } from "radix-ui";
|
|
5
|
+
import { ArrowLeft, Check, ChevronDown, CloudOff, PanelRight, TriangleAlert } from "lucide-react";
|
|
6
|
+
import { cn } from "../lib/cn.js";
|
|
7
|
+
import { useLabels } from "../lib/labels.js";
|
|
8
|
+
import { useLocale } from "../lib/locale.js";
|
|
9
|
+
import { SmartLink } from "../lib/provider.js";
|
|
10
|
+
import { useHotkeys } from "../lib/use-hotkeys.js";
|
|
11
|
+
import { useContainerWidth } from "../lib/use-container-width.js";
|
|
12
|
+
import { useControllableState } from "../lib/use-controllable-state.js";
|
|
13
|
+
import { useComposedRefs } from "../lib/compose-refs.js";
|
|
14
|
+
import { Button } from "./button.js";
|
|
15
|
+
import { ActionMenu } from "./dropdown-menu.js";
|
|
16
|
+
import { Skeleton, SkeletonText } from "./skeleton.js";
|
|
17
|
+
import { Spinner } from "./spinner.js";
|
|
18
|
+
import { Sheet, SheetBody, SheetContent, SheetHeader } from "./sheet.js";
|
|
19
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./tabs.js";
|
|
20
|
+
import { SidePaneHandle } from "./record-detail-layout.js";
|
|
21
|
+
/* ------------------------------------------------------------------ */
|
|
22
|
+
/* Labels & context */
|
|
23
|
+
/* ------------------------------------------------------------------ */
|
|
24
|
+
const editorLabels = {
|
|
25
|
+
panel: "Settings",
|
|
26
|
+
togglePanel: "Settings panel",
|
|
27
|
+
resizePanel: "Resize settings panel",
|
|
28
|
+
focusMode: "Focus mode",
|
|
29
|
+
exitFocusMode: "Exit focus mode",
|
|
30
|
+
moreActions: "More actions",
|
|
31
|
+
dirty: "Unsaved changes",
|
|
32
|
+
saving: "Saving…",
|
|
33
|
+
saved: "Saved {time}",
|
|
34
|
+
savedJustNow: "Saved just now",
|
|
35
|
+
savedPlain: "Saved",
|
|
36
|
+
error: "Couldn't save",
|
|
37
|
+
retry: "Retry",
|
|
38
|
+
offline: "Offline · changes kept locally",
|
|
39
|
+
loading: "Loading editor",
|
|
40
|
+
};
|
|
41
|
+
/** Below this container width (44rem) the side panel becomes a sheet. Matches navigation.css. */
|
|
42
|
+
const NARROW = 704;
|
|
43
|
+
const EditorLayoutContext = React.createContext(null);
|
|
44
|
+
function useEditorLayout() {
|
|
45
|
+
return React.useContext(EditorLayoutContext);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The "edit one thing" page: a sticky bar with back link, title, save status and publish
|
|
49
|
+
* actions; a wide content canvas; and a side panel of collapsible settings sections (status,
|
|
50
|
+
* SEO, taxonomy…). Below 44rem (704px) of its own width the panel opens as a non-modal sheet.
|
|
51
|
+
*
|
|
52
|
+
* ```tsx
|
|
53
|
+
* <EditorLayout>
|
|
54
|
+
* <EditorBar back={{ href: "/posts", label: "Posts" }} title="Spring menu launch"
|
|
55
|
+
* status={<SaveStatus state="saved" at={savedAt} />}
|
|
56
|
+
* actions={<><Button>Preview</Button><Button variant="primary">Publish</Button></>} />
|
|
57
|
+
* <EditorCanvas width="prose">{editor}</EditorCanvas>
|
|
58
|
+
* <EditorPanel>
|
|
59
|
+
* <EditorPanelSection id="status" title="Status" summary="Draft">…</EditorPanelSection>
|
|
60
|
+
* </EditorPanel>
|
|
61
|
+
* </EditorLayout>
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export const EditorLayout = React.forwardRef(function EditorLayout({ panelOpen: panelOpenProp, defaultPanelOpen = true, onPanelOpenChange, panelWidth: panelWidthProp, defaultPanelWidth = 320, onPanelWidthChange, resizable = false, focusMode: focusModeProp, defaultFocusMode = false, onFocusModeChange, readOnly = false, scroll = "page", stickyTop, shortcuts = true, labels, className, style, children, ...props }, ref) {
|
|
65
|
+
const { ref: measureRef, width } = useContainerWidth();
|
|
66
|
+
const composed = useComposedRefs(ref, measureRef);
|
|
67
|
+
const narrow = width !== undefined && width < NARROW;
|
|
68
|
+
const autoId = React.useId();
|
|
69
|
+
const panelId = `editor-panel${autoId.replace(/:/g, "")}`;
|
|
70
|
+
const [wideOpen, setWideOpen] = useControllableState({ value: panelOpenProp, defaultValue: defaultPanelOpen, onChange: onPanelOpenChange, name: "EditorLayout" });
|
|
71
|
+
const [sheetOpen, setSheetOpen] = React.useState(false);
|
|
72
|
+
const panelOpen = narrow ? (panelOpenProp !== undefined ? panelOpenProp : sheetOpen) : wideOpen;
|
|
73
|
+
const setPanelOpen = React.useCallback((open) => {
|
|
74
|
+
if (narrow) {
|
|
75
|
+
setSheetOpen(open);
|
|
76
|
+
onPanelOpenChange?.(open);
|
|
77
|
+
}
|
|
78
|
+
else
|
|
79
|
+
setWideOpen(open);
|
|
80
|
+
}, [narrow, setWideOpen, onPanelOpenChange]);
|
|
81
|
+
// Leaving the narrow layout closes the sheet; the wide panel keeps its own state.
|
|
82
|
+
React.useEffect(() => {
|
|
83
|
+
if (!narrow)
|
|
84
|
+
setSheetOpen(false);
|
|
85
|
+
}, [narrow]);
|
|
86
|
+
const [focusMode, setFocusMode] = useControllableState({ value: focusModeProp, defaultValue: defaultFocusMode, onChange: onFocusModeChange, name: "EditorLayout" });
|
|
87
|
+
const [panelWidth, setPanelWidth] = useControllableState({ value: panelWidthProp, defaultValue: defaultPanelWidth, onChange: onPanelWidthChange, name: "EditorLayout" });
|
|
88
|
+
// Focus mode: the bar dims after 1.5s without pointer movement.
|
|
89
|
+
const [idle, setIdle] = React.useState(false);
|
|
90
|
+
React.useEffect(() => {
|
|
91
|
+
if (!focusMode) {
|
|
92
|
+
setIdle(false);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
let timer = window.setTimeout(() => setIdle(true), 1500);
|
|
96
|
+
const wake = () => {
|
|
97
|
+
setIdle(false);
|
|
98
|
+
window.clearTimeout(timer);
|
|
99
|
+
timer = window.setTimeout(() => setIdle(true), 1500);
|
|
100
|
+
};
|
|
101
|
+
window.addEventListener("pointermove", wake);
|
|
102
|
+
return () => {
|
|
103
|
+
window.clearTimeout(timer);
|
|
104
|
+
window.removeEventListener("pointermove", wake);
|
|
105
|
+
};
|
|
106
|
+
}, [focusMode]);
|
|
107
|
+
// `mod+shift+,` — `,` is `<` with Shift on many layouts, so listen for both.
|
|
108
|
+
useHotkeys(["mod+shift+comma", "mod+shift+<"], () => setPanelOpen(!panelOpen), { enabled: shortcuts && !focusMode });
|
|
109
|
+
useHotkeys("mod+shift+f", () => setFocusMode(!focusMode), { enabled: shortcuts });
|
|
110
|
+
useHotkeys("escape", () => setFocusMode(false), { enabled: focusMode, preventDefault: false });
|
|
111
|
+
const ctx = React.useMemo(() => ({ panelId, panelOpen: panelOpen && !focusMode, setPanelOpen, narrow, focusMode, setFocusMode, readOnly, idle, resizable, panelWidth, defaultPanelWidth, setPanelWidth, labels }), [panelId, panelOpen, setPanelOpen, narrow, focusMode, setFocusMode, readOnly, idle, resizable, panelWidth, defaultPanelWidth, setPanelWidth, labels]);
|
|
112
|
+
const top = stickyTop === undefined ? undefined : typeof stickyTop === "number" ? `${stickyTop}px` : stickyTop;
|
|
113
|
+
return (_jsx(EditorLayoutContext.Provider, { value: ctx, children: _jsx("div", { ref: composed, "data-slot": "editor-layout", "data-scroll": scroll, "data-focus-mode": focusMode ? "" : undefined, "data-read-only": readOnly ? "" : undefined, className: cn("@container/editor relative w-full min-w-0", scroll === "panes" && "h-full min-h-0", className), style: { "--editor-panel-w": `${panelWidth}px`, ...(top !== undefined ? { "--editor-sticky-top": top } : null), ...style }, ...props, children: _jsx("div", { className: "vui-editor-grid", "data-panel": ctx.panelOpen && !narrow ? "open" : "closed", "data-scroll": scroll, children: children }) }) }));
|
|
114
|
+
});
|
|
115
|
+
/** The sticky publish bar: back, title, save status, actions, panel toggle. */
|
|
116
|
+
export const EditorBar = React.forwardRef(function EditorBar({ back, title, status, actions, secondaryActions, menu, panelToggle = true, focusToggle = false, labels, className, children, ...props }, ref) {
|
|
117
|
+
const ctx = useEditorLayout();
|
|
118
|
+
const t = useLabels("editor", editorLabels, labels ?? ctx?.labels);
|
|
119
|
+
const readOnly = ctx?.readOnly ?? false;
|
|
120
|
+
return (_jsxs("div", { ref: ref, "data-slot": "editor-bar", "data-idle": ctx?.idle ? "" : undefined, className: cn("vui-editor-bar surface-bar flex h-(--editor-bar-h,3.5rem) min-w-0 items-center gap-2 px-3 @2xl/editor:gap-3 @2xl/editor:px-4", className), ...props, children: [back ? (_jsxs(SmartLink, { href: back.href, "aria-label": back.label, className: "inline-flex h-8 shrink-0 items-center gap-1.5 rounded-ui-sm px-2 text-[13px] text-fg-muted transition-colors hover:bg-hover hover:text-fg focus-ring", children: [_jsx(ArrowLeft, { "aria-hidden": true, className: "size-4 rtl:-scale-x-100" }), _jsx("span", { "aria-hidden": true, className: "hidden @3xl/editor:inline", children: back.label })] })) : null, back && title ? _jsx("span", { "aria-hidden": true, className: "hidden h-5 w-px bg-line @3xl/editor:block" }) : null, _jsx("div", { "data-slot": "editor-bar-title", className: "min-w-0 flex-1 truncate text-[14px] font-medium text-fg", children: title }), status ? _jsx("div", { className: "hidden shrink-0 @md/editor:block", children: status }) : null, _jsxs("div", { className: "flex shrink-0 items-center gap-1.5", children: [secondaryActions && !readOnly ? _jsx("div", { className: "hidden items-center gap-1.5 @2xl/editor:flex", children: secondaryActions }) : null, actions && !readOnly ? actions : null, children, menu?.length ? _jsx(ActionMenu, { items: menu, triggerSize: "sm", triggerLabel: t("moreActions") }) : null, focusToggle && ctx ? (_jsx(Button, { variant: "ghost", size: "sm", "aria-pressed": ctx.focusMode, onClick: () => ctx.setFocusMode(!ctx.focusMode), "aria-keyshortcuts": "Control+Shift+F Meta+Shift+F", children: ctx.focusMode ? t("exitFocusMode") : t("focusMode") })) : null, panelToggle && ctx && !ctx.focusMode ? (_jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": t("togglePanel"), title: t("togglePanel"), "aria-expanded": ctx.panelOpen, "aria-controls": ctx.panelOpen || !ctx.narrow ? ctx.panelId : undefined, "aria-keyshortcuts": "Control+Shift+Comma Meta+Shift+Comma", "data-active": ctx.panelOpen ? "" : undefined, onClick: () => ctx.setPanelOpen(!ctx.panelOpen), className: "data-active:bg-selected", children: _jsx(PanelRight, { "aria-hidden": true, className: "rtl:-scale-x-100" }) })) : null] })] }));
|
|
121
|
+
});
|
|
122
|
+
const UNITS = [
|
|
123
|
+
["day", 86400],
|
|
124
|
+
["hour", 3600],
|
|
125
|
+
["minute", 60],
|
|
126
|
+
];
|
|
127
|
+
/**
|
|
128
|
+
* Where the document's changes are: "Unsaved changes" · "Saving…" · "Saved 2 min ago" ·
|
|
129
|
+
* "Couldn't save · Retry" · "Offline · changes kept locally". A polite status; the error is an alert.
|
|
130
|
+
*/
|
|
131
|
+
export const SaveStatus = React.forwardRef(function SaveStatus({ state, at, onRetry, guard = true, now: nowProp, labels, className, ...props }, ref) {
|
|
132
|
+
const ctx = useEditorLayout();
|
|
133
|
+
const t = useLabels("editor", editorLabels, labels ?? ctx?.labels);
|
|
134
|
+
const { locale } = useLocale();
|
|
135
|
+
const [tick, setTick] = React.useState(0);
|
|
136
|
+
React.useEffect(() => {
|
|
137
|
+
if (state !== "saved" || at === undefined || nowProp !== undefined)
|
|
138
|
+
return;
|
|
139
|
+
const id = window.setInterval(() => setTick((n) => n + 1), 30_000);
|
|
140
|
+
return () => window.clearInterval(id);
|
|
141
|
+
}, [state, at, nowProp]);
|
|
142
|
+
React.useEffect(() => {
|
|
143
|
+
if (!guard || (state !== "dirty" && state !== "saving"))
|
|
144
|
+
return;
|
|
145
|
+
const onBeforeUnload = (e) => {
|
|
146
|
+
e.preventDefault();
|
|
147
|
+
e.returnValue = "";
|
|
148
|
+
};
|
|
149
|
+
window.addEventListener("beforeunload", onBeforeUnload);
|
|
150
|
+
return () => window.removeEventListener("beforeunload", onBeforeUnload);
|
|
151
|
+
}, [guard, state]);
|
|
152
|
+
const savedText = React.useMemo(() => {
|
|
153
|
+
if (at === undefined)
|
|
154
|
+
return t("savedPlain");
|
|
155
|
+
const now = nowProp !== undefined ? +nowProp : Date.now();
|
|
156
|
+
const secs = Math.round((now - +at) / 1000);
|
|
157
|
+
if (secs < 45)
|
|
158
|
+
return t("savedJustNow");
|
|
159
|
+
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto", style: "short" });
|
|
160
|
+
for (const [unit, size] of UNITS) {
|
|
161
|
+
if (secs >= size || unit === "minute")
|
|
162
|
+
return t("saved", { time: rtf.format(-Math.max(1, Math.round(secs / size)), unit) });
|
|
163
|
+
}
|
|
164
|
+
return t("savedPlain");
|
|
165
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
166
|
+
}, [at, nowProp, locale, t, tick]);
|
|
167
|
+
const content = state === "dirty" ? (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": true, className: "size-1.5 rounded-full bg-warning" }), t("dirty")] })) : state === "saving" ? (_jsxs(_Fragment, { children: [_jsx(Spinner, { size: "xs" }), t("saving")] })) : state === "saved" ? (_jsxs(_Fragment, { children: [_jsx(Check, { "aria-hidden": true, className: "size-3.5 text-success" }), savedText] })) : state === "offline" ? (_jsxs(_Fragment, { children: [_jsx(CloudOff, { "aria-hidden": true, className: "size-3.5" }), t("offline")] })) : null;
|
|
168
|
+
return (_jsxs("span", { ref: ref, "data-slot": "save-status", "data-state": state, className: cn("inline-flex items-center gap-1.5 whitespace-nowrap text-[13px] text-fg-subtle", className), ...props, children: [_jsx("span", { role: "status", className: "inline-flex items-center gap-1.5", children: content }), state === "error" ? (_jsxs("span", { role: "alert", className: "inline-flex items-center gap-1.5 text-danger", children: [_jsx(TriangleAlert, { "aria-hidden": true, className: "size-3.5" }), t("error"), onRetry ? (_jsxs(_Fragment, { children: [_jsx("span", { "aria-hidden": true, children: "\u00B7" }), _jsx("button", { type: "button", onClick: onRetry, className: "rounded-ui-sm font-medium underline underline-offset-2 hover:no-underline focus-ring", children: t("retry") })] })) : null] })) : null] }));
|
|
169
|
+
});
|
|
170
|
+
/* ------------------------------------------------------------------ */
|
|
171
|
+
/* EditorCanvas */
|
|
172
|
+
/* ------------------------------------------------------------------ */
|
|
173
|
+
const canvasWidth = { prose: "max-w-[720px]", wide: "max-w-[1080px]", full: "max-w-none" };
|
|
174
|
+
/** The writing area: a centred column with generous margins. */
|
|
175
|
+
export const EditorCanvas = React.forwardRef(function EditorCanvas({ width = "prose", tone = "surface", notice, loading, labels, className, children, ...props }, ref) {
|
|
176
|
+
const ctx = useEditorLayout();
|
|
177
|
+
const t = useLabels("editor", editorLabels, labels ?? ctx?.labels);
|
|
178
|
+
return (_jsx("div", { ref: ref, "data-slot": "editor-canvas", "data-tone": tone, "aria-busy": loading || undefined, className: cn("vui-editor-canvas min-w-0 px-[var(--gutter,1.5rem)] py-8 @3xl/editor:py-12", tone === "surface" ? "bg-surface" : "bg-transparent", className), ...props, children: _jsxs("div", { className: cn("mx-auto flex w-full flex-col gap-6", canvasWidth[width]), children: [notice, loading ? (_jsxs("div", { role: "status", "aria-label": t("loading"), className: "grid gap-6", children: [_jsx(Skeleton, { className: "h-10 w-3/4 rounded-ui-sm" }), _jsx(SkeletonText, { lines: 4 }), _jsx(SkeletonText, { lines: 5 })] })) : (children)] }) }));
|
|
179
|
+
});
|
|
180
|
+
/** The side panel: `<aside>` of collapsible settings sections; a non-modal sheet on narrow layouts. */
|
|
181
|
+
export const EditorPanel = React.forwardRef(function EditorPanel({ tabs, value: valueProp, defaultValue, onValueChange, footer, labels, className, children, ...props }, ref) {
|
|
182
|
+
const ctx = useEditorLayout();
|
|
183
|
+
const t = useLabels("editor", editorLabels, labels ?? ctx?.labels);
|
|
184
|
+
const [value, setValue] = useControllableState({ value: valueProp, defaultValue: defaultValue ?? tabs?.[0]?.id ?? "", onChange: onValueChange, name: "EditorPanel" });
|
|
185
|
+
const label = props["aria-label"] ?? t("panel");
|
|
186
|
+
let inner = children;
|
|
187
|
+
if (tabs?.length) {
|
|
188
|
+
inner = (_jsxs(Tabs, { value: value, onValueChange: setValue, className: "gap-0", children: [_jsx("div", { className: "sticky top-0 z-[1] border-b border-line bg-surface px-3 py-2.5", children: _jsx(TabsList, { variant: "segmented", size: "sm", fill: true, "aria-label": label, children: tabs.map((tab) => (_jsx(TabsTrigger, { value: tab.id, children: tab.label }, tab.id))) }) }), children] }));
|
|
189
|
+
}
|
|
190
|
+
const body = (_jsxs("fieldset", { disabled: ctx?.readOnly || undefined, className: "m-0 flex min-h-0 min-w-0 flex-1 flex-col border-0 p-0", children: [_jsx("div", { className: "min-h-0 flex-1", children: inner }), footer ? _jsx("div", { className: "sticky bottom-0 border-t border-line bg-surface px-4 py-3", children: footer }) : null] }));
|
|
191
|
+
if (ctx?.narrow) {
|
|
192
|
+
return (_jsx(Sheet, { open: ctx.panelOpen, onOpenChange: ctx.setPanelOpen, modal: false, children: _jsxs(SheetContent, { side: "end", size: "sm", id: ctx.panelId, children: [_jsx(SheetHeader, { title: label }), _jsx(SheetBody, { className: "p-0", children: _jsx("section", { "aria-label": label, className: cn("flex min-h-full flex-col", className), children: body }) })] }) }));
|
|
193
|
+
}
|
|
194
|
+
return (_jsxs("aside", { ref: ref, id: ctx?.panelId, "aria-label": label, hidden: ctx ? !ctx.panelOpen : undefined, "data-slot": "editor-panel", className: cn("vui-editor-panel relative flex min-w-0 flex-col border-s border-line bg-surface", className), ...props, children: [ctx?.resizable ? (_jsx(SidePaneHandle, { "aria-label": t("resizePanel"), edge: "start", value: ctx.panelWidth, min: 280, max: 520, defaultValue: ctx.defaultPanelWidth, onValueChange: ctx.setPanelWidth, className: "-start-1" })) : null, body] }));
|
|
195
|
+
});
|
|
196
|
+
/** The sections of one panel tab (`value` matches a tab `id`). */
|
|
197
|
+
export const EditorPanelContent = React.forwardRef(function EditorPanelContent({ className, ...props }, ref) {
|
|
198
|
+
return _jsx(TabsContent, { ref: ref, className: cn("mt-0", className), ...props });
|
|
199
|
+
});
|
|
200
|
+
const storageKey = (id) => `vui:editor-section:${id}`;
|
|
201
|
+
function readStored(id) {
|
|
202
|
+
if (!id || typeof window === "undefined")
|
|
203
|
+
return undefined;
|
|
204
|
+
try {
|
|
205
|
+
const v = window.localStorage.getItem(storageKey(id));
|
|
206
|
+
return v === "1" ? true : v === "0" ? false : undefined;
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/** A folding meta box in the panel: Status, Permalink, Categories, Featured image, SEO. */
|
|
213
|
+
export const EditorPanelSection = React.forwardRef(function EditorPanelSection({ id, title, summary, defaultOpen = false, open: openProp, onOpenChange, actions, headingLevel = 2, className, children, ...props }, ref) {
|
|
214
|
+
const [open, setOpen] = useControllableState({ value: openProp, defaultValue: defaultOpen, onChange: onOpenChange, name: "EditorPanelSection" });
|
|
215
|
+
// Restore after mount (SSR renders the default).
|
|
216
|
+
React.useEffect(() => {
|
|
217
|
+
if (openProp !== undefined)
|
|
218
|
+
return;
|
|
219
|
+
const stored = readStored(id);
|
|
220
|
+
if (stored !== undefined)
|
|
221
|
+
setOpen(stored);
|
|
222
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
223
|
+
}, [id]);
|
|
224
|
+
const autoId = React.useId();
|
|
225
|
+
const titleId = `editor-section${autoId.replace(/:/g, "")}`;
|
|
226
|
+
const H = `h${headingLevel}`;
|
|
227
|
+
return (_jsx(Collapsible.Root, { open: open, onOpenChange: (v) => {
|
|
228
|
+
setOpen(v);
|
|
229
|
+
if (id)
|
|
230
|
+
try {
|
|
231
|
+
window.localStorage.setItem(storageKey(id), v ? "1" : "0");
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
/* storage blocked */
|
|
235
|
+
}
|
|
236
|
+
}, asChild: true, children: _jsxs("section", { ref: ref, "aria-labelledby": titleId, "data-slot": "editor-panel-section", "data-section": id, className: cn("group/section border-b border-line last:border-b-0", className), ...props, children: [_jsxs("div", { className: "flex items-center gap-1 pe-2", children: [_jsx(H, { id: titleId, className: "min-w-0 flex-1", children: _jsxs(Collapsible.Trigger, { className: "flex w-full min-w-0 items-center gap-2 py-3 ps-4 pe-2 text-start outline-none transition-colors hover:bg-hover focus-visible:bg-hover focus-ring focus-visible:outline-offset-[-2px]", children: [_jsxs("span", { className: "min-w-0 flex-1", children: [_jsx("span", { className: "block truncate text-[13px] font-semibold text-fg", children: title }), summary && !open ? _jsx("span", { className: "mt-0.5 block truncate text-[12px] font-normal text-fg-subtle", children: summary }) : null] }), _jsx(ChevronDown, { "aria-hidden": true, className: "size-4 shrink-0 text-fg-subtle transition-transform duration-200 group-data-[state=open]/section:rotate-180 motion-reduce:transition-none" })] }) }), actions ? _jsx("div", { className: "flex shrink-0 items-center gap-1", children: actions }) : null] }), _jsx(Collapsible.Content, { className: "ui-collapse", children: _jsx("div", { className: "grid gap-3 px-4 pb-4 pt-0.5 text-[13px]", children: children }) })] }) }));
|
|
237
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export type EmptyStateKind = "first-use" | "no-results" | "error" | "forbidden" | "done";
|
|
3
|
+
export declare const emptyStateVariants: (props?: ({
|
|
4
|
+
size?: "sm" | "md" | "lg" | null | undefined;
|
|
5
|
+
framed?: boolean | null | undefined;
|
|
6
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
|
+
export interface EmptyStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
|
|
8
|
+
/** Picks the default icon, its tint and the default title. Default `"first-use"`. */
|
|
9
|
+
kind?: EmptyStateKind;
|
|
10
|
+
/** `sm` inside a table/card, `md` a page section, `lg` a full page. Default `"md"`. */
|
|
11
|
+
size?: "sm" | "md" | "lg";
|
|
12
|
+
/** Replace the kind's icon, or `false` for none. */
|
|
13
|
+
icon?: React.ReactNode | false;
|
|
14
|
+
/** A larger picture in place of the icon well (SVG, image). */
|
|
15
|
+
illustration?: React.ReactNode;
|
|
16
|
+
/** Default copy comes from the dictionary (`empty.firstUse`, `empty.noResults`…). */
|
|
17
|
+
title?: React.ReactNode;
|
|
18
|
+
description?: React.ReactNode;
|
|
19
|
+
/** One primary next step, optionally a secondary one. */
|
|
20
|
+
actions?: React.ReactNode;
|
|
21
|
+
/** Dashed frame — a drop zone or an empty column. */
|
|
22
|
+
framed?: boolean;
|
|
23
|
+
/** Title element. Default `"h3"`. */
|
|
24
|
+
as?: "h2" | "h3" | "h4" | "p";
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Points to a next step when a list is empty, a search finds nothing, access is denied or
|
|
28
|
+
* something failed. Server-compatible. A `no-results` state is announced (`role="status"`).
|
|
29
|
+
*
|
|
30
|
+
* ```tsx
|
|
31
|
+
* <EmptyState
|
|
32
|
+
* title="No posts yet"
|
|
33
|
+
* description="Write your first post, or import from WordPress."
|
|
34
|
+
* actions={<Button variant="primary">Write a post</Button>}
|
|
35
|
+
* />
|
|
36
|
+
* <EmptyState kind="no-results" size="sm" actions={<Button size="sm" onClick={clear}>Clear filters</Button>} />
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare const EmptyState: React.ForwardRefExoticComponent<EmptyStateProps & React.RefAttributes<HTMLDivElement>>;
|
|
40
|
+
/** The icon well (sits on two faint contour rings). */
|
|
41
|
+
export declare function EmptyStateIcon({ className, children, ...props }: React.HTMLAttributes<HTMLDivElement>): React.JSX.Element;
|
|
42
|
+
export declare function EmptyStateTitle({ as: Tag, size, className, ...props }: React.HTMLAttributes<HTMLHeadingElement> & {
|
|
43
|
+
as?: "h2" | "h3" | "h4" | "p";
|
|
44
|
+
size?: "sm" | "md" | "lg";
|
|
45
|
+
}): React.JSX.Element;
|
|
46
|
+
export declare function EmptyStateDescription({ size, className, ...props }: React.HTMLAttributes<HTMLParagraphElement> & {
|
|
47
|
+
size?: "sm" | "md" | "lg";
|
|
48
|
+
}): React.JSX.Element;
|
|
49
|
+
export declare function EmptyStateActions({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): React.JSX.Element;
|
|
@@ -0,0 +1,68 @@
|
|
|
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 { CircleCheck, FilePlus2, LockKeyhole, SearchX, TriangleAlert } from "lucide-react";
|
|
5
|
+
import { cn } from "../lib/cn.js";
|
|
6
|
+
import { LocalizedText } from "../lib/islands.js";
|
|
7
|
+
const emptyLabels = {
|
|
8
|
+
firstUse: "Nothing here yet",
|
|
9
|
+
noResults: "No results match your filters",
|
|
10
|
+
error: "Something went wrong",
|
|
11
|
+
forbidden: "You don't have access to this page",
|
|
12
|
+
done: "You're all caught up",
|
|
13
|
+
retry: "Try again",
|
|
14
|
+
};
|
|
15
|
+
const KIND = {
|
|
16
|
+
"first-use": { icon: FilePlus2, label: "firstUse", well: "bg-accent-soft text-accent-ink" },
|
|
17
|
+
"no-results": { icon: SearchX, label: "noResults", well: "surface-2 text-fg-muted" },
|
|
18
|
+
error: { icon: TriangleAlert, label: "error", well: "tone-danger tone-soft" },
|
|
19
|
+
forbidden: { icon: LockKeyhole, label: "forbidden", well: "surface-2 text-fg-muted" },
|
|
20
|
+
done: { icon: CircleCheck, label: "done", well: "tone-success tone-soft" },
|
|
21
|
+
};
|
|
22
|
+
export const emptyStateVariants = cva("vui-empty flex w-full flex-col items-center text-center", {
|
|
23
|
+
variants: {
|
|
24
|
+
size: {
|
|
25
|
+
/** Inside a table, card or popover. */
|
|
26
|
+
sm: "gap-2.5 px-4 py-8 [--empty-well:2.5rem] [--empty-icon:1.125rem]",
|
|
27
|
+
/** A page section. */
|
|
28
|
+
md: "gap-3 px-6 py-14 [--empty-well:3rem] [--empty-icon:1.375rem]",
|
|
29
|
+
/** A whole page. */
|
|
30
|
+
lg: "gap-4 px-6 py-24 [--empty-well:3.75rem] [--empty-icon:1.625rem]",
|
|
31
|
+
},
|
|
32
|
+
framed: {
|
|
33
|
+
true: "rounded-ui-lg border border-dashed border-field-border",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
defaultVariants: { size: "md" },
|
|
37
|
+
});
|
|
38
|
+
/**
|
|
39
|
+
* Points to a next step when a list is empty, a search finds nothing, access is denied or
|
|
40
|
+
* something failed. Server-compatible. A `no-results` state is announced (`role="status"`).
|
|
41
|
+
*
|
|
42
|
+
* ```tsx
|
|
43
|
+
* <EmptyState
|
|
44
|
+
* title="No posts yet"
|
|
45
|
+
* description="Write your first post, or import from WordPress."
|
|
46
|
+
* actions={<Button variant="primary">Write a post</Button>}
|
|
47
|
+
* />
|
|
48
|
+
* <EmptyState kind="no-results" size="sm" actions={<Button size="sm" onClick={clear}>Clear filters</Button>} />
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export const EmptyState = React.forwardRef(function EmptyState({ kind = "first-use", size = "md", icon, illustration, title, description, actions, framed, as = "h3", className, children, role, ...props }, ref) {
|
|
52
|
+
const k = KIND[kind];
|
|
53
|
+
const Icon = k.icon;
|
|
54
|
+
return (_jsxs("div", { ref: ref, "data-slot": "empty-state", "data-kind": kind, "data-size": size, role: role ?? (kind === "no-results" ? "status" : undefined), className: cn(emptyStateVariants({ size, framed }), className), ...props, children: [illustration ? (_jsx("div", { "data-slot": "empty-state-illustration", className: cn("mb-1 flex justify-center text-fg-subtle", size === "lg" ? "max-w-72" : "max-w-48"), children: illustration })) : icon === false ? null : (_jsx(EmptyStateIcon, { className: cn(k.well, size === "sm" ? "mb-1" : "mb-2"), children: icon ?? _jsx(Icon, { "aria-hidden": true }) })), _jsx(EmptyStateTitle, { as: as, size: size, children: title ?? _jsx(LocalizedText, { namespace: "empty", id: k.label, defaults: emptyLabels }) }), description ? _jsx(EmptyStateDescription, { size: size, children: description }) : null, children, actions ? _jsx(EmptyStateActions, { className: size === "sm" ? "mt-1" : "mt-2", children: actions }) : null] }));
|
|
55
|
+
});
|
|
56
|
+
/** The icon well (sits on two faint contour rings). */
|
|
57
|
+
export function EmptyStateIcon({ className, children, ...props }) {
|
|
58
|
+
return (_jsx("div", { "aria-hidden": true, "data-slot": "empty-state-icon", className: cn("vui-empty-well flex size-(--empty-well,3rem) items-center justify-center rounded-ui [&_svg]:size-(--empty-icon,1.375rem) [&_svg]:stroke-[1.75]", className), ...props, children: children }));
|
|
59
|
+
}
|
|
60
|
+
export function EmptyStateTitle({ as: Tag = "h3", size = "md", className, ...props }) {
|
|
61
|
+
return (_jsx(Tag, { "data-slot": "empty-state-title", className: cn("max-w-[36ch] text-balance text-fg", size === "sm" && "text-sm font-semibold", size === "md" && "text-base font-semibold tracking-[-0.01em]", size === "lg" && "font-display text-[1.75rem] leading-tight", className), ...props }));
|
|
62
|
+
}
|
|
63
|
+
export function EmptyStateDescription({ size = "md", className, ...props }) {
|
|
64
|
+
return (_jsx("p", { "data-slot": "empty-state-description", className: cn("max-w-[44ch] text-pretty text-fg-muted", size === "sm" ? "-mt-1 text-[13px]" : size === "lg" ? "-mt-1 text-[15px] leading-relaxed" : "-mt-1 text-sm leading-relaxed", className), ...props }));
|
|
65
|
+
}
|
|
66
|
+
export function EmptyStateActions({ className, ...props }) {
|
|
67
|
+
return _jsx("div", { "data-slot": "empty-state-actions", className: cn("flex flex-wrap items-center justify-center gap-2", className), ...props });
|
|
68
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type ValueFormat } from "../lib/value-format.js";
|
|
3
|
+
import { type DescriptionEntry } from "./description-list.js";
|
|
4
|
+
export type EntityKind = "person" | "organization" | "product" | "generic";
|
|
5
|
+
export type EntityTone = "neutral" | "accent" | "success" | "warning" | "danger" | "info";
|
|
6
|
+
/** A compact fact in the card's stat row ("Open deals · 4", "Lifetime value · $182,400"). */
|
|
7
|
+
export interface EntityStat {
|
|
8
|
+
label: string;
|
|
9
|
+
value: number | string;
|
|
10
|
+
format?: ValueFormat;
|
|
11
|
+
}
|
|
12
|
+
export declare const entityCardLabels: {
|
|
13
|
+
email: string;
|
|
14
|
+
call: string;
|
|
15
|
+
website: string;
|
|
16
|
+
archived: string;
|
|
17
|
+
selected: string;
|
|
18
|
+
};
|
|
19
|
+
export type EntityCardLabels = Partial<typeof entityCardLabels>;
|
|
20
|
+
export interface EntityCardProps extends Omit<React.HTMLAttributes<HTMLElement>, "title"> {
|
|
21
|
+
/** Changes defaults only: avatar shape and fallback icon. Default `"person"`. */
|
|
22
|
+
kind?: EntityKind;
|
|
23
|
+
name: string;
|
|
24
|
+
/** Role · company, domain, SKU. */
|
|
25
|
+
subtitle?: React.ReactNode;
|
|
26
|
+
/** Photo, logo or product image. Missing → initials (person, organization) or an icon. */
|
|
27
|
+
media?: {
|
|
28
|
+
src?: string | null;
|
|
29
|
+
alt?: string;
|
|
30
|
+
fallback?: React.ReactNode;
|
|
31
|
+
};
|
|
32
|
+
/** Badges after the name (tags, plan, segment). */
|
|
33
|
+
badges?: React.ReactNode;
|
|
34
|
+
/** One status pill ("Active", "Out of stock"). */
|
|
35
|
+
status?: {
|
|
36
|
+
tone: EntityTone;
|
|
37
|
+
label: string;
|
|
38
|
+
};
|
|
39
|
+
/** Key facts — a mini Description list. */
|
|
40
|
+
fields?: DescriptionEntry[];
|
|
41
|
+
/** 2–3 numbers in a row. */
|
|
42
|
+
stats?: EntityStat[];
|
|
43
|
+
/** Quick actions. Each is a labelled button or link ("Email Jane Cooper"). */
|
|
44
|
+
actions?: React.ReactNode;
|
|
45
|
+
/** Built-in labelled quick actions: mailto / tel / website links. */
|
|
46
|
+
contact?: {
|
|
47
|
+
email?: string;
|
|
48
|
+
phone?: string;
|
|
49
|
+
website?: string;
|
|
50
|
+
};
|
|
51
|
+
/** Short free text (bio, product summary). */
|
|
52
|
+
description?: React.ReactNode;
|
|
53
|
+
/** The name becomes the card's one primary link (stretched over the card). */
|
|
54
|
+
href?: string;
|
|
55
|
+
/** `card` (grid tile), `compact` (row in a side panel), `header` (top of a record page), `chip` (inline name with a hover card). Default `"card"`. */
|
|
56
|
+
variant?: "card" | "compact" | "header" | "chip";
|
|
57
|
+
/** Heading level of the name. Default `h3` (`h1` for `header`). */
|
|
58
|
+
headingAs?: "h1" | "h2" | "h3" | "h4" | "p";
|
|
59
|
+
/** Muted with an "Archived" badge. */
|
|
60
|
+
archived?: boolean;
|
|
61
|
+
/** Picker state: accent outline + `aria-current`. */
|
|
62
|
+
selected?: boolean;
|
|
63
|
+
/** Skeleton in the variant's shape. */
|
|
64
|
+
loading?: boolean;
|
|
65
|
+
labels?: EntityCardLabels;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The identity of a record at a glance — a contact, a company, a product, an employee — with
|
|
69
|
+
* key facts and quick actions. An `<article>` with the name as its heading; with `href` the name
|
|
70
|
+
* is the one primary link (stretched over the card) and actions stay separate, labelled buttons.
|
|
71
|
+
*
|
|
72
|
+
* ```tsx
|
|
73
|
+
* <EntityCard
|
|
74
|
+
* name="Jane Cooper"
|
|
75
|
+
* subtitle="Head of Operations · Northwind Traders"
|
|
76
|
+
* status={{ tone: "success", label: "Customer" }}
|
|
77
|
+
* contact={{ email: "jane@northwind.com", phone: "+1 415 555 0136" }}
|
|
78
|
+
* fields={[{ key: "owner", label: "Owner", value: "Ayşe Kaya" }]}
|
|
79
|
+
* href="/contacts/jane-cooper"
|
|
80
|
+
* />
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare const EntityCard: React.ForwardRefExoticComponent<EntityCardProps & React.RefAttributes<HTMLElement>>;
|
|
@@ -0,0 +1,92 @@
|
|
|
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 { Building2, Globe, Mail, Package, Phone, Shapes, UserRound } from "lucide-react";
|
|
5
|
+
import { cn } from "../lib/cn.js";
|
|
6
|
+
import { useLabels } from "../lib/labels.js";
|
|
7
|
+
import { useFormat } from "../lib/locale.js";
|
|
8
|
+
import { formatValue } from "../lib/value-format.js";
|
|
9
|
+
import { Avatar } from "./avatar.js";
|
|
10
|
+
import { Badge } from "./badge.js";
|
|
11
|
+
import { IconButton } from "./button.js";
|
|
12
|
+
import { DescriptionList } from "./description-list.js";
|
|
13
|
+
import { HoverCard, HoverCardContent, HoverCardTrigger } from "./hover-card.js";
|
|
14
|
+
import { Skeleton } from "./skeleton.js";
|
|
15
|
+
export const entityCardLabels = {
|
|
16
|
+
email: "Email {name}",
|
|
17
|
+
call: "Call {name}",
|
|
18
|
+
website: "Open {name}'s website",
|
|
19
|
+
archived: "Archived",
|
|
20
|
+
selected: "Selected",
|
|
21
|
+
};
|
|
22
|
+
const KIND_ICON = { person: UserRound, organization: Building2, product: Package, generic: Shapes };
|
|
23
|
+
function EntityMedia({ kind, name, media, size, className }) {
|
|
24
|
+
const Icon = KIND_ICON[kind];
|
|
25
|
+
if (kind === "product" || size === "product" || size === "product-lg") {
|
|
26
|
+
const big = size === "product-lg";
|
|
27
|
+
return (_jsx("span", { "data-slot": "entity-media", className: cn("relative flex shrink-0 items-center justify-center overflow-hidden bg-surface-2 text-fg-subtle ring-1 ring-inset ring-line", big ? "aspect-[4/3] w-full rounded-[calc(var(--radius)-2px)]" : size === "xl" ? "size-16 rounded-ui" : size === "lg" ? "size-12 rounded-ui-sm" : "size-10 rounded-ui-sm", className), children: media?.src ? _jsx("img", { src: media.src, alt: media.alt ?? "", loading: "lazy", className: "size-full object-cover" }) : (media?.fallback ?? _jsx(Icon, { "aria-hidden": true, strokeWidth: 1.5, className: big ? "size-9" : "size-5" })) }));
|
|
28
|
+
}
|
|
29
|
+
const avatarSize = size;
|
|
30
|
+
return (_jsx(Avatar, { "data-slot": "entity-media", name: name, src: media?.src, size: avatarSize, shape: kind === "person" ? "circle" : "square", fallback: media?.fallback ?? (kind === "generic" ? _jsx(Icon, { "aria-hidden": true }) : undefined), className: cn("ring-2 ring-(--surface-solid)", className), "aria-hidden": true }));
|
|
31
|
+
}
|
|
32
|
+
function EntityStats({ stats, size = "md" }) {
|
|
33
|
+
const f = useFormat();
|
|
34
|
+
return (_jsx("dl", { "data-slot": "entity-stats", className: "flex flex-wrap gap-y-2", children: stats.map((s) => (_jsxs("div", { className: "grid min-w-0 flex-auto gap-0.5 border-s border-line px-3 first:border-s-0 first:ps-0 last:pe-0", children: [_jsx("dt", { className: "truncate text-[11.5px] text-fg-muted", children: s.label }), _jsx("dd", { className: cn("whitespace-nowrap font-heading font-semibold tracking-[-0.01em] text-fg tabular", size === "lg" ? "text-xl" : size === "sm" ? "text-sm" : "text-base"), children: typeof s.value === "number" ? formatValue(f, s.value, s.format ?? "number") : s.format && !Number.isNaN(Number(s.value)) ? formatValue(f, s.value, s.format) : s.value })] }, s.label))) }));
|
|
35
|
+
}
|
|
36
|
+
function ContactActions({ name, contact, t, size = "sm" }) {
|
|
37
|
+
return (_jsxs(_Fragment, { children: [contact.email ? (_jsx(IconButton, { asChild: true, label: t("email", { name }), size: size, variant: "secondary", tooltip: false, children: _jsx("a", { href: `mailto:${contact.email}`, children: _jsx(Mail, {}) }) })) : null, contact.phone ? (_jsx(IconButton, { asChild: true, label: t("call", { name }), size: size, variant: "secondary", tooltip: false, children: _jsx("a", { href: `tel:${contact.phone.replace(/[^\d+]/g, "")}`, children: _jsx(Phone, {}) }) })) : null, contact.website ? (_jsx(IconButton, { asChild: true, label: t("website", { name }), size: size, variant: "secondary", tooltip: false, children: _jsx("a", { href: contact.website, target: "_blank", rel: "noreferrer", children: _jsx(Globe, {}) }) })) : null] }));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The identity of a record at a glance — a contact, a company, a product, an employee — with
|
|
41
|
+
* key facts and quick actions. An `<article>` with the name as its heading; with `href` the name
|
|
42
|
+
* is the one primary link (stretched over the card) and actions stay separate, labelled buttons.
|
|
43
|
+
*
|
|
44
|
+
* ```tsx
|
|
45
|
+
* <EntityCard
|
|
46
|
+
* name="Jane Cooper"
|
|
47
|
+
* subtitle="Head of Operations · Northwind Traders"
|
|
48
|
+
* status={{ tone: "success", label: "Customer" }}
|
|
49
|
+
* contact={{ email: "jane@northwind.com", phone: "+1 415 555 0136" }}
|
|
50
|
+
* fields={[{ key: "owner", label: "Owner", value: "Ayşe Kaya" }]}
|
|
51
|
+
* href="/contacts/jane-cooper"
|
|
52
|
+
* />
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export const EntityCard = React.forwardRef(function EntityCard({ kind = "person", name, subtitle, media, badges, status, fields, stats, actions, contact, description, href, variant = "card", headingAs, archived, selected, loading, labels, className, ...props }, ref) {
|
|
56
|
+
const t = useLabels("entityCard", entityCardLabels, labels);
|
|
57
|
+
const H = headingAs ?? (variant === "header" ? "h1" : "h3");
|
|
58
|
+
const headingId = React.useId();
|
|
59
|
+
if (variant === "chip") {
|
|
60
|
+
const chip = (_jsxs("span", { className: "inline-flex max-w-full items-center gap-1.5 align-middle", children: [_jsx(EntityMedia, { kind: kind, name: name, media: media, size: "xs", className: "ring-0" }), _jsx("span", { className: "truncate font-medium", children: name })] }));
|
|
61
|
+
return (_jsxs(HoverCard, { children: [_jsx(HoverCardTrigger, { asChild: true, children: href ? (_jsx("a", { ref: ref, href: href, "data-slot": "entity-chip", className: cn("inline-flex max-w-full rounded-full py-0.5 pe-2 ps-0.5 text-[13px] text-fg hover:bg-hover focus-ring", className), ...props, children: chip })) : (_jsx("span", { ref: ref, tabIndex: 0, "data-slot": "entity-chip", className: cn("inline-flex max-w-full cursor-default rounded-full py-0.5 pe-2 ps-0.5 text-[13px] text-fg hover:bg-hover focus-ring", className), ...props, children: chip })) }), _jsx(HoverCardContent, { className: "w-80 p-0", children: _jsx(EntityCardPreview, { kind: kind, name: name, subtitle: subtitle, media: media, badges: badges, status: status, fields: fields, stats: stats, contact: contact, actions: actions, description: description, archived: archived, headingAs: "p", className: "border-0 bg-transparent shadow-none backdrop-blur-none", labels: labels }) })] }));
|
|
62
|
+
}
|
|
63
|
+
if (loading) {
|
|
64
|
+
return (_jsxs("article", { ref: ref, "aria-busy": "true", "data-slot": "entity-card", "data-variant": variant, className: cn(variant === "card" && "surface rounded-ui p-(--gap)", variant === "compact" && "flex items-center gap-3 py-2", variant === "header" && "flex items-center gap-5", className), ...props, children: [_jsxs("span", { className: cn("flex items-center gap-3", variant === "card" && "mb-4"), children: [_jsx(Skeleton, { shape: "circle", className: variant === "header" ? "size-16" : variant === "compact" ? "size-8" : "size-10" }), _jsxs("span", { className: "grid flex-1 gap-2", children: [_jsx(Skeleton, { className: cn("h-4 rounded-ui-sm", variant === "header" ? "w-56" : "w-32") }), _jsx(Skeleton, { className: "h-3 w-44 rounded-ui-sm" })] })] }), variant === "card" ? (_jsxs("span", { className: "grid gap-2", children: [_jsx(Skeleton, { className: "h-3 w-full rounded-ui-sm" }), _jsx(Skeleton, { className: "h-3 w-4/5 rounded-ui-sm" })] })) : null] }));
|
|
65
|
+
}
|
|
66
|
+
const title = (_jsx(H, { id: headingId, className: cn("min-w-0 text-fg", variant === "header" ? "font-heading text-2xl font-semibold tracking-[-0.02em] sm:text-[1.75rem]" : variant === "compact" ? "truncate text-[13.5px] font-semibold" : "truncate text-[15px] font-semibold tracking-[-0.005em]"), children: href ? (_jsx("a", { href: href, className: "rounded-ui-sm outline-none after:absolute after:inset-0 after:rounded-[inherit] after:content-[''] hover:underline underline-offset-[3px] focus-visible:after:outline-2 focus-visible:after:outline-offset-2 focus-visible:after:outline-(--ring)", children: name })) : (name) }));
|
|
67
|
+
const pills = status || badges || archived ? (_jsxs("span", { "data-slot": "entity-badges", className: "flex flex-wrap items-center gap-1", children: [status ? (_jsx(Badge, { tone: status.tone, dot: true, children: status.label })) : null, archived ? _jsx(Badge, { tone: "outline", children: t("archived") }) : null, badges] })) : null;
|
|
68
|
+
const quick = contact || actions ? (_jsxs("div", { "data-slot": "entity-actions", className: "relative z-1 flex shrink-0 flex-wrap items-center gap-1.5", children: [contact ? _jsx(ContactActions, { name: name, contact: contact, t: t, size: variant === "compact" ? "xs" : "sm" }) : null, actions] })) : null;
|
|
69
|
+
const shared = {
|
|
70
|
+
ref,
|
|
71
|
+
"data-slot": "entity-card",
|
|
72
|
+
"data-variant": variant,
|
|
73
|
+
"data-kind": kind,
|
|
74
|
+
"data-archived": archived ? "" : undefined,
|
|
75
|
+
"aria-labelledby": headingId,
|
|
76
|
+
"aria-current": selected ? true : undefined,
|
|
77
|
+
...props,
|
|
78
|
+
};
|
|
79
|
+
if (variant === "compact") {
|
|
80
|
+
return (_jsxs("article", { ...shared, className: cn("group relative flex items-center gap-3 rounded-ui-sm px-2 py-2 transition-colors", href && "hover:bg-hover", selected && "bg-selected ring-1 ring-inset ring-[color-mix(in_srgb,var(--accent-ink)_45%,transparent)]", archived && "opacity-65", className), children: [_jsx(EntityMedia, { kind: kind, name: name, media: media, size: "md", className: "ring-0" }), _jsxs("div", { className: "grid min-w-0 flex-1 gap-0.5", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [title, status ? (_jsx(Badge, { tone: status.tone, dot: true, size: "sm", className: "shrink-0", children: status.label })) : null] }), subtitle ? _jsx("p", { className: "truncate text-xs text-fg-muted", children: subtitle }) : null] }), quick] }));
|
|
81
|
+
}
|
|
82
|
+
if (variant === "header") {
|
|
83
|
+
return (_jsxs("article", { ...shared, className: cn("relative grid gap-5", archived && "[&_[data-slot=entity-media]]:grayscale", className), children: [_jsxs("div", { className: "flex flex-wrap items-start gap-x-5 gap-y-4", children: [_jsx(EntityMedia, { kind: kind, name: name, media: media, size: "xl", className: kind === "product" ? undefined : "size-16 text-xl" }), _jsxs("div", { className: "grid min-w-0 flex-1 basis-64 gap-1.5", children: [pills, title, subtitle ? _jsx("p", { className: "text-sm text-fg-muted", children: subtitle }) : null, description ? _jsx("p", { className: "max-w-[62ch] text-[13.5px] leading-relaxed text-fg-muted", children: description }) : null] }), quick ? _jsx("div", { className: "self-start", children: quick }) : null] }), stats?.length ? (_jsx("div", { className: "border-y border-line py-3", children: _jsx(EntityStats, { stats: stats, size: "lg" }) })) : null, fields?.length ? (_jsx("div", { className: "@container", children: _jsx(DescriptionList, { items: fields, layout: "grid", size: "sm", className: "grid-cols-2 @2xl:grid-cols-3" }) })) : null] }));
|
|
84
|
+
}
|
|
85
|
+
// card
|
|
86
|
+
const productTile = kind === "product";
|
|
87
|
+
return (_jsxs("article", { ...shared, className: cn("surface group relative flex flex-col overflow-hidden rounded-ui transition-[border-color,box-shadow]", href && "hover:border-field-border-hover", selected && "border-[color-mix(in_srgb,var(--accent-ink)_55%,var(--line))] shadow-[0_0_0_1px_color-mix(in_srgb,var(--accent-ink)_55%,transparent)]", archived && "[&>*]:opacity-70", className), children: [productTile ? (_jsx("div", { className: "p-1.5 pb-0", children: _jsx(EntityMedia, { kind: kind, name: name, media: media, size: "product-lg" }) })) : null, _jsxs("div", { className: "flex flex-1 flex-col gap-3 p-(--gap)", children: [_jsxs("div", { className: "flex min-w-0 items-start gap-3", children: [!productTile ? _jsx(EntityMedia, { kind: kind, name: name, media: media, size: "lg" }) : null, _jsxs("div", { className: "grid min-w-0 flex-1 gap-0.5", children: [title, subtitle ? _jsx("p", { className: "truncate text-[12.5px] text-fg-muted", children: subtitle }) : null] })] }), pills, description ? _jsx("p", { className: "line-clamp-3 text-[13px] leading-relaxed text-fg-muted", children: description }) : null, stats?.length ? (_jsx("div", { className: "rounded-ui-sm bg-surface-2 px-3 py-2.5", children: _jsx(EntityStats, { stats: stats, size: "sm" }) })) : null, fields?.length ? _jsx(DescriptionList, { items: fields, layout: "grid", size: "sm", className: "relative z-1 grid-cols-2 gap-y-3" }) : null, quick ? _jsx("div", { className: "mt-auto flex items-center pt-1", children: quick }) : null] })] }));
|
|
88
|
+
});
|
|
89
|
+
/** The card shown inside the chip variant's hover card. */
|
|
90
|
+
function EntityCardPreview(props) {
|
|
91
|
+
return _jsx(EntityCard, { ...props });
|
|
92
|
+
}
|