@samva/markup 0.8.0 → 0.10.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.
Files changed (172) hide show
  1. package/AGENTS.md +107 -46
  2. package/CHANGELOG.md +345 -0
  3. package/README.md +188 -52
  4. package/dist/{brand-DcoVkh_S.d.ts → assets-BIsyMQ92.d.ts} +41 -11
  5. package/dist/{email/brand.js → brand-C0MKTwmX.js} +64 -4
  6. package/dist/{theme-css.d.ts → brand.d.ts} +12 -3
  7. package/dist/brand.js +4 -0
  8. package/dist/channel-specs-C2feJwuP.d.ts +13 -0
  9. package/dist/compiler.d.ts +88 -115
  10. package/dist/compiler.js +750 -171
  11. package/dist/components-BZCqegS8.js +1864 -0
  12. package/dist/diagnostic-model-DJtqbETd.js +38 -0
  13. package/dist/{diagnostics-OcQKQYSY.d.ts → diagnostic-model-DxthUZBT.d.ts} +3 -21
  14. package/dist/{diagnostics-BMYtBCQk.d.ts → diagnostics-B-Gym34R.d.ts} +8 -4
  15. package/dist/{email/diagnostics.js → diagnostics-CnKFefKz.js} +4 -3
  16. package/dist/diagnostics.d.ts +410 -2
  17. package/dist/diagnostics.js +402 -52
  18. package/dist/edit.d.ts +234 -0
  19. package/dist/edit.js +947 -0
  20. package/dist/email/jsx-dev-runtime.d.ts +2 -2
  21. package/dist/email/jsx-dev-runtime.js +1 -2
  22. package/dist/email/jsx-runtime.d.ts +1 -1
  23. package/dist/email/jsx-runtime.js +1 -85
  24. package/dist/{email/components.d.ts → email.d.ts} +22 -11
  25. package/dist/email.js +2 -0
  26. package/dist/fmt.d.ts +32 -0
  27. package/dist/fmt.js +174 -0
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.js +2 -0
  30. package/dist/{render-vAv_4r9v.js → ir-CLhlklKV.js} +96 -279
  31. package/dist/jsx-runtime-CBlexoeR.js +98 -0
  32. package/dist/{elements-BzjjnoCS.d.ts → jsx-runtime-ylIOnaSf.d.ts} +76 -76
  33. package/dist/profile-pWGtWZXF.js +3803 -0
  34. package/dist/render-BPonDpCl.d.ts +539 -0
  35. package/dist/render-BQmfh94k.js +257 -0
  36. package/dist/render.d.ts +35 -0
  37. package/dist/render.js +49 -0
  38. package/dist/sms.d.ts +16 -0
  39. package/dist/sms.js +12 -0
  40. package/dist/source-locations-C8wCsiAy.d.ts +23 -0
  41. package/dist/template-DMPwxMSq.d.ts +65 -0
  42. package/dist/template-zLUjcwfF.js +42 -0
  43. package/dist/{theme-css-hFqcPSar.js → theme-css-JtRCm1fb.js} +2 -2
  44. package/dist/whatsapp.d.ts +57 -0
  45. package/dist/whatsapp.js +22 -0
  46. package/generated/contract.json +1788 -0
  47. package/generated/reference.md +360 -0
  48. package/package.json +46 -239
  49. package/samva-brand.d.ts +4 -4
  50. package/skills/sml/SKILL.md +123 -0
  51. package/dist/ast-BrDtApwS.d.ts +0 -107
  52. package/dist/ast.d.ts +0 -2
  53. package/dist/ast.js +0 -124
  54. package/dist/candidate.d.ts +0 -29
  55. package/dist/candidate.js +0 -88
  56. package/dist/catalog-CKuOooB8.d.ts +0 -354
  57. package/dist/checks-D73Xizbw.js +0 -59366
  58. package/dist/checks.d.ts +0 -33
  59. package/dist/checks.js +0 -2
  60. package/dist/classes.d.ts +0 -26
  61. package/dist/classes.js +0 -184
  62. package/dist/compile-sms.d.ts +0 -28
  63. package/dist/compile-sms.js +0 -44
  64. package/dist/compile-whatsapp.d.ts +0 -56
  65. package/dist/compile-whatsapp.js +0 -186
  66. package/dist/compile.d.ts +0 -18
  67. package/dist/compile.js +0 -29
  68. package/dist/components.d.ts +0 -289
  69. package/dist/components.js +0 -106
  70. package/dist/conditionals.d.ts +0 -10
  71. package/dist/conditionals.js +0 -74
  72. package/dist/corpus-CPPfgAHN.d.ts +0 -106
  73. package/dist/css-CS2jLID6.d.ts +0 -109
  74. package/dist/email/assets.d.ts +0 -40
  75. package/dist/email/assets.js +0 -63
  76. package/dist/email/brand-footer.d.ts +0 -34
  77. package/dist/email/brand-footer.js +0 -62
  78. package/dist/email/brand.d.ts +0 -2
  79. package/dist/email/components.js +0 -240
  80. package/dist/email/diagnostics.d.ts +0 -2
  81. package/dist/email/elements.d.ts +0 -2
  82. package/dist/email/elements.js +0 -299
  83. package/dist/email/html.d.ts +0 -2
  84. package/dist/email/html.js +0 -278
  85. package/dist/email/render.d.ts +0 -50
  86. package/dist/email/render.js +0 -3
  87. package/dist/email/selection.d.ts +0 -2
  88. package/dist/email/selection.js +0 -91
  89. package/dist/email/source-edit.d.ts +0 -67
  90. package/dist/email/source-edit.js +0 -185
  91. package/dist/email/stylesheets.d.ts +0 -15
  92. package/dist/email/stylesheets.js +0 -48
  93. package/dist/email/text.d.ts +0 -7
  94. package/dist/email/text.js +0 -100
  95. package/dist/emit.d.ts +0 -51
  96. package/dist/emit.js +0 -151
  97. package/dist/html-Bl9BAdqc.d.ts +0 -42
  98. package/dist/interpolate.d.ts +0 -24
  99. package/dist/interpolate.js +0 -43
  100. package/dist/jsx-dev-runtime.d.ts +0 -11
  101. package/dist/jsx-dev-runtime.js +0 -15
  102. package/dist/jsx-runtime-I-1nCtl2.d.ts +0 -57
  103. package/dist/jsx-runtime.d.ts +0 -2
  104. package/dist/jsx-runtime.js +0 -121
  105. package/dist/lexer.d.ts +0 -60
  106. package/dist/lexer.js +0 -281
  107. package/dist/model.d.ts +0 -24
  108. package/dist/model.js +0 -77
  109. package/dist/ops-BvwqHl7V.js +0 -630
  110. package/dist/ops.d.ts +0 -114
  111. package/dist/ops.js +0 -2
  112. package/dist/parser-t29cHLVL.d.ts +0 -396
  113. package/dist/parser.d.ts +0 -2
  114. package/dist/parser.js +0 -859
  115. package/dist/predicate-BI6uRRM-.js +0 -549
  116. package/dist/predicate-M-05Nd7R.d.ts +0 -56
  117. package/dist/predicate.d.ts +0 -2
  118. package/dist/predicate.js +0 -2
  119. package/dist/printer.d.ts +0 -6
  120. package/dist/printer.js +0 -122
  121. package/dist/registry-Dcp6QEK_.d.ts +0 -73
  122. package/dist/registry.d.ts +0 -2
  123. package/dist/registry.js +0 -646
  124. package/dist/render-template.d.ts +0 -45
  125. package/dist/render-template.js +0 -76
  126. package/dist/selection-CCArx9lU.d.ts +0 -91
  127. package/dist/showcase-egkusQBf.d.ts +0 -415
  128. package/dist/sms-segments-y4FpPilJ.d.ts +0 -13
  129. package/dist/sms-segments.d.ts +0 -2
  130. package/dist/sms-segments.js +0 -46
  131. package/dist/source-locations-DrCM82Ym.d.ts +0 -67
  132. package/dist/source-locations.d.ts +0 -2
  133. package/dist/source-locations.js +0 -102
  134. package/dist/starters/category-mapping.d.ts +0 -13
  135. package/dist/starters/category-mapping.js +0 -49
  136. package/dist/starters/corpus.d.ts +0 -2
  137. package/dist/starters/corpus.js +0 -194
  138. package/dist/starters/library.d.ts +0 -18
  139. package/dist/starters/library.js +0 -692
  140. package/dist/starters/public-gallery.d.ts +0 -266
  141. package/dist/starters/public-gallery.js +0 -916
  142. package/dist/starters/public-handoff.d.ts +0 -164
  143. package/dist/starters/public-handoff.js +0 -361
  144. package/dist/starters/public-preview-artifacts.d.ts +0 -43
  145. package/dist/starters/public-preview-artifacts.js +0 -104
  146. package/dist/starters/public-preview.d.ts +0 -61
  147. package/dist/starters/public-preview.js +0 -83
  148. package/dist/starters/showcase.d.ts +0 -2
  149. package/dist/starters/showcase.js +0 -335
  150. package/dist/starters/sources.d.ts +0 -45
  151. package/dist/starters/sources.js +0 -7762
  152. package/dist/starters/theme.d.ts +0 -45
  153. package/dist/starters/theme.js +0 -77
  154. package/dist/starters.d.ts +0 -2
  155. package/dist/starters.js +0 -874
  156. package/dist/tailwind-BYq7Lo6u.js +0 -727
  157. package/dist/template-DWftqh4x.d.ts +0 -60
  158. package/dist/template.d.ts +0 -2
  159. package/dist/template.js +0 -37
  160. package/dist/theme-css.js +0 -2
  161. package/dist/tsx-source-instrumentation.d.ts +0 -30
  162. package/dist/tsx-source-instrumentation.js +0 -115
  163. package/dist/tsx-tracer.d.ts +0 -112
  164. package/dist/tsx-tracer.js +0 -985
  165. package/dist/variables-J_L3qxRa.d.ts +0 -77
  166. package/dist/variables.d.ts +0 -2
  167. package/dist/variables.js +0 -141
  168. package/dist/version-BITr58kk.js +0 -96
  169. package/generated/sml-agent-contract.json +0 -709
  170. package/generated/sml-email-agent-contract.json +0 -615
  171. package/generated/sml-email-language-reference.md +0 -94
  172. package/generated/sml-language-reference.md +0 -195
@@ -0,0 +1,257 @@
1
+ import { P as emailElement, f as preheaderNode, v as serializeEmailHtml } from "./components-BZCqegS8.js";
2
+ import { i as drainEmailDiagnostics, t as EmailNode } from "./jsx-runtime-CBlexoeR.js";
3
+ import { n as applyStylesheet } from "./ir-CLhlklKV.js";
4
+ import { r as hasBlockingDiagnostic, t as EmailCompileError } from "./diagnostics-CnKFefKz.js";
5
+ //#region src/email/text.ts
6
+ const PARAGRAPH = "\n\n";
7
+ const LINE = "\n";
8
+ const INVISIBLE = /\u200b|\u200c|\u200d|\u200e|\u200f|\u2060|\ufeff/g;
9
+ const isLayoutTable = (props) => props.role === "presentation" || props.role === "none";
10
+ /**
11
+ * A data-table cell that reads as nothing and holds only imagery with empty alt text carries no
12
+ * column of its own; an empty cell without such an image is a positional placeholder.
13
+ */
14
+ const isDecorativeCell = (cell, context) => {
15
+ const images = collect(cell.children, (tag) => tag === "img", () => true);
16
+ return images.length > 0 && images.every((image) => image.props.alt === "") && childText(cell, context).trim() === "";
17
+ };
18
+ /** Wrap a block's content in separators; empty blocks contribute nothing. */
19
+ const block = (inner, separator) => {
20
+ const trimmed = inner.replace(/^\s+/, "").replace(/\s+$/, "");
21
+ return trimmed === "" ? "" : `${separator}${trimmed}${separator}`;
22
+ };
23
+ const collect = (nodes, keep, descend) => nodes.flatMap((child) => {
24
+ if (child.type === "Fragment") return collect(child.children, keep, descend);
25
+ if (child.type !== "Element") return [];
26
+ if (keep(child.tag)) return [child];
27
+ return descend(child.tag) ? collect(child.children, keep, descend) : [];
28
+ });
29
+ const TABLE_SECTIONS = /* @__PURE__ */ new Set([
30
+ "thead",
31
+ "tbody",
32
+ "tfoot"
33
+ ]);
34
+ const childText = (node, context) => node.children.map((child) => derive(child, context)).join("");
35
+ const derive = (node, context) => {
36
+ switch (node.type) {
37
+ case "Text": return context.preformatted ? node.value : node.value.replace(INVISIBLE, "").replace(/[^\S\n]+/g, " ");
38
+ case "Raw": return node.text;
39
+ case "Fragment": return node.children.map((child) => derive(child, context)).join("");
40
+ case "Element": {
41
+ const spec = emailElement(node.tag);
42
+ if (spec === void 0) return childText(node, context);
43
+ switch (spec.layout) {
44
+ case "metadata": return "";
45
+ case "document":
46
+ case "inline":
47
+ case "list-item": return childText(node, context);
48
+ case "break": return LINE;
49
+ case "rule": return `${PARAGRAPH}---${PARAGRAPH}`;
50
+ case "image": {
51
+ const alt = typeof node.props.alt === "string" ? node.props.alt.trim() : "";
52
+ return alt === "" ? "" : `[${alt}]`;
53
+ }
54
+ case "link": {
55
+ const label = childText(node, context).replace(/\s+/g, " ").trim();
56
+ const href = typeof node.props.href === "string" ? node.props.href : "";
57
+ if (href === "" || href === label) return label;
58
+ return label === "" ? href : `${label} (${href})`;
59
+ }
60
+ case "list": {
61
+ const indent = " ".repeat(context.listDepth);
62
+ const start = Number(node.props.start ?? 1);
63
+ const first = Number.isFinite(start) ? start : 1;
64
+ const nested = {
65
+ ...context,
66
+ listDepth: context.listDepth + 1
67
+ };
68
+ const lines = collect(node.children, (tag) => tag === "li", () => false).map((item, index) => {
69
+ const marker = node.tag === "ol" ? `${first + index}.` : "-";
70
+ const continuation = `${indent}${" ".repeat(marker.length + 1)}`;
71
+ const [head = "", ...rest] = derive(item, nested).replace(/^\s+/, "").replace(/\s+$/, "").replace(/\n{2,}/g, LINE).split("\n");
72
+ return [`${indent}${marker} ${head}`, ...rest.map((line) => line.trim() === "" ? "" : /^\s/.test(line) ? line : `${continuation}${line}`)].join(LINE);
73
+ });
74
+ return block(lines.join(LINE), PARAGRAPH);
75
+ }
76
+ case "table": {
77
+ if (isLayoutTable(node.props)) return childText(node, context);
78
+ const rows = collect(node.children, (tag) => tag === "tr", (tag) => TABLE_SECTIONS.has(tag)).map((row) => collect(row.children, (tag) => tag === "td" || tag === "th", () => false).filter((cell) => !isDecorativeCell(cell, context)).map((cell) => childText(cell, context).replace(/\s+/g, " ").trim()).join(" | "));
79
+ return block(rows.join(LINE), PARAGRAPH);
80
+ }
81
+ case "row": return block(collect(node.children, (tag) => tag === "td" || tag === "th", () => false).map((cell) => childText(cell, context).replace(/^\s+|\s+$/g, "")).filter((cell) => cell !== "").join(LINE), LINE);
82
+ case "table-section":
83
+ case "cell": return block(childText(node, context), LINE);
84
+ case "preformatted": return block(childText(node, {
85
+ ...context,
86
+ preformatted: true
87
+ }), PARAGRAPH);
88
+ case "block": return block(childText(node, context), PARAGRAPH);
89
+ }
90
+ }
91
+ }
92
+ };
93
+ /** Collapse the separators the walk emits into readable plain text. */
94
+ const normalize = (value) => value.replace(/\r\n?/g, "\n").split("\n").map((line) => line.replace(/[^\S\n]+$/, "")).join("\n").replace(/\n{3,}/g, PARAGRAPH).trim();
95
+ /** Derive the plain-text alternative from the semantic tree in reading order. */
96
+ const deriveEmailText = (node) => normalize(derive(node, {
97
+ preformatted: false,
98
+ listDepth: 0
99
+ }));
100
+ //#endregion
101
+ //#region src/email/render.ts
102
+ /** Classic Outlook lays a document out correctly only under a transitional doctype. */
103
+ const EMAIL_DOCTYPE = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">";
104
+ const settle = (diagnostics) => {
105
+ if (hasBlockingDiagnostic(diagnostics)) throw new EmailCompileError({ diagnostics });
106
+ return diagnostics;
107
+ };
108
+ /** Lower the derived tree to HTML and its plain-text alternative. */
109
+ const compileEmail = (node, options = {}) => {
110
+ const serialized = serializeEmailHtml(node, options);
111
+ const diagnostics = settle([...drainEmailDiagnostics(), ...serialized.diagnostics]);
112
+ return {
113
+ html: serialized.html,
114
+ text: deriveEmailText(node),
115
+ diagnostics,
116
+ positions: serialized.positions
117
+ };
118
+ };
119
+ /** Put the hidden preview block first inside `<body>`, or first overall when there is no shell. */
120
+ const withPreheader = (node, text) => {
121
+ const insert = (current) => {
122
+ if (current.type === "Fragment") {
123
+ for (const [index, child] of current.children.entries()) {
124
+ const replaced = insert(child);
125
+ if (replaced !== void 0) return EmailNode.Fragment({ children: current.children.with(index, replaced) });
126
+ }
127
+ return;
128
+ }
129
+ if (current.type !== "Element") return void 0;
130
+ if (current.tag === "body") return EmailNode.Element({
131
+ ...current,
132
+ children: [preheaderNode(text), ...current.children]
133
+ });
134
+ for (const [index, child] of current.children.entries()) {
135
+ const replaced = insert(child);
136
+ if (replaced !== void 0) return EmailNode.Element({
137
+ ...current,
138
+ children: current.children.with(index, replaced)
139
+ });
140
+ }
141
+ };
142
+ return insert(node) ?? EmailNode.Fragment({ children: [preheaderNode(text), node] });
143
+ };
144
+ const headStyle = (css, origins) => EmailNode.Element({
145
+ tag: "style",
146
+ props: {},
147
+ children: [EmailNode.Text({ value: css })],
148
+ origins,
149
+ authored: false
150
+ });
151
+ /**
152
+ * Put the retained rules in a `<style>` at the end of `<head>`, and project
153
+ * `@font-face` rules in a sibling classic Outlook cannot see. Outlook for
154
+ * Windows registers a face it cannot load and then renders the family in Times
155
+ * New Roman, ignoring the stack; hidden, the family is merely missing and the
156
+ * stack's fallback applies.
157
+ */
158
+ const withHeadCss = (node, css, fontFaceCss) => {
159
+ const insert = (current) => {
160
+ if (current.type === "Fragment") {
161
+ for (const [index, child] of current.children.entries()) {
162
+ const replaced = insert(child);
163
+ if (replaced !== void 0) return EmailNode.Fragment({ children: current.children.with(index, replaced) });
164
+ }
165
+ return;
166
+ }
167
+ if (current.type !== "Element") return void 0;
168
+ if (current.tag === "head") return EmailNode.Element({
169
+ ...current,
170
+ children: [
171
+ ...current.children,
172
+ ...css === "" ? [] : [headStyle(css, current.origins)],
173
+ ...fontFaceCss === "" ? [] : [
174
+ EmailNode.Raw({
175
+ html: "<!--[if !mso]><!-->",
176
+ text: "",
177
+ origins: []
178
+ }),
179
+ headStyle(fontFaceCss, current.origins),
180
+ EmailNode.Raw({
181
+ html: "<!--<![endif]-->",
182
+ text: "",
183
+ origins: []
184
+ })
185
+ ]
186
+ ]
187
+ });
188
+ for (const [index, child] of current.children.entries()) {
189
+ const replaced = insert(child);
190
+ if (replaced !== void 0) return EmailNode.Element({
191
+ ...current,
192
+ children: current.children.with(index, replaced)
193
+ });
194
+ }
195
+ };
196
+ return insert(node);
197
+ };
198
+ /**
199
+ * Render authored content against a stylesheet: inline what a client honors,
200
+ * keep the rest for `<head>`, and lower to HTML and text.
201
+ */
202
+ const renderEmailContent = (stylesheet, render, options = {}) => {
203
+ drainEmailDiagnostics();
204
+ const content = render();
205
+ const invalid = [];
206
+ const fail = (code, message) => invalid.push({
207
+ code,
208
+ severity: "error",
209
+ message,
210
+ origins: []
211
+ });
212
+ if (typeof content.subject !== "string" || /[\r\n\u0000]/.test(content.subject)) fail("invalid-subject", "Invalid email subject: it must be one line of text.");
213
+ if (content.preheader !== void 0 && typeof content.preheader !== "string") fail("invalid-preheader", "Invalid email preheader: it must be a string.");
214
+ if (content.text !== void 0 && typeof content.text !== "string") fail("invalid-text", "Invalid plain text: it must be a string.");
215
+ settle(invalid);
216
+ const base = content.preheader === void 0 ? content.body : withPreheader(content.body, content.preheader);
217
+ const styled = stylesheet === void 0 ? {
218
+ tree: base,
219
+ headCss: "",
220
+ fontFaceCss: "",
221
+ diagnostics: []
222
+ } : applyStylesheet(base, stylesheet);
223
+ const style = [...styled.diagnostics];
224
+ let tree = styled.tree;
225
+ if (styled.headCss !== "" || styled.fontFaceCss !== "") {
226
+ const placed = withHeadCss(tree, styled.headCss, styled.fontFaceCss);
227
+ if (placed === void 0) style.push({
228
+ code: "missing-head",
229
+ severity: "error",
230
+ message: "Styles that cannot be inlined — media queries, dark-scheme rules and pseudo-selectors — need a <head> to live in. Wrap the message in <Email>, or write those declarations as inline styles.",
231
+ origins: []
232
+ });
233
+ else tree = placed;
234
+ }
235
+ settle(style);
236
+ const compiled = compileEmail(tree, options);
237
+ const prefix = compiled.html.startsWith("<html") ? EMAIL_DOCTYPE : "";
238
+ const html = `${prefix}${compiled.html}`;
239
+ const positions = prefix === "" ? compiled.positions : compiled.positions.map((position) => ({
240
+ ...position,
241
+ start: position.start + prefix.length,
242
+ end: position.end + prefix.length
243
+ }));
244
+ return {
245
+ subject: content.subject,
246
+ preheader: content.preheader,
247
+ html,
248
+ text: content.text ?? compiled.text,
249
+ tree,
250
+ diagnostics: [...style, ...compiled.diagnostics],
251
+ positions
252
+ };
253
+ };
254
+ //#endregion
255
+ export { deriveEmailText as i, compileEmail as n, renderEmailContent as r, EMAIL_DOCTYPE as t };
256
+
257
+ //# sourceMappingURL=render-BQmfh94k.js.map
@@ -0,0 +1,35 @@
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-ylIOnaSf.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-BPonDpCl.js";
3
+ //#region src/render-ir.d.ts
4
+ interface IrRenderDiagnostic {
5
+ readonly code: string;
6
+ readonly message: string;
7
+ }
8
+ declare class IrRenderError extends Error {
9
+ readonly diagnostics: readonly IrRenderDiagnostic[];
10
+ constructor(diagnostics: readonly IrRenderDiagnostic[]);
11
+ }
12
+ /** Render the email channel of a compiled template against one validated input. */
13
+ declare const renderIr: (ir: TemplateIr, input: unknown, options?: RenderOptions) => RenderedIrEmail;
14
+ /** Render the SMS channel of a compiled template to plain text. */
15
+ declare const renderIrSms: (ir: TemplateIr, input: unknown, options?: RenderOptions) => string;
16
+ /** Render the WhatsApp channel of a compiled template: every text rendered, conditional buttons resolved. */
17
+ declare const renderIrWhatsApp: (ir: TemplateIr, input: unknown, options?: RenderOptions) => RenderedIrWhatsApp;
18
+ //#endregion
19
+ //#region src/email/text.d.ts
20
+ /** Derive the plain-text alternative from the semantic tree in reading order. */
21
+ declare const deriveEmailText: (node: EmailNode) => string;
22
+ //#endregion
23
+ //#region src/sms-segments.d.ts
24
+ /** The encoding a message needs: GSM-7 when every character fits, UCS-2 otherwise. */
25
+ type SmsEncoding = "gsm7" | "ucs2";
26
+ interface SmsSegmentInfo {
27
+ readonly encoding: SmsEncoding;
28
+ readonly characterCount: number;
29
+ readonly segmentCount: number;
30
+ }
31
+ declare const smsSegmentInfo: (text: string) => SmsSegmentInfo;
32
+ declare const hasSmsOptOut: (text: string) => boolean;
33
+ //#endregion
34
+ export { EMAIL_DOCTYPE, EMAIL_ELEMENTS, EMAIL_GLOBAL_ATTRIBUTES, EmailAttributeSpec, EmailCompileOutput, EmailElementSelection, EmailElementSpec, EmailGlobalProps, EmailHtmlOutput, EmailIntrinsicElements, EmailLayout, EmailStyle, EmailTag, EmittedPosition, INSTANCE_PATH_ATTRIBUTE, IrArithmetic, IrComparison, IrEach, IrElement, IrEmail, IrFormatter, IrIf, IrNode, IrPredicate, IrPreheader, IrPreview, IrRaw, IrRawPart, IrRenderDiagnostic, IrRenderError, IrSms, IrSource, IrStyle, IrValue, IrWhatsApp, IrWhatsAppButton, IrWhatsAppButtonNode, RenderOptions, RenderedEmail, RenderedIrEmail, RenderedIrWhatsApp, RenderedPosition, RenderedWhatsAppButton, SML_IR_VERSION, SerializeEmailOptions, SmsEncoding, SmsSegmentInfo, TemplateIr, checkAttribute, compileEmail, declarationValue, deriveEmailText, emailAuthoringTarget, emailDefinitionInstances, emailElement, emailSelectionAncestry, emailSelectionIndex, emailSelectionSiblings, emailSelections, escapeAttribute, escapeText, hasSmsOptOut, isUrlAttribute, kebab, renderEmailContent, renderIr, renderIrPreview, renderIrSms, renderIrWhatsApp, serializeEmailHtml, serializeStyle, smsSegmentInfo };
35
+ //# sourceMappingURL=render.d.ts.map
package/dist/render.js ADDED
@@ -0,0 +1,49 @@
1
+ import { A as renderIrSms, C as emailSelectionAncestry, D as renderIrPreview, E as emailSelections, F as isUrlAttribute, M as EMAIL_ELEMENTS, N as EMAIL_GLOBAL_ATTRIBUTES, O as IrRenderError, P as emailElement, S as emailDefinitionInstances, T as emailSelectionSiblings, _ as kebab, b as INSTANCE_PATH_ATTRIBUTE, g as escapeText, h as escapeAttribute, j as renderIrWhatsApp, k as renderIr, m as declarationValue, p as checkAttribute, v as serializeEmailHtml, w as emailSelectionIndex, x as emailAuthoringTarget, y as serializeStyle } from "./components-BZCqegS8.js";
2
+ import { t as SML_IR_VERSION } from "./ir-CLhlklKV.js";
3
+ import { i as deriveEmailText, n as compileEmail, r as renderEmailContent, t as EMAIL_DOCTYPE } from "./render-BQmfh94k.js";
4
+ //#region src/sms-segments.ts
5
+ const GSM7_EXTENDED = /* @__PURE__ */ new Set([
6
+ "[",
7
+ "]",
8
+ "{",
9
+ "}",
10
+ "\\",
11
+ "~",
12
+ "|",
13
+ "€",
14
+ "^",
15
+ "\f"
16
+ ]);
17
+ const GSM7_BASIC_PATTERN = /^[@£$¥èéùìòÇ\nØø\rÅåΔ_ΦΓΛΩΠΨΣΘΞÆæßÉ !"#¤%&'()*+,\-./:;<=>?¡0-9ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÑܧ¿abcdefghijklmnopqrstuvwxyzäöñüà]*$/;
18
+ const containsNonGsmCharacters = (text) => {
19
+ for (const char of text) {
20
+ if (GSM7_EXTENDED.has(char)) continue;
21
+ if (!GSM7_BASIC_PATTERN.test(char)) return true;
22
+ }
23
+ return false;
24
+ };
25
+ const smsSegmentInfo = (text) => {
26
+ if (containsNonGsmCharacters(text)) {
27
+ const codePoints = [...text].length;
28
+ const segmentCount = codePoints <= 70 ? 1 : Math.ceil(codePoints / 67);
29
+ return {
30
+ encoding: "ucs2",
31
+ characterCount: text.length,
32
+ segmentCount
33
+ };
34
+ }
35
+ let encodedLength = 0;
36
+ for (const char of text) encodedLength += GSM7_EXTENDED.has(char) ? 2 : 1;
37
+ const segmentCount = encodedLength <= 160 ? 1 : Math.ceil(encodedLength / 153);
38
+ return {
39
+ encoding: "gsm7",
40
+ characterCount: text.length,
41
+ segmentCount
42
+ };
43
+ };
44
+ const SMS_OPT_OUT_PATTERN = /\b(stop|unsubscribe|opt[\s-]?out|cancel|quit)\b/i;
45
+ const hasSmsOptOut = (text) => SMS_OPT_OUT_PATTERN.test(text);
46
+ //#endregion
47
+ export { EMAIL_DOCTYPE, EMAIL_ELEMENTS, EMAIL_GLOBAL_ATTRIBUTES, INSTANCE_PATH_ATTRIBUTE, IrRenderError, SML_IR_VERSION, checkAttribute, compileEmail, declarationValue, deriveEmailText, emailAuthoringTarget, emailDefinitionInstances, emailElement, emailSelectionAncestry, emailSelectionIndex, emailSelectionSiblings, emailSelections, escapeAttribute, escapeText, hasSmsOptOut, isUrlAttribute, kebab, renderEmailContent, renderIr, renderIrPreview, renderIrSms, renderIrWhatsApp, serializeEmailHtml, serializeStyle, smsSegmentInfo };
48
+
49
+ //# sourceMappingURL=render.js.map
package/dist/sms.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { r as EmailNode, t as EmailChild } from "./jsx-runtime-ylIOnaSf.js";
2
+ import { t as SmsCategory } from "./channel-specs-C2feJwuP.js";
3
+ //#region src/sms.d.ts
4
+ interface SmsProps {
5
+ readonly category?: SmsCategory | undefined;
6
+ readonly children?: EmailChild;
7
+ }
8
+ /**
9
+ * The root of an SMS body: plain text with bindings, conditionals and formatters. The compiler
10
+ * reads it from source; executed, it is a fragment of its children so a template file that also
11
+ * declares an email body still evaluates.
12
+ */
13
+ declare const Sms: (props: SmsProps) => EmailNode;
14
+ //#endregion
15
+ export { Sms, type SmsCategory, SmsProps };
16
+ //# sourceMappingURL=sms.d.ts.map
package/dist/sms.js ADDED
@@ -0,0 +1,12 @@
1
+ import { a as jsx, n as Fragment } from "./jsx-runtime-CBlexoeR.js";
2
+ //#region src/sms.ts
3
+ /**
4
+ * The root of an SMS body: plain text with bindings, conditionals and formatters. The compiler
5
+ * reads it from source; executed, it is a fragment of its children so a template file that also
6
+ * declares an email body still evaluates.
7
+ */
8
+ const Sms = (props) => jsx(Fragment, { children: props.children });
9
+ //#endregion
10
+ export { Sms };
11
+
12
+ //# sourceMappingURL=sms.js.map
@@ -0,0 +1,23 @@
1
+ //#region src/source-locations.d.ts
2
+ /**
3
+ * The source payload a JSX transform may attach to an element. The transform may omit any field
4
+ * for synthetic calls; only a complete payload can identify a source origin safely.
5
+ */
6
+ interface JsxSource {
7
+ readonly fileName?: string | undefined;
8
+ readonly lineNumber?: number | undefined;
9
+ readonly columnNumber?: number | undefined;
10
+ }
11
+ /** A complete, normalized source origin for a JSX element. */
12
+ interface JsxSourceLocation {
13
+ readonly fileName: string;
14
+ readonly lineNumber: number;
15
+ readonly columnNumber: number;
16
+ }
17
+ /** The JSX prop that carries a {@link JsxSource} to the email JSX runtime. */
18
+ declare const JSX_SOURCE_LOCATION_PROP: "__samva_source_location";
19
+ /** Normalize the optional payload a JSX transform attaches. */
20
+ declare const completeJsxSourceLocation: (source: JsxSource | null | undefined) => JsxSourceLocation | undefined;
21
+ //#endregion
22
+ export { completeJsxSourceLocation as i, JsxSource as n, JsxSourceLocation as r, JSX_SOURCE_LOCATION_PROP as t };
23
+ //# sourceMappingURL=source-locations-C8wCsiAy.d.ts.map
@@ -0,0 +1,65 @@
1
+ import { r as EmailNode } from "./jsx-runtime-ylIOnaSf.js";
2
+ import { r as InputSchema } from "./input-schema-7dPFVvNE.js";
3
+ import { StandardJSONSchemaV1 } from "@standard-schema/spec";
4
+ //#region src/template.d.ts
5
+ /** One actual-input render owns all of a message's authored content. */
6
+ interface EmailContent {
7
+ readonly subject: string;
8
+ readonly preheader?: string;
9
+ readonly body: EmailNode;
10
+ readonly text?: string;
11
+ }
12
+ /**
13
+ * The one naming contract for a template id and a fixture key: a letter, a digit or `_` first,
14
+ * then those plus `.`, `_` and `-`.
15
+ *
16
+ * Both names are written into file paths — a local export writes one page at
17
+ * `templates/<id>/<fixture>.html` — so each has to be a single plain path segment. The rule lives
18
+ * at the declaration, so a project that could not be exported is refused where the name is
19
+ * written rather than at the end of a build. Consumers that resolve a path from these names
20
+ * import this pattern; they do not restate it.
21
+ */
22
+ declare const TEMPLATE_NAME_PATTERN: RegExp;
23
+ /** Caller input for generated references and separate authoring consumers. */
24
+ type TemplateInput<T extends {
25
+ readonly schema: unknown;
26
+ }> = T["schema"] extends InputSchema<infer Input> ? Input : never;
27
+ /**
28
+ * The one naming contract for a template `id`: lowercase kebab-case, the same rule as the CLI and
29
+ * API slug, so the id a definition declares is the handle a caller sends by.
30
+ */
31
+ declare const TEMPLATE_ID_PATTERN: RegExp;
32
+ /** The email channel of a template: an envelope and a body, each a function of the input. */
33
+ interface EmailChannel<Input> {
34
+ readonly subject: (input: Input) => string;
35
+ readonly preheader?: ((input: Input) => string | undefined) | undefined;
36
+ readonly body: (input: Input) => EmailNode;
37
+ }
38
+ /** A template as `defineTemplate` returns it: its identity, input contract and each channel it declares. */
39
+ interface SmlTemplate<Input> {
40
+ readonly id: string;
41
+ readonly schema: InputSchema<Input>;
42
+ readonly fixtures: Readonly<Record<string, Input>>;
43
+ readonly locale?: string | undefined;
44
+ readonly email?: EmailChannel<Input> | undefined;
45
+ readonly sms?: ((input: Input) => EmailNode) | undefined;
46
+ readonly whatsapp?: ((input: Input) => EmailNode) | undefined;
47
+ }
48
+ /**
49
+ * Define a template: one id, one input schema, named fixtures and one body per channel. Every
50
+ * function in it receives the validated input and returns JSX or a string; a compiler reads them
51
+ * without running them, so nothing here executes at send time. Types are inferred from the
52
+ * Standard JSON Schema input.
53
+ */
54
+ declare const defineTemplate: <S extends StandardJSONSchemaV1>(definition: {
55
+ readonly id: string;
56
+ readonly schema: S;
57
+ readonly fixtures: Readonly<Record<string, NoInfer<StandardJSONSchemaV1.InferInput<S>>>>;
58
+ readonly locale?: string | undefined;
59
+ readonly email?: EmailChannel<NoInfer<StandardJSONSchemaV1.InferInput<S>>> | undefined;
60
+ readonly sms?: ((input: NoInfer<StandardJSONSchemaV1.InferInput<S>>) => EmailNode) | undefined;
61
+ readonly whatsapp?: ((input: NoInfer<StandardJSONSchemaV1.InferInput<S>>) => EmailNode) | undefined;
62
+ }) => SmlTemplate<StandardJSONSchemaV1.InferInput<S>>;
63
+ //#endregion
64
+ export { TEMPLATE_NAME_PATTERN as a, TEMPLATE_ID_PATTERN as i, EmailContent as n, TemplateInput as o, SmlTemplate as r, defineTemplate as s, EmailChannel as t };
65
+ //# sourceMappingURL=template-DMPwxMSq.d.ts.map
@@ -0,0 +1,42 @@
1
+ import { n as inputSchema } from "./input-schema-zjkgrXn2.js";
2
+ //#region src/template.ts
3
+ /**
4
+ * The one naming contract for a template id and a fixture key: a letter, a digit or `_` first,
5
+ * then those plus `.`, `_` and `-`.
6
+ *
7
+ * Both names are written into file paths — a local export writes one page at
8
+ * `templates/<id>/<fixture>.html` — so each has to be a single plain path segment. The rule lives
9
+ * at the declaration, so a project that could not be exported is refused where the name is
10
+ * written rather than at the end of a build. Consumers that resolve a path from these names
11
+ * import this pattern; they do not restate it.
12
+ */
13
+ const TEMPLATE_NAME_PATTERN = /^[A-Za-z0-9_][A-Za-z0-9._-]*$/;
14
+ const checkTemplateName = (kind, value) => {
15
+ if (TEMPLATE_NAME_PATTERN.test(value)) return;
16
+ throw new TypeError(`${kind} ${JSON.stringify(value)} is not one path segment. A template id and a fixture key are written into file paths, so each must start with a letter, a digit or "_" and continue with letters, digits, ".", "_" or "-".`);
17
+ };
18
+ /**
19
+ * The one naming contract for a template `id`: lowercase kebab-case, the same rule as the CLI and
20
+ * API slug, so the id a definition declares is the handle a caller sends by.
21
+ */
22
+ const TEMPLATE_ID_PATTERN = /^(?=.{1,100}$)[a-z0-9]+(?:-[a-z0-9]+)*$/;
23
+ /**
24
+ * Define a template: one id, one input schema, named fixtures and one body per channel. Every
25
+ * function in it receives the validated input and returns JSX or a string; a compiler reads them
26
+ * without running them, so nothing here executes at send time. Types are inferred from the
27
+ * Standard JSON Schema input.
28
+ */
29
+ const defineTemplate = (definition) => {
30
+ if (!TEMPLATE_ID_PATTERN.test(definition.id)) throw new TypeError(`Template id ${JSON.stringify(definition.id)} is not lowercase kebab-case. The id is the handle a send names, so write lowercase letters and digits joined by single hyphens, for example "order-shipped".`);
31
+ const fixtureNames = Object.keys(definition.fixtures);
32
+ if (fixtureNames.length === 0) throw new TypeError(`Template ${definition.id} declares no fixtures. Fixtures are the preview, the agent's render targets and the publish check; declare at least one.`);
33
+ for (const fixture of fixtureNames) checkTemplateName("Fixture key", fixture);
34
+ return {
35
+ ...definition,
36
+ schema: inputSchema(definition.schema)
37
+ };
38
+ };
39
+ //#endregion
40
+ export { TEMPLATE_NAME_PATTERN as n, defineTemplate as r, TEMPLATE_ID_PATTERN as t };
41
+
42
+ //# sourceMappingURL=template-zLUjcwfF.js.map
@@ -1,5 +1,5 @@
1
- import { Result } from "better-result";
2
1
  import { generate, parse, walk } from "css-tree";
2
+ import { Result } from "better-result";
3
3
  //#region src/email/css-color.ts
4
4
  const clamp = (value, low = 0, high = 1) => value < low ? low : value > high ? high : value;
5
5
  const toGamma = (channel) => channel <= .0031308 ? 12.92 * channel : 1.055 * channel ** (1 / 2.4) - .055;
@@ -584,4 +584,4 @@ const brandTailwindCss = (brand) => printBrandCss({
584
584
  //#endregion
585
585
  export { brandThemeVariables as a, parseBrandCss as c, formatColor as d, parseColor as f, brandTailwindCss as i, printBrandCss as l, BRAND_FOREGROUND_VARIABLE as n, contrastForeground as o, brandForegroundDefaults as r, darkVariableName as s, BRAND_COLOR_VARIABLE as t, downlevelColors as u };
586
586
 
587
- //# sourceMappingURL=theme-css-hFqcPSar.js.map
587
+ //# sourceMappingURL=theme-css-JtRCm1fb.js.map
@@ -0,0 +1,57 @@
1
+ import { r as EmailNode, t as EmailChild } from "./jsx-runtime-ylIOnaSf.js";
2
+ import { n as WhatsAppCategory, r as WhatsAppHeaderType } from "./channel-specs-C2feJwuP.js";
3
+ //#region src/whatsapp.d.ts
4
+ interface WhatsAppProps {
5
+ readonly name?: string | undefined;
6
+ /** The Meta language code, for example `en_US`. */
7
+ readonly language: string;
8
+ readonly category: WhatsAppCategory;
9
+ readonly children?: EmailChild;
10
+ }
11
+ interface WhatsAppHeaderProps {
12
+ /** `text` by default; for `image`, `video` and `document` the child is the media URL. */
13
+ readonly type?: WhatsAppHeaderType | undefined;
14
+ readonly children?: EmailChild;
15
+ }
16
+ interface WhatsAppTextProps {
17
+ readonly children?: EmailChild;
18
+ }
19
+ interface WhatsAppButtonsProps {
20
+ readonly children?: EmailChild;
21
+ }
22
+ interface WhatsAppUrlButtonProps {
23
+ readonly url: string;
24
+ /** The button label. */
25
+ readonly children?: EmailChild;
26
+ }
27
+ interface WhatsAppPhoneButtonProps {
28
+ readonly phone: string;
29
+ /** The button label. */
30
+ readonly children?: EmailChild;
31
+ }
32
+ interface WhatsAppQuickReplyButtonProps {
33
+ /** The button label. */
34
+ readonly children?: EmailChild;
35
+ }
36
+ interface WhatsAppCopyCodeButtonProps {
37
+ /** The code the button copies. */
38
+ readonly children?: EmailChild;
39
+ }
40
+ /**
41
+ * The root of a WhatsApp body. Meta's template anatomy is the vocabulary: `WhatsApp.Header`,
42
+ * `WhatsApp.Body`, `WhatsApp.Footer` and `WhatsApp.Buttons`, whose children are the four button
43
+ * kinds.
44
+ */
45
+ declare const WhatsApp: ((props: WhatsAppProps) => EmailNode) & {
46
+ Header: (props: WhatsAppHeaderProps) => EmailNode;
47
+ Body: (props: WhatsAppTextProps) => EmailNode;
48
+ Footer: (props: WhatsAppTextProps) => EmailNode;
49
+ Buttons: (props: WhatsAppButtonsProps) => EmailNode;
50
+ UrlButton: (props: WhatsAppUrlButtonProps) => EmailNode;
51
+ QuickReplyButton: (props: WhatsAppQuickReplyButtonProps) => EmailNode;
52
+ PhoneButton: (props: WhatsAppPhoneButtonProps) => EmailNode;
53
+ CopyCodeButton: (props: WhatsAppCopyCodeButtonProps) => EmailNode;
54
+ };
55
+ //#endregion
56
+ export { WhatsApp, WhatsAppButtonsProps, type WhatsAppCategory, WhatsAppCopyCodeButtonProps, WhatsAppHeaderProps, type WhatsAppHeaderType, WhatsAppPhoneButtonProps, WhatsAppProps, WhatsAppQuickReplyButtonProps, WhatsAppTextProps, WhatsAppUrlButtonProps };
57
+ //# sourceMappingURL=whatsapp.d.ts.map
@@ -0,0 +1,22 @@
1
+ import { a as jsx, n as Fragment } from "./jsx-runtime-CBlexoeR.js";
2
+ //#region src/whatsapp.ts
3
+ const fragment = (children) => jsx(Fragment, { children });
4
+ /**
5
+ * The root of a WhatsApp body. Meta's template anatomy is the vocabulary: `WhatsApp.Header`,
6
+ * `WhatsApp.Body`, `WhatsApp.Footer` and `WhatsApp.Buttons`, whose children are the four button
7
+ * kinds.
8
+ */
9
+ const WhatsApp = Object.assign((props) => fragment(props.children), {
10
+ Header: (props) => fragment(props.children),
11
+ Body: (props) => fragment(props.children),
12
+ Footer: (props) => fragment(props.children),
13
+ Buttons: (props) => fragment(props.children),
14
+ UrlButton: (props) => fragment(props.children),
15
+ QuickReplyButton: (props) => fragment(props.children),
16
+ PhoneButton: (props) => fragment(props.children),
17
+ CopyCodeButton: (props) => fragment(props.children)
18
+ });
19
+ //#endregion
20
+ export { WhatsApp };
21
+
22
+ //# sourceMappingURL=whatsapp.js.map