97 lines
2.2 KiB
Vue
97 lines
2.2 KiB
Vue
<template>
|
||
<div ref="divRef" :class="['tinyflow', className]" :style="style" />
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import {Tinyflow as TinyflowNative, TinyflowOptions} from '@tinyflow-ai/ui';
|
||
import '@tinyflow-ai/ui/dist/index.css';
|
||
import {onMounted, onUnmounted, ref, watch} from 'vue';
|
||
|
||
const props = defineProps<
|
||
{
|
||
className?: string;
|
||
style?: Record<string, string>;
|
||
} & Omit<TinyflowOptions, 'element'>
|
||
>();
|
||
|
||
const divRef = ref<HTMLDivElement | null>(null);
|
||
let tinyflow: TinyflowNative | null = null;
|
||
|
||
// 安全深拷贝工具函数
|
||
function safeDeepClone<T>(obj: T): T {
|
||
if (obj === null || typeof obj !== 'object') return obj;
|
||
|
||
try {
|
||
return structuredClone(obj);
|
||
} catch {
|
||
try {
|
||
return JSON.parse(JSON.stringify(obj));
|
||
} catch {
|
||
console.warn('Failed to clone object, returning original (may cause issues)', obj);
|
||
return obj;
|
||
}
|
||
}
|
||
}
|
||
|
||
onMounted(() => {
|
||
if (divRef.value) {
|
||
// 净化 props.data,避免响应式对象或函数污染
|
||
const cleanedProps = { ...props } as any;
|
||
if ('data' in cleanedProps && cleanedProps.data != null) {
|
||
cleanedProps.data = safeDeepClone(cleanedProps.data);
|
||
}
|
||
|
||
tinyflow = new TinyflowNative({
|
||
...cleanedProps,
|
||
element: divRef.value
|
||
});
|
||
}
|
||
});
|
||
|
||
onUnmounted(() => {
|
||
if (tinyflow) {
|
||
tinyflow.destroy();
|
||
tinyflow = null;
|
||
}
|
||
});
|
||
|
||
watch(
|
||
() => props.theme,
|
||
(theme) => {
|
||
if (tinyflow) {
|
||
tinyflow.setTheme(theme || 'light');
|
||
}
|
||
}
|
||
);
|
||
|
||
const getData = () => {
|
||
if (tinyflow) {
|
||
return tinyflow.getData();
|
||
}
|
||
console.warn('Tinyflow instance is not initialized');
|
||
return null;
|
||
};
|
||
|
||
const getInstance = () => {
|
||
if (tinyflow) {
|
||
return tinyflow;
|
||
}
|
||
console.warn('Tinyflow instance is not initialized');
|
||
return null;
|
||
};
|
||
|
||
const focusNode = async (nodeId: string, options?: { duration?: number; zoom?: number }) => {
|
||
if (tinyflow) {
|
||
return tinyflow.focusNode(nodeId, options);
|
||
}
|
||
console.warn('Tinyflow instance is not initialized');
|
||
return false;
|
||
};
|
||
|
||
defineExpose({
|
||
getData,
|
||
getInstance,
|
||
focusNode
|
||
});
|
||
</script>
|