@lupinum/nuxt-email 0.1.0

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.
Files changed (159) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/LICENSE +21 -0
  3. package/README.md +172 -0
  4. package/THIRD_PARTY_NOTICES +75 -0
  5. package/dist/chunks/setup.mjs +149 -0
  6. package/dist/module.d.mts +15 -0
  7. package/dist/module.json +12 -0
  8. package/dist/module.mjs +300 -0
  9. package/dist/runtime/code-block/create-component.d.ts +16 -0
  10. package/dist/runtime/code-block/create-component.js +106 -0
  11. package/dist/runtime/components/EBody.d.ts +4 -0
  12. package/dist/runtime/components/EBody.js +75 -0
  13. package/dist/runtime/components/EButton.d.ts +11 -0
  14. package/dist/runtime/components/EButton.js +89 -0
  15. package/dist/runtime/components/EButton.padding.d.ts +12 -0
  16. package/dist/runtime/components/EButton.padding.js +118 -0
  17. package/dist/runtime/components/ECodeInline.d.ts +13 -0
  18. package/dist/runtime/components/ECodeInline.js +43 -0
  19. package/dist/runtime/components/EColumn.d.ts +4 -0
  20. package/dist/runtime/components/EColumn.js +12 -0
  21. package/dist/runtime/components/EContainer.d.ts +4 -0
  22. package/dist/runtime/components/EContainer.js +35 -0
  23. package/dist/runtime/components/EFont.d.ts +24 -0
  24. package/dist/runtime/components/EFont.js +124 -0
  25. package/dist/runtime/components/EHead.d.ts +4 -0
  26. package/dist/runtime/components/EHead.js +17 -0
  27. package/dist/runtime/components/EHeading.d.ts +7 -0
  28. package/dist/runtime/components/EHeading.js +23 -0
  29. package/dist/runtime/components/EHr.d.ts +4 -0
  30. package/dist/runtime/components/EHr.js +26 -0
  31. package/dist/runtime/components/EHtml.d.ts +4 -0
  32. package/dist/runtime/components/EHtml.js +17 -0
  33. package/dist/runtime/components/EImg.d.ts +7 -0
  34. package/dist/runtime/components/EImg.js +44 -0
  35. package/dist/runtime/components/ELink.d.ts +6 -0
  36. package/dist/runtime/components/ELink.js +35 -0
  37. package/dist/runtime/components/EMarkdown.d.ts +8 -0
  38. package/dist/runtime/components/EMarkdown.js +64 -0
  39. package/dist/runtime/components/EPreview.d.ts +8 -0
  40. package/dist/runtime/components/EPreview.js +85 -0
  41. package/dist/runtime/components/ERow.d.ts +4 -0
  42. package/dist/runtime/components/ERow.js +53 -0
  43. package/dist/runtime/components/ESection.d.ts +4 -0
  44. package/dist/runtime/components/ESection.js +35 -0
  45. package/dist/runtime/components/ETailwind.d.ts +24 -0
  46. package/dist/runtime/components/ETailwind.js +49 -0
  47. package/dist/runtime/components/EText.d.ts +4 -0
  48. package/dist/runtime/components/EText.js +20 -0
  49. package/dist/runtime/components/EText.margins.d.ts +18 -0
  50. package/dist/runtime/components/EText.margins.js +81 -0
  51. package/dist/runtime/components/attributes.d.ts +4 -0
  52. package/dist/runtime/components/attributes.js +11 -0
  53. package/dist/runtime/components/email-component-names.d.ts +2 -0
  54. package/dist/runtime/components/email-component-names.js +20 -0
  55. package/dist/runtime/components/email-component-registry.d.ts +8 -0
  56. package/dist/runtime/components/email-component-registry.js +2 -0
  57. package/dist/runtime/components/index.d.ts +23 -0
  58. package/dist/runtime/components/index.js +18 -0
  59. package/dist/runtime/components/markdown/parse-css-in-js-to-inline-css.d.ts +2 -0
  60. package/dist/runtime/components/markdown/parse-css-in-js-to-inline-css.js +60 -0
  61. package/dist/runtime/components/markdown/render-markdown.d.ts +2 -0
  62. package/dist/runtime/components/markdown/render-markdown.js +137 -0
  63. package/dist/runtime/components/markdown/styles.d.ts +30 -0
  64. package/dist/runtime/components/markdown/styles.js +91 -0
  65. package/dist/runtime/components/presentation-table.d.ts +7 -0
  66. package/dist/runtime/components/presentation-table.js +11 -0
  67. package/dist/runtime/components/style.d.ts +5 -0
  68. package/dist/runtime/components/style.js +32 -0
  69. package/dist/runtime/components/table-padding.d.ts +6 -0
  70. package/dist/runtime/components/table-padding.js +20 -0
  71. package/dist/runtime/define-email.d.ts +2 -0
  72. package/dist/runtime/define-email.js +5 -0
  73. package/dist/runtime/dev-preview/page-script.d.ts +1 -0
  74. package/dist/runtime/dev-preview/page-script.js +403 -0
  75. package/dist/runtime/dev-preview/page.css.d.ts +1 -0
  76. package/dist/runtime/dev-preview/page.css.js +602 -0
  77. package/dist/runtime/dev-preview/page.get.d.ts +4 -0
  78. package/dist/runtime/dev-preview/page.get.js +119 -0
  79. package/dist/runtime/dev-preview/render.get.d.ts +3 -0
  80. package/dist/runtime/dev-preview/render.get.js +123 -0
  81. package/dist/runtime/dev-preview/templates.get.d.ts +7 -0
  82. package/dist/runtime/dev-preview/templates.get.js +14 -0
  83. package/dist/runtime/errors.d.ts +4 -0
  84. package/dist/runtime/errors.js +7 -0
  85. package/dist/runtime/render/define-email.d.ts +56 -0
  86. package/dist/runtime/render/define-email.js +40 -0
  87. package/dist/runtime/render/document.d.ts +4 -0
  88. package/dist/runtime/render/document.js +75 -0
  89. package/dist/runtime/render/errors.d.ts +4 -0
  90. package/dist/runtime/render/errors.js +8 -0
  91. package/dist/runtime/render/plain-text.d.ts +1 -0
  92. package/dist/runtime/render/plain-text.js +15 -0
  93. package/dist/runtime/render/render-component.d.ts +4 -0
  94. package/dist/runtime/render/render-component.js +46 -0
  95. package/dist/runtime/render/render-email-component.d.ts +16 -0
  96. package/dist/runtime/render/render-email-component.js +46 -0
  97. package/dist/runtime/render/types.d.ts +9 -0
  98. package/dist/runtime/render/types.js +0 -0
  99. package/dist/runtime/tailwind/engine/compatibility/escape-class-name.d.ts +8 -0
  100. package/dist/runtime/tailwind/engine/compatibility/escape-class-name.js +10 -0
  101. package/dist/runtime/tailwind/engine/compatibility/sanitize-class-name.d.ts +7 -0
  102. package/dist/runtime/tailwind/engine/compatibility/sanitize-class-name.js +17 -0
  103. package/dist/runtime/tailwind/engine/compatibility/unescape-class.d.ts +1 -0
  104. package/dist/runtime/tailwind/engine/compatibility/unescape-class.js +3 -0
  105. package/dist/runtime/tailwind/engine/css/downlevel-for-email-clients.d.ts +63 -0
  106. package/dist/runtime/tailwind/engine/css/downlevel-for-email-clients.js +107 -0
  107. package/dist/runtime/tailwind/engine/css/extract-rules-per-class.d.ts +6 -0
  108. package/dist/runtime/tailwind/engine/css/extract-rules-per-class.js +54 -0
  109. package/dist/runtime/tailwind/engine/css/get-css-property.d.ts +17 -0
  110. package/dist/runtime/tailwind/engine/css/get-css-property.js +3 -0
  111. package/dist/runtime/tailwind/engine/css/get-custom-properties.d.ts +8 -0
  112. package/dist/runtime/tailwind/engine/css/get-custom-properties.js +37 -0
  113. package/dist/runtime/tailwind/engine/css/is-part-inlinable.d.ts +2 -0
  114. package/dist/runtime/tailwind/engine/css/is-part-inlinable.js +9 -0
  115. package/dist/runtime/tailwind/engine/css/is-rule-inlinable.d.ts +2 -0
  116. package/dist/runtime/tailwind/engine/css/is-rule-inlinable.js +9 -0
  117. package/dist/runtime/tailwind/engine/css/make-inline-styles-for.d.ts +21 -0
  118. package/dist/runtime/tailwind/engine/css/make-inline-styles-for.js +62 -0
  119. package/dist/runtime/tailwind/engine/css/resolve-all-css-variables.d.ts +8 -0
  120. package/dist/runtime/tailwind/engine/css/resolve-all-css-variables.js +138 -0
  121. package/dist/runtime/tailwind/engine/css/resolve-calc-expressions.d.ts +5 -0
  122. package/dist/runtime/tailwind/engine/css/resolve-calc-expressions.js +101 -0
  123. package/dist/runtime/tailwind/engine/css/sanitize-declarations.d.ts +15 -0
  124. package/dist/runtime/tailwind/engine/css/sanitize-declarations.js +358 -0
  125. package/dist/runtime/tailwind/engine/css/sanitize-non-inlinable-rules.d.ts +17 -0
  126. package/dist/runtime/tailwind/engine/css/sanitize-non-inlinable-rules.js +30 -0
  127. package/dist/runtime/tailwind/engine/css/split-mixed-rule.d.ts +12 -0
  128. package/dist/runtime/tailwind/engine/css/split-mixed-rule.js +37 -0
  129. package/dist/runtime/tailwind/engine/css/strip-empty-tailwind-vars.d.ts +19 -0
  130. package/dist/runtime/tailwind/engine/css/strip-empty-tailwind-vars.js +44 -0
  131. package/dist/runtime/tailwind/engine/css/unwrap-value.d.ts +2 -0
  132. package/dist/runtime/tailwind/engine/css/unwrap-value.js +6 -0
  133. package/dist/runtime/tailwind/engine/index.d.ts +63 -0
  134. package/dist/runtime/tailwind/engine/index.js +53 -0
  135. package/dist/runtime/tailwind/engine/pixel-based-preset.d.ts +9 -0
  136. package/dist/runtime/tailwind/engine/pixel-based-preset.js +58 -0
  137. package/dist/runtime/tailwind/engine/sanitize-stylesheet.d.ts +10 -0
  138. package/dist/runtime/tailwind/engine/sanitize-stylesheet.js +8 -0
  139. package/dist/runtime/tailwind/engine/setup-tailwind.d.ts +23 -0
  140. package/dist/runtime/tailwind/engine/setup-tailwind.js +98 -0
  141. package/dist/runtime/tailwind/engine/stylesheets.d.ts +4 -0
  142. package/dist/runtime/tailwind/engine/stylesheets.js +1756 -0
  143. package/dist/runtime/tailwind/engine/types.d.ts +25 -0
  144. package/dist/runtime/tailwind/engine/types.js +0 -0
  145. package/dist/runtime/tailwind/errors.d.ts +7 -0
  146. package/dist/runtime/tailwind/errors.js +9 -0
  147. package/dist/runtime/tailwind/inline-utils.d.ts +19 -0
  148. package/dist/runtime/tailwind/inline-utils.js +24 -0
  149. package/dist/runtime/tailwind/nested.d.ts +59 -0
  150. package/dist/runtime/tailwind/nested.js +47 -0
  151. package/dist/runtime/tailwind/post-render.d.ts +7 -0
  152. package/dist/runtime/tailwind/post-render.js +156 -0
  153. package/dist/runtime/template-registry/errors.d.ts +5 -0
  154. package/dist/runtime/template-registry/errors.js +11 -0
  155. package/dist/runtime/template-registry/registry.d.ts +13 -0
  156. package/dist/runtime/testing/index.d.ts +13 -0
  157. package/dist/runtime/testing/index.js +2 -0
  158. package/dist/types.d.mts +5 -0
  159. package/package.json +122 -0
@@ -0,0 +1,358 @@
1
+ import {
2
+ generate,
3
+ List,
4
+ parse,
5
+ walk
6
+ } from "css-tree";
7
+ function rgbNode(r, g, b, alpha) {
8
+ const children = new List();
9
+ children.appendData({
10
+ type: "Number",
11
+ value: r.toFixed(0)
12
+ });
13
+ children.appendData({
14
+ type: "Operator",
15
+ value: ","
16
+ });
17
+ children.appendData({
18
+ type: "Number",
19
+ value: g.toFixed(0)
20
+ });
21
+ children.appendData({
22
+ type: "Operator",
23
+ value: ","
24
+ });
25
+ children.appendData({
26
+ type: "Number",
27
+ value: b.toFixed(0)
28
+ });
29
+ if (alpha !== 1 && alpha !== void 0) {
30
+ children.appendData({
31
+ type: "Operator",
32
+ value: ","
33
+ });
34
+ children.appendData({
35
+ type: "Number",
36
+ value: alpha.toString()
37
+ });
38
+ }
39
+ return {
40
+ type: "Function",
41
+ name: "rgb",
42
+ children
43
+ };
44
+ }
45
+ const LAB_TO_LMS = {
46
+ l: [0.3963377773761749, 0.2158037573099136],
47
+ m: [-0.1055613458156586, -0.0638541728258133],
48
+ s: [-0.0894841775298119, -1.2914855480194092]
49
+ };
50
+ const LSM_TO_RGB = {
51
+ r: [4.076741636075958, -3.307711539258063, 0.2309699031821043],
52
+ g: [-1.2684379732850315, 2.609757349287688, -0.341319376002657],
53
+ b: [-0.0041960761386756, -0.7034186179359362, 1.7076146940746117]
54
+ };
55
+ function lrgbToRgb(input) {
56
+ const absoluteNumber = Math.abs(input);
57
+ const sign = input < 0 ? -1 : 1;
58
+ if (absoluteNumber > 31308e-7) {
59
+ return sign * (absoluteNumber ** (1 / 2.4) * 1.055 - 0.055);
60
+ }
61
+ return input * 12.92;
62
+ }
63
+ function clamp(value, min, max) {
64
+ return Math.min(Math.max(value, min), max);
65
+ }
66
+ function oklchToOklab(oklch) {
67
+ return {
68
+ l: oklch.l,
69
+ a: oklch.c * Math.cos(oklch.h / 180 * Math.PI),
70
+ b: oklch.c * Math.sin(oklch.h / 180 * Math.PI)
71
+ };
72
+ }
73
+ function oklchToRgb(oklch) {
74
+ const oklab = oklchToOklab(oklch);
75
+ const l = (oklab.l + LAB_TO_LMS.l[0] * oklab.a + LAB_TO_LMS.l[1] * oklab.b) ** 3;
76
+ const m = (oklab.l + LAB_TO_LMS.m[0] * oklab.a + LAB_TO_LMS.m[1] * oklab.b) ** 3;
77
+ const s = (oklab.l + LAB_TO_LMS.s[0] * oklab.a + LAB_TO_LMS.s[1] * oklab.b) ** 3;
78
+ const r = 255 * lrgbToRgb(
79
+ LSM_TO_RGB.r[0] * l + LSM_TO_RGB.r[1] * m + LSM_TO_RGB.r[2] * s
80
+ );
81
+ const g = 255 * lrgbToRgb(
82
+ LSM_TO_RGB.g[0] * l + LSM_TO_RGB.g[1] * m + LSM_TO_RGB.g[2] * s
83
+ );
84
+ const b = 255 * lrgbToRgb(
85
+ LSM_TO_RGB.b[0] * l + LSM_TO_RGB.b[1] * m + LSM_TO_RGB.b[2] * s
86
+ );
87
+ return {
88
+ r: clamp(r, 0, 255),
89
+ g: clamp(g, 0, 255),
90
+ b: clamp(b, 0, 255)
91
+ };
92
+ }
93
+ function separteShorthandDeclaration(shorthandToReplace, [start, end]) {
94
+ shorthandToReplace.property = start;
95
+ const values = shorthandToReplace.value.type === "Value" ? shorthandToReplace.value.children.toArray().filter(
96
+ (child) => child.type !== "Operator" && child.type !== "WhiteSpace"
97
+ ) : [shorthandToReplace.value];
98
+ let endValue = shorthandToReplace.value;
99
+ if (values.length === 2) {
100
+ endValue = {
101
+ type: "Value",
102
+ children: new List().fromArray([values[1]])
103
+ };
104
+ shorthandToReplace.value = {
105
+ type: "Value",
106
+ children: new List().fromArray([values[0]])
107
+ };
108
+ }
109
+ return {
110
+ type: "Declaration",
111
+ property: end,
112
+ value: endValue,
113
+ important: shorthandToReplace.important
114
+ };
115
+ }
116
+ export function sanitizeDeclarations(nodeContainingDeclarations) {
117
+ walk(nodeContainingDeclarations, {
118
+ visit: "Declaration",
119
+ enter(declaration, item, list) {
120
+ if (declaration.value.type === "Raw") {
121
+ declaration.value = parse(declaration.value.value, {
122
+ context: "value"
123
+ });
124
+ }
125
+ if (/border-(?:[a-z]+-){0,2}radius\s*:\s*calc\s*\(\s*infinity\s*\*\s*1px\s*\)/i.test(
126
+ generate(declaration)
127
+ )) {
128
+ declaration.value = parse("9999px", { context: "value" });
129
+ }
130
+ walk(declaration, {
131
+ visit: "Function",
132
+ enter(func, funcParentListItem) {
133
+ const children = func.children.toArray();
134
+ if (func.name === "oklch") {
135
+ let l;
136
+ let c;
137
+ let h;
138
+ let a;
139
+ for (const child of children) {
140
+ if (child.type === "Number") {
141
+ if (l === void 0) {
142
+ l = Number.parseFloat(child.value);
143
+ continue;
144
+ }
145
+ if (c === void 0) {
146
+ c = Number.parseFloat(child.value);
147
+ continue;
148
+ }
149
+ if (h === void 0) {
150
+ h = Number.parseFloat(child.value);
151
+ continue;
152
+ }
153
+ if (a === void 0) {
154
+ a = Number.parseFloat(child.value);
155
+ continue;
156
+ }
157
+ }
158
+ if (child.type === "Dimension" && child.unit === "deg") {
159
+ if (h === void 0) {
160
+ h = Number.parseFloat(child.value);
161
+ continue;
162
+ }
163
+ }
164
+ if (child.type === "Percentage") {
165
+ if (l === void 0) {
166
+ l = Number.parseFloat(child.value) / 100;
167
+ continue;
168
+ }
169
+ if (a === void 0) {
170
+ a = Number.parseFloat(child.value) / 100;
171
+ }
172
+ }
173
+ }
174
+ if (l === void 0 || c === void 0 || h === void 0) {
175
+ throw new Error(
176
+ "Could not determine the parameters of an oklch() function.",
177
+ {
178
+ cause: declaration
179
+ }
180
+ );
181
+ }
182
+ const rgb = oklchToRgb({
183
+ l,
184
+ c,
185
+ h
186
+ });
187
+ funcParentListItem.data = rgbNode(rgb.r, rgb.g, rgb.b, a);
188
+ }
189
+ if (func.name === "rgb" || func.name === "rgba") {
190
+ let r;
191
+ let g;
192
+ let b;
193
+ let a;
194
+ for (const child of children) {
195
+ if (child.type === "Number") {
196
+ if (r === void 0) {
197
+ r = Number.parseFloat(child.value);
198
+ continue;
199
+ }
200
+ if (g === void 0) {
201
+ g = Number.parseFloat(child.value);
202
+ continue;
203
+ }
204
+ if (b === void 0) {
205
+ b = Number.parseFloat(child.value);
206
+ continue;
207
+ }
208
+ if (a === void 0) {
209
+ a = Number.parseFloat(child.value);
210
+ continue;
211
+ }
212
+ }
213
+ if (child.type === "Percentage") {
214
+ if (r === void 0) {
215
+ r = Number.parseFloat(child.value) * 255 / 100;
216
+ continue;
217
+ }
218
+ if (g === void 0) {
219
+ g = Number.parseFloat(child.value) * 255 / 100;
220
+ continue;
221
+ }
222
+ if (b === void 0) {
223
+ b = Number.parseFloat(child.value) * 255 / 100;
224
+ continue;
225
+ }
226
+ if (a === void 0) {
227
+ a = Number.parseFloat(child.value) / 100;
228
+ }
229
+ }
230
+ }
231
+ if (r === void 0 || g === void 0 || b === void 0) {
232
+ throw new Error(
233
+ "Could not determine the parameters of an rgb() function.",
234
+ {
235
+ cause: declaration
236
+ }
237
+ );
238
+ }
239
+ if (a === void 0 || a === 1) {
240
+ funcParentListItem.data = rgbNode(r, g, b);
241
+ } else {
242
+ funcParentListItem.data = rgbNode(r, g, b, a);
243
+ }
244
+ }
245
+ }
246
+ });
247
+ walk(declaration, {
248
+ visit: "Hash",
249
+ enter(hash, hashParentListItem) {
250
+ const hex = hash.value.trim();
251
+ if (hex.length === 3) {
252
+ const r2 = Number.parseInt(hex.charAt(0) + hex.charAt(0), 16);
253
+ const g2 = Number.parseInt(hex.charAt(1) + hex.charAt(1), 16);
254
+ const b2 = Number.parseInt(hex.charAt(2) + hex.charAt(2), 16);
255
+ hashParentListItem.data = rgbNode(r2, g2, b2);
256
+ return;
257
+ }
258
+ if (hex.length === 4) {
259
+ const r2 = Number.parseInt(hex.charAt(0) + hex.charAt(0), 16);
260
+ const g2 = Number.parseInt(hex.charAt(1) + hex.charAt(1), 16);
261
+ const b2 = Number.parseInt(hex.charAt(2) + hex.charAt(2), 16);
262
+ const a2 = Number.parseInt(hex.charAt(3) + hex.charAt(3), 16) / 255;
263
+ hashParentListItem.data = rgbNode(r2, g2, b2, a2);
264
+ return;
265
+ }
266
+ if (hex.length === 5) {
267
+ const r2 = Number.parseInt(hex.slice(0, 2), 16);
268
+ const g2 = Number.parseInt(hex.charAt(2) + hex.charAt(2), 16);
269
+ const b2 = Number.parseInt(hex.charAt(3) + hex.charAt(3), 16);
270
+ const a2 = Number.parseInt(hex.charAt(4) + hex.charAt(4), 16) / 255;
271
+ hashParentListItem.data = rgbNode(r2, g2, b2, a2);
272
+ return;
273
+ }
274
+ if (hex.length === 6) {
275
+ const r2 = Number.parseInt(hex.slice(0, 2), 16);
276
+ const g2 = Number.parseInt(hex.slice(2, 4), 16);
277
+ const b2 = Number.parseInt(hex.slice(4, 6), 16);
278
+ hashParentListItem.data = rgbNode(r2, g2, b2);
279
+ return;
280
+ }
281
+ if (hex.length === 7) {
282
+ const r2 = Number.parseInt(hex.slice(0, 2), 16);
283
+ const g2 = Number.parseInt(hex.slice(2, 4), 16);
284
+ const b2 = Number.parseInt(hex.slice(4, 6), 16);
285
+ const a2 = Number.parseInt(hex.charAt(6) + hex.charAt(6), 16) / 255;
286
+ hashParentListItem.data = rgbNode(r2, g2, b2, a2);
287
+ return;
288
+ }
289
+ const r = Number.parseInt(hex.slice(0, 2), 16);
290
+ const g = Number.parseInt(hex.slice(2, 4), 16);
291
+ const b = Number.parseInt(hex.slice(4, 6), 16);
292
+ const a = Number.parseInt(hex.slice(6, 8), 16) / 255;
293
+ hashParentListItem.data = rgbNode(r, g, b, a);
294
+ }
295
+ });
296
+ walk(declaration, {
297
+ visit: "Function",
298
+ enter(func, parentListItem) {
299
+ if (func.name === "color-mix") {
300
+ const children = func.children.toArray();
301
+ const color = children[3];
302
+ const opacity = children[4];
303
+ if (func.children.last?.type === "Identifier" && func.children.last.name === "transparent" && color?.type === "Function" && color?.name === "rgb" && opacity) {
304
+ if (opacity.type === "Percentage") {
305
+ const alpha = Number.parseFloat(opacity.value) / 100;
306
+ if (alpha < 1) {
307
+ color.children.appendData({
308
+ type: "Operator",
309
+ value: ","
310
+ });
311
+ color.children.appendData({
312
+ type: "Number",
313
+ value: alpha.toString()
314
+ });
315
+ }
316
+ } else {
317
+ color.children.appendData({
318
+ type: "Operator",
319
+ value: ","
320
+ });
321
+ color.children.appendData(opacity);
322
+ }
323
+ parentListItem.data = color;
324
+ }
325
+ }
326
+ }
327
+ });
328
+ if (declaration.property === "padding-inline") {
329
+ const paddingRight = separteShorthandDeclaration(declaration, [
330
+ "padding-left",
331
+ "padding-right"
332
+ ]);
333
+ list.insertData(paddingRight, item);
334
+ }
335
+ if (declaration.property === "padding-block") {
336
+ const paddingBottom = separteShorthandDeclaration(declaration, [
337
+ "padding-top",
338
+ "padding-bottom"
339
+ ]);
340
+ list.insertData(paddingBottom, item);
341
+ }
342
+ if (declaration.property === "margin-inline") {
343
+ const marginRight = separteShorthandDeclaration(declaration, [
344
+ "margin-left",
345
+ "margin-right"
346
+ ]);
347
+ list.insertData(marginRight, item);
348
+ }
349
+ if (declaration.property === "margin-block") {
350
+ const paddingBottom = separteShorthandDeclaration(declaration, [
351
+ "margin-top",
352
+ "margin-bottom"
353
+ ]);
354
+ list.insertData(paddingBottom, item);
355
+ }
356
+ }
357
+ });
358
+ }
@@ -0,0 +1,17 @@
1
+ import { type CssNode } from 'css-tree';
2
+ /**
3
+ * This function goes through a few steps to ensure the best email client support and
4
+ * to ensure that media queries and pseudo classes are applied correctly alongside
5
+ * the inline styles.
6
+ *
7
+ * What it does:
8
+ * 1. Converts all declarations in all rules into important ones
9
+ * 2. Sanitizes class selectors of all non-inlinable rules
10
+ * 3. Removes --tw-* custom property declarations — by this point all CSS
11
+ * variables have been resolved, so these are dead weight in email HTML.
12
+ * 4. Strips empty-fallback var(--tw-*,) refs that Tailwind v4 emits for
13
+ * variant-stacking idioms (filter, font-variant-numeric, etc.) — email
14
+ * clients can't resolve CSS custom properties reliably, so any --tw-*
15
+ * left as a bare empty-fallback ref would reach the client broken.
16
+ */
17
+ export declare function sanitizeNonInlinableRules(node: CssNode): void;
@@ -0,0 +1,30 @@
1
+ import { string, walk } from "css-tree";
2
+ import { sanitizeClassName } from "../compatibility/sanitize-class-name.js";
3
+ import { isRuleInlinable } from "./is-rule-inlinable.js";
4
+ import { stripEmptyTailwindVars } from "./strip-empty-tailwind-vars.js";
5
+ export function sanitizeNonInlinableRules(node) {
6
+ walk(node, {
7
+ visit: "Rule",
8
+ enter(rule) {
9
+ if (!isRuleInlinable(rule)) {
10
+ walk(rule.prelude, (node2) => {
11
+ if (node2.type === "ClassSelector") {
12
+ const unescapedClassName = string.decode(node2.name);
13
+ node2.name = sanitizeClassName(unescapedClassName);
14
+ }
15
+ });
16
+ walk(rule, {
17
+ visit: "Declaration",
18
+ enter(declaration, item, list) {
19
+ if (declaration.property.startsWith("--tw-")) {
20
+ list.remove(item);
21
+ return;
22
+ }
23
+ declaration.important = true;
24
+ stripEmptyTailwindVars(declaration.value);
25
+ }
26
+ });
27
+ }
28
+ }
29
+ });
30
+ }
@@ -0,0 +1,12 @@
1
+ import { type Rule } from 'css-tree';
2
+ /**
3
+ * Split a rule into inlinable and non-inlinable parts. Caller must only pass rules
4
+ * for which isRuleInlinable(rule) is false. Returns clones so the original stylesheet is never mutated.
5
+ *
6
+ * @returns inlinablePart: rule with only inlinable block children, or null if none.
7
+ * nonInlinablePart: rule with only non-inlinable block children, or null if none.
8
+ */
9
+ export declare function splitMixedRule(rule: Rule): {
10
+ inlinablePart: Rule | null;
11
+ nonInlinablePart: Rule | null;
12
+ };
@@ -0,0 +1,37 @@
1
+ import { clone, find, List } from "css-tree";
2
+ import { isPartInlinable } from "./is-part-inlinable.js";
3
+ export function splitMixedRule(rule) {
4
+ const selectorHasPseudo = rule.prelude !== null && find(
5
+ rule.prelude,
6
+ (node) => node.type === "PseudoClassSelector" || node.type === "PseudoElementSelector"
7
+ ) !== null;
8
+ if (selectorHasPseudo) {
9
+ return { inlinablePart: null, nonInlinablePart: clone(rule) };
10
+ }
11
+ const ruleCloneInlinable = clone(rule);
12
+ const ruleCloneNonInlinable = clone(rule);
13
+ const inlinableParts = [];
14
+ const nonInlinableParts = [];
15
+ for (const part of ruleCloneInlinable.block.children.toArray()) {
16
+ if (isPartInlinable(part)) {
17
+ inlinableParts.push(part);
18
+ } else {
19
+ nonInlinableParts.push(part);
20
+ }
21
+ }
22
+ const inlinablePart = inlinableParts.length > 0 ? {
23
+ ...ruleCloneInlinable,
24
+ block: {
25
+ type: "Block",
26
+ children: new List().fromArray(inlinableParts)
27
+ }
28
+ } : null;
29
+ const nonInlinablePart = nonInlinableParts.length > 0 ? {
30
+ ...ruleCloneNonInlinable,
31
+ block: {
32
+ type: "Block",
33
+ children: new List().fromArray(nonInlinableParts)
34
+ }
35
+ } : null;
36
+ return { inlinablePart, nonInlinablePart };
37
+ }
@@ -0,0 +1,19 @@
1
+ import { type CssNode } from 'css-tree';
2
+ /**
3
+ * Tailwind v4 emits variant-stacking idioms like
4
+ * font-variant-numeric: var(--tw-ordinal,) var(--tw-slashed-zero,) tabular-nums var(--tw-numeric-fraction,)
5
+ * filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-invert,) ...
6
+ * where each var() has an empty fallback so missing variants collapse to nothing.
7
+ * Tailwind deliberately leaves these variant vars undefined until used, so they
8
+ * stay in the output here and produce unresolvable custom properties in email HTML
9
+ * (no email client supports CSS custom properties reliably). Per the CSS spec
10
+ * (https://www.w3.org/TR/css-variables-1/#using-variables) an empty fallback means
11
+ * "use empty string if the variable is undefined", which is exactly what we want.
12
+ *
13
+ * Scoped to the `--tw-` prefix so any user-authored empty-fallback var() refs
14
+ * are left untouched.
15
+ *
16
+ * Uses post-order traversal so an outer var(--tw-X, var(--tw-Y,)) collapses
17
+ * correctly after the inner var() has been removed.
18
+ */
19
+ export declare function stripEmptyTailwindVars(node: CssNode): void;
@@ -0,0 +1,44 @@
1
+ import { generate, walk } from "css-tree";
2
+ export function stripEmptyTailwindVars(node) {
3
+ walk(node, {
4
+ visit: "Function",
5
+ leave(func, funcItem, funcList) {
6
+ if (func.name !== "var") {
7
+ return;
8
+ }
9
+ let variableName;
10
+ walk(func, {
11
+ visit: "Identifier",
12
+ enter(identifier) {
13
+ variableName = identifier.name;
14
+ return this.break;
15
+ }
16
+ });
17
+ if (!variableName?.startsWith("--tw-")) {
18
+ return;
19
+ }
20
+ let sawComma = false;
21
+ let hasFallbackContent = false;
22
+ func.children.forEach((child) => {
23
+ if (!sawComma) {
24
+ if (child.type === "Operator" && child.value === ",") {
25
+ sawComma = true;
26
+ }
27
+ return;
28
+ }
29
+ let childValue = generate(child).trim();
30
+ if (child.type === "Raw") {
31
+ const emptyTailwindVarPattern = /var\(--tw-[^,()]+,\s*\)/g;
32
+ childValue = childValue.replaceAll(emptyTailwindVarPattern, "").trim();
33
+ }
34
+ if (childValue.length > 0) {
35
+ hasFallbackContent = true;
36
+ }
37
+ });
38
+ if (!sawComma || hasFallbackContent) {
39
+ return;
40
+ }
41
+ funcList.remove(funcItem);
42
+ }
43
+ });
44
+ }
@@ -0,0 +1,2 @@
1
+ import type { Raw, Value } from 'css-tree';
2
+ export declare function unwrapValue(value: Value | Raw): import("css-tree").CssNode;
@@ -0,0 +1,6 @@
1
+ export function unwrapValue(value) {
2
+ if (value.type === "Value" && value.children.size === 1) {
3
+ return value.children.first ?? value;
4
+ }
5
+ return value;
6
+ }
@@ -0,0 +1,63 @@
1
+ import type { TailwindEngineOptions } from './types.js';
2
+ /**
3
+ * A single element's inline styles as ordered kebab-case CSS declarations
4
+ * (`cssProperty -> value`). Insertion order matches React Email's object-spread
5
+ * serialization order; `Map.set` semantics (keep first position, overwrite
6
+ * value) mirror plain-object key assignment, so a consumer can replicate
7
+ * `{ ...twStyle, ...authorStyle }` author-wins merging exactly.
8
+ */
9
+ export type InlineStyleMap = Map<string, string>;
10
+ export interface ComputedStyles {
11
+ /**
12
+ * Per-class inline styles. Only classes that produced at least one inlinable
13
+ * declaration appear here. Keyed by the ORIGINAL (unsanitized) class name.
14
+ */
15
+ inlinable: Map<string, InlineStyleMap>;
16
+ /**
17
+ * The `<style>` body to inject into the first `<head>`: media-query and
18
+ * pseudo-class rules, unnested and downleveled for email clients, with class
19
+ * selectors sanitized. Empty string when there are no such rules.
20
+ */
21
+ nonInlinableCss: string;
22
+ /**
23
+ * Classes that must REMAIN on the element, mapped ORIGINAL -> OUTPUT:
24
+ * - a non-inlinable class maps to its sanitized selector name
25
+ * (matching the selectors emitted in {@link nonInlinableCss});
26
+ * - an unknown class (no Tailwind rule at all) maps to itself.
27
+ * A class that only produced inlinable styles is absent — the consumer drops
28
+ * it from the `class` attribute. Mirrors React Email's residual-class logic in
29
+ * `clone-element-with-inlined-styles.ts`.
30
+ */
31
+ residualClassMap: Map<string, string>;
32
+ /**
33
+ * Original (unsanitized) names of every class that produced a non-inlinable
34
+ * rule, in stylesheet-emission order — the exact list React Email interpolates
35
+ * into its no-`<head>` error (`Array.from(nonInlinableRules.keys())`,
36
+ * tailwind.tsx). This order (breakpoint/variant emission order) differs from the
37
+ * authored class order, so it cannot be reconstructed from {@link residualClassMap}
38
+ * and must be carried canonically.
39
+ */
40
+ nonInlinableClassNames: string[];
41
+ }
42
+ export interface TailwindEngine {
43
+ /**
44
+ * Compute inline styles, injectable CSS, and residual classes for the given
45
+ * set of class names (collected across the whole `<Tailwind>` subtree).
46
+ *
47
+ * Should be called once per engine with the full class list, matching React
48
+ * Email's one-setup-per-`<Tailwind>` model. The underlying compiler only
49
+ * accumulates candidates, and each call re-parses a fresh stylesheet AST, so
50
+ * repeated calls never cross-contaminate — but a call only "sees" classes in
51
+ * its own argument.
52
+ */
53
+ computeStyles: (classNames: string[]) => ComputedStyles;
54
+ }
55
+ /**
56
+ * Framework-neutral Tailwind engine. Mirrors the CSS pipeline of React Email's
57
+ * `<Tailwind>` component (`tailwind.tsx`) without any view-layer coupling: a
58
+ * consumer collects the class names used in a rendered email, calls
59
+ * {@link TailwindEngine.computeStyles}, then applies the result to the HTML.
60
+ */
61
+ export declare function createTailwindEngine(options?: TailwindEngineOptions): Promise<TailwindEngine>;
62
+ export { pixelBasedPreset } from './pixel-based-preset.js';
63
+ export type { TailwindConfig, TailwindEngineOptions } from './types.js';
@@ -0,0 +1,53 @@
1
+ import { generate, List } from "css-tree";
2
+ import { downlevelForEmailClients } from "./css/downlevel-for-email-clients.js";
3
+ import { extractRulesPerClass } from "./css/extract-rules-per-class.js";
4
+ import { getCustomProperties } from "./css/get-custom-properties.js";
5
+ import { makeInlineStylesFor } from "./css/make-inline-styles-for.js";
6
+ import { sanitizeClassName } from "./compatibility/sanitize-class-name.js";
7
+ import { sanitizeNonInlinableRules } from "./css/sanitize-non-inlinable-rules.js";
8
+ import { sanitizeStyleSheet } from "./sanitize-stylesheet.js";
9
+ import { setupTailwind } from "./setup-tailwind.js";
10
+ export async function createTailwindEngine(options = {}) {
11
+ const { config, theme, utility } = options;
12
+ const tailwindSetup = await setupTailwind({
13
+ config,
14
+ cssConfigs: { theme, utility }
15
+ });
16
+ const computeStyles = (classNames) => {
17
+ tailwindSetup.addUtilities(classNames);
18
+ const styleSheet = tailwindSetup.getStyleSheet();
19
+ sanitizeStyleSheet(styleSheet);
20
+ const { inlinable: inlinableRules, nonInlinable: nonInlinableRules } = extractRulesPerClass(styleSheet, classNames);
21
+ const customProperties = getCustomProperties(styleSheet);
22
+ const nonInlineStyles = {
23
+ type: "StyleSheet",
24
+ children: new List().fromArray(
25
+ Array.from(nonInlinableRules.values()).flat()
26
+ )
27
+ };
28
+ sanitizeNonInlinableRules(nonInlineStyles);
29
+ downlevelForEmailClients(nonInlineStyles);
30
+ const nonInlinableCss = nonInlinableRules.size > 0 ? generate(nonInlineStyles) : "";
31
+ const inlinable = /* @__PURE__ */ new Map();
32
+ for (const [className, rules] of inlinableRules) {
33
+ inlinable.set(className, makeInlineStylesFor(rules, customProperties));
34
+ }
35
+ const residualClassMap = /* @__PURE__ */ new Map();
36
+ for (const className of classNames) {
37
+ if (residualClassMap.has(className)) continue;
38
+ if (nonInlinableRules.has(className)) {
39
+ residualClassMap.set(className, sanitizeClassName(className));
40
+ } else if (!inlinableRules.has(className)) {
41
+ residualClassMap.set(className, className);
42
+ }
43
+ }
44
+ return {
45
+ inlinable,
46
+ nonInlinableCss,
47
+ residualClassMap,
48
+ nonInlinableClassNames: Array.from(nonInlinableRules.keys())
49
+ };
50
+ };
51
+ return { computeStyles };
52
+ }
53
+ export { pixelBasedPreset } from "./pixel-based-preset.js";
@@ -0,0 +1,9 @@
1
+ import type { TailwindConfig } from './types.js';
2
+ /**
3
+ * A Tailwind config preset that redefines the default `rem`-based `fontSize` and
4
+ * `spacing` scales in pixels, since many email clients handle `px` more
5
+ * predictably than `rem`.
6
+ *
7
+ * Direct port of React Email's `pixelBasedPreset`.
8
+ */
9
+ export declare const pixelBasedPreset: TailwindConfig;