@samva/markup 0.15.1 → 0.17.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 (51) hide show
  1. package/AGENTS.md +42 -35
  2. package/CHANGELOG.md +92 -0
  3. package/README.md +10 -9
  4. package/dist/{assets-tISHaQNF.d.ts → assets-CS5Xa_mr.d.ts} +3 -3
  5. package/dist/{brand-nreeKWxF.js → brand-CIiEqkU7.js} +24 -31
  6. package/dist/{brand-plugin-CHhcei-j.d.ts → brand-plugin-Dj9SMpfS.d.ts} +3 -1
  7. package/dist/brand.d.ts +2 -2
  8. package/dist/brand.js +3 -3
  9. package/dist/compatibility.d.ts +76 -0
  10. package/dist/compatibility.js +807 -0
  11. package/dist/compiled-template-Bc4Dq9zy.d.ts +268 -0
  12. package/dist/compiler.d.ts +58 -225
  13. package/dist/compiler.js +261 -1297
  14. package/dist/{components-3XHjYD3i.js → components-C5850-Qg.js} +37 -29
  15. package/dist/css-B_aVKrDo.js +436 -0
  16. package/dist/css-color-DLM12Osu.js +315 -0
  17. package/dist/{diagnostic-codes-UXwOO3A-.js → diagnostic-codes-DZKb0Xcg.js} +4 -0
  18. package/dist/{diagnostics-CUYlQ_6x.d.ts → diagnostics-D4vSLQrO.d.ts} +1 -10
  19. package/dist/diagnostics.d.ts +6 -2
  20. package/dist/diagnostics.js +3 -3
  21. package/dist/edit.d.ts +10 -9
  22. package/dist/edit.js +12 -11
  23. package/dist/email/jsx-dev-runtime.d.ts +1 -1
  24. package/dist/email/jsx-dev-runtime.js +1 -1
  25. package/dist/email/jsx-runtime.d.ts +2 -2
  26. package/dist/email/jsx-runtime.js +2 -2
  27. package/dist/email.d.ts +1 -1
  28. package/dist/email.js +1 -1
  29. package/dist/html-DJUK2YJF.js +483 -0
  30. package/dist/index.d.ts +1 -1
  31. package/dist/{jsx-runtime-DC7xG0aA.d.ts → jsx-runtime-DL8NVF1f.d.ts} +12 -6
  32. package/dist/{jsx-runtime-CBlexoeR.js → jsx-runtime-qL19u3Fy.js} +17 -10
  33. package/dist/preview-rNoJBEIY.d.ts +104 -0
  34. package/dist/{profile-AatO_SvP.js → profile-JTvgCD6X.js} +614 -24
  35. package/dist/{html-BvRFepeO.js → render-template-DwPDm3Hq.js} +155 -572
  36. package/dist/render.d.ts +40 -28
  37. package/dist/render.js +3 -47
  38. package/dist/selectors-CYWCoxZr.js +157 -0
  39. package/dist/sms.d.ts +1 -1
  40. package/dist/sms.js +1 -1
  41. package/dist/{template-B-UDXK8a.d.ts → template-DmNcoH4Q.d.ts} +2 -9
  42. package/dist/{theme-css-s9QwD5Ko.js → theme-css-P9F5S7Ic.js} +3 -316
  43. package/dist/whatsapp.d.ts +1 -1
  44. package/dist/whatsapp.js +1 -1
  45. package/generated/contract.json +7 -2
  46. package/generated/reference.md +3 -2
  47. package/package.json +5 -1
  48. package/skills/sml/SKILL.md +2 -2
  49. package/dist/ir-DNL6H7jA.js +0 -705
  50. package/dist/render-BdvewoQt.d.ts +0 -564
  51. package/dist/render-DpYouYYG.js +0 -258
@@ -0,0 +1,315 @@
1
+ //#region src/email/css-color.ts
2
+ const clamp = (value, low = 0, high = 1) => value < low ? low : value > high ? high : value;
3
+ const toGamma = (channel) => channel <= .0031308 ? 12.92 * channel : 1.055 * channel ** (1 / 2.4) - .055;
4
+ const toLinear = (channel) => channel <= .04045 ? channel / 12.92 : ((channel + .055) / 1.055) ** 2.4;
5
+ /** OKLab is the interpolation space Tailwind mixes in, so conversions run both ways. */
6
+ const oklabToRgb = (lightness, a, b, alpha) => {
7
+ const l = (lightness + .3963377774 * a + .2158037573 * b) ** 3;
8
+ const m = (lightness - .1055613458 * a - .0638541728 * b) ** 3;
9
+ const s = (lightness - .0894841775 * a - 1.291485548 * b) ** 3;
10
+ return {
11
+ r: toGamma(4.0767416621 * l - 3.3077115913 * m + .2309699292 * s),
12
+ g: toGamma(-1.2684380046 * l + 2.6097574011 * m - .3413193965 * s),
13
+ b: toGamma(-.0041960863 * l - .7034186147 * m + 1.707614701 * s),
14
+ a: alpha
15
+ };
16
+ };
17
+ const rgbToOklab = (color) => {
18
+ const r = toLinear(color.r);
19
+ const g = toLinear(color.g);
20
+ const b = toLinear(color.b);
21
+ const l = Math.cbrt(.4122214708 * r + .5363325363 * g + .0514459929 * b);
22
+ const m = Math.cbrt(.2119034982 * r + .6806995451 * g + .1073969566 * b);
23
+ const s = Math.cbrt(.0883024619 * r + .2817188376 * g + .6299787005 * b);
24
+ return {
25
+ L: .2104542553 * l + .793617785 * m - .0040720468 * s,
26
+ a: 1.9779984951 * l - 2.428592205 * m + .4505937099 * s,
27
+ b: .0259040371 * l + .7827717662 * m - .808675766 * s,
28
+ alpha: color.a
29
+ };
30
+ };
31
+ const hslToRgb = (hue, saturation, lightness, alpha) => {
32
+ const h = (hue % 360 + 360) % 360;
33
+ const c = (1 - Math.abs(2 * lightness - 1)) * saturation;
34
+ const x = c * (1 - Math.abs(h / 60 % 2 - 1));
35
+ const m = lightness - c / 2;
36
+ const [r, g, b] = [
37
+ [
38
+ c,
39
+ x,
40
+ 0
41
+ ],
42
+ [
43
+ x,
44
+ c,
45
+ 0
46
+ ],
47
+ [
48
+ 0,
49
+ c,
50
+ x
51
+ ],
52
+ [
53
+ 0,
54
+ x,
55
+ c
56
+ ],
57
+ [
58
+ x,
59
+ 0,
60
+ c
61
+ ],
62
+ [
63
+ c,
64
+ 0,
65
+ x
66
+ ]
67
+ ][Math.min(5, Math.floor(h / 60))];
68
+ return {
69
+ r: r + m,
70
+ g: g + m,
71
+ b: b + m,
72
+ a: alpha
73
+ };
74
+ };
75
+ /** The named colors an email template actually reaches for; anything else stays literal. */
76
+ const NAMED = {
77
+ transparent: "#00000000",
78
+ black: "#000000",
79
+ white: "#ffffff",
80
+ red: "#ff0000",
81
+ green: "#008000",
82
+ blue: "#0000ff",
83
+ gray: "#808080",
84
+ grey: "#808080",
85
+ silver: "#c0c0c0",
86
+ yellow: "#ffff00",
87
+ orange: "#ffa500",
88
+ purple: "#800080",
89
+ navy: "#000080",
90
+ teal: "#008080",
91
+ olive: "#808000",
92
+ maroon: "#800000",
93
+ lime: "#00ff00",
94
+ aqua: "#00ffff",
95
+ cyan: "#00ffff",
96
+ fuchsia: "#ff00ff",
97
+ magenta: "#ff00ff"
98
+ };
99
+ const number = (token, reference = 1) => {
100
+ const text = token.trim();
101
+ if (text === "none") return 0;
102
+ if (text.endsWith("%")) {
103
+ const value = Number.parseFloat(text.slice(0, -1));
104
+ return Number.isFinite(value) ? value / 100 * reference : void 0;
105
+ }
106
+ const value = Number.parseFloat(text);
107
+ return Number.isFinite(value) ? value : void 0;
108
+ };
109
+ const angle = (token) => {
110
+ const text = token.trim();
111
+ const value = Number.parseFloat(text);
112
+ if (!Number.isFinite(value)) return void 0;
113
+ if (text.endsWith("turn")) return value * 360;
114
+ if (text.endsWith("rad")) return value * 180 / Math.PI;
115
+ if (text.endsWith("grad")) return value * .9;
116
+ return value;
117
+ };
118
+ /** Split a function's arguments on top-level commas and `/`, keeping nested calls intact. */
119
+ const argumentTokens = (body) => {
120
+ const parts = [];
121
+ let alpha;
122
+ let depth = 0;
123
+ let current = "";
124
+ let afterSlash = false;
125
+ for (const character of body) {
126
+ if (character === "(") depth += 1;
127
+ if (character === ")") depth -= 1;
128
+ if (depth === 0 && (character === "," || character === " " || character === "/")) {
129
+ if (character === "/") {
130
+ if (current.trim() !== "") parts.push(current.trim());
131
+ current = "";
132
+ afterSlash = true;
133
+ continue;
134
+ }
135
+ if (current.trim() !== "") {
136
+ if (afterSlash) alpha = current.trim();
137
+ else parts.push(current.trim());
138
+ }
139
+ current = "";
140
+ continue;
141
+ }
142
+ current += character;
143
+ }
144
+ if (current.trim() !== "") {
145
+ if (afterSlash) alpha = current.trim();
146
+ else parts.push(current.trim());
147
+ }
148
+ return alpha === void 0 ? { parts } : {
149
+ parts,
150
+ alpha
151
+ };
152
+ };
153
+ /** Read one function call at the start of `value`, returning its name and body. */
154
+ const functionCall = (value) => {
155
+ const match = /^([a-zA-Z-]+)\(/.exec(value.trim());
156
+ if (match === null) return void 0;
157
+ const text = value.trim();
158
+ let depth = 0;
159
+ for (let index = match[0].length - 1; index < text.length; index++) if (text[index] === "(") depth += 1;
160
+ else if (text[index] === ")") {
161
+ depth -= 1;
162
+ if (depth === 0) return {
163
+ name: match[1].toLowerCase(),
164
+ body: text.slice(match[0].length, index)
165
+ };
166
+ }
167
+ };
168
+ /** Parse any supported color notation into extended sRGB. `undefined` means "leave it alone". */
169
+ const parseColor = (value) => {
170
+ const text = value.trim();
171
+ const named = NAMED[text.toLowerCase()];
172
+ if (named !== void 0) return parseColor(named);
173
+ if (text.startsWith("#")) {
174
+ const hex = text.slice(1);
175
+ const expand = (part) => Number.parseInt(part.repeat(2 / part.length), 16) / 255;
176
+ if (hex.length === 3 || hex.length === 4) return {
177
+ r: expand(hex[0]),
178
+ g: expand(hex[1]),
179
+ b: expand(hex[2]),
180
+ a: hex.length === 4 ? expand(hex[3]) : 1
181
+ };
182
+ if (hex.length === 6 || hex.length === 8) return {
183
+ r: Number.parseInt(hex.slice(0, 2), 16) / 255,
184
+ g: Number.parseInt(hex.slice(2, 4), 16) / 255,
185
+ b: Number.parseInt(hex.slice(4, 6), 16) / 255,
186
+ a: hex.length === 8 ? Number.parseInt(hex.slice(6, 8), 16) / 255 : 1
187
+ };
188
+ return;
189
+ }
190
+ const call = functionCall(text);
191
+ if (call === void 0) return void 0;
192
+ const { parts, alpha } = argumentTokens(call.body);
193
+ const opacity = alpha === void 0 ? 1 : number(alpha) ?? 1;
194
+ switch (call.name) {
195
+ case "rgb":
196
+ case "rgba": {
197
+ const [r, g, b, legacy] = parts;
198
+ if (r === void 0 || g === void 0 || b === void 0) return void 0;
199
+ const channel = (token) => {
200
+ const parsed = number(token, 255);
201
+ return parsed === void 0 ? void 0 : parsed / 255;
202
+ };
203
+ const [red, green, blue] = [
204
+ channel(r),
205
+ channel(g),
206
+ channel(b)
207
+ ];
208
+ if (red === void 0 || green === void 0 || blue === void 0) return void 0;
209
+ return {
210
+ r: red,
211
+ g: green,
212
+ b: blue,
213
+ a: legacy === void 0 ? opacity : number(legacy) ?? 1
214
+ };
215
+ }
216
+ case "hsl":
217
+ case "hsla": {
218
+ const [h, s, l, legacy] = parts;
219
+ if (h === void 0 || s === void 0 || l === void 0) return void 0;
220
+ const hue = angle(h);
221
+ const saturation = number(s);
222
+ const lightness = number(l);
223
+ if (hue === void 0 || saturation === void 0 || lightness === void 0) return void 0;
224
+ return hslToRgb(hue, saturation, lightness, legacy === void 0 ? opacity : number(legacy) ?? 1);
225
+ }
226
+ case "oklch": {
227
+ const [l, c, h] = parts;
228
+ if (l === void 0 || c === void 0 || h === void 0) return void 0;
229
+ const lightness = number(l);
230
+ const chroma = number(c, .4);
231
+ const hue = angle(h);
232
+ if (lightness === void 0 || chroma === void 0 || hue === void 0) return void 0;
233
+ const radians = hue * Math.PI / 180;
234
+ return oklabToRgb(lightness, chroma * Math.cos(radians), chroma * Math.sin(radians), opacity);
235
+ }
236
+ case "oklab": {
237
+ const [l, a, b] = parts;
238
+ if (l === void 0 || a === void 0 || b === void 0) return void 0;
239
+ const lightness = number(l);
240
+ const green = number(a, .4);
241
+ const blue = number(b, .4);
242
+ if (lightness === void 0 || green === void 0 || blue === void 0) return void 0;
243
+ return oklabToRgb(lightness, green, blue, opacity);
244
+ }
245
+ case "color-mix": return mixColors(call.body);
246
+ default: return;
247
+ }
248
+ };
249
+ /** `color-mix(in <space>, <color> <pct>?, <color> <pct>?)` — Tailwind's opacity modifier. */
250
+ const mixColors = (body) => {
251
+ const stops = body.split(",").map((part) => part.trim());
252
+ const [space, first, second] = stops;
253
+ if (space === void 0 || first === void 0 || second === void 0 || stops.length !== 3) return void 0;
254
+ const method = /^in\s+([a-z-]+)/i.exec(space)?.[1]?.toLowerCase();
255
+ if (method === void 0) return void 0;
256
+ const stop = (text) => {
257
+ const percentage = /\s([\d.]+)%$/.exec(text);
258
+ const color = parseColor(percentage === null ? text : text.slice(0, percentage.index));
259
+ if (color === void 0) return void 0;
260
+ return {
261
+ color,
262
+ weight: percentage === null ? void 0 : Number.parseFloat(percentage[1]) / 100
263
+ };
264
+ };
265
+ const left = stop(first);
266
+ const right = stop(second);
267
+ if (left === void 0 || right === void 0) return void 0;
268
+ const leftWeight = left.weight ?? (right.weight === void 0 ? .5 : 1 - right.weight);
269
+ const total = leftWeight + (right.weight ?? 1 - leftWeight);
270
+ if (total === 0) return void 0;
271
+ const p = leftWeight / total;
272
+ const alpha = left.color.a * p + right.color.a * (1 - p);
273
+ const mix = (l, r) => alpha === 0 ? 0 : (l * left.color.a * p + r * right.color.a * (1 - p)) / alpha;
274
+ if (method === "srgb") return {
275
+ r: mix(left.color.r, right.color.r),
276
+ g: mix(left.color.g, right.color.g),
277
+ b: mix(left.color.b, right.color.b),
278
+ a: alpha
279
+ };
280
+ const l = rgbToOklab(left.color);
281
+ const r = rgbToOklab(right.color);
282
+ const channel = (a, b) => alpha === 0 ? 0 : (a * left.color.a * p + b * right.color.a * (1 - p)) / alpha;
283
+ return oklabToRgb(channel(l.L, r.L), channel(l.a, r.a), channel(l.b, r.b), alpha);
284
+ };
285
+ const byte = (channel) => Math.round(clamp(channel) * 255).toString(16).padStart(2, "0");
286
+ /** sRGB hex, or `rgba()` when the color is not opaque. */
287
+ const formatColor = (color) => color.a >= 1 ? `#${byte(color.r)}${byte(color.g)}${byte(color.b)}` : `rgba(${Math.round(clamp(color.r) * 255)},${Math.round(clamp(color.g) * 255)},${Math.round(clamp(color.b) * 255)},${Math.round(clamp(color.a) * 1e3) / 1e3})`;
288
+ const MODERN_COLOR = /\b(oklch|oklab|color-mix|lab|lch)\(/i;
289
+ /** Rewrite every modern color function in a declaration value; other text is untouched. */
290
+ const downlevelColors = (value) => {
291
+ if (!MODERN_COLOR.test(value)) return value;
292
+ let result = "";
293
+ let rest = value;
294
+ while (rest.length > 0) {
295
+ const match = MODERN_COLOR.exec(rest);
296
+ if (match === null || match.index === void 0) {
297
+ result += rest;
298
+ break;
299
+ }
300
+ result += rest.slice(0, match.index);
301
+ const remainder = rest.slice(match.index);
302
+ const call = functionCall(remainder);
303
+ if (call === void 0) {
304
+ result += remainder;
305
+ break;
306
+ }
307
+ const consumed = remainder.indexOf("(") + call.body.length + 2;
308
+ const color = parseColor(remainder.slice(0, consumed));
309
+ result += color === void 0 ? remainder.slice(0, consumed) : formatColor(color);
310
+ rest = remainder.slice(consumed);
311
+ }
312
+ return result;
313
+ };
314
+ //#endregion
315
+ export { parseColor as n, downlevelColors as t };
@@ -376,6 +376,10 @@ const DIAGNOSTIC_CODES = codes({
376
376
  summary: "@font-face names a file the project does not hold.",
377
377
  fix: "Add the file; paths resolve from the stylesheet's directory."
378
378
  },
379
+ "email-external-asset": {
380
+ summary: "An image points at another site's URL; a hotlinked image can disappear, be blocked, track recipients or slow the message.",
381
+ fix: "Add the image to the project's files and import it (import logo from './logo.png'), then use the import as the src."
382
+ },
379
383
  "invalid-asset-base": {
380
384
  summary: "The asset base is not an https URL or a path.",
381
385
  fix: "Use an https URL, an absolute path, or a relative path."
@@ -34,18 +34,9 @@ interface TemplateDiagnostic extends EmailDiagnostic {
34
34
  /** Agent instructions for migrating a template made incompatible by a compiler change. */
35
35
  readonly upgrade?: string | undefined;
36
36
  }
37
- declare const EmailCompileError_base: import("better-result").TaggedErrorClass<"EmailCompileError">;
38
- declare class EmailCompileError extends EmailCompileError_base<{
39
- readonly diagnostics: ReadonlyArray<EmailDiagnostic>;
40
- readonly message: string;
41
- }> {
42
- constructor(args: {
43
- readonly diagnostics: ReadonlyArray<EmailDiagnostic>;
44
- });
45
- }
46
37
  /** `emails/welcome.tsx:12:3 unsupported-element: …` — the shape agents iterate on. */
47
38
  declare const formatEmailDiagnostic: (diagnostic: TemplateDiagnostic) => string;
48
39
  /** True when a set of findings must stop the compile or refuse a publication. */
49
40
  declare const hasBlockingDiagnostic: (diagnostics: readonly EmailDiagnostic[]) => boolean;
50
41
  //#endregion
51
- export { TemplateDiagnostic as a, EmailDiagnosticSeverity as i, EmailCompileError as n, formatEmailDiagnostic as o, EmailDiagnostic as r, hasBlockingDiagnostic as s, EmailCompatibilityAssessment as t };
42
+ export { formatEmailDiagnostic as a, TemplateDiagnostic as i, EmailDiagnostic as n, hasBlockingDiagnostic as o, EmailDiagnosticSeverity as r, EmailCompatibilityAssessment as t };
@@ -1,4 +1,4 @@
1
- import { a as TemplateDiagnostic, i as EmailDiagnosticSeverity, n as EmailCompileError, o as formatEmailDiagnostic, r as EmailDiagnostic, s as hasBlockingDiagnostic, t as EmailCompatibilityAssessment } from "./diagnostics-CUYlQ_6x.js";
1
+ import { a as formatEmailDiagnostic, i as TemplateDiagnostic, n as EmailDiagnostic, o as hasBlockingDiagnostic, r as EmailDiagnosticSeverity, t as EmailCompatibilityAssessment } from "./diagnostics-D4vSLQrO.js";
2
2
  import { a as createDiagnosticFormatter, i as buildLineMap, n as DiagnosticRepair, o as formatDiagnostic, r as Span, s as lineColumn, t as Diagnostic } from "./diagnostic-model-DxthUZBT.js";
3
3
  //#region src/diagnostic-codes.d.ts
4
4
  interface DiagnosticCodeSpec {
@@ -340,6 +340,10 @@ declare const DIAGNOSTIC_CODES: {
340
340
  readonly summary: "@font-face names a file the project does not hold.";
341
341
  readonly fix: "Add the file; paths resolve from the stylesheet's directory.";
342
342
  };
343
+ readonly "email-external-asset": {
344
+ readonly summary: "An image points at another site's URL; a hotlinked image can disappear, be blocked, track recipients or slow the message.";
345
+ readonly fix: "Add the image to the project's files and import it (import logo from './logo.png'), then use the import as the src.";
346
+ };
343
347
  readonly "invalid-asset-base": {
344
348
  readonly summary: "The asset base is not an https URL or a path.";
345
349
  readonly fix: "Use an https URL, an absolute path, or a relative path.";
@@ -429,4 +433,4 @@ declare const DIAGNOSTIC_CODE_FAMILIES: {
429
433
  };
430
434
  };
431
435
  //#endregion
432
- export { DIAGNOSTIC_CODES, DIAGNOSTIC_CODE_FAMILIES, Diagnostic, DiagnosticCode, DiagnosticCodeSpec, DiagnosticRepair, EmailCompatibilityAssessment, EmailCompileError, EmailDiagnostic, EmailDiagnosticSeverity, Span, TemplateDiagnostic, buildLineMap, createDiagnosticFormatter, formatDiagnostic, formatEmailDiagnostic, hasBlockingDiagnostic, hasUpgradeRecipe, lineColumn };
436
+ export { DIAGNOSTIC_CODES, DIAGNOSTIC_CODE_FAMILIES, Diagnostic, DiagnosticCode, DiagnosticCodeSpec, DiagnosticRepair, type EmailCompatibilityAssessment, type EmailDiagnostic, type EmailDiagnosticSeverity, Span, type TemplateDiagnostic, buildLineMap, createDiagnosticFormatter, formatDiagnostic, formatEmailDiagnostic, hasBlockingDiagnostic, hasUpgradeRecipe, lineColumn };
@@ -1,3 +1,3 @@
1
- import { a as createDiagnosticFormatter, i as buildLineMap, n as DIAGNOSTIC_CODE_FAMILIES, o as formatDiagnostic, r as hasUpgradeRecipe, s as lineColumn, t as DIAGNOSTIC_CODES } from "./diagnostic-codes-UXwOO3A-.js";
2
- import { n as formatEmailDiagnostic, r as hasBlockingDiagnostic, t as EmailCompileError } from "./diagnostics-C0Tr8-eQ.js";
3
- export { DIAGNOSTIC_CODES, DIAGNOSTIC_CODE_FAMILIES, EmailCompileError, buildLineMap, createDiagnosticFormatter, formatDiagnostic, formatEmailDiagnostic, hasBlockingDiagnostic, hasUpgradeRecipe, lineColumn };
1
+ import { n as formatEmailDiagnostic, r as hasBlockingDiagnostic } from "./diagnostics-C0Tr8-eQ.js";
2
+ import { a as createDiagnosticFormatter, i as buildLineMap, n as DIAGNOSTIC_CODE_FAMILIES, o as formatDiagnostic, r as hasUpgradeRecipe, s as lineColumn, t as DIAGNOSTIC_CODES } from "./diagnostic-codes-DZKb0Xcg.js";
3
+ export { DIAGNOSTIC_CODES, DIAGNOSTIC_CODE_FAMILIES, buildLineMap, createDiagnosticFormatter, formatDiagnostic, formatEmailDiagnostic, hasBlockingDiagnostic, hasUpgradeRecipe, lineColumn };
package/dist/edit.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { i as completeJsxSourceLocation, n as JsxSource, r as JsxSourceLocation, t as JSX_SOURCE_LOCATION_PROP } from "./source-locations-C8wCsiAy.js";
2
+ import { a as emailAuthoringTarget, c as emailSelectionIndex, d as previewEmail, i as INSTANCE_PATH_ATTRIBUTE, l as emailSelectionSiblings, n as EmailPreview, o as emailDefinitionInstances, r as EmittedPosition, s as emailSelectionAncestry, t as EmailElementSelection, u as emailSelections } from "./preview-rNoJBEIY.js";
2
3
  import { n as WhatsAppCategory, r as WhatsAppHeaderType, t as SmsCategory } from "./channel-specs-C2feJwuP.js";
3
4
  //#region src/source-edit.d.ts
4
5
  /** One exact source replacement; before text guards against concurrent changes. */
@@ -163,12 +164,12 @@ type WhatsAppButtonRow = {
163
164
  interface WhatsAppChannelForm {
164
165
  readonly language: AttributeState;
165
166
  readonly category: AttributeState;
166
- /** Null when the template has no header. */
167
- readonly header: readonly ChannelSegment[] | null;
167
+ /** Undefined when the template has no header. */
168
+ readonly header: readonly ChannelSegment[] | undefined;
168
169
  readonly headerType: AttributeState;
169
170
  readonly body: readonly ChannelSegment[];
170
- /** Null when the template has no footer. */
171
- readonly footer: readonly ChannelSegment[] | null;
171
+ /** Undefined when the template has no footer. */
172
+ readonly footer: readonly ChannelSegment[] | undefined;
172
173
  readonly buttons: readonly WhatsAppButtonRow[];
173
174
  readonly variables: readonly string[];
174
175
  }
@@ -220,13 +221,13 @@ type WhatsAppEdit = {
220
221
  readonly kind: "buttonRemove";
221
222
  readonly button: number;
222
223
  };
223
- /** The form model of the template's SMS body, or null when it is not a `<Sms>` written in place. */
224
- declare const readSmsChannel: (source: string) => SmsChannelForm | null;
224
+ /** The form model of the template's SMS body, or undefined when it is not a `<Sms>` written in place. */
225
+ declare const readSmsChannel: (source: string) => SmsChannelForm | undefined;
225
226
  /** The source replacements that apply one form change to the SMS body. */
226
227
  declare const editSmsChannel: (source: string, edit: SmsEdit) => ChannelEditResult;
227
- /** The form model of the template's WhatsApp body, or null when it is not a `<WhatsApp>` written in place. */
228
- declare const readWhatsAppChannel: (source: string) => WhatsAppChannelForm | null;
228
+ /** The form model of the template's WhatsApp body, or undefined when it is not a `<WhatsApp>` written in place. */
229
+ declare const readWhatsAppChannel: (source: string) => WhatsAppChannelForm | undefined;
229
230
  /** The source replacements that apply one form change to the WhatsApp body. */
230
231
  declare const editWhatsAppChannel: (source: string, edit: WhatsAppEdit) => ChannelEditResult;
231
232
  //#endregion
232
- export { ApplyOptions, AttributeState, ChannelEditResult, ChannelSegment, ClassNameOperation, JSX_SOURCE_LOCATION_PROP, JsxSource, JsxSourceLocation, LockedSegment, ProfileGuard, type SmsCategory, SmsChannelForm, SmsEdit, SourceEditResult, SourceElement, SourceFixture, SourceProperty, SourceProposal, SourceRange, SourceReplacement, TextSegment, WhatsAppButtonKind, WhatsAppButtonRow, type WhatsAppCategory, WhatsAppChannelForm, WhatsAppEdit, type WhatsAppHeaderType, WhatsAppPart, applySourceReplacements, classNameEdit, completeJsxSourceLocation, editSmsChannel, editWhatsAppChannel, expressionReplacement, inspectSourceElement, inspectSourceFixtures, literalReplacement, readSmsChannel, readWhatsAppChannel, structuralReplacements };
233
+ export { ApplyOptions, AttributeState, ChannelEditResult, ChannelSegment, ClassNameOperation, type EmailElementSelection, type EmailPreview, type EmittedPosition, INSTANCE_PATH_ATTRIBUTE, JSX_SOURCE_LOCATION_PROP, JsxSource, JsxSourceLocation, LockedSegment, ProfileGuard, type SmsCategory, SmsChannelForm, SmsEdit, SourceEditResult, SourceElement, SourceFixture, SourceProperty, SourceProposal, SourceRange, SourceReplacement, TextSegment, WhatsAppButtonKind, WhatsAppButtonRow, type WhatsAppCategory, WhatsAppChannelForm, WhatsAppEdit, type WhatsAppHeaderType, WhatsAppPart, applySourceReplacements, classNameEdit, completeJsxSourceLocation, editSmsChannel, editWhatsAppChannel, emailAuthoringTarget, emailDefinitionInstances, emailSelectionAncestry, emailSelectionIndex, emailSelectionSiblings, emailSelections, expressionReplacement, inspectSourceElement, inspectSourceFixtures, literalReplacement, previewEmail, readSmsChannel, readWhatsAppChannel, structuralReplacements };
package/dist/edit.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { n as isObject } from "./guards-eV1qLbf2.js";
2
- import { d as completeJsxSourceLocation, u as JSX_SOURCE_LOCATION_PROP } from "./jsx-runtime-CBlexoeR.js";
3
- import { i as buildLineMap } from "./diagnostic-codes-UXwOO3A-.js";
4
- import { c as WHATSAPP_HEADER_TYPES, n as introducedProfileErrors, o as SMS_CATEGORIES, s as WHATSAPP_CATEGORIES, t as checkStaticProfile } from "./profile-AatO_SvP.js";
2
+ import { c as INSTANCE_PATH_ATTRIBUTE, d as emailSelectionAncestry, f as emailSelectionIndex, h as previewEmail, l as emailAuthoringTarget, m as emailSelections, p as emailSelectionSiblings, u as emailDefinitionInstances } from "./html-DJUK2YJF.js";
3
+ import { d as completeJsxSourceLocation, u as JSX_SOURCE_LOCATION_PROP } from "./jsx-runtime-qL19u3Fy.js";
4
+ import { i as buildLineMap } from "./diagnostic-codes-DZKb0Xcg.js";
5
+ import { c as SMS_CATEGORIES, l as WHATSAPP_CATEGORIES, n as introducedErrors, t as checkTemplate, u as WHATSAPP_HEADER_TYPES } from "./profile-JTvgCD6X.js";
5
6
  import { parse } from "@babel/parser";
6
7
  //#region src/source-edit.ts
7
8
  const node = (value) => isObject(value) && "type" in value && typeof value.type === "string" && "start" in value && typeof value.start === "number" && "end" in value && typeof value.end === "number";
@@ -146,7 +147,7 @@ const profileRefusal = (source, result, guard) => {
146
147
  ...guard.files,
147
148
  [file]: content
148
149
  });
149
- const introduced = introducedProfileErrors(checkStaticProfile(project(source), guard.entry), checkStaticProfile(project(result), guard.entry));
150
+ const introduced = introducedErrors(checkTemplate(project(source), { entry: guard.entry }), checkTemplate(project(result), { entry: guard.entry }));
150
151
  const first = introduced[0];
151
152
  if (first === void 0) return null;
152
153
  const more = introduced.length > 1 ? ` (and ${introduced.length - 1} more)` : "";
@@ -700,10 +701,10 @@ const smsChannel = (source) => {
700
701
  tree
701
702
  };
702
703
  };
703
- /** The form model of the template's SMS body, or null when it is not a `<Sms>` written in place. */
704
+ /** The form model of the template's SMS body, or undefined when it is not a `<Sms>` written in place. */
704
705
  const readSmsChannel = (source) => {
705
706
  const channel = smsChannel(source);
706
- if (channel === null) return null;
707
+ if (channel === null) return void 0;
707
708
  return {
708
709
  category: attributeState(source, channel.root, "category"),
709
710
  segments: segmentsOf(source, channel.root),
@@ -800,18 +801,18 @@ const buttonRows = (source, channel) => {
800
801
  }
801
802
  return rows;
802
803
  };
803
- /** The form model of the template's WhatsApp body, or null when it is not a `<WhatsApp>` written in place. */
804
+ /** The form model of the template's WhatsApp body, or undefined when it is not a `<WhatsApp>` written in place. */
804
805
  const readWhatsAppChannel = (source) => {
805
806
  const channel = whatsappChannel(source);
806
- if (channel === null || channel.body === null) return null;
807
+ if (channel === null || channel.body === null) return void 0;
807
808
  const { root } = channel;
808
809
  return {
809
810
  language: attributeState(source, root, "language"),
810
811
  category: attributeState(source, root, "category"),
811
- header: channel.header === null ? null : segmentsOf(source, channel.header),
812
+ header: channel.header === null ? void 0 : segmentsOf(source, channel.header),
812
813
  headerType: channel.header === null ? { kind: "absent" } : attributeState(source, channel.header, "type"),
813
814
  body: segmentsOf(source, channel.body),
814
- footer: channel.footer === null ? null : segmentsOf(source, channel.footer),
815
+ footer: channel.footer === null ? void 0 : segmentsOf(source, channel.footer),
815
816
  buttons: buttonRows(source, channel).map(({ row }) => row),
816
817
  variables: variablesOf(source, root, channel.parameter)
817
818
  };
@@ -939,4 +940,4 @@ const editWhatsAppChannel = (source, edit) => {
939
940
  }
940
941
  };
941
942
  //#endregion
942
- export { JSX_SOURCE_LOCATION_PROP, applySourceReplacements, classNameEdit, completeJsxSourceLocation, editSmsChannel, editWhatsAppChannel, expressionReplacement, inspectSourceElement, inspectSourceFixtures, literalReplacement, readSmsChannel, readWhatsAppChannel, structuralReplacements };
943
+ export { INSTANCE_PATH_ATTRIBUTE, JSX_SOURCE_LOCATION_PROP, applySourceReplacements, classNameEdit, completeJsxSourceLocation, editSmsChannel, editWhatsAppChannel, emailAuthoringTarget, emailDefinitionInstances, emailSelectionAncestry, emailSelectionIndex, emailSelectionSiblings, emailSelections, expressionReplacement, inspectSourceElement, inspectSourceFixtures, literalReplacement, previewEmail, readSmsChannel, readWhatsAppChannel, structuralReplacements };
@@ -1,5 +1,5 @@
1
1
  import { n as JsxSource } from "../source-locations-C8wCsiAy.js";
2
- import { a as JSX, i as Fragment, n as EmailComponent, r as EmailNode } from "../jsx-runtime-DC7xG0aA.js";
2
+ import { a as Fragment, i as EmailNode, n as EmailComponent, o as JSX } from "../jsx-runtime-DL8NVF1f.js";
3
3
  //#region src/email/jsx-dev-runtime.d.ts
4
4
  /** Development JSX retains compiler-provided origins directly on the semantic tree. */
5
5
  declare const jsxDEV: (type: string | EmailComponent<Record<string, unknown>> | typeof Fragment, props: Record<string, unknown> | null, _key?: unknown, _staticChildren?: boolean, source?: JsxSource) => EmailNode;
@@ -1,4 +1,4 @@
1
- import { a as jsx, n as Fragment, u as JSX_SOURCE_LOCATION_PROP } from "../jsx-runtime-CBlexoeR.js";
1
+ import { a as jsx, n as Fragment, u as JSX_SOURCE_LOCATION_PROP } from "../jsx-runtime-qL19u3Fy.js";
2
2
  //#region src/email/jsx-dev-runtime.ts
3
3
  /** Development JSX retains compiler-provided origins directly on the semantic tree. */
4
4
  const jsxDEV = (type, props, _key, _staticChildren, source) => jsx(type, {
@@ -1,2 +1,2 @@
1
- import { a as JSX, c as jsx, d as rawMarkup, f as reportEmailDiagnostic, i as Fragment, l as jsxs, n as EmailComponent, o as currentEmailOrigins, r as EmailNode, s as drainEmailDiagnostics, t as EmailChild, u as normalizeChildren } from "../jsx-runtime-DC7xG0aA.js";
2
- export { EmailChild, EmailComponent, EmailNode, Fragment, JSX, currentEmailOrigins, drainEmailDiagnostics, jsx, jsxs, normalizeChildren, rawMarkup, reportEmailDiagnostic };
1
+ import { a as Fragment, c as currentEmailOrigins, d as normalizeChildren, f as rawMarkup, i as EmailNode, l as jsx, n as EmailComponent, o as JSX, p as withEmailDiagnostics, r as EmailFinding, s as collectEmailDiagnostics, t as EmailChild, u as jsxs } from "../jsx-runtime-DL8NVF1f.js";
2
+ export { EmailChild, EmailComponent, EmailFinding, EmailNode, Fragment, JSX, collectEmailDiagnostics, currentEmailOrigins, jsx, jsxs, normalizeChildren, rawMarkup, withEmailDiagnostics };
@@ -1,2 +1,2 @@
1
- import { a as jsx, c as rawMarkup, i as drainEmailDiagnostics, l as reportEmailDiagnostic, n as Fragment, o as jsxs, r as currentEmailOrigins, s as normalizeChildren, t as EmailNode } from "../jsx-runtime-CBlexoeR.js";
2
- export { EmailNode, Fragment, currentEmailOrigins, drainEmailDiagnostics, jsx, jsxs, normalizeChildren, rawMarkup, reportEmailDiagnostic };
1
+ import { a as jsx, c as rawMarkup, i as currentEmailOrigins, l as withEmailDiagnostics, n as Fragment, o as jsxs, r as collectEmailDiagnostics, s as normalizeChildren, t as EmailNode } from "../jsx-runtime-qL19u3Fy.js";
2
+ export { EmailNode, Fragment, collectEmailDiagnostics, currentEmailOrigins, jsx, jsxs, normalizeChildren, rawMarkup, withEmailDiagnostics };
package/dist/email.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { b as EmailStyle, r as EmailNode, t as EmailChild } from "./jsx-runtime-DC7xG0aA.js";
1
+ import { i as EmailNode, t as EmailChild, x as EmailStyle } from "./jsx-runtime-DL8NVF1f.js";
2
2
  //#region src/email/components.d.ts
3
3
  /** Marks the hidden preview block so the renderer can read it back and the text lane can keep it. */
4
4
  declare const PREHEADER_ATTRIBUTE = "data-samva-preheader";
package/dist/email.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as Email, c as PREHEADER_ATTRIBUTE, d as equalColumnWidth, f as preheaderNode, 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-3XHjYD3i.js";
1
+ import { a as Email, c as PREHEADER_ATTRIBUTE, d as equalColumnWidth, f as preheaderNode, 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-C5850-Qg.js";
2
2
  export { Button, Column, Columns, Divider, Email, Image, Link, PREHEADER_ATTRIBUTE, Section, Spacer, equalColumnWidth, preheaderNode };