@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.
- package/README.md +162 -1
- package/README.zh-TW.md +166 -2
- package/dist/module.d.mts +83 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +126 -9
- package/dist/runtime/components/Mermaid.d.vue.ts +6 -4
- package/dist/runtime/components/Mermaid.vue +492 -36
- package/dist/runtime/components/Mermaid.vue.d.ts +6 -4
- package/dist/runtime/components/MermaidExpandOverlay.d.vue.ts +25 -0
- package/dist/runtime/components/MermaidExpandOverlay.vue +140 -0
- package/dist/runtime/components/MermaidExpandOverlay.vue.d.ts +25 -0
- package/dist/runtime/components/MermaidZoomToolbar.d.vue.ts +23 -0
- package/dist/runtime/components/MermaidZoomToolbar.vue +66 -0
- package/dist/runtime/components/MermaidZoomToolbar.vue.d.ts +23 -0
- package/dist/runtime/components/icons/IconClipboard.d.vue.ts +8 -0
- package/dist/runtime/components/icons/IconClipboard.vue +32 -0
- package/dist/runtime/components/icons/IconClipboard.vue.d.ts +8 -0
- package/dist/runtime/components/icons/IconClipboardHover.d.vue.ts +8 -0
- package/dist/runtime/components/icons/IconClipboardHover.vue +33 -0
- package/dist/runtime/components/icons/IconClipboardHover.vue.d.ts +8 -0
- package/dist/runtime/components/icons/IconClipboardSuccess.d.vue.ts +8 -0
- package/dist/runtime/components/icons/IconClipboardSuccess.vue +33 -0
- package/dist/runtime/components/icons/IconClipboardSuccess.vue.d.ts +8 -0
- package/dist/runtime/components/icons/IconCollapse.d.vue.ts +8 -0
- package/dist/runtime/components/icons/IconCollapse.vue +34 -0
- package/dist/runtime/components/icons/IconCollapse.vue.d.ts +8 -0
- package/dist/runtime/components/icons/IconExpand.d.vue.ts +8 -0
- package/dist/runtime/components/icons/IconExpand.vue +34 -0
- package/dist/runtime/components/icons/IconExpand.vue.d.ts +8 -0
- package/dist/runtime/components/icons/IconMinus.d.vue.ts +8 -0
- package/dist/runtime/components/icons/IconMinus.vue +46 -0
- package/dist/runtime/components/icons/IconMinus.vue.d.ts +8 -0
- package/dist/runtime/components/icons/IconPlus.d.vue.ts +8 -0
- package/dist/runtime/components/icons/IconPlus.vue +57 -0
- package/dist/runtime/components/icons/IconPlus.vue.d.ts +8 -0
- package/dist/runtime/components/icons/iconFullScreen.d.vue.ts +8 -0
- package/dist/runtime/components/icons/iconFullScreen.vue +26 -0
- package/dist/runtime/components/icons/iconFullScreen.vue.d.ts +8 -0
- package/dist/runtime/components/icons/iconFullScreenExit.d.vue.ts +8 -0
- package/dist/runtime/components/icons/iconFullScreenExit.vue +26 -0
- package/dist/runtime/components/icons/iconFullScreenExit.vue.d.ts +8 -0
- package/dist/runtime/composables/_configurable.d.ts +27 -0
- package/dist/runtime/composables/_configurable.js +5 -0
- package/dist/runtime/composables/shared/index.d.ts +5 -0
- package/dist/runtime/composables/shared/index.js +5 -0
- package/dist/runtime/composables/shared/tryOnMounted.d.ts +10 -0
- package/dist/runtime/composables/shared/tryOnMounted.js +11 -0
- package/dist/runtime/composables/shared/tryOnScopeDispose.d.ts +7 -0
- package/dist/runtime/composables/shared/tryOnScopeDispose.js +8 -0
- package/dist/runtime/composables/shared/watchImmediate.d.ts +5 -0
- package/dist/runtime/composables/shared/watchImmediate.js +11 -0
- package/dist/runtime/composables/unrefElement.d.ts +12 -0
- package/dist/runtime/composables/unrefElement.js +5 -0
- package/dist/runtime/composables/useEventListener.d.ts +73 -0
- package/dist/runtime/composables/useEventListener.js +40 -0
- package/dist/runtime/composables/useFullscreen.d.ts +25 -0
- package/dist/runtime/composables/useFullscreen.js +122 -0
- package/dist/runtime/composables/useMermaidCursors.d.ts +12 -0
- package/dist/runtime/composables/useMermaidCursors.js +41 -0
- package/dist/runtime/composables/useMermaidExpand.d.ts +45 -0
- package/dist/runtime/composables/useMermaidExpand.js +480 -0
- package/dist/runtime/composables/useMermaidZoom.d.ts +37 -0
- package/dist/runtime/composables/useMermaidZoom.js +261 -0
- package/dist/runtime/composables/useMounted.d.ts +8 -0
- package/dist/runtime/composables/useMounted.js +16 -0
- package/dist/runtime/composables/useSupported.d.ts +2 -0
- package/dist/runtime/composables/useSupported.js +10 -0
- package/dist/runtime/constants.d.ts +4 -0
- package/dist/runtime/constants.js +24 -0
- package/dist/runtime/mermaid-config.d.ts +1 -1
- package/dist/runtime/plugins/mermaid.client.d.ts +2 -2
- package/dist/runtime/styles.css +1 -0
- package/dist/runtime/types/expand.d.ts +48 -0
- package/dist/runtime/types/expand.js +0 -0
- package/dist/runtime/types/utils.d.ts +115 -0
- package/dist/runtime/types/utils.js +0 -0
- package/dist/runtime/utils/index.d.ts +52 -0
- package/dist/runtime/utils/index.js +113 -0
- package/dist/runtime/utils/is.d.ts +15 -0
- package/dist/runtime/utils/is.js +31 -0
- package/dist/runtime/utils/mermaid-transform.d.ts +18 -0
- package/dist/runtime/utils/mermaid-transform.js +345 -0
- package/dist/runtime/utils/vue.d.ts +2 -0
- package/dist/runtime/utils/vue.js +4 -0
- package/package.json +4 -2
- package/dist/runtime/utils.d.ts +0 -1
- package/dist/runtime/utils.js +0 -30
|
@@ -10,12 +10,30 @@ import {
|
|
|
10
10
|
shallowRef,
|
|
11
11
|
useTemplateRef
|
|
12
12
|
} from "vue";
|
|
13
|
+
import { defu } from "defu";
|
|
13
14
|
import { mergeMermaidConfig, resolveMermaidTheme } from "../mermaid-config";
|
|
14
|
-
import { enqueueRender } from "../utils";
|
|
15
|
+
import { enqueueRender, parseSizeToPx, isRecord } from "../utils";
|
|
15
16
|
import { useMermaidTheme } from "../composables/useMermaidTheme";
|
|
17
|
+
import { useMermaidExpand } from "../composables/useMermaidExpand";
|
|
18
|
+
import { useMermaidCursors } from "../composables/useMermaidCursors";
|
|
19
|
+
import { useFullscreen } from "../composables/useFullscreen";
|
|
20
|
+
import { useMermaidZoom } from "../composables/useMermaidZoom";
|
|
21
|
+
import { useEventListener } from "../composables/useEventListener";
|
|
22
|
+
import { DEFAULT_TOOLBAR_OPTIONS, DEFAULT_EXPAND_OPTIONS } from "../constants";
|
|
16
23
|
import Spinner from "./Spinner.vue";
|
|
24
|
+
import IconClipboard from "./icons/IconClipboard.vue";
|
|
25
|
+
import IconClipboardHover from "./icons/IconClipboardHover.vue";
|
|
26
|
+
import IconClipboardSuccess from "./icons/IconClipboardSuccess.vue";
|
|
27
|
+
import IconFullScreen from "./icons/iconFullScreen.vue";
|
|
28
|
+
import IconFullScreenExit from "./icons/iconFullScreenExit.vue";
|
|
29
|
+
import MermaidExpandOverlay from "./MermaidExpandOverlay.vue";
|
|
30
|
+
import IconExpand from "./icons/IconExpand.vue";
|
|
31
|
+
import IconCollapse from "./icons/IconCollapse.vue";
|
|
32
|
+
import MermaidZoomToolbar from "./MermaidZoomToolbar.vue";
|
|
33
|
+
const isMac = import.meta.client ? /Mac|iPhone|iPad|iPod/.test(navigator.userAgent) : false;
|
|
17
34
|
const props = defineProps({
|
|
18
35
|
config: { type: null, required: false },
|
|
36
|
+
toolbar: { type: Object, required: false },
|
|
19
37
|
code: { type: String, required: false }
|
|
20
38
|
});
|
|
21
39
|
const nuxtApp = useNuxtApp();
|
|
@@ -26,6 +44,24 @@ const debug = contentMermaidOptions.debug || false;
|
|
|
26
44
|
const loaderOptions = contentMermaidOptions.loader || {};
|
|
27
45
|
const themeOptions = contentMermaidOptions.theme || {};
|
|
28
46
|
const componentOptions = contentMermaidOptions.components || {};
|
|
47
|
+
function resolveExpandOptions(expand) {
|
|
48
|
+
if (expand === false)
|
|
49
|
+
return { ...DEFAULT_EXPAND_OPTIONS, enabled: false };
|
|
50
|
+
if (expand === true || !expand || typeof expand !== "object")
|
|
51
|
+
return DEFAULT_EXPAND_OPTIONS;
|
|
52
|
+
return defu({}, expand, DEFAULT_EXPAND_OPTIONS);
|
|
53
|
+
}
|
|
54
|
+
const expandOptions = resolveExpandOptions(contentMermaidOptions.expand);
|
|
55
|
+
const expandEnabled = expandOptions.enabled !== false;
|
|
56
|
+
const expandOpenOptions = expandOptions.invokeOpenOn || {};
|
|
57
|
+
const expandCloseOptions = expandOptions.invokeCloseOn || {};
|
|
58
|
+
const expandMargin = typeof expandOptions.margin === "number" && Number.isFinite(expandOptions.margin) ? Math.max(0, expandOptions.margin) : 0;
|
|
59
|
+
const allowOpenDiagramClick = expandOpenOptions.diagramClick !== false;
|
|
60
|
+
const allowOverlayClose = expandCloseOptions.overlayClick !== false;
|
|
61
|
+
const allowCloseButtonClose = expandCloseOptions.closeButtonClick !== false;
|
|
62
|
+
const allowEscClose = expandCloseOptions.esc !== false;
|
|
63
|
+
const allowWheelClose = expandCloseOptions.wheel !== false;
|
|
64
|
+
const allowSwipeClose = expandCloseOptions.swipe !== false;
|
|
29
65
|
const lazyOption = loaderOptions.lazy;
|
|
30
66
|
const isLazy = lazyOption !== false;
|
|
31
67
|
const lazyThreshold = typeof lazyOption === "object" && typeof lazyOption.threshold === "number" ? lazyOption.threshold : 0.1;
|
|
@@ -35,6 +71,7 @@ const darkTheme = themeOptions.dark;
|
|
|
35
71
|
const colorMode = nuxtApp.$colorMode;
|
|
36
72
|
const { $mermaid } = nuxtApp;
|
|
37
73
|
const { currentTheme: manualThemeMode } = useMermaidTheme();
|
|
74
|
+
const mermaidBlock = useTemplateRef("mermaidBlock");
|
|
38
75
|
const mermaidContainer = useTemplateRef("mermaidContainer");
|
|
39
76
|
const hasRenderedOnce = ref(false);
|
|
40
77
|
const isLoading = ref(false);
|
|
@@ -43,7 +80,81 @@ const errorContent = shallowRef(null);
|
|
|
43
80
|
const decodedCode = computed(() => props.code ? decodeURIComponent(props.code) : "");
|
|
44
81
|
const mermaidDefinition = ref(decodedCode.value);
|
|
45
82
|
let observer = null;
|
|
46
|
-
const
|
|
83
|
+
const defaultToolbarTitle = DEFAULT_TOOLBAR_OPTIONS.title ?? "mermaid";
|
|
84
|
+
const defaultToolbarFontSize = DEFAULT_TOOLBAR_OPTIONS.fontSize ?? "14px";
|
|
85
|
+
const defaultFullscreenToolbarScale = DEFAULT_TOOLBAR_OPTIONS.fullscreenToolbarScale ?? 1.25;
|
|
86
|
+
const baseToolbarDefaults = DEFAULT_TOOLBAR_OPTIONS;
|
|
87
|
+
const runtimeToolbarDefaults = computed(() => {
|
|
88
|
+
const toolbar = contentMermaidOptions.toolbar;
|
|
89
|
+
return toolbar && typeof toolbar === "object" ? toolbar : {};
|
|
90
|
+
});
|
|
91
|
+
const resolvedToolbar = computed(() => {
|
|
92
|
+
return defu({}, props.toolbar ?? {}, runtimeToolbarDefaults.value, baseToolbarDefaults);
|
|
93
|
+
});
|
|
94
|
+
const toolbarButtons = computed(() => {
|
|
95
|
+
const buttons = resolvedToolbar.value.buttons;
|
|
96
|
+
return isRecord(buttons) ? buttons : {};
|
|
97
|
+
});
|
|
98
|
+
const toolbarTitle = computed(() => resolvedToolbar.value.title ?? defaultToolbarTitle);
|
|
99
|
+
const toolbarFontSize = computed(() => {
|
|
100
|
+
const value = resolvedToolbar.value.fontSize ?? defaultToolbarFontSize;
|
|
101
|
+
if (typeof value === "number")
|
|
102
|
+
return `${value}px`;
|
|
103
|
+
if (typeof value === "string") {
|
|
104
|
+
const trimmed = value.trim();
|
|
105
|
+
if (/^\d+(?:\.\d+)?$/.test(trimmed))
|
|
106
|
+
return `${trimmed}px`;
|
|
107
|
+
return trimmed;
|
|
108
|
+
}
|
|
109
|
+
return defaultToolbarFontSize;
|
|
110
|
+
});
|
|
111
|
+
const showCopyButton = computed(() => toolbarButtons.value.copy !== false);
|
|
112
|
+
const copySource = computed(() => decodedCode.value || mermaidDefinition.value || "");
|
|
113
|
+
const hasCopySource = computed(() => !!copySource.value);
|
|
114
|
+
const copyState = ref("idle");
|
|
115
|
+
const copyLabel = computed(() => {
|
|
116
|
+
if (copyState.value === "copied") return "Copied";
|
|
117
|
+
if (copyState.value === "error") return "Copy failed";
|
|
118
|
+
return "Copy";
|
|
119
|
+
});
|
|
120
|
+
let copyResetTimer = null;
|
|
121
|
+
const isCopyHovered = ref(false);
|
|
122
|
+
const copyIcon = computed(() => {
|
|
123
|
+
if (copyState.value === "copied") return IconClipboardSuccess;
|
|
124
|
+
if (isCopyHovered.value && hasCopySource.value) return IconClipboardHover;
|
|
125
|
+
return IconClipboard;
|
|
126
|
+
});
|
|
127
|
+
const { isSupported: isFullscreenSupported, isFullscreen, toggle: toggleFullscreen } = useFullscreen(mermaidBlock, {
|
|
128
|
+
autoExit: true
|
|
129
|
+
});
|
|
130
|
+
const showFullscreenButton = computed(() => toolbarButtons.value.fullscreen !== false && isFullscreenSupported.value);
|
|
131
|
+
const fullscreenLabel = computed(() => isFullscreen.value ? "Exit fullscreen" : "Enter fullscreen");
|
|
132
|
+
const fullscreenToolbarScale = computed(() => {
|
|
133
|
+
const raw = resolvedToolbar.value.fullscreenToolbarScale ?? defaultFullscreenToolbarScale;
|
|
134
|
+
if (typeof raw === "number" && Number.isFinite(raw))
|
|
135
|
+
return raw;
|
|
136
|
+
if (typeof raw === "string") {
|
|
137
|
+
const parsed = Number.parseFloat(raw);
|
|
138
|
+
if (Number.isFinite(parsed))
|
|
139
|
+
return parsed;
|
|
140
|
+
}
|
|
141
|
+
return defaultFullscreenToolbarScale;
|
|
142
|
+
});
|
|
143
|
+
const toolbarFontSizePx = computed(() => {
|
|
144
|
+
return parseSizeToPx(resolvedToolbar.value.fontSize ?? defaultToolbarFontSize, 14);
|
|
145
|
+
});
|
|
146
|
+
const fullscreenToolbarFontSize = computed(() => {
|
|
147
|
+
const scaled = toolbarFontSizePx.value * fullscreenToolbarScale.value;
|
|
148
|
+
return `${Math.round(scaled * 100) / 100}px`;
|
|
149
|
+
});
|
|
150
|
+
const effectiveToolbarFontSize = computed(() => {
|
|
151
|
+
return isFullscreen.value ? fullscreenToolbarFontSize.value : toolbarFontSize.value;
|
|
152
|
+
});
|
|
153
|
+
const effectiveToolbarFontSizePx = computed(() => {
|
|
154
|
+
const baseSize = toolbarFontSizePx.value;
|
|
155
|
+
return isFullscreen.value ? baseSize * fullscreenToolbarScale.value : baseSize;
|
|
156
|
+
});
|
|
157
|
+
const pageConfig = computed(() => {
|
|
47
158
|
const value = props.config;
|
|
48
159
|
if (!value)
|
|
49
160
|
return void 0;
|
|
@@ -62,7 +173,7 @@ const mermaidTheme = computed(() => {
|
|
|
62
173
|
return resolveMermaidTheme({
|
|
63
174
|
colorModeValue: colorMode?.value,
|
|
64
175
|
manualThemeMode: manualThemeMode.value,
|
|
65
|
-
frontmatterTheme:
|
|
176
|
+
frontmatterTheme: pageConfig.value?.theme,
|
|
66
177
|
baseTheme: baseMermaidInit.theme,
|
|
67
178
|
lightTheme,
|
|
68
179
|
darkTheme
|
|
@@ -71,7 +182,7 @@ const mermaidTheme = computed(() => {
|
|
|
71
182
|
const effectiveMermaidInit = computed(() => {
|
|
72
183
|
return mergeMermaidConfig({
|
|
73
184
|
baseConfig: baseMermaidInit,
|
|
74
|
-
overrideConfig:
|
|
185
|
+
overrideConfig: pageConfig.value,
|
|
75
186
|
theme: mermaidTheme.value
|
|
76
187
|
});
|
|
77
188
|
});
|
|
@@ -82,6 +193,162 @@ const customMermaidImpl = shallowRef(null);
|
|
|
82
193
|
const configuredErrorName = computed(() => componentOptions.error?.trim() || "");
|
|
83
194
|
const errorComponent = shallowRef(null);
|
|
84
195
|
const spinnerComponent = computed(() => customSpinner.value || Spinner);
|
|
196
|
+
const iconSize = computed(() => {
|
|
197
|
+
return Math.round(effectiveToolbarFontSizePx.value * 1.2);
|
|
198
|
+
});
|
|
199
|
+
const isExpandBlocked = computed(() => !isEnabled || !expandEnabled || isLoading.value || hasError.value || isFullscreen.value);
|
|
200
|
+
const fullscreenZoom = useMermaidZoom({
|
|
201
|
+
active: isFullscreen,
|
|
202
|
+
minScale: 0.1,
|
|
203
|
+
maxScale: 10
|
|
204
|
+
});
|
|
205
|
+
const showFullscreenZoomHint = ref(false);
|
|
206
|
+
const fullscreenHintDurationMs = 3e3;
|
|
207
|
+
let fullscreenHintTimeout;
|
|
208
|
+
let hasShownFullscreenZoomHint = false;
|
|
209
|
+
watch(isFullscreen, (value) => {
|
|
210
|
+
if (value) {
|
|
211
|
+
hasShownFullscreenZoomHint = false;
|
|
212
|
+
nextTick(() => {
|
|
213
|
+
const el = mermaidContainer.value;
|
|
214
|
+
if (el) {
|
|
215
|
+
const rect = el.getBoundingClientRect();
|
|
216
|
+
fullscreenZoom.init({
|
|
217
|
+
scale: 1,
|
|
218
|
+
translateX: 0,
|
|
219
|
+
translateY: 0,
|
|
220
|
+
top: rect.top,
|
|
221
|
+
left: rect.left
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
} else {
|
|
226
|
+
showFullscreenZoomHint.value = false;
|
|
227
|
+
clearTimeout(fullscreenHintTimeout);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
function refreshFullscreenOrigin() {
|
|
231
|
+
if (!import.meta.client || !isFullscreen.value) return;
|
|
232
|
+
const el = mermaidContainer.value;
|
|
233
|
+
if (!el) return;
|
|
234
|
+
requestAnimationFrame(() => {
|
|
235
|
+
requestAnimationFrame(() => {
|
|
236
|
+
const rect = el.getBoundingClientRect();
|
|
237
|
+
fullscreenZoom.setMetrics({
|
|
238
|
+
scale: fullscreenZoom.scale.value,
|
|
239
|
+
translateX: fullscreenZoom.translateX.value,
|
|
240
|
+
translateY: fullscreenZoom.translateY.value,
|
|
241
|
+
top: rect.top,
|
|
242
|
+
left: rect.left
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
function handleFullscreenWheel(event) {
|
|
248
|
+
if (!isFullscreen.value) return;
|
|
249
|
+
const handled = fullscreenZoom.handleWheel(event);
|
|
250
|
+
if (handled) {
|
|
251
|
+
if (fullscreenHintTimeout && showFullscreenZoomHint.value) {
|
|
252
|
+
showFullscreenZoomHint.value = false;
|
|
253
|
+
clearTimeout(fullscreenHintTimeout);
|
|
254
|
+
}
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
if (!hasShownFullscreenZoomHint) {
|
|
258
|
+
hasShownFullscreenZoomHint = true;
|
|
259
|
+
showFullscreenZoomHint.value = true;
|
|
260
|
+
clearTimeout(fullscreenHintTimeout);
|
|
261
|
+
fullscreenHintTimeout = setTimeout(() => {
|
|
262
|
+
showFullscreenZoomHint.value = false;
|
|
263
|
+
}, fullscreenHintDurationMs);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function handleFullscreenKeyDown(event) {
|
|
267
|
+
if (!isFullscreen.value) return;
|
|
268
|
+
if (event.defaultPrevented) return;
|
|
269
|
+
const target = event.target;
|
|
270
|
+
if (target) {
|
|
271
|
+
const tagName = target.tagName;
|
|
272
|
+
if (target.isContentEditable || tagName === "INPUT" || tagName === "TEXTAREA" || tagName === "SELECT")
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
const browserZoomKeys = /* @__PURE__ */ new Set(["+", "=", "-", "_"]);
|
|
276
|
+
if (event.ctrlKey || event.metaKey) {
|
|
277
|
+
if (browserZoomKeys.has(event.key))
|
|
278
|
+
event.preventDefault();
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const moveStep = 20 / fullscreenZoom.scale.value;
|
|
282
|
+
const keyHandlers = {
|
|
283
|
+
"+": () => fullscreenZoom.zoomIn(),
|
|
284
|
+
"=": () => fullscreenZoom.zoomIn(),
|
|
285
|
+
"-": () => fullscreenZoom.zoomOut(),
|
|
286
|
+
"_": () => fullscreenZoom.zoomOut(),
|
|
287
|
+
"0": () => fullscreenZoom.reset(),
|
|
288
|
+
"ArrowUp": () => {
|
|
289
|
+
fullscreenZoom.translateY.value += moveStep;
|
|
290
|
+
},
|
|
291
|
+
"ArrowDown": () => {
|
|
292
|
+
fullscreenZoom.translateY.value -= moveStep;
|
|
293
|
+
},
|
|
294
|
+
"ArrowLeft": () => {
|
|
295
|
+
fullscreenZoom.translateX.value += moveStep;
|
|
296
|
+
},
|
|
297
|
+
"ArrowRight": () => {
|
|
298
|
+
fullscreenZoom.translateX.value -= moveStep;
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
const handler = keyHandlers[event.key];
|
|
302
|
+
if (handler) {
|
|
303
|
+
event.preventDefault();
|
|
304
|
+
handler();
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (import.meta.client) {
|
|
308
|
+
const fullscreenDocument = computed(() => isFullscreen.value ? document : null);
|
|
309
|
+
const fullscreenWindow = computed(() => isFullscreen.value ? window : null);
|
|
310
|
+
const fullscreenVisualViewport = computed(() => isFullscreen.value ? window.visualViewport : null);
|
|
311
|
+
useEventListener(fullscreenWindow, "wheel", handleFullscreenWheel, { passive: false });
|
|
312
|
+
useEventListener(fullscreenDocument, "keydown", handleFullscreenKeyDown);
|
|
313
|
+
useEventListener(fullscreenWindow, "focus", refreshFullscreenOrigin);
|
|
314
|
+
useEventListener(fullscreenDocument, "fullscreenchange", refreshFullscreenOrigin);
|
|
315
|
+
useEventListener(fullscreenVisualViewport, "resize", refreshFullscreenOrigin, { passive: true });
|
|
316
|
+
useEventListener(fullscreenDocument, "visibilitychange", () => {
|
|
317
|
+
if (document.visibilityState === "visible") refreshFullscreenOrigin();
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
const {
|
|
321
|
+
setExpandTargetWrap,
|
|
322
|
+
expandTargetStyle,
|
|
323
|
+
isExpandActive,
|
|
324
|
+
isVisible,
|
|
325
|
+
closeExpand,
|
|
326
|
+
toggleExpand,
|
|
327
|
+
handleExpandTransitionEnd,
|
|
328
|
+
handleMermaidClick,
|
|
329
|
+
resetExpand,
|
|
330
|
+
zoom,
|
|
331
|
+
showZoomHint
|
|
332
|
+
} = useMermaidExpand({
|
|
333
|
+
getExpandTarget: getMermaidSvg,
|
|
334
|
+
expandMargin,
|
|
335
|
+
isBlocked: isExpandBlocked,
|
|
336
|
+
invokeOpenOn: {
|
|
337
|
+
diagramClick: allowOpenDiagramClick
|
|
338
|
+
},
|
|
339
|
+
invokeCloseOn: {
|
|
340
|
+
esc: allowEscClose,
|
|
341
|
+
wheel: allowWheelClose,
|
|
342
|
+
swipe: allowSwipeClose
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
const showExpandToolbarButton = computed(() => {
|
|
346
|
+
if (!expandEnabled) return false;
|
|
347
|
+
if (toolbarButtons.value.expand === false) return false;
|
|
348
|
+
if (isExpandActive.value) return false;
|
|
349
|
+
if (isFullscreen.value) return false;
|
|
350
|
+
return true;
|
|
351
|
+
});
|
|
85
352
|
function normalizeIdentifier(value) {
|
|
86
353
|
return value.replace(/\.vue$/i, "").split(/[\\/]/).pop()?.replace(/[\s_-]+/g, "").toLowerCase() || "";
|
|
87
354
|
}
|
|
@@ -192,11 +459,19 @@ function extractMermaidDefinition(container) {
|
|
|
192
459
|
if (pre) return serializeMermaidFromNode(pre).trim();
|
|
193
460
|
return serializeMermaidFromNode(container).trim();
|
|
194
461
|
}
|
|
462
|
+
function getMermaidSvg() {
|
|
463
|
+
if (!mermaidContainer.value) return null;
|
|
464
|
+
const svg = mermaidContainer.value.querySelector("svg");
|
|
465
|
+
return svg instanceof SVGSVGElement ? svg : null;
|
|
466
|
+
}
|
|
195
467
|
async function renderMermaid() {
|
|
196
468
|
if (!mermaidContainer.value || !mermaidDefinition.value) return;
|
|
197
469
|
isLoading.value = true;
|
|
198
470
|
const performRender = async () => {
|
|
199
471
|
if (!mermaidContainer.value) return;
|
|
472
|
+
if (import.meta.client && isExpandActive.value) {
|
|
473
|
+
resetExpand();
|
|
474
|
+
}
|
|
200
475
|
hasError.value = false;
|
|
201
476
|
errorContent.value = null;
|
|
202
477
|
const startTime = performance.now();
|
|
@@ -211,6 +486,8 @@ async function renderMermaid() {
|
|
|
211
486
|
suppressErrors: !debug
|
|
212
487
|
});
|
|
213
488
|
hasRenderedOnce.value = true;
|
|
489
|
+
const svg = getMermaidSvg();
|
|
490
|
+
if (svg) ensureViewBox(svg);
|
|
214
491
|
if (debug) {
|
|
215
492
|
const endTime = performance.now();
|
|
216
493
|
console.log(`[nuxt-content-mermaid] \u23F1\uFE0F Rendered in ${(endTime - startTime).toFixed(2)}ms`);
|
|
@@ -245,6 +522,44 @@ function setupMermaidContainer() {
|
|
|
245
522
|
);
|
|
246
523
|
observer.observe(container);
|
|
247
524
|
}
|
|
525
|
+
async function copyMermaidSource() {
|
|
526
|
+
if (!copySource.value) return;
|
|
527
|
+
const copied = await copyToClipboard(copySource.value);
|
|
528
|
+
copyState.value = copied ? "copied" : "error";
|
|
529
|
+
if (copyResetTimer)
|
|
530
|
+
clearTimeout(copyResetTimer);
|
|
531
|
+
copyResetTimer = setTimeout(() => {
|
|
532
|
+
copyState.value = "idle";
|
|
533
|
+
}, 2e3);
|
|
534
|
+
}
|
|
535
|
+
async function copyToClipboard(text) {
|
|
536
|
+
if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
|
|
537
|
+
try {
|
|
538
|
+
await navigator.clipboard.writeText(text);
|
|
539
|
+
return true;
|
|
540
|
+
} catch {
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
if (typeof document === "undefined")
|
|
544
|
+
return false;
|
|
545
|
+
const textarea = document.createElement("textarea");
|
|
546
|
+
textarea.value = text;
|
|
547
|
+
textarea.setAttribute("readonly", "");
|
|
548
|
+
textarea.style.position = "fixed";
|
|
549
|
+
textarea.style.top = "-9999px";
|
|
550
|
+
textarea.style.opacity = "0";
|
|
551
|
+
document.body.appendChild(textarea);
|
|
552
|
+
textarea.select();
|
|
553
|
+
let copied = false;
|
|
554
|
+
try {
|
|
555
|
+
copied = document.execCommand("copy");
|
|
556
|
+
} catch {
|
|
557
|
+
copied = false;
|
|
558
|
+
} finally {
|
|
559
|
+
document.body.removeChild(textarea);
|
|
560
|
+
}
|
|
561
|
+
return copied;
|
|
562
|
+
}
|
|
248
563
|
onMounted(() => {
|
|
249
564
|
if (!isEnabled) return;
|
|
250
565
|
if (!mermaidDefinition.value && mermaidContainer.value)
|
|
@@ -253,13 +568,14 @@ onMounted(() => {
|
|
|
253
568
|
});
|
|
254
569
|
onUnmounted(() => {
|
|
255
570
|
if (observer) observer.disconnect();
|
|
571
|
+
if (copyResetTimer) clearTimeout(copyResetTimer);
|
|
256
572
|
});
|
|
257
573
|
watch(mermaidTheme, () => {
|
|
258
574
|
if (!isEnabled) return;
|
|
259
575
|
if (hasRenderedOnce.value) renderMermaid();
|
|
260
576
|
});
|
|
261
577
|
watch(
|
|
262
|
-
|
|
578
|
+
pageConfig,
|
|
263
579
|
() => {
|
|
264
580
|
if (!isEnabled) return;
|
|
265
581
|
if (hasRenderedOnce.value) renderMermaid();
|
|
@@ -271,6 +587,17 @@ watch(decodedCode, (newCode) => {
|
|
|
271
587
|
mermaidDefinition.value = newCode;
|
|
272
588
|
if (hasRenderedOnce.value) renderMermaid();
|
|
273
589
|
});
|
|
590
|
+
function ensureViewBox(svg) {
|
|
591
|
+
if (svg.hasAttribute("viewBox"))
|
|
592
|
+
return;
|
|
593
|
+
try {
|
|
594
|
+
const bbox = svg.getBBox();
|
|
595
|
+
if (bbox.width > 0 && bbox.height > 0)
|
|
596
|
+
svg.setAttribute("viewBox", `${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}`);
|
|
597
|
+
} catch {
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
const { cursorVariables } = useMermaidCursors(iconSize, expandEnabled);
|
|
274
601
|
</script>
|
|
275
602
|
|
|
276
603
|
<template>
|
|
@@ -279,7 +606,10 @@ watch(decodedCode, (newCode) => {
|
|
|
279
606
|
v-if="!isEnabled"
|
|
280
607
|
class="mermaid-wrapper"
|
|
281
608
|
>
|
|
282
|
-
<div
|
|
609
|
+
<div
|
|
610
|
+
ref="mermaidContainer"
|
|
611
|
+
class="mermaid"
|
|
612
|
+
>
|
|
283
613
|
<slot />
|
|
284
614
|
</div>
|
|
285
615
|
</div>
|
|
@@ -297,46 +627,172 @@ watch(decodedCode, (newCode) => {
|
|
|
297
627
|
|
|
298
628
|
<div
|
|
299
629
|
v-else
|
|
300
|
-
|
|
301
|
-
|
|
630
|
+
ref="mermaidBlock"
|
|
631
|
+
class="mermaid-block"
|
|
632
|
+
:style="{ '--ncm-icon-size': `${iconSize}px` }"
|
|
302
633
|
>
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
<
|
|
306
|
-
|
|
307
|
-
|
|
634
|
+
<!-- Toolbar: Title and Actions -->
|
|
635
|
+
<div class="mermaid-toolbar">
|
|
636
|
+
<div
|
|
637
|
+
class="mermaid-title"
|
|
638
|
+
:style="{ fontSize: effectiveToolbarFontSize }"
|
|
639
|
+
>
|
|
640
|
+
<span v-if="toolbarTitle">{{ toolbarTitle }}</span>
|
|
641
|
+
</div>
|
|
642
|
+
<div class="mermaid-actions">
|
|
643
|
+
<button
|
|
644
|
+
v-if="showCopyButton"
|
|
645
|
+
type="button"
|
|
646
|
+
class="mermaid-btn"
|
|
647
|
+
:title="copyLabel"
|
|
648
|
+
:aria-label="copyLabel"
|
|
649
|
+
:disabled="!hasCopySource"
|
|
650
|
+
@click="copyMermaidSource"
|
|
651
|
+
@mouseenter="isCopyHovered = true"
|
|
652
|
+
@mouseleave="isCopyHovered = false"
|
|
653
|
+
>
|
|
654
|
+
<component
|
|
655
|
+
:is="copyIcon"
|
|
656
|
+
:size="iconSize"
|
|
657
|
+
/>
|
|
658
|
+
</button>
|
|
659
|
+
<button
|
|
660
|
+
v-if="showExpandToolbarButton"
|
|
661
|
+
type="button"
|
|
662
|
+
class="mermaid-btn"
|
|
663
|
+
:title="isExpandActive ? 'Collapse' : 'Expand'"
|
|
664
|
+
:aria-label="isExpandActive ? 'Collapse diagram' : 'Expand diagram'"
|
|
665
|
+
@click="toggleExpand"
|
|
666
|
+
>
|
|
667
|
+
<IconExpand
|
|
668
|
+
v-if="!isExpandActive"
|
|
669
|
+
:size="iconSize"
|
|
670
|
+
/>
|
|
671
|
+
<IconCollapse
|
|
672
|
+
v-else
|
|
673
|
+
:size="iconSize"
|
|
674
|
+
/>
|
|
675
|
+
</button>
|
|
676
|
+
<button
|
|
677
|
+
v-if="showFullscreenButton"
|
|
678
|
+
type="button"
|
|
679
|
+
class="mermaid-btn"
|
|
680
|
+
:title="fullscreenLabel"
|
|
681
|
+
:aria-label="fullscreenLabel"
|
|
682
|
+
@click="toggleFullscreen"
|
|
683
|
+
>
|
|
684
|
+
<IconFullScreen
|
|
685
|
+
v-if="!isFullscreen"
|
|
686
|
+
:size="iconSize"
|
|
687
|
+
/>
|
|
688
|
+
<IconFullScreenExit
|
|
689
|
+
v-else
|
|
690
|
+
:size="iconSize"
|
|
691
|
+
/>
|
|
692
|
+
</button>
|
|
693
|
+
</div>
|
|
308
694
|
</div>
|
|
309
695
|
|
|
310
|
-
<
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
696
|
+
<MermaidZoomToolbar
|
|
697
|
+
v-if="isFullscreen"
|
|
698
|
+
variant="fullscreen"
|
|
699
|
+
:scale="fullscreenZoom.scale.value"
|
|
700
|
+
:icon-size="iconSize"
|
|
701
|
+
@zoom-out="fullscreenZoom.zoomOut()"
|
|
702
|
+
@zoom-in="fullscreenZoom.zoomIn()"
|
|
703
|
+
@reset="fullscreenZoom.reset()"
|
|
704
|
+
/>
|
|
705
|
+
|
|
706
|
+
<!-- Fullscreen Zoom Hint -->
|
|
707
|
+
<Transition name="ncm-hint-fade">
|
|
708
|
+
<div
|
|
709
|
+
v-if="showFullscreenZoomHint && isFullscreen"
|
|
710
|
+
class="ncm-fullscreen-zoom-hint"
|
|
320
711
|
>
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
712
|
+
{{ isMac ? "\u2318" : "Ctrl" }} + Scroll to zoom
|
|
713
|
+
</div>
|
|
714
|
+
</Transition>
|
|
715
|
+
|
|
716
|
+
<!-- Diagram Container -->
|
|
717
|
+
<div
|
|
718
|
+
class="mermaid-wrapper"
|
|
719
|
+
:class="{
|
|
720
|
+
'ncm-is-loading': isLoading && !hasRenderedOnce,
|
|
721
|
+
'ncm-expand-hidden': isExpandActive,
|
|
722
|
+
'ncm-expand-clickable': expandEnabled && allowOpenDiagramClick && !isFullscreen,
|
|
723
|
+
'ncm-fullscreen-zoom': isFullscreen
|
|
724
|
+
}"
|
|
725
|
+
:style="cursorVariables"
|
|
726
|
+
@click="handleMermaidClick"
|
|
727
|
+
@mousedown="isFullscreen && fullscreenZoom.handleDragStart($event)"
|
|
728
|
+
@mousemove="isFullscreen && fullscreenZoom.handleDragMove($event)"
|
|
729
|
+
@touchstart="isFullscreen && fullscreenZoom.handleDragStart($event)"
|
|
730
|
+
@touchmove="isFullscreen && fullscreenZoom.handleDragMove($event)"
|
|
731
|
+
@touchend="isFullscreen && fullscreenZoom.handleDragEnd()"
|
|
732
|
+
>
|
|
733
|
+
<div
|
|
734
|
+
ref="mermaidContainer"
|
|
735
|
+
class="mermaid"
|
|
736
|
+
:style="isFullscreen ? {
|
|
737
|
+
transform: fullscreenZoom.transformStyle.value.transform,
|
|
738
|
+
transformOrigin: '0 0',
|
|
739
|
+
cursor: fullscreenZoom.cursor.value
|
|
740
|
+
} : void 0"
|
|
741
|
+
>
|
|
742
|
+
<!-- Initially show the slot's <pre><code> for SSR; client-side rendering will replace it with the mermaid SVG -->
|
|
743
|
+
<slot>
|
|
744
|
+
<pre v-if="decodedCode"><code>{{ decodedCode }}</code></pre>
|
|
745
|
+
</slot>
|
|
746
|
+
</div>
|
|
747
|
+
|
|
748
|
+
<template v-if="isLoading && !hasRenderedOnce">
|
|
749
|
+
<slot name="loading">
|
|
750
|
+
<component :is="spinnerComponent" />
|
|
751
|
+
</slot>
|
|
752
|
+
</template>
|
|
753
|
+
<template v-else-if="hasError">
|
|
754
|
+
<slot
|
|
755
|
+
name="error"
|
|
324
756
|
:error="errorContent"
|
|
325
757
|
:source="mermaidDefinition"
|
|
326
|
-
/>
|
|
327
|
-
|
|
328
|
-
<div
|
|
329
|
-
v-else
|
|
330
|
-
class="mermaid-error-default"
|
|
331
758
|
>
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
759
|
+
<component
|
|
760
|
+
:is="errorComponent"
|
|
761
|
+
v-if="errorComponent"
|
|
762
|
+
:error="errorContent"
|
|
763
|
+
:source="mermaidDefinition"
|
|
764
|
+
/>
|
|
765
|
+
|
|
766
|
+
<div
|
|
767
|
+
v-else
|
|
768
|
+
class="mermaid-error-default"
|
|
769
|
+
>
|
|
770
|
+
⚠️ Mermaid Diagram Error
|
|
771
|
+
</div>
|
|
772
|
+
</slot>
|
|
773
|
+
</template>
|
|
774
|
+
</div>
|
|
775
|
+
|
|
776
|
+
<MermaidExpandOverlay
|
|
777
|
+
:active="isExpandActive"
|
|
778
|
+
:is-visable="isVisible"
|
|
779
|
+
:overlay-style="cursorVariables"
|
|
780
|
+
:content-style="cursorVariables"
|
|
781
|
+
:target-style="expandTargetStyle"
|
|
782
|
+
:target-ref="setExpandTargetWrap"
|
|
783
|
+
:allow-overlay-close="allowOverlayClose"
|
|
784
|
+
:allow-close-button="allowCloseButtonClose"
|
|
785
|
+
:target-has-margin="expandMargin > 0"
|
|
786
|
+
:icon-size="iconSize"
|
|
787
|
+
:zoom="zoom"
|
|
788
|
+
:show-hint="showZoomHint"
|
|
789
|
+
@close="closeExpand"
|
|
790
|
+
@transitionend="handleExpandTransitionEnd"
|
|
791
|
+
/>
|
|
336
792
|
</div>
|
|
337
793
|
</div>
|
|
338
794
|
</template>
|
|
339
795
|
|
|
340
796
|
<style scoped>
|
|
341
|
-
.mermaid-
|
|
797
|
+
.mermaid-block{border:var(--ncm-border);border-radius:4px;flex-direction:column;margin:1rem 0;overflow:hidden;--ncm-toolbar-height:calc(var(--ncm-icon-size, 17px) + 20px)}.mermaid-block,.mermaid-toolbar{background-color:var(--ncm-code-bg);display:flex}.mermaid-toolbar{align-items:center;border-bottom:var(--ncm-border-bottom);border-top-left-radius:4px;border-top-right-radius:4px;justify-content:space-between;padding:.375rem .375rem .375rem .75rem;z-index:20}.mermaid-title{color:var(--ncm-text-muted);font-weight:500;letter-spacing:0;line-height:1.25;max-width:80%;overflow:hidden;padding:4px 0;text-overflow:ellipsis;white-space:nowrap}:fullscreen .mermaid-title{max-width:80%}.mermaid-actions{display:flex;gap:0;justify-self:flex-end}.mermaid-btn{align-items:center;background:var(--ncm-code-bg);border:none;border-radius:4px;color:var(--ncm-text-xmuted);cursor:pointer;display:flex;justify-content:center;line-height:1.25;padding:4px;transition:color .2s,background-color .2s}.mermaid-btn:hover{background-color:var(--ncm-code-bg-hover);color:var(--ncm-text)}.mermaid-btn:disabled{color:var(--ncm-text-xmuted);cursor:not-allowed;opacity:.6}.mermaid-wrapper{align-items:center;display:flex;justify-content:center;overflow:auto;padding:1rem;position:relative;--sb-thumb:rgba(0,0,0,.2);--sb-thumb-hover:rgba(0,0,0,.35)}.mermaid-wrapper>div{height:100%;width:100%}.mermaid-wrapper>div>:deep(svg){margin:0 auto}.mermaid-wrapper :deep(code),.mermaid-wrapper :deep(pre){height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0,0,0,0);border:0;clip-path:inset(50%);white-space:nowrap}.mermaid:not([data-processed]){color:transparent;min-height:100px}:fullscreen .mermaid-wrapper{flex:1;overflow:hidden;touch-action:none}:fullscreen .mermaid-wrapper::-webkit-scrollbar{display:none}:fullscreen .mermaid-wrapper :deep(svg){height:100%!important;max-height:none!important;max-width:none!important;width:100%!important}:global(.dark .mermaid-wrapper){--sb-thumb:hsla(0,0%,100%,.2);--sb-thumb-hover:hsla(0,0%,100%,.35)}.mermaid-wrapper::-webkit-scrollbar{width:14px}.mermaid-wrapper::-webkit-scrollbar-track{background:hsla(0,0%,94%,.08)}:global(.dark .mermaid-wrapper::-webkit-scrollbar-track){background:hsla(0,0%,9%,.08)}.mermaid-wrapper::-webkit-scrollbar-corner{background:transparent}.mermaid-wrapper::-webkit-scrollbar-thumb{background-clip:content-box;background-color:var(--sb-thumb);border:3px solid transparent;border-radius:10px}.mermaid-wrapper::-webkit-scrollbar-thumb:hover{background-color:var(--sb-thumb-hover)}.mermaid-wrapper.ncm-is-loading{align-items:center;display:flex;justify-content:center;min-height:150px}.mermaid-wrapper.ncm-expand-hidden{opacity:0;pointer-events:none}.mermaid-wrapper.ncm-expand-clickable :deep(svg){cursor:var(--ncm-cursor-expand)}.ncm-fullscreen-zoom-hint{display:none}:fullscreen .ncm-fullscreen-zoom-hint{background-color:var(--ncm-hint-bg,rgba(0,0,0,.75));border-radius:var(--ncm-hint-radius,8px);color:var(--ncm-hint-text,#fff);display:block;font-size:20px;font-weight:500;left:50%;padding:12px 24px;pointer-events:none;position:absolute;top:50%;transform:translate(-50%,-50%);-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap;z-index:20}.ncm-hint-fade-enter-active,.ncm-hint-fade-leave-active{transition:opacity .2s ease}.ncm-hint-fade-enter-from,.ncm-hint-fade-leave-to{opacity:0}@media (prefers-reduced-motion:reduce){.ncm-hint-fade-enter-active,.ncm-hint-fade-leave-active{transition-duration:.01ms!important}}.mermaid-error-default{color:#f55;font-family:monospace;padding:1rem;white-space:pre-wrap}
|
|
342
798
|
</style>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { MermaidConfig } from 'mermaid';
|
|
2
|
+
import type { MermaidToolbarOptions } from '~/src/types/mermaid';
|
|
2
3
|
type __VLS_Props = {
|
|
3
4
|
config?: MermaidConfig | string | unknown;
|
|
5
|
+
toolbar?: MermaidToolbarOptions;
|
|
4
6
|
code?: string;
|
|
5
7
|
};
|
|
6
|
-
declare var __VLS_1: {}, __VLS_9: {},
|
|
8
|
+
declare var __VLS_1: {}, __VLS_9: {}, __VLS_52: {}, __VLS_54: {}, __VLS_62: {
|
|
7
9
|
error: unknown;
|
|
8
10
|
source: string;
|
|
9
11
|
};
|
|
@@ -12,11 +14,11 @@ type __VLS_Slots = {} & {
|
|
|
12
14
|
} & {
|
|
13
15
|
default?: (props: typeof __VLS_9) => any;
|
|
14
16
|
} & {
|
|
15
|
-
default?: (props: typeof
|
|
17
|
+
default?: (props: typeof __VLS_52) => any;
|
|
16
18
|
} & {
|
|
17
|
-
loading?: (props: typeof
|
|
19
|
+
loading?: (props: typeof __VLS_54) => any;
|
|
18
20
|
} & {
|
|
19
|
-
error?: (props: typeof
|
|
21
|
+
error?: (props: typeof __VLS_62) => any;
|
|
20
22
|
};
|
|
21
23
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
22
24
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|