@flopay/ui 0.6.1 → 0.7.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/README.md CHANGED
@@ -162,6 +162,74 @@ Colour and face come from `--annotation-ink` (brand blue) and
162
162
  floating/list switch is a `@media (min-width: 1120px)` rule sized for a ~720px
163
163
  content box — apps in a constrained layout should re-declare that one block.
164
164
 
165
+ ### 6. Transactional email
166
+
167
+ `@flopay/ui/email` renders a provider-neutral HTML string and matching plain
168
+ text. It does not send messages or configure a delivery provider.
169
+
170
+ ```tsx
171
+ import { renderTransactionalEmail } from "@flopay/ui/email";
172
+
173
+ const { html, text } = renderTransactionalEmail({
174
+ preheader: "Your FloPay payment receipt is ready",
175
+ heading: "Payment received",
176
+ body: [
177
+ "Thanks, Alex. Your payment was processed successfully.",
178
+ "Keep this receipt for your records.",
179
+ ],
180
+ action: {
181
+ label: "View receipt",
182
+ href: "https://flopay.com/receipts/FP-2048",
183
+ },
184
+ detail: {
185
+ kind: "keyValue",
186
+ rows: [
187
+ { label: "Reference", value: "FP-2048" },
188
+ { label: "Amount", value: "$48.00 USD" },
189
+ ],
190
+ },
191
+ footer: {
192
+ address: "FloPay LLC, 100 Payments Way, New York, NY",
193
+ },
194
+ });
195
+ ```
196
+
197
+ The fixed slots are the content contract: one concise preheader, one heading,
198
+ plain-text body paragraphs, an optional action, and either a code or key-value
199
+ detail. Consumers supply content rather than React children or arbitrary HTML,
200
+ so new account and payment messages reuse the same reading order and layout.
201
+ All links are real anchors, and the action URL and labelled details remain
202
+ usable in the generated plain text.
203
+
204
+ Email clients cannot use the live CSS token preset. The template therefore
205
+ mirrors the approved values as inline literals: brand `#1785e0`, text
206
+ `#0a0a0b`, border `#e5e5e8`, an `8px` radius, and an Inter-first system font
207
+ stack with Roboto/Arial fallbacks. The layout is a 600px table-based card with
208
+ 40px desktop padding and 24px narrow-screen padding. Update
209
+ `src/email/theme.ts` whenever the corresponding values in `styles/tokens.css`
210
+ change.
211
+
212
+ The default `FLOPAY_EMAIL_LOGO_URL` is the hosted approved asset at
213
+ `https://flopay.com/logo.png`. The logo is decorative (`alt=""`) because the
214
+ adjacent text brand name provides the accessible name and remains visible for
215
+ images-off clients. A service may pass an absolute HTTPS `logoUrl` when it
216
+ needs to host the same asset itself; packaged files, `data:` URLs, and
217
+ provider-specific CID references are not portable email sources.
218
+
219
+ The shared transactional footer defaults to `FloPay LLC`,
220
+ `hello@flopay.com`, Privacy, Terms, and a service-message notice. It does not
221
+ include a marketing unsubscribe. `footer` can override the company, support
222
+ label/URL, legal URLs, notice, and optional mailing address when legal or
223
+ support requirements differ.
224
+
225
+ The initial compatibility baseline is Apple Mail on macOS/iOS; Gmail web,
226
+ iOS, and Android; Outlook Windows desktop/MSO, Outlook.com, and Microsoft 365
227
+ web; and Yahoo. The markup uses layout tables and inline styles, with responsive
228
+ and dark-mode CSS as progressive enhancements. Before a release changes the
229
+ layout, verify Outlook Windows, dark mode, and images-off behavior in real
230
+ clients or an email rendering service in addition to the automated render
231
+ snapshot.
232
+
165
233
  ## Design tokens
166
234
 
167
235
  `styles/tokens.css` defines surfaces, borders, text, accent, **brand
@@ -0,0 +1,425 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/email/index.tsx
21
+ var email_exports = {};
22
+ __export(email_exports, {
23
+ FLOPAY_EMAIL_LOGO_URL: () => FLOPAY_EMAIL_LOGO_URL,
24
+ TransactionalEmail: () => TransactionalEmail,
25
+ renderTransactionalEmail: () => renderTransactionalEmail
26
+ });
27
+ module.exports = __toCommonJS(email_exports);
28
+ var import_components = require("@react-email/components");
29
+ var import_render = require("@react-email/render");
30
+ var import_server = require("react-dom/server");
31
+
32
+ // src/email/theme.ts
33
+ var emailTheme = {
34
+ colors: {
35
+ background: "#f7f7f8",
36
+ surface: "#ffffff",
37
+ muted: "#f0f0f2",
38
+ border: "#e5e5e8",
39
+ text: "#0a0a0b",
40
+ textSecondary: "#52525b",
41
+ brand: "#1785e0",
42
+ brandLight: "#4ba6ec",
43
+ accessibleLink: "#0969b3",
44
+ darkBackground: "#0a0a0b",
45
+ darkSurface: "#141416",
46
+ darkMuted: "#1c1c1f",
47
+ darkBorder: "#27272a",
48
+ darkText: "#fafafa",
49
+ darkTextSecondary: "#a1a1aa"
50
+ },
51
+ radius: "8px",
52
+ font: "Inter, -apple-system, BlinkMacSystemFont, Roboto, Arial, sans-serif",
53
+ fontMono: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
54
+ width: "600px"
55
+ };
56
+
57
+ // src/email/index.tsx
58
+ var import_jsx_runtime = require("react/jsx-runtime");
59
+ var FLOPAY_EMAIL_LOGO_URL = "https://flopay.com/logo.png";
60
+ var DEFAULT_TRANSACTIONAL_FOOTER = {
61
+ companyName: "FloPay LLC",
62
+ supportLabel: "hello@flopay.com",
63
+ supportUrl: "mailto:hello@flopay.com",
64
+ privacyUrl: "https://flopay.com/legal/privacy",
65
+ termsUrl: "https://flopay.com/legal/terms",
66
+ notice: "This is a service message about your FloPay account.",
67
+ address: ""
68
+ };
69
+ var FOOTER_TEXT_STYLE = {
70
+ color: emailTheme.colors.textSecondary,
71
+ fontSize: "13px",
72
+ lineHeight: "20px",
73
+ margin: "0 0 12px"
74
+ };
75
+ function Detail({ detail }) {
76
+ if (detail.kind === "keyValue") {
77
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
78
+ "table",
79
+ {
80
+ cellPadding: "0",
81
+ cellSpacing: "0",
82
+ className: "email-detail",
83
+ "data-key-value": "true",
84
+ style: {
85
+ backgroundColor: emailTheme.colors.background,
86
+ border: `1px solid ${emailTheme.colors.border}`,
87
+ borderRadius: emailTheme.radius,
88
+ margin: "24px 0",
89
+ width: "100%"
90
+ },
91
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: detail.rows.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { "data-key-value-row": "true", children: [
92
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
93
+ "th",
94
+ {
95
+ className: "email-muted",
96
+ scope: "row",
97
+ style: {
98
+ borderBottom: index < detail.rows.length - 1 ? `1px solid ${emailTheme.colors.border}` : void 0,
99
+ color: emailTheme.colors.textSecondary,
100
+ fontSize: "14px",
101
+ fontWeight: 600,
102
+ padding: "12px 16px",
103
+ verticalAlign: "top",
104
+ width: "36%"
105
+ },
106
+ children: [
107
+ row.label,
108
+ ":"
109
+ ]
110
+ }
111
+ ),
112
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
113
+ "td",
114
+ {
115
+ className: "email-text",
116
+ style: {
117
+ borderBottom: index < detail.rows.length - 1 ? `1px solid ${emailTheme.colors.border}` : void 0,
118
+ color: emailTheme.colors.text,
119
+ fontSize: "14px",
120
+ padding: "12px 16px",
121
+ verticalAlign: "top",
122
+ wordBreak: "break-word"
123
+ },
124
+ children: [
125
+ " ",
126
+ row.value
127
+ ]
128
+ }
129
+ )
130
+ ] }, `${index}-${row.label}`)) })
131
+ }
132
+ );
133
+ }
134
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
135
+ import_components.Section,
136
+ {
137
+ className: "email-detail",
138
+ style: {
139
+ backgroundColor: emailTheme.colors.muted,
140
+ border: `1px solid ${emailTheme.colors.border}`,
141
+ borderRadius: emailTheme.radius,
142
+ margin: "24px 0",
143
+ padding: "20px"
144
+ },
145
+ children: [
146
+ detail.caption ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
147
+ import_components.Text,
148
+ {
149
+ className: "email-muted",
150
+ style: {
151
+ color: emailTheme.colors.textSecondary,
152
+ fontSize: "13px",
153
+ fontWeight: 600,
154
+ lineHeight: "20px",
155
+ margin: "0 0 8px"
156
+ },
157
+ children: detail.caption
158
+ }
159
+ ) : null,
160
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
161
+ import_components.Text,
162
+ {
163
+ className: "email-text",
164
+ style: {
165
+ color: emailTheme.colors.text,
166
+ fontFamily: emailTheme.fontMono,
167
+ fontSize: "24px",
168
+ fontWeight: 700,
169
+ letterSpacing: "0.12em",
170
+ lineHeight: "32px",
171
+ margin: 0,
172
+ overflowWrap: "anywhere"
173
+ },
174
+ children: detail.value
175
+ }
176
+ )
177
+ ]
178
+ }
179
+ );
180
+ }
181
+ function EmailFooter({ overrides }) {
182
+ const footer = { ...DEFAULT_TRANSACTIONAL_FOOTER, ...overrides };
183
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Section, { style: { marginTop: "32px" }, children: [
184
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
185
+ import_components.Hr,
186
+ {
187
+ className: "email-divider",
188
+ style: { borderColor: emailTheme.colors.border, margin: "0 0 24px" }
189
+ }
190
+ ),
191
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Text, { className: "email-muted", style: FOOTER_TEXT_STYLE, children: footer.notice }),
192
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Text, { className: "email-muted", style: FOOTER_TEXT_STYLE, children: [
193
+ "Need help?",
194
+ " ",
195
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
196
+ import_components.Link,
197
+ {
198
+ className: "email-link",
199
+ href: footer.supportUrl,
200
+ style: { color: emailTheme.colors.accessibleLink, textDecoration: "underline" },
201
+ children: footer.supportLabel
202
+ }
203
+ )
204
+ ] }),
205
+ footer.address ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Text, { className: "email-muted", style: FOOTER_TEXT_STYLE, children: footer.address }) : null,
206
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Text, { className: "email-muted", style: { ...FOOTER_TEXT_STYLE, margin: 0 }, children: [
207
+ "\xA9 ",
208
+ (/* @__PURE__ */ new Date()).getFullYear(),
209
+ " ",
210
+ footer.companyName,
211
+ ".",
212
+ " ",
213
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
214
+ import_components.Link,
215
+ {
216
+ className: "email-link",
217
+ href: footer.privacyUrl,
218
+ style: { color: emailTheme.colors.accessibleLink, textDecoration: "underline" },
219
+ children: "Privacy"
220
+ }
221
+ ),
222
+ " ",
223
+ "\xB7",
224
+ " ",
225
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
226
+ import_components.Link,
227
+ {
228
+ className: "email-link",
229
+ href: footer.termsUrl,
230
+ style: { color: emailTheme.colors.accessibleLink, textDecoration: "underline" },
231
+ children: "Terms"
232
+ }
233
+ )
234
+ ] })
235
+ ] });
236
+ }
237
+ function Brand({ logoUrl }) {
238
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("table", { cellPadding: "0", cellSpacing: "0", role: "presentation", style: { marginBottom: "32px" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("tr", { children: [
239
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: { verticalAlign: "middle", width: "40px" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
240
+ import_components.Img,
241
+ {
242
+ alt: "",
243
+ height: "40",
244
+ src: logoUrl,
245
+ style: { borderRadius: emailTheme.radius },
246
+ width: "40"
247
+ }
248
+ ) }),
249
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { style: { paddingLeft: "12px", verticalAlign: "middle" }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
250
+ import_components.Text,
251
+ {
252
+ className: "email-text",
253
+ style: {
254
+ color: emailTheme.colors.text,
255
+ fontSize: "18px",
256
+ fontWeight: 700,
257
+ lineHeight: "24px",
258
+ margin: 0
259
+ },
260
+ children: "FloPay"
261
+ }
262
+ ) })
263
+ ] }) }) });
264
+ }
265
+ function TransactionalEmail({
266
+ preheader,
267
+ heading,
268
+ body,
269
+ action,
270
+ detail,
271
+ logoUrl = FLOPAY_EMAIL_LOGO_URL,
272
+ footer
273
+ }) {
274
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Html, { lang: "en", children: [
275
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Head, { children: [
276
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("meta", { content: "width=device-width, initial-scale=1.0", name: "viewport" }),
277
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `
278
+ :root {
279
+ color-scheme: light dark;
280
+ supported-color-schemes: light dark;
281
+ }
282
+
283
+ @media only screen and (max-width: 620px) {
284
+ .email-shell { padding: 0 !important; }
285
+ .email-card { border-left: 0 !important; border-radius: 0 !important; border-right: 0 !important; margin: 0 !important; width: 100% !important; }
286
+ .email-content { padding: 24px !important; }
287
+ }
288
+
289
+ @media (prefers-color-scheme: dark) {
290
+ .email-body { background-color: ${emailTheme.colors.darkBackground} !important; }
291
+ .email-shell { background-color: ${emailTheme.colors.darkBackground} !important; }
292
+ .email-card { background-color: ${emailTheme.colors.darkSurface} !important; border-color: ${emailTheme.colors.darkBorder} !important; }
293
+ .email-text { color: ${emailTheme.colors.darkText} !important; }
294
+ .email-muted { color: ${emailTheme.colors.darkTextSecondary} !important; }
295
+ .email-detail { background-color: ${emailTheme.colors.darkMuted} !important; border-color: ${emailTheme.colors.darkBorder} !important; }
296
+ .email-link { color: ${emailTheme.colors.brandLight} !important; }
297
+ .email-action { background-color: ${emailTheme.colors.darkText} !important; color: ${emailTheme.colors.darkBackground} !important; }
298
+ .email-divider { border-color: ${emailTheme.colors.darkBorder} !important; }
299
+ }
300
+ ` })
301
+ ] }),
302
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_components.Preview, { children: preheader }),
303
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
304
+ import_components.Body,
305
+ {
306
+ className: "email-body",
307
+ style: {
308
+ backgroundColor: emailTheme.colors.background,
309
+ margin: 0,
310
+ padding: 0
311
+ },
312
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
313
+ import_components.Section,
314
+ {
315
+ className: "email-shell",
316
+ style: {
317
+ backgroundColor: emailTheme.colors.background,
318
+ color: emailTheme.colors.text,
319
+ fontFamily: emailTheme.font,
320
+ padding: "32px 12px",
321
+ width: "100%"
322
+ },
323
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
324
+ import_components.Container,
325
+ {
326
+ className: "email-card",
327
+ style: {
328
+ backgroundColor: emailTheme.colors.surface,
329
+ border: `1px solid ${emailTheme.colors.border}`,
330
+ borderRadius: emailTheme.radius,
331
+ borderTop: `4px solid ${emailTheme.colors.brand}`,
332
+ margin: "0 auto",
333
+ maxWidth: emailTheme.width,
334
+ overflow: "hidden",
335
+ width: "100%"
336
+ },
337
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_components.Section, { className: "email-content", style: { padding: "40px" }, children: [
338
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Brand, { logoUrl }),
339
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
340
+ import_components.Heading,
341
+ {
342
+ as: "h1",
343
+ className: "email-text",
344
+ style: {
345
+ color: emailTheme.colors.text,
346
+ fontSize: "28px",
347
+ fontWeight: 700,
348
+ letterSpacing: "-0.02em",
349
+ lineHeight: "36px",
350
+ margin: "0 0 16px"
351
+ },
352
+ children: heading
353
+ }
354
+ ),
355
+ body.map((paragraph, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
356
+ import_components.Text,
357
+ {
358
+ className: "email-text",
359
+ style: {
360
+ color: emailTheme.colors.text,
361
+ fontSize: "16px",
362
+ lineHeight: "25px",
363
+ margin: "0 0 16px"
364
+ },
365
+ children: paragraph
366
+ },
367
+ `${index}-${paragraph}`
368
+ )),
369
+ detail ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Detail, { detail }) : null,
370
+ action ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
371
+ import_components.Button,
372
+ {
373
+ className: "email-action",
374
+ href: action.href,
375
+ style: {
376
+ backgroundColor: emailTheme.colors.text,
377
+ borderRadius: emailTheme.radius,
378
+ color: emailTheme.colors.surface,
379
+ fontSize: "16px",
380
+ fontWeight: 700,
381
+ lineHeight: "20px",
382
+ marginTop: "8px",
383
+ padding: "14px 24px",
384
+ textDecoration: "none"
385
+ },
386
+ children: action.label
387
+ }
388
+ ) : null,
389
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(EmailFooter, { overrides: footer })
390
+ ] })
391
+ }
392
+ )
393
+ }
394
+ )
395
+ }
396
+ )
397
+ ] });
398
+ }
399
+ function renderTransactionalEmail(props) {
400
+ const markup = (0, import_server.renderToStaticMarkup)(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TransactionalEmail, { ...props }));
401
+ const html = `<!doctype html>${markup.replace(
402
+ /<link\b(?=[^>]*\brel="preload")(?=[^>]*\bas="image")[^>]*\/?>/gi,
403
+ ""
404
+ )}`;
405
+ return {
406
+ html,
407
+ text: (0, import_render.toPlainText)(html, {
408
+ selectors: [
409
+ { selector: "h1", options: { uppercase: false } },
410
+ {
411
+ selector: 'tr[data-key-value-row="true"]',
412
+ format: "block",
413
+ options: { leadingLineBreaks: 1, trailingLineBreaks: 1 }
414
+ }
415
+ ]
416
+ })
417
+ };
418
+ }
419
+ // Annotate the CommonJS export names for ESM import in node:
420
+ 0 && (module.exports = {
421
+ FLOPAY_EMAIL_LOGO_URL,
422
+ TransactionalEmail,
423
+ renderTransactionalEmail
424
+ });
425
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/email/index.tsx","../../src/email/theme.ts"],"sourcesContent":["import {\n Body,\n Button,\n Container,\n Head,\n Heading,\n Hr,\n Html,\n Img,\n Link,\n Preview,\n Section,\n Text,\n} from '@react-email/components';\nimport { toPlainText } from '@react-email/render';\nimport { renderToStaticMarkup } from 'react-dom/server';\nimport { emailTheme } from './theme';\n\nexport const FLOPAY_EMAIL_LOGO_URL = 'https://flopay.com/logo.png';\n\nexport interface TransactionalEmailAction {\n label: string;\n href: string;\n}\n\nexport interface TransactionalCodeDetail {\n kind: 'code';\n value: string;\n caption?: string;\n}\n\nexport interface TransactionalKeyValueDetail {\n kind: 'keyValue';\n rows: { label: string; value: string }[];\n}\n\nexport type TransactionalEmailDetail = TransactionalCodeDetail | TransactionalKeyValueDetail;\n\nexport interface TransactionalFooter {\n companyName: string;\n supportLabel: string;\n supportUrl: string;\n privacyUrl: string;\n termsUrl: string;\n notice: string;\n address: string;\n}\n\nexport interface TransactionalEmailProps {\n preheader: string;\n heading: string;\n body: string[];\n action?: TransactionalEmailAction;\n detail?: TransactionalEmailDetail;\n logoUrl?: string;\n footer?: Partial<TransactionalFooter>;\n}\n\nexport interface RenderedTransactionalEmail {\n html: string;\n text: string;\n}\n\nconst DEFAULT_TRANSACTIONAL_FOOTER: TransactionalFooter = {\n companyName: 'FloPay LLC',\n supportLabel: 'hello@flopay.com',\n supportUrl: 'mailto:hello@flopay.com',\n privacyUrl: 'https://flopay.com/legal/privacy',\n termsUrl: 'https://flopay.com/legal/terms',\n notice: 'This is a service message about your FloPay account.',\n address: '',\n};\n\nconst FOOTER_TEXT_STYLE = {\n color: emailTheme.colors.textSecondary,\n fontSize: '13px',\n lineHeight: '20px',\n margin: '0 0 12px',\n} as const;\n\nfunction Detail({ detail }: { detail: TransactionalEmailDetail }) {\n if (detail.kind === 'keyValue') {\n return (\n <table\n cellPadding=\"0\"\n cellSpacing=\"0\"\n className=\"email-detail\"\n data-key-value=\"true\"\n style={{\n backgroundColor: emailTheme.colors.background,\n border: `1px solid ${emailTheme.colors.border}`,\n borderRadius: emailTheme.radius,\n margin: '24px 0',\n width: '100%',\n }}\n >\n <tbody>\n {detail.rows.map((row, index) => (\n <tr data-key-value-row=\"true\" key={`${index}-${row.label}`}>\n <th\n className=\"email-muted\"\n scope=\"row\"\n style={{\n borderBottom:\n index < detail.rows.length - 1\n ? `1px solid ${emailTheme.colors.border}`\n : undefined,\n color: emailTheme.colors.textSecondary,\n fontSize: '14px',\n fontWeight: 600,\n padding: '12px 16px',\n verticalAlign: 'top',\n width: '36%',\n }}\n >\n {row.label}:\n </th>\n <td\n className=\"email-text\"\n style={{\n borderBottom:\n index < detail.rows.length - 1\n ? `1px solid ${emailTheme.colors.border}`\n : undefined,\n color: emailTheme.colors.text,\n fontSize: '14px',\n padding: '12px 16px',\n verticalAlign: 'top',\n wordBreak: 'break-word',\n }}\n >\n {' '}\n {row.value}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n );\n }\n\n return (\n <Section\n className=\"email-detail\"\n style={{\n backgroundColor: emailTheme.colors.muted,\n border: `1px solid ${emailTheme.colors.border}`,\n borderRadius: emailTheme.radius,\n margin: '24px 0',\n padding: '20px',\n }}\n >\n {detail.caption ? (\n <Text\n className=\"email-muted\"\n style={{\n color: emailTheme.colors.textSecondary,\n fontSize: '13px',\n fontWeight: 600,\n lineHeight: '20px',\n margin: '0 0 8px',\n }}\n >\n {detail.caption}\n </Text>\n ) : null}\n <Text\n className=\"email-text\"\n style={{\n color: emailTheme.colors.text,\n fontFamily: emailTheme.fontMono,\n fontSize: '24px',\n fontWeight: 700,\n letterSpacing: '0.12em',\n lineHeight: '32px',\n margin: 0,\n overflowWrap: 'anywhere',\n }}\n >\n {detail.value}\n </Text>\n </Section>\n );\n}\n\nfunction EmailFooter({ overrides }: { overrides?: Partial<TransactionalFooter> }) {\n const footer = { ...DEFAULT_TRANSACTIONAL_FOOTER, ...overrides };\n\n return (\n <Section style={{ marginTop: '32px' }}>\n <Hr\n className=\"email-divider\"\n style={{ borderColor: emailTheme.colors.border, margin: '0 0 24px' }}\n />\n <Text className=\"email-muted\" style={FOOTER_TEXT_STYLE}>\n {footer.notice}\n </Text>\n <Text className=\"email-muted\" style={FOOTER_TEXT_STYLE}>\n Need help?{' '}\n <Link\n className=\"email-link\"\n href={footer.supportUrl}\n style={{ color: emailTheme.colors.accessibleLink, textDecoration: 'underline' }}\n >\n {footer.supportLabel}\n </Link>\n </Text>\n {footer.address ? (\n <Text className=\"email-muted\" style={FOOTER_TEXT_STYLE}>\n {footer.address}\n </Text>\n ) : null}\n <Text className=\"email-muted\" style={{ ...FOOTER_TEXT_STYLE, margin: 0 }}>\n © {new Date().getFullYear()} {footer.companyName}.{' '}\n <Link\n className=\"email-link\"\n href={footer.privacyUrl}\n style={{ color: emailTheme.colors.accessibleLink, textDecoration: 'underline' }}\n >\n Privacy\n </Link>{' '}\n ·{' '}\n <Link\n className=\"email-link\"\n href={footer.termsUrl}\n style={{ color: emailTheme.colors.accessibleLink, textDecoration: 'underline' }}\n >\n Terms\n </Link>\n </Text>\n </Section>\n );\n}\n\nfunction Brand({ logoUrl }: { logoUrl: string }) {\n return (\n <table cellPadding=\"0\" cellSpacing=\"0\" role=\"presentation\" style={{ marginBottom: '32px' }}>\n <tbody>\n <tr>\n <td style={{ verticalAlign: 'middle', width: '40px' }}>\n <Img\n alt=\"\"\n height=\"40\"\n src={logoUrl}\n style={{ borderRadius: emailTheme.radius }}\n width=\"40\"\n />\n </td>\n <td style={{ paddingLeft: '12px', verticalAlign: 'middle' }}>\n <Text\n className=\"email-text\"\n style={{\n color: emailTheme.colors.text,\n fontSize: '18px',\n fontWeight: 700,\n lineHeight: '24px',\n margin: 0,\n }}\n >\n FloPay\n </Text>\n </td>\n </tr>\n </tbody>\n </table>\n );\n}\n\nexport function TransactionalEmail({\n preheader,\n heading,\n body,\n action,\n detail,\n logoUrl = FLOPAY_EMAIL_LOGO_URL,\n footer,\n}: TransactionalEmailProps) {\n return (\n <Html lang=\"en\">\n <Head>\n <meta content=\"width=device-width, initial-scale=1.0\" name=\"viewport\" />\n <style>{`\n :root {\n color-scheme: light dark;\n supported-color-schemes: light dark;\n }\n\n @media only screen and (max-width: 620px) {\n .email-shell { padding: 0 !important; }\n .email-card { border-left: 0 !important; border-radius: 0 !important; border-right: 0 !important; margin: 0 !important; width: 100% !important; }\n .email-content { padding: 24px !important; }\n }\n\n @media (prefers-color-scheme: dark) {\n .email-body { background-color: ${emailTheme.colors.darkBackground} !important; }\n .email-shell { background-color: ${emailTheme.colors.darkBackground} !important; }\n .email-card { background-color: ${emailTheme.colors.darkSurface} !important; border-color: ${emailTheme.colors.darkBorder} !important; }\n .email-text { color: ${emailTheme.colors.darkText} !important; }\n .email-muted { color: ${emailTheme.colors.darkTextSecondary} !important; }\n .email-detail { background-color: ${emailTheme.colors.darkMuted} !important; border-color: ${emailTheme.colors.darkBorder} !important; }\n .email-link { color: ${emailTheme.colors.brandLight} !important; }\n .email-action { background-color: ${emailTheme.colors.darkText} !important; color: ${emailTheme.colors.darkBackground} !important; }\n .email-divider { border-color: ${emailTheme.colors.darkBorder} !important; }\n }\n `}</style>\n </Head>\n <Preview>{preheader}</Preview>\n <Body\n className=\"email-body\"\n style={{\n backgroundColor: emailTheme.colors.background,\n margin: 0,\n padding: 0,\n }}\n >\n <Section\n className=\"email-shell\"\n style={{\n backgroundColor: emailTheme.colors.background,\n color: emailTheme.colors.text,\n fontFamily: emailTheme.font,\n padding: '32px 12px',\n width: '100%',\n }}\n >\n <Container\n className=\"email-card\"\n style={{\n backgroundColor: emailTheme.colors.surface,\n border: `1px solid ${emailTheme.colors.border}`,\n borderRadius: emailTheme.radius,\n borderTop: `4px solid ${emailTheme.colors.brand}`,\n margin: '0 auto',\n maxWidth: emailTheme.width,\n overflow: 'hidden',\n width: '100%',\n }}\n >\n <Section className=\"email-content\" style={{ padding: '40px' }}>\n <Brand logoUrl={logoUrl} />\n <Heading\n as=\"h1\"\n className=\"email-text\"\n style={{\n color: emailTheme.colors.text,\n fontSize: '28px',\n fontWeight: 700,\n letterSpacing: '-0.02em',\n lineHeight: '36px',\n margin: '0 0 16px',\n }}\n >\n {heading}\n </Heading>\n {body.map((paragraph, index) => (\n <Text\n className=\"email-text\"\n key={`${index}-${paragraph}`}\n style={{\n color: emailTheme.colors.text,\n fontSize: '16px',\n lineHeight: '25px',\n margin: '0 0 16px',\n }}\n >\n {paragraph}\n </Text>\n ))}\n {detail ? <Detail detail={detail} /> : null}\n {action ? (\n <Button\n className=\"email-action\"\n href={action.href}\n style={{\n backgroundColor: emailTheme.colors.text,\n borderRadius: emailTheme.radius,\n color: emailTheme.colors.surface,\n fontSize: '16px',\n fontWeight: 700,\n lineHeight: '20px',\n marginTop: '8px',\n padding: '14px 24px',\n textDecoration: 'none',\n }}\n >\n {action.label}\n </Button>\n ) : null}\n <EmailFooter overrides={footer} />\n </Section>\n </Container>\n </Section>\n </Body>\n </Html>\n );\n}\n\nexport function renderTransactionalEmail(\n props: TransactionalEmailProps,\n): RenderedTransactionalEmail {\n const markup = renderToStaticMarkup(<TransactionalEmail {...props} />);\n const html = `<!doctype html>${markup.replace(\n /<link\\b(?=[^>]*\\brel=\"preload\")(?=[^>]*\\bas=\"image\")[^>]*\\/?>/gi,\n '',\n )}`;\n\n return {\n html,\n text: toPlainText(html, {\n selectors: [\n { selector: 'h1', options: { uppercase: false } },\n {\n selector: 'tr[data-key-value-row=\"true\"]',\n format: 'block',\n options: { leadingLineBreaks: 1, trailingLineBreaks: 1 },\n },\n ],\n }),\n };\n}\n","/**\n * Email clients cannot resolve the package's CSS custom properties. Keep this\n * literal palette aligned with styles/tokens.css and cover changes in the\n * rendered-output snapshot.\n */\nexport const emailTheme = {\n colors: {\n background: '#f7f7f8',\n surface: '#ffffff',\n muted: '#f0f0f2',\n border: '#e5e5e8',\n text: '#0a0a0b',\n textSecondary: '#52525b',\n brand: '#1785e0',\n brandLight: '#4ba6ec',\n accessibleLink: '#0969b3',\n darkBackground: '#0a0a0b',\n darkSurface: '#141416',\n darkMuted: '#1c1c1f',\n darkBorder: '#27272a',\n darkText: '#fafafa',\n darkTextSecondary: '#a1a1aa',\n },\n radius: '8px',\n font: 'Inter, -apple-system, BlinkMacSystemFont, Roboto, Arial, sans-serif',\n fontMono: 'ui-monospace, SFMono-Regular, Menlo, Consolas, monospace',\n width: '600px',\n} as const;\n"],"mappings":"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","names":[]}
@@ -0,0 +1,46 @@
1
+ import * as react from 'react';
2
+
3
+ declare const FLOPAY_EMAIL_LOGO_URL = "https://flopay.com/logo.png";
4
+ interface TransactionalEmailAction {
5
+ label: string;
6
+ href: string;
7
+ }
8
+ interface TransactionalCodeDetail {
9
+ kind: 'code';
10
+ value: string;
11
+ caption?: string;
12
+ }
13
+ interface TransactionalKeyValueDetail {
14
+ kind: 'keyValue';
15
+ rows: {
16
+ label: string;
17
+ value: string;
18
+ }[];
19
+ }
20
+ type TransactionalEmailDetail = TransactionalCodeDetail | TransactionalKeyValueDetail;
21
+ interface TransactionalFooter {
22
+ companyName: string;
23
+ supportLabel: string;
24
+ supportUrl: string;
25
+ privacyUrl: string;
26
+ termsUrl: string;
27
+ notice: string;
28
+ address: string;
29
+ }
30
+ interface TransactionalEmailProps {
31
+ preheader: string;
32
+ heading: string;
33
+ body: string[];
34
+ action?: TransactionalEmailAction;
35
+ detail?: TransactionalEmailDetail;
36
+ logoUrl?: string;
37
+ footer?: Partial<TransactionalFooter>;
38
+ }
39
+ interface RenderedTransactionalEmail {
40
+ html: string;
41
+ text: string;
42
+ }
43
+ declare function TransactionalEmail({ preheader, heading, body, action, detail, logoUrl, footer, }: TransactionalEmailProps): react.JSX.Element;
44
+ declare function renderTransactionalEmail(props: TransactionalEmailProps): RenderedTransactionalEmail;
45
+
46
+ export { FLOPAY_EMAIL_LOGO_URL, type RenderedTransactionalEmail, type TransactionalCodeDetail, TransactionalEmail, type TransactionalEmailAction, type TransactionalEmailDetail, type TransactionalEmailProps, type TransactionalFooter, type TransactionalKeyValueDetail, renderTransactionalEmail };
@@ -0,0 +1,46 @@
1
+ import * as react from 'react';
2
+
3
+ declare const FLOPAY_EMAIL_LOGO_URL = "https://flopay.com/logo.png";
4
+ interface TransactionalEmailAction {
5
+ label: string;
6
+ href: string;
7
+ }
8
+ interface TransactionalCodeDetail {
9
+ kind: 'code';
10
+ value: string;
11
+ caption?: string;
12
+ }
13
+ interface TransactionalKeyValueDetail {
14
+ kind: 'keyValue';
15
+ rows: {
16
+ label: string;
17
+ value: string;
18
+ }[];
19
+ }
20
+ type TransactionalEmailDetail = TransactionalCodeDetail | TransactionalKeyValueDetail;
21
+ interface TransactionalFooter {
22
+ companyName: string;
23
+ supportLabel: string;
24
+ supportUrl: string;
25
+ privacyUrl: string;
26
+ termsUrl: string;
27
+ notice: string;
28
+ address: string;
29
+ }
30
+ interface TransactionalEmailProps {
31
+ preheader: string;
32
+ heading: string;
33
+ body: string[];
34
+ action?: TransactionalEmailAction;
35
+ detail?: TransactionalEmailDetail;
36
+ logoUrl?: string;
37
+ footer?: Partial<TransactionalFooter>;
38
+ }
39
+ interface RenderedTransactionalEmail {
40
+ html: string;
41
+ text: string;
42
+ }
43
+ declare function TransactionalEmail({ preheader, heading, body, action, detail, logoUrl, footer, }: TransactionalEmailProps): react.JSX.Element;
44
+ declare function renderTransactionalEmail(props: TransactionalEmailProps): RenderedTransactionalEmail;
45
+
46
+ export { FLOPAY_EMAIL_LOGO_URL, type RenderedTransactionalEmail, type TransactionalCodeDetail, TransactionalEmail, type TransactionalEmailAction, type TransactionalEmailDetail, type TransactionalEmailProps, type TransactionalFooter, type TransactionalKeyValueDetail, renderTransactionalEmail };