@samva/markup 0.13.0 → 0.14.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/AGENTS.md +11 -1
- package/CHANGELOG.md +50 -0
- package/dist/{assets-DCULM6QD.d.ts → assets-tISHaQNF.d.ts} +1 -1
- package/dist/{brand-C45QBKX9.js → brand-B-t62NJB.js} +4 -4
- package/dist/brand.d.ts +48 -25
- package/dist/brand.js +3 -3
- package/dist/compiler.d.ts +23 -6
- package/dist/compiler.js +657 -199
- package/dist/components-CwWSoG5N.js +401 -0
- package/dist/dark-scheme-CbCwGDWH.js +12 -0
- package/dist/{diagnostic-codes-DdZ4tka5.js → diagnostic-codes-UXwOO3A-.js} +22 -0
- package/dist/diagnostics.d.ts +17 -0
- package/dist/diagnostics.js +1 -1
- package/dist/edit.js +2 -2
- package/dist/email.d.ts +52 -9
- package/dist/email.js +1 -1
- package/dist/{ir-C-ubz6N3.js → ir-D-gTGquU.js} +202 -78
- package/dist/{profile-CXnkfEMi.js → profile-Cc8VxOKA.js} +72 -11
- package/dist/{render-Cja448i0.js → render-6gLei61p.js} +7 -5
- package/dist/{render-C6OTH8BQ.d.ts → render-C1X3S5or.d.ts} +5 -0
- package/dist/render.d.ts +1 -1
- package/dist/render.js +2 -2
- package/dist/{theme-css-CEUrDpqq.js → theme-css-s9QwD5Ko.js} +108 -46
- package/generated/contract.json +176 -2
- package/generated/reference.md +165 -118
- package/package.json +1 -1
- package/skills/sml/SKILL.md +63 -5
- package/dist/components-DycSEKva.js +0 -273
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { n as isObject } from "./guards-eV1qLbf2.js";
|
|
2
2
|
import { a as kebab, n as declarationValue, r as escapeAttribute } from "./html-eOZfDwVf.js";
|
|
3
3
|
import { t as EmailNode } from "./jsx-runtime-CBlexoeR.js";
|
|
4
|
+
import { i as withinDarkScheme, t as DARK_SCHEME_MEDIA } from "./dark-scheme-CbCwGDWH.js";
|
|
4
5
|
//#region src/email/font-stacks.ts
|
|
5
6
|
/** Generic families every email client understands as the last resort in a stack. */
|
|
6
7
|
const GENERIC_FAMILIES = /* @__PURE__ */ new Set([
|
|
@@ -90,6 +91,73 @@ const fontFallbackDiagnostic = (value) => ({
|
|
|
90
91
|
message: `font-family ${JSON.stringify(value)} uses a project font without a generic fallback. Clients that drop webfonts (Gmail, classic Outlook) render this stack as written, so end it with sans-serif, serif or monospace.`
|
|
91
92
|
});
|
|
92
93
|
//#endregion
|
|
94
|
+
//#region src/email/selectors.ts
|
|
95
|
+
const classListOf = (element) => {
|
|
96
|
+
const value = element.props.class ?? element.props.className;
|
|
97
|
+
return typeof value === "string" ? value.split(/\s+/).filter((name) => name !== "") : [];
|
|
98
|
+
};
|
|
99
|
+
const attributeOf = (element, name) => {
|
|
100
|
+
const value = element.props[name];
|
|
101
|
+
if (value === void 0 || value === null || value === false) return void 0;
|
|
102
|
+
if (value === true) return "";
|
|
103
|
+
return typeof value === "string" || typeof value === "number" ? String(value) : void 0;
|
|
104
|
+
};
|
|
105
|
+
const matchesAttribute = (element, test) => {
|
|
106
|
+
const actual = test.name === "class" ? classListOf(element).join(" ") : attributeOf(element, test.name);
|
|
107
|
+
if (actual === void 0) return false;
|
|
108
|
+
if (test.operator === void 0 || test.value === void 0) return true;
|
|
109
|
+
switch (test.operator) {
|
|
110
|
+
case "=": return actual === test.value;
|
|
111
|
+
case "~=": return actual.split(/\s+/).includes(test.value);
|
|
112
|
+
case "^=": return actual.startsWith(test.value);
|
|
113
|
+
case "$=": return actual.endsWith(test.value);
|
|
114
|
+
case "*=": return actual.includes(test.value);
|
|
115
|
+
case "|=": return actual === test.value || actual.startsWith(`${test.value}-`);
|
|
116
|
+
default: return false;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
const matchesCompound = (element, compound) => {
|
|
120
|
+
if (compound.opaque) return false;
|
|
121
|
+
if (compound.tag !== void 0 && compound.tag !== element.tag) return false;
|
|
122
|
+
if (compound.id !== void 0 && attributeOf(element, "id") !== compound.id) return false;
|
|
123
|
+
if (compound.classes.length > 0) {
|
|
124
|
+
const classes = classListOf(element);
|
|
125
|
+
if (!compound.classes.every((name) => classes.includes(name))) return false;
|
|
126
|
+
}
|
|
127
|
+
return compound.attributes.every((test) => matchesAttribute(element, test));
|
|
128
|
+
};
|
|
129
|
+
const matchesFrom = (selector, index, ancestry) => {
|
|
130
|
+
if (ancestry === void 0) return false;
|
|
131
|
+
const part = selector.parts[index];
|
|
132
|
+
if (part === void 0) return false;
|
|
133
|
+
if (!matchesCompound(ancestry.element, part.compound)) return false;
|
|
134
|
+
const left = selector.parts[index - 1];
|
|
135
|
+
if (left === void 0) return true;
|
|
136
|
+
switch (left.after ?? "descendant") {
|
|
137
|
+
case "child": return matchesFrom(selector, index - 1, ancestry.parent);
|
|
138
|
+
case "descendant":
|
|
139
|
+
for (let parent = ancestry.parent; parent !== void 0; parent = parent.parent) if (matchesFrom(selector, index - 1, parent)) return true;
|
|
140
|
+
return false;
|
|
141
|
+
case "adjacent": {
|
|
142
|
+
const sibling = ancestry.previous.at(-1);
|
|
143
|
+
return sibling === void 0 ? false : matchesFrom(selector, index - 1, {
|
|
144
|
+
element: sibling,
|
|
145
|
+
parent: ancestry.parent,
|
|
146
|
+
previous: ancestry.previous.slice(0, -1)
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
case "sibling":
|
|
150
|
+
for (let position = ancestry.previous.length - 1; position >= 0; position--) if (matchesFrom(selector, index - 1, {
|
|
151
|
+
element: ancestry.previous[position],
|
|
152
|
+
parent: ancestry.parent,
|
|
153
|
+
previous: ancestry.previous.slice(0, position)
|
|
154
|
+
})) return true;
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
/** Match a compiled selector against one element in its tree position. */
|
|
159
|
+
const matchesSelector = (selector, ancestry) => selector === void 0 || selector.parts.length === 0 ? false : matchesFrom(selector, selector.parts.length - 1, ancestry);
|
|
160
|
+
//#endregion
|
|
93
161
|
//#region src/email/css-values.ts
|
|
94
162
|
const MAX_RESOLVED_VALUE_LENGTH = 65536;
|
|
95
163
|
const MAX_RESOLUTION_WORK = 262144;
|
|
@@ -253,8 +321,12 @@ const downlevelMediaQuery = (condition) => condition.replace(RANGE_FEATURE, (who
|
|
|
253
321
|
return `(${comparison.startsWith(">") ? "min-" : "max-"}${feature}:${bound})`;
|
|
254
322
|
});
|
|
255
323
|
/** Render the rules that could not be inlined as one `<style>` body. */
|
|
256
|
-
const renderHeadCss = (rules, headAtRules, variables) => {
|
|
324
|
+
const renderHeadCss = (rules, headAtRules, variables, darkVariables = {}) => {
|
|
257
325
|
const blocks = [...headAtRules];
|
|
326
|
+
const darkScope = {
|
|
327
|
+
...variables,
|
|
328
|
+
...darkVariables
|
|
329
|
+
};
|
|
258
330
|
const grouped = /* @__PURE__ */ new Map();
|
|
259
331
|
for (const rule of rules) {
|
|
260
332
|
const conditions = rule.conditions.map(downlevelMediaQuery);
|
|
@@ -267,8 +339,9 @@ const renderHeadCss = (rules, headAtRules, variables) => {
|
|
|
267
339
|
else bucket.rules.push(rule);
|
|
268
340
|
}
|
|
269
341
|
for (const { conditions, rules: bucket } of grouped.values()) {
|
|
342
|
+
const scope = withinDarkScheme(conditions) ? darkScope : variables;
|
|
270
343
|
const body = bucket.map((rule) => {
|
|
271
|
-
const declarations = rule.declarations.filter((declaration) => !declaration.property.startsWith("--")).map((declaration) => `${declaration.property}:${finalizeValue(declaration.value,
|
|
344
|
+
const declarations = rule.declarations.filter((declaration) => !declaration.property.startsWith("--")).map((declaration) => `${declaration.property}:${finalizeValue(declaration.value, scope)}!important`).join(";");
|
|
272
345
|
return declarations === "" ? "" : `${rule.selector}{${declarations}}`;
|
|
273
346
|
}).filter((block) => block !== "").join("");
|
|
274
347
|
if (body === "") continue;
|
|
@@ -277,73 +350,6 @@ const renderHeadCss = (rules, headAtRules, variables) => {
|
|
|
277
350
|
return blocks.join("");
|
|
278
351
|
};
|
|
279
352
|
//#endregion
|
|
280
|
-
//#region src/email/selectors.ts
|
|
281
|
-
const classListOf = (element) => {
|
|
282
|
-
const value = element.props.class ?? element.props.className;
|
|
283
|
-
return typeof value === "string" ? value.split(/\s+/).filter((name) => name !== "") : [];
|
|
284
|
-
};
|
|
285
|
-
const attributeOf = (element, name) => {
|
|
286
|
-
const value = element.props[name];
|
|
287
|
-
if (value === void 0 || value === null || value === false) return void 0;
|
|
288
|
-
if (value === true) return "";
|
|
289
|
-
return typeof value === "string" || typeof value === "number" ? String(value) : void 0;
|
|
290
|
-
};
|
|
291
|
-
const matchesAttribute = (element, test) => {
|
|
292
|
-
const actual = test.name === "class" ? classListOf(element).join(" ") : attributeOf(element, test.name);
|
|
293
|
-
if (actual === void 0) return false;
|
|
294
|
-
if (test.operator === void 0 || test.value === void 0) return true;
|
|
295
|
-
switch (test.operator) {
|
|
296
|
-
case "=": return actual === test.value;
|
|
297
|
-
case "~=": return actual.split(/\s+/).includes(test.value);
|
|
298
|
-
case "^=": return actual.startsWith(test.value);
|
|
299
|
-
case "$=": return actual.endsWith(test.value);
|
|
300
|
-
case "*=": return actual.includes(test.value);
|
|
301
|
-
case "|=": return actual === test.value || actual.startsWith(`${test.value}-`);
|
|
302
|
-
default: return false;
|
|
303
|
-
}
|
|
304
|
-
};
|
|
305
|
-
const matchesCompound = (element, compound) => {
|
|
306
|
-
if (compound.opaque) return false;
|
|
307
|
-
if (compound.tag !== void 0 && compound.tag !== element.tag) return false;
|
|
308
|
-
if (compound.id !== void 0 && attributeOf(element, "id") !== compound.id) return false;
|
|
309
|
-
if (compound.classes.length > 0) {
|
|
310
|
-
const classes = classListOf(element);
|
|
311
|
-
if (!compound.classes.every((name) => classes.includes(name))) return false;
|
|
312
|
-
}
|
|
313
|
-
return compound.attributes.every((test) => matchesAttribute(element, test));
|
|
314
|
-
};
|
|
315
|
-
const matchesFrom = (selector, index, ancestry) => {
|
|
316
|
-
if (ancestry === void 0) return false;
|
|
317
|
-
const part = selector.parts[index];
|
|
318
|
-
if (part === void 0) return false;
|
|
319
|
-
if (!matchesCompound(ancestry.element, part.compound)) return false;
|
|
320
|
-
const left = selector.parts[index - 1];
|
|
321
|
-
if (left === void 0) return true;
|
|
322
|
-
switch (left.after ?? "descendant") {
|
|
323
|
-
case "child": return matchesFrom(selector, index - 1, ancestry.parent);
|
|
324
|
-
case "descendant":
|
|
325
|
-
for (let parent = ancestry.parent; parent !== void 0; parent = parent.parent) if (matchesFrom(selector, index - 1, parent)) return true;
|
|
326
|
-
return false;
|
|
327
|
-
case "adjacent": {
|
|
328
|
-
const sibling = ancestry.previous.at(-1);
|
|
329
|
-
return sibling === void 0 ? false : matchesFrom(selector, index - 1, {
|
|
330
|
-
element: sibling,
|
|
331
|
-
parent: ancestry.parent,
|
|
332
|
-
previous: ancestry.previous.slice(0, -1)
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
case "sibling":
|
|
336
|
-
for (let position = ancestry.previous.length - 1; position >= 0; position--) if (matchesFrom(selector, index - 1, {
|
|
337
|
-
element: ancestry.previous[position],
|
|
338
|
-
parent: ancestry.parent,
|
|
339
|
-
previous: ancestry.previous.slice(0, position)
|
|
340
|
-
})) return true;
|
|
341
|
-
return false;
|
|
342
|
-
}
|
|
343
|
-
};
|
|
344
|
-
/** Match a compiled selector against one element in its tree position. */
|
|
345
|
-
const matchesSelector = (selector, ancestry) => selector === void 0 || selector.parts.length === 0 ? false : matchesFrom(selector, selector.parts.length - 1, ancestry);
|
|
346
|
-
//#endregion
|
|
347
353
|
//#region src/email/cascade.ts
|
|
348
354
|
const VARIABLE_REFERENCE = /var\(\s*--[\w-]+\s*(?:,[^()]*)?\)/g;
|
|
349
355
|
/**
|
|
@@ -434,12 +440,98 @@ const physicalPadding = (property, value, context) => {
|
|
|
434
440
|
if (match[2] !== void 0) return [[`padding-${sides[match[2] === "start" ? 0 : 1]}`, values[0]]];
|
|
435
441
|
return [[`padding-${sides[0]}`, values[0]], [`padding-${sides[1]}`, values[1] ?? values[0]]];
|
|
436
442
|
};
|
|
443
|
+
/** Generated dark-mode classes share this prefix; it is reserved for the compiler. */
|
|
444
|
+
const DARK_CLASS_PREFIX = "sml-dark-";
|
|
445
|
+
/** A class named for its declarations, so equal sets share one rule and builds are stable. */
|
|
446
|
+
const darkClassName = (body) => {
|
|
447
|
+
let hash = 2166136261;
|
|
448
|
+
for (let index = 0; index < body.length; index++) {
|
|
449
|
+
hash ^= body.charCodeAt(index);
|
|
450
|
+
hash = Math.imul(hash, 16777619) >>> 0;
|
|
451
|
+
}
|
|
452
|
+
return `${DARK_CLASS_PREFIX}${hash.toString(36)}`;
|
|
453
|
+
};
|
|
454
|
+
const SIDES = [
|
|
455
|
+
"top",
|
|
456
|
+
"right",
|
|
457
|
+
"bottom",
|
|
458
|
+
"left"
|
|
459
|
+
];
|
|
460
|
+
const BORDER_PARTS = [
|
|
461
|
+
"width",
|
|
462
|
+
"style",
|
|
463
|
+
"color"
|
|
464
|
+
];
|
|
465
|
+
const CORNERS = [
|
|
466
|
+
"top-left",
|
|
467
|
+
"top-right",
|
|
468
|
+
"bottom-right",
|
|
469
|
+
"bottom-left"
|
|
470
|
+
];
|
|
471
|
+
const BORDER_IMAGE = [
|
|
472
|
+
"source",
|
|
473
|
+
"slice",
|
|
474
|
+
"width",
|
|
475
|
+
"outset",
|
|
476
|
+
"repeat"
|
|
477
|
+
].map((part) => `border-image-${part}`);
|
|
478
|
+
/**
|
|
479
|
+
* The longhands a border property writes: `border` writes the twelve per-side longhands and
|
|
480
|
+
* resets the border image, `border-top` the top three, `border-color` the four colors,
|
|
481
|
+
* `border-radius` the four corners.
|
|
482
|
+
* `undefined` for a property outside the border box.
|
|
483
|
+
*/
|
|
484
|
+
const borderLonghands = (property) => {
|
|
485
|
+
if (property === "border") return [...SIDES.flatMap((side) => BORDER_PARTS.map((part) => `border-${side}-${part}`)), ...BORDER_IMAGE];
|
|
486
|
+
if (property === "border-image") return BORDER_IMAGE;
|
|
487
|
+
if (property === "border-radius") return CORNERS.map((corner) => `border-${corner}-radius`);
|
|
488
|
+
const side = /^border-(top|right|bottom|left)$/.exec(property)?.[1];
|
|
489
|
+
if (side !== void 0) return BORDER_PARTS.map((part) => `border-${side}-${part}`);
|
|
490
|
+
const part = /^border-(width|style|color)$/.exec(property)?.[1];
|
|
491
|
+
if (part !== void 0) return SIDES.map((each) => `border-${each}-${part}`);
|
|
492
|
+
return property.startsWith("border-") ? [property] : void 0;
|
|
493
|
+
};
|
|
494
|
+
/**
|
|
495
|
+
* Whether two declarations can override one another because they write a property in common:
|
|
496
|
+
* `background` and `background-color`, `border-color` and `border-top`, `font` and `line-height`.
|
|
497
|
+
* `border-radius` shares nothing with `border-color`.
|
|
498
|
+
*/
|
|
499
|
+
const overlaps = (left, right) => {
|
|
500
|
+
if (left === right) return true;
|
|
501
|
+
const leftBorder = borderLonghands(left);
|
|
502
|
+
const rightBorder = borderLonghands(right);
|
|
503
|
+
if (leftBorder !== void 0 || rightBorder !== void 0) return leftBorder !== void 0 && rightBorder !== void 0 && leftBorder.some((longhand) => rightBorder.includes(longhand));
|
|
504
|
+
const sets = (shorthand, longhand) => longhand.startsWith(`${shorthand}-`) || shorthand === "font" && longhand === "line-height";
|
|
505
|
+
return sets(left, right) || sets(right, left);
|
|
506
|
+
};
|
|
507
|
+
/** Add a class to an element's props, whichever of `class` and `className` it uses. */
|
|
508
|
+
const withClass = (props, name) => {
|
|
509
|
+
const key = typeof props.class === "string" || props.className === void 0 ? "class" : "className";
|
|
510
|
+
const current = props[key];
|
|
511
|
+
return {
|
|
512
|
+
...props,
|
|
513
|
+
[key]: typeof current === "string" && current.trim() !== "" ? `${current} ${name}` : name
|
|
514
|
+
};
|
|
515
|
+
};
|
|
516
|
+
/** The generated dark-mode classes as one `@media (prefers-color-scheme:dark)` block, written as the head CSS writes its media queries. */
|
|
517
|
+
const renderDarkRules = (rules) => rules.size === 0 ? "" : `${DARK_SCHEME_MEDIA.replace(": ", ":")}{${[...rules].sort(([left], [right]) => left.localeCompare(right)).map(([name, body]) => `.${name}{${body}}`).join("")}}`;
|
|
437
518
|
/**
|
|
438
519
|
* Resolve every stylesheet against the tree: inline what a client will honor on
|
|
439
|
-
* the element, and keep the rest for `<head>`.
|
|
520
|
+
* the element, and keep the rest for `<head>`. Where the sheet has a dark-mode
|
|
521
|
+
* theme, an element whose inlined styles read a color it redefines also gets a
|
|
522
|
+
* generated class whose dark-mode rule restates those styles at their dark
|
|
523
|
+
* values.
|
|
440
524
|
*/
|
|
441
525
|
const applyStylesheet = (root, sheet, options = {}) => {
|
|
442
526
|
const diagnostics = [...sheet.diagnostics];
|
|
527
|
+
const hasDarkTheme = Object.keys(sheet.darkVariables).length > 0;
|
|
528
|
+
const darkRules = /* @__PURE__ */ new Map();
|
|
529
|
+
const darkClassFor = (declarations) => {
|
|
530
|
+
const body = declarations.map(([property, value]) => `${property}:${value}!important`).join(";");
|
|
531
|
+
const name = darkClassName(body);
|
|
532
|
+
darkRules.set(name, body);
|
|
533
|
+
return name;
|
|
534
|
+
};
|
|
443
535
|
const inlinable = [];
|
|
444
536
|
const retained = [];
|
|
445
537
|
const styledClasses = /* @__PURE__ */ new Set();
|
|
@@ -462,7 +554,7 @@ const applyStylesheet = (root, sheet, options = {}) => {
|
|
|
462
554
|
* A fragment is not an element in the serialized document, so its children
|
|
463
555
|
* join that same list rather than starting a new one.
|
|
464
556
|
*/
|
|
465
|
-
const visitChildren = (children, ancestry, variables, writing) => {
|
|
557
|
+
const visitChildren = (children, ancestry, variables, darkScope, writing) => {
|
|
466
558
|
const previous = [];
|
|
467
559
|
const visit = (nodes) => nodes.map((child) => {
|
|
468
560
|
if (child.type === "Element") {
|
|
@@ -470,7 +562,7 @@ const applyStylesheet = (root, sheet, options = {}) => {
|
|
|
470
562
|
element: child,
|
|
471
563
|
parent: ancestry,
|
|
472
564
|
previous: [...previous]
|
|
473
|
-
}, variables, writing);
|
|
565
|
+
}, variables, darkScope, writing);
|
|
474
566
|
previous.push(child);
|
|
475
567
|
return result;
|
|
476
568
|
}
|
|
@@ -489,7 +581,7 @@ const applyStylesheet = (root, sheet, options = {}) => {
|
|
|
489
581
|
* cascade like any other declaration and then inherit, so a `--brand` declared
|
|
490
582
|
* on `.card` has to reach `var(--brand)` on `.card` and everything under it.
|
|
491
583
|
*/
|
|
492
|
-
const applyTo = (element, ancestry, inherited, inheritedWriting) => {
|
|
584
|
+
const applyTo = (element, ancestry, inherited, inheritedDark, inheritedWriting) => {
|
|
493
585
|
const conditionalWriting = conditionalWritingRules.some((rule) => {
|
|
494
586
|
if (rule.matcher === void 0 || rule.matcher.parts.length === 0 || rule.matcher.parts.some((part) => part.compound.opaque)) return true;
|
|
495
587
|
for (let context = ancestry; context !== void 0; context = context.parent) if (matchesSelector(rule.matcher, context)) return true;
|
|
@@ -519,6 +611,10 @@ const applyStylesheet = (root, sheet, options = {}) => {
|
|
|
519
611
|
...inherited,
|
|
520
612
|
...declared
|
|
521
613
|
};
|
|
614
|
+
const darkScope = Object.keys(declared).length === 0 ? inheritedDark : {
|
|
615
|
+
...inheritedDark,
|
|
616
|
+
...declared
|
|
617
|
+
};
|
|
522
618
|
const inheritedValue = (property, parent, initial, fallback = parent) => {
|
|
523
619
|
const value = winners.get(property)?.value;
|
|
524
620
|
if (value === void 0) return fallback;
|
|
@@ -537,24 +633,51 @@ const applyStylesheet = (root, sheet, options = {}) => {
|
|
|
537
633
|
physical.set(name, lowered);
|
|
538
634
|
}
|
|
539
635
|
const bgcolor = element.props.bgcolor;
|
|
540
|
-
const
|
|
636
|
+
const lightProps = typeof bgcolor === "string" && bgcolor.includes("var(") ? {
|
|
541
637
|
...element.props,
|
|
542
638
|
bgcolor: finalizeValue(bgcolor, variables)
|
|
543
639
|
} : element.props;
|
|
640
|
+
const dark = [];
|
|
641
|
+
if (hasDarkTheme) {
|
|
642
|
+
const changed = [];
|
|
643
|
+
for (const [property, entry] of winners) {
|
|
644
|
+
if (property.startsWith("--") || !entry.value.includes("var(")) continue;
|
|
645
|
+
if (finalizeValue(entry.value, darkScope) !== finalizeValue(entry.value, variables)) changed.push(property);
|
|
646
|
+
}
|
|
647
|
+
const restated = new Set(changed);
|
|
648
|
+
for (let grew = changed.length > 0; grew;) {
|
|
649
|
+
grew = false;
|
|
650
|
+
for (const property of winners.keys()) if (!property.startsWith("--") && !restated.has(property) && [...restated].some((candidate) => overlaps(candidate, property))) {
|
|
651
|
+
restated.add(property);
|
|
652
|
+
grew = true;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
for (const [property, entry] of [...winners].sort(([, left], [, right]) => compareRank(left.key, right.key))) if (restated.has(property)) dark.push([property, finalizeValue(entry.value, darkScope)]);
|
|
656
|
+
if (typeof bgcolor === "string" && bgcolor.includes("var(") && !winners.has("background-color") && !winners.has("background")) {
|
|
657
|
+
const value = finalizeValue(bgcolor, darkScope);
|
|
658
|
+
if (value !== finalizeValue(bgcolor, variables)) dark.push(["background-color", value]);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
const darkClass = dark.length === 0 ? void 0 : darkClassFor(dark);
|
|
662
|
+
const props = darkClass === void 0 ? lightProps : withClass(lightProps, darkClass);
|
|
544
663
|
return EmailNode.Element({
|
|
545
664
|
...element,
|
|
546
665
|
props: emitted.length === 0 ? props : {
|
|
547
666
|
...props,
|
|
548
667
|
style: Object.fromEntries(physical)
|
|
549
668
|
},
|
|
550
|
-
children: visitChildren(element.children, ancestry, variables, writing)
|
|
669
|
+
children: visitChildren(element.children, ancestry, variables, darkScope, writing)
|
|
551
670
|
});
|
|
552
671
|
};
|
|
672
|
+
const rootDark = {
|
|
673
|
+
...sheet.variables,
|
|
674
|
+
...sheet.darkVariables
|
|
675
|
+
};
|
|
553
676
|
const tree = root.type === "Element" ? applyTo(root, {
|
|
554
677
|
element: root,
|
|
555
678
|
parent: void 0,
|
|
556
679
|
previous: []
|
|
557
|
-
}, sheet.variables, horizontalWriting) : root.type === "Fragment" ? EmailNode.Fragment({ children: visitChildren(root.children, void 0, sheet.variables, horizontalWriting) }) : root;
|
|
680
|
+
}, sheet.variables, rootDark, horizontalWriting) : root.type === "Fragment" ? EmailNode.Fragment({ children: visitChildren(root.children, void 0, sheet.variables, rootDark, horizontalWriting) }) : root;
|
|
558
681
|
for (const rule of retained) for (const declaration of rule.declarations) checkFallback(declaration.property, finalizeValue(declaration.value, sheet.variables), []);
|
|
559
682
|
for (const [value, origins] of fallbackFindings) diagnostics.push({
|
|
560
683
|
...fontFallbackDiagnostic(value),
|
|
@@ -568,7 +691,8 @@ const applyStylesheet = (root, sheet, options = {}) => {
|
|
|
568
691
|
});
|
|
569
692
|
return {
|
|
570
693
|
tree,
|
|
571
|
-
headCss: renderHeadCss(retained, sheet.headAtRules, sheet.variables),
|
|
694
|
+
headCss: renderHeadCss(retained, sheet.headAtRules, sheet.variables, sheet.darkVariables),
|
|
695
|
+
darkRules,
|
|
572
696
|
fontFaceCss: sheet.fontFaces.map((face) => face.css).join(""),
|
|
573
697
|
diagnostics
|
|
574
698
|
};
|
|
@@ -578,4 +702,4 @@ const applyStylesheet = (root, sheet, options = {}) => {
|
|
|
578
702
|
/** The IR version this package writes. A publication pins the version it was built with. */
|
|
579
703
|
const SML_IR_VERSION = 1;
|
|
580
704
|
//#endregion
|
|
581
|
-
export { downlevelMediaQuery as a, renderHeadCss as c, matchesSelector as i, resolveVariables as l,
|
|
705
|
+
export { downlevelMediaQuery as a, renderHeadCss as c, matchesSelector as d, unquote as f, renderDarkRules as i, resolveVariables as l, DARK_CLASS_PREFIX as n, finalizeValue as o, applyStylesheet as r, foldCalc as s, SML_IR_VERSION as t, classListOf as u };
|
|
@@ -4,10 +4,10 @@ import { n as TEMPLATE_NAME_PATTERN, t as TEMPLATE_ID_PATTERN } from "./template
|
|
|
4
4
|
import { D as samvaBrandPlugin, E as reservedBrandAttributes, O as BRAND_FOOTER_MARKER, S as emailElement, T as parseBrandSpecifier, b as EMAIL_ELEMENTS, s as serializeStyle, t as checkAttribute } from "./html-eOZfDwVf.js";
|
|
5
5
|
import { FORMATTER_NAMES } from "./fmt.js";
|
|
6
6
|
import { i as drainEmailDiagnostics, t as EmailNode } from "./jsx-runtime-CBlexoeR.js";
|
|
7
|
-
import { a as Email, d as equalColumnWidth, i as Divider, l as Section, n as Column, o as Image, r as Columns, s as Link, t as Button, u as Spacer } from "./components-
|
|
8
|
-
import { n as applyStylesheet } from "./ir-
|
|
9
|
-
import { i as buildLineMap, s as lineColumn, t as DIAGNOSTIC_CODES } from "./diagnostic-codes-
|
|
10
|
-
import { l as isAssetPath, n as brandComponents } from "./brand-
|
|
7
|
+
import { a as Email, d as equalColumnWidth, i as Divider, l as Section, n as Column, o as Image, p as PRIMITIVE_CLASSES, r as Columns, s as Link, t as Button, u as Spacer } from "./components-CwWSoG5N.js";
|
|
8
|
+
import { i as renderDarkRules, n as DARK_CLASS_PREFIX, r as applyStylesheet } from "./ir-D-gTGquU.js";
|
|
9
|
+
import { i as buildLineMap, s as lineColumn, t as DIAGNOSTIC_CODES } from "./diagnostic-codes-UXwOO3A-.js";
|
|
10
|
+
import { l as isAssetPath, n as brandComponents } from "./brand-B-t62NJB.js";
|
|
11
11
|
import { parse } from "css-tree";
|
|
12
12
|
import { parse as parse$1 } from "@babel/parser";
|
|
13
13
|
//#region src/email/theme-imports.ts
|
|
@@ -156,11 +156,13 @@ const mergeStylesheets = (sheets) => {
|
|
|
156
156
|
}));
|
|
157
157
|
});
|
|
158
158
|
const variables = {};
|
|
159
|
+
const darkVariables = {};
|
|
159
160
|
const headAtRules = [];
|
|
160
161
|
const fontFaces = /* @__PURE__ */ new Map();
|
|
161
162
|
const diagnostics = sheets.flatMap((sheet) => sheet.diagnostics);
|
|
162
163
|
for (const sheet of sheets) {
|
|
163
164
|
Object.assign(variables, sheet.variables);
|
|
165
|
+
Object.assign(darkVariables, sheet.darkVariables);
|
|
164
166
|
headAtRules.push(...sheet.headAtRules);
|
|
165
167
|
for (const face of sheet.fontFaces) fontFaces.set(face.css, face);
|
|
166
168
|
}
|
|
@@ -169,6 +171,7 @@ const mergeStylesheets = (sheets) => {
|
|
|
169
171
|
headAtRules,
|
|
170
172
|
fontFaces: [...fontFaces.values()],
|
|
171
173
|
variables,
|
|
174
|
+
darkVariables,
|
|
172
175
|
diagnostics
|
|
173
176
|
};
|
|
174
177
|
};
|
|
@@ -974,6 +977,7 @@ const emailNodeToIr = (node, tokens, source) => {
|
|
|
974
977
|
//#endregion
|
|
975
978
|
//#region src/sml/components.ts
|
|
976
979
|
const NUMERIC = {
|
|
980
|
+
Email: ["gutter"],
|
|
977
981
|
Button: [
|
|
978
982
|
"height",
|
|
979
983
|
"paddingX",
|
|
@@ -983,6 +987,7 @@ const NUMERIC = {
|
|
|
983
987
|
"width"
|
|
984
988
|
],
|
|
985
989
|
Spacer: ["height"],
|
|
990
|
+
Columns: ["gap"],
|
|
986
991
|
Divider: ["thickness"],
|
|
987
992
|
BrandLogo: ["width"]
|
|
988
993
|
};
|
|
@@ -1043,7 +1048,7 @@ const equalWidth = (per, list) => {
|
|
|
1043
1048
|
* items (all in one row without `per`), each cell from the callback. Returns the nodes to place
|
|
1044
1049
|
* inside the Columns table, and a wrapper that repeats that table per chunk.
|
|
1045
1050
|
*/
|
|
1046
|
-
const columnsEach = (call, bindings) => {
|
|
1051
|
+
const columnsEach = (call, bindings, stack) => {
|
|
1047
1052
|
const { lowerer, ctx, node } = call;
|
|
1048
1053
|
const listValue = bindings.get("each");
|
|
1049
1054
|
const list = listValue === void 0 ? void 0 : bindingValue(listValue);
|
|
@@ -1070,7 +1075,8 @@ const columnsEach = (call, bindings) => {
|
|
|
1070
1075
|
const cellCtx = {
|
|
1071
1076
|
...ctx,
|
|
1072
1077
|
loops: row === void 0 ? ctx.loops : [...ctx.loops, row],
|
|
1073
|
-
columnWidth: equalWidth(per, list)
|
|
1078
|
+
columnWidth: equalWidth(per, list),
|
|
1079
|
+
columnStack: stack
|
|
1074
1080
|
};
|
|
1075
1081
|
const cells = lowerer.eachOver(cellCtx, node, row === void 0 ? list : { bind: `$${row}` }, fn);
|
|
1076
1082
|
if (cells === void 0) return void 0;
|
|
@@ -1124,17 +1130,32 @@ const runBuiltinComponent = (call) => {
|
|
|
1124
1130
|
let bindings = declared;
|
|
1125
1131
|
let wrap = (table) => table;
|
|
1126
1132
|
let kids;
|
|
1133
|
+
const stackBinding = declared.get("stack");
|
|
1134
|
+
const stack = stackBinding === void 0 ? true : bindingValue(stackBinding);
|
|
1135
|
+
if (exported === "Columns" && typeof stack !== "boolean") {
|
|
1136
|
+
lowerer.error(ctx, node, "invalid-columns-stack", "<Columns stack> decides the layout at compile time, so it must be true or false.", "Write stack={false}, or leave it out to stack on narrow screens.");
|
|
1137
|
+
return [];
|
|
1138
|
+
}
|
|
1127
1139
|
const childCtx = {
|
|
1128
1140
|
...ctx,
|
|
1129
|
-
columnWidth: void 0
|
|
1141
|
+
columnWidth: void 0,
|
|
1142
|
+
columnStack: exported === "Columns" ? stack === true : void 0
|
|
1130
1143
|
};
|
|
1144
|
+
if (exported === "Columns" && declared.has("each") && declared.has("gap")) {
|
|
1145
|
+
lowerer.error(ctx, node, "invalid-columns-gap", "<Columns gap> spaces Column children written out in the row; cells repeated with each cannot take it.", "Write the Columns out, or pad each repeated cell (className=\"px-2\").");
|
|
1146
|
+
return [];
|
|
1147
|
+
}
|
|
1131
1148
|
if (exported === "Columns" && declared.has("each")) {
|
|
1132
|
-
const chunked = columnsEach(call, declared);
|
|
1149
|
+
const chunked = columnsEach(call, declared, stack === true);
|
|
1133
1150
|
if (chunked === void 0) return [];
|
|
1134
|
-
bindings = new Map([...declared].filter(([name]) => name !== "each" && name !== "per"));
|
|
1151
|
+
bindings = new Map([...declared].filter(([name]) => name !== "each" && name !== "per" && name !== "stack"));
|
|
1135
1152
|
kids = [chunked.cells];
|
|
1136
1153
|
wrap = chunked.wrap;
|
|
1137
1154
|
} else kids = lowerer.jsxChildren(childCtx, node);
|
|
1155
|
+
if (exported === "Columns" && declared.has("gap") && kids.some((kid) => !isValueNode(kid) && !("el" in kid))) {
|
|
1156
|
+
lowerer.error(ctx, node, "invalid-columns-gap", "<Columns gap> spaces Column children that always render; a conditional or repeated Column would leave a stray gap.", "Pad the cells instead (className=\"pr-6\"), or write each Column unconditionally.");
|
|
1157
|
+
return [];
|
|
1158
|
+
}
|
|
1138
1159
|
const tokens = new Tokens();
|
|
1139
1160
|
const props = {};
|
|
1140
1161
|
for (const [name, bound] of bindings) props[name] = bindingToProp(call, tokens, name, bound);
|
|
@@ -1146,6 +1167,7 @@ const runBuiltinComponent = (call) => {
|
|
|
1146
1167
|
}
|
|
1147
1168
|
}
|
|
1148
1169
|
if (exported === "Column" && props.width === void 0 && ctx.columnWidth !== void 0) props.width = propFor(tokens, ctx.columnWidth);
|
|
1170
|
+
if (exported === "Column" && ctx.columnStack === true) props.className = typeof props.className === "string" && props.className !== "" ? `${PRIMITIVE_CLASSES.stack} ${props.className}` : PRIMITIVE_CLASSES.stack;
|
|
1149
1171
|
if (kids.length > 0) props.children = childrenProp(tokens, kids);
|
|
1150
1172
|
if (exported === "Button" && typeof props.children === "string" && props.children !== "" && props.width === void 0 && props.height !== void 0 && tokens.toValue(props.children) !== props.children) {
|
|
1151
1173
|
lowerer.error(ctx, node, "button-dynamic-label", "Classic Outlook draws the button from a fixed box, and a label read at render time cannot size it.", "Give the button a width: <Button width={200} …>.");
|
|
@@ -2951,6 +2973,35 @@ const mapTree = (tree, leafStyle, counter = { next: 0 }) => {
|
|
|
2951
2973
|
else: otherwise
|
|
2952
2974
|
};
|
|
2953
2975
|
};
|
|
2976
|
+
/** A class tree as the IR value it was read from: a literal, or a choice between literals. */
|
|
2977
|
+
const treeValue = (tree) => "leaf" in tree ? tree.leaf : {
|
|
2978
|
+
if: tree.pred,
|
|
2979
|
+
then: treeValue(tree.then),
|
|
2980
|
+
else: treeValue(tree.else)
|
|
2981
|
+
};
|
|
2982
|
+
const appendClass = (classes, name) => name === void 0 ? classes : classes.trim() === "" ? name : `${classes} ${name}`;
|
|
2983
|
+
/**
|
|
2984
|
+
* An element's class with the dark-mode class each pass gave it. A choice between literal class
|
|
2985
|
+
* lists resolved one list per pass, so each list gains its own pass's class; any other class
|
|
2986
|
+
* value gains the first pass's. `undefined` when no pass gave the element one.
|
|
2987
|
+
*/
|
|
2988
|
+
const withDarkClass = (value, tree, perPass) => {
|
|
2989
|
+
if (perPass.every((name) => name === void 0)) return void 0;
|
|
2990
|
+
if (tree !== void 0 && leavesOf(tree).length > 1) {
|
|
2991
|
+
let leaf = 0;
|
|
2992
|
+
const extend = (node) => "leaf" in node ? { leaf: appendClass(node.leaf, perPass[Math.min(leaf++, perPass.length - 1)]) } : {
|
|
2993
|
+
pred: node.pred,
|
|
2994
|
+
then: extend(node.then),
|
|
2995
|
+
else: extend(node.else)
|
|
2996
|
+
};
|
|
2997
|
+
return treeValue(extend(tree));
|
|
2998
|
+
}
|
|
2999
|
+
const name = perPass[0];
|
|
3000
|
+
if (name === void 0) return value;
|
|
3001
|
+
if (value === void 0) return name;
|
|
3002
|
+
if (typeof value === "string") return appendClass(value, name);
|
|
3003
|
+
return { concat: [value, ` ${name}`] };
|
|
3004
|
+
};
|
|
2954
3005
|
const collect = (nodes, into) => {
|
|
2955
3006
|
for (const node of nodes) {
|
|
2956
3007
|
if (isValueNode(node)) continue;
|
|
@@ -3057,6 +3108,8 @@ const applyStyles = (root, sheet, options) => {
|
|
|
3057
3108
|
for (const node of nodes) if (node.type === "Fragment") read(node.children, into);
|
|
3058
3109
|
else if (node.type === "Raw") into.raws.push(node.html);
|
|
3059
3110
|
else if (node.type === "Element") {
|
|
3111
|
+
const classes = typeof node.props.class === "string" ? node.props.class.split(" ") : [];
|
|
3112
|
+
into.darkClasses.push(classes.find((name) => name.startsWith(DARK_CLASS_PREFIX)));
|
|
3060
3113
|
into.styles.push(node.props.style === void 0 ? void 0 : node.props.style);
|
|
3061
3114
|
into.bgcolors.push(typeof node.props.bgcolor === "string" ? node.props.bgcolor : void 0);
|
|
3062
3115
|
read(node.children, into);
|
|
@@ -3065,6 +3118,7 @@ const applyStyles = (root, sheet, options) => {
|
|
|
3065
3118
|
const results = [];
|
|
3066
3119
|
let headCss = "";
|
|
3067
3120
|
let fontFaceCss = "";
|
|
3121
|
+
const darkRules = /* @__PURE__ */ new Map();
|
|
3068
3122
|
const seen = /* @__PURE__ */ new Set();
|
|
3069
3123
|
for (let pass = 0; pass < passes; pass++) {
|
|
3070
3124
|
const tree = shadow([root], pass, { next: 0 });
|
|
@@ -3073,6 +3127,7 @@ const applyStyles = (root, sheet, options) => {
|
|
|
3073
3127
|
headCss = applied.headCss;
|
|
3074
3128
|
fontFaceCss = applied.fontFaceCss;
|
|
3075
3129
|
}
|
|
3130
|
+
for (const [name, body] of applied.darkRules) darkRules.set(name, body);
|
|
3076
3131
|
for (const diagnostic of applied.diagnostics) {
|
|
3077
3132
|
const key = `${diagnostic.code}\0${diagnostic.message}`;
|
|
3078
3133
|
if (seen.has(key)) continue;
|
|
@@ -3082,6 +3137,7 @@ const applyStyles = (root, sheet, options) => {
|
|
|
3082
3137
|
const result = {
|
|
3083
3138
|
styles: [],
|
|
3084
3139
|
bgcolors: [],
|
|
3140
|
+
darkClasses: [],
|
|
3085
3141
|
raws: []
|
|
3086
3142
|
};
|
|
3087
3143
|
read([applied.tree], result);
|
|
@@ -3114,10 +3170,15 @@ const applyStyles = (root, sheet, options) => {
|
|
|
3114
3170
|
const baseStyle = first?.styles[ordinal];
|
|
3115
3171
|
const style = tree !== void 0 && leavesOf(tree).length > 1 ? mapTree(tree, (leaf) => styleOf(results[Math.min(leaf, results.length - 1)]?.styles[ordinal], node)) : styleOf(baseStyle, node);
|
|
3116
3172
|
const bgcolor = first?.bgcolors[ordinal];
|
|
3117
|
-
const
|
|
3173
|
+
const painted = typeof node.attrs?.bgcolor === "string" && bgcolor !== void 0 && bgcolor !== node.attrs.bgcolor ? {
|
|
3118
3174
|
...node.attrs,
|
|
3119
3175
|
bgcolor: tokens.toValue(bgcolor) ?? bgcolor
|
|
3120
3176
|
} : node.attrs;
|
|
3177
|
+
const darkClass = withDarkClass(node.attrs?.class, tree, results.map((result) => result.darkClasses[ordinal]));
|
|
3178
|
+
const attrs = darkClass === void 0 ? painted : {
|
|
3179
|
+
...painted,
|
|
3180
|
+
class: darkClass
|
|
3181
|
+
};
|
|
3121
3182
|
const kids = rebuild(node.children ?? []);
|
|
3122
3183
|
const { style: _authored, children: _children, attrs: _attrs, ...rest } = node;
|
|
3123
3184
|
return {
|
|
@@ -3152,7 +3213,7 @@ const applyStyles = (root, sheet, options) => {
|
|
|
3152
3213
|
});
|
|
3153
3214
|
return {
|
|
3154
3215
|
root: rebuild([root])[0] ?? root,
|
|
3155
|
-
headCss
|
|
3216
|
+
headCss: `${renderDarkRules(darkRules)}${headCss}`,
|
|
3156
3217
|
fontFaceCss
|
|
3157
3218
|
};
|
|
3158
3219
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { S as emailElement, o as serializeEmailHtml } from "./html-eOZfDwVf.js";
|
|
2
2
|
import { i as drainEmailDiagnostics, t as EmailNode } from "./jsx-runtime-CBlexoeR.js";
|
|
3
|
-
import { f as preheaderNode } from "./components-
|
|
4
|
-
import {
|
|
3
|
+
import { f as preheaderNode } from "./components-CwWSoG5N.js";
|
|
4
|
+
import { i as renderDarkRules, r as applyStylesheet } from "./ir-D-gTGquU.js";
|
|
5
5
|
import { r as hasBlockingDiagnostic, t as EmailCompileError } from "./diagnostics-C0Tr8-eQ.js";
|
|
6
6
|
//#region src/email/text.ts
|
|
7
7
|
const PARAGRAPH = "\n\n";
|
|
@@ -219,12 +219,14 @@ const renderEmailContent = (stylesheet, render, options = {}) => {
|
|
|
219
219
|
tree: base,
|
|
220
220
|
headCss: "",
|
|
221
221
|
fontFaceCss: "",
|
|
222
|
-
diagnostics: []
|
|
222
|
+
diagnostics: [],
|
|
223
|
+
darkRules: /* @__PURE__ */ new Map()
|
|
223
224
|
} : applyStylesheet(base, stylesheet);
|
|
225
|
+
const headCss = `${renderDarkRules(styled.darkRules)}${styled.headCss}`;
|
|
224
226
|
const style = [...styled.diagnostics];
|
|
225
227
|
let tree = styled.tree;
|
|
226
|
-
if (
|
|
227
|
-
const placed = withHeadCss(tree,
|
|
228
|
+
if (headCss !== "" || styled.fontFaceCss !== "") {
|
|
229
|
+
const placed = withHeadCss(tree, headCss, styled.fontFaceCss);
|
|
228
230
|
if (placed === void 0) style.push({
|
|
229
231
|
code: "missing-head",
|
|
230
232
|
severity: "error",
|
|
@@ -441,6 +441,11 @@ interface Stylesheet {
|
|
|
441
441
|
readonly fontFaces: readonly FontFaceRule[];
|
|
442
442
|
/** Unconditional custom properties, for resolving `var()` before inlining. */
|
|
443
443
|
readonly variables: Readonly<Record<string, string>>;
|
|
444
|
+
/**
|
|
445
|
+
* The custom properties the dark-mode query redefines (a theme's dark-mode
|
|
446
|
+
* block). A declaration that reads one switches in dark mode.
|
|
447
|
+
*/
|
|
448
|
+
readonly darkVariables: Readonly<Record<string, string>>;
|
|
444
449
|
readonly diagnostics: readonly EmailDiagnostic[];
|
|
445
450
|
}
|
|
446
451
|
/** Compile a selector into the plain-data matcher the render lane uses. */
|
package/dist/render.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { C as isUrlAttribute, S as emailElement, _ as EmailGlobalProps, b as EmailStyle, g as EmailElementSpec, h as EmailAttributeSpec, m as EMAIL_GLOBAL_ATTRIBUTES, p as EMAIL_ELEMENTS, r as EmailNode, v as EmailIntrinsicElements, x as EmailTag, y as EmailLayout } from "./jsx-runtime-DC7xG0aA.js";
|
|
2
|
-
import { $ as IrWhatsApp, A as emailAuthoringTarget, B as IrElement, D as EmittedPosition, E as EmailElementSelection, F as emailSelections, G as IrPredicate, H as IrFormatter, I as renderIrPreview, J as IrRawPart, K as IrPreheader, L as IrArithmetic, M as emailSelectionAncestry, N as emailSelectionIndex, O as INSTANCE_PATH_ATTRIBUTE, P as emailSelectionSiblings, Q as IrValue, R as IrComparison, U as IrIf, V as IrEmail, W as IrNode, X as IrSource, Y as IrSms, Z as IrStyle, a as renderEmailContent, at as RenderedPosition, c as checkAttribute, ct as TemplateIr, d as escapeText, et as IrWhatsAppButton, f as kebab, i as compileEmail, it as RenderedIrWhatsApp, j as emailDefinitionInstances, k as IrPreview, l as declarationValue, m as serializeStyle, n as EmailCompileOutput, nt as RenderOptions, o as EmailHtmlOutput, ot as RenderedWhatsAppButton, p as serializeEmailHtml, q as IrRaw, r as RenderedEmail, rt as RenderedIrEmail, s as SerializeEmailOptions, st as SML_IR_VERSION, t as EMAIL_DOCTYPE, tt as IrWhatsAppButtonNode, u as escapeAttribute, z as IrEach } from "./render-
|
|
2
|
+
import { $ as IrWhatsApp, A as emailAuthoringTarget, B as IrElement, D as EmittedPosition, E as EmailElementSelection, F as emailSelections, G as IrPredicate, H as IrFormatter, I as renderIrPreview, J as IrRawPart, K as IrPreheader, L as IrArithmetic, M as emailSelectionAncestry, N as emailSelectionIndex, O as INSTANCE_PATH_ATTRIBUTE, P as emailSelectionSiblings, Q as IrValue, R as IrComparison, U as IrIf, V as IrEmail, W as IrNode, X as IrSource, Y as IrSms, Z as IrStyle, a as renderEmailContent, at as RenderedPosition, c as checkAttribute, ct as TemplateIr, d as escapeText, et as IrWhatsAppButton, f as kebab, i as compileEmail, it as RenderedIrWhatsApp, j as emailDefinitionInstances, k as IrPreview, l as declarationValue, m as serializeStyle, n as EmailCompileOutput, nt as RenderOptions, o as EmailHtmlOutput, ot as RenderedWhatsAppButton, p as serializeEmailHtml, q as IrRaw, r as RenderedEmail, rt as RenderedIrEmail, s as SerializeEmailOptions, st as SML_IR_VERSION, t as EMAIL_DOCTYPE, tt as IrWhatsAppButtonNode, u as escapeAttribute, z as IrEach } from "./render-C1X3S5or.js";
|
|
3
3
|
//#region src/render-ir.d.ts
|
|
4
4
|
interface IrRenderDiagnostic {
|
|
5
5
|
readonly code: string;
|
package/dist/render.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { C as isUrlAttribute, S as emailElement, _ as renderIr, a as kebab, b as EMAIL_ELEMENTS, c as INSTANCE_PATH_ATTRIBUTE, d as emailSelectionAncestry, f as emailSelectionIndex, g as IrRenderError, h as renderIrPreview, i as escapeText, l as emailAuthoringTarget, m as emailSelections, n as declarationValue, o as serializeEmailHtml, p as emailSelectionSiblings, r as escapeAttribute, s as serializeStyle, t as checkAttribute, u as emailDefinitionInstances, v as renderIrSms, x as EMAIL_GLOBAL_ATTRIBUTES, y as renderIrWhatsApp } from "./html-eOZfDwVf.js";
|
|
2
|
-
import { t as SML_IR_VERSION } from "./ir-
|
|
3
|
-
import { i as deriveEmailText, n as compileEmail, r as renderEmailContent, t as EMAIL_DOCTYPE } from "./render-
|
|
2
|
+
import { t as SML_IR_VERSION } from "./ir-D-gTGquU.js";
|
|
3
|
+
import { i as deriveEmailText, n as compileEmail, r as renderEmailContent, t as EMAIL_DOCTYPE } from "./render-6gLei61p.js";
|
|
4
4
|
//#region src/sms-segments.ts
|
|
5
5
|
const GSM7_EXTENDED = /* @__PURE__ */ new Set([
|
|
6
6
|
"[",
|