feat(node-toolbar): add node-toolbar component
Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
8
packages/node-toolbar/.eslintrc.js
Normal file
8
packages/node-toolbar/.eslintrc.js
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
rules: {
|
||||
'no-use-before-define': 0,
|
||||
'vue/no-setup-props-destructure': 0,
|
||||
},
|
||||
extends: ['../../.eslintrc.js'],
|
||||
ignorePatterns: ['!**/*'],
|
||||
}
|
||||
3
packages/node-toolbar/README.md
Normal file
3
packages/node-toolbar/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Vue Flow: Toolbar Component
|
||||
|
||||
This is a toolbar component for Vue Flow.
|
||||
@@ -1,30 +1,30 @@
|
||||
{
|
||||
"name": "@vue-flow/toolbar",
|
||||
"name": "@vue-flow/node-toolbar",
|
||||
"version": "0.0.1",
|
||||
"private": false,
|
||||
"license": "MIT",
|
||||
"author": "Burak Cakmakoglu<78412429+bcakmakoglu@users.noreply.github.com>",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/bcakmakoglu/vue-flow/packages/plugins/toolbar"
|
||||
"url": "git+https://github.com/bcakmakoglu/vue-flow/packages/plugins/node-toolbar"
|
||||
},
|
||||
"homepage": "https://github.com/bcakmakoglu/vue-flow#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/bcakmakoglu/vue-flow/issues"
|
||||
},
|
||||
"main": "./dist/vue-flow-plugin-toolbar.js",
|
||||
"module": "./dist/vue-flow-toolbar.mjs",
|
||||
"main": "./dist/vue-flow-plugin-node-toolbar.js",
|
||||
"module": "./dist/vue-flow-node-toolbar.mjs",
|
||||
"types": "./dist/index.d.ts",
|
||||
"unpkg": "./dist/vue-flow-toolbar.iife.js",
|
||||
"jsdelivr": "./dist/vue-flow-toolbar.iife.js",
|
||||
"unpkg": "./dist/vue-flow-node-toolbar.iife.js",
|
||||
"jsdelivr": "./dist/vue-flow-node-toolbar.iife.js",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
"types": "tsc && shx rm -rf tmp",
|
||||
"lint": "eslint --ext \".js,.jsx,.ts,.tsx\" --fix --ignore-path ../../../.gitignore .",
|
||||
"types": "vue-tsc --declaration --emitDeclarationOnly && pnpm lint:dist",
|
||||
"lint": "eslint --ext \".js,.jsx,.ts,.tsx\" --fix --ignore-path ../../.gitignore .",
|
||||
"lint:dist": "eslint --ext \".ts,.tsx\" -c .eslintrc.js --fix ./dist",
|
||||
"test": "exit 0"
|
||||
},
|
||||
@@ -35,7 +35,11 @@
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@vue-flow/core": "workspace:*",
|
||||
"vite": "^3.2.2"
|
||||
"@vitejs/plugin-vue": "^3.2.0",
|
||||
"unplugin-auto-import": "^0.12.0",
|
||||
"vite": "^3.2.5",
|
||||
"vite-plugin-vue-type-imports": "0.2.0",
|
||||
"vue-tsc": "^1.0.11"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
91
packages/node-toolbar/src/NodeToolbar.vue
Normal file
91
packages/node-toolbar/src/NodeToolbar.vue
Normal file
@@ -0,0 +1,91 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject } from 'vue'
|
||||
import type { GraphNode, Rect, ViewpaneTransform } from '@vue-flow/core'
|
||||
import { NodeIdInjection, Position, getRectOfNodes, useVueFlow } from '@vue-flow/core'
|
||||
|
||||
import type { CSSProperties } from 'vue'
|
||||
import type { NodeToolbarProps } from './types'
|
||||
|
||||
const props = withDefaults(defineProps<NodeToolbarProps>(), {
|
||||
position: Position.Top,
|
||||
offset: 10,
|
||||
})
|
||||
|
||||
const contextNodeId = inject(NodeIdInjection, null)
|
||||
|
||||
const { viewportRef, viewport, getSelectedNodes, findNode } = useVueFlow()
|
||||
|
||||
function getTransform(nodeRect: Rect, transform: ViewpaneTransform, position: Position, offset: number): string {
|
||||
// position === Position.Top
|
||||
let xPos = (nodeRect.x + nodeRect.width / 2) * transform.zoom + transform.x
|
||||
let yPos = nodeRect.y * transform.zoom + transform.y - offset
|
||||
let xShift = -50
|
||||
let yShift = -100
|
||||
|
||||
switch (position) {
|
||||
case Position.Right:
|
||||
xPos = (nodeRect.x + nodeRect.width) * transform.zoom + transform.x + offset
|
||||
yPos = (nodeRect.y + nodeRect.height / 2) * transform.zoom + transform.y
|
||||
xShift = 0
|
||||
yShift = -50
|
||||
break
|
||||
case Position.Bottom:
|
||||
yPos = (nodeRect.y + nodeRect.height) * transform.zoom + transform.y + offset
|
||||
yShift = 0
|
||||
break
|
||||
case Position.Left:
|
||||
xPos = nodeRect.x * transform.zoom + transform.x - offset
|
||||
yPos = (nodeRect.y + nodeRect.height / 2) * transform.zoom + transform.y
|
||||
xShift = -100
|
||||
yShift = -50
|
||||
break
|
||||
}
|
||||
|
||||
return `translate(${xPos}px, ${yPos}px) translate(${xShift}%, ${yShift}%)`
|
||||
}
|
||||
|
||||
const nodes = computed(() => {
|
||||
const nodeIds = Array.isArray(props.nodeId) ? props.nodeId : [props.nodeId || contextNodeId || '']
|
||||
|
||||
return nodeIds.reduce<GraphNode[]>((acc, id) => {
|
||||
const node = findNode(id)
|
||||
|
||||
if (node) {
|
||||
acc.push(node)
|
||||
}
|
||||
|
||||
return acc
|
||||
}, [] as GraphNode[])
|
||||
})
|
||||
|
||||
const isActive = computed(() =>
|
||||
typeof props.isVisible === 'boolean'
|
||||
? props.isVisible
|
||||
: nodes.value.length === 1 && nodes.value[0].selected && getSelectedNodes.value.length === 1,
|
||||
)
|
||||
|
||||
const nodeRect = computed<Rect>(() => getRectOfNodes(nodes.value))
|
||||
|
||||
const zIndex = computed<number>(() => Math.max(...nodes.value.map((node) => (node.computedPosition.z || 1) + 1)))
|
||||
|
||||
const wrapperStyle = computed<CSSProperties>(() => ({
|
||||
position: 'absolute',
|
||||
transform: getTransform(nodeRect.value, viewport.value, props.position, props.offset),
|
||||
zIndex: zIndex.value,
|
||||
}))
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'NodeToolbar',
|
||||
inheritAttrs: false,
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Teleport :to="viewportRef">
|
||||
<div v-if="isActive && nodes.length" v-bind="$attrs" :style="wrapperStyle" class="vue-flow__node-toolbar">
|
||||
<slot />
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
2
packages/node-toolbar/src/index.ts
Normal file
2
packages/node-toolbar/src/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './types'
|
||||
export { default as NodeToolbar } from './NodeToolbar.vue'
|
||||
8
packages/node-toolbar/src/types.ts
Normal file
8
packages/node-toolbar/src/types.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import type { Position } from '@vue-flow/core'
|
||||
|
||||
export interface NodeToolbarProps {
|
||||
nodeId?: string | string[]
|
||||
isVisible?: boolean
|
||||
position?: Position
|
||||
offset?: number
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
import { resolve } from 'path'
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import AutoImport from 'unplugin-auto-import/vite'
|
||||
import vueTypes from 'vite-plugin-vue-type-imports'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
@@ -11,8 +14,8 @@ export default defineConfig({
|
||||
lib: {
|
||||
formats: ['es', 'cjs', 'iife'],
|
||||
entry: resolve(__dirname, 'src/index.ts'),
|
||||
fileName: 'vue-flow-toolbar',
|
||||
name: 'vueFlowToolbar',
|
||||
fileName: 'vue-flow-node-toolbar',
|
||||
name: 'vueFlowNodeToolbar',
|
||||
},
|
||||
rollupOptions: {
|
||||
// make sure to externalize deps that shouldn't be bundled
|
||||
@@ -29,4 +32,14 @@ export default defineConfig({
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
vue({
|
||||
reactivityTransform: true,
|
||||
}),
|
||||
vueTypes(),
|
||||
AutoImport({
|
||||
imports: ['vue', 'vue/macros'],
|
||||
dts: 'src/auto-imports.d.ts',
|
||||
}),
|
||||
],
|
||||
})
|
||||
@@ -1 +0,0 @@
|
||||
# Vue Flow: Toolbar Component
|
||||
@@ -1 +0,0 @@
|
||||
export * from './types'
|
||||
@@ -1,8 +0,0 @@
|
||||
import type dagre from 'dagre'
|
||||
|
||||
export type Direction = 'TB' | 'BT' | 'LR' | 'RL'
|
||||
|
||||
export interface UseDagreState {
|
||||
layout: (direction: Direction) => void
|
||||
dagreGraph: dagre.graphlib.Graph
|
||||
}
|
||||
39
pnpm-lock.yaml
generated
39
pnpm-lock.yaml
generated
@@ -144,6 +144,7 @@ importers:
|
||||
'@vitejs/plugin-vue': ^3.2.0
|
||||
'@vue-flow/additional-components': workspace:*
|
||||
'@vue-flow/core': workspace:*
|
||||
'@vue-flow/node-toolbar': workspace:*
|
||||
dagre: ^0.8.5
|
||||
unplugin-auto-import: ^0.12.0
|
||||
vite: ^3.2.5
|
||||
@@ -155,6 +156,7 @@ importers:
|
||||
dependencies:
|
||||
'@vue-flow/additional-components': link:../../packages/additional-components
|
||||
'@vue-flow/core': link:../../packages/core
|
||||
'@vue-flow/node-toolbar': link:../../packages/node-toolbar
|
||||
vueflow: link:../../packages/vue-flow
|
||||
devDependencies:
|
||||
'@types/dagre': 0.7.48
|
||||
@@ -239,6 +241,25 @@ importers:
|
||||
vite-plugin-vue-type-imports: 0.2.0_ek75d3noihdfv6qzog663yntom
|
||||
vue-tsc: 1.0.11_typescript@4.8.4
|
||||
|
||||
packages/node-toolbar:
|
||||
specifiers:
|
||||
'@vitejs/plugin-vue': ^3.2.0
|
||||
'@vue-flow/core': workspace:*
|
||||
unplugin-auto-import: ^0.12.0
|
||||
vite: ^3.2.5
|
||||
vite-plugin-vue-type-imports: 0.2.0
|
||||
vue: ^3.2.37
|
||||
vue-tsc: ^1.0.11
|
||||
dependencies:
|
||||
vue: 3.2.40
|
||||
devDependencies:
|
||||
'@vitejs/plugin-vue': 3.2.0_vite@3.2.5+vue@3.2.40
|
||||
'@vue-flow/core': link:../core
|
||||
unplugin-auto-import: 0.12.0
|
||||
vite: 3.2.5
|
||||
vite-plugin-vue-type-imports: 0.2.0_ek75d3noihdfv6qzog663yntom
|
||||
vue-tsc: 1.0.11_typescript@4.8.4
|
||||
|
||||
packages/pathfinding-edge:
|
||||
specifiers:
|
||||
'@types/pathfinding': ^0.0.5
|
||||
@@ -607,7 +628,7 @@ packages:
|
||||
'@babel/helper-compilation-targets': 7.19.3_@babel+core@7.19.3
|
||||
'@babel/helper-module-transforms': 7.19.0
|
||||
'@babel/helpers': 7.19.0
|
||||
'@babel/parser': 7.19.3
|
||||
'@babel/parser': 7.20.2
|
||||
'@babel/template': 7.18.10
|
||||
'@babel/traverse': 7.19.3
|
||||
'@babel/types': 7.20.2
|
||||
@@ -801,14 +822,6 @@ packages:
|
||||
dependencies:
|
||||
'@babel/types': 7.20.2
|
||||
|
||||
/@babel/parser/7.19.3:
|
||||
resolution: {integrity: sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@babel/types': 7.20.2
|
||||
dev: true
|
||||
|
||||
/@babel/parser/7.20.2:
|
||||
resolution: {integrity: sha512-afk318kh2uKbo7BEj2QtEi8HVCGrwHUffrYDy7dgVcSa2j9lY3LDjPzcyGdpX7xgm35aWqvciZJ4WKmdF/SxYg==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
@@ -2522,7 +2535,7 @@ packages:
|
||||
dependencies:
|
||||
'@volar/code-gen': 0.40.13
|
||||
'@volar/source-map': 0.40.13
|
||||
'@vue/compiler-core': 3.2.40
|
||||
'@vue/compiler-core': 3.2.45
|
||||
'@vue/compiler-dom': 3.2.45
|
||||
'@vue/compiler-sfc': 3.2.45
|
||||
'@vue/reactivity': 3.2.40
|
||||
@@ -7522,8 +7535,8 @@ packages:
|
||||
/mlly/0.5.5:
|
||||
resolution: {integrity: sha512-2R4JT/SxRDPexomw4rmHYY/gWAGmL9Kkq1OR76Ua6w+P340a1aBDTWzKo2kAlxzrG82OdXs5VB9Lmcmyit0Obg==}
|
||||
dependencies:
|
||||
pathe: 0.3.2
|
||||
pkg-types: 0.3.3
|
||||
pathe: 0.3.9
|
||||
pkg-types: 0.3.5
|
||||
dev: true
|
||||
|
||||
/mlly/1.0.0:
|
||||
@@ -9761,7 +9774,7 @@ packages:
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@jridgewell/source-map': 0.3.2
|
||||
acorn: 8.8.0
|
||||
acorn: 8.8.1
|
||||
commander: 2.20.3
|
||||
source-map-support: 0.5.21
|
||||
dev: true
|
||||
|
||||
Reference in New Issue
Block a user