@nookuio/iframe 0.1.0
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/constants.d.ts +7 -0
- package/dist/constants.js +10 -0
- package/dist/constants.mjs +4 -0
- package/dist/createClient.d.ts +54 -0
- package/dist/createClient.js +98 -0
- package/dist/createClient.mjs +95 -0
- package/dist/editor.d.ts +11 -0
- package/dist/editor.js +101 -0
- package/dist/editor.mjs +85 -0
- package/dist/iframe.d.ts +11 -0
- package/dist/iframe.js +238 -0
- package/dist/iframe.mjs +209 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +38 -0
- package/dist/index.mjs +3 -0
- package/dist/types.d.ts +95 -0
- package/dist/types.js +1 -0
- package/dist/types.mjs +0 -0
- package/package.json +42 -0
@@ -0,0 +1,7 @@
|
|
1
|
+
/**
|
2
|
+
* The path of the editor page which will be rendered in canvas
|
3
|
+
*/
|
4
|
+
export declare const EDITOR_PAGE_PATH = "/__nooku/editor";
|
5
|
+
export declare const COMPONENT_PREVIEW_PAGE_PATH = "/__nooku/component-preview";
|
6
|
+
export declare const IFRAME_SOURCE_NAME = "nooku-frame";
|
7
|
+
export declare const EDITOR_SOURCE_NAME = "nooku-editor";
|
@@ -0,0 +1,10 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.IFRAME_SOURCE_NAME = exports.EDITOR_SOURCE_NAME = exports.EDITOR_PAGE_PATH = exports.COMPONENT_PREVIEW_PAGE_PATH = void 0;
|
7
|
+
const EDITOR_PAGE_PATH = exports.EDITOR_PAGE_PATH = `/__nooku/editor`;
|
8
|
+
const COMPONENT_PREVIEW_PAGE_PATH = exports.COMPONENT_PREVIEW_PAGE_PATH = `/__nooku/component-preview`;
|
9
|
+
const IFRAME_SOURCE_NAME = exports.IFRAME_SOURCE_NAME = "nooku-frame";
|
10
|
+
const EDITOR_SOURCE_NAME = exports.EDITOR_SOURCE_NAME = "nooku-editor";
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import type { ContextRequest, ContextResponse, EventListener } from './types';
|
2
|
+
type ArgumentsType<T> = T extends (...args: infer A) => any ? A : never;
|
3
|
+
type ClientReturnBase<R, L, RE, LE> = {
|
4
|
+
[K in keyof R]: R[K] extends (...args: any[]) => any ? (...args: Parameters<R[K]>) => Promise<Awaited<ReturnType<R[K]>>> : R[K] extends any[] ? Promise<R[K]> : R[K] extends object ? ClientReturnBase<R[K], L, RE, LE> : Promise<R[K]>;
|
5
|
+
};
|
6
|
+
type ClientReturn<R, L, RE, LE> = ClientReturnBase<R, L, RE, LE> & {
|
7
|
+
$context: L;
|
8
|
+
on: <E extends keyof RE>(eventName: E, listener: (...args: ArgumentsType<RE[E]>) => void) => void;
|
9
|
+
off: <E extends keyof RE>(eventName: E, listener: (...args: ArgumentsType<RE[E]>) => void) => void;
|
10
|
+
emit: <E extends keyof LE>(eventName: E, ...args: ArgumentsType<LE[E]>) => void;
|
11
|
+
removeAllListeners: () => void;
|
12
|
+
};
|
13
|
+
interface ClientOptions {
|
14
|
+
/**
|
15
|
+
* Function to send requests to the main remote process
|
16
|
+
*
|
17
|
+
* Should return a ContextResponse
|
18
|
+
*/
|
19
|
+
invoke: (request: ContextRequest) => Promise<ContextResponse>;
|
20
|
+
/**
|
21
|
+
* Function to handle incoming requests from the remote process
|
22
|
+
*/
|
23
|
+
handle: (handler: (request: ContextRequest) => Promise<ContextResponse>) => void;
|
24
|
+
/**
|
25
|
+
* Function to emit events to the remote process
|
26
|
+
*/
|
27
|
+
emit: (eventName: string, ...args: any[]) => void;
|
28
|
+
/**
|
29
|
+
* Function to subscribe to events from the remote process
|
30
|
+
*/
|
31
|
+
subscribe: (eventName: string, listener: EventListener) => void;
|
32
|
+
/**
|
33
|
+
* Unsubscribe to events from the remote process
|
34
|
+
*/
|
35
|
+
unsubscribe: (eventName: string, listener: EventListener) => void;
|
36
|
+
/**
|
37
|
+
* Remove all the listeners
|
38
|
+
*/
|
39
|
+
removeAllListeners: () => void;
|
40
|
+
/**
|
41
|
+
* Custom function to serialize data
|
42
|
+
*
|
43
|
+
* by default it uses JSON.stringify
|
44
|
+
*/
|
45
|
+
serialize?: (data: any) => any;
|
46
|
+
/**
|
47
|
+
* Custom function to deserialize data
|
48
|
+
*
|
49
|
+
* by default it uses JSON.parse
|
50
|
+
*/
|
51
|
+
deserialize?: (data: any) => any;
|
52
|
+
}
|
53
|
+
export declare function createClient<R, L, RE, LE>(localCtx: L, options: ClientOptions): ClientReturn<R, L, RE, LE>;
|
54
|
+
export {};
|
@@ -0,0 +1,98 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.createClient = createClient;
|
7
|
+
var _lodash = _interopRequireDefault(require("lodash"));
|
8
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
9
|
+
function defaultSerialize(data) {
|
10
|
+
try {
|
11
|
+
return JSON.stringify(data);
|
12
|
+
} catch (error) {
|
13
|
+
return data;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
function defaultDeserialize(data) {
|
17
|
+
try {
|
18
|
+
return JSON.parse(data);
|
19
|
+
} catch (error) {
|
20
|
+
return data;
|
21
|
+
}
|
22
|
+
}
|
23
|
+
function createClient(localCtx, options) {
|
24
|
+
const {
|
25
|
+
invoke,
|
26
|
+
handle,
|
27
|
+
subscribe,
|
28
|
+
removeAllListeners,
|
29
|
+
emit,
|
30
|
+
unsubscribe,
|
31
|
+
serialize = defaultSerialize,
|
32
|
+
deserialize = defaultDeserialize
|
33
|
+
} = options;
|
34
|
+
handle(async request => {
|
35
|
+
const value = _lodash.default.get(localCtx, request.key);
|
36
|
+
if (value === void 0) return {
|
37
|
+
type: "response",
|
38
|
+
id: request.id,
|
39
|
+
key: request.key,
|
40
|
+
result: void 0
|
41
|
+
};
|
42
|
+
const result = typeof value === "function" ? await value(...deserialize(request.args)) : value;
|
43
|
+
return {
|
44
|
+
type: "response",
|
45
|
+
id: request.id,
|
46
|
+
key: request.key,
|
47
|
+
result: serialize(result)
|
48
|
+
};
|
49
|
+
});
|
50
|
+
const proxyCache = /* @__PURE__ */new Map();
|
51
|
+
function createProxyForPath(path) {
|
52
|
+
const pathKey = path.join(".");
|
53
|
+
if (proxyCache.has(pathKey)) {
|
54
|
+
return proxyCache.get(pathKey);
|
55
|
+
}
|
56
|
+
const callHandler = async (...args) => {
|
57
|
+
const request = {
|
58
|
+
type: "request",
|
59
|
+
id: `${pathKey}-${Date.now()}-${Math.random()}`,
|
60
|
+
// More robust ID
|
61
|
+
key: pathKey,
|
62
|
+
args: serialize(args)
|
63
|
+
};
|
64
|
+
const response = await invoke(request);
|
65
|
+
return deserialize(response.result);
|
66
|
+
};
|
67
|
+
const proxy = new Proxy(callHandler, {
|
68
|
+
get(target, prop) {
|
69
|
+
if (prop === "then") {
|
70
|
+
const promise = target();
|
71
|
+
return promise.then.bind(promise);
|
72
|
+
}
|
73
|
+
if (prop === "catch" || prop === "finally") {
|
74
|
+
const promise = target();
|
75
|
+
return promise[prop].bind(promise);
|
76
|
+
}
|
77
|
+
return createProxyForPath([...path, prop]);
|
78
|
+
},
|
79
|
+
apply(target, thisArg, args) {
|
80
|
+
return target.apply(thisArg, args);
|
81
|
+
}
|
82
|
+
});
|
83
|
+
proxyCache.set(pathKey, proxy);
|
84
|
+
return proxy;
|
85
|
+
}
|
86
|
+
const rootProxy = new Proxy({}, {
|
87
|
+
get(_target, prop) {
|
88
|
+
if (prop === "$context") return localCtx;
|
89
|
+
if (prop === "on") return subscribe;
|
90
|
+
if (prop === "off") return unsubscribe;
|
91
|
+
if (prop === "emit") return emit;
|
92
|
+
if (prop === "removeAllListeners") return removeAllListeners;
|
93
|
+
if (typeof prop === "symbol") return void 0;
|
94
|
+
return createProxyForPath([prop]);
|
95
|
+
}
|
96
|
+
});
|
97
|
+
return rootProxy;
|
98
|
+
}
|
@@ -0,0 +1,95 @@
|
|
1
|
+
import _ from "lodash";
|
2
|
+
function defaultSerialize(data) {
|
3
|
+
try {
|
4
|
+
return JSON.stringify(data);
|
5
|
+
} catch (error) {
|
6
|
+
return data;
|
7
|
+
}
|
8
|
+
}
|
9
|
+
function defaultDeserialize(data) {
|
10
|
+
try {
|
11
|
+
return JSON.parse(data);
|
12
|
+
} catch (error) {
|
13
|
+
return data;
|
14
|
+
}
|
15
|
+
}
|
16
|
+
export function createClient(localCtx, options) {
|
17
|
+
const {
|
18
|
+
invoke,
|
19
|
+
handle,
|
20
|
+
subscribe,
|
21
|
+
removeAllListeners,
|
22
|
+
emit,
|
23
|
+
unsubscribe,
|
24
|
+
serialize = defaultSerialize,
|
25
|
+
deserialize = defaultDeserialize
|
26
|
+
} = options;
|
27
|
+
handle(async (request) => {
|
28
|
+
const value = _.get(localCtx, request.key);
|
29
|
+
if (value === void 0)
|
30
|
+
return {
|
31
|
+
type: "response",
|
32
|
+
id: request.id,
|
33
|
+
key: request.key,
|
34
|
+
result: void 0
|
35
|
+
};
|
36
|
+
const result = typeof value === "function" ? await value(...deserialize(request.args)) : value;
|
37
|
+
return {
|
38
|
+
type: "response",
|
39
|
+
id: request.id,
|
40
|
+
key: request.key,
|
41
|
+
result: serialize(result)
|
42
|
+
};
|
43
|
+
});
|
44
|
+
const proxyCache = /* @__PURE__ */ new Map();
|
45
|
+
function createProxyForPath(path) {
|
46
|
+
const pathKey = path.join(".");
|
47
|
+
if (proxyCache.has(pathKey)) {
|
48
|
+
return proxyCache.get(pathKey);
|
49
|
+
}
|
50
|
+
const callHandler = async (...args) => {
|
51
|
+
const request = {
|
52
|
+
type: "request",
|
53
|
+
id: `${pathKey}-${Date.now()}-${Math.random()}`,
|
54
|
+
// More robust ID
|
55
|
+
key: pathKey,
|
56
|
+
args: serialize(args)
|
57
|
+
};
|
58
|
+
const response = await invoke(request);
|
59
|
+
return deserialize(response.result);
|
60
|
+
};
|
61
|
+
const proxy = new Proxy(callHandler, {
|
62
|
+
get(target, prop) {
|
63
|
+
if (prop === "then") {
|
64
|
+
const promise = target();
|
65
|
+
return promise.then.bind(promise);
|
66
|
+
}
|
67
|
+
if (prop === "catch" || prop === "finally") {
|
68
|
+
const promise = target();
|
69
|
+
return promise[prop].bind(promise);
|
70
|
+
}
|
71
|
+
return createProxyForPath([...path, prop]);
|
72
|
+
},
|
73
|
+
apply(target, thisArg, args) {
|
74
|
+
return target.apply(thisArg, args);
|
75
|
+
}
|
76
|
+
});
|
77
|
+
proxyCache.set(pathKey, proxy);
|
78
|
+
return proxy;
|
79
|
+
}
|
80
|
+
const rootProxy = new Proxy(
|
81
|
+
{},
|
82
|
+
{
|
83
|
+
get(_target, prop) {
|
84
|
+
if (prop === "$context") return localCtx;
|
85
|
+
if (prop === "on") return subscribe;
|
86
|
+
if (prop === "off") return unsubscribe;
|
87
|
+
if (prop === "emit") return emit;
|
88
|
+
if (prop === "removeAllListeners") return removeAllListeners;
|
89
|
+
if (typeof prop === "symbol") return void 0;
|
90
|
+
return createProxyForPath([prop]);
|
91
|
+
}
|
92
|
+
}
|
93
|
+
);
|
94
|
+
return rootProxy;
|
95
|
+
}
|
package/dist/editor.d.ts
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
import type { CoreIframeContext, CoreIframeEvents, EditorContext, EditorEvents } from './types';
|
2
|
+
/**
|
3
|
+
* This function should be called inside the editor
|
4
|
+
*/
|
5
|
+
export declare function createIframeClient<IframeContext extends CoreIframeContext, IframeEvents extends CoreIframeEvents>(iframe: string | HTMLIFrameElement): { [K in keyof IframeContext]: IframeContext[K] extends (...args: any[]) => any ? (...args: Parameters<IframeContext[K]>) => Promise<Awaited<ReturnType<IframeContext[K]>>> : IframeContext[K] extends any[] ? Promise<IframeContext[K]> : IframeContext[K] extends object ? IframeContext[K] extends infer T ? { [K_1 in keyof T]: IframeContext[K][K_1] extends (...args: any[]) => any ? (...args: Parameters<IframeContext[K][K_1]>) => Promise<Awaited<ReturnType<IframeContext[K][K_1]>>> : IframeContext[K][K_1] extends any[] ? Promise<IframeContext[K][K_1]> : IframeContext[K][K_1] extends object ? IframeContext[K][K_1] extends infer T_1 ? { [K_2 in keyof T_1]: IframeContext[K][K_1][K_2] extends (...args: any[]) => any ? (...args: Parameters<IframeContext[K][K_1][K_2]>) => Promise<Awaited<ReturnType<IframeContext[K][K_1][K_2]>>> : IframeContext[K][K_1][K_2] extends any[] ? Promise<IframeContext[K][K_1][K_2]> : IframeContext[K][K_1][K_2] extends object ? IframeContext[K][K_1][K_2] extends infer T_2 ? { [K_3 in keyof T_2]: IframeContext[K][K_1][K_2][K_3] extends (...args: any[]) => any ? (...args: Parameters<IframeContext[K][K_1][K_2][K_3]>) => Promise<Awaited<ReturnType<IframeContext[K][K_1][K_2][K_3]>>> : IframeContext[K][K_1][K_2][K_3] extends any[] ? Promise<IframeContext[K][K_1][K_2][K_3]> : IframeContext[K][K_1][K_2][K_3] extends object ? IframeContext[K][K_1][K_2][K_3] extends infer T_3 ? { [K_4 in keyof T_3]: IframeContext[K][K_1][K_2][K_3][K_4] extends (...args: any[]) => any ? (...args: Parameters<IframeContext[K][K_1][K_2][K_3][K_4]>) => Promise<Awaited<ReturnType<IframeContext[K][K_1][K_2][K_3][K_4]>>> : IframeContext[K][K_1][K_2][K_3][K_4] extends any[] ? Promise<IframeContext[K][K_1][K_2][K_3][K_4]> : IframeContext[K][K_1][K_2][K_3][K_4] extends object ? IframeContext[K][K_1][K_2][K_3][K_4] extends infer T_4 ? { [K_5 in keyof T_4]: IframeContext[K][K_1][K_2][K_3][K_4][K_5] extends (...args: any[]) => any ? (...args: Parameters<IframeContext[K][K_1][K_2][K_3][K_4][K_5]>) => Promise<Awaited<ReturnType<IframeContext[K][K_1][K_2][K_3][K_4][K_5]>>> : IframeContext[K][K_1][K_2][K_3][K_4][K_5] extends any[] ? Promise<IframeContext[K][K_1][K_2][K_3][K_4][K_5]> : IframeContext[K][K_1][K_2][K_3][K_4][K_5] extends object ? IframeContext[K][K_1][K_2][K_3][K_4][K_5] extends infer T_5 ? { [K_6 in keyof T_5]: IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6] extends (...args: any[]) => any ? (...args: Parameters<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6]>) => Promise<Awaited<ReturnType<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6]>>> : IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6] extends any[] ? Promise<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6]> : IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6] extends object ? IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6] extends infer T_6 ? { [K_7 in keyof T_6]: IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] extends (...args: any[]) => any ? (...args: Parameters<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7]>) => Promise<Awaited<ReturnType<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7]>>> : IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] extends any[] ? Promise<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7]> : IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] extends object ? IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7] extends infer T_7 ? { [K_8 in keyof T_7]: IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] extends (...args: any[]) => any ? (...args: Parameters<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8]>) => Promise<Awaited<ReturnType<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8]>>> : IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] extends any[] ? Promise<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8]> : IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] extends object ? IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8] extends infer T_8 ? { [K_9 in keyof T_8]: IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] extends (...args: any[]) => any ? (...args: Parameters<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9]>) => Promise<Awaited<ReturnType<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9]>>> : IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] extends any[] ? Promise<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9]> : IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] extends object ? IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9] extends infer T_9 ? { [K_10 in keyof T_9]: IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] extends (...args: any[]) => any ? (...args: Parameters<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10]>) => Promise<Awaited<ReturnType<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10]>>> : IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] extends any[] ? Promise<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10]> : IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10] extends object ? /*elided*/ any : Promise<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9][K_10]>; } : never : Promise<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8][K_9]>; } : never : Promise<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7][K_8]>; } : never : Promise<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6][K_7]>; } : never : Promise<IframeContext[K][K_1][K_2][K_3][K_4][K_5][K_6]>; } : never : Promise<IframeContext[K][K_1][K_2][K_3][K_4][K_5]>; } : never : Promise<IframeContext[K][K_1][K_2][K_3][K_4]>; } : never : Promise<IframeContext[K][K_1][K_2][K_3]>; } : never : Promise<IframeContext[K][K_1][K_2]>; } : never : Promise<IframeContext[K][K_1]>; } : never : Promise<IframeContext[K]>; } & {
|
6
|
+
$context: EditorContext;
|
7
|
+
on: <E extends keyof IframeEvents>(eventName: E, listener: (...args: IframeEvents[E] extends infer T_10 ? T_10 extends IframeEvents[E] ? T_10 extends (...args: infer A) => any ? A : never : never : never) => void) => void;
|
8
|
+
off: <E extends keyof IframeEvents>(eventName: E, listener: (...args: IframeEvents[E] extends infer T_10 ? T_10 extends IframeEvents[E] ? T_10 extends (...args: infer A) => any ? A : never : never : never) => void) => void;
|
9
|
+
emit: <E extends never>(eventName: E, ...args: EditorEvents[E] extends infer T_10 ? T_10 extends EditorEvents[E] ? T_10 extends (...args: infer A) => any ? A : never : never : never) => void;
|
10
|
+
removeAllListeners: () => void;
|
11
|
+
};
|
package/dist/editor.js
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.createIframeClient = createIframeClient;
|
7
|
+
var _constants = require("./constants");
|
8
|
+
var _createClient = require("./createClient");
|
9
|
+
var _telejson = require("telejson");
|
10
|
+
const listenersCollection = /* @__PURE__ */new Map();
|
11
|
+
function createIframeClient(iframe) {
|
12
|
+
let iframeElement;
|
13
|
+
function getIframe() {
|
14
|
+
if (!iframeElement) {
|
15
|
+
iframeElement = typeof iframe === "string" ? document.querySelector(`#${iframe}`) : iframe;
|
16
|
+
}
|
17
|
+
return iframeElement;
|
18
|
+
}
|
19
|
+
const client = (0, _createClient.createClient)({}, {
|
20
|
+
emit(eventName, ...args) {
|
21
|
+
const iframe2 = getIframe();
|
22
|
+
if (!iframe2) return;
|
23
|
+
iframe2.contentWindow?.postMessage({
|
24
|
+
source: _constants.EDITOR_SOURCE_NAME,
|
25
|
+
request: {
|
26
|
+
eventName,
|
27
|
+
args
|
28
|
+
}
|
29
|
+
}, "*");
|
30
|
+
},
|
31
|
+
handle(handler) {
|
32
|
+
window.addEventListener("message", async event => {
|
33
|
+
if (typeof event.data !== "object") return;
|
34
|
+
if (event.data.source !== _constants.IFRAME_SOURCE_NAME) return;
|
35
|
+
const iframe2 = getIframe();
|
36
|
+
if (!iframe2) return;
|
37
|
+
const response = await handler(event.data.request);
|
38
|
+
iframe2.contentWindow?.postMessage({
|
39
|
+
source: _constants.EDITOR_SOURCE_NAME,
|
40
|
+
response
|
41
|
+
}, "*");
|
42
|
+
});
|
43
|
+
},
|
44
|
+
async invoke(request) {
|
45
|
+
const iframe2 = getIframe();
|
46
|
+
if (!iframe2) return {
|
47
|
+
type: "response",
|
48
|
+
id: request.id,
|
49
|
+
key: request.key,
|
50
|
+
result: void 0
|
51
|
+
};
|
52
|
+
return new Promise((resolve, reject) => {
|
53
|
+
const timeout = setTimeout(() => {
|
54
|
+
window.removeEventListener("message", messageHandler);
|
55
|
+
reject(new Error("Request timed out"));
|
56
|
+
}, 5e3);
|
57
|
+
function messageHandler(event) {
|
58
|
+
if (typeof event.data !== "object") return;
|
59
|
+
if (event.data.source !== _constants.IFRAME_SOURCE_NAME || !event.data.response) return;
|
60
|
+
if (event.data.response.id !== request.id) return;
|
61
|
+
clearTimeout(timeout);
|
62
|
+
window.removeEventListener("message", messageHandler);
|
63
|
+
resolve(event.data.response);
|
64
|
+
}
|
65
|
+
iframe2.contentWindow?.postMessage({
|
66
|
+
source: _constants.IFRAME_SOURCE_NAME,
|
67
|
+
request
|
68
|
+
}, "*");
|
69
|
+
window.addEventListener("message", messageHandler);
|
70
|
+
});
|
71
|
+
},
|
72
|
+
subscribe(eventName, listener) {
|
73
|
+
const currentEventListenersCollection = listenersCollection.get(eventName);
|
74
|
+
if (!currentEventListenersCollection) {
|
75
|
+
listenersCollection.set(eventName, [listener]);
|
76
|
+
return;
|
77
|
+
}
|
78
|
+
currentEventListenersCollection.push(listener);
|
79
|
+
},
|
80
|
+
unsubscribe(eventName, listener) {
|
81
|
+
const index = listenersCollection.get(eventName)?.indexOf(listener);
|
82
|
+
if (index === -1 || index === void 0) return;
|
83
|
+
listenersCollection.get(eventName)?.splice(index, 1);
|
84
|
+
},
|
85
|
+
removeAllListeners() {
|
86
|
+
listenersCollection.clear();
|
87
|
+
},
|
88
|
+
deserialize: v => (0, _telejson.parse)(v),
|
89
|
+
serialize: v => (0, _telejson.stringify)(v, {
|
90
|
+
maxDepth: Infinity
|
91
|
+
})
|
92
|
+
});
|
93
|
+
window.addEventListener("message", event => {
|
94
|
+
if (typeof event.data !== "object") return;
|
95
|
+
if (event.data.source !== _constants.IFRAME_SOURCE_NAME || !event.data.request) return;
|
96
|
+
const currentEventListeners = listenersCollection.get(event.data.request.eventName);
|
97
|
+
if (!currentEventListeners?.length) return;
|
98
|
+
currentEventListeners.forEach(listener => listener(...event.data.request.args));
|
99
|
+
});
|
100
|
+
return client;
|
101
|
+
}
|
package/dist/editor.mjs
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
import { EDITOR_SOURCE_NAME, IFRAME_SOURCE_NAME } from "./constants.mjs";
|
2
|
+
import { createClient } from "./createClient.mjs";
|
3
|
+
import { stringify, parse } from "telejson";
|
4
|
+
const listenersCollection = /* @__PURE__ */ new Map();
|
5
|
+
export function createIframeClient(iframe) {
|
6
|
+
let iframeElement;
|
7
|
+
function getIframe() {
|
8
|
+
if (!iframeElement) {
|
9
|
+
iframeElement = typeof iframe === "string" ? document.querySelector(`#${iframe}`) : iframe;
|
10
|
+
}
|
11
|
+
return iframeElement;
|
12
|
+
}
|
13
|
+
const client = createClient(
|
14
|
+
{},
|
15
|
+
{
|
16
|
+
emit(eventName, ...args) {
|
17
|
+
const iframe2 = getIframe();
|
18
|
+
if (!iframe2) return;
|
19
|
+
iframe2.contentWindow?.postMessage({ source: EDITOR_SOURCE_NAME, request: { eventName, args } }, "*");
|
20
|
+
},
|
21
|
+
handle(handler) {
|
22
|
+
window.addEventListener("message", async (event) => {
|
23
|
+
if (typeof event.data !== "object") return;
|
24
|
+
if (event.data.source !== IFRAME_SOURCE_NAME) return;
|
25
|
+
const iframe2 = getIframe();
|
26
|
+
if (!iframe2) return;
|
27
|
+
const response = await handler(event.data.request);
|
28
|
+
iframe2.contentWindow?.postMessage({ source: EDITOR_SOURCE_NAME, response }, "*");
|
29
|
+
});
|
30
|
+
},
|
31
|
+
async invoke(request) {
|
32
|
+
const iframe2 = getIframe();
|
33
|
+
if (!iframe2)
|
34
|
+
return {
|
35
|
+
type: "response",
|
36
|
+
id: request.id,
|
37
|
+
key: request.key,
|
38
|
+
result: void 0
|
39
|
+
};
|
40
|
+
return new Promise((resolve, reject) => {
|
41
|
+
const timeout = setTimeout(() => {
|
42
|
+
window.removeEventListener("message", messageHandler);
|
43
|
+
reject(new Error("Request timed out"));
|
44
|
+
}, 5e3);
|
45
|
+
function messageHandler(event) {
|
46
|
+
if (typeof event.data !== "object") return;
|
47
|
+
if (event.data.source !== IFRAME_SOURCE_NAME || !event.data.response) return;
|
48
|
+
if (event.data.response.id !== request.id) return;
|
49
|
+
clearTimeout(timeout);
|
50
|
+
window.removeEventListener("message", messageHandler);
|
51
|
+
resolve(event.data.response);
|
52
|
+
}
|
53
|
+
iframe2.contentWindow?.postMessage({ source: IFRAME_SOURCE_NAME, request }, "*");
|
54
|
+
window.addEventListener("message", messageHandler);
|
55
|
+
});
|
56
|
+
},
|
57
|
+
subscribe(eventName, listener) {
|
58
|
+
const currentEventListenersCollection = listenersCollection.get(eventName);
|
59
|
+
if (!currentEventListenersCollection) {
|
60
|
+
listenersCollection.set(eventName, [listener]);
|
61
|
+
return;
|
62
|
+
}
|
63
|
+
currentEventListenersCollection.push(listener);
|
64
|
+
},
|
65
|
+
unsubscribe(eventName, listener) {
|
66
|
+
const index = listenersCollection.get(eventName)?.indexOf(listener);
|
67
|
+
if (index === -1 || index === void 0) return;
|
68
|
+
listenersCollection.get(eventName)?.splice(index, 1);
|
69
|
+
},
|
70
|
+
removeAllListeners() {
|
71
|
+
listenersCollection.clear();
|
72
|
+
},
|
73
|
+
deserialize: (v) => parse(v),
|
74
|
+
serialize: (v) => stringify(v, { maxDepth: Infinity })
|
75
|
+
}
|
76
|
+
);
|
77
|
+
window.addEventListener("message", (event) => {
|
78
|
+
if (typeof event.data !== "object") return;
|
79
|
+
if (event.data.source !== IFRAME_SOURCE_NAME || !event.data.request) return;
|
80
|
+
const currentEventListeners = listenersCollection.get(event.data.request.eventName);
|
81
|
+
if (!currentEventListeners?.length) return;
|
82
|
+
currentEventListeners.forEach((listener) => listener(...event.data.request.args));
|
83
|
+
});
|
84
|
+
return client;
|
85
|
+
}
|
package/dist/iframe.d.ts
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
import type { CoreIframeContext, CoreIframeEvents, EditorEvents } from './types';
|
2
|
+
/**
|
3
|
+
* This function should be called inside the iframe
|
4
|
+
*/
|
5
|
+
export declare function createIframeClient<IframeContext extends CoreIframeContext, IframeEvents extends CoreIframeEvents>(local: Exclude<IframeContext, CoreIframeContext>): {} & {
|
6
|
+
$context: CoreIframeContext;
|
7
|
+
on: <E extends never>(eventName: E, listener: (...args: EditorEvents[E] extends infer T ? T extends EditorEvents[E] ? T extends (...args: infer A) => any ? A : never : never : never) => void) => void;
|
8
|
+
off: <E extends never>(eventName: E, listener: (...args: EditorEvents[E] extends infer T ? T extends EditorEvents[E] ? T extends (...args: infer A) => any ? A : never : never : never) => void) => void;
|
9
|
+
emit: <E extends keyof CoreIframeEvents>(eventName: E, ...args: CoreIframeEvents[E] extends infer T ? T extends CoreIframeEvents[E] ? T extends (...args: infer A) => any ? A : never : never : never) => void;
|
10
|
+
removeAllListeners: () => void;
|
11
|
+
};
|
package/dist/iframe.js
ADDED
@@ -0,0 +1,238 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
exports.createIframeClient = createIframeClient;
|
7
|
+
var _constants = require("./constants");
|
8
|
+
var _createClient = require("./createClient");
|
9
|
+
var _telejson = require("telejson");
|
10
|
+
const listenersCollection = /* @__PURE__ */new Map();
|
11
|
+
function getSelector(path, id) {
|
12
|
+
return `[data-node-id="${id}"][data-node-path="${path}"]`;
|
13
|
+
}
|
14
|
+
function getElementStyles(selector, withPadding) {
|
15
|
+
const elements = document.querySelectorAll(selector);
|
16
|
+
if (!elements?.length) return;
|
17
|
+
const styles = Array.from(elements).map(element => {
|
18
|
+
const clientRect = element.getBoundingClientRect();
|
19
|
+
const position = {
|
20
|
+
width: clientRect.width,
|
21
|
+
height: clientRect.height,
|
22
|
+
top: clientRect.top,
|
23
|
+
left: clientRect.left
|
24
|
+
};
|
25
|
+
if (!withPadding) return position;
|
26
|
+
const computedStyle = window.getComputedStyle(element) ?? {};
|
27
|
+
return {
|
28
|
+
...position,
|
29
|
+
padding: {
|
30
|
+
top: computedStyle.paddingTop,
|
31
|
+
right: computedStyle.paddingRight,
|
32
|
+
bottom: computedStyle.paddingBottom,
|
33
|
+
left: computedStyle.paddingLeft
|
34
|
+
}
|
35
|
+
};
|
36
|
+
});
|
37
|
+
if (!styles?.length) return;
|
38
|
+
return styles.length === 1 ? styles[0] : styles;
|
39
|
+
}
|
40
|
+
function createIframeClient(local) {
|
41
|
+
const client = (0, _createClient.createClient)({
|
42
|
+
document: window.document,
|
43
|
+
async editText({
|
44
|
+
path,
|
45
|
+
id
|
46
|
+
}) {
|
47
|
+
if (!path || id === void 0) return;
|
48
|
+
const selector = getSelector(path, id);
|
49
|
+
const element = document.querySelector(selector);
|
50
|
+
if (!element) return;
|
51
|
+
element.style.outline = "none";
|
52
|
+
element.setAttribute("spellcheck", "false");
|
53
|
+
element.setAttribute("contenteditable", "true");
|
54
|
+
const blurEvtHandler = event => {
|
55
|
+
const elm = event.target;
|
56
|
+
if (!elm) return;
|
57
|
+
const content = elm.innerText;
|
58
|
+
element.removeAttribute("contenteditable");
|
59
|
+
client.emit("text-update", {
|
60
|
+
path,
|
61
|
+
id,
|
62
|
+
content
|
63
|
+
});
|
64
|
+
element.removeEventListener("blur", blurEvtHandler);
|
65
|
+
element.removeEventListener("keydown", keyDownEvtHandler);
|
66
|
+
element.blur();
|
67
|
+
};
|
68
|
+
const keyDownEvtHandler = event => {
|
69
|
+
if (event.key === "Enter") {
|
70
|
+
event.stopPropagation();
|
71
|
+
event.preventDefault();
|
72
|
+
blurEvtHandler(event);
|
73
|
+
}
|
74
|
+
};
|
75
|
+
element.addEventListener("keydown", keyDownEvtHandler);
|
76
|
+
element.addEventListener("blur", blurEvtHandler);
|
77
|
+
element.focus();
|
78
|
+
},
|
79
|
+
async getHoveredElement({
|
80
|
+
path,
|
81
|
+
id,
|
82
|
+
x,
|
83
|
+
y
|
84
|
+
}) {
|
85
|
+
if (!path) return;
|
86
|
+
if (x !== void 0 && y !== void 0) {
|
87
|
+
let element = document.elementFromPoint(x, y);
|
88
|
+
if (!element) return;
|
89
|
+
let elementPath = element.getAttribute("data-node-path");
|
90
|
+
if (elementPath !== path) {
|
91
|
+
if (!element.parentElement) return;
|
92
|
+
while (element.parentElement && path !== path) {
|
93
|
+
element = element.parentElement;
|
94
|
+
elementPath = element.getAttribute("data-node-path");
|
95
|
+
}
|
96
|
+
}
|
97
|
+
const elementId = element.getAttribute("data-node-id");
|
98
|
+
if (!elementId) return;
|
99
|
+
const selector = getSelector(path, elementId);
|
100
|
+
const styles = getElementStyles(selector, false);
|
101
|
+
if (!styles) return;
|
102
|
+
return {
|
103
|
+
id: elementId,
|
104
|
+
path,
|
105
|
+
data: styles
|
106
|
+
};
|
107
|
+
} else {
|
108
|
+
const selector = getSelector(path, id);
|
109
|
+
const styles = getElementStyles(selector, false);
|
110
|
+
if (!styles) return;
|
111
|
+
return {
|
112
|
+
id,
|
113
|
+
path,
|
114
|
+
data: styles
|
115
|
+
};
|
116
|
+
}
|
117
|
+
},
|
118
|
+
async getPageHeight() {
|
119
|
+
const height = document.body.scrollHeight > 0 ? document.body.scrollHeight : document.documentElement.scrollHeight;
|
120
|
+
return height;
|
121
|
+
},
|
122
|
+
async getSelectedElement({
|
123
|
+
path,
|
124
|
+
id
|
125
|
+
}) {
|
126
|
+
const selector = getSelector(path, id);
|
127
|
+
const styles = getElementStyles(selector, true);
|
128
|
+
if (!styles) return;
|
129
|
+
return {
|
130
|
+
path,
|
131
|
+
id,
|
132
|
+
data: styles
|
133
|
+
};
|
134
|
+
},
|
135
|
+
toggleTheme(theme) {
|
136
|
+
if (theme === "dark") {
|
137
|
+
document.documentElement.classList.remove("light");
|
138
|
+
document.documentElement.classList.add("dark");
|
139
|
+
} else {
|
140
|
+
document.documentElement.classList.remove("dark");
|
141
|
+
document.documentElement.classList.add("light");
|
142
|
+
}
|
143
|
+
}
|
144
|
+
}, {
|
145
|
+
emit(eventName, ...args) {
|
146
|
+
window.parent.postMessage({
|
147
|
+
source: _constants.IFRAME_SOURCE_NAME,
|
148
|
+
request: {
|
149
|
+
eventName,
|
150
|
+
args
|
151
|
+
}
|
152
|
+
}, "*");
|
153
|
+
},
|
154
|
+
handle(handler) {
|
155
|
+
window.addEventListener("message", async event => {
|
156
|
+
if (typeof event.data !== "object") return;
|
157
|
+
if (event.data.source !== _constants.EDITOR_SOURCE_NAME) return;
|
158
|
+
const response = await handler(event.data.request);
|
159
|
+
window.parent.postMessage({
|
160
|
+
source: _constants.IFRAME_SOURCE_NAME,
|
161
|
+
response
|
162
|
+
}, "*");
|
163
|
+
});
|
164
|
+
},
|
165
|
+
invoke(request) {
|
166
|
+
return new Promise((resolve, reject) => {
|
167
|
+
const timeout = setTimeout(() => {
|
168
|
+
window.removeEventListener("message", messageHandler);
|
169
|
+
reject(new Error("Request timed out"));
|
170
|
+
}, 5e3);
|
171
|
+
function messageHandler(event) {
|
172
|
+
if (typeof event.data !== "object") return;
|
173
|
+
if (event.data.source !== _constants.EDITOR_SOURCE_NAME || !event.data.response) return;
|
174
|
+
if (event.data.response.id !== request.id) return;
|
175
|
+
clearTimeout(timeout);
|
176
|
+
window.removeEventListener("message", messageHandler);
|
177
|
+
resolve(event.data.response);
|
178
|
+
}
|
179
|
+
window.parent.postMessage({
|
180
|
+
source: _constants.IFRAME_SOURCE_NAME,
|
181
|
+
request
|
182
|
+
}, "*");
|
183
|
+
window.addEventListener("message", messageHandler);
|
184
|
+
});
|
185
|
+
},
|
186
|
+
subscribe(eventName, listener) {
|
187
|
+
const currentEventListeners = listenersCollection.get(eventName);
|
188
|
+
if (!currentEventListeners) {
|
189
|
+
listenersCollection.set(eventName, [listener]);
|
190
|
+
return;
|
191
|
+
}
|
192
|
+
currentEventListeners.push(listener);
|
193
|
+
},
|
194
|
+
unsubscribe(eventName, listener) {
|
195
|
+
const index = listenersCollection.get(eventName)?.indexOf(listener);
|
196
|
+
if (index === -1 || index === void 0) return;
|
197
|
+
listenersCollection.get(eventName)?.splice(index, 1);
|
198
|
+
},
|
199
|
+
removeAllListeners() {
|
200
|
+
listenersCollection.clear();
|
201
|
+
},
|
202
|
+
deserialize: v => (0, _telejson.parse)(v),
|
203
|
+
serialize: v => (0, _telejson.stringify)(v, {
|
204
|
+
maxDepth: Infinity
|
205
|
+
})
|
206
|
+
});
|
207
|
+
window.addEventListener("message", event => {
|
208
|
+
if (typeof event.data !== "object") return;
|
209
|
+
if (event.data.source !== _constants.EDITOR_SOURCE_NAME || !event.data.request) return;
|
210
|
+
const currentEventListeners = listenersCollection.get(event.data.request.eventName);
|
211
|
+
if (!currentEventListeners?.length) return;
|
212
|
+
currentEventListeners.forEach(listener => listener(...event.data.request.args));
|
213
|
+
});
|
214
|
+
console.log = (...args) => {
|
215
|
+
client.emit("console", "log", args);
|
216
|
+
};
|
217
|
+
console.warn = (...args) => {};
|
218
|
+
console.error = (...args) => {
|
219
|
+
client.emit("console", "error", args);
|
220
|
+
};
|
221
|
+
console.info = (...args) => {
|
222
|
+
client.emit("console", "info", args);
|
223
|
+
};
|
224
|
+
window.addEventListener("resize", async () => client.emit("resize", await client.$context.getPageHeight()));
|
225
|
+
const mutationObserver = new MutationObserver(async () => client.emit("resize", await client.$context.getPageHeight()));
|
226
|
+
mutationObserver.observe(document.body, {
|
227
|
+
childList: true,
|
228
|
+
// observe direct children additions/removals
|
229
|
+
subtree: true,
|
230
|
+
// observe all descendants
|
231
|
+
attributes: true,
|
232
|
+
// observe attribute changes (like style, class)
|
233
|
+
characterData: true
|
234
|
+
// observe text changes
|
235
|
+
});
|
236
|
+
client.emit("ready");
|
237
|
+
return client;
|
238
|
+
}
|
package/dist/iframe.mjs
ADDED
@@ -0,0 +1,209 @@
|
|
1
|
+
import { EDITOR_SOURCE_NAME, IFRAME_SOURCE_NAME } from "./constants.mjs";
|
2
|
+
import { createClient } from "./createClient.mjs";
|
3
|
+
import { stringify, parse } from "telejson";
|
4
|
+
const listenersCollection = /* @__PURE__ */ new Map();
|
5
|
+
function getSelector(path, id) {
|
6
|
+
return `[data-node-id="${id}"][data-node-path="${path}"]`;
|
7
|
+
}
|
8
|
+
function getElementStyles(selector, withPadding) {
|
9
|
+
const elements = document.querySelectorAll(selector);
|
10
|
+
if (!elements?.length) return;
|
11
|
+
const styles = Array.from(elements).map((element) => {
|
12
|
+
const clientRect = element.getBoundingClientRect();
|
13
|
+
const position = {
|
14
|
+
width: clientRect.width,
|
15
|
+
height: clientRect.height,
|
16
|
+
top: clientRect.top,
|
17
|
+
left: clientRect.left
|
18
|
+
};
|
19
|
+
if (!withPadding) return position;
|
20
|
+
const computedStyle = window.getComputedStyle(element) ?? {};
|
21
|
+
return {
|
22
|
+
...position,
|
23
|
+
padding: {
|
24
|
+
top: computedStyle.paddingTop,
|
25
|
+
right: computedStyle.paddingRight,
|
26
|
+
bottom: computedStyle.paddingBottom,
|
27
|
+
left: computedStyle.paddingLeft
|
28
|
+
}
|
29
|
+
};
|
30
|
+
});
|
31
|
+
if (!styles?.length) return;
|
32
|
+
return styles.length === 1 ? styles[0] : styles;
|
33
|
+
}
|
34
|
+
export function createIframeClient(local) {
|
35
|
+
const client = createClient(
|
36
|
+
{
|
37
|
+
document: window.document,
|
38
|
+
async editText({ path, id }) {
|
39
|
+
if (!path || id === void 0) return;
|
40
|
+
const selector = getSelector(path, id);
|
41
|
+
const element = document.querySelector(selector);
|
42
|
+
if (!element) return;
|
43
|
+
element.style.outline = "none";
|
44
|
+
element.setAttribute("spellcheck", "false");
|
45
|
+
element.setAttribute("contenteditable", "true");
|
46
|
+
const blurEvtHandler = (event) => {
|
47
|
+
const elm = event.target;
|
48
|
+
if (!elm) return;
|
49
|
+
const content = elm.innerText;
|
50
|
+
element.removeAttribute("contenteditable");
|
51
|
+
client.emit("text-update", { path, id, content });
|
52
|
+
element.removeEventListener("blur", blurEvtHandler);
|
53
|
+
element.removeEventListener("keydown", keyDownEvtHandler);
|
54
|
+
element.blur();
|
55
|
+
};
|
56
|
+
const keyDownEvtHandler = (event) => {
|
57
|
+
if (event.key === "Enter") {
|
58
|
+
event.stopPropagation();
|
59
|
+
event.preventDefault();
|
60
|
+
blurEvtHandler(event);
|
61
|
+
}
|
62
|
+
};
|
63
|
+
element.addEventListener("keydown", keyDownEvtHandler);
|
64
|
+
element.addEventListener("blur", blurEvtHandler);
|
65
|
+
element.focus();
|
66
|
+
},
|
67
|
+
async getHoveredElement({ path, id, x, y }) {
|
68
|
+
if (!path) return;
|
69
|
+
if (x !== void 0 && y !== void 0) {
|
70
|
+
let element = document.elementFromPoint(x, y);
|
71
|
+
if (!element) return;
|
72
|
+
let elementPath = element.getAttribute("data-node-path");
|
73
|
+
if (elementPath !== path) {
|
74
|
+
if (!element.parentElement) return;
|
75
|
+
while (element.parentElement && path !== path) {
|
76
|
+
element = element.parentElement;
|
77
|
+
elementPath = element.getAttribute("data-node-path");
|
78
|
+
}
|
79
|
+
}
|
80
|
+
const elementId = element.getAttribute("data-node-id");
|
81
|
+
if (!elementId) return;
|
82
|
+
const selector = getSelector(path, elementId);
|
83
|
+
const styles = getElementStyles(selector, false);
|
84
|
+
if (!styles) return;
|
85
|
+
return {
|
86
|
+
id: elementId,
|
87
|
+
path,
|
88
|
+
data: styles
|
89
|
+
};
|
90
|
+
} else {
|
91
|
+
const selector = getSelector(path, id);
|
92
|
+
const styles = getElementStyles(selector, false);
|
93
|
+
if (!styles) return;
|
94
|
+
return {
|
95
|
+
id,
|
96
|
+
path,
|
97
|
+
data: styles
|
98
|
+
};
|
99
|
+
}
|
100
|
+
},
|
101
|
+
async getPageHeight() {
|
102
|
+
const height = document.body.scrollHeight > 0 ? document.body.scrollHeight : document.documentElement.scrollHeight;
|
103
|
+
return height;
|
104
|
+
},
|
105
|
+
async getSelectedElement({ path, id }) {
|
106
|
+
const selector = getSelector(path, id);
|
107
|
+
const styles = getElementStyles(selector, true);
|
108
|
+
if (!styles) return;
|
109
|
+
return {
|
110
|
+
path,
|
111
|
+
id,
|
112
|
+
data: styles
|
113
|
+
};
|
114
|
+
},
|
115
|
+
toggleTheme(theme) {
|
116
|
+
if (theme === "dark") {
|
117
|
+
document.documentElement.classList.remove("light");
|
118
|
+
document.documentElement.classList.add("dark");
|
119
|
+
} else {
|
120
|
+
document.documentElement.classList.remove("dark");
|
121
|
+
document.documentElement.classList.add("light");
|
122
|
+
}
|
123
|
+
}
|
124
|
+
},
|
125
|
+
{
|
126
|
+
emit(eventName, ...args) {
|
127
|
+
window.parent.postMessage({ source: IFRAME_SOURCE_NAME, request: { eventName, args } }, "*");
|
128
|
+
},
|
129
|
+
handle(handler) {
|
130
|
+
window.addEventListener("message", async (event) => {
|
131
|
+
if (typeof event.data !== "object") return;
|
132
|
+
if (event.data.source !== EDITOR_SOURCE_NAME) return;
|
133
|
+
const response = await handler(event.data.request);
|
134
|
+
window.parent.postMessage({ source: IFRAME_SOURCE_NAME, response }, "*");
|
135
|
+
});
|
136
|
+
},
|
137
|
+
invoke(request) {
|
138
|
+
return new Promise((resolve, reject) => {
|
139
|
+
const timeout = setTimeout(() => {
|
140
|
+
window.removeEventListener("message", messageHandler);
|
141
|
+
reject(new Error("Request timed out"));
|
142
|
+
}, 5e3);
|
143
|
+
function messageHandler(event) {
|
144
|
+
if (typeof event.data !== "object") return;
|
145
|
+
if (event.data.source !== EDITOR_SOURCE_NAME || !event.data.response) return;
|
146
|
+
if (event.data.response.id !== request.id) return;
|
147
|
+
clearTimeout(timeout);
|
148
|
+
window.removeEventListener("message", messageHandler);
|
149
|
+
resolve(event.data.response);
|
150
|
+
}
|
151
|
+
window.parent.postMessage({ source: IFRAME_SOURCE_NAME, request }, "*");
|
152
|
+
window.addEventListener("message", messageHandler);
|
153
|
+
});
|
154
|
+
},
|
155
|
+
subscribe(eventName, listener) {
|
156
|
+
const currentEventListeners = listenersCollection.get(eventName);
|
157
|
+
if (!currentEventListeners) {
|
158
|
+
listenersCollection.set(eventName, [listener]);
|
159
|
+
return;
|
160
|
+
}
|
161
|
+
currentEventListeners.push(listener);
|
162
|
+
},
|
163
|
+
unsubscribe(eventName, listener) {
|
164
|
+
const index = listenersCollection.get(eventName)?.indexOf(listener);
|
165
|
+
if (index === -1 || index === void 0) return;
|
166
|
+
listenersCollection.get(eventName)?.splice(index, 1);
|
167
|
+
},
|
168
|
+
removeAllListeners() {
|
169
|
+
listenersCollection.clear();
|
170
|
+
},
|
171
|
+
deserialize: (v) => parse(v),
|
172
|
+
serialize: (v) => stringify(v, { maxDepth: Infinity })
|
173
|
+
}
|
174
|
+
);
|
175
|
+
window.addEventListener("message", (event) => {
|
176
|
+
if (typeof event.data !== "object") return;
|
177
|
+
if (event.data.source !== EDITOR_SOURCE_NAME || !event.data.request) return;
|
178
|
+
const currentEventListeners = listenersCollection.get(event.data.request.eventName);
|
179
|
+
if (!currentEventListeners?.length) return;
|
180
|
+
currentEventListeners.forEach((listener) => listener(...event.data.request.args));
|
181
|
+
});
|
182
|
+
console.log = (...args) => {
|
183
|
+
client.emit("console", "log", args);
|
184
|
+
};
|
185
|
+
console.warn = (...args) => {
|
186
|
+
};
|
187
|
+
console.error = (...args) => {
|
188
|
+
client.emit("console", "error", args);
|
189
|
+
};
|
190
|
+
console.info = (...args) => {
|
191
|
+
client.emit("console", "info", args);
|
192
|
+
};
|
193
|
+
window.addEventListener("resize", async () => client.emit("resize", await client.$context.getPageHeight()));
|
194
|
+
const mutationObserver = new MutationObserver(
|
195
|
+
async () => client.emit("resize", await client.$context.getPageHeight())
|
196
|
+
);
|
197
|
+
mutationObserver.observe(document.body, {
|
198
|
+
childList: true,
|
199
|
+
// observe direct children additions/removals
|
200
|
+
subtree: true,
|
201
|
+
// observe all descendants
|
202
|
+
attributes: true,
|
203
|
+
// observe attribute changes (like style, class)
|
204
|
+
characterData: true
|
205
|
+
// observe text changes
|
206
|
+
});
|
207
|
+
client.emit("ready");
|
208
|
+
return client;
|
209
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
4
|
+
value: true
|
5
|
+
});
|
6
|
+
var _createClient = require("./createClient");
|
7
|
+
Object.keys(_createClient).forEach(function (key) {
|
8
|
+
if (key === "default" || key === "__esModule") return;
|
9
|
+
if (key in exports && exports[key] === _createClient[key]) return;
|
10
|
+
Object.defineProperty(exports, key, {
|
11
|
+
enumerable: true,
|
12
|
+
get: function () {
|
13
|
+
return _createClient[key];
|
14
|
+
}
|
15
|
+
});
|
16
|
+
});
|
17
|
+
var _constants = require("./constants");
|
18
|
+
Object.keys(_constants).forEach(function (key) {
|
19
|
+
if (key === "default" || key === "__esModule") return;
|
20
|
+
if (key in exports && exports[key] === _constants[key]) return;
|
21
|
+
Object.defineProperty(exports, key, {
|
22
|
+
enumerable: true,
|
23
|
+
get: function () {
|
24
|
+
return _constants[key];
|
25
|
+
}
|
26
|
+
});
|
27
|
+
});
|
28
|
+
var _types = require("./types");
|
29
|
+
Object.keys(_types).forEach(function (key) {
|
30
|
+
if (key === "default" || key === "__esModule") return;
|
31
|
+
if (key in exports && exports[key] === _types[key]) return;
|
32
|
+
Object.defineProperty(exports, key, {
|
33
|
+
enumerable: true,
|
34
|
+
get: function () {
|
35
|
+
return _types[key];
|
36
|
+
}
|
37
|
+
});
|
38
|
+
});
|
package/dist/index.mjs
ADDED
package/dist/types.d.ts
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
export interface EventRequest {
|
2
|
+
eventName: string;
|
3
|
+
args: any[];
|
4
|
+
}
|
5
|
+
export type EventListener = (...args: any[]) => void;
|
6
|
+
export interface ContextRequest {
|
7
|
+
type: 'request';
|
8
|
+
id: string;
|
9
|
+
key: string;
|
10
|
+
args: any[];
|
11
|
+
}
|
12
|
+
export interface ContextResponse {
|
13
|
+
type: 'response';
|
14
|
+
id: string;
|
15
|
+
key: string;
|
16
|
+
result: any;
|
17
|
+
}
|
18
|
+
export interface CoreIframeContext {
|
19
|
+
toggleTheme: (theme: 'dark' | 'light') => void;
|
20
|
+
getHoveredElement: (options: {
|
21
|
+
path: string;
|
22
|
+
id?: string;
|
23
|
+
x?: number;
|
24
|
+
y?: number;
|
25
|
+
}) => Promise<{
|
26
|
+
id: string;
|
27
|
+
path: string;
|
28
|
+
data: ElementPosition | ElementPosition[];
|
29
|
+
} | undefined>;
|
30
|
+
getSelectedElement: (options: {
|
31
|
+
path: string;
|
32
|
+
id: string;
|
33
|
+
}) => Promise<{
|
34
|
+
id: string;
|
35
|
+
path: string;
|
36
|
+
data: ElementStyles | ElementStyles[];
|
37
|
+
} | undefined>;
|
38
|
+
getPageHeight: () => Promise<number>;
|
39
|
+
editText: (options: {
|
40
|
+
path: string;
|
41
|
+
id: string;
|
42
|
+
}) => void;
|
43
|
+
document: Document;
|
44
|
+
}
|
45
|
+
export interface CoreIframeEvents {
|
46
|
+
ready: () => void;
|
47
|
+
'route-change': (to: string) => void;
|
48
|
+
resize: (height: number) => void;
|
49
|
+
'text-update': (options: {
|
50
|
+
path: string;
|
51
|
+
id: string;
|
52
|
+
content: string;
|
53
|
+
}) => void;
|
54
|
+
console: (type: 'log' | 'error' | 'info' | 'warn', message: any[]) => void;
|
55
|
+
}
|
56
|
+
export interface IframeContext extends CoreIframeContext {
|
57
|
+
navigateTo: (to: string) => void;
|
58
|
+
getValue: (opts: {
|
59
|
+
code: string;
|
60
|
+
path?: string;
|
61
|
+
onTemplateContext?: boolean;
|
62
|
+
context?: Record<string, any>;
|
63
|
+
}) => any;
|
64
|
+
getInstanceData: (path: string /** filepath path of the component */) => Record<string, any>;
|
65
|
+
runCode: (opts: {
|
66
|
+
path?: string;
|
67
|
+
code: string;
|
68
|
+
onTemplateContext?: boolean;
|
69
|
+
context?: Record<string, any>;
|
70
|
+
}) => any;
|
71
|
+
updatePreview?: (options: {
|
72
|
+
path: string;
|
73
|
+
code: string;
|
74
|
+
}) => void;
|
75
|
+
}
|
76
|
+
export interface IframeEvents extends CoreIframeEvents {
|
77
|
+
}
|
78
|
+
export interface EditorContext {
|
79
|
+
}
|
80
|
+
export interface EditorEvents {
|
81
|
+
}
|
82
|
+
export interface ElementPosition {
|
83
|
+
top: number;
|
84
|
+
left: number;
|
85
|
+
width: number;
|
86
|
+
height: number;
|
87
|
+
}
|
88
|
+
export interface ElementStyles extends ElementPosition {
|
89
|
+
padding: {
|
90
|
+
top: string;
|
91
|
+
right: string;
|
92
|
+
bottom: string;
|
93
|
+
left: string;
|
94
|
+
};
|
95
|
+
}
|
package/dist/types.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
"use strict";
|
package/dist/types.mjs
ADDED
File without changes
|
package/package.json
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
{
|
2
|
+
"name": "@nookuio/iframe",
|
3
|
+
"description": "",
|
4
|
+
"version": "0.1.0",
|
5
|
+
"main": "./dist/index.js",
|
6
|
+
"module": "./dist/index.mjs",
|
7
|
+
"exports": {
|
8
|
+
".": {
|
9
|
+
"require": "./dist/index.js",
|
10
|
+
"import": "./dist/index.mjs",
|
11
|
+
"types": "./dist/index.d.ts"
|
12
|
+
},
|
13
|
+
"./iframe": {
|
14
|
+
"require": "./dist/iframe.js",
|
15
|
+
"import": "./dist/iframe.mjs",
|
16
|
+
"types": "./dist/iframe.d.ts"
|
17
|
+
},
|
18
|
+
"./editor": {
|
19
|
+
"require": "./dist/editor.js",
|
20
|
+
"import": "./dist/editor.mjs",
|
21
|
+
"types": "./dist/editor.d.ts"
|
22
|
+
},
|
23
|
+
"./types": {
|
24
|
+
"require": "./dist/types.js",
|
25
|
+
"import": "./dist/types.mjs",
|
26
|
+
"types": "./dist/types.d.ts"
|
27
|
+
}
|
28
|
+
},
|
29
|
+
"files": [
|
30
|
+
"dist"
|
31
|
+
],
|
32
|
+
"dependencies": {
|
33
|
+
"telejson": "^7.2.0"
|
34
|
+
},
|
35
|
+
"devDependencies": {},
|
36
|
+
"keywords": [],
|
37
|
+
"author": "",
|
38
|
+
"license": "ISC",
|
39
|
+
"scripts": {
|
40
|
+
"build": "unbuild"
|
41
|
+
}
|
42
|
+
}
|