@barzhsieh/nuxt-content-mermaid 2.1.2 → 2.2.0

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 (87) hide show
  1. package/README.md +162 -1
  2. package/README.zh-TW.md +166 -2
  3. package/dist/module.d.mts +83 -1
  4. package/dist/module.json +1 -1
  5. package/dist/module.mjs +126 -9
  6. package/dist/runtime/components/Mermaid.d.vue.ts +6 -4
  7. package/dist/runtime/components/Mermaid.vue +492 -36
  8. package/dist/runtime/components/Mermaid.vue.d.ts +6 -4
  9. package/dist/runtime/components/MermaidExpandOverlay.d.vue.ts +25 -0
  10. package/dist/runtime/components/MermaidExpandOverlay.vue +140 -0
  11. package/dist/runtime/components/MermaidExpandOverlay.vue.d.ts +25 -0
  12. package/dist/runtime/components/MermaidZoomToolbar.d.vue.ts +23 -0
  13. package/dist/runtime/components/MermaidZoomToolbar.vue +66 -0
  14. package/dist/runtime/components/MermaidZoomToolbar.vue.d.ts +23 -0
  15. package/dist/runtime/components/icons/IconClipboard.d.vue.ts +8 -0
  16. package/dist/runtime/components/icons/IconClipboard.vue +32 -0
  17. package/dist/runtime/components/icons/IconClipboard.vue.d.ts +8 -0
  18. package/dist/runtime/components/icons/IconClipboardHover.d.vue.ts +8 -0
  19. package/dist/runtime/components/icons/IconClipboardHover.vue +33 -0
  20. package/dist/runtime/components/icons/IconClipboardHover.vue.d.ts +8 -0
  21. package/dist/runtime/components/icons/IconClipboardSuccess.d.vue.ts +8 -0
  22. package/dist/runtime/components/icons/IconClipboardSuccess.vue +33 -0
  23. package/dist/runtime/components/icons/IconClipboardSuccess.vue.d.ts +8 -0
  24. package/dist/runtime/components/icons/IconCollapse.d.vue.ts +8 -0
  25. package/dist/runtime/components/icons/IconCollapse.vue +34 -0
  26. package/dist/runtime/components/icons/IconCollapse.vue.d.ts +8 -0
  27. package/dist/runtime/components/icons/IconExpand.d.vue.ts +8 -0
  28. package/dist/runtime/components/icons/IconExpand.vue +34 -0
  29. package/dist/runtime/components/icons/IconExpand.vue.d.ts +8 -0
  30. package/dist/runtime/components/icons/IconMinus.d.vue.ts +8 -0
  31. package/dist/runtime/components/icons/IconMinus.vue +46 -0
  32. package/dist/runtime/components/icons/IconMinus.vue.d.ts +8 -0
  33. package/dist/runtime/components/icons/IconPlus.d.vue.ts +8 -0
  34. package/dist/runtime/components/icons/IconPlus.vue +57 -0
  35. package/dist/runtime/components/icons/IconPlus.vue.d.ts +8 -0
  36. package/dist/runtime/components/icons/iconFullScreen.d.vue.ts +8 -0
  37. package/dist/runtime/components/icons/iconFullScreen.vue +26 -0
  38. package/dist/runtime/components/icons/iconFullScreen.vue.d.ts +8 -0
  39. package/dist/runtime/components/icons/iconFullScreenExit.d.vue.ts +8 -0
  40. package/dist/runtime/components/icons/iconFullScreenExit.vue +26 -0
  41. package/dist/runtime/components/icons/iconFullScreenExit.vue.d.ts +8 -0
  42. package/dist/runtime/composables/_configurable.d.ts +27 -0
  43. package/dist/runtime/composables/_configurable.js +5 -0
  44. package/dist/runtime/composables/shared/index.d.ts +5 -0
  45. package/dist/runtime/composables/shared/index.js +5 -0
  46. package/dist/runtime/composables/shared/tryOnMounted.d.ts +10 -0
  47. package/dist/runtime/composables/shared/tryOnMounted.js +11 -0
  48. package/dist/runtime/composables/shared/tryOnScopeDispose.d.ts +7 -0
  49. package/dist/runtime/composables/shared/tryOnScopeDispose.js +8 -0
  50. package/dist/runtime/composables/shared/watchImmediate.d.ts +5 -0
  51. package/dist/runtime/composables/shared/watchImmediate.js +11 -0
  52. package/dist/runtime/composables/unrefElement.d.ts +12 -0
  53. package/dist/runtime/composables/unrefElement.js +5 -0
  54. package/dist/runtime/composables/useEventListener.d.ts +73 -0
  55. package/dist/runtime/composables/useEventListener.js +40 -0
  56. package/dist/runtime/composables/useFullscreen.d.ts +25 -0
  57. package/dist/runtime/composables/useFullscreen.js +122 -0
  58. package/dist/runtime/composables/useMermaidCursors.d.ts +12 -0
  59. package/dist/runtime/composables/useMermaidCursors.js +41 -0
  60. package/dist/runtime/composables/useMermaidExpand.d.ts +45 -0
  61. package/dist/runtime/composables/useMermaidExpand.js +480 -0
  62. package/dist/runtime/composables/useMermaidZoom.d.ts +37 -0
  63. package/dist/runtime/composables/useMermaidZoom.js +261 -0
  64. package/dist/runtime/composables/useMounted.d.ts +8 -0
  65. package/dist/runtime/composables/useMounted.js +16 -0
  66. package/dist/runtime/composables/useSupported.d.ts +2 -0
  67. package/dist/runtime/composables/useSupported.js +10 -0
  68. package/dist/runtime/constants.d.ts +4 -0
  69. package/dist/runtime/constants.js +24 -0
  70. package/dist/runtime/mermaid-config.d.ts +1 -1
  71. package/dist/runtime/plugins/mermaid.client.d.ts +2 -2
  72. package/dist/runtime/styles.css +1 -0
  73. package/dist/runtime/types/expand.d.ts +48 -0
  74. package/dist/runtime/types/expand.js +0 -0
  75. package/dist/runtime/types/utils.d.ts +115 -0
  76. package/dist/runtime/types/utils.js +0 -0
  77. package/dist/runtime/utils/index.d.ts +52 -0
  78. package/dist/runtime/utils/index.js +113 -0
  79. package/dist/runtime/utils/is.d.ts +15 -0
  80. package/dist/runtime/utils/is.js +31 -0
  81. package/dist/runtime/utils/mermaid-transform.d.ts +18 -0
  82. package/dist/runtime/utils/mermaid-transform.js +345 -0
  83. package/dist/runtime/utils/vue.d.ts +2 -0
  84. package/dist/runtime/utils/vue.js +4 -0
  85. package/package.json +4 -2
  86. package/dist/runtime/utils.d.ts +0 -1
  87. package/dist/runtime/utils.js +0 -30
@@ -0,0 +1,45 @@
1
+ import type { CSSProperties, ComponentPublicInstance, Ref } from 'vue';
2
+ import type { ExpandInvokeCloseOn, ExpandInvokeOpenOn } from '../types/expand.js';
3
+ interface UseMermaidExpandOptions {
4
+ getExpandTarget: () => SVGElement | null;
5
+ expandMargin?: number;
6
+ isBlocked?: Ref<boolean>;
7
+ invokeOpenOn?: ExpandInvokeOpenOn;
8
+ invokeCloseOn?: ExpandInvokeCloseOn;
9
+ }
10
+ export declare function useMermaidExpand(options: UseMermaidExpandOptions): {
11
+ setExpandTargetWrap: (el: Element | ComponentPublicInstance | null) => void;
12
+ expandTargetStyle: import("vue").ComputedRef<CSSProperties>;
13
+ isExpandActive: import("vue").ComputedRef<boolean>;
14
+ isVisible: import("vue").ComputedRef<boolean>;
15
+ openExpand: (_event?: Event) => void;
16
+ closeExpand: (_event?: Event) => void;
17
+ toggleExpand: (event?: Event) => void;
18
+ handleExpandTransitionEnd: (event: TransitionEvent) => void;
19
+ handleMermaidClick: (event: MouseEvent) => void;
20
+ resetExpand: () => void;
21
+ zoom: {
22
+ scale: Ref<number, number>;
23
+ translateX: Ref<number, number>;
24
+ translateY: Ref<number, number>;
25
+ transformStyle: import("vue").ComputedRef<{
26
+ transform: string;
27
+ }>;
28
+ isDragging: Ref<boolean, boolean>;
29
+ isSpacePressed: Ref<boolean, boolean>;
30
+ wasLastInteractionDrag: Ref<boolean, boolean>;
31
+ cursor: import("vue").ComputedRef<"grabbing" | "grab" | "auto">;
32
+ init: (metrics: import("./useMermaidZoom.js").ZoomMetrics) => void;
33
+ reset: () => void;
34
+ zoomIn: () => void;
35
+ zoomOut: () => void;
36
+ setMetrics: (metrics: import("./useMermaidZoom.js").ZoomMetrics) => void;
37
+ handleWheel: (event: WheelEvent) => boolean;
38
+ handleDragStart: (event: MouseEvent | TouchEvent) => void;
39
+ handleDragMove: (event: MouseEvent | TouchEvent) => void;
40
+ handleDragEnd: () => void;
41
+ isPointerDown: Ref<boolean, boolean>;
42
+ };
43
+ showZoomHint: Ref<boolean, boolean>;
44
+ };
45
+ export {};
@@ -0,0 +1,480 @@
1
+ import { computed, nextTick, ref } from "vue";
2
+ import { useMermaidZoom } from "./useMermaidZoom.js";
3
+ import { useEventListener } from "./useEventListener.js";
4
+ import { tryOnScopeDispose } from "./shared/tryOnScopeDispose.js";
5
+ const swipeToCloseThreshold = 10;
6
+ export function useMermaidExpand(options) {
7
+ const isClient = typeof import.meta.client === "boolean" ? import.meta.client : typeof window !== "undefined" && typeof document !== "undefined";
8
+ const expandTargetWrap = ref(null);
9
+ const setExpandTargetWrap = (el) => {
10
+ if (el && "nodeType" in el) {
11
+ expandTargetWrap.value = el;
12
+ return;
13
+ }
14
+ expandTargetWrap.value = null;
15
+ };
16
+ const expandState = ref("idle");
17
+ const expandMetrics = ref(null);
18
+ const isExpanded = ref(false);
19
+ const showZoomHint = ref(false);
20
+ let hasShownZoomHint = false;
21
+ let hintTimeout;
22
+ const shouldRefreshExpand = ref(false);
23
+ const isExpandActive = computed(() => expandState.value !== "idle");
24
+ const zoom = useMermaidZoom({
25
+ active: isExpandActive,
26
+ minScale: 0.1,
27
+ maxScale: 10
28
+ });
29
+ const isVisible = computed(() => expandState.value === "open");
30
+ const allowTargetClick = options.invokeOpenOn?.diagramClick !== false;
31
+ const allowCloseByEsc = options.invokeCloseOn?.esc !== false;
32
+ const allowCloseByWheel = options.invokeCloseOn?.wheel !== false;
33
+ const allowCloseBySwipe = options.invokeCloseOn?.swipe !== false;
34
+ const expandTargetStyle = computed(() => {
35
+ const metrics = expandMetrics.value;
36
+ if (!metrics) return {};
37
+ const { transform } = zoom.transformStyle.value;
38
+ return {
39
+ top: `${metrics.top}px`,
40
+ left: `${metrics.left}px`,
41
+ width: `${metrics.width}px`,
42
+ height: `${metrics.height}px`,
43
+ transform: isExpanded.value ? transform : "translate(0px, 0px) scale(1)",
44
+ transitionDuration: shouldRefreshExpand.value || zoom.isPointerDown.value ? "0ms" : void 0
45
+ };
46
+ });
47
+ let expandTransitionTimeout;
48
+ let expandResizeTimeout;
49
+ const resizeDoubleRaf = {
50
+ raf1: void 0,
51
+ raf2: void 0,
52
+ run(fn) {
53
+ this.cancel();
54
+ this.raf1 = requestAnimationFrame(() => {
55
+ fn();
56
+ this.raf2 = requestAnimationFrame(() => {
57
+ fn();
58
+ this.raf2 = void 0;
59
+ });
60
+ this.raf1 = void 0;
61
+ });
62
+ },
63
+ cancel() {
64
+ if (this.raf1 != null) cancelAnimationFrame(this.raf1);
65
+ if (this.raf2 != null) cancelAnimationFrame(this.raf2);
66
+ this.raf1 = void 0;
67
+ this.raf2 = void 0;
68
+ }
69
+ };
70
+ let expandRefreshRaf;
71
+ const resizeRefreshDelay = 180;
72
+ const scrollState = {
73
+ bodyOverflow: "",
74
+ bodyWidth: "",
75
+ htmlOverflow: "",
76
+ htmlWidth: "",
77
+ lockedWidth: false
78
+ };
79
+ const touchState = {
80
+ isScaling: false
81
+ };
82
+ let expandInstanceId = 0;
83
+ function resolveExpandMargin() {
84
+ const margin = options.expandMargin;
85
+ if (typeof margin !== "number" || Number.isNaN(margin)) return 0;
86
+ return Math.max(0, margin);
87
+ }
88
+ function getLayoutViewportSize() {
89
+ const viewport = window.visualViewport;
90
+ const scale = viewport?.scale ?? 1;
91
+ return {
92
+ width: (viewport?.width ?? window.innerWidth) * scale,
93
+ height: (viewport?.height ?? window.innerHeight) * scale
94
+ };
95
+ }
96
+ function getLockedViewportWidth() {
97
+ const width = document.documentElement.clientWidth || window.innerWidth;
98
+ return Math.max(1, Math.round(width));
99
+ }
100
+ function shouldLockWidth() {
101
+ return window.innerWidth - document.documentElement.clientWidth > 0;
102
+ }
103
+ function updateLockedWidth() {
104
+ if (!scrollState.lockedWidth || document.body.style.overflow !== "hidden") return;
105
+ document.documentElement.style.width = "";
106
+ document.body.style.width = "";
107
+ void document.body.offsetHeight;
108
+ const clientWidth = getLockedViewportWidth();
109
+ document.documentElement.style.width = `${clientWidth}px`;
110
+ document.body.style.width = `${clientWidth}px`;
111
+ }
112
+ function clearResizeTimers() {
113
+ clearTimeout(expandResizeTimeout);
114
+ resizeDoubleRaf.cancel();
115
+ expandResizeTimeout = void 0;
116
+ }
117
+ function clearRefreshRaf() {
118
+ if (expandRefreshRaf != null) cancelAnimationFrame(expandRefreshRaf);
119
+ expandRefreshRaf = void 0;
120
+ }
121
+ function calculateExpandMetrics(target) {
122
+ const rect = target.getBoundingClientRect();
123
+ if (!rect.width || !rect.height) return null;
124
+ const margin = resolveExpandMargin();
125
+ const { width, height } = getLayoutViewportSize();
126
+ const viewportWidth = Math.max(1, width - margin * 2);
127
+ const viewportHeight = Math.max(1, height - margin * 2);
128
+ const scaleX = viewportWidth / rect.width;
129
+ const scaleY = viewportHeight / rect.height;
130
+ const scale = Number.isFinite(scaleX) && Number.isFinite(scaleY) ? Math.min(scaleX, scaleY) : 1;
131
+ const safeScale = scale > 0 ? scale : 1;
132
+ return {
133
+ top: rect.top,
134
+ left: rect.left,
135
+ width: rect.width,
136
+ height: rect.height,
137
+ translateX: width / 2 - (rect.left + rect.width * safeScale / 2),
138
+ translateY: height / 2 - (rect.top + rect.height * safeScale / 2),
139
+ scale: safeScale
140
+ };
141
+ }
142
+ function adjustSvgIDs(svgEl, suffix) {
143
+ const attrs = [
144
+ "clip-path",
145
+ "fill",
146
+ "mask",
147
+ "marker-start",
148
+ "marker-mid",
149
+ "marker-end"
150
+ ];
151
+ const idMap = /* @__PURE__ */ new Map();
152
+ if (svgEl.hasAttribute("id")) {
153
+ const oldId = svgEl.id;
154
+ const newId = oldId + suffix;
155
+ idMap.set(oldId, newId);
156
+ svgEl.id = newId;
157
+ }
158
+ svgEl.querySelectorAll("[id]").forEach((el) => {
159
+ const oldId = el.id;
160
+ const newId = oldId + suffix;
161
+ idMap.set(oldId, newId);
162
+ el.id = newId;
163
+ });
164
+ idMap.forEach((newId, oldId) => {
165
+ const urlOldID = `url(#${oldId})`;
166
+ const urlNewID = `url(#${newId})`;
167
+ const attrsQuery = attrs.map((attr) => `[${attr}="${urlOldID}"]`).join(", ");
168
+ svgEl.querySelectorAll(attrsQuery).forEach((usedEl) => {
169
+ attrs.forEach((attr) => {
170
+ if (usedEl.getAttribute(attr) === urlOldID) {
171
+ usedEl.setAttribute(attr, urlNewID);
172
+ }
173
+ });
174
+ });
175
+ });
176
+ svgEl.querySelectorAll("style").forEach((styleEl) => {
177
+ if (!styleEl.textContent) return;
178
+ idMap.forEach((newId, oldId) => {
179
+ styleEl.textContent = styleEl.textContent.replaceAll(`#${oldId}`, `#${newId}`);
180
+ });
181
+ });
182
+ }
183
+ function mountExpandSvg(svg) {
184
+ const wrap = expandTargetWrap.value;
185
+ if (!wrap) return false;
186
+ wrap.textContent = "";
187
+ const clone = svg.cloneNode(true);
188
+ const suffix = `-ncm-${expandInstanceId++}`;
189
+ adjustSvgIDs(clone, suffix);
190
+ clone.removeAttribute("width");
191
+ clone.removeAttribute("height");
192
+ clone.style.width = "100%";
193
+ clone.style.height = "100%";
194
+ wrap.appendChild(clone);
195
+ return true;
196
+ }
197
+ function clearExpandSvg() {
198
+ if (!expandTargetWrap.value) return;
199
+ expandTargetWrap.value.textContent = "";
200
+ }
201
+ function resetExpand() {
202
+ if (!isClient) return;
203
+ clearTimeout(expandTransitionTimeout);
204
+ clearTimeout(hintTimeout);
205
+ clearResizeTimers();
206
+ clearRefreshRaf();
207
+ clearExpandSvg();
208
+ expandState.value = "idle";
209
+ isExpanded.value = false;
210
+ shouldRefreshExpand.value = false;
211
+ showZoomHint.value = false;
212
+ expandMetrics.value = null;
213
+ enableBodyScroll();
214
+ }
215
+ function openExpand(_event) {
216
+ if (!isClient || isExpandActive.value) return;
217
+ if (options.isBlocked?.value) return;
218
+ const svg = options.getExpandTarget();
219
+ if (!svg) return;
220
+ const metrics = calculateExpandMetrics(svg);
221
+ if (!metrics) return;
222
+ expandMetrics.value = metrics;
223
+ hasShownZoomHint = false;
224
+ zoom.init({
225
+ scale: metrics.scale,
226
+ translateX: metrics.translateX,
227
+ translateY: metrics.translateY,
228
+ top: metrics.top,
229
+ left: metrics.left
230
+ });
231
+ expandState.value = "opening";
232
+ isExpanded.value = false;
233
+ disableBodyScroll();
234
+ nextTick(() => {
235
+ if (expandState.value !== "opening") return;
236
+ if (!mountExpandSvg(svg)) {
237
+ resetExpand();
238
+ return;
239
+ }
240
+ requestAnimationFrame(() => {
241
+ if (expandState.value !== "opening") return;
242
+ isExpanded.value = true;
243
+ expandState.value = "open";
244
+ });
245
+ });
246
+ }
247
+ function closeExpand(_event) {
248
+ if (!isClient || !isExpandActive.value) return;
249
+ if (expandState.value === "opening" && !expandTargetWrap.value) {
250
+ resetExpand();
251
+ return;
252
+ }
253
+ expandState.value = "closing";
254
+ isExpanded.value = false;
255
+ ensureExpandTransitionEnd();
256
+ }
257
+ function toggleExpand(event) {
258
+ if (isExpandActive.value) {
259
+ closeExpand(event);
260
+ } else {
261
+ openExpand(event);
262
+ }
263
+ }
264
+ function handleExpandTransitionEnd(event) {
265
+ if (event.propertyName !== "transform") return;
266
+ if (expandState.value === "closing") {
267
+ resetExpand();
268
+ }
269
+ }
270
+ function ensureExpandTransitionEnd() {
271
+ if (!expandTargetWrap.value) return;
272
+ const duration = window.getComputedStyle(expandTargetWrap.value).transitionDuration;
273
+ const durationMs = Number.parseFloat(duration) * (duration.endsWith("ms") ? 1 : 1e3);
274
+ if (!durationMs) return;
275
+ clearTimeout(expandTransitionTimeout);
276
+ expandTransitionTimeout = setTimeout(() => {
277
+ if (expandState.value === "closing") resetExpand();
278
+ }, durationMs + 50);
279
+ }
280
+ function handleExpandKeyDown(event) {
281
+ if (!allowCloseByEsc && event.key === "Escape") return;
282
+ if (event.key === "Escape") {
283
+ event.preventDefault();
284
+ event.stopPropagation();
285
+ closeExpand(event);
286
+ return;
287
+ }
288
+ const browserZoomKeys = /* @__PURE__ */ new Set(["+", "=", "-", "_"]);
289
+ if (event.ctrlKey || event.metaKey) {
290
+ if (browserZoomKeys.has(event.key))
291
+ event.preventDefault();
292
+ return;
293
+ }
294
+ if (expandState.value !== "open") return;
295
+ const moveStep = 20 / zoom.scale.value;
296
+ switch (event.key) {
297
+ case "+":
298
+ case "=":
299
+ zoom.zoomIn();
300
+ break;
301
+ case "-":
302
+ case "_":
303
+ zoom.zoomOut();
304
+ break;
305
+ case "0":
306
+ zoom.reset();
307
+ break;
308
+ case "ArrowUp":
309
+ zoom.translateY.value += moveStep;
310
+ break;
311
+ case "ArrowDown":
312
+ zoom.translateY.value -= moveStep;
313
+ break;
314
+ case "ArrowLeft":
315
+ zoom.translateX.value += moveStep;
316
+ break;
317
+ case "ArrowRight":
318
+ zoom.translateX.value -= moveStep;
319
+ break;
320
+ }
321
+ }
322
+ function handleExpandWheel(event) {
323
+ const isInside = expandTargetWrap.value && expandTargetWrap.value.contains(event.target);
324
+ if (isInside) {
325
+ const handled = zoom.handleWheel(event);
326
+ if (handled) return;
327
+ event.preventDefault();
328
+ event.stopPropagation();
329
+ if (!hasShownZoomHint) {
330
+ hasShownZoomHint = true;
331
+ showZoomHint.value = true;
332
+ hintTimeout = setTimeout(() => {
333
+ showZoomHint.value = false;
334
+ }, 1500);
335
+ }
336
+ return;
337
+ }
338
+ if (!allowCloseByWheel) return;
339
+ if (event.ctrlKey || event.metaKey) return;
340
+ event.preventDefault();
341
+ event.stopPropagation();
342
+ queueMicrotask(() => closeExpand(event));
343
+ }
344
+ function handleExpandTouchStart(event) {
345
+ if (zoom.isDragging.value) return;
346
+ if (!allowCloseBySwipe) return;
347
+ if (event.touches.length > 1) {
348
+ touchState.isScaling = true;
349
+ return;
350
+ }
351
+ if (event.changedTouches.length === 1 && event.changedTouches[0]) {
352
+ touchState.start = event.changedTouches[0].screenY;
353
+ }
354
+ }
355
+ function handleExpandTouchMove(event) {
356
+ if (zoom.isDragging.value || touchState.isScaling) return;
357
+ if (!allowCloseBySwipe) return;
358
+ const browserScale = window.visualViewport?.scale ?? 1;
359
+ if (!touchState.isScaling && browserScale <= 1 && touchState.start != null && event.changedTouches[0]) {
360
+ touchState.end = event.changedTouches[0].screenY;
361
+ const max = Math.max(touchState.start, touchState.end);
362
+ const min = Math.min(touchState.start, touchState.end);
363
+ const delta = Math.abs(max - min);
364
+ if (delta > swipeToCloseThreshold) {
365
+ touchState.start = void 0;
366
+ touchState.end = void 0;
367
+ closeExpand(event);
368
+ }
369
+ }
370
+ }
371
+ function handleExpandTouchEnd() {
372
+ if (!allowCloseBySwipe) return;
373
+ touchState.isScaling = false;
374
+ touchState.start = void 0;
375
+ touchState.end = void 0;
376
+ }
377
+ function handleExpandTouchCancel() {
378
+ if (!allowCloseBySwipe) return;
379
+ touchState.isScaling = false;
380
+ touchState.start = void 0;
381
+ touchState.end = void 0;
382
+ }
383
+ function handleExpandResize() {
384
+ if (!isExpandActive.value) return;
385
+ scheduleExpandRefresh();
386
+ }
387
+ function refreshExpandMetrics() {
388
+ if (!isExpandActive.value) return;
389
+ updateLockedWidth();
390
+ const svg = options.getExpandTarget();
391
+ if (!svg) return;
392
+ const metrics = calculateExpandMetrics(svg);
393
+ if (!metrics) return;
394
+ expandMetrics.value = metrics;
395
+ zoom.init({
396
+ scale: metrics.scale,
397
+ translateX: metrics.translateX,
398
+ translateY: metrics.translateY,
399
+ top: metrics.top,
400
+ left: metrics.left
401
+ });
402
+ shouldRefreshExpand.value = true;
403
+ clearRefreshRaf();
404
+ expandRefreshRaf = requestAnimationFrame(() => {
405
+ shouldRefreshExpand.value = false;
406
+ expandRefreshRaf = void 0;
407
+ });
408
+ }
409
+ function scheduleExpandRefresh() {
410
+ clearResizeTimers();
411
+ resizeDoubleRaf.run(refreshExpandMetrics);
412
+ expandResizeTimeout = setTimeout(() => {
413
+ refreshExpandMetrics();
414
+ }, resizeRefreshDelay);
415
+ }
416
+ if (isClient) {
417
+ const activeWindow = computed(() => isExpandActive.value ? window : null);
418
+ const activeDocument = computed(() => isExpandActive.value ? document : null);
419
+ const activeVisualViewport = computed(() => isExpandActive.value ? window.visualViewport : null);
420
+ useEventListener(activeWindow, "resize", handleExpandResize, { passive: true });
421
+ useEventListener(activeWindow, "orientationchange", handleExpandResize, { passive: true });
422
+ useEventListener(activeVisualViewport, "resize", handleExpandResize, { passive: true });
423
+ useEventListener(activeWindow, "wheel", handleExpandWheel, { passive: false });
424
+ useEventListener(activeWindow, "touchstart", handleExpandTouchStart, { passive: true });
425
+ useEventListener(activeWindow, "touchmove", handleExpandTouchMove, { passive: true });
426
+ useEventListener(activeWindow, "touchend", handleExpandTouchEnd, { passive: true });
427
+ useEventListener(activeWindow, "touchcancel", handleExpandTouchCancel, { passive: true });
428
+ useEventListener(activeDocument, "keydown", handleExpandKeyDown, true);
429
+ }
430
+ function disableBodyScroll() {
431
+ scrollState.bodyOverflow = document.body.style.overflow;
432
+ scrollState.bodyWidth = document.body.style.width;
433
+ scrollState.htmlOverflow = document.documentElement.style.overflow;
434
+ scrollState.htmlWidth = document.documentElement.style.width;
435
+ scrollState.lockedWidth = shouldLockWidth();
436
+ document.documentElement.style.overflow = "hidden";
437
+ document.body.style.overflow = "hidden";
438
+ if (scrollState.lockedWidth) {
439
+ const clientWidth = getLockedViewportWidth();
440
+ document.documentElement.style.width = `${clientWidth}px`;
441
+ document.body.style.width = `${clientWidth}px`;
442
+ }
443
+ }
444
+ function enableBodyScroll() {
445
+ document.documentElement.style.width = scrollState.htmlWidth;
446
+ document.documentElement.style.overflow = scrollState.htmlOverflow;
447
+ scrollState.htmlOverflow = "";
448
+ scrollState.htmlWidth = "";
449
+ document.body.style.width = scrollState.bodyWidth;
450
+ document.body.style.overflow = scrollState.bodyOverflow;
451
+ scrollState.bodyOverflow = "";
452
+ scrollState.bodyWidth = "";
453
+ scrollState.lockedWidth = false;
454
+ }
455
+ function handleMermaidClick(event) {
456
+ if (!allowTargetClick) return;
457
+ if (isExpandActive.value || options.isBlocked?.value) return;
458
+ const svg = options.getExpandTarget();
459
+ if (!svg) return;
460
+ if (!svg.contains(event.target)) return;
461
+ openExpand(event);
462
+ }
463
+ tryOnScopeDispose(() => {
464
+ if (isClient) resetExpand();
465
+ });
466
+ return {
467
+ setExpandTargetWrap,
468
+ expandTargetStyle,
469
+ isExpandActive,
470
+ isVisible,
471
+ openExpand,
472
+ closeExpand,
473
+ toggleExpand,
474
+ handleExpandTransitionEnd,
475
+ handleMermaidClick,
476
+ resetExpand,
477
+ zoom,
478
+ showZoomHint
479
+ };
480
+ }
@@ -0,0 +1,37 @@
1
+ import { type Ref } from 'vue';
2
+ export interface ZoomMetrics {
3
+ scale: number;
4
+ translateX: number;
5
+ translateY: number;
6
+ top?: number;
7
+ left?: number;
8
+ }
9
+ export interface UseMermaidZoomOptions {
10
+ active?: Ref<boolean>;
11
+ minScale?: number;
12
+ maxScale?: number;
13
+ zoomSpeed?: number;
14
+ }
15
+ export declare function useMermaidZoom(options?: UseMermaidZoomOptions): {
16
+ scale: Ref<number, number>;
17
+ translateX: Ref<number, number>;
18
+ translateY: Ref<number, number>;
19
+ transformStyle: import("vue").ComputedRef<{
20
+ transform: string;
21
+ }>;
22
+ isDragging: Ref<boolean, boolean>;
23
+ isSpacePressed: Ref<boolean, boolean>;
24
+ wasLastInteractionDrag: Ref<boolean, boolean>;
25
+ cursor: import("vue").ComputedRef<"grabbing" | "grab" | "auto">;
26
+ init: (metrics: ZoomMetrics) => void;
27
+ reset: () => void;
28
+ zoomIn: () => void;
29
+ zoomOut: () => void;
30
+ setMetrics: (metrics: ZoomMetrics) => void;
31
+ handleWheel: (event: WheelEvent) => boolean;
32
+ handleDragStart: (event: MouseEvent | TouchEvent) => void;
33
+ handleDragMove: (event: MouseEvent | TouchEvent) => void;
34
+ handleDragEnd: () => void;
35
+ isPointerDown: Ref<boolean, boolean>;
36
+ };
37
+ export type MermaidZoomReturn = ReturnType<typeof useMermaidZoom>;