@stonecrop/node-editor 0.4.36 → 0.5.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stonecrop/node-editor",
3
- "version": "0.4.36",
3
+ "version": "0.5.0",
4
4
  "description": "Node editor UI for Stonecrop",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -36,21 +36,22 @@
36
36
  "src/*"
37
37
  ],
38
38
  "dependencies": {
39
- "@vue-flow/core": "^1.45.0",
39
+ "@vue-flow/core": "^1.47.0",
40
40
  "vue": "^3.5.22",
41
41
  "vue-router": "^4.6.3",
42
42
  "xstate": "^5.20.1"
43
43
  },
44
44
  "devDependencies": {
45
- "@microsoft/api-documenter": "^7.26.31",
46
- "@rushstack/heft": "^0.74.2",
47
- "@typescript-eslint/eslint-plugin": "^7.18.0",
48
- "@typescript-eslint/parser": "^7.18.0",
45
+ "@eslint/js": "^9.38.0",
46
+ "@microsoft/api-documenter": "^7.27.3",
47
+ "@rushstack/heft": "^1.1.3",
49
48
  "@vitejs/plugin-vue": "^6.0.1",
50
- "eslint": "^8.57.1",
51
- "eslint-config-prettier": "^8.10.0",
52
- "eslint-plugin-vue": "^9.33.0",
49
+ "eslint": "^9.38.0",
50
+ "eslint-config-prettier": "^10.1.8",
51
+ "eslint-plugin-vue": "^10.5.1",
52
+ "globals": "^16.4.0",
53
53
  "typescript": "^5.9.3",
54
+ "typescript-eslint": "^8.46.2",
54
55
  "vite": "^7.1.1",
55
56
  "stonecrop-rig": "0.2.22"
56
57
  },
@@ -66,7 +67,7 @@
66
67
  "build": "heft build && vite build && rushx docs",
67
68
  "dev": "vite",
68
69
  "docs": "cd ../common/autoinstallers/doc-tools && node generate-docs.mjs node_editor",
69
- "lint": "eslint . --ext .ts,.vue",
70
+ "lint": "eslint .",
70
71
  "preview": "vite preview"
71
72
  }
72
73
  }
@@ -14,8 +14,8 @@
14
14
  <div v-if="showInput" class="label-input-wrapper">
15
15
  <input
16
16
  ref="labelInput"
17
- class="label-input"
18
17
  v-model="newLabel"
18
+ class="label-input"
19
19
  @blur="showInput = false"
20
20
  @keypress.enter="submitNewLabel" />
21
21
  </div>
@@ -4,8 +4,8 @@
4
4
  <div v-if="showInput" class="label-input-wrapper">
5
5
  <input
6
6
  ref="labelInput"
7
- class="label-input"
8
7
  v-model="newLabel"
8
+ class="label-input"
9
9
  @blur="showInput = false"
10
10
  @keypress.enter="submitNewLabel" />
11
11
  </div>
@@ -22,11 +22,14 @@
22
22
 
23
23
  <VueFlow
24
24
  v-if="vueFlowElements && vueFlowElements.length"
25
+ v-model="vueFlowElements"
25
26
  class="nowheel"
26
27
  :prevent-scrolling="true"
27
28
  :zoom-on-scroll="false"
28
29
  :fit-view-on-init="true"
29
- v-model="vueFlowElements"
30
+ @connect="handleConnect"
31
+ @pane-ready="setInstance"
32
+ @edge-context-menu="handleEdgeContextMenu"
30
33
  @wheel.prevent="onWheel">
31
34
  <template #node-editable="props">
32
35
  <EditableNode v-bind="props" @change="labelChanged($event, props.id)" />
@@ -39,14 +42,23 @@
39
42
  </template>
40
43
 
41
44
  <script setup lang="ts">
42
- import { type VueFlowStore, Position, VueFlow, useVueFlow, Connection, Node } from '@vue-flow/core'
45
+ import {
46
+ type VueFlowStore,
47
+ Position,
48
+ VueFlow,
49
+ useVueFlow,
50
+ Connection,
51
+ Node,
52
+ EdgeMouseEvent,
53
+ DefaultEdge,
54
+ } from '@vue-flow/core'
43
55
  import { type HTMLAttributes, ref, computed, defineEmits, onBeforeUnmount, onMounted } from 'vue'
44
56
 
45
57
  import EditableEdge from './EditableEdge.vue'
46
58
  import EditableNode from './EditableNode.vue'
47
59
  import type { FlowElements } from '../types'
48
60
 
49
- const { modelValue, nodeContainerClass } = defineProps<{
61
+ const { modelValue, nodeContainerClass = '' } = defineProps<{
50
62
  modelValue: FlowElements
51
63
  nodeContainerClass?: HTMLAttributes['class']
52
64
  }>()
@@ -103,7 +115,7 @@ const elements = computed({
103
115
  emit('update:modelValue', JSON.parse(JSON.stringify(newValue)))
104
116
  },
105
117
  })
106
- const { onConnect, addEdges, onEdgeContextMenu, onPaneReady, removeEdges } = useVueFlow()
118
+ const { addEdges, removeEdges } = useVueFlow()
107
119
 
108
120
  onMounted(() => {
109
121
  document.removeEventListener('keypress', handleKeypress)
@@ -114,9 +126,9 @@ onBeforeUnmount(() => {
114
126
  document.removeEventListener('keypress', handleKeypress)
115
127
  })
116
128
 
117
- onPaneReady(instance => {
129
+ const setInstance = (instance: VueFlowStore) => {
118
130
  vueFlowInstance.value = instance
119
- })
131
+ }
120
132
 
121
133
  vueFlowElements.value = elements.value
122
134
 
@@ -133,6 +145,7 @@ const shiftTerminal = (currentTerminal: Position) => {
133
145
  const shiftOutput = () => {
134
146
  if (activeElementIndex.value > -1) {
135
147
  const activeNode = vueFlowElements.value[activeElementIndex.value] as Node
148
+ if (!activeNode.sourcePosition) return
136
149
  activeNode.sourcePosition = shiftTerminal(activeNode.sourcePosition)
137
150
  }
138
151
  }
@@ -140,6 +153,7 @@ const shiftOutput = () => {
140
153
  const shiftInput = () => {
141
154
  if (activeElementIndex.value > -1) {
142
155
  const activeNode = vueFlowElements.value[activeElementIndex.value] as Node
156
+ if (!activeNode.targetPosition) return
143
157
  activeNode.targetPosition = shiftTerminal(activeNode.targetPosition)
144
158
  }
145
159
  }
@@ -151,16 +165,16 @@ const onWheel = (event: WheelEvent) => {
151
165
  const handleKeypress = (event: KeyboardEvent) => {
152
166
  if (hover.value && event.ctrlKey == true) {
153
167
  if (event.key == '+' || event.key == '=') {
154
- void vueFlowInstance.value.zoomIn()
168
+ void vueFlowInstance.value?.zoomIn()
155
169
  }
156
170
  if (event.key == '-') {
157
- void vueFlowInstance.value.zoomOut()
171
+ void vueFlowInstance.value?.zoomOut()
158
172
  }
159
173
  }
160
174
  }
161
175
 
162
176
  const fitView = async () => {
163
- await vueFlowInstance.value.fitView()
177
+ await vueFlowInstance.value?.fitView()
164
178
  }
165
179
 
166
180
  const addNode = () => {
@@ -168,7 +182,7 @@ const addNode = () => {
168
182
  let newNodePosition = { x: Math.random() * 200, y: Math.random() * 200 }
169
183
  if (activeElementIndex.value > -1) {
170
184
  const activeNode = vueFlowElements.value[activeElementIndex.value]
171
- if (activeNode.data.hasOutput) {
185
+ if (activeNode.data?.hasOutput) {
172
186
  newNodePosition = { x: (activeNode as Node).position.x + 200, y: (activeNode as Node).position.y + 50 }
173
187
  makeEdge = true
174
188
  }
@@ -214,21 +228,21 @@ const addNode = () => {
214
228
  }
215
229
  }
216
230
 
217
- const labelChanged = (e, id) => {
231
+ const labelChanged = (event: DefaultEdge['label'], id: DefaultEdge['id']) => {
218
232
  for (let j = 0; j < vueFlowElements.value.length; j++) {
219
233
  if (vueFlowElements.value[j].id == id) {
220
- vueFlowElements.value[j].label = e
234
+ vueFlowElements.value[j].label = event
221
235
  break
222
236
  }
223
237
  }
224
238
  }
225
239
 
226
- const handleConnect = (connection: Connection) => {
240
+ const handleConnect = (event: Connection) => {
227
241
  const id = vueFlowElements.value.length
228
242
  const newEdge = {
229
243
  id: `edge-${id}`,
230
- source: connection.source,
231
- target: connection.target,
244
+ source: event.source,
245
+ target: event.target,
232
246
  type: 'editable',
233
247
  label: `New Edge`,
234
248
  interactionWidth: 400,
@@ -242,15 +256,9 @@ const handleConnect = (connection: Connection) => {
242
256
  addEdges([newEdge])
243
257
  }
244
258
 
245
- onConnect(handleConnect)
246
-
247
- const handleEdgeRemove = edgeId => {
248
- removeEdges(edgeId)
259
+ const handleEdgeContextMenu = (event: EdgeMouseEvent) => {
260
+ removeEdges(event.edge.id)
249
261
  }
250
-
251
- onEdgeContextMenu(({ event, edge }) => {
252
- handleEdgeRemove(edge.id)
253
- })
254
262
  </script>
255
263
 
256
264
  <style>
@@ -13,7 +13,7 @@ import type { EditorStates, FlowElement, FlowElements, Layout } from '../types'
13
13
 
14
14
  const emit = defineEmits(['update:modelValue'])
15
15
  const states = defineModel<EditorStates>()
16
- const { layout, nodeContainerClass } = defineProps<{
16
+ const { layout, nodeContainerClass = '' } = defineProps<{
17
17
  layout: Layout
18
18
  nodeContainerClass?: HTMLAttributes['class']
19
19
  }>()
@@ -53,7 +53,6 @@ const elements = computed<FlowElements>({
53
53
  // where 'target' can be accessed. Otherwise, 'edgeValue' will be available directly.
54
54
 
55
55
  // TODO: resolve type issues with xstate
56
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
57
56
  const target = edgeValue.target || edgeValue
58
57
  stateElements.push({
59
58
  id: `${key}-${target}`,
@@ -63,7 +62,6 @@ const elements = computed<FlowElements>({
63
62
  animated: true,
64
63
  })
65
64
 
66
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
67
65
  hasInputs[target] = true
68
66
  }
69
67
  }