@maizzle/framework 6.0.0-rc.24 → 6.0.0-rc.25
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.
- package/dist/build.js.map +1 -1
- package/dist/components/Body.vue +12 -0
- package/dist/components/Button.vue +16 -29
- package/dist/components/CodeBlock.vue +5 -4
- package/dist/components/CodeInline.vue +9 -8
- package/dist/components/Column.vue +17 -4
- package/dist/components/Container.vue +7 -11
- package/dist/components/Hr.vue +1 -1
- package/dist/components/Img.vue +39 -22
- package/dist/components/Layout.vue +1 -1
- package/dist/components/Markdown.vue +9 -14
- package/dist/components/QrCode.vue +2 -2
- package/dist/components/Section.vue +9 -6
- package/dist/components/Text.vue +2 -2
- package/dist/components/utils.d.ts +25 -1
- package/dist/components/utils.d.ts.map +1 -1
- package/dist/components/utils.js +29 -1
- package/dist/components/utils.js.map +1 -1
- package/dist/components/utils.ts +46 -0
- package/dist/composables/useConfig.d.ts.map +1 -1
- package/dist/composables/useCurrentTemplate.d.ts.map +1 -1
- package/dist/composables/useEvent.d.ts.map +1 -1
- package/dist/composables/useFont.js.map +1 -1
- package/dist/config/index.js.map +1 -1
- package/dist/events/index.d.ts.map +1 -1
- package/dist/events/index.js.map +1 -1
- package/dist/plaintext.js.map +1 -1
- package/dist/plugins/postcss/mergeMediaQueries.js.map +1 -1
- package/dist/plugins/postcss/pruneVars.js.map +1 -1
- package/dist/plugins/postcss/quoteFontFamilies.d.ts.map +1 -1
- package/dist/plugins/postcss/quoteFontFamilies.js.map +1 -1
- package/dist/plugins/postcss/removeDeclarations.js.map +1 -1
- package/dist/plugins/postcss/resolveProps.d.ts.map +1 -1
- package/dist/plugins/postcss/resolveProps.js +0 -3
- package/dist/plugins/postcss/resolveProps.js.map +1 -1
- package/dist/plugins/postcss/tailwindCleanup.js.map +1 -1
- package/dist/prepare.js +1 -1
- package/dist/prepare.js.map +1 -1
- package/dist/render/active.d.ts.map +1 -1
- package/dist/render/createRenderer.d.ts.map +1 -1
- package/dist/render/createRenderer.js +3 -7
- package/dist/render/createRenderer.js.map +1 -1
- package/dist/render/index.js.map +1 -1
- package/dist/render/injectFonts.js.map +1 -1
- package/dist/render/plugins/codeBlockExtract.d.ts.map +1 -1
- package/dist/render/plugins/codeBlockExtract.js.map +1 -1
- package/dist/render/plugins/markdownExtract.d.ts.map +1 -1
- package/dist/render/plugins/markdownExtract.js.map +1 -1
- package/dist/render/plugins/rawExtract.d.ts.map +1 -1
- package/dist/render/plugins/rawExtract.js.map +1 -1
- package/dist/render/plugins/rowSourceLocation.d.ts.map +1 -1
- package/dist/render/plugins/rowSourceLocation.js.map +1 -1
- package/dist/serve.js.map +1 -1
- package/dist/server/compatibility.d.ts.map +1 -1
- package/dist/server/compatibility.js.map +1 -1
- package/dist/server/linter.js.map +1 -1
- package/dist/server/sfc-utils.js.map +1 -1
- package/dist/tests/render/_helpers.d.ts.map +1 -1
- package/dist/tests/render/_helpers.js.map +1 -1
- package/dist/transformers/addAttributes.js +2 -3
- package/dist/transformers/addAttributes.js.map +1 -1
- package/dist/transformers/base.d.ts +1 -1
- package/dist/transformers/base.d.ts.map +1 -1
- package/dist/transformers/base.js +5 -10
- package/dist/transformers/base.js.map +1 -1
- package/dist/transformers/columnWidth.d.ts.map +1 -1
- package/dist/transformers/columnWidth.js +2 -7
- package/dist/transformers/columnWidth.js.map +1 -1
- package/dist/transformers/entities.js.map +1 -1
- package/dist/transformers/filters/defaults.js.map +1 -1
- package/dist/transformers/filters/index.js.map +1 -1
- package/dist/transformers/format.js.map +1 -1
- package/dist/transformers/imgWidth.d.ts +20 -0
- package/dist/transformers/imgWidth.d.ts.map +1 -0
- package/dist/transformers/imgWidth.js +76 -0
- package/dist/transformers/imgWidth.js.map +1 -0
- package/dist/transformers/index.d.ts.map +1 -1
- package/dist/transformers/index.js +2 -0
- package/dist/transformers/index.js.map +1 -1
- package/dist/transformers/inlineCss.d.ts +3 -2
- package/dist/transformers/inlineCss.d.ts.map +1 -1
- package/dist/transformers/inlineCss.js.map +1 -1
- package/dist/transformers/inlineLink.js +1 -1
- package/dist/transformers/inlineLink.js.map +1 -1
- package/dist/transformers/minify.js.map +1 -1
- package/dist/transformers/minifyCodeInline.js.map +1 -1
- package/dist/transformers/msoPlaceholders.d.ts.map +1 -1
- package/dist/transformers/msoPlaceholders.js +2 -7
- package/dist/transformers/msoPlaceholders.js.map +1 -1
- package/dist/transformers/purgeCss.js.map +1 -1
- package/dist/transformers/replaceStrings.js.map +1 -1
- package/dist/transformers/safeSelectors.js.map +1 -1
- package/dist/transformers/shorthandCss.js.map +1 -1
- package/dist/transformers/tailwindComponent.js.map +1 -1
- package/dist/transformers/tailwindcss.js +1 -1
- package/dist/transformers/tailwindcss.js.map +1 -1
- package/dist/transformers/urlQuery.js.map +1 -1
- package/dist/types/config.d.ts +5 -4
- package/dist/types/config.d.ts.map +1 -1
- package/dist/utils/ast/serializer.js.map +1 -1
- package/dist/utils/compileTailwindCss.js.map +1 -1
- package/dist/utils/componentSources.js.map +1 -1
- package/dist/utils/cssBox.d.ts.map +1 -1
- package/dist/utils/cssBox.js +2 -7
- package/dist/utils/cssBox.js.map +1 -1
- package/dist/utils/decodeStyleEntities.js.map +1 -1
- package/dist/utils/url.js.map +1 -1
- package/dist/utils/watchPaths.js.map +1 -1
- package/node_modules/@clack/core/CHANGELOG.md +30 -0
- package/node_modules/@clack/core/dist/index.d.mts +109 -3
- package/node_modules/@clack/core/dist/index.mjs +972 -17
- package/node_modules/@clack/core/package.json +2 -1
- package/node_modules/@clack/prompts/CHANGELOG.md +42 -0
- package/node_modules/@clack/prompts/README.md +30 -9
- package/node_modules/@clack/prompts/dist/index.d.mts +458 -27
- package/node_modules/@clack/prompts/dist/index.mjs +1378 -141
- package/node_modules/@clack/prompts/package.json +2 -2
- package/node_modules/tinyexec/package.json +4 -4
- package/package.json +8 -7
- package/dist/components/Overlap.vue +0 -156
- package/node_modules/@clack/core/dist/index.mjs.map +0 -1
- package/node_modules/@clack/prompts/dist/index.mjs.map +0 -1
package/dist/build.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","names":["parsePath"],"sources":["../src/build.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync, cpSync, existsSync, rmSync } from 'node:fs'\nimport { resolve, dirname, basename, relative, join, parse as parsePath } 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 { normalizeComponentSources } from './utils/componentSources.ts'\nimport { _setCurrentTemplate } from './composables/useCurrentTemplate.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: normalizeComponentSources(config.components?.source, process.cwd()), vite: config.vite })\n const outputFiles: string[] = []\n\n try {\n for (const templatePath of templateFiles) {\n const absolutePath = resolve(templatePath)\n const parsedPath = parsePath(absolutePath)\n const template = { source: readFileSync(absolutePath, 'utf-8'), path: parsedPath }\n\n _setCurrentTemplate(parsedPath)\n\n try {\n await events.fireBeforeRender({ config, template })\n\n const rendered = await renderer.render(absolutePath, config)\n\n /**\n * Register SFC event handlers collected during render so they take\n * part in the post-render events (afterRender / afterTransform).\n * They're cleared at the end of the iteration so they don't\n * leak into the next template.\n */\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 /**\n * Use the per-template merged config (from defineConfig() in the SFC) so\n * that template-level overrides like css.safe: false are respected\n * by transformers.\n */\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 if (doctype) html = `${doctype}\\n${html}`\n\n const htmlOut = stripForHtml(html)\n const sfcOutputPath = rendered.outputPath\n let outputFilePath: string\n\n if (sfcOutputPath) {\n const parsed = parsePath(resolve(sfcOutputPath))\n const ext = parsed.ext ? parsed.ext.slice(1) : outputExtension\n outputFilePath = join(parsed.dir, `${parsed.name}.${ext}`)\n } else {\n outputFilePath = resolveOutputPath(templatePath, outputPath, outputExtension, contentBase)\n }\n\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 (sfcOutputPath) {\n const parsed = parsePath(outputFilePath)\n ptOutputPath = join(parsed.dir, `${parsed.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 } finally {\n _setCurrentTemplate(undefined)\n events.clearSfcHandlers()\n }\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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"}
|
|
1
|
+
{"version":3,"file":"build.js","names":["parsePath"],"sources":["../src/build.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync, cpSync, existsSync, rmSync } from 'node:fs'\nimport { resolve, dirname, basename, relative, join, parse as parsePath } 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 { normalizeComponentSources } from './utils/componentSources.ts'\nimport { _setCurrentTemplate } from './composables/useCurrentTemplate.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: normalizeComponentSources(config.components?.source, process.cwd()), vite: config.vite })\n const outputFiles: string[] = []\n\n try {\n for (const templatePath of templateFiles) {\n const absolutePath = resolve(templatePath)\n const parsedPath = parsePath(absolutePath)\n const template = { source: readFileSync(absolutePath, 'utf-8'), path: parsedPath }\n\n _setCurrentTemplate(parsedPath)\n\n try {\n await events.fireBeforeRender({ config, template })\n\n const rendered = await renderer.render(absolutePath, config)\n\n /**\n * Register SFC event handlers collected during render so they take\n * part in the post-render events (afterRender / afterTransform).\n * They're cleared at the end of the iteration so they don't\n * leak into the next template.\n */\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 /**\n * Use the per-template merged config (from defineConfig() in the SFC) so\n * that template-level overrides like css.safe: false are respected\n * by transformers.\n */\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 if (doctype) html = `${doctype}\\n${html}`\n\n const htmlOut = stripForHtml(html)\n const sfcOutputPath = rendered.outputPath\n let outputFilePath: string\n\n if (sfcOutputPath) {\n const parsed = parsePath(resolve(sfcOutputPath))\n const ext = parsed.ext ? parsed.ext.slice(1) : outputExtension\n outputFilePath = join(parsed.dir, `${parsed.name}.${ext}`)\n } else {\n outputFilePath = resolveOutputPath(templatePath, outputPath, outputExtension, contentBase)\n }\n\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 (sfcOutputPath) {\n const parsed = parsePath(outputFilePath)\n ptOutputPath = join(parsed.dir, `${parsed.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 } finally {\n _setCurrentTemplate(undefined)\n events.clearSfcHandlers()\n }\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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"}
|
package/dist/components/Body.vue
CHANGED
|
@@ -85,6 +85,17 @@ const outlookFallback = useOutlookFallback(props.outlookFallback)
|
|
|
85
85
|
|
|
86
86
|
const htmlLang = inject<string>('htmlLang', 'en')
|
|
87
87
|
|
|
88
|
+
const msoBody = `<!--[if mso]>
|
|
89
|
+
<xml>
|
|
90
|
+
<o:OfficeDocumentSettings>
|
|
91
|
+
<o:PixelsPerInch>96</o:PixelsPerInch>
|
|
92
|
+
</o:OfficeDocumentSettings>
|
|
93
|
+
<w:WordDocument>
|
|
94
|
+
<w:DontUseAdvancedTypographyReadingMail />
|
|
95
|
+
</w:WordDocument>
|
|
96
|
+
</xml>
|
|
97
|
+
<![endif]-->`
|
|
98
|
+
|
|
88
99
|
const render = () => {
|
|
89
100
|
const extraAttrs = Object.entries(attrs)
|
|
90
101
|
.map(([key, value]) => value === true ? key : `${key}="${value}"`)
|
|
@@ -115,6 +126,7 @@ const render = () => {
|
|
|
115
126
|
|
|
116
127
|
return [
|
|
117
128
|
createStaticVNode(`<body ${parts.join(' ')}>`, 1),
|
|
129
|
+
outlookFallback ? createStaticVNode(`<span style="display: none">${msoBody}</span>`, 1) : null,
|
|
118
130
|
createStaticVNode(`<div ${articleParts}>`, 1),
|
|
119
131
|
slots.default?.(),
|
|
120
132
|
createStaticVNode('</div>', 1),
|
|
@@ -129,48 +129,35 @@ const alignClass = computed(() => props.align ? ({
|
|
|
129
129
|
right: 'text-right',
|
|
130
130
|
})[props.align] || '' : '')
|
|
131
131
|
|
|
132
|
-
const
|
|
132
|
+
const baseClasses = computed(() => {
|
|
133
133
|
if (props.variant === 'link') {
|
|
134
|
-
return 'text-
|
|
134
|
+
return 'no-underline text-gray-950'
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
const
|
|
138
|
-
'
|
|
139
|
-
'
|
|
140
|
-
'
|
|
141
|
-
'
|
|
142
|
-
'
|
|
143
|
-
'
|
|
137
|
+
const classes = [
|
|
138
|
+
'inline-block',
|
|
139
|
+
'no-underline',
|
|
140
|
+
'px-6',
|
|
141
|
+
'py-4',
|
|
142
|
+
'text-base',
|
|
143
|
+
'leading-none',
|
|
144
|
+
'rounded',
|
|
144
145
|
]
|
|
145
146
|
|
|
146
147
|
if (props.variant === 'outline') {
|
|
147
|
-
|
|
148
|
-
'background-color: transparent;',
|
|
149
|
-
'border: 1px solid #4338ca;',
|
|
150
|
-
'color: #4338ca;',
|
|
151
|
-
)
|
|
148
|
+
classes.push('bg-transparent', 'border', 'border-solid', 'border-indigo-700', 'text-indigo-700')
|
|
152
149
|
} else if (props.variant === 'ghost') {
|
|
153
|
-
|
|
154
|
-
'background-color: transparent;',
|
|
155
|
-
'color: #4338ca;',
|
|
156
|
-
)
|
|
150
|
+
classes.push('bg-transparent', 'text-indigo-700', 'hover:bg-indigo-50')
|
|
157
151
|
} else {
|
|
158
|
-
|
|
159
|
-
'background-color: #4338ca;',
|
|
160
|
-
'color: #fffffe;',
|
|
161
|
-
)
|
|
152
|
+
classes.push('bg-indigo-700', 'text-white')
|
|
162
153
|
}
|
|
163
154
|
|
|
164
|
-
return
|
|
155
|
+
return classes.join(' ')
|
|
165
156
|
})
|
|
166
157
|
|
|
167
158
|
const isLink = computed(() => props.variant === 'link')
|
|
168
159
|
|
|
169
|
-
const
|
|
170
|
-
props.variant === 'ghost' ? 'hover:bg-indigo-50' : '',
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
const mergedClass = computed(() => twMerge(variantClasses.value, attrs.class as string))
|
|
160
|
+
const mergedClass = computed(() => twMerge(baseClasses.value, attrs.class as string))
|
|
174
161
|
|
|
175
162
|
const textSpanStyle = computed(() =>
|
|
176
163
|
outlookFallback ? `mso-text-raise: ${props.msoPt};` : undefined,
|
|
@@ -209,7 +196,7 @@ const MsoIconGap = () => createStaticVNode(
|
|
|
209
196
|
<a
|
|
210
197
|
v-bind="{ ...$attrs, class: undefined, style: undefined }"
|
|
211
198
|
:href="href"
|
|
212
|
-
:style="
|
|
199
|
+
:style="$attrs.style as any"
|
|
213
200
|
:class="mergedClass"
|
|
214
201
|
>
|
|
215
202
|
<template v-if="!isLink">
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { createStaticVNode, type PropType } from 'vue'
|
|
3
3
|
import { twMerge } from 'tailwind-merge'
|
|
4
4
|
import { codeToHtml, getSingletonHighlighter, type BundledLanguage, type BundledTheme } from 'shiki'
|
|
5
|
+
import { buildCodeBlock, codeBlockPreClass } from './utils'
|
|
5
6
|
|
|
6
7
|
export default {
|
|
7
8
|
props: {
|
|
@@ -57,11 +58,11 @@ export default {
|
|
|
57
58
|
.replace(/^<pre[^>]*><code>/, '')
|
|
58
59
|
.replace(/<\/code><\/pre>$/, '')
|
|
59
60
|
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
const
|
|
61
|
+
const preClass = twMerge(codeBlockPreClass(bg), attrs.class as string)
|
|
62
|
+
const tdClass = twMerge(`bg-[${bg}]`, props.tdClass)
|
|
63
|
+
const styleAttr = attrs.style ? ` style="${attrs.style}"` : ''
|
|
63
64
|
|
|
64
|
-
const html =
|
|
65
|
+
const html = buildCodeBlock(codeContent, bg, { preClass, tdClass, styleAttr })
|
|
65
66
|
|
|
66
67
|
return () => createStaticVNode(html, 1)
|
|
67
68
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { createStaticVNode, type PropType } from 'vue'
|
|
3
|
+
import { twMerge } from 'tailwind-merge'
|
|
3
4
|
import { codeToHtml, getSingletonHighlighter, type BundledLanguage, type BundledTheme } from 'shiki'
|
|
4
5
|
|
|
5
6
|
export default {
|
|
@@ -50,8 +51,6 @@ export default {
|
|
|
50
51
|
return () => createStaticVNode('', 0)
|
|
51
52
|
}
|
|
52
53
|
|
|
53
|
-
const classes = attrs.class ? ` class="${attrs.class}"` : ''
|
|
54
|
-
|
|
55
54
|
if (props.theme) {
|
|
56
55
|
const highlighted = await codeToHtml(source, {
|
|
57
56
|
lang: props.language,
|
|
@@ -95,15 +94,17 @@ export default {
|
|
|
95
94
|
.replace(/</g, '§MZLT§')
|
|
96
95
|
.replace(/>/g, '§MZGT§')
|
|
97
96
|
|
|
98
|
-
const
|
|
99
|
-
const
|
|
97
|
+
const base = `bg-[${bg}] rounded-md py-0.5 px-1.5 text-[11px]`
|
|
98
|
+
const merged = twMerge(base, (attrs.class as string) ?? '')
|
|
99
|
+
const styleAttr = attrs.style ? ` style="${attrs.style}"` : ''
|
|
100
100
|
|
|
101
|
-
const html = `<code${
|
|
101
|
+
const html = `<code class="${merged}"${styleAttr} data-minify-inline>${escaped}</code>`
|
|
102
102
|
return () => createStaticVNode(html, 1)
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
const
|
|
106
|
-
const
|
|
105
|
+
const base = 'whitespace-normal rounded-md [border:1px_solid_#d1d5db] bg-gray-100 py-0.5 px-1.5 text-[11px] text-inherit'
|
|
106
|
+
const merged = twMerge(base, (attrs.class as string) ?? '')
|
|
107
|
+
const styleAttr = attrs.style ? ` style="${attrs.style}"` : ''
|
|
107
108
|
|
|
108
109
|
const escaped = source
|
|
109
110
|
.replace(/&/g, '&')
|
|
@@ -111,7 +112,7 @@ export default {
|
|
|
111
112
|
.replace(/>/g, '>')
|
|
112
113
|
.replace(/"/g, '"')
|
|
113
114
|
|
|
114
|
-
const html = `<code${
|
|
115
|
+
const html = `<code class="${merged}"${styleAttr}>${escaped}</code>`
|
|
115
116
|
|
|
116
117
|
return () => createStaticVNode(html, 1)
|
|
117
118
|
}
|
|
@@ -70,14 +70,27 @@ const msoWidth = computed(() => {
|
|
|
70
70
|
* `display: inline-block` would silently shadow a class like
|
|
71
71
|
* `inline-table` during CSS inlining; routing both through twMerge lets
|
|
72
72
|
* the user's utility cleanly replace ours instead of being dropped.
|
|
73
|
+
*
|
|
74
|
+
* When `width` is set as a prop the resolved pixel value also goes
|
|
75
|
+
* through the class list (`min-w-[Npx]`) so it dedupes against the
|
|
76
|
+
* user's `min-w-*` utility. The marker path (no prop) has to stay
|
|
77
|
+
* inline because the placeholder string is replaced post-render and
|
|
78
|
+
* Tailwind's content scanner can't compile a class whose value is
|
|
79
|
+
* still a marker.
|
|
73
80
|
*/
|
|
74
|
-
const baseClass = 'inline-block
|
|
75
|
-
const mergedClass = computed(() =>
|
|
81
|
+
const baseClass = 'inline-block text-[medium]'
|
|
82
|
+
const mergedClass = computed(() => {
|
|
83
|
+
const parts = [baseClass]
|
|
84
|
+
if (props.width != null) parts.push(`min-w-[${normalizeToPixels(props.width)}]`)
|
|
85
|
+
return twMerge(parts.join(' '), (attrs.class as string) ?? '')
|
|
86
|
+
})
|
|
76
87
|
|
|
77
|
-
const styles = computed(() =>
|
|
88
|
+
const styles = computed(() =>
|
|
89
|
+
props.width != null ? undefined : `min-width: ${minWidth.value};`
|
|
90
|
+
)
|
|
78
91
|
|
|
79
92
|
const tdStyle = computed(() => {
|
|
80
|
-
const parts = [`width: ${msoWidth.value}
|
|
93
|
+
const parts = [`width: ${msoWidth.value}`]
|
|
81
94
|
if (useMarker) parts.push(`__MAIZZLE_COLTDX_${colId}__`)
|
|
82
95
|
if (props.msoStyle) parts.push(props.msoStyle)
|
|
83
96
|
return parts.join('; ')
|
|
@@ -60,18 +60,15 @@ const useMarker = outlookFallback && props.width == null
|
|
|
60
60
|
const msoId = useMarker ? nextId('c') : null
|
|
61
61
|
const tdId = outlookFallback ? nextId('ct') : null
|
|
62
62
|
|
|
63
|
-
const styles = computed(() => {
|
|
64
|
-
if (props.width == null) return undefined
|
|
65
|
-
return `max-width: ${normalizeToPixels(props.width)}; margin: 0 auto;`
|
|
66
|
-
})
|
|
67
|
-
|
|
68
63
|
const mergedClass = computed(() => {
|
|
69
|
-
if (props.width != null) return attrs.class as string | undefined
|
|
70
64
|
const userClass = (attrs.class as string) ?? ''
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
65
|
+
const parts: string[] = ['m-0', 'mx-auto']
|
|
66
|
+
if (props.width != null) {
|
|
67
|
+
parts.push(`max-w-[${normalizeToPixels(props.width)}]`)
|
|
68
|
+
} else if (!hasWidthUtility(userClass)) {
|
|
69
|
+
parts.push('max-w-150')
|
|
70
|
+
}
|
|
71
|
+
return twMerge(parts.join(' '), userClass)
|
|
75
72
|
})
|
|
76
73
|
|
|
77
74
|
const msoWidth = computed(() => {
|
|
@@ -101,7 +98,6 @@ const MsoAfter = () => createStaticVNode(
|
|
|
101
98
|
<div
|
|
102
99
|
v-bind="{ ...attrs, class: undefined }"
|
|
103
100
|
:class="mergedClass"
|
|
104
|
-
:style="styles"
|
|
105
101
|
:data-maizzle-msow-id="msoId"
|
|
106
102
|
:data-maizzle-cw="colWidthSource"
|
|
107
103
|
:data-maizzle-mso-td-id="tdId"
|
package/dist/components/Hr.vue
CHANGED
|
@@ -15,7 +15,7 @@ const mergedClass = computed(() => {
|
|
|
15
15
|
const userHeight = heights.length ? heights[heights.length - 1][1] : null
|
|
16
16
|
const userHasLeading = LEADING_RE.test(userClass)
|
|
17
17
|
|
|
18
|
-
const defaults = ['my-6', 'bg-
|
|
18
|
+
const defaults = ['my-6', 'bg-gray-300']
|
|
19
19
|
if (!userHeight) defaults.push('h-px')
|
|
20
20
|
if (!userHasLeading && !userHeight) defaults.push('leading-px')
|
|
21
21
|
|
package/dist/components/Img.vue
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, createStaticVNode, useAttrs, type PropType } from 'vue'
|
|
3
|
+
import { twMerge } from 'tailwind-merge'
|
|
3
4
|
import { outlookFallbackProp } from './utils.ts'
|
|
4
5
|
import { useOutlookFallback } from '../composables/useOutlookFallback'
|
|
5
6
|
|
|
@@ -32,15 +33,22 @@ const props = defineProps({
|
|
|
32
33
|
type: String,
|
|
33
34
|
default: null
|
|
34
35
|
},
|
|
35
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* The width of the image, rendered without units.
|
|
38
|
+
*
|
|
39
|
+
* Optional: when omitted, the width is auto-derived post-render from
|
|
40
|
+
* the nearest sized ancestor (Container/Section/Column or any element
|
|
41
|
+
* with a pixel width). Falls back to fluid when no pixel width is
|
|
42
|
+
* resolvable. The `aspect` crop mode still requires an explicit width.
|
|
43
|
+
*/
|
|
36
44
|
width: {
|
|
37
45
|
type: [String, Number],
|
|
38
|
-
|
|
46
|
+
default: undefined
|
|
39
47
|
},
|
|
40
48
|
/** Animated image source, shown when user has no reduced motion preference. */
|
|
41
49
|
motionSrc: {
|
|
42
50
|
type: String,
|
|
43
|
-
default:
|
|
51
|
+
default: ''
|
|
44
52
|
},
|
|
45
53
|
/**
|
|
46
54
|
* Aspect ratio for cropped images.
|
|
@@ -111,7 +119,7 @@ const props = defineProps({
|
|
|
111
119
|
const outlookFallback = useOutlookFallback(props.outlookFallback)
|
|
112
120
|
|
|
113
121
|
function mimeFromExtension(src: string): string {
|
|
114
|
-
const ext = src.
|
|
122
|
+
const ext = src.slice(src.lastIndexOf('.') + 1).toLowerCase()
|
|
115
123
|
|
|
116
124
|
const types: Record<string, string> = {
|
|
117
125
|
apng: 'image/apng',
|
|
@@ -133,17 +141,12 @@ const ASPECT_KEYWORDS: Record<string, string> = {
|
|
|
133
141
|
'aspect-video': '16/9',
|
|
134
142
|
}
|
|
135
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Vue normalizes a component's `class` attr to a string before it
|
|
146
|
+
* reaches `attrs`, so only the string/empty cases can occur here.
|
|
147
|
+
*/
|
|
136
148
|
function normalizeClass(value: unknown): string {
|
|
137
|
-
|
|
138
|
-
if (typeof value === 'string') return value
|
|
139
|
-
if (Array.isArray(value)) return value.map(normalizeClass).filter(Boolean).join(' ')
|
|
140
|
-
if (typeof value === 'object') {
|
|
141
|
-
return Object.entries(value as Record<string, unknown>)
|
|
142
|
-
.filter(([, v]) => v)
|
|
143
|
-
.map(([k]) => k)
|
|
144
|
-
.join(' ')
|
|
145
|
-
}
|
|
146
|
-
return ''
|
|
149
|
+
return typeof value === 'string' ? value : ''
|
|
147
150
|
}
|
|
148
151
|
|
|
149
152
|
/**
|
|
@@ -182,10 +185,18 @@ const ratio = computed(() => {
|
|
|
182
185
|
|
|
183
186
|
const isCropped = computed(() => ratio.value !== null)
|
|
184
187
|
|
|
185
|
-
const motionType = computed(() => mimeFromExtension(props.motionSrc
|
|
188
|
+
const motionType = computed(() => mimeFromExtension(props.motionSrc))
|
|
186
189
|
|
|
187
190
|
const imgWidth = computed(() => Number.parseInt(String(props.width), 10))
|
|
188
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Whether an explicit, usable pixel width was supplied. When false, the
|
|
194
|
+
* non-cropped `<img>` is emitted without a width attribute plus a
|
|
195
|
+
* `data-maizzle-img-width` marker the `imgWidth` transformer reads to
|
|
196
|
+
* backfill the width from the nearest sized ancestor.
|
|
197
|
+
*/
|
|
198
|
+
const hasWidth = computed(() => props.width != null && props.width !== '' && Number.isFinite(imgWidth.value))
|
|
199
|
+
|
|
189
200
|
const heightPx = computed(() =>
|
|
190
201
|
ratio.value && Number.isFinite(imgWidth.value)
|
|
191
202
|
? Math.round((imgWidth.value * ratio.value.h) / ratio.value.w)
|
|
@@ -243,6 +254,13 @@ const NotMsoBefore = () => createStaticVNode('<!--[if !mso]><!-->', 1)
|
|
|
243
254
|
const NotMsoAfter = () => createStaticVNode('<!--<![endif]-->', 1)
|
|
244
255
|
|
|
245
256
|
const imgClass = 'max-w-full align-middle'
|
|
257
|
+
|
|
258
|
+
const cropClass = computed(() =>
|
|
259
|
+
twMerge(
|
|
260
|
+
`overflow-hidden table max-w-full${hasWidth.value ? ` w-[${imgWidth.value}px]` : ''}`,
|
|
261
|
+
parsedClass.value.className,
|
|
262
|
+
)
|
|
263
|
+
)
|
|
246
264
|
</script>
|
|
247
265
|
|
|
248
266
|
<template>
|
|
@@ -254,8 +272,7 @@ const imgClass = 'max-w-full align-middle'
|
|
|
254
272
|
v-bind="{ ...attrs, class: undefined }"
|
|
255
273
|
role="img"
|
|
256
274
|
:aria-label="alt || undefined"
|
|
257
|
-
:class="
|
|
258
|
-
:style="`width: ${imgWidth}px;`"
|
|
275
|
+
:class="cropClass"
|
|
259
276
|
>
|
|
260
277
|
<div
|
|
261
278
|
:class="[
|
|
@@ -278,7 +295,7 @@ const imgClass = 'max-w-full align-middle'
|
|
|
278
295
|
role="img"
|
|
279
296
|
:aria-label="alt || undefined"
|
|
280
297
|
:class="['overflow-hidden table max-w-full', parsedClass.className]"
|
|
281
|
-
:style="`width: ${imgWidth}px;`"
|
|
298
|
+
:style="hasWidth ? `width: ${imgWidth}px;` : undefined"
|
|
282
299
|
>
|
|
283
300
|
<div
|
|
284
301
|
:class="[
|
|
@@ -300,16 +317,16 @@ const imgClass = 'max-w-full align-middle'
|
|
|
300
317
|
<picture>
|
|
301
318
|
<source v-if="darkSrc" :srcset="darkSrc" media="(prefers-color-scheme: dark)">
|
|
302
319
|
<source v-if="motionSrc" :srcset="motionSrc" :type="motionType || undefined" media="(prefers-reduced-motion: no-preference)">
|
|
303
|
-
<img v-bind="attrs" :src="src" :alt="alt" :width="imgWidth" :class="imgClass">
|
|
320
|
+
<img v-bind="attrs" :src="src" :alt="alt" :width="hasWidth ? imgWidth : undefined" :data-maizzle-img-width="hasWidth ? undefined : ''" :class="imgClass" data-juice-duplicates="false">
|
|
304
321
|
</picture>
|
|
305
322
|
</a>
|
|
306
323
|
<picture v-else-if="usePicture">
|
|
307
324
|
<source v-if="darkSrc" :srcset="darkSrc" media="(prefers-color-scheme: dark)">
|
|
308
325
|
<source v-if="motionSrc" :srcset="motionSrc" :type="motionType || undefined" media="(prefers-reduced-motion: no-preference)">
|
|
309
|
-
<img v-bind="attrs" :src="src" :alt="alt" :width="imgWidth" :class="imgClass">
|
|
326
|
+
<img v-bind="attrs" :src="src" :alt="alt" :width="hasWidth ? imgWidth : undefined" :data-maizzle-img-width="hasWidth ? undefined : ''" :class="imgClass" data-juice-duplicates="false">
|
|
310
327
|
</picture>
|
|
311
328
|
<a v-else-if="href" :href="href">
|
|
312
|
-
<img v-bind="attrs" :src="src" :alt="alt" :width="imgWidth" :class="imgClass">
|
|
329
|
+
<img v-bind="attrs" :src="src" :alt="alt" :width="hasWidth ? imgWidth : undefined" :data-maizzle-img-width="hasWidth ? undefined : ''" :class="imgClass" data-juice-duplicates="false">
|
|
313
330
|
</a>
|
|
314
|
-
<img v-else v-bind="attrs" :src="src" :alt="alt" :width="imgWidth" :class="imgClass">
|
|
331
|
+
<img v-else v-bind="attrs" :src="src" :alt="alt" :width="hasWidth ? imgWidth : undefined" :data-maizzle-img-width="hasWidth ? undefined : ''" :class="imgClass" data-juice-duplicates="false">
|
|
315
332
|
</template>
|
|
@@ -116,7 +116,7 @@ const htmlXmlns = computed(() => outlookFallback ? {
|
|
|
116
116
|
<MsoHead v-if="outlookFallback" />
|
|
117
117
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
118
118
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous">
|
|
119
|
-
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet" media="screen">
|
|
119
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet" media="screen">
|
|
120
120
|
<style>
|
|
121
121
|
@import "@maizzle/tailwindcss";
|
|
122
122
|
|
|
@@ -3,7 +3,8 @@ import { createStaticVNode, inject, type PropType } from 'vue'
|
|
|
3
3
|
import { createMarkdownExit, type MarkdownExitOptions } from 'markdown-exit'
|
|
4
4
|
import { codeToHtml, type BundledTheme } from 'shiki'
|
|
5
5
|
import { defu } from 'defu'
|
|
6
|
-
import { MaizzleConfigKey } from '../composables/useConfig
|
|
6
|
+
import { MaizzleConfigKey } from '../composables/useConfig'
|
|
7
|
+
import { shikiToCodeBlock } from './utils'
|
|
7
8
|
|
|
8
9
|
export default {
|
|
9
10
|
props: {
|
|
@@ -62,9 +63,9 @@ export default {
|
|
|
62
63
|
* still works standalone, when no config is provided.
|
|
63
64
|
*/
|
|
64
65
|
const mdConfig = inject(MaizzleConfigKey, undefined)?.markdown ?? {}
|
|
65
|
-
const markdownOptions = mdConfig.markdownOptions
|
|
66
|
-
const markdownUses = mdConfig.markdownUses
|
|
67
|
-
const markdownSetup = mdConfig.markdownSetup
|
|
66
|
+
const markdownOptions = mdConfig.markdownOptions
|
|
67
|
+
const markdownUses = mdConfig.markdownUses
|
|
68
|
+
const markdownSetup = mdConfig.markdownSetup
|
|
68
69
|
const theme = props.shikiTheme ?? mdConfig.shikiTheme ?? 'github-dark-high-contrast'
|
|
69
70
|
|
|
70
71
|
const md = createMarkdownExit(defu(
|
|
@@ -89,23 +90,17 @@ export default {
|
|
|
89
90
|
* code-block wrapping below composes over whatever they emit.
|
|
90
91
|
*/
|
|
91
92
|
for (const use of markdownUses ?? []) {
|
|
92
|
-
if (Array.isArray(use)) md.use(...use)
|
|
93
|
+
if (Array.isArray(use)) md.use(use[0], ...use.slice(1))
|
|
93
94
|
else md.use(use)
|
|
94
95
|
}
|
|
95
96
|
await markdownSetup?.(md)
|
|
96
97
|
|
|
97
|
-
const wrapPre = (html: string) =>
|
|
98
|
-
`<table class="w-full"><tr><td class="max-w-0 mso-padding-alt-4">${html}</td></tr></table>\n`
|
|
99
|
-
|
|
100
98
|
const defaultFence = md.renderer.rules.fence!
|
|
101
|
-
md.renderer.rules.fence = (...args) =>
|
|
102
|
-
|
|
103
|
-
if (typeof result === 'string') return wrapPre(result)
|
|
104
|
-
return result.then(wrapPre)
|
|
105
|
-
}
|
|
99
|
+
md.renderer.rules.fence = (...args) =>
|
|
100
|
+
Promise.resolve(defaultFence(...args)).then(shikiToCodeBlock)
|
|
106
101
|
|
|
107
102
|
const defaultCodeBlock = md.renderer.rules.code_block!
|
|
108
|
-
md.renderer.rules.code_block = (...args) =>
|
|
103
|
+
md.renderer.rules.code_block = (...args) => shikiToCodeBlock(defaultCodeBlock(...args) as string)
|
|
109
104
|
|
|
110
105
|
let html = await md.renderAsync(source)
|
|
111
106
|
|
|
@@ -21,7 +21,7 @@ const escapeAttr = (v: string) =>
|
|
|
21
21
|
* fall through to the caller's default.
|
|
22
22
|
*/
|
|
23
23
|
function tokenToPx(token: string): number {
|
|
24
|
-
const seg = token.
|
|
24
|
+
const seg = token.slice(token.lastIndexOf(':') + 1)
|
|
25
25
|
const m = seg.match(/^(?:size|w|h)-(.+)$/)
|
|
26
26
|
if (!m) return 0
|
|
27
27
|
const v = m[1]
|
|
@@ -45,7 +45,7 @@ function partition(cls: string): { neutral: string[]; sizing: string[] } {
|
|
|
45
45
|
const neutral: string[] = []
|
|
46
46
|
const sizing: string[] = []
|
|
47
47
|
for (const t of cls.split(/\s+/).filter(Boolean)) {
|
|
48
|
-
const last = t.
|
|
48
|
+
const last = t.slice(t.lastIndexOf(':') + 1)
|
|
49
49
|
if (/^(?:size|w|h|min-w|min-h|max-w|max-h)-/.test(last)) sizing.push(t)
|
|
50
50
|
else neutral.push(t)
|
|
51
51
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { computed, createStaticVNode, useAttrs } from 'vue'
|
|
3
|
+
import { twMerge } from 'tailwind-merge'
|
|
3
4
|
import { hasWidthInStyle, hasWidthUtility, nextId, normalizeToPixels, outlookFallbackProp } from './utils.ts'
|
|
4
5
|
import { useOutlookFallback } from '../composables/useOutlookFallback'
|
|
5
6
|
|
|
@@ -65,15 +66,16 @@ const useMarker = outlookFallback && props.width == null && userHasWidth.value
|
|
|
65
66
|
const msoId = useMarker ? nextId('s') : null
|
|
66
67
|
const tdId = outlookFallback ? nextId('st') : null
|
|
67
68
|
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
if (props.width
|
|
71
|
-
|
|
72
|
-
return parts.length ? parts.join('; ') : undefined
|
|
69
|
+
const mergedClass = computed(() => {
|
|
70
|
+
const userClass = (attrs.class as string) ?? ''
|
|
71
|
+
if (props.width == null) return userClass || undefined
|
|
72
|
+
return twMerge(`max-w-[${normalizeToPixels(props.width)}]`, userClass)
|
|
73
73
|
})
|
|
74
74
|
|
|
75
|
+
const divStyle = computed(() => userStyle.value || undefined)
|
|
76
|
+
|
|
75
77
|
const restAttrs = computed(() => {
|
|
76
|
-
const { style: _, ...rest } = attrs
|
|
78
|
+
const { style: _, class: __, ...rest } = attrs
|
|
77
79
|
return rest
|
|
78
80
|
})
|
|
79
81
|
|
|
@@ -106,6 +108,7 @@ const MsoAfter = () => createStaticVNode(
|
|
|
106
108
|
<MsoBefore v-if="outlookFallback" />
|
|
107
109
|
<div
|
|
108
110
|
v-bind="restAttrs"
|
|
111
|
+
:class="mergedClass"
|
|
109
112
|
:style="divStyle"
|
|
110
113
|
:data-maizzle-msow-id="msoId"
|
|
111
114
|
:data-maizzle-msow-fallback="useMarker ? '100%' : null"
|
package/dist/components/Text.vue
CHANGED
|
@@ -18,8 +18,8 @@ const props = defineProps({
|
|
|
18
18
|
|
|
19
19
|
const attrs = useAttrs()
|
|
20
20
|
|
|
21
|
-
const defaultClass = computed(() => props.as === 'span' ? '
|
|
22
|
-
const mergedClass = computed(() => twMerge(defaultClass.value, attrs.class as string))
|
|
21
|
+
const defaultClass = computed(() => props.as === 'span' ? '' : 'mt-4 text-base')
|
|
22
|
+
const mergedClass = computed(() => twMerge(defaultClass.value, attrs.class as string) || undefined)
|
|
23
23
|
</script>
|
|
24
24
|
|
|
25
25
|
<template>
|
|
@@ -23,6 +23,30 @@ declare const outlookFallbackProp: {
|
|
|
23
23
|
readonly type: BooleanConstructor;
|
|
24
24
|
readonly default: null;
|
|
25
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* Default utility classes for a code-block `<pre>`. `whitespace-pre!` is
|
|
28
|
+
* forced important so Gmail's stylesheet can't reset it to `normal`, and
|
|
29
|
+
* `mb-0` strips the browser's default `<pre>` bottom margin.
|
|
30
|
+
*/
|
|
31
|
+
declare function codeBlockPreClass(bg: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* Build the email-safe table wrapper around highlighted code. Shared by the
|
|
34
|
+
* `<CodeBlock>` component and the Markdown fenced/indented code-block
|
|
35
|
+
* rules so both render identical markup: a full-width table whose
|
|
36
|
+
* cell carries the theme background, wrapping a `<pre>` styled
|
|
37
|
+
* with utility classes (not Shiki's raw inline styles).
|
|
38
|
+
*/
|
|
39
|
+
declare function buildCodeBlock(codeContent: string, bg: string, options?: {
|
|
40
|
+
preClass?: string;
|
|
41
|
+
tdClass?: string;
|
|
42
|
+
styleAttr?: string;
|
|
43
|
+
}): string;
|
|
44
|
+
/**
|
|
45
|
+
* Re-wrap a Shiki (or plain markdown-it) `<pre><code>` block as a CodeBlock,
|
|
46
|
+
* pulling the inner code and the theme background out of the highlighted
|
|
47
|
+
* HTML. Falls back to a white background for unhighlighted blocks.
|
|
48
|
+
*/
|
|
49
|
+
declare function shikiToCodeBlock(highlighted: string): string;
|
|
26
50
|
//#endregion
|
|
27
|
-
export { hasHeightInStyle, hasHeightUtility, hasWidthInStyle, hasWidthUtility, nextId, normalizeToPixels, outlookFallbackProp };
|
|
51
|
+
export { buildCodeBlock, codeBlockPreClass, hasHeightInStyle, hasHeightUtility, hasWidthInStyle, hasWidthUtility, nextId, normalizeToPixels, outlookFallbackProp, shikiToCodeBlock };
|
|
28
52
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","names":[],"sources":["../../src/components/utils.ts"],"mappings":";iBAAgB,iBAAA,CAAkB,KAAsB;AAAxD;;;;AAAwD;AAiBxD;;;AAjBA,iBAiBgB,MAAA,CAAO,MAAc;AAAA,iBAKrB,eAAA,CAAgB,QAAgB;AAAA,iBAQhC,eAAA,CAAgB,QAAgB;AAAA,iBAIhC,gBAAA,CAAiB,QAAgB;AAAA,iBAQjC,gBAAA,CAAiB,QAAgB;;AApBD;AAQhD;;;;cAsBa,mBAAA;EAAA,eAGH,kBAAA;EAAA"}
|
|
1
|
+
{"version":3,"file":"utils.d.ts","names":[],"sources":["../../src/components/utils.ts"],"mappings":";iBAAgB,iBAAA,CAAkB,KAAsB;AAAxD;;;;AAAwD;AAiBxD;;;AAjBA,iBAiBgB,MAAA,CAAO,MAAc;AAAA,iBAKrB,eAAA,CAAgB,QAAgB;AAAA,iBAQhC,eAAA,CAAgB,QAAgB;AAAA,iBAIhC,gBAAA,CAAiB,QAAgB;AAAA,iBAQjC,gBAAA,CAAiB,QAAgB;;AApBD;AAQhD;;;;cAsBa,mBAAA;EAAA,eAGH,kBAAA;EAAA;;;AArBuC;AAQjD;;;iBAoBgB,iBAAA,CAAkB,EAAU;AApBK;AAUjD;;;;;;AAViD,iBA+BjC,cAAA,CACd,WAAA,UACA,EAAA,UACA,OAAA;EAAW,QAAA;EAAmB,OAAA;EAAkB,SAAA;AAAA;;;AAdN;AAW5C;;iBAoBgB,gBAAA,CAAiB,WAAmB"}
|