@servicetitan/dte-unlayer 0.153.0 → 0.154.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/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/merge-tags.d.ts +6 -10
- package/dist/merge-tags.d.ts.map +1 -1
- package/dist/merge-tags.js +35 -44
- package/dist/merge-tags.js.map +1 -1
- package/dist/shared/instance-id.d.ts +13 -0
- package/dist/shared/instance-id.d.ts.map +1 -0
- package/dist/shared/instance-id.js +22 -0
- package/dist/shared/instance-id.js.map +1 -0
- package/dist/store.d.ts +14 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +51 -3
- package/dist/store.js.map +1 -1
- package/dist/tools.d.ts +12 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +47 -0
- package/dist/tools.js.map +1 -1
- package/dist/unlayer-interface.d.ts +11 -1
- package/dist/unlayer-interface.d.ts.map +1 -1
- package/dist/unlayer-interface.js.map +1 -1
- package/dist/unlayer.d.ts.map +1 -1
- package/dist/unlayer.js +5 -3
- package/dist/unlayer.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/merge-tags.test.ts +98 -76
- package/src/__tests__/store.merge-tags.test.ts +186 -0
- package/src/index.ts +1 -2
- package/src/merge-tags.ts +41 -60
- package/src/shared/instance-id.ts +23 -0
- package/src/store.ts +62 -2
- package/src/tools.ts +51 -0
- package/src/unlayer-interface.tsx +11 -1
- package/src/unlayer.tsx +5 -3
package/src/store.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { loadScript } from './loadScript';
|
|
2
2
|
import { logUnlayerError } from './log';
|
|
3
|
+
import { toUnlayerMergeTags, type UnlayerMergeTagsConfig } from './merge-tags';
|
|
3
4
|
import { defaultImageValidation } from './shared/configs';
|
|
4
5
|
import type { UnlayerEditorTwin, UnlayerEventConfig, UnlayerEventRegister } from './shared/const';
|
|
5
6
|
import { unlayerSupportedFonts } from './shared/fonts';
|
|
@@ -11,14 +12,19 @@ import {
|
|
|
11
12
|
} from './shared/forms';
|
|
12
13
|
import { schemaBuildMap, schemaIsDate } from './shared/schema';
|
|
13
14
|
import { unlayerToolsParseTwinKey } from './shared/tools';
|
|
14
|
-
import { unlayerToolsIterate } from './tools';
|
|
15
|
+
import { unlayerToolsDedupeInstanceIds, unlayerToolsIterate } from './tools';
|
|
15
16
|
import {
|
|
16
17
|
createUnlayerEditor,
|
|
17
18
|
DesignUpdatedEventType,
|
|
18
19
|
EventDesignUpdated,
|
|
19
20
|
Unlayer,
|
|
20
21
|
} from './unlayer';
|
|
21
|
-
import {
|
|
22
|
+
import {
|
|
23
|
+
CreateUnlayerEditorProps,
|
|
24
|
+
UnlayerDesignFormat,
|
|
25
|
+
UnlayerEditorMergeTagInfo,
|
|
26
|
+
UnlayerRef,
|
|
27
|
+
} from './unlayer-interface';
|
|
22
28
|
|
|
23
29
|
const defaultScriptUrl = 'https://editor.unlayer.com/embed.js?2';
|
|
24
30
|
const UNLAYER_TOOLS_READY_TIMEOUT_MS = 30000;
|
|
@@ -191,6 +197,9 @@ export class UnlayerStore {
|
|
|
191
197
|
private toolsReadyWatchdogId?: number;
|
|
192
198
|
private formFieldsByFormId: Record<number, FormFieldInfo[]> = {};
|
|
193
199
|
private formFieldSamples: Record<string, unknown> = {};
|
|
200
|
+
private isEditorReady = false;
|
|
201
|
+
private isMergeTagsApplied = false;
|
|
202
|
+
private mergeTagsConfig?: UnlayerMergeTagsConfig;
|
|
194
203
|
|
|
195
204
|
private onMessageCB?: (type: string, data: any) => void;
|
|
196
205
|
private onChangeCB?: (info: UnlayerDesignChangeInfo) => void;
|
|
@@ -236,6 +245,9 @@ export class UnlayerStore {
|
|
|
236
245
|
sendCalcFieldLabels: labels => {
|
|
237
246
|
this.sendCalcFieldLabels(labels);
|
|
238
247
|
},
|
|
248
|
+
setMergeTags: tags => {
|
|
249
|
+
this.setMergeTags(tags);
|
|
250
|
+
},
|
|
239
251
|
};
|
|
240
252
|
}
|
|
241
253
|
|
|
@@ -256,6 +268,9 @@ export class UnlayerStore {
|
|
|
256
268
|
}
|
|
257
269
|
|
|
258
270
|
this.editor = createUnlayerEditor(container, this.props);
|
|
271
|
+
// The host may already have pushed a newer set through `setMergeTags`; keep it.
|
|
272
|
+
this.mergeTagsConfig ??= toUnlayerMergeTags(this.props.mergeTags);
|
|
273
|
+
this.editor.addEventListener('editor:ready', this.onEditorReady);
|
|
259
274
|
this.editor.addEventListener('design:loaded', this.onDesignLoaded);
|
|
260
275
|
this.editor.addEventListener('design:updated', this.onDesignUpdated);
|
|
261
276
|
this.editor.registerCallback('image', this.uploadImage);
|
|
@@ -280,6 +295,7 @@ export class UnlayerStore {
|
|
|
280
295
|
window.removeEventListener('message', this.onPostMessage);
|
|
281
296
|
|
|
282
297
|
if (this.editor) {
|
|
298
|
+
this.editor.removeEventListener('editor:ready', this.onEditorReady);
|
|
283
299
|
this.editor.removeEventListener('design:loaded', this.onDesignLoaded);
|
|
284
300
|
this.editor.removeEventListener('design:updated', this.onDesignUpdated);
|
|
285
301
|
this.editor.unregisterCallback('image', this.uploadImage);
|
|
@@ -355,7 +371,46 @@ export class UnlayerStore {
|
|
|
355
371
|
this.sendMessage('--calc-field-labels', { labels });
|
|
356
372
|
};
|
|
357
373
|
|
|
374
|
+
/**
|
|
375
|
+
* Replaces the editor's merge tag menu. Nested groups passed to `createEditor` stop DTE
|
|
376
|
+
* custom tools from registering, so init only carries the flat shape and the grouped
|
|
377
|
+
* config is applied here once the editor is ready. A call before that (including the
|
|
378
|
+
* initial props) is parked; a later call replaces it. A failed apply is retried on the
|
|
379
|
+
* next `design:loaded`.
|
|
380
|
+
*/
|
|
381
|
+
setMergeTags = (tags: UnlayerEditorMergeTagInfo[] | undefined) => {
|
|
382
|
+
this.mergeTagsConfig = toUnlayerMergeTags(tags);
|
|
383
|
+
this.isMergeTagsApplied = false;
|
|
384
|
+
this.applyMergeTags();
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
private applyMergeTags = () => {
|
|
388
|
+
if (
|
|
389
|
+
!this.editor ||
|
|
390
|
+
!this.isEditorReady ||
|
|
391
|
+
this.isMergeTagsApplied ||
|
|
392
|
+
!this.mergeTagsConfig
|
|
393
|
+
) {
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
try {
|
|
398
|
+
this.editor.setMergeTags(this.mergeTagsConfig);
|
|
399
|
+
this.isMergeTagsApplied = true;
|
|
400
|
+
} catch (error: unknown) {
|
|
401
|
+
logUnlayerError('Failed to apply merge tags', error);
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
private onEditorReady = () => {
|
|
406
|
+
this.isEditorReady = true;
|
|
407
|
+
this.applyMergeTags();
|
|
408
|
+
};
|
|
409
|
+
|
|
358
410
|
private onDesignLoaded = () => {
|
|
411
|
+
// A loaded design means the editor is up even if `editor:ready` never reached us.
|
|
412
|
+
this.onEditorReady();
|
|
413
|
+
|
|
359
414
|
if (!this.hasDesign) {
|
|
360
415
|
this.hasDesign = true;
|
|
361
416
|
this.editor?.setBodyValues({
|
|
@@ -391,6 +446,11 @@ export class UnlayerStore {
|
|
|
391
446
|
}
|
|
392
447
|
});
|
|
393
448
|
|
|
449
|
+
// Duplicated contents/rows carry the original's instance GUIDs; give copies new ones.
|
|
450
|
+
if (unlayerToolsDedupeInstanceIds(data.design, event.item?.values?._meta?.htmlID)) {
|
|
451
|
+
hasChanges = true;
|
|
452
|
+
}
|
|
453
|
+
|
|
394
454
|
if (hasChanges) {
|
|
395
455
|
this.setDesign(data.design);
|
|
396
456
|
}
|
package/src/tools.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { constGenericsEditor, UnlayerToolMetaData } from './shared/const';
|
|
2
2
|
import { editIconSvg } from './shared/edit-icon';
|
|
3
|
+
import { generateInstanceId, INSTANCE_ID_TOOL_SLUGS } from './shared/instance-id';
|
|
3
4
|
import { unlayerToolsParseUnitKey } from './shared/tools';
|
|
4
5
|
import { versions } from './unlayer';
|
|
5
6
|
|
|
@@ -202,6 +203,56 @@ export const unlayerToolsListCustom = (design: UnlayerDesignFormat): UnlayerDesi
|
|
|
202
203
|
return tools;
|
|
203
204
|
};
|
|
204
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Makes `values.id` unique across all instance-id tools (see `INSTANCE_ID_TOOL_SLUGS`)
|
|
208
|
+
* in the design. Duplicating content/rows in Unlayer copies the values verbatim, so
|
|
209
|
+
* every copy ends up with the original's GUID; this gives each copy a fresh one.
|
|
210
|
+
*
|
|
211
|
+
* Of the contents sharing an id, the one that keeps it is the first in document
|
|
212
|
+
* order that is not the just-added content (`addedHtmlID`), so the original always
|
|
213
|
+
* wins over its duplicate regardless of where the copy was inserted.
|
|
214
|
+
*
|
|
215
|
+
* @returns `true` when at least one id was regenerated.
|
|
216
|
+
*/
|
|
217
|
+
export const unlayerToolsDedupeInstanceIds = (
|
|
218
|
+
design: UnlayerDesignFormat,
|
|
219
|
+
addedHtmlID?: string
|
|
220
|
+
): boolean => {
|
|
221
|
+
const byId = new Map<string, UnlayerDesignCustomTool[]>();
|
|
222
|
+
|
|
223
|
+
unlayerToolsIterateCustom(design, tool => {
|
|
224
|
+
const id = tool.values?.id;
|
|
225
|
+
|
|
226
|
+
if (INSTANCE_ID_TOOL_SLUGS.includes(tool.slug) && typeof id === 'string' && id) {
|
|
227
|
+
const key = `${tool.slug}|${id}`;
|
|
228
|
+
byId.set(key, [...(byId.get(key) ?? []), tool]);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
let hasChanges = false;
|
|
233
|
+
|
|
234
|
+
byId.forEach(tools => {
|
|
235
|
+
if (tools.length < 2) {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const keeper = tools.find(tool => tool.values?._meta?.htmlID !== addedHtmlID) ?? tools[0];
|
|
240
|
+
|
|
241
|
+
for (const tool of tools) {
|
|
242
|
+
if (tool !== keeper) {
|
|
243
|
+
/*
|
|
244
|
+
* If no id can be generated the copy is left without one, which is still
|
|
245
|
+
* better than two instances bound to the same image.
|
|
246
|
+
*/
|
|
247
|
+
tool.values.id = generateInstanceId();
|
|
248
|
+
hasChanges = true;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
return hasChanges;
|
|
254
|
+
};
|
|
255
|
+
|
|
205
256
|
export const unlayerToolsBuildDesign = (tools: UnlayerDesignTool[]): UnlayerDesignFormat => {
|
|
206
257
|
const design = unlayerGetDefaultDesign();
|
|
207
258
|
|
|
@@ -45,13 +45,23 @@ export interface UnlayerRef {
|
|
|
45
45
|
sendFormList(forms: FormInfo[]): void;
|
|
46
46
|
sendFormFields(formId: number, fields: FormFieldInfo[]): void;
|
|
47
47
|
sendCalcFieldLabels(labels: Record<string, string>): void;
|
|
48
|
+
/**
|
|
49
|
+
* Replaces the editor's merge tag menu with `tags` (grouped). Safe to call before the editor is
|
|
50
|
+
* ready — the tags are applied once it is. Lets hosts add tags that finish loading after init
|
|
51
|
+
* (e.g. form fields) without remounting the editor.
|
|
52
|
+
*/
|
|
53
|
+
setMergeTags(tags: UnlayerEditorMergeTagInfo[] | undefined): void;
|
|
48
54
|
}
|
|
49
55
|
|
|
50
56
|
export interface UnlayerEditorMergeTagInfo {
|
|
51
57
|
id: string;
|
|
52
58
|
name: string;
|
|
53
59
|
propertyPath: string;
|
|
54
|
-
|
|
60
|
+
/**
|
|
61
|
+
* Submenu the tag is listed under. A string is a single submenu (`'Custom Fields'`);
|
|
62
|
+
* an array nests submenus in order (`['Forms', 'Customer Intake']` → Forms ▸ Customer Intake ▸ tag).
|
|
63
|
+
*/
|
|
64
|
+
group?: string | string[];
|
|
55
65
|
}
|
|
56
66
|
|
|
57
67
|
export interface UnlayerEditorCustomTool {
|
package/src/unlayer.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { emitDisplayCondition } from './display-conditions/displayConditionController';
|
|
2
2
|
import { editorCoreScript, editorCoreStyles, editorCoreTools } from './editor-core';
|
|
3
3
|
import { logUnlayerError } from './log';
|
|
4
|
-
import {
|
|
4
|
+
import { toUnlayerMergeTags } from './merge-tags';
|
|
5
5
|
import { constGenericsEditor } from './shared/const';
|
|
6
6
|
import { unlayerSupportedFonts } from './shared/fonts';
|
|
7
7
|
import {
|
|
@@ -299,6 +299,10 @@ export const createUnlayerEditor = (
|
|
|
299
299
|
tables: true,
|
|
300
300
|
},
|
|
301
301
|
},
|
|
302
|
+
/*
|
|
303
|
+
* Flat only: nested groups here break custom tool registration. UnlayerStore applies
|
|
304
|
+
* the grouped config via setMergeTags once the editor is ready.
|
|
305
|
+
*/
|
|
302
306
|
mergeTags: toUnlayerMergeTags(mergeTags, { groups: false }),
|
|
303
307
|
projectId: 5713,
|
|
304
308
|
version: latest ? undefined : versions.unlayer,
|
|
@@ -362,8 +366,6 @@ export const createUnlayerEditor = (
|
|
|
362
366
|
document.getElementById = currentFind;
|
|
363
367
|
}
|
|
364
368
|
|
|
365
|
-
scheduleUnlayerMergeTags(result, mergeTags);
|
|
366
|
-
|
|
367
369
|
if (displayConditions) {
|
|
368
370
|
result.registerCallback(
|
|
369
371
|
'displayCondition',
|