@templatical/types 0.0.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.cjs +697 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +753 -0
- package/dist/index.d.ts +753 -0
- package/dist/index.js +614 -0
- package/dist/index.js.map +1 -0
- package/package.json +32 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
// src/guards.ts
|
|
2
|
+
function isSection(block) {
|
|
3
|
+
return block.type === "section";
|
|
4
|
+
}
|
|
5
|
+
function isText(block) {
|
|
6
|
+
return block.type === "text";
|
|
7
|
+
}
|
|
8
|
+
function isImage(block) {
|
|
9
|
+
return block.type === "image";
|
|
10
|
+
}
|
|
11
|
+
function isButton(block) {
|
|
12
|
+
return block.type === "button";
|
|
13
|
+
}
|
|
14
|
+
function isDivider(block) {
|
|
15
|
+
return block.type === "divider";
|
|
16
|
+
}
|
|
17
|
+
function isVideo(block) {
|
|
18
|
+
return block.type === "video";
|
|
19
|
+
}
|
|
20
|
+
function isSocialIcons(block) {
|
|
21
|
+
return block.type === "social";
|
|
22
|
+
}
|
|
23
|
+
function isSpacer(block) {
|
|
24
|
+
return block.type === "spacer";
|
|
25
|
+
}
|
|
26
|
+
function isHtml(block) {
|
|
27
|
+
return block.type === "html";
|
|
28
|
+
}
|
|
29
|
+
function isMenu(block) {
|
|
30
|
+
return block.type === "menu";
|
|
31
|
+
}
|
|
32
|
+
function isTable(block) {
|
|
33
|
+
return block.type === "table";
|
|
34
|
+
}
|
|
35
|
+
function isCountdown(block) {
|
|
36
|
+
return block.type === "countdown";
|
|
37
|
+
}
|
|
38
|
+
function isCustomBlock(block) {
|
|
39
|
+
return block.type === "custom";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/defaults.ts
|
|
43
|
+
var TEXT_BLOCK_DEFAULTS = {
|
|
44
|
+
content: "<p>Enter your text here</p>",
|
|
45
|
+
fontSize: 16,
|
|
46
|
+
color: "#1a1a1a",
|
|
47
|
+
textAlign: "left",
|
|
48
|
+
fontWeight: "normal"
|
|
49
|
+
};
|
|
50
|
+
var IMAGE_BLOCK_DEFAULTS = {
|
|
51
|
+
src: "",
|
|
52
|
+
alt: "",
|
|
53
|
+
width: "full",
|
|
54
|
+
align: "center"
|
|
55
|
+
};
|
|
56
|
+
var BUTTON_BLOCK_DEFAULTS = {
|
|
57
|
+
text: "Click Here",
|
|
58
|
+
url: "",
|
|
59
|
+
backgroundColor: "#333333",
|
|
60
|
+
textColor: "#ffffff",
|
|
61
|
+
borderRadius: 6,
|
|
62
|
+
fontSize: 15,
|
|
63
|
+
buttonPadding: { top: 12, right: 24, bottom: 12, left: 24 }
|
|
64
|
+
};
|
|
65
|
+
var DIVIDER_BLOCK_DEFAULTS = {
|
|
66
|
+
lineStyle: "solid",
|
|
67
|
+
color: "#e0e0e0",
|
|
68
|
+
thickness: 1,
|
|
69
|
+
width: "full"
|
|
70
|
+
};
|
|
71
|
+
var SECTION_BLOCK_DEFAULTS = {
|
|
72
|
+
columns: "1"
|
|
73
|
+
};
|
|
74
|
+
var VIDEO_BLOCK_DEFAULTS = {
|
|
75
|
+
url: "",
|
|
76
|
+
thumbnailUrl: "",
|
|
77
|
+
alt: "Video",
|
|
78
|
+
width: "full",
|
|
79
|
+
align: "center"
|
|
80
|
+
};
|
|
81
|
+
var SOCIAL_ICONS_BLOCK_DEFAULTS = {
|
|
82
|
+
iconStyle: "solid",
|
|
83
|
+
iconSize: "medium",
|
|
84
|
+
spacing: 10,
|
|
85
|
+
align: "center"
|
|
86
|
+
};
|
|
87
|
+
var SPACER_BLOCK_DEFAULTS = {
|
|
88
|
+
height: 24
|
|
89
|
+
};
|
|
90
|
+
var HTML_BLOCK_DEFAULTS = {
|
|
91
|
+
content: ""
|
|
92
|
+
};
|
|
93
|
+
var MENU_BLOCK_DEFAULTS = {
|
|
94
|
+
fontSize: 15,
|
|
95
|
+
color: "#1a1a1a",
|
|
96
|
+
textAlign: "center",
|
|
97
|
+
separator: "|",
|
|
98
|
+
separatorColor: "#e0e0e0",
|
|
99
|
+
spacing: 10
|
|
100
|
+
};
|
|
101
|
+
var TABLE_BLOCK_DEFAULTS = {
|
|
102
|
+
hasHeaderRow: true,
|
|
103
|
+
borderColor: "#e0e0e0",
|
|
104
|
+
borderWidth: 1,
|
|
105
|
+
cellPadding: 8,
|
|
106
|
+
fontSize: 15,
|
|
107
|
+
color: "#1a1a1a",
|
|
108
|
+
textAlign: "left"
|
|
109
|
+
};
|
|
110
|
+
var COUNTDOWN_BLOCK_DEFAULTS = {
|
|
111
|
+
targetDate: "",
|
|
112
|
+
timezone: "UTC",
|
|
113
|
+
showDays: true,
|
|
114
|
+
showHours: true,
|
|
115
|
+
showMinutes: true,
|
|
116
|
+
showSeconds: true,
|
|
117
|
+
separator: ":",
|
|
118
|
+
digitFontSize: 32,
|
|
119
|
+
digitColor: "#1a1a1a",
|
|
120
|
+
labelColor: "#6b7280",
|
|
121
|
+
labelFontSize: 12,
|
|
122
|
+
backgroundColor: "#ffffff",
|
|
123
|
+
labelDays: "Days",
|
|
124
|
+
labelHours: "Hours",
|
|
125
|
+
labelMinutes: "Minutes",
|
|
126
|
+
labelSeconds: "Seconds",
|
|
127
|
+
expiredMessage: "This offer has expired",
|
|
128
|
+
expiredImageUrl: "",
|
|
129
|
+
hideOnExpiry: false
|
|
130
|
+
};
|
|
131
|
+
var DEFAULT_BLOCK_DEFAULTS = {
|
|
132
|
+
text: TEXT_BLOCK_DEFAULTS,
|
|
133
|
+
image: IMAGE_BLOCK_DEFAULTS,
|
|
134
|
+
button: BUTTON_BLOCK_DEFAULTS,
|
|
135
|
+
divider: DIVIDER_BLOCK_DEFAULTS,
|
|
136
|
+
section: SECTION_BLOCK_DEFAULTS,
|
|
137
|
+
video: VIDEO_BLOCK_DEFAULTS,
|
|
138
|
+
social: SOCIAL_ICONS_BLOCK_DEFAULTS,
|
|
139
|
+
spacer: SPACER_BLOCK_DEFAULTS,
|
|
140
|
+
html: HTML_BLOCK_DEFAULTS,
|
|
141
|
+
menu: MENU_BLOCK_DEFAULTS,
|
|
142
|
+
table: TABLE_BLOCK_DEFAULTS,
|
|
143
|
+
countdown: COUNTDOWN_BLOCK_DEFAULTS
|
|
144
|
+
};
|
|
145
|
+
var DEFAULT_TEMPLATE_DEFAULTS = {
|
|
146
|
+
width: 600,
|
|
147
|
+
backgroundColor: "#ffffff",
|
|
148
|
+
fontFamily: "Arial, sans-serif"
|
|
149
|
+
};
|
|
150
|
+
function isPlainObject(value) {
|
|
151
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
|
|
152
|
+
}
|
|
153
|
+
function deepMergeDefaults(base, overrides) {
|
|
154
|
+
const result = { ...base };
|
|
155
|
+
for (const key of Object.keys(overrides)) {
|
|
156
|
+
const baseVal = base[key];
|
|
157
|
+
const overrideVal = overrides[key];
|
|
158
|
+
if (overrideVal === void 0) {
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (isPlainObject(baseVal) && isPlainObject(overrideVal)) {
|
|
162
|
+
result[key] = deepMergeDefaults(
|
|
163
|
+
baseVal,
|
|
164
|
+
overrideVal
|
|
165
|
+
);
|
|
166
|
+
} else {
|
|
167
|
+
result[key] = overrideVal;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// src/template.ts
|
|
174
|
+
function createDefaultTemplateContent(defaultFontFamily = "Arial, sans-serif", templateDefaults) {
|
|
175
|
+
return {
|
|
176
|
+
blocks: [],
|
|
177
|
+
settings: {
|
|
178
|
+
...DEFAULT_TEMPLATE_DEFAULTS,
|
|
179
|
+
fontFamily: defaultFontFamily,
|
|
180
|
+
...templateDefaults
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// src/factory.ts
|
|
186
|
+
function applyDefaults(base, partial) {
|
|
187
|
+
if (!partial || Object.keys(partial).length === 0) return base;
|
|
188
|
+
return deepMergeDefaults(
|
|
189
|
+
base,
|
|
190
|
+
partial
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
function generateId() {
|
|
194
|
+
return crypto.randomUUID();
|
|
195
|
+
}
|
|
196
|
+
function createDefaultSpacing(value = 0) {
|
|
197
|
+
return { top: value, right: value, bottom: value, left: value };
|
|
198
|
+
}
|
|
199
|
+
function createDefaultStyles(padding = 10) {
|
|
200
|
+
return {
|
|
201
|
+
padding: createDefaultSpacing(padding),
|
|
202
|
+
margin: createDefaultSpacing(0)
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function createTextBlock(partial = {}) {
|
|
206
|
+
const base = {
|
|
207
|
+
id: generateId(),
|
|
208
|
+
type: "text",
|
|
209
|
+
...TEXT_BLOCK_DEFAULTS,
|
|
210
|
+
styles: createDefaultStyles()
|
|
211
|
+
};
|
|
212
|
+
return applyDefaults(base, partial);
|
|
213
|
+
}
|
|
214
|
+
function createImageBlock(partial = {}) {
|
|
215
|
+
const base = {
|
|
216
|
+
id: generateId(),
|
|
217
|
+
type: "image",
|
|
218
|
+
...IMAGE_BLOCK_DEFAULTS,
|
|
219
|
+
styles: createDefaultStyles()
|
|
220
|
+
};
|
|
221
|
+
return applyDefaults(base, partial);
|
|
222
|
+
}
|
|
223
|
+
function createButtonBlock(partial = {}) {
|
|
224
|
+
const base = {
|
|
225
|
+
id: generateId(),
|
|
226
|
+
type: "button",
|
|
227
|
+
...BUTTON_BLOCK_DEFAULTS,
|
|
228
|
+
styles: createDefaultStyles()
|
|
229
|
+
};
|
|
230
|
+
return applyDefaults(base, partial);
|
|
231
|
+
}
|
|
232
|
+
function createDividerBlock(partial = {}) {
|
|
233
|
+
const base = {
|
|
234
|
+
id: generateId(),
|
|
235
|
+
type: "divider",
|
|
236
|
+
...DIVIDER_BLOCK_DEFAULTS,
|
|
237
|
+
styles: createDefaultStyles(20)
|
|
238
|
+
};
|
|
239
|
+
return applyDefaults(base, partial);
|
|
240
|
+
}
|
|
241
|
+
function createSectionBlock(partial = {}) {
|
|
242
|
+
const base = {
|
|
243
|
+
id: generateId(),
|
|
244
|
+
type: "section",
|
|
245
|
+
...SECTION_BLOCK_DEFAULTS,
|
|
246
|
+
children: [[]],
|
|
247
|
+
styles: createDefaultStyles(20)
|
|
248
|
+
};
|
|
249
|
+
return applyDefaults(base, partial);
|
|
250
|
+
}
|
|
251
|
+
function createVideoBlock(partial = {}) {
|
|
252
|
+
const base = {
|
|
253
|
+
id: generateId(),
|
|
254
|
+
type: "video",
|
|
255
|
+
...VIDEO_BLOCK_DEFAULTS,
|
|
256
|
+
styles: createDefaultStyles()
|
|
257
|
+
};
|
|
258
|
+
return applyDefaults(base, partial);
|
|
259
|
+
}
|
|
260
|
+
function createSocialIconsBlock(partial = {}) {
|
|
261
|
+
const base = {
|
|
262
|
+
id: generateId(),
|
|
263
|
+
type: "social",
|
|
264
|
+
icons: [],
|
|
265
|
+
...SOCIAL_ICONS_BLOCK_DEFAULTS,
|
|
266
|
+
styles: createDefaultStyles()
|
|
267
|
+
};
|
|
268
|
+
return applyDefaults(base, partial);
|
|
269
|
+
}
|
|
270
|
+
function createSpacerBlock(partial = {}) {
|
|
271
|
+
const base = {
|
|
272
|
+
id: generateId(),
|
|
273
|
+
type: "spacer",
|
|
274
|
+
...SPACER_BLOCK_DEFAULTS,
|
|
275
|
+
styles: createDefaultStyles(0)
|
|
276
|
+
};
|
|
277
|
+
return applyDefaults(base, partial);
|
|
278
|
+
}
|
|
279
|
+
function createHtmlBlock(partial = {}) {
|
|
280
|
+
const base = {
|
|
281
|
+
id: generateId(),
|
|
282
|
+
type: "html",
|
|
283
|
+
...HTML_BLOCK_DEFAULTS,
|
|
284
|
+
styles: createDefaultStyles()
|
|
285
|
+
};
|
|
286
|
+
return applyDefaults(base, partial);
|
|
287
|
+
}
|
|
288
|
+
function createMenuBlock(partial = {}) {
|
|
289
|
+
const base = {
|
|
290
|
+
id: generateId(),
|
|
291
|
+
type: "menu",
|
|
292
|
+
items: [],
|
|
293
|
+
...MENU_BLOCK_DEFAULTS,
|
|
294
|
+
styles: createDefaultStyles()
|
|
295
|
+
};
|
|
296
|
+
return applyDefaults(base, partial);
|
|
297
|
+
}
|
|
298
|
+
function createDefaultTableRows(columns, rows) {
|
|
299
|
+
return Array.from({ length: rows }, () => ({
|
|
300
|
+
id: generateId(),
|
|
301
|
+
cells: Array.from(
|
|
302
|
+
{ length: columns },
|
|
303
|
+
() => ({
|
|
304
|
+
id: generateId(),
|
|
305
|
+
content: ""
|
|
306
|
+
})
|
|
307
|
+
)
|
|
308
|
+
}));
|
|
309
|
+
}
|
|
310
|
+
function createTableBlock(partial = {}) {
|
|
311
|
+
const base = {
|
|
312
|
+
id: generateId(),
|
|
313
|
+
type: "table",
|
|
314
|
+
rows: createDefaultTableRows(3, 3),
|
|
315
|
+
...TABLE_BLOCK_DEFAULTS,
|
|
316
|
+
styles: createDefaultStyles()
|
|
317
|
+
};
|
|
318
|
+
return applyDefaults(base, partial);
|
|
319
|
+
}
|
|
320
|
+
function createCountdownBlock(partial = {}) {
|
|
321
|
+
const base = {
|
|
322
|
+
id: generateId(),
|
|
323
|
+
type: "countdown",
|
|
324
|
+
...COUNTDOWN_BLOCK_DEFAULTS,
|
|
325
|
+
styles: createDefaultStyles()
|
|
326
|
+
};
|
|
327
|
+
return applyDefaults(base, partial);
|
|
328
|
+
}
|
|
329
|
+
function getFieldDefault(field) {
|
|
330
|
+
if (field.type === "repeatable") {
|
|
331
|
+
return field.default ?? [];
|
|
332
|
+
}
|
|
333
|
+
if (field.type === "boolean") {
|
|
334
|
+
return field.default ?? false;
|
|
335
|
+
}
|
|
336
|
+
if (field.type === "number") {
|
|
337
|
+
return field.default ?? 0;
|
|
338
|
+
}
|
|
339
|
+
return field.default ?? "";
|
|
340
|
+
}
|
|
341
|
+
function createCustomBlock(definition) {
|
|
342
|
+
const fieldValues = {};
|
|
343
|
+
for (const field of definition.fields) {
|
|
344
|
+
fieldValues[field.key] = getFieldDefault(field);
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
id: generateId(),
|
|
348
|
+
type: "custom",
|
|
349
|
+
customType: definition.type,
|
|
350
|
+
fieldValues,
|
|
351
|
+
styles: createDefaultStyles(),
|
|
352
|
+
...definition.dataSource ? { dataSourceFetched: false } : {}
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
function createBlock(type, blockDefaults) {
|
|
356
|
+
switch (type) {
|
|
357
|
+
case "section":
|
|
358
|
+
return createSectionBlock(blockDefaults?.section);
|
|
359
|
+
case "text":
|
|
360
|
+
return createTextBlock(blockDefaults?.text);
|
|
361
|
+
case "image":
|
|
362
|
+
return createImageBlock(blockDefaults?.image);
|
|
363
|
+
case "button":
|
|
364
|
+
return createButtonBlock(blockDefaults?.button);
|
|
365
|
+
case "divider":
|
|
366
|
+
return createDividerBlock(blockDefaults?.divider);
|
|
367
|
+
case "video":
|
|
368
|
+
return createVideoBlock(blockDefaults?.video);
|
|
369
|
+
case "social":
|
|
370
|
+
return createSocialIconsBlock(blockDefaults?.social);
|
|
371
|
+
case "spacer":
|
|
372
|
+
return createSpacerBlock(blockDefaults?.spacer);
|
|
373
|
+
case "html":
|
|
374
|
+
return createHtmlBlock(blockDefaults?.html);
|
|
375
|
+
case "menu":
|
|
376
|
+
return createMenuBlock(blockDefaults?.menu);
|
|
377
|
+
case "table":
|
|
378
|
+
return createTableBlock(blockDefaults?.table);
|
|
379
|
+
case "countdown":
|
|
380
|
+
return createCountdownBlock(blockDefaults?.countdown);
|
|
381
|
+
default:
|
|
382
|
+
throw new Error(`Unknown block type: ${type}`);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
function cloneBlock(block) {
|
|
386
|
+
const cloned = JSON.parse(JSON.stringify(block));
|
|
387
|
+
cloned.id = generateId();
|
|
388
|
+
if (cloned.type === "section") {
|
|
389
|
+
cloned.children = cloned.children.map(
|
|
390
|
+
(column) => column.map((child) => cloneBlock(child))
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
return cloned;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// src/events.ts
|
|
397
|
+
var EventEmitter = class {
|
|
398
|
+
constructor() {
|
|
399
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
400
|
+
}
|
|
401
|
+
on(event, handler) {
|
|
402
|
+
if (!this.handlers.has(event)) {
|
|
403
|
+
this.handlers.set(event, /* @__PURE__ */ new Set());
|
|
404
|
+
}
|
|
405
|
+
const set = this.handlers.get(event);
|
|
406
|
+
set.add(handler);
|
|
407
|
+
return () => {
|
|
408
|
+
set.delete(handler);
|
|
409
|
+
if (set.size === 0) {
|
|
410
|
+
this.handlers.delete(event);
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
off(event, handler) {
|
|
415
|
+
const set = this.handlers.get(event);
|
|
416
|
+
if (!set) {
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
set.delete(handler);
|
|
420
|
+
if (set.size === 0) {
|
|
421
|
+
this.handlers.delete(event);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
emit(event, data) {
|
|
425
|
+
const set = this.handlers.get(event);
|
|
426
|
+
if (!set) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
for (const handler of [...set]) {
|
|
430
|
+
handler(data);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
removeAllListeners(event) {
|
|
434
|
+
if (event) {
|
|
435
|
+
this.handlers.delete(event);
|
|
436
|
+
} else {
|
|
437
|
+
this.handlers.clear();
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
listenerCount(event) {
|
|
441
|
+
return this.handlers.get(event)?.size ?? 0;
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
// src/merge-tags.ts
|
|
446
|
+
var SYNTAX_PRESETS = {
|
|
447
|
+
liquid: { value: /\{\{.+?\}\}/g, logic: /\{%-?\s*(\w+).*?-?%\}/g },
|
|
448
|
+
handlebars: {
|
|
449
|
+
value: /\{\{\{?.+?\}?\}\}/g,
|
|
450
|
+
logic: /\{\{[#/](\w+).*?\}\}/g
|
|
451
|
+
},
|
|
452
|
+
mailchimp: { value: /\*\|\w+\|\*/g, logic: /\*\|(\w+)[:|].*?\|\*/g },
|
|
453
|
+
ampscript: { value: /%%=.+?=%%/g, logic: /%%\[\s*(\w+).*?\]%%/g }
|
|
454
|
+
};
|
|
455
|
+
function resolveSyntax(syntax) {
|
|
456
|
+
if (!syntax) {
|
|
457
|
+
return SYNTAX_PRESETS.liquid;
|
|
458
|
+
}
|
|
459
|
+
if (typeof syntax === "string") {
|
|
460
|
+
return SYNTAX_PRESETS[syntax];
|
|
461
|
+
}
|
|
462
|
+
return syntax;
|
|
463
|
+
}
|
|
464
|
+
function escapeRegExp(str) {
|
|
465
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
466
|
+
}
|
|
467
|
+
function anchoredRegex(pattern) {
|
|
468
|
+
const source = pattern.source;
|
|
469
|
+
const flags = pattern.flags.replace("g", "");
|
|
470
|
+
return new RegExp(`^${source}$`, flags);
|
|
471
|
+
}
|
|
472
|
+
function isMergeTagValue(value, syntax) {
|
|
473
|
+
return anchoredRegex(syntax.value).test(value?.trim() || "");
|
|
474
|
+
}
|
|
475
|
+
function getMergeTagLabel(value, mergeTags) {
|
|
476
|
+
const found = mergeTags.find((p) => p.value === value);
|
|
477
|
+
if (found) {
|
|
478
|
+
return found.label;
|
|
479
|
+
}
|
|
480
|
+
return value;
|
|
481
|
+
}
|
|
482
|
+
function resolveHtmlMergeTagLabels(html, mergeTags) {
|
|
483
|
+
return html.replace(
|
|
484
|
+
/(<span[^>]*\sdata-merge-tag="([^"]*)"[^>]*>)(.*?)(<\/span>)/g,
|
|
485
|
+
(_match, openTag, value, _oldLabel, closeTag) => {
|
|
486
|
+
const label = getMergeTagLabel(value, mergeTags);
|
|
487
|
+
return `${openTag}${label}${closeTag}`;
|
|
488
|
+
}
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
function containsMergeTag(value, syntax) {
|
|
492
|
+
if (!value) return false;
|
|
493
|
+
const valueRegex = new RegExp(syntax.value.source, syntax.value.flags);
|
|
494
|
+
const logicRegex = new RegExp(syntax.logic.source, syntax.logic.flags);
|
|
495
|
+
return valueRegex.test(value) || logicRegex.test(value);
|
|
496
|
+
}
|
|
497
|
+
function restoreMergeTagMarkup(html, mergeTags, syntax) {
|
|
498
|
+
let result = html;
|
|
499
|
+
for (const tag of mergeTags) {
|
|
500
|
+
const escaped = escapeRegExp(tag.value);
|
|
501
|
+
const pattern = new RegExp(`(?<!data-merge-tag=")${escaped}`, "g");
|
|
502
|
+
result = result.replace(pattern, (match) => {
|
|
503
|
+
const label = getMergeTagLabel(match, mergeTags);
|
|
504
|
+
return `<span data-merge-tag="${match}">${label}</span>`;
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
const logicRegex = new RegExp(
|
|
508
|
+
`(?<!data-logic-merge-tag=")${syntax.logic.source}`,
|
|
509
|
+
syntax.logic.flags
|
|
510
|
+
);
|
|
511
|
+
result = result.replace(logicRegex, (match) => {
|
|
512
|
+
const keyword = getLogicMergeTagKeyword(match, syntax);
|
|
513
|
+
return `<span data-logic-merge-tag="${match}">${keyword}</span>`;
|
|
514
|
+
});
|
|
515
|
+
return result;
|
|
516
|
+
}
|
|
517
|
+
function isLogicMergeTagValue(value, syntax) {
|
|
518
|
+
return anchoredRegex(syntax.logic).test(value?.trim() || "");
|
|
519
|
+
}
|
|
520
|
+
function getLogicMergeTagKeyword(value, syntax) {
|
|
521
|
+
const regex = new RegExp(
|
|
522
|
+
syntax.logic.source,
|
|
523
|
+
syntax.logic.flags.replace("g", "")
|
|
524
|
+
);
|
|
525
|
+
const match = value.match(regex);
|
|
526
|
+
return match && match[1] ? match[1].toUpperCase() : value;
|
|
527
|
+
}
|
|
528
|
+
function resolveHtmlLogicMergeTagLabels(html, syntax) {
|
|
529
|
+
return html.replace(
|
|
530
|
+
/(<span[^>]*\sdata-logic-merge-tag="([^"]*)"[^>]*>)(.*?)(<\/span>)/g,
|
|
531
|
+
(_match, openTag, value, _oldLabel, closeTag) => {
|
|
532
|
+
const keyword = getLogicMergeTagKeyword(value, syntax);
|
|
533
|
+
return `${openTag}${keyword}${closeTag}`;
|
|
534
|
+
}
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
// src/config.ts
|
|
539
|
+
var SdkError = class extends Error {
|
|
540
|
+
constructor(message, statusCode) {
|
|
541
|
+
super(message);
|
|
542
|
+
this.statusCode = statusCode;
|
|
543
|
+
this.name = "SdkError";
|
|
544
|
+
}
|
|
545
|
+
get isNotFound() {
|
|
546
|
+
return this.statusCode === 404;
|
|
547
|
+
}
|
|
548
|
+
get isUnauthorized() {
|
|
549
|
+
return this.statusCode === 401;
|
|
550
|
+
}
|
|
551
|
+
get isServerError() {
|
|
552
|
+
return this.statusCode !== void 0 && this.statusCode >= 500;
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
export {
|
|
556
|
+
BUTTON_BLOCK_DEFAULTS,
|
|
557
|
+
COUNTDOWN_BLOCK_DEFAULTS,
|
|
558
|
+
DEFAULT_BLOCK_DEFAULTS,
|
|
559
|
+
DEFAULT_TEMPLATE_DEFAULTS,
|
|
560
|
+
DIVIDER_BLOCK_DEFAULTS,
|
|
561
|
+
EventEmitter,
|
|
562
|
+
HTML_BLOCK_DEFAULTS,
|
|
563
|
+
IMAGE_BLOCK_DEFAULTS,
|
|
564
|
+
MENU_BLOCK_DEFAULTS,
|
|
565
|
+
SECTION_BLOCK_DEFAULTS,
|
|
566
|
+
SOCIAL_ICONS_BLOCK_DEFAULTS,
|
|
567
|
+
SPACER_BLOCK_DEFAULTS,
|
|
568
|
+
SYNTAX_PRESETS,
|
|
569
|
+
SdkError,
|
|
570
|
+
TABLE_BLOCK_DEFAULTS,
|
|
571
|
+
TEXT_BLOCK_DEFAULTS,
|
|
572
|
+
VIDEO_BLOCK_DEFAULTS,
|
|
573
|
+
cloneBlock,
|
|
574
|
+
containsMergeTag,
|
|
575
|
+
createBlock,
|
|
576
|
+
createButtonBlock,
|
|
577
|
+
createCountdownBlock,
|
|
578
|
+
createCustomBlock,
|
|
579
|
+
createDefaultTemplateContent,
|
|
580
|
+
createDividerBlock,
|
|
581
|
+
createHtmlBlock,
|
|
582
|
+
createImageBlock,
|
|
583
|
+
createMenuBlock,
|
|
584
|
+
createSectionBlock,
|
|
585
|
+
createSocialIconsBlock,
|
|
586
|
+
createSpacerBlock,
|
|
587
|
+
createTableBlock,
|
|
588
|
+
createTextBlock,
|
|
589
|
+
createVideoBlock,
|
|
590
|
+
deepMergeDefaults,
|
|
591
|
+
generateId,
|
|
592
|
+
getLogicMergeTagKeyword,
|
|
593
|
+
getMergeTagLabel,
|
|
594
|
+
isButton,
|
|
595
|
+
isCountdown,
|
|
596
|
+
isCustomBlock,
|
|
597
|
+
isDivider,
|
|
598
|
+
isHtml,
|
|
599
|
+
isImage,
|
|
600
|
+
isLogicMergeTagValue,
|
|
601
|
+
isMenu,
|
|
602
|
+
isMergeTagValue,
|
|
603
|
+
isSection,
|
|
604
|
+
isSocialIcons,
|
|
605
|
+
isSpacer,
|
|
606
|
+
isTable,
|
|
607
|
+
isText,
|
|
608
|
+
isVideo,
|
|
609
|
+
resolveHtmlLogicMergeTagLabels,
|
|
610
|
+
resolveHtmlMergeTagLabels,
|
|
611
|
+
resolveSyntax,
|
|
612
|
+
restoreMergeTagMarkup
|
|
613
|
+
};
|
|
614
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/guards.ts","../src/defaults.ts","../src/template.ts","../src/factory.ts","../src/events.ts","../src/merge-tags.ts","../src/config.ts"],"sourcesContent":["import type {\n Block,\n ButtonBlock,\n CountdownBlock,\n CustomBlock,\n DividerBlock,\n HtmlBlock,\n ImageBlock,\n MenuBlock,\n SectionBlock,\n SocialIconsBlock,\n SpacerBlock,\n TableBlock,\n TextBlock,\n VideoBlock,\n} from \"./blocks\";\n\nexport function isSection(block: Block): block is SectionBlock {\n return block.type === \"section\";\n}\n\nexport function isText(block: Block): block is TextBlock {\n return block.type === \"text\";\n}\n\nexport function isImage(block: Block): block is ImageBlock {\n return block.type === \"image\";\n}\n\nexport function isButton(block: Block): block is ButtonBlock {\n return block.type === \"button\";\n}\n\nexport function isDivider(block: Block): block is DividerBlock {\n return block.type === \"divider\";\n}\n\nexport function isVideo(block: Block): block is VideoBlock {\n return block.type === \"video\";\n}\n\nexport function isSocialIcons(block: Block): block is SocialIconsBlock {\n return block.type === \"social\";\n}\n\nexport function isSpacer(block: Block): block is SpacerBlock {\n return block.type === \"spacer\";\n}\n\nexport function isHtml(block: Block): block is HtmlBlock {\n return block.type === \"html\";\n}\n\nexport function isMenu(block: Block): block is MenuBlock {\n return block.type === \"menu\";\n}\n\nexport function isTable(block: Block): block is TableBlock {\n return block.type === \"table\";\n}\n\nexport function isCountdown(block: Block): block is CountdownBlock {\n return block.type === \"countdown\";\n}\n\nexport function isCustomBlock(block: Block): block is CustomBlock {\n return block.type === \"custom\";\n}\n","import type {\n ButtonBlock,\n CountdownBlock,\n DividerBlock,\n HtmlBlock,\n ImageBlock,\n MenuBlock,\n SectionBlock,\n SocialIconsBlock,\n SpacerBlock,\n TableBlock,\n TextBlock,\n VideoBlock,\n} from \"./blocks\";\nimport type { TemplateSettings } from \"./template\";\n\ntype BlockDefaultsFor<T> = Partial<Omit<T, \"id\" | \"type\">>;\n\nexport interface BlockDefaults {\n text?: BlockDefaultsFor<TextBlock>;\n image?: BlockDefaultsFor<ImageBlock>;\n button?: BlockDefaultsFor<ButtonBlock>;\n divider?: BlockDefaultsFor<DividerBlock>;\n section?: BlockDefaultsFor<SectionBlock>;\n video?: BlockDefaultsFor<VideoBlock>;\n social?: BlockDefaultsFor<SocialIconsBlock>;\n spacer?: BlockDefaultsFor<SpacerBlock>;\n html?: BlockDefaultsFor<HtmlBlock>;\n menu?: BlockDefaultsFor<MenuBlock>;\n table?: BlockDefaultsFor<TableBlock>;\n countdown?: BlockDefaultsFor<CountdownBlock>;\n}\n\nexport type TemplateDefaults = Partial<TemplateSettings>;\n\n// ---------------------------------------------------------------------------\n// Built-in default values — single source of truth for factories & consumers\n// ---------------------------------------------------------------------------\n\nexport const TEXT_BLOCK_DEFAULTS: BlockDefaultsFor<TextBlock> = {\n content: \"<p>Enter your text here</p>\",\n fontSize: 16,\n color: \"#1a1a1a\",\n textAlign: \"left\",\n fontWeight: \"normal\",\n};\n\nexport const IMAGE_BLOCK_DEFAULTS: BlockDefaultsFor<ImageBlock> = {\n src: \"\",\n alt: \"\",\n width: \"full\",\n align: \"center\",\n};\n\nexport const BUTTON_BLOCK_DEFAULTS: BlockDefaultsFor<ButtonBlock> = {\n text: \"Click Here\",\n url: \"\",\n backgroundColor: \"#333333\",\n textColor: \"#ffffff\",\n borderRadius: 6,\n fontSize: 15,\n buttonPadding: { top: 12, right: 24, bottom: 12, left: 24 },\n};\n\nexport const DIVIDER_BLOCK_DEFAULTS: BlockDefaultsFor<DividerBlock> = {\n lineStyle: \"solid\",\n color: \"#e0e0e0\",\n thickness: 1,\n width: \"full\",\n};\n\nexport const SECTION_BLOCK_DEFAULTS: BlockDefaultsFor<SectionBlock> = {\n columns: \"1\",\n};\n\nexport const VIDEO_BLOCK_DEFAULTS: BlockDefaultsFor<VideoBlock> = {\n url: \"\",\n thumbnailUrl: \"\",\n alt: \"Video\",\n width: \"full\",\n align: \"center\",\n};\n\nexport const SOCIAL_ICONS_BLOCK_DEFAULTS: BlockDefaultsFor<SocialIconsBlock> = {\n iconStyle: \"solid\",\n iconSize: \"medium\",\n spacing: 10,\n align: \"center\",\n};\n\nexport const SPACER_BLOCK_DEFAULTS: BlockDefaultsFor<SpacerBlock> = {\n height: 24,\n};\n\nexport const HTML_BLOCK_DEFAULTS: BlockDefaultsFor<HtmlBlock> = {\n content: \"\",\n};\n\nexport const MENU_BLOCK_DEFAULTS: BlockDefaultsFor<MenuBlock> = {\n fontSize: 15,\n color: \"#1a1a1a\",\n textAlign: \"center\",\n separator: \"|\",\n separatorColor: \"#e0e0e0\",\n spacing: 10,\n};\n\nexport const TABLE_BLOCK_DEFAULTS: BlockDefaultsFor<TableBlock> = {\n hasHeaderRow: true,\n borderColor: \"#e0e0e0\",\n borderWidth: 1,\n cellPadding: 8,\n fontSize: 15,\n color: \"#1a1a1a\",\n textAlign: \"left\",\n};\n\nexport const COUNTDOWN_BLOCK_DEFAULTS: BlockDefaultsFor<CountdownBlock> = {\n targetDate: \"\",\n timezone: \"UTC\",\n showDays: true,\n showHours: true,\n showMinutes: true,\n showSeconds: true,\n separator: \":\",\n digitFontSize: 32,\n digitColor: \"#1a1a1a\",\n labelColor: \"#6b7280\",\n labelFontSize: 12,\n backgroundColor: \"#ffffff\",\n labelDays: \"Days\",\n labelHours: \"Hours\",\n labelMinutes: \"Minutes\",\n labelSeconds: \"Seconds\",\n expiredMessage: \"This offer has expired\",\n expiredImageUrl: \"\",\n hideOnExpiry: false,\n};\n\nexport const DEFAULT_BLOCK_DEFAULTS: Required<BlockDefaults> = {\n text: TEXT_BLOCK_DEFAULTS,\n image: IMAGE_BLOCK_DEFAULTS,\n button: BUTTON_BLOCK_DEFAULTS,\n divider: DIVIDER_BLOCK_DEFAULTS,\n section: SECTION_BLOCK_DEFAULTS,\n video: VIDEO_BLOCK_DEFAULTS,\n social: SOCIAL_ICONS_BLOCK_DEFAULTS,\n spacer: SPACER_BLOCK_DEFAULTS,\n html: HTML_BLOCK_DEFAULTS,\n menu: MENU_BLOCK_DEFAULTS,\n table: TABLE_BLOCK_DEFAULTS,\n countdown: COUNTDOWN_BLOCK_DEFAULTS,\n};\n\nexport const DEFAULT_TEMPLATE_DEFAULTS: TemplateDefaults = {\n width: 600,\n backgroundColor: \"#ffffff\",\n fontFamily: \"Arial, sans-serif\",\n};\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return (\n typeof value === \"object\" &&\n value !== null &&\n !Array.isArray(value) &&\n Object.getPrototypeOf(value) === Object.prototype\n );\n}\n\nexport function deepMergeDefaults<T extends Record<string, unknown>>(\n base: T,\n overrides: Partial<T>,\n): T {\n const result = { ...base };\n\n for (const key of Object.keys(overrides) as Array<keyof T>) {\n const baseVal = base[key];\n const overrideVal = overrides[key];\n\n if (overrideVal === undefined) {\n continue;\n }\n\n if (isPlainObject(baseVal) && isPlainObject(overrideVal)) {\n result[key] = deepMergeDefaults(\n baseVal as Record<string, unknown>,\n overrideVal as Record<string, unknown>,\n ) as T[keyof T];\n } else {\n result[key] = overrideVal as T[keyof T];\n }\n }\n\n return result;\n}\n","import type { Block } from \"./blocks\";\nimport { DEFAULT_TEMPLATE_DEFAULTS } from \"./defaults\";\nimport type { TemplateDefaults } from \"./defaults\";\n\nexport interface TemplateSettings {\n width: number;\n backgroundColor: string;\n fontFamily: string;\n preheaderText?: string;\n}\n\nexport interface TemplateContent {\n blocks: Block[];\n settings: TemplateSettings;\n}\n\nexport function createDefaultTemplateContent(\n defaultFontFamily = \"Arial, sans-serif\",\n templateDefaults?: TemplateDefaults,\n): TemplateContent {\n return {\n blocks: [],\n settings: {\n ...DEFAULT_TEMPLATE_DEFAULTS,\n fontFamily: defaultFontFamily,\n ...templateDefaults,\n } as TemplateSettings,\n };\n}\n","import type {\n Block,\n BlockStyles,\n BlockType,\n ButtonBlock,\n CountdownBlock,\n CustomBlock,\n DividerBlock,\n HtmlBlock,\n ImageBlock,\n MenuBlock,\n SectionBlock,\n SocialIconsBlock,\n SpacerBlock,\n SpacingValue,\n TableBlock,\n TableCellData,\n TableRowData,\n TextBlock,\n VideoBlock,\n} from \"./blocks\";\nimport type { CustomBlockDefinition, CustomBlockField } from \"./custom-blocks\";\nimport type { BlockDefaults } from \"./defaults\";\nimport {\n BUTTON_BLOCK_DEFAULTS,\n COUNTDOWN_BLOCK_DEFAULTS,\n deepMergeDefaults,\n DIVIDER_BLOCK_DEFAULTS,\n HTML_BLOCK_DEFAULTS,\n IMAGE_BLOCK_DEFAULTS,\n MENU_BLOCK_DEFAULTS,\n SECTION_BLOCK_DEFAULTS,\n SOCIAL_ICONS_BLOCK_DEFAULTS,\n SPACER_BLOCK_DEFAULTS,\n TABLE_BLOCK_DEFAULTS,\n TEXT_BLOCK_DEFAULTS,\n VIDEO_BLOCK_DEFAULTS,\n} from \"./defaults\";\n\nfunction applyDefaults<T>(base: T, partial: Partial<T> | undefined): T {\n if (!partial || Object.keys(partial).length === 0) return base;\n return deepMergeDefaults(\n base as unknown as Record<string, unknown>,\n partial as unknown as Record<string, unknown>,\n ) as unknown as T;\n}\n\nexport function generateId(): string {\n return crypto.randomUUID();\n}\n\nfunction createDefaultSpacing(value = 0): SpacingValue {\n return { top: value, right: value, bottom: value, left: value };\n}\n\nfunction createDefaultStyles(padding = 10): BlockStyles {\n return {\n padding: createDefaultSpacing(padding),\n margin: createDefaultSpacing(0),\n };\n}\n\nexport function createTextBlock(partial: Partial<TextBlock> = {}): TextBlock {\n const base: TextBlock = {\n id: generateId(),\n type: \"text\",\n ...TEXT_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as TextBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createImageBlock(\n partial: Partial<ImageBlock> = {},\n): ImageBlock {\n const base: ImageBlock = {\n id: generateId(),\n type: \"image\",\n ...IMAGE_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as ImageBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createButtonBlock(\n partial: Partial<ButtonBlock> = {},\n): ButtonBlock {\n const base: ButtonBlock = {\n id: generateId(),\n type: \"button\",\n ...BUTTON_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as ButtonBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createDividerBlock(\n partial: Partial<DividerBlock> = {},\n): DividerBlock {\n const base: DividerBlock = {\n id: generateId(),\n type: \"divider\",\n ...DIVIDER_BLOCK_DEFAULTS,\n styles: createDefaultStyles(20),\n } as DividerBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createSectionBlock(\n partial: Partial<SectionBlock> = {},\n): SectionBlock {\n const base: SectionBlock = {\n id: generateId(),\n type: \"section\",\n ...SECTION_BLOCK_DEFAULTS,\n children: [[]],\n styles: createDefaultStyles(20),\n } as SectionBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createVideoBlock(\n partial: Partial<VideoBlock> = {},\n): VideoBlock {\n const base: VideoBlock = {\n id: generateId(),\n type: \"video\",\n ...VIDEO_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as VideoBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createSocialIconsBlock(\n partial: Partial<SocialIconsBlock> = {},\n): SocialIconsBlock {\n const base: SocialIconsBlock = {\n id: generateId(),\n type: \"social\",\n icons: [],\n ...SOCIAL_ICONS_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as SocialIconsBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createSpacerBlock(\n partial: Partial<SpacerBlock> = {},\n): SpacerBlock {\n const base: SpacerBlock = {\n id: generateId(),\n type: \"spacer\",\n ...SPACER_BLOCK_DEFAULTS,\n styles: createDefaultStyles(0),\n } as SpacerBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createHtmlBlock(partial: Partial<HtmlBlock> = {}): HtmlBlock {\n const base: HtmlBlock = {\n id: generateId(),\n type: \"html\",\n ...HTML_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as HtmlBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createMenuBlock(partial: Partial<MenuBlock> = {}): MenuBlock {\n const base: MenuBlock = {\n id: generateId(),\n type: \"menu\",\n items: [],\n ...MENU_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as MenuBlock;\n return applyDefaults(base, partial);\n}\n\nfunction createDefaultTableRows(columns: number, rows: number): TableRowData[] {\n return Array.from({ length: rows }, () => ({\n id: generateId(),\n cells: Array.from(\n { length: columns },\n (): TableCellData => ({\n id: generateId(),\n content: \"\",\n }),\n ),\n }));\n}\n\nexport function createTableBlock(\n partial: Partial<TableBlock> = {},\n): TableBlock {\n const base: TableBlock = {\n id: generateId(),\n type: \"table\",\n rows: createDefaultTableRows(3, 3),\n ...TABLE_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as TableBlock;\n return applyDefaults(base, partial);\n}\n\nexport function createCountdownBlock(\n partial: Partial<CountdownBlock> = {},\n): CountdownBlock {\n const base: CountdownBlock = {\n id: generateId(),\n type: \"countdown\",\n ...COUNTDOWN_BLOCK_DEFAULTS,\n styles: createDefaultStyles(),\n } as CountdownBlock;\n return applyDefaults(base, partial);\n}\n\nfunction getFieldDefault(field: CustomBlockField): unknown {\n if (field.type === \"repeatable\") {\n return field.default ?? [];\n }\n if (field.type === \"boolean\") {\n return field.default ?? false;\n }\n if (field.type === \"number\") {\n return field.default ?? 0;\n }\n\n return field.default ?? \"\";\n}\n\nexport function createCustomBlock(\n definition: CustomBlockDefinition,\n): CustomBlock {\n const fieldValues: Record<string, unknown> = {};\n\n for (const field of definition.fields) {\n fieldValues[field.key] = getFieldDefault(field);\n }\n\n return {\n id: generateId(),\n type: \"custom\",\n customType: definition.type,\n fieldValues,\n styles: createDefaultStyles(),\n ...(definition.dataSource ? { dataSourceFetched: false } : {}),\n };\n}\n\nexport function createBlock(\n type: BlockType,\n blockDefaults?: BlockDefaults,\n): Block {\n switch (type) {\n case \"section\":\n return createSectionBlock(blockDefaults?.section);\n case \"text\":\n return createTextBlock(blockDefaults?.text);\n case \"image\":\n return createImageBlock(blockDefaults?.image);\n case \"button\":\n return createButtonBlock(blockDefaults?.button);\n case \"divider\":\n return createDividerBlock(blockDefaults?.divider);\n case \"video\":\n return createVideoBlock(blockDefaults?.video);\n case \"social\":\n return createSocialIconsBlock(blockDefaults?.social);\n case \"spacer\":\n return createSpacerBlock(blockDefaults?.spacer);\n case \"html\":\n return createHtmlBlock(blockDefaults?.html);\n case \"menu\":\n return createMenuBlock(blockDefaults?.menu);\n case \"table\":\n return createTableBlock(blockDefaults?.table);\n case \"countdown\":\n return createCountdownBlock(blockDefaults?.countdown);\n default:\n throw new Error(`Unknown block type: ${type}`);\n }\n}\n\nexport function cloneBlock(block: Block): Block {\n const cloned = JSON.parse(JSON.stringify(block)) as Block;\n cloned.id = generateId();\n\n if (cloned.type === \"section\") {\n cloned.children = cloned.children.map((column) =>\n column.map((child) => cloneBlock(child)),\n );\n }\n\n return cloned;\n}\n","export class EventEmitter<\n TEvents extends Record<string, unknown> = Record<string, unknown>,\n> {\n private handlers = new Map<keyof TEvents, Set<(data: never) => void>>();\n\n on<K extends keyof TEvents>(\n event: K,\n handler: (data: TEvents[K]) => void,\n ): () => void {\n if (!this.handlers.has(event)) {\n this.handlers.set(event, new Set());\n }\n\n const set = this.handlers.get(event)!;\n set.add(handler as (data: never) => void);\n\n return () => {\n set.delete(handler as (data: never) => void);\n if (set.size === 0) {\n this.handlers.delete(event);\n }\n };\n }\n\n off<K extends keyof TEvents>(\n event: K,\n handler: (data: TEvents[K]) => void,\n ): void {\n const set = this.handlers.get(event);\n if (!set) {\n return;\n }\n\n set.delete(handler as (data: never) => void);\n if (set.size === 0) {\n this.handlers.delete(event);\n }\n }\n\n emit<K extends keyof TEvents>(event: K, data: TEvents[K]): void {\n const set = this.handlers.get(event);\n if (!set) {\n return;\n }\n\n // Copy to avoid issues with handlers modifying the set during iteration\n for (const handler of [...set]) {\n handler(data as never);\n }\n }\n\n removeAllListeners(event?: keyof TEvents): void {\n if (event) {\n this.handlers.delete(event);\n } else {\n this.handlers.clear();\n }\n }\n\n listenerCount(event: keyof TEvents): number {\n return this.handlers.get(event)?.size ?? 0;\n }\n}\n","import type { MergeTag } from \"./config\";\n\n// --- Syntax Presets ---\n\nexport interface SyntaxPreset {\n value: RegExp;\n logic: RegExp;\n}\n\nexport type SyntaxPresetName =\n | \"liquid\"\n | \"handlebars\"\n | \"mailchimp\"\n | \"ampscript\";\n\nexport const SYNTAX_PRESETS: Record<SyntaxPresetName, SyntaxPreset> = {\n liquid: { value: /\\{\\{.+?\\}\\}/g, logic: /\\{%-?\\s*(\\w+).*?-?%\\}/g },\n handlebars: {\n value: /\\{\\{\\{?.+?\\}?\\}\\}/g,\n logic: /\\{\\{[#/](\\w+).*?\\}\\}/g,\n },\n mailchimp: { value: /\\*\\|\\w+\\|\\*/g, logic: /\\*\\|(\\w+)[:|].*?\\|\\*/g },\n ampscript: { value: /%%=.+?=%%/g, logic: /%%\\[\\s*(\\w+).*?\\]%%/g },\n};\n\nexport function resolveSyntax(\n syntax?: SyntaxPresetName | SyntaxPreset,\n): SyntaxPreset {\n if (!syntax) {\n return SYNTAX_PRESETS.liquid;\n }\n\n if (typeof syntax === \"string\") {\n return SYNTAX_PRESETS[syntax];\n }\n\n return syntax;\n}\n\n// --- Merge Tag Utilities ---\n\nfunction escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction anchoredRegex(pattern: RegExp): RegExp {\n const source = pattern.source;\n const flags = pattern.flags.replace(\"g\", \"\");\n return new RegExp(`^${source}$`, flags);\n}\n\nexport function isMergeTagValue(value: string, syntax: SyntaxPreset): boolean {\n return anchoredRegex(syntax.value).test(value?.trim() || \"\");\n}\n\nexport function getMergeTagLabel(value: string, mergeTags: MergeTag[]): string {\n const found = mergeTags.find((p) => p.value === value);\n if (found) {\n return found.label;\n }\n return value;\n}\n\nexport function resolveHtmlMergeTagLabels(\n html: string,\n mergeTags: MergeTag[],\n): string {\n return html.replace(\n /(<span[^>]*\\sdata-merge-tag=\"([^\"]*)\"[^>]*>)(.*?)(<\\/span>)/g,\n (_match, openTag, value, _oldLabel, closeTag) => {\n const label = getMergeTagLabel(value, mergeTags);\n return `${openTag}${label}${closeTag}`;\n },\n );\n}\n\nexport function containsMergeTag(value: string, syntax: SyntaxPreset): boolean {\n if (!value) return false;\n\n const valueRegex = new RegExp(syntax.value.source, syntax.value.flags);\n const logicRegex = new RegExp(syntax.logic.source, syntax.logic.flags);\n\n return valueRegex.test(value) || logicRegex.test(value);\n}\n\nexport function restoreMergeTagMarkup(\n html: string,\n mergeTags: MergeTag[],\n syntax: SyntaxPreset,\n): string {\n let result = html;\n\n for (const tag of mergeTags) {\n const escaped = escapeRegExp(tag.value);\n const pattern = new RegExp(`(?<!data-merge-tag=\")${escaped}`, \"g\");\n result = result.replace(pattern, (match) => {\n const label = getMergeTagLabel(match, mergeTags);\n return `<span data-merge-tag=\"${match}\">${label}</span>`;\n });\n }\n\n const logicRegex = new RegExp(\n `(?<!data-logic-merge-tag=\")${syntax.logic.source}`,\n syntax.logic.flags,\n );\n result = result.replace(logicRegex, (match) => {\n const keyword = getLogicMergeTagKeyword(match, syntax);\n return `<span data-logic-merge-tag=\"${match}\">${keyword}</span>`;\n });\n\n return result;\n}\n\nexport function isLogicMergeTagValue(\n value: string,\n syntax: SyntaxPreset,\n): boolean {\n return anchoredRegex(syntax.logic).test(value?.trim() || \"\");\n}\n\nexport function getLogicMergeTagKeyword(\n value: string,\n syntax: SyntaxPreset,\n): string {\n const regex = new RegExp(\n syntax.logic.source,\n syntax.logic.flags.replace(\"g\", \"\"),\n );\n const match = value.match(regex);\n return match && match[1] ? match[1].toUpperCase() : value;\n}\n\nexport function resolveHtmlLogicMergeTagLabels(\n html: string,\n syntax: SyntaxPreset,\n): string {\n return html.replace(\n /(<span[^>]*\\sdata-logic-merge-tag=\"([^\"]*)\"[^>]*>)(.*?)(<\\/span>)/g,\n (_match, openTag, value, _oldLabel, closeTag) => {\n const keyword = getLogicMergeTagKeyword(value, syntax);\n return `${openTag}${keyword}${closeTag}`;\n },\n );\n}\n","import type { SyntaxPreset, SyntaxPresetName } from \"./merge-tags\";\n\nexport type ViewportSize = \"desktop\" | \"tablet\" | \"mobile\";\n\nexport interface CustomFont {\n name: string;\n url: string;\n fallback?: string;\n}\n\nexport interface FontsConfig {\n defaultFallback?: string;\n defaultFont?: string;\n customFonts?: CustomFont[];\n}\n\nexport interface ExportResult {\n html: string;\n mjml: string;\n}\n\nexport interface MergeTag {\n label: string;\n value: string;\n}\n\nexport interface MediaResult {\n url: string;\n alt?: string;\n}\n\nexport interface MergeTagsConfig {\n syntax?: SyntaxPresetName | SyntaxPreset;\n tags?: MergeTag[];\n onRequest?: () => Promise<MergeTag | null>;\n}\n\nexport interface DisplayCondition {\n label: string;\n before: string;\n after: string;\n group?: string;\n description?: string;\n}\n\nexport interface DisplayConditionsConfig {\n conditions: DisplayCondition[];\n allowCustom?: boolean;\n}\n\nexport interface ThemeOverrides {\n bg?: string;\n bgElevated?: string;\n bgHover?: string;\n bgActive?: string;\n border?: string;\n borderLight?: string;\n text?: string;\n textMuted?: string;\n textDim?: string;\n primary?: string;\n primaryHover?: string;\n primaryLight?: string;\n secondary?: string;\n secondaryHover?: string;\n secondaryLight?: string;\n success?: string;\n successLight?: string;\n warning?: string;\n warningLight?: string;\n danger?: string;\n dangerLight?: string;\n canvasBg?: string;\n}\n\nexport class SdkError extends Error {\n constructor(\n message: string,\n public readonly statusCode?: number,\n ) {\n super(message);\n this.name = \"SdkError\";\n }\n\n get isNotFound(): boolean {\n return this.statusCode === 404;\n }\n\n get isUnauthorized(): boolean {\n return this.statusCode === 401;\n }\n\n get isServerError(): boolean {\n return this.statusCode !== undefined && this.statusCode >= 500;\n }\n}\n"],"mappings":"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","names":[]}
|