| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- import { z } from "zod";
- const styleSchema = z.record(z.string(), z.any()).nullable();
- /**
- * Standard component definitions for React Email catalogs.
- *
- * These define the available email components with their Zod prop schemas.
- * All components render using @react-email/components primitives.
- */
- export const standardComponentDefinitions = {
- // ==========================================================================
- // Document Structure
- // ==========================================================================
- Html: {
- props: z.object({
- lang: z.string().nullable(),
- dir: z.enum(["ltr", "rtl"]).nullable(),
- }),
- slots: ["default"],
- description:
- "Top-level HTML email wrapper. Must be the root element. Children should include Head and Body.",
- example: { lang: "en", dir: "ltr" },
- },
- Head: {
- props: z.object({}),
- slots: ["default"],
- description:
- "Email head section. Place inside Html. Can contain metadata but typically left empty.",
- example: {},
- },
- Body: {
- props: z.object({
- style: styleSchema,
- }),
- slots: ["default"],
- description:
- "Email body wrapper. Place inside Html after Head. Contains all visible email content.",
- example: { style: { backgroundColor: "#f6f9fc" } },
- },
- Container: {
- props: z.object({
- style: styleSchema,
- }),
- slots: ["default"],
- description:
- "Constrains content width for email clients. Place inside Body. Typically max-width 600px.",
- example: {
- style: {
- maxWidth: "600px",
- margin: "0 auto",
- padding: "20px 0 48px",
- },
- },
- },
- Section: {
- props: z.object({
- style: styleSchema,
- }),
- slots: ["default"],
- description:
- "Groups related content. Renders as a table-based section for email compatibility.",
- example: { style: { padding: "24px", backgroundColor: "#ffffff" } },
- },
- Row: {
- props: z.object({
- style: styleSchema,
- }),
- slots: ["default"],
- description:
- "Horizontal layout row. Use inside Section for multi-column layouts.",
- example: { style: {} },
- },
- Column: {
- props: z.object({
- style: styleSchema,
- }),
- slots: ["default"],
- description:
- "Column within a Row. Set width via style for proportional layouts.",
- example: { style: { width: "50%" } },
- },
- // ==========================================================================
- // Content Components
- // ==========================================================================
- Heading: {
- props: z.object({
- text: z.string(),
- as: z.enum(["h1", "h2", "h3", "h4", "h5", "h6"]).nullable(),
- style: styleSchema,
- }),
- slots: [],
- description:
- "Heading text at various levels. h1 is largest, h6 is smallest.",
- example: { text: "Welcome!", as: "h1" },
- },
- Text: {
- props: z.object({
- text: z.string(),
- style: styleSchema,
- }),
- slots: [],
- description:
- "Body text paragraph. Use style for font size, color, weight, and alignment.",
- example: { text: "Thank you for signing up." },
- },
- Link: {
- props: z.object({
- text: z.string(),
- href: z.string(),
- style: styleSchema,
- }),
- slots: [],
- description: "Hyperlink with visible text and a URL.",
- example: {
- text: "Visit our website",
- href: "https://example.com",
- style: { color: "#2563eb" },
- },
- },
- Button: {
- props: z.object({
- text: z.string(),
- href: z.string(),
- style: styleSchema,
- }),
- slots: [],
- description:
- "Call-to-action button rendered as a link styled as a button. Provide text and href.",
- example: {
- text: "Get Started",
- href: "https://example.com",
- style: {
- backgroundColor: "#5F51E8",
- borderRadius: "3px",
- color: "#fff",
- padding: "12px 20px",
- },
- },
- },
- Image: {
- props: z.object({
- src: z.string(),
- alt: z.string().nullable(),
- width: z.number().nullable(),
- height: z.number().nullable(),
- style: styleSchema,
- }),
- slots: [],
- description:
- "Image from a URL. src must be a fully qualified URL. Specify width and height for consistent rendering.",
- example: {
- src: "https://picsum.photos/400/200?random=1",
- alt: "Hero image",
- width: 400,
- height: 200,
- },
- },
- Hr: {
- props: z.object({
- style: styleSchema,
- }),
- slots: [],
- description: "Horizontal rule separator between content sections.",
- example: {
- style: { borderColor: "#e6ebf1", margin: "20px 0" },
- },
- },
- // ==========================================================================
- // Utility Components
- // ==========================================================================
- Preview: {
- props: z.object({
- text: z.string(),
- }),
- slots: [],
- description:
- "Preview text shown in email client inboxes before the email is opened. Place inside Html.",
- example: { text: "You have a new message from Acme Corp" },
- },
- Markdown: {
- props: z.object({
- content: z.string(),
- markdownContainerStyles: styleSchema,
- markdownCustomStyles: z.record(z.string(), z.any()).nullable(),
- }),
- slots: [],
- description:
- "Renders markdown content as email-safe HTML. Supports headings, paragraphs, lists, links, bold, italic, and code.",
- example: {
- content: "# Hello\n\nThis is **bold** and *italic* text.",
- },
- },
- };
- export type StandardComponentDefinitions = typeof standardComponentDefinitions;
- export type StandardComponentProps<
- K extends keyof StandardComponentDefinitions,
- > = StandardComponentDefinitions[K]["props"] extends { _output: infer O }
- ? O
- : z.output<StandardComponentDefinitions[K]["props"]>;
|