@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.
- package/AGENTS.md +107 -46
- package/CHANGELOG.md +345 -0
- package/README.md +188 -52
- package/dist/{brand-DcoVkh_S.d.ts → assets-BIsyMQ92.d.ts} +41 -11
- package/dist/{email/brand.js → brand-C0MKTwmX.js} +64 -4
- package/dist/{theme-css.d.ts → brand.d.ts} +12 -3
- package/dist/brand.js +4 -0
- package/dist/channel-specs-C2feJwuP.d.ts +13 -0
- package/dist/compiler.d.ts +88 -115
- package/dist/compiler.js +750 -171
- package/dist/components-BZCqegS8.js +1864 -0
- package/dist/diagnostic-model-DJtqbETd.js +38 -0
- package/dist/{diagnostics-OcQKQYSY.d.ts → diagnostic-model-DxthUZBT.d.ts} +3 -21
- package/dist/{diagnostics-BMYtBCQk.d.ts → diagnostics-B-Gym34R.d.ts} +8 -4
- package/dist/{email/diagnostics.js → diagnostics-CnKFefKz.js} +4 -3
- package/dist/diagnostics.d.ts +410 -2
- package/dist/diagnostics.js +402 -52
- package/dist/edit.d.ts +234 -0
- package/dist/edit.js +947 -0
- package/dist/email/jsx-dev-runtime.d.ts +2 -2
- package/dist/email/jsx-dev-runtime.js +1 -2
- package/dist/email/jsx-runtime.d.ts +1 -1
- package/dist/email/jsx-runtime.js +1 -85
- package/dist/{email/components.d.ts → email.d.ts} +22 -11
- package/dist/email.js +2 -0
- package/dist/fmt.d.ts +32 -0
- package/dist/fmt.js +174 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/{render-vAv_4r9v.js → ir-CLhlklKV.js} +96 -279
- package/dist/jsx-runtime-CBlexoeR.js +98 -0
- package/dist/{elements-BzjjnoCS.d.ts → jsx-runtime-ylIOnaSf.d.ts} +76 -76
- package/dist/profile-pWGtWZXF.js +3803 -0
- package/dist/render-BPonDpCl.d.ts +539 -0
- package/dist/render-BQmfh94k.js +257 -0
- package/dist/render.d.ts +35 -0
- package/dist/render.js +49 -0
- package/dist/sms.d.ts +16 -0
- package/dist/sms.js +12 -0
- package/dist/source-locations-C8wCsiAy.d.ts +23 -0
- package/dist/template-DMPwxMSq.d.ts +65 -0
- package/dist/template-zLUjcwfF.js +42 -0
- package/dist/{theme-css-hFqcPSar.js → theme-css-JtRCm1fb.js} +2 -2
- package/dist/whatsapp.d.ts +57 -0
- package/dist/whatsapp.js +22 -0
- package/generated/contract.json +1788 -0
- package/generated/reference.md +360 -0
- package/package.json +46 -239
- package/samva-brand.d.ts +4 -4
- package/skills/sml/SKILL.md +123 -0
- package/dist/ast-BrDtApwS.d.ts +0 -107
- package/dist/ast.d.ts +0 -2
- package/dist/ast.js +0 -124
- package/dist/candidate.d.ts +0 -29
- package/dist/candidate.js +0 -88
- package/dist/catalog-CKuOooB8.d.ts +0 -354
- package/dist/checks-D73Xizbw.js +0 -59366
- package/dist/checks.d.ts +0 -33
- package/dist/checks.js +0 -2
- package/dist/classes.d.ts +0 -26
- package/dist/classes.js +0 -184
- package/dist/compile-sms.d.ts +0 -28
- package/dist/compile-sms.js +0 -44
- package/dist/compile-whatsapp.d.ts +0 -56
- package/dist/compile-whatsapp.js +0 -186
- package/dist/compile.d.ts +0 -18
- package/dist/compile.js +0 -29
- package/dist/components.d.ts +0 -289
- package/dist/components.js +0 -106
- package/dist/conditionals.d.ts +0 -10
- package/dist/conditionals.js +0 -74
- package/dist/corpus-CPPfgAHN.d.ts +0 -106
- package/dist/css-CS2jLID6.d.ts +0 -109
- package/dist/email/assets.d.ts +0 -40
- package/dist/email/assets.js +0 -63
- package/dist/email/brand-footer.d.ts +0 -34
- package/dist/email/brand-footer.js +0 -62
- package/dist/email/brand.d.ts +0 -2
- package/dist/email/components.js +0 -240
- package/dist/email/diagnostics.d.ts +0 -2
- package/dist/email/elements.d.ts +0 -2
- package/dist/email/elements.js +0 -299
- package/dist/email/html.d.ts +0 -2
- package/dist/email/html.js +0 -278
- package/dist/email/render.d.ts +0 -50
- package/dist/email/render.js +0 -3
- package/dist/email/selection.d.ts +0 -2
- package/dist/email/selection.js +0 -91
- package/dist/email/source-edit.d.ts +0 -67
- package/dist/email/source-edit.js +0 -185
- package/dist/email/stylesheets.d.ts +0 -15
- package/dist/email/stylesheets.js +0 -48
- package/dist/email/text.d.ts +0 -7
- package/dist/email/text.js +0 -100
- package/dist/emit.d.ts +0 -51
- package/dist/emit.js +0 -151
- package/dist/html-Bl9BAdqc.d.ts +0 -42
- package/dist/interpolate.d.ts +0 -24
- package/dist/interpolate.js +0 -43
- package/dist/jsx-dev-runtime.d.ts +0 -11
- package/dist/jsx-dev-runtime.js +0 -15
- package/dist/jsx-runtime-I-1nCtl2.d.ts +0 -57
- package/dist/jsx-runtime.d.ts +0 -2
- package/dist/jsx-runtime.js +0 -121
- package/dist/lexer.d.ts +0 -60
- package/dist/lexer.js +0 -281
- package/dist/model.d.ts +0 -24
- package/dist/model.js +0 -77
- package/dist/ops-BvwqHl7V.js +0 -630
- package/dist/ops.d.ts +0 -114
- package/dist/ops.js +0 -2
- package/dist/parser-t29cHLVL.d.ts +0 -396
- package/dist/parser.d.ts +0 -2
- package/dist/parser.js +0 -859
- package/dist/predicate-BI6uRRM-.js +0 -549
- package/dist/predicate-M-05Nd7R.d.ts +0 -56
- package/dist/predicate.d.ts +0 -2
- package/dist/predicate.js +0 -2
- package/dist/printer.d.ts +0 -6
- package/dist/printer.js +0 -122
- package/dist/registry-Dcp6QEK_.d.ts +0 -73
- package/dist/registry.d.ts +0 -2
- package/dist/registry.js +0 -646
- package/dist/render-template.d.ts +0 -45
- package/dist/render-template.js +0 -76
- package/dist/selection-CCArx9lU.d.ts +0 -91
- package/dist/showcase-egkusQBf.d.ts +0 -415
- package/dist/sms-segments-y4FpPilJ.d.ts +0 -13
- package/dist/sms-segments.d.ts +0 -2
- package/dist/sms-segments.js +0 -46
- package/dist/source-locations-DrCM82Ym.d.ts +0 -67
- package/dist/source-locations.d.ts +0 -2
- package/dist/source-locations.js +0 -102
- package/dist/starters/category-mapping.d.ts +0 -13
- package/dist/starters/category-mapping.js +0 -49
- package/dist/starters/corpus.d.ts +0 -2
- package/dist/starters/corpus.js +0 -194
- package/dist/starters/library.d.ts +0 -18
- package/dist/starters/library.js +0 -692
- package/dist/starters/public-gallery.d.ts +0 -266
- package/dist/starters/public-gallery.js +0 -916
- package/dist/starters/public-handoff.d.ts +0 -164
- package/dist/starters/public-handoff.js +0 -361
- package/dist/starters/public-preview-artifacts.d.ts +0 -43
- package/dist/starters/public-preview-artifacts.js +0 -104
- package/dist/starters/public-preview.d.ts +0 -61
- package/dist/starters/public-preview.js +0 -83
- package/dist/starters/showcase.d.ts +0 -2
- package/dist/starters/showcase.js +0 -335
- package/dist/starters/sources.d.ts +0 -45
- package/dist/starters/sources.js +0 -7762
- package/dist/starters/theme.d.ts +0 -45
- package/dist/starters/theme.js +0 -77
- package/dist/starters.d.ts +0 -2
- package/dist/starters.js +0 -874
- package/dist/tailwind-BYq7Lo6u.js +0 -727
- package/dist/template-DWftqh4x.d.ts +0 -60
- package/dist/template.d.ts +0 -2
- package/dist/template.js +0 -37
- package/dist/theme-css.js +0 -2
- package/dist/tsx-source-instrumentation.d.ts +0 -30
- package/dist/tsx-source-instrumentation.js +0 -115
- package/dist/tsx-tracer.d.ts +0 -112
- package/dist/tsx-tracer.js +0 -985
- package/dist/variables-J_L3qxRa.d.ts +0 -77
- package/dist/variables.d.ts +0 -2
- package/dist/variables.js +0 -141
- package/dist/version-BITr58kk.js +0 -96
- package/generated/sml-agent-contract.json +0 -709
- package/generated/sml-email-agent-contract.json +0 -615
- package/generated/sml-email-language-reference.md +0 -94
- package/generated/sml-language-reference.md +0 -195
package/dist/css-CS2jLID6.d.ts
DELETED
|
@@ -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
|
package/dist/email/assets.d.ts
DELETED
|
@@ -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
|
package/dist/email/assets.js
DELETED
|
@@ -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
|
package/dist/email/brand.d.ts
DELETED
|
@@ -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 };
|
package/dist/email/components.js
DELETED
|
@@ -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 };
|
package/dist/email/elements.d.ts
DELETED
|
@@ -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 };
|