@resq-systems/email-templates 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +236 -0
  2. package/lib/contract.d.ts +125 -0
  3. package/lib/contract.d.ts.map +1 -0
  4. package/lib/contract.js +29 -0
  5. package/lib/contract.js.map +1 -0
  6. package/lib/emails/incident-alert.d.ts +8 -0
  7. package/lib/emails/incident-alert.d.ts.map +1 -0
  8. package/lib/emails/incident-alert.js +44 -0
  9. package/lib/emails/incident-alert.js.map +1 -0
  10. package/lib/emails/index.d.ts +13 -0
  11. package/lib/emails/index.js +13 -0
  12. package/lib/emails/mission-approval.d.ts +8 -0
  13. package/lib/emails/mission-approval.d.ts.map +1 -0
  14. package/lib/emails/mission-approval.js +46 -0
  15. package/lib/emails/mission-approval.js.map +1 -0
  16. package/lib/emails/new-device-login.d.ts +8 -0
  17. package/lib/emails/new-device-login.d.ts.map +1 -0
  18. package/lib/emails/new-device-login.js +47 -0
  19. package/lib/emails/new-device-login.js.map +1 -0
  20. package/lib/emails/notification.d.ts +8 -0
  21. package/lib/emails/notification.d.ts.map +1 -0
  22. package/lib/emails/notification.js +33 -0
  23. package/lib/emails/notification.js.map +1 -0
  24. package/lib/emails/org-invitation.d.ts +8 -0
  25. package/lib/emails/org-invitation.d.ts.map +1 -0
  26. package/lib/emails/org-invitation.js +41 -0
  27. package/lib/emails/org-invitation.js.map +1 -0
  28. package/lib/emails/otp.d.ts +11 -0
  29. package/lib/emails/otp.d.ts.map +1 -0
  30. package/lib/emails/otp.js +37 -0
  31. package/lib/emails/otp.js.map +1 -0
  32. package/lib/emails/password-changed.d.ts +8 -0
  33. package/lib/emails/password-changed.d.ts.map +1 -0
  34. package/lib/emails/password-changed.js +36 -0
  35. package/lib/emails/password-changed.js.map +1 -0
  36. package/lib/emails/password-reset.d.ts +8 -0
  37. package/lib/emails/password-reset.d.ts.map +1 -0
  38. package/lib/emails/password-reset.js +37 -0
  39. package/lib/emails/password-reset.js.map +1 -0
  40. package/lib/emails/primitives.d.ts +94 -0
  41. package/lib/emails/primitives.d.ts.map +1 -0
  42. package/lib/emails/primitives.js +233 -0
  43. package/lib/emails/primitives.js.map +1 -0
  44. package/lib/emails/theme.d.ts +89 -0
  45. package/lib/emails/theme.d.ts.map +1 -0
  46. package/lib/emails/theme.js +93 -0
  47. package/lib/emails/theme.js.map +1 -0
  48. package/lib/emails/tokens.d.ts +65 -0
  49. package/lib/emails/tokens.d.ts.map +1 -0
  50. package/lib/emails/tokens.js +46 -0
  51. package/lib/emails/tokens.js.map +1 -0
  52. package/lib/emails/welcome.d.ts +8 -0
  53. package/lib/emails/welcome.d.ts.map +1 -0
  54. package/lib/emails/welcome.js +32 -0
  55. package/lib/emails/welcome.js.map +1 -0
  56. package/lib/index.d.ts +8 -0
  57. package/lib/index.js +8 -0
  58. package/lib/mailer.d.ts +89 -0
  59. package/lib/mailer.d.ts.map +1 -0
  60. package/lib/mailer.js +85 -0
  61. package/lib/mailer.js.map +1 -0
  62. package/lib/node_modules/@react-email/tailwind/dist/index.d.ts +9 -0
  63. package/lib/node_modules/@react-email/tailwind/dist/index.d.ts.map +1 -0
  64. package/lib/node_modules/tailwindcss/dist/colors.d.ts +349 -0
  65. package/lib/node_modules/tailwindcss/dist/colors.d.ts.map +1 -0
  66. package/lib/node_modules/tailwindcss/dist/lib.d.ts +6 -0
  67. package/lib/node_modules/tailwindcss/dist/lib.d.ts.map +1 -0
  68. package/lib/node_modules/tailwindcss/dist/resolve-config-QUZ9b-Gn.d.ts +29 -0
  69. package/lib/node_modules/tailwindcss/dist/resolve-config-QUZ9b-Gn.d.ts.map +1 -0
  70. package/lib/node_modules/tailwindcss/dist/types-DWdTiksJ.d.ts +126 -0
  71. package/lib/node_modules/tailwindcss/dist/types-DWdTiksJ.d.ts.map +1 -0
  72. package/lib/registry.d.ts +25 -0
  73. package/lib/registry.d.ts.map +1 -0
  74. package/lib/registry.js +26 -0
  75. package/lib/registry.js.map +1 -0
  76. package/lib/render.d.ts +13 -0
  77. package/lib/render.d.ts.map +1 -0
  78. package/lib/render.js +29 -0
  79. package/lib/render.js.map +1 -0
  80. package/lib/schemas.d.ts +86 -0
  81. package/lib/schemas.d.ts.map +1 -0
  82. package/lib/schemas.js +104 -0
  83. package/lib/schemas.js.map +1 -0
  84. package/lib/send/index.d.ts +4 -0
  85. package/lib/send/index.js +3 -0
  86. package/lib/send/resend-sender.d.ts +14 -0
  87. package/lib/send/resend-sender.d.ts.map +1 -0
  88. package/lib/send/resend-sender.js +76 -0
  89. package/lib/send/resend-sender.js.map +1 -0
  90. package/lib/send/send-email.d.ts +19 -0
  91. package/lib/send/send-email.d.ts.map +1 -0
  92. package/lib/send/send-email.js +67 -0
  93. package/lib/send/send-email.js.map +1 -0
  94. package/lib/send/sender.d.ts +58 -0
  95. package/lib/send/sender.d.ts.map +1 -0
  96. package/lib/send/sender.js +0 -0
  97. package/lib/suite.d.ts +130 -0
  98. package/lib/suite.d.ts.map +1 -0
  99. package/lib/suite.js +28 -0
  100. package/lib/suite.js.map +1 -0
  101. package/lib/templates.d.ts +131 -0
  102. package/lib/templates.d.ts.map +1 -0
  103. package/lib/templates.js +98 -0
  104. package/lib/templates.js.map +1 -0
  105. package/package.json +95 -0
@@ -0,0 +1,33 @@
1
+ import { Email } from "./primitives.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ //#region src/emails/notification.tsx
4
+ const severityClass = {
5
+ info: "text-info",
6
+ success: "text-success",
7
+ warning: "text-warning",
8
+ error: "text-danger"
9
+ };
10
+ /** Generic notification / alert email with an optional call-to-action. */
11
+ function NotificationEmail({ title, body, severity = "info", actionUrl, actionLabel }) {
12
+ return /* @__PURE__ */ jsxs(Email.Shell, {
13
+ preview: title,
14
+ children: [
15
+ /* @__PURE__ */ jsx(Email.Header, {}),
16
+ /* @__PURE__ */ jsx(Email.Text, {
17
+ className: `mb-2 text-xs font-bold uppercase tracking-wide ${severityClass[severity]}`,
18
+ children: severity
19
+ }),
20
+ /* @__PURE__ */ jsx(Email.Title, { children: title }),
21
+ /* @__PURE__ */ jsx(Email.Paragraph, { children: body }),
22
+ actionUrl ? /* @__PURE__ */ jsx(Email.CTA, {
23
+ href: actionUrl,
24
+ children: actionLabel ?? "View details"
25
+ }) : null,
26
+ /* @__PURE__ */ jsx(Email.LegalFooter, { reason: "You are receiving this notification because of recent activity on your ResQ Systems account." })
27
+ ]
28
+ });
29
+ }
30
+ //#endregion
31
+ export { NotificationEmail };
32
+
33
+ //# sourceMappingURL=notification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification.js","names":[],"sources":["../../src/emails/notification.tsx"],"sourcesContent":["/**\n * Copyright 2026 ResQ Systems, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { NotificationData } from \"../schemas.js\";\nimport { Email } from \"./primitives.js\";\n\nexport type NotificationEmailProps = NotificationData;\n\nconst severityClass: Record<\"info\" | \"success\" | \"warning\" | \"error\", string> = {\n\tinfo: \"text-info\",\n\tsuccess: \"text-success\",\n\twarning: \"text-warning\",\n\terror: \"text-danger\",\n};\n\n/** Generic notification / alert email with an optional call-to-action. */\nexport function NotificationEmail({\n\ttitle,\n\tbody,\n\tseverity = \"info\",\n\tactionUrl,\n\tactionLabel,\n}: NotificationEmailProps) {\n\treturn (\n\t\t<Email.Shell preview={title}>\n\t\t\t<Email.Header />\n\t\t\t<Email.Text\n\t\t\t\tclassName={`mb-2 text-xs font-bold uppercase tracking-wide ${severityClass[severity]}`}\n\t\t\t>\n\t\t\t\t{severity}\n\t\t\t</Email.Text>\n\t\t\t<Email.Title>{title}</Email.Title>\n\t\t\t<Email.Paragraph>{body}</Email.Paragraph>\n\t\t\t{actionUrl ? <Email.CTA href={actionUrl}>{actionLabel ?? \"View details\"}</Email.CTA> : null}\n\t\t\t<Email.LegalFooter reason=\"You are receiving this notification because of recent activity on your ResQ Systems account.\" />\n\t\t</Email.Shell>\n\t);\n}\n"],"mappings":";;;AAqBA,MAAM,gBAA0E;CAC/E,MAAM;CACN,SAAS;CACT,SAAS;CACT,OAAO;AACR;;AAGA,SAAgB,kBAAkB,EACjC,OACA,MACA,WAAW,QACX,WACA,eAC0B;CAC1B,OACC,qBAAC,MAAM,OAAP;EAAa,SAAS;YAAtB;GACC,oBAAC,MAAM,QAAP,CAAe,CAAA;GACf,oBAAC,MAAM,MAAP;IACC,WAAW,kDAAkD,cAAc;cAE1E;GACU,CAAA;GACZ,oBAAC,MAAM,OAAP,EAAA,UAAc,MAAmB,CAAA;GACjC,oBAAC,MAAM,WAAP,EAAA,UAAkB,KAAsB,CAAA;GACvC,YAAY,oBAAC,MAAM,KAAP;IAAW,MAAM;cAAY,eAAe;GAA0B,CAAA,IAAI;GACvF,oBAAC,MAAM,aAAP,EAAmB,QAAO,+FAAgG,CAAA;EAC9G;;AAEf"}
@@ -0,0 +1,8 @@
1
+ import { OrgInvitationData } from "../schemas.js";
2
+ //#region src/emails/org-invitation.d.ts
3
+ type OrgInvitationEmailProps = OrgInvitationData;
4
+ /** Invitation to join a ResQ Systems organization / team. */
5
+ declare function OrgInvitationEmail({ orgName, inviterName, orgRole, acceptUrl, expiresInDays }: OrgInvitationEmailProps): import("react").JSX.Element;
6
+ //#endregion
7
+ export { OrgInvitationEmail, OrgInvitationEmailProps };
8
+ //# sourceMappingURL=org-invitation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"org-invitation.d.ts","names":[],"sources":["../../src/emails/org-invitation.tsx"],"mappings":";;KAmBY,0BAA0B;;iBAGtB,qBACf,SACA,aACA,SACA,WACA,iBACE,0CAAuB,IAAA"}
@@ -0,0 +1,41 @@
1
+ import { Email } from "./primitives.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ //#region src/emails/org-invitation.tsx
4
+ /** Invitation to join a ResQ Systems organization / team. */
5
+ function OrgInvitationEmail({ orgName, inviterName, orgRole, acceptUrl = "https://app.resq.software/invitations/accept", expiresInDays }) {
6
+ const inviterPhrase = inviterName ? `${inviterName} invited you` : "You have been invited";
7
+ const reason = inviterName ? `You are receiving this email because ${inviterName} invited you to join ${orgName} on ResQ Systems.` : `You are receiving this email because you were invited to join ${orgName} on ResQ Systems.`;
8
+ return /* @__PURE__ */ jsxs(Email.Shell, {
9
+ preview: `You're invited to join ${orgName} on ResQ Systems`,
10
+ children: [
11
+ /* @__PURE__ */ jsx(Email.Header, {}),
12
+ /* @__PURE__ */ jsxs(Email.Title, { children: ["You're invited to join ", orgName] }),
13
+ /* @__PURE__ */ jsxs(Email.Paragraph, { children: [
14
+ inviterPhrase,
15
+ " to join ",
16
+ orgName,
17
+ " on ResQ Systems",
18
+ orgRole ? ` as ${orgRole}` : "",
19
+ "."
20
+ ] }),
21
+ /* @__PURE__ */ jsx(Email.CTA, {
22
+ href: acceptUrl,
23
+ children: "Accept invitation"
24
+ }),
25
+ expiresInDays ? /* @__PURE__ */ jsxs(Email.Paragraph, { children: [
26
+ "This invitation expires in ",
27
+ expiresInDays,
28
+ " days."
29
+ ] }) : null,
30
+ /* @__PURE__ */ jsx(Email.Paragraph, { children: "Weren't expecting this? You can safely ignore this email." }),
31
+ /* @__PURE__ */ jsx(Email.LegalFooter, {
32
+ category: "transactional",
33
+ reason
34
+ })
35
+ ]
36
+ });
37
+ }
38
+ //#endregion
39
+ export { OrgInvitationEmail };
40
+
41
+ //# sourceMappingURL=org-invitation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"org-invitation.js","names":[],"sources":["../../src/emails/org-invitation.tsx"],"sourcesContent":["/**\n * Copyright 2026 ResQ Systems, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { OrgInvitationData } from \"../schemas.js\";\nimport { Email } from \"./primitives.js\";\n\nexport type OrgInvitationEmailProps = OrgInvitationData;\n\n/** Invitation to join a ResQ Systems organization / team. */\nexport function OrgInvitationEmail({\n\torgName,\n\tinviterName,\n\torgRole,\n\tacceptUrl = \"https://app.resq.software/invitations/accept\",\n\texpiresInDays,\n}: OrgInvitationEmailProps) {\n\tconst inviterPhrase = inviterName ? `${inviterName} invited you` : \"You have been invited\";\n\tconst reason = inviterName\n\t\t? `You are receiving this email because ${inviterName} invited you to join ${orgName} on ResQ Systems.`\n\t\t: `You are receiving this email because you were invited to join ${orgName} on ResQ Systems.`;\n\n\treturn (\n\t\t<Email.Shell preview={`You're invited to join ${orgName} on ResQ Systems`}>\n\t\t\t<Email.Header />\n\t\t\t<Email.Title>You're invited to join {orgName}</Email.Title>\n\t\t\t<Email.Paragraph>\n\t\t\t\t{inviterPhrase} to join {orgName} on ResQ Systems{orgRole ? ` as ${orgRole}` : \"\"}.\n\t\t\t</Email.Paragraph>\n\t\t\t<Email.CTA href={acceptUrl}>Accept invitation</Email.CTA>\n\t\t\t{expiresInDays ? (\n\t\t\t\t<Email.Paragraph>This invitation expires in {expiresInDays} days.</Email.Paragraph>\n\t\t\t) : null}\n\t\t\t<Email.Paragraph>Weren't expecting this? You can safely ignore this email.</Email.Paragraph>\n\t\t\t<Email.LegalFooter category=\"transactional\" reason={reason} />\n\t\t</Email.Shell>\n\t);\n}\n"],"mappings":";;;;AAsBA,SAAgB,mBAAmB,EAClC,SACA,aACA,SACA,YAAY,gDACZ,iBAC2B;CAC3B,MAAM,gBAAgB,cAAc,GAAG,YAAY,gBAAgB;CACnE,MAAM,SAAS,cACZ,wCAAwC,YAAY,uBAAuB,QAAQ,qBACnF,iEAAiE,QAAQ;CAE5E,OACC,qBAAC,MAAM,OAAP;EAAa,SAAS,0BAA0B,QAAQ;YAAxD;GACC,oBAAC,MAAM,QAAP,CAAe,CAAA;GACf,qBAAC,MAAM,OAAP,EAAA,UAAA,CAAa,2BAAwB,OAAqB,EAAA,CAAA;GAC1D,qBAAC,MAAM,WAAP,EAAA,UAAA;IACE;IAAc;IAAU;IAAQ;IAAiB,UAAU,OAAO,YAAY;IAAG;GAClE,EAAA,CAAA;GACjB,oBAAC,MAAM,KAAP;IAAW,MAAM;cAAW;GAA4B,CAAA;GACvD,gBACA,qBAAC,MAAM,WAAP,EAAA,UAAA;IAAiB;IAA4B;IAAc;GAAuB,EAAA,CAAA,IAC/E;GACJ,oBAAC,MAAM,WAAP,EAAA,UAAiB,4DAA0E,CAAA;GAC3F,oBAAC,MAAM,aAAP;IAAmB,UAAS;IAAwB;GAAS,CAAA;EACjD;;AAEf"}
@@ -0,0 +1,11 @@
1
+ import { OtpData } from "../schemas.js";
2
+ //#region src/emails/otp.d.ts
3
+ type OtpEmailProps = OtpData;
4
+ /**
5
+ * One-time verification code email. Default prop values make it previewable via
6
+ * `email dev`.
7
+ */
8
+ declare function OtpEmail({ code, firstName, expiresInMinutes }: OtpEmailProps): import("react").JSX.Element;
9
+ //#endregion
10
+ export { OtpEmail, OtpEmailProps };
11
+ //# sourceMappingURL=otp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otp.d.ts","names":[],"sources":["../../src/emails/otp.tsx"],"mappings":";;KAmBY,gBAAgB;;;;;iBAMZ,WAAW,MAAiB,WAAW,oBAAyB,gCAAa,IAAA"}
@@ -0,0 +1,37 @@
1
+ import { Email } from "./primitives.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ //#region src/emails/otp.tsx
4
+ /**
5
+ * One-time verification code email. Default prop values make it previewable via
6
+ * `email dev`.
7
+ */
8
+ function OtpEmail({ code = "123456", firstName, expiresInMinutes = 10 }) {
9
+ return /* @__PURE__ */ jsxs(Email.Shell, {
10
+ preview: "Your ResQ Systems verification code",
11
+ children: [
12
+ /* @__PURE__ */ jsx(Email.Header, {}),
13
+ /* @__PURE__ */ jsx(Email.Title, { children: "Verification code" }),
14
+ firstName ? /* @__PURE__ */ jsxs(Email.Paragraph, { children: [
15
+ "Hi ",
16
+ firstName,
17
+ ","
18
+ ] }) : null,
19
+ /* @__PURE__ */ jsx(Email.Paragraph, { children: "Use this one-time code to continue." }),
20
+ /* @__PURE__ */ jsx(Email.Code, { children: code }),
21
+ expiresInMinutes ? /* @__PURE__ */ jsxs(Email.Paragraph, { children: [
22
+ "This code expires in ",
23
+ expiresInMinutes,
24
+ " minutes."
25
+ ] }) : null,
26
+ /* @__PURE__ */ jsx(Email.Paragraph, { children: "If you didn't request this code, ignore this email." }),
27
+ /* @__PURE__ */ jsx(Email.LegalFooter, {
28
+ category: "transactional",
29
+ reason: "You received this email because a verification code was requested for your account."
30
+ })
31
+ ]
32
+ });
33
+ }
34
+ //#endregion
35
+ export { OtpEmail };
36
+
37
+ //# sourceMappingURL=otp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otp.js","names":[],"sources":["../../src/emails/otp.tsx"],"sourcesContent":["/**\n * Copyright 2026 ResQ Systems, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { OtpData } from \"../schemas.js\";\nimport { Email } from \"./primitives.js\";\n\nexport type OtpEmailProps = OtpData;\n\n/**\n * One-time verification code email. Default prop values make it previewable via\n * `email dev`.\n */\nexport function OtpEmail({ code = \"123456\", firstName, expiresInMinutes = 10 }: OtpEmailProps) {\n\treturn (\n\t\t<Email.Shell preview=\"Your ResQ Systems verification code\">\n\t\t\t<Email.Header />\n\t\t\t<Email.Title>Verification code</Email.Title>\n\t\t\t{firstName ? <Email.Paragraph>Hi {firstName},</Email.Paragraph> : null}\n\t\t\t<Email.Paragraph>Use this one-time code to continue.</Email.Paragraph>\n\t\t\t<Email.Code>{code}</Email.Code>\n\t\t\t{expiresInMinutes ? (\n\t\t\t\t<Email.Paragraph>This code expires in {expiresInMinutes} minutes.</Email.Paragraph>\n\t\t\t) : null}\n\t\t\t<Email.Paragraph>If you didn't request this code, ignore this email.</Email.Paragraph>\n\t\t\t<Email.LegalFooter\n\t\t\t\tcategory=\"transactional\"\n\t\t\t\treason=\"You received this email because a verification code was requested for your account.\"\n\t\t\t/>\n\t\t</Email.Shell>\n\t);\n}\n"],"mappings":";;;;;;;AAyBA,SAAgB,SAAS,EAAE,OAAO,UAAU,WAAW,mBAAmB,MAAqB;CAC9F,OACC,qBAAC,MAAM,OAAP;EAAa,SAAQ;YAArB;GACC,oBAAC,MAAM,QAAP,CAAe,CAAA;GACf,oBAAC,MAAM,OAAP,EAAA,UAAa,oBAA8B,CAAA;GAC1C,YAAY,qBAAC,MAAM,WAAP,EAAA,UAAA;IAAiB;IAAI;IAAU;GAAkB,EAAA,CAAA,IAAI;GAClE,oBAAC,MAAM,WAAP,EAAA,UAAiB,sCAAoD,CAAA;GACrE,oBAAC,MAAM,MAAP,EAAA,UAAa,KAAiB,CAAA;GAC7B,mBACA,qBAAC,MAAM,WAAP,EAAA,UAAA;IAAiB;IAAsB;IAAiB;GAA0B,EAAA,CAAA,IAC/E;GACJ,oBAAC,MAAM,WAAP,EAAA,UAAiB,sDAAoE,CAAA;GACrF,oBAAC,MAAM,aAAP;IACC,UAAS;IACT,QAAO;GACP,CAAA;EACW;;AAEf"}
@@ -0,0 +1,8 @@
1
+ import { PasswordChangedData } from "../schemas.js";
2
+ //#region src/emails/password-changed.d.ts
3
+ type PasswordChangedEmailProps = PasswordChangedData;
4
+ /** Security notice confirming the account password was changed. */
5
+ declare function PasswordChangedEmail({ firstName, changedAt, secureAccountUrl }: PasswordChangedEmailProps): import("react").JSX.Element;
6
+ //#endregion
7
+ export { PasswordChangedEmail, PasswordChangedEmailProps };
8
+ //# sourceMappingURL=password-changed.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password-changed.d.ts","names":[],"sources":["../../src/emails/password-changed.tsx"],"mappings":";;KAmBY,4BAA4B;;iBAGxB,uBACf,WACA,WACA,oBACE,4CAAyB,IAAA"}
@@ -0,0 +1,36 @@
1
+ import { Email } from "./primitives.js";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ //#region src/emails/password-changed.tsx
4
+ /** Security notice confirming the account password was changed. */
5
+ function PasswordChangedEmail({ firstName, changedAt, secureAccountUrl }) {
6
+ return /* @__PURE__ */ jsxs(Email.Shell, {
7
+ preview: "Your ResQ Systems password was changed",
8
+ children: [
9
+ /* @__PURE__ */ jsx(Email.Header, {}),
10
+ /* @__PURE__ */ jsx(Email.Title, { children: "Your password was changed" }),
11
+ firstName ? /* @__PURE__ */ jsxs(Email.Paragraph, { children: [
12
+ "Hi ",
13
+ firstName,
14
+ ","
15
+ ] }) : null,
16
+ /* @__PURE__ */ jsxs(Email.Paragraph, { children: [
17
+ "The password on your ResQ Systems account was changed",
18
+ changedAt ? ` on ${changedAt}` : "",
19
+ ". If you made this change, no further action is needed."
20
+ ] }),
21
+ secureAccountUrl ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Email.Paragraph, { children: "If you didn't change your password, your account may be at risk — secure it now." }), /* @__PURE__ */ jsx(Email.CTA, {
22
+ href: secureAccountUrl,
23
+ children: "Secure your account"
24
+ })] }) : /* @__PURE__ */ jsx(Email.Paragraph, { children: "If you didn't change your password, your account may be at risk. Please contact support immediately." }),
25
+ /* @__PURE__ */ jsx(Email.SupportLine, { children: "Didn't change your password?" }),
26
+ /* @__PURE__ */ jsx(Email.LegalFooter, {
27
+ category: "transactional",
28
+ reason: "You are receiving this email because the password on your ResQ Systems account was changed."
29
+ })
30
+ ]
31
+ });
32
+ }
33
+ //#endregion
34
+ export { PasswordChangedEmail };
35
+
36
+ //# sourceMappingURL=password-changed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password-changed.js","names":[],"sources":["../../src/emails/password-changed.tsx"],"sourcesContent":["/**\n * Copyright 2026 ResQ Systems, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { PasswordChangedData } from \"../schemas.js\";\nimport { Email } from \"./primitives.js\";\n\nexport type PasswordChangedEmailProps = PasswordChangedData;\n\n/** Security notice confirming the account password was changed. */\nexport function PasswordChangedEmail({\n\tfirstName,\n\tchangedAt,\n\tsecureAccountUrl,\n}: PasswordChangedEmailProps) {\n\treturn (\n\t\t<Email.Shell preview=\"Your ResQ Systems password was changed\">\n\t\t\t<Email.Header />\n\t\t\t<Email.Title>Your password was changed</Email.Title>\n\t\t\t{firstName ? <Email.Paragraph>Hi {firstName},</Email.Paragraph> : null}\n\t\t\t<Email.Paragraph>\n\t\t\t\tThe password on your ResQ Systems account was changed{changedAt ? ` on ${changedAt}` : \"\"}.\n\t\t\t\tIf you made this change, no further action is needed.\n\t\t\t</Email.Paragraph>\n\t\t\t{secureAccountUrl ? (\n\t\t\t\t<>\n\t\t\t\t\t<Email.Paragraph>\n\t\t\t\t\t\tIf you didn't change your password, your account may be at risk — secure it now.\n\t\t\t\t\t</Email.Paragraph>\n\t\t\t\t\t<Email.CTA href={secureAccountUrl}>Secure your account</Email.CTA>\n\t\t\t\t</>\n\t\t\t) : (\n\t\t\t\t<Email.Paragraph>\n\t\t\t\t\tIf you didn't change your password, your account may be at risk. Please contact support\n\t\t\t\t\timmediately.\n\t\t\t\t</Email.Paragraph>\n\t\t\t)}\n\t\t\t<Email.SupportLine>Didn't change your password?</Email.SupportLine>\n\t\t\t<Email.LegalFooter\n\t\t\t\tcategory=\"transactional\"\n\t\t\t\treason=\"You are receiving this email because the password on your ResQ Systems account was changed.\"\n\t\t\t/>\n\t\t</Email.Shell>\n\t);\n}\n"],"mappings":";;;;AAsBA,SAAgB,qBAAqB,EACpC,WACA,WACA,oBAC6B;CAC7B,OACC,qBAAC,MAAM,OAAP;EAAa,SAAQ;YAArB;GACC,oBAAC,MAAM,QAAP,CAAe,CAAA;GACf,oBAAC,MAAM,OAAP,EAAA,UAAa,4BAAsC,CAAA;GAClD,YAAY,qBAAC,MAAM,WAAP,EAAA,UAAA;IAAiB;IAAI;IAAU;GAAkB,EAAA,CAAA,IAAI;GAClE,qBAAC,MAAM,WAAP,EAAA,UAAA;IAAiB;IACsC,YAAY,OAAO,cAAc;IAAG;GAE1E,EAAA,CAAA;GAChB,mBACA,qBAAA,UAAA,EAAA,UAAA,CACC,oBAAC,MAAM,WAAP,EAAA,UAAiB,mFAEA,CAAA,GACjB,oBAAC,MAAM,KAAP;IAAW,MAAM;cAAkB;GAA8B,CAAA,CAChE,EAAA,CAAA,IAEF,oBAAC,MAAM,WAAP,EAAA,UAAiB,uGAGA,CAAA;GAElB,oBAAC,MAAM,aAAP,EAAA,UAAmB,+BAA+C,CAAA;GAClE,oBAAC,MAAM,aAAP;IACC,UAAS;IACT,QAAO;GACP,CAAA;EACW;;AAEf"}
@@ -0,0 +1,8 @@
1
+ import { PasswordResetData } from "../schemas.js";
2
+ //#region src/emails/password-reset.d.ts
3
+ type PasswordResetEmailProps = PasswordResetData;
4
+ /** Password reset email with a single call-to-action link. */
5
+ declare function PasswordResetEmail({ firstName, resetUrl, expiresInMinutes }: PasswordResetEmailProps): import("react").JSX.Element;
6
+ //#endregion
7
+ export { PasswordResetEmail, PasswordResetEmailProps };
8
+ //# sourceMappingURL=password-reset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password-reset.d.ts","names":[],"sources":["../../src/emails/password-reset.tsx"],"mappings":";;KAmBY,0BAA0B;;iBAGtB,qBACf,WACA,UACA,oBACE,0CAAuB,IAAA"}
@@ -0,0 +1,37 @@
1
+ import { Email } from "./primitives.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ //#region src/emails/password-reset.tsx
4
+ /** Password reset email with a single call-to-action link. */
5
+ function PasswordResetEmail({ firstName, resetUrl = "https://app.resq.example/reset", expiresInMinutes = 30 }) {
6
+ return /* @__PURE__ */ jsxs(Email.Shell, {
7
+ preview: "Reset your password",
8
+ children: [
9
+ /* @__PURE__ */ jsx(Email.Header, {}),
10
+ /* @__PURE__ */ jsx(Email.Title, { children: "Reset your password" }),
11
+ firstName ? /* @__PURE__ */ jsxs(Email.Paragraph, { children: [
12
+ "Hi ",
13
+ firstName,
14
+ ","
15
+ ] }) : null,
16
+ /* @__PURE__ */ jsx(Email.Paragraph, { children: "Someone requested a password reset for your account. Use the button below to choose a new password." }),
17
+ /* @__PURE__ */ jsx(Email.CTA, {
18
+ href: resetUrl,
19
+ children: "Reset password"
20
+ }),
21
+ /* @__PURE__ */ jsxs(Email.Paragraph, { children: [
22
+ "This link expires in ",
23
+ expiresInMinutes,
24
+ " minutes."
25
+ ] }),
26
+ /* @__PURE__ */ jsx(Email.Paragraph, { children: "If you didn't request this, your password is unchanged and you can ignore this email. If you're concerned about unauthorized access, reset your password to secure your account." }),
27
+ /* @__PURE__ */ jsx(Email.LegalFooter, {
28
+ category: "transactional",
29
+ reason: "You're receiving this email because a password reset was requested for your account."
30
+ })
31
+ ]
32
+ });
33
+ }
34
+ //#endregion
35
+ export { PasswordResetEmail };
36
+
37
+ //# sourceMappingURL=password-reset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password-reset.js","names":[],"sources":["../../src/emails/password-reset.tsx"],"sourcesContent":["/**\n * Copyright 2026 ResQ Systems, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { PasswordResetData } from \"../schemas.js\";\nimport { Email } from \"./primitives.js\";\n\nexport type PasswordResetEmailProps = PasswordResetData;\n\n/** Password reset email with a single call-to-action link. */\nexport function PasswordResetEmail({\n\tfirstName,\n\tresetUrl = \"https://app.resq.example/reset\",\n\texpiresInMinutes = 30,\n}: PasswordResetEmailProps) {\n\treturn (\n\t\t<Email.Shell preview=\"Reset your password\">\n\t\t\t<Email.Header />\n\t\t\t<Email.Title>Reset your password</Email.Title>\n\t\t\t{firstName ? <Email.Paragraph>Hi {firstName},</Email.Paragraph> : null}\n\t\t\t<Email.Paragraph>\n\t\t\t\tSomeone requested a password reset for your account. Use the button below to choose a new\n\t\t\t\tpassword.\n\t\t\t</Email.Paragraph>\n\t\t\t<Email.CTA href={resetUrl}>Reset password</Email.CTA>\n\t\t\t<Email.Paragraph>This link expires in {expiresInMinutes} minutes.</Email.Paragraph>\n\t\t\t<Email.Paragraph>\n\t\t\t\tIf you didn't request this, your password is unchanged and you can ignore this email. If\n\t\t\t\tyou're concerned about unauthorized access, reset your password to secure your account.\n\t\t\t</Email.Paragraph>\n\t\t\t<Email.LegalFooter\n\t\t\t\tcategory=\"transactional\"\n\t\t\t\treason=\"You're receiving this email because a password reset was requested for your account.\"\n\t\t\t/>\n\t\t</Email.Shell>\n\t);\n}\n"],"mappings":";;;;AAsBA,SAAgB,mBAAmB,EAClC,WACA,WAAW,kCACX,mBAAmB,MACQ;CAC3B,OACC,qBAAC,MAAM,OAAP;EAAa,SAAQ;YAArB;GACC,oBAAC,MAAM,QAAP,CAAe,CAAA;GACf,oBAAC,MAAM,OAAP,EAAA,UAAa,sBAAgC,CAAA;GAC5C,YAAY,qBAAC,MAAM,WAAP,EAAA,UAAA;IAAiB;IAAI;IAAU;GAAkB,EAAA,CAAA,IAAI;GAClE,oBAAC,MAAM,WAAP,EAAA,UAAiB,sGAGA,CAAA;GACjB,oBAAC,MAAM,KAAP;IAAW,MAAM;cAAU;GAAyB,CAAA;GACpD,qBAAC,MAAM,WAAP,EAAA,UAAA;IAAiB;IAAsB;IAAiB;GAA0B,EAAA,CAAA;GAClF,oBAAC,MAAM,WAAP,EAAA,UAAiB,mLAGA,CAAA;GACjB,oBAAC,MAAM,aAAP;IACC,UAAS;IACT,QAAO;GACP,CAAA;EACW;;AAEf"}
@@ -0,0 +1,94 @@
1
+ import { EmailCategory } from "../schemas.js";
2
+ import { EmailThemeOverride } from "./theme.js";
3
+ import { Hr, Link, Section, Text } from "@react-email/components";
4
+ import { ReactNode } from "react";
5
+ //#region src/emails/primitives.d.ts
6
+ interface ShellProps {
7
+ preview: string;
8
+ /** Per-render brand override, merged over the active theme (context or default). */
9
+ theme?: EmailThemeOverride;
10
+ children: ReactNode;
11
+ }
12
+ /** Outer document, resolved theme, preview text, and a single bordered card. */
13
+ declare function Shell({ preview, theme, children }: ShellProps): import("react").JSX.Element;
14
+ /** Brand lockup (logo + product wordmark) rendered at the top of the card. */
15
+ declare function Header(): import("react").JSX.Element;
16
+ declare function Title({ children }: {
17
+ children: ReactNode;
18
+ }): import("react").JSX.Element;
19
+ declare function Paragraph({ children }: {
20
+ children: ReactNode;
21
+ }): import("react").JSX.Element;
22
+ /**
23
+ * Role-based sign-off. Defaults to "— The {brand} team", derived from the active
24
+ * theme's org so a rebrand flows through. Keep copy neutral: no first-person
25
+ * promises or commitments (per the content & legal guide).
26
+ */
27
+ declare function Signature({ children }: {
28
+ children?: ReactNode;
29
+ }): import("react").JSX.Element;
30
+ /**
31
+ * Muted support-contact line for security notices, sourced from
32
+ * `theme.org.supportEmail` so there is always an actionable path even when a
33
+ * template's optional CTA is absent. `children` overrides the lead-in prompt.
34
+ */
35
+ declare function SupportLine({ children }: {
36
+ children?: ReactNode;
37
+ }): import("react").JSX.Element;
38
+ /** A large, letter-spaced code block for OTP / verification codes. */
39
+ declare function Code({ children }: {
40
+ children: ReactNode;
41
+ }): import("react").JSX.Element;
42
+ /**
43
+ * Plain-text fallback for a link/button — improves deliverability and works in
44
+ * clients that strip buttons. Renders the raw URL so it stays copy-pasteable.
45
+ */
46
+ declare function FallbackLink({ href }: {
47
+ href: string;
48
+ }): import("react").JSX.Element;
49
+ /** Primary call-to-action — brand primary, mono, uppercase, tracked (per style guide). */
50
+ declare function CTA({ href, children, fallback }: {
51
+ href: string;
52
+ children: ReactNode;
53
+ /** Render a copy-pasteable {@link FallbackLink} below the button (default `true`). */
54
+ fallback?: boolean;
55
+ }): import("react").JSX.Element;
56
+ declare function Footer({ children }: {
57
+ children: ReactNode;
58
+ }): import("react").JSX.Element;
59
+ /**
60
+ * Compliance footer: legal entity + registered postal address, Terms/Privacy
61
+ * links, and — for `marketing` sends only — an unsubscribe affordance. The
62
+ * effective category is the `category` prop, falling back to the active
63
+ * {@link EmailMessageContext}. All copy is small and muted.
64
+ */
65
+ declare function LegalFooter({ reason, category }: {
66
+ reason?: ReactNode;
67
+ category?: EmailCategory;
68
+ }): import("react").JSX.Element;
69
+ /**
70
+ * Compound email primitives. Templates compose only from these so styling stays
71
+ * consistent, theme-driven, and email-client safe. The raw react-email
72
+ * `Section`, `Text`, `Link`, and `Hr` are re-exported for templates that need
73
+ * finer control.
74
+ */
75
+ declare const Email: {
76
+ readonly Shell: typeof Shell;
77
+ readonly Header: typeof Header;
78
+ readonly Title: typeof Title;
79
+ readonly Paragraph: typeof Paragraph;
80
+ readonly Signature: typeof Signature;
81
+ readonly SupportLine: typeof SupportLine;
82
+ readonly Code: typeof Code;
83
+ readonly CTA: typeof CTA;
84
+ readonly FallbackLink: typeof FallbackLink;
85
+ readonly Footer: typeof Footer;
86
+ readonly LegalFooter: typeof LegalFooter;
87
+ readonly Section: typeof Section;
88
+ readonly Text: typeof Text;
89
+ readonly Link: typeof Link;
90
+ readonly Hr: typeof Hr;
91
+ };
92
+ //#endregion
93
+ export { Email };
94
+ //# sourceMappingURL=primitives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.d.ts","names":[],"sources":["../../src/emails/primitives.tsx"],"mappings":";;;;;UAyCU;EACT;;EAEA,QAAQ;EACR,UAAU;;;iBAIF,QAAQ,SAAS,OAAO,YAAY,6BAAU,IAAA;;iBAwB9C,0BAAM,IAAA;iBAkBN,QAAQ;EAAc,UAAU;oBAAW,IAAA;iBAQ3C,YAAY;EAAc,UAAU;oBAAW,IAAA;;;;;;iBAW/C,YAAY;EAAc,WAAW;oBAAW,IAAA;;;;;;iBAchD,cAAc;EAAc,WAAW;oBAAW,IAAA;;iBAclD,OAAO;EAAc,UAAU;oBAAW,IAAA;;;;;iBAc1C,eAAe;EAAU;oBAAc,IAAA;;iBAavC,MACR,MACA,UACA;EAEA;EACA,UAAU;;EAEV;oBACA,IAAA;iBAcQ,SAAS;EAAc,UAAU;oBAAW,IAAA;;;;;;;iBAe5C,cAAc,QAAQ;EAAc,SAAS;EAAW,WAAW;oBAAe,IAAA;;;;;;;cA6C9E;WACH,cAAc;WACd,eAAe;WACf,cAAc;WACd,kBAAkB;WAClB,kBAAkB;WAClB,oBAAoB;WACpB,aAAa;WACb,YAAY;WACZ,qBAAqB;WACrB,eAAe;WACf,oBAAoB;WACpB,gBAAgB;WAChB,aAAa;WACb,aAAa;WACb,WAAW"}
@@ -0,0 +1,233 @@
1
+ import { EmailMessageContext, EmailThemeContext, buildTailwindConfig, resolveEmailTheme } from "./theme.js";
2
+ import { Body, Button, Container, Head, Heading, Hr, Html, Img, Link, Preview, Section, Tailwind, Text } from "@react-email/components";
3
+ import { useContext } from "react";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/emails/primitives.tsx
6
+ /**
7
+ * Copyright 2026 ResQ Systems, Inc.
8
+ *
9
+ * Licensed under the Apache License, Version 2.0 (the "License");
10
+ * you may not use this file except in compliance with the License.
11
+ * You may obtain a copy of the License at
12
+ *
13
+ * http://www.apache.org/licenses/LICENSE-2.0
14
+ *
15
+ * Unless required by applicable law or agreed to in writing, software
16
+ * distributed under the License is distributed on an "AS IS" BASIS,
17
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ * See the License for the specific language governing permissions and
19
+ * limitations under the License.
20
+ */
21
+ /** Outer document, resolved theme, preview text, and a single bordered card. */
22
+ function Shell({ preview, theme, children }) {
23
+ const resolved = resolveEmailTheme(useContext(EmailThemeContext), theme);
24
+ const config = buildTailwindConfig(resolved);
25
+ return /* @__PURE__ */ jsxs(Html, {
26
+ lang: "en",
27
+ children: [/* @__PURE__ */ jsxs(Head, { children: [
28
+ /* @__PURE__ */ jsx("meta", {
29
+ name: "color-scheme",
30
+ content: "dark"
31
+ }),
32
+ /* @__PURE__ */ jsx("meta", {
33
+ name: "supported-color-schemes",
34
+ content: "dark"
35
+ }),
36
+ resolved.fontsHref ? /* @__PURE__ */ jsx("link", {
37
+ href: resolved.fontsHref,
38
+ rel: "stylesheet"
39
+ }) : null
40
+ ] }), /* @__PURE__ */ jsxs(Tailwind, {
41
+ config,
42
+ children: [/* @__PURE__ */ jsx(Preview, { children: preview }), /* @__PURE__ */ jsx(Body, {
43
+ className: "bg-background font-sans text-foreground",
44
+ children: /* @__PURE__ */ jsx(Container, {
45
+ className: "mx-auto my-10 max-w-xl rounded-xl border border-solid border-border bg-surface p-10",
46
+ children
47
+ })
48
+ })]
49
+ })]
50
+ });
51
+ }
52
+ /** Brand lockup (logo + product wordmark) rendered at the top of the card. */
53
+ function Header() {
54
+ const { org } = useContext(EmailThemeContext);
55
+ return /* @__PURE__ */ jsxs(Section, {
56
+ className: "mb-8",
57
+ children: [/* @__PURE__ */ jsx(Img, {
58
+ src: org.logoUrl,
59
+ width: "40",
60
+ height: "40",
61
+ alt: org.productName,
62
+ className: "inline-block align-middle"
63
+ }), /* @__PURE__ */ jsx(Text, {
64
+ className: "ml-3 inline-block align-middle font-display text-lg font-bold tracking-tight text-foreground",
65
+ children: org.productName
66
+ })]
67
+ });
68
+ }
69
+ function Title({ children }) {
70
+ return /* @__PURE__ */ jsx(Heading, {
71
+ className: "mb-4 font-display text-2xl font-bold tracking-tight text-foreground",
72
+ children
73
+ });
74
+ }
75
+ function Paragraph({ children }) {
76
+ return /* @__PURE__ */ jsx(Text, {
77
+ className: "mb-4 font-sans text-base leading-relaxed text-foreground",
78
+ children
79
+ });
80
+ }
81
+ /**
82
+ * Role-based sign-off. Defaults to "— The {brand} team", derived from the active
83
+ * theme's org so a rebrand flows through. Keep copy neutral: no first-person
84
+ * promises or commitments (per the content & legal guide).
85
+ */
86
+ function Signature({ children }) {
87
+ const { org } = useContext(EmailThemeContext);
88
+ return /* @__PURE__ */ jsx(Text, {
89
+ className: "mt-6 font-sans text-sm leading-relaxed text-muted",
90
+ children: children ?? `— The ${org.brandName} team`
91
+ });
92
+ }
93
+ /**
94
+ * Muted support-contact line for security notices, sourced from
95
+ * `theme.org.supportEmail` so there is always an actionable path even when a
96
+ * template's optional CTA is absent. `children` overrides the lead-in prompt.
97
+ */
98
+ function SupportLine({ children }) {
99
+ const { org } = useContext(EmailThemeContext);
100
+ return /* @__PURE__ */ jsxs(Text, {
101
+ className: "mb-4 font-sans text-sm leading-relaxed text-muted",
102
+ children: [
103
+ children ?? "Didn't do this?",
104
+ " Contact us at",
105
+ " ",
106
+ /* @__PURE__ */ jsx(Link, {
107
+ href: `mailto:${org.supportEmail}`,
108
+ className: "text-primary underline",
109
+ children: org.supportEmail
110
+ }),
111
+ "."
112
+ ]
113
+ });
114
+ }
115
+ /** A large, letter-spaced code block for OTP / verification codes. */
116
+ function Code({ children }) {
117
+ return /* @__PURE__ */ jsx(Section, {
118
+ className: "my-6 rounded-md border border-solid border-border bg-background py-4 text-center",
119
+ children: /* @__PURE__ */ jsx(Text, {
120
+ className: "font-mono text-3xl font-medium tracking-[8px] text-foreground",
121
+ children
122
+ })
123
+ });
124
+ }
125
+ /**
126
+ * Plain-text fallback for a link/button — improves deliverability and works in
127
+ * clients that strip buttons. Renders the raw URL so it stays copy-pasteable.
128
+ */
129
+ function FallbackLink({ href }) {
130
+ return /* @__PURE__ */ jsxs(Text, {
131
+ className: "mt-4 font-sans text-xs leading-relaxed text-muted",
132
+ children: [
133
+ "Or paste this link into your browser:",
134
+ /* @__PURE__ */ jsx("br", {}),
135
+ /* @__PURE__ */ jsx(Link, {
136
+ href,
137
+ className: "break-all text-primary",
138
+ children: href
139
+ })
140
+ ]
141
+ });
142
+ }
143
+ /** Primary call-to-action — brand primary, mono, uppercase, tracked (per style guide). */
144
+ function CTA({ href, children, fallback = true }) {
145
+ return /* @__PURE__ */ jsxs(Section, {
146
+ className: "my-6",
147
+ children: [/* @__PURE__ */ jsx(Button, {
148
+ href,
149
+ className: "box-border block rounded-md bg-primary px-8 py-3.5 text-center font-mono text-sm font-medium uppercase tracking-wide text-white no-underline",
150
+ children
151
+ }), fallback ? /* @__PURE__ */ jsx(FallbackLink, { href }) : null]
152
+ });
153
+ }
154
+ function Footer({ children }) {
155
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Hr, { className: "my-6 border-border" }), /* @__PURE__ */ jsx(Text, {
156
+ className: "font-sans text-xs leading-relaxed text-muted",
157
+ children
158
+ })] });
159
+ }
160
+ /**
161
+ * Compliance footer: legal entity + registered postal address, Terms/Privacy
162
+ * links, and — for `marketing` sends only — an unsubscribe affordance. The
163
+ * effective category is the `category` prop, falling back to the active
164
+ * {@link EmailMessageContext}. All copy is small and muted.
165
+ */
166
+ function LegalFooter({ reason, category }) {
167
+ const { org } = useContext(EmailThemeContext);
168
+ const message = useContext(EmailMessageContext);
169
+ const effectiveCategory = category ?? message.category;
170
+ const unsubscribeHref = message.unsubscribeUrl;
171
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
172
+ /* @__PURE__ */ jsx(Hr, { className: "my-6 border-border" }),
173
+ reason ? /* @__PURE__ */ jsx(Text, {
174
+ className: "mb-2 font-sans text-xs leading-relaxed text-muted",
175
+ children: reason
176
+ }) : null,
177
+ /* @__PURE__ */ jsx(Text, {
178
+ className: "mb-2 font-sans text-xs leading-relaxed text-muted",
179
+ children: org.registeredAddress
180
+ }),
181
+ /* @__PURE__ */ jsxs(Text, {
182
+ className: "mb-2 font-sans text-xs leading-relaxed text-muted",
183
+ children: [
184
+ /* @__PURE__ */ jsx(Link, {
185
+ href: org.termsUrl,
186
+ className: "text-muted underline",
187
+ children: "Terms"
188
+ }),
189
+ " · ",
190
+ /* @__PURE__ */ jsx(Link, {
191
+ href: org.privacyUrl,
192
+ className: "text-muted underline",
193
+ children: "Privacy"
194
+ })
195
+ ]
196
+ }),
197
+ effectiveCategory === "marketing" && unsubscribeHref ? /* @__PURE__ */ jsx(Text, {
198
+ className: "font-sans text-xs leading-relaxed text-muted",
199
+ children: /* @__PURE__ */ jsx(Link, {
200
+ href: unsubscribeHref,
201
+ className: "text-muted underline",
202
+ children: "Unsubscribe or manage preferences"
203
+ })
204
+ }) : null
205
+ ] });
206
+ }
207
+ /**
208
+ * Compound email primitives. Templates compose only from these so styling stays
209
+ * consistent, theme-driven, and email-client safe. The raw react-email
210
+ * `Section`, `Text`, `Link`, and `Hr` are re-exported for templates that need
211
+ * finer control.
212
+ */
213
+ const Email = {
214
+ Shell,
215
+ Header,
216
+ Title,
217
+ Paragraph,
218
+ Signature,
219
+ SupportLine,
220
+ Code,
221
+ CTA,
222
+ FallbackLink,
223
+ Footer,
224
+ LegalFooter,
225
+ Section,
226
+ Text,
227
+ Link,
228
+ Hr
229
+ };
230
+ //#endregion
231
+ export { Email };
232
+
233
+ //# sourceMappingURL=primitives.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.js","names":[],"sources":["../../src/emails/primitives.tsx"],"sourcesContent":["/**\n * Copyright 2026 ResQ Systems, Inc.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n\tBody,\n\tButton,\n\tContainer,\n\tHead,\n\tHeading,\n\tHr,\n\tHtml,\n\tImg,\n\tLink,\n\tPreview,\n\tSection,\n\tTailwind,\n\tText,\n} from \"@react-email/components\";\nimport { type ReactNode, useContext } from \"react\";\nimport type { EmailCategory } from \"../schemas.js\";\nimport {\n\tEmailMessageContext,\n\tEmailThemeContext,\n\ttype EmailThemeOverride,\n\tbuildTailwindConfig,\n\tresolveEmailTheme,\n} from \"./theme.js\";\n\ninterface ShellProps {\n\tpreview: string;\n\t/** Per-render brand override, merged over the active theme (context or default). */\n\ttheme?: EmailThemeOverride;\n\tchildren: ReactNode;\n}\n\n/** Outer document, resolved theme, preview text, and a single bordered card. */\nfunction Shell({ preview, theme, children }: ShellProps) {\n\tconst resolved = resolveEmailTheme(useContext(EmailThemeContext), theme);\n\tconst config = buildTailwindConfig(resolved);\n\n\treturn (\n\t\t<Html lang=\"en\">\n\t\t\t<Head>\n\t\t\t\t<meta name=\"color-scheme\" content=\"dark\" />\n\t\t\t\t<meta name=\"supported-color-schemes\" content=\"dark\" />\n\t\t\t\t{resolved.fontsHref ? <link href={resolved.fontsHref} rel=\"stylesheet\" /> : null}\n\t\t\t</Head>\n\t\t\t<Tailwind config={config}>\n\t\t\t\t<Preview>{preview}</Preview>\n\t\t\t\t<Body className=\"bg-background font-sans text-foreground\">\n\t\t\t\t\t<Container className=\"mx-auto my-10 max-w-xl rounded-xl border border-solid border-border bg-surface p-10\">\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</Container>\n\t\t\t\t</Body>\n\t\t\t</Tailwind>\n\t\t</Html>\n\t);\n}\n\n/** Brand lockup (logo + product wordmark) rendered at the top of the card. */\nfunction Header() {\n\tconst { org } = useContext(EmailThemeContext);\n\treturn (\n\t\t<Section className=\"mb-8\">\n\t\t\t<Img\n\t\t\t\tsrc={org.logoUrl}\n\t\t\t\twidth=\"40\"\n\t\t\t\theight=\"40\"\n\t\t\t\talt={org.productName}\n\t\t\t\tclassName=\"inline-block align-middle\"\n\t\t\t/>\n\t\t\t<Text className=\"ml-3 inline-block align-middle font-display text-lg font-bold tracking-tight text-foreground\">\n\t\t\t\t{org.productName}\n\t\t\t</Text>\n\t\t</Section>\n\t);\n}\n\nfunction Title({ children }: { children: ReactNode }) {\n\treturn (\n\t\t<Heading className=\"mb-4 font-display text-2xl font-bold tracking-tight text-foreground\">\n\t\t\t{children}\n\t\t</Heading>\n\t);\n}\n\nfunction Paragraph({ children }: { children: ReactNode }) {\n\treturn (\n\t\t<Text className=\"mb-4 font-sans text-base leading-relaxed text-foreground\">{children}</Text>\n\t);\n}\n\n/**\n * Role-based sign-off. Defaults to \"— The {brand} team\", derived from the active\n * theme's org so a rebrand flows through. Keep copy neutral: no first-person\n * promises or commitments (per the content & legal guide).\n */\nfunction Signature({ children }: { children?: ReactNode }) {\n\tconst { org } = useContext(EmailThemeContext);\n\treturn (\n\t\t<Text className=\"mt-6 font-sans text-sm leading-relaxed text-muted\">\n\t\t\t{children ?? `— The ${org.brandName} team`}\n\t\t</Text>\n\t);\n}\n\n/**\n * Muted support-contact line for security notices, sourced from\n * `theme.org.supportEmail` so there is always an actionable path even when a\n * template's optional CTA is absent. `children` overrides the lead-in prompt.\n */\nfunction SupportLine({ children }: { children?: ReactNode }) {\n\tconst { org } = useContext(EmailThemeContext);\n\treturn (\n\t\t<Text className=\"mb-4 font-sans text-sm leading-relaxed text-muted\">\n\t\t\t{children ?? \"Didn't do this?\"} Contact us at{\" \"}\n\t\t\t<Link href={`mailto:${org.supportEmail}`} className=\"text-primary underline\">\n\t\t\t\t{org.supportEmail}\n\t\t\t</Link>\n\t\t\t.\n\t\t</Text>\n\t);\n}\n\n/** A large, letter-spaced code block for OTP / verification codes. */\nfunction Code({ children }: { children: ReactNode }) {\n\treturn (\n\t\t<Section className=\"my-6 rounded-md border border-solid border-border bg-background py-4 text-center\">\n\t\t\t<Text className=\"font-mono text-3xl font-medium tracking-[8px] text-foreground\">\n\t\t\t\t{children}\n\t\t\t</Text>\n\t\t</Section>\n\t);\n}\n\n/**\n * Plain-text fallback for a link/button — improves deliverability and works in\n * clients that strip buttons. Renders the raw URL so it stays copy-pasteable.\n */\nfunction FallbackLink({ href }: { href: string }) {\n\treturn (\n\t\t<Text className=\"mt-4 font-sans text-xs leading-relaxed text-muted\">\n\t\t\tOr paste this link into your browser:\n\t\t\t<br />\n\t\t\t<Link href={href} className=\"break-all text-primary\">\n\t\t\t\t{href}\n\t\t\t</Link>\n\t\t</Text>\n\t);\n}\n\n/** Primary call-to-action — brand primary, mono, uppercase, tracked (per style guide). */\nfunction CTA({\n\thref,\n\tchildren,\n\tfallback = true,\n}: {\n\thref: string;\n\tchildren: ReactNode;\n\t/** Render a copy-pasteable {@link FallbackLink} below the button (default `true`). */\n\tfallback?: boolean;\n}) {\n\treturn (\n\t\t<Section className=\"my-6\">\n\t\t\t<Button\n\t\t\t\thref={href}\n\t\t\t\tclassName=\"box-border block rounded-md bg-primary px-8 py-3.5 text-center font-mono text-sm font-medium uppercase tracking-wide text-white no-underline\"\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Button>\n\t\t\t{fallback ? <FallbackLink href={href} /> : null}\n\t\t</Section>\n\t);\n}\n\nfunction Footer({ children }: { children: ReactNode }) {\n\treturn (\n\t\t<>\n\t\t\t<Hr className=\"my-6 border-border\" />\n\t\t\t<Text className=\"font-sans text-xs leading-relaxed text-muted\">{children}</Text>\n\t\t</>\n\t);\n}\n\n/**\n * Compliance footer: legal entity + registered postal address, Terms/Privacy\n * links, and — for `marketing` sends only — an unsubscribe affordance. The\n * effective category is the `category` prop, falling back to the active\n * {@link EmailMessageContext}. All copy is small and muted.\n */\nfunction LegalFooter({ reason, category }: { reason?: ReactNode; category?: EmailCategory }) {\n\tconst { org } = useContext(EmailThemeContext);\n\tconst message = useContext(EmailMessageContext);\n\tconst effectiveCategory = category ?? message.category;\n\t// CAN-SPAM/GDPR: the homepage is not a valid opt-out, so never fall back to\n\t// `org.websiteUrl`. Marketing sends without a real `unsubscribeUrl` simply\n\t// omit the affordance (and are effectively transactional).\n\tconst unsubscribeHref = message.unsubscribeUrl;\n\treturn (\n\t\t<>\n\t\t\t<Hr className=\"my-6 border-border\" />\n\t\t\t{reason ? (\n\t\t\t\t<Text className=\"mb-2 font-sans text-xs leading-relaxed text-muted\">{reason}</Text>\n\t\t\t) : null}\n\t\t\t{/* `registeredAddress` already leads with the legal entity name, so it is a\n\t\t\t complete CAN-SPAM postal line on its own — no separate `legalName`. */}\n\t\t\t<Text className=\"mb-2 font-sans text-xs leading-relaxed text-muted\">\n\t\t\t\t{org.registeredAddress}\n\t\t\t</Text>\n\t\t\t<Text className=\"mb-2 font-sans text-xs leading-relaxed text-muted\">\n\t\t\t\t<Link href={org.termsUrl} className=\"text-muted underline\">\n\t\t\t\t\tTerms\n\t\t\t\t</Link>\n\t\t\t\t{\" · \"}\n\t\t\t\t<Link href={org.privacyUrl} className=\"text-muted underline\">\n\t\t\t\t\tPrivacy\n\t\t\t\t</Link>\n\t\t\t</Text>\n\t\t\t{effectiveCategory === \"marketing\" && unsubscribeHref ? (\n\t\t\t\t<Text className=\"font-sans text-xs leading-relaxed text-muted\">\n\t\t\t\t\t<Link href={unsubscribeHref} className=\"text-muted underline\">\n\t\t\t\t\t\tUnsubscribe or manage preferences\n\t\t\t\t\t</Link>\n\t\t\t\t</Text>\n\t\t\t) : null}\n\t\t</>\n\t);\n}\n\n/**\n * Compound email primitives. Templates compose only from these so styling stays\n * consistent, theme-driven, and email-client safe. The raw react-email\n * `Section`, `Text`, `Link`, and `Hr` are re-exported for templates that need\n * finer control.\n */\nexport const Email: {\n\treadonly Shell: typeof Shell;\n\treadonly Header: typeof Header;\n\treadonly Title: typeof Title;\n\treadonly Paragraph: typeof Paragraph;\n\treadonly Signature: typeof Signature;\n\treadonly SupportLine: typeof SupportLine;\n\treadonly Code: typeof Code;\n\treadonly CTA: typeof CTA;\n\treadonly FallbackLink: typeof FallbackLink;\n\treadonly Footer: typeof Footer;\n\treadonly LegalFooter: typeof LegalFooter;\n\treadonly Section: typeof Section;\n\treadonly Text: typeof Text;\n\treadonly Link: typeof Link;\n\treadonly Hr: typeof Hr;\n} = {\n\tShell,\n\tHeader,\n\tTitle,\n\tParagraph,\n\tSignature,\n\tSupportLine,\n\tCode,\n\tCTA,\n\tFallbackLink,\n\tFooter,\n\tLegalFooter,\n\tSection,\n\tText,\n\tLink,\n\tHr,\n};\n"],"mappings":"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"}