mktcms 0.3.6 → 0.3.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/dist/module.json +1 -1
- package/dist/runtime/app/components/content/editor/frontmatter/form.vue +95 -1
- package/dist/runtime/app/components/content/editor/frontmatter/input.d.vue.ts +13 -3
- package/dist/runtime/app/components/content/editor/frontmatter/input.vue +81 -3
- package/dist/runtime/app/components/content/editor/frontmatter/input.vue.d.ts +13 -3
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -29,6 +29,30 @@ function isObjectSchema(schema) {
|
|
|
29
29
|
function isPrimitiveSchema(schema) {
|
|
30
30
|
return isRecord(schema) && ["string", "number", "date", "datetime"].includes(schema.type ?? "");
|
|
31
31
|
}
|
|
32
|
+
function isSelectSingleSchema(schema) {
|
|
33
|
+
if (!isRecord(schema)) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return schema["x-ui"] === "select-single" || schema.type === "string" && Array.isArray(schema.enum);
|
|
37
|
+
}
|
|
38
|
+
function isSelectMultipleSchema(schema) {
|
|
39
|
+
if (!isRecord(schema)) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
if (schema["x-ui"] === "select-multiple") {
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
if (schema.type !== "array") {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (Array.isArray(schema.enum)) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
if (!isRecord(schema.items)) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return schema.items.type === "string" && Array.isArray(schema.items.enum);
|
|
55
|
+
}
|
|
32
56
|
function isSchemaMap(schema) {
|
|
33
57
|
return isRecord(schema) && !("type" in schema);
|
|
34
58
|
}
|
|
@@ -39,7 +63,18 @@ function createDefaultFromSchema(schema) {
|
|
|
39
63
|
if (!schema || !schema.type) {
|
|
40
64
|
return "";
|
|
41
65
|
}
|
|
66
|
+
if (isSelectSingleSchema(schema)) {
|
|
67
|
+
const options = getSelectSingleOptionsFromSchema(schema);
|
|
68
|
+
const firstOption = options[0];
|
|
69
|
+
if (firstOption) {
|
|
70
|
+
return firstOption.value;
|
|
71
|
+
}
|
|
72
|
+
return "";
|
|
73
|
+
}
|
|
42
74
|
if (schema.type === "array") {
|
|
75
|
+
if (isSelectMultipleSchema(schema)) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
43
78
|
return [];
|
|
44
79
|
}
|
|
45
80
|
if (schema.type === "object") {
|
|
@@ -58,6 +93,43 @@ function createDefaultFromSchema(schema) {
|
|
|
58
93
|
}
|
|
59
94
|
return "";
|
|
60
95
|
}
|
|
96
|
+
function getSelectOptionsFromSchema(schema) {
|
|
97
|
+
if (!schema) {
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
const rawOptions = Array.isArray(schema.oneOf) ? schema.oneOf : Array.isArray(schema.enum) ? schema.enum.map((value) => ({ value })) : [];
|
|
101
|
+
return rawOptions.filter((option) => option !== null && option !== void 0).map((option) => {
|
|
102
|
+
if (typeof option === "string" || typeof option === "number") {
|
|
103
|
+
return {
|
|
104
|
+
label: String(option),
|
|
105
|
+
value: String(option)
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
if (isRecord(option) && option.value !== void 0 && option.value !== null) {
|
|
109
|
+
const optionLabel = "label" in option ? option.label : void 0;
|
|
110
|
+
return {
|
|
111
|
+
label: String(optionLabel ?? option.value),
|
|
112
|
+
value: String(option.value)
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}).filter((option) => option !== null);
|
|
117
|
+
}
|
|
118
|
+
function getSelectSingleOptionsFromSchema(schema) {
|
|
119
|
+
return getSelectOptionsFromSchema(schema);
|
|
120
|
+
}
|
|
121
|
+
function getSelectMultipleOptionsFromSchema(schema) {
|
|
122
|
+
if (!schema || !isArraySchema(schema)) {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
if (Array.isArray(schema.enum) || Array.isArray(schema.oneOf)) {
|
|
126
|
+
return getSelectOptionsFromSchema(schema);
|
|
127
|
+
}
|
|
128
|
+
if (schema.items && isRecord(schema.items)) {
|
|
129
|
+
return getSelectOptionsFromSchema(schema.items);
|
|
130
|
+
}
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
61
133
|
function ensureInitializedFromSchema() {
|
|
62
134
|
const schema = props.schema;
|
|
63
135
|
if (!schema) {
|
|
@@ -192,6 +264,14 @@ function removeArrayItem(arrayRef, index) {
|
|
|
192
264
|
</label>
|
|
193
265
|
</div>
|
|
194
266
|
|
|
267
|
+
<FrontmatterInput
|
|
268
|
+
v-else-if="isSelectSingleSchema(arrayItemSchema)"
|
|
269
|
+
v-model:value="frontmatter[index]"
|
|
270
|
+
label=""
|
|
271
|
+
:select-options="getSelectSingleOptionsFromSchema(arrayItemSchema)"
|
|
272
|
+
select-mode="single"
|
|
273
|
+
/>
|
|
274
|
+
|
|
195
275
|
<FrontmatterInput
|
|
196
276
|
v-else-if="isPrimitiveSchema(arrayItemSchema)"
|
|
197
277
|
v-model:value="frontmatter[index]"
|
|
@@ -247,7 +327,21 @@ function removeArrayItem(arrayRef, index) {
|
|
|
247
327
|
</p>
|
|
248
328
|
|
|
249
329
|
<FrontmatterInput
|
|
250
|
-
v-if="
|
|
330
|
+
v-if="isSelectSingleSchema(entry[1])"
|
|
331
|
+
v-model:value="frontmatter[entry[0]]"
|
|
332
|
+
:select-options="getSelectSingleOptionsFromSchema(entry[1])"
|
|
333
|
+
select-mode="single"
|
|
334
|
+
/>
|
|
335
|
+
|
|
336
|
+
<FrontmatterInput
|
|
337
|
+
v-else-if="isSelectMultipleSchema(entry[1])"
|
|
338
|
+
v-model:value="frontmatter[entry[0]]"
|
|
339
|
+
:select-options="getSelectMultipleOptionsFromSchema(entry[1])"
|
|
340
|
+
select-mode="multiple"
|
|
341
|
+
/>
|
|
342
|
+
|
|
343
|
+
<FrontmatterInput
|
|
344
|
+
v-else-if="isPrimitiveSchema(entry[1])"
|
|
251
345
|
v-model:value="frontmatter[entry[0]]"
|
|
252
346
|
:input-type="getInputTypeFromSchema(entry[1])"
|
|
253
347
|
:ui-hint="getUiHintFromSchema(entry[1])"
|
|
@@ -2,19 +2,29 @@ type __VLS_Props = {
|
|
|
2
2
|
label?: string;
|
|
3
3
|
inputType?: 'text' | 'number' | 'date' | 'datetime-local';
|
|
4
4
|
uiHint?: 'image' | 'pdf' | 'file';
|
|
5
|
+
selectMode?: 'single' | 'multiple';
|
|
6
|
+
selectOptions?: Array<{
|
|
7
|
+
label: string;
|
|
8
|
+
value: string | number;
|
|
9
|
+
}>;
|
|
5
10
|
};
|
|
6
11
|
type __VLS_ModelProps = {
|
|
7
|
-
'value': string | number
|
|
12
|
+
'value': string | number | Array<string | number>;
|
|
8
13
|
};
|
|
9
14
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
10
15
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
|
-
"update:value": (value: string | number) => any;
|
|
16
|
+
"update:value": (value: string | number | (string | number)[]) => any;
|
|
12
17
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
|
-
"onUpdate:value"?: ((value: string | number) => any) | undefined;
|
|
18
|
+
"onUpdate:value"?: ((value: string | number | (string | number)[]) => any) | undefined;
|
|
14
19
|
}>, {
|
|
15
20
|
label: string;
|
|
16
21
|
uiHint: "image" | "pdf" | "file";
|
|
17
22
|
inputType: "text" | "number" | "date" | "datetime-local";
|
|
23
|
+
selectMode: "single" | "multiple";
|
|
24
|
+
selectOptions: Array<{
|
|
25
|
+
label: string;
|
|
26
|
+
value: string | number;
|
|
27
|
+
}>;
|
|
18
28
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
19
29
|
declare const _default: typeof __VLS_export;
|
|
20
30
|
export default _default;
|
|
@@ -4,12 +4,15 @@ import FilePickerModal from "./filePicker/modal.vue";
|
|
|
4
4
|
const props = defineProps({
|
|
5
5
|
label: { type: String, required: false, default: "" },
|
|
6
6
|
inputType: { type: String, required: false, default: "text" },
|
|
7
|
-
uiHint: { type: String, required: false, default: void 0 }
|
|
7
|
+
uiHint: { type: String, required: false, default: void 0 },
|
|
8
|
+
selectMode: { type: String, required: false, default: void 0 },
|
|
9
|
+
selectOptions: { type: Array, required: false, default: () => [] }
|
|
8
10
|
});
|
|
9
|
-
const value = defineModel("value", { type: [String, Number], ...{
|
|
11
|
+
const value = defineModel("value", { type: [String, Number, Array], ...{
|
|
10
12
|
required: true
|
|
11
13
|
} });
|
|
12
14
|
const isPickerOpen = ref(false);
|
|
15
|
+
const hasSelectInput = computed(() => props.selectMode === "single" || props.selectMode === "multiple");
|
|
13
16
|
const resolvedInputType = computed(() => {
|
|
14
17
|
if (props.inputType !== "text") {
|
|
15
18
|
return props.inputType;
|
|
@@ -17,6 +20,14 @@ const resolvedInputType = computed(() => {
|
|
|
17
20
|
return typeof value.value === "number" ? "number" : "text";
|
|
18
21
|
});
|
|
19
22
|
const isNumberInput = computed(() => resolvedInputType.value === "number");
|
|
23
|
+
function normalizeOptionValue(optionValue) {
|
|
24
|
+
for (const option of props.selectOptions) {
|
|
25
|
+
if (String(option.value) === optionValue) {
|
|
26
|
+
return option.value;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return optionValue;
|
|
30
|
+
}
|
|
20
31
|
const inputValue = computed({
|
|
21
32
|
get() {
|
|
22
33
|
return `${value.value ?? ""}`;
|
|
@@ -30,6 +41,37 @@ const inputValue = computed({
|
|
|
30
41
|
value.value = newValue;
|
|
31
42
|
}
|
|
32
43
|
});
|
|
44
|
+
const singleSelectValue = computed({
|
|
45
|
+
get() {
|
|
46
|
+
if (Array.isArray(value.value)) {
|
|
47
|
+
return value.value.length > 0 ? String(value.value[0]) : "";
|
|
48
|
+
}
|
|
49
|
+
return `${value.value ?? ""}`;
|
|
50
|
+
},
|
|
51
|
+
set(newValue) {
|
|
52
|
+
value.value = normalizeOptionValue(newValue);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
function isMultipleOptionSelected(optionValue) {
|
|
56
|
+
if (!Array.isArray(value.value)) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return value.value.some((selected) => String(selected) === String(optionValue));
|
|
60
|
+
}
|
|
61
|
+
function toggleMultipleOption(optionValue, isChecked) {
|
|
62
|
+
const normalizedValue = normalizeOptionValue(String(optionValue));
|
|
63
|
+
const currentValues = Array.isArray(value.value) ? [...value.value] : [];
|
|
64
|
+
if (isChecked) {
|
|
65
|
+
if (!currentValues.some((selected) => String(selected) === String(normalizedValue))) {
|
|
66
|
+
currentValues.push(normalizedValue);
|
|
67
|
+
}
|
|
68
|
+
} else {
|
|
69
|
+
const nextValues = currentValues.filter((selected) => String(selected) !== String(normalizedValue));
|
|
70
|
+
value.value = nextValues;
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
value.value = currentValues;
|
|
74
|
+
}
|
|
33
75
|
const pickerButtonLabel = computed(() => {
|
|
34
76
|
if (props.uiHint === "image") {
|
|
35
77
|
return "Bild ausw\xE4hlen";
|
|
@@ -55,7 +97,43 @@ function onPickerSelect(path) {
|
|
|
55
97
|
>
|
|
56
98
|
{{ props.label }}
|
|
57
99
|
</label>
|
|
58
|
-
|
|
100
|
+
|
|
101
|
+
<select
|
|
102
|
+
v-if="hasSelectInput && props.selectMode === 'single'"
|
|
103
|
+
v-model="singleSelectValue"
|
|
104
|
+
class="w-full"
|
|
105
|
+
>
|
|
106
|
+
<option
|
|
107
|
+
v-for="option in props.selectOptions"
|
|
108
|
+
:key="`${option.value}`"
|
|
109
|
+
:value="`${option.value}`"
|
|
110
|
+
>
|
|
111
|
+
{{ option.label }}
|
|
112
|
+
</option>
|
|
113
|
+
</select>
|
|
114
|
+
|
|
115
|
+
<div
|
|
116
|
+
v-else-if="hasSelectInput && props.selectMode === 'multiple'"
|
|
117
|
+
class="flex flex-col gap-2 w-full"
|
|
118
|
+
>
|
|
119
|
+
<label
|
|
120
|
+
v-for="option in props.selectOptions"
|
|
121
|
+
:key="`${option.value}`"
|
|
122
|
+
class="inline-flex items-center gap-2"
|
|
123
|
+
>
|
|
124
|
+
<input
|
|
125
|
+
type="checkbox"
|
|
126
|
+
:checked="isMultipleOptionSelected(option.value)"
|
|
127
|
+
@change="toggleMultipleOption(option.value, $event.target.checked)"
|
|
128
|
+
>
|
|
129
|
+
{{ option.label }}
|
|
130
|
+
</label>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<div
|
|
134
|
+
v-else
|
|
135
|
+
class="flex items-center gap-2"
|
|
136
|
+
>
|
|
59
137
|
<input
|
|
60
138
|
v-model="inputValue"
|
|
61
139
|
:type="resolvedInputType"
|
|
@@ -2,19 +2,29 @@ type __VLS_Props = {
|
|
|
2
2
|
label?: string;
|
|
3
3
|
inputType?: 'text' | 'number' | 'date' | 'datetime-local';
|
|
4
4
|
uiHint?: 'image' | 'pdf' | 'file';
|
|
5
|
+
selectMode?: 'single' | 'multiple';
|
|
6
|
+
selectOptions?: Array<{
|
|
7
|
+
label: string;
|
|
8
|
+
value: string | number;
|
|
9
|
+
}>;
|
|
5
10
|
};
|
|
6
11
|
type __VLS_ModelProps = {
|
|
7
|
-
'value': string | number
|
|
12
|
+
'value': string | number | Array<string | number>;
|
|
8
13
|
};
|
|
9
14
|
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
10
15
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
|
-
"update:value": (value: string | number) => any;
|
|
16
|
+
"update:value": (value: string | number | (string | number)[]) => any;
|
|
12
17
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
|
-
"onUpdate:value"?: ((value: string | number) => any) | undefined;
|
|
18
|
+
"onUpdate:value"?: ((value: string | number | (string | number)[]) => any) | undefined;
|
|
14
19
|
}>, {
|
|
15
20
|
label: string;
|
|
16
21
|
uiHint: "image" | "pdf" | "file";
|
|
17
22
|
inputType: "text" | "number" | "date" | "datetime-local";
|
|
23
|
+
selectMode: "single" | "multiple";
|
|
24
|
+
selectOptions: Array<{
|
|
25
|
+
label: string;
|
|
26
|
+
value: string | number;
|
|
27
|
+
}>;
|
|
18
28
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
19
29
|
declare const _default: typeof __VLS_export;
|
|
20
30
|
export default _default;
|