@maizzle/framework 6.0.0-rc.23 → 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 +11 -2
- 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 +51 -24
- 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/renderContext.d.ts +1 -0
- package/dist/composables/renderContext.d.ts.map +1 -1
- package/dist/composables/renderContext.js +1 -1
- package/dist/composables/renderContext.js.map +1 -1
- package/dist/composables/useConfig.d.ts +7 -0
- package/dist/composables/useConfig.d.ts.map +1 -1
- package/dist/composables/useConfig.js +8 -1
- package/dist/composables/useConfig.js.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/composables/useOutputPath.d.ts +17 -0
- package/dist/composables/useOutputPath.d.ts.map +1 -0
- package/dist/composables/useOutputPath.js +23 -0
- package/dist/composables/useOutputPath.js.map +1 -0
- 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/index.d.ts +2 -1
- package/dist/index.js +2 -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 +1 -0
- package/dist/render/createRenderer.d.ts.map +1 -1
- package/dist/render/createRenderer.js +19 -7
- package/dist/render/createRenderer.js.map +1 -1
- package/dist/render/index.js +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 +3 -3
- 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/server/ui/App.vue +3 -4
- package/dist/server/ui/main.css +25 -0
- package/dist/server/ui/pages/Preview.vue +5 -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/dist/server/ui/components/Markdown.vue +0 -17
- package/node_modules/@clack/core/dist/index.mjs.map +0 -1
- package/node_modules/@clack/prompts/dist/index.mjs.map +0 -1
|
@@ -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"}
|
package/dist/components/utils.js
CHANGED
|
@@ -44,7 +44,35 @@ const outlookFallbackProp = {
|
|
|
44
44
|
type: Boolean,
|
|
45
45
|
default: null
|
|
46
46
|
};
|
|
47
|
+
/**
|
|
48
|
+
* Default utility classes for a code-block `<pre>`. `whitespace-pre!` is
|
|
49
|
+
* forced important so Gmail's stylesheet can't reset it to `normal`, and
|
|
50
|
+
* `mb-0` strips the browser's default `<pre>` bottom margin.
|
|
51
|
+
*/
|
|
52
|
+
function codeBlockPreClass(bg) {
|
|
53
|
+
return `font-mono bg-[${bg}] p-4 mb-0 overflow-auto whitespace-pre! [word-wrap:normal] [word-break:normal] [word-spacing:normal]`;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Build the email-safe table wrapper around highlighted code. Shared by the
|
|
57
|
+
* `<CodeBlock>` component and the Markdown fenced/indented code-block
|
|
58
|
+
* rules so both render identical markup: a full-width table whose
|
|
59
|
+
* cell carries the theme background, wrapping a `<pre>` styled
|
|
60
|
+
* with utility classes (not Shiki's raw inline styles).
|
|
61
|
+
*/
|
|
62
|
+
function buildCodeBlock(codeContent, bg, options = {}) {
|
|
63
|
+
const preClass = options.preClass ?? codeBlockPreClass(bg);
|
|
64
|
+
return `<table class="w-full"><tr><td class="${options.tdClass ?? `bg-[${bg}] max-w-0 mso-padding-alt-4`}"><pre class="${preClass}"${options.styleAttr ?? ""} data-juice-important><code>${codeContent}</code></pre></td></tr></table>`;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Re-wrap a Shiki (or plain markdown-it) `<pre><code>` block as a CodeBlock,
|
|
68
|
+
* pulling the inner code and the theme background out of the highlighted
|
|
69
|
+
* HTML. Falls back to a white background for unhighlighted blocks.
|
|
70
|
+
*/
|
|
71
|
+
function shikiToCodeBlock(highlighted) {
|
|
72
|
+
const bg = highlighted.match(/background-color:\s*(#[0-9a-fA-F]+)/)?.[1] ?? "#fff";
|
|
73
|
+
return buildCodeBlock(highlighted.trim().replace(/^<pre[^>]*><code[^>]*>/, "").replace(/<\/code><\/pre>$/, ""), bg);
|
|
74
|
+
}
|
|
47
75
|
//#endregion
|
|
48
|
-
export { hasHeightInStyle, hasHeightUtility, hasWidthInStyle, hasWidthUtility, nextId, normalizeToPixels, outlookFallbackProp };
|
|
76
|
+
export { buildCodeBlock, codeBlockPreClass, hasHeightInStyle, hasHeightUtility, hasWidthInStyle, hasWidthUtility, nextId, normalizeToPixels, outlookFallbackProp, shikiToCodeBlock };
|
|
49
77
|
|
|
50
78
|
//# sourceMappingURL=utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","names":[],"sources":["../../src/components/utils.ts"],"sourcesContent":["export function normalizeToPixels(value: string | number): string {\n if (typeof value === 'number' || Number.isFinite(Number(value))) {\n return `${value}px`\n }\n return value\n}\n\nconst counters: Record<string, number> = {}\n\n/**\n * Module-scoped sequential ID generator. Used by components to mint\n * unique marker ids (e.g. `c1`, `c2`) for the post-render transformer.\n *\n * Must live here (not inside `<script setup>`) because Vue compiles\n * `<script setup>` into the component's `setup()` function — any\n * `let counter = 0` there resets per instance, causing id collisions.\n */\nexport function nextId(prefix: string): string {\n counters[prefix] = (counters[prefix] ?? 0) + 1\n return `${prefix}${counters[prefix]}`\n}\n\nexport function hasWidthUtility(classStr: string): boolean {\n return classStr.split(/\\s+/).some((c) => {\n const utility = c.split(':').pop() ?? ''\n const clean = utility.replace(/^!/, '')\n return /^(w-|max-w-|min-w-)/.test(clean)\n })\n}\n\nexport function hasWidthInStyle(styleStr: string): boolean {\n return /(?:^|;\\s*)(?:max-width|width)\\s*:/i.test(styleStr)\n}\n\nexport function hasHeightUtility(classStr: string): boolean {\n return classStr.split(/\\s+/).some((c) => {\n const utility = c.split(':').pop() ?? ''\n const clean = utility.replace(/^!/, '')\n return /^(h-|max-h-|min-h-)/.test(clean)\n })\n}\n\nexport function hasHeightInStyle(styleStr: string): boolean {\n return /(?:^|;\\s*)(?:max-height|height)\\s*:/i.test(styleStr)\n}\n\n/**\n * Shared prop for components that emit MSO/VML fallback markup. The\n * `null` default acts as the \"unset\" sentinel — `useOutlookFallback`\n * treats `null` as inherit-from-ancestor (root default `true`),\n * letting users override per-component without losing inheritance.\n */\nexport const outlookFallbackProp = {\n type: Boolean,\n default: null,\n} as const\n\n"],"mappings":";AAAA,SAAgB,kBAAkB,OAAgC;CAChE,IAAI,OAAO,UAAU,YAAY,OAAO,SAAS,OAAO,KAAK,CAAC,GAC5D,OAAO,GAAG,MAAM;CAElB,OAAO;AACT;AAEA,MAAM,WAAmC,CAAC;;;;;;;;;AAU1C,SAAgB,OAAO,QAAwB;CAC7C,SAAS,WAAW,SAAS,WAAW,KAAK;CAC7C,OAAO,GAAG,SAAS,SAAS;AAC9B;AAEA,SAAgB,gBAAgB,UAA2B;CACzD,OAAO,SAAS,MAAM,KAAK,
|
|
1
|
+
{"version":3,"file":"utils.js","names":[],"sources":["../../src/components/utils.ts"],"sourcesContent":["export function normalizeToPixels(value: string | number): string {\n if (typeof value === 'number' || Number.isFinite(Number(value))) {\n return `${value}px`\n }\n return value\n}\n\nconst counters: Record<string, number> = {}\n\n/**\n * Module-scoped sequential ID generator. Used by components to mint\n * unique marker ids (e.g. `c1`, `c2`) for the post-render transformer.\n *\n * Must live here (not inside `<script setup>`) because Vue compiles\n * `<script setup>` into the component's `setup()` function — any\n * `let counter = 0` there resets per instance, causing id collisions.\n */\nexport function nextId(prefix: string): string {\n counters[prefix] = (counters[prefix] ?? 0) + 1\n return `${prefix}${counters[prefix]}`\n}\n\nexport function hasWidthUtility(classStr: string): boolean {\n return classStr.split(/\\s+/).some((c) => {\n const utility = c.split(':').pop() ?? ''\n const clean = utility.replace(/^!/, '')\n return /^(w-|max-w-|min-w-)/.test(clean)\n })\n}\n\nexport function hasWidthInStyle(styleStr: string): boolean {\n return /(?:^|;\\s*)(?:max-width|width)\\s*:/i.test(styleStr)\n}\n\nexport function hasHeightUtility(classStr: string): boolean {\n return classStr.split(/\\s+/).some((c) => {\n const utility = c.split(':').pop() ?? ''\n const clean = utility.replace(/^!/, '')\n return /^(h-|max-h-|min-h-)/.test(clean)\n })\n}\n\nexport function hasHeightInStyle(styleStr: string): boolean {\n return /(?:^|;\\s*)(?:max-height|height)\\s*:/i.test(styleStr)\n}\n\n/**\n * Shared prop for components that emit MSO/VML fallback markup. The\n * `null` default acts as the \"unset\" sentinel — `useOutlookFallback`\n * treats `null` as inherit-from-ancestor (root default `true`),\n * letting users override per-component without losing inheritance.\n */\nexport const outlookFallbackProp = {\n type: Boolean,\n default: null,\n} as const\n\n/**\n * Default utility classes for a code-block `<pre>`. `whitespace-pre!` is\n * forced important so Gmail's stylesheet can't reset it to `normal`, and\n * `mb-0` strips the browser's default `<pre>` bottom margin.\n */\nexport function codeBlockPreClass(bg: string): string {\n return `font-mono bg-[${bg}] p-4 mb-0 overflow-auto whitespace-pre! [word-wrap:normal] [word-break:normal] [word-spacing:normal]`\n}\n\n/**\n * Build the email-safe table wrapper around highlighted code. Shared by the\n * `<CodeBlock>` component and the Markdown fenced/indented code-block\n * rules so both render identical markup: a full-width table whose\n * cell carries the theme background, wrapping a `<pre>` styled\n * with utility classes (not Shiki's raw inline styles).\n */\nexport function buildCodeBlock(\n codeContent: string,\n bg: string,\n options: { preClass?: string; tdClass?: string; styleAttr?: string } = {},\n): string {\n const preClass = options.preClass ?? codeBlockPreClass(bg)\n const tdClass = options.tdClass ?? `bg-[${bg}] max-w-0 mso-padding-alt-4`\n const styleAttr = options.styleAttr ?? ''\n\n // `data-juice-important` tells the CSS inliner to keep `!important` on this\n // element's inlined declarations (e.g. `white-space: pre !important`), which\n // it strips by default. Juice removes the attribute from the output.\n return `<table class=\"w-full\"><tr><td class=\"${tdClass}\"><pre class=\"${preClass}\"${styleAttr} data-juice-important><code>${codeContent}</code></pre></td></tr></table>`\n}\n\n/**\n * Re-wrap a Shiki (or plain markdown-it) `<pre><code>` block as a CodeBlock,\n * pulling the inner code and the theme background out of the highlighted\n * HTML. Falls back to a white background for unhighlighted blocks.\n */\nexport function shikiToCodeBlock(highlighted: string): string {\n const bg = highlighted.match(/background-color:\\s*(#[0-9a-fA-F]+)/)?.[1] ?? '#fff'\n const codeContent = highlighted\n .trim()\n .replace(/^<pre[^>]*><code[^>]*>/, '')\n .replace(/<\\/code><\\/pre>$/, '')\n\n return buildCodeBlock(codeContent, bg)\n}\n\n"],"mappings":";AAAA,SAAgB,kBAAkB,OAAgC;CAChE,IAAI,OAAO,UAAU,YAAY,OAAO,SAAS,OAAO,KAAK,CAAC,GAC5D,OAAO,GAAG,MAAM;CAElB,OAAO;AACT;AAEA,MAAM,WAAmC,CAAC;;;;;;;;;AAU1C,SAAgB,OAAO,QAAwB;CAC7C,SAAS,WAAW,SAAS,WAAW,KAAK;CAC7C,OAAO,GAAG,SAAS,SAAS;AAC9B;AAEA,SAAgB,gBAAgB,UAA2B;CACzD,OAAO,SAAS,MAAM,KAAK,CAAC,CAAC,MAAM,MAAM;EAEvC,MAAM,SADU,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,GAAA,CAChB,QAAQ,MAAM,EAAE;EACtC,OAAO,sBAAsB,KAAK,KAAK;CACzC,CAAC;AACH;AAEA,SAAgB,gBAAgB,UAA2B;CACzD,OAAO,qCAAqC,KAAK,QAAQ;AAC3D;AAEA,SAAgB,iBAAiB,UAA2B;CAC1D,OAAO,SAAS,MAAM,KAAK,CAAC,CAAC,MAAM,MAAM;EAEvC,MAAM,SADU,EAAE,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,GAAA,CAChB,QAAQ,MAAM,EAAE;EACtC,OAAO,sBAAsB,KAAK,KAAK;CACzC,CAAC;AACH;AAEA,SAAgB,iBAAiB,UAA2B;CAC1D,OAAO,uCAAuC,KAAK,QAAQ;AAC7D;;;;;;;AAQA,MAAa,sBAAsB;CACjC,MAAM;CACN,SAAS;AACX;;;;;;AAOA,SAAgB,kBAAkB,IAAoB;CACpD,OAAO,iBAAiB,GAAG;AAC7B;;;;;;;;AASA,SAAgB,eACd,aACA,IACA,UAAuE,CAAC,GAChE;CACR,MAAM,WAAW,QAAQ,YAAY,kBAAkB,EAAE;CAOzD,OAAO,wCANS,QAAQ,WAAW,OAAO,GAAG,6BAMU,gBAAgB,SAAS,GAL9D,QAAQ,aAAa,GAKsD,8BAA8B,YAAY;AACzI;;;;;;AAOA,SAAgB,iBAAiB,aAA6B;CAC5D,MAAM,KAAK,YAAY,MAAM,qCAAqC,CAAC,GAAG,MAAM;CAM5E,OAAO,eALa,YACjB,KAAK,CAAC,CACN,QAAQ,0BAA0B,EAAE,CAAC,CACrC,QAAQ,oBAAoB,EAEC,GAAG,EAAE;AACvC"}
|
package/dist/components/utils.ts
CHANGED
|
@@ -55,3 +55,49 @@ export const outlookFallbackProp = {
|
|
|
55
55
|
default: null,
|
|
56
56
|
} as const
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Default utility classes for a code-block `<pre>`. `whitespace-pre!` is
|
|
60
|
+
* forced important so Gmail's stylesheet can't reset it to `normal`, and
|
|
61
|
+
* `mb-0` strips the browser's default `<pre>` bottom margin.
|
|
62
|
+
*/
|
|
63
|
+
export function codeBlockPreClass(bg: string): string {
|
|
64
|
+
return `font-mono bg-[${bg}] p-4 mb-0 overflow-auto whitespace-pre! [word-wrap:normal] [word-break:normal] [word-spacing:normal]`
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Build the email-safe table wrapper around highlighted code. Shared by the
|
|
69
|
+
* `<CodeBlock>` component and the Markdown fenced/indented code-block
|
|
70
|
+
* rules so both render identical markup: a full-width table whose
|
|
71
|
+
* cell carries the theme background, wrapping a `<pre>` styled
|
|
72
|
+
* with utility classes (not Shiki's raw inline styles).
|
|
73
|
+
*/
|
|
74
|
+
export function buildCodeBlock(
|
|
75
|
+
codeContent: string,
|
|
76
|
+
bg: string,
|
|
77
|
+
options: { preClass?: string; tdClass?: string; styleAttr?: string } = {},
|
|
78
|
+
): string {
|
|
79
|
+
const preClass = options.preClass ?? codeBlockPreClass(bg)
|
|
80
|
+
const tdClass = options.tdClass ?? `bg-[${bg}] max-w-0 mso-padding-alt-4`
|
|
81
|
+
const styleAttr = options.styleAttr ?? ''
|
|
82
|
+
|
|
83
|
+
// `data-juice-important` tells the CSS inliner to keep `!important` on this
|
|
84
|
+
// element's inlined declarations (e.g. `white-space: pre !important`), which
|
|
85
|
+
// it strips by default. Juice removes the attribute from the output.
|
|
86
|
+
return `<table class="w-full"><tr><td class="${tdClass}"><pre class="${preClass}"${styleAttr} data-juice-important><code>${codeContent}</code></pre></td></tr></table>`
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Re-wrap a Shiki (or plain markdown-it) `<pre><code>` block as a CodeBlock,
|
|
91
|
+
* pulling the inner code and the theme background out of the highlighted
|
|
92
|
+
* HTML. Falls back to a white background for unhighlighted blocks.
|
|
93
|
+
*/
|
|
94
|
+
export function shikiToCodeBlock(highlighted: string): string {
|
|
95
|
+
const bg = highlighted.match(/background-color:\s*(#[0-9a-fA-F]+)/)?.[1] ?? '#fff'
|
|
96
|
+
const codeContent = highlighted
|
|
97
|
+
.trim()
|
|
98
|
+
.replace(/^<pre[^>]*><code[^>]*>/, '')
|
|
99
|
+
.replace(/<\/code><\/pre>$/, '')
|
|
100
|
+
|
|
101
|
+
return buildCodeBlock(codeContent, bg)
|
|
102
|
+
}
|
|
103
|
+
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderContext.d.ts","names":[],"sources":["../../src/composables/renderContext.ts"],"mappings":";;;;;;UAKiB,gBAAA;EACf,MAAA;EACA,IAAA;EACA,WAAA;EACA,GAAA;AAAA;AAAA,UAGe,aAAA;EACf,EAAA;EANA;EAQA,GAAG;AAAA;AAAA,UAGY,aAAA;EACf,OAAA;EACA,SAAA;IAAc,IAAA;IAAc,WAAA;EAAA;EAC5B,SAAA,GAAY,aAAA;EACZ,gBAAA,EAAkB,KAAA;IAAQ,IAAA,EAAM,SAAA;IAAW,OAAA,EAAS,QAAA,CAAS,SAAA;EAAA;EAC7D,SAAA,GAAY,mBAAA;EACZ,KAAA,GAAQ,gBAAA;EACR,cAAA,GAAiB,aAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"renderContext.d.ts","names":[],"sources":["../../src/composables/renderContext.ts"],"mappings":";;;;;;UAKiB,gBAAA;EACf,MAAA;EACA,IAAA;EACA,WAAA;EACA,GAAA;AAAA;AAAA,UAGe,aAAA;EACf,EAAA;EANA;EAQA,GAAG;AAAA;AAAA,UAGY,aAAA;EACf,OAAA;EACA,SAAA;IAAc,IAAA;IAAc,WAAA;EAAA;EAC5B,SAAA,GAAY,aAAA;EACZ,gBAAA,EAAkB,KAAA;IAAQ,IAAA,EAAM,SAAA;IAAW,OAAA,EAAS,QAAA,CAAS,SAAA;EAAA;EAC7D,SAAA,GAAY,mBAAA;EACZ,UAAA;EACA,KAAA,GAAQ,gBAAA;EACR,cAAA,GAAiB,aAAA;AAAA;AAAA,cAIN,gBAAA,EAAkB,YAAY,CAAC,aAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderContext.js","names":[],"sources":["../../src/composables/renderContext.ts"],"sourcesContent":["import type { InjectionKey } from 'vue'\nimport type { MaizzleConfig } from '../types/index.ts'\nimport type { EventName, EventMap } from '../events/index.ts'\nimport type { UsePlaintextOptions } from './usePlaintext.ts'\n\nexport interface FontRegistration {\n family: string\n slug: string\n declaration: string\n url: string\n}\n\nexport interface TailwindBlock {\n id: string\n /** Optional raw CSS from the component's `#config` slot. */\n css?: string\n}\n\nexport interface RenderContext {\n doctype?: string\n preheader?: { text: string; fillerCount: number }\n sfcConfig?: MaizzleConfig\n sfcEventHandlers: Array<{ name: EventName; handler: EventMap[EventName] }>\n plaintext?: UsePlaintextOptions\n fonts?: FontRegistration[]\n tailwindBlocks?: TailwindBlock[]\n}\n\nexport const RenderContextKey: InjectionKey<RenderContext> = Symbol('
|
|
1
|
+
{"version":3,"file":"renderContext.js","names":[],"sources":["../../src/composables/renderContext.ts"],"sourcesContent":["import type { InjectionKey } from 'vue'\nimport type { MaizzleConfig } from '../types/index.ts'\nimport type { EventName, EventMap } from '../events/index.ts'\nimport type { UsePlaintextOptions } from './usePlaintext.ts'\n\nexport interface FontRegistration {\n family: string\n slug: string\n declaration: string\n url: string\n}\n\nexport interface TailwindBlock {\n id: string\n /** Optional raw CSS from the component's `#config` slot. */\n css?: string\n}\n\nexport interface RenderContext {\n doctype?: string\n preheader?: { text: string; fillerCount: number }\n sfcConfig?: MaizzleConfig\n sfcEventHandlers: Array<{ name: EventName; handler: EventMap[EventName] }>\n plaintext?: UsePlaintextOptions\n outputPath?: string\n fonts?: FontRegistration[]\n tailwindBlocks?: TailwindBlock[]\n}\n\n// Global symbol registry — same rationale as MaizzleConfigKey in useConfig.ts.\nexport const RenderContextKey: InjectionKey<RenderContext> = Symbol.for('maizzle.renderContext')\n"],"mappings":";AA8BA,MAAa,mBAAgD,OAAO,IAAI,uBAAuB"}
|
|
@@ -2,6 +2,13 @@ import { MaizzleConfig } from "../types/config.js";
|
|
|
2
2
|
import { InjectionKey } from "vue";
|
|
3
3
|
|
|
4
4
|
//#region src/composables/useConfig.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Use the global symbol registry so the key is identical across every
|
|
7
|
+
* module instance. In dev, `render()` (Node) and the SFC's auto-imported
|
|
8
|
+
* composables can resolve to two separate instances of this module; a plain
|
|
9
|
+
* `Symbol()` would differ between them, so `app.provide()` and the SFC's
|
|
10
|
+
* `inject()` would miss each other and `useConfig()` would throw.
|
|
11
|
+
*/
|
|
5
12
|
declare const MaizzleConfigKey: InjectionKey<MaizzleConfig>;
|
|
6
13
|
declare function useConfig(): MaizzleConfig;
|
|
7
14
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useConfig.d.ts","names":[],"sources":["../../src/composables/useConfig.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"useConfig.d.ts","names":[],"sources":["../../src/composables/useConfig.ts"],"mappings":";;;;;;;AAWA;;;;cAAa,gBAAA,EAAkB,YAAY,CAAC,aAAA;AAAA,iBAE5B,SAAA,IAAa,aAAa"}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { inject } from "vue";
|
|
2
2
|
//#region src/composables/useConfig.ts
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Use the global symbol registry so the key is identical across every
|
|
5
|
+
* module instance. In dev, `render()` (Node) and the SFC's auto-imported
|
|
6
|
+
* composables can resolve to two separate instances of this module; a plain
|
|
7
|
+
* `Symbol()` would differ between them, so `app.provide()` and the SFC's
|
|
8
|
+
* `inject()` would miss each other and `useConfig()` would throw.
|
|
9
|
+
*/
|
|
10
|
+
const MaizzleConfigKey = Symbol.for("maizzle.config");
|
|
4
11
|
function useConfig() {
|
|
5
12
|
const config = inject(MaizzleConfigKey);
|
|
6
13
|
if (!config) throw new Error("useConfig() requires the Maizzle plugin to provide config. Make sure you are using it inside a Maizzle template.");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useConfig.js","names":[],"sources":["../../src/composables/useConfig.ts"],"sourcesContent":["import { inject } from 'vue'\nimport type { InjectionKey } from 'vue'\nimport type { MaizzleConfig } from '../types/index.ts'\n\nexport const MaizzleConfigKey: InjectionKey<MaizzleConfig> = Symbol('
|
|
1
|
+
{"version":3,"file":"useConfig.js","names":[],"sources":["../../src/composables/useConfig.ts"],"sourcesContent":["import { inject } from 'vue'\nimport type { InjectionKey } from 'vue'\nimport type { MaizzleConfig } from '../types/index.ts'\n\n/**\n * Use the global symbol registry so the key is identical across every\n * module instance. In dev, `render()` (Node) and the SFC's auto-imported\n * composables can resolve to two separate instances of this module; a plain\n * `Symbol()` would differ between them, so `app.provide()` and the SFC's\n * `inject()` would miss each other and `useConfig()` would throw.\n */\nexport const MaizzleConfigKey: InjectionKey<MaizzleConfig> = Symbol.for('maizzle.config')\n\nexport function useConfig(): MaizzleConfig {\n const config = inject(MaizzleConfigKey)\n\n if (!config) {\n throw new Error('useConfig() requires the Maizzle plugin to provide config. Make sure you are using it inside a Maizzle template.')\n }\n\n return config\n}\n"],"mappings":";;;;;;;;;AAWA,MAAa,mBAAgD,OAAO,IAAI,gBAAgB;AAExF,SAAgB,YAA2B;CACzC,MAAM,SAAS,OAAO,gBAAgB;CAEtC,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,kHAAkH;CAGpI,OAAO;AACT"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCurrentTemplate.d.ts","names":[],"sources":["../../src/composables/useCurrentTemplate.ts"],"mappings":";;;;;AAmBA;;iBAAgB,mBAAA,CAAoB,MAA8B,EAAtB,UAAU;;AAAY;AAuBlE;;;;AAAgD;;;;;;;;;;;;;iBAAhC,kBAAA,
|
|
1
|
+
{"version":3,"file":"useCurrentTemplate.d.ts","names":[],"sources":["../../src/composables/useCurrentTemplate.ts"],"mappings":";;;;;AAmBA;;iBAAgB,mBAAA,CAAoB,MAA8B,EAAtB,UAAU;;AAAY;AAuBlE;;;;AAAgD;;;;;;;;;;;;;iBAAhC,kBAAA,IAAsB,UAAU"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useEvent.d.ts","names":[],"sources":["../../src/composables/useEvent.ts"],"mappings":";;;;;AAcA;;;;;;;;iBAAgB,QAAA,WAAmB,SAAA,
|
|
1
|
+
{"version":3,"file":"useEvent.d.ts","names":[],"sources":["../../src/composables/useEvent.ts"],"mappings":";;;;;AAcA;;;;;;;;iBAAgB,QAAA,WAAmB,SAAA,EAAW,IAAA,EAAM,CAAA,EAAG,OAAA,EAAS,QAAA,CAAS,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFont.js","names":[],"sources":["../../src/composables/useFont.ts"],"sourcesContent":["import { inject } from 'vue'\nimport { RenderContextKey } from './renderContext.ts'\n\ntype FontCategory = 'sans' | 'serif' | 'mono' | 'display' | 'handwriting'\n\nconst FAMILY_CATEGORIES: Record<string, FontCategory> = {\n // Sans-serif\n 'Roboto': 'sans',\n 'Open Sans': 'sans',\n 'Inter': 'sans',\n 'Lato': 'sans',\n 'Montserrat': 'sans',\n // Serif\n 'Merriweather': 'serif',\n 'Playfair Display': 'serif',\n 'Lora': 'serif',\n 'PT Serif': 'serif',\n 'Noto Serif': 'serif',\n // Display\n 'Oswald': 'display',\n 'Bebas Neue': 'display',\n 'Anton': 'display',\n 'Lobster': 'display',\n 'Pacifico': 'display',\n // Handwriting\n 'Dancing Script': 'handwriting',\n 'Caveat': 'handwriting',\n 'Shadows Into Light': 'handwriting',\n 'Satisfy': 'handwriting',\n 'Great Vibes': 'handwriting',\n // Monospace\n 'Roboto Mono': 'mono',\n 'Source Code Pro': 'mono',\n 'JetBrains Mono': 'mono',\n 'Fira Code': 'mono',\n 'Inconsolata': 'mono',\n}\n\nconst DEFAULT_FALLBACKS: Record<FontCategory, string> = {\n sans: 'ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif',\n serif: 'ui-serif, Georgia, Cambria, \"Times New Roman\", Times, serif',\n mono: 'ui-monospace, Menlo, Consolas, monospace',\n display: 'Impact, \"Arial Black\", system-ui, sans-serif',\n handwriting: '\"Segoe Script\", \"Brush Script MT\", cursive',\n}\n\nexport type FontProvider = 'google' | 'bunny'\n\nexport interface UseFontOptions {\n /**\n * A single font family name, e.g. `\"Roboto\"` or `\"Open Sans\"`.\n *\n * For fallback fonts, use the `fallback` option instead of a\n * comma-separated list here.\n */\n family: string\n /** CSS fallback list appended to the `font-family` declaration. */\n fallback?: string\n /**\n * Font provider used to build the stylesheet URL when `url` is omitted.\n * Bunny Fonts is a drop-in, privacy-friendly Google Fonts mirror.\n * @default 'google'\n */\n provider?: FontProvider\n /**\n * Stylesheet URL. When provided, used as-is for the `<link href>`.\n * When omitted, a URL is built from `provider`, `family`, `weights`,\n * `display` and `styles`.\n */\n url?: string\n /** Font weights to load. Ignored when `url` is provided. */\n weights?: number[]\n /** `font-display` value. Ignored when `url` is provided. */\n display?: 'auto' | 'block' | 'swap' | 'fallback' | 'optional'\n /** Font styles to load. Ignored when `url` is provided. */\n styles?: Array<'normal' | 'italic'>\n}\n\nconst PROVIDER_BASE_URL: Record<FontProvider, string> = {\n google: 'https://fonts.googleapis.com/css2',\n bunny: 'https://fonts.bunny.net/css2',\n}\n\nfunction slugify(family: string): string {\n return family\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9-]/g, '')\n}\n\nfunction buildProviderUrl(opts: Required<Omit<UseFontOptions, 'url' | 'fallback'>>): string {\n const familyParam = opts.family.trim().replace(/\\s+/g, '+')\n const weights = [...opts.weights].sort((a, b) => a - b)\n const hasItalic = opts.styles.includes('italic')\n const hasNormal = opts.styles.includes('normal')\n\n const axis = hasItalic\n ? `:ital,wght@${weights.flatMap(w => [\n ...(hasNormal ? [`0,${w}`] : []),\n `1,${w}`,\n ]).join(';')}`\n : `:wght@${weights.join(';')}`\n\n return `${PROVIDER_BASE_URL[opts.provider]}?family=${familyParam}${axis}&display=${opts.display}`\n}\n\n/**\n * Register a font for the current email template.\n *\n * Builds a Google Fonts stylesheet URL from `family`/`weights`/`display`/`styles`\n * (or uses `url` as-is). The renderer injects a `<link>` tag into `<head>`\n * and merges `--font-{slug}` declarations into the template's existing\n * `@import \"tailwindcss\"` style block so a `font-{slug}` utility class\n * is generated. If no Tailwind import is found, falls back to a `:root`\n * declaration so the CSS variable is still available.\n *\n * Usage in SFC <script setup>:\n * ```ts\n * useFont({ family: 'Roboto', fallback: 'Verdana, sans-serif', weights: [400, 600] })\n * ```\n */\nexport function useFont(options: UseFontOptions): void {\n const ctx = inject(RenderContextKey)\n if (!ctx) return\n\n ctx.fonts = ctx.fonts ?? []\n if (ctx.fonts.some(f => f.family === options.family)) return\n\n const url = options.url ?? buildProviderUrl({\n family: options.family,\n provider: options.provider ?? 'google',\n weights: options.weights ?? [400],\n display: options.display ?? 'swap',\n styles: options.styles ?? ['normal'],\n })\n\n const fallback = options.fallback\n ?? DEFAULT_FALLBACKS[FAMILY_CATEGORIES[options.family] ?? 'sans']\n const quoted = /\\s/.test(options.family) ? `\"${options.family}\"` : options.family\n const declaration = `${quoted}, ${fallback}`\n\n ctx.fonts.push({\n family: options.family,\n slug: slugify(options.family),\n declaration,\n url,\n })\n}\n"],"mappings":";;;AAKA,MAAM,oBAAkD;CAEtD,UAAU;CACV,aAAa;CACb,SAAS;CACT,QAAQ;CACR,cAAc;CAEd,gBAAgB;CAChB,oBAAoB;CACpB,QAAQ;CACR,YAAY;CACZ,cAAc;CAEd,UAAU;CACV,cAAc;CACd,SAAS;CACT,WAAW;CACX,YAAY;CAEZ,kBAAkB;CAClB,UAAU;CACV,sBAAsB;CACtB,WAAW;CACX,eAAe;CAEf,eAAe;CACf,mBAAmB;CACnB,kBAAkB;CAClB,aAAa;CACb,eAAe;AACjB;AAEA,MAAM,oBAAkD;CACtD,MAAM;CACN,OAAO;CACP,MAAM;CACN,SAAS;CACT,aAAa;AACf;AAkCA,MAAM,oBAAkD;CACtD,QAAQ;CACR,OAAO;AACT;AAEA,SAAS,QAAQ,QAAwB;CACvC,OAAO,OACJ,KAAK,
|
|
1
|
+
{"version":3,"file":"useFont.js","names":[],"sources":["../../src/composables/useFont.ts"],"sourcesContent":["import { inject } from 'vue'\nimport { RenderContextKey } from './renderContext.ts'\n\ntype FontCategory = 'sans' | 'serif' | 'mono' | 'display' | 'handwriting'\n\nconst FAMILY_CATEGORIES: Record<string, FontCategory> = {\n // Sans-serif\n 'Roboto': 'sans',\n 'Open Sans': 'sans',\n 'Inter': 'sans',\n 'Lato': 'sans',\n 'Montserrat': 'sans',\n // Serif\n 'Merriweather': 'serif',\n 'Playfair Display': 'serif',\n 'Lora': 'serif',\n 'PT Serif': 'serif',\n 'Noto Serif': 'serif',\n // Display\n 'Oswald': 'display',\n 'Bebas Neue': 'display',\n 'Anton': 'display',\n 'Lobster': 'display',\n 'Pacifico': 'display',\n // Handwriting\n 'Dancing Script': 'handwriting',\n 'Caveat': 'handwriting',\n 'Shadows Into Light': 'handwriting',\n 'Satisfy': 'handwriting',\n 'Great Vibes': 'handwriting',\n // Monospace\n 'Roboto Mono': 'mono',\n 'Source Code Pro': 'mono',\n 'JetBrains Mono': 'mono',\n 'Fira Code': 'mono',\n 'Inconsolata': 'mono',\n}\n\nconst DEFAULT_FALLBACKS: Record<FontCategory, string> = {\n sans: 'ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif',\n serif: 'ui-serif, Georgia, Cambria, \"Times New Roman\", Times, serif',\n mono: 'ui-monospace, Menlo, Consolas, monospace',\n display: 'Impact, \"Arial Black\", system-ui, sans-serif',\n handwriting: '\"Segoe Script\", \"Brush Script MT\", cursive',\n}\n\nexport type FontProvider = 'google' | 'bunny'\n\nexport interface UseFontOptions {\n /**\n * A single font family name, e.g. `\"Roboto\"` or `\"Open Sans\"`.\n *\n * For fallback fonts, use the `fallback` option instead of a\n * comma-separated list here.\n */\n family: string\n /** CSS fallback list appended to the `font-family` declaration. */\n fallback?: string\n /**\n * Font provider used to build the stylesheet URL when `url` is omitted.\n * Bunny Fonts is a drop-in, privacy-friendly Google Fonts mirror.\n * @default 'google'\n */\n provider?: FontProvider\n /**\n * Stylesheet URL. When provided, used as-is for the `<link href>`.\n * When omitted, a URL is built from `provider`, `family`, `weights`,\n * `display` and `styles`.\n */\n url?: string\n /** Font weights to load. Ignored when `url` is provided. */\n weights?: number[]\n /** `font-display` value. Ignored when `url` is provided. */\n display?: 'auto' | 'block' | 'swap' | 'fallback' | 'optional'\n /** Font styles to load. Ignored when `url` is provided. */\n styles?: Array<'normal' | 'italic'>\n}\n\nconst PROVIDER_BASE_URL: Record<FontProvider, string> = {\n google: 'https://fonts.googleapis.com/css2',\n bunny: 'https://fonts.bunny.net/css2',\n}\n\nfunction slugify(family: string): string {\n return family\n .trim()\n .toLowerCase()\n .replace(/\\s+/g, '-')\n .replace(/[^a-z0-9-]/g, '')\n}\n\nfunction buildProviderUrl(opts: Required<Omit<UseFontOptions, 'url' | 'fallback'>>): string {\n const familyParam = opts.family.trim().replace(/\\s+/g, '+')\n const weights = [...opts.weights].sort((a, b) => a - b)\n const hasItalic = opts.styles.includes('italic')\n const hasNormal = opts.styles.includes('normal')\n\n const axis = hasItalic\n ? `:ital,wght@${weights.flatMap(w => [\n ...(hasNormal ? [`0,${w}`] : []),\n `1,${w}`,\n ]).join(';')}`\n : `:wght@${weights.join(';')}`\n\n return `${PROVIDER_BASE_URL[opts.provider]}?family=${familyParam}${axis}&display=${opts.display}`\n}\n\n/**\n * Register a font for the current email template.\n *\n * Builds a Google Fonts stylesheet URL from `family`/`weights`/`display`/`styles`\n * (or uses `url` as-is). The renderer injects a `<link>` tag into `<head>`\n * and merges `--font-{slug}` declarations into the template's existing\n * `@import \"tailwindcss\"` style block so a `font-{slug}` utility class\n * is generated. If no Tailwind import is found, falls back to a `:root`\n * declaration so the CSS variable is still available.\n *\n * Usage in SFC <script setup>:\n * ```ts\n * useFont({ family: 'Roboto', fallback: 'Verdana, sans-serif', weights: [400, 600] })\n * ```\n */\nexport function useFont(options: UseFontOptions): void {\n const ctx = inject(RenderContextKey)\n if (!ctx) return\n\n ctx.fonts = ctx.fonts ?? []\n if (ctx.fonts.some(f => f.family === options.family)) return\n\n const url = options.url ?? buildProviderUrl({\n family: options.family,\n provider: options.provider ?? 'google',\n weights: options.weights ?? [400],\n display: options.display ?? 'swap',\n styles: options.styles ?? ['normal'],\n })\n\n const fallback = options.fallback\n ?? DEFAULT_FALLBACKS[FAMILY_CATEGORIES[options.family] ?? 'sans']\n const quoted = /\\s/.test(options.family) ? `\"${options.family}\"` : options.family\n const declaration = `${quoted}, ${fallback}`\n\n ctx.fonts.push({\n family: options.family,\n slug: slugify(options.family),\n declaration,\n url,\n })\n}\n"],"mappings":";;;AAKA,MAAM,oBAAkD;CAEtD,UAAU;CACV,aAAa;CACb,SAAS;CACT,QAAQ;CACR,cAAc;CAEd,gBAAgB;CAChB,oBAAoB;CACpB,QAAQ;CACR,YAAY;CACZ,cAAc;CAEd,UAAU;CACV,cAAc;CACd,SAAS;CACT,WAAW;CACX,YAAY;CAEZ,kBAAkB;CAClB,UAAU;CACV,sBAAsB;CACtB,WAAW;CACX,eAAe;CAEf,eAAe;CACf,mBAAmB;CACnB,kBAAkB;CAClB,aAAa;CACb,eAAe;AACjB;AAEA,MAAM,oBAAkD;CACtD,MAAM;CACN,OAAO;CACP,MAAM;CACN,SAAS;CACT,aAAa;AACf;AAkCA,MAAM,oBAAkD;CACtD,QAAQ;CACR,OAAO;AACT;AAEA,SAAS,QAAQ,QAAwB;CACvC,OAAO,OACJ,KAAK,CAAC,CACN,YAAY,CAAC,CACb,QAAQ,QAAQ,GAAG,CAAC,CACpB,QAAQ,eAAe,EAAE;AAC9B;AAEA,SAAS,iBAAiB,MAAkE;CAC1F,MAAM,cAAc,KAAK,OAAO,KAAK,CAAC,CAAC,QAAQ,QAAQ,GAAG;CAC1D,MAAM,UAAU,CAAC,GAAG,KAAK,OAAO,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CACtD,MAAM,YAAY,KAAK,OAAO,SAAS,QAAQ;CAC/C,MAAM,YAAY,KAAK,OAAO,SAAS,QAAQ;CAE/C,MAAM,OAAO,YACT,cAAc,QAAQ,SAAQ,MAAK,CACjC,GAAI,YAAY,CAAC,KAAK,GAAG,IAAI,CAAC,GAC9B,KAAK,GACP,CAAC,CAAC,CAAC,KAAK,GAAG,MACX,SAAS,QAAQ,KAAK,GAAG;CAE7B,OAAO,GAAG,kBAAkB,KAAK,UAAU,UAAU,cAAc,KAAK,WAAW,KAAK;AAC1F;;;;;;;;;;;;;;;;AAiBA,SAAgB,QAAQ,SAA+B;CACrD,MAAM,MAAM,OAAO,gBAAgB;CACnC,IAAI,CAAC,KAAK;CAEV,IAAI,QAAQ,IAAI,SAAS,CAAC;CAC1B,IAAI,IAAI,MAAM,MAAK,MAAK,EAAE,WAAW,QAAQ,MAAM,GAAG;CAEtD,MAAM,MAAM,QAAQ,OAAO,iBAAiB;EAC1C,QAAQ,QAAQ;EAChB,UAAU,QAAQ,YAAY;EAC9B,SAAS,QAAQ,WAAW,CAAC,GAAG;EAChC,SAAS,QAAQ,WAAW;EAC5B,QAAQ,QAAQ,UAAU,CAAC,QAAQ;CACrC,CAAC;CAED,MAAM,WAAW,QAAQ,YACpB,kBAAkB,kBAAkB,QAAQ,WAAW;CAE5D,MAAM,cAAc,GADL,KAAK,KAAK,QAAQ,MAAM,IAAI,IAAI,QAAQ,OAAO,KAAK,QAAQ,OAC7C,IAAI;CAElC,IAAI,MAAM,KAAK;EACb,QAAQ,QAAQ;EAChB,MAAM,QAAQ,QAAQ,MAAM;EAC5B;EACA;CACF,CAAC;AACH"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/composables/useOutputPath.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Override the output file path for the current template.
|
|
4
|
+
*
|
|
5
|
+
* The path is relative to the project root (cwd); it may be
|
|
6
|
+
* absolute or escape the output directory with `../`. If it
|
|
7
|
+
* has no extension, `output.extension` is appended.
|
|
8
|
+
*
|
|
9
|
+
* Usage in SFC <script setup>:
|
|
10
|
+
* ```ts
|
|
11
|
+
* useOutputPath('dist/promos/black-friday.html')
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
declare function useOutputPath(path: string): void;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { useOutputPath };
|
|
17
|
+
//# sourceMappingURL=useOutputPath.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useOutputPath.d.ts","names":[],"sources":["../../src/composables/useOutputPath.ts"],"mappings":";;AAeA;;;;AAA0C;;;;;;;iBAA1B,aAAA,CAAc,IAAY"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { RenderContextKey } from "./renderContext.js";
|
|
2
|
+
import { inject } from "vue";
|
|
3
|
+
//#region src/composables/useOutputPath.ts
|
|
4
|
+
/**
|
|
5
|
+
* Override the output file path for the current template.
|
|
6
|
+
*
|
|
7
|
+
* The path is relative to the project root (cwd); it may be
|
|
8
|
+
* absolute or escape the output directory with `../`. If it
|
|
9
|
+
* has no extension, `output.extension` is appended.
|
|
10
|
+
*
|
|
11
|
+
* Usage in SFC <script setup>:
|
|
12
|
+
* ```ts
|
|
13
|
+
* useOutputPath('dist/promos/black-friday.html')
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
function useOutputPath(path) {
|
|
17
|
+
const ctx = inject(RenderContextKey);
|
|
18
|
+
if (ctx) ctx.outputPath = path;
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { useOutputPath };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=useOutputPath.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useOutputPath.js","names":[],"sources":["../../src/composables/useOutputPath.ts"],"sourcesContent":["import { inject } from 'vue'\nimport { RenderContextKey } from './renderContext.ts'\n\n/**\n * Override the output file path for the current template.\n *\n * The path is relative to the project root (cwd); it may be\n * absolute or escape the output directory with `../`. If it\n * has no extension, `output.extension` is appended.\n *\n * Usage in SFC <script setup>:\n * ```ts\n * useOutputPath('dist/promos/black-friday.html')\n * ```\n */\nexport function useOutputPath(path: string): void {\n const ctx = inject(RenderContextKey)\n if (ctx) ctx.outputPath = path\n}\n"],"mappings":";;;;;;;;;;;;;;;AAeA,SAAgB,cAAc,MAAoB;CAChD,MAAM,MAAM,OAAO,gBAAgB;CACnC,IAAI,KAAK,IAAI,aAAa;AAC5B"}
|
package/dist/config/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/config/index.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { createJiti } from 'jiti'\nimport { fileURLToPath } from 'node:url'\nimport { createDefu } from 'defu'\n\n// defu that replaces arrays: if user provides content: ['x'], it replaces the default, not appends\nconst merge = createDefu((obj, key, value) => {\n if (Array.isArray(obj[key])) {\n obj[key] = value\n return true\n }\n})\nimport { defaults } from './defaults.ts'\nimport type { MaizzleConfig } from '../types/index.ts'\n\nexport { defineConfig } from '../composables/defineConfig.ts'\nexport { defaults } from './defaults.ts'\n\nconst CONFIG_FILES = [\n 'maizzle.config.ts',\n 'maizzle.config.js',\n]\n\n/**\n * Resolve the Maizzle config.\n *\n * Always loads from the config file on disk (maizzle.config.{ts,js}),\n * then merges the programmatic config on top, then fills in defaults.\n */\nexport async function resolveConfig(\n config?: Partial<MaizzleConfig> | string,\n cwd: string = process.cwd(),\n): Promise<MaizzleConfig> {\n // If a string path was provided, load that specific file\n const fileConfig = await loadConfig(\n typeof config === 'string' ? config : undefined,\n cwd,\n )\n\n // Programmatic config (object) overrides file config, which overrides defaults\n const programmaticConfig = typeof config === 'object' && config !== null ? config : {}\n\n const merged = merge(programmaticConfig, fileConfig, defaults) as MaizzleConfig\n\n // Check if root was explicitly provided before resolving\n const hasExplicitRoot = !!(programmaticConfig.root ?? fileConfig.root)\n\n // Resolve root to an absolute path (defaults to cwd)\n const root = resolve(cwd, merged.root ?? '.')\n merged.root = root\n\n // Resolve content patterns relative to root\n if (merged.content) {\n merged.content = merged.content.map(p => {\n // Skip already-absolute or negated patterns\n if (p.startsWith('/') || p.startsWith('!')) return p\n return resolve(root, p).replace(/\\\\/g, '/')\n })\n }\n\n // Resolve static source patterns relative to root\n if (merged.static?.source) {\n merged.static.source = merged.static.source.map(p => {\n if (p.startsWith('/') || p.startsWith('!')) return p\n return resolve(root, p).replace(/\\\\/g, '/')\n })\n }\n\n /**\n * Resolve components.source paths relative to cwd (not root), since extra\n * component dirs often live outside the root directory. String\n * entries → resolve in-place. Object entries → resolve\n * `path`, preserve `prefix`/`pathPrefix`.\n */\n if (merged.components?.source) {\n const dirs = Array.isArray(merged.components.source)\n ? merged.components.source\n : [merged.components.source]\n\n merged.components.source = dirs.map(entry => {\n if (typeof entry === 'string') {\n return entry.startsWith('/') ? entry : resolve(cwd, entry)\n }\n return {\n ...entry,\n path: entry.path.startsWith('/') ? entry.path : resolve(cwd, entry.path),\n }\n })\n }\n\n /**\n * Default css.base to root when root is explicitly set, so Tailwind resolves\n * @source from the right directory. When root is not set, leave\n * css.base undefined so Tailwind uses its own default (the\n * template file's directory).\n */\n if (hasExplicitRoot && !merged.css?.base) {\n if (!merged.css) merged.css = {}\n merged.css.base = root\n }\n\n return merged\n}\n\nasync function loadConfig(\n configPath?: string,\n cwd: string = process.cwd(),\n): Promise<MaizzleConfig> {\n const jiti = createJiti(fileURLToPath(import.meta.url), { moduleCache: false })\n\n // If an explicit path was provided, use it directly\n if (configPath) {\n const absolutePath = resolve(cwd, configPath)\n\n if (!existsSync(absolutePath)) {\n throw new Error(`Config file not found: ${absolutePath}`)\n }\n\n const mod = await jiti.import(absolutePath) as any\n return mod.default ?? mod\n }\n\n // Otherwise scan cwd for known config file names\n for (const filename of CONFIG_FILES) {\n const filepath = resolve(cwd, filename)\n\n if (existsSync(filepath)) {\n const mod = await jiti.import(filepath) as any\n return mod.default ?? mod\n }\n }\n\n // No config file found, return empty (defaults will be applied by resolveConfig)\n return {}\n}\n"],"mappings":";;;;;;;;AAOA,MAAM,QAAQ,YAAY,KAAK,KAAK,UAAU;CAC5C,IAAI,MAAM,QAAQ,IAAI,IAAI,GAAG;EAC3B,IAAI,OAAO;EACX,OAAO;CACT;AACF,CAAC;AAOD,MAAM,eAAe,CACnB,qBACA,mBACF;;;;;;;AAQA,eAAsB,cACpB,QACA,MAAc,QAAQ,IAAI,GACF;CAExB,MAAM,aAAa,MAAM,WACvB,OAAO,WAAW,WAAW,SAAS,KAAA,GACtC,GACF;CAGA,MAAM,qBAAqB,OAAO,WAAW,YAAY,WAAW,OAAO,SAAS,CAAC;CAErF,MAAM,SAAS,MAAM,oBAAoB,YAAY,QAAQ;CAG7D,MAAM,kBAAkB,CAAC,EAAE,mBAAmB,QAAQ,WAAW;CAGjE,MAAM,OAAO,QAAQ,KAAK,OAAO,QAAQ,GAAG;CAC5C,OAAO,OAAO;CAGd,IAAI,OAAO,SACT,OAAO,UAAU,OAAO,QAAQ,KAAI,MAAK;EAEvC,IAAI,EAAE,WAAW,GAAG,KAAK,EAAE,WAAW,GAAG,GAAG,OAAO;EACnD,OAAO,QAAQ,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/config/index.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { createJiti } from 'jiti'\nimport { fileURLToPath } from 'node:url'\nimport { createDefu } from 'defu'\n\n// defu that replaces arrays: if user provides content: ['x'], it replaces the default, not appends\nconst merge = createDefu((obj, key, value) => {\n if (Array.isArray(obj[key])) {\n obj[key] = value\n return true\n }\n})\nimport { defaults } from './defaults.ts'\nimport type { MaizzleConfig } from '../types/index.ts'\n\nexport { defineConfig } from '../composables/defineConfig.ts'\nexport { defaults } from './defaults.ts'\n\nconst CONFIG_FILES = [\n 'maizzle.config.ts',\n 'maizzle.config.js',\n]\n\n/**\n * Resolve the Maizzle config.\n *\n * Always loads from the config file on disk (maizzle.config.{ts,js}),\n * then merges the programmatic config on top, then fills in defaults.\n */\nexport async function resolveConfig(\n config?: Partial<MaizzleConfig> | string,\n cwd: string = process.cwd(),\n): Promise<MaizzleConfig> {\n // If a string path was provided, load that specific file\n const fileConfig = await loadConfig(\n typeof config === 'string' ? config : undefined,\n cwd,\n )\n\n // Programmatic config (object) overrides file config, which overrides defaults\n const programmaticConfig = typeof config === 'object' && config !== null ? config : {}\n\n const merged = merge(programmaticConfig, fileConfig, defaults) as MaizzleConfig\n\n // Check if root was explicitly provided before resolving\n const hasExplicitRoot = !!(programmaticConfig.root ?? fileConfig.root)\n\n // Resolve root to an absolute path (defaults to cwd)\n const root = resolve(cwd, merged.root ?? '.')\n merged.root = root\n\n // Resolve content patterns relative to root\n if (merged.content) {\n merged.content = merged.content.map(p => {\n // Skip already-absolute or negated patterns\n if (p.startsWith('/') || p.startsWith('!')) return p\n return resolve(root, p).replace(/\\\\/g, '/')\n })\n }\n\n // Resolve static source patterns relative to root\n if (merged.static?.source) {\n merged.static.source = merged.static.source.map(p => {\n if (p.startsWith('/') || p.startsWith('!')) return p\n return resolve(root, p).replace(/\\\\/g, '/')\n })\n }\n\n /**\n * Resolve components.source paths relative to cwd (not root), since extra\n * component dirs often live outside the root directory. String\n * entries → resolve in-place. Object entries → resolve\n * `path`, preserve `prefix`/`pathPrefix`.\n */\n if (merged.components?.source) {\n const dirs = Array.isArray(merged.components.source)\n ? merged.components.source\n : [merged.components.source]\n\n merged.components.source = dirs.map(entry => {\n if (typeof entry === 'string') {\n return entry.startsWith('/') ? entry : resolve(cwd, entry)\n }\n return {\n ...entry,\n path: entry.path.startsWith('/') ? entry.path : resolve(cwd, entry.path),\n }\n })\n }\n\n /**\n * Default css.base to root when root is explicitly set, so Tailwind resolves\n * @source from the right directory. When root is not set, leave\n * css.base undefined so Tailwind uses its own default (the\n * template file's directory).\n */\n if (hasExplicitRoot && !merged.css?.base) {\n if (!merged.css) merged.css = {}\n merged.css.base = root\n }\n\n return merged\n}\n\nasync function loadConfig(\n configPath?: string,\n cwd: string = process.cwd(),\n): Promise<MaizzleConfig> {\n const jiti = createJiti(fileURLToPath(import.meta.url), { moduleCache: false })\n\n // If an explicit path was provided, use it directly\n if (configPath) {\n const absolutePath = resolve(cwd, configPath)\n\n if (!existsSync(absolutePath)) {\n throw new Error(`Config file not found: ${absolutePath}`)\n }\n\n const mod = await jiti.import(absolutePath) as any\n return mod.default ?? mod\n }\n\n // Otherwise scan cwd for known config file names\n for (const filename of CONFIG_FILES) {\n const filepath = resolve(cwd, filename)\n\n if (existsSync(filepath)) {\n const mod = await jiti.import(filepath) as any\n return mod.default ?? mod\n }\n }\n\n // No config file found, return empty (defaults will be applied by resolveConfig)\n return {}\n}\n"],"mappings":";;;;;;;;AAOA,MAAM,QAAQ,YAAY,KAAK,KAAK,UAAU;CAC5C,IAAI,MAAM,QAAQ,IAAI,IAAI,GAAG;EAC3B,IAAI,OAAO;EACX,OAAO;CACT;AACF,CAAC;AAOD,MAAM,eAAe,CACnB,qBACA,mBACF;;;;;;;AAQA,eAAsB,cACpB,QACA,MAAc,QAAQ,IAAI,GACF;CAExB,MAAM,aAAa,MAAM,WACvB,OAAO,WAAW,WAAW,SAAS,KAAA,GACtC,GACF;CAGA,MAAM,qBAAqB,OAAO,WAAW,YAAY,WAAW,OAAO,SAAS,CAAC;CAErF,MAAM,SAAS,MAAM,oBAAoB,YAAY,QAAQ;CAG7D,MAAM,kBAAkB,CAAC,EAAE,mBAAmB,QAAQ,WAAW;CAGjE,MAAM,OAAO,QAAQ,KAAK,OAAO,QAAQ,GAAG;CAC5C,OAAO,OAAO;CAGd,IAAI,OAAO,SACT,OAAO,UAAU,OAAO,QAAQ,KAAI,MAAK;EAEvC,IAAI,EAAE,WAAW,GAAG,KAAK,EAAE,WAAW,GAAG,GAAG,OAAO;EACnD,OAAO,QAAQ,MAAM,CAAC,CAAC,CAAC,QAAQ,OAAO,GAAG;CAC5C,CAAC;CAIH,IAAI,OAAO,QAAQ,QACjB,OAAO,OAAO,SAAS,OAAO,OAAO,OAAO,KAAI,MAAK;EACnD,IAAI,EAAE,WAAW,GAAG,KAAK,EAAE,WAAW,GAAG,GAAG,OAAO;EACnD,OAAO,QAAQ,MAAM,CAAC,CAAC,CAAC,QAAQ,OAAO,GAAG;CAC5C,CAAC;;;;;;;CASH,IAAI,OAAO,YAAY,QAAQ;EAC7B,MAAM,OAAO,MAAM,QAAQ,OAAO,WAAW,MAAM,IAC/C,OAAO,WAAW,SAClB,CAAC,OAAO,WAAW,MAAM;EAE7B,OAAO,WAAW,SAAS,KAAK,KAAI,UAAS;GAC3C,IAAI,OAAO,UAAU,UACnB,OAAO,MAAM,WAAW,GAAG,IAAI,QAAQ,QAAQ,KAAK,KAAK;GAE3D,OAAO;IACL,GAAG;IACH,MAAM,MAAM,KAAK,WAAW,GAAG,IAAI,MAAM,OAAO,QAAQ,KAAK,MAAM,IAAI;GACzE;EACF,CAAC;CACH;;;;;;;CAQA,IAAI,mBAAmB,CAAC,OAAO,KAAK,MAAM;EACxC,IAAI,CAAC,OAAO,KAAK,OAAO,MAAM,CAAC;EAC/B,OAAO,IAAI,OAAO;CACpB;CAEA,OAAO;AACT;AAEA,eAAe,WACb,YACA,MAAc,QAAQ,IAAI,GACF;CACxB,MAAM,OAAO,WAAW,cAAc,OAAO,KAAK,GAAG,GAAG,EAAE,aAAa,MAAM,CAAC;CAG9E,IAAI,YAAY;EACd,MAAM,eAAe,QAAQ,KAAK,UAAU;EAE5C,IAAI,CAAC,WAAW,YAAY,GAC1B,MAAM,IAAI,MAAM,0BAA0B,cAAc;EAG1D,MAAM,MAAM,MAAM,KAAK,OAAO,YAAY;EAC1C,OAAO,IAAI,WAAW;CACxB;CAGA,KAAK,MAAM,YAAY,cAAc;EACnC,MAAM,WAAW,QAAQ,KAAK,QAAQ;EAEtC,IAAI,WAAW,QAAQ,GAAG;GACxB,MAAM,MAAM,MAAM,KAAK,OAAO,QAAQ;GACtC,OAAO,IAAI,WAAW;EACxB;CACF;CAGA,OAAO,CAAC;AACV"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/events/index.ts"],"mappings":";;;;KAGY,SAAA;;;AAAZ;;;UAOiB,YAAA;EACf,MAAA;EACA,IAAA,EAAM,UAAU;AAAA;AAAA,UAGD,QAAA;EACf,YAAA,GAAe,MAAA;IAAU,MAAA,EAAQ,aAAA;EAAA,aAA2B,OAAA;EAC5D,YAAA,GAAe,MAAA;IAAU,MAAA,EAAQ,aAAA;IAAe,QAAA,EAAU,YAAA;EAAA,sBAAmC,OAAA;EAC7F,WAAA,GAAc,MAAA;IAAU,MAAA,EAAQ,aAAA;IAAe,QAAA,EAAU,YAAA;IAAc,IAAA;EAAA,sBAAmC,OAAA;EAC1G,cAAA,GAAiB,MAAA;IAAU,MAAA,EAAQ,aAAA;IAAe,QAAA,EAAU,YAAA;IAAc,IAAA;EAAA,sBAAmC,OAAA;EAC7G,UAAA,GAAa,MAAA;IAAU,KAAA;IAAiB,MAAA,EAAQ,aAAA;EAAA,aAA2B,OAAA;AAAA;;;;;;;;cAUhE,YAAA;EAAA,QACH,QAAA;EAdyB;;;;;EAAA,QAoBzB,kBAAA;EAnBgB;;;EAwBxB,cAAA,CAAe,MAAA,EAAQ,aAAA;EAxBgD;;;EAuCvE,EAAA,WAAa,SAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/events/index.ts"],"mappings":";;;;KAGY,SAAA;;;AAAZ;;;UAOiB,YAAA;EACf,MAAA;EACA,IAAA,EAAM,UAAU;AAAA;AAAA,UAGD,QAAA;EACf,YAAA,GAAe,MAAA;IAAU,MAAA,EAAQ,aAAA;EAAA,aAA2B,OAAA;EAC5D,YAAA,GAAe,MAAA;IAAU,MAAA,EAAQ,aAAA;IAAe,QAAA,EAAU,YAAA;EAAA,sBAAmC,OAAA;EAC7F,WAAA,GAAc,MAAA;IAAU,MAAA,EAAQ,aAAA;IAAe,QAAA,EAAU,YAAA;IAAc,IAAA;EAAA,sBAAmC,OAAA;EAC1G,cAAA,GAAiB,MAAA;IAAU,MAAA,EAAQ,aAAA;IAAe,QAAA,EAAU,YAAA;IAAc,IAAA;EAAA,sBAAmC,OAAA;EAC7G,UAAA,GAAa,MAAA;IAAU,KAAA;IAAiB,MAAA,EAAQ,aAAA;EAAA,aAA2B,OAAA;AAAA;;;;;;;;cAUhE,YAAA;EAAA,QACH,QAAA;EAdyB;;;;;EAAA,QAoBzB,kBAAA;EAnBgB;;;EAwBxB,cAAA,CAAe,MAAA,EAAQ,aAAA;EAxBgD;;;EAuCvE,EAAA,WAAa,SAAA,EAAW,IAAA,EAAM,CAAA,EAAG,OAAA,EAAS,QAAA,CAAS,CAAA;EAtCxB;;;EAiDrB,gBAAA,CAAiB,MAAA;IAAU,MAAA,EAAQ,aAAA;EAAA,IAAe,OAAA;EAjDqD;;;;EA6DvG,gBAAA,CAAiB,MAAA;IAAU,MAAA,EAAQ,aAAA;IAAe,QAAA,EAAU,YAAA;EAAA,IAAiB,OAAA;EA5DD;AAUpF;;EAmEQ,eAAA,CAAgB,MAAA;IAAU,MAAA,EAAQ,aAAA;IAAe,QAAA,EAAU,YAAA;IAAc,IAAA;EAAA,IAAiB,OAAA;EAxC7C;;;EA2D7C,kBAAA,CAAmB,MAAA;IAAU,MAAA,EAAQ,aAAA;IAAe,QAAA,EAAU,YAAA;IAAc,IAAA;EAAA,IAAiB,OAAA;EAnBH;;;EAsC1F,cAAA,CAAe,MAAA;IAAU,KAAA;IAAiB,MAAA,EAAQ,aAAA;EAAA,IAAe,OAAA;EAgBrC;;;;;;;;EAAlC,gBAAA,CAAiB,MAAA,GAAQ,SAAA;EA9FZ;;;EA4Gb,KAAA;AAAA"}
|
package/dist/events/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/events/index.ts"],"sourcesContent":["import type { ParsedPath } from 'node:path'\nimport type { MaizzleConfig } from '../types/index.ts'\n\nexport type EventName = 'beforeCreate' | 'beforeRender' | 'afterRender' | 'afterTransform' | 'afterBuild'\n\n/**\n * Info about the template currently being processed, passed to per-template\n * event handlers. `source` is the SFC file contents; `path` is the result of\n * `path.parse(absolutePath)` — `{ root, dir, base, ext, name }`.\n */\nexport interface TemplateInfo {\n source: string\n path: ParsedPath\n}\n\nexport interface EventMap {\n beforeCreate: (params: { config: MaizzleConfig }) => void | Promise<void>\n beforeRender: (params: { config: MaizzleConfig; template: TemplateInfo }) => string | void | Promise<string | void>\n afterRender: (params: { config: MaizzleConfig; template: TemplateInfo; html: string }) => string | void | Promise<string | void>\n afterTransform: (params: { config: MaizzleConfig; template: TemplateInfo; html: string }) => string | void | Promise<string | void>\n afterBuild: (params: { files: string[]; config: MaizzleConfig }) => void | Promise<void>\n}\n\n/**\n * Central event manager that collects handlers from config and useEvent() calls.\n *\n * Handlers are run in order: config handler first, then SFC handlers in registration order.\n * For events that return a value (beforeRender, afterRender, afterTransform),\n * the returned value replaces the corresponding input for the next handler.\n */\nexport class EventManager {\n private handlers = new Map<EventName, EventMap[EventName][]>()\n /**\n * Snapshot of config-handler counts per event, captured at registerConfig().\n * clearSfcHandlers() truncates each list back to this count, dropping\n * any SFC-registered handlers that were appended after.\n */\n private configHandlerCount = new Map<EventName, number>()\n\n /**\n * Register handlers from the Maizzle config.\n */\n registerConfig(config: MaizzleConfig) {\n const eventNames: EventName[] = ['beforeCreate', 'beforeRender', 'afterRender', 'afterTransform', 'afterBuild']\n\n for (const name of eventNames) {\n const handler = config[name]\n if (typeof handler === 'function') {\n this.on(name, handler as EventMap[typeof name])\n }\n this.configHandlerCount.set(name, this.handlers.get(name)?.length ?? 0)\n }\n }\n\n /**\n * Register a handler for an event (used by useEvent composable).\n */\n on<K extends EventName>(name: K, handler: EventMap[K]) {\n if (!this.handlers.has(name)) {\n this.handlers.set(name, [])\n }\n\n this.handlers.get(name)!.push(handler)\n }\n\n /**\n * Fire beforeCreate — runs all handlers, config is mutated in place.\n */\n async fireBeforeCreate(params: { config: MaizzleConfig }) {\n const handlers = this.handlers.get('beforeCreate') ?? []\n\n for (const handler of handlers) {\n await (handler as EventMap['beforeCreate'])(params)\n }\n }\n\n /**\n * Fire beforeRender — if a handler returns a string, it replaces\n * `template.source` for subsequent handlers and the renderer.\n */\n async fireBeforeRender(params: { config: MaizzleConfig; template: TemplateInfo }): Promise<string> {\n const handlers = this.handlers.get('beforeRender') ?? []\n\n for (const handler of handlers) {\n const result = await (handler as EventMap['beforeRender'])(params)\n\n if (typeof result === 'string') {\n params.template.source = result\n }\n }\n\n return params.template.source\n }\n\n /**\n * Fire afterRender — if a handler returns a string, it replaces `html`.\n */\n async fireAfterRender(params: { config: MaizzleConfig; template: TemplateInfo; html: string }): Promise<string> {\n const handlers = this.handlers.get('afterRender') ?? []\n\n let { html } = params\n\n for (const handler of handlers) {\n const result = await (handler as EventMap['afterRender'])({ config: params.config, template: params.template, html })\n\n if (typeof result === 'string') {\n html = result\n }\n }\n\n return html\n }\n\n /**\n * Fire afterTransform — if a handler returns a string, it replaces `html`.\n */\n async fireAfterTransform(params: { config: MaizzleConfig; template: TemplateInfo; html: string }): Promise<string> {\n const handlers = this.handlers.get('afterTransform') ?? []\n\n let { html } = params\n\n for (const handler of handlers) {\n const result = await (handler as EventMap['afterTransform'])({ config: params.config, template: params.template, html })\n\n if (typeof result === 'string') {\n html = result\n }\n }\n\n return html\n }\n\n /**\n * Fire afterBuild — runs all handlers with the file list.\n */\n async fireAfterBuild(params: { files: string[]; config: MaizzleConfig }) {\n const handlers = this.handlers.get('afterBuild') ?? []\n\n for (const handler of handlers) {\n await (handler as EventMap['afterBuild'])(params)\n }\n }\n\n /**\n * Drop SFC-registered handlers, keep config-registered ones.\n *\n * Per default, only clears events whose scope is per-template\n * (`beforeRender`, `afterRender`, `afterTransform`). Build-scoped events\n * (`afterBuild`) accumulate across all templates and fire once at end of\n * build. Pass an explicit list to override.\n */\n clearSfcHandlers(events: EventName[] = ['beforeRender', 'afterRender', 'afterTransform']) {\n for (const name of events) {\n const handlers = this.handlers.get(name)\n if (!handlers) continue\n const keep = this.configHandlerCount.get(name) ?? 0\n if (handlers.length > keep) {\n this.handlers.set(name, handlers.slice(0, keep))\n }\n }\n }\n\n /**\n * Clear all handlers entirely.\n */\n clear() {\n this.handlers.clear()\n }\n}\n"],"mappings":";;;;;;;;AA8BA,IAAa,eAAb,MAA0B;CACxB,2BAAmB,IAAI,IAAsC;;;;;;CAM7D,qCAA6B,IAAI,IAAuB;;;;CAKxD,eAAe,QAAuB;EAGpC,KAAK,MAAM,QAAQ;GAFc;GAAgB;GAAgB;GAAe;GAAkB;EAEtE,GAAG;GAC7B,MAAM,UAAU,OAAO;GACvB,IAAI,OAAO,YAAY,YACrB,KAAK,GAAG,MAAM,OAAgC;GAEhD,KAAK,mBAAmB,IAAI,MAAM,KAAK,SAAS,IAAI,IAAI,
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/events/index.ts"],"sourcesContent":["import type { ParsedPath } from 'node:path'\nimport type { MaizzleConfig } from '../types/index.ts'\n\nexport type EventName = 'beforeCreate' | 'beforeRender' | 'afterRender' | 'afterTransform' | 'afterBuild'\n\n/**\n * Info about the template currently being processed, passed to per-template\n * event handlers. `source` is the SFC file contents; `path` is the result of\n * `path.parse(absolutePath)` — `{ root, dir, base, ext, name }`.\n */\nexport interface TemplateInfo {\n source: string\n path: ParsedPath\n}\n\nexport interface EventMap {\n beforeCreate: (params: { config: MaizzleConfig }) => void | Promise<void>\n beforeRender: (params: { config: MaizzleConfig; template: TemplateInfo }) => string | void | Promise<string | void>\n afterRender: (params: { config: MaizzleConfig; template: TemplateInfo; html: string }) => string | void | Promise<string | void>\n afterTransform: (params: { config: MaizzleConfig; template: TemplateInfo; html: string }) => string | void | Promise<string | void>\n afterBuild: (params: { files: string[]; config: MaizzleConfig }) => void | Promise<void>\n}\n\n/**\n * Central event manager that collects handlers from config and useEvent() calls.\n *\n * Handlers are run in order: config handler first, then SFC handlers in registration order.\n * For events that return a value (beforeRender, afterRender, afterTransform),\n * the returned value replaces the corresponding input for the next handler.\n */\nexport class EventManager {\n private handlers = new Map<EventName, EventMap[EventName][]>()\n /**\n * Snapshot of config-handler counts per event, captured at registerConfig().\n * clearSfcHandlers() truncates each list back to this count, dropping\n * any SFC-registered handlers that were appended after.\n */\n private configHandlerCount = new Map<EventName, number>()\n\n /**\n * Register handlers from the Maizzle config.\n */\n registerConfig(config: MaizzleConfig) {\n const eventNames: EventName[] = ['beforeCreate', 'beforeRender', 'afterRender', 'afterTransform', 'afterBuild']\n\n for (const name of eventNames) {\n const handler = config[name]\n if (typeof handler === 'function') {\n this.on(name, handler as EventMap[typeof name])\n }\n this.configHandlerCount.set(name, this.handlers.get(name)?.length ?? 0)\n }\n }\n\n /**\n * Register a handler for an event (used by useEvent composable).\n */\n on<K extends EventName>(name: K, handler: EventMap[K]) {\n if (!this.handlers.has(name)) {\n this.handlers.set(name, [])\n }\n\n this.handlers.get(name)!.push(handler)\n }\n\n /**\n * Fire beforeCreate — runs all handlers, config is mutated in place.\n */\n async fireBeforeCreate(params: { config: MaizzleConfig }) {\n const handlers = this.handlers.get('beforeCreate') ?? []\n\n for (const handler of handlers) {\n await (handler as EventMap['beforeCreate'])(params)\n }\n }\n\n /**\n * Fire beforeRender — if a handler returns a string, it replaces\n * `template.source` for subsequent handlers and the renderer.\n */\n async fireBeforeRender(params: { config: MaizzleConfig; template: TemplateInfo }): Promise<string> {\n const handlers = this.handlers.get('beforeRender') ?? []\n\n for (const handler of handlers) {\n const result = await (handler as EventMap['beforeRender'])(params)\n\n if (typeof result === 'string') {\n params.template.source = result\n }\n }\n\n return params.template.source\n }\n\n /**\n * Fire afterRender — if a handler returns a string, it replaces `html`.\n */\n async fireAfterRender(params: { config: MaizzleConfig; template: TemplateInfo; html: string }): Promise<string> {\n const handlers = this.handlers.get('afterRender') ?? []\n\n let { html } = params\n\n for (const handler of handlers) {\n const result = await (handler as EventMap['afterRender'])({ config: params.config, template: params.template, html })\n\n if (typeof result === 'string') {\n html = result\n }\n }\n\n return html\n }\n\n /**\n * Fire afterTransform — if a handler returns a string, it replaces `html`.\n */\n async fireAfterTransform(params: { config: MaizzleConfig; template: TemplateInfo; html: string }): Promise<string> {\n const handlers = this.handlers.get('afterTransform') ?? []\n\n let { html } = params\n\n for (const handler of handlers) {\n const result = await (handler as EventMap['afterTransform'])({ config: params.config, template: params.template, html })\n\n if (typeof result === 'string') {\n html = result\n }\n }\n\n return html\n }\n\n /**\n * Fire afterBuild — runs all handlers with the file list.\n */\n async fireAfterBuild(params: { files: string[]; config: MaizzleConfig }) {\n const handlers = this.handlers.get('afterBuild') ?? []\n\n for (const handler of handlers) {\n await (handler as EventMap['afterBuild'])(params)\n }\n }\n\n /**\n * Drop SFC-registered handlers, keep config-registered ones.\n *\n * Per default, only clears events whose scope is per-template\n * (`beforeRender`, `afterRender`, `afterTransform`). Build-scoped events\n * (`afterBuild`) accumulate across all templates and fire once at end of\n * build. Pass an explicit list to override.\n */\n clearSfcHandlers(events: EventName[] = ['beforeRender', 'afterRender', 'afterTransform']) {\n for (const name of events) {\n const handlers = this.handlers.get(name)\n if (!handlers) continue\n const keep = this.configHandlerCount.get(name) ?? 0\n if (handlers.length > keep) {\n this.handlers.set(name, handlers.slice(0, keep))\n }\n }\n }\n\n /**\n * Clear all handlers entirely.\n */\n clear() {\n this.handlers.clear()\n }\n}\n"],"mappings":";;;;;;;;AA8BA,IAAa,eAAb,MAA0B;CACxB,2BAAmB,IAAI,IAAsC;;;;;;CAM7D,qCAA6B,IAAI,IAAuB;;;;CAKxD,eAAe,QAAuB;EAGpC,KAAK,MAAM,QAAQ;GAFc;GAAgB;GAAgB;GAAe;GAAkB;EAEtE,GAAG;GAC7B,MAAM,UAAU,OAAO;GACvB,IAAI,OAAO,YAAY,YACrB,KAAK,GAAG,MAAM,OAAgC;GAEhD,KAAK,mBAAmB,IAAI,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,EAAE,UAAU,CAAC;EACxE;CACF;;;;CAKA,GAAwB,MAAS,SAAsB;EACrD,IAAI,CAAC,KAAK,SAAS,IAAI,IAAI,GACzB,KAAK,SAAS,IAAI,MAAM,CAAC,CAAC;EAG5B,KAAK,SAAS,IAAI,IAAI,CAAC,CAAE,KAAK,OAAO;CACvC;;;;CAKA,MAAM,iBAAiB,QAAmC;EACxD,MAAM,WAAW,KAAK,SAAS,IAAI,cAAc,KAAK,CAAC;EAEvD,KAAK,MAAM,WAAW,UACpB,MAAO,QAAqC,MAAM;CAEtD;;;;;CAMA,MAAM,iBAAiB,QAA4E;EACjG,MAAM,WAAW,KAAK,SAAS,IAAI,cAAc,KAAK,CAAC;EAEvD,KAAK,MAAM,WAAW,UAAU;GAC9B,MAAM,SAAS,MAAO,QAAqC,MAAM;GAEjE,IAAI,OAAO,WAAW,UACpB,OAAO,SAAS,SAAS;EAE7B;EAEA,OAAO,OAAO,SAAS;CACzB;;;;CAKA,MAAM,gBAAgB,QAA0F;EAC9G,MAAM,WAAW,KAAK,SAAS,IAAI,aAAa,KAAK,CAAC;EAEtD,IAAI,EAAE,SAAS;EAEf,KAAK,MAAM,WAAW,UAAU;GAC9B,MAAM,SAAS,MAAO,QAAoC;IAAE,QAAQ,OAAO;IAAQ,UAAU,OAAO;IAAU;GAAK,CAAC;GAEpH,IAAI,OAAO,WAAW,UACpB,OAAO;EAEX;EAEA,OAAO;CACT;;;;CAKA,MAAM,mBAAmB,QAA0F;EACjH,MAAM,WAAW,KAAK,SAAS,IAAI,gBAAgB,KAAK,CAAC;EAEzD,IAAI,EAAE,SAAS;EAEf,KAAK,MAAM,WAAW,UAAU;GAC9B,MAAM,SAAS,MAAO,QAAuC;IAAE,QAAQ,OAAO;IAAQ,UAAU,OAAO;IAAU;GAAK,CAAC;GAEvH,IAAI,OAAO,WAAW,UACpB,OAAO;EAEX;EAEA,OAAO;CACT;;;;CAKA,MAAM,eAAe,QAAoD;EACvE,MAAM,WAAW,KAAK,SAAS,IAAI,YAAY,KAAK,CAAC;EAErD,KAAK,MAAM,WAAW,UACpB,MAAO,QAAmC,MAAM;CAEpD;;;;;;;;;CAUA,iBAAiB,SAAsB;EAAC;EAAgB;EAAe;CAAgB,GAAG;EACxF,KAAK,MAAM,QAAQ,QAAQ;GACzB,MAAM,WAAW,KAAK,SAAS,IAAI,IAAI;GACvC,IAAI,CAAC,UAAU;GACf,MAAM,OAAO,KAAK,mBAAmB,IAAI,IAAI,KAAK;GAClD,IAAI,SAAS,SAAS,MACpB,KAAK,SAAS,IAAI,MAAM,SAAS,MAAM,GAAG,IAAI,CAAC;EAEnD;CACF;;;;CAKA,QAAQ;EACN,KAAK,SAAS,MAAM;CACtB;AACF"}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { useDoctype } from "./composables/useDoctype.js";
|
|
|
9
9
|
import { useEvent } from "./composables/useEvent.js";
|
|
10
10
|
import { useFont } from "./composables/useFont.js";
|
|
11
11
|
import { useOutlookFallback } from "./composables/useOutlookFallback.js";
|
|
12
|
+
import { useOutputPath } from "./composables/useOutputPath.js";
|
|
12
13
|
import { useTransformers } from "./composables/useTransformers.js";
|
|
13
14
|
import { useUrlQuery } from "./composables/useUrlQuery.js";
|
|
14
15
|
import { resolveConfig } from "./config/index.js";
|
|
@@ -36,4 +37,4 @@ import { replaceStrings } from "./transformers/replaceStrings.js";
|
|
|
36
37
|
import { FormatOptions, format } from "./transformers/format.js";
|
|
37
38
|
import { MinifyOptions, minify } from "./transformers/minify.js";
|
|
38
39
|
import { useHead } from "@unhead/vue";
|
|
39
|
-
export { type AttributesConfig, type BaseUrlOptions, type ComponentSource, type CreateRendererOptions, type CssConfig, type EntitiesConfig, type FilterFunction, type FiltersConfig, type FormatOptions, type HtmlConfig, type InlineCssOptions, type MaizzleConfig, type MinifyOptions, type NormalizedComponentSource, type PlaintextConfig, type PrepareOptions, type PurgeCssOptions, type RemoveAttributeOption, type RemoveAttributeRule, type RenderResult, type RenderedTemplate, type Renderer, type ShorthandCssOptions, type UrlConfig, type UrlQuery, type UrlQueryOptions, addAttributes, attributeToStyle, base, build, createPlaintext, createRenderer, defineConfig, entities, filters, format, inlineCss, inlineLink, maizzle, minify, normalizeComponentSources, prepare, purgeCss, removeAttributes, render, replaceStrings, resolveConfig, safeSelectors, serve, shorthandCss, sixHex, urlQuery, useBaseUrl, useConfig, useCurrentTemplate, useDoctype, useEvent, useFont, useHead, useOutlookFallback, usePlaintext, useTransformers, useUrlQuery };
|
|
40
|
+
export { type AttributesConfig, type BaseUrlOptions, type ComponentSource, type CreateRendererOptions, type CssConfig, type EntitiesConfig, type FilterFunction, type FiltersConfig, type FormatOptions, type HtmlConfig, type InlineCssOptions, type MaizzleConfig, type MinifyOptions, type NormalizedComponentSource, type PlaintextConfig, type PrepareOptions, type PurgeCssOptions, type RemoveAttributeOption, type RemoveAttributeRule, type RenderResult, type RenderedTemplate, type Renderer, type ShorthandCssOptions, type UrlConfig, type UrlQuery, type UrlQueryOptions, addAttributes, attributeToStyle, base, build, createPlaintext, createRenderer, defineConfig, entities, filters, format, inlineCss, inlineLink, maizzle, minify, normalizeComponentSources, prepare, purgeCss, removeAttributes, render, replaceStrings, resolveConfig, safeSelectors, serve, shorthandCss, sixHex, urlQuery, useBaseUrl, useConfig, useCurrentTemplate, useDoctype, useEvent, useFont, useHead, useOutlookFallback, useOutputPath, usePlaintext, useTransformers, useUrlQuery };
|
package/dist/index.js
CHANGED
|
@@ -30,9 +30,10 @@ import { useDoctype } from "./composables/useDoctype.js";
|
|
|
30
30
|
import { useEvent } from "./composables/useEvent.js";
|
|
31
31
|
import { useFont } from "./composables/useFont.js";
|
|
32
32
|
import { useOutlookFallback } from "./composables/useOutlookFallback.js";
|
|
33
|
+
import { useOutputPath } from "./composables/useOutputPath.js";
|
|
33
34
|
import { usePlaintext } from "./composables/usePlaintext.js";
|
|
34
35
|
import { useTransformers } from "./composables/useTransformers.js";
|
|
35
36
|
import { useBaseUrl } from "./composables/useBaseUrl.js";
|
|
36
37
|
import { useUrlQuery } from "./composables/useUrlQuery.js";
|
|
37
38
|
import { useHead } from "@unhead/vue";
|
|
38
|
-
export { addAttributes, attributeToStyle, base, build, createPlaintext, createRenderer, defineConfig, entities, filters, format, inlineCss, inlineLink, maizzle, minify, normalizeComponentSources, prepare, purgeCss, removeAttributes, render, replaceStrings, resolveConfig, safeSelectors, serve, shorthandCss, sixHex, urlQuery, useBaseUrl, useConfig, useCurrentTemplate, useDoctype, useEvent, useFont, useHead, useOutlookFallback, usePlaintext, useTransformers, useUrlQuery };
|
|
39
|
+
export { addAttributes, attributeToStyle, base, build, createPlaintext, createRenderer, defineConfig, entities, filters, format, inlineCss, inlineLink, maizzle, minify, normalizeComponentSources, prepare, purgeCss, removeAttributes, render, replaceStrings, resolveConfig, safeSelectors, serve, shorthandCss, sixHex, urlQuery, useBaseUrl, useConfig, useCurrentTemplate, useDoctype, useEvent, useFont, useHead, useOutlookFallback, useOutputPath, usePlaintext, useTransformers, useUrlQuery };
|
package/dist/plaintext.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plaintext.js","names":[],"sources":["../src/plaintext.ts"],"sourcesContent":["import { stripHtml } from 'string-strip-html'\nimport defu from 'defu'\n\nconst defaults = {\n dumpLinkHrefsNearby: {\n enabled: true,\n putOnNewLine: true,\n },\n}\n\nexport function createPlaintext(html: string, options?: Record<string, unknown>): string {\n return stripHtml(html, defu(options, defaults)).result\n}\n"],"mappings":";;;AAGA,MAAM,WAAW,EACf,qBAAqB;CACnB,SAAS;CACT,cAAc;AAChB,EACF;AAEA,SAAgB,gBAAgB,MAAc,SAA2C;CACvF,OAAO,UAAU,MAAM,KAAK,SAAS,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"plaintext.js","names":[],"sources":["../src/plaintext.ts"],"sourcesContent":["import { stripHtml } from 'string-strip-html'\nimport defu from 'defu'\n\nconst defaults = {\n dumpLinkHrefsNearby: {\n enabled: true,\n putOnNewLine: true,\n },\n}\n\nexport function createPlaintext(html: string, options?: Record<string, unknown>): string {\n return stripHtml(html, defu(options, defaults)).result\n}\n"],"mappings":";;;AAGA,MAAM,WAAW,EACf,qBAAqB;CACnB,SAAS;CACT,cAAc;AAChB,EACF;AAEA,SAAgB,gBAAgB,MAAc,SAA2C;CACvF,OAAO,UAAU,MAAM,KAAK,SAAS,QAAQ,CAAC,CAAC,CAAC;AAClD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mergeMediaQueries.js","names":[],"sources":["../../../src/plugins/postcss/mergeMediaQueries.ts"],"sourcesContent":["import sortMediaQueries from 'postcss-sort-media-queries'\nimport type postcss from 'postcss'\nimport type { MaizzleConfig } from '../../types/config.ts'\n\n/**\n * Sorts and merges CSS media queries using postcss-sort-media-queries.\n *\n * Enabled by default. Opt out with css: { media: false }.\n *\n * Config examples:\n * css: { media: true } // merge, mobile-first sort (default)\n * css: { media: { sort: 'desktop-first' } } // merge, desktop-first sort\n * css: { media: false } // disabled\n */\nexport function mergeMediaQueries(config: MaizzleConfig): postcss.Plugin | null {\n const media = config.css?.media\n\n if (media === false) return null\n\n const options = typeof media === 'object' ? media : {}\n const sort = options.sort ?? 'mobile-first'\n\n return sortMediaQueries({ sort }) as postcss.Plugin\n}\n"],"mappings":";;;;;;;;;;;;AAcA,SAAgB,kBAAkB,QAA8C;CAC9E,MAAM,QAAQ,OAAO,KAAK;CAE1B,IAAI,UAAU,OAAO,OAAO;CAK5B,OAAO,iBAAiB,EAAE,OAHV,OAAO,UAAU,WAAW,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"mergeMediaQueries.js","names":[],"sources":["../../../src/plugins/postcss/mergeMediaQueries.ts"],"sourcesContent":["import sortMediaQueries from 'postcss-sort-media-queries'\nimport type postcss from 'postcss'\nimport type { MaizzleConfig } from '../../types/config.ts'\n\n/**\n * Sorts and merges CSS media queries using postcss-sort-media-queries.\n *\n * Enabled by default. Opt out with css: { media: false }.\n *\n * Config examples:\n * css: { media: true } // merge, mobile-first sort (default)\n * css: { media: { sort: 'desktop-first' } } // merge, desktop-first sort\n * css: { media: false } // disabled\n */\nexport function mergeMediaQueries(config: MaizzleConfig): postcss.Plugin | null {\n const media = config.css?.media\n\n if (media === false) return null\n\n const options = typeof media === 'object' ? media : {}\n const sort = options.sort ?? 'mobile-first'\n\n return sortMediaQueries({ sort }) as postcss.Plugin\n}\n"],"mappings":";;;;;;;;;;;;AAcA,SAAgB,kBAAkB,QAA8C;CAC9E,MAAM,QAAQ,OAAO,KAAK;CAE1B,IAAI,UAAU,OAAO,OAAO;CAK5B,OAAO,iBAAiB,EAAE,OAHV,OAAO,UAAU,WAAW,QAAQ,CAAC,EAAA,CAChC,QAAQ,eAEE,CAAC;AAClC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pruneVars.js","names":[],"sources":["../../../src/plugins/postcss/pruneVars.ts"],"sourcesContent":["/**\n * postcss-prune-var\n * Removes unused CSS custom properties.\n */\n\nimport type { Declaration, Plugin, Root } from 'postcss';\n\nconst PLUGIN_NAME = 'postcss-prune-var';\n\nconst VAR_RE = /var\\(\\s*(--[^ ,);]+)/g;\n\ninterface VarRecord {\n uses: number;\n declarations: Set<Declaration>;\n dependencies: Set<string>;\n}\n\nexport default (): Plugin => {\n return {\n postcssPlugin: PLUGIN_NAME,\n\n Once(root: Root) {\n const records = new Map<string, VarRecord>();\n const usedVars = new Set<string>();\n\n const getRecord = (name: string): VarRecord => {\n let r = records.get(name);\n if (!r) {\n r = { uses: 0, declarations: new Set(), dependencies: new Set() };\n records.set(name, r);\n }\n return r;\n };\n\n const registerUse = (name: string, seen = new Set<string>()) => {\n const r = getRecord(name);\n r.uses++;\n seen.add(name);\n for (const dep of r.dependencies) {\n if (!seen.has(dep)) registerUse(dep, seen);\n }\n };\n\n // Build dependency graph\n root.walkDecls((decl) => {\n const isVar = decl.prop.startsWith('--');\n\n if (isVar) getRecord(decl.prop).declarations.add(decl);\n\n if (!decl.value.includes('var(')) return;\n\n let m;\n VAR_RE.lastIndex = 0;\n while ((m = VAR_RE.exec(decl.value))) {\n const ref = m[1].trim();\n if (isVar) {\n getRecord(decl.prop).dependencies.add(ref);\n } else {\n usedVars.add(ref);\n }\n }\n });\n\n // Propagate usage through the graph\n for (const v of usedVars) registerUse(v);\n\n // Remove declarations with zero uses\n for (const { uses, declarations } of records.values()) {\n if (uses === 0) {\n for (const decl of declarations) decl.remove();\n }\n }\n },\n };\n};\n\nexport const postcss = true;\n"],"mappings":";AAOA,MAAM,cAAc;AAEpB,MAAM,SAAS;AAQf,IAAA,0BAA6B;CAC3B,OAAO;EACL,eAAe;EAEf,KAAK,MAAY;GACf,MAAM,0BAAU,IAAI,IAAuB;GAC3C,MAAM,2BAAW,IAAI,IAAY;GAEjC,MAAM,aAAa,SAA4B;IAC7C,IAAI,IAAI,QAAQ,IAAI,IAAI;IACxB,IAAI,CAAC,GAAG;KACN,IAAI;MAAE,MAAM;MAAG,8BAAc,IAAI,IAAI;MAAG,8BAAc,IAAI,IAAI;KAAE;KAChE,QAAQ,IAAI,MAAM,CAAC;IACrB;IACA,OAAO;GACT;GAEA,MAAM,eAAe,MAAc,uBAAO,IAAI,IAAY,MAAM;IAC9D,MAAM,IAAI,UAAU,IAAI;IACxB,EAAE;IACF,KAAK,IAAI,IAAI;IACb,KAAK,MAAM,OAAO,EAAE,cAClB,IAAI,CAAC,KAAK,IAAI,GAAG,GAAG,YAAY,KAAK,IAAI;GAE7C;GAGA,KAAK,WAAW,SAAS;IACvB,MAAM,QAAQ,KAAK,KAAK,WAAW,IAAI;IAEvC,IAAI,OAAO,UAAU,KAAK,IAAI,
|
|
1
|
+
{"version":3,"file":"pruneVars.js","names":[],"sources":["../../../src/plugins/postcss/pruneVars.ts"],"sourcesContent":["/**\n * postcss-prune-var\n * Removes unused CSS custom properties.\n */\n\nimport type { Declaration, Plugin, Root } from 'postcss';\n\nconst PLUGIN_NAME = 'postcss-prune-var';\n\nconst VAR_RE = /var\\(\\s*(--[^ ,);]+)/g;\n\ninterface VarRecord {\n uses: number;\n declarations: Set<Declaration>;\n dependencies: Set<string>;\n}\n\nexport default (): Plugin => {\n return {\n postcssPlugin: PLUGIN_NAME,\n\n Once(root: Root) {\n const records = new Map<string, VarRecord>();\n const usedVars = new Set<string>();\n\n const getRecord = (name: string): VarRecord => {\n let r = records.get(name);\n if (!r) {\n r = { uses: 0, declarations: new Set(), dependencies: new Set() };\n records.set(name, r);\n }\n return r;\n };\n\n const registerUse = (name: string, seen = new Set<string>()) => {\n const r = getRecord(name);\n r.uses++;\n seen.add(name);\n for (const dep of r.dependencies) {\n if (!seen.has(dep)) registerUse(dep, seen);\n }\n };\n\n // Build dependency graph\n root.walkDecls((decl) => {\n const isVar = decl.prop.startsWith('--');\n\n if (isVar) getRecord(decl.prop).declarations.add(decl);\n\n if (!decl.value.includes('var(')) return;\n\n let m;\n VAR_RE.lastIndex = 0;\n while ((m = VAR_RE.exec(decl.value))) {\n const ref = m[1].trim();\n if (isVar) {\n getRecord(decl.prop).dependencies.add(ref);\n } else {\n usedVars.add(ref);\n }\n }\n });\n\n // Propagate usage through the graph\n for (const v of usedVars) registerUse(v);\n\n // Remove declarations with zero uses\n for (const { uses, declarations } of records.values()) {\n if (uses === 0) {\n for (const decl of declarations) decl.remove();\n }\n }\n },\n };\n};\n\nexport const postcss = true;\n"],"mappings":";AAOA,MAAM,cAAc;AAEpB,MAAM,SAAS;AAQf,IAAA,0BAA6B;CAC3B,OAAO;EACL,eAAe;EAEf,KAAK,MAAY;GACf,MAAM,0BAAU,IAAI,IAAuB;GAC3C,MAAM,2BAAW,IAAI,IAAY;GAEjC,MAAM,aAAa,SAA4B;IAC7C,IAAI,IAAI,QAAQ,IAAI,IAAI;IACxB,IAAI,CAAC,GAAG;KACN,IAAI;MAAE,MAAM;MAAG,8BAAc,IAAI,IAAI;MAAG,8BAAc,IAAI,IAAI;KAAE;KAChE,QAAQ,IAAI,MAAM,CAAC;IACrB;IACA,OAAO;GACT;GAEA,MAAM,eAAe,MAAc,uBAAO,IAAI,IAAY,MAAM;IAC9D,MAAM,IAAI,UAAU,IAAI;IACxB,EAAE;IACF,KAAK,IAAI,IAAI;IACb,KAAK,MAAM,OAAO,EAAE,cAClB,IAAI,CAAC,KAAK,IAAI,GAAG,GAAG,YAAY,KAAK,IAAI;GAE7C;GAGA,KAAK,WAAW,SAAS;IACvB,MAAM,QAAQ,KAAK,KAAK,WAAW,IAAI;IAEvC,IAAI,OAAO,UAAU,KAAK,IAAI,CAAC,CAAC,aAAa,IAAI,IAAI;IAErD,IAAI,CAAC,KAAK,MAAM,SAAS,MAAM,GAAG;IAElC,IAAI;IACJ,OAAO,YAAY;IACnB,OAAQ,IAAI,OAAO,KAAK,KAAK,KAAK,GAAI;KACpC,MAAM,MAAM,EAAE,EAAE,CAAC,KAAK;KACtB,IAAI,OACF,UAAU,KAAK,IAAI,CAAC,CAAC,aAAa,IAAI,GAAG;UAEzC,SAAS,IAAI,GAAG;IAEpB;GACF,CAAC;GAGD,KAAK,MAAM,KAAK,UAAU,YAAY,CAAC;GAGvC,KAAK,MAAM,EAAE,MAAM,kBAAkB,QAAQ,OAAO,GAClD,IAAI,SAAS,GACX,KAAK,MAAM,QAAQ,cAAc,KAAK,OAAO;EAGnD;CACF;AACF;AAEA,MAAa,UAAU"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quoteFontFamilies.d.ts","names":[],"sources":["../../../src/plugins/postcss/quoteFontFamilies.ts"],"mappings":";;;;;AA+CA;;;iBAAgB,iBAAA,
|
|
1
|
+
{"version":3,"file":"quoteFontFamilies.d.ts","names":[],"sources":["../../../src/plugins/postcss/quoteFontFamilies.ts"],"mappings":";;;;;AA+CA;;;iBAAgB,iBAAA,IAAqB,MAAM;AAAA,cA6B9B,OAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"quoteFontFamilies.js","names":[],"sources":["../../../src/plugins/postcss/quoteFontFamilies.ts"],"sourcesContent":["import type { Plugin } from 'postcss'\n\nconst GENERIC_KEYWORDS = new Set([\n 'serif', 'sans-serif', 'monospace', 'cursive', 'fantasy',\n 'system-ui', 'ui-serif', 'ui-sans-serif', 'ui-monospace', 'ui-rounded',\n 'emoji', 'math', 'fangsong',\n 'inherit', 'initial', 'unset', 'revert', 'revert-layer',\n])\n\n/**\n * Split a font-family value on top-level commas only, preserving quoted\n * strings and parenthesised groups like `var(...)`.\n */\nfunction splitFamilies(value: string): string[] {\n const parts: string[] = []\n let depth = 0\n let quote: string | null = null\n let start = 0\n\n for (let i = 0; i < value.length; i++) {\n const ch = value[i]\n if (quote) {\n if (ch === '\\\\') { i++; continue }\n if (ch === quote) quote = null\n continue\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch\n continue\n }\n if (ch === '(') depth++\n else if (ch === ')') depth--\n else if (ch === ',' && depth === 0) {\n parts.push(value.slice(start, i).trim())\n start = i + 1\n }\n }\n\n parts.push(value.slice(start).trim())\n return parts.filter(Boolean)\n}\n\n/**\n * Re-quote multi-word font-family identifiers that lightningcss \"optimised\"\n * by removing quotes. CSS allows space-separated identifiers as a family\n * name, but Google Fonts (and most style guides) prescribe quoted form.\n */\nexport function quoteFontFamilies(): Plugin {\n return {\n postcssPlugin: 'quote-font-families',\n Declaration: {\n 'font-family': (decl) => {\n const value = decl.value\n if (!value || !/\\s/.test(value)) return\n\n const families = splitFamilies(value)\n let changed = false\n\n const fixed = families.map((token) => {\n if (token.startsWith('\"') || token.startsWith(\"'\")) return token\n if (token.startsWith('var(')) return token\n if (!token.includes(' ')) return token\n if (GENERIC_KEYWORDS.has(token.toLowerCase())) return token\n\n changed = true\n return `\"${token}\"`\n })\n\n if (changed) {\n decl.value = fixed.join(', ')\n }\n },\n },\n }\n}\n\nexport const postcss = true\n"],"mappings":";AAEA,MAAM,mBAAmB,IAAI,IAAI;CAC/B;CAAS;CAAc;CAAa;CAAW;CAC/C;CAAa;CAAY;CAAiB;CAAgB;CAC1D;CAAS;CAAQ;CACjB;CAAW;CAAW;CAAS;CAAU;AAC3C,CAAC;;;;;AAMD,SAAS,cAAc,OAAyB;CAC9C,MAAM,QAAkB,CAAC;CACzB,IAAI,QAAQ;CACZ,IAAI,QAAuB;CAC3B,IAAI,QAAQ;CAEZ,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,KAAK,MAAM;EACjB,IAAI,OAAO;GACT,IAAI,OAAO,MAAM;IAAE;IAAK;GAAS;GACjC,IAAI,OAAO,OAAO,QAAQ;GAC1B;EACF;EACA,IAAI,OAAO,QAAO,OAAO,KAAK;GAC5B,QAAQ;GACR;EACF;EACA,IAAI,OAAO,KAAK;OACX,IAAI,OAAO,KAAK;OAChB,IAAI,OAAO,OAAO,UAAU,GAAG;GAClC,MAAM,KAAK,MAAM,MAAM,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"quoteFontFamilies.js","names":[],"sources":["../../../src/plugins/postcss/quoteFontFamilies.ts"],"sourcesContent":["import type { Plugin } from 'postcss'\n\nconst GENERIC_KEYWORDS = new Set([\n 'serif', 'sans-serif', 'monospace', 'cursive', 'fantasy',\n 'system-ui', 'ui-serif', 'ui-sans-serif', 'ui-monospace', 'ui-rounded',\n 'emoji', 'math', 'fangsong',\n 'inherit', 'initial', 'unset', 'revert', 'revert-layer',\n])\n\n/**\n * Split a font-family value on top-level commas only, preserving quoted\n * strings and parenthesised groups like `var(...)`.\n */\nfunction splitFamilies(value: string): string[] {\n const parts: string[] = []\n let depth = 0\n let quote: string | null = null\n let start = 0\n\n for (let i = 0; i < value.length; i++) {\n const ch = value[i]\n if (quote) {\n if (ch === '\\\\') { i++; continue }\n if (ch === quote) quote = null\n continue\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch\n continue\n }\n if (ch === '(') depth++\n else if (ch === ')') depth--\n else if (ch === ',' && depth === 0) {\n parts.push(value.slice(start, i).trim())\n start = i + 1\n }\n }\n\n parts.push(value.slice(start).trim())\n return parts.filter(Boolean)\n}\n\n/**\n * Re-quote multi-word font-family identifiers that lightningcss \"optimised\"\n * by removing quotes. CSS allows space-separated identifiers as a family\n * name, but Google Fonts (and most style guides) prescribe quoted form.\n */\nexport function quoteFontFamilies(): Plugin {\n return {\n postcssPlugin: 'quote-font-families',\n Declaration: {\n 'font-family': (decl) => {\n const value = decl.value\n if (!value || !/\\s/.test(value)) return\n\n const families = splitFamilies(value)\n let changed = false\n\n const fixed = families.map((token) => {\n if (token.startsWith('\"') || token.startsWith(\"'\")) return token\n if (token.startsWith('var(')) return token\n if (!token.includes(' ')) return token\n if (GENERIC_KEYWORDS.has(token.toLowerCase())) return token\n\n changed = true\n return `\"${token}\"`\n })\n\n if (changed) {\n decl.value = fixed.join(', ')\n }\n },\n },\n }\n}\n\nexport const postcss = true\n"],"mappings":";AAEA,MAAM,mBAAmB,IAAI,IAAI;CAC/B;CAAS;CAAc;CAAa;CAAW;CAC/C;CAAa;CAAY;CAAiB;CAAgB;CAC1D;CAAS;CAAQ;CACjB;CAAW;CAAW;CAAS;CAAU;AAC3C,CAAC;;;;;AAMD,SAAS,cAAc,OAAyB;CAC9C,MAAM,QAAkB,CAAC;CACzB,IAAI,QAAQ;CACZ,IAAI,QAAuB;CAC3B,IAAI,QAAQ;CAEZ,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;EACrC,MAAM,KAAK,MAAM;EACjB,IAAI,OAAO;GACT,IAAI,OAAO,MAAM;IAAE;IAAK;GAAS;GACjC,IAAI,OAAO,OAAO,QAAQ;GAC1B;EACF;EACA,IAAI,OAAO,QAAO,OAAO,KAAK;GAC5B,QAAQ;GACR;EACF;EACA,IAAI,OAAO,KAAK;OACX,IAAI,OAAO,KAAK;OAChB,IAAI,OAAO,OAAO,UAAU,GAAG;GAClC,MAAM,KAAK,MAAM,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;GACvC,QAAQ,IAAI;EACd;CACF;CAEA,MAAM,KAAK,MAAM,MAAM,KAAK,CAAC,CAAC,KAAK,CAAC;CACpC,OAAO,MAAM,OAAO,OAAO;AAC7B;;;;;;AAOA,SAAgB,oBAA4B;CAC1C,OAAO;EACL,eAAe;EACf,aAAa,EACX,gBAAgB,SAAS;GACvB,MAAM,QAAQ,KAAK;GACnB,IAAI,CAAC,SAAS,CAAC,KAAK,KAAK,KAAK,GAAG;GAEjC,MAAM,WAAW,cAAc,KAAK;GACpC,IAAI,UAAU;GAEd,MAAM,QAAQ,SAAS,KAAK,UAAU;IACpC,IAAI,MAAM,WAAW,IAAG,KAAK,MAAM,WAAW,GAAG,GAAG,OAAO;IAC3D,IAAI,MAAM,WAAW,MAAM,GAAG,OAAO;IACrC,IAAI,CAAC,MAAM,SAAS,GAAG,GAAG,OAAO;IACjC,IAAI,iBAAiB,IAAI,MAAM,YAAY,CAAC,GAAG,OAAO;IAEtD,UAAU;IACV,OAAO,IAAI,MAAM;GACnB,CAAC;GAED,IAAI,SACF,KAAK,QAAQ,MAAM,KAAK,IAAI;EAEhC,EACF;CACF;AACF;AAEA,MAAa,UAAU"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"removeDeclarations.js","names":[],"sources":["../../../src/plugins/postcss/removeDeclarations.ts"],"sourcesContent":["/**\n * postcss-remove-declarations\n *\n * Removes CSS declarations (or whole rules) based on a selector map.\n *\n * The `remove` option maps a selector string to one of:\n *\n * - `\"*\"` — remove the entire rule\n * - `string` — remove the single named property\n * - `string[]` — remove every listed property\n * - `Record<string, string>` — remove a property only when its value matches.\n * Append `!important` to the value to restrict the match\n * to non-important declarations only.\n *\n * Example:\n * removeDeclarations({\n * remove: {\n * ':root': '*',\n * '.foo': ['color', 'margin'],\n * '.bar': { color: 'red' },\n * }\n * })\n */\n\nimport type { Plugin, Root } from 'postcss'\n\nexport type RemoveValue =\n | '*'\n | string\n | string[]\n | Record<string, string>\n\nexport interface RemoveDeclarationsOptions {\n remove: Record<string, RemoveValue>\n}\n\nconst IMPORTANT = '!important'\n\nfunction normalizeSelector(selector: string): string {\n return selector.replace(/(\\r\\n|\\n|\\r)/gm, '')\n}\n\nexport default (options: RemoveDeclarationsOptions): Plugin => {\n return {\n postcssPlugin: 'postcss-remove-declarations',\n\n Once(root: Root) {\n const remove = options.remove ?? {}\n\n root.walkRules((rule) => {\n let toRemove = remove[normalizeSelector(rule.selector)]\n\n if (!toRemove) return\n\n // Remove the entire rule\n if (toRemove === '*') {\n rule.remove()\n return\n }\n\n // Normalise a bare string into an array\n if (typeof toRemove === 'string') {\n toRemove = [toRemove]\n }\n\n if (Array.isArray(toRemove)) {\n const props = toRemove as string[]\n rule.walkDecls((decl) => {\n if (props.includes(decl.prop)) decl.remove()\n })\n } else if (typeof toRemove === 'object') {\n // Object: match both property and value\n const map = toRemove as Record<string, string>\n rule.walkDecls((decl) => {\n if (!(decl.prop in map)) return\n\n let expected = map[decl.prop]\n const requireNonImportant = expected.endsWith(IMPORTANT)\n\n if (requireNonImportant) {\n expected = expected.slice(0, -IMPORTANT.length).trim()\n }\n\n if (decl.value !== expected) return\n if (decl.important && requireNonImportant) return\n\n decl.remove()\n })\n }\n\n // Remove the rule if all declarations were removed\n if (rule.nodes?.length === 0) {\n rule.remove()\n }\n })\n },\n }\n}\n\nexport const postcss = true\n"],"mappings":";AAoCA,MAAM,YAAY;AAElB,SAAS,kBAAkB,UAA0B;CACnD,OAAO,SAAS,QAAQ,kBAAkB,EAAE;AAC9C;AAEA,IAAA,8BAAgB,YAA+C;CAC7D,OAAO;EACL,eAAe;EAEf,KAAK,MAAY;GACf,MAAM,SAAS,QAAQ,UAAU,CAAC;GAElC,KAAK,WAAW,SAAS;IACvB,IAAI,WAAW,OAAO,kBAAkB,KAAK,QAAQ;IAErD,IAAI,CAAC,UAAU;IAGf,IAAI,aAAa,KAAK;KACpB,KAAK,OAAO;KACZ;IACF;IAGA,IAAI,OAAO,aAAa,UACtB,WAAW,CAAC,QAAQ;IAGtB,IAAI,MAAM,QAAQ,QAAQ,GAAG;KAC3B,MAAM,QAAQ;KACd,KAAK,WAAW,SAAS;MACvB,IAAI,MAAM,SAAS,KAAK,IAAI,GAAG,KAAK,OAAO;KAC7C,CAAC;IACH,OAAO,IAAI,OAAO,aAAa,UAAU;KAEvC,MAAM,MAAM;KACZ,KAAK,WAAW,SAAS;MACvB,IAAI,EAAE,KAAK,QAAQ,MAAM;MAEzB,IAAI,WAAW,IAAI,KAAK;MACxB,MAAM,sBAAsB,SAAS,SAAS,SAAS;MAEvD,IAAI,qBACF,WAAW,SAAS,MAAM,GAAG,GAAiB,
|
|
1
|
+
{"version":3,"file":"removeDeclarations.js","names":[],"sources":["../../../src/plugins/postcss/removeDeclarations.ts"],"sourcesContent":["/**\n * postcss-remove-declarations\n *\n * Removes CSS declarations (or whole rules) based on a selector map.\n *\n * The `remove` option maps a selector string to one of:\n *\n * - `\"*\"` — remove the entire rule\n * - `string` — remove the single named property\n * - `string[]` — remove every listed property\n * - `Record<string, string>` — remove a property only when its value matches.\n * Append `!important` to the value to restrict the match\n * to non-important declarations only.\n *\n * Example:\n * removeDeclarations({\n * remove: {\n * ':root': '*',\n * '.foo': ['color', 'margin'],\n * '.bar': { color: 'red' },\n * }\n * })\n */\n\nimport type { Plugin, Root } from 'postcss'\n\nexport type RemoveValue =\n | '*'\n | string\n | string[]\n | Record<string, string>\n\nexport interface RemoveDeclarationsOptions {\n remove: Record<string, RemoveValue>\n}\n\nconst IMPORTANT = '!important'\n\nfunction normalizeSelector(selector: string): string {\n return selector.replace(/(\\r\\n|\\n|\\r)/gm, '')\n}\n\nexport default (options: RemoveDeclarationsOptions): Plugin => {\n return {\n postcssPlugin: 'postcss-remove-declarations',\n\n Once(root: Root) {\n const remove = options.remove ?? {}\n\n root.walkRules((rule) => {\n let toRemove = remove[normalizeSelector(rule.selector)]\n\n if (!toRemove) return\n\n // Remove the entire rule\n if (toRemove === '*') {\n rule.remove()\n return\n }\n\n // Normalise a bare string into an array\n if (typeof toRemove === 'string') {\n toRemove = [toRemove]\n }\n\n if (Array.isArray(toRemove)) {\n const props = toRemove as string[]\n rule.walkDecls((decl) => {\n if (props.includes(decl.prop)) decl.remove()\n })\n } else if (typeof toRemove === 'object') {\n // Object: match both property and value\n const map = toRemove as Record<string, string>\n rule.walkDecls((decl) => {\n if (!(decl.prop in map)) return\n\n let expected = map[decl.prop]\n const requireNonImportant = expected.endsWith(IMPORTANT)\n\n if (requireNonImportant) {\n expected = expected.slice(0, -IMPORTANT.length).trim()\n }\n\n if (decl.value !== expected) return\n if (decl.important && requireNonImportant) return\n\n decl.remove()\n })\n }\n\n // Remove the rule if all declarations were removed\n if (rule.nodes?.length === 0) {\n rule.remove()\n }\n })\n },\n }\n}\n\nexport const postcss = true\n"],"mappings":";AAoCA,MAAM,YAAY;AAElB,SAAS,kBAAkB,UAA0B;CACnD,OAAO,SAAS,QAAQ,kBAAkB,EAAE;AAC9C;AAEA,IAAA,8BAAgB,YAA+C;CAC7D,OAAO;EACL,eAAe;EAEf,KAAK,MAAY;GACf,MAAM,SAAS,QAAQ,UAAU,CAAC;GAElC,KAAK,WAAW,SAAS;IACvB,IAAI,WAAW,OAAO,kBAAkB,KAAK,QAAQ;IAErD,IAAI,CAAC,UAAU;IAGf,IAAI,aAAa,KAAK;KACpB,KAAK,OAAO;KACZ;IACF;IAGA,IAAI,OAAO,aAAa,UACtB,WAAW,CAAC,QAAQ;IAGtB,IAAI,MAAM,QAAQ,QAAQ,GAAG;KAC3B,MAAM,QAAQ;KACd,KAAK,WAAW,SAAS;MACvB,IAAI,MAAM,SAAS,KAAK,IAAI,GAAG,KAAK,OAAO;KAC7C,CAAC;IACH,OAAO,IAAI,OAAO,aAAa,UAAU;KAEvC,MAAM,MAAM;KACZ,KAAK,WAAW,SAAS;MACvB,IAAI,EAAE,KAAK,QAAQ,MAAM;MAEzB,IAAI,WAAW,IAAI,KAAK;MACxB,MAAM,sBAAsB,SAAS,SAAS,SAAS;MAEvD,IAAI,qBACF,WAAW,SAAS,MAAM,GAAG,GAAiB,CAAC,CAAC,KAAK;MAGvD,IAAI,KAAK,UAAU,UAAU;MAC7B,IAAI,KAAK,aAAa,qBAAqB;MAE3C,KAAK,OAAO;KACd,CAAC;IACH;IAGA,IAAI,KAAK,OAAO,WAAW,GACzB,KAAK,OAAO;GAEhB,CAAC;EACH;CACF;AACF;AAEA,MAAa,UAAU"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveProps.d.ts","names":[],"sources":["../../../src/plugins/postcss/resolveProps.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"resolveProps.d.ts","names":[],"sources":["../../../src/plugins/postcss/resolveProps.ts"],"mappings":";;;cAiBsE,QAAA,QA+FnD,MAAM;AAAA,cA+IZ,OAAA"}
|
|
@@ -143,9 +143,6 @@ var resolveProps_default = () => {
|
|
|
143
143
|
root.walkRules((rule) => {
|
|
144
144
|
if (!isRootRule(rule)) return;
|
|
145
145
|
if (rule.parent?.type !== "root" && !isInLayer(rule)) return;
|
|
146
|
-
rule.each((node) => {
|
|
147
|
-
if (node.type === "decl" && node.prop.startsWith("--")) node.remove();
|
|
148
|
-
});
|
|
149
146
|
if (rule.nodes?.length === 0) rule.remove();
|
|
150
147
|
});
|
|
151
148
|
}
|