@logicflow/vue-node-registry 1.2.0-alpha.7 → 1.2.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/README.md +6 -3
- package/es/registry.d.ts +14 -3
- package/es/registry.js +28 -5
- package/es/registry.js.map +1 -1
- package/es/view.js +18 -2
- package/es/view.js.map +1 -1
- package/lib/registry.d.ts +14 -3
- package/lib/registry.js +30 -6
- package/lib/registry.js.map +1 -1
- package/lib/view.js +17 -1
- package/lib/view.js.map +1 -1
- package/package.json +10 -5
- package/.turbo/turbo-build$colon$dev.log +0 -10
- package/.turbo/turbo-build.log +0 -34
- package/CHANGELOG.md +0 -272
- package/rollup.config.js +0 -52
- package/src/assets/arrow.svg +0 -10
- package/src/components/container.ts +0 -36
- package/src/components/titleBar.ts +0 -189
- package/src/index.less +0 -1
- package/src/index.ts +0 -4
- package/src/model.ts +0 -141
- package/src/registry.ts +0 -43
- package/src/style/index.less +0 -140
- package/src/style/raw.ts +0 -129
- package/src/teleport.ts +0 -155
- package/src/utils/size.ts +0 -22
- package/src/view.ts +0 -238
- package/stats.html +0 -4842
- package/tsconfig.json +0 -20
package/src/view.ts
DELETED
|
@@ -1,238 +0,0 @@
|
|
|
1
|
-
import { isVue2, isVue3, createApp, h, Vue2, defineComponent } from 'vue-demi'
|
|
2
|
-
// Vue2/3 兼容 API;使用 vue-demi 保持两端一致
|
|
3
|
-
import {
|
|
4
|
-
throttle,
|
|
5
|
-
round,
|
|
6
|
-
get,
|
|
7
|
-
isFunction,
|
|
8
|
-
isArray,
|
|
9
|
-
clamp,
|
|
10
|
-
isNumber,
|
|
11
|
-
} from 'lodash-es'
|
|
12
|
-
import { HtmlNode } from '@logicflow/core'
|
|
13
|
-
import { vueNodesMap } from './registry'
|
|
14
|
-
import { isActive, connect, disconnect } from './teleport'
|
|
15
|
-
import { Container } from './components/container'
|
|
16
|
-
|
|
17
|
-
export class VueNodeView extends HtmlNode {
|
|
18
|
-
root?: any
|
|
19
|
-
private vm: any
|
|
20
|
-
// 尺寸监听相关状态
|
|
21
|
-
private __resizeObserver?: ResizeObserver
|
|
22
|
-
private __resizeRafId?: number
|
|
23
|
-
private __lastWidth?: number
|
|
24
|
-
private __lastHeight?: number
|
|
25
|
-
private __fallbackUnlisten?: () => void
|
|
26
|
-
private __throttledUpdate = throttle(() => this.measureAndUpdate(), 80)
|
|
27
|
-
// private isMounted: boolean = false
|
|
28
|
-
|
|
29
|
-
getComponentContainer() {
|
|
30
|
-
return this.root
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
protected targetId() {
|
|
34
|
-
return `${this.props.graphModel.flowId}:${this.props.model.id}`
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
componentWillUnmount() {
|
|
38
|
-
super.componentWillUnmount()
|
|
39
|
-
this.unmount()
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
setHtml(rootEl: SVGForeignObjectElement) {
|
|
43
|
-
// 创建节点内容容器并注入到 foreignObject(若已存在则复用)
|
|
44
|
-
const existed = rootEl.querySelector('.custom-vue-node-content')
|
|
45
|
-
if (!existed) {
|
|
46
|
-
const el = document.createElement('div')
|
|
47
|
-
el.className = 'custom-vue-node-content'
|
|
48
|
-
this.root = el
|
|
49
|
-
rootEl.appendChild(el)
|
|
50
|
-
}
|
|
51
|
-
// 渲染 Vue 组件并启用尺寸监听
|
|
52
|
-
this.renderVueComponent()
|
|
53
|
-
this.startResizeObserver()
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
57
|
-
confirmUpdate(_rootEl: SVGForeignObjectElement) {
|
|
58
|
-
// TODO: 如有需要,可以先通过继承的方式,自定义该节点的更新逻辑;我们后续会根据实际需求,丰富该功能
|
|
59
|
-
const { model } = this.props
|
|
60
|
-
const { _showTitle = false } = model.properties || {}
|
|
61
|
-
if (_showTitle) {
|
|
62
|
-
this.setHtml(_rootEl)
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
protected renderVueComponent() {
|
|
67
|
-
this.unmountVueComponent()
|
|
68
|
-
const root = this.getComponentContainer()
|
|
69
|
-
const { model, graphModel } = this.props
|
|
70
|
-
const { _showTitle = false } = model.properties || {}
|
|
71
|
-
const wrapWithContainer = (child: any) =>
|
|
72
|
-
defineComponent({
|
|
73
|
-
name: 'LFVueNodeContainerWrapper',
|
|
74
|
-
props: {
|
|
75
|
-
node: { type: Object, required: true },
|
|
76
|
-
graph: { type: Object, required: true },
|
|
77
|
-
},
|
|
78
|
-
render(this: any) {
|
|
79
|
-
// 根据 _showTitle 决定是否用 Container 包裹,避免无标题时额外结构
|
|
80
|
-
if (!_showTitle) {
|
|
81
|
-
return h(child, { node: this.node, graph: this.graph })
|
|
82
|
-
}
|
|
83
|
-
return h(Container, { node: this.node, graph: this.graph }, [
|
|
84
|
-
h(child, { node: this.node, graph: this.graph }),
|
|
85
|
-
])
|
|
86
|
-
},
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
if (root) {
|
|
90
|
-
const { component } = vueNodesMap[model.type]
|
|
91
|
-
if (component) {
|
|
92
|
-
if (isVue2) {
|
|
93
|
-
const Vue = Vue2 as any
|
|
94
|
-
const Composed = wrapWithContainer(component)
|
|
95
|
-
this.vm = new Vue({
|
|
96
|
-
el: root,
|
|
97
|
-
render(h: any) {
|
|
98
|
-
return h(Composed, {
|
|
99
|
-
props: {
|
|
100
|
-
node: model,
|
|
101
|
-
graph: graphModel,
|
|
102
|
-
},
|
|
103
|
-
})
|
|
104
|
-
},
|
|
105
|
-
provide() {
|
|
106
|
-
return {
|
|
107
|
-
getNode: () => model,
|
|
108
|
-
getGraph: () => graphModel,
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
})
|
|
112
|
-
} else if (isVue3) {
|
|
113
|
-
if (isActive()) {
|
|
114
|
-
const Composed = wrapWithContainer(component)
|
|
115
|
-
connect(this.targetId(), Composed, root, model, graphModel)
|
|
116
|
-
} else {
|
|
117
|
-
const Composed = wrapWithContainer(component)
|
|
118
|
-
this.vm = createApp({
|
|
119
|
-
render() {
|
|
120
|
-
return h(Composed, {
|
|
121
|
-
node: model,
|
|
122
|
-
graph: graphModel,
|
|
123
|
-
})
|
|
124
|
-
},
|
|
125
|
-
provide() {
|
|
126
|
-
return {
|
|
127
|
-
getNode: () => model,
|
|
128
|
-
getGraph: () => graphModel,
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
})
|
|
132
|
-
this.vm?.mount(root)
|
|
133
|
-
// this.isMounted = true
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
private measureAndUpdate = () => {
|
|
141
|
-
try {
|
|
142
|
-
// 读取子组件(或容器本身)的实际尺寸并更新模型属性
|
|
143
|
-
const root = this.getComponentContainer() as HTMLElement
|
|
144
|
-
if (!root) return
|
|
145
|
-
const target = (root.firstElementChild as HTMLElement) || root
|
|
146
|
-
const rect = target.getBoundingClientRect()
|
|
147
|
-
const width = round(rect.width)
|
|
148
|
-
const height = round(rect.height)
|
|
149
|
-
if (width <= 0 || height <= 0) return
|
|
150
|
-
if (width === this.__lastWidth && height === this.__lastHeight) return
|
|
151
|
-
this.__lastWidth = width
|
|
152
|
-
this.__lastHeight = height
|
|
153
|
-
const props = this.props.model.properties as any
|
|
154
|
-
const extra = get(props, '_showTitle')
|
|
155
|
-
? isNumber(get(props, '_titleHeight'))
|
|
156
|
-
? get(props, '_titleHeight')
|
|
157
|
-
: 28
|
|
158
|
-
: 0
|
|
159
|
-
// 去掉标题占用的高度,保证内容区域与模型高度一致
|
|
160
|
-
const baseHeight = clamp(height - extra, 1, Number.MAX_SAFE_INTEGER)
|
|
161
|
-
this.props.model.setProperties({ width, height: baseHeight })
|
|
162
|
-
} catch (err) {
|
|
163
|
-
// swallow error
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
private startResizeObserver() {
|
|
168
|
-
// 启动尺寸监听:优先使用 ResizeObserver,退化到 window.resize
|
|
169
|
-
const root = this.getComponentContainer() as HTMLElement
|
|
170
|
-
if (!root) return
|
|
171
|
-
try {
|
|
172
|
-
if (isFunction((window as any).ResizeObserver)) {
|
|
173
|
-
this.__resizeObserver = new (window as any).ResizeObserver(
|
|
174
|
-
(entries: any[]) => {
|
|
175
|
-
if (!isArray(entries) || !entries.length) return
|
|
176
|
-
if (this.__resizeRafId) cancelAnimationFrame(this.__resizeRafId)
|
|
177
|
-
// 使用 RAF 对齐绘制帧,再用节流函数合并频繁变更
|
|
178
|
-
this.__resizeRafId = requestAnimationFrame(this.__throttledUpdate)
|
|
179
|
-
},
|
|
180
|
-
)
|
|
181
|
-
const target = (root.firstElementChild as HTMLElement) || root
|
|
182
|
-
this.__resizeObserver?.observe(target)
|
|
183
|
-
} else {
|
|
184
|
-
// 退化监听:在窗口尺寸变化时尝试更新
|
|
185
|
-
window.addEventListener('resize', () => this.__throttledUpdate())
|
|
186
|
-
this.__fallbackUnlisten = () =>
|
|
187
|
-
window.removeEventListener('resize', () => this.__throttledUpdate())
|
|
188
|
-
}
|
|
189
|
-
} catch (err) {
|
|
190
|
-
// swallow error
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
private stopResizeObserver() {
|
|
195
|
-
try {
|
|
196
|
-
// 停止所有监听与异步回调,避免内存泄漏
|
|
197
|
-
if (this.__resizeObserver) {
|
|
198
|
-
this.__resizeObserver.disconnect()
|
|
199
|
-
this.__resizeObserver = undefined
|
|
200
|
-
}
|
|
201
|
-
if (this.__resizeRafId) {
|
|
202
|
-
cancelAnimationFrame(this.__resizeRafId)
|
|
203
|
-
this.__resizeRafId = undefined
|
|
204
|
-
}
|
|
205
|
-
if (this.__fallbackUnlisten) {
|
|
206
|
-
this.__fallbackUnlisten()
|
|
207
|
-
this.__fallbackUnlisten = undefined
|
|
208
|
-
}
|
|
209
|
-
} catch (err) {
|
|
210
|
-
// swallow error
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
protected unmountVueComponent() {
|
|
215
|
-
const root = this.getComponentContainer()
|
|
216
|
-
// 在卸载 Vue 实例前先停止尺寸监听
|
|
217
|
-
this.stopResizeObserver()
|
|
218
|
-
if (this.vm) {
|
|
219
|
-
isVue2 && this.vm.$destroy()
|
|
220
|
-
isVue3 && this.vm.unmount()
|
|
221
|
-
this.vm = null
|
|
222
|
-
}
|
|
223
|
-
if (root && !isActive()) {
|
|
224
|
-
root.innerHTML = ''
|
|
225
|
-
}
|
|
226
|
-
return root
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
unmount() {
|
|
230
|
-
// Teleport 模式下断开连接,并清理视图与监听
|
|
231
|
-
if (isActive()) {
|
|
232
|
-
disconnect(this.targetId(), this.props.graphModel.flowId as string)
|
|
233
|
-
}
|
|
234
|
-
this.unmountVueComponent()
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
export default VueNodeView
|