@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,96 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type MediaLibraryLabels } from "./media-library.js";
|
|
3
|
+
import type { MediaAdapter, MediaAsset } from "./types.js";
|
|
4
|
+
declare const pickerLabels: {
|
|
5
|
+
title: string;
|
|
6
|
+
titleImage: string;
|
|
7
|
+
titleImages: string;
|
|
8
|
+
library: string;
|
|
9
|
+
upload: string;
|
|
10
|
+
url: string;
|
|
11
|
+
uploadTitle: string;
|
|
12
|
+
uploadHint: string;
|
|
13
|
+
uploadButton: string;
|
|
14
|
+
uploadAccept: string;
|
|
15
|
+
urlLabel: string;
|
|
16
|
+
urlHint: string;
|
|
17
|
+
urlPlaceholder: string;
|
|
18
|
+
urlImport: string;
|
|
19
|
+
urlImporting: string;
|
|
20
|
+
urlError: string;
|
|
21
|
+
cancel: string;
|
|
22
|
+
confirm: string;
|
|
23
|
+
confirmImage: string;
|
|
24
|
+
selected: string;
|
|
25
|
+
maxHint: string;
|
|
26
|
+
remove: string;
|
|
27
|
+
more: string;
|
|
28
|
+
altTitle: string;
|
|
29
|
+
altDescription: string;
|
|
30
|
+
altFor: string;
|
|
31
|
+
decorative: string;
|
|
32
|
+
shortcut: string;
|
|
33
|
+
};
|
|
34
|
+
export type MediaPickerLabels = typeof pickerLabels;
|
|
35
|
+
export type MediaPickerTab = "library" | "upload" | "url";
|
|
36
|
+
export interface MediaPickerProps {
|
|
37
|
+
open?: boolean;
|
|
38
|
+
defaultOpen?: boolean;
|
|
39
|
+
onOpenChange?: (open: boolean) => void;
|
|
40
|
+
/** Else from `MediaProvider`. */
|
|
41
|
+
adapter?: MediaAdapter;
|
|
42
|
+
multiple?: boolean;
|
|
43
|
+
/** Selection limit with `multiple`. */
|
|
44
|
+
max?: number;
|
|
45
|
+
/** `"image/*"`: library filter and upload restriction. */
|
|
46
|
+
accept?: string;
|
|
47
|
+
/** Preselected asset ids. */
|
|
48
|
+
value?: string[];
|
|
49
|
+
/** Called with the chosen assets on confirm (alt text already saved when `requireAlt`). */
|
|
50
|
+
onSelect?: (assets: MediaAsset[]) => void;
|
|
51
|
+
/** Dialog title. Default "Select image(s)" / "Select media". */
|
|
52
|
+
title?: string;
|
|
53
|
+
/** Confirm button text ("Set featured image"). Default is pluralised: "Insert 2 images". */
|
|
54
|
+
confirmLabel?: string;
|
|
55
|
+
/** Tabs to show, in order. Default library + upload (+ "url" when the adapter can sideload). */
|
|
56
|
+
tabs?: MediaPickerTab[];
|
|
57
|
+
/** Ask for alt text on images that have none before confirming. */
|
|
58
|
+
requireAlt?: boolean;
|
|
59
|
+
/** `md` 720px · `lg` 1080px (with details panel) · `full`. Default `"lg"`. */
|
|
60
|
+
size?: "md" | "lg" | "full";
|
|
61
|
+
/** Optional trigger (rendered as `DialogTrigger asChild`). */
|
|
62
|
+
children?: React.ReactNode;
|
|
63
|
+
labels?: Partial<MediaPickerLabels>;
|
|
64
|
+
libraryLabels?: Partial<MediaLibraryLabels>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A dialog that picks one or more files for a field: featured image, gallery blocks, logos,
|
|
68
|
+
* profile photos, attachments. Library, Upload and From URL tabs; new uploads are selected
|
|
69
|
+
* automatically; optional alt-text check before confirming. ⌘/Ctrl + Enter confirms.
|
|
70
|
+
*
|
|
71
|
+
* ```tsx
|
|
72
|
+
* <MediaPicker accept="image/*" confirmLabel="Set featured image" onSelect={([asset]) => setCover(asset)}>
|
|
73
|
+
* <Button>Choose image</Button>
|
|
74
|
+
* </MediaPicker>
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export declare function MediaPicker({ open: openProp, defaultOpen, onOpenChange, adapter: adapterProp, multiple, max, accept, value, onSelect, title, confirmLabel, tabs: tabsProp, requireAlt, size, children, labels, libraryLabels, }: MediaPickerProps): React.JSX.Element;
|
|
78
|
+
export type MediaPickOptions = Omit<MediaPickerProps, "open" | "defaultOpen" | "onOpenChange" | "onSelect" | "children">;
|
|
79
|
+
type PickFn = (options?: MediaPickOptions) => Promise<MediaAsset[]>;
|
|
80
|
+
/**
|
|
81
|
+
* Hosts one Media picker for `useMediaPicker()`. Put it once near the app root, inside `MediaProvider`.
|
|
82
|
+
*/
|
|
83
|
+
export declare function MediaPickerProvider({ children, adapter }: {
|
|
84
|
+
children: React.ReactNode;
|
|
85
|
+
adapter?: MediaAdapter;
|
|
86
|
+
}): React.JSX.Element;
|
|
87
|
+
/**
|
|
88
|
+
* Opens the picker from code and resolves with the chosen assets (`[]` when cancelled).
|
|
89
|
+
*
|
|
90
|
+
* ```ts
|
|
91
|
+
* const pick = useMediaPicker();
|
|
92
|
+
* const [logo] = await pick({ accept: "image/*", confirmLabel: "Use as logo" });
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export declare function useMediaPicker(): PickFn;
|
|
96
|
+
export {};
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Link2, TriangleAlert, Upload, X } 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 { useControllableState } from "../lib/use-controllable-state.js";
|
|
9
|
+
import { FieldContextReset } from "../lib/field-context.js";
|
|
10
|
+
import { Alert } from "../components/alert.js";
|
|
11
|
+
import { Button } from "../components/button.js";
|
|
12
|
+
import { Checkbox } from "../components/checkbox.js";
|
|
13
|
+
import { Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTrigger } from "../components/dialog.js";
|
|
14
|
+
import { Input } from "../components/input.js";
|
|
15
|
+
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../components/tabs.js";
|
|
16
|
+
import { MediaLibrary, MediaThumb } from "./media-library.js";
|
|
17
|
+
import { useMedia } from "./media-provider.js";
|
|
18
|
+
import { DECORATIVE_TAG, isAltMissing } from "./media-utils.js";
|
|
19
|
+
const pickerLabels = {
|
|
20
|
+
title: "Select media",
|
|
21
|
+
titleImage: "Select image",
|
|
22
|
+
titleImages: "Select images",
|
|
23
|
+
library: "Library",
|
|
24
|
+
upload: "Upload",
|
|
25
|
+
url: "From URL",
|
|
26
|
+
uploadTitle: "Drop files to upload",
|
|
27
|
+
uploadHint: "or choose them from your computer. They are added to the library and selected.",
|
|
28
|
+
uploadButton: "Choose files",
|
|
29
|
+
uploadAccept: "Accepted: {accept}",
|
|
30
|
+
urlLabel: "File URL",
|
|
31
|
+
urlHint: "Paste a link to an image or file. It is copied into the library.",
|
|
32
|
+
urlPlaceholder: "https://",
|
|
33
|
+
urlImport: "Import",
|
|
34
|
+
urlImporting: "Importing…",
|
|
35
|
+
urlError: "That URL couldn't be imported. Check the link and try again.",
|
|
36
|
+
cancel: "Cancel",
|
|
37
|
+
confirm: "{count, plural, =0 {Insert} one {Insert file} other {Insert # files}}",
|
|
38
|
+
confirmImage: "{count, plural, =0 {Insert} one {Insert image} other {Insert # images}}",
|
|
39
|
+
selected: "{count, plural, =0 {Nothing selected} one {# selected} other {# selected}}",
|
|
40
|
+
maxHint: "Up to {max}",
|
|
41
|
+
remove: "Remove {name} from selection",
|
|
42
|
+
more: "+{count}",
|
|
43
|
+
altTitle: "{count, plural, one {An image needs alt text} other {# images need alt text}}",
|
|
44
|
+
altDescription: "Describe each image, or mark it as decorative.",
|
|
45
|
+
altFor: "Alt text for {name}",
|
|
46
|
+
decorative: "Decorative",
|
|
47
|
+
shortcut: "Ctrl + Enter to confirm",
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* A dialog that picks one or more files for a field: featured image, gallery blocks, logos,
|
|
51
|
+
* profile photos, attachments. Library, Upload and From URL tabs; new uploads are selected
|
|
52
|
+
* automatically; optional alt-text check before confirming. ⌘/Ctrl + Enter confirms.
|
|
53
|
+
*
|
|
54
|
+
* ```tsx
|
|
55
|
+
* <MediaPicker accept="image/*" confirmLabel="Set featured image" onSelect={([asset]) => setCover(asset)}>
|
|
56
|
+
* <Button>Choose image</Button>
|
|
57
|
+
* </MediaPicker>
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export function MediaPicker({ open: openProp, defaultOpen, onOpenChange, adapter: adapterProp, multiple = false, max, accept, value, onSelect, title, confirmLabel, tabs: tabsProp, requireAlt = false, size = "lg", children, labels, libraryLabels, }) {
|
|
61
|
+
const [open, setOpen] = useControllableState({ value: openProp, defaultValue: defaultOpen ?? false, onChange: onOpenChange, name: "MediaPicker" });
|
|
62
|
+
return (_jsxs(Dialog, { open: open, onOpenChange: setOpen, children: [children ? _jsx(DialogTrigger, { asChild: true, children: children }) : null, open ? (_jsx(MediaPickerContent, { adapter: adapterProp, multiple: multiple, max: max, accept: accept, value: value, title: title, confirmLabel: confirmLabel, tabs: tabsProp, requireAlt: requireAlt, size: size, labels: labels, libraryLabels: libraryLabels, onCancel: () => setOpen(false), onConfirm: (assets) => {
|
|
63
|
+
onSelect?.(assets);
|
|
64
|
+
setOpen(false);
|
|
65
|
+
} })) : null] }));
|
|
66
|
+
}
|
|
67
|
+
const SIZE_W = { md: "45rem", lg: "67.5rem", full: "none" };
|
|
68
|
+
function MediaPickerContent({ adapter: adapterProp, multiple, max, accept, value, title, confirmLabel, tabs: tabsProp, requireAlt, size = "lg", labels, libraryLabels, onCancel, onConfirm }) {
|
|
69
|
+
const t = useLabels("mediaPicker", pickerLabels, labels);
|
|
70
|
+
const f = useFormat();
|
|
71
|
+
const ctx = useMedia();
|
|
72
|
+
const adapter = adapterProp ?? ctx;
|
|
73
|
+
const imagesOnly = Boolean(accept && accept.split(",").every((r) => r.trim().startsWith("image/")));
|
|
74
|
+
const tabs = tabsProp ?? ["library", "upload", ...(adapter?.sideload ? ["url"] : [])];
|
|
75
|
+
const [tab, setTab] = React.useState(tabs[0] ?? "library");
|
|
76
|
+
const [ids, setIds] = React.useState(value ?? []);
|
|
77
|
+
const [assets, setAssets] = React.useState(new Map());
|
|
78
|
+
const [altDrafts, setAltDrafts] = React.useState({});
|
|
79
|
+
const [decorative, setDecorative] = React.useState({});
|
|
80
|
+
const [saving, setSaving] = React.useState(false);
|
|
81
|
+
const library = React.useRef(null);
|
|
82
|
+
const searchRef = React.useRef(null);
|
|
83
|
+
// Preselected ids the library hasn't loaded yet.
|
|
84
|
+
React.useEffect(() => {
|
|
85
|
+
if (!adapter || !value?.length)
|
|
86
|
+
return;
|
|
87
|
+
const load = adapter.getMany ? adapter.getMany(value) : Promise.all(value.map((id) => adapter.get(id)));
|
|
88
|
+
load.then((list) => setAssets((m) => new Map([...m, ...list.map((a) => [a.id, a])]))).catch(() => { });
|
|
89
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
90
|
+
}, [adapter]);
|
|
91
|
+
const chosen = ids.map((id) => assets.get(id)).filter((a) => Boolean(a));
|
|
92
|
+
const needsAlt = requireAlt ? chosen.filter((a) => isAltMissing(a) && !decorative[a.id]) : [];
|
|
93
|
+
const unresolved = needsAlt.filter((a) => !(altDrafts[a.id] ?? "").trim());
|
|
94
|
+
const canConfirm = chosen.length > 0 && unresolved.length === 0 && !saving;
|
|
95
|
+
const confirm = async () => {
|
|
96
|
+
if (!canConfirm)
|
|
97
|
+
return;
|
|
98
|
+
let out = chosen;
|
|
99
|
+
if (requireAlt && adapter) {
|
|
100
|
+
setSaving(true);
|
|
101
|
+
try {
|
|
102
|
+
out = await Promise.all(chosen.map(async (a) => {
|
|
103
|
+
if (decorative[a.id])
|
|
104
|
+
return adapter.update(a.id, { alt: "", tags: [...(a.tags ?? []).filter((x) => x !== DECORATIVE_TAG), DECORATIVE_TAG] });
|
|
105
|
+
const draft = altDrafts[a.id]?.trim();
|
|
106
|
+
return draft && isAltMissing(a) ? adapter.update(a.id, { alt: draft }) : a;
|
|
107
|
+
}));
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
setSaving(false);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
onConfirm(out);
|
|
114
|
+
};
|
|
115
|
+
const dialogTitle = title ?? (imagesOnly ? (multiple ? t("titleImages") : t("titleImage")) : t("title"));
|
|
116
|
+
const buttonText = confirmLabel ?? t(imagesOnly ? "confirmImage" : "confirm", { count: chosen.length });
|
|
117
|
+
const tabLabel = { library: t("library"), upload: t("upload"), url: t("url") };
|
|
118
|
+
const onFiles = (files) => {
|
|
119
|
+
if (!files?.length)
|
|
120
|
+
return;
|
|
121
|
+
library.current?.addFiles(files);
|
|
122
|
+
setTab("library");
|
|
123
|
+
};
|
|
124
|
+
return (_jsx(DialogContent, { size: size === "full" ? "full" : "xl", mobile: "fullscreen", className: "vui-media-picker", style: { "--dialog-w": SIZE_W[size] }, onOpenAutoFocus: (e) => {
|
|
125
|
+
e.preventDefault();
|
|
126
|
+
searchRef.current?.focus();
|
|
127
|
+
}, onKeyDown: (e) => {
|
|
128
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
129
|
+
e.preventDefault();
|
|
130
|
+
void confirm();
|
|
131
|
+
}
|
|
132
|
+
}, children: _jsxs(FieldContextReset, { children: [_jsx(DialogHeader, { title: dialogTitle }), _jsxs(Tabs, { value: tab, onValueChange: (v) => setTab(v), className: "flex min-h-0 flex-1 flex-col", children: [tabs.length > 1 ? (_jsx(TabsList, { className: "mx-6 shrink-0", children: tabs.map((k) => (_jsx(TabsTrigger, { value: k, children: tabLabel[k] }, k))) })) : null, _jsxs(DialogBody, { flush: true, className: "flex min-h-0 flex-1 flex-col", children: [_jsx(TabsContent, { value: "library", forceMount: true, className: "min-h-0 flex-1 p-4 data-[state=inactive]:hidden", children: _jsx(MediaLibrary, { handleRef: library, adapter: adapter, searchRef: searchRef, selection: multiple ? "multiple" : "single", max: multiple ? max : undefined, accept: accept, selected: ids, onSelectedChange: (next, list) => {
|
|
133
|
+
setIds(next);
|
|
134
|
+
setAssets((m) => new Map([...m, ...list.map((a) => [a.id, a])]));
|
|
135
|
+
}, selectUploaded: true, detailsPanel: size === "md" ? false : "side", height: "min(30rem, 52dvh)", labels: libraryLabels, className: "shadow-none" }) }), tabs.includes("upload") ? (_jsx(TabsContent, { value: "upload", className: "p-4", children: _jsx(PickerDropzone, { accept: accept, multiple: Boolean(multiple), onFiles: onFiles, t: t }) })) : null, tabs.includes("url") && adapter?.sideload ? (_jsx(TabsContent, { value: "url", className: "p-6", children: _jsx(PickerUrlForm, { adapter: adapter, t: t, onImported: (asset) => {
|
|
136
|
+
setAssets((m) => new Map(m).set(asset.id, asset));
|
|
137
|
+
library.current?.addAssets([asset], { select: true });
|
|
138
|
+
setTab("library");
|
|
139
|
+
} }) })) : null] })] }), needsAlt.length ? (_jsxs("div", { "data-slot": "media-picker-alt", className: "border-t border-line px-6 py-3", children: [_jsx(Alert, { tone: "warning", title: t("altTitle", { count: needsAlt.length }), children: t("altDescription") }), _jsx("ul", { className: "mt-3 grid max-h-40 gap-2 overflow-y-auto", children: needsAlt.map((a) => (_jsxs("li", { className: "grid grid-cols-[2.25rem_minmax(0,1fr)_auto] items-center gap-3", children: [_jsx("span", { className: "size-9 overflow-hidden rounded-ui-sm ring-1 ring-line", children: _jsx(MediaThumb, { asset: a, rounded: "none" }) }), _jsx(Input, { size: "sm", "aria-label": t("altFor", { name: a.filename }), placeholder: a.filename, value: altDrafts[a.id] ?? "", onChange: (e) => setAltDrafts((d) => ({ ...d, [a.id]: e.target.value })) }), _jsx(Checkbox, { size: "sm", label: t("decorative"), checked: Boolean(decorative[a.id]), onCheckedChange: (c) => setDecorative((d) => ({ ...d, [a.id]: c === true })) })] }, a.id))) })] })) : null, _jsxs(DialogFooter, { align: "between", className: "gap-3", children: [_jsxs("div", { "data-slot": "media-picker-tray", className: "flex min-w-0 items-center gap-2", children: [chosen.length ? (_jsxs("ul", { "aria-label": t("selected", { count: chosen.length }), className: "flex items-center -space-x-1.5", children: [chosen.slice(0, 6).map((a) => (_jsxs("li", { className: "group/tray relative size-9 overflow-hidden rounded-ui-sm bg-surface-2 ring-2 ring-[var(--popover)]", children: [_jsx(MediaThumb, { asset: a, rounded: "none" }), _jsx("button", { type: "button", "aria-label": t("remove", { name: a.filename }), onClick: () => setIds((l) => l.filter((id) => id !== a.id)), className: "focus-ring absolute inset-0 flex items-center justify-center bg-[color-mix(in_srgb,var(--scene)_70%,transparent)] text-fg opacity-0 transition-opacity group-hover/tray:opacity-100 focus-visible:opacity-100", children: _jsx(X, { className: "size-3.5" }) })] }, a.id))), chosen.length > 6 ? _jsx("li", { className: "tabular flex size-9 items-center justify-center rounded-ui-sm bg-surface-2 text-[11.5px] text-fg-muted ring-2 ring-[var(--popover)]", children: t("more", { count: chosen.length - 6 }) }) : null] })) : null, _jsxs("span", { className: "tabular truncate text-[12.5px] text-fg-muted", children: [t("selected", { count: chosen.length }), multiple && max ? ` · ${t("maxHint", { max: f.number(max) })}` : null] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { onClick: onCancel, children: t("cancel") }), _jsx(Button, { variant: "primary", disabled: !canConfirm, loading: saving, onClick: () => void confirm(), "aria-keyshortcuts": "Control+Enter Meta+Enter", title: t("shortcut"), children: buttonText })] })] })] }) }));
|
|
140
|
+
}
|
|
141
|
+
function PickerDropzone({ accept, multiple, onFiles, t }) {
|
|
142
|
+
const input = React.useRef(null);
|
|
143
|
+
const [over, setOver] = React.useState(false);
|
|
144
|
+
return (_jsxs("div", { "data-slot": "media-picker-dropzone", "data-dragging": over ? "" : undefined, onDragOver: (e) => {
|
|
145
|
+
e.preventDefault();
|
|
146
|
+
setOver(true);
|
|
147
|
+
}, onDragLeave: () => setOver(false), onDrop: (e) => {
|
|
148
|
+
e.preventDefault();
|
|
149
|
+
setOver(false);
|
|
150
|
+
onFiles(e.dataTransfer.files);
|
|
151
|
+
}, className: cn("vui-media-dropzone flex min-h-72 flex-col items-center justify-center gap-3 rounded-ui border border-dashed border-field-border bg-surface-2 px-6 py-10 text-center transition-colors", over && "border-ring bg-accent-soft"), children: [_jsx("span", { className: "flex size-11 items-center justify-center rounded-full bg-surface text-fg-muted ring-1 ring-line", children: _jsx(Upload, { "aria-hidden": true, className: "size-5" }) }), _jsxs("div", { className: "grid gap-1", children: [_jsx("p", { className: "text-[15px] font-semibold text-fg", children: t("uploadTitle") }), _jsx("p", { className: "max-w-sm text-[13px] text-fg-muted", children: t("uploadHint") })] }), _jsx(Button, { variant: "secondary", onClick: () => input.current?.click(), children: t("uploadButton") }), accept ? _jsx("p", { className: "text-[12px] text-fg-subtle", children: t("uploadAccept", { accept }) }) : null, _jsx("input", { ref: input, type: "file", hidden: true, tabIndex: -1, "aria-hidden": true, accept: accept, multiple: multiple, onChange: (e) => {
|
|
152
|
+
onFiles(e.target.files);
|
|
153
|
+
e.target.value = "";
|
|
154
|
+
} })] }));
|
|
155
|
+
}
|
|
156
|
+
function PickerUrlForm({ adapter, onImported, t }) {
|
|
157
|
+
const [url, setUrl] = React.useState("");
|
|
158
|
+
const [state, setState] = React.useState("idle");
|
|
159
|
+
const id = React.useId();
|
|
160
|
+
const hintId = React.useId();
|
|
161
|
+
const valid = /^https?:\/\/\S+\.\S+/.test(url.trim());
|
|
162
|
+
const submit = async (e) => {
|
|
163
|
+
e.preventDefault();
|
|
164
|
+
if (!valid || !adapter.sideload)
|
|
165
|
+
return;
|
|
166
|
+
setState("loading");
|
|
167
|
+
try {
|
|
168
|
+
const asset = await adapter.sideload(url.trim(), { signal: new AbortController().signal, onProgress: () => { } });
|
|
169
|
+
setState("idle");
|
|
170
|
+
setUrl("");
|
|
171
|
+
onImported(asset);
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
setState("error");
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
return (_jsxs("form", { onSubmit: submit, className: "mx-auto grid max-w-xl gap-2 py-6", children: [_jsx("label", { htmlFor: id, className: "text-[13px] font-medium text-fg", children: t("urlLabel") }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Input, { id: id, type: "url", inputMode: "url", leading: _jsx(Link2, { "aria-hidden": true }), placeholder: t("urlPlaceholder"), value: url, "aria-describedby": hintId, invalid: state === "error", onChange: (e) => setUrl(e.target.value), className: "flex-1" }), _jsx(Button, { type: "submit", variant: "secondary", disabled: !valid, loading: state === "loading", loadingText: t("urlImporting"), children: t("urlImport") })] }), _jsx("p", { id: hintId, className: cn("text-[12.5px]", state === "error" ? "text-danger" : "text-fg-muted"), children: state === "error" ? (_jsxs("span", { className: "inline-flex items-center gap-1.5", children: [_jsx(TriangleAlert, { "aria-hidden": true, className: "size-3.5" }), t("urlError")] })) : (t("urlHint")) })] }));
|
|
178
|
+
}
|
|
179
|
+
const PickerContext = React.createContext(null);
|
|
180
|
+
/**
|
|
181
|
+
* Hosts one Media picker for `useMediaPicker()`. Put it once near the app root, inside `MediaProvider`.
|
|
182
|
+
*/
|
|
183
|
+
export function MediaPickerProvider({ children, adapter }) {
|
|
184
|
+
const [request, setRequest] = React.useState(null);
|
|
185
|
+
const pick = React.useCallback((options = {}) => new Promise((resolve) => setRequest({ options, resolve })), []);
|
|
186
|
+
return (_jsxs(PickerContext.Provider, { value: pick, children: [children, _jsx(MediaPicker, { adapter: adapter, ...request?.options, open: Boolean(request), onOpenChange: (o) => {
|
|
187
|
+
if (!o && request) {
|
|
188
|
+
request.resolve([]);
|
|
189
|
+
setRequest(null);
|
|
190
|
+
}
|
|
191
|
+
}, onSelect: (assets) => {
|
|
192
|
+
request?.resolve(assets);
|
|
193
|
+
setRequest(null);
|
|
194
|
+
} })] }));
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Opens the picker from code and resolves with the chosen assets (`[]` when cancelled).
|
|
198
|
+
*
|
|
199
|
+
* ```ts
|
|
200
|
+
* const pick = useMediaPicker();
|
|
201
|
+
* const [logo] = await pick({ accept: "image/*", confirmLabel: "Use as logo" });
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
export function useMediaPicker() {
|
|
205
|
+
const pick = React.useContext(PickerContext);
|
|
206
|
+
if (!pick)
|
|
207
|
+
throw new Error("useMediaPicker() needs a <MediaPickerProvider> above it.");
|
|
208
|
+
return pick;
|
|
209
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { MediaAdapter, MediaAsset, MediaItem, MediaSource } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Provides the media adapter to Media library, Media picker, Image field, Gallery and the editor.
|
|
5
|
+
* `VamosProvider media={adapter}` works too; this provider wins when both are set.
|
|
6
|
+
*
|
|
7
|
+
* ```tsx
|
|
8
|
+
* <MediaProvider adapter={createMemoryAdapter({ seed })}>…</MediaProvider>
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
export declare function MediaProvider({ adapter, children }: {
|
|
12
|
+
adapter: MediaAdapter;
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
}): React.JSX.Element;
|
|
15
|
+
/** The adapter from `MediaProvider`, else from `VamosProvider media`. */
|
|
16
|
+
export declare function useMedia(): MediaAdapter | undefined;
|
|
17
|
+
/** `true` for a full `MediaAsset` (has `id` + `url`). */
|
|
18
|
+
export declare function isMediaAsset(item: unknown): item is MediaAsset;
|
|
19
|
+
/** Normalises an asset or a plain source to the fields viewers need. */
|
|
20
|
+
export declare function toMediaSource(item: MediaItem, index?: number): MediaSource & {
|
|
21
|
+
id: string;
|
|
22
|
+
kind: "image" | "video";
|
|
23
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { useMediaAdapter } from "../lib/provider.js";
|
|
5
|
+
const MediaContext = React.createContext(undefined);
|
|
6
|
+
/**
|
|
7
|
+
* Provides the media adapter to Media library, Media picker, Image field, Gallery and the editor.
|
|
8
|
+
* `VamosProvider media={adapter}` works too; this provider wins when both are set.
|
|
9
|
+
*
|
|
10
|
+
* ```tsx
|
|
11
|
+
* <MediaProvider adapter={createMemoryAdapter({ seed })}>…</MediaProvider>
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export function MediaProvider({ adapter, children }) {
|
|
15
|
+
return _jsx(MediaContext.Provider, { value: adapter, children: children });
|
|
16
|
+
}
|
|
17
|
+
/** The adapter from `MediaProvider`, else from `VamosProvider media`. */
|
|
18
|
+
export function useMedia() {
|
|
19
|
+
const own = React.useContext(MediaContext);
|
|
20
|
+
const app = useMediaAdapter();
|
|
21
|
+
return own ?? app;
|
|
22
|
+
}
|
|
23
|
+
/** `true` for a full `MediaAsset` (has `id` + `url`). */
|
|
24
|
+
export function isMediaAsset(item) {
|
|
25
|
+
return typeof item === "object" && item !== null && "url" in item && "id" in item && "mime" in item;
|
|
26
|
+
}
|
|
27
|
+
/** Normalises an asset or a plain source to the fields viewers need. */
|
|
28
|
+
export function toMediaSource(item, index = 0) {
|
|
29
|
+
if (isMediaAsset(item)) {
|
|
30
|
+
return {
|
|
31
|
+
id: item.id,
|
|
32
|
+
src: item.url,
|
|
33
|
+
alt: item.alt,
|
|
34
|
+
width: item.width,
|
|
35
|
+
height: item.height,
|
|
36
|
+
caption: item.caption,
|
|
37
|
+
kind: item.kind === "video" ? "video" : "image",
|
|
38
|
+
placeholder: item.placeholder,
|
|
39
|
+
focalPoint: item.focalPoint,
|
|
40
|
+
poster: item.variants?.poster?.url ?? item.variants?.thumb?.url,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return { ...item, id: item.id ?? `${index}:${item.src}`, kind: item.kind ?? "image" };
|
|
44
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { MediaAsset, MediaKind } from "./types.js";
|
|
2
|
+
/** MIME → the kit's media kind. */
|
|
3
|
+
export declare function mediaKindOf(mime: string, filename?: string): MediaKind;
|
|
4
|
+
/**
|
|
5
|
+
* `true` when a file or asset matches an `accept` string (`"image/*,.pdf,application/zip"`).
|
|
6
|
+
* An empty accept matches everything.
|
|
7
|
+
*/
|
|
8
|
+
export declare function acceptsMedia(accept: string | undefined, item: {
|
|
9
|
+
mime?: string;
|
|
10
|
+
type?: string;
|
|
11
|
+
filename?: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
}): boolean;
|
|
14
|
+
/** Kinds an accept string allows (`"image/*"` → `["image"]`), or `undefined` when it is mixed/any. */
|
|
15
|
+
export declare function kindsFromAccept(accept: string | undefined): MediaKind[] | undefined;
|
|
16
|
+
/** `"2026-11-04T09:12:00Z"` → `"2026-11"`. */
|
|
17
|
+
export declare const monthKey: (iso: string) => string;
|
|
18
|
+
/** A `YYYY-MM` key as a Date in the middle of the month (no time-zone edge). */
|
|
19
|
+
export declare const monthDate: (key: string) => Date;
|
|
20
|
+
/** Short file extension label for tiles without a preview ("PDF", "DOCX"). */
|
|
21
|
+
export declare function extensionOf(filename: string): string;
|
|
22
|
+
/** Best small preview URL of an asset (thumb variant → medium → original), images only. */
|
|
23
|
+
export declare function thumbUrl(asset: MediaAsset): string | undefined;
|
|
24
|
+
/** Tag that marks an image as intentionally decorative (`alt=""` on purpose). */
|
|
25
|
+
export declare const DECORATIVE_TAG = "decorative";
|
|
26
|
+
export declare const isDecorative: (asset: MediaAsset) => boolean;
|
|
27
|
+
/** Missing alt text matters for images only; `""` marked decorative (tag) is fine. */
|
|
28
|
+
export declare function isAltMissing(asset: MediaAsset, alt?: string): boolean;
|
|
29
|
+
export declare const clientId: (prefix?: string) => string;
|
|
30
|
+
/** Reads an image file's pixel size (client only). */
|
|
31
|
+
export declare function readImageSize(file: Blob): Promise<{
|
|
32
|
+
width: number;
|
|
33
|
+
height: number;
|
|
34
|
+
} | null>;
|
|
35
|
+
/**
|
|
36
|
+
* Downscales a raster image so its longer side is at most `maxDimension` (canvas, zero deps).
|
|
37
|
+
* Returns the original file for SVG/GIF, non-images, small images, or when canvas is unavailable.
|
|
38
|
+
*/
|
|
39
|
+
export declare function downscaleImage(file: File, maxDimension: number, quality?: number): Promise<File>;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/** MIME → the kit's media kind. */
|
|
2
|
+
export function mediaKindOf(mime, filename = "") {
|
|
3
|
+
const m = mime.toLowerCase();
|
|
4
|
+
if (m.startsWith("image/"))
|
|
5
|
+
return "image";
|
|
6
|
+
if (m.startsWith("video/"))
|
|
7
|
+
return "video";
|
|
8
|
+
if (m.startsWith("audio/"))
|
|
9
|
+
return "audio";
|
|
10
|
+
if (/pdf|word|sheet|excel|presentation|powerpoint|text|csv|rtf|opendocument/.test(m))
|
|
11
|
+
return "document";
|
|
12
|
+
if (/zip|tar|rar|7z|gzip|compressed/.test(m))
|
|
13
|
+
return "archive";
|
|
14
|
+
const ext = filename.toLowerCase().split(".").pop() ?? "";
|
|
15
|
+
if (["jpg", "jpeg", "png", "gif", "webp", "avif", "svg", "heic"].includes(ext))
|
|
16
|
+
return "image";
|
|
17
|
+
if (["pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "csv"].includes(ext))
|
|
18
|
+
return "document";
|
|
19
|
+
if (["zip", "rar", "7z", "tar", "gz"].includes(ext))
|
|
20
|
+
return "archive";
|
|
21
|
+
return "other";
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* `true` when a file or asset matches an `accept` string (`"image/*,.pdf,application/zip"`).
|
|
25
|
+
* An empty accept matches everything.
|
|
26
|
+
*/
|
|
27
|
+
export function acceptsMedia(accept, item) {
|
|
28
|
+
if (!accept || !accept.trim())
|
|
29
|
+
return true;
|
|
30
|
+
const mime = (item.mime ?? item.type ?? "").toLowerCase();
|
|
31
|
+
const name = (item.filename ?? item.name ?? "").toLowerCase();
|
|
32
|
+
return accept.split(",").some((raw) => {
|
|
33
|
+
const rule = raw.trim().toLowerCase();
|
|
34
|
+
if (!rule)
|
|
35
|
+
return false;
|
|
36
|
+
if (rule === "*" || rule === "*/*")
|
|
37
|
+
return true;
|
|
38
|
+
if (rule.startsWith("."))
|
|
39
|
+
return name.endsWith(rule);
|
|
40
|
+
if (rule.endsWith("/*"))
|
|
41
|
+
return mime.startsWith(rule.slice(0, -1));
|
|
42
|
+
return mime === rule;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/** Kinds an accept string allows (`"image/*"` → `["image"]`), or `undefined` when it is mixed/any. */
|
|
46
|
+
export function kindsFromAccept(accept) {
|
|
47
|
+
if (!accept)
|
|
48
|
+
return undefined;
|
|
49
|
+
const kinds = new Set();
|
|
50
|
+
for (const raw of accept.split(",")) {
|
|
51
|
+
const rule = raw.trim().toLowerCase();
|
|
52
|
+
if (!rule)
|
|
53
|
+
continue;
|
|
54
|
+
if (rule.startsWith("image/"))
|
|
55
|
+
kinds.add("image");
|
|
56
|
+
else if (rule.startsWith("video/"))
|
|
57
|
+
kinds.add("video");
|
|
58
|
+
else if (rule.startsWith("audio/"))
|
|
59
|
+
kinds.add("audio");
|
|
60
|
+
else
|
|
61
|
+
return undefined;
|
|
62
|
+
}
|
|
63
|
+
return kinds.size ? [...kinds] : undefined;
|
|
64
|
+
}
|
|
65
|
+
/** `"2026-11-04T09:12:00Z"` → `"2026-11"`. */
|
|
66
|
+
export const monthKey = (iso) => iso.slice(0, 7);
|
|
67
|
+
/** A `YYYY-MM` key as a Date in the middle of the month (no time-zone edge). */
|
|
68
|
+
export const monthDate = (key) => new Date(`${key}-15T12:00:00Z`);
|
|
69
|
+
/** Short file extension label for tiles without a preview ("PDF", "DOCX"). */
|
|
70
|
+
export function extensionOf(filename) {
|
|
71
|
+
const ext = filename.includes(".") ? filename.split(".").pop() ?? "" : "";
|
|
72
|
+
return ext.slice(0, 5).toUpperCase();
|
|
73
|
+
}
|
|
74
|
+
/** Best small preview URL of an asset (thumb variant → medium → original), images only. */
|
|
75
|
+
export function thumbUrl(asset) {
|
|
76
|
+
if (asset.kind !== "image" && !asset.variants?.thumb && !asset.variants?.poster)
|
|
77
|
+
return undefined;
|
|
78
|
+
return asset.variants?.thumb?.url ?? asset.variants?.medium?.url ?? asset.variants?.poster?.url ?? (asset.kind === "image" ? asset.url : undefined);
|
|
79
|
+
}
|
|
80
|
+
/** Tag that marks an image as intentionally decorative (`alt=""` on purpose). */
|
|
81
|
+
export const DECORATIVE_TAG = "decorative";
|
|
82
|
+
export const isDecorative = (asset) => Boolean(asset.tags?.includes(DECORATIVE_TAG));
|
|
83
|
+
/** Missing alt text matters for images only; `""` marked decorative (tag) is fine. */
|
|
84
|
+
export function isAltMissing(asset, alt = asset.alt) {
|
|
85
|
+
return asset.kind === "image" && !alt.trim() && !isDecorative(asset);
|
|
86
|
+
}
|
|
87
|
+
/** Stable id for client-side records. */
|
|
88
|
+
let seq = 0;
|
|
89
|
+
export const clientId = (prefix = "u") => `${prefix}_${Date.now().toString(36)}${(seq++).toString(36)}`;
|
|
90
|
+
/** Reads an image file's pixel size (client only). */
|
|
91
|
+
export function readImageSize(file) {
|
|
92
|
+
if (typeof window === "undefined" || typeof URL === "undefined" || !URL.createObjectURL)
|
|
93
|
+
return Promise.resolve(null);
|
|
94
|
+
return new Promise((resolve) => {
|
|
95
|
+
const url = URL.createObjectURL(file);
|
|
96
|
+
const img = new window.Image();
|
|
97
|
+
img.onload = () => {
|
|
98
|
+
resolve(img.naturalWidth ? { width: img.naturalWidth, height: img.naturalHeight } : null);
|
|
99
|
+
URL.revokeObjectURL(url);
|
|
100
|
+
};
|
|
101
|
+
img.onerror = () => {
|
|
102
|
+
resolve(null);
|
|
103
|
+
URL.revokeObjectURL(url);
|
|
104
|
+
};
|
|
105
|
+
img.src = url;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Downscales a raster image so its longer side is at most `maxDimension` (canvas, zero deps).
|
|
110
|
+
* Returns the original file for SVG/GIF, non-images, small images, or when canvas is unavailable.
|
|
111
|
+
*/
|
|
112
|
+
export async function downscaleImage(file, maxDimension, quality = 0.9) {
|
|
113
|
+
if (!file.type.startsWith("image/") || /svg|gif/.test(file.type) || typeof document === "undefined")
|
|
114
|
+
return file;
|
|
115
|
+
const size = await readImageSize(file);
|
|
116
|
+
if (!size || Math.max(size.width, size.height) <= maxDimension)
|
|
117
|
+
return file;
|
|
118
|
+
const scale = maxDimension / Math.max(size.width, size.height);
|
|
119
|
+
const url = URL.createObjectURL(file);
|
|
120
|
+
try {
|
|
121
|
+
const img = await new Promise((resolve, reject) => {
|
|
122
|
+
const el = new window.Image();
|
|
123
|
+
el.onload = () => resolve(el);
|
|
124
|
+
el.onerror = () => reject(new Error("decode"));
|
|
125
|
+
el.src = url;
|
|
126
|
+
});
|
|
127
|
+
const canvas = document.createElement("canvas");
|
|
128
|
+
canvas.width = Math.round(size.width * scale);
|
|
129
|
+
canvas.height = Math.round(size.height * scale);
|
|
130
|
+
const ctx = canvas.getContext("2d");
|
|
131
|
+
if (!ctx)
|
|
132
|
+
return file;
|
|
133
|
+
ctx.imageSmoothingQuality = "high";
|
|
134
|
+
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
|
135
|
+
const type = file.type === "image/png" ? "image/png" : file.type === "image/webp" ? "image/webp" : "image/jpeg";
|
|
136
|
+
const blob = await new Promise((resolve) => canvas.toBlob(resolve, type, quality));
|
|
137
|
+
return blob ? new File([blob], file.name, { type, lastModified: file.lastModified }) : file;
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
return file;
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
URL.revokeObjectURL(url);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { MediaAdapter, MediaAsset, MediaFolder } from "./types.js";
|
|
2
|
+
export interface MemoryAdapterOptions {
|
|
3
|
+
/** Initial assets. */
|
|
4
|
+
seed?: MediaAsset[];
|
|
5
|
+
folders?: MediaFolder[];
|
|
6
|
+
/** Simulated latency in ms. Default 120 (0 in tests is fine). */
|
|
7
|
+
latency?: number;
|
|
8
|
+
/** Simulated upload duration in ms. Default 900. */
|
|
9
|
+
uploadDuration?: number;
|
|
10
|
+
/** Locale for search folding (Turkish İ/ı). Default "en-US". */
|
|
11
|
+
locale?: string;
|
|
12
|
+
capabilities?: Partial<MediaAdapter["capabilities"]>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* An in-memory adapter for docs, demos, prototypes and tests: object URLs for uploads,
|
|
16
|
+
* simulated progress, locale-aware search. Nothing persists.
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* const adapter = createMemoryAdapter({ seed: assets, locale: "tr-TR" });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function createMemoryAdapter(options?: MemoryAdapterOptions): MediaAdapter;
|