update: remove examples-app dir
Signed-off-by: Braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
node_modules
|
||||
.DS_Store
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
@@ -1,11 +0,0 @@
|
||||
# Vue 3 + Typescript + Vite
|
||||
|
||||
This template should help get you started developing with Vue 3 and Typescript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
- [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar)
|
||||
|
||||
## Type Support For `.vue` Imports in TS
|
||||
|
||||
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can enable Volar's `.vue` type support plugin by running `Volar: Switch TS Plugin on/off` from VSCode command palette.
|
||||
@@ -1,13 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,26 +0,0 @@
|
||||
{
|
||||
"name": "vue-flow-example",
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"serve": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@braks/vue-flow": "link:..",
|
||||
"dagre": "^0.8.5",
|
||||
"localforage": "^1.10.0",
|
||||
"vue": "^3.2.16",
|
||||
"vue-router": "^4.0.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/dagre": "^0.7.46",
|
||||
"@vitejs/plugin-vue": "^1.9.3",
|
||||
"typescript": "^4.4.3",
|
||||
"unplugin-auto-import": "^0.4.13",
|
||||
"vite": "^2.6.4",
|
||||
"vite-plugin-windicss": "^1.5.1",
|
||||
"vue-tsc": "^0.3.0",
|
||||
"windicss": "^3.2.1"
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import Sidebar from './Sidebar.vue'
|
||||
import Header from './Header.vue'
|
||||
</script>
|
||||
<template>
|
||||
<Header />
|
||||
<div id="app" class="flex">
|
||||
<Sidebar />
|
||||
<div id="vue-flow-docs" class="flex-1">
|
||||
<router-view />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
@import 'assets/index.css';
|
||||
@import '@braks/vue-flow/dist/style.css';
|
||||
|
||||
#app {
|
||||
height: calc(100% - 92px);
|
||||
}
|
||||
</style>
|
||||
@@ -1,91 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
MiniMap,
|
||||
Controls,
|
||||
Background,
|
||||
Connection,
|
||||
Edge,
|
||||
Elements,
|
||||
FlowElement,
|
||||
FlowInstance,
|
||||
addEdge,
|
||||
isNode,
|
||||
removeElements,
|
||||
Node,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
const onNodeDragStop = ({ node }: { node: Node }) => console.log('drag stop', node)
|
||||
const onElementClick = ({ node }: { node: Node }) => console.log('click', node)
|
||||
const elements = ref<Elements>([
|
||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
|
||||
{ id: 'e1-2', source: '1', target: '2', animated: true },
|
||||
{ id: 'e1-3', source: '1', target: '3' },
|
||||
])
|
||||
const rfInstance = ref<FlowInstance | null>(null)
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const onConnect = (params: Edge | Connection) => (elements.value = addEdge(params, elements.value))
|
||||
const onLoad = (flowInstance: FlowInstance) => {
|
||||
flowInstance?.fitView({ padding: 0.1 })
|
||||
rfInstance.value = flowInstance
|
||||
}
|
||||
|
||||
const updatePos = () => {
|
||||
elements.value = elements.value.map((el: FlowElement) => {
|
||||
if (isNode(el)) {
|
||||
el.position = {
|
||||
x: Math.random() * 400,
|
||||
y: Math.random() * 400,
|
||||
}
|
||||
}
|
||||
return el
|
||||
})
|
||||
}
|
||||
|
||||
const logToObject = () => console.log(rfInstance.value?.toObject())
|
||||
const resetTransform = () => rfInstance.value?.setTransform({ x: 0, y: 0, zoom: 1 })
|
||||
|
||||
const toggleClassnames = () => {
|
||||
elements.value = elements.value.map((el: FlowElement) => {
|
||||
if (isNode(el)) el.class = el.class === 'dark' ? 'light' : 'dark'
|
||||
return el
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
class="vue-flow-basic-example"
|
||||
:elements="elements"
|
||||
:default-zoom="1.5"
|
||||
:min-zoom="0.2"
|
||||
:max-zoom="4"
|
||||
@elements-remove="onElementsRemove"
|
||||
@connect="onConnect"
|
||||
@node-drag-stop="onNodeDragStop"
|
||||
@node-click="onElementClick"
|
||||
@elementClick="onElementClick"
|
||||
@load="onLoad"
|
||||
>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
<Background color="#aaa" :gap="8" />
|
||||
<div class="absolute right-[10px] top-[10px] z-4">
|
||||
<button class="button" @click="resetTransform">reset transform</button>
|
||||
<button class="button" @click="updatePos">change pos</button>
|
||||
<button class="button" @click="toggleClassnames">toggle classnames</button>
|
||||
<button class="button" @click="logToObject">toObject</button>
|
||||
</div>
|
||||
</Flow>
|
||||
</template>
|
||||
<style>
|
||||
.vue-flow--node .light {
|
||||
@apply bg-white;
|
||||
}
|
||||
|
||||
.vue-flow--node .dark {
|
||||
@apply bg-black;
|
||||
}
|
||||
</style>
|
||||
@@ -1,23 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { ConnectionLineComponentProps } from '@braks/vue-flow'
|
||||
|
||||
interface ConnectionLineProps extends ConnectionLineComponentProps {
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
targetX: number
|
||||
targetY: number
|
||||
}
|
||||
const props = defineProps<ConnectionLineProps>()
|
||||
</script>
|
||||
<template>
|
||||
<g>
|
||||
<path
|
||||
class="animated"
|
||||
fill="none"
|
||||
stroke="#222"
|
||||
:stroke-width="1.5"
|
||||
:d="`M${props.sourceX},${props.sourceY} C ${props.sourceX} ${props.targetY} ${props.sourceX} ${props.targetY} ${props.targetX},${props.targetY}`"
|
||||
/>
|
||||
<circle :cx="props.targetX" :cy="props.targetY" fill="#fff" :r="3" stroke="#222" :stroke-width="1.5" />
|
||||
</g>
|
||||
</template>
|
||||
@@ -1,23 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { Flow, removeElements, addEdge, Background, BackgroundVariant, Elements, Connection, Edge } from '@braks/vue-flow'
|
||||
import CustomConnectionLine from './CustomConnectionLine.vue'
|
||||
|
||||
const elements = ref<Elements>([
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'Node 1' },
|
||||
position: { x: 250, y: 5 },
|
||||
},
|
||||
])
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" @elements-remove="onElementsRemove" @connect="onConnect">
|
||||
<template #custom-connection-line="props">
|
||||
<CustomConnectionLine v-bind="props" />
|
||||
</template>
|
||||
<Background :variant="BackgroundVariant.Lines" />
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,38 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import { Handle, Position, Connection, Edge, NodeProps } from '@braks/vue-flow'
|
||||
|
||||
interface ColorSelectorNodeProps extends NodeProps {
|
||||
data: {
|
||||
color: string
|
||||
onChange: (event: any) => void
|
||||
}
|
||||
type: string
|
||||
selected?: boolean
|
||||
connectable?: boolean
|
||||
xPos?: number
|
||||
yPos?: number
|
||||
targetPosition?: Position
|
||||
sourcePosition?: Position
|
||||
dragging?: boolean
|
||||
}
|
||||
const props = defineProps<ColorSelectorNodeProps>()
|
||||
|
||||
const targetHandleStyle: CSSProperties = { background: '#555' }
|
||||
const sourceHandleStyleA: CSSProperties = { ...targetHandleStyle, top: '10px' }
|
||||
const sourceHandleStyleB: CSSProperties = { ...targetHandleStyle, bottom: '10px', top: 'auto' }
|
||||
|
||||
const onConnect = (params: Connection | Edge) => console.log('handle onConnect', params)
|
||||
</script>
|
||||
<template>
|
||||
<div class="py-1 px-1 flex flex-col gap-1 justify-center items-center">
|
||||
<Handle type="target" :position="Position.Left" :style="targetHandleStyle" :on-connect="onConnect" />
|
||||
<div class="text-md font-bold">Custom Color Picker Node</div>
|
||||
<div :style="{ color: data.color }" class="text-md font-semibold">
|
||||
{{ data.color }}
|
||||
</div>
|
||||
<input class="nodrag" type="color" :value="data.color" @input="props.data.onChange" />
|
||||
<Handle id="a" type="source" :position="Position.Right" :style="sourceHandleStyleA" />
|
||||
<Handle id="b" type="source" :position="Position.Right" :style="sourceHandleStyleB" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,132 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
isEdge,
|
||||
removeElements,
|
||||
addEdge,
|
||||
MiniMap,
|
||||
Controls,
|
||||
Node,
|
||||
FlowElement,
|
||||
FlowInstance,
|
||||
Elements,
|
||||
Position,
|
||||
SnapGrid,
|
||||
Connection,
|
||||
ConnectionMode,
|
||||
Edge,
|
||||
} from '@braks/vue-flow'
|
||||
import ColorPickerNode from './ColorPickerNode.vue'
|
||||
|
||||
const elements = ref<Elements>([])
|
||||
const bgColor = ref('#1A192B')
|
||||
const connectionLineStyle = { stroke: '#fff' }
|
||||
const snapGrid: SnapGrid = [16, 16]
|
||||
const nodeTypes = {
|
||||
selectorNode: ColorPickerNode,
|
||||
}
|
||||
|
||||
const onLoad = (flowInstance: FlowInstance) => {
|
||||
flowInstance.fitView()
|
||||
console.log('flow loaded:', flowInstance)
|
||||
}
|
||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node)
|
||||
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element)
|
||||
const nodeStroke = (n: Node): string => {
|
||||
if (n.type === 'input') return '#0041d0'
|
||||
if (n.type === 'selectorNode') return bgColor.value
|
||||
if (n.type === 'output') return '#ff0072'
|
||||
return '#eee'
|
||||
}
|
||||
const nodeColor = (n: Node): string => {
|
||||
if (n.type === 'selectorNode') return bgColor.value
|
||||
return '#fff'
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const onChange = (event: Event) => {
|
||||
elements.value = elements.value.map((e: FlowElement) => {
|
||||
if (isEdge(e) || e.id !== '2') {
|
||||
return e
|
||||
}
|
||||
const color = (event.target as HTMLInputElement).value
|
||||
bgColor.value = color
|
||||
|
||||
return {
|
||||
...e,
|
||||
data: {
|
||||
...e.data,
|
||||
color,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
elements.value = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'An input node' },
|
||||
position: { x: 0, y: 50 },
|
||||
sourcePosition: Position.Right,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'selectorNode',
|
||||
data: { onChange, color: bgColor.value },
|
||||
style: { border: '1px solid #777', padding: '10px' },
|
||||
position: { x: 250, y: 50 },
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'output',
|
||||
data: { label: 'Output A' },
|
||||
position: { x: 650, y: 25 },
|
||||
targetPosition: Position.Left,
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
type: 'output',
|
||||
data: { label: 'Output B' },
|
||||
position: { x: 650, y: 100 },
|
||||
targetPosition: Position.Left,
|
||||
},
|
||||
|
||||
{ id: 'e1-2', source: '1', target: '2', animated: true, style: { stroke: '#fff' } },
|
||||
{ id: 'e2a-3', source: '2', sourceHandle: 'a', target: '3', animated: true, style: { stroke: '#fff' } },
|
||||
{ id: 'e2b-4', source: '2', sourceHandle: 'b', target: '4', animated: true, style: { stroke: '#fff' } },
|
||||
]
|
||||
})
|
||||
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
|
||||
const onConnect = (params: Connection | Edge) =>
|
||||
(elements.value = addEdge(
|
||||
{
|
||||
...params,
|
||||
animated: true,
|
||||
style: { stroke: '#fff' },
|
||||
} as Edge,
|
||||
elements.value,
|
||||
))
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:style="`background: ${bgColor}`"
|
||||
:node-types="nodeTypes"
|
||||
:connection-mode="ConnectionMode.Loose"
|
||||
:connection-line-style="connectionLineStyle"
|
||||
:snap-to-grid="true"
|
||||
:snap-grid="snapGrid"
|
||||
:default-zoom="1.5"
|
||||
@element-click="onElementClick"
|
||||
@elements-remove="onElementsRemove"
|
||||
@connect="onConnect"
|
||||
@node-drag-stop="onNodeDragStop"
|
||||
@load="onLoad"
|
||||
>
|
||||
<MiniMap :node-stroke-color="nodeStroke" :node-color="nodeColor" />
|
||||
<Controls />
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,70 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
addEdge,
|
||||
removeElements,
|
||||
Controls,
|
||||
MiniMap,
|
||||
Background,
|
||||
FlowInstance,
|
||||
Elements,
|
||||
Connection,
|
||||
Edge,
|
||||
ElementId,
|
||||
} from '@braks/vue-flow'
|
||||
import Sidebar from './Sidebar.vue'
|
||||
|
||||
const flowInstance = ref<FlowInstance>()
|
||||
const elements = ref<Elements>([
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'input node' },
|
||||
position: { x: 250, y: 5 },
|
||||
},
|
||||
])
|
||||
|
||||
let id = 0
|
||||
const getId = (): ElementId => `dndnode_${id++}`
|
||||
|
||||
const onDragOver = (event: DragEvent) => {
|
||||
event.preventDefault()
|
||||
if (event.dataTransfer) {
|
||||
event.dataTransfer.dropEffect = 'move'
|
||||
}
|
||||
}
|
||||
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const onLoad = (instance: FlowInstance) => (flowInstance.value = instance)
|
||||
|
||||
const onDrop = (event: DragEvent) => {
|
||||
event.preventDefault()
|
||||
|
||||
if (flowInstance.value) {
|
||||
console.log(event.dataTransfer?.getData('application/vueflow'))
|
||||
const type = event.dataTransfer?.getData('application/vueflow')
|
||||
const position = flowInstance.value.project({ x: event.clientX - 400, y: event.clientY - 40 })
|
||||
const newNode = {
|
||||
id: getId(),
|
||||
type,
|
||||
position,
|
||||
data: { label: `${type} node` },
|
||||
}
|
||||
|
||||
elements.value.push(newNode)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="flex flex-col md:flex-row h-full">
|
||||
<div class="flex-1 h-full" @drop="onDrop">
|
||||
<Flow :elements="elements" @elements-remove="onElementsRemove" @load="onLoad" @connect="onConnect" @dragover="onDragOver">
|
||||
<Controls />
|
||||
<MiniMap />
|
||||
<Background color="#aaa" :gap="8" />
|
||||
</Flow>
|
||||
</div>
|
||||
<Sidebar />
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,47 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
const onDragStart = (event: DragEvent, nodeType: string) => {
|
||||
if (event.dataTransfer) {
|
||||
event.dataTransfer.setData('application/vueflow', nodeType)
|
||||
event.dataTransfer.effectAllowed = 'move'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<aside class="md:(w-[30%] max-w-[200px])">
|
||||
<div class="mb-6">You can drag these nodes to the pane on the left.</div>
|
||||
<div
|
||||
class="droppable-node vue-flow__node-input"
|
||||
:draggable="true"
|
||||
@dragstart="(event: DragEvent) => onDragStart(event, 'input')"
|
||||
>
|
||||
Input Node
|
||||
</div>
|
||||
<div
|
||||
class="droppable-node vue-flow__node-default"
|
||||
:draggable="true"
|
||||
@dragstart="(event: DragEvent) => onDragStart(event, 'default')"
|
||||
>
|
||||
Default Node
|
||||
</div>
|
||||
<div
|
||||
class="droppable-node vue-flow__node-output"
|
||||
:draggable="true"
|
||||
@dragstart="(event: DragEvent) => onDragStart(event, 'output')"
|
||||
>
|
||||
Output Node
|
||||
</div>
|
||||
</aside>
|
||||
</template>
|
||||
<style scoped>
|
||||
aside {
|
||||
border-right: 1px solid #eee;
|
||||
padding: 15px 10px;
|
||||
font-size: 12px;
|
||||
background: #fcfcfc;
|
||||
}
|
||||
|
||||
.droppable-node {
|
||||
@apply mb-6;
|
||||
cursor: grab;
|
||||
}
|
||||
</style>
|
||||
@@ -1,30 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
removeElements,
|
||||
addEdge,
|
||||
MiniMap,
|
||||
Controls,
|
||||
Background,
|
||||
FlowInstance,
|
||||
Connection,
|
||||
Edge,
|
||||
Elements,
|
||||
} from '@braks/vue-flow'
|
||||
import { getElements } from './utils'
|
||||
|
||||
const onLoad = (flowInstance: FlowInstance) => {
|
||||
flowInstance.fitView()
|
||||
console.log(flowInstance.getElements())
|
||||
}
|
||||
|
||||
const elements = ref<Elements>(getElements())
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" :min-zoom="0.2" @load="onLoad" @elements-remove="onElementsRemove" @connect="onConnect">
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,106 +0,0 @@
|
||||
import { ElementId, Elements, Position } from '@braks/vue-flow'
|
||||
|
||||
const nodeWidth = 80
|
||||
const nodeGapWidth = nodeWidth * 2
|
||||
const nodeStyle = { width: `${nodeWidth}px`, fontSize: '11px', color: 'white' }
|
||||
|
||||
const sourceTargetPositions = [
|
||||
{ source: Position.Bottom, target: Position.Top },
|
||||
{ source: Position.Right, target: Position.Left },
|
||||
]
|
||||
const nodeColors = [
|
||||
['#1e9e99', '#4cb3ac', '#6ec9c0', '#8ddfd4'],
|
||||
['#0f4c75', '#1b5d8b', '#276fa1', '#3282b8'],
|
||||
]
|
||||
const edgeTypes = ['default', 'step', 'smoothstep', 'straight']
|
||||
const offsets = [
|
||||
{
|
||||
x: 0,
|
||||
y: -nodeGapWidth,
|
||||
},
|
||||
{
|
||||
x: nodeGapWidth,
|
||||
y: -nodeGapWidth,
|
||||
},
|
||||
{
|
||||
x: nodeGapWidth,
|
||||
y: 0,
|
||||
},
|
||||
{
|
||||
x: nodeGapWidth,
|
||||
y: nodeGapWidth,
|
||||
},
|
||||
{
|
||||
x: 0,
|
||||
y: nodeGapWidth,
|
||||
},
|
||||
{
|
||||
x: -nodeGapWidth,
|
||||
y: nodeGapWidth,
|
||||
},
|
||||
{
|
||||
x: -nodeGapWidth,
|
||||
y: 0,
|
||||
},
|
||||
{
|
||||
x: -nodeGapWidth,
|
||||
y: -nodeGapWidth,
|
||||
},
|
||||
]
|
||||
|
||||
let id = 0
|
||||
const getNodeId = (): ElementId => (id++).toString()
|
||||
|
||||
export function getElements(): Elements {
|
||||
const initialElements = []
|
||||
|
||||
for (let sourceTargetIndex = 0; sourceTargetIndex < sourceTargetPositions.length; sourceTargetIndex++) {
|
||||
const currSourceTargetPos = sourceTargetPositions[sourceTargetIndex]
|
||||
|
||||
for (let edgeTypeIndex = 0; edgeTypeIndex < edgeTypes.length; edgeTypeIndex++) {
|
||||
const currEdgeType = edgeTypes[edgeTypeIndex]
|
||||
|
||||
for (let offsetIndex = 0; offsetIndex < offsets.length; offsetIndex++) {
|
||||
const currOffset = offsets[offsetIndex]
|
||||
|
||||
const style = { ...nodeStyle, background: nodeColors[sourceTargetIndex][edgeTypeIndex] }
|
||||
const sourcePosition = {
|
||||
x: offsetIndex * nodeWidth * 4,
|
||||
y: edgeTypeIndex * 300 + sourceTargetIndex * edgeTypes.length * 300,
|
||||
}
|
||||
const sourceId = getNodeId()
|
||||
const sourceData = { label: `Source ${sourceId}` }
|
||||
const sourceNode = {
|
||||
id: sourceId,
|
||||
style,
|
||||
data: sourceData,
|
||||
position: sourcePosition,
|
||||
sourcePosition: currSourceTargetPos.source,
|
||||
targetPosition: currSourceTargetPos.target,
|
||||
}
|
||||
|
||||
const targetId = getNodeId()
|
||||
const targetData = { label: `Target ${targetId}` }
|
||||
const targetPosition = {
|
||||
x: sourcePosition.x + currOffset.x,
|
||||
y: sourcePosition.y + currOffset.y,
|
||||
}
|
||||
const targetNode = {
|
||||
id: targetId,
|
||||
style,
|
||||
data: targetData,
|
||||
position: targetPosition,
|
||||
sourcePosition: currSourceTargetPos.source,
|
||||
targetPosition: currSourceTargetPos.target,
|
||||
}
|
||||
|
||||
initialElements.push(sourceNode)
|
||||
initialElements.push(targetNode)
|
||||
|
||||
initialElements.push({ id: `${sourceId}-${targetId}`, source: sourceId, target: targetId, type: currEdgeType })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return initialElements
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
useHooks,
|
||||
useStore,
|
||||
getEdgeCenter,
|
||||
getBezierPath,
|
||||
getMarkerEnd,
|
||||
ArrowHeadType,
|
||||
EdgeProps,
|
||||
ElementId,
|
||||
Position,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
interface CustomEdgeProps<T = any> extends EdgeProps<T> {
|
||||
id: ElementId
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
targetX: number
|
||||
targetY: number
|
||||
sourcePosition: Position
|
||||
targetPosition: Position
|
||||
arrowHeadType?: ArrowHeadType
|
||||
markerEndId?: string
|
||||
data?: T
|
||||
}
|
||||
|
||||
const props = defineProps<CustomEdgeProps>()
|
||||
const store = useStore()
|
||||
const hooks = useHooks()
|
||||
const onEdgeClick = (evt: Event, id: string) => {
|
||||
const edge = store.edges.find((edge) => edge.id === id)
|
||||
if (edge) {
|
||||
hooks.elementsRemove.trigger([edge])
|
||||
}
|
||||
evt.stopPropagation()
|
||||
alert(`remove ${id}`)
|
||||
}
|
||||
|
||||
const foreignObjectSize = 40
|
||||
|
||||
const edgePath = computed(() =>
|
||||
getBezierPath({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
sourcePosition: props.sourcePosition,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
targetPosition: props.targetPosition,
|
||||
}),
|
||||
)
|
||||
const markerEnd = computed(() => getMarkerEnd(props.arrowHeadType, props.markerEndId))
|
||||
const center = computed(() =>
|
||||
getEdgeCenter({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
}),
|
||||
)
|
||||
</script>
|
||||
<template>
|
||||
<path :id="props.id" :style="props.style" class="vue-flow__edge-path" :d="edgePath" :marker-end="markerEnd" />
|
||||
<foreignObject
|
||||
:width="foreignObjectSize"
|
||||
:height="foreignObjectSize"
|
||||
:x="center[0] - foreignObjectSize / 2"
|
||||
:y="center[1] - foreignObjectSize / 2"
|
||||
class="edgebutton-foreignobject"
|
||||
requiredExtensions="http://www.w3.org/1999/xhtml"
|
||||
>
|
||||
<body class="p-1">
|
||||
<button class="edgebutton bg-gray-500 p-[4px] h-full w-full" @click="(event) => onEdgeClick(event, props.id)">×</button>
|
||||
</body>
|
||||
</foreignObject>
|
||||
</template>
|
||||
<style scoped>
|
||||
body {
|
||||
background: unset;
|
||||
}
|
||||
</style>
|
||||
@@ -1,55 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
addEdge,
|
||||
Background,
|
||||
Connection,
|
||||
Controls,
|
||||
Edge,
|
||||
EdgeType,
|
||||
Elements,
|
||||
MiniMap,
|
||||
FlowInstance,
|
||||
removeElements,
|
||||
} from '@braks/vue-flow'
|
||||
import ButtonEdge from './ButtonEdge.vue'
|
||||
const edgeTypes = {
|
||||
buttonedge: ButtonEdge as EdgeType,
|
||||
}
|
||||
|
||||
const elements = ref<Elements>([
|
||||
{
|
||||
id: 'ewb-1',
|
||||
type: 'input',
|
||||
data: { label: 'Input 1' },
|
||||
position: { x: 250, y: 0 },
|
||||
},
|
||||
{ id: 'ewb-2', data: { label: 'Node 2' }, position: { x: 250, y: 300 } },
|
||||
{
|
||||
id: 'edge-1-2',
|
||||
source: 'ewb-1',
|
||||
target: 'ewb-2',
|
||||
type: 'buttonedge',
|
||||
},
|
||||
])
|
||||
|
||||
const onLoad = (flowInstance: FlowInstance) => flowInstance.fitView()
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const onConnect = (params: Connection | Edge) =>
|
||||
(elements.value = addEdge({ ...params, type: 'buttonedge' } as Edge, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
key="edge-with-button"
|
||||
:elements="elements"
|
||||
:snap-to-grid="true"
|
||||
:edge-types="edgeTypes"
|
||||
@load="onLoad"
|
||||
@elementsRemove="onElementsRemove"
|
||||
@connect="onConnect"
|
||||
>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
<Background />
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,41 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { ArrowHeadType, ElementId, getBezierPath, getMarkerEnd, Position, EdgeProps } from '@braks/vue-flow'
|
||||
|
||||
interface CustomEdgeProps<T = any> extends EdgeProps<T> {
|
||||
source: ElementId
|
||||
target: ElementId
|
||||
sourceHandleId?: ElementId
|
||||
targetHandleId?: ElementId
|
||||
id: ElementId
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
targetX: number
|
||||
targetY: number
|
||||
sourcePosition: Position
|
||||
targetPosition: Position
|
||||
arrowHeadType?: ArrowHeadType
|
||||
markerEndId?: string
|
||||
data?: T
|
||||
}
|
||||
|
||||
const props = defineProps<CustomEdgeProps>()
|
||||
const edgePath = computed(() =>
|
||||
getBezierPath({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
sourcePosition: props.sourcePosition,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
targetPosition: props.targetPosition,
|
||||
}),
|
||||
)
|
||||
const markerEnd = computed(() => getMarkerEnd(props.arrowHeadType, props.markerEndId))
|
||||
</script>
|
||||
<template>
|
||||
<path :id="props.id" class="vue-flow__edge-path" :d="edgePath" :marker-end="markerEnd" />
|
||||
<text>
|
||||
<textPath :href="`#${props.id}`" :style="{ fontSize: '12px' }" startOffset="50%" text-anchor="middle">
|
||||
{{ props.data.text }}
|
||||
</textPath>
|
||||
</text>
|
||||
</template>
|
||||
@@ -1,65 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
getBezierPath,
|
||||
getMarkerEnd,
|
||||
ArrowHeadType,
|
||||
EdgeProps,
|
||||
ElementId,
|
||||
getEdgeCenter,
|
||||
Position,
|
||||
EdgeText,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
interface CustomEdgeProps<T = any> extends EdgeProps<T> {
|
||||
source: ElementId
|
||||
target: ElementId
|
||||
sourceHandleId?: ElementId
|
||||
targetHandleId?: ElementId
|
||||
id: ElementId
|
||||
sourceX: number
|
||||
sourceY: number
|
||||
targetX: number
|
||||
targetY: number
|
||||
sourcePosition: Position
|
||||
targetPosition: Position
|
||||
arrowHeadType?: ArrowHeadType
|
||||
markerEndId?: string
|
||||
data?: T
|
||||
}
|
||||
|
||||
const props = defineProps<CustomEdgeProps>()
|
||||
|
||||
const edgePath = computed(() =>
|
||||
getBezierPath({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
sourcePosition: props.sourcePosition,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
targetPosition: props.targetPosition,
|
||||
}),
|
||||
)
|
||||
const markerEnd = computed(() => getMarkerEnd(props.arrowHeadType, props.markerEndId))
|
||||
const center = computed(() =>
|
||||
getEdgeCenter({
|
||||
sourceX: props.sourceX,
|
||||
sourceY: props.sourceY,
|
||||
targetX: props.targetX,
|
||||
targetY: props.targetY,
|
||||
}),
|
||||
)
|
||||
</script>
|
||||
<template>
|
||||
<path :id="props.id" class="vue-flow__edge-path" :d="edgePath" :marker-end="markerEnd" />
|
||||
<EdgeText
|
||||
:x="center[0]"
|
||||
:y="center[1]"
|
||||
:label="props.data?.text"
|
||||
:label-style="{ fill: 'white' }"
|
||||
:label-show-bg="true"
|
||||
:label-bg-style="{ fill: 'red' }"
|
||||
:label-bg-padding="[2, 4]"
|
||||
:label-bg-border-radius="2"
|
||||
@click="() => console.log(props.data)"
|
||||
/>
|
||||
</template>
|
||||
@@ -1,10 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
interface CustomLabelProps {
|
||||
text: string
|
||||
}
|
||||
|
||||
const props = defineProps<CustomLabelProps>()
|
||||
</script>
|
||||
<template>
|
||||
<tspan dy="10" x="0">{{ props.text }}</tspan>
|
||||
</template>
|
||||
@@ -1,106 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
MiniMap,
|
||||
Controls,
|
||||
Background,
|
||||
Elements,
|
||||
FlowInstance,
|
||||
FlowElement,
|
||||
removeElements,
|
||||
Connection,
|
||||
Edge,
|
||||
addEdge,
|
||||
ArrowHeadType,
|
||||
} from '@braks/vue-flow'
|
||||
import CustomEdge from './CustomEdge.vue'
|
||||
import CustomEdge2 from './CustomEdge2.vue'
|
||||
import CustomLabel from './CustomLabel.vue'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', type: 'input', data: { label: 'Input 1' }, position: { x: 250, y: 0 } },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 150, y: 100 } },
|
||||
{ id: '2a', data: { label: 'Node 2a' }, position: { x: 0, y: 180 } },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 250, y: 200 } },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 300 } },
|
||||
{ id: '3a', data: { label: 'Node 3a' }, position: { x: 150, y: 300 } },
|
||||
{ id: '5', data: { label: 'Node 5' }, position: { x: 250, y: 400 } },
|
||||
{ id: '6', type: 'output', data: { label: 'Output 6' }, position: { x: 50, y: 550 } },
|
||||
{ id: '7', type: 'output', data: { label: 'Output 7' }, position: { x: 250, y: 550 } },
|
||||
{ id: '8', type: 'output', data: { label: 'Output 8' }, position: { x: 525, y: 600 } },
|
||||
{ id: '9', type: 'output', data: { label: 'Output 9' }, position: { x: 675, y: 500 } },
|
||||
{ id: 'e1-2', source: '1', target: '2', label: 'bezier edge (default)', class: 'normal-edge' },
|
||||
{ id: 'e2-2a', source: '2', target: '2a', type: 'smoothstep', label: 'smoothstep edge' },
|
||||
{ id: 'e2-3', source: '2', target: '3', type: 'step', label: 'step edge' },
|
||||
{ id: 'e3-4', source: '3', target: '4', type: 'straight', label: 'straight edge' },
|
||||
{ id: 'e3-3a', source: '3', target: '3a', type: 'straight', label: 'label only edge', style: { stroke: 'none' } },
|
||||
{ id: 'e3-5', source: '4', target: '5', animated: true, label: 'animated styled edge', style: { stroke: 'red' } },
|
||||
{
|
||||
id: 'e5-6',
|
||||
source: '5',
|
||||
target: '6',
|
||||
label: {
|
||||
component: CustomLabel,
|
||||
props: {
|
||||
text: 'custom label text',
|
||||
},
|
||||
},
|
||||
labelStyle: { fill: 'red', fontWeight: 700 },
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e5-7',
|
||||
source: '5',
|
||||
target: '7',
|
||||
label: 'label with styled bg',
|
||||
labelBgPadding: [8, 4],
|
||||
labelBgBorderRadius: 4,
|
||||
labelBgStyle: { fill: '#FFCC00', color: '#fff', fillOpacity: 0.7 },
|
||||
arrowHeadType: ArrowHeadType.ArrowClosed,
|
||||
},
|
||||
{
|
||||
id: 'e5-8',
|
||||
source: '5',
|
||||
target: '8',
|
||||
type: 'custom',
|
||||
data: { text: 'custom edge' },
|
||||
arrowHeadType: ArrowHeadType.ArrowClosed,
|
||||
},
|
||||
{
|
||||
id: 'e5-9',
|
||||
source: '5',
|
||||
target: '9',
|
||||
type: 'custom2',
|
||||
data: { text: 'custom edge 2' },
|
||||
},
|
||||
]
|
||||
|
||||
const edgeTypes: Record<string, any> = {
|
||||
custom: CustomEdge,
|
||||
custom2: CustomEdge2,
|
||||
}
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
|
||||
const onLoad = (flowInstance: FlowInstance) => flowInstance.fitView()
|
||||
const onNodeDragStop = (node: Node) => console.log('drag stop', node)
|
||||
const onElementClick = (element: FlowElement) => console.log('click', element)
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:snap-to-grid="true"
|
||||
:edge-types="edgeTypes"
|
||||
@element-click="onElementClick"
|
||||
@elements-remove="onElementsRemove"
|
||||
@connect="onConnect"
|
||||
@node-drag-stop="onNodeDragStop"
|
||||
@load="onLoad"
|
||||
>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
<Background />
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,54 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import {
|
||||
Flow,
|
||||
MiniMap,
|
||||
Controls,
|
||||
Background,
|
||||
BackgroundVariant,
|
||||
Connection,
|
||||
Edge,
|
||||
ElementId,
|
||||
Elements,
|
||||
FlowElement,
|
||||
Node,
|
||||
FlowInstance,
|
||||
addEdge,
|
||||
removeElements,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
const elements = ref<Elements>([])
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
|
||||
const onLoad = (flowInstance: FlowInstance) => console.log('flow loaded:', flowInstance)
|
||||
const onElementClick = (element: FlowElement) => console.log('click', element)
|
||||
const onNodeDragStop = (node: Node) => console.log('drag stop', node)
|
||||
|
||||
const buttonStyle: CSSProperties = { position: 'absolute', left: '10px', top: '10px', zIndex: 4 }
|
||||
const addRandomNode = () => {
|
||||
const nodeId: ElementId = (elements.value.length + 1).toString()
|
||||
const newNode: Node = {
|
||||
id: nodeId,
|
||||
data: { label: `Node: ${nodeId}` },
|
||||
position: { x: Math.random() * window.innerWidth, y: Math.random() * window.innerHeight },
|
||||
} as Node
|
||||
elements.value = [...elements.value, newNode]
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
@load="onLoad"
|
||||
@element-click="onElementClick"
|
||||
@elements-remove="onElementsRemove"
|
||||
@connect="(p) => onConnect(p)"
|
||||
@node-drag-stop="onNodeDragStop"
|
||||
>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
<Background :variant="BackgroundVariant.Lines" />
|
||||
|
||||
<button class="button" type="button" :style="buttonStyle" @click="addRandomNode">add node</button>
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,16 +0,0 @@
|
||||
<template>
|
||||
<header class="flex items-center py-4 px-8 text-white h-[92px]">
|
||||
<div class="flex flex-col">
|
||||
<a class="logo text-xl" href="https://github.com/bcakmakoglu/vue-flow"> Vue Flow </a>
|
||||
<span class="text-xs text-gray-800 mt-2"
|
||||
>An open source library by <a href="https://github.com/bcakmakoglu/bcakmakoglu">Braks</a> <br />
|
||||
Based on <a href="https://reactflow.dev">React Flow</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex-1">Docs</div>
|
||||
<div class="flex-1">
|
||||
<router-link to="/examples"> Examples </router-link>
|
||||
</div>
|
||||
<div class="flex-1"><a href="https://github.com/bcakmakoglu/vue-flow">Github</a></div>
|
||||
</header>
|
||||
</template>
|
||||
@@ -1,39 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { Flow, MiniMap, Controls, Connection, Edge, Elements, addEdge } from '@braks/vue-flow'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
|
||||
{ id: 'e1-2', source: '1', target: '2' },
|
||||
{ id: 'e1-3', source: '1', target: '3' },
|
||||
{ id: 'e3-4', source: '3', target: '4' },
|
||||
]
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const isHidden = ref<boolean>(false)
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
|
||||
watchEffect(() => {
|
||||
elements.value = elements.value.map((e) => {
|
||||
e.isHidden = isHidden.value
|
||||
return e
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" @connect="onConnect">
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
|
||||
<div :style="{ position: 'absolute', left: '10px', top: '10px', zIndex: 4 }">
|
||||
<div>
|
||||
<label for="ishidden">
|
||||
isHidden
|
||||
<input id="ishidden" v-model="isHidden" type="checkbox" class="vue-flow__ishidden" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,152 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
addEdge,
|
||||
MiniMap,
|
||||
Controls,
|
||||
Elements,
|
||||
Node,
|
||||
FlowElement,
|
||||
Connection,
|
||||
Edge,
|
||||
PanOnScrollMode,
|
||||
FlowTransform,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
|
||||
{ id: 'e1-2', source: '1', target: '2', animated: true },
|
||||
{ id: 'e1-3', source: '1', target: '3' },
|
||||
]
|
||||
|
||||
const onNodeDragStart = (_: MouseEvent, node: Node) => console.log('drag start', node)
|
||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node)
|
||||
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element)
|
||||
const onPaneClick = (event: MouseEvent) => console.log('onPaneClick', event)
|
||||
const onPaneScroll = (event?: WheelEvent) => console.log('onPaneScroll', event)
|
||||
const onPaneContextMenu = (event: MouseEvent) => console.log('onPaneContextMenu', event)
|
||||
const onMoveEnd = (flowTranasform?: FlowTransform) => console.log('onMoveEnd', flowTranasform)
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
|
||||
const isSelectable = ref(false)
|
||||
const isDraggable = ref(false)
|
||||
const isConnectable = ref(false)
|
||||
const zoomOnScroll = ref(false)
|
||||
const zoomOnPinch = ref(false)
|
||||
const panOnScroll = ref(false)
|
||||
const panOnScrollMode = ref<PanOnScrollMode>(PanOnScrollMode.Free)
|
||||
const zoomOnDoubleClick = ref(false)
|
||||
const paneMoveable = ref(true)
|
||||
const captureZoomClick = ref(false)
|
||||
const captureZoomScroll = ref(false)
|
||||
const captureElementClick = ref(false)
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:elements-selectable="isSelectable"
|
||||
:nodes-connectable="isConnectable"
|
||||
:nodes-draggable="isDraggable"
|
||||
:zoom-on-scroll="zoomOnScroll"
|
||||
:zoom-on-pinch="zoomOnPinch"
|
||||
:pan-on-scroll="panOnScroll"
|
||||
:pan-on-scroll-mode="panOnScrollMode"
|
||||
:zoom-on-double-click="zoomOnDoubleClick"
|
||||
:pane-moveable="paneMoveable"
|
||||
@connect="onConnect"
|
||||
@element-click="captureElementClick ? onElementClick : undefined"
|
||||
@node-drag-start="onNodeDragStart"
|
||||
@node-drag-stop="onNodeDragStop"
|
||||
@pane-click="captureZoomClick ? onPaneClick : undefined"
|
||||
@pane-scroll="captureZoomScroll ? onPaneScroll : undefined"
|
||||
@pane-context-menu="captureZoomClick ? onPaneContextMenu : undefined"
|
||||
@move-end="onMoveEnd"
|
||||
>
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
|
||||
<div :style="{ position: 'absolute', left: 10, top: 10, zIndex: 4 }">
|
||||
<div>
|
||||
<label for="draggable">
|
||||
nodesDraggable
|
||||
<input id="draggable" v-model="isDraggable" type="checkbox" class="vue-flow__draggable" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="connectable">
|
||||
nodesConnectable
|
||||
<input id="connectable" v-model="isConnectable" type="checkbox" class="vue-flow__connectable" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="selectable">
|
||||
elementsSelectable
|
||||
<input id="selectable" v-model="isSelectable" type="checkbox" class="vue-flow__selectable" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="zoomonscroll">
|
||||
zoomOnScroll
|
||||
<input id="zoomonscroll" v-model="zoomOnScroll" type="checkbox" class="vue-flow__zoomonscroll" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="zoomonpinch">
|
||||
zoomOnPinch
|
||||
<input id="zoomonpinch" v-model="zoomOnPinch" type="checkbox" class="vue-flow__zoomonpinch" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="panonscroll">
|
||||
panOnScroll
|
||||
<input id="panonscroll" v-model="panOnScroll" type="checkbox" class="vue-flow__panonscroll" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label>
|
||||
panOnScrollMode
|
||||
<select id="panonscrollmode" v-model="panOnScrollMode" class="vue-flow__panonscrollmode">
|
||||
<option value="free">free</option>
|
||||
<option value="horizontal">horizontal</option>
|
||||
<option value="vertical">vertical</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="zoomondbl">
|
||||
zoomOnDoubleClick
|
||||
<input id="zoomondbl" v-model="zoomOnDoubleClick" type="checkbox" class="vue-flow__zoomondbl" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="panemoveable">
|
||||
paneMoveable
|
||||
<input id="panemoveable" v-model="paneMoveable" type="checkbox" class="vue-flow__panemoveable" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="capturezoompaneclick">
|
||||
capture onPaneClick
|
||||
<input id="capturezoompaneclick" v-model="captureZoomClick" type="checkbox" class="vue-flow__capturezoompaneclick" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="capturezoompanescroll">
|
||||
capture onPaneScroll
|
||||
<input id="capturezoompanescroll" v-model="captureZoomScroll" type="checkbox" class="vue-flow__capturezoompanescroll" />
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="captureelementclick">
|
||||
capture onElementClick
|
||||
<input id="captureelementclick" v-model="captureElementClick" type="checkbox" class="vue-flow__captureelementclick" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,92 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import dagre from 'dagre'
|
||||
import {
|
||||
Flow,
|
||||
Controls,
|
||||
addEdge,
|
||||
ConnectionMode,
|
||||
Connection,
|
||||
Edge,
|
||||
Elements,
|
||||
isNode,
|
||||
NodeExtent,
|
||||
Position,
|
||||
removeElements,
|
||||
} from '@braks/vue-flow'
|
||||
import initialElements from './initial-elements'
|
||||
|
||||
const dagreGraph = new dagre.graphlib.Graph()
|
||||
dagreGraph.setDefaultEdgeLabel(() => ({}))
|
||||
|
||||
const nodeExtent: NodeExtent = [
|
||||
[0, 0],
|
||||
[1000, 1000],
|
||||
]
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge({ ...params, animated: true }, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
|
||||
// todo changing elements not properly updating flowchart...
|
||||
const onLayout = (direction: string) => {
|
||||
const isHorizontal = direction === 'LR'
|
||||
dagreGraph.setGraph({ rankdir: direction })
|
||||
|
||||
elements.value.forEach((el) => {
|
||||
if (isNode(el)) {
|
||||
dagreGraph.setNode(el.id, { width: 150, height: 50 })
|
||||
} else {
|
||||
dagreGraph.setEdge(el.source, el.target)
|
||||
}
|
||||
})
|
||||
|
||||
dagre.layout(dagreGraph)
|
||||
|
||||
elements.value = elements.value.map((el) => {
|
||||
if (isNode(el)) {
|
||||
const nodeWithPosition = dagreGraph.node(el.id)
|
||||
el.targetPosition = isHorizontal ? Position.Left : Position.Top
|
||||
el.sourcePosition = isHorizontal ? Position.Right : Position.Bottom
|
||||
el.position = { x: nodeWithPosition.x, y: nodeWithPosition.y }
|
||||
}
|
||||
|
||||
return el
|
||||
})
|
||||
console.log(elements.value)
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="layoutflow">
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:node-extent="nodeExtent"
|
||||
:connection-mode="ConnectionMode.Loose"
|
||||
@connect="onConnect"
|
||||
@clements-remove="onElementsRemove"
|
||||
@load="() => onLayout('TB')"
|
||||
>
|
||||
<Controls />
|
||||
</Flow>
|
||||
<div class="controls">
|
||||
<button class="button" :style="{ marginRight: 10 }" @click="() => onLayout('TB')">vertical layout</button>
|
||||
<button class="button" @click="() => onLayout('LR')">horizontal layout</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
.layoutflow {
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.layoutflow .controls {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.controls button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,71 +0,0 @@
|
||||
import { Elements, XYPosition } from '@braks/vue-flow'
|
||||
|
||||
const position: XYPosition = { x: 0, y: 0 }
|
||||
|
||||
const elements: Elements = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: { label: 'input' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
data: { label: 'node 2' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '2a',
|
||||
data: { label: 'node 2a' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '2b',
|
||||
data: { label: 'node 2b' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '2c',
|
||||
data: { label: 'node 2c' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '2d',
|
||||
data: { label: 'node 2d' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
data: { label: 'node 3' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
data: { label: 'node 4' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
data: { label: 'node 5' },
|
||||
position,
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
type: 'output',
|
||||
data: { label: 'output' },
|
||||
position,
|
||||
},
|
||||
{ id: '7', type: 'output', data: { label: 'output' }, position: { x: 400, y: 450 } },
|
||||
{ id: 'e12', source: '1', target: '2', type: 'smoothstep', animated: true },
|
||||
{ id: 'e13', source: '1', target: '3', type: 'smoothstep', animated: true },
|
||||
{ id: 'e22a', source: '2', target: '2a', type: 'smoothstep', animated: true },
|
||||
{ id: 'e22b', source: '2', target: '2b', type: 'smoothstep', animated: true },
|
||||
{ id: 'e22c', source: '2', target: '2c', type: 'smoothstep', animated: true },
|
||||
{ id: 'e2c2d', source: '2c', target: '2d', type: 'smoothstep', animated: true },
|
||||
|
||||
{ id: 'e45', source: '4', target: '5', type: 'smoothstep', animated: true },
|
||||
{ id: 'e56', source: '5', target: '6', type: 'smoothstep', animated: true },
|
||||
{ id: 'e57', source: '5', target: '7', type: 'smoothstep', animated: true },
|
||||
]
|
||||
|
||||
export default elements
|
||||
@@ -1,20 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { Flow, Background, Connection, Elements, Edge, removeElements, addEdge } from '@braks/vue-flow'
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 }, class: 'light' },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, class: 'light' },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, class: 'light' },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, class: 'light' },
|
||||
{ id: 'e1-2', source: '1', target: '2', animated: true },
|
||||
{ id: 'e1-3', source: '1', target: '3' },
|
||||
]
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" @elements-remove="onElementsRemove" @connect="onConnect">
|
||||
<Background />
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,24 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import Flow from './Flow.vue'
|
||||
</script>
|
||||
<template>
|
||||
<div class="vue-flow__example-multiflows flex-1">
|
||||
<Flow />
|
||||
<Flow />
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
.vue-flow__example-multiflows {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.vue-flow__example-multiflows .vue-flow {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.vue-flow__example-multiflows .vue-flow:first-child {
|
||||
border-right: 2px solid #333;
|
||||
}
|
||||
</style>
|
||||
@@ -1,47 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import { Flow, addEdge, Connection, Edge, Elements, isEdge, FlowInstance, Position } from '@braks/vue-flow'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{
|
||||
id: '1',
|
||||
sourcePosition: Position.Right,
|
||||
type: 'input',
|
||||
data: { label: 'Input' },
|
||||
position: { x: 0, y: 80 },
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'output',
|
||||
sourcePosition: Position.Right,
|
||||
targetPosition: Position.Left,
|
||||
data: { label: 'A Node' },
|
||||
position: { x: 250, y: 0 },
|
||||
},
|
||||
{ id: 'e1-2', source: '1', type: 'smoothstep', target: '2', animated: true },
|
||||
]
|
||||
|
||||
const buttonStyle: CSSProperties = { position: 'absolute', right: 10, top: 30, zIndex: 4 }
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
|
||||
const onLoad = (flowInstance: FlowInstance) => flowInstance.fitView()
|
||||
|
||||
const changeType = () => {
|
||||
elements.value = elements.value.map((el) => {
|
||||
if (isEdge(el) || el.type === 'input') return el
|
||||
|
||||
return {
|
||||
...el,
|
||||
type: el.type === 'default' ? 'output' : 'default',
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" @connect="onConnect" @load="onLoad">
|
||||
<button class="button mt-2" :style="buttonStyle" @click="changeType">change type</button>
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,11 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { NodeProps } from '@braks/vue-flow'
|
||||
|
||||
interface NodeAProps extends NodeProps {
|
||||
nodeStyles: Record<string, any>
|
||||
}
|
||||
const props = defineProps<NodeAProps>()
|
||||
</script>
|
||||
<template>
|
||||
<div :style="props.nodeStyles">A</div>
|
||||
</template>
|
||||
@@ -1,11 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { NodeProps } from '@braks/vue-flow'
|
||||
|
||||
interface NodeBPro extends NodeProps {
|
||||
nodeStyles: Record<string, any>
|
||||
}
|
||||
const props = defineProps<NodeBPro>()
|
||||
</script>
|
||||
<template>
|
||||
<div :style="props.nodeStyles">B</div>
|
||||
</template>
|
||||
@@ -1,60 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import { Flow, Elements, Position, NodeType, Connection, Edge, addEdge } from '@braks/vue-flow'
|
||||
import NodeA from './NodeA.vue'
|
||||
import NodeB from './NodeB.vue'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{
|
||||
id: '1',
|
||||
sourcePosition: Position.Right,
|
||||
type: 'input',
|
||||
data: { label: 'Input' },
|
||||
position: { x: 0, y: 80 },
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'a',
|
||||
sourcePosition: Position.Right,
|
||||
targetPosition: Position.Left,
|
||||
data: { label: 'A Node' },
|
||||
position: { x: 250, y: 0 },
|
||||
},
|
||||
]
|
||||
|
||||
const buttonStyle: CSSProperties = { position: 'absolute', right: 10, top: 30, zIndex: 4 }
|
||||
|
||||
const nodeStyles: CSSProperties = { padding: '10px 15px', border: '1px solid #ddd' }
|
||||
type NodeTypesObject = {
|
||||
[key: string]: Record<string, NodeType>
|
||||
}
|
||||
|
||||
const nodeTypesObjects: NodeTypesObject = {
|
||||
a: {
|
||||
a: NodeA as NodeType,
|
||||
},
|
||||
b: {
|
||||
b: NodeB as NodeType,
|
||||
},
|
||||
}
|
||||
|
||||
const elements = ref(initialElements)
|
||||
const nodeTypesId = ref('a')
|
||||
const changeType = () => {
|
||||
const id = nodeTypesId.value === 'a' ? 'b' : 'a'
|
||||
elements.value[1].type = id
|
||||
nodeTypesId.value = id
|
||||
}
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" :node-types="nodeTypesObjects[nodeTypesId]" :node-types-id="nodeTypesId" @connect="onConnect">
|
||||
<template #node-a>
|
||||
<NodeA :node-styles="nodeStyles" />
|
||||
</template>
|
||||
<template #node-b>
|
||||
<NodeB :node-styles="nodeStyles" />
|
||||
</template>
|
||||
<button class="button mt-2" :style="buttonStyle" @click="changeType">change type</button>
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,172 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import {
|
||||
Flow,
|
||||
removeElements,
|
||||
addEdge,
|
||||
MiniMap,
|
||||
Controls,
|
||||
Background,
|
||||
isNode,
|
||||
Node,
|
||||
Elements,
|
||||
FlowElement,
|
||||
FlowInstance,
|
||||
FlowTransform,
|
||||
SnapGrid,
|
||||
ArrowHeadType,
|
||||
Connection,
|
||||
Edge,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
const onNodeDragStart = (node: Node) => console.log('drag start', node)
|
||||
const onNodeDrag = (node: Node) => console.log('drag', node)
|
||||
const onNodeDragStop = (node: Node) => console.log('drag stop', node)
|
||||
const onNodeDoubleClick = (node: Node) => console.log('node double click', node)
|
||||
const onPaneClick = (event: MouseEvent) => console.log('pane click', event)
|
||||
const onPaneScroll = (event?: MouseEvent) => console.log('pane scroll', event)
|
||||
const onPaneContextMenu = (event: MouseEvent) => console.log('pane context menu', event)
|
||||
const onSelectionDrag = (nodes: Node[]) => console.log('selection drag', nodes)
|
||||
const onSelectionDragStart = (nodes: Node[]) => console.log('selection drag start', nodes)
|
||||
const onSelectionDragStop = (nodes: Node[]) => console.log('selection drag stop', nodes)
|
||||
const onSelectionContextMenu = (event: MouseEvent, nodes: Node[]) => {
|
||||
event.preventDefault()
|
||||
console.log('selection context menu', nodes)
|
||||
}
|
||||
const onElementClick = (element: FlowElement) => console.log(`${isNode(element) ? 'node' : 'edge'} click:`, element)
|
||||
const onSelectionChange = (elements: Elements | null) => console.log('selection change', elements)
|
||||
const onLoad = (flowInstance: FlowInstance) => {
|
||||
console.log('flow loaded:', flowInstance)
|
||||
flowInstance.fitView()
|
||||
}
|
||||
|
||||
const onMoveEnd = (transform?: FlowTransform) => console.log('zoom/move end', transform)
|
||||
const onEdgeContextMenu = (edge: Edge) => console.log('edge context menu', edge)
|
||||
const onEdgeMouseEnter = (edge: Edge) => console.log('edge mouse enter', edge)
|
||||
const onEdgeMouseMove = (edge: Edge) => console.log('edge mouse move', edge)
|
||||
const onEdgeMouseLeave = (edge: Edge) => console.log('edge mouse leave', edge)
|
||||
const onEdgeDoubleClick = (edge: Edge) => console.log('edge double click', edge)
|
||||
|
||||
const initialElements: Elements = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: {
|
||||
label: 'Welcome to <strong>Vue Flow!</strong>',
|
||||
},
|
||||
position: { x: 250, y: 0 },
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
data: {
|
||||
label: 'This is a <strong>default node</strong>',
|
||||
},
|
||||
position: { x: 100, y: 100 },
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
data: {
|
||||
label: 'This one has a <strong>custom style</strong>',
|
||||
},
|
||||
position: { x: 400, y: 100 },
|
||||
style: { background: '#D6D5E6', color: '#333', border: '1px solid #222138', width: 180 },
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
position: { x: 250, y: 200 },
|
||||
data: {
|
||||
label: `You can find the docs on
|
||||
<a href="https://github.com/bcakmakoglu/vue-flow" target="_blank" rel="noopener noreferrer">
|
||||
Github
|
||||
</a>`,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
data: {
|
||||
label: 'Or check out the other <strong>examples</strong>',
|
||||
},
|
||||
position: { x: 250, y: 325 },
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
type: 'output',
|
||||
data: {
|
||||
label: 'An <strong>output node</strong>',
|
||||
},
|
||||
position: { x: 100, y: 480 },
|
||||
},
|
||||
{ id: '7', type: 'output', data: { label: 'Another output node' }, position: { x: 400, y: 450 } },
|
||||
{ id: 'e1-2', source: '1', target: '2', label: 'this is an edge label' },
|
||||
{ id: 'e1-3', source: '1', target: '3' },
|
||||
{ id: 'e3-4', source: '3', target: '4', animated: true, label: 'animated edge' },
|
||||
{ id: 'e4-5', source: '4', target: '5', arrowHeadType: ArrowHeadType.Arrow, label: 'edge with arrow head' },
|
||||
{ id: 'e5-6', source: '5', target: '6', type: 'smoothstep', label: 'smooth step edge' },
|
||||
{
|
||||
id: 'e5-7',
|
||||
source: '5',
|
||||
target: '7',
|
||||
type: 'step',
|
||||
style: { stroke: '#f6ab6c' },
|
||||
label: 'a step edge',
|
||||
animated: true,
|
||||
labelStyle: { fill: '#f6ab6c', fontWeight: 700 },
|
||||
},
|
||||
]
|
||||
|
||||
const connectionLineStyle: CSSProperties = { stroke: '#ddd' }
|
||||
const snapGrid: SnapGrid = [16, 16]
|
||||
|
||||
const nodeStrokeColor = (n: Node): string => {
|
||||
if (n.style?.background) return n.style.background as string
|
||||
if (n.type === 'input') return '#0041d0'
|
||||
if (n.type === 'output') return '#ff0072'
|
||||
if (n.type === 'default') return '#1a192b'
|
||||
|
||||
return '#eee'
|
||||
}
|
||||
|
||||
const nodeColor = (n: Node): string => {
|
||||
if (n.style?.background) return n.style.background as string
|
||||
|
||||
return '#fff'
|
||||
}
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:connection-line-style="connectionLineStyle"
|
||||
:snap-to-grid="true"
|
||||
:snap-grid="snapGrid"
|
||||
@element-click="onElementClick"
|
||||
@elements-remove="onElementsRemove"
|
||||
@eonnect="onConnect"
|
||||
@pane-click="onPaneClick"
|
||||
@pane-scroll="onPaneScroll"
|
||||
@pane-contex-menu="onPaneContextMenu"
|
||||
@node-drag-start="onNodeDragStart"
|
||||
@node-drag="onNodeDrag"
|
||||
@node-drag-stop="onNodeDragStop"
|
||||
@node-double-click="onNodeDoubleClick"
|
||||
@selection-drag-start="onSelectionDragStart"
|
||||
@selection-drag="onSelectionDrag"
|
||||
@selection-drag-stop="onSelectionDragStop"
|
||||
@selection-context-menu="onSelectionContextMenu"
|
||||
@selection-change="onSelectionChange"
|
||||
@move-end="onMoveEnd"
|
||||
@load="onLoad"
|
||||
@edge-context-menu="onEdgeContextMenu"
|
||||
@edge-mouse-enter="onEdgeMouseEnter"
|
||||
@edge-mouse-move="onEdgeMouseMove"
|
||||
@edge-mouse-leave="onEdgeMouseLeave"
|
||||
@edge-double-click="onEdgeDoubleClick"
|
||||
>
|
||||
<MiniMap :node-stroke-color="nodeStrokeColor" :node-color="nodeColor" :node-border-radius="2" />
|
||||
<Controls />
|
||||
<Background color="#aaa" gap="20" />
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,97 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
addEdge,
|
||||
removeElements,
|
||||
Controls,
|
||||
FlowInstance,
|
||||
FlowElement,
|
||||
Connection,
|
||||
Edge,
|
||||
Elements,
|
||||
ConnectionMode,
|
||||
useStore,
|
||||
} from '@braks/vue-flow'
|
||||
import Sidebar from './Sidebar.vue'
|
||||
|
||||
const onElementClick = (element: FlowElement) => console.log('click', element)
|
||||
const onLoad = (flowInstance: FlowInstance) => console.log('flow loaded:', flowInstance)
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 } },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 } },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 } },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 } },
|
||||
{ id: 'e1-2', source: '1', target: '2', animated: true },
|
||||
{ id: 'e1-3', source: '1', target: '3' },
|
||||
]
|
||||
|
||||
useStore()
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<div class="providerflow">
|
||||
<Sidebar />
|
||||
<div class="vue-flow-wrapper">
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:connection-mode="ConnectionMode.Loose"
|
||||
@element-click="onElementClick"
|
||||
@connect="onConnect"
|
||||
@elements-remove="onElementsRemove"
|
||||
@load="onLoad"
|
||||
>
|
||||
<Controls />
|
||||
</Flow>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<style>
|
||||
.providerflow {
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.providerflow aside {
|
||||
border-right: 1px solid #eee;
|
||||
padding: 15px 10px;
|
||||
font-size: 12px;
|
||||
background: #fcfcfc;
|
||||
}
|
||||
|
||||
.providerflow aside .description {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.providerflow aside .title {
|
||||
font-weight: 700;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.providerflow aside .transform {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.providerflow .vue-flow-wrapper {
|
||||
flex-grow: 1;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.providerflow .selectall {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.providerflow {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.providerflow aside {
|
||||
max-width: 250px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,27 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { useStore } from '@braks/vue-flow'
|
||||
const store = useStore()
|
||||
|
||||
const nodes = computed(() => store.nodes)
|
||||
const transform = computed(() => store.transform)
|
||||
|
||||
const selectAll = () => {
|
||||
store.selectedElements = nodes.value
|
||||
store.unsetUserSelection()
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<aside>
|
||||
<div class="description">This is an example of how you can access the internal state outside of the Vue Flow component.</div>
|
||||
<div class="title">Zoom & pan transform</div>
|
||||
<div class="transform">{{ [transform[0].toFixed(2), transform[1].toFixed(2), transform[2].toFixed(2)] }}</div>
|
||||
<div class="title">Nodes</div>
|
||||
<div v-for="node of nodes" :key="node.id">
|
||||
Node {{ node.id }} - x: {{ node.__rf.position.x.toFixed(2) }}, y: {{ node.__rf.position.y.toFixed(2) }}
|
||||
</div>
|
||||
|
||||
<div class="selectall">
|
||||
<button class="button" @click="selectAll">select all nodes</button>
|
||||
</div>
|
||||
</aside>
|
||||
</template>
|
||||
@@ -1,60 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import localforage from 'localforage'
|
||||
import { useZoomPanHelper, FlowInstance, FlowExportObject, Node } from '@braks/vue-flow'
|
||||
|
||||
localforage.config({
|
||||
name: 'vue-flow',
|
||||
storeName: 'flows',
|
||||
})
|
||||
|
||||
const flowKey = 'example-flow'
|
||||
|
||||
const getNodeId = () => `randomnode_${+new Date()}`
|
||||
|
||||
const { transform } = useZoomPanHelper()
|
||||
|
||||
type ControlsProps = {
|
||||
flowInstance?: FlowInstance
|
||||
}
|
||||
|
||||
const props = defineProps<ControlsProps>()
|
||||
const emit = defineEmits(['restore', 'add'])
|
||||
|
||||
const onSave = () => {
|
||||
if (props.flowInstance) {
|
||||
const flow = props.flowInstance.toObject()
|
||||
localforage.setItem(flowKey, flow)
|
||||
}
|
||||
}
|
||||
|
||||
const onRestore = () => {
|
||||
const restoreFlow = async () => {
|
||||
const flow: FlowExportObject | null = await localforage.getItem(flowKey)
|
||||
|
||||
console.log(flow)
|
||||
if (flow) {
|
||||
const [x = 0, y = 0] = flow.position
|
||||
emit('restore', flow.elements ?? [])
|
||||
transform({ x, y, zoom: flow.zoom || 0 })
|
||||
}
|
||||
}
|
||||
|
||||
restoreFlow()
|
||||
}
|
||||
|
||||
const onAdd = () => {
|
||||
const newNode = {
|
||||
id: `random_node-${getNodeId()}`,
|
||||
data: { label: 'Added node' },
|
||||
position: { x: Math.random() * window.innerWidth - 100, y: Math.random() * window.innerHeight },
|
||||
} as Node
|
||||
emit('add', newNode)
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div class="save__controls">
|
||||
<button class="button" @click="onSave">save</button>
|
||||
<button class="button" @click="onRestore">restore</button>
|
||||
<button class="button" @click="onAdd">add node</button>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,37 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { Flow, addEdge, Connection, Node, Edge, Elements, FlowInstance, removeElements } from '@braks/vue-flow'
|
||||
import Controls from './Controls.vue'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', data: { label: 'Node 1' }, position: { x: 100, y: 100 } },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 200 } },
|
||||
{ id: 'e1-2', source: '1', target: '2' },
|
||||
]
|
||||
|
||||
const elements = ref(initialElements)
|
||||
const flowInstance = ref()
|
||||
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const onLoad = (instance: FlowInstance) => (flowInstance.value = instance)
|
||||
const onRestore = (els: Elements) => (elements.value = els)
|
||||
const onAdd = (el: Node) => (elements.value = elements.value.concat(el))
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" @elements-remove="onElementsRemove" @connect="onConnect" @load="onLoad">
|
||||
<Controls :flow-instance="flowInstance" @restore="onRestore" @add="onAdd" />
|
||||
</Flow>
|
||||
</template>
|
||||
<style>
|
||||
.save__controls {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
z-index: 4;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.save__controls button {
|
||||
margin-left: 5px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,126 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
const examples = [
|
||||
{
|
||||
path: '/',
|
||||
label: 'Overview',
|
||||
},
|
||||
{
|
||||
path: '/basic',
|
||||
label: 'Basic',
|
||||
},
|
||||
{
|
||||
path: '/custom-connectionline',
|
||||
label: 'Custom Connectionline',
|
||||
},
|
||||
{
|
||||
path: '/custom-node',
|
||||
label: 'Custom Node',
|
||||
},
|
||||
{
|
||||
path: '/drag-n-drop',
|
||||
label: 'Drag and Drop',
|
||||
},
|
||||
{
|
||||
path: '/edges',
|
||||
label: 'Edges',
|
||||
},
|
||||
{
|
||||
path: '/button-edge',
|
||||
label: 'Edge with Button',
|
||||
},
|
||||
{
|
||||
path: '/edge-types',
|
||||
label: 'Edge Types',
|
||||
},
|
||||
{
|
||||
path: '/empty',
|
||||
label: 'Empty',
|
||||
},
|
||||
{
|
||||
path: '/hidden',
|
||||
label: 'Hidden',
|
||||
},
|
||||
{
|
||||
path: '/interaction',
|
||||
label: 'Interaction',
|
||||
},
|
||||
{
|
||||
path: '/layouting',
|
||||
label: 'Layouting',
|
||||
},
|
||||
{
|
||||
path: '/multi-flows',
|
||||
label: 'Multi Flows',
|
||||
},
|
||||
{
|
||||
path: '/node-type-change',
|
||||
label: 'Node Type Change',
|
||||
},
|
||||
{
|
||||
path: '/node-types-id-change',
|
||||
label: 'Node Types ID Change',
|
||||
},
|
||||
{
|
||||
path: '/provider',
|
||||
label: 'Provider',
|
||||
},
|
||||
{
|
||||
path: '/save-restore',
|
||||
label: 'Save and Restore',
|
||||
},
|
||||
{
|
||||
path: '/stress',
|
||||
label: 'Stress',
|
||||
},
|
||||
{
|
||||
path: '/switch',
|
||||
label: 'Switch',
|
||||
},
|
||||
{
|
||||
path: '/unidirectional',
|
||||
label: 'Unidirectional',
|
||||
},
|
||||
{
|
||||
path: '/updatable-edge',
|
||||
label: 'Updatable Edge',
|
||||
},
|
||||
{
|
||||
path: '/update-node',
|
||||
label: 'Update Node',
|
||||
},
|
||||
{
|
||||
path: '/update-node-internals',
|
||||
label: 'Update Node Internals',
|
||||
},
|
||||
{
|
||||
path: '/validation',
|
||||
label: 'Validation',
|
||||
},
|
||||
{
|
||||
path: '/zoom-pan-helper',
|
||||
label: 'Zoom Pan Helper',
|
||||
},
|
||||
]
|
||||
</script>
|
||||
<template>
|
||||
<aside>
|
||||
<div class="flex flex-col justify-center items-start">
|
||||
<router-link v-for="(example, i) of examples" :key="`example-link-${i}`" class="example-link" :to="example.path">
|
||||
{{ example.label }}
|
||||
</router-link>
|
||||
</div>
|
||||
<slot></slot>
|
||||
</aside>
|
||||
</template>
|
||||
<style>
|
||||
.example-link {
|
||||
@apply text-lg text-white hover:text-black py-2 underline;
|
||||
}
|
||||
aside {
|
||||
border-right: 1px solid #eee;
|
||||
padding: 15px 10px;
|
||||
height: 100%; /* Full-height: remove this if you want "auto" height */
|
||||
width: 280px; /* Set the width of the sidebar */
|
||||
overflow-x: hidden; /* Disable horizontal scroll */
|
||||
}
|
||||
</style>
|
||||
@@ -1,90 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import {
|
||||
Flow,
|
||||
removeElements,
|
||||
addEdge,
|
||||
MiniMap,
|
||||
isNode,
|
||||
Controls,
|
||||
Background,
|
||||
FlowInstance,
|
||||
Elements,
|
||||
Connection,
|
||||
Edge,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
function getElements(xElements = 10, yElements = 10): Elements {
|
||||
const initialElements = []
|
||||
let nodeId = 1
|
||||
let recentNodeId = null
|
||||
|
||||
for (let y = 0; y < yElements; y++) {
|
||||
for (let x = 0; x < xElements; x++) {
|
||||
const position = { x: x * 100, y: y * 50 }
|
||||
const data = { label: `Node ${nodeId}` }
|
||||
const node = {
|
||||
id: nodeId.toString(),
|
||||
style: { width: 50, fontSize: 11 },
|
||||
data,
|
||||
position,
|
||||
}
|
||||
initialElements.push(node)
|
||||
|
||||
if (recentNodeId && nodeId <= xElements * yElements) {
|
||||
initialElements.push({ id: `${x}-${y}`, source: recentNodeId.toString(), target: nodeId.toString() })
|
||||
}
|
||||
|
||||
recentNodeId = nodeId
|
||||
nodeId++
|
||||
}
|
||||
}
|
||||
|
||||
return initialElements
|
||||
}
|
||||
|
||||
const buttonWrapperStyles: CSSProperties = { position: 'absolute', right: 10, top: 10, zIndex: 4 }
|
||||
|
||||
const onLoad = (flowInstance: FlowInstance) => {
|
||||
flowInstance.fitView()
|
||||
console.log(flowInstance.getElements())
|
||||
}
|
||||
|
||||
const initialElements: Elements = getElements(10, 10)
|
||||
const elements = ref(initialElements)
|
||||
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
const updatePos = () => {
|
||||
elements.value = elements.value.map((el) => {
|
||||
if (isNode(el)) {
|
||||
return {
|
||||
...el,
|
||||
position: {
|
||||
x: Math.random() * window.innerWidth,
|
||||
y: Math.random() * window.innerHeight,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return el
|
||||
})
|
||||
}
|
||||
|
||||
const updateElements = () => {
|
||||
const grid = Math.ceil(Math.random() * 10)
|
||||
elements.value = getElements(grid, grid)
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" @load="onLoad" @elementsRemove="onElementsRemove" @connect="onConnect">
|
||||
<MiniMap />
|
||||
<Controls />
|
||||
<Background />
|
||||
|
||||
<div :style="buttonWrapperStyles">
|
||||
<button style="margin-right: 5px" @click="updatePos">change pos</button>
|
||||
<button @click="updateElements">update elements</button>
|
||||
</div>
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,47 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { Flow, removeElements, addEdge, Node, FlowElement, Elements, Connection, Edge } from '@braks/vue-flow'
|
||||
|
||||
const onNodeDragStop = (_: MouseEvent, node: Node) => console.log('drag stop', node)
|
||||
const onElementClick = (_: MouseEvent, element: FlowElement) => console.log('click', element)
|
||||
|
||||
const elementsA: Elements = [
|
||||
{ id: '1a', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 }, class: 'light' },
|
||||
{ id: '2a', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, class: 'light' },
|
||||
{ id: '3a', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, class: 'light' },
|
||||
{ id: '4a', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, class: 'light' },
|
||||
{ id: 'e1-2', source: '1a', target: '2a' },
|
||||
{ id: 'e1-3', source: '1a', target: '3a' },
|
||||
]
|
||||
|
||||
const elementsB: Elements = [
|
||||
{ id: 'inputb', type: 'input', data: { label: 'Input' }, position: { x: 300, y: 5 }, class: 'light' },
|
||||
{ id: '1b', data: { label: 'Node 1' }, position: { x: 0, y: 100 }, class: 'light' },
|
||||
{ id: '2b', data: { label: 'Node 2' }, position: { x: 200, y: 100 }, class: 'light' },
|
||||
{ id: '3b', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, class: 'light' },
|
||||
{ id: '4b', data: { label: 'Node 4' }, position: { x: 600, y: 100 }, class: 'light' },
|
||||
|
||||
{ id: 'e1b', source: 'inputb', target: '1b' },
|
||||
{ id: 'e2b', source: 'inputb', target: '2b' },
|
||||
{ id: 'e3b', source: 'inputb', target: '3b' },
|
||||
{ id: 'e4b', source: 'inputb', target: '4b' },
|
||||
]
|
||||
|
||||
const elements = ref(elementsA)
|
||||
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
@element-click="onElementClick"
|
||||
@elements-remove="onElementsRemove"
|
||||
@connect="onConnect"
|
||||
@node-drag-stop="onNodeDragStop"
|
||||
>
|
||||
<div :style="{ position: 'absolute', right: '10px', top: '10px', zIndex: 4 }">
|
||||
<button class="button" style="margin-right: 5px" @click="() => (elements = elementsA)">flow a</button>
|
||||
<button class="button" @click="() => (elements = elementsB)">flow b</button>
|
||||
</div>
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,19 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import { Handle, NodeProps, Position } from '@braks/vue-flow'
|
||||
|
||||
interface CustomNodeProps extends NodeProps {
|
||||
id: string
|
||||
}
|
||||
const props = defineProps<CustomNodeProps>()
|
||||
const nodeStyles: CSSProperties = { padding: '10px 15px', border: '1px solid #ddd' }
|
||||
</script>
|
||||
<template>
|
||||
<div :style="nodeStyles">
|
||||
<div>node {{ props.id }}</div>
|
||||
<Handle id="left" type="source" :position="Position.Left" />
|
||||
<Handle id="right" type="source" :position="Position.Right" />
|
||||
<Handle id="top" type="source" :position="Position.Top" />
|
||||
<Handle id="bottom" type="source" :position="Position.Bottom" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,205 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
NodeType,
|
||||
addEdge,
|
||||
useZoomPanHelper,
|
||||
Elements,
|
||||
Connection,
|
||||
Edge,
|
||||
ElementId,
|
||||
Node,
|
||||
ConnectionLineType,
|
||||
ConnectionMode,
|
||||
updateEdge,
|
||||
ArrowHeadType,
|
||||
} from '@braks/vue-flow'
|
||||
import CustomNode from './CustomNode.vue'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{
|
||||
id: '00',
|
||||
type: 'custom',
|
||||
position: { x: 300, y: 250 },
|
||||
},
|
||||
{
|
||||
id: '01',
|
||||
type: 'custom',
|
||||
position: { x: 100, y: 50 },
|
||||
},
|
||||
{
|
||||
id: '02',
|
||||
type: 'custom',
|
||||
position: { x: 500, y: 50 },
|
||||
},
|
||||
{
|
||||
id: '03',
|
||||
type: 'custom',
|
||||
position: { x: 500, y: 500 },
|
||||
},
|
||||
{
|
||||
id: '04',
|
||||
type: 'custom',
|
||||
position: { x: 100, y: 500 },
|
||||
},
|
||||
{
|
||||
id: '10',
|
||||
type: 'custom',
|
||||
position: { x: 300, y: 5 },
|
||||
},
|
||||
{
|
||||
id: '20',
|
||||
type: 'custom',
|
||||
position: { x: 600, y: 250 },
|
||||
},
|
||||
{
|
||||
id: '30',
|
||||
type: 'custom',
|
||||
position: { x: 300, y: 600 },
|
||||
},
|
||||
{
|
||||
id: '40',
|
||||
type: 'custom',
|
||||
position: { x: 5, y: 250 },
|
||||
},
|
||||
{
|
||||
id: 'e0-1a',
|
||||
source: '00',
|
||||
target: '01',
|
||||
sourceHandle: 'left',
|
||||
targetHandle: 'bottom',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-1b',
|
||||
source: '00',
|
||||
target: '01',
|
||||
sourceHandle: 'top',
|
||||
targetHandle: 'right',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-2a',
|
||||
source: '00',
|
||||
target: '02',
|
||||
sourceHandle: 'top',
|
||||
targetHandle: 'left',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-2b',
|
||||
source: '00',
|
||||
target: '02',
|
||||
sourceHandle: 'right',
|
||||
targetHandle: 'bottom',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-3a',
|
||||
source: '00',
|
||||
target: '03',
|
||||
sourceHandle: 'right',
|
||||
targetHandle: 'top',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-3b',
|
||||
source: '00',
|
||||
target: '03',
|
||||
sourceHandle: 'bottom',
|
||||
targetHandle: 'left',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-4a',
|
||||
source: '00',
|
||||
target: '04',
|
||||
sourceHandle: 'bottom',
|
||||
targetHandle: 'right',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-4b',
|
||||
source: '00',
|
||||
target: '04',
|
||||
sourceHandle: 'left',
|
||||
targetHandle: 'top',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-10',
|
||||
source: '00',
|
||||
target: '10',
|
||||
sourceHandle: 'top',
|
||||
targetHandle: 'bottom',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-20',
|
||||
source: '00',
|
||||
target: '20',
|
||||
sourceHandle: 'right',
|
||||
targetHandle: 'left',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-30',
|
||||
source: '00',
|
||||
target: '30',
|
||||
sourceHandle: 'bottom',
|
||||
targetHandle: 'top',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
{
|
||||
id: 'e0-40',
|
||||
source: '00',
|
||||
target: '40',
|
||||
sourceHandle: 'left',
|
||||
targetHandle: 'right',
|
||||
type: 'smoothstep',
|
||||
arrowHeadType: ArrowHeadType.Arrow,
|
||||
},
|
||||
]
|
||||
|
||||
const nodeTypes: Record<string, NodeType> = {
|
||||
custom: CustomNode as NodeType,
|
||||
}
|
||||
|
||||
let id = 4
|
||||
const getId = (): ElementId => `${id++}`
|
||||
|
||||
const elements = ref(initialElements)
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge({ ...params, type: 'smoothstep' }, elements.value))
|
||||
const { project } = useZoomPanHelper()
|
||||
const onEdgeUpdate = (oldEdge: Edge, newConnection: Connection) =>
|
||||
(elements.value = updateEdge(oldEdge, newConnection, elements.value))
|
||||
|
||||
const onPaneClick = (evt: MouseEvent) =>
|
||||
(elements.value = elements.value.concat({
|
||||
id: getId(),
|
||||
position: project({ x: evt.clientX, y: evt.clientY - 40 }),
|
||||
type: 'custom',
|
||||
} as Node))
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:node-types="nodeTypes"
|
||||
:connection-line-type="ConnectionLineType.SmoothStep"
|
||||
:connection-mode="ConnectionMode.Loose"
|
||||
@connect="onConnect"
|
||||
@pane-click="onPaneClick"
|
||||
@edge-pdate="onEdgeUpdate"
|
||||
/>
|
||||
</template>
|
||||
@@ -1,89 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
Controls,
|
||||
updateEdge,
|
||||
addEdge,
|
||||
Elements,
|
||||
FlowInstance,
|
||||
Connection,
|
||||
Edge,
|
||||
removeElements,
|
||||
FlowEvents,
|
||||
ConnectionMode,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'input',
|
||||
data: {
|
||||
label: 'Node <strong>A</strong>',
|
||||
},
|
||||
position: { x: 250, y: 0 },
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
data: {
|
||||
label: 'Node <strong>B</strong>',
|
||||
},
|
||||
position: { x: 100, y: 100 },
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
data: {
|
||||
label: 'Node <strong>C</strong>',
|
||||
},
|
||||
position: { x: 400, y: 100 },
|
||||
style: { background: '#D6D5E6', color: '#333', border: '1px solid #222138', width: 180 },
|
||||
},
|
||||
{ id: 'e1-2', source: '1', target: '2', label: 'Updateable edge' },
|
||||
]
|
||||
|
||||
const elements = ref(initialElements)
|
||||
const onLoad = (flowInstance: FlowInstance) => flowInstance.fitView()
|
||||
const onEdgeUpdateStart = (edge: Edge) => console.log('start update', edge)
|
||||
const onEdgeUpdateEnd = (edge: Edge) => console.log('end update', edge)
|
||||
const onEdgeUpdate = ({ edge, connection }: FlowEvents['edgeUpdate']) =>
|
||||
(elements.value = updateEdge(edge, connection, elements.value))
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:snap-to-grid="true"
|
||||
:connection-mode="ConnectionMode.Loose"
|
||||
@load="onLoad"
|
||||
@edge-update="onEdgeUpdate"
|
||||
@connect="onConnect"
|
||||
@edge-update-start="onEdgeUpdateStart"
|
||||
@elements-remove="onElementsRemove"
|
||||
@edge-update-end="onEdgeUpdateEnd"
|
||||
>
|
||||
<Controls />
|
||||
</Flow>
|
||||
</template>
|
||||
<style>
|
||||
.updatenode__controls {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
z-index: 4;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.updatenode__controls label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.updatenode__bglabel {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.updatenode__checkboxwrapper {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,73 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { Flow, Elements } from '@braks/vue-flow'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', data: { label: '-' }, position: { x: 100, y: 100 } },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 200 } },
|
||||
{ id: 'e1-2', source: '1', target: '2' },
|
||||
]
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const nodeName = ref<string>('Node 1')
|
||||
const nodeBg = ref<string>('#eee')
|
||||
const nodeHidden = ref<boolean>(false)
|
||||
|
||||
const updateNode = () => {
|
||||
elements.value = elements.value.map((el) => {
|
||||
if (el.id === '1') {
|
||||
// it's important that you create a new object here in order to notify react flow about the change
|
||||
el.data = {
|
||||
...el.data,
|
||||
label: nodeName.value,
|
||||
}
|
||||
el.style = { backgroundColor: nodeBg.value }
|
||||
el.isHidden = nodeHidden.value
|
||||
}
|
||||
|
||||
return el
|
||||
})
|
||||
}
|
||||
|
||||
watchEffect(() => {
|
||||
updateNode()
|
||||
})
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" :default-zoom="1.5" :min-zoom="0.2" :max-zoom="4">
|
||||
<div class="updatenode__controls p-4 bg-gray-300 rounded-xl">
|
||||
<label>label:</label>
|
||||
<input v-model="nodeName" />
|
||||
|
||||
<label class="updatenode__bglabel">background:</label>
|
||||
<input v-model="nodeBg" type="color" />
|
||||
|
||||
<div class="updatenode__checkboxwrapper">
|
||||
<label>hidden:</label>
|
||||
<input v-model="nodeHidden" type="checkbox" />
|
||||
</div>
|
||||
</div>
|
||||
</Flow>
|
||||
</template>
|
||||
<style>
|
||||
.updatenode__controls {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
z-index: 4;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.updatenode__controls label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.updatenode__bglabel {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.updatenode__checkboxwrapper {
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -1,25 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import { Handle, Position, NodeProps } from '@braks/vue-flow'
|
||||
|
||||
interface CustomNodeProps extends NodeProps {
|
||||
data: any
|
||||
}
|
||||
const nodeStyles: CSSProperties = { padding: 10, border: '1px solid #ddd' }
|
||||
|
||||
const props = defineProps<CustomNodeProps>()
|
||||
</script>
|
||||
<template>
|
||||
<div :style="nodeStyles">
|
||||
<Handle type="target" :position="Position.Left" />
|
||||
<div>output handle count: {{ props.data.handleCount }}</div>
|
||||
<Handle
|
||||
v-for="i of props.data.handleCount"
|
||||
:id="`handle-${i}`"
|
||||
:key="`handle-${i}`"
|
||||
type="source"
|
||||
:position="Position.Right"
|
||||
:style="{ top: 10 * i + props.data.handlePosition * 10 }"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,83 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { CSSProperties } from 'vue'
|
||||
import {
|
||||
Flow,
|
||||
NodeType,
|
||||
addEdge,
|
||||
useZoomPanHelper,
|
||||
Node,
|
||||
Elements,
|
||||
Connection,
|
||||
Edge,
|
||||
ElementId,
|
||||
Position,
|
||||
isEdge,
|
||||
FlowInstance,
|
||||
} from '@braks/vue-flow'
|
||||
import CustomNode from './CustomNode.vue'
|
||||
|
||||
const initialHandleCount = 1
|
||||
|
||||
const initialElements: Elements = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'custom',
|
||||
data: { label: 'Node 1', handleCount: initialHandleCount, handlePosition: 0 },
|
||||
position: { x: 250, y: 5 },
|
||||
},
|
||||
]
|
||||
|
||||
const buttonWrapperStyles: CSSProperties = { position: 'absolute', right: '10px', top: '10px', zIndex: 10 }
|
||||
|
||||
const nodeTypes: Record<string, NodeType> = {
|
||||
custom: CustomNode as NodeType,
|
||||
}
|
||||
|
||||
let id = 5
|
||||
const getId = (): ElementId => `${id++}`
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const flowInstance = ref<FlowInstance>()
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const { project } = useZoomPanHelper()
|
||||
|
||||
const onPaneClick = (evt: MouseEvent) =>
|
||||
(elements.value = elements.value.concat({
|
||||
id: getId(),
|
||||
position: project({ x: evt.clientX, y: evt.clientY - 40 }),
|
||||
data: { label: 'new node' },
|
||||
targetPosition: Position.Left,
|
||||
sourcePosition: Position.Right,
|
||||
} as Node))
|
||||
|
||||
const toggleHandleCount = () =>
|
||||
(elements.value = elements.value.map((el) => {
|
||||
if (isEdge(el)) {
|
||||
return el
|
||||
}
|
||||
|
||||
return { ...el, data: { ...el.data, handleCount: el.data?.handleCount === 1 ? 2 : 1 } }
|
||||
}))
|
||||
|
||||
const toggleHandlePosition = () =>
|
||||
(elements.value = elements.value.map((el) => {
|
||||
if (isEdge(el)) return el
|
||||
return { ...el, data: { ...el.data, handlePosition: el.data?.handlePosition === 0 ? 1 : 0 } }
|
||||
}))
|
||||
|
||||
const onLoad = (instance: FlowInstance) => {
|
||||
instance.fitView()
|
||||
flowInstance.value = instance
|
||||
}
|
||||
|
||||
const updateNodeInternals = () => flowInstance.value?.updateNodeInternals('1')
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" :node-types="nodeTypes" @connect="onConnect" @pane-click="onPaneClick" @load="onLoad">
|
||||
<div :style="buttonWrapperStyles">
|
||||
<button class="button" @click="toggleHandleCount">toggle handle count</button>
|
||||
<button class="button" @click="toggleHandlePosition">toggle handle position</button>
|
||||
<button class="button" @click="updateNodeInternals">update node internals</button>
|
||||
</div>
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,9 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { Position, Handle, Connection } from '@braks/vue-flow'
|
||||
|
||||
const isValidConnection = (connection: Connection) => connection.target === 'B'
|
||||
</script>
|
||||
<template>
|
||||
<div>Only connectable with B</div>
|
||||
<Handle type="source" :position="Position.Right" :is-valid-connection="isValidConnection" />
|
||||
</template>
|
||||
@@ -1,16 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import { Position, Handle, Connection, NodeProps } from '@braks/vue-flow'
|
||||
|
||||
interface CustomNodeProps extends NodeProps {
|
||||
id: string
|
||||
}
|
||||
|
||||
const props = defineProps<CustomNodeProps>()
|
||||
|
||||
const isValidConnection = (connection: Connection) => connection.target === 'B'
|
||||
</script>
|
||||
<template>
|
||||
<Handle type="target" :position="Position.Left" :is-valid-connection="isValidConnection" />
|
||||
<div>{{ props.id }}</div>
|
||||
<Handle type="source" :position="Position.Right" :is-valid-connection="isValidConnection" />
|
||||
</template>
|
||||
@@ -1,84 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
addEdge,
|
||||
Handle,
|
||||
Connection,
|
||||
Position,
|
||||
Elements,
|
||||
Edge,
|
||||
OnConnectStartParams,
|
||||
NodeProps,
|
||||
FlowInstance,
|
||||
NodeType,
|
||||
} from '@braks/vue-flow'
|
||||
import CustomInput from './CustomInput.vue'
|
||||
import CustomNode from './CustomNode.vue'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '0', type: 'custominput', position: { x: 0, y: 150 } },
|
||||
{ id: 'A', type: 'customnode', position: { x: 250, y: 0 } },
|
||||
{ id: 'B', type: 'customnode', position: { x: 250, y: 150 } },
|
||||
{ id: 'C', type: 'customnode', position: { x: 250, y: 300 } },
|
||||
]
|
||||
|
||||
const onLoad = (reactFlowInstance: FlowInstance) => reactFlowInstance.fitView()
|
||||
const onConnectStart = ({ nodeId, handleType }: OnConnectStartParams) => console.log('on connect start', { nodeId, handleType })
|
||||
const onConnectStop = (event: MouseEvent) => console.log('on connect stop', event)
|
||||
const onConnectEnd = (event: MouseEvent) => console.log('on connect end', event)
|
||||
|
||||
const elements = ref<Elements>(initialElements)
|
||||
const onConnect = (params: Connection | Edge) => {
|
||||
console.log('on connect', params)
|
||||
elements.value = addEdge(params, elements.value)
|
||||
}
|
||||
const nodeTypes: Record<string, NodeType> = {
|
||||
custominput: CustomInput as NodeType,
|
||||
customnode: CustomNode as NodeType,
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Flow
|
||||
:elements="elements"
|
||||
:select-nodes-on-drag="false"
|
||||
class="validationflow"
|
||||
:node-types="nodeTypes"
|
||||
@connect="onConnect"
|
||||
@oad="onLoad"
|
||||
@connect-start="onConnectStart"
|
||||
@connect-stop="onConnectStop"
|
||||
@connect-end="onConnectEnd"
|
||||
/>
|
||||
</template>
|
||||
<style>
|
||||
.validationflow .vue-flow__node {
|
||||
width: 150px;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
color: #555;
|
||||
border: 1px solid #ddd;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.validationflow .vue-flow__node-customnode {
|
||||
background: #e6e6e9;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.vue-flow__node-custominput .vue-flow__handle {
|
||||
background: #e6e6e9;
|
||||
}
|
||||
|
||||
.validationflow .vue-flow__node-custominput {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.validationflow .vue-flow__handle-connecting {
|
||||
background: #ff6060;
|
||||
}
|
||||
|
||||
.validationflow .vue-flow__handle-valid {
|
||||
background: #55dd99;
|
||||
}
|
||||
</style>
|
||||
@@ -1,51 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {
|
||||
Flow,
|
||||
removeElements,
|
||||
addEdge,
|
||||
Background,
|
||||
MiniMap,
|
||||
useZoomPanHelper,
|
||||
Elements,
|
||||
ElementId,
|
||||
Connection,
|
||||
Edge,
|
||||
Node,
|
||||
} from '@braks/vue-flow'
|
||||
|
||||
const initialElements: Elements = [
|
||||
{ id: '1', type: 'input', data: { label: 'Node 1' }, position: { x: 250, y: 5 }, class: 'light' },
|
||||
{ id: '2', data: { label: 'Node 2' }, position: { x: 100, y: 100 }, class: 'light' },
|
||||
{ id: '3', data: { label: 'Node 3' }, position: { x: 400, y: 100 }, class: 'light' },
|
||||
{ id: '4', data: { label: 'Node 4' }, position: { x: 400, y: 200 }, class: 'light' },
|
||||
{ id: 'e1-2', source: '1', target: '2', animated: true },
|
||||
{ id: 'e1-3', source: '1', target: '3' },
|
||||
]
|
||||
|
||||
let id = 5
|
||||
const getId = (): ElementId => `${id++}`
|
||||
|
||||
const { project } = useZoomPanHelper()
|
||||
|
||||
const elements = ref(initialElements)
|
||||
|
||||
const onPaneClick = (evt: MouseEvent) => {
|
||||
const projectedPosition = project({ x: evt.clientX, y: evt.clientY - 40 })
|
||||
|
||||
elements.value = elements.value.concat({
|
||||
id: getId(),
|
||||
position: projectedPosition,
|
||||
data: {
|
||||
label: `${projectedPosition.x}-${projectedPosition.y}`,
|
||||
},
|
||||
} as Node)
|
||||
}
|
||||
const onConnect = (params: Connection | Edge) => (elements.value = addEdge(params, elements.value))
|
||||
const onElementsRemove = (elementsToRemove: Elements) => (elements.value = removeElements(elementsToRemove, elements.value))
|
||||
</script>
|
||||
<template>
|
||||
<Flow :elements="elements" @elements-remove="onElementsRemove" @connect="onConnect" @pane-click="onPaneClick">
|
||||
<Background />
|
||||
<MiniMap />
|
||||
</Flow>
|
||||
</template>
|
||||
@@ -1,108 +0,0 @@
|
||||
#root{
|
||||
text-transform: uppercase;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
margin-top: 60px;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#root{
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
margin: 0;
|
||||
color: #111;
|
||||
overflow: hidden;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url('./polygon-scatter.svg');
|
||||
}
|
||||
|
||||
.backround-img {
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url('./polygon-scatter.svg');
|
||||
}
|
||||
|
||||
#root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
header {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.logo {
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
header a:hover {
|
||||
color: #c9c9c9;
|
||||
}
|
||||
|
||||
header select {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.overview-example__add {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vue-flow__node a {
|
||||
font-weight: 700;
|
||||
color: #111;
|
||||
}
|
||||
|
||||
.vue-flow__node.dark-node {
|
||||
background: #0041d0;
|
||||
color: #f8f8f8;
|
||||
}
|
||||
|
||||
.vue-flow__node.dark {
|
||||
background: #557;
|
||||
color: #f8f8f8;
|
||||
}
|
||||
|
||||
.vue-flow__node-selectorNode {
|
||||
font-size: 14px;
|
||||
background: #f0f2f3;
|
||||
border: 1px solid #555;
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.vue-flow__node-selectorNode .vue-flow__handle {
|
||||
border-color: #f0f2f3;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.overview-example__add {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.edgebutton {
|
||||
border-radius: 999px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.edgebutton:hover {
|
||||
box-shadow: 0 0 0 2px pink , 0 0 0 4px #f05f75;
|
||||
}
|
||||
|
||||
#vue-flow-docs {
|
||||
display: flex;
|
||||
margin:0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.button {
|
||||
@apply bg-gray-200 hover:bg-gray-300 focus:outline-none font-bold mr-2 border-2 p-2 rounded-xl;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
<svg id="visual" viewBox="0 0 960 540" width="960" height="540" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1"><rect width="960" height="540" fill="#31475e"></rect><g><g transform="translate(57 45)"><path d="M0 -106.9L83.6 -66.7L104.2 23.8L46.4 96.3L-46.4 96.3L-104.2 23.8L-83.6 -66.7Z" fill="#3fb984"></path></g><g transform="translate(708 88)"><path d="M0 -66L51.6 -41.2L64.3 14.7L28.6 59.5L-28.6 59.5L-64.3 14.7L-51.6 -41.2Z" fill="#3fb984"></path></g><g transform="translate(823 510)"><path d="M0 -77L60.2 -48L75.1 17.1L33.4 69.4L-33.4 69.4L-75.1 17.1L-60.2 -48Z" fill="#3fb984"></path></g><g transform="translate(896 280)"><path d="M0 -45L35.2 -28.1L43.9 10L19.5 40.5L-19.5 40.5L-43.9 10L-35.2 -28.1Z" fill="#3fb984"></path></g><g transform="translate(287 458)"><path d="M0 -58L45.3 -36.2L56.5 12.9L25.2 52.3L-25.2 52.3L-56.5 12.9L-45.3 -36.2Z" fill="#3fb984"></path></g><g transform="translate(12 380)"><path d="M0 -101L79 -63L98.5 22.5L43.8 91L-43.8 91L-98.5 22.5L-79 -63Z" fill="#3fb984"></path></g><g transform="translate(609 440)"><path d="M0 -60L46.9 -37.4L58.5 13.4L26 54.1L-26 54.1L-58.5 13.4L-46.9 -37.4Z" fill="#3fb984"></path></g><g transform="translate(457 42)"><path d="M0 -81L63.3 -50.5L79 18L35.1 73L-35.1 73L-79 18L-63.3 -50.5Z" fill="#3fb984"></path></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
Vendored
-50
@@ -1,50 +0,0 @@
|
||||
// Generated by 'unplugin-auto-import'
|
||||
// We suggest you to commit this file into source control
|
||||
declare global {
|
||||
const computed: typeof import('vue')['computed']
|
||||
const createApp: typeof import('vue')['createApp']
|
||||
const customRef: typeof import('vue')['customRef']
|
||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||
const defineComponent: typeof import('vue')['defineComponent']
|
||||
const effectScope: typeof import('vue')['effectScope']
|
||||
const EffectScope: typeof import('vue')['EffectScope']
|
||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||
const h: typeof import('vue')['h']
|
||||
const inject: typeof import('vue')['inject']
|
||||
const isReadonly: typeof import('vue')['isReadonly']
|
||||
const isRef: typeof import('vue')['isRef']
|
||||
const markRaw: typeof import('vue')['markRaw']
|
||||
const nextTick: typeof import('vue')['nextTick']
|
||||
const onActivated: typeof import('vue')['onActivated']
|
||||
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
||||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
||||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
||||
const onDeactivated: typeof import('vue')['onDeactivated']
|
||||
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
||||
const onMounted: typeof import('vue')['onMounted']
|
||||
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
||||
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
||||
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||
const onUpdated: typeof import('vue')['onUpdated']
|
||||
const provide: typeof import('vue')['provide']
|
||||
const reactive: typeof import('vue')['reactive']
|
||||
const readonly: typeof import('vue')['readonly']
|
||||
const ref: typeof import('vue')['ref']
|
||||
const shallowReactive: typeof import('vue')['shallowReactive']
|
||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||
const shallowRef: typeof import('vue')['shallowRef']
|
||||
const toRaw: typeof import('vue')['toRaw']
|
||||
const toRef: typeof import('vue')['toRef']
|
||||
const toRefs: typeof import('vue')['toRefs']
|
||||
const triggerRef: typeof import('vue')['triggerRef']
|
||||
const unref: typeof import('vue')['unref']
|
||||
const useAttrs: typeof import('vue')['useAttrs']
|
||||
const useCssModule: typeof import('vue')['useCssModule']
|
||||
const useSlots: typeof import('vue')['useSlots']
|
||||
const watch: typeof import('vue')['watch']
|
||||
const watchEffect: typeof import('vue')['watchEffect']
|
||||
}
|
||||
export {}
|
||||
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
declare module '*.vue' {
|
||||
import { DefineComponent } from 'vue'
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import 'virtual:windi.css'
|
||||
import { createApp } from 'vue'
|
||||
import './assets/index.css'
|
||||
import { createPinia } from 'pinia'
|
||||
import { DraggablePlugin } from '@braks/revue-draggable'
|
||||
import App from './App.vue'
|
||||
import { router } from './router'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
app.config.performance = true
|
||||
app.use(router)
|
||||
app.use(DraggablePlugin)
|
||||
app.use(createPinia())
|
||||
app.mount('#root')
|
||||
@@ -1,113 +0,0 @@
|
||||
import { createRouter, createWebHashHistory, RouterOptions } from 'vue-router'
|
||||
|
||||
export const routes: RouterOptions['routes'] = [
|
||||
{
|
||||
path: '/',
|
||||
redirect: '/overview',
|
||||
},
|
||||
{
|
||||
path: '/basic',
|
||||
component: () => import('./Basic/Basic.vue'),
|
||||
},
|
||||
{
|
||||
path: '/custom-connectionline',
|
||||
component: () => import('./CustomConnectionLine/CustomConnectionLine.vue'),
|
||||
},
|
||||
{
|
||||
path: '/custom-node',
|
||||
component: () => import('./CustomNode/CustomNode.vue'),
|
||||
},
|
||||
{
|
||||
path: '/drag-n-drop',
|
||||
component: () => import('./DragNDrop/DnD.vue'),
|
||||
},
|
||||
{
|
||||
path: '/edges',
|
||||
component: () => import('./Edges/EdgesExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/button-edge',
|
||||
component: () => import('./EdgeWithButton/EdgeWithButton.vue'),
|
||||
},
|
||||
{
|
||||
path: '/edge-types',
|
||||
component: () => import('./EdgeTypes/EdgeTypesExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/empty',
|
||||
component: () => import('./Empty/EmptyExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/hidden',
|
||||
component: () => import('./Hidden/HiddenExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/interaction',
|
||||
component: () => import('./Interaction/InteractionExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/layouting',
|
||||
component: () => import('./Layouting/LayoutingExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/multi-flows',
|
||||
component: () => import('./MultiFlows/MultiFlowsExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/node-type-change',
|
||||
component: () => import('./NodeTypeChange/NodeTypeChangeExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/node-types-id-change',
|
||||
component: () => import('./NodeTypesIdChange/NodeTypesIdChangeExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/overview',
|
||||
component: () => import('./Overview/Overview.vue'),
|
||||
},
|
||||
{
|
||||
path: '/provider',
|
||||
component: () => import('./Provider/ProviderExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/save-restore',
|
||||
component: () => import('./SaveRestore/SaveRestoreExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/stress',
|
||||
component: () => import('./Stress/StressExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/switch',
|
||||
component: () => import('./Switch/SwitchExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/unidirectional',
|
||||
component: () => import('./Unidirectional/UnidirectionalExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/updateable-edge',
|
||||
component: () => import('./UpdatableEdge/UpdatableEdgeExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/update-node',
|
||||
component: () => import('./UpdateNode/UpdateNodeExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/update-node-internals',
|
||||
component: () => import('./UpdateNodeInternals/UpdateNodeInternalsExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/validation',
|
||||
component: () => import('./Validation/ValidationExample.vue'),
|
||||
},
|
||||
{
|
||||
path: '/zoom-pan-helper',
|
||||
component: () => import('./ZoomPanHelper/ZoomPanHelperExample.vue'),
|
||||
},
|
||||
]
|
||||
|
||||
export const router = createRouter({
|
||||
history: createWebHashHistory(),
|
||||
routes,
|
||||
})
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"sourceMap": true,
|
||||
"resolveJsonModule": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": ["esnext", "dom"]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import { resolve } from 'path'
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import AutoImport from 'unplugin-auto-import/vite'
|
||||
import WindiCSS from 'vite-plugin-windicss'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
alias: {
|
||||
vue: resolve('./node_modules/vue'),
|
||||
},
|
||||
resolve: {
|
||||
dedupe: ['vue'],
|
||||
preserveSymlinks: false,
|
||||
},
|
||||
build: {
|
||||
emptyOutDir: true,
|
||||
},
|
||||
plugins: [
|
||||
vue(),
|
||||
AutoImport({
|
||||
imports: ['vue'],
|
||||
dts: 'src/auto-imports.d.ts',
|
||||
}),
|
||||
WindiCSS(),
|
||||
],
|
||||
})
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user