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

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 (42) hide show
  1. package/dist/components/Body.vue +105 -36
  2. package/dist/components/Button.vue +4 -1
  3. package/dist/components/CodeBlock.vue +1 -1
  4. package/dist/components/CodeInline.vue +6 -1
  5. package/dist/components/Column.vue +30 -5
  6. package/dist/components/Container.vue +10 -2
  7. package/dist/components/Divider.vue +28 -0
  8. package/dist/components/Head.vue +22 -0
  9. package/dist/components/Heading.vue +28 -0
  10. package/dist/components/Html.vue +98 -47
  11. package/dist/components/Layout.vue +93 -0
  12. package/dist/components/Link.vue +26 -0
  13. package/dist/components/Markdown.vue +15 -2
  14. package/dist/components/Outlook.vue +36 -0
  15. package/dist/components/Overlap.vue +25 -5
  16. package/dist/components/Preheader.vue +1 -1
  17. package/dist/components/Row.vue +16 -5
  18. package/dist/components/Section.vue +83 -0
  19. package/dist/components/Text.vue +29 -0
  20. package/dist/components/Vml.vue +165 -13
  21. package/dist/render/createRenderer.d.mts.map +1 -1
  22. package/dist/render/createRenderer.mjs +13 -1
  23. package/dist/render/createRenderer.mjs.map +1 -1
  24. package/dist/serve.mjs +1 -1
  25. package/dist/serve.mjs.map +1 -1
  26. package/dist/server/compatibility.mjs +15 -1
  27. package/dist/server/compatibility.mjs.map +1 -1
  28. package/dist/server/email.mjs +2 -1
  29. package/dist/server/email.mjs.map +1 -1
  30. package/dist/server/linter.d.mts +1 -2
  31. package/dist/server/linter.d.mts.map +1 -1
  32. package/dist/server/linter.mjs +60 -71
  33. package/dist/server/linter.mjs.map +1 -1
  34. package/dist/server/ui/App.vue +9 -9
  35. package/dist/server/ui/pages/Preview.vue +215 -150
  36. package/dist/transformers/inlineCSS.d.mts +1 -14
  37. package/dist/transformers/inlineCSS.d.mts.map +1 -1
  38. package/dist/transformers/inlineCSS.mjs +16 -34
  39. package/dist/transformers/inlineCSS.mjs.map +1 -1
  40. package/dist/types/config.d.mts +11 -27
  41. package/dist/types/config.d.mts.map +1 -1
  42. package/package.json +1 -1
@@ -20,10 +20,10 @@ export default {
20
20
  type: String as PropType<BundledTheme>,
21
21
  default: 'github-dark-high-contrast'
22
22
  },
23
- /** Wrap output in a div element. @default true */
23
+ /** Wrap output in a div element. @default false */
24
24
  wrapper: {
25
25
  type: Boolean,
26
- default: true
26
+ default: false
27
27
  },
28
28
  },
29
29
  inheritAttrs: false,
@@ -56,6 +56,19 @@ export default {
56
56
  },
57
57
  })
58
58
 
59
+ const wrapPre = (html: string) =>
60
+ `<table class="w-full"><tr><td class="max-w-0 mso-padding-alt-4">${html}</td></tr></table>\n`
61
+
62
+ const defaultFence = md.renderer.rules.fence!
63
+ md.renderer.rules.fence = (...args) => {
64
+ const result = defaultFence(...args)
65
+ if (typeof result === 'string') return wrapPre(result)
66
+ return result.then(wrapPre)
67
+ }
68
+
69
+ const defaultCodeBlock = md.renderer.rules.code_block!
70
+ md.renderer.rules.code_block = (...args) => wrapPre(defaultCodeBlock(...args) as string)
71
+
59
72
  let html = await md.renderAsync(source)
60
73
 
61
74
  if (props.wrapper) {
@@ -22,11 +22,47 @@ const parseList = (value: string) =>
22
22
  export default {
23
23
  name: 'Outlook',
24
24
  props: {
25
+ /**
26
+ * Render content only in the specified Outlook version(s).
27
+ *
28
+ * Comma-separated list of years.
29
+ *
30
+ * @example '2013'
31
+ * @example '2013,2016'
32
+ */
25
33
  only: String,
34
+ /**
35
+ * Render content in all Outlook versions except the specified one(s).
36
+ *
37
+ * Comma-separated list of years.
38
+ *
39
+ * @example '2007'
40
+ * @example '2007,2010'
41
+ */
26
42
  not: String,
43
+ /**
44
+ * Render content in Outlook versions lower than the specified year.
45
+ *
46
+ * @example '2013'
47
+ */
27
48
  lt: String,
49
+ /**
50
+ * Render content in Outlook versions lower than or equal to the specified year.
51
+ *
52
+ * @example '2013'
53
+ */
28
54
  lte: String,
55
+ /**
56
+ * Render content in Outlook versions greater than the specified year.
57
+ *
58
+ * @example '2010'
59
+ */
29
60
  gt: String,
61
+ /**
62
+ * Render content in Outlook versions greater than or equal to the specified year.
63
+ *
64
+ * @example '2010'
65
+ */
30
66
  gte: String
31
67
  },
32
68
  setup(props, { slots }) {
@@ -7,22 +7,42 @@ defineOptions({ inheritAttrs: false })
7
7
  const attrs = useAttrs()
8
8
 
9
9
  const props = defineProps({
10
- /** Max height of the overlapped (background) content. */
10
+ /**
11
+ * Max height of the background (default slot) content.
12
+ *
13
+ * This constrains the visible area of the background layer.
14
+ */
11
15
  height: {
12
16
  type: [String, Number],
13
17
  required: true
14
18
  },
15
- /** Width of the overlay table and VML rect. */
19
+ /**
20
+ * Width of the overlay table and VML rectangle.
21
+ *
22
+ * Should match the width of the content being overlapped.
23
+ */
16
24
  width: {
17
25
  type: [String, Number],
18
26
  required: true
19
27
  },
20
- /** Height of the VML rect for Outlook. Defaults to height. */
28
+ /**
29
+ * Height of the VML rectangle in Outlook.
30
+ *
31
+ * Defaults to the `height` prop value. Use this to fine-tune
32
+ * the overlay height specifically for Outlook rendering.
33
+ */
21
34
  msoHeight: {
22
35
  type: [String, Number],
23
36
  default: null
24
37
  },
25
- /** VML textbox inset value for Outlook positioning. */
38
+ /**
39
+ * VML textbox inset for Outlook positioning.
40
+ *
41
+ * Controls the offset of the overlay content as `top,right,bottom,left`.
42
+ * Use negative values to shift content upward into the background area.
43
+ *
44
+ * @default '0,-60px,0,0'
45
+ */
26
46
  msoInset: {
27
47
  type: String,
28
48
  default: '0,-60px,0,0'
@@ -37,7 +57,7 @@ const vmlOpen = computed(() => {
37
57
  const w = normalizeToPixels(props.width)
38
58
  const h = normalizeToPixels(props.msoHeight ?? props.height)
39
59
 
40
- return `<!--[if mso]><v:rect xmlns:v="urn:schemas-microsoft-com:vml" stroked="f" filled="f" style="width:${w};height:${h};"><v:textbox inset="${props.msoInset}"><![endif]-->`
60
+ return `<!--[if mso]><v:rect xmlns:v="urn:schemas-microsoft-com:vml" stroked="f" filled="f" style="width: ${w}; height: ${h};"><v:textbox inset="${props.msoInset}"><![endif]-->`
41
61
  })
42
62
 
43
63
  const VmlBefore = () => createStaticVNode(vmlOpen.value, 1)
@@ -15,6 +15,6 @@ defineProps({
15
15
 
16
16
  <template>
17
17
  <Teleport to="body:start">
18
- <div style="display:none"><slot /><template v-for="i in fillerCount" :key="'f'+i">&#8199;&#847; </template><template v-for="i in shyCount" :key="'s'+i">&shy; </template>&nbsp;</div>
18
+ <div style="display: none"><slot /><template v-for="i in fillerCount" :key="'f'+i">&#8199;&#847; </template><template v-for="i in shyCount" :key="'s'+i">&shy; </template>&nbsp;</div>
19
19
  </Teleport>
20
20
  </template>
@@ -7,12 +7,23 @@ defineOptions({ inheritAttrs: false })
7
7
  const attrs = useAttrs()
8
8
 
9
9
  const props = defineProps({
10
- /** Override the inherited container width. */
10
+ /**
11
+ * Override the inherited container width.
12
+ *
13
+ * Used to calculate column widths. Inherited from the
14
+ * parent `Container` by default.
15
+ */
11
16
  width: {
12
17
  type: [String, Number],
13
18
  default: null
14
19
  },
15
- /** Override the auto-detected column count. */
20
+ /**
21
+ * Override the auto-detected column count.
22
+ *
23
+ * By default, the number of direct child elements is used.
24
+ * Set this when the auto-detection doesn't match your layout
25
+ * (e.g. when using `v-if` or `v-for`).
26
+ */
16
27
  cols: {
17
28
  type: Number,
18
29
  default: null
@@ -48,13 +59,13 @@ const rowWidth = computed(() => props.width ?? containerWidth?.value ?? '37.5em'
48
59
 
49
60
  function divideValue(value: string | number, divisor: number): string {
50
61
  if (typeof value === 'number') {
51
- return `${value / divisor}px`
62
+ return `${parseFloat((value / divisor).toFixed(2))}px`
52
63
  }
53
64
 
54
65
  const num = Number.parseFloat(value)
55
66
  const unit = value.replace(String(num), '') || 'px'
56
67
 
57
- return `${num / divisor}${unit}`
68
+ return `${parseFloat((num / divisor).toFixed(2))}${unit}`
58
69
  }
59
70
 
60
71
  provide('columnMinWidth', computed(() => divideValue(rowWidth.value, columnCount.value)))
@@ -73,7 +84,7 @@ const MsoAfter = () => createStaticVNode(
73
84
 
74
85
  <template>
75
86
  <MsoBefore />
76
- <div v-bind="attrs" style="width: 100%; font-size: 0;">
87
+ <div v-bind="attrs" style="font-size: 0;">
77
88
  <slot />
78
89
  </div>
79
90
  <MsoAfter />
@@ -0,0 +1,83 @@
1
+ <script setup lang="ts">
2
+ import { computed, createStaticVNode, useAttrs } from 'vue'
3
+ import { normalizeToPixels } from './utils.ts'
4
+
5
+ defineOptions({ inheritAttrs: false })
6
+
7
+ const attrs = useAttrs()
8
+
9
+ const props = defineProps({
10
+ /**
11
+ * Width of the section.
12
+ *
13
+ * Applied as `max-width` on the div and as `width` on the MSO table.
14
+ *
15
+ * @default '100%'
16
+ */
17
+ width: {
18
+ type: [String, Number],
19
+ default: '100%'
20
+ },
21
+ /**
22
+ * Inline CSS applied only to the MSO `<td>` element.
23
+ *
24
+ * Use for Outlook-specific styling that shouldn't affect other clients.
25
+ *
26
+ * @example 'padding: 10px 20px'
27
+ */
28
+ msoStyle: {
29
+ type: String,
30
+ default: undefined
31
+ }
32
+ })
33
+
34
+ const hasCustomWidth = computed(() => props.width !== '100%')
35
+
36
+ const userStyle = computed(() => {
37
+ const s = attrs.style
38
+ if (!s) return ''
39
+ return typeof s === 'object'
40
+ ? Object.entries(s).map(([k, v]) => `${k.replace(/([A-Z])/g, '-$1').toLowerCase()}: ${v}`).join('; ')
41
+ : String(s)
42
+ })
43
+
44
+ const divStyle = computed(() => {
45
+ const parts: string[] = []
46
+ if (hasCustomWidth.value) parts.push(`max-width: ${normalizeToPixels(props.width)}`)
47
+ if (userStyle.value) parts.push(userStyle.value)
48
+ return parts.length ? parts.join('; ') : undefined
49
+ })
50
+
51
+ const restAttrs = computed(() => {
52
+ const { style: _, ...rest } = attrs
53
+ return rest
54
+ })
55
+
56
+ const tdStyles = computed(() => {
57
+ const parts: string[] = []
58
+ if (userStyle.value) parts.push(userStyle.value)
59
+ if (props.msoStyle) parts.push(props.msoStyle)
60
+ return parts.length ? parts.join('; ') : ''
61
+ })
62
+
63
+ const MsoBefore = () => {
64
+ const tdStyle = tdStyles.value ? ` style="${tdStyles.value}"` : ''
65
+ return createStaticVNode(
66
+ `<!--[if mso]><table role="none" cellpadding="0" cellspacing="0" style="width: ${normalizeToPixels(props.width)}"><tr><td${tdStyle}><![endif]-->`,
67
+ 1
68
+ )
69
+ }
70
+
71
+ const MsoAfter = () => createStaticVNode(
72
+ '<!--[if mso]></td></tr></table><![endif]-->',
73
+ 1
74
+ )
75
+ </script>
76
+
77
+ <template>
78
+ <MsoBefore />
79
+ <div v-bind="restAttrs" :style="divStyle">
80
+ <slot />
81
+ </div>
82
+ <MsoAfter />
83
+ </template>
@@ -0,0 +1,29 @@
1
+ <script setup lang="ts">
2
+ import { type PropType, computed, useAttrs } from 'vue'
3
+ import { twMerge } from 'tailwind-merge'
4
+
5
+ defineOptions({ inheritAttrs: false })
6
+
7
+ const props = defineProps({
8
+ /**
9
+ * The HTML element to render.
10
+ * @default 'p'
11
+ */
12
+ as: {
13
+ type: String as PropType<'p' | 'span'>,
14
+ default: 'p',
15
+ validator: (v: string) => ['p', 'span'].includes(v),
16
+ },
17
+ })
18
+
19
+ const attrs = useAttrs()
20
+
21
+ const defaultClass = computed(() => props.as === 'span' ? 'text-base' : 'm-0 my-4 text-base')
22
+ const mergedClass = computed(() => twMerge(defaultClass.value, attrs.class as string))
23
+ </script>
24
+
25
+ <template>
26
+ <component :is="props.as" v-bind="$attrs" :class="mergedClass">
27
+ <slot />
28
+ </component>
29
+ </template>
@@ -1,56 +1,208 @@
1
1
  <script lang="ts">
2
2
  import { computed, createStaticVNode } from 'vue'
3
+ import type { PropType } from 'vue'
3
4
  import { normalizeToPixels } from './utils.ts'
4
5
 
5
6
  export default {
6
7
  name: 'Vml',
7
8
  props: {
9
+ /**
10
+ * Width of the VML rectangle.
11
+ *
12
+ * Accepts a number (treated as pixels) or a string with units.
13
+ *
14
+ * @default '600px'
15
+ */
8
16
  width: {
9
17
  type: [String, Number],
10
18
  default: '600px'
11
19
  },
20
+ /**
21
+ * Height of the VML rectangle.
22
+ *
23
+ * Accepts a number (treated as pixels) or a string with units.
24
+ * When not set, the rectangle auto-sizes to fit its content.
25
+ */
12
26
  height: {
13
27
  type: [String, Number],
14
28
  default: null
15
29
  },
30
+ /**
31
+ * VML fill type that controls how the background image is rendered.
32
+ *
33
+ * - `frame` — scale to fill the rectangle (default)
34
+ * - `tile` — repeat the image to fill the rectangle
35
+ * - `pattern` — tile at original size
36
+ * - `solid` — solid color fill, no image
37
+ * - `gradient` — linear gradient fill
38
+ * - `gradientradial` — radial gradient fill
39
+ *
40
+ * @default 'frame'
41
+ */
16
42
  type: {
17
- type: String,
43
+ type: String as PropType<'solid' | 'gradient' | 'gradientradial' | 'tile' | 'pattern' | 'frame'>,
18
44
  default: 'frame'
19
45
  },
20
- sizes: String,
21
- origin: String,
22
- position: String,
23
- aspect: String,
46
+ /**
47
+ * Comma-separated dimensions for the fill image.
48
+ *
49
+ * Controls the rendered size of the background image.
50
+ *
51
+ * @example '300px,200px'
52
+ */
53
+ sizes: {
54
+ type: String,
55
+ validator: (v: string) => /^[\d.]+(px|%|em|rem)?(,[\d.]+(px|%|em|rem)?)+$/.test(v.replace(/\s/g, ''))
56
+ },
57
+ /**
58
+ * Fill origin offset as comma-separated fractional values.
59
+ *
60
+ * Controls where the fill image anchors relative to the shape.
61
+ * Values are fractions of the shape's dimensions, where `0,0` is
62
+ * center and `-0.5,-0.5` is the top-left corner.
63
+ *
64
+ * Overridden by `backgroundPosition` if both are set.
65
+ *
66
+ * @example '0,0'
67
+ * @example '-0.5,-0.5'
68
+ */
69
+ origin: {
70
+ type: String,
71
+ validator: (v: string) => /^-?[\d.]+(,-?[\d.]+)+$/.test(v.replace(/\s/g, ''))
72
+ },
73
+ /**
74
+ * Fill position offset as comma-separated fractional values.
75
+ *
76
+ * Controls where the fill image is positioned within the shape.
77
+ * Values are fractions of the shape's dimensions, where `0,0` is
78
+ * center and `0.5,0.5` is the bottom-right corner.
79
+ *
80
+ * Overridden by `backgroundPosition` if both are set.
81
+ *
82
+ * @example '0,0'
83
+ * @example '0.5,0.5'
84
+ */
85
+ position: {
86
+ type: String,
87
+ validator: (v: string) => /^-?[\d.]+(,-?[\d.]+)+$/.test(v.replace(/\s/g, ''))
88
+ },
89
+ /**
90
+ * Background image position as `vertical,horizontal`.
91
+ *
92
+ * First value is the vertical axis: `top`, `center`, or `bottom`.
93
+ * Second value is the horizontal axis: `left`, `center`, or `right`.
94
+ *
95
+ * Convenience prop that maps to VML `origin` and `position` attributes.
96
+ *
97
+ * @example 'top,left'
98
+ * @example 'center,center'
99
+ */
100
+ backgroundPosition: {
101
+ type: String as PropType<
102
+ | 'top,left' | 'top,center' | 'top,right'
103
+ | 'center,left' | 'center,center' | 'center,right'
104
+ | 'bottom,left' | 'bottom,center' | 'bottom,right'
105
+ >,
106
+ validator: (v: string) => /^(top|center|bottom),(left|center|right)$/.test(v.replace(/\s/g, ''))
107
+ },
108
+ /**
109
+ * Aspect ratio constraint for the fill image.
110
+ *
111
+ * - `atleast` — image is at least as large as the shape
112
+ * - `atmost` — image is at most as large as the shape
113
+ */
114
+ aspect: {
115
+ type: String as PropType<'atleast' | 'atmost'>,
116
+ },
117
+ /**
118
+ * Fill color used for `solid` and `gradient` fill types.
119
+ *
120
+ * @example '#ffffff'
121
+ */
24
122
  color: String,
123
+ /**
124
+ * Text box inset (padding) as `top,right,bottom,left`.
125
+ *
126
+ * Controls the inner spacing of the `v:textbox` element.
127
+ *
128
+ * @default '0,0,0,0'
129
+ */
25
130
  inset: {
26
131
  type: String,
27
132
  default: '0,0,0,0'
28
133
  },
134
+ /**
135
+ * Whether the VML rectangle has a visible border.
136
+ *
137
+ * @default false
138
+ */
29
139
  stroke: {
30
- type: String,
31
- default: 'f'
140
+ type: [Boolean, String],
141
+ default: false
32
142
  },
143
+ /**
144
+ * Border color for the VML rectangle.
145
+ *
146
+ * Setting this also enables `stroke` automatically.
147
+ *
148
+ * @example '#000000'
149
+ */
33
150
  strokecolor: String,
151
+ /**
152
+ * Whether the VML rectangle has a fill.
153
+ *
154
+ * @default true
155
+ */
34
156
  fill: {
35
- type: String,
36
- default: 't'
157
+ type: [Boolean, String],
158
+ default: true
37
159
  },
160
+ /**
161
+ * Background color of the VML rectangle.
162
+ *
163
+ * Used as a fallback when the background image cannot be loaded.
164
+ *
165
+ * @default 'none'
166
+ * @example '#3b82f6'
167
+ */
38
168
  fillcolor: {
39
169
  type: String,
40
170
  default: 'none'
41
171
  },
172
+ /**
173
+ * URL of the background image.
174
+ *
175
+ * @default 'https://via.placeholder.com/600x400'
176
+ */
42
177
  src: {
43
178
  type: String,
44
179
  default: 'https://via.placeholder.com/600x400'
45
180
  }
46
181
  },
47
182
  setup(props, { slots }) {
183
+ const backgroundPositionMap: Record<string, string> = {
184
+ 'top,left': '-0.5,-0.5',
185
+ 'top,center': '0,-0.5',
186
+ 'top,right': '0.5,-0.5',
187
+ 'center,left': '-0.5,0',
188
+ 'center,center': '0,0',
189
+ 'center,right': '0.5,0',
190
+ 'bottom,left': '-0.5,0.5',
191
+ 'bottom,center': '0,0.5',
192
+ 'bottom,right': '0.5,0.5',
193
+ }
194
+
195
+ const resolvedOrigin = computed(() => props.origin ?? (props.backgroundPosition ? backgroundPositionMap[props.backgroundPosition.replace(/\s/g, '')] : undefined))
196
+ const resolvedPosition = computed(() => props.position ?? (props.backgroundPosition ? backgroundPositionMap[props.backgroundPosition.replace(/\s/g, '')] : undefined))
197
+
48
198
  const before = computed(() => {
49
199
  const width = normalizeToPixels(props.width)
50
200
 
201
+ const toBool = (v: boolean | string) => v === true || v === 'true' ? 'true' : 'false'
202
+
51
203
  const rectAttrs = [
52
- `fill="${props.fillcolor ? 't' : props.fill}"`,
53
- `stroke="${props.strokecolor ? 't' : props.stroke}"`,
204
+ `fill="${props.fillcolor ? 'true' : toBool(props.fill)}"`,
205
+ `stroke="${props.strokecolor ? 'true' : toBool(props.stroke)}"`,
54
206
  `style="width: ${width};${props.height ? ` height: ${normalizeToPixels(props.height)};` : ''}"`,
55
207
  props.strokecolor ? `strokecolor="${props.strokecolor}"` : '',
56
208
  props.fillcolor ? `fillcolor="${props.fillcolor}"` : ''
@@ -61,8 +213,8 @@ export default {
61
213
  `src="${props.src}"`,
62
214
  props.sizes ? `sizes="${props.sizes}"` : '',
63
215
  props.aspect ? `aspect="${props.aspect}"` : '',
64
- props.origin ? `origin="${props.origin}"` : '',
65
- props.position ? `position="${props.position}"` : '',
216
+ resolvedOrigin.value ? `origin="${resolvedOrigin.value}"` : '',
217
+ resolvedPosition.value ? `position="${resolvedPosition.value}"` : '',
66
218
  props.color ? `color="${props.color}"` : ''
67
219
  ].filter(Boolean).join(' ')
68
220
 
@@ -1 +1 @@
1
- {"version":3,"file":"createRenderer.d.mts","names":[],"sources":["../../src/render/createRenderer.ts"],"mappings":";;;;;UAwJiB,gBAAA;EACf,IAAA;EACA,OAAA;EACA,cAAA,EAAgB,aAAA;EAChB,gBAAA,EAAkB,aAAA;EAClB,SAAA,GAAY,aAAA;AAAA;AAAA,UAGG,QAAA;EACf,MAAA,CAAO,KAAA,WAAgB,SAAA,EAAW,MAAA,EAAQ,aAAA,GAAgB,OAAA,CAAQ,gBAAA;EAClE,UAAA,CAAW,QAAA,WAAmB,OAAA;EAC9B,aAAA,IAAiB,OAAA;EACjB,KAAA,IAAS,OAAA;AAAA;AAAA,UAGM,qBAAA;EAZC;EAchB,GAAA;EAbkB;EAelB,QAAA,GAAW,cAAA;EAdC;EAgBZ,IAAA;EAhByB;EAkBzB,aAAA;AAAA;;;;;;;iBASoB,cAAA,CACpB,OAAA,GAAS,qBAAA,GACR,OAAA,CAAQ,QAAA"}
1
+ {"version":3,"file":"createRenderer.d.mts","names":[],"sources":["../../src/render/createRenderer.ts"],"mappings":";;;;;UAyJiB,gBAAA;EACf,IAAA;EACA,OAAA;EACA,cAAA,EAAgB,aAAA;EAChB,gBAAA,EAAkB,aAAA;EAClB,SAAA,GAAY,aAAA;AAAA;AAAA,UAGG,QAAA;EACf,MAAA,CAAO,KAAA,WAAgB,SAAA,EAAW,MAAA,EAAQ,aAAA,GAAgB,OAAA,CAAQ,gBAAA;EAClE,UAAA,CAAW,QAAA,WAAmB,OAAA;EAC9B,aAAA,IAAiB,OAAA;EACjB,KAAA,IAAS,OAAA;AAAA;AAAA,UAGM,qBAAA;EAZC;EAchB,GAAA;EAbkB;EAelB,QAAA,GAAW,cAAA;EAdC;EAgBZ,IAAA;EAhByB;EAkBzB,aAAA;AAAA;;;;;;;iBASoB,cAAA,CACpB,OAAA,GAAS,qBAAA,GACR,OAAA,CAAQ,QAAA"}
@@ -125,13 +125,25 @@ async function createRenderer(options = {}) {
125
125
  Markdown(defu(markdownOptions ?? {}, {
126
126
  headEnabled: true,
127
127
  wrapperDiv: false,
128
+ wrapperClasses: "prose",
128
129
  markdownOptions: { async highlight(code, lang) {
129
130
  const { codeToHtml } = await import("shiki");
130
131
  return codeToHtml(code, {
131
132
  lang,
132
133
  theme: shikiTheme
133
134
  });
134
- } }
135
+ } },
136
+ markdownSetup(md) {
137
+ const wrapPre = (html) => `<table class="w-full"><tr><td class="max-w-0 mso-padding-alt-4">${html}</td></tr></table>\n`;
138
+ const defaultFence = md.renderer.rules.fence;
139
+ md.renderer.rules.fence = (...args) => {
140
+ const result = defaultFence(...args);
141
+ if (typeof result === "string") return wrapPre(result);
142
+ return result.then(wrapPre);
143
+ };
144
+ const defaultCodeBlock = md.renderer.rules.code_block;
145
+ md.renderer.rules.code_block = (...args) => wrapPre(defaultCodeBlock(...args));
146
+ }
135
147
  })),
136
148
  AutoImport({
137
149
  dirs: [resolve(__dirname, "../composables"), resolve(__dirname, "../filters")],