@ai-markdown/core 3.3.1 → 3.4.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.
- package/LICENSE +1 -1
- package/dist/components/index.cjs +866 -167
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.d.cts +439 -55
- package/dist/components/index.d.ts +439 -55
- package/dist/components/index.js +855 -163
- package/dist/components/index.js.map +1 -1
- package/package.json +3 -2
package/dist/components/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { StreamingLanguageDetector } from "@ai-markdown/code-language-detector";
|
|
1
2
|
function extractCode(node) {
|
|
2
3
|
if (node?.tagName !== "pre" || node.children.length !== 1 || Object.keys(node.properties).length) return null;
|
|
3
4
|
const child = node.children[0];
|
|
@@ -43,19 +44,26 @@ function text(node) {
|
|
|
43
44
|
if (node.tagName === "img" || node.tagName === "cross-chunk-image") return String(node.properties.alt ?? "");
|
|
44
45
|
return node.children.map(text).join("");
|
|
45
46
|
}
|
|
47
|
+
var ExportRefused = class extends Error {
|
|
48
|
+
reason;
|
|
49
|
+
constructor(reason) {
|
|
50
|
+
super(reason);
|
|
51
|
+
this.reason = reason;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
46
54
|
function projectTable(node) {
|
|
47
55
|
try {
|
|
48
|
-
if (node?.tagName !== "table") throw new
|
|
56
|
+
if (node?.tagName !== "table") throw new ExportRefused("unavailable");
|
|
49
57
|
const rows = [];
|
|
50
58
|
const walk = (parent) => {
|
|
51
59
|
for (const child of parent.children) {
|
|
52
60
|
if (child.type === "text" && !child.value.trim()) continue;
|
|
53
|
-
if (child.type !== "element") throw new
|
|
61
|
+
if (child.type !== "element") throw new ExportRefused("unsupportedContent");
|
|
54
62
|
if (child.tagName === "tr") {
|
|
55
63
|
const cells = [];
|
|
56
64
|
for (const cell of child.children) {
|
|
57
65
|
if (cell.type === "text" && !cell.value.trim()) continue;
|
|
58
|
-
if (cell.type !== "element" || !["th", "td"].includes(cell.tagName) || Number(cell.properties.colSpan ?? 1) !== 1 || Number(cell.properties.rowSpan ?? 1) !== 1) throw new
|
|
66
|
+
if (cell.type !== "element" || !["th", "td"].includes(cell.tagName) || Number(cell.properties.colSpan ?? 1) !== 1 || Number(cell.properties.rowSpan ?? 1) !== 1) throw new ExportRefused("mergedCells");
|
|
59
67
|
cells.push(text(cell));
|
|
60
68
|
}
|
|
61
69
|
rows.push(cells);
|
|
@@ -64,14 +72,14 @@ function projectTable(node) {
|
|
|
64
72
|
"tbody",
|
|
65
73
|
"tfoot"
|
|
66
74
|
].includes(child.tagName) && parent === node) walk(child);
|
|
67
|
-
else throw new
|
|
75
|
+
else throw new ExportRefused("unsupportedStructure");
|
|
68
76
|
}
|
|
69
77
|
};
|
|
70
78
|
walk(node);
|
|
71
|
-
if (!rows.length || !rows[0].length || rows.some((r) => r.length !== rows[0].length)) throw new
|
|
79
|
+
if (!rows.length || !rows[0].length || rows.some((r) => r.length !== rows[0].length)) throw new ExportRefused("notRectangular");
|
|
72
80
|
return { rows };
|
|
73
81
|
} catch (error) {
|
|
74
|
-
return { reason: error instanceof
|
|
82
|
+
return { reason: error instanceof ExportRefused ? error.reason : "unavailable" };
|
|
75
83
|
}
|
|
76
84
|
}
|
|
77
85
|
const formulaPrefix = /^[\s\u0000-\u001f]*[=+@-]/;
|
|
@@ -81,6 +89,57 @@ function serializeTable(rows, delimiter = ",") {
|
|
|
81
89
|
return /["\r\n\t,]/.test(value) ? `"${value.replaceAll("\"", "\"\"")}"` : value;
|
|
82
90
|
}).join(delimiter)).join("\r\n");
|
|
83
91
|
}
|
|
92
|
+
function codeBody(code) {
|
|
93
|
+
return code.endsWith("\n") ? code.slice(0, -1) : code;
|
|
94
|
+
}
|
|
95
|
+
function startsWithText(text, prefix) {
|
|
96
|
+
return text.length >= prefix.length && text.slice(0, prefix.length) === prefix;
|
|
97
|
+
}
|
|
98
|
+
function extendsCode(next, previous) {
|
|
99
|
+
return startsWithText(next, codeBody(previous));
|
|
100
|
+
}
|
|
101
|
+
function createCodeLanguageTracker(onSettle) {
|
|
102
|
+
const detector = new StreamingLanguageDetector();
|
|
103
|
+
let followed;
|
|
104
|
+
let settled = null;
|
|
105
|
+
let timer;
|
|
106
|
+
const cancel = () => {
|
|
107
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
108
|
+
timer = void 0;
|
|
109
|
+
};
|
|
110
|
+
const judge = (from, text, streaming) => (streaming && settled !== text ? from.update(text) : from.finalize(text)).language;
|
|
111
|
+
return {
|
|
112
|
+
read(code, streaming) {
|
|
113
|
+
if (followed !== void 0 && extendsCode(code, followed)) return detector.current.language;
|
|
114
|
+
return judge(new StreamingLanguageDetector(), codeBody(code), streaming);
|
|
115
|
+
},
|
|
116
|
+
observe(code, streaming) {
|
|
117
|
+
cancel();
|
|
118
|
+
const text = codeBody(code);
|
|
119
|
+
const starting = followed === void 0 || !extendsCode(code, followed);
|
|
120
|
+
if (starting) detector.reset();
|
|
121
|
+
const before = detector.current.language;
|
|
122
|
+
followed = code;
|
|
123
|
+
const after = judge(detector, text, streaming);
|
|
124
|
+
if (streaming && settled !== text) timer = setTimeout(() => {
|
|
125
|
+
timer = void 0;
|
|
126
|
+
settled = text;
|
|
127
|
+
detector.finalize(text);
|
|
128
|
+
onSettle();
|
|
129
|
+
}, 300);
|
|
130
|
+
return !starting && before !== after;
|
|
131
|
+
},
|
|
132
|
+
dispose: cancel
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function nextCodeFrame(previous, code, language) {
|
|
136
|
+
if (previous?.code === code && previous.language === language) return previous;
|
|
137
|
+
return {
|
|
138
|
+
code,
|
|
139
|
+
language,
|
|
140
|
+
generation: previous && language === previous.language && extendsCode(code, previous.code) ? previous.generation : {}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
84
143
|
function createCodeFrame(initial, publish) {
|
|
85
144
|
let shown = initial;
|
|
86
145
|
let latest = initial;
|
|
@@ -98,7 +157,7 @@ function createCodeFrame(initial, publish) {
|
|
|
98
157
|
};
|
|
99
158
|
return {
|
|
100
159
|
update(next, streaming, interval) {
|
|
101
|
-
const replaced = next.
|
|
160
|
+
const replaced = next.generation !== latest.generation;
|
|
102
161
|
latest = next;
|
|
103
162
|
if (delay !== interval) cancel();
|
|
104
163
|
delay = interval;
|
|
@@ -160,16 +219,17 @@ function createJsonCompletenessScanner() {
|
|
|
160
219
|
let invalid = false;
|
|
161
220
|
let last = "";
|
|
162
221
|
return (text) => {
|
|
222
|
+
const body = codeBody(text);
|
|
163
223
|
let from = previous.length;
|
|
164
|
-
if (!
|
|
224
|
+
if (!startsWithText(body, previous)) {
|
|
165
225
|
from = 0;
|
|
166
226
|
depth = 0;
|
|
167
227
|
quoted = escaped = invalid = false;
|
|
168
228
|
last = "";
|
|
169
229
|
}
|
|
170
|
-
previous =
|
|
171
|
-
for (let i = from; i <
|
|
172
|
-
const c =
|
|
230
|
+
previous = body;
|
|
231
|
+
for (let i = from; i < body.length; i++) {
|
|
232
|
+
const c = body[i];
|
|
173
233
|
if (!/\s/.test(c)) last = c;
|
|
174
234
|
if (quoted) {
|
|
175
235
|
if (escaped) escaped = false;
|
|
@@ -188,6 +248,89 @@ function createJsonCompletenessScanner() {
|
|
|
188
248
|
function jsonLooksComplete(text) {
|
|
189
249
|
return createJsonCompletenessScanner()(text);
|
|
190
250
|
}
|
|
251
|
+
function createCodeBlockSession(onChange) {
|
|
252
|
+
let committed;
|
|
253
|
+
let shown;
|
|
254
|
+
let frames;
|
|
255
|
+
let token;
|
|
256
|
+
let committing = false;
|
|
257
|
+
const tracker = createCodeLanguageTracker(() => onChange());
|
|
258
|
+
const scanJson = createJsonCompletenessScanner();
|
|
259
|
+
let formatted;
|
|
260
|
+
const generationOf = (input) => {
|
|
261
|
+
if (!committed) return 0;
|
|
262
|
+
return input.identity === committed.identity && input.language === committed.language && extendsCode(input.code, committed.code) ? committed.generation : committed.generation + 1;
|
|
263
|
+
};
|
|
264
|
+
const languageOf = (input) => input.language || (input.autoDetect ? tracker.read(input.code, input.streaming) ?? "" : "");
|
|
265
|
+
const pretty = (source, nested) => {
|
|
266
|
+
if (formatted?.source !== source || formatted.nested !== nested) formatted = {
|
|
267
|
+
source,
|
|
268
|
+
nested,
|
|
269
|
+
text: prettyPrintJson(source, nested)
|
|
270
|
+
};
|
|
271
|
+
return formatted.text;
|
|
272
|
+
};
|
|
273
|
+
return {
|
|
274
|
+
read(input) {
|
|
275
|
+
const generation = generationOf(input);
|
|
276
|
+
const language = languageOf(input);
|
|
277
|
+
const displayed = !shown || !input.streaming || input.highlightIntervalMs === 0 || shown.generation !== generation || shown.language !== language ? input.code : shown.code;
|
|
278
|
+
return {
|
|
279
|
+
text: input.formatJson && displayed && language === "json" && (!input.streaming || scanJson(displayed)) ? pretty(displayed, input.expandNestedJson) : displayed,
|
|
280
|
+
language,
|
|
281
|
+
generation
|
|
282
|
+
};
|
|
283
|
+
},
|
|
284
|
+
commit(input) {
|
|
285
|
+
const generation = generationOf(input);
|
|
286
|
+
const moved = input.autoDetect && !input.language ? tracker.observe(input.code, input.streaming) : (tracker.dispose(), false);
|
|
287
|
+
const language = languageOf(input);
|
|
288
|
+
committed = {
|
|
289
|
+
code: input.code,
|
|
290
|
+
language: input.language,
|
|
291
|
+
identity: input.identity,
|
|
292
|
+
generation
|
|
293
|
+
};
|
|
294
|
+
const key = `${generation}:${language}`;
|
|
295
|
+
if (token?.key !== key) token = {
|
|
296
|
+
key,
|
|
297
|
+
value: {}
|
|
298
|
+
};
|
|
299
|
+
const frame = {
|
|
300
|
+
code: input.code,
|
|
301
|
+
language,
|
|
302
|
+
generation: token.value
|
|
303
|
+
};
|
|
304
|
+
committing = true;
|
|
305
|
+
try {
|
|
306
|
+
if (!frames) {
|
|
307
|
+
shown = {
|
|
308
|
+
code: input.code,
|
|
309
|
+
language,
|
|
310
|
+
generation
|
|
311
|
+
};
|
|
312
|
+
frames = createCodeFrame(frame, (next) => {
|
|
313
|
+
shown = {
|
|
314
|
+
code: next.code,
|
|
315
|
+
language: next.language,
|
|
316
|
+
generation: committed.generation
|
|
317
|
+
};
|
|
318
|
+
if (!committing) onChange();
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
frames.update(frame, input.streaming, input.highlightIntervalMs);
|
|
322
|
+
if (shown.code === input.code && shown.language === language) shown.generation = generation;
|
|
323
|
+
} finally {
|
|
324
|
+
committing = false;
|
|
325
|
+
}
|
|
326
|
+
if (moved) onChange();
|
|
327
|
+
},
|
|
328
|
+
dispose() {
|
|
329
|
+
frames?.dispose();
|
|
330
|
+
tracker.dispose();
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
}
|
|
191
334
|
function createRenderQueue() {
|
|
192
335
|
const pending = /* @__PURE__ */ new Map();
|
|
193
336
|
let running = false;
|
|
@@ -229,9 +372,6 @@ function createRenderQueue() {
|
|
|
229
372
|
const mermaidRenderQueue = createRenderQueue();
|
|
230
373
|
const SAFE_SECURITY_LEVELS = /* @__PURE__ */ new Set(["strict", "sandbox"]);
|
|
231
374
|
let ownedThemes = /* @__PURE__ */ new WeakMap();
|
|
232
|
-
const resetMermaidInitializationForTests = () => {
|
|
233
|
-
ownedThemes = /* @__PURE__ */ new WeakMap();
|
|
234
|
-
};
|
|
235
375
|
const readSiteConfig = (mermaid) => {
|
|
236
376
|
const api = mermaid.mermaidAPI;
|
|
237
377
|
return api?.getSiteConfig?.() ?? api?.getConfig?.() ?? {};
|
|
@@ -269,94 +409,265 @@ const ensureMermaidInitialized = (mermaid, isDark) => {
|
|
|
269
409
|
}
|
|
270
410
|
mermaid.initialize(next);
|
|
271
411
|
};
|
|
272
|
-
|
|
412
|
+
function diagramErrorText(error, labels) {
|
|
413
|
+
if (error.reason === "tooLarge") return labels.tooLarge(error.length, error.limit);
|
|
414
|
+
return error.message || labels.renderFailed;
|
|
415
|
+
}
|
|
416
|
+
const ERROR_MESSAGE_MAX_CHARS = 500;
|
|
417
|
+
const LOAD_RETRIES = 3;
|
|
418
|
+
const LOAD_RETRY_MS = 1500;
|
|
419
|
+
function engineMessage(error) {
|
|
420
|
+
const text = (error instanceof Error ? error.message : typeof error === "string" ? error : "").replace(/\r\n?/g, "\n").trim();
|
|
421
|
+
return text.length > ERROR_MESSAGE_MAX_CHARS ? `${text.slice(0, ERROR_MESSAGE_MAX_CHARS)}…` : text;
|
|
422
|
+
}
|
|
423
|
+
var DiagramFailure = class {
|
|
424
|
+
view;
|
|
425
|
+
constructor(view) {
|
|
426
|
+
this.view = view;
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
const diagramId = () => `mermaid-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
|
|
273
430
|
function createDiagramController(load, publish) {
|
|
274
431
|
const owner = {};
|
|
432
|
+
let request;
|
|
433
|
+
let current;
|
|
434
|
+
let shown;
|
|
435
|
+
let frames;
|
|
436
|
+
let updating = false;
|
|
437
|
+
let view = { kind: "source" };
|
|
438
|
+
let loadFailed = false;
|
|
439
|
+
let previousStreaming = false;
|
|
440
|
+
let needsCorrective = false;
|
|
441
|
+
let lastSuccess;
|
|
442
|
+
let loadFailures = 0;
|
|
443
|
+
let nonce = 0;
|
|
444
|
+
let ran;
|
|
275
445
|
let epoch = 0;
|
|
276
|
-
let
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
446
|
+
let retryTimer;
|
|
447
|
+
const sameError = (a, b) => a.reason === "tooLarge" ? b.reason === "tooLarge" && a.length === b.length && a.limit === b.limit : b.reason === a.reason && a.message === b.message;
|
|
448
|
+
const emit = () => publish({
|
|
449
|
+
view,
|
|
450
|
+
loadFailed
|
|
451
|
+
});
|
|
452
|
+
const show = (next) => {
|
|
453
|
+
if (next.kind === "source" && view.kind === "source") return;
|
|
454
|
+
if (next.kind === "error" && view.kind === "error" && sameError(next, view)) return;
|
|
455
|
+
view = next;
|
|
456
|
+
emit();
|
|
457
|
+
};
|
|
280
458
|
const cancel = () => {
|
|
281
459
|
epoch++;
|
|
282
|
-
if (timer !== void 0) clearTimeout(timer);
|
|
283
|
-
timer = void 0;
|
|
284
460
|
mermaidRenderQueue.cancel(owner);
|
|
461
|
+
if (retryTimer !== void 0) clearTimeout(retryTimer);
|
|
462
|
+
retryTimer = void 0;
|
|
285
463
|
};
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
if (
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
464
|
+
const attempt = async (code, dark, streaming, generation) => {
|
|
465
|
+
const stale = () => generation !== epoch;
|
|
466
|
+
let engine;
|
|
467
|
+
try {
|
|
468
|
+
engine = await load();
|
|
469
|
+
} catch {
|
|
470
|
+
if (stale()) return;
|
|
471
|
+
if (loadFailures < LOAD_RETRIES) {
|
|
472
|
+
loadFailures += 1;
|
|
473
|
+
retryTimer = setTimeout(() => {
|
|
474
|
+
retryTimer = void 0;
|
|
475
|
+
nonce++;
|
|
476
|
+
run();
|
|
477
|
+
}, LOAD_RETRY_MS);
|
|
478
|
+
} else if (!loadFailed) {
|
|
479
|
+
loadFailed = true;
|
|
480
|
+
emit();
|
|
302
481
|
}
|
|
303
|
-
|
|
304
|
-
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
loadFailures = 0;
|
|
485
|
+
let reason = "render";
|
|
486
|
+
try {
|
|
487
|
+
if (stale()) return;
|
|
488
|
+
ensureMermaidInitialized(engine, dark);
|
|
489
|
+
const maxTextSize = getMermaidMaxTextSize(engine);
|
|
490
|
+
if (code.length > maxTextSize) throw new DiagramFailure({
|
|
491
|
+
kind: "error",
|
|
492
|
+
reason: "tooLarge",
|
|
493
|
+
length: code.length,
|
|
494
|
+
limit: maxTextSize
|
|
495
|
+
});
|
|
496
|
+
reason = "parse";
|
|
497
|
+
if (!await engine.parse(code)) throw new DiagramFailure({
|
|
498
|
+
kind: "error",
|
|
499
|
+
reason: "parse",
|
|
500
|
+
message: ""
|
|
501
|
+
});
|
|
502
|
+
reason = "render";
|
|
503
|
+
if (stale()) return;
|
|
504
|
+
const { svg, bindFunctions, diagramType } = await engine.render(diagramId(), code);
|
|
505
|
+
if (stale()) return;
|
|
506
|
+
needsCorrective = false;
|
|
507
|
+
lastSuccess = {
|
|
508
|
+
code,
|
|
509
|
+
dark
|
|
510
|
+
};
|
|
511
|
+
loadFailed = false;
|
|
512
|
+
show({
|
|
513
|
+
kind: "diagram",
|
|
305
514
|
svg,
|
|
306
|
-
|
|
515
|
+
chartType: diagramType ?? "",
|
|
516
|
+
bind: bindFunctions
|
|
307
517
|
});
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
phase = "render";
|
|
316
|
-
if (!valid()) return;
|
|
317
|
-
return mermaidRenderQueue.enqueue(owner, async () => {
|
|
318
|
-
if (!valid()) return;
|
|
319
|
-
ensureMermaidInitialized(engine, current.dark);
|
|
320
|
-
if (current.code.length > getMermaidMaxTextSize(engine)) throw new Error("Diagram exceeds Mermaid’s maximum text size");
|
|
321
|
-
const parsed = await engine.parse(current.code, { suppressErrors: true });
|
|
322
|
-
if (!valid()) return;
|
|
323
|
-
if (parsed === false) throw new Error("Diagram syntax is incomplete or invalid");
|
|
324
|
-
const result = await engine.render(`aimd-diagram-${++nextId}`, current.code);
|
|
325
|
-
if (!valid()) return;
|
|
326
|
-
svg = result.svg;
|
|
327
|
-
bind = result.bindFunctions;
|
|
328
|
-
publish({
|
|
329
|
-
status: "ready",
|
|
330
|
-
svg,
|
|
331
|
-
bind
|
|
332
|
-
});
|
|
333
|
-
});
|
|
334
|
-
}).catch((error) => {
|
|
335
|
-
if (valid()) publish({
|
|
336
|
-
status: current.streaming && phase === "render" ? "loading" : "error",
|
|
337
|
-
svg,
|
|
338
|
-
bind,
|
|
339
|
-
error: (phase === "load" ? "Diagram engine could not load: " : "") + (error instanceof Error ? error.message : String(error)).slice(0, 500)
|
|
340
|
-
});
|
|
341
|
-
});
|
|
518
|
+
} catch (error) {
|
|
519
|
+
if (stale()) return;
|
|
520
|
+
if (streaming) return;
|
|
521
|
+
const failure = error instanceof DiagramFailure ? error.view : {
|
|
522
|
+
kind: "error",
|
|
523
|
+
reason,
|
|
524
|
+
message: engineMessage(error)
|
|
342
525
|
};
|
|
343
|
-
if (
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
526
|
+
if (needsCorrective) {
|
|
527
|
+
needsCorrective = false;
|
|
528
|
+
show(failure);
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
if (view.kind === "diagram") return;
|
|
532
|
+
show(failure);
|
|
533
|
+
}
|
|
534
|
+
};
|
|
535
|
+
function run() {
|
|
536
|
+
if (!request || !current || !shown) return;
|
|
537
|
+
const { dark, active, streaming, interval } = request;
|
|
538
|
+
const code = !streaming || interval === 0 || current.generation !== shown.generation ? request.code : shown.code;
|
|
539
|
+
if (ran && ran.code === code && ran.dark === dark && ran.active === active && ran.streaming === streaming && ran.nonce === nonce) return;
|
|
540
|
+
ran = {
|
|
541
|
+
code,
|
|
542
|
+
dark,
|
|
543
|
+
active,
|
|
544
|
+
streaming,
|
|
545
|
+
nonce
|
|
546
|
+
};
|
|
547
|
+
cancel();
|
|
548
|
+
if (streaming && !previousStreaming) {
|
|
549
|
+
needsCorrective = false;
|
|
550
|
+
lastSuccess = void 0;
|
|
551
|
+
loadFailures = 0;
|
|
552
|
+
if (view.kind !== "source" || loadFailed) {
|
|
553
|
+
loadFailed = false;
|
|
554
|
+
view = { kind: "source" };
|
|
555
|
+
emit();
|
|
556
|
+
}
|
|
557
|
+
} else if (!streaming && previousStreaming) needsCorrective = true;
|
|
558
|
+
previousStreaming = streaming;
|
|
559
|
+
if (!code || !active) return;
|
|
560
|
+
if (lastSuccess?.code === code && lastSuccess.dark === dark) {
|
|
561
|
+
needsCorrective = false;
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
const generation = epoch;
|
|
565
|
+
mermaidRenderQueue.enqueue(owner, () => attempt(code, dark, streaming, generation));
|
|
566
|
+
}
|
|
567
|
+
return {
|
|
568
|
+
update(next) {
|
|
569
|
+
request = next;
|
|
570
|
+
updating = true;
|
|
571
|
+
try {
|
|
572
|
+
if (!frames || !current) {
|
|
573
|
+
current = shown = nextCodeFrame(void 0, next.code, "");
|
|
574
|
+
frames = createCodeFrame(current, (frame) => {
|
|
575
|
+
shown = frame;
|
|
576
|
+
if (!updating) run();
|
|
577
|
+
});
|
|
578
|
+
} else current = nextCodeFrame(current, next.code, "");
|
|
579
|
+
frames.update(current, next.streaming, next.interval);
|
|
580
|
+
} finally {
|
|
581
|
+
updating = false;
|
|
582
|
+
}
|
|
583
|
+
run();
|
|
347
584
|
},
|
|
348
|
-
|
|
585
|
+
retry() {
|
|
586
|
+
loadFailures = 0;
|
|
587
|
+
if (loadFailed) {
|
|
588
|
+
loadFailed = false;
|
|
589
|
+
emit();
|
|
590
|
+
}
|
|
591
|
+
nonce++;
|
|
592
|
+
run();
|
|
593
|
+
},
|
|
594
|
+
dispose() {
|
|
595
|
+
cancel();
|
|
596
|
+
frames?.dispose();
|
|
597
|
+
ran = void 0;
|
|
598
|
+
}
|
|
349
599
|
};
|
|
350
600
|
}
|
|
601
|
+
function resolveLabels(defaults, option) {
|
|
602
|
+
const overrides = typeof option === "function" ? option() : option;
|
|
603
|
+
if (!overrides) return defaults;
|
|
604
|
+
const labels = { ...defaults };
|
|
605
|
+
for (const key of Object.keys(overrides)) {
|
|
606
|
+
const value = overrides[key];
|
|
607
|
+
if (value !== void 0) labels[key] = value;
|
|
608
|
+
}
|
|
609
|
+
return labels;
|
|
610
|
+
}
|
|
611
|
+
const defaultCodeBlockLabels = Object.freeze({
|
|
612
|
+
actions: "Code block actions",
|
|
613
|
+
plainText: "text",
|
|
614
|
+
copy: "Copy code",
|
|
615
|
+
copied: "Copied",
|
|
616
|
+
copyFailed: "Copy failed",
|
|
617
|
+
showSource: "Show source",
|
|
618
|
+
showPreview: "Show preview",
|
|
619
|
+
expand: "Expand",
|
|
620
|
+
collapse: "Collapse",
|
|
621
|
+
previewFailed: "Preview failed. Source is available below."
|
|
622
|
+
});
|
|
623
|
+
const defaultDiagramLabels = Object.freeze({
|
|
624
|
+
waiting: "Waiting for diagram…",
|
|
625
|
+
rendering: "Rendering diagram…",
|
|
626
|
+
loadFailed: "Diagram engine could not load.",
|
|
627
|
+
retry: "Retry diagram",
|
|
628
|
+
renderFailed: "Mermaid could not render this diagram.",
|
|
629
|
+
tooLarge: (length, limit) => `Diagram source is ${length} characters, above mermaid's maxTextSize of ${limit}.`
|
|
630
|
+
});
|
|
631
|
+
const defaultImageLabels = Object.freeze({
|
|
632
|
+
close: "Close preview",
|
|
633
|
+
prev: "Previous image",
|
|
634
|
+
next: "Next image",
|
|
635
|
+
rotateLeft: "Rotate left",
|
|
636
|
+
rotateRight: "Rotate right",
|
|
637
|
+
zoomIn: "Zoom in",
|
|
638
|
+
zoomOut: "Zoom out",
|
|
639
|
+
flipX: "Flip horizontally",
|
|
640
|
+
flipY: "Flip vertically",
|
|
641
|
+
loading: "Loading image…",
|
|
642
|
+
loadFailed: "Image could not be loaded.",
|
|
643
|
+
open: (alt) => `Preview image${alt ? `: ${alt}` : ""}`,
|
|
644
|
+
preview: "Image preview",
|
|
645
|
+
actions: "Image preview actions"
|
|
646
|
+
});
|
|
647
|
+
const defaultTableLabels = Object.freeze({
|
|
648
|
+
actions: "Table actions",
|
|
649
|
+
copy: "Copy table",
|
|
650
|
+
download: "Download CSV",
|
|
651
|
+
copied: "Table copied",
|
|
652
|
+
copyFailed: "Copy failed",
|
|
653
|
+
scrollRegion: "Scrollable table",
|
|
654
|
+
mergedCells: "Only tables without merged cells can be exported",
|
|
655
|
+
notRectangular: "Only rectangular tables can be exported",
|
|
656
|
+
unsupportedStructure: "Unsupported table structure",
|
|
657
|
+
unsupportedContent: "Unsupported table content",
|
|
658
|
+
unavailable: "Table source is unavailable"
|
|
659
|
+
});
|
|
351
660
|
const locks = /* @__PURE__ */ new WeakMap();
|
|
352
|
-
function lockImagePreviewScroll(target) {
|
|
661
|
+
function lockImagePreviewScroll(target, scrollbarWidth = 0) {
|
|
353
662
|
let lock = locks.get(target);
|
|
354
663
|
if (!lock) {
|
|
355
664
|
lock = {
|
|
356
665
|
count: 0,
|
|
357
|
-
overflow: target.style.overflow
|
|
666
|
+
overflow: target.style.overflow,
|
|
667
|
+
paddingRight: target.style.paddingRight
|
|
358
668
|
};
|
|
359
669
|
locks.set(target, lock);
|
|
670
|
+
if (scrollbarWidth > 0) target.style.paddingRight = lock.paddingRight ? `calc(${lock.paddingRight} + ${scrollbarWidth}px)` : `${scrollbarWidth}px`;
|
|
360
671
|
}
|
|
361
672
|
lock.count++;
|
|
362
673
|
target.style.overflow = "hidden";
|
|
@@ -366,10 +677,454 @@ function lockImagePreviewScroll(target) {
|
|
|
366
677
|
released = true;
|
|
367
678
|
if (--lock.count === 0) {
|
|
368
679
|
if (target.style.overflow === "hidden") target.style.overflow = lock.overflow;
|
|
680
|
+
target.style.paddingRight = lock.paddingRight;
|
|
369
681
|
locks.delete(target);
|
|
370
682
|
}
|
|
371
683
|
};
|
|
372
684
|
}
|
|
685
|
+
const initialImageTransform = () => ({
|
|
686
|
+
x: 0,
|
|
687
|
+
y: 0,
|
|
688
|
+
rotate: 0,
|
|
689
|
+
scale: 1,
|
|
690
|
+
flipX: false,
|
|
691
|
+
flipY: false
|
|
692
|
+
});
|
|
693
|
+
function imageTransformStyle(transform) {
|
|
694
|
+
const { x, y, scale, rotate, flipX, flipY } = transform;
|
|
695
|
+
return `translate3d(${x}px, ${y}px, 0) scale3d(${flipX ? "-" : ""}${scale}, ${flipY ? "-" : ""}${scale}, 1) rotate(${rotate}deg)`;
|
|
696
|
+
}
|
|
697
|
+
const DEFAULT_SCALE_LIMITS = {
|
|
698
|
+
min: 1,
|
|
699
|
+
max: 50
|
|
700
|
+
};
|
|
701
|
+
function zoomImage(transform, ratio, geometry, centerX = geometry.viewportWidth / 2, centerY = geometry.viewportHeight / 2, touch = false, limits = DEFAULT_SCALE_LIMITS) {
|
|
702
|
+
if (!Number.isFinite(ratio) || ratio <= 0) return transform;
|
|
703
|
+
const floor = touch ? .01 : limits.min;
|
|
704
|
+
const scale = Math.min(limits.max, Math.max(floor, transform.scale * ratio));
|
|
705
|
+
const difference = scale / transform.scale - 1;
|
|
706
|
+
let x = transform.x - difference * (centerX - transform.x - geometry.left - geometry.width / 2);
|
|
707
|
+
let y = transform.y - difference * (centerY - transform.y - geometry.top - geometry.height / 2);
|
|
708
|
+
if (ratio < 1 && scale === 1 && geometry.width <= geometry.viewportWidth && geometry.height <= geometry.viewportHeight) x = y = 0;
|
|
709
|
+
return {
|
|
710
|
+
...transform,
|
|
711
|
+
x,
|
|
712
|
+
y,
|
|
713
|
+
scale
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
function imageWheelRatio(delta, mode = 0, pinch = false, step = .5) {
|
|
717
|
+
if (!Number.isFinite(delta) || delta === 0) return 1;
|
|
718
|
+
if (pinch) return Math.min(1 + step, Math.max(1 / (1 + step), Math.exp(-delta / 100)));
|
|
719
|
+
const pixels = mode === 1 ? delta * 100 / 3 : mode === 2 ? delta * 100 : delta;
|
|
720
|
+
const ratio = 1 + Math.min(Math.abs(pixels / 100), 1) * step;
|
|
721
|
+
return pixels > 0 ? 1 / ratio : ratio;
|
|
722
|
+
}
|
|
723
|
+
function reboundImage(transform, geometry, bounds, minScale = 1) {
|
|
724
|
+
if (transform.scale < minScale) return {
|
|
725
|
+
...transform,
|
|
726
|
+
x: 0,
|
|
727
|
+
y: 0,
|
|
728
|
+
scale: minScale
|
|
729
|
+
};
|
|
730
|
+
const rotated = transform.rotate % 180 !== 0;
|
|
731
|
+
const width = (rotated ? geometry.height : geometry.width) * transform.scale;
|
|
732
|
+
const height = (rotated ? geometry.width : geometry.height) * transform.scale;
|
|
733
|
+
if (width <= geometry.viewportWidth && height <= geometry.viewportHeight) return {
|
|
734
|
+
...transform,
|
|
735
|
+
x: 0,
|
|
736
|
+
y: 0
|
|
737
|
+
};
|
|
738
|
+
const fix = (position, start, size, viewport) => {
|
|
739
|
+
const offset = (size - viewport) / 2;
|
|
740
|
+
if (size > viewport) {
|
|
741
|
+
if (start > 0) return offset;
|
|
742
|
+
if (start < 0 && start + size < viewport) return -offset;
|
|
743
|
+
} else if (start < 0 || start + size > viewport) return start < 0 ? offset : -offset;
|
|
744
|
+
return position;
|
|
745
|
+
};
|
|
746
|
+
return {
|
|
747
|
+
...transform,
|
|
748
|
+
x: fix(transform.x, bounds.left, width, geometry.viewportWidth),
|
|
749
|
+
y: fix(transform.y, bounds.top, height, geometry.viewportHeight)
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
function imagePinchCenter(oldA, oldB, a, b) {
|
|
753
|
+
const distanceA = Math.hypot(a.x - oldA.x, a.y - oldA.y), distanceB = Math.hypot(b.x - oldB.x, b.y - oldB.y);
|
|
754
|
+
const ratio = distanceA + distanceB ? distanceA / (distanceA + distanceB) : 0;
|
|
755
|
+
return {
|
|
756
|
+
x: oldA.x + ratio * (oldB.x - oldA.x),
|
|
757
|
+
y: oldA.y + ratio * (oldB.y - oldA.y)
|
|
758
|
+
};
|
|
759
|
+
}
|
|
760
|
+
const CLOSE_MS = 300;
|
|
761
|
+
const positive = (value, fallback) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
|
|
762
|
+
const closedState = Object.freeze({
|
|
763
|
+
phase: "closed",
|
|
764
|
+
items: Object.freeze([]),
|
|
765
|
+
current: -1,
|
|
766
|
+
item: void 0,
|
|
767
|
+
transform: initialImageTransform(),
|
|
768
|
+
status: "loading",
|
|
769
|
+
moving: false,
|
|
770
|
+
movable: true,
|
|
771
|
+
origin: void 0,
|
|
772
|
+
canPrevious: false,
|
|
773
|
+
canNext: false,
|
|
774
|
+
canZoomIn: false,
|
|
775
|
+
canZoomOut: false
|
|
776
|
+
});
|
|
777
|
+
function createImagePreviewController(host, publish, options = {}) {
|
|
778
|
+
const limits = {
|
|
779
|
+
min: positive(options.minScale, 1),
|
|
780
|
+
max: 0
|
|
781
|
+
};
|
|
782
|
+
limits.max = Math.max(limits.min, positive(options.maxScale, 50));
|
|
783
|
+
const baseScale = Math.min(limits.max, Math.max(limits.min, 1));
|
|
784
|
+
const scaleStep = positive(options.scaleStep, .5);
|
|
785
|
+
const movable = options.movable ?? true;
|
|
786
|
+
const wheelZoom = options.wheel ?? true;
|
|
787
|
+
let phase = "closed";
|
|
788
|
+
let items = [];
|
|
789
|
+
let selected;
|
|
790
|
+
let current = -1;
|
|
791
|
+
let transform = {
|
|
792
|
+
...initialImageTransform(),
|
|
793
|
+
scale: baseScale
|
|
794
|
+
};
|
|
795
|
+
let status = "loading";
|
|
796
|
+
let moving = false;
|
|
797
|
+
let origin;
|
|
798
|
+
let unsubscribe;
|
|
799
|
+
let cancelPublish;
|
|
800
|
+
let cancelOpening;
|
|
801
|
+
let closeTimer;
|
|
802
|
+
const pointers = /* @__PURE__ */ new Map();
|
|
803
|
+
let grip;
|
|
804
|
+
let displaced = false;
|
|
805
|
+
const snapshot = () => {
|
|
806
|
+
if (phase === "closed") return closedState;
|
|
807
|
+
const ready = status === "ready";
|
|
808
|
+
return {
|
|
809
|
+
phase,
|
|
810
|
+
items,
|
|
811
|
+
current,
|
|
812
|
+
item: items[current],
|
|
813
|
+
transform,
|
|
814
|
+
status,
|
|
815
|
+
moving,
|
|
816
|
+
movable,
|
|
817
|
+
origin,
|
|
818
|
+
canPrevious: current > 0,
|
|
819
|
+
canNext: current < items.length - 1,
|
|
820
|
+
canZoomIn: ready && transform.scale < limits.max,
|
|
821
|
+
canZoomOut: ready && transform.scale > limits.min
|
|
822
|
+
};
|
|
823
|
+
};
|
|
824
|
+
let reported;
|
|
825
|
+
const flush = () => {
|
|
826
|
+
publish(snapshot());
|
|
827
|
+
const action = reported;
|
|
828
|
+
reported = void 0;
|
|
829
|
+
if (action) options.onTransform?.({
|
|
830
|
+
transform,
|
|
831
|
+
action
|
|
832
|
+
});
|
|
833
|
+
};
|
|
834
|
+
const emit = () => {
|
|
835
|
+
cancelPublish?.();
|
|
836
|
+
cancelPublish = void 0;
|
|
837
|
+
flush();
|
|
838
|
+
};
|
|
839
|
+
const emitNextFrame = () => {
|
|
840
|
+
cancelPublish ??= host.frame(() => {
|
|
841
|
+
cancelPublish = void 0;
|
|
842
|
+
flush();
|
|
843
|
+
});
|
|
844
|
+
};
|
|
845
|
+
const apply = (next, action) => {
|
|
846
|
+
if (next.x === transform.x && next.y === transform.y && next.scale === transform.scale && next.rotate === transform.rotate && next.flipX === transform.flipX && next.flipY === transform.flipY) return;
|
|
847
|
+
transform = next;
|
|
848
|
+
reported = action;
|
|
849
|
+
};
|
|
850
|
+
const endGesture = () => {
|
|
851
|
+
pointers.clear();
|
|
852
|
+
grip = void 0;
|
|
853
|
+
displaced = false;
|
|
854
|
+
moving = false;
|
|
855
|
+
};
|
|
856
|
+
const startImage = () => {
|
|
857
|
+
transform = {
|
|
858
|
+
...initialImageTransform(),
|
|
859
|
+
scale: baseScale
|
|
860
|
+
};
|
|
861
|
+
reported = void 0;
|
|
862
|
+
status = "loading";
|
|
863
|
+
endGesture();
|
|
864
|
+
};
|
|
865
|
+
const zoom = (action, ratio, x, y, touch = false) => {
|
|
866
|
+
const box = host.geometry();
|
|
867
|
+
if (box && status === "ready") apply(zoomImage(transform, ratio, box, x, y, touch, limits), action);
|
|
868
|
+
};
|
|
869
|
+
const rebound = () => {
|
|
870
|
+
if (transform.scale < limits.min) {
|
|
871
|
+
apply({
|
|
872
|
+
...transform,
|
|
873
|
+
x: 0,
|
|
874
|
+
y: 0,
|
|
875
|
+
scale: limits.min
|
|
876
|
+
}, "rebound");
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
const box = host.geometry();
|
|
880
|
+
if (!box) return;
|
|
881
|
+
const turned = transform.rotate % 180 !== 0;
|
|
882
|
+
const width = (turned ? box.height : box.width) * transform.scale;
|
|
883
|
+
const height = (turned ? box.width : box.height) * transform.scale;
|
|
884
|
+
apply(reboundImage(transform, box, {
|
|
885
|
+
left: box.left + box.width / 2 + transform.x - width / 2,
|
|
886
|
+
top: box.top + box.height / 2 + transform.y - height / 2
|
|
887
|
+
}, limits.min), "rebound");
|
|
888
|
+
};
|
|
889
|
+
const anchorOf = (id) => {
|
|
890
|
+
const point = host.anchor?.(id);
|
|
891
|
+
return point && Number.isFinite(point.x) && Number.isFinite(point.y) ? {
|
|
892
|
+
x: point.x,
|
|
893
|
+
y: point.y
|
|
894
|
+
} : void 0;
|
|
895
|
+
};
|
|
896
|
+
const finishClosing = () => {
|
|
897
|
+
closeTimer = void 0;
|
|
898
|
+
phase = "closed";
|
|
899
|
+
items = [];
|
|
900
|
+
selected = void 0;
|
|
901
|
+
origin = void 0;
|
|
902
|
+
current = -1;
|
|
903
|
+
reported = void 0;
|
|
904
|
+
emit();
|
|
905
|
+
options.afterOpenChange?.(false);
|
|
906
|
+
};
|
|
907
|
+
const close = () => {
|
|
908
|
+
if (phase === "closed" || phase === "closing") return;
|
|
909
|
+
cancelOpening?.();
|
|
910
|
+
cancelOpening = void 0;
|
|
911
|
+
unsubscribe?.();
|
|
912
|
+
unsubscribe = void 0;
|
|
913
|
+
endGesture();
|
|
914
|
+
reported = void 0;
|
|
915
|
+
origin = selected ? anchorOf(selected) : void 0;
|
|
916
|
+
phase = "closing";
|
|
917
|
+
const info = {
|
|
918
|
+
current,
|
|
919
|
+
item: items[current]
|
|
920
|
+
};
|
|
921
|
+
const duration = typeof options.closeDuration === "function" ? options.closeDuration() : options.closeDuration ?? CLOSE_MS;
|
|
922
|
+
if (duration > 0) {
|
|
923
|
+
emit();
|
|
924
|
+
closeTimer = setTimeout(finishClosing, duration);
|
|
925
|
+
options.onOpenChange?.(false, info);
|
|
926
|
+
} else try {
|
|
927
|
+
options.onOpenChange?.(false, info);
|
|
928
|
+
} finally {
|
|
929
|
+
if (phase === "closing") finishClosing();
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
const go = (delta) => {
|
|
933
|
+
const target = current + delta;
|
|
934
|
+
if (phase === "closed" || phase === "closing" || target < 0 || target >= items.length || target === current) return;
|
|
935
|
+
const previous = current;
|
|
936
|
+
const { x, y, scale, rotate, flipX, flipY } = transform;
|
|
937
|
+
const transformed = x !== 0 || y !== 0 || scale !== baseScale || rotate !== 0 || flipX || flipY;
|
|
938
|
+
current = target;
|
|
939
|
+
selected = items[target].id;
|
|
940
|
+
startImage();
|
|
941
|
+
if (transformed) reported = delta < 0 ? "prev" : "next";
|
|
942
|
+
emit();
|
|
943
|
+
options.onChange?.(current, previous);
|
|
944
|
+
};
|
|
945
|
+
const follow = (gallery) => {
|
|
946
|
+
const next = gallery.items();
|
|
947
|
+
const index = next.findIndex((item) => item.id === selected);
|
|
948
|
+
if (index < 0) return close();
|
|
949
|
+
if (next[index].src !== items[current]?.src) startImage();
|
|
950
|
+
items = next;
|
|
951
|
+
current = index;
|
|
952
|
+
emit();
|
|
953
|
+
};
|
|
954
|
+
return {
|
|
955
|
+
state: snapshot,
|
|
956
|
+
open(gallery, id) {
|
|
957
|
+
const list = gallery.items();
|
|
958
|
+
const index = list.findIndex((item) => item.id === id);
|
|
959
|
+
if (index < 0) return false;
|
|
960
|
+
if (closeTimer !== void 0) clearTimeout(closeTimer);
|
|
961
|
+
closeTimer = void 0;
|
|
962
|
+
unsubscribe?.();
|
|
963
|
+
cancelOpening?.();
|
|
964
|
+
items = list;
|
|
965
|
+
current = index;
|
|
966
|
+
selected = id;
|
|
967
|
+
origin = anchorOf(id);
|
|
968
|
+
startImage();
|
|
969
|
+
unsubscribe = gallery.subscribe(() => follow(gallery));
|
|
970
|
+
if (phase === "open") {
|
|
971
|
+
emit();
|
|
972
|
+
return true;
|
|
973
|
+
}
|
|
974
|
+
cancelOpening = void 0;
|
|
975
|
+
const starting = phase !== "opening";
|
|
976
|
+
phase = "opening";
|
|
977
|
+
emit();
|
|
978
|
+
cancelOpening = host.frame(() => {
|
|
979
|
+
const measured = selected ? anchorOf(selected) : void 0;
|
|
980
|
+
if (measured?.x !== origin?.x || measured?.y !== origin?.y) {
|
|
981
|
+
origin = measured;
|
|
982
|
+
emit();
|
|
983
|
+
}
|
|
984
|
+
cancelOpening = host.frame(() => {
|
|
985
|
+
cancelOpening = void 0;
|
|
986
|
+
phase = "open";
|
|
987
|
+
emit();
|
|
988
|
+
options.afterOpenChange?.(true);
|
|
989
|
+
});
|
|
990
|
+
});
|
|
991
|
+
if (starting) options.onOpenChange?.(true, {
|
|
992
|
+
current,
|
|
993
|
+
item: items[current]
|
|
994
|
+
});
|
|
995
|
+
return true;
|
|
996
|
+
},
|
|
997
|
+
close,
|
|
998
|
+
go,
|
|
999
|
+
action(name) {
|
|
1000
|
+
if (phase === "closed" || phase === "closing") return;
|
|
1001
|
+
if (name === "close") return close();
|
|
1002
|
+
if (name === "prev") return go(-1);
|
|
1003
|
+
if (name === "next") return go(1);
|
|
1004
|
+
if (status !== "ready") return;
|
|
1005
|
+
if (name === "zoomIn") zoom(name, 1 + scaleStep);
|
|
1006
|
+
else if (name === "zoomOut") zoom(name, 1 / (1 + scaleStep));
|
|
1007
|
+
else if (name === "rotateLeft") apply({
|
|
1008
|
+
...transform,
|
|
1009
|
+
rotate: transform.rotate - 90
|
|
1010
|
+
}, name);
|
|
1011
|
+
else if (name === "rotateRight") apply({
|
|
1012
|
+
...transform,
|
|
1013
|
+
rotate: transform.rotate + 90
|
|
1014
|
+
}, name);
|
|
1015
|
+
else if (name === "flipX") apply({
|
|
1016
|
+
...transform,
|
|
1017
|
+
flipX: !transform.flipX
|
|
1018
|
+
}, name);
|
|
1019
|
+
else if (name === "flipY") apply({
|
|
1020
|
+
...transform,
|
|
1021
|
+
flipY: !transform.flipY
|
|
1022
|
+
}, name);
|
|
1023
|
+
emit();
|
|
1024
|
+
},
|
|
1025
|
+
loaded() {
|
|
1026
|
+
if (phase === "closed" || status === "ready") return;
|
|
1027
|
+
status = "ready";
|
|
1028
|
+
emit();
|
|
1029
|
+
},
|
|
1030
|
+
failed() {
|
|
1031
|
+
if (phase === "closed" || status === "error") return;
|
|
1032
|
+
status = "error";
|
|
1033
|
+
endGesture();
|
|
1034
|
+
emit();
|
|
1035
|
+
},
|
|
1036
|
+
pointerDown(pointer) {
|
|
1037
|
+
if (!movable || phase !== "open" && phase !== "opening" || status !== "ready") return false;
|
|
1038
|
+
if (pointer.button !== void 0 && pointer.button !== 0) return false;
|
|
1039
|
+
if (pointers.size >= 2 && !pointers.has(pointer.id)) return false;
|
|
1040
|
+
pointers.set(pointer.id, {
|
|
1041
|
+
x: pointer.x,
|
|
1042
|
+
y: pointer.y
|
|
1043
|
+
});
|
|
1044
|
+
grip = pointers.size === 1 ? {
|
|
1045
|
+
x: pointer.x - transform.x,
|
|
1046
|
+
y: pointer.y - transform.y
|
|
1047
|
+
} : void 0;
|
|
1048
|
+
moving = true;
|
|
1049
|
+
emit();
|
|
1050
|
+
return true;
|
|
1051
|
+
},
|
|
1052
|
+
pointerMove(pointer) {
|
|
1053
|
+
const previous = pointers.get(pointer.id);
|
|
1054
|
+
if (!previous || previous.x === pointer.x && previous.y === pointer.y) return;
|
|
1055
|
+
const before = [...pointers.values()];
|
|
1056
|
+
pointers.set(pointer.id, {
|
|
1057
|
+
x: pointer.x,
|
|
1058
|
+
y: pointer.y
|
|
1059
|
+
});
|
|
1060
|
+
if (pointers.size === 2) {
|
|
1061
|
+
const [a, b] = [...pointers.values()];
|
|
1062
|
+
const span = Math.hypot(before[0].x - before[1].x, before[0].y - before[1].y);
|
|
1063
|
+
const center = imagePinchCenter(before[0], before[1], a, b);
|
|
1064
|
+
if (span > 0) zoom("pinch", Math.hypot(a.x - b.x, a.y - b.y) / span, center.x, center.y, true);
|
|
1065
|
+
} else if (grip) apply({
|
|
1066
|
+
...transform,
|
|
1067
|
+
x: pointer.x - grip.x,
|
|
1068
|
+
y: pointer.y - grip.y
|
|
1069
|
+
}, "move");
|
|
1070
|
+
displaced = true;
|
|
1071
|
+
emitNextFrame();
|
|
1072
|
+
},
|
|
1073
|
+
pointerUp(id) {
|
|
1074
|
+
if (!pointers.delete(id)) return;
|
|
1075
|
+
const [remaining] = pointers.values();
|
|
1076
|
+
if (remaining) {
|
|
1077
|
+
grip = {
|
|
1078
|
+
x: remaining.x - transform.x,
|
|
1079
|
+
y: remaining.y - transform.y
|
|
1080
|
+
};
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
const settle = displaced;
|
|
1084
|
+
endGesture();
|
|
1085
|
+
if (settle) rebound();
|
|
1086
|
+
emit();
|
|
1087
|
+
},
|
|
1088
|
+
wheel(input) {
|
|
1089
|
+
if (!wheelZoom || phase !== "open" || status !== "ready" || !input.deltaY) return false;
|
|
1090
|
+
zoom("wheel", imageWheelRatio(input.deltaY, input.mode, input.pinch, scaleStep), input.x, input.y);
|
|
1091
|
+
emitNextFrame();
|
|
1092
|
+
return true;
|
|
1093
|
+
},
|
|
1094
|
+
doubleClick(x, y) {
|
|
1095
|
+
if (phase !== "open" || status !== "ready") return;
|
|
1096
|
+
if (transform.scale !== baseScale) apply({
|
|
1097
|
+
...transform,
|
|
1098
|
+
x: 0,
|
|
1099
|
+
y: 0,
|
|
1100
|
+
scale: baseScale
|
|
1101
|
+
}, "doubleClick");
|
|
1102
|
+
else zoom("doubleClick", 1 + scaleStep, x, y);
|
|
1103
|
+
emit();
|
|
1104
|
+
},
|
|
1105
|
+
key(key) {
|
|
1106
|
+
if (phase !== "open" && phase !== "opening" || items.length < 2) return false;
|
|
1107
|
+
if (key !== "ArrowLeft" && key !== "ArrowRight") return false;
|
|
1108
|
+
go(key === "ArrowLeft" ? -1 : 1);
|
|
1109
|
+
return true;
|
|
1110
|
+
},
|
|
1111
|
+
dispose() {
|
|
1112
|
+
if (closeTimer !== void 0) clearTimeout(closeTimer);
|
|
1113
|
+
closeTimer = void 0;
|
|
1114
|
+
cancelPublish?.();
|
|
1115
|
+
cancelOpening?.();
|
|
1116
|
+
unsubscribe?.();
|
|
1117
|
+
cancelPublish = cancelOpening = unsubscribe = void 0;
|
|
1118
|
+
endGesture();
|
|
1119
|
+
phase = "closed";
|
|
1120
|
+
items = [];
|
|
1121
|
+
selected = void 0;
|
|
1122
|
+
origin = void 0;
|
|
1123
|
+
current = -1;
|
|
1124
|
+
reported = void 0;
|
|
1125
|
+
}
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
373
1128
|
const imageIconPaths = {
|
|
374
1129
|
rotateLeft: ["M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8", "M3 3v5h5"],
|
|
375
1130
|
rotateRight: ["M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8", "M21 3v5h-5"],
|
|
@@ -416,16 +1171,20 @@ const imageIconPaths = {
|
|
|
416
1171
|
"M11 9a2 2 0 1 1-4 0 2 2 0 0 1 4 0"
|
|
417
1172
|
]
|
|
418
1173
|
};
|
|
419
|
-
const imageGroupSelector = "[data-aimd-image-scope], .aim-typography-root, .aimd-vue, .mantine-Typography-root";
|
|
420
1174
|
const galleries = /* @__PURE__ */ new WeakMap();
|
|
421
1175
|
function getImageGallery(scope) {
|
|
422
1176
|
const existing = galleries.get(scope);
|
|
423
1177
|
if (existing) return existing;
|
|
424
1178
|
const entries = /* @__PURE__ */ new Map();
|
|
425
1179
|
const listeners = /* @__PURE__ */ new Set();
|
|
426
|
-
|
|
1180
|
+
let sorted;
|
|
1181
|
+
const notify = () => {
|
|
1182
|
+
sorted = void 0;
|
|
1183
|
+
listeners.forEach((listener) => listener());
|
|
1184
|
+
};
|
|
427
1185
|
const gallery = {
|
|
428
|
-
items: () => [...entries.values()].sort((a, b) => a.precedes(b.id) ? -1 : b.precedes(a.id) ? 1 : 0),
|
|
1186
|
+
items: () => sorted ??= [...entries.values()].sort((a, b) => a.precedes(b.id) ? -1 : b.precedes(a.id) ? 1 : 0),
|
|
1187
|
+
size: () => entries.size,
|
|
429
1188
|
subscribe(listener) {
|
|
430
1189
|
listeners.add(listener);
|
|
431
1190
|
return () => {
|
|
@@ -445,84 +1204,17 @@ function getImageGallery(scope) {
|
|
|
445
1204
|
galleries.set(scope, gallery);
|
|
446
1205
|
return gallery;
|
|
447
1206
|
}
|
|
448
|
-
const
|
|
449
|
-
close
|
|
450
|
-
prev
|
|
451
|
-
next
|
|
452
|
-
rotateLeft
|
|
453
|
-
rotateRight
|
|
454
|
-
zoomIn
|
|
455
|
-
zoomOut
|
|
456
|
-
flipX
|
|
457
|
-
flipY
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
x: 0,
|
|
461
|
-
y: 0,
|
|
462
|
-
rotate: 0,
|
|
463
|
-
scale: 1,
|
|
464
|
-
flipX: false,
|
|
465
|
-
flipY: false
|
|
466
|
-
});
|
|
467
|
-
function imageTransformStyle(transform) {
|
|
468
|
-
const { x, y, scale, rotate, flipX, flipY } = transform;
|
|
469
|
-
return `translate3d(${x}px, ${y}px, 0) scale3d(${flipX ? "-" : ""}${scale}, ${flipY ? "-" : ""}${scale}, 1) rotate(${rotate}deg)`;
|
|
470
|
-
}
|
|
471
|
-
function zoomImage(transform, ratio, geometry, centerX = geometry.viewportWidth / 2, centerY = geometry.viewportHeight / 2, touch = false) {
|
|
472
|
-
if (!Number.isFinite(ratio) || ratio <= 0) return transform;
|
|
473
|
-
const scale = Math.min(50, touch ? Math.max(.01, transform.scale * ratio) : Math.max(1, transform.scale * ratio));
|
|
474
|
-
const difference = scale / transform.scale - 1;
|
|
475
|
-
let x = transform.x - difference * (centerX - transform.x - geometry.left - geometry.width / 2);
|
|
476
|
-
let y = transform.y - difference * (centerY - transform.y - geometry.top - geometry.height / 2);
|
|
477
|
-
if (ratio < 1 && scale === 1 && geometry.width <= geometry.viewportWidth && geometry.height <= geometry.viewportHeight) x = y = 0;
|
|
478
|
-
return {
|
|
479
|
-
...transform,
|
|
480
|
-
x,
|
|
481
|
-
y,
|
|
482
|
-
scale
|
|
483
|
-
};
|
|
484
|
-
}
|
|
485
|
-
function imageWheelRatio(delta) {
|
|
486
|
-
const ratio = 1 + Math.min(Math.abs(delta / 100), 1) * .5;
|
|
487
|
-
return delta > 0 ? 1 / ratio : ratio;
|
|
488
|
-
}
|
|
489
|
-
function reboundImage(transform, geometry, bounds) {
|
|
490
|
-
if (transform.scale < 1) return {
|
|
491
|
-
...transform,
|
|
492
|
-
x: 0,
|
|
493
|
-
y: 0,
|
|
494
|
-
scale: 1
|
|
495
|
-
};
|
|
496
|
-
const rotated = transform.rotate % 180 !== 0;
|
|
497
|
-
const width = (rotated ? geometry.height : geometry.width) * transform.scale;
|
|
498
|
-
const height = (rotated ? geometry.width : geometry.height) * transform.scale;
|
|
499
|
-
if (width <= geometry.viewportWidth && height <= geometry.viewportHeight) return {
|
|
500
|
-
...transform,
|
|
501
|
-
x: 0,
|
|
502
|
-
y: 0
|
|
503
|
-
};
|
|
504
|
-
const fix = (position, start, size, viewport) => {
|
|
505
|
-
const offset = (size - viewport) / 2;
|
|
506
|
-
if (size > viewport) {
|
|
507
|
-
if (start > 0) return offset;
|
|
508
|
-
if (start < 0 && start + size < viewport) return -offset;
|
|
509
|
-
} else if (start < 0 || start + size > viewport) return start < 0 ? offset : -offset;
|
|
510
|
-
return position;
|
|
511
|
-
};
|
|
512
|
-
return {
|
|
513
|
-
...transform,
|
|
514
|
-
x: fix(transform.x, bounds.left, width, geometry.viewportWidth),
|
|
515
|
-
y: fix(transform.y, bounds.top, height, geometry.viewportHeight)
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
function imagePinchCenter(oldA, oldB, a, b) {
|
|
519
|
-
const distanceA = Math.hypot(a.x - oldA.x, a.y - oldA.y), distanceB = Math.hypot(b.x - oldB.x, b.y - oldB.y);
|
|
520
|
-
const ratio = distanceA + distanceB ? distanceA / (distanceA + distanceB) : 0;
|
|
521
|
-
return {
|
|
522
|
-
x: oldA.x + ratio * (oldB.x - oldA.x),
|
|
523
|
-
y: oldA.y + ratio * (oldB.y - oldA.y)
|
|
524
|
-
};
|
|
525
|
-
}
|
|
526
|
-
export { MERMAID_DEFAULT_MAX_TEXT_SIZE, createCodeFrame, createDiagramController, createJsonCompletenessScanner, createRenderQueue, ensureMermaidInitialized, extractCode, getImageGallery, getMermaidMaxTextSize, imageActionLabels, imageGroupSelector, imageIconPaths, imagePinchCenter, imageTransformStyle, imageWheelRatio, initialImageTransform, jsonLooksComplete, lockImagePreviewScroll, mermaidRenderQueue, normalizeRenderers, prettyPrintJson, projectTable, reboundImage, resetMermaidInitializationForTests, serializeTable, zoomImage };
|
|
1207
|
+
const imageActionNames = Object.freeze([
|
|
1208
|
+
"close",
|
|
1209
|
+
"prev",
|
|
1210
|
+
"next",
|
|
1211
|
+
"rotateLeft",
|
|
1212
|
+
"rotateRight",
|
|
1213
|
+
"zoomIn",
|
|
1214
|
+
"zoomOut",
|
|
1215
|
+
"flipX",
|
|
1216
|
+
"flipY"
|
|
1217
|
+
]);
|
|
1218
|
+
export { createCodeBlockSession, createCodeFrame, createCodeLanguageTracker, createDiagramController, createImagePreviewController, createJsonCompletenessScanner, defaultCodeBlockLabels, defaultDiagramLabels, defaultImageLabels, defaultTableLabels, diagramErrorText, ensureMermaidInitialized, extendsCode, extractCode, getImageGallery, getMermaidMaxTextSize, imageActionNames, imageIconPaths, imagePinchCenter, imageTransformStyle, imageWheelRatio, initialImageTransform, jsonLooksComplete, lockImagePreviewScroll, mermaidRenderQueue, nextCodeFrame, normalizeRenderers, prettyPrintJson, projectTable, reboundImage, resolveLabels, serializeTable, zoomImage };
|
|
527
1219
|
|
|
528
1220
|
//# sourceMappingURL=index.js.map
|