catalog.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import { z } from "zod";
  2. const styleSchema = z.record(z.string(), z.any()).nullable();
  3. /**
  4. * Standard component definitions for React Email catalogs.
  5. *
  6. * These define the available email components with their Zod prop schemas.
  7. * All components render using @react-email/components primitives.
  8. */
  9. export const standardComponentDefinitions = {
  10. // ==========================================================================
  11. // Document Structure
  12. // ==========================================================================
  13. Html: {
  14. props: z.object({
  15. lang: z.string().nullable(),
  16. dir: z.enum(["ltr", "rtl"]).nullable(),
  17. }),
  18. slots: ["default"],
  19. description:
  20. "Top-level HTML email wrapper. Must be the root element. Children should include Head and Body.",
  21. example: { lang: "en", dir: "ltr" },
  22. },
  23. Head: {
  24. props: z.object({}),
  25. slots: ["default"],
  26. description:
  27. "Email head section. Place inside Html. Can contain metadata but typically left empty.",
  28. example: {},
  29. },
  30. Body: {
  31. props: z.object({
  32. style: styleSchema,
  33. }),
  34. slots: ["default"],
  35. description:
  36. "Email body wrapper. Place inside Html after Head. Contains all visible email content.",
  37. example: { style: { backgroundColor: "#f6f9fc" } },
  38. },
  39. Container: {
  40. props: z.object({
  41. style: styleSchema,
  42. }),
  43. slots: ["default"],
  44. description:
  45. "Constrains content width for email clients. Place inside Body. Typically max-width 600px.",
  46. example: {
  47. style: {
  48. maxWidth: "600px",
  49. margin: "0 auto",
  50. padding: "20px 0 48px",
  51. },
  52. },
  53. },
  54. Section: {
  55. props: z.object({
  56. style: styleSchema,
  57. }),
  58. slots: ["default"],
  59. description:
  60. "Groups related content. Renders as a table-based section for email compatibility.",
  61. example: { style: { padding: "24px", backgroundColor: "#ffffff" } },
  62. },
  63. Row: {
  64. props: z.object({
  65. style: styleSchema,
  66. }),
  67. slots: ["default"],
  68. description:
  69. "Horizontal layout row. Use inside Section for multi-column layouts.",
  70. example: { style: {} },
  71. },
  72. Column: {
  73. props: z.object({
  74. style: styleSchema,
  75. }),
  76. slots: ["default"],
  77. description:
  78. "Column within a Row. Set width via style for proportional layouts.",
  79. example: { style: { width: "50%" } },
  80. },
  81. // ==========================================================================
  82. // Content Components
  83. // ==========================================================================
  84. Heading: {
  85. props: z.object({
  86. text: z.string(),
  87. as: z.enum(["h1", "h2", "h3", "h4", "h5", "h6"]).nullable(),
  88. style: styleSchema,
  89. }),
  90. slots: [],
  91. description:
  92. "Heading text at various levels. h1 is largest, h6 is smallest.",
  93. example: { text: "Welcome!", as: "h1" },
  94. },
  95. Text: {
  96. props: z.object({
  97. text: z.string(),
  98. style: styleSchema,
  99. }),
  100. slots: [],
  101. description:
  102. "Body text paragraph. Use style for font size, color, weight, and alignment.",
  103. example: { text: "Thank you for signing up." },
  104. },
  105. Link: {
  106. props: z.object({
  107. text: z.string(),
  108. href: z.string(),
  109. style: styleSchema,
  110. }),
  111. slots: [],
  112. description: "Hyperlink with visible text and a URL.",
  113. example: {
  114. text: "Visit our website",
  115. href: "https://example.com",
  116. style: { color: "#2563eb" },
  117. },
  118. },
  119. Button: {
  120. props: z.object({
  121. text: z.string(),
  122. href: z.string(),
  123. style: styleSchema,
  124. }),
  125. slots: [],
  126. description:
  127. "Call-to-action button rendered as a link styled as a button. Provide text and href.",
  128. example: {
  129. text: "Get Started",
  130. href: "https://example.com",
  131. style: {
  132. backgroundColor: "#5F51E8",
  133. borderRadius: "3px",
  134. color: "#fff",
  135. padding: "12px 20px",
  136. },
  137. },
  138. },
  139. Image: {
  140. props: z.object({
  141. src: z.string(),
  142. alt: z.string().nullable(),
  143. width: z.number().nullable(),
  144. height: z.number().nullable(),
  145. style: styleSchema,
  146. }),
  147. slots: [],
  148. description:
  149. "Image from a URL. src must be a fully qualified URL. Specify width and height for consistent rendering.",
  150. example: {
  151. src: "https://picsum.photos/400/200?random=1",
  152. alt: "Hero image",
  153. width: 400,
  154. height: 200,
  155. },
  156. },
  157. Hr: {
  158. props: z.object({
  159. style: styleSchema,
  160. }),
  161. slots: [],
  162. description: "Horizontal rule separator between content sections.",
  163. example: {
  164. style: { borderColor: "#e6ebf1", margin: "20px 0" },
  165. },
  166. },
  167. // ==========================================================================
  168. // Utility Components
  169. // ==========================================================================
  170. Preview: {
  171. props: z.object({
  172. text: z.string(),
  173. }),
  174. slots: [],
  175. description:
  176. "Preview text shown in email client inboxes before the email is opened. Place inside Html.",
  177. example: { text: "You have a new message from Acme Corp" },
  178. },
  179. Markdown: {
  180. props: z.object({
  181. content: z.string(),
  182. markdownContainerStyles: styleSchema,
  183. markdownCustomStyles: z.record(z.string(), z.any()).nullable(),
  184. }),
  185. slots: [],
  186. description:
  187. "Renders markdown content as email-safe HTML. Supports headings, paragraphs, lists, links, bold, italic, and code.",
  188. example: {
  189. content: "# Hello\n\nThis is **bold** and *italic* text.",
  190. },
  191. },
  192. };
  193. export type StandardComponentDefinitions = typeof standardComponentDefinitions;
  194. export type StandardComponentProps<
  195. K extends keyof StandardComponentDefinitions,
  196. > = StandardComponentDefinitions[K]["props"] extends { _output: infer O }
  197. ? O
  198. : z.output<StandardComponentDefinitions[K]["props"]>;