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',
+ }),
+ ],
+})