@simon_he/vue-tui 1.0.2 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +44 -26
  2. package/dist/TMermaidText-CXm_L969.js +885 -0
  3. package/dist/{TSelect-DR0FomSu.js → TSelect-CiyMvwl-.js} +60 -81
  4. package/dist/{TTree-kzhlB5P0.js → TTree-DKGiuIcM.js} +140 -103
  5. package/dist/agent/mermaid.cjs +2 -0
  6. package/dist/agent/mermaid.d.cts +2 -0
  7. package/dist/agent/mermaid.d.ts +2 -0
  8. package/dist/agent/mermaid.js +1 -0
  9. package/dist/agent.cjs +31184 -24907
  10. package/dist/agent.d.cts +11 -1
  11. package/dist/agent.d.ts +11 -1
  12. package/dist/agent.js +1700 -13
  13. package/dist/block-source-5CQp4tF8.js +3230 -0
  14. package/dist/cli/stdin-buffer.d.ts +1 -1
  15. package/dist/cli.cjs +5037 -6767
  16. package/dist/cli.d.cts +4 -0
  17. package/dist/cli.d.ts +4 -0
  18. package/dist/cli.js +2733 -148
  19. package/dist/core/buffer/eaw-ranges-unicode-17.d.ts +14 -0
  20. package/dist/core/perf/instrumentation-noop.d.ts +48 -0
  21. package/dist/core/perf/instrumentation.d.ts +136 -0
  22. package/dist/core/terminal/create-terminal.d.ts +1 -0
  23. package/dist/core.cjs +843 -1469
  24. package/dist/core.js +6 -6
  25. package/dist/{create-terminal-DBFNYr8f.js → create-terminal-DXuZ2fci.js} +39 -13
  26. package/dist/debug-logger-ChY_PXVk.js +74 -0
  27. package/dist/{dom-renderer-BniJSQyX.js → dom-renderer-DNzmg2As.js} +2 -2
  28. package/dist/experimental.cjs +4115 -5928
  29. package/dist/experimental.d.cts +2 -0
  30. package/dist/experimental.d.ts +2 -0
  31. package/dist/experimental.js +1490 -9
  32. package/dist/frame-perf-BBhE-iuS.js +111 -0
  33. package/dist/{sgr-BmzxEjAO.js → hyperlink-B35-O-cW.js} +100 -1
  34. package/dist/index.cjs +5017 -10339
  35. package/dist/index.js +16 -14
  36. package/dist/{linkify-D_gzn9Xq.js → linkify-CuuquMQT.js} +32 -3
  37. package/dist/markdown.cjs +21295 -12691
  38. package/dist/markdown.d.cts +1 -1
  39. package/dist/markdown.d.ts +1 -1
  40. package/dist/markdown.js +211 -51
  41. package/dist/mermaid-CWto52Wk.js +123 -0
  42. package/dist/mermaid.cjs +1707 -0
  43. package/dist/mermaid.d.cts +3 -0
  44. package/dist/mermaid.d.ts +3 -0
  45. package/dist/mermaid.js +6 -0
  46. package/dist/observability/frame-perf-store.d.ts +2 -1
  47. package/dist/observability/frame-perf.d.ts +33 -0
  48. package/dist/observability.cjs +106 -107
  49. package/dist/observability.d.cts +2 -2
  50. package/dist/observability.d.ts +2 -2
  51. package/dist/observability.js +3 -3
  52. package/dist/{path-suggest-BNqcuE3-.js → path-suggest-fPzRsgPv.js} +1 -1
  53. package/dist/{wheel-scroll-vBRaQ7p-.js → rect-Ng-3eKzF.js} +253 -117
  54. package/dist/renderer/cli/stdout-metrics.d.ts +10 -0
  55. package/dist/renderer/cli/stdout-renderer.d.ts +3 -0
  56. package/dist/renderer/terminal-graphic-render-queue.d.ts +50 -0
  57. package/dist/renderer/terminal-graphics-trace.d.ts +53 -0
  58. package/dist/renderer/terminal-graphics.d.ts +146 -0
  59. package/dist/renderer-dom.cjs +364 -903
  60. package/dist/renderer-dom.js +4 -4
  61. package/dist/runtime/index.d.ts +2 -0
  62. package/dist/{runtime-rfcZCyJq.js → runtime-D77C03RM.js} +28 -15
  63. package/dist/runtime.cjs +427 -889
  64. package/dist/runtime.js +2 -2
  65. package/dist/{terminal-selection-DBinO6p5.js → terminal-selection-CQYr--26.js} +4 -1
  66. package/dist/{tlog-theme-CvLFNMwk.js → tlog-theme-CopRt9SC.js} +37 -6
  67. package/dist/{trace-CjzYeIxN.js → trace-CYHDKM1m.js} +5 -0
  68. package/dist/vue/agent/create-png-terminal-graphic-renderer.d.ts +19 -0
  69. package/dist/vue/components/TAgentTerminalGraphic.d.ts +481 -0
  70. package/dist/vue/components/TCharts.d.ts +1121 -0
  71. package/dist/vue/components/TFeedback.d.ts +1 -1
  72. package/dist/vue/components/TFlex.d.ts +389 -0
  73. package/dist/vue/components/TForm.d.ts +4 -4
  74. package/dist/vue/components/TLogSearchBar.d.ts +3 -3
  75. package/dist/vue/components/TLogSearchPager.d.ts +2 -2
  76. package/dist/vue/components/TMarkdownText.d.ts +162 -4
  77. package/dist/vue/components/TMermaidText.d.ts +900 -0
  78. package/dist/vue/components/TVirtualList.d.ts +9 -0
  79. package/dist/vue/components/TVirtualMarkdown.d.ts +170 -9
  80. package/dist/vue/components/TVirtualRows.d.ts +9 -0
  81. package/dist/vue/components/TerminalProvider.d.ts +2 -0
  82. package/dist/vue/context.d.ts +24 -0
  83. package/dist/vue/index.d.ts +5 -0
  84. package/dist/vue/layout/flex.d.ts +67 -0
  85. package/dist/vue/markdown/ast.d.ts +5 -2
  86. package/dist/vue/markdown/document.d.ts +5 -0
  87. package/dist/vue/markdown/image-actions.d.ts +14 -0
  88. package/dist/vue/markdown/image.d.ts +11 -0
  89. package/dist/vue/markdown/link-actions.d.ts +14 -0
  90. package/dist/vue/markdown/math-actions.d.ts +14 -0
  91. package/dist/vue/markdown/math.d.ts +6 -0
  92. package/dist/vue/markdown/render.d.ts +28 -0
  93. package/dist/vue/markdown/types.d.ts +78 -0
  94. package/dist/vue/mermaid/beautiful-mermaid.d.ts +1436 -0
  95. package/dist/vue/render/render-manager.d.ts +7 -0
  96. package/dist/vue.cjs +7207 -12437
  97. package/dist/vue.js +706 -39
  98. package/dist/wheel-scroll-CQ22Hcyj.js +106 -0
  99. package/dist/{hyperlink-Bn02UXJb.js → width-GqllnV8C.js} +166 -111
  100. package/package.json +85 -14
  101. package/dist/block-source-CKUOnkgT.js +0 -1663
  102. package/dist/frame-perf-C6Xfg85O.js +0 -24
  103. /package/dist/{env-Cl8qmNFN.js → env-DNCzvX8b.js} +0 -0
  104. /package/dist/{path-mnSgEpCm.js → path-BI9W15Zt.js} +0 -0
@@ -0,0 +1,885 @@
1
+ import { EventZIndexContextKey, intersectRect, padEndByCells$1 as padEndByCells, repeatChar, sanitizeInlineText, sanitizeTextBlock, sliceByCells, sliceByCellsRange, spaces, textCellWidth$1 as textCellWidth, translateRect, useLayout, useRenderNode, useTerminal, useTerminalNode, useVisibility, withTextWidthProvider } from "./rect-Ng-3eKzF.js";
2
+ import { computed, defineComponent, getCurrentInstance, h, inject, markRaw, onBeforeUnmount, shallowRef, watch } from "vue";
3
+
4
+ //#region src/vue/components/TMermaidText.ts
5
+ const TUI_MERMAID_FATAL_RENDER_ERROR = "__vueTuiMermaidFatalRenderError";
6
+ const fatalMermaidRenderErrors = new WeakSet();
7
+ const DEFAULT_MERMAID_RENDER_TIMEOUT_MS = 2500;
8
+ const DEFAULT_MERMAID_MAX_RENDER_SOURCE_CHARS = 2e4;
9
+ const DEFAULT_MERMAID_MAX_RENDER_SOURCE_LINES = 400;
10
+ const DEFAULT_MERMAID_COPIED_DURATION_MS = 1200;
11
+ const UNICODE_MERMAID_BOX_CHARS = Object.freeze({
12
+ tl: "┌",
13
+ tr: "┐",
14
+ bl: "└",
15
+ br: "┘",
16
+ h: "─",
17
+ v: "│"
18
+ });
19
+ const ASCII_MERMAID_BOX_CHARS = Object.freeze({
20
+ tl: "+",
21
+ tr: "+",
22
+ bl: "+",
23
+ br: "+",
24
+ h: "-",
25
+ v: "|"
26
+ });
27
+ const DEFAULT_MERMAID_MAX_RENDER_FLOW_STATEMENTS = 120;
28
+ const SIMPLE_MERMAID_DIRECTIVE_RE = /^(?:graph|flowchart)\s+(?:TB|TD|BT|LR|RL)\s*$/i;
29
+ const MERMAID_INIT_DIRECTIVE_RE = /^%%\{/;
30
+ const MERMAID_COMMENT_RE = /^%%/;
31
+ const MERMAID_FRONTMATTER_DELIMITER_RE = /^---\s*$/;
32
+ const SIMPLE_MERMAID_FLOW_STATEMENT_START_RE = /^(?:"[^"]+"|'[^']+'|`[^`]+`|[A-Za-z0-9_][A-Za-z0-9_-]*)/;
33
+ const COMPLEX_MERMAID_FLOW_FEATURE_RE = /^(?:subgraph|end|classDef|class|click|style|linkStyle|accTitle|accDescr|direction)\b/i;
34
+ const ESC = String.fromCharCode(27);
35
+ const BEL = String.fromCharCode(7);
36
+ const TERMINAL_ESCAPE_RE = new RegExp([
37
+ `${ESC}\\][\\s\\S]*?(?:${BEL}|${ESC}\\\\)`,
38
+ `${ESC}[PX^_][\\s\\S]*?${ESC}\\\\`,
39
+ `${ESC}\\[[0-?]*[ -/]*[@-~]`,
40
+ `${ESC}[@-Z\\\\-_]`
41
+ ].join("|"), "g");
42
+ function stripTerminalEscapes(value) {
43
+ return value.replace(TERMINAL_ESCAPE_RE, "");
44
+ }
45
+ function normalizeNonNegativeInt(value, fallback) {
46
+ const n = Number(value);
47
+ if (!Number.isFinite(n)) return fallback;
48
+ return Math.max(0, Math.floor(n));
49
+ }
50
+ function countLinesUpTo(value, max) {
51
+ if (max <= 0) return 0;
52
+ let lines = 1;
53
+ for (let index = 0; index < value.length; index++) {
54
+ const code = value.charCodeAt(index);
55
+ if (code !== 10 && code !== 13) continue;
56
+ lines++;
57
+ if (code === 13 && value.charCodeAt(index + 1) === 10) index++;
58
+ if (lines > max) return lines;
59
+ }
60
+ return lines;
61
+ }
62
+ function createMermaidScannerState() {
63
+ return {
64
+ quote: "",
65
+ escaped: false,
66
+ squareDepth: 0,
67
+ parenDepth: 0,
68
+ braceDepth: 0,
69
+ pipeLabel: false
70
+ };
71
+ }
72
+ function scannerAtTopLevel(state) {
73
+ return !state.quote && !state.pipeLabel && state.squareDepth === 0 && state.parenDepth === 0 && state.braceDepth === 0;
74
+ }
75
+ function advanceMermaidScannerState(state, ch) {
76
+ if (state.pipeLabel) {
77
+ if (state.escaped) {
78
+ state.escaped = false;
79
+ return;
80
+ }
81
+ if (ch === "\\") {
82
+ state.escaped = true;
83
+ return;
84
+ }
85
+ if (ch === "|") state.pipeLabel = false;
86
+ return;
87
+ }
88
+ if (state.quote) {
89
+ if (state.escaped) {
90
+ state.escaped = false;
91
+ return;
92
+ }
93
+ if (ch === "\\") {
94
+ state.escaped = true;
95
+ return;
96
+ }
97
+ if (ch === state.quote) state.quote = "";
98
+ return;
99
+ }
100
+ if (ch === "\"" || ch === "'" || ch === "`") {
101
+ state.quote = ch;
102
+ state.escaped = false;
103
+ return;
104
+ }
105
+ if (ch === "|" && scannerAtTopLevel(state)) {
106
+ state.pipeLabel = true;
107
+ state.escaped = false;
108
+ return;
109
+ }
110
+ if (ch === "[") {
111
+ state.squareDepth++;
112
+ return;
113
+ }
114
+ if (ch === "]") {
115
+ state.squareDepth = Math.max(0, state.squareDepth - 1);
116
+ return;
117
+ }
118
+ if (ch === "(") {
119
+ state.parenDepth++;
120
+ return;
121
+ }
122
+ if (ch === ")") {
123
+ state.parenDepth = Math.max(0, state.parenDepth - 1);
124
+ return;
125
+ }
126
+ if (ch === "{") {
127
+ state.braceDepth++;
128
+ return;
129
+ }
130
+ if (ch === "}") state.braceDepth = Math.max(0, state.braceDepth - 1);
131
+ }
132
+ function splitMermaidLineStatements(line) {
133
+ const out = [];
134
+ const state = createMermaidScannerState();
135
+ let start = 0;
136
+ for (let index = 0; index < line.length; index++) {
137
+ const ch = line[index] ?? "";
138
+ if (ch === ";" && scannerAtTopLevel(state)) {
139
+ const statement = line.slice(start, index).trim();
140
+ if (statement) out.push(statement);
141
+ start = index + 1;
142
+ continue;
143
+ }
144
+ advanceMermaidScannerState(state, ch);
145
+ }
146
+ const tail = line.slice(start).trim();
147
+ if (tail) out.push(tail);
148
+ return out;
149
+ }
150
+ function stripTopLevelMermaidComment(statement) {
151
+ const state = createMermaidScannerState();
152
+ for (let index = 0; index < statement.length; index++) {
153
+ const ch = statement[index] ?? "";
154
+ if (ch === "%" && statement[index + 1] === "%" && scannerAtTopLevel(state)) return statement.slice(0, index).trim();
155
+ advanceMermaidScannerState(state, ch);
156
+ }
157
+ return statement.trim();
158
+ }
159
+ function mermaidSourceLines(code) {
160
+ return String(code ?? "").replace(/\r\n?/g, "\n").split("\n");
161
+ }
162
+ function mermaidSourceStatements(code) {
163
+ const statements = [];
164
+ for (const rawLine of mermaidSourceLines(code)) {
165
+ const line = rawLine.trim();
166
+ if (!line) continue;
167
+ if (MERMAID_INIT_DIRECTIVE_RE.test(line) || MERMAID_FRONTMATTER_DELIMITER_RE.test(line)) {
168
+ statements.push(line);
169
+ continue;
170
+ }
171
+ if (MERMAID_COMMENT_RE.test(line)) continue;
172
+ for (const rawStatement of splitMermaidLineStatements(line)) {
173
+ const statement = stripTopLevelMermaidComment(rawStatement);
174
+ if (!statement || MERMAID_COMMENT_RE.test(statement)) continue;
175
+ statements.push(statement);
176
+ }
177
+ }
178
+ return statements;
179
+ }
180
+ function isForbiddenMermaidFlowStatement(statement) {
181
+ return MERMAID_INIT_DIRECTIVE_RE.test(statement) || MERMAID_FRONTMATTER_DELIMITER_RE.test(statement) || COMPLEX_MERMAID_FLOW_FEATURE_RE.test(statement);
182
+ }
183
+ function hasTopLevelMermaidComplexToken(statement) {
184
+ const state = createMermaidScannerState();
185
+ for (let index = 0; index < statement.length; index++) {
186
+ const ch = statement[index] ?? "";
187
+ if (scannerAtTopLevel(state)) {
188
+ if (ch === "@") return true;
189
+ if (statement.startsWith(":::", index) && /[A-Za-z_]/.test(statement[index + 3] ?? "")) return true;
190
+ }
191
+ advanceMermaidScannerState(state, ch);
192
+ }
193
+ return false;
194
+ }
195
+ function isSimpleMermaidFlowStatement(statement) {
196
+ if (SIMPLE_MERMAID_DIRECTIVE_RE.test(statement)) return false;
197
+ if (isForbiddenMermaidFlowStatement(statement)) return false;
198
+ if (hasTopLevelMermaidComplexToken(statement)) return false;
199
+ return SIMPLE_MERMAID_FLOW_STATEMENT_START_RE.test(statement);
200
+ }
201
+ function isSimpleMermaidFlowchartSource(code) {
202
+ const statements = mermaidSourceStatements(code);
203
+ let sawDirective = false;
204
+ let renderableStatements = 0;
205
+ for (const statement of statements) {
206
+ if (!sawDirective) {
207
+ if (!SIMPLE_MERMAID_DIRECTIVE_RE.test(statement)) return false;
208
+ sawDirective = true;
209
+ continue;
210
+ }
211
+ if (!isSimpleMermaidFlowStatement(statement)) return false;
212
+ renderableStatements++;
213
+ if (renderableStatements > DEFAULT_MERMAID_MAX_RENDER_FLOW_STATEMENTS) return false;
214
+ }
215
+ return sawDirective && renderableStatements > 0;
216
+ }
217
+ function clipboardCanWrite(api) {
218
+ return api.canWrite ?? api.supported;
219
+ }
220
+ const MERMAID_RENDER_TIMEOUT = Symbol("MERMAID_RENDER_TIMEOUT");
221
+ function markMermaidRenderErrorFatal(error) {
222
+ const normalized = error instanceof Error ? error : new Error(String(error));
223
+ fatalMermaidRenderErrors.add(normalized);
224
+ try {
225
+ Object.defineProperty(normalized, TUI_MERMAID_FATAL_RENDER_ERROR, {
226
+ value: true,
227
+ configurable: true
228
+ });
229
+ } catch {
230
+ try {
231
+ normalized[TUI_MERMAID_FATAL_RENDER_ERROR] = true;
232
+ } catch {}
233
+ }
234
+ return normalized;
235
+ }
236
+ function splitRenderedOutput(value) {
237
+ const normalized = sanitizeTextBlock(stripTerminalEscapes(String(value ?? "")).replace(/\r\n?/g, "\n"));
238
+ const lines = normalized.split("\n");
239
+ return lines.length ? lines : [""];
240
+ }
241
+ function hasVisibleRenderedOutput(value) {
242
+ return value.some((line) => line.trim().length > 0);
243
+ }
244
+ const tMermaidTextProps = {
245
+ x: {
246
+ type: Number,
247
+ required: true
248
+ },
249
+ y: {
250
+ type: Number,
251
+ required: true
252
+ },
253
+ w: {
254
+ type: Number,
255
+ required: true
256
+ },
257
+ h: {
258
+ type: Number,
259
+ default: void 0
260
+ },
261
+ zIndex: {
262
+ type: Number,
263
+ default: 0
264
+ },
265
+ content: {
266
+ type: String,
267
+ default: ""
268
+ },
269
+ code: {
270
+ type: String,
271
+ default: void 0
272
+ },
273
+ style: {
274
+ type: Object,
275
+ default: void 0
276
+ },
277
+ loadingStyle: {
278
+ type: Object,
279
+ default: void 0
280
+ },
281
+ errorStyle: {
282
+ type: Object,
283
+ default: void 0
284
+ },
285
+ clear: {
286
+ type: Boolean,
287
+ default: true
288
+ },
289
+ final: {
290
+ type: Boolean,
291
+ default: true
292
+ },
293
+ streaming: {
294
+ type: Boolean,
295
+ default: false
296
+ },
297
+ ascii: {
298
+ type: Boolean,
299
+ default: false
300
+ },
301
+ paddingX: {
302
+ type: Number,
303
+ default: void 0
304
+ },
305
+ paddingY: {
306
+ type: Number,
307
+ default: void 0
308
+ },
309
+ boxBorderPadding: {
310
+ type: Number,
311
+ default: void 0
312
+ },
313
+ options: {
314
+ type: Object,
315
+ default: void 0
316
+ },
317
+ renderer: {
318
+ type: Function,
319
+ default: void 0
320
+ },
321
+ isTransientError: {
322
+ type: Function,
323
+ default: void 0
324
+ },
325
+ shouldRenderSource: {
326
+ type: Function,
327
+ default: void 0
328
+ },
329
+ loadingText: {
330
+ type: String,
331
+ default: "Rendering Mermaid diagram..."
332
+ },
333
+ incompleteText: {
334
+ type: String,
335
+ default: "Waiting for complete Mermaid diagram..."
336
+ },
337
+ missingDependencyText: {
338
+ type: String,
339
+ default: "Install the Mermaid renderer package and use TMermaidText from @simon_he/vue-tui/mermaid or @simon_he/vue-tui/agent/mermaid, or pass a renderer prop."
340
+ },
341
+ errorText: {
342
+ type: String,
343
+ default: "Mermaid render failed"
344
+ },
345
+ showErrorDetails: {
346
+ type: Boolean,
347
+ default: true
348
+ },
349
+ box: {
350
+ type: Boolean,
351
+ default: true
352
+ },
353
+ title: {
354
+ type: String,
355
+ default: "mermaid"
356
+ },
357
+ copyButton: {
358
+ type: Boolean,
359
+ default: true
360
+ },
361
+ copyText: {
362
+ type: String,
363
+ default: "copy"
364
+ },
365
+ copiedText: {
366
+ type: String,
367
+ default: "copied"
368
+ },
369
+ renderTimeoutMs: {
370
+ type: Number,
371
+ default: DEFAULT_MERMAID_RENDER_TIMEOUT_MS
372
+ },
373
+ maxRenderSourceChars: {
374
+ type: Number,
375
+ default: DEFAULT_MERMAID_MAX_RENDER_SOURCE_CHARS
376
+ },
377
+ maxRenderSourceLines: {
378
+ type: Number,
379
+ default: DEFAULT_MERMAID_MAX_RENDER_SOURCE_LINES
380
+ },
381
+ copiedDurationMs: {
382
+ type: Number,
383
+ default: DEFAULT_MERMAID_COPIED_DURATION_MS
384
+ }
385
+ };
386
+ const TMermaidText = defineComponent({
387
+ name: "TMermaidText",
388
+ props: tMermaidTextProps,
389
+ emits: { copy: (_payload) => true },
390
+ setup(props, { emit }) {
391
+ const instance = getCurrentInstance();
392
+ const terminalContext = useTerminal();
393
+ const { terminal, defaultStyle, scheduler, widthProvider } = terminalContext;
394
+ const layout = useLayout();
395
+ const { visible, rootProps } = useVisibility();
396
+ const parentEventZ = inject(EventZIndexContextKey, computed(() => 0));
397
+ const renderedSnapshot = shallowRef(null);
398
+ const documentVersion = shallowRef(0);
399
+ const copied = shallowRef(false);
400
+ let builtOnce = false;
401
+ let renderVersion = 0;
402
+ let alive = true;
403
+ const frameTaskId = `TMermaidText:${instance?.uid ?? "unknown"}:mermaid`;
404
+ let copiedTimer = null;
405
+ let copyRequestVersion = 0;
406
+ const source = computed(() => props.code ?? props.content ?? "");
407
+ const waitingForStreamingSourceToFinish = computed(() => props.streaming && !props.final);
408
+ function bump() {
409
+ documentVersion.value++;
410
+ }
411
+ function resolveAsciiOptions() {
412
+ const base = props.options ?? {};
413
+ return {
414
+ ...base,
415
+ useAscii: props.ascii,
416
+ paddingX: props.paddingX ?? base.paddingX,
417
+ paddingY: props.paddingY ?? base.paddingY,
418
+ boxBorderPadding: props.boxBorderPadding ?? base.boxBorderPadding,
419
+ colorMode: "none"
420
+ };
421
+ }
422
+ function clearCopiedTimer() {
423
+ if (copiedTimer == null) return;
424
+ clearTimeout(copiedTimer);
425
+ copiedTimer = null;
426
+ }
427
+ function setCopied(next, repaint = true) {
428
+ if (!next) clearCopiedTimer();
429
+ if (copied.value === next) return;
430
+ copied.value = next;
431
+ if (repaint) bump();
432
+ }
433
+ function resetCopyFeedback(repaint = true) {
434
+ copyRequestVersion++;
435
+ setCopied(false, repaint);
436
+ }
437
+ function clearRenderedSnapshot() {
438
+ if (renderedSnapshot.value == null) return false;
439
+ renderedSnapshot.value = null;
440
+ return true;
441
+ }
442
+ function showCopiedFeedback() {
443
+ clearCopiedTimer();
444
+ const duration = normalizeNonNegativeInt(props.copiedDurationMs, DEFAULT_MERMAID_COPIED_DURATION_MS);
445
+ if (duration <= 0) {
446
+ setCopied(false);
447
+ return;
448
+ }
449
+ setCopied(true);
450
+ copiedTimer = setTimeout(() => {
451
+ copiedTimer = null;
452
+ if (!alive) return;
453
+ setCopied(false);
454
+ }, duration);
455
+ }
456
+ function shouldSkipRenderForSize(code) {
457
+ const maxChars = normalizeNonNegativeInt(props.maxRenderSourceChars, DEFAULT_MERMAID_MAX_RENDER_SOURCE_CHARS);
458
+ if (maxChars > 0 && code.length > maxChars) return true;
459
+ const maxLines = normalizeNonNegativeInt(props.maxRenderSourceLines, DEFAULT_MERMAID_MAX_RENDER_SOURCE_LINES);
460
+ if (maxLines > 0 && countLinesUpTo(code, maxLines) > maxLines) return true;
461
+ return false;
462
+ }
463
+ function shouldSkipRender(code) {
464
+ if (shouldSkipRenderForSize(code)) return true;
465
+ const shouldRenderSource = props.shouldRenderSource;
466
+ if (!shouldRenderSource) return false;
467
+ try {
468
+ return !shouldRenderSource(code, {
469
+ final: props.final,
470
+ streaming: props.streaming
471
+ });
472
+ } catch {
473
+ return true;
474
+ }
475
+ }
476
+ async function renderWithTimeout(renderer, code, options) {
477
+ const timeoutMs = normalizeNonNegativeInt(props.renderTimeoutMs, DEFAULT_MERMAID_RENDER_TIMEOUT_MS);
478
+ if (timeoutMs <= 0) return await renderer(code, options);
479
+ let timer = null;
480
+ try {
481
+ return await Promise.race([Promise.resolve().then(() => renderer(code, options)), new Promise((_resolve, reject) => {
482
+ timer = setTimeout(() => reject(MERMAID_RENDER_TIMEOUT), timeoutMs);
483
+ })]);
484
+ } finally {
485
+ if (timer != null) clearTimeout(timer);
486
+ }
487
+ }
488
+ function clearRenderState() {
489
+ renderedSnapshot.value = null;
490
+ }
491
+ function acceptRenderedSnapshot(code, rendered) {
492
+ const renderedLines = splitRenderedOutput(rendered);
493
+ if (!hasVisibleRenderedOutput(renderedLines)) {
494
+ renderedSnapshot.value = null;
495
+ return;
496
+ }
497
+ renderedSnapshot.value = markRaw({
498
+ source: code,
499
+ lines: markRaw(renderedLines)
500
+ });
501
+ }
502
+ async function renderNow(version) {
503
+ const code = source.value;
504
+ if (!code.trim()) {
505
+ if (!alive || version !== renderVersion) return;
506
+ clearRenderState();
507
+ bump();
508
+ return;
509
+ }
510
+ if (waitingForStreamingSourceToFinish.value) {
511
+ if (!alive || version !== renderVersion) return;
512
+ clearRenderState();
513
+ bump();
514
+ return;
515
+ }
516
+ if (shouldSkipRender(code)) {
517
+ if (!alive || version !== renderVersion) return;
518
+ clearRenderState();
519
+ bump();
520
+ return;
521
+ }
522
+ renderedSnapshot.value = null;
523
+ bump();
524
+ try {
525
+ const renderer = props.renderer;
526
+ if (!renderer) {
527
+ if (!alive || version !== renderVersion) return;
528
+ clearRenderState();
529
+ bump();
530
+ return;
531
+ }
532
+ const rendered = await renderWithTimeout(renderer, code, resolveAsciiOptions());
533
+ if (!alive || version !== renderVersion) return;
534
+ acceptRenderedSnapshot(code, rendered);
535
+ bump();
536
+ } catch {
537
+ if (!alive || version !== renderVersion) return;
538
+ clearRenderState();
539
+ bump();
540
+ }
541
+ }
542
+ function scheduleRender() {
543
+ const version = ++renderVersion;
544
+ const copiedWasVisible = copied.value;
545
+ resetCopyFeedback(false);
546
+ const snapshotCleared = clearRenderedSnapshot();
547
+ if (waitingForStreamingSourceToFinish.value) {
548
+ builtOnce = true;
549
+ scheduler.cancelFrameTask?.(frameTaskId);
550
+ if (copiedWasVisible || snapshotCleared) bump();
551
+ return;
552
+ }
553
+ if (!builtOnce || !props.streaming) {
554
+ builtOnce = true;
555
+ renderNow(version);
556
+ return;
557
+ }
558
+ if (copiedWasVisible || snapshotCleared) bump();
559
+ const accepted = scheduler.queueFrameTask({
560
+ id: frameTaskId,
561
+ reason: "stream",
562
+ priority: "low",
563
+ sync: false,
564
+ run: () => {
565
+ if (!alive) return;
566
+ if (version !== renderVersion) return;
567
+ renderNow(version);
568
+ }
569
+ });
570
+ if (accepted === false) renderNow(version);
571
+ }
572
+ watch([
573
+ source,
574
+ () => props.renderer,
575
+ () => props.ascii,
576
+ () => props.paddingX,
577
+ () => props.paddingY,
578
+ () => props.boxBorderPadding,
579
+ () => props.options,
580
+ () => props.streaming,
581
+ () => props.final,
582
+ () => props.renderTimeoutMs,
583
+ () => props.maxRenderSourceChars,
584
+ () => props.maxRenderSourceLines,
585
+ () => props.shouldRenderSource
586
+ ], () => {
587
+ scheduleRender();
588
+ }, {
589
+ immediate: true,
590
+ deep: true
591
+ });
592
+ onBeforeUnmount(() => {
593
+ alive = false;
594
+ renderVersion++;
595
+ clearCopiedTimer();
596
+ scheduler.cancelFrameTask?.(frameTaskId);
597
+ });
598
+ const hasBox = computed(() => props.box !== false);
599
+ const normalizedWidth = computed(() => {
600
+ const width = Math.floor(Number(props.w));
601
+ return Number.isFinite(width) ? Math.max(0, width) : 0;
602
+ });
603
+ const reservesBoxRows = computed(() => hasBox.value && normalizedWidth.value >= 2);
604
+ const boxChars = computed(() => props.ascii ? ASCII_MERMAID_BOX_CHARS : UNICODE_MERMAID_BOX_CHARS);
605
+ const sourceLines = computed(() => splitRenderedOutput(source.value));
606
+ const displayLines = computed(() => {
607
+ const snapshot = renderedSnapshot.value;
608
+ if (snapshot && snapshot.source === source.value && hasVisibleRenderedOutput(snapshot.lines)) return snapshot.lines;
609
+ return sourceLines.value;
610
+ });
611
+ const currentStyle = computed(() => {
612
+ return props.style ?? defaultStyle.value;
613
+ });
614
+ const fullHeight = computed(() => {
615
+ if (props.h != null) {
616
+ const h$1 = Math.floor(Number(props.h));
617
+ return Number.isFinite(h$1) ? Math.max(0, h$1) : 0;
618
+ }
619
+ const autoContentHeight = Math.max(1, displayLines.value.length);
620
+ return reservesBoxRows.value ? autoContentHeight + 2 : autoContentHeight;
621
+ });
622
+ const fullRect = computed(() => {
623
+ return translateRect({
624
+ x: props.x,
625
+ y: props.y,
626
+ w: props.w,
627
+ h: fullHeight.value
628
+ }, layout.originX, layout.originY);
629
+ });
630
+ const absRect = computed(() => {
631
+ const translated = fullRect.value;
632
+ if (!layout.clipRect) return translated;
633
+ return intersectRect(translated, layout.clipRect) ?? {
634
+ x: 0,
635
+ y: 0,
636
+ w: 0,
637
+ h: 0
638
+ };
639
+ });
640
+ const copyLabel = computed(() => copied.value ? props.copiedText : props.copyText);
641
+ function cellWidth(value) {
642
+ return withTextWidthProvider(widthProvider, () => textCellWidth(value));
643
+ }
644
+ function sliceCells(text, maxCells) {
645
+ return withTextWidthProvider(widthProvider, () => sliceByCells(text, maxCells));
646
+ }
647
+ function sliceCellsRange(text, startCells, endCells) {
648
+ return withTextWidthProvider(widthProvider, () => sliceByCellsRange(text, startCells, endCells));
649
+ }
650
+ function padCells(text, width) {
651
+ return withTextWidthProvider(widthProvider, () => padEndByCells(text, width));
652
+ }
653
+ function canDrawBox(width, height) {
654
+ return hasBox.value && Math.floor(width) >= 2 && Math.floor(height) >= 2;
655
+ }
656
+ function segmentCells(text) {
657
+ return cellWidth(text);
658
+ }
659
+ function headerCopySegment(width) {
660
+ if (!hasBox.value || !props.copyButton) return null;
661
+ const rowWidth = Math.max(0, Math.floor(width));
662
+ if (rowWidth < 4) return null;
663
+ const label = sanitizeInlineText(copyLabel.value);
664
+ if (!label) return null;
665
+ const maxCells = Math.max(0, rowWidth - 2);
666
+ const text = sliceCells(` ${label} `, maxCells);
667
+ const cells = segmentCells(text);
668
+ if (!text || cells <= 0) return null;
669
+ return {
670
+ text,
671
+ start: Math.max(1, rowWidth - cells - 1),
672
+ cells
673
+ };
674
+ }
675
+ function headerTitleSegment(width, copy) {
676
+ if (!hasBox.value) return null;
677
+ const rowWidth = Math.max(0, Math.floor(width));
678
+ if (rowWidth < 4) return null;
679
+ const title = sanitizeInlineText(props.title);
680
+ if (!title) return null;
681
+ const titleStart = 1;
682
+ const titleEnd = copy ? Math.max(titleStart, copy.start - 1) : rowWidth - 1;
683
+ const maxCells = Math.max(0, titleEnd - titleStart);
684
+ if (maxCells <= 0) return null;
685
+ const text = sliceCells(` ${title} `, maxCells);
686
+ const cells = segmentCells(text);
687
+ if (!text || cells <= 0) return null;
688
+ return {
689
+ text,
690
+ start: titleStart,
691
+ cells
692
+ };
693
+ }
694
+ const copyHitRect = computed(() => {
695
+ const full = fullRect.value;
696
+ if (!visible.value || !props.copyButton || !canDrawBox(full.w, full.h)) return {
697
+ x: 0,
698
+ y: 0,
699
+ w: 0,
700
+ h: 0
701
+ };
702
+ const copy = headerCopySegment(Math.max(0, Math.floor(full.w)));
703
+ if (!copy) return {
704
+ x: 0,
705
+ y: 0,
706
+ w: 0,
707
+ h: 0
708
+ };
709
+ const raw = {
710
+ x: Math.floor(full.x) + copy.start,
711
+ y: Math.floor(full.y),
712
+ w: copy.cells,
713
+ h: 1
714
+ };
715
+ if (!layout.clipRect) return raw;
716
+ return intersectRect(raw, layout.clipRect) ?? {
717
+ x: 0,
718
+ y: 0,
719
+ w: 0,
720
+ h: 0
721
+ };
722
+ });
723
+ async function writeClipboardText(text) {
724
+ const contextClipboard = terminalContext.clipboard;
725
+ if (contextClipboard) {
726
+ if (!clipboardCanWrite(contextClipboard)) throw new Error("Clipboard write not available in this runtime");
727
+ await contextClipboard.writeText(text);
728
+ return;
729
+ }
730
+ const navClipboard = globalThis.navigator?.clipboard;
731
+ if (navClipboard && typeof navClipboard.writeText === "function") {
732
+ await navClipboard.writeText(text);
733
+ return;
734
+ }
735
+ throw new Error("Clipboard write not available in this runtime");
736
+ }
737
+ async function copySource() {
738
+ const text = source.value;
739
+ const requestVersion = ++copyRequestVersion;
740
+ let ok = false;
741
+ let copyError;
742
+ try {
743
+ await writeClipboardText(text);
744
+ ok = true;
745
+ } catch (err) {
746
+ copyError = err;
747
+ }
748
+ if (!alive) return;
749
+ const isLatestForCurrentSource = requestVersion === copyRequestVersion && source.value === text;
750
+ if (isLatestForCurrentSource) if (ok) showCopiedFeedback();
751
+ else setCopied(false);
752
+ emit("copy", ok ? {
753
+ text,
754
+ ok
755
+ } : {
756
+ text,
757
+ ok,
758
+ error: copyError
759
+ });
760
+ }
761
+ function onCopyClick(event) {
762
+ event.preventDefault();
763
+ event.stopPropagation();
764
+ copySource();
765
+ }
766
+ function onCopyKeydown(event) {
767
+ if (event.key !== "Enter" && event.key !== " ") return;
768
+ event.preventDefault();
769
+ event.stopPropagation();
770
+ copySource();
771
+ }
772
+ const copyNodeActive = computed(() => visible.value && props.copyButton && copyHitRect.value.w > 0 && copyHitRect.value.h > 0);
773
+ useTerminalNode(() => ({
774
+ rect: copyHitRect.value,
775
+ zIndex: (parentEventZ.value ?? 0) + props.zIndex + 1,
776
+ visible: copyNodeActive.value,
777
+ focusable: copyNodeActive.value,
778
+ selectable: false,
779
+ handlers: copyNodeActive.value ? {
780
+ click: onCopyClick,
781
+ keydown: onCopyKeydown
782
+ } : {}
783
+ }));
784
+ function overlayCells(row, segment, width) {
785
+ const rowWidth = Math.max(0, Math.floor(width));
786
+ const start = Math.max(0, Math.floor(segment.start));
787
+ if (rowWidth <= 1 || start >= rowWidth - 1 || segment.cells <= 0) return row;
788
+ const maxCells = Math.max(0, rowWidth - 1 - start);
789
+ const text = sliceCells(segment.text, maxCells);
790
+ const cells = segmentCells(text);
791
+ if (!text || cells <= 0) return row;
792
+ return `${sliceCells(row, start)}${text}${sliceCellsRange(row, start + cells, rowWidth)}`;
793
+ }
794
+ function contentLine(rowIndex, width, pad) {
795
+ const src = displayLines.value[rowIndex] ?? "";
796
+ const clipped = sliceCells(src, width);
797
+ return pad ? padCells(clipped, width) : clipped;
798
+ }
799
+ function boxRow(rowIndex, width, height) {
800
+ const rowWidth = Math.max(0, Math.floor(width));
801
+ const rowHeight = Math.max(0, Math.floor(height));
802
+ if (!canDrawBox(rowWidth, rowHeight)) return contentLine(rowIndex, rowWidth, props.clear);
803
+ const chars = boxChars.value;
804
+ const innerW = Math.max(0, rowWidth - 2);
805
+ if (rowIndex === 0) {
806
+ let row = `${chars.tl}${repeatChar(chars.h, innerW)}${chars.tr}`;
807
+ const copy = headerCopySegment(rowWidth);
808
+ const title = headerTitleSegment(rowWidth, copy);
809
+ if (title) row = overlayCells(row, title, rowWidth);
810
+ if (copy) row = overlayCells(row, copy, rowWidth);
811
+ return row;
812
+ }
813
+ if (rowIndex === rowHeight - 1) return `${chars.bl}${repeatChar(chars.h, innerW)}${chars.br}`;
814
+ return `${chars.v}${contentLine(rowIndex - 1, innerW, true)}${chars.v}`;
815
+ }
816
+ useRenderNode(() => ({
817
+ zIndex: props.zIndex,
818
+ rect: visible.value ? absRect.value : {
819
+ x: 0,
820
+ y: 0,
821
+ w: 0,
822
+ h: 0
823
+ },
824
+ deps: [
825
+ visible.value,
826
+ absRect.value,
827
+ fullRect.value,
828
+ displayLines.value,
829
+ currentStyle.value,
830
+ props.clear,
831
+ renderedSnapshot.value,
832
+ hasBox.value,
833
+ boxChars.value,
834
+ props.title,
835
+ props.copyButton,
836
+ copyLabel.value,
837
+ documentVersion.value
838
+ ],
839
+ paint: (dirtyRows) => {
840
+ withTextWidthProvider(widthProvider, () => {
841
+ if (!visible.value) return;
842
+ const r = absRect.value;
843
+ const full = fullRect.value;
844
+ if (r.w <= 0 || r.h <= 0) return;
845
+ const style = currentStyle.value;
846
+ const dx = Math.max(0, Math.floor(r.x - full.x));
847
+ const fullY = Math.floor(full.y);
848
+ const fullW = Math.max(0, Math.floor(full.w));
849
+ const fullH = Math.max(0, Math.floor(full.h));
850
+ const blank = props.clear ? spaces(r.w) : "";
851
+ const paintRow = (y) => {
852
+ if (y < r.y || y >= r.y + r.h) return;
853
+ const rowIndex = y - fullY;
854
+ if (rowIndex < 0 || rowIndex >= fullH) {
855
+ if (props.clear) terminal.write(blank, {
856
+ x: r.x,
857
+ y,
858
+ style
859
+ });
860
+ return;
861
+ }
862
+ const src = boxRow(rowIndex, fullW, fullH);
863
+ const clipped = dx > 0 ? sliceCellsRange(src, dx, dx + r.w) : sliceCells(src, r.w);
864
+ const value = props.clear ? padCells(clipped, r.w) : clipped;
865
+ if (value || props.clear) terminal.write(value, {
866
+ x: r.x,
867
+ y,
868
+ style
869
+ });
870
+ };
871
+ if (dirtyRows?.length) {
872
+ for (const y of dirtyRows) paintRow(y);
873
+ return;
874
+ }
875
+ for (let y = r.y; y < r.y + r.h; y++) paintRow(y);
876
+ });
877
+ }
878
+ }));
879
+ return () => h("span", rootProps);
880
+ }
881
+ });
882
+ const TMermaid = TMermaidText;
883
+
884
+ //#endregion
885
+ export { TMermaid as TMermaid$1, TMermaidText as TMermaidText$1, isSimpleMermaidFlowchartSource, markMermaidRenderErrorFatal, tMermaidTextProps };