@saltcorn/markup 1.2.0-beta.1 → 1.2.0-beta.3

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.
@@ -0,0 +1,618 @@
1
+ "use strict";
2
+ /**
3
+ * @category saltcorn-markup
4
+ * @module layout
5
+ * @description Duplicate of layout.ts for testing purposes
6
+ */
7
+ const tags = require("./tags");
8
+ const { div, a, span, text, img, p, h1, h2, h3, h4, h5, h6, label, ul, button, li, i, genericElement, table, tr, td, tbody, iframe, script, text_attr, form, } = tags;
9
+ const { toast, breadcrumbs, renderTabs, show_icon, show_icon_and_label, } = require("./layout_utils");
10
+ const base_types_1 = require("@saltcorn/types/base_types");
11
+ const helpers = require("./helpers");
12
+ const mjml_layout_1 = require("./mjml-layout");
13
+ const { search_bar } = helpers;
14
+ /**
15
+ * @param {any|any[]} [alerts]
16
+ * @returns {boolean}
17
+ */
18
+ const couldHaveAlerts = (alerts) => alerts || Array.isArray(alerts);
19
+ /**
20
+ * @param {string|any} body
21
+ * @param {object[]} [alerts]
22
+ * @returns {object}
23
+ */
24
+ const makeSegments = (body, isWeb, alerts) => {
25
+ const toastSegments = couldHaveAlerts(alerts) && !body.noWrapTop
26
+ ? [
27
+ {
28
+ type: "blank",
29
+ contents: div({
30
+ id: "toasts-area",
31
+ class: `toast-container position-fixed ${isWeb
32
+ ? "top-0 end-0 p-2"
33
+ : "bottom-0 start-50 p-0 mobile-toast-margin"} `,
34
+ style: "z-index: 9999;",
35
+ "aria-live": "polite",
36
+ "aria-atomic": "true",
37
+ }, (alerts || []).map((a) => toast(a.type, a.msg))),
38
+ },
39
+ ]
40
+ : [];
41
+ if (typeof body === "string")
42
+ return {
43
+ above: [{ type: "blank", contents: body }, ...toastSegments],
44
+ };
45
+ else if (body.above) {
46
+ if (couldHaveAlerts(alerts))
47
+ body.above.push(toastSegments[0]);
48
+ return body;
49
+ }
50
+ else
51
+ return {
52
+ above: [body, ...toastSegments],
53
+ };
54
+ };
55
+ /**
56
+ *
57
+ * @param {any} segment
58
+ * @param {string} inner
59
+ * @returns {div|span|string}
60
+ */
61
+ const selfStylingTypes = new Set(["card", "container", "besides", "image"]);
62
+ const textStyleToArray = (textStyle) => Array.isArray(textStyle) ? textStyle : !textStyle ? [] : [textStyle];
63
+ const applyTextStyle = (segment, inner) => {
64
+ const to_bs5 = (s) => (s === "font-italic" ? "fst-italic" : s);
65
+ const styleArray = textStyleToArray(segment.textStyle);
66
+ const hs = styleArray.find((s) => s[0] === "h");
67
+ const klasses = styleArray.filter((s) => s[0] !== "h").map(to_bs5);
68
+ const inline_h = segment.textStyle && hs && segment.inline;
69
+ const style = segment.font
70
+ ? { fontFamily: segment.font, ...segment.style }
71
+ : segment.style || {};
72
+ const hasStyle = Object.keys(style).length > 0 && !selfStylingTypes.has(segment.type);
73
+ if (inline_h)
74
+ style.display = "inline-block";
75
+ if (segment.customClass)
76
+ klasses.push(segment.customClass);
77
+ const klass = klasses.join(" ");
78
+ switch (hs) {
79
+ case "h1":
80
+ return h1({ style, class: klass }, inner);
81
+ case "h2":
82
+ return h2({ style, class: klass }, inner);
83
+ case "h3":
84
+ return h3({ style, class: klass }, inner);
85
+ case "h4":
86
+ return h4({ style, class: klass }, inner);
87
+ case "h5":
88
+ return h5({ style, class: klass }, inner);
89
+ case "h6":
90
+ return h6({ style, class: klass }, inner);
91
+ default:
92
+ return segment.block || (segment.display === "block" && hasStyle)
93
+ ? div({ class: klass, style }, inner)
94
+ : segment.textStyle || hasStyle || klass
95
+ ? span({ class: klass, style }, inner)
96
+ : inner;
97
+ }
98
+ };
99
+ /**
100
+ * @param {object} opts
101
+ * @param {object} opts.blockDispatch
102
+ * @param {object|string} opts.layout
103
+ * @param {object} [opts.role]
104
+ * @param {object[]} [opts.alerts]
105
+ * @param {boolean} opts.is_owner
106
+ * @returns {string}
107
+ */
108
+ const render = ({ blockDispatch, layout, role, alerts, is_owner, req, hints = {}, }) => {
109
+ //console.log(JSON.stringify(layout, null, 2));
110
+ const isWeb = typeof window === "undefined" && !req?.smr;
111
+ //const hints = blockDispatch?.hints || {};
112
+ function wrap(segment, isTop, ix, inner) {
113
+ const iconTag = segment.icon
114
+ ? show_icon(segment.icon, "", true) + " "
115
+ : "";
116
+ if (isTop && blockDispatch && blockDispatch.wrapTop && !layout?.noWrapTop)
117
+ return blockDispatch.wrapTop(segment, ix, inner);
118
+ else
119
+ return segment.labelFor
120
+ ? label({ for: `input${text(segment.labelFor)}` }, applyTextStyle(segment, iconTag + inner))
121
+ : applyTextStyle(segment, iconTag + inner);
122
+ }
123
+ function go(segment, isTop = false, ix = 0) {
124
+ if (!segment)
125
+ return "";
126
+ if (typeof segment === "object" &&
127
+ Object.keys(segment).length === 0 &&
128
+ segment.constructor === Object)
129
+ return "";
130
+ if (typeof segment === "string")
131
+ return wrap(segment, isTop, ix, segment);
132
+ if (Array.isArray(segment))
133
+ return wrap(segment, isTop, ix, segment.map((s, jx) => go(s, isTop, jx + ix)).join(""));
134
+ if (segment.minRole && role > segment.minRole)
135
+ return "";
136
+ if (segment.type && blockDispatch && blockDispatch[segment.type]) {
137
+ const resp = blockDispatch[segment.type](segment, go);
138
+ if (resp !== false)
139
+ return wrap(segment, isTop, ix, resp);
140
+ //else continue below
141
+ }
142
+ if (segment.type === "blank") {
143
+ return wrap(segment, isTop, ix, segment.contents || "");
144
+ }
145
+ if (segment.type === "breadcrumbs") {
146
+ return wrap(segment, isTop, ix, breadcrumbs(segment.crumbs || [], segment.right, segment.after));
147
+ }
148
+ if (segment.type === "view") {
149
+ return wrap(segment, isTop, ix, segment.contents || "");
150
+ }
151
+ if (segment.type === "page") {
152
+ return wrap(segment, isTop, ix, segment.contents || "");
153
+ }
154
+ if (segment.type === "pageHeader") {
155
+ return wrap(segment, isTop, ix, h1(segment.title) + p(segment.blurb || ""));
156
+ }
157
+ if (segment.type === "table") {
158
+ const ntimes = (n, f) => {
159
+ const res = [];
160
+ for (let index = 0; index < n; index++) {
161
+ res.push(f(index));
162
+ }
163
+ return res;
164
+ };
165
+ const { bs_style, bs_small, bs_striped, bs_bordered, bs_borderless, bs_wauto, customClass, } = segment;
166
+ const tabHtml = table({
167
+ class: !bs_style
168
+ ? customClass
169
+ : [
170
+ "table",
171
+ bs_small && "table-sm",
172
+ bs_striped && "table-striped",
173
+ bs_bordered && "table-bordered",
174
+ bs_borderless && "table-borderless",
175
+ bs_wauto && "w-auto",
176
+ customClass,
177
+ ],
178
+ }, tbody(ntimes(segment.rows, (ri) => tr(ntimes(segment.columns, (ci) => td(go(segment.contents?.[ri]?.[ci])))))));
179
+ return wrap(segment, isTop, ix, tabHtml);
180
+ }
181
+ if (segment.type === "image") {
182
+ const srctype = segment.srctype || "File";
183
+ const src = isWeb
184
+ ? srctype === "File"
185
+ ? `/files/serve/${encodeURIComponent(segment.fileid)}`
186
+ : segment.url
187
+ : segment.encoded_image
188
+ ? segment.encoded_image
189
+ : segment.url;
190
+ const imageCfg = {
191
+ class: [
192
+ segment.style && segment.style.width ? null : "w-100",
193
+ segment.customClass,
194
+ ],
195
+ alt: segment.alt,
196
+ style: segment.style,
197
+ srcset: segment.imgResponsiveWidths &&
198
+ segment.fileid &&
199
+ (srctype === "File" || srctype === "Field")
200
+ ? segment.imgResponsiveWidths
201
+ .split(",")
202
+ .map((w) => `/files/resize/${w.trim()}/0/${encodeURIComponent(segment.fileid)} ${w.trim()}w`)
203
+ .join(",")
204
+ : undefined,
205
+ src,
206
+ };
207
+ if (!isWeb && !segment.encoded_image) {
208
+ imageCfg["mobile-img-path"] =
209
+ srctype === "File"
210
+ ? segment.fileid
211
+ : segment.url?.startsWith("/files/serve/")
212
+ ? segment.url.substr(13)
213
+ : undefined;
214
+ }
215
+ return wrap(segment, isTop, ix, img(imageCfg));
216
+ }
217
+ if (segment.type === "dropdown_menu") {
218
+ const rndid = `actiondd${Math.floor(Math.random() * 16777215).toString(16)}`;
219
+ let style = segment.action_style === "btn-custom-color"
220
+ ? `background-color: ${segment.action_bgcol || "#000000"};border-color: ${segment.action_bordercol || "#000000"}; color: ${segment.action_textcol || "#000000"}`
221
+ : null;
222
+ return div({ class: "dropdown" }, button({
223
+ class: segment.action_style === "btn-link"
224
+ ? "btn btn-link"
225
+ : `btn ${segment.action_style || "btn-primary"} ${segment.action_size || ""} dropdown-toggle`,
226
+ "data-boundary": "viewport",
227
+ type: "button",
228
+ id: rndid,
229
+ "data-bs-toggle": "dropdown",
230
+ "aria-haspopup": "true",
231
+ "aria-expanded": "false",
232
+ style,
233
+ }, show_icon_and_label(segment.action_icon, segment.label ||
234
+ (!segment.action_icon || segment.action_icon == "empty"
235
+ ? "Actions"
236
+ : ""), segment.label && "me-1")), div({
237
+ class: [
238
+ "dropdown-menu",
239
+ segment.menu_direction === "end" && "dropdown-menu-end",
240
+ ],
241
+ "aria-labelledby": rndid,
242
+ }, div({ class: "d-flex flex-column px-2" }, go(segment.contents))));
243
+ }
244
+ if (segment.type === "link") {
245
+ let style = segment.link_style === "btn btn-custom-color"
246
+ ? `background-color: ${segment.link_bgcol || "#000000"};border-color: ${segment.link_bordercol || "#000000"}; color: ${segment.link_textcol || "#000000"}`
247
+ : null;
248
+ return wrap(segment, isTop, ix, a({
249
+ ...(isWeb
250
+ ? {
251
+ href: segment.in_modal
252
+ ? `javascript:ajax_modal('${segment.url}');`
253
+ : segment.url,
254
+ }
255
+ : {
256
+ onclick: segment.in_modal
257
+ ? `javascript:mobile_modal('${segment.url}');`
258
+ : `execLink('${segment.url}', '${segment.link_src || "URL"}')`,
259
+ }),
260
+ class: [
261
+ segment.link_style || "",
262
+ segment.link_size || "",
263
+ segment.link_class || "",
264
+ ],
265
+ target: isWeb && segment.target_blank ? "_blank" : false,
266
+ title: segment.link_title,
267
+ rel: segment.nofollow ? "nofollow" : false,
268
+ style,
269
+ }, show_icon_and_label(segment.link_icon, segment.text)));
270
+ }
271
+ if (segment.type === "card") {
272
+ return wrap(segment, isTop, ix, div({
273
+ class: [
274
+ "card",
275
+ !(segment.class || "").includes("mt-") && "mt-4",
276
+ segment.shadow === false ? false : "shadow",
277
+ segment.class,
278
+ segment.url && "with-link",
279
+ hints.cardClass,
280
+ ],
281
+ ...(segment.id ? { id: segment.id } : {}),
282
+ onclick: segment.url
283
+ ? isWeb
284
+ ? segment.url?.startsWith?.("javascript:")
285
+ ? text_attr(segment.url.replace("javascript:", ""))
286
+ : `location.href='${segment.url}'`
287
+ : `execLink('${segment.url}')`
288
+ : false,
289
+ style: segment.style,
290
+ }, segment.title &&
291
+ span({ class: "card-header" }, typeof segment.title === "string"
292
+ ? hints.cardTitleWrapDiv
293
+ ? div({ class: "card-title" }, genericElement(`h${hints.cardTitleHeader || 5}`, segment.title))
294
+ : genericElement(`h${hints.cardTitleHeader || 5}`, {
295
+ class: hints.cardTitleClass ||
296
+ "m-0 fw-bold text-primary d-inline",
297
+ }, segment.title)
298
+ : segment.title, segment.subtitle ? span(segment.subtitle) : "", segment.titleAjaxIndicator &&
299
+ span({
300
+ class: "float-end ms-auto sc-ajax-indicator",
301
+ style: { display: "none" },
302
+ }, i({ class: "fas fa-save" })), segment.titleErrorInidicator &&
303
+ span({
304
+ class: "float-end sc-error-indicator",
305
+ style: { display: "none", color: "#ff0033" },
306
+ }, i({ class: "fas fa-exclamation-triangle" }))), segment.tabContents && // TODO remove all calls to this, use tab in content instead
307
+ div({ class: "card-header" }, ul({ class: ["nav nav-tabs card-header-tabs", hints.tabClass] }, Object.keys(segment.tabContents).map((title, ix) => li({ class: "nav-item" }, a({
308
+ class: ["nav-link", ix === 0 && "active"],
309
+ href: `#tab-${title}`,
310
+ "data-bs-toggle": "tab",
311
+ role: "tab",
312
+ }, title))))) +
313
+ div({
314
+ class: [
315
+ "card-body",
316
+ segment.bodyClass,
317
+ segment.noPadding && "p-0",
318
+ ],
319
+ }, div({ class: "tab-content", id: "myTabContent" }, Object.entries(segment.tabContents).map(([title, contents], ix) => div({
320
+ class: ["tab-pane", ix == 0 && "show active"],
321
+ id: `tab-${title}`,
322
+ }, contents)))), segment.contents &&
323
+ (segment.contents.type === "tabs" &&
324
+ segment.contents.tabsStyle !== "Value switch"
325
+ ? renderTabs({
326
+ tabClass: "card-header-tabs",
327
+ headerWrapperClass: "card-header",
328
+ contentWrapperClass: [
329
+ "card-body",
330
+ segment.bodyClass,
331
+ segment.noPadding && "p-0",
332
+ ],
333
+ ...segment.contents,
334
+ }, go, segment.serverRendered
335
+ ? req?.query?.[segment.tabId || "_tab"]
336
+ : undefined, hints)
337
+ : div({
338
+ class: [
339
+ "card-body",
340
+ segment.bodyClass,
341
+ segment.noPadding && "p-0",
342
+ ],
343
+ }, go(segment.contents))), (segment.hasFooter ||
344
+ (segment.footer && segment.hasFooter !== false)) &&
345
+ div({ class: "card-footer" }, go(segment.footer))));
346
+ }
347
+ if (segment.type === "tabs") {
348
+ return wrap(segment, isTop, ix, renderTabs(segment, go, segment.serverRendered
349
+ ? req?.query?.[segment.tabId || "_tab"]
350
+ : undefined, hints, !isWeb));
351
+ }
352
+ if (segment.type === "container") {
353
+ const { bgFileId, bgType, bgColor, vAlign, hAlign, block, display, imageSize, borderWidth, borderStyle, setTextColor, textColor, showForRole, hide, customClass, customId, customCSS, minScreenWidth, maxScreenWidth, showIfFormulaInputs, showIfFormulaJoinFields, show_for_owner, borderDirection, borderColor, url, hoverColor, gradStartColor, gradEndColor, gradDirection, fullPageWidth, overflow, rotate, style, transform, imgResponsiveWidths, htmlElement, animateName, animateDelay, animateDuration, animateInitialHide, } = segment;
354
+ if (hide)
355
+ return "";
356
+ if (showForRole &&
357
+ showForRole[role] === false &&
358
+ !(show_for_owner && is_owner))
359
+ return "";
360
+ const renderBg = true;
361
+ const sizeProp = (segKey, cssNm, unit) => typeof segment[segKey] === "undefined"
362
+ ? ""
363
+ : `${cssNm}: ${segment[segKey]}${unit || segment[segKey + "Unit"] || "px"};`;
364
+ const ppCustomCSS = (s) => s ? s.split("\n").join("") + ";" : "";
365
+ const baseDisplayClass = block === false ? "inline-block" : display ? display : "block";
366
+ let displayClass = minScreenWidth
367
+ ? `d-none d-${minScreenWidth}-${baseDisplayClass}`
368
+ : baseDisplayClass === "block"
369
+ ? false // no need
370
+ : `d-${baseDisplayClass}`;
371
+ if (maxScreenWidth)
372
+ displayClass = `${displayClass} d-${maxScreenWidth}-none`;
373
+ const allZero = (xs) => xs.every((x) => +x === 0);
374
+ const ppBox = (what) => !segment[what] || allZero(segment[what])
375
+ ? ""
376
+ : `${what}: ${segment[what].map((p) => p + "px").join(" ")};`;
377
+ let flexStyles = "";
378
+ Object.keys(style || {}).forEach((k) => {
379
+ flexStyles += `${k}:${style[k]};`;
380
+ });
381
+ const to_bs5 = (s) => {
382
+ if (s === "left")
383
+ return "start";
384
+ if (s === "right")
385
+ return "end";
386
+ return s;
387
+ };
388
+ const hasImgBg = renderBg && bgType === "Image" && bgFileId;
389
+ const useImgTagAsBg = hasImgBg && imageSize !== "repeat" && isTop;
390
+ let image = undefined;
391
+ if (hasImgBg && useImgTagAsBg) {
392
+ const imgCfg = {
393
+ class: `containerbgimage `,
394
+ srcset: imgResponsiveWidths
395
+ ? imgResponsiveWidths
396
+ .split(",")
397
+ .map((w) => `/files/resize/${w.trim()}/0/${bgFileId} ${w.trim()}w`)
398
+ .join(",")
399
+ : undefined,
400
+ style: { "object-fit": imageSize || "contain" },
401
+ alt: "",
402
+ };
403
+ if (isWeb)
404
+ imgCfg.src = `/files/serve/${bgFileId}`;
405
+ else
406
+ imgCfg["mobile-img-path"] = bgFileId;
407
+ image = img(imgCfg);
408
+ }
409
+ const legacyBorder = borderWidth
410
+ ? `border${borderDirection ? `-${borderDirection}` : ""}: ${borderWidth || 0}px ${borderStyle || "none"} ${borderColor || "black"};`
411
+ : "";
412
+ const transforms = { ...transform };
413
+ if (rotate && rotate !== "0")
414
+ transforms.rotate = `${rotate}deg`;
415
+ let stransform = Object.keys(transforms).length
416
+ ? "transform: " +
417
+ Object.entries(transforms)
418
+ .filter(([k, v]) => v !== "")
419
+ .map(([k, v]) => `${k}(${v})`)
420
+ .join(" ")
421
+ : "";
422
+ return wrap(segment, isTop, ix, genericElement(htmlElement || "div", {
423
+ class: [
424
+ customClass || false,
425
+ hAlign && `text-${to_bs5(hAlign)}`,
426
+ vAlign === "middle" && "d-flex align-items-center",
427
+ vAlign === "bottom" && "d-flex align-items-end",
428
+ vAlign === "middle" &&
429
+ hAlign === "center" &&
430
+ "justify-content-center",
431
+ displayClass,
432
+ url && "with-link",
433
+ hoverColor && `hover-${hoverColor}`,
434
+ fullPageWidth && "full-page-width",
435
+ ],
436
+ id: customId || undefined,
437
+ onclick: segment.url
438
+ ? isWeb
439
+ ? segment.url?.startsWith?.("javascript:")
440
+ ? text_attr(segment.url.replace("javascript:", ""))
441
+ : `location.href='${segment.url}'`
442
+ : `execLink('${segment.url}')`
443
+ : false,
444
+ "data-animate": animateName && animateName !== "None" ? animateName : undefined,
445
+ "data-animate-delay": animateDelay || undefined,
446
+ "data-animate-initial-hide": animateInitialHide || undefined,
447
+ "data-animate-duration": animateDuration || undefined,
448
+ style: `${flexStyles}${ppCustomCSS(customCSS || "")}${sizeProp("minHeight", "min-height")}${sizeProp("height", "height")}${sizeProp("width", "width")}${sizeProp("widthPct", "width", "%")}${legacyBorder}${sizeProp("borderRadius", "border-radius")}${ppBox("padding")}${ppBox("margin")}${overflow && overflow !== "visible"
449
+ ? ` overflow: ${overflow};`
450
+ : ""} ${hasImgBg && !useImgTagAsBg
451
+ ? ` ${isWeb
452
+ ? `background-image: url('/files/serve/${bgFileId}');`
453
+ : ""} background-size: ${imageSize === "repeat" ? "auto" : imageSize || "contain"}; background-repeat: ${imageSize === "repeat" ? "repeat" : "no-repeat"};`
454
+ : ""} ${renderBg && bgType === "Color"
455
+ ? `background-color: ${bgColor};`
456
+ : ""} ${renderBg && bgType === "Gradient"
457
+ ? `background-image: linear-gradient(${gradDirection || 0}deg, ${gradStartColor}, ${gradEndColor});`
458
+ : ""} ${setTextColor ? `color: ${textColor};` : ""}${stransform}${showIfFormulaInputs ? ` display: none;` : ``}`,
459
+ ...(showIfFormulaInputs
460
+ ? {
461
+ "data-show-if": encodeURIComponent(`showIfFormulaInputs(e, '${showIfFormulaInputs.replaceAll("'", "\\'")}')`),
462
+ }
463
+ : {}),
464
+ ...(showIfFormulaJoinFields
465
+ ? {
466
+ "data-show-if-joinfields": encodeURIComponent(JSON.stringify(showIfFormulaJoinFields)),
467
+ }
468
+ : {}),
469
+ ...(!isWeb && hasImgBg && !useImgTagAsBg
470
+ ? { "mobile-bg-img-path": bgFileId }
471
+ : {}),
472
+ }, hasImgBg && useImgTagAsBg && image, go(segment.contents)));
473
+ }
474
+ if (segment.type === "line_break") {
475
+ if (segment.hr)
476
+ return "<hr>";
477
+ if (segment.page_break_after)
478
+ return '<div style="break-after:page"></div>';
479
+ return "<br />";
480
+ }
481
+ if (segment.type === "search_bar") {
482
+ return form({
483
+ action: "/search",
484
+ method: "get",
485
+ }, search_bar("q", "", {
486
+ has_dropdown: segment.has_dropdown,
487
+ autofocus: segment.autofocus,
488
+ contents: go(segment.contents),
489
+ hints,
490
+ }));
491
+ }
492
+ if (segment.above) {
493
+ return segment.above
494
+ .map((s, segmentIx) => go(s, isTop, segmentIx + ix))
495
+ .join("");
496
+ }
497
+ else if (segment.besides) {
498
+ const defwidth = Math.round(12 / segment.besides.length);
499
+ //legacy, for empty (null) in the columns
500
+ const isOneCard = (segs) => segs.length === 1 && segs[0].type === "card";
501
+ const onlyCard = (s) => (s && s.type === "card") ||
502
+ (s.above && isOneCard(s.above.filter(Boolean)));
503
+ const cardDeck = segment.besides
504
+ .filter(Boolean) // allow blank
505
+ .every(onlyCard);
506
+ let markup;
507
+ if (cardDeck) {
508
+ const sameWidths = !segment.widths ||
509
+ segment.widths.every((w) => w === defwidth);
510
+ markup = div({
511
+ class: [
512
+ "row",
513
+ segment.class,
514
+ segment.customClass,
515
+ sameWidths && `row-cols-1 row-cols-md-${segment.besides.length}`,
516
+ typeof segment.gx !== "undefined" &&
517
+ segment.gx !== null &&
518
+ `gx-${segment.gx}`,
519
+ typeof segment.gy !== "undefined" &&
520
+ segment.gy !== null &&
521
+ `gy-${segment.gy}`,
522
+ !segment.style?.["margin-bottom"] && `mb-3`,
523
+ ],
524
+ style: segment.style,
525
+ }, segment.besides.map((t, ixb) => {
526
+ if (!t)
527
+ return ""; //blank col
528
+ const newt = { ...t };
529
+ newt.class = t.class
530
+ ? Array.isArray(t.class)
531
+ ? ["h-100", ...t.class]
532
+ : t.class + " h-100"
533
+ : "h-100";
534
+ return div({
535
+ class: sameWidths
536
+ ? "col"
537
+ : `col-${segment.breakpoint
538
+ ? segment.breakpoint + "-"
539
+ : segment.breakpoints && segment.breakpoints[ixb]
540
+ ? segment.breakpoints[ixb] + "-"
541
+ : ""}${segment.widths ? segment.widths[ixb] : defwidth}`,
542
+ }, go(newt, false, ixb));
543
+ }));
544
+ }
545
+ else
546
+ markup = div({
547
+ class: [
548
+ "row",
549
+ segment.class,
550
+ segment.customClass,
551
+ typeof segment.gx !== "undefined" &&
552
+ segment.gx !== null &&
553
+ `gx-${segment.gx}`,
554
+ typeof segment.gy !== "undefined" &&
555
+ segment.gy !== null &&
556
+ `gy-${segment.gy}`,
557
+ ],
558
+ style: segment.style,
559
+ }, segment.besides.map((t, ixb) => div({
560
+ class: segment.widths === false
561
+ ? ""
562
+ : `col-${segment.breakpoint
563
+ ? segment.breakpoint + "-"
564
+ : segment.breakpoints && segment.breakpoints[ixb]
565
+ ? segment.breakpoints[ixb] + "-"
566
+ : ""}${segment.widths ? segment.widths[ixb] : defwidth}${segment.aligns ? " text-" + segment.aligns[ixb] : ""}${segment.vAligns
567
+ ? " align-items-" + segment.vAligns[ixb]
568
+ : ""}${segment.colClasses?.[ixb]
569
+ ? " " + segment.colClasses[ixb]
570
+ : ""}`,
571
+ style: segment.colStyles?.[ixb] || undefined,
572
+ }, go(t, false, ixb))));
573
+ return isTop
574
+ ? wrap({ ...segment, customClass: null }, isTop, ix, markup)
575
+ : markup;
576
+ }
577
+ else
578
+ throw new Error("unknown layout segment" + JSON.stringify(segment));
579
+ }
580
+ if ((0, base_types_1.instanceOWithHtmlFile)(layout)) {
581
+ const rndid = `iframe_${Math.floor(Math.random() * 16777215).toString(16)}`;
582
+ return `${iframe({
583
+ id: rndid,
584
+ src: `/files/serve/${encodeURIComponent(layout.html_file)}`,
585
+ })} ${script(`
586
+ (() => {
587
+ const iframe = document.getElementById("${rndid}");
588
+ iframe.onload = () => {
589
+ const _iframe = document.getElementById("${rndid}");
590
+ if (_iframe.contentWindow.document.body) {
591
+ _iframe.width = _iframe.contentWindow.document.body.scrollWidth;
592
+ _iframe.height = _iframe.contentWindow.document.body.scrollHeight;
593
+ }
594
+ }
595
+ })();
596
+ `)}`;
597
+ }
598
+ if (req && req.generate_email)
599
+ return (0, mjml_layout_1.renderMJML)({
600
+ blockDispatch,
601
+ layout,
602
+ role,
603
+ alerts,
604
+ is_owner,
605
+ req,
606
+ });
607
+ else
608
+ return go(makeSegments(layout, isWeb, alerts), true, 0);
609
+ };
610
+ // declaration merging
611
+ const LayoutExports = {
612
+ render,
613
+ makeSegments,
614
+ textStyleToArray,
615
+ applyTextStyle,
616
+ };
617
+ module.exports = LayoutExports;
618
+ //# sourceMappingURL=internal.js.map