@maizzle/framework 6.0.0-14 → 6.0.0-15

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maizzle/framework",
3
- "version": "6.0.0-14",
3
+ "version": "6.0.0-15",
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",
@@ -71,6 +71,7 @@
71
71
  "ora": "^8.1.0",
72
72
  "pathe": "^2.0.0",
73
73
  "postcss": "^8.4.49",
74
+ "postcss-calc": "^10.1.1",
74
75
  "postcss-custom-properties": "^14.0.6",
75
76
  "postcss-safe-parser": "^7.0.0",
76
77
  "postcss-sort-media-queries": "^5.2.0",
@@ -65,6 +65,10 @@ async function processCss(css, config) {
65
65
  * PostCSS pipeline. Plugins defined and added here
66
66
  * will apply to all `<style>` tags in the HTML,
67
67
  * unless marked to be excluded.
68
+ *
69
+ * @param {string} css CSS content to process
70
+ * @param {Object} config Maizzle configuration object
71
+ * @returns {Promise<string>} Processed CSS string
68
72
  */
69
73
  let resolveCSSProps = get(config, 'css.resolveProps')
70
74
  if (resolveCSSProps !== false) {
@@ -91,7 +95,7 @@ async function processCss(css, config) {
91
95
  ].filter(Boolean)).process(css, merge(
92
96
  get(config, 'postcss.options', {}),
93
97
  {
94
- from: config.cwd || './',
98
+ from: get(config, 'cwd', './'),
95
99
  parser: postcssSafeParser
96
100
  }
97
101
  ))
@@ -107,10 +111,10 @@ async function processCss(css, config) {
107
111
  try {
108
112
  const { code } = transform(
109
113
  merge(
110
- lightningCssOptions,
111
114
  {
112
115
  code: Buffer.from(result.css)
113
- }
116
+ },
117
+ lightningCssOptions,
114
118
  )
115
119
  )
116
120
 
@@ -2,6 +2,7 @@ import juice from 'juice'
2
2
  import postcss from 'postcss'
3
3
  import get from 'lodash-es/get.js'
4
4
  import has from 'lodash-es/has.js'
5
+ import postcssCalc from 'postcss-calc'
5
6
  import * as cheerio from 'cheerio/slim'
6
7
  import remove from 'lodash-es/remove.js'
7
8
  import { render } from 'posthtml-render'
@@ -10,6 +11,7 @@ import { match } from 'posthtml/lib/api.js'
10
11
  import safeParser from 'postcss-safe-parser'
11
12
  import isObject from 'lodash-es/isObject.js'
12
13
  import { parser as parse } from 'posthtml-parser'
14
+ import customProperties from 'postcss-custom-properties'
13
15
  import { useAttributeSizes } from './useAttributeSizes.js'
14
16
  import { getPosthtmlOptions } from '../posthtml/defaultConfig.js'
15
17
 
@@ -134,6 +136,7 @@ export async function inline(html = '', options = {}) {
134
136
 
135
137
  const preservedAtRules = get(options, 'preservedAtRules', ['media'])
136
138
  const selectors = new Set()
139
+ const rootSelectorCss = new Set()
137
140
 
138
141
  inlined_tree.match({ tag: 'style' }, node => {
139
142
  // If this is an embedded style tag, exit early
@@ -177,6 +180,10 @@ export async function inline(html = '', options = {}) {
177
180
  // Create a set of selectors
178
181
  const { selector } = rule
179
182
 
183
+ if (selector.includes(':root')) {
184
+ rootSelectorCss.add(rule.toString())
185
+ }
186
+
180
187
  // Add the selector to the set as long as it's not a pseudo selector
181
188
  if (!/.+[^\\\s]::?\w+/.test(selector)) {
182
189
  selectors.add({
@@ -189,7 +196,6 @@ export async function inline(html = '', options = {}) {
189
196
  options.safelist.add(selector)
190
197
  }
191
198
 
192
-
193
199
  if (options.removeInlinedSelectors) {
194
200
  // Remove the rule in the <style> tag as long as it's not a preserved class
195
201
  if (!options.safelist.has(selector) && !combinedRegex.test(selector)) {
@@ -288,6 +294,46 @@ export async function inline(html = '', options = {}) {
288
294
  } catch { }
289
295
  })
290
296
 
297
+ /**
298
+ * Find all elements with non-empty `style` attributes and
299
+ * process their values with PostCSS.
300
+ *
301
+ * We do this in order to compile CSS variables and calc()
302
+ * functions that may have been inlined by Juice.
303
+ */
304
+ for (const el of $('[style]')) {
305
+ const styleAttr = $(el).attr('style')
306
+ if (!styleAttr || styleAttr.trim() === '') {
307
+ continue
308
+ }
309
+
310
+ const processedCss = postcss([
311
+ customProperties({ preserve: false }),
312
+ postcssCalc(),
313
+ {
314
+ postcssPlugin: 'remove-root-selectors',
315
+ Rule(rule) {
316
+ // Split comma-separated selectors and filter out :root
317
+ const selectors = rule.selector.split(',').map(s => s.trim());
318
+ const filteredSelectors = selectors.filter(s => !s.startsWith(':root'));
319
+
320
+ if (filteredSelectors.length === 0) {
321
+ // Remove the entire rule if all selectors were :root
322
+ rule.remove();
323
+ } else if (filteredSelectors.length < selectors.length) {
324
+ // Update the selector if some (but not all) were :root
325
+ rule.selector = filteredSelectors.join(', ');
326
+ }
327
+ }
328
+ }
329
+ ]).process(`${[...rootSelectorCss].join('\n')} ${styleAttr}`, {
330
+ from: undefined,
331
+ parser: safeParser,
332
+ }).css
333
+
334
+ $(el).attr('style', processedCss.trim())
335
+ }
336
+
291
337
  const optimized_tree = parse($.html(), posthtmlOptions)
292
338
  optimized_tree.match = match
293
339
 
package/types/config.d.ts CHANGED
@@ -242,6 +242,24 @@ export default interface Config {
242
242
  * ```
243
243
  */
244
244
  combineMediaQueries?: PostCSSSortMediaQueriesOptions;
245
+
246
+ /**
247
+ * `replaceCssProperties` Transformer.
248
+ *
249
+ * Define a mapping object of which CSS properties to replace with what strings.
250
+ *
251
+ * @default {'text-decoration-line': 'text-decoration'}
252
+ *
253
+ * @example
254
+ * ```
255
+ * export default {
256
+ * css: {
257
+ * replaceCssProperties: {
258
+ * 'text-decoration-line': 'text-decoration',
259
+ * 'margin': 'Margin',
260
+ * }
261
+ */
262
+ replaceCssProperties?: Record<string, string>;
245
263
  }
246
264
 
247
265
  /**
@@ -215,4 +215,22 @@ export default interface InlineCSSConfig {
215
215
  * ```
216
216
  */
217
217
  safelist?: string[];
218
+
219
+ /**
220
+ * Preserved CSS at-rules.
221
+ *
222
+ * These will not be removed as part of the CSS inlining process.
223
+ *
224
+ * @default ['media']
225
+ *
226
+ * @example
227
+ * ```
228
+ * export default {
229
+ * css: {
230
+ * preservedAtRules: ['media', 'supports'],
231
+ * }
232
+ * }
233
+ * ```
234
+ */
235
+ preservedAtRules?: string[];
218
236
  }