@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
@@ -1,109 +0,0 @@
1
- import { r as EmailDiagnostic } from "./diagnostics-BMYtBCQk.js";
2
- import { m as EmailNode } from "./elements-BzjjnoCS.js";
3
- import "css-tree";
4
- //#region src/email/font-stacks.d.ts
5
- /** One `@font-face` rule, its `src` already resolved to served URLs. */
6
- interface FontFaceRule {
7
- /** The family the rule declares, unquoted. */
8
- readonly family: string;
9
- /** The rule as it goes into the email's `<head>`. */
10
- readonly css: string;
11
- }
12
- //#endregion
13
- //#region src/email/fonts.d.ts
14
- /**
15
- * Maps a relative `src` URL, as authored, to the URL its project file is served
16
- * from, or `undefined` when the project has no such file. The stylesheet's host
17
- * owns this: it knows which file the stylesheet came from and the asset base.
18
- */
19
- type FontFileResolver = (reference: string) => string | undefined;
20
- //#endregion
21
- //#region src/email/selectors.d.ts
22
- type EmailElementNode = Extract<EmailNode, {
23
- type: "Element";
24
- }>;
25
- interface AttributeTest {
26
- readonly name: string;
27
- readonly operator?: string | undefined;
28
- readonly value?: string | undefined;
29
- }
30
- interface Compound {
31
- readonly tag?: string | undefined;
32
- readonly id?: string | undefined;
33
- readonly classes: readonly string[];
34
- readonly attributes: readonly AttributeTest[];
35
- /** A compound the matcher cannot evaluate — a pseudo-class, say — never matches. */
36
- readonly opaque: boolean;
37
- }
38
- type Combinator = "descendant" | "child" | "adjacent" | "sibling";
39
- interface CompiledSelector {
40
- /** Document order, left to right; each part names the combinator that follows it. */
41
- readonly parts: readonly {
42
- readonly compound: Compound;
43
- readonly after?: Combinator;
44
- }[];
45
- }
46
- /** An element together with the ancestors and preceding siblings a combinator needs. */
47
- interface Ancestry {
48
- readonly element: EmailElementNode;
49
- readonly parent: Ancestry | undefined;
50
- readonly previous: readonly EmailElementNode[];
51
- }
52
- declare const classListOf: (element: EmailElementNode) => readonly string[];
53
- /** Match a compiled selector against one element in its tree position. */
54
- declare const matchesSelector: (selector: CompiledSelector | undefined, ancestry: Ancestry) => boolean;
55
- //#endregion
56
- //#region src/email/css.d.ts
57
- interface CssDeclaration {
58
- /** Kebab-case property name, as authored. */
59
- readonly property: string;
60
- readonly value: string;
61
- readonly important: boolean;
62
- }
63
- /** Specificity as the CSS triple (id, class/attribute/pseudo-class, type). */
64
- type Specificity = readonly [number, number, number];
65
- interface CssRule {
66
- /** Exactly one selector; a selector list is split into one rule each. */
67
- readonly selector: string;
68
- /** Decoded class identifiers mentioned by this selector, including nested pseudo selectors. */
69
- readonly classes: readonly string[];
70
- readonly specificity: Specificity;
71
- readonly declarations: readonly CssDeclaration[];
72
- /** Position across every stylesheet, in the order they were imported. */
73
- readonly order: number;
74
- /** Declared `@layer` index; unlayered declarations sort above every layer. */
75
- readonly layer: number;
76
- /** Enclosing conditional at-rule preludes, outermost first. */
77
- readonly conditions: readonly string[];
78
- /** Unconditional and pseudo-free rules are the only ones that can become an inline style. */
79
- readonly inlinable: boolean;
80
- /** Compiled at build time so the render lane needs no CSS parser. */
81
- readonly matcher: CompiledSelector | undefined;
82
- }
83
- interface Stylesheet {
84
- readonly rules: readonly CssRule[];
85
- /** `@page`, `@keyframes` and other at-rules kept verbatim in `<head>`. */
86
- readonly headAtRules: readonly string[];
87
- /** Validated `@font-face` rules, `src` resolved; the render hides them from classic Outlook. */
88
- readonly fontFaces: readonly FontFaceRule[];
89
- /** Unconditional custom properties, for resolving `var()` before inlining. */
90
- readonly variables: Readonly<Record<string, string>>;
91
- readonly diagnostics: readonly EmailDiagnostic[];
92
- }
93
- /** Compile a selector into the plain-data matcher the render lane uses. */
94
- declare const compileSelector: (selector: string) => CompiledSelector | undefined;
95
- /** Parse one stylesheet into rules, keeping layer, order and conditions. */
96
- declare const parseStylesheet: (source: string, options?: {
97
- readonly origin?: string;
98
- readonly startOrder?: number;
99
- /** Resolves a relative `@font-face` src to the URL its project file is served from. */
100
- readonly resolveFontFile?: FontFileResolver | undefined;
101
- /**
102
- * The sheet belongs to the project theme, whose `@import`s the Tailwind
103
- * compile resolves; they are layering, not something to report here.
104
- */
105
- readonly themeImports?: boolean | undefined;
106
- }) => Stylesheet;
107
- //#endregion
108
- export { compileSelector as a, CompiledSelector as c, matchesSelector as d, Stylesheet as i, Compound as l, CssRule as n, parseStylesheet as o, Specificity as r, Ancestry as s, CssDeclaration as t, classListOf as u };
109
- //# sourceMappingURL=css-CS2jLID6.d.ts.map
@@ -1,40 +0,0 @@
1
- import { r as EmailDiagnostic } from "../diagnostics-BMYtBCQk.js";
2
- //#region src/email/assets.d.ts
3
- /** Files a template may import, and what they are served as. */
4
- declare const ASSET_CONTENT_TYPES: Readonly<Record<string, string>>;
5
- interface AssetEntry {
6
- /** Project-relative path the template imported. */
7
- readonly path: string;
8
- /** SHA-256 of the exact bytes, lowercase hex. */
9
- readonly digest: string;
10
- readonly bytes: number;
11
- readonly contentType: string;
12
- /** `<digest><ext>` — the name the asset has under any base. */
13
- readonly fileName: string;
14
- }
15
- interface AssetManifest {
16
- /** Where these assets are served from in this build. */
17
- readonly base: string;
18
- readonly assets: readonly AssetEntry[];
19
- }
20
- /** True when the compiler turns this import into a content-addressed asset. */
21
- declare const isAssetPath: (path: string) => boolean;
22
- /** Address one file by its content. */
23
- declare const assetEntry: (path: string, bytes: Uint8Array) => Promise<AssetEntry>;
24
- /**
25
- * The URL an asset has under a base. The base is a build input: publication
26
- * passes its hosted origin, and a local export passes whatever it will serve
27
- * the exported files from.
28
- */
29
- declare const assetUrl: (entry: AssetEntry, base: string) => string;
30
- /** Record, but never fetch, a URL the template points at. */
31
- declare const isExternalAsset: (reference: string) => boolean;
32
- /**
33
- * Reject an asset base that would produce URLs a client will not load. The
34
- * relative forms are the ones a page on disk resolves against its own
35
- * directory, which is what a local export writes.
36
- */
37
- declare const checkAssetBase: (base: string) => readonly EmailDiagnostic[];
38
- //#endregion
39
- export { ASSET_CONTENT_TYPES, AssetEntry, AssetManifest, assetEntry, assetUrl, checkAssetBase, isAssetPath, isExternalAsset };
40
- //# sourceMappingURL=assets.d.ts.map
@@ -1,63 +0,0 @@
1
- //#region src/email/assets.ts
2
- /** Files a template may import, and what they are served as. */
3
- const ASSET_CONTENT_TYPES = {
4
- ".png": "image/png",
5
- ".jpg": "image/jpeg",
6
- ".jpeg": "image/jpeg",
7
- ".gif": "image/gif",
8
- ".webp": "image/webp",
9
- ".avif": "image/avif",
10
- ".svg": "image/svg+xml",
11
- ".ico": "image/x-icon",
12
- ".woff": "font/woff",
13
- ".woff2": "font/woff2",
14
- ".ttf": "font/ttf",
15
- ".otf": "font/otf",
16
- ".pdf": "application/pdf",
17
- ".txt": "text/plain"
18
- };
19
- const extensionOf = (path) => {
20
- const dot = path.lastIndexOf(".");
21
- return dot < 0 ? "" : path.slice(dot).toLowerCase();
22
- };
23
- /** True when the compiler turns this import into a content-addressed asset. */
24
- const isAssetPath = (path) => Object.hasOwn(ASSET_CONTENT_TYPES, extensionOf(path));
25
- const hex = (buffer) => Array.from(new Uint8Array(buffer), (byte) => byte.toString(16).padStart(2, "0")).join("");
26
- /** Address one file by its content. */
27
- const assetEntry = async (path, bytes) => {
28
- const extension = extensionOf(path);
29
- const view = new Uint8Array(bytes.byteLength);
30
- view.set(bytes);
31
- const digest = hex(await crypto.subtle.digest("SHA-256", view));
32
- return {
33
- path,
34
- digest,
35
- bytes: bytes.byteLength,
36
- contentType: ASSET_CONTENT_TYPES[extension] ?? "application/octet-stream",
37
- fileName: `${digest}${extension}`
38
- };
39
- };
40
- /**
41
- * The URL an asset has under a base. The base is a build input: publication
42
- * passes its hosted origin, and a local export passes whatever it will serve
43
- * the exported files from.
44
- */
45
- const assetUrl = (entry, base) => `${base.replace(/\/+$/, "")}/${entry.fileName}`;
46
- const EXTERNAL_IMAGE = /^https:\/\//i;
47
- /** Record, but never fetch, a URL the template points at. */
48
- const isExternalAsset = (reference) => EXTERNAL_IMAGE.test(reference);
49
- /**
50
- * Reject an asset base that would produce URLs a client will not load. The
51
- * relative forms are the ones a page on disk resolves against its own
52
- * directory, which is what a local export writes.
53
- */
54
- const checkAssetBase = (base) => /^(https:\/\/|\.{1,2}\/|\/)/i.test(base) ? [] : [{
55
- code: "invalid-asset-base",
56
- severity: "error",
57
- message: `Asset base ${JSON.stringify(base)} must be an https URL, an absolute path, or a relative path for a local export.`,
58
- origins: []
59
- }];
60
- //#endregion
61
- export { ASSET_CONTENT_TYPES, assetEntry, assetUrl, checkAssetBase, isAssetPath, isExternalAsset };
62
-
63
- //# sourceMappingURL=assets.js.map
@@ -1,34 +0,0 @@
1
- import { t as EmailContent } from "../template-DWftqh4x.js";
2
- import { RenderedEmail } from "./render.js";
3
- import { a as EmailBrand, n as BrandComponents } from "../brand-DcoVkh_S.js";
4
- //#region src/email/brand-footer.d.ts
5
- /** A footer block for the send path to append, and its plain-text tail. */
6
- interface RenderedBrandFooter {
7
- readonly html: string;
8
- readonly text: string;
9
- }
10
- /**
11
- * Render `BrandFooter` against a brand on its own, for the send path to
12
- * append to a message whose template renders no footer of its own. It
13
- * compiles the same component, styled by the same brand theme, a template
14
- * would get from `samva:brand`. Without `unsubscribe` the unsubscribe row is
15
- * left out.
16
- */
17
- declare const renderBrandFooter: (brand: EmailBrand, options: {
18
- readonly unsubscribe: boolean;
19
- }) => Promise<RenderedBrandFooter>;
20
- /**
21
- * Render content against a brand as a project whose `theme.css` is
22
- * `@import "samva:brand";` renders it: Tailwind compiles the brand theme for
23
- * the classes the content names, `BrandLogo` and `BrandFooter` are bound to the
24
- * brand, and the render inlines the result. A brand preview renders through
25
- * this, so it shows what a template importing the brand compiles to.
26
- */
27
- declare const renderBrandSample: (brand: EmailBrand, sample: {
28
- /** Every class the content names; nothing is discovered from source here. */
29
- readonly classes: readonly string[];
30
- readonly render: (components: BrandComponents) => EmailContent;
31
- }) => Promise<RenderedEmail>;
32
- //#endregion
33
- export { RenderedBrandFooter, renderBrandFooter, renderBrandSample };
34
- //# sourceMappingURL=brand-footer.d.ts.map
@@ -1,62 +0,0 @@
1
- import { a as renderEmailContent, o as applyStylesheet, r as compileEmail } from "../render-vAv_4r9v.js";
2
- import { EmailCompileError } from "./diagnostics.js";
3
- import { BRAND_COMPONENT_CLASSES, brandComponents, withoutUnsubscribeRow } from "./brand.js";
4
- import { c as parseBrandCss, i as brandTailwindCss } from "../theme-css-hFqcPSar.js";
5
- import { t as compileTailwind, u as parseStylesheet } from "../tailwind-BYq7Lo6u.js";
6
- //#region src/email/brand-footer.ts
7
- /** The brand theme as Tailwind compiles it; a theme outside the grammar is a compile refusal. */
8
- const brandTheme = (brand) => {
9
- const parsed = parseBrandCss(brand.css);
10
- if (parsed.isErr()) throw new EmailCompileError({ diagnostics: parsed.error.map((finding) => ({
11
- code: finding.code,
12
- severity: "error",
13
- message: `samva:brand: ${finding.message}`,
14
- origins: []
15
- })) });
16
- return brandTailwindCss(parsed.value);
17
- };
18
- /**
19
- * Render `BrandFooter` against a brand on its own, for the send path to
20
- * append to a message whose template renders no footer of its own. It
21
- * compiles the same component, styled by the same brand theme, a template
22
- * would get from `samva:brand`. Without `unsubscribe` the unsubscribe row is
23
- * left out.
24
- */
25
- const renderBrandFooter = async (brand, options) => {
26
- const tailwind = await compileTailwind(BRAND_COMPONENT_CLASSES, { css: brandTheme(brand) });
27
- const node = brandComponents(brand).BrandFooter({});
28
- if (node === null) return {
29
- html: "",
30
- text: ""
31
- };
32
- const styled = applyStylesheet(node, parseStylesheet(tailwind.css, { origin: "samva:brand" }));
33
- const compiled = compileEmail(styled.tree);
34
- const rendered = options.unsubscribe ? compiled : withoutUnsubscribeRow({
35
- html: compiled.html,
36
- text: compiled.text
37
- });
38
- const text = (rendered.text ?? "").trim();
39
- return {
40
- html: rendered.html ?? "",
41
- text: text === "" ? "" : `\n\n---\n${text}`
42
- };
43
- };
44
- /**
45
- * Render content against a brand as a project whose `theme.css` is
46
- * `@import "samva:brand";` renders it: Tailwind compiles the brand theme for
47
- * the classes the content names, `BrandLogo` and `BrandFooter` are bound to the
48
- * brand, and the render inlines the result. A brand preview renders through
49
- * this, so it shows what a template importing the brand compiles to.
50
- */
51
- const renderBrandSample = async (brand, sample) => {
52
- const tailwind = await compileTailwind([...BRAND_COMPONENT_CLASSES, ...sample.classes], { css: "@import \"samva:brand\";" }, {
53
- stylesheets: /* @__PURE__ */ new Map(),
54
- brandCss: brandTheme(brand)
55
- });
56
- const components = brandComponents(brand);
57
- return renderEmailContent(parseStylesheet(tailwind.css, { origin: "samva:brand" }), () => sample.render(components));
58
- };
59
- //#endregion
60
- export { renderBrandFooter, renderBrandSample };
61
-
62
- //# sourceMappingURL=brand-footer.js.map
@@ -1,2 +0,0 @@
1
- import { a as EmailBrand, c as EmailBrandFooter, d as RenderedFooterMarkers, f as UNSUBSCRIBE_ROW_ATTRIBUTE, g as UNSUBSCRIBE_URL_PLACEHOLDER, h as withoutUnsubscribeRow, i as BrandLogoProps, l as EmailBrandSocialLink, m as renderedFooterMarkers, n as BrandComponents, o as EmailBrandAddress, p as brandComponents, r as BrandFooterProps, s as EmailBrandAssets, t as BRAND_COMPONENT_CLASSES, u as FOOTER_ATTRIBUTE } from "../brand-DcoVkh_S.js";
2
- export { BRAND_COMPONENT_CLASSES, BrandComponents, BrandFooterProps, BrandLogoProps, EmailBrand, EmailBrandAddress, EmailBrandAssets, EmailBrandFooter, EmailBrandSocialLink, FOOTER_ATTRIBUTE, RenderedFooterMarkers, UNSUBSCRIBE_ROW_ATTRIBUTE, UNSUBSCRIBE_URL_PLACEHOLDER, brandComponents, renderedFooterMarkers, withoutUnsubscribeRow };
@@ -1,240 +0,0 @@
1
- import { jsx, rawMarkup, reportEmailDiagnostic } from "./jsx-runtime.js";
2
- import { escapeAttribute, escapeText } from "./html.js";
3
- //#region src/email/components.ts
4
- /** Marks the hidden preview block so the renderer can read it back and the text lane can keep it. */
5
- const PREHEADER_ATTRIBUTE = "data-samva-preheader";
6
- const PREHEADER_PADDING_ATTRIBUTE = "data-samva-preheader-padding";
7
- const PREHEADER_TARGET_LENGTH = 200;
8
- const PREHEADER_PADDING = "\xA0‌​‍‎‏";
9
- const presentation = (table, row, rowProps = {}) => jsx("table", {
10
- role: "presentation",
11
- border: 0,
12
- cellpadding: 0,
13
- cellspacing: 0,
14
- ...table,
15
- children: jsx("tbody", { children: jsx("tr", {
16
- ...rowProps,
17
- children: row
18
- }) })
19
- });
20
- /** The hidden inbox preview block. Padding characters stop the client borrowing body copy. */
21
- const preheaderNode = (text) => jsx("div", {
22
- [PREHEADER_ATTRIBUTE]: text,
23
- style: {
24
- display: "none",
25
- overflow: "hidden",
26
- lineHeight: "1px",
27
- opacity: 0,
28
- maxHeight: 0,
29
- maxWidth: 0
30
- },
31
- children: [text, text.length >= PREHEADER_TARGET_LENGTH ? null : jsx("div", {
32
- [PREHEADER_PADDING_ATTRIBUTE]: true,
33
- children: PREHEADER_PADDING.repeat(Math.ceil((PREHEADER_TARGET_LENGTH - text.length) / 7))
34
- })]
35
- });
36
- /** Document shell: the head every target client needs, plus the body content cell. */
37
- const Email = ({ className, lang = "en", dir = "ltr", title, preheader, backgroundColor, style, children }) => jsx("html", {
38
- lang,
39
- dir,
40
- xmlns: "http://www.w3.org/1999/xhtml",
41
- "xmlns:o": "urn:schemas-microsoft-com:office:office",
42
- children: [jsx("head", { children: [
43
- jsx("meta", { charset: "utf-8" }),
44
- jsx("meta", {
45
- "http-equiv": "Content-Type",
46
- content: "text/html; charset=UTF-8"
47
- }),
48
- jsx("meta", {
49
- name: "viewport",
50
- content: "width=device-width, initial-scale=1"
51
- }),
52
- jsx("meta", { name: "x-apple-disable-message-reformatting" }),
53
- jsx("meta", {
54
- name: "color-scheme",
55
- content: "light dark"
56
- }),
57
- jsx("meta", {
58
- name: "supported-color-schemes",
59
- content: "light dark"
60
- }),
61
- title === void 0 ? null : jsx("title", { children: title }),
62
- rawMarkup("<!--[if mso]><xml><o:OfficeDocumentSettings><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings></xml><![endif]-->")
63
- ] }), jsx("body", {
64
- style: {
65
- margin: 0,
66
- padding: 0,
67
- ...backgroundColor === void 0 ? {} : { backgroundColor }
68
- },
69
- children: [preheader === void 0 ? null : preheaderNode(preheader), presentation({
70
- align: "center",
71
- width: "100%",
72
- ...backgroundColor === void 0 ? {} : { bgcolor: backgroundColor }
73
- }, jsx("td", {
74
- className,
75
- ...style === void 0 ? {} : { style },
76
- children
77
- }))]
78
- })]
79
- });
80
- /** A full-width band of content, as the single-cell table every client agrees on. */
81
- const Section = ({ className, align = "center", width = "100%", bgcolor, style, tableStyle, children }) => presentation({
82
- align,
83
- width,
84
- ...bgcolor === void 0 ? {} : { bgcolor },
85
- ...tableStyle === void 0 ? {} : { style: tableStyle }
86
- }, jsx("td", {
87
- className,
88
- ...style === void 0 ? {} : { style },
89
- children
90
- }));
91
- /** A row of side-by-side `Column`s. No flex or grid conversion happens here. */
92
- const Columns = ({ className, align = "center", width = "100%", style, children }) => presentation({
93
- className,
94
- align,
95
- width,
96
- ...style === void 0 ? {} : { style }
97
- }, children, { style: { width: "100%" } });
98
- /** One cell of a `Columns` row. */
99
- const Column = ({ className, align, valign, width, style, children }) => jsx("td", {
100
- className,
101
- ...align === void 0 ? {} : { align },
102
- ...valign === void 0 ? {} : { valign },
103
- ...width === void 0 ? {} : { width },
104
- ...style === void 0 ? {} : { style },
105
- children
106
- });
107
- const DEFAULT_BUTTON_FONT = "Helvetica, Arial, sans-serif";
108
- /** Average advance of a bold sans-serif glyph, as a fraction of the font size. */
109
- const BOLD_GLYPH_ADVANCE = .6;
110
- const invalidButtonNumber = (name) => reportEmailDiagnostic({
111
- code: "invalid-button-number",
112
- severity: "error",
113
- message: `<Button ${name}> must be a finite number.`
114
- });
115
- const buttonNumber = (name, value, fallback) => {
116
- if (typeof value === "number" && Number.isFinite(value)) return value;
117
- invalidButtonNumber(name);
118
- return fallback;
119
- };
120
- const optionalButtonNumber = (name, value) => {
121
- if (value === void 0) return void 0;
122
- if (typeof value === "number" && Number.isFinite(value)) return value;
123
- invalidButtonNumber(name);
124
- };
125
- const optionalPositiveButtonNumber = (name, value) => {
126
- if (value === void 0) return void 0;
127
- if (typeof value === "number" && Number.isFinite(value) && value > 0) return value;
128
- reportEmailDiagnostic({
129
- code: "invalid-button-number",
130
- severity: "error",
131
- message: `<Button ${name}> must be a positive finite number.`
132
- });
133
- };
134
- /** A link styled as a button, with a VML fallback so classic Outlook draws the shape. */
135
- const Button = ({ className, href, width, height, paddingX = 16, backgroundColor = "#000000", color = "#ffffff", borderRadius = 0, borderColor, borderWidth = 0, fontSize = 16, fontFamily = DEFAULT_BUTTON_FONT, align = "left", style, children }) => {
136
- const safeWidth = optionalButtonNumber("width", width);
137
- const safeHeight = optionalPositiveButtonNumber("height", height);
138
- const safePaddingX = buttonNumber("paddingX", paddingX, 16);
139
- const safeBorderRadius = buttonNumber("borderRadius", borderRadius, 0);
140
- const safeBorderWidth = buttonNumber("borderWidth", borderWidth, 0);
141
- const safeFontSize = buttonNumber("fontSize", fontSize, 16);
142
- const label = typeof children === "string" ? children : void 0;
143
- const fallback = safeHeight !== void 0 && label !== void 0;
144
- if (!fallback) reportEmailDiagnostic({
145
- code: "button-outlook-fallback",
146
- severity: "warning",
147
- message: "<Button> draws its classic Outlook shape from VML, which needs a height and a plain string label. Without both, classic Windows Outlook shows an unstyled link.",
148
- clients: ["outlook-windows"]
149
- });
150
- const arcsize = safeHeight === void 0 ? 0 : Math.round(safeBorderRadius / safeHeight * 100);
151
- const fallbackWidth = safeWidth ?? Math.ceil((label?.length ?? 0) * safeFontSize * BOLD_GLYPH_ADVANCE) + 2 * safePaddingX;
152
- return presentation({
153
- width: "100%",
154
- style: { borderCollapse: "collapse" }
155
- }, jsx("td", {
156
- align,
157
- children: [fallback ? rawMarkup(`<!--[if mso]><v:roundrect xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word" href="${escapeAttribute(href)}" style="height:${safeHeight}px;v-text-anchor:middle;width:${fallbackWidth}px;" arcsize="${arcsize}%" ${borderColor === void 0 ? "stroke=\"false\"" : `strokecolor="${escapeAttribute(borderColor)}" strokeweight="${safeBorderWidth}px"`} fillcolor="${escapeAttribute(backgroundColor)}"><w:anchorlock/><center style="color:${escapeAttribute(color)};font-family:${escapeAttribute(fontFamily)};font-size:${safeFontSize}px;font-weight:bold;">${escapeText(label)}</center></v:roundrect><![endif]-->`) : null, jsx("a", {
158
- className,
159
- href,
160
- target: "_blank",
161
- rel: "noopener noreferrer",
162
- style: {
163
- backgroundColor,
164
- color,
165
- borderRadius: `${safeBorderRadius}px`,
166
- display: "inline-block",
167
- fontFamily,
168
- fontSize: `${safeFontSize}px`,
169
- fontWeight: "bold",
170
- lineHeight: safeHeight === void 0 ? "120%" : `${safeHeight - 2 * safeBorderWidth}px`,
171
- textAlign: "center",
172
- textDecoration: "none",
173
- ...safeWidth === void 0 ? { padding: `0 ${safePaddingX}px` } : {
174
- width: `${safeWidth}px`,
175
- maxWidth: "100%"
176
- },
177
- ...borderColor === void 0 ? {} : { border: `${safeBorderWidth}px solid ${borderColor}` },
178
- ...fallback ? { msoHide: "all" } : {},
179
- ...style
180
- },
181
- children
182
- })]
183
- }));
184
- };
185
- /** Vertical space that survives clients which collapse margins. */
186
- const Spacer = ({ height }) => presentation({ width: "100%" }, jsx("td", {
187
- height,
188
- style: {
189
- height: `${height}px`,
190
- lineHeight: `${height}px`,
191
- fontSize: "1px"
192
- },
193
- children: "​"
194
- }));
195
- /** A horizontal rule drawn as a cell border, which every target client renders. */
196
- const Divider = ({ className, color = "#e5e7eb", thickness = 1, style }) => presentation({ width: "100%" }, jsx("td", {
197
- className,
198
- style: {
199
- borderTop: `${thickness}px solid ${color}`,
200
- fontSize: "1px",
201
- lineHeight: "1px",
202
- ...style
203
- },
204
- children: "​"
205
- }));
206
- /** An image with the width/height attributes Outlook sizes from before CSS applies. */
207
- const Image = ({ className, src, alt, width, height, align, style }) => jsx("img", {
208
- className,
209
- src,
210
- alt,
211
- border: 0,
212
- ...width === void 0 ? {} : { width },
213
- ...height === void 0 ? {} : { height },
214
- ...align === void 0 ? {} : { align },
215
- style: {
216
- display: "block",
217
- outline: "none",
218
- border: "none",
219
- textDecoration: "none",
220
- maxWidth: "100%",
221
- ...style
222
- }
223
- });
224
- /** A text link that opens outside the client and cannot reach back at the opener. */
225
- const Link = ({ className, href, target = "_blank", rel = "noopener noreferrer", style, children }) => jsx("a", {
226
- className,
227
- href,
228
- target,
229
- rel,
230
- style: {
231
- color: "#067df7",
232
- textDecoration: "none",
233
- ...style
234
- },
235
- children
236
- });
237
- //#endregion
238
- export { Button, Column, Columns, Divider, Email, Image, Link, PREHEADER_ATTRIBUTE, Section, Spacer, preheaderNode };
239
-
240
- //# sourceMappingURL=components.js.map
@@ -1,2 +0,0 @@
1
- import { a as formatEmailDiagnostic, i as EmailDiagnosticSeverity, n as EmailCompileError, o as hasBlockingDiagnostic, r as EmailDiagnostic, t as EmailCompatibilityAssessment } from "../diagnostics-BMYtBCQk.js";
2
- export { EmailCompatibilityAssessment, EmailCompileError, EmailDiagnostic, EmailDiagnosticSeverity, formatEmailDiagnostic, hasBlockingDiagnostic };
@@ -1,2 +0,0 @@
1
- import { a as EmailGlobalProps, c as EmailStyle, d as isUrlAttribute, i as EmailElementSpec, l as EmailTag, n as EMAIL_GLOBAL_ATTRIBUTES, o as EmailIntrinsicElements, r as EmailAttributeSpec, s as EmailLayout, t as EMAIL_ELEMENTS, u as emailElement } from "../elements-BzjjnoCS.js";
2
- export { EMAIL_ELEMENTS, EMAIL_GLOBAL_ATTRIBUTES, EmailAttributeSpec, EmailElementSpec, EmailGlobalProps, EmailIntrinsicElements, EmailLayout, EmailStyle, EmailTag, emailElement, isUrlAttribute };