vue-wswg-editor 0.0.11 → 0.0.13

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.
Files changed (72) hide show
  1. package/README.md +23 -8
  2. package/dist/style.css +1 -1
  3. package/dist/types/components/AddBlockItem/AddBlockItem.vue.d.ts +6 -0
  4. package/dist/types/components/BlockBrowser/BlockBrowser.vue.d.ts +2 -0
  5. package/dist/types/components/BlockComponent/BlockComponent.vue.d.ts +15 -0
  6. package/dist/types/components/BlockEditorFieldNode/BlockEditorFieldNode.vue.d.ts +15 -0
  7. package/dist/types/components/BlockEditorFields/BlockEditorFields.vue.d.ts +17 -0
  8. package/dist/types/components/BlockImageFieldNode/BlockImageNode.vue.d.ts +19 -0
  9. package/dist/types/components/BlockMarginFieldNode/BlockMarginNode.vue.d.ts +23 -0
  10. package/dist/types/components/BlockRepeaterFieldNode/BlockRepeaterNode.vue.d.ts +15 -0
  11. package/dist/types/components/BrowserNavigation/BrowserNavigation.vue.d.ts +5 -0
  12. package/dist/types/components/EditorPageRenderer/EditorPageRenderer.vue.d.ts +21 -0
  13. package/dist/types/components/EmptyState/EmptyState.vue.d.ts +9 -0
  14. package/dist/types/components/IframePreview/IframePreview.vue.d.ts +26 -0
  15. package/dist/types/components/IframePreview/iframeContent.d.ts +9 -0
  16. package/dist/types/components/IframePreview/iframePreviewApp.d.ts +36 -0
  17. package/dist/types/components/IframePreview/messageHandler.d.ts +55 -0
  18. package/dist/types/components/IframePreview/types.d.ts +77 -0
  19. package/dist/types/components/PageBlockList/PageBlockList.vue.d.ts +19 -0
  20. package/dist/types/components/PageBuilderSidebar/PageBuilderSidebar.vue.d.ts +37 -0
  21. package/dist/types/components/PageBuilderToolbar/PageBuilderToolbar.vue.d.ts +28 -0
  22. package/dist/types/components/PageRenderer/PageRenderer.vue.d.ts +15 -0
  23. package/dist/types/components/PageSettings/PageSettings.vue.d.ts +19 -0
  24. package/dist/types/components/ResizeHandle/ResizeHandle.vue.d.ts +6 -0
  25. package/dist/types/components/WswgPageBuilder/WswgPageBuilder.test.d.ts +1 -0
  26. package/dist/types/components/WswgPageBuilder/WswgPageBuilder.vue.d.ts +38 -0
  27. package/dist/types/index.d.ts +13 -0
  28. package/dist/types/util/fieldConfig.d.ts +87 -0
  29. package/dist/types/util/helpers.d.ts +28 -0
  30. package/dist/types/util/registry.d.ts +27 -0
  31. package/dist/types/util/theme-registry.d.ts +42 -0
  32. package/dist/types/util/validation.d.ts +26 -0
  33. package/dist/types/vite-plugin.d.ts +9 -0
  34. package/dist/vite-plugin.js +80 -0
  35. package/dist/vue-wswg-editor.es.js +2854 -2006
  36. package/package.json +1 -2
  37. package/src/assets/styles/_mixins.scss +15 -0
  38. package/src/components/AddBlockItem/AddBlockItem.vue +13 -4
  39. package/src/components/BlockBrowser/BlockBrowser.vue +5 -5
  40. package/src/components/BlockComponent/BlockComponent.vue +23 -50
  41. package/src/components/BlockEditorFieldNode/BlockEditorFieldNode.vue +12 -10
  42. package/src/components/BlockEditorFields/BlockEditorFields.vue +24 -4
  43. package/src/components/BlockRepeaterFieldNode/BlockRepeaterNode.vue +9 -4
  44. package/src/components/BrowserNavigation/BrowserNavigation.vue +1 -1
  45. package/src/components/EditorPageRenderer/EditorPageRenderer.vue +641 -0
  46. package/src/components/EmptyState/EmptyState.vue +3 -12
  47. package/src/components/IframePreview/IframePreview.vue +211 -0
  48. package/src/components/IframePreview/iframeContent.ts +210 -0
  49. package/src/components/IframePreview/iframePreviewApp.ts +221 -0
  50. package/src/components/IframePreview/messageHandler.ts +219 -0
  51. package/src/components/IframePreview/types.ts +126 -0
  52. package/src/components/PageBlockList/PageBlockList.vue +8 -6
  53. package/src/components/PageBuilderSidebar/PageBuilderSidebar.vue +5 -3
  54. package/src/components/PageRenderer/PageRenderer.vue +9 -33
  55. package/src/components/PageSettings/PageSettings.vue +10 -6
  56. package/src/components/ResizeHandle/ResizeHandle.vue +68 -10
  57. package/src/components/{WswgJsonEditor/WswgJsonEditor.test.ts → WswgPageBuilder/WswgPageBuilder.test.ts} +8 -8
  58. package/src/components/WswgPageBuilder/WswgPageBuilder.vue +375 -0
  59. package/src/index.ts +10 -2
  60. package/src/shims.d.ts +4 -0
  61. package/src/types/Theme.d.ts +15 -0
  62. package/src/util/registry.ts +2 -2
  63. package/src/util/theme-registry.ts +397 -0
  64. package/src/util/validation.ts +104 -13
  65. package/src/vite-plugin.ts +8 -4
  66. package/types/vue-wswg-editor.d.ts +4 -0
  67. package/src/components/PageRenderer/blockModules-alternative.ts.example +0 -9
  68. package/src/components/PageRenderer/blockModules-manual.ts.example +0 -19
  69. package/src/components/PageRenderer/blockModules-runtime.ts.example +0 -23
  70. package/src/components/PageRenderer/blockModules.ts +0 -32
  71. package/src/components/PageRenderer/layoutModules.ts +0 -32
  72. package/src/components/WswgJsonEditor/WswgJsonEditor.vue +0 -595
@@ -1,18 +1,18 @@
1
1
  import { describe, it, expect } from "vitest";
2
2
  import { mount } from "@vue/test-utils";
3
- import WswgJsonEditor from "./WswgJsonEditor.vue";
3
+ import WswgPageBuilder from "./WswgPageBuilder.vue";
4
4
 
5
- describe("WswgJsonEditor", () => {
5
+ describe("WswgPageBuilder", () => {
6
6
  it("renders the placeholder component", () => {
7
- const wrapper = mount(WswgJsonEditor);
7
+ const wrapper = mount(WswgPageBuilder);
8
8
 
9
- expect(wrapper.text()).toContain("WswgJsonEditor");
9
+ expect(wrapper.text()).toContain("WswgPageBuilder");
10
10
  expect(wrapper.text()).toContain("This is a placeholder component");
11
11
  });
12
12
 
13
13
  it("renders header slot content when provided", () => {
14
14
  const headerContent = "Custom Header Content";
15
- const wrapper = mount(WswgJsonEditor, {
15
+ const wrapper = mount(WswgPageBuilder, {
16
16
  slots: {
17
17
  header: headerContent,
18
18
  },
@@ -22,7 +22,7 @@ describe("WswgJsonEditor", () => {
22
22
  });
23
23
 
24
24
  it("renders header slot with HTML content", () => {
25
- const wrapper = mount(WswgJsonEditor, {
25
+ const wrapper = mount(WswgPageBuilder, {
26
26
  slots: {
27
27
  header: "<div class='custom-header'>Header Title</div>",
28
28
  },
@@ -33,10 +33,10 @@ describe("WswgJsonEditor", () => {
33
33
  });
34
34
 
35
35
  it("does not render header slot when not provided", () => {
36
- const wrapper = mount(WswgJsonEditor);
36
+ const wrapper = mount(WswgPageBuilder);
37
37
 
38
38
  // The component should still render without the header slot
39
- expect(wrapper.text()).toContain("WswgJsonEditor");
39
+ expect(wrapper.text()).toContain("WswgPageBuilder");
40
40
  // Header slot should be empty/not present
41
41
  expect(wrapper.html()).not.toContain("custom-header");
42
42
  });
@@ -0,0 +1,375 @@
1
+ <template>
2
+ <div class="wswg-page-builder" :class="{ 'settings-open': showPageSettings }">
3
+ <slot v-if="loading || themeLoading" name="loading">
4
+ <div class="wswg-page-builder-loading flex h-full flex-col items-center justify-center gap-4">
5
+ <svg
6
+ class="mx-auto size-8 animate-spin text-blue-600"
7
+ xmlns="http://www.w3.org/2000/svg"
8
+ fill="none"
9
+ viewBox="0 0 24 24"
10
+ >
11
+ <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
12
+
13
+ <path
14
+ class="opacity-75"
15
+ fill="currentColor"
16
+ d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
17
+ ></path>
18
+ </svg>
19
+ <span>Loading editor...</span>
20
+ </div>
21
+ </slot>
22
+ <!-- WYSIWYG editor -->
23
+ <div v-else class="wswg-page-builder-body">
24
+ <!-- Page preview -->
25
+ <div class="wswg-page-builder-preview overflow-y-auto">
26
+ <div
27
+ id="page-preview-container"
28
+ class="mx-auto flex flex-col overflow-hidden rounded-lg bg-white transition-all duration-300"
29
+ style="height: -webkit-fill-available"
30
+ :class="{ 'w-full': editorViewport === 'desktop', 'w-96': editorViewport === 'mobile' }"
31
+ >
32
+ <BrowserNavigation v-if="showBrowserBar" class="browser-navigation-bar" :url="url" />
33
+ <IframePreview
34
+ ref="previewRef"
35
+ :pageData="pageData"
36
+ :activeBlock="activeBlock"
37
+ :hoveredBlockId="hoveredBlockId"
38
+ :viewport="editorViewport"
39
+ :editable="editable"
40
+ :blocksKey="blocksKey"
41
+ :settingsKey="settingsKey"
42
+ :settingsOpen="showPageSettings"
43
+ :theme="theme"
44
+ @hover-block="setHoveredBlockId"
45
+ @click-block="handleBlockClick"
46
+ @block-reorder="handleBlockReorder"
47
+ @block-add="handleBlockAdd"
48
+ @click-partial="handleClickPartial"
49
+ />
50
+ </div>
51
+ </div>
52
+
53
+ <!-- Resizable divider -->
54
+ <ResizeHandle @sidebar-width="handleSidebarWidth" />
55
+
56
+ <!-- Sidebar -->
57
+ <div
58
+ id="page-builder-sidebar"
59
+ class="page-builder-sidebar-wrapper bg-white"
60
+ :style="{ width: sidebarWidth + 'px' }"
61
+ >
62
+ <PageBuilderSidebar
63
+ v-model="pageData"
64
+ v-model:activeBlock="activeBlock"
65
+ v-model:hoveredBlockId="hoveredBlockId"
66
+ v-model:showPageSettings="showPageSettings"
67
+ v-model:showAddBlockMenu="showAddBlockMenu"
68
+ v-model:editorViewport="editorViewport"
69
+ :hasPageSettings="hasPageSettings"
70
+ :editable="editable"
71
+ :blocksKey="blocksKey"
72
+ :settingsKey="settingsKey"
73
+ :activeSettingsTab="activeSettingsTab"
74
+ />
75
+ </div>
76
+ </div>
77
+ </div>
78
+ </template>
79
+
80
+ <script setup lang="ts">
81
+ import { ref, withDefaults, onBeforeMount, computed, watch } from "vue";
82
+ import ResizeHandle from "../ResizeHandle/ResizeHandle.vue";
83
+ import PageBuilderSidebar from "../PageBuilderSidebar/PageBuilderSidebar.vue";
84
+ import BrowserNavigation from "../BrowserNavigation/BrowserNavigation.vue";
85
+ import IframePreview from "../IframePreview/IframePreview.vue";
86
+ import { initialiseRegistry, getBlock, themeLayouts } from "../../util/theme-registry";
87
+ import type { Block } from "../../types/Block";
88
+ import { onKeyStroke, onClickOutside } from "@vueuse/core";
89
+
90
+ const props = withDefaults(
91
+ defineProps<{
92
+ editable?: boolean;
93
+ loading?: boolean;
94
+ url?: string;
95
+ showBrowserBar?: boolean;
96
+ blocksKey?: string;
97
+ settingsKey?: string;
98
+ defaultBlockMargin?: "none" | "small" | "medium" | "large";
99
+ theme?: string;
100
+ }>(),
101
+ {
102
+ editable: false,
103
+ loading: false,
104
+ url: "",
105
+ showBrowserBar: false,
106
+ blocksKey: "blocks",
107
+ settingsKey: "settings",
108
+ defaultBlockMargin: "none",
109
+ theme: "default",
110
+ }
111
+ );
112
+
113
+ const editorViewport = ref<"desktop" | "mobile">("desktop");
114
+ const showPageSettings = ref(false);
115
+ const showAddBlockMenu = ref(false);
116
+ const activeBlock = ref<any>(null);
117
+ const isSorting = ref(false);
118
+ const hoveredBlockId = ref<string | null>(null);
119
+ const activeSettingsTab = ref<string | undefined>(undefined);
120
+ const sidebarWidth = ref(380); // Default sidebar width (380px)
121
+ const previewRef = ref<HTMLElement | null>(null);
122
+ const themeLoading = ref(false);
123
+
124
+ // Model value for the JSON page data
125
+ const pageData = defineModel<Record<string, any>>();
126
+
127
+ // Apply the sidebar width from the resize handle
128
+ function handleSidebarWidth(width: number) {
129
+ sidebarWidth.value = width;
130
+ }
131
+
132
+ // Check if the page has settings
133
+ const hasPageSettings = computed(() => {
134
+ // Show page settings if there are multiple layouts to choose from
135
+ // Note: This computed might run before registry is initialized, so we check if layouts exist
136
+ if (Object.keys(themeLayouts).length > 1) {
137
+ return true;
138
+ }
139
+
140
+ // If the layout has settings
141
+ if (pageData.value?.[props.settingsKey]) {
142
+ if (Object.keys(pageData.value?.[props.settingsKey]).length > 0) {
143
+ return true;
144
+ }
145
+ }
146
+
147
+ return false;
148
+ });
149
+
150
+ function handleBlockClick(block: Block | null) {
151
+ activeBlock.value = block;
152
+ showPageSettings.value = false;
153
+ hoveredBlockId.value = null;
154
+ showAddBlockMenu.value = false;
155
+ }
156
+
157
+ async function handleAddBlock(blockType: string, insertIndex?: number) {
158
+ if (!pageData.value) return;
159
+
160
+ // Ensure blocks array exists
161
+ if (!pageData.value[props.blocksKey]) {
162
+ pageData.value[props.blocksKey] = [];
163
+ }
164
+
165
+ // Create a new block object
166
+ const newBlock = {
167
+ id: `block-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
168
+ type: blockType,
169
+ margin: props.defaultBlockMargin
170
+ ? { top: props.defaultBlockMargin, bottom: props.defaultBlockMargin }
171
+ : undefined,
172
+ };
173
+ // Get the default prop values from the block component
174
+ const blockComponent = getBlock(blockType);
175
+ if (blockComponent?.props) {
176
+ // loop props and set their default value
177
+ Object.entries(blockComponent.props).forEach(([key, value]: [string, any]) => {
178
+ if (value.default) {
179
+ if (typeof value.default === "function") {
180
+ newBlock[key as keyof typeof newBlock] = value.default();
181
+ } else {
182
+ newBlock[key as keyof typeof newBlock] = value.default;
183
+ }
184
+ }
185
+ });
186
+ }
187
+
188
+ // Add the new block at the specified index or at the end
189
+ if (insertIndex !== undefined) {
190
+ pageData.value[props.blocksKey].splice(insertIndex, 0, newBlock);
191
+ } else {
192
+ pageData.value[props.blocksKey].push(newBlock);
193
+ }
194
+
195
+ // Set the new block as active only when adding to the end (from EmptyState)
196
+ activeBlock.value = newBlock;
197
+ showAddBlockMenu.value = false;
198
+
199
+ return newBlock;
200
+ }
201
+
202
+ function setHoveredBlockId(id: string | null) {
203
+ if (isSorting.value) return;
204
+ hoveredBlockId.value = id;
205
+ }
206
+
207
+ // On escape key press
208
+ onKeyStroke("Escape", () => {
209
+ // Unset active block
210
+ activeBlock.value = null;
211
+ hoveredBlockId.value = null;
212
+ showAddBlockMenu.value = false;
213
+ showPageSettings.value = false;
214
+ activeSettingsTab.value = undefined;
215
+ });
216
+
217
+ // Click outside detection
218
+ onClickOutside(
219
+ previewRef,
220
+ () => {
221
+ // Unset active block
222
+ activeBlock.value = null;
223
+ hoveredBlockId.value = null;
224
+ showAddBlockMenu.value = false;
225
+ showPageSettings.value = false;
226
+ activeSettingsTab.value = undefined;
227
+ },
228
+ { ignore: ["#page-builder-sidebar", "#page-builder-resize-handle"] }
229
+ );
230
+
231
+ onBeforeMount(async () => {
232
+ // Initialise the registry with the active theme
233
+ // Include the editing registry to load additional theme fields and thumbnails
234
+ await initialiseRegistry(props.theme, true);
235
+
236
+ sanitizePageData();
237
+ });
238
+
239
+ // Watch for theme changes to re-initialize the registry
240
+ watch(
241
+ () => props.theme,
242
+ async (newTheme) => {
243
+ themeLoading.value = true;
244
+ await initialiseRegistry(newTheme, true);
245
+ sanitizePageData();
246
+ themeLoading.value = false;
247
+ }
248
+ );
249
+
250
+ function handleBlockReorder(oldIndex: number, newIndex: number) {
251
+ if (!pageData.value?.[props.blocksKey]) return;
252
+
253
+ const blocks = pageData.value[props.blocksKey];
254
+ if (oldIndex < 0 || oldIndex >= blocks.length || newIndex < 0 || newIndex >= blocks.length) {
255
+ return;
256
+ }
257
+
258
+ // Move block from oldIndex to newIndex
259
+ const movedBlock = blocks[oldIndex];
260
+ blocks.splice(oldIndex, 1);
261
+ blocks.splice(newIndex, 0, movedBlock);
262
+ }
263
+
264
+ function handleBlockAdd(blockType: string, index: number) {
265
+ // Use the existing handleAddBlock function
266
+ handleAddBlock(blockType, index);
267
+ }
268
+
269
+ function handleClickPartial(partialValue: string) {
270
+ const hasValue = partialValue !== null && partialValue !== "";
271
+
272
+ // Show the settings sidebar when a partial is clicked
273
+ showPageSettings.value = true;
274
+ // Clear active block when clicking on a partial
275
+ activeBlock.value = null;
276
+ hoveredBlockId.value = null;
277
+ showAddBlockMenu.value = false;
278
+
279
+ // If partial has a value (e.g., "header"), set it as the active tab
280
+ if (hasValue && partialValue) {
281
+ activeSettingsTab.value = partialValue;
282
+ } else {
283
+ activeSettingsTab.value = undefined;
284
+ }
285
+ }
286
+
287
+ function sanitizePageData() {
288
+ // Initialise the page data if not present
289
+ if (!pageData.value) {
290
+ pageData.value = {};
291
+ }
292
+
293
+ // Initialise settings value if not present
294
+ if (!pageData.value?.[props.settingsKey]) {
295
+ if (pageData.value) {
296
+ pageData.value[props.settingsKey] = {};
297
+ }
298
+ }
299
+
300
+ // Set the default layout if not present
301
+ if (!pageData.value?.[props.settingsKey]?.layout) {
302
+ const settings = pageData.value?.[props.settingsKey];
303
+ if (settings) {
304
+ if (typeof settings.layout !== "string") {
305
+ settings.layout = "default";
306
+ }
307
+ }
308
+ }
309
+
310
+ // Sanitise the layout data (must be a valid layout name string)
311
+ if (pageData.value?.[props.settingsKey]?.layout) {
312
+ const settings = pageData.value?.[props.settingsKey];
313
+ if (settings) {
314
+ if (typeof settings.layout !== "string") {
315
+ settings.layout = "default";
316
+ } else if (!themeLayouts.value[settings.layout]) {
317
+ settings.layout = "default";
318
+ }
319
+ }
320
+ }
321
+
322
+ // Set a default blocks array if not present
323
+ if (!pageData.value?.[props.blocksKey]) {
324
+ if (pageData.value) {
325
+ pageData.value[props.blocksKey] = [];
326
+ }
327
+ }
328
+ }
329
+ </script>
330
+
331
+ <style lang="scss">
332
+ @use "../../assets/styles/mixins" as *;
333
+
334
+ $editor-background-color: #6a6a6a;
335
+
336
+ .wswg-page-builder {
337
+ position: relative;
338
+ width: 100%;
339
+ max-width: 100vw;
340
+ height: var(--editor-height);
341
+ overflow-y: auto;
342
+
343
+ &-loading {
344
+ display: flex;
345
+ align-items: center;
346
+ justify-content: center;
347
+ }
348
+
349
+ &-body {
350
+ display: flex;
351
+ width: 100%;
352
+ background-color: var(--editor-bg-color, $editor-background-color);
353
+ }
354
+
355
+ &-preview {
356
+ position: relative;
357
+ display: flex;
358
+ flex: 1;
359
+ flex-grow: 1;
360
+ flex-shrink: 0;
361
+ flex-direction: column;
362
+ height: -webkit-fill-available;
363
+ min-height: 0;
364
+ padding: 1.5rem;
365
+ }
366
+
367
+ .page-builder-sidebar-wrapper {
368
+ position: sticky;
369
+ top: 0;
370
+ z-index: 12;
371
+ height: var(--editor-height);
372
+ overflow-y: auto;
373
+ }
374
+ }
375
+ </style>
package/src/index.ts CHANGED
@@ -2,13 +2,21 @@
2
2
  // This ensures createField is available immediately without waiting for CSS or component imports
3
3
  export { createField } from "./util/fieldConfig";
4
4
  export type { EditorFieldConfig, ValidatorFunction } from "./util/fieldConfig";
5
- export { getLayouts, initialiseRegistry } from "./util/registry";
5
+ export { getLayouts, initialiseRegistry, initialiseLayoutRegistry, initialiseBlockRegistry } from "./util/registry";
6
6
  export { validateField, validateAllFields, type ValidationResult } from "./util/validation";
7
7
 
8
+ export { getActiveTheme, setActiveTheme, getThemeThumbnail, getThemes } from "./util/theme-registry";
9
+ export type { Theme } from "./types/Theme";
10
+ export type { Layout } from "./types/Layout";
11
+ export type { Block } from "./types/Block";
12
+
8
13
  // Export components (component exports don't cause side effects until used)
9
- export { default as WswgJsonEditor } from "./components/WswgJsonEditor/WswgJsonEditor.vue";
14
+ export { default as WswgPageBuilder } from "./components/WswgPageBuilder/WswgPageBuilder.vue";
10
15
  // Export PageRenderer separately - it doesn't use the registry, so it won't trigger field loading
11
16
  export { default as PageRenderer } from "./components/PageRenderer/PageRenderer.vue";
17
+ // Export iframe preview app for Vue app in iframe
18
+ export { createIframeApp, getIframeAppModuleUrl } from "./components/IframePreview/iframePreviewApp";
19
+ export type { IframeAppState, IframeAppCallbacks } from "./components/IframePreview/iframePreviewApp";
12
20
 
13
21
  // Import CSS - Vite will extract this to dist/style.css during build
14
22
  // Consuming apps should import "vue-wswg-editor/style.css"
package/src/shims.d.ts CHANGED
@@ -67,6 +67,10 @@ declare module "vue-wswg-editor:thumbnails" {
67
67
  export const modules: Record<string, () => Promise<any>>;
68
68
  }
69
69
 
70
+ declare module "vue-wswg-editor:themes" {
71
+ export const modules: Record<string, () => Promise<any>>;
72
+ }
73
+
70
74
  // SortableJS type declaration - reference @types/sortablejs and re-export as ESM default
71
75
  /// <reference types="sortablejs" />
72
76
  declare module "sortablejs" {
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Custom component type with additional layout-specific properties
3
+ * These properties are set via defineOptions() in Vue components
4
+ */
5
+ export type Theme = {
6
+ id: string; // The ID of the theme
7
+ path: string; // The path to the theme
8
+ title: string; // The title of the theme
9
+ description: string; // The description of the theme
10
+ version: string; // The version of the theme
11
+ author: string; // The author of the theme
12
+ authorWebsite: string; // The author website of the theme
13
+ tags: string[]; // The tags of the theme
14
+ license: string; // The license of the theme
15
+ };
@@ -161,7 +161,7 @@ async function initialiseBlockFieldsRegistry(): Promise<void> {
161
161
  }
162
162
  }
163
163
 
164
- async function initialiseLayoutRegistry(): Promise<void> {
164
+ export async function initialiseLayoutRegistry(): Promise<void> {
165
165
  Object.keys(pageBuilderLayouts.value).forEach((key) => {
166
166
  delete pageBuilderLayouts.value[key];
167
167
  });
@@ -186,7 +186,7 @@ async function initialiseLayoutRegistry(): Promise<void> {
186
186
  }
187
187
  }
188
188
 
189
- async function initialiseBlockRegistry(): Promise<void> {
189
+ export async function initialiseBlockRegistry(): Promise<void> {
190
190
  // Clear existing registry
191
191
  Object.keys(pageBuilderBlocks.value).forEach((key) => {
192
192
  delete pageBuilderBlocks.value[key];