@depup/react-email 6.9.3-depup.0 → 6.11.0-depup.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 (32) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +8 -9
  3. package/changes.json +7 -11
  4. package/dist/cli/index.mjs +74 -33
  5. package/dist/components/container/container.cjs +18 -3
  6. package/dist/components/container/container.d.cts +3 -1
  7. package/dist/components/container/container.d.mts +3 -1
  8. package/dist/components/container/container.mjs +18 -3
  9. package/dist/components/element-marker.cjs +8 -2
  10. package/dist/components/element-marker.d.cts +14 -0
  11. package/dist/components/element-marker.d.mts +14 -0
  12. package/dist/components/element-marker.mjs +8 -3
  13. package/dist/components/index.d.cts +1 -0
  14. package/dist/components/index.d.mts +1 -0
  15. package/dist/components/section/section.cjs +18 -3
  16. package/dist/components/section/section.d.cts +3 -1
  17. package/dist/components/section/section.d.mts +3 -1
  18. package/dist/components/section/section.mjs +18 -3
  19. package/dist/components/tailwind/utils/tailwindcss/clone-element-with-inlined-styles.cjs +34 -21
  20. package/dist/components/tailwind/utils/tailwindcss/clone-element-with-inlined-styles.mjs +34 -21
  21. package/dist/index.cjs +2 -0
  22. package/dist/index.d.cts +2 -1
  23. package/dist/index.d.mts +2 -1
  24. package/dist/index.mjs +2 -1
  25. package/package.json +16 -20
  26. package/readme.md +8 -0
  27. package/src/components/container/container.tsx +66 -46
  28. package/src/components/element-marker.ts +25 -2
  29. package/src/components/index.ts +5 -0
  30. package/src/components/section/section.tsx +66 -46
  31. package/src/components/tailwind/tailwind.spec.tsx +13 -0
  32. package/src/components/tailwind/utils/tailwindcss/clone-element-with-inlined-styles.ts +46 -37
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # react-email
2
2
 
3
+ ## 6.11.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 0432f96: Use custom esbuild plugins by passing the new `--esbuild-plugins` flag to `email dev`, `email build` and `email export`, so templates that need a custom compile-time transform can be previewed and exported.
8
+
9
+ ## 6.10.0
10
+
11
+ ### Minor Changes
12
+
13
+ - e9939f0: Upgrade `chokidar` to v5, which ships with npm provenance, so installs under pnpm's `trustPolicy: no-downgrade` no longer fail. The CLI now needs Node 20.19 or newer.
14
+
15
+ ### Patch Changes
16
+
17
+ - 1b45ed0: The dev server now refuses to start on Node older than 20.19, which matches the package's declared minimum, and names the installed version in the error.
18
+
19
+ ## 6.9.5
20
+
21
+ ### Patch Changes
22
+
23
+ - 0250981: fix responsive padding not applying to inner td for Container and Section
24
+
25
+ ## 6.9.4
26
+
3
27
  ## 6.9.3
4
28
 
5
29
  ## 6.9.2
package/README.md CHANGED
@@ -13,29 +13,28 @@ npm install @depup/react-email
13
13
 
14
14
  | Field | Value |
15
15
  |-------|-------|
16
- | Original | [react-email](https://www.npmjs.com/package/react-email) @ 6.9.3 |
17
- | Processed | 2026-08-26 |
16
+ | Original | [react-email](https://www.npmjs.com/package/react-email) @ 6.11.0 |
17
+ | Processed | 2026-09-27 |
18
18
  | Smoke test | failed |
19
- | Deps updated | 15 |
19
+ | Deps updated | 14 |
20
20
 
21
21
  ## Dependency Changes
22
22
 
23
23
  | Dependency | From | To |
24
24
  |------------|------|-----|
25
- | @babel/parser | 7.29.2 | ^8.0.4 |
26
- | @babel/traverse | 7.29.0 | ^8.0.4 |
27
- | chokidar | ^4.0.3 | ^5.0.0 |
25
+ | @babel/parser | 7.29.2 | ^7.29.9 |
26
+ | @babel/traverse | 7.29.0 | ^8.0.6 |
28
27
  | commander | ^13.0.0 | ^15.0.0 |
29
28
  | conf | ^15.0.2 | ^15.1.0 |
30
29
  | debounce | ^2.0.0 | ^3.0.0 |
31
30
  | esbuild | ^0.28.0 | ^0.28.2 |
32
31
  | jiti | 2.6.1 | ^2.7.0 |
33
32
  | log-symbols | ^7.0.0 | ^7.0.1 |
34
- | marked | ^15.0.12 | ^18.0.11 |
33
+ | marked | ^15.0.12 | ^18.0.14 |
35
34
  | mime-types | ^3.0.0 | ^3.0.2 |
36
- | nypm | 0.6.6 | ^0.6.9 |
35
+ | nypm | 0.6.6 | ^0.6.10 |
37
36
  | picospinner | ^3.0.0 | ^3.1.2 |
38
- | socket.io | ^4.8.1 | ^4.8.3 |
37
+ | socket.io | ^4.8.1 | ^4.8.4 |
39
38
  | tailwindcss | ^4.1.18 | ^4.3.3 |
40
39
 
41
40
  ---
package/changes.json CHANGED
@@ -2,15 +2,11 @@
2
2
  "bumped": {
3
3
  "@babel/parser": {
4
4
  "from": "7.29.2",
5
- "to": "^8.0.4"
5
+ "to": "^7.29.9"
6
6
  },
7
7
  "@babel/traverse": {
8
8
  "from": "7.29.0",
9
- "to": "^8.0.4"
10
- },
11
- "chokidar": {
12
- "from": "^4.0.3",
13
- "to": "^5.0.0"
9
+ "to": "^8.0.6"
14
10
  },
15
11
  "commander": {
16
12
  "from": "^13.0.0",
@@ -38,7 +34,7 @@
38
34
  },
39
35
  "marked": {
40
36
  "from": "^15.0.12",
41
- "to": "^18.0.11"
37
+ "to": "^18.0.14"
42
38
  },
43
39
  "mime-types": {
44
40
  "from": "^3.0.0",
@@ -46,7 +42,7 @@
46
42
  },
47
43
  "nypm": {
48
44
  "from": "0.6.6",
49
- "to": "^0.6.9"
45
+ "to": "^0.6.10"
50
46
  },
51
47
  "picospinner": {
52
48
  "from": "^3.0.0",
@@ -54,13 +50,13 @@
54
50
  },
55
51
  "socket.io": {
56
52
  "from": "^4.8.1",
57
- "to": "^4.8.3"
53
+ "to": "^4.8.4"
58
54
  },
59
55
  "tailwindcss": {
60
56
  "from": "^4.1.18",
61
57
  "to": "^4.3.3"
62
58
  }
63
59
  },
64
- "timestamp": "2026-08-26T00:16:59.732Z",
65
- "totalUpdated": 15
60
+ "timestamp": "2026-09-27T01:01:16.578Z",
61
+ "totalUpdated": 14
66
62
  }
@@ -6,7 +6,7 @@ import * as fs$1 from "node:fs";
6
6
  import fs, { existsSync, promises, statSync } from "node:fs";
7
7
  import * as path$2 from "node:path";
8
8
  import path from "node:path";
9
- import url, { fileURLToPath } from "node:url";
9
+ import url, { fileURLToPath, pathToFileURL } from "node:url";
10
10
  import logSymbols from "log-symbols";
11
11
  import { addDevDependency, installDependencies, runScript } from "nypm";
12
12
  import * as fsp$1 from "node:fs/promises";
@@ -6533,7 +6533,7 @@ const getTracingRootDir = async (usersProjectLocation) => {
6533
6533
  //#region package.json
6534
6534
  var package_default = {
6535
6535
  name: "react-email",
6536
- version: "6.9.3",
6536
+ version: "6.11.0",
6537
6537
  description: "A live preview of your emails right in your browser.",
6538
6538
  bin: { "email": "./dist/cli/index.mjs" },
6539
6539
  type: "module",
@@ -6565,7 +6565,7 @@ var package_default = {
6565
6565
  "directory": "packages/react-email"
6566
6566
  },
6567
6567
  keywords: ["react", "email"],
6568
- engines: { "node": ">=20.0.0" },
6568
+ engines: { "node": ">=20.19.0" },
6569
6569
  peerDependencies: {
6570
6570
  "react": "^18.0 || ^19.0 || ^19.0.0-rc",
6571
6571
  "react-dom": "^18.0 || ^19.0 || ^19.0.0-rc"
@@ -6574,7 +6574,7 @@ var package_default = {
6574
6574
  "@babel/parser": "catalog:",
6575
6575
  "@babel/traverse": "catalog:",
6576
6576
  "@react-email/render": "workspace:>=2.1.0",
6577
- "chokidar": "^4.0.3",
6577
+ "chokidar": "^5.0.0",
6578
6578
  "commander": "catalog:",
6579
6579
  "conf": "^15.0.2",
6580
6580
  "css-tree": "3.2.1",
@@ -6739,8 +6739,9 @@ const stopSpinnerAndPersist = (spinner, display) => {
6739
6739
  //#endregion
6740
6740
  //#region src/cli/commands/build.ts
6741
6741
  const isInReactEmailMonorepo = !path.dirname(fileURLToPath(import.meta.url)).includes("node_modules");
6742
- const setNextEnvironmentVariablesForBuild = async (emailsDirRelativePath, builtPreviewAppPath, usersProjectLocation) => {
6742
+ const setNextEnvironmentVariablesForBuild = async (emailsDirRelativePath, builtPreviewAppPath, usersProjectLocation, esbuildPluginsPath) => {
6743
6743
  const rootDir = await getTracingRootDir(usersProjectLocation);
6744
+ const esbuildPluginsAbsolutePath = esbuildPluginsPath ? path.resolve(usersProjectLocation, esbuildPluginsPath).replaceAll("\\", "/") : void 0;
6744
6745
  const nextConfigContents = `
6745
6746
  import path from 'path';
6746
6747
  const emailsDirRelativePath = path.normalize('${emailsDirRelativePath}');
@@ -6754,13 +6755,14 @@ const nextConfig = {
6754
6755
  REACT_EMAIL_INTERNAL_EMAILS_DIR_RELATIVE_PATH: emailsDirRelativePath,
6755
6756
  REACT_EMAIL_INTERNAL_EMAILS_DIR_ABSOLUTE_PATH: path.resolve(userProjectLocation, emailsDirRelativePath),
6756
6757
  REACT_EMAIL_INTERNAL_PREVIEW_SERVER_LOCATION: previewServerLocation,
6757
- REACT_EMAIL_INTERNAL_USER_PROJECT_LOCATION: userProjectLocation
6758
+ REACT_EMAIL_INTERNAL_USER_PROJECT_LOCATION: userProjectLocation,
6759
+ ${esbuildPluginsAbsolutePath ? `REACT_EMAIL_INTERNAL_ESBUILD_PLUGINS_PATH: '${esbuildPluginsAbsolutePath}',` : ""}
6758
6760
  },
6759
6761
  turbopack: {
6760
6762
  root: rootDir,
6761
6763
  },
6762
6764
  outputFileTracingRoot: rootDir,
6763
- serverExternalPackages: ['esbuild'],
6765
+ serverExternalPackages: ['esbuild', 'jiti'],
6764
6766
  typescript: {
6765
6767
  ignoreBuildErrors: true
6766
6768
  },
@@ -6803,7 +6805,7 @@ const updatePackageJson = async (builtUiPath) => {
6803
6805
  for (const [dependency, version] of Object.entries(packageJson.devDependencies)) packageJson.devDependencies[dependency] = version.replace("workspace:", "");
6804
6806
  await fs.promises.writeFile(packageJsonPath, JSON.stringify(packageJson), "utf8");
6805
6807
  };
6806
- const build$1 = async ({ dir: emailsDirRelativePath, packageManager }) => {
6808
+ const build$1 = async ({ dir: emailsDirRelativePath, packageManager, esbuildPlugins }) => {
6807
6809
  if (packageManager) console.warn("The --packageManager option is deprecated and ignored. The build command now just uses npm.");
6808
6810
  try {
6809
6811
  const usersProjectLocation = process.cwd();
@@ -6837,7 +6839,7 @@ const build$1 = async ({ dir: emailsDirRelativePath, packageManager }) => {
6837
6839
  await fs.promises.cp(staticPath, builtStaticDirectory, { recursive: true });
6838
6840
  }
6839
6841
  spinner.setText("Setting Next environment variables for preview app to work properly");
6840
- await setNextEnvironmentVariablesForBuild(emailsDirRelativePath, builtPreviewAppPath, usersProjectLocation);
6842
+ await setNextEnvironmentVariablesForBuild(emailsDirRelativePath, builtPreviewAppPath, usersProjectLocation, esbuildPlugins);
6841
6843
  spinner.setText("Setting server side generation for the email preview pages");
6842
6844
  await forceSSGForEmailPreviews(emailsDirPath, builtPreviewAppPath);
6843
6845
  spinner.setText("Updating package.json's build and start scripts");
@@ -7229,21 +7231,18 @@ const conf = new Conf({
7229
7231
  });
7230
7232
  //#endregion
7231
7233
  //#region src/cli/utils/style-text.ts
7232
- /**
7233
- * Centralized fallback for Node versions (<20.12.0) without util.styleText.
7234
- * Returns the original text when styleText is unavailable.
7235
- */
7236
7234
  const styleText = nodeUtil.styleText ? nodeUtil.styleText : (_, text) => text;
7237
7235
  //#endregion
7238
7236
  //#region src/cli/utils/preview/get-env-variables-for-preview-app.ts
7239
- const getEnvVariablesForPreviewApp = (relativePathToEmailsDirectory, previewServerLocation, cwd, resendApiKey, compatibilityClients) => {
7237
+ const getEnvVariablesForPreviewApp = (relativePathToEmailsDirectory, previewServerLocation, cwd, resendApiKey, compatibilityClients, esbuildPluginsPath) => {
7240
7238
  return {
7241
7239
  REACT_EMAIL_INTERNAL_EMAILS_DIR_RELATIVE_PATH: relativePathToEmailsDirectory,
7242
7240
  REACT_EMAIL_INTERNAL_EMAILS_DIR_ABSOLUTE_PATH: path.resolve(cwd, relativePathToEmailsDirectory),
7243
7241
  REACT_EMAIL_INTERNAL_PREVIEW_SERVER_LOCATION: previewServerLocation,
7244
7242
  REACT_EMAIL_INTERNAL_USER_PROJECT_LOCATION: cwd,
7245
7243
  REACT_EMAIL_INTERNAL_RESEND_API_KEY: resendApiKey,
7246
- ...compatibilityClients !== void 0 && { COMPATIBILITY_EMAIL_CLIENTS: compatibilityClients }
7244
+ ...compatibilityClients !== void 0 && { COMPATIBILITY_EMAIL_CLIENTS: compatibilityClients },
7245
+ ...esbuildPluginsPath !== void 0 && { REACT_EMAIL_INTERNAL_ESBUILD_PLUGINS_PATH: path.resolve(cwd, esbuildPluginsPath) }
7247
7246
  };
7248
7247
  };
7249
7248
  //#endregion
@@ -7298,10 +7297,10 @@ const safeAsyncServerListen = (server, port) => {
7298
7297
  });
7299
7298
  });
7300
7299
  };
7301
- const startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, port, compatibilityClients) => {
7302
- const [majorNodeVersion] = process.versions.node.split(".");
7303
- if (majorNodeVersion && Number.parseInt(majorNodeVersion, 10) < 20) {
7304
- console.error(` ${logSymbols.error} Node ${majorNodeVersion} is not supported. Please upgrade to Node 20 or higher.`);
7300
+ const startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath, port, compatibilityClients, esbuildPluginsPath) => {
7301
+ const [major = 0, minor = 0] = process.versions.node.split(".").map(Number);
7302
+ if (major < 20 || major === 20 && minor < 19) {
7303
+ console.error(` ${logSymbols.error} Node ${process.versions.node} is not supported. Please upgrade to Node 20.19 or higher.`);
7305
7304
  process.exit(1);
7306
7305
  }
7307
7306
  const previewServerLocation = await getUiLocation();
@@ -7332,7 +7331,7 @@ const startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath,
7332
7331
  } else {
7333
7332
  const nextPortToTry = port + 1;
7334
7333
  console.warn(` ${logSymbols.warning} Port ${port} is already in use, trying ${nextPortToTry}`);
7335
- return startDevServer(emailsDirRelativePath, staticBaseDirRelativePath, nextPortToTry, compatibilityClients);
7334
+ return startDevServer(emailsDirRelativePath, staticBaseDirRelativePath, nextPortToTry, compatibilityClients, esbuildPluginsPath);
7336
7335
  }
7337
7336
  devServer.on("close", async () => {
7338
7337
  await app.close();
@@ -7354,7 +7353,7 @@ const startDevServer = async (emailsDirRelativePath, staticBaseDirRelativePath,
7354
7353
  process.env = {
7355
7354
  NODE_ENV: "development",
7356
7355
  ...process.env,
7357
- ...getEnvVariablesForPreviewApp(path.normalize(emailsDirRelativePath), previewServerLocation, process.cwd(), conf.get("resendApiKey"), compatibilityClients)
7356
+ ...getEnvVariablesForPreviewApp(path.normalize(emailsDirRelativePath), previewServerLocation, process.cwd(), conf.get("resendApiKey"), compatibilityClients, esbuildPluginsPath)
7358
7357
  };
7359
7358
  if (!process.env.ESBUILD_BINARY_PATH) try {
7360
7359
  const esbuild = createJiti(previewServer.esmResolve("esbuild"));
@@ -7453,13 +7452,13 @@ const tree = async (dirPath, depth) => {
7453
7452
  };
7454
7453
  //#endregion
7455
7454
  //#region src/cli/commands/dev.ts
7456
- const dev = async ({ dir: emailsDirRelativePath, port, clients }) => {
7455
+ const dev = async ({ dir: emailsDirRelativePath, port, clients, esbuildPlugins }) => {
7457
7456
  try {
7458
7457
  if (!fs.existsSync(emailsDirRelativePath)) {
7459
7458
  console.error(`Missing ${emailsDirRelativePath} folder`);
7460
7459
  process.exit(1);
7461
7460
  }
7462
- await setupHotreloading(await startDevServer(emailsDirRelativePath, emailsDirRelativePath, Number.parseInt(port, 10), clients), emailsDirRelativePath);
7461
+ await setupHotreloading(await startDevServer(emailsDirRelativePath, emailsDirRelativePath, Number.parseInt(port, 10), clients, esbuildPlugins), emailsDirRelativePath);
7463
7462
  } catch (error) {
7464
7463
  console.log(error);
7465
7464
  process.exit(1);
@@ -7493,12 +7492,26 @@ const inlineCssLoader = () => ({
7493
7492
  }
7494
7493
  });
7495
7494
  //#endregion
7495
+ //#region src/cli/utils/esbuild/load-esbuild-plugins.ts
7496
+ /**
7497
+ * Loads the esbuild plugins a user wants applied when their templates are
7498
+ * bundled. The module's default export is either an array of plugins or a
7499
+ * function returning one, so plugins that need setup can do it lazily.
7500
+ */
7501
+ const loadEsbuildPlugins = async (modulePath) => {
7502
+ const exported = await createJiti(pathToFileURL(modulePath).href).import(modulePath, { default: true });
7503
+ const plugins = typeof exported === "function" ? await exported() : exported;
7504
+ if (!Array.isArray(plugins)) throw new Error(`Expected the default export of ${modulePath} to be an array of esbuild plugins or a function returning one`);
7505
+ return plugins;
7506
+ };
7507
+ //#endregion
7496
7508
  //#region src/cli/utils/esbuild/escape-string-for-regex.ts
7497
7509
  function escapeStringForRegex(string) {
7498
7510
  return string.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&").replace(/-/g, "\\x2d");
7499
7511
  }
7500
7512
  //#endregion
7501
7513
  //#region src/cli/utils/esbuild/renderring-utilities-exporter.ts
7514
+ const ENTRY_SUFFIX = "?react-email-entry";
7502
7515
  /**
7503
7516
  * Made to export the `render` function out of the user's email template
7504
7517
  * so that issues like https://github.com/resend/react-email/issues/649 don't
@@ -7509,17 +7522,39 @@ function escapeStringForRegex(string) {
7509
7522
  *
7510
7523
  * This avoids multiple versions of React being involved, i.e., the version
7511
7524
  * in the CLI vs. the version the user has on their emails.
7525
+ *
7526
+ * Each template entry point is replaced by a wrapper module that re-exports
7527
+ * it along with the utilities, instead of loading the template's source here.
7528
+ * The template itself then goes through the regular load pipeline, so other
7529
+ * plugins (for example the user's `--esbuild-plugins`) can still transform it.
7512
7530
  */
7513
7531
  const renderingUtilitiesExporter = (emailTemplates) => ({
7514
7532
  name: "rendering-utilities-exporter",
7515
- setup: (b) => {
7516
- b.onLoad({ filter: new RegExp(emailTemplates.map((emailPath) => escapeStringForRegex(emailPath)).join("|")) }, async ({ path: pathToFile }) => {
7533
+ setup: async (b) => {
7534
+ const templatePaths = await Promise.all(emailTemplates.map((emailPath) => promises.realpath(emailPath)));
7535
+ const templateFilter = new RegExp(templatePaths.map((templatePath) => escapeStringForRegex(templatePath)).join("|"));
7536
+ b.onResolve({ filter: /.*/ }, async (args) => {
7537
+ if (args.kind !== "entry-point") return null;
7538
+ const resolvedPath = path.isAbsolute(args.path) ? args.path : path.resolve(args.resolveDir, args.path);
7539
+ const realPath = await promises.realpath(resolvedPath);
7540
+ if (!templatePaths.includes(realPath)) return null;
7517
7541
  return {
7518
- contents: `${await promises.readFile(pathToFile, "utf8")};
7519
- export { render } from 'react-email-module-that-will-export-render'
7542
+ path: realPath,
7543
+ suffix: ENTRY_SUFFIX
7544
+ };
7545
+ });
7546
+ b.onLoad({ filter: templateFilter }, ({ path: pathToFile, suffix }) => {
7547
+ if (suffix !== ENTRY_SUFFIX) return null;
7548
+ const templateSpecifier = JSON.stringify(pathToFile);
7549
+ return {
7550
+ contents: `export * from ${templateSpecifier};
7551
+ import * as emailModule from ${templateSpecifier};
7552
+ export default emailModule.default;
7553
+ export { render } from 'react-email-module-that-will-export-render';
7520
7554
  export { createElement as reactEmailCreateReactElement } from 'react';
7521
7555
  `,
7522
- loader: path.extname(pathToFile).slice(1)
7556
+ loader: "js",
7557
+ resolveDir: path.dirname(pathToFile)
7523
7558
  };
7524
7559
  });
7525
7560
  b.onResolve({ filter: /^react-email-module-that-will-export-render$/ }, async (args) => {
@@ -7595,6 +7630,7 @@ const exportTemplates = async (pathToWhereEmailMarkupShouldBeDumped, emailsDirec
7595
7630
  if (fs.existsSync(pathToWhereEmailMarkupShouldBeDumped)) fs.rmSync(pathToWhereEmailMarkupShouldBeDumped, { recursive: true });
7596
7631
  const allTemplates = getEmailTemplatesFromDirectory(emailsDirectoryMetadata);
7597
7632
  try {
7633
+ const userPlugins = options.esbuildPlugins ? await loadEsbuildPlugins(path.resolve(process.cwd(), options.esbuildPlugins)) : [];
7598
7634
  for (let i = 0; i < allTemplates.length; i += BUILD_BATCH_SIZE) {
7599
7635
  const batch = allTemplates.slice(i, i + BUILD_BATCH_SIZE);
7600
7636
  await build({
@@ -7608,7 +7644,11 @@ const exportTemplates = async (pathToWhereEmailMarkupShouldBeDumped, emailsDirec
7608
7644
  outExtension: { ".js": ".cjs" },
7609
7645
  outdir: pathToWhereEmailMarkupShouldBeDumped,
7610
7646
  platform: "node",
7611
- plugins: [inlineCssLoader(), renderingUtilitiesExporter(batch)],
7647
+ plugins: [
7648
+ inlineCssLoader(),
7649
+ renderingUtilitiesExporter(batch),
7650
+ ...userPlugins
7651
+ ],
7612
7652
  write: true
7613
7653
  });
7614
7654
  await stop();
@@ -7792,14 +7832,15 @@ if (!requiredFlags.every((flag) => process.execArgv.includes(flag))) spawn(proce
7792
7832
  });
7793
7833
  else {
7794
7834
  program.name("react-email").description("A live preview of your emails right in your browser").version(package_default.version);
7795
- program.command("dev").description("Starts the preview email development app").option("-d, --dir <path>", "Directory with your email templates", "./emails").option("-p --port <port>", "Port to run dev server on", "3000").option("-c, --clients <clients>", "Comma-separated list of email clients to show compatibility warnings for (overrides COMPATIBILITY_EMAIL_CLIENTS)", parseClientsOption).action(dev);
7796
- program.command("build").description("Copies the preview app for onto .react-email and builds it").option("-d, --dir <path>", "Directory with your email templates", "./emails").addOption(new Option("-p, --packageManager <name>").hideHelp()).action(build$1);
7835
+ program.command("dev").description("Starts the preview email development app").option("-d, --dir <path>", "Directory with your email templates", "./emails").option("-p --port <port>", "Port to run dev server on", "3000").option("-c, --clients <clients>", "Comma-separated list of email clients to show compatibility warnings for (overrides COMPATIBILITY_EMAIL_CLIENTS)", parseClientsOption).option("--esbuild-plugins <path>", "Path to a module whose default export is an array of esbuild plugins (or a function returning one) applied when bundling email templates").action(dev);
7836
+ program.command("build").description("Copies the preview app for onto .react-email and builds it").option("-d, --dir <path>", "Directory with your email templates", "./emails").addOption(new Option("-p, --packageManager <name>").hideHelp()).option("--esbuild-plugins <path>", "Path to a module whose default export is an array of esbuild plugins (or a function returning one) applied when bundling email templates").action(build$1);
7797
7837
  program.command("start").description("Runs the built preview app that is inside of \".react-email\"").action(start);
7798
- program.command("export").description("Build the templates to the `out` directory").option("--outDir <path>", "Output directory", "out").option("-p, --pretty", "Pretty print the output", false).option("-t, --plainText", "Set output format as plain text", false).option("-d, --dir <path>", "Directory with your email templates", "./emails").option("-e, --extension <extension>", "Set a custom file extension for rendered emails (e.g. blade.php)").option("-s, --silent", "To, or not to show a spinner with process information", false).action(({ outDir, pretty, plainText, silent, dir: srcDir, extension }) => exportTemplates(outDir, srcDir, {
7838
+ program.command("export").description("Build the templates to the `out` directory").option("--outDir <path>", "Output directory", "out").option("-p, --pretty", "Pretty print the output", false).option("-t, --plainText", "Set output format as plain text", false).option("-d, --dir <path>", "Directory with your email templates", "./emails").option("-e, --extension <extension>", "Set a custom file extension for rendered emails (e.g. blade.php)").option("-s, --silent", "To, or not to show a spinner with process information", false).option("--esbuild-plugins <path>", "Path to a module whose default export is an array of esbuild plugins (or a function returning one) applied when bundling email templates").action(({ outDir, pretty, plainText, silent, dir: srcDir, extension, esbuildPlugins }) => exportTemplates(outDir, srcDir, {
7799
7839
  silent,
7800
7840
  plainText,
7801
7841
  pretty,
7802
- extension
7842
+ extension,
7843
+ esbuildPlugins
7803
7844
  }));
7804
7845
  const resend = program.command("resend");
7805
7846
  resend.command("setup").description("Sets up the integration between the React Email CLI, and your Resend account through an API Key").action(resendSetup);
@@ -4,14 +4,14 @@ let react = require("react");
4
4
  react = require_runtime.__toESM(react);
5
5
  let react_jsx_runtime = require("react/jsx-runtime");
6
6
  //#region src/components/container/container.tsx
7
- const Container = react.forwardRef(({ children, style = {}, ...props }, ref) => {
7
+ const Container = react.forwardRef(({ children, style = {}, tdClassName, ...props }, ref) => {
8
8
  const tdStyle = {};
9
9
  const tableStyle = {};
10
10
  const styleRecord = style;
11
11
  for (const key in styleRecord) {
12
12
  if (!Object.hasOwn(styleRecord, key)) continue;
13
13
  const value = styleRecord[key];
14
- if (key === "padding" || key === "paddingTop" || key === "paddingRight" || key === "paddingBottom" || key === "paddingLeft") tdStyle[key] = value;
14
+ if (key.startsWith("padding")) tdStyle[key] = value;
15
15
  else tableStyle[key] = value;
16
16
  }
17
17
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("table", {
@@ -30,6 +30,7 @@ const Container = react.forwardRef(({ children, style = {}, ...props }, ref) =>
30
30
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", {
31
31
  style: { width: "100%" },
32
32
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
33
+ className: tdClassName,
33
34
  style: tdStyle,
34
35
  children
35
36
  })
@@ -37,6 +38,20 @@ const Container = react.forwardRef(({ children, style = {}, ...props }, ref) =>
37
38
  });
38
39
  });
39
40
  Container.displayName = "Container";
40
- require_element_marker.markAsElement(Container);
41
+ require_element_marker.markAsElement(Container, { resolveTailwind(props, { style, className, classProperties }) {
42
+ const tableClasses = [];
43
+ const tdClasses = props.tdClassName ? [props.tdClassName] : [];
44
+ for (const name of className?.split(" ") ?? []) {
45
+ const properties = classProperties[name];
46
+ if (properties && properties.length > 0 && properties.every((property) => property.startsWith("padding"))) tdClasses.push(name);
47
+ else tableClasses.push(name);
48
+ }
49
+ return {
50
+ ...props,
51
+ style,
52
+ className: tableClasses.length > 0 ? tableClasses.join(" ") : void 0,
53
+ tdClassName: tdClasses.length > 0 ? tdClasses.join(" ") : void 0
54
+ };
55
+ } });
41
56
  //#endregion
42
57
  exports.Container = Container;
@@ -2,6 +2,8 @@ import * as React$1 from "react";
2
2
 
3
3
  //#region src/components/container/container.d.ts
4
4
  type ContainerProps = Readonly<React$1.ComponentPropsWithoutRef<'table'>>;
5
- declare const Container: React$1.ForwardRefExoticComponent<Readonly<Omit<React$1.DetailedHTMLProps<React$1.TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>, "ref">> & React$1.RefAttributes<HTMLTableElement>>;
5
+ declare const Container: React$1.ForwardRefExoticComponent<Readonly<Omit<React$1.DetailedHTMLProps<React$1.TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>, "ref">> & {
6
+ tdClassName?: string;
7
+ } & React$1.RefAttributes<HTMLTableElement>>;
6
8
  //#endregion
7
9
  export { Container, ContainerProps };
@@ -2,6 +2,8 @@ import * as React$1 from "react";
2
2
 
3
3
  //#region src/components/container/container.d.ts
4
4
  type ContainerProps = Readonly<React$1.ComponentPropsWithoutRef<'table'>>;
5
- declare const Container: React$1.ForwardRefExoticComponent<Readonly<Omit<React$1.DetailedHTMLProps<React$1.TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>, "ref">> & React$1.RefAttributes<HTMLTableElement>>;
5
+ declare const Container: React$1.ForwardRefExoticComponent<Readonly<Omit<React$1.DetailedHTMLProps<React$1.TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>, "ref">> & {
6
+ tdClassName?: string;
7
+ } & React$1.RefAttributes<HTMLTableElement>>;
6
8
  //#endregion
7
9
  export { Container, ContainerProps };
@@ -2,14 +2,14 @@ import { markAsElement } from "../element-marker.mjs";
2
2
  import * as React$1 from "react";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  //#region src/components/container/container.tsx
5
- const Container = React$1.forwardRef(({ children, style = {}, ...props }, ref) => {
5
+ const Container = React$1.forwardRef(({ children, style = {}, tdClassName, ...props }, ref) => {
6
6
  const tdStyle = {};
7
7
  const tableStyle = {};
8
8
  const styleRecord = style;
9
9
  for (const key in styleRecord) {
10
10
  if (!Object.hasOwn(styleRecord, key)) continue;
11
11
  const value = styleRecord[key];
12
- if (key === "padding" || key === "paddingTop" || key === "paddingRight" || key === "paddingBottom" || key === "paddingLeft") tdStyle[key] = value;
12
+ if (key.startsWith("padding")) tdStyle[key] = value;
13
13
  else tableStyle[key] = value;
14
14
  }
15
15
  return /* @__PURE__ */ jsx("table", {
@@ -28,6 +28,7 @@ const Container = React$1.forwardRef(({ children, style = {}, ...props }, ref) =
28
28
  children: /* @__PURE__ */ jsx("tbody", { children: /* @__PURE__ */ jsx("tr", {
29
29
  style: { width: "100%" },
30
30
  children: /* @__PURE__ */ jsx("td", {
31
+ className: tdClassName,
31
32
  style: tdStyle,
32
33
  children
33
34
  })
@@ -35,6 +36,20 @@ const Container = React$1.forwardRef(({ children, style = {}, ...props }, ref) =
35
36
  });
36
37
  });
37
38
  Container.displayName = "Container";
38
- markAsElement(Container);
39
+ markAsElement(Container, { resolveTailwind(props, { style, className, classProperties }) {
40
+ const tableClasses = [];
41
+ const tdClasses = props.tdClassName ? [props.tdClassName] : [];
42
+ for (const name of className?.split(" ") ?? []) {
43
+ const properties = classProperties[name];
44
+ if (properties && properties.length > 0 && properties.every((property) => property.startsWith("padding"))) tdClasses.push(name);
45
+ else tableClasses.push(name);
46
+ }
47
+ return {
48
+ ...props,
49
+ style,
50
+ className: tableClasses.length > 0 ? tableClasses.join(" ") : void 0,
51
+ tdClassName: tdClasses.length > 0 ? tdClasses.join(" ") : void 0
52
+ };
53
+ } });
39
54
  //#endregion
40
55
  export { Container };
@@ -1,8 +1,14 @@
1
1
  //#region src/components/element-marker.ts
2
2
  const elementMarker = Symbol.for("react-email.element");
3
- const markAsElement = (component) => {
4
- component[elementMarker] = true;
3
+ const markAsElement = (component, options = {}) => {
4
+ component[elementMarker] = options;
5
+ };
6
+ const getElementOptions = (type) => {
7
+ if (typeof type !== "function" && typeof type !== "object") return void 0;
8
+ if (type === null) return void 0;
9
+ return type[elementMarker];
5
10
  };
6
11
  //#endregion
7
12
  exports.elementMarker = elementMarker;
13
+ exports.getElementOptions = getElementOptions;
8
14
  exports.markAsElement = markAsElement;
@@ -0,0 +1,14 @@
1
+ import * as React$1 from "react";
2
+
3
+ //#region src/components/element-marker.d.ts
4
+ interface ResolvedTailwind {
5
+ style: React$1.CSSProperties;
6
+ className: string | undefined;
7
+ classProperties: Record<string, string[]>;
8
+ }
9
+ interface ElementOptions<Props = object> {
10
+ resolveTailwind?: (props: Props, resolved: ResolvedTailwind) => Props;
11
+ }
12
+ declare const markAsElement: <Props>(component: unknown, options?: ElementOptions<Props>) => void;
13
+ //#endregion
14
+ export { ElementOptions, ResolvedTailwind, markAsElement };
@@ -0,0 +1,14 @@
1
+ import * as React$1 from "react";
2
+
3
+ //#region src/components/element-marker.d.ts
4
+ interface ResolvedTailwind {
5
+ style: React$1.CSSProperties;
6
+ className: string | undefined;
7
+ classProperties: Record<string, string[]>;
8
+ }
9
+ interface ElementOptions<Props = object> {
10
+ resolveTailwind?: (props: Props, resolved: ResolvedTailwind) => Props;
11
+ }
12
+ declare const markAsElement: <Props>(component: unknown, options?: ElementOptions<Props>) => void;
13
+ //#endregion
14
+ export { ElementOptions, ResolvedTailwind, markAsElement };
@@ -1,7 +1,12 @@
1
1
  //#region src/components/element-marker.ts
2
2
  const elementMarker = Symbol.for("react-email.element");
3
- const markAsElement = (component) => {
4
- component[elementMarker] = true;
3
+ const markAsElement = (component, options = {}) => {
4
+ component[elementMarker] = options;
5
+ };
6
+ const getElementOptions = (type) => {
7
+ if (typeof type !== "function" && typeof type !== "object") return void 0;
8
+ if (type === null) return void 0;
9
+ return type[elementMarker];
5
10
  };
6
11
  //#endregion
7
- export { elementMarker, markAsElement };
12
+ export { elementMarker, getElementOptions, markAsElement };
@@ -6,6 +6,7 @@ import { CodeBlock, CodeBlockProps } from "./code-block/code-block.cjs";
6
6
  import { CodeInline, CodeInlineProps } from "./code-inline/code-inline.cjs";
7
7
  import { Column, ColumnProps } from "./column/column.cjs";
8
8
  import { Container, ContainerProps } from "./container/container.cjs";
9
+ import { ElementOptions, ResolvedTailwind, markAsElement } from "./element-marker.cjs";
9
10
  import { Font, FontProps } from "./font/font.cjs";
10
11
  import { Head, HeadProps } from "./head/head.cjs";
11
12
  import { Heading, HeadingAs, HeadingProps } from "./heading/heading.cjs";
@@ -6,6 +6,7 @@ import { CodeBlock, CodeBlockProps } from "./code-block/code-block.mjs";
6
6
  import { CodeInline, CodeInlineProps } from "./code-inline/code-inline.mjs";
7
7
  import { Column, ColumnProps } from "./column/column.mjs";
8
8
  import { Container, ContainerProps } from "./container/container.mjs";
9
+ import { ElementOptions, ResolvedTailwind, markAsElement } from "./element-marker.mjs";
9
10
  import { Font, FontProps } from "./font/font.mjs";
10
11
  import { Head, HeadProps } from "./head/head.mjs";
11
12
  import { Heading, HeadingAs, HeadingProps } from "./heading/heading.mjs";
@@ -4,14 +4,14 @@ let react = require("react");
4
4
  react = require_runtime.__toESM(react);
5
5
  let react_jsx_runtime = require("react/jsx-runtime");
6
6
  //#region src/components/section/section.tsx
7
- const Section = react.forwardRef(({ children, style = {}, ...props }, ref) => {
7
+ const Section = react.forwardRef(({ children, style = {}, tdClassName, ...props }, ref) => {
8
8
  const tdStyle = {};
9
9
  const tableStyle = {};
10
10
  const styleRecord = style;
11
11
  for (const key in styleRecord) {
12
12
  if (!Object.hasOwn(styleRecord, key)) continue;
13
13
  const value = styleRecord[key];
14
- if (key === "padding" || key === "paddingTop" || key === "paddingRight" || key === "paddingBottom" || key === "paddingLeft") tdStyle[key] = value;
14
+ if (key.startsWith("padding")) tdStyle[key] = value;
15
15
  else tableStyle[key] = value;
16
16
  }
17
17
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("table", {
@@ -25,12 +25,27 @@ const Section = react.forwardRef(({ children, style = {}, ...props }, ref) => {
25
25
  ref,
26
26
  style: tableStyle,
27
27
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
28
+ className: tdClassName,
28
29
  style: tdStyle,
29
30
  children
30
31
  }) }) })
31
32
  });
32
33
  });
33
34
  Section.displayName = "Section";
34
- require_element_marker.markAsElement(Section);
35
+ require_element_marker.markAsElement(Section, { resolveTailwind(props, { style, className, classProperties }) {
36
+ const tableClasses = [];
37
+ const tdClasses = props.tdClassName ? [props.tdClassName] : [];
38
+ for (const name of className?.split(" ") ?? []) {
39
+ const properties = classProperties[name];
40
+ if (properties && properties.length > 0 && properties.every((property) => property.startsWith("padding"))) tdClasses.push(name);
41
+ else tableClasses.push(name);
42
+ }
43
+ return {
44
+ ...props,
45
+ style,
46
+ className: tableClasses.length > 0 ? tableClasses.join(" ") : void 0,
47
+ tdClassName: tdClasses.length > 0 ? tdClasses.join(" ") : void 0
48
+ };
49
+ } });
35
50
  //#endregion
36
51
  exports.Section = Section;
@@ -2,6 +2,8 @@ import * as React$1 from "react";
2
2
 
3
3
  //#region src/components/section/section.d.ts
4
4
  type SectionProps = Readonly<React$1.ComponentPropsWithoutRef<'table'>>;
5
- declare const Section: React$1.ForwardRefExoticComponent<Readonly<Omit<React$1.DetailedHTMLProps<React$1.TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>, "ref">> & React$1.RefAttributes<HTMLTableElement>>;
5
+ declare const Section: React$1.ForwardRefExoticComponent<Readonly<Omit<React$1.DetailedHTMLProps<React$1.TableHTMLAttributes<HTMLTableElement>, HTMLTableElement>, "ref">> & {
6
+ tdClassName?: string;
7
+ } & React$1.RefAttributes<HTMLTableElement>>;
6
8
  //#endregion
7
9
  export { Section, SectionProps };