@alfakit/vue 0.1.2 → 0.1.7
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/CHANGELOG.md +16 -0
- package/dist/AlfakitRoot.js.map +1 -1
- package/dist/AlfakitRoot.vue.d.ts.map +1 -1
- package/dist/AlfakitRoot.vue_vue_type_script_setup_true_lang.js +3 -1
- package/dist/AlfakitRoot.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/actions/ActionGroupMenu.js.map +1 -1
- package/dist/components/actions/ActionGroupMenu.vue.d.ts.map +1 -1
- package/dist/components/actions/ActionGroupMenu.vue_vue_type_script_setup_true_lang.js +69 -65
- package/dist/components/actions/ActionGroupMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/actions/ActionModal.js.map +1 -1
- package/dist/components/actions/ActionModal.vue.d.ts.map +1 -1
- package/dist/components/actions/ActionModal.vue_vue_type_script_setup_true_lang.js +17 -15
- package/dist/components/actions/ActionModal.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/ai/AiCopilot.js.map +1 -1
- package/dist/components/ai/AiCopilot.vue.d.ts +2 -0
- package/dist/components/ai/AiCopilot.vue.d.ts.map +1 -1
- package/dist/components/ai/AiCopilot.vue_vue_type_script_setup_true_lang.js +7 -2
- package/dist/components/ai/AiCopilot.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/cms/CmsPage.vue_vue_type_script_setup_true_lang.js +19 -19
- package/dist/components/cms/CmsPage.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/cms/LivePreview.js.map +1 -1
- package/dist/components/cms/LivePreview.vue.d.ts.map +1 -1
- package/dist/components/cms/LivePreview.vue_vue_type_script_setup_true_lang.js +83 -83
- package/dist/components/cms/LivePreview.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/BuilderField.js.map +1 -1
- package/dist/components/fields/BuilderField.vue.d.ts.map +1 -1
- package/dist/components/fields/BuilderField.vue_vue_type_script_setup_true_lang.js +162 -157
- package/dist/components/fields/BuilderField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/ImageEditorDialog.js.map +1 -1
- package/dist/components/fields/ImageEditorDialog.vue.d.ts.map +1 -1
- package/dist/components/fields/ImageEditorDialog.vue_vue_type_script_setup_true_lang.js +46 -46
- package/dist/components/fields/ImageEditorDialog.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/KeyValueField.js.map +1 -1
- package/dist/components/fields/KeyValueField.vue.d.ts.map +1 -1
- package/dist/components/fields/KeyValueField.vue_vue_type_script_setup_true_lang.js +66 -66
- package/dist/components/fields/KeyValueField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/ModalTablePicker.js.map +1 -1
- package/dist/components/fields/ModalTablePicker.vue.d.ts.map +1 -1
- package/dist/components/fields/ModalTablePicker.vue_vue_type_script_setup_true_lang.js +113 -113
- package/dist/components/fields/ModalTablePicker.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/RepeaterField.js.map +1 -1
- package/dist/components/fields/RepeaterField.vue.d.ts.map +1 -1
- package/dist/components/fields/RepeaterField.vue_vue_type_script_setup_true_lang.js +12 -12
- package/dist/components/fields/RepeaterField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/RichEditorInput.js.map +1 -1
- package/dist/components/fields/RichEditorInput.vue.d.ts.map +1 -1
- package/dist/components/fields/RichEditorInput.vue_vue_type_script_setup_true_lang.js +166 -165
- package/dist/components/fields/RichEditorInput.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/SliderField.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/fields/item-actions.d.ts +2 -2
- package/dist/components/fields/item-actions.d.ts.map +1 -1
- package/dist/components/fields/item-actions.js +31 -31
- package/dist/components/fields/item-actions.js.map +1 -1
- package/dist/components/form/FormBlock.js.map +1 -1
- package/dist/components/form/FormBlock.vue.d.ts.map +1 -1
- package/dist/components/form/FormBlock.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/form/FormBlock.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/form/form-context.js +25 -25
- package/dist/components/form/form-context.js.map +1 -1
- package/dist/components/kanban/KanbanBoard.js.map +1 -1
- package/dist/components/kanban/KanbanBoard.vue.d.ts.map +1 -1
- package/dist/components/kanban/KanbanBoard.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/components/kanban/KanbanBoard.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/kanban/KanbanColumnHeader.js.map +1 -1
- package/dist/components/kanban/KanbanColumnHeader.vue.d.ts.map +1 -1
- package/dist/components/kanban/KanbanColumnHeader.vue_vue_type_script_setup_true_lang.js +64 -64
- package/dist/components/kanban/KanbanColumnHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/layout/SectionComponent.js.map +1 -1
- package/dist/components/layout/SectionComponent.vue.d.ts.map +1 -1
- package/dist/components/layout/SectionComponent.vue_vue_type_script_setup_true_lang.js +23 -23
- package/dist/components/layout/SectionComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/DebugPanel.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/components/panel/DebugPanel.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/GlobalSearchPalette.js.map +1 -1
- package/dist/components/panel/GlobalSearchPalette.vue.d.ts.map +1 -1
- package/dist/components/panel/GlobalSearchPalette.vue_vue_type_script_setup_true_lang.js +102 -96
- package/dist/components/panel/GlobalSearchPalette.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/NavGroup.vue_vue_type_script_setup_true_lang.js +10 -10
- package/dist/components/panel/NavGroup.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/NavGroupFlyout.vue_vue_type_script_setup_true_lang.js +9 -9
- package/dist/components/panel/NavGroupFlyout.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/NavItem.vue_vue_type_script_setup_true_lang.js +16 -16
- package/dist/components/panel/NavItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/NavSubItem.vue_vue_type_script_setup_true_lang.js +10 -10
- package/dist/components/panel/NavSubItem.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/TenantMenu.vue_vue_type_script_setup_true_lang.js +35 -35
- package/dist/components/panel/TenantMenu.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/panel/Topbar.vue_vue_type_script_setup_true_lang.js +11 -11
- package/dist/components/panel/Topbar.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/realtime/use-live-updates.d.ts.map +1 -1
- package/dist/components/realtime/use-live-updates.js +24 -23
- package/dist/components/realtime/use-live-updates.js.map +1 -1
- package/dist/components/table/BooleanCell.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/components/table/BooleanCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/ColumnHeader.js.map +1 -1
- package/dist/components/table/ColumnHeader.vue.d.ts.map +1 -1
- package/dist/components/table/ColumnHeader.vue_vue_type_script_setup_true_lang.js +55 -49
- package/dist/components/table/ColumnHeader.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/ColumnManager.js.map +1 -1
- package/dist/components/table/ColumnManager.vue.d.ts.map +1 -1
- package/dist/components/table/ColumnManager.vue_vue_type_script_setup_true_lang.js +5 -4
- package/dist/components/table/ColumnManager.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/ContentLayoutSort.js.map +1 -1
- package/dist/components/table/ContentLayoutSort.vue.d.ts.map +1 -1
- package/dist/components/table/ContentLayoutSort.vue_vue_type_script_setup_true_lang.js +5 -5
- package/dist/components/table/ContentLayoutSort.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/SelectCell.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/components/table/SelectCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/SelectComboboxCell.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/components/table/SelectComboboxCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/TableCellContent.js.map +1 -1
- package/dist/components/table/TableCellContent.vue.d.ts.map +1 -1
- package/dist/components/table/TableCellContent.vue_vue_type_script_setup_true_lang.js +4 -3
- package/dist/components/table/TableCellContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/TablePagination.js.map +1 -1
- package/dist/components/table/TablePagination.vue.d.ts.map +1 -1
- package/dist/components/table/TablePagination.vue_vue_type_script_setup_true_lang.js +87 -87
- package/dist/components/table/TablePagination.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/TextInputCell.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/components/table/TextInputCell.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/table/cell-update.d.ts +6 -0
- package/dist/components/table/cell-update.d.ts.map +1 -1
- package/dist/components/table/cell-update.js.map +1 -1
- package/dist/components/translation-manager/TranslationManagerView.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/components/translation-manager/TranslationManagerView.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/ui/CommandAutoHighlight.js +7 -0
- package/dist/components/ui/CommandAutoHighlight.js.map +1 -0
- package/dist/components/ui/CommandAutoHighlight.vue.d.ts +21 -0
- package/dist/components/ui/CommandAutoHighlight.vue.d.ts.map +1 -0
- package/dist/components/ui/CommandAutoHighlight.vue_vue_type_script_setup_true_lang.js +18 -0
- package/dist/components/ui/CommandAutoHighlight.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/components/ui/DialogContent.js.map +1 -1
- package/dist/components/ui/DialogContent.vue.d.ts.map +1 -1
- package/dist/components/ui/DialogContent.vue_vue_type_script_setup_true_lang.js +13 -12
- package/dist/components/ui/DialogContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/ui/PopoverContent.js.map +1 -1
- package/dist/components/ui/PopoverContent.vue.d.ts.map +1 -1
- package/dist/components/ui/PopoverContent.vue_vue_type_script_setup_true_lang.js +9 -8
- package/dist/components/ui/PopoverContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/ui/SheetContent.js.map +1 -1
- package/dist/components/ui/SheetContent.vue.d.ts.map +1 -1
- package/dist/components/ui/SheetContent.vue_vue_type_script_setup_true_lang.js +13 -12
- package/dist/components/ui/SheetContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/components/ui/TooltipContent.js.map +1 -1
- package/dist/components/ui/TooltipContent.vue.d.ts.map +1 -1
- package/dist/components/ui/TooltipContent.vue_vue_type_script_setup_true_lang.js +9 -8
- package/dist/components/ui/TooltipContent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/context.d.ts +7 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +29 -26
- package/dist/context.js.map +1 -1
- package/dist/create-alfakit.d.ts.map +1 -1
- package/dist/create-alfakit.js +33 -31
- package/dist/create-alfakit.js.map +1 -1
- package/dist/eject-manifest.json +11 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +219 -217
- package/dist/layouts/AppLayout.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/layouts/AppLayout.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/layouts/AuthLayout.vue_vue_type_script_setup_true_lang.js +9 -9
- package/dist/layouts/FullscreenLayout.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/layouts/FullscreenLayout.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/layouts/TopNavLayout.vue_vue_type_script_setup_true_lang.js +15 -15
- package/dist/layouts/TopNavLayout.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/layouts/lazy-layouts.d.ts +10 -0
- package/dist/layouts/lazy-layouts.d.ts.map +1 -0
- package/dist/layouts/lazy-layouts.js +8 -0
- package/dist/layouts/lazy-layouts.js.map +1 -0
- package/dist/layouts/panel-layouts.d.ts +8 -0
- package/dist/layouts/panel-layouts.d.ts.map +1 -0
- package/dist/layouts/panel-layouts.js +15 -0
- package/dist/layouts/panel-layouts.js.map +1 -0
- package/dist/lib/lazy.d.ts.map +1 -1
- package/dist/lib/lazy.js +2 -2
- package/dist/lib/lazy.js.map +1 -1
- package/dist/pages/PageShell.js.map +1 -1
- package/dist/pages/PageShell.vue.d.ts.map +1 -1
- package/dist/pages/PageShell.vue_vue_type_script_setup_true_lang.js +39 -42
- package/dist/pages/PageShell.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/standalone/AlfakitComponent.js.map +1 -1
- package/dist/standalone/AlfakitComponent.vue.d.ts.map +1 -1
- package/dist/standalone/AlfakitComponent.vue_vue_type_script_setup_true_lang.js +56 -52
- package/dist/standalone/AlfakitComponent.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/standalone.css +7 -0
- package/dist/starter-kit/AlfakitStarterKitRoot.js.map +1 -1
- package/dist/starter-kit/AlfakitStarterKitRoot.vue.d.ts +2 -2
- package/dist/starter-kit/AlfakitStarterKitRoot.vue.d.ts.map +1 -1
- package/dist/starter-kit/AlfakitStarterKitRoot.vue_vue_type_script_setup_true_lang.js +17 -12
- package/dist/starter-kit/AlfakitStarterKitRoot.vue_vue_type_script_setup_true_lang.js.map +1 -1
- package/dist/starter-kit/dashboard-widgets.d.ts +54 -0
- package/dist/starter-kit/dashboard-widgets.d.ts.map +1 -0
- package/dist/starter-kit/dashboard-widgets.js +54 -0
- package/dist/starter-kit/dashboard-widgets.js.map +1 -0
- package/dist/starter-kit/index.d.ts +2 -1
- package/dist/starter-kit/index.d.ts.map +1 -1
- package/dist/starter-kit/index.js +5 -4
- package/dist/starter-kit/runtime.d.ts +6 -0
- package/dist/starter-kit/runtime.d.ts.map +1 -1
- package/dist/starter-kit/runtime.js +19 -15
- package/dist/starter-kit/runtime.js.map +1 -1
- package/dist/starter-kit/starter-kit.d.ts.map +1 -1
- package/dist/starter-kit/starter-kit.js +8 -8
- package/dist/starter-kit/starter-kit.js.map +1 -1
- package/dist/starter-kit/widgets/CopilotTrigger.js +7 -0
- package/dist/starter-kit/widgets/CopilotTrigger.js.map +1 -0
- package/dist/starter-kit/widgets/CopilotTrigger.vue.d.ts +12 -0
- package/dist/starter-kit/widgets/CopilotTrigger.vue.d.ts.map +1 -0
- package/dist/starter-kit/widgets/CopilotTrigger.vue_vue_type_script_setup_true_lang.js +23 -0
- package/dist/starter-kit/widgets/CopilotTrigger.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/starter-kit/widgets/LoadedCopilot.js +7 -0
- package/dist/starter-kit/widgets/LoadedCopilot.js.map +1 -0
- package/dist/starter-kit/widgets/LoadedCopilot.vue.d.ts +8 -0
- package/dist/starter-kit/widgets/LoadedCopilot.vue.d.ts.map +1 -0
- package/dist/starter-kit/widgets/LoadedCopilot.vue_vue_type_script_setup_true_lang.js +31 -0
- package/dist/starter-kit/widgets/LoadedCopilot.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/starter-kit/widgets/StarterKitImpersonationBanner.js +7 -0
- package/dist/starter-kit/widgets/StarterKitImpersonationBanner.js.map +1 -0
- package/dist/starter-kit/widgets/StarterKitImpersonationBanner.vue.d.ts +8 -0
- package/dist/starter-kit/widgets/StarterKitImpersonationBanner.vue.d.ts.map +1 -0
- package/dist/starter-kit/widgets/StarterKitImpersonationBanner.vue_vue_type_script_setup_true_lang.js +34 -0
- package/dist/starter-kit/widgets/StarterKitImpersonationBanner.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/starter-kit/widgets/index.d.ts +40 -9
- package/dist/starter-kit/widgets/index.d.ts.map +1 -1
- package/dist/starter-kit/widgets/index.js +21 -18
- package/dist/starter-kit/widgets/index.js.map +1 -1
- package/dist/starter-kit/widgets/loaded.d.ts +10 -0
- package/dist/starter-kit/widgets/loaded.d.ts.map +1 -0
- package/dist/starter-kit/widgets/loaded.js +5 -0
- package/dist/styles.css +9 -2
- package/dist/themes.css +6 -1
- package/package.json +2 -2
- package/src/AlfakitRoot.vue +9 -1
- package/src/components/actions/ActionGroupMenu.vue +13 -1
- package/src/components/actions/ActionModal.vue +9 -0
- package/src/components/ai/AiCopilot.vue +7 -1
- package/src/components/cms/LivePreview.vue +8 -2
- package/src/components/fields/BuilderField.vue +15 -2
- package/src/components/fields/ImageEditorDialog.vue +7 -3
- package/src/components/fields/KeyValueField.vue +3 -2
- package/src/components/fields/ModalTablePicker.vue +7 -2
- package/src/components/fields/RepeaterField.vue +2 -3
- package/src/components/fields/RichEditorInput.vue +3 -0
- package/src/components/fields/item-actions.ts +31 -10
- package/src/components/form/FormBlock.vue +2 -1
- package/src/components/form/form-context.ts +2 -2
- package/src/components/kanban/KanbanBoard.vue +15 -3
- package/src/components/kanban/KanbanColumnHeader.vue +6 -4
- package/src/components/layout/SectionComponent.vue +10 -4
- package/src/components/panel/GlobalSearchPalette.vue +2 -0
- package/src/components/realtime/use-live-updates.ts +3 -1
- package/src/components/table/ColumnHeader.vue +23 -12
- package/src/components/table/ColumnManager.vue +12 -8
- package/src/components/table/ContentLayoutSort.vue +7 -1
- package/src/components/table/TableCellContent.vue +4 -2
- package/src/components/table/TablePagination.vue +12 -7
- package/src/components/table/cell-update.ts +6 -0
- package/src/components/ui/CommandAutoHighlight.vue +27 -0
- package/src/components/ui/DialogContent.vue +5 -1
- package/src/components/ui/PopoverContent.vue +5 -1
- package/src/components/ui/SheetContent.vue +5 -1
- package/src/components/ui/TooltipContent.vue +5 -1
- package/src/context.ts +10 -0
- package/src/create-alfakit.ts +5 -0
- package/src/index.ts +2 -0
- package/src/layouts/lazy-layouts.ts +14 -0
- package/src/layouts/panel-layouts.ts +17 -0
- package/src/lib/lazy.ts +11 -1
- package/src/pages/PageShell.vue +5 -6
- package/src/standalone/AlfakitComponent.vue +17 -6
- package/src/starter-kit/AlfakitStarterKitRoot.vue +12 -3
- package/src/starter-kit/dashboard-widgets.ts +93 -0
- package/src/starter-kit/index.ts +7 -1
- package/src/starter-kit/runtime.ts +17 -1
- package/src/starter-kit/starter-kit.ts +2 -1
- package/src/starter-kit/widgets/CopilotTrigger.vue +58 -0
- package/src/starter-kit/widgets/LoadedCopilot.vue +29 -0
- package/src/starter-kit/widgets/StarterKitImpersonationBanner.vue +57 -0
- package/src/starter-kit/widgets/index.ts +56 -11
- package/src/starter-kit/widgets/loaded.ts +9 -0
- package/src/styles.css +9 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BuilderField.vue_vue_type_script_setup_true_lang.js","names":["_resolveComponent","_unref","_openBlock","_createBlock","DeferredSchema","_withCtx","_createVNode","FieldWrapper","_createElementVNode","_toDisplayString","_createElementBlock","BuilderBlockPickerPanel","_createCommentVNode","CollapseAllActions","_normalizeStyle","_normalizeClass","_Fragment","_renderList","Collapsible","Icon","ItemHeaderActions","Button","BuilderBlockActionsMenu","CollapsibleContent","_withKeys","_withModifiers","_resolveDynamicComponent","SchemaRenderer","AddActionRow","BuilderBlockPicker","_createTextVNode","Icon_default","Button_default","SchemaRenderer_default","Collapsible_default","CollapsibleContent_default","DeferredSchema_default","FieldWrapper_default","AddActionRow_default","CollapseAllActions_default","ItemHeaderActions_default","BuilderBlockActionsMenu_default","BuilderBlockPickerPanel_default","BuilderBlockPicker_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","BuilderField_vue_vue_type_script_setup_true_lang_default","props","__props","t","useT","formatter","useFormatter","registry","useOptionalRegistry","form","useOptionalFormStore","context","useFieldActionContext","runItemAction","useRunItemAction","fallbacks","useItemActionFallbacks","serverItemOf","server","index","items","resolve","resolveItemAction","name","fieldDisabled","useField","locked","computed","readOnly","builderItems","value","collapsed","ref","editing","dragIndex","virtual","useVirtualList","virtualizeOptions","VIRTUAL_ESTIMATES","visibleItems","blockOf","block","type","isCollapsed","canAdd","canDelete","canClone","item","canAddBuilderBlock","draggable","buttons","addAction","showEmptyPicker","menu","runner","useActionRunner","onMenuAction","moves","cloneItem","removeItem","onMenuExtra","action","itemActionContext","update","setValue","next","moveItem","moveRepeaterItem","from","to","moveIndexedState","useItemMoves","builderItemLabel","moveAnnouncement","moveContainer","removeRepeaterItem","removeIndexedState","cloneRepeaterItem","cloneIndexedState","addBlock","insertBuilderItem","onDrop","reorderedItemKeys","setAllCollapsed","previewComponentOf","hasPreview","showPreview","toggleEditing","open","openEditor","previewIsButton","_component_BuilderField","resolveComponent","unref","isDeferredPlaceholder","openBlock","createBlock","withCtx","loaded","createVNode","id","error","createElementVNode","toDisplayString","createElementBlock","createCommentVNode","_cache","fieldIds","aria","normalizeStyle","normalizeClass","cn","Fragment","renderList","$event","PencilIcon","withKeys","withModifiers","resolveDynamicComponent","builderItemSchema","createTextVNode"],"sources":["../../../src/components/fields/BuilderField.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { BuilderBlockSchema, BuilderItemState, BuilderSchema } from '@alfakit/core'\nimport {\n isDeferredPlaceholder,\n VIRTUAL_ESTIMATES,\n builderItemLabel,\n builderItems,\n builderItemSchema,\n canAddBuilderBlock,\n cloneIndexedState,\n cloneRepeaterItem,\n fieldIds,\n insertBuilderItem,\n itemActionContext,\n moveIndexedState,\n moveRepeaterItem,\n removeIndexedState,\n removeRepeaterItem,\n reorderedItemKeys,\n resolveItemAction,\n virtualizeOptions,\n type ActionSchema,\n type ItemActionName,\n} from '@alfakit/core'\nimport { PencilIcon } from '@lucide/vue'\nimport { computed, ref } from 'vue'\nimport { useScrollToErroredItem, useVirtualList } from '../../composables/use-virtual-list'\nimport { useActionRunner, useFormatter, useOptionalRegistry, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport DeferredSchema from '../layout/DeferredSchema.vue'\nimport { useField, useOptionalFormStore } from '../form/form-context'\nimport { useFieldActionContext } from '../schema/field-actions'\nimport FieldWrapper from '../schema/FieldWrapper.vue'\nimport SchemaRenderer from '../schema/SchemaRenderer.vue'\nimport Button from '../ui/Button.vue'\nimport Collapsible from '../ui/Collapsible.vue'\nimport CollapsibleContent from '../ui/CollapsibleContent.vue'\nimport AddActionRow from './AddActionRow.vue'\nimport CollapseAllActions from './CollapseAllActions.vue'\nimport ItemHeaderActions from './ItemHeaderActions.vue'\nimport { useItemActionFallbacks, useItemMoves, useRunItemAction } from './item-actions'\nimport BuilderBlockActionsMenu from './BuilderBlockActionsMenu.vue'\nimport BuilderBlockPicker from './BuilderBlockPicker.vue'\nimport BuilderBlockPickerPanel from './BuilderBlockPickerPanel.vue'\n\n/**\n * A list of blocks, each with its own schema. Items use the server's per-item schema\n * when it describes the same block, else the block's template (fresh, moved or cloned\n * items the server has not seen yet).\n */\nconst props = defineProps<{ component: BuilderSchema }>()\nconst t = useT()\nconst formatter = useFormatter()\nconst registry = useOptionalRegistry()\nconst form = useOptionalFormStore()\nconst context = useFieldActionContext(() => props.component)\nconst runItemAction = useRunItemAction(context)\nconst fallbacks = useItemActionFallbacks()\nconst serverItemOf = (index: number) => {\n const server = props.component.items[index]\n\n return server && server.type === items.value[index]?.type ? server : undefined\n}\nconst resolve = (name: ItemActionName, index?: number) =>\n resolveItemAction(\n name,\n props.component,\n index === undefined ? undefined : serverItemOf(index),\n name === 'add' ? { ...fallbacks.add, label: props.component.addActionLabel } : fallbacks[name],\n )\n\nconst {\n value,\n setValue,\n error,\n id,\n disabled: fieldDisabled,\n readOnly,\n aria,\n} = useField<unknown>(() => props.component)\nconst locked = computed(() => fieldDisabled.value || readOnly.value)\nconst items = computed(() => builderItems(value.value))\nconst collapsed = ref<Record<number, boolean>>({})\nconst editing = ref<Record<number, boolean>>({})\nconst dragIndex = ref<number | null>(null)\n// Long lists render only the visible blocks (plus a few around them).\nconst virtual = useVirtualList(\n () => items.value.length,\n () => virtualizeOptions(props.component.virtualize, VIRTUAL_ESTIMATES.item, 12),\n)\nuseScrollToErroredItem(virtual, () => props.component.statePath)\nconst visibleItems = computed(() =>\n virtual.indexes.value.map((index) => ({ item: items.value[index] as BuilderItemState, index })),\n)\n\nconst blockOf = (type: string) => props.component.blocks.find((block) => block.name === type)\nconst isCollapsed = (index: number) => collapsed.value[index] ?? props.component.collapsed ?? false\nconst canAdd = computed(\n () =>\n props.component.addable &&\n !locked.value &&\n (props.component.maxItems == null || items.value.length < props.component.maxItems),\n)\nconst canDelete = computed(\n () =>\n props.component.deletable &&\n !locked.value &&\n (props.component.minItems == null || items.value.length > props.component.minItems),\n)\nconst canClone = (item: BuilderItemState) => {\n const block = blockOf(item.type)\n\n return Boolean(\n props.component.cloneable &&\n canAdd.value &&\n block &&\n canAddBuilderBlock(props.component, block, items.value),\n )\n}\n\nconst draggable = computed(\n () =>\n props.component.reorderable &&\n props.component.reorderableWithDragAndDrop !== false &&\n !locked.value &&\n resolve('reorder') !== null,\n)\nconst buttons = computed(\n () =>\n props.component.reorderable &&\n props.component.reorderableWithButtons !== false &&\n !locked.value,\n)\nconst addAction = computed(() => resolve('add'))\nconst showEmptyPicker = computed(\n () =>\n canAdd.value &&\n addAction.value !== null &&\n !addAction.value.disabled &&\n props.component.blocks.length > 0,\n)\nconst menu = computed(() => Boolean(props.component.blockActionsMenu) && !locked.value)\nconst runner = useActionRunner()\n// `blockActionsMenu()`: built-in actions run in the browser unless customised.\nconst onMenuAction = (name: ItemActionName, index: number) =>\n runItemAction(resolve(name, index), { item: String(index) }, () => {\n if (name === 'moveUp') moves.moveWithButton(index, index - 1)\n else if (name === 'moveDown') moves.moveWithButton(index, index + 1)\n else if (name === 'clone') cloneItem(index)\n else if (name === 'delete') removeItem(index)\n })\nconst onMenuExtra = (action: ActionSchema, index: number) =>\n void runner.trigger(action, itemActionContext(context.value, { item: String(index) }))\n\nconst update = (next: unknown[]) => setValue(next as BuilderItemState[])\nconst moveItem = (from: number, to: number) => {\n update(moveRepeaterItem(items.value, from, to))\n collapsed.value = moveIndexedState(collapsed.value, from, to)\n editing.value = moveIndexedState(editing.value, from, to)\n}\n// Move buttons: announced, one at a time, focus kept on the moved item.\nconst moves = useItemMoves(\n value,\n (from, to) => moveItem(from, to),\n (index) => builderItemLabel(props.component, items.value, index),\n () => items.value.length,\n)\nconst moveAnnouncement = moves.announcement\nconst moveContainer = moves.container\nconst removeItem = (index: number) => {\n update(removeRepeaterItem(items.value, index))\n collapsed.value = removeIndexedState(collapsed.value, index)\n editing.value = removeIndexedState(editing.value, index)\n}\nconst cloneItem = (index: number) => {\n update(cloneRepeaterItem(items.value, index))\n collapsed.value = cloneIndexedState(collapsed.value, index)\n editing.value = cloneIndexedState(editing.value, index)\n}\nconst addBlock = (block: BuilderBlockSchema) =>\n runItemAction(addAction.value, { block: block.name }, () =>\n update(insertBuilderItem(items.value, block)),\n )\n// A drop runs the reorder action: in the browser, or on the server when customised.\nconst onDrop = (index: number) => {\n const from = dragIndex.value\n dragIndex.value = null\n if (from === null || from === index) return\n runItemAction(\n resolve('reorder'),\n { items: reorderedItemKeys(items.value.length, from, index) },\n () => moveItem(from, index),\n )\n}\nconst setAllCollapsed = (value: boolean) => {\n collapsed.value = Object.fromEntries(items.value.map((_, index) => [index, value]))\n}\n\n// Previews (`blockPreviews()`): server HTML or a registered `builder-preview:{name}`.\nconst previewComponentOf = (index: number) => {\n const name =\n serverItemOf(index)?.previewComponent ??\n blockOf(items.value[index]?.type ?? '')?.previewComponent\n\n return name ? registry?.resolve(`builder-preview:${name}`) : undefined\n}\nconst hasPreview = (index: number) =>\n props.component.blockPreviews === true &&\n (previewComponentOf(index) !== undefined || Boolean(serverItemOf(index)?.preview))\nconst showPreview = (index: number) => hasPreview(index) && !editing.value[index]\n// Closing the editor re-renders the previews from the server.\nconst toggleEditing = (index: number) => {\n const open = !editing.value[index]\n editing.value = { ...editing.value, [index]: open }\n if (!open) void form?.refresh(props.component.statePath)\n}\nconst openEditor = (index: number) => {\n if (!locked.value) toggleEditing(index)\n}\nconst previewIsButton = computed(() => !props.component.interactivePreviews && !locked.value)\n</script>\n\n<template>\n <!-- `deferLoading()`: a skeleton until the field scrolls into view. -->\n <DeferredSchema\n v-if=\"isDeferredPlaceholder(props.component)\"\n v-slot=\"{ component: loaded }\"\n :component=\"props.component\"\n >\n <BuilderField :component=\"loaded\" />\n </DeferredSchema>\n <FieldWrapper v-else :field=\"props.component\" :html-for=\"id\" :error=\"error\">\n <div ref=\"moveContainer\" class=\"flex flex-col gap-3\" data-slot=\"builder\">\n <span aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\" data-slot=\"item-move-status\">{{\n moveAnnouncement\n }}</span>\n <!-- No blocks yet: the picker is right there instead of behind a button. -->\n <div\n v-if=\"items.length === 0 && showEmptyPicker\"\n data-slot=\"builder-empty\"\n class=\"bg-muted/30 flex flex-col gap-3 rounded-lg border border-dashed p-3 sm:p-4\"\n >\n <div class=\"px-1\">\n <p class=\"text-sm font-medium\">\n {{ t('builder.empty_heading', {}, 'Add your first block') }}\n </p>\n <p class=\"text-muted-foreground text-sm\">\n {{\n t(\n 'builder.empty_description',\n {},\n 'Pick one to start. You can add more, reorder and remove them at any time.',\n )\n }}\n </p>\n </div>\n <BuilderBlockPickerPanel\n :component=\"props.component\"\n :items=\"items\"\n class=\"bg-card max-h-[28rem] rounded-md border\"\n @pick=\"addBlock\"\n />\n </div>\n <p\n v-else-if=\"items.length === 0\"\n class=\"text-muted-foreground rounded-lg border border-dashed p-4 text-center text-sm\"\n >\n {{ t('builder.empty', {}, 'No blocks yet.') }}\n </p>\n <CollapseAllActions\n v-if=\"props.component.collapsible && items.length > 0\"\n :context=\"context\"\n :collapse-all=\"resolve('collapseAll')\"\n :expand-all=\"resolve('expandAll')\"\n @collapse-all=\"setAllCollapsed(true)\"\n @expand-all=\"setAllCollapsed(false)\"\n />\n <ul\n :id=\"id\"\n :ref=\"virtual.attach\"\n :aria-labelledby=\"props.component.label ? fieldIds(id).label : undefined\"\n :aria-describedby=\"aria['aria-describedby']\"\n :style=\"virtual.style.value\"\n :class=\"cn('grid gap-3', items.length === 0 && 'hidden')\"\n >\n <li\n v-for=\"{ item, index } in visibleItems\"\n :key=\"index\"\n :ref=\"virtual.item\"\n :data-index=\"index\"\n :aria-setsize=\"virtual.range.value.active ? items.length : undefined\"\n :aria-posinset=\"virtual.range.value.active ? index + 1 : undefined\"\n :data-block=\"item.type\"\n :draggable=\"draggable\"\n :class=\"\n cn('bg-card min-w-0 rounded-lg border shadow-xs', dragIndex === index && 'opacity-50')\n \"\n @dragstart=\"dragIndex = index\"\n @dragover=\"draggable && $event.preventDefault()\"\n @drop=\"onDrop(index)\"\n @dragend=\"dragIndex = null\"\n >\n <Collapsible :open=\"!isCollapsed(index)\">\n <div\n class=\"flex flex-wrap items-center gap-1 border-b px-2 py-1.5\"\n data-slot=\"item-header\"\n >\n <span\n v-if=\"draggable\"\n class=\"text-muted-foreground cursor-grab\"\n :title=\"resolve('reorder')?.label ?? undefined\"\n aria-hidden=\"true\"\n ><Icon :name=\"resolve('reorder')?.icon ?? 'grip-vertical'\"\n /></span>\n <Icon\n v-if=\"\n props.component.blockIcons &&\n (blockOf(item.type)?.icon ?? props.component.items[index]?.icon)\n \"\n :name=\"blockOf(item.type)?.icon ?? props.component.items[index]?.icon\"\n class=\"text-muted-foreground size-4\"\n />\n <span\n v-if=\"props.component.blockNumbers\"\n class=\"text-muted-foreground text-xs tabular-nums\"\n >{{ formatter.number(index + 1) }}</span\n >\n <span class=\"flex min-w-0 flex-1 items-baseline gap-2\">\n <span\n v-if=\"props.component.blockLabels\"\n dir=\"auto\"\n class=\"min-w-0 shrink-0 truncate text-sm font-medium sm:max-w-[60%]\"\n >{{ builderItemLabel(props.component, items, index) }}</span\n >\n <span\n v-if=\"serverItemOf(index)?.summary\"\n dir=\"auto\"\n class=\"text-muted-foreground min-w-0 truncate text-sm\"\n data-slot=\"builder-item-summary\"\n >{{ serverItemOf(index)?.summary }}</span\n >\n </span>\n <ItemHeaderActions\n :context=\"context\"\n :item-key=\"String(index)\"\n :index=\"index\"\n :count=\"items.length\"\n :resolve=\"(name: ItemActionName) => resolve(name, index)\"\n :extra-actions=\"menu || locked ? undefined : serverItemOf(index)?.actions\"\n :buttons=\"buttons && !menu\"\n :can-clone=\"canClone(item) && !menu\"\n :can-delete=\"canDelete && !menu\"\n :collapsible=\"Boolean(props.component.collapsible)\"\n :collapsed=\"isCollapsed(index)\"\n @move=\"moves.moveWithButton\"\n @clone=\"cloneItem(index)\"\n @delete=\"removeItem(index)\"\n @toggle=\"collapsed = { ...collapsed, [index]: !isCollapsed(index) }\"\n >\n <Button\n v-if=\"hasPreview(index) && !locked\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :aria-label=\"t('builder.edit_block', {}, 'Edit block')\"\n :aria-pressed=\"Boolean(editing[index])\"\n @click=\"toggleEditing(index)\"\n ><Icon\n name=\"alfakit::forms.components.builder.actions.edit\"\n :fallback=\"PencilIcon\"\n /></Button>\n <BuilderBlockActionsMenu\n v-if=\"menu\"\n :label=\"builderItemLabel(props.component, items, index) ?? ''\"\n :resolve=\"(name: ItemActionName) => resolve(name, index)\"\n :can-move-up=\"buttons && index > 0\"\n :can-move-down=\"buttons && index < items.length - 1\"\n :can-clone=\"canClone(item)\"\n :can-delete=\"canDelete\"\n :extra-actions=\"serverItemOf(index)?.actions\"\n @action=\"(name: ItemActionName) => onMenuAction(name, index)\"\n @extra=\"(action: ActionSchema) => onMenuExtra(action, index)\"\n />\n </ItemHeaderActions>\n </div>\n <CollapsibleContent>\n <div\n v-if=\"showPreview(index)\"\n data-slot=\"builder-preview\"\n :class=\"cn('p-4', previewIsButton && 'cursor-pointer')\"\n :role=\"previewIsButton ? 'button' : undefined\"\n :tabindex=\"previewIsButton ? 0 : undefined\"\n :aria-label=\"\n previewIsButton ? t('builder.edit_block', {}, 'Edit block') : undefined\n \"\n @click=\"previewIsButton && openEditor(index)\"\n @keydown.enter.prevent=\"previewIsButton && openEditor(index)\"\n @keydown.space.prevent=\"previewIsButton && openEditor(index)\"\n >\n <div :class=\"cn(!props.component.interactivePreviews && 'pointer-events-none')\">\n <component\n :is=\"previewComponentOf(index)\"\n v-if=\"previewComponentOf(index)\"\n :data=\"item.data\"\n :block=\"item.type\"\n :index=\"index\"\n />\n <!-- Server-rendered `Block::preview()` HTML (Blade escapes the data). -->\n <!-- eslint-disable-next-line vue/no-v-html -->\n <div v-else v-html=\"serverItemOf(index)?.preview ?? ''\" />\n </div>\n </div>\n <div v-else class=\"p-4\">\n <SchemaRenderer\n :components=\"builderItemSchema(props.component, items, index)\"\n :columns=\"\n blockOf(item.type)?.columns ??\n props.component.items[index]?.columns ?? { default: 1 }\n \"\n />\n </div>\n </CollapsibleContent>\n </Collapsible>\n </li>\n </ul>\n <AddActionRow\n v-if=\"canAdd && addAction && props.component.blocks.length > 0 && items.length > 0\"\n :alignment=\"props.component.addActionAlignment\"\n >\n <BuilderBlockPicker :component=\"props.component\" :items=\"items\" @pick=\"addBlock\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n :disabled=\"addAction?.disabled\"\n data-slot=\"builder-add\"\n ><Icon v-if=\"addAction?.icon\" :name=\"addAction.icon\" /> {{ addAction?.label }}</Button\n >\n </BuilderBlockPicker>\n </AddActionRow>\n </div>\n </FieldWrapper>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BuilderField.vue_vue_type_script_setup_true_lang.js","names":["_resolveComponent","_unref","_openBlock","_createBlock","DeferredSchema","_withCtx","_createVNode","FieldWrapper","_createElementVNode","_toDisplayString","_createElementBlock","BuilderBlockPickerPanel","_createCommentVNode","CollapseAllActions","_normalizeStyle","_normalizeClass","_Fragment","_renderList","Collapsible","Icon","ItemHeaderActions","Button","BuilderBlockActionsMenu","CollapsibleContent","_withKeys","_withModifiers","_resolveDynamicComponent","SchemaRenderer","AddActionRow","BuilderBlockPicker","_createTextVNode","Icon_default","Button_default","SchemaRenderer_default","DeferredSchema_default","FieldWrapper_default","Collapsible_default","CollapsibleContent_default","AddActionRow_default","CollapseAllActions_default","ItemHeaderActions_default","BuilderBlockActionsMenu_default","BuilderBlockPickerPanel_default","BuilderBlockPicker_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_16","_hoisted_17","BuilderField_vue_vue_type_script_setup_true_lang_default","props","__props","t","useT","formatter","useFormatter","registry","useOptionalRegistry","form","useOptionalFormStore","context","useFieldActionContext","runItemAction","useRunItemAction","fallbacks","useItemActionFallbacks","serverItemOf","server","index","items","resolve","resolveItemAction","name","fieldDisabled","useField","locked","computed","readOnly","builderItems","value","collapsed","ref","editing","dragIndex","virtual","useVirtualList","virtualizeOptions","VIRTUAL_ESTIMATES","visibleItems","blockOf","block","type","isCollapsed","canAdd","canDelete","canClone","item","canAddBuilderBlock","draggable","buttons","addAction","showEmptyPicker","menu","runner","useActionRunner","onMenuAction","moves","cloneItem","removeItem","onMenuExtra","action","itemActionContext","update","setValue","next","moveItem","moveRepeaterItem","from","to","moveIndexedState","useItemMoves","builderItemLabel","moveAnnouncement","moveContainer","removeRepeaterItem","removeIndexedState","cloneRepeaterItem","cloneIndexedState","addBlock","insertBuilderItem","onDrop","reorderedItemKeys","setAllCollapsed","refreshSummaries","indexes","toggleCollapsed","collapse","previewComponentOf","hasPreview","showPreview","toggleEditing","open","openEditor","previewIsButton","_component_BuilderField","resolveComponent","unref","isDeferredPlaceholder","openBlock","createBlock","withCtx","loaded","createVNode","id","error","createElementVNode","toDisplayString","createElementBlock","createCommentVNode","_cache","fieldIds","aria","normalizeStyle","normalizeClass","cn","Fragment","renderList","$event","PencilIcon","withKeys","withModifiers","resolveDynamicComponent","builderItemSchema","createTextVNode"],"sources":["../../../src/components/fields/BuilderField.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { BuilderBlockSchema, BuilderItemState, BuilderSchema } from '@alfakit/core'\nimport {\n isDeferredPlaceholder,\n VIRTUAL_ESTIMATES,\n builderItemLabel,\n builderItems,\n builderItemSchema,\n canAddBuilderBlock,\n cloneIndexedState,\n cloneRepeaterItem,\n fieldIds,\n insertBuilderItem,\n itemActionContext,\n moveIndexedState,\n moveRepeaterItem,\n removeIndexedState,\n removeRepeaterItem,\n reorderedItemKeys,\n resolveItemAction,\n virtualizeOptions,\n type ActionSchema,\n type ItemActionName,\n} from '@alfakit/core'\nimport { PencilIcon } from '@lucide/vue'\nimport { computed, ref } from 'vue'\nimport { useScrollToErroredItem, useVirtualList } from '../../composables/use-virtual-list'\nimport { useActionRunner, useFormatter, useOptionalRegistry, useT } from '../../context'\nimport { Icon } from '../../lib/icons'\nimport { cn } from '../../lib/utils'\nimport DeferredSchema from '../layout/DeferredSchema.vue'\nimport { useField, useOptionalFormStore } from '../form/form-context'\nimport { useFieldActionContext } from '../schema/field-actions'\nimport FieldWrapper from '../schema/FieldWrapper.vue'\nimport SchemaRenderer from '../schema/SchemaRenderer.vue'\nimport Button from '../ui/Button.vue'\nimport Collapsible from '../ui/Collapsible.vue'\nimport CollapsibleContent from '../ui/CollapsibleContent.vue'\nimport AddActionRow from './AddActionRow.vue'\nimport CollapseAllActions from './CollapseAllActions.vue'\nimport ItemHeaderActions from './ItemHeaderActions.vue'\nimport { useItemActionFallbacks, useItemMoves, useRunItemAction } from './item-actions'\nimport BuilderBlockActionsMenu from './BuilderBlockActionsMenu.vue'\nimport BuilderBlockPicker from './BuilderBlockPicker.vue'\nimport BuilderBlockPickerPanel from './BuilderBlockPickerPanel.vue'\n\n/**\n * A list of blocks, each with its own schema. Items use the server's per-item schema\n * when it describes the same block, else the block's template (fresh, moved or cloned\n * items the server has not seen yet).\n */\nconst props = defineProps<{ component: BuilderSchema }>()\nconst t = useT()\nconst formatter = useFormatter()\nconst registry = useOptionalRegistry()\nconst form = useOptionalFormStore()\nconst context = useFieldActionContext(() => props.component)\nconst runItemAction = useRunItemAction(context)\nconst fallbacks = useItemActionFallbacks('builder')\nconst serverItemOf = (index: number) => {\n const server = props.component.items[index]\n\n return server && server.type === items.value[index]?.type ? server : undefined\n}\nconst resolve = (name: ItemActionName, index?: number) =>\n resolveItemAction(\n name,\n props.component,\n index === undefined ? undefined : serverItemOf(index),\n name === 'add' ? { ...fallbacks.add, label: props.component.addActionLabel } : fallbacks[name],\n )\n\nconst {\n value,\n setValue,\n error,\n id,\n disabled: fieldDisabled,\n readOnly,\n aria,\n} = useField<unknown>(() => props.component)\nconst locked = computed(() => fieldDisabled.value || readOnly.value)\nconst items = computed(() => builderItems(value.value))\nconst collapsed = ref<Record<number, boolean>>({})\nconst editing = ref<Record<number, boolean>>({})\nconst dragIndex = ref<number | null>(null)\n// Long lists render only the visible blocks (plus a few around them).\nconst virtual = useVirtualList(\n () => items.value.length,\n () => virtualizeOptions(props.component.virtualize, VIRTUAL_ESTIMATES.item, 12),\n)\nuseScrollToErroredItem(virtual, () => props.component.statePath)\nconst visibleItems = computed(() =>\n virtual.indexes.value.map((index) => ({ item: items.value[index] as BuilderItemState, index })),\n)\n\nconst blockOf = (type: string) => props.component.blocks.find((block) => block.name === type)\nconst isCollapsed = (index: number) => collapsed.value[index] ?? props.component.collapsed ?? false\nconst canAdd = computed(\n () =>\n props.component.addable &&\n !locked.value &&\n (props.component.maxItems == null || items.value.length < props.component.maxItems),\n)\nconst canDelete = computed(\n () =>\n props.component.deletable &&\n !locked.value &&\n (props.component.minItems == null || items.value.length > props.component.minItems),\n)\nconst canClone = (item: BuilderItemState) => {\n const block = blockOf(item.type)\n\n return Boolean(\n props.component.cloneable &&\n canAdd.value &&\n block &&\n canAddBuilderBlock(props.component, block, items.value),\n )\n}\n\nconst draggable = computed(\n () =>\n props.component.reorderable &&\n props.component.reorderableWithDragAndDrop !== false &&\n !locked.value &&\n resolve('reorder') !== null,\n)\nconst buttons = computed(\n () =>\n props.component.reorderable &&\n props.component.reorderableWithButtons !== false &&\n !locked.value,\n)\nconst addAction = computed(() => resolve('add'))\nconst showEmptyPicker = computed(\n () =>\n canAdd.value &&\n addAction.value !== null &&\n !addAction.value.disabled &&\n props.component.blocks.length > 0,\n)\nconst menu = computed(() => Boolean(props.component.blockActionsMenu) && !locked.value)\nconst runner = useActionRunner()\n// `blockActionsMenu()`: built-in actions run in the browser unless customised.\nconst onMenuAction = (name: ItemActionName, index: number) =>\n runItemAction(resolve(name, index), { item: String(index) }, () => {\n if (name === 'moveUp') moves.moveWithButton(index, index - 1)\n else if (name === 'moveDown') moves.moveWithButton(index, index + 1)\n else if (name === 'clone') cloneItem(index)\n else if (name === 'delete') removeItem(index)\n })\nconst onMenuExtra = (action: ActionSchema, index: number) =>\n void runner.trigger(action, itemActionContext(context.value, { item: String(index) }))\n\nconst update = (next: unknown[]) => setValue(next as BuilderItemState[])\nconst moveItem = (from: number, to: number) => {\n update(moveRepeaterItem(items.value, from, to))\n collapsed.value = moveIndexedState(collapsed.value, from, to)\n editing.value = moveIndexedState(editing.value, from, to)\n}\n// Move buttons: announced, one at a time, focus kept on the moved item.\nconst moves = useItemMoves(\n value,\n (from, to) => moveItem(from, to),\n (index) => builderItemLabel(props.component, items.value, index),\n () => items.value.length,\n)\nconst moveAnnouncement = moves.announcement\nconst moveContainer = moves.container\nconst removeItem = (index: number) => {\n update(removeRepeaterItem(items.value, index))\n collapsed.value = removeIndexedState(collapsed.value, index)\n editing.value = removeIndexedState(editing.value, index)\n}\nconst cloneItem = (index: number) => {\n update(cloneRepeaterItem(items.value, index))\n collapsed.value = cloneIndexedState(collapsed.value, index)\n editing.value = cloneIndexedState(editing.value, index)\n}\nconst addBlock = (block: BuilderBlockSchema) =>\n runItemAction(addAction.value, { block: block.name }, () =>\n update(insertBuilderItem(items.value, block)),\n )\n// A drop runs the reorder action: in the browser, or on the server when customised.\nconst onDrop = (index: number) => {\n const from = dragIndex.value\n dragIndex.value = null\n if (from === null || from === index) return\n runItemAction(\n resolve('reorder'),\n { items: reorderedItemKeys(items.value.length, from, index) },\n () => moveItem(from, index),\n )\n}\nconst setAllCollapsed = (value: boolean) => {\n collapsed.value = Object.fromEntries(items.value.map((_, index) => [index, value]))\n if (value) refreshSummaries(items.value.map((_, index) => index))\n}\n// Summaries are made on the server: collapsing items whose block has one brings them up\n// to date with the edits.\nconst refreshSummaries = (indexes: number[]) => {\n if (indexes.some((index) => blockOf(items.value[index]?.type ?? '')?.summary)) {\n void form?.refresh(props.component.statePath)\n }\n}\nconst toggleCollapsed = (index: number) => {\n const collapse = !isCollapsed(index)\n collapsed.value = { ...collapsed.value, [index]: collapse }\n if (collapse) refreshSummaries([index])\n}\n\n// Previews (`blockPreviews()`): server HTML or a registered `builder-preview:{name}`.\nconst previewComponentOf = (index: number) => {\n const name =\n serverItemOf(index)?.previewComponent ??\n blockOf(items.value[index]?.type ?? '')?.previewComponent\n\n return name ? registry?.resolve(`builder-preview:${name}`) : undefined\n}\nconst hasPreview = (index: number) =>\n props.component.blockPreviews === true &&\n (previewComponentOf(index) !== undefined || Boolean(serverItemOf(index)?.preview))\nconst showPreview = (index: number) => hasPreview(index) && !editing.value[index]\n// Closing the editor re-renders the previews from the server.\nconst toggleEditing = (index: number) => {\n const open = !editing.value[index]\n editing.value = { ...editing.value, [index]: open }\n if (!open) void form?.refresh(props.component.statePath)\n}\nconst openEditor = (index: number) => {\n if (!locked.value) toggleEditing(index)\n}\nconst previewIsButton = computed(() => !props.component.interactivePreviews && !locked.value)\n</script>\n\n<template>\n <!-- `deferLoading()`: a skeleton until the field scrolls into view. -->\n <DeferredSchema\n v-if=\"isDeferredPlaceholder(props.component)\"\n v-slot=\"{ component: loaded }\"\n :component=\"props.component\"\n >\n <BuilderField :component=\"loaded\" />\n </DeferredSchema>\n <FieldWrapper v-else :field=\"props.component\" :html-for=\"id\" :error=\"error\">\n <div ref=\"moveContainer\" class=\"flex flex-col gap-3\" data-slot=\"builder\">\n <span aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\" data-slot=\"item-move-status\">{{\n moveAnnouncement\n }}</span>\n <!-- No blocks yet: the picker is right there instead of behind a button. -->\n <div\n v-if=\"items.length === 0 && showEmptyPicker\"\n data-slot=\"builder-empty\"\n class=\"bg-muted/30 flex flex-col gap-3 rounded-lg border border-dashed p-3 sm:p-4\"\n >\n <div class=\"px-1\">\n <p class=\"text-sm font-medium\">\n {{ t('builder.empty_heading', {}, 'Add your first block') }}\n </p>\n <p class=\"text-muted-foreground text-sm\">\n {{\n t(\n 'builder.empty_description',\n {},\n 'Pick one to start. You can add more, reorder and remove them at any time.',\n )\n }}\n </p>\n </div>\n <BuilderBlockPickerPanel\n :component=\"props.component\"\n :items=\"items\"\n class=\"bg-card max-h-[28rem] rounded-md border\"\n @pick=\"addBlock\"\n />\n </div>\n <p\n v-else-if=\"items.length === 0\"\n class=\"text-muted-foreground rounded-lg border border-dashed p-4 text-center text-sm\"\n >\n {{ t('builder.empty', {}, 'No blocks yet.') }}\n </p>\n <CollapseAllActions\n v-if=\"props.component.collapsible && items.length > 0\"\n :context=\"context\"\n :collapse-all=\"resolve('collapseAll')\"\n :expand-all=\"resolve('expandAll')\"\n @collapse-all=\"setAllCollapsed(true)\"\n @expand-all=\"setAllCollapsed(false)\"\n />\n <ul\n :id=\"id\"\n :ref=\"virtual.attach\"\n :aria-labelledby=\"props.component.label ? fieldIds(id).label : undefined\"\n :aria-describedby=\"aria['aria-describedby']\"\n :style=\"virtual.style.value\"\n :class=\"cn('grid gap-3', items.length === 0 && 'hidden')\"\n >\n <li\n v-for=\"{ item, index } in visibleItems\"\n :key=\"index\"\n :ref=\"virtual.item\"\n :data-index=\"index\"\n :aria-setsize=\"virtual.range.value.active ? items.length : undefined\"\n :aria-posinset=\"virtual.range.value.active ? index + 1 : undefined\"\n :data-block=\"item.type\"\n :draggable=\"draggable\"\n :class=\"\n cn('bg-card min-w-0 rounded-lg border shadow-xs', dragIndex === index && 'opacity-50')\n \"\n @dragstart=\"dragIndex = index\"\n @dragover=\"draggable && $event.preventDefault()\"\n @drop=\"onDrop(index)\"\n @dragend=\"dragIndex = null\"\n >\n <Collapsible :open=\"!isCollapsed(index)\">\n <div\n class=\"flex flex-wrap items-center gap-1 border-b px-2 py-1.5\"\n data-slot=\"item-header\"\n >\n <span\n v-if=\"draggable\"\n class=\"text-muted-foreground cursor-grab\"\n :title=\"resolve('reorder')?.label ?? undefined\"\n aria-hidden=\"true\"\n ><Icon :name=\"resolve('reorder')?.icon ?? 'grip-vertical'\"\n /></span>\n <Icon\n v-if=\"\n props.component.blockIcons &&\n (blockOf(item.type)?.icon ?? props.component.items[index]?.icon)\n \"\n :name=\"blockOf(item.type)?.icon ?? props.component.items[index]?.icon\"\n class=\"text-muted-foreground size-4\"\n />\n <span\n v-if=\"props.component.blockNumbers\"\n class=\"text-muted-foreground text-xs tabular-nums\"\n >{{ formatter.number(index + 1) }}</span\n >\n <span class=\"flex min-w-0 flex-1 items-baseline gap-2\">\n <span\n v-if=\"props.component.blockLabels\"\n dir=\"auto\"\n class=\"min-w-0 shrink-0 truncate text-sm font-medium sm:max-w-[60%]\"\n >{{ builderItemLabel(props.component, items, index) }}</span\n >\n <span\n v-if=\"serverItemOf(index)?.summary\"\n dir=\"auto\"\n class=\"text-muted-foreground min-w-0 truncate text-sm\"\n data-slot=\"builder-item-summary\"\n >{{ serverItemOf(index)?.summary }}</span\n >\n </span>\n <ItemHeaderActions\n :context=\"context\"\n :item-key=\"String(index)\"\n :index=\"index\"\n :count=\"items.length\"\n :resolve=\"(name: ItemActionName) => resolve(name, index)\"\n :extra-actions=\"menu || locked ? undefined : serverItemOf(index)?.actions\"\n :buttons=\"buttons && !menu\"\n :can-clone=\"canClone(item) && !menu\"\n :can-delete=\"canDelete && !menu\"\n :collapsible=\"Boolean(props.component.collapsible)\"\n :collapsed=\"isCollapsed(index)\"\n @move=\"moves.moveWithButton\"\n @clone=\"cloneItem(index)\"\n @delete=\"removeItem(index)\"\n @toggle=\"toggleCollapsed(index)\"\n >\n <Button\n v-if=\"hasPreview(index) && !locked\"\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :aria-label=\"t('builder.edit_block', {}, 'Edit block')\"\n :aria-pressed=\"Boolean(editing[index])\"\n @click=\"toggleEditing(index)\"\n ><Icon\n name=\"alfakit::forms.components.builder.actions.edit\"\n :fallback=\"PencilIcon\"\n /></Button>\n <BuilderBlockActionsMenu\n v-if=\"menu\"\n :label=\"builderItemLabel(props.component, items, index) ?? ''\"\n :resolve=\"(name: ItemActionName) => resolve(name, index)\"\n :can-move-up=\"buttons && index > 0\"\n :can-move-down=\"buttons && index < items.length - 1\"\n :can-clone=\"canClone(item)\"\n :can-delete=\"canDelete\"\n :extra-actions=\"serverItemOf(index)?.actions\"\n @action=\"(name: ItemActionName) => onMenuAction(name, index)\"\n @extra=\"(action: ActionSchema) => onMenuExtra(action, index)\"\n />\n </ItemHeaderActions>\n </div>\n <CollapsibleContent>\n <div\n v-if=\"showPreview(index)\"\n data-slot=\"builder-preview\"\n :class=\"cn('p-4', previewIsButton && 'cursor-pointer')\"\n :role=\"previewIsButton ? 'button' : undefined\"\n :tabindex=\"previewIsButton ? 0 : undefined\"\n :aria-label=\"\n previewIsButton ? t('builder.edit_block', {}, 'Edit block') : undefined\n \"\n @click=\"previewIsButton && openEditor(index)\"\n @keydown.enter.prevent=\"previewIsButton && openEditor(index)\"\n @keydown.space.prevent=\"previewIsButton && openEditor(index)\"\n >\n <div :class=\"cn(!props.component.interactivePreviews && 'pointer-events-none')\">\n <component\n :is=\"previewComponentOf(index)\"\n v-if=\"previewComponentOf(index)\"\n :data=\"item.data\"\n :block=\"item.type\"\n :index=\"index\"\n />\n <!-- Server-rendered `Block::preview()` HTML (Blade escapes the data). -->\n <!-- eslint-disable-next-line vue/no-v-html -->\n <div v-else v-html=\"serverItemOf(index)?.preview ?? ''\" />\n </div>\n </div>\n <div v-else class=\"p-4\">\n <SchemaRenderer\n :components=\"builderItemSchema(props.component, items, index)\"\n :columns=\"\n blockOf(item.type)?.columns ??\n props.component.items[index]?.columns ?? { default: 1 }\n \"\n />\n </div>\n </CollapsibleContent>\n </Collapsible>\n </li>\n </ul>\n <AddActionRow\n v-if=\"canAdd && addAction && props.component.blocks.length > 0 && items.length > 0\"\n :alignment=\"props.component.addActionAlignment\"\n >\n <BuilderBlockPicker :component=\"props.component\" :items=\"items\" @pick=\"addBlock\">\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n :disabled=\"addAction?.disabled\"\n data-slot=\"builder-add\"\n ><Icon v-if=\"addAction?.icon\" :name=\"addAction.icon\" /> {{ addAction?.label }}</Button\n >\n </BuilderBlockPicker>\n </AddActionRow>\n </div>\n </FieldWrapper>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageEditorDialog.js","names":["_sfc_main","ImageEditorDialog_vue_vue_type_script_setup_true_lang_default","ImageEditorDialog_default"],"sources":["../../../src/components/fields/ImageEditorDialog.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * `FileUpload::imageEditor()`: crop, zoom, rotate and flip an image before it is uploaded\n * (or to replace an uploaded one). Resolves the request with the edited file, or null\n * when cancelled.\n */\nimport type {\n CropHandle,\n FileUploadImageEditorSchema,\n ImageEditorData,\n ImageEditorDragMode,\n ImageEditorState,\n} from '@alfakit/core'\nimport { ImageEditor, loadEditorImage } from '@alfakit/core'\nimport {\n FlipHorizontal2Icon,\n FlipVertical2Icon,\n RotateCcwIcon,\n RotateCwIcon,\n Undo2Icon,\n ZoomInIcon,\n ZoomOutIcon,\n} from '@lucide/vue'\nimport { computed, onScopeDispose, ref, shallowRef, useId, watch, type Component } from 'vue'\nimport { useT } from '../../context'\nimport { cn } from '../../lib/utils'\nimport Button from '../ui/Button.vue'\nimport Dialog from '../ui/Dialog.vue'\nimport DialogContent from '../ui/DialogContent.vue'\nimport DialogDescription from '../ui/DialogDescription.vue'\nimport DialogFooter from '../ui/DialogFooter.vue'\nimport DialogHeader from '../ui/DialogHeader.vue'\nimport DialogTitle from '../ui/DialogTitle.vue'\nimport Input from '../ui/Input.vue'\nimport Spinner from '../ui/Spinner.vue'\n\nexport interface ImageEditRequest {\n file: File\n resolve: (file: File | null) => void\n}\n\nconst HANDLES: CropHandle[] = ['nw', 'ne', 'sw', 'se']\n\n/** The numeric inputs, in the order Filament shows them. */\nconst NUMERIC_FIELDS = [\n ['x', 'image_editor.x', 'X'],\n ['y', 'image_editor.y', 'Y'],\n ['width', 'image_editor.width', 'Width'],\n ['height', 'image_editor.height', 'Height'],\n ['rotate', 'image_editor.rotation', 'Rotation'],\n] as const satisfies ReadonlyArray<readonly [keyof ImageEditorData, string, string]>\n\nconst SCALES = [\n ['x', 'image_editor.scale_x', 'Scale X'],\n ['y', 'image_editor.scale_y', 'Scale Y'],\n] as const\n\nconst props = defineProps<{\n request: ImageEditRequest | null\n options: FileUploadImageEditorSchema\n}>()\n\nconst t = useT()\nconst loaded = shallowRef<{ bitmap: ImageBitmap; editor: ImageEditor } | null>(null)\nconst state = shallowRef<ImageEditorState | null>(null)\nconst saving = ref(false)\nconst hintId = useId()\nconst inputsId = useId()\nconst canvas = ref<HTMLCanvasElement | null>(null)\nconst frame = ref<HTMLDivElement | null>(null)\nlet unsubscribe: (() => void) | null = null\nlet stopObserving: (() => void) | null = null\n\nconst release = () => {\n unsubscribe?.()\n unsubscribe = null\n stopObserving?.()\n stopObserving = null\n loaded.value?.bitmap.close()\n loaded.value = null\n state.value = null\n}\n\nwatch(\n () => [props.request, props.options] as const,\n ([request, options], _previous, onCleanup) => {\n if (!request) return\n\n let cancelled = false\n\n loadEditorImage(request.file)\n .then((bitmap) => {\n if (cancelled) return bitmap.close()\n\n const editor = new ImageEditor({\n width: bitmap.width,\n height: bitmap.height,\n aspectRatios: options.aspectRatios,\n circle: options.circle,\n mode: options.mode,\n emptyFillColor: options.emptyFillColor,\n viewportWidth: options.viewportWidth,\n viewportHeight: options.viewportHeight,\n })\n\n loaded.value = { bitmap, editor }\n state.value = editor.store.get()\n unsubscribe = editor.store.subscribe((next) => {\n state.value = next\n })\n })\n // Undecodable: upload the file as it is.\n .catch(() => !cancelled && request.resolve(request.file))\n\n onCleanup(() => {\n cancelled = true\n release()\n })\n },\n { immediate: true },\n)\n\nonScopeDispose(release)\n\n// Redraw on every change (crop, zoom, rotation, flips, container size).\nwatch(\n () => [canvas.value, state.value] as const,\n ([element]) => {\n if (element && loaded.value) {\n loaded.value.editor.drawPreview(\n element,\n loaded.value.bitmap,\n globalThis.devicePixelRatio || 1,\n )\n }\n },\n { flush: 'post' },\n)\n\n// Measure the container and follow its size; zoom with the wheel and trackpad pinch.\nwatch(\n () => [frame.value, loaded.value?.editor] as const,\n ([element, editor]) => {\n stopObserving?.()\n stopObserving = null\n\n if (!element || !editor) return\n\n const measure = () => editor.setContainer(element.clientWidth, element.clientHeight)\n measure()\n\n const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(measure)\n observer?.observe(element)\n\n const onWheel = (event: WheelEvent) => {\n const rect = element.getBoundingClientRect()\n\n if (editor.wheel(event, { x: event.clientX - rect.left, y: event.clientY - rect.top })) {\n event.preventDefault()\n }\n }\n\n element.addEventListener('wheel', onWheel, { passive: false })\n\n stopObserving = () => {\n observer?.disconnect()\n element.removeEventListener('wheel', onWheel)\n }\n },\n { flush: 'post' },\n)\n\nconst data = computed<ImageEditorData | null>(() => {\n void state.value\n\n return loaded.value?.editor.getData() ?? null\n})\n\n// Numeric inputs apply on change (blur, Enter, spinner); invalid values snap back.\nconst commit = (field: keyof ImageEditorData, event: Event) => {\n const editor = loaded.value?.editor\n const input = event.target as HTMLInputElement | null\n\n if (!editor || !input) return\n\n const value = input.value.trim() === '' ? Number.NaN : Number(input.value)\n editor.setData({ [field]: value })\n input.value = String(editor.getData()[field])\n}\n\nconst box = computed(() => {\n void state.value\n\n return loaded.value?.editor.cropBox() ?? { left: 0, top: 0, width: 0, height: 0 }\n})\n\nconst finish = (file: File | null) => {\n props.request?.resolve(file)\n}\n\nconst save = async () => {\n const request = props.request\n const current = loaded.value\n\n if (!request || !current) return\n\n saving.value = true\n\n try {\n finish(await current.editor.export(current.bitmap, request.file))\n } catch {\n finish(request.file)\n } finally {\n saving.value = false\n }\n}\n\nconst start = (mode: ImageEditorDragMode, event: PointerEvent) => {\n const editor = loaded.value?.editor\n\n if (!editor) return\n\n event.preventDefault()\n event.stopPropagation()\n ;(event.currentTarget as HTMLElement | null)?.setPointerCapture?.(event.pointerId)\n editor.startDrag(mode, event.clientX, event.clientY, undefined, event.pointerId ?? 0)\n}\n\nconst onKeydown = (event: KeyboardEvent) => {\n if (loaded.value?.editor.handleKey(event)) event.preventDefault()\n}\n\nconst ratioLabel = (ratio: string | null) => ratio ?? t('image_editor.free', {}, 'Free')\n\nconst tools = computed<\n Array<{ label: string; icon: Component; run: () => void; disabled?: boolean }>\n>(() => [\n {\n label: t('image_editor.zoom_out', {}, 'Zoom out'),\n icon: ZoomOutIcon,\n run: () => loaded.value?.editor.zoomOut(),\n disabled: !(state.value && loaded.value?.editor.canZoomOut),\n },\n {\n label: t('image_editor.zoom_in', {}, 'Zoom in'),\n icon: ZoomInIcon,\n run: () => loaded.value?.editor.zoomIn(),\n disabled: !(state.value && loaded.value?.editor.canZoomIn),\n },\n {\n label: t('image_editor.rotate_left', {}, 'Rotate left'),\n icon: RotateCcwIcon,\n run: () => loaded.value?.editor.rotate(-1),\n },\n {\n label: t('image_editor.rotate_right', {}, 'Rotate right'),\n icon: RotateCwIcon,\n run: () => loaded.value?.editor.rotate(1),\n },\n {\n label: t('image_editor.flip_horizontal', {}, 'Flip horizontally'),\n icon: FlipHorizontal2Icon,\n run: () => loaded.value?.editor.flip('x'),\n },\n {\n label: t('image_editor.flip_vertical', {}, 'Flip vertically'),\n icon: FlipVertical2Icon,\n run: () => loaded.value?.editor.flip('y'),\n },\n {\n label: t('image_editor.reset', {}, 'Reset'),\n icon: Undo2Icon,\n run: () => loaded.value?.editor.reset(),\n },\n])\n</script>\n\n<template>\n <Dialog :open=\"props.request !== null\" @update:open=\"(open) => !open && finish(null)\">\n <DialogContent class=\"sm:max-w-3xl\" data-slot=\"image-editor\">\n <DialogHeader>\n <DialogTitle>{{ t('image_editor.title', {}, 'Edit image') }}</DialogTitle>\n <DialogDescription class=\"sr-only\">\n <span :id=\"hintId\"\n >{{\n t(\n 'image_editor.keyboard_hint',\n {},\n 'Arrow keys move the crop area. Shift and arrow keys resize it.',\n )\n }}\n {{ t('image_editor.zoom_hint', {}, 'Plus and minus keys zoom the image.') }}</span\n >\n </DialogDescription>\n </DialogHeader>\n <div v-if=\"loaded && state && data\" class=\"flex flex-col gap-4 md:flex-row\">\n <div class=\"flex min-w-0 flex-1 flex-col gap-3\">\n <!-- Image space: left is the image's left in every reading direction. -->\n <div\n ref=\"frame\"\n dir=\"ltr\"\n data-slot=\"image-editor-viewport\"\n class=\"bg-muted/40 relative h-72 w-full cursor-grab touch-none overflow-hidden rounded-md select-none sm:h-96\"\n @pointerdown=\"start('pan', $event)\"\n @pointermove=\"\n loaded.editor.dragTo($event.clientX, $event.clientY, $event.pointerId ?? 0)\n \"\n @pointerup=\"loaded.editor.endDrag($event.pointerId ?? 0)\"\n @pointercancel=\"loaded.editor.endDrag($event.pointerId ?? 0)\"\n >\n <canvas ref=\"canvas\" class=\"pointer-events-none absolute inset-0 block size-full\" />\n <!-- Runtime geometry: no Tailwind class can hold these values. -->\n <div\n role=\"group\"\n tabindex=\"0\"\n :aria-label=\"t('image_editor.crop_area', {}, 'Crop area')\"\n :aria-describedby=\"hintId\"\n data-slot=\"image-editor-crop\"\n :class=\"\n cn(\n 'ring-ring/50 absolute cursor-move border-2 border-white shadow-[0_0_0_9999px_rgb(0_0_0/0.5)] outline-none focus-visible:ring-[3px]',\n loaded.editor.circle && 'rounded-full',\n )\n \"\n :style=\"{\n left: `${box.left}%`,\n top: `${box.top}%`,\n width: `${box.width}%`,\n height: `${box.height}%`,\n }\"\n @pointerdown=\"start('move', $event)\"\n @keydown=\"onKeydown\"\n >\n <span\n v-for=\"handle in HANDLES\"\n :key=\"handle\"\n :data-handle=\"handle\"\n aria-hidden=\"true\"\n class=\"absolute size-3 -translate-x-1/2 -translate-y-1/2 rounded-sm border border-black/40 bg-white\"\n :style=\"{\n left: handle.endsWith('w') ? '0%' : '100%',\n top: handle.startsWith('n') ? '0%' : '100%',\n cursor: handle === 'nw' || handle === 'se' ? 'nwse-resize' : 'nesw-resize',\n }\"\n @pointerdown=\"start(handle, $event)\"\n />\n </div>\n </div>\n <div class=\"flex flex-wrap items-center justify-between gap-2\">\n <div\n v-if=\"loaded.editor.aspectRatios.length > 1\"\n role=\"group\"\n :aria-label=\"t('image_editor.aspect_ratio', {}, 'Aspect ratio')\"\n class=\"flex flex-wrap gap-1\"\n >\n <Button\n v-for=\"ratio in loaded.editor.aspectRatios\"\n :key=\"ratio ?? 'free'\"\n type=\"button\"\n size=\"sm\"\n :variant=\"state.aspectRatio === ratio ? 'default' : 'outline'\"\n :aria-pressed=\"String(state.aspectRatio === ratio)\"\n @click=\"loaded.editor.setAspectRatio(ratio)\"\n >\n {{ ratioLabel(ratio) }}\n </Button>\n </div>\n <span v-else />\n <div class=\"flex flex-wrap gap-1\">\n <Button\n v-for=\"tool in tools\"\n :key=\"tool.label\"\n type=\"button\"\n variant=\"outline\"\n size=\"icon-sm\"\n :aria-label=\"tool.label\"\n :title=\"tool.label\"\n :disabled=\"tool.disabled\"\n @click=\"tool.run()\"\n >\n <component :is=\"tool.icon\" />\n </Button>\n </div>\n </div>\n </div>\n <!-- Numeric inputs: beside the image from md up, under it on phones. -->\n <div\n role=\"group\"\n :aria-label=\"t('image_editor.inputs', {}, 'Position and size')\"\n data-slot=\"image-editor-inputs\"\n class=\"grid grid-cols-2 content-start gap-x-3 gap-y-2 sm:grid-cols-4 md:w-40 md:shrink-0 md:grid-cols-1\"\n >\n <div\n v-for=\"[field, key, fallback] in NUMERIC_FIELDS\"\n :key=\"field\"\n class=\"flex flex-col gap-1\"\n >\n <label :for=\"`${inputsId}-${field}`\" class=\"text-muted-foreground text-xs\">\n {{ t(key, {}, fallback) }}\n </label>\n <Input\n :id=\"`${inputsId}-${field}`\"\n type=\"number\"\n inputmode=\"decimal\"\n step=\"1\"\n :data-field=\"field\"\n class=\"h-8 tabular-nums\"\n :model-value=\"data[field]\"\n @change=\"commit(field, $event)\"\n @keydown.enter.prevent=\"commit(field, $event)\"\n />\n </div>\n <div class=\"col-span-2 flex gap-1 sm:col-span-4 md:col-span-1\">\n <Button\n v-for=\"[axis, key, fallback] in SCALES\"\n :key=\"axis\"\n type=\"button\"\n size=\"sm\"\n :variant=\"(axis === 'x' ? state.flipX : state.flipY) ? 'default' : 'outline'\"\n :aria-pressed=\"String(axis === 'x' ? state.flipX : state.flipY)\"\n :data-field=\"`scale${axis.toUpperCase()}`\"\n class=\"flex-1\"\n @click=\"loaded.editor.flip(axis)\"\n >\n {{ t(key, {}, fallback) }}\n </Button>\n </div>\n </div>\n </div>\n <div v-else class=\"flex h-48 items-center justify-center\">\n <Spinner />\n </div>\n <DialogFooter>\n <Button type=\"button\" variant=\"outline\" @click=\"finish(null)\">\n {{ t('image_editor.cancel', {}, 'Cancel') }}\n </Button>\n <Button type=\"button\" :disabled=\"!loaded || saving\" @click=\"void save()\">\n <Spinner v-if=\"saving\" />\n {{ t('image_editor.save', {}, 'Apply') }}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ImageEditorDialog.js","names":["_sfc_main","ImageEditorDialog_vue_vue_type_script_setup_true_lang_default","ImageEditorDialog_default"],"sources":["../../../src/components/fields/ImageEditorDialog.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * `FileUpload::imageEditor()`: crop, zoom, rotate and flip an image before it is uploaded\n * (or to replace an uploaded one). Resolves the request with the edited file, or null\n * when cancelled.\n */\nimport type {\n CropHandle,\n FileUploadImageEditorSchema,\n ImageEditorData,\n ImageEditorDragMode,\n ImageEditorState,\n} from '@alfakit/core'\nimport { ImageEditor, imageEditorOptionsKey, loadEditorImage } from '@alfakit/core'\nimport {\n FlipHorizontal2Icon,\n FlipVertical2Icon,\n RotateCcwIcon,\n RotateCwIcon,\n Undo2Icon,\n ZoomInIcon,\n ZoomOutIcon,\n} from '@lucide/vue'\nimport { computed, onScopeDispose, ref, shallowRef, useId, watch, type Component } from 'vue'\nimport { useT } from '../../context'\nimport { cn } from '../../lib/utils'\nimport Button from '../ui/Button.vue'\nimport Dialog from '../ui/Dialog.vue'\nimport DialogContent from '../ui/DialogContent.vue'\nimport DialogDescription from '../ui/DialogDescription.vue'\nimport DialogFooter from '../ui/DialogFooter.vue'\nimport DialogHeader from '../ui/DialogHeader.vue'\nimport DialogTitle from '../ui/DialogTitle.vue'\nimport Input from '../ui/Input.vue'\nimport Spinner from '../ui/Spinner.vue'\n\nexport interface ImageEditRequest {\n file: File\n resolve: (file: File | null) => void\n}\n\nconst HANDLES: CropHandle[] = ['nw', 'ne', 'sw', 'se']\n\n/** The numeric inputs, in the order Filament shows them. */\nconst NUMERIC_FIELDS = [\n ['x', 'image_editor.x', 'X'],\n ['y', 'image_editor.y', 'Y'],\n ['width', 'image_editor.width', 'Width'],\n ['height', 'image_editor.height', 'Height'],\n ['rotate', 'image_editor.rotation', 'Rotation'],\n] as const satisfies ReadonlyArray<readonly [keyof ImageEditorData, string, string]>\n\nconst SCALES = [\n ['x', 'image_editor.scale_x', 'Scale X'],\n ['y', 'image_editor.scale_y', 'Scale Y'],\n] as const\n\nconst props = defineProps<{\n request: ImageEditRequest | null\n options: FileUploadImageEditorSchema\n}>()\n\nconst t = useT()\nconst loaded = shallowRef<{ bitmap: ImageBitmap; editor: ImageEditor } | null>(null)\nconst state = shallowRef<ImageEditorState | null>(null)\nconst saving = ref(false)\nconst hintId = useId()\nconst inputsId = useId()\nconst canvas = ref<HTMLCanvasElement | null>(null)\nconst frame = ref<HTMLDivElement | null>(null)\nlet unsubscribe: (() => void) | null = null\nlet stopObserving: (() => void) | null = null\n\nconst release = () => {\n unsubscribe?.()\n unsubscribe = null\n stopObserving?.()\n stopObserving = null\n loaded.value?.bitmap.close()\n loaded.value = null\n state.value = null\n}\n\n// Restart only for another image or other settings: the schema object itself is new on\n// every render of a template item (a new builder block), which kept restarting the load.\nwatch(\n [() => props.request, () => imageEditorOptionsKey(props.options)],\n ([request], _previous, onCleanup) => {\n if (!request) return\n\n const options = props.options\n\n let cancelled = false\n\n loadEditorImage(request.file)\n .then((bitmap) => {\n if (cancelled) return bitmap.close()\n\n const editor = new ImageEditor({\n width: bitmap.width,\n height: bitmap.height,\n aspectRatios: options.aspectRatios,\n circle: options.circle,\n mode: options.mode,\n emptyFillColor: options.emptyFillColor,\n viewportWidth: options.viewportWidth,\n viewportHeight: options.viewportHeight,\n })\n\n loaded.value = { bitmap, editor }\n state.value = editor.store.get()\n unsubscribe = editor.store.subscribe((next) => {\n state.value = next\n })\n })\n // Undecodable: upload the file as it is.\n .catch(() => !cancelled && request.resolve(request.file))\n\n onCleanup(() => {\n cancelled = true\n release()\n })\n },\n { immediate: true },\n)\n\nonScopeDispose(release)\n\n// Redraw on every change (crop, zoom, rotation, flips, container size).\nwatch(\n () => [canvas.value, state.value] as const,\n ([element]) => {\n if (element && loaded.value) {\n loaded.value.editor.drawPreview(\n element,\n loaded.value.bitmap,\n globalThis.devicePixelRatio || 1,\n )\n }\n },\n { flush: 'post' },\n)\n\n// Measure the container and follow its size; zoom with the wheel and trackpad pinch.\nwatch(\n () => [frame.value, loaded.value?.editor] as const,\n ([element, editor]) => {\n stopObserving?.()\n stopObserving = null\n\n if (!element || !editor) return\n\n const measure = () => editor.setContainer(element.clientWidth, element.clientHeight)\n measure()\n\n const observer = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(measure)\n observer?.observe(element)\n\n const onWheel = (event: WheelEvent) => {\n const rect = element.getBoundingClientRect()\n\n if (editor.wheel(event, { x: event.clientX - rect.left, y: event.clientY - rect.top })) {\n event.preventDefault()\n }\n }\n\n element.addEventListener('wheel', onWheel, { passive: false })\n\n stopObserving = () => {\n observer?.disconnect()\n element.removeEventListener('wheel', onWheel)\n }\n },\n { flush: 'post' },\n)\n\nconst data = computed<ImageEditorData | null>(() => {\n void state.value\n\n return loaded.value?.editor.getData() ?? null\n})\n\n// Numeric inputs apply on change (blur, Enter, spinner); invalid values snap back.\nconst commit = (field: keyof ImageEditorData, event: Event) => {\n const editor = loaded.value?.editor\n const input = event.target as HTMLInputElement | null\n\n if (!editor || !input) return\n\n const value = input.value.trim() === '' ? Number.NaN : Number(input.value)\n editor.setData({ [field]: value })\n input.value = String(editor.getData()[field])\n}\n\nconst box = computed(() => {\n void state.value\n\n return loaded.value?.editor.cropBox() ?? { left: 0, top: 0, width: 0, height: 0 }\n})\n\nconst finish = (file: File | null) => {\n props.request?.resolve(file)\n}\n\nconst save = async () => {\n const request = props.request\n const current = loaded.value\n\n if (!request || !current) return\n\n saving.value = true\n\n try {\n finish(await current.editor.export(current.bitmap, request.file))\n } catch {\n finish(request.file)\n } finally {\n saving.value = false\n }\n}\n\nconst start = (mode: ImageEditorDragMode, event: PointerEvent) => {\n const editor = loaded.value?.editor\n\n if (!editor) return\n\n event.preventDefault()\n event.stopPropagation()\n ;(event.currentTarget as HTMLElement | null)?.setPointerCapture?.(event.pointerId)\n editor.startDrag(mode, event.clientX, event.clientY, undefined, event.pointerId ?? 0)\n}\n\nconst onKeydown = (event: KeyboardEvent) => {\n if (loaded.value?.editor.handleKey(event)) event.preventDefault()\n}\n\nconst ratioLabel = (ratio: string | null) => ratio ?? t('image_editor.free', {}, 'Free')\n\nconst tools = computed<\n Array<{ label: string; icon: Component; run: () => void; disabled?: boolean }>\n>(() => [\n {\n label: t('image_editor.zoom_out', {}, 'Zoom out'),\n icon: ZoomOutIcon,\n run: () => loaded.value?.editor.zoomOut(),\n disabled: !(state.value && loaded.value?.editor.canZoomOut),\n },\n {\n label: t('image_editor.zoom_in', {}, 'Zoom in'),\n icon: ZoomInIcon,\n run: () => loaded.value?.editor.zoomIn(),\n disabled: !(state.value && loaded.value?.editor.canZoomIn),\n },\n {\n label: t('image_editor.rotate_left', {}, 'Rotate left'),\n icon: RotateCcwIcon,\n run: () => loaded.value?.editor.rotate(-1),\n },\n {\n label: t('image_editor.rotate_right', {}, 'Rotate right'),\n icon: RotateCwIcon,\n run: () => loaded.value?.editor.rotate(1),\n },\n {\n label: t('image_editor.flip_horizontal', {}, 'Flip horizontally'),\n icon: FlipHorizontal2Icon,\n run: () => loaded.value?.editor.flip('x'),\n },\n {\n label: t('image_editor.flip_vertical', {}, 'Flip vertically'),\n icon: FlipVertical2Icon,\n run: () => loaded.value?.editor.flip('y'),\n },\n {\n label: t('image_editor.reset', {}, 'Reset'),\n icon: Undo2Icon,\n run: () => loaded.value?.editor.reset(),\n },\n])\n</script>\n\n<template>\n <Dialog :open=\"props.request !== null\" @update:open=\"(open) => !open && finish(null)\">\n <DialogContent class=\"sm:max-w-3xl\" data-slot=\"image-editor\">\n <DialogHeader>\n <DialogTitle>{{ t('image_editor.title', {}, 'Edit image') }}</DialogTitle>\n <DialogDescription class=\"sr-only\">\n <span :id=\"hintId\"\n >{{\n t(\n 'image_editor.keyboard_hint',\n {},\n 'Arrow keys move the crop area. Shift and arrow keys resize it.',\n )\n }}\n {{ t('image_editor.zoom_hint', {}, 'Plus and minus keys zoom the image.') }}</span\n >\n </DialogDescription>\n </DialogHeader>\n <div v-if=\"loaded && state && data\" class=\"flex flex-col gap-4 md:flex-row\">\n <div class=\"flex min-w-0 flex-1 flex-col gap-3\">\n <!-- Image space: left is the image's left in every reading direction. -->\n <div\n ref=\"frame\"\n dir=\"ltr\"\n data-slot=\"image-editor-viewport\"\n class=\"bg-muted/40 relative h-72 w-full cursor-grab touch-none overflow-hidden rounded-md select-none sm:h-96\"\n @pointerdown=\"start('pan', $event)\"\n @pointermove=\"\n loaded.editor.dragTo($event.clientX, $event.clientY, $event.pointerId ?? 0)\n \"\n @pointerup=\"loaded.editor.endDrag($event.pointerId ?? 0)\"\n @pointercancel=\"loaded.editor.endDrag($event.pointerId ?? 0)\"\n >\n <canvas ref=\"canvas\" class=\"pointer-events-none absolute inset-0 block size-full\" />\n <!-- Runtime geometry: no Tailwind class can hold these values. -->\n <div\n role=\"group\"\n tabindex=\"0\"\n :aria-label=\"t('image_editor.crop_area', {}, 'Crop area')\"\n :aria-describedby=\"hintId\"\n data-slot=\"image-editor-crop\"\n :class=\"\n cn(\n 'ring-ring/50 absolute cursor-move border-2 border-white shadow-[0_0_0_9999px_rgb(0_0_0/0.5)] outline-none focus-visible:ring-[3px]',\n loaded.editor.circle && 'rounded-full',\n )\n \"\n :style=\"{\n left: `${box.left}%`,\n top: `${box.top}%`,\n width: `${box.width}%`,\n height: `${box.height}%`,\n }\"\n @pointerdown=\"start('move', $event)\"\n @keydown=\"onKeydown\"\n >\n <span\n v-for=\"handle in HANDLES\"\n :key=\"handle\"\n :data-handle=\"handle\"\n aria-hidden=\"true\"\n class=\"absolute size-3 -translate-x-1/2 -translate-y-1/2 rounded-sm border border-black/40 bg-white\"\n :style=\"{\n left: handle.endsWith('w') ? '0%' : '100%',\n top: handle.startsWith('n') ? '0%' : '100%',\n cursor: handle === 'nw' || handle === 'se' ? 'nwse-resize' : 'nesw-resize',\n }\"\n @pointerdown=\"start(handle, $event)\"\n />\n </div>\n </div>\n <div class=\"flex flex-wrap items-center justify-between gap-2\">\n <div\n v-if=\"loaded.editor.aspectRatios.length > 1\"\n role=\"group\"\n :aria-label=\"t('image_editor.aspect_ratio', {}, 'Aspect ratio')\"\n class=\"flex flex-wrap gap-1\"\n >\n <Button\n v-for=\"ratio in loaded.editor.aspectRatios\"\n :key=\"ratio ?? 'free'\"\n type=\"button\"\n size=\"sm\"\n :variant=\"state.aspectRatio === ratio ? 'default' : 'outline'\"\n :aria-pressed=\"String(state.aspectRatio === ratio)\"\n @click=\"loaded.editor.setAspectRatio(ratio)\"\n >\n {{ ratioLabel(ratio) }}\n </Button>\n </div>\n <span v-else />\n <div class=\"flex flex-wrap gap-1\">\n <Button\n v-for=\"tool in tools\"\n :key=\"tool.label\"\n type=\"button\"\n variant=\"outline\"\n size=\"icon-sm\"\n :aria-label=\"tool.label\"\n :title=\"tool.label\"\n :disabled=\"tool.disabled\"\n @click=\"tool.run()\"\n >\n <component :is=\"tool.icon\" />\n </Button>\n </div>\n </div>\n </div>\n <!-- Numeric inputs: beside the image from md up, under it on phones. -->\n <div\n role=\"group\"\n :aria-label=\"t('image_editor.inputs', {}, 'Position and size')\"\n data-slot=\"image-editor-inputs\"\n class=\"grid grid-cols-2 content-start gap-x-3 gap-y-2 sm:grid-cols-4 md:w-40 md:shrink-0 md:grid-cols-1\"\n >\n <div\n v-for=\"[field, key, fallback] in NUMERIC_FIELDS\"\n :key=\"field\"\n class=\"flex flex-col gap-1\"\n >\n <label :for=\"`${inputsId}-${field}`\" class=\"text-muted-foreground text-xs\">\n {{ t(key, {}, fallback) }}\n </label>\n <Input\n :id=\"`${inputsId}-${field}`\"\n type=\"number\"\n inputmode=\"decimal\"\n step=\"1\"\n :data-field=\"field\"\n class=\"h-8 tabular-nums\"\n :model-value=\"data[field]\"\n @change=\"commit(field, $event)\"\n @keydown.enter.prevent=\"commit(field, $event)\"\n />\n </div>\n <div class=\"col-span-2 flex gap-1 sm:col-span-4 md:col-span-1\">\n <Button\n v-for=\"[axis, key, fallback] in SCALES\"\n :key=\"axis\"\n type=\"button\"\n size=\"sm\"\n :variant=\"(axis === 'x' ? state.flipX : state.flipY) ? 'default' : 'outline'\"\n :aria-pressed=\"String(axis === 'x' ? state.flipX : state.flipY)\"\n :data-field=\"`scale${axis.toUpperCase()}`\"\n class=\"flex-1\"\n @click=\"loaded.editor.flip(axis)\"\n >\n {{ t(key, {}, fallback) }}\n </Button>\n </div>\n </div>\n </div>\n <div v-else class=\"flex h-48 items-center justify-center\">\n <Spinner />\n </div>\n <DialogFooter>\n <Button type=\"button\" variant=\"outline\" @click=\"finish(null)\">\n {{ t('image_editor.cancel', {}, 'Cancel') }}\n </Button>\n <Button type=\"button\" :disabled=\"!loaded || saving\" @click=\"void save()\">\n <Spinner v-if=\"saving\" />\n {{ t('image_editor.save', {}, 'Apply') }}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageEditorDialog.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fields/ImageEditorDialog.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ImageEditorDialog.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fields/ImageEditorDialog.vue"],"names":[],"mappings":"AAkcA;;;;GAIG;AACH,OAAO,KAAK,EAEV,2BAA2B,EAI5B,MAAM,eAAe,CAAA;AAwBtB,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,IAAI,CAAA;IACV,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,KAAK,IAAI,CAAA;CACrC;AAkBD,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAChC,OAAO,EAAE,2BAA2B,CAAA;CACrC,CAAC;;AA+uBF,wBAMG"}
|
|
@@ -9,14 +9,14 @@ import ne from "../ui/DialogDescription.js";
|
|
|
9
9
|
import re from "../ui/DialogHeader.js";
|
|
10
10
|
import ie from "../ui/DialogTitle.js";
|
|
11
11
|
import ae from "../ui/DialogFooter.js";
|
|
12
|
-
import { ImageEditor as a,
|
|
13
|
-
import { Fragment as o, computed as s, createBlock as c, createCommentVNode as
|
|
14
|
-
import { FlipHorizontal2Icon as
|
|
12
|
+
import { ImageEditor as a, imageEditorOptionsKey as oe, loadEditorImage as se } from "@alfakit/core";
|
|
13
|
+
import { Fragment as o, computed as s, createBlock as c, createCommentVNode as ce, createElementBlock as l, createElementVNode as u, createTextVNode as d, createVNode as f, defineComponent as p, normalizeClass as le, normalizeStyle as m, onScopeDispose as ue, openBlock as h, ref as g, renderList as _, resolveDynamicComponent as de, shallowRef as v, toDisplayString as y, unref as b, useId as x, watch as S, withCtx as C, withKeys as fe, withModifiers as pe } from "vue";
|
|
14
|
+
import { FlipHorizontal2Icon as me, FlipVertical2Icon as he, RotateCcwIcon as ge, RotateCwIcon as _e, Undo2Icon as ve, ZoomInIcon as ye, ZoomOutIcon as w } from "@lucide/vue";
|
|
15
15
|
//#region src/components/fields/ImageEditorDialog.vue?vue&type=script&setup=true&lang.ts
|
|
16
|
-
var
|
|
16
|
+
var T = ["id"], E = {
|
|
17
17
|
key: 0,
|
|
18
18
|
class: "flex flex-col gap-4 md:flex-row"
|
|
19
|
-
},
|
|
19
|
+
}, D = { class: "flex min-w-0 flex-1 flex-col gap-3" }, O = ["aria-label", "aria-describedby"], k = ["data-handle", "onPointerdown"], A = { class: "flex flex-wrap items-center justify-between gap-2" }, j = ["aria-label"], M = { key: 1 }, N = { class: "flex flex-wrap gap-1" }, P = ["aria-label"], F = ["for"], be = { class: "col-span-2 flex gap-1 sm:col-span-4 md:col-span-1" }, xe = {
|
|
20
20
|
key: 1,
|
|
21
21
|
class: "flex h-48 items-center justify-center"
|
|
22
22
|
}, I = /*@__PURE__*/ p({
|
|
@@ -31,7 +31,7 @@ var w = ["id"], T = {
|
|
|
31
31
|
"ne",
|
|
32
32
|
"sw",
|
|
33
33
|
"se"
|
|
34
|
-
],
|
|
34
|
+
], Se = [
|
|
35
35
|
[
|
|
36
36
|
"x",
|
|
37
37
|
"image_editor.x",
|
|
@@ -57,7 +57,7 @@ var w = ["id"], T = {
|
|
|
57
57
|
"image_editor.rotation",
|
|
58
58
|
"Rotation"
|
|
59
59
|
]
|
|
60
|
-
],
|
|
60
|
+
], Ce = [[
|
|
61
61
|
"x",
|
|
62
62
|
"image_editor.scale_x",
|
|
63
63
|
"Scale X"
|
|
@@ -68,31 +68,31 @@ var w = ["id"], T = {
|
|
|
68
68
|
]], L = p, R = e(), z = v(null), B = v(null), V = g(!1), H = x(), U = x(), W = g(null), G = g(null), K = null, q = null, J = () => {
|
|
69
69
|
K?.(), K = null, q?.(), q = null, z.value?.bitmap.close(), z.value = null, B.value = null;
|
|
70
70
|
};
|
|
71
|
-
S(() =>
|
|
71
|
+
S([() => L.request, () => oe(L.options)], ([e], t, n) => {
|
|
72
72
|
if (!e) return;
|
|
73
|
-
let i = !1;
|
|
74
|
-
|
|
73
|
+
let r = L.options, i = !1;
|
|
74
|
+
se(e.file).then((e) => {
|
|
75
75
|
if (i) return e.close();
|
|
76
|
-
let
|
|
76
|
+
let t = new a({
|
|
77
77
|
width: e.width,
|
|
78
78
|
height: e.height,
|
|
79
|
-
aspectRatios:
|
|
80
|
-
circle:
|
|
81
|
-
mode:
|
|
82
|
-
emptyFillColor:
|
|
83
|
-
viewportWidth:
|
|
84
|
-
viewportHeight:
|
|
79
|
+
aspectRatios: r.aspectRatios,
|
|
80
|
+
circle: r.circle,
|
|
81
|
+
mode: r.mode,
|
|
82
|
+
emptyFillColor: r.emptyFillColor,
|
|
83
|
+
viewportWidth: r.viewportWidth,
|
|
84
|
+
viewportHeight: r.viewportHeight
|
|
85
85
|
});
|
|
86
86
|
z.value = {
|
|
87
87
|
bitmap: e,
|
|
88
|
-
editor:
|
|
89
|
-
}, B.value =
|
|
88
|
+
editor: t
|
|
89
|
+
}, B.value = t.store.get(), K = t.store.subscribe((e) => {
|
|
90
90
|
B.value = e;
|
|
91
91
|
});
|
|
92
|
-
}).catch(() => !i && e.resolve(e.file)),
|
|
92
|
+
}).catch(() => !i && e.resolve(e.file)), n(() => {
|
|
93
93
|
i = !0, J();
|
|
94
94
|
});
|
|
95
|
-
}, { immediate: !0 }),
|
|
95
|
+
}, { immediate: !0 }), ue(J), S(() => [W.value, B.value], ([e]) => {
|
|
96
96
|
e && z.value && z.value.editor.drawPreview(e, z.value.bitmap, globalThis.devicePixelRatio || 1);
|
|
97
97
|
}, { flush: "post" }), S(() => [G.value, z.value?.editor], ([e, t]) => {
|
|
98
98
|
if (q?.(), q = null, !e || !t) return;
|
|
@@ -123,7 +123,7 @@ var w = ["id"], T = {
|
|
|
123
123
|
height: 0
|
|
124
124
|
})), Q = (e) => {
|
|
125
125
|
L.request?.resolve(e);
|
|
126
|
-
},
|
|
126
|
+
}, we = async () => {
|
|
127
127
|
let e = L.request, t = z.value;
|
|
128
128
|
if (e && t) {
|
|
129
129
|
V.value = !0;
|
|
@@ -138,44 +138,44 @@ var w = ["id"], T = {
|
|
|
138
138
|
}, $ = (e, t) => {
|
|
139
139
|
let n = z.value?.editor;
|
|
140
140
|
n && (t.preventDefault(), t.stopPropagation(), t.currentTarget?.setPointerCapture?.(t.pointerId), n.startDrag(e, t.clientX, t.clientY, void 0, t.pointerId ?? 0));
|
|
141
|
-
},
|
|
141
|
+
}, Te = (e) => {
|
|
142
142
|
z.value?.editor.handleKey(e) && e.preventDefault();
|
|
143
|
-
},
|
|
143
|
+
}, Ee = (e) => e ?? R("image_editor.free", {}, "Free"), De = s(() => [
|
|
144
144
|
{
|
|
145
145
|
label: R("image_editor.zoom_out", {}, "Zoom out"),
|
|
146
|
-
icon:
|
|
146
|
+
icon: w,
|
|
147
147
|
run: () => z.value?.editor.zoomOut(),
|
|
148
148
|
disabled: !(B.value && z.value?.editor.canZoomOut)
|
|
149
149
|
},
|
|
150
150
|
{
|
|
151
151
|
label: R("image_editor.zoom_in", {}, "Zoom in"),
|
|
152
|
-
icon:
|
|
152
|
+
icon: ye,
|
|
153
153
|
run: () => z.value?.editor.zoomIn(),
|
|
154
154
|
disabled: !(B.value && z.value?.editor.canZoomIn)
|
|
155
155
|
},
|
|
156
156
|
{
|
|
157
157
|
label: R("image_editor.rotate_left", {}, "Rotate left"),
|
|
158
|
-
icon:
|
|
158
|
+
icon: ge,
|
|
159
159
|
run: () => z.value?.editor.rotate(-1)
|
|
160
160
|
},
|
|
161
161
|
{
|
|
162
162
|
label: R("image_editor.rotate_right", {}, "Rotate right"),
|
|
163
|
-
icon:
|
|
163
|
+
icon: _e,
|
|
164
164
|
run: () => z.value?.editor.rotate(1)
|
|
165
165
|
},
|
|
166
166
|
{
|
|
167
167
|
label: R("image_editor.flip_horizontal", {}, "Flip horizontally"),
|
|
168
|
-
icon:
|
|
168
|
+
icon: me,
|
|
169
169
|
run: () => z.value?.editor.flip("x")
|
|
170
170
|
},
|
|
171
171
|
{
|
|
172
172
|
label: R("image_editor.flip_vertical", {}, "Flip vertically"),
|
|
173
|
-
icon:
|
|
173
|
+
icon: he,
|
|
174
174
|
run: () => z.value?.editor.flip("y")
|
|
175
175
|
},
|
|
176
176
|
{
|
|
177
177
|
label: R("image_editor.reset", {}, "Reset"),
|
|
178
|
-
icon:
|
|
178
|
+
icon: ve,
|
|
179
179
|
run: () => z.value?.editor.reset()
|
|
180
180
|
}
|
|
181
181
|
]);
|
|
@@ -193,12 +193,12 @@ var w = ["id"], T = {
|
|
|
193
193
|
default: C(() => [d(y(b(R)("image_editor.title", {}, "Edit image")), 1)]),
|
|
194
194
|
_: 1
|
|
195
195
|
}), f(ne, { class: "sr-only" }, {
|
|
196
|
-
default: C(() => [u("span", { id: b(H) }, y(b(R)("image_editor.keyboard_hint", {}, "Arrow keys move the crop area. Shift and arrow keys resize it.")) + " " + y(b(R)("image_editor.zoom_hint", {}, "Plus and minus keys zoom the image.")), 9,
|
|
196
|
+
default: C(() => [u("span", { id: b(H) }, y(b(R)("image_editor.keyboard_hint", {}, "Arrow keys move the crop area. Shift and arrow keys resize it.")) + " " + y(b(R)("image_editor.zoom_hint", {}, "Plus and minus keys zoom the image.")), 9, T)]),
|
|
197
197
|
_: 1
|
|
198
198
|
})]),
|
|
199
199
|
_: 1
|
|
200
200
|
}),
|
|
201
|
-
z.value && B.value && Y.value ? (h(), l("div",
|
|
201
|
+
z.value && B.value && Y.value ? (h(), l("div", E, [u("div", D, [u("div", {
|
|
202
202
|
ref_key: "frame",
|
|
203
203
|
ref: G,
|
|
204
204
|
dir: "ltr",
|
|
@@ -218,7 +218,7 @@ var w = ["id"], T = {
|
|
|
218
218
|
"aria-label": b(R)("image_editor.crop_area", {}, "Crop area"),
|
|
219
219
|
"aria-describedby": b(H),
|
|
220
220
|
"data-slot": "image-editor-crop",
|
|
221
|
-
class:
|
|
221
|
+
class: le(b(t)("ring-ring/50 absolute cursor-move border-2 border-white shadow-[0_0_0_9999px_rgb(0_0_0/0.5)] outline-none focus-visible:ring-[3px]", z.value.editor.circle && "rounded-full")),
|
|
222
222
|
style: m({
|
|
223
223
|
left: `${Z.value.left}%`,
|
|
224
224
|
top: `${Z.value.top}%`,
|
|
@@ -226,7 +226,7 @@ var w = ["id"], T = {
|
|
|
226
226
|
height: `${Z.value.height}%`
|
|
227
227
|
}),
|
|
228
228
|
onPointerdown: a[0] ||= (e) => $("move", e),
|
|
229
|
-
onKeydown:
|
|
229
|
+
onKeydown: Te
|
|
230
230
|
}, [(h(), l(o, null, _(I, (e) => u("span", {
|
|
231
231
|
key: e,
|
|
232
232
|
"data-handle": e,
|
|
@@ -238,7 +238,7 @@ var w = ["id"], T = {
|
|
|
238
238
|
cursor: e === "nw" || e === "se" ? "nwse-resize" : "nesw-resize"
|
|
239
239
|
}),
|
|
240
240
|
onPointerdown: (t) => $(e, t)
|
|
241
|
-
}, null, 44,
|
|
241
|
+
}, null, 44, k)), 64))], 46, O)], 544), u("div", A, [z.value.editor.aspectRatios.length > 1 ? (h(), l("div", {
|
|
242
242
|
key: 0,
|
|
243
243
|
role: "group",
|
|
244
244
|
"aria-label": b(R)("image_editor.aspect_ratio", {}, "Aspect ratio"),
|
|
@@ -251,13 +251,13 @@ var w = ["id"], T = {
|
|
|
251
251
|
"aria-pressed": String(B.value.aspectRatio === e),
|
|
252
252
|
onClick: (t) => z.value.editor.setAspectRatio(e)
|
|
253
253
|
}, {
|
|
254
|
-
default: C(() => [d(y(
|
|
254
|
+
default: C(() => [d(y(Ee(e)), 1)]),
|
|
255
255
|
_: 2
|
|
256
256
|
}, 1032, [
|
|
257
257
|
"variant",
|
|
258
258
|
"aria-pressed",
|
|
259
259
|
"onClick"
|
|
260
|
-
]))), 128))], 8,
|
|
260
|
+
]))), 128))], 8, j)) : (h(), l("span", M)), u("div", N, [(h(!0), l(o, null, _(De.value, (e) => (h(), c(n, {
|
|
261
261
|
key: e.label,
|
|
262
262
|
type: "button",
|
|
263
263
|
variant: "outline",
|
|
@@ -267,7 +267,7 @@ var w = ["id"], T = {
|
|
|
267
267
|
disabled: e.disabled,
|
|
268
268
|
onClick: (t) => e.run()
|
|
269
269
|
}, {
|
|
270
|
-
default: C(() => [(h(), c(
|
|
270
|
+
default: C(() => [(h(), c(de(e.icon)))]),
|
|
271
271
|
_: 2
|
|
272
272
|
}, 1032, [
|
|
273
273
|
"aria-label",
|
|
@@ -279,13 +279,13 @@ var w = ["id"], T = {
|
|
|
279
279
|
"aria-label": b(R)("image_editor.inputs", {}, "Position and size"),
|
|
280
280
|
"data-slot": "image-editor-inputs",
|
|
281
281
|
class: "grid grid-cols-2 content-start gap-x-3 gap-y-2 sm:grid-cols-4 md:w-40 md:shrink-0 md:grid-cols-1"
|
|
282
|
-
}, [(h(), l(o, null, _(
|
|
282
|
+
}, [(h(), l(o, null, _(Se, ([e, t, n]) => u("div", {
|
|
283
283
|
key: e,
|
|
284
284
|
class: "flex flex-col gap-1"
|
|
285
285
|
}, [u("label", {
|
|
286
286
|
for: `${b(U)}-${e}`,
|
|
287
287
|
class: "text-muted-foreground text-xs"
|
|
288
|
-
}, y(b(R)(t, {}, n)), 9,
|
|
288
|
+
}, y(b(R)(t, {}, n)), 9, F), f(i, {
|
|
289
289
|
id: `${b(U)}-${e}`,
|
|
290
290
|
type: "number",
|
|
291
291
|
inputmode: "decimal",
|
|
@@ -294,14 +294,14 @@ var w = ["id"], T = {
|
|
|
294
294
|
class: "h-8 tabular-nums",
|
|
295
295
|
"model-value": Y.value[e],
|
|
296
296
|
onChange: (t) => X(e, t),
|
|
297
|
-
onKeydown:
|
|
297
|
+
onKeydown: fe(pe((t) => X(e, t), ["prevent"]), ["enter"])
|
|
298
298
|
}, null, 8, [
|
|
299
299
|
"id",
|
|
300
300
|
"data-field",
|
|
301
301
|
"model-value",
|
|
302
302
|
"onChange",
|
|
303
303
|
"onKeydown"
|
|
304
|
-
])])), 64)), u("div",
|
|
304
|
+
])])), 64)), u("div", be, [(h(), l(o, null, _(Ce, ([e, t, r]) => f(n, {
|
|
305
305
|
key: e,
|
|
306
306
|
type: "button",
|
|
307
307
|
size: "sm",
|
|
@@ -318,7 +318,7 @@ var w = ["id"], T = {
|
|
|
318
318
|
"aria-pressed",
|
|
319
319
|
"data-field",
|
|
320
320
|
"onClick"
|
|
321
|
-
])), 64))])], 8,
|
|
321
|
+
])), 64))])], 8, P)])) : (h(), l("div", xe, [f(r)])),
|
|
322
322
|
f(ae, null, {
|
|
323
323
|
default: C(() => [f(n, {
|
|
324
324
|
type: "button",
|
|
@@ -330,9 +330,9 @@ var w = ["id"], T = {
|
|
|
330
330
|
}), f(n, {
|
|
331
331
|
type: "button",
|
|
332
332
|
disabled: !z.value || V.value,
|
|
333
|
-
onClick: a[6] ||= (e) => void
|
|
333
|
+
onClick: a[6] ||= (e) => void we()
|
|
334
334
|
}, {
|
|
335
|
-
default: C(() => [V.value ? (h(), c(r, { key: 0 })) :
|
|
335
|
+
default: C(() => [V.value ? (h(), c(r, { key: 0 })) : ce("", !0), d(" " + y(b(R)("image_editor.save", {}, "Apply")), 1)]),
|
|
336
336
|
_: 1
|
|
337
337
|
}, 8, ["disabled"])]),
|
|
338
338
|
_: 1
|