@templatical/types 0.9.1 → 0.10.1

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,567 @@
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
- margin: createDefaultSpacing(0)
215
- };
206
+ return { padding: createDefaultSpacing(padding) };
216
207
  }
217
208
  function createTitleBlock(partial = {}) {
218
- const base = {
219
- id: generateId(),
220
- type: "title",
221
- ...TITLE_BLOCK_DEFAULTS,
222
- styles: createDefaultStyles()
223
- };
224
- return applyDefaults(base, partial);
209
+ return applyDefaults({
210
+ id: generateId(),
211
+ type: "title",
212
+ ...TITLE_BLOCK_DEFAULTS,
213
+ styles: createDefaultStyles()
214
+ }, partial);
225
215
  }
226
216
  function createParagraphBlock(partial = {}) {
227
- const base = {
228
- id: generateId(),
229
- type: "paragraph",
230
- ...PARAGRAPH_BLOCK_DEFAULTS,
231
- styles: createDefaultStyles()
232
- };
233
- return applyDefaults(base, partial);
217
+ return applyDefaults({
218
+ id: generateId(),
219
+ type: "paragraph",
220
+ ...PARAGRAPH_BLOCK_DEFAULTS,
221
+ styles: createDefaultStyles()
222
+ }, partial);
234
223
  }
235
224
  function createImageBlock(partial = {}) {
236
- const base = {
237
- id: generateId(),
238
- type: "image",
239
- ...IMAGE_BLOCK_DEFAULTS,
240
- styles: createDefaultStyles()
241
- };
242
- return applyDefaults(base, partial);
225
+ return applyDefaults({
226
+ id: generateId(),
227
+ type: "image",
228
+ ...IMAGE_BLOCK_DEFAULTS,
229
+ styles: createDefaultStyles()
230
+ }, partial);
243
231
  }
244
232
  function createButtonBlock(partial = {}) {
245
- const base = {
246
- id: generateId(),
247
- type: "button",
248
- ...BUTTON_BLOCK_DEFAULTS,
249
- styles: createDefaultStyles()
250
- };
251
- return applyDefaults(base, partial);
233
+ return applyDefaults({
234
+ id: generateId(),
235
+ type: "button",
236
+ ...BUTTON_BLOCK_DEFAULTS,
237
+ styles: createDefaultStyles()
238
+ }, partial);
252
239
  }
253
240
  function createDividerBlock(partial = {}) {
254
- const base = {
255
- id: generateId(),
256
- type: "divider",
257
- ...DIVIDER_BLOCK_DEFAULTS,
258
- styles: createDefaultStyles(20)
259
- };
260
- return applyDefaults(base, partial);
241
+ return applyDefaults({
242
+ id: generateId(),
243
+ type: "divider",
244
+ ...DIVIDER_BLOCK_DEFAULTS,
245
+ styles: createDefaultStyles(20)
246
+ }, partial);
261
247
  }
262
248
  function createSectionBlock(partial = {}) {
263
- const base = {
264
- id: generateId(),
265
- type: "section",
266
- ...SECTION_BLOCK_DEFAULTS,
267
- children: [[]],
268
- styles: createDefaultStyles(20)
269
- };
270
- 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);
271
256
  }
272
257
  function createVideoBlock(partial = {}) {
273
- const base = {
274
- id: generateId(),
275
- type: "video",
276
- ...VIDEO_BLOCK_DEFAULTS,
277
- styles: createDefaultStyles()
278
- };
279
- return applyDefaults(base, partial);
258
+ return applyDefaults({
259
+ id: generateId(),
260
+ type: "video",
261
+ ...VIDEO_BLOCK_DEFAULTS,
262
+ styles: createDefaultStyles()
263
+ }, partial);
280
264
  }
281
265
  function createSocialIconsBlock(partial = {}) {
282
- const base = {
283
- id: generateId(),
284
- type: "social",
285
- icons: [],
286
- ...SOCIAL_ICONS_BLOCK_DEFAULTS,
287
- styles: createDefaultStyles()
288
- };
289
- 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);
290
273
  }
291
274
  function createSpacerBlock(partial = {}) {
292
- const base = {
293
- id: generateId(),
294
- type: "spacer",
295
- ...SPACER_BLOCK_DEFAULTS,
296
- styles: createDefaultStyles(0)
297
- };
298
- return applyDefaults(base, partial);
275
+ return applyDefaults({
276
+ id: generateId(),
277
+ type: "spacer",
278
+ ...SPACER_BLOCK_DEFAULTS,
279
+ styles: createDefaultStyles(0)
280
+ }, partial);
299
281
  }
300
282
  function createHtmlBlock(partial = {}) {
301
- const base = {
302
- id: generateId(),
303
- type: "html",
304
- ...HTML_BLOCK_DEFAULTS,
305
- styles: createDefaultStyles()
306
- };
307
- return applyDefaults(base, partial);
283
+ return applyDefaults({
284
+ id: generateId(),
285
+ type: "html",
286
+ ...HTML_BLOCK_DEFAULTS,
287
+ styles: createDefaultStyles()
288
+ }, partial);
308
289
  }
309
290
  function createMenuBlock(partial = {}) {
310
- const base = {
311
- id: generateId(),
312
- type: "menu",
313
- items: [],
314
- ...MENU_BLOCK_DEFAULTS,
315
- styles: createDefaultStyles()
316
- };
317
- return applyDefaults(base, partial);
291
+ return applyDefaults({
292
+ id: generateId(),
293
+ type: "menu",
294
+ items: [],
295
+ ...MENU_BLOCK_DEFAULTS,
296
+ styles: createDefaultStyles()
297
+ }, partial);
318
298
  }
319
299
  function createDefaultTableRows(columns, rows) {
320
- return Array.from({ length: rows }, () => ({
321
- id: generateId(),
322
- cells: Array.from(
323
- { length: columns },
324
- () => ({
325
- id: generateId(),
326
- content: ""
327
- })
328
- )
329
- }));
300
+ return Array.from({ length: rows }, () => ({
301
+ id: generateId(),
302
+ cells: Array.from({ length: columns }, () => ({
303
+ id: generateId(),
304
+ content: ""
305
+ }))
306
+ }));
330
307
  }
331
308
  function createTableBlock(partial = {}) {
332
- const base = {
333
- id: generateId(),
334
- type: "table",
335
- rows: createDefaultTableRows(3, 3),
336
- ...TABLE_BLOCK_DEFAULTS,
337
- styles: createDefaultStyles()
338
- };
339
- 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);
340
316
  }
341
317
  function createCountdownBlock(partial = {}) {
342
- const base = {
343
- id: generateId(),
344
- type: "countdown",
345
- ...COUNTDOWN_BLOCK_DEFAULTS,
346
- styles: createDefaultStyles()
347
- };
348
- return applyDefaults(base, partial);
318
+ return applyDefaults({
319
+ id: generateId(),
320
+ type: "countdown",
321
+ ...COUNTDOWN_BLOCK_DEFAULTS,
322
+ styles: createDefaultStyles()
323
+ }, partial);
349
324
  }
350
325
  function getFieldDefault(field) {
351
- if (field.type === "repeatable") {
352
- return field.default ?? [];
353
- }
354
- if (field.type === "boolean") {
355
- return field.default ?? false;
356
- }
357
- if (field.type === "number") {
358
- return field.default ?? 0;
359
- }
360
- 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 ?? "";
361
330
  }
362
331
  function createCustomBlock(definition) {
363
- const fieldValues = {};
364
- for (const field of definition.fields) {
365
- fieldValues[field.key] = getFieldDefault(field);
366
- }
367
- return {
368
- id: generateId(),
369
- type: "custom",
370
- customType: definition.type,
371
- fieldValues,
372
- styles: createDefaultStyles(),
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/merge-tags.ts
402
+ const SYNTAX_PRESETS = {
403
+ liquid: {
404
+ value: /\{\{.+?\}\}/g,
405
+ logic: /\{%-?\s*(\w+).*?-?%\}/g
406
+ },
407
+ handlebars: {
408
+ value: /\{\{\{?.+?\}?\}\}/g,
409
+ logic: /\{\{[#/](\w+).*?\}\}/g
410
+ },
411
+ mailchimp: {
412
+ value: /\*\|\w+\|\*/g,
413
+ logic: /\*\|(\w+)[:|].*?\|\*/g
414
+ },
415
+ ampscript: {
416
+ value: /%%=.+?=%%/g,
417
+ logic: /%%\[\s*(\w+).*?\]%%/g
418
+ }
475
419
  };
476
- var SYNTAX_TRIGGER_CHARS = {
477
- liquid: "{{",
478
- handlebars: "{{",
479
- mailchimp: "*|",
480
- ampscript: "%%="
420
+ const SYNTAX_TRIGGER_CHARS = {
421
+ liquid: "{{",
422
+ handlebars: "{{",
423
+ mailchimp: "*|",
424
+ ampscript: "%%="
481
425
  };
426
+ /**
427
+ * Resolves the autocomplete trigger string for a syntax preset.
428
+ * Returns null when the syntax doesn't match any built-in preset
429
+ * (custom regex syntax — autocomplete cannot be enabled safely).
430
+ */
482
431
  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;
432
+ for (const name of Object.keys(SYNTAX_PRESETS)) if (SYNTAX_PRESETS[name].value.source === syntax.value.source) return SYNTAX_TRIGGER_CHARS[name];
433
+ return null;
489
434
  }
490
435
  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;
436
+ if (!syntax) return SYNTAX_PRESETS.liquid;
437
+ if (typeof syntax === "string") return SYNTAX_PRESETS[syntax] ?? SYNTAX_PRESETS.liquid;
438
+ return syntax;
498
439
  }
499
440
  function escapeRegExp(str) {
500
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
441
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
501
442
  }
502
443
  function anchoredRegex(pattern) {
503
- const source = pattern.source;
504
- const flags = pattern.flags.replace("g", "");
505
- return new RegExp(`^${source}$`, flags);
444
+ const source = pattern.source;
445
+ const flags = pattern.flags.replace("g", "");
446
+ return new RegExp(`^${source}$`, flags);
506
447
  }
507
448
  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);
449
+ const trimmed = value?.trim() || "";
450
+ if (anchoredRegex(syntax.logic).test(trimmed)) return false;
451
+ return anchoredRegex(syntax.value).test(trimmed);
513
452
  }
514
453
  function getMergeTagLabel(value, mergeTags) {
515
- const found = mergeTags.find((p) => p.value === value);
516
- if (found) {
517
- return found.label;
518
- }
519
- return value;
454
+ const found = mergeTags.find((p) => p.value === value);
455
+ if (found) return found.label;
456
+ return value;
520
457
  }
521
458
  function resolveHtmlMergeTagLabels(html, mergeTags) {
522
- return rewriteSpanByAttr(
523
- html,
524
- "data-merge-tag",
525
- (value) => getMergeTagLabel(value, mergeTags)
526
- );
459
+ return rewriteSpanByAttr(html, "data-merge-tag", (value) => getMergeTagLabel(value, mergeTags));
527
460
  }
528
461
  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);
462
+ if (!value) return false;
463
+ const valueRegex = new RegExp(syntax.value.source, syntax.value.flags);
464
+ const logicRegex = new RegExp(syntax.logic.source, syntax.logic.flags);
465
+ return valueRegex.test(value) || logicRegex.test(value);
533
466
  }
534
467
  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;
468
+ let result = html;
469
+ for (const tag of mergeTags) {
470
+ const escaped = escapeRegExp(tag.value);
471
+ const pattern = new RegExp(`(?<!data-merge-tag=")${escaped}`, "g");
472
+ result = result.replace(pattern, (match) => {
473
+ return `<span data-merge-tag="${match}">${getMergeTagLabel(match, mergeTags)}</span>`;
474
+ });
475
+ }
476
+ const logicRegex = new RegExp(`(?<!data-logic-merge-tag=")${syntax.logic.source}`, syntax.logic.flags);
477
+ result = result.replace(logicRegex, (match) => {
478
+ return `<span data-logic-merge-tag="${match}">${getLogicMergeTagKeyword(match, syntax)}</span>`;
479
+ });
480
+ return result;
553
481
  }
554
482
  function isLogicMergeTagValue(value, syntax) {
555
- return anchoredRegex(syntax.logic).test(value?.trim() || "");
483
+ return anchoredRegex(syntax.logic).test(value?.trim() || "");
556
484
  }
557
485
  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;
486
+ const regex = new RegExp(syntax.logic.source, syntax.logic.flags.replace("g", ""));
487
+ const match = value.match(regex);
488
+ return match && match[1] ? match[1].toUpperCase() : value;
564
489
  }
565
490
  function resolveHtmlLogicMergeTagLabels(html, syntax) {
566
- return rewriteSpanByAttr(
567
- html,
568
- "data-logic-merge-tag",
569
- (value) => getLogicMergeTagKeyword(value, syntax)
570
- );
571
- }
491
+ return rewriteSpanByAttr(html, "data-logic-merge-tag", (value) => getLogicMergeTagKeyword(value, syntax));
492
+ }
493
+ /**
494
+ * Walk `html` and rewrite the inner text of every `<span … {attrName}="…">…</span>`
495
+ * by passing the attribute value through `relabel`. Linear in `html.length`:
496
+ * each `indexOf` advances the cursor monotonically, and no regex backtracking
497
+ * can run over the whole string.
498
+ *
499
+ * Replaces the original `/<span[^>]*…[^>]*>(.*?)<\/span>/g` pattern, which
500
+ * was polynomial-ReDoS over inputs that contained many `<span` starts with
501
+ * no closing `>`.
502
+ */
572
503
  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
504
+ const attrPattern = new RegExp(`(?:^|\\s)${attrName}="([^"<>]*)"`);
505
+ let out = "";
506
+ let i = 0;
507
+ while (i < html.length) {
508
+ const open = html.indexOf("<span", i);
509
+ if (open === -1) {
510
+ out += html.substring(i);
511
+ break;
512
+ }
513
+ const afterTagName = html[open + 5];
514
+ if (afterTagName !== ">" && afterTagName !== " " && afterTagName !== " " && afterTagName !== "\n" && afterTagName !== "\r" && afterTagName !== "/") {
515
+ out += html.substring(i, open + 5);
516
+ i = open + 5;
517
+ continue;
518
+ }
519
+ const openEnd = html.indexOf(">", open + 5);
520
+ if (openEnd === -1) {
521
+ out += html.substring(i);
522
+ break;
523
+ }
524
+ const closeStart = html.indexOf("</span>", openEnd + 1);
525
+ if (closeStart === -1) {
526
+ out += html.substring(i);
527
+ break;
528
+ }
529
+ const attrs = html.substring(open + 5, openEnd);
530
+ const attrMatch = attrPattern.exec(attrs);
531
+ if (!attrMatch) {
532
+ out += html.substring(i, open + 5);
533
+ i = open + 5;
534
+ continue;
535
+ }
536
+ const value = attrMatch[1];
537
+ const newLabel = relabel(value);
538
+ out += html.substring(i, openEnd + 1);
539
+ out += newLabel;
540
+ out += "</span>";
541
+ i = closeStart + 7;
542
+ }
543
+ return out;
544
+ }
545
+ //#endregion
546
+ //#region src/config.ts
616
547
  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
548
+ statusCode;
549
+ constructor(message, statusCode) {
550
+ super(message);
551
+ this.statusCode = statusCode;
552
+ this.name = "SdkError";
553
+ }
554
+ get isNotFound() {
555
+ return this.statusCode === 404;
556
+ }
557
+ get isUnauthorized() {
558
+ return this.statusCode === 401;
559
+ }
560
+ get isServerError() {
561
+ return this.statusCode !== void 0 && this.statusCode >= 500;
562
+ }
696
563
  };
564
+ //#endregion
565
+ 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 };
566
+
697
567
  //# sourceMappingURL=index.js.map