@react-email/tailwind 0.0.8 → 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.d.mts +10 -0
- package/dist/index.js +171 -91
- package/dist/index.mjs +171 -92
- package/package.json +30 -23
- package/readme.md +1 -1
package/dist/index.d.mts
ADDED
package/dist/index.js
CHANGED
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __create = Object.create;
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
|
+
var __defProps = Object.defineProperties;
|
|
4
5
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
5
7
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
6
9
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
10
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
11
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
12
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
13
|
+
var __spreadValues = (a, b) => {
|
|
14
|
+
for (var prop in b || (b = {}))
|
|
15
|
+
if (__hasOwnProp.call(b, prop))
|
|
16
|
+
__defNormalProp(a, prop, b[prop]);
|
|
17
|
+
if (__getOwnPropSymbols)
|
|
18
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
19
|
+
if (__propIsEnum.call(b, prop))
|
|
20
|
+
__defNormalProp(a, prop, b[prop]);
|
|
21
|
+
}
|
|
22
|
+
return a;
|
|
23
|
+
};
|
|
24
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
8
25
|
var __export = (target, all) => {
|
|
9
26
|
for (var name in all)
|
|
10
27
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -18,6 +35,10 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
35
|
return to;
|
|
19
36
|
};
|
|
20
37
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
38
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
39
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
40
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
41
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
42
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
43
|
mod
|
|
23
44
|
));
|
|
@@ -33,111 +54,170 @@ module.exports = __toCommonJS(src_exports);
|
|
|
33
54
|
// src/tailwind.tsx
|
|
34
55
|
var React = __toESM(require("react"));
|
|
35
56
|
var import_server = require("react-dom/server");
|
|
36
|
-
var import_html_react_parser = __toESM(require("html-react-parser"));
|
|
37
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
|
|
38
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
|
+
}
|
|
39
187
|
var Tailwind = ({ children, config }) => {
|
|
188
|
+
const headStyles = [];
|
|
40
189
|
const { twi } = (0, import_tw_to_css.tailwindToCSS)({
|
|
41
190
|
config
|
|
42
191
|
});
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
192
|
+
const childrenWithInlineStyles = React.Children.map(children, (child) => {
|
|
193
|
+
if (React.isValidElement(child)) {
|
|
194
|
+
return processElement(child, headStyles, twi);
|
|
195
|
+
}
|
|
196
|
+
return child;
|
|
48
197
|
});
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
const hasResponsiveStyles =
|
|
53
|
-
|
|
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(" ")
|
|
54
203
|
);
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
if (hasResponsiveStyles && (!hasHTML || !hasHead)) {
|
|
204
|
+
const hasHTMLAndHead = /<html[^>]*>(?=[\s\S]*<head[^>]*>)/gm.test(fullHTML);
|
|
205
|
+
if (hasResponsiveStyles && !hasHTMLAndHead) {
|
|
58
206
|
throw new Error(
|
|
59
207
|
"Tailwind: To use responsive styles you must have a <html> and <head> element in your template."
|
|
60
208
|
);
|
|
61
209
|
}
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
replace: (domNode) => {
|
|
68
|
-
var _a;
|
|
69
|
-
if (domNode instanceof import_html_react_parser.Element) {
|
|
70
|
-
if (hasResponsiveStyles && hasHead && domNode.name === "head") {
|
|
71
|
-
let newDomNode = null;
|
|
72
|
-
if (domNode.children) {
|
|
73
|
-
const props = (0, import_html_react_parser.attributesToProps)(domNode.attribs);
|
|
74
|
-
newDomNode = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("head", { ...props, children: [
|
|
75
|
-
(0, import_html_react_parser.domToReact)(domNode.children),
|
|
76
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: headStyle })
|
|
77
|
-
] });
|
|
78
|
-
}
|
|
79
|
-
return newDomNode;
|
|
80
|
-
}
|
|
81
|
-
if ((_a = domNode.attribs) == null ? void 0 : _a.class) {
|
|
82
|
-
const cleanRegex = /[:#\!\-[\]\/\.%]+/g;
|
|
83
|
-
const cleanTailwindClasses = domNode.attribs.class.replace(cleanRegex, "_");
|
|
84
|
-
const currentStyles = domNode.attribs.style ? `${domNode.attribs.style};` : "";
|
|
85
|
-
const tailwindStyles = cleanTailwindClasses.split(" ").map((className) => {
|
|
86
|
-
return cssMap[`.${className}`];
|
|
87
|
-
}).join(";");
|
|
88
|
-
domNode.attribs.style = `${currentStyles} ${tailwindStyles}`;
|
|
89
|
-
domNode.attribs.class = domNode.attribs.class.split(" ").filter((className) => className.search(/^.{2}:/) !== -1).join(" ").replace(cleanRegex, "_");
|
|
90
|
-
if (domNode.attribs.class === "")
|
|
91
|
-
delete domNode.attribs.class;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
210
|
+
const childrenWithInlineAndResponsiveStyles = React.Children.map(
|
|
211
|
+
childrenWithInlineStyles,
|
|
212
|
+
(child) => {
|
|
213
|
+
if (React.isValidElement(child)) {
|
|
214
|
+
return processHead(child, headStyles);
|
|
94
215
|
}
|
|
95
|
-
|
|
96
|
-
return parsedHTML;
|
|
97
|
-
});
|
|
98
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: reactHTML });
|
|
99
|
-
};
|
|
100
|
-
Tailwind.displayName = "Tailwind";
|
|
101
|
-
function cleanCss(css) {
|
|
102
|
-
let newCss = css.replace(/\\/g, "").replace(/[.\!\#\w\d\\:\-\[\]\/\.%\(\))]+(?=\s*?{[^{]*?\})\s*?{/g, (m) => {
|
|
103
|
-
return m.replace(/(?<=.)[:#\!\-[\\\]\/\.%]+/g, "_");
|
|
104
|
-
}).replace(/font-family(?<value>[^;\r\n]+)/g, (m, value) => {
|
|
105
|
-
return `font-family${value.replace(/['"]+/g, "")}`;
|
|
106
|
-
});
|
|
107
|
-
return newCss;
|
|
108
|
-
}
|
|
109
|
-
function getMediaQueryCss(css) {
|
|
110
|
-
var _a;
|
|
111
|
-
const mediaQueryRegex = /@media[^{]+\{(?<content>[\s\S]+?)\}\s*\}/gm;
|
|
112
|
-
return ((_a = css.replace(mediaQueryRegex, (m) => {
|
|
113
|
-
return m.replace(
|
|
114
|
-
/([^{]+\{)([\s\S]+?)(\}\s*\})/gm,
|
|
115
|
-
(_, start, content, end) => {
|
|
116
|
-
const newContent = content.replace(
|
|
117
|
-
/(?:[\s\r\n]*)?(?<prop>[\w-]+)\s*:\s*(?<value>[^};\r\n]+)/gm,
|
|
118
|
-
(_2, prop, value) => {
|
|
119
|
-
return `${prop}: ${value} !important;`;
|
|
120
|
-
}
|
|
121
|
-
);
|
|
122
|
-
return `${start}${newContent}${end}`;
|
|
123
|
-
}
|
|
124
|
-
);
|
|
125
|
-
}).match(/@media\s*([^{]+)\{([^{}]*\{[^{}]*\})*[^{}]*\}/g)) == null ? void 0 : _a.join("")) ?? "";
|
|
126
|
-
}
|
|
127
|
-
function makeCssMap(css) {
|
|
128
|
-
const cssNoMedia = css.replace(
|
|
129
|
-
/@media[^{]+\{(?<content>[\s\S]+?)\}\s*\}/gm,
|
|
130
|
-
""
|
|
131
|
-
);
|
|
132
|
-
const cssMap = cssNoMedia.split("}").reduce((acc, cur) => {
|
|
133
|
-
const [key, value] = cur.split("{");
|
|
134
|
-
if (key && value) {
|
|
135
|
-
acc[key] = value;
|
|
216
|
+
return child;
|
|
136
217
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
218
|
+
);
|
|
219
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: childrenWithInlineAndResponsiveStyles });
|
|
220
|
+
};
|
|
141
221
|
// Annotate the CommonJS export names for ESM import in node:
|
|
142
222
|
0 && (module.exports = {
|
|
143
223
|
Tailwind
|
package/dist/index.mjs
CHANGED
|
@@ -1,111 +1,190 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
|
|
1
21
|
// src/tailwind.tsx
|
|
2
22
|
import * as React from "react";
|
|
3
23
|
import { renderToStaticMarkup } from "react-dom/server";
|
|
4
|
-
import htmlParser, { attributesToProps, domToReact, Element } from "html-react-parser";
|
|
5
24
|
import { tailwindToCSS } from "tw-to-css";
|
|
6
|
-
|
|
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
|
+
}
|
|
7
154
|
var Tailwind = ({ children, config }) => {
|
|
155
|
+
const headStyles = [];
|
|
8
156
|
const { twi } = tailwindToCSS({
|
|
9
157
|
config
|
|
10
158
|
});
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
159
|
+
const childrenWithInlineStyles = React.Children.map(children, (child) => {
|
|
160
|
+
if (React.isValidElement(child)) {
|
|
161
|
+
return processElement(child, headStyles, twi);
|
|
162
|
+
}
|
|
163
|
+
return child;
|
|
16
164
|
});
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
const hasResponsiveStyles =
|
|
21
|
-
|
|
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(" ")
|
|
22
170
|
);
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
if (hasResponsiveStyles && (!hasHTML || !hasHead)) {
|
|
171
|
+
const hasHTMLAndHead = /<html[^>]*>(?=[\s\S]*<head[^>]*>)/gm.test(fullHTML);
|
|
172
|
+
if (hasResponsiveStyles && !hasHTMLAndHead) {
|
|
26
173
|
throw new Error(
|
|
27
174
|
"Tailwind: To use responsive styles you must have a <html> and <head> element in your template."
|
|
28
175
|
);
|
|
29
176
|
}
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
replace: (domNode) => {
|
|
36
|
-
var _a;
|
|
37
|
-
if (domNode instanceof Element) {
|
|
38
|
-
if (hasResponsiveStyles && hasHead && domNode.name === "head") {
|
|
39
|
-
let newDomNode = null;
|
|
40
|
-
if (domNode.children) {
|
|
41
|
-
const props = attributesToProps(domNode.attribs);
|
|
42
|
-
newDomNode = /* @__PURE__ */ jsxs("head", { ...props, children: [
|
|
43
|
-
domToReact(domNode.children),
|
|
44
|
-
/* @__PURE__ */ jsx("style", { children: headStyle })
|
|
45
|
-
] });
|
|
46
|
-
}
|
|
47
|
-
return newDomNode;
|
|
48
|
-
}
|
|
49
|
-
if ((_a = domNode.attribs) == null ? void 0 : _a.class) {
|
|
50
|
-
const cleanRegex = /[:#\!\-[\]\/\.%]+/g;
|
|
51
|
-
const cleanTailwindClasses = domNode.attribs.class.replace(cleanRegex, "_");
|
|
52
|
-
const currentStyles = domNode.attribs.style ? `${domNode.attribs.style};` : "";
|
|
53
|
-
const tailwindStyles = cleanTailwindClasses.split(" ").map((className) => {
|
|
54
|
-
return cssMap[`.${className}`];
|
|
55
|
-
}).join(";");
|
|
56
|
-
domNode.attribs.style = `${currentStyles} ${tailwindStyles}`;
|
|
57
|
-
domNode.attribs.class = domNode.attribs.class.split(" ").filter((className) => className.search(/^.{2}:/) !== -1).join(" ").replace(cleanRegex, "_");
|
|
58
|
-
if (domNode.attribs.class === "")
|
|
59
|
-
delete domNode.attribs.class;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
return parsedHTML;
|
|
65
|
-
});
|
|
66
|
-
return /* @__PURE__ */ jsx(Fragment, { children: reactHTML });
|
|
67
|
-
};
|
|
68
|
-
Tailwind.displayName = "Tailwind";
|
|
69
|
-
function cleanCss(css) {
|
|
70
|
-
let newCss = css.replace(/\\/g, "").replace(/[.\!\#\w\d\\:\-\[\]\/\.%\(\))]+(?=\s*?{[^{]*?\})\s*?{/g, (m) => {
|
|
71
|
-
return m.replace(/(?<=.)[:#\!\-[\\\]\/\.%]+/g, "_");
|
|
72
|
-
}).replace(/font-family(?<value>[^;\r\n]+)/g, (m, value) => {
|
|
73
|
-
return `font-family${value.replace(/['"]+/g, "")}`;
|
|
74
|
-
});
|
|
75
|
-
return newCss;
|
|
76
|
-
}
|
|
77
|
-
function getMediaQueryCss(css) {
|
|
78
|
-
var _a;
|
|
79
|
-
const mediaQueryRegex = /@media[^{]+\{(?<content>[\s\S]+?)\}\s*\}/gm;
|
|
80
|
-
return ((_a = css.replace(mediaQueryRegex, (m) => {
|
|
81
|
-
return m.replace(
|
|
82
|
-
/([^{]+\{)([\s\S]+?)(\}\s*\})/gm,
|
|
83
|
-
(_, start, content, end) => {
|
|
84
|
-
const newContent = content.replace(
|
|
85
|
-
/(?:[\s\r\n]*)?(?<prop>[\w-]+)\s*:\s*(?<value>[^};\r\n]+)/gm,
|
|
86
|
-
(_2, prop, value) => {
|
|
87
|
-
return `${prop}: ${value} !important;`;
|
|
88
|
-
}
|
|
89
|
-
);
|
|
90
|
-
return `${start}${newContent}${end}`;
|
|
177
|
+
const childrenWithInlineAndResponsiveStyles = React.Children.map(
|
|
178
|
+
childrenWithInlineStyles,
|
|
179
|
+
(child) => {
|
|
180
|
+
if (React.isValidElement(child)) {
|
|
181
|
+
return processHead(child, headStyles);
|
|
91
182
|
}
|
|
92
|
-
|
|
93
|
-
}).match(/@media\s*([^{]+)\{([^{}]*\{[^{}]*\})*[^{}]*\}/g)) == null ? void 0 : _a.join("")) ?? "";
|
|
94
|
-
}
|
|
95
|
-
function makeCssMap(css) {
|
|
96
|
-
const cssNoMedia = css.replace(
|
|
97
|
-
/@media[^{]+\{(?<content>[\s\S]+?)\}\s*\}/gm,
|
|
98
|
-
""
|
|
99
|
-
);
|
|
100
|
-
const cssMap = cssNoMedia.split("}").reduce((acc, cur) => {
|
|
101
|
-
const [key, value] = cur.split("{");
|
|
102
|
-
if (key && value) {
|
|
103
|
-
acc[key] = value;
|
|
183
|
+
return child;
|
|
104
184
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
185
|
+
);
|
|
186
|
+
return /* @__PURE__ */ jsx(Fragment, { children: childrenWithInlineAndResponsiveStyles });
|
|
187
|
+
};
|
|
109
188
|
export {
|
|
110
189
|
Tailwind
|
|
111
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",
|
|
@@ -9,20 +9,30 @@
|
|
|
9
9
|
"files": [
|
|
10
10
|
"dist/**"
|
|
11
11
|
],
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.mjs"
|
|
17
|
+
},
|
|
18
|
+
"require": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
12
24
|
"license": "MIT",
|
|
13
25
|
"scripts": {
|
|
14
26
|
"build": "tsup src/index.ts --format esm,cjs --dts --external react",
|
|
15
|
-
"dev": "tsup src/index.ts --format esm,cjs --dts --external react --watch",
|
|
16
|
-
"lint": "eslint",
|
|
17
27
|
"clean": "rm -rf dist",
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
28
|
+
"dev": "tsup src/index.ts --format esm,cjs --dts --external react --watch",
|
|
29
|
+
"lint": "eslint .",
|
|
30
|
+
"test:watch": "vitest",
|
|
31
|
+
"test": "vitest run"
|
|
22
32
|
},
|
|
23
33
|
"repository": {
|
|
24
34
|
"type": "git",
|
|
25
|
-
"url": "https://github.com/
|
|
35
|
+
"url": "https://github.com/resendlabs/react-email.git",
|
|
26
36
|
"directory": "packages/tailwind"
|
|
27
37
|
},
|
|
28
38
|
"keywords": [
|
|
@@ -31,29 +41,26 @@
|
|
|
31
41
|
"tailwind"
|
|
32
42
|
],
|
|
33
43
|
"engines": {
|
|
34
|
-
"node": ">=
|
|
44
|
+
"node": ">=18.0.0"
|
|
35
45
|
},
|
|
36
46
|
"dependencies": {
|
|
37
|
-
"html-react-parser": "3.0.9",
|
|
38
47
|
"react": "18.2.0",
|
|
39
48
|
"react-dom": "18.2.0",
|
|
40
49
|
"tw-to-css": "0.0.11"
|
|
41
50
|
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"react": "18.2.0"
|
|
53
|
+
},
|
|
42
54
|
"devDependencies": {
|
|
43
|
-
"@babel/
|
|
44
|
-
"@react
|
|
55
|
+
"@babel/core": "7.21.8",
|
|
56
|
+
"@babel/preset-react": "7.22.5",
|
|
57
|
+
"@react-email/hr": "workspace:*",
|
|
58
|
+
"@react-email/head": "workspace:*",
|
|
59
|
+
"@react-email/html": "workspace:*",
|
|
45
60
|
"@testing-library/react": "14.0.0",
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"babel-jest": "29.5.0",
|
|
50
|
-
"eslint": "8.23.1",
|
|
51
|
-
"jest": "29.5.0",
|
|
52
|
-
"prettier": "2.8.4",
|
|
53
|
-
"react": "18.2.0",
|
|
54
|
-
"ts-jest": "29.0.5",
|
|
55
|
-
"tsup": "6.2.3",
|
|
56
|
-
"typescript": "4.8.3"
|
|
61
|
+
"eslint-config-custom": "workspace:*",
|
|
62
|
+
"tsconfig": "workspace:*",
|
|
63
|
+
"typescript": "5.1.6"
|
|
57
64
|
},
|
|
58
65
|
"publishConfig": {
|
|
59
66
|
"access": "public"
|
package/readme.md
CHANGED
|
@@ -65,7 +65,7 @@ This component was tested using the most popular email clients.
|
|
|
65
65
|
|
|
66
66
|
| <img src="https://react.email/static/icons/gmail.svg" width="48px" height="48px" alt="Gmail logo"> | <img src="https://react.email/static/icons/apple-mail.svg" width="48px" height="48px" alt="Apple Mail"> | <img src="https://react.email/static/icons/outlook.svg" width="48px" height="48px" alt="Outlook logo"> | <img src="https://react.email/static/icons/yahoo-mail.svg" width="48px" height="48px" alt="Yahoo! Mail logo"> | <img src="https://react.email/static/icons/hey.svg" width="48px" height="48px" alt="HEY logo"> | <img src="https://react.email/static/icons/superhuman.svg" width="48px" height="48px" alt="Superhuman logo"> |
|
|
67
67
|
| -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
|
68
|
-
| Gmail ✔
|
|
68
|
+
| Gmail ✔ | Apple Mail ✔ | Outlook ✔ | Yahoo! Mail ✔ | HEY ✔ | Superhuman ✔ |
|
|
69
69
|
|
|
70
70
|
## License
|
|
71
71
|
|