vue-wswg-editor 0.0.17 → 0.0.19
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/style.css +1 -1
- package/dist/types/components/IframePreview/iframeContent.d.ts +3 -3
- package/dist/types/components/IframePreview/messageHandler.d.ts +5 -0
- package/dist/vue-wswg-editor.es.js +407 -405
- package/package.json +1 -1
- package/src/components/IframePreview/IframePreview.vue +28 -1
- package/src/components/IframePreview/iframeContent.ts +67 -86
- package/src/components/IframePreview/messageHandler.ts +19 -0
package/package.json
CHANGED
|
@@ -21,12 +21,15 @@ import {
|
|
|
21
21
|
sendSettingsOpen,
|
|
22
22
|
sendScrollToBlock,
|
|
23
23
|
handleIframeMessage,
|
|
24
|
+
sendInitIframeApp,
|
|
24
25
|
} from "./messageHandler";
|
|
25
26
|
import type { Block } from "../../types/Block";
|
|
26
27
|
import { getIframeAppModuleUrl } from "./iframePreviewApp";
|
|
27
28
|
|
|
28
29
|
// Get the iframe app module URL
|
|
29
30
|
// This will be processed by the consuming app's Vite build
|
|
31
|
+
// Note: When the library is consumed as a bundled file, this URL may not resolve
|
|
32
|
+
// In that case, we'll use the postMessage fallback mechanism
|
|
30
33
|
const iframeAppModuleUrl = getIframeAppModuleUrl();
|
|
31
34
|
|
|
32
35
|
const props = defineProps<{
|
|
@@ -79,7 +82,9 @@ function onIframeLoad() {
|
|
|
79
82
|
// Generate blob URL for iframe
|
|
80
83
|
function createIframeSrc(): string {
|
|
81
84
|
console.info("[parent] Creating iframe src, module URL:", iframeAppModuleUrl);
|
|
82
|
-
|
|
85
|
+
// Always pass undefined to use postMessage mechanism
|
|
86
|
+
// The module URL will be sent via postMessage after iframe loads
|
|
87
|
+
const html = generateIframeHTML(undefined);
|
|
83
88
|
const blob = new Blob([html], { type: "text/html" });
|
|
84
89
|
const blobUrl = URL.createObjectURL(blob);
|
|
85
90
|
console.info("[parent] Iframe blob URL created:", blobUrl);
|
|
@@ -122,6 +127,28 @@ function setupMessageListener() {
|
|
|
122
127
|
|
|
123
128
|
console.info("[parent] Received message from iframe:", event.data);
|
|
124
129
|
|
|
130
|
+
// Handle IFRAME_READY_FOR_APP - iframe is ready and requesting module URL
|
|
131
|
+
if (event.data && event.data.type === "IFRAME_READY_FOR_APP") {
|
|
132
|
+
console.info("[parent] IFRAME_READY_FOR_APP received, sending module URL");
|
|
133
|
+
if (iframeRef.value && iframeAppModuleUrl) {
|
|
134
|
+
sendInitIframeApp(iframeRef.value, iframeAppModuleUrl);
|
|
135
|
+
} else {
|
|
136
|
+
console.warn("[parent] Cannot send module URL - iframe ref or module URL not available");
|
|
137
|
+
}
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Handle IFRAME_NEEDS_MODULE_URL - same as IFRAME_READY_FOR_APP
|
|
142
|
+
if (event.data && event.data.type === "IFRAME_NEEDS_MODULE_URL") {
|
|
143
|
+
console.info("[parent] IFRAME_NEEDS_MODULE_URL received, sending module URL");
|
|
144
|
+
if (iframeRef.value && iframeAppModuleUrl) {
|
|
145
|
+
sendInitIframeApp(iframeRef.value, iframeAppModuleUrl);
|
|
146
|
+
} else {
|
|
147
|
+
console.warn("[parent] Cannot send module URL - iframe ref or module URL not available");
|
|
148
|
+
}
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
125
152
|
handleIframeMessage(event, {
|
|
126
153
|
onBlockClick: (_blockId: string, block: any) => {
|
|
127
154
|
emit("click-block", block);
|
|
@@ -99,10 +99,10 @@ function extractParentStylesheets(): string {
|
|
|
99
99
|
* This creates a standalone HTML page with a Vue app that will be loaded in the iframe
|
|
100
100
|
* The Vue app uses PageRenderer to render blocks reactively
|
|
101
101
|
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
102
|
+
* Note: The module URL is now sent via postMessage after iframe loads
|
|
103
|
+
* This parameter is kept for backward compatibility but is not used
|
|
104
104
|
*/
|
|
105
|
-
export function generateIframeHTML(
|
|
105
|
+
export function generateIframeHTML(_iframeAppModuleUrl?: string): string {
|
|
106
106
|
const parentStylesheets = extractParentStylesheets();
|
|
107
107
|
const parentCSSVariables = extractParentCSSVariables();
|
|
108
108
|
const vueCdnUrl = "https://unpkg.com/vue@3/dist/vue.esm-browser.js";
|
|
@@ -127,93 +127,74 @@ export function generateIframeHTML(iframeAppModuleUrl?: string): string {
|
|
|
127
127
|
</script>`;
|
|
128
128
|
|
|
129
129
|
// Generate script that loads Vue, vue-router, and initializes the iframe app
|
|
130
|
-
//
|
|
131
|
-
const appScript =
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
console.info('[iframe] createIframeApp
|
|
154
|
-
|
|
155
|
-
console.
|
|
130
|
+
// Always use postMessage fallback mechanism since module URLs may not resolve when bundled
|
|
131
|
+
const appScript = `<script type="module">
|
|
132
|
+
console.info('[iframe] Script module starting...');
|
|
133
|
+
|
|
134
|
+
import { createApp } from 'vue';
|
|
135
|
+
console.info('[iframe] Vue imported successfully');
|
|
136
|
+
|
|
137
|
+
import * as VueRouter from 'vue-router';
|
|
138
|
+
console.info('[iframe] VueRouter imported successfully');
|
|
139
|
+
// Make vue-router available globally so it can be accessed in the iframe app
|
|
140
|
+
window.VueRouter = VueRouter;
|
|
141
|
+
|
|
142
|
+
let appInitialized = false;
|
|
143
|
+
|
|
144
|
+
// Always use postMessage mechanism to get the module URL
|
|
145
|
+
// This works whether the library is consumed as source or bundled
|
|
146
|
+
window.addEventListener('message', async (event) => {
|
|
147
|
+
console.info('[iframe] Received message:', event.data);
|
|
148
|
+
if (event.data.type === 'INIT_IFRAME_APP' && event.data.moduleUrl && !appInitialized) {
|
|
149
|
+
appInitialized = true;
|
|
150
|
+
console.info('[iframe] Initializing app with module URL:', event.data.moduleUrl);
|
|
151
|
+
try {
|
|
152
|
+
const { createIframeApp } = await import(event.data.moduleUrl);
|
|
153
|
+
console.info('[iframe] createIframeApp imported successfully');
|
|
154
|
+
const appEl = document.getElementById('app');
|
|
155
|
+
console.info('[iframe] App element found:', appEl);
|
|
156
|
+
if (appEl) {
|
|
157
|
+
console.info('[iframe] Calling createIframeApp...');
|
|
158
|
+
createIframeApp(appEl).then(() => {
|
|
159
|
+
console.info('[iframe] createIframeApp completed successfully');
|
|
160
|
+
}).catch(error => {
|
|
161
|
+
console.error('[iframe] createIframeApp failed:', error);
|
|
162
|
+
console.error('[iframe] Error stack:', error.stack);
|
|
163
|
+
// Fallback: create minimal Vue app
|
|
164
|
+
const appEl = document.getElementById('app');
|
|
165
|
+
if (appEl) {
|
|
166
|
+
console.info('[iframe] Creating fallback Vue app after error');
|
|
167
|
+
createApp({
|
|
168
|
+
template: '<div class="p-4">Error loading preview. Check console for details.</div>'
|
|
169
|
+
}).mount(appEl);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
} else {
|
|
173
|
+
console.error('[iframe] App element not found!');
|
|
174
|
+
}
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error('[iframe] Failed to load iframe app module:', error);
|
|
156
177
|
console.error('[iframe] Error stack:', error.stack);
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
console.info('[iframe] Fallback script module starting...');
|
|
165
|
-
import { createApp } from 'vue';
|
|
166
|
-
console.info('[iframe] Vue imported successfully (fallback)');
|
|
167
|
-
import * as VueRouter from 'vue-router';
|
|
168
|
-
console.info('[iframe] VueRouter imported successfully (fallback)');
|
|
169
|
-
// Make vue-router available globally so it can be imported in the iframe app
|
|
170
|
-
window.VueRouter = VueRouter;
|
|
171
|
-
|
|
172
|
-
let appInitialized = false;
|
|
173
|
-
|
|
174
|
-
window.addEventListener('message', async (event) => {
|
|
175
|
-
console.info('[iframe] Received message:', event.data);
|
|
176
|
-
if (event.data.type === 'INIT_IFRAME_APP' && event.data.moduleUrl && !appInitialized) {
|
|
177
|
-
appInitialized = true;
|
|
178
|
-
console.info('[iframe] Initializing app with module URL:', event.data.moduleUrl);
|
|
179
|
-
try {
|
|
180
|
-
const { createIframeApp } = await import(event.data.moduleUrl);
|
|
181
|
-
console.info('[iframe] createIframeApp imported successfully (fallback)');
|
|
182
|
-
const appEl = document.getElementById('app');
|
|
183
|
-
console.info('[iframe] App element found (fallback):', appEl);
|
|
184
|
-
if (appEl) {
|
|
185
|
-
console.info('[iframe] Calling createIframeApp (fallback)...');
|
|
186
|
-
createIframeApp(appEl).then(() => {
|
|
187
|
-
console.info('[iframe] createIframeApp completed successfully (fallback)');
|
|
188
|
-
}).catch(error => {
|
|
189
|
-
console.error('[iframe] createIframeApp failed (fallback):', error);
|
|
190
|
-
});
|
|
191
|
-
} else {
|
|
192
|
-
console.error('[iframe] App element not found (fallback)!');
|
|
193
|
-
}
|
|
194
|
-
} catch (error) {
|
|
195
|
-
console.error('[iframe] Failed to load iframe app module:', error);
|
|
196
|
-
console.error('[iframe] Error stack:', error.stack);
|
|
197
|
-
// Fallback: create minimal Vue app
|
|
198
|
-
const appEl = document.getElementById('app');
|
|
199
|
-
if (appEl) {
|
|
200
|
-
console.info('[iframe] Creating fallback Vue app');
|
|
201
|
-
createApp({
|
|
202
|
-
template: '<div class="p-4">Loading preview...</div>'
|
|
203
|
-
}).mount(appEl);
|
|
204
|
-
}
|
|
178
|
+
// Fallback: create minimal Vue app
|
|
179
|
+
const appEl = document.getElementById('app');
|
|
180
|
+
if (appEl) {
|
|
181
|
+
console.info('[iframe] Creating fallback Vue app');
|
|
182
|
+
createApp({
|
|
183
|
+
template: '<div class="p-4">Loading preview...</div>'
|
|
184
|
+
}).mount(appEl);
|
|
205
185
|
}
|
|
206
186
|
}
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
// Notify parent that we're ready to receive module URL
|
|
210
|
-
if (window.parent) {
|
|
211
|
-
console.info('[iframe] Notifying parent that iframe is ready for app');
|
|
212
|
-
window.parent.postMessage({ type: 'IFRAME_READY_FOR_APP' }, '*');
|
|
213
|
-
} else {
|
|
214
|
-
console.warn('[iframe] window.parent is not available');
|
|
215
187
|
}
|
|
216
|
-
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// Notify parent that we're ready to receive module URL
|
|
191
|
+
if (window.parent) {
|
|
192
|
+
console.info('[iframe] Notifying parent that iframe is ready for app');
|
|
193
|
+
window.parent.postMessage({ type: 'IFRAME_READY_FOR_APP' }, '*');
|
|
194
|
+
} else {
|
|
195
|
+
console.warn('[iframe] window.parent is not available');
|
|
196
|
+
}
|
|
197
|
+
</script>`;
|
|
217
198
|
|
|
218
199
|
return `<!DOCTYPE html>
|
|
219
200
|
<html lang="en">
|
|
@@ -149,6 +149,25 @@ export function sendScrollToBlock(iframe: HTMLIFrameElement | null, blockId: str
|
|
|
149
149
|
sendToIframe(iframe, message);
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
/**
|
|
153
|
+
* Send module URL to iframe for initialization
|
|
154
|
+
* Used when iframe requests the module URL via postMessage
|
|
155
|
+
*/
|
|
156
|
+
export function sendInitIframeApp(iframe: HTMLIFrameElement | null, moduleUrl: string): void {
|
|
157
|
+
if (!iframe || !iframe.contentWindow) {
|
|
158
|
+
console.warn("[parent] Cannot send INIT_IFRAME_APP: iframe not ready");
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
try {
|
|
163
|
+
console.info("[parent] Sending INIT_IFRAME_APP with module URL:", moduleUrl);
|
|
164
|
+
iframe.contentWindow.postMessage({ type: "INIT_IFRAME_APP", moduleUrl }, "*");
|
|
165
|
+
console.info("[parent] INIT_IFRAME_APP message sent successfully");
|
|
166
|
+
} catch (error) {
|
|
167
|
+
console.error("[parent] Error sending INIT_IFRAME_APP message:", error);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
152
171
|
/**
|
|
153
172
|
* Validate incoming message from iframe
|
|
154
173
|
*/
|