react-email
Version:
A live preview of your emails right in your browser.
122 lines (106 loc) • 3.17 kB
text/typescript
import { parse, type StyleSheet } from 'css-tree';
import { compile } from 'tailwindcss';
import type { TailwindConfig } from '../../tailwind.js';
import indexCss from './tailwind-stylesheets/index.js';
import preflightCss from './tailwind-stylesheets/preflight.js';
import themeCss from './tailwind-stylesheets/theme.js';
import utilitiesCss from './tailwind-stylesheets/utilities.js';
export type TailwindSetup = Awaited<ReturnType<typeof setupTailwind>>;
interface CSSConfigs {
theme?: string;
utility?: string;
}
interface SetupTailwindProps {
config?: TailwindConfig;
cssConfigs?: CSSConfigs;
}
const SETUP_TAILWIND_KEYS = new Set(['config', 'cssConfigs']);
export async function setupTailwind(props: SetupTailwindProps = {}) {
const stray = Object.keys(props).filter((k) => !SETUP_TAILWIND_KEYS.has(k));
if (stray.length > 0) {
throw new Error(
`setupTailwind now takes { config, cssConfigs } — received unexpected keys: ${stray.join(', ')}. ` +
'If you used to call setupTailwind(config), wrap it: setupTailwind({ config }).',
);
}
const { config, cssConfigs } = props;
const baseCss = `
@layer theme, base, components, utilities;
@import "tailwindcss/theme.css" layer(theme);
@import "tailwindcss/utilities.css" layer(utilities);
${cssConfigs?.theme ? '@import "custom-theme.css" layer(theme);' : ''}
${cssConfigs?.utility ? '@import "custom-utilities.css" layer(utilities);' : ''}
@config;
`;
const compiler = await compile(baseCss, {
async loadModule(id, base, resourceHint) {
if (resourceHint === 'config') {
return {
path: id,
base: base,
module: config ?? {},
};
}
throw new Error(
`NO-OP: should we implement support for ${resourceHint}?`,
);
},
polyfills: 0, // All
async loadStylesheet(id, base) {
if (id === 'tailwindcss') {
return {
base,
path: 'tailwindcss/index.css',
content: indexCss,
};
}
if (id === 'tailwindcss/preflight.css') {
return {
base,
path: id,
content: preflightCss,
};
}
if (id === 'tailwindcss/theme.css') {
return {
base,
path: id,
content: themeCss,
};
}
if (id === 'tailwindcss/utilities.css') {
return {
base,
path: id,
content: utilitiesCss,
};
}
if (id === 'custom-theme.css') {
return {
base,
path: id,
content: cssConfigs?.theme ?? '',
};
}
if (id === 'custom-utilities.css') {
return {
base,
path: id,
content: cssConfigs?.utility ?? '',
};
}
throw new Error(
'stylesheet not supported, you can only import the ones from tailwindcss',
);
},
});
let css: string = baseCss;
return {
addUtilities: function addUtilities(candidates: string[]): void {
css = compiler.build(candidates);
},
getStyleSheet: function getCss() {
return parse(css) as StyleSheet;
},
};
}