@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":"ImageEditorDialog.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","Dialog","_withCtx","_createVNode","DialogContent","DialogHeader","DialogTitle","_createTextVNode","_toDisplayString","_unref","DialogDescription","_createElementVNode","_createElementBlock","_normalizeClass","_normalizeStyle","_Fragment","_renderList","Button","_resolveDynamicComponent","Input","_withKeys","_withModifiers","Spinner","DialogFooter","_createCommentVNode","Button_default","Spinner_default","Input_default","Dialog_default","DialogContent_default","DialogDescription_default","DialogHeader_default","DialogTitle_default","DialogFooter_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","ImageEditorDialog_vue_vue_type_script_setup_true_lang_default","HANDLES","NUMERIC_FIELDS","SCALES","props","__props","t","useT","loaded","shallowRef","state","saving","ref","hintId","useId","inputsId","canvas","frame","unsubscribe","stopObserving","release","watch","request","options","cancelled","loadEditorImage","bitmap","editor","ImageEditor","next","onCleanup","onScopeDispose","element","measure","observer","onWheel","rect","event","data","computed","commit","input","value","field","box","finish","file","save","current","start","mode","onKeydown","ratioLabel","ratio","tools","ZoomOutIcon","ZoomInIcon","RotateCcwIcon","RotateCwIcon","FlipHorizontal2Icon","FlipVertical2Icon","Undo2Icon","openBlock","createBlock","_cache","open","withCtx","createVNode","createTextVNode","toDisplayString","unref","createElementVNode","createElementBlock","$event","normalizeClass","cn","normalizeStyle","Fragment","renderList","handle","tool","resolveDynamicComponent","key","fallback","withKeys","withModifiers","axis","createCommentVNode"],"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":"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"}
|
|
1
|
+
{"version":3,"file":"ImageEditorDialog.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","Dialog","_withCtx","_createVNode","DialogContent","DialogHeader","DialogTitle","_createTextVNode","_toDisplayString","_unref","DialogDescription","_createElementVNode","_createElementBlock","_normalizeClass","_normalizeStyle","_Fragment","_renderList","Button","_resolveDynamicComponent","Input","_withKeys","_withModifiers","Spinner","DialogFooter","_createCommentVNode","Button_default","Spinner_default","Input_default","Dialog_default","DialogContent_default","DialogDescription_default","DialogHeader_default","DialogTitle_default","DialogFooter_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","ImageEditorDialog_vue_vue_type_script_setup_true_lang_default","HANDLES","NUMERIC_FIELDS","SCALES","props","__props","t","useT","loaded","shallowRef","state","saving","ref","hintId","useId","inputsId","canvas","frame","unsubscribe","stopObserving","release","watch","imageEditorOptionsKey","request","options","cancelled","loadEditorImage","bitmap","editor","ImageEditor","next","onCleanup","onScopeDispose","element","measure","observer","onWheel","rect","event","data","computed","commit","input","value","field","box","finish","file","save","current","start","mode","onKeydown","ratioLabel","ratio","tools","ZoomOutIcon","ZoomInIcon","RotateCcwIcon","RotateCwIcon","FlipHorizontal2Icon","FlipVertical2Icon","Undo2Icon","openBlock","createBlock","_cache","open","withCtx","createVNode","createTextVNode","toDisplayString","unref","createElementVNode","createElementBlock","$event","normalizeClass","cn","normalizeStyle","Fragment","renderList","handle","tool","resolveDynamicComponent","key","fallback","withKeys","withModifiers","axis","createCommentVNode"],"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":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KeyValueField.js","names":["_sfc_main","KeyValueField_vue_vue_type_script_setup_true_lang_default","KeyValueField_default"],"sources":["../../../src/components/fields/KeyValueField.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n fieldIds,\n moveRepeaterItem,\n reorderedItemKeys,\n resolveItemAction,\n type KeyValueSchema,\n} from '@alfakit/core'\nimport { ChevronDownIcon, ChevronUpIcon } from '@lucide/vue'\nimport { computed, ref } from 'vue'\nimport { cn } from '../../lib/utils'\nimport { useField } from '../form/form-context'\nimport { useFieldActionContext } from '../schema/field-actions'\nimport FieldWrapper from '../schema/FieldWrapper.vue'\nimport Button from '../ui/Button.vue'\nimport Input from '../ui/Input.vue'\nimport { useT } from '../../context'\nimport ItemActionButton from './ItemActionButton.vue'\nimport { useItemMoves, useRunItemAction } from './item-actions'\n\ntype Row = { key: string; value: string }\n\n/**\n * The server stores an object; while editing we keep an ordered list of rows so keys\n * can be typed freely (including temporarily duplicate or empty keys).\n */\nconst props = defineProps<{ component: KeyValueSchema }>()\nconst { value, setValue, blur, error, id, disabled, readOnly, aria } = useField<\n Record<string, unknown> | Row[] | null\n>(() => props.component)\n\nconst rows = computed<Row[]>(() => {\n if (Array.isArray(value.value)) {\n return value.value.map((row) => ({\n key: String(row.key ?? ''),\n value: row.value === null || row.value === undefined ? '' : String(row.value),\n }))\n }\n\n return Object.entries(value.value ?? {}).map(([key, rowValue]) => ({\n key,\n value: rowValue === null || rowValue === undefined ? '' : String(rowValue),\n }))\n})\n\nconst update = (next: Row[]) => setValue(next)\nconst patch = (index: number, change: Partial<Row>) =>\n update(rows.value.map((item, i) => (i === index ? { ...item, ...change } : item)))\nconst t = useT()\n\nconst context = useFieldActionContext(() => props.component)\nconst runItemAction = useRunItemAction(context)\nconst addAction = computed(() =>\n resolveItemAction('add', props.component, undefined, {\n label: props.component.addActionLabel,\n icon: 'plus',\n variant: 'ghost',\n }),\n)\nconst deleteAction = computed(() =>\n resolveItemAction('delete', props.component, undefined, {\n label: t('form.remove_row', {}, 'Remove row'),\n icon: 'trash-2',\n }),\n)\nconst reorderAction = computed(() =>\n resolveItemAction('reorder', props.component, undefined, {\n label: t('form.reorder_item', {}, 'Reorder'),\n icon: 'grip-vertical',\n }),\n)\nconst deletable = computed(\n () => props.component.deletable && !readOnly.value && deleteAction.value !== null,\n)\nconst reorderable = computed(\n () =>\n props.component.reorderable &&\n !readOnly.value &&\n !disabled.value &&\n reorderAction.value !== null,\n)\nconst dragIndex = ref<number | null>(null)\n// Moving runs the reorder action: in the browser, or on the server when customised.\nconst move = (from: number, to: number) =>\n runItemAction(\n reorderAction.value,\n { items: reorderedItemKeys(rows.value.length, from, to) },\n () => update(moveRepeaterItem(rows.value, from, to) as Row[]),\n )\n// Move buttons: announced, one at a time, focus kept on the moved row.\nconst moves = useItemMoves(\n value,\n move,\n (index) => rows.value[index]?.key || null,\n () => rows.value.length,\n)\nconst moveAnnouncement = moves.announcement\nconst moveContainer = moves.container\nconst onRowDrop = (index: number) => {\n if (dragIndex.value !== null && dragIndex.value !== index) move(dragIndex.value, index)\n dragIndex.value = null\n}\n</script>\n\n<template>\n <FieldWrapper :field=\"props.component\" :html-for=\"id\" :error=\"error\">\n <div ref=\"moveContainer\" class=\"overflow-hidden rounded-md border\">\n <span aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\" data-slot=\"item-move-status\">{{\n moveAnnouncement\n }}</span>\n <table\n class=\"w-full text-sm\"\n :aria-labelledby=\"props.component.label ? fieldIds(id).label : undefined\"\n :aria-describedby=\"aria['aria-describedby']\"\n >\n <thead class=\"bg-muted/50 text-muted-foreground text-xs\">\n <tr>\n <th v-if=\"reorderable\" class=\"w-16\" />\n <th class=\"px-3 py-2 text-start font-medium\">{{ props.component.keyLabel }}</th>\n <th class=\"px-3 py-2 text-start font-medium\">{{ props.component.valueLabel }}</th>\n <th v-if=\"deletable\" class=\"w-10\" />\n </tr>\n </thead>\n <tbody>\n <tr\n v-for=\"(row, index) in rows\"\n :key=\"index\"\n :data-index=\"index\"\n :draggable=\"reorderable\"\n :class=\"cn('border-t', dragIndex === index && 'opacity-50')\"\n @dragstart=\"dragIndex = index\"\n @dragover=\"reorderable && $event.preventDefault()\"\n @drop=\"onRowDrop(index)\"\n @dragend=\"dragIndex = null\"\n >\n <td v-if=\"reorderable\" class=\"p-1.5\">\n <div class=\"flex items-center\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :aria-label=\"t('form.move_up', {}, 'Move up')\"\n :disabled=\"index === 0\"\n data-item-move=\"up\"\n @click=\"moves.moveWithButton(index, index - 1)\"\n ><ChevronUpIcon\n /></Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :aria-label=\"t('form.move_down', {}, 'Move down')\"\n :disabled=\"index === rows.length - 1\"\n data-item-move=\"down\"\n @click=\"moves.moveWithButton(index, index + 1)\"\n ><ChevronDownIcon\n /></Button>\n </div>\n </td>\n <td class=\"p-1.5\">\n <Input\n dir=\"auto\"\n :model-value=\"row.key\"\n :readonly=\"readOnly || !props.component.editableKeys\"\n :disabled=\"disabled\"\n :placeholder=\"props.component.keyPlaceholder\"\n :aria-label=\"props.component.keyLabel\"\n :aria-invalid=\"aria['aria-invalid']\"\n class=\"h-8\"\n @update:model-value=\"patch(index, { key: $event })\"\n @blur=\"blur\"\n />\n </td>\n <td class=\"p-1.5\">\n <Input\n dir=\"auto\"\n :model-value=\"row.value\"\n :readonly=\"readOnly || !props.component.editableValues\"\n :disabled=\"disabled\"\n :placeholder=\"props.component.valuePlaceholder\"\n :aria-label=\"props.component.valueLabel\"\n :aria-invalid=\"aria['aria-invalid']\"\n class=\"h-8\"\n @update:model-value=\"patch(index, { value: $event })\"\n @blur=\"blur\"\n />\n </td>\n <td v-if=\"deletable\" class=\"p-1.5\">\n <ItemActionButton\n :action=\"deleteAction\"\n :context=\"context\"\n :args=\"{ item: String(index) }\"\n size=\"sm\"\n :disabled=\"disabled\"\n class=\"text-muted-foreground\"\n @client=\"update(rows.filter((_, i) => i !== index))\"\n />\n </td>\n </tr>\n <tr v-if=\"rows.length === 0\" class=\"border-t\">\n <td\n :colspan=\"reorderable ? 4 : 3\"\n class=\"text-muted-foreground px-3 py-4 text-center text-xs\"\n >\n —\n </td>\n </tr>\n </tbody>\n </table>\n <div v-if=\"props.component.addable && !readOnly && addAction\" class=\"border-t p-1.5\">\n <ItemActionButton\n :action=\"addAction\"\n :context=\"context\"\n size=\"sm\"\n :disabled=\"disabled\"\n @client=\"update([...rows, { key: '', value: '' }])\"\n />\n </div>\n </div>\n </FieldWrapper>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"KeyValueField.js","names":["_sfc_main","KeyValueField_vue_vue_type_script_setup_true_lang_default","KeyValueField_default"],"sources":["../../../src/components/fields/KeyValueField.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n fieldIds,\n moveRepeaterItem,\n reorderedItemKeys,\n resolveItemAction,\n type KeyValueSchema,\n itemActionIcon,\n} from '@alfakit/core'\nimport { ChevronDownIcon, ChevronUpIcon } from '@lucide/vue'\nimport { computed, ref } from 'vue'\nimport { cn } from '../../lib/utils'\nimport { useField } from '../form/form-context'\nimport { useFieldActionContext } from '../schema/field-actions'\nimport FieldWrapper from '../schema/FieldWrapper.vue'\nimport Button from '../ui/Button.vue'\nimport Input from '../ui/Input.vue'\nimport { useT } from '../../context'\nimport ItemActionButton from './ItemActionButton.vue'\nimport { useItemMoves, useRunItemAction } from './item-actions'\n\ntype Row = { key: string; value: string }\n\n/**\n * The server stores an object; while editing we keep an ordered list of rows so keys\n * can be typed freely (including temporarily duplicate or empty keys).\n */\nconst props = defineProps<{ component: KeyValueSchema }>()\nconst { value, setValue, blur, error, id, disabled, readOnly, aria } = useField<\n Record<string, unknown> | Row[] | null\n>(() => props.component)\n\nconst rows = computed<Row[]>(() => {\n if (Array.isArray(value.value)) {\n return value.value.map((row) => ({\n key: String(row.key ?? ''),\n value: row.value === null || row.value === undefined ? '' : String(row.value),\n }))\n }\n\n return Object.entries(value.value ?? {}).map(([key, rowValue]) => ({\n key,\n value: rowValue === null || rowValue === undefined ? '' : String(rowValue),\n }))\n})\n\nconst update = (next: Row[]) => setValue(next)\nconst patch = (index: number, change: Partial<Row>) =>\n update(rows.value.map((item, i) => (i === index ? { ...item, ...change } : item)))\nconst t = useT()\n\nconst context = useFieldActionContext(() => props.component)\nconst runItemAction = useRunItemAction(context)\nconst addAction = computed(() =>\n resolveItemAction('add', props.component, undefined, {\n label: props.component.addActionLabel,\n icon: 'plus',\n variant: 'ghost',\n }),\n)\nconst deleteAction = computed(() =>\n resolveItemAction('delete', props.component, undefined, {\n label: t('form.remove_row', {}, 'Remove row'),\n icon: itemActionIcon('key-value', 'delete', 'trash-2'),\n }),\n)\nconst reorderAction = computed(() =>\n resolveItemAction('reorder', props.component, undefined, {\n label: t('form.reorder_item', {}, 'Reorder'),\n icon: itemActionIcon('key-value', 'reorder', 'grip-vertical'),\n }),\n)\nconst deletable = computed(\n () => props.component.deletable && !readOnly.value && deleteAction.value !== null,\n)\nconst reorderable = computed(\n () =>\n props.component.reorderable &&\n !readOnly.value &&\n !disabled.value &&\n reorderAction.value !== null,\n)\nconst dragIndex = ref<number | null>(null)\n// Moving runs the reorder action: in the browser, or on the server when customised.\nconst move = (from: number, to: number) =>\n runItemAction(\n reorderAction.value,\n { items: reorderedItemKeys(rows.value.length, from, to) },\n () => update(moveRepeaterItem(rows.value, from, to) as Row[]),\n )\n// Move buttons: announced, one at a time, focus kept on the moved row.\nconst moves = useItemMoves(\n value,\n move,\n (index) => rows.value[index]?.key || null,\n () => rows.value.length,\n)\nconst moveAnnouncement = moves.announcement\nconst moveContainer = moves.container\nconst onRowDrop = (index: number) => {\n if (dragIndex.value !== null && dragIndex.value !== index) move(dragIndex.value, index)\n dragIndex.value = null\n}\n</script>\n\n<template>\n <FieldWrapper :field=\"props.component\" :html-for=\"id\" :error=\"error\">\n <div ref=\"moveContainer\" class=\"overflow-hidden rounded-md border\">\n <span aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\" data-slot=\"item-move-status\">{{\n moveAnnouncement\n }}</span>\n <table\n class=\"w-full text-sm\"\n :aria-labelledby=\"props.component.label ? fieldIds(id).label : undefined\"\n :aria-describedby=\"aria['aria-describedby']\"\n >\n <thead class=\"bg-muted/50 text-muted-foreground text-xs\">\n <tr>\n <th v-if=\"reorderable\" class=\"w-16\" />\n <th class=\"px-3 py-2 text-start font-medium\">{{ props.component.keyLabel }}</th>\n <th class=\"px-3 py-2 text-start font-medium\">{{ props.component.valueLabel }}</th>\n <th v-if=\"deletable\" class=\"w-10\" />\n </tr>\n </thead>\n <tbody>\n <tr\n v-for=\"(row, index) in rows\"\n :key=\"index\"\n :data-index=\"index\"\n :draggable=\"reorderable\"\n :class=\"cn('border-t', dragIndex === index && 'opacity-50')\"\n @dragstart=\"dragIndex = index\"\n @dragover=\"reorderable && $event.preventDefault()\"\n @drop=\"onRowDrop(index)\"\n @dragend=\"dragIndex = null\"\n >\n <td v-if=\"reorderable\" class=\"p-1.5\">\n <div class=\"flex items-center\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :aria-label=\"t('form.move_up', {}, 'Move up')\"\n :disabled=\"index === 0\"\n data-item-move=\"up\"\n @click=\"moves.moveWithButton(index, index - 1)\"\n ><ChevronUpIcon\n /></Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :aria-label=\"t('form.move_down', {}, 'Move down')\"\n :disabled=\"index === rows.length - 1\"\n data-item-move=\"down\"\n @click=\"moves.moveWithButton(index, index + 1)\"\n ><ChevronDownIcon\n /></Button>\n </div>\n </td>\n <td class=\"p-1.5\">\n <Input\n dir=\"auto\"\n :model-value=\"row.key\"\n :readonly=\"readOnly || !props.component.editableKeys\"\n :disabled=\"disabled\"\n :placeholder=\"props.component.keyPlaceholder\"\n :aria-label=\"props.component.keyLabel\"\n :aria-invalid=\"aria['aria-invalid']\"\n class=\"h-8\"\n @update:model-value=\"patch(index, { key: $event })\"\n @blur=\"blur\"\n />\n </td>\n <td class=\"p-1.5\">\n <Input\n dir=\"auto\"\n :model-value=\"row.value\"\n :readonly=\"readOnly || !props.component.editableValues\"\n :disabled=\"disabled\"\n :placeholder=\"props.component.valuePlaceholder\"\n :aria-label=\"props.component.valueLabel\"\n :aria-invalid=\"aria['aria-invalid']\"\n class=\"h-8\"\n @update:model-value=\"patch(index, { value: $event })\"\n @blur=\"blur\"\n />\n </td>\n <td v-if=\"deletable\" class=\"p-1.5\">\n <ItemActionButton\n :action=\"deleteAction\"\n :context=\"context\"\n :args=\"{ item: String(index) }\"\n size=\"sm\"\n :disabled=\"disabled\"\n class=\"text-muted-foreground\"\n @client=\"update(rows.filter((_, i) => i !== index))\"\n />\n </td>\n </tr>\n <tr v-if=\"rows.length === 0\" class=\"border-t\">\n <td\n :colspan=\"reorderable ? 4 : 3\"\n class=\"text-muted-foreground px-3 py-4 text-center text-xs\"\n >\n —\n </td>\n </tr>\n </tbody>\n </table>\n <div v-if=\"props.component.addable && !readOnly && addAction\" class=\"border-t p-1.5\">\n <ItemActionButton\n :action=\"addAction\"\n :context=\"context\"\n size=\"sm\"\n :disabled=\"disabled\"\n @client=\"update([...rows, { key: '', value: '' }])\"\n />\n </div>\n </div>\n </FieldWrapper>\n</template>\n"],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KeyValueField.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fields/KeyValueField.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"KeyValueField.vue.d.ts","sourceRoot":"","sources":["../../../src/components/fields/KeyValueField.vue"],"names":[],"mappings":"AAgOA,OAAO,EAKL,KAAK,cAAc,EAEpB,MAAM,eAAe,CAAA;AAetB;;;GAGG;AACH,KAAK,WAAW,GAAG;IAAE,SAAS,EAAE,cAAc,CAAA;CAAE,CAAC;;AAkejD,wBAMG"}
|
|
@@ -4,30 +4,30 @@ import n from "../ui/Button2.js";
|
|
|
4
4
|
import { useField as r } from "../form/form-context.js";
|
|
5
5
|
import i from "../ui/Input.js";
|
|
6
6
|
import { useFieldActionContext as a } from "../schema/field-actions.js";
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import { useItemMoves as
|
|
10
|
-
import { fieldIds as
|
|
11
|
-
import { Fragment as re, computed as
|
|
12
|
-
import { ChevronDownIcon as
|
|
7
|
+
import o from "../schema/FieldWrapper.js";
|
|
8
|
+
import s from "./ItemActionButton.js";
|
|
9
|
+
import { useItemMoves as c, useRunItemAction as l } from "./item-actions.js";
|
|
10
|
+
import { fieldIds as ee, itemActionIcon as u, moveRepeaterItem as te, reorderedItemKeys as ne, resolveItemAction as d } from "@alfakit/core";
|
|
11
|
+
import { Fragment as re, computed as f, createBlock as p, createCommentVNode as m, createElementBlock as h, createElementVNode as g, createVNode as _, defineComponent as v, normalizeClass as ie, openBlock as y, ref as ae, renderList as oe, toDisplayString as b, unref as x, withCtx as S } from "vue";
|
|
12
|
+
import { ChevronDownIcon as C, ChevronUpIcon as w } from "@lucide/vue";
|
|
13
13
|
//#region src/components/fields/KeyValueField.vue?vue&type=script&setup=true&lang.ts
|
|
14
|
-
var
|
|
14
|
+
var se = {
|
|
15
15
|
"aria-live": "polite",
|
|
16
16
|
"aria-atomic": "true",
|
|
17
17
|
class: "sr-only",
|
|
18
18
|
"data-slot": "item-move-status"
|
|
19
|
-
},
|
|
19
|
+
}, ce = ["aria-labelledby", "aria-describedby"], le = { class: "bg-muted/50 text-muted-foreground text-xs" }, ue = {
|
|
20
20
|
key: 0,
|
|
21
21
|
class: "w-16"
|
|
22
|
-
},
|
|
22
|
+
}, de = { class: "px-3 py-2 text-start font-medium" }, fe = { class: "px-3 py-2 text-start font-medium" }, pe = {
|
|
23
23
|
key: 1,
|
|
24
24
|
class: "w-10"
|
|
25
|
-
},
|
|
25
|
+
}, me = [
|
|
26
26
|
"data-index",
|
|
27
27
|
"draggable",
|
|
28
28
|
"onDragstart",
|
|
29
29
|
"onDrop"
|
|
30
|
-
],
|
|
30
|
+
], he = {
|
|
31
31
|
key: 0,
|
|
32
32
|
class: "p-1.5"
|
|
33
33
|
}, T = { class: "flex items-center" }, E = { class: "p-1.5" }, D = { class: "p-1.5" }, O = {
|
|
@@ -39,11 +39,11 @@ var w = {
|
|
|
39
39
|
}, A = ["colspan"], j = {
|
|
40
40
|
key: 0,
|
|
41
41
|
class: "border-t p-1.5"
|
|
42
|
-
}, M = /*@__PURE__*/
|
|
42
|
+
}, M = /*@__PURE__*/ v({
|
|
43
43
|
__name: "KeyValueField",
|
|
44
44
|
props: { component: {} },
|
|
45
|
-
setup(
|
|
46
|
-
let M =
|
|
45
|
+
setup(v) {
|
|
46
|
+
let M = v, { value: N, setValue: P, blur: F, error: I, id: L, disabled: R, readOnly: z, aria: B } = r(() => M.component), V = f(() => Array.isArray(N.value) ? N.value.map((e) => ({
|
|
47
47
|
key: String(e.key ?? ""),
|
|
48
48
|
value: e.value === null || e.value === void 0 ? "" : String(e.value)
|
|
49
49
|
})) : Object.entries(N.value ?? {}).map(([e, t]) => ({
|
|
@@ -52,91 +52,91 @@ var w = {
|
|
|
52
52
|
}))), H = (e) => P(e), U = (e, t) => H(V.value.map((n, r) => r === e ? {
|
|
53
53
|
...n,
|
|
54
54
|
...t
|
|
55
|
-
} : n)), W = e(), G = a(() => M.component),
|
|
55
|
+
} : n)), W = e(), G = a(() => M.component), ge = l(G), K = f(() => d("add", M.component, void 0, {
|
|
56
56
|
label: M.component.addActionLabel,
|
|
57
57
|
icon: "plus",
|
|
58
58
|
variant: "ghost"
|
|
59
|
-
})), q =
|
|
59
|
+
})), q = f(() => d("delete", M.component, void 0, {
|
|
60
60
|
label: W("form.remove_row", {}, "Remove row"),
|
|
61
|
-
icon: "trash-2"
|
|
62
|
-
})), J =
|
|
61
|
+
icon: u("key-value", "delete", "trash-2")
|
|
62
|
+
})), J = f(() => d("reorder", M.component, void 0, {
|
|
63
63
|
label: W("form.reorder_item", {}, "Reorder"),
|
|
64
|
-
icon: "grip-vertical"
|
|
65
|
-
})), Y =
|
|
64
|
+
icon: u("key-value", "reorder", "grip-vertical")
|
|
65
|
+
})), Y = f(() => M.component.deletable && !z.value && q.value !== null), X = f(() => M.component.reorderable && !z.value && !R.value && J.value !== null), Z = ae(null), Q = (e, t) => ge(J.value, { items: ne(V.value.length, e, t) }, () => H(te(V.value, e, t))), $ = c(N, Q, (e) => V.value[e]?.key || null, () => V.value.length), _e = $.announcement, ve = $.container, ye = (e) => {
|
|
66
66
|
Z.value !== null && Z.value !== e && Q(Z.value, e), Z.value = null;
|
|
67
67
|
};
|
|
68
|
-
return (e, r) => (
|
|
68
|
+
return (e, r) => (y(), p(o, {
|
|
69
69
|
field: M.component,
|
|
70
|
-
"html-for":
|
|
71
|
-
error:
|
|
70
|
+
"html-for": x(L),
|
|
71
|
+
error: x(I)
|
|
72
72
|
}, {
|
|
73
|
-
default:
|
|
73
|
+
default: S(() => [g("div", {
|
|
74
74
|
ref_key: "moveContainer",
|
|
75
|
-
ref:
|
|
75
|
+
ref: ve,
|
|
76
76
|
class: "overflow-hidden rounded-md border"
|
|
77
77
|
}, [
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
g("span", se, b(x(_e)), 1),
|
|
79
|
+
g("table", {
|
|
80
80
|
class: "w-full text-sm",
|
|
81
|
-
"aria-labelledby": M.component.label ?
|
|
82
|
-
"aria-describedby":
|
|
83
|
-
}, [
|
|
84
|
-
X.value ? (
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
Y.value ? (
|
|
88
|
-
])]),
|
|
81
|
+
"aria-labelledby": M.component.label ? x(ee)(x(L)).label : void 0,
|
|
82
|
+
"aria-describedby": x(B)["aria-describedby"]
|
|
83
|
+
}, [g("thead", le, [g("tr", null, [
|
|
84
|
+
X.value ? (y(), h("th", ue)) : m("", !0),
|
|
85
|
+
g("th", de, b(M.component.keyLabel), 1),
|
|
86
|
+
g("th", fe, b(M.component.valueLabel), 1),
|
|
87
|
+
Y.value ? (y(), h("th", pe)) : m("", !0)
|
|
88
|
+
])]), g("tbody", null, [(y(!0), h(re, null, oe(V.value, (e, a) => (y(), h("tr", {
|
|
89
89
|
key: a,
|
|
90
90
|
"data-index": a,
|
|
91
91
|
draggable: X.value,
|
|
92
|
-
class: ie(
|
|
92
|
+
class: ie(x(t)("border-t", Z.value === a && "opacity-50")),
|
|
93
93
|
onDragstart: (e) => Z.value = a,
|
|
94
94
|
onDragover: r[0] ||= (e) => X.value && e.preventDefault(),
|
|
95
|
-
onDrop: (e) =>
|
|
95
|
+
onDrop: (e) => ye(a),
|
|
96
96
|
onDragend: r[1] ||= (e) => Z.value = null
|
|
97
97
|
}, [
|
|
98
|
-
X.value ? (
|
|
98
|
+
X.value ? (y(), h("td", he, [g("div", T, [_(n, {
|
|
99
99
|
type: "button",
|
|
100
100
|
variant: "ghost",
|
|
101
101
|
size: "icon-xs",
|
|
102
|
-
"aria-label":
|
|
102
|
+
"aria-label": x(W)("form.move_up", {}, "Move up"),
|
|
103
103
|
disabled: a === 0,
|
|
104
104
|
"data-item-move": "up",
|
|
105
|
-
onClick: (e) =>
|
|
105
|
+
onClick: (e) => x($).moveWithButton(a, a - 1)
|
|
106
106
|
}, {
|
|
107
|
-
default:
|
|
107
|
+
default: S(() => [_(x(w))]),
|
|
108
108
|
_: 1
|
|
109
109
|
}, 8, [
|
|
110
110
|
"aria-label",
|
|
111
111
|
"disabled",
|
|
112
112
|
"onClick"
|
|
113
|
-
]),
|
|
113
|
+
]), _(n, {
|
|
114
114
|
type: "button",
|
|
115
115
|
variant: "ghost",
|
|
116
116
|
size: "icon-xs",
|
|
117
|
-
"aria-label":
|
|
117
|
+
"aria-label": x(W)("form.move_down", {}, "Move down"),
|
|
118
118
|
disabled: a === V.value.length - 1,
|
|
119
119
|
"data-item-move": "down",
|
|
120
|
-
onClick: (e) =>
|
|
120
|
+
onClick: (e) => x($).moveWithButton(a, a + 1)
|
|
121
121
|
}, {
|
|
122
|
-
default:
|
|
122
|
+
default: S(() => [_(x(C))]),
|
|
123
123
|
_: 1
|
|
124
124
|
}, 8, [
|
|
125
125
|
"aria-label",
|
|
126
126
|
"disabled",
|
|
127
127
|
"onClick"
|
|
128
|
-
])])])) :
|
|
129
|
-
|
|
128
|
+
])])])) : m("", !0),
|
|
129
|
+
g("td", E, [_(i, {
|
|
130
130
|
dir: "auto",
|
|
131
131
|
"model-value": e.key,
|
|
132
|
-
readonly:
|
|
133
|
-
disabled:
|
|
132
|
+
readonly: x(z) || !M.component.editableKeys,
|
|
133
|
+
disabled: x(R),
|
|
134
134
|
placeholder: M.component.keyPlaceholder,
|
|
135
135
|
"aria-label": M.component.keyLabel,
|
|
136
|
-
"aria-invalid":
|
|
136
|
+
"aria-invalid": x(B)["aria-invalid"],
|
|
137
137
|
class: "h-8",
|
|
138
138
|
"onUpdate:modelValue": (e) => U(a, { key: e }),
|
|
139
|
-
onBlur:
|
|
139
|
+
onBlur: x(F)
|
|
140
140
|
}, null, 8, [
|
|
141
141
|
"model-value",
|
|
142
142
|
"readonly",
|
|
@@ -147,17 +147,17 @@ var w = {
|
|
|
147
147
|
"onUpdate:modelValue",
|
|
148
148
|
"onBlur"
|
|
149
149
|
])]),
|
|
150
|
-
|
|
150
|
+
g("td", D, [_(i, {
|
|
151
151
|
dir: "auto",
|
|
152
152
|
"model-value": e.value,
|
|
153
|
-
readonly:
|
|
154
|
-
disabled:
|
|
153
|
+
readonly: x(z) || !M.component.editableValues,
|
|
154
|
+
disabled: x(R),
|
|
155
155
|
placeholder: M.component.valuePlaceholder,
|
|
156
156
|
"aria-label": M.component.valueLabel,
|
|
157
|
-
"aria-invalid":
|
|
157
|
+
"aria-invalid": x(B)["aria-invalid"],
|
|
158
158
|
class: "h-8",
|
|
159
159
|
"onUpdate:modelValue": (e) => U(a, { value: e }),
|
|
160
|
-
onBlur:
|
|
160
|
+
onBlur: x(F)
|
|
161
161
|
}, null, 8, [
|
|
162
162
|
"model-value",
|
|
163
163
|
"readonly",
|
|
@@ -168,12 +168,12 @@ var w = {
|
|
|
168
168
|
"onUpdate:modelValue",
|
|
169
169
|
"onBlur"
|
|
170
170
|
])]),
|
|
171
|
-
Y.value ? (
|
|
171
|
+
Y.value ? (y(), h("td", O, [_(s, {
|
|
172
172
|
action: q.value,
|
|
173
|
-
context:
|
|
173
|
+
context: x(G),
|
|
174
174
|
args: { item: String(a) },
|
|
175
175
|
size: "sm",
|
|
176
|
-
disabled:
|
|
176
|
+
disabled: x(R),
|
|
177
177
|
class: "text-muted-foreground",
|
|
178
178
|
onClient: (e) => H(V.value.filter((e, t) => t !== a))
|
|
179
179
|
}, null, 8, [
|
|
@@ -182,16 +182,16 @@ var w = {
|
|
|
182
182
|
"args",
|
|
183
183
|
"disabled",
|
|
184
184
|
"onClient"
|
|
185
|
-
])])) :
|
|
186
|
-
], 42,
|
|
185
|
+
])])) : m("", !0)
|
|
186
|
+
], 42, me))), 128)), V.value.length === 0 ? (y(), h("tr", k, [g("td", {
|
|
187
187
|
colspan: X.value ? 4 : 3,
|
|
188
188
|
class: "text-muted-foreground px-3 py-4 text-center text-xs"
|
|
189
|
-
}, " — ", 8, A)])) :
|
|
190
|
-
M.component.addable && !
|
|
189
|
+
}, " — ", 8, A)])) : m("", !0)])], 8, ce),
|
|
190
|
+
M.component.addable && !x(z) && K.value ? (y(), h("div", j, [_(s, {
|
|
191
191
|
action: K.value,
|
|
192
|
-
context:
|
|
192
|
+
context: x(G),
|
|
193
193
|
size: "sm",
|
|
194
|
-
disabled:
|
|
194
|
+
disabled: x(R),
|
|
195
195
|
onClient: r[2] ||= (e) => H([...V.value, {
|
|
196
196
|
key: "",
|
|
197
197
|
value: ""
|
|
@@ -200,7 +200,7 @@ var w = {
|
|
|
200
200
|
"action",
|
|
201
201
|
"context",
|
|
202
202
|
"disabled"
|
|
203
|
-
])])) :
|
|
203
|
+
])])) : m("", !0)
|
|
204
204
|
], 512)]),
|
|
205
205
|
_: 1
|
|
206
206
|
}, 8, [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"KeyValueField.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","FieldWrapper","_unref","_withCtx","_createElementVNode","_toDisplayString","_createElementBlock","_createCommentVNode","_Fragment","_renderList","_normalizeClass","_createVNode","Button","Input","ItemActionButton","Button_default","Input_default","FieldWrapper_default","ItemActionButton_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","KeyValueField_vue_vue_type_script_setup_true_lang_default","props","__props","useField","rows","computed","value","row","key","rowValue","update","setValue","next","patch","i","index","item","change","t","useT","context","useFieldActionContext","runItemAction","useRunItemAction","addAction","resolveItemAction","deleteAction","reorderAction","deletable","readOnly","reorderable","disabled","dragIndex","ref","move","reorderedItemKeys","from","to","moveRepeaterItem","moves","useItemMoves","moveAnnouncement","moveContainer","onRowDrop","openBlock","createBlock","unref","id","error","withCtx","createElementVNode","toDisplayString","fieldIds","aria","createElementBlock","createCommentVNode","Fragment","renderList","normalizeClass","cn","_cache","$event","createVNode","ChevronUpIcon","ChevronDownIcon","blur"],"sources":["../../../src/components/fields/KeyValueField.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n fieldIds,\n moveRepeaterItem,\n reorderedItemKeys,\n resolveItemAction,\n type KeyValueSchema,\n} from '@alfakit/core'\nimport { ChevronDownIcon, ChevronUpIcon } from '@lucide/vue'\nimport { computed, ref } from 'vue'\nimport { cn } from '../../lib/utils'\nimport { useField } from '../form/form-context'\nimport { useFieldActionContext } from '../schema/field-actions'\nimport FieldWrapper from '../schema/FieldWrapper.vue'\nimport Button from '../ui/Button.vue'\nimport Input from '../ui/Input.vue'\nimport { useT } from '../../context'\nimport ItemActionButton from './ItemActionButton.vue'\nimport { useItemMoves, useRunItemAction } from './item-actions'\n\ntype Row = { key: string; value: string }\n\n/**\n * The server stores an object; while editing we keep an ordered list of rows so keys\n * can be typed freely (including temporarily duplicate or empty keys).\n */\nconst props = defineProps<{ component: KeyValueSchema }>()\nconst { value, setValue, blur, error, id, disabled, readOnly, aria } = useField<\n Record<string, unknown> | Row[] | null\n>(() => props.component)\n\nconst rows = computed<Row[]>(() => {\n if (Array.isArray(value.value)) {\n return value.value.map((row) => ({\n key: String(row.key ?? ''),\n value: row.value === null || row.value === undefined ? '' : String(row.value),\n }))\n }\n\n return Object.entries(value.value ?? {}).map(([key, rowValue]) => ({\n key,\n value: rowValue === null || rowValue === undefined ? '' : String(rowValue),\n }))\n})\n\nconst update = (next: Row[]) => setValue(next)\nconst patch = (index: number, change: Partial<Row>) =>\n update(rows.value.map((item, i) => (i === index ? { ...item, ...change } : item)))\nconst t = useT()\n\nconst context = useFieldActionContext(() => props.component)\nconst runItemAction = useRunItemAction(context)\nconst addAction = computed(() =>\n resolveItemAction('add', props.component, undefined, {\n label: props.component.addActionLabel,\n icon: 'plus',\n variant: 'ghost',\n }),\n)\nconst deleteAction = computed(() =>\n resolveItemAction('delete', props.component, undefined, {\n label: t('form.remove_row', {}, 'Remove row'),\n icon: 'trash-2',\n }),\n)\nconst reorderAction = computed(() =>\n resolveItemAction('reorder', props.component, undefined, {\n label: t('form.reorder_item', {}, 'Reorder'),\n icon: 'grip-vertical',\n }),\n)\nconst deletable = computed(\n () => props.component.deletable && !readOnly.value && deleteAction.value !== null,\n)\nconst reorderable = computed(\n () =>\n props.component.reorderable &&\n !readOnly.value &&\n !disabled.value &&\n reorderAction.value !== null,\n)\nconst dragIndex = ref<number | null>(null)\n// Moving runs the reorder action: in the browser, or on the server when customised.\nconst move = (from: number, to: number) =>\n runItemAction(\n reorderAction.value,\n { items: reorderedItemKeys(rows.value.length, from, to) },\n () => update(moveRepeaterItem(rows.value, from, to) as Row[]),\n )\n// Move buttons: announced, one at a time, focus kept on the moved row.\nconst moves = useItemMoves(\n value,\n move,\n (index) => rows.value[index]?.key || null,\n () => rows.value.length,\n)\nconst moveAnnouncement = moves.announcement\nconst moveContainer = moves.container\nconst onRowDrop = (index: number) => {\n if (dragIndex.value !== null && dragIndex.value !== index) move(dragIndex.value, index)\n dragIndex.value = null\n}\n</script>\n\n<template>\n <FieldWrapper :field=\"props.component\" :html-for=\"id\" :error=\"error\">\n <div ref=\"moveContainer\" class=\"overflow-hidden rounded-md border\">\n <span aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\" data-slot=\"item-move-status\">{{\n moveAnnouncement\n }}</span>\n <table\n class=\"w-full text-sm\"\n :aria-labelledby=\"props.component.label ? fieldIds(id).label : undefined\"\n :aria-describedby=\"aria['aria-describedby']\"\n >\n <thead class=\"bg-muted/50 text-muted-foreground text-xs\">\n <tr>\n <th v-if=\"reorderable\" class=\"w-16\" />\n <th class=\"px-3 py-2 text-start font-medium\">{{ props.component.keyLabel }}</th>\n <th class=\"px-3 py-2 text-start font-medium\">{{ props.component.valueLabel }}</th>\n <th v-if=\"deletable\" class=\"w-10\" />\n </tr>\n </thead>\n <tbody>\n <tr\n v-for=\"(row, index) in rows\"\n :key=\"index\"\n :data-index=\"index\"\n :draggable=\"reorderable\"\n :class=\"cn('border-t', dragIndex === index && 'opacity-50')\"\n @dragstart=\"dragIndex = index\"\n @dragover=\"reorderable && $event.preventDefault()\"\n @drop=\"onRowDrop(index)\"\n @dragend=\"dragIndex = null\"\n >\n <td v-if=\"reorderable\" class=\"p-1.5\">\n <div class=\"flex items-center\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :aria-label=\"t('form.move_up', {}, 'Move up')\"\n :disabled=\"index === 0\"\n data-item-move=\"up\"\n @click=\"moves.moveWithButton(index, index - 1)\"\n ><ChevronUpIcon\n /></Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :aria-label=\"t('form.move_down', {}, 'Move down')\"\n :disabled=\"index === rows.length - 1\"\n data-item-move=\"down\"\n @click=\"moves.moveWithButton(index, index + 1)\"\n ><ChevronDownIcon\n /></Button>\n </div>\n </td>\n <td class=\"p-1.5\">\n <Input\n dir=\"auto\"\n :model-value=\"row.key\"\n :readonly=\"readOnly || !props.component.editableKeys\"\n :disabled=\"disabled\"\n :placeholder=\"props.component.keyPlaceholder\"\n :aria-label=\"props.component.keyLabel\"\n :aria-invalid=\"aria['aria-invalid']\"\n class=\"h-8\"\n @update:model-value=\"patch(index, { key: $event })\"\n @blur=\"blur\"\n />\n </td>\n <td class=\"p-1.5\">\n <Input\n dir=\"auto\"\n :model-value=\"row.value\"\n :readonly=\"readOnly || !props.component.editableValues\"\n :disabled=\"disabled\"\n :placeholder=\"props.component.valuePlaceholder\"\n :aria-label=\"props.component.valueLabel\"\n :aria-invalid=\"aria['aria-invalid']\"\n class=\"h-8\"\n @update:model-value=\"patch(index, { value: $event })\"\n @blur=\"blur\"\n />\n </td>\n <td v-if=\"deletable\" class=\"p-1.5\">\n <ItemActionButton\n :action=\"deleteAction\"\n :context=\"context\"\n :args=\"{ item: String(index) }\"\n size=\"sm\"\n :disabled=\"disabled\"\n class=\"text-muted-foreground\"\n @client=\"update(rows.filter((_, i) => i !== index))\"\n />\n </td>\n </tr>\n <tr v-if=\"rows.length === 0\" class=\"border-t\">\n <td\n :colspan=\"reorderable ? 4 : 3\"\n class=\"text-muted-foreground px-3 py-4 text-center text-xs\"\n >\n —\n </td>\n </tr>\n </tbody>\n </table>\n <div v-if=\"props.component.addable && !readOnly && addAction\" class=\"border-t p-1.5\">\n <ItemActionButton\n :action=\"addAction\"\n :context=\"context\"\n size=\"sm\"\n :disabled=\"disabled\"\n @client=\"update([...rows, { key: '', value: '' }])\"\n />\n </div>\n </div>\n </FieldWrapper>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"KeyValueField.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createBlock","FieldWrapper","_unref","_withCtx","_createElementVNode","_toDisplayString","_createElementBlock","_createCommentVNode","_Fragment","_renderList","_normalizeClass","_createVNode","Button","Input","ItemActionButton","Button_default","Input_default","FieldWrapper_default","ItemActionButton_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","KeyValueField_vue_vue_type_script_setup_true_lang_default","props","__props","useField","rows","computed","value","row","key","rowValue","update","setValue","next","patch","i","index","item","change","t","useT","context","useFieldActionContext","runItemAction","useRunItemAction","addAction","resolveItemAction","deleteAction","itemActionIcon","reorderAction","deletable","readOnly","reorderable","disabled","dragIndex","ref","move","reorderedItemKeys","from","to","moveRepeaterItem","moves","useItemMoves","moveAnnouncement","moveContainer","onRowDrop","openBlock","createBlock","unref","id","error","withCtx","createElementVNode","toDisplayString","fieldIds","aria","createElementBlock","createCommentVNode","Fragment","renderList","normalizeClass","cn","_cache","$event","createVNode","ChevronUpIcon","ChevronDownIcon","blur"],"sources":["../../../src/components/fields/KeyValueField.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n fieldIds,\n moveRepeaterItem,\n reorderedItemKeys,\n resolveItemAction,\n type KeyValueSchema,\n itemActionIcon,\n} from '@alfakit/core'\nimport { ChevronDownIcon, ChevronUpIcon } from '@lucide/vue'\nimport { computed, ref } from 'vue'\nimport { cn } from '../../lib/utils'\nimport { useField } from '../form/form-context'\nimport { useFieldActionContext } from '../schema/field-actions'\nimport FieldWrapper from '../schema/FieldWrapper.vue'\nimport Button from '../ui/Button.vue'\nimport Input from '../ui/Input.vue'\nimport { useT } from '../../context'\nimport ItemActionButton from './ItemActionButton.vue'\nimport { useItemMoves, useRunItemAction } from './item-actions'\n\ntype Row = { key: string; value: string }\n\n/**\n * The server stores an object; while editing we keep an ordered list of rows so keys\n * can be typed freely (including temporarily duplicate or empty keys).\n */\nconst props = defineProps<{ component: KeyValueSchema }>()\nconst { value, setValue, blur, error, id, disabled, readOnly, aria } = useField<\n Record<string, unknown> | Row[] | null\n>(() => props.component)\n\nconst rows = computed<Row[]>(() => {\n if (Array.isArray(value.value)) {\n return value.value.map((row) => ({\n key: String(row.key ?? ''),\n value: row.value === null || row.value === undefined ? '' : String(row.value),\n }))\n }\n\n return Object.entries(value.value ?? {}).map(([key, rowValue]) => ({\n key,\n value: rowValue === null || rowValue === undefined ? '' : String(rowValue),\n }))\n})\n\nconst update = (next: Row[]) => setValue(next)\nconst patch = (index: number, change: Partial<Row>) =>\n update(rows.value.map((item, i) => (i === index ? { ...item, ...change } : item)))\nconst t = useT()\n\nconst context = useFieldActionContext(() => props.component)\nconst runItemAction = useRunItemAction(context)\nconst addAction = computed(() =>\n resolveItemAction('add', props.component, undefined, {\n label: props.component.addActionLabel,\n icon: 'plus',\n variant: 'ghost',\n }),\n)\nconst deleteAction = computed(() =>\n resolveItemAction('delete', props.component, undefined, {\n label: t('form.remove_row', {}, 'Remove row'),\n icon: itemActionIcon('key-value', 'delete', 'trash-2'),\n }),\n)\nconst reorderAction = computed(() =>\n resolveItemAction('reorder', props.component, undefined, {\n label: t('form.reorder_item', {}, 'Reorder'),\n icon: itemActionIcon('key-value', 'reorder', 'grip-vertical'),\n }),\n)\nconst deletable = computed(\n () => props.component.deletable && !readOnly.value && deleteAction.value !== null,\n)\nconst reorderable = computed(\n () =>\n props.component.reorderable &&\n !readOnly.value &&\n !disabled.value &&\n reorderAction.value !== null,\n)\nconst dragIndex = ref<number | null>(null)\n// Moving runs the reorder action: in the browser, or on the server when customised.\nconst move = (from: number, to: number) =>\n runItemAction(\n reorderAction.value,\n { items: reorderedItemKeys(rows.value.length, from, to) },\n () => update(moveRepeaterItem(rows.value, from, to) as Row[]),\n )\n// Move buttons: announced, one at a time, focus kept on the moved row.\nconst moves = useItemMoves(\n value,\n move,\n (index) => rows.value[index]?.key || null,\n () => rows.value.length,\n)\nconst moveAnnouncement = moves.announcement\nconst moveContainer = moves.container\nconst onRowDrop = (index: number) => {\n if (dragIndex.value !== null && dragIndex.value !== index) move(dragIndex.value, index)\n dragIndex.value = null\n}\n</script>\n\n<template>\n <FieldWrapper :field=\"props.component\" :html-for=\"id\" :error=\"error\">\n <div ref=\"moveContainer\" class=\"overflow-hidden rounded-md border\">\n <span aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\" data-slot=\"item-move-status\">{{\n moveAnnouncement\n }}</span>\n <table\n class=\"w-full text-sm\"\n :aria-labelledby=\"props.component.label ? fieldIds(id).label : undefined\"\n :aria-describedby=\"aria['aria-describedby']\"\n >\n <thead class=\"bg-muted/50 text-muted-foreground text-xs\">\n <tr>\n <th v-if=\"reorderable\" class=\"w-16\" />\n <th class=\"px-3 py-2 text-start font-medium\">{{ props.component.keyLabel }}</th>\n <th class=\"px-3 py-2 text-start font-medium\">{{ props.component.valueLabel }}</th>\n <th v-if=\"deletable\" class=\"w-10\" />\n </tr>\n </thead>\n <tbody>\n <tr\n v-for=\"(row, index) in rows\"\n :key=\"index\"\n :data-index=\"index\"\n :draggable=\"reorderable\"\n :class=\"cn('border-t', dragIndex === index && 'opacity-50')\"\n @dragstart=\"dragIndex = index\"\n @dragover=\"reorderable && $event.preventDefault()\"\n @drop=\"onRowDrop(index)\"\n @dragend=\"dragIndex = null\"\n >\n <td v-if=\"reorderable\" class=\"p-1.5\">\n <div class=\"flex items-center\">\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :aria-label=\"t('form.move_up', {}, 'Move up')\"\n :disabled=\"index === 0\"\n data-item-move=\"up\"\n @click=\"moves.moveWithButton(index, index - 1)\"\n ><ChevronUpIcon\n /></Button>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-xs\"\n :aria-label=\"t('form.move_down', {}, 'Move down')\"\n :disabled=\"index === rows.length - 1\"\n data-item-move=\"down\"\n @click=\"moves.moveWithButton(index, index + 1)\"\n ><ChevronDownIcon\n /></Button>\n </div>\n </td>\n <td class=\"p-1.5\">\n <Input\n dir=\"auto\"\n :model-value=\"row.key\"\n :readonly=\"readOnly || !props.component.editableKeys\"\n :disabled=\"disabled\"\n :placeholder=\"props.component.keyPlaceholder\"\n :aria-label=\"props.component.keyLabel\"\n :aria-invalid=\"aria['aria-invalid']\"\n class=\"h-8\"\n @update:model-value=\"patch(index, { key: $event })\"\n @blur=\"blur\"\n />\n </td>\n <td class=\"p-1.5\">\n <Input\n dir=\"auto\"\n :model-value=\"row.value\"\n :readonly=\"readOnly || !props.component.editableValues\"\n :disabled=\"disabled\"\n :placeholder=\"props.component.valuePlaceholder\"\n :aria-label=\"props.component.valueLabel\"\n :aria-invalid=\"aria['aria-invalid']\"\n class=\"h-8\"\n @update:model-value=\"patch(index, { value: $event })\"\n @blur=\"blur\"\n />\n </td>\n <td v-if=\"deletable\" class=\"p-1.5\">\n <ItemActionButton\n :action=\"deleteAction\"\n :context=\"context\"\n :args=\"{ item: String(index) }\"\n size=\"sm\"\n :disabled=\"disabled\"\n class=\"text-muted-foreground\"\n @client=\"update(rows.filter((_, i) => i !== index))\"\n />\n </td>\n </tr>\n <tr v-if=\"rows.length === 0\" class=\"border-t\">\n <td\n :colspan=\"reorderable ? 4 : 3\"\n class=\"text-muted-foreground px-3 py-4 text-center text-xs\"\n >\n —\n </td>\n </tr>\n </tbody>\n </table>\n <div v-if=\"props.component.addable && !readOnly && addAction\" class=\"border-t p-1.5\">\n <ItemActionButton\n :action=\"addAction\"\n :context=\"context\"\n size=\"sm\"\n :disabled=\"disabled\"\n @client=\"update([...rows, { key: '', value: '' }])\"\n />\n </div>\n </div>\n </FieldWrapper>\n</template>\n"],"mappings":"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"}
|