@react-email/tailwind 0.0.9 → 0.0.11
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.js +149 -96
- package/dist/index.mjs +150 -101
- package/package.json +15 -21
package/dist/index.js
CHANGED
|
@@ -54,117 +54,170 @@ 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_html_react_parser = __toESM(require("html-react-parser"));
|
|
58
57
|
var import_tw_to_css = require("tw-to-css");
|
|
58
|
+
|
|
59
|
+
// src/utils/css-to-jsx-style.ts
|
|
60
|
+
var camelCase = (string) => string.replace(/-(\w|$)/g, (_, p1) => p1.toUpperCase());
|
|
61
|
+
var convertPropertyName = (prop) => {
|
|
62
|
+
let modifiedProp = prop;
|
|
63
|
+
modifiedProp = modifiedProp.toLowerCase();
|
|
64
|
+
if (modifiedProp === "float") {
|
|
65
|
+
return "cssFloat";
|
|
66
|
+
}
|
|
67
|
+
if (modifiedProp.startsWith("--")) {
|
|
68
|
+
return modifiedProp;
|
|
69
|
+
}
|
|
70
|
+
if (modifiedProp.startsWith("-ms-")) {
|
|
71
|
+
modifiedProp = modifiedProp.substr(1);
|
|
72
|
+
}
|
|
73
|
+
return camelCase(modifiedProp);
|
|
74
|
+
};
|
|
75
|
+
var splitDeclarations = (cssText) => {
|
|
76
|
+
const declarations = [];
|
|
77
|
+
let capturing;
|
|
78
|
+
let i = cssText.length;
|
|
79
|
+
let last = i;
|
|
80
|
+
while (i-- > -1) {
|
|
81
|
+
if ((cssText[i] === '"' || cssText[i] === "'") && cssText[i - 1] !== "\\") {
|
|
82
|
+
if (!capturing) {
|
|
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;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return declarations;
|
|
100
|
+
};
|
|
101
|
+
var splitDeclaration = (declaration) => {
|
|
102
|
+
const i = declaration.indexOf(":");
|
|
103
|
+
return [declaration.substr(0, i).trim(), declaration.substr(i + 1).trim()];
|
|
104
|
+
};
|
|
105
|
+
var cssToJsxStyle = (cssText) => splitDeclarations(cssText).map(splitDeclaration).reduce((styles, [name, value]) => {
|
|
106
|
+
if (name && value) {
|
|
107
|
+
styles[convertPropertyName(name)] = value;
|
|
108
|
+
}
|
|
109
|
+
return styles;
|
|
110
|
+
}, {});
|
|
111
|
+
|
|
112
|
+
// src/tailwind.tsx
|
|
59
113
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
114
|
+
function processElement(element, headStyles, twi) {
|
|
115
|
+
let modifiedElement = element;
|
|
116
|
+
if (modifiedElement.props.className) {
|
|
117
|
+
const convertedStyles = [];
|
|
118
|
+
const responsiveStyles = [];
|
|
119
|
+
const classNames = modifiedElement.props.className.split(" ");
|
|
120
|
+
const customClassNames = classNames.filter((className) => {
|
|
121
|
+
const tailwindClassName = twi(className, { ignoreMediaQueries: true });
|
|
122
|
+
if (tailwindClassName) {
|
|
123
|
+
convertedStyles.push(tailwindClassName);
|
|
124
|
+
return false;
|
|
125
|
+
} else if (twi(className, { ignoreMediaQueries: false })) {
|
|
126
|
+
responsiveStyles.push(className);
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
return true;
|
|
130
|
+
});
|
|
131
|
+
const convertedResponsiveStyles = twi(responsiveStyles, {
|
|
132
|
+
ignoreMediaQueries: false,
|
|
133
|
+
merge: false
|
|
134
|
+
});
|
|
135
|
+
headStyles.push(
|
|
136
|
+
convertedResponsiveStyles.replace(/^\n+/, "").replace(/\n+$/, "")
|
|
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
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
if (modifiedElement.props.children) {
|
|
144
|
+
const children = React.Children.toArray(modifiedElement.props.children);
|
|
145
|
+
const processedChildren = children.map((child) => {
|
|
146
|
+
if (React.isValidElement(child)) {
|
|
147
|
+
return processElement(child, headStyles, twi);
|
|
148
|
+
}
|
|
149
|
+
return child;
|
|
150
|
+
});
|
|
151
|
+
modifiedElement = React.cloneElement(
|
|
152
|
+
modifiedElement,
|
|
153
|
+
modifiedElement.props,
|
|
154
|
+
...processedChildren
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
return modifiedElement;
|
|
158
|
+
}
|
|
159
|
+
function processHead(child, responsiveStyles) {
|
|
160
|
+
let modifiedChild = child;
|
|
161
|
+
if (modifiedChild.type === "head" || modifiedChild.type.displayName === "Head") {
|
|
162
|
+
const styleElement = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: responsiveStyles });
|
|
163
|
+
const headChildren = React.Children.toArray(modifiedChild.props.children);
|
|
164
|
+
headChildren.push(styleElement);
|
|
165
|
+
modifiedChild = React.cloneElement(
|
|
166
|
+
modifiedChild,
|
|
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;
|
|
186
|
+
}
|
|
60
187
|
var Tailwind = ({ children, config }) => {
|
|
188
|
+
const headStyles = [];
|
|
61
189
|
const { twi } = (0, import_tw_to_css.tailwindToCSS)({
|
|
62
190
|
config
|
|
63
191
|
});
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
192
|
+
const childrenWithInlineStyles = React.Children.map(children, (child) => {
|
|
193
|
+
if (React.isValidElement(child)) {
|
|
194
|
+
return processElement(child, headStyles, twi);
|
|
195
|
+
}
|
|
196
|
+
return child;
|
|
69
197
|
});
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const
|
|
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 }));
|
|
73
201
|
const hasResponsiveStyles = new RegExp("@media[^{]+\\{(?<content>[\\s\\S]+?)\\}\\s*\\}", "gm").test(
|
|
74
|
-
|
|
202
|
+
headStyles.join(" ")
|
|
75
203
|
);
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
if (hasResponsiveStyles && (!hasHTML || !hasHead)) {
|
|
204
|
+
const hasHTMLAndHead = /<html[^>]*>(?=[\s\S]*<head[^>]*>)/gm.test(fullHTML);
|
|
205
|
+
if (hasResponsiveStyles && !hasHTMLAndHead) {
|
|
79
206
|
throw new Error(
|
|
80
207
|
"Tailwind: To use responsive styles you must have a <html> and <head> element in your template."
|
|
81
208
|
);
|
|
82
209
|
}
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
replace: (domNode) => {
|
|
89
|
-
var _a;
|
|
90
|
-
if (domNode instanceof import_html_react_parser.Element) {
|
|
91
|
-
if (hasResponsiveStyles && hasHead && domNode.name === "head") {
|
|
92
|
-
let newDomNode = null;
|
|
93
|
-
if (domNode.children) {
|
|
94
|
-
const props = (0, import_html_react_parser.attributesToProps)(domNode.attribs);
|
|
95
|
-
newDomNode = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("head", __spreadProps(__spreadValues({}, props), { children: [
|
|
96
|
-
(0, import_html_react_parser.domToReact)(domNode.children),
|
|
97
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: headStyle })
|
|
98
|
-
] }));
|
|
99
|
-
}
|
|
100
|
-
return newDomNode;
|
|
101
|
-
}
|
|
102
|
-
if ((_a = domNode.attribs) == null ? void 0 : _a.class) {
|
|
103
|
-
const cleanRegex = /[:#\!\-[\]\/\.%]+/g;
|
|
104
|
-
const cleanTailwindClasses = domNode.attribs.class.replace(cleanRegex, "_");
|
|
105
|
-
const currentStyles = domNode.attribs.style ? `${domNode.attribs.style};` : "";
|
|
106
|
-
const tailwindStyles = cleanTailwindClasses.split(" ").map((className) => {
|
|
107
|
-
return cssMap[`.${className}`];
|
|
108
|
-
}).join(";");
|
|
109
|
-
domNode.attribs.style = `${currentStyles} ${tailwindStyles}`;
|
|
110
|
-
domNode.attribs.class = domNode.attribs.class.split(" ").filter((className) => {
|
|
111
|
-
const cleanedClassName = className.replace(cleanRegex, "_");
|
|
112
|
-
return className.search(/^.{2}:/) !== -1 || !cssMap[`.${cleanedClassName}`];
|
|
113
|
-
}).join(" ").replace(cleanRegex, "_");
|
|
114
|
-
if (domNode.attribs.class === "")
|
|
115
|
-
delete domNode.attribs.class;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
210
|
+
const childrenWithInlineAndResponsiveStyles = React.Children.map(
|
|
211
|
+
childrenWithInlineStyles,
|
|
212
|
+
(child) => {
|
|
213
|
+
if (React.isValidElement(child)) {
|
|
214
|
+
return processHead(child, headStyles);
|
|
118
215
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
});
|
|
122
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: reactHTML });
|
|
123
|
-
};
|
|
124
|
-
Tailwind.displayName = "Tailwind";
|
|
125
|
-
function cleanCss(css) {
|
|
126
|
-
let newCss = css.replace(/\\/g, "").replace(/[.\!\#\w\d\\:\-\[\]\/\.%\(\))]+(?=\s*?{[^{]*?\})\s*?{/g, (m) => {
|
|
127
|
-
return m.replace(new RegExp("(?<=.)[:#\\!\\-[\\\\\\]\\/\\.%]+", "g"), "_");
|
|
128
|
-
}).replace(new RegExp("font-family(?<value>[^;\\r\\n]+)", "g"), (m, value) => {
|
|
129
|
-
return `font-family${value.replace(/['"]+/g, "")}`;
|
|
130
|
-
});
|
|
131
|
-
return newCss;
|
|
132
|
-
}
|
|
133
|
-
function getMediaQueryCss(css) {
|
|
134
|
-
var _a, _b;
|
|
135
|
-
const mediaQueryRegex = new RegExp("@media[^{]+\\{(?<content>[\\s\\S]+?)\\}\\s*\\}", "gm");
|
|
136
|
-
return (_b = (_a = css.replace(mediaQueryRegex, (m) => {
|
|
137
|
-
return m.replace(
|
|
138
|
-
/([^{]+\{)([\s\S]+?)(\}\s*\})/gm,
|
|
139
|
-
(_, start, content, end) => {
|
|
140
|
-
const newContent = content.replace(
|
|
141
|
-
new RegExp("(?:[\\s\\r\\n]*)?(?<prop>[\\w-]+)\\s*:\\s*(?<value>[^};\\r\\n]+)", "gm"),
|
|
142
|
-
(_2, prop, value) => {
|
|
143
|
-
return `${prop}: ${value} !important;`;
|
|
144
|
-
}
|
|
145
|
-
);
|
|
146
|
-
return `${start}${newContent}${end}`;
|
|
147
|
-
}
|
|
148
|
-
);
|
|
149
|
-
}).match(/@media\s*([^{]+)\{([^{}]*\{[^{}]*\})*[^{}]*\}/g)) == null ? void 0 : _a.join("")) != null ? _b : "";
|
|
150
|
-
}
|
|
151
|
-
function makeCssMap(css) {
|
|
152
|
-
const cssNoMedia = css.replace(
|
|
153
|
-
new RegExp("@media[^{]+\\{(?<content>[\\s\\S]+?)\\}\\s*\\}", "gm"),
|
|
154
|
-
""
|
|
155
|
-
);
|
|
156
|
-
const cssMap = cssNoMedia.split("}").reduce(
|
|
157
|
-
(acc, cur) => {
|
|
158
|
-
const [key, value] = cur.split("{");
|
|
159
|
-
if (key && value) {
|
|
160
|
-
acc[key] = value;
|
|
161
|
-
}
|
|
162
|
-
return acc;
|
|
163
|
-
},
|
|
164
|
-
{}
|
|
216
|
+
return child;
|
|
217
|
+
}
|
|
165
218
|
);
|
|
166
|
-
return
|
|
167
|
-
}
|
|
219
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: childrenWithInlineAndResponsiveStyles });
|
|
220
|
+
};
|
|
168
221
|
// Annotate the CommonJS export names for ESM import in node:
|
|
169
222
|
0 && (module.exports = {
|
|
170
223
|
Tailwind
|
package/dist/index.mjs
CHANGED
|
@@ -21,121 +21,170 @@ 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 htmlParser, {
|
|
25
|
-
attributesToProps,
|
|
26
|
-
domToReact,
|
|
27
|
-
Element
|
|
28
|
-
} from "html-react-parser";
|
|
29
24
|
import { tailwindToCSS } from "tw-to-css";
|
|
30
|
-
|
|
25
|
+
|
|
26
|
+
// src/utils/css-to-jsx-style.ts
|
|
27
|
+
var camelCase = (string) => string.replace(/-(\w|$)/g, (_, p1) => p1.toUpperCase());
|
|
28
|
+
var convertPropertyName = (prop) => {
|
|
29
|
+
let modifiedProp = prop;
|
|
30
|
+
modifiedProp = modifiedProp.toLowerCase();
|
|
31
|
+
if (modifiedProp === "float") {
|
|
32
|
+
return "cssFloat";
|
|
33
|
+
}
|
|
34
|
+
if (modifiedProp.startsWith("--")) {
|
|
35
|
+
return modifiedProp;
|
|
36
|
+
}
|
|
37
|
+
if (modifiedProp.startsWith("-ms-")) {
|
|
38
|
+
modifiedProp = modifiedProp.substr(1);
|
|
39
|
+
}
|
|
40
|
+
return camelCase(modifiedProp);
|
|
41
|
+
};
|
|
42
|
+
var splitDeclarations = (cssText) => {
|
|
43
|
+
const declarations = [];
|
|
44
|
+
let capturing;
|
|
45
|
+
let i = cssText.length;
|
|
46
|
+
let last = i;
|
|
47
|
+
while (i-- > -1) {
|
|
48
|
+
if ((cssText[i] === '"' || cssText[i] === "'") && cssText[i - 1] !== "\\") {
|
|
49
|
+
if (!capturing) {
|
|
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;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return declarations;
|
|
67
|
+
};
|
|
68
|
+
var splitDeclaration = (declaration) => {
|
|
69
|
+
const i = declaration.indexOf(":");
|
|
70
|
+
return [declaration.substr(0, i).trim(), declaration.substr(i + 1).trim()];
|
|
71
|
+
};
|
|
72
|
+
var cssToJsxStyle = (cssText) => splitDeclarations(cssText).map(splitDeclaration).reduce((styles, [name, value]) => {
|
|
73
|
+
if (name && value) {
|
|
74
|
+
styles[convertPropertyName(name)] = value;
|
|
75
|
+
}
|
|
76
|
+
return styles;
|
|
77
|
+
}, {});
|
|
78
|
+
|
|
79
|
+
// src/tailwind.tsx
|
|
80
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
81
|
+
function processElement(element, headStyles, twi) {
|
|
82
|
+
let modifiedElement = element;
|
|
83
|
+
if (modifiedElement.props.className) {
|
|
84
|
+
const convertedStyles = [];
|
|
85
|
+
const responsiveStyles = [];
|
|
86
|
+
const classNames = modifiedElement.props.className.split(" ");
|
|
87
|
+
const customClassNames = classNames.filter((className) => {
|
|
88
|
+
const tailwindClassName = twi(className, { ignoreMediaQueries: true });
|
|
89
|
+
if (tailwindClassName) {
|
|
90
|
+
convertedStyles.push(tailwindClassName);
|
|
91
|
+
return false;
|
|
92
|
+
} else if (twi(className, { ignoreMediaQueries: false })) {
|
|
93
|
+
responsiveStyles.push(className);
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
return true;
|
|
97
|
+
});
|
|
98
|
+
const convertedResponsiveStyles = twi(responsiveStyles, {
|
|
99
|
+
ignoreMediaQueries: false,
|
|
100
|
+
merge: false
|
|
101
|
+
});
|
|
102
|
+
headStyles.push(
|
|
103
|
+
convertedResponsiveStyles.replace(/^\n+/, "").replace(/\n+$/, "")
|
|
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
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
if (modifiedElement.props.children) {
|
|
111
|
+
const children = React.Children.toArray(modifiedElement.props.children);
|
|
112
|
+
const processedChildren = children.map((child) => {
|
|
113
|
+
if (React.isValidElement(child)) {
|
|
114
|
+
return processElement(child, headStyles, twi);
|
|
115
|
+
}
|
|
116
|
+
return child;
|
|
117
|
+
});
|
|
118
|
+
modifiedElement = React.cloneElement(
|
|
119
|
+
modifiedElement,
|
|
120
|
+
modifiedElement.props,
|
|
121
|
+
...processedChildren
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
return modifiedElement;
|
|
125
|
+
}
|
|
126
|
+
function processHead(child, responsiveStyles) {
|
|
127
|
+
let modifiedChild = child;
|
|
128
|
+
if (modifiedChild.type === "head" || modifiedChild.type.displayName === "Head") {
|
|
129
|
+
const styleElement = /* @__PURE__ */ jsx("style", { children: responsiveStyles });
|
|
130
|
+
const headChildren = React.Children.toArray(modifiedChild.props.children);
|
|
131
|
+
headChildren.push(styleElement);
|
|
132
|
+
modifiedChild = React.cloneElement(
|
|
133
|
+
modifiedChild,
|
|
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;
|
|
153
|
+
}
|
|
31
154
|
var Tailwind = ({ children, config }) => {
|
|
155
|
+
const headStyles = [];
|
|
32
156
|
const { twi } = tailwindToCSS({
|
|
33
157
|
config
|
|
34
158
|
});
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
159
|
+
const childrenWithInlineStyles = React.Children.map(children, (child) => {
|
|
160
|
+
if (React.isValidElement(child)) {
|
|
161
|
+
return processElement(child, headStyles, twi);
|
|
162
|
+
}
|
|
163
|
+
return child;
|
|
40
164
|
});
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
165
|
+
if (!childrenWithInlineStyles)
|
|
166
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
167
|
+
const fullHTML = renderToStaticMarkup(/* @__PURE__ */ jsx(Fragment, { children: childrenWithInlineStyles }));
|
|
44
168
|
const hasResponsiveStyles = new RegExp("@media[^{]+\\{(?<content>[\\s\\S]+?)\\}\\s*\\}", "gm").test(
|
|
45
|
-
|
|
169
|
+
headStyles.join(" ")
|
|
46
170
|
);
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
if (hasResponsiveStyles && (!hasHTML || !hasHead)) {
|
|
171
|
+
const hasHTMLAndHead = /<html[^>]*>(?=[\s\S]*<head[^>]*>)/gm.test(fullHTML);
|
|
172
|
+
if (hasResponsiveStyles && !hasHTMLAndHead) {
|
|
50
173
|
throw new Error(
|
|
51
174
|
"Tailwind: To use responsive styles you must have a <html> and <head> element in your template."
|
|
52
175
|
);
|
|
53
176
|
}
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
replace: (domNode) => {
|
|
60
|
-
var _a;
|
|
61
|
-
if (domNode instanceof Element) {
|
|
62
|
-
if (hasResponsiveStyles && hasHead && domNode.name === "head") {
|
|
63
|
-
let newDomNode = null;
|
|
64
|
-
if (domNode.children) {
|
|
65
|
-
const props = attributesToProps(domNode.attribs);
|
|
66
|
-
newDomNode = /* @__PURE__ */ jsxs("head", __spreadProps(__spreadValues({}, props), { children: [
|
|
67
|
-
domToReact(domNode.children),
|
|
68
|
-
/* @__PURE__ */ jsx("style", { children: headStyle })
|
|
69
|
-
] }));
|
|
70
|
-
}
|
|
71
|
-
return newDomNode;
|
|
72
|
-
}
|
|
73
|
-
if ((_a = domNode.attribs) == null ? void 0 : _a.class) {
|
|
74
|
-
const cleanRegex = /[:#\!\-[\]\/\.%]+/g;
|
|
75
|
-
const cleanTailwindClasses = domNode.attribs.class.replace(cleanRegex, "_");
|
|
76
|
-
const currentStyles = domNode.attribs.style ? `${domNode.attribs.style};` : "";
|
|
77
|
-
const tailwindStyles = cleanTailwindClasses.split(" ").map((className) => {
|
|
78
|
-
return cssMap[`.${className}`];
|
|
79
|
-
}).join(";");
|
|
80
|
-
domNode.attribs.style = `${currentStyles} ${tailwindStyles}`;
|
|
81
|
-
domNode.attribs.class = domNode.attribs.class.split(" ").filter((className) => {
|
|
82
|
-
const cleanedClassName = className.replace(cleanRegex, "_");
|
|
83
|
-
return className.search(/^.{2}:/) !== -1 || !cssMap[`.${cleanedClassName}`];
|
|
84
|
-
}).join(" ").replace(cleanRegex, "_");
|
|
85
|
-
if (domNode.attribs.class === "")
|
|
86
|
-
delete domNode.attribs.class;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
177
|
+
const childrenWithInlineAndResponsiveStyles = React.Children.map(
|
|
178
|
+
childrenWithInlineStyles,
|
|
179
|
+
(child) => {
|
|
180
|
+
if (React.isValidElement(child)) {
|
|
181
|
+
return processHead(child, headStyles);
|
|
89
182
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
});
|
|
93
|
-
return /* @__PURE__ */ jsx(Fragment, { children: reactHTML });
|
|
94
|
-
};
|
|
95
|
-
Tailwind.displayName = "Tailwind";
|
|
96
|
-
function cleanCss(css) {
|
|
97
|
-
let newCss = css.replace(/\\/g, "").replace(/[.\!\#\w\d\\:\-\[\]\/\.%\(\))]+(?=\s*?{[^{]*?\})\s*?{/g, (m) => {
|
|
98
|
-
return m.replace(new RegExp("(?<=.)[:#\\!\\-[\\\\\\]\\/\\.%]+", "g"), "_");
|
|
99
|
-
}).replace(new RegExp("font-family(?<value>[^;\\r\\n]+)", "g"), (m, value) => {
|
|
100
|
-
return `font-family${value.replace(/['"]+/g, "")}`;
|
|
101
|
-
});
|
|
102
|
-
return newCss;
|
|
103
|
-
}
|
|
104
|
-
function getMediaQueryCss(css) {
|
|
105
|
-
var _a, _b;
|
|
106
|
-
const mediaQueryRegex = new RegExp("@media[^{]+\\{(?<content>[\\s\\S]+?)\\}\\s*\\}", "gm");
|
|
107
|
-
return (_b = (_a = css.replace(mediaQueryRegex, (m) => {
|
|
108
|
-
return m.replace(
|
|
109
|
-
/([^{]+\{)([\s\S]+?)(\}\s*\})/gm,
|
|
110
|
-
(_, start, content, end) => {
|
|
111
|
-
const newContent = content.replace(
|
|
112
|
-
new RegExp("(?:[\\s\\r\\n]*)?(?<prop>[\\w-]+)\\s*:\\s*(?<value>[^};\\r\\n]+)", "gm"),
|
|
113
|
-
(_2, prop, value) => {
|
|
114
|
-
return `${prop}: ${value} !important;`;
|
|
115
|
-
}
|
|
116
|
-
);
|
|
117
|
-
return `${start}${newContent}${end}`;
|
|
118
|
-
}
|
|
119
|
-
);
|
|
120
|
-
}).match(/@media\s*([^{]+)\{([^{}]*\{[^{}]*\})*[^{}]*\}/g)) == null ? void 0 : _a.join("")) != null ? _b : "";
|
|
121
|
-
}
|
|
122
|
-
function makeCssMap(css) {
|
|
123
|
-
const cssNoMedia = css.replace(
|
|
124
|
-
new RegExp("@media[^{]+\\{(?<content>[\\s\\S]+?)\\}\\s*\\}", "gm"),
|
|
125
|
-
""
|
|
126
|
-
);
|
|
127
|
-
const cssMap = cssNoMedia.split("}").reduce(
|
|
128
|
-
(acc, cur) => {
|
|
129
|
-
const [key, value] = cur.split("{");
|
|
130
|
-
if (key && value) {
|
|
131
|
-
acc[key] = value;
|
|
132
|
-
}
|
|
133
|
-
return acc;
|
|
134
|
-
},
|
|
135
|
-
{}
|
|
183
|
+
return child;
|
|
184
|
+
}
|
|
136
185
|
);
|
|
137
|
-
return
|
|
138
|
-
}
|
|
186
|
+
return /* @__PURE__ */ jsx(Fragment, { children: childrenWithInlineAndResponsiveStyles });
|
|
187
|
+
};
|
|
139
188
|
export {
|
|
140
189
|
Tailwind
|
|
141
190
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-email/tailwind",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"description": "A React component to wrap emails with Tailwind CSS",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -24,13 +24,11 @@
|
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"scripts": {
|
|
26
26
|
"build": "tsup src/index.ts --format esm,cjs --dts --external react",
|
|
27
|
-
"dev": "tsup src/index.ts --format esm,cjs --dts --external react --watch",
|
|
28
|
-
"lint": "eslint",
|
|
29
27
|
"clean": "rm -rf dist",
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
28
|
+
"dev": "tsup src/index.ts --format esm,cjs --dts --external react --watch",
|
|
29
|
+
"lint": "eslint .",
|
|
30
|
+
"test:watch": "vitest",
|
|
31
|
+
"test": "vitest run"
|
|
34
32
|
},
|
|
35
33
|
"repository": {
|
|
36
34
|
"type": "git",
|
|
@@ -43,29 +41,25 @@
|
|
|
43
41
|
"tailwind"
|
|
44
42
|
],
|
|
45
43
|
"engines": {
|
|
46
|
-
"node": ">=
|
|
44
|
+
"node": ">=18.0.0"
|
|
47
45
|
},
|
|
48
46
|
"dependencies": {
|
|
49
|
-
"html-react-parser": "4.0.0",
|
|
50
47
|
"react": "18.2.0",
|
|
51
48
|
"react-dom": "18.2.0",
|
|
52
49
|
"tw-to-css": "0.0.11"
|
|
53
50
|
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"react": "18.2.0"
|
|
53
|
+
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@babel/core": "
|
|
55
|
+
"@babel/core": "7.21.8",
|
|
56
56
|
"@babel/preset-react": "7.22.5",
|
|
57
|
-
"@react-email/
|
|
57
|
+
"@react-email/hr": "workspace:*",
|
|
58
|
+
"@react-email/head": "workspace:*",
|
|
59
|
+
"@react-email/html": "workspace:*",
|
|
58
60
|
"@testing-library/react": "14.0.0",
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"@types/react-dom": "18.0.6",
|
|
62
|
-
"babel-jest": "29.6.1",
|
|
63
|
-
"eslint": "8.45.0",
|
|
64
|
-
"jest": "29.6.1",
|
|
65
|
-
"prettier": "3.0.0",
|
|
66
|
-
"react": "18.2.0",
|
|
67
|
-
"ts-jest": "29.1.1",
|
|
68
|
-
"tsup": "7.1.0",
|
|
61
|
+
"eslint-config-custom": "workspace:*",
|
|
62
|
+
"tsconfig": "workspace:*",
|
|
69
63
|
"typescript": "5.1.6"
|
|
70
64
|
},
|
|
71
65
|
"publishConfig": {
|