@react-email/tailwind 0.0.12 → 0.0.13-canary.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/dist/index.d.mts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +153 -120
- package/dist/index.mjs +153 -120
- package/package.json +7 -3
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { Config } from 'tailwindcss';
|
|
3
3
|
|
|
4
|
+
type TailwindConfig = Omit<Config, "content">;
|
|
4
5
|
interface TailwindProps {
|
|
5
6
|
children: React.ReactNode;
|
|
6
7
|
config?: TailwindConfig;
|
|
7
8
|
}
|
|
8
9
|
declare const Tailwind: React.FC<TailwindProps>;
|
|
9
10
|
|
|
10
|
-
export { Tailwind, TailwindProps };
|
|
11
|
+
export { Tailwind, TailwindConfig, TailwindProps };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { Config } from 'tailwindcss';
|
|
3
3
|
|
|
4
|
+
type TailwindConfig = Omit<Config, "content">;
|
|
4
5
|
interface TailwindProps {
|
|
5
6
|
children: React.ReactNode;
|
|
6
7
|
config?: TailwindConfig;
|
|
7
8
|
}
|
|
8
9
|
declare const Tailwind: React.FC<TailwindProps>;
|
|
9
10
|
|
|
10
|
-
export { Tailwind, TailwindProps };
|
|
11
|
+
export { Tailwind, TailwindConfig, TailwindProps };
|
package/dist/index.js
CHANGED
|
@@ -54,7 +54,6 @@ module.exports = __toCommonJS(src_exports);
|
|
|
54
54
|
// src/tailwind.tsx
|
|
55
55
|
var React = __toESM(require("react"));
|
|
56
56
|
var import_server = require("react-dom/server");
|
|
57
|
-
var import_tw_to_css = require("tw-to-css");
|
|
58
57
|
|
|
59
58
|
// src/utils/css-to-jsx-style.ts
|
|
60
59
|
var camelCase = (string) => string.replace(/-(\w|$)/g, (_, p1) => p1.toUpperCase());
|
|
@@ -68,155 +67,189 @@ var convertPropertyName = (prop) => {
|
|
|
68
67
|
return modifiedProp;
|
|
69
68
|
}
|
|
70
69
|
if (modifiedProp.startsWith("-ms-")) {
|
|
71
|
-
modifiedProp = modifiedProp.
|
|
70
|
+
modifiedProp = modifiedProp.slice(1);
|
|
72
71
|
}
|
|
73
72
|
return camelCase(modifiedProp);
|
|
74
73
|
};
|
|
75
|
-
var
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (
|
|
82
|
-
|
|
83
|
-
capturing = cssText[i];
|
|
84
|
-
} else if (cssText[i] === capturing) {
|
|
85
|
-
capturing = false;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
if (!capturing && cssText[i] === ")") {
|
|
89
|
-
capturing = cssText[i];
|
|
90
|
-
}
|
|
91
|
-
if (cssText[i] === "(" && capturing === ")") {
|
|
92
|
-
capturing = false;
|
|
93
|
-
}
|
|
94
|
-
if (i < 0 || !capturing && cssText[i] === ";") {
|
|
95
|
-
declarations.unshift(cssText.slice(i + 1, last));
|
|
96
|
-
last = i;
|
|
74
|
+
var cssToJsxStyle = (cssText) => {
|
|
75
|
+
const style = {};
|
|
76
|
+
const declarations = cssText.matchAll(
|
|
77
|
+
/([a-zA-Z0-9\-_]+)\s*:\s*('[^']*'[^;]*|"[^"]*"[^;]*|.*?\([^)]*\)[^;]*|[^;]*);?/gm
|
|
78
|
+
);
|
|
79
|
+
for (const [_declaration, property, value] of declarations) {
|
|
80
|
+
if (property.length > 0 && value.trim().length > 0) {
|
|
81
|
+
style[convertPropertyName(property)] = value.trim();
|
|
97
82
|
}
|
|
98
83
|
}
|
|
99
|
-
return
|
|
84
|
+
return style;
|
|
100
85
|
};
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
86
|
+
|
|
87
|
+
// src/utils/get-css-for-markup.ts
|
|
88
|
+
var import_postcss = __toESM(require("postcss"));
|
|
89
|
+
var import_tailwindcss = __toESM(require("tailwindcss"));
|
|
90
|
+
var import_postcss_css_variables = __toESM(require("postcss-css-variables"));
|
|
91
|
+
global.__OXIDE__ = void 0;
|
|
92
|
+
var getCssForMarkup = (markup, config) => {
|
|
93
|
+
const corePlugins = config == null ? void 0 : config.corePlugins;
|
|
94
|
+
const tailwindConfig = __spreadProps(__spreadValues({}, config), {
|
|
95
|
+
corePlugins: __spreadValues({
|
|
96
|
+
preflight: false
|
|
97
|
+
}, corePlugins)
|
|
98
|
+
});
|
|
99
|
+
const processor = (0, import_postcss.default)([
|
|
100
|
+
(0, import_tailwindcss.default)(__spreadProps(__spreadValues({}, tailwindConfig), {
|
|
101
|
+
content: [{ raw: markup, extension: "html" }]
|
|
102
|
+
})),
|
|
103
|
+
(0, import_postcss_css_variables.default)()
|
|
104
|
+
]);
|
|
105
|
+
const result = processor.process(
|
|
106
|
+
String.raw`
|
|
107
|
+
@tailwind base;
|
|
108
|
+
@tailwind components;
|
|
109
|
+
@tailwind utilities;
|
|
110
|
+
`,
|
|
111
|
+
{ from: void 0 }
|
|
112
|
+
// no need to use from since the `content` context is sent into tailwind
|
|
113
|
+
);
|
|
114
|
+
return result.css;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// src/utils/minify-css.ts
|
|
118
|
+
var minifyCss = (css) => {
|
|
119
|
+
return css.replace(/\/\*[\s\S]*?\*\//gm, "").replace(/;\s+/gm, ";").replace(/:\s+/gm, ":").replace(/\)\s*{/gm, "){").replace(/\s+\(/gm, "(").replace(/{\s+/gm, "{").replace(/}\s+/gm, "}").replace(/\s*{/gm, "{").replace(/;?\s*}/gm, "}");
|
|
104
120
|
};
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
121
|
+
|
|
122
|
+
// src/utils/get-css-class-properties-map.ts
|
|
123
|
+
var getStylesPerClassMap = (css) => {
|
|
124
|
+
const map = {};
|
|
125
|
+
for (const [_match, className, contents] of css.matchAll(
|
|
126
|
+
/\s*\.([\S]+)\s*{([^}]*)}/gm
|
|
127
|
+
)) {
|
|
128
|
+
map[className.trim()] = contents.replace(/^\n+/, "").replace(/\n+$/, "").trim();
|
|
108
129
|
}
|
|
109
|
-
return
|
|
110
|
-
}
|
|
130
|
+
return map;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// src/utils/escape-class-name.ts
|
|
134
|
+
var escapeClassName = (className) => {
|
|
135
|
+
return className.replace(
|
|
136
|
+
/* we need this look ahead capturing group to avoid using negative look behinds */
|
|
137
|
+
/([^\\]|^)(?=([^a-zA-Z0-9\-_]))/g,
|
|
138
|
+
(match, prefixCharacter, characterToEscape) => {
|
|
139
|
+
if (prefixCharacter === "" && characterToEscape === "\\")
|
|
140
|
+
return match;
|
|
141
|
+
return `${prefixCharacter}\\`;
|
|
142
|
+
}
|
|
143
|
+
);
|
|
144
|
+
};
|
|
111
145
|
|
|
112
146
|
// src/tailwind.tsx
|
|
113
147
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
114
|
-
function processElement(element,
|
|
148
|
+
function processElement(element, nonMediaQueryTailwindStylesPerClass) {
|
|
115
149
|
let modifiedElement = element;
|
|
150
|
+
let resultingClassName = modifiedElement.props.className;
|
|
151
|
+
let resultingStyle = modifiedElement.props.style;
|
|
152
|
+
let resultingChildren = [];
|
|
116
153
|
if (modifiedElement.props.className) {
|
|
117
|
-
const
|
|
118
|
-
const
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
} else
|
|
126
|
-
|
|
127
|
-
|
|
154
|
+
const fullClassName = modifiedElement.props.className;
|
|
155
|
+
const classNames = fullClassName.split(" ");
|
|
156
|
+
const classNamesToKeep = [];
|
|
157
|
+
const styles = [];
|
|
158
|
+
classNames.forEach((className) => {
|
|
159
|
+
const escapedClassName = escapeClassName(className);
|
|
160
|
+
if (typeof nonMediaQueryTailwindStylesPerClass[escapedClassName] === "undefined") {
|
|
161
|
+
classNamesToKeep.push(className);
|
|
162
|
+
} else {
|
|
163
|
+
styles.push(
|
|
164
|
+
`${nonMediaQueryTailwindStylesPerClass[escapedClassName]};`
|
|
165
|
+
);
|
|
128
166
|
}
|
|
129
|
-
return true;
|
|
130
|
-
});
|
|
131
|
-
const convertedResponsiveStyles = twi(responsiveStyles, {
|
|
132
|
-
ignoreMediaQueries: false,
|
|
133
|
-
merge: false
|
|
134
167
|
});
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
);
|
|
138
|
-
modifiedElement = React.cloneElement(modifiedElement, __spreadProps(__spreadValues({}, modifiedElement.props), {
|
|
139
|
-
className: customClassNames.length ? customClassNames.join(" ") : void 0,
|
|
140
|
-
style: __spreadValues(__spreadValues({}, modifiedElement.props.style), cssToJsxStyle(convertedStyles.join(" ")))
|
|
141
|
-
}));
|
|
168
|
+
resultingStyle = __spreadValues(__spreadValues({}, modifiedElement.props.style), cssToJsxStyle(styles.join(" ")));
|
|
169
|
+
resultingClassName = classNamesToKeep.length > 0 ? classNamesToKeep.join(" ") : void 0;
|
|
142
170
|
}
|
|
143
171
|
if (modifiedElement.props.children) {
|
|
144
|
-
|
|
145
|
-
|
|
172
|
+
resultingChildren = React.Children.toArray(
|
|
173
|
+
modifiedElement.props.children
|
|
174
|
+
).map((child) => {
|
|
146
175
|
if (React.isValidElement(child)) {
|
|
147
|
-
return processElement(child,
|
|
176
|
+
return processElement(child, nonMediaQueryTailwindStylesPerClass);
|
|
148
177
|
}
|
|
149
178
|
return child;
|
|
150
179
|
});
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
180
|
+
}
|
|
181
|
+
modifiedElement = React.cloneElement(
|
|
182
|
+
modifiedElement,
|
|
183
|
+
__spreadValues(__spreadProps(__spreadValues({}, modifiedElement.props), {
|
|
184
|
+
className: resultingClassName
|
|
185
|
+
}), typeof resultingStyle === "undefined" ? {} : { style: resultingStyle }),
|
|
186
|
+
...resultingChildren
|
|
187
|
+
);
|
|
188
|
+
if (typeof modifiedElement.type === "function") {
|
|
189
|
+
const component = modifiedElement.type;
|
|
190
|
+
const renderedComponent = component(modifiedElement.props);
|
|
191
|
+
if (React.isValidElement(renderedComponent)) {
|
|
192
|
+
modifiedElement = processElement(
|
|
193
|
+
renderedComponent,
|
|
194
|
+
nonMediaQueryTailwindStylesPerClass
|
|
195
|
+
);
|
|
196
|
+
}
|
|
156
197
|
}
|
|
157
198
|
return modifiedElement;
|
|
158
199
|
}
|
|
159
|
-
function processHead(
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
modifiedChild.props,
|
|
168
|
-
...headChildren
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
if (modifiedChild.props.children) {
|
|
172
|
-
const children = React.Children.toArray(modifiedChild.props.children);
|
|
173
|
-
const processedChildren = children.map((processedChild) => {
|
|
174
|
-
if (React.isValidElement(processedChild)) {
|
|
175
|
-
return processHead(processedChild, responsiveStyles);
|
|
176
|
-
}
|
|
177
|
-
return processedChild;
|
|
178
|
-
});
|
|
179
|
-
modifiedChild = React.cloneElement(
|
|
180
|
-
modifiedChild,
|
|
181
|
-
modifiedChild.props,
|
|
182
|
-
...processedChildren
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
return modifiedChild;
|
|
200
|
+
function processHead(headElement, responsiveStyles) {
|
|
201
|
+
const styleElement = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: minifyCss(responsiveStyles.join("")) });
|
|
202
|
+
return React.cloneElement(
|
|
203
|
+
headElement,
|
|
204
|
+
headElement.props,
|
|
205
|
+
...React.Children.toArray(headElement.props.children),
|
|
206
|
+
styleElement
|
|
207
|
+
);
|
|
186
208
|
}
|
|
187
209
|
var Tailwind = ({ children, config }) => {
|
|
188
|
-
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
210
|
+
let headStyles = [];
|
|
211
|
+
const markupWithTailwindClasses = (0, import_server.renderToStaticMarkup)(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children }));
|
|
212
|
+
const markupCSS = getCssForMarkup(markupWithTailwindClasses, config);
|
|
213
|
+
const nonMediaQueryCSS = markupCSS.replaceAll(
|
|
214
|
+
/@media\s*\(.*\)\s*{\s*\.(.*)\s*{[\s\S]*}\s*}/gm,
|
|
215
|
+
(mediaQuery, _className) => {
|
|
216
|
+
headStyles.push(
|
|
217
|
+
mediaQuery.replace(/[\r\n|\r|\n]+/g, "").replace(/\s+/g, " ").replaceAll(/\s*\.[\S]+\s*{([^}]*)}/gm, (match, content) => {
|
|
218
|
+
return match.replace(
|
|
219
|
+
content,
|
|
220
|
+
content.split(";").map(
|
|
221
|
+
(propertyDeclaration) => propertyDeclaration.endsWith("!important") ? propertyDeclaration.trim() : `${propertyDeclaration.trim()}!important`
|
|
222
|
+
).join(";")
|
|
223
|
+
);
|
|
224
|
+
})
|
|
225
|
+
);
|
|
226
|
+
return "";
|
|
195
227
|
}
|
|
196
|
-
return child;
|
|
197
|
-
});
|
|
198
|
-
if (!childrenWithInlineStyles)
|
|
199
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
|
|
200
|
-
const fullHTML = (0, import_server.renderToStaticMarkup)(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: childrenWithInlineStyles }));
|
|
201
|
-
const hasResponsiveStyles = new RegExp("@media[^{]+\\{(?<content>[\\s\\S]+?)\\}\\s*\\}", "gm").test(
|
|
202
|
-
headStyles.join(" ")
|
|
203
228
|
);
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
229
|
+
const nonMediaQueryTailwindStylesPerClass = getStylesPerClassMap(nonMediaQueryCSS);
|
|
230
|
+
const childrenArray = React.Children.toArray(children);
|
|
231
|
+
const validElementsWithIndexes = childrenArray.map((child, i) => [child, i]).filter(([child]) => React.isValidElement(child));
|
|
232
|
+
let headElementIndex = -1;
|
|
233
|
+
validElementsWithIndexes.forEach(([element, i]) => {
|
|
234
|
+
childrenArray[i] = processElement(
|
|
235
|
+
element,
|
|
236
|
+
nonMediaQueryTailwindStylesPerClass
|
|
208
237
|
);
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
childrenWithInlineStyles,
|
|
212
|
-
(child) => {
|
|
213
|
-
if (React.isValidElement(child)) {
|
|
214
|
-
return processHead(child, headStyles);
|
|
215
|
-
}
|
|
216
|
-
return child;
|
|
238
|
+
if (element.type === "head" || typeof element.type === "function" && "name" in element.type && element.type.name === "Head") {
|
|
239
|
+
headElementIndex = i;
|
|
217
240
|
}
|
|
218
|
-
);
|
|
219
|
-
|
|
241
|
+
});
|
|
242
|
+
headStyles = headStyles.filter((style) => style.trim().length > 0);
|
|
243
|
+
if (headStyles.length > 0) {
|
|
244
|
+
if (headElementIndex === -1) {
|
|
245
|
+
throw new Error(
|
|
246
|
+
"Tailwind: To use responsive styles you must have a <head> element as a direct child of the Tailwind component."
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
const [headElement, headAllElementsIndex] = validElementsWithIndexes[headElementIndex];
|
|
250
|
+
childrenArray[headAllElementsIndex] = processHead(headElement, headStyles);
|
|
251
|
+
}
|
|
252
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: childrenArray });
|
|
220
253
|
};
|
|
221
254
|
// Annotate the CommonJS export names for ESM import in node:
|
|
222
255
|
0 && (module.exports = {
|
package/dist/index.mjs
CHANGED
|
@@ -21,7 +21,6 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
|
21
21
|
// src/tailwind.tsx
|
|
22
22
|
import * as React from "react";
|
|
23
23
|
import { renderToStaticMarkup } from "react-dom/server";
|
|
24
|
-
import { tailwindToCSS } from "tw-to-css";
|
|
25
24
|
|
|
26
25
|
// src/utils/css-to-jsx-style.ts
|
|
27
26
|
var camelCase = (string) => string.replace(/-(\w|$)/g, (_, p1) => p1.toUpperCase());
|
|
@@ -35,155 +34,189 @@ var convertPropertyName = (prop) => {
|
|
|
35
34
|
return modifiedProp;
|
|
36
35
|
}
|
|
37
36
|
if (modifiedProp.startsWith("-ms-")) {
|
|
38
|
-
modifiedProp = modifiedProp.
|
|
37
|
+
modifiedProp = modifiedProp.slice(1);
|
|
39
38
|
}
|
|
40
39
|
return camelCase(modifiedProp);
|
|
41
40
|
};
|
|
42
|
-
var
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
capturing = cssText[i];
|
|
51
|
-
} else if (cssText[i] === capturing) {
|
|
52
|
-
capturing = false;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
if (!capturing && cssText[i] === ")") {
|
|
56
|
-
capturing = cssText[i];
|
|
57
|
-
}
|
|
58
|
-
if (cssText[i] === "(" && capturing === ")") {
|
|
59
|
-
capturing = false;
|
|
60
|
-
}
|
|
61
|
-
if (i < 0 || !capturing && cssText[i] === ";") {
|
|
62
|
-
declarations.unshift(cssText.slice(i + 1, last));
|
|
63
|
-
last = i;
|
|
41
|
+
var cssToJsxStyle = (cssText) => {
|
|
42
|
+
const style = {};
|
|
43
|
+
const declarations = cssText.matchAll(
|
|
44
|
+
/([a-zA-Z0-9\-_]+)\s*:\s*('[^']*'[^;]*|"[^"]*"[^;]*|.*?\([^)]*\)[^;]*|[^;]*);?/gm
|
|
45
|
+
);
|
|
46
|
+
for (const [_declaration, property, value] of declarations) {
|
|
47
|
+
if (property.length > 0 && value.trim().length > 0) {
|
|
48
|
+
style[convertPropertyName(property)] = value.trim();
|
|
64
49
|
}
|
|
65
50
|
}
|
|
66
|
-
return
|
|
51
|
+
return style;
|
|
67
52
|
};
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
53
|
+
|
|
54
|
+
// src/utils/get-css-for-markup.ts
|
|
55
|
+
import postcss from "postcss";
|
|
56
|
+
import tailwindcss from "tailwindcss";
|
|
57
|
+
import postcssCssVariables from "postcss-css-variables";
|
|
58
|
+
global.__OXIDE__ = void 0;
|
|
59
|
+
var getCssForMarkup = (markup, config) => {
|
|
60
|
+
const corePlugins = config == null ? void 0 : config.corePlugins;
|
|
61
|
+
const tailwindConfig = __spreadProps(__spreadValues({}, config), {
|
|
62
|
+
corePlugins: __spreadValues({
|
|
63
|
+
preflight: false
|
|
64
|
+
}, corePlugins)
|
|
65
|
+
});
|
|
66
|
+
const processor = postcss([
|
|
67
|
+
tailwindcss(__spreadProps(__spreadValues({}, tailwindConfig), {
|
|
68
|
+
content: [{ raw: markup, extension: "html" }]
|
|
69
|
+
})),
|
|
70
|
+
postcssCssVariables()
|
|
71
|
+
]);
|
|
72
|
+
const result = processor.process(
|
|
73
|
+
String.raw`
|
|
74
|
+
@tailwind base;
|
|
75
|
+
@tailwind components;
|
|
76
|
+
@tailwind utilities;
|
|
77
|
+
`,
|
|
78
|
+
{ from: void 0 }
|
|
79
|
+
// no need to use from since the `content` context is sent into tailwind
|
|
80
|
+
);
|
|
81
|
+
return result.css;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// src/utils/minify-css.ts
|
|
85
|
+
var minifyCss = (css) => {
|
|
86
|
+
return css.replace(/\/\*[\s\S]*?\*\//gm, "").replace(/;\s+/gm, ";").replace(/:\s+/gm, ":").replace(/\)\s*{/gm, "){").replace(/\s+\(/gm, "(").replace(/{\s+/gm, "{").replace(/}\s+/gm, "}").replace(/\s*{/gm, "{").replace(/;?\s*}/gm, "}");
|
|
71
87
|
};
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
88
|
+
|
|
89
|
+
// src/utils/get-css-class-properties-map.ts
|
|
90
|
+
var getStylesPerClassMap = (css) => {
|
|
91
|
+
const map = {};
|
|
92
|
+
for (const [_match, className, contents] of css.matchAll(
|
|
93
|
+
/\s*\.([\S]+)\s*{([^}]*)}/gm
|
|
94
|
+
)) {
|
|
95
|
+
map[className.trim()] = contents.replace(/^\n+/, "").replace(/\n+$/, "").trim();
|
|
75
96
|
}
|
|
76
|
-
return
|
|
77
|
-
}
|
|
97
|
+
return map;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// src/utils/escape-class-name.ts
|
|
101
|
+
var escapeClassName = (className) => {
|
|
102
|
+
return className.replace(
|
|
103
|
+
/* we need this look ahead capturing group to avoid using negative look behinds */
|
|
104
|
+
/([^\\]|^)(?=([^a-zA-Z0-9\-_]))/g,
|
|
105
|
+
(match, prefixCharacter, characterToEscape) => {
|
|
106
|
+
if (prefixCharacter === "" && characterToEscape === "\\")
|
|
107
|
+
return match;
|
|
108
|
+
return `${prefixCharacter}\\`;
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
};
|
|
78
112
|
|
|
79
113
|
// src/tailwind.tsx
|
|
80
114
|
import { Fragment, jsx } from "react/jsx-runtime";
|
|
81
|
-
function processElement(element,
|
|
115
|
+
function processElement(element, nonMediaQueryTailwindStylesPerClass) {
|
|
82
116
|
let modifiedElement = element;
|
|
117
|
+
let resultingClassName = modifiedElement.props.className;
|
|
118
|
+
let resultingStyle = modifiedElement.props.style;
|
|
119
|
+
let resultingChildren = [];
|
|
83
120
|
if (modifiedElement.props.className) {
|
|
84
|
-
const
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
} else
|
|
93
|
-
|
|
94
|
-
|
|
121
|
+
const fullClassName = modifiedElement.props.className;
|
|
122
|
+
const classNames = fullClassName.split(" ");
|
|
123
|
+
const classNamesToKeep = [];
|
|
124
|
+
const styles = [];
|
|
125
|
+
classNames.forEach((className) => {
|
|
126
|
+
const escapedClassName = escapeClassName(className);
|
|
127
|
+
if (typeof nonMediaQueryTailwindStylesPerClass[escapedClassName] === "undefined") {
|
|
128
|
+
classNamesToKeep.push(className);
|
|
129
|
+
} else {
|
|
130
|
+
styles.push(
|
|
131
|
+
`${nonMediaQueryTailwindStylesPerClass[escapedClassName]};`
|
|
132
|
+
);
|
|
95
133
|
}
|
|
96
|
-
return true;
|
|
97
|
-
});
|
|
98
|
-
const convertedResponsiveStyles = twi(responsiveStyles, {
|
|
99
|
-
ignoreMediaQueries: false,
|
|
100
|
-
merge: false
|
|
101
134
|
});
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
);
|
|
105
|
-
modifiedElement = React.cloneElement(modifiedElement, __spreadProps(__spreadValues({}, modifiedElement.props), {
|
|
106
|
-
className: customClassNames.length ? customClassNames.join(" ") : void 0,
|
|
107
|
-
style: __spreadValues(__spreadValues({}, modifiedElement.props.style), cssToJsxStyle(convertedStyles.join(" ")))
|
|
108
|
-
}));
|
|
135
|
+
resultingStyle = __spreadValues(__spreadValues({}, modifiedElement.props.style), cssToJsxStyle(styles.join(" ")));
|
|
136
|
+
resultingClassName = classNamesToKeep.length > 0 ? classNamesToKeep.join(" ") : void 0;
|
|
109
137
|
}
|
|
110
138
|
if (modifiedElement.props.children) {
|
|
111
|
-
|
|
112
|
-
|
|
139
|
+
resultingChildren = React.Children.toArray(
|
|
140
|
+
modifiedElement.props.children
|
|
141
|
+
).map((child) => {
|
|
113
142
|
if (React.isValidElement(child)) {
|
|
114
|
-
return processElement(child,
|
|
143
|
+
return processElement(child, nonMediaQueryTailwindStylesPerClass);
|
|
115
144
|
}
|
|
116
145
|
return child;
|
|
117
146
|
});
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
147
|
+
}
|
|
148
|
+
modifiedElement = React.cloneElement(
|
|
149
|
+
modifiedElement,
|
|
150
|
+
__spreadValues(__spreadProps(__spreadValues({}, modifiedElement.props), {
|
|
151
|
+
className: resultingClassName
|
|
152
|
+
}), typeof resultingStyle === "undefined" ? {} : { style: resultingStyle }),
|
|
153
|
+
...resultingChildren
|
|
154
|
+
);
|
|
155
|
+
if (typeof modifiedElement.type === "function") {
|
|
156
|
+
const component = modifiedElement.type;
|
|
157
|
+
const renderedComponent = component(modifiedElement.props);
|
|
158
|
+
if (React.isValidElement(renderedComponent)) {
|
|
159
|
+
modifiedElement = processElement(
|
|
160
|
+
renderedComponent,
|
|
161
|
+
nonMediaQueryTailwindStylesPerClass
|
|
162
|
+
);
|
|
163
|
+
}
|
|
123
164
|
}
|
|
124
165
|
return modifiedElement;
|
|
125
166
|
}
|
|
126
|
-
function processHead(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
modifiedChild.props,
|
|
135
|
-
...headChildren
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
if (modifiedChild.props.children) {
|
|
139
|
-
const children = React.Children.toArray(modifiedChild.props.children);
|
|
140
|
-
const processedChildren = children.map((processedChild) => {
|
|
141
|
-
if (React.isValidElement(processedChild)) {
|
|
142
|
-
return processHead(processedChild, responsiveStyles);
|
|
143
|
-
}
|
|
144
|
-
return processedChild;
|
|
145
|
-
});
|
|
146
|
-
modifiedChild = React.cloneElement(
|
|
147
|
-
modifiedChild,
|
|
148
|
-
modifiedChild.props,
|
|
149
|
-
...processedChildren
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
return modifiedChild;
|
|
167
|
+
function processHead(headElement, responsiveStyles) {
|
|
168
|
+
const styleElement = /* @__PURE__ */ jsx("style", { children: minifyCss(responsiveStyles.join("")) });
|
|
169
|
+
return React.cloneElement(
|
|
170
|
+
headElement,
|
|
171
|
+
headElement.props,
|
|
172
|
+
...React.Children.toArray(headElement.props.children),
|
|
173
|
+
styleElement
|
|
174
|
+
);
|
|
153
175
|
}
|
|
154
176
|
var Tailwind = ({ children, config }) => {
|
|
155
|
-
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
177
|
+
let headStyles = [];
|
|
178
|
+
const markupWithTailwindClasses = renderToStaticMarkup(/* @__PURE__ */ jsx(Fragment, { children }));
|
|
179
|
+
const markupCSS = getCssForMarkup(markupWithTailwindClasses, config);
|
|
180
|
+
const nonMediaQueryCSS = markupCSS.replaceAll(
|
|
181
|
+
/@media\s*\(.*\)\s*{\s*\.(.*)\s*{[\s\S]*}\s*}/gm,
|
|
182
|
+
(mediaQuery, _className) => {
|
|
183
|
+
headStyles.push(
|
|
184
|
+
mediaQuery.replace(/[\r\n|\r|\n]+/g, "").replace(/\s+/g, " ").replaceAll(/\s*\.[\S]+\s*{([^}]*)}/gm, (match, content) => {
|
|
185
|
+
return match.replace(
|
|
186
|
+
content,
|
|
187
|
+
content.split(";").map(
|
|
188
|
+
(propertyDeclaration) => propertyDeclaration.endsWith("!important") ? propertyDeclaration.trim() : `${propertyDeclaration.trim()}!important`
|
|
189
|
+
).join(";")
|
|
190
|
+
);
|
|
191
|
+
})
|
|
192
|
+
);
|
|
193
|
+
return "";
|
|
162
194
|
}
|
|
163
|
-
return child;
|
|
164
|
-
});
|
|
165
|
-
if (!childrenWithInlineStyles)
|
|
166
|
-
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
167
|
-
const fullHTML = renderToStaticMarkup(/* @__PURE__ */ jsx(Fragment, { children: childrenWithInlineStyles }));
|
|
168
|
-
const hasResponsiveStyles = new RegExp("@media[^{]+\\{(?<content>[\\s\\S]+?)\\}\\s*\\}", "gm").test(
|
|
169
|
-
headStyles.join(" ")
|
|
170
195
|
);
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
196
|
+
const nonMediaQueryTailwindStylesPerClass = getStylesPerClassMap(nonMediaQueryCSS);
|
|
197
|
+
const childrenArray = React.Children.toArray(children);
|
|
198
|
+
const validElementsWithIndexes = childrenArray.map((child, i) => [child, i]).filter(([child]) => React.isValidElement(child));
|
|
199
|
+
let headElementIndex = -1;
|
|
200
|
+
validElementsWithIndexes.forEach(([element, i]) => {
|
|
201
|
+
childrenArray[i] = processElement(
|
|
202
|
+
element,
|
|
203
|
+
nonMediaQueryTailwindStylesPerClass
|
|
175
204
|
);
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
childrenWithInlineStyles,
|
|
179
|
-
(child) => {
|
|
180
|
-
if (React.isValidElement(child)) {
|
|
181
|
-
return processHead(child, headStyles);
|
|
182
|
-
}
|
|
183
|
-
return child;
|
|
205
|
+
if (element.type === "head" || typeof element.type === "function" && "name" in element.type && element.type.name === "Head") {
|
|
206
|
+
headElementIndex = i;
|
|
184
207
|
}
|
|
185
|
-
);
|
|
186
|
-
|
|
208
|
+
});
|
|
209
|
+
headStyles = headStyles.filter((style) => style.trim().length > 0);
|
|
210
|
+
if (headStyles.length > 0) {
|
|
211
|
+
if (headElementIndex === -1) {
|
|
212
|
+
throw new Error(
|
|
213
|
+
"Tailwind: To use responsive styles you must have a <head> element as a direct child of the Tailwind component."
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
const [headElement, headAllElementsIndex] = validElementsWithIndexes[headElementIndex];
|
|
217
|
+
childrenArray[headAllElementsIndex] = processHead(headElement, headStyles);
|
|
218
|
+
}
|
|
219
|
+
return /* @__PURE__ */ jsx(Fragment, { children: childrenArray });
|
|
187
220
|
};
|
|
188
221
|
export {
|
|
189
222
|
Tailwind
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-email/tailwind",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13-canary.1",
|
|
4
4
|
"description": "A React component to wrap emails with Tailwind CSS",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -44,9 +44,11 @@
|
|
|
44
44
|
"node": ">=18.0.0"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
+
"postcss": "8.4.31",
|
|
48
|
+
"postcss-css-variables": "0.19.0",
|
|
47
49
|
"react": "18.2.0",
|
|
48
50
|
"react-dom": "18.2.0",
|
|
49
|
-
"
|
|
51
|
+
"tailwindcss": "3.3.2"
|
|
50
52
|
},
|
|
51
53
|
"peerDependencies": {
|
|
52
54
|
"react": "18.2.0"
|
|
@@ -54,11 +56,13 @@
|
|
|
54
56
|
"devDependencies": {
|
|
55
57
|
"@babel/core": "7.21.8",
|
|
56
58
|
"@babel/preset-react": "7.22.5",
|
|
57
|
-
"@react-email/hr": "workspace:*",
|
|
58
59
|
"@react-email/head": "workspace:*",
|
|
60
|
+
"@react-email/hr": "workspace:*",
|
|
59
61
|
"@react-email/html": "workspace:*",
|
|
60
62
|
"@testing-library/react": "14.0.0",
|
|
63
|
+
"@types/postcss-css-variables": "0.18.2",
|
|
61
64
|
"eslint-config-custom": "workspace:*",
|
|
65
|
+
"eslint-plugin-regex": "1.10.0",
|
|
62
66
|
"tsconfig": "workspace:*",
|
|
63
67
|
"typescript": "5.1.6"
|
|
64
68
|
},
|