@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
package/src/store.ts
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { loadScript } from './loadScript';
|
|
2
|
+
import { UnlayerEventConfig, UnlayerEventRegister } from './shared/const';
|
|
3
|
+
import {
|
|
4
|
+
createUnlayerEditor,
|
|
5
|
+
DesignUpdatedEventType,
|
|
6
|
+
EventDesignUpdated,
|
|
7
|
+
Unlayer,
|
|
8
|
+
} from './unlayer';
|
|
9
|
+
import { CreateUnlayerEditorProps, UnlayerDesignFormat, UnlayerRef } from './unlayer-interface';
|
|
10
|
+
|
|
11
|
+
const defaultScriptUrl = 'https://editor.unlayer.com/embed.js?2';
|
|
12
|
+
|
|
13
|
+
export interface UnlayerDesignChangeInfo {
|
|
14
|
+
isToolsListChanged: boolean;
|
|
15
|
+
event: any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const eventsNotChangingToolsList: DesignUpdatedEventType[] = [
|
|
19
|
+
DesignUpdatedEventType.ContentMoved,
|
|
20
|
+
DesignUpdatedEventType.ContentModified,
|
|
21
|
+
DesignUpdatedEventType.ColumnModified,
|
|
22
|
+
DesignUpdatedEventType.RowMoved,
|
|
23
|
+
DesignUpdatedEventType.RowModified,
|
|
24
|
+
DesignUpdatedEventType.BodyModified,
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
export class UnlayerStore {
|
|
28
|
+
readonly unlayerRef: UnlayerRef;
|
|
29
|
+
|
|
30
|
+
private editor: Unlayer | undefined;
|
|
31
|
+
private isInit = false;
|
|
32
|
+
private iframe?: HTMLIFrameElement;
|
|
33
|
+
private hasDesign = false;
|
|
34
|
+
|
|
35
|
+
private onMessageCB?: (type: string, data: any) => void;
|
|
36
|
+
private onChangeCB?: (info: UnlayerDesignChangeInfo) => void;
|
|
37
|
+
private onReadyCB?: () => void;
|
|
38
|
+
private onImageCB?: (file: File) => Promise<{ url: string }>;
|
|
39
|
+
|
|
40
|
+
constructor(readonly props: CreateUnlayerEditorProps) {
|
|
41
|
+
this.unlayerRef = {
|
|
42
|
+
loadDesign: design => {
|
|
43
|
+
this.editor?.loadDesign(design);
|
|
44
|
+
},
|
|
45
|
+
saveDesign: cb => {
|
|
46
|
+
this.editor?.saveDesign(cb);
|
|
47
|
+
},
|
|
48
|
+
exportHtml: cb => {
|
|
49
|
+
this.editor?.exportHtml(data => {
|
|
50
|
+
cb(data);
|
|
51
|
+
});
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
init = async (container: HTMLDivElement) => {
|
|
57
|
+
if (this.isInit) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
this.isInit = true;
|
|
62
|
+
|
|
63
|
+
window.addEventListener('message', this.onPostMessage);
|
|
64
|
+
|
|
65
|
+
await loadScript(defaultScriptUrl);
|
|
66
|
+
|
|
67
|
+
this.editor = createUnlayerEditor(container, this.props);
|
|
68
|
+
this.editor.addEventListener('design:loaded', this.onDesignLoaded);
|
|
69
|
+
this.editor.addEventListener('design:updated', this.onDesignUpdated);
|
|
70
|
+
this.editor.registerCallback('image', this.uploadImage);
|
|
71
|
+
|
|
72
|
+
this.iframe = container.querySelector(`iframe`) ?? undefined;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
destroy = () => {
|
|
76
|
+
window.removeEventListener('message', this.onPostMessage);
|
|
77
|
+
|
|
78
|
+
if (this.editor) {
|
|
79
|
+
this.editor.removeEventListener('design:loaded', this.onDesignLoaded);
|
|
80
|
+
this.editor.removeEventListener('design:updated', this.onDesignUpdated);
|
|
81
|
+
this.editor.unregisterCallback('image', this.uploadImage);
|
|
82
|
+
|
|
83
|
+
this.editor = undefined;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
setDesign = (design?: UnlayerDesignFormat) => {
|
|
88
|
+
if (!this.editor) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this.hasDesign = !!design;
|
|
93
|
+
|
|
94
|
+
if (design) {
|
|
95
|
+
this.editor.loadDesign(design);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
setOnChange = (onChange?: UnlayerStore['onChangeCB']) => {
|
|
100
|
+
this.onChangeCB = onChange;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
setOnReady = (onReady?: UnlayerStore['onReadyCB']) => {
|
|
104
|
+
this.onReadyCB = onReady;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
setOnImage = (onImage?: UnlayerStore['onImageCB']) => {
|
|
108
|
+
this.onImageCB = onImage;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
setOnMessage = (onMessage?: UnlayerStore['onMessageCB']) => {
|
|
112
|
+
this.onMessageCB = onMessage;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
private onDesignLoaded = () => {
|
|
116
|
+
if (!this.hasDesign) {
|
|
117
|
+
this.hasDesign = true;
|
|
118
|
+
this.editor?.setBodyValues({
|
|
119
|
+
backgroundColor: 'rgba(0,0,0,0)',
|
|
120
|
+
contentWidth: '100%',
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
private onDesignUpdated = (event: EventDesignUpdated) => {
|
|
126
|
+
this.onChangeCB?.({
|
|
127
|
+
isToolsListChanged: !eventsNotChangingToolsList.includes(event.type),
|
|
128
|
+
event,
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
private onPostMessage = (e: MessageEvent) => {
|
|
133
|
+
if (!e.data?.['-dte-message-from']) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const type = e.data?.['-dte-message-from']?.type;
|
|
138
|
+
const data = e.data?.['-dte-message-from']?.data;
|
|
139
|
+
|
|
140
|
+
if (!type) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (type === '--ready' || type === '--registered') {
|
|
145
|
+
this.onReadyCB?.();
|
|
146
|
+
} else if (type === '--core-loaded') {
|
|
147
|
+
const data: UnlayerEventConfig = {
|
|
148
|
+
dummyData: this.props.dummyData,
|
|
149
|
+
schema: this.props.schema,
|
|
150
|
+
generics: this.props.generics,
|
|
151
|
+
genericConfigMode: this.props.genericConfigMode,
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
this.sendMessage('--config', JSON.parse(JSON.stringify(data)));
|
|
155
|
+
} else if (type === '--data-loaded') {
|
|
156
|
+
const data: UnlayerEventRegister = {
|
|
157
|
+
customTools: this.props.tools.map(tool => ({ key: tool.key })),
|
|
158
|
+
units: this.props.units?.map(unit => ({
|
|
159
|
+
...unit,
|
|
160
|
+
values: {
|
|
161
|
+
...unit.values,
|
|
162
|
+
adminConfig: undefined,
|
|
163
|
+
},
|
|
164
|
+
})),
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
this.sendMessage('--register', JSON.parse(JSON.stringify(data)));
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
this.onMessageCB?.(type, data);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
private sendMessage = (type: string, data?: any) => {
|
|
174
|
+
this.iframe?.contentWindow?.postMessage(
|
|
175
|
+
{
|
|
176
|
+
'-dte-message-to': {
|
|
177
|
+
type,
|
|
178
|
+
data,
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
'*'
|
|
182
|
+
);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
private uploadImage = (data: any, done: (result: any) => void) => {
|
|
186
|
+
if (!this.onImageCB) {
|
|
187
|
+
done({ progress: 100 });
|
|
188
|
+
throw new Error('image upload is not implemented');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (data.attachments?.length) {
|
|
192
|
+
this.onImageCB(data.attachments[0])
|
|
193
|
+
.then(({ url }) => done({ progress: 100, url }))
|
|
194
|
+
.catch(() => done({ progress: 100 }));
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
package/src/tools.ts
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { constGenericsEditor } from './shared/const';
|
|
2
|
+
import { unlayerUnitsParseToolKey } from './shared/tools';
|
|
3
|
+
import { versions } from './unlayer';
|
|
4
|
+
import { UnlayerDesignFormat, UnlayerDesignTool } from './unlayer-interface';
|
|
5
|
+
|
|
6
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
7
|
+
export const unlayerGetDefaultDesign = (): UnlayerDesignFormat => ({
|
|
8
|
+
counters: {
|
|
9
|
+
u_column: 1,
|
|
10
|
+
u_row: 1,
|
|
11
|
+
u_content_custom_generic_list_of_fields: 1,
|
|
12
|
+
},
|
|
13
|
+
body: {
|
|
14
|
+
rows: [
|
|
15
|
+
{
|
|
16
|
+
cells: [1],
|
|
17
|
+
columns: [
|
|
18
|
+
{
|
|
19
|
+
contents: [],
|
|
20
|
+
values: {
|
|
21
|
+
backgroundColor: '',
|
|
22
|
+
padding: '0px',
|
|
23
|
+
border: {},
|
|
24
|
+
_meta: {
|
|
25
|
+
htmlID: 'u_column_1',
|
|
26
|
+
htmlClassNames: 'u_column',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
values: {
|
|
32
|
+
displayCondition: null,
|
|
33
|
+
columns: false,
|
|
34
|
+
backgroundColor: '',
|
|
35
|
+
columnsBackgroundColor: '',
|
|
36
|
+
backgroundImage: {
|
|
37
|
+
url: '',
|
|
38
|
+
fullWidth: true,
|
|
39
|
+
repeat: false,
|
|
40
|
+
center: true,
|
|
41
|
+
cover: false,
|
|
42
|
+
},
|
|
43
|
+
padding: '0px',
|
|
44
|
+
hideDesktop: false,
|
|
45
|
+
hideMobile: false,
|
|
46
|
+
noStackMobile: false,
|
|
47
|
+
_meta: {
|
|
48
|
+
htmlID: 'u_row_1',
|
|
49
|
+
htmlClassNames: 'u_row',
|
|
50
|
+
},
|
|
51
|
+
selectable: true,
|
|
52
|
+
draggable: true,
|
|
53
|
+
duplicatable: true,
|
|
54
|
+
deletable: true,
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
values: {
|
|
59
|
+
backgroundColor: 'rgba(0,0,0,0)',
|
|
60
|
+
backgroundImage: {
|
|
61
|
+
url: '',
|
|
62
|
+
fullWidth: true,
|
|
63
|
+
repeat: false,
|
|
64
|
+
center: true,
|
|
65
|
+
cover: false,
|
|
66
|
+
},
|
|
67
|
+
contentWidth: '100%',
|
|
68
|
+
contentAlign: 'center',
|
|
69
|
+
fontFamily: {
|
|
70
|
+
label: 'Arial',
|
|
71
|
+
value: 'arial,helvetica,sans-serif',
|
|
72
|
+
},
|
|
73
|
+
preheaderText: '',
|
|
74
|
+
linkStyle: {
|
|
75
|
+
body: true,
|
|
76
|
+
linkColor: '#0000ee',
|
|
77
|
+
linkHoverColor: '#0000ee',
|
|
78
|
+
linkUnderline: true,
|
|
79
|
+
linkHoverUnderline: true,
|
|
80
|
+
},
|
|
81
|
+
_meta: {
|
|
82
|
+
htmlID: 'u_body',
|
|
83
|
+
htmlClassNames: 'u_body',
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
schemaVersion: versions.schema,
|
|
88
|
+
});
|
|
89
|
+
/* eslint-enable @typescript-eslint/naming-convention */
|
|
90
|
+
|
|
91
|
+
export const unlayerToolsIterate = (
|
|
92
|
+
design: UnlayerDesignFormat,
|
|
93
|
+
cb: (tool: UnlayerDesignTool) => boolean | undefined | void
|
|
94
|
+
) => {
|
|
95
|
+
for (const row of design?.body?.rows ?? []) {
|
|
96
|
+
for (const column of row.columns) {
|
|
97
|
+
for (const content of column.contents) {
|
|
98
|
+
if (cb(content) === false) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const unlayerToolsIterateCustom = (
|
|
107
|
+
design: UnlayerDesignFormat,
|
|
108
|
+
cb: (tool: UnlayerDesignTool) => boolean | undefined | void
|
|
109
|
+
) => {
|
|
110
|
+
unlayerToolsIterate(design, tool => {
|
|
111
|
+
if (tool.type === 'custom') {
|
|
112
|
+
return cb(tool);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
export const unlayerToolsListCustomKeys = (design: UnlayerDesignFormat): string[] => {
|
|
118
|
+
return Array.from(new Set(unlayerToolsListCustom(design).map(tool => tool.slug)));
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
export const unlayerToolsFind = (
|
|
122
|
+
design: UnlayerDesignFormat,
|
|
123
|
+
cb: (tool: UnlayerDesignTool) => boolean | void
|
|
124
|
+
): UnlayerDesignTool | undefined => {
|
|
125
|
+
let out: UnlayerDesignTool | undefined;
|
|
126
|
+
|
|
127
|
+
unlayerToolsIterate(design, tool => {
|
|
128
|
+
if (cb(tool)) {
|
|
129
|
+
out = tool;
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
return out;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export interface UnlayerCustomToolsStat {
|
|
138
|
+
counters: Record<string, number>;
|
|
139
|
+
missing: string[];
|
|
140
|
+
notSupported: string[];
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export const unlayerToolsCustomStat = (
|
|
144
|
+
design: UnlayerDesignFormat,
|
|
145
|
+
tools?: { key: string; isRequired?: boolean }[],
|
|
146
|
+
units?: { id: string; generic: string; isRequired?: boolean }[]
|
|
147
|
+
): UnlayerCustomToolsStat => {
|
|
148
|
+
const counters: Record<string, number> = {};
|
|
149
|
+
const notSupported = new Set<string>();
|
|
150
|
+
const unitIDs = new Set<string>();
|
|
151
|
+
|
|
152
|
+
unlayerToolsIterateCustom(design, tool => {
|
|
153
|
+
if (!counters[tool.slug]) {
|
|
154
|
+
counters[tool.slug] = 0;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
counters[tool.slug]++;
|
|
158
|
+
|
|
159
|
+
const isUnit = unlayerUnitsParseToolKey(tool.slug);
|
|
160
|
+
|
|
161
|
+
if (isUnit) {
|
|
162
|
+
unitIDs.add(isUnit.id);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (
|
|
166
|
+
(isUnit && !units?.some(unit => unit.id === isUnit.id)) ||
|
|
167
|
+
(!isUnit && !tools?.some(t => t.key === tool.slug))
|
|
168
|
+
) {
|
|
169
|
+
notSupported.add(tool.slug);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
counters,
|
|
175
|
+
notSupported: Array.from(notSupported),
|
|
176
|
+
|
|
177
|
+
missing: [
|
|
178
|
+
...(tools
|
|
179
|
+
?.filter(tool => tool.isRequired && !counters[tool.key])
|
|
180
|
+
.map(tool => tool.key) ?? []),
|
|
181
|
+
...(units
|
|
182
|
+
?.filter(unit => unit.isRequired && !unitIDs.has(unit.id))
|
|
183
|
+
.map(unit => unit.id) ?? []),
|
|
184
|
+
],
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export const unlayerToolsListCustom = (design: UnlayerDesignFormat): UnlayerDesignTool[] => {
|
|
189
|
+
const tools: UnlayerDesignTool[] = [];
|
|
190
|
+
|
|
191
|
+
unlayerToolsIterateCustom(design, tool => {
|
|
192
|
+
tools.push(tool);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
return tools;
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
export const unlayerToolsBuildDesign = (tools: UnlayerDesignTool[]): UnlayerDesignFormat => {
|
|
199
|
+
const design = unlayerGetDefaultDesign();
|
|
200
|
+
|
|
201
|
+
design.body.rows[0].columns[0].contents = tools;
|
|
202
|
+
return design;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
export const unlayerUnitsGetIdFromValues = (values?: any): string | undefined =>
|
|
206
|
+
values?.[constGenericsEditor.adminConfigProperty]?.crossId;
|
|
207
|
+
export const unlayerUnitsGetTitleFromValues = (values?: any): string | undefined =>
|
|
208
|
+
values?.[constGenericsEditor.adminConfigProperty]?.title;
|
|
209
|
+
|
|
210
|
+
export const unlayerUnitsGetId = (tool: UnlayerDesignTool): string | undefined =>
|
|
211
|
+
unlayerUnitsGetIdFromValues(tool.values);
|
|
212
|
+
export const unlayerUnitsGetTitle = (tool: UnlayerDesignTool): string | undefined =>
|
|
213
|
+
unlayerUnitsGetTitleFromValues(tool.values);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { UnlayerCoreApi } from './api-core';
|
|
2
|
+
import { SchemaObject } from './shared/schema';
|
|
3
|
+
|
|
4
|
+
export interface UnlayerDesignTool {
|
|
5
|
+
type: string;
|
|
6
|
+
slug: string;
|
|
7
|
+
values: any;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface UnlayerDesignFormat {
|
|
11
|
+
body: {
|
|
12
|
+
rows: {
|
|
13
|
+
cells: number[];
|
|
14
|
+
columns: {
|
|
15
|
+
contents: UnlayerDesignTool[];
|
|
16
|
+
values?: any;
|
|
17
|
+
}[];
|
|
18
|
+
values?: any;
|
|
19
|
+
}[];
|
|
20
|
+
values?: any;
|
|
21
|
+
};
|
|
22
|
+
counters: Record<string, number>;
|
|
23
|
+
schemaVersion: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface UnlayerExport {
|
|
27
|
+
html: string;
|
|
28
|
+
chunks: any;
|
|
29
|
+
design: UnlayerDesignFormat;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface UnlayerRef {
|
|
33
|
+
loadDesign(design: any): void;
|
|
34
|
+
saveDesign(cb: (design: any) => void): void;
|
|
35
|
+
exportHtml(cb: (data: UnlayerExport) => void): void;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface UnlayerEditorMergeTagInfo {
|
|
39
|
+
id: string;
|
|
40
|
+
name: string;
|
|
41
|
+
propertyPath: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface UnlayerEditorUnit {
|
|
45
|
+
id: string;
|
|
46
|
+
generic: string;
|
|
47
|
+
title: string;
|
|
48
|
+
values: any;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface UnlayerEditorCustomTool {
|
|
52
|
+
key: string;
|
|
53
|
+
title: string;
|
|
54
|
+
path: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface CreateUnlayerEditorProps {
|
|
58
|
+
tools: UnlayerEditorCustomTool[];
|
|
59
|
+
dummyData?: any;
|
|
60
|
+
schema?: SchemaObject;
|
|
61
|
+
customCSS?: string | string[] | undefined;
|
|
62
|
+
customJS?: string | string[] | undefined;
|
|
63
|
+
mergeTags?: UnlayerEditorMergeTagInfo[] | undefined;
|
|
64
|
+
genericConfigMode?: boolean;
|
|
65
|
+
generics?: true | string[];
|
|
66
|
+
units?: UnlayerEditorUnit[];
|
|
67
|
+
noCoreTools?: boolean;
|
|
68
|
+
latest?: boolean;
|
|
69
|
+
blocks?: boolean;
|
|
70
|
+
coreApi: UnlayerCoreApi;
|
|
71
|
+
}
|
package/src/unlayer.tsx
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { constGenericsEditor } from './shared/const';
|
|
2
|
+
import { unlayerSupportedFonts } from './shared/fonts';
|
|
3
|
+
import { CreateUnlayerEditorProps } from './unlayer-interface';
|
|
4
|
+
|
|
5
|
+
export interface UnlayerExport {
|
|
6
|
+
html: string;
|
|
7
|
+
chunks: any;
|
|
8
|
+
design: any;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface Unlayer {
|
|
12
|
+
addEventListener(event: string, cb: (arg: any) => void): void;
|
|
13
|
+
removeEventListener(event: string, cb: (arg: any) => void): void;
|
|
14
|
+
registerCallback(type: string, cb: (...args: any[]) => void): void;
|
|
15
|
+
unregisterCallback(type: string, cb: (...args: any[]) => void): void;
|
|
16
|
+
registerProvider(type: string, cb: (...args: any[]) => void): void;
|
|
17
|
+
unregisterProvider(type: string, cb: (...args: any[]) => void): void;
|
|
18
|
+
loadDesign(design: any): void;
|
|
19
|
+
saveDesign(callback: (design: any) => void): void;
|
|
20
|
+
exportHtml(callback: (data: UnlayerExport) => void): void;
|
|
21
|
+
setMergeTags(tags: any): void;
|
|
22
|
+
createViewer(opts: { render: (values: any) => string }): any;
|
|
23
|
+
registerTool(tool: any): void;
|
|
24
|
+
setBodyValues(values: any): void;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export enum DesignUpdatedEventType {
|
|
28
|
+
ContentAdded = 'content:added',
|
|
29
|
+
ContentMoved = 'content:moved',
|
|
30
|
+
ContentRemoved = 'content:removed',
|
|
31
|
+
ContentModified = 'content:modified',
|
|
32
|
+
RowAdded = 'row:added',
|
|
33
|
+
RowMoved = 'row:moved',
|
|
34
|
+
RowRemoved = 'row:removed',
|
|
35
|
+
RowModified = 'row:modified',
|
|
36
|
+
ColumnAdded = 'column:added',
|
|
37
|
+
ColumnRemoved = 'column:removed',
|
|
38
|
+
ColumnModified = 'column:modified',
|
|
39
|
+
BodyModified = 'body:modified',
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface EventDesignUpdated {
|
|
43
|
+
type: DesignUpdatedEventType;
|
|
44
|
+
item: {
|
|
45
|
+
type: string;
|
|
46
|
+
slug?: string;
|
|
47
|
+
values: any;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* !!! IMPORTANT !!!
|
|
53
|
+
* do not forget to update schema version when updating unlayer version
|
|
54
|
+
* it is important for templates export and should be in sync
|
|
55
|
+
* to know correct schema version, open unlayer editor and check output design ('schema' property)
|
|
56
|
+
*/
|
|
57
|
+
export const versions = {
|
|
58
|
+
unlayer: '1.2.9',
|
|
59
|
+
schema: 5,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const createUnlayerEditor = (
|
|
63
|
+
container: HTMLDivElement,
|
|
64
|
+
{
|
|
65
|
+
coreApi,
|
|
66
|
+
customCSS,
|
|
67
|
+
customJS,
|
|
68
|
+
latest,
|
|
69
|
+
mergeTags,
|
|
70
|
+
noCoreTools,
|
|
71
|
+
tools,
|
|
72
|
+
units,
|
|
73
|
+
}: CreateUnlayerEditorProps
|
|
74
|
+
): Unlayer => {
|
|
75
|
+
const customScripts = [
|
|
76
|
+
...coreApi.pathsCore,
|
|
77
|
+
...coreApi.pathsCoreTools,
|
|
78
|
+
'window.dteStore.sendData("--core-loaded")',
|
|
79
|
+
...tools.map(tool => tool.path),
|
|
80
|
+
...(customJS ? (Array.isArray(customJS) ? customJS : [customJS]) : []),
|
|
81
|
+
'window.dteStore.sendData("--data-loaded")',
|
|
82
|
+
].filter(js => !!js?.trim());
|
|
83
|
+
const customStyles = [
|
|
84
|
+
coreApi.customCss,
|
|
85
|
+
...(customCSS ? (Array.isArray(customCSS) ? customCSS : [customCSS]) : []),
|
|
86
|
+
].filter(css => !!css?.trim());
|
|
87
|
+
|
|
88
|
+
console.log('###unlayer init', customScripts, customStyles);
|
|
89
|
+
/**
|
|
90
|
+
* Unlayer supports only passing id of container, but when we use shadowDOM (MFE),
|
|
91
|
+
* getElementById can't find element in it
|
|
92
|
+
* so making this dirty hack to let unlayer find container in DOM
|
|
93
|
+
*/
|
|
94
|
+
const id = container.id;
|
|
95
|
+
const currentFind = document.getElementById;
|
|
96
|
+
document.getElementById = function (elementId: string) {
|
|
97
|
+
if (id === elementId) {
|
|
98
|
+
return container;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return currentFind.call(document, id);
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const acv = constGenericsEditor.adminConfigProperty;
|
|
105
|
+
const unitsConfig = (units ?? []).reduce((out, unit) => {
|
|
106
|
+
out[`custom#${unit.generic}:unit:${unit.id}`] = {
|
|
107
|
+
data: {
|
|
108
|
+
[acv]: unit.values[acv],
|
|
109
|
+
},
|
|
110
|
+
properties: {
|
|
111
|
+
[constGenericsEditor.userConfigProperty]: {
|
|
112
|
+
editor: {
|
|
113
|
+
data: { [acv]: unit.values[acv] },
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
[constGenericsEditor.infoDataProperty]: {
|
|
117
|
+
editor: {
|
|
118
|
+
data: { title: unit.title },
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
};
|
|
123
|
+
return out;
|
|
124
|
+
}, {} as Record<string, any>);
|
|
125
|
+
|
|
126
|
+
const result = (window as any).unlayer.createEditor({
|
|
127
|
+
displayMode: 'web',
|
|
128
|
+
devices: ['desktop'],
|
|
129
|
+
features: {
|
|
130
|
+
preview: false,
|
|
131
|
+
userUploads: false,
|
|
132
|
+
stockImages: false,
|
|
133
|
+
},
|
|
134
|
+
mergeTags: mergeTags?.reduce((out, tag) => {
|
|
135
|
+
out[tag.id] = { name: tag.name, value: tag.propertyPath };
|
|
136
|
+
|
|
137
|
+
return out;
|
|
138
|
+
}, {} as Record<string, { name: string; value: string }>),
|
|
139
|
+
projectId: 5713,
|
|
140
|
+
version: latest ? undefined : versions.unlayer,
|
|
141
|
+
tools: {
|
|
142
|
+
button: { enabled: false },
|
|
143
|
+
html: { enabled: false },
|
|
144
|
+
menu: { enabled: false },
|
|
145
|
+
form: { enabled: false },
|
|
146
|
+
image: { enabled: false },
|
|
147
|
+
...(noCoreTools
|
|
148
|
+
? {
|
|
149
|
+
columns: { enabled: false },
|
|
150
|
+
text: { enabled: false },
|
|
151
|
+
heading: { enabled: false },
|
|
152
|
+
divider: { enabled: false },
|
|
153
|
+
}
|
|
154
|
+
: {}),
|
|
155
|
+
...unitsConfig,
|
|
156
|
+
},
|
|
157
|
+
editor: {
|
|
158
|
+
autoSelectOnDrop: true,
|
|
159
|
+
},
|
|
160
|
+
customJS: customScripts,
|
|
161
|
+
customCSS: customStyles,
|
|
162
|
+
id,
|
|
163
|
+
fonts: {
|
|
164
|
+
showDefaultFonts: false,
|
|
165
|
+
customFonts: unlayerSupportedFonts,
|
|
166
|
+
},
|
|
167
|
+
tabs: {
|
|
168
|
+
content: {},
|
|
169
|
+
body: {},
|
|
170
|
+
blocks: { enabled: false },
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
document.getElementById = currentFind;
|
|
175
|
+
return result;
|
|
176
|
+
};
|