refactor(background): move background into separate package
Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
module.exports = {
|
||||||
|
rules: {
|
||||||
|
'no-use-before-define': 0,
|
||||||
|
'vue/no-setup-props-destructure': 0,
|
||||||
|
},
|
||||||
|
extends: ['../../.eslintrc.js'],
|
||||||
|
ignorePatterns: ['!**/*'],
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Vue Flow: Background Component
|
||||||
|
|
||||||
|
This is a background component for Vue Flow.
|
||||||
|
It can be used to create a background in your canvas.
|
||||||
|
|
||||||
|
## 🛠 Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# install
|
||||||
|
$ yarn add @vue-flow/background
|
||||||
|
|
||||||
|
# or
|
||||||
|
$ npm i --save @vue-flow/background
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🎮 Quickstart
|
||||||
|
|
||||||
|
```vue
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { VueFlow } from '@vue-flow/core'
|
||||||
|
import { Background } from '@vue-flow/background'
|
||||||
|
import initialElements from './initial-elements'
|
||||||
|
|
||||||
|
// some nodes and edges
|
||||||
|
const elements = ref(initialElements)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VueFlow v-model="elements" fit-view-on-init class="vue-flow-basic-example">
|
||||||
|
<Background />
|
||||||
|
</VueFlow>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"name": "@vue-flow/background",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"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/background"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/bcakmakoglu/vue-flow#readme",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/bcakmakoglu/vue-flow/issues"
|
||||||
|
},
|
||||||
|
"main": "./dist/vue-flow-plugin-background.js",
|
||||||
|
"module": "./dist/vue-flow-background.mjs",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"unpkg": "./dist/vue-flow-background.iife.js",
|
||||||
|
"jsdelivr": "./dist/vue-flow-background.iife.js",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"sideEffects": false,
|
||||||
|
"scripts": {
|
||||||
|
"build": "vite build",
|
||||||
|
"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"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@vue-flow/core": "^1.0.0",
|
||||||
|
"vue": "^3.2.37"
|
||||||
|
},
|
||||||
|
"dependencies": {},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vue-flow/core": "workspace:*",
|
||||||
|
"@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",
|
||||||
|
"registry": "https://registry.npmjs.org/"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { useVueFlow } from '@vue-flow/core'
|
||||||
|
import { BackgroundVariant } from './types'
|
||||||
|
import type { BackgroundProps } from './types'
|
||||||
|
|
||||||
|
const {
|
||||||
|
variant = 'dots' as BackgroundVariant,
|
||||||
|
gap = 10,
|
||||||
|
size = 0.4,
|
||||||
|
height = 100,
|
||||||
|
width = 100,
|
||||||
|
x = 0,
|
||||||
|
y = 0,
|
||||||
|
bgColor,
|
||||||
|
patternColor: initialPatternColor,
|
||||||
|
} = defineProps<BackgroundProps>()
|
||||||
|
|
||||||
|
const defaultColors: Record<BackgroundVariant, string> = {
|
||||||
|
[BackgroundVariant.Dots]: '#81818a',
|
||||||
|
[BackgroundVariant.Lines]: '#eee',
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id, viewport } = useVueFlow()
|
||||||
|
|
||||||
|
const background = $computed(() => {
|
||||||
|
const scaledGap = gap && gap * viewport.value.zoom
|
||||||
|
const xOffset = scaledGap && viewport.value.x % scaledGap
|
||||||
|
const yOffset = scaledGap && viewport.value.y % scaledGap
|
||||||
|
const bgSize = size * viewport.value.zoom
|
||||||
|
|
||||||
|
return {
|
||||||
|
scaledGap,
|
||||||
|
xOffset,
|
||||||
|
yOffset,
|
||||||
|
size: bgSize,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// when there are multiple flows on a page we need to make sure that every background gets its own pattern.
|
||||||
|
const patternId = `pattern-${id}`
|
||||||
|
|
||||||
|
const patternColor = computed(() => initialPatternColor || defaultColors[variant || BackgroundVariant.Dots])
|
||||||
|
|
||||||
|
const d = computed(
|
||||||
|
() => `M${background.scaledGap / 2} 0 V${background.scaledGap} M0 ${background.scaledGap / 2} H${background.scaledGap}`,
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
export default {
|
||||||
|
name: 'Background',
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<svg
|
||||||
|
class="vue-flow__background"
|
||||||
|
:style="{
|
||||||
|
height: `${height > 100 ? 100 : height}%`,
|
||||||
|
width: `${width > 100 ? 100 : width}%`,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<slot :id="patternId" name="pattern-container">
|
||||||
|
<pattern
|
||||||
|
:id="patternId"
|
||||||
|
:x="background.xOffset"
|
||||||
|
:y="background.yOffset"
|
||||||
|
:width="background.scaledGap"
|
||||||
|
:height="background.scaledGap"
|
||||||
|
patternUnits="userSpaceOnUse"
|
||||||
|
>
|
||||||
|
<slot name="pattern">
|
||||||
|
<template v-if="variant === BackgroundVariant.Lines">
|
||||||
|
<path :stroke="patternColor" :stroke-width="size" :d="d" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-else-if="variant === BackgroundVariant.Dots">
|
||||||
|
<circle :cx="background.size" :cy="background.size" :r="background.size" :fill="patternColor" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<svg v-if="bgColor" height="100" width="100">
|
||||||
|
<rect width="100%" height="100%" :fill="bgColor" />
|
||||||
|
</svg>
|
||||||
|
</slot>
|
||||||
|
</pattern>
|
||||||
|
</slot>
|
||||||
|
|
||||||
|
<rect :x="x" :y="y" width="100%" height="100%" :fill="`url(#${patternId})`" />
|
||||||
|
|
||||||
|
<slot :id="patternId" />
|
||||||
|
</svg>
|
||||||
|
</template>
|
||||||
@@ -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>
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export { default as Background } from './Background.vue'
|
||||||
|
export * from './types'
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
export enum BackgroundVariant {
|
||||||
|
Lines = 'lines',
|
||||||
|
Dots = 'dots',
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BackgroundProps {
|
||||||
|
/** The background pattern variant, {@link BackgroundVariant} */
|
||||||
|
variant?: BackgroundVariant
|
||||||
|
/** Background pattern gap */
|
||||||
|
gap?: number
|
||||||
|
/** Background pattern size */
|
||||||
|
size?: number
|
||||||
|
/** Background pattern color */
|
||||||
|
patternColor?: string
|
||||||
|
/** Background color */
|
||||||
|
bgColor?: string
|
||||||
|
/** Background height */
|
||||||
|
height?: number
|
||||||
|
/** Background width */
|
||||||
|
width?: number
|
||||||
|
/** Background x-coordinate (offset x) */
|
||||||
|
x?: number
|
||||||
|
/** Background y-coordinate (offset y) */
|
||||||
|
y?: number
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"module": "ESNext",
|
||||||
|
"target": "es2017",
|
||||||
|
"lib": [
|
||||||
|
"DOM",
|
||||||
|
"ESNext"
|
||||||
|
],
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"incremental": false,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"declaration": true,
|
||||||
|
"declarationDir": "./dist",
|
||||||
|
"emitDeclarationOnly": true,
|
||||||
|
"types": [],
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./src",
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"dist"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
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({
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.ts', '.vue'],
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
emptyOutDir: false,
|
||||||
|
lib: {
|
||||||
|
formats: ['es', 'cjs', 'iife'],
|
||||||
|
entry: resolve(__dirname, 'src/index.ts'),
|
||||||
|
fileName: 'vue-flow-background',
|
||||||
|
name: 'vueFlowBackground',
|
||||||
|
},
|
||||||
|
rollupOptions: {
|
||||||
|
// make sure to externalize deps that shouldn't be bundled
|
||||||
|
// into your library
|
||||||
|
external: ['vue', '@vue-flow/core'],
|
||||||
|
output: {
|
||||||
|
dir: './dist',
|
||||||
|
// Provide global variables to use in the UMD build
|
||||||
|
// for externalized deps
|
||||||
|
globals: {
|
||||||
|
'vue': 'Vue',
|
||||||
|
'@vue-flow/core': 'VueFlow',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
vue({
|
||||||
|
reactivityTransform: true,
|
||||||
|
}),
|
||||||
|
vueTypes(),
|
||||||
|
AutoImport({
|
||||||
|
imports: ['vue', 'vue/macros'],
|
||||||
|
dts: 'src/auto-imports.d.ts',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
Generated
+19
@@ -200,6 +200,25 @@ importers:
|
|||||||
vite-svg-loader: 3.6.0
|
vite-svg-loader: 3.6.0
|
||||||
vue-tsc: 1.0.11_typescript@4.8.4
|
vue-tsc: 1.0.11_typescript@4.8.4
|
||||||
|
|
||||||
|
packages/background:
|
||||||
|
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/core:
|
packages/core:
|
||||||
specifiers:
|
specifiers:
|
||||||
'@rollup/plugin-replace': ^5.0.1
|
'@rollup/plugin-replace': ^5.0.1
|
||||||
|
|||||||
Reference in New Issue
Block a user