@templatical/types 0.10.0 → 0.10.2

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.js CHANGED
@@ -1,697 +1,596 @@
1
- // src/blocks.ts
2
- var HEADING_LEVEL_FONT_SIZE = {
3
- 1: 36,
4
- 2: 28,
5
- 3: 22,
6
- 4: 18
1
+ //#region src/blocks.ts
2
+ const HEADING_LEVEL_FONT_SIZE = {
3
+ 1: 36,
4
+ 2: 28,
5
+ 3: 22,
6
+ 4: 18
7
7
  };
8
-
9
- // src/guards.ts
8
+ //#endregion
9
+ //#region src/guards.ts
10
10
  function isSection(block) {
11
- return block.type === "section";
11
+ return block.type === "section";
12
12
  }
13
13
  function isTitle(block) {
14
- return block.type === "title";
14
+ return block.type === "title";
15
15
  }
16
16
  function isParagraph(block) {
17
- return block.type === "paragraph";
17
+ return block.type === "paragraph";
18
18
  }
19
19
  function isImage(block) {
20
- return block.type === "image";
20
+ return block.type === "image";
21
21
  }
22
22
  function isButton(block) {
23
- return block.type === "button";
23
+ return block.type === "button";
24
24
  }
25
25
  function isDivider(block) {
26
- return block.type === "divider";
26
+ return block.type === "divider";
27
27
  }
28
28
  function isVideo(block) {
29
- return block.type === "video";
29
+ return block.type === "video";
30
30
  }
31
31
  function isSocialIcons(block) {
32
- return block.type === "social";
32
+ return block.type === "social";
33
33
  }
34
34
  function isSpacer(block) {
35
- return block.type === "spacer";
35
+ return block.type === "spacer";
36
36
  }
37
37
  function isHtml(block) {
38
- return block.type === "html";
38
+ return block.type === "html";
39
39
  }
40
40
  function isMenu(block) {
41
- return block.type === "menu";
41
+ return block.type === "menu";
42
42
  }
43
43
  function isTable(block) {
44
- return block.type === "table";
44
+ return block.type === "table";
45
45
  }
46
46
  function isCountdown(block) {
47
- return block.type === "countdown";
47
+ return block.type === "countdown";
48
48
  }
49
49
  function isCustomBlock(block) {
50
- return block.type === "custom";
51
- }
52
-
53
- // src/defaults.ts
54
- var TITLE_BLOCK_DEFAULTS = {
55
- content: "<p>Enter your title</p>",
56
- level: 2,
57
- color: "#1a1a1a",
58
- textAlign: "left"
59
- };
60
- var PARAGRAPH_BLOCK_DEFAULTS = {
61
- content: "<p>Enter your text here</p>"
62
- };
63
- var IMAGE_BLOCK_DEFAULTS = {
64
- src: "",
65
- alt: "",
66
- width: "full",
67
- align: "center"
50
+ return block.type === "custom";
51
+ }
52
+ //#endregion
53
+ //#region src/defaults.ts
54
+ const TITLE_BLOCK_DEFAULTS = {
55
+ content: "<p>Enter your title</p>",
56
+ level: 2,
57
+ color: "#1a1a1a",
58
+ textAlign: "left"
68
59
  };
69
- var BUTTON_BLOCK_DEFAULTS = {
70
- text: "Click Here",
71
- url: "",
72
- backgroundColor: "#333333",
73
- textColor: "#ffffff",
74
- borderRadius: 6,
75
- fontSize: 15,
76
- buttonPadding: { top: 12, right: 24, bottom: 12, left: 24 }
60
+ const PARAGRAPH_BLOCK_DEFAULTS = { content: "<p>Enter your text here</p>" };
61
+ const IMAGE_BLOCK_DEFAULTS = {
62
+ src: "",
63
+ alt: "",
64
+ width: "full",
65
+ align: "center"
77
66
  };
78
- var DIVIDER_BLOCK_DEFAULTS = {
79
- lineStyle: "solid",
80
- color: "#e0e0e0",
81
- thickness: 1,
82
- width: "full"
67
+ const BUTTON_BLOCK_DEFAULTS = {
68
+ text: "Click Here",
69
+ url: "",
70
+ backgroundColor: "#333333",
71
+ textColor: "#ffffff",
72
+ borderRadius: 6,
73
+ fontSize: 15,
74
+ buttonPadding: {
75
+ top: 12,
76
+ right: 24,
77
+ bottom: 12,
78
+ left: 24
79
+ }
83
80
  };
84
- var SECTION_BLOCK_DEFAULTS = {
85
- columns: "1"
81
+ const DIVIDER_BLOCK_DEFAULTS = {
82
+ lineStyle: "solid",
83
+ color: "#e0e0e0",
84
+ thickness: 1,
85
+ width: "full"
86
86
  };
87
- var VIDEO_BLOCK_DEFAULTS = {
88
- url: "",
89
- thumbnailUrl: "",
90
- alt: "Video",
91
- width: "full",
92
- align: "center"
87
+ const SECTION_BLOCK_DEFAULTS = { columns: "1" };
88
+ const VIDEO_BLOCK_DEFAULTS = {
89
+ url: "",
90
+ thumbnailUrl: "",
91
+ alt: "Video",
92
+ width: "full",
93
+ align: "center"
93
94
  };
94
- var SOCIAL_ICONS_BLOCK_DEFAULTS = {
95
- iconStyle: "solid",
96
- iconSize: "medium",
97
- spacing: 10,
98
- align: "center"
95
+ const SOCIAL_ICONS_BLOCK_DEFAULTS = {
96
+ iconStyle: "solid",
97
+ iconSize: "medium",
98
+ spacing: 10,
99
+ align: "center"
99
100
  };
100
- var SPACER_BLOCK_DEFAULTS = {
101
- height: 24
101
+ const SPACER_BLOCK_DEFAULTS = { height: 24 };
102
+ const HTML_BLOCK_DEFAULTS = { content: "" };
103
+ const MENU_BLOCK_DEFAULTS = {
104
+ fontSize: 15,
105
+ color: "#1a1a1a",
106
+ textAlign: "center",
107
+ separator: "|",
108
+ separatorColor: "#e0e0e0",
109
+ spacing: 10
102
110
  };
103
- var HTML_BLOCK_DEFAULTS = {
104
- content: ""
111
+ const TABLE_BLOCK_DEFAULTS = {
112
+ hasHeaderRow: true,
113
+ borderColor: "#e0e0e0",
114
+ borderWidth: 1,
115
+ cellPadding: 8,
116
+ fontSize: 15,
117
+ color: "#1a1a1a",
118
+ textAlign: "left"
105
119
  };
106
- var MENU_BLOCK_DEFAULTS = {
107
- fontSize: 15,
108
- color: "#1a1a1a",
109
- textAlign: "center",
110
- separator: "|",
111
- separatorColor: "#e0e0e0",
112
- spacing: 10
120
+ const COUNTDOWN_BLOCK_DEFAULTS = {
121
+ targetDate: "",
122
+ timezone: "UTC",
123
+ showDays: true,
124
+ showHours: true,
125
+ showMinutes: true,
126
+ showSeconds: true,
127
+ separator: ":",
128
+ digitFontSize: 32,
129
+ digitColor: "#1a1a1a",
130
+ labelColor: "#6b7280",
131
+ labelFontSize: 12,
132
+ backgroundColor: "#ffffff",
133
+ labelDays: "Days",
134
+ labelHours: "Hours",
135
+ labelMinutes: "Minutes",
136
+ labelSeconds: "Seconds",
137
+ expiredMessage: "This offer has expired",
138
+ expiredImageUrl: "",
139
+ hideOnExpiry: false
113
140
  };
114
- var TABLE_BLOCK_DEFAULTS = {
115
- hasHeaderRow: true,
116
- borderColor: "#e0e0e0",
117
- borderWidth: 1,
118
- cellPadding: 8,
119
- fontSize: 15,
120
- color: "#1a1a1a",
121
- textAlign: "left"
141
+ const DEFAULT_BLOCK_DEFAULTS = {
142
+ title: TITLE_BLOCK_DEFAULTS,
143
+ paragraph: PARAGRAPH_BLOCK_DEFAULTS,
144
+ image: IMAGE_BLOCK_DEFAULTS,
145
+ button: BUTTON_BLOCK_DEFAULTS,
146
+ divider: DIVIDER_BLOCK_DEFAULTS,
147
+ section: SECTION_BLOCK_DEFAULTS,
148
+ video: VIDEO_BLOCK_DEFAULTS,
149
+ social: SOCIAL_ICONS_BLOCK_DEFAULTS,
150
+ spacer: SPACER_BLOCK_DEFAULTS,
151
+ html: HTML_BLOCK_DEFAULTS,
152
+ menu: MENU_BLOCK_DEFAULTS,
153
+ table: TABLE_BLOCK_DEFAULTS,
154
+ countdown: COUNTDOWN_BLOCK_DEFAULTS
122
155
  };
123
- var COUNTDOWN_BLOCK_DEFAULTS = {
124
- targetDate: "",
125
- timezone: "UTC",
126
- showDays: true,
127
- showHours: true,
128
- showMinutes: true,
129
- showSeconds: true,
130
- separator: ":",
131
- digitFontSize: 32,
132
- digitColor: "#1a1a1a",
133
- labelColor: "#6b7280",
134
- labelFontSize: 12,
135
- backgroundColor: "#ffffff",
136
- labelDays: "Days",
137
- labelHours: "Hours",
138
- labelMinutes: "Minutes",
139
- labelSeconds: "Seconds",
140
- expiredMessage: "This offer has expired",
141
- expiredImageUrl: "",
142
- hideOnExpiry: false
143
- };
144
- var DEFAULT_BLOCK_DEFAULTS = {
145
- title: TITLE_BLOCK_DEFAULTS,
146
- paragraph: PARAGRAPH_BLOCK_DEFAULTS,
147
- image: IMAGE_BLOCK_DEFAULTS,
148
- button: BUTTON_BLOCK_DEFAULTS,
149
- divider: DIVIDER_BLOCK_DEFAULTS,
150
- section: SECTION_BLOCK_DEFAULTS,
151
- video: VIDEO_BLOCK_DEFAULTS,
152
- social: SOCIAL_ICONS_BLOCK_DEFAULTS,
153
- spacer: SPACER_BLOCK_DEFAULTS,
154
- html: HTML_BLOCK_DEFAULTS,
155
- menu: MENU_BLOCK_DEFAULTS,
156
- table: TABLE_BLOCK_DEFAULTS,
157
- countdown: COUNTDOWN_BLOCK_DEFAULTS
158
- };
159
- var DEFAULT_TEMPLATE_DEFAULTS = {
160
- width: 600,
161
- backgroundColor: "#ffffff",
162
- fontFamily: "Arial",
163
- locale: "en"
156
+ const DEFAULT_TEMPLATE_DEFAULTS = {
157
+ width: 600,
158
+ backgroundColor: "#ffffff",
159
+ fontFamily: "Arial",
160
+ locale: "en"
164
161
  };
165
162
  function isPlainObject(value) {
166
- return typeof value === "object" && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
163
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
167
164
  }
168
165
  function deepMergeDefaults(base, overrides) {
169
- const result = { ...base };
170
- for (const key of Object.keys(overrides)) {
171
- const baseVal = base[key];
172
- const overrideVal = overrides[key];
173
- if (overrideVal === void 0) {
174
- continue;
175
- }
176
- if (isPlainObject(baseVal) && isPlainObject(overrideVal)) {
177
- result[key] = deepMergeDefaults(
178
- baseVal,
179
- overrideVal
180
- );
181
- } else {
182
- result[key] = overrideVal;
183
- }
184
- }
185
- return result;
186
- }
187
-
188
- // src/template.ts
166
+ const result = { ...base };
167
+ for (const key of Object.keys(overrides)) {
168
+ const baseVal = base[key];
169
+ const overrideVal = overrides[key];
170
+ if (overrideVal === void 0) continue;
171
+ if (isPlainObject(baseVal) && isPlainObject(overrideVal)) result[key] = deepMergeDefaults(baseVal, overrideVal);
172
+ else result[key] = overrideVal;
173
+ }
174
+ return result;
175
+ }
176
+ //#endregion
177
+ //#region src/template.ts
189
178
  function createDefaultTemplateContent(defaultFontFamily = "Arial", templateDefaults) {
190
- return {
191
- blocks: [],
192
- settings: {
193
- ...DEFAULT_TEMPLATE_DEFAULTS,
194
- fontFamily: defaultFontFamily,
195
- ...templateDefaults
196
- }
197
- };
198
- }
199
-
200
- // src/factory.ts
179
+ return {
180
+ blocks: [],
181
+ settings: {
182
+ ...DEFAULT_TEMPLATE_DEFAULTS,
183
+ fontFamily: defaultFontFamily,
184
+ ...templateDefaults
185
+ }
186
+ };
187
+ }
188
+ //#endregion
189
+ //#region src/factory.ts
201
190
  function applyDefaults(base, partial) {
202
- if (!partial || Object.keys(partial).length === 0) return base;
203
- return deepMergeDefaults(base, partial);
191
+ if (!partial || Object.keys(partial).length === 0) return base;
192
+ return deepMergeDefaults(base, partial);
204
193
  }
205
194
  function generateId() {
206
- return crypto.randomUUID();
195
+ return crypto.randomUUID();
207
196
  }
208
197
  function createDefaultSpacing(value = 0) {
209
- return { top: value, right: value, bottom: value, left: value };
198
+ return {
199
+ top: value,
200
+ right: value,
201
+ bottom: value,
202
+ left: value
203
+ };
210
204
  }
211
205
  function createDefaultStyles(padding = 10) {
212
- return {
213
- padding: createDefaultSpacing(padding)
214
- };
206
+ return { padding: createDefaultSpacing(padding) };
215
207
  }
216
208
  function createTitleBlock(partial = {}) {
217
- const base = {
218
- id: generateId(),
219
- type: "title",
220
- ...TITLE_BLOCK_DEFAULTS,
221
- styles: createDefaultStyles()
222
- };
223
- return applyDefaults(base, partial);
209
+ return applyDefaults({
210
+ id: generateId(),
211
+ type: "title",
212
+ ...TITLE_BLOCK_DEFAULTS,
213
+ styles: createDefaultStyles()
214
+ }, partial);
224
215
  }
225
216
  function createParagraphBlock(partial = {}) {
226
- const base = {
227
- id: generateId(),
228
- type: "paragraph",
229
- ...PARAGRAPH_BLOCK_DEFAULTS,
230
- styles: createDefaultStyles()
231
- };
232
- return applyDefaults(base, partial);
217
+ return applyDefaults({
218
+ id: generateId(),
219
+ type: "paragraph",
220
+ ...PARAGRAPH_BLOCK_DEFAULTS,
221
+ styles: createDefaultStyles()
222
+ }, partial);
233
223
  }
234
224
  function createImageBlock(partial = {}) {
235
- const base = {
236
- id: generateId(),
237
- type: "image",
238
- ...IMAGE_BLOCK_DEFAULTS,
239
- styles: createDefaultStyles()
240
- };
241
- return applyDefaults(base, partial);
225
+ return applyDefaults({
226
+ id: generateId(),
227
+ type: "image",
228
+ ...IMAGE_BLOCK_DEFAULTS,
229
+ styles: createDefaultStyles()
230
+ }, partial);
242
231
  }
243
232
  function createButtonBlock(partial = {}) {
244
- const base = {
245
- id: generateId(),
246
- type: "button",
247
- ...BUTTON_BLOCK_DEFAULTS,
248
- styles: createDefaultStyles()
249
- };
250
- return applyDefaults(base, partial);
233
+ return applyDefaults({
234
+ id: generateId(),
235
+ type: "button",
236
+ ...BUTTON_BLOCK_DEFAULTS,
237
+ styles: createDefaultStyles()
238
+ }, partial);
251
239
  }
252
240
  function createDividerBlock(partial = {}) {
253
- const base = {
254
- id: generateId(),
255
- type: "divider",
256
- ...DIVIDER_BLOCK_DEFAULTS,
257
- styles: createDefaultStyles(20)
258
- };
259
- return applyDefaults(base, partial);
241
+ return applyDefaults({
242
+ id: generateId(),
243
+ type: "divider",
244
+ ...DIVIDER_BLOCK_DEFAULTS,
245
+ styles: createDefaultStyles(20)
246
+ }, partial);
260
247
  }
261
248
  function createSectionBlock(partial = {}) {
262
- const base = {
263
- id: generateId(),
264
- type: "section",
265
- ...SECTION_BLOCK_DEFAULTS,
266
- children: [[]],
267
- styles: createDefaultStyles(20)
268
- };
269
- return applyDefaults(base, partial);
249
+ return applyDefaults({
250
+ id: generateId(),
251
+ type: "section",
252
+ ...SECTION_BLOCK_DEFAULTS,
253
+ children: [[]],
254
+ styles: createDefaultStyles(20)
255
+ }, partial);
270
256
  }
271
257
  function createVideoBlock(partial = {}) {
272
- const base = {
273
- id: generateId(),
274
- type: "video",
275
- ...VIDEO_BLOCK_DEFAULTS,
276
- styles: createDefaultStyles()
277
- };
278
- return applyDefaults(base, partial);
258
+ return applyDefaults({
259
+ id: generateId(),
260
+ type: "video",
261
+ ...VIDEO_BLOCK_DEFAULTS,
262
+ styles: createDefaultStyles()
263
+ }, partial);
279
264
  }
280
265
  function createSocialIconsBlock(partial = {}) {
281
- const base = {
282
- id: generateId(),
283
- type: "social",
284
- icons: [],
285
- ...SOCIAL_ICONS_BLOCK_DEFAULTS,
286
- styles: createDefaultStyles()
287
- };
288
- return applyDefaults(base, partial);
266
+ return applyDefaults({
267
+ id: generateId(),
268
+ type: "social",
269
+ icons: [],
270
+ ...SOCIAL_ICONS_BLOCK_DEFAULTS,
271
+ styles: createDefaultStyles()
272
+ }, partial);
289
273
  }
290
274
  function createSpacerBlock(partial = {}) {
291
- const base = {
292
- id: generateId(),
293
- type: "spacer",
294
- ...SPACER_BLOCK_DEFAULTS,
295
- styles: createDefaultStyles(0)
296
- };
297
- return applyDefaults(base, partial);
275
+ return applyDefaults({
276
+ id: generateId(),
277
+ type: "spacer",
278
+ ...SPACER_BLOCK_DEFAULTS,
279
+ styles: createDefaultStyles(0)
280
+ }, partial);
298
281
  }
299
282
  function createHtmlBlock(partial = {}) {
300
- const base = {
301
- id: generateId(),
302
- type: "html",
303
- ...HTML_BLOCK_DEFAULTS,
304
- styles: createDefaultStyles()
305
- };
306
- return applyDefaults(base, partial);
283
+ return applyDefaults({
284
+ id: generateId(),
285
+ type: "html",
286
+ ...HTML_BLOCK_DEFAULTS,
287
+ styles: createDefaultStyles()
288
+ }, partial);
307
289
  }
308
290
  function createMenuBlock(partial = {}) {
309
- const base = {
310
- id: generateId(),
311
- type: "menu",
312
- items: [],
313
- ...MENU_BLOCK_DEFAULTS,
314
- styles: createDefaultStyles()
315
- };
316
- return applyDefaults(base, partial);
291
+ return applyDefaults({
292
+ id: generateId(),
293
+ type: "menu",
294
+ items: [],
295
+ ...MENU_BLOCK_DEFAULTS,
296
+ styles: createDefaultStyles()
297
+ }, partial);
317
298
  }
318
299
  function createDefaultTableRows(columns, rows) {
319
- return Array.from({ length: rows }, () => ({
320
- id: generateId(),
321
- cells: Array.from(
322
- { length: columns },
323
- () => ({
324
- id: generateId(),
325
- content: ""
326
- })
327
- )
328
- }));
300
+ return Array.from({ length: rows }, () => ({
301
+ id: generateId(),
302
+ cells: Array.from({ length: columns }, () => ({
303
+ id: generateId(),
304
+ content: ""
305
+ }))
306
+ }));
329
307
  }
330
308
  function createTableBlock(partial = {}) {
331
- const base = {
332
- id: generateId(),
333
- type: "table",
334
- rows: createDefaultTableRows(3, 3),
335
- ...TABLE_BLOCK_DEFAULTS,
336
- styles: createDefaultStyles()
337
- };
338
- return applyDefaults(base, partial);
309
+ return applyDefaults({
310
+ id: generateId(),
311
+ type: "table",
312
+ rows: createDefaultTableRows(3, 3),
313
+ ...TABLE_BLOCK_DEFAULTS,
314
+ styles: createDefaultStyles()
315
+ }, partial);
339
316
  }
340
317
  function createCountdownBlock(partial = {}) {
341
- const base = {
342
- id: generateId(),
343
- type: "countdown",
344
- ...COUNTDOWN_BLOCK_DEFAULTS,
345
- styles: createDefaultStyles()
346
- };
347
- return applyDefaults(base, partial);
318
+ return applyDefaults({
319
+ id: generateId(),
320
+ type: "countdown",
321
+ ...COUNTDOWN_BLOCK_DEFAULTS,
322
+ styles: createDefaultStyles()
323
+ }, partial);
348
324
  }
349
325
  function getFieldDefault(field) {
350
- if (field.type === "repeatable") {
351
- return field.default ?? [];
352
- }
353
- if (field.type === "boolean") {
354
- return field.default ?? false;
355
- }
356
- if (field.type === "number") {
357
- return field.default ?? 0;
358
- }
359
- return field.default ?? "";
326
+ if (field.type === "repeatable") return field.default ?? [];
327
+ if (field.type === "boolean") return field.default ?? false;
328
+ if (field.type === "number") return field.default ?? 0;
329
+ return field.default ?? "";
360
330
  }
361
331
  function createCustomBlock(definition) {
362
- const fieldValues = {};
363
- for (const field of definition.fields) {
364
- fieldValues[field.key] = getFieldDefault(field);
365
- }
366
- const styles = applyDefaults(createDefaultStyles(), definition.defaultStyles);
367
- return {
368
- id: generateId(),
369
- type: "custom",
370
- customType: definition.type,
371
- fieldValues,
372
- styles,
373
- ...definition.dataSource ? { dataSourceFetched: false } : {}
374
- };
332
+ const fieldValues = {};
333
+ for (const field of definition.fields) fieldValues[field.key] = getFieldDefault(field);
334
+ const styles = applyDefaults(createDefaultStyles(), definition.defaultStyles);
335
+ return {
336
+ id: generateId(),
337
+ type: "custom",
338
+ customType: definition.type,
339
+ fieldValues,
340
+ styles,
341
+ ...definition.dataSource ? { dataSourceFetched: false } : {}
342
+ };
375
343
  }
376
344
  function createBlock(type, blockDefaults) {
377
- switch (type) {
378
- case "section":
379
- return createSectionBlock(blockDefaults?.section);
380
- case "title":
381
- return createTitleBlock(blockDefaults?.title);
382
- case "paragraph":
383
- return createParagraphBlock(blockDefaults?.paragraph);
384
- case "image":
385
- return createImageBlock(blockDefaults?.image);
386
- case "button":
387
- return createButtonBlock(blockDefaults?.button);
388
- case "divider":
389
- return createDividerBlock(blockDefaults?.divider);
390
- case "video":
391
- return createVideoBlock(blockDefaults?.video);
392
- case "social":
393
- return createSocialIconsBlock(blockDefaults?.social);
394
- case "spacer":
395
- return createSpacerBlock(blockDefaults?.spacer);
396
- case "html":
397
- return createHtmlBlock(blockDefaults?.html);
398
- case "menu":
399
- return createMenuBlock(blockDefaults?.menu);
400
- case "table":
401
- return createTableBlock(blockDefaults?.table);
402
- case "countdown":
403
- return createCountdownBlock(blockDefaults?.countdown);
404
- default:
405
- throw new Error(`Unknown block type: ${type}`);
406
- }
345
+ switch (type) {
346
+ case "section": return createSectionBlock(blockDefaults?.section);
347
+ case "title": return createTitleBlock(blockDefaults?.title);
348
+ case "paragraph": return createParagraphBlock(blockDefaults?.paragraph);
349
+ case "image": return createImageBlock(blockDefaults?.image);
350
+ case "button": return createButtonBlock(blockDefaults?.button);
351
+ case "divider": return createDividerBlock(blockDefaults?.divider);
352
+ case "video": return createVideoBlock(blockDefaults?.video);
353
+ case "social": return createSocialIconsBlock(blockDefaults?.social);
354
+ case "spacer": return createSpacerBlock(blockDefaults?.spacer);
355
+ case "html": return createHtmlBlock(blockDefaults?.html);
356
+ case "menu": return createMenuBlock(blockDefaults?.menu);
357
+ case "table": return createTableBlock(blockDefaults?.table);
358
+ case "countdown": return createCountdownBlock(blockDefaults?.countdown);
359
+ default: throw new Error(`Unknown block type: ${type}`);
360
+ }
407
361
  }
408
362
  function cloneBlock(block) {
409
- const cloned = JSON.parse(JSON.stringify(block));
410
- cloned.id = generateId();
411
- if (cloned.type === "section") {
412
- cloned.children = cloned.children.map(
413
- (column) => column.map((child) => cloneBlock(child))
414
- );
415
- }
416
- return cloned;
363
+ const cloned = JSON.parse(JSON.stringify(block));
364
+ cloned.id = generateId();
365
+ if (cloned.type === "section") cloned.children = cloned.children.map((column) => column.map((child) => cloneBlock(child)));
366
+ return cloned;
417
367
  }
418
-
419
- // src/events.ts
368
+ //#endregion
369
+ //#region src/events.ts
420
370
  var EventEmitter = class {
421
- handlers = /* @__PURE__ */ new Map();
422
- on(event, handler) {
423
- if (!this.handlers.has(event)) {
424
- this.handlers.set(event, /* @__PURE__ */ new Set());
425
- }
426
- const set = this.handlers.get(event);
427
- set.add(handler);
428
- return () => {
429
- set.delete(handler);
430
- if (set.size === 0) {
431
- this.handlers.delete(event);
432
- }
433
- };
434
- }
435
- off(event, handler) {
436
- const set = this.handlers.get(event);
437
- if (!set) {
438
- return;
439
- }
440
- set.delete(handler);
441
- if (set.size === 0) {
442
- this.handlers.delete(event);
443
- }
444
- }
445
- emit(event, data) {
446
- const set = this.handlers.get(event);
447
- if (!set) {
448
- return;
449
- }
450
- for (const handler of [...set]) {
451
- handler(data);
452
- }
453
- }
454
- removeAllListeners(event) {
455
- if (event) {
456
- this.handlers.delete(event);
457
- } else {
458
- this.handlers.clear();
459
- }
460
- }
461
- listenerCount(event) {
462
- return this.handlers.get(event)?.size ?? 0;
463
- }
371
+ handlers = /* @__PURE__ */ new Map();
372
+ on(event, handler) {
373
+ if (!this.handlers.has(event)) this.handlers.set(event, /* @__PURE__ */ new Set());
374
+ const set = this.handlers.get(event);
375
+ set.add(handler);
376
+ return () => {
377
+ set.delete(handler);
378
+ if (set.size === 0) this.handlers.delete(event);
379
+ };
380
+ }
381
+ off(event, handler) {
382
+ const set = this.handlers.get(event);
383
+ if (!set) return;
384
+ set.delete(handler);
385
+ if (set.size === 0) this.handlers.delete(event);
386
+ }
387
+ emit(event, data) {
388
+ const set = this.handlers.get(event);
389
+ if (!set) return;
390
+ for (const handler of [...set]) handler(data);
391
+ }
392
+ removeAllListeners(event) {
393
+ if (event) this.handlers.delete(event);
394
+ else this.handlers.clear();
395
+ }
396
+ listenerCount(event) {
397
+ return this.handlers.get(event)?.size ?? 0;
398
+ }
464
399
  };
465
-
466
- // src/merge-tags.ts
467
- var SYNTAX_PRESETS = {
468
- liquid: { value: /\{\{.+?\}\}/g, logic: /\{%-?\s*(\w+).*?-?%\}/g },
469
- handlebars: {
470
- value: /\{\{\{?.+?\}?\}\}/g,
471
- logic: /\{\{[#/](\w+).*?\}\}/g
472
- },
473
- mailchimp: { value: /\*\|\w+\|\*/g, logic: /\*\|(\w+)[:|].*?\|\*/g },
474
- ampscript: { value: /%%=.+?=%%/g, logic: /%%\[\s*(\w+).*?\]%%/g }
400
+ //#endregion
401
+ //#region src/clone.ts
402
+ /**
403
+ * Cycle-safe deep clone via a JSON round-trip.
404
+ *
405
+ * A naked `JSON.stringify` throws `Converting circular structure to JSON`
406
+ * if the tree is self-referencing — e.g. a DOM element carrying a Sortable
407
+ * expando back-ref (`HTMLDivElement.SortableXXX -> instance -> el -> div`)
408
+ * leaks into block data through a drag handler inside a section. Both the
409
+ * editor's public `getContent()` export path and the history snapshot path
410
+ * must tolerate that: we drop the offending back-ref from the clone rather
411
+ * than throw. Losing a transient DOM expando is harmless; the block data is
412
+ * intact.
413
+ *
414
+ * The `WeakSet` replacer omits any object already seen on the current path,
415
+ * which covers every cyclic shape. Template content is tree-shaped (and is
416
+ * serialized to JSON for storage anyway), so dropping repeated references
417
+ * never costs real data.
418
+ */
419
+ function safeClone(value) {
420
+ const seen = /* @__PURE__ */ new WeakSet();
421
+ return JSON.parse(JSON.stringify(value, (_key, val) => {
422
+ if (typeof val === "object" && val !== null) {
423
+ if (seen.has(val)) return void 0;
424
+ seen.add(val);
425
+ }
426
+ return val;
427
+ }));
428
+ }
429
+ //#endregion
430
+ //#region src/merge-tags.ts
431
+ const SYNTAX_PRESETS = {
432
+ liquid: {
433
+ value: /\{\{.+?\}\}/g,
434
+ logic: /\{%-?\s*(\w+).*?-?%\}/g
435
+ },
436
+ handlebars: {
437
+ value: /\{\{\{?.+?\}?\}\}/g,
438
+ logic: /\{\{[#/](\w+).*?\}\}/g
439
+ },
440
+ mailchimp: {
441
+ value: /\*\|\w+\|\*/g,
442
+ logic: /\*\|(\w+)[:|].*?\|\*/g
443
+ },
444
+ ampscript: {
445
+ value: /%%=.+?=%%/g,
446
+ logic: /%%\[\s*(\w+).*?\]%%/g
447
+ }
475
448
  };
476
- var SYNTAX_TRIGGER_CHARS = {
477
- liquid: "{{",
478
- handlebars: "{{",
479
- mailchimp: "*|",
480
- ampscript: "%%="
449
+ const SYNTAX_TRIGGER_CHARS = {
450
+ liquid: "{{",
451
+ handlebars: "{{",
452
+ mailchimp: "*|",
453
+ ampscript: "%%="
481
454
  };
455
+ /**
456
+ * Resolves the autocomplete trigger string for a syntax preset.
457
+ * Returns null when the syntax doesn't match any built-in preset
458
+ * (custom regex syntax — autocomplete cannot be enabled safely).
459
+ */
482
460
  function getSyntaxTriggerChar(syntax) {
483
- for (const name of Object.keys(SYNTAX_PRESETS)) {
484
- if (SYNTAX_PRESETS[name].value.source === syntax.value.source) {
485
- return SYNTAX_TRIGGER_CHARS[name];
486
- }
487
- }
488
- return null;
461
+ for (const name of Object.keys(SYNTAX_PRESETS)) if (SYNTAX_PRESETS[name].value.source === syntax.value.source) return SYNTAX_TRIGGER_CHARS[name];
462
+ return null;
489
463
  }
490
464
  function resolveSyntax(syntax) {
491
- if (!syntax) {
492
- return SYNTAX_PRESETS.liquid;
493
- }
494
- if (typeof syntax === "string") {
495
- return SYNTAX_PRESETS[syntax] ?? SYNTAX_PRESETS.liquid;
496
- }
497
- return syntax;
465
+ if (!syntax) return SYNTAX_PRESETS.liquid;
466
+ if (typeof syntax === "string") return SYNTAX_PRESETS[syntax] ?? SYNTAX_PRESETS.liquid;
467
+ return syntax;
498
468
  }
499
469
  function escapeRegExp(str) {
500
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
470
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
501
471
  }
502
472
  function anchoredRegex(pattern) {
503
- const source = pattern.source;
504
- const flags = pattern.flags.replace("g", "");
505
- return new RegExp(`^${source}$`, flags);
473
+ const source = pattern.source;
474
+ const flags = pattern.flags.replace("g", "");
475
+ return new RegExp(`^${source}$`, flags);
506
476
  }
507
477
  function isMergeTagValue(value, syntax) {
508
- const trimmed = value?.trim() || "";
509
- if (anchoredRegex(syntax.logic).test(trimmed)) {
510
- return false;
511
- }
512
- return anchoredRegex(syntax.value).test(trimmed);
478
+ const trimmed = value?.trim() || "";
479
+ if (anchoredRegex(syntax.logic).test(trimmed)) return false;
480
+ return anchoredRegex(syntax.value).test(trimmed);
513
481
  }
514
482
  function getMergeTagLabel(value, mergeTags) {
515
- const found = mergeTags.find((p) => p.value === value);
516
- if (found) {
517
- return found.label;
518
- }
519
- return value;
483
+ const found = mergeTags.find((p) => p.value === value);
484
+ if (found) return found.label;
485
+ return value;
520
486
  }
521
487
  function resolveHtmlMergeTagLabels(html, mergeTags) {
522
- return rewriteSpanByAttr(
523
- html,
524
- "data-merge-tag",
525
- (value) => getMergeTagLabel(value, mergeTags)
526
- );
488
+ return rewriteSpanByAttr(html, "data-merge-tag", (value) => getMergeTagLabel(value, mergeTags));
527
489
  }
528
490
  function containsMergeTag(value, syntax) {
529
- if (!value) return false;
530
- const valueRegex = new RegExp(syntax.value.source, syntax.value.flags);
531
- const logicRegex = new RegExp(syntax.logic.source, syntax.logic.flags);
532
- return valueRegex.test(value) || logicRegex.test(value);
491
+ if (!value) return false;
492
+ const valueRegex = new RegExp(syntax.value.source, syntax.value.flags);
493
+ const logicRegex = new RegExp(syntax.logic.source, syntax.logic.flags);
494
+ return valueRegex.test(value) || logicRegex.test(value);
533
495
  }
534
496
  function restoreMergeTagMarkup(html, mergeTags, syntax) {
535
- let result = html;
536
- for (const tag of mergeTags) {
537
- const escaped = escapeRegExp(tag.value);
538
- const pattern = new RegExp(`(?<!data-merge-tag=")${escaped}`, "g");
539
- result = result.replace(pattern, (match) => {
540
- const label = getMergeTagLabel(match, mergeTags);
541
- return `<span data-merge-tag="${match}">${label}</span>`;
542
- });
543
- }
544
- const logicRegex = new RegExp(
545
- `(?<!data-logic-merge-tag=")${syntax.logic.source}`,
546
- syntax.logic.flags
547
- );
548
- result = result.replace(logicRegex, (match) => {
549
- const keyword = getLogicMergeTagKeyword(match, syntax);
550
- return `<span data-logic-merge-tag="${match}">${keyword}</span>`;
551
- });
552
- return result;
497
+ let result = html;
498
+ for (const tag of mergeTags) {
499
+ const escaped = escapeRegExp(tag.value);
500
+ const pattern = new RegExp(`(?<!data-merge-tag=")${escaped}`, "g");
501
+ result = result.replace(pattern, (match) => {
502
+ return `<span data-merge-tag="${match}">${getMergeTagLabel(match, mergeTags)}</span>`;
503
+ });
504
+ }
505
+ const logicRegex = new RegExp(`(?<!data-logic-merge-tag=")${syntax.logic.source}`, syntax.logic.flags);
506
+ result = result.replace(logicRegex, (match) => {
507
+ return `<span data-logic-merge-tag="${match}">${getLogicMergeTagKeyword(match, syntax)}</span>`;
508
+ });
509
+ return result;
553
510
  }
554
511
  function isLogicMergeTagValue(value, syntax) {
555
- return anchoredRegex(syntax.logic).test(value?.trim() || "");
512
+ return anchoredRegex(syntax.logic).test(value?.trim() || "");
556
513
  }
557
514
  function getLogicMergeTagKeyword(value, syntax) {
558
- const regex = new RegExp(
559
- syntax.logic.source,
560
- syntax.logic.flags.replace("g", "")
561
- );
562
- const match = value.match(regex);
563
- return match && match[1] ? match[1].toUpperCase() : value;
515
+ const regex = new RegExp(syntax.logic.source, syntax.logic.flags.replace("g", ""));
516
+ const match = value.match(regex);
517
+ return match && match[1] ? match[1].toUpperCase() : value;
564
518
  }
565
519
  function resolveHtmlLogicMergeTagLabels(html, syntax) {
566
- return rewriteSpanByAttr(
567
- html,
568
- "data-logic-merge-tag",
569
- (value) => getLogicMergeTagKeyword(value, syntax)
570
- );
571
- }
520
+ return rewriteSpanByAttr(html, "data-logic-merge-tag", (value) => getLogicMergeTagKeyword(value, syntax));
521
+ }
522
+ /**
523
+ * Walk `html` and rewrite the inner text of every `<span … {attrName}="…">…</span>`
524
+ * by passing the attribute value through `relabel`. Linear in `html.length`:
525
+ * each `indexOf` advances the cursor monotonically, and no regex backtracking
526
+ * can run over the whole string.
527
+ *
528
+ * Replaces the original `/<span[^>]*…[^>]*>(.*?)<\/span>/g` pattern, which
529
+ * was polynomial-ReDoS over inputs that contained many `<span` starts with
530
+ * no closing `>`.
531
+ */
572
532
  function rewriteSpanByAttr(html, attrName, relabel) {
573
- const attrPattern = new RegExp(`(?:^|\\s)${attrName}="([^"<>]*)"`);
574
- let out = "";
575
- let i = 0;
576
- while (i < html.length) {
577
- const open = html.indexOf("<span", i);
578
- if (open === -1) {
579
- out += html.substring(i);
580
- break;
581
- }
582
- const afterTagName = html[open + 5];
583
- if (afterTagName !== ">" && afterTagName !== " " && afterTagName !== " " && afterTagName !== "\n" && afterTagName !== "\r" && afterTagName !== "/") {
584
- out += html.substring(i, open + 5);
585
- i = open + 5;
586
- continue;
587
- }
588
- const openEnd = html.indexOf(">", open + 5);
589
- if (openEnd === -1) {
590
- out += html.substring(i);
591
- break;
592
- }
593
- const closeStart = html.indexOf("</span>", openEnd + 1);
594
- if (closeStart === -1) {
595
- out += html.substring(i);
596
- break;
597
- }
598
- const attrs = html.substring(open + 5, openEnd);
599
- const attrMatch = attrPattern.exec(attrs);
600
- if (!attrMatch) {
601
- out += html.substring(i, open + 5);
602
- i = open + 5;
603
- continue;
604
- }
605
- const value = attrMatch[1];
606
- const newLabel = relabel(value);
607
- out += html.substring(i, openEnd + 1);
608
- out += newLabel;
609
- out += "</span>";
610
- i = closeStart + 7;
611
- }
612
- return out;
613
- }
614
-
615
- // src/config.ts
533
+ const attrPattern = new RegExp(`(?:^|\\s)${attrName}="([^"<>]*)"`);
534
+ let out = "";
535
+ let i = 0;
536
+ while (i < html.length) {
537
+ const open = html.indexOf("<span", i);
538
+ if (open === -1) {
539
+ out += html.substring(i);
540
+ break;
541
+ }
542
+ const afterTagName = html[open + 5];
543
+ if (afterTagName !== ">" && afterTagName !== " " && afterTagName !== " " && afterTagName !== "\n" && afterTagName !== "\r" && afterTagName !== "/") {
544
+ out += html.substring(i, open + 5);
545
+ i = open + 5;
546
+ continue;
547
+ }
548
+ const openEnd = html.indexOf(">", open + 5);
549
+ if (openEnd === -1) {
550
+ out += html.substring(i);
551
+ break;
552
+ }
553
+ const closeStart = html.indexOf("</span>", openEnd + 1);
554
+ if (closeStart === -1) {
555
+ out += html.substring(i);
556
+ break;
557
+ }
558
+ const attrs = html.substring(open + 5, openEnd);
559
+ const attrMatch = attrPattern.exec(attrs);
560
+ if (!attrMatch) {
561
+ out += html.substring(i, open + 5);
562
+ i = open + 5;
563
+ continue;
564
+ }
565
+ const value = attrMatch[1];
566
+ const newLabel = relabel(value);
567
+ out += html.substring(i, openEnd + 1);
568
+ out += newLabel;
569
+ out += "</span>";
570
+ i = closeStart + 7;
571
+ }
572
+ return out;
573
+ }
574
+ //#endregion
575
+ //#region src/config.ts
616
576
  var SdkError = class extends Error {
617
- constructor(message, statusCode) {
618
- super(message);
619
- this.statusCode = statusCode;
620
- this.name = "SdkError";
621
- }
622
- statusCode;
623
- get isNotFound() {
624
- return this.statusCode === 404;
625
- }
626
- get isUnauthorized() {
627
- return this.statusCode === 401;
628
- }
629
- get isServerError() {
630
- return this.statusCode !== void 0 && this.statusCode >= 500;
631
- }
632
- };
633
- export {
634
- BUTTON_BLOCK_DEFAULTS,
635
- COUNTDOWN_BLOCK_DEFAULTS,
636
- DEFAULT_BLOCK_DEFAULTS,
637
- DEFAULT_TEMPLATE_DEFAULTS,
638
- DIVIDER_BLOCK_DEFAULTS,
639
- EventEmitter,
640
- HEADING_LEVEL_FONT_SIZE,
641
- HTML_BLOCK_DEFAULTS,
642
- IMAGE_BLOCK_DEFAULTS,
643
- MENU_BLOCK_DEFAULTS,
644
- PARAGRAPH_BLOCK_DEFAULTS,
645
- SECTION_BLOCK_DEFAULTS,
646
- SOCIAL_ICONS_BLOCK_DEFAULTS,
647
- SPACER_BLOCK_DEFAULTS,
648
- SYNTAX_PRESETS,
649
- SdkError,
650
- TABLE_BLOCK_DEFAULTS,
651
- TITLE_BLOCK_DEFAULTS,
652
- VIDEO_BLOCK_DEFAULTS,
653
- cloneBlock,
654
- containsMergeTag,
655
- createBlock,
656
- createButtonBlock,
657
- createCountdownBlock,
658
- createCustomBlock,
659
- createDefaultTemplateContent,
660
- createDividerBlock,
661
- createHtmlBlock,
662
- createImageBlock,
663
- createMenuBlock,
664
- createParagraphBlock,
665
- createSectionBlock,
666
- createSocialIconsBlock,
667
- createSpacerBlock,
668
- createTableBlock,
669
- createTitleBlock,
670
- createVideoBlock,
671
- deepMergeDefaults,
672
- generateId,
673
- getLogicMergeTagKeyword,
674
- getMergeTagLabel,
675
- getSyntaxTriggerChar,
676
- isButton,
677
- isCountdown,
678
- isCustomBlock,
679
- isDivider,
680
- isHtml,
681
- isImage,
682
- isLogicMergeTagValue,
683
- isMenu,
684
- isMergeTagValue,
685
- isParagraph,
686
- isSection,
687
- isSocialIcons,
688
- isSpacer,
689
- isTable,
690
- isTitle,
691
- isVideo,
692
- resolveHtmlLogicMergeTagLabels,
693
- resolveHtmlMergeTagLabels,
694
- resolveSyntax,
695
- restoreMergeTagMarkup
577
+ statusCode;
578
+ constructor(message, statusCode) {
579
+ super(message);
580
+ this.statusCode = statusCode;
581
+ this.name = "SdkError";
582
+ }
583
+ get isNotFound() {
584
+ return this.statusCode === 404;
585
+ }
586
+ get isUnauthorized() {
587
+ return this.statusCode === 401;
588
+ }
589
+ get isServerError() {
590
+ return this.statusCode !== void 0 && this.statusCode >= 500;
591
+ }
696
592
  };
593
+ //#endregion
594
+ export { BUTTON_BLOCK_DEFAULTS, COUNTDOWN_BLOCK_DEFAULTS, DEFAULT_BLOCK_DEFAULTS, DEFAULT_TEMPLATE_DEFAULTS, DIVIDER_BLOCK_DEFAULTS, EventEmitter, HEADING_LEVEL_FONT_SIZE, HTML_BLOCK_DEFAULTS, IMAGE_BLOCK_DEFAULTS, MENU_BLOCK_DEFAULTS, PARAGRAPH_BLOCK_DEFAULTS, SECTION_BLOCK_DEFAULTS, SOCIAL_ICONS_BLOCK_DEFAULTS, SPACER_BLOCK_DEFAULTS, SYNTAX_PRESETS, SdkError, TABLE_BLOCK_DEFAULTS, TITLE_BLOCK_DEFAULTS, VIDEO_BLOCK_DEFAULTS, cloneBlock, containsMergeTag, createBlock, createButtonBlock, createCountdownBlock, createCustomBlock, createDefaultTemplateContent, createDividerBlock, createHtmlBlock, createImageBlock, createMenuBlock, createParagraphBlock, createSectionBlock, createSocialIconsBlock, createSpacerBlock, createTableBlock, createTitleBlock, createVideoBlock, deepMergeDefaults, generateId, getLogicMergeTagKeyword, getMergeTagLabel, getSyntaxTriggerChar, isButton, isCountdown, isCustomBlock, isDivider, isHtml, isImage, isLogicMergeTagValue, isMenu, isMergeTagValue, isParagraph, isSection, isSocialIcons, isSpacer, isTable, isTitle, isVideo, resolveHtmlLogicMergeTagLabels, resolveHtmlMergeTagLabels, resolveSyntax, restoreMergeTagMarkup, safeClone };
595
+
697
596
  //# sourceMappingURL=index.js.map