@mapomodule/form 2.0.0-beta.4 → 2.0.0-beta.5
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/README.md +2 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/module.d.ts.map +1 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +12 -0
- package/dist/runtime/components/fields/MapoEnhancedMediaField.vue +128 -0
- package/dist/runtime/components/fields/MapoEnhancedMediaField.vue.d.ts +16 -0
- package/dist/runtime/components/fields/MapoEnhancedMediaField.vue.d.ts.map +1 -0
- package/dist/runtime/components/fields/MapoMediaField.vue +89 -0
- package/dist/runtime/components/fields/MapoMediaField.vue.d.ts +16 -0
- package/dist/runtime/components/fields/MapoMediaField.vue.d.ts.map +1 -0
- package/dist/runtime/components/fields/MapoMediaM2mField.vue +106 -0
- package/dist/runtime/components/fields/MapoMediaM2mField.vue.d.ts +16 -0
- package/dist/runtime/components/fields/MapoMediaM2mField.vue.d.ts.map +1 -0
- package/dist/runtime/components/fields/MapoMediaUnavailable.vue +15 -0
- package/dist/runtime/components/fields/MapoMediaUnavailable.vue.d.ts +4 -0
- package/dist/runtime/components/fields/MapoMediaUnavailable.vue.d.ts.map +1 -0
- package/dist/runtime/components/fields/MapoWygEditor.vue +26 -5
- package/dist/runtime/components/fields/MapoWygEditor.vue.d.ts.map +1 -1
- package/dist/runtime/composables/useMediaManager.d.ts +17 -0
- package/dist/runtime/composables/useMediaManager.d.ts.map +1 -0
- package/dist/runtime/composables/useMediaManager.js +6 -0
- package/dist/runtime/registry/defaults.d.ts.map +1 -1
- package/dist/runtime/registry/defaults.js +8 -2
- package/dist/runtime/types/descriptor.d.ts +18 -4
- package/dist/runtime/types/descriptor.d.ts.map +1 -1
- package/dist/runtime/types/index.d.ts +2 -1
- package/dist/runtime/types/index.d.ts.map +1 -1
- package/dist/runtime/types/media.d.ts +43 -0
- package/dist/runtime/types/media.d.ts.map +1 -0
- package/dist/runtime/types/media.js +0 -0
- package/package.json +3 -2
- package/src/index.ts +5 -0
- package/src/module.ts +15 -0
- package/src/runtime/components/fields/MapoEnhancedMediaField.vue +150 -0
- package/src/runtime/components/fields/MapoMediaField.vue +101 -0
- package/src/runtime/components/fields/MapoMediaM2mField.vue +123 -0
- package/src/runtime/components/fields/MapoMediaUnavailable.vue +19 -0
- package/src/runtime/components/fields/MapoWygEditor.vue +40 -5
- package/src/runtime/composables/useMediaManager.ts +21 -0
- package/src/runtime/registry/defaults.ts +9 -1
- package/src/runtime/types/descriptor.ts +22 -7
- package/src/runtime/types/index.ts +4 -0
- package/src/runtime/types/media.ts +44 -0
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Form engine for Mapo v2 — descriptor-driven, typesafe, headless-ready admin fo
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **Descriptor-driven**: define fields as `FieldDescriptor[]` — layout, validation, i18n in one object
|
|
8
|
-
- **All field types built-in**: text, select, date/time, FK/M2M autocomplete, WYSIWYG editor, SEO preview, map, repeater
|
|
8
|
+
- **All field types built-in**: text, select, date/time, FK/M2M autocomplete, WYSIWYG editor, SEO preview, map, repeater, media pickers
|
|
9
9
|
- **Headless composable**: `useMapoForm()` for fully custom layouts; `<MapoForm>` for the default shell
|
|
10
10
|
- **Registry auto-injection**: `<MapoForm>` and `<MapoDetail>` resolve `$mapoFormRegistry` automatically — no boilerplate
|
|
11
11
|
- **Typed extension API**: `defineFormField(type, entry, opts)` to register custom fields with collision detection
|
|
@@ -16,6 +16,7 @@ Form engine for Mapo v2 — descriptor-driven, typesafe, headless-ready admin fo
|
|
|
16
16
|
- **Consistent repeater items**: `MapoRepeater` drives each item through `useMapoForm`, so nested-path keys, `translatable`, accessors, `descriptor.is` overrides and **client validation** behave identically inside a repeater
|
|
17
17
|
- **Draft persistence**: `draftKey` option on `useMapoForm()` auto-saves to localStorage every 2 s; `checkDraft()` / `draftBanner` offer restore/discard; clears on successful `submit()`
|
|
18
18
|
- **Fail-soft**: unknown field types render a non-destructive placeholder, never crash the form
|
|
19
|
+
- **Media pickers**: `media`, `media-m2m` and `enhanced-media` field types are built in; they drive the Media Manager from [`@mapomodule/uikit`](../uikit/README.md), resolved at runtime — install it to enable them
|
|
19
20
|
|
|
20
21
|
## Install
|
|
21
22
|
|
package/dist/index.d.mts
CHANGED
|
@@ -5,5 +5,5 @@ export { FocusTarget, useFocusMode } from '../dist/runtime/composables/useFocusM
|
|
|
5
5
|
export { UnsavedChangesGuardOptions, useUnsavedChangesGuard } from '../dist/runtime/composables/useUnsavedChangesGuard.js';
|
|
6
6
|
export { greaterThan, isEmpty, isNoneOf, isNotEmpty, isOneOf, lessThan, matches, matchesField, when, whenAny, whenNot } from '../dist/runtime/composables/useProgressiveDisclosure.js';
|
|
7
7
|
export { FieldGroupDescriptor, flattenFieldGroups } from '../dist/runtime/utils/flattenFieldGroups.js';
|
|
8
|
-
export { AnyFieldDescriptor, BooleanDescriptor, ColorDescriptor, CustomDescriptor, DateDescriptor, EditorDescriptor, FieldAccessor, FieldComponentEntry, FieldDescriptor, FieldRegistry, FieldType, FileDescriptor, FksDescriptor, KnownFieldType, MapDescriptor, MediaDescriptor, NumberDescriptor, PartialFieldRegistry, RepeaterDescriptor, SelectDescriptor, SeoDescriptor, TextDescriptor } from '../dist/runtime/types/index.js';
|
|
8
|
+
export { AnyFieldDescriptor, BooleanDescriptor, ColorDescriptor, CustomDescriptor, DateDescriptor, EditorDescriptor, EnhancedMediaDescriptor, EnhancedMediaValue, FieldAccessor, FieldComponentEntry, FieldDescriptor, FieldRegistry, FieldType, FileDescriptor, FksDescriptor, KnownFieldType, MapDescriptor, MediaDescriptor, MediaItem, MediaLink, MediaM2mDescriptor, NumberDescriptor, PartialFieldRegistry, RepeaterDescriptor, SelectDescriptor, SeoDescriptor, TextDescriptor } from '../dist/runtime/types/index.js';
|
|
9
9
|
import '@nuxt/schema';
|
package/dist/index.d.ts
CHANGED
|
@@ -11,5 +11,5 @@ export { when, whenAny, whenNot, matchesField, isOneOf, isNoneOf, isNotEmpty, is
|
|
|
11
11
|
export { flattenFieldGroups } from "./runtime/utils/flattenFieldGroups.js";
|
|
12
12
|
export type { FieldGroupDescriptor } from "./runtime/utils/flattenFieldGroups.js";
|
|
13
13
|
export { KnownFieldType } from "./runtime/types/index.js";
|
|
14
|
-
export type { FieldType, FieldAccessor, FieldDescriptor, AnyFieldDescriptor, TextDescriptor, NumberDescriptor, BooleanDescriptor, SelectDescriptor, FksDescriptor, DateDescriptor, ColorDescriptor, FileDescriptor, EditorDescriptor, SeoDescriptor, MapDescriptor, RepeaterDescriptor, MediaDescriptor, CustomDescriptor, FieldComponentEntry, FieldRegistry, PartialFieldRegistry, } from "./runtime/types/index.js";
|
|
14
|
+
export type { FieldType, FieldAccessor, FieldDescriptor, AnyFieldDescriptor, TextDescriptor, NumberDescriptor, BooleanDescriptor, SelectDescriptor, FksDescriptor, DateDescriptor, ColorDescriptor, FileDescriptor, EditorDescriptor, SeoDescriptor, MapDescriptor, RepeaterDescriptor, MediaDescriptor, MediaM2mDescriptor, EnhancedMediaDescriptor, CustomDescriptor, MediaLink, MediaItem, EnhancedMediaValue, FieldComponentEntry, FieldRegistry, PartialFieldRegistry, } from "./runtime/types/index.js";
|
|
15
15
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAC/E,YAAY,EAAE,wBAAwB,EAAE,MAAM,4CAA4C,CAAC;AAC3F,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AACrE,YAAY,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AACrE,YAAY,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iDAAiD,CAAC;AACzF,YAAY,EAAE,0BAA0B,EAAE,MAAM,iDAAiD,CAAC;AAElG,OAAO,EACL,IAAI,EACJ,OAAO,EACP,OAAO,EACP,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,UAAU,EACV,OAAO,EACP,WAAW,EACX,QAAQ,EACR,OAAO,GACR,MAAM,mDAAmD,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,YAAY,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAClF,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,YAAY,EACV,SAAS,EACT,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,aAAa,EACb,oBAAoB,GACrB,MAAM,0BAA0B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AAC/E,YAAY,EAAE,wBAAwB,EAAE,MAAM,4CAA4C,CAAC;AAC3F,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AACrE,YAAY,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AACrE,YAAY,EAAE,WAAW,EAAE,MAAM,uCAAuC,CAAC;AACzE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iDAAiD,CAAC;AACzF,YAAY,EAAE,0BAA0B,EAAE,MAAM,iDAAiD,CAAC;AAElG,OAAO,EACL,IAAI,EACJ,OAAO,EACP,OAAO,EACP,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,UAAU,EACV,OAAO,EACP,WAAW,EACX,QAAQ,EACR,OAAO,GACR,MAAM,mDAAmD,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,YAAY,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAClF,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,YAAY,EACV,SAAS,EACT,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,uBAAuB,EACvB,gBAAgB,EAChB,SAAS,EACT,SAAS,EACT,kBAAkB,EAClB,mBAAmB,EACnB,aAAa,EACb,oBAAoB,GACrB,MAAM,0BAA0B,CAAC"}
|
package/dist/module.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAErE,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;;AAED,
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAErE,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;;AAED,wBA2NyC"}
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -74,6 +74,18 @@ export {};
|
|
|
74
74
|
filePath: resolver.resolve(`./runtime/components/${name}.vue`)
|
|
75
75
|
});
|
|
76
76
|
}
|
|
77
|
+
const mediaFieldComponents = [
|
|
78
|
+
"MapoMediaField",
|
|
79
|
+
"MapoMediaM2mField",
|
|
80
|
+
"MapoEnhancedMediaField",
|
|
81
|
+
"MapoMediaUnavailable"
|
|
82
|
+
];
|
|
83
|
+
for (const name of mediaFieldComponents) {
|
|
84
|
+
addComponent({
|
|
85
|
+
name,
|
|
86
|
+
filePath: resolver.resolve(`./runtime/components/fields/${name}.vue`)
|
|
87
|
+
});
|
|
88
|
+
}
|
|
77
89
|
addImports([
|
|
78
90
|
{
|
|
79
91
|
name: "useMapoForm",
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref, computed } from "vue";
|
|
3
|
+
import { useMediaManager } from "../../composables/useMediaManager.js";
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
modelValue: { type: null, required: true },
|
|
6
|
+
descriptor: { type: Object, required: true },
|
|
7
|
+
errors: { type: Array, required: false },
|
|
8
|
+
readonly: { type: Boolean, required: false },
|
|
9
|
+
disabled: { type: Boolean, required: false }
|
|
10
|
+
});
|
|
11
|
+
const emit = defineEmits(["update:modelValue"]);
|
|
12
|
+
const dialogOpen = ref(false);
|
|
13
|
+
const { MediaDialog, available } = useMediaManager();
|
|
14
|
+
const current = computed(
|
|
15
|
+
() => props.modelValue?.media ?? null
|
|
16
|
+
);
|
|
17
|
+
const altValue = computed({
|
|
18
|
+
get: () => props.modelValue?.alt ?? "",
|
|
19
|
+
set: (v) => emit("update:modelValue", {
|
|
20
|
+
...props.modelValue ?? { media: null },
|
|
21
|
+
alt: v
|
|
22
|
+
})
|
|
23
|
+
});
|
|
24
|
+
const captionValue = computed({
|
|
25
|
+
get: () => props.modelValue?.caption ?? "",
|
|
26
|
+
set: (v) => emit("update:modelValue", {
|
|
27
|
+
...props.modelValue ?? { media: null },
|
|
28
|
+
caption: v
|
|
29
|
+
})
|
|
30
|
+
});
|
|
31
|
+
const mime = computed(() => props.descriptor.attrs?.mime);
|
|
32
|
+
function onConfirm(selection) {
|
|
33
|
+
const media = Array.isArray(selection) ? selection[0] ?? null : selection;
|
|
34
|
+
emit("update:modelValue", {
|
|
35
|
+
...props.modelValue ?? {},
|
|
36
|
+
media,
|
|
37
|
+
alt: props.modelValue?.alt ?? media?.alt_text ?? "",
|
|
38
|
+
caption: props.modelValue?.caption ?? ""
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function clear() {
|
|
42
|
+
emit("update:modelValue", null);
|
|
43
|
+
}
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<template>
|
|
47
|
+
<div class="mapo-enhanced-media-field space-y-3">
|
|
48
|
+
<MapoMediaUnavailable v-if="!available" />
|
|
49
|
+
|
|
50
|
+
<template v-else>
|
|
51
|
+
<div class="flex gap-3">
|
|
52
|
+
<!-- Preview -->
|
|
53
|
+
<div class="shrink-0">
|
|
54
|
+
<div
|
|
55
|
+
class="flex size-24 cursor-pointer items-center justify-center overflow-hidden rounded-lg border-2 border-dashed transition-colors"
|
|
56
|
+
:class="
|
|
57
|
+
current ? 'border-default' : 'border-accented hover:border-primary'
|
|
58
|
+
"
|
|
59
|
+
@click="!readonly && !disabled && (dialogOpen = true)"
|
|
60
|
+
>
|
|
61
|
+
<MapoMediaPreview v-if="current" :media="current" size="md" />
|
|
62
|
+
<div v-else class="flex flex-col items-center gap-1 text-dimmed">
|
|
63
|
+
<UIcon name="i-lucide-image-plus" class="size-7" />
|
|
64
|
+
<span class="text-[10px]">Select</span>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<!-- Metadata fields -->
|
|
70
|
+
<div class="flex-1 space-y-2">
|
|
71
|
+
<div v-if="current" class="flex items-start justify-between gap-2">
|
|
72
|
+
<p class="truncate text-xs text-muted">
|
|
73
|
+
{{ current.title || current.file?.split("/").pop() }}
|
|
74
|
+
</p>
|
|
75
|
+
<div class="flex gap-1">
|
|
76
|
+
<UButton
|
|
77
|
+
v-if="!readonly && !disabled"
|
|
78
|
+
icon="i-lucide-refresh-cw"
|
|
79
|
+
size="xs"
|
|
80
|
+
variant="ghost"
|
|
81
|
+
color="neutral"
|
|
82
|
+
title="Change"
|
|
83
|
+
@click="dialogOpen = true"
|
|
84
|
+
/>
|
|
85
|
+
<UButton
|
|
86
|
+
v-if="!readonly && !disabled"
|
|
87
|
+
icon="i-lucide-x"
|
|
88
|
+
size="xs"
|
|
89
|
+
variant="ghost"
|
|
90
|
+
color="neutral"
|
|
91
|
+
title="Remove"
|
|
92
|
+
@click="clear"
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
<UInput
|
|
98
|
+
v-model="altValue"
|
|
99
|
+
size="sm"
|
|
100
|
+
placeholder="Alt text"
|
|
101
|
+
:disabled="readonly || disabled || !current"
|
|
102
|
+
/>
|
|
103
|
+
<UInput
|
|
104
|
+
v-model="captionValue"
|
|
105
|
+
size="sm"
|
|
106
|
+
placeholder="Caption"
|
|
107
|
+
:disabled="readonly || disabled || !current"
|
|
108
|
+
/>
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<!-- Dialog -->
|
|
113
|
+
<component
|
|
114
|
+
:is="MediaDialog"
|
|
115
|
+
v-model="dialogOpen"
|
|
116
|
+
selection-mode="single"
|
|
117
|
+
:mime="mime"
|
|
118
|
+
:selected="current"
|
|
119
|
+
@confirm="onConfirm"
|
|
120
|
+
/>
|
|
121
|
+
</template>
|
|
122
|
+
|
|
123
|
+
<!-- Errors -->
|
|
124
|
+
<p v-for="err in errors" :key="err" class="text-xs text-error" role="alert">
|
|
125
|
+
{{ err }}
|
|
126
|
+
</p>
|
|
127
|
+
</div>
|
|
128
|
+
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { EnhancedMediaDescriptor, EnhancedMediaValue } from "../../types/index.js";
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
modelValue: EnhancedMediaValue | null | undefined;
|
|
4
|
+
descriptor: EnhancedMediaDescriptor;
|
|
5
|
+
errors?: string[];
|
|
6
|
+
readonly?: boolean;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
};
|
|
9
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
|
+
"update:modelValue": (value: EnhancedMediaValue | null) => any;
|
|
11
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
12
|
+
"onUpdate:modelValue"?: ((value: EnhancedMediaValue | null) => any) | undefined;
|
|
13
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
declare const _default: typeof __VLS_export;
|
|
15
|
+
export default _default;
|
|
16
|
+
//# sourceMappingURL=MapoEnhancedMediaField.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MapoEnhancedMediaField.vue.d.ts","sourceRoot":"","sources":["../../../../src/runtime/components/fields/MapoEnhancedMediaField.vue"],"names":[],"mappings":"AA0JA,OAAO,KAAK,EACV,uBAAuB,EACvB,kBAAkB,EAEnB,MAAM,sBAAsB,CAAC;AAG9B,KAAK,WAAW,GAAG;IACjB,UAAU,EAAE,kBAAkB,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD,UAAU,EAAE,uBAAuB,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AA2UF,QAAA,MAAM,YAAY;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref, computed } from "vue";
|
|
3
|
+
import { useMediaManager } from "../../composables/useMediaManager.js";
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
modelValue: { type: null, required: true },
|
|
6
|
+
descriptor: { type: Object, required: true },
|
|
7
|
+
errors: { type: Array, required: false },
|
|
8
|
+
readonly: { type: Boolean, required: false },
|
|
9
|
+
disabled: { type: Boolean, required: false }
|
|
10
|
+
});
|
|
11
|
+
const emit = defineEmits(["update:modelValue"]);
|
|
12
|
+
const dialogOpen = ref(false);
|
|
13
|
+
const { MediaDialog, available } = useMediaManager();
|
|
14
|
+
const current = computed(() => {
|
|
15
|
+
if (!props.modelValue) return null;
|
|
16
|
+
if (typeof props.modelValue === "object") return props.modelValue;
|
|
17
|
+
return null;
|
|
18
|
+
});
|
|
19
|
+
const mime = computed(() => props.descriptor.attrs?.mime);
|
|
20
|
+
function onConfirm(selection) {
|
|
21
|
+
emit(
|
|
22
|
+
"update:modelValue",
|
|
23
|
+
Array.isArray(selection) ? selection[0] ?? null : selection
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
function clear() {
|
|
27
|
+
emit("update:modelValue", null);
|
|
28
|
+
}
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<div class="mapo-media-field space-y-2">
|
|
33
|
+
<MapoMediaUnavailable v-if="!available" />
|
|
34
|
+
|
|
35
|
+
<template v-else>
|
|
36
|
+
<!-- Selected media preview -->
|
|
37
|
+
<div
|
|
38
|
+
v-if="current"
|
|
39
|
+
class="flex items-center gap-3 rounded-lg border border-default p-2"
|
|
40
|
+
>
|
|
41
|
+
<MapoMediaPreview :media="current" size="sm" />
|
|
42
|
+
<div class="flex-1 min-w-0">
|
|
43
|
+
<p class="truncate text-xs font-medium">
|
|
44
|
+
{{ current.title || current.file?.split("/").pop() }}
|
|
45
|
+
</p>
|
|
46
|
+
<p class="text-xs text-dimmed">
|
|
47
|
+
{{ current.mime_type }}
|
|
48
|
+
</p>
|
|
49
|
+
</div>
|
|
50
|
+
<UButton
|
|
51
|
+
v-if="!readonly && !disabled"
|
|
52
|
+
icon="i-lucide-x"
|
|
53
|
+
size="xs"
|
|
54
|
+
variant="ghost"
|
|
55
|
+
color="neutral"
|
|
56
|
+
@click="clear"
|
|
57
|
+
/>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<!-- Trigger button -->
|
|
61
|
+
<UButton
|
|
62
|
+
v-if="!readonly && !disabled"
|
|
63
|
+
:icon="current ? 'i-lucide-refresh-cw' : 'i-lucide-image-plus'"
|
|
64
|
+
size="sm"
|
|
65
|
+
variant="soft"
|
|
66
|
+
color="neutral"
|
|
67
|
+
:block="!current"
|
|
68
|
+
@click="dialogOpen = true"
|
|
69
|
+
>
|
|
70
|
+
{{ current ? "Change" : "Select media" }}
|
|
71
|
+
</UButton>
|
|
72
|
+
|
|
73
|
+
<!-- Dialog -->
|
|
74
|
+
<component
|
|
75
|
+
:is="MediaDialog"
|
|
76
|
+
v-model="dialogOpen"
|
|
77
|
+
selection-mode="single"
|
|
78
|
+
:mime="mime"
|
|
79
|
+
:selected="current"
|
|
80
|
+
@confirm="onConfirm"
|
|
81
|
+
/>
|
|
82
|
+
</template>
|
|
83
|
+
|
|
84
|
+
<!-- Errors -->
|
|
85
|
+
<p v-for="err in errors" :key="err" class="text-xs text-error" role="alert">
|
|
86
|
+
{{ err }}
|
|
87
|
+
</p>
|
|
88
|
+
</div>
|
|
89
|
+
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MediaDescriptor, MediaItem } from "../../types/index.js";
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
modelValue: MediaItem | number | null | undefined;
|
|
4
|
+
descriptor: MediaDescriptor;
|
|
5
|
+
errors?: string[];
|
|
6
|
+
readonly?: boolean;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
};
|
|
9
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
|
+
"update:modelValue": (value: MediaItem | null) => any;
|
|
11
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
12
|
+
"onUpdate:modelValue"?: ((value: MediaItem | null) => any) | undefined;
|
|
13
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
declare const _default: typeof __VLS_export;
|
|
15
|
+
export default _default;
|
|
16
|
+
//# sourceMappingURL=MapoMediaField.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MapoMediaField.vue.d.ts","sourceRoot":"","sources":["../../../../src/runtime/components/fields/MapoMediaField.vue"],"names":[],"mappings":"AAyGA,OAAO,KAAK,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGvE,KAAK,WAAW,GAAG;IACjB,UAAU,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAClD,UAAU,EAAE,eAAe,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AA6NF,QAAA,MAAM,YAAY;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref, computed } from "vue";
|
|
3
|
+
import { useMediaManager } from "../../composables/useMediaManager.js";
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
modelValue: { type: null, required: true },
|
|
6
|
+
descriptor: { type: Object, required: true },
|
|
7
|
+
errors: { type: Array, required: false },
|
|
8
|
+
readonly: { type: Boolean, required: false },
|
|
9
|
+
disabled: { type: Boolean, required: false }
|
|
10
|
+
});
|
|
11
|
+
const emit = defineEmits(["update:modelValue"]);
|
|
12
|
+
const dialogOpen = ref(false);
|
|
13
|
+
const { MediaDialog, available } = useMediaManager();
|
|
14
|
+
const current = computed(() => {
|
|
15
|
+
if (!props.modelValue) return [];
|
|
16
|
+
return props.modelValue.filter((v) => typeof v === "object");
|
|
17
|
+
});
|
|
18
|
+
const mime = computed(() => props.descriptor.attrs?.mime);
|
|
19
|
+
function onConfirm(selection) {
|
|
20
|
+
emit("update:modelValue", Array.isArray(selection) ? selection : [selection]);
|
|
21
|
+
}
|
|
22
|
+
function removeItem(id) {
|
|
23
|
+
emit(
|
|
24
|
+
"update:modelValue",
|
|
25
|
+
current.value.filter((m) => m.id !== id)
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
const dragIndex = ref(null);
|
|
29
|
+
function onDragStart(index) {
|
|
30
|
+
dragIndex.value = index;
|
|
31
|
+
}
|
|
32
|
+
function onDragOverItem(index) {
|
|
33
|
+
if (dragIndex.value === null || dragIndex.value === index) return;
|
|
34
|
+
const items = [...current.value];
|
|
35
|
+
const [moved] = items.splice(dragIndex.value, 1);
|
|
36
|
+
if (!moved) return;
|
|
37
|
+
items.splice(index, 0, moved);
|
|
38
|
+
dragIndex.value = index;
|
|
39
|
+
emit("update:modelValue", items);
|
|
40
|
+
}
|
|
41
|
+
function onDragEnd() {
|
|
42
|
+
dragIndex.value = null;
|
|
43
|
+
}
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<template>
|
|
47
|
+
<div class="mapo-media-m2m-field space-y-2">
|
|
48
|
+
<MapoMediaUnavailable v-if="!available" />
|
|
49
|
+
|
|
50
|
+
<template v-else>
|
|
51
|
+
<!-- Selected items grid -->
|
|
52
|
+
<div v-if="current.length > 0" class="flex flex-wrap gap-2">
|
|
53
|
+
<div
|
|
54
|
+
v-for="(media, i) in current"
|
|
55
|
+
:key="media.id"
|
|
56
|
+
class="group relative"
|
|
57
|
+
:class="{
|
|
58
|
+
'opacity-50': dragIndex === i,
|
|
59
|
+
'cursor-grab': !readonly && !disabled
|
|
60
|
+
}"
|
|
61
|
+
:draggable="!readonly && !disabled"
|
|
62
|
+
@dragstart="onDragStart(i)"
|
|
63
|
+
@dragover.prevent="onDragOverItem(i)"
|
|
64
|
+
@dragend="onDragEnd"
|
|
65
|
+
>
|
|
66
|
+
<MapoMediaPreview :media="media" size="sm" />
|
|
67
|
+
<button
|
|
68
|
+
v-if="!readonly && !disabled"
|
|
69
|
+
class="absolute -right-1.5 -top-1.5 hidden size-4 items-center justify-center rounded-full bg-error text-inverted group-hover:flex"
|
|
70
|
+
type="button"
|
|
71
|
+
@click="removeItem(media.id)"
|
|
72
|
+
>
|
|
73
|
+
<UIcon name="i-lucide-x" class="size-2.5" />
|
|
74
|
+
</button>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<!-- Add button -->
|
|
79
|
+
<UButton
|
|
80
|
+
v-if="!readonly && !disabled"
|
|
81
|
+
icon="i-lucide-plus"
|
|
82
|
+
size="sm"
|
|
83
|
+
variant="soft"
|
|
84
|
+
color="neutral"
|
|
85
|
+
@click="dialogOpen = true"
|
|
86
|
+
>
|
|
87
|
+
{{ current.length > 0 ? "Add media" : "Select media" }}
|
|
88
|
+
</UButton>
|
|
89
|
+
|
|
90
|
+
<!-- Dialog -->
|
|
91
|
+
<component
|
|
92
|
+
:is="MediaDialog"
|
|
93
|
+
v-model="dialogOpen"
|
|
94
|
+
selection-mode="multi"
|
|
95
|
+
:mime="mime"
|
|
96
|
+
:selected="current"
|
|
97
|
+
@confirm="onConfirm"
|
|
98
|
+
/>
|
|
99
|
+
</template>
|
|
100
|
+
|
|
101
|
+
<!-- Errors -->
|
|
102
|
+
<p v-for="err in errors" :key="err" class="text-xs text-error" role="alert">
|
|
103
|
+
{{ err }}
|
|
104
|
+
</p>
|
|
105
|
+
</div>
|
|
106
|
+
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { MediaM2mDescriptor, MediaItem } from "../../types/index.js";
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
modelValue: MediaItem[] | number[] | null | undefined;
|
|
4
|
+
descriptor: MediaM2mDescriptor;
|
|
5
|
+
errors?: string[];
|
|
6
|
+
readonly?: boolean;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
};
|
|
9
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
|
+
"update:modelValue": (value: MediaItem[]) => any;
|
|
11
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
12
|
+
"onUpdate:modelValue"?: ((value: MediaItem[]) => any) | undefined;
|
|
13
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
14
|
+
declare const _default: typeof __VLS_export;
|
|
15
|
+
export default _default;
|
|
16
|
+
//# sourceMappingURL=MapoMediaM2mField.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MapoMediaM2mField.vue.d.ts","sourceRoot":"","sources":["../../../../src/runtime/components/fields/MapoMediaM2mField.vue"],"names":[],"mappings":"AA+HA,OAAO,KAAK,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAG1E,KAAK,WAAW,GAAG;IACjB,UAAU,EAAE,SAAS,EAAE,GAAG,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,CAAC;IACtD,UAAU,EAAE,kBAAkB,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAwQF,QAAA,MAAM,YAAY;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<template>
|
|
6
|
+
<div
|
|
7
|
+
class="flex items-center gap-2 rounded-lg border border-dashed border-default px-3 py-2 text-xs text-muted"
|
|
8
|
+
>
|
|
9
|
+
<UIcon
|
|
10
|
+
name="i-lucide-triangle-alert"
|
|
11
|
+
class="size-4 shrink-0 text-warning"
|
|
12
|
+
/>
|
|
13
|
+
<span>Media fields require <code>@mapomodule/uikit</code>.</span>
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
4
|
+
//# sourceMappingURL=MapoMediaUnavailable.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MapoMediaUnavailable.vue.d.ts","sourceRoot":"","sources":["../../../../src/runtime/components/fields/MapoMediaUnavailable.vue"],"names":[],"mappings":"AAuEA,QAAA,MAAM,YAAY,+QAChB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { watch, onBeforeUnmount } from "vue";
|
|
2
|
+
import { ref, watch, onBeforeUnmount, resolveComponent } from "vue";
|
|
3
3
|
import { useEditor, EditorContent } from "@tiptap/vue-3";
|
|
4
4
|
import StarterKit from "@tiptap/starter-kit";
|
|
5
5
|
import Link from "@tiptap/extension-link";
|
|
6
6
|
import Underline from "@tiptap/extension-underline";
|
|
7
|
+
import Image from "@tiptap/extension-image";
|
|
7
8
|
const props = defineProps({
|
|
8
9
|
modelValue: { type: null, required: true },
|
|
9
10
|
descriptor: { type: Object, required: true },
|
|
@@ -61,6 +62,7 @@ const editor = useEditor({
|
|
|
61
62
|
validate: (href) => isSafeUrl(href)
|
|
62
63
|
}),
|
|
63
64
|
Underline,
|
|
65
|
+
Image.configure({ inline: false, allowBase64: false }),
|
|
64
66
|
...extraExtensions
|
|
65
67
|
],
|
|
66
68
|
onUpdate: ({ editor: e }) => {
|
|
@@ -83,6 +85,14 @@ watch(
|
|
|
83
85
|
}
|
|
84
86
|
);
|
|
85
87
|
onBeforeUnmount(() => editor.value?.destroy());
|
|
88
|
+
const imagePickerOpen = ref(false);
|
|
89
|
+
const MediaManagerDialog = resolveComponent("MapoMediaManagerDialog");
|
|
90
|
+
const hasMediaManager = typeof MediaManagerDialog !== "string";
|
|
91
|
+
function onImageConfirm(selection) {
|
|
92
|
+
const media = Array.isArray(selection) ? selection[0] : selection;
|
|
93
|
+
if (!media || !editor.value) return;
|
|
94
|
+
editor.value.chain().focus().setImage({ src: media.file, alt: media.alt_text ?? "" }).run();
|
|
95
|
+
}
|
|
86
96
|
</script>
|
|
87
97
|
|
|
88
98
|
<template>
|
|
@@ -194,9 +204,9 @@ onBeforeUnmount(() => editor.value?.destroy());
|
|
|
194
204
|
|
|
195
205
|
<USeparator orientation="vertical" class="mx-1 h-5" />
|
|
196
206
|
|
|
197
|
-
<!-- Insert Image
|
|
207
|
+
<!-- Insert Image via Media Manager (available when @mapomodule/uikit is installed) -->
|
|
198
208
|
<UTooltip
|
|
199
|
-
text="Insert image
|
|
209
|
+
:text="hasMediaManager ? 'Insert image' : 'Requires @mapomodule/uikit'"
|
|
200
210
|
:delay-open="300"
|
|
201
211
|
>
|
|
202
212
|
<UButton
|
|
@@ -204,12 +214,13 @@ onBeforeUnmount(() => editor.value?.destroy());
|
|
|
204
214
|
variant="ghost"
|
|
205
215
|
color="neutral"
|
|
206
216
|
icon="i-lucide-image"
|
|
207
|
-
disabled
|
|
217
|
+
:disabled="readonly || disabled || !hasMediaManager"
|
|
218
|
+
@click="imagePickerOpen = true"
|
|
208
219
|
/>
|
|
209
220
|
</UTooltip>
|
|
210
221
|
</div>
|
|
211
222
|
|
|
212
|
-
<!--
|
|
223
|
+
<!-- Editor content -->
|
|
213
224
|
<EditorContent
|
|
214
225
|
:editor="editor"
|
|
215
226
|
class="prose prose-sm max-w-none px-3 py-2 focus-within:outline-none"
|
|
@@ -224,4 +235,14 @@ onBeforeUnmount(() => editor.value?.destroy());
|
|
|
224
235
|
{{ err }}
|
|
225
236
|
</p>
|
|
226
237
|
</div>
|
|
238
|
+
|
|
239
|
+
<!-- Image picker dialog — only rendered when MapoMediaManagerDialog is globally available -->
|
|
240
|
+
<component
|
|
241
|
+
:is="MediaManagerDialog"
|
|
242
|
+
v-if="hasMediaManager"
|
|
243
|
+
v-model="imagePickerOpen"
|
|
244
|
+
selection-mode="single"
|
|
245
|
+
mime="image/*"
|
|
246
|
+
@confirm="onImageConfirm"
|
|
247
|
+
/>
|
|
227
248
|
</template>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MapoWygEditor.vue.d.ts","sourceRoot":"","sources":["../../../../src/runtime/components/fields/MapoWygEditor.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MapoWygEditor.vue.d.ts","sourceRoot":"","sources":["../../../../src/runtime/components/fields/MapoWygEditor.vue"],"names":[],"mappings":"AA6SA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,KAAK,WAAW,GAAG;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AA+oBF,QAAA,MAAM,YAAY;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves the Media Manager picker dialog at runtime.
|
|
3
|
+
*
|
|
4
|
+
* The media field types ship with `@mapomodule/form`, but the Media Manager
|
|
5
|
+
* itself lives in `@mapomodule/uikit`. Resolving the dialog by name instead of
|
|
6
|
+
* importing it keeps `form` free of a static dependency on `uikit` (which
|
|
7
|
+
* depends on `form`, so a static import would be a cycle) and lets `form` stay
|
|
8
|
+
* usable standalone — the fields then render an explicit notice instead of a
|
|
9
|
+
* broken picker.
|
|
10
|
+
*
|
|
11
|
+
* Must be called from `setup()`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useMediaManager(): {
|
|
14
|
+
MediaDialog: string | import("vue").ConcreteComponent<{}, any, any, import("vue").ComputedOptions, import("vue").MethodOptions, {}, any>;
|
|
15
|
+
available: boolean;
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=useMediaManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useMediaManager.d.ts","sourceRoot":"","sources":["../../../src/runtime/composables/useMediaManager.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe;;;EAM9B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../../src/runtime/registry/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAMvD,eAAO,MAAM,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../../src/runtime/registry/defaults.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAMvD,eAAO,MAAM,eAAe,EAAE,aAkG7B,CAAC"}
|
|
@@ -22,8 +22,14 @@ export const defaultRegistry = {
|
|
|
22
22
|
seo: () => import("../components/fields/MapoSeoPreview.vue"),
|
|
23
23
|
editor: () => import("../components/fields/MapoWygEditor.vue"),
|
|
24
24
|
map: () => import("../components/fields/MapoMapField.vue"),
|
|
25
|
-
repeater: () => import("../components/fields/MapoRepeater.vue")
|
|
26
|
-
//
|
|
25
|
+
repeater: () => import("../components/fields/MapoRepeater.vue"),
|
|
26
|
+
// ─── Media pickers ────────────────────────────────────────────────────────
|
|
27
|
+
// The fields live here with every other field type; the Media Manager they
|
|
28
|
+
// drive ships with @mapomodule/uikit and is resolved at runtime
|
|
29
|
+
// (see useMediaManager). Without uikit they render an explicit notice.
|
|
30
|
+
media: () => import("../components/fields/MapoMediaField.vue"),
|
|
31
|
+
"media-m2m": () => import("../components/fields/MapoMediaM2mField.vue"),
|
|
32
|
+
"enhanced-media": () => import("../components/fields/MapoEnhancedMediaField.vue")
|
|
27
33
|
},
|
|
28
34
|
attrs: {
|
|
29
35
|
// Applied to all fields
|