@maizzle/framework 6.0.0-rc.17 → 6.0.0-rc.19

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 (349) hide show
  1. package/bin/maizzle.mjs +1 -1
  2. package/dist/build.d.ts +6 -5
  3. package/dist/build.d.ts.map +1 -1
  4. package/dist/{build.mjs → build.js} +23 -15
  5. package/dist/build.js.map +1 -0
  6. package/dist/components/Body.vue +10 -0
  7. package/dist/components/Button.vue +86 -49
  8. package/dist/components/Column.vue +10 -0
  9. package/dist/components/Container.vue +35 -7
  10. package/dist/components/Hr.vue +33 -0
  11. package/dist/components/Html.vue +29 -1
  12. package/dist/components/Layout.vue +27 -12
  13. package/dist/components/MarkdownLayout.vue +39 -0
  14. package/dist/components/NotPlaintext.vue +14 -0
  15. package/dist/components/{Vml.vue → OutlookBg.vue} +1 -1
  16. package/dist/components/Overlap.vue +10 -0
  17. package/dist/components/Plaintext.vue +14 -0
  18. package/dist/components/Preheader.vue +3 -8
  19. package/dist/components/QrCode.vue +157 -0
  20. package/dist/components/Row.vue +10 -0
  21. package/dist/components/Section.vue +10 -0
  22. package/dist/components/Spacer.vue +28 -27
  23. package/dist/components/{utils.mjs → utils.js} +2 -2
  24. package/dist/components/utils.js.map +1 -0
  25. package/dist/composables/{defineConfig.mjs → defineConfig.js} +4 -5
  26. package/dist/composables/defineConfig.js.map +1 -0
  27. package/dist/composables/{renderContext.mjs → renderContext.js} +2 -2
  28. package/dist/composables/renderContext.js.map +1 -0
  29. package/dist/composables/useBaseUrl.d.ts +19 -0
  30. package/dist/composables/useBaseUrl.d.ts.map +1 -0
  31. package/dist/composables/useBaseUrl.js +26 -0
  32. package/dist/composables/useBaseUrl.js.map +1 -0
  33. package/dist/composables/{useConfig.mjs → useConfig.js} +2 -3
  34. package/dist/composables/useConfig.js.map +1 -0
  35. package/dist/composables/{useDoctype.mjs → useDoctype.js} +3 -4
  36. package/dist/composables/useDoctype.js.map +1 -0
  37. package/dist/composables/{useEvent.mjs → useEvent.js} +3 -4
  38. package/dist/composables/useEvent.js.map +1 -0
  39. package/dist/composables/{useFont.mjs → useFont.js} +3 -4
  40. package/dist/composables/useFont.js.map +1 -0
  41. package/dist/composables/{useOutlookFallback.mjs → useOutlookFallback.js} +2 -3
  42. package/dist/composables/useOutlookFallback.js.map +1 -0
  43. package/dist/composables/usePlaintext.d.ts +2 -0
  44. package/dist/composables/usePlaintext.d.ts.map +1 -1
  45. package/dist/composables/{usePlaintext.mjs → usePlaintext.js} +4 -4
  46. package/dist/composables/usePlaintext.js.map +1 -0
  47. package/dist/composables/{usePreheader.mjs → usePreheader.js} +3 -4
  48. package/dist/composables/usePreheader.js.map +1 -0
  49. package/dist/composables/useTransformers.d.ts +34 -0
  50. package/dist/composables/useTransformers.d.ts.map +1 -0
  51. package/dist/composables/useTransformers.js +48 -0
  52. package/dist/composables/useTransformers.js.map +1 -0
  53. package/dist/composables/useUrlQuery.d.ts +19 -0
  54. package/dist/composables/useUrlQuery.d.ts.map +1 -0
  55. package/dist/composables/useUrlQuery.js +26 -0
  56. package/dist/composables/useUrlQuery.js.map +1 -0
  57. package/dist/config/{defaults.mjs → defaults.js} +9 -3
  58. package/dist/config/defaults.js.map +1 -0
  59. package/dist/config/{index.mjs → index.js} +4 -5
  60. package/dist/config/index.js.map +1 -0
  61. package/dist/events/index.d.ts +8 -2
  62. package/dist/events/index.d.ts.map +1 -1
  63. package/dist/events/{index.mjs → index.js} +21 -5
  64. package/dist/events/index.js.map +1 -0
  65. package/dist/index.d.ts +12 -9
  66. package/dist/index.js +36 -0
  67. package/dist/{plaintext.mjs → plaintext.js} +4 -5
  68. package/dist/plaintext.js.map +1 -0
  69. package/dist/{plugin.mjs → plugin.js} +6 -7
  70. package/dist/plugin.js.map +1 -0
  71. package/dist/plugins/postcss/{mergeMediaQueries.mjs → mergeMediaQueries.js} +2 -3
  72. package/dist/plugins/postcss/mergeMediaQueries.js.map +1 -0
  73. package/dist/plugins/postcss/{pruneVars.mjs → pruneVars.js} +2 -2
  74. package/dist/plugins/postcss/pruneVars.js.map +1 -0
  75. package/dist/plugins/postcss/{quoteFontFamilies.mjs → quoteFontFamilies.js} +2 -2
  76. package/dist/plugins/postcss/quoteFontFamilies.js.map +1 -0
  77. package/dist/plugins/postcss/{removeDeclarations.mjs → removeDeclarations.js} +2 -2
  78. package/dist/plugins/postcss/removeDeclarations.js.map +1 -0
  79. package/dist/plugins/postcss/{resolveMaizzleImports.mjs → resolveMaizzleImports.js} +2 -3
  80. package/dist/plugins/postcss/resolveMaizzleImports.js.map +1 -0
  81. package/dist/plugins/postcss/{resolveProps.mjs → resolveProps.js} +2 -2
  82. package/dist/plugins/postcss/resolveProps.js.map +1 -0
  83. package/dist/plugins/postcss/{tailwindCleanup.mjs → tailwindCleanup.js} +2 -2
  84. package/dist/plugins/postcss/tailwindCleanup.js.map +1 -0
  85. package/dist/{prepare.mjs → prepare.js} +5 -6
  86. package/dist/prepare.js.map +1 -0
  87. package/dist/render/active.d.ts +8 -0
  88. package/dist/render/active.d.ts.map +1 -0
  89. package/dist/render/active.js +12 -0
  90. package/dist/render/active.js.map +1 -0
  91. package/dist/render/createRenderer.d.ts.map +1 -1
  92. package/dist/render/{createRenderer.mjs → createRenderer.js} +24 -19
  93. package/dist/render/createRenderer.js.map +1 -0
  94. package/dist/render/index.d.ts.map +1 -1
  95. package/dist/render/{index.mjs → index.js} +18 -11
  96. package/dist/render/index.js.map +1 -0
  97. package/dist/render/{injectFonts.mjs → injectFonts.js} +3 -4
  98. package/dist/render/injectFonts.js.map +1 -0
  99. package/dist/render/plugins/{codeBlockExtract.mjs → codeBlockExtract.js} +2 -2
  100. package/dist/render/plugins/codeBlockExtract.js.map +1 -0
  101. package/dist/render/plugins/{markdownExtract.mjs → markdownExtract.js} +2 -3
  102. package/dist/render/plugins/markdownExtract.js.map +1 -0
  103. package/dist/render/plugins/{rawExtract.mjs → rawExtract.js} +2 -2
  104. package/dist/render/plugins/rawExtract.js.map +1 -0
  105. package/dist/render/plugins/{rowSourceLocation.mjs → rowSourceLocation.js} +2 -2
  106. package/dist/render/plugins/rowSourceLocation.js.map +1 -0
  107. package/dist/serve.d.ts +2 -0
  108. package/dist/serve.d.ts.map +1 -1
  109. package/dist/{serve.mjs → serve.js} +20 -15
  110. package/dist/serve.js.map +1 -0
  111. package/dist/server/{compatibility.mjs → compatibility.js} +5 -6
  112. package/dist/server/compatibility.js.map +1 -0
  113. package/dist/server/{email.mjs → email.js} +2 -3
  114. package/dist/server/email.js.map +1 -0
  115. package/dist/server/{linter.mjs → linter.js} +3 -4
  116. package/dist/server/linter.js.map +1 -0
  117. package/dist/server/{sfc-utils.mjs → sfc-utils.js} +2 -3
  118. package/dist/server/sfc-utils.js.map +1 -0
  119. package/dist/server/ui/App.vue +18 -0
  120. package/dist/server/ui/components/ui/command/Command.vue +4 -1
  121. package/dist/tests/render/_helpers.d.ts +6 -0
  122. package/dist/tests/render/_helpers.d.ts.map +1 -0
  123. package/dist/tests/render/_helpers.js +16 -0
  124. package/dist/tests/render/_helpers.js.map +1 -0
  125. package/dist/transformers/{addAttributes.mjs → addAttributes.js} +6 -7
  126. package/dist/transformers/addAttributes.js.map +1 -0
  127. package/dist/transformers/attributeToStyle.d.ts +27 -14
  128. package/dist/transformers/attributeToStyle.d.ts.map +1 -1
  129. package/dist/transformers/attributeToStyle.js +94 -0
  130. package/dist/transformers/attributeToStyle.js.map +1 -0
  131. package/dist/transformers/base.d.ts +66 -3
  132. package/dist/transformers/base.d.ts.map +1 -1
  133. package/dist/transformers/{base.mjs → base.js} +56 -30
  134. package/dist/transformers/base.js.map +1 -0
  135. package/dist/transformers/{columnWidth.mjs → columnWidth.js} +4 -5
  136. package/dist/transformers/columnWidth.js.map +1 -0
  137. package/dist/transformers/entities.d.ts +31 -2
  138. package/dist/transformers/entities.d.ts.map +1 -1
  139. package/dist/transformers/entities.js +73 -0
  140. package/dist/transformers/entities.js.map +1 -0
  141. package/dist/transformers/filters/{defaults.mjs → defaults.js} +2 -2
  142. package/dist/transformers/filters/defaults.js.map +1 -0
  143. package/dist/transformers/filters/index.d.ts +31 -10
  144. package/dist/transformers/filters/index.d.ts.map +1 -1
  145. package/dist/transformers/filters/index.js +89 -0
  146. package/dist/transformers/filters/index.js.map +1 -0
  147. package/dist/transformers/format.d.ts +14 -7
  148. package/dist/transformers/format.d.ts.map +1 -1
  149. package/dist/transformers/format.js +30 -0
  150. package/dist/transformers/format.js.map +1 -0
  151. package/dist/transformers/index.js +133 -0
  152. package/dist/transformers/index.js.map +1 -0
  153. package/dist/transformers/inlineCss.d.ts +84 -0
  154. package/dist/transformers/inlineCss.d.ts.map +1 -0
  155. package/dist/transformers/{inlineCSS.mjs → inlineCss.js} +28 -18
  156. package/dist/transformers/inlineCss.js.map +1 -0
  157. package/dist/transformers/inlineLink.d.ts +26 -5
  158. package/dist/transformers/inlineLink.d.ts.map +1 -1
  159. package/dist/transformers/{inlineLink.mjs → inlineLink.js} +34 -10
  160. package/dist/transformers/inlineLink.js.map +1 -0
  161. package/dist/transformers/minify.d.ts +13 -9
  162. package/dist/transformers/minify.d.ts.map +1 -1
  163. package/dist/transformers/minify.js +25 -0
  164. package/dist/transformers/minify.js.map +1 -0
  165. package/dist/transformers/msoPlaceholders.d.ts +28 -0
  166. package/dist/transformers/msoPlaceholders.d.ts.map +1 -0
  167. package/dist/transformers/msoPlaceholders.js +88 -0
  168. package/dist/transformers/msoPlaceholders.js.map +1 -0
  169. package/dist/transformers/purgeCss.d.ts +43 -0
  170. package/dist/transformers/purgeCss.d.ts.map +1 -0
  171. package/dist/transformers/{purgeCSS.mjs → purgeCss.js} +36 -29
  172. package/dist/transformers/purgeCss.js.map +1 -0
  173. package/dist/transformers/removeAttributes.d.ts +43 -20
  174. package/dist/transformers/removeAttributes.d.ts.map +1 -1
  175. package/dist/transformers/removeAttributes.js +70 -0
  176. package/dist/transformers/removeAttributes.js.map +1 -0
  177. package/dist/transformers/{replaceStrings.mjs → replaceStrings.js} +2 -2
  178. package/dist/transformers/replaceStrings.js.map +1 -0
  179. package/dist/transformers/{safeClassNames.mjs → safeClassNames.js} +4 -5
  180. package/dist/transformers/safeClassNames.js.map +1 -0
  181. package/dist/transformers/shorthandCss.d.ts +47 -0
  182. package/dist/transformers/shorthandCss.d.ts.map +1 -0
  183. package/dist/transformers/shorthandCss.js +61 -0
  184. package/dist/transformers/shorthandCss.js.map +1 -0
  185. package/dist/transformers/sixHex.d.ts +16 -7
  186. package/dist/transformers/sixHex.d.ts.map +1 -1
  187. package/dist/transformers/sixHex.js +42 -0
  188. package/dist/transformers/sixHex.js.map +1 -0
  189. package/dist/transformers/{tailwindComponent.mjs → tailwindComponent.js} +5 -6
  190. package/dist/transformers/tailwindComponent.js.map +1 -0
  191. package/dist/transformers/{tailwindcss.mjs → tailwindcss.js} +6 -7
  192. package/dist/transformers/tailwindcss.js.map +1 -0
  193. package/dist/transformers/urlQuery.d.ts +26 -14
  194. package/dist/transformers/urlQuery.d.ts.map +1 -1
  195. package/dist/transformers/urlQuery.js +77 -0
  196. package/dist/transformers/urlQuery.js.map +1 -0
  197. package/dist/types/config.d.ts +108 -15
  198. package/dist/types/config.d.ts.map +1 -1
  199. package/dist/types/config.js +1 -0
  200. package/dist/types/index.d.ts +2 -2
  201. package/dist/types/index.js +1 -0
  202. package/dist/utils/ast/index.js +4 -0
  203. package/dist/utils/ast/{parser.mjs → parser.js} +2 -3
  204. package/dist/utils/ast/parser.js.map +1 -0
  205. package/dist/utils/ast/{serializer.mjs → serializer.js} +3 -4
  206. package/dist/utils/ast/serializer.js.map +1 -0
  207. package/dist/utils/ast/{walker.mjs → walker.js} +2 -2
  208. package/dist/utils/ast/walker.js.map +1 -0
  209. package/dist/utils/{compileTailwindCss.mjs → compileTailwindCss.js} +8 -9
  210. package/dist/utils/compileTailwindCss.js.map +1 -0
  211. package/dist/utils/{decodeStyleEntities.mjs → decodeStyleEntities.js} +2 -2
  212. package/dist/utils/decodeStyleEntities.js.map +1 -0
  213. package/dist/utils/{detect.mjs → detect.js} +2 -3
  214. package/dist/utils/detect.js.map +1 -0
  215. package/dist/utils/output-markers.d.ts +29 -0
  216. package/dist/utils/output-markers.d.ts.map +1 -0
  217. package/dist/utils/output-markers.js +68 -0
  218. package/dist/utils/output-markers.js.map +1 -0
  219. package/dist/utils/{url.mjs → url.js} +2 -3
  220. package/dist/utils/url.js.map +1 -0
  221. package/node_modules/@clack/core/CHANGELOG.md +8 -0
  222. package/node_modules/@clack/core/dist/index.d.mts +18 -4
  223. package/node_modules/@clack/core/dist/index.mjs +16 -10
  224. package/node_modules/@clack/core/dist/index.mjs.map +1 -1
  225. package/node_modules/@clack/core/package.json +5 -2
  226. package/node_modules/@clack/prompts/CHANGELOG.md +15 -0
  227. package/node_modules/@clack/prompts/README.md +107 -2
  228. package/node_modules/@clack/prompts/dist/index.d.mts +16 -11
  229. package/node_modules/@clack/prompts/dist/index.mjs +114 -107
  230. package/node_modules/@clack/prompts/dist/index.mjs.map +1 -1
  231. package/node_modules/@clack/prompts/package.json +7 -4
  232. package/node_modules/fast-string-truncated-width/dist/index.js +36 -96
  233. package/node_modules/fast-string-truncated-width/dist/types.d.ts +0 -3
  234. package/node_modules/fast-string-truncated-width/dist/utils.d.ts +3 -3
  235. package/node_modules/fast-string-truncated-width/dist/utils.js +14 -9
  236. package/node_modules/fast-string-truncated-width/package.json +1 -1
  237. package/node_modules/fast-string-truncated-width/readme.md +2 -3
  238. package/node_modules/fast-string-width/package.json +2 -2
  239. package/node_modules/fast-string-width/readme.md +0 -3
  240. package/node_modules/fast-wrap-ansi/lib/main.js +4 -1
  241. package/node_modules/fast-wrap-ansi/lib/main.js.map +1 -1
  242. package/node_modules/fast-wrap-ansi/package.json +2 -2
  243. package/node_modules/maizzle/README.md +24 -0
  244. package/node_modules/maizzle/dist/commands/make/component.mjs +1 -1
  245. package/node_modules/maizzle/dist/commands/make/config.mjs +1 -1
  246. package/node_modules/maizzle/dist/commands/make/layout.mjs +3 -3
  247. package/node_modules/maizzle/dist/commands/make/scaffold.mjs +1 -1
  248. package/node_modules/maizzle/dist/commands/make/stubs/Layout.vue +146 -0
  249. package/node_modules/maizzle/dist/commands/make/stubs/component.vue +2 -4
  250. package/node_modules/maizzle/dist/commands/make/stubs/config.ts +1 -5
  251. package/node_modules/maizzle/dist/commands/make/template.mjs +1 -1
  252. package/node_modules/maizzle/dist/commands/new.mjs +29 -24
  253. package/node_modules/maizzle/dist/index.mjs +28 -8
  254. package/node_modules/maizzle/package.json +1 -1
  255. package/node_modules/tinyexec/README.md +1 -1
  256. package/node_modules/tinyexec/dist/main.d.mts +6 -6
  257. package/node_modules/tinyexec/dist/main.mjs +126 -134
  258. package/node_modules/tinyexec/package.json +9 -9
  259. package/package.json +4 -4
  260. package/dist/build.mjs.map +0 -1
  261. package/dist/components/Divider.vue +0 -133
  262. package/dist/components/utils.mjs.map +0 -1
  263. package/dist/composables/defineConfig.mjs.map +0 -1
  264. package/dist/composables/renderContext.mjs.map +0 -1
  265. package/dist/composables/useConfig.mjs.map +0 -1
  266. package/dist/composables/useDoctype.mjs.map +0 -1
  267. package/dist/composables/useEvent.mjs.map +0 -1
  268. package/dist/composables/useFont.mjs.map +0 -1
  269. package/dist/composables/useOutlookFallback.mjs.map +0 -1
  270. package/dist/composables/usePlaintext.mjs.map +0 -1
  271. package/dist/composables/usePreheader.mjs.map +0 -1
  272. package/dist/config/defaults.mjs.map +0 -1
  273. package/dist/config/index.mjs.map +0 -1
  274. package/dist/events/index.mjs.map +0 -1
  275. package/dist/index.mjs +0 -34
  276. package/dist/plaintext.mjs.map +0 -1
  277. package/dist/plugin.mjs.map +0 -1
  278. package/dist/plugins/postcss/mergeMediaQueries.mjs.map +0 -1
  279. package/dist/plugins/postcss/pruneVars.mjs.map +0 -1
  280. package/dist/plugins/postcss/quoteFontFamilies.mjs.map +0 -1
  281. package/dist/plugins/postcss/removeDeclarations.mjs.map +0 -1
  282. package/dist/plugins/postcss/resolveMaizzleImports.mjs.map +0 -1
  283. package/dist/plugins/postcss/resolveProps.mjs.map +0 -1
  284. package/dist/plugins/postcss/tailwindCleanup.mjs.map +0 -1
  285. package/dist/prepare.mjs.map +0 -1
  286. package/dist/render/createRenderer.mjs.map +0 -1
  287. package/dist/render/index.mjs.map +0 -1
  288. package/dist/render/injectFonts.mjs.map +0 -1
  289. package/dist/render/plugins/codeBlockExtract.mjs.map +0 -1
  290. package/dist/render/plugins/markdownExtract.mjs.map +0 -1
  291. package/dist/render/plugins/rawExtract.mjs.map +0 -1
  292. package/dist/render/plugins/rowSourceLocation.mjs.map +0 -1
  293. package/dist/serve.mjs.map +0 -1
  294. package/dist/server/compatibility.mjs.map +0 -1
  295. package/dist/server/email.mjs.map +0 -1
  296. package/dist/server/linter.mjs.map +0 -1
  297. package/dist/server/sfc-utils.mjs.map +0 -1
  298. package/dist/transformers/addAttributes.mjs.map +0 -1
  299. package/dist/transformers/attributeToStyle.mjs +0 -80
  300. package/dist/transformers/attributeToStyle.mjs.map +0 -1
  301. package/dist/transformers/base.mjs.map +0 -1
  302. package/dist/transformers/columnWidth.mjs.map +0 -1
  303. package/dist/transformers/entities.mjs +0 -41
  304. package/dist/transformers/entities.mjs.map +0 -1
  305. package/dist/transformers/filters/defaults.mjs.map +0 -1
  306. package/dist/transformers/filters/index.mjs +0 -67
  307. package/dist/transformers/filters/index.mjs.map +0 -1
  308. package/dist/transformers/format.mjs +0 -26
  309. package/dist/transformers/format.mjs.map +0 -1
  310. package/dist/transformers/index.mjs +0 -87
  311. package/dist/transformers/index.mjs.map +0 -1
  312. package/dist/transformers/inlineCSS.d.ts +0 -17
  313. package/dist/transformers/inlineCSS.d.ts.map +0 -1
  314. package/dist/transformers/inlineCSS.mjs.map +0 -1
  315. package/dist/transformers/inlineLink.mjs.map +0 -1
  316. package/dist/transformers/minify.mjs +0 -24
  317. package/dist/transformers/minify.mjs.map +0 -1
  318. package/dist/transformers/msoWidthFromClass.d.ts +0 -19
  319. package/dist/transformers/msoWidthFromClass.d.ts.map +0 -1
  320. package/dist/transformers/msoWidthFromClass.mjs +0 -61
  321. package/dist/transformers/msoWidthFromClass.mjs.map +0 -1
  322. package/dist/transformers/purgeCSS.d.ts +0 -23
  323. package/dist/transformers/purgeCSS.d.ts.map +0 -1
  324. package/dist/transformers/purgeCSS.mjs.map +0 -1
  325. package/dist/transformers/removeAttributes.mjs +0 -63
  326. package/dist/transformers/removeAttributes.mjs.map +0 -1
  327. package/dist/transformers/replaceStrings.mjs.map +0 -1
  328. package/dist/transformers/safeClassNames.mjs.map +0 -1
  329. package/dist/transformers/shorthandCSS.d.ts +0 -24
  330. package/dist/transformers/shorthandCSS.d.ts.map +0 -1
  331. package/dist/transformers/shorthandCSS.mjs +0 -48
  332. package/dist/transformers/shorthandCSS.mjs.map +0 -1
  333. package/dist/transformers/sixHex.mjs +0 -30
  334. package/dist/transformers/sixHex.mjs.map +0 -1
  335. package/dist/transformers/tailwindComponent.mjs.map +0 -1
  336. package/dist/transformers/tailwindcss.mjs.map +0 -1
  337. package/dist/transformers/urlQuery.mjs +0 -65
  338. package/dist/transformers/urlQuery.mjs.map +0 -1
  339. package/dist/types/config.mjs +0 -1
  340. package/dist/types/index.mjs +0 -1
  341. package/dist/utils/ast/index.mjs +0 -5
  342. package/dist/utils/ast/parser.mjs.map +0 -1
  343. package/dist/utils/ast/serializer.mjs.map +0 -1
  344. package/dist/utils/ast/walker.mjs.map +0 -1
  345. package/dist/utils/compileTailwindCss.mjs.map +0 -1
  346. package/dist/utils/decodeStyleEntities.mjs.map +0 -1
  347. package/dist/utils/detect.mjs.map +0 -1
  348. package/dist/utils/url.mjs.map +0 -1
  349. package/node_modules/maizzle/dist/commands/make/stubs/layout.vue +0 -39
package/bin/maizzle.mjs CHANGED
@@ -5,6 +5,6 @@ import { fileURLToPath } from 'node:url'
5
5
 
6
6
  const jiti = createJiti(fileURLToPath(import.meta.url), { interopDefault: true })
7
7
  const { default: bootstrap } = await jiti.import('maizzle')
8
- const framework = await jiti.import('../dist/index.mjs')
8
+ const framework = await jiti.import('../dist/index.js')
9
9
 
10
10
  await bootstrap(framework)
package/dist/build.d.ts CHANGED
@@ -1,8 +1,5 @@
1
1
  import { MaizzleConfig } from "./types/config.js";
2
2
  //#region src/build.d.ts
3
- interface BuildOptions {
4
- config?: Partial<MaizzleConfig> | string;
5
- }
6
3
  interface BuildResult {
7
4
  files: string[];
8
5
  config: MaizzleConfig;
@@ -12,8 +9,12 @@ interface BuildResult {
12
9
  *
13
10
  * Creates a single Renderer instance, then loops through each template
14
11
  * calling render → transformers → write to disk.
12
+ *
13
+ * Pass a `Partial<MaizzleConfig>` to override config inline, or a string
14
+ * to load config from a specific file path. Omit to load `maizzle.config`
15
+ * from the working directory.
15
16
  */
16
- declare function build(options?: BuildOptions): Promise<BuildResult>;
17
+ declare function build(configInput?: Partial<MaizzleConfig> | string): Promise<BuildResult>;
17
18
  //#endregion
18
- export { BuildOptions, BuildResult, build };
19
+ export { BuildResult, build };
19
20
  //# sourceMappingURL=build.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","names":[],"sources":["../src/build.ts"],"mappings":";;UAWiB,YAAA;EACf,MAAA,GAAS,OAAA,CAAQ,aAAA;AAAA;AAAA,UAGF,WAAA;EACf,KAAA;EACA,MAAA,EAAQ,aAAA;AAAA;;;;;;AAFV;iBAWsB,KAAA,CAAM,OAAA,GAAS,YAAA,GAAoB,OAAA,CAAQ,WAAA"}
1
+ {"version":3,"file":"build.d.ts","names":[],"sources":["../src/build.ts"],"mappings":";;UAaiB,WAAA;EACf,KAAA;EACA,MAAA,EAAQ,aAAA;AAAA;;;;;;;;;AAaV;;iBAAsB,KAAA,CAAM,WAAA,GAAc,OAAA,CAAQ,aAAA,aAA0B,OAAA,CAAQ,WAAA"}
@@ -1,27 +1,32 @@
1
- import { resolveConfig } from "./config/index.mjs";
2
- import { EventManager } from "./events/index.mjs";
3
- import { runTransformers } from "./transformers/index.mjs";
4
- import { createRenderer } from "./render/createRenderer.mjs";
5
- import { createPlaintext } from "./plaintext.mjs";
1
+ import { resolveConfig } from "./config/index.js";
2
+ import { EventManager } from "./events/index.js";
3
+ import { runTransformers } from "./transformers/index.js";
4
+ import { createRenderer } from "./render/createRenderer.js";
5
+ import { createPlaintext } from "./plaintext.js";
6
+ import { stripForHtml, stripForPlaintext } from "./utils/output-markers.js";
6
7
  import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
7
8
  import { basename, dirname, join, relative, resolve } from "node:path";
8
9
  import { glob } from "tinyglobby";
9
10
  import ora from "ora";
10
-
11
+ import defu from "defu";
11
12
  //#region src/build.ts
12
13
  /**
13
14
  * Build all SFC email templates to HTML files.
14
15
  *
15
16
  * Creates a single Renderer instance, then loops through each template
16
17
  * calling render → transformers → write to disk.
18
+ *
19
+ * Pass a `Partial<MaizzleConfig>` to override config inline, or a string
20
+ * to load config from a specific file path. Omit to load `maizzle.config`
21
+ * from the working directory.
17
22
  */
18
- async function build(options = {}) {
23
+ async function build(configInput) {
19
24
  const start = Date.now();
20
25
  const spinner = ora({
21
26
  text: "Building templates...",
22
27
  spinner: "circleHalves"
23
28
  }).start();
24
- const config = await resolveConfig(options.config);
29
+ const config = await resolveConfig(configInput);
25
30
  const events = new EventManager();
26
31
  events.registerConfig(config);
27
32
  await events.fireBeforeCreate({ config });
@@ -57,6 +62,7 @@ async function build(options = {}) {
57
62
  template
58
63
  });
59
64
  const rendered = await renderer.render(absolutePath, config);
65
+ for (const { name, handler } of rendered.sfcEventHandlers) events.on(name, handler);
60
66
  let html = await events.fireAfterRender({
61
67
  config,
62
68
  template,
@@ -71,25 +77,27 @@ async function build(options = {}) {
71
77
  html
72
78
  });
73
79
  html = `${doctype}\n${html}`;
80
+ const htmlOut = stripForHtml(html);
74
81
  const outputFilePath = resolveOutputPath(templatePath, outputPath, outputExtension, contentBase);
75
82
  mkdirSync(dirname(outputFilePath), { recursive: true });
76
- writeFileSync(outputFilePath, html);
83
+ writeFileSync(outputFilePath, htmlOut);
77
84
  outputFiles.push(outputFilePath);
78
85
  const globalPlaintext = templateConfig.plaintext;
79
86
  const sfcPlaintext = rendered.plaintext;
80
87
  if (globalPlaintext || sfcPlaintext) {
81
- const plaintext = createPlaintext(html, typeof globalPlaintext === "object" ? globalPlaintext : {});
82
- const ptExtension = sfcPlaintext?.extension ?? "txt";
88
+ const globalCfg = typeof globalPlaintext === "object" ? globalPlaintext : {};
89
+ const stripOptions = defu(sfcPlaintext?.options, globalCfg.options);
90
+ const plaintext = createPlaintext(stripForPlaintext(html), stripOptions);
91
+ const ptExtension = sfcPlaintext?.extension ?? globalCfg.extension ?? "txt";
83
92
  let ptOutputPath;
84
93
  if (sfcPlaintext?.destination) {
85
94
  const name = basename(templatePath).replace(/\.(vue|md)$/, "");
86
95
  ptOutputPath = join(resolve(sfcPlaintext.destination), `${name}.${ptExtension}`);
87
- } else if (typeof globalPlaintext === "string") ptOutputPath = resolveOutputPath(templatePath, resolve(globalPlaintext), ptExtension, contentBase);
96
+ } else if (globalCfg.destination) ptOutputPath = resolveOutputPath(templatePath, resolve(globalCfg.destination), ptExtension, contentBase);
88
97
  else ptOutputPath = resolveOutputPath(templatePath, outputPath, ptExtension, contentBase);
89
98
  mkdirSync(dirname(ptOutputPath), { recursive: true });
90
99
  writeFileSync(ptOutputPath, plaintext);
91
100
  }
92
- for (const { name, handler } of rendered.sfcEventHandlers) events.on(name, handler);
93
101
  events.clearSfcHandlers();
94
102
  }
95
103
  await copyStatic(config, outputPath);
@@ -138,7 +146,7 @@ async function copyStatic(config, outputPath) {
138
146
  cpSync(file, destPath);
139
147
  }
140
148
  }
141
-
142
149
  //#endregion
143
150
  export { build };
144
- //# sourceMappingURL=build.mjs.map
151
+
152
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build.js","names":[],"sources":["../src/build.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync, cpSync, existsSync, rmSync } from 'node:fs'\nimport { resolve, dirname, basename, relative, join } from 'node:path'\nimport { glob } from 'tinyglobby'\nimport ora from 'ora'\nimport { resolveConfig } from './config/index.ts'\nimport { EventManager } from './events/index.ts'\nimport { runTransformers } from './transformers/index.ts'\nimport { createRenderer } from './render/createRenderer.ts'\nimport { createPlaintext } from './plaintext.ts'\nimport { stripForHtml, stripForPlaintext } from './utils/output-markers.ts'\nimport defu from 'defu'\nimport type { MaizzleConfig } from './types/index.ts'\n\nexport interface BuildResult {\n files: string[]\n config: MaizzleConfig\n}\n\n/**\n * Build all SFC email templates to HTML files.\n *\n * Creates a single Renderer instance, then loops through each template\n * calling render → transformers → write to disk.\n *\n * Pass a `Partial<MaizzleConfig>` to override config inline, or a string\n * to load config from a specific file path. Omit to load `maizzle.config`\n * from the working directory.\n */\nexport async function build(configInput?: Partial<MaizzleConfig> | string): Promise<BuildResult> {\n const start = Date.now()\n const spinner = ora({ text: 'Building templates...', spinner: 'circleHalves' }).start()\n\n const config = await resolveConfig(configInput)\n\n const events = new EventManager()\n events.registerConfig(config)\n await events.fireBeforeCreate({ config })\n\n const outputPath = resolve(config.output?.path ?? 'dist')\n const outputExtension = config.output?.extension ?? 'html'\n\n const contentPatterns = config.content ?? ['emails/**/*.vue']\n const contentBase = computeContentBase(contentPatterns)\n const templateFiles = await glob(contentPatterns)\n\n if (templateFiles.length === 0) {\n spinner.succeed('No templates found')\n return { files: [], config }\n }\n\n // Clear the output directory before writing fresh output\n if (existsSync(outputPath)) {\n rmSync(outputPath, { recursive: true, force: true })\n }\n\n const renderer = await createRenderer({ markdown: config.markdown, root: config.root, componentDirs: [config.components?.source ?? []].flat(), vite: config.vite })\n const outputFiles: string[] = []\n\n try {\n for (const templatePath of templateFiles) {\n const absolutePath = resolve(templatePath)\n let template = readFileSync(absolutePath, 'utf-8')\n\n template = await events.fireBeforeRender({ config, template })\n\n const rendered = await renderer.render(absolutePath, config)\n\n // Register SFC event handlers collected during render so they participate\n // in the post-render events (afterRender / afterTransform). They're cleared\n // at the end of the iteration so they don't leak into the next template.\n for (const { name, handler } of rendered.sfcEventHandlers) {\n events.on(name, handler)\n }\n\n let html = await events.fireAfterRender({ config, template, html: rendered.html })\n\n // Use the per-template merged config (from defineConfig() in the SFC) so that\n // template-level overrides like css.safe: false are respected by transformers.\n const templateConfig = rendered.templateConfig\n\n const doctype = rendered.doctype ?? templateConfig.doctype ?? '<!DOCTYPE html>'\n\n if (templateConfig.useTransformers !== false) {\n html = await runTransformers(html, templateConfig, absolutePath, doctype, rendered.tailwindBlocks)\n }\n\n html = await events.fireAfterTransform({ config, template, html })\n html = `${doctype}\\n${html}`\n\n const htmlOut = stripForHtml(html)\n const outputFilePath = resolveOutputPath(templatePath, outputPath, outputExtension, contentBase)\n mkdirSync(dirname(outputFilePath), { recursive: true })\n writeFileSync(outputFilePath, htmlOut)\n outputFiles.push(outputFilePath)\n\n // Generate plaintext version if configured\n const globalPlaintext = templateConfig.plaintext\n const sfcPlaintext = rendered.plaintext\n\n if (globalPlaintext || sfcPlaintext) {\n const globalCfg = typeof globalPlaintext === 'object' ? globalPlaintext : {}\n const stripOptions = defu(sfcPlaintext?.options, globalCfg.options)\n const plaintext = createPlaintext(stripForPlaintext(html), stripOptions)\n const ptExtension = sfcPlaintext?.extension ?? globalCfg.extension ?? 'txt'\n\n let ptOutputPath: string\n\n if (sfcPlaintext?.destination) {\n const name = basename(templatePath).replace(/\\.(vue|md)$/, '')\n ptOutputPath = join(resolve(sfcPlaintext.destination), `${name}.${ptExtension}`)\n } else if (globalCfg.destination) {\n ptOutputPath = resolveOutputPath(templatePath, resolve(globalCfg.destination), ptExtension, contentBase)\n } else {\n ptOutputPath = resolveOutputPath(templatePath, outputPath, ptExtension, contentBase)\n }\n\n mkdirSync(dirname(ptOutputPath), { recursive: true })\n writeFileSync(ptOutputPath, plaintext)\n }\n\n events.clearSfcHandlers()\n }\n\n await copyStatic(config, outputPath)\n await events.fireAfterBuild({ files: outputFiles, config })\n } finally {\n await renderer.close()\n }\n\n const duration = ((Date.now() - start) / 1000).toFixed(2)\n const count = outputFiles.length\n spinner.stopAndPersist({\n symbol: '✅',\n text: `Built ${count} template${count !== 1 ? 's' : ''} in ${duration}s`,\n })\n\n return { files: outputFiles, config }\n}\n\n/**\n * Extract the static (non-glob) prefix from content patterns.\n *\n * For example, `['/abs/path/emails/**\\/*.vue']` → `'/abs/path/emails'`\n *\n * This is used to strip the content base from template paths\n * so the output preserves only the subdirectory structure.\n */\nfunction computeContentBase(patterns: string[]): string {\n // Use the first non-negated pattern\n const pattern = patterns.find(p => !p.startsWith('!')) ?? patterns[0]\n\n // Split on first glob character (* { ? [) and take the directory part\n const staticPart = pattern.split(/[*{?[]/)[0]\n\n // Ensure we have a clean directory path (not a partial segment)\n return resolve(staticPart.endsWith('/') ? staticPart : dirname(staticPart))\n}\n\nfunction resolveOutputPath(templatePath: string, outputDir: string, extension: string, contentBase: string): string {\n const name = basename(templatePath).replace(/\\.(vue|md)$/, '')\n const absTemplate = resolve(templatePath)\n const rel = relative(contentBase, dirname(absTemplate))\n\n return join(outputDir, rel, `${name}.${extension}`)\n}\n\nasync function copyStatic(config: MaizzleConfig, outputPath: string): Promise<void> {\n const sources = config.static?.source ?? ['public/**/*.*']\n const destination = config.static?.destination ?? 'public'\n\n const files = await glob(sources)\n\n for (const file of files) {\n const destPath = join(outputPath, destination, relative(dirname(sources[0]).replace(/\\*.*$/, ''), file))\n const destDir = dirname(destPath)\n\n if (!existsSync(destDir)) {\n mkdirSync(destDir, { recursive: true })\n }\n\n cpSync(file, destPath)\n }\n}\n"],"mappings":"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"}
@@ -68,6 +68,16 @@ const props = defineProps({
68
68
  type: String,
69
69
  default: undefined
70
70
  },
71
+ /**
72
+ * Toggle Outlook (MSO) and VML fallback markup for this
73
+ * component and all descendants.
74
+ *
75
+ * When `false`, skips MSO ghost tables, VML shapes,
76
+ * `xmlns:v`/`xmlns:o` attributes, and mso-specific CSS
77
+ * in all built-in components.
78
+ *
79
+ * @default true
80
+ */
71
81
  outlookFallback: outlookFallbackProp,
72
82
  })
73
83
 
@@ -1,8 +1,7 @@
1
1
  <script setup lang="ts">
2
- import { computed, useAttrs } from 'vue'
2
+ import { computed, useAttrs, createStaticVNode } from 'vue'
3
3
  import type { PropType } from 'vue'
4
4
  import { twMerge } from 'tailwind-merge'
5
- import Outlook from './Outlook.vue'
6
5
  import { outlookFallbackProp } from './utils.ts'
7
6
  import { useOutlookFallback } from '../composables/useOutlookFallback'
8
7
 
@@ -37,24 +36,6 @@ const props = defineProps({
37
36
  type: String as PropType<'left' | 'center' | 'right' | null>,
38
37
  default: null
39
38
  },
40
- /**
41
- * Background color for `solid` and `outline` variants.
42
- * Also used as the text color for `outline` and `ghost` variants when `color` is not set.
43
- * @default '#4338ca'
44
- */
45
- bgColor: {
46
- type: String,
47
- default: '#4338ca'
48
- },
49
- /**
50
- * Explicit text color. When omitted, `solid` buttons use `#fffffe`
51
- * and all other variants fall back to `bgColor`.
52
- * @default null
53
- */
54
- color: {
55
- type: String,
56
- default: null
57
- },
58
39
  /**
59
40
  * `mso-text-raise` value applied to the inner `<span>` elements.
60
41
  * Controls vertical text alignment inside the button in old Outlook.
@@ -106,6 +87,35 @@ const props = defineProps({
106
87
  type: String,
107
88
  default: ''
108
89
  },
90
+ /**
91
+ * Alt text for the icon image.
92
+ * @default ''
93
+ */
94
+ iconAlt: {
95
+ type: String,
96
+ default: ''
97
+ },
98
+ /**
99
+ * Horizontal padding in old Outlook, applied as `mso-font-width` on the
100
+ * outer spacer `<i>` elements. Accepts a number, a numeric string, or a
101
+ * string with `%`. Bare numbers are treated as percentages. Effective
102
+ * range up to 500%.
103
+ * @default 150
104
+ */
105
+ msoPx: {
106
+ type: [String, Number],
107
+ default: 150
108
+ },
109
+ /**
110
+ * Toggle Outlook (MSO) and VML fallback markup for this
111
+ * component and all descendants.
112
+ *
113
+ * When `false`, skips MSO ghost tables, VML shapes,
114
+ * `xmlns:v`/`xmlns:o` attributes, and mso-specific CSS
115
+ * in all built-in components.
116
+ *
117
+ * @default true
118
+ */
109
119
  outlookFallback: outlookFallbackProp,
110
120
  })
111
121
 
@@ -119,18 +129,9 @@ const alignClass = computed(() => props.align ? ({
119
129
  right: 'text-right',
120
130
  })[props.align] || '' : '')
121
131
 
122
- const textColor = computed(() => {
123
- if (props.color) return props.color
124
-
125
- return props.variant === 'solid' ? '#fffffe' : props.bgColor
126
- })
127
-
128
132
  const styles = computed(() => {
129
133
  if (props.variant === 'link') {
130
- return [
131
- 'text-decoration: none;',
132
- `color: ${textColor.value};`,
133
- ].join('')
134
+ return 'text-decoration: none; color: #4338ca;'
134
135
  }
135
136
 
136
137
  const base = [
@@ -140,18 +141,24 @@ const styles = computed(() => {
140
141
  'font-size: 16px;',
141
142
  'line-height: 1;',
142
143
  'border-radius: 4px;',
143
- `color: ${textColor.value};`,
144
144
  ]
145
145
 
146
146
  if (props.variant === 'outline') {
147
147
  base.push(
148
148
  'background-color: transparent;',
149
- `border: 1px solid ${props.bgColor};`,
149
+ 'border: 1px solid #4338ca;',
150
+ 'color: #4338ca;',
150
151
  )
151
152
  } else if (props.variant === 'ghost') {
152
- base.push('background-color: transparent;')
153
+ base.push(
154
+ 'background-color: transparent;',
155
+ 'color: #4338ca;',
156
+ )
153
157
  } else {
154
- base.push(`background-color: ${props.bgColor};`)
158
+ base.push(
159
+ 'background-color: #4338ca;',
160
+ 'color: #fffffe;',
161
+ )
155
162
  }
156
163
 
157
164
  return base.join('')
@@ -159,38 +166,68 @@ const styles = computed(() => {
159
166
 
160
167
  const isLink = computed(() => props.variant === 'link')
161
168
 
162
- const defaultClasses = computed(() => {
163
- if (props.variant === 'ghost') return 'hover:bg-indigo-50'
164
- return ''
169
+ const variantClasses = computed(() =>
170
+ props.variant === 'ghost' ? 'hover:bg-indigo-50' : '',
171
+ )
172
+
173
+ const mergedClass = computed(() => twMerge(variantClasses.value, attrs.class as string))
174
+
175
+ const textSpanStyle = computed(() =>
176
+ outlookFallback ? `mso-text-raise: ${props.msoPt};` : undefined,
177
+ )
178
+
179
+ const msoPx = computed(() => {
180
+ const v = String(props.msoPx).trim()
181
+ // Bare number → percentage. Anything with a unit passes through.
182
+ return /^\d+(\.\d+)?$/.test(v) ? `${v}%` : v
165
183
  })
166
184
 
167
- const mergedClass = computed(() => twMerge(defaultClasses.value, attrs.class as string))
185
+ /**
186
+ * Outlook spacer `<i>` elements rendered as raw HTML inside MSO conditional
187
+ * comments. JS strings keep `&emsp;` / `&#8203;` from being decoded by
188
+ * Vue's template parser; htmlparser2 then preserves the comment
189
+ * data verbatim because conditional comments are opaque.
190
+ */
191
+ const MsoSpacerLeft = () => createStaticVNode(
192
+ `<!--[if mso]><i style="mso-font-width: ${msoPx.value}; mso-text-raise: ${props.msoPb};" hidden>&emsp;</i><![endif]-->`,
193
+ 1,
194
+ )
195
+
196
+ const MsoSpacerRight = () => createStaticVNode(
197
+ `<!--[if mso]><i style="mso-font-width: ${msoPx.value};" hidden>&emsp;&#8203;</i><![endif]-->`,
198
+ 1,
199
+ )
200
+
201
+ const MsoIconGap = () => createStaticVNode(
202
+ `<!--[if mso]><i style="mso-font-width: 30%;" hidden>&emsp;&#8203;</i><![endif]-->`,
203
+ 1,
204
+ )
168
205
  </script>
169
206
 
170
207
  <template>
171
208
  <div :class="alignClass">
172
209
  <a
173
- v-bind="{ ...$attrs, class: undefined }"
210
+ v-bind="{ ...$attrs, class: undefined, style: undefined }"
174
211
  :href="href"
175
- :style="styles"
212
+ :style="[styles, $attrs.style as any]"
176
213
  :class="mergedClass"
177
214
  >
178
215
  <template v-if="!isLink">
179
- <Outlook v-if="outlookFallback"><i class="mso-font-width-[150%]" :style="`mso-text-raise: ${msoPb};`" hidden>&emsp;</i></Outlook>
216
+ <MsoSpacerLeft v-if="outlookFallback" />
180
217
  <template v-if="icon && iconPosition === 'left'">
181
- <span :style="outlookFallback ? `mso-text-raise: ${msoPt}` : undefined">
182
- <img :src="icon" :width="parsedIconWidth" :class="`align-baseline max-w-full ${iconClass}`" alt="">
218
+ <span :style="textSpanStyle">
219
+ <img :src="icon" :width="parsedIconWidth" :alt="iconAlt" style="vertical-align: baseline; max-width: 100%;" :class="iconClass">
183
220
  </span>
184
- <Outlook v-if="outlookFallback"><i class="mso-font-width-[30%]" hidden>&emsp;&#8203;</i></Outlook>
221
+ <MsoIconGap v-if="outlookFallback" />
185
222
  </template>
186
- <span :class="icon ? (iconPosition === 'right' ? 'mr-2' : 'ml-2') : ''" :style="outlookFallback ? `mso-text-raise: ${msoPt}` : undefined"><slot /></span>
223
+ <span :style="textSpanStyle"><slot /></span>
187
224
  <template v-if="icon && iconPosition === 'right'">
188
- <Outlook v-if="outlookFallback"><i class="mso-font-width-[30%]" hidden>&emsp;&#8203;</i></Outlook>
189
- <span :style="outlookFallback ? `mso-text-raise: ${msoPt}` : undefined">
190
- <img :src="icon" :width="parsedIconWidth" :class="`align-baseline max-w-full ${iconClass}`" alt="">
225
+ <MsoIconGap v-if="outlookFallback" />
226
+ <span :style="textSpanStyle">
227
+ <img :src="icon" :width="parsedIconWidth" :alt="iconAlt" style="vertical-align: baseline; max-width: 100%;" :class="iconClass">
191
228
  </span>
192
229
  </template>
193
- <Outlook v-if="outlookFallback"><i class="mso-font-width-[150%]" hidden>&emsp;&#8203;</i></Outlook>
230
+ <MsoSpacerRight v-if="outlookFallback" />
194
231
  </template>
195
232
  <template v-else>
196
233
  <slot />
@@ -32,6 +32,16 @@ const props = defineProps({
32
32
  type: String,
33
33
  default: undefined
34
34
  },
35
+ /**
36
+ * Toggle Outlook (MSO) and VML fallback markup for this
37
+ * component and all descendants.
38
+ *
39
+ * When `false`, skips MSO ghost tables, VML shapes,
40
+ * `xmlns:v`/`xmlns:o` attributes, and mso-specific CSS
41
+ * in all built-in components.
42
+ *
43
+ * @default true
44
+ */
35
45
  outlookFallback: outlookFallbackProp,
36
46
  })
37
47
 
@@ -16,11 +16,11 @@ const props = defineProps({
16
16
  * Also used as the width source for descendant `Row`/`Column`
17
17
  * components when computing column widths.
18
18
  *
19
- * When not set, the div defaults to `w-150 mx-auto` (600px,
20
- * centered) — overridable via Tailwind classes such as
21
- * `w-[400px]` or `max-w-xl`. The MSO table width is auto-derived
22
- * from the resolved width/max-width after CSS inlining, falling
23
- * back to 600px when unresolvable.
19
+ * When not set, the div defaults to `max-w-150 mx-auto` (max
20
+ * 600px, centered, shrinks below) — overridable via Tailwind
21
+ * classes such as `w-[400px]` or `max-w-xl`. The MSO table
22
+ * width is auto-derived from the resolved width/max-width after
23
+ * CSS inlining, falling back to 600px when unresolvable.
24
24
  */
25
25
  width: {
26
26
  type: [String, Number],
@@ -35,6 +35,29 @@ const props = defineProps({
35
35
  type: [String, Number],
36
36
  default: null
37
37
  },
38
+ /**
39
+ * Inline CSS applied only to the MSO `<td>` element.
40
+ *
41
+ * Use for Outlook-specific styling that shouldn't affect other clients.
42
+ * Appended after any padding propagated from the outer div's
43
+ * inlined style, so msoStyle wins on duplicate properties.
44
+ *
45
+ * @example 'padding: 10px 20px'
46
+ */
47
+ msoStyle: {
48
+ type: String,
49
+ default: undefined
50
+ },
51
+ /**
52
+ * Toggle Outlook (MSO) and VML fallback markup for this
53
+ * component and all descendants.
54
+ *
55
+ * When `false`, skips MSO ghost tables, VML shapes,
56
+ * `xmlns:v`/`xmlns:o` attributes, and mso-specific CSS
57
+ * in all built-in components.
58
+ *
59
+ * @default true
60
+ */
38
61
  outlookFallback: outlookFallbackProp,
39
62
  })
40
63
 
@@ -44,6 +67,7 @@ provide('containerWidth', computed(() => props.width))
44
67
 
45
68
  const useMarker = outlookFallback && props.width == null && props.msoWidth == null
46
69
  const msoId = useMarker ? nextId('c') : null
70
+ const tdId = outlookFallback ? nextId('ct') : null
47
71
 
48
72
  const styles = computed(() => {
49
73
  if (props.width == null) return undefined
@@ -55,7 +79,7 @@ const mergedClass = computed(() => {
55
79
  const userClass = (attrs.class as string) ?? ''
56
80
  const defaultClass = hasWidthUtility(userClass)
57
81
  ? 'm-0 mx-auto'
58
- : 'w-150 m-0 mx-auto'
82
+ : 'max-w-150 m-0 mx-auto'
59
83
  return twMerge(defaultClass, userClass)
60
84
  })
61
85
 
@@ -69,8 +93,10 @@ const colWidthSource = computed(() =>
69
93
  props.width != null ? normalizeToPixels(props.width) : ''
70
94
  )
71
95
 
96
+ const tdMarker = tdId ? `__MAIZZLE_MSOTDSTYLE_${tdId}__` : ''
97
+
72
98
  const MsoBefore = () => createStaticVNode(
73
- `<!--[if mso]><table role="none" cellpadding="0" cellspacing="0" style="width: ${msoWidth.value}" align="center"><tr><td><![endif]-->`,
99
+ `<!--[if mso]><table role="none" cellpadding="0" cellspacing="0" style="width: ${msoWidth.value}" align="center"><tr><td${tdMarker}><![endif]-->`,
74
100
  1
75
101
  )
76
102
 
@@ -88,6 +114,8 @@ const MsoAfter = () => createStaticVNode(
88
114
  :style="styles"
89
115
  :data-maizzle-msow-id="msoId"
90
116
  :data-maizzle-cw="colWidthSource"
117
+ :data-maizzle-mso-td-id="tdId"
118
+ :data-maizzle-mso-style="tdId && props.msoStyle ? props.msoStyle : null"
91
119
  >
92
120
  <slot />
93
121
  </div>
@@ -0,0 +1,33 @@
1
+ <script setup lang="ts">
2
+ import { computed, useAttrs } from 'vue'
3
+ import { twMerge } from 'tailwind-merge'
4
+
5
+ defineOptions({ inheritAttrs: false })
6
+
7
+ const attrs = useAttrs()
8
+
9
+ const HEIGHT_RE = /(?:^|\s)h-([\w./\-[\]%]+)/g
10
+ const LEADING_RE = /(?:^|\s)leading-/
11
+
12
+ const mergedClass = computed(() => {
13
+ const userClass = (attrs.class as string) || ''
14
+ const heights = [...userClass.matchAll(HEIGHT_RE)]
15
+ const userHeight = heights.length ? heights[heights.length - 1][1] : null
16
+ const userHasLeading = LEADING_RE.test(userClass)
17
+
18
+ const defaults = ['my-6', 'bg-slate-300']
19
+ if (!userHeight) defaults.push('h-px')
20
+ if (!userHasLeading && !userHeight) defaults.push('leading-px')
21
+
22
+ const derived = userHeight && !userHasLeading ? `leading-${userHeight}` : ''
23
+ return twMerge(defaults.join(' '), userClass, derived)
24
+ })
25
+ </script>
26
+
27
+ <template>
28
+ <div
29
+ role="separator"
30
+ v-bind="{ ...$attrs, class: undefined }"
31
+ :class="mergedClass"
32
+ >&zwj;</div>
33
+ </template>
@@ -1,8 +1,9 @@
1
1
  <script setup lang="ts">
2
- import { createStaticVNode, provide, useAttrs, useSlots } from 'vue'
2
+ import { createStaticVNode, inject, provide, useAttrs, useSlots } from 'vue'
3
3
  import type { PropType } from 'vue'
4
4
  import { outlookFallbackProp } from './utils.ts'
5
5
  import { useOutlookFallback } from '../composables/useOutlookFallback'
6
+ import { RenderContextKey } from '../composables/renderContext'
6
7
 
7
8
  defineOptions({ inheritAttrs: false })
8
9
 
@@ -68,11 +69,38 @@ const props = defineProps({
68
69
  type: [Boolean, String],
69
70
  default: true
70
71
  },
72
+ /**
73
+ * Toggle Outlook (MSO) and VML fallback markup for this
74
+ * component and all descendants.
75
+ *
76
+ * When `false`, skips MSO ghost tables, VML shapes,
77
+ * `xmlns:v`/`xmlns:o` attributes, and mso-specific CSS
78
+ * in all built-in components.
79
+ *
80
+ * @default true
81
+ */
71
82
  outlookFallback: outlookFallbackProp,
83
+ /**
84
+ * DOCTYPE declaration prepended to the rendered HTML.
85
+ *
86
+ * Overrides `doctype` in the Maizzle config and any value
87
+ * set via `useDoctype()` in the same template.
88
+ *
89
+ * @default '<!DOCTYPE html>'
90
+ */
91
+ doctype: {
92
+ type: String,
93
+ default: undefined,
94
+ },
72
95
  })
73
96
 
74
97
  const outlookFallback = useOutlookFallback(props.outlookFallback)
75
98
 
99
+ if (props.doctype !== undefined) {
100
+ const ctx = inject(RenderContextKey, undefined)
101
+ if (ctx) ctx.doctype = props.doctype
102
+ }
103
+
76
104
  provide('htmlLang', props.lang)
77
105
 
78
106
  const render = () => {
@@ -55,6 +55,16 @@ const props = defineProps({
55
55
  type: String,
56
56
  default: undefined
57
57
  },
58
+ /**
59
+ * Toggle Outlook (MSO) and VML fallback markup for this
60
+ * component and all descendants.
61
+ *
62
+ * When `false`, skips MSO ghost tables, VML shapes,
63
+ * `xmlns:v`/`xmlns:o` attributes, and mso-specific CSS
64
+ * in all built-in components.
65
+ *
66
+ * @default true
67
+ */
58
68
  outlookFallback: outlookFallbackProp,
59
69
  })
60
70
 
@@ -68,21 +78,25 @@ const EmptyHead = () => createStaticVNode('<head></head>', 1)
68
78
 
69
79
  const MsoHead = () => createStaticVNode(
70
80
  `<!--[if mso]>
71
- <noscript>
72
- <xml>
73
- <o:OfficeDocumentSettings xmlns:o="urn:schemas-microsoft-com:office:office">
74
- <o:PixelsPerInch>96</o:PixelsPerInch>
75
- </o:OfficeDocumentSettings>
76
- </xml>
77
- </noscript>
78
- <style>
79
- td,th,div,p,a,h1,h2,h3,h4,h5,h6 {font-family: "Segoe UI", sans-serif; mso-line-height-rule: exactly;}
80
- .mso-break-all {word-break: break-all;}
81
- </style>
82
- <![endif]-->`,
81
+ <style>
82
+ td,th,div,p,a,h1,h2,h3,h4,h5,h6 {font-family: "Segoe UI", sans-serif; mso-line-height-rule: exactly;}
83
+ .mso-break-all {word-break: break-all;}
84
+ </style>
85
+ <![endif]-->`,
83
86
  1
84
87
  )
85
88
 
89
+ const msoBody = `<!--[if mso]>
90
+ <xml>
91
+ <o:OfficeDocumentSettings>
92
+ <o:PixelsPerInch>96</o:PixelsPerInch>
93
+ </o:OfficeDocumentSettings>
94
+ <w:WordDocument>
95
+ <w:DontUseAdvancedTypographyReadingMail />
96
+ </w:WordDocument>
97
+ </xml>
98
+ <![endif]-->`
99
+
86
100
  const htmlXmlns = computed(() => outlookFallback ? {
87
101
  'xmlns:v': 'urn:schemas-microsoft-com:vml',
88
102
  'xmlns:o': 'urn:schemas-microsoft-com:office:office',
@@ -112,6 +126,7 @@ const htmlXmlns = computed(() => outlookFallback ? {
112
126
  </style>
113
127
  </head>
114
128
  <body :xml:lang="outlookFallback ? lang : null" :class="bodyMergedClass">
129
+ <span v-if="outlookFallback" style="display: none" v-html="msoBody"></span>
115
130
  <div
116
131
  role="article"
117
132
  aria-roledescription="email"
@@ -0,0 +1,39 @@
1
+ <script setup lang="ts">
2
+ import type { PropType } from 'vue'
3
+ import Layout from './Layout.vue'
4
+ import Container from './Container.vue'
5
+
6
+ defineOptions({ inheritAttrs: false })
7
+
8
+ const props = defineProps({
9
+ /**
10
+ * Frontmatter object — wired in automatically when this layout
11
+ * wraps a `.md` template (the default behavior, or via the
12
+ * `layout: MarkdownLayout` frontmatter key).
13
+ *
14
+ * Keys matching `Layout`'s props (`lang`, `dir`, `bodyClass`,
15
+ * `doubleHead`, `ariaLabel`, `outlookFallback`) flow through to
16
+ * the wrapped `Layout`. Missing keys fall back to `Layout`'s
17
+ * own defaults.
18
+ */
19
+ frontmatter: {
20
+ type: Object as PropType<Record<string, unknown>>,
21
+ default: () => ({})
22
+ },
23
+ })
24
+ </script>
25
+
26
+ <template>
27
+ <Layout
28
+ :lang="props.frontmatter.lang as string | undefined"
29
+ :dir="props.frontmatter.dir as 'ltr' | 'rtl' | undefined"
30
+ :body-class="props.frontmatter.bodyClass as string | undefined"
31
+ :double-head="props.frontmatter.doubleHead as boolean | string | undefined"
32
+ :aria-label="props.frontmatter.ariaLabel as string | undefined"
33
+ :outlook-fallback="props.frontmatter.outlookFallback as boolean | undefined"
34
+ >
35
+ <Container class="max-w-xl">
36
+ <slot />
37
+ </Container>
38
+ </Layout>
39
+ </template>