@samva/markup 0.2.0 → 0.3.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/dist/presets.d.ts CHANGED
@@ -13,14 +13,41 @@ interface PresetMeta {
13
13
  /** One-line description of when to reach for this preset. */
14
14
  readonly description: string;
15
15
  /**
16
- * Every variable the source interpolates, sorted. A sender fills these in;
17
- * an org theme re-themes the brand tokens. Kept in exact parity with
18
- * collectVariableReferences(source) by the preset test suite.
16
+ * Every input property declared by the template schema, sorted.
17
+ * A sender supplies these values when rendering the template.
19
18
  */
20
19
  readonly variables: ReadonlyArray<string>;
21
20
  }
22
21
  declare const RECOMMENDED_THEME: TokenOverrides;
23
22
  declare const presetCatalog: readonly [{
23
+ readonly id: "linear-login-code";
24
+ readonly channel: "email";
25
+ readonly category: "transactional";
26
+ readonly name: "Linear login code";
27
+ readonly description: "Recreate Linear's login code email with an editable magic link, code, and bundled logo.";
28
+ readonly variables: readonly ["expiryNotice", "homeUrl", "loginUrl", "productName", "validationCode"];
29
+ }, {
30
+ readonly id: "product-newsletter";
31
+ readonly channel: "email";
32
+ readonly category: "digest";
33
+ readonly name: "Product newsletter";
34
+ readonly description: "A monthly product newsletter with a lead story, mapped secondary stories, a changelog and one action.";
35
+ readonly variables: readonly ["changelog", "issueMonth", "issueNumber", "issueUrl", "leadImage", "leadSummary", "leadTitle", "leadUrl", "preferencesUrl", "stories", "unsubscribeUrl"];
36
+ }, {
37
+ readonly id: "vercel-invitation";
38
+ readonly channel: "email";
39
+ readonly category: "transactional";
40
+ readonly name: "Vercel team invitation";
41
+ readonly description: "Recreate Vercel's team invitation with editable source and bundled assets.";
42
+ readonly variables: readonly ["inviteFromIp", "inviteFromLocation", "inviteLink", "invitedByEmail", "invitedByUsername", "teamImage", "teamName", "userImage", "username"];
43
+ }, {
44
+ readonly id: "order-receipt";
45
+ readonly channel: "email";
46
+ readonly category: "transactional";
47
+ readonly name: "Order receipt";
48
+ readonly description: "Itemized order receipt with product thumbnails, totals, payment summary and shipping address.";
49
+ readonly variables: readonly ["customerName", "discount", "items", "orderDate", "orderNumber", "orderUrl", "paymentBrand", "paymentLast4", "shipping", "shippingAddress", "subtotal", "supportEmail", "tax", "total"];
50
+ }, {
24
51
  readonly id: "welcome";
25
52
  readonly channel: "email";
26
53
  readonly category: "transactional";
@@ -244,6 +271,13 @@ declare const presetCatalog: readonly [{
244
271
  readonly name: "Season clearance promotion";
245
272
  readonly description: "A last-chance clearance promotion with a hero banner, a deadline phrase, and a single shop action.";
246
273
  readonly variables: readonly ["contactEmailUrl", "grabDealsUrl", "heroImageUrl", "offerDeadlinePhrase", "offerEndLong", "offerEndShort", "onlineVersionUrl", "preferencesUrl", "seasonYear", "secondaryBannerImageUrl", "socialFourIconUrl", "socialOneIconUrl", "socialThreeIconUrl", "socialTwoIconUrl", "termsUrl", "unsubscribeUrl"];
274
+ }, {
275
+ readonly id: "product-launch-promo";
276
+ readonly channel: "email";
277
+ readonly category: "marketing";
278
+ readonly name: "Product launch promotion";
279
+ readonly description: "Launch a collection with a hero, a four-product grid, a discount code, and one shop action.";
280
+ readonly variables: readonly ["bestSellersUrl", "discountCode", "firstName", "headline", "newArrivalsUrl", "offerEnds", "preferencesUrl", "products", "saleUrl", "shopUrl", "subhead", "unsubscribeUrl"];
247
281
  }, {
248
282
  readonly id: "onboarding-step";
249
283
  readonly channel: "email";
package/dist/presets.js CHANGED
@@ -7,6 +7,81 @@ const RECOMMENDED_THEME = {
7
7
  radiusPx: { brand: 8 }
8
8
  };
9
9
  const presetCatalog = [
10
+ {
11
+ id: "linear-login-code",
12
+ channel: "email",
13
+ category: "transactional",
14
+ name: "Linear login code",
15
+ description: "Recreate Linear's login code email with an editable magic link, code, and bundled logo.",
16
+ variables: [
17
+ "expiryNotice",
18
+ "homeUrl",
19
+ "loginUrl",
20
+ "productName",
21
+ "validationCode"
22
+ ]
23
+ },
24
+ {
25
+ id: "product-newsletter",
26
+ channel: "email",
27
+ category: "digest",
28
+ name: "Product newsletter",
29
+ description: "A monthly product newsletter with a lead story, mapped secondary stories, a changelog and one action.",
30
+ variables: [
31
+ "changelog",
32
+ "issueMonth",
33
+ "issueNumber",
34
+ "issueUrl",
35
+ "leadImage",
36
+ "leadSummary",
37
+ "leadTitle",
38
+ "leadUrl",
39
+ "preferencesUrl",
40
+ "stories",
41
+ "unsubscribeUrl"
42
+ ]
43
+ },
44
+ {
45
+ id: "vercel-invitation",
46
+ channel: "email",
47
+ category: "transactional",
48
+ name: "Vercel team invitation",
49
+ description: "Recreate Vercel's team invitation with editable source and bundled assets.",
50
+ variables: [
51
+ "inviteFromIp",
52
+ "inviteFromLocation",
53
+ "inviteLink",
54
+ "invitedByEmail",
55
+ "invitedByUsername",
56
+ "teamImage",
57
+ "teamName",
58
+ "userImage",
59
+ "username"
60
+ ]
61
+ },
62
+ {
63
+ id: "order-receipt",
64
+ channel: "email",
65
+ category: "transactional",
66
+ name: "Order receipt",
67
+ description: "Itemized order receipt with product thumbnails, totals, payment summary and shipping address.",
68
+ variables: [
69
+ "customerName",
70
+ "discount",
71
+ "items",
72
+ "orderDate",
73
+ "orderNumber",
74
+ "orderUrl",
75
+ "paymentBrand",
76
+ "paymentLast4",
77
+ "shipping",
78
+ "shippingAddress",
79
+ "subtotal",
80
+ "supportEmail",
81
+ "tax",
82
+ "total"
83
+ ]
84
+ },
10
85
  {
11
86
  id: "welcome",
12
87
  channel: "email",
@@ -1044,6 +1119,27 @@ const presetCatalog = [
1044
1119
  "unsubscribeUrl"
1045
1120
  ]
1046
1121
  },
1122
+ {
1123
+ id: "product-launch-promo",
1124
+ channel: "email",
1125
+ category: "marketing",
1126
+ name: "Product launch promotion",
1127
+ description: "Launch a collection with a hero, a four-product grid, a discount code, and one shop action.",
1128
+ variables: [
1129
+ "bestSellersUrl",
1130
+ "discountCode",
1131
+ "firstName",
1132
+ "headline",
1133
+ "newArrivalsUrl",
1134
+ "offerEnds",
1135
+ "preferencesUrl",
1136
+ "products",
1137
+ "saleUrl",
1138
+ "shopUrl",
1139
+ "subhead",
1140
+ "unsubscribeUrl"
1141
+ ]
1142
+ },
1047
1143
  {
1048
1144
  id: "onboarding-step",
1049
1145
  channel: "email",
@@ -2,7 +2,7 @@ import { EmailNode, drainEmailDiagnostics } from "./email/jsx-runtime.js";
2
2
  import { declarationValue, kebab, serializeEmailHtml } from "./email/html.js";
3
3
  import { PREHEADER_ATTRIBUTE, preheaderNode } from "./email/components.js";
4
4
  import { EmailCompileError, hasBlockingDiagnostic } from "./email/diagnostics.js";
5
- import { collectStylesheets, hasStylesheets } from "./email/stylesheets.js";
5
+ import { snapshotStylesheets } from "./email/stylesheets.js";
6
6
  import { deriveEmailText } from "./email/text.js";
7
7
  import { Predicate } from "effect";
8
8
  //#region src/email/css-values.ts
@@ -525,7 +525,14 @@ const withHeadCss = (node, css) => {
525
525
  return insert(node);
526
526
  };
527
527
  /** Render one validated input through the template's only content function. Host isolation is required for untrusted source. */
528
- const renderEmail = (template, data, options = {}) => {
528
+ const renderEmail = (template, data, options = {}) => renderEmailWith(snapshotStylesheets(), template, data, options);
529
+ /**
530
+ * A render bound to the sheets registered so far. A compiled project's wrapper
531
+ * calls this once its own stylesheet imports have run, so a later project
532
+ * loaded into the same process cannot restyle an entry that is rendered again.
533
+ */
534
+ const bindStylesheets = (stylesheet = snapshotStylesheets()) => (template, data, options = {}) => renderEmailWith(stylesheet, template, data, options);
535
+ const renderEmailWith = (stylesheet, template, data, options) => {
529
536
  if (!template.schema.validate(data)) throw new TypeError(`Invalid template input: ${JSON.stringify(template.schema.validate.errors)}`);
530
537
  drainEmailDiagnostics();
531
538
  const content = template.render(data);
@@ -543,11 +550,11 @@ const renderEmail = (template, data, options = {}) => {
543
550
  if (content.preheader !== void 0 && declared !== void 0) fail("duplicate-preheader", "Preheader is set on both the template content and <Email preheader>; keep one.");
544
551
  settle(invalid);
545
552
  const base = content.preheader === void 0 ? content.body : withPreheader(content.body, content.preheader);
546
- const styled = hasStylesheets() ? applyStylesheet(base, collectStylesheets()) : {
553
+ const styled = stylesheet === void 0 ? {
547
554
  tree: base,
548
555
  headCss: "",
549
556
  diagnostics: []
550
- };
557
+ } : applyStylesheet(base, stylesheet);
551
558
  const style = [...styled.diagnostics];
552
559
  let tree = styled.tree;
553
560
  if (styled.headCss !== "") {
@@ -580,6 +587,6 @@ const renderEmail = (template, data, options = {}) => {
580
587
  };
581
588
  };
582
589
  //#endregion
583
- export { classListOf as a, finalizeValue as c, resolveVariables as d, applyStylesheet as i, foldCalc as l, compileEmail as n, matchesSelector as o, renderEmail as r, downlevelMediaQuery as s, EMAIL_DOCTYPE as t, renderHeadCss as u };
590
+ export { applyStylesheet as a, downlevelMediaQuery as c, renderHeadCss as d, resolveVariables as f, renderEmail as i, finalizeValue as l, bindStylesheets as n, classListOf as o, compileEmail as r, matchesSelector as s, EMAIL_DOCTYPE as t, foldCalc as u };
584
591
 
585
- //# sourceMappingURL=render-Cddsy_XF.js.map
592
+ //# sourceMappingURL=render-ykQhtMs_.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@samva/markup",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Type-safe authoring and compilation primitives for Samva templates",
5
5
  "keywords": [
6
6
  "email",