docs: add teleportable example
This commit is contained in:
@@ -14,7 +14,7 @@ import { HiddenApp } from './hidden'
|
||||
import { InteractionApp, InteractionCSS, InteractionControls } from './interaction'
|
||||
import { MultiApp, MultiCSS, MultiFlow } from './multi'
|
||||
import { HorizontalApp, HorizontalElements } from './horizontal'
|
||||
import { TeleportApp, TeleportSidebar, TeleportCSS } from './teleport'
|
||||
import { TeleportApp, TeleportCSS, TeleportSidebar, TeleportableNode } from './teleport'
|
||||
|
||||
export const exampleImports = {
|
||||
basic: {
|
||||
@@ -93,6 +93,7 @@ export const exampleImports = {
|
||||
teleport: {
|
||||
'App.vue': TeleportApp,
|
||||
'Sidebar.vue': TeleportSidebar,
|
||||
'TeleportableNode.vue': TeleportableNode,
|
||||
'style.css': TeleportCSS,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,23 +1,30 @@
|
||||
<script setup>
|
||||
import { VueFlow, useVueFlow } from '@braks/vue-flow'
|
||||
import { reactive, ref } from 'vue'
|
||||
import { ref } from 'vue'
|
||||
import Sidebar from './Sidebar.vue'
|
||||
import TeleportableNode from './TeleportableNode.vue'
|
||||
|
||||
const elements = ref([
|
||||
{
|
||||
id: '1',
|
||||
label: 'Click to teleport',
|
||||
type: 'teleportable',
|
||||
position: { x: 125, y: 0 },
|
||||
data: {},
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
label: 'Click to teleport',
|
||||
type: 'teleportable',
|
||||
position: { x: 250, y: 100 },
|
||||
data: {},
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
label: 'Click to teleport',
|
||||
type: 'teleportable',
|
||||
position: { x: 0, y: 100 },
|
||||
data: {},
|
||||
},
|
||||
{
|
||||
id: 'e1-2',
|
||||
@@ -25,43 +32,15 @@ const elements = ref([
|
||||
target: '2',
|
||||
},
|
||||
])
|
||||
|
||||
const { onNodeClick } = useVueFlow()
|
||||
|
||||
const lastPositions = {}
|
||||
|
||||
onNodeClick(({ node, connectedEdges }) => {
|
||||
/**
|
||||
* specify a selector to teleport to
|
||||
* beware that teleports only work after viewpane is ready
|
||||
*
|
||||
* teleported elements still behave like they're at their position before,
|
||||
* i.e. if they emit events, they will still emit them up their regular tree
|
||||
*/
|
||||
const target = node.teleport ? null : '#port'
|
||||
|
||||
// teleport to target or disable teleport
|
||||
node.teleport = target
|
||||
|
||||
// hide connected edges when teleporting
|
||||
connectedEdges.forEach((edge) => (edge.hidden = !!target))
|
||||
|
||||
if (!target) {
|
||||
// apply last position (so the transformation gets applied)
|
||||
node.position = lastPositions[node.id]
|
||||
} else {
|
||||
// save last position
|
||||
lastPositions[node.id] = Object.assign({}, { ...node.position })
|
||||
|
||||
// remove current position (so the transformation gets removed)
|
||||
node.position = { x: 0, y: 0 }
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="teleportflow">
|
||||
<VueFlow v-model="elements" :fit-view-on-init="true" />
|
||||
<VueFlow v-model="elements" :fit-view-on-init="true">
|
||||
<template #node-teleportable="props">
|
||||
<TeleportableNode :id="props.id" />
|
||||
</template>
|
||||
</VueFlow>
|
||||
<Sidebar />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<script setup>
|
||||
import { Handle, Position, getConnectedEdges, useVueFlow } from '@braks/vue-flow'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
id: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const { edges, getNode } = useVueFlow()
|
||||
|
||||
const teleport = ref(null)
|
||||
|
||||
const onClick = () => {
|
||||
/**
|
||||
* specify a selector to teleport to
|
||||
*
|
||||
* teleported elements still behave like they're at their position before,
|
||||
* i.e. if they emit events, they will still emit them up their regular tree
|
||||
*/
|
||||
const target = teleport.value ? null : '#port'
|
||||
|
||||
// teleport to target or disable teleport
|
||||
teleport.value = target
|
||||
|
||||
// hide connected edges when teleporting
|
||||
const connectedEdges = getConnectedEdges([getNode.value(props.id)], edges.value)
|
||||
|
||||
console.log(connectedEdges)
|
||||
|
||||
connectedEdges.forEach((edge) => (edge.hidden = !!target))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<teleport :disabled="!teleport" :to="teleport">
|
||||
<div class="teleportable" @click.prevent="onClick">
|
||||
<Handle type="target" :position="Position.Top" />
|
||||
Click to teleport
|
||||
<Handle type="source" :position="Position.Bottom" />
|
||||
</div>
|
||||
</teleport>
|
||||
</template>
|
||||
@@ -1,3 +1,4 @@
|
||||
export { default as TeleportApp } from './App.vue?raw'
|
||||
export { default as TeleportSidebar } from './Sidebar.vue?raw'
|
||||
export { default as TeleportableNode } from './TeleportableNode.vue?raw'
|
||||
export { default as TeleportCSS } from './style.css'
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
padding: 15px 10px;
|
||||
font-size: 12px;
|
||||
background: rgba(16, 185, 129, 0.75);
|
||||
-webkit-box-shadow: 0px 5px 10px 0px rgba(0,0,0,0.3);
|
||||
box-shadow: 0px 5px 10px 0px rgba(0,0,0,0.3);
|
||||
-webkit-box-shadow: 0px 5px 10px 0px rgba(0, 0, 0, 0.3);
|
||||
box-shadow: 0px 5px 10px 0px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.teleportflow aside .port > * {
|
||||
@@ -20,8 +20,8 @@
|
||||
margin-bottom: 10px;
|
||||
cursor: grab;
|
||||
font-weight: 500;
|
||||
-webkit-box-shadow: 5px 5px 10px 2px rgba(0,0,0,0.25);
|
||||
box-shadow: 5px 5px 10px 2px rgba(0,0,0,0.25);
|
||||
-webkit-box-shadow: 5px 5px 10px 2px rgba(0, 0, 0, 0.25);
|
||||
box-shadow: 5px 5px 10px 2px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.teleportflow aside .description {
|
||||
@@ -50,3 +50,11 @@
|
||||
gap: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.teleportable {
|
||||
padding: 10px;
|
||||
background: white;
|
||||
border: 1px solid black;
|
||||
border-radius: 10px;
|
||||
color: black
|
||||
}
|
||||
|
||||
Vendored
+1
@@ -29,6 +29,7 @@ declare module 'vue' {
|
||||
Repl: typeof import('./../../components/Repl.vue')['default']
|
||||
RGB: typeof import('./../../components/home/flows/RGB.vue')['default']
|
||||
Sidebar: typeof import('./../../components/examples/dnd/Sidebar.vue')['default']
|
||||
TeleportableNode: typeof import('./../../components/examples/teleport/TeleportableNode.vue')['default']
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -246,40 +246,38 @@ export default {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Teleport :disabled="!node.teleport" :to="node.teleport">
|
||||
<div
|
||||
ref="nodeElement"
|
||||
:class="getClass"
|
||||
:style="getStyle"
|
||||
:data-id="id"
|
||||
@mouseenter="onMouseEnter"
|
||||
@mousemove="onMouseMove"
|
||||
@mouseleave="onMouseLeave"
|
||||
@contextmenu="onContextMenu"
|
||||
@click="onSelectNode"
|
||||
@dblclick="onDoubleClick"
|
||||
>
|
||||
<component
|
||||
:is="type"
|
||||
:id="node.id"
|
||||
:type="node.type"
|
||||
:data="node.data"
|
||||
:selected="!!node.selected"
|
||||
:connectable="connectable"
|
||||
:position="node.position"
|
||||
:computed-position="node.computedPosition"
|
||||
:dimensions="node.dimensions"
|
||||
:is-valid-target-pos="node.isValidTargetPos"
|
||||
:is-valid-source-pos="node.isValidSourcePos"
|
||||
:parent-node="node.parentNode"
|
||||
:dragging="!!node.dragging"
|
||||
:z-index="node.computedPosition.z"
|
||||
:target-position="node.targetPosition"
|
||||
:source-position="node.sourcePosition"
|
||||
:label="node.label"
|
||||
:drag-handle="node.dragHandle"
|
||||
:node-element="nodeElement"
|
||||
/>
|
||||
</div>
|
||||
</Teleport>
|
||||
<div
|
||||
ref="nodeElement"
|
||||
:class="getClass"
|
||||
:style="getStyle"
|
||||
:data-id="id"
|
||||
@mouseenter="onMouseEnter"
|
||||
@mousemove="onMouseMove"
|
||||
@mouseleave="onMouseLeave"
|
||||
@contextmenu="onContextMenu"
|
||||
@click="onSelectNode"
|
||||
@dblclick="onDoubleClick"
|
||||
>
|
||||
<component
|
||||
:is="type"
|
||||
:id="node.id"
|
||||
:type="node.type"
|
||||
:data="node.data"
|
||||
:selected="!!node.selected"
|
||||
:connectable="connectable"
|
||||
:position="node.position"
|
||||
:computed-position="node.computedPosition"
|
||||
:dimensions="node.dimensions"
|
||||
:is-valid-target-pos="node.isValidTargetPos"
|
||||
:is-valid-source-pos="node.isValidSourcePos"
|
||||
:parent-node="node.parentNode"
|
||||
:dragging="!!node.dragging"
|
||||
:z-index="node.computedPosition.z"
|
||||
:target-position="node.targetPosition"
|
||||
:source-position="node.sourcePosition"
|
||||
:label="node.label"
|
||||
:drag-handle="node.dragHandle"
|
||||
:node-element="nodeElement"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Component, TeleportProps, VNode } from 'vue'
|
||||
import type { Component, VNode } from 'vue'
|
||||
import type { BaseElement, Dimensions, ElementData, Position, SnapGrid, XYPosition, XYZPosition } from './flow'
|
||||
import type { DefaultNodeTypes, NodeComponent } from './components'
|
||||
import type { HandleElement, ValidConnectionFunc } from './handle'
|
||||
@@ -69,9 +69,6 @@ export interface GraphNode<Data = ElementData> extends Node<Data> {
|
||||
isParent: boolean
|
||||
selected: boolean
|
||||
dragging: boolean
|
||||
|
||||
/** teleports node element to specified dom location, this property is _not_ available on initial load, only after viewpane is ready */
|
||||
teleport?: TeleportProps['to']
|
||||
}
|
||||
|
||||
/** these props are passed to node components */
|
||||
|
||||
Reference in New Issue
Block a user