@maizzle/framework 6.0.0-rc.22 → 6.0.0-rc.24

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 (222) hide show
  1. package/dist/build.d.ts.map +1 -1
  2. package/dist/build.js +22 -2
  3. package/dist/build.js.map +1 -1
  4. package/dist/components/Heading.vue +1 -1
  5. package/dist/components/Img.vue +60 -10
  6. package/dist/components/Link.vue +1 -1
  7. package/dist/components/Markdown.vue +48 -16
  8. package/dist/components/Preheader.vue +4 -2
  9. package/dist/components/Tailwind.vue +4 -2
  10. package/dist/components/Text.vue +1 -1
  11. package/dist/components/Vml.vue +354 -0
  12. package/dist/components/utils.d.ts.map +1 -1
  13. package/dist/components/utils.js.map +1 -1
  14. package/dist/composables/defineConfig.js.map +1 -1
  15. package/dist/composables/renderContext.d.ts +1 -0
  16. package/dist/composables/renderContext.d.ts.map +1 -1
  17. package/dist/composables/renderContext.js +1 -1
  18. package/dist/composables/renderContext.js.map +1 -1
  19. package/dist/composables/useBaseUrl.d.ts.map +1 -1
  20. package/dist/composables/useBaseUrl.js.map +1 -1
  21. package/dist/composables/useConfig.d.ts +7 -0
  22. package/dist/composables/useConfig.d.ts.map +1 -1
  23. package/dist/composables/useConfig.js +8 -1
  24. package/dist/composables/useConfig.js.map +1 -1
  25. package/dist/composables/useCurrentTemplate.d.ts.map +1 -1
  26. package/dist/composables/useCurrentTemplate.js +10 -3
  27. package/dist/composables/useCurrentTemplate.js.map +1 -1
  28. package/dist/composables/useDoctype.d.ts.map +1 -1
  29. package/dist/composables/useDoctype.js.map +1 -1
  30. package/dist/composables/useEvent.js.map +1 -1
  31. package/dist/composables/useFont.d.ts.map +1 -1
  32. package/dist/composables/useFont.js.map +1 -1
  33. package/dist/composables/useOutlookFallback.d.ts.map +1 -1
  34. package/dist/composables/useOutlookFallback.js.map +1 -1
  35. package/dist/composables/useOutputPath.d.ts +17 -0
  36. package/dist/composables/useOutputPath.d.ts.map +1 -0
  37. package/dist/composables/useOutputPath.js +23 -0
  38. package/dist/composables/useOutputPath.js.map +1 -0
  39. package/dist/composables/usePlaintext.d.ts.map +1 -1
  40. package/dist/composables/usePlaintext.js.map +1 -1
  41. package/dist/composables/usePreheader.d.ts.map +1 -1
  42. package/dist/composables/usePreheader.js.map +1 -1
  43. package/dist/composables/useTransformers.d.ts.map +1 -1
  44. package/dist/composables/useTransformers.js.map +1 -1
  45. package/dist/composables/useUrlQuery.d.ts.map +1 -1
  46. package/dist/composables/useUrlQuery.js.map +1 -1
  47. package/dist/config/defaults.d.ts.map +1 -1
  48. package/dist/config/defaults.js.map +1 -1
  49. package/dist/config/index.js +12 -0
  50. package/dist/config/index.js.map +1 -1
  51. package/dist/events/index.d.ts +5 -0
  52. package/dist/events/index.d.ts.map +1 -1
  53. package/dist/events/index.js +5 -0
  54. package/dist/events/index.js.map +1 -1
  55. package/dist/index.d.ts +2 -1
  56. package/dist/index.js +2 -1
  57. package/dist/plaintext.d.ts.map +1 -1
  58. package/dist/plaintext.js.map +1 -1
  59. package/dist/plugin.js.map +1 -1
  60. package/dist/plugins/postcss/mergeMediaQueries.d.ts.map +1 -1
  61. package/dist/plugins/postcss/mergeMediaQueries.js.map +1 -1
  62. package/dist/plugins/postcss/pruneVars.d.ts.map +1 -1
  63. package/dist/plugins/postcss/pruneVars.js.map +1 -1
  64. package/dist/plugins/postcss/quoteFontFamilies.d.ts.map +1 -1
  65. package/dist/plugins/postcss/quoteFontFamilies.js.map +1 -1
  66. package/dist/plugins/postcss/removeDeclarations.d.ts.map +1 -1
  67. package/dist/plugins/postcss/removeDeclarations.js.map +1 -1
  68. package/dist/plugins/postcss/resolveMaizzleImports.d.ts.map +1 -1
  69. package/dist/plugins/postcss/resolveMaizzleImports.js.map +1 -1
  70. package/dist/plugins/postcss/resolveProps.d.ts.map +1 -1
  71. package/dist/plugins/postcss/resolveProps.js +14 -0
  72. package/dist/plugins/postcss/resolveProps.js.map +1 -1
  73. package/dist/plugins/postcss/tailwindCleanup.d.ts.map +1 -1
  74. package/dist/plugins/postcss/tailwindCleanup.js.map +1 -1
  75. package/dist/prepare.d.ts.map +1 -1
  76. package/dist/prepare.js.map +1 -1
  77. package/dist/render/active.d.ts.map +1 -1
  78. package/dist/render/active.js.map +1 -1
  79. package/dist/render/createRenderer.d.ts +1 -0
  80. package/dist/render/createRenderer.d.ts.map +1 -1
  81. package/dist/render/createRenderer.js +105 -1
  82. package/dist/render/createRenderer.js.map +1 -1
  83. package/dist/render/index.d.ts.map +1 -1
  84. package/dist/render/index.js +7 -1
  85. package/dist/render/index.js.map +1 -1
  86. package/dist/render/injectFonts.js.map +1 -1
  87. package/dist/render/plugins/codeBlockExtract.d.ts.map +1 -1
  88. package/dist/render/plugins/codeBlockExtract.js +4 -0
  89. package/dist/render/plugins/codeBlockExtract.js.map +1 -1
  90. package/dist/render/plugins/markdownExtract.d.ts.map +1 -1
  91. package/dist/render/plugins/markdownExtract.js.map +1 -1
  92. package/dist/render/plugins/rawExtract.d.ts.map +1 -1
  93. package/dist/render/plugins/rawExtract.js.map +1 -1
  94. package/dist/render/plugins/rowSourceLocation.d.ts.map +1 -1
  95. package/dist/render/plugins/rowSourceLocation.js.map +1 -1
  96. package/dist/serve.d.ts.map +1 -1
  97. package/dist/serve.js +51 -18
  98. package/dist/serve.js.map +1 -1
  99. package/dist/server/compatibility.d.ts.map +1 -1
  100. package/dist/server/compatibility.js +48 -0
  101. package/dist/server/compatibility.js.map +1 -1
  102. package/dist/server/email.js.map +1 -1
  103. package/dist/server/linter.js +6 -0
  104. package/dist/server/linter.js.map +1 -1
  105. package/dist/server/sfc-utils.d.ts.map +1 -1
  106. package/dist/server/sfc-utils.js.map +1 -1
  107. package/dist/server/ui/App.vue +16 -16
  108. package/dist/server/ui/components/SidebarClose.vue +1 -1
  109. package/dist/server/ui/components/ui/checkbox/Checkbox.vue +1 -1
  110. package/dist/server/ui/components/ui/command/CommandInput.vue +2 -2
  111. package/dist/server/ui/components/ui/dialog/DialogContent.vue +1 -1
  112. package/dist/server/ui/components/ui/dialog/DialogScrollContent.vue +1 -1
  113. package/dist/server/ui/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +1 -1
  114. package/dist/server/ui/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +1 -1
  115. package/dist/server/ui/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +1 -1
  116. package/dist/server/ui/components/ui/sheet/SheetContent.vue +1 -1
  117. package/dist/server/ui/components/ui/sidebar/SidebarTrigger.vue +1 -1
  118. package/dist/server/ui/components/ui/tags-input/TagsInputItemDelete.vue +1 -1
  119. package/dist/server/ui/lib/emulated-dark-mode.ts +25 -10
  120. package/dist/server/ui/main.css +25 -0
  121. package/dist/server/ui/pages/Home.vue +1 -1
  122. package/dist/server/ui/pages/Preview.vue +37 -19
  123. package/dist/tests/render/_helpers.js.map +1 -1
  124. package/dist/transformers/addAttributes.d.ts.map +1 -1
  125. package/dist/transformers/addAttributes.js.map +1 -1
  126. package/dist/transformers/attributeToStyle.d.ts.map +1 -1
  127. package/dist/transformers/attributeToStyle.js.map +1 -1
  128. package/dist/transformers/base.d.ts.map +1 -1
  129. package/dist/transformers/base.js +4 -0
  130. package/dist/transformers/base.js.map +1 -1
  131. package/dist/transformers/columnWidth.d.ts.map +1 -1
  132. package/dist/transformers/columnWidth.js.map +1 -1
  133. package/dist/transformers/entities.d.ts.map +1 -1
  134. package/dist/transformers/entities.js.map +1 -1
  135. package/dist/transformers/filters/defaults.d.ts.map +1 -1
  136. package/dist/transformers/filters/defaults.js.map +1 -1
  137. package/dist/transformers/filters/index.d.ts.map +1 -1
  138. package/dist/transformers/filters/index.js.map +1 -1
  139. package/dist/transformers/format.d.ts.map +1 -1
  140. package/dist/transformers/format.js.map +1 -1
  141. package/dist/transformers/index.d.ts.map +1 -1
  142. package/dist/transformers/index.js +26 -0
  143. package/dist/transformers/index.js.map +1 -1
  144. package/dist/transformers/inlineCss.d.ts.map +1 -1
  145. package/dist/transformers/inlineCss.js +25 -2
  146. package/dist/transformers/inlineCss.js.map +1 -1
  147. package/dist/transformers/inlineLink.d.ts.map +1 -1
  148. package/dist/transformers/inlineLink.js.map +1 -1
  149. package/dist/transformers/minify.d.ts.map +1 -1
  150. package/dist/transformers/minify.js.map +1 -1
  151. package/dist/transformers/minifyCodeInline.d.ts.map +1 -1
  152. package/dist/transformers/minifyCodeInline.js.map +1 -1
  153. package/dist/transformers/msoPlaceholders.d.ts.map +1 -1
  154. package/dist/transformers/msoPlaceholders.js.map +1 -1
  155. package/dist/transformers/purgeCss.d.ts.map +1 -1
  156. package/dist/transformers/purgeCss.js +29 -3
  157. package/dist/transformers/purgeCss.js.map +1 -1
  158. package/dist/transformers/removeAttributes.d.ts.map +1 -1
  159. package/dist/transformers/removeAttributes.js.map +1 -1
  160. package/dist/transformers/replaceStrings.d.ts.map +1 -1
  161. package/dist/transformers/replaceStrings.js.map +1 -1
  162. package/dist/transformers/safeSelectors.d.ts.map +1 -1
  163. package/dist/transformers/safeSelectors.js +13 -1
  164. package/dist/transformers/safeSelectors.js.map +1 -1
  165. package/dist/transformers/shorthandCss.d.ts.map +1 -1
  166. package/dist/transformers/shorthandCss.js.map +1 -1
  167. package/dist/transformers/sixHex.d.ts.map +1 -1
  168. package/dist/transformers/sixHex.js.map +1 -1
  169. package/dist/transformers/tailwindComponent.js +9 -0
  170. package/dist/transformers/tailwindComponent.js.map +1 -1
  171. package/dist/transformers/tailwindcss.d.ts.map +1 -1
  172. package/dist/transformers/tailwindcss.js +22 -0
  173. package/dist/transformers/tailwindcss.js.map +1 -1
  174. package/dist/transformers/urlQuery.d.ts.map +1 -1
  175. package/dist/transformers/urlQuery.js.map +1 -1
  176. package/dist/types/config.d.ts +4 -8
  177. package/dist/types/config.d.ts.map +1 -1
  178. package/dist/types/index.d.ts +1 -1
  179. package/dist/utils/ast/parser.d.ts.map +1 -1
  180. package/dist/utils/ast/parser.js.map +1 -1
  181. package/dist/utils/ast/serializer.d.ts.map +1 -1
  182. package/dist/utils/ast/serializer.js.map +1 -1
  183. package/dist/utils/ast/walker.d.ts.map +1 -1
  184. package/dist/utils/ast/walker.js.map +1 -1
  185. package/dist/utils/compileTailwindCss.d.ts.map +1 -1
  186. package/dist/utils/compileTailwindCss.js.map +1 -1
  187. package/dist/utils/componentSources.d.ts.map +1 -1
  188. package/dist/utils/componentSources.js.map +1 -1
  189. package/dist/utils/cssBox.d.ts.map +1 -1
  190. package/dist/utils/cssBox.js.map +1 -1
  191. package/dist/utils/decodeStyleEntities.d.ts.map +1 -1
  192. package/dist/utils/decodeStyleEntities.js.map +1 -1
  193. package/dist/utils/detect.d.ts.map +1 -1
  194. package/dist/utils/detect.js.map +1 -1
  195. package/dist/utils/output-markers.d.ts.map +1 -1
  196. package/dist/utils/output-markers.js.map +1 -1
  197. package/dist/utils/url.d.ts.map +1 -1
  198. package/dist/utils/url.js.map +1 -1
  199. package/dist/utils/watchPaths.js.map +1 -1
  200. package/node_modules/@clack/core/CHANGELOG.md +6 -0
  201. package/node_modules/@clack/core/dist/index.d.mts +1 -1
  202. package/node_modules/@clack/core/dist/index.mjs +8 -8
  203. package/node_modules/@clack/core/dist/index.mjs.map +1 -1
  204. package/node_modules/@clack/core/package.json +1 -1
  205. package/node_modules/@clack/prompts/CHANGELOG.md +13 -0
  206. package/node_modules/@clack/prompts/README.md +2 -2
  207. package/node_modules/@clack/prompts/dist/index.d.mts +98 -0
  208. package/node_modules/@clack/prompts/dist/index.mjs +122 -121
  209. package/node_modules/@clack/prompts/dist/index.mjs.map +1 -1
  210. package/node_modules/@clack/prompts/package.json +2 -2
  211. package/node_modules/fast-wrap-ansi/lib/main.js +0 -1
  212. package/node_modules/fast-wrap-ansi/package.json +10 -10
  213. package/node_modules/maizzle/dist/commands/make/config.mjs +7 -6
  214. package/node_modules/maizzle/dist/commands/new.mjs +15 -84
  215. package/node_modules/maizzle/package.json +2 -2
  216. package/node_modules/tinyexec/README.md +8 -0
  217. package/node_modules/tinyexec/dist/main.d.mts +16 -1
  218. package/node_modules/tinyexec/dist/main.mjs +163 -457
  219. package/node_modules/tinyexec/package.json +12 -14
  220. package/package.json +3 -4
  221. package/node_modules/fast-wrap-ansi/lib/main.js.map +0 -1
  222. package/node_modules/tinyexec/dist/LICENSES.txt +0 -83
@@ -2,7 +2,7 @@
2
2
  import type { DialogContentEmits, DialogContentProps } from "reka-ui"
3
3
  import type { HTMLAttributes } from "vue"
4
4
  import { reactiveOmit } from "@vueuse/core"
5
- import { X } from "lucide-vue-next"
5
+ import { X } from "@lucide/vue"
6
6
  import {
7
7
  DialogClose,
8
8
  DialogContent,
@@ -2,7 +2,7 @@
2
2
  import type { DropdownMenuCheckboxItemEmits, DropdownMenuCheckboxItemProps } from "reka-ui"
3
3
  import type { HTMLAttributes } from "vue"
4
4
  import { reactiveOmit } from "@vueuse/core"
5
- import { Check } from "lucide-vue-next"
5
+ import { Check } from "@lucide/vue"
6
6
  import {
7
7
  DropdownMenuCheckboxItem,
8
8
  DropdownMenuItemIndicator,
@@ -2,7 +2,7 @@
2
2
  import type { DropdownMenuRadioItemEmits, DropdownMenuRadioItemProps } from "reka-ui"
3
3
  import type { HTMLAttributes } from "vue"
4
4
  import { reactiveOmit } from "@vueuse/core"
5
- import { Circle } from "lucide-vue-next"
5
+ import { Circle } from "@lucide/vue"
6
6
  import {
7
7
  DropdownMenuItemIndicator,
8
8
  DropdownMenuRadioItem,
@@ -2,7 +2,7 @@
2
2
  import type { DropdownMenuSubTriggerProps } from "reka-ui"
3
3
  import type { HTMLAttributes } from "vue"
4
4
  import { reactiveOmit } from "@vueuse/core"
5
- import { ChevronRight } from "lucide-vue-next"
5
+ import { ChevronRight } from "@lucide/vue"
6
6
  import {
7
7
  DropdownMenuSubTrigger,
8
8
  useForwardProps,
@@ -2,7 +2,7 @@
2
2
  import type { DialogContentEmits, DialogContentProps } from "reka-ui"
3
3
  import type { HTMLAttributes } from "vue"
4
4
  import { reactiveOmit } from "@vueuse/core"
5
- import { X } from "lucide-vue-next"
5
+ import { X } from "@lucide/vue"
6
6
  import {
7
7
  DialogClose,
8
8
  DialogContent,
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import type { HTMLAttributes } from "vue"
3
- import { PanelRightClose, PanelRightOpen } from "lucide-vue-next"
3
+ import { PanelRightClose, PanelRightOpen } from "@lucide/vue"
4
4
  import { cn } from "@/lib/utils"
5
5
  import { Button } from '@/components/ui/button'
6
6
  import { useSidebar } from "./utils"
@@ -3,7 +3,7 @@ import type { TagsInputItemDeleteProps } from "reka-ui"
3
3
  import type { HTMLAttributes } from "vue"
4
4
  import { reactiveOmit } from "@vueuse/core"
5
5
  import { TagsInputItemDelete, useForwardProps } from "reka-ui"
6
- import { X } from "lucide-vue-next"
6
+ import { X } from "@lucide/vue"
7
7
  import { cn } from "@/lib/utils"
8
8
 
9
9
  const props = defineProps<TagsInputItemDeleteProps & { class?: HTMLAttributes["class"] }>()
@@ -1,13 +1,14 @@
1
1
  import { parse, converter, formatRgb } from 'culori'
2
- import safeParser from 'postcss-safe-parser'
3
2
 
4
3
  const toLch = converter('lch')
5
4
 
6
5
  type Mode = 'background' | 'foreground'
7
6
 
8
- // CSS properties whose values contain colors we should invert, mapped to
9
- // the inversion mode. Kebab-case for <style> decls; inline styles are
10
- // handled via the same lookup after lowercasing.
7
+ /**
8
+ * CSS properties whose values contain colors we should invert, mapped to
9
+ * the inversion mode. Kebab-case for <style> decls; inline styles
10
+ * are handled via the same lookup after lowercasing.
11
+ */
11
12
  const styleProps = new Map<string, Mode>([
12
13
  ['background', 'background'],
13
14
  ['background-color', 'background'],
@@ -71,12 +72,26 @@ function invertInlineStyle(style: string): string {
71
72
 
72
73
  function invertStyleTag(css: string): string {
73
74
  try {
74
- const root = safeParser(css)
75
- root.walkDecls((decl) => {
76
- const mode = styleProps.get(decl.prop.toLowerCase())
77
- if (mode) decl.value = invertValue(decl.value, mode)
78
- })
79
- return root.toString()
75
+ const sheet = new CSSStyleSheet()
76
+ sheet.replaceSync(css)
77
+ const walk = (rules: CSSRuleList) => {
78
+ for (const rule of Array.from(rules)) {
79
+ if (rule instanceof CSSStyleRule) {
80
+ const props = Array.from({ length: rule.style.length }, (_, i) => rule.style.item(i))
81
+ for (const prop of props) {
82
+ const mode = styleProps.get(prop.toLowerCase())
83
+ if (!mode) continue
84
+ const value = rule.style.getPropertyValue(prop)
85
+ const priority = rule.style.getPropertyPriority(prop)
86
+ rule.style.setProperty(prop, invertValue(value, mode), priority)
87
+ }
88
+ } else if ('cssRules' in rule) {
89
+ walk((rule as CSSGroupingRule).cssRules)
90
+ }
91
+ }
92
+ }
93
+ walk(sheet.cssRules)
94
+ return Array.from(sheet.cssRules).map(r => r.cssText).join('\n')
80
95
  } catch {
81
96
  return css
82
97
  }
@@ -127,3 +127,28 @@
127
127
  border-left: 2px solid #f59e0b;
128
128
  min-width: fit-content;
129
129
  }
130
+
131
+ /**
132
+ * Template list icons, painted as a CSS mask so the sidebar can render
133
+ * thousands of rows without a Vue component or inline <svg> per row. Each
134
+ * icon SVG is decoded once and reused; background-color: currentColor keeps
135
+ * the currentColor theming the old <svg> icons had.
136
+ */
137
+ .mz-tpl-icon {
138
+ display: inline-block;
139
+ background-color: currentColor;
140
+ -webkit-mask-position: center;
141
+ mask-position: center;
142
+ -webkit-mask-size: contain;
143
+ mask-size: contain;
144
+ -webkit-mask-repeat: no-repeat;
145
+ mask-repeat: no-repeat;
146
+ }
147
+ .mz-tpl-icon-vue {
148
+ -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12.15V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-3.35'/%3E%3Cpath d='M14 2v5a1 1 0 0 0 1 1h5'/%3E%3Cpath d='m5 16-3 3 3 3'/%3E%3Cpath d='m9 22 3-3-3-3'/%3E%3C/svg%3E");
149
+ mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12.15V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-3.35'/%3E%3Cpath d='M14 2v5a1 1 0 0 0 1 1h5'/%3E%3Cpath d='m5 16-3 3 3 3'/%3E%3Cpath d='m9 22 3-3-3-3'/%3E%3C/svg%3E");
150
+ }
151
+ .mz-tpl-icon-md {
152
+ -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 22h6a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v6'/%3E%3Cpath d='M14 2v5a1 1 0 0 0 1 1h5'/%3E%3Cpath d='M3 22V14l4 4 4-4v8'/%3E%3C/svg%3E");
153
+ mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 22h6a2 2 0 0 0 2-2V8a2.4 2.4 0 0 0-.706-1.706l-3.588-3.588A2.4 2.4 0 0 0 14 2H6a2 2 0 0 0-2 2v6'/%3E%3Cpath d='M14 2v5a1 1 0 0 0 1 1h5'/%3E%3Cpath d='M3 22V14l4 4 4-4v8'/%3E%3C/svg%3E");
154
+ }
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { computed } from 'vue'
3
- import { Terminal } from 'lucide-vue-next'
3
+ import { Terminal } from '@lucide/vue'
4
4
  import { Kbd } from '@/components/ui/kbd'
5
5
  import {
6
6
  Empty,
@@ -1,7 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { ref, computed, watch, nextTick, onMounted, onUnmounted } from 'vue'
3
3
  import { useRoute } from 'vue-router'
4
- import { ChevronUp, ChevronDown, Check } from 'lucide-vue-next'
4
+ import { ChevronUp, ChevronDown, Check } from '@lucide/vue'
5
5
  import {
6
6
  DropdownMenu,
7
7
  DropdownMenuContent,
@@ -84,8 +84,10 @@ const iframeContentHeight = ref<number | null>(null)
84
84
  function copySource() {
85
85
  let text: string
86
86
  if (sourceView.value === 'compiled') {
87
- // `renderedHtml` holds the raw compiled HTML (srcdoc is only populated
88
- // for the initial iframe load; subsequent renders use doc.write).
87
+ /**
88
+ * `renderedHtml` holds the raw compiled HTML (srcdoc is only populated
89
+ * for the initial iframe load; subsequent renders use doc.write).
90
+ */
89
91
  text = renderedHtml || srcdoc.value
90
92
  } else if (sourceView.value === 'plaintext') {
91
93
  text = plaintextContent.value
@@ -160,8 +162,10 @@ const compatibilityIssues = ref<CheckIssue[]>([])
160
162
  const compatibilityLoading = ref(false)
161
163
  const compatibilityError = ref('')
162
164
  const compatibilityCategory = ref('')
163
- // Injected by serveDevUI into index.html — synchronous, available before
164
- // any HTTP calls, so the Checks tab never flashes in when disabled.
165
+ /**
166
+ * Injected by serveDevUI into index.html synchronous, available before
167
+ * any HTTP calls, so the Checks tab never flashes in when disabled.
168
+ */
165
169
  const checksConfig = (window as any).__MAIZZLE_CONFIG__?.checks
166
170
  const compatibilityDisabled = ref(checksConfig === false)
167
171
  const expandedIssueKeys = ref(new Set<string>())
@@ -237,7 +241,11 @@ function updateIframeContentHeight() {
237
241
 
238
242
  // Temporarily collapse to measure true content height
239
243
  iframe.style.height = '0'
240
- iframeContentHeight.value = doc.documentElement.scrollHeight
244
+ const contentHeight = doc.documentElement.scrollHeight
245
+ // Fill the preview viewport when the email is shorter than it; grow past it
246
+ // (and let the ScrollArea scroll) when the email is taller.
247
+ const availableHeight = viewport?.clientHeight ?? 0
248
+ iframeContentHeight.value = Math.max(contentHeight, availableHeight)
241
249
  iframe.style.height = `${iframeContentHeight.value}px`
242
250
 
243
251
  // Restore scroll position
@@ -266,8 +274,10 @@ async function fetchTemplate() {
266
274
  const iframe = iframeEl.value
267
275
  const doc = iframe?.contentDocument
268
276
 
269
- // Write directly into the iframe document to avoid a full reload,
270
- // which preserves scroll position natively.
277
+ /**
278
+ * Write directly into the iframe document to avoid a full reload,
279
+ * which preserves scroll position natively.
280
+ */
271
281
  if (doc) {
272
282
  doc.open()
273
283
  doc.write(renderedHtml)
@@ -359,9 +369,12 @@ async function fetchCompatibility() {
359
369
  } else {
360
370
  const issues: CheckIssue[] = Array.isArray(data) ? data : []
361
371
  compatibilityIssues.value = issues
362
- // Keep the current category if it still has issues; otherwise fall
363
- // back to the first category that does. Prevents a "refresh" during
364
- // edits from snapping back to CSS when the user is on HTML/Image.
372
+ /**
373
+ * Keep the current category if it still has issues; otherwise fall
374
+ * back to the first category that does. Prevents a "refresh"
375
+ * during edits from snapping back to CSS when the user is
376
+ * on HTML/Image.
377
+ */
365
378
  const current = compatibilityCategory.value
366
379
  const currentStillActive = current && issues.some((i) => i.category === current)
367
380
  if (!currentStillActive) {
@@ -462,20 +475,25 @@ if ((import.meta as any).hot) {
462
475
  fetchCompatibility()
463
476
  fetchStats()
464
477
 
465
- // Refetch in place — don't clear the previous values first. v-html
466
- // replaces the highlighted block atomically when the new content
467
- // arrives, and the ScrollArea viewport keeps its scrollTop as long
468
- // as the new content's height is similar. Plaintext interpolation
469
- // updates a single text node, so scroll is naturally preserved.
478
+ /**
479
+ * Refetch in place don't clear the previous values first. v-html
480
+ * replaces the highlighted block atomically when the new content
481
+ * arrives, and the ScrollArea viewport keeps its scrollTop as
482
+ * long as the new content's height is similar. Plaintext
483
+ * interpolation updates a single text node, so scroll
484
+ * is naturally preserved.
485
+ */
470
486
  fetchTemplate()
471
487
  fetchSource()
472
488
  fetchVueSource()
473
489
  fetchPlaintext()
474
490
  })
475
491
 
476
- // Keep the UI in sync with live config edits. Payload is the same shape
477
- // as the initial `window.__MAIZZLE_CONFIG__` inject we replace it and
478
- // derive per-feature flags from there.
492
+ /**
493
+ * Keep the UI in sync with live config edits. Payload is the same shape
494
+ * as the initial `window.__MAIZZLE_CONFIG__` inject — we replace it
495
+ * and derive per-feature flags from there.
496
+ */
479
497
  ;(import.meta as any).hot.on('maizzle:config-updated', (data: Record<string, unknown>) => {
480
498
  ;(window as any).__MAIZZLE_CONFIG__ = data
481
499
  const wasDisabled = compatibilityDisabled.value
@@ -1 +1 @@
1
- {"version":3,"file":"_helpers.js","names":[],"sources":["../../../src/tests/render/_helpers.ts"],"sourcesContent":["import { mkdtempSync, writeFileSync, mkdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { tmpdir } from 'node:os'\n\nexport function createTempProject() {\n const dir = mkdtempSync(join(tmpdir(), 'maizzle-render-'))\n return dir\n}\n\nexport function writeSfc(dir: string, path: string, content: string) {\n const full = join(dir, path)\n mkdirSync(join(dir, ...path.split('/').slice(0, -1)), { recursive: true })\n writeFileSync(full, content)\n}\n"],"mappings":";;;;AAIA,SAAgB,oBAAoB;CAElC,OADY,YAAY,KAAK,QAAQ,EAAE,kBAAkB,CAC/C;;AAGZ,SAAgB,SAAS,KAAa,MAAc,SAAiB;CACnE,MAAM,OAAO,KAAK,KAAK,KAAK;CAC5B,UAAU,KAAK,KAAK,GAAG,KAAK,MAAM,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,EAAE,EAAE,WAAW,MAAM,CAAC;CAC1E,cAAc,MAAM,QAAQ"}
1
+ {"version":3,"file":"_helpers.js","names":[],"sources":["../../../src/tests/render/_helpers.ts"],"sourcesContent":["import { mkdtempSync, writeFileSync, mkdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { tmpdir } from 'node:os'\n\nexport function createTempProject() {\n const dir = mkdtempSync(join(tmpdir(), 'maizzle-render-'))\n return dir\n}\n\nexport function writeSfc(dir: string, path: string, content: string) {\n const full = join(dir, path)\n mkdirSync(join(dir, ...path.split('/').slice(0, -1)), { recursive: true })\n writeFileSync(full, content)\n}\n"],"mappings":";;;;AAIA,SAAgB,oBAAoB;CAElC,OADY,YAAY,KAAK,OAAO,GAAG,iBAAiB,CAC/C;AACX;AAEA,SAAgB,SAAS,KAAa,MAAc,SAAiB;CACnE,MAAM,OAAO,KAAK,KAAK,IAAI;CAC3B,UAAU,KAAK,KAAK,GAAG,KAAK,MAAM,GAAG,EAAE,MAAM,GAAG,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,CAAC;CACzE,cAAc,MAAM,OAAO;AAC7B"}
@@ -1 +1 @@
1
- {"version":3,"file":"addAttributes.d.ts","names":[],"sources":["../../src/transformers/addAttributes.ts"],"mappings":";;;;;;AA+CA;;;;;;;;;AASA;;;;;;;;;;;;;;;;;iBATgB,aAAA,CAAc,IAAA,UAAc,MAAA,GAAQ,gBAAA;;;;;;iBASpC,gBAAA,CAAiB,GAAA,EAAK,SAAA,IAAa,MAAA,GAAQ,gBAAA,GAAwB,SAAA"}
1
+ {"version":3,"file":"addAttributes.d.ts","names":[],"sources":["../../src/transformers/addAttributes.ts"],"mappings":";;;;;;AA+CA;;;;;;;;AAAyE;AASzE;;;;;;;;;;;;;;AAA4F;;;iBAT5E,aAAA,CAAc,IAAA,UAAc,MAAA,GAAQ,gBAAqB;;;;;;iBASzD,gBAAA,CAAiB,GAAA,EAAK,SAAA,IAAa,MAAA,GAAQ,gBAAA,GAAwB,SAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"addAttributes.js","names":["merge"],"sources":["../../src/transformers/addAttributes.ts"],"sourcesContent":["import { defu as merge } from 'defu'\nimport type { ChildNode, Element } from 'domhandler'\nimport { parse, serialize, walk } from '../utils/ast/index.ts'\nimport type { AttributesConfig } from '../types/config.ts'\n\n/**\n * Default attributes to add to elements.\n */\nconst DEFAULT_ATTRIBUTES: Record<string, Record<string, string | boolean | number>> = {\n table: {\n cellpadding: 0,\n cellspacing: 0,\n role: 'none',\n },\n img: {\n alt: '',\n },\n}\n\n/**\n * Add attributes transformer.\n *\n * Automatically adds attributes to HTML elements based on CSS selectors.\n *\n * Default attributes (can be disabled by setting `attributes.add` to false):\n * - table: cellpadding=\"0\", cellspacing=\"0\", role=\"none\"\n * - img: alt=\"\"\n *\n * Supports tag, class, id, and attribute selectors.\n * Multiple selectors can be specified by comma-separating them.\n *\n * @param html HTML string to transform.\n * @param config Attributes config (see {@link AttributesConfig}).\n * @returns The transformed HTML string.\n *\n * @example\n * import { addAttributes } from '@maizzle/framework'\n *\n * const out = addAttributes('<div></div>', {\n * add: {\n * div: { role: 'article' },\n * '.test': { editable: true },\n * '#header': { 'data-id': 'main' },\n * 'div, p': { class: 'content' },\n * },\n * })\n */\nexport function addAttributes(html: string, config: AttributesConfig = {}): string {\n return serialize(addAttributesDom(parse(html), config))\n}\n\n/**\n * DOM-form of {@link addAttributes} 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 addAttributesDom(dom: ChildNode[], config: AttributesConfig = {}): ChildNode[] {\n const addConfig = config.add\n\n // Disabled when explicitly set to false\n if (addConfig === false) {\n return dom\n }\n\n // Deep merge user attributes on top of defaults using defu\n const userAttributes = typeof addConfig === 'object' ? addConfig : {}\n const attributesToAdd = merge(userAttributes, DEFAULT_ATTRIBUTES) as Record<string, false | Record<string, false | string | boolean | number>>\n\n if (Object.keys(attributesToAdd).length === 0) {\n return dom\n }\n\n // Process each selector pattern\n for (const [selectorPattern, attributes] of Object.entries(attributesToAdd)) {\n // User opted out of this selector entirely (e.g. `table: false`)\n if (attributes === false) continue\n // Split by comma for multiple selectors\n const selectors = selectorPattern.split(',').map(s => s.trim())\n\n walk(dom, (node) => {\n const el = node as Element\n if (!el.name) return\n\n // Check if element matches any selector in the pattern\n const matches = selectors.some(selector => elementMatches(el, selector))\n\n if (matches) {\n // Initialize attribs if needed\n if (!el.attribs) {\n el.attribs = {}\n }\n\n for (const [attrName, attrValue] of Object.entries(attributes)) {\n // User opted out of this specific attribute (e.g. `role: false`)\n if (attrValue === false) continue\n // Special handling for class - merge instead of replace\n if (attrName === 'class' && el.attribs.class) {\n const existingClasses = el.attribs.class.split(/\\s+/).filter(Boolean)\n const newClasses = String(attrValue).split(/\\s+/).filter(Boolean)\n const mergedClasses = [...new Set([...existingClasses, ...newClasses])]\n if (mergedClasses.join(' ') !== el.attribs.class) {\n el.attribs.class = mergedClasses.join(' ')\n }\n } else {\n // Only add attribute if not already present\n if (!(attrName in el.attribs)) {\n el.attribs[attrName] = String(attrValue)\n }\n }\n }\n }\n })\n }\n\n return dom\n}\n\n/**\n * Check if an element matches a CSS selector.\n * Supports: tag, .class, #id, [attribute], [attribute=value]\n */\nfunction elementMatches(el: Element, selector: string): boolean {\n // Remove whitespace\n selector = selector.trim()\n\n // Check for attribute selector [attr] or [attr=value]\n const attrMatch = selector.match(/^\\[([^\\]=]+)(?:=([^\\]]*))?\\]$/)\n if (attrMatch) {\n const [, attrName, attrValue] = attrMatch\n if (attrValue === undefined) {\n // Just checking if attribute exists\n return attrName in (el.attribs || {})\n } else {\n // Check if attribute has specific value\n return el.attribs?.[attrName] === attrValue\n }\n }\n\n // Check for class selector .class\n if (selector.startsWith('.')) {\n const className = selector.slice(1)\n const classes = el.attribs?.class?.split(/\\s+/) || []\n return classes.includes(className)\n }\n\n // Check for id selector #id\n if (selector.startsWith('#')) {\n const id = selector.slice(1)\n return el.attribs?.id === id\n }\n\n // Check for tag selector (possibly with attribute)\n // Split tag from attribute if present, e.g., \"div[role=alert]\"\n const tagAttrMatch = selector.match(/^([a-z][a-z0-9]*)\\[([^\\]]+)\\]$/i)\n if (tagAttrMatch) {\n const [, tagName, attrPart] = tagAttrMatch\n if (el.name !== tagName) return false\n\n // Parse attribute part: could be \"attr\" or \"attr=value\"\n const attrEqMatch = attrPart.match(/^([^=]+)(?:=(.*))?$/)\n if (attrEqMatch) {\n const [, attrName, attrValue] = attrEqMatch\n if (attrValue === undefined) {\n return attrName in (el.attribs || {})\n } else {\n return el.attribs?.[attrName] === attrValue\n }\n }\n return false\n }\n\n // Simple tag selector\n return el.name === selector\n}\n"],"mappings":";;;;;;;;;AAQA,MAAM,qBAAgF;CACpF,OAAO;EACL,aAAa;EACb,aAAa;EACb,MAAM;EACP;CACD,KAAK,EACH,KAAK,IACN;CACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BD,SAAgB,cAAc,MAAc,SAA2B,EAAE,EAAU;CACjF,OAAO,UAAU,iBAAiB,MAAM,KAAK,EAAE,OAAO,CAAC;;;;;;;AAQzD,SAAgB,iBAAiB,KAAkB,SAA2B,EAAE,EAAe;CAC7F,MAAM,YAAY,OAAO;CAGzB,IAAI,cAAc,OAChB,OAAO;CAKT,MAAM,kBAAkBA,OADD,OAAO,cAAc,WAAW,YAAY,EAAE,EACvB,mBAAmB;CAEjE,IAAI,OAAO,KAAK,gBAAgB,CAAC,WAAW,GAC1C,OAAO;CAIT,KAAK,MAAM,CAAC,iBAAiB,eAAe,OAAO,QAAQ,gBAAgB,EAAE;EAE3E,IAAI,eAAe,OAAO;EAE1B,MAAM,YAAY,gBAAgB,MAAM,IAAI,CAAC,KAAI,MAAK,EAAE,MAAM,CAAC;EAE/D,KAAK,MAAM,SAAS;GAClB,MAAM,KAAK;GACX,IAAI,CAAC,GAAG,MAAM;GAKd,IAFgB,UAAU,MAAK,aAAY,eAAe,IAAI,SAAS,CAE5D,EAAE;IAEX,IAAI,CAAC,GAAG,SACN,GAAG,UAAU,EAAE;IAGjB,KAAK,MAAM,CAAC,UAAU,cAAc,OAAO,QAAQ,WAAW,EAAE;KAE9D,IAAI,cAAc,OAAO;KAEzB,IAAI,aAAa,WAAW,GAAG,QAAQ,OAAO;MAC5C,MAAM,kBAAkB,GAAG,QAAQ,MAAM,MAAM,MAAM,CAAC,OAAO,QAAQ;MACrE,MAAM,aAAa,OAAO,UAAU,CAAC,MAAM,MAAM,CAAC,OAAO,QAAQ;MACjE,MAAM,gBAAgB,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,iBAAiB,GAAG,WAAW,CAAC,CAAC;MACvE,IAAI,cAAc,KAAK,IAAI,KAAK,GAAG,QAAQ,OACzC,GAAG,QAAQ,QAAQ,cAAc,KAAK,IAAI;YAI5C,IAAI,EAAE,YAAY,GAAG,UACnB,GAAG,QAAQ,YAAY,OAAO,UAAU;;;IAKhD;;CAGJ,OAAO;;;;;;AAOT,SAAS,eAAe,IAAa,UAA2B;CAE9D,WAAW,SAAS,MAAM;CAG1B,MAAM,YAAY,SAAS,MAAM,gCAAgC;CACjE,IAAI,WAAW;EACb,MAAM,GAAG,UAAU,aAAa;EAChC,IAAI,cAAc,KAAA,GAEhB,OAAO,aAAa,GAAG,WAAW,EAAE;OAGpC,OAAO,GAAG,UAAU,cAAc;;CAKtC,IAAI,SAAS,WAAW,IAAI,EAAE;EAC5B,MAAM,YAAY,SAAS,MAAM,EAAE;EAEnC,QADgB,GAAG,SAAS,OAAO,MAAM,MAAM,IAAI,EAAE,EACtC,SAAS,UAAU;;CAIpC,IAAI,SAAS,WAAW,IAAI,EAAE;EAC5B,MAAM,KAAK,SAAS,MAAM,EAAE;EAC5B,OAAO,GAAG,SAAS,OAAO;;CAK5B,MAAM,eAAe,SAAS,MAAM,kCAAkC;CACtE,IAAI,cAAc;EAChB,MAAM,GAAG,SAAS,YAAY;EAC9B,IAAI,GAAG,SAAS,SAAS,OAAO;EAGhC,MAAM,cAAc,SAAS,MAAM,sBAAsB;EACzD,IAAI,aAAa;GACf,MAAM,GAAG,UAAU,aAAa;GAChC,IAAI,cAAc,KAAA,GAChB,OAAO,aAAa,GAAG,WAAW,EAAE;QAEpC,OAAO,GAAG,UAAU,cAAc;;EAGtC,OAAO;;CAIT,OAAO,GAAG,SAAS"}
1
+ {"version":3,"file":"addAttributes.js","names":["merge"],"sources":["../../src/transformers/addAttributes.ts"],"sourcesContent":["import { defu as merge } from 'defu'\nimport type { ChildNode, Element } from 'domhandler'\nimport { parse, serialize, walk } from '../utils/ast/index.ts'\nimport type { AttributesConfig } from '../types/config.ts'\n\n/**\n * Default attributes to add to elements.\n */\nconst DEFAULT_ATTRIBUTES: Record<string, Record<string, string | boolean | number>> = {\n table: {\n cellpadding: 0,\n cellspacing: 0,\n role: 'none',\n },\n img: {\n alt: '',\n },\n}\n\n/**\n * Add attributes transformer.\n *\n * Automatically adds attributes to HTML elements based on CSS selectors.\n *\n * Default attributes (can be disabled by setting `attributes.add` to false):\n * - table: cellpadding=\"0\", cellspacing=\"0\", role=\"none\"\n * - img: alt=\"\"\n *\n * Supports tag, class, id, and attribute selectors.\n * Multiple selectors can be specified by comma-separating them.\n *\n * @param html HTML string to transform.\n * @param config Attributes config (see {@link AttributesConfig}).\n * @returns The transformed HTML string.\n *\n * @example\n * import { addAttributes } from '@maizzle/framework'\n *\n * const out = addAttributes('<div></div>', {\n * add: {\n * div: { role: 'article' },\n * '.test': { editable: true },\n * '#header': { 'data-id': 'main' },\n * 'div, p': { class: 'content' },\n * },\n * })\n */\nexport function addAttributes(html: string, config: AttributesConfig = {}): string {\n return serialize(addAttributesDom(parse(html), config))\n}\n\n/**\n * DOM-form of {@link addAttributes} 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 addAttributesDom(dom: ChildNode[], config: AttributesConfig = {}): ChildNode[] {\n const addConfig = config.add\n\n // Disabled when explicitly set to false\n if (addConfig === false) {\n return dom\n }\n\n // Deep merge user attributes on top of defaults using defu\n const userAttributes = typeof addConfig === 'object' ? addConfig : {}\n const attributesToAdd = merge(userAttributes, DEFAULT_ATTRIBUTES) as Record<string, false | Record<string, false | string | boolean | number>>\n\n if (Object.keys(attributesToAdd).length === 0) {\n return dom\n }\n\n // Process each selector pattern\n for (const [selectorPattern, attributes] of Object.entries(attributesToAdd)) {\n // User opted out of this selector entirely (e.g. `table: false`)\n if (attributes === false) continue\n // Split by comma for multiple selectors\n const selectors = selectorPattern.split(',').map(s => s.trim())\n\n walk(dom, (node) => {\n const el = node as Element\n if (!el.name) return\n\n // Check if element matches any selector in the pattern\n const matches = selectors.some(selector => elementMatches(el, selector))\n\n if (matches) {\n // Initialize attribs if needed\n if (!el.attribs) {\n el.attribs = {}\n }\n\n for (const [attrName, attrValue] of Object.entries(attributes)) {\n // User opted out of this specific attribute (e.g. `role: false`)\n if (attrValue === false) continue\n // Special handling for class - merge instead of replace\n if (attrName === 'class' && el.attribs.class) {\n const existingClasses = el.attribs.class.split(/\\s+/).filter(Boolean)\n const newClasses = String(attrValue).split(/\\s+/).filter(Boolean)\n const mergedClasses = [...new Set([...existingClasses, ...newClasses])]\n if (mergedClasses.join(' ') !== el.attribs.class) {\n el.attribs.class = mergedClasses.join(' ')\n }\n } else {\n // Only add attribute if not already present\n if (!(attrName in el.attribs)) {\n el.attribs[attrName] = String(attrValue)\n }\n }\n }\n }\n })\n }\n\n return dom\n}\n\n/**\n * Check if an element matches a CSS selector.\n * Supports: tag, .class, #id, [attribute], [attribute=value]\n */\nfunction elementMatches(el: Element, selector: string): boolean {\n // Remove whitespace\n selector = selector.trim()\n\n // Check for attribute selector [attr] or [attr=value]\n const attrMatch = selector.match(/^\\[([^\\]=]+)(?:=([^\\]]*))?\\]$/)\n if (attrMatch) {\n const [, attrName, attrValue] = attrMatch\n if (attrValue === undefined) {\n // Just checking if attribute exists\n return attrName in (el.attribs || {})\n } else {\n // Check if attribute has specific value\n return el.attribs?.[attrName] === attrValue\n }\n }\n\n // Check for class selector .class\n if (selector.startsWith('.')) {\n const className = selector.slice(1)\n const classes = el.attribs?.class?.split(/\\s+/) || []\n return classes.includes(className)\n }\n\n // Check for id selector #id\n if (selector.startsWith('#')) {\n const id = selector.slice(1)\n return el.attribs?.id === id\n }\n\n // Check for tag selector (possibly with attribute)\n // Split tag from attribute if present, e.g., \"div[role=alert]\"\n const tagAttrMatch = selector.match(/^([a-z][a-z0-9]*)\\[([^\\]]+)\\]$/i)\n if (tagAttrMatch) {\n const [, tagName, attrPart] = tagAttrMatch\n if (el.name !== tagName) return false\n\n // Parse attribute part: could be \"attr\" or \"attr=value\"\n const attrEqMatch = attrPart.match(/^([^=]+)(?:=(.*))?$/)\n if (attrEqMatch) {\n const [, attrName, attrValue] = attrEqMatch\n if (attrValue === undefined) {\n return attrName in (el.attribs || {})\n } else {\n return el.attribs?.[attrName] === attrValue\n }\n }\n return false\n }\n\n // Simple tag selector\n return el.name === selector\n}\n"],"mappings":";;;;;;;;;AAQA,MAAM,qBAAgF;CACpF,OAAO;EACL,aAAa;EACb,aAAa;EACb,MAAM;CACR;CACA,KAAK,EACH,KAAK,GACP;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,SAAgB,cAAc,MAAc,SAA2B,CAAC,GAAW;CACjF,OAAO,UAAU,iBAAiB,MAAM,IAAI,GAAG,MAAM,CAAC;AACxD;;;;;;AAOA,SAAgB,iBAAiB,KAAkB,SAA2B,CAAC,GAAgB;CAC7F,MAAM,YAAY,OAAO;CAGzB,IAAI,cAAc,OAChB,OAAO;CAKT,MAAM,kBAAkBA,OADD,OAAO,cAAc,WAAW,YAAY,CAAC,GACtB,kBAAkB;CAEhE,IAAI,OAAO,KAAK,eAAe,EAAE,WAAW,GAC1C,OAAO;CAIT,KAAK,MAAM,CAAC,iBAAiB,eAAe,OAAO,QAAQ,eAAe,GAAG;EAE3E,IAAI,eAAe,OAAO;EAE1B,MAAM,YAAY,gBAAgB,MAAM,GAAG,EAAE,KAAI,MAAK,EAAE,KAAK,CAAC;EAE9D,KAAK,MAAM,SAAS;GAClB,MAAM,KAAK;GACX,IAAI,CAAC,GAAG,MAAM;GAKd,IAFgB,UAAU,MAAK,aAAY,eAAe,IAAI,QAAQ,CAE5D,GAAG;IAEX,IAAI,CAAC,GAAG,SACN,GAAG,UAAU,CAAC;IAGhB,KAAK,MAAM,CAAC,UAAU,cAAc,OAAO,QAAQ,UAAU,GAAG;KAE9D,IAAI,cAAc,OAAO;KAEzB,IAAI,aAAa,WAAW,GAAG,QAAQ,OAAO;MAC5C,MAAM,kBAAkB,GAAG,QAAQ,MAAM,MAAM,KAAK,EAAE,OAAO,OAAO;MACpE,MAAM,aAAa,OAAO,SAAS,EAAE,MAAM,KAAK,EAAE,OAAO,OAAO;MAChE,MAAM,gBAAgB,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,iBAAiB,GAAG,UAAU,CAAC,CAAC;MACtE,IAAI,cAAc,KAAK,GAAG,MAAM,GAAG,QAAQ,OACzC,GAAG,QAAQ,QAAQ,cAAc,KAAK,GAAG;KAE7C,OAEE,IAAI,EAAE,YAAY,GAAG,UACnB,GAAG,QAAQ,YAAY,OAAO,SAAS;IAG7C;GACF;EACF,CAAC;CACH;CAEA,OAAO;AACT;;;;;AAMA,SAAS,eAAe,IAAa,UAA2B;CAE9D,WAAW,SAAS,KAAK;CAGzB,MAAM,YAAY,SAAS,MAAM,+BAA+B;CAChE,IAAI,WAAW;EACb,MAAM,GAAG,UAAU,aAAa;EAChC,IAAI,cAAc,KAAA,GAEhB,OAAO,aAAa,GAAG,WAAW,CAAC;OAGnC,OAAO,GAAG,UAAU,cAAc;CAEtC;CAGA,IAAI,SAAS,WAAW,GAAG,GAAG;EAC5B,MAAM,YAAY,SAAS,MAAM,CAAC;EAElC,QADgB,GAAG,SAAS,OAAO,MAAM,KAAK,KAAK,CAAC,GACrC,SAAS,SAAS;CACnC;CAGA,IAAI,SAAS,WAAW,GAAG,GAAG;EAC5B,MAAM,KAAK,SAAS,MAAM,CAAC;EAC3B,OAAO,GAAG,SAAS,OAAO;CAC5B;CAIA,MAAM,eAAe,SAAS,MAAM,iCAAiC;CACrE,IAAI,cAAc;EAChB,MAAM,GAAG,SAAS,YAAY;EAC9B,IAAI,GAAG,SAAS,SAAS,OAAO;EAGhC,MAAM,cAAc,SAAS,MAAM,qBAAqB;EACxD,IAAI,aAAa;GACf,MAAM,GAAG,UAAU,aAAa;GAChC,IAAI,cAAc,KAAA,GAChB,OAAO,aAAa,GAAG,WAAW,CAAC;QAEnC,OAAO,GAAG,UAAU,cAAc;EAEtC;EACA,OAAO;CACT;CAGA,OAAO,GAAG,SAAS;AACrB"}
@@ -1 +1 @@
1
- {"version":3,"file":"attributeToStyle.d.ts","names":[],"sources":["../../src/transformers/attributeToStyle.ts"],"mappings":";;;;;AAiCA;;;;;AASA;;;;;;;;;;;;;;;;;;iBATgB,gBAAA,CAAiB,IAAA,UAAc,UAAA;;;;;;iBAS/B,mBAAA,CAAoB,GAAA,EAAK,SAAA,IAAa,UAAA,wBAAwC,SAAA"}
1
+ {"version":3,"file":"attributeToStyle.d.ts","names":[],"sources":["../../src/transformers/attributeToStyle.ts"],"mappings":";;;;;AAiCA;;;;AAAoF;AASpF;;;;;;;;;AAAuG;;;;;;;;;iBATvF,gBAAA,CAAiB,IAAA,UAAc,UAAqC;;;;;;iBASpE,mBAAA,CAAoB,GAAA,EAAK,SAAA,IAAa,UAAA,wBAAwC,SAAS"}
@@ -1 +1 @@
1
- {"version":3,"file":"attributeToStyle.js","names":[],"sources":["../../src/transformers/attributeToStyle.ts"],"sourcesContent":["import type { ChildNode, Element } from 'domhandler'\nimport { parse, serialize, walk } from '../utils/ast/index.ts'\n\n/**\n * Default list of attributes that can be converted to inline styles.\n */\nconst DEFAULT_ATTRIBUTES = ['width', 'height', 'bgcolor', 'background', 'align', 'valign']\n\n/**\n * Convert HTML attributes to inline CSS styles.\n *\n * Supported attributes:\n * - `width`: `width: ${value}${unit}` (px and %, defaults to px)\n * - `height`: `height: ${value}${unit}` (px and %, defaults to px)\n * - `bgcolor`: `background-color: ${value}`\n * - `background`: `background-image: url('${value}')`\n * - `align`: on `<table>`, `left`/`right` become `float`, `center` becomes\n * `margin-left/right: auto`; on other elements, becomes `text-align`\n * - `valign`: `vertical-align: ${value}`\n *\n * @param html HTML string to transform.\n * @param attributes `true` to process the default set, an array to restrict\n * to specific attribute names, `false` to disable.\n * @returns The transformed HTML string.\n *\n * @example\n * import { attributeToStyle } from '@maizzle/framework'\n *\n * const out = attributeToStyle('<table align=\"center\"><tr><td bgcolor=\"#f00\">x</td></tr></table>')\n *\n * // Restrict to specific attributes:\n * const limited = attributeToStyle(html, ['width', 'height'])\n */\nexport function attributeToStyle(html: string, attributes: boolean | string[] = true): string {\n return serialize(attributeToStyleDom(parse(html), attributes))\n}\n\n/**\n * DOM-form of {@link attributeToStyle} used by the internal transformer\n * pipeline. Takes a parsed DOM, returns a parsed DOM — avoids redundant\n * serialize/parse round-trips when chained with other transformers.\n */\nexport function attributeToStyleDom(dom: ChildNode[], attributes: boolean | string[] = true): ChildNode[] {\n if (!attributes) return dom\n\n const attributesToProcess: string[] = attributes === true\n ? DEFAULT_ATTRIBUTES\n : Array.isArray(attributes)\n ? attributes\n : []\n\n if (attributesToProcess.length === 0) return dom\n\n walk(dom, (node) => {\n const el = node as Element\n\n if (!('attribs' in el) || !el.attribs) {\n return\n }\n\n const styles: string[] = []\n\n for (const attr of attributesToProcess) {\n const value = el.attribs[attr]\n if (!value) continue\n\n const styleValue = convertAttributeToStyle(el.name, attr, value)\n if (styleValue) {\n styles.push(styleValue)\n }\n }\n\n // Append new styles to existing style attribute\n if (styles.length > 0) {\n const existingStyle = el.attribs.style || ''\n const separator = existingStyle ? '; ' : ''\n el.attribs.style = existingStyle + separator + styles.join('; ')\n }\n })\n\n return dom\n}\n\n/**\n * Convert a single HTML attribute value to a CSS style declaration.\n */\nfunction convertAttributeToStyle(\n tagName: string,\n attr: string,\n value: string,\n): string | null {\n switch (attr) {\n case 'width':\n case 'height': {\n // Support px and % values, default to px if no unit\n const normalizedValue = /^\\d+$/.test(value) ? `${value}px` : value\n return `${attr}: ${normalizedValue}`\n }\n\n case 'bgcolor':\n return `background-color: ${value}`\n\n case 'background':\n return `background-image: url('${value}')`\n\n case 'align': {\n // On table elements: left/right -> float, center -> margin auto\n if (tagName === 'table') {\n if (value === 'left' || value === 'right') {\n return `float: ${value}`\n }\n if (value === 'center') {\n return 'margin-left: auto; margin-right: auto'\n }\n }\n // On other elements: text-align\n return `text-align: ${value}`\n }\n\n case 'valign':\n return `vertical-align: ${value}`\n\n default:\n return null\n }\n}\n"],"mappings":";;;;;;;;AAMA,MAAM,qBAAqB;CAAC;CAAS;CAAU;CAAW;CAAc;CAAS;CAAS;;;;;;;;;;;;;;;;;;;;;;;;;;AA2B1F,SAAgB,iBAAiB,MAAc,aAAiC,MAAc;CAC5F,OAAO,UAAU,oBAAoB,MAAM,KAAK,EAAE,WAAW,CAAC;;;;;;;AAQhE,SAAgB,oBAAoB,KAAkB,aAAiC,MAAmB;CACxG,IAAI,CAAC,YAAY,OAAO;CAExB,MAAM,sBAAgC,eAAe,OACjD,qBACA,MAAM,QAAQ,WAAW,GACvB,aACA,EAAE;CAER,IAAI,oBAAoB,WAAW,GAAG,OAAO;CAE7C,KAAK,MAAM,SAAS;EAClB,MAAM,KAAK;EAEX,IAAI,EAAE,aAAa,OAAO,CAAC,GAAG,SAC5B;EAGF,MAAM,SAAmB,EAAE;EAE3B,KAAK,MAAM,QAAQ,qBAAqB;GACtC,MAAM,QAAQ,GAAG,QAAQ;GACzB,IAAI,CAAC,OAAO;GAEZ,MAAM,aAAa,wBAAwB,GAAG,MAAM,MAAM,MAAM;GAChE,IAAI,YACF,OAAO,KAAK,WAAW;;EAK3B,IAAI,OAAO,SAAS,GAAG;GACrB,MAAM,gBAAgB,GAAG,QAAQ,SAAS;GAC1C,MAAM,YAAY,gBAAgB,OAAO;GACzC,GAAG,QAAQ,QAAQ,gBAAgB,YAAY,OAAO,KAAK,KAAK;;GAElE;CAEF,OAAO;;;;;AAMT,SAAS,wBACP,SACA,MACA,OACe;CACf,QAAQ,MAAR;EACE,KAAK;EACL,KAAK,UAGH,OAAO,GAAG,KAAK,IADS,QAAQ,KAAK,MAAM,GAAG,GAAG,MAAM,MAAM;EAI/D,KAAK,WACH,OAAO,qBAAqB;EAE9B,KAAK,cACH,OAAO,0BAA0B,MAAM;EAEzC,KAAK;GAEH,IAAI,YAAY,SAAS;IACvB,IAAI,UAAU,UAAU,UAAU,SAChC,OAAO,UAAU;IAEnB,IAAI,UAAU,UACZ,OAAO;;GAIX,OAAO,eAAe;EAGxB,KAAK,UACH,OAAO,mBAAmB;EAE5B,SACE,OAAO"}
1
+ {"version":3,"file":"attributeToStyle.js","names":[],"sources":["../../src/transformers/attributeToStyle.ts"],"sourcesContent":["import type { ChildNode, Element } from 'domhandler'\nimport { parse, serialize, walk } from '../utils/ast/index.ts'\n\n/**\n * Default list of attributes that can be converted to inline styles.\n */\nconst DEFAULT_ATTRIBUTES = ['width', 'height', 'bgcolor', 'background', 'align', 'valign']\n\n/**\n * Convert HTML attributes to inline CSS styles.\n *\n * Supported attributes:\n * - `width`: `width: ${value}${unit}` (px and %, defaults to px)\n * - `height`: `height: ${value}${unit}` (px and %, defaults to px)\n * - `bgcolor`: `background-color: ${value}`\n * - `background`: `background-image: url('${value}')`\n * - `align`: on `<table>`, `left`/`right` become `float`, `center` becomes\n * `margin-left/right: auto`; on other elements, becomes `text-align`\n * - `valign`: `vertical-align: ${value}`\n *\n * @param html HTML string to transform.\n * @param attributes `true` to process the default set, an array to restrict\n * to specific attribute names, `false` to disable.\n * @returns The transformed HTML string.\n *\n * @example\n * import { attributeToStyle } from '@maizzle/framework'\n *\n * const out = attributeToStyle('<table align=\"center\"><tr><td bgcolor=\"#f00\">x</td></tr></table>')\n *\n * // Restrict to specific attributes:\n * const limited = attributeToStyle(html, ['width', 'height'])\n */\nexport function attributeToStyle(html: string, attributes: boolean | string[] = true): string {\n return serialize(attributeToStyleDom(parse(html), attributes))\n}\n\n/**\n * DOM-form of {@link attributeToStyle} used by the internal transformer\n * pipeline. Takes a parsed DOM, returns a parsed DOM — avoids redundant\n * serialize/parse round-trips when chained with other transformers.\n */\nexport function attributeToStyleDom(dom: ChildNode[], attributes: boolean | string[] = true): ChildNode[] {\n if (!attributes) return dom\n\n const attributesToProcess: string[] = attributes === true\n ? DEFAULT_ATTRIBUTES\n : Array.isArray(attributes)\n ? attributes\n : []\n\n if (attributesToProcess.length === 0) return dom\n\n walk(dom, (node) => {\n const el = node as Element\n\n if (!('attribs' in el) || !el.attribs) {\n return\n }\n\n const styles: string[] = []\n\n for (const attr of attributesToProcess) {\n const value = el.attribs[attr]\n if (!value) continue\n\n const styleValue = convertAttributeToStyle(el.name, attr, value)\n if (styleValue) {\n styles.push(styleValue)\n }\n }\n\n // Append new styles to existing style attribute\n if (styles.length > 0) {\n const existingStyle = el.attribs.style || ''\n const separator = existingStyle ? '; ' : ''\n el.attribs.style = existingStyle + separator + styles.join('; ')\n }\n })\n\n return dom\n}\n\n/**\n * Convert a single HTML attribute value to a CSS style declaration.\n */\nfunction convertAttributeToStyle(\n tagName: string,\n attr: string,\n value: string,\n): string | null {\n switch (attr) {\n case 'width':\n case 'height': {\n // Support px and % values, default to px if no unit\n const normalizedValue = /^\\d+$/.test(value) ? `${value}px` : value\n return `${attr}: ${normalizedValue}`\n }\n\n case 'bgcolor':\n return `background-color: ${value}`\n\n case 'background':\n return `background-image: url('${value}')`\n\n case 'align': {\n // On table elements: left/right -> float, center -> margin auto\n if (tagName === 'table') {\n if (value === 'left' || value === 'right') {\n return `float: ${value}`\n }\n if (value === 'center') {\n return 'margin-left: auto; margin-right: auto'\n }\n }\n // On other elements: text-align\n return `text-align: ${value}`\n }\n\n case 'valign':\n return `vertical-align: ${value}`\n\n default:\n return null\n }\n}\n"],"mappings":";;;;;;;;AAMA,MAAM,qBAAqB;CAAC;CAAS;CAAU;CAAW;CAAc;CAAS;AAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BzF,SAAgB,iBAAiB,MAAc,aAAiC,MAAc;CAC5F,OAAO,UAAU,oBAAoB,MAAM,IAAI,GAAG,UAAU,CAAC;AAC/D;;;;;;AAOA,SAAgB,oBAAoB,KAAkB,aAAiC,MAAmB;CACxG,IAAI,CAAC,YAAY,OAAO;CAExB,MAAM,sBAAgC,eAAe,OACjD,qBACA,MAAM,QAAQ,UAAU,IACtB,aACA,CAAC;CAEP,IAAI,oBAAoB,WAAW,GAAG,OAAO;CAE7C,KAAK,MAAM,SAAS;EAClB,MAAM,KAAK;EAEX,IAAI,EAAE,aAAa,OAAO,CAAC,GAAG,SAC5B;EAGF,MAAM,SAAmB,CAAC;EAE1B,KAAK,MAAM,QAAQ,qBAAqB;GACtC,MAAM,QAAQ,GAAG,QAAQ;GACzB,IAAI,CAAC,OAAO;GAEZ,MAAM,aAAa,wBAAwB,GAAG,MAAM,MAAM,KAAK;GAC/D,IAAI,YACF,OAAO,KAAK,UAAU;EAE1B;EAGA,IAAI,OAAO,SAAS,GAAG;GACrB,MAAM,gBAAgB,GAAG,QAAQ,SAAS;GAC1C,MAAM,YAAY,gBAAgB,OAAO;GACzC,GAAG,QAAQ,QAAQ,gBAAgB,YAAY,OAAO,KAAK,IAAI;EACjE;CACF,CAAC;CAED,OAAO;AACT;;;;AAKA,SAAS,wBACP,SACA,MACA,OACe;CACf,QAAQ,MAAR;EACE,KAAK;EACL,KAAK,UAGH,OAAO,GAAG,KAAK,IADS,QAAQ,KAAK,KAAK,IAAI,GAAG,MAAM,MAAM;EAI/D,KAAK,WACH,OAAO,qBAAqB;EAE9B,KAAK,cACH,OAAO,0BAA0B,MAAM;EAEzC,KAAK;GAEH,IAAI,YAAY,SAAS;IACvB,IAAI,UAAU,UAAU,UAAU,SAChC,OAAO,UAAU;IAEnB,IAAI,UAAU,UACZ,OAAO;GAEX;GAEA,OAAO,eAAe;EAGxB,KAAK,UACH,OAAO,mBAAmB;EAE5B,SACE,OAAO;CACX;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"base.d.ts","names":[],"sources":["../../src/transformers/base.ts"],"mappings":";;;;;AAUA;UAAiB,cAAA;;EAEf,GAAA;EAUkB;;;;;;;;;EAAlB,IAAA,cAAkB,MAAA,SAAe,MAAA;EAWjC;;;;EANA,UAAA,GAAa,MAAA;EAuIK;;;;;EAjIlB,QAAA;EAiIiE;;AASnE;;;EApIE,SAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;iBA2Hc,IAAA,CAAK,IAAA,UAAc,OAAA,WAAkB,cAAA;;;;;;iBASrC,OAAA,CAAQ,GAAA,EAAK,SAAA,IAAa,OAAA,WAAkB,cAAA,8BAA4C,SAAA"}
1
+ {"version":3,"file":"base.d.ts","names":[],"sources":["../../src/transformers/base.ts"],"mappings":";;;;;AAUA;UAAiB,cAAA;;EAEf,GAAA;EAUkB;;;;;;;;;EAAlB,IAAA,cAAkB,MAAA,SAAe,MAAA;EAWjC;;;AAMS;EAZT,UAAA,GAAa,MAAA;EAuIK;;;;;EAjIlB,QAAA;EAiIiE;AAAA;AASnE;;;EApIE,SAAA;AAAA;;;;;;;;;;AAoI+G;;;;;;;;;;;;;;;iBATjG,IAAA,CAAK,IAAA,UAAc,OAAA,WAAkB,cAAc;;;;;;iBASnD,OAAA,CAAQ,GAAA,EAAK,SAAA,IAAa,OAAA,WAAkB,cAAA,8BAA4C,SAAA"}
@@ -146,6 +146,10 @@ function baseDom(dom, options) {
146
146
  }
147
147
  for (const [attr, url] of Object.entries(attributes)) if (el.attribs[attr] && !isAbsoluteUrl(el.attribs[attr])) el.attribs[attr] = url + el.attribs[attr];
148
148
  });
149
+ /**
150
+ * VML and MSO comment rewrites require operating on serialized HTML
151
+ * (HTML comments are not represented as traversable DOM nodes).
152
+ */
149
153
  const serialized = serialize(dom);
150
154
  const rewritten = rewriteMsoComments(rewriteVMLs(serialized, baseUrl), baseUrl);
151
155
  if (rewritten !== serialized) return parse(rewritten);
@@ -1 +1 @@
1
- {"version":3,"file":"base.js","names":[],"sources":["../../src/transformers/base.ts"],"sourcesContent":["import postcss from 'postcss'\nimport safeParser from 'postcss-safe-parser'\nimport valueParser from 'postcss-value-parser'\nimport { walk, serialize, parse } from '../utils/ast/index.ts'\nimport { isAbsoluteUrl, defaultTags, processSrcset } from '../utils/url.ts'\nimport type { ChildNode, Element } from 'domhandler'\n\n/**\n * Options for the `base` transformer.\n */\nexport interface BaseUrlOptions {\n /** Base URL to prepend to relative links. */\n url: string\n /**\n * Tag/attribute scope for prepending. Omit to use the built-in defaults\n * (`a[href]`, `img[src]`, `link[href]`, etc.).\n *\n * - Array of tag names — restrict the built-in defaults to these tags.\n * - Object — explicit per-tag attribute map. Each attribute value is\n * `true` (use the base url) or a string (use that string as the url\n * for this attribute only).\n */\n tags?: string[] | Record<string, Record<string, string | boolean>>\n /**\n * Custom attributes to rewrite globally, regardless of tag. Each key\n * is the attribute name; the value is the URL to prepend.\n */\n attributes?: Record<string, string>\n /**\n * Rewrite `url()` references inside `<style>` tag contents.\n *\n * @default true\n */\n styleTag?: boolean\n /**\n * Rewrite `url()` references inside inline `style` attributes.\n *\n * @default true\n */\n inlineCss?: boolean\n}\n\nconst sourceAttributes = ['src', 'href', 'srcset', 'poster', 'background', 'data']\n\n/**\n * Convert the shared `defaultTags` (tag → string[]) into the richer format\n * the transformer needs (tag → Record<attr, true>).\n */\nconst defaultTagConfig: Record<string, Record<string, string | boolean>> = Object.fromEntries(\n Object.entries(defaultTags).map(([tag, attrs]) => [\n tag,\n Object.fromEntries(attrs.map(attr => [attr, true])),\n ]),\n)\n\nconst postcssBaseUrl: postcss.PluginCreator<{ url: string }> = (opts) => {\n return {\n postcssPlugin: 'postcss-base-url',\n Declaration(decl) {\n if (!decl.value.includes('url(')) return\n\n const parsed = valueParser(decl.value)\n let changed = false\n\n parsed.walk(node => {\n if (node.type !== 'function' || node.value !== 'url') return\n\n const urlNode = node.nodes[0]\n if (!urlNode) return\n\n if (isAbsoluteUrl(urlNode.value)) return\n\n urlNode.value = opts!.url + urlNode.value\n changed = true\n })\n\n if (changed) {\n decl.value = parsed.toString()\n }\n }\n }\n}\npostcssBaseUrl.postcss = true\n\nfunction processCss(css: string, url: string): string {\n const { css: result } = postcss([postcssBaseUrl({ url })]).process(css, { parser: safeParser, from: undefined })\n return result\n}\n\nfunction processInlineStyle(style: string, url: string): string {\n try {\n const { css } = postcss([postcssBaseUrl({ url })]).process(`a{${style}}`, { parser: safeParser, from: undefined })\n const match = css.match(/a\\s*\\{\\s*([\\s\\S]*?)\\s*\\}/)\n return match?.[1]?.trim() ?? style\n } catch {\n return style\n }\n}\n\nfunction resolveOptions(input: string | BaseUrlOptions | undefined | null | false): BaseUrlOptions | undefined {\n if (!input) return undefined\n if (typeof input === 'string') {\n return { url: input, styleTag: true, inlineCss: true }\n }\n if (typeof input === 'object' && 'url' in input) {\n return {\n url: input.url ?? '',\n tags: input.tags,\n attributes: input.attributes,\n styleTag: input.styleTag ?? true,\n inlineCss: input.inlineCss ?? true,\n }\n }\n return undefined\n}\n\nfunction getTagConfig(\n tagName: string,\n options: BaseUrlOptions\n): Record<string, string | boolean> | undefined {\n const { tags } = options\n\n if (tags === undefined) {\n return defaultTagConfig[tagName]\n }\n\n if (Array.isArray(tags)) {\n if (!tags.includes(tagName)) return undefined\n return defaultTagConfig[tagName]\n }\n\n if (typeof tags === 'object') {\n return tags[tagName]\n }\n\n return undefined\n}\n\n/**\n * Prepend a base URL to relative `src`/`href`/etc. references throughout\n * the document, including inside `<style>` blocks, inline `style`\n * attributes, MSO conditional comments, and VML tags.\n *\n * @param html HTML string to transform.\n * @param options Either a base URL string, or a {@link BaseUrlOptions} object\n * for finer control.\n * @returns The transformed HTML string.\n *\n * @example\n * import { base } from '@maizzle/framework'\n *\n * // Just a URL — applied with the built-in tag/attribute defaults.\n * const out = base('<img src=\"/a.png\">', 'https://cdn.example.com/')\n *\n * // Restrict to specific tags, opt out of style rewriting:\n * const limited = base(html, {\n * url: 'https://cdn.example.com/',\n * tags: ['img'],\n * styleTag: false,\n * inlineCss: false,\n * })\n */\nexport function base(html: string, options: string | BaseUrlOptions): string {\n return serialize(baseDom(parse(html), options))\n}\n\n/**\n * DOM-form of {@link base} 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 baseDom(dom: ChildNode[], options: string | BaseUrlOptions | undefined | null | false): ChildNode[] {\n const resolved = resolveOptions(options)\n if (!resolved || !resolved.url) return dom\n\n const { url: baseUrl, styleTag = true, inlineCss = true, attributes = {} } = resolved\n\n walk(dom, (node) => {\n const el = node as Element\n if (!el.name) return\n\n // Process <style> tag content with PostCSS\n if (el.name === 'style' && styleTag && el.children) {\n for (const child of el.children) {\n if (child.type === 'text') {\n const textNode = child as unknown as { data: string }\n const processed = processCss(textNode.data, baseUrl)\n if (processed !== textNode.data) {\n textNode.data = processed\n }\n }\n }\n return\n }\n\n if (!el.attribs) return\n\n // Process tag-specific attributes (respects tags filter)\n const tagConfig = getTagConfig(el.name, resolved)\n\n if (tagConfig || resolved.tags === undefined) {\n for (const [attr, value] of Object.entries(el.attribs)) {\n if (!value) continue\n\n const attrConfig = tagConfig?.[attr]\n if (!attrConfig && attr !== 'style') continue\n\n if (attr === 'srcset' && (attrConfig === true || typeof attrConfig === 'string')) {\n const newSrcset = processSrcset(value, typeof attrConfig === 'string' ? attrConfig : baseUrl)\n if (newSrcset !== value) {\n el.attribs.srcset = newSrcset\n }\n } else if (attr === 'style' && inlineCss && value.includes('url(')) {\n const newStyle = processInlineStyle(value, baseUrl)\n if (newStyle !== value) {\n el.attribs.style = newStyle\n }\n } else if (attrConfig === true && !isAbsoluteUrl(value)) {\n el.attribs[attr] = baseUrl + value\n } else if (typeof attrConfig === 'string' && !isAbsoluteUrl(value)) {\n el.attribs[attr] = attrConfig + value\n }\n }\n }\n\n // Process custom attributes (not affected by tags filter)\n for (const [attr, url] of Object.entries(attributes)) {\n if (el.attribs[attr] && !isAbsoluteUrl(el.attribs[attr])) {\n el.attribs[attr] = url + el.attribs[attr]\n }\n }\n })\n\n // VML and MSO comment rewrites require operating on serialized HTML\n // (HTML comments are not represented as traversable DOM nodes)\n const serialized = serialize(dom)\n const rewritten = rewriteMsoComments(rewriteVMLs(serialized, baseUrl), baseUrl)\n\n // Only re-parse if the regex passes actually changed anything\n if (rewritten !== serialized) {\n return parse(rewritten)\n }\n\n return dom\n}\n\nfunction rewriteVMLs(html: string, url: string): string {\n html = html.replace(/<v:image[^>]+src=\"?([^\"\\s]+)\"/gi, (match, src) => {\n if (isAbsoluteUrl(src)) return match\n return match.replace(src, url + src)\n })\n\n html = html.replace(/<v:fill[^>]+src=\"?([^\"\\s]+)\"/gi, (match, src) => {\n if (isAbsoluteUrl(src)) return match\n return match.replace(src, url + src)\n })\n\n return html\n}\n\nfunction rewriteMsoComments(html: string, url: string): string {\n return html.replace(/<!--\\[if [^\\]]+\\]>[\\s\\S]*?<!\\[endif\\]-->/g, (msoBlock) => {\n let result = msoBlock\n\n for (const attr of sourceAttributes) {\n const attrRegex = new RegExp(`\\\\b${attr}=\"([^\"]+)\"`, 'gi')\n result = result.replace(attrRegex, (match, value) => {\n if (isAbsoluteUrl(value)) return match\n\n if (attr === 'srcset') {\n return `srcset=\"${processSrcset(value, url)}\"`\n }\n\n return `${attr}=\"${url}${value}\"`\n })\n }\n\n // Use PostCSS for style attribute url() rewriting inside MSO comments\n result = result.replace(/style=\"([^\"]+)\"/gi, (match, style) => {\n if (!style.includes('url(')) return match\n const processed = processInlineStyle(style, url)\n return `style=\"${processed}\"`\n })\n\n return result\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"base.js","names":[],"sources":["../../src/transformers/base.ts"],"sourcesContent":["import postcss from 'postcss'\nimport safeParser from 'postcss-safe-parser'\nimport valueParser from 'postcss-value-parser'\nimport { walk, serialize, parse } from '../utils/ast/index.ts'\nimport { isAbsoluteUrl, defaultTags, processSrcset } from '../utils/url.ts'\nimport type { ChildNode, Element } from 'domhandler'\n\n/**\n * Options for the `base` transformer.\n */\nexport interface BaseUrlOptions {\n /** Base URL to prepend to relative links. */\n url: string\n /**\n * Tag/attribute scope for prepending. Omit to use the built-in defaults\n * (`a[href]`, `img[src]`, `link[href]`, etc.).\n *\n * - Array of tag names — restrict the built-in defaults to these tags.\n * - Object — explicit per-tag attribute map. Each attribute value is\n * `true` (use the base url) or a string (use that string as the url\n * for this attribute only).\n */\n tags?: string[] | Record<string, Record<string, string | boolean>>\n /**\n * Custom attributes to rewrite globally, regardless of tag. Each key\n * is the attribute name; the value is the URL to prepend.\n */\n attributes?: Record<string, string>\n /**\n * Rewrite `url()` references inside `<style>` tag contents.\n *\n * @default true\n */\n styleTag?: boolean\n /**\n * Rewrite `url()` references inside inline `style` attributes.\n *\n * @default true\n */\n inlineCss?: boolean\n}\n\nconst sourceAttributes = ['src', 'href', 'srcset', 'poster', 'background', 'data']\n\n/**\n * Convert the shared `defaultTags` (tag → string[]) into the richer format\n * the transformer needs (tag → Record<attr, true>).\n */\nconst defaultTagConfig: Record<string, Record<string, string | boolean>> = Object.fromEntries(\n Object.entries(defaultTags).map(([tag, attrs]) => [\n tag,\n Object.fromEntries(attrs.map(attr => [attr, true])),\n ]),\n)\n\nconst postcssBaseUrl: postcss.PluginCreator<{ url: string }> = (opts) => {\n return {\n postcssPlugin: 'postcss-base-url',\n Declaration(decl) {\n if (!decl.value.includes('url(')) return\n\n const parsed = valueParser(decl.value)\n let changed = false\n\n parsed.walk(node => {\n if (node.type !== 'function' || node.value !== 'url') return\n\n const urlNode = node.nodes[0]\n if (!urlNode) return\n\n if (isAbsoluteUrl(urlNode.value)) return\n\n urlNode.value = opts!.url + urlNode.value\n changed = true\n })\n\n if (changed) {\n decl.value = parsed.toString()\n }\n }\n }\n}\npostcssBaseUrl.postcss = true\n\nfunction processCss(css: string, url: string): string {\n const { css: result } = postcss([postcssBaseUrl({ url })]).process(css, { parser: safeParser, from: undefined })\n return result\n}\n\nfunction processInlineStyle(style: string, url: string): string {\n try {\n const { css } = postcss([postcssBaseUrl({ url })]).process(`a{${style}}`, { parser: safeParser, from: undefined })\n const match = css.match(/a\\s*\\{\\s*([\\s\\S]*?)\\s*\\}/)\n return match?.[1]?.trim() ?? style\n } catch {\n return style\n }\n}\n\nfunction resolveOptions(input: string | BaseUrlOptions | undefined | null | false): BaseUrlOptions | undefined {\n if (!input) return undefined\n if (typeof input === 'string') {\n return { url: input, styleTag: true, inlineCss: true }\n }\n if (typeof input === 'object' && 'url' in input) {\n return {\n url: input.url ?? '',\n tags: input.tags,\n attributes: input.attributes,\n styleTag: input.styleTag ?? true,\n inlineCss: input.inlineCss ?? true,\n }\n }\n return undefined\n}\n\nfunction getTagConfig(\n tagName: string,\n options: BaseUrlOptions\n): Record<string, string | boolean> | undefined {\n const { tags } = options\n\n if (tags === undefined) {\n return defaultTagConfig[tagName]\n }\n\n if (Array.isArray(tags)) {\n if (!tags.includes(tagName)) return undefined\n return defaultTagConfig[tagName]\n }\n\n if (typeof tags === 'object') {\n return tags[tagName]\n }\n\n return undefined\n}\n\n/**\n * Prepend a base URL to relative `src`/`href`/etc. references throughout\n * the document, including inside `<style>` blocks, inline `style`\n * attributes, MSO conditional comments, and VML tags.\n *\n * @param html HTML string to transform.\n * @param options Either a base URL string, or a {@link BaseUrlOptions} object\n * for finer control.\n * @returns The transformed HTML string.\n *\n * @example\n * import { base } from '@maizzle/framework'\n *\n * // Just a URL — applied with the built-in tag/attribute defaults.\n * const out = base('<img src=\"/a.png\">', 'https://cdn.example.com/')\n *\n * // Restrict to specific tags, opt out of style rewriting:\n * const limited = base(html, {\n * url: 'https://cdn.example.com/',\n * tags: ['img'],\n * styleTag: false,\n * inlineCss: false,\n * })\n */\nexport function base(html: string, options: string | BaseUrlOptions): string {\n return serialize(baseDom(parse(html), options))\n}\n\n/**\n * DOM-form of {@link base} 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 baseDom(dom: ChildNode[], options: string | BaseUrlOptions | undefined | null | false): ChildNode[] {\n const resolved = resolveOptions(options)\n if (!resolved || !resolved.url) return dom\n\n const { url: baseUrl, styleTag = true, inlineCss = true, attributes = {} } = resolved\n\n walk(dom, (node) => {\n const el = node as Element\n if (!el.name) return\n\n // Process <style> tag content with PostCSS\n if (el.name === 'style' && styleTag && el.children) {\n for (const child of el.children) {\n if (child.type === 'text') {\n const textNode = child as unknown as { data: string }\n const processed = processCss(textNode.data, baseUrl)\n if (processed !== textNode.data) {\n textNode.data = processed\n }\n }\n }\n return\n }\n\n if (!el.attribs) return\n\n // Process tag-specific attributes (respects tags filter)\n const tagConfig = getTagConfig(el.name, resolved)\n\n if (tagConfig || resolved.tags === undefined) {\n for (const [attr, value] of Object.entries(el.attribs)) {\n if (!value) continue\n\n const attrConfig = tagConfig?.[attr]\n if (!attrConfig && attr !== 'style') continue\n\n if (attr === 'srcset' && (attrConfig === true || typeof attrConfig === 'string')) {\n const newSrcset = processSrcset(value, typeof attrConfig === 'string' ? attrConfig : baseUrl)\n if (newSrcset !== value) {\n el.attribs.srcset = newSrcset\n }\n } else if (attr === 'style' && inlineCss && value.includes('url(')) {\n const newStyle = processInlineStyle(value, baseUrl)\n if (newStyle !== value) {\n el.attribs.style = newStyle\n }\n } else if (attrConfig === true && !isAbsoluteUrl(value)) {\n el.attribs[attr] = baseUrl + value\n } else if (typeof attrConfig === 'string' && !isAbsoluteUrl(value)) {\n el.attribs[attr] = attrConfig + value\n }\n }\n }\n\n // Process custom attributes (not affected by tags filter)\n for (const [attr, url] of Object.entries(attributes)) {\n if (el.attribs[attr] && !isAbsoluteUrl(el.attribs[attr])) {\n el.attribs[attr] = url + el.attribs[attr]\n }\n }\n })\n\n /**\n * VML and MSO comment rewrites require operating on serialized HTML\n * (HTML comments are not represented as traversable DOM nodes).\n */\n const serialized = serialize(dom)\n const rewritten = rewriteMsoComments(rewriteVMLs(serialized, baseUrl), baseUrl)\n\n // Only re-parse if the regex passes actually changed anything\n if (rewritten !== serialized) {\n return parse(rewritten)\n }\n\n return dom\n}\n\nfunction rewriteVMLs(html: string, url: string): string {\n html = html.replace(/<v:image[^>]+src=\"?([^\"\\s]+)\"/gi, (match, src) => {\n if (isAbsoluteUrl(src)) return match\n return match.replace(src, url + src)\n })\n\n html = html.replace(/<v:fill[^>]+src=\"?([^\"\\s]+)\"/gi, (match, src) => {\n if (isAbsoluteUrl(src)) return match\n return match.replace(src, url + src)\n })\n\n return html\n}\n\nfunction rewriteMsoComments(html: string, url: string): string {\n return html.replace(/<!--\\[if [^\\]]+\\]>[\\s\\S]*?<!\\[endif\\]-->/g, (msoBlock) => {\n let result = msoBlock\n\n for (const attr of sourceAttributes) {\n const attrRegex = new RegExp(`\\\\b${attr}=\"([^\"]+)\"`, 'gi')\n result = result.replace(attrRegex, (match, value) => {\n if (isAbsoluteUrl(value)) return match\n\n if (attr === 'srcset') {\n return `srcset=\"${processSrcset(value, url)}\"`\n }\n\n return `${attr}=\"${url}${value}\"`\n })\n }\n\n // Use PostCSS for style attribute url() rewriting inside MSO comments\n result = result.replace(/style=\"([^\"]+)\"/gi, (match, style) => {\n if (!style.includes('url(')) return match\n const processed = processInlineStyle(style, url)\n return `style=\"${processed}\"`\n })\n\n return result\n })\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"columnWidth.d.ts","names":[],"sources":["../../src/transformers/columnWidth.ts"],"mappings":";;;;;AAyKA;;;;;;;;;;;;;;;;;;;;;;iBAAgB,WAAA,CAAY,GAAA,EAAK,SAAA,KAAc,SAAA"}
1
+ {"version":3,"file":"columnWidth.d.ts","names":[],"sources":["../../src/transformers/columnWidth.ts"],"mappings":";;;;;AAyKA;;;;;;;;AAAwD;;;;;;;;;;;;;;iBAAxC,WAAA,CAAY,GAAA,EAAK,SAAA,KAAc,SAAS"}