@stonecrop/node-editor 0.31.0 → 0.32.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/dist/assets/index.css +430 -0
- package/dist/node-editor.js +821 -644
- package/dist/node-editor.js.map +1 -1
- package/dist/src/components/EditableEdge.vue.d.ts +11 -0
- package/dist/src/components/EditableEdge.vue.d.ts.map +1 -0
- package/dist/src/components/EditableNode.vue.d.ts +10 -0
- package/dist/src/components/EditableNode.vue.d.ts.map +1 -0
- package/dist/src/components/NodeEditor.vue.d.ts +14 -0
- package/dist/src/components/NodeEditor.vue.d.ts.map +1 -0
- package/dist/src/components/SelfLoopEdge.vue.d.ts +11 -0
- package/dist/src/components/SelfLoopEdge.vue.d.ts.map +1 -0
- package/dist/src/components/StateEditor.vue.d.ts +69 -0
- package/dist/src/components/StateEditor.vue.d.ts.map +1 -0
- package/dist/{tsdoc-metadata.json → src/tsdoc-metadata.json} +1 -1
- package/package.json +35 -28
- package/dist/node-editor.css +0 -1
- package/dist/node-editor.d.ts +0 -60
- package/dist/node_editor.tsbuildinfo +0 -1
- package/dist/src/index.js +0 -16
- package/dist/src/types/index.js +0 -0
- package/dist/src/utils/autoLayout.js +0 -50
- package/dist/src/utils/stateTransforms.js +0 -148
- package/src/components/EditableEdge.vue +0 -92
- package/src/components/EditableNode.vue +0 -65
- package/src/components/NodeEditor.vue +0 -397
- package/src/components/SelfLoopEdge.vue +0 -88
- package/src/components/StateEditor.vue +0 -46
- package/src/index.ts +0 -22
- package/src/shims-vue.d.ts +0 -5
- package/src/types/index.ts +0 -33
- package/src/utils/autoLayout.ts +0 -67
- package/src/utils/stateTransforms.ts +0 -164
package/dist/node-editor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-editor.js","sources":["../src/components/EditableEdge.vue","../src/components/EditableNode.vue","../src/components/SelfLoopEdge.vue","../src/utils/autoLayout.ts","../src/components/NodeEditor.vue","../src/utils/stateTransforms.ts","../src/components/StateEditor.vue","../src/index.ts"],"sourcesContent":["<template>\n\t<!-- transparent ghost path gives a ~20px click zone around the 2px visible stroke -->\n\t<path :d=\"path[0]\" fill=\"none\" stroke=\"transparent\" stroke-width=\"20\" class=\"vue-flow__edge-interaction\" />\n\t<path :id=\"id\" :style=\"style\" class=\"vue-flow__edge-path\" :d=\"path[0]\" :marker-end=\"markerEnd\" />\n\n\t<EdgeLabelRenderer>\n\t\t<div\n\t\t\t:style=\"{\n\t\t\t\tpointerEvents: 'all',\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttransform: `translate(-50%, -50%) translate(${path[1]}px,${path[2]}px)`,\n\t\t\t}\"\n\t\t\tclass=\"nodrag nopan editable-edge-label\"\n\t\t\t@click=\"labelOnClick()\"\n\t\t\t@contextmenu.prevent=\"$emit('remove', id)\">\n\t\t\t<div class=\"vue-flow__edge-label\">{{ label }}</div>\n\t\t\t<div v-if=\"showInput\" class=\"label-input-wrapper\">\n\t\t\t\t<input\n\t\t\t\t\tref=\"labelInput\"\n\t\t\t\t\tv-model=\"newLabel\"\n\t\t\t\t\tclass=\"label-input\"\n\t\t\t\t\t@blur=\"showInput = false\"\n\t\t\t\t\t@keypress.enter=\"submitNewLabel\" />\n\t\t\t</div>\n\t\t</div>\n\t</EdgeLabelRenderer>\n</template>\n\n<script setup lang=\"ts\">\nimport { type EdgeProps, EdgeLabelRenderer, getBezierPath /* useVueFlow */ } from '@vue-flow/core'\nimport { computed, ref, nextTick, useTemplateRef } from 'vue'\n\nconst props = defineProps<EdgeProps>()\nconst emit = defineEmits(['change', 'remove'])\n\nconst inputRef = useTemplateRef<HTMLInputElement>('labelInput')\nconst newLabel = ref<EdgeProps['label']>('')\nconst showInput = ref(false)\nlet lastClick = 0\n\nconst labelOnClick = async () => {\n\tlet now = Date.now()\n\tif (now - lastClick < 500 && !showInput.value) {\n\t\tawait showLabelInput()\n\t}\n\tlastClick = now\n}\n\nconst showLabelInput = async () => {\n\tnewLabel.value = props.label\n\tshowInput.value = true\n\tawait nextTick()\n\tinputRef.value?.focus()\n}\n\nconst submitNewLabel = () => {\n\tshowInput.value = false\n\temit('change', newLabel.value)\n}\n\nconst path = computed(() => getBezierPath(props))\n</script>\n\n<script lang=\"ts\">\nexport default {\n\tinheritAttrs: false,\n}\n</script>\n\n<style>\n.editable-edge-label {\n\tbackground-color: white;\n\tposition: relative;\n\tfont-size: 12px;\n}\n\n.label-input-wrapper {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.label-input {\n\ttext-align: center;\n\twidth: 40ch;\n}\n</style>\n","<template>\n\t<div @click=\"nodeOnClick()\">\n\t\t<div>{{ label }}</div>\n\t\t<div v-if=\"showInput\" class=\"label-input-wrapper\">\n\t\t\t<input\n\t\t\t\tref=\"labelInput\"\n\t\t\t\tv-model=\"newLabel\"\n\t\t\t\tclass=\"label-input\"\n\t\t\t\t@blur=\"showInput = false\"\n\t\t\t\t@keypress.enter=\"submitNewLabel\" />\n\t\t</div>\n\t\t<Handle v-if=\"data.hasInput\" id=\"a\" type=\"target\" :position=\"targetPosition\" />\n\t\t<Handle v-if=\"data.hasOutput\" id=\"b\" type=\"source\" :position=\"sourcePosition\" />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { NodeProps, Handle } from '@vue-flow/core'\nimport { ref, nextTick, useTemplateRef } from 'vue'\n\nconst props = defineProps<NodeProps>()\nconst emit = defineEmits(['change'])\n\nconst inputRef = useTemplateRef<HTMLInputElement>('labelInput')\nconst newLabel = ref<NodeProps['label']>('')\nconst showInput = ref(false)\nlet lastClick = 0\n\nconst nodeOnClick = async () => {\n\tlet now = Date.now()\n\tif (now - lastClick < 500 && !showInput.value) {\n\t\tawait showLabelInput()\n\t}\n\tlastClick = now\n}\n\nconst showLabelInput = async () => {\n\tnewLabel.value = props.label\n\tshowInput.value = true\n\tawait nextTick()\n\tinputRef.value?.focus()\n}\n\nconst submitNewLabel = () => {\n\tshowInput.value = false\n\temit('change', newLabel.value)\n}\n</script>\n\n<style>\n.label-input-wrapper {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.label-input {\n\ttext-align: center;\n}\n</style>\n","<template>\n\t<!-- transparent ghost path gives a ~20px click zone around the 2px visible stroke -->\n\t<path :d=\"path.d\" fill=\"none\" stroke=\"transparent\" stroke-width=\"20\" class=\"vue-flow__edge-interaction\" />\n\t<path :id=\"id\" :style=\"style\" class=\"vue-flow__edge-path\" :d=\"path.d\" :marker-end=\"markerEnd\" />\n\n\t<EdgeLabelRenderer>\n\t\t<div\n\t\t\t:style=\"{\n\t\t\t\tpointerEvents: 'all',\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttransform: `translate(-50%, -50%) translate(${path.labelX}px,${path.labelY}px)`,\n\t\t\t}\"\n\t\t\tclass=\"nodrag nopan editable-edge-label\"\n\t\t\t@click=\"labelOnClick()\"\n\t\t\t@contextmenu.prevent=\"$emit('remove', id)\">\n\t\t\t<div class=\"vue-flow__edge-label\">{{ label }}</div>\n\t\t\t<div v-if=\"showInput\" class=\"label-input-wrapper\">\n\t\t\t\t<input\n\t\t\t\t\tref=\"labelInput\"\n\t\t\t\t\tv-model=\"newLabel\"\n\t\t\t\t\tclass=\"label-input\"\n\t\t\t\t\t@blur=\"showInput = false\"\n\t\t\t\t\t@keypress.enter=\"submitNewLabel\" />\n\t\t\t</div>\n\t\t</div>\n\t</EdgeLabelRenderer>\n</template>\n\n<script setup lang=\"ts\">\nimport { type EdgeProps, EdgeLabelRenderer } from '@vue-flow/core'\nimport { computed, ref, nextTick, useTemplateRef } from 'vue'\n\nconst props = defineProps<EdgeProps>()\nconst emit = defineEmits(['change', 'remove'])\n\n// A self-loop connects a node's source handle to its own target handle. getBezierPath draws a nearly\n// straight segment across the node for that (the two handles are on the same box), so it's useless\n// here — we hand-author an arc that leaves the source handle, loops up and over the node top, and\n// returns to the target handle. LOOP_HEIGHT is how far above the handles the arc bulges.\nconst LOOP_HEIGHT = 90\nconst LOOP_SPREAD = 45\n\nconst path = computed(() => {\n\tconst { sourceX, sourceY, targetX, targetY } = props\n\tconst d = `M ${sourceX},${sourceY} C ${sourceX + LOOP_SPREAD},${sourceY - LOOP_HEIGHT} ${\n\t\ttargetX - LOOP_SPREAD\n\t},${targetY - LOOP_HEIGHT} ${targetX},${targetY}`\n\t// Place the label near the arc's apex (a cubic bezier peaks around 0.75 of the control offset).\n\tconst labelX = (sourceX + targetX) / 2\n\tconst labelY = Math.min(sourceY, targetY) - LOOP_HEIGHT * 0.72\n\treturn { d, labelX, labelY }\n})\n\nconst inputRef = useTemplateRef<HTMLInputElement>('labelInput')\nconst newLabel = ref<EdgeProps['label']>('')\nconst showInput = ref(false)\nlet lastClick = 0\n\nconst labelOnClick = async () => {\n\tlet now = Date.now()\n\tif (now - lastClick < 500 && !showInput.value) {\n\t\tawait showLabelInput()\n\t}\n\tlastClick = now\n}\n\nconst showLabelInput = async () => {\n\tnewLabel.value = props.label\n\tshowInput.value = true\n\tawait nextTick()\n\tinputRef.value?.focus()\n}\n\nconst submitNewLabel = () => {\n\tshowInput.value = false\n\temit('change', newLabel.value)\n}\n</script>\n\n<script lang=\"ts\">\nexport default {\n\tinheritAttrs: false,\n}\n</script>\n\n<style>\n/* Label + input styles are shared with EditableEdge (defined there, global scope). */\n</style>\n","import { Graph, layout } from '@dagrejs/dagre'\n\nimport type { FlowElements } from '../types'\n\n/**\n * Options for {@link autoLayout}.\n * @public\n */\nexport interface AutoLayoutOptions {\n\t/** Layout direction. Defaults to `'LR'` to match the editor's Left/Right handle defaults. */\n\trankdir?: 'LR' | 'RL' | 'TB' | 'BT'\n\t/** Fallback node width when no measured size is supplied (the seed path has no DOM to measure). */\n\tnodeWidth?: number\n\t/** Fallback node height when no measured size is supplied. */\n\tnodeHeight?: number\n\t/** Measured per-node sizes (node id → box) — supplied by the on-demand \"Auto-arrange\" button. */\n\tdimensions?: Record<string, { width: number; height: number }>\n}\n\n/**\n * Compute node positions for a workflow graph with dagre's layered (Sugiyama) algorithm.\n *\n * Pure and synchronous: takes VueFlow elements (nodes + edges) and returns a new elements array with\n * each node's `position` replaced by a laid-out coordinate; edges and every other node field are\n * passed through untouched. Used two ways — as the seed for an un-arranged workflow (fixed default\n * dimensions, no DOM) and behind the toolbar button (measured `dimensions`).\n *\n * Self-loop edges (`source === target`) are skipped: dagre doesn't rank them, and they're reserved\n * for the separate mutate-in-place self-transition feature.\n * @public\n */\nexport function autoLayout(elements: FlowElements, options: AutoLayoutOptions = {}): FlowElements {\n\tconst { rankdir = 'LR', nodeWidth = 160, nodeHeight = 40, dimensions } = options\n\tconst sizeOf = (id: string) => dimensions?.[id] ?? { width: nodeWidth, height: nodeHeight }\n\n\t// Nodes are the elements without a `source` (the same discriminator flowElementsToStates uses).\n\tconst nodeIds: string[] = []\n\tfor (const el of elements) {\n\t\tif (!('source' in el)) nodeIds.push(el.id)\n\t}\n\tif (nodeIds.length === 0) return [...elements]\n\n\tconst graph = new Graph()\n\tgraph.setGraph({ rankdir, nodesep: 40, ranksep: 80, edgesep: 20 })\n\tgraph.setDefaultEdgeLabel(() => ({}))\n\n\tfor (const id of nodeIds) {\n\t\tconst { width, height } = sizeOf(id)\n\t\tgraph.setNode(id, { width, height })\n\t}\n\tfor (const el of elements) {\n\t\tif (!('source' in el)) continue\n\t\tif (el.source === el.target) continue\n\t\tgraph.setEdge(el.source, el.target)\n\t}\n\n\tlayout(graph)\n\n\t// dagre reports each node by its CENTER; VueFlow positions nodes by their TOP-LEFT corner.\n\treturn elements.map(el => {\n\t\tif ('source' in el) return el\n\t\tconst center = graph.node(el.id)\n\t\tif (!center) return el\n\t\tconst { width, height } = sizeOf(el.id)\n\t\treturn { ...el, position: { x: center.x - width / 2, y: center.y - height / 2 } }\n\t})\n}\n","<template>\n\t<div\n\t\tclass=\"node-editor-wrapper\"\n\t\t:class=\"nodeContainerClass\"\n\t\t@contextmenu.prevent\n\t\t@mouseover=\"hover = true\"\n\t\t@mouseleave=\"hover = false\">\n\t\t<div class=\"chart-controls\">\n\t\t\t<div class=\"chart-controls-left\">\n\t\t\t\t<div><b>Selected Node:</b> {{ activeElementKey ? activeElementKey : 'none' }}</div>\n\t\t\t</div>\n\t\t\t<div class=\"chart-controls-right\">\n\t\t\t\t<div>\n\t\t\t\t\t<button class=\"button-default\" @click=\"addNode\">Add Node</button>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<button class=\"button-default\" @click=\"fitView\">Center</button>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<button class=\"button-default\" @click=\"autoArrange\">Auto-arrange</button>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"activeElementIndex > -1\">\n\t\t\t\t\t<button class=\"button-default\" @click=\"shiftInput\">Shift Input Position</button>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"activeElementIndex > -1\">\n\t\t\t\t\t<button class=\"button-default\" @click=\"shiftOutput\">Shift Output Position</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<VueFlow\n\t\t\tv-if=\"vueFlowElements && vueFlowElements.length\"\n\t\t\tv-model=\"vueFlowElements\"\n\t\t\tclass=\"nowheel\"\n\t\t\t:prevent-scrolling=\"true\"\n\t\t\t:zoom-on-scroll=\"false\"\n\t\t\t:fit-view-on-init=\"true\"\n\t\t\t:pan-activation-key-code=\"null\"\n\t\t\t@connect=\"handleConnect\"\n\t\t\t@pane-ready=\"setInstance\"\n\t\t\t@node-click=\"handleNodeClick\"\n\t\t\t@edge-click=\"handleEdgeClick\"\n\t\t\t@edge-context-menu=\"handleEdgeContextMenu\"\n\t\t\t@node-drag-stop=\"emitElements\"\n\t\t\t@wheel.prevent=\"onWheel\">\n\t\t\t<template #node-editable=\"props\">\n\t\t\t\t<EditableNode v-bind=\"props\" @change=\"labelChanged($event, props.id)\" />\n\t\t\t</template>\n\t\t\t<template #edge-editable=\"props\">\n\t\t\t\t<EditableEdge v-bind=\"props\" @change=\"labelChanged($event, props.id)\" @remove=\"removeEdge(props.id)\" />\n\t\t\t</template>\n\t\t\t<template #edge-selfloop=\"props\">\n\t\t\t\t<SelfLoopEdge v-bind=\"props\" @change=\"labelChanged($event, props.id)\" @remove=\"removeEdge(props.id)\" />\n\t\t\t</template>\n\t\t</VueFlow>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport {\n\ttype VueFlowStore,\n\tPosition,\n\tVueFlow,\n\tuseVueFlow,\n\tConnection,\n\tNode,\n\tNodeMouseEvent,\n\tEdgeMouseEvent,\n\tDefaultEdge,\n} from '@vue-flow/core'\nimport { type HTMLAttributes, ref, computed, nextTick, onBeforeUnmount, onMounted } from 'vue'\n\nimport EditableEdge from './EditableEdge.vue'\nimport EditableNode from './EditableNode.vue'\nimport SelfLoopEdge from './SelfLoopEdge.vue'\nimport { autoLayout } from '../utils/autoLayout'\nimport type { FlowElements } from '../types'\n\nconst { modelValue, nodeContainerClass = '' } = defineProps<{\n\tmodelValue: FlowElements\n\tnodeContainerClass?: HTMLAttributes['class']\n}>()\nconst emit = defineEmits(['update:modelValue'])\n\nconst hover = ref(false)\nconst vueFlowElements = ref<FlowElements>([])\nconst vueFlowInstance = ref<VueFlowStore>()\n\nconst activeElementKey = ref('')\nconst activeElementIndex = computed(() =>\n\tvueFlowElements.value.findIndex(element => element.id === activeElementKey.value)\n)\n\nconst elements = computed({\n\tget: () => {\n\t\tconst items = modelValue\n\n\t\t// Add rendering flags without clobbering caller-provided data. Edges carry `data.actionKey`\n\t\t// (the stable action identity from stateTransforms); wiping data here would drop it before it\n\t\t// round-trips back through emitElements, silently re-keying actions on every graph edit.\n\t\tfor (const element of items) {\n\t\t\telement.data = { ...element.data }\n\t\t\tif (element.type === 'input') {\n\t\t\t\telement.data.hasInput = false\n\t\t\t\telement.data.hasOutput = true\n\t\t\t} else if (element.type === 'output') {\n\t\t\t\telement.data.hasInput = true\n\t\t\t\telement.data.hasOutput = false\n\t\t\t} else {\n\t\t\t\telement.data.hasInput = true\n\t\t\t\telement.data.hasOutput = true\n\t\t\t}\n\t\t\telement.class = 'vue-flow__node-default'\n\t\t\t// A self-loop edge (source === target) routes to the SelfLoopEdge arc renderer; everything\n\t\t\t// else (nodes and cross-state edges) uses the default editable slot. getBezierPath draws a\n\t\t\t// useless near-straight segment for a self-loop, so it must not fall through to 'editable'.\n\t\t\telement.type = 'source' in element && element.source === element.target ? 'selfloop' : 'editable'\n\t\t}\n\n\t\treturn items\n\t},\n\tset: newValue => {\n\t\temit('update:modelValue', JSON.parse(JSON.stringify(newValue)))\n\t},\n})\nconst { addEdges, removeEdges } = useVueFlow()\n\nonMounted(() => {\n\tdocument.removeEventListener('keypress', handleKeypress)\n\tdocument.addEventListener('keypress', handleKeypress)\n})\n\nonBeforeUnmount(() => {\n\tdocument.removeEventListener('keypress', handleKeypress)\n})\n\nconst setInstance = (instance: VueFlowStore) => {\n\tvueFlowInstance.value = instance\n}\n\nvueFlowElements.value = elements.value\n\n// Methods\nconst shiftTerminal = (currentTerminal: Position) => {\n\treturn {\n\t\t[Position.Top]: Position.Right,\n\t\t[Position.Right]: Position.Bottom,\n\t\t[Position.Bottom]: Position.Left,\n\t\t[Position.Left]: Position.Top,\n\t}[currentTerminal]\n}\n\nconst shiftOutput = () => {\n\tif (activeElementIndex.value > -1) {\n\t\tconst activeNode = vueFlowElements.value[activeElementIndex.value] as Node\n\t\tif (!activeNode.sourcePosition) return\n\t\tactiveNode.sourcePosition = shiftTerminal(activeNode.sourcePosition)\n\t\temitElements()\n\t}\n}\n\nconst shiftInput = () => {\n\tif (activeElementIndex.value > -1) {\n\t\tconst activeNode = vueFlowElements.value[activeElementIndex.value] as Node\n\t\tif (!activeNode.targetPosition) return\n\t\tactiveNode.targetPosition = shiftTerminal(activeNode.targetPosition)\n\t\temitElements()\n\t}\n}\n\nconst onWheel = (event: WheelEvent) => {\n\twindow.scrollBy(0, event.deltaY)\n}\n\nconst handleKeypress = (event: KeyboardEvent) => {\n\tif (hover.value && event.ctrlKey == true) {\n\t\tif (event.key == '+' || event.key == '=') {\n\t\t\tvoid vueFlowInstance.value?.zoomIn()\n\t\t}\n\t\tif (event.key == '-') {\n\t\t\tvoid vueFlowInstance.value?.zoomOut()\n\t\t}\n\t}\n}\n\nconst fitView = async () => {\n\tawait vueFlowInstance.value?.fitView()\n}\n\nconst autoArrange = async () => {\n\t// Read measured node sizes from the VueFlow store so the layout fits actual box widths (state\n\t// labels differ in length); autoLayout falls back to default dimensions for any unmeasured node.\n\tconst store = vueFlowInstance.value\n\tconst dimensions: Record<string, { width: number; height: number }> = {}\n\tfor (const el of vueFlowElements.value) {\n\t\tif ('source' in el) continue\n\t\tconst dims = store?.findNode?.(el.id)?.dimensions\n\t\tif (dims?.width && dims?.height) dimensions[el.id] = { width: dims.width, height: dims.height }\n\t}\n\n\tconst laid = autoLayout(vueFlowElements.value, { dimensions })\n\tconst positionById = new Map<string, { x: number; y: number }>()\n\tfor (const el of laid) {\n\t\tif ('source' in el) continue\n\t\tpositionById.set(el.id, el.position)\n\t}\n\t// Apply positions onto the v-model elements — VueFlow reacts to these, same as shiftInput/Output.\n\tfor (const el of vueFlowElements.value) {\n\t\tif ('source' in el) continue\n\t\tconst position = positionById.get(el.id)\n\t\tif (position) el.position = position\n\t}\n\n\temitElements()\n\tawait nextTick()\n\tawait fitView()\n}\n\nconst addNode = () => {\n\tlet makeEdge = false\n\tlet newNodePosition = { x: Math.random() * 200, y: Math.random() * 200 }\n\tif (activeElementIndex.value > -1) {\n\t\tconst activeNode = vueFlowElements.value[activeElementIndex.value]\n\t\tif (activeNode.data?.hasOutput) {\n\t\t\tnewNodePosition = { x: (activeNode as Node).position.x + 200, y: (activeNode as Node).position.y + 50 }\n\t\t\tmakeEdge = true\n\t\t}\n\t}\n\n\tconst id = vueFlowElements.value.length\n\tconst nodeId = `node-${id}`\n\tvueFlowElements.value.push({\n\t\tid: nodeId,\n\t\tlabel: 'Node ' + id,\n\t\tsourcePosition: Position.Right,\n\t\ttargetPosition: Position.Left,\n\t\tclass: 'vue-flow__node-default',\n\t\ttype: 'editable',\n\t\tdata: {\n\t\t\thasInput: true,\n\t\t\thasOutput: true,\n\t\t},\n\t\tposition: newNodePosition,\n\t})\n\n\tif (makeEdge) {\n\t\tconst edgeId = `edge-${id + 1}`\n\t\tvueFlowElements.value.push({\n\t\t\tid: edgeId,\n\t\t\tsource: activeElementKey.value,\n\t\t\ttarget: nodeId,\n\t\t\ttype: 'editable',\n\t\t\tlabel: `EDGE ${id + 1}`,\n\t\t\tanimated: true,\n\t\t})\n\t}\n\temitElements()\n}\n\nconst labelChanged = (event: DefaultEdge['label'], id: DefaultEdge['id']) => {\n\tfor (let j = 0; j < vueFlowElements.value.length; j++) {\n\t\tif (vueFlowElements.value[j].id == id) {\n\t\t\tvueFlowElements.value[j].label = event\n\t\t\tbreak\n\t\t}\n\t}\n\temitElements()\n}\n\nconst handleNodeClick = ({ node }: NodeMouseEvent) => {\n\tactiveElementKey.value = node.id\n}\n\nconst handleEdgeClick = ({ edge }: EdgeMouseEvent) => {\n\tactiveElementKey.value = edge.id\n}\n\nconst handleConnect = async (event: Connection) => {\n\tconst id = vueFlowElements.value.length\n\t// A node connected to itself is a self-transition (mutate-in-place) — render it as a loop.\n\tconst isSelfLoop = event.source === event.target\n\tconst newEdge = {\n\t\tid: `edge-${id}`,\n\t\tsource: event.source,\n\t\ttarget: event.target,\n\t\ttype: isSelfLoop ? 'selfloop' : 'editable',\n\t\tlabel: `New Edge`,\n\t\tinteractionWidth: 400,\n\t\tanimated: true,\n\t}\n\taddEdges([newEdge])\n\tawait nextTick()\n\temitElements()\n}\n\nconst handleEdgeContextMenu = async (event: EdgeMouseEvent) => {\n\tremoveEdges([event.edge.id])\n\tawait nextTick()\n\temitElements()\n}\n\nconst removeEdge = async (id: string) => {\n\tremoveEdges([id])\n\tawait nextTick()\n\temitElements()\n}\n\nconst emitElements = () => {\n\temit('update:modelValue', JSON.parse(JSON.stringify(vueFlowElements.value)))\n}\n</script>\n\n<style>\n@import '@vue-flow/core/dist/style.css';\n@import '@vue-flow/core/dist/theme-default.css';\n\n.chart-controls-left,\n.chart-controls-right {\n\theight: 1.8em;\n\tdisplay: flex;\n\tflex-direction: row;\n\talign-items: center;\n\tpadding-top: 0.2em;\n}\n\n.chart-controls-right div {\n\tmargin-left: 5px;\n}\n\n.chart-controls {\n\tposition: absolute;\n\tbottom: 0.5rem;\n\tleft: 0.5rem;\n\tz-index: 10;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: flex-start;\n\tgap: 0.35rem;\n\tpadding: 0.4rem 0.5rem;\n\tbackground: rgba(255, 255, 255, 0.92);\n\tborder: 1px solid #ccc;\n\tborder-radius: 4px;\n\tbox-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);\n}\n\n.chart-controls div {\n\tmargin-bottom: 0;\n}\n\n.defaultContainerClass {\n\theight: 90vh;\n\twidth: 100%;\n\tborder: 1px solid #ccc;\n}\n\n.default-input-node.vue-flow__node-input,\n.default-output-node.vue-flow__node-output {\n\tborder-color: #000;\n}\n\n.default-input-node.vue-flow__node-input .vue-flow__handle,\n.default-output-node.vue-flow__node-output .vue-flow__handle {\n\tbackground-color: #000;\n}\n\n.default-input-node.vue-flow__node-input.selected,\n.default-output-node.vue-flow__node-output.selected {\n\tbox-shadow: 0 0 0 0.5px #000;\n}\n\nbutton.button-default {\n\tbackground-color: #ffffff;\n\tpadding: 1px 12px;\n\tborder-radius: 3px;\n\tborder: 1px solid #ccc;\n\tcursor: pointer;\n\twhite-space: nowrap;\n}\n\nbutton.button-default:hover {\n\tbackground-color: #f2f2f2;\n}\n\n.vue-flow {\n\tbackground-size: 40px 40px;\n\tbackground-image:\n\t\tlinear-gradient(to right, #ccc 1px, transparent 1px), linear-gradient(to bottom, #ccc 1px, transparent 1px);\n}\n\ninput.label-editor {\n\tposition: absolute;\n}\n\n.node-editor-wrapper {\n\tposition: relative;\n}\n</style>\n","import { Position, type Node } from '@vue-flow/core'\nimport type { ActionDefinition, WorkflowMeta } from '@stonecrop/schema'\n\nimport type { FlowElements, Layout } from '../types'\n\nexport function statesToFlowElements(workflow: WorkflowMeta, layout?: Layout): FlowElements {\n\tconst { states = [], actions = {} } = workflow\n\tconst edges: FlowElements = []\n\tconst nodes: Node[] = []\n\n\tfor (const [actionKey, actionDef] of Object.entries(actions)) {\n\t\t// Stateless commands (print/email) have no graph presence; anything graph-owned needs states.\n\t\tif (actionDef.stateless || !actionDef.allowedStates?.length) continue\n\n\t\t// A self-transition (mutate-in-place `save`) renders as a self-loop on each allowed state:\n\t\t// `source === target`, tagged `selfloop` so NodeEditor routes it to the arc renderer.\n\t\tif (actionDef.selfTransition) {\n\t\t\tfor (const source of actionDef.allowedStates) {\n\t\t\t\tedges.push({\n\t\t\t\t\tid: `${actionKey}-${source}`,\n\t\t\t\t\tsource,\n\t\t\t\t\ttarget: source,\n\t\t\t\t\tlabel: actionDef.label ?? actionKey,\n\t\t\t\t\tdata: { actionKey },\n\t\t\t\t\tanimated: true,\n\t\t\t\t\ttype: 'selfloop',\n\t\t\t\t\tinteractionWidth: 40,\n\t\t\t\t})\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// A cross-state transition needs a target; a malformed action with neither is skipped.\n\t\tif (!actionDef.nextState) continue\n\t\tfor (const source of actionDef.allowedStates) {\n\t\t\tedges.push({\n\t\t\t\tid: `${actionKey}-${source}`,\n\t\t\t\tsource,\n\t\t\t\ttarget: actionDef.nextState,\n\t\t\t\t// The edge paints the human display label; its identity (the action key) rides in\n\t\t\t\t// `data.actionKey`, so relabeling the edge renames the action without re-keying it.\n\t\t\t\tlabel: actionDef.label ?? actionKey,\n\t\t\t\tdata: { actionKey },\n\t\t\t\tanimated: true,\n\t\t\t\ttype: 'smoothstep',\n\t\t\t\tinteractionWidth: 40,\n\t\t\t})\n\t\t}\n\t}\n\n\tfor (let index = 0; index < states.length; index++) {\n\t\tconst state = states[index]\n\t\tconst node: Node = {\n\t\t\tid: state,\n\t\t\tlabel: state,\n\t\t\tposition: layout?.[state]?.position ?? { x: 200 * index, y: 100 },\n\t\t\ttargetPosition: layout?.[state]?.targetPosition ?? Position.Left,\n\t\t\tsourcePosition: layout?.[state]?.sourcePosition ?? Position.Right,\n\t\t}\n\t\t// Every state renders identically — both handles, no start-state styling — so any transition\n\t\t// (including a returning `reject`/`reopen` into the initial state) is authorable and a\n\t\t// self-loop can anchor both ends. Marking an entry state is deferred (YAGNI) until needed.\n\t\tnodes.push(node)\n\t}\n\n\treturn [...edges, ...nodes]\n}\n\nexport function flowElementsToStates(\n\tnextElements: FlowElements,\n\texistingWorkflow?: WorkflowMeta\n): { workflow: WorkflowMeta; layout: Layout } {\n\tconst idToLabel: Record<string, string> = {}\n\tconst nextLayout: Layout = {}\n\tconst stateNames: string[] = []\n\n\tfor (const el of nextElements) {\n\t\tif ('source' in el) continue\n\t\tconst label = typeof el.label === 'string' ? el.label : el.id\n\t\tidToLabel[el.id] = label\n\t\tstateNames.push(label)\n\t\tif (el.position) {\n\t\t\tnextLayout[label] = {\n\t\t\t\tposition: el.position,\n\t\t\t\t...(el.targetPosition !== undefined && { targetPosition: el.targetPosition }),\n\t\t\t\t...(el.sourcePosition !== undefined && { sourcePosition: el.sourcePosition }),\n\t\t\t}\n\t\t}\n\t}\n\n\t// Group directed edges by their stable action key. A round-tripped edge carries the key in\n\t// `data.actionKey`; a freshly-drawn edge (no data yet) falls back to its label as the key — the\n\t// one moment label and key coincide, when the action is first born. The edge's label is captured\n\t// separately as the display name, so a later relabel renames the action without re-keying it.\n\tconst transitionGroups: Record<\n\t\tstring,\n\t\t{ nextState?: string; allowedStates: string[]; label: string; selfLoop: boolean }\n\t> = {}\n\tfor (const el of nextElements) {\n\t\tif (!('source' in el)) continue\n\t\tconst edgeLabel = typeof el.label === 'string' ? el.label : el.id\n\t\tconst actionKey = el.data?.actionKey ?? edgeLabel\n\t\tconst sourceLabel = idToLabel[el.source] || el.source\n\t\tconst targetLabel = idToLabel[el.target] || el.target\n\t\t// Classify by topology, not by edge `type`: a self-loop (source === target) round-trips to a\n\t\t// self-transition regardless of how it was authored (drawn node→itself, or re-rendered from a\n\t\t// `selfTransition` action). A group's kind is set by its first edge; a multi-state self-loop\n\t\t// (e.g. `save` on Draft AND Pending) accumulates each source into allowedStates.\n\t\tconst isSelf = el.source === el.target\n\t\tif (!transitionGroups[actionKey]) {\n\t\t\ttransitionGroups[actionKey] = {\n\t\t\t\tallowedStates: [sourceLabel],\n\t\t\t\tlabel: edgeLabel,\n\t\t\t\tselfLoop: isSelf,\n\t\t\t\t...(isSelf ? {} : { nextState: targetLabel }),\n\t\t\t}\n\t\t} else {\n\t\t\ttransitionGroups[actionKey].allowedStates.push(sourceLabel)\n\t\t}\n\t}\n\n\tconst nextActions: Record<string, ActionDefinition> = {}\n\n\t// Transitions (and self-transitions) derived from graph edges\n\tfor (const [actionKey, group] of Object.entries(transitionGroups)) {\n\t\tconst existing = existingWorkflow?.actions?.[actionKey]\n\t\tnextActions[actionKey] = {\n\t\t\t// Spread existing first so every field the graph does NOT own — clientHandler,\n\t\t\t// requiredFields and any field added to ActionDefinition later — survives the\n\t\t\t// round-trip. The graph owns topology (allowedStates/nextState/selfTransition) and the\n\t\t\t// display label. (Enumerating named fields here previously dropped clientHandler.)\n\t\t\t...existing,\n\t\t\t// The edge's label is the display name (decoupled from the key). Fall back to the\n\t\t\t// existing label, then the key, if an edge ever arrives label-less.\n\t\t\tlabel: group.label || existing?.label || actionKey,\n\t\t\t// The graph owns topology only. A self-transition (self-loop) stays in place: mark\n\t\t\t// `selfTransition`, carry NO `nextState`. A cross-state transition carries `nextState`\n\t\t\t// and clears any stale self flag (a self-loop redrawn as a normal edge). Explicit\n\t\t\t// `undefined` on the unused field is dropped by JSON.stringify, so no format churn.\n\t\t\tallowedStates: group.allowedStates,\n\t\t\tnextState: group.selfLoop ? undefined : group.nextState,\n\t\t\tselfTransition: group.selfLoop ? true : undefined,\n\t\t}\n\t}\n\n\t// Pass through Verbs (stateless: true) and global Workflow actions (no allowedStates) verbatim\n\tfor (const [actionKey, actionDef] of Object.entries(existingWorkflow?.actions ?? {})) {\n\t\tif (actionKey in transitionGroups) continue\n\t\tif (actionDef.stateless || !actionDef.allowedStates?.length) {\n\t\t\tnextActions[actionKey] = actionDef\n\t\t}\n\t\t// Workflow action with allowedStates not in graph = user deleted its edges → remove\n\t}\n\n\treturn {\n\t\t// Spread existingWorkflow first so every top-level key the graph does NOT own — the\n\t\t// sibling `triggers` map (field-validation triggers), and any WorkflowMeta key added\n\t\t// later — survives the round-trip. The graph owns topology only: states + actions,\n\t\t// overridden below. (Same principle the per-action spread applies above; enumerating\n\t\t// only states+actions here previously dropped `triggers` on every graph edit.)\n\t\tworkflow: { ...existingWorkflow, states: stateNames, actions: nextActions },\n\t\tlayout: nextLayout,\n\t}\n}\n","<template>\n\t<div>\n\t\t<NodeEditor v-model=\"elements\" :node-container-class=\"nodeContainerClass\" />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { type HTMLAttributes, computed, onMounted } from 'vue'\nimport type { WorkflowMeta } from '@stonecrop/schema'\n\nimport NodeEditor from './NodeEditor.vue'\nimport type { FlowElements, Layout } from '../types'\nimport { autoLayout } from '../utils/autoLayout'\nimport { statesToFlowElements, flowElementsToStates } from '../utils/stateTransforms'\n\nconst workflow = defineModel<WorkflowMeta>()\nconst layout = defineModel<Layout>('layout')\nconst { nodeContainerClass = '' } = defineProps<{\n\tnodeContainerClass?: HTMLAttributes['class']\n}>()\n\nonMounted(() => {\n\tif (layout.value === undefined) {\n\t\tconsole.warn('[StateEditor] v-model:layout is not bound. Node position changes will not be persisted.')\n\t}\n})\n\nconst elements = computed<FlowElements>({\n\tget: () => {\n\t\tif (!workflow.value) return []\n\t\tconst els = statesToFlowElements(workflow.value, layout.value)\n\t\t// Seed an un-arranged workflow with an auto-computed dagre layout instead of the naive row.\n\t\t// Ephemeral: these positions are persisted only once the author drags a node (which routes\n\t\t// through flowElementsToStates → layout). A workflow with any saved layout keeps it as-is.\n\t\tconst noSavedLayout = !layout.value || Object.keys(layout.value).length === 0\n\t\treturn noSavedLayout ? autoLayout(els) : els\n\t},\n\tset: newValue => {\n\t\tconst { workflow: nextWorkflow, layout: nextLayout } = flowElementsToStates(newValue, workflow.value)\n\t\tworkflow.value = nextWorkflow\n\t\tif (layout.value !== undefined) {\n\t\t\tlayout.value = nextLayout\n\t\t}\n\t},\n})\n</script>\n","import { App } from 'vue'\n\nimport NodeEditor from './components/NodeEditor.vue'\nimport StateEditor from './components/StateEditor.vue'\nexport type * from './types'\n\n// `Layout` types its handle placement as this enum, so a consumer cannot fill that field without\n// naming it. It is an enum rather than a string union, which makes the obvious `'left'` a type\n// error, and @vue-flow/core is a transitive dependency a consumer should not have to add.\nexport { Position } from '@vue-flow/core'\n\n/**\n * Install all Node Editor components\n * @param app - Vue app instance\n * @public\n */\nfunction install(app: App) {\n\tapp.component('NodeEditor', NodeEditor)\n\tapp.component('StateEditor', StateEditor)\n}\n\nexport { install, NodeEditor, StateEditor }\n"],"names":["__default__","props","__props","emit","__emit","inputRef","useTemplateRef","newLabel","ref","showInput","lastClick","labelOnClick","now","showLabelInput","nextTick","submitNewLabel","path","computed","getBezierPath","_createElementVNode","_createVNode","_unref","EdgeLabelRenderer","_normalizeStyle","_cache","_withModifiers","$event","$emit","_hoisted_3","_toDisplayString","_openBlock","_createElementBlock","_hoisted_4","nodeOnClick","_hoisted_1","_createBlock","Handle","LOOP_HEIGHT","LOOP_SPREAD","sourceX","sourceY","targetX","targetY","d","labelX","labelY","autoLayout","elements","options","rankdir","nodeWidth","nodeHeight","dimensions","sizeOf","id","nodeIds","el","graph","Graph","width","height","layout","center","hover","vueFlowElements","vueFlowInstance","activeElementKey","activeElementIndex","element","items","newValue","addEdges","removeEdges","useVueFlow","onMounted","handleKeypress","onBeforeUnmount","setInstance","instance","shiftTerminal","currentTerminal","Position","shiftOutput","activeNode","emitElements","shiftInput","onWheel","event","fitView","autoArrange","store","dims","laid","positionById","position","addNode","makeEdge","newNodePosition","nodeId","edgeId","labelChanged","j","handleNodeClick","node","handleEdgeClick","edge","handleConnect","isSelfLoop","newEdge","handleEdgeContextMenu","removeEdge","_normalizeClass","_hoisted_2","_hoisted_5","VueFlow","_withCtx","EditableNode","_mergeProps","EditableEdge","SelfLoopEdge","statesToFlowElements","workflow","states","actions","edges","nodes","actionKey","actionDef","source","index","state","flowElementsToStates","nextElements","existingWorkflow","idToLabel","nextLayout","stateNames","label","transitionGroups","edgeLabel","sourceLabel","targetLabel","isSelf","nextActions","group","existing","_useModel","els","nextWorkflow","NodeEditor","install","app","StateEditor"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"node-editor.js","names":["$emit","$emit"],"sources":["../src/components/EditableEdge.vue","../src/components/EditableEdge.vue","../src/components/EditableNode.vue","../src/components/EditableNode.vue","../src/components/SelfLoopEdge.vue","../src/components/SelfLoopEdge.vue","../src/utils/autoLayout.ts","../src/components/NodeEditor.vue","../src/components/NodeEditor.vue","../src/utils/stateTransforms.ts","../src/components/StateEditor.vue","../src/components/StateEditor.vue","../src/index.ts"],"sourcesContent":["<template>\n\t<!-- transparent ghost path gives a ~20px click zone around the 2px visible stroke -->\n\t<path :d=\"path[0]\" fill=\"none\" stroke=\"transparent\" stroke-width=\"20\" class=\"vue-flow__edge-interaction\" />\n\t<path :id=\"id\" :style=\"style\" class=\"vue-flow__edge-path\" :d=\"path[0]\" :marker-end=\"markerEnd\" />\n\n\t<EdgeLabelRenderer>\n\t\t<div\n\t\t\t:style=\"{\n\t\t\t\tpointerEvents: 'all',\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttransform: `translate(-50%, -50%) translate(${path[1]}px,${path[2]}px)`,\n\t\t\t}\"\n\t\t\tclass=\"nodrag nopan editable-edge-label\"\n\t\t\t@click=\"labelOnClick()\"\n\t\t\t@contextmenu.prevent=\"$emit('remove', id)\">\n\t\t\t<div class=\"vue-flow__edge-label\">{{ label }}</div>\n\t\t\t<div v-if=\"showInput\" class=\"label-input-wrapper\">\n\t\t\t\t<input\n\t\t\t\t\tref=\"labelInput\"\n\t\t\t\t\tv-model=\"newLabel\"\n\t\t\t\t\tclass=\"label-input\"\n\t\t\t\t\t@blur=\"showInput = false\"\n\t\t\t\t\t@keypress.enter=\"submitNewLabel\" />\n\t\t\t</div>\n\t\t</div>\n\t</EdgeLabelRenderer>\n</template>\n\n<script setup lang=\"ts\">\nimport { type EdgeProps, EdgeLabelRenderer, getBezierPath /* useVueFlow */ } from '@vue-flow/core'\nimport { computed, ref, nextTick, useTemplateRef } from 'vue'\n\nconst props = defineProps<EdgeProps>()\nconst emit = defineEmits(['change', 'remove'])\n\nconst inputRef = useTemplateRef<HTMLInputElement>('labelInput')\nconst newLabel = ref<EdgeProps['label']>('')\nconst showInput = ref(false)\nlet lastClick = 0\n\nconst labelOnClick = async () => {\n\tlet now = Date.now()\n\tif (now - lastClick < 500 && !showInput.value) {\n\t\tawait showLabelInput()\n\t}\n\tlastClick = now\n}\n\nconst showLabelInput = async () => {\n\tnewLabel.value = props.label\n\tshowInput.value = true\n\tawait nextTick()\n\tinputRef.value?.focus()\n}\n\nconst submitNewLabel = () => {\n\tshowInput.value = false\n\temit('change', newLabel.value)\n}\n\nconst path = computed(() => getBezierPath(props))\n</script>\n\n<script lang=\"ts\">\nexport default {\n\tinheritAttrs: false,\n}\n</script>\n\n<style>\n.editable-edge-label {\n\tbackground-color: white;\n\tposition: relative;\n\tfont-size: 12px;\n}\n\n.label-input-wrapper {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.label-input {\n\ttext-align: center;\n\twidth: 40ch;\n}\n</style>\n","<template>\n\t<!-- transparent ghost path gives a ~20px click zone around the 2px visible stroke -->\n\t<path :d=\"path[0]\" fill=\"none\" stroke=\"transparent\" stroke-width=\"20\" class=\"vue-flow__edge-interaction\" />\n\t<path :id=\"id\" :style=\"style\" class=\"vue-flow__edge-path\" :d=\"path[0]\" :marker-end=\"markerEnd\" />\n\n\t<EdgeLabelRenderer>\n\t\t<div\n\t\t\t:style=\"{\n\t\t\t\tpointerEvents: 'all',\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttransform: `translate(-50%, -50%) translate(${path[1]}px,${path[2]}px)`,\n\t\t\t}\"\n\t\t\tclass=\"nodrag nopan editable-edge-label\"\n\t\t\t@click=\"labelOnClick()\"\n\t\t\t@contextmenu.prevent=\"$emit('remove', id)\">\n\t\t\t<div class=\"vue-flow__edge-label\">{{ label }}</div>\n\t\t\t<div v-if=\"showInput\" class=\"label-input-wrapper\">\n\t\t\t\t<input\n\t\t\t\t\tref=\"labelInput\"\n\t\t\t\t\tv-model=\"newLabel\"\n\t\t\t\t\tclass=\"label-input\"\n\t\t\t\t\t@blur=\"showInput = false\"\n\t\t\t\t\t@keypress.enter=\"submitNewLabel\" />\n\t\t\t</div>\n\t\t</div>\n\t</EdgeLabelRenderer>\n</template>\n\n<script setup lang=\"ts\">\nimport { type EdgeProps, EdgeLabelRenderer, getBezierPath /* useVueFlow */ } from '@vue-flow/core'\nimport { computed, ref, nextTick, useTemplateRef } from 'vue'\n\nconst props = defineProps<EdgeProps>()\nconst emit = defineEmits(['change', 'remove'])\n\nconst inputRef = useTemplateRef<HTMLInputElement>('labelInput')\nconst newLabel = ref<EdgeProps['label']>('')\nconst showInput = ref(false)\nlet lastClick = 0\n\nconst labelOnClick = async () => {\n\tlet now = Date.now()\n\tif (now - lastClick < 500 && !showInput.value) {\n\t\tawait showLabelInput()\n\t}\n\tlastClick = now\n}\n\nconst showLabelInput = async () => {\n\tnewLabel.value = props.label\n\tshowInput.value = true\n\tawait nextTick()\n\tinputRef.value?.focus()\n}\n\nconst submitNewLabel = () => {\n\tshowInput.value = false\n\temit('change', newLabel.value)\n}\n\nconst path = computed(() => getBezierPath(props))\n</script>\n\n<script lang=\"ts\">\nexport default {\n\tinheritAttrs: false,\n}\n</script>\n\n<style>\n.editable-edge-label {\n\tbackground-color: white;\n\tposition: relative;\n\tfont-size: 12px;\n}\n\n.label-input-wrapper {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.label-input {\n\ttext-align: center;\n\twidth: 40ch;\n}\n</style>\n","<template>\n\t<div @click=\"nodeOnClick()\">\n\t\t<div>{{ label }}</div>\n\t\t<div v-if=\"showInput\" class=\"label-input-wrapper\">\n\t\t\t<input\n\t\t\t\tref=\"labelInput\"\n\t\t\t\tv-model=\"newLabel\"\n\t\t\t\tclass=\"label-input\"\n\t\t\t\t@blur=\"showInput = false\"\n\t\t\t\t@keypress.enter=\"submitNewLabel\" />\n\t\t</div>\n\t\t<Handle v-if=\"data.hasInput\" id=\"a\" type=\"target\" :position=\"targetPosition\" />\n\t\t<Handle v-if=\"data.hasOutput\" id=\"b\" type=\"source\" :position=\"sourcePosition\" />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { NodeProps, Handle } from '@vue-flow/core'\nimport { ref, nextTick, useTemplateRef } from 'vue'\n\nconst props = defineProps<NodeProps>()\nconst emit = defineEmits(['change'])\n\nconst inputRef = useTemplateRef<HTMLInputElement>('labelInput')\nconst newLabel = ref<NodeProps['label']>('')\nconst showInput = ref(false)\nlet lastClick = 0\n\nconst nodeOnClick = async () => {\n\tlet now = Date.now()\n\tif (now - lastClick < 500 && !showInput.value) {\n\t\tawait showLabelInput()\n\t}\n\tlastClick = now\n}\n\nconst showLabelInput = async () => {\n\tnewLabel.value = props.label\n\tshowInput.value = true\n\tawait nextTick()\n\tinputRef.value?.focus()\n}\n\nconst submitNewLabel = () => {\n\tshowInput.value = false\n\temit('change', newLabel.value)\n}\n</script>\n\n<style>\n.label-input-wrapper {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.label-input {\n\ttext-align: center;\n}\n</style>\n","<template>\n\t<div @click=\"nodeOnClick()\">\n\t\t<div>{{ label }}</div>\n\t\t<div v-if=\"showInput\" class=\"label-input-wrapper\">\n\t\t\t<input\n\t\t\t\tref=\"labelInput\"\n\t\t\t\tv-model=\"newLabel\"\n\t\t\t\tclass=\"label-input\"\n\t\t\t\t@blur=\"showInput = false\"\n\t\t\t\t@keypress.enter=\"submitNewLabel\" />\n\t\t</div>\n\t\t<Handle v-if=\"data.hasInput\" id=\"a\" type=\"target\" :position=\"targetPosition\" />\n\t\t<Handle v-if=\"data.hasOutput\" id=\"b\" type=\"source\" :position=\"sourcePosition\" />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { NodeProps, Handle } from '@vue-flow/core'\nimport { ref, nextTick, useTemplateRef } from 'vue'\n\nconst props = defineProps<NodeProps>()\nconst emit = defineEmits(['change'])\n\nconst inputRef = useTemplateRef<HTMLInputElement>('labelInput')\nconst newLabel = ref<NodeProps['label']>('')\nconst showInput = ref(false)\nlet lastClick = 0\n\nconst nodeOnClick = async () => {\n\tlet now = Date.now()\n\tif (now - lastClick < 500 && !showInput.value) {\n\t\tawait showLabelInput()\n\t}\n\tlastClick = now\n}\n\nconst showLabelInput = async () => {\n\tnewLabel.value = props.label\n\tshowInput.value = true\n\tawait nextTick()\n\tinputRef.value?.focus()\n}\n\nconst submitNewLabel = () => {\n\tshowInput.value = false\n\temit('change', newLabel.value)\n}\n</script>\n\n<style>\n.label-input-wrapper {\n\tposition: absolute;\n\ttop: 0;\n\tleft: 0;\n\tright: 0;\n\tbottom: 0;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.label-input {\n\ttext-align: center;\n}\n</style>\n","<template>\n\t<!-- transparent ghost path gives a ~20px click zone around the 2px visible stroke -->\n\t<path :d=\"path.d\" fill=\"none\" stroke=\"transparent\" stroke-width=\"20\" class=\"vue-flow__edge-interaction\" />\n\t<path :id=\"id\" :style=\"style\" class=\"vue-flow__edge-path\" :d=\"path.d\" :marker-end=\"markerEnd\" />\n\n\t<EdgeLabelRenderer>\n\t\t<div\n\t\t\t:style=\"{\n\t\t\t\tpointerEvents: 'all',\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttransform: `translate(-50%, -50%) translate(${path.labelX}px,${path.labelY}px)`,\n\t\t\t}\"\n\t\t\tclass=\"nodrag nopan editable-edge-label\"\n\t\t\t@click=\"labelOnClick()\"\n\t\t\t@contextmenu.prevent=\"$emit('remove', id)\">\n\t\t\t<div class=\"vue-flow__edge-label\">{{ label }}</div>\n\t\t\t<div v-if=\"showInput\" class=\"label-input-wrapper\">\n\t\t\t\t<input\n\t\t\t\t\tref=\"labelInput\"\n\t\t\t\t\tv-model=\"newLabel\"\n\t\t\t\t\tclass=\"label-input\"\n\t\t\t\t\t@blur=\"showInput = false\"\n\t\t\t\t\t@keypress.enter=\"submitNewLabel\" />\n\t\t\t</div>\n\t\t</div>\n\t</EdgeLabelRenderer>\n</template>\n\n<script setup lang=\"ts\">\nimport { type EdgeProps, EdgeLabelRenderer } from '@vue-flow/core'\nimport { computed, ref, nextTick, useTemplateRef } from 'vue'\n\nconst props = defineProps<EdgeProps>()\nconst emit = defineEmits(['change', 'remove'])\n\n// A self-loop connects a node's source handle to its own target handle. getBezierPath draws a nearly\n// straight segment across the node for that (the two handles are on the same box), so it's useless\n// here — we hand-author an arc that leaves the source handle, loops up and over the node top, and\n// returns to the target handle. LOOP_HEIGHT is how far above the handles the arc bulges.\nconst LOOP_HEIGHT = 90\nconst LOOP_SPREAD = 45\n\nconst path = computed(() => {\n\tconst { sourceX, sourceY, targetX, targetY } = props\n\tconst d = `M ${sourceX},${sourceY} C ${sourceX + LOOP_SPREAD},${sourceY - LOOP_HEIGHT} ${\n\t\ttargetX - LOOP_SPREAD\n\t},${targetY - LOOP_HEIGHT} ${targetX},${targetY}`\n\t// Place the label near the arc's apex (a cubic bezier peaks around 0.75 of the control offset).\n\tconst labelX = (sourceX + targetX) / 2\n\tconst labelY = Math.min(sourceY, targetY) - LOOP_HEIGHT * 0.72\n\treturn { d, labelX, labelY }\n})\n\nconst inputRef = useTemplateRef<HTMLInputElement>('labelInput')\nconst newLabel = ref<EdgeProps['label']>('')\nconst showInput = ref(false)\nlet lastClick = 0\n\nconst labelOnClick = async () => {\n\tlet now = Date.now()\n\tif (now - lastClick < 500 && !showInput.value) {\n\t\tawait showLabelInput()\n\t}\n\tlastClick = now\n}\n\nconst showLabelInput = async () => {\n\tnewLabel.value = props.label\n\tshowInput.value = true\n\tawait nextTick()\n\tinputRef.value?.focus()\n}\n\nconst submitNewLabel = () => {\n\tshowInput.value = false\n\temit('change', newLabel.value)\n}\n</script>\n\n<script lang=\"ts\">\nexport default {\n\tinheritAttrs: false,\n}\n</script>\n\n<style>\n/* Label + input styles are shared with EditableEdge (defined there, global scope). */\n</style>\n","<template>\n\t<!-- transparent ghost path gives a ~20px click zone around the 2px visible stroke -->\n\t<path :d=\"path.d\" fill=\"none\" stroke=\"transparent\" stroke-width=\"20\" class=\"vue-flow__edge-interaction\" />\n\t<path :id=\"id\" :style=\"style\" class=\"vue-flow__edge-path\" :d=\"path.d\" :marker-end=\"markerEnd\" />\n\n\t<EdgeLabelRenderer>\n\t\t<div\n\t\t\t:style=\"{\n\t\t\t\tpointerEvents: 'all',\n\t\t\t\tposition: 'absolute',\n\t\t\t\ttransform: `translate(-50%, -50%) translate(${path.labelX}px,${path.labelY}px)`,\n\t\t\t}\"\n\t\t\tclass=\"nodrag nopan editable-edge-label\"\n\t\t\t@click=\"labelOnClick()\"\n\t\t\t@contextmenu.prevent=\"$emit('remove', id)\">\n\t\t\t<div class=\"vue-flow__edge-label\">{{ label }}</div>\n\t\t\t<div v-if=\"showInput\" class=\"label-input-wrapper\">\n\t\t\t\t<input\n\t\t\t\t\tref=\"labelInput\"\n\t\t\t\t\tv-model=\"newLabel\"\n\t\t\t\t\tclass=\"label-input\"\n\t\t\t\t\t@blur=\"showInput = false\"\n\t\t\t\t\t@keypress.enter=\"submitNewLabel\" />\n\t\t\t</div>\n\t\t</div>\n\t</EdgeLabelRenderer>\n</template>\n\n<script setup lang=\"ts\">\nimport { type EdgeProps, EdgeLabelRenderer } from '@vue-flow/core'\nimport { computed, ref, nextTick, useTemplateRef } from 'vue'\n\nconst props = defineProps<EdgeProps>()\nconst emit = defineEmits(['change', 'remove'])\n\n// A self-loop connects a node's source handle to its own target handle. getBezierPath draws a nearly\n// straight segment across the node for that (the two handles are on the same box), so it's useless\n// here — we hand-author an arc that leaves the source handle, loops up and over the node top, and\n// returns to the target handle. LOOP_HEIGHT is how far above the handles the arc bulges.\nconst LOOP_HEIGHT = 90\nconst LOOP_SPREAD = 45\n\nconst path = computed(() => {\n\tconst { sourceX, sourceY, targetX, targetY } = props\n\tconst d = `M ${sourceX},${sourceY} C ${sourceX + LOOP_SPREAD},${sourceY - LOOP_HEIGHT} ${\n\t\ttargetX - LOOP_SPREAD\n\t},${targetY - LOOP_HEIGHT} ${targetX},${targetY}`\n\t// Place the label near the arc's apex (a cubic bezier peaks around 0.75 of the control offset).\n\tconst labelX = (sourceX + targetX) / 2\n\tconst labelY = Math.min(sourceY, targetY) - LOOP_HEIGHT * 0.72\n\treturn { d, labelX, labelY }\n})\n\nconst inputRef = useTemplateRef<HTMLInputElement>('labelInput')\nconst newLabel = ref<EdgeProps['label']>('')\nconst showInput = ref(false)\nlet lastClick = 0\n\nconst labelOnClick = async () => {\n\tlet now = Date.now()\n\tif (now - lastClick < 500 && !showInput.value) {\n\t\tawait showLabelInput()\n\t}\n\tlastClick = now\n}\n\nconst showLabelInput = async () => {\n\tnewLabel.value = props.label\n\tshowInput.value = true\n\tawait nextTick()\n\tinputRef.value?.focus()\n}\n\nconst submitNewLabel = () => {\n\tshowInput.value = false\n\temit('change', newLabel.value)\n}\n</script>\n\n<script lang=\"ts\">\nexport default {\n\tinheritAttrs: false,\n}\n</script>\n\n<style>\n/* Label + input styles are shared with EditableEdge (defined there, global scope). */\n</style>\n","import { Graph, layout } from '@dagrejs/dagre'\n\nimport type { FlowElements } from '../types'\n\n/**\n * Options for {@link autoLayout}.\n * @public\n */\nexport interface AutoLayoutOptions {\n\t/** Layout direction. Defaults to `'LR'` to match the editor's Left/Right handle defaults. */\n\trankdir?: 'LR' | 'RL' | 'TB' | 'BT'\n\t/** Fallback node width when no measured size is supplied (the seed path has no DOM to measure). */\n\tnodeWidth?: number\n\t/** Fallback node height when no measured size is supplied. */\n\tnodeHeight?: number\n\t/** Measured per-node sizes (node id → box) — supplied by the on-demand \"Auto-arrange\" button. */\n\tdimensions?: Record<string, { width: number; height: number }>\n}\n\n/**\n * Compute node positions for a workflow graph with dagre's layered (Sugiyama) algorithm.\n *\n * Pure and synchronous: takes VueFlow elements (nodes + edges) and returns a new elements array with\n * each node's `position` replaced by a laid-out coordinate; edges and every other node field are\n * passed through untouched. Used two ways — as the seed for an un-arranged workflow (fixed default\n * dimensions, no DOM) and behind the toolbar button (measured `dimensions`).\n *\n * Self-loop edges (`source === target`) are skipped: dagre doesn't rank them, and they're reserved\n * for the separate mutate-in-place self-transition feature.\n * @public\n */\nexport function autoLayout(elements: FlowElements, options: AutoLayoutOptions = {}): FlowElements {\n\tconst { rankdir = 'LR', nodeWidth = 160, nodeHeight = 40, dimensions } = options\n\tconst sizeOf = (id: string) => dimensions?.[id] ?? { width: nodeWidth, height: nodeHeight }\n\n\t// Nodes are the elements without a `source` (the same discriminator flowElementsToStates uses).\n\tconst nodeIds: string[] = []\n\tfor (const el of elements) {\n\t\tif (!('source' in el)) nodeIds.push(el.id)\n\t}\n\tif (nodeIds.length === 0) return [...elements]\n\n\tconst graph = new Graph()\n\tgraph.setGraph({ rankdir, nodesep: 40, ranksep: 80, edgesep: 20 })\n\tgraph.setDefaultEdgeLabel(() => ({}))\n\n\tfor (const id of nodeIds) {\n\t\tconst { width, height } = sizeOf(id)\n\t\tgraph.setNode(id, { width, height })\n\t}\n\tfor (const el of elements) {\n\t\tif (!('source' in el)) continue\n\t\tif (el.source === el.target) continue\n\t\tgraph.setEdge(el.source, el.target)\n\t}\n\n\tlayout(graph)\n\n\t// dagre reports each node by its CENTER; VueFlow positions nodes by their TOP-LEFT corner.\n\treturn elements.map(el => {\n\t\tif ('source' in el) return el\n\t\tconst center = graph.node(el.id)\n\t\tif (!center) return el\n\t\tconst { width, height } = sizeOf(el.id)\n\t\treturn { ...el, position: { x: center.x - width / 2, y: center.y - height / 2 } }\n\t})\n}\n","<template>\n\t<div\n\t\tclass=\"node-editor-wrapper\"\n\t\t:class=\"nodeContainerClass\"\n\t\t@contextmenu.prevent\n\t\t@mouseover=\"hover = true\"\n\t\t@mouseleave=\"hover = false\">\n\t\t<div class=\"chart-controls\">\n\t\t\t<div class=\"chart-controls-left\">\n\t\t\t\t<div><b>Selected Node:</b> {{ activeElementKey ? activeElementKey : 'none' }}</div>\n\t\t\t</div>\n\t\t\t<div class=\"chart-controls-right\">\n\t\t\t\t<div>\n\t\t\t\t\t<button class=\"button-default\" @click=\"addNode\">Add Node</button>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<button class=\"button-default\" @click=\"fitView\">Center</button>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<button class=\"button-default\" @click=\"autoArrange\">Auto-arrange</button>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"activeElementIndex > -1\">\n\t\t\t\t\t<button class=\"button-default\" @click=\"shiftInput\">Shift Input Position</button>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"activeElementIndex > -1\">\n\t\t\t\t\t<button class=\"button-default\" @click=\"shiftOutput\">Shift Output Position</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<VueFlow\n\t\t\tv-if=\"vueFlowElements && vueFlowElements.length\"\n\t\t\tv-model=\"vueFlowElements\"\n\t\t\tclass=\"nowheel\"\n\t\t\t:prevent-scrolling=\"true\"\n\t\t\t:zoom-on-scroll=\"false\"\n\t\t\t:fit-view-on-init=\"true\"\n\t\t\t:pan-activation-key-code=\"null\"\n\t\t\t@connect=\"handleConnect\"\n\t\t\t@pane-ready=\"setInstance\"\n\t\t\t@node-click=\"handleNodeClick\"\n\t\t\t@edge-click=\"handleEdgeClick\"\n\t\t\t@edge-context-menu=\"handleEdgeContextMenu\"\n\t\t\t@node-drag-stop=\"emitElements\"\n\t\t\t@wheel.prevent=\"onWheel\">\n\t\t\t<template #node-editable=\"props\">\n\t\t\t\t<EditableNode v-bind=\"props\" @change=\"labelChanged($event, props.id)\" />\n\t\t\t</template>\n\t\t\t<template #edge-editable=\"props\">\n\t\t\t\t<EditableEdge v-bind=\"props\" @change=\"labelChanged($event, props.id)\" @remove=\"removeEdge(props.id)\" />\n\t\t\t</template>\n\t\t\t<template #edge-selfloop=\"props\">\n\t\t\t\t<SelfLoopEdge v-bind=\"props\" @change=\"labelChanged($event, props.id)\" @remove=\"removeEdge(props.id)\" />\n\t\t\t</template>\n\t\t</VueFlow>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport {\n\ttype VueFlowStore,\n\tPosition,\n\tVueFlow,\n\tuseVueFlow,\n\tConnection,\n\tNode,\n\tNodeMouseEvent,\n\tEdgeMouseEvent,\n\tDefaultEdge,\n} from '@vue-flow/core'\nimport { type HTMLAttributes, ref, computed, nextTick, onBeforeUnmount, onMounted } from 'vue'\n\nimport EditableEdge from './EditableEdge.vue'\nimport EditableNode from './EditableNode.vue'\nimport SelfLoopEdge from './SelfLoopEdge.vue'\nimport { autoLayout } from '../utils/autoLayout'\nimport type { FlowElements } from '../types'\n\nconst { modelValue, nodeContainerClass = '' } = defineProps<{\n\tmodelValue: FlowElements\n\tnodeContainerClass?: HTMLAttributes['class']\n}>()\nconst emit = defineEmits(['update:modelValue'])\n\nconst hover = ref(false)\nconst vueFlowElements = ref<FlowElements>([])\nconst vueFlowInstance = ref<VueFlowStore>()\n\nconst activeElementKey = ref('')\nconst activeElementIndex = computed(() =>\n\tvueFlowElements.value.findIndex(element => element.id === activeElementKey.value)\n)\n\nconst elements = computed({\n\tget: () => {\n\t\tconst items = modelValue\n\n\t\t// Add rendering flags without clobbering caller-provided data. Edges carry `data.actionKey`\n\t\t// (the stable action identity from stateTransforms); wiping data here would drop it before it\n\t\t// round-trips back through emitElements, silently re-keying actions on every graph edit.\n\t\tfor (const element of items) {\n\t\t\telement.data = { ...element.data }\n\t\t\tif (element.type === 'input') {\n\t\t\t\telement.data.hasInput = false\n\t\t\t\telement.data.hasOutput = true\n\t\t\t} else if (element.type === 'output') {\n\t\t\t\telement.data.hasInput = true\n\t\t\t\telement.data.hasOutput = false\n\t\t\t} else {\n\t\t\t\telement.data.hasInput = true\n\t\t\t\telement.data.hasOutput = true\n\t\t\t}\n\t\t\telement.class = 'vue-flow__node-default'\n\t\t\t// A self-loop edge (source === target) routes to the SelfLoopEdge arc renderer; everything\n\t\t\t// else (nodes and cross-state edges) uses the default editable slot. getBezierPath draws a\n\t\t\t// useless near-straight segment for a self-loop, so it must not fall through to 'editable'.\n\t\t\telement.type = 'source' in element && element.source === element.target ? 'selfloop' : 'editable'\n\t\t}\n\n\t\treturn items\n\t},\n\tset: newValue => {\n\t\temit('update:modelValue', JSON.parse(JSON.stringify(newValue)))\n\t},\n})\nconst { addEdges, removeEdges } = useVueFlow()\n\nonMounted(() => {\n\tdocument.removeEventListener('keypress', handleKeypress)\n\tdocument.addEventListener('keypress', handleKeypress)\n})\n\nonBeforeUnmount(() => {\n\tdocument.removeEventListener('keypress', handleKeypress)\n})\n\nconst setInstance = (instance: VueFlowStore) => {\n\tvueFlowInstance.value = instance\n}\n\nvueFlowElements.value = elements.value\n\n// Methods\nconst shiftTerminal = (currentTerminal: Position) => {\n\treturn {\n\t\t[Position.Top]: Position.Right,\n\t\t[Position.Right]: Position.Bottom,\n\t\t[Position.Bottom]: Position.Left,\n\t\t[Position.Left]: Position.Top,\n\t}[currentTerminal]\n}\n\nconst shiftOutput = () => {\n\tif (activeElementIndex.value > -1) {\n\t\tconst activeNode = vueFlowElements.value[activeElementIndex.value] as Node\n\t\tif (!activeNode.sourcePosition) return\n\t\tactiveNode.sourcePosition = shiftTerminal(activeNode.sourcePosition)\n\t\temitElements()\n\t}\n}\n\nconst shiftInput = () => {\n\tif (activeElementIndex.value > -1) {\n\t\tconst activeNode = vueFlowElements.value[activeElementIndex.value] as Node\n\t\tif (!activeNode.targetPosition) return\n\t\tactiveNode.targetPosition = shiftTerminal(activeNode.targetPosition)\n\t\temitElements()\n\t}\n}\n\nconst onWheel = (event: WheelEvent) => {\n\twindow.scrollBy(0, event.deltaY)\n}\n\nconst handleKeypress = (event: KeyboardEvent) => {\n\tif (hover.value && event.ctrlKey == true) {\n\t\tif (event.key == '+' || event.key == '=') {\n\t\t\tvoid vueFlowInstance.value?.zoomIn()\n\t\t}\n\t\tif (event.key == '-') {\n\t\t\tvoid vueFlowInstance.value?.zoomOut()\n\t\t}\n\t}\n}\n\nconst fitView = async () => {\n\tawait vueFlowInstance.value?.fitView()\n}\n\nconst autoArrange = async () => {\n\t// Read measured node sizes from the VueFlow store so the layout fits actual box widths (state\n\t// labels differ in length); autoLayout falls back to default dimensions for any unmeasured node.\n\tconst store = vueFlowInstance.value\n\tconst dimensions: Record<string, { width: number; height: number }> = {}\n\tfor (const el of vueFlowElements.value) {\n\t\tif ('source' in el) continue\n\t\tconst dims = store?.findNode?.(el.id)?.dimensions\n\t\tif (dims?.width && dims?.height) dimensions[el.id] = { width: dims.width, height: dims.height }\n\t}\n\n\tconst laid = autoLayout(vueFlowElements.value, { dimensions })\n\tconst positionById = new Map<string, { x: number; y: number }>()\n\tfor (const el of laid) {\n\t\tif ('source' in el) continue\n\t\tpositionById.set(el.id, el.position)\n\t}\n\t// Apply positions onto the v-model elements — VueFlow reacts to these, same as shiftInput/Output.\n\tfor (const el of vueFlowElements.value) {\n\t\tif ('source' in el) continue\n\t\tconst position = positionById.get(el.id)\n\t\tif (position) el.position = position\n\t}\n\n\temitElements()\n\tawait nextTick()\n\tawait fitView()\n}\n\nconst addNode = () => {\n\tlet makeEdge = false\n\tlet newNodePosition = { x: Math.random() * 200, y: Math.random() * 200 }\n\tif (activeElementIndex.value > -1) {\n\t\tconst activeNode = vueFlowElements.value[activeElementIndex.value]\n\t\tif (activeNode.data?.hasOutput) {\n\t\t\tnewNodePosition = { x: (activeNode as Node).position.x + 200, y: (activeNode as Node).position.y + 50 }\n\t\t\tmakeEdge = true\n\t\t}\n\t}\n\n\tconst id = vueFlowElements.value.length\n\tconst nodeId = `node-${id}`\n\tvueFlowElements.value.push({\n\t\tid: nodeId,\n\t\tlabel: 'Node ' + id,\n\t\tsourcePosition: Position.Right,\n\t\ttargetPosition: Position.Left,\n\t\tclass: 'vue-flow__node-default',\n\t\ttype: 'editable',\n\t\tdata: {\n\t\t\thasInput: true,\n\t\t\thasOutput: true,\n\t\t},\n\t\tposition: newNodePosition,\n\t})\n\n\tif (makeEdge) {\n\t\tconst edgeId = `edge-${id + 1}`\n\t\tvueFlowElements.value.push({\n\t\t\tid: edgeId,\n\t\t\tsource: activeElementKey.value,\n\t\t\ttarget: nodeId,\n\t\t\ttype: 'editable',\n\t\t\tlabel: `EDGE ${id + 1}`,\n\t\t\tanimated: true,\n\t\t})\n\t}\n\temitElements()\n}\n\nconst labelChanged = (event: DefaultEdge['label'], id: DefaultEdge['id']) => {\n\tfor (let j = 0; j < vueFlowElements.value.length; j++) {\n\t\tif (vueFlowElements.value[j].id == id) {\n\t\t\tvueFlowElements.value[j].label = event\n\t\t\tbreak\n\t\t}\n\t}\n\temitElements()\n}\n\nconst handleNodeClick = ({ node }: NodeMouseEvent) => {\n\tactiveElementKey.value = node.id\n}\n\nconst handleEdgeClick = ({ edge }: EdgeMouseEvent) => {\n\tactiveElementKey.value = edge.id\n}\n\nconst handleConnect = async (event: Connection) => {\n\tconst id = vueFlowElements.value.length\n\t// A node connected to itself is a self-transition (mutate-in-place) — render it as a loop.\n\tconst isSelfLoop = event.source === event.target\n\tconst newEdge = {\n\t\tid: `edge-${id}`,\n\t\tsource: event.source,\n\t\ttarget: event.target,\n\t\ttype: isSelfLoop ? 'selfloop' : 'editable',\n\t\tlabel: `New Edge`,\n\t\tinteractionWidth: 400,\n\t\tanimated: true,\n\t}\n\taddEdges([newEdge])\n\tawait nextTick()\n\temitElements()\n}\n\nconst handleEdgeContextMenu = async (event: EdgeMouseEvent) => {\n\tremoveEdges([event.edge.id])\n\tawait nextTick()\n\temitElements()\n}\n\nconst removeEdge = async (id: string) => {\n\tremoveEdges([id])\n\tawait nextTick()\n\temitElements()\n}\n\nconst emitElements = () => {\n\temit('update:modelValue', JSON.parse(JSON.stringify(vueFlowElements.value)))\n}\n</script>\n\n<style>\n@import '@vue-flow/core/dist/style.css';\n@import '@vue-flow/core/dist/theme-default.css';\n\n.chart-controls-left,\n.chart-controls-right {\n\theight: 1.8em;\n\tdisplay: flex;\n\tflex-direction: row;\n\talign-items: center;\n\tpadding-top: 0.2em;\n}\n\n.chart-controls-right div {\n\tmargin-left: 5px;\n}\n\n.chart-controls {\n\tposition: absolute;\n\tbottom: 0.5rem;\n\tleft: 0.5rem;\n\tz-index: 10;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: flex-start;\n\tgap: 0.35rem;\n\tpadding: 0.4rem 0.5rem;\n\tbackground: rgba(255, 255, 255, 0.92);\n\tborder: 1px solid #ccc;\n\tborder-radius: 4px;\n\tbox-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);\n}\n\n.chart-controls div {\n\tmargin-bottom: 0;\n}\n\n.defaultContainerClass {\n\theight: 90vh;\n\twidth: 100%;\n\tborder: 1px solid #ccc;\n}\n\n.default-input-node.vue-flow__node-input,\n.default-output-node.vue-flow__node-output {\n\tborder-color: #000;\n}\n\n.default-input-node.vue-flow__node-input .vue-flow__handle,\n.default-output-node.vue-flow__node-output .vue-flow__handle {\n\tbackground-color: #000;\n}\n\n.default-input-node.vue-flow__node-input.selected,\n.default-output-node.vue-flow__node-output.selected {\n\tbox-shadow: 0 0 0 0.5px #000;\n}\n\nbutton.button-default {\n\tbackground-color: #ffffff;\n\tpadding: 1px 12px;\n\tborder-radius: 3px;\n\tborder: 1px solid #ccc;\n\tcursor: pointer;\n\twhite-space: nowrap;\n}\n\nbutton.button-default:hover {\n\tbackground-color: #f2f2f2;\n}\n\n.vue-flow {\n\tbackground-size: 40px 40px;\n\tbackground-image:\n\t\tlinear-gradient(to right, #ccc 1px, transparent 1px), linear-gradient(to bottom, #ccc 1px, transparent 1px);\n}\n\ninput.label-editor {\n\tposition: absolute;\n}\n\n.node-editor-wrapper {\n\tposition: relative;\n}\n</style>\n","<template>\n\t<div\n\t\tclass=\"node-editor-wrapper\"\n\t\t:class=\"nodeContainerClass\"\n\t\t@contextmenu.prevent\n\t\t@mouseover=\"hover = true\"\n\t\t@mouseleave=\"hover = false\">\n\t\t<div class=\"chart-controls\">\n\t\t\t<div class=\"chart-controls-left\">\n\t\t\t\t<div><b>Selected Node:</b> {{ activeElementKey ? activeElementKey : 'none' }}</div>\n\t\t\t</div>\n\t\t\t<div class=\"chart-controls-right\">\n\t\t\t\t<div>\n\t\t\t\t\t<button class=\"button-default\" @click=\"addNode\">Add Node</button>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<button class=\"button-default\" @click=\"fitView\">Center</button>\n\t\t\t\t</div>\n\t\t\t\t<div>\n\t\t\t\t\t<button class=\"button-default\" @click=\"autoArrange\">Auto-arrange</button>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"activeElementIndex > -1\">\n\t\t\t\t\t<button class=\"button-default\" @click=\"shiftInput\">Shift Input Position</button>\n\t\t\t\t</div>\n\t\t\t\t<div v-if=\"activeElementIndex > -1\">\n\t\t\t\t\t<button class=\"button-default\" @click=\"shiftOutput\">Shift Output Position</button>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t</div>\n\n\t\t<VueFlow\n\t\t\tv-if=\"vueFlowElements && vueFlowElements.length\"\n\t\t\tv-model=\"vueFlowElements\"\n\t\t\tclass=\"nowheel\"\n\t\t\t:prevent-scrolling=\"true\"\n\t\t\t:zoom-on-scroll=\"false\"\n\t\t\t:fit-view-on-init=\"true\"\n\t\t\t:pan-activation-key-code=\"null\"\n\t\t\t@connect=\"handleConnect\"\n\t\t\t@pane-ready=\"setInstance\"\n\t\t\t@node-click=\"handleNodeClick\"\n\t\t\t@edge-click=\"handleEdgeClick\"\n\t\t\t@edge-context-menu=\"handleEdgeContextMenu\"\n\t\t\t@node-drag-stop=\"emitElements\"\n\t\t\t@wheel.prevent=\"onWheel\">\n\t\t\t<template #node-editable=\"props\">\n\t\t\t\t<EditableNode v-bind=\"props\" @change=\"labelChanged($event, props.id)\" />\n\t\t\t</template>\n\t\t\t<template #edge-editable=\"props\">\n\t\t\t\t<EditableEdge v-bind=\"props\" @change=\"labelChanged($event, props.id)\" @remove=\"removeEdge(props.id)\" />\n\t\t\t</template>\n\t\t\t<template #edge-selfloop=\"props\">\n\t\t\t\t<SelfLoopEdge v-bind=\"props\" @change=\"labelChanged($event, props.id)\" @remove=\"removeEdge(props.id)\" />\n\t\t\t</template>\n\t\t</VueFlow>\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport {\n\ttype VueFlowStore,\n\tPosition,\n\tVueFlow,\n\tuseVueFlow,\n\tConnection,\n\tNode,\n\tNodeMouseEvent,\n\tEdgeMouseEvent,\n\tDefaultEdge,\n} from '@vue-flow/core'\nimport { type HTMLAttributes, ref, computed, nextTick, onBeforeUnmount, onMounted } from 'vue'\n\nimport EditableEdge from './EditableEdge.vue'\nimport EditableNode from './EditableNode.vue'\nimport SelfLoopEdge from './SelfLoopEdge.vue'\nimport { autoLayout } from '../utils/autoLayout'\nimport type { FlowElements } from '../types'\n\nconst { modelValue, nodeContainerClass = '' } = defineProps<{\n\tmodelValue: FlowElements\n\tnodeContainerClass?: HTMLAttributes['class']\n}>()\nconst emit = defineEmits(['update:modelValue'])\n\nconst hover = ref(false)\nconst vueFlowElements = ref<FlowElements>([])\nconst vueFlowInstance = ref<VueFlowStore>()\n\nconst activeElementKey = ref('')\nconst activeElementIndex = computed(() =>\n\tvueFlowElements.value.findIndex(element => element.id === activeElementKey.value)\n)\n\nconst elements = computed({\n\tget: () => {\n\t\tconst items = modelValue\n\n\t\t// Add rendering flags without clobbering caller-provided data. Edges carry `data.actionKey`\n\t\t// (the stable action identity from stateTransforms); wiping data here would drop it before it\n\t\t// round-trips back through emitElements, silently re-keying actions on every graph edit.\n\t\tfor (const element of items) {\n\t\t\telement.data = { ...element.data }\n\t\t\tif (element.type === 'input') {\n\t\t\t\telement.data.hasInput = false\n\t\t\t\telement.data.hasOutput = true\n\t\t\t} else if (element.type === 'output') {\n\t\t\t\telement.data.hasInput = true\n\t\t\t\telement.data.hasOutput = false\n\t\t\t} else {\n\t\t\t\telement.data.hasInput = true\n\t\t\t\telement.data.hasOutput = true\n\t\t\t}\n\t\t\telement.class = 'vue-flow__node-default'\n\t\t\t// A self-loop edge (source === target) routes to the SelfLoopEdge arc renderer; everything\n\t\t\t// else (nodes and cross-state edges) uses the default editable slot. getBezierPath draws a\n\t\t\t// useless near-straight segment for a self-loop, so it must not fall through to 'editable'.\n\t\t\telement.type = 'source' in element && element.source === element.target ? 'selfloop' : 'editable'\n\t\t}\n\n\t\treturn items\n\t},\n\tset: newValue => {\n\t\temit('update:modelValue', JSON.parse(JSON.stringify(newValue)))\n\t},\n})\nconst { addEdges, removeEdges } = useVueFlow()\n\nonMounted(() => {\n\tdocument.removeEventListener('keypress', handleKeypress)\n\tdocument.addEventListener('keypress', handleKeypress)\n})\n\nonBeforeUnmount(() => {\n\tdocument.removeEventListener('keypress', handleKeypress)\n})\n\nconst setInstance = (instance: VueFlowStore) => {\n\tvueFlowInstance.value = instance\n}\n\nvueFlowElements.value = elements.value\n\n// Methods\nconst shiftTerminal = (currentTerminal: Position) => {\n\treturn {\n\t\t[Position.Top]: Position.Right,\n\t\t[Position.Right]: Position.Bottom,\n\t\t[Position.Bottom]: Position.Left,\n\t\t[Position.Left]: Position.Top,\n\t}[currentTerminal]\n}\n\nconst shiftOutput = () => {\n\tif (activeElementIndex.value > -1) {\n\t\tconst activeNode = vueFlowElements.value[activeElementIndex.value] as Node\n\t\tif (!activeNode.sourcePosition) return\n\t\tactiveNode.sourcePosition = shiftTerminal(activeNode.sourcePosition)\n\t\temitElements()\n\t}\n}\n\nconst shiftInput = () => {\n\tif (activeElementIndex.value > -1) {\n\t\tconst activeNode = vueFlowElements.value[activeElementIndex.value] as Node\n\t\tif (!activeNode.targetPosition) return\n\t\tactiveNode.targetPosition = shiftTerminal(activeNode.targetPosition)\n\t\temitElements()\n\t}\n}\n\nconst onWheel = (event: WheelEvent) => {\n\twindow.scrollBy(0, event.deltaY)\n}\n\nconst handleKeypress = (event: KeyboardEvent) => {\n\tif (hover.value && event.ctrlKey == true) {\n\t\tif (event.key == '+' || event.key == '=') {\n\t\t\tvoid vueFlowInstance.value?.zoomIn()\n\t\t}\n\t\tif (event.key == '-') {\n\t\t\tvoid vueFlowInstance.value?.zoomOut()\n\t\t}\n\t}\n}\n\nconst fitView = async () => {\n\tawait vueFlowInstance.value?.fitView()\n}\n\nconst autoArrange = async () => {\n\t// Read measured node sizes from the VueFlow store so the layout fits actual box widths (state\n\t// labels differ in length); autoLayout falls back to default dimensions for any unmeasured node.\n\tconst store = vueFlowInstance.value\n\tconst dimensions: Record<string, { width: number; height: number }> = {}\n\tfor (const el of vueFlowElements.value) {\n\t\tif ('source' in el) continue\n\t\tconst dims = store?.findNode?.(el.id)?.dimensions\n\t\tif (dims?.width && dims?.height) dimensions[el.id] = { width: dims.width, height: dims.height }\n\t}\n\n\tconst laid = autoLayout(vueFlowElements.value, { dimensions })\n\tconst positionById = new Map<string, { x: number; y: number }>()\n\tfor (const el of laid) {\n\t\tif ('source' in el) continue\n\t\tpositionById.set(el.id, el.position)\n\t}\n\t// Apply positions onto the v-model elements — VueFlow reacts to these, same as shiftInput/Output.\n\tfor (const el of vueFlowElements.value) {\n\t\tif ('source' in el) continue\n\t\tconst position = positionById.get(el.id)\n\t\tif (position) el.position = position\n\t}\n\n\temitElements()\n\tawait nextTick()\n\tawait fitView()\n}\n\nconst addNode = () => {\n\tlet makeEdge = false\n\tlet newNodePosition = { x: Math.random() * 200, y: Math.random() * 200 }\n\tif (activeElementIndex.value > -1) {\n\t\tconst activeNode = vueFlowElements.value[activeElementIndex.value]\n\t\tif (activeNode.data?.hasOutput) {\n\t\t\tnewNodePosition = { x: (activeNode as Node).position.x + 200, y: (activeNode as Node).position.y + 50 }\n\t\t\tmakeEdge = true\n\t\t}\n\t}\n\n\tconst id = vueFlowElements.value.length\n\tconst nodeId = `node-${id}`\n\tvueFlowElements.value.push({\n\t\tid: nodeId,\n\t\tlabel: 'Node ' + id,\n\t\tsourcePosition: Position.Right,\n\t\ttargetPosition: Position.Left,\n\t\tclass: 'vue-flow__node-default',\n\t\ttype: 'editable',\n\t\tdata: {\n\t\t\thasInput: true,\n\t\t\thasOutput: true,\n\t\t},\n\t\tposition: newNodePosition,\n\t})\n\n\tif (makeEdge) {\n\t\tconst edgeId = `edge-${id + 1}`\n\t\tvueFlowElements.value.push({\n\t\t\tid: edgeId,\n\t\t\tsource: activeElementKey.value,\n\t\t\ttarget: nodeId,\n\t\t\ttype: 'editable',\n\t\t\tlabel: `EDGE ${id + 1}`,\n\t\t\tanimated: true,\n\t\t})\n\t}\n\temitElements()\n}\n\nconst labelChanged = (event: DefaultEdge['label'], id: DefaultEdge['id']) => {\n\tfor (let j = 0; j < vueFlowElements.value.length; j++) {\n\t\tif (vueFlowElements.value[j].id == id) {\n\t\t\tvueFlowElements.value[j].label = event\n\t\t\tbreak\n\t\t}\n\t}\n\temitElements()\n}\n\nconst handleNodeClick = ({ node }: NodeMouseEvent) => {\n\tactiveElementKey.value = node.id\n}\n\nconst handleEdgeClick = ({ edge }: EdgeMouseEvent) => {\n\tactiveElementKey.value = edge.id\n}\n\nconst handleConnect = async (event: Connection) => {\n\tconst id = vueFlowElements.value.length\n\t// A node connected to itself is a self-transition (mutate-in-place) — render it as a loop.\n\tconst isSelfLoop = event.source === event.target\n\tconst newEdge = {\n\t\tid: `edge-${id}`,\n\t\tsource: event.source,\n\t\ttarget: event.target,\n\t\ttype: isSelfLoop ? 'selfloop' : 'editable',\n\t\tlabel: `New Edge`,\n\t\tinteractionWidth: 400,\n\t\tanimated: true,\n\t}\n\taddEdges([newEdge])\n\tawait nextTick()\n\temitElements()\n}\n\nconst handleEdgeContextMenu = async (event: EdgeMouseEvent) => {\n\tremoveEdges([event.edge.id])\n\tawait nextTick()\n\temitElements()\n}\n\nconst removeEdge = async (id: string) => {\n\tremoveEdges([id])\n\tawait nextTick()\n\temitElements()\n}\n\nconst emitElements = () => {\n\temit('update:modelValue', JSON.parse(JSON.stringify(vueFlowElements.value)))\n}\n</script>\n\n<style>\n@import '@vue-flow/core/dist/style.css';\n@import '@vue-flow/core/dist/theme-default.css';\n\n.chart-controls-left,\n.chart-controls-right {\n\theight: 1.8em;\n\tdisplay: flex;\n\tflex-direction: row;\n\talign-items: center;\n\tpadding-top: 0.2em;\n}\n\n.chart-controls-right div {\n\tmargin-left: 5px;\n}\n\n.chart-controls {\n\tposition: absolute;\n\tbottom: 0.5rem;\n\tleft: 0.5rem;\n\tz-index: 10;\n\tdisplay: flex;\n\tflex-direction: column;\n\talign-items: flex-start;\n\tgap: 0.35rem;\n\tpadding: 0.4rem 0.5rem;\n\tbackground: rgba(255, 255, 255, 0.92);\n\tborder: 1px solid #ccc;\n\tborder-radius: 4px;\n\tbox-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);\n}\n\n.chart-controls div {\n\tmargin-bottom: 0;\n}\n\n.defaultContainerClass {\n\theight: 90vh;\n\twidth: 100%;\n\tborder: 1px solid #ccc;\n}\n\n.default-input-node.vue-flow__node-input,\n.default-output-node.vue-flow__node-output {\n\tborder-color: #000;\n}\n\n.default-input-node.vue-flow__node-input .vue-flow__handle,\n.default-output-node.vue-flow__node-output .vue-flow__handle {\n\tbackground-color: #000;\n}\n\n.default-input-node.vue-flow__node-input.selected,\n.default-output-node.vue-flow__node-output.selected {\n\tbox-shadow: 0 0 0 0.5px #000;\n}\n\nbutton.button-default {\n\tbackground-color: #ffffff;\n\tpadding: 1px 12px;\n\tborder-radius: 3px;\n\tborder: 1px solid #ccc;\n\tcursor: pointer;\n\twhite-space: nowrap;\n}\n\nbutton.button-default:hover {\n\tbackground-color: #f2f2f2;\n}\n\n.vue-flow {\n\tbackground-size: 40px 40px;\n\tbackground-image:\n\t\tlinear-gradient(to right, #ccc 1px, transparent 1px), linear-gradient(to bottom, #ccc 1px, transparent 1px);\n}\n\ninput.label-editor {\n\tposition: absolute;\n}\n\n.node-editor-wrapper {\n\tposition: relative;\n}\n</style>\n","import { Position, type Node } from '@vue-flow/core'\nimport type { ActionDefinition, WorkflowMeta } from '@stonecrop/schema'\n\nimport type { FlowElements, Layout } from '../types'\n\nexport function statesToFlowElements(workflow: WorkflowMeta, layout?: Layout): FlowElements {\n\tconst { states = [], actions = {} } = workflow\n\tconst edges: FlowElements = []\n\tconst nodes: Node[] = []\n\n\tfor (const [actionKey, actionDef] of Object.entries(actions)) {\n\t\t// Stateless commands (print/email) have no graph presence; anything graph-owned needs states.\n\t\tif (actionDef.stateless || !actionDef.allowedStates?.length) continue\n\n\t\t// A self-transition (mutate-in-place `save`) renders as a self-loop on each allowed state:\n\t\t// `source === target`, tagged `selfloop` so NodeEditor routes it to the arc renderer.\n\t\tif (actionDef.selfTransition) {\n\t\t\tfor (const source of actionDef.allowedStates) {\n\t\t\t\tedges.push({\n\t\t\t\t\tid: `${actionKey}-${source}`,\n\t\t\t\t\tsource,\n\t\t\t\t\ttarget: source,\n\t\t\t\t\tlabel: actionDef.label ?? actionKey,\n\t\t\t\t\tdata: { actionKey },\n\t\t\t\t\tanimated: true,\n\t\t\t\t\ttype: 'selfloop',\n\t\t\t\t\tinteractionWidth: 40,\n\t\t\t\t})\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\t// A cross-state transition needs a target; a malformed action with neither is skipped.\n\t\tif (!actionDef.nextState) continue\n\t\tfor (const source of actionDef.allowedStates) {\n\t\t\tedges.push({\n\t\t\t\tid: `${actionKey}-${source}`,\n\t\t\t\tsource,\n\t\t\t\ttarget: actionDef.nextState,\n\t\t\t\t// The edge paints the human display label; its identity (the action key) rides in\n\t\t\t\t// `data.actionKey`, so relabeling the edge renames the action without re-keying it.\n\t\t\t\tlabel: actionDef.label ?? actionKey,\n\t\t\t\tdata: { actionKey },\n\t\t\t\tanimated: true,\n\t\t\t\ttype: 'smoothstep',\n\t\t\t\tinteractionWidth: 40,\n\t\t\t})\n\t\t}\n\t}\n\n\tfor (let index = 0; index < states.length; index++) {\n\t\tconst state = states[index]\n\t\tconst node: Node = {\n\t\t\tid: state,\n\t\t\tlabel: state,\n\t\t\tposition: layout?.[state]?.position ?? { x: 200 * index, y: 100 },\n\t\t\ttargetPosition: layout?.[state]?.targetPosition ?? Position.Left,\n\t\t\tsourcePosition: layout?.[state]?.sourcePosition ?? Position.Right,\n\t\t}\n\t\t// Every state renders identically — both handles, no start-state styling — so any transition\n\t\t// (including a returning `reject`/`reopen` into the initial state) is authorable and a\n\t\t// self-loop can anchor both ends. Marking an entry state is deferred (YAGNI) until needed.\n\t\tnodes.push(node)\n\t}\n\n\treturn [...edges, ...nodes]\n}\n\nexport function flowElementsToStates(\n\tnextElements: FlowElements,\n\texistingWorkflow?: WorkflowMeta\n): { workflow: WorkflowMeta; layout: Layout } {\n\tconst idToLabel: Record<string, string> = {}\n\tconst nextLayout: Layout = {}\n\tconst stateNames: string[] = []\n\n\tfor (const el of nextElements) {\n\t\tif ('source' in el) continue\n\t\tconst label = typeof el.label === 'string' ? el.label : el.id\n\t\tidToLabel[el.id] = label\n\t\tstateNames.push(label)\n\t\tif (el.position) {\n\t\t\tnextLayout[label] = {\n\t\t\t\tposition: el.position,\n\t\t\t\t...(el.targetPosition !== undefined && { targetPosition: el.targetPosition }),\n\t\t\t\t...(el.sourcePosition !== undefined && { sourcePosition: el.sourcePosition }),\n\t\t\t}\n\t\t}\n\t}\n\n\t// Group directed edges by their stable action key. A round-tripped edge carries the key in\n\t// `data.actionKey`; a freshly-drawn edge (no data yet) falls back to its label as the key — the\n\t// one moment label and key coincide, when the action is first born. The edge's label is captured\n\t// separately as the display name, so a later relabel renames the action without re-keying it.\n\tconst transitionGroups: Record<\n\t\tstring,\n\t\t{ nextState?: string; allowedStates: string[]; label: string; selfLoop: boolean }\n\t> = {}\n\tfor (const el of nextElements) {\n\t\tif (!('source' in el)) continue\n\t\tconst edgeLabel = typeof el.label === 'string' ? el.label : el.id\n\t\tconst actionKey = el.data?.actionKey ?? edgeLabel\n\t\tconst sourceLabel = idToLabel[el.source] || el.source\n\t\tconst targetLabel = idToLabel[el.target] || el.target\n\t\t// Classify by topology, not by edge `type`: a self-loop (source === target) round-trips to a\n\t\t// self-transition regardless of how it was authored (drawn node→itself, or re-rendered from a\n\t\t// `selfTransition` action). A group's kind is set by its first edge; a multi-state self-loop\n\t\t// (e.g. `save` on Draft AND Pending) accumulates each source into allowedStates.\n\t\tconst isSelf = el.source === el.target\n\t\tif (!transitionGroups[actionKey]) {\n\t\t\ttransitionGroups[actionKey] = {\n\t\t\t\tallowedStates: [sourceLabel],\n\t\t\t\tlabel: edgeLabel,\n\t\t\t\tselfLoop: isSelf,\n\t\t\t\t...(isSelf ? {} : { nextState: targetLabel }),\n\t\t\t}\n\t\t} else {\n\t\t\ttransitionGroups[actionKey].allowedStates.push(sourceLabel)\n\t\t}\n\t}\n\n\tconst nextActions: Record<string, ActionDefinition> = {}\n\n\t// Transitions (and self-transitions) derived from graph edges\n\tfor (const [actionKey, group] of Object.entries(transitionGroups)) {\n\t\tconst existing = existingWorkflow?.actions?.[actionKey]\n\t\tnextActions[actionKey] = {\n\t\t\t// Spread existing first so every field the graph does NOT own — clientHandler,\n\t\t\t// requiredFields and any field added to ActionDefinition later — survives the\n\t\t\t// round-trip. The graph owns topology (allowedStates/nextState/selfTransition) and the\n\t\t\t// display label. (Enumerating named fields here previously dropped clientHandler.)\n\t\t\t...existing,\n\t\t\t// The edge's label is the display name (decoupled from the key). Fall back to the\n\t\t\t// existing label, then the key, if an edge ever arrives label-less.\n\t\t\tlabel: group.label || existing?.label || actionKey,\n\t\t\t// The graph owns topology only. A self-transition (self-loop) stays in place: mark\n\t\t\t// `selfTransition`, carry NO `nextState`. A cross-state transition carries `nextState`\n\t\t\t// and clears any stale self flag (a self-loop redrawn as a normal edge). Explicit\n\t\t\t// `undefined` on the unused field is dropped by JSON.stringify, so no format churn.\n\t\t\tallowedStates: group.allowedStates,\n\t\t\tnextState: group.selfLoop ? undefined : group.nextState,\n\t\t\tselfTransition: group.selfLoop ? true : undefined,\n\t\t}\n\t}\n\n\t// Pass through Verbs (stateless: true) and global Workflow actions (no allowedStates) verbatim\n\tfor (const [actionKey, actionDef] of Object.entries(existingWorkflow?.actions ?? {})) {\n\t\tif (actionKey in transitionGroups) continue\n\t\tif (actionDef.stateless || !actionDef.allowedStates?.length) {\n\t\t\tnextActions[actionKey] = actionDef\n\t\t}\n\t\t// Workflow action with allowedStates not in graph = user deleted its edges → remove\n\t}\n\n\treturn {\n\t\t// Spread existingWorkflow first so every top-level key the graph does NOT own — the\n\t\t// sibling `triggers` map (field-validation triggers), and any WorkflowMeta key added\n\t\t// later — survives the round-trip. The graph owns topology only: states + actions,\n\t\t// overridden below. (Same principle the per-action spread applies above; enumerating\n\t\t// only states+actions here previously dropped `triggers` on every graph edit.)\n\t\tworkflow: { ...existingWorkflow, states: stateNames, actions: nextActions },\n\t\tlayout: nextLayout,\n\t}\n}\n","<template>\n\t<div>\n\t\t<NodeEditor v-model=\"elements\" :node-container-class=\"nodeContainerClass\" />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { type HTMLAttributes, computed, onMounted } from 'vue'\nimport type { WorkflowMeta } from '@stonecrop/schema'\n\nimport NodeEditor from './NodeEditor.vue'\nimport type { FlowElements, Layout } from '../types'\nimport { autoLayout } from '../utils/autoLayout'\nimport { statesToFlowElements, flowElementsToStates } from '../utils/stateTransforms'\n\nconst workflow = defineModel<WorkflowMeta>()\nconst layout = defineModel<Layout>('layout')\nconst { nodeContainerClass = '' } = defineProps<{\n\tnodeContainerClass?: HTMLAttributes['class']\n}>()\n\nonMounted(() => {\n\tif (layout.value === undefined) {\n\t\tconsole.warn('[StateEditor] v-model:layout is not bound. Node position changes will not be persisted.')\n\t}\n})\n\nconst elements = computed<FlowElements>({\n\tget: () => {\n\t\tif (!workflow.value) return []\n\t\tconst els = statesToFlowElements(workflow.value, layout.value)\n\t\t// Seed an un-arranged workflow with an auto-computed dagre layout instead of the naive row.\n\t\t// Ephemeral: these positions are persisted only once the author drags a node (which routes\n\t\t// through flowElementsToStates → layout). A workflow with any saved layout keeps it as-is.\n\t\tconst noSavedLayout = !layout.value || Object.keys(layout.value).length === 0\n\t\treturn noSavedLayout ? autoLayout(els) : els\n\t},\n\tset: newValue => {\n\t\tconst { workflow: nextWorkflow, layout: nextLayout } = flowElementsToStates(newValue, workflow.value)\n\t\tworkflow.value = nextWorkflow\n\t\tif (layout.value !== undefined) {\n\t\t\tlayout.value = nextLayout\n\t\t}\n\t},\n})\n</script>\n","<template>\n\t<div>\n\t\t<NodeEditor v-model=\"elements\" :node-container-class=\"nodeContainerClass\" />\n\t</div>\n</template>\n\n<script setup lang=\"ts\">\nimport { type HTMLAttributes, computed, onMounted } from 'vue'\nimport type { WorkflowMeta } from '@stonecrop/schema'\n\nimport NodeEditor from './NodeEditor.vue'\nimport type { FlowElements, Layout } from '../types'\nimport { autoLayout } from '../utils/autoLayout'\nimport { statesToFlowElements, flowElementsToStates } from '../utils/stateTransforms'\n\nconst workflow = defineModel<WorkflowMeta>()\nconst layout = defineModel<Layout>('layout')\nconst { nodeContainerClass = '' } = defineProps<{\n\tnodeContainerClass?: HTMLAttributes['class']\n}>()\n\nonMounted(() => {\n\tif (layout.value === undefined) {\n\t\tconsole.warn('[StateEditor] v-model:layout is not bound. Node position changes will not be persisted.')\n\t}\n})\n\nconst elements = computed<FlowElements>({\n\tget: () => {\n\t\tif (!workflow.value) return []\n\t\tconst els = statesToFlowElements(workflow.value, layout.value)\n\t\t// Seed an un-arranged workflow with an auto-computed dagre layout instead of the naive row.\n\t\t// Ephemeral: these positions are persisted only once the author drags a node (which routes\n\t\t// through flowElementsToStates → layout). A workflow with any saved layout keeps it as-is.\n\t\tconst noSavedLayout = !layout.value || Object.keys(layout.value).length === 0\n\t\treturn noSavedLayout ? autoLayout(els) : els\n\t},\n\tset: newValue => {\n\t\tconst { workflow: nextWorkflow, layout: nextLayout } = flowElementsToStates(newValue, workflow.value)\n\t\tworkflow.value = nextWorkflow\n\t\tif (layout.value !== undefined) {\n\t\t\tlayout.value = nextLayout\n\t\t}\n\t},\n})\n</script>\n","import { App } from 'vue'\n\nimport NodeEditor from './components/NodeEditor.vue'\nimport StateEditor from './components/StateEditor.vue'\nexport type * from './types'\n\n// `Layout` types its handle placement as this enum, so a consumer cannot fill that field without\n// naming it. It is an enum rather than a string union, which makes the obvious `'left'` a type\n// error, and @vue-flow/core is a transitive dependency a consumer should not have to add.\nexport { Position } from '@vue-flow/core'\n\n/**\n * Install all Node Editor components\n * @param app - Vue app instance\n * @public\n */\nfunction install(app: App) {\n\tapp.component('NodeEditor', NodeEditor)\n\tapp.component('StateEditor', StateEditor)\n}\n\nexport { install, NodeEditor, StateEditor }\n"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type EdgeProps } from '@vue-flow/core';
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
4
|
+
declare const __VLS_export: import("vue").DefineComponent<EdgeProps<any, object, string>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
change: (...args: any[]) => void;
|
|
6
|
+
remove: (...args: any[]) => void;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<EdgeProps<any, object, string>> & Readonly<{
|
|
8
|
+
onChange?: ((...args: any[]) => any) | undefined;
|
|
9
|
+
onRemove?: ((...args: any[]) => any) | undefined;
|
|
10
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
|
+
//# sourceMappingURL=EditableEdge.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditableEdge.vue.d.ts","sourceRoot":"","sources":["../../../src/components/EditableEdge.vue"],"names":[],"mappings":"AAAA,OA+FO,EAAE,KAAK,SAAS,EAAqD,MAAM,gBAAgB,CAAA;wBAI7E,OAAO,YAAY;AAAxC,wBAAyC;AAKzC,QAAA,MAAM,YAAY;;;;;;kFAyId,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { NodeProps } from '@vue-flow/core';
|
|
2
|
+
type __VLS_Props = NodeProps;
|
|
3
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
4
|
+
change: (...args: any[]) => void;
|
|
5
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
6
|
+
onChange?: ((...args: any[]) => any) | undefined;
|
|
7
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
8
|
+
declare const _default: typeof __VLS_export;
|
|
9
|
+
export default _default;
|
|
10
|
+
//# sourceMappingURL=EditableNode.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EditableNode.vue.d.ts","sourceRoot":"","sources":["../../../src/components/EditableNode.vue"],"names":[],"mappings":"AAAA,OAoEO,EAAE,SAAS,EAAU,MAAM,gBAAgB,CAAA;AAGlD,KAAK,WAAW,GAAG,SAAS,CAAC;AAuH7B,QAAA,MAAM,YAAY;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type HTMLAttributes } from 'vue';
|
|
2
|
+
import type { FlowElements } from '../types';
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
modelValue: FlowElements;
|
|
5
|
+
nodeContainerClass?: HTMLAttributes['class'];
|
|
6
|
+
};
|
|
7
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
8
|
+
"update:modelValue": (...args: any[]) => void;
|
|
9
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
10
|
+
"onUpdate:modelValue"?: ((...args: any[]) => any) | undefined;
|
|
11
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
12
|
+
declare const _default: typeof __VLS_export;
|
|
13
|
+
export default _default;
|
|
14
|
+
//# sourceMappingURL=NodeEditor.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NodeEditor.vue.d.ts","sourceRoot":"","sources":["../../../src/components/NodeEditor.vue"],"names":[],"mappings":"AA2ZA,OAAO,EAAE,KAAK,cAAc,EAAuD,MAAM,KAAK,CAAA;AAM9F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAE5C,KAAK,WAAW,GAAG;IAClB,UAAU,EAAE,YAAY,CAAA;IACxB,kBAAkB,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAA;CAC5C,CAAC;AA0gBF,QAAA,MAAM,YAAY;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type EdgeProps } from '@vue-flow/core';
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
4
|
+
declare const __VLS_export: import("vue").DefineComponent<EdgeProps<any, object, string>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
change: (...args: any[]) => void;
|
|
6
|
+
remove: (...args: any[]) => void;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<EdgeProps<any, object, string>> & Readonly<{
|
|
8
|
+
onChange?: ((...args: any[]) => any) | undefined;
|
|
9
|
+
onRemove?: ((...args: any[]) => any) | undefined;
|
|
10
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
11
|
+
//# sourceMappingURL=SelfLoopEdge.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SelfLoopEdge.vue.d.ts","sourceRoot":"","sources":["../../../src/components/SelfLoopEdge.vue"],"names":[],"mappings":"AAAA,OA2FO,EAAE,KAAK,SAAS,EAAqB,MAAM,gBAAgB,CAAA;wBAI7C,OAAO,YAAY;AAAxC,wBAAyC;AAKzC,QAAA,MAAM,YAAY;;;;;;kFAyJd,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type HTMLAttributes } from 'vue';
|
|
2
|
+
import type { WorkflowMeta } from '@stonecrop/schema';
|
|
3
|
+
import type { Layout } from '../types';
|
|
4
|
+
type __VLS_Props = {
|
|
5
|
+
nodeContainerClass?: HTMLAttributes['class'];
|
|
6
|
+
};
|
|
7
|
+
type __VLS_ModelProps = {
|
|
8
|
+
modelValue?: WorkflowMeta;
|
|
9
|
+
'layout'?: Layout;
|
|
10
|
+
};
|
|
11
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
12
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
13
|
+
"update:modelValue": (value: {
|
|
14
|
+
states?: string[] | undefined;
|
|
15
|
+
actions?: Record<string, {
|
|
16
|
+
label: string;
|
|
17
|
+
requiredFields?: string[] | undefined;
|
|
18
|
+
allowedStates?: string[] | undefined;
|
|
19
|
+
nextState?: string | undefined;
|
|
20
|
+
stateless?: boolean | undefined;
|
|
21
|
+
selfTransition?: boolean | undefined;
|
|
22
|
+
clientHandler?: string | undefined;
|
|
23
|
+
}> | undefined;
|
|
24
|
+
triggers?: Record<string, {
|
|
25
|
+
on: string[];
|
|
26
|
+
clientHandler: string;
|
|
27
|
+
label?: string | undefined;
|
|
28
|
+
}> | undefined;
|
|
29
|
+
layout?: Record<string, {
|
|
30
|
+
position?: {
|
|
31
|
+
x: number;
|
|
32
|
+
y: number;
|
|
33
|
+
} | undefined;
|
|
34
|
+
targetPosition?: "bottom" | "left" | "right" | "top" | undefined;
|
|
35
|
+
sourcePosition?: "bottom" | "left" | "right" | "top" | undefined;
|
|
36
|
+
}> | undefined;
|
|
37
|
+
} | undefined) => any;
|
|
38
|
+
"update:layout": (value: Layout | undefined) => any;
|
|
39
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
40
|
+
"onUpdate:modelValue"?: ((value: {
|
|
41
|
+
states?: string[] | undefined;
|
|
42
|
+
actions?: Record<string, {
|
|
43
|
+
label: string;
|
|
44
|
+
requiredFields?: string[] | undefined;
|
|
45
|
+
allowedStates?: string[] | undefined;
|
|
46
|
+
nextState?: string | undefined;
|
|
47
|
+
stateless?: boolean | undefined;
|
|
48
|
+
selfTransition?: boolean | undefined;
|
|
49
|
+
clientHandler?: string | undefined;
|
|
50
|
+
}> | undefined;
|
|
51
|
+
triggers?: Record<string, {
|
|
52
|
+
on: string[];
|
|
53
|
+
clientHandler: string;
|
|
54
|
+
label?: string | undefined;
|
|
55
|
+
}> | undefined;
|
|
56
|
+
layout?: Record<string, {
|
|
57
|
+
position?: {
|
|
58
|
+
x: number;
|
|
59
|
+
y: number;
|
|
60
|
+
} | undefined;
|
|
61
|
+
targetPosition?: "bottom" | "left" | "right" | "top" | undefined;
|
|
62
|
+
sourcePosition?: "bottom" | "left" | "right" | "top" | undefined;
|
|
63
|
+
}> | undefined;
|
|
64
|
+
} | undefined) => any) | undefined;
|
|
65
|
+
"onUpdate:layout"?: ((value: Layout | undefined) => any) | undefined;
|
|
66
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
67
|
+
declare const _default: typeof __VLS_export;
|
|
68
|
+
export default _default;
|
|
69
|
+
//# sourceMappingURL=StateEditor.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StateEditor.vue.d.ts","sourceRoot":"","sources":["../../../src/components/StateEditor.vue"],"names":[],"mappings":"AAAA,OAiDO,EAAE,KAAK,cAAc,EAAuB,MAAM,KAAK,CAAA;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAGrD,OAAO,KAAK,EAAgB,MAAM,EAAE,MAAM,UAAU,CAAA;AAMpD,KAAK,WAAW,GAAG;IAClB,kBAAkB,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAA;CAC5C,CAAC;AA8BF,KAAK,gBAAgB,GAAG;IACxB,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAMF,KAAK,iBAAiB,GAAG,WAAW,GAAG,gBAAgB,CAAC;AAkCxD,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kFAGhB,CAAC;wBACkB,OAAO,YAAY;AAAxC,wBAAyC"}
|
package/package.json
CHANGED
|
@@ -1,56 +1,68 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stonecrop/node-editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "Node editor UI for Stonecrop",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"components",
|
|
7
|
+
"graph",
|
|
8
|
+
"node-editor",
|
|
9
|
+
"stonecrop",
|
|
10
|
+
"vue",
|
|
11
|
+
"workflow"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/agritheory/stonecrop#readme",
|
|
5
14
|
"bugs": {
|
|
6
15
|
"url": "https://github.com/agritheory/stonecrop/issues"
|
|
7
16
|
},
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "https://github.com/agritheory/stonecrop",
|
|
11
|
-
"directory": "node_editor"
|
|
12
|
-
},
|
|
13
17
|
"license": "MIT",
|
|
14
18
|
"author": {
|
|
15
19
|
"name": "Tyler Matteson",
|
|
16
20
|
"email": "tyler@agritheory.com"
|
|
17
21
|
},
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "https://github.com/agritheory/stonecrop",
|
|
25
|
+
"directory": "node_editor"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"type": "module",
|
|
18
31
|
"sideEffects": [
|
|
19
32
|
"**/*.css"
|
|
20
33
|
],
|
|
21
|
-
"
|
|
34
|
+
"types": "./dist/src/index.d.ts",
|
|
22
35
|
"exports": {
|
|
23
36
|
".": {
|
|
24
|
-
"types": "./dist/
|
|
37
|
+
"types": "./dist/src/index.d.ts",
|
|
25
38
|
"import": "./dist/node-editor.js"
|
|
26
39
|
},
|
|
27
|
-
"./styles": "./dist/
|
|
28
|
-
"./types": "./dist/src/types/index.d.ts"
|
|
40
|
+
"./styles": "./dist/assets/index.css",
|
|
41
|
+
"./types": "./dist/src/types/index.d.ts",
|
|
42
|
+
"./package.json": "./package.json"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
29
46
|
},
|
|
30
|
-
"types": "./dist/node-editor.d.ts",
|
|
31
|
-
"files": [
|
|
32
|
-
"dist/*",
|
|
33
|
-
"src/*"
|
|
34
|
-
],
|
|
35
47
|
"dependencies": {
|
|
36
48
|
"@dagrejs/dagre": "^3.0.0",
|
|
37
49
|
"@vue-flow/core": "^1.48.1",
|
|
38
|
-
"@stonecrop/schema": "0.
|
|
50
|
+
"@stonecrop/schema": "0.32.0"
|
|
39
51
|
},
|
|
40
52
|
"devDependencies": {
|
|
41
|
-
"@microsoft/api-
|
|
42
|
-
"@rushstack/heft": "^1.2.17",
|
|
53
|
+
"@microsoft/api-extractor": "^7.58.7",
|
|
43
54
|
"@vitejs/plugin-vue": "^6.0.6",
|
|
44
55
|
"@vitest/coverage-istanbul": "^4.1.5",
|
|
45
56
|
"oxlint": "1.67.0",
|
|
46
57
|
"oxlint-tsgolint": "0.23.0",
|
|
47
58
|
"typescript": "^6.0.3",
|
|
48
|
-
"vite": "^
|
|
59
|
+
"vite": "^8.2.2",
|
|
60
|
+
"vite-plugin-lib-inject-css": "^2.2.2",
|
|
49
61
|
"vitest": "^4.1.5",
|
|
50
62
|
"vue": "^3.5.33",
|
|
63
|
+
"vue-component-meta": "^3.3.11",
|
|
51
64
|
"vue-router": "^5.0.6",
|
|
52
|
-
"vue-tsc": "^3.3.6"
|
|
53
|
-
"stonecrop-rig": "0.7.0"
|
|
65
|
+
"vue-tsc": "^3.3.6"
|
|
54
66
|
},
|
|
55
67
|
"peerDependencies": {
|
|
56
68
|
"vue": "^3.5.33",
|
|
@@ -59,14 +71,9 @@
|
|
|
59
71
|
"engines": {
|
|
60
72
|
"node": ">=24.0.0"
|
|
61
73
|
},
|
|
62
|
-
"publishConfig": {
|
|
63
|
-
"access": "public"
|
|
64
|
-
},
|
|
65
74
|
"scripts": {
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"dev": "vite",
|
|
69
|
-
"docs": "bash ../common/scripts/run-docs.sh node_editor",
|
|
75
|
+
"dev": "vite build --watch",
|
|
76
|
+
"docs": "bash ../tools/scripts/run-docs.sh node_editor",
|
|
70
77
|
"lint": "oxlint",
|
|
71
78
|
"lint:fix": "oxlint --fix",
|
|
72
79
|
"preview": "vite preview",
|
package/dist/node-editor.css
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.editable-edge-label{background-color:#fff;position:relative;font-size:12px}.label-input{text-align:center;width:40ch}.label-input-wrapper{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.label-input{text-align:center}.vue-flow{position:relative;width:100%;height:100%;overflow:hidden;z-index:0;direction:ltr}.vue-flow__container{position:absolute;height:100%;width:100%;left:0;top:0}.vue-flow__pane{z-index:1}.vue-flow__pane.draggable{cursor:grab}.vue-flow__pane.selection{cursor:pointer}.vue-flow__pane.dragging{cursor:grabbing}.vue-flow__transformationpane{transform-origin:0 0;z-index:2;pointer-events:none}.vue-flow__viewport{z-index:4;overflow:clip}.vue-flow__selection{z-index:6}.vue-flow__edge-labels{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.vue-flow__nodesselection-rect:focus,.vue-flow__nodesselection-rect:focus-visible{outline:none}.vue-flow .vue-flow__edges{pointer-events:none;overflow:visible}.vue-flow__edge-path,.vue-flow__connection-path{stroke:#b1b1b7;stroke-width:1;fill:none}.vue-flow__edge{pointer-events:visibleStroke;cursor:pointer}.vue-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.vue-flow__edge.animated path.vue-flow__edge-interaction{stroke-dasharray:none;animation:none}.vue-flow__edge.inactive{pointer-events:none}.vue-flow__edge.selected,.vue-flow__edge:focus,.vue-flow__edge:focus-visible{outline:none}.vue-flow__edge.selected .vue-flow__edge-path,.vue-flow__edge:focus .vue-flow__edge-path,.vue-flow__edge:focus-visible .vue-flow__edge-path{stroke:#555}.vue-flow__edge-textwrapper{pointer-events:all}.vue-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.vue-flow__connection{pointer-events:none}.vue-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.vue-flow__connectionline{z-index:1001}.vue-flow__nodes{pointer-events:none;transform-origin:0 0}.vue-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.vue-flow__node.draggable{cursor:grab;pointer-events:all}.vue-flow__node.draggable.dragging{cursor:grabbing}.vue-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.vue-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.vue-flow__nodesselection-rect.dragging{cursor:grabbing}.vue-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px}.vue-flow__handle.connectable{pointer-events:all;cursor:crosshair}.vue-flow__handle-bottom{left:50%;bottom:0;transform:translate(-50%,50%)}.vue-flow__handle-top{left:50%;top:0;transform:translate(-50%,-50%)}.vue-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.vue-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.vue-flow__edgeupdater{cursor:move;pointer-events:all}.vue-flow__panel{position:absolute;z-index:5;margin:15px}.vue-flow__panel.top{top:0}.vue-flow__panel.bottom{bottom:0}.vue-flow__panel.left{left:0}.vue-flow__panel.right{right:0}.vue-flow__panel.center{left:50%;transform:translate(-50%)}@keyframes dashdraw{0%{stroke-dashoffset:10}}:root{--vf-node-bg: #fff;--vf-node-text: #222;--vf-connection-path: #b1b1b7;--vf-handle: #555}.vue-flow__edge.updating .vue-flow__edge-path{stroke:#777}.vue-flow__edge-text{font-size:10px}.vue-flow__edge-textbg{fill:#fff}.vue-flow__connection-path{stroke:var(--vf-connection-path)}.vue-flow__node{cursor:grab}.vue-flow__node.selectable:focus,.vue-flow__node.selectable:focus-visible{outline:none}.vue-flow__node-default,.vue-flow__node-input,.vue-flow__node-output{padding:10px;border-radius:3px;width:150px;font-size:12px;text-align:center;border-width:1px;border-style:solid;color:var(--vf-node-text);background-color:var(--vf-node-bg);border-color:var(--vf-node-color)}.vue-flow__node-default.selected,.vue-flow__node-default.selected:hover,.vue-flow__node-input.selected,.vue-flow__node-input.selected:hover,.vue-flow__node-output.selected,.vue-flow__node-output.selected:hover{box-shadow:0 0 0 .5px var(--vf-box-shadow)}.vue-flow__node-default.selected,.vue-flow__node-default:focus,.vue-flow__node-default:focus-visible,.vue-flow__node-input.selected,.vue-flow__node-input:focus,.vue-flow__node-input:focus-visible,.vue-flow__node-output.selected,.vue-flow__node-output:focus,.vue-flow__node-output:focus-visible{outline:none;border:1px solid #555}.vue-flow__node-default .vue-flow__handle,.vue-flow__node-input .vue-flow__handle,.vue-flow__node-output .vue-flow__handle{background:var(--vf-handle)}.vue-flow__node-default.selectable:hover,.vue-flow__node-input.selectable:hover,.vue-flow__node-output.selectable:hover{box-shadow:0 1px 4px 1px #00000014}.vue-flow__node-input{--vf-node-color: var(--vf-node-color, #0041d0);--vf-handle: var(--vf-node-color, #0041d0);--vf-box-shadow: var(--vf-node-color, #0041d0);background:var(--vf-node-bg);border-color:var(--vf-node-color, #0041d0)}.vue-flow__node-input.selected,.vue-flow__node-input:focus,.vue-flow__node-input:focus-visible{outline:none;border:1px solid var(--vf-node-color, #0041d0)}.vue-flow__node-default{--vf-handle: var(--vf-node-color, #1a192b);--vf-box-shadow: var(--vf-node-color, #1a192b);background:var(--vf-node-bg);border-color:var(--vf-node-color, #1a192b)}.vue-flow__node-default.selected,.vue-flow__node-default:focus,.vue-flow__node-default:focus-visible{outline:none;border:1px solid var(--vf-node-color, #1a192b)}.vue-flow__node-output{--vf-handle: var(--vf-node-color, #ff0072);--vf-box-shadow: var(--vf-node-color, #ff0072);background:var(--vf-node-bg);border-color:var(--vf-node-color, #ff0072)}.vue-flow__node-output.selected,.vue-flow__node-output:focus,.vue-flow__node-output:focus-visible{outline:none;border:1px solid var(--vf-node-color, #ff0072)}.vue-flow__nodesselection-rect,.vue-flow__selection{background:#0059dc14;border:1px dotted rgba(0,89,220,.8)}.vue-flow__nodesselection-rect:focus,.vue-flow__nodesselection-rect:focus-visible,.vue-flow__selection:focus,.vue-flow__selection:focus-visible{outline:none}.vue-flow__handle{width:6px;height:6px;background:var(--vf-handle);border:1px solid #fff;border-radius:100%}.chart-controls-left,.chart-controls-right{height:1.8em;display:flex;flex-direction:row;align-items:center;padding-top:.2em}.chart-controls-right div{margin-left:5px}.chart-controls{position:absolute;bottom:.5rem;left:.5rem;z-index:10;display:flex;flex-direction:column;align-items:flex-start;gap:.35rem;padding:.4rem .5rem;background:#ffffffeb;border:1px solid #ccc;border-radius:4px;box-shadow:0 1px 3px #0000001f}.chart-controls div{margin-bottom:0}.defaultContainerClass{height:90vh;width:100%;border:1px solid #ccc}.default-input-node.vue-flow__node-input,.default-output-node.vue-flow__node-output{border-color:#000}.default-input-node.vue-flow__node-input .vue-flow__handle,.default-output-node.vue-flow__node-output .vue-flow__handle{background-color:#000}.default-input-node.vue-flow__node-input.selected,.default-output-node.vue-flow__node-output.selected{box-shadow:0 0 0 .5px #000}button.button-default{background-color:#fff;padding:1px 12px;border-radius:3px;border:1px solid #ccc;cursor:pointer;white-space:nowrap}button.button-default:hover{background-color:#f2f2f2}.vue-flow{background-size:40px 40px;background-image:linear-gradient(to right,#ccc 1px,transparent 1px),linear-gradient(to bottom,#ccc 1px,transparent 1px)}input.label-editor{position:absolute}.node-editor-wrapper{position:relative}
|