@maizzle/framework 5.3.1 → 5.4.0-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/package.json +2 -2
- package/src/transformers/inline.js +3 -87
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maizzle/framework",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.4.0-0",
|
|
4
4
|
"description": "Maizzle is a framework that helps you quickly build HTML emails with Tailwind CSS.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"html-crush": "^6.0.19",
|
|
64
64
|
"is-url-superb": "^6.1.0",
|
|
65
65
|
"istextorbinary": "^9.5.0",
|
|
66
|
-
"juice": "
|
|
66
|
+
"juice": "next",
|
|
67
67
|
"lodash-es": "^4.17.21",
|
|
68
68
|
"morphdom": "^2.7.4",
|
|
69
69
|
"ora": "^8.1.0",
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import juice from 'juice'
|
|
2
2
|
import postcss from 'postcss'
|
|
3
3
|
import get from 'lodash-es/get.js'
|
|
4
|
-
import has from 'lodash-es/has.js'
|
|
5
4
|
import * as cheerio from 'cheerio/slim'
|
|
6
|
-
import remove from 'lodash-es/remove.js'
|
|
7
5
|
import { render } from 'posthtml-render'
|
|
8
6
|
import isEmpty from 'lodash-es/isEmpty.js'
|
|
9
7
|
import safeParser from 'postcss-safe-parser'
|
|
@@ -29,26 +27,7 @@ export async function inline(html = '', options = {}) {
|
|
|
29
27
|
|
|
30
28
|
options.removeInlinedSelectors = get(options, 'removeInlinedSelectors', true)
|
|
31
29
|
options.preferUnitlessValues = get(options, 'preferUnitlessValues', true)
|
|
32
|
-
options.
|
|
33
|
-
...get(options, 'safelist', []),
|
|
34
|
-
...[
|
|
35
|
-
'.body', // Gmail
|
|
36
|
-
'.gmail', // Gmail
|
|
37
|
-
'.apple', // Apple Mail
|
|
38
|
-
'.ios', // Mail on iOS
|
|
39
|
-
'.ox-', // Open-Xchange
|
|
40
|
-
'.outlook', // Outlook.com
|
|
41
|
-
'[data-ogs', // Outlook.com
|
|
42
|
-
'.bloop_container', // Airmail
|
|
43
|
-
'.Singleton', // Apple Mail 10
|
|
44
|
-
'.unused', // Notes 8
|
|
45
|
-
'.moz-text-html', // Thunderbird
|
|
46
|
-
'.mail-detail-content', // Comcast, Libero webmail
|
|
47
|
-
'edo', // Edison (all)
|
|
48
|
-
'#msgBody', // Freenet uses #msgBody
|
|
49
|
-
'.lang' // Fenced code blocks
|
|
50
|
-
],
|
|
51
|
-
])
|
|
30
|
+
options.preservedSelectors = get(options, 'safelist', [])
|
|
52
31
|
|
|
53
32
|
juice.styleToAttribute = get(options, 'styleToAttribute', {})
|
|
54
33
|
juice.applyWidthAttributes = get(options, 'applyWidthAttributes', true)
|
|
@@ -86,7 +65,7 @@ export async function inline(html = '', options = {}) {
|
|
|
86
65
|
*/
|
|
87
66
|
$.root().html(
|
|
88
67
|
css
|
|
89
|
-
? juice
|
|
68
|
+
? juice($.html(), { extraCss: css, removeStyleTags, ...options })
|
|
90
69
|
: juice($.html(), { removeStyleTags, ...options })
|
|
91
70
|
)
|
|
92
71
|
|
|
@@ -110,9 +89,7 @@ export async function inline(html = '', options = {}) {
|
|
|
110
89
|
/**
|
|
111
90
|
* Remove inlined selectors from the HTML
|
|
112
91
|
*/
|
|
113
|
-
// For each style tag
|
|
114
92
|
$('style:not([embed])').each((_i, el) => {
|
|
115
|
-
// Parse the CSS
|
|
116
93
|
const { root } = postcss()
|
|
117
94
|
.process(
|
|
118
95
|
$(el).html(),
|
|
@@ -122,27 +99,9 @@ export async function inline(html = '', options = {}) {
|
|
|
122
99
|
}
|
|
123
100
|
)
|
|
124
101
|
|
|
125
|
-
// Precompile a single regex to match any substring from the preservedClasses set
|
|
126
|
-
const combinedPattern = Array.from(options.safelist)
|
|
127
|
-
.map(pattern => pattern.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')) // Escape special regex chars
|
|
128
|
-
.join('|') // Combine all patterns into a single regex pattern with 'OR' (|)
|
|
129
|
-
|
|
130
|
-
const combinedRegex = new RegExp(combinedPattern)
|
|
131
|
-
|
|
132
102
|
const selectors = new Set()
|
|
133
103
|
|
|
134
|
-
// Preserve selectors in at rules
|
|
135
|
-
root.walkAtRules(rule => {
|
|
136
|
-
if (['media', 'supports'].includes(rule.name)) {
|
|
137
|
-
rule.walkRules(rule => {
|
|
138
|
-
options.safelist.add(rule.selector)
|
|
139
|
-
})
|
|
140
|
-
}
|
|
141
|
-
})
|
|
142
|
-
|
|
143
|
-
// For each rule in the CSS block we're parsing
|
|
144
104
|
root.walkRules(rule => {
|
|
145
|
-
// Create a set of selectors
|
|
146
105
|
const { selector } = rule
|
|
147
106
|
|
|
148
107
|
// Add the selector to the set as long as it's not a pseudo selector
|
|
@@ -152,30 +111,11 @@ export async function inline(html = '', options = {}) {
|
|
|
152
111
|
prop: get(rule.nodes[0], 'prop')
|
|
153
112
|
})
|
|
154
113
|
}
|
|
155
|
-
// Preserve pseudo selectors
|
|
156
|
-
else {
|
|
157
|
-
options.safelist.add(selector)
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (options.removeInlinedSelectors) {
|
|
161
|
-
// Remove the rule in the <style> tag as long as it's not a preserved class
|
|
162
|
-
if (!options.safelist.has(selector) && !combinedRegex.test(selector)) {
|
|
163
|
-
rule.remove()
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Update the <style> tag contents
|
|
167
|
-
$(el).html(root.toString())
|
|
168
|
-
}
|
|
169
114
|
})
|
|
170
115
|
|
|
171
116
|
/**
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
* 1. `preferUnitlessValues` - Replace unit values with `0` where possible
|
|
175
|
-
* 2. `removeInlinedSelectors` - Remove inlined selectors from the HTML
|
|
117
|
+
* `preferUnitlessValues` - replace unit values with `0` where possible
|
|
176
118
|
*/
|
|
177
|
-
|
|
178
|
-
// Loop over selectors that we found in the <style> tags
|
|
179
119
|
selectors.forEach(({ name, prop }) => {
|
|
180
120
|
const elements = $(name).get()
|
|
181
121
|
|
|
@@ -187,7 +127,6 @@ export async function inline(html = '', options = {}) {
|
|
|
187
127
|
const styleAttr = $(el).attr('style')
|
|
188
128
|
const inlineStyles = {}
|
|
189
129
|
|
|
190
|
-
// 1. `preferUnitlessValues`
|
|
191
130
|
if (styleAttr) {
|
|
192
131
|
try {
|
|
193
132
|
const root = postcss.parse(`* { ${styleAttr} }`)
|
|
@@ -215,29 +154,6 @@ export async function inline(html = '', options = {}) {
|
|
|
215
154
|
)
|
|
216
155
|
} catch {}
|
|
217
156
|
}
|
|
218
|
-
|
|
219
|
-
// Get the classes from the element's class attribute
|
|
220
|
-
const classes = $(el).attr('class')
|
|
221
|
-
|
|
222
|
-
// 2. `removeInlinedSelectors`
|
|
223
|
-
if (options.removeInlinedSelectors && classes) {
|
|
224
|
-
const classList = classes.split(' ')
|
|
225
|
-
|
|
226
|
-
// If the class has been inlined in the style attribute...
|
|
227
|
-
if (has(inlineStyles, prop)) {
|
|
228
|
-
// Try to remove the classes that have been inlined
|
|
229
|
-
if (![...options.safelist].some(item => item.includes(name))) {
|
|
230
|
-
remove(classList, classToRemove => name.includes(classToRemove))
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// Update the class list on the element with the new classes
|
|
234
|
-
if (classList.length > 0) {
|
|
235
|
-
$(el).attr('class', classList.join(' '))
|
|
236
|
-
} else {
|
|
237
|
-
$(el).removeAttr('class')
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
157
|
})
|
|
242
158
|
}
|
|
243
159
|
})
|