@cymbal/atoms-email-renderer 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs ADDED
@@ -0,0 +1,964 @@
1
+ import { render, Html, Head, Body, Container, Section, Button, Text, Column, Row, Hr, Img, Link, Heading } from '@react-email/components';
2
+ import React from 'react';
3
+ import { defaultStyles } from '@cymbal/legos';
4
+ import '@primer/octicons-react';
5
+ import 'date-fns';
6
+ import 'date-fns-tz';
7
+ import 'slate';
8
+ import 'date-fns/addMinutes';
9
+ import 'date-fns/differenceInMinutes';
10
+ import 'date-fns/format';
11
+ import 'date-fns/addHours';
12
+ import 'date-fns/differenceInHours';
13
+ import 'date-fns/getHours';
14
+ import 'date-fns/getMinutes';
15
+ import 'date-fns/isValid';
16
+ import 'date-fns/parse';
17
+ import 'slate-react';
18
+ import 'uuid';
19
+ import '@dnd-kit/core';
20
+
21
+ const envVariables = {
22
+ etixOAuth2Params: {
23
+ clientId: process.env.ETIX_OAUTH2_CLIENT_ID ?? "",
24
+ clientSecret: process.env.ETIX_OAUTH2_CLIENT_SECRET ?? "",
25
+ redirectUri: "https://manager.cymbal.co/oauth2/etix/callback"
26
+ },
27
+ eventbriteOAuth2Params: {
28
+ apiKey: process.env.EVENTBRITE_OAUTH2_API_KEY ?? "",
29
+ clientSecret: process.env.EVENTBRITE_OAUTH2_CLIENT_SECRET ?? ""
30
+ },
31
+ shopifyOAuth2Params: {
32
+ clientId: process.env.SHOPIFY_OAUTH2_CLIENT_ID ?? "",
33
+ clientSecret: process.env.SHOPIFY_OAUTH2_CLIENT_SECRET ?? ""
34
+ },
35
+ universeOAuth2Params: {
36
+ clientId: "26360beb48fefbbb4c45e0e4053123272a03fd4cf3eae54f5dd4620520c819d3",
37
+ clientSecret: "4e46048f9a7c74271b9907f25663dd5d9131159b70dea225a6808f8d2200beab",
38
+ redirectUri: "https://manager.cymbal.co/oauth2/universe/callback"
39
+ },
40
+ turnstileSecretKey: process.env.TURNSTILE_SECRET_KEY ?? ""
41
+ };
42
+ const envConfigRecord = {
43
+ development: {
44
+ ...envVariables,
45
+ eventbriteOAuth2Params: {
46
+ ...envVariables.eventbriteOAuth2Params,
47
+ redirectUri: "http://localhost:3031/oauth2/eventbrite/callback"
48
+ },
49
+ shopifyOAuth2Params: {
50
+ ...envVariables.shopifyOAuth2Params,
51
+ redirectUri: "http://localhost:3031/oauth2/shopify/callback"
52
+ },
53
+ universeOAuth2Params: {
54
+ ...envVariables.universeOAuth2Params,
55
+ redirectUri: "https://localhost:3031/oauth2/universe/callback"
56
+ },
57
+ showclixLoginUrl: "https://admin-demo.showclix.com/api/registration",
58
+ showclixEventBaseUrl: "https://www-demo.showclix.com/event"
59
+ },
60
+ staging: {
61
+ ...envVariables,
62
+ eventbriteOAuth2Params: {
63
+ ...envVariables.eventbriteOAuth2Params,
64
+ redirectUri: "https://staging-manager.cymbal.co/oauth2/eventbrite/callback"
65
+ },
66
+ shopifyOAuth2Params: {
67
+ ...envVariables.shopifyOAuth2Params,
68
+ redirectUri: "https://staging-manager.cymbal.co/oauth2/shopify/callback"
69
+ },
70
+ universeOAuth2Params: {
71
+ ...envVariables.universeOAuth2Params,
72
+ redirectUri: "https://staging-manager.cymbal.co/oauth2/universe/callback"
73
+ },
74
+ showclixLoginUrl: "https://admin-demo.showclix.com/api/registration",
75
+ showclixEventBaseUrl: "https://www-demo.showclix.com/event"
76
+ },
77
+ production: {
78
+ ...envVariables,
79
+ eventbriteOAuth2Params: {
80
+ ...envVariables.eventbriteOAuth2Params,
81
+ redirectUri: "https://manager.cymbal.co/oauth2/eventbrite/callback"
82
+ },
83
+ shopifyOAuth2Params: {
84
+ ...envVariables.shopifyOAuth2Params,
85
+ redirectUri: "https://manager.cymbal.co/oauth2/shopify/callback"
86
+ },
87
+ universeOAuth2Params: {
88
+ ...envVariables.universeOAuth2Params,
89
+ redirectUri: "https://manager.cymbal.co/oauth2/universe/callback"
90
+ },
91
+ showclixLoginUrl: "https://admin.showclix.com/api/registration",
92
+ showclixEventBaseUrl: "https://www.showclix.com/event"
93
+ }
94
+ };
95
+ const configRecord = {
96
+ development: {
97
+ env: "development",
98
+ host: "http://localhost:3031",
99
+ apiHost: "http://localhost:8080",
100
+ cachedApiHost: "http://localhost:8080",
101
+ homepageHost: "http://localhost:3029",
102
+ webHost: "http://localhost:3030",
103
+ trackingHost: "http://localhost:8081",
104
+ stripeApiKey: "pk_test_51LKSx9DUFJHrciOV6vQAOVOCPJWBZOPIQZ7MqDykKdRFk5oRGOc1OCZOzo3kIPJKr6tVr3jOJefmKZmiSMRPJtwq007p0vVP57",
105
+ turnstileSiteKey: "1x00000000000000000000AA"
106
+ // AA to always succeed, AB to always fail
107
+ },
108
+ staging: {
109
+ env: "staging",
110
+ host: "https://staging-manager.cymbal.co",
111
+ apiHost: "https://staging-api.cymbal.co",
112
+ cachedApiHost: "https://staging-cache-api.cymbal.co",
113
+ homepageHost: "https://staging.cymbal.co",
114
+ webHost: "https://staging-app.cymbal.co",
115
+ trackingHost: "https://staging.cy.link",
116
+ stripeApiKey: "pk_test_51LKSx9DUFJHrciOV6vQAOVOCPJWBZOPIQZ7MqDykKdRFk5oRGOc1OCZOzo3kIPJKr6tVr3jOJefmKZmiSMRPJtwq007p0vVP57",
117
+ turnstileSiteKey: "0x4AAAAAADcxWmLeTC3FZ8Pt"
118
+ },
119
+ production: {
120
+ env: "production",
121
+ host: "https://manager.cymbal.co",
122
+ apiHost: "https://api.cymbal.co",
123
+ cachedApiHost: "https://cache-api.cymbal.co",
124
+ homepageHost: "https://cymbal.co",
125
+ webHost: "https://app.cymbal.co",
126
+ trackingHost: "https://cy.link",
127
+ stripeApiKey: "pk_live_51LKSx9DUFJHrciOVruTpEgzJ8HU2rnpfUoBvSFrwULMpRCzLoVaEeLI4crV4GhykMN2cgNAmmVhLbXK2rMiBIASp00HdegT6uO",
128
+ turnstileSiteKey: "0x4AAAAAADcxWmLeTC3FZ8Pt"
129
+ }
130
+ };
131
+ const getEnv = () => {
132
+ switch (process.env.NEXT_PUBLIC_ENV) {
133
+ case "production":
134
+ case "staging":
135
+ case "development":
136
+ return process.env.NEXT_PUBLIC_ENV;
137
+ default:
138
+ return "development";
139
+ }
140
+ };
141
+ configRecord[getEnv()] ?? configRecord["development"];
142
+ envConfigRecord[getEnv()] ?? envConfigRecord["development"];
143
+
144
+ const allMarksKeys = [
145
+ "color",
146
+ "fontWeight",
147
+ "fontStyle",
148
+ "textDecoration",
149
+ "textTransform",
150
+ "fontSize",
151
+ "fontFamily",
152
+ "lineHeight",
153
+ "letterSpacing"
154
+ ];
155
+ new Set(allMarksKeys);
156
+
157
+ const MIN_LAYOUT_BASIS = 1;
158
+ const DEFAULT_LAYOUT_BASIS = 100;
159
+
160
+ ({
161
+ linkColor: defaultStyles.page_style.link_color,
162
+ pagesMaxWidth: defaultStyles.page_style.pages_max_width,
163
+ underlineLinks: defaultStyles.page_style.underline_links
164
+ });
165
+ const zeroPadding = { top: 0, right: 0, bottom: 0, left: 0 };
166
+ function normalizePadding(padding) {
167
+ if (padding === null || padding === void 0) {
168
+ return { ...zeroPadding };
169
+ }
170
+ return { ...zeroPadding, ...padding };
171
+ }
172
+ function resolveLayoutVisualStyleValue({
173
+ override,
174
+ global
175
+ }) {
176
+ if (override === void 0 || override === null) {
177
+ return global;
178
+ }
179
+ return override;
180
+ }
181
+ function mergeResolvedLayoutWidth(overrides, global) {
182
+ if (overrides === null) {
183
+ return { ...global.width };
184
+ }
185
+ const widthOverride = overrides.width;
186
+ if (widthOverride === void 0 || widthOverride === null) {
187
+ return { ...global.width };
188
+ }
189
+ if (widthOverride && typeof widthOverride === "object" && "type" in widthOverride && widthOverride.type === "max") {
190
+ const legacyMaxWidth = widthOverride;
191
+ return {
192
+ basis: global.width.basis,
193
+ max: legacyMaxWidth.max ?? 200
194
+ };
195
+ }
196
+ if (widthOverride && typeof widthOverride === "object" && "type" in widthOverride && widthOverride.type === "maxWidth") {
197
+ const legacyMaxWidth = widthOverride;
198
+ return {
199
+ basis: global.width.basis,
200
+ max: legacyMaxWidth.maxWidth ?? 200
201
+ };
202
+ }
203
+ if (widthOverride && typeof widthOverride === "object" && "type" in widthOverride && widthOverride.type === "basis") {
204
+ const legacyBasis = widthOverride;
205
+ return {
206
+ basis: legacyBasis.basis ?? DEFAULT_LAYOUT_BASIS,
207
+ max: "none"
208
+ };
209
+ }
210
+ const normalizedWidth = widthOverride;
211
+ return {
212
+ basis: normalizedWidth.basis ?? global.width.basis,
213
+ max: normalizedWidth.max !== void 0 ? normalizedWidth.max : global.width.max
214
+ };
215
+ }
216
+ function resolveTextStyles(overrides, global) {
217
+ if (overrides === null) {
218
+ return { ...global };
219
+ }
220
+ return {
221
+ color: overrides.color ?? global.color,
222
+ fontWeight: overrides.fontWeight ?? global.fontWeight,
223
+ fontStyle: overrides.fontStyle ?? global.fontStyle,
224
+ textTransform: overrides.textTransform ?? global.textTransform,
225
+ textDecoration: overrides.textDecoration ?? global.textDecoration,
226
+ fontSizePx: overrides.fontSizePx ?? global.fontSizePx,
227
+ fontFamily: overrides.fontFamily ?? global.fontFamily,
228
+ align: overrides.align ?? global.align,
229
+ lineHeight: overrides.lineHeight ?? global.lineHeight,
230
+ letterSpacingEm: overrides.letterSpacingEm ?? global.letterSpacingEm
231
+ };
232
+ }
233
+ function resolveDividerStyles(overrides, global) {
234
+ if (overrides === null) {
235
+ return { ...global };
236
+ }
237
+ return {
238
+ color: overrides.color ?? global.color,
239
+ width: overrides.width ?? global.width,
240
+ style: overrides.style ?? global.style,
241
+ side: overrides.side ?? global.side
242
+ };
243
+ }
244
+ function resolveColumnsStyles(overrides, global) {
245
+ if (overrides === null) {
246
+ return { ...global };
247
+ }
248
+ return {
249
+ gap: overrides.gap ?? global.gap,
250
+ verticalAlign: overrides.verticalAlign ?? global.verticalAlign,
251
+ horizontalAlign: overrides.horizontalAlign ?? global.horizontalAlign,
252
+ format: overrides.format ?? global.format
253
+ };
254
+ }
255
+ function effectiveBlockHorizontalAlign({
256
+ layoutHorizontalAlign,
257
+ parentRowBlockHorizontalAlign
258
+ }) {
259
+ if (layoutHorizontalAlign !== "inherit") {
260
+ return layoutHorizontalAlign;
261
+ }
262
+ if (parentRowBlockHorizontalAlign !== null) {
263
+ return parentRowBlockHorizontalAlign;
264
+ }
265
+ return "left";
266
+ }
267
+ function resolveRowsStyles(overrides, global) {
268
+ if (overrides === null) {
269
+ return { ...global };
270
+ }
271
+ return {
272
+ gap: overrides.gap ?? global.gap,
273
+ horizontalAlign: overrides.horizontalAlign ?? global.horizontalAlign
274
+ };
275
+ }
276
+ function resolvePadding(overrides, global) {
277
+ if (overrides === null) {
278
+ return { ...global };
279
+ }
280
+ return {
281
+ top: overrides.top ?? global.top,
282
+ right: overrides.right ?? global.right,
283
+ bottom: overrides.bottom ?? global.bottom,
284
+ left: overrides.left ?? global.left
285
+ };
286
+ }
287
+ function getRootTextStyles(textType, globalAtomStyles) {
288
+ switch (textType) {
289
+ case "title":
290
+ return globalAtomStyles.titleStyles;
291
+ case "subtitle":
292
+ return globalAtomStyles.subtitleStyles;
293
+ case "heading":
294
+ return globalAtomStyles.headingStyles;
295
+ case "subheading":
296
+ return globalAtomStyles.subheadingStyles;
297
+ case "section":
298
+ return globalAtomStyles.sectionStyles;
299
+ case "body":
300
+ return globalAtomStyles.bodyStyles;
301
+ case "accent":
302
+ return globalAtomStyles.accentStyles;
303
+ case "caption":
304
+ return globalAtomStyles.captionStyles;
305
+ case "promo":
306
+ return {
307
+ textStyles: globalAtomStyles.promoStyles.textStyles,
308
+ layoutStyles: {
309
+ ...globalAtomStyles.promoStyles.layoutStyles,
310
+ padding: globalAtomStyles.promoStyles.innerPadding
311
+ }
312
+ };
313
+ }
314
+ }
315
+ function getRootLayoutStyles(atom, globalAtomStyles) {
316
+ switch (atom.type) {
317
+ case "text":
318
+ return getRootTextStyles(atom.textType, globalAtomStyles).layoutStyles;
319
+ case "button":
320
+ return globalAtomStyles.buttonStyles.layoutStyles;
321
+ case "image":
322
+ return globalAtomStyles.imageStyles.layoutStyles;
323
+ case "divider":
324
+ return globalAtomStyles.dividerStyles.layoutStyles;
325
+ case "option":
326
+ return globalAtomStyles.optionStyles.layoutStyles;
327
+ case "input":
328
+ return globalAtomStyles.inputStyles.layoutStyles;
329
+ case "contest":
330
+ return globalAtomStyles.buttonStyles.layoutStyles;
331
+ case "question":
332
+ return globalAtomStyles.questionStyles.layoutStyles;
333
+ case "form":
334
+ return globalAtomStyles.formStyles.layoutStyles;
335
+ case "automation-upcoming-events":
336
+ case "automation-triggered-event":
337
+ return globalAtomStyles.rowsStyles.layoutStyles;
338
+ case "rows":
339
+ return globalAtomStyles.rowsStyles.layoutStyles;
340
+ case "columns":
341
+ return globalAtomStyles.columnsStyles.layoutStyles;
342
+ }
343
+ }
344
+ function resolveAtomLayoutStyles(atom, globalAtomStyles) {
345
+ const overrides = atom.layoutStyles;
346
+ const global = getRootLayoutStyles(atom, globalAtomStyles);
347
+ if (overrides === null) {
348
+ return { ...global };
349
+ }
350
+ const width = mergeResolvedLayoutWidth(overrides, global);
351
+ const background = resolveLayoutVisualStyleValue({
352
+ override: overrides.background,
353
+ global: global.background
354
+ });
355
+ const border = resolveLayoutVisualStyleValue({
356
+ override: overrides.border,
357
+ global: global.border
358
+ });
359
+ return {
360
+ margin: overrides.margin !== null ? overrides.margin : global.margin,
361
+ padding: normalizePadding(overrides.padding !== null ? overrides.padding : global.padding),
362
+ background,
363
+ border,
364
+ borderRadius: overrides.borderRadius ?? global.borderRadius,
365
+ width,
366
+ horizontalAlign: overrides.horizontalAlign ?? global.horizontalAlign
367
+ };
368
+ }
369
+ function horizontalBorderInsetPx(border) {
370
+ const borderWidth = border.width;
371
+ const side = border.side;
372
+ if (side === "all") {
373
+ return borderWidth * 2;
374
+ }
375
+ if (side === "left") {
376
+ return borderWidth;
377
+ }
378
+ if (side === "right") {
379
+ return borderWidth;
380
+ }
381
+ return 0;
382
+ }
383
+ function computeAtomContentWidth(boxWidth, layoutStyles) {
384
+ const borderW = layoutStyles.border !== "none" ? horizontalBorderInsetPx(layoutStyles.border) : 0;
385
+ const padLeft = layoutStyles.padding?.left ?? 0;
386
+ const padRight = layoutStyles.padding?.right ?? 0;
387
+ return Math.max(0, boxWidth - padLeft - padRight - borderW);
388
+ }
389
+ function calculateRowChildWidth({
390
+ contentWidth,
391
+ child,
392
+ globalAtomStyles
393
+ }) {
394
+ const resolved = resolveAtomLayoutStyles(child, globalAtomStyles);
395
+ const cap = resolved.width.max;
396
+ if (cap === "none") {
397
+ return contentWidth;
398
+ }
399
+ return Math.min(cap, contentWidth);
400
+ }
401
+ const COLUMN_WIDTH_SPLIT_EPS = 1e-6;
402
+ function calculateColumnChildWidths({
403
+ contentWidth,
404
+ children,
405
+ gap,
406
+ globalAtomStyles
407
+ }) {
408
+ const childCount = children.length;
409
+ if (childCount === 0) {
410
+ return [];
411
+ }
412
+ const totalGap = gap * (childCount - 1);
413
+ const distributable = Math.max(0, contentWidth - totalGap);
414
+ const resolvedLayouts = children.map((child) => resolveAtomLayoutStyles(child, globalAtomStyles));
415
+ const bases = resolvedLayouts.map((layoutStyles) => layoutStyles.width.basis);
416
+ const caps = resolvedLayouts.map(
417
+ (layoutStyles) => layoutStyles.width.max === "none" ? Number.POSITIVE_INFINITY : layoutStyles.width.max
418
+ );
419
+ const widths = Array(childCount).fill(0);
420
+ const active = new Set(Array.from({ length: childCount }, (_, index) => index));
421
+ let remaining = distributable;
422
+ let guard = 0;
423
+ while (active.size > 0 && guard < childCount + 24) {
424
+ guard += 1;
425
+ const activeList = [...active].sort((indexA, indexB) => indexA - indexB);
426
+ const sumBasis = activeList.reduce((sum, index) => sum + bases[index], 0);
427
+ const denominator = sumBasis > 0 ? sumBasis : MIN_LAYOUT_BASIS;
428
+ const tentative = Array(childCount).fill(0);
429
+ for (const index of activeList) {
430
+ tentative[index] = bases[index] / denominator * remaining;
431
+ }
432
+ const clampedIndices = [];
433
+ for (const index of activeList) {
434
+ if (caps[index] < Number.POSITIVE_INFINITY && tentative[index] > caps[index] + COLUMN_WIDTH_SPLIT_EPS) {
435
+ clampedIndices.push(index);
436
+ }
437
+ }
438
+ if (clampedIndices.length === 0) {
439
+ for (const index of activeList) {
440
+ widths[index] = tentative[index];
441
+ }
442
+ break;
443
+ }
444
+ clampedIndices.sort((indexA, indexB) => indexA - indexB);
445
+ for (const index of clampedIndices) {
446
+ const assigned = caps[index];
447
+ widths[index] = assigned;
448
+ remaining -= assigned;
449
+ active.delete(index);
450
+ }
451
+ if (remaining <= COLUMN_WIDTH_SPLIT_EPS) {
452
+ for (const index of activeList) {
453
+ if (active.has(index)) {
454
+ widths[index] = 0;
455
+ active.delete(index);
456
+ }
457
+ }
458
+ break;
459
+ }
460
+ }
461
+ return widths;
462
+ }
463
+
464
+ const ATOM_SOCIAL_ORDINAL_TO_PLATFORM = {
465
+ facebookOrdinal: "facebook",
466
+ xOrdinal: "x",
467
+ instagramOrdinal: "instagram",
468
+ tiktokOrdinal: "tiktok",
469
+ youtubeOrdinal: "youtube",
470
+ websiteOrdinal: "website",
471
+ spotifyOrdinal: "spotify",
472
+ discordOrdinal: "discord",
473
+ soundcloudOrdinal: "soundcloud",
474
+ appleMusicOrdinal: "apple_music",
475
+ threadsOrdinal: "threads"
476
+ };
477
+ Object.entries(ATOM_SOCIAL_ORDINAL_TO_PLATFORM).reduce(
478
+ (accumulator, [ordinalKey, platform]) => {
479
+ accumulator[platform] = ordinalKey;
480
+ return accumulator;
481
+ },
482
+ {}
483
+ );
484
+ function ensureUrlHasProtocolForPreview(url) {
485
+ const trimmed = url.trim();
486
+ if (trimmed === "") {
487
+ return "";
488
+ }
489
+ if (/^https?:\/\//i.test(trimmed)) {
490
+ return trimmed;
491
+ }
492
+ if (trimmed.startsWith("mailto:")) {
493
+ return trimmed;
494
+ }
495
+ return `https://${trimmed}`;
496
+ }
497
+
498
+ const atomBorderToReactStyle = (border) => {
499
+ const side = border.side;
500
+ const spec = `${border.width}px ${border.style} ${border.color}`;
501
+ const none = "none";
502
+ if (side === "all") {
503
+ return { border: spec };
504
+ }
505
+ if (side === "top") {
506
+ return { borderTop: spec, borderRight: none, borderBottom: none, borderLeft: none };
507
+ }
508
+ if (side === "right") {
509
+ return { borderTop: none, borderRight: spec, borderBottom: none, borderLeft: none };
510
+ }
511
+ if (side === "bottom") {
512
+ return { borderTop: none, borderRight: none, borderBottom: spec, borderLeft: none };
513
+ }
514
+ return { borderTop: none, borderRight: none, borderBottom: none, borderLeft: spec };
515
+ };
516
+
517
+ const SYSTEM_SAFE_FONTS = /* @__PURE__ */ new Set([
518
+ "Arial",
519
+ "Arial Black",
520
+ "Arial Narrow",
521
+ "Calibri",
522
+ "Consolas",
523
+ "Courier",
524
+ "Courier New",
525
+ "Franklin Gothic",
526
+ "Garamond",
527
+ "Georgia",
528
+ "Helvetica",
529
+ "Lucida Console",
530
+ "Lucida Grande",
531
+ "Tahoma",
532
+ "Times New Roman",
533
+ "Trebuchet MS",
534
+ "Verdana"
535
+ ]);
536
+ function collectFontFamilies(doc) {
537
+ const families = /* @__PURE__ */ new Set();
538
+ const rootStyles = doc.globalAtomStyles;
539
+ const addFromTextStyles = (ts) => {
540
+ if (!ts) {
541
+ return;
542
+ }
543
+ if (ts.fontFamily) {
544
+ families.add(ts.fontFamily);
545
+ }
546
+ };
547
+ addFromTextStyles(rootStyles.titleStyles.textStyles);
548
+ addFromTextStyles(rootStyles.subtitleStyles.textStyles);
549
+ addFromTextStyles(rootStyles.headingStyles.textStyles);
550
+ addFromTextStyles(rootStyles.subheadingStyles.textStyles);
551
+ addFromTextStyles(rootStyles.sectionStyles.textStyles);
552
+ addFromTextStyles(rootStyles.bodyStyles.textStyles);
553
+ addFromTextStyles(rootStyles.accentStyles.textStyles);
554
+ addFromTextStyles(rootStyles.captionStyles.textStyles);
555
+ addFromTextStyles(rootStyles.promoStyles.textStyles);
556
+ addFromTextStyles(rootStyles.inputStyles.textStyles);
557
+ addFromTextStyles(rootStyles.optionStyles.textStyles);
558
+ const walkAtom = (atom) => {
559
+ if (atom.type === "text" || atom.type === "button" || atom.type === "input" || atom.type === "contest" || atom.type === "option") {
560
+ addFromTextStyles(atom.textStyles);
561
+ }
562
+ if ("children" in atom && atom.children) {
563
+ atom.children.forEach(walkAtom);
564
+ }
565
+ };
566
+ walkAtom(doc.rootRow);
567
+ return [...families].filter((f) => !SYSTEM_SAFE_FONTS.has(f));
568
+ }
569
+ function backgroundColorFromAtomBg(bg) {
570
+ if (bg === "none") {
571
+ return void 0;
572
+ }
573
+ if (bg.color) {
574
+ return bg.color;
575
+ }
576
+ return void 0;
577
+ }
578
+ function cornerRadiusToCssValue(radius) {
579
+ return `${radius.topLeft}px ${radius.topRight}px ${radius.bottomRight}px ${radius.bottomLeft}px`;
580
+ }
581
+ function layoutHorizontalBlockStyle(horizontalAlign) {
582
+ return {
583
+ display: "flex",
584
+ flexDirection: "row",
585
+ justifyContent: horizontalAlign === "left" ? "flex-start" : horizontalAlign === "center" ? "center" : "flex-end",
586
+ width: "100%"
587
+ };
588
+ }
589
+ function layoutToWrapperStyle(ls, parentRowBlockHorizontalAlign, forceBlockHorizontalAlign) {
590
+ const paddingTop = (ls.padding?.top ?? 0) + (ls.margin?.top ?? 0);
591
+ const paddingBottom = (ls.padding?.bottom ?? 0) + (ls.margin?.bottom ?? 0);
592
+ const paddingLeft = ls.padding?.left ?? 0;
593
+ const paddingRight = ls.padding?.right ?? 0;
594
+ const hasPadding = paddingTop > 0 || paddingRight > 0 || paddingBottom > 0 || paddingLeft > 0;
595
+ const blockAlign = forceBlockHorizontalAlign !== void 0 ? forceBlockHorizontalAlign : effectiveBlockHorizontalAlign({
596
+ layoutHorizontalAlign: ls.horizontalAlign,
597
+ parentRowBlockHorizontalAlign
598
+ });
599
+ return {
600
+ ...hasPadding ? { padding: `${paddingTop}px ${paddingRight}px ${paddingBottom}px ${paddingLeft}px` } : {},
601
+ ...backgroundColorFromAtomBg(ls.background) ? { backgroundColor: backgroundColorFromAtomBg(ls.background) } : {},
602
+ ...ls.border !== "none" ? atomBorderToReactStyle(ls.border) : {},
603
+ ...ls.borderRadius ? { borderRadius: cornerRadiusToCssValue(ls.borderRadius) } : {},
604
+ ...layoutHorizontalBlockStyle(blockAlign)
605
+ };
606
+ }
607
+ function textStyleToCss(styles) {
608
+ return {
609
+ color: styles.color,
610
+ fontWeight: Number(styles.fontWeight),
611
+ fontStyle: styles.fontStyle,
612
+ textTransform: styles.textTransform,
613
+ textDecoration: styles.textDecoration,
614
+ fontSize: styles.fontSizePx,
615
+ fontFamily: styles.fontFamily,
616
+ textAlign: styles.align,
617
+ lineHeight: styles.lineHeight,
618
+ letterSpacing: `${styles.letterSpacingEm}em`,
619
+ margin: 0
620
+ };
621
+ }
622
+ function headingLevel(textType) {
623
+ switch (textType) {
624
+ case "title":
625
+ return "h1";
626
+ case "subtitle":
627
+ return "h2";
628
+ case "heading":
629
+ return "h3";
630
+ default:
631
+ return "h1";
632
+ }
633
+ }
634
+ const EmailTextAtom = ({ atom, ctx }) => {
635
+ const rootTextStyles = getRootTextStyles(atom.textType ?? "body", ctx.globalAtomStyles);
636
+ const resolvedText = resolveTextStyles(atom.textStyles, rootTextStyles.textStyles);
637
+ const resolvedLayout = resolveAtomLayoutStyles(atom, ctx.globalAtomStyles);
638
+ const wrapperStyle = layoutToWrapperStyle(resolvedLayout, ctx.parentRowBlockHorizontalAlign);
639
+ const cssStyles = textStyleToCss(resolvedText);
640
+ const inner = /* @__PURE__ */ React.createElement("span", { dangerouslySetInnerHTML: { __html: atom.text } });
641
+ if (atom.textType === "title" || atom.textType === "subtitle" || atom.textType === "heading") {
642
+ return /* @__PURE__ */ React.createElement(Heading, { as: headingLevel(atom.textType), style: { ...wrapperStyle, ...cssStyles, width: "100%" } }, inner);
643
+ }
644
+ return /* @__PURE__ */ React.createElement(Text, { style: { ...wrapperStyle, ...cssStyles, width: "100%" } }, inner);
645
+ };
646
+ const EmailButtonAtom = ({ atom, ctx }) => {
647
+ const resolvedText = resolveTextStyles(atom.textStyles, ctx.globalAtomStyles.buttonStyles.textStyles);
648
+ const resolvedInnerPadding = resolvePadding(atom.innerPadding, ctx.globalAtomStyles.buttonStyles.innerPadding);
649
+ const resolvedLayout = resolveAtomLayoutStyles(atom, ctx.globalAtomStyles);
650
+ const wrapperStyle = layoutToWrapperStyle(resolvedLayout, ctx.parentRowBlockHorizontalAlign);
651
+ const cssStyles = textStyleToCss(resolvedText);
652
+ const buttonStyle = {
653
+ ...cssStyles,
654
+ display: "block",
655
+ width: "100%",
656
+ boxSizing: "border-box",
657
+ textDecoration: "none",
658
+ padding: `${resolvedInnerPadding.top}px ${resolvedInnerPadding.right}px ${resolvedInnerPadding.bottom}px ${resolvedInnerPadding.left}px`,
659
+ maxWidth: "100%"
660
+ };
661
+ return /* @__PURE__ */ React.createElement("div", { style: wrapperStyle }, /* @__PURE__ */ React.createElement(Button, { href: atom.href || "#", style: buttonStyle }, /* @__PURE__ */ React.createElement("span", { dangerouslySetInnerHTML: { __html: atom.text } })));
662
+ };
663
+ const EmailImageAtom = ({ atom, ctx }) => {
664
+ const resolvedLayout = resolveAtomLayoutStyles(atom, ctx.globalAtomStyles);
665
+ const wrapperStyle = layoutToWrapperStyle(resolvedLayout, ctx.parentRowBlockHorizontalAlign);
666
+ const imgStyle = {
667
+ width: "100%",
668
+ display: "block",
669
+ ...resolvedLayout.borderRadius ? { borderRadius: cornerRadiusToCssValue(resolvedLayout.borderRadius) } : {}
670
+ };
671
+ const img = /* @__PURE__ */ React.createElement(Img, { src: atom.src, alt: "", style: imgStyle });
672
+ if (atom.href) {
673
+ return /* @__PURE__ */ React.createElement("div", { style: wrapperStyle }, /* @__PURE__ */ React.createElement(Link, { href: ensureUrlHasProtocolForPreview(atom.href), style: { display: "inline-block", width: "100%" } }, img));
674
+ }
675
+ return /* @__PURE__ */ React.createElement("div", { style: wrapperStyle }, img);
676
+ };
677
+ const EmailDividerAtom = ({ atom, ctx }) => {
678
+ const resolvedDivider = resolveDividerStyles(atom.dividerStyles, ctx.globalAtomStyles.dividerStyles.dividerStyles);
679
+ const resolvedLayout = resolveAtomLayoutStyles(atom, ctx.globalAtomStyles);
680
+ const wrapperStyle = layoutToWrapperStyle(resolvedLayout, ctx.parentRowBlockHorizontalAlign);
681
+ return /* @__PURE__ */ React.createElement(
682
+ Hr,
683
+ {
684
+ style: {
685
+ ...wrapperStyle,
686
+ ...atomBorderToReactStyle(resolvedDivider)
687
+ }
688
+ }
689
+ );
690
+ };
691
+ const fieldBoxStyle = {
692
+ border: "1px solid #555",
693
+ borderRadius: 8,
694
+ boxSizing: "border-box",
695
+ color: "#999",
696
+ fontSize: 14,
697
+ minHeight: 40,
698
+ padding: "10px 12px",
699
+ width: "100%"
700
+ };
701
+ const EmailInputAtom = ({ atom, ctx }) => {
702
+ const resolvedLayout = resolveAtomLayoutStyles(atom, ctx.globalAtomStyles);
703
+ const wrapperStyle = layoutToWrapperStyle(resolvedLayout, ctx.parentRowBlockHorizontalAlign);
704
+ const resolvedText = resolveTextStyles(atom.textStyles, ctx.globalAtomStyles.inputStyles.textStyles);
705
+ const resolvedInnerPadding = resolvePadding(atom.innerPadding, ctx.globalAtomStyles.inputStyles.innerPadding);
706
+ const fieldStyle = {
707
+ ...fieldBoxStyle,
708
+ ...textStyleToCss(resolvedText),
709
+ backgroundColor: backgroundColorFromAtomBg(resolvedLayout.background),
710
+ border: resolvedLayout.border !== "none" ? `${resolvedLayout.border.width}px ${resolvedLayout.border.style} ${resolvedLayout.border.color}` : fieldBoxStyle.border,
711
+ borderRadius: cornerRadiusToCssValue(resolvedLayout.borderRadius),
712
+ padding: `${resolvedInnerPadding.top}px ${resolvedInnerPadding.right}px ${resolvedInnerPadding.bottom}px ${resolvedInnerPadding.left}px`
713
+ };
714
+ return /* @__PURE__ */ React.createElement("div", { style: wrapperStyle }, /* @__PURE__ */ React.createElement("div", { style: fieldStyle }, atom.placeholder || "Text input"));
715
+ };
716
+ const EmailQuestionAtom = ({ atom, ctx }) => {
717
+ const resolvedLayout = resolveAtomLayoutStyles(atom, ctx.globalAtomStyles);
718
+ const wrapperStyle = layoutToWrapperStyle(resolvedLayout, ctx.parentRowBlockHorizontalAlign);
719
+ const resolvedInnerPadding = resolvePadding(atom.innerPadding, ctx.globalAtomStyles.questionStyles.innerPadding);
720
+ const dropdownStyle = {
721
+ ...fieldBoxStyle,
722
+ padding: `${resolvedInnerPadding.top}px ${resolvedInnerPadding.right}px ${resolvedInnerPadding.bottom}px ${resolvedInnerPadding.left}px`
723
+ };
724
+ const optionNodes = atom.children.map((option) => /* @__PURE__ */ React.createElement(
725
+ Text,
726
+ {
727
+ key: option.id,
728
+ style: {
729
+ ...textStyleToCss(resolveTextStyles(option.textStyles, ctx.globalAtomStyles.optionStyles.textStyles)),
730
+ margin: "0 0 6px 0"
731
+ }
732
+ },
733
+ "[ ] ",
734
+ option.text
735
+ ));
736
+ return /* @__PURE__ */ React.createElement("div", { style: wrapperStyle }, atom.questionType === "dropdown" ? /* @__PURE__ */ React.createElement("div", { style: dropdownStyle }, "Select an option") : optionNodes);
737
+ };
738
+ const EmailOptionAtom = ({ atom, ctx }) => {
739
+ const resolvedLayout = resolveAtomLayoutStyles(atom, ctx.globalAtomStyles);
740
+ const wrapperStyle = layoutToWrapperStyle(resolvedLayout, ctx.parentRowBlockHorizontalAlign);
741
+ const resolvedText = resolveTextStyles(atom.textStyles, ctx.globalAtomStyles.optionStyles.textStyles);
742
+ return /* @__PURE__ */ React.createElement("div", { style: wrapperStyle }, /* @__PURE__ */ React.createElement(Text, { style: { ...textStyleToCss(resolvedText), margin: 0 } }, atom.text));
743
+ };
744
+ const EmailContestAtom = ({ atom, ctx }) => {
745
+ const resolvedLayout = resolveAtomLayoutStyles(atom, ctx.globalAtomStyles);
746
+ const wrapperStyle = layoutToWrapperStyle(resolvedLayout, ctx.parentRowBlockHorizontalAlign);
747
+ const resolvedText = resolveTextStyles(atom.textStyles, ctx.globalAtomStyles.buttonStyles.textStyles);
748
+ const resolvedButtonLayout = resolvedLayout;
749
+ const resolvedInnerPadding = resolvePadding(atom.innerPadding, ctx.globalAtomStyles.buttonStyles.innerPadding);
750
+ const buttonBackground = resolvedButtonLayout.background !== "none" ? backgroundColorFromAtomBg(resolvedButtonLayout.background) : void 0;
751
+ const buttonStyle = {
752
+ ...textStyleToCss(resolvedText),
753
+ backgroundColor: buttonBackground,
754
+ borderRadius: cornerRadiusToCssValue(resolvedButtonLayout.borderRadius),
755
+ boxSizing: "border-box",
756
+ display: "block",
757
+ minHeight: Math.max(42, resolvedText.fontSizePx * 2.5),
758
+ padding: `${resolvedInnerPadding.top}px ${resolvedInnerPadding.right}px ${resolvedInnerPadding.bottom}px ${resolvedInnerPadding.left}px`,
759
+ textDecoration: "none",
760
+ width: "100%"
761
+ };
762
+ const label = atom.contestType === "facebook" ? "Share link on Facebook" : atom.contestType === "instagram" ? `Follow ${atom.identifier}` : "Share this contest";
763
+ return /* @__PURE__ */ React.createElement("div", { style: wrapperStyle }, /* @__PURE__ */ React.createElement(Button, { href: "#", style: buttonStyle }, label, " +", atom.entriesPerSubmission));
764
+ };
765
+ const EmailAutomationUpcomingEventsAtom = ({
766
+ atom,
767
+ ctx
768
+ }) => {
769
+ return null;
770
+ };
771
+ const EmailAutomationTriggeredEventAtom = ({
772
+ atom,
773
+ ctx
774
+ }) => {
775
+ return null;
776
+ };
777
+ const EmailFormAtom = ({ atom, ctx }) => {
778
+ const rowsAtom = {
779
+ atomKey: atom.atomKey,
780
+ type: "rows",
781
+ source: null,
782
+ children: atom.children,
783
+ rowsStyles: atom.rowsStyles,
784
+ layoutStyles: atom.layoutStyles
785
+ };
786
+ const belowSubmitRowsAtom = {
787
+ atomKey: atom.atomKey,
788
+ type: "rows",
789
+ source: null,
790
+ children: atom.belowSubmitChildren,
791
+ rowsStyles: null,
792
+ layoutStyles: null
793
+ };
794
+ return /* @__PURE__ */ React.createElement(Section, null, /* @__PURE__ */ React.createElement(EmailRowsAtom, { atom: rowsAtom, ctx }), atom.belowSubmitChildren.length > 0 && /* @__PURE__ */ React.createElement(EmailRowsAtom, { atom: belowSubmitRowsAtom, ctx }));
795
+ };
796
+ const EmailAtom = ({ atom, ctx }) => {
797
+ switch (atom.type) {
798
+ case "text":
799
+ return /* @__PURE__ */ React.createElement(EmailTextAtom, { atom, ctx });
800
+ case "button":
801
+ return /* @__PURE__ */ React.createElement(EmailButtonAtom, { atom, ctx });
802
+ case "image":
803
+ return /* @__PURE__ */ React.createElement(EmailImageAtom, { atom, ctx });
804
+ case "divider":
805
+ return /* @__PURE__ */ React.createElement(EmailDividerAtom, { atom, ctx });
806
+ case "option":
807
+ return /* @__PURE__ */ React.createElement(EmailOptionAtom, { atom, ctx });
808
+ case "rows":
809
+ return /* @__PURE__ */ React.createElement(EmailRowsAtom, { atom, ctx });
810
+ case "columns":
811
+ return /* @__PURE__ */ React.createElement(EmailColumnsAtom, { atom, ctx });
812
+ case "input":
813
+ return /* @__PURE__ */ React.createElement(EmailInputAtom, { atom, ctx });
814
+ case "question":
815
+ return /* @__PURE__ */ React.createElement(EmailQuestionAtom, { atom, ctx });
816
+ case "contest":
817
+ return /* @__PURE__ */ React.createElement(EmailContestAtom, { atom, ctx });
818
+ case "form":
819
+ return /* @__PURE__ */ React.createElement(EmailFormAtom, { atom, ctx });
820
+ case "automation-upcoming-events":
821
+ return /* @__PURE__ */ React.createElement(EmailAutomationUpcomingEventsAtom, { atom, ctx });
822
+ case "automation-triggered-event":
823
+ return /* @__PURE__ */ React.createElement(EmailAutomationTriggeredEventAtom, { atom, ctx });
824
+ }
825
+ };
826
+ const EmailRowsAtom = ({ atom, ctx }) => {
827
+ const resolvedLayout = resolveAtomLayoutStyles(atom, ctx.globalAtomStyles);
828
+ const resolvedRows = resolveRowsStyles(atom.rowsStyles, ctx.globalAtomStyles.rowsStyles.rowsStyles);
829
+ const wrapperStyle = layoutToWrapperStyle(resolvedLayout, ctx.parentRowBlockHorizontalAlign, "left");
830
+ const gap = resolvedRows.gap;
831
+ const innerWidth = computeAtomContentWidth(ctx.contentWidthPx, resolvedLayout);
832
+ const rowCrossAlign = resolvedRows.horizontalAlign === "left" ? "flex-start" : resolvedRows.horizontalAlign === "center" ? "center" : "flex-end";
833
+ const widthStyle = {
834
+ width: "100%",
835
+ ...resolvedLayout.width.max !== "none" ? { maxWidth: resolvedLayout.width.max } : {}
836
+ };
837
+ return /* @__PURE__ */ React.createElement(Section, { style: { ...wrapperStyle, ...widthStyle } }, /* @__PURE__ */ React.createElement(
838
+ "div",
839
+ {
840
+ style: {
841
+ width: "100%",
842
+ display: "flex",
843
+ flexDirection: "column",
844
+ alignItems: rowCrossAlign
845
+ }
846
+ },
847
+ atom.children.map((child, i) => {
848
+ const childResolved = resolveAtomLayoutStyles(child, ctx.globalAtomStyles);
849
+ const childMaxWidth = childResolved.width.max;
850
+ const slotOuterWidth = calculateRowChildWidth({
851
+ contentWidth: innerWidth,
852
+ child,
853
+ globalAtomStyles: ctx.globalAtomStyles
854
+ });
855
+ const childContentWidthPx = computeAtomContentWidth(slotOuterWidth, childResolved);
856
+ const childWidthStyle = {
857
+ width: "100%",
858
+ ...childMaxWidth !== "none" ? { maxWidth: childMaxWidth } : {}
859
+ };
860
+ const gapStyle = i > 0 && gap > 0 ? { paddingTop: gap } : {};
861
+ const childCtx = {
862
+ ...ctx,
863
+ contentWidthPx: childContentWidthPx,
864
+ parentRowBlockHorizontalAlign: resolvedRows.horizontalAlign
865
+ };
866
+ return /* @__PURE__ */ React.createElement("div", { key: child.atomKey, style: { ...gapStyle, ...childWidthStyle } }, /* @__PURE__ */ React.createElement(EmailAtom, { atom: child, ctx: childCtx }));
867
+ })
868
+ ));
869
+ };
870
+ const EmailColumnsAtom = ({ atom, ctx }) => {
871
+ const resolvedLayout = resolveAtomLayoutStyles(atom, ctx.globalAtomStyles);
872
+ const resolvedCols = resolveColumnsStyles(atom.columnsStyles, ctx.globalAtomStyles.columnsStyles.columnsStyles);
873
+ const wrapperStyle = layoutToWrapperStyle(resolvedLayout, ctx.parentRowBlockHorizontalAlign, "left");
874
+ const gap = resolvedCols.gap;
875
+ const gapPx = Math.max(0, Math.round(gap));
876
+ const innerWidth = computeAtomContentWidth(ctx.contentWidthPx, resolvedLayout);
877
+ const innerWidthPx = Math.max(0, Math.round(innerWidth));
878
+ const resolvedChildLayouts = atom.children.map(
879
+ (child) => resolveAtomLayoutStyles(child, ctx.globalAtomStyles)
880
+ );
881
+ const verticalAlignMap = {
882
+ top: "top",
883
+ middle: "middle",
884
+ bottom: "bottom"
885
+ };
886
+ const vAlign = verticalAlignMap[resolvedCols.verticalAlign] ?? "top";
887
+ const childCount = atom.children.length;
888
+ const totalGapPx = childCount > 1 ? gapPx * (childCount - 1) : 0;
889
+ const rawColumnWidths = childCount === 0 ? [] : calculateColumnChildWidths({
890
+ contentWidth: innerWidthPx,
891
+ children: atom.children,
892
+ gap: gapPx,
893
+ globalAtomStyles: ctx.globalAtomStyles
894
+ });
895
+ const columnWidthsPx = rawColumnWidths.map((w) => Math.round(w));
896
+ const columnsWidthSum = columnWidthsPx.reduce((a, b) => a + b, 0);
897
+ const totalTableWidth = columnsWidthSum + totalGapPx;
898
+ const horizontalAlign = resolvedCols.horizontalAlign;
899
+ const narrowColumnsMargins = horizontalAlign === "center" ? { marginLeft: "auto", marginRight: "auto" } : horizontalAlign === "right" ? { marginLeft: "auto", marginRight: "0" } : { marginLeft: "0", marginRight: "auto" };
900
+ const outerTableStyle = {
901
+ ...wrapperStyle,
902
+ width: totalTableWidth,
903
+ ...narrowColumnsMargins,
904
+ ...resolvedLayout.width.max !== "none" ? { maxWidth: resolvedLayout.width.max } : {}
905
+ };
906
+ const innerRowStyle = {
907
+ width: totalTableWidth,
908
+ tableLayout: "fixed"
909
+ };
910
+ const spacerStyle = {
911
+ width: gapPx,
912
+ padding: 0,
913
+ verticalAlign: vAlign,
914
+ lineHeight: 0,
915
+ fontSize: 0
916
+ };
917
+ const cells = [];
918
+ atom.children.forEach((child, i) => {
919
+ if (i > 0 && gapPx > 0) {
920
+ cells.push(
921
+ /* @__PURE__ */ React.createElement(Column, { key: `${atom.atomKey}-gap-${i}`, style: spacerStyle }, "\xA0")
922
+ );
923
+ }
924
+ const wPx = columnWidthsPx[i] ?? 0;
925
+ const childResolved = resolvedChildLayouts[i];
926
+ const childContentWidthPx = computeAtomContentWidth(wPx, childResolved);
927
+ const columnStyle = {
928
+ width: wPx,
929
+ verticalAlign: vAlign
930
+ };
931
+ const childCtx = {
932
+ ...ctx,
933
+ contentWidthPx: childContentWidthPx,
934
+ parentRowBlockHorizontalAlign: null
935
+ };
936
+ cells.push(
937
+ /* @__PURE__ */ React.createElement(Column, { key: child.atomKey, style: columnStyle }, /* @__PURE__ */ React.createElement(EmailAtom, { atom: child, ctx: childCtx }))
938
+ );
939
+ });
940
+ return /* @__PURE__ */ React.createElement(Section, { style: outerTableStyle }, /* @__PURE__ */ React.createElement(Row, { style: innerRowStyle }, cells));
941
+ };
942
+ const AtomDocumentContentsEmail = ({ document: doc }) => {
943
+ const webFonts = collectFontFamilies(doc);
944
+ const ctx = {
945
+ globalAtomStyles: doc.globalAtomStyles,
946
+ contentWidthPx: doc.maxWidth,
947
+ parentRowBlockHorizontalAlign: null
948
+ };
949
+ const resolvedRootLayoutStyles = resolveAtomLayoutStyles(doc.rootRow, doc.globalAtomStyles);
950
+ const bodyBackgroundColor = resolvedRootLayoutStyles.background === "none" ? void 0 : backgroundColorFromAtomBg(resolvedRootLayoutStyles.background);
951
+ return /* @__PURE__ */ React.createElement(Html, { lang: "en", dir: "ltr" }, /* @__PURE__ */ React.createElement(Head, null, webFonts.map((fontFamily) => /* @__PURE__ */ React.createElement(
952
+ "link",
953
+ {
954
+ key: fontFamily,
955
+ rel: "stylesheet",
956
+ href: `https://fonts.googleapis.com/css2?family=${encodeURIComponent(fontFamily)}:wght@100;200;300;400;500;600;700;800;900&display=swap`
957
+ }
958
+ ))), /* @__PURE__ */ React.createElement(Body, { style: { backgroundColor: bodyBackgroundColor, margin: 0, padding: 0 } }, /* @__PURE__ */ React.createElement(Container, { style: { maxWidth: doc.maxWidth, margin: "0 auto" } }, /* @__PURE__ */ React.createElement(EmailRowsAtom, { atom: doc.rootRow, ctx }))));
959
+ };
960
+ async function renderAtomDocumentToHtml(doc) {
961
+ return render(/* @__PURE__ */ React.createElement(AtomDocumentContentsEmail, { document: doc }));
962
+ }
963
+
964
+ export { renderAtomDocumentToHtml };