@simon_he/vue-tui 1.1.4 → 1.1.5
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/README.md +18 -18
- package/dist/agent/mermaid.d.cts +1 -1
- package/dist/agent/mermaid.d.ts +1 -1
- package/dist/agent.cjs +5 -1
- package/dist/agent.js +3 -3
- package/dist/{block-source-D3YGTErb.js → block-source-DhzajB9H.js} +1 -1
- package/dist/cli.cjs +5 -1
- package/dist/cli.js +1 -1
- package/dist/experimental.cjs +5 -1
- package/dist/experimental.js +2 -2
- package/dist/markdown.js +2 -2
- package/dist/{mermaid-uEfRItDe.js → mermaid-N3kGTHFy.js} +655 -163
- package/dist/mermaid.cjs +544 -176
- package/dist/mermaid.d.cts +1 -1
- package/dist/mermaid.d.ts +1 -1
- package/dist/mermaid.js +3 -3
- package/dist/renderer/terminal-graphics.d.ts +17 -0
- package/dist/{terminal-graphics-DWZrl3oh.js → terminal-graphics-2FTRg9x3.js} +6 -1
- package/dist/{tlog-theme-DqnF_zNe.js → tlog-theme-B91Wv7Zj.js} +1 -1
- package/dist/vue/components/TMermaidImage.d.ts +187 -0
- package/dist/vue/mermaid/beautiful-mermaid.d.ts +282 -238
- package/dist/vue/mermaid/mermaid-image.d.ts +8 -0
- package/package.json +11 -10
package/dist/mermaid.cjs
CHANGED
|
@@ -41,6 +41,7 @@ __export(mermaid_exports, {
|
|
|
41
41
|
markMermaidRenderErrorFatal: () => markMermaidRenderErrorFatal,
|
|
42
42
|
normalizeMermaidImageOptions: () => normalizeMermaidImageOptions,
|
|
43
43
|
resolveMermaidImageColor: () => resolveMermaidImageColor,
|
|
44
|
+
resolveMermaidSvgForResvg: () => resolveMermaidSvgForResvg,
|
|
44
45
|
setMermaidImageRasterizer: () => setMermaidImageRasterizer,
|
|
45
46
|
subscribeMermaidImage: () => subscribeMermaidImage
|
|
46
47
|
});
|
|
@@ -1597,127 +1598,10 @@ var tMermaidTextProps = {
|
|
|
1597
1598
|
});
|
|
1598
1599
|
|
|
1599
1600
|
// src/vue/mermaid/beautiful-mermaid.ts
|
|
1600
|
-
var
|
|
1601
|
-
var BEAUTIFUL_MERMAID_INSTALL_HINT = "Install beautiful-mermaid and use TMermaidText from @simon_he/vue-tui/mermaid or @simon_he/vue-tui/agent/mermaid, or pass a custom renderer prop.", MISSING_BEAUTIFUL_MERMAID_ERROR_CODE = "VUE_TUI_MISSING_BEAUTIFUL_MERMAID", INVALID_BEAUTIFUL_MERMAID_EXPORT_ERROR_CODE = "VUE_TUI_INVALID_BEAUTIFUL_MERMAID_EXPORT", cachedBeautifulMermaid = null;
|
|
1602
|
-
function functionValue(value) {
|
|
1603
|
-
return typeof value == "function" ? value : null;
|
|
1604
|
-
}
|
|
1605
|
-
function functionProp(target, key) {
|
|
1606
|
-
if (!target || typeof target != "object" || !(key in target))
|
|
1607
|
-
return null;
|
|
1608
|
-
let value = target[key];
|
|
1609
|
-
return typeof value == "function" ? value : null;
|
|
1610
|
-
}
|
|
1611
|
-
function errorMessage(error) {
|
|
1612
|
-
return error instanceof Error ? error.message : String(error);
|
|
1613
|
-
}
|
|
1614
|
-
function codedError(message, code) {
|
|
1615
|
-
let error = new Error(message);
|
|
1616
|
-
return error.code = code, error;
|
|
1617
|
-
}
|
|
1618
|
-
function missingBeautifulMermaidError(error) {
|
|
1619
|
-
if (error && typeof error == "object" && errorCode(error) === MISSING_BEAUTIFUL_MERMAID_ERROR_CODE)
|
|
1620
|
-
return markMermaidRenderErrorFatal(error);
|
|
1621
|
-
let detail = errorMessage(error);
|
|
1622
|
-
return markMermaidRenderErrorFatal(
|
|
1623
|
-
codedError(
|
|
1624
|
-
`${BEAUTIFUL_MERMAID_INSTALL_HINT} (${detail})`,
|
|
1625
|
-
MISSING_BEAUTIFUL_MERMAID_ERROR_CODE
|
|
1626
|
-
)
|
|
1627
|
-
);
|
|
1628
|
-
}
|
|
1629
|
-
function errorCode(error) {
|
|
1630
|
-
if (!error || typeof error != "object")
|
|
1631
|
-
return "";
|
|
1632
|
-
let value = error.code;
|
|
1633
|
-
return typeof value == "string" ? value : "";
|
|
1634
|
-
}
|
|
1635
|
-
function errorCause(error) {
|
|
1636
|
-
if (!(!error || typeof error != "object"))
|
|
1637
|
-
return error.cause;
|
|
1638
|
-
}
|
|
1639
|
-
function isMissingBeautifulMermaid(error) {
|
|
1640
|
-
return isMissingBeautifulMermaidWithSeen(error, /* @__PURE__ */ new WeakSet());
|
|
1641
|
-
}
|
|
1642
|
-
function isMissingBeautifulMermaidWithSeen(error, seen) {
|
|
1643
|
-
if (error && typeof error == "object") {
|
|
1644
|
-
if (seen.has(error))
|
|
1645
|
-
return !1;
|
|
1646
|
-
seen.add(error);
|
|
1647
|
-
}
|
|
1648
|
-
let message = errorMessage(error), code = errorCode(error);
|
|
1649
|
-
if (code === MISSING_BEAUTIFUL_MERMAID_ERROR_CODE || (/Cannot find package ['"]beautiful-mermaid['"]/.test(message) || /Cannot find module ['"]beautiful-mermaid['"]/.test(message) || /Cannot resolve module ['"]beautiful-mermaid['"]/.test(message) || /Can't resolve ['"]beautiful-mermaid['"]/.test(message) || /Failed to resolve module specifier ['"]beautiful-mermaid['"]/.test(message) || /Failed to resolve import ['"]beautiful-mermaid['"]/.test(message) || /Could not resolve ['"]beautiful-mermaid['"]/.test(message)) && (code === "" || code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND" || code === "UNRESOLVED_IMPORT"))
|
|
1650
|
-
return !0;
|
|
1651
|
-
let cause = errorCause(error);
|
|
1652
|
-
return cause !== void 0 && isMissingBeautifulMermaidWithSeen(cause, seen);
|
|
1653
|
-
}
|
|
1654
|
-
function resolveBeautifulMermaidRenderer(mod) {
|
|
1655
|
-
let renderer = functionProp(mod, "renderMermaidASCII") ?? functionProp(mod, "renderMermaidAscii") ?? functionValue(mod.default) ?? functionProp(mod.default, "renderMermaidASCII") ?? functionProp(mod.default, "renderMermaidAscii");
|
|
1656
|
-
if (!renderer)
|
|
1657
|
-
throw markMermaidRenderErrorFatal(
|
|
1658
|
-
codedError(
|
|
1659
|
-
"beautiful-mermaid is installed but does not export renderMermaidASCII.",
|
|
1660
|
-
INVALID_BEAUTIFUL_MERMAID_EXPORT_ERROR_CODE
|
|
1661
|
-
)
|
|
1662
|
-
);
|
|
1663
|
-
return renderer;
|
|
1664
|
-
}
|
|
1665
|
-
function hasErrorCode(error, code, seen = /* @__PURE__ */ new WeakSet()) {
|
|
1666
|
-
if (!error || typeof error != "object" || seen.has(error))
|
|
1667
|
-
return !1;
|
|
1668
|
-
if (seen.add(error), errorCode(error) === code)
|
|
1669
|
-
return !0;
|
|
1670
|
-
let cause = errorCause(error);
|
|
1671
|
-
return cause !== void 0 && hasErrorCode(cause, code, seen);
|
|
1672
|
-
}
|
|
1673
|
-
function isBeautifulMermaidExportError(error) {
|
|
1674
|
-
return hasErrorCode(error, INVALID_BEAUTIFUL_MERMAID_EXPORT_ERROR_CODE);
|
|
1675
|
-
}
|
|
1676
|
-
var isTransientBeautifulMermaidRenderError = (error) => !(isMissingBeautifulMermaid(error) || isBeautifulMermaidExportError(error));
|
|
1677
|
-
async function loadBeautifulMermaid() {
|
|
1678
|
-
return cachedBeautifulMermaid || (cachedBeautifulMermaid = import("beautiful-mermaid").then((mod) => mod).catch((error) => {
|
|
1679
|
-
throw cachedBeautifulMermaid = null, isMissingBeautifulMermaid(error) ? missingBeautifulMermaidError(error) : markMermaidRenderErrorFatal(error);
|
|
1680
|
-
})), cachedBeautifulMermaid;
|
|
1681
|
-
}
|
|
1682
|
-
var beautifulMermaidRenderer = async (code, options) => {
|
|
1683
|
-
try {
|
|
1684
|
-
let mod = await loadBeautifulMermaid();
|
|
1685
|
-
return await resolveBeautifulMermaidRenderer(mod)(code, options);
|
|
1686
|
-
} catch (error) {
|
|
1687
|
-
throw isMissingBeautifulMermaid(error) ? missingBeautifulMermaidError(error) : error;
|
|
1688
|
-
}
|
|
1689
|
-
};
|
|
1690
|
-
function createBeautifulMermaidRenderer() {
|
|
1691
|
-
return beautifulMermaidRenderer;
|
|
1692
|
-
}
|
|
1693
|
-
var TMermaidText2 = (0, import_vue9.defineComponent)({
|
|
1694
|
-
name: "TMermaidText",
|
|
1695
|
-
inheritAttrs: !1,
|
|
1696
|
-
props: tMermaidTextProps,
|
|
1697
|
-
emits: {
|
|
1698
|
-
copy: (_payload) => !0
|
|
1699
|
-
},
|
|
1700
|
-
setup(props, { attrs, emit, slots }) {
|
|
1701
|
-
return () => {
|
|
1702
|
-
let renderer = props.renderer ?? beautifulMermaidRenderer, shouldRenderSource = props.shouldRenderSource ?? isSimpleMermaidFlowchartSource;
|
|
1703
|
-
return (0, import_vue9.h)(
|
|
1704
|
-
TMermaidText,
|
|
1705
|
-
{
|
|
1706
|
-
...attrs,
|
|
1707
|
-
...props,
|
|
1708
|
-
renderer,
|
|
1709
|
-
shouldRenderSource,
|
|
1710
|
-
isTransientError: props.isTransientError ?? isTransientBeautifulMermaidRenderError,
|
|
1711
|
-
onCopy: (payload) => emit("copy", payload)
|
|
1712
|
-
},
|
|
1713
|
-
slots
|
|
1714
|
-
);
|
|
1715
|
-
};
|
|
1716
|
-
}
|
|
1717
|
-
}), TMermaid = TMermaidText2, TBeautifulMermaidText = TMermaidText2, TBeautifulMermaid = TMermaidText2;
|
|
1601
|
+
var import_vue10 = require("vue");
|
|
1718
1602
|
|
|
1719
1603
|
// src/vue/components/TMermaidImage.ts
|
|
1720
|
-
var
|
|
1604
|
+
var import_vue9 = require("vue");
|
|
1721
1605
|
|
|
1722
1606
|
// src/core/terminal/create-terminal.ts
|
|
1723
1607
|
var TERMINAL_PLANE_INTERNALS = Symbol.for("@simon_he/vue-tui:v1:terminal-plane-internals"), TERMINAL_ROOT = Symbol.for("@simon_he/vue-tui:v1:terminal-root");
|
|
@@ -1928,6 +1812,10 @@ function createTerminalGraphicPngSequence(options) {
|
|
|
1928
1812
|
);
|
|
1929
1813
|
crop && (placement = { ...placement, ...crop });
|
|
1930
1814
|
}
|
|
1815
|
+
let transmissionPlacement = options.cropTransmission !== !1 ? placement : {
|
|
1816
|
+
columns: options.transmissionColumns ?? options.placementColumns,
|
|
1817
|
+
rows: options.transmissionRows ?? options.placementRows
|
|
1818
|
+
};
|
|
1931
1819
|
return {
|
|
1932
1820
|
type: "sequence",
|
|
1933
1821
|
protocol: "kitty",
|
|
@@ -1935,7 +1823,7 @@ function createTerminalGraphicPngSequence(options) {
|
|
|
1935
1823
|
imageId: options.imageId,
|
|
1936
1824
|
placementId: options.placementId,
|
|
1937
1825
|
zIndex: options.zIndex,
|
|
1938
|
-
...
|
|
1826
|
+
...transmissionPlacement
|
|
1939
1827
|
}),
|
|
1940
1828
|
resizeSequence: createKittyPlacementSequence({
|
|
1941
1829
|
imageId: options.imageId,
|
|
@@ -2154,6 +2042,106 @@ function svgRenderFunction(mod) {
|
|
|
2154
2042
|
return candidate;
|
|
2155
2043
|
return null;
|
|
2156
2044
|
}
|
|
2045
|
+
function resolveMermaidSvgForResvg(svg, fallbackBg, fallbackFg) {
|
|
2046
|
+
let { bg, fg } = extractSvgRootStyleColors(svg, fallbackBg, fallbackFg), variables = extractSvgCssVariables(svg), root = { bg, fg }, resolved = svg, guard = 0;
|
|
2047
|
+
for (; (resolved.includes("var(") || resolved.includes("color-mix(")) && guard++ < 500; ) {
|
|
2048
|
+
let varIndex = resolved.lastIndexOf("var("), mixIndex = resolved.lastIndexOf("color-mix("), at = Math.max(varIndex, mixIndex);
|
|
2049
|
+
if (at < 0)
|
|
2050
|
+
break;
|
|
2051
|
+
let open = resolved.indexOf("(", at), close = findMatchingSvgParen(resolved, open);
|
|
2052
|
+
if (open < 0 || close < 0)
|
|
2053
|
+
break;
|
|
2054
|
+
let expr = resolved.slice(at, close + 1), color = resolveSvgColorExpr(expr, root, variables);
|
|
2055
|
+
resolved = resolved.slice(0, at) + color + resolved.slice(close + 1);
|
|
2056
|
+
}
|
|
2057
|
+
return stripSvgStyleBlocks(resolved);
|
|
2058
|
+
}
|
|
2059
|
+
function extractSvgRootStyleColors(svg, fallbackBg, fallbackFg) {
|
|
2060
|
+
let bg = fallbackBg, fg = fallbackFg, styleMatch = /<svg\b[^>]*\bstyle="([^"]*)"/i.exec(svg);
|
|
2061
|
+
if (styleMatch?.[1]) {
|
|
2062
|
+
let bgMatch = /(?:^|;)\s*--bg\s*:\s*([^;]+)/i.exec(styleMatch[1]), fgMatch = /(?:^|;)\s*--fg\s*:\s*([^;]+)/i.exec(styleMatch[1]);
|
|
2063
|
+
bgMatch?.[1] && (bg = bgMatch[1].trim()), fgMatch?.[1] && (fg = fgMatch[1].trim());
|
|
2064
|
+
}
|
|
2065
|
+
return { bg, fg };
|
|
2066
|
+
}
|
|
2067
|
+
function extractSvgCssVariables(svg) {
|
|
2068
|
+
let map = /* @__PURE__ */ new Map(), styleMatch = /<style[^>]*>([\s\S]*?)<\/style>/i.exec(svg);
|
|
2069
|
+
if (!styleMatch?.[1])
|
|
2070
|
+
return map;
|
|
2071
|
+
let declaration = /(--[A-Za-z0-9_-]+)\s*:\s*([^;{}]+);/g, match;
|
|
2072
|
+
for (; (match = declaration.exec(styleMatch[1])) !== null; )
|
|
2073
|
+
map.set(match[1], match[2].trim());
|
|
2074
|
+
return map;
|
|
2075
|
+
}
|
|
2076
|
+
function stripSvgStyleBlocks(svg) {
|
|
2077
|
+
return svg.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "");
|
|
2078
|
+
}
|
|
2079
|
+
function findMatchingSvgParen(input, openIndex) {
|
|
2080
|
+
let depth = 0;
|
|
2081
|
+
for (let i = openIndex; i < input.length; i++) {
|
|
2082
|
+
let ch = input[i];
|
|
2083
|
+
if (ch === "(")
|
|
2084
|
+
depth++;
|
|
2085
|
+
else if (ch === ")" && (depth--, depth === 0))
|
|
2086
|
+
return i;
|
|
2087
|
+
}
|
|
2088
|
+
return -1;
|
|
2089
|
+
}
|
|
2090
|
+
function findTopLevelSvgComma(input) {
|
|
2091
|
+
let depth = 0;
|
|
2092
|
+
for (let i = 0; i < input.length; i++) {
|
|
2093
|
+
let ch = input[i];
|
|
2094
|
+
if (ch === "(")
|
|
2095
|
+
depth++;
|
|
2096
|
+
else if (ch === ")")
|
|
2097
|
+
depth--;
|
|
2098
|
+
else if (ch === "," && depth === 0)
|
|
2099
|
+
return i;
|
|
2100
|
+
}
|
|
2101
|
+
return -1;
|
|
2102
|
+
}
|
|
2103
|
+
function normalizeHexColor(value) {
|
|
2104
|
+
let match = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(value.trim());
|
|
2105
|
+
if (!match)
|
|
2106
|
+
return null;
|
|
2107
|
+
let hex = match[1];
|
|
2108
|
+
return hex.length === 3 && (hex = hex.split("").map((ch) => ch + ch).join("")), `#${hex.toLowerCase()}`;
|
|
2109
|
+
}
|
|
2110
|
+
function mixSrgbColors(aHex, bHex, percent) {
|
|
2111
|
+
let a = parseHexRgb(aHex), b = parseHexRgb(bHex), p = Math.max(0, Math.min(100, percent)) / 100, mix = (x, y) => Math.round(x * p + y * (1 - p)), toHex = (value) => value.toString(16).padStart(2, "0");
|
|
2112
|
+
return `#${toHex(mix(a[0], b[0]))}${toHex(mix(a[1], b[1]))}${toHex(mix(a[2], b[2]))}`;
|
|
2113
|
+
}
|
|
2114
|
+
function parseHexRgb(hex) {
|
|
2115
|
+
return [
|
|
2116
|
+
parseInt(hex.slice(1, 3), 16),
|
|
2117
|
+
parseInt(hex.slice(3, 5), 16),
|
|
2118
|
+
parseInt(hex.slice(5, 7), 16)
|
|
2119
|
+
];
|
|
2120
|
+
}
|
|
2121
|
+
function resolveSvgColorExpr(expr, root, variables) {
|
|
2122
|
+
let value = expr.trim();
|
|
2123
|
+
if (value.startsWith("var(")) {
|
|
2124
|
+
let close = findMatchingSvgParen(value, 3);
|
|
2125
|
+
if (close < 0)
|
|
2126
|
+
return value;
|
|
2127
|
+
let inner = value.slice(4, close).trim(), comma = findTopLevelSvgComma(inner), name = (comma < 0 ? inner : inner.slice(0, comma)).trim(), fallback = comma < 0 ? "" : inner.slice(comma + 1).trim(), direct = name === "--fg" ? root.fg : name === "--bg" ? root.bg : variables.get(name);
|
|
2128
|
+
return direct != null ? resolveSvgColorExpr(direct, root, variables) : fallback ? resolveSvgColorExpr(fallback, root, variables) : value;
|
|
2129
|
+
}
|
|
2130
|
+
if (value.startsWith("color-mix(")) {
|
|
2131
|
+
let close = findMatchingSvgParen(value, 9);
|
|
2132
|
+
if (close < 0)
|
|
2133
|
+
return value;
|
|
2134
|
+
let afterMethod = value.slice(10, close).trim().replace(/^in\s+srgb\s*,\s*/i, ""), comma = findTopLevelSvgComma(afterMethod);
|
|
2135
|
+
if (comma < 0)
|
|
2136
|
+
return value;
|
|
2137
|
+
let left = afterMethod.slice(0, comma).trim(), right = afterMethod.slice(comma + 1).trim(), leftMatch = /^([^%\s]+)\s+([\d.]+)%$/.exec(left) ?? /^([\d.]+)%\s+([^%\s]+)$/.exec(left);
|
|
2138
|
+
if (!leftMatch)
|
|
2139
|
+
return value;
|
|
2140
|
+
let a = normalizeHexColor(resolveSvgColorExpr(leftMatch[1], root, variables)), b = normalizeHexColor(resolveSvgColorExpr(right, root, variables));
|
|
2141
|
+
return !a || !b ? value : mixSrgbColors(a, b, Number(leftMatch[2]));
|
|
2142
|
+
}
|
|
2143
|
+
return normalizeHexColor(value) ?? value;
|
|
2144
|
+
}
|
|
2157
2145
|
function loadBuiltinMermaidRasterizer() {
|
|
2158
2146
|
return builtinRasterizerLoad || (builtinRasterizerLoad = (async () => {
|
|
2159
2147
|
try {
|
|
@@ -2176,7 +2164,7 @@ function loadBuiltinMermaidRasterizer() {
|
|
|
2176
2164
|
}), svgText = String(svg ?? "");
|
|
2177
2165
|
if (!svgText.includes("<svg"))
|
|
2178
2166
|
return null;
|
|
2179
|
-
let rendered = new Resvg(
|
|
2167
|
+
let resolvedSvg = resolveMermaidSvgForResvg(svgText, options.bg, options.fg), rendered = new Resvg(resolvedSvg, {
|
|
2180
2168
|
background: "rgba(0,0,0,0)"
|
|
2181
2169
|
}).render(), naturalWidth = positiveInt(rendered?.width), naturalHeight = positiveInt(rendered?.height), png = typeof rendered?.asPng == "function" ? rendered.asPng() : void 0;
|
|
2182
2170
|
if (!png || png.length < 8 || naturalWidth == null || naturalHeight == null)
|
|
@@ -2290,6 +2278,25 @@ var tMermaidImageProps = {
|
|
|
2290
2278
|
maxWidthCells: { type: Number, default: void 0 },
|
|
2291
2279
|
maxHeightCells: { type: Number, default: void 0 },
|
|
2292
2280
|
padding: { type: Number, default: void 0 },
|
|
2281
|
+
// Adaptive ANSI fallback. When the terminal has no graphics protocol (or the
|
|
2282
|
+
// image rasterizer fails for this source), the component renders the diagram
|
|
2283
|
+
// as ASCII text through a text renderer before falling back to the raw
|
|
2284
|
+
// source. Without a textRenderer the component stays image-or-raw.
|
|
2285
|
+
textRenderer: {
|
|
2286
|
+
type: Function,
|
|
2287
|
+
default: void 0
|
|
2288
|
+
},
|
|
2289
|
+
// Eligibility guard for the ANSI fallback; returning false keeps the raw
|
|
2290
|
+
// source visible (e.g. only render simple flowcharts as ASCII).
|
|
2291
|
+
shouldRenderSource: {
|
|
2292
|
+
type: Function,
|
|
2293
|
+
default: void 0
|
|
2294
|
+
},
|
|
2295
|
+
// Spacing/theme options forwarded to the ANSI text renderer.
|
|
2296
|
+
textOptions: {
|
|
2297
|
+
type: Object,
|
|
2298
|
+
default: void 0
|
|
2299
|
+
},
|
|
2293
2300
|
// Box chrome (mirrors TMermaidText).
|
|
2294
2301
|
box: { type: Boolean, default: !0 },
|
|
2295
2302
|
title: { type: String, default: "mermaid" },
|
|
@@ -2302,15 +2309,28 @@ var tMermaidImageProps = {
|
|
|
2302
2309
|
maxRenderSourceLines: { type: Number, default: DEFAULT_MERMAID_IMAGE_MAX_RENDER_SOURCE_LINES },
|
|
2303
2310
|
// Clicking the diagram (or the copy button) copies the full raw mermaid source.
|
|
2304
2311
|
copyOnClick: { type: Boolean, default: !0 },
|
|
2305
|
-
ascii: { type: Boolean, default: !1 }
|
|
2306
|
-
|
|
2312
|
+
ascii: { type: Boolean, default: !1 },
|
|
2313
|
+
// Wheel zoom (Kitty graphics only): with the zoom modifier held, wheel over
|
|
2314
|
+
// the image zooms centered on the mouse, clamped to the container area.
|
|
2315
|
+
// Without the modifier the wheel passes through to the surrounding scroll
|
|
2316
|
+
// container (historical-message scrolling is never blocked). iTerm2 has no
|
|
2317
|
+
// in-place resize sequence, so zoom stays disabled there.
|
|
2318
|
+
zoomOnWheel: { type: Boolean, default: !0 },
|
|
2319
|
+
zoomModifier: {
|
|
2320
|
+
type: String,
|
|
2321
|
+
default: "metaCtrl"
|
|
2322
|
+
},
|
|
2323
|
+
minZoom: { type: Number, default: 1 },
|
|
2324
|
+
maxZoom: { type: Number, default: 6 },
|
|
2325
|
+
zoomSensitivity: { type: Number, default: 2e-3 }
|
|
2326
|
+
}, TMermaidImage = (0, import_vue9.defineComponent)({
|
|
2307
2327
|
name: "TMermaidImage",
|
|
2308
2328
|
props: tMermaidImageProps,
|
|
2309
2329
|
emits: {
|
|
2310
2330
|
copy: (_payload) => !0
|
|
2311
2331
|
},
|
|
2312
2332
|
setup(props, { emit }) {
|
|
2313
|
-
let instance = (0,
|
|
2333
|
+
let instance = (0, import_vue9.getCurrentInstance)(), terminalContext = useTerminal(), { terminal, defaultStyle, scheduler, widthProvider } = terminalContext, layout = useLayout(), { visible, rootProps } = useVisibility(), parentEventZ = (0, import_vue9.inject)(EventZIndexContextKey, (0, import_vue9.computed)(() => 0)), imageCells = (0, import_vue9.shallowRef)(null), textSnapshot = (0, import_vue9.shallowRef)(null), zoomScale = (0, import_vue9.shallowRef)(1), panX = (0, import_vue9.shallowRef)(0), panY = (0, import_vue9.shallowRef)(0), documentVersion = (0, import_vue9.shallowRef)(0), copied = (0, import_vue9.shallowRef)(!1), dragState = null, dragMoved = !1, lastDragAt = 0, DRAG_CLICK_SUPPRESS_MS = 250, builtOnce = !1, renderVersion = 0, alive = !0, frameTaskId = `TMermaidImage:${instance?.uid ?? "unknown"}:mermaid-image`, uid = instance?.uid ?? 0, copiedTimer = null, copyRequestVersion = 0, activeGraphicId = null, activeImageSignature = "", source = (0, import_vue9.computed)(() => props.code ?? props.content ?? ""), waitingForStreamingSourceToFinish = (0, import_vue9.computed)(() => props.streaming && !props.final), graphicsOutputVersion = (0, import_vue9.shallowRef)(getTerminalGraphicsOutputVersion(terminal)), graphicsOutput = (0, import_vue9.computed)(() => (graphicsOutputVersion.value, getTerminalGraphicsOutput(terminal))), graphicsProtocol = (0, import_vue9.computed)(() => {
|
|
2314
2334
|
let output = graphicsOutput.value;
|
|
2315
2335
|
if (!output?.capabilities.supported)
|
|
2316
2336
|
return null;
|
|
@@ -2353,15 +2373,51 @@ var tMermaidImageProps = {
|
|
|
2353
2373
|
} catch {
|
|
2354
2374
|
}
|
|
2355
2375
|
}
|
|
2356
|
-
|
|
2376
|
+
function clampZoom(zoom) {
|
|
2377
|
+
let min = Number.isFinite(Number(props.minZoom)) ? Math.max(0.05, Number(props.minZoom)) : 1, max = Number.isFinite(Number(props.maxZoom)) ? Math.max(min, Number(props.maxZoom)) : Math.max(min, 6);
|
|
2378
|
+
return Math.min(max, Math.max(min, zoom));
|
|
2379
|
+
}
|
|
2380
|
+
function zoomSensitivity() {
|
|
2381
|
+
let value = Number(props.zoomSensitivity);
|
|
2382
|
+
return Number.isFinite(value) && value > 0 ? value : 2e-3;
|
|
2383
|
+
}
|
|
2384
|
+
function wheelZoomFactor(deltaY, deltaMode) {
|
|
2385
|
+
let sign = deltaY > 0 ? -1 : 1, sensitivity = zoomSensitivity(), abs = Math.abs(deltaY), magnitude = (deltaMode ?? 0) === 1 || abs > 0 && abs <= 3 && Number.isInteger(deltaY) ? 100 : abs;
|
|
2386
|
+
return Math.exp(sign * magnitude * sensitivity);
|
|
2387
|
+
}
|
|
2388
|
+
function resetZoomState() {
|
|
2389
|
+
zoomScale.value === 1 && panX.value === 0 && panY.value === 0 || (zoomScale.value = 1, panX.value = 0, panY.value = 0, dragState = null);
|
|
2390
|
+
}
|
|
2391
|
+
function hasZoomModifier(event) {
|
|
2392
|
+
let modifier = props.zoomModifier ?? "metaCtrl";
|
|
2393
|
+
return modifier === "none" ? !0 : modifier === "meta" ? event.metaKey === !0 : modifier === "ctrl" ? event.ctrlKey === !0 : event.ctrlKey === !0 || event.metaKey === !0;
|
|
2394
|
+
}
|
|
2395
|
+
function clampPan() {
|
|
2396
|
+
let inner = innerRectFrom(fullRect.value), fit = displayFit.value;
|
|
2397
|
+
if (!fit || inner.w <= 0 || inner.h <= 0)
|
|
2398
|
+
return;
|
|
2399
|
+
let zoom = clampZoom(zoomScale.value), fullW = fit.displayW * zoom, fullH = fit.displayH * zoom, fitOriginX = inner.x + (inner.w > fit.displayW ? Math.floor((inner.w - fit.displayW) / 2) : 0), nextX = panX.value, nextY = panY.value;
|
|
2400
|
+
fullW <= inner.w ? nextX = 0 : nextX = Math.min(
|
|
2401
|
+
inner.x - fitOriginX,
|
|
2402
|
+
Math.max(inner.x + inner.w - fullW - fitOriginX, nextX)
|
|
2403
|
+
), fullH <= inner.h ? nextY = 0 : nextY = Math.min(0, Math.max(inner.h - fullH, nextY)), nextX !== panX.value && (panX.value = nextX), nextY !== panY.value && (panY.value = nextY);
|
|
2404
|
+
}
|
|
2405
|
+
function setImageCells(cells) {
|
|
2406
|
+
let signature = cells ? cells.base64 : "";
|
|
2407
|
+
signature !== activeImageSignature && (activeImageSignature = signature, resetZoomState()), imageCells.value = cells;
|
|
2408
|
+
}
|
|
2409
|
+
let hasBox = (0, import_vue9.computed)(() => props.box !== !1), normalizedWidth = (0, import_vue9.computed)(() => {
|
|
2357
2410
|
let width = Math.floor(Number(props.w));
|
|
2358
2411
|
return Number.isFinite(width) ? Math.max(0, width) : 0;
|
|
2359
|
-
}), reservesBoxRows = (0,
|
|
2412
|
+
}), reservesBoxRows = (0, import_vue9.computed)(() => hasBox.value && normalizedWidth.value >= 2), boxChars = (0, import_vue9.computed)(
|
|
2360
2413
|
() => props.ascii ? ASCII_MERMAID_IMAGE_BOX_CHARS : UNICODE_MERMAID_IMAGE_BOX_CHARS
|
|
2361
|
-
), sourceLines = (0,
|
|
2414
|
+
), sourceLines = (0, import_vue9.computed)(() => splitRenderedOutput2(source.value)), displayLines = (0, import_vue9.computed)(() => {
|
|
2415
|
+
let snapshot = textSnapshot.value;
|
|
2416
|
+
return snapshot && snapshot.source === source.value && hasVisibleTextOutput(snapshot.lines) ? snapshot.lines : sourceLines.value;
|
|
2417
|
+
}), currentStyle = (0, import_vue9.computed)(() => props.style ?? defaultStyle.value), innerWidth = (0, import_vue9.computed)(() => {
|
|
2362
2418
|
let w = normalizedWidth.value;
|
|
2363
2419
|
return reservesBoxRows.value ? Math.max(0, w - 2) : w;
|
|
2364
|
-
}), fixedInnerHeight = (0,
|
|
2420
|
+
}), fixedInnerHeight = (0, import_vue9.computed)(() => {
|
|
2365
2421
|
if (props.h == null)
|
|
2366
2422
|
return 0;
|
|
2367
2423
|
let h4 = Math.floor(Number(props.h));
|
|
@@ -2369,23 +2425,23 @@ var tMermaidImageProps = {
|
|
|
2369
2425
|
return 0;
|
|
2370
2426
|
let value = Math.max(0, h4);
|
|
2371
2427
|
return reservesBoxRows.value ? Math.max(0, value - 2) : value;
|
|
2372
|
-
}), autoHeight = (0,
|
|
2428
|
+
}), autoHeight = (0, import_vue9.computed)(() => props.h == null), displayFit = (0, import_vue9.computed)(() => {
|
|
2373
2429
|
let cells = imageCells.value;
|
|
2374
2430
|
return cells ? autoHeight.value ? fitImageCells(cells, innerWidth.value, Number.MAX_SAFE_INTEGER) : fitImageCells(cells, innerWidth.value, fixedInnerHeight.value) : null;
|
|
2375
|
-
}), contentHeight = (0,
|
|
2431
|
+
}), contentHeight = (0, import_vue9.computed)(() => autoHeight.value ? displayFit.value?.displayH ?? Math.max(1, displayLines.value.length) : fixedInnerHeight.value), fullHeight = (0, import_vue9.computed)(() => {
|
|
2376
2432
|
if (props.h != null) {
|
|
2377
2433
|
let h4 = Math.floor(Number(props.h));
|
|
2378
2434
|
return Number.isFinite(h4) ? Math.max(0, h4) : 0;
|
|
2379
2435
|
}
|
|
2380
2436
|
return reservesBoxRows.value ? contentHeight.value + 2 : contentHeight.value;
|
|
2381
|
-
}), fullRect = (0,
|
|
2437
|
+
}), fullRect = (0, import_vue9.computed)(() => translateRect(
|
|
2382
2438
|
{ x: props.x, y: props.y, w: props.w, h: fullHeight.value },
|
|
2383
2439
|
layout.originX,
|
|
2384
2440
|
layout.originY
|
|
2385
|
-
)), absRect = (0,
|
|
2441
|
+
)), absRect = (0, import_vue9.computed)(() => {
|
|
2386
2442
|
let translated = fullRect.value;
|
|
2387
2443
|
return layout.clipRect ? intersectRect(translated, layout.clipRect) ?? { x: 0, y: 0, w: 0, h: 0 } : translated;
|
|
2388
|
-
}), copyLabel = (0,
|
|
2444
|
+
}), copyLabel = (0, import_vue9.computed)(() => copied.value ? props.copiedText : props.copyText);
|
|
2389
2445
|
function cellWidth(value) {
|
|
2390
2446
|
return withTextWidthProvider(widthProvider, () => textCellWidth(value));
|
|
2391
2447
|
}
|
|
@@ -2414,6 +2470,60 @@ var tMermaidImageProps = {
|
|
|
2414
2470
|
padding: props.padding
|
|
2415
2471
|
});
|
|
2416
2472
|
}
|
|
2473
|
+
function hasVisibleTextOutput(lines) {
|
|
2474
|
+
return lines.some((line) => line.trim().length > 0);
|
|
2475
|
+
}
|
|
2476
|
+
function resolveTextOptions() {
|
|
2477
|
+
return {
|
|
2478
|
+
...props.textOptions ?? {},
|
|
2479
|
+
useAscii: props.ascii,
|
|
2480
|
+
colorMode: "none"
|
|
2481
|
+
};
|
|
2482
|
+
}
|
|
2483
|
+
function textRenderSignature(code) {
|
|
2484
|
+
return [
|
|
2485
|
+
code,
|
|
2486
|
+
props.ascii ? "a" : "",
|
|
2487
|
+
JSON.stringify(props.textOptions ?? null),
|
|
2488
|
+
props.textRenderer != null ? "r" : "",
|
|
2489
|
+
props.shouldRenderSource != null ? "g" : ""
|
|
2490
|
+
].join("");
|
|
2491
|
+
}
|
|
2492
|
+
async function renderTextWithTimeout(renderer, code, options) {
|
|
2493
|
+
let timeoutMs = normalizeNonNegativeInt2(props.renderTimeoutMs, 0);
|
|
2494
|
+
if (timeoutMs <= 0)
|
|
2495
|
+
return await renderer(code, options);
|
|
2496
|
+
let timer = null;
|
|
2497
|
+
try {
|
|
2498
|
+
return await Promise.race([
|
|
2499
|
+
Promise.resolve().then(() => renderer(code, options)),
|
|
2500
|
+
new Promise((_resolve, reject) => {
|
|
2501
|
+
timer = setTimeout(() => reject(new Error("Mermaid text render timeout")), timeoutMs);
|
|
2502
|
+
})
|
|
2503
|
+
]);
|
|
2504
|
+
} finally {
|
|
2505
|
+
timer != null && clearTimeout(timer);
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
async function runCustomRasterizer(code, options) {
|
|
2509
|
+
let renderer = props.renderer;
|
|
2510
|
+
if (!renderer)
|
|
2511
|
+
return null;
|
|
2512
|
+
let timeoutMs = normalizeNonNegativeInt2(props.renderTimeoutMs, 0), run = () => renderer(code, options);
|
|
2513
|
+
if (timeoutMs <= 0)
|
|
2514
|
+
return await run() ?? null;
|
|
2515
|
+
let timer = null;
|
|
2516
|
+
try {
|
|
2517
|
+
return await Promise.race([
|
|
2518
|
+
run(),
|
|
2519
|
+
new Promise((resolve) => {
|
|
2520
|
+
timer = setTimeout(() => resolve(null), timeoutMs);
|
|
2521
|
+
})
|
|
2522
|
+
]) ?? null;
|
|
2523
|
+
} finally {
|
|
2524
|
+
timer != null && clearTimeout(timer);
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2417
2527
|
function shouldSkipRenderForSize(code) {
|
|
2418
2528
|
let maxChars = normalizeNonNegativeInt2(
|
|
2419
2529
|
props.maxRenderSourceChars,
|
|
@@ -2443,46 +2553,87 @@ var tMermaidImageProps = {
|
|
|
2443
2553
|
timer != null && clearTimeout(timer);
|
|
2444
2554
|
}
|
|
2445
2555
|
}
|
|
2446
|
-
async function
|
|
2556
|
+
async function renderTextFallback(version) {
|
|
2557
|
+
let code = source.value, renderer = props.textRenderer;
|
|
2558
|
+
if (!renderer)
|
|
2559
|
+
return;
|
|
2560
|
+
let guard = props.shouldRenderSource;
|
|
2561
|
+
if (guard) {
|
|
2562
|
+
let eligible = !1;
|
|
2563
|
+
try {
|
|
2564
|
+
eligible = guard(code, { final: props.final, streaming: props.streaming });
|
|
2565
|
+
} catch {
|
|
2566
|
+
eligible = !1;
|
|
2567
|
+
}
|
|
2568
|
+
if (!eligible)
|
|
2569
|
+
return;
|
|
2570
|
+
}
|
|
2571
|
+
try {
|
|
2572
|
+
let rendered = await renderTextWithTimeout(renderer, code, resolveTextOptions());
|
|
2573
|
+
if (!alive || version !== renderVersion)
|
|
2574
|
+
return;
|
|
2575
|
+
let lines = splitRenderedOutput2(rendered);
|
|
2576
|
+
if (!hasVisibleTextOutput(lines))
|
|
2577
|
+
return;
|
|
2578
|
+
textSnapshot.value = (0, import_vue9.markRaw)({
|
|
2579
|
+
source: code,
|
|
2580
|
+
signature: textRenderSignature(code),
|
|
2581
|
+
lines: (0, import_vue9.markRaw)(lines)
|
|
2582
|
+
}), bump();
|
|
2583
|
+
} catch {
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
async function renderPresentation(version) {
|
|
2447
2587
|
let code = source.value;
|
|
2448
2588
|
if (!code.trim()) {
|
|
2449
2589
|
if (!alive || version !== renderVersion)
|
|
2450
2590
|
return;
|
|
2451
|
-
|
|
2591
|
+
setImageCells(null), textSnapshot.value = null, bump();
|
|
2452
2592
|
return;
|
|
2453
2593
|
}
|
|
2454
2594
|
if (waitingForStreamingSourceToFinish.value || shouldSkipRenderForSize(code)) {
|
|
2455
2595
|
if (!alive || version !== renderVersion)
|
|
2456
2596
|
return;
|
|
2457
|
-
|
|
2597
|
+
setImageCells(null), textSnapshot.value = null, bump();
|
|
2458
2598
|
return;
|
|
2459
2599
|
}
|
|
2460
|
-
|
|
2461
|
-
return;
|
|
2462
|
-
let options = resolveImageOptions(), cached = getCachedMermaidImage(code, options);
|
|
2600
|
+
let protocol = graphicsProtocol.value, options = resolveImageOptions(), cached = protocol && !props.renderer ? getCachedMermaidImage(code, options) : null;
|
|
2463
2601
|
if (cached) {
|
|
2464
2602
|
if (!alive || version !== renderVersion)
|
|
2465
2603
|
return;
|
|
2466
|
-
|
|
2604
|
+
setImageCells(cached), textSnapshot.value = null, bump();
|
|
2467
2605
|
return;
|
|
2468
2606
|
}
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2607
|
+
let currentSignature = textRenderSignature(code), keepText = textSnapshot.value != null && textSnapshot.value.source === code && textSnapshot.value.signature === currentSignature;
|
|
2608
|
+
if (keepText || (setImageCells(null), textSnapshot.value = null, bump()), protocol) {
|
|
2609
|
+
let result = null;
|
|
2610
|
+
if (props.renderer)
|
|
2611
|
+
result = await runCustomRasterizer(code, options);
|
|
2612
|
+
else if (isMermaidImageRendererReady())
|
|
2613
|
+
result = await rasterizeWithTimeout(code, options);
|
|
2614
|
+
else {
|
|
2615
|
+
loadMermaidImageRenderer().then((ready) => {
|
|
2616
|
+
!alive || version !== renderVersion || !ready || renderPresentation(version);
|
|
2617
|
+
});
|
|
2618
|
+
return;
|
|
2619
|
+
}
|
|
2620
|
+
if (!alive || version !== renderVersion)
|
|
2621
|
+
return;
|
|
2622
|
+
if (result) {
|
|
2623
|
+
setImageCells(result), textSnapshot.value = null, bump();
|
|
2624
|
+
return;
|
|
2625
|
+
}
|
|
2474
2626
|
}
|
|
2475
|
-
|
|
2476
|
-
!alive || version !== renderVersion || (imageCells.value = result, bump());
|
|
2627
|
+
keepText || await renderTextFallback(version);
|
|
2477
2628
|
}
|
|
2478
2629
|
function scheduleRender() {
|
|
2479
2630
|
let version = ++renderVersion;
|
|
2480
|
-
if (resetCopyFeedback(!1),
|
|
2631
|
+
if (resetCopyFeedback(!1), setImageCells(null), waitingForStreamingSourceToFinish.value) {
|
|
2481
2632
|
builtOnce = !0, scheduler.cancelFrameTask?.(frameTaskId), bump();
|
|
2482
2633
|
return;
|
|
2483
2634
|
}
|
|
2484
2635
|
if (!builtOnce || !props.streaming) {
|
|
2485
|
-
builtOnce = !0,
|
|
2636
|
+
builtOnce = !0, renderPresentation(version);
|
|
2486
2637
|
return;
|
|
2487
2638
|
}
|
|
2488
2639
|
scheduler.queueFrameTask({
|
|
@@ -2491,11 +2642,11 @@ var tMermaidImageProps = {
|
|
|
2491
2642
|
priority: "low",
|
|
2492
2643
|
sync: !1,
|
|
2493
2644
|
run: () => {
|
|
2494
|
-
alive && version === renderVersion &&
|
|
2645
|
+
alive && version === renderVersion && renderPresentation(version);
|
|
2495
2646
|
}
|
|
2496
|
-
}) === !1 &&
|
|
2647
|
+
}) === !1 && renderPresentation(version);
|
|
2497
2648
|
}
|
|
2498
|
-
(0,
|
|
2649
|
+
(0, import_vue9.watch)(
|
|
2499
2650
|
[
|
|
2500
2651
|
source,
|
|
2501
2652
|
() => props.renderer,
|
|
@@ -2511,7 +2662,11 @@ var tMermaidImageProps = {
|
|
|
2511
2662
|
() => props.final,
|
|
2512
2663
|
() => props.maxRenderSourceChars,
|
|
2513
2664
|
() => props.maxRenderSourceLines,
|
|
2514
|
-
|
|
2665
|
+
() => props.textRenderer,
|
|
2666
|
+
() => props.shouldRenderSource,
|
|
2667
|
+
() => props.textOptions,
|
|
2668
|
+
() => props.ascii,
|
|
2669
|
+
() => props.zoomModifier
|
|
2515
2670
|
],
|
|
2516
2671
|
() => {
|
|
2517
2672
|
scheduleRender();
|
|
@@ -2519,11 +2674,14 @@ var tMermaidImageProps = {
|
|
|
2519
2674
|
{ immediate: !0, deep: !0 }
|
|
2520
2675
|
);
|
|
2521
2676
|
let unsubscribeMermaidImage = subscribeMermaidImage(() => {
|
|
2522
|
-
alive
|
|
2677
|
+
if (!alive || !graphicsProtocol.value || props.renderer)
|
|
2678
|
+
return;
|
|
2679
|
+
let cached = getCachedMermaidImage(source.value, resolveImageOptions());
|
|
2680
|
+
cached && alive && (setImageCells(cached), textSnapshot.value = null, bump());
|
|
2523
2681
|
}), unsubscribeGraphicsOutput = subscribeTerminalGraphicsOutput(terminal, () => {
|
|
2524
2682
|
alive && (graphicsOutputVersion.value = getTerminalGraphicsOutputVersion(terminal), scheduleRender());
|
|
2525
2683
|
});
|
|
2526
|
-
(0,
|
|
2684
|
+
(0, import_vue9.onBeforeUnmount)(() => {
|
|
2527
2685
|
alive = !1, renderVersion++, clearCopiedTimer(), queueClearGraphic(), unsubscribeMermaidImage(), unsubscribeGraphicsOutput(), scheduler.cancelFrameTask?.(frameTaskId);
|
|
2528
2686
|
});
|
|
2529
2687
|
function canDrawBox(width, height) {
|
|
@@ -2583,7 +2741,7 @@ var tMermaidImageProps = {
|
|
|
2583
2741
|
return rowIndex === rowHeight - 1 ? `${chars.bl}${repeatChar(chars.h, innerW)}${chars.br}` : `${chars.v}${contentLine(rowIndex - 1, innerW, !0)}${chars.v}`;
|
|
2584
2742
|
}
|
|
2585
2743
|
function contentLine(rowIndex, width, pad) {
|
|
2586
|
-
let src = imageCells.value != null && displayFit.value != null && graphicsProtocol.value != null ? spaces(width) :
|
|
2744
|
+
let src = imageCells.value != null && displayFit.value != null && graphicsProtocol.value != null ? spaces(width) : displayLines.value[rowIndex] ?? "", clipped = sliceCells(src, width);
|
|
2587
2745
|
return pad ? padCells(clipped, width) : clipped;
|
|
2588
2746
|
}
|
|
2589
2747
|
function innerRectFrom(full) {
|
|
@@ -2601,11 +2759,21 @@ var tMermaidImageProps = {
|
|
|
2601
2759
|
queueClearGraphic();
|
|
2602
2760
|
return;
|
|
2603
2761
|
}
|
|
2604
|
-
let
|
|
2605
|
-
x: inner.x +
|
|
2606
|
-
y: inner.y,
|
|
2607
|
-
w:
|
|
2608
|
-
h:
|
|
2762
|
+
let zoom = clampZoom(zoomScale.value), fitW = fit.displayW, fitH = fit.displayH, fullRect2 = {
|
|
2763
|
+
x: inner.x + (inner.w > fitW ? Math.floor((inner.w - fitW) / 2) : 0) + panX.value,
|
|
2764
|
+
y: inner.y + panY.value,
|
|
2765
|
+
w: fitW * zoom,
|
|
2766
|
+
h: fitH * zoom
|
|
2767
|
+
}, visible2 = intersectRect(fullRect2, inner);
|
|
2768
|
+
if (!visible2 || visible2.w < 1 || visible2.h < 1) {
|
|
2769
|
+
queueClearGraphic();
|
|
2770
|
+
return;
|
|
2771
|
+
}
|
|
2772
|
+
let rectX = Math.max(inner.x, Math.round(visible2.x)), rectY = Math.max(inner.y, Math.round(visible2.y)), rect = {
|
|
2773
|
+
x: rectX,
|
|
2774
|
+
y: rectY,
|
|
2775
|
+
w: Math.max(1, Math.min(inner.x + inner.w, rectX + Math.round(visible2.w)) - rectX),
|
|
2776
|
+
h: Math.max(1, Math.min(inner.y + inner.h, rectY + Math.round(visible2.h)) - rectY)
|
|
2609
2777
|
}, imageId = stableTerminalGraphicNumericId(`mermaid-image:${uid}:${renderVersion}:img`), placementId = stableTerminalGraphicNumericId(
|
|
2610
2778
|
`mermaid-image:${uid}:${renderVersion}:plc`
|
|
2611
2779
|
), built = createTerminalGraphicPngSequence({
|
|
@@ -2617,10 +2785,16 @@ var tMermaidImageProps = {
|
|
|
2617
2785
|
rows: cells.heightCells,
|
|
2618
2786
|
sourceWidth: cells.naturalWidth,
|
|
2619
2787
|
sourceHeight: cells.naturalHeight,
|
|
2620
|
-
placementColumns:
|
|
2621
|
-
placementRows:
|
|
2788
|
+
placementColumns: rect.w,
|
|
2789
|
+
placementRows: rect.h,
|
|
2790
|
+
// Keep the initial transmission stable at the fit size without a
|
|
2791
|
+
// source crop so wheel zoom can replace the placement (a=p) without
|
|
2792
|
+
// re-sending the PNG, and every placement references the full image.
|
|
2793
|
+
transmissionColumns: fitW,
|
|
2794
|
+
transmissionRows: fitH,
|
|
2795
|
+
cropTransmission: !1,
|
|
2622
2796
|
rect,
|
|
2623
|
-
fullRect:
|
|
2797
|
+
fullRect: fullRect2,
|
|
2624
2798
|
zIndex: -1,
|
|
2625
2799
|
fallback: source.value
|
|
2626
2800
|
});
|
|
@@ -2644,16 +2818,19 @@ var tMermaidImageProps = {
|
|
|
2644
2818
|
id,
|
|
2645
2819
|
x: rect.x,
|
|
2646
2820
|
y: rect.y,
|
|
2647
|
-
w:
|
|
2648
|
-
h:
|
|
2821
|
+
w: rect.w,
|
|
2822
|
+
h: rect.h,
|
|
2649
2823
|
protocol,
|
|
2650
2824
|
sequence: built.sequence,
|
|
2651
2825
|
resizeSequence: built.resizeSequence,
|
|
2652
2826
|
clearSequence: built.clearSequence,
|
|
2653
|
-
fallbackText: source.value
|
|
2827
|
+
fallbackText: source.value,
|
|
2828
|
+
// Same image data + placement id: let the stdout renderer replace the
|
|
2829
|
+
// placement with the resize sequence instead of re-sending the PNG.
|
|
2830
|
+
placementMoveWithoutClear: protocol === "kitty"
|
|
2654
2831
|
}) ? activeGraphicId = id : queueClearGraphic();
|
|
2655
2832
|
}
|
|
2656
|
-
let copyHitRect = (0,
|
|
2833
|
+
let copyHitRect = (0, import_vue9.computed)(() => {
|
|
2657
2834
|
let full = fullRect.value;
|
|
2658
2835
|
if (!visible.value || !props.copyButton || !canDrawBox(full.w, full.h))
|
|
2659
2836
|
return { x: 0, y: 0, w: 0, h: 0 };
|
|
@@ -2667,8 +2844,8 @@ var tMermaidImageProps = {
|
|
|
2667
2844
|
h: 1
|
|
2668
2845
|
};
|
|
2669
2846
|
return layout.clipRect ? intersectRect(raw, layout.clipRect) ?? { x: 0, y: 0, w: 0, h: 0 } : raw;
|
|
2670
|
-
}), contentHitRect = (0,
|
|
2671
|
-
if (!visible.value
|
|
2847
|
+
}), contentHitRect = (0, import_vue9.computed)(() => {
|
|
2848
|
+
if (!visible.value)
|
|
2672
2849
|
return { x: 0, y: 0, w: 0, h: 0 };
|
|
2673
2850
|
let full = fullRect.value;
|
|
2674
2851
|
if (full.w <= 0 || full.h <= 0)
|
|
@@ -2706,12 +2883,52 @@ var tMermaidImageProps = {
|
|
|
2706
2883
|
requestVersion === copyRequestVersion && source.value === text && (ok ? showCopiedFeedback() : setCopied(!1)), emit("copy", ok ? { text, ok } : { text, ok, error: copyError });
|
|
2707
2884
|
}
|
|
2708
2885
|
function onCopyClick(event) {
|
|
2709
|
-
event.preventDefault(), event.stopPropagation(), copySource();
|
|
2886
|
+
event.preventDefault(), event.stopPropagation(), !(Date.now() - lastDragAt < DRAG_CLICK_SUPPRESS_MS) && copySource();
|
|
2710
2887
|
}
|
|
2711
2888
|
function onCopyKeydown(event) {
|
|
2712
2889
|
event.key !== "Enter" && event.key !== " " || (event.preventDefault(), event.stopPropagation(), copySource());
|
|
2713
2890
|
}
|
|
2714
|
-
let
|
|
2891
|
+
let zoomEnabled = (0, import_vue9.computed)(
|
|
2892
|
+
() => props.zoomOnWheel !== !1 && imageCells.value != null && displayFit.value != null && graphicsProtocol.value === "kitty" && contentHitRect.value.w > 0 && contentHitRect.value.h > 0
|
|
2893
|
+
), dragEnabled = (0, import_vue9.computed)(
|
|
2894
|
+
() => props.zoomOnWheel !== !1 && imageCells.value != null && displayFit.value != null && graphicsProtocol.value === "kitty" && zoomScale.value > 1 && contentHitRect.value.w > 0 && contentHitRect.value.h > 0
|
|
2895
|
+
);
|
|
2896
|
+
function onWheel(event) {
|
|
2897
|
+
if (!zoomEnabled.value || !hasZoomModifier(event))
|
|
2898
|
+
return;
|
|
2899
|
+
event.preventDefault(), event.stopPropagation();
|
|
2900
|
+
let deltaY = event.deltaY ?? 0;
|
|
2901
|
+
if (!Number.isFinite(deltaY) || deltaY === 0)
|
|
2902
|
+
return;
|
|
2903
|
+
let inner = innerRectFrom(fullRect.value), fit = displayFit.value;
|
|
2904
|
+
if (!fit || inner.w <= 0 || inner.h <= 0)
|
|
2905
|
+
return;
|
|
2906
|
+
let currentZoom = clampZoom(zoomScale.value), fitW = fit.displayW, fitH = fit.displayH, fitOriginX = inner.x + (inner.w > fitW ? Math.floor((inner.w - fitW) / 2) : 0), fullX = fitOriginX + panX.value, fullY = inner.y + panY.value, mouseX = event.cellX, mouseY = event.cellY, fx = currentZoom > 0 ? (mouseX - fullX) / (fitW * currentZoom) : 0.5, fy = currentZoom > 0 ? (mouseY - fullY) / (fitH * currentZoom) : 0.5, nextZoom = clampZoom(currentZoom * wheelZoomFactor(deltaY, event.deltaMode));
|
|
2907
|
+
if (nextZoom === currentZoom)
|
|
2908
|
+
return;
|
|
2909
|
+
let nextW = fitW * nextZoom, nextH = fitH * nextZoom, nextX = mouseX - fx * nextW, nextY = mouseY - fy * nextH;
|
|
2910
|
+
nextW <= inner.w ? nextX = inner.x + (inner.w - nextW) / 2 : nextX = Math.min(inner.x, Math.max(inner.x + inner.w - nextW, nextX)), nextH <= inner.h ? nextY = inner.y + (inner.h - nextH) / 2 : nextY = Math.min(inner.y, Math.max(inner.y + inner.h - nextH, nextY)), zoomScale.value = nextZoom, panX.value = nextX - fitOriginX, panY.value = nextY - inner.y, clampPan(), bump();
|
|
2911
|
+
}
|
|
2912
|
+
function onPointerDown(event) {
|
|
2913
|
+
dragEnabled.value && (event.preventDefault(), event.stopPropagation(), dragState = {
|
|
2914
|
+
startX: event.cellX,
|
|
2915
|
+
startY: event.cellY,
|
|
2916
|
+
panStartX: panX.value,
|
|
2917
|
+
panStartY: panY.value
|
|
2918
|
+
}, dragMoved = !1);
|
|
2919
|
+
}
|
|
2920
|
+
function onPointerMove(event) {
|
|
2921
|
+
let drag = dragState;
|
|
2922
|
+
if (!drag)
|
|
2923
|
+
return;
|
|
2924
|
+
event.preventDefault(), event.stopPropagation();
|
|
2925
|
+
let dx = event.cellX - drag.startX, dy = event.cellY - drag.startY;
|
|
2926
|
+
!dragMoved && Math.abs(dx) + Math.abs(dy) >= 1 && (dragMoved = !0), dragMoved && (panX.value = drag.panStartX + dx, panY.value = drag.panStartY + dy, clampPan(), bump());
|
|
2927
|
+
}
|
|
2928
|
+
function onPointerUp(event) {
|
|
2929
|
+
dragState && (event.preventDefault(), event.stopPropagation(), dragState = null, dragMoved && (lastDragAt = Date.now()));
|
|
2930
|
+
}
|
|
2931
|
+
let copyNodeActive = (0, import_vue9.computed)(
|
|
2715
2932
|
() => visible.value && props.copyButton && copyHitRect.value.w > 0 && copyHitRect.value.h > 0
|
|
2716
2933
|
);
|
|
2717
2934
|
useTerminalNode(() => ({
|
|
@@ -2725,8 +2942,8 @@ var tMermaidImageProps = {
|
|
|
2725
2942
|
keydown: onCopyKeydown
|
|
2726
2943
|
} : {}
|
|
2727
2944
|
}));
|
|
2728
|
-
let contentNodeActive = (0,
|
|
2729
|
-
() => visible.value && props.copyOnClick && contentHitRect.value.w > 0 && contentHitRect.value.h > 0
|
|
2945
|
+
let contentNodeActive = (0, import_vue9.computed)(
|
|
2946
|
+
() => visible.value && (props.copyOnClick || zoomEnabled.value || dragEnabled.value) && contentHitRect.value.w > 0 && contentHitRect.value.h > 0
|
|
2730
2947
|
);
|
|
2731
2948
|
return useTerminalNode(() => ({
|
|
2732
2949
|
rect: contentHitRect.value,
|
|
@@ -2735,7 +2952,11 @@ var tMermaidImageProps = {
|
|
|
2735
2952
|
focusable: !1,
|
|
2736
2953
|
selectable: !1,
|
|
2737
2954
|
handlers: contentNodeActive.value ? {
|
|
2738
|
-
click: onCopyClick
|
|
2955
|
+
click: props.copyOnClick ? onCopyClick : void 0,
|
|
2956
|
+
wheel: zoomEnabled.value ? onWheel : void 0,
|
|
2957
|
+
pointerdown: dragEnabled.value ? onPointerDown : void 0,
|
|
2958
|
+
pointermove: dragEnabled.value ? onPointerMove : void 0,
|
|
2959
|
+
pointerup: dragEnabled.value ? onPointerUp : void 0
|
|
2739
2960
|
} : {}
|
|
2740
2961
|
})), useRenderNode(() => ({
|
|
2741
2962
|
zIndex: props.zIndex,
|
|
@@ -2746,6 +2967,11 @@ var tMermaidImageProps = {
|
|
|
2746
2967
|
fullRect.value,
|
|
2747
2968
|
imageCells.value,
|
|
2748
2969
|
displayFit.value,
|
|
2970
|
+
zoomScale.value,
|
|
2971
|
+
panX.value,
|
|
2972
|
+
panY.value,
|
|
2973
|
+
textSnapshot.value,
|
|
2974
|
+
displayLines.value,
|
|
2749
2975
|
sourceLines.value,
|
|
2750
2976
|
currentStyle.value,
|
|
2751
2977
|
props.clear,
|
|
@@ -2788,6 +3014,148 @@ var tMermaidImageProps = {
|
|
|
2788
3014
|
paintRow(y);
|
|
2789
3015
|
});
|
|
2790
3016
|
}
|
|
2791
|
-
})), () => (0,
|
|
3017
|
+
})), () => (0, import_vue9.h)("span", rootProps);
|
|
2792
3018
|
}
|
|
2793
3019
|
});
|
|
3020
|
+
|
|
3021
|
+
// src/vue/mermaid/beautiful-mermaid.ts
|
|
3022
|
+
var BEAUTIFUL_MERMAID_INSTALL_HINT = "Install beautiful-mermaid and use TMermaidText from @simon_he/vue-tui/mermaid or @simon_he/vue-tui/agent/mermaid, or pass a custom renderer prop.", MISSING_BEAUTIFUL_MERMAID_ERROR_CODE = "VUE_TUI_MISSING_BEAUTIFUL_MERMAID", INVALID_BEAUTIFUL_MERMAID_EXPORT_ERROR_CODE = "VUE_TUI_INVALID_BEAUTIFUL_MERMAID_EXPORT", cachedBeautifulMermaid = null;
|
|
3023
|
+
function functionValue(value) {
|
|
3024
|
+
return typeof value == "function" ? value : null;
|
|
3025
|
+
}
|
|
3026
|
+
function functionProp(target, key) {
|
|
3027
|
+
if (!target || typeof target != "object" || !(key in target))
|
|
3028
|
+
return null;
|
|
3029
|
+
let value = target[key];
|
|
3030
|
+
return typeof value == "function" ? value : null;
|
|
3031
|
+
}
|
|
3032
|
+
function errorMessage(error) {
|
|
3033
|
+
return error instanceof Error ? error.message : String(error);
|
|
3034
|
+
}
|
|
3035
|
+
function codedError(message, code) {
|
|
3036
|
+
let error = new Error(message);
|
|
3037
|
+
return error.code = code, error;
|
|
3038
|
+
}
|
|
3039
|
+
function missingBeautifulMermaidError(error) {
|
|
3040
|
+
if (error && typeof error == "object" && errorCode(error) === MISSING_BEAUTIFUL_MERMAID_ERROR_CODE)
|
|
3041
|
+
return markMermaidRenderErrorFatal(error);
|
|
3042
|
+
let detail = errorMessage(error);
|
|
3043
|
+
return markMermaidRenderErrorFatal(
|
|
3044
|
+
codedError(
|
|
3045
|
+
`${BEAUTIFUL_MERMAID_INSTALL_HINT} (${detail})`,
|
|
3046
|
+
MISSING_BEAUTIFUL_MERMAID_ERROR_CODE
|
|
3047
|
+
)
|
|
3048
|
+
);
|
|
3049
|
+
}
|
|
3050
|
+
function errorCode(error) {
|
|
3051
|
+
if (!error || typeof error != "object")
|
|
3052
|
+
return "";
|
|
3053
|
+
let value = error.code;
|
|
3054
|
+
return typeof value == "string" ? value : "";
|
|
3055
|
+
}
|
|
3056
|
+
function errorCause(error) {
|
|
3057
|
+
if (!(!error || typeof error != "object"))
|
|
3058
|
+
return error.cause;
|
|
3059
|
+
}
|
|
3060
|
+
function isMissingBeautifulMermaid(error) {
|
|
3061
|
+
return isMissingBeautifulMermaidWithSeen(error, /* @__PURE__ */ new WeakSet());
|
|
3062
|
+
}
|
|
3063
|
+
function isMissingBeautifulMermaidWithSeen(error, seen) {
|
|
3064
|
+
if (error && typeof error == "object") {
|
|
3065
|
+
if (seen.has(error))
|
|
3066
|
+
return !1;
|
|
3067
|
+
seen.add(error);
|
|
3068
|
+
}
|
|
3069
|
+
let message = errorMessage(error), code = errorCode(error);
|
|
3070
|
+
if (code === MISSING_BEAUTIFUL_MERMAID_ERROR_CODE || (/Cannot find package ['"]beautiful-mermaid['"]/.test(message) || /Cannot find module ['"]beautiful-mermaid['"]/.test(message) || /Cannot resolve module ['"]beautiful-mermaid['"]/.test(message) || /Can't resolve ['"]beautiful-mermaid['"]/.test(message) || /Failed to resolve module specifier ['"]beautiful-mermaid['"]/.test(message) || /Failed to resolve import ['"]beautiful-mermaid['"]/.test(message) || /Could not resolve ['"]beautiful-mermaid['"]/.test(message)) && (code === "" || code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND" || code === "UNRESOLVED_IMPORT"))
|
|
3071
|
+
return !0;
|
|
3072
|
+
let cause = errorCause(error);
|
|
3073
|
+
return cause !== void 0 && isMissingBeautifulMermaidWithSeen(cause, seen);
|
|
3074
|
+
}
|
|
3075
|
+
function resolveBeautifulMermaidRenderer(mod) {
|
|
3076
|
+
let renderer = functionProp(mod, "renderMermaidASCII") ?? functionProp(mod, "renderMermaidAscii") ?? functionValue(mod.default) ?? functionProp(mod.default, "renderMermaidASCII") ?? functionProp(mod.default, "renderMermaidAscii");
|
|
3077
|
+
if (!renderer)
|
|
3078
|
+
throw markMermaidRenderErrorFatal(
|
|
3079
|
+
codedError(
|
|
3080
|
+
"beautiful-mermaid is installed but does not export renderMermaidASCII.",
|
|
3081
|
+
INVALID_BEAUTIFUL_MERMAID_EXPORT_ERROR_CODE
|
|
3082
|
+
)
|
|
3083
|
+
);
|
|
3084
|
+
return renderer;
|
|
3085
|
+
}
|
|
3086
|
+
function hasErrorCode(error, code, seen = /* @__PURE__ */ new WeakSet()) {
|
|
3087
|
+
if (!error || typeof error != "object" || seen.has(error))
|
|
3088
|
+
return !1;
|
|
3089
|
+
if (seen.add(error), errorCode(error) === code)
|
|
3090
|
+
return !0;
|
|
3091
|
+
let cause = errorCause(error);
|
|
3092
|
+
return cause !== void 0 && hasErrorCode(cause, code, seen);
|
|
3093
|
+
}
|
|
3094
|
+
function isBeautifulMermaidExportError(error) {
|
|
3095
|
+
return hasErrorCode(error, INVALID_BEAUTIFUL_MERMAID_EXPORT_ERROR_CODE);
|
|
3096
|
+
}
|
|
3097
|
+
var isTransientBeautifulMermaidRenderError = (error) => !(isMissingBeautifulMermaid(error) || isBeautifulMermaidExportError(error));
|
|
3098
|
+
async function loadBeautifulMermaid() {
|
|
3099
|
+
return cachedBeautifulMermaid || (cachedBeautifulMermaid = import("beautiful-mermaid").then((mod) => mod).catch((error) => {
|
|
3100
|
+
throw cachedBeautifulMermaid = null, isMissingBeautifulMermaid(error) ? missingBeautifulMermaidError(error) : markMermaidRenderErrorFatal(error);
|
|
3101
|
+
})), cachedBeautifulMermaid;
|
|
3102
|
+
}
|
|
3103
|
+
var beautifulMermaidRenderer = async (code, options) => {
|
|
3104
|
+
try {
|
|
3105
|
+
let mod = await loadBeautifulMermaid();
|
|
3106
|
+
return await resolveBeautifulMermaidRenderer(mod)(code, options);
|
|
3107
|
+
} catch (error) {
|
|
3108
|
+
throw isMissingBeautifulMermaid(error) ? missingBeautifulMermaidError(error) : error;
|
|
3109
|
+
}
|
|
3110
|
+
};
|
|
3111
|
+
function createBeautifulMermaidRenderer() {
|
|
3112
|
+
return beautifulMermaidRenderer;
|
|
3113
|
+
}
|
|
3114
|
+
var TMermaidText2 = (0, import_vue10.defineComponent)({
|
|
3115
|
+
name: "TMermaidText",
|
|
3116
|
+
inheritAttrs: !1,
|
|
3117
|
+
props: tMermaidTextProps,
|
|
3118
|
+
emits: {
|
|
3119
|
+
copy: (_payload) => !0
|
|
3120
|
+
},
|
|
3121
|
+
setup(props, { attrs, emit, slots }) {
|
|
3122
|
+
return () => {
|
|
3123
|
+
let renderer = props.renderer ?? beautifulMermaidRenderer, shouldRenderSource = props.shouldRenderSource ?? isSimpleMermaidFlowchartSource;
|
|
3124
|
+
return (0, import_vue10.h)(
|
|
3125
|
+
TMermaidText,
|
|
3126
|
+
{
|
|
3127
|
+
...attrs,
|
|
3128
|
+
...props,
|
|
3129
|
+
renderer,
|
|
3130
|
+
shouldRenderSource,
|
|
3131
|
+
isTransientError: props.isTransientError ?? isTransientBeautifulMermaidRenderError,
|
|
3132
|
+
onCopy: (payload) => emit("copy", payload)
|
|
3133
|
+
},
|
|
3134
|
+
slots
|
|
3135
|
+
);
|
|
3136
|
+
};
|
|
3137
|
+
}
|
|
3138
|
+
}), TMermaid = (0, import_vue10.defineComponent)({
|
|
3139
|
+
name: "TMermaid",
|
|
3140
|
+
inheritAttrs: !1,
|
|
3141
|
+
props: tMermaidImageProps,
|
|
3142
|
+
emits: {
|
|
3143
|
+
copy: (_payload) => !0
|
|
3144
|
+
},
|
|
3145
|
+
setup(props, { attrs, emit, slots }) {
|
|
3146
|
+
return () => {
|
|
3147
|
+
let { renderer: _legacyTextRenderer, ...rest } = props, textRenderer = props.textRenderer ?? props.renderer ?? beautifulMermaidRenderer;
|
|
3148
|
+
return (0, import_vue10.h)(
|
|
3149
|
+
TMermaidImage,
|
|
3150
|
+
{
|
|
3151
|
+
...attrs,
|
|
3152
|
+
...rest,
|
|
3153
|
+
textRenderer,
|
|
3154
|
+
shouldRenderSource: props.shouldRenderSource ?? isSimpleMermaidFlowchartSource,
|
|
3155
|
+
onCopy: (payload) => emit("copy", payload)
|
|
3156
|
+
},
|
|
3157
|
+
slots
|
|
3158
|
+
);
|
|
3159
|
+
};
|
|
3160
|
+
}
|
|
3161
|
+
}), TBeautifulMermaidText = TMermaidText2, TBeautifulMermaid = TMermaid;
|