From 281279044c4f18b18f9f4c651c79652320a93bce Mon Sep 17 00:00:00 2001 From: braks <78412429+bcakmakoglu@users.noreply.github.com> Date: Tue, 13 Dec 2022 14:17:40 +0100 Subject: [PATCH] refactor(minimap): move minimap to separate package Signed-off-by: braks <78412429+bcakmakoglu@users.noreply.github.com> --- packages/core/src/theme-default.css | 10 - packages/minimap/.eslintrc.js | 8 + packages/minimap/README.md | 39 ++++ packages/minimap/package.json | 53 ++++++ packages/minimap/src/MiniMap.vue | 242 +++++++++++++++++++++++++ packages/minimap/src/MiniMapNode.ts | 40 ++++ packages/minimap/src/auto-imports.d.ts | 63 +++++++ packages/minimap/src/index.ts | 5 + packages/minimap/src/style.css | 7 + packages/minimap/src/types.ts | 58 ++++++ packages/minimap/src/window-shims.d.ts | 3 + packages/minimap/tsconfig.json | 31 ++++ packages/minimap/vite.config.ts | 45 +++++ 13 files changed, 594 insertions(+), 10 deletions(-) create mode 100644 packages/minimap/.eslintrc.js create mode 100644 packages/minimap/README.md create mode 100644 packages/minimap/package.json create mode 100644 packages/minimap/src/MiniMap.vue create mode 100644 packages/minimap/src/MiniMapNode.ts create mode 100644 packages/minimap/src/auto-imports.d.ts create mode 100644 packages/minimap/src/index.ts create mode 100644 packages/minimap/src/style.css create mode 100644 packages/minimap/src/types.ts create mode 100644 packages/minimap/src/window-shims.d.ts create mode 100644 packages/minimap/tsconfig.json create mode 100644 packages/minimap/vite.config.ts diff --git a/packages/core/src/theme-default.css b/packages/core/src/theme-default.css index 5930312e..c432d980 100644 --- a/packages/core/src/theme-default.css +++ b/packages/core/src/theme-default.css @@ -104,16 +104,6 @@ border-radius: 100%; } -.vue-flow__minimap { - background-color: #fff; -} - -.vue-flow__minimap-mask { - &.pannable { - cursor: grab; - } -} - .vue-flow__controls { box-shadow: 0 0 2px 1px rgba(0, 0, 0, 0.08); diff --git a/packages/minimap/.eslintrc.js b/packages/minimap/.eslintrc.js new file mode 100644 index 00000000..98c0e4cb --- /dev/null +++ b/packages/minimap/.eslintrc.js @@ -0,0 +1,8 @@ +module.exports = { + rules: { + 'no-use-before-define': 0, + 'vue/no-setup-props-destructure': 0, + }, + extends: ['../../.eslintrc.js'], + ignorePatterns: ['!**/*'], +} diff --git a/packages/minimap/README.md b/packages/minimap/README.md new file mode 100644 index 00000000..463f6545 --- /dev/null +++ b/packages/minimap/README.md @@ -0,0 +1,39 @@ +# Vue Flow: MiniMap + +This is a minimap component for Vue Flow. +It can be used to add a minimap to the canvas, which will show a smaller version of the canvas with your nodes. +The minimap can also be used to pan and zoom the main canvas. + +## 🛠 Setup + +```bash +# install +$ yarn add @vue-flow/minimap + +# or +$ npm i --save @vue-flow/minimap +``` + +## 🎮 Quickstart + +```vue + + + + +``` diff --git a/packages/minimap/package.json b/packages/minimap/package.json new file mode 100644 index 00000000..e387647f --- /dev/null +++ b/packages/minimap/package.json @@ -0,0 +1,53 @@ +{ + "name": "@vue-flow/minimap", + "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/minimap" + }, + "homepage": "https://github.com/bcakmakoglu/vue-flow#readme", + "bugs": { + "url": "https://github.com/bcakmakoglu/vue-flow/issues" + }, + "main": "./dist/vue-flow-plugin-minimap.js", + "module": "./dist/vue-flow-minimap.mjs", + "types": "./dist/index.d.ts", + "unpkg": "./dist/vue-flow-minimap.iife.js", + "jsdelivr": "./dist/vue-flow-minimap.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": { + "d3-selection": "^3.0.0", + "d3-zoom": "^3.0.0" + }, + "devDependencies": { + "@types/d3-selection": "^3.0.3", + "@types/d3-zoom": "^3.0.1", + "@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/" + } +} diff --git a/packages/minimap/src/MiniMap.vue b/packages/minimap/src/MiniMap.vue new file mode 100644 index 00000000..82eafc2a --- /dev/null +++ b/packages/minimap/src/MiniMap.vue @@ -0,0 +1,242 @@ + + + + + diff --git a/packages/minimap/src/MiniMapNode.ts b/packages/minimap/src/MiniMapNode.ts new file mode 100644 index 00000000..cf60cc17 --- /dev/null +++ b/packages/minimap/src/MiniMapNode.ts @@ -0,0 +1,40 @@ +import type { CSSProperties, Slots } from 'vue' +import type { MiniMapNodeProps } from './types' +import { MiniMapSlots } from './types' + +export default defineComponent({ + name: 'MiniMapNode', + props: ['id', 'position', 'dimensions', 'strokeWidth', 'strokeColor', 'borderRadius', 'color', 'shapeRendering', 'type'], + emits: ['click', 'dblclick', 'mouseenter', 'mousemove', 'mouseleave'], + setup(props: MiniMapNodeProps, { attrs, emit }) { + const miniMapSlots: Slots = inject(MiniMapSlots)! + + return () => { + const style = (attrs.style ?? {}) as CSSProperties + const slot = miniMapSlots[`node-${props.type}`] + + if (slot) return slot!(props) + + return h('rect', { + id: props.id, + class: ['vue-flow__minimap-node', attrs.class].join(' '), + style, + x: props.position.x, + y: props.position.y, + rx: props.borderRadius, + ry: props.borderRadius, + width: props.dimensions.width, + height: props.dimensions.height, + fill: props.color || (style.background as string) || style.backgroundColor, + stroke: props.strokeColor, + strokeWidth: props.strokeWidth, + shapeRendering: props.shapeRendering, + onClick: (e: MouseEvent) => emit('click', e), + onDblClick: (e: MouseEvent) => emit('dblclick', e), + onMouseenter: (e: MouseEvent) => emit('mouseenter', e), + onMousemove: (e: MouseEvent) => emit('mousemove', e), + onMouseleave: (e: MouseEvent) => emit('mouseleave', e), + }) + } + }, +}) diff --git a/packages/minimap/src/auto-imports.d.ts b/packages/minimap/src/auto-imports.d.ts new file mode 100644 index 00000000..05f84c95 --- /dev/null +++ b/packages/minimap/src/auto-imports.d.ts @@ -0,0 +1,63 @@ +// Generated by 'unplugin-auto-import' +export {} +declare global { + const $$: typeof import('vue/macros')['$$'] + const $: typeof import('vue/macros')['$'] + const $computed: typeof import('vue/macros')['$computed'] + const $customRef: typeof import('vue/macros')['$customRef'] + const $ref: typeof import('vue/macros')['$ref'] + const $shallowRef: typeof import('vue/macros')['$shallowRef'] + const $toRef: typeof import('vue/macros')['$toRef'] + const EffectScope: typeof import('vue')['EffectScope'] + 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 getCurrentInstance: typeof import('vue')['getCurrentInstance'] + const getCurrentScope: typeof import('vue')['getCurrentScope'] + const h: typeof import('vue')['h'] + const inject: typeof import('vue')['inject'] + const isProxy: typeof import('vue')['isProxy'] + const isReactive: typeof import('vue')['isReactive'] + 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 resolveComponent: typeof import('vue')['resolveComponent'] + const resolveDirective: typeof import('vue')['resolveDirective'] + 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 useCssVars: typeof import('vue')['useCssVars'] + const useSlots: typeof import('vue')['useSlots'] + const watch: typeof import('vue')['watch'] + const watchEffect: typeof import('vue')['watchEffect'] + const watchPostEffect: typeof import('vue')['watchPostEffect'] + const watchSyncEffect: typeof import('vue')['watchSyncEffect'] +} diff --git a/packages/minimap/src/index.ts b/packages/minimap/src/index.ts new file mode 100644 index 00000000..2da1d1d9 --- /dev/null +++ b/packages/minimap/src/index.ts @@ -0,0 +1,5 @@ +import './style.css' +export { default as MiniMap } from './MiniMap.vue' +export { default as MiniMapNode } from './MiniMapNode' + +export * from './types' diff --git a/packages/minimap/src/style.css b/packages/minimap/src/style.css new file mode 100644 index 00000000..08986fa4 --- /dev/null +++ b/packages/minimap/src/style.css @@ -0,0 +1,7 @@ +.vue-flow__minimap { + background-color: #fff; +} + +.vue-flow__minimap-mask.pannable { + cursor: grab; +} diff --git a/packages/minimap/src/types.ts b/packages/minimap/src/types.ts new file mode 100644 index 00000000..220db199 --- /dev/null +++ b/packages/minimap/src/types.ts @@ -0,0 +1,58 @@ +import type { Dimensions, GraphNode, XYPosition } from '@vue-flow/core' +import type { CSSProperties, InjectionKey, Slots } from 'vue' +import type { PanelPosition } from '../panel' + +/** expects a node and returns a color value */ +export type MiniMapNodeFunc = (node: GraphNode) => string +// hack for vue-type imports +type MiniMapNodeFunc2 = (node: GraphNode) => string +type MiniMapNodeFunc3 = (node: GraphNode) => string + +export type ShapeRendering = CSSProperties['shapeRendering'] + +export interface MiniMapProps { + /** Node color, can be either a string or a string func that receives the current node */ + nodeColor?: string | MiniMapNodeFunc + /** Node stroke color, can be either a string or a string func that receives the current node */ + nodeStrokeColor?: string | MiniMapNodeFunc2 + /** Additional node class name, can be either a string or a string func that receives the current node */ + nodeClassName?: string | MiniMapNodeFunc3 + /** Node border radius */ + nodeBorderRadius?: number + /** Node stroke width */ + nodeStrokeWidth?: number + /** Background color of minimap mask */ + maskColor?: string + /** Border color of minimap mask */ + maskStrokeColor?: string + /** Border width of minimap mask */ + maskStrokeWidth?: number + /** Position of the minimap {@link PanelPosition} */ + position?: PanelPosition + /** Enable drag minimap to drag viewport */ + pannable?: boolean + /** Enable zoom minimap to zoom viewport */ + zoomable?: boolean + + width?: number + + height?: number +} + +/** these props are passed to mini map node slots */ +export interface MiniMapNodeProps { + id: string + type: string + parentNode?: string + selected?: boolean + dragging?: boolean + position: XYPosition + dimensions: Dimensions + borderRadius?: number + color?: string + shapeRendering?: ShapeRendering + strokeColor?: string + strokeWidth?: number +} + +export const MiniMapSlots: InjectionKey = Symbol('MiniMapSlots') diff --git a/packages/minimap/src/window-shims.d.ts b/packages/minimap/src/window-shims.d.ts new file mode 100644 index 00000000..bf00fe03 --- /dev/null +++ b/packages/minimap/src/window-shims.d.ts @@ -0,0 +1,3 @@ +declare interface Window { + chrome: any +} diff --git a/packages/minimap/tsconfig.json b/packages/minimap/tsconfig.json new file mode 100644 index 00000000..e9fd0ac1 --- /dev/null +++ b/packages/minimap/tsconfig.json @@ -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" + ] +} diff --git a/packages/minimap/vite.config.ts b/packages/minimap/vite.config.ts new file mode 100644 index 00000000..91d0f60b --- /dev/null +++ b/packages/minimap/vite.config.ts @@ -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-minimap', + name: 'vueFlowMiniMap', + }, + 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', + }), + ], +})