@hintoric/email 0.1.2 → 0.2.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.
@@ -9,6 +9,15 @@ export interface LayoutProps {
9
9
  preview: string;
10
10
  /** Rendered under the card: why the reader got this, the sender's legal line. */
11
11
  footer?: React.ReactNode;
12
+ /**
13
+ * An unsubscribe link, rendered as the last line of the footer. Only for
14
+ * mails a reader can opt out of — marketing and updates, not security alerts.
15
+ * Without a safe http(s)/mailto `href` nothing is rendered.
16
+ */
17
+ unsubscribe?: {
18
+ href: string;
19
+ label: string;
20
+ };
12
21
  /** Forces a scheme for previews. Left out, the email follows the reader's OS where the client supports that. */
13
22
  colorScheme?: 'light' | 'dark';
14
23
  children: React.ReactNode;
@@ -18,7 +27,7 @@ export interface LayoutProps {
18
27
  * with a 20px radius and 48px padding on a `surface-1` page, the fine print
19
28
  * centred under it. In dark the page and card swap surfaces, as AuthScreen's do.
20
29
  */
21
- export declare function Layout({ lang, preview, footer, colorScheme, children }: LayoutProps): React.JSX.Element;
30
+ export declare function Layout({ lang, preview, footer, unsubscribe, colorScheme, children }: LayoutProps): React.JSX.Element;
22
31
  /**
23
32
  * The dark-mode stylesheet on its own. Layout includes it; render it
24
33
  * once yourself when email components are shown inside a normal page — a
@@ -1 +1 @@
1
- {"version":3,"file":"Layout.d.ts","sourceRoot":"","sources":["../../src/components/Layout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB,gHAAgH;IAChH,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,WAAW,qBA8BnF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,sBAEhC"}
1
+ {"version":3,"file":"Layout.d.ts","sourceRoot":"","sources":["../../src/components/Layout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAQ/B,MAAM,WAAW,WAAW;IAC1B,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,iFAAiF;IACjF,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB;;;;OAIG;IACH,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,gHAAgH;IAChH,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC/B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,WAAW,qBAyChG;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,sBAEhC"}
package/dist/index.js CHANGED
@@ -226,66 +226,25 @@ var D = [
226
226
  E()
227
227
  ].join("\n");
228
228
  //#endregion
229
- //#region src/components/Layout.tsx
230
- function O({ lang: e, preview: n, footer: o, colorScheme: s, children: l }) {
231
- let f = v.light;
232
- return /* @__PURE__ */ d(a, {
233
- lang: e,
234
- "data-color-scheme": s,
235
- children: [
236
- /* @__PURE__ */ d(i, { children: [
237
- /* @__PURE__ */ u("meta", {
238
- name: "color-scheme",
239
- content: "light dark"
240
- }),
241
- /* @__PURE__ */ u("meta", {
242
- name: "supported-color-schemes",
243
- content: "light dark"
244
- }),
245
- /* @__PURE__ */ u(k, {})
246
- ] }),
247
- /* @__PURE__ */ u(c, { children: n }),
248
- /* @__PURE__ */ d(t, {
249
- className: w.layoutCanvas,
250
- style: {
251
- margin: 0,
252
- padding: "40px 0",
253
- backgroundColor: f.surface1,
254
- fontFamily: y.body
255
- },
256
- children: [/* @__PURE__ */ u(r, {
257
- className: w.layoutCard,
258
- style: {
259
- width: "100%",
260
- maxWidth: "440px",
261
- boxSizing: "border-box",
262
- backgroundColor: f.surface,
263
- border: `1px solid ${g("light", "outlined", "neutral").borderColor}`,
264
- borderRadius: "20px"
265
- },
266
- children: /* @__PURE__ */ u("div", {
267
- className: w.layoutCardBody,
268
- style: { padding: "48px" },
269
- children: l
270
- })
271
- }), o && /* @__PURE__ */ u(r, {
272
- style: {
273
- maxWidth: "440px",
274
- padding: "24px 24px 0",
275
- textAlign: "center"
276
- },
277
- children: o
278
- })]
279
- })
280
- ]
281
- });
282
- }
283
- function k() {
284
- return /* @__PURE__ */ u("style", { dangerouslySetInnerHTML: { __html: D } });
229
+ //#region src/components/Link.tsx
230
+ function O({ href: e, color: t = "primary", underline: n = "always", style: r, children: i }) {
231
+ let a = S(e);
232
+ return a ? /* @__PURE__ */ u(s, {
233
+ href: a,
234
+ className: w.main(t),
235
+ style: {
236
+ fontFamily: y.body,
237
+ color: _("light", t),
238
+ textDecoration: n === "always" ? "underline" : "none",
239
+ wordBreak: "break-word",
240
+ ...r
241
+ },
242
+ children: i
243
+ }) : /* @__PURE__ */ u(l, { children: i });
285
244
  }
286
245
  //#endregion
287
246
  //#region src/components/Typography.tsx
288
- var A = {
247
+ var k = {
289
248
  h1: {
290
249
  fontSize: "36px",
291
250
  fontWeight: 700,
@@ -356,7 +315,7 @@ var A = {
356
315
  lineHeight: 1.5,
357
316
  ink: "inkTertiary"
358
317
  }
359
- }, j = {
318
+ }, A = {
360
319
  h1: "h1",
361
320
  h2: "h2",
362
321
  h3: "h3",
@@ -368,14 +327,14 @@ var A = {
368
327
  "body-md": "p",
369
328
  "body-sm": "p",
370
329
  "body-xs": "span"
371
- }, ee = {
330
+ }, j = {
372
331
  primary: "inkPrimary",
373
332
  secondary: "inkSecondary",
374
333
  tertiary: "inkTertiary",
375
334
  icon: "inkIcon"
376
335
  };
377
336
  function M({ level: e = "body-md", component: t, textAlign: n, textColor: r, style: i, children: a }) {
378
- let o = A[e], s = r ? ee[r] : o.ink, c = t ?? j[e];
337
+ let o = k[e], s = r ? j[r] : o.ink, c = t ?? A[e];
379
338
  return /* @__PURE__ */ u(c, {
380
339
  className: w[s],
381
340
  style: {
@@ -393,8 +352,80 @@ function M({ level: e = "body-md", component: t, textAlign: n, textColor: r, sty
393
352
  });
394
353
  }
395
354
  //#endregion
355
+ //#region src/components/Layout.tsx
356
+ function N({ lang: e, preview: n, footer: o, unsubscribe: s, colorScheme: l, children: f }) {
357
+ let p = v.light;
358
+ return /* @__PURE__ */ d(a, {
359
+ lang: e,
360
+ "data-color-scheme": l,
361
+ children: [
362
+ /* @__PURE__ */ d(i, { children: [
363
+ /* @__PURE__ */ u("meta", {
364
+ name: "color-scheme",
365
+ content: "light dark"
366
+ }),
367
+ /* @__PURE__ */ u("meta", {
368
+ name: "supported-color-schemes",
369
+ content: "light dark"
370
+ }),
371
+ /* @__PURE__ */ u(P, {})
372
+ ] }),
373
+ /* @__PURE__ */ u(c, { children: n }),
374
+ /* @__PURE__ */ d(t, {
375
+ className: w.layoutCanvas,
376
+ style: {
377
+ margin: 0,
378
+ padding: "40px 0",
379
+ backgroundColor: p.surface1,
380
+ fontFamily: y.body
381
+ },
382
+ children: [/* @__PURE__ */ u(r, {
383
+ className: w.layoutCard,
384
+ style: {
385
+ width: "100%",
386
+ maxWidth: "440px",
387
+ boxSizing: "border-box",
388
+ backgroundColor: p.surface,
389
+ border: `1px solid ${g("light", "outlined", "neutral").borderColor}`,
390
+ borderRadius: "20px"
391
+ },
392
+ children: /* @__PURE__ */ u("div", {
393
+ className: w.layoutCardBody,
394
+ style: { padding: "48px" },
395
+ children: f
396
+ })
397
+ }), (o || s) && /* @__PURE__ */ d(r, {
398
+ style: {
399
+ maxWidth: "440px",
400
+ padding: "24px 24px 0",
401
+ textAlign: "center"
402
+ },
403
+ children: [o, s && S(s.href) && /* @__PURE__ */ u(M, {
404
+ level: "body-xs",
405
+ component: "p",
406
+ textAlign: "center",
407
+ textColor: "icon",
408
+ style: {
409
+ margin: o ? "12px 0 0" : 0,
410
+ fontWeight: 400
411
+ },
412
+ children: /* @__PURE__ */ u(O, {
413
+ href: s.href,
414
+ color: "neutral",
415
+ children: s.label
416
+ })
417
+ })]
418
+ })]
419
+ })
420
+ ]
421
+ });
422
+ }
423
+ function P() {
424
+ return /* @__PURE__ */ u("style", { dangerouslySetInnerHTML: { __html: D } });
425
+ }
426
+ //#endregion
396
427
  //#region src/components/Button.tsx
397
- var N = {
428
+ var F = {
398
429
  sm: {
399
430
  minHeight: 32,
400
431
  paddingInline: 12,
@@ -414,10 +445,10 @@ var N = {
414
445
  lineHeight: 24
415
446
  }
416
447
  };
417
- function P({ href: e, variant: t = "solid", color: r = "primary", size: i = "md", pill: a = !1, fullWidth: o = !1, style: s, children: c }) {
448
+ function I({ href: e, variant: t = "solid", color: r = "primary", size: i = "md", pill: a = !1, fullWidth: o = !1, style: s, children: c }) {
418
449
  let l = S(e);
419
450
  if (!l || l.startsWith("mailto:")) return null;
420
- let d = N[i], f = g("light", t, r), p = +(t === "outlined"), m = (d.minHeight - d.lineHeight) / 2 - p;
451
+ let d = F[i], f = g("light", t, r), p = +(t === "outlined"), m = (d.minHeight - d.lineHeight) / 2 - p;
421
452
  return /* @__PURE__ */ u(n, {
422
453
  href: l,
423
454
  className: w.variant(t, r),
@@ -451,25 +482,8 @@ function P({ href: e, variant: t = "solid", color: r = "primary", size: i = "md"
451
482
  });
452
483
  }
453
484
  //#endregion
454
- //#region src/components/Link.tsx
455
- function F({ href: e, color: t = "primary", underline: n = "always", style: r, children: i }) {
456
- let a = S(e);
457
- return a ? /* @__PURE__ */ u(s, {
458
- href: a,
459
- className: w.main(t),
460
- style: {
461
- fontFamily: y.body,
462
- color: _("light", t),
463
- textDecoration: n === "always" ? "underline" : "none",
464
- wordBreak: "break-word",
465
- ...r
466
- },
467
- children: i
468
- }) : /* @__PURE__ */ u(l, { children: i });
469
- }
470
- //#endregion
471
485
  //#region src/components/Divider.tsx
472
- function I({ style: e }) {
486
+ function L({ style: e }) {
473
487
  let t = v.light;
474
488
  return /* @__PURE__ */ u("div", {
475
489
  role: "separator",
@@ -489,7 +503,7 @@ function I({ style: e }) {
489
503
  }
490
504
  //#endregion
491
505
  //#region src/components/Card.tsx
492
- function L({ variant: e = "outlined", color: t = "neutral", style: n, children: r }) {
506
+ function R({ variant: e = "outlined", color: t = "neutral", style: n, children: r }) {
493
507
  let i = g("light", e, t), a = i.backgroundColor !== void 0;
494
508
  return /* @__PURE__ */ u("table", {
495
509
  role: "presentation",
@@ -515,7 +529,7 @@ function L({ variant: e = "outlined", color: t = "neutral", style: n, children:
515
529
  }
516
530
  //#endregion
517
531
  //#region src/components/Avatar.tsx
518
- var te = {
532
+ var z = {
519
533
  sm: {
520
534
  box: 32,
521
535
  fontSize: "14px",
@@ -532,8 +546,8 @@ var te = {
532
546
  fontWeight: 600
533
547
  }
534
548
  };
535
- function R({ variant: e = "soft", color: t = "neutral", size: n = "md", src: r, alt: i = "", children: a }) {
536
- let s = te[n], c = C(r);
549
+ function B({ variant: e = "soft", color: t = "neutral", size: n = "md", src: r, alt: i = "", children: a }) {
550
+ let s = z[n], c = C(r);
537
551
  if (c) return /* @__PURE__ */ u(o, {
538
552
  src: c,
539
553
  width: s.box,
@@ -581,7 +595,7 @@ function R({ variant: e = "soft", color: t = "neutral", size: n = "md", src: r,
581
595
  }
582
596
  //#endregion
583
597
  //#region src/components/Chip.tsx
584
- var z = {
598
+ var V = {
585
599
  sm: {
586
600
  minHeight: 20,
587
601
  paddingInline: 6,
@@ -598,8 +612,8 @@ var z = {
598
612
  fontSize: 16
599
613
  }
600
614
  };
601
- function B({ variant: e = "soft", color: t = "neutral", size: n = "md", style: r, children: i }) {
602
- let a = z[n], o = g("light", e, t), s = o.backgroundColor !== void 0, c = +!!o.borderColor, l = a.fontSize * 1.5, d = (a.minHeight - l) / 2 - c;
615
+ function H({ variant: e = "soft", color: t = "neutral", size: n = "md", style: r, children: i }) {
616
+ let a = V[n], o = g("light", e, t), s = o.backgroundColor !== void 0, c = +!!o.borderColor, l = a.fontSize * 1.5, d = (a.minHeight - l) / 2 - c;
603
617
  return /* @__PURE__ */ u("span", {
604
618
  className: [w.variant(e, t), s ? "" : w.surface].filter(Boolean).join(" "),
605
619
  style: {
@@ -623,17 +637,17 @@ function B({ variant: e = "soft", color: t = "neutral", size: n = "md", style: r
623
637
  }
624
638
  //#endregion
625
639
  //#region src/components/HintoricLogo.tsx
626
- var V = {
640
+ var U = {
627
641
  light: "https://cdn.hintoric.com/assets/logo/black.png",
628
642
  dark: "https://cdn.hintoric.com/assets/logo/white.png",
629
643
  width: 104,
630
644
  height: 32
631
645
  };
632
- function H() {
646
+ function W() {
633
647
  return /* @__PURE__ */ d(l, { children: [/* @__PURE__ */ u(o, {
634
- src: V.light,
635
- width: V.width,
636
- height: V.height,
648
+ src: U.light,
649
+ width: U.width,
650
+ height: U.height,
637
651
  alt: "hintoric",
638
652
  className: w.logoLight,
639
653
  style: {
@@ -641,9 +655,9 @@ function H() {
641
655
  margin: "0 auto"
642
656
  }
643
657
  }), /* @__PURE__ */ u(o, {
644
- src: V.dark,
645
- width: V.width,
646
- height: V.height,
658
+ src: U.dark,
659
+ width: U.width,
660
+ height: U.height,
647
661
  alt: "hintoric",
648
662
  className: w.logoDark,
649
663
  style: {
@@ -654,23 +668,23 @@ function H() {
654
668
  }
655
669
  //#endregion
656
670
  //#region src/templates/SecurityActivityAlert/SecurityActivityAlertEmail.tsx
657
- function U(e) {
671
+ function G(e) {
658
672
  return {
659
673
  activity: e.activity,
660
674
  target: e.target,
661
- targetName: W(e),
675
+ targetName: K(e),
662
676
  occurredAt: e.messages.formatDateTime(e.activity.occurredAt, e.timeZone)
663
677
  };
664
678
  }
665
- function W({ target: e }) {
679
+ function K({ target: e }) {
666
680
  return e.type === "workspace" ? e.workspaceName : e.email;
667
681
  }
668
- function G(e) {
682
+ function q(e) {
669
683
  return e.split(/\s+/).map((e) => e.match(/\p{L}/u)?.[0]).filter((e) => e !== void 0).slice(0, 2).map((e) => e.toUpperCase()).join("");
670
684
  }
671
- function K(e) {
672
- let { messages: t } = e, n = U(e);
673
- return /* @__PURE__ */ u(O, {
685
+ function J(e) {
686
+ let { messages: t } = e, n = G(e);
687
+ return /* @__PURE__ */ u(N, {
674
688
  lang: t.lang,
675
689
  preview: t.preview(n),
676
690
  colorScheme: e.colorScheme,
@@ -682,16 +696,16 @@ function K(e) {
682
696
  style: { fontWeight: 400 },
683
697
  children: [t.footer(n), e.legalNotice && /* @__PURE__ */ d(l, { children: [/* @__PURE__ */ u("br", {}), e.legalNotice] })]
684
698
  }),
685
- children: /* @__PURE__ */ u(q, { ...e })
699
+ children: /* @__PURE__ */ u(Y, { ...e })
686
700
  });
687
701
  }
688
- function q(e) {
689
- let { messages: t, activityLogUrl: n } = e, r = U(e);
702
+ function Y(e) {
703
+ let { messages: t, activityLogUrl: n } = e, r = G(e);
690
704
  return /* @__PURE__ */ d(l, { children: [
691
705
  /* @__PURE__ */ d("div", {
692
706
  style: { textAlign: "center" },
693
707
  children: [
694
- /* @__PURE__ */ u(H, {}),
708
+ /* @__PURE__ */ u(W, {}),
695
709
  /* @__PURE__ */ u(M, {
696
710
  level: "h3",
697
711
  component: "h1",
@@ -701,10 +715,10 @@ function q(e) {
701
715
  },
702
716
  children: e.activity.title
703
717
  }),
704
- /* @__PURE__ */ u(R, {
718
+ /* @__PURE__ */ u(B, {
705
719
  size: "sm",
706
720
  color: "primary",
707
- children: G(r.targetName)
721
+ children: q(r.targetName)
708
722
  }),
709
723
  /* @__PURE__ */ u(M, {
710
724
  level: "title-sm",
@@ -717,7 +731,7 @@ function q(e) {
717
731
  })
718
732
  ]
719
733
  }),
720
- /* @__PURE__ */ u(I, { style: { margin: "32px 0" } }),
734
+ /* @__PURE__ */ u(L, { style: { margin: "32px 0" } }),
721
735
  /* @__PURE__ */ d(M, {
722
736
  level: "body-sm",
723
737
  style: { marginBottom: "24px" },
@@ -727,7 +741,7 @@ function q(e) {
727
741
  t.guidance(r)
728
742
  ]
729
743
  }),
730
- /* @__PURE__ */ u(P, {
744
+ /* @__PURE__ */ u(I, {
731
745
  href: e.reviewUrl,
732
746
  size: "lg",
733
747
  fullWidth: !0,
@@ -741,7 +755,7 @@ function q(e) {
741
755
  marginTop: "24px",
742
756
  fontWeight: 400
743
757
  },
744
- children: t.activityLogHint((e) => /* @__PURE__ */ u(F, {
758
+ children: t.activityLogHint((e) => /* @__PURE__ */ u(O, {
745
759
  href: n,
746
760
  underline: "none",
747
761
  children: e
@@ -749,24 +763,24 @@ function q(e) {
749
763
  })
750
764
  ] });
751
765
  }
752
- async function J(e) {
753
- let { html: t, text: n } = await f(/* @__PURE__ */ u(K, { ...e }));
766
+ async function X(e) {
767
+ let { html: t, text: n } = await f(/* @__PURE__ */ u(J, { ...e }));
754
768
  return {
755
- subject: e.messages.subject(U(e)),
769
+ subject: e.messages.subject(G(e)),
756
770
  html: t,
757
771
  text: n
758
772
  };
759
773
  }
760
774
  //#endregion
761
775
  //#region src/templates/SecurityActivityAlert/messages.tsx
762
- function Y(e) {
776
+ function Z(e) {
763
777
  return (t, n) => new Intl.DateTimeFormat(e, {
764
778
  dateStyle: "long",
765
779
  timeStyle: "short",
766
780
  timeZone: n
767
781
  }).format(t);
768
782
  }
769
- var X = {
783
+ var ee = {
770
784
  lang: "de",
771
785
  subject: ({ activity: e, targetName: t }) => `${e.title} – ${t}`,
772
786
  preview: ({ activity: e, occurredAt: t }) => `${e.actorName} · ${t}`,
@@ -779,8 +793,8 @@ var X = {
779
793
  "."
780
794
  ] }),
781
795
  footer: ({ target: e }) => e.type === "workspace" ? "Wir haben dir diese E-Mail gesendet, um dich als Administrator über wichtige Änderungen in deinem Workspace zu informieren." : "Wir haben dir diese E-Mail gesendet, um dich über wichtige Änderungen an deinem hintoric-Konto zu informieren.",
782
- formatDateTime: Y("de-DE")
783
- }, Z = {
796
+ formatDateTime: Z("de-DE")
797
+ }, te = {
784
798
  lang: "en",
785
799
  subject: ({ activity: e, targetName: t }) => `${e.title} – ${t}`,
786
800
  preview: ({ activity: e, occurredAt: t }) => `${e.actorName} · ${t}`,
@@ -793,16 +807,20 @@ var X = {
793
807
  "."
794
808
  ] }),
795
809
  footer: ({ target: e }) => e.type === "workspace" ? "We sent you this email to let you know, as an admin, about important changes in your workspace." : "We sent you this email to let you know about important changes to your hintoric account.",
796
- formatDateTime: Y("en-GB")
810
+ formatDateTime: Z("en-GB")
797
811
  };
798
812
  //#endregion
799
813
  //#region src/templates/WaitlistWelcome/WaitlistWelcomeEmail.tsx
800
814
  function Q(e) {
801
815
  let { messages: t } = e;
802
- return /* @__PURE__ */ u(O, {
816
+ return /* @__PURE__ */ u(N, {
803
817
  lang: t.lang,
804
818
  preview: t.preview,
805
819
  colorScheme: e.colorScheme,
820
+ unsubscribe: e.unsubscribeUrl && t.unsubscribe ? {
821
+ href: e.unsubscribeUrl,
822
+ label: t.unsubscribe
823
+ } : void 0,
806
824
  footer: /* @__PURE__ */ d(M, {
807
825
  level: "body-xs",
808
826
  component: "p",
@@ -818,7 +836,7 @@ function $({ messages: e, websiteUrl: t }) {
818
836
  return /* @__PURE__ */ d("div", {
819
837
  style: { textAlign: "center" },
820
838
  children: [
821
- /* @__PURE__ */ u(H, {}),
839
+ /* @__PURE__ */ u(W, {}),
822
840
  /* @__PURE__ */ u(M, {
823
841
  level: "body-xs",
824
842
  component: "p",
@@ -849,7 +867,7 @@ function $({ messages: e, websiteUrl: t }) {
849
867
  style: { marginBottom: "24px" },
850
868
  children: e.body2
851
869
  }),
852
- /* @__PURE__ */ u(P, {
870
+ /* @__PURE__ */ u(I, {
853
871
  href: t,
854
872
  size: "lg",
855
873
  fullWidth: !0,
@@ -889,7 +907,8 @@ var re = {
889
907
  body2: "Bis dahin halten wir dich auf dem Laufenden. Wenn jemand aus deinem Umfeld auch dazugehören sollte, leite diese Mail gerne weiter.",
890
908
  cta: "Zu hintoric.com",
891
909
  signoff: "— Dein Hintoric-Team",
892
- footer: "Wir haben dir diese E-Mail gesendet, weil du dich für die Hintoric-Warteliste eingetragen hast."
910
+ footer: "Wir haben dir diese E-Mail gesendet, weil du dich für die Hintoric-Warteliste eingetragen hast.",
911
+ unsubscribe: "Abmelden"
893
912
  }, ie = {
894
913
  lang: "en",
895
914
  subject: "You're on the Hintoric waitlist",
@@ -900,9 +919,10 @@ var re = {
900
919
  body2: "Until then we'll keep you posted. If someone you know should be on the list too, feel free to forward this email.",
901
920
  cta: "Go to hintoric.com",
902
921
  signoff: "— Your Hintoric team",
903
- footer: "We sent you this email because you signed up for the Hintoric waitlist."
922
+ footer: "We sent you this email because you signed up for the Hintoric waitlist.",
923
+ unsubscribe: "Unsubscribe"
904
924
  };
905
925
  //#endregion
906
- export { R as Avatar, P as Button, L as Card, B as Chip, k as ColorSchemeStyles, I as Divider, m as EMAIL_COLORS, h as EMAIL_VARIANTS, H as HintoricLogo, O as Layout, F as Link, q as SecurityActivityAlertContent, K as SecurityActivityAlertEmail, M as Typography, $ as WaitlistWelcomeContent, Q as WaitlistWelcomeEmail, y as emailFonts, p as emailPalette, b as emailRadius, v as emailSchemes, _ as mainColor, f as renderEmail, J as renderSecurityActivityAlert, ne as renderWaitlistWelcome, S as safeHref, C as safeImageSrc, X as securityActivityAlertMessagesDe, Z as securityActivityAlertMessagesEn, g as variantTokens, re as waitlistWelcomeMessagesDe, ie as waitlistWelcomeMessagesEn };
926
+ export { B as Avatar, I as Button, R as Card, H as Chip, P as ColorSchemeStyles, L as Divider, m as EMAIL_COLORS, h as EMAIL_VARIANTS, W as HintoricLogo, N as Layout, O as Link, Y as SecurityActivityAlertContent, J as SecurityActivityAlertEmail, M as Typography, $ as WaitlistWelcomeContent, Q as WaitlistWelcomeEmail, y as emailFonts, p as emailPalette, b as emailRadius, v as emailSchemes, _ as mainColor, f as renderEmail, X as renderSecurityActivityAlert, ne as renderWaitlistWelcome, S as safeHref, C as safeImageSrc, ee as securityActivityAlertMessagesDe, te as securityActivityAlertMessagesEn, g as variantTokens, re as waitlistWelcomeMessagesDe, ie as waitlistWelcomeMessagesEn };
907
927
 
908
928
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/render.ts","../src/tokens.ts","../src/safeUrl.ts","../src/styles.ts","../src/components/Layout.tsx","../src/components/Typography.tsx","../src/components/Button.tsx","../src/components/Link.tsx","../src/components/Divider.tsx","../src/components/Card.tsx","../src/components/Avatar.tsx","../src/components/Chip.tsx","../src/components/HintoricLogo.tsx","../src/templates/SecurityActivityAlert/SecurityActivityAlertEmail.tsx","../src/templates/SecurityActivityAlert/messages.tsx","../src/templates/WaitlistWelcome/WaitlistWelcomeEmail.tsx","../src/templates/WaitlistWelcome/messages.ts"],"sourcesContent":["import type * as React from 'react';\nimport { render } from '@react-email/render';\n\nexport interface RenderedEmailBody {\n html: string;\n /** The plain-text part. Multipart mails without one score worse with spam filters. */\n text: string;\n}\n\n/** Renders an email element — normally a `<Layout>` — to HTML and plain text. */\nexport async function renderEmail(element: React.ReactElement): Promise<RenderedEmailBody> {\n const [html, text] = await Promise.all([render(element), render(element, { plainText: true })]);\n return { html, text };\n}\n","/*\n * The email module's copy of theme.css, resolved to literal values.\n *\n * Email clients cannot use the component library's styling: Gmail, Outlook\n * and Apple Mail resolve neither CSS custom properties nor Tailwind classes,\n * and Gmail drops <style> blocks in some contexts. So every email component\n * paints with inline `style` values taken from here, and the dark scheme is a\n * progressive enhancement layered on top (see styles.ts).\n *\n * The raw stops are theme.css's; the per-variant mapping below is the same\n * formula theme.css spells out token by token (Joy's createLight/DarkMode\n * VariantVariables, with neutral's -700 plain/outlined override in light).\n * The parity tests in src/visual/email/*.visual.test.tsx compare every email\n * component against its web counterpart in both schemes, so a drift between\n * the two shows up as a failing computed-style assertion.\n */\n\nexport type EmailColor = 'primary' | 'neutral' | 'danger' | 'success' | 'warning';\nexport type EmailVariant = 'solid' | 'soft' | 'outlined' | 'plain';\nexport type EmailScheme = 'light' | 'dark';\n\ntype Stop = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;\n\nexport const emailPalette: Record<EmailColor, Record<Stop, string>> = {\n neutral: { 50: '#FBFCFE', 100: '#F0F4F8', 200: '#DDE7EE', 300: '#CDD7E1', 400: '#9FA6AD', 500: '#636B74', 600: '#555E68', 700: '#32383E', 800: '#171A1C', 900: '#0B0D0E' },\n primary: { 50: '#EDF5FD', 100: '#E3EFFB', 200: '#C7DFF7', 300: '#97C3F0', 400: '#4393E4', 500: '#0B6BCB', 600: '#185EA5', 700: '#12467B', 800: '#0A2744', 900: '#051423' },\n warning: { 50: '#FEFAF6', 100: '#FDF0E1', 200: '#FCE1C2', 300: '#F3C896', 400: '#EA9A3E', 500: '#9A5B13', 600: '#72430D', 700: '#492B08', 800: '#2E1B05', 900: '#1D1002' },\n danger: { 50: '#FEF6F6', 100: '#FCE4E4', 200: '#F7C5C5', 300: '#F09898', 400: '#E47474', 500: '#C41C1C', 600: '#A51818', 700: '#7D1212', 800: '#430A0A', 900: '#240505' },\n success: { 50: '#F6FEF6', 100: '#E3FBE3', 200: '#C7F7C7', 300: '#A1E8A1', 400: '#51BC51', 500: '#1F7A1F', 600: '#136C13', 700: '#0A470A', 800: '#042F04', 900: '#021D02' },\n};\n\nexport const EMAIL_COLORS: EmailColor[] = ['primary', 'neutral', 'danger', 'success', 'warning'];\nexport const EMAIL_VARIANTS: EmailVariant[] = ['solid', 'soft', 'outlined', 'plain'];\n\n/** What one variant × colour paints. `undefined` means \"leaves it to the surroundings\". */\nexport interface EmailVariantTokens {\n color: string;\n backgroundColor?: string;\n borderColor?: string;\n}\n\nexport function variantTokens(scheme: EmailScheme, variant: EmailVariant, color: EmailColor): EmailVariantTokens {\n const c = emailPalette[color];\n const dark = scheme === 'dark';\n switch (variant) {\n case 'solid':\n return { color: '#FFFFFF', backgroundColor: c[500] };\n case 'soft':\n return dark ? { color: c[200], backgroundColor: c[800] } : { color: c[700], backgroundColor: c[100] };\n case 'outlined':\n return dark\n ? { color: c[200], borderColor: c[700] }\n : { color: color === 'neutral' ? c[700] : c[500], borderColor: c[300] };\n case 'plain':\n return { color: dark ? c[300] : color === 'neutral' ? c[700] : c[500] };\n }\n}\n\n/** `--color-*-main`: step 500 in light, 400 in dark. What Link renders. */\nexport function mainColor(scheme: EmailScheme, color: EmailColor): string {\n return emailPalette[color][scheme === 'dark' ? 400 : 500];\n}\n\nexport interface EmailSchemeTokens {\n inkPrimary: string;\n inkSecondary: string;\n inkTertiary: string;\n /** `--color-ink-icon`: the faintest ink. */\n inkIcon: string;\n /** `--color-surface`: what a Sheet / Card paints under outlined and plain. */\n surface: string;\n /** `--color-surface-1`. */\n surface1: string;\n /**\n * `--color-divider`. Kept as the rgba() theme.css uses so it composites the\n * same way over any surface; Outlook's Word engine drops rgba(), which is\n * why Divider also sets a solid `dividerFallback`.\n */\n divider: string;\n /** `divider` flattened onto `surface`. */\n dividerFallback: string;\n}\n\nexport const emailSchemes: Record<EmailScheme, EmailSchemeTokens> = {\n light: {\n inkPrimary: emailPalette.neutral[800],\n inkSecondary: emailPalette.neutral[700],\n inkTertiary: emailPalette.neutral[600],\n inkIcon: emailPalette.neutral[500],\n surface: emailPalette.neutral[50],\n surface1: emailPalette.neutral[100],\n divider: 'rgba(99, 107, 116, 0.2)',\n dividerFallback: '#DCDFE2',\n },\n dark: {\n inkPrimary: emailPalette.neutral[100],\n inkSecondary: emailPalette.neutral[300],\n inkTertiary: emailPalette.neutral[400],\n inkIcon: emailPalette.neutral[400],\n surface: emailPalette.neutral[900],\n surface1: emailPalette.neutral[800],\n divider: 'rgba(159, 166, 173, 0.16)',\n dividerFallback: '#232628',\n },\n};\n\nexport const emailFonts = {\n // `--font-body`.\n body: \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif\",\n // core's `--font-heading`. Only clients with the font installed or web-font\n // support (Apple Mail) show Montserrat; the rest fall back to the body stack.\n heading: \"Montserrat, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif\",\n};\n\n/** theme.css's radius scale. */\nexport const emailRadius = { xs: '2px', sm: '6px', md: '8px', lg: '12px', xl: '16px' };\n","/*\n * Every link in an email is a link someone may click without a second look —\n * a security alert's \"review this activity\" button most of all. React escapes\n * text but not the scheme of an href, so a `javascript:` or `data:` URL that\n * reached a template through data would survive rendering intact. Only these\n * schemes are let through; anything else renders as plain, unlinked text.\n */\nconst LINK_PROTOCOLS = new Set(['https:', 'http:', 'mailto:']);\n\nexport function safeHref(href: string | undefined | null): string | undefined {\n if (!href) return undefined;\n try {\n const url = new URL(href);\n return LINK_PROTOCOLS.has(url.protocol) ? url.href : undefined;\n } catch {\n // Relative URLs are meaningless in an email: there is no base to resolve\n // them against once the message leaves the server.\n return undefined;\n }\n}\n\n/** Images additionally have to be https: mail clients block or warn on http. */\nexport function safeImageSrc(src: string | undefined | null): string | undefined {\n if (!src) return undefined;\n try {\n const url = new URL(src);\n return url.protocol === 'https:' ? url.href : undefined;\n } catch {\n return undefined;\n }\n}\n","import {\n EMAIL_COLORS,\n EMAIL_VARIANTS,\n emailSchemes,\n mainColor,\n variantTokens,\n type EmailColor,\n type EmailVariant,\n} from './tokens';\n\n/*\n * Inline styles carry the light scheme, so an email always renders correctly\n * even where <style> is stripped. Dark mode is a progressive enhancement: each\n * painted element also carries a class from here, and the stylesheet below\n * overrides it — `!important` because it has to beat the inline value.\n *\n * Two triggers, deliberately:\n * - `prefers-color-scheme: dark`, which Apple Mail, iOS Mail, Outlook for\n * Mac and Thunderbird honour. Guarded by `:not([data-color-scheme=\"light\"])`\n * so a preview forced to light stays light on a dark OS.\n * - `[data-color-scheme=\"dark\"]` on any ancestor — the same switch the\n * component library uses, so an email component rendered inside the docs\n * or a visual test follows the page's scheme.\n *\n * Gmail and Outlook.com ignore both and apply their own colour inversion,\n * which is out of any template's control.\n */\nexport const emailClass = {\n variant: (variant: EmailVariant, color: EmailColor) => `hx-${variant}-${color}`,\n main: (color: EmailColor) => `hx-main-${color}`,\n inkPrimary: 'hx-ink-1',\n inkSecondary: 'hx-ink-2',\n inkTertiary: 'hx-ink-3',\n inkIcon: 'hx-ink-icon',\n surface: 'hx-surface',\n divider: 'hx-divider',\n // Layout's AuthScreen shell: page and card swap surfaces in dark.\n layoutCanvas: 'hx-layout-canvas',\n layoutCard: 'hx-layout-card',\n // The card's inner area, which carries its padding. A div of our own rather\n // than react-email's cell: Container moves its `padding` onto an inner <td>,\n // so a rule on the card itself added to it instead of replacing it.\n layoutCardBody: 'hx-layout-card-body',\n // A logo pair: the light one shows by default, the dark one only once the\n // dark rules apply — clients without <style> support keep the light logo.\n logoLight: 'hx-logo-light',\n logoDark: 'hx-logo-dark',\n} as const;\n\nfunction darkRules(scope: string): string {\n const t = emailSchemes.dark;\n const rule = (selector: string, body: string) => `${scope} .${selector}{${body}}`;\n const rules = [\n rule(emailClass.inkPrimary, `color:${t.inkPrimary}!important;`),\n rule(emailClass.inkSecondary, `color:${t.inkSecondary}!important;`),\n rule(emailClass.inkTertiary, `color:${t.inkTertiary}!important;`),\n rule(emailClass.inkIcon, `color:${t.inkIcon}!important;`),\n rule(emailClass.surface, `background-color:${t.surface}!important;`),\n rule(emailClass.divider, `background-color:${t.divider}!important;`),\n rule(emailClass.layoutCanvas, `background-color:${t.surface}!important;`),\n // react-email's Body repeats its inline style on an inner wrapper cell\n // that carries no class, so the canvas colour has to reach it too.\n rule(`${emailClass.layoutCanvas}>table>tbody>tr>td`, `background-color:${t.surface}!important;`),\n rule(emailClass.logoLight, 'display:none!important;'),\n rule(emailClass.logoDark, 'display:inline-block!important;'),\n rule(emailClass.layoutCard,`background-color:${t.surface1}!important;border-color:${variantTokens('dark', 'outlined', 'neutral').borderColor}!important;`),\n ];\n for (const color of EMAIL_COLORS) {\n rules.push(rule(emailClass.main(color), `color:${mainColor('dark', color)}!important;`));\n for (const variant of EMAIL_VARIANTS) {\n const v = variantTokens('dark', variant, color);\n rules.push(\n rule(\n emailClass.variant(variant, color),\n [\n `color:${v.color}!important;`,\n v.backgroundColor && `background-color:${v.backgroundColor}!important;`,\n v.borderColor && `border-color:${v.borderColor}!important;`,\n ]\n .filter(Boolean)\n .join(''),\n ),\n );\n }\n }\n return rules.join('');\n}\n\n/*\n * AuthScreen's phone layout: the card stops being a card. It fills the width,\n * loses border and radius, insets its content by 24px, and the page around it\n * takes the card's colour — surface in light, surface-1 in dark. Last in the\n * sheet so it wins over the dark rules at equal specificity.\n */\nfunction phoneRules(): string {\n const canvas = (scope: string) => `${scope}.${emailClass.layoutCanvas},${scope}.${emailClass.layoutCanvas}>table>tbody>tr>td`;\n const dark = (scope: string) => `${canvas(scope)}{background-color:${emailSchemes.dark.surface1}!important;}`;\n return [\n `@media only screen and (max-width:600px){`,\n `.${emailClass.layoutCard}{max-width:100%!important;border:0!important;border-radius:0!important;}`,\n `.${emailClass.layoutCardBody}{padding:32px 24px!important;}`,\n `${canvas('')}{padding:0!important;background-color:${emailSchemes.light.surface}!important;}`,\n dark('[data-color-scheme=\"dark\"] '),\n `}`,\n `@media only screen and (max-width:600px) and (prefers-color-scheme:dark){${dark(':root:not([data-color-scheme=\"light\"]) ')}}`,\n ].join('');\n}\n\nexport const emailStylesheet = [\n // iOS turns dates and addresses into blue links that ignore the text colour.\n 'a[x-apple-data-detectors]{color:inherit!important;text-decoration:none!important;}',\n `@media (prefers-color-scheme:dark){${darkRules(':root:not([data-color-scheme=\"light\"])')}}`,\n darkRules('[data-color-scheme=\"dark\"]'),\n phoneRules(),\n].join('\\n');\n","import * as React from 'react';\nimport { Body, Container, Head, Html, Preview } from 'react-email';\nimport { emailClass, emailStylesheet } from '../styles';\nimport { emailFonts, emailSchemes, variantTokens } from '../tokens';\n\nexport interface LayoutProps {\n /** The `lang` of the message — screen readers pick their voice from it. */\n lang: string;\n /**\n * The line inbox lists show after the subject. Without one, clients take the\n * first text they find, which is usually the brand name.\n */\n preview: string;\n /** Rendered under the card: why the reader got this, the sender's legal line. */\n footer?: React.ReactNode;\n /** Forces a scheme for previews. Left out, the email follows the reader's OS where the client supports that. */\n colorScheme?: 'light' | 'dark';\n children: React.ReactNode;\n}\n\n/**\n * The whole document, laid out like core's AuthScreen: a 440px outlined card\n * with a 20px radius and 48px padding on a `surface-1` page, the fine print\n * centred under it. In dark the page and card swap surfaces, as AuthScreen's do.\n */\nexport function Layout({ lang, preview, footer, colorScheme, children }: LayoutProps) {\n const t = emailSchemes.light;\n return (\n <Html lang={lang} data-color-scheme={colorScheme}>\n <Head>\n <meta name=\"color-scheme\" content=\"light dark\" />\n <meta name=\"supported-color-schemes\" content=\"light dark\" />\n <ColorSchemeStyles />\n </Head>\n <Preview>{preview}</Preview>\n <Body className={emailClass.layoutCanvas} style={{ margin: 0, padding: '40px 0', backgroundColor: t.surface1, fontFamily: emailFonts.body }}>\n <Container\n className={emailClass.layoutCard}\n style={{\n width: '100%',\n maxWidth: '440px',\n boxSizing: 'border-box',\n backgroundColor: t.surface,\n border: `1px solid ${variantTokens('light', 'outlined', 'neutral').borderColor}`,\n borderRadius: '20px',\n }}\n >\n <div className={emailClass.layoutCardBody} style={{ padding: '48px' }}>\n {children}\n </div>\n </Container>\n {footer && <Container style={{ maxWidth: '440px', padding: '24px 24px 0', textAlign: 'center' }}>{footer}</Container>}\n </Body>\n </Html>\n );\n}\n\n/**\n * The dark-mode stylesheet on its own. Layout includes it; render it\n * once yourself when email components are shown inside a normal page — a\n * preview, the docs — so they follow that page's `data-color-scheme`.\n */\nexport function ColorSchemeStyles() {\n return <style dangerouslySetInnerHTML={{ __html: emailStylesheet }} />;\n}\n","import * as React from 'react';\nimport { emailClass } from '../styles';\nimport { emailFonts, emailSchemes } from '../tokens';\n\nexport type TypographyLevel =\n | 'h1'\n | 'h2'\n | 'h3'\n | 'h4'\n | 'title-lg'\n | 'title-md'\n | 'title-sm'\n | 'body-lg'\n | 'body-md'\n | 'body-sm'\n | 'body-xs';\n\ntype Ink = 'inkPrimary' | 'inkSecondary' | 'inkTertiary' | 'inkIcon';\n\n/*\n * Typography's typographyVariants.ts, resolved: Tailwind's text-4xl…text-xs\n * in px, its font-bold/semibold/medium as numbers, `tracking-tight` as\n * -0.025em, and the same unitless line-heights (1.33334, 1.5, 1.42858), so the\n * computed line box matches the web component to the sub-pixel.\n */\nconst LEVELS: Record<TypographyLevel, { fontSize: string; fontWeight: number; lineHeight: number; letterSpacing?: string; ink: Ink }> = {\n h1: { fontSize: '36px', fontWeight: 700, lineHeight: 1.33334, letterSpacing: '-0.025em', ink: 'inkPrimary' },\n h2: { fontSize: '30px', fontWeight: 700, lineHeight: 1.33334, letterSpacing: '-0.025em', ink: 'inkPrimary' },\n h3: { fontSize: '24px', fontWeight: 600, lineHeight: 1.33334, letterSpacing: '-0.025em', ink: 'inkPrimary' },\n h4: { fontSize: '20px', fontWeight: 600, lineHeight: 1.5, letterSpacing: '-0.025em', ink: 'inkPrimary' },\n 'title-lg': { fontSize: '18px', fontWeight: 600, lineHeight: 1.33334, ink: 'inkPrimary' },\n 'title-md': { fontSize: '16px', fontWeight: 500, lineHeight: 1.5, ink: 'inkPrimary' },\n 'title-sm': { fontSize: '14px', fontWeight: 500, lineHeight: 1.42858, ink: 'inkPrimary' },\n 'body-lg': { fontSize: '18px', fontWeight: 400, lineHeight: 1.5, ink: 'inkSecondary' },\n 'body-md': { fontSize: '16px', fontWeight: 400, lineHeight: 1.5, ink: 'inkSecondary' },\n 'body-sm': { fontSize: '14px', fontWeight: 400, lineHeight: 1.5, ink: 'inkTertiary' },\n 'body-xs': { fontSize: '12px', fontWeight: 500, lineHeight: 1.5, ink: 'inkTertiary' },\n};\n\nconst DEFAULT_TAG: Record<TypographyLevel, 'h1' | 'h2' | 'h3' | 'h4' | 'p' | 'span'> = {\n h1: 'h1',\n h2: 'h2',\n h3: 'h3',\n h4: 'h4',\n 'title-lg': 'p',\n 'title-md': 'p',\n 'title-sm': 'p',\n 'body-lg': 'p',\n 'body-md': 'p',\n 'body-sm': 'p',\n 'body-xs': 'span',\n};\n\nexport interface TypographyProps {\n level?: TypographyLevel;\n /** The element to render. Defaults to the same tag the web Typography picks for the level. */\n component?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span' | 'div';\n textAlign?: 'left' | 'center' | 'right';\n /**\n * Overrides the level's ink, like Joy's `textColor=\"text.tertiary\"`.\n * `icon` is the theme's faintest ink — for fine print that should recede.\n */\n textColor?: 'primary' | 'secondary' | 'tertiary' | 'icon';\n /** Margin, spacing and the like — there is no Stack in email, so spacing lives on the text. */\n style?: React.CSSProperties;\n children?: React.ReactNode;\n}\n\nconst TEXT_COLOR: Record<NonNullable<TypographyProps['textColor']>, Ink> = {\n primary: 'inkPrimary',\n secondary: 'inkSecondary',\n tertiary: 'inkTertiary',\n icon: 'inkIcon',\n};\n\n/** Typography for email: the same levels, sizes and ink colours, as inline styles. */\nexport function Typography({ level = 'body-md', component, textAlign, textColor, style, children }: TypographyProps) {\n const spec = LEVELS[level];\n const ink = textColor ? TEXT_COLOR[textColor] : spec.ink;\n const Tag = component ?? DEFAULT_TAG[level];\n return (\n <Tag\n className={emailClass[ink]}\n style={{\n margin: 0,\n fontFamily: emailFonts.body,\n fontSize: spec.fontSize,\n fontWeight: spec.fontWeight,\n lineHeight: spec.lineHeight,\n letterSpacing: spec.letterSpacing,\n color: emailSchemes.light[ink],\n textAlign,\n ...style,\n }}\n >\n {children}\n </Tag>\n );\n}\n","import * as React from 'react';\nimport { Button as ReactEmailButton } from 'react-email';\nimport { emailClass } from '../styles';\nimport { emailFonts, emailRadius, variantTokens, type EmailColor, type EmailVariant } from '../tokens';\nimport { safeHref } from '../safeUrl';\n\n/*\n * buttonVariants.ts, resolved. The web Button gets its height from\n * `min-h-8/9/11` and centres the label with flexbox; email has neither, so the\n * same box is built from line-height plus vertical padding:\n * (min-height − line-height) / 2, less the 1px border for outlined.\n */\nconst SIZES = {\n sm: { minHeight: 32, paddingInline: 12, fontSize: 14, lineHeight: 21 },\n md: { minHeight: 36, paddingInline: 16, fontSize: 14, lineHeight: 21 },\n lg: { minHeight: 44, paddingInline: 24, fontSize: 16, lineHeight: 24 },\n} as const;\n\nexport interface ButtonProps {\n /** Rendered only for http(s) URLs; anything else renders nothing — a button nobody can follow is worse than none. */\n href: string;\n variant?: EmailVariant;\n color?: EmailColor;\n size?: keyof typeof SIZES;\n /** `rounded-full`, as on the web Button. */\n pill?: boolean;\n /** Stretches to the container — the usual call-to-action layout in a narrow email. */\n fullWidth?: boolean;\n style?: React.CSSProperties;\n children: React.ReactNode;\n}\n\n/** Button for email: a link styled as the web Button, built on react-email's Outlook-safe Button. */\nexport function Button({ href, variant = 'solid', color = 'primary', size = 'md', pill = false, fullWidth = false, style, children }: ButtonProps) {\n const safe = safeHref(href);\n if (!safe || safe.startsWith('mailto:')) return null;\n const s = SIZES[size];\n const v = variantTokens('light', variant, color);\n const border = variant === 'outlined' ? 1 : 0;\n const paddingBlock = (s.minHeight - s.lineHeight) / 2 - border;\n return (\n <ReactEmailButton\n href={safe}\n className={emailClass.variant(variant, color)}\n style={{\n display: fullWidth ? 'block' : 'inline-block',\n boxSizing: 'border-box',\n width: fullWidth ? '100%' : undefined,\n textAlign: 'center',\n paddingTop: `${paddingBlock}px`,\n paddingBottom: `${paddingBlock}px`,\n paddingLeft: `${s.paddingInline}px`,\n paddingRight: `${s.paddingInline}px`,\n fontFamily: emailFonts.body,\n fontSize: `${s.fontSize}px`,\n fontWeight: 600,\n lineHeight: `${s.lineHeight}px`,\n textDecoration: 'none',\n borderRadius: pill ? '9999px' : emailRadius.sm,\n color: v.color,\n backgroundColor: v.backgroundColor ?? 'transparent',\n border: v.borderColor ? `1px solid ${v.borderColor}` : undefined,\n ...style,\n }}\n >\n {/* react-email wraps the label in its own inline-block span at\n line-height 120%. In the modes mail is actually shown in — the\n limited-quirks mode its XHTML doctype yields, or full quirks where a\n webmail drops the doctype — the link's own line-height no longer\n props the line up, so the button shrank to 120% of the font plus\n padding: 4–5px short at every size. This span carries the full\n line-height itself, so the box no longer depends on the mode. */}\n <span style={{ display: 'inline-block', lineHeight: `${s.lineHeight}px` }}>{children}</span>\n </ReactEmailButton>\n );\n}\n","import * as React from 'react';\nimport { Link as ReactEmailLink } from 'react-email';\nimport { emailClass } from '../styles';\nimport { emailFonts, mainColor, type EmailColor } from '../tokens';\nimport { safeHref } from '../safeUrl';\n\nexport interface LinkProps {\n /** Rendered only for http(s) and mailto URLs; anything else becomes plain text. */\n href: string;\n color?: EmailColor;\n /**\n * The web Link defaults to `hover`, but there is no reliable hover in email,\n * so the default here is `always`: an inbox reader needs to see a link is\n * one without touching it.\n */\n underline?: 'none' | 'always';\n style?: React.CSSProperties;\n children: React.ReactNode;\n}\n\n/** Link for email: the web Link's `--color-*-main` colour, which steps from 500 to 400 in dark. */\nexport function Link({ href, color = 'primary', underline = 'always', style, children }: LinkProps) {\n const safe = safeHref(href);\n if (!safe) return <>{children}</>;\n return (\n <ReactEmailLink\n href={safe}\n className={emailClass.main(color)}\n style={{ fontFamily: emailFonts.body, color: mainColor('light', color), textDecoration: underline === 'always' ? 'underline' : 'none', wordBreak: 'break-word', ...style }}\n >\n {children}\n </ReactEmailLink>\n );\n}\n","import * as React from 'react';\nimport { emailClass } from '../styles';\nimport { emailSchemes } from '../tokens';\n\nexport interface DividerProps {\n /** Spacing around the line — the web Divider has none of its own either. */\n style?: React.CSSProperties;\n}\n\n/**\n * Divider for email: a 1px line in `--color-divider`. A div rather than an\n * <hr>, whose borders Outlook and Gmail each draw differently. `background`\n * carries a solid fallback that Outlook's Word engine — which drops rgba() —\n * keeps; every other client takes the rgba `background-color` after it.\n */\nexport function Divider({ style }: DividerProps) {\n const t = emailSchemes.light;\n return (\n <div\n role=\"separator\"\n className={emailClass.divider}\n style={{ height: '1px', lineHeight: '1px', fontSize: '1px', background: t.dividerFallback, backgroundColor: t.divider, border: 'none', margin: 0, ...style }}\n >\n &nbsp;\n </div>\n );\n}\n","import * as React from 'react';\nimport { emailClass } from '../styles';\nimport { emailFonts, emailRadius, emailSchemes, variantTokens, type EmailColor, type EmailVariant } from '../tokens';\n\nexport interface CardProps {\n variant?: EmailVariant;\n color?: EmailColor;\n style?: React.CSSProperties;\n children?: React.ReactNode;\n}\n\n/**\n * Card for email: Sheet's variant colours plus Card's own `rounded-md p-4`,\n * defaulting to outlined / neutral like the web Card. Outlined and plain fill\n * with `surface`, as Joy's Sheet does. A one-cell table, because that is the\n * only box Outlook pads reliably; Card's `gap-2` has no email equivalent, so\n * spacing between children is theirs to set.\n */\nexport function Card({ variant = 'outlined', color = 'neutral', style, children }: CardProps) {\n const v = variantTokens('light', variant, color);\n const filled = v.backgroundColor !== undefined;\n return (\n <table\n role=\"presentation\"\n width=\"100%\"\n cellPadding={0}\n cellSpacing={0}\n border={0}\n className={[emailClass.variant(variant, color), filled ? '' : emailClass.surface].filter(Boolean).join(' ')}\n style={{\n borderCollapse: 'separate',\n borderRadius: emailRadius.md,\n backgroundColor: v.backgroundColor ?? emailSchemes.light.surface,\n color: v.color,\n border: v.borderColor ? `1px solid ${v.borderColor}` : undefined,\n fontFamily: emailFonts.body,\n ...style,\n }}\n >\n <tbody>\n <tr>\n <td style={{ padding: '16px' }}>{children}</td>\n </tr>\n </tbody>\n </table>\n );\n}\n","import * as React from 'react';\nimport { Img } from 'react-email';\nimport { emailClass } from '../styles';\nimport { emailFonts, variantTokens, type EmailColor, type EmailVariant } from '../tokens';\nimport { safeImageSrc } from '../safeUrl';\n\n/** avatarVariants.ts: 32/40/48px boxes, text-sm/base/lg, medium/medium/semibold. */\nconst SIZES = {\n sm: { box: 32, fontSize: '14px', fontWeight: 500 },\n md: { box: 40, fontSize: '16px', fontWeight: 500 },\n lg: { box: 48, fontSize: '18px', fontWeight: 600 },\n} as const;\n\nexport interface AvatarProps {\n variant?: EmailVariant;\n color?: EmailColor;\n size?: keyof typeof SIZES;\n /** An https image. Without one, `children` (usually initials) is shown. */\n src?: string;\n alt?: string;\n children?: React.ReactNode;\n}\n\n/**\n * Avatar for email, defaulting to soft / neutral like the web Avatar. Unlike\n * Card, outlined and plain stay transparent — Joy's Avatar has no surface\n * fallback. The initials are centred by a table cell, since email has no flexbox.\n */\nexport function Avatar({ variant = 'soft', color = 'neutral', size = 'md', src, alt = '', children }: AvatarProps) {\n const s = SIZES[size];\n const safe = safeImageSrc(src);\n if (safe) {\n return <Img src={safe} width={s.box} height={s.box} alt={alt} style={{ display: 'inline-block', borderRadius: '50%', objectFit: 'cover' }} />;\n }\n const v = variantTokens('light', variant, color);\n return (\n <table\n role=\"presentation\"\n cellPadding={0}\n cellSpacing={0}\n border={0}\n className={emailClass.variant(variant, color)}\n style={{\n display: 'inline-table',\n boxSizing: 'border-box',\n width: `${s.box}px`,\n height: `${s.box}px`,\n borderCollapse: 'separate',\n borderRadius: '50%',\n backgroundColor: v.backgroundColor ?? 'transparent',\n color: v.color,\n border: v.borderColor ? `1px solid ${v.borderColor}` : undefined,\n fontFamily: emailFonts.body,\n fontSize: s.fontSize,\n fontWeight: s.fontWeight,\n lineHeight: 1,\n verticalAlign: 'middle',\n }}\n >\n <tbody>\n <tr>\n <td align=\"center\" style={{ padding: 0, verticalAlign: 'middle', textAlign: 'center' }}>\n {children}\n </td>\n </tr>\n </tbody>\n </table>\n );\n}\n","import * as React from 'react';\nimport { emailClass } from '../styles';\nimport { emailFonts, emailSchemes, variantTokens, type EmailColor, type EmailVariant } from '../tokens';\n\n/**\n * chipVariants.ts: `min-h-5/6/7`, `px-1.5/2/3`, `text-xs/sm/base` at a 1.5\n * line-height. As with Button, the min-height becomes vertical padding.\n */\nconst SIZES = {\n sm: { minHeight: 20, paddingInline: 6, fontSize: 12 },\n md: { minHeight: 24, paddingInline: 8, fontSize: 14 },\n lg: { minHeight: 28, paddingInline: 12, fontSize: 16 },\n} as const;\n\nexport interface ChipProps {\n variant?: EmailVariant;\n color?: EmailColor;\n size?: keyof typeof SIZES;\n style?: React.CSSProperties;\n children: React.ReactNode;\n}\n\n/** Chip for email, defaulting to soft / neutral like the web Chip; outlined and plain fill with `surface`. */\nexport function Chip({ variant = 'soft', color = 'neutral', size = 'md', style, children }: ChipProps) {\n const s = SIZES[size];\n const v = variantTokens('light', variant, color);\n const filled = v.backgroundColor !== undefined;\n const border = v.borderColor ? 1 : 0;\n const lineHeight = s.fontSize * 1.5;\n const paddingBlock = (s.minHeight - lineHeight) / 2 - border;\n return (\n <span\n className={[emailClass.variant(variant, color), filled ? '' : emailClass.surface].filter(Boolean).join(' ')}\n style={{\n display: 'inline-block',\n boxSizing: 'border-box',\n whiteSpace: 'nowrap',\n verticalAlign: 'middle',\n padding: `${paddingBlock}px ${s.paddingInline}px`,\n borderRadius: '1.5rem',\n fontFamily: emailFonts.body,\n fontSize: `${s.fontSize}px`,\n fontWeight: 500,\n lineHeight: 1.5,\n color: v.color,\n backgroundColor: v.backgroundColor ?? emailSchemes.light.surface,\n border: v.borderColor ? `1px solid ${v.borderColor}` : undefined,\n ...style,\n }}\n >\n {children}\n </span>\n );\n}\n","import { Img } from 'react-email';\nimport { emailClass } from '../styles';\n\n/*\n * The hintoric wordmark as hosted PNGs (1336 × 410 artwork, shown at 104 × 32\n * so it stays sharp on HiDPI screens). PNG rather than SVG, which Gmail and\n * desktop Outlook don't display; linked rather than attached, so messages stay\n * small. A client that blocks remote images until asked shows the alt text.\n */\nconst LOGO = {\n light: 'https://cdn.hintoric.com/assets/logo/black.png',\n dark: 'https://cdn.hintoric.com/assets/logo/white.png',\n width: 104,\n height: 32,\n};\n\n/**\n * The email counterpart of the web HintoricLogo: the black wordmark, swapped\n * for the white one where the client applies the dark stylesheet.\n */\nexport function HintoricLogo() {\n return (\n <>\n <Img\n src={LOGO.light}\n width={LOGO.width}\n height={LOGO.height}\n alt=\"hintoric\"\n className={emailClass.logoLight}\n style={{ display: 'inline-block', margin: '0 auto' }}\n />\n <Img\n src={LOGO.dark}\n width={LOGO.width}\n height={LOGO.height}\n alt=\"hintoric\"\n className={emailClass.logoDark}\n style={{ display: 'none', margin: '0 auto' }}\n />\n </>\n );\n}\n","import { Avatar } from '../../components/Avatar';\nimport { Button } from '../../components/Button';\nimport { Divider } from '../../components/Divider';\nimport { Layout } from '../../components/Layout';\nimport { Link } from '../../components/Link';\nimport { Typography } from '../../components/Typography';\nimport { HintoricLogo } from '../../components/HintoricLogo';\nimport { renderEmail } from '../../render';\nimport { emailFonts } from '../../tokens';\nimport type { SecurityActivityAlertContext, SecurityActivityAlertProps } from './types';\n\nfunction contextOf(props: SecurityActivityAlertProps): SecurityActivityAlertContext {\n return {\n activity: props.activity,\n target: props.target,\n targetName: targetNameOf(props),\n occurredAt: props.messages.formatDateTime(props.activity.occurredAt, props.timeZone),\n };\n}\n\nfunction targetNameOf({ target }: SecurityActivityAlertProps): string {\n return target.type === 'workspace' ? target.workspaceName : target.email;\n}\n\n/**\n * The first letter of the first two words that have one: \"Müller & Söhne\"\n * is MS, not M&, and a quote or dash in front of a word does not count.\n */\nfunction initials(name: string): string {\n return name\n .split(/\\s+/)\n .map((word) => word.match(/\\p{L}/u)?.[0])\n .filter((letter): letter is string => letter !== undefined)\n .slice(0, 2)\n .map((letter) => letter.toUpperCase())\n .join('');\n}\n\n/**\n * For security-relevant activity: a change in a workspace (sent to its\n * admins) or to an account (sent to its owner) — see `SecurityActivityTarget`.\n * Deliberately short: what happened as the heading, what it concerns, one\n * sentence, one button, one link.\n */\nexport function SecurityActivityAlertEmail(props: SecurityActivityAlertProps) {\n const { messages } = props;\n const ctx = contextOf(props);\n return (\n <Layout\n lang={messages.lang}\n preview={messages.preview(ctx)}\n colorScheme={props.colorScheme}\n footer={\n <Typography level=\"body-xs\" component=\"p\" textAlign=\"center\" textColor=\"icon\" style={{ fontWeight: 400 }}>\n {messages.footer(ctx)}\n {props.legalNotice && (\n <>\n <br />\n {props.legalNotice}\n </>\n )}\n </Typography>\n }\n >\n <SecurityActivityAlertContent {...props} />\n </Layout>\n );\n}\n\n/** What goes inside the card, without the document — for in-app previews (render `ColorSchemeStyles` next to it). */\nexport function SecurityActivityAlertContent(props: SecurityActivityAlertProps) {\n const { messages, activityLogUrl } = props;\n const ctx = contextOf(props);\n return (\n <>\n <div style={{ textAlign: 'center' }}>\n <HintoricLogo />\n <Typography level=\"h3\" component=\"h1\" style={{ margin: '16px 0 12px', fontFamily: emailFonts.heading }}>\n {props.activity.title}\n </Typography>\n {/* primary, not the default neutral: in dark the layout card is surface-1,\n exactly the soft-neutral avatar fill, which would make it vanish. */}\n <Avatar size=\"sm\" color=\"primary\">\n {initials(ctx.targetName)}\n </Avatar>\n <Typography level=\"title-sm\" component=\"span\" style={{ marginLeft: '8px', verticalAlign: 'middle' }}>\n {ctx.targetName}\n </Typography>\n </div>\n <Divider style={{ margin: '32px 0' }} />\n <Typography level=\"body-sm\" style={{ marginBottom: '24px' }}>\n {props.activity.description?.trim() || messages.summary(ctx)} {messages.guidance(ctx)}\n </Typography>\n <Button href={props.reviewUrl} size=\"lg\" fullWidth>\n {messages.reviewButton}\n </Button>\n {activityLogUrl && (\n <Typography level=\"body-xs\" component=\"p\" textAlign=\"center\" style={{ marginTop: '24px', fontWeight: 400 }}>\n {messages.activityLogHint((label) => (\n <Link href={activityLogUrl} underline=\"none\">\n {label}\n </Link>\n ))}\n </Typography>\n )}\n </>\n );\n}\n\nexport interface RenderedEmail {\n subject: string;\n html: string;\n text: string;\n}\n\n/** Subject, HTML and plain-text body in one call — what a mail API's send() takes. */\nexport async function renderSecurityActivityAlert(props: SecurityActivityAlertProps): Promise<RenderedEmail> {\n const { html, text } = await renderEmail(<SecurityActivityAlertEmail {...props} />);\n return { subject: props.messages.subject(contextOf(props)), html, text };\n}\n","import type { SecurityActivityAlertMessages } from './types';\n\nfunction dateTimeFormatter(locale: string) {\n return (date: Date, timeZone: string) =>\n new Intl.DateTimeFormat(locale, { dateStyle: 'long', timeStyle: 'short', timeZone }).format(date);\n}\n\nexport const securityActivityAlertMessagesDe: SecurityActivityAlertMessages = {\n lang: 'de',\n subject: ({ activity, targetName }) => `${activity.title} – ${targetName}`,\n preview: ({ activity, occurredAt }) => `${activity.actorName} · ${occurredAt}`,\n summary: ({ activity, occurredAt }) => `${activity.actorName} hat am ${occurredAt} eine sicherheitsrelevante Änderung vorgenommen.`,\n guidance: () => 'Wenn du diese Änderung nicht erwartet hast, prüfe die Aktivität jetzt.',\n reviewButton: 'Aktivität prüfen',\n activityLogHint: (link) => <>Alle sicherheitsrelevanten Aktivitäten findest du im {link('Aktivitätsprotokoll')}.</>,\n footer: ({ target }) =>\n target.type === 'workspace'\n ? 'Wir haben dir diese E-Mail gesendet, um dich als Administrator über wichtige Änderungen in deinem Workspace zu informieren.'\n : 'Wir haben dir diese E-Mail gesendet, um dich über wichtige Änderungen an deinem hintoric-Konto zu informieren.',\n formatDateTime: dateTimeFormatter('de-DE'),\n};\n\nexport const securityActivityAlertMessagesEn: SecurityActivityAlertMessages = {\n lang: 'en',\n subject: ({ activity, targetName }) => `${activity.title} – ${targetName}`,\n preview: ({ activity, occurredAt }) => `${activity.actorName} · ${occurredAt}`,\n summary: ({ activity, occurredAt }) => `${activity.actorName} made a security-relevant change on ${occurredAt}.`,\n guidance: () => \"If you didn't expect this change, review the activity now.\",\n reviewButton: 'Review activity',\n activityLogHint: (link) => <>You can see all security-relevant activity in the {link('activity log')}.</>,\n footer: ({ target }) =>\n target.type === 'workspace'\n ? 'We sent you this email to let you know, as an admin, about important changes in your workspace.'\n : 'We sent you this email to let you know about important changes to your hintoric account.',\n formatDateTime: dateTimeFormatter('en-GB'),\n};\n","import { Button } from '../../components/Button';\nimport { HintoricLogo } from '../../components/HintoricLogo';\nimport { Layout } from '../../components/Layout';\nimport { Typography } from '../../components/Typography';\nimport { renderEmail } from '../../render';\nimport { emailFonts } from '../../tokens';\nimport type { WaitlistWelcomeProps } from './types';\n\n/**\n * Sent right after someone joins the waitlist: a thank-you, what happens\n * next, one button to the website. Centred, like the other single-purpose\n * mails — logo, heading, two short paragraphs, button, sign-off.\n */\n/** @deprecated New consumers should not use this template. */\nexport function WaitlistWelcomeEmail(props: WaitlistWelcomeProps) {\n const { messages } = props;\n return (\n <Layout\n lang={messages.lang}\n preview={messages.preview}\n colorScheme={props.colorScheme}\n footer={\n <Typography level=\"body-xs\" component=\"p\" textAlign=\"center\" textColor=\"icon\" style={{ fontWeight: 400 }}>\n {messages.footer}\n {props.legalNotice && (\n <>\n <br />\n {props.legalNotice}\n </>\n )}\n </Typography>\n }\n >\n <WaitlistWelcomeContent {...props} />\n </Layout>\n );\n}\n\n/** What goes inside the card, without the document — for in-app previews (render `ColorSchemeStyles` next to it). */\n/** @deprecated New consumers should not use this template. */\nexport function WaitlistWelcomeContent({ messages, websiteUrl }: WaitlistWelcomeProps) {\n return (\n <div style={{ textAlign: 'center' }}>\n <HintoricLogo />\n <Typography level=\"body-xs\" component=\"p\" textAlign=\"center\" textColor=\"icon\" style={{ margin: '24px 0 8px', fontWeight: 400 }}>\n {messages.eyebrow}\n </Typography>\n <Typography level=\"h3\" component=\"h1\" style={{ margin: '0 0 16px', fontFamily: emailFonts.heading }}>\n {messages.heading}\n </Typography>\n <Typography level=\"body-sm\" style={{ marginBottom: '12px' }}>\n {messages.body1}\n </Typography>\n <Typography level=\"body-sm\" style={{ marginBottom: '24px' }}>\n {messages.body2}\n </Typography>\n <Button href={websiteUrl} size=\"lg\" fullWidth>\n {messages.cta}\n </Button>\n <Typography level=\"body-xs\" component=\"p\" textAlign=\"center\" textColor=\"icon\" style={{ margin: '24px 0 0', fontWeight: 400 }}>\n {messages.signoff}\n </Typography>\n </div>\n );\n}\n\nexport interface RenderedWaitlistWelcome {\n subject: string;\n html: string;\n text: string;\n}\n\n/** Subject, HTML and plain-text body in one call — what SES, Resend and the like take. */\n/** @deprecated New consumers should not use this template. */\nexport async function renderWaitlistWelcome(props: WaitlistWelcomeProps): Promise<RenderedWaitlistWelcome> {\n const { html, text } = await renderEmail(<WaitlistWelcomeEmail {...props} />);\n return { subject: props.messages.subject, html, text };\n}\n","import type { WaitlistWelcomeMessages } from './types';\n\n/** @deprecated New consumers should not use this template. */\nexport const waitlistWelcomeMessagesDe: WaitlistWelcomeMessages = {\n lang: 'de',\n subject: 'Du bist auf der Hintoric-Warteliste',\n preview: 'Willkommen an Bord — Hintoric',\n eyebrow: 'Danke, dass du dabei bist',\n heading: 'Willkommen bei Hintoric',\n body1: 'Alles erledigt. Sobald dein Platz frei wird, melden wir uns sofort — du bist einer der Ersten, die Hintoric ausprobieren dürfen.',\n body2: 'Bis dahin halten wir dich auf dem Laufenden. Wenn jemand aus deinem Umfeld auch dazugehören sollte, leite diese Mail gerne weiter.',\n cta: 'Zu hintoric.com',\n signoff: '— Dein Hintoric-Team',\n footer: 'Wir haben dir diese E-Mail gesendet, weil du dich für die Hintoric-Warteliste eingetragen hast.',\n};\n\n/** @deprecated New consumers should not use this template. */\nexport const waitlistWelcomeMessagesEn: WaitlistWelcomeMessages = {\n lang: 'en',\n subject: \"You're on the Hintoric waitlist\",\n preview: 'Welcome aboard — Hintoric',\n eyebrow: 'Thanks for joining',\n heading: 'Welcome to Hintoric',\n body1: \"You're all set. As soon as your spot opens up we'll let you know — you'll be one of the first to try Hintoric.\",\n body2: \"Until then we'll keep you posted. If someone you know should be on the list too, feel free to forward this email.\",\n cta: 'Go to hintoric.com',\n signoff: '— Your Hintoric team',\n footer: 'We sent you this email because you signed up for the Hintoric waitlist.',\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/render.ts","../src/tokens.ts","../src/safeUrl.ts","../src/styles.ts","../src/components/Link.tsx","../src/components/Typography.tsx","../src/components/Layout.tsx","../src/components/Button.tsx","../src/components/Divider.tsx","../src/components/Card.tsx","../src/components/Avatar.tsx","../src/components/Chip.tsx","../src/components/HintoricLogo.tsx","../src/templates/SecurityActivityAlert/SecurityActivityAlertEmail.tsx","../src/templates/SecurityActivityAlert/messages.tsx","../src/templates/WaitlistWelcome/WaitlistWelcomeEmail.tsx","../src/templates/WaitlistWelcome/messages.ts"],"sourcesContent":["import type * as React from 'react';\nimport { render } from '@react-email/render';\n\nexport interface RenderedEmailBody {\n html: string;\n /** The plain-text part. Multipart mails without one score worse with spam filters. */\n text: string;\n}\n\n/** Renders an email element — normally a `<Layout>` — to HTML and plain text. */\nexport async function renderEmail(element: React.ReactElement): Promise<RenderedEmailBody> {\n const [html, text] = await Promise.all([render(element), render(element, { plainText: true })]);\n return { html, text };\n}\n","/*\n * The email module's copy of theme.css, resolved to literal values.\n *\n * Email clients cannot use the component library's styling: Gmail, Outlook\n * and Apple Mail resolve neither CSS custom properties nor Tailwind classes,\n * and Gmail drops <style> blocks in some contexts. So every email component\n * paints with inline `style` values taken from here, and the dark scheme is a\n * progressive enhancement layered on top (see styles.ts).\n *\n * The raw stops are theme.css's; the per-variant mapping below is the same\n * formula theme.css spells out token by token (Joy's createLight/DarkMode\n * VariantVariables, with neutral's -700 plain/outlined override in light).\n * The parity tests in src/visual/email/*.visual.test.tsx compare every email\n * component against its web counterpart in both schemes, so a drift between\n * the two shows up as a failing computed-style assertion.\n */\n\nexport type EmailColor = 'primary' | 'neutral' | 'danger' | 'success' | 'warning';\nexport type EmailVariant = 'solid' | 'soft' | 'outlined' | 'plain';\nexport type EmailScheme = 'light' | 'dark';\n\ntype Stop = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;\n\nexport const emailPalette: Record<EmailColor, Record<Stop, string>> = {\n neutral: { 50: '#FBFCFE', 100: '#F0F4F8', 200: '#DDE7EE', 300: '#CDD7E1', 400: '#9FA6AD', 500: '#636B74', 600: '#555E68', 700: '#32383E', 800: '#171A1C', 900: '#0B0D0E' },\n primary: { 50: '#EDF5FD', 100: '#E3EFFB', 200: '#C7DFF7', 300: '#97C3F0', 400: '#4393E4', 500: '#0B6BCB', 600: '#185EA5', 700: '#12467B', 800: '#0A2744', 900: '#051423' },\n warning: { 50: '#FEFAF6', 100: '#FDF0E1', 200: '#FCE1C2', 300: '#F3C896', 400: '#EA9A3E', 500: '#9A5B13', 600: '#72430D', 700: '#492B08', 800: '#2E1B05', 900: '#1D1002' },\n danger: { 50: '#FEF6F6', 100: '#FCE4E4', 200: '#F7C5C5', 300: '#F09898', 400: '#E47474', 500: '#C41C1C', 600: '#A51818', 700: '#7D1212', 800: '#430A0A', 900: '#240505' },\n success: { 50: '#F6FEF6', 100: '#E3FBE3', 200: '#C7F7C7', 300: '#A1E8A1', 400: '#51BC51', 500: '#1F7A1F', 600: '#136C13', 700: '#0A470A', 800: '#042F04', 900: '#021D02' },\n};\n\nexport const EMAIL_COLORS: EmailColor[] = ['primary', 'neutral', 'danger', 'success', 'warning'];\nexport const EMAIL_VARIANTS: EmailVariant[] = ['solid', 'soft', 'outlined', 'plain'];\n\n/** What one variant × colour paints. `undefined` means \"leaves it to the surroundings\". */\nexport interface EmailVariantTokens {\n color: string;\n backgroundColor?: string;\n borderColor?: string;\n}\n\nexport function variantTokens(scheme: EmailScheme, variant: EmailVariant, color: EmailColor): EmailVariantTokens {\n const c = emailPalette[color];\n const dark = scheme === 'dark';\n switch (variant) {\n case 'solid':\n return { color: '#FFFFFF', backgroundColor: c[500] };\n case 'soft':\n return dark ? { color: c[200], backgroundColor: c[800] } : { color: c[700], backgroundColor: c[100] };\n case 'outlined':\n return dark\n ? { color: c[200], borderColor: c[700] }\n : { color: color === 'neutral' ? c[700] : c[500], borderColor: c[300] };\n case 'plain':\n return { color: dark ? c[300] : color === 'neutral' ? c[700] : c[500] };\n }\n}\n\n/** `--color-*-main`: step 500 in light, 400 in dark. What Link renders. */\nexport function mainColor(scheme: EmailScheme, color: EmailColor): string {\n return emailPalette[color][scheme === 'dark' ? 400 : 500];\n}\n\nexport interface EmailSchemeTokens {\n inkPrimary: string;\n inkSecondary: string;\n inkTertiary: string;\n /** `--color-ink-icon`: the faintest ink. */\n inkIcon: string;\n /** `--color-surface`: what a Sheet / Card paints under outlined and plain. */\n surface: string;\n /** `--color-surface-1`. */\n surface1: string;\n /**\n * `--color-divider`. Kept as the rgba() theme.css uses so it composites the\n * same way over any surface; Outlook's Word engine drops rgba(), which is\n * why Divider also sets a solid `dividerFallback`.\n */\n divider: string;\n /** `divider` flattened onto `surface`. */\n dividerFallback: string;\n}\n\nexport const emailSchemes: Record<EmailScheme, EmailSchemeTokens> = {\n light: {\n inkPrimary: emailPalette.neutral[800],\n inkSecondary: emailPalette.neutral[700],\n inkTertiary: emailPalette.neutral[600],\n inkIcon: emailPalette.neutral[500],\n surface: emailPalette.neutral[50],\n surface1: emailPalette.neutral[100],\n divider: 'rgba(99, 107, 116, 0.2)',\n dividerFallback: '#DCDFE2',\n },\n dark: {\n inkPrimary: emailPalette.neutral[100],\n inkSecondary: emailPalette.neutral[300],\n inkTertiary: emailPalette.neutral[400],\n inkIcon: emailPalette.neutral[400],\n surface: emailPalette.neutral[900],\n surface1: emailPalette.neutral[800],\n divider: 'rgba(159, 166, 173, 0.16)',\n dividerFallback: '#232628',\n },\n};\n\nexport const emailFonts = {\n // `--font-body`.\n body: \"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif\",\n // core's `--font-heading`. Only clients with the font installed or web-font\n // support (Apple Mail) show Montserrat; the rest fall back to the body stack.\n heading: \"Montserrat, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif\",\n};\n\n/** theme.css's radius scale. */\nexport const emailRadius = { xs: '2px', sm: '6px', md: '8px', lg: '12px', xl: '16px' };\n","/*\n * Every link in an email is a link someone may click without a second look —\n * a security alert's \"review this activity\" button most of all. React escapes\n * text but not the scheme of an href, so a `javascript:` or `data:` URL that\n * reached a template through data would survive rendering intact. Only these\n * schemes are let through; anything else renders as plain, unlinked text.\n */\nconst LINK_PROTOCOLS = new Set(['https:', 'http:', 'mailto:']);\n\nexport function safeHref(href: string | undefined | null): string | undefined {\n if (!href) return undefined;\n try {\n const url = new URL(href);\n return LINK_PROTOCOLS.has(url.protocol) ? url.href : undefined;\n } catch {\n // Relative URLs are meaningless in an email: there is no base to resolve\n // them against once the message leaves the server.\n return undefined;\n }\n}\n\n/** Images additionally have to be https: mail clients block or warn on http. */\nexport function safeImageSrc(src: string | undefined | null): string | undefined {\n if (!src) return undefined;\n try {\n const url = new URL(src);\n return url.protocol === 'https:' ? url.href : undefined;\n } catch {\n return undefined;\n }\n}\n","import {\n EMAIL_COLORS,\n EMAIL_VARIANTS,\n emailSchemes,\n mainColor,\n variantTokens,\n type EmailColor,\n type EmailVariant,\n} from './tokens';\n\n/*\n * Inline styles carry the light scheme, so an email always renders correctly\n * even where <style> is stripped. Dark mode is a progressive enhancement: each\n * painted element also carries a class from here, and the stylesheet below\n * overrides it — `!important` because it has to beat the inline value.\n *\n * Two triggers, deliberately:\n * - `prefers-color-scheme: dark`, which Apple Mail, iOS Mail, Outlook for\n * Mac and Thunderbird honour. Guarded by `:not([data-color-scheme=\"light\"])`\n * so a preview forced to light stays light on a dark OS.\n * - `[data-color-scheme=\"dark\"]` on any ancestor — the same switch the\n * component library uses, so an email component rendered inside the docs\n * or a visual test follows the page's scheme.\n *\n * Gmail and Outlook.com ignore both and apply their own colour inversion,\n * which is out of any template's control.\n */\nexport const emailClass = {\n variant: (variant: EmailVariant, color: EmailColor) => `hx-${variant}-${color}`,\n main: (color: EmailColor) => `hx-main-${color}`,\n inkPrimary: 'hx-ink-1',\n inkSecondary: 'hx-ink-2',\n inkTertiary: 'hx-ink-3',\n inkIcon: 'hx-ink-icon',\n surface: 'hx-surface',\n divider: 'hx-divider',\n // Layout's AuthScreen shell: page and card swap surfaces in dark.\n layoutCanvas: 'hx-layout-canvas',\n layoutCard: 'hx-layout-card',\n // The card's inner area, which carries its padding. A div of our own rather\n // than react-email's cell: Container moves its `padding` onto an inner <td>,\n // so a rule on the card itself added to it instead of replacing it.\n layoutCardBody: 'hx-layout-card-body',\n // A logo pair: the light one shows by default, the dark one only once the\n // dark rules apply — clients without <style> support keep the light logo.\n logoLight: 'hx-logo-light',\n logoDark: 'hx-logo-dark',\n} as const;\n\nfunction darkRules(scope: string): string {\n const t = emailSchemes.dark;\n const rule = (selector: string, body: string) => `${scope} .${selector}{${body}}`;\n const rules = [\n rule(emailClass.inkPrimary, `color:${t.inkPrimary}!important;`),\n rule(emailClass.inkSecondary, `color:${t.inkSecondary}!important;`),\n rule(emailClass.inkTertiary, `color:${t.inkTertiary}!important;`),\n rule(emailClass.inkIcon, `color:${t.inkIcon}!important;`),\n rule(emailClass.surface, `background-color:${t.surface}!important;`),\n rule(emailClass.divider, `background-color:${t.divider}!important;`),\n rule(emailClass.layoutCanvas, `background-color:${t.surface}!important;`),\n // react-email's Body repeats its inline style on an inner wrapper cell\n // that carries no class, so the canvas colour has to reach it too.\n rule(`${emailClass.layoutCanvas}>table>tbody>tr>td`, `background-color:${t.surface}!important;`),\n rule(emailClass.logoLight, 'display:none!important;'),\n rule(emailClass.logoDark, 'display:inline-block!important;'),\n rule(emailClass.layoutCard,`background-color:${t.surface1}!important;border-color:${variantTokens('dark', 'outlined', 'neutral').borderColor}!important;`),\n ];\n for (const color of EMAIL_COLORS) {\n rules.push(rule(emailClass.main(color), `color:${mainColor('dark', color)}!important;`));\n for (const variant of EMAIL_VARIANTS) {\n const v = variantTokens('dark', variant, color);\n rules.push(\n rule(\n emailClass.variant(variant, color),\n [\n `color:${v.color}!important;`,\n v.backgroundColor && `background-color:${v.backgroundColor}!important;`,\n v.borderColor && `border-color:${v.borderColor}!important;`,\n ]\n .filter(Boolean)\n .join(''),\n ),\n );\n }\n }\n return rules.join('');\n}\n\n/*\n * AuthScreen's phone layout: the card stops being a card. It fills the width,\n * loses border and radius, insets its content by 24px, and the page around it\n * takes the card's colour — surface in light, surface-1 in dark. Last in the\n * sheet so it wins over the dark rules at equal specificity.\n */\nfunction phoneRules(): string {\n const canvas = (scope: string) => `${scope}.${emailClass.layoutCanvas},${scope}.${emailClass.layoutCanvas}>table>tbody>tr>td`;\n const dark = (scope: string) => `${canvas(scope)}{background-color:${emailSchemes.dark.surface1}!important;}`;\n return [\n `@media only screen and (max-width:600px){`,\n `.${emailClass.layoutCard}{max-width:100%!important;border:0!important;border-radius:0!important;}`,\n `.${emailClass.layoutCardBody}{padding:32px 24px!important;}`,\n `${canvas('')}{padding:0!important;background-color:${emailSchemes.light.surface}!important;}`,\n dark('[data-color-scheme=\"dark\"] '),\n `}`,\n `@media only screen and (max-width:600px) and (prefers-color-scheme:dark){${dark(':root:not([data-color-scheme=\"light\"]) ')}}`,\n ].join('');\n}\n\nexport const emailStylesheet = [\n // iOS turns dates and addresses into blue links that ignore the text colour.\n 'a[x-apple-data-detectors]{color:inherit!important;text-decoration:none!important;}',\n `@media (prefers-color-scheme:dark){${darkRules(':root:not([data-color-scheme=\"light\"])')}}`,\n darkRules('[data-color-scheme=\"dark\"]'),\n phoneRules(),\n].join('\\n');\n","import * as React from 'react';\nimport { Link as ReactEmailLink } from 'react-email';\nimport { emailClass } from '../styles';\nimport { emailFonts, mainColor, type EmailColor } from '../tokens';\nimport { safeHref } from '../safeUrl';\n\nexport interface LinkProps {\n /** Rendered only for http(s) and mailto URLs; anything else becomes plain text. */\n href: string;\n color?: EmailColor;\n /**\n * The web Link defaults to `hover`, but there is no reliable hover in email,\n * so the default here is `always`: an inbox reader needs to see a link is\n * one without touching it.\n */\n underline?: 'none' | 'always';\n style?: React.CSSProperties;\n children: React.ReactNode;\n}\n\n/** Link for email: the web Link's `--color-*-main` colour, which steps from 500 to 400 in dark. */\nexport function Link({ href, color = 'primary', underline = 'always', style, children }: LinkProps) {\n const safe = safeHref(href);\n if (!safe) return <>{children}</>;\n return (\n <ReactEmailLink\n href={safe}\n className={emailClass.main(color)}\n style={{ fontFamily: emailFonts.body, color: mainColor('light', color), textDecoration: underline === 'always' ? 'underline' : 'none', wordBreak: 'break-word', ...style }}\n >\n {children}\n </ReactEmailLink>\n );\n}\n","import * as React from 'react';\nimport { emailClass } from '../styles';\nimport { emailFonts, emailSchemes } from '../tokens';\n\nexport type TypographyLevel =\n | 'h1'\n | 'h2'\n | 'h3'\n | 'h4'\n | 'title-lg'\n | 'title-md'\n | 'title-sm'\n | 'body-lg'\n | 'body-md'\n | 'body-sm'\n | 'body-xs';\n\ntype Ink = 'inkPrimary' | 'inkSecondary' | 'inkTertiary' | 'inkIcon';\n\n/*\n * Typography's typographyVariants.ts, resolved: Tailwind's text-4xl…text-xs\n * in px, its font-bold/semibold/medium as numbers, `tracking-tight` as\n * -0.025em, and the same unitless line-heights (1.33334, 1.5, 1.42858), so the\n * computed line box matches the web component to the sub-pixel.\n */\nconst LEVELS: Record<TypographyLevel, { fontSize: string; fontWeight: number; lineHeight: number; letterSpacing?: string; ink: Ink }> = {\n h1: { fontSize: '36px', fontWeight: 700, lineHeight: 1.33334, letterSpacing: '-0.025em', ink: 'inkPrimary' },\n h2: { fontSize: '30px', fontWeight: 700, lineHeight: 1.33334, letterSpacing: '-0.025em', ink: 'inkPrimary' },\n h3: { fontSize: '24px', fontWeight: 600, lineHeight: 1.33334, letterSpacing: '-0.025em', ink: 'inkPrimary' },\n h4: { fontSize: '20px', fontWeight: 600, lineHeight: 1.5, letterSpacing: '-0.025em', ink: 'inkPrimary' },\n 'title-lg': { fontSize: '18px', fontWeight: 600, lineHeight: 1.33334, ink: 'inkPrimary' },\n 'title-md': { fontSize: '16px', fontWeight: 500, lineHeight: 1.5, ink: 'inkPrimary' },\n 'title-sm': { fontSize: '14px', fontWeight: 500, lineHeight: 1.42858, ink: 'inkPrimary' },\n 'body-lg': { fontSize: '18px', fontWeight: 400, lineHeight: 1.5, ink: 'inkSecondary' },\n 'body-md': { fontSize: '16px', fontWeight: 400, lineHeight: 1.5, ink: 'inkSecondary' },\n 'body-sm': { fontSize: '14px', fontWeight: 400, lineHeight: 1.5, ink: 'inkTertiary' },\n 'body-xs': { fontSize: '12px', fontWeight: 500, lineHeight: 1.5, ink: 'inkTertiary' },\n};\n\nconst DEFAULT_TAG: Record<TypographyLevel, 'h1' | 'h2' | 'h3' | 'h4' | 'p' | 'span'> = {\n h1: 'h1',\n h2: 'h2',\n h3: 'h3',\n h4: 'h4',\n 'title-lg': 'p',\n 'title-md': 'p',\n 'title-sm': 'p',\n 'body-lg': 'p',\n 'body-md': 'p',\n 'body-sm': 'p',\n 'body-xs': 'span',\n};\n\nexport interface TypographyProps {\n level?: TypographyLevel;\n /** The element to render. Defaults to the same tag the web Typography picks for the level. */\n component?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' | 'span' | 'div';\n textAlign?: 'left' | 'center' | 'right';\n /**\n * Overrides the level's ink, like Joy's `textColor=\"text.tertiary\"`.\n * `icon` is the theme's faintest ink — for fine print that should recede.\n */\n textColor?: 'primary' | 'secondary' | 'tertiary' | 'icon';\n /** Margin, spacing and the like — there is no Stack in email, so spacing lives on the text. */\n style?: React.CSSProperties;\n children?: React.ReactNode;\n}\n\nconst TEXT_COLOR: Record<NonNullable<TypographyProps['textColor']>, Ink> = {\n primary: 'inkPrimary',\n secondary: 'inkSecondary',\n tertiary: 'inkTertiary',\n icon: 'inkIcon',\n};\n\n/** Typography for email: the same levels, sizes and ink colours, as inline styles. */\nexport function Typography({ level = 'body-md', component, textAlign, textColor, style, children }: TypographyProps) {\n const spec = LEVELS[level];\n const ink = textColor ? TEXT_COLOR[textColor] : spec.ink;\n const Tag = component ?? DEFAULT_TAG[level];\n return (\n <Tag\n className={emailClass[ink]}\n style={{\n margin: 0,\n fontFamily: emailFonts.body,\n fontSize: spec.fontSize,\n fontWeight: spec.fontWeight,\n lineHeight: spec.lineHeight,\n letterSpacing: spec.letterSpacing,\n color: emailSchemes.light[ink],\n textAlign,\n ...style,\n }}\n >\n {children}\n </Tag>\n );\n}\n","import * as React from 'react';\nimport { Body, Container, Head, Html, Preview } from 'react-email';\nimport { emailClass, emailStylesheet } from '../styles';\nimport { emailFonts, emailSchemes, variantTokens } from '../tokens';\nimport { safeHref } from '../safeUrl';\nimport { Link } from './Link';\nimport { Typography } from './Typography';\n\nexport interface LayoutProps {\n /** The `lang` of the message — screen readers pick their voice from it. */\n lang: string;\n /**\n * The line inbox lists show after the subject. Without one, clients take the\n * first text they find, which is usually the brand name.\n */\n preview: string;\n /** Rendered under the card: why the reader got this, the sender's legal line. */\n footer?: React.ReactNode;\n /**\n * An unsubscribe link, rendered as the last line of the footer. Only for\n * mails a reader can opt out of — marketing and updates, not security alerts.\n * Without a safe http(s)/mailto `href` nothing is rendered.\n */\n unsubscribe?: { href: string; label: string };\n /** Forces a scheme for previews. Left out, the email follows the reader's OS where the client supports that. */\n colorScheme?: 'light' | 'dark';\n children: React.ReactNode;\n}\n\n/**\n * The whole document, laid out like core's AuthScreen: a 440px outlined card\n * with a 20px radius and 48px padding on a `surface-1` page, the fine print\n * centred under it. In dark the page and card swap surfaces, as AuthScreen's do.\n */\nexport function Layout({ lang, preview, footer, unsubscribe, colorScheme, children }: LayoutProps) {\n const t = emailSchemes.light;\n return (\n <Html lang={lang} data-color-scheme={colorScheme}>\n <Head>\n <meta name=\"color-scheme\" content=\"light dark\" />\n <meta name=\"supported-color-schemes\" content=\"light dark\" />\n <ColorSchemeStyles />\n </Head>\n <Preview>{preview}</Preview>\n <Body className={emailClass.layoutCanvas} style={{ margin: 0, padding: '40px 0', backgroundColor: t.surface1, fontFamily: emailFonts.body }}>\n <Container\n className={emailClass.layoutCard}\n style={{\n width: '100%',\n maxWidth: '440px',\n boxSizing: 'border-box',\n backgroundColor: t.surface,\n border: `1px solid ${variantTokens('light', 'outlined', 'neutral').borderColor}`,\n borderRadius: '20px',\n }}\n >\n <div className={emailClass.layoutCardBody} style={{ padding: '48px' }}>\n {children}\n </div>\n </Container>\n {(footer || unsubscribe) && (\n <Container style={{ maxWidth: '440px', padding: '24px 24px 0', textAlign: 'center' }}>\n {footer}\n {unsubscribe && safeHref(unsubscribe.href) && (\n <Typography level=\"body-xs\" component=\"p\" textAlign=\"center\" textColor=\"icon\" style={{ margin: footer ? '12px 0 0' : 0, fontWeight: 400 }}>\n <Link href={unsubscribe.href} color=\"neutral\">\n {unsubscribe.label}\n </Link>\n </Typography>\n )}\n </Container>\n )}\n </Body>\n </Html>\n );\n}\n\n/**\n * The dark-mode stylesheet on its own. Layout includes it; render it\n * once yourself when email components are shown inside a normal page — a\n * preview, the docs — so they follow that page's `data-color-scheme`.\n */\nexport function ColorSchemeStyles() {\n return <style dangerouslySetInnerHTML={{ __html: emailStylesheet }} />;\n}\n","import * as React from 'react';\nimport { Button as ReactEmailButton } from 'react-email';\nimport { emailClass } from '../styles';\nimport { emailFonts, emailRadius, variantTokens, type EmailColor, type EmailVariant } from '../tokens';\nimport { safeHref } from '../safeUrl';\n\n/*\n * buttonVariants.ts, resolved. The web Button gets its height from\n * `min-h-8/9/11` and centres the label with flexbox; email has neither, so the\n * same box is built from line-height plus vertical padding:\n * (min-height − line-height) / 2, less the 1px border for outlined.\n */\nconst SIZES = {\n sm: { minHeight: 32, paddingInline: 12, fontSize: 14, lineHeight: 21 },\n md: { minHeight: 36, paddingInline: 16, fontSize: 14, lineHeight: 21 },\n lg: { minHeight: 44, paddingInline: 24, fontSize: 16, lineHeight: 24 },\n} as const;\n\nexport interface ButtonProps {\n /** Rendered only for http(s) URLs; anything else renders nothing — a button nobody can follow is worse than none. */\n href: string;\n variant?: EmailVariant;\n color?: EmailColor;\n size?: keyof typeof SIZES;\n /** `rounded-full`, as on the web Button. */\n pill?: boolean;\n /** Stretches to the container — the usual call-to-action layout in a narrow email. */\n fullWidth?: boolean;\n style?: React.CSSProperties;\n children: React.ReactNode;\n}\n\n/** Button for email: a link styled as the web Button, built on react-email's Outlook-safe Button. */\nexport function Button({ href, variant = 'solid', color = 'primary', size = 'md', pill = false, fullWidth = false, style, children }: ButtonProps) {\n const safe = safeHref(href);\n if (!safe || safe.startsWith('mailto:')) return null;\n const s = SIZES[size];\n const v = variantTokens('light', variant, color);\n const border = variant === 'outlined' ? 1 : 0;\n const paddingBlock = (s.minHeight - s.lineHeight) / 2 - border;\n return (\n <ReactEmailButton\n href={safe}\n className={emailClass.variant(variant, color)}\n style={{\n display: fullWidth ? 'block' : 'inline-block',\n boxSizing: 'border-box',\n width: fullWidth ? '100%' : undefined,\n textAlign: 'center',\n paddingTop: `${paddingBlock}px`,\n paddingBottom: `${paddingBlock}px`,\n paddingLeft: `${s.paddingInline}px`,\n paddingRight: `${s.paddingInline}px`,\n fontFamily: emailFonts.body,\n fontSize: `${s.fontSize}px`,\n fontWeight: 600,\n lineHeight: `${s.lineHeight}px`,\n textDecoration: 'none',\n borderRadius: pill ? '9999px' : emailRadius.sm,\n color: v.color,\n backgroundColor: v.backgroundColor ?? 'transparent',\n border: v.borderColor ? `1px solid ${v.borderColor}` : undefined,\n ...style,\n }}\n >\n {/* react-email wraps the label in its own inline-block span at\n line-height 120%. In the modes mail is actually shown in — the\n limited-quirks mode its XHTML doctype yields, or full quirks where a\n webmail drops the doctype — the link's own line-height no longer\n props the line up, so the button shrank to 120% of the font plus\n padding: 4–5px short at every size. This span carries the full\n line-height itself, so the box no longer depends on the mode. */}\n <span style={{ display: 'inline-block', lineHeight: `${s.lineHeight}px` }}>{children}</span>\n </ReactEmailButton>\n );\n}\n","import * as React from 'react';\nimport { emailClass } from '../styles';\nimport { emailSchemes } from '../tokens';\n\nexport interface DividerProps {\n /** Spacing around the line — the web Divider has none of its own either. */\n style?: React.CSSProperties;\n}\n\n/**\n * Divider for email: a 1px line in `--color-divider`. A div rather than an\n * <hr>, whose borders Outlook and Gmail each draw differently. `background`\n * carries a solid fallback that Outlook's Word engine — which drops rgba() —\n * keeps; every other client takes the rgba `background-color` after it.\n */\nexport function Divider({ style }: DividerProps) {\n const t = emailSchemes.light;\n return (\n <div\n role=\"separator\"\n className={emailClass.divider}\n style={{ height: '1px', lineHeight: '1px', fontSize: '1px', background: t.dividerFallback, backgroundColor: t.divider, border: 'none', margin: 0, ...style }}\n >\n &nbsp;\n </div>\n );\n}\n","import * as React from 'react';\nimport { emailClass } from '../styles';\nimport { emailFonts, emailRadius, emailSchemes, variantTokens, type EmailColor, type EmailVariant } from '../tokens';\n\nexport interface CardProps {\n variant?: EmailVariant;\n color?: EmailColor;\n style?: React.CSSProperties;\n children?: React.ReactNode;\n}\n\n/**\n * Card for email: Sheet's variant colours plus Card's own `rounded-md p-4`,\n * defaulting to outlined / neutral like the web Card. Outlined and plain fill\n * with `surface`, as Joy's Sheet does. A one-cell table, because that is the\n * only box Outlook pads reliably; Card's `gap-2` has no email equivalent, so\n * spacing between children is theirs to set.\n */\nexport function Card({ variant = 'outlined', color = 'neutral', style, children }: CardProps) {\n const v = variantTokens('light', variant, color);\n const filled = v.backgroundColor !== undefined;\n return (\n <table\n role=\"presentation\"\n width=\"100%\"\n cellPadding={0}\n cellSpacing={0}\n border={0}\n className={[emailClass.variant(variant, color), filled ? '' : emailClass.surface].filter(Boolean).join(' ')}\n style={{\n borderCollapse: 'separate',\n borderRadius: emailRadius.md,\n backgroundColor: v.backgroundColor ?? emailSchemes.light.surface,\n color: v.color,\n border: v.borderColor ? `1px solid ${v.borderColor}` : undefined,\n fontFamily: emailFonts.body,\n ...style,\n }}\n >\n <tbody>\n <tr>\n <td style={{ padding: '16px' }}>{children}</td>\n </tr>\n </tbody>\n </table>\n );\n}\n","import * as React from 'react';\nimport { Img } from 'react-email';\nimport { emailClass } from '../styles';\nimport { emailFonts, variantTokens, type EmailColor, type EmailVariant } from '../tokens';\nimport { safeImageSrc } from '../safeUrl';\n\n/** avatarVariants.ts: 32/40/48px boxes, text-sm/base/lg, medium/medium/semibold. */\nconst SIZES = {\n sm: { box: 32, fontSize: '14px', fontWeight: 500 },\n md: { box: 40, fontSize: '16px', fontWeight: 500 },\n lg: { box: 48, fontSize: '18px', fontWeight: 600 },\n} as const;\n\nexport interface AvatarProps {\n variant?: EmailVariant;\n color?: EmailColor;\n size?: keyof typeof SIZES;\n /** An https image. Without one, `children` (usually initials) is shown. */\n src?: string;\n alt?: string;\n children?: React.ReactNode;\n}\n\n/**\n * Avatar for email, defaulting to soft / neutral like the web Avatar. Unlike\n * Card, outlined and plain stay transparent — Joy's Avatar has no surface\n * fallback. The initials are centred by a table cell, since email has no flexbox.\n */\nexport function Avatar({ variant = 'soft', color = 'neutral', size = 'md', src, alt = '', children }: AvatarProps) {\n const s = SIZES[size];\n const safe = safeImageSrc(src);\n if (safe) {\n return <Img src={safe} width={s.box} height={s.box} alt={alt} style={{ display: 'inline-block', borderRadius: '50%', objectFit: 'cover' }} />;\n }\n const v = variantTokens('light', variant, color);\n return (\n <table\n role=\"presentation\"\n cellPadding={0}\n cellSpacing={0}\n border={0}\n className={emailClass.variant(variant, color)}\n style={{\n display: 'inline-table',\n boxSizing: 'border-box',\n width: `${s.box}px`,\n height: `${s.box}px`,\n borderCollapse: 'separate',\n borderRadius: '50%',\n backgroundColor: v.backgroundColor ?? 'transparent',\n color: v.color,\n border: v.borderColor ? `1px solid ${v.borderColor}` : undefined,\n fontFamily: emailFonts.body,\n fontSize: s.fontSize,\n fontWeight: s.fontWeight,\n lineHeight: 1,\n verticalAlign: 'middle',\n }}\n >\n <tbody>\n <tr>\n <td align=\"center\" style={{ padding: 0, verticalAlign: 'middle', textAlign: 'center' }}>\n {children}\n </td>\n </tr>\n </tbody>\n </table>\n );\n}\n","import * as React from 'react';\nimport { emailClass } from '../styles';\nimport { emailFonts, emailSchemes, variantTokens, type EmailColor, type EmailVariant } from '../tokens';\n\n/**\n * chipVariants.ts: `min-h-5/6/7`, `px-1.5/2/3`, `text-xs/sm/base` at a 1.5\n * line-height. As with Button, the min-height becomes vertical padding.\n */\nconst SIZES = {\n sm: { minHeight: 20, paddingInline: 6, fontSize: 12 },\n md: { minHeight: 24, paddingInline: 8, fontSize: 14 },\n lg: { minHeight: 28, paddingInline: 12, fontSize: 16 },\n} as const;\n\nexport interface ChipProps {\n variant?: EmailVariant;\n color?: EmailColor;\n size?: keyof typeof SIZES;\n style?: React.CSSProperties;\n children: React.ReactNode;\n}\n\n/** Chip for email, defaulting to soft / neutral like the web Chip; outlined and plain fill with `surface`. */\nexport function Chip({ variant = 'soft', color = 'neutral', size = 'md', style, children }: ChipProps) {\n const s = SIZES[size];\n const v = variantTokens('light', variant, color);\n const filled = v.backgroundColor !== undefined;\n const border = v.borderColor ? 1 : 0;\n const lineHeight = s.fontSize * 1.5;\n const paddingBlock = (s.minHeight - lineHeight) / 2 - border;\n return (\n <span\n className={[emailClass.variant(variant, color), filled ? '' : emailClass.surface].filter(Boolean).join(' ')}\n style={{\n display: 'inline-block',\n boxSizing: 'border-box',\n whiteSpace: 'nowrap',\n verticalAlign: 'middle',\n padding: `${paddingBlock}px ${s.paddingInline}px`,\n borderRadius: '1.5rem',\n fontFamily: emailFonts.body,\n fontSize: `${s.fontSize}px`,\n fontWeight: 500,\n lineHeight: 1.5,\n color: v.color,\n backgroundColor: v.backgroundColor ?? emailSchemes.light.surface,\n border: v.borderColor ? `1px solid ${v.borderColor}` : undefined,\n ...style,\n }}\n >\n {children}\n </span>\n );\n}\n","import { Img } from 'react-email';\nimport { emailClass } from '../styles';\n\n/*\n * The hintoric wordmark as hosted PNGs (1336 × 410 artwork, shown at 104 × 32\n * so it stays sharp on HiDPI screens). PNG rather than SVG, which Gmail and\n * desktop Outlook don't display; linked rather than attached, so messages stay\n * small. A client that blocks remote images until asked shows the alt text.\n */\nconst LOGO = {\n light: 'https://cdn.hintoric.com/assets/logo/black.png',\n dark: 'https://cdn.hintoric.com/assets/logo/white.png',\n width: 104,\n height: 32,\n};\n\n/**\n * The email counterpart of the web HintoricLogo: the black wordmark, swapped\n * for the white one where the client applies the dark stylesheet.\n */\nexport function HintoricLogo() {\n return (\n <>\n <Img\n src={LOGO.light}\n width={LOGO.width}\n height={LOGO.height}\n alt=\"hintoric\"\n className={emailClass.logoLight}\n style={{ display: 'inline-block', margin: '0 auto' }}\n />\n <Img\n src={LOGO.dark}\n width={LOGO.width}\n height={LOGO.height}\n alt=\"hintoric\"\n className={emailClass.logoDark}\n style={{ display: 'none', margin: '0 auto' }}\n />\n </>\n );\n}\n","import { Avatar } from '../../components/Avatar';\nimport { Button } from '../../components/Button';\nimport { Divider } from '../../components/Divider';\nimport { Layout } from '../../components/Layout';\nimport { Link } from '../../components/Link';\nimport { Typography } from '../../components/Typography';\nimport { HintoricLogo } from '../../components/HintoricLogo';\nimport { renderEmail } from '../../render';\nimport { emailFonts } from '../../tokens';\nimport type { SecurityActivityAlertContext, SecurityActivityAlertProps } from './types';\n\nfunction contextOf(props: SecurityActivityAlertProps): SecurityActivityAlertContext {\n return {\n activity: props.activity,\n target: props.target,\n targetName: targetNameOf(props),\n occurredAt: props.messages.formatDateTime(props.activity.occurredAt, props.timeZone),\n };\n}\n\nfunction targetNameOf({ target }: SecurityActivityAlertProps): string {\n return target.type === 'workspace' ? target.workspaceName : target.email;\n}\n\n/**\n * The first letter of the first two words that have one: \"Müller & Söhne\"\n * is MS, not M&, and a quote or dash in front of a word does not count.\n */\nfunction initials(name: string): string {\n return name\n .split(/\\s+/)\n .map((word) => word.match(/\\p{L}/u)?.[0])\n .filter((letter): letter is string => letter !== undefined)\n .slice(0, 2)\n .map((letter) => letter.toUpperCase())\n .join('');\n}\n\n/**\n * For security-relevant activity: a change in a workspace (sent to its\n * admins) or to an account (sent to its owner) — see `SecurityActivityTarget`.\n * Deliberately short: what happened as the heading, what it concerns, one\n * sentence, one button, one link.\n */\nexport function SecurityActivityAlertEmail(props: SecurityActivityAlertProps) {\n const { messages } = props;\n const ctx = contextOf(props);\n return (\n <Layout\n lang={messages.lang}\n preview={messages.preview(ctx)}\n colorScheme={props.colorScheme}\n footer={\n <Typography level=\"body-xs\" component=\"p\" textAlign=\"center\" textColor=\"icon\" style={{ fontWeight: 400 }}>\n {messages.footer(ctx)}\n {props.legalNotice && (\n <>\n <br />\n {props.legalNotice}\n </>\n )}\n </Typography>\n }\n >\n <SecurityActivityAlertContent {...props} />\n </Layout>\n );\n}\n\n/** What goes inside the card, without the document — for in-app previews (render `ColorSchemeStyles` next to it). */\nexport function SecurityActivityAlertContent(props: SecurityActivityAlertProps) {\n const { messages, activityLogUrl } = props;\n const ctx = contextOf(props);\n return (\n <>\n <div style={{ textAlign: 'center' }}>\n <HintoricLogo />\n <Typography level=\"h3\" component=\"h1\" style={{ margin: '16px 0 12px', fontFamily: emailFonts.heading }}>\n {props.activity.title}\n </Typography>\n {/* primary, not the default neutral: in dark the layout card is surface-1,\n exactly the soft-neutral avatar fill, which would make it vanish. */}\n <Avatar size=\"sm\" color=\"primary\">\n {initials(ctx.targetName)}\n </Avatar>\n <Typography level=\"title-sm\" component=\"span\" style={{ marginLeft: '8px', verticalAlign: 'middle' }}>\n {ctx.targetName}\n </Typography>\n </div>\n <Divider style={{ margin: '32px 0' }} />\n <Typography level=\"body-sm\" style={{ marginBottom: '24px' }}>\n {props.activity.description?.trim() || messages.summary(ctx)} {messages.guidance(ctx)}\n </Typography>\n <Button href={props.reviewUrl} size=\"lg\" fullWidth>\n {messages.reviewButton}\n </Button>\n {activityLogUrl && (\n <Typography level=\"body-xs\" component=\"p\" textAlign=\"center\" style={{ marginTop: '24px', fontWeight: 400 }}>\n {messages.activityLogHint((label) => (\n <Link href={activityLogUrl} underline=\"none\">\n {label}\n </Link>\n ))}\n </Typography>\n )}\n </>\n );\n}\n\nexport interface RenderedEmail {\n subject: string;\n html: string;\n text: string;\n}\n\n/** Subject, HTML and plain-text body in one call — what a mail API's send() takes. */\nexport async function renderSecurityActivityAlert(props: SecurityActivityAlertProps): Promise<RenderedEmail> {\n const { html, text } = await renderEmail(<SecurityActivityAlertEmail {...props} />);\n return { subject: props.messages.subject(contextOf(props)), html, text };\n}\n","import type { SecurityActivityAlertMessages } from './types';\n\nfunction dateTimeFormatter(locale: string) {\n return (date: Date, timeZone: string) =>\n new Intl.DateTimeFormat(locale, { dateStyle: 'long', timeStyle: 'short', timeZone }).format(date);\n}\n\nexport const securityActivityAlertMessagesDe: SecurityActivityAlertMessages = {\n lang: 'de',\n subject: ({ activity, targetName }) => `${activity.title} – ${targetName}`,\n preview: ({ activity, occurredAt }) => `${activity.actorName} · ${occurredAt}`,\n summary: ({ activity, occurredAt }) => `${activity.actorName} hat am ${occurredAt} eine sicherheitsrelevante Änderung vorgenommen.`,\n guidance: () => 'Wenn du diese Änderung nicht erwartet hast, prüfe die Aktivität jetzt.',\n reviewButton: 'Aktivität prüfen',\n activityLogHint: (link) => <>Alle sicherheitsrelevanten Aktivitäten findest du im {link('Aktivitätsprotokoll')}.</>,\n footer: ({ target }) =>\n target.type === 'workspace'\n ? 'Wir haben dir diese E-Mail gesendet, um dich als Administrator über wichtige Änderungen in deinem Workspace zu informieren.'\n : 'Wir haben dir diese E-Mail gesendet, um dich über wichtige Änderungen an deinem hintoric-Konto zu informieren.',\n formatDateTime: dateTimeFormatter('de-DE'),\n};\n\nexport const securityActivityAlertMessagesEn: SecurityActivityAlertMessages = {\n lang: 'en',\n subject: ({ activity, targetName }) => `${activity.title} – ${targetName}`,\n preview: ({ activity, occurredAt }) => `${activity.actorName} · ${occurredAt}`,\n summary: ({ activity, occurredAt }) => `${activity.actorName} made a security-relevant change on ${occurredAt}.`,\n guidance: () => \"If you didn't expect this change, review the activity now.\",\n reviewButton: 'Review activity',\n activityLogHint: (link) => <>You can see all security-relevant activity in the {link('activity log')}.</>,\n footer: ({ target }) =>\n target.type === 'workspace'\n ? 'We sent you this email to let you know, as an admin, about important changes in your workspace.'\n : 'We sent you this email to let you know about important changes to your hintoric account.',\n formatDateTime: dateTimeFormatter('en-GB'),\n};\n","import { Button } from '../../components/Button';\nimport { HintoricLogo } from '../../components/HintoricLogo';\nimport { Layout } from '../../components/Layout';\nimport { Typography } from '../../components/Typography';\nimport { renderEmail } from '../../render';\nimport { emailFonts } from '../../tokens';\nimport type { WaitlistWelcomeProps } from './types';\n\n/**\n * Sent right after someone joins the waitlist: a thank-you, what happens\n * next, one button to the website. Centred, like the other single-purpose\n * mails — logo, heading, two short paragraphs, button, sign-off.\n */\n/** @deprecated New consumers should not use this template. */\nexport function WaitlistWelcomeEmail(props: WaitlistWelcomeProps) {\n const { messages } = props;\n return (\n <Layout\n lang={messages.lang}\n preview={messages.preview}\n colorScheme={props.colorScheme}\n unsubscribe={props.unsubscribeUrl && messages.unsubscribe ? { href: props.unsubscribeUrl, label: messages.unsubscribe } : undefined}\n footer={\n <Typography level=\"body-xs\" component=\"p\" textAlign=\"center\" textColor=\"icon\" style={{ fontWeight: 400 }}>\n {messages.footer}\n {props.legalNotice && (\n <>\n <br />\n {props.legalNotice}\n </>\n )}\n </Typography>\n }\n >\n <WaitlistWelcomeContent {...props} />\n </Layout>\n );\n}\n\n/** What goes inside the card, without the document — for in-app previews (render `ColorSchemeStyles` next to it). */\n/** @deprecated New consumers should not use this template. */\nexport function WaitlistWelcomeContent({ messages, websiteUrl }: WaitlistWelcomeProps) {\n return (\n <div style={{ textAlign: 'center' }}>\n <HintoricLogo />\n <Typography level=\"body-xs\" component=\"p\" textAlign=\"center\" textColor=\"icon\" style={{ margin: '24px 0 8px', fontWeight: 400 }}>\n {messages.eyebrow}\n </Typography>\n <Typography level=\"h3\" component=\"h1\" style={{ margin: '0 0 16px', fontFamily: emailFonts.heading }}>\n {messages.heading}\n </Typography>\n <Typography level=\"body-sm\" style={{ marginBottom: '12px' }}>\n {messages.body1}\n </Typography>\n <Typography level=\"body-sm\" style={{ marginBottom: '24px' }}>\n {messages.body2}\n </Typography>\n <Button href={websiteUrl} size=\"lg\" fullWidth>\n {messages.cta}\n </Button>\n <Typography level=\"body-xs\" component=\"p\" textAlign=\"center\" textColor=\"icon\" style={{ margin: '24px 0 0', fontWeight: 400 }}>\n {messages.signoff}\n </Typography>\n </div>\n );\n}\n\nexport interface RenderedWaitlistWelcome {\n subject: string;\n html: string;\n text: string;\n}\n\n/** Subject, HTML and plain-text body in one call — what SES, Resend and the like take. */\n/** @deprecated New consumers should not use this template. */\nexport async function renderWaitlistWelcome(props: WaitlistWelcomeProps): Promise<RenderedWaitlistWelcome> {\n const { html, text } = await renderEmail(<WaitlistWelcomeEmail {...props} />);\n return { subject: props.messages.subject, html, text };\n}\n","import type { WaitlistWelcomeMessages } from './types';\n\n/** @deprecated New consumers should not use this template. */\nexport const waitlistWelcomeMessagesDe: WaitlistWelcomeMessages = {\n lang: 'de',\n subject: 'Du bist auf der Hintoric-Warteliste',\n preview: 'Willkommen an Bord — Hintoric',\n eyebrow: 'Danke, dass du dabei bist',\n heading: 'Willkommen bei Hintoric',\n body1: 'Alles erledigt. Sobald dein Platz frei wird, melden wir uns sofort — du bist einer der Ersten, die Hintoric ausprobieren dürfen.',\n body2: 'Bis dahin halten wir dich auf dem Laufenden. Wenn jemand aus deinem Umfeld auch dazugehören sollte, leite diese Mail gerne weiter.',\n cta: 'Zu hintoric.com',\n signoff: '— Dein Hintoric-Team',\n footer: 'Wir haben dir diese E-Mail gesendet, weil du dich für die Hintoric-Warteliste eingetragen hast.',\n unsubscribe: 'Abmelden',\n};\n\n/** @deprecated New consumers should not use this template. */\nexport const waitlistWelcomeMessagesEn: WaitlistWelcomeMessages = {\n lang: 'en',\n subject: \"You're on the Hintoric waitlist\",\n preview: 'Welcome aboard — Hintoric',\n eyebrow: 'Thanks for joining',\n heading: 'Welcome to Hintoric',\n body1: \"You're all set. As soon as your spot opens up we'll let you know — you'll be one of the first to try Hintoric.\",\n body2: \"Until then we'll keep you posted. If someone you know should be on the list too, feel free to forward this email.\",\n cta: 'Go to hintoric.com',\n signoff: '— Your Hintoric team',\n footer: 'We sent you this email because you signed up for the Hintoric waitlist.',\n unsubscribe: 'Unsubscribe',\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"WaitlistWelcomeEmail.d.ts","sourceRoot":"","sources":["../../../src/templates/WaitlistWelcome/WaitlistWelcomeEmail.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEpD;;;;GAIG;AACH,8DAA8D;AAC9D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,oBAAoB,+BAsB/D;AAED,qHAAqH;AACrH,8DAA8D;AAC9D,wBAAgB,sBAAsB,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,oBAAoB,+BAwBpF;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,0FAA0F;AAC1F,8DAA8D;AAC9D,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAGzG"}
1
+ {"version":3,"file":"WaitlistWelcomeEmail.d.ts","sourceRoot":"","sources":["../../../src/templates/WaitlistWelcome/WaitlistWelcomeEmail.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAEpD;;;;GAIG;AACH,8DAA8D;AAC9D,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,oBAAoB,+BAuB/D;AAED,qHAAqH;AACrH,8DAA8D;AAC9D,wBAAgB,sBAAsB,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,oBAAoB,+BAwBpF;AAED,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,0FAA0F;AAC1F,8DAA8D;AAC9D,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAGzG"}
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/templates/WaitlistWelcome/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAEvD,8DAA8D;AAC9D,eAAO,MAAM,yBAAyB,EAAE,uBAWvC,CAAC;AAEF,8DAA8D;AAC9D,eAAO,MAAM,yBAAyB,EAAE,uBAWvC,CAAC"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../src/templates/WaitlistWelcome/messages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAEvD,8DAA8D;AAC9D,eAAO,MAAM,yBAAyB,EAAE,uBAYvC,CAAC;AAEF,8DAA8D;AAC9D,eAAO,MAAM,yBAAyB,EAAE,uBAYvC,CAAC"}
@@ -19,11 +19,15 @@ export interface WaitlistWelcomeMessages {
19
19
  signoff: string;
20
20
  /** Under the card: why the reader got this mail. */
21
21
  footer: string;
22
+ /** Label of the unsubscribe link under the footer. Shown only when `unsubscribeUrl` is set. */
23
+ unsubscribe?: string;
22
24
  }
23
25
  export interface WaitlistWelcomeProps {
24
26
  messages: WaitlistWelcomeMessages;
25
27
  /** Where the button leads — normally the marketing site. */
26
28
  websiteUrl: string;
29
+ /** One-click opt-out. When set (and `messages.unsubscribe` is), the footer ends with an unsubscribe link. */
30
+ unsubscribeUrl?: string;
27
31
  /** The sender's legal line under the footer — company, address. */
28
32
  legalNotice?: string;
29
33
  /** Previews only — see `Layout`. */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/templates/WaitlistWelcome/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,uBAAuB,CAAC;IAClC,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAChC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/templates/WaitlistWelcome/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,uBAAuB;IACtC,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,MAAM,EAAE,MAAM,CAAC;IACf,+FAA+F;IAC/F,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,uBAAuB,CAAC;IAClC,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;IACnB,6GAA6G;IAC7G,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAChC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hintoric/email",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "Transactional email components in @hintoric/ui's look, built on react-email.",
5
5
  "type": "module",
6
6
  "license": "MIT",