@react-email/tailwind 0.0.3 → 0.0.5
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.ts +1 -1
- package/dist/index.js +80 -19
- package/dist/index.mjs +80 -19
- package/package.json +8 -2
- package/readme.md +1 -1
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -32,31 +32,92 @@ module.exports = __toCommonJS(src_exports);
|
|
|
32
32
|
|
|
33
33
|
// src/tailwind.tsx
|
|
34
34
|
var React = __toESM(require("react"));
|
|
35
|
+
var import_server = require("react-dom/server");
|
|
36
|
+
var import_html_react_parser = __toESM(require("html-react-parser"));
|
|
35
37
|
var import_tw_to_css = require("tw-to-css");
|
|
36
38
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
37
|
-
var Tailwind = ({
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
})
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
|
|
39
|
+
var Tailwind = ({ children, config }) => {
|
|
40
|
+
const { twi } = (0, import_tw_to_css.tailwindToCSS)({
|
|
41
|
+
config
|
|
42
|
+
});
|
|
43
|
+
const newChildren = React.Children.toArray(children);
|
|
44
|
+
const fullHTML = (0, import_server.renderToStaticMarkup)(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: newChildren }));
|
|
45
|
+
const headStyle = getMediaQueryCSS(
|
|
46
|
+
twi(fullHTML, {
|
|
47
|
+
merge: false,
|
|
48
|
+
ignoreMediaQueries: false
|
|
49
|
+
})
|
|
50
|
+
);
|
|
51
|
+
const hasResponsiveStyles = /@media[^{]+\{(?<content>[\s\S]+?)\}\s*\}/gm.test(
|
|
52
|
+
headStyle
|
|
53
|
+
);
|
|
54
|
+
const hasHTML = /<html[^>]*>/gm.test(fullHTML);
|
|
55
|
+
const hasHead = /<head[^>]*>/gm.test(fullHTML);
|
|
56
|
+
if (hasResponsiveStyles && !hasHTML && !hasHead) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
"Tailwind: To use responsive styles you must have a <html> and <head> element in your template."
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
const reactHTML = React.Children.map(newChildren, (child) => {
|
|
62
|
+
if (!React.isValidElement(child))
|
|
44
63
|
return child;
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
64
|
+
const html = (0, import_server.renderToStaticMarkup)(child);
|
|
65
|
+
const parsedHTML = (0, import_html_react_parser.default)(html, {
|
|
66
|
+
replace: (domNode) => {
|
|
67
|
+
var _a;
|
|
68
|
+
if (domNode instanceof import_html_react_parser.Element) {
|
|
69
|
+
if (hasResponsiveStyles && hasHead && domNode.name === "head") {
|
|
70
|
+
let newDomNode = null;
|
|
71
|
+
if (domNode.children) {
|
|
72
|
+
const style = domNode.children.find(
|
|
73
|
+
(child2) => child2 instanceof import_html_react_parser.Element && child2.name === "style"
|
|
74
|
+
);
|
|
75
|
+
const props = (0, import_html_react_parser.attributesToProps)(domNode.attribs);
|
|
76
|
+
newDomNode = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("head", { ...props, children: style && style instanceof import_html_react_parser.Element ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `${style.children} ${headStyle}` }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: headStyle }) });
|
|
77
|
+
}
|
|
78
|
+
return newDomNode;
|
|
79
|
+
}
|
|
80
|
+
if ((_a = domNode.attribs) == null ? void 0 : _a.class) {
|
|
81
|
+
if (hasResponsiveStyles) {
|
|
82
|
+
domNode.attribs.class = domNode.attribs.class.replace(
|
|
83
|
+
/[:#\!\-[\]]+/g,
|
|
84
|
+
"_"
|
|
85
|
+
);
|
|
86
|
+
} else {
|
|
87
|
+
domNode.attribs.style = `${twi(domNode.attribs.class)} ${domNode.attribs.style || ""}`;
|
|
88
|
+
delete domNode.attribs.class;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
51
93
|
});
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
replaceTailwindStyles
|
|
56
|
-
);
|
|
57
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: tailwindStylesToCSS });
|
|
94
|
+
return parsedHTML;
|
|
95
|
+
});
|
|
96
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: reactHTML });
|
|
58
97
|
};
|
|
59
98
|
Tailwind.displayName = "Tailwind";
|
|
99
|
+
function getMediaQueryCSS(css) {
|
|
100
|
+
const mediaQueryRegex = /@media[^{]+\{(?<content>[\s\S]+?)\}\s*\}/gm;
|
|
101
|
+
let newCss = css.replace(mediaQueryRegex, (m) => {
|
|
102
|
+
return m.replace(
|
|
103
|
+
/([^{]+\{)([\s\S]+?)(\}\s*\})/gm,
|
|
104
|
+
(_, start, content, end) => {
|
|
105
|
+
const newcontent = content.replace(
|
|
106
|
+
/(?:[\s\r\n]*)?(?<prop>[\w-]+)\s*:\s*(?<value>[^;\r\n]+)/gm,
|
|
107
|
+
(_2, prop, value) => {
|
|
108
|
+
return `${prop}: ${value} !important`;
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
return `${start}${newcontent}${end}`;
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
}).replace(/[.\!\#\w\d\\:\-\[\]]+\s*?{/g, (m) => {
|
|
115
|
+
return m.replace(/[:#\!\-[\\\]]+/g, "_");
|
|
116
|
+
}).replace(/font-family(?<value>[^;\r\n]+)/g, (m, value) => {
|
|
117
|
+
return `font-family${value.replace(/['"]+/g, "")}`;
|
|
118
|
+
});
|
|
119
|
+
return newCss;
|
|
120
|
+
}
|
|
60
121
|
// Annotate the CommonJS export names for ESM import in node:
|
|
61
122
|
0 && (module.exports = {
|
|
62
123
|
Tailwind
|
package/dist/index.mjs
CHANGED
|
@@ -1,30 +1,91 @@
|
|
|
1
1
|
// src/tailwind.tsx
|
|
2
2
|
import * as React from "react";
|
|
3
|
+
import { renderToStaticMarkup } from "react-dom/server";
|
|
4
|
+
import htmlParser, { attributesToProps, Element } from "html-react-parser";
|
|
3
5
|
import { tailwindToCSS } from "tw-to-css";
|
|
4
6
|
import { Fragment, jsx } from "react/jsx-runtime";
|
|
5
|
-
var Tailwind = ({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
})
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
|
|
7
|
+
var Tailwind = ({ children, config }) => {
|
|
8
|
+
const { twi } = tailwindToCSS({
|
|
9
|
+
config
|
|
10
|
+
});
|
|
11
|
+
const newChildren = React.Children.toArray(children);
|
|
12
|
+
const fullHTML = renderToStaticMarkup(/* @__PURE__ */ jsx(Fragment, { children: newChildren }));
|
|
13
|
+
const headStyle = getMediaQueryCSS(
|
|
14
|
+
twi(fullHTML, {
|
|
15
|
+
merge: false,
|
|
16
|
+
ignoreMediaQueries: false
|
|
17
|
+
})
|
|
18
|
+
);
|
|
19
|
+
const hasResponsiveStyles = /@media[^{]+\{(?<content>[\s\S]+?)\}\s*\}/gm.test(
|
|
20
|
+
headStyle
|
|
21
|
+
);
|
|
22
|
+
const hasHTML = /<html[^>]*>/gm.test(fullHTML);
|
|
23
|
+
const hasHead = /<head[^>]*>/gm.test(fullHTML);
|
|
24
|
+
if (hasResponsiveStyles && !hasHTML && !hasHead) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
"Tailwind: To use responsive styles you must have a <html> and <head> element in your template."
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
const reactHTML = React.Children.map(newChildren, (child) => {
|
|
30
|
+
if (!React.isValidElement(child))
|
|
12
31
|
return child;
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
32
|
+
const html = renderToStaticMarkup(child);
|
|
33
|
+
const parsedHTML = htmlParser(html, {
|
|
34
|
+
replace: (domNode) => {
|
|
35
|
+
var _a;
|
|
36
|
+
if (domNode instanceof Element) {
|
|
37
|
+
if (hasResponsiveStyles && hasHead && domNode.name === "head") {
|
|
38
|
+
let newDomNode = null;
|
|
39
|
+
if (domNode.children) {
|
|
40
|
+
const style = domNode.children.find(
|
|
41
|
+
(child2) => child2 instanceof Element && child2.name === "style"
|
|
42
|
+
);
|
|
43
|
+
const props = attributesToProps(domNode.attribs);
|
|
44
|
+
newDomNode = /* @__PURE__ */ jsx("head", { ...props, children: style && style instanceof Element ? /* @__PURE__ */ jsx("style", { children: `${style.children} ${headStyle}` }) : /* @__PURE__ */ jsx("style", { children: headStyle }) });
|
|
45
|
+
}
|
|
46
|
+
return newDomNode;
|
|
47
|
+
}
|
|
48
|
+
if ((_a = domNode.attribs) == null ? void 0 : _a.class) {
|
|
49
|
+
if (hasResponsiveStyles) {
|
|
50
|
+
domNode.attribs.class = domNode.attribs.class.replace(
|
|
51
|
+
/[:#\!\-[\]]+/g,
|
|
52
|
+
"_"
|
|
53
|
+
);
|
|
54
|
+
} else {
|
|
55
|
+
domNode.attribs.style = `${twi(domNode.attribs.class)} ${domNode.attribs.style || ""}`;
|
|
56
|
+
delete domNode.attribs.class;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
19
61
|
});
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
replaceTailwindStyles
|
|
24
|
-
);
|
|
25
|
-
return /* @__PURE__ */ jsx(Fragment, { children: tailwindStylesToCSS });
|
|
62
|
+
return parsedHTML;
|
|
63
|
+
});
|
|
64
|
+
return /* @__PURE__ */ jsx(Fragment, { children: reactHTML });
|
|
26
65
|
};
|
|
27
66
|
Tailwind.displayName = "Tailwind";
|
|
67
|
+
function getMediaQueryCSS(css) {
|
|
68
|
+
const mediaQueryRegex = /@media[^{]+\{(?<content>[\s\S]+?)\}\s*\}/gm;
|
|
69
|
+
let newCss = css.replace(mediaQueryRegex, (m) => {
|
|
70
|
+
return m.replace(
|
|
71
|
+
/([^{]+\{)([\s\S]+?)(\}\s*\})/gm,
|
|
72
|
+
(_, start, content, end) => {
|
|
73
|
+
const newcontent = content.replace(
|
|
74
|
+
/(?:[\s\r\n]*)?(?<prop>[\w-]+)\s*:\s*(?<value>[^;\r\n]+)/gm,
|
|
75
|
+
(_2, prop, value) => {
|
|
76
|
+
return `${prop}: ${value} !important`;
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
return `${start}${newcontent}${end}`;
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
}).replace(/[.\!\#\w\d\\:\-\[\]]+\s*?{/g, (m) => {
|
|
83
|
+
return m.replace(/[:#\!\-[\\\]]+/g, "_");
|
|
84
|
+
}).replace(/font-family(?<value>[^;\r\n]+)/g, (m, value) => {
|
|
85
|
+
return `font-family${value.replace(/['"]+/g, "")}`;
|
|
86
|
+
});
|
|
87
|
+
return newCss;
|
|
88
|
+
}
|
|
28
89
|
export {
|
|
29
90
|
Tailwind
|
|
30
91
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-email/tailwind",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "A React component to wrap emails with Tailwind CSS",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
"dev": "tsup src/index.ts --format esm,cjs --dts --external react --watch",
|
|
16
16
|
"lint": "eslint",
|
|
17
17
|
"clean": "rm -rf dist",
|
|
18
|
+
"test": "jest",
|
|
19
|
+
"test:watch": "jest --watch",
|
|
18
20
|
"format:check": "prettier --ignore-path ./../../.prettierignore --check \"**/*.{ts,tsx,md}\"",
|
|
19
21
|
"format": "prettier --ignore-path ./../../.prettierignore --write \"**/*.{ts,tsx,md}\""
|
|
20
22
|
},
|
|
@@ -32,9 +34,13 @@
|
|
|
32
34
|
"node": ">=16.0.0"
|
|
33
35
|
},
|
|
34
36
|
"dependencies": {
|
|
35
|
-
"
|
|
37
|
+
"html-react-parser": "3.0.9",
|
|
38
|
+
"react": "18.2.0",
|
|
39
|
+
"react-dom": "18.2.0",
|
|
40
|
+
"tw-to-css": "0.0.10"
|
|
36
41
|
},
|
|
37
42
|
"devDependencies": {
|
|
43
|
+
"@testing-library/react": "14.0.0",
|
|
38
44
|
"@types/react": "18.0.20",
|
|
39
45
|
"@types/react-dom": "18.0.6",
|
|
40
46
|
"eslint": "8.23.1",
|
package/readme.md
CHANGED