@servicetitan/dte-unlayer 0.0.1-test1
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/api-core.d.ts +19 -0
- package/dist/api-core.d.ts.map +1 -0
- package/dist/api-core.js +121 -0
- package/dist/api-core.js.map +1 -0
- package/dist/api-custom-tools.d.ts +18 -0
- package/dist/api-custom-tools.d.ts.map +1 -0
- package/dist/api-custom-tools.js +96 -0
- package/dist/api-custom-tools.js.map +1 -0
- package/dist/editor.d.ts +19 -0
- package/dist/editor.d.ts.map +1 -0
- package/dist/editor.js +47 -0
- package/dist/editor.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/loadScript.d.ts +2 -0
- package/dist/loadScript.d.ts.map +1 -0
- package/dist/loadScript.js +24 -0
- package/dist/loadScript.js.map +1 -0
- package/dist/shared/const.d.ts +27 -0
- package/dist/shared/const.d.ts.map +1 -0
- package/dist/shared/const.js +6 -0
- package/dist/shared/const.js.map +1 -0
- package/dist/shared/fonts.d.ts +10 -0
- package/dist/shared/fonts.d.ts.map +1 -0
- package/dist/shared/fonts.js +127 -0
- package/dist/shared/fonts.js.map +1 -0
- package/dist/shared/schema.d.ts +51 -0
- package/dist/shared/schema.d.ts.map +1 -0
- package/dist/shared/schema.js +104 -0
- package/dist/shared/schema.js.map +1 -0
- package/dist/shared/tools.d.ts +14 -0
- package/dist/shared/tools.d.ts.map +1 -0
- package/dist/shared/tools.js +8 -0
- package/dist/shared/tools.js.map +1 -0
- package/dist/store.d.ts +31 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +274 -0
- package/dist/store.js.map +1 -0
- package/dist/tools.d.ts +26 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +164 -0
- package/dist/tools.js.map +1 -0
- package/dist/unlayer-interface.d.ts +64 -0
- package/dist/unlayer-interface.d.ts.map +1 -0
- package/dist/unlayer-interface.js +2 -0
- package/dist/unlayer-interface.js.map +1 -0
- package/dist/unlayer.d.ts +57 -0
- package/dist/unlayer.d.ts.map +1 -0
- package/dist/unlayer.js +117 -0
- package/dist/unlayer.js.map +1 -0
- package/package.json +20 -0
- package/src/__tests__/schema.test.ts +96 -0
- package/src/api-core.ts +94 -0
- package/src/api-custom-tools.ts +79 -0
- package/src/editor.tsx +87 -0
- package/src/index.ts +11 -0
- package/src/loadScript.ts +27 -0
- package/src/shared/const.ts +30 -0
- package/src/shared/fonts.ts +126 -0
- package/src/shared/schema.ts +190 -0
- package/src/shared/tools.ts +18 -0
- package/src/store.ts +197 -0
- package/src/tools.ts +213 -0
- package/src/unlayer-interface.tsx +71 -0
- package/src/unlayer.tsx +176 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { loadScript } from './loadScript';
|
|
2
|
+
import { UnlayerEditorCustomTool } from './unlayer-interface';
|
|
3
|
+
|
|
4
|
+
export interface UnlayerCustomToolsPackageData {
|
|
5
|
+
packageUrl: string;
|
|
6
|
+
customTools: UnlayerEditorCustomTool[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class UnlayerCustomToolsApi {
|
|
10
|
+
private dataInternal?: UnlayerCustomToolsPackageData;
|
|
11
|
+
private loaded = new Set<string>();
|
|
12
|
+
private schemas?: Record<string, any>;
|
|
13
|
+
|
|
14
|
+
constructor(private packageUrl: string) {}
|
|
15
|
+
|
|
16
|
+
get data() {
|
|
17
|
+
return this.dataInternal!;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async init() {
|
|
21
|
+
await fetch(`${this.packageUrl}/data.json`)
|
|
22
|
+
.then(response =>
|
|
23
|
+
response
|
|
24
|
+
.json()
|
|
25
|
+
.then(data => ({ ...data, packageUrl: response.url.replace('/data.json', '') }))
|
|
26
|
+
)
|
|
27
|
+
.then(({ packageUrl, tools }) => ({
|
|
28
|
+
customTools: tools.map((tool: any) => ({
|
|
29
|
+
key: tool.key,
|
|
30
|
+
title: tool.title,
|
|
31
|
+
path: `${packageUrl}/${tool.path}`,
|
|
32
|
+
})),
|
|
33
|
+
packageUrl,
|
|
34
|
+
}))
|
|
35
|
+
.then(data => {
|
|
36
|
+
this.dataInternal = data;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
clean() {
|
|
41
|
+
this.dataInternal = undefined;
|
|
42
|
+
this.loaded = new Set();
|
|
43
|
+
this.schemas = undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async loadSchemas(): Promise<Record<string, any>> {
|
|
47
|
+
if (this.schemas) {
|
|
48
|
+
return this.schemas;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return fetch(`${this.data.packageUrl}/schemas.json`)
|
|
52
|
+
.then(response => response.json())
|
|
53
|
+
.then(schemas => {
|
|
54
|
+
this.schemas = schemas;
|
|
55
|
+
|
|
56
|
+
return schemas;
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async preloadCustomTools(tools: string[]) {
|
|
61
|
+
if (!this.dataInternal) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const toolsMap = this.data.customTools.reduce((out, t) => {
|
|
65
|
+
out[t.key] = t.path;
|
|
66
|
+
|
|
67
|
+
return out;
|
|
68
|
+
}, {} as Record<string, string>);
|
|
69
|
+
|
|
70
|
+
await Promise.all(
|
|
71
|
+
tools
|
|
72
|
+
.filter(t => !!toolsMap[t] && !this.loaded.has(t))
|
|
73
|
+
.map(t => {
|
|
74
|
+
this.loaded.add(t);
|
|
75
|
+
return loadScript(this.data.packageUrl + '/' + toolsMap[t]).catch(() => null);
|
|
76
|
+
})
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
package/src/editor.tsx
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CSSProperties,
|
|
3
|
+
forwardRef,
|
|
4
|
+
useEffect,
|
|
5
|
+
useImperativeHandle,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
} from 'react';
|
|
10
|
+
import { UnlayerStore, UnlayerDesignChangeInfo } from './store';
|
|
11
|
+
import { UnlayerRef, CreateUnlayerEditorProps } from './unlayer-interface';
|
|
12
|
+
|
|
13
|
+
export interface UnlayerEditorProps {
|
|
14
|
+
id?: string;
|
|
15
|
+
design?: any;
|
|
16
|
+
opts: CreateUnlayerEditorProps;
|
|
17
|
+
minHeight?: number;
|
|
18
|
+
style?: CSSProperties;
|
|
19
|
+
onReady?(): void;
|
|
20
|
+
onChange?(info: UnlayerDesignChangeInfo): void;
|
|
21
|
+
onImage?(file: File): Promise<{ url: string }>;
|
|
22
|
+
onMessage?(type: string, data: any): void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const useUnlayerRef = () => useRef<UnlayerRef | null>(null);
|
|
26
|
+
|
|
27
|
+
export const UnlayerEditor = forwardRef<UnlayerRef, UnlayerEditorProps>((props, ref) => {
|
|
28
|
+
const [status, setStatus] = useState(0);
|
|
29
|
+
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
30
|
+
const store = useMemo(
|
|
31
|
+
() => new UnlayerStore(props.opts),
|
|
32
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
33
|
+
[]
|
|
34
|
+
);
|
|
35
|
+
const isReady = status === 2;
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (containerRef.current) {
|
|
39
|
+
store
|
|
40
|
+
.init(containerRef.current)
|
|
41
|
+
.then(() => setStatus(2))
|
|
42
|
+
.catch(() => setStatus(1));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return () => store.destroy();
|
|
46
|
+
}, [store]);
|
|
47
|
+
useImperativeHandle(ref, () => store.unlayerRef, [store]);
|
|
48
|
+
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (isReady) {
|
|
51
|
+
store.setDesign(props.design);
|
|
52
|
+
}
|
|
53
|
+
}, [isReady, props.design, store]);
|
|
54
|
+
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
store.setOnChange(props.onChange);
|
|
57
|
+
|
|
58
|
+
return () => store.setOnChange();
|
|
59
|
+
}, [props.onChange, store]);
|
|
60
|
+
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
store.setOnReady(props.onReady);
|
|
63
|
+
|
|
64
|
+
return () => store.setOnReady();
|
|
65
|
+
}, [props.onReady, store]);
|
|
66
|
+
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
store.setOnImage(props.onImage);
|
|
69
|
+
|
|
70
|
+
return () => store.setOnImage();
|
|
71
|
+
}, [props.onImage, store]);
|
|
72
|
+
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
store.setOnMessage(props.onMessage);
|
|
75
|
+
|
|
76
|
+
return () => store.setOnMessage();
|
|
77
|
+
}, [props.onMessage, store]);
|
|
78
|
+
|
|
79
|
+
const { minHeight = 800, style = {} } = props;
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<div style={{ minHeight, display: 'flex' }}>
|
|
83
|
+
{status === 1 && <p className="c-red-500">error loading editor</p>}
|
|
84
|
+
<div id={props.id ?? 'editor'} style={style} ref={containerRef} />
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './editor';
|
|
2
|
+
export * from './tools';
|
|
3
|
+
export * from './api-core';
|
|
4
|
+
export * from './api-custom-tools';
|
|
5
|
+
export * from './unlayer-interface';
|
|
6
|
+
export * from './loadScript';
|
|
7
|
+
export * from './shared/const';
|
|
8
|
+
export * from './shared/schema';
|
|
9
|
+
export * from './shared/tools';
|
|
10
|
+
export { UnlayerDesignChangeInfo } from './store';
|
|
11
|
+
export { versions } from './unlayer';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const isScriptInjected = (scriptUrl: string) => {
|
|
2
|
+
const scripts = document.querySelectorAll('script');
|
|
3
|
+
let injected = false;
|
|
4
|
+
|
|
5
|
+
scripts.forEach(script => {
|
|
6
|
+
if (script.src.includes(scriptUrl)) {
|
|
7
|
+
injected = true;
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
return injected;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const loadScript = (scriptUrl: string): Promise<void> => {
|
|
15
|
+
return new Promise<void>(resolve => {
|
|
16
|
+
if (isScriptInjected(scriptUrl)) {
|
|
17
|
+
resolve();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const embedScript = document.createElement('script');
|
|
21
|
+
embedScript.setAttribute('src', scriptUrl);
|
|
22
|
+
embedScript.onload = () => {
|
|
23
|
+
resolve();
|
|
24
|
+
};
|
|
25
|
+
document.head.appendChild(embedScript);
|
|
26
|
+
});
|
|
27
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { SchemaObject } from './schema';
|
|
2
|
+
|
|
3
|
+
export const constGenericsEditor = {
|
|
4
|
+
infoDataProperty: '_info',
|
|
5
|
+
adminConfigProperty: 'adminConfig',
|
|
6
|
+
userConfigProperty: 'config',
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export interface IUnlayerEditorUnit {
|
|
10
|
+
id: string;
|
|
11
|
+
generic: string;
|
|
12
|
+
title: string;
|
|
13
|
+
values: any;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface UnlayerEventConfig {
|
|
17
|
+
dummyData?: any;
|
|
18
|
+
schema?: SchemaObject;
|
|
19
|
+
generics?: true | string[];
|
|
20
|
+
genericConfigMode?: boolean;
|
|
21
|
+
units?: IUnlayerEditorUnit[];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface UnlayerEventRegister {
|
|
25
|
+
units?: IUnlayerEditorUnit[];
|
|
26
|
+
customTools?: {
|
|
27
|
+
key: string;
|
|
28
|
+
title?: string;
|
|
29
|
+
}[];
|
|
30
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
export const unlayerSupportedFonts = [
|
|
2
|
+
{
|
|
3
|
+
label: 'Andale Mono',
|
|
4
|
+
value: 'andale mono,times',
|
|
5
|
+
},
|
|
6
|
+
{
|
|
7
|
+
label: 'Arial',
|
|
8
|
+
value: 'arial,helvetica,sans-serif',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
label: 'Arial Black',
|
|
12
|
+
value: 'arial black,avant garde,arial',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
label: 'Book Antiqua',
|
|
16
|
+
value: 'book antiqua,palatino',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
label: 'Comic Sans MS',
|
|
20
|
+
value: 'comic sans ms,sans-serif',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
label: 'Courier New',
|
|
24
|
+
value: 'courier new,courier',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
label: 'Georgia',
|
|
28
|
+
value: 'georgia,palatino',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
label: 'Helvetica',
|
|
32
|
+
value: 'helvetica,sans-serif',
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
label: 'Impact',
|
|
36
|
+
value: 'impact,chicago',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
label: 'Symbol',
|
|
40
|
+
value: 'symbol',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
label: 'Tahoma',
|
|
44
|
+
value: 'tahoma,arial,helvetica,sans-serif',
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
label: 'Terminal',
|
|
48
|
+
value: 'terminal,monaco',
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
label: 'Times New Roman',
|
|
52
|
+
value: 'times new roman,times',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
label: 'Trebuchet MS',
|
|
56
|
+
value: 'trebuchet ms,geneva',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
label: 'Verdana',
|
|
60
|
+
value: 'verdana,geneva',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
label: 'Lobster Two',
|
|
64
|
+
value: "'Lobster Two',cursive",
|
|
65
|
+
url: 'https://fonts.googleapis.com/css?family=Lobster+Two:400,700',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
label: 'Playfair Display',
|
|
69
|
+
value: "'Playfair Display',serif",
|
|
70
|
+
url: 'https://fonts.googleapis.com/css?family=Playfair+Display:400,700',
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
label: 'Rubik',
|
|
74
|
+
value: "'Rubik',sans-serif",
|
|
75
|
+
url: 'https://fonts.googleapis.com/css?family=Rubik:400,700',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
label: 'Source Sans Pro',
|
|
79
|
+
value: "'Source Sans Pro',sans-serif",
|
|
80
|
+
url: 'https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700',
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
label: 'Open Sans',
|
|
84
|
+
value: "'Open Sans',sans-serif",
|
|
85
|
+
url: 'https://fonts.googleapis.com/css?family=Open+Sans:400,700',
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
label: 'Crimson Text',
|
|
89
|
+
value: "'Crimson Text',serif",
|
|
90
|
+
url: 'https://fonts.googleapis.com/css?family=Crimson+Text:400,700',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
label: 'Montserrat',
|
|
94
|
+
value: "'Montserrat',sans-serif",
|
|
95
|
+
url: 'https://fonts.googleapis.com/css?family=Montserrat:400,700',
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
label: 'Old Standard TT',
|
|
99
|
+
value: "'Old Standard TT',serif",
|
|
100
|
+
url: 'https://fonts.googleapis.com/css?family=Old+Standard+TT:400,700',
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
label: 'Lato',
|
|
104
|
+
value: "'Lato',sans-serif",
|
|
105
|
+
url: 'https://fonts.googleapis.com/css?family=Lato:400,700',
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
label: 'Raleway',
|
|
109
|
+
value: "'Raleway',sans-serif",
|
|
110
|
+
url: 'https://fonts.googleapis.com/css?family=Raleway:400,700',
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
label: 'Cabin',
|
|
114
|
+
value: "'Cabin',sans-serif",
|
|
115
|
+
url: 'https://fonts.googleapis.com/css?family=Cabin:400,700',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
label: 'Pacifico',
|
|
119
|
+
value: "'Pacifico',cursive",
|
|
120
|
+
url: 'https://fonts.googleapis.com/css?family=Pacifico',
|
|
121
|
+
},
|
|
122
|
+
// custom DTE fonts
|
|
123
|
+
{ label: 'Sofia Pro', value: 'Sofia Pro' },
|
|
124
|
+
{ label: 'Nunito Sans', value: 'Nunito Sans' },
|
|
125
|
+
{ label: 'Montserrat', value: 'Montserrat' },
|
|
126
|
+
];
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
export type SchemaNodeAvailableTypes = 'object' | 'array' | 'string';
|
|
2
|
+
export const schemaNodeAvailableTypes = ['object', 'array', 'string'];
|
|
3
|
+
|
|
4
|
+
export type SchemaNodeStringSubTypes = 'string' | 'text' | 'html';
|
|
5
|
+
export const schemaNodeStringSubTypes = ['string', 'text', 'html'];
|
|
6
|
+
|
|
7
|
+
export const schemaIsAvailableType = (type: string): type is SchemaNodeAvailableTypes =>
|
|
8
|
+
schemaNodeAvailableTypes.includes(type);
|
|
9
|
+
|
|
10
|
+
export interface SchemaFieldBaseOptions {
|
|
11
|
+
placeholder?: any;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface SchemaNodeProps {
|
|
15
|
+
title?: string;
|
|
16
|
+
options?: SchemaFieldBaseOptions;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface SchemaObject extends SchemaNodeProps {
|
|
20
|
+
type: 'object';
|
|
21
|
+
properties: Record<string, SchemaNode>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface SchemaArray extends SchemaNodeProps {
|
|
25
|
+
type: 'array';
|
|
26
|
+
items: SchemaNode;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface SchemaSimpleString extends SchemaNodeProps {
|
|
30
|
+
type: 'string';
|
|
31
|
+
subType?: SchemaNodeStringSubTypes;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type SchemaSimple = SchemaSimpleString;
|
|
35
|
+
|
|
36
|
+
export const schemaArrayRootKey = '[]';
|
|
37
|
+
export type SchemaNode = SchemaObject | SchemaArray | SchemaSimple;
|
|
38
|
+
|
|
39
|
+
export const schemaIsObject = (node?: SchemaNode): node is SchemaObject => node?.type === 'object';
|
|
40
|
+
export const schemaIsArray = (node?: SchemaNode): node is SchemaArray => node?.type === 'array';
|
|
41
|
+
export const schemaIsString = (node?: SchemaNode): node is SchemaSimpleString =>
|
|
42
|
+
node?.type === 'string';
|
|
43
|
+
export const schemaIsStringHtml = (node?: SchemaNode): node is SchemaSimpleString =>
|
|
44
|
+
node?.type === 'string' && node?.subType === 'html';
|
|
45
|
+
|
|
46
|
+
export const schemaFindNode = (schema: SchemaNode, key: string): SchemaNode | undefined => {
|
|
47
|
+
const nodeFinder = (node: SchemaNode, keys: string[]): SchemaNode | undefined => {
|
|
48
|
+
if (!node) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!keys.length) {
|
|
53
|
+
return node;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const key = keys.shift();
|
|
57
|
+
|
|
58
|
+
if (!key) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (key === schemaArrayRootKey) {
|
|
63
|
+
return schemaIsArray(node) ? nodeFinder(node.items, keys) : undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return schemaIsObject(node) ? nodeFinder(node.properties[key], keys) : undefined;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
return nodeFinder(schema, key.split('.'));
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export const schemaFindParentNode = (schema: SchemaNode, key: string): SchemaNode | undefined => {
|
|
73
|
+
const keys = key.split('.');
|
|
74
|
+
|
|
75
|
+
keys.pop();
|
|
76
|
+
|
|
77
|
+
return keys.length
|
|
78
|
+
? schemaFindNode(schema, keys.join('.'))
|
|
79
|
+
: schemaIsObject(schema) && schema.properties[key]
|
|
80
|
+
? schema
|
|
81
|
+
: undefined;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const schemaGetFieldKey = (fullKey: string): string => fullKey.split('.').pop() ?? '';
|
|
85
|
+
|
|
86
|
+
export const schemaBuildNode = (
|
|
87
|
+
type: SchemaNodeAvailableTypes,
|
|
88
|
+
arrayItemType?: SchemaNodeAvailableTypes
|
|
89
|
+
): SchemaNode => {
|
|
90
|
+
if (type === 'object') {
|
|
91
|
+
return { type: 'object', properties: {}, options: {} };
|
|
92
|
+
}
|
|
93
|
+
if (type === 'array') {
|
|
94
|
+
return { type: 'array', items: schemaBuildNode(arrayItemType ?? 'object'), options: {} };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return { type, options: {} };
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
export interface SchemaMetaField {
|
|
101
|
+
fieldKey: string;
|
|
102
|
+
fullKey: string;
|
|
103
|
+
node: SchemaNode;
|
|
104
|
+
title: string; // node.title or fullTitle
|
|
105
|
+
fullTitle: string; // joined title of all parents and field
|
|
106
|
+
isArrayed: boolean;
|
|
107
|
+
isValue: boolean;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export type SchemaMap = Record<string, SchemaMetaField>;
|
|
111
|
+
|
|
112
|
+
export const schemaBuildMap = (schema: SchemaObject): { map: SchemaMap; dummyData: any } => {
|
|
113
|
+
const fieldsMap: Record<string, SchemaMetaField> = {};
|
|
114
|
+
const dummyData: any = {};
|
|
115
|
+
|
|
116
|
+
const processNode = (
|
|
117
|
+
node: SchemaNode,
|
|
118
|
+
nodeKey: string,
|
|
119
|
+
parentNodes: { key: string; title: string }[],
|
|
120
|
+
isArrayed: boolean,
|
|
121
|
+
dummyDataNode: any
|
|
122
|
+
) => {
|
|
123
|
+
const nodeLabel = node.title ?? nodeKey;
|
|
124
|
+
const isArrayRoot = nodeKey === schemaArrayRootKey;
|
|
125
|
+
|
|
126
|
+
if (nodeKey) {
|
|
127
|
+
const fullKey = [...parentNodes.map(n => n.key), nodeKey].join('.');
|
|
128
|
+
const fullTitle = [...parentNodes.map(n => n.title), nodeLabel].join(' - ');
|
|
129
|
+
|
|
130
|
+
fieldsMap[fullKey] = {
|
|
131
|
+
fieldKey: nodeKey,
|
|
132
|
+
fullKey,
|
|
133
|
+
fullTitle,
|
|
134
|
+
title: node.title ?? fullTitle,
|
|
135
|
+
node,
|
|
136
|
+
isArrayed,
|
|
137
|
+
isValue: !schemaIsObject(node) && !schemaIsArray(node),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (schemaIsObject(node)) {
|
|
142
|
+
const properties = node.properties ?? {};
|
|
143
|
+
const keys = Object.keys(properties ?? {}).sort();
|
|
144
|
+
let dummyDataObject = {};
|
|
145
|
+
|
|
146
|
+
if (isArrayRoot) {
|
|
147
|
+
dummyDataNode.push?.(dummyDataObject);
|
|
148
|
+
} else if (nodeKey) {
|
|
149
|
+
dummyDataNode[nodeKey] = dummyDataObject;
|
|
150
|
+
} else {
|
|
151
|
+
dummyDataObject = dummyDataNode;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
for (const key of keys) {
|
|
155
|
+
processNode(
|
|
156
|
+
properties[key],
|
|
157
|
+
key,
|
|
158
|
+
nodeKey ? [...parentNodes, { key: nodeKey, title: nodeLabel }] : [],
|
|
159
|
+
isArrayed,
|
|
160
|
+
dummyDataObject
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
} else if (schemaIsArray(node)) {
|
|
164
|
+
const items = node.items ?? {};
|
|
165
|
+
|
|
166
|
+
dummyDataNode[nodeKey] = [];
|
|
167
|
+
processNode(
|
|
168
|
+
items,
|
|
169
|
+
schemaArrayRootKey,
|
|
170
|
+
nodeKey ? [...parentNodes, { key: nodeKey, title: nodeLabel }] : [],
|
|
171
|
+
true,
|
|
172
|
+
dummyDataNode[nodeKey]
|
|
173
|
+
);
|
|
174
|
+
} else if (nodeKey) {
|
|
175
|
+
const placeholder = node?.options?.placeholder;
|
|
176
|
+
|
|
177
|
+
if (placeholder !== undefined) {
|
|
178
|
+
if (isArrayRoot) {
|
|
179
|
+
dummyDataNode.push?.(placeholder);
|
|
180
|
+
} else {
|
|
181
|
+
dummyDataNode[nodeKey] = placeholder;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
processNode(schema, '', [], false, dummyData);
|
|
188
|
+
|
|
189
|
+
return { map: fieldsMap, dummyData };
|
|
190
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const unlayerUnitsGenerateToolKey = (unitId: string, unitGeneric: string) =>
|
|
2
|
+
`${unitGeneric}:unit:${unitId}`;
|
|
3
|
+
|
|
4
|
+
export const unlayerUnitsParseToolKey = (
|
|
5
|
+
toolKey: string
|
|
6
|
+
): { id: string; generic: string } | undefined => {
|
|
7
|
+
const [generic, type, id] = (toolKey ?? '').split(':');
|
|
8
|
+
|
|
9
|
+
if (type === 'unit' && generic && id) {
|
|
10
|
+
return { id, generic };
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export interface UnlayerStore {
|
|
15
|
+
renderHtml(html: string, data: any): string;
|
|
16
|
+
sendData(type: string, data?: any): void;
|
|
17
|
+
getTool(key: string): { getModel(): object; dataSources(values?: any): string[] } | undefined;
|
|
18
|
+
}
|