@samva/markup 0.2.0 → 0.4.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/catalog-Ck1tAGwO.d.ts +356 -0
- package/dist/compiler.d.ts +7 -5
- package/dist/compiler.js +7 -6
- package/dist/{corpus-Dz5irJ9x.d.ts → corpus-U2EeALvS.d.ts} +76 -3
- package/dist/{stylesheets-oDRAnYA3.d.ts → css-ar2lU3NC.d.ts} +2 -12
- package/dist/email/components.d.ts +8 -2
- package/dist/email/components.js +8 -5
- package/dist/email/render.d.ts +8 -1
- package/dist/email/render.js +2 -2
- package/dist/email/stylesheets.d.ts +15 -2
- package/dist/email/stylesheets.js +3 -1
- package/dist/email/text.js +9 -1
- package/dist/presets/category-mapping.d.ts +1 -1
- package/dist/presets/corpus.d.ts +2 -2
- package/dist/presets/corpus.js +55 -4
- package/dist/presets/public-gallery.d.ts +123 -129
- package/dist/presets/public-gallery.js +260 -215
- package/dist/presets/public-handoff.d.ts +31 -7
- package/dist/presets/public-handoff.js +107 -35
- package/dist/presets/public-preview-artifacts.d.ts +1 -1
- package/dist/presets/public-preview-artifacts.js +6 -6
- package/dist/presets/public-preview.d.ts +11 -6
- package/dist/presets/public-preview.js +48 -359
- package/dist/presets/showcase.d.ts +2 -0
- package/dist/presets/showcase.js +627 -0
- package/dist/presets/sources.d.ts +21 -3
- package/dist/presets/sources.js +6008 -1148
- package/dist/presets.d.ts +2 -350
- package/dist/presets.js +395 -765
- package/dist/{render-Cddsy_XF.js → render-ykQhtMs_.js} +13 -6
- package/dist/showcase-C_xgl6hz.d.ts +456 -0
- package/package.json +5 -1
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
import { d as Channel } from "./ast-63I-VLQx.js";
|
|
2
|
+
import { o as TokenOverrides } from "./theme-6ApjjiBo.js";
|
|
3
|
+
//#region presets/catalog.d.ts
|
|
4
|
+
type PresetCategory = "transactional" | "digest" | "marketing" | "lifecycle";
|
|
5
|
+
interface PresetMeta {
|
|
6
|
+
/** Stable id and source filename stem (`${id}.tsx`). */
|
|
7
|
+
readonly id: string;
|
|
8
|
+
/** The source's root-tag channel; the gallery filters by it. */
|
|
9
|
+
readonly channel: Channel;
|
|
10
|
+
readonly category: PresetCategory;
|
|
11
|
+
/** Human title for the gallery card. */
|
|
12
|
+
readonly name: string;
|
|
13
|
+
/** One-line description of when to reach for this preset. */
|
|
14
|
+
readonly description: string;
|
|
15
|
+
/**
|
|
16
|
+
* Every input property declared by the template schema, sorted.
|
|
17
|
+
* A sender supplies these values when rendering the template.
|
|
18
|
+
*/
|
|
19
|
+
readonly variables: ReadonlyArray<string>;
|
|
20
|
+
}
|
|
21
|
+
declare const RECOMMENDED_THEME: TokenOverrides;
|
|
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
|
+
}, {
|
|
51
|
+
readonly id: "welcome";
|
|
52
|
+
readonly channel: "email";
|
|
53
|
+
readonly category: "transactional";
|
|
54
|
+
readonly name: "Welcome";
|
|
55
|
+
readonly description: "First email after signup, with a lead illustration and a numbered list of first steps from the input.";
|
|
56
|
+
readonly variables: readonly ["ctaUrl", "docsUrl", "firstName", "planNote", "steps", "supportEmail", "workspace"];
|
|
57
|
+
}, {
|
|
58
|
+
readonly id: "email-verification";
|
|
59
|
+
readonly channel: "email";
|
|
60
|
+
readonly category: "transactional";
|
|
61
|
+
readonly name: "Email verification";
|
|
62
|
+
readonly description: "Confirm a new email address with a one-click button, a fallback code and the request details behind it.";
|
|
63
|
+
readonly variables: readonly ["email", "expiryNotice", "firstName", "previousEmail", "requestDetails", "supportEmail", "verificationCode", "verifyUrl", "workspace"];
|
|
64
|
+
}, {
|
|
65
|
+
readonly id: "otp";
|
|
66
|
+
readonly channel: "email";
|
|
67
|
+
readonly category: "transactional";
|
|
68
|
+
readonly name: "One-time passcode";
|
|
69
|
+
readonly description: "Deliver a short-lived sign-in code as the only thing on the page, with the request details under it.";
|
|
70
|
+
readonly variables: readonly ["code", "expiryNotice", "helpUrl", "newDevice", "requestDetails", "workspace"];
|
|
71
|
+
}, {
|
|
72
|
+
readonly id: "password-reset";
|
|
73
|
+
readonly channel: "email";
|
|
74
|
+
readonly category: "transactional";
|
|
75
|
+
readonly name: "Password reset";
|
|
76
|
+
readonly description: "Send an expiring reset link with the request details, a paste-able fallback URL and an optional passkey offer.";
|
|
77
|
+
readonly variables: readonly ["expiryNotice", "firstName", "passkeyPrompt", "requestDetails", "resetUrl", "securityUrl", "supportEmail", "workspace"];
|
|
78
|
+
}, {
|
|
79
|
+
readonly id: "payment-failed";
|
|
80
|
+
readonly channel: "email";
|
|
81
|
+
readonly category: "transactional";
|
|
82
|
+
readonly name: "Payment failed";
|
|
83
|
+
readonly description: "Declined-charge notice with the amount due, the card on file, the held order and every charge attempt.";
|
|
84
|
+
readonly variables: readonly ["amountDue", "attempts", "automaticRetry", "customerName", "declineReason", "holdUntil", "items", "orderNumber", "paymentBrand", "paymentLast4", "supportEmail", "updatePaymentUrl"];
|
|
85
|
+
}, {
|
|
86
|
+
readonly id: "shipping-update";
|
|
87
|
+
readonly channel: "email";
|
|
88
|
+
readonly category: "transactional";
|
|
89
|
+
readonly name: "Shipping update";
|
|
90
|
+
readonly description: "Shipment notice with the carrier, tracking, delivery estimate, the packed items and anything still to come.";
|
|
91
|
+
readonly variables: readonly ["carrier", "customerName", "estimatedDelivery", "items", "orderNumber", "pendingItems", "shippedDate", "shippingAddress", "supportEmail", "trackingNumber", "trackingUrl"];
|
|
92
|
+
}, {
|
|
93
|
+
readonly id: "notification";
|
|
94
|
+
readonly channel: "email";
|
|
95
|
+
readonly category: "transactional";
|
|
96
|
+
readonly name: "Activity notification";
|
|
97
|
+
readonly description: "Workspace activity notification with the actor, the message quoted in full, recent activity and a deep link back.";
|
|
98
|
+
readonly variables: readonly ["actionSummary", "actorAvatar", "actorName", "attachment", "itemTitle", "itemUrl", "message", "otherActivity", "settingsUrl", "timestamp", "workspaceName"];
|
|
99
|
+
}, {
|
|
100
|
+
readonly id: "team-invite";
|
|
101
|
+
readonly channel: "email";
|
|
102
|
+
readonly category: "transactional";
|
|
103
|
+
readonly name: "Team invite";
|
|
104
|
+
readonly description: "Invite someone into a workspace with one accept action, the inviter's note and the people already there.";
|
|
105
|
+
readonly variables: readonly ["acceptUrl", "expiryNotice", "inviteeEmail", "inviterAvatarUrl", "inviterEmail", "inviterName", "personalNote", "productName", "teammates", "workspace"];
|
|
106
|
+
}, {
|
|
107
|
+
readonly id: "data-sharing-review";
|
|
108
|
+
readonly channel: "email";
|
|
109
|
+
readonly category: "transactional";
|
|
110
|
+
readonly name: "Data-sharing review";
|
|
111
|
+
readonly description: "Ask a customer to keep or remove a third-party connection, listing every permission it holds.";
|
|
112
|
+
readonly variables: readonly ["connectedServiceIconUrl", "connectedServiceName", "connectedSince", "keepConnectionUrl", "lastAccess", "recipientEmail", "referenceCode", "removeConnectionUrl", "scopes", "securityUrl", "settingsUrl", "workspace"];
|
|
113
|
+
}, {
|
|
114
|
+
readonly id: "product-digest";
|
|
115
|
+
readonly channel: "email";
|
|
116
|
+
readonly category: "digest";
|
|
117
|
+
readonly name: "Weekly digest";
|
|
118
|
+
readonly description: "A weekly reader digest: mapped stories with their desk and reading time, a most-read list, and an optional audio edition.";
|
|
119
|
+
readonly variables: readonly ["archiveUrl", "editionLabel", "mostRead", "podcast", "preferencesUrl", "readerName", "stories", "unsubscribeUrl"];
|
|
120
|
+
}, {
|
|
121
|
+
readonly id: "editorial-newsletter";
|
|
122
|
+
readonly channel: "email";
|
|
123
|
+
readonly category: "digest";
|
|
124
|
+
readonly name: "Long-form newsletter";
|
|
125
|
+
readonly description: "A long-form editorial issue: a byline, an essay that renders from a list of paragraphs, a pull quote, an optional labelled sponsor and a reading list.";
|
|
126
|
+
readonly variables: readonly ["authorAvatar", "authorName", "authorRole", "heroImage", "issueLabel", "paragraphs", "preferencesUrl", "pullQuote", "readingList", "sponsor", "standfirst", "storyUrl", "subscribeUrl", "title", "unsubscribeUrl"];
|
|
127
|
+
}, {
|
|
128
|
+
readonly id: "events-roundup";
|
|
129
|
+
readonly channel: "email";
|
|
130
|
+
readonly category: "digest";
|
|
131
|
+
readonly name: "Events roundup";
|
|
132
|
+
readonly description: "A dated events digest: an optional spotlight billing and a grid of upcoming shows with images, dates, rooms, prices and per-event tickets.";
|
|
133
|
+
readonly variables: readonly ["calendarUrl", "cityName", "events", "helpUrl", "seasonLabel", "spotlight", "unsubscribeUrl"];
|
|
134
|
+
}, {
|
|
135
|
+
readonly id: "industry-news-digest";
|
|
136
|
+
readonly channel: "email";
|
|
137
|
+
readonly category: "digest";
|
|
138
|
+
readonly name: "Industry news digest";
|
|
139
|
+
readonly description: "A dense industry brief: an agenda, a lead story with details and analysis, mapped desk stories, an optional labelled sponsor, and tool and job lists.";
|
|
140
|
+
readonly variables: readonly ["agenda", "audienceSize", "editionDate", "editionUrl", "intro", "jobs", "lead", "sponsor", "sponsorContactUrl", "stories", "tools", "unsubscribeUrl"];
|
|
141
|
+
}, {
|
|
142
|
+
readonly id: "announcement";
|
|
143
|
+
readonly channel: "email";
|
|
144
|
+
readonly category: "marketing";
|
|
145
|
+
readonly name: "Feature announcement";
|
|
146
|
+
readonly description: "Announce one change with a hero image, highlights from a list, an availability date and a single action.";
|
|
147
|
+
readonly variables: readonly ["availableFrom", "ctaUrl", "featureDescription", "featureName", "featureTagline", "firstName", "highlights", "preferencesUrl", "releaseNoteUrl", "unsubscribeUrl"];
|
|
148
|
+
}, {
|
|
149
|
+
readonly id: "event-invite";
|
|
150
|
+
readonly channel: "email";
|
|
151
|
+
readonly category: "marketing";
|
|
152
|
+
readonly name: "Event invite";
|
|
153
|
+
readonly description: "Invite members to an event with the date, the place, an agenda from a list, and one RSVP action.";
|
|
154
|
+
readonly variables: readonly ["agenda", "capacityNote", "declineUrl", "eventAddress", "eventDate", "eventDescription", "eventLocation", "eventName", "eventTagline", "eventTime", "firstName", "preferencesUrl", "rsvpUrl", "travelNote", "unsubscribeUrl"];
|
|
155
|
+
}, {
|
|
156
|
+
readonly id: "membership-promo";
|
|
157
|
+
readonly channel: "email";
|
|
158
|
+
readonly category: "marketing";
|
|
159
|
+
readonly name: "Membership promotion";
|
|
160
|
+
readonly description: "Promote a paid membership with tier cards from a list, a discount code, a deadline, and one join action.";
|
|
161
|
+
readonly variables: readonly ["compareUrl", "discountPercent", "firstName", "headline", "joinUrl", "offerEnds", "preferencesUrl", "promoCode", "savingsNote", "subhead", "tiers", "unsubscribeUrl"];
|
|
162
|
+
}, {
|
|
163
|
+
readonly id: "member-referral-offer";
|
|
164
|
+
readonly channel: "email";
|
|
165
|
+
readonly category: "marketing";
|
|
166
|
+
readonly name: "Member referral offer";
|
|
167
|
+
readonly description: "Ask a member to bring people onto their account for a limited-time reward, with the steps and the terms as lists.";
|
|
168
|
+
readonly variables: readonly ["firstName", "headline", "maxMembers", "maxReward", "offerEnds", "offerStarts", "preferencesUrl", "referralCode", "referralUrl", "reminderNote", "rewardPerMember", "spendMinimum", "steps", "subhead", "terms", "termsUrl", "unsubscribeUrl"];
|
|
169
|
+
}, {
|
|
170
|
+
readonly id: "catalog-sale-newsletter";
|
|
171
|
+
readonly channel: "email";
|
|
172
|
+
readonly category: "marketing";
|
|
173
|
+
readonly name: "Catalog sale newsletter";
|
|
174
|
+
readonly description: "Open a catalogue-wide sale with a bundle offer, a product grid from a list, a discount code, and the shop dates.";
|
|
175
|
+
readonly variables: readonly ["bundleListPrice", "bundleName", "bundleSalePrice", "bundleUrl", "dates", "discountCode", "editionLabel", "editionYear", "firstName", "headline", "intro", "items", "offerEnds", "preferencesUrl", "shopUrl", "stockNote", "unsubscribeUrl"];
|
|
176
|
+
}, {
|
|
177
|
+
readonly id: "limited-time-savings";
|
|
178
|
+
readonly channel: "email";
|
|
179
|
+
readonly category: "marketing";
|
|
180
|
+
readonly name: "Limited-time savings";
|
|
181
|
+
readonly description: "A time-boxed savings offer with the hours remaining, reasons from a list, member quotes, and one claim action.";
|
|
182
|
+
readonly variables: readonly ["claimUrl", "firstName", "headline", "hoursRemaining", "listPrice", "offerEnds", "postscript", "preferencesUrl", "promoCode", "reasons", "salePrice", "savingsAmount", "subhead", "testimonials", "timezoneUrl", "unsubscribeUrl"];
|
|
183
|
+
}, {
|
|
184
|
+
readonly id: "rewards-milestone";
|
|
185
|
+
readonly channel: "email";
|
|
186
|
+
readonly category: "marketing";
|
|
187
|
+
readonly name: "Rewards milestone";
|
|
188
|
+
readonly description: "Show a member how far through a rewards ladder they are, what the next step unlocks, and what each tier is worth.";
|
|
189
|
+
readonly variables: readonly ["bonusNote", "expiresOn", "firstName", "headline", "milestoneLabel", "nextReward", "pointsBalance", "preferencesUrl", "rewardsUrl", "steps", "stepsCompleted", "stepsTotal", "subhead", "termsUrl", "tiers", "unsubscribeUrl"];
|
|
190
|
+
}, {
|
|
191
|
+
readonly id: "travel-rewards-promo";
|
|
192
|
+
readonly channel: "email";
|
|
193
|
+
readonly category: "marketing";
|
|
194
|
+
readonly name: "Travel rewards promotion";
|
|
195
|
+
readonly description: "A travel rewards promotion with a member balance, earning tiers from a list, and partner offers.";
|
|
196
|
+
readonly variables: readonly ["accountUrl", "bookUrl", "firstName", "headline", "memberNumber", "milesBalance", "offerEnds", "partners", "preferencesUrl", "subhead", "termsUrl", "tierName", "tiers", "unsubscribeUrl"];
|
|
197
|
+
}, {
|
|
198
|
+
readonly id: "product-updates-roundup";
|
|
199
|
+
readonly channel: "email";
|
|
200
|
+
readonly category: "marketing";
|
|
201
|
+
readonly name: "Product updates roundup";
|
|
202
|
+
readonly description: "A monthly product roundup with a metrics strip, shipped updates from a list, and an optional event.";
|
|
203
|
+
readonly variables: readonly ["changelogUrl", "event", "firstName", "headline", "intro", "issueMonth", "issueNumber", "metrics", "preferencesUrl", "unsubscribeUrl", "updates"];
|
|
204
|
+
}, {
|
|
205
|
+
readonly id: "flash-getaway-offer";
|
|
206
|
+
readonly channel: "email";
|
|
207
|
+
readonly category: "marketing";
|
|
208
|
+
readonly name: "Flash getaway offer";
|
|
209
|
+
readonly description: "A flash getaway offer with an input countdown, destinations from a list, and one booking action.";
|
|
210
|
+
readonly variables: readonly ["countdown", "destinations", "exploreUrl", "firstName", "headline", "offerEnds", "offerWindow", "preferencesUrl", "subhead", "termsUrl", "unsubscribeUrl"];
|
|
211
|
+
}, {
|
|
212
|
+
readonly id: "membership-benefits-promo";
|
|
213
|
+
readonly channel: "email";
|
|
214
|
+
readonly category: "marketing";
|
|
215
|
+
readonly name: "Membership benefits promotion";
|
|
216
|
+
readonly description: "A paid-membership promotion with a price panel, benefits from a list, and one join action.";
|
|
217
|
+
readonly variables: readonly ["benefits", "billingNote", "comparePlansUrl", "firstName", "headline", "joinUrl", "preferencesUrl", "priceLabel", "renewsOn", "subhead", "supportEmail", "trialLabel", "unsubscribeUrl"];
|
|
218
|
+
}, {
|
|
219
|
+
readonly id: "weekly-deals-circular";
|
|
220
|
+
readonly channel: "email";
|
|
221
|
+
readonly category: "marketing";
|
|
222
|
+
readonly name: "Weekly deals circular";
|
|
223
|
+
readonly description: "A weekly retail circular with deals from a list, clippable coupons, and one shop action.";
|
|
224
|
+
readonly variables: readonly ["coupons", "deals", "headline", "intro", "memberPerk", "membershipUrl", "preferencesUrl", "shopUrl", "unsubscribeUrl", "validThrough", "weekLabel"];
|
|
225
|
+
}, {
|
|
226
|
+
readonly id: "seasonal-sale-flyer";
|
|
227
|
+
readonly channel: "email";
|
|
228
|
+
readonly category: "marketing";
|
|
229
|
+
readonly name: "Seasonal sale flyer";
|
|
230
|
+
readonly description: "A seasonal sale flyer with tiered promo codes, a category grid, and an optional gift-card offer.";
|
|
231
|
+
readonly variables: readonly ["categories", "giftCard", "headline", "intro", "offerWindow", "preferencesUrl", "promoTiers", "seasonLabel", "shopUrl", "subhead", "termsUrl", "unsubscribeUrl"];
|
|
232
|
+
}, {
|
|
233
|
+
readonly id: "feature-release-roundup";
|
|
234
|
+
readonly channel: "email";
|
|
235
|
+
readonly category: "marketing";
|
|
236
|
+
readonly name: "Feature release roundup";
|
|
237
|
+
readonly description: "A feature release roundup with image-left rows from a list, release badges, and docs links.";
|
|
238
|
+
readonly variables: readonly ["changelogUrl", "firstName", "headline", "intro", "migrationUrl", "preferencesUrl", "releases", "sunsetOn", "unsubscribeUrl"];
|
|
239
|
+
}, {
|
|
240
|
+
readonly id: "season-clearance-promo";
|
|
241
|
+
readonly channel: "email";
|
|
242
|
+
readonly category: "marketing";
|
|
243
|
+
readonly name: "Season clearance promotion";
|
|
244
|
+
readonly description: "A last-chance clearance promotion with marked-down highlights three a row and one shop action.";
|
|
245
|
+
readonly variables: readonly ["deadlinePhrase", "firstName", "headline", "highlights", "intro", "newArrivalsUrl", "preferencesUrl", "remainingNote", "shopUrl", "unsubscribeUrl"];
|
|
246
|
+
}, {
|
|
247
|
+
readonly id: "product-launch-promo";
|
|
248
|
+
readonly channel: "email";
|
|
249
|
+
readonly category: "marketing";
|
|
250
|
+
readonly name: "Product launch promotion";
|
|
251
|
+
readonly description: "Launch a collection with a hero, a four-product grid, a discount code, and one shop action.";
|
|
252
|
+
readonly variables: readonly ["bestSellersUrl", "discountCode", "firstName", "headline", "newArrivalsUrl", "offerEnds", "preferencesUrl", "products", "saleUrl", "shopUrl", "subhead", "unsubscribeUrl"];
|
|
253
|
+
}, {
|
|
254
|
+
readonly id: "onboarding-step";
|
|
255
|
+
readonly channel: "email";
|
|
256
|
+
readonly category: "lifecycle";
|
|
257
|
+
readonly name: "Onboarding step";
|
|
258
|
+
readonly description: "One step of an onboarding sequence, with the whole setup list, its progress, and a single next action.";
|
|
259
|
+
readonly variables: readonly ["actionUrl", "docsUrl", "firstName", "stepBody", "stepNumber", "stepTitle", "steps", "supportEmail", "tip", "workspace"];
|
|
260
|
+
}, {
|
|
261
|
+
readonly id: "trial-ending";
|
|
262
|
+
readonly channel: "email";
|
|
263
|
+
readonly category: "lifecycle";
|
|
264
|
+
readonly name: "Trial ending";
|
|
265
|
+
readonly description: "Warn a trial user their access is ending, with what the trial produced, the plan that keeps it, and an optional offer.";
|
|
266
|
+
readonly variables: readonly ["contactUrl", "daysLeft", "firstName", "highlights", "keeps", "offer", "plan", "trialEndDate", "upgradeUrl", "workspace"];
|
|
267
|
+
}, {
|
|
268
|
+
readonly id: "win-back";
|
|
269
|
+
readonly channel: "email";
|
|
270
|
+
readonly category: "lifecycle";
|
|
271
|
+
readonly name: "Win-back";
|
|
272
|
+
readonly description: "Re-engage a lapsed user with an illustrated list of what shipped while they were away, and an optional return offer.";
|
|
273
|
+
readonly variables: readonly ["firstName", "lastActive", "offer", "preferencesUrl", "returnUrl", "unsubscribeUrl", "updates", "workspace"];
|
|
274
|
+
}, {
|
|
275
|
+
readonly id: "feedback-request";
|
|
276
|
+
readonly channel: "email";
|
|
277
|
+
readonly category: "lifecycle";
|
|
278
|
+
readonly name: "Feedback request";
|
|
279
|
+
readonly description: "Ask an active user one question with clickable answers, a short survey, and a named sender who reads the replies.";
|
|
280
|
+
readonly variables: readonly ["firstName", "incentive", "options", "question", "sender", "surveyUrl", "tenure", "workspace"];
|
|
281
|
+
}, {
|
|
282
|
+
readonly id: "product-onboarding-tour";
|
|
283
|
+
readonly channel: "email";
|
|
284
|
+
readonly category: "lifecycle";
|
|
285
|
+
readonly name: "Product onboarding tour";
|
|
286
|
+
readonly description: "Walk a new user through the features worth turning on first, each with a still, its own points and a link, followed by a reading list.";
|
|
287
|
+
readonly variables: readonly ["features", "firstName", "helpCenterUrl", "intro", "mobile", "preferencesUrl", "reads", "unsubscribeUrl"];
|
|
288
|
+
}, {
|
|
289
|
+
readonly id: "setup-checklist";
|
|
290
|
+
readonly channel: "email";
|
|
291
|
+
readonly category: "lifecycle";
|
|
292
|
+
readonly name: "Setup checklist";
|
|
293
|
+
readonly description: "Welcome a new customer with the setup steps that remain, each marked done or outstanding, and one link back into the flow.";
|
|
294
|
+
readonly variables: readonly ["continueUrl", "firstName", "helpUrl", "note", "steps", "unsubscribeUrl", "welcome", "workspace"];
|
|
295
|
+
}, {
|
|
296
|
+
readonly id: "sms-otp";
|
|
297
|
+
readonly channel: "sms";
|
|
298
|
+
readonly category: "transactional";
|
|
299
|
+
readonly name: "One-time passcode (SMS)";
|
|
300
|
+
readonly description: "Deliver a short-lived sign-in or 2FA code in a single GSM-7 segment.";
|
|
301
|
+
readonly variables: readonly ["code", "expiryMinutes", "workspace"];
|
|
302
|
+
}, {
|
|
303
|
+
readonly id: "sms-shipping-update";
|
|
304
|
+
readonly channel: "sms";
|
|
305
|
+
readonly category: "transactional";
|
|
306
|
+
readonly name: "Shipping update (SMS)";
|
|
307
|
+
readonly description: "Tell a customer their order shipped, with a tracking link.";
|
|
308
|
+
readonly variables: readonly ["orderNumber", "trackingUrl", "workspace"];
|
|
309
|
+
}, {
|
|
310
|
+
readonly id: "sms-appointment-reminder";
|
|
311
|
+
readonly channel: "sms";
|
|
312
|
+
readonly category: "lifecycle";
|
|
313
|
+
readonly name: "Appointment reminder (SMS)";
|
|
314
|
+
readonly description: "Remind a customer of an upcoming appointment with a reschedule path.";
|
|
315
|
+
readonly variables: readonly ["appointmentDate", "appointmentTime", "workspace"];
|
|
316
|
+
}, {
|
|
317
|
+
readonly id: "sms-flash-sale";
|
|
318
|
+
readonly channel: "sms";
|
|
319
|
+
readonly category: "marketing";
|
|
320
|
+
readonly name: "Flash sale (SMS)";
|
|
321
|
+
readonly description: "Drive a limited-time offer with a promo code and a conditional urgency line.";
|
|
322
|
+
readonly variables: readonly ["endsToday", "offerHeadline", "promoCode", "shopUrl", "workspace"];
|
|
323
|
+
}, {
|
|
324
|
+
readonly id: "whatsapp-order-update";
|
|
325
|
+
readonly channel: "whatsapp";
|
|
326
|
+
readonly category: "transactional";
|
|
327
|
+
readonly name: "Order update (WhatsApp)";
|
|
328
|
+
readonly description: "Utility template: shipping confirmation with a tracking URL button.";
|
|
329
|
+
readonly variables: readonly ["estimatedDelivery", "firstName", "orderNumber", "trackingUrl"];
|
|
330
|
+
}, {
|
|
331
|
+
readonly id: "whatsapp-appointment-reminder";
|
|
332
|
+
readonly channel: "whatsapp";
|
|
333
|
+
readonly category: "lifecycle";
|
|
334
|
+
readonly name: "Appointment reminder (WhatsApp)";
|
|
335
|
+
readonly description: "Utility template: appointment reminder with confirm/reschedule quick replies.";
|
|
336
|
+
readonly variables: readonly ["appointmentDate", "appointmentTime", "firstName", "workspace"];
|
|
337
|
+
}, {
|
|
338
|
+
readonly id: "whatsapp-flash-sale";
|
|
339
|
+
readonly channel: "whatsapp";
|
|
340
|
+
readonly category: "marketing";
|
|
341
|
+
readonly name: "Flash sale (WhatsApp)";
|
|
342
|
+
readonly description: "Marketing template: limited-time offer with a copyable promo code and a shop button.";
|
|
343
|
+
readonly variables: readonly ["endsToday", "firstName", "offerDetails", "offerHeadline", "promoCode", "shopUrl"];
|
|
344
|
+
}];
|
|
345
|
+
type PresetId = (typeof presetCatalog)[number]["id"];
|
|
346
|
+
type PresetVariable = (typeof presetCatalog)[number]["variables"][number];
|
|
347
|
+
type EmailPreset = Extract<(typeof presetCatalog)[number], {
|
|
348
|
+
channel: "email";
|
|
349
|
+
}>;
|
|
350
|
+
type EmailPresetId = EmailPreset["id"];
|
|
351
|
+
type EmailPresetVariable = EmailPreset extends (infer Preset) ? Preset extends {
|
|
352
|
+
readonly variables: ReadonlyArray<infer Variable>;
|
|
353
|
+
} ? Variable : never : never;
|
|
354
|
+
//#endregion
|
|
355
|
+
export { PresetMeta as a, presetCatalog as c, PresetId as i, EmailPresetVariable as n, PresetVariable as o, PresetCategory as r, RECOMMENDED_THEME as s, EmailPresetId as t };
|
|
356
|
+
//# sourceMappingURL=catalog-Ck1tAGwO.d.ts.map
|
package/dist/compiler.d.ts
CHANGED
|
@@ -3,8 +3,9 @@ import { a as EmailGlobalProps, c as EmailStyle, d as isUrlAttribute, i as Email
|
|
|
3
3
|
import { EmailElementSelection, EmittedPosition, INSTANCE_PATH_ATTRIBUTE, emailAuthoringTarget, emailDefinitionInstances, emailSelectionAncestry, emailSelectionIndex, emailSelectionSiblings, emailSelections } from "./email/selection.js";
|
|
4
4
|
import { EmailHtmlOutput, SerializeEmailOptions, escapeAttribute, escapeText, serializeEmailHtml } from "./email/html.js";
|
|
5
5
|
import { deriveEmailText } from "./email/text.js";
|
|
6
|
+
import { a as compileSelector, c as CompiledSelector, d as matchesSelector, i as Stylesheet, l as Compound, n as CssRule, o as parseStylesheet, r as Specificity, s as Ancestry, t as CssDeclaration, u as classListOf } from "./css-ar2lU3NC.js";
|
|
6
7
|
import { EMAIL_DOCTYPE, EmailCompileOutput, RenderedEmail, compileEmail, renderEmail } from "./email/render.js";
|
|
7
|
-
import {
|
|
8
|
+
import { collectStylesheets, hasStylesheets, registerStylesheet, resetStylesheets } from "./email/stylesheets.js";
|
|
8
9
|
import { instrumentTsxSourceForPreview } from "./tsx-source-instrumentation.js";
|
|
9
10
|
import { caniemail } from "caniemail";
|
|
10
11
|
//#region src/email/compatibility.d.ts
|
|
@@ -268,10 +269,11 @@ declare const EMAIL_ENTRY_WRAPPER = ".samva-email-entry.ts";
|
|
|
268
269
|
*/
|
|
269
270
|
declare const EMAIL_RESET_MODULE = ".samva-email-reset.ts";
|
|
270
271
|
/**
|
|
271
|
-
* The wrapper's source. It
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
272
|
+
* The wrapper's source. It exports the template beside a render bound to the
|
|
273
|
+
* sheets the project's own imports registered, so the render runs inside the
|
|
274
|
+
* project's module graph and keeps its styles when a later project loaded into
|
|
275
|
+
* the same process resets the registry. Importing the renderer from outside
|
|
276
|
+
* that graph reaches a second copy of the registry and silently renders unstyled.
|
|
275
277
|
*/
|
|
276
278
|
declare const emailEntryWrapper: (entryPoint: string, imports?: readonly string[]) => string;
|
|
277
279
|
/**
|
package/dist/compiler.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as applyStylesheet, c as downlevelMediaQuery, d as renderHeadCss, f as resolveVariables, i as renderEmail, l as finalizeValue, o as classListOf, r as compileEmail, s as matchesSelector, t as EMAIL_DOCTYPE, u as foldCalc } from "./render-ykQhtMs_.js";
|
|
2
2
|
import { EMAIL_ELEMENTS, EMAIL_GLOBAL_ATTRIBUTES, emailElement, isUrlAttribute } from "./email/elements.js";
|
|
3
3
|
import { EmailElementSelection, EmittedPosition, INSTANCE_PATH_ATTRIBUTE, emailAuthoringTarget, emailDefinitionInstances, emailSelectionAncestry, emailSelectionIndex, emailSelectionSiblings, emailSelections } from "./email/selection.js";
|
|
4
4
|
import { escapeAttribute, escapeText, serializeEmailHtml } from "./email/html.js";
|
|
@@ -1340,12 +1340,13 @@ const EMAIL_ENTRY_WRAPPER = ".samva-email-entry.ts";
|
|
|
1340
1340
|
*/
|
|
1341
1341
|
const EMAIL_RESET_MODULE = ".samva-email-reset.ts";
|
|
1342
1342
|
/**
|
|
1343
|
-
* The wrapper's source. It
|
|
1344
|
-
*
|
|
1345
|
-
*
|
|
1346
|
-
*
|
|
1343
|
+
* The wrapper's source. It exports the template beside a render bound to the
|
|
1344
|
+
* sheets the project's own imports registered, so the render runs inside the
|
|
1345
|
+
* project's module graph and keeps its styles when a later project loaded into
|
|
1346
|
+
* the same process resets the registry. Importing the renderer from outside
|
|
1347
|
+
* that graph reaches a second copy of the registry and silently renders unstyled.
|
|
1347
1348
|
*/
|
|
1348
|
-
const emailEntryWrapper = (entryPoint, imports = []) => `${[`./${EMAIL_RESET_MODULE}`, ...imports].map((specifier) => `import ${JSON.stringify(specifier)};\n`).join("")}import * as entry from ${JSON.stringify(`./${entryPoint}`)};\
|
|
1349
|
+
const emailEntryWrapper = (entryPoint, imports = []) => `${[`./${EMAIL_RESET_MODULE}`, ...imports].map((specifier) => `import ${JSON.stringify(specifier)};\n`).join("")}import * as entry from ${JSON.stringify(`./${entryPoint}`)};\nimport { bindStylesheets } from "@samva/markup/email/render";\nexport const template = entry.default;\nexport const renderEmail = bindStylesheets();\nexport { isTemplateDefinition } from "@samva/markup/template";\n`;
|
|
1349
1350
|
/**
|
|
1350
1351
|
* A host that renders more than one project in one process shares the registry
|
|
1351
1352
|
* through its module cache, so every project graph starts by clearing it.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { n as OwnedShowcaseId, t as BrandRecreationShowcaseId } from "./showcase-C_xgl6hz.js";
|
|
1
2
|
import { Result, Schema } from "effect";
|
|
2
3
|
//#region presets/corpus.d.ts
|
|
3
|
-
declare const TemplateCorpusKind: Schema.Literals<readonly ["owned-editable-sml", "inspiration-reference"]>;
|
|
4
|
+
declare const TemplateCorpusKind: Schema.Literals<readonly ["owned-editable-sml", "brand-recreation-sml", "inspiration-reference"]>;
|
|
4
5
|
type TemplateCorpusKind = typeof TemplateCorpusKind.Type;
|
|
5
6
|
declare const templateFacetOptions: {
|
|
6
7
|
readonly jobType: readonly ["account-access", "commerce", "product-communication", "lifecycle", "publishing-campaigns"];
|
|
@@ -49,6 +50,47 @@ declare const OwnedEditablePreset: Schema.TaggedStruct<"OwnedEditablePreset", {
|
|
|
49
50
|
}>;
|
|
50
51
|
}>;
|
|
51
52
|
interface OwnedEditablePreset extends Schema.Schema.Type<typeof OwnedEditablePreset> {}
|
|
53
|
+
declare const BrandRecreationPreset: Schema.TaggedStruct<"BrandRecreationPreset", {
|
|
54
|
+
readonly corpusKind: Schema.Literal<"brand-recreation-sml">;
|
|
55
|
+
readonly provenance: Schema.Struct<{
|
|
56
|
+
readonly owner: Schema.Literal<"Samva">;
|
|
57
|
+
readonly sourcePath: Schema.String;
|
|
58
|
+
readonly recordedAt: Schema.String;
|
|
59
|
+
/** The brand whose own email is recreated, named on every public surface. */
|
|
60
|
+
readonly brand: Schema.String;
|
|
61
|
+
/** What that brand's email does, in the customer's words. */
|
|
62
|
+
readonly subject: Schema.String;
|
|
63
|
+
readonly reviewedNote: Schema.String;
|
|
64
|
+
}>;
|
|
65
|
+
readonly review: Schema.Struct<{
|
|
66
|
+
readonly state: Schema.Literals<readonly ["draft", "approved", "rejected"]>;
|
|
67
|
+
readonly reviewedBy: Schema.String;
|
|
68
|
+
readonly reviewedAt: Schema.String;
|
|
69
|
+
readonly notes: Schema.String;
|
|
70
|
+
}>;
|
|
71
|
+
readonly display: Schema.Struct<{
|
|
72
|
+
readonly state: Schema.Literals<readonly ["hidden", "public"]>;
|
|
73
|
+
readonly attributionLabel: Schema.String;
|
|
74
|
+
}>;
|
|
75
|
+
readonly retention: Schema.Struct<{
|
|
76
|
+
readonly policy: Schema.Literals<readonly ["retain-until-withdrawn", "retain-while-linked"]>;
|
|
77
|
+
readonly reviewedAt: Schema.String;
|
|
78
|
+
}>;
|
|
79
|
+
readonly takedown: Schema.Struct<{
|
|
80
|
+
readonly state: Schema.Literals<readonly ["active", "removed"]>;
|
|
81
|
+
readonly contact: Schema.String;
|
|
82
|
+
readonly procedureUrl: Schema.String;
|
|
83
|
+
}>;
|
|
84
|
+
}>;
|
|
85
|
+
interface BrandRecreationPreset extends Schema.Schema.Type<typeof BrandRecreationPreset> {}
|
|
86
|
+
/** Clean-room recreations of a named brand's own email, authored as editable Samva projects. */
|
|
87
|
+
declare const brandRecreationProvenance: Record<BrandRecreationShowcaseId, BrandRecreationPreset["provenance"]>;
|
|
88
|
+
/**
|
|
89
|
+
* Owned presets authored as complete showcase projects with their own stylesheet and assets.
|
|
90
|
+
* Every other owned preset is the single module `packages/markup/presets/<id>.tsx`.
|
|
91
|
+
*/
|
|
92
|
+
declare const ownedShowcasePresetSources: Record<OwnedShowcaseId, string>;
|
|
93
|
+
declare const ownedPresetSourcePath: (id: string) => string;
|
|
52
94
|
declare const InspirationReference: Schema.TaggedStruct<"InspirationReference", {
|
|
53
95
|
readonly corpusKind: Schema.Literal<"inspiration-reference">;
|
|
54
96
|
readonly provenance: Schema.Struct<{
|
|
@@ -104,6 +146,37 @@ declare const TemplateCorpusRecord: Schema.Union<readonly [Schema.TaggedStruct<"
|
|
|
104
146
|
readonly contact: Schema.String;
|
|
105
147
|
readonly procedureUrl: Schema.String;
|
|
106
148
|
}>;
|
|
149
|
+
}>, Schema.TaggedStruct<"BrandRecreationPreset", {
|
|
150
|
+
readonly corpusKind: Schema.Literal<"brand-recreation-sml">;
|
|
151
|
+
readonly provenance: Schema.Struct<{
|
|
152
|
+
readonly owner: Schema.Literal<"Samva">;
|
|
153
|
+
readonly sourcePath: Schema.String;
|
|
154
|
+
readonly recordedAt: Schema.String;
|
|
155
|
+
/** The brand whose own email is recreated, named on every public surface. */
|
|
156
|
+
readonly brand: Schema.String;
|
|
157
|
+
/** What that brand's email does, in the customer's words. */
|
|
158
|
+
readonly subject: Schema.String;
|
|
159
|
+
readonly reviewedNote: Schema.String;
|
|
160
|
+
}>;
|
|
161
|
+
readonly review: Schema.Struct<{
|
|
162
|
+
readonly state: Schema.Literals<readonly ["draft", "approved", "rejected"]>;
|
|
163
|
+
readonly reviewedBy: Schema.String;
|
|
164
|
+
readonly reviewedAt: Schema.String;
|
|
165
|
+
readonly notes: Schema.String;
|
|
166
|
+
}>;
|
|
167
|
+
readonly display: Schema.Struct<{
|
|
168
|
+
readonly state: Schema.Literals<readonly ["hidden", "public"]>;
|
|
169
|
+
readonly attributionLabel: Schema.String;
|
|
170
|
+
}>;
|
|
171
|
+
readonly retention: Schema.Struct<{
|
|
172
|
+
readonly policy: Schema.Literals<readonly ["retain-until-withdrawn", "retain-while-linked"]>;
|
|
173
|
+
readonly reviewedAt: Schema.String;
|
|
174
|
+
}>;
|
|
175
|
+
readonly takedown: Schema.Struct<{
|
|
176
|
+
readonly state: Schema.Literals<readonly ["active", "removed"]>;
|
|
177
|
+
readonly contact: Schema.String;
|
|
178
|
+
readonly procedureUrl: Schema.String;
|
|
179
|
+
}>;
|
|
107
180
|
}>, Schema.TaggedStruct<"InspirationReference", {
|
|
108
181
|
readonly corpusKind: Schema.Literal<"inspiration-reference">;
|
|
109
182
|
readonly provenance: Schema.Struct<{
|
|
@@ -157,5 +230,5 @@ interface TemplateFacetQuery extends Schema.Schema.Type<typeof TemplateFacetQuer
|
|
|
157
230
|
/** Strict intersection: every selected value in every selected dimension must match. */
|
|
158
231
|
declare const matchesTemplateFacets: (facets: TemplateFacetSet, query: TemplateFacetQuery) => boolean;
|
|
159
232
|
//#endregion
|
|
160
|
-
export {
|
|
161
|
-
//# sourceMappingURL=corpus-
|
|
233
|
+
export { PublicCorpusRegistrationIssue as a, TemplateFacetQuery as c, matchesTemplateFacets as d, ownedPresetSourcePath as f, templateFacetOptions as h, PublicCorpusRegistration as i, TemplateFacetSet as l, registerPublicCorpusEntry as m, InspirationReference as n, TemplateCorpusKind as o, ownedShowcasePresetSources as p, OwnedEditablePreset as r, TemplateCorpusRecord as s, BrandRecreationPreset as t, brandRecreationProvenance as u };
|
|
234
|
+
//# sourceMappingURL=corpus-U2EeALvS.d.ts.map
|
|
@@ -80,15 +80,5 @@ declare const parseStylesheet: (source: string, options?: {
|
|
|
80
80
|
readonly startOrder?: number;
|
|
81
81
|
}) => Stylesheet;
|
|
82
82
|
//#endregion
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
declare const registerStylesheet: (sheet: Stylesheet) => void;
|
|
86
|
-
/** Drop every registration. The render entry calls this before a render. */
|
|
87
|
-
declare const resetStylesheets: () => void;
|
|
88
|
-
/** Every registered sheet flattened into one, with order preserved across sheets. */
|
|
89
|
-
declare const collectStylesheets: () => Stylesheet;
|
|
90
|
-
/** True when a template registered no styles at all, so the render can skip the pass. */
|
|
91
|
-
declare const hasStylesheets: () => boolean;
|
|
92
|
-
//#endregion
|
|
93
|
-
export { CssDeclaration as a, Stylesheet as c, Ancestry as d, CompiledSelector as f, matchesSelector as h, resetStylesheets as i, compileSelector as l, classListOf as m, hasStylesheets as n, CssRule as o, Compound as p, registerStylesheet as r, Specificity as s, collectStylesheets as t, parseStylesheet as u };
|
|
94
|
-
//# sourceMappingURL=stylesheets-oDRAnYA3.d.ts.map
|
|
83
|
+
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 };
|
|
84
|
+
//# sourceMappingURL=css-ar2lU3NC.d.ts.map
|
|
@@ -59,9 +59,15 @@ interface ButtonProps {
|
|
|
59
59
|
/** CSS classes applied to the primitive's content element. */
|
|
60
60
|
readonly className?: string | undefined;
|
|
61
61
|
readonly href: string;
|
|
62
|
-
/**
|
|
62
|
+
/**
|
|
63
|
+
* Pixel width of the box. Classic Outlook draws the VML shape at a fixed width, so without
|
|
64
|
+
* this it is estimated from the label and `paddingX`, and the anchor sizes to its label.
|
|
65
|
+
*/
|
|
63
66
|
readonly width?: number | undefined;
|
|
67
|
+
/** Pixel height; classic Outlook's VML fallback needs it. */
|
|
64
68
|
readonly height?: number | undefined;
|
|
69
|
+
/** Horizontal padding on each side of the label when no `width` fixes the box. */
|
|
70
|
+
readonly paddingX?: number | undefined;
|
|
65
71
|
readonly backgroundColor?: string | undefined;
|
|
66
72
|
readonly color?: string | undefined;
|
|
67
73
|
readonly borderRadius?: number | undefined;
|
|
@@ -75,7 +81,7 @@ interface ButtonProps {
|
|
|
75
81
|
readonly children?: EmailChild;
|
|
76
82
|
}
|
|
77
83
|
/** A link styled as a button, with a VML fallback so classic Outlook draws the shape. */
|
|
78
|
-
declare const Button: ({ className, href, width, height, backgroundColor, color, borderRadius, borderColor, borderWidth, fontSize, fontFamily, align, style, children }: ButtonProps) => EmailNode;
|
|
84
|
+
declare const Button: ({ className, href, width, height, paddingX, backgroundColor, color, borderRadius, borderColor, borderWidth, fontSize, fontFamily, align, style, children }: ButtonProps) => EmailNode;
|
|
79
85
|
interface SpacerProps {
|
|
80
86
|
readonly height: number;
|
|
81
87
|
}
|
package/dist/email/components.js
CHANGED
|
@@ -105,23 +105,26 @@ const Column = ({ className, align, valign, width, style, children }) => jsx("td
|
|
|
105
105
|
children
|
|
106
106
|
});
|
|
107
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;
|
|
108
110
|
/** A link styled as a button, with a VML fallback so classic Outlook draws the shape. */
|
|
109
|
-
const Button = ({ className, href, width, height, backgroundColor = "#000000", color = "#ffffff", borderRadius = 0, borderColor, borderWidth = 0, fontSize = 16, fontFamily = DEFAULT_BUTTON_FONT, align = "left", style, children }) => {
|
|
111
|
+
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 }) => {
|
|
110
112
|
const label = typeof children === "string" ? children : void 0;
|
|
111
|
-
const fallback =
|
|
113
|
+
const fallback = height !== void 0 && label !== void 0;
|
|
112
114
|
if (!fallback) reportEmailDiagnostic({
|
|
113
115
|
code: "button-outlook-fallback",
|
|
114
116
|
severity: "warning",
|
|
115
|
-
message: "<Button> draws its classic Outlook shape from VML, which needs
|
|
117
|
+
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.",
|
|
116
118
|
clients: ["outlook-windows"]
|
|
117
119
|
});
|
|
118
120
|
const arcsize = height === void 0 ? 0 : Math.round(borderRadius / height * 100);
|
|
121
|
+
const fallbackWidth = width ?? Math.ceil((label?.length ?? 0) * fontSize * BOLD_GLYPH_ADVANCE) + 2 * paddingX;
|
|
119
122
|
return presentation({
|
|
120
123
|
width: "100%",
|
|
121
124
|
style: { borderCollapse: "collapse" }
|
|
122
125
|
}, jsx("td", {
|
|
123
126
|
align,
|
|
124
|
-
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:${height}px;v-text-anchor:middle;width:${
|
|
127
|
+
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:${height}px;v-text-anchor:middle;width:${fallbackWidth}px;" arcsize="${arcsize}%" ${borderColor === void 0 ? "stroke=\"false\"" : `strokecolor="${escapeAttribute(borderColor)}" strokeweight="${borderWidth}px"`} fillcolor="${escapeAttribute(backgroundColor)}"><w:anchorlock/><center style="color:${escapeAttribute(color)};font-family:${escapeAttribute(fontFamily)};font-size:${fontSize}px;font-weight:bold;">${escapeText(label)}</center></v:roundrect><![endif]-->`) : null, jsx("a", {
|
|
125
128
|
className,
|
|
126
129
|
href,
|
|
127
130
|
target: "_blank",
|
|
@@ -137,7 +140,7 @@ const Button = ({ className, href, width, height, backgroundColor = "#000000", c
|
|
|
137
140
|
lineHeight: height === void 0 ? "120%" : `${height - 2 * borderWidth}px`,
|
|
138
141
|
textAlign: "center",
|
|
139
142
|
textDecoration: "none",
|
|
140
|
-
...width === void 0 ? {} : {
|
|
143
|
+
...width === void 0 ? { padding: `0 ${paddingX}px` } : {
|
|
141
144
|
width: `${width}px`,
|
|
142
145
|
maxWidth: "100%"
|
|
143
146
|
},
|
package/dist/email/render.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { m as EmailNode } from "../elements-DtwKlFVH.js";
|
|
|
3
3
|
import { EmittedPosition } from "./selection.js";
|
|
4
4
|
import { SerializeEmailOptions } from "./html.js";
|
|
5
5
|
import { r as TemplateDefinition } from "../template-Dy5yOPyp.js";
|
|
6
|
+
import { i as Stylesheet } from "../css-ar2lU3NC.js";
|
|
6
7
|
//#region src/email/render.d.ts
|
|
7
8
|
/** Classic Outlook lays a document out correctly only under a transitional doctype. */
|
|
8
9
|
declare const EMAIL_DOCTYPE = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">";
|
|
@@ -31,6 +32,12 @@ interface RenderedEmail {
|
|
|
31
32
|
}
|
|
32
33
|
/** Render one validated input through the template's only content function. Host isolation is required for untrusted source. */
|
|
33
34
|
declare const renderEmail: <Input>(template: TemplateDefinition<Input>, data: unknown, options?: SerializeEmailOptions) => RenderedEmail;
|
|
35
|
+
/**
|
|
36
|
+
* A render bound to the sheets registered so far. A compiled project's wrapper
|
|
37
|
+
* calls this once its own stylesheet imports have run, so a later project
|
|
38
|
+
* loaded into the same process cannot restyle an entry that is rendered again.
|
|
39
|
+
*/
|
|
40
|
+
declare const bindStylesheets: (stylesheet?: Stylesheet | undefined) => typeof renderEmail;
|
|
34
41
|
//#endregion
|
|
35
|
-
export { EMAIL_DOCTYPE, EmailCompileOutput, RenderedEmail, compileEmail, renderEmail };
|
|
42
|
+
export { EMAIL_DOCTYPE, EmailCompileOutput, RenderedEmail, bindStylesheets, compileEmail, renderEmail };
|
|
36
43
|
//# sourceMappingURL=render.d.ts.map
|