diff --git a/.changeset/dirty-needles-chew.md b/.changeset/dirty-needles-chew.md new file mode 100644 index 0000000000..acc7dd42e2 --- /dev/null +++ b/.changeset/dirty-needles-chew.md @@ -0,0 +1,5 @@ +--- +"react-email": minor +--- + +Theme switcher for email template diff --git a/.changeset/great-parrots-yell.md b/.changeset/great-parrots-yell.md new file mode 100644 index 0000000000..429c2c034d --- /dev/null +++ b/.changeset/great-parrots-yell.md @@ -0,0 +1,5 @@ +--- +"@react-email/tailwind": minor +--- + +Extract tailwind pseudo classes to stylesheet diff --git a/.changeset/pre.json b/.changeset/pre.json new file mode 100644 index 0000000000..6fcff1e14b --- /dev/null +++ b/.changeset/pre.json @@ -0,0 +1,37 @@ +{ + "mode": "pre", + "tag": "canary", + "initialVersions": { + "demo": "0.0.0", + "docs": "0.0.0", + "web": "0.0.0", + "@benchmarks/preview-server": "0.0.0", + "@benchmarks/tailwind-component": "0.0.0", + "@react-email/body": "0.0.11", + "@react-email/button": "0.0.19", + "@react-email/code-block": "0.0.13", + "@react-email/code-inline": "0.0.5", + "@react-email/column": "0.0.13", + "@react-email/components": "0.0.37", + "@react-email/container": "0.0.15", + "create-email": "1.2.0", + "react-email-starter": "1.0.7", + "@react-email/font": "0.0.9", + "@react-email/head": "0.0.12", + "@react-email/heading": "0.0.15", + "@react-email/hr": "0.0.11", + "@react-email/html": "0.0.11", + "@react-email/img": "0.0.11", + "@react-email/link": "0.0.12", + "@react-email/markdown": "0.0.15", + "@react-email/preview": "0.0.12", + "react-email": "4.0.11", + "@react-email/render": "1.1.0", + "@react-email/row": "0.0.12", + "@react-email/section": "0.0.16", + "@react-email/tailwind": "1.0.5", + "@react-email/text": "0.1.2", + "tsconfig": "0.0.0" + }, + "changesets": ["dirty-needles-chew"] +} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 5940842a7d..370f054766 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -20,7 +20,7 @@ jobs: uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda - name: pnpm Cache id: pnpm-cache - uses: buildjet/cache@3e70d19e31d6a8030aeddf6ed8dbe601f94d09f4 + uses: buildjet/cache@9347ea1c7c1f331d397aa98b3894420448373372 with: path: | ~/.pnpm-store diff --git a/.github/workflows/preview-release.yml b/.github/workflows/preview-release.yml index 0721b053b0..e5b568744f 100644 --- a/.github/workflows/preview-release.yml +++ b/.github/workflows/preview-release.yml @@ -28,7 +28,7 @@ jobs: uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda - name: pnpm Cache id: pnpm-cache - uses: buildjet/cache@3e70d19e31d6a8030aeddf6ed8dbe601f94d09f4 + uses: buildjet/cache@9347ea1c7c1f331d397aa98b3894420448373372 with: path: | ~/.pnpm-store diff --git a/.github/workflows/release-canary.yml b/.github/workflows/release-canary.yml index 472aeb8e29..8d106ba0f1 100644 --- a/.github/workflows/release-canary.yml +++ b/.github/workflows/release-canary.yml @@ -1,12 +1,9 @@ -name: rsnd - +name: Release Canary on: push: branches: - canary - concurrency: ${{ github.workflow }}-${{ github.ref }} - jobs: release: name: release canary @@ -19,21 +16,18 @@ jobs: uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 22 - - name: Enable Corepack id: pnpm-setup run: | corepack enable corepack prepare pnpm@9.15.0 --activate pnpm config set script-shell "/usr/bin/bash" - - name: pnpm Cache - uses: buildjet/cache@3e70d19e31d6a8030aeddf6ed8dbe601f94d09f4 + uses: buildjet/cache@9347ea1c7c1f331d397aa98b3894420448373372 with: path: | ~/.pnpm-store @@ -42,18 +36,15 @@ jobs: key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} restore-keys: | ${{ runner.os }}-pnpm- - - name: Install packages if: steps.pnpm-cache.outputs.cache-hit != 'true' run: pnpm install --frozen-lockfile - - name: Enter prerelease mode # This step errors if it is already in prerelease mode continue-on-error: true run: pnpm canary:enter - - name: Create "Version packages" PR or publish release - uses: changesets/action@06245a4e0a36c064a573d4150030f5ec548e4fcc + uses: changesets/action@5f15b43b429db9083a86b852c3a1b3a6973e8225 with: version: pnpm run version publish: pnpm run release diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8ee98ea20f..371166b7f0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,7 +23,7 @@ jobs: uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda - name: pnpm Cache id: pnpm-cache - uses: buildjet/cache@3e70d19e31d6a8030aeddf6ed8dbe601f94d09f4 + uses: buildjet/cache@9347ea1c7c1f331d397aa98b3894420448373372 with: path: | ~/.pnpm-store diff --git a/.github/workflows/version.yml b/.github/workflows/version.yml index 57fdbed3c7..208f1ed84f 100644 --- a/.github/workflows/version.yml +++ b/.github/workflows/version.yml @@ -31,7 +31,7 @@ jobs: - name: pnpm Cache id: pnpm-cache - uses: buildjet/cache@3e70d19e31d6a8030aeddf6ed8dbe601f94d09f4 + uses: buildjet/cache@9347ea1c7c1f331d397aa98b3894420448373372 with: path: | ~/.pnpm-store @@ -51,7 +51,7 @@ jobs: run: pnpm canary:exit - name: Create Release Pull Request - uses: changesets/action@06245a4e0a36c064a573d4150030f5ec548e4fcc + uses: changesets/action@5f15b43b429db9083a86b852c3a1b3a6973e8225 with: version: pnpm run version title: "chore(root): Version packages" diff --git a/package.json b/package.json index 0ff3928aa9..b428547c18 100644 --- a/package.json +++ b/package.json @@ -18,14 +18,14 @@ "@biomejs/biome": "2.0.0-beta.1", "@changesets/cli": "2.29.2", "@types/node": "22.14.1", - "@types/react": "19.0.1", - "@types/react-dom": "19.0.1", + "@types/react": "19.1.2", + "@types/react-dom": "19.1.3", "happy-dom": "17.4.4", "pkg-pr-new": "0.0.43", "tsconfig": "workspace:*", "tsup": "8.4.0", "turbo": "2.5.0", - "vite": "6.3.2", + "vite": "6.3.4", "vitest": "3.1.1" }, "pnpm": { diff --git a/packages/code-block/CHANGELOG.md b/packages/code-block/CHANGELOG.md index f0c77fde15..b84e73687d 100644 --- a/packages/code-block/CHANGELOG.md +++ b/packages/code-block/CHANGELOG.md @@ -6,6 +6,12 @@ - 9aa033c: Use range of versions for dependencies +## 0.0.13-canary.0 + +### Patch Changes + +- 9b1adb0: Use range of versions for dependencies + ## 0.0.12 ### Patch Changes diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 5e76e542b5..4232f40592 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -36,6 +36,79 @@ - @react-email/row@0.0.12 - @react-email/section@0.0.16 +## 0.0.37-canary.4 + +### Patch Changes + +- Updated dependencies [bd58fa9] + - @react-email/text@0.1.2-canary.0 + +## 0.0.37-canary.3 + +### Patch Changes + +- Updated dependencies [8179dc6] + - @react-email/tailwind@1.1.0-canary.1 + +## 0.0.37-canary.2 + +### Patch Changes + +- Updated dependencies [9b1adb0] + - @react-email/code-block@0.0.13-canary.0 + - @react-email/markdown@0.0.15-canary.0 + - @react-email/render@1.1.0-canary.1 + - @react-email/body@0.0.11 + - @react-email/button@0.0.19 + - @react-email/code-inline@0.0.5 + - @react-email/column@0.0.13 + - @react-email/container@0.0.15 + - @react-email/font@0.0.9 + - @react-email/head@0.0.12 + - @react-email/heading@0.0.15 + - @react-email/hr@0.0.11 + - @react-email/html@0.0.11 + - @react-email/img@0.0.11 + - @react-email/link@0.0.12 + - @react-email/preview@0.0.12 + - @react-email/row@0.0.12 + - @react-email/section@0.0.16 + - @react-email/tailwind@1.1.0-canary.0 + - @react-email/text@0.1.1 + +## 0.0.37-canary.1 + +### Patch Changes + +- Updated dependencies [32372da] + - @react-email/render@1.1.0-canary.0 + - @react-email/body@0.0.11 + - @react-email/button@0.0.19 + - @react-email/code-block@0.0.12 + - @react-email/code-inline@0.0.5 + - @react-email/column@0.0.13 + - @react-email/container@0.0.15 + - @react-email/font@0.0.9 + - @react-email/head@0.0.12 + - @react-email/heading@0.0.15 + - @react-email/hr@0.0.11 + - @react-email/html@0.0.11 + - @react-email/img@0.0.11 + - @react-email/link@0.0.12 + - @react-email/markdown@0.0.14 + - @react-email/preview@0.0.12 + - @react-email/row@0.0.12 + - @react-email/section@0.0.16 + - @react-email/tailwind@1.1.0-canary.0 + - @react-email/text@0.1.1 + +## 0.0.37-canary.0 + +### Patch Changes + +- Updated dependencies [ae8c007] + - @react-email/tailwind@1.1.0-canary.0 + ## 0.0.36 ### Patch Changes diff --git a/packages/create-email/CHANGELOG.md b/packages/create-email/CHANGELOG.md index 7cc5f8d414..f6272af56e 100644 --- a/packages/create-email/CHANGELOG.md +++ b/packages/create-email/CHANGELOG.md @@ -10,12 +10,26 @@ - d689346: Show package.json's version on --version for create-email +## 1.2.0-canary.1 + +### Patch Changes + +- 0c3aaa3: Show package.json's version on --version for create-email + +## 1.2.0-canary.0 + +### Minor Changes + +- 237d115: Fetch react-email package versions at runtime from `--tag` option + ## 1.1.0 ### Minor Changes - 31fd7cc: use caret for dependency on react-email and @react-email/components +## 1.0.8-canary.0 + ## 1.0.7 ### Patch Changes diff --git a/packages/create-email/package.json b/packages/create-email/package.json index 5a02794616..c05408a63a 100644 --- a/packages/create-email/package.json +++ b/packages/create-email/package.json @@ -30,7 +30,7 @@ "create-email": "src/index.js" }, "devDependencies": { - "react": "19.0.0", + "react": "19.1.0", "tsconfig": "workspace:*", "typescript": "5.8.3" } diff --git a/packages/create-email/template/CHANGELOG.md b/packages/create-email/template/CHANGELOG.md index 195b70b0d4..7870c01034 100644 --- a/packages/create-email/template/CHANGELOG.md +++ b/packages/create-email/template/CHANGELOG.md @@ -2,6 +2,12 @@ ## 1.1.0 +## 1.0.8-canary.0 + +### Patch Changes + +- @react-email/components@0.0.37-canary.0 + ## 1.0.7 ## 1.0.6 diff --git a/packages/markdown/CHANGELOG.md b/packages/markdown/CHANGELOG.md index 6eb2ce0d6e..d0cd8933e0 100644 --- a/packages/markdown/CHANGELOG.md +++ b/packages/markdown/CHANGELOG.md @@ -6,6 +6,12 @@ - 9aa033c: Use range of versions for dependencies +## 0.0.15-canary.0 + +### Patch Changes + +- 9b1adb0: Use range of versions for dependencies + ## 0.0.14 ### Patch Changes diff --git a/packages/react-email/CHANGELOG.md b/packages/react-email/CHANGELOG.md index f8dc3d7fe9..d846498be6 100644 --- a/packages/react-email/CHANGELOG.md +++ b/packages/react-email/CHANGELOG.md @@ -1,5 +1,38 @@ # react-email +## 4.1.0-canary.4 + +### Patch Changes + +- 5c6150d: Add .json import support for hot reloading +- aae2f59: Ensure dependencies outside emails directory are completely resolved +- b4b2373: Fix non-email files being rendered during hot reloading + +## 4.1.0-canary.3 + +### Patch Changes + +- 681d4ed: fix backwards compatibility with `render` versions + +## 4.1.0-canary.2 + +### Patch Changes + +- 9b1adb0: Use range of versions for dependencies + +## 4.1.0-canary.1 + +### Patch Changes + +- a587e17: Fix dependent of dependents not causing hot reloads +- dbf3a64: Add error message for when an email template does not have a default export + +## 4.1.0-canary.0 + +### Minor Changes + +- 4a0d4e3: Theme switcher for email template + ## 4.0.11 ### Patch Changes diff --git a/packages/react-email/package.json b/packages/react-email/package.json index 7997cd4af5..6973155b53 100644 --- a/packages/react-email/package.json +++ b/packages/react-email/package.json @@ -1,6 +1,6 @@ { "name": "react-email", - "version": "4.0.11", + "version": "4.1.0-canary.4", "description": "A live preview of your emails right in your browser.", "bin": { "email": "./dist/cli/index.mjs" @@ -62,8 +62,8 @@ "@types/mime-types": "2.1.4", "@types/node": "22.14.1", "@types/normalize-path": "3.0.2", - "@types/react": "19.0.10", - "@types/react-dom": "19.0.4", + "@types/react": "19.1.2", + "@types/react-dom": "19.1.3", "@types/webpack": "5.28.5", "autoprefixer": "10.4.21", "clsx": "2.1.1", @@ -75,8 +75,8 @@ "postcss": "8.5.3", "pretty-bytes": "6.1.1", "prism-react-renderer": "2.4.1", - "react": "19.0.0", - "react-dom": "19.0.0", + "react": "19.1.0", + "react-dom": "19.1.0", "sharp": "0.34.1", "socket.io-client": "4.8.1", "sonner": "2.0.3", diff --git a/packages/react-email/src/app/preview/[...slug]/preview.tsx b/packages/react-email/src/app/preview/[...slug]/preview.tsx index 474c33e65a..4342c7fdfb 100644 --- a/packages/react-email/src/app/preview/[...slug]/preview.tsx +++ b/packages/react-email/src/app/preview/[...slug]/preview.tsx @@ -1,7 +1,7 @@ 'use client'; import { usePathname, useRouter, useSearchParams } from 'next/navigation'; -import { use, useState } from 'react'; +import { use, useRef, useState } from 'react'; import { flushSync } from 'react-dom'; import { Toaster } from 'sonner'; import { useDebouncedCallback } from 'use-debounce'; @@ -15,9 +15,11 @@ import { Send } from '../../../components/send'; import { useToolbarState } from '../../../components/toolbar'; import { Tooltip } from '../../../components/tooltip'; import { ActiveViewToggleGroup } from '../../../components/topbar/active-view-toggle-group'; +import { ThemeToggleGroup } from '../../../components/topbar/theme-toggle-group'; import { ViewSizeControls } from '../../../components/topbar/view-size-controls'; import { PreviewContext } from '../../../contexts/preview'; import { useClampedState } from '../../../hooks/use-clamped-state'; +import { useIframeColorScheme } from '../../../hooks/use-iframe-color-scheme'; import { cn } from '../../../utils'; import { RenderingError } from './rendering-error'; @@ -32,9 +34,17 @@ const Preview = ({ emailTitle, className, ...props }: PreviewProps) => { const pathname = usePathname(); const searchParams = useSearchParams(); + const activeTheme: 'dark' | 'light' = + searchParams.get('theme') === 'dark' ? 'dark' : 'light'; const activeView = searchParams.get('view') ?? 'preview'; const activeLang = searchParams.get('lang') ?? 'jsx'; + const handleThemeChange = (theme: 'dark' | 'light') => { + const params = new URLSearchParams(searchParams); + params.set('theme', theme); + router.push(`${pathname}?${params.toString()}`); + }; + const handleViewChange = (view: string) => { const params = new URLSearchParams(searchParams); params.set('view', view); @@ -51,6 +61,9 @@ const Preview = ({ emailTitle, className, ...props }: PreviewProps) => { ); }; + const iframeRef = useRef(null); + useIframeColorScheme(iframeRef, activeTheme); + const hasRenderingMetadata = typeof renderedEmailMetadata !== 'undefined'; const hasErrors = 'error' in renderingResult; @@ -99,6 +112,10 @@ const Preview = ({ emailTitle, className, ...props }: PreviewProps) => { viewHeight={height} viewWidth={width} /> + handleThemeChange(theme)} + /> {