better-svelte-email 1.0.3 → 1.1.0-beta.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.
- package/README.md +1 -1
- package/dist/render/index.js +7 -6
- package/dist/render/utils/css/extract-rules-per-class.d.ts +2 -2
- package/dist/render/utils/css/extract-rules-per-class.js +13 -24
- package/dist/render/utils/css/get-custom-properties.d.ts +2 -2
- package/dist/render/utils/css/get-custom-properties.js +16 -31
- package/dist/render/utils/css/is-rule-inlinable.d.ts +1 -1
- package/dist/render/utils/css/is-rule-inlinable.js +30 -4
- package/dist/render/utils/css/make-inline-styles-for.d.ts +2 -2
- package/dist/render/utils/css/make-inline-styles-for.js +38 -41
- package/dist/render/utils/css/resolve-all-css-variables.d.ts +3 -3
- package/dist/render/utils/css/resolve-all-css-variables.js +107 -95
- package/dist/render/utils/css/resolve-calc-expressions.d.ts +2 -5
- package/dist/render/utils/css/resolve-calc-expressions.js +155 -118
- package/dist/render/utils/css/sanitize-declarations.d.ts +2 -2
- package/dist/render/utils/css/sanitize-declarations.js +226 -282
- package/dist/render/utils/css/sanitize-non-inlinable-rules.d.ts +2 -2
- package/dist/render/utils/css/sanitize-non-inlinable-rules.js +14 -19
- package/dist/render/utils/css/sanitize-stylesheet.d.ts +2 -2
- package/dist/render/utils/css/sanitize-stylesheet.js +4 -4
- package/dist/render/utils/tailwindcss/add-inlined-styles-to-element.d.ts +1 -1
- package/dist/render/utils/tailwindcss/setup-tailwind.d.ts +2 -2
- package/dist/render/utils/tailwindcss/setup-tailwind.js +3 -3
- package/package.json +5 -4
- package/dist/render/utils/css/unwrap-value.d.ts +0 -2
- package/dist/render/utils/css/unwrap-value.js +0 -6
|
@@ -1,42 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
const children = new List();
|
|
4
|
-
children.appendData({
|
|
5
|
-
type: 'Number',
|
|
6
|
-
value: r.toFixed(0)
|
|
7
|
-
});
|
|
8
|
-
children.appendData({
|
|
9
|
-
type: 'Operator',
|
|
10
|
-
value: ','
|
|
11
|
-
});
|
|
12
|
-
children.appendData({
|
|
13
|
-
type: 'Number',
|
|
14
|
-
value: g.toFixed(0)
|
|
15
|
-
});
|
|
16
|
-
children.appendData({
|
|
17
|
-
type: 'Operator',
|
|
18
|
-
value: ','
|
|
19
|
-
});
|
|
20
|
-
children.appendData({
|
|
21
|
-
type: 'Number',
|
|
22
|
-
value: b.toFixed(0)
|
|
23
|
-
});
|
|
24
|
-
if (alpha !== 1 && alpha !== undefined) {
|
|
25
|
-
children.appendData({
|
|
26
|
-
type: 'Operator',
|
|
27
|
-
value: ','
|
|
28
|
-
});
|
|
29
|
-
children.appendData({
|
|
30
|
-
type: 'Number',
|
|
31
|
-
value: alpha.toString()
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
return {
|
|
35
|
-
type: 'Function',
|
|
36
|
-
name: 'rgb',
|
|
37
|
-
children
|
|
38
|
-
};
|
|
39
|
-
}
|
|
1
|
+
import valueParser, {} from 'postcss-value-parser';
|
|
2
|
+
// Color conversion constants
|
|
40
3
|
const LAB_TO_LMS = {
|
|
41
4
|
l: [0.3963377773761749, 0.2158037573099136],
|
|
42
5
|
m: [-0.1055613458156586, -0.0638541728258133],
|
|
@@ -65,7 +28,7 @@ function oklchToOklab(oklch) {
|
|
|
65
28
|
b: oklch.c * Math.sin((oklch.h / 180) * Math.PI)
|
|
66
29
|
};
|
|
67
30
|
}
|
|
68
|
-
/** Convert
|
|
31
|
+
/** Convert oklch to RGB */
|
|
69
32
|
function oklchToRgb(oklch) {
|
|
70
33
|
const oklab = oklchToOklab(oklch);
|
|
71
34
|
const l = (oklab.l + LAB_TO_LMS.l[0] * oklab.a + LAB_TO_LMS.l[1] * oklab.b) ** 3;
|
|
@@ -80,31 +43,155 @@ function oklchToRgb(oklch) {
|
|
|
80
43
|
b: clamp(b, 0, 255)
|
|
81
44
|
};
|
|
82
45
|
}
|
|
83
|
-
function
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
46
|
+
function formatRgb(r, g, b, a) {
|
|
47
|
+
const rInt = Math.round(r);
|
|
48
|
+
const gInt = Math.round(g);
|
|
49
|
+
const bInt = Math.round(b);
|
|
50
|
+
if (a !== undefined && a !== 1) {
|
|
51
|
+
return `rgb(${rInt}, ${gInt}, ${bInt}, ${a})`;
|
|
52
|
+
}
|
|
53
|
+
return `rgb(${rInt}, ${gInt}, ${bInt})`;
|
|
54
|
+
}
|
|
55
|
+
function hexToRgb(hex) {
|
|
56
|
+
hex = hex.replace('#', '');
|
|
57
|
+
if (hex.length === 3) {
|
|
58
|
+
return {
|
|
59
|
+
r: parseInt(hex[0] + hex[0], 16),
|
|
60
|
+
g: parseInt(hex[1] + hex[1], 16),
|
|
61
|
+
b: parseInt(hex[2] + hex[2], 16)
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (hex.length === 4) {
|
|
65
|
+
return {
|
|
66
|
+
r: parseInt(hex[0] + hex[0], 16),
|
|
67
|
+
g: parseInt(hex[1] + hex[1], 16),
|
|
68
|
+
b: parseInt(hex[2] + hex[2], 16),
|
|
69
|
+
a: parseInt(hex[3] + hex[3], 16) / 255
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (hex.length === 5) {
|
|
73
|
+
return {
|
|
74
|
+
r: parseInt(hex.slice(0, 2), 16),
|
|
75
|
+
g: parseInt(hex[2] + hex[2], 16),
|
|
76
|
+
b: parseInt(hex[3] + hex[3], 16),
|
|
77
|
+
a: parseInt(hex[4] + hex[4], 16) / 255
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
if (hex.length === 6) {
|
|
81
|
+
return {
|
|
82
|
+
r: parseInt(hex.slice(0, 2), 16),
|
|
83
|
+
g: parseInt(hex.slice(2, 4), 16),
|
|
84
|
+
b: parseInt(hex.slice(4, 6), 16)
|
|
95
85
|
};
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
86
|
+
}
|
|
87
|
+
if (hex.length === 7) {
|
|
88
|
+
return {
|
|
89
|
+
r: parseInt(hex.slice(0, 2), 16),
|
|
90
|
+
g: parseInt(hex.slice(2, 4), 16),
|
|
91
|
+
b: parseInt(hex.slice(4, 6), 16),
|
|
92
|
+
a: parseInt(hex[6] + hex[6], 16) / 255
|
|
99
93
|
};
|
|
100
94
|
}
|
|
95
|
+
// 8 character hex
|
|
101
96
|
return {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
97
|
+
r: parseInt(hex.slice(0, 2), 16),
|
|
98
|
+
g: parseInt(hex.slice(2, 4), 16),
|
|
99
|
+
b: parseInt(hex.slice(4, 6), 16),
|
|
100
|
+
a: parseInt(hex.slice(6, 8), 16) / 255
|
|
106
101
|
};
|
|
107
102
|
}
|
|
103
|
+
function parseOklchValues(nodes) {
|
|
104
|
+
const result = {};
|
|
105
|
+
for (const node of nodes) {
|
|
106
|
+
if (node.type === 'word') {
|
|
107
|
+
const numMatch = node.value.match(/^(-?[\d.]+)(%|deg)?$/i);
|
|
108
|
+
if (numMatch) {
|
|
109
|
+
const value = parseFloat(numMatch[1]);
|
|
110
|
+
const unit = numMatch[2]?.toLowerCase();
|
|
111
|
+
if (unit === '%') {
|
|
112
|
+
if (result.l === undefined) {
|
|
113
|
+
result.l = value / 100;
|
|
114
|
+
}
|
|
115
|
+
else if (result.a === undefined) {
|
|
116
|
+
result.a = value / 100;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (unit === 'deg') {
|
|
120
|
+
if (result.h === undefined) {
|
|
121
|
+
result.h = value;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
if (result.l === undefined) {
|
|
126
|
+
result.l = value;
|
|
127
|
+
}
|
|
128
|
+
else if (result.c === undefined) {
|
|
129
|
+
result.c = value;
|
|
130
|
+
}
|
|
131
|
+
else if (result.h === undefined) {
|
|
132
|
+
result.h = value;
|
|
133
|
+
}
|
|
134
|
+
else if (result.a === undefined) {
|
|
135
|
+
result.a = value;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
function parseRgbValues(nodes) {
|
|
144
|
+
const result = {};
|
|
145
|
+
for (const node of nodes) {
|
|
146
|
+
if (node.type === 'word') {
|
|
147
|
+
const numMatch = node.value.match(/^(-?[\d.]+)(%)?$/);
|
|
148
|
+
if (numMatch) {
|
|
149
|
+
const value = parseFloat(numMatch[1]);
|
|
150
|
+
const isPercent = numMatch[2] === '%';
|
|
151
|
+
if (result.r === undefined) {
|
|
152
|
+
result.r = isPercent ? (value * 255) / 100 : value;
|
|
153
|
+
}
|
|
154
|
+
else if (result.g === undefined) {
|
|
155
|
+
result.g = isPercent ? (value * 255) / 100 : value;
|
|
156
|
+
}
|
|
157
|
+
else if (result.b === undefined) {
|
|
158
|
+
result.b = isPercent ? (value * 255) / 100 : value;
|
|
159
|
+
}
|
|
160
|
+
else if (result.a === undefined) {
|
|
161
|
+
result.a = isPercent ? value / 100 : value;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return result;
|
|
167
|
+
}
|
|
168
|
+
function transformColorMix(node) {
|
|
169
|
+
// We're expecting the structure to be something like:
|
|
170
|
+
// color-mix(in oklab, rgb(...) X%, transparent)
|
|
171
|
+
// Check if it ends with transparent
|
|
172
|
+
const lastNode = node.nodes[node.nodes.length - 1];
|
|
173
|
+
if (lastNode?.type !== 'word' || lastNode.value !== 'transparent') {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
// Find the rgb function and percentage
|
|
177
|
+
let rgbFunc = null;
|
|
178
|
+
let percentage = null;
|
|
179
|
+
for (const child of node.nodes) {
|
|
180
|
+
if (child.type === 'function' && child.value === 'rgb') {
|
|
181
|
+
rgbFunc = child;
|
|
182
|
+
}
|
|
183
|
+
if (child.type === 'word' && child.value.endsWith('%')) {
|
|
184
|
+
percentage = parseFloat(child.value) / 100;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (rgbFunc && percentage !== null) {
|
|
188
|
+
const rgbValues = parseRgbValues(rgbFunc.nodes);
|
|
189
|
+
if (rgbValues.r !== undefined && rgbValues.g !== undefined && rgbValues.b !== undefined) {
|
|
190
|
+
return formatRgb(rgbValues.r, rgbValues.g, rgbValues.b, percentage);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
108
195
|
/**
|
|
109
196
|
* Meant to do all the things necessary, in a per-declaration basis, to have the best email client
|
|
110
197
|
* support possible.
|
|
@@ -118,237 +205,94 @@ function separteShorthandDeclaration(shorthandToReplace, [start, end]) {
|
|
|
118
205
|
* - convert `margin-inline` into `margin-left` and `margin-right`;
|
|
119
206
|
* - convert `margin-block` into `margin-top` and `margin-bottom`.
|
|
120
207
|
*/
|
|
121
|
-
export function sanitizeDeclarations(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (child.type === 'Percentage') {
|
|
168
|
-
if (l === undefined) {
|
|
169
|
-
l = Number.parseFloat(child.value) / 100;
|
|
170
|
-
continue;
|
|
171
|
-
}
|
|
172
|
-
if (a === undefined) {
|
|
173
|
-
a = Number.parseFloat(child.value) / 100;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
if (l === undefined || c === undefined || h === undefined) {
|
|
178
|
-
throw new Error('Could not determine the parameters of an oklch() function.', {
|
|
179
|
-
cause: declaration
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
const rgb = oklchToRgb({
|
|
183
|
-
l,
|
|
184
|
-
c,
|
|
185
|
-
h
|
|
208
|
+
export function sanitizeDeclarations(root) {
|
|
209
|
+
root.walkDecls((decl) => {
|
|
210
|
+
// Handle infinity calc for border-radius
|
|
211
|
+
if (decl.prop === 'border-radius' && /calc\s*\(\s*infinity\s*\*\s*1px\s*\)/i.test(decl.value)) {
|
|
212
|
+
decl.value = '9999px';
|
|
213
|
+
}
|
|
214
|
+
// Handle shorthand properties
|
|
215
|
+
if (decl.prop === 'padding-inline') {
|
|
216
|
+
const values = decl.value.split(/\s+/).filter(Boolean);
|
|
217
|
+
decl.prop = 'padding-left';
|
|
218
|
+
decl.value = values[0];
|
|
219
|
+
decl.cloneAfter({ prop: 'padding-right', value: values[1] || values[0] });
|
|
220
|
+
}
|
|
221
|
+
if (decl.prop === 'padding-block') {
|
|
222
|
+
const values = decl.value.split(/\s+/).filter(Boolean);
|
|
223
|
+
decl.prop = 'padding-top';
|
|
224
|
+
decl.value = values[0];
|
|
225
|
+
decl.cloneAfter({ prop: 'padding-bottom', value: values[1] || values[0] });
|
|
226
|
+
}
|
|
227
|
+
if (decl.prop === 'margin-inline') {
|
|
228
|
+
const values = decl.value.split(/\s+/).filter(Boolean);
|
|
229
|
+
decl.prop = 'margin-left';
|
|
230
|
+
decl.value = values[0];
|
|
231
|
+
decl.cloneAfter({ prop: 'margin-right', value: values[1] || values[0] });
|
|
232
|
+
}
|
|
233
|
+
if (decl.prop === 'margin-block') {
|
|
234
|
+
const values = decl.value.split(/\s+/).filter(Boolean);
|
|
235
|
+
decl.prop = 'margin-top';
|
|
236
|
+
decl.value = values[0];
|
|
237
|
+
decl.cloneAfter({ prop: 'margin-bottom', value: values[1] || values[0] });
|
|
238
|
+
}
|
|
239
|
+
// Parse and transform color values
|
|
240
|
+
if (decl.value.includes('oklch(') ||
|
|
241
|
+
decl.value.includes('rgb(') ||
|
|
242
|
+
decl.value.includes('#') ||
|
|
243
|
+
decl.value.includes('color-mix(')) {
|
|
244
|
+
const parsed = valueParser(decl.value);
|
|
245
|
+
parsed.walk((node) => {
|
|
246
|
+
// Convert oklch to rgb
|
|
247
|
+
if (node.type === 'function' && node.value === 'oklch') {
|
|
248
|
+
const oklchValues = parseOklchValues(node.nodes);
|
|
249
|
+
if (oklchValues.l === undefined ||
|
|
250
|
+
oklchValues.c === undefined ||
|
|
251
|
+
oklchValues.h === undefined) {
|
|
252
|
+
throw new Error('Could not determine the parameters of an oklch() function.', {
|
|
253
|
+
cause: decl
|
|
186
254
|
});
|
|
187
|
-
funcParentListItem.data = rgbNode(rgb.r, rgb.g, rgb.b, a);
|
|
188
|
-
}
|
|
189
|
-
if (func.name === 'rgb') {
|
|
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 === undefined) {
|
|
197
|
-
r = Number.parseFloat(child.value);
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
200
|
-
if (g === undefined) {
|
|
201
|
-
g = Number.parseFloat(child.value);
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
if (b === undefined) {
|
|
205
|
-
b = Number.parseFloat(child.value);
|
|
206
|
-
continue;
|
|
207
|
-
}
|
|
208
|
-
if (a === undefined) {
|
|
209
|
-
a = Number.parseFloat(child.value);
|
|
210
|
-
continue;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
if (child.type === 'Percentage') {
|
|
214
|
-
if (r === undefined) {
|
|
215
|
-
r = (Number.parseFloat(child.value) * 255) / 100;
|
|
216
|
-
continue;
|
|
217
|
-
}
|
|
218
|
-
if (g === undefined) {
|
|
219
|
-
g = (Number.parseFloat(child.value) * 255) / 100;
|
|
220
|
-
continue;
|
|
221
|
-
}
|
|
222
|
-
if (b === undefined) {
|
|
223
|
-
b = (Number.parseFloat(child.value) * 255) / 100;
|
|
224
|
-
continue;
|
|
225
|
-
}
|
|
226
|
-
if (a === undefined) {
|
|
227
|
-
a = Number.parseFloat(child.value) / 100;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
if (r === undefined || g === undefined || b === undefined) {
|
|
232
|
-
throw new Error('Could not determine the parameters of an rgb() function.', {
|
|
233
|
-
cause: declaration
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
if (a === undefined || a === 1) {
|
|
237
|
-
funcParentListItem.data = rgbNode(r, g, b);
|
|
238
|
-
}
|
|
239
|
-
else {
|
|
240
|
-
funcParentListItem.data = rgbNode(r, g, b, a);
|
|
241
|
-
}
|
|
242
255
|
}
|
|
256
|
+
const rgb = oklchToRgb({
|
|
257
|
+
l: oklchValues.l,
|
|
258
|
+
c: oklchValues.c,
|
|
259
|
+
h: oklchValues.h
|
|
260
|
+
});
|
|
261
|
+
// Transform function node to word node
|
|
262
|
+
node.type = 'word';
|
|
263
|
+
node.value = formatRgb(rgb.r, rgb.g, rgb.b, oklchValues.a);
|
|
264
|
+
node.nodes = [];
|
|
243
265
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
const g = Number.parseInt(hex.charAt(1) + hex.charAt(1), 16);
|
|
252
|
-
const b = Number.parseInt(hex.charAt(2) + hex.charAt(2), 16);
|
|
253
|
-
hashParentListItem.data = rgbNode(r, g, b);
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
if (hex.length === 4) {
|
|
257
|
-
const r = Number.parseInt(hex.charAt(0) + hex.charAt(0), 16);
|
|
258
|
-
const g = Number.parseInt(hex.charAt(1) + hex.charAt(1), 16);
|
|
259
|
-
const b = Number.parseInt(hex.charAt(2) + hex.charAt(2), 16);
|
|
260
|
-
const a = Number.parseInt(hex.charAt(3) + hex.charAt(3), 16) / 255;
|
|
261
|
-
hashParentListItem.data = rgbNode(r, g, b, a);
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
if (hex.length === 5) {
|
|
265
|
-
const r = Number.parseInt(hex.slice(0, 2), 16);
|
|
266
|
-
const g = Number.parseInt(hex.charAt(2) + hex.charAt(2), 16);
|
|
267
|
-
const b = Number.parseInt(hex.charAt(3) + hex.charAt(3), 16);
|
|
268
|
-
const a = Number.parseInt(hex.charAt(4) + hex.charAt(4), 16) / 255;
|
|
269
|
-
hashParentListItem.data = rgbNode(r, g, b, a);
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
if (hex.length === 6) {
|
|
273
|
-
const r = Number.parseInt(hex.slice(0, 2), 16);
|
|
274
|
-
const g = Number.parseInt(hex.slice(2, 4), 16);
|
|
275
|
-
const b = Number.parseInt(hex.slice(4, 6), 16);
|
|
276
|
-
hashParentListItem.data = rgbNode(r, g, b);
|
|
277
|
-
return;
|
|
278
|
-
}
|
|
279
|
-
if (hex.length === 7) {
|
|
280
|
-
const r = Number.parseInt(hex.slice(0, 2), 16);
|
|
281
|
-
const g = Number.parseInt(hex.slice(2, 4), 16);
|
|
282
|
-
const b = Number.parseInt(hex.slice(4, 6), 16);
|
|
283
|
-
const a = Number.parseInt(hex.charAt(6) + hex.charAt(6), 16) / 255;
|
|
284
|
-
hashParentListItem.data = rgbNode(r, g, b, a);
|
|
285
|
-
return;
|
|
266
|
+
// Convert space-based rgb to comma-based
|
|
267
|
+
if (node.type === 'function' && node.value === 'rgb') {
|
|
268
|
+
const rgbValues = parseRgbValues(node.nodes);
|
|
269
|
+
if (rgbValues.r === undefined || rgbValues.g === undefined || rgbValues.b === undefined) {
|
|
270
|
+
throw new Error('Could not determine the parameters of an rgb() function.', {
|
|
271
|
+
cause: decl
|
|
272
|
+
});
|
|
286
273
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
hashParentListItem.data = rgbNode(r, g, b, a);
|
|
274
|
+
// Transform function node to word node
|
|
275
|
+
node.type = 'word';
|
|
276
|
+
node.value = formatRgb(rgbValues.r, rgbValues.g, rgbValues.b, rgbValues.a);
|
|
277
|
+
node.nodes = [];
|
|
292
278
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
// Identifier (oklab)
|
|
302
|
-
// Operator (,)
|
|
303
|
-
// FunctionNode (rgb(...))
|
|
304
|
-
// Node (opacity)
|
|
305
|
-
// Operator (,)
|
|
306
|
-
// Identifier (transparent)
|
|
307
|
-
const color = children[3];
|
|
308
|
-
const opacity = children[4];
|
|
309
|
-
if (func.children.last?.type === 'Identifier' &&
|
|
310
|
-
func.children.last.name === 'transparent' &&
|
|
311
|
-
color?.type === 'Function' &&
|
|
312
|
-
color?.name === 'rgb' &&
|
|
313
|
-
opacity) {
|
|
314
|
-
color.children.appendData({
|
|
315
|
-
type: 'Operator',
|
|
316
|
-
value: ','
|
|
317
|
-
});
|
|
318
|
-
color.children.appendData(opacity);
|
|
319
|
-
parentListItem.data = color;
|
|
320
|
-
}
|
|
279
|
+
// Handle color-mix with transparent
|
|
280
|
+
if (node.type === 'function' && node.value === 'color-mix') {
|
|
281
|
+
const result = transformColorMix(node);
|
|
282
|
+
if (result) {
|
|
283
|
+
// Transform function node to word node
|
|
284
|
+
node.type = 'word';
|
|
285
|
+
node.value = result;
|
|
286
|
+
node.nodes = [];
|
|
321
287
|
}
|
|
322
288
|
}
|
|
289
|
+
// Convert hex to rgb
|
|
290
|
+
if (node.type === 'word' && node.value.startsWith('#')) {
|
|
291
|
+
const rgb = hexToRgb(node.value);
|
|
292
|
+
node.value = formatRgb(rgb.r, rgb.g, rgb.b, rgb.a);
|
|
293
|
+
}
|
|
323
294
|
});
|
|
324
|
-
|
|
325
|
-
const paddingRight = separteShorthandDeclaration(declaration, [
|
|
326
|
-
'padding-left',
|
|
327
|
-
'padding-right'
|
|
328
|
-
]);
|
|
329
|
-
list.insertData(paddingRight, item);
|
|
330
|
-
}
|
|
331
|
-
if (declaration.property === 'padding-block') {
|
|
332
|
-
const paddingBottom = separteShorthandDeclaration(declaration, [
|
|
333
|
-
'padding-top',
|
|
334
|
-
'padding-bottom'
|
|
335
|
-
]);
|
|
336
|
-
list.insertData(paddingBottom, item);
|
|
337
|
-
}
|
|
338
|
-
if (declaration.property === 'margin-inline') {
|
|
339
|
-
const marginRight = separteShorthandDeclaration(declaration, [
|
|
340
|
-
'margin-left',
|
|
341
|
-
'margin-right'
|
|
342
|
-
]);
|
|
343
|
-
list.insertData(marginRight, item);
|
|
344
|
-
}
|
|
345
|
-
if (declaration.property === 'margin-block') {
|
|
346
|
-
const paddingBottom = separteShorthandDeclaration(declaration, [
|
|
347
|
-
'margin-top',
|
|
348
|
-
'margin-bottom'
|
|
349
|
-
]);
|
|
350
|
-
list.insertData(paddingBottom, item);
|
|
351
|
-
}
|
|
295
|
+
decl.value = valueParser.stringify(parsed.nodes);
|
|
352
296
|
}
|
|
353
297
|
});
|
|
354
298
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Root } from 'postcss';
|
|
2
2
|
/**
|
|
3
3
|
* This function goes through a few steps to ensure the best email client support and
|
|
4
4
|
* to ensure that media queries and pseudo classes are applied correctly alongside
|
|
@@ -8,4 +8,4 @@ import { type CssNode } from 'css-tree';
|
|
|
8
8
|
* 1. Converts all declarations in all rules into important ones
|
|
9
9
|
* 2. Sanitizes class selectors of all non-inlinable rules
|
|
10
10
|
*/
|
|
11
|
-
export declare function sanitizeNonInlinableRules(
|
|
11
|
+
export declare function sanitizeNonInlinableRules(root: Root): void;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { string, walk } from 'css-tree';
|
|
2
1
|
import { sanitizeClassName } from '../compatibility/sanitize-class-name.js';
|
|
3
2
|
import { isRuleInlinable } from './is-rule-inlinable.js';
|
|
4
3
|
/**
|
|
@@ -10,24 +9,20 @@ import { isRuleInlinable } from './is-rule-inlinable.js';
|
|
|
10
9
|
* 1. Converts all declarations in all rules into important ones
|
|
11
10
|
* 2. Sanitizes class selectors of all non-inlinable rules
|
|
12
11
|
*/
|
|
13
|
-
export function sanitizeNonInlinableRules(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
declaration.important = true;
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
}
|
|
12
|
+
export function sanitizeNonInlinableRules(root) {
|
|
13
|
+
root.walkRules((rule) => {
|
|
14
|
+
if (!isRuleInlinable(rule)) {
|
|
15
|
+
// Sanitize class names in selector
|
|
16
|
+
// The regex matches class names including escaped characters (like \: or \/)
|
|
17
|
+
// Note: \\. must come FIRST in the alternation to properly match escapes
|
|
18
|
+
rule.selector = rule.selector.replace(/\.((?:\\.|[^\s.:>+~[#,])+)/g, (match, className) => {
|
|
19
|
+
const unescaped = className.replace(/\\(.)/g, '$1');
|
|
20
|
+
return '.' + sanitizeClassName(unescaped);
|
|
21
|
+
});
|
|
22
|
+
// Make all declarations important
|
|
23
|
+
rule.walkDecls((decl) => {
|
|
24
|
+
decl.important = true;
|
|
25
|
+
});
|
|
31
26
|
}
|
|
32
27
|
});
|
|
33
28
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function sanitizeStyleSheet(
|
|
1
|
+
import type { Root } from 'postcss';
|
|
2
|
+
export declare function sanitizeStyleSheet(root: Root): void;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { resolveAllCssVariables } from './resolve-all-css-variables.js';
|
|
2
2
|
import { resolveCalcExpressions } from './resolve-calc-expressions.js';
|
|
3
3
|
import { sanitizeDeclarations } from './sanitize-declarations.js';
|
|
4
|
-
export function sanitizeStyleSheet(
|
|
5
|
-
resolveAllCssVariables(
|
|
6
|
-
resolveCalcExpressions(
|
|
7
|
-
sanitizeDeclarations(
|
|
4
|
+
export function sanitizeStyleSheet(root) {
|
|
5
|
+
resolveAllCssVariables(root);
|
|
6
|
+
resolveCalcExpressions(root);
|
|
7
|
+
sanitizeDeclarations(root);
|
|
8
8
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Rule } from '
|
|
1
|
+
import type { Rule } from 'postcss';
|
|
2
2
|
import type { CustomProperties } from '../css/get-custom-properties.js';
|
|
3
3
|
import type { AST } from '../../index.js';
|
|
4
4
|
export declare function addInlinedStylesToElement(element: AST.Element, inlinableRules: Map<string, Rule>, nonInlinableRules: Map<string, Rule>, customProperties: CustomProperties, unknownClasses: string[]): AST.Element;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type Root } from 'postcss';
|
|
2
2
|
import type { TailwindConfig } from '../../index.js';
|
|
3
3
|
export type TailwindSetup = Awaited<ReturnType<typeof setupTailwind>>;
|
|
4
4
|
export declare function setupTailwind(config: TailwindConfig): Promise<{
|
|
5
5
|
addUtilities: (candidates: string[]) => void;
|
|
6
|
-
getStyleSheet: () =>
|
|
6
|
+
getStyleSheet: () => Root;
|
|
7
7
|
}>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import postcss, {} from 'postcss';
|
|
2
2
|
import { compile } from 'tailwindcss';
|
|
3
3
|
import indexCss from './tailwind-stylesheets/index.js';
|
|
4
4
|
import preflightCss from './tailwind-stylesheets/preflight.js';
|
|
@@ -60,8 +60,8 @@ export async function setupTailwind(config) {
|
|
|
60
60
|
addUtilities: function addUtilities(candidates) {
|
|
61
61
|
css = compiler.build(candidates);
|
|
62
62
|
},
|
|
63
|
-
getStyleSheet: function
|
|
64
|
-
return parse(css);
|
|
63
|
+
getStyleSheet: function getStyleSheet() {
|
|
64
|
+
return postcss.parse(css);
|
|
65
65
|
}
|
|
66
66
|
};
|
|
67
67
|
}
|