vue-wswg-editor 0.0.10 → 0.0.11
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 +493 -20
- package/dist/style.css +1 -1
- package/dist/vue-wswg-editor.es.js +2249 -1782
- package/package.json +15 -8
- package/src/assets/styles/_mixins.scss +12 -17
- package/src/components/BlockEditorFieldNode/BlockEditorFieldNode.vue +39 -4
- package/src/components/BlockEditorFields/BlockEditorFields.vue +12 -3
- package/src/components/BlockImageFieldNode/BlockImageNode.vue +373 -0
- package/src/components/PageBuilderSidebar/PageBuilderSidebar.vue +1 -5
- package/src/components/PageRenderer/PageRenderer.vue +40 -41
- package/src/components/PageRenderer/blockModules.ts +32 -3
- package/src/components/PageRenderer/layoutModules.ts +32 -3
- package/src/components/WswgJsonEditor/WswgJsonEditor.vue +230 -62
- package/src/index.ts +2 -3
- package/src/style.css +10 -3
- package/src/util/fieldConfig.ts +22 -0
- package/src/util/helpers.ts +1 -1
- package/src/util/registry.ts +30 -23
- package/src/util/validation.ts +178 -23
- package/types/vue-wswg-editor.d.ts +161 -0
- package/dist/types/components/AddBlockItem/AddBlockItem.vue.d.ts +0 -6
- package/dist/types/components/BlockBrowser/BlockBrowser.vue.d.ts +0 -2
- package/dist/types/components/BlockComponent/BlockComponent.vue.d.ts +0 -15
- package/dist/types/components/BlockEditorFieldNode/BlockEditorFieldNode.vue.d.ts +0 -15
- package/dist/types/components/BlockEditorFields/BlockEditorFields.vue.d.ts +0 -15
- package/dist/types/components/BlockMarginFieldNode/BlockMarginNode.vue.d.ts +0 -23
- package/dist/types/components/BlockRepeaterFieldNode/BlockRepeaterNode.vue.d.ts +0 -15
- package/dist/types/components/BrowserNavigation/BrowserNavigation.vue.d.ts +0 -5
- package/dist/types/components/EmptyState/EmptyState.vue.d.ts +0 -15
- package/dist/types/components/PageBlockList/PageBlockList.vue.d.ts +0 -19
- package/dist/types/components/PageBuilderSidebar/PageBuilderSidebar.vue.d.ts +0 -35
- package/dist/types/components/PageBuilderToolbar/PageBuilderToolbar.vue.d.ts +0 -28
- package/dist/types/components/PageRenderer/PageRenderer.vue.d.ts +0 -13
- package/dist/types/components/PageRenderer/blockModules.d.ts +0 -1
- package/dist/types/components/PageRenderer/layoutModules.d.ts +0 -1
- package/dist/types/components/PageSettings/PageSettings.vue.d.ts +0 -17
- package/dist/types/components/ResizeHandle/ResizeHandle.vue.d.ts +0 -6
- package/dist/types/components/WswgJsonEditor/WswgJsonEditor.test.d.ts +0 -1
- package/dist/types/components/WswgJsonEditor/WswgJsonEditor.vue.d.ts +0 -36
- package/dist/types/index.d.ts +0 -8
- package/dist/types/util/fieldConfig.d.ts +0 -83
- package/dist/types/util/helpers.d.ts +0 -28
- package/dist/types/util/registry.d.ts +0 -20
- package/dist/types/util/validation.d.ts +0 -15
- package/dist/types/vite-plugin.d.ts +0 -9
- package/dist/vite-plugin.js +0 -76
package/src/util/fieldConfig.ts
CHANGED
|
@@ -26,6 +26,8 @@ export type EditorFieldType =
|
|
|
26
26
|
| "repeater" // ✅
|
|
27
27
|
| "margin" // ✅
|
|
28
28
|
| "info" // ✅
|
|
29
|
+
| "image" // ✅
|
|
30
|
+
| "object" // ✅
|
|
29
31
|
| "custom"; // 🔌 (image, json, video, richtext, etc)
|
|
30
32
|
|
|
31
33
|
/**
|
|
@@ -57,6 +59,8 @@ export interface EditorFieldConfig {
|
|
|
57
59
|
// Repeater-specific properties
|
|
58
60
|
repeaterFields?: Record<string, EditorFieldConfig>;
|
|
59
61
|
repeaterFieldLabel?: string; // attribute key for the repeater field label
|
|
62
|
+
// Object-specific properties
|
|
63
|
+
objectFields?: Record<string, EditorFieldConfig>; // nested fields for object type
|
|
60
64
|
// String length validation
|
|
61
65
|
minLength?: number;
|
|
62
66
|
maxLength?: number;
|
|
@@ -69,6 +73,9 @@ export interface EditorFieldConfig {
|
|
|
69
73
|
// Image specific
|
|
70
74
|
// Whether the image is responsive eg: xs, sm, md, lg, xl, primary
|
|
71
75
|
responsive?: boolean;
|
|
76
|
+
// Range specific
|
|
77
|
+
// Suffix to display after the range value (e.g., "px", "%", "rem")
|
|
78
|
+
valueSuffix?: string;
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
/**
|
|
@@ -156,6 +163,11 @@ export const createField = {
|
|
|
156
163
|
...config,
|
|
157
164
|
}),
|
|
158
165
|
|
|
166
|
+
image: (config: Partial<EditorFieldConfig> = {}): EditorFieldConfig => ({
|
|
167
|
+
type: "image",
|
|
168
|
+
...config,
|
|
169
|
+
}),
|
|
170
|
+
|
|
159
171
|
margin: (config: Partial<EditorFieldConfig> = {}): EditorFieldConfig => ({
|
|
160
172
|
type: "margin",
|
|
161
173
|
options: [
|
|
@@ -177,4 +189,14 @@ export const createField = {
|
|
|
177
189
|
type: "info",
|
|
178
190
|
...config,
|
|
179
191
|
}),
|
|
192
|
+
|
|
193
|
+
// Object field for nested properties (e.g., meta.description)
|
|
194
|
+
object: (
|
|
195
|
+
objectFields: Record<string, EditorFieldConfig>,
|
|
196
|
+
config: Partial<EditorFieldConfig> = {}
|
|
197
|
+
): EditorFieldConfig => ({
|
|
198
|
+
type: "object",
|
|
199
|
+
objectFields,
|
|
200
|
+
...config,
|
|
201
|
+
}),
|
|
180
202
|
};
|
package/src/util/helpers.ts
CHANGED
|
@@ -148,7 +148,7 @@ export function toCamelCase(input: string): string {
|
|
|
148
148
|
if (parts.length === 0) return "";
|
|
149
149
|
|
|
150
150
|
return (
|
|
151
|
-
parts
|
|
151
|
+
parts[0].toLowerCase() +
|
|
152
152
|
parts
|
|
153
153
|
.slice(1)
|
|
154
154
|
.map((p) => p.charAt(0).toUpperCase() + p.slice(1).toLowerCase())
|
package/src/util/registry.ts
CHANGED
|
@@ -3,14 +3,6 @@ import type { EditorFieldConfig } from "./fieldConfig";
|
|
|
3
3
|
import type { Block } from "../types/Block";
|
|
4
4
|
import type { Layout } from "../types/Layout";
|
|
5
5
|
import { generateNameVariations, toCamelCase } from "./helpers";
|
|
6
|
-
// Dynamic imports for all page builder blocks and layouts
|
|
7
|
-
// IMPORTANT: These globs use the @page-builder alias which must be configured in the CONSUMING APP's vite.config.ts
|
|
8
|
-
// The globs are evaluated by the consuming app's Vite build, so they resolve relative to the consuming app's project root
|
|
9
|
-
// The consuming app should have: "@page-builder": fileURLToPath(new URL("../page-builder", import.meta.url))
|
|
10
|
-
import { modules as layoutModules } from "vue-wswg-editor:layouts";
|
|
11
|
-
import { modules as blockModules } from "vue-wswg-editor:blocks";
|
|
12
|
-
import { modules as fieldModules } from "vue-wswg-editor:fields";
|
|
13
|
-
import { modules as thumbnailModules } from "vue-wswg-editor:thumbnails";
|
|
14
6
|
|
|
15
7
|
// Load all thumbnail images - Vite will process these as assets and provide URLs
|
|
16
8
|
// For images, Vite returns the URL as the default export when using eager: true
|
|
@@ -22,6 +14,8 @@ import { modules as thumbnailModules } from "vue-wswg-editor:thumbnails";
|
|
|
22
14
|
export const pageBuilderBlocks: Ref<Record<string, Block>> = shallowRef({});
|
|
23
15
|
export const pageBuilderLayouts: Ref<Record<string, Layout>> = shallowRef({});
|
|
24
16
|
const pageBuilderBlockFields: Ref<Record<string, any>> = ref({});
|
|
17
|
+
// Store thumbnail modules after lazy loading
|
|
18
|
+
let thumbnailModulesCache: Record<string, any> | null = null;
|
|
25
19
|
|
|
26
20
|
////////////////////////////////////////////////////////////
|
|
27
21
|
// Helper Functions
|
|
@@ -55,7 +49,7 @@ function markComponentsAsRaw(obj: any): any {
|
|
|
55
49
|
* Extract the default export from a module, handling different module formats
|
|
56
50
|
* Works with both eager and lazy-loaded modules from import.meta.glob
|
|
57
51
|
*/
|
|
58
|
-
function getModuleDefault(module: any): any {
|
|
52
|
+
export function getModuleDefault(module: any): any {
|
|
59
53
|
if (!module) return undefined;
|
|
60
54
|
|
|
61
55
|
// If module is a function (lazy-loaded), we'd need to await it, but with eager: true it should be resolved
|
|
@@ -98,11 +92,11 @@ export function getLayouts(): Record<string, Layout> {
|
|
|
98
92
|
* @returns Thumbnail URL or undefined if not found
|
|
99
93
|
*/
|
|
100
94
|
export function getBlockThumbnailUrl(directory: string | undefined): string | undefined {
|
|
101
|
-
if (!directory) return undefined;
|
|
95
|
+
if (!directory || !thumbnailModulesCache) return undefined;
|
|
102
96
|
// Construct the thumbnail path from the directory
|
|
103
97
|
const thumbnailPath = `${directory}/thumbnail.png`;
|
|
104
98
|
// Look up the thumbnail in the preloaded modules
|
|
105
|
-
const thumbnailModule =
|
|
99
|
+
const thumbnailModule = thumbnailModulesCache[thumbnailPath];
|
|
106
100
|
if (!thumbnailModule) return undefined;
|
|
107
101
|
// For images, Vite returns an object with a default property containing the URL
|
|
108
102
|
// When using eager: true, the module is already loaded
|
|
@@ -152,6 +146,9 @@ async function initialiseBlockFieldsRegistry(): Promise<void> {
|
|
|
152
146
|
delete pageBuilderBlockFields.value[key];
|
|
153
147
|
});
|
|
154
148
|
|
|
149
|
+
// Lazy load virtual modules to prevent initialization order issues
|
|
150
|
+
const { modules: fieldModules } = await import("vue-wswg-editor:fields");
|
|
151
|
+
|
|
155
152
|
for (const [path, module] of Object.entries(fieldModules)) {
|
|
156
153
|
let resolvedModule = module;
|
|
157
154
|
// If module is a function (lazy-loaded), call it to get the actual module
|
|
@@ -169,19 +166,21 @@ async function initialiseLayoutRegistry(): Promise<void> {
|
|
|
169
166
|
delete pageBuilderLayouts.value[key];
|
|
170
167
|
});
|
|
171
168
|
|
|
172
|
-
//
|
|
173
|
-
const
|
|
169
|
+
// Lazy load virtual modules to prevent initialization order issues
|
|
170
|
+
const { modules: layoutModules } = await import("vue-wswg-editor:layouts");
|
|
174
171
|
|
|
175
172
|
// Handle both eager-loaded modules and lazy-loaded modules (functions)
|
|
176
|
-
for (const [, module] of Object.entries(
|
|
173
|
+
for (const [, module] of Object.entries(layoutModules)) {
|
|
177
174
|
let resolvedModule = module;
|
|
178
175
|
// If module is a function (lazy-loaded), call it to get the actual module
|
|
179
176
|
if (typeof module === "function") {
|
|
180
177
|
resolvedModule = await module();
|
|
181
178
|
}
|
|
182
179
|
const layout = getModuleDefault(resolvedModule);
|
|
183
|
-
// exclude modules without name
|
|
184
|
-
if (!layout || !layout.label)
|
|
180
|
+
// exclude modules without name or label - use continue instead of return to skip this iteration
|
|
181
|
+
if (!layout || !layout.label) {
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
185
184
|
// Mark layout component as raw to prevent Vue from making it reactive
|
|
186
185
|
pageBuilderLayouts.value[layout.__name] = markRaw(layout);
|
|
187
186
|
}
|
|
@@ -193,6 +192,9 @@ async function initialiseBlockRegistry(): Promise<void> {
|
|
|
193
192
|
delete pageBuilderBlocks.value[key];
|
|
194
193
|
});
|
|
195
194
|
|
|
195
|
+
// Lazy load virtual modules to prevent initialization order issues
|
|
196
|
+
const { modules: blockModules } = await import("vue-wswg-editor:blocks");
|
|
197
|
+
|
|
196
198
|
// Load all blocks from the glob pattern
|
|
197
199
|
// With eager: true, module is the actual module object, not a loader function
|
|
198
200
|
for (const [path, module] of Object.entries(blockModules)) {
|
|
@@ -220,11 +222,16 @@ async function initialiseBlockRegistry(): Promise<void> {
|
|
|
220
222
|
}
|
|
221
223
|
|
|
222
224
|
export async function initialiseRegistry(): Promise<void> {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
225
|
+
try {
|
|
226
|
+
// Lazy load thumbnail modules for getBlockThumbnailUrl
|
|
227
|
+
const { modules: thumbnailModules } = await import("vue-wswg-editor:thumbnails");
|
|
228
|
+
thumbnailModulesCache = thumbnailModules;
|
|
227
229
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
230
|
+
await initialiseLayoutRegistry();
|
|
231
|
+
await initialiseBlockFieldsRegistry();
|
|
232
|
+
await initialiseBlockRegistry();
|
|
233
|
+
} catch (error) {
|
|
234
|
+
console.error("[vue-wswg-editor:registry] Error during registry initialization:", error);
|
|
235
|
+
throw error;
|
|
236
|
+
}
|
|
237
|
+
}
|
package/src/util/validation.ts
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
import type { ValidatorFunction } from "./fieldConfig";
|
|
1
|
+
import type { EditorFieldConfig, ValidatorFunction } from "./fieldConfig";
|
|
2
2
|
import { getBlockComponent, getLayoutFields } from "./registry";
|
|
3
3
|
import { toNiceName } from "./helpers";
|
|
4
4
|
|
|
5
|
-
export function validateField(value: any,
|
|
6
|
-
|
|
5
|
+
export function validateField(value: any, fieldConfig: EditorFieldConfig) {
|
|
6
|
+
// Create generic validator from field config properties (minLength, maxLength, etc.)
|
|
7
|
+
const genericValidator = createGenericValidator(fieldConfig);
|
|
8
|
+
|
|
9
|
+
// Combine generic validator with custom validator if provided
|
|
10
|
+
const combinedValidator = combineValidators(genericValidator, fieldConfig.validator);
|
|
11
|
+
|
|
12
|
+
// If no validator exists, clear any error message
|
|
13
|
+
if (!combinedValidator) return true;
|
|
14
|
+
|
|
15
|
+
// Validate the value
|
|
16
|
+
return combinedValidator(value);
|
|
7
17
|
}
|
|
8
18
|
|
|
9
19
|
export interface ValidationResult {
|
|
@@ -33,8 +43,8 @@ export async function validateAllFields(
|
|
|
33
43
|
}
|
|
34
44
|
|
|
35
45
|
// Validate blocks
|
|
36
|
-
const blockResults = await validateBlocks(value, blocksKey);
|
|
37
|
-
Object.assign(validationResults, blockResults);
|
|
46
|
+
// const blockResults = await validateBlocks(value, blocksKey);
|
|
47
|
+
// Object.assign(validationResults, blockResults);
|
|
38
48
|
|
|
39
49
|
return validationResults;
|
|
40
50
|
}
|
|
@@ -48,18 +58,15 @@ async function validateSettings(value: any, settingsKey: string = "settings"): P
|
|
|
48
58
|
|
|
49
59
|
if (!value[settingsKey]) return validationResult;
|
|
50
60
|
const layoutOptions = getLayoutFields(value[settingsKey].layout);
|
|
51
|
-
|
|
52
61
|
// Loop each field in the settings
|
|
53
62
|
for (const field in value[settingsKey]) {
|
|
54
63
|
const fieldConfig = layoutOptions[field];
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
validationResult.isValid = false;
|
|
62
|
-
}
|
|
64
|
+
if (!fieldConfig) continue;
|
|
65
|
+
const result = await validateField(value[settingsKey][field], fieldConfig);
|
|
66
|
+
// If validation fails (returns false or a string), add to validation results
|
|
67
|
+
if (result !== true) {
|
|
68
|
+
validationResult.errors[fieldConfig.label || field] = result;
|
|
69
|
+
validationResult.isValid = false;
|
|
63
70
|
}
|
|
64
71
|
}
|
|
65
72
|
|
|
@@ -81,7 +88,7 @@ async function validateBlocks(value: any, blocksKey: string = "blocks"): Promise
|
|
|
81
88
|
|
|
82
89
|
// Add validation results entry for the section
|
|
83
90
|
validationResults[blockType] = {
|
|
84
|
-
title: toNiceName(blockType),
|
|
91
|
+
title: blockComponent.label || toNiceName(blockType),
|
|
85
92
|
isValid: true,
|
|
86
93
|
errors: {},
|
|
87
94
|
};
|
|
@@ -94,17 +101,165 @@ async function validateBlocks(value: any, blocksKey: string = "blocks"): Promise
|
|
|
94
101
|
// Loop each field in the block
|
|
95
102
|
for (const field in blockComponent?.fields || {}) {
|
|
96
103
|
const fieldConfig = blockComponent?.fields?.[field];
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
104
|
+
if (!fieldConfig) continue;
|
|
105
|
+
// Validate
|
|
106
|
+
const result = await validateField(block[field], fieldConfig);
|
|
107
|
+
// If validation fails (returns false or a string), add to validation results
|
|
108
|
+
if (result !== true) {
|
|
109
|
+
validationResults[blockType].errors[fieldConfig.label || field] = result;
|
|
110
|
+
validationResults[blockType].isValid = false;
|
|
105
111
|
}
|
|
106
112
|
}
|
|
107
113
|
}
|
|
108
114
|
// Return validation results if there are any errors, otherwise return true
|
|
109
115
|
return validationResults;
|
|
110
116
|
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Creates a generic validator function based on field config properties
|
|
120
|
+
* Handles: required, minLength, maxLength, min, max, minItems, maxItems
|
|
121
|
+
* Returns a ValidatorFunction that can be combined with custom validators
|
|
122
|
+
*/
|
|
123
|
+
export function createGenericValidator(fieldConfig: EditorFieldConfig): ValidatorFunction | null {
|
|
124
|
+
const validations: Array<(value: any) => Promise<boolean | string>> = [];
|
|
125
|
+
|
|
126
|
+
// Required validation
|
|
127
|
+
if (fieldConfig.required) {
|
|
128
|
+
validations.push(async (value: any) => {
|
|
129
|
+
if (value === null || value === undefined || value === "") {
|
|
130
|
+
return "This field is required";
|
|
131
|
+
}
|
|
132
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
133
|
+
return "This field is required";
|
|
134
|
+
}
|
|
135
|
+
return true;
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// String length validations (for text, textarea, email, url)
|
|
140
|
+
if (
|
|
141
|
+
fieldConfig.type === "text" ||
|
|
142
|
+
fieldConfig.type === "textarea" ||
|
|
143
|
+
fieldConfig.type === "email" ||
|
|
144
|
+
fieldConfig.type === "url"
|
|
145
|
+
) {
|
|
146
|
+
if (fieldConfig.minLength !== undefined) {
|
|
147
|
+
validations.push(async (value: any) => {
|
|
148
|
+
if (value === null || value === undefined || value === "") return true; // Skip if empty (required handles this)
|
|
149
|
+
const strValue = String(value);
|
|
150
|
+
if (strValue.length < fieldConfig.minLength!) {
|
|
151
|
+
return `Must be at least ${fieldConfig.minLength} characters`;
|
|
152
|
+
}
|
|
153
|
+
return true;
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (fieldConfig.maxLength !== undefined) {
|
|
158
|
+
validations.push(async (value: any) => {
|
|
159
|
+
if (value === null || value === undefined || value === "") return true; // Skip if empty
|
|
160
|
+
const strValue = String(value);
|
|
161
|
+
if (strValue.length >= fieldConfig.maxLength!) {
|
|
162
|
+
return `Must be no more than ${fieldConfig.maxLength} characters`;
|
|
163
|
+
}
|
|
164
|
+
return true;
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Number validations
|
|
170
|
+
if (fieldConfig.type === "number" || fieldConfig.type === "range") {
|
|
171
|
+
if (fieldConfig.min !== undefined) {
|
|
172
|
+
validations.push(async (value: any) => {
|
|
173
|
+
if (value === null || value === undefined || value === "") return true; // Skip if empty
|
|
174
|
+
const numValue = Number(value);
|
|
175
|
+
if (isNaN(numValue) || numValue < fieldConfig.min!) {
|
|
176
|
+
return `Must be at least ${fieldConfig.min}`;
|
|
177
|
+
}
|
|
178
|
+
return true;
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (fieldConfig.max !== undefined) {
|
|
183
|
+
validations.push(async (value: any) => {
|
|
184
|
+
if (value === null || value === undefined || value === "") return true; // Skip if empty
|
|
185
|
+
const numValue = Number(value);
|
|
186
|
+
if (isNaN(numValue) || numValue > fieldConfig.max!) {
|
|
187
|
+
return `Must be no more than ${fieldConfig.max}`;
|
|
188
|
+
}
|
|
189
|
+
return true;
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Repeater validations
|
|
195
|
+
if (fieldConfig.type === "repeater") {
|
|
196
|
+
if (fieldConfig.minItems !== undefined) {
|
|
197
|
+
validations.push(async (value: any) => {
|
|
198
|
+
if (!Array.isArray(value)) return true; // Skip if not array
|
|
199
|
+
if (value.length < fieldConfig.minItems!) {
|
|
200
|
+
return `Must have at least ${fieldConfig.minItems} item${fieldConfig.minItems! > 1 ? "s" : ""}`;
|
|
201
|
+
}
|
|
202
|
+
return true;
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (fieldConfig.maxItems !== undefined) {
|
|
207
|
+
validations.push(async (value: any) => {
|
|
208
|
+
if (!Array.isArray(value)) return true; // Skip if not array
|
|
209
|
+
if (value.length > fieldConfig.maxItems!) {
|
|
210
|
+
return `Must have no more than ${fieldConfig.maxItems} item${fieldConfig.maxItems! > 1 ? "s" : ""}`;
|
|
211
|
+
}
|
|
212
|
+
return true;
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// If no built-in validations, return null
|
|
218
|
+
if (validations.length === 0) {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Return a combined validator function
|
|
223
|
+
return async (value: any): Promise<boolean | string> => {
|
|
224
|
+
for (const validation of validations) {
|
|
225
|
+
const result = await validation(value);
|
|
226
|
+
if (result !== true) {
|
|
227
|
+
return result;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return true;
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Combines a generic validator (built-in validations) with a custom validator
|
|
236
|
+
* Runs built-in validations first, then custom validator if provided
|
|
237
|
+
*/
|
|
238
|
+
export function combineValidators(
|
|
239
|
+
genericValidator: ValidatorFunction | null,
|
|
240
|
+
customValidator?: ValidatorFunction
|
|
241
|
+
): ValidatorFunction | undefined {
|
|
242
|
+
if (!genericValidator && !customValidator) {
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (!genericValidator) {
|
|
247
|
+
return customValidator;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (!customValidator) {
|
|
251
|
+
return genericValidator;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Return combined validator that runs both
|
|
255
|
+
return async (value: any): Promise<boolean | string> => {
|
|
256
|
+
// Run generic validator first
|
|
257
|
+
const genericResult = await genericValidator(value);
|
|
258
|
+
if (genericResult !== true) {
|
|
259
|
+
return genericResult;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Then run custom validator
|
|
263
|
+
return await customValidator(value);
|
|
264
|
+
};
|
|
265
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// Type declarations for vue-wswg-editor library dependencies
|
|
2
|
+
// These declarations allow the library to use internal dependencies without requiring
|
|
3
|
+
// consumers to install their type definitions
|
|
4
|
+
|
|
5
|
+
// SortableJS type declaration - self-contained for library consumers
|
|
6
|
+
// This allows the library to use sortablejs without requiring consumers to install @types/sortablejs
|
|
7
|
+
declare module "sortablejs" {
|
|
8
|
+
interface SortableOptions {
|
|
9
|
+
group?:
|
|
10
|
+
| string
|
|
11
|
+
| {
|
|
12
|
+
name?: string;
|
|
13
|
+
pull?: boolean | string | ((to: any, from: any, dragEl: HTMLElement) => boolean | string);
|
|
14
|
+
put?: boolean | string | ((to: any) => boolean | string);
|
|
15
|
+
};
|
|
16
|
+
sort?: boolean;
|
|
17
|
+
delay?: number;
|
|
18
|
+
delayOnTouchStart?: boolean;
|
|
19
|
+
touchStartThreshold?: number;
|
|
20
|
+
disabled?: boolean;
|
|
21
|
+
store?: { get: (sortable: any) => any[]; set: (sortable: any) => void };
|
|
22
|
+
animation?: number;
|
|
23
|
+
easing?: string;
|
|
24
|
+
handle?: string;
|
|
25
|
+
filter?: string | ((event: Event | TouchEvent) => boolean);
|
|
26
|
+
preventOnFilter?: boolean;
|
|
27
|
+
draggable?: string;
|
|
28
|
+
dataIdAttr?: string;
|
|
29
|
+
ghostClass?: string;
|
|
30
|
+
chosenClass?: string;
|
|
31
|
+
dragClass?: string;
|
|
32
|
+
swapThreshold?: number;
|
|
33
|
+
invertSwap?: boolean;
|
|
34
|
+
invertedSwapThreshold?: number;
|
|
35
|
+
direction?: "vertical" | "horizontal";
|
|
36
|
+
forceFallback?: boolean;
|
|
37
|
+
fallbackClass?: string;
|
|
38
|
+
fallbackOnBody?: boolean;
|
|
39
|
+
fallbackTolerance?: number;
|
|
40
|
+
fallbackOffset?: { x: number; y: number };
|
|
41
|
+
supportPointer?: boolean;
|
|
42
|
+
emptyInsertThreshold?: number;
|
|
43
|
+
setData?: (dataTransfer: DataTransfer, dragEl: HTMLElement) => void;
|
|
44
|
+
onStart?: (evt: any) => void;
|
|
45
|
+
onEnd?: (evt: any) => void;
|
|
46
|
+
onAdd?: (evt: any) => void;
|
|
47
|
+
onUpdate?: (evt: any) => void;
|
|
48
|
+
onSort?: (evt: any) => void;
|
|
49
|
+
onRemove?: (evt: any) => void;
|
|
50
|
+
onFilter?: (evt: any) => void;
|
|
51
|
+
onMove?: (evt: any, originalEvent: Event) => boolean | -1 | 1 | void;
|
|
52
|
+
onClone?: (evt: any) => void;
|
|
53
|
+
[key: string]: any;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
class Sortable {
|
|
57
|
+
constructor(element: HTMLElement, options?: SortableOptions);
|
|
58
|
+
option(name: string, value?: any): any;
|
|
59
|
+
destroy(): void;
|
|
60
|
+
el: HTMLElement;
|
|
61
|
+
options: SortableOptions;
|
|
62
|
+
static active: Sortable | null;
|
|
63
|
+
static utils: {
|
|
64
|
+
on(el: HTMLElement, event: string, fn: (evt: Event) => void): void;
|
|
65
|
+
off(el: HTMLElement, event: string, fn: (evt: Event) => void): void;
|
|
66
|
+
get(el: HTMLElement, path: string): any;
|
|
67
|
+
set(el: HTMLElement, path: string, value: any): void;
|
|
68
|
+
closest(el: HTMLElement, selector: string): HTMLElement | null;
|
|
69
|
+
matches(el: HTMLElement, selector: string): boolean;
|
|
70
|
+
find(el: HTMLElement, selector: string): HTMLElement[];
|
|
71
|
+
create(tag: string, classes?: string): HTMLElement;
|
|
72
|
+
is(el: HTMLElement, selector: string): boolean;
|
|
73
|
+
extend(dest: any, ...src: any[]): any;
|
|
74
|
+
throttle(fn: (...args: any[]) => any, wait: number): (...args: any[]) => any;
|
|
75
|
+
debounce(fn: (...args: any[]) => any, wait: number): (...args: any[]) => any;
|
|
76
|
+
clone(el: HTMLElement): HTMLElement;
|
|
77
|
+
toggleClass(el: HTMLElement, name: string, state?: boolean): void;
|
|
78
|
+
index(el: HTMLElement, selector?: string): number;
|
|
79
|
+
nextTick(fn: () => void): void;
|
|
80
|
+
cancelNextTick(id: number): void;
|
|
81
|
+
detectDirection(el: HTMLElement): "vertical" | "horizontal";
|
|
82
|
+
getChild(el: HTMLElement, childNum: number): HTMLElement | null;
|
|
83
|
+
};
|
|
84
|
+
static mount(...plugins: any[]): void;
|
|
85
|
+
static create(element: HTMLElement, options?: SortableOptions): Sortable;
|
|
86
|
+
static get(element: HTMLElement): Sortable | undefined;
|
|
87
|
+
static readonly version: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export = Sortable;
|
|
91
|
+
export default Sortable;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Yup type declaration - self-contained for library consumers
|
|
95
|
+
// This allows the library to use yup without requiring consumers to install yup types
|
|
96
|
+
declare module "yup" {
|
|
97
|
+
export interface Schema<T = any> {
|
|
98
|
+
validate(value: any, options?: any): Promise<T>;
|
|
99
|
+
isValid(value: any, options?: any): Promise<boolean>;
|
|
100
|
+
validateSync(value: any, options?: any): T;
|
|
101
|
+
isValidSync(value: any, options?: any): boolean;
|
|
102
|
+
cast(value: any, options?: any): T;
|
|
103
|
+
nullable(isNullable?: boolean): Schema<T | null>;
|
|
104
|
+
required(message?: string): Schema<T>;
|
|
105
|
+
notRequired(): Schema<T | undefined>;
|
|
106
|
+
default(value: T | (() => T)): Schema<T>;
|
|
107
|
+
typeError(message?: string): Schema<T>;
|
|
108
|
+
oneOf(values: any[], message?: string): Schema<T>;
|
|
109
|
+
notOneOf(values: any[], message?: string): Schema<T>;
|
|
110
|
+
when(keys: string | string[], builder: any): Schema<T>;
|
|
111
|
+
test(
|
|
112
|
+
name: string,
|
|
113
|
+
message: string | ((value: any) => string),
|
|
114
|
+
test: (value: any) => boolean | Promise<boolean>
|
|
115
|
+
): Schema<T>;
|
|
116
|
+
transform(transform: (value: any) => any): Schema<T>;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function string(): Schema<string>;
|
|
120
|
+
export function number(): Schema<number>;
|
|
121
|
+
export function boolean(): Schema<boolean>;
|
|
122
|
+
export function date(): Schema<Date>;
|
|
123
|
+
export function object(shape?: Record<string, Schema>): Schema<Record<string, any>>;
|
|
124
|
+
export function array(of?: Schema): Schema<any[]>;
|
|
125
|
+
export function mixed(): Schema<any>;
|
|
126
|
+
export function lazy(fn: () => Schema): Schema;
|
|
127
|
+
export function reach(schema: Schema, path: string, value?: any, context?: any): Schema;
|
|
128
|
+
export function ref(path: string, options?: { contextPrefix?: string }): any;
|
|
129
|
+
export function setLocale(customLocale: Record<string, any>): void;
|
|
130
|
+
export function getLocale(): Record<string, any>;
|
|
131
|
+
export function addMethod(schemaType: string, name: string, method: (...args: any[]) => any): void;
|
|
132
|
+
export class ValidationError extends Error {
|
|
133
|
+
value: any;
|
|
134
|
+
path: string;
|
|
135
|
+
type?: string;
|
|
136
|
+
errors: string[];
|
|
137
|
+
inner: ValidationError[];
|
|
138
|
+
params?: Record<string, any>;
|
|
139
|
+
constructor(errors: string | string[], value: any, path?: string, type?: string);
|
|
140
|
+
}
|
|
141
|
+
export const mixed: {
|
|
142
|
+
(): Schema<any>;
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// Virtual modules created by vue-wswg-editor vite plugin
|
|
147
|
+
declare module "vue-wswg-editor:layouts" {
|
|
148
|
+
export const modules: Record<string, () => Promise<any>>;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
declare module "vue-wswg-editor:blocks" {
|
|
152
|
+
export const modules: Record<string, () => Promise<any>>;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
declare module "vue-wswg-editor:fields" {
|
|
156
|
+
export const modules: Record<string, () => Promise<any>>;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
declare module "vue-wswg-editor:thumbnails" {
|
|
160
|
+
export const modules: Record<string, () => Promise<any>>;
|
|
161
|
+
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { Block } from "../../types/Block";
|
|
2
|
-
type __VLS_Props = {
|
|
3
|
-
block: Block;
|
|
4
|
-
};
|
|
5
|
-
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
6
|
-
export default _default;
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
-
export default _default;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Block } from "../../types/Block";
|
|
2
|
-
type __VLS_Props = {
|
|
3
|
-
block: Block;
|
|
4
|
-
blockIndex: number;
|
|
5
|
-
activeBlock: Block | null;
|
|
6
|
-
hoveredBlockId: string | null;
|
|
7
|
-
};
|
|
8
|
-
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
9
|
-
hoverBlock: (id: string | null) => any;
|
|
10
|
-
clickBlock: (block: any) => any;
|
|
11
|
-
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
12
|
-
onHoverBlock?: ((id: string | null) => any) | undefined;
|
|
13
|
-
onClickBlock?: ((block: any) => any) | undefined;
|
|
14
|
-
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
|
-
export default _default;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { EditorFieldConfig } from "../../util/fieldConfig";
|
|
2
|
-
type __VLS_Props = {
|
|
3
|
-
fieldConfig: EditorFieldConfig;
|
|
4
|
-
fieldName: string;
|
|
5
|
-
editable: boolean;
|
|
6
|
-
};
|
|
7
|
-
type __VLS_PublicProps = __VLS_Props & {
|
|
8
|
-
modelValue?: any;
|
|
9
|
-
};
|
|
10
|
-
declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
|
-
"update:modelValue": (value: any) => any;
|
|
12
|
-
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
|
-
"onUpdate:modelValue"?: ((value: any) => any) | undefined;
|
|
14
|
-
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
|
-
export default _default;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { EditorFieldConfig } from "../../util/fieldConfig";
|
|
2
|
-
type __VLS_Props = {
|
|
3
|
-
fields?: Record<string, EditorFieldConfig>;
|
|
4
|
-
editable: boolean;
|
|
5
|
-
isLayoutBlock?: boolean;
|
|
6
|
-
};
|
|
7
|
-
type __VLS_PublicProps = __VLS_Props & {
|
|
8
|
-
modelValue?: any;
|
|
9
|
-
};
|
|
10
|
-
declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
11
|
-
"update:modelValue": (value: any) => any;
|
|
12
|
-
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
|
-
"onUpdate:modelValue"?: ((value: any) => any) | undefined;
|
|
14
|
-
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
15
|
-
export default _default;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { EditorFieldConfig } from "../../util/fieldConfig";
|
|
2
|
-
type __VLS_Props = {
|
|
3
|
-
fieldConfig: EditorFieldConfig;
|
|
4
|
-
editable: boolean;
|
|
5
|
-
};
|
|
6
|
-
type __VLS_PublicProps = __VLS_Props & {
|
|
7
|
-
modelValue?: {
|
|
8
|
-
top: string;
|
|
9
|
-
bottom: string;
|
|
10
|
-
} | undefined;
|
|
11
|
-
};
|
|
12
|
-
declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
13
|
-
"update:modelValue": (value: {
|
|
14
|
-
top: string;
|
|
15
|
-
bottom: string;
|
|
16
|
-
} | undefined) => any;
|
|
17
|
-
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
18
|
-
"onUpdate:modelValue"?: ((value: {
|
|
19
|
-
top: string;
|
|
20
|
-
bottom: string;
|
|
21
|
-
} | undefined) => any) | undefined;
|
|
22
|
-
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
23
|
-
export default _default;
|