@depup/react-email 5.2.10-depup.1 → 6.9.0-depup.1
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.
- package/CHANGELOG.md +313 -0
- package/README.md +11 -10
- package/changes.json +21 -17
- package/dev/CHANGELOG.md +2 -0
- package/dev/index.js +1 -1
- package/dev/package.json +1 -1
- package/dist/_virtual/_rolldown/runtime.cjs +23 -0
- package/dist/cli/index.mjs +7801 -0
- package/dist/components/body/body.cjs +39 -0
- package/dist/components/body/body.d.cts +7 -0
- package/dist/components/body/body.d.mts +7 -0
- package/dist/components/body/body.mjs +37 -0
- package/dist/components/body/index.d.cts +1 -0
- package/dist/components/body/index.d.mts +1 -0
- package/dist/components/body/margin-properties.cjs +30 -0
- package/dist/components/body/margin-properties.mjs +29 -0
- package/dist/components/button/button.cjs +64 -0
- package/dist/components/button/button.d.cts +13 -0
- package/dist/components/button/button.d.mts +13 -0
- package/dist/components/button/button.mjs +62 -0
- package/dist/components/button/index.d.cts +1 -0
- package/dist/components/button/index.d.mts +1 -0
- package/dist/components/button/utils/parse-padding.cjs +90 -0
- package/dist/components/button/utils/parse-padding.mjs +90 -0
- package/dist/components/button/utils/px-to-pt.cjs +4 -0
- package/dist/components/button/utils/px-to-pt.mjs +4 -0
- package/dist/components/code-block/code-block.cjs +79 -0
- package/dist/components/code-block/code-block.d.cts +20 -0
- package/dist/components/code-block/code-block.d.mts +20 -0
- package/dist/components/code-block/code-block.mjs +77 -0
- package/dist/components/code-block/index.d.cts +3 -0
- package/dist/components/code-block/index.d.mts +3 -0
- package/dist/components/code-block/languages-available.d.cts +4 -0
- package/dist/components/code-block/languages-available.d.mts +4 -0
- package/dist/components/code-block/prism.cjs +14564 -0
- package/dist/components/code-block/prism.mjs +14562 -0
- package/dist/components/code-block/themes.cjs +2578 -0
- package/dist/components/code-block/themes.d.cts +4877 -0
- package/dist/components/code-block/themes.d.mts +4877 -0
- package/dist/components/code-block/themes.mjs +2541 -0
- package/dist/components/code-inline/code-inline.cjs +43 -0
- package/dist/components/code-inline/code-inline.d.cts +12 -0
- package/dist/components/code-inline/code-inline.d.mts +12 -0
- package/dist/components/code-inline/code-inline.mjs +41 -0
- package/dist/components/code-inline/index.d.cts +1 -0
- package/dist/components/code-inline/index.d.mts +1 -0
- package/dist/components/column/column.cjs +19 -0
- package/dist/components/column/column.d.cts +7 -0
- package/dist/components/column/column.d.mts +7 -0
- package/dist/components/column/column.mjs +17 -0
- package/dist/components/column/index.d.cts +1 -0
- package/dist/components/column/index.d.mts +1 -0
- package/dist/components/container/container.cjs +42 -0
- package/dist/components/container/container.d.cts +7 -0
- package/dist/components/container/container.d.mts +7 -0
- package/dist/components/container/container.mjs +40 -0
- package/dist/components/container/index.d.cts +1 -0
- package/dist/components/container/index.d.mts +1 -0
- package/dist/components/element-marker.cjs +8 -0
- package/dist/components/element-marker.mjs +7 -0
- package/dist/components/font/font.cjs +22 -0
- package/dist/components/font/font.d.cts +26 -0
- package/dist/components/font/font.d.mts +26 -0
- package/dist/components/font/font.mjs +21 -0
- package/dist/components/font/index.d.cts +1 -0
- package/dist/components/font/index.d.mts +1 -0
- package/dist/components/head/head.cjs +20 -0
- package/dist/components/head/head.d.cts +7 -0
- package/dist/components/head/head.d.mts +7 -0
- package/dist/components/head/head.mjs +18 -0
- package/dist/components/head/index.d.cts +1 -0
- package/dist/components/head/index.d.mts +1 -0
- package/dist/components/heading/heading.cjs +30 -0
- package/dist/components/heading/heading.d.cts +22 -0
- package/dist/components/heading/heading.d.mts +22 -0
- package/dist/components/heading/heading.mjs +28 -0
- package/dist/components/heading/index.d.cts +1 -0
- package/dist/components/heading/index.d.mts +1 -0
- package/dist/components/heading/utils/as.d.cts +16 -0
- package/dist/components/heading/utils/as.d.mts +16 -0
- package/dist/components/heading/utils/spaces.cjs +24 -0
- package/dist/components/heading/utils/spaces.d.cts +14 -0
- package/dist/components/heading/utils/spaces.d.mts +14 -0
- package/dist/components/heading/utils/spaces.mjs +24 -0
- package/dist/components/hr/hr.cjs +21 -0
- package/dist/components/hr/hr.d.cts +7 -0
- package/dist/components/hr/hr.d.mts +7 -0
- package/dist/components/hr/hr.mjs +19 -0
- package/dist/components/hr/index.d.cts +1 -0
- package/dist/components/hr/index.d.mts +1 -0
- package/dist/components/html/html.cjs +15 -0
- package/dist/components/html/html.d.cts +7 -0
- package/dist/components/html/html.d.mts +7 -0
- package/dist/components/html/html.mjs +13 -0
- package/dist/components/html/index.d.cts +1 -0
- package/dist/components/html/index.d.mts +1 -0
- package/dist/components/img/img.cjs +25 -0
- package/dist/components/img/img.d.cts +7 -0
- package/dist/components/img/img.d.mts +7 -0
- package/dist/components/img/img.mjs +23 -0
- package/dist/components/img/index.d.cts +1 -0
- package/dist/components/img/index.d.mts +1 -0
- package/dist/components/index.d.cts +24 -0
- package/dist/components/index.d.mts +24 -0
- package/dist/components/link/index.d.cts +1 -0
- package/dist/components/link/index.d.mts +1 -0
- package/dist/components/link/link.cjs +21 -0
- package/dist/components/link/link.d.cts +7 -0
- package/dist/components/link/link.d.mts +7 -0
- package/dist/components/link/link.mjs +19 -0
- package/dist/components/markdown/index.d.cts +1 -0
- package/dist/components/markdown/index.d.mts +1 -0
- package/dist/components/markdown/markdown.cjs +101 -0
- package/dist/components/markdown/markdown.d.cts +16 -0
- package/dist/components/markdown/markdown.d.mts +16 -0
- package/dist/components/markdown/markdown.mjs +99 -0
- package/dist/components/markdown/styles.cjs +92 -0
- package/dist/components/markdown/styles.d.cts +31 -0
- package/dist/components/markdown/styles.d.mts +31 -0
- package/dist/components/markdown/styles.mjs +92 -0
- package/dist/components/markdown/utils/parse-css-in-js-to-inline-css.cjs +60 -0
- package/dist/components/markdown/utils/parse-css-in-js-to-inline-css.mjs +60 -0
- package/dist/components/preview/index.d.cts +1 -0
- package/dist/components/preview/index.d.mts +1 -0
- package/dist/components/preview/preview.cjs +34 -0
- package/dist/components/preview/preview.d.cts +21 -0
- package/dist/components/preview/preview.d.mts +21 -0
- package/dist/components/preview/preview.mjs +31 -0
- package/dist/components/row/index.d.cts +1 -0
- package/dist/components/row/index.d.mts +1 -0
- package/dist/components/row/row.cjs +30 -0
- package/dist/components/row/row.d.cts +11 -0
- package/dist/components/row/row.d.mts +11 -0
- package/dist/components/row/row.mjs +28 -0
- package/dist/components/section/index.d.cts +1 -0
- package/dist/components/section/index.d.mts +1 -0
- package/dist/components/section/section.cjs +36 -0
- package/dist/components/section/section.d.cts +7 -0
- package/dist/components/section/section.d.mts +7 -0
- package/dist/components/section/section.mjs +34 -0
- package/dist/components/tailwind/hooks/use-suspended-promise.cjs +15 -0
- package/dist/components/tailwind/hooks/use-suspended-promise.mjs +15 -0
- package/dist/components/tailwind/index.d.cts +4 -0
- package/dist/components/tailwind/index.d.mts +4 -0
- package/dist/components/tailwind/inline-styles.cjs +11 -0
- package/dist/components/tailwind/inline-styles.d.cts +6 -0
- package/dist/components/tailwind/inline-styles.d.mts +6 -0
- package/dist/components/tailwind/inline-styles.mjs +11 -0
- package/dist/components/tailwind/sanitize-stylesheet.cjs +11 -0
- package/dist/components/tailwind/sanitize-stylesheet.d.cts +6 -0
- package/dist/components/tailwind/sanitize-stylesheet.d.mts +6 -0
- package/dist/components/tailwind/sanitize-stylesheet.mjs +11 -0
- package/dist/components/tailwind/tailwind.cjs +120 -0
- package/dist/components/tailwind/tailwind.d.cts +25 -0
- package/dist/components/tailwind/tailwind.d.mts +25 -0
- package/dist/components/tailwind/tailwind.mjs +117 -0
- package/dist/components/tailwind/utils/compatibility/get-react-property.cjs +10 -0
- package/dist/components/tailwind/utils/compatibility/get-react-property.mjs +10 -0
- package/dist/components/tailwind/utils/compatibility/sanitize-class-name.cjs +26 -0
- package/dist/components/tailwind/utils/compatibility/sanitize-class-name.mjs +26 -0
- package/dist/components/tailwind/utils/css/downlevel-for-email-clients.cjs +126 -0
- package/dist/components/tailwind/utils/css/downlevel-for-email-clients.mjs +125 -0
- package/dist/components/tailwind/utils/css/extract-rules-per-class.cjs +45 -0
- package/dist/components/tailwind/utils/css/extract-rules-per-class.mjs +44 -0
- package/dist/components/tailwind/utils/css/get-custom-properties.cjs +35 -0
- package/dist/components/tailwind/utils/css/get-custom-properties.mjs +34 -0
- package/dist/components/tailwind/utils/css/is-part-inlinable.cjs +10 -0
- package/dist/components/tailwind/utils/css/is-part-inlinable.mjs +9 -0
- package/dist/components/tailwind/utils/css/is-rule-inlinable.cjs +10 -0
- package/dist/components/tailwind/utils/css/is-rule-inlinable.mjs +9 -0
- package/dist/components/tailwind/utils/css/make-inline-styles-for.cjs +52 -0
- package/dist/components/tailwind/utils/css/make-inline-styles-for.mjs +51 -0
- package/dist/components/tailwind/utils/css/resolve-all-css-variables.cjs +89 -0
- package/dist/components/tailwind/utils/css/resolve-all-css-variables.mjs +88 -0
- package/dist/components/tailwind/utils/css/resolve-calc-expressions.cjs +92 -0
- package/dist/components/tailwind/utils/css/resolve-calc-expressions.mjs +91 -0
- package/dist/components/tailwind/utils/css/sanitize-declarations.cjs +310 -0
- package/dist/components/tailwind/utils/css/sanitize-declarations.mjs +309 -0
- package/dist/components/tailwind/utils/css/sanitize-non-inlinable-rules.cjs +46 -0
- package/dist/components/tailwind/utils/css/sanitize-non-inlinable-rules.mjs +45 -0
- package/dist/components/tailwind/utils/css/split-mixed-rule.cjs +41 -0
- package/dist/components/tailwind/utils/css/split-mixed-rule.mjs +40 -0
- package/dist/components/tailwind/utils/css/strip-empty-tailwind-vars.cjs +52 -0
- package/dist/components/tailwind/utils/css/strip-empty-tailwind-vars.mjs +51 -0
- package/dist/components/tailwind/utils/css/unwrap-value.cjs +7 -0
- package/dist/components/tailwind/utils/css/unwrap-value.mjs +7 -0
- package/dist/components/tailwind/utils/react/is-component.cjs +7 -0
- package/dist/components/tailwind/utils/react/is-component.mjs +7 -0
- package/dist/components/tailwind/utils/react/map-react-tree.cjs +32 -0
- package/dist/components/tailwind/utils/react/map-react-tree.mjs +30 -0
- package/dist/components/tailwind/utils/tailwindcss/clone-element-with-inlined-styles.cjs +37 -0
- package/dist/components/tailwind/utils/tailwindcss/clone-element-with-inlined-styles.mjs +35 -0
- package/dist/components/tailwind/utils/tailwindcss/setup-tailwind.cjs +77 -0
- package/dist/components/tailwind/utils/tailwindcss/setup-tailwind.d.cts +19 -0
- package/dist/components/tailwind/utils/tailwindcss/setup-tailwind.d.mts +19 -0
- package/dist/components/tailwind/utils/tailwindcss/setup-tailwind.mjs +76 -0
- package/dist/components/tailwind/utils/tailwindcss/tailwind-stylesheets/index.cjs +901 -0
- package/dist/components/tailwind/utils/tailwindcss/tailwind-stylesheets/index.mjs +901 -0
- package/dist/components/tailwind/utils/tailwindcss/tailwind-stylesheets/preflight.cjs +398 -0
- package/dist/components/tailwind/utils/tailwindcss/tailwind-stylesheets/preflight.mjs +398 -0
- package/dist/components/tailwind/utils/tailwindcss/tailwind-stylesheets/theme.cjs +467 -0
- package/dist/components/tailwind/utils/tailwindcss/tailwind-stylesheets/theme.mjs +467 -0
- package/dist/components/tailwind/utils/tailwindcss/tailwind-stylesheets/utilities.cjs +6 -0
- package/dist/components/tailwind/utils/tailwindcss/tailwind-stylesheets/utilities.mjs +6 -0
- package/dist/components/tailwind/utils/text/from-dash-case-to-camel-case.cjs +6 -0
- package/dist/components/tailwind/utils/text/from-dash-case-to-camel-case.mjs +6 -0
- package/dist/components/text/index.d.cts +1 -0
- package/dist/components/text/index.d.mts +1 -0
- package/dist/components/text/text.cjs +43 -0
- package/dist/components/text/text.d.cts +7 -0
- package/dist/components/text/text.d.mts +7 -0
- package/dist/components/text/text.mjs +41 -0
- package/dist/components/text/utils/compute-margins.cjs +62 -0
- package/dist/components/text/utils/compute-margins.mjs +62 -0
- package/dist/index.cjs +95 -0
- package/dist/index.d.cts +26 -0
- package/dist/index.d.mts +26 -0
- package/dist/index.mjs +25 -7326
- package/package.json +64 -32
- package/src/components/body/__snapshots__/body.spec.tsx.snap +23 -0
- package/src/components/body/body.spec.tsx +78 -0
- package/src/components/body/body.tsx +62 -0
- package/src/components/body/index.ts +1 -0
- package/src/components/body/margin-properties.ts +27 -0
- package/src/components/button/button.spec.tsx +53 -0
- package/src/components/button/button.tsx +114 -0
- package/src/components/button/index.ts +1 -0
- package/src/components/button/utils/parse-padding.ts +137 -0
- package/src/components/button/utils/px-to-pt.ts +4 -0
- package/src/components/button/utils/utils.spec.ts +153 -0
- package/src/components/code-block/code-block.tsx +136 -0
- package/src/components/code-block/index.ts +3 -0
- package/src/components/code-block/languages-available.ts +402 -0
- package/src/components/code-block/prism.ts +15618 -0
- package/src/components/code-block/themes.ts +4929 -0
- package/src/components/code-inline/code-inline.tsx +60 -0
- package/src/components/code-inline/index.ts +1 -0
- package/src/components/column/column.spec.tsx +28 -0
- package/src/components/column/column.tsx +17 -0
- package/src/components/column/index.ts +1 -0
- package/src/components/container/container.spec.tsx +33 -0
- package/src/components/container/container.tsx +59 -0
- package/src/components/container/index.ts +1 -0
- package/src/components/element-marker.ts +5 -0
- package/src/components/font/font.spec.tsx +63 -0
- package/src/components/font/font.tsx +76 -0
- package/src/components/font/index.ts +1 -0
- package/src/components/head/head.spec.tsx +34 -0
- package/src/components/head/head.tsx +15 -0
- package/src/components/head/index.ts +1 -0
- package/src/components/heading/heading.spec.tsx +32 -0
- package/src/components/heading/heading.tsx +31 -0
- package/src/components/heading/index.ts +1 -0
- package/src/components/heading/utils/as.ts +26 -0
- package/src/components/heading/utils/spaces.ts +64 -0
- package/src/components/heading/utils/utils.spec.ts +70 -0
- package/src/components/hr/hr.spec.tsx +22 -0
- package/src/components/hr/hr.tsx +23 -0
- package/src/components/hr/index.ts +1 -0
- package/src/components/html/html.spec.tsx +26 -0
- package/src/components/html/html.tsx +13 -0
- package/src/components/html/index.ts +1 -0
- package/src/components/img/img.spec.tsx +30 -0
- package/src/components/img/img.tsx +27 -0
- package/src/components/img/index.ts +1 -0
- package/src/components/index.ts +19 -0
- package/src/components/link/index.ts +1 -0
- package/src/components/link/link.spec.tsx +37 -0
- package/src/components/link/link.tsx +24 -0
- package/src/components/markdown/index.ts +1 -0
- package/src/components/markdown/markdown.spec.tsx +221 -0
- package/src/components/markdown/markdown.tsx +239 -0
- package/src/components/markdown/styles.ts +130 -0
- package/src/components/markdown/utils/parse-css-in-js-to-inline-css.spec.ts +42 -0
- package/src/components/markdown/utils/parse-css-in-js-to-inline-css.ts +73 -0
- package/src/components/preview/index.ts +1 -0
- package/src/components/preview/preview.spec.tsx +49 -0
- package/src/components/preview/preview.tsx +56 -0
- package/src/components/row/index.ts +1 -0
- package/src/components/row/row.spec.tsx +28 -0
- package/src/components/row/row.tsx +33 -0
- package/src/components/section/index.ts +1 -0
- package/src/components/section/section.spec.tsx +58 -0
- package/src/components/section/section.tsx +59 -0
- package/src/components/tailwind/e2e/integrations.spec.ts +44 -0
- package/src/components/tailwind/e2e/nextjs/README.md +9 -0
- package/src/components/tailwind/e2e/nextjs/emails/vercel-invite-user.tsx +151 -0
- package/src/components/tailwind/e2e/nextjs/next.config.mjs +6 -0
- package/src/components/tailwind/e2e/nextjs/package.json +24 -0
- package/src/components/tailwind/e2e/nextjs/src/app/favicon.ico +0 -0
- package/src/components/tailwind/e2e/nextjs/src/app/layout.tsx +23 -0
- package/src/components/tailwind/e2e/nextjs/src/app/page.tsx +7 -0
- package/src/components/tailwind/e2e/nextjs/tsconfig.json +27 -0
- package/src/components/tailwind/e2e/vite/README.md +9 -0
- package/src/components/tailwind/e2e/vite/emails/vercel-invite-user.tsx +151 -0
- package/src/components/tailwind/e2e/vite/index.html +13 -0
- package/src/components/tailwind/e2e/vite/package.json +25 -0
- package/src/components/tailwind/e2e/vite/public/vite.svg +1 -0
- package/src/components/tailwind/e2e/vite/src/App.tsx +10 -0
- package/src/components/tailwind/e2e/vite/src/main.tsx +9 -0
- package/src/components/tailwind/e2e/vite/src/vite-env.d.ts +1 -0
- package/src/components/tailwind/e2e/vite/tsconfig.json +25 -0
- package/src/components/tailwind/e2e/vite/tsconfig.node.json +11 -0
- package/src/components/tailwind/e2e/vite/vite.config.ts +7 -0
- package/src/components/tailwind/hooks/use-suspended-promise.ts +34 -0
- package/src/components/tailwind/hooks/use-suspensed-promise.spec.ts +263 -0
- package/src/components/tailwind/index.ts +4 -0
- package/src/components/tailwind/inline-styles.spec.ts +49 -0
- package/src/components/tailwind/inline-styles.ts +21 -0
- package/src/components/tailwind/sanitize-stylesheet.ts +10 -0
- package/src/components/tailwind/tailwind.spec.tsx +1390 -0
- package/src/components/tailwind/tailwind.tsx +178 -0
- package/src/components/tailwind/utils/__snapshots__/quick-safe-render-to-string.spec.tsx.snap +3 -0
- package/src/components/tailwind/utils/compatibility/escape-class-name.spec.ts +17 -0
- package/src/components/tailwind/utils/compatibility/escape-class-name.ts +18 -0
- package/src/components/tailwind/utils/compatibility/get-react-property.ts +15 -0
- package/src/components/tailwind/utils/compatibility/sanitize-class-name.spec.ts +7 -0
- package/src/components/tailwind/utils/compatibility/sanitize-class-name.ts +36 -0
- package/src/components/tailwind/utils/compatibility/unescape-class.ts +3 -0
- package/src/components/tailwind/utils/css/__snapshots__/extract-rules-matching-classes.spec.ts.snap +23 -0
- package/src/components/tailwind/utils/css/__snapshots__/remove-rule-duplicates-from-root.spec.ts.snap +3 -0
- package/src/components/tailwind/utils/css/__snapshots__/sanitize-non-inlinable-classes.spec.ts.snap +7 -0
- package/src/components/tailwind/utils/css/downlevel-for-email-clients.spec.ts +119 -0
- package/src/components/tailwind/utils/css/downlevel-for-email-clients.ts +244 -0
- package/src/components/tailwind/utils/css/extract-rules-per-class.spec.ts +232 -0
- package/src/components/tailwind/utils/css/extract-rules-per-class.ts +76 -0
- package/src/components/tailwind/utils/css/get-custom-properties.ts +49 -0
- package/src/components/tailwind/utils/css/is-part-inlinable.ts +15 -0
- package/src/components/tailwind/utils/css/is-rule-inlinable.ts +15 -0
- package/src/components/tailwind/utils/css/make-inline-styles-for.spec.ts +124 -0
- package/src/components/tailwind/utils/css/make-inline-styles-for.ts +73 -0
- package/src/components/tailwind/utils/css/resolve-all-css-variables.spec.ts +296 -0
- package/src/components/tailwind/utils/css/resolve-all-css-variables.ts +236 -0
- package/src/components/tailwind/utils/css/resolve-calc-expressions.spec.ts +36 -0
- package/src/components/tailwind/utils/css/resolve-calc-expressions.ts +147 -0
- package/src/components/tailwind/utils/css/sanitize-declarations.spec.ts +491 -0
- package/src/components/tailwind/utils/css/sanitize-declarations.ts +443 -0
- package/src/components/tailwind/utils/css/sanitize-non-inlinable-rules.spec.ts +72 -0
- package/src/components/tailwind/utils/css/sanitize-non-inlinable-rules.ts +48 -0
- package/src/components/tailwind/utils/css/split-mixed-rule.ts +68 -0
- package/src/components/tailwind/utils/css/strip-empty-tailwind-vars.spec.ts +128 -0
- package/src/components/tailwind/utils/css/strip-empty-tailwind-vars.ts +70 -0
- package/src/components/tailwind/utils/css/unwrap-value.ts +9 -0
- package/src/components/tailwind/utils/react/is-component.ts +12 -0
- package/src/components/tailwind/utils/react/map-react-tree.spec.tsx +58 -0
- package/src/components/tailwind/utils/react/map-react-tree.ts +58 -0
- package/src/components/tailwind/utils/tailwindcss/clone-element-with-inlined-styles.ts +61 -0
- package/src/components/tailwind/utils/tailwindcss/setup-tailwind.spec.ts +25 -0
- package/src/components/tailwind/utils/tailwindcss/setup-tailwind.ts +121 -0
- package/src/components/tailwind/utils/tailwindcss/tailwind-stylesheets/index.ts +900 -0
- package/src/components/tailwind/utils/tailwindcss/tailwind-stylesheets/preflight.ts +397 -0
- package/src/components/tailwind/utils/tailwindcss/tailwind-stylesheets/theme.ts +466 -0
- package/src/components/tailwind/utils/tailwindcss/tailwind-stylesheets/utilities.ts +5 -0
- package/src/components/tailwind/utils/text/from-dash-case-to-camel-case.ts +3 -0
- package/src/components/text/index.ts +1 -0
- package/src/components/text/text.spec.tsx +35 -0
- package/src/components/text/text.tsx +50 -0
- package/src/components/text/utils/compute-margins.spec.ts +67 -0
- package/src/components/text/utils/compute-margins.ts +102 -0
- package/src/index.ts +2 -110
- package/tsconfig.json +9 -4
- package/tsdown.config.ts +51 -6
- package/vitest.config.ts +1 -0
- package/vitest.e2e.config.ts +17 -0
- package/src/commands/build.ts +0 -269
- package/src/commands/dev.ts +0 -27
- package/src/commands/export.ts +0 -204
- package/src/commands/resend/reset.ts +0 -8
- package/src/commands/resend/setup.ts +0 -29
- package/src/commands/start.ts +0 -38
- package/src/utils/conf.ts +0 -9
- package/src/utils/esbuild/escape-string-for-regex.ts +0 -3
- package/src/utils/esbuild/renderring-utilities-exporter.ts +0 -63
- package/src/utils/get-emails-directory-metadata.spec.ts +0 -82
- package/src/utils/get-emails-directory-metadata.ts +0 -140
- package/src/utils/get-preview-server-location.ts +0 -50
- package/src/utils/index.ts +0 -2
- package/src/utils/packageJson.ts +0 -4
- package/src/utils/preview/get-env-variables-for-preview-app.ts +0 -20
- package/src/utils/preview/hot-reloading/create-dependency-graph.spec.ts +0 -226
- package/src/utils/preview/hot-reloading/create-dependency-graph.ts +0 -343
- package/src/utils/preview/hot-reloading/get-imported-modules.spec.ts +0 -151
- package/src/utils/preview/hot-reloading/get-imported-modules.ts +0 -49
- package/src/utils/preview/hot-reloading/resolve-path-aliases.spec.ts +0 -11
- package/src/utils/preview/hot-reloading/resolve-path-aliases.ts +0 -32
- package/src/utils/preview/hot-reloading/setup-hot-reloading.ts +0 -121
- package/src/utils/preview/hot-reloading/test/dependency-graph/inner/data-to-import.json +0 -1
- package/src/utils/preview/hot-reloading/test/dependency-graph/inner/file-a.ts +0 -5
- package/src/utils/preview/hot-reloading/test/dependency-graph/inner/file-b.ts +0 -5
- package/src/utils/preview/hot-reloading/test/dependency-graph/inner/general-importing-file.ts +0 -9
- package/src/utils/preview/hot-reloading/test/dependency-graph/inner/outer-dependency.ts +0 -3
- package/src/utils/preview/hot-reloading/test/dependency-graph/inner/path-aliases.ts +0 -1
- package/src/utils/preview/hot-reloading/test/dependency-graph/outer.ts +0 -5
- package/src/utils/preview/hot-reloading/test/some-file.ts +0 -0
- package/src/utils/preview/hot-reloading/test/tsconfig.json +0 -8
- package/src/utils/preview/index.ts +0 -2
- package/src/utils/preview/serve-static-file.ts +0 -51
- package/src/utils/preview/start-dev-server.ts +0 -252
- package/src/utils/register-spinner-autostopping.ts +0 -28
- package/src/utils/style-text.ts +0 -11
- package/src/utils/tree.spec.ts +0 -29
- package/src/utils/tree.ts +0 -76
- package/src/utils/types/hot-reload-change.ts +0 -6
- package/src/utils/types/hot-reload-event.ts +0 -3
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { render } from '@react-email/render';
|
|
2
|
+
import { Section } from './index.js';
|
|
3
|
+
|
|
4
|
+
describe('<Section> component', () => {
|
|
5
|
+
it('renders correctly', async () => {
|
|
6
|
+
const actualOutput = await render(<Section>Lorem ipsum</Section>);
|
|
7
|
+
expect(actualOutput).toMatchInlineSnapshot(
|
|
8
|
+
`"<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><!--$--><table align="center" width="100%" border="0" cellPadding="0" cellSpacing="0" role="presentation"><tbody><tr><td>Lorem ipsum</td></tr></tbody></table><!--/$-->"`,
|
|
9
|
+
);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('renders children correctly', async () => {
|
|
13
|
+
const testMessage = 'Test message';
|
|
14
|
+
const html = await render(<Section>{testMessage}</Section>);
|
|
15
|
+
expect(html).toContain(testMessage);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('passes style and other props correctly', async () => {
|
|
19
|
+
const style = { backgroundColor: 'red' };
|
|
20
|
+
const html = await render(
|
|
21
|
+
<Section data-testid="section-test" style={style}>
|
|
22
|
+
Test
|
|
23
|
+
</Section>,
|
|
24
|
+
);
|
|
25
|
+
expect(html).toContain('style="background-color:red"');
|
|
26
|
+
expect(html).toContain('data-testid="section-test"');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('renders with <td> wrapper if no <Column> is provided', async () => {
|
|
30
|
+
const actualOutput = await render(
|
|
31
|
+
<Section>
|
|
32
|
+
<div>Lorem ipsum</div>
|
|
33
|
+
</Section>,
|
|
34
|
+
);
|
|
35
|
+
expect(actualOutput).toContain('<td>');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('renders with <td> wrapper if <Column> is provided', async () => {
|
|
39
|
+
const actualOutput = await render(
|
|
40
|
+
<Section>
|
|
41
|
+
<td>Lorem ipsum</td>
|
|
42
|
+
</Section>,
|
|
43
|
+
);
|
|
44
|
+
expect(actualOutput).toContain('<td>');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('renders wrapping any child provided in a <td> tag', async () => {
|
|
48
|
+
const actualOutput = await render(
|
|
49
|
+
<Section>
|
|
50
|
+
<div>Lorem ipsum</div>
|
|
51
|
+
<p>Lorem ipsum</p>
|
|
52
|
+
<img alt="Lorem" src="lorem.ipsum" />
|
|
53
|
+
</Section>,
|
|
54
|
+
);
|
|
55
|
+
const tdChildrenArr = actualOutput.match(/<td\s*.*?>.*?<\/td>/g);
|
|
56
|
+
expect(tdChildrenArr).toHaveLength(1);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { markAsElement } from '../element-marker.js';
|
|
3
|
+
|
|
4
|
+
export type SectionProps = Readonly<React.ComponentPropsWithoutRef<'table'>>;
|
|
5
|
+
|
|
6
|
+
export const Section = React.forwardRef<HTMLTableElement, SectionProps>(
|
|
7
|
+
({ children, style = {}, ...props }, ref) => {
|
|
8
|
+
// Split padding styles to improve compatibility with Klaviyo and Outlook,
|
|
9
|
+
// while preserving user-provided style property order without allocating
|
|
10
|
+
// entry arrays on each render.
|
|
11
|
+
const tdStyle: React.CSSProperties = {};
|
|
12
|
+
const tableStyle: React.CSSProperties = {};
|
|
13
|
+
|
|
14
|
+
const styleRecord = style as Record<string, unknown>;
|
|
15
|
+
|
|
16
|
+
for (const key in styleRecord) {
|
|
17
|
+
if (!Object.hasOwn(styleRecord, key)) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const value = styleRecord[key];
|
|
22
|
+
|
|
23
|
+
if (
|
|
24
|
+
key === 'padding' ||
|
|
25
|
+
key === 'paddingTop' ||
|
|
26
|
+
key === 'paddingRight' ||
|
|
27
|
+
key === 'paddingBottom' ||
|
|
28
|
+
key === 'paddingLeft'
|
|
29
|
+
) {
|
|
30
|
+
(tdStyle as Record<string, unknown>)[key] = value;
|
|
31
|
+
} else {
|
|
32
|
+
(tableStyle as Record<string, unknown>)[key] = value;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<table
|
|
38
|
+
align="center"
|
|
39
|
+
width="100%"
|
|
40
|
+
border={0}
|
|
41
|
+
cellPadding="0"
|
|
42
|
+
cellSpacing="0"
|
|
43
|
+
role="presentation"
|
|
44
|
+
{...props}
|
|
45
|
+
ref={ref}
|
|
46
|
+
style={tableStyle}
|
|
47
|
+
>
|
|
48
|
+
<tbody>
|
|
49
|
+
<tr>
|
|
50
|
+
<td style={tdStyle}>{children}</td>
|
|
51
|
+
</tr>
|
|
52
|
+
</tbody>
|
|
53
|
+
</table>
|
|
54
|
+
);
|
|
55
|
+
},
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
Section.displayName = 'Section';
|
|
59
|
+
markAsElement(Section);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import shell from 'shelljs';
|
|
3
|
+
|
|
4
|
+
const $ = (command: string, cwd: string = path.resolve(__dirname, '..')) => {
|
|
5
|
+
const executionResult = shell.exec(command, {
|
|
6
|
+
cwd,
|
|
7
|
+
fatal: true,
|
|
8
|
+
silent: true,
|
|
9
|
+
});
|
|
10
|
+
if (executionResult.code !== 0) {
|
|
11
|
+
process.stdout.write(executionResult.stderr);
|
|
12
|
+
process.stderr.write(executionResult.stderr);
|
|
13
|
+
}
|
|
14
|
+
expect(
|
|
15
|
+
executionResult.code,
|
|
16
|
+
`Expected command "${command}" to work properly but it returned a non-zero exit code`,
|
|
17
|
+
).toBe(0);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
describe('integrations', () => {
|
|
21
|
+
beforeAll(() => {
|
|
22
|
+
const packageLocation = path.resolve(__dirname, '../../../..');
|
|
23
|
+
$('yalc installations clean react-email', packageLocation);
|
|
24
|
+
$('yalc publish', packageLocation);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const integrationsLocation = __dirname;
|
|
28
|
+
|
|
29
|
+
test("Tailwind works on the Next App's build process", {
|
|
30
|
+
timeout: 65_000,
|
|
31
|
+
}, () => {
|
|
32
|
+
const nextAppLocation = path.resolve(integrationsLocation, 'nextjs');
|
|
33
|
+
$('npm install', nextAppLocation);
|
|
34
|
+
$('npm run build', nextAppLocation);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
test("Tailwind works on the Vite App's build process", {
|
|
38
|
+
timeout: 15_000,
|
|
39
|
+
}, () => {
|
|
40
|
+
const viteAppLocation = path.resolve(integrationsLocation, 'vite');
|
|
41
|
+
$('npm install', viteAppLocation);
|
|
42
|
+
$('npm run build', viteAppLocation);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
This is a NextJS project bootstrapped with `create-next-app@latest` that contains a Tailwind
|
|
2
|
+
email using most of the features we provide that will be auto-built on testing to
|
|
3
|
+
make sure this new release works properly with the latest version of NextJS when being built.
|
|
4
|
+
|
|
5
|
+
We do this testing so that things are more reliable and this couldn't be done using pnpm
|
|
6
|
+
workspaces as they link code instead of actually copying the content into node_modules.
|
|
7
|
+
The solution we use to copy the code in a way that mimics the actual `npm install @react-email/tailwind` is `yalc`.
|
|
8
|
+
|
|
9
|
+
Se [the test file](../_tests/nextjs.spec.ts) for more info.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Body,
|
|
3
|
+
Button,
|
|
4
|
+
Column,
|
|
5
|
+
Container,
|
|
6
|
+
Head,
|
|
7
|
+
Heading,
|
|
8
|
+
Hr,
|
|
9
|
+
Html,
|
|
10
|
+
Img,
|
|
11
|
+
Link,
|
|
12
|
+
Preview,
|
|
13
|
+
Row,
|
|
14
|
+
Section,
|
|
15
|
+
Tailwind,
|
|
16
|
+
Text,
|
|
17
|
+
} from 'react-email';
|
|
18
|
+
|
|
19
|
+
interface VercelInviteUserEmailProps {
|
|
20
|
+
username?: string;
|
|
21
|
+
userImage?: string;
|
|
22
|
+
invitedByUsername?: string;
|
|
23
|
+
invitedByEmail?: string;
|
|
24
|
+
teamName?: string;
|
|
25
|
+
teamImage?: string;
|
|
26
|
+
inviteLink?: string;
|
|
27
|
+
inviteFromIp?: string;
|
|
28
|
+
inviteFromLocation?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const baseUrl = process.env.VERCEL_URL
|
|
32
|
+
? `https://${process.env.VERCEL_URL}`
|
|
33
|
+
: '';
|
|
34
|
+
|
|
35
|
+
export const VercelInviteUserEmail = ({
|
|
36
|
+
username,
|
|
37
|
+
userImage,
|
|
38
|
+
invitedByUsername,
|
|
39
|
+
invitedByEmail,
|
|
40
|
+
teamName,
|
|
41
|
+
teamImage,
|
|
42
|
+
inviteLink,
|
|
43
|
+
inviteFromIp,
|
|
44
|
+
inviteFromLocation,
|
|
45
|
+
}: VercelInviteUserEmailProps) => {
|
|
46
|
+
const previewText = `Join ${invitedByUsername} on Vercel`;
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<Html>
|
|
50
|
+
<Head />
|
|
51
|
+
<Preview>{previewText}</Preview>
|
|
52
|
+
<Tailwind>
|
|
53
|
+
<Body className="mx-auto my-auto bg-white px-2 font-sans">
|
|
54
|
+
<Container className="mx-auto my-[40px] max-w-[465px] rounded border border-[#eaeaea] border-solid p-[20px]">
|
|
55
|
+
<Section className="mt-[32px]">
|
|
56
|
+
<Img
|
|
57
|
+
src={`${baseUrl}/static/vercel-logo.png`}
|
|
58
|
+
width="40"
|
|
59
|
+
height="37"
|
|
60
|
+
alt="Vercel"
|
|
61
|
+
className="mx-auto my-0"
|
|
62
|
+
/>
|
|
63
|
+
</Section>
|
|
64
|
+
<Heading className="mx-0 my-[30px] p-0 text-center font-normal text-[24px] text-black">
|
|
65
|
+
Join <strong>{teamName}</strong> on <strong>Vercel</strong>
|
|
66
|
+
</Heading>
|
|
67
|
+
<Text className="text-[14px] text-black leading-[24px]">
|
|
68
|
+
Hello {username},
|
|
69
|
+
</Text>
|
|
70
|
+
<Text className="text-[14px] text-black leading-[24px]">
|
|
71
|
+
<strong>{invitedByUsername}</strong> (
|
|
72
|
+
<Link
|
|
73
|
+
href={`mailto:${invitedByEmail}`}
|
|
74
|
+
className="text-blue-600 no-underline"
|
|
75
|
+
>
|
|
76
|
+
{invitedByEmail}
|
|
77
|
+
</Link>
|
|
78
|
+
) has invited you to the <strong>{teamName}</strong> team on{' '}
|
|
79
|
+
<strong>Vercel</strong>.
|
|
80
|
+
</Text>
|
|
81
|
+
<Section>
|
|
82
|
+
<Row>
|
|
83
|
+
<Column align="right">
|
|
84
|
+
<Img
|
|
85
|
+
className="rounded-full"
|
|
86
|
+
src={userImage}
|
|
87
|
+
width="64"
|
|
88
|
+
height="64"
|
|
89
|
+
/>
|
|
90
|
+
</Column>
|
|
91
|
+
<Column align="center">
|
|
92
|
+
<Img
|
|
93
|
+
src={`${baseUrl}/static/vercel-arrow.png`}
|
|
94
|
+
width="12"
|
|
95
|
+
height="9"
|
|
96
|
+
alt="invited you to"
|
|
97
|
+
/>
|
|
98
|
+
</Column>
|
|
99
|
+
<Column align="left">
|
|
100
|
+
<Img
|
|
101
|
+
className="rounded-full"
|
|
102
|
+
src={teamImage}
|
|
103
|
+
width="64"
|
|
104
|
+
height="64"
|
|
105
|
+
/>
|
|
106
|
+
</Column>
|
|
107
|
+
</Row>
|
|
108
|
+
</Section>
|
|
109
|
+
<Section className="mt-[32px] mb-[32px] text-center">
|
|
110
|
+
<Button
|
|
111
|
+
className="rounded bg-[#000000] px-5 py-3 text-center font-semibold text-[12px] text-white no-underline"
|
|
112
|
+
href={inviteLink}
|
|
113
|
+
>
|
|
114
|
+
Join the team
|
|
115
|
+
</Button>
|
|
116
|
+
</Section>
|
|
117
|
+
<Text className="text-[14px] text-black leading-[24px]">
|
|
118
|
+
or copy and paste this URL into your browser:{' '}
|
|
119
|
+
<Link href={inviteLink} className="text-blue-600 no-underline">
|
|
120
|
+
{inviteLink}
|
|
121
|
+
</Link>
|
|
122
|
+
</Text>
|
|
123
|
+
<Hr className="mx-0 my-[26px] w-full border border-[#eaeaea] border-solid" />
|
|
124
|
+
<Text className="text-[#666666] text-[12px] leading-[24px]">
|
|
125
|
+
This invitation was intended for{' '}
|
|
126
|
+
<span className="text-black">{username}</span>. This invite was
|
|
127
|
+
sent from <span className="text-black">{inviteFromIp}</span>{' '}
|
|
128
|
+
located in{' '}
|
|
129
|
+
<span className="text-black">{inviteFromLocation}</span>. If you
|
|
130
|
+
were not expecting this invitation, you can ignore this email. If
|
|
131
|
+
you are concerned about your account's safety, please reply to
|
|
132
|
+
this email to get in touch with us.
|
|
133
|
+
</Text>
|
|
134
|
+
</Container>
|
|
135
|
+
</Body>
|
|
136
|
+
</Tailwind>
|
|
137
|
+
</Html>
|
|
138
|
+
);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
VercelInviteUserEmail.PreviewProps = {
|
|
142
|
+
username: 'alanturing',
|
|
143
|
+
userImage: `${baseUrl}/static/vercel-user.png`,
|
|
144
|
+
invitedByUsername: 'Alan',
|
|
145
|
+
invitedByEmail: 'alan.turing@example.com',
|
|
146
|
+
teamName: 'Enigma',
|
|
147
|
+
teamImage: `${baseUrl}/static/vercel-team.png`,
|
|
148
|
+
inviteLink: 'https://vercel.com/teams/invite/foo',
|
|
149
|
+
inviteFromIp: '204.13.186.218',
|
|
150
|
+
inviteFromLocation: 'São Paulo, Brazil',
|
|
151
|
+
} as VercelInviteUserEmailProps;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nextjs-with-tailwind",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "next dev",
|
|
7
|
+
"build": "next build",
|
|
8
|
+
"start": "next start",
|
|
9
|
+
"preinstall": "yalc add react-email"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"react-email": "file:.yalc/react-email",
|
|
13
|
+
"next": "^16",
|
|
14
|
+
"react": "^19",
|
|
15
|
+
"react-dom": "^19"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/node": "^22.0.0",
|
|
19
|
+
"@types/react": "19.2.14",
|
|
20
|
+
"@types/react-dom": "19.2.3",
|
|
21
|
+
"typescript": "^5",
|
|
22
|
+
"yalc": "1.0.0-pre.53"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Metadata } from 'next';
|
|
2
|
+
import { Inter } from 'next/font/google';
|
|
3
|
+
|
|
4
|
+
const inter = Inter({ subsets: ['latin'] });
|
|
5
|
+
|
|
6
|
+
export const metadata: Metadata = {
|
|
7
|
+
title: 'Create Next App',
|
|
8
|
+
description: 'Generated by create next app',
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const RootLayout = ({
|
|
12
|
+
children,
|
|
13
|
+
}: Readonly<{
|
|
14
|
+
children: React.ReactNode;
|
|
15
|
+
}>) => {
|
|
16
|
+
return (
|
|
17
|
+
<html lang="en">
|
|
18
|
+
<body className={inter.className}>{children}</body>
|
|
19
|
+
</html>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default RootLayout;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { render } from 'react-email';
|
|
2
|
+
import { VercelInviteUserEmail } from '../../emails/vercel-invite-user';
|
|
3
|
+
|
|
4
|
+
export default async function Home() {
|
|
5
|
+
const emailHtml = await render(<VercelInviteUserEmail />);
|
|
6
|
+
return <div dangerouslySetInnerHTML={{ __html: emailHtml }} />;
|
|
7
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
4
|
+
"allowJs": true,
|
|
5
|
+
"skipLibCheck": true,
|
|
6
|
+
"strict": true,
|
|
7
|
+
"noEmit": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"module": "esnext",
|
|
10
|
+
"moduleResolution": "bundler",
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"isolatedModules": true,
|
|
13
|
+
"jsx": "preserve",
|
|
14
|
+
"incremental": true,
|
|
15
|
+
"plugins": [
|
|
16
|
+
{
|
|
17
|
+
"name": "next"
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
"paths": {
|
|
21
|
+
"@/*": ["./src/*"]
|
|
22
|
+
},
|
|
23
|
+
"target": "ES2017"
|
|
24
|
+
},
|
|
25
|
+
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
26
|
+
"exclude": ["node_modules"]
|
|
27
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
This is a Vite React project bootstrapped with `npm create vite@latest` that contains a Tailwind
|
|
2
|
+
email using most of the features we provide that will be auto-built on testing to
|
|
3
|
+
make sure this new release works properly with the latest version of Vite when being built.
|
|
4
|
+
|
|
5
|
+
We do this testing so that things are more reliable before we get to publishing. This
|
|
6
|
+
couldn't be done using pnpm workspaces as they link code instead of actually copying the content into node_modules.
|
|
7
|
+
The solution we use to copy the code, in a way that mimics the actual `npm install @react-email/tailwind`, is `yalc`.
|
|
8
|
+
|
|
9
|
+
Se [the test file](../_tests/vite.spec.ts) for more info.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Body,
|
|
3
|
+
Button,
|
|
4
|
+
Column,
|
|
5
|
+
Container,
|
|
6
|
+
Head,
|
|
7
|
+
Heading,
|
|
8
|
+
Hr,
|
|
9
|
+
Html,
|
|
10
|
+
Img,
|
|
11
|
+
Link,
|
|
12
|
+
Preview,
|
|
13
|
+
Row,
|
|
14
|
+
Section,
|
|
15
|
+
Tailwind,
|
|
16
|
+
Text,
|
|
17
|
+
} from 'react-email';
|
|
18
|
+
|
|
19
|
+
interface VercelInviteUserEmailProps {
|
|
20
|
+
username?: string;
|
|
21
|
+
userImage?: string;
|
|
22
|
+
invitedByUsername?: string;
|
|
23
|
+
invitedByEmail?: string;
|
|
24
|
+
teamName?: string;
|
|
25
|
+
teamImage?: string;
|
|
26
|
+
inviteLink?: string;
|
|
27
|
+
inviteFromIp?: string;
|
|
28
|
+
inviteFromLocation?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const baseUrl = import.meta.env.VERCEL_URL
|
|
32
|
+
? `https://${import.meta.env.VERCEL_URL}`
|
|
33
|
+
: '';
|
|
34
|
+
|
|
35
|
+
export const VercelInviteUserEmail = ({
|
|
36
|
+
username,
|
|
37
|
+
userImage,
|
|
38
|
+
invitedByUsername,
|
|
39
|
+
invitedByEmail,
|
|
40
|
+
teamName,
|
|
41
|
+
teamImage,
|
|
42
|
+
inviteLink,
|
|
43
|
+
inviteFromIp,
|
|
44
|
+
inviteFromLocation,
|
|
45
|
+
}: VercelInviteUserEmailProps) => {
|
|
46
|
+
const previewText = `Join ${invitedByUsername} on Vercel`;
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<Html>
|
|
50
|
+
<Head />
|
|
51
|
+
<Preview>{previewText}</Preview>
|
|
52
|
+
<Tailwind>
|
|
53
|
+
<Body className="mx-auto my-auto bg-white px-2 font-sans">
|
|
54
|
+
<Container className="mx-auto my-[40px] max-w-[465px] rounded border border-[#eaeaea] border-solid p-[20px]">
|
|
55
|
+
<Section className="mt-[32px]">
|
|
56
|
+
<Img
|
|
57
|
+
src={`${baseUrl}/static/vercel-logo.png`}
|
|
58
|
+
width="40"
|
|
59
|
+
height="37"
|
|
60
|
+
alt="Vercel"
|
|
61
|
+
className="mx-auto my-0"
|
|
62
|
+
/>
|
|
63
|
+
</Section>
|
|
64
|
+
<Heading className="mx-0 my-[30px] p-0 text-center font-normal text-[24px] text-black">
|
|
65
|
+
Join <strong>{teamName}</strong> on <strong>Vercel</strong>
|
|
66
|
+
</Heading>
|
|
67
|
+
<Text className="text-[14px] text-black leading-[24px]">
|
|
68
|
+
Hello {username},
|
|
69
|
+
</Text>
|
|
70
|
+
<Text className="text-[14px] text-black leading-[24px]">
|
|
71
|
+
<strong>{invitedByUsername}</strong> (
|
|
72
|
+
<Link
|
|
73
|
+
href={`mailto:${invitedByEmail}`}
|
|
74
|
+
className="text-blue-600 no-underline"
|
|
75
|
+
>
|
|
76
|
+
{invitedByEmail}
|
|
77
|
+
</Link>
|
|
78
|
+
) has invited you to the <strong>{teamName}</strong> team on{' '}
|
|
79
|
+
<strong>Vercel</strong>.
|
|
80
|
+
</Text>
|
|
81
|
+
<Section>
|
|
82
|
+
<Row>
|
|
83
|
+
<Column align="right">
|
|
84
|
+
<Img
|
|
85
|
+
className="rounded-full"
|
|
86
|
+
src={userImage}
|
|
87
|
+
width="64"
|
|
88
|
+
height="64"
|
|
89
|
+
/>
|
|
90
|
+
</Column>
|
|
91
|
+
<Column align="center">
|
|
92
|
+
<Img
|
|
93
|
+
src={`${baseUrl}/static/vercel-arrow.png`}
|
|
94
|
+
width="12"
|
|
95
|
+
height="9"
|
|
96
|
+
alt="invited you to"
|
|
97
|
+
/>
|
|
98
|
+
</Column>
|
|
99
|
+
<Column align="left">
|
|
100
|
+
<Img
|
|
101
|
+
className="rounded-full"
|
|
102
|
+
src={teamImage}
|
|
103
|
+
width="64"
|
|
104
|
+
height="64"
|
|
105
|
+
/>
|
|
106
|
+
</Column>
|
|
107
|
+
</Row>
|
|
108
|
+
</Section>
|
|
109
|
+
<Section className="mt-[32px] mb-[32px] text-center">
|
|
110
|
+
<Button
|
|
111
|
+
className="rounded bg-[#000000] px-5 py-3 text-center font-semibold text-[12px] text-white no-underline"
|
|
112
|
+
href={inviteLink}
|
|
113
|
+
>
|
|
114
|
+
Join the team
|
|
115
|
+
</Button>
|
|
116
|
+
</Section>
|
|
117
|
+
<Text className="text-[14px] text-black leading-[24px]">
|
|
118
|
+
or copy and paste this URL into your browser:{' '}
|
|
119
|
+
<Link href={inviteLink} className="text-blue-600 no-underline">
|
|
120
|
+
{inviteLink}
|
|
121
|
+
</Link>
|
|
122
|
+
</Text>
|
|
123
|
+
<Hr className="mx-0 my-[26px] w-full border border-[#eaeaea] border-solid" />
|
|
124
|
+
<Text className="text-[#666666] text-[12px] leading-[24px]">
|
|
125
|
+
This invitation was intended for{' '}
|
|
126
|
+
<span className="text-black">{username}</span>. This invite was
|
|
127
|
+
sent from <span className="text-black">{inviteFromIp}</span>{' '}
|
|
128
|
+
located in{' '}
|
|
129
|
+
<span className="text-black">{inviteFromLocation}</span>. If you
|
|
130
|
+
were not expecting this invitation, you can ignore this email. If
|
|
131
|
+
you are concerned about your account's safety, please reply to
|
|
132
|
+
this email to get in touch with us.
|
|
133
|
+
</Text>
|
|
134
|
+
</Container>
|
|
135
|
+
</Body>
|
|
136
|
+
</Tailwind>
|
|
137
|
+
</Html>
|
|
138
|
+
);
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
VercelInviteUserEmail.PreviewProps = {
|
|
142
|
+
username: 'alanturing',
|
|
143
|
+
userImage: `${baseUrl}/static/vercel-user.png`,
|
|
144
|
+
invitedByUsername: 'Alan',
|
|
145
|
+
invitedByEmail: 'alan.turing@example.com',
|
|
146
|
+
teamName: 'Enigma',
|
|
147
|
+
teamImage: `${baseUrl}/static/vercel-team.png`,
|
|
148
|
+
inviteLink: 'https://vercel.com/teams/invite/foo',
|
|
149
|
+
inviteFromIp: '204.13.186.218',
|
|
150
|
+
inviteFromLocation: 'São Paulo, Brazil',
|
|
151
|
+
} as VercelInviteUserEmailProps;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Vite + React + TS</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="root"></div>
|
|
11
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vite-with-tailwind",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"preinstall": "yalc add react-email",
|
|
10
|
+
"preview": "vite preview"
|
|
11
|
+
},
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"react-email": "file:.yalc/react-email",
|
|
14
|
+
"react": "^19",
|
|
15
|
+
"react-dom": "^19"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/react": "^19",
|
|
19
|
+
"@types/react-dom": "^19",
|
|
20
|
+
"@vitejs/plugin-react": "^5.1.4",
|
|
21
|
+
"typescript": "^5.2.2",
|
|
22
|
+
"vite": "^7.3.1",
|
|
23
|
+
"yalc": "1.0.0-pre.53"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { render } from 'react-email';
|
|
2
|
+
import { VercelInviteUserEmail } from '../emails/vercel-invite-user';
|
|
3
|
+
|
|
4
|
+
function App() {
|
|
5
|
+
const emailHtml = render(<VercelInviteUserEmail />);
|
|
6
|
+
|
|
7
|
+
return <div dangerouslySetInnerHTML={{ __html: emailHtml }} />;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default App;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|