@maizzle/framework 6.1.0 → 6.1.1

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 (49) hide show
  1. package/dist/build.js +2 -1
  2. package/dist/build.js.map +1 -1
  3. package/dist/config/index.js.map +1 -1
  4. package/dist/plugins/postcss/mergeMediaQueries.js +2 -1
  5. package/dist/plugins/postcss/mergeMediaQueries.js.map +1 -1
  6. package/dist/plugins/postcss/resolveMaizzleImports.js.map +1 -1
  7. package/dist/render/buildTemplate.js +3 -1
  8. package/dist/render/buildTemplate.js.map +1 -1
  9. package/dist/render/createRenderer.js +8 -1
  10. package/dist/render/createRenderer.js.map +1 -1
  11. package/dist/serve.js +18 -9
  12. package/dist/serve.js.map +1 -1
  13. package/dist/server/compatibility.js +2 -1
  14. package/dist/server/compatibility.js.map +1 -1
  15. package/dist/server/linter.js +2 -1
  16. package/dist/server/linter.js.map +1 -1
  17. package/dist/server/sfc-utils.js.map +1 -1
  18. package/dist/server/ui/.vite/deps/@lucide_vue.js +6845 -6285
  19. package/dist/server/ui/.vite/deps/@lucide_vue.js.map +1 -1
  20. package/dist/server/ui/.vite/deps/@vueuse_core.js +2 -6
  21. package/dist/server/ui/.vite/deps/@vueuse_core.js.map +1 -1
  22. package/dist/server/ui/.vite/deps/@vueuse_shared.js +1 -1
  23. package/dist/server/ui/.vite/deps/@vueuse_shared.js.map +1 -1
  24. package/dist/server/ui/.vite/deps/_metadata.json +15 -15
  25. package/dist/server/ui/.vite/deps/culori.js +8 -6
  26. package/dist/server/ui/.vite/deps/culori.js.map +1 -1
  27. package/dist/server/ui/.vite/deps/reka-ui.js +63 -73
  28. package/dist/server/ui/.vite/deps/reka-ui.js.map +1 -1
  29. package/dist/server/ui/.vite/deps/tailwind-merge.js.map +1 -1
  30. package/dist/server/ui/.vite/deps/vue-router.js +5 -13
  31. package/dist/server/ui/.vite/deps/vue-router.js.map +1 -1
  32. package/dist/server/ui/.vite/deps/vue.js +1 -1
  33. package/dist/server/ui/.vite/deps/{vue.runtime.esm-bundler-BHD3r-bP.js → vue.runtime.esm-bundler-S54atuNJ.js} +323 -259
  34. package/dist/server/ui/.vite/deps/{vue.runtime.esm-bundler-BHD3r-bP.js.map → vue.runtime.esm-bundler-S54atuNJ.js.map} +1 -1
  35. package/dist/transformers/format.js +2 -1
  36. package/dist/transformers/format.js.map +1 -1
  37. package/dist/transformers/inlineCss.js +3 -2
  38. package/dist/transformers/inlineCss.js.map +1 -1
  39. package/dist/transformers/inlineLink.js +2 -1
  40. package/dist/transformers/inlineLink.js.map +1 -1
  41. package/dist/transformers/minify.js +2 -1
  42. package/dist/transformers/minify.js.map +1 -1
  43. package/dist/transformers/tailwindComponent.js +2 -1
  44. package/dist/transformers/tailwindComponent.js.map +1 -1
  45. package/dist/transformers/urlQuery.js +2 -1
  46. package/dist/transformers/urlQuery.js.map +1 -1
  47. package/dist/utils/cssBox.js +2 -6
  48. package/dist/utils/cssBox.js.map +1 -1
  49. package/package.json +2 -2
@@ -22,7 +22,8 @@ const DEFAULT_OPTIONS = {
22
22
  * const pretty = await format(html, { useTabs: true, tabWidth: 4 })
23
23
  */
24
24
  async function format(html, options = {}) {
25
- return (await format$1("input.html", html, defu$1(options, DEFAULT_OPTIONS))).code;
25
+ const merged = defu$1(options, DEFAULT_OPTIONS);
26
+ return (await format$1("input.html", html, merged)).code;
26
27
  }
27
28
  //#endregion
28
29
  export { format };
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","names":["oxfmt","merge"],"sources":["../../src/transformers/format.ts"],"sourcesContent":["import { format as oxfmt } from 'oxfmt'\nimport { defu as merge } from 'defu'\nimport type { FormatConfig } from 'oxfmt'\n\nexport type { FormatConfig } from 'oxfmt'\n\nconst DEFAULT_OPTIONS: FormatConfig = {\n printWidth: 320,\n htmlWhitespaceSensitivity: 'ignore',\n embeddedLanguageFormatting: 'off',\n}\n\n/**\n * Pretty-print an HTML string with `oxfmt`. Maizzle defaults\n * (`printWidth: 320`, `htmlWhitespaceSensitivity: 'ignore'`,\n * `embeddedLanguageFormatting: 'off'`) are merged underneath any options\n * you pass.\n *\n * @param html HTML string to format.\n * @param options [oxfmt `FormatConfig`](https://github.com/oxc-project/oxfmt).\n * @returns The formatted HTML string.\n *\n * @example\n * import { format } from '@maizzle/framework'\n *\n * const pretty = await format(html, { useTabs: true, tabWidth: 4 })\n */\nexport async function format(html: string, options: FormatConfig = {}): Promise<string> {\n const merged = merge(options, DEFAULT_OPTIONS)\n const result = await oxfmt('input.html', html, merged)\n return result.code\n}\n"],"mappings":";;;AAMA,MAAM,kBAAgC;CACpC,YAAY;CACZ,2BAA2B;CAC3B,4BAA4B;AAC9B;;;;;;;;;;;;;;;;AAiBA,eAAsB,OAAO,MAAc,UAAwB,CAAC,GAAoB;CAGtF,QAAO,MADcA,SAAM,cAAc,MAD1BC,OAAM,SAAS,eACsB,CAAC,EAAA,CACvC;AAChB"}
1
+ {"version":3,"file":"format.js","names":["merge","oxfmt"],"sources":["../../src/transformers/format.ts"],"sourcesContent":["import { format as oxfmt } from 'oxfmt'\nimport { defu as merge } from 'defu'\nimport type { FormatConfig } from 'oxfmt'\n\nexport type { FormatConfig } from 'oxfmt'\n\nconst DEFAULT_OPTIONS: FormatConfig = {\n printWidth: 320,\n htmlWhitespaceSensitivity: 'ignore',\n embeddedLanguageFormatting: 'off',\n}\n\n/**\n * Pretty-print an HTML string with `oxfmt`. Maizzle defaults\n * (`printWidth: 320`, `htmlWhitespaceSensitivity: 'ignore'`,\n * `embeddedLanguageFormatting: 'off'`) are merged underneath any options\n * you pass.\n *\n * @param html HTML string to format.\n * @param options [oxfmt `FormatConfig`](https://github.com/oxc-project/oxfmt).\n * @returns The formatted HTML string.\n *\n * @example\n * import { format } from '@maizzle/framework'\n *\n * const pretty = await format(html, { useTabs: true, tabWidth: 4 })\n */\nexport async function format(html: string, options: FormatConfig = {}): Promise<string> {\n const merged = merge(options, DEFAULT_OPTIONS)\n const result = await oxfmt('input.html', html, merged)\n return result.code\n}\n"],"mappings":";;;AAMA,MAAM,kBAAgC;CACpC,YAAY;CACZ,2BAA2B;CAC3B,4BAA4B;AAC9B;;;;;;;;;;;;;;;;AAiBA,eAAsB,OAAO,MAAc,UAAwB,CAAC,GAAoB;CACtF,MAAM,SAASA,OAAM,SAAS,eAAe;CAE7C,QAAO,MADcC,SAAM,cAAc,MAAM,MAAM,EAAA,CACvC;AAChB"}
@@ -66,7 +66,7 @@ function inlineCssDom(dom, options = {}) {
66
66
  const serialized = serialize(dom);
67
67
  let inlinedHtml;
68
68
  try {
69
- inlinedHtml = juice(serialized, {
69
+ const juiceOptions = {
70
70
  removeStyleTags: juicePassthrough.removeStyleTags ?? false,
71
71
  removeInlinedSelectors: juicePassthrough.removeInlinedSelectors ?? true,
72
72
  applyWidthAttributes: juicePassthrough.applyWidthAttributes ?? true,
@@ -75,7 +75,8 @@ function inlineCssDom(dom, options = {}) {
75
75
  ...customCSS ? { extraCss: customCSS } : {},
76
76
  inlineDuplicateProperties: juicePassthrough.inlineDuplicateProperties ?? false,
77
77
  ...juicePassthrough
78
- });
78
+ };
79
+ inlinedHtml = juice(serialized, juiceOptions);
79
80
  } catch {
80
81
  return dom;
81
82
  }
@@ -1 +1 @@
1
- {"version":3,"file":"inlineCss.js","names":[],"sources":["../../src/transformers/inlineCss.ts"],"sourcesContent":["import juice from 'juice'\nimport { walk, parse, serialize } from '../utils/ast/index.ts'\n\n/** Juice's built-in code blocks, captured before any per-call mutation. */\nconst DEFAULT_CODE_BLOCKS = { ...juice.codeBlocks }\nimport type { ChildNode, Element } from 'domhandler'\ntype JuiceOptions = NonNullable<Parameters<typeof juice>[1]>\n\n/**\n * Options for the `inlineCss` transformer. Accepts every Juice option plus a\n * handful of Maizzle-specific extras.\n */\nexport interface InlineCssOptions extends JuiceOptions {\n /**\n * Convert `0px`, `0em` etc. to `0` in inline styles.\n *\n * @default true\n */\n preferUnitlessValues?: boolean\n /**\n * CSS selectors to preserve in `<style>` tags, even after inlining.\n * Mapped to Juice's `preservedSelectors` option.\n *\n * @default []\n */\n safelist?: string[]\n /**\n * Additional CSS string to inline alongside `<style>` tag contents.\n * Mapped to Juice's `extraCss` option.\n */\n customCSS?: string\n /**\n * Duplicate CSS properties to HTML attributes.\n * Mapped to Juice's static `styleToAttribute` property.\n */\n styleToAttribute?: Record<string, string>\n /**\n * CSS properties to exclude from inlining.\n * Mapped to Juice's static `excludedProperties` property.\n */\n excludedProperties?: string[]\n /**\n * Elements that can receive `width` HTML attributes.\n * Mapped to Juice's static `widthElements` property.\n *\n * @default ['img', 'video']\n */\n widthElements?: string[]\n /**\n * Elements that can receive `height` HTML attributes.\n * Mapped to Juice's static `heightElements` property.\n *\n * @default ['img', 'video']\n */\n heightElements?: string[]\n /**\n * Template language code blocks to preserve during inlining.\n * Mapped to Juice's static `codeBlocks` property.\n */\n codeBlocks?: Record<string, { start: string; end: string }>\n}\n\n/**\n * Inline CSS from `<style>` tags into `style` attributes on matching elements.\n *\n * @param html HTML string to transform.\n * @param options Juice options plus Maizzle-specific extras.\n * @returns The transformed HTML string.\n *\n * @example\n * import { inlineCss } from '@maizzle/framework'\n *\n * const out = inlineCss('<style>.red{color:red}</style><p class=\"red\">x</p>', {\n * removeStyleTags: true,\n * })\n */\nexport function inlineCss(html: string, options: InlineCssOptions = {}): string {\n return serialize(inlineCssDom(parse(html), options))\n}\n\n/**\n * DOM-form of {@link inlineCss} used by the internal transformer pipeline.\n * Takes a parsed DOM, returns a parsed DOM — avoids the redundant\n * serialize/parse round-trips when chained with other transformers.\n */\nexport function inlineCssDom(dom: ChildNode[], options: InlineCssOptions = {}): ChildNode[] {\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 // Reset to defaults each call so a previous template's custom code blocks\n // don't accumulate on juice's module-global state, then add this call's.\n juice.codeBlocks = { ...DEFAULT_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 /**\n * Handle style tags with embed attributes. We add a marker attribute\n * that persists through the pipeline, then restore data-embed from\n * it after Juice runs. `amp-custom` (AMP4Email's CSS attribute)\n * is treated the same as embed: contents are preserved,\n * never inlined.\n */\n walk(dom, (node) => {\n const el = node as Element\n if (el.name === 'style' && el.attribs) {\n /**\n * `amp-custom` → tell juice to skip via data-embed, but don't mirror\n * back to `embed` (user wrote amp-custom, that's what stays in\n * output).\n */\n if ('amp-custom' in el.attribs && !('data-embed' in el.attribs)) {\n el.attribs['data-embed'] = ''\n }\n /**\n * Sync data-embed ↔ embed. Use `in` so presence-only attrs\n * (<style embed> → attribs.embed === '') still count.\n */\n if ('embed' in el.attribs && !('data-embed' in el.attribs)) {\n el.attribs['data-embed'] = ''\n }\n if ('data-embed' in el.attribs && !('embed' in el.attribs) && !('amp-custom' 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 ?? false,\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 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 /**\n * Restore `embed` from our marker so the purge step can detect\n * these tags and skip them. Drop `data-embed` (juice's name)\n * since it's redundant once `embed` is back, and let purge\n * strip `embed` itself at the end of its run.\n */\n walk(result, (node) => {\n const el = node as Element\n if (el.name === 'style' && el.attribs && 'data-maizzle-embed' in el.attribs) {\n /**\n * Only restore `embed` when the original signal was embed/data-embed —\n * an `amp-custom` style was tagged for juice's benefit only and\n * must not pick up a stray `embed` attribute in the rendered\n * output.\n */\n if (!('amp-custom' in el.attribs)) {\n el.attribs.embed = ''\n }\n delete el.attribs['data-embed']\n delete el.attribs['data-maizzle-embed']\n }\n })\n\n return result\n}\n"],"mappings":";;;;;;;AAIA,MAAM,sBAAsB,EAAE,GAAG,MAAM,WAAW;;;;;;;;;;;;;;;AAwElD,SAAgB,UAAU,MAAc,UAA4B,CAAC,GAAW;CAC9E,OAAO,UAAU,aAAa,MAAM,IAAI,GAAG,OAAO,CAAC;AACrD;;;;;;AAOA,SAAgB,aAAa,KAAkB,UAA4B,CAAC,GAAgB;CAC1F,MAAM,EACJ,uBAAuB,MACvB,UACA,YAAY,IACZ,kBACA,oBACA,eACA,gBACA,YACA,GAAG,qBACD;CAGJ,MAAM,mBAAmB,oBAAoB,CAAC;CAC9C,MAAM,qBAAqB,CAAC,eAAe,GAAI,sBAAsB,CAAC,CAAE;CACxE,MAAM,iBAAiB,iBAAiB,CAAC,OAAO,OAAO,EAAA,CAAG,KAAI,MAAK,EAAE,YAAY,CAAC;CAClF,MAAM,kBAAkB,kBAAkB,CAAC,OAAO,OAAO,EAAA,CAAG,KAAI,MAAK,EAAE,YAAY,CAAC;CAIpF,MAAM,aAAa,EAAE,GAAG,oBAAoB;CAC5C,IAAI,cAAc,OAAO,eAAe,UACtC,OAAO,QAAQ,UAAU,CAAC,CAAC,SAAS,CAAC,KAAK,WAAW;EACnD,IAAI,MAAM,SAAS,MAAM,KACvB,MAAM,WAAW,OAAO;CAE5B,CAAC;;;;;;;;CAUH,KAAK,MAAM,SAAS;EAClB,MAAM,KAAK;EACX,IAAI,GAAG,SAAS,WAAW,GAAG,SAAS;;;;;;GAMrC,IAAI,gBAAgB,GAAG,WAAW,EAAE,gBAAgB,GAAG,UACrD,GAAG,QAAQ,gBAAgB;;;;;GAM7B,IAAI,WAAW,GAAG,WAAW,EAAE,gBAAgB,GAAG,UAChD,GAAG,QAAQ,gBAAgB;GAE7B,IAAI,gBAAgB,GAAG,WAAW,EAAE,WAAW,GAAG,YAAY,EAAE,gBAAgB,GAAG,UACjF,GAAG,QAAQ,QAAQ;GAIrB,IAAI,gBAAgB,GAAG,SACrB,GAAG,QAAQ,wBAAwB;EAEvC;CACF,CAAC;CAGD,MAAM,aAAa,UAAU,GAAG;CAEhC,IAAI;CAEJ,IAAI;EAYF,cAAc,MAAM,YAAY;GAV9B,iBAAiB,iBAAiB,mBAAmB;GACrD,wBAAwB,iBAAiB,0BAA0B;GACnE,sBAAsB,iBAAiB,wBAAwB;GAC/D,uBAAuB,iBAAiB,yBAAyB;GACjE,oBAAoB,YAAY,CAAC;GACjC,GAAG,YAAY,EAAE,UAAU,UAAU,IAAI,CAAC;GAC1C,2BAA2B,iBAAiB,6BAA6B;GACzE,GAAG;EAGsC,CAAC;CAC9C,QAAQ;EAEN,OAAO;CACT;CAEA,MAAM,SAAS,MAAM,WAAW;CAEhC,IAAI,sBACF,KAAK,SAAS,SAAS;EACrB,MAAM,KAAK;EACX,IAAI,GAAG,SAAS,OACd,GAAG,QAAQ,QAAQ,GAAG,QAAQ,MAAM,QAClC,4DACA,GACF;CAEJ,CAAC;;;;;;;CASH,KAAK,SAAS,SAAS;EACrB,MAAM,KAAK;EACX,IAAI,GAAG,SAAS,WAAW,GAAG,WAAW,wBAAwB,GAAG,SAAS;;;;;;;GAO3E,IAAI,EAAE,gBAAgB,GAAG,UACvB,GAAG,QAAQ,QAAQ;GAErB,OAAO,GAAG,QAAQ;GAClB,OAAO,GAAG,QAAQ;EACpB;CACF,CAAC;CAED,OAAO;AACT"}
1
+ {"version":3,"file":"inlineCss.js","names":[],"sources":["../../src/transformers/inlineCss.ts"],"sourcesContent":["import juice from 'juice'\nimport { walk, parse, serialize } from '../utils/ast/index.ts'\n\n/** Juice's built-in code blocks, captured before any per-call mutation. */\nconst DEFAULT_CODE_BLOCKS = { ...juice.codeBlocks }\nimport type { ChildNode, Element } from 'domhandler'\ntype JuiceOptions = NonNullable<Parameters<typeof juice>[1]>\n\n/**\n * Options for the `inlineCss` transformer. Accepts every Juice option plus a\n * handful of Maizzle-specific extras.\n */\nexport interface InlineCssOptions extends JuiceOptions {\n /**\n * Convert `0px`, `0em` etc. to `0` in inline styles.\n *\n * @default true\n */\n preferUnitlessValues?: boolean\n /**\n * CSS selectors to preserve in `<style>` tags, even after inlining.\n * Mapped to Juice's `preservedSelectors` option.\n *\n * @default []\n */\n safelist?: string[]\n /**\n * Additional CSS string to inline alongside `<style>` tag contents.\n * Mapped to Juice's `extraCss` option.\n */\n customCSS?: string\n /**\n * Duplicate CSS properties to HTML attributes.\n * Mapped to Juice's static `styleToAttribute` property.\n */\n styleToAttribute?: Record<string, string>\n /**\n * CSS properties to exclude from inlining.\n * Mapped to Juice's static `excludedProperties` property.\n */\n excludedProperties?: string[]\n /**\n * Elements that can receive `width` HTML attributes.\n * Mapped to Juice's static `widthElements` property.\n *\n * @default ['img', 'video']\n */\n widthElements?: string[]\n /**\n * Elements that can receive `height` HTML attributes.\n * Mapped to Juice's static `heightElements` property.\n *\n * @default ['img', 'video']\n */\n heightElements?: string[]\n /**\n * Template language code blocks to preserve during inlining.\n * Mapped to Juice's static `codeBlocks` property.\n */\n codeBlocks?: Record<string, { start: string; end: string }>\n}\n\n/**\n * Inline CSS from `<style>` tags into `style` attributes on matching elements.\n *\n * @param html HTML string to transform.\n * @param options Juice options plus Maizzle-specific extras.\n * @returns The transformed HTML string.\n *\n * @example\n * import { inlineCss } from '@maizzle/framework'\n *\n * const out = inlineCss('<style>.red{color:red}</style><p class=\"red\">x</p>', {\n * removeStyleTags: true,\n * })\n */\nexport function inlineCss(html: string, options: InlineCssOptions = {}): string {\n return serialize(inlineCssDom(parse(html), options))\n}\n\n/**\n * DOM-form of {@link inlineCss} used by the internal transformer pipeline.\n * Takes a parsed DOM, returns a parsed DOM — avoids the redundant\n * serialize/parse round-trips when chained with other transformers.\n */\nexport function inlineCssDom(dom: ChildNode[], options: InlineCssOptions = {}): ChildNode[] {\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 // Reset to defaults each call so a previous template's custom code blocks\n // don't accumulate on juice's module-global state, then add this call's.\n juice.codeBlocks = { ...DEFAULT_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 /**\n * Handle style tags with embed attributes. We add a marker attribute\n * that persists through the pipeline, then restore data-embed from\n * it after Juice runs. `amp-custom` (AMP4Email's CSS attribute)\n * is treated the same as embed: contents are preserved,\n * never inlined.\n */\n walk(dom, (node) => {\n const el = node as Element\n if (el.name === 'style' && el.attribs) {\n /**\n * `amp-custom` → tell juice to skip via data-embed, but don't mirror\n * back to `embed` (user wrote amp-custom, that's what stays in\n * output).\n */\n if ('amp-custom' in el.attribs && !('data-embed' in el.attribs)) {\n el.attribs['data-embed'] = ''\n }\n /**\n * Sync data-embed ↔ embed. Use `in` so presence-only attrs\n * (<style embed> → attribs.embed === '') still count.\n */\n if ('embed' in el.attribs && !('data-embed' in el.attribs)) {\n el.attribs['data-embed'] = ''\n }\n if ('data-embed' in el.attribs && !('embed' in el.attribs) && !('amp-custom' 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 ?? false,\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 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 /**\n * Restore `embed` from our marker so the purge step can detect\n * these tags and skip them. Drop `data-embed` (juice's name)\n * since it's redundant once `embed` is back, and let purge\n * strip `embed` itself at the end of its run.\n */\n walk(result, (node) => {\n const el = node as Element\n if (el.name === 'style' && el.attribs && 'data-maizzle-embed' in el.attribs) {\n /**\n * Only restore `embed` when the original signal was embed/data-embed —\n * an `amp-custom` style was tagged for juice's benefit only and\n * must not pick up a stray `embed` attribute in the rendered\n * output.\n */\n if (!('amp-custom' in el.attribs)) {\n el.attribs.embed = ''\n }\n delete el.attribs['data-embed']\n delete el.attribs['data-maizzle-embed']\n }\n })\n\n return result\n}\n"],"mappings":";;;;;;;AAIA,MAAM,sBAAsB,EAAE,GAAG,MAAM,WAAW;;;;;;;;;;;;;;;AAwElD,SAAgB,UAAU,MAAc,UAA4B,CAAC,GAAW;CAC9E,OAAO,UAAU,aAAa,MAAM,IAAI,GAAG,OAAO,CAAC;AACrD;;;;;;AAOA,SAAgB,aAAa,KAAkB,UAA4B,CAAC,GAAgB;CAC1F,MAAM,EACJ,uBAAuB,MACvB,UACA,YAAY,IACZ,kBACA,oBACA,eACA,gBACA,YACA,GAAG,qBACD;CAGJ,MAAM,mBAAmB,oBAAoB,CAAC;CAC9C,MAAM,qBAAqB,CAAC,eAAe,GAAI,sBAAsB,CAAC,CAAE;CACxE,MAAM,iBAAiB,iBAAiB,CAAC,OAAO,OAAO,EAAA,CAAG,KAAI,MAAK,EAAE,YAAY,CAAC;CAClF,MAAM,kBAAkB,kBAAkB,CAAC,OAAO,OAAO,EAAA,CAAG,KAAI,MAAK,EAAE,YAAY,CAAC;CAIpF,MAAM,aAAa,EAAE,GAAG,oBAAoB;CAC5C,IAAI,cAAc,OAAO,eAAe,UACtC,OAAO,QAAQ,UAAU,CAAC,CAAC,SAAS,CAAC,KAAK,WAAW;EACnD,IAAI,MAAM,SAAS,MAAM,KACvB,MAAM,WAAW,OAAO;CAE5B,CAAC;;;;;;;;CAUH,KAAK,MAAM,SAAS;EAClB,MAAM,KAAK;EACX,IAAI,GAAG,SAAS,WAAW,GAAG,SAAS;;;;;;GAMrC,IAAI,gBAAgB,GAAG,WAAW,EAAE,gBAAgB,GAAG,UACrD,GAAG,QAAQ,gBAAgB;;;;;GAM7B,IAAI,WAAW,GAAG,WAAW,EAAE,gBAAgB,GAAG,UAChD,GAAG,QAAQ,gBAAgB;GAE7B,IAAI,gBAAgB,GAAG,WAAW,EAAE,WAAW,GAAG,YAAY,EAAE,gBAAgB,GAAG,UACjF,GAAG,QAAQ,QAAQ;GAIrB,IAAI,gBAAgB,GAAG,SACrB,GAAG,QAAQ,wBAAwB;EAEvC;CACF,CAAC;CAGD,MAAM,aAAa,UAAU,GAAG;CAEhC,IAAI;CAEJ,IAAI;EACF,MAAM,eAA6B;GACjC,iBAAiB,iBAAiB,mBAAmB;GACrD,wBAAwB,iBAAiB,0BAA0B;GACnE,sBAAsB,iBAAiB,wBAAwB;GAC/D,uBAAuB,iBAAiB,yBAAyB;GACjE,oBAAoB,YAAY,CAAC;GACjC,GAAG,YAAY,EAAE,UAAU,UAAU,IAAI,CAAC;GAC1C,2BAA2B,iBAAiB,6BAA6B;GACzE,GAAG;EACL;EAEA,cAAc,MAAM,YAAY,YAAY;CAC9C,QAAQ;EAEN,OAAO;CACT;CAEA,MAAM,SAAS,MAAM,WAAW;CAEhC,IAAI,sBACF,KAAK,SAAS,SAAS;EACrB,MAAM,KAAK;EACX,IAAI,GAAG,SAAS,OACd,GAAG,QAAQ,QAAQ,GAAG,QAAQ,MAAM,QAClC,4DACA,GACF;CAEJ,CAAC;;;;;;;CASH,KAAK,SAAS,SAAS;EACrB,MAAM,KAAK;EACX,IAAI,GAAG,SAAS,WAAW,GAAG,WAAW,wBAAwB,GAAG,SAAS;;;;;;;GAO3E,IAAI,EAAE,gBAAgB,GAAG,UACvB,GAAG,QAAQ,QAAQ;GAErB,OAAO,GAAG,QAAQ;GAClB,OAAO,GAAG,QAAQ;EACpB;CACF,CAAC;CAED,OAAO;AACT"}
@@ -73,7 +73,8 @@ async function inlineLinkDom(dom, filePath) {
73
73
  } else {
74
74
  if (!filePath) continue;
75
75
  try {
76
- css = readFileSync(resolve(dirname(filePath), href), "utf8");
76
+ const absolutePath = resolve(dirname(filePath), href);
77
+ css = readFileSync(absolutePath, "utf8");
77
78
  } catch {
78
79
  continue;
79
80
  }
@@ -1 +1 @@
1
- {"version":3,"file":"inlineLink.js","names":["parse"],"sources":["../../src/transformers/inlineLink.ts"],"sourcesContent":["import { readFileSync } from 'node:fs'\nimport { resolve, dirname } from 'node:path'\nimport type { ChildNode, Element } from 'domhandler'\nimport { parse, serialize, walk } from '../utils/ast/index.ts'\n\n/**\n * Inline `<link rel=\"stylesheet\">` tags as `<style>` tags.\n *\n * - Local file paths are inlined when `filePath` is provided (resolved\n * relative to it).\n * - Remote URLs (`http://` / `https://`) are only inlined when the link\n * carries an `inline` attribute, e.g. `<link rel=\"stylesheet\" inline href=\"…\">`.\n *\n * @param html HTML string to transform.\n * @param filePath Path of the source file the HTML came from, used as the\n * base for resolving relative `href` values. Required for\n * local-file inlining; remote `inline` links work without it.\n * @returns The transformed HTML string.\n *\n * @example\n * import { inlineLink } from '@maizzle/framework'\n *\n * const out = await inlineLink(\n * '<link rel=\"stylesheet\" href=\"./styles.css\">',\n * '/path/to/template.html',\n * )\n */\nexport async function inlineLink(html: string, filePath?: string): Promise<string> {\n return serialize(await inlineLinkDom(parse(html), filePath))\n}\n\n/**\n * DOM-form of {@link inlineLink} used by the internal transformer pipeline.\n * Takes a parsed DOM, returns a parsed DOM — avoids redundant\n * serialize/parse round-trips when chained with other transformers.\n */\nexport async function inlineLinkDom(dom: ChildNode[], filePath?: string): Promise<ChildNode[]> {\n const links: { node: Element; parent: ChildNode; index: number }[] = []\n\n walk(dom, (node) => {\n if ((node as Element).name !== 'link') return\n\n const el = node as Element\n const attrs = el.attribs\n\n if (attrs.rel !== 'stylesheet' || !attrs.href) return\n\n const parent = el.parent as ChildNode\n\n if (parent && 'children' in parent) {\n const index = (parent.children as ChildNode[]).indexOf(el)\n if (index !== -1) {\n links.push({ node: el, parent, index })\n }\n } else {\n // Top-level node\n const index = dom.indexOf(el)\n if (index !== -1) {\n links.push({ node: el, parent: null as any, index })\n }\n }\n })\n\n for (const { node, parent, index } of links) {\n const href = node.attribs.href\n const isRemote = href.startsWith('http://') || href.startsWith('https://')\n\n let css: string | undefined\n\n if (isRemote) {\n if (!('inline' in node.attribs)) continue\n\n try {\n const response = await fetch(href)\n css = await response.text()\n } catch {\n continue\n }\n } else {\n if (!filePath) continue\n\n try {\n const absolutePath = resolve(dirname(filePath), href)\n css = readFileSync(absolutePath, 'utf8')\n } catch {\n continue\n }\n }\n\n const styleNode = {\n type: 'tag',\n name: 'style',\n attribs: {},\n children: [{\n type: 'text',\n data: css,\n parent: null as any,\n }],\n parent: parent || null,\n } as any\n\n // Set parent reference on the text child\n styleNode.children[0].parent = styleNode\n\n const siblings = parent && 'children' in parent\n ? parent.children as ChildNode[]\n : dom\n\n siblings.splice(index, 1, styleNode)\n }\n\n return dom\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,eAAsB,WAAW,MAAc,UAAoC;CACjF,OAAO,UAAU,MAAM,cAAcA,QAAM,IAAI,GAAG,QAAQ,CAAC;AAC7D;;;;;;AAOA,eAAsB,cAAc,KAAkB,UAAyC;CAC7F,MAAM,QAA+D,CAAC;CAEtE,KAAK,MAAM,SAAS;EAClB,IAAK,KAAiB,SAAS,QAAQ;EAEvC,MAAM,KAAK;EACX,MAAM,QAAQ,GAAG;EAEjB,IAAI,MAAM,QAAQ,gBAAgB,CAAC,MAAM,MAAM;EAE/C,MAAM,SAAS,GAAG;EAElB,IAAI,UAAU,cAAc,QAAQ;GAClC,MAAM,QAAS,OAAO,SAAyB,QAAQ,EAAE;GACzD,IAAI,UAAU,IACZ,MAAM,KAAK;IAAE,MAAM;IAAI;IAAQ;GAAM,CAAC;EAE1C,OAAO;GAEL,MAAM,QAAQ,IAAI,QAAQ,EAAE;GAC5B,IAAI,UAAU,IACZ,MAAM,KAAK;IAAE,MAAM;IAAI,QAAQ;IAAa;GAAM,CAAC;EAEvD;CACF,CAAC;CAED,KAAK,MAAM,EAAE,MAAM,QAAQ,WAAW,OAAO;EAC3C,MAAM,OAAO,KAAK,QAAQ;EAC1B,MAAM,WAAW,KAAK,WAAW,SAAS,KAAK,KAAK,WAAW,UAAU;EAEzE,IAAI;EAEJ,IAAI,UAAU;GACZ,IAAI,EAAE,YAAY,KAAK,UAAU;GAEjC,IAAI;IAEF,MAAM,OAAM,MADW,MAAM,IAAI,EAAA,CACZ,KAAK;GAC5B,QAAQ;IACN;GACF;EACF,OAAO;GACL,IAAI,CAAC,UAAU;GAEf,IAAI;IAEF,MAAM,aADe,QAAQ,QAAQ,QAAQ,GAAG,IAClB,GAAG,MAAM;GACzC,QAAQ;IACN;GACF;EACF;EAEA,MAAM,YAAY;GAChB,MAAM;GACN,MAAM;GACN,SAAS,CAAC;GACV,UAAU,CAAC;IACT,MAAM;IACN,MAAM;IACN,QAAQ;GACV,CAAC;GACD,QAAQ,UAAU;EACpB;EAGA,UAAU,SAAS,EAAE,CAAC,SAAS;EAM/B,CAJiB,UAAU,cAAc,SACrC,OAAO,WACP,IAAA,CAEK,OAAO,OAAO,GAAG,SAAS;CACrC;CAEA,OAAO;AACT"}
1
+ {"version":3,"file":"inlineLink.js","names":["parse"],"sources":["../../src/transformers/inlineLink.ts"],"sourcesContent":["import { readFileSync } from 'node:fs'\nimport { resolve, dirname } from 'node:path'\nimport type { ChildNode, Element } from 'domhandler'\nimport { parse, serialize, walk } from '../utils/ast/index.ts'\n\n/**\n * Inline `<link rel=\"stylesheet\">` tags as `<style>` tags.\n *\n * - Local file paths are inlined when `filePath` is provided (resolved\n * relative to it).\n * - Remote URLs (`http://` / `https://`) are only inlined when the link\n * carries an `inline` attribute, e.g. `<link rel=\"stylesheet\" inline href=\"…\">`.\n *\n * @param html HTML string to transform.\n * @param filePath Path of the source file the HTML came from, used as the\n * base for resolving relative `href` values. Required for\n * local-file inlining; remote `inline` links work without it.\n * @returns The transformed HTML string.\n *\n * @example\n * import { inlineLink } from '@maizzle/framework'\n *\n * const out = await inlineLink(\n * '<link rel=\"stylesheet\" href=\"./styles.css\">',\n * '/path/to/template.html',\n * )\n */\nexport async function inlineLink(html: string, filePath?: string): Promise<string> {\n return serialize(await inlineLinkDom(parse(html), filePath))\n}\n\n/**\n * DOM-form of {@link inlineLink} used by the internal transformer pipeline.\n * Takes a parsed DOM, returns a parsed DOM — avoids redundant\n * serialize/parse round-trips when chained with other transformers.\n */\nexport async function inlineLinkDom(dom: ChildNode[], filePath?: string): Promise<ChildNode[]> {\n const links: { node: Element; parent: ChildNode; index: number }[] = []\n\n walk(dom, (node) => {\n if ((node as Element).name !== 'link') return\n\n const el = node as Element\n const attrs = el.attribs\n\n if (attrs.rel !== 'stylesheet' || !attrs.href) return\n\n const parent = el.parent as ChildNode\n\n if (parent && 'children' in parent) {\n const index = (parent.children as ChildNode[]).indexOf(el)\n if (index !== -1) {\n links.push({ node: el, parent, index })\n }\n } else {\n // Top-level node\n const index = dom.indexOf(el)\n if (index !== -1) {\n links.push({ node: el, parent: null as any, index })\n }\n }\n })\n\n for (const { node, parent, index } of links) {\n const href = node.attribs.href\n const isRemote = href.startsWith('http://') || href.startsWith('https://')\n\n let css: string | undefined\n\n if (isRemote) {\n if (!('inline' in node.attribs)) continue\n\n try {\n const response = await fetch(href)\n css = await response.text()\n } catch {\n continue\n }\n } else {\n if (!filePath) continue\n\n try {\n const absolutePath = resolve(dirname(filePath), href)\n css = readFileSync(absolutePath, 'utf8')\n } catch {\n continue\n }\n }\n\n const styleNode = {\n type: 'tag',\n name: 'style',\n attribs: {},\n children: [{\n type: 'text',\n data: css,\n parent: null as any,\n }],\n parent: parent || null,\n } as any\n\n // Set parent reference on the text child\n styleNode.children[0].parent = styleNode\n\n const siblings = parent && 'children' in parent\n ? parent.children as ChildNode[]\n : dom\n\n siblings.splice(index, 1, styleNode)\n }\n\n return dom\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,eAAsB,WAAW,MAAc,UAAoC;CACjF,OAAO,UAAU,MAAM,cAAcA,QAAM,IAAI,GAAG,QAAQ,CAAC;AAC7D;;;;;;AAOA,eAAsB,cAAc,KAAkB,UAAyC;CAC7F,MAAM,QAA+D,CAAC;CAEtE,KAAK,MAAM,SAAS;EAClB,IAAK,KAAiB,SAAS,QAAQ;EAEvC,MAAM,KAAK;EACX,MAAM,QAAQ,GAAG;EAEjB,IAAI,MAAM,QAAQ,gBAAgB,CAAC,MAAM,MAAM;EAE/C,MAAM,SAAS,GAAG;EAElB,IAAI,UAAU,cAAc,QAAQ;GAClC,MAAM,QAAS,OAAO,SAAyB,QAAQ,EAAE;GACzD,IAAI,UAAU,IACZ,MAAM,KAAK;IAAE,MAAM;IAAI;IAAQ;GAAM,CAAC;EAE1C,OAAO;GAEL,MAAM,QAAQ,IAAI,QAAQ,EAAE;GAC5B,IAAI,UAAU,IACZ,MAAM,KAAK;IAAE,MAAM;IAAI,QAAQ;IAAa;GAAM,CAAC;EAEvD;CACF,CAAC;CAED,KAAK,MAAM,EAAE,MAAM,QAAQ,WAAW,OAAO;EAC3C,MAAM,OAAO,KAAK,QAAQ;EAC1B,MAAM,WAAW,KAAK,WAAW,SAAS,KAAK,KAAK,WAAW,UAAU;EAEzE,IAAI;EAEJ,IAAI,UAAU;GACZ,IAAI,EAAE,YAAY,KAAK,UAAU;GAEjC,IAAI;IAEF,MAAM,OAAM,MADW,MAAM,IAAI,EAAA,CACZ,KAAK;GAC5B,QAAQ;IACN;GACF;EACF,OAAO;GACL,IAAI,CAAC,UAAU;GAEf,IAAI;IACF,MAAM,eAAe,QAAQ,QAAQ,QAAQ,GAAG,IAAI;IACpD,MAAM,aAAa,cAAc,MAAM;GACzC,QAAQ;IACN;GACF;EACF;EAEA,MAAM,YAAY;GAChB,MAAM;GACN,MAAM;GACN,SAAS,CAAC;GACV,UAAU,CAAC;IACT,MAAM;IACN,MAAM;IACN,QAAQ;GACV,CAAC;GACD,QAAQ,UAAU;EACpB;EAGA,UAAU,SAAS,EAAE,CAAC,SAAS;EAM/B,CAJiB,UAAU,cAAc,SACrC,OAAO,WACP,IAAA,CAEK,OAAO,OAAO,GAAG,SAAS;CACrC;CAEA,OAAO;AACT"}
@@ -17,7 +17,8 @@ const DEFAULT_OPTIONS = { removeLineBreaks: true };
17
17
  * const tight = minify('<p> hello </p>', { removeIndentations: true })
18
18
  */
19
19
  function minify(html, options = {}) {
20
- return crush(html, defu$1(options, DEFAULT_OPTIONS)).result;
20
+ const merged = defu$1(options, DEFAULT_OPTIONS);
21
+ return crush(html, merged).result;
21
22
  }
22
23
  //#endregion
23
24
  export { minify };
@@ -1 +1 @@
1
- {"version":3,"file":"minify.js","names":["merge"],"sources":["../../src/transformers/minify.ts"],"sourcesContent":["import { crush } from 'html-crush'\nimport { defu as merge } from 'defu'\nimport type { Opts as HtmlCrushOptions } from 'html-crush'\n\nexport type { Opts as MinifyOptions } from 'html-crush'\n\nconst DEFAULT_OPTIONS: Partial<HtmlCrushOptions> = {\n removeLineBreaks: true,\n}\n\n/**\n * Minify an HTML string using `html-crush`. Maizzle's only default that\n * differs from html-crush's own defaults is `removeLineBreaks: true`.\n *\n * @param html HTML string to minify.\n * @param options [html-crush options](https://codsen.com/os/html-crush) merged\n * on top of the Maizzle defaults.\n * @returns The minified HTML string.\n *\n * @example\n * import { minify } from '@maizzle/framework'\n *\n * const tight = minify('<p> hello </p>', { removeIndentations: true })\n */\nexport function minify(html: string, options: Partial<HtmlCrushOptions> = {}): string {\n const merged = merge(options, DEFAULT_OPTIONS) as Partial<HtmlCrushOptions>\n return crush(html, merged).result\n}\n"],"mappings":";;;AAMA,MAAM,kBAA6C,EACjD,kBAAkB,KACpB;;;;;;;;;;;;;;;AAgBA,SAAgB,OAAO,MAAc,UAAqC,CAAC,GAAW;CAEpF,OAAO,MAAM,MADEA,OAAM,SAAS,eACN,CAAC,CAAC,CAAC;AAC7B"}
1
+ {"version":3,"file":"minify.js","names":["merge"],"sources":["../../src/transformers/minify.ts"],"sourcesContent":["import { crush } from 'html-crush'\nimport { defu as merge } from 'defu'\nimport type { Opts as HtmlCrushOptions } from 'html-crush'\n\nexport type { Opts as MinifyOptions } from 'html-crush'\n\nconst DEFAULT_OPTIONS: Partial<HtmlCrushOptions> = {\n removeLineBreaks: true,\n}\n\n/**\n * Minify an HTML string using `html-crush`. Maizzle's only default that\n * differs from html-crush's own defaults is `removeLineBreaks: true`.\n *\n * @param html HTML string to minify.\n * @param options [html-crush options](https://codsen.com/os/html-crush) merged\n * on top of the Maizzle defaults.\n * @returns The minified HTML string.\n *\n * @example\n * import { minify } from '@maizzle/framework'\n *\n * const tight = minify('<p> hello </p>', { removeIndentations: true })\n */\nexport function minify(html: string, options: Partial<HtmlCrushOptions> = {}): string {\n const merged = merge(options, DEFAULT_OPTIONS) as Partial<HtmlCrushOptions>\n return crush(html, merged).result\n}\n"],"mappings":";;;AAMA,MAAM,kBAA6C,EACjD,kBAAkB,KACpB;;;;;;;;;;;;;;;AAgBA,SAAgB,OAAO,MAAc,UAAqC,CAAC,GAAW;CACpF,MAAM,SAASA,OAAM,SAAS,eAAe;CAC7C,OAAO,MAAM,MAAM,MAAM,CAAC,CAAC;AAC7B"}
@@ -62,7 +62,8 @@ async function tailwindComponent(dom, blocks, config, filePath) {
62
62
  */
63
63
  for (const meta of map.values()) {
64
64
  if (meta.nested) continue;
65
- const css = (await compileTailwindCss(buildCssInput(meta.configCss, meta.classes), config, `${fromPath}?tw=${meta.id}`)).trim();
65
+ const cssInput = buildCssInput(meta.configCss, meta.classes);
66
+ const css = (await compileTailwindCss(cssInput, config, `${fromPath}?tw=${meta.id}`)).trim();
66
67
  if (!css) continue;
67
68
  const styleNode = {
68
69
  type: "tag",
@@ -1 +1 @@
1
- {"version":3,"file":"tailwindComponent.js","names":[],"sources":["../../src/transformers/tailwindComponent.ts"],"sourcesContent":["import { resolve } from 'pathe'\nimport type { ChildNode, Element, Comment } from 'domhandler'\nimport { walk } from '../utils/ast/index.ts'\nimport { compileTailwindCss } from '../utils/compileTailwindCss.ts'\nimport type { TailwindBlock } from '../composables/renderContext.ts'\nimport type { MaizzleConfig } from '../types/config.ts'\n\nconst DEFAULT_SEED = '@import \"@maizzle/tailwindcss\" source(none);'\n\ninterface BlockMeta {\n id: string\n configCss?: string\n nested: boolean\n classes: Set<string>\n}\n\nconst OPEN_RE = /^mz-tw:(\\S+)$/\nconst CLOSE_RE = /^\\/mz-tw:(\\S+)$/\n\n/**\n * Compile Tailwind CSS for each top-level <Tailwind> block in the render\n * context. Nested <Tailwind> instances are flattened: their classes flow\n * up to the outermost block, their `#config` slot (if any) is ignored.\n * One <style> per outermost block is appended to <head>; marker comments\n * are stripped after.\n */\nexport async function tailwindComponent(\n dom: ChildNode[],\n blocks: TailwindBlock[],\n config: MaizzleConfig,\n filePath?: string,\n): Promise<ChildNode[]> {\n if (!blocks.length) return dom\n\n const map = new Map<string, BlockMeta>()\n for (const b of blocks) {\n map.set(b.id, { id: b.id, configCss: b.css, nested: false, classes: new Set() })\n }\n\n const stack: string[] = []\n const markers: Comment[] = []\n\n walk(dom, (node) => {\n if (node.type === 'comment') {\n const data = (node as Comment).data\n const open = data.match(OPEN_RE)\n const close = data.match(CLOSE_RE)\n if (open) {\n const id = open[1]\n const meta = map.get(id)\n if (meta && stack.length > 0) meta.nested = true\n if (meta) stack.push(id)\n markers.push(node as Comment)\n } else if (close) {\n const id = close[1]\n if (stack[stack.length - 1] === id) stack.pop()\n markers.push(node as Comment)\n }\n return\n }\n\n const el = node as Element\n /**\n * Always assign to the OUTERMOST active marker (stack[0]) so nested\n * <Tailwind> blocks merge their classes into the parent's scope.\n */\n if (el.attribs?.class && stack.length > 0) {\n map.get(stack[0])!.classes.add(el.attribs.class)\n }\n })\n\n const fromPath = filePath ?? resolve(process.cwd(), 'template.vue')\n\n let head: Element | undefined\n walk(dom, (n) => {\n if (!head && (n as Element).name === 'head') head = n as Element\n })\n\n if (!head) {\n throw new Error('`Tailwind` component requires `Head` component to be present in the template.')\n }\n\n /**\n * Compile + inject one <style raw> per outermost block. `raw` opts\n * the existing tailwindcss transformer out of recompiling\n * already-compiled CSS.\n */\n for (const meta of map.values()) {\n if (meta.nested) continue\n\n const cssInput = buildCssInput(meta.configCss, meta.classes)\n const css = (await compileTailwindCss(cssInput, config, `${fromPath}?tw=${meta.id}`)).trim()\n if (!css) continue\n\n const styleNode: Element = {\n type: 'tag',\n name: 'style',\n attribs: { raw: '' },\n children: [],\n parent: head,\n prev: null,\n next: null,\n } as any\n\n const textNode = {\n type: 'text',\n data: css,\n parent: styleNode,\n prev: null,\n next: null,\n } as any\n\n styleNode.children = [textNode]\n head.children.push(styleNode)\n }\n\n // Strip marker comments from their parents\n for (const c of markers) {\n const parent = c.parent as Element | null\n if (!parent?.children) continue\n const i = parent.children.indexOf(c)\n if (i >= 0) parent.children.splice(i, 1)\n }\n\n return dom\n}\n\nfunction buildCssInput(configCss: string | undefined, classes: Set<string>): string {\n const seed = configCss ?? DEFAULT_SEED\n\n if (!classes.size) return seed\n\n const inline = [...classes].join(' ').replace(/\"/g, '\\\\\"')\n return `${seed}\\n@source inline(\"${inline}\");`\n}\n"],"mappings":";;;;;AAOA,MAAM,eAAe;AASrB,MAAM,UAAU;AAChB,MAAM,WAAW;;;;;;;;AASjB,eAAsB,kBACpB,KACA,QACA,QACA,UACsB;CACtB,IAAI,CAAC,OAAO,QAAQ,OAAO;CAE3B,MAAM,sBAAM,IAAI,IAAuB;CACvC,KAAK,MAAM,KAAK,QACd,IAAI,IAAI,EAAE,IAAI;EAAE,IAAI,EAAE;EAAI,WAAW,EAAE;EAAK,QAAQ;EAAO,yBAAS,IAAI,IAAI;CAAE,CAAC;CAGjF,MAAM,QAAkB,CAAC;CACzB,MAAM,UAAqB,CAAC;CAE5B,KAAK,MAAM,SAAS;EAClB,IAAI,KAAK,SAAS,WAAW;GAC3B,MAAM,OAAQ,KAAiB;GAC/B,MAAM,OAAO,KAAK,MAAM,OAAO;GAC/B,MAAM,QAAQ,KAAK,MAAM,QAAQ;GACjC,IAAI,MAAM;IACR,MAAM,KAAK,KAAK;IAChB,MAAM,OAAO,IAAI,IAAI,EAAE;IACvB,IAAI,QAAQ,MAAM,SAAS,GAAG,KAAK,SAAS;IAC5C,IAAI,MAAM,MAAM,KAAK,EAAE;IACvB,QAAQ,KAAK,IAAe;GAC9B,OAAO,IAAI,OAAO;IAChB,MAAM,KAAK,MAAM;IACjB,IAAI,MAAM,MAAM,SAAS,OAAO,IAAI,MAAM,IAAI;IAC9C,QAAQ,KAAK,IAAe;GAC9B;GACA;EACF;EAEA,MAAM,KAAK;;;;;EAKX,IAAI,GAAG,SAAS,SAAS,MAAM,SAAS,GACtC,IAAI,IAAI,MAAM,EAAE,CAAC,CAAE,QAAQ,IAAI,GAAG,QAAQ,KAAK;CAEnD,CAAC;CAED,MAAM,WAAW,YAAY,QAAQ,QAAQ,IAAI,GAAG,cAAc;CAElE,IAAI;CACJ,KAAK,MAAM,MAAM;EACf,IAAI,CAAC,QAAS,EAAc,SAAS,QAAQ,OAAO;CACtD,CAAC;CAED,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,+EAA+E;;;;;;CAQjG,KAAK,MAAM,QAAQ,IAAI,OAAO,GAAG;EAC/B,IAAI,KAAK,QAAQ;EAGjB,MAAM,OAAO,MAAM,mBADF,cAAc,KAAK,WAAW,KAAK,OACP,GAAG,QAAQ,GAAG,SAAS,MAAM,KAAK,IAAI,EAAA,CAAG,KAAK;EAC3F,IAAI,CAAC,KAAK;EAEV,MAAM,YAAqB;GACzB,MAAM;GACN,MAAM;GACN,SAAS,EAAE,KAAK,GAAG;GACnB,UAAU,CAAC;GACX,QAAQ;GACR,MAAM;GACN,MAAM;EACR;EAUA,UAAU,WAAW,CAAC;GAPpB,MAAM;GACN,MAAM;GACN,QAAQ;GACR,MAAM;GACN,MAAM;EAGqB,CAAC;EAC9B,KAAK,SAAS,KAAK,SAAS;CAC9B;CAGA,KAAK,MAAM,KAAK,SAAS;EACvB,MAAM,SAAS,EAAE;EACjB,IAAI,CAAC,QAAQ,UAAU;EACvB,MAAM,IAAI,OAAO,SAAS,QAAQ,CAAC;EACnC,IAAI,KAAK,GAAG,OAAO,SAAS,OAAO,GAAG,CAAC;CACzC;CAEA,OAAO;AACT;AAEA,SAAS,cAAc,WAA+B,SAA8B;CAClF,MAAM,OAAO,aAAa;CAE1B,IAAI,CAAC,QAAQ,MAAM,OAAO;CAG1B,OAAO,GAAG,KAAK,oBADA,CAAC,GAAG,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,QAAQ,MAAM,MACZ,EAAE;AAC5C"}
1
+ {"version":3,"file":"tailwindComponent.js","names":[],"sources":["../../src/transformers/tailwindComponent.ts"],"sourcesContent":["import { resolve } from 'pathe'\nimport type { ChildNode, Element, Comment } from 'domhandler'\nimport { walk } from '../utils/ast/index.ts'\nimport { compileTailwindCss } from '../utils/compileTailwindCss.ts'\nimport type { TailwindBlock } from '../composables/renderContext.ts'\nimport type { MaizzleConfig } from '../types/config.ts'\n\nconst DEFAULT_SEED = '@import \"@maizzle/tailwindcss\" source(none);'\n\ninterface BlockMeta {\n id: string\n configCss?: string\n nested: boolean\n classes: Set<string>\n}\n\nconst OPEN_RE = /^mz-tw:(\\S+)$/\nconst CLOSE_RE = /^\\/mz-tw:(\\S+)$/\n\n/**\n * Compile Tailwind CSS for each top-level <Tailwind> block in the render\n * context. Nested <Tailwind> instances are flattened: their classes flow\n * up to the outermost block, their `#config` slot (if any) is ignored.\n * One <style> per outermost block is appended to <head>; marker comments\n * are stripped after.\n */\nexport async function tailwindComponent(\n dom: ChildNode[],\n blocks: TailwindBlock[],\n config: MaizzleConfig,\n filePath?: string,\n): Promise<ChildNode[]> {\n if (!blocks.length) return dom\n\n const map = new Map<string, BlockMeta>()\n for (const b of blocks) {\n map.set(b.id, { id: b.id, configCss: b.css, nested: false, classes: new Set() })\n }\n\n const stack: string[] = []\n const markers: Comment[] = []\n\n walk(dom, (node) => {\n if (node.type === 'comment') {\n const data = (node as Comment).data\n const open = data.match(OPEN_RE)\n const close = data.match(CLOSE_RE)\n if (open) {\n const id = open[1]\n const meta = map.get(id)\n if (meta && stack.length > 0) meta.nested = true\n if (meta) stack.push(id)\n markers.push(node as Comment)\n } else if (close) {\n const id = close[1]\n if (stack[stack.length - 1] === id) stack.pop()\n markers.push(node as Comment)\n }\n return\n }\n\n const el = node as Element\n /**\n * Always assign to the OUTERMOST active marker (stack[0]) so nested\n * <Tailwind> blocks merge their classes into the parent's scope.\n */\n if (el.attribs?.class && stack.length > 0) {\n map.get(stack[0])!.classes.add(el.attribs.class)\n }\n })\n\n const fromPath = filePath ?? resolve(process.cwd(), 'template.vue')\n\n let head: Element | undefined\n walk(dom, (n) => {\n if (!head && (n as Element).name === 'head') head = n as Element\n })\n\n if (!head) {\n throw new Error('`Tailwind` component requires `Head` component to be present in the template.')\n }\n\n /**\n * Compile + inject one <style raw> per outermost block. `raw` opts\n * the existing tailwindcss transformer out of recompiling\n * already-compiled CSS.\n */\n for (const meta of map.values()) {\n if (meta.nested) continue\n\n const cssInput = buildCssInput(meta.configCss, meta.classes)\n const css = (await compileTailwindCss(cssInput, config, `${fromPath}?tw=${meta.id}`)).trim()\n if (!css) continue\n\n const styleNode: Element = {\n type: 'tag',\n name: 'style',\n attribs: { raw: '' },\n children: [],\n parent: head,\n prev: null,\n next: null,\n } as any\n\n const textNode = {\n type: 'text',\n data: css,\n parent: styleNode,\n prev: null,\n next: null,\n } as any\n\n styleNode.children = [textNode]\n head.children.push(styleNode)\n }\n\n // Strip marker comments from their parents\n for (const c of markers) {\n const parent = c.parent as Element | null\n if (!parent?.children) continue\n const i = parent.children.indexOf(c)\n if (i >= 0) parent.children.splice(i, 1)\n }\n\n return dom\n}\n\nfunction buildCssInput(configCss: string | undefined, classes: Set<string>): string {\n const seed = configCss ?? DEFAULT_SEED\n\n if (!classes.size) return seed\n\n const inline = [...classes].join(' ').replace(/\"/g, '\\\\\"')\n return `${seed}\\n@source inline(\"${inline}\");`\n}\n"],"mappings":";;;;;AAOA,MAAM,eAAe;AASrB,MAAM,UAAU;AAChB,MAAM,WAAW;;;;;;;;AASjB,eAAsB,kBACpB,KACA,QACA,QACA,UACsB;CACtB,IAAI,CAAC,OAAO,QAAQ,OAAO;CAE3B,MAAM,sBAAM,IAAI,IAAuB;CACvC,KAAK,MAAM,KAAK,QACd,IAAI,IAAI,EAAE,IAAI;EAAE,IAAI,EAAE;EAAI,WAAW,EAAE;EAAK,QAAQ;EAAO,yBAAS,IAAI,IAAI;CAAE,CAAC;CAGjF,MAAM,QAAkB,CAAC;CACzB,MAAM,UAAqB,CAAC;CAE5B,KAAK,MAAM,SAAS;EAClB,IAAI,KAAK,SAAS,WAAW;GAC3B,MAAM,OAAQ,KAAiB;GAC/B,MAAM,OAAO,KAAK,MAAM,OAAO;GAC/B,MAAM,QAAQ,KAAK,MAAM,QAAQ;GACjC,IAAI,MAAM;IACR,MAAM,KAAK,KAAK;IAChB,MAAM,OAAO,IAAI,IAAI,EAAE;IACvB,IAAI,QAAQ,MAAM,SAAS,GAAG,KAAK,SAAS;IAC5C,IAAI,MAAM,MAAM,KAAK,EAAE;IACvB,QAAQ,KAAK,IAAe;GAC9B,OAAO,IAAI,OAAO;IAChB,MAAM,KAAK,MAAM;IACjB,IAAI,MAAM,MAAM,SAAS,OAAO,IAAI,MAAM,IAAI;IAC9C,QAAQ,KAAK,IAAe;GAC9B;GACA;EACF;EAEA,MAAM,KAAK;;;;;EAKX,IAAI,GAAG,SAAS,SAAS,MAAM,SAAS,GACtC,IAAI,IAAI,MAAM,EAAE,CAAC,CAAE,QAAQ,IAAI,GAAG,QAAQ,KAAK;CAEnD,CAAC;CAED,MAAM,WAAW,YAAY,QAAQ,QAAQ,IAAI,GAAG,cAAc;CAElE,IAAI;CACJ,KAAK,MAAM,MAAM;EACf,IAAI,CAAC,QAAS,EAAc,SAAS,QAAQ,OAAO;CACtD,CAAC;CAED,IAAI,CAAC,MACH,MAAM,IAAI,MAAM,+EAA+E;;;;;;CAQjG,KAAK,MAAM,QAAQ,IAAI,OAAO,GAAG;EAC/B,IAAI,KAAK,QAAQ;EAEjB,MAAM,WAAW,cAAc,KAAK,WAAW,KAAK,OAAO;EAC3D,MAAM,OAAO,MAAM,mBAAmB,UAAU,QAAQ,GAAG,SAAS,MAAM,KAAK,IAAI,EAAA,CAAG,KAAK;EAC3F,IAAI,CAAC,KAAK;EAEV,MAAM,YAAqB;GACzB,MAAM;GACN,MAAM;GACN,SAAS,EAAE,KAAK,GAAG;GACnB,UAAU,CAAC;GACX,QAAQ;GACR,MAAM;GACN,MAAM;EACR;EAUA,UAAU,WAAW,CAAC;GAPpB,MAAM;GACN,MAAM;GACN,QAAQ;GACR,MAAM;GACN,MAAM;EAGqB,CAAC;EAC9B,KAAK,SAAS,KAAK,SAAS;CAC9B;CAGA,KAAK,MAAM,KAAK,SAAS;EACvB,MAAM,SAAS,EAAE;EACjB,IAAI,CAAC,QAAQ,UAAU;EACvB,MAAM,IAAI,OAAO,SAAS,QAAQ,CAAC;EACnC,IAAI,KAAK,GAAG,OAAO,SAAS,OAAO,GAAG,CAAC;CACzC;CAEA,OAAO;AACT;AAEA,SAAS,cAAc,WAA+B,SAA8B;CAClF,MAAM,OAAO,aAAa;CAE1B,IAAI,CAAC,QAAQ,MAAM,OAAO;CAG1B,OAAO,GAAG,KAAK,oBADA,CAAC,GAAG,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,QAAQ,MAAM,MACZ,EAAE;AAC5C"}
@@ -62,7 +62,8 @@ function urlQueryDom(dom, params = {}, options = {}) {
62
62
  encode: false,
63
63
  ...options.qs ?? {}
64
64
  };
65
- const elements = selectAll(tags.join(", "), dom);
65
+ const selector = tags.join(", ");
66
+ const elements = selectAll(selector, dom);
66
67
  for (const el of elements) for (const attr of attributes) {
67
68
  const value = el.attribs[attr];
68
69
  if (!value) continue;
@@ -1 +1 @@
1
- {"version":3,"file":"urlQuery.js","names":[],"sources":["../../src/transformers/urlQuery.ts"],"sourcesContent":["import queryString from 'query-string'\nimport { selectAll } from 'css-select'\nimport type { ChildNode, Element } from 'domhandler'\nimport { parse, serialize } from '../utils/ast/index.ts'\nimport { isAbsoluteUrl } from '../utils/url.ts'\nimport type { UrlQueryOptions } from '../types/config.ts'\n\nconst DEFAULT_ATTRIBUTES = ['src', 'href', 'poster', 'srcset', 'background']\nconst DEFAULT_TAGS = ['a']\n\n/**\n * Append query parameters to a URL string using query-string.\n */\nfunction appendParams(\n url: string,\n params: Record<string, unknown>,\n qsOptions: queryString.StringifyOptions,\n strict: boolean,\n): string {\n if (strict && !isAbsoluteUrl(url)) return url\n\n return queryString.stringifyUrl(\n { url, query: params as queryString.StringifiableRecord },\n qsOptions,\n )\n}\n\n/**\n * Append query parameters to URLs found in matching attributes/elements.\n *\n * @param html HTML string to transform.\n * @param params Query parameters to append (e.g. `{ utm_source: 'newsletter' }`).\n * @param options Behaviour overrides — `tags` (CSS selectors, default `['a']`),\n * `attributes` (default `['src', 'href', 'poster', 'srcset', 'background']`),\n * `strict` (default `true`, only rewrites absolute URLs),\n * `qs` (forwarded to `query-string`, default `{ encode: false }`).\n * @returns The transformed HTML string.\n *\n * @example\n * import { urlQuery } from '@maizzle/framework'\n *\n * const out = urlQuery(\n * '<a href=\"https://example.com\">x</a>',\n * { utm_source: 'newsletter' },\n * )\n *\n * // Restrict to specific tags / attributes:\n * urlQuery(html, { ref: 'email' }, { tags: ['a', 'img'], attributes: ['href', 'src'] })\n */\nexport function urlQuery(\n html: string,\n params: Record<string, unknown> = {},\n options: UrlQueryOptions = {},\n): string {\n return serialize(urlQueryDom(parse(html), params, options))\n}\n\n/**\n * DOM-form of {@link urlQuery} used by the internal transformer pipeline.\n * Takes a parsed DOM, returns a parsed DOM — avoids redundant\n * serialize/parse round-trips when chained with other transformers.\n */\nexport function urlQueryDom(\n dom: ChildNode[],\n params: Record<string, unknown> = {},\n options: UrlQueryOptions = {},\n): ChildNode[] {\n if (!params || Object.keys(params).length === 0) return dom\n\n const tags = options.tags ?? DEFAULT_TAGS\n const attributes = options.attributes ?? DEFAULT_ATTRIBUTES\n const strict = options.strict ?? true\n const qsOptions: queryString.StringifyOptions = { encode: false, ...((options.qs ?? {}) as queryString.StringifyOptions) }\n\n // Use css-select to find all elements matching any of the tag selectors\n const selector = tags.join(', ')\n const elements = selectAll(selector, dom) as Element[]\n\n for (const el of elements) {\n for (const attr of attributes) {\n const value = el.attribs[attr]\n if (!value) continue\n\n const updated = appendParams(value, params, qsOptions, strict)\n if (updated !== value) {\n el.attribs[attr] = updated\n }\n }\n }\n\n return dom\n}\n"],"mappings":";;;;;;;AAOA,MAAM,qBAAqB;CAAC;CAAO;CAAQ;CAAU;CAAU;AAAY;AAC3E,MAAM,eAAe,CAAC,GAAG;;;;AAKzB,SAAS,aACP,KACA,QACA,WACA,QACQ;CACR,IAAI,UAAU,CAAC,cAAc,GAAG,GAAG,OAAO;CAE1C,OAAO,YAAY,aACjB;EAAE;EAAK,OAAO;CAA0C,GACxD,SACF;AACF;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,SACd,MACA,SAAkC,CAAC,GACnC,UAA2B,CAAC,GACpB;CACR,OAAO,UAAU,YAAY,MAAM,IAAI,GAAG,QAAQ,OAAO,CAAC;AAC5D;;;;;;AAOA,SAAgB,YACd,KACA,SAAkC,CAAC,GACnC,UAA2B,CAAC,GACf;CACb,IAAI,CAAC,UAAU,OAAO,KAAK,MAAM,CAAC,CAAC,WAAW,GAAG,OAAO;CAExD,MAAM,OAAO,QAAQ,QAAQ;CAC7B,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,YAA0C;EAAE,QAAQ;EAAO,GAAK,QAAQ,MAAM,CAAC;CAAoC;CAIzH,MAAM,WAAW,UADA,KAAK,KAAK,IACO,GAAG,GAAG;CAExC,KAAK,MAAM,MAAM,UACf,KAAK,MAAM,QAAQ,YAAY;EAC7B,MAAM,QAAQ,GAAG,QAAQ;EACzB,IAAI,CAAC,OAAO;EAEZ,MAAM,UAAU,aAAa,OAAO,QAAQ,WAAW,MAAM;EAC7D,IAAI,YAAY,OACd,GAAG,QAAQ,QAAQ;CAEvB;CAGF,OAAO;AACT"}
1
+ {"version":3,"file":"urlQuery.js","names":[],"sources":["../../src/transformers/urlQuery.ts"],"sourcesContent":["import queryString from 'query-string'\nimport { selectAll } from 'css-select'\nimport type { ChildNode, Element } from 'domhandler'\nimport { parse, serialize } from '../utils/ast/index.ts'\nimport { isAbsoluteUrl } from '../utils/url.ts'\nimport type { UrlQueryOptions } from '../types/config.ts'\n\nconst DEFAULT_ATTRIBUTES = ['src', 'href', 'poster', 'srcset', 'background']\nconst DEFAULT_TAGS = ['a']\n\n/**\n * Append query parameters to a URL string using query-string.\n */\nfunction appendParams(\n url: string,\n params: Record<string, unknown>,\n qsOptions: queryString.StringifyOptions,\n strict: boolean,\n): string {\n if (strict && !isAbsoluteUrl(url)) return url\n\n return queryString.stringifyUrl(\n { url, query: params as queryString.StringifiableRecord },\n qsOptions,\n )\n}\n\n/**\n * Append query parameters to URLs found in matching attributes/elements.\n *\n * @param html HTML string to transform.\n * @param params Query parameters to append (e.g. `{ utm_source: 'newsletter' }`).\n * @param options Behaviour overrides — `tags` (CSS selectors, default `['a']`),\n * `attributes` (default `['src', 'href', 'poster', 'srcset', 'background']`),\n * `strict` (default `true`, only rewrites absolute URLs),\n * `qs` (forwarded to `query-string`, default `{ encode: false }`).\n * @returns The transformed HTML string.\n *\n * @example\n * import { urlQuery } from '@maizzle/framework'\n *\n * const out = urlQuery(\n * '<a href=\"https://example.com\">x</a>',\n * { utm_source: 'newsletter' },\n * )\n *\n * // Restrict to specific tags / attributes:\n * urlQuery(html, { ref: 'email' }, { tags: ['a', 'img'], attributes: ['href', 'src'] })\n */\nexport function urlQuery(\n html: string,\n params: Record<string, unknown> = {},\n options: UrlQueryOptions = {},\n): string {\n return serialize(urlQueryDom(parse(html), params, options))\n}\n\n/**\n * DOM-form of {@link urlQuery} used by the internal transformer pipeline.\n * Takes a parsed DOM, returns a parsed DOM — avoids redundant\n * serialize/parse round-trips when chained with other transformers.\n */\nexport function urlQueryDom(\n dom: ChildNode[],\n params: Record<string, unknown> = {},\n options: UrlQueryOptions = {},\n): ChildNode[] {\n if (!params || Object.keys(params).length === 0) return dom\n\n const tags = options.tags ?? DEFAULT_TAGS\n const attributes = options.attributes ?? DEFAULT_ATTRIBUTES\n const strict = options.strict ?? true\n const qsOptions: queryString.StringifyOptions = { encode: false, ...((options.qs ?? {}) as queryString.StringifyOptions) }\n\n // Use css-select to find all elements matching any of the tag selectors\n const selector = tags.join(', ')\n const elements = selectAll(selector, dom) as Element[]\n\n for (const el of elements) {\n for (const attr of attributes) {\n const value = el.attribs[attr]\n if (!value) continue\n\n const updated = appendParams(value, params, qsOptions, strict)\n if (updated !== value) {\n el.attribs[attr] = updated\n }\n }\n }\n\n return dom\n}\n"],"mappings":";;;;;;;AAOA,MAAM,qBAAqB;CAAC;CAAO;CAAQ;CAAU;CAAU;AAAY;AAC3E,MAAM,eAAe,CAAC,GAAG;;;;AAKzB,SAAS,aACP,KACA,QACA,WACA,QACQ;CACR,IAAI,UAAU,CAAC,cAAc,GAAG,GAAG,OAAO;CAE1C,OAAO,YAAY,aACjB;EAAE;EAAK,OAAO;CAA0C,GACxD,SACF;AACF;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,SACd,MACA,SAAkC,CAAC,GACnC,UAA2B,CAAC,GACpB;CACR,OAAO,UAAU,YAAY,MAAM,IAAI,GAAG,QAAQ,OAAO,CAAC;AAC5D;;;;;;AAOA,SAAgB,YACd,KACA,SAAkC,CAAC,GACnC,UAA2B,CAAC,GACf;CACb,IAAI,CAAC,UAAU,OAAO,KAAK,MAAM,CAAC,CAAC,WAAW,GAAG,OAAO;CAExD,MAAM,OAAO,QAAQ,QAAQ;CAC7B,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,SAAS,QAAQ,UAAU;CACjC,MAAM,YAA0C;EAAE,QAAQ;EAAO,GAAK,QAAQ,MAAM,CAAC;CAAoC;CAGzH,MAAM,WAAW,KAAK,KAAK,IAAI;CAC/B,MAAM,WAAW,UAAU,UAAU,GAAG;CAExC,KAAK,MAAM,MAAM,UACf,KAAK,MAAM,QAAQ,YAAY;EAC7B,MAAM,QAAQ,GAAG,QAAQ;EACzB,IAAI,CAAC,OAAO;EAEZ,MAAM,UAAU,aAAa,OAAO,QAAQ,WAAW,MAAM;EAC7D,IAAI,YAAY,OACd,GAAG,QAAQ,QAAQ;CAEvB;CAGF,OAAO;AACT"}
@@ -56,9 +56,7 @@ function horizontalPaddingPx(root) {
56
56
  case "padding-left":
57
57
  left = lengthToPx(d.value);
58
58
  break;
59
- case "padding-right":
60
- right = lengthToPx(d.value);
61
- break;
59
+ case "padding-right": right = lengthToPx(d.value);
62
60
  }
63
61
  });
64
62
  return (left ?? 0) + (right ?? 0);
@@ -138,9 +136,7 @@ function horizontalBorderPx(root) {
138
136
  case "border-left-style":
139
137
  if (NO_BORDER_STYLES.has(d.value.trim().toLowerCase())) leftNone = true;
140
138
  break;
141
- case "border-right-style":
142
- if (NO_BORDER_STYLES.has(d.value.trim().toLowerCase())) rightNone = true;
143
- break;
139
+ case "border-right-style": if (NO_BORDER_STYLES.has(d.value.trim().toLowerCase())) rightNone = true;
144
140
  }
145
141
  });
146
142
  return (leftNone ? 0 : left ?? 0) + (rightNone ? 0 : right ?? 0);
@@ -1 +1 @@
1
- {"version":3,"file":"cssBox.js","names":[],"sources":["../../src/utils/cssBox.ts"],"sourcesContent":["import type { Root } from 'postcss'\n\nexport const NO_BORDER_STYLES = new Set(['none', 'hidden'])\n\n/**\n * Parse a length token into px. Handles `Npx`, `Nrem`, `Nem`, `Npt`, and\n * unitless N (treated as px). Returns null for percentages, calc(),\n * keywords, or anything that doesn't reduce to a concrete length.\n */\nexport function lengthToPx(value: string): number | null {\n const m = value.trim().match(/^([\\d.]+)(px|rem|em|pt)?$/i)\n if (!m) return null\n const n = parseFloat(m[1])\n const unit = (m[2] || 'px').toLowerCase()\n return n * (unit === 'rem' || unit === 'em' ? 16 : unit === 'pt' ? 1.333 : 1)\n}\n\n/**\n * Expand a 1-4 token CSS shorthand (T R B L) into a left/right pair:\n * 1: all sides\n * 2: TB RL\n * 3: T RL B\n * 4: T R B L\n */\nexport function shorthandSides(value: string): { left?: string; right?: string } {\n const parts = value.trim().split(/\\s+/)\n switch (parts.length) {\n case 1: return { left: parts[0], right: parts[0] }\n case 2:\n case 3: return { left: parts[1], right: parts[1] }\n case 4: return { left: parts[3], right: parts[1] }\n default: return {}\n }\n}\n\n/**\n * Read horizontal padding (left + right) px from a parsed style root.\n * Percentages are skipped since they'd need a known container width.\n */\nexport function horizontalPaddingPx(root: Root): number {\n let left: number | null = null\n let right: number | null = null\n\n root.walkDecls((d) => {\n switch (d.prop) {\n case 'padding': {\n const { left: l, right: r } = shorthandSides(d.value)\n if (l) left = lengthToPx(l)\n if (r) right = lengthToPx(r)\n break\n }\n case 'padding-left':\n left = lengthToPx(d.value)\n break\n case 'padding-right':\n right = lengthToPx(d.value)\n break\n }\n })\n\n return (left ?? 0) + (right ?? 0)\n}\n\n/**\n * Extract a px length from a CSS border shorthand (e.g. `1px solid red` → 1).\n * Returns null when the value indicates no border (`none` or `hidden`).\n * Defaults to 3px (CSS `medium`) when a visible style is set but no\n * explicit width token is present in the shorthand value.\n */\nexport function shorthandBorderWidthPx(value: string): number | null {\n const tokens = value.trim().split(/\\s+/)\n if (tokens.some((t) => NO_BORDER_STYLES.has(t.toLowerCase()))) return null\n for (const t of tokens) {\n const px = lengthToPx(t)\n if (px != null) return px\n }\n return 3\n}\n\n/**\n * Read horizontal border widths (left + right) px from a parsed style root.\n * Per-side `border-style: none|hidden` overrides count as zero\n * contribution. Returns total px or 0 when nothing resolves.\n */\nexport function horizontalBorderPx(root: Root): number {\n let left: number | null = null\n let right: number | null = null\n let leftNone = false\n let rightNone = false\n\n root.walkDecls((d) => {\n switch (d.prop) {\n case 'border': {\n const w = shorthandBorderWidthPx(d.value)\n if (w == null) {\n leftNone = rightNone = true\n }\n else {\n left = right = w\n leftNone = rightNone = false\n }\n break\n }\n case 'border-width': {\n const { left: l, right: r } = shorthandSides(d.value)\n if (l) left = lengthToPx(l) ?? left\n if (r) right = lengthToPx(r) ?? right\n break\n }\n case 'border-style': {\n const { left: l, right: r } = shorthandSides(d.value)\n if (l && NO_BORDER_STYLES.has(l.toLowerCase())) leftNone = true\n if (r && NO_BORDER_STYLES.has(r.toLowerCase())) rightNone = true\n break\n }\n case 'border-left': {\n const w = shorthandBorderWidthPx(d.value)\n if (w == null) leftNone = true\n else { left = w; leftNone = false }\n break\n }\n case 'border-right': {\n const w = shorthandBorderWidthPx(d.value)\n if (w == null) rightNone = true\n else { right = w; rightNone = false }\n break\n }\n case 'border-left-width':\n left = lengthToPx(d.value) ?? left\n break\n case 'border-right-width':\n right = lengthToPx(d.value) ?? right\n break\n case 'border-left-style':\n if (NO_BORDER_STYLES.has(d.value.trim().toLowerCase())) leftNone = true\n break\n case 'border-right-style':\n if (NO_BORDER_STYLES.has(d.value.trim().toLowerCase())) rightNone = true\n break\n }\n })\n\n return (leftNone ? 0 : (left ?? 0)) + (rightNone ? 0 : (right ?? 0))\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cssBox.js","names":[],"sources":["../../src/utils/cssBox.ts"],"sourcesContent":["import type { Root } from 'postcss'\n\nexport const NO_BORDER_STYLES = new Set(['none', 'hidden'])\n\n/**\n * Parse a length token into px. Handles `Npx`, `Nrem`, `Nem`, `Npt`, and\n * unitless N (treated as px). Returns null for percentages, calc(),\n * keywords, or anything that doesn't reduce to a concrete length.\n */\nexport function lengthToPx(value: string): number | null {\n const m = value.trim().match(/^([\\d.]+)(px|rem|em|pt)?$/i)\n if (!m) return null\n const n = parseFloat(m[1])\n const unit = (m[2] || 'px').toLowerCase()\n return n * (unit === 'rem' || unit === 'em' ? 16 : unit === 'pt' ? 1.333 : 1)\n}\n\n/**\n * Expand a 1-4 token CSS shorthand (T R B L) into a left/right pair:\n * 1: all sides\n * 2: TB RL\n * 3: T RL B\n * 4: T R B L\n */\nexport function shorthandSides(value: string): { left?: string; right?: string } {\n const parts = value.trim().split(/\\s+/)\n switch (parts.length) {\n case 1: return { left: parts[0], right: parts[0] }\n case 2:\n case 3: return { left: parts[1], right: parts[1] }\n case 4: return { left: parts[3], right: parts[1] }\n default: return {}\n }\n}\n\n/**\n * Read horizontal padding (left + right) px from a parsed style root.\n * Percentages are skipped since they'd need a known container width.\n */\nexport function horizontalPaddingPx(root: Root): number {\n let left: number | null = null\n let right: number | null = null\n\n root.walkDecls((d) => {\n switch (d.prop) {\n case 'padding': {\n const { left: l, right: r } = shorthandSides(d.value)\n if (l) left = lengthToPx(l)\n if (r) right = lengthToPx(r)\n break\n }\n case 'padding-left':\n left = lengthToPx(d.value)\n break\n case 'padding-right':\n right = lengthToPx(d.value)\n break\n }\n })\n\n return (left ?? 0) + (right ?? 0)\n}\n\n/**\n * Extract a px length from a CSS border shorthand (e.g. `1px solid red` → 1).\n * Returns null when the value indicates no border (`none` or `hidden`).\n * Defaults to 3px (CSS `medium`) when a visible style is set but no\n * explicit width token is present in the shorthand value.\n */\nexport function shorthandBorderWidthPx(value: string): number | null {\n const tokens = value.trim().split(/\\s+/)\n if (tokens.some((t) => NO_BORDER_STYLES.has(t.toLowerCase()))) return null\n for (const t of tokens) {\n const px = lengthToPx(t)\n if (px != null) return px\n }\n return 3\n}\n\n/**\n * Read horizontal border widths (left + right) px from a parsed style root.\n * Per-side `border-style: none|hidden` overrides count as zero\n * contribution. Returns total px or 0 when nothing resolves.\n */\nexport function horizontalBorderPx(root: Root): number {\n let left: number | null = null\n let right: number | null = null\n let leftNone = false\n let rightNone = false\n\n root.walkDecls((d) => {\n switch (d.prop) {\n case 'border': {\n const w = shorthandBorderWidthPx(d.value)\n if (w == null) {\n leftNone = rightNone = true\n }\n else {\n left = right = w\n leftNone = rightNone = false\n }\n break\n }\n case 'border-width': {\n const { left: l, right: r } = shorthandSides(d.value)\n if (l) left = lengthToPx(l) ?? left\n if (r) right = lengthToPx(r) ?? right\n break\n }\n case 'border-style': {\n const { left: l, right: r } = shorthandSides(d.value)\n if (l && NO_BORDER_STYLES.has(l.toLowerCase())) leftNone = true\n if (r && NO_BORDER_STYLES.has(r.toLowerCase())) rightNone = true\n break\n }\n case 'border-left': {\n const w = shorthandBorderWidthPx(d.value)\n if (w == null) leftNone = true\n else { left = w; leftNone = false }\n break\n }\n case 'border-right': {\n const w = shorthandBorderWidthPx(d.value)\n if (w == null) rightNone = true\n else { right = w; rightNone = false }\n break\n }\n case 'border-left-width':\n left = lengthToPx(d.value) ?? left\n break\n case 'border-right-width':\n right = lengthToPx(d.value) ?? right\n break\n case 'border-left-style':\n if (NO_BORDER_STYLES.has(d.value.trim().toLowerCase())) leftNone = true\n break\n case 'border-right-style':\n if (NO_BORDER_STYLES.has(d.value.trim().toLowerCase())) rightNone = true\n break\n }\n })\n\n return (leftNone ? 0 : (left ?? 0)) + (rightNone ? 0 : (right ?? 0))\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maizzle/framework",
3
- "version": "6.1.0",
3
+ "version": "6.1.1",
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",
@@ -58,7 +58,7 @@
58
58
  "markdown-exit": "^1.1.0-beta.2",
59
59
  "nodemailer": "^9.0.0",
60
60
  "ora": "^9.3.0",
61
- "oxfmt": "^0.61.0",
61
+ "oxfmt": "^0.64.0",
62
62
  "pathe": "^2.0.3",
63
63
  "postcss": "^8.5.6",
64
64
  "postcss-calc": "^10.1.1",