@maizzle/framework 6.0.0-rc.7 → 6.0.0-rc.9

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 (76) hide show
  1. package/dist/_virtual/_rolldown/runtime.mjs +32 -0
  2. package/dist/build.mjs +2 -1
  3. package/dist/build.mjs.map +1 -1
  4. package/dist/components/Body.vue +105 -36
  5. package/dist/components/Button.vue +4 -1
  6. package/dist/components/CodeBlock.vue +1 -1
  7. package/dist/components/CodeInline.vue +6 -1
  8. package/dist/components/Column.vue +30 -5
  9. package/dist/components/Container.vue +10 -2
  10. package/dist/components/Divider.vue +28 -0
  11. package/dist/components/Head.vue +22 -0
  12. package/dist/components/Heading.vue +28 -0
  13. package/dist/components/Html.vue +98 -47
  14. package/dist/components/Layout.vue +93 -0
  15. package/dist/components/Link.vue +26 -0
  16. package/dist/components/Markdown.vue +22 -3
  17. package/dist/components/Outlook.vue +36 -0
  18. package/dist/components/Overlap.vue +25 -5
  19. package/dist/components/Preheader.vue +1 -1
  20. package/dist/components/Row.vue +16 -5
  21. package/dist/components/Section.vue +83 -0
  22. package/dist/components/Text.vue +29 -0
  23. package/dist/components/Vml.vue +165 -13
  24. package/dist/index.d.mts +2 -1
  25. package/dist/index.mjs +2 -1
  26. package/dist/node_modules/picomatch/index.mjs +13 -0
  27. package/dist/node_modules/picomatch/index.mjs.map +1 -0
  28. package/dist/node_modules/picomatch/lib/constants.mjs +174 -0
  29. package/dist/node_modules/picomatch/lib/constants.mjs.map +1 -0
  30. package/dist/node_modules/picomatch/lib/parse.mjs +1067 -0
  31. package/dist/node_modules/picomatch/lib/parse.mjs.map +1 -0
  32. package/dist/node_modules/picomatch/lib/picomatch.mjs +304 -0
  33. package/dist/node_modules/picomatch/lib/picomatch.mjs.map +1 -0
  34. package/dist/node_modules/picomatch/lib/scan.mjs +296 -0
  35. package/dist/node_modules/picomatch/lib/scan.mjs.map +1 -0
  36. package/dist/node_modules/picomatch/lib/utils.mjs +53 -0
  37. package/dist/node_modules/picomatch/lib/utils.mjs.map +1 -0
  38. package/dist/plugin.mjs +11 -7
  39. package/dist/plugin.mjs.map +1 -1
  40. package/dist/plugins/postcss/tailwindCleanup.d.mts.map +1 -1
  41. package/dist/plugins/postcss/tailwindCleanup.mjs +24 -2
  42. package/dist/plugins/postcss/tailwindCleanup.mjs.map +1 -1
  43. package/dist/render/createRenderer.d.mts +3 -0
  44. package/dist/render/createRenderer.d.mts.map +1 -1
  45. package/dist/render/createRenderer.mjs +26 -7
  46. package/dist/render/createRenderer.mjs.map +1 -1
  47. package/dist/render/index.mjs +2 -1
  48. package/dist/render/index.mjs.map +1 -1
  49. package/dist/serve.d.mts.map +1 -1
  50. package/dist/serve.mjs +13 -6
  51. package/dist/serve.mjs.map +1 -1
  52. package/dist/server/compatibility.mjs +15 -1
  53. package/dist/server/compatibility.mjs.map +1 -1
  54. package/dist/server/email.mjs +2 -1
  55. package/dist/server/email.mjs.map +1 -1
  56. package/dist/server/linter.d.mts +1 -2
  57. package/dist/server/linter.d.mts.map +1 -1
  58. package/dist/server/linter.mjs +60 -71
  59. package/dist/server/linter.mjs.map +1 -1
  60. package/dist/server/ui/App.vue +9 -9
  61. package/dist/server/ui/pages/Preview.vue +215 -150
  62. package/dist/transformers/index.d.mts +10 -9
  63. package/dist/transformers/index.d.mts.map +1 -1
  64. package/dist/transformers/index.mjs +12 -9
  65. package/dist/transformers/index.mjs.map +1 -1
  66. package/dist/transformers/inlineCSS.d.mts +1 -14
  67. package/dist/transformers/inlineCSS.d.mts.map +1 -1
  68. package/dist/transformers/inlineCSS.mjs +16 -34
  69. package/dist/transformers/inlineCSS.mjs.map +1 -1
  70. package/dist/transformers/sixHex.d.mts +16 -0
  71. package/dist/transformers/sixHex.d.mts.map +1 -0
  72. package/dist/transformers/sixHex.mjs +30 -0
  73. package/dist/transformers/sixHex.mjs.map +1 -0
  74. package/dist/types/config.d.mts +57 -28
  75. package/dist/types/config.d.mts.map +1 -1
  76. package/package.json +2 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/transformers/index.ts"],"sourcesContent":["import { parse, serialize } from '../utils/ast/index.ts'\nimport { inlineLink } from './inlineLink.ts'\nimport { tailwindcss } from './tailwindcss.ts'\nimport { safeClassNames } from './safeClassNames.ts'\nimport { attributeToStyle } from './attributeToStyle.ts'\nimport { inlineCSS } from './inlineCSS.ts'\nimport { removeAttributes } from './removeAttributes.ts'\nimport { shorthandCSS } from './shorthandCSS.ts'\nimport { addAttributes } from './addAttributes.ts'\nimport { filters } from './filters/index.ts'\nimport { base } from './base.ts'\nimport { entities } from './entities.ts'\nimport { urlQuery } from './urlQuery.ts'\nimport { purgeCSS } from './purgeCSS.ts'\nimport { replaceStrings } from './replaceStrings.ts'\nimport { format } from './format.ts'\nimport { minify } from './minify.ts'\nimport type { MaizzleConfig } from '../types/config.ts'\n\n/**\n * Run all Maizzle transformers on the rendered HTML.\n *\n * The HTML is parsed into a DOM once at the start and passed through all\n * DOM-based transformers as a shared `ChildNode[]`. After all DOM transformers\n * complete, the DOM is serialized back to a string exactly once.\n *\n * String-only transformers (those that rely on external tools that require a\n * raw HTML string) then run on the serialized output.\n *\n * Transformers run in a specific order:\n * 0. Inline link stylesheets — replace `<link rel=\"stylesheet\">` with `<style>` tags\n * 1. Tailwind CSS — compile CSS, lower syntax, optimize (cleanup + merge media queries)\n * 2. Safe class names\n * 3. Attribute to style\n * 4. CSS inliner\n * 5. Remove attributes\n * 6. Shorthand CSS\n * 7. Add attributes\n * 8. Filters\n * 9. Base URL\n * 10. URL query\n * 11. Purge CSS (serializes/parses internally around email-comb)\n * 12. Entities\n * + Vue-generated comments stripped here (on serialized string)\n * 13. Replace strings\n * 14. Prettify\n * 15. Minify\n */\nexport async function runTransformers(\n html: string,\n config: MaizzleConfig,\n filePath?: string,\n doctype?: string,\n): Promise<string> {\n // Parse once — all DOM transformers share this array\n let dom = parse(html)\n\n // 0. Inline <link> stylesheets\n dom = await inlineLink(dom, filePath)\n\n // 1. Tailwind CSS — always runs first\n dom = await tailwindcss(dom, config, filePath)\n\n // 2. Safe class names\n dom = safeClassNames(dom, config.css)\n\n // 3. Attribute to style\n dom = attributeToStyle(dom, config.css)\n\n // 4. CSS inliner (serializes/parses internally around juice)\n dom = inlineCSS(dom, config.css)\n\n // 5. Remove attributes\n dom = removeAttributes(dom, config.html?.attributes)\n\n // 6. Shorthand CSS\n dom = shorthandCSS(dom, config.css)\n\n // 7. Add attributes\n dom = addAttributes(dom, config.html?.attributes)\n\n // 8. Filters\n dom = filters(dom, config.filters)\n\n // 9. Base URL (serializes/parses internally for VML/MSO regex passes)\n dom = base(dom, config.url)\n\n // 10. URL query\n dom = urlQuery(dom, config.url)\n\n // 11. Purge CSS (serializes/parses internally around email-comb)\n dom = purgeCSS(dom, config.css)\n\n // 12. Entities\n dom = entities(dom, config.html?.decodeEntities)\n\n // Serialize once — remaining transformers operate on the HTML string\n const isXhtml = doctype ? /xhtml/i.test(doctype) : false\n let result = serialize(dom, { selfClosingTags: isXhtml })\n\n // Remove Vue-generated comments after serializing\n result = result\n .replaceAll('<!--[-->', '')\n .replaceAll('<!--]-->', '')\n .replaceAll('<!--teleport start anchor-->', '')\n .replaceAll('<!--teleport anchor-->', '')\n .replaceAll('<!--teleport start-->', '')\n .replaceAll('<!--teleport end-->', '')\n\n // 13. Replace strings\n result = replaceStrings(result, config)\n\n // 14. Format\n result = await format(result, config)\n\n // 15. Minify\n result = minify(result, config)\n\n // Strip self-closing slashes for HTML5 doctypes\n if (!isXhtml) {\n result = result.replace(/ \\/>/g, '>')\n }\n\n return result\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDA,eAAsB,gBACpB,MACA,QACA,UACA,SACiB;CAEjB,IAAI,MAAM,MAAM,KAAK;AAGrB,OAAM,MAAM,WAAW,KAAK,SAAS;AAGrC,OAAM,MAAM,YAAY,KAAK,QAAQ,SAAS;AAG9C,OAAM,eAAe,KAAK,OAAO,IAAI;AAGrC,OAAM,iBAAiB,KAAK,OAAO,IAAI;AAGvC,OAAM,UAAU,KAAK,OAAO,IAAI;AAGhC,OAAM,iBAAiB,KAAK,OAAO,MAAM,WAAW;AAGpD,OAAM,aAAa,KAAK,OAAO,IAAI;AAGnC,OAAM,cAAc,KAAK,OAAO,MAAM,WAAW;AAGjD,OAAM,QAAQ,KAAK,OAAO,QAAQ;AAGlC,OAAM,KAAK,KAAK,OAAO,IAAI;AAG3B,OAAM,SAAS,KAAK,OAAO,IAAI;AAG/B,OAAM,SAAS,KAAK,OAAO,IAAI;AAG/B,OAAM,SAAS,KAAK,OAAO,MAAM,eAAe;CAGhD,MAAM,UAAU,UAAU,SAAS,KAAK,QAAQ,GAAG;CACnD,IAAI,SAAS,UAAU,KAAK,EAAE,iBAAiB,SAAS,CAAC;AAGzD,UAAS,OACN,WAAW,YAAY,GAAG,CAC1B,WAAW,YAAY,GAAG,CAC1B,WAAW,gCAAgC,GAAG,CAC9C,WAAW,0BAA0B,GAAG,CACxC,WAAW,yBAAyB,GAAG,CACvC,WAAW,uBAAuB,GAAG;AAGxC,UAAS,eAAe,QAAQ,OAAO;AAGvC,UAAS,MAAM,OAAO,QAAQ,OAAO;AAGrC,UAAS,OAAO,QAAQ,OAAO;AAG/B,KAAI,CAAC,QACH,UAAS,OAAO,QAAQ,SAAS,IAAI;AAGvC,QAAO"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/transformers/index.ts"],"sourcesContent":["import { parse, serialize } from '../utils/ast/index.ts'\nimport { inlineLink } from './inlineLink.ts'\nimport { tailwindcss } from './tailwindcss.ts'\nimport { safeClassNames } from './safeClassNames.ts'\nimport { attributeToStyle } from './attributeToStyle.ts'\nimport { inlineCSS } from './inlineCSS.ts'\nimport { removeAttributes } from './removeAttributes.ts'\nimport { shorthandCSS } from './shorthandCSS.ts'\nimport { sixHex } from './sixHex.ts'\nimport { addAttributes } from './addAttributes.ts'\nimport { filters } from './filters/index.ts'\nimport { base } from './base.ts'\nimport { entities } from './entities.ts'\nimport { urlQuery } from './urlQuery.ts'\nimport { purgeCSS } from './purgeCSS.ts'\nimport { replaceStrings } from './replaceStrings.ts'\nimport { format } from './format.ts'\nimport { minify } from './minify.ts'\nimport type { MaizzleConfig } from '../types/config.ts'\n\n/**\n * Run all Maizzle transformers on the rendered HTML.\n *\n * The HTML is parsed into a DOM once at the start and passed through all\n * DOM-based transformers as a shared `ChildNode[]`. After all DOM transformers\n * complete, the DOM is serialized back to a string exactly once.\n *\n * String-only transformers (those that rely on external tools that require a\n * raw HTML string) then run on the serialized output.\n *\n * Transformers run in a specific order:\n * 0. Inline link stylesheets — replace `<link rel=\"stylesheet\">` with `<style>` tags\n * 1. Tailwind CSS — compile CSS, lower syntax, optimize (cleanup + merge media queries)\n * 2. Safe class names\n * 3. Attribute to style\n * 4. CSS inliner\n * 5. Remove attributes\n * 6. Shorthand CSS\n * 7. Six-digit HEX\n * 8. Add attributes\n * 9. Filters\n * 10. Base URL\n * 11. URL query\n * 12. Purge CSS (serializes/parses internally around email-comb)\n * 13. Entities\n * + Vue-generated comments stripped here (on serialized string)\n * 14. Replace strings\n * 15. Prettify\n * 16. Minify\n */\nexport async function runTransformers(\n html: string,\n config: MaizzleConfig,\n filePath?: string,\n doctype?: string,\n): Promise<string> {\n // Parse once — all DOM transformers share this array\n let dom = parse(html)\n\n // 0. Inline <link> stylesheets\n dom = await inlineLink(dom, filePath)\n\n // 1. Tailwind CSS — always runs first\n dom = await tailwindcss(dom, config, filePath)\n\n // 2. Safe class names\n dom = safeClassNames(dom, config.css)\n\n // 3. Attribute to style\n dom = attributeToStyle(dom, config.css)\n\n // 4. CSS inliner (serializes/parses internally around juice)\n dom = inlineCSS(dom, config.css)\n\n // 5. Remove attributes\n dom = removeAttributes(dom, config.html?.attributes)\n\n // 6. Shorthand CSS\n dom = shorthandCSS(dom, config.css)\n\n // 7. Six-digit HEX\n dom = sixHex(dom, config.css)\n\n // 8. Add attributes\n dom = addAttributes(dom, config.html?.attributes)\n\n // 9. Filters\n dom = filters(dom, config.filters)\n\n // 10. Base URL (serializes/parses internally for VML/MSO regex passes)\n dom = base(dom, config.url)\n\n // 11. URL query\n dom = urlQuery(dom, config.url)\n\n // 12. Purge CSS (serializes/parses internally around email-comb)\n dom = purgeCSS(dom, config.css)\n\n // 13. Entities\n dom = entities(dom, config.html?.decodeEntities)\n\n // Serialize once — remaining transformers operate on the HTML string\n const isXhtml = doctype ? /xhtml/i.test(doctype) : false\n let result = serialize(dom, { selfClosingTags: isXhtml })\n\n // Remove Vue-generated comments after serializing\n result = result\n .replaceAll('<!--[-->', '')\n .replaceAll('<!--]-->', '')\n .replaceAll('<!--teleport start anchor-->', '')\n .replaceAll('<!--teleport anchor-->', '')\n .replaceAll('<!--teleport start-->', '')\n .replaceAll('<!--teleport end-->', '')\n\n // 14. Replace strings\n result = replaceStrings(result, config)\n\n // 15. Format\n result = await format(result, config)\n\n // 16. Minify\n result = minify(result, config)\n\n // Strip self-closing slashes for HTML5 doctypes\n if (!isXhtml) {\n result = result.replace(/ \\/>/g, '>')\n }\n\n return result\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA,eAAsB,gBACpB,MACA,QACA,UACA,SACiB;CAEjB,IAAI,MAAM,MAAM,KAAK;AAGrB,OAAM,MAAM,WAAW,KAAK,SAAS;AAGrC,OAAM,MAAM,YAAY,KAAK,QAAQ,SAAS;AAG9C,OAAM,eAAe,KAAK,OAAO,IAAI;AAGrC,OAAM,iBAAiB,KAAK,OAAO,IAAI;AAGvC,OAAM,UAAU,KAAK,OAAO,IAAI;AAGhC,OAAM,iBAAiB,KAAK,OAAO,MAAM,WAAW;AAGpD,OAAM,aAAa,KAAK,OAAO,IAAI;AAGnC,OAAM,OAAO,KAAK,OAAO,IAAI;AAG7B,OAAM,cAAc,KAAK,OAAO,MAAM,WAAW;AAGjD,OAAM,QAAQ,KAAK,OAAO,QAAQ;AAGlC,OAAM,KAAK,KAAK,OAAO,IAAI;AAG3B,OAAM,SAAS,KAAK,OAAO,IAAI;AAG/B,OAAM,SAAS,KAAK,OAAO,IAAI;AAG/B,OAAM,SAAS,KAAK,OAAO,MAAM,eAAe;CAGhD,MAAM,UAAU,UAAU,SAAS,KAAK,QAAQ,GAAG;CACnD,IAAI,SAAS,UAAU,KAAK,EAAE,iBAAiB,SAAS,CAAC;AAGzD,UAAS,OACN,WAAW,YAAY,GAAG,CAC1B,WAAW,YAAY,GAAG,CAC1B,WAAW,gCAAgC,GAAG,CAC9C,WAAW,0BAA0B,GAAG,CACxC,WAAW,yBAAyB,GAAG,CACvC,WAAW,uBAAuB,GAAG;AAGxC,UAAS,eAAe,QAAQ,OAAO;AAGvC,UAAS,MAAM,OAAO,QAAQ,OAAO;AAGrC,UAAS,OAAO,QAAQ,OAAO;AAG/B,KAAI,CAAC,QACH,UAAS,OAAO,QAAQ,SAAS,IAAI;AAGvC,QAAO"}
@@ -9,20 +9,7 @@ import { ChildNode } from "domhandler";
9
9
  * This is important for email client compatibility (especially Outlook on Windows).
10
10
  *
11
11
  * Enabled when `css.inline` is set to `true` or an object with options.
12
- *
13
- * Options:
14
- * - removeStyleTags: Remove style tags after inlining (default: false)
15
- * - removeInlinedSelectors: Remove classes after they've been inlined (default: true)
16
- * - preferUnitlessValues: Convert 0px, 0em, etc. to 0 (default: true)
17
- * - safelist: Selectors that should not be removed after inlining
18
- * - styleToAttribute: Map CSS properties to HTML attributes (e.g., background-color -> bgcolor)
19
- * - applyWidthAttributes: Add width attributes based on inline CSS (default: true)
20
- * - applyHeightAttributes: Add height attributes based on inline CSS (default: true)
21
- * - widthElements: Elements that can receive width attributes (default: ['img', 'video'])
22
- * - heightElements: Elements that can receive height attributes (default: ['img', 'video'])
23
- * - excludedProperties: CSS properties to exclude from inlining
24
- * - codeBlocks: Fenced code blocks to ignore (default: { EJS: { start: '<%', end: '%>' }, HBS: { start: '{{', end: '}}' } })
25
- * - customCSS: Additional CSS to inline
12
+ * All Juice options are supported and passed through directly.
26
13
  */
27
14
  declare function inlineCSS(dom: ChildNode[], config?: CssConfig): ChildNode[];
28
15
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"inlineCSS.d.mts","names":[],"sources":["../../src/transformers/inlineCSS.ts"],"mappings":";;;;;;AA2CA;;;;;;;;;;;;;;;;;;;;iBAAgB,SAAA,CAAU,GAAA,EAAK,SAAA,IAAa,MAAA,GAAQ,SAAA,GAAiB,SAAA"}
1
+ {"version":3,"file":"inlineCSS.d.mts","names":[],"sources":["../../src/transformers/inlineCSS.ts"],"mappings":";;;;;;AAeA;;;;;;;iBAAgB,SAAA,CAAU,GAAA,EAAK,SAAA,IAAa,MAAA,GAAQ,SAAA,GAAiB,SAAA"}
@@ -12,32 +12,17 @@ import juice from "juice";
12
12
  * This is important for email client compatibility (especially Outlook on Windows).
13
13
  *
14
14
  * Enabled when `css.inline` is set to `true` or an object with options.
15
- *
16
- * Options:
17
- * - removeStyleTags: Remove style tags after inlining (default: false)
18
- * - removeInlinedSelectors: Remove classes after they've been inlined (default: true)
19
- * - preferUnitlessValues: Convert 0px, 0em, etc. to 0 (default: true)
20
- * - safelist: Selectors that should not be removed after inlining
21
- * - styleToAttribute: Map CSS properties to HTML attributes (e.g., background-color -> bgcolor)
22
- * - applyWidthAttributes: Add width attributes based on inline CSS (default: true)
23
- * - applyHeightAttributes: Add height attributes based on inline CSS (default: true)
24
- * - widthElements: Elements that can receive width attributes (default: ['img', 'video'])
25
- * - heightElements: Elements that can receive height attributes (default: ['img', 'video'])
26
- * - excludedProperties: CSS properties to exclude from inlining
27
- * - codeBlocks: Fenced code blocks to ignore (default: { EJS: { start: '<%', end: '%>' }, HBS: { start: '{{', end: '}}' } })
28
- * - customCSS: Additional CSS to inline
15
+ * All Juice options are supported and passed through directly.
29
16
  */
30
17
  function inlineCSS(dom, config = {}) {
31
18
  const inline = config.inline;
32
19
  if (!inline) return dom;
33
- const options = typeof inline === "object" ? inline : {};
34
- const removeStyleTags = options.removeStyleTags ?? false;
35
- const customCSS = options.customCSS ?? "";
36
- juice.styleToAttribute = options.styleToAttribute ?? {};
37
- juice.excludedProperties = ["--tw-shadow", ...options.excludedProperties ?? []];
38
- juice.widthElements = (options.widthElements ?? ["img", "video"]).map((i) => i.toUpperCase());
39
- juice.heightElements = (options.heightElements ?? ["img", "video"]).map((i) => i.toUpperCase());
40
- if (options.codeBlocks && typeof options.codeBlocks === "object") Object.entries(options.codeBlocks).forEach(([key, value]) => {
20
+ const { preferUnitlessValues = true, safelist, customCSS = "", styleToAttribute, excludedProperties, widthElements, heightElements, codeBlocks, ...juicePassthrough } = typeof inline === "object" ? inline : {};
21
+ juice.styleToAttribute = styleToAttribute ?? {};
22
+ juice.excludedProperties = ["--tw-shadow", ...excludedProperties ?? []];
23
+ juice.widthElements = (widthElements ?? ["img", "video"]).map((i) => i.toUpperCase());
24
+ juice.heightElements = (heightElements ?? ["img", "video"]).map((i) => i.toUpperCase());
25
+ if (codeBlocks && typeof codeBlocks === "object") Object.entries(codeBlocks).forEach(([key, value]) => {
41
26
  if (value.start && value.end) juice.codeBlocks[key] = value;
42
27
  });
43
28
  walk(dom, (node) => {
@@ -51,22 +36,19 @@ function inlineCSS(dom, config = {}) {
51
36
  const serialized = serialize(dom);
52
37
  let inlinedHtml;
53
38
  try {
54
- const juiceOptions = {
55
- removeStyleTags,
56
- removeInlinedSelectors: options.removeInlinedSelectors ?? true,
57
- preservedSelectors: options.safelist ?? [],
58
- applyWidthAttributes: options.applyWidthAttributes ?? true,
59
- applyHeightAttributes: options.applyHeightAttributes ?? true
60
- };
61
- if (customCSS) inlinedHtml = juice(serialized, {
62
- ...juiceOptions,
63
- extraCss: customCSS
39
+ inlinedHtml = juice(serialized, {
40
+ removeStyleTags: juicePassthrough.removeStyleTags ?? false,
41
+ removeInlinedSelectors: juicePassthrough.removeInlinedSelectors ?? true,
42
+ applyWidthAttributes: juicePassthrough.applyWidthAttributes ?? true,
43
+ applyHeightAttributes: juicePassthrough.applyHeightAttributes ?? true,
44
+ preservedSelectors: safelist ?? [],
45
+ ...customCSS ? { extraCss: customCSS } : {},
46
+ inlineDuplicateProperties: juicePassthrough.inlineDuplicateProperties ?? true,
47
+ ...juicePassthrough
64
48
  });
65
- else inlinedHtml = juice(serialized, juiceOptions);
66
49
  } catch {
67
50
  return dom;
68
51
  }
69
- const preferUnitlessValues = options.preferUnitlessValues ?? true;
70
52
  const result = parse(inlinedHtml);
71
53
  if (preferUnitlessValues) walk(result, (node) => {
72
54
  const el = node;
@@ -1 +1 @@
1
- {"version":3,"file":"inlineCSS.mjs","names":[],"sources":["../../src/transformers/inlineCSS.ts"],"sourcesContent":["import juice from 'juice'\nimport { walk, parse, serialize } from '../utils/ast/index.ts'\nimport type { ChildNode, Element } from 'domhandler'\nimport type { Options as JuiceOptions } from 'juice'\nimport type { CssConfig } from '../types/config.ts'\n\ninterface InlineCssOptions {\n removeStyleTags?: boolean\n removeInlinedSelectors?: boolean\n preferUnitlessValues?: boolean\n safelist?: string[]\n styleToAttribute?: Record<string, string>\n applyWidthAttributes?: boolean\n applyHeightAttributes?: boolean\n widthElements?: string[]\n heightElements?: string[]\n excludedProperties?: string[]\n codeBlocks?: Record<string, { start: string; end: string }>\n customCSS?: string\n}\n\n/**\n * Inline CSS transformer.\n *\n * Inlines CSS from `<style>` tags into inline style attributes on HTML elements.\n * This is important for email client compatibility (especially Outlook on Windows).\n *\n * Enabled when `css.inline` is set to `true` or an object with options.\n *\n * Options:\n * - removeStyleTags: Remove style tags after inlining (default: false)\n * - removeInlinedSelectors: Remove classes after they've been inlined (default: true)\n * - preferUnitlessValues: Convert 0px, 0em, etc. to 0 (default: true)\n * - safelist: Selectors that should not be removed after inlining\n * - styleToAttribute: Map CSS properties to HTML attributes (e.g., background-color -> bgcolor)\n * - applyWidthAttributes: Add width attributes based on inline CSS (default: true)\n * - applyHeightAttributes: Add height attributes based on inline CSS (default: true)\n * - widthElements: Elements that can receive width attributes (default: ['img', 'video'])\n * - heightElements: Elements that can receive height attributes (default: ['img', 'video'])\n * - excludedProperties: CSS properties to exclude from inlining\n * - codeBlocks: Fenced code blocks to ignore (default: { EJS: { start: '<%', end: '%>' }, HBS: { start: '{{', end: '}}' } })\n * - customCSS: Additional CSS to inline\n */\nexport function inlineCSS(dom: ChildNode[], config: CssConfig = {}): ChildNode[] {\n const inline = config.inline\n\n // Disabled when inline is falsy or not an object/truthy\n if (!inline) {\n return dom\n }\n\n // Build options from config\n const options: InlineCssOptions = typeof inline === 'object' ? inline : {}\n\n const removeStyleTags = options.removeStyleTags ?? false\n const customCSS = options.customCSS ?? ''\n\n // Configure Juice static properties\n juice.styleToAttribute = options.styleToAttribute ?? {}\n juice.excludedProperties = ['--tw-shadow', ...(options.excludedProperties ?? [])]\n juice.widthElements = (options.widthElements ?? ['img', 'video']).map(i => i.toUpperCase()) as unknown as HTMLElement[]\n juice.heightElements = (options.heightElements ?? ['img', 'video']).map(i => i.toUpperCase()) as unknown as HTMLElement[]\n\n // Add custom code blocks\n if (options.codeBlocks && typeof options.codeBlocks === 'object') {\n Object.entries(options.codeBlocks).forEach(([key, value]) => {\n if (value.start && value.end) {\n juice.codeBlocks[key] = value\n }\n })\n }\n\n // Handle style tags with embed attributes.\n // We add a marker attribute that persists through the pipeline,\n // then restore data-embed from it after Juice runs.\n walk(dom, (node) => {\n const el = node as Element\n if (el.name === 'style' && el.attribs) {\n // Sync data-embed ↔ embed\n if (el.attribs.embed && !('data-embed' in el.attribs)) {\n el.attribs['data-embed'] = ''\n }\n if (el.attribs['data-embed'] && !('embed' in el.attribs)) {\n el.attribs.embed = ''\n }\n\n // Add marker that persists through the pipeline\n if ('data-embed' in el.attribs) {\n el.attribs['data-maizzle-embed'] = ''\n }\n }\n })\n\n // Serialize for juice (juice requires a string)\n const serialized = serialize(dom)\n\n let inlinedHtml: string\n\n try {\n const juiceOptions: JuiceOptions = {\n removeStyleTags,\n removeInlinedSelectors: options.removeInlinedSelectors ?? true,\n preservedSelectors: options.safelist ?? [],\n applyWidthAttributes: options.applyWidthAttributes ?? true,\n applyHeightAttributes: options.applyHeightAttributes ?? true,\n }\n\n if (customCSS) {\n inlinedHtml = juice(serialized, { ...juiceOptions, extraCss: customCSS })\n } else {\n inlinedHtml = juice(serialized, juiceOptions)\n }\n } catch {\n // If Juice fails, return the dom unchanged\n return dom\n }\n\n // Post-process for preferUnitlessValues\n const preferUnitlessValues = options.preferUnitlessValues ?? true\n const result = parse(inlinedHtml)\n\n if (preferUnitlessValues) {\n walk(result, (node) => {\n const el = node as Element\n if (el.attribs?.style) {\n el.attribs.style = el.attribs.style.replace(\n /\\b0(px|rem|em|%|vh|vw|vmin|vmax|in|cm|mm|pt|pc|ex|ch)\\b/g,\n '0'\n )\n }\n })\n }\n\n // Restore data-embed from our marker, then remove the marker.\n // The purge step will handle final data-embed/embed removal.\n walk(result, (node) => {\n const el = node as Element\n if (el.name === 'style' && el.attribs && 'data-maizzle-embed' in el.attribs) {\n el.attribs['data-embed'] = ''\n el.attribs.embed = ''\n delete el.attribs['data-maizzle-embed']\n }\n })\n\n return result\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,SAAgB,UAAU,KAAkB,SAAoB,EAAE,EAAe;CAC/E,MAAM,SAAS,OAAO;AAGtB,KAAI,CAAC,OACH,QAAO;CAIT,MAAM,UAA4B,OAAO,WAAW,WAAW,SAAS,EAAE;CAE1E,MAAM,kBAAkB,QAAQ,mBAAmB;CACnD,MAAM,YAAY,QAAQ,aAAa;AAGvC,OAAM,mBAAmB,QAAQ,oBAAoB,EAAE;AACvD,OAAM,qBAAqB,CAAC,eAAe,GAAI,QAAQ,sBAAsB,EAAE,CAAE;AACjF,OAAM,iBAAiB,QAAQ,iBAAiB,CAAC,OAAO,QAAQ,EAAE,KAAI,MAAK,EAAE,aAAa,CAAC;AAC3F,OAAM,kBAAkB,QAAQ,kBAAkB,CAAC,OAAO,QAAQ,EAAE,KAAI,MAAK,EAAE,aAAa,CAAC;AAG7F,KAAI,QAAQ,cAAc,OAAO,QAAQ,eAAe,SACtD,QAAO,QAAQ,QAAQ,WAAW,CAAC,SAAS,CAAC,KAAK,WAAW;AAC3D,MAAI,MAAM,SAAS,MAAM,IACvB,OAAM,WAAW,OAAO;GAE1B;AAMJ,MAAK,MAAM,SAAS;EAClB,MAAM,KAAK;AACX,MAAI,GAAG,SAAS,WAAW,GAAG,SAAS;AAErC,OAAI,GAAG,QAAQ,SAAS,EAAE,gBAAgB,GAAG,SAC3C,IAAG,QAAQ,gBAAgB;AAE7B,OAAI,GAAG,QAAQ,iBAAiB,EAAE,WAAW,GAAG,SAC9C,IAAG,QAAQ,QAAQ;AAIrB,OAAI,gBAAgB,GAAG,QACrB,IAAG,QAAQ,wBAAwB;;GAGvC;CAGF,MAAM,aAAa,UAAU,IAAI;CAEjC,IAAI;AAEJ,KAAI;EACF,MAAM,eAA6B;GACjC;GACA,wBAAwB,QAAQ,0BAA0B;GAC1D,oBAAoB,QAAQ,YAAY,EAAE;GAC1C,sBAAsB,QAAQ,wBAAwB;GACtD,uBAAuB,QAAQ,yBAAyB;GACzD;AAED,MAAI,UACF,eAAc,MAAM,YAAY;GAAE,GAAG;GAAc,UAAU;GAAW,CAAC;MAEzE,eAAc,MAAM,YAAY,aAAa;SAEzC;AAEN,SAAO;;CAIT,MAAM,uBAAuB,QAAQ,wBAAwB;CAC7D,MAAM,SAAS,MAAM,YAAY;AAEjC,KAAI,qBACF,MAAK,SAAS,SAAS;EACrB,MAAM,KAAK;AACX,MAAI,GAAG,SAAS,MACd,IAAG,QAAQ,QAAQ,GAAG,QAAQ,MAAM,QAClC,4DACA,IACD;GAEH;AAKJ,MAAK,SAAS,SAAS;EACrB,MAAM,KAAK;AACX,MAAI,GAAG,SAAS,WAAW,GAAG,WAAW,wBAAwB,GAAG,SAAS;AAC3E,MAAG,QAAQ,gBAAgB;AAC3B,MAAG,QAAQ,QAAQ;AACnB,UAAO,GAAG,QAAQ;;GAEpB;AAEF,QAAO"}
1
+ {"version":3,"file":"inlineCSS.mjs","names":[],"sources":["../../src/transformers/inlineCSS.ts"],"sourcesContent":["import juice from 'juice'\nimport { walk, parse, serialize } from '../utils/ast/index.ts'\nimport type { ChildNode, Element } from 'domhandler'\nimport type { Options as JuiceOptions } from 'juice'\nimport type { CssConfig } from '../types/config.ts'\n\n/**\n * Inline CSS transformer.\n *\n * Inlines CSS from `<style>` tags into inline style attributes on HTML elements.\n * This is important for email client compatibility (especially Outlook on Windows).\n *\n * Enabled when `css.inline` is set to `true` or an object with options.\n * All Juice options are supported and passed through directly.\n */\nexport function inlineCSS(dom: ChildNode[], config: CssConfig = {}): ChildNode[] {\n const inline = config.inline\n\n // Disabled when inline is falsy or not an object/truthy\n if (!inline) {\n return dom\n }\n\n // Build options from config\n const options = typeof inline === 'object' ? inline : {}\n\n // Separate Maizzle-specific options from Juice options\n const {\n preferUnitlessValues = true,\n safelist,\n customCSS = '',\n styleToAttribute,\n excludedProperties,\n widthElements,\n heightElements,\n codeBlocks,\n ...juicePassthrough\n } = options\n\n // Configure Juice static properties\n juice.styleToAttribute = styleToAttribute ?? {}\n juice.excludedProperties = ['--tw-shadow', ...(excludedProperties ?? [])]\n juice.widthElements = (widthElements ?? ['img', 'video']).map(i => i.toUpperCase()) as unknown as HTMLElement[]\n juice.heightElements = (heightElements ?? ['img', 'video']).map(i => i.toUpperCase()) as unknown as HTMLElement[]\n\n // Add custom code blocks\n if (codeBlocks && typeof codeBlocks === 'object') {\n Object.entries(codeBlocks).forEach(([key, value]) => {\n if (value.start && value.end) {\n juice.codeBlocks[key] = value\n }\n })\n }\n\n // Handle style tags with embed attributes.\n // We add a marker attribute that persists through the pipeline,\n // then restore data-embed from it after Juice runs.\n walk(dom, (node) => {\n const el = node as Element\n if (el.name === 'style' && el.attribs) {\n // Sync data-embed ↔ embed\n if (el.attribs.embed && !('data-embed' in el.attribs)) {\n el.attribs['data-embed'] = ''\n }\n if (el.attribs['data-embed'] && !('embed' in el.attribs)) {\n el.attribs.embed = ''\n }\n\n // Add marker that persists through the pipeline\n if ('data-embed' in el.attribs) {\n el.attribs['data-maizzle-embed'] = ''\n }\n }\n })\n\n // Serialize for juice (juice requires a string)\n const serialized = serialize(dom)\n\n let inlinedHtml: string\n\n try {\n const juiceOptions: JuiceOptions = {\n removeStyleTags: juicePassthrough.removeStyleTags ?? false,\n removeInlinedSelectors: juicePassthrough.removeInlinedSelectors ?? true,\n applyWidthAttributes: juicePassthrough.applyWidthAttributes ?? true,\n applyHeightAttributes: juicePassthrough.applyHeightAttributes ?? true,\n preservedSelectors: safelist ?? [],\n ...customCSS ? { extraCss: customCSS } : {},\n inlineDuplicateProperties: juicePassthrough.inlineDuplicateProperties ?? true,\n ...juicePassthrough,\n }\n\n inlinedHtml = juice(serialized, juiceOptions)\n } catch {\n // If Juice fails, return the dom unchanged\n return dom\n }\n\n // Post-process for preferUnitlessValues\n const result = parse(inlinedHtml)\n\n if (preferUnitlessValues) {\n walk(result, (node) => {\n const el = node as Element\n if (el.attribs?.style) {\n el.attribs.style = el.attribs.style.replace(\n /\\b0(px|rem|em|%|vh|vw|vmin|vmax|in|cm|mm|pt|pc|ex|ch)\\b/g,\n '0'\n )\n }\n })\n }\n\n // Restore data-embed from our marker, then remove the marker.\n // The purge step will handle final data-embed/embed removal.\n walk(result, (node) => {\n const el = node as Element\n if (el.name === 'style' && el.attribs && 'data-maizzle-embed' in el.attribs) {\n el.attribs['data-embed'] = ''\n el.attribs.embed = ''\n delete el.attribs['data-maizzle-embed']\n }\n })\n\n return result\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,SAAgB,UAAU,KAAkB,SAAoB,EAAE,EAAe;CAC/E,MAAM,SAAS,OAAO;AAGtB,KAAI,CAAC,OACH,QAAO;CAOT,MAAM,EACJ,uBAAuB,MACvB,UACA,YAAY,IACZ,kBACA,oBACA,eACA,gBACA,YACA,GAAG,qBAZW,OAAO,WAAW,WAAW,SAAS,EAAE;AAgBxD,OAAM,mBAAmB,oBAAoB,EAAE;AAC/C,OAAM,qBAAqB,CAAC,eAAe,GAAI,sBAAsB,EAAE,CAAE;AACzE,OAAM,iBAAiB,iBAAiB,CAAC,OAAO,QAAQ,EAAE,KAAI,MAAK,EAAE,aAAa,CAAC;AACnF,OAAM,kBAAkB,kBAAkB,CAAC,OAAO,QAAQ,EAAE,KAAI,MAAK,EAAE,aAAa,CAAC;AAGrF,KAAI,cAAc,OAAO,eAAe,SACtC,QAAO,QAAQ,WAAW,CAAC,SAAS,CAAC,KAAK,WAAW;AACnD,MAAI,MAAM,SAAS,MAAM,IACvB,OAAM,WAAW,OAAO;GAE1B;AAMJ,MAAK,MAAM,SAAS;EAClB,MAAM,KAAK;AACX,MAAI,GAAG,SAAS,WAAW,GAAG,SAAS;AAErC,OAAI,GAAG,QAAQ,SAAS,EAAE,gBAAgB,GAAG,SAC3C,IAAG,QAAQ,gBAAgB;AAE7B,OAAI,GAAG,QAAQ,iBAAiB,EAAE,WAAW,GAAG,SAC9C,IAAG,QAAQ,QAAQ;AAIrB,OAAI,gBAAgB,GAAG,QACrB,IAAG,QAAQ,wBAAwB;;GAGvC;CAGF,MAAM,aAAa,UAAU,IAAI;CAEjC,IAAI;AAEJ,KAAI;AAYF,gBAAc,MAAM,YAXe;GACjC,iBAAiB,iBAAiB,mBAAmB;GACrD,wBAAwB,iBAAiB,0BAA0B;GACnE,sBAAsB,iBAAiB,wBAAwB;GAC/D,uBAAuB,iBAAiB,yBAAyB;GACjE,oBAAoB,YAAY,EAAE;GAClC,GAAG,YAAY,EAAE,UAAU,WAAW,GAAG,EAAE;GAC3C,2BAA2B,iBAAiB,6BAA6B;GACzE,GAAG;GACJ,CAE4C;SACvC;AAEN,SAAO;;CAIT,MAAM,SAAS,MAAM,YAAY;AAEjC,KAAI,qBACF,MAAK,SAAS,SAAS;EACrB,MAAM,KAAK;AACX,MAAI,GAAG,SAAS,MACd,IAAG,QAAQ,QAAQ,GAAG,QAAQ,MAAM,QAClC,4DACA,IACD;GAEH;AAKJ,MAAK,SAAS,SAAS;EACrB,MAAM,KAAK;AACX,MAAI,GAAG,SAAS,WAAW,GAAG,WAAW,wBAAwB,GAAG,SAAS;AAC3E,MAAG,QAAQ,gBAAgB;AAC3B,MAAG,QAAQ,QAAQ;AACnB,UAAO,GAAG,QAAQ;;GAEpB;AAEF,QAAO"}
@@ -0,0 +1,16 @@
1
+ import { CssConfig } from "../types/config.mjs";
2
+ import { ChildNode } from "domhandler";
3
+
4
+ //#region src/transformers/sixHex.d.ts
5
+ /**
6
+ * Six-digit HEX transformer.
7
+ *
8
+ * Converts 3-digit HEX color codes to 6-digit in `bgcolor` and `color`
9
+ * attributes, for better email client compatibility.
10
+ *
11
+ * Enabled by default via `css.sixHex`.
12
+ */
13
+ declare function sixHex(dom: ChildNode[], config?: CssConfig): ChildNode[];
14
+ //#endregion
15
+ export { sixHex };
16
+ //# sourceMappingURL=sixHex.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sixHex.d.mts","names":[],"sources":["../../src/transformers/sixHex.ts"],"mappings":";;;;;;AAeA;;;;;;iBAAgB,MAAA,CAAO,GAAA,EAAK,SAAA,IAAa,MAAA,GAAQ,SAAA,GAAiB,SAAA"}
@@ -0,0 +1,30 @@
1
+ import { walk } from "../utils/ast/walker.mjs";
2
+ import "../utils/ast/index.mjs";
3
+ import { conv } from "color-shorthand-hex-to-six-digit";
4
+
5
+ //#region src/transformers/sixHex.ts
6
+ const targets = new Set(["bgcolor", "color"]);
7
+ /**
8
+ * Six-digit HEX transformer.
9
+ *
10
+ * Converts 3-digit HEX color codes to 6-digit in `bgcolor` and `color`
11
+ * attributes, for better email client compatibility.
12
+ *
13
+ * Enabled by default via `css.sixHex`.
14
+ */
15
+ function sixHex(dom, config = {}) {
16
+ if (config.sixHex === false) return dom;
17
+ walk(dom, (node) => {
18
+ const el = node;
19
+ if (!el.attribs) return;
20
+ for (const attr of targets) {
21
+ const value = el.attribs[attr];
22
+ if (value) el.attribs[attr] = conv(value);
23
+ }
24
+ });
25
+ return dom;
26
+ }
27
+
28
+ //#endregion
29
+ export { sixHex };
30
+ //# sourceMappingURL=sixHex.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sixHex.mjs","names":[],"sources":["../../src/transformers/sixHex.ts"],"sourcesContent":["import { conv } from 'color-shorthand-hex-to-six-digit'\nimport type { ChildNode, Element } from 'domhandler'\nimport { walk } from '../utils/ast/index.ts'\nimport type { CssConfig } from '../types/config.ts'\n\nconst targets = new Set(['bgcolor', 'color'])\n\n/**\n * Six-digit HEX transformer.\n *\n * Converts 3-digit HEX color codes to 6-digit in `bgcolor` and `color`\n * attributes, for better email client compatibility.\n *\n * Enabled by default via `css.sixHex`.\n */\nexport function sixHex(dom: ChildNode[], config: CssConfig = {}): ChildNode[] {\n if (config.sixHex === false) {\n return dom\n }\n\n walk(dom, (node) => {\n const el = node as Element\n\n if (!el.attribs) {\n return\n }\n\n for (const attr of targets) {\n const value = el.attribs[attr]\n\n if (value) {\n el.attribs[attr] = conv(value)\n }\n }\n })\n\n return dom\n}\n"],"mappings":";;;;;AAKA,MAAM,UAAU,IAAI,IAAI,CAAC,WAAW,QAAQ,CAAC;;;;;;;;;AAU7C,SAAgB,OAAO,KAAkB,SAAoB,EAAE,EAAe;AAC5E,KAAI,OAAO,WAAW,MACpB,QAAO;AAGT,MAAK,MAAM,SAAS;EAClB,MAAM,KAAK;AAEX,MAAI,CAAC,GAAG,QACN;AAGF,OAAK,MAAM,QAAQ,SAAS;GAC1B,MAAM,QAAQ,GAAG,QAAQ;AAEzB,OAAI,MACF,IAAG,QAAQ,QAAQ,KAAK,MAAM;;GAGlC;AAEF,QAAO"}
@@ -1,7 +1,10 @@
1
1
  import { RemoveValue } from "../plugins/postcss/removeDeclarations.mjs";
2
+ import { Directive, Plugin } from "vue";
3
+ import { Options } from "juice";
2
4
  import * as oxfmt from "oxfmt";
5
+ import { InlineConfig } from "vite";
3
6
  import * as shiki from "shiki";
4
- import { Options } from "unplugin-vue-markdown/types";
7
+ import { Options as Options$1 } from "unplugin-vue-markdown/types";
5
8
 
6
9
  //#region src/types/config.d.ts
7
10
  interface UrlQueryOptions {
@@ -92,7 +95,7 @@ interface CssConfig {
92
95
  * }
93
96
  * }
94
97
  */
95
- inline?: boolean | {
98
+ inline?: boolean | Options & {
96
99
  /**
97
100
  * Convert HTML attributes like `width`, `height`, `bgcolor`, and `valign`
98
101
  * to inline CSS styles. Set to `true` for all, or pass an array of attribute names.
@@ -100,18 +103,6 @@ interface CssConfig {
100
103
  * @default false
101
104
  */
102
105
  attributeToStyle?: boolean | string[];
103
- /**
104
- * Remove `<style>` tags after inlining.
105
- *
106
- * @default false
107
- */
108
- removeStyleTags?: boolean;
109
- /**
110
- * Remove selectors from `<style>` tags after they have been inlined.
111
- *
112
- * @default true
113
- */
114
- removeInlinedSelectors?: boolean;
115
106
  /**
116
107
  * Convert `0px`, `0em` etc. to `0` in inline styles.
117
108
  *
@@ -120,12 +111,14 @@ interface CssConfig {
120
111
  preferUnitlessValues?: boolean;
121
112
  /**
122
113
  * CSS selectors to preserve in `<style>` tags, even after inlining.
114
+ * Mapped to Juice's `preservedSelectors` option.
123
115
  *
124
116
  * @default []
125
117
  */
126
118
  safelist?: string[];
127
119
  /**
128
120
  * Duplicate CSS properties to HTML attributes.
121
+ * Mapped to Juice's static `styleToAttribute` property.
129
122
  *
130
123
  * @default {}
131
124
  *
@@ -135,38 +128,30 @@ interface CssConfig {
135
128
  * }
136
129
  */
137
130
  styleToAttribute?: Record<string, string>;
138
- /**
139
- * Add `width` HTML attributes based on inline CSS width values.
140
- *
141
- * @default true
142
- */
143
- applyWidthAttributes?: boolean;
144
- /**
145
- * Add `height` HTML attributes based on inline CSS height values.
146
- *
147
- * @default true
148
- */
149
- applyHeightAttributes?: boolean;
150
131
  /**
151
132
  * Elements that can receive `width` HTML attributes.
133
+ * Mapped to Juice's static `widthElements` property.
152
134
  *
153
135
  * @default ['img', 'video']
154
136
  */
155
137
  widthElements?: string[];
156
138
  /**
157
139
  * Elements that can receive `height` HTML attributes.
140
+ * Mapped to Juice's static `heightElements` property.
158
141
  *
159
142
  * @default ['img', 'video']
160
143
  */
161
144
  heightElements?: string[];
162
145
  /**
163
146
  * CSS properties to exclude from inlining.
147
+ * Mapped to Juice's static `excludedProperties` property.
164
148
  *
165
149
  * @default []
166
150
  */
167
151
  excludedProperties?: string[];
168
152
  /**
169
153
  * Template language code blocks to preserve during inlining.
154
+ * Mapped to Juice's static `codeBlocks` property.
170
155
  *
171
156
  * @default { EJS: { start: '<%', end: '%>' }, HBS: { start: '\{\{', end: '}}' } }
172
157
  */
@@ -176,6 +161,7 @@ interface CssConfig {
176
161
  }>;
177
162
  /**
178
163
  * Additional CSS string to inline alongside `<style>` tag contents.
164
+ * Mapped to Juice's `extraCss` option.
179
165
  */
180
166
  customCSS?: string;
181
167
  };
@@ -235,6 +221,14 @@ interface CssConfig {
235
221
  shorthand?: boolean | {
236
222
  tags?: string[];
237
223
  };
224
+ /**
225
+ * Convert 3-digit HEX colors to 6-digit in `bgcolor` and `color` attributes.
226
+ *
227
+ * Some email clients don't support shorthand HEX like `#fff`.
228
+ *
229
+ * @default true
230
+ */
231
+ sixHex?: boolean;
238
232
  /**
239
233
  * Remove specific CSS declarations by selector.
240
234
  *
@@ -337,7 +331,7 @@ interface HtmlConfig {
337
331
  }
338
332
  type FilterFunction = (str: string, value: string) => string;
339
333
  type FiltersConfig = false | Record<string, FilterFunction>;
340
- interface MarkdownConfig extends Options {
334
+ interface MarkdownConfig extends Options$1 {
341
335
  /**
342
336
  * The shiki theme to use for syntax highlighting in Markdown fenced code blocks.
343
337
  *
@@ -345,6 +339,14 @@ interface MarkdownConfig extends Options {
345
339
  */
346
340
  shikiTheme?: shiki.BundledTheme;
347
341
  }
342
+ interface VueConfig {
343
+ /** Vue plugins to register on the app instance before rendering. */
344
+ plugins?: Plugin[];
345
+ /** Custom Vue directives to register globally. */
346
+ directives?: Record<string, Directive>;
347
+ /** Properties added to `app.config.globalProperties`, available in all templates. */
348
+ globalProperties?: Record<string, unknown>;
349
+ }
348
350
  interface MaizzleConfig {
349
351
  /**
350
352
  * Root directory for the Maizzle email project.
@@ -509,6 +511,33 @@ interface MaizzleConfig {
509
511
  url?: UrlConfig;
510
512
  /** HTML post-processing settings (attributes, formatting, minification). */
511
513
  html?: HtmlConfig;
514
+ /**
515
+ * Vite configuration options passed to the internal Vite SSR server.
516
+ *
517
+ * Use this to add custom Vite plugins or other Vite options.
518
+ * If a `vite.config.{ts,js}` file exists in the project root, it takes
519
+ * precedence and this option is used as a fallback.
520
+ *
521
+ * @example
522
+ * vite: {
523
+ * plugins: [myPlugin()],
524
+ * }
525
+ */
526
+ vite?: InlineConfig;
527
+ /**
528
+ * Vue app customization options.
529
+ *
530
+ * Register plugins, directives, or global properties on the
531
+ * internal Vue app instance used for SSR rendering.
532
+ *
533
+ * @example
534
+ * vue: {
535
+ * plugins: [createI18n({ locale: 'en', messages })],
536
+ * directives: { focus: vFocus },
537
+ * globalProperties: { $format: dateFormat },
538
+ * }
539
+ */
540
+ vue?: VueConfig;
512
541
  /** Called before any templates are processed. */
513
542
  beforeCreate?: (params: {
514
543
  config: MaizzleConfig;
@@ -538,5 +567,5 @@ interface MaizzleConfig {
538
567
  [key: string]: any;
539
568
  }
540
569
  //#endregion
541
- export { AttributesConfig, CssConfig, EntitiesConfig, FilterFunction, FiltersConfig, HtmlConfig, MaizzleConfig, MarkdownConfig, PostcssConfig, UrlConfig, UrlQuery, UrlQueryOptions };
570
+ export { AttributesConfig, CssConfig, EntitiesConfig, FilterFunction, FiltersConfig, HtmlConfig, MaizzleConfig, MarkdownConfig, PostcssConfig, UrlConfig, UrlQuery, UrlQueryOptions, VueConfig };
542
571
  //# sourceMappingURL=config.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.mts","names":[],"sources":["../../src/types/config.ts"],"mappings":";;;;;;UAEiB,eAAA;;;;;AAAjB;EAME,IAAA;;;;;;EAMA,UAAA;EAYK;;;AAGP;;EATE,MAAA;EAU0B;;;;;EAJ1B,EAAA,GAAK,MAAA;AAAA;AAAA,KAGK,QAAA,GAAW,MAAA;EACrB,QAAA,GAAW,eAAA;AAAA;AAAA,UAGI,SAAA;EA2BK;;;;;;;;;;;EAfpB,KAAA,GAAQ,QAAA;EAiBO;;;;;AAQjB;;;;;EAdE,IAAA;IA2KiB,+BAzKf,GAAA,WA4LmB;IA1LnB,IAAA,cAAkB,MAAA,SAAe,MAAA,6BA0LR;IAxLzB,UAAA,GAAa,MAAA,kBAsBf;IApBE,QAAA,YAkCF;IAhCE,SAAA;EAAA;AAAA;AAAA,UAIa,SAAA;EA2Db;;;;;EArDF,IAAA;EAwFE;;;;;;;EAhFF,KAAA,aAAkB,MAAA;EAoHhB;;;;;;;;;;;;;EAtGF,MAAA;IA6JO;;AAGT;;;;IAzJI,gBAAA;IAkLuD;;;;;IA5KvD,eAAA;IAiK2B;;;;;IA3J3B,sBAAA;IAsK6D;;AAGjE;;;IAnKI,oBAAA;IAmKyC;AAE7C;;;;IA/JI,QAAA;IAwLa;;;;;;;;;;IA7Kb,gBAAA,GAAmB,MAAA;IAuLrB;;;;;IAjLE,oBAAA;IA6LuB;;AAG3B;;;IA1LI,qBAAA;IA0LoD;AACxD;;;;IArLI,aAAA;IAuLa;;;;;IAjLb,cAAA;IAuLQ;;;AAGZ;;IApLI,kBAAA;IAqMS;;;;;IA/LT,UAAA,GAAa,MAAA;MAAiB,KAAA;MAAe,GAAA;IAAA;IA0Vb;;;IAtVhC,SAAA;EAAA;EA0VmG;;;;;;;;;;;;EA5UrG,KAAA;IAwME;;;;;IAlMA,IAAA,wCAA4C,CAAA,UAAW,CAAA;EAAA;EAyOvD;;;;;;;EAhOF,cAAA;EA2QA;;;;;EArQA,WAAA;EAqRA;;;;;EA/QA,YAAA;EAsSM;;;;;EAhSN,IAAA,aAAiB,MAAA;EAuSD;;;;;;;EA/RhB,SAAA;IAAwB,IAAA;EAAA;EAmSS;;;;;;;;;;EAxRjC,kBAAA,GAAqB,MAAA,SAnBE,WAAA;EA6SiF;;;;;;;;EAjRxG,OAAA;AAAA;AAAA,UAGe,gBAAA;;;;;;;;;;;;;;EAcf,GAAA,WAAc,MAAA,SAAe,MAAA;;;;;;;;;;;EAW7B,MAAA,GAAS,KAAA;IAAiB,IAAA;IAAc,KAAA,YAAiB,MAAA;EAAA;AAAA;AAAA,KAG/C,cAAA,aAA2B,MAAA;AAAA,UAEtB,aAAA;;;;;;;;;;;EAWf,eAAA;;;;;;;;;;;EAWA,aAAA;AAAA;AAAA,UAGe,UAAA;;EAEf,UAAA,GAAa,gBAAA;;;;;;;;EAQb,cAAA,GAAiB,cAAA;;;;;;EAMjB,MAAA,aAN+B,KAAA,CAMI,aAAA;;;;;;EAMnC,MAAA,aAAmB,MAAA;AAAA;AAAA,KAGT,cAAA,IAAkB,GAAA,UAAa,KAAA;AAAA,KAC/B,aAAA,WAAwB,MAAA,SAAe,cAAA;AAAA,UAElC,cAAA,SAAuB,OAAA;;;;;;EAMtC,UAAA,GAN8B,KAAA,CAMD,YAAA;AAAA;AAAA,UAGd,aAAA;;;;;;;;;;;;;;;EAef,IAAA;;EAEA,QAAA,GAAW,cAAA;;;;;;;;EAQX,OAAA;;EAEA,MAAA;;;;;;IAME,IAAA;;;;;;;;;;;IAWA,SAAA;EAAA;;EAGF,MAAA;;;;;;IAME,MAAA;;;;;;IAMA,WAAA;EAAA;;EAGF,UAAA;;;;;;;;;;;;IAYE,MAAA;EAAA;;EAGF,MAAA;;;;;;IAME,IAAA;;;;;;;;;;;IAWA,KAAA;;;;;;;;;;;;;;;;;;;;IAoBA,KAAA;kCAEE,EAAA;MAEA,IAAA;MAEA,OAAA;MAEA,SAAA,GAAY,MAAA;IAAA;EAAA;;EAIhB,GAAA,GAAM,SAAA;;;;;;;;EAQN,SAAA,sBAA+B,MAAA;;EAE/B,OAAA,GAAU,aAAA;;;;;;EAMV,eAAA;;;;;;;;;EASA,cAAA,GAAiB,MAAA;;;;;;;;;;;;EAYjB,OAAA,GAAU,aAAA;;EAEV,GAAA,GAAM,SAAA;;EAEN,IAAA,GAAO,UAAA;;EAKP,YAAA,IAAgB,MAAA;IAAU,MAAA,EAAQ,aAAA;EAAA,aAA2B,OAAA;;EAE7D,YAAA,IAAgB,MAAA;IAAU,MAAA,EAAQ,aAAA;IAAe,QAAA;EAAA,sBAAuC,OAAA;;EAExF,WAAA,IAAe,MAAA;IAAU,MAAA,EAAQ,aAAA;IAAe,QAAA;IAAkB,IAAA;EAAA,sBAAmC,OAAA;;EAErG,cAAA,IAAkB,MAAA;IAAU,MAAA,EAAQ,aAAA;IAAe,QAAA;IAAkB,IAAA;EAAA,sBAAmC,OAAA;;EAExG,UAAA,IAAc,MAAA;IAAU,KAAA;IAAiB,MAAA,EAAQ,aAAA;EAAA,aAA2B,OAAA;EAAA,CAG3E,GAAA;AAAA"}
1
+ {"version":3,"file":"config.d.mts","names":[],"sources":["../../src/types/config.ts"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maizzle/framework",
3
- "version": "6.0.0-rc.7",
3
+ "version": "6.0.0-rc.9",
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",
@@ -42,6 +42,7 @@
42
42
  "caniemail": "^1.0.5",
43
43
  "class-variance-authority": "^0.7.1",
44
44
  "clsx": "^2.1.1",
45
+ "color-shorthand-hex-to-six-digit": "^5.1.3",
45
46
  "css-select": "^6.0.0",
46
47
  "defu": "^6.1.4",
47
48
  "dom-serializer": "^2.0.0",