@servicetitan/dte-unlayer 0.154.0 → 0.156.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.
Files changed (71) hide show
  1. package/dist/display-conditions/ConditionRow.d.ts.map +1 -1
  2. package/dist/display-conditions/ConditionRow.js +111 -95
  3. package/dist/display-conditions/ConditionRow.js.map +1 -1
  4. package/dist/display-conditions/DisplayConditionModal.d.ts +3 -3
  5. package/dist/display-conditions/DisplayConditionModal.d.ts.map +1 -1
  6. package/dist/display-conditions/DisplayConditionModal.js +8 -95
  7. package/dist/display-conditions/DisplayConditionModal.js.map +1 -1
  8. package/dist/display-conditions/useConditionForms.d.ts +22 -0
  9. package/dist/display-conditions/useConditionForms.d.ts.map +1 -0
  10. package/dist/display-conditions/useConditionForms.js +110 -0
  11. package/dist/display-conditions/useConditionForms.js.map +1 -0
  12. package/dist/e-sign-offset/ESignDateSignedOffsetModal.d.ts +11 -0
  13. package/dist/e-sign-offset/ESignDateSignedOffsetModal.d.ts.map +1 -0
  14. package/dist/e-sign-offset/ESignDateSignedOffsetModal.js +192 -0
  15. package/dist/e-sign-offset/ESignDateSignedOffsetModal.js.map +1 -0
  16. package/dist/e-sign-offset/ESignOffsetRuleRow.d.ts +20 -0
  17. package/dist/e-sign-offset/ESignOffsetRuleRow.d.ts.map +1 -0
  18. package/dist/e-sign-offset/ESignOffsetRuleRow.js +87 -0
  19. package/dist/e-sign-offset/ESignOffsetRuleRow.js.map +1 -0
  20. package/dist/e-sign-offset/eSignOffsetController.d.ts +10 -0
  21. package/dist/e-sign-offset/eSignOffsetController.d.ts.map +1 -0
  22. package/dist/e-sign-offset/eSignOffsetController.js +27 -0
  23. package/dist/e-sign-offset/eSignOffsetController.js.map +1 -0
  24. package/dist/editor-core-source.d.ts +2 -2
  25. package/dist/editor-core-source.d.ts.map +1 -1
  26. package/dist/editor-core-source.js +2 -2
  27. package/dist/editor-core-source.js.map +1 -1
  28. package/dist/editor.d.ts.map +1 -1
  29. package/dist/editor.js +8 -0
  30. package/dist/editor.js.map +1 -1
  31. package/dist/image-upload-error.d.ts +5 -0
  32. package/dist/image-upload-error.d.ts.map +1 -0
  33. package/dist/image-upload-error.js +8 -0
  34. package/dist/image-upload-error.js.map +1 -0
  35. package/dist/index.d.ts +1 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +1 -0
  38. package/dist/index.js.map +1 -1
  39. package/dist/shared/const.d.ts +30 -0
  40. package/dist/shared/const.d.ts.map +1 -1
  41. package/dist/shared/const.js +5 -0
  42. package/dist/shared/const.js.map +1 -1
  43. package/dist/shared/e-sign-offset.d.ts +21 -0
  44. package/dist/shared/e-sign-offset.d.ts.map +1 -0
  45. package/dist/shared/e-sign-offset.js +130 -0
  46. package/dist/shared/e-sign-offset.js.map +1 -0
  47. package/dist/store.d.ts +1 -0
  48. package/dist/store.d.ts.map +1 -1
  49. package/dist/store.js +36 -11
  50. package/dist/store.js.map +1 -1
  51. package/dist/tools.d.ts +6 -0
  52. package/dist/tools.d.ts.map +1 -1
  53. package/dist/tools.js +21 -1
  54. package/dist/tools.js.map +1 -1
  55. package/package.json +1 -1
  56. package/src/__tests__/e-sign-offset.test.ts +281 -0
  57. package/src/__tests__/store.image-upload.test.ts +132 -0
  58. package/src/display-conditions/ConditionRow.tsx +86 -81
  59. package/src/display-conditions/DisplayConditionModal.tsx +12 -116
  60. package/src/display-conditions/useConditionForms.ts +146 -0
  61. package/src/e-sign-offset/ESignDateSignedOffsetModal.tsx +197 -0
  62. package/src/e-sign-offset/ESignOffsetRuleRow.tsx +101 -0
  63. package/src/e-sign-offset/eSignOffsetController.ts +39 -0
  64. package/src/editor-core-source.ts +2 -2
  65. package/src/editor.tsx +9 -0
  66. package/src/image-upload-error.ts +7 -0
  67. package/src/index.ts +1 -0
  68. package/src/shared/const.ts +37 -0
  69. package/src/shared/e-sign-offset.ts +173 -0
  70. package/src/store.ts +53 -8
  71. package/src/tools.ts +36 -1
package/src/editor.tsx CHANGED
@@ -8,6 +8,7 @@ import {
8
8
  useState,
9
9
  } from 'react';
10
10
  import { DisplayConditionModal } from './display-conditions/DisplayConditionModal';
11
+ import { ESignDateSignedOffsetModal } from './e-sign-offset/ESignDateSignedOffsetModal';
11
12
  import { getErrorMessage } from './log';
12
13
  import { UnlayerEditorTwin } from './shared/const';
13
14
  import { UnlayerStore, UnlayerDesignChangeInfo } from './store';
@@ -146,6 +147,14 @@ export const UnlayerEditor = forwardRef<UnlayerRef, UnlayerEditorProps>((props,
146
147
  onConditionFormSelect={props.opts.onConditionFormSelect}
147
148
  />
148
149
  )}
150
+ {!!props.opts.eSignRecipients?.length && (
151
+ <ESignDateSignedOffsetModal
152
+ portalContainer={props.opts.displayConditionModalPortalContainer}
153
+ schema={props.opts.schema}
154
+ onConditionalsOpen={props.opts.onConditionalsOpen}
155
+ onConditionFormSelect={props.opts.onConditionFormSelect}
156
+ />
157
+ )}
149
158
  </div>
150
159
  );
151
160
  });
@@ -0,0 +1,7 @@
1
+ /** Reject `onImage` with this error to show its message to the user instead of the generic upload failure text. */
2
+ export class ImageUploadError extends Error {
3
+ constructor(message: string, options?: ErrorOptions) {
4
+ super(message, options);
5
+ this.name = 'ImageUploadError';
6
+ }
7
+ }
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './editor';
2
+ export { ImageUploadError } from './image-upload-error';
2
3
  export * from './tools';
3
4
  export * from './api-core';
4
5
  export * from './api-custom-tools';
@@ -1,3 +1,4 @@
1
+ import type { DisplayConditionState } from '../display-conditions/types';
1
2
  import { SchemaObject } from './schema';
2
3
 
3
4
  export const constGenericsEditor = {
@@ -12,6 +13,41 @@ export interface UnlayerEditorESignRecipientInfo {
12
13
  displayName: string;
13
14
  }
14
15
 
16
+ export const E_SIGN_TOOL_SLUG = 'e-sign';
17
+ export const E_SIGN_DATE_SIGNED_OFFSET_TYPE = 'dateSignedOffset';
18
+ /** Must match the backend `EsignFieldSubTypes` registry key read from the e-sign tool values. */
19
+ export const E_SIGN_DATE_SIGNED_OFFSET_VALUES_KEY = 'eSignDateSignedOffset';
20
+ export const MAX_E_SIGN_OFFSET_DAYS = 365;
21
+ /** Counts the trailing unconditional rule too. */
22
+ export const MAX_E_SIGN_OFFSET_RULES = 5;
23
+
24
+ export interface ESignDateSignedOffsetRule {
25
+ days: number;
26
+ /** Always `behavior: 'show'` with exactly one condition; the backend rejects anything else. */
27
+ condition: DisplayConditionState;
28
+ }
29
+
30
+ export interface ESignDateSignedOffsetFinalRule {
31
+ days: number;
32
+ condition?: never;
33
+ }
34
+
35
+ /**
36
+ * Ordered if / else-if / else chain: the first rule whose condition matches supplies the offset,
37
+ * and the last rule is always the unconditional fallback.
38
+ */
39
+ export interface ESignDateSignedOffsetSettings {
40
+ rules:
41
+ | [ESignDateSignedOffsetFinalRule]
42
+ | [...ESignDateSignedOffsetRule[], ESignDateSignedOffsetFinalRule];
43
+ }
44
+
45
+ /** Payload of both `--esign-offset-open` (iframe to parent) and `--esign-offset-result` (back). */
46
+ export interface UnlayerEventESignOffset {
47
+ requestId: string;
48
+ value: ESignDateSignedOffsetSettings;
49
+ }
50
+
15
51
  export interface UnlayerEditorUnit {
16
52
  id: string;
17
53
  generic: string;
@@ -33,6 +69,7 @@ export interface UnlayerEventConfig {
33
69
  isSnapshotMode?: boolean;
34
70
  units?: UnlayerEditorUnit[];
35
71
  holidays?: string[];
72
+ conditionalRulesEnabled?: boolean;
36
73
  }
37
74
 
38
75
  export interface UnlayerEventRegister {
@@ -0,0 +1,173 @@
1
+ import { defaultGroup } from '../display-conditions/constants';
2
+ import {
3
+ CONDITION_OPERATORS,
4
+ type DataPointOption,
5
+ type DisplayConditionState,
6
+ type SingleCondition,
7
+ VALUE_LESS_OPERATORS,
8
+ } from '../display-conditions/types';
9
+ import {
10
+ type ESignDateSignedOffsetFinalRule,
11
+ type ESignDateSignedOffsetRule,
12
+ type ESignDateSignedOffsetSettings,
13
+ MAX_E_SIGN_OFFSET_DAYS,
14
+ MAX_E_SIGN_OFFSET_RULES,
15
+ } from './const';
16
+
17
+ const NUMERIC_VALUE_RE = /^-?(?:\d+\.?\d*|\.\d+)$/;
18
+
19
+ function isRecord(value: unknown): value is Record<string, unknown> {
20
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
21
+ }
22
+
23
+ function isConditionState(value: unknown): value is DisplayConditionState {
24
+ return isRecord(value) && Array.isArray(value.groups) && value.groups.length > 0;
25
+ }
26
+
27
+ function isConditionedRule(
28
+ rule: ESignDateSignedOffsetRule | ESignDateSignedOffsetFinalRule,
29
+ ): rule is ESignDateSignedOffsetRule {
30
+ return rule.condition !== undefined;
31
+ }
32
+
33
+ export const clampESignOffsetDays = (days: unknown) => {
34
+ if (typeof days !== 'number' || !Number.isFinite(days)) {
35
+ return 0;
36
+ }
37
+
38
+ return Math.max(Math.min(MAX_E_SIGN_OFFSET_DAYS, Math.trunc(days)), 0);
39
+ };
40
+
41
+ export const createESignOffsetSettings = (days = 0): ESignDateSignedOffsetSettings => {
42
+ return { rules: [{ days: clampESignOffsetDays(days) }] };
43
+ };
44
+
45
+ export const createESignOffsetRule = (): ESignDateSignedOffsetRule => {
46
+ return { condition: { behavior: 'show', groups: [defaultGroup()] }, days: 0 };
47
+ };
48
+
49
+ export const buildESignOffsetSettings = (
50
+ conditionedRules: ESignDateSignedOffsetRule[],
51
+ finalDays: number,
52
+ ): ESignDateSignedOffsetSettings => {
53
+ return {
54
+ rules: [
55
+ ...conditionedRules.map(rule => ({ ...rule, days: clampESignOffsetDays(rule.days) })),
56
+ { days: clampESignOffsetDays(finalDays) },
57
+ ],
58
+ };
59
+ };
60
+
61
+ export const splitESignOffsetSettings = (settings: ESignDateSignedOffsetSettings) => {
62
+ const rules: readonly (ESignDateSignedOffsetRule | ESignDateSignedOffsetFinalRule)[] =
63
+ settings.rules;
64
+
65
+ return {
66
+ conditionedRules: rules.filter(isConditionedRule),
67
+ finalDays: rules[rules.length - 1]?.days ?? 0,
68
+ };
69
+ };
70
+
71
+ export function isESignOffsetSettings(value: unknown): value is ESignDateSignedOffsetSettings {
72
+ if (!isRecord(value) || !Array.isArray(value.rules)) {
73
+ return false;
74
+ }
75
+
76
+ const rules: unknown[] = value.rules;
77
+
78
+ if (rules.length === 0 || rules.length > MAX_E_SIGN_OFFSET_RULES) {
79
+ return false;
80
+ }
81
+
82
+ return rules.every((rule, index) => {
83
+ if (!isRecord(rule) || clampESignOffsetDays(rule.days) !== rule.days) {
84
+ return false;
85
+ }
86
+
87
+ return index === rules.length - 1
88
+ ? rule.condition === undefined
89
+ : isConditionState(rule.condition);
90
+ });
91
+ }
92
+
93
+ /** Coerces whatever is stored on the tool (missing, legacy or hand-edited) into a valid chain. */
94
+ export const normalizeESignOffsetSettings = (value: unknown): ESignDateSignedOffsetSettings => {
95
+ if (isESignOffsetSettings(value)) {
96
+ return value;
97
+ }
98
+
99
+ if (!isRecord(value) || !Array.isArray(value.rules)) {
100
+ return createESignOffsetSettings();
101
+ }
102
+
103
+ const rules: unknown[] = value.rules;
104
+ const lastRule = rules[rules.length - 1];
105
+ const conditionedRules = rules
106
+ .slice(0, -1)
107
+ .flatMap(rule =>
108
+ isRecord(rule) && isConditionState(rule.condition)
109
+ ? [{ condition: rule.condition, days: clampESignOffsetDays(rule.days) }]
110
+ : [],
111
+ )
112
+ .slice(0, MAX_E_SIGN_OFFSET_RULES - 1);
113
+
114
+ return buildESignOffsetSettings(
115
+ conditionedRules,
116
+ isRecord(lastRule) ? clampESignOffsetDays(lastRule.days) : 0,
117
+ );
118
+ };
119
+
120
+ export const canAddESignOffsetRule = (rules: ESignDateSignedOffsetRule[]) => {
121
+ return rules.length < MAX_E_SIGN_OFFSET_RULES - 1;
122
+ };
123
+
124
+ export const addESignOffsetRule = (rules: ESignDateSignedOffsetRule[]) => {
125
+ return canAddESignOffsetRule(rules) ? [...rules, createESignOffsetRule()] : rules;
126
+ };
127
+
128
+ export const updateESignOffsetRule = (
129
+ rules: ESignDateSignedOffsetRule[],
130
+ index: number,
131
+ nextRule: ESignDateSignedOffsetRule,
132
+ ) => {
133
+ return rules.map((rule, ruleIndex) => (ruleIndex === index ? nextRule : rule));
134
+ };
135
+
136
+ export const removeESignOffsetRule = (rules: ESignDateSignedOffsetRule[], index: number) => {
137
+ return rules.filter((_, ruleIndex) => ruleIndex !== index);
138
+ };
139
+
140
+ export const getESignOffsetRuleCondition = (rule: ESignDateSignedOffsetRule) => {
141
+ return rule.condition.groups[0]?.conditions[0];
142
+ };
143
+
144
+ export const isCompleteESignOffsetCondition = (
145
+ condition: SingleCondition | undefined,
146
+ fieldType: DataPointOption['fieldType'],
147
+ ) => {
148
+ if (!condition?.dataPointKey) {
149
+ return false;
150
+ }
151
+
152
+ if (VALUE_LESS_OPERATORS.includes(condition.operator)) {
153
+ return true;
154
+ }
155
+
156
+ const value = condition.value.trim();
157
+
158
+ return value !== '' && (fieldType !== 'number' || NUMERIC_VALUE_RE.test(value));
159
+ };
160
+
161
+ export const getESignOffsetConditionText = (condition: SingleCondition, dataPointTitle: string) => {
162
+ const operatorLabel = (
163
+ CONDITION_OPERATORS.find(operator => operator.value === condition.operator)?.label ??
164
+ condition.operator
165
+ )
166
+ .split(' (')[0]
167
+ .replace('==', '=')
168
+ .toLowerCase();
169
+
170
+ return VALUE_LESS_OPERATORS.includes(condition.operator)
171
+ ? `${dataPointTitle} ${operatorLabel}`
172
+ : `${dataPointTitle} ${operatorLabel} ${condition.value}`;
173
+ };
package/src/store.ts CHANGED
@@ -1,8 +1,16 @@
1
+ import { emitESignOffsetRequest } from './e-sign-offset/eSignOffsetController';
2
+ import { ImageUploadError } from './image-upload-error';
1
3
  import { loadScript } from './loadScript';
2
4
  import { logUnlayerError } from './log';
3
5
  import { toUnlayerMergeTags, type UnlayerMergeTagsConfig } from './merge-tags';
4
6
  import { defaultImageValidation } from './shared/configs';
5
- import type { UnlayerEditorTwin, UnlayerEventConfig, UnlayerEventRegister } from './shared/const';
7
+ import type {
8
+ UnlayerEditorTwin,
9
+ UnlayerEventConfig,
10
+ UnlayerEventESignOffset,
11
+ UnlayerEventRegister,
12
+ } from './shared/const';
13
+ import { normalizeESignOffsetSettings } from './shared/e-sign-offset';
6
14
  import { unlayerSupportedFonts } from './shared/fonts';
7
15
  import {
8
16
  FormFieldInfo,
@@ -12,7 +20,11 @@ import {
12
20
  } from './shared/forms';
13
21
  import { schemaBuildMap, schemaIsDate } from './shared/schema';
14
22
  import { unlayerToolsParseTwinKey } from './shared/tools';
15
- import { unlayerToolsDedupeInstanceIds, unlayerToolsIterate } from './tools';
23
+ import {
24
+ unlayerToolsDedupeInstanceIds,
25
+ unlayerToolsIterate,
26
+ unlayerToolsNormalizeESignOffsets,
27
+ } from './tools';
16
28
  import {
17
29
  createUnlayerEditor,
18
30
  DesignUpdatedEventType,
@@ -220,18 +232,28 @@ export class UnlayerStore {
220
232
  .map(field => field.fullKey),
221
233
  );
222
234
 
223
- this.props.eSignFieldTypes = ['Signature', 'Initials', 'Date Signed', 'Full Name'];
235
+ this.props.eSignFieldTypes = [
236
+ 'Signature',
237
+ 'Initials',
238
+ 'Date Signed',
239
+ 'Date Signed Offset',
240
+ 'Full Name',
241
+ ];
224
242
 
225
243
  this.unlayerRef = {
226
244
  loadDesign: design => {
227
245
  this.editor?.loadDesign(design);
228
246
  },
229
247
  saveDesign: cb => {
230
- this.editor?.saveDesign(cb);
248
+ this.editor?.saveDesign(design => {
249
+ unlayerToolsNormalizeESignOffsets(design);
250
+ cb(design);
251
+ });
231
252
  },
232
253
  exportHtml: cb => {
233
254
  this.editor?.exportHtml(data => {
234
255
  const result = ensureChunksFonts(data);
256
+ unlayerToolsNormalizeESignOffsets(result?.design);
235
257
  result.demoData = this.buildCalculatedFieldDemoData(result.design);
236
258
  cb(result);
237
259
  });
@@ -487,6 +509,8 @@ export class UnlayerStore {
487
509
  genericConfigMode: this.props.genericConfigMode,
488
510
  isSnapshotMode: this.props.isSnapshotMode,
489
511
  holidays: this.props.holidays,
512
+ conditionalRulesEnabled:
513
+ !!this.props.displayConditions || !!this.props.onConditionalsOpen,
490
514
  };
491
515
 
492
516
  this.sendMessage('--config', JSON.parse(JSON.stringify(configData)));
@@ -494,6 +518,8 @@ export class UnlayerStore {
494
518
  this.onFormSelectCB?.(data?.formId);
495
519
  } else if (type === '--calc-field-open') {
496
520
  this.onCalcFieldOpenCB?.(data?.usedFormIds ?? []);
521
+ } else if (type === '--esign-offset-open') {
522
+ this.openESignOffsetRules(data);
497
523
  } else if (type === '--calc-field-select') {
498
524
  if (this.onCalcFieldSelectCB) {
499
525
  this.onCalcFieldSelectCB(data?.fieldKeys ?? []);
@@ -538,6 +564,22 @@ export class UnlayerStore {
538
564
  this.onMessageCB?.(type, data);
539
565
  };
540
566
 
567
+ private openESignOffsetRules = (data?: Partial<UnlayerEventESignOffset>) => {
568
+ const requestId = data?.requestId;
569
+
570
+ if (!requestId) {
571
+ return;
572
+ }
573
+
574
+ emitESignOffsetRequest({
575
+ value: normalizeESignOffsetSettings(data.value),
576
+ done: value => {
577
+ const result: UnlayerEventESignOffset = { requestId, value };
578
+ this.sendMessage('--esign-offset-result', JSON.parse(JSON.stringify(result)));
579
+ },
580
+ });
581
+ };
582
+
541
583
  private updateFormFieldSamples = (formId: number, fields: FormFieldInfo[]) => {
542
584
  fields.forEach((field, index) => {
543
585
  const normalizedFieldId = String(field.id ?? '').replaceAll('-', '');
@@ -679,8 +721,10 @@ export class UnlayerStore {
679
721
  return;
680
722
  }
681
723
 
682
- done({ progress: 0 });
683
-
724
+ /*
725
+ * Unlayer only leaves its "uploading" state when `done` receives a url, so `done` must not be
726
+ * called before the upload succeeds or after it fails, otherwise the image widget gets stuck.
727
+ */
684
728
  try {
685
729
  const { url } = await this.onImageCB(file);
686
730
  done({ progress: 100, url });
@@ -688,9 +732,10 @@ export class UnlayerStore {
688
732
  logUnlayerError('Image upload failed', error);
689
733
  this.onErrorCB?.(
690
734
  'Image upload failed',
691
- 'Something went wrong while uploading the image. Please try again or select another image.',
735
+ error instanceof ImageUploadError
736
+ ? error.message
737
+ : 'Something went wrong while uploading the image. Please try again or select another image.',
692
738
  );
693
- done({ progress: 100 });
694
739
  }
695
740
  };
696
741
 
package/src/tools.ts CHANGED
@@ -1,4 +1,11 @@
1
- import { constGenericsEditor, UnlayerToolMetaData } from './shared/const';
1
+ import {
2
+ constGenericsEditor,
3
+ E_SIGN_DATE_SIGNED_OFFSET_TYPE,
4
+ E_SIGN_DATE_SIGNED_OFFSET_VALUES_KEY,
5
+ E_SIGN_TOOL_SLUG,
6
+ UnlayerToolMetaData,
7
+ } from './shared/const';
8
+ import { isESignOffsetSettings, normalizeESignOffsetSettings } from './shared/e-sign-offset';
2
9
  import { editIconSvg } from './shared/edit-icon';
3
10
  import { generateInstanceId, INSTANCE_ID_TOOL_SLUGS } from './shared/instance-id';
4
11
  import { unlayerToolsParseUnitKey } from './shared/tools';
@@ -253,6 +260,34 @@ export const unlayerToolsDedupeInstanceIds = (
253
260
  return hasChanges;
254
261
  };
255
262
 
263
+ /**
264
+ * Gives every "Date Signed Offset" e-sign placement valid settings. Unlayer never applies an
265
+ * option's default to placements saved before the option existed, and the backend rejects a
266
+ * design whose dateSignedOffset recipient has no settings.
267
+ */
268
+ export const unlayerToolsNormalizeESignOffsets = (design: UnlayerDesignFormat): boolean => {
269
+ let hasChanges = false;
270
+
271
+ unlayerToolsIterateCustom(design, tool => {
272
+ if (
273
+ tool.slug !== E_SIGN_TOOL_SLUG ||
274
+ tool.values?.eSignFieldType !== E_SIGN_DATE_SIGNED_OFFSET_TYPE
275
+ ) {
276
+ return;
277
+ }
278
+
279
+ const settings = tool.values[E_SIGN_DATE_SIGNED_OFFSET_VALUES_KEY];
280
+
281
+ if (!isESignOffsetSettings(settings)) {
282
+ tool.values[E_SIGN_DATE_SIGNED_OFFSET_VALUES_KEY] =
283
+ normalizeESignOffsetSettings(settings);
284
+ hasChanges = true;
285
+ }
286
+ });
287
+
288
+ return hasChanges;
289
+ };
290
+
256
291
  export const unlayerToolsBuildDesign = (tools: UnlayerDesignTool[]): UnlayerDesignFormat => {
257
292
  const design = unlayerGetDefaultDesign();
258
293