From beba0a32de72375cbcfbf0603cbe0b6f14d045b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christopher=20M=C3=B6ller?= Date: Tue, 15 Nov 2022 21:48:08 +0100 Subject: [PATCH 1/8] feat(node-toolbar): add node-toolbar component --- examples/vite-app/src/App/index.tsx | 6 + .../src/examples/NodeToolbar/CustomNode.tsx | 19 +++ .../src/examples/NodeToolbar/index.tsx | 74 ++++++++++ packages/node-toolbar/.eslintrc.js | 4 + packages/node-toolbar/CHANGELOG.md | 1 + packages/node-toolbar/README.md | 10 ++ packages/node-toolbar/package.json | 68 ++++++++++ packages/node-toolbar/src/NodeToolbar.tsx | 83 ++++++++++++ .../node-toolbar/src/NodeToolbarPortal.tsx | 15 +++ packages/node-toolbar/src/index.tsx | 2 + packages/node-toolbar/src/style.css | 4 + packages/node-toolbar/src/types.ts | 9 ++ packages/node-toolbar/tsconfig.json | 6 + packages/reactflow/package.json | 6 +- packages/reactflow/src/index.ts | 1 + packages/reactflow/src/style.css | 1 + pnpm-lock.yaml | 127 +++++++++++------- 17 files changed, 386 insertions(+), 50 deletions(-) create mode 100644 examples/vite-app/src/examples/NodeToolbar/CustomNode.tsx create mode 100644 examples/vite-app/src/examples/NodeToolbar/index.tsx create mode 100644 packages/node-toolbar/.eslintrc.js create mode 100644 packages/node-toolbar/CHANGELOG.md create mode 100644 packages/node-toolbar/README.md create mode 100644 packages/node-toolbar/package.json create mode 100644 packages/node-toolbar/src/NodeToolbar.tsx create mode 100644 packages/node-toolbar/src/NodeToolbarPortal.tsx create mode 100644 packages/node-toolbar/src/index.tsx create mode 100644 packages/node-toolbar/src/style.css create mode 100644 packages/node-toolbar/src/types.ts create mode 100644 packages/node-toolbar/tsconfig.json diff --git a/examples/vite-app/src/App/index.tsx b/examples/vite-app/src/App/index.tsx index f0e32fb8..5b596f48 100644 --- a/examples/vite-app/src/App/index.tsx +++ b/examples/vite-app/src/App/index.tsx @@ -40,6 +40,7 @@ import EdgeRouting from '../examples/EdgeRouting'; import CancelConnection from '../examples/CancelConnection'; import InteractiveMinimap from '../examples/InteractiveMinimap'; import UseOnSelectionChange from '../examples/UseOnSelectionChange'; +import NodeToolbar from '../examples/NodeToolbar'; interface IRoute { name: string; @@ -168,6 +169,11 @@ const routes: IRoute[] = [ path: '/nodetypesobject-change', component: NodeTypesObjectChange, }, + { + name: 'NodeToolbar', + path: '/node-toolbar', + component: NodeToolbar, + }, { name: 'Overview', path: '/overview', diff --git a/examples/vite-app/src/examples/NodeToolbar/CustomNode.tsx b/examples/vite-app/src/examples/NodeToolbar/CustomNode.tsx new file mode 100644 index 00000000..221b0034 --- /dev/null +++ b/examples/vite-app/src/examples/NodeToolbar/CustomNode.tsx @@ -0,0 +1,19 @@ +import { memo, FC } from 'react'; +import { Handle, Position, NodeProps, NodeToolbar } from 'reactflow'; + +const CustomNode: FC = ({ id, data, selected }) => { + return ( + <> + + + + + +
{data.label}
+ + + + ); +}; + +export default memo(CustomNode); diff --git a/examples/vite-app/src/examples/NodeToolbar/index.tsx b/examples/vite-app/src/examples/NodeToolbar/index.tsx new file mode 100644 index 00000000..13dba39b --- /dev/null +++ b/examples/vite-app/src/examples/NodeToolbar/index.tsx @@ -0,0 +1,74 @@ +import ReactFlow, { + MiniMap, + Background, + BackgroundVariant, + Controls, + Node, + Edge, + NodeTypes, + Position, +} from 'reactflow'; + +import CustomNode from './CustomNode'; + +const nodeTypes: NodeTypes = { + custom: CustomNode, +}; + +const initialNodes: Node[] = [ + { + id: '1', + type: 'custom', + data: { label: 'toolbar top', toolbarPosition: Position.Top }, + position: { x: 0, y: 100 }, + className: 'react-flow__node-default', + }, + { + id: '2', + type: 'custom', + data: { label: 'toolbar right', toolbarPosition: Position.Right }, + position: { x: 400, y: 0 }, + className: 'react-flow__node-default', + }, + { + id: '3', + type: 'custom', + data: { label: 'toolbar bottom', toolbarPosition: Position.Bottom }, + position: { x: 400, y: 100 }, + className: 'react-flow__node-default', + }, + { + id: '4', + type: 'custom', + data: { label: 'toolbar left', toolbarPosition: Position.Left }, + position: { x: 400, y: 200 }, + className: 'react-flow__node-default', + }, +]; + +const initialEdges: Edge[] = [ + { id: 'e1-2', source: '1', target: '2' }, + { id: 'e1-3', source: '1', target: '3' }, + { id: 'e1-4', source: '1', target: '4' }, +]; + +const defaultEdgeOptions = { zIndex: 0 }; + +export default function NodeToolbarExample() { + return ( + + + + + + ); +} diff --git a/packages/node-toolbar/.eslintrc.js b/packages/node-toolbar/.eslintrc.js new file mode 100644 index 00000000..31cfbd11 --- /dev/null +++ b/packages/node-toolbar/.eslintrc.js @@ -0,0 +1,4 @@ +module.exports = { + root: true, + extends: ['@reactflow/eslint-config'], +}; diff --git a/packages/node-toolbar/CHANGELOG.md b/packages/node-toolbar/CHANGELOG.md new file mode 100644 index 00000000..b1a03fb6 --- /dev/null +++ b/packages/node-toolbar/CHANGELOG.md @@ -0,0 +1 @@ +# @reactflow/node-toolbar \ No newline at end of file diff --git a/packages/node-toolbar/README.md b/packages/node-toolbar/README.md new file mode 100644 index 00000000..210d62ac --- /dev/null +++ b/packages/node-toolbar/README.md @@ -0,0 +1,10 @@ +# @reactflow/node-toolbar + +A toolbar component for React Flow that can be attached to a node. + +## Installation + +```sh +npm install @reactflow/node-toolbar +``` + diff --git a/packages/node-toolbar/package.json b/packages/node-toolbar/package.json new file mode 100644 index 00000000..01cfd4f3 --- /dev/null +++ b/packages/node-toolbar/package.json @@ -0,0 +1,68 @@ +{ + "name": "@reactflow/node-toolbar", + "version": "0.0.1", + "description": "A toolbar component for React Flow that can be attached to a node.", + "keywords": [ + "react", + "node-based UI", + "graph", + "diagram", + "workflow", + "react-flow" + ], + "files": [ + "dist" + ], + "source": "src/index.tsx", + "main": "dist/umd/index.js", + "module": "dist/esm/index.js", + "types": "dist/esm/index.d.ts", + "sideEffects": [ + "*.css" + ], + "publishConfig": { + "access": "public" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/wbkd/react-flow.git", + "directory": "packages/node-toolbar" + }, + "scripts": { + "dev": "concurrently \"rollup --config node:@reactflow/rollup-config --watch\" pnpm:css-watch", + "build": "rollup --config node:@reactflow/rollup-config --environment NODE_ENV:production && npm run css", + "css": "postcss src/*.css --config ../../tooling/postcss-config/postcss.config.js --dir dist", + "css-watch": "pnpm css --watch", + "lint": "eslint --ext .js,.jsx,.ts,.tsx src", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@babel/runtime": "^7.18.9", + "@reactflow/core": "workspace:*", + "classcat": "^5.0.3", + "zustand": "^4.1.1" + }, + "peerDependencies": { + "react": ">=17", + "react-dom": ">=17" + }, + "devDependencies": { + "@reactflow/eslint-config": "workspace:^0.0.0", + "@reactflow/rollup-config": "workspace:*", + "@reactflow/tsconfig": "workspace:*", + "@types/node": "^18.7.16", + "@types/react": "^18.0.19", + "@types/react-dom": "^18.0.6", + "react": "^18.2.0", + "typescript": "^4.8.3" + }, + "rollup": { + "globals": { + "zustand": "Zustand", + "zustand/shallow": "zustandShallow", + "classcat": "cc" + }, + "name": "ReactFlowNodeToolbar" + } +} diff --git a/packages/node-toolbar/src/NodeToolbar.tsx b/packages/node-toolbar/src/NodeToolbar.tsx new file mode 100644 index 00000000..696b490e --- /dev/null +++ b/packages/node-toolbar/src/NodeToolbar.tsx @@ -0,0 +1,83 @@ +import { useCallback, CSSProperties } from 'react'; +import { Node, ReactFlowState, useStore, getRectOfNodes, Transform, Rect, Position } from '@reactflow/core'; +import cc from 'classcat'; +import shallow from 'zustand/shallow'; + +import NodeToolbarPortal from './NodeToolbarPortal'; +import { NodeToolbarProps } from './types'; + +type SelectedNode = Node | undefined; + +const nodeEqualityFn = (a: SelectedNode, b: SelectedNode) => + a?.positionAbsolute?.x === b?.positionAbsolute?.x && + a?.positionAbsolute?.y === b?.positionAbsolute?.y && + a?.width === b?.width && + a?.height === b?.height && + a?.selected === b?.selected; + +const transformSelector = (state: ReactFlowState) => state.transform; + +function getTransform(nodeRect: Rect, transform: Transform, position: Position, offset: number): string { + // position === Position.Top + let xPos = (nodeRect.x + nodeRect.width / 2) * transform[2] + transform[0]; + let yPos = nodeRect.y * transform[2] + transform[1] - offset; + let xShift = -50; + let yShift = -100; + + switch (position) { + case Position.Right: + xPos = (nodeRect.x + nodeRect.width) * transform[2] + transform[0] + offset; + yPos = (nodeRect.y + nodeRect.height / 2) * transform[2] + transform[1]; + xShift = 0; + yShift = -50; + break; + case Position.Bottom: + yPos = (nodeRect.y + nodeRect.height) * transform[2] + transform[1] + offset; + yShift = 0; + break; + case Position.Left: + xPos = nodeRect.x * transform[2] + transform[0] - offset; + yPos = (nodeRect.y + nodeRect.height / 2) * transform[2] + transform[1]; + xShift = -100; + yShift = -50; + break; + } + + return `translate(${xPos}px, ${yPos}px) translate(${xShift}%, ${yShift}%)`; +} + +function NodeToolbar({ + nodeId, + children, + className, + style, + isActive, + position = Position.Top, + offset = 10, + ...rest +}: NodeToolbarProps) { + const nodeSelector = useCallback((state: ReactFlowState): SelectedNode => state.nodeInternals.get(nodeId), [nodeId]); + const node = useStore(nodeSelector, nodeEqualityFn); + const transform = useStore(transformSelector, shallow); + + if (!isActive || !node) { + return null; + } + + const nodeRect: Rect = getRectOfNodes([node]); + + const wrapperStyle: CSSProperties = { + transform: getTransform(nodeRect, transform, position, offset), + ...style, + }; + + return ( + +
+ {children} +
+
+ ); +} + +export default NodeToolbar; diff --git a/packages/node-toolbar/src/NodeToolbarPortal.tsx b/packages/node-toolbar/src/NodeToolbarPortal.tsx new file mode 100644 index 00000000..fa1509a4 --- /dev/null +++ b/packages/node-toolbar/src/NodeToolbarPortal.tsx @@ -0,0 +1,15 @@ +import { ReactNode } from 'react'; +import { createPortal } from 'react-dom'; +import { ReactFlowState, useStore } from '@reactflow/core'; + +function NodeToolbarPortal({ children }: { children: ReactNode }) { + const wrapperRef = useStore((state: ReactFlowState) => state.domNode?.querySelector('.react-flow__pane')); + + if (!wrapperRef) { + return null; + } + + return createPortal(children, wrapperRef); +} + +export default NodeToolbarPortal; diff --git a/packages/node-toolbar/src/index.tsx b/packages/node-toolbar/src/index.tsx new file mode 100644 index 00000000..3cded08b --- /dev/null +++ b/packages/node-toolbar/src/index.tsx @@ -0,0 +1,2 @@ +export { default as NodeToolbar } from './NodeToolbar'; +export * from './types'; diff --git a/packages/node-toolbar/src/style.css b/packages/node-toolbar/src/style.css new file mode 100644 index 00000000..2f59ab13 --- /dev/null +++ b/packages/node-toolbar/src/style.css @@ -0,0 +1,4 @@ +.react-flow__node-toolbar { + position: absolute; + z-index: 1000; +} diff --git a/packages/node-toolbar/src/types.ts b/packages/node-toolbar/src/types.ts new file mode 100644 index 00000000..c8720df7 --- /dev/null +++ b/packages/node-toolbar/src/types.ts @@ -0,0 +1,9 @@ +import { Position } from '@reactflow/core'; +import type { HTMLAttributes } from 'react'; + +export type NodeToolbarProps = HTMLAttributes & { + nodeId: string; + isActive?: boolean; + position?: Position; + offset?: number; +}; diff --git a/packages/node-toolbar/tsconfig.json b/packages/node-toolbar/tsconfig.json new file mode 100644 index 00000000..994d3bf0 --- /dev/null +++ b/packages/node-toolbar/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "@reactflow/tsconfig/react.json", + "display": "@reactflow/node-toolbar", + "include": ["**/*.ts", "**/*.tsx"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/reactflow/package.json b/packages/reactflow/package.json index 3cd02d16..bc6095ef 100644 --- a/packages/reactflow/package.json +++ b/packages/reactflow/package.json @@ -38,7 +38,8 @@ "@reactflow/background": "workspace:*", "@reactflow/controls": "workspace:*", "@reactflow/core": "workspace:*", - "@reactflow/minimap": "workspace:*" + "@reactflow/minimap": "workspace:*", + "@reactflow/node-toolbar": "workspace:*" }, "peerDependencies": { "react": ">=17", @@ -58,7 +59,8 @@ "@reactflow/background": "ReactFlowBackground", "@reactflow/controls": "ReactFlowControls", "@reactflow/core": "ReactFlowCore", - "@reactflow/minimap": "ReactFlowMinimap" + "@reactflow/minimap": "ReactFlowMinimap", + "@reactflow/node-toolbar": "ReactFlowNodeToolbar" }, "name": "ReactFlow" } diff --git a/packages/reactflow/src/index.ts b/packages/reactflow/src/index.ts index 310aa1f4..935883dc 100644 --- a/packages/reactflow/src/index.ts +++ b/packages/reactflow/src/index.ts @@ -2,5 +2,6 @@ export * from '@reactflow/core'; export * from '@reactflow/minimap'; export * from '@reactflow/controls'; export * from '@reactflow/background'; +export * from '@reactflow/node-toolbar'; export { ReactFlow as default } from '@reactflow/core'; diff --git a/packages/reactflow/src/style.css b/packages/reactflow/src/style.css index 96c6e6a1..f2d7c76c 100644 --- a/packages/reactflow/src/style.css +++ b/packages/reactflow/src/style.css @@ -1,3 +1,4 @@ @import '@reactflow/core/dist/style.css'; @import '@reactflow/controls/dist/style.css'; @import '@reactflow/minimap/dist/style.css'; +@import '@reactflow/node-toolbar/dist/style.css'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index afd78032..6d9414c1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,8 +32,8 @@ importers: '@changesets/changelog-github': registry.npmjs.org/@changesets/changelog-github/0.4.7 '@changesets/cli': registry.npmjs.org/@changesets/cli/2.25.0 '@preconstruct/cli': registry.npmjs.org/@preconstruct/cli/2.2.1 - '@typescript-eslint/eslint-plugin': registry.npmjs.org/@typescript-eslint/eslint-plugin/5.42.0_dcn2ddfkdgyby36a3kmqplwxkq - '@typescript-eslint/parser': registry.npmjs.org/@typescript-eslint/parser/5.42.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/eslint-plugin': registry.npmjs.org/@typescript-eslint/eslint-plugin/5.43.0_nctdnn3gg3ldnbrjkdxid2oppm + '@typescript-eslint/parser': registry.npmjs.org/@typescript-eslint/parser/5.43.0_irgkl5vooow2ydyo6aokmferha autoprefixer: registry.npmjs.org/autoprefixer/10.4.9_postcss@8.4.16 concurrently: registry.npmjs.org/concurrently/7.4.0 cypress: registry.npmjs.org/cypress/10.7.0 @@ -215,6 +215,35 @@ importers: react: registry.npmjs.org/react/18.2.0 typescript: registry.npmjs.org/typescript/4.8.3 + packages/node-toolbar: + specifiers: + '@babel/runtime': ^7.18.9 + '@reactflow/core': workspace:* + '@reactflow/eslint-config': workspace:^0.0.0 + '@reactflow/rollup-config': workspace:* + '@reactflow/tsconfig': workspace:* + '@types/node': ^18.7.16 + '@types/react': ^18.0.19 + '@types/react-dom': ^18.0.6 + classcat: ^5.0.3 + react: ^18.2.0 + typescript: ^4.8.3 + zustand: ^4.1.1 + dependencies: + '@babel/runtime': registry.npmjs.org/@babel/runtime/7.19.0 + '@reactflow/core': link:../core + classcat: registry.npmjs.org/classcat/5.0.4 + zustand: registry.npmjs.org/zustand/4.1.1_react@18.2.0 + devDependencies: + '@reactflow/eslint-config': link:../../tooling/eslint-config + '@reactflow/rollup-config': link:../../tooling/rollup-config + '@reactflow/tsconfig': link:../../tooling/tsconfig + '@types/node': registry.npmjs.org/@types/node/18.7.16 + '@types/react': registry.npmjs.org/@types/react/18.0.19 + '@types/react-dom': registry.npmjs.org/@types/react-dom/18.0.6 + react: registry.npmjs.org/react/18.2.0 + typescript: registry.npmjs.org/typescript/4.8.3 + packages/reactflow: specifiers: '@reactflow/background': workspace:* @@ -222,6 +251,7 @@ importers: '@reactflow/core': workspace:* '@reactflow/eslint-config': workspace:^0.0.0 '@reactflow/minimap': workspace:* + '@reactflow/node-toolbar': workspace:* '@reactflow/rollup-config': workspace:* '@reactflow/tsconfig': workspace:* '@types/node': ^18.7.16 @@ -233,6 +263,7 @@ importers: '@reactflow/controls': link:../controls '@reactflow/core': link:../core '@reactflow/minimap': link:../minimap + '@reactflow/node-toolbar': link:../node-toolbar devDependencies: '@reactflow/eslint-config': link:../../tooling/eslint-config '@reactflow/rollup-config': link:../../tooling/rollup-config @@ -1720,11 +1751,11 @@ packages: dev: true optional: true - registry.npmjs.org/@typescript-eslint/eslint-plugin/5.42.0_dcn2ddfkdgyby36a3kmqplwxkq: - resolution: {integrity: sha512-5TJh2AgL6+wpL8H/GTSjNb4WrjKoR2rqvFxR/DDTqYNk6uXn8BJMEcncLSpMbf/XV1aS0jAjYwn98uvVCiAywQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.42.0.tgz} - id: registry.npmjs.org/@typescript-eslint/eslint-plugin/5.42.0 + registry.npmjs.org/@typescript-eslint/eslint-plugin/5.43.0_nctdnn3gg3ldnbrjkdxid2oppm: + resolution: {integrity: sha512-wNPzG+eDR6+hhW4yobEmpR36jrqqQv1vxBq5LJO3fBAktjkvekfr4BRl+3Fn1CM/A+s8/EiGUbOMDoYqWdbtXA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.43.0.tgz} + id: registry.npmjs.org/@typescript-eslint/eslint-plugin/5.43.0 name: '@typescript-eslint/eslint-plugin' - version: 5.42.0 + version: 5.43.0 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: '@typescript-eslint/parser': ^5.0.0 @@ -1734,10 +1765,10 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': registry.npmjs.org/@typescript-eslint/parser/5.42.0_irgkl5vooow2ydyo6aokmferha - '@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager/5.42.0 - '@typescript-eslint/type-utils': registry.npmjs.org/@typescript-eslint/type-utils/5.42.0_irgkl5vooow2ydyo6aokmferha - '@typescript-eslint/utils': registry.npmjs.org/@typescript-eslint/utils/5.42.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/parser': registry.npmjs.org/@typescript-eslint/parser/5.43.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager/5.43.0 + '@typescript-eslint/type-utils': registry.npmjs.org/@typescript-eslint/type-utils/5.43.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/utils': registry.npmjs.org/@typescript-eslint/utils/5.43.0_irgkl5vooow2ydyo6aokmferha debug: registry.npmjs.org/debug/4.3.4 eslint: registry.npmjs.org/eslint/8.23.1 ignore: registry.npmjs.org/ignore/5.2.0 @@ -1750,11 +1781,11 @@ packages: - supports-color dev: true - registry.npmjs.org/@typescript-eslint/parser/5.42.0_irgkl5vooow2ydyo6aokmferha: - resolution: {integrity: sha512-Ixh9qrOTDRctFg3yIwrLkgf33AHyEIn6lhyf5cCfwwiGtkWhNpVKlEZApi3inGQR/barWnY7qY8FbGKBO7p3JA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.42.0.tgz} - id: registry.npmjs.org/@typescript-eslint/parser/5.42.0 + registry.npmjs.org/@typescript-eslint/parser/5.43.0_irgkl5vooow2ydyo6aokmferha: + resolution: {integrity: sha512-2iHUK2Lh7PwNUlhFxxLI2haSDNyXvebBO9izhjhMoDC+S3XI9qt2DGFUsiJ89m2k7gGYch2aEpYqV5F/+nwZug==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.43.0.tgz} + id: registry.npmjs.org/@typescript-eslint/parser/5.43.0 name: '@typescript-eslint/parser' - version: 5.42.0 + version: 5.43.0 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -1763,9 +1794,9 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager/5.42.0 - '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.42.0 - '@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree/5.42.0_typescript@4.8.3 + '@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager/5.43.0 + '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.43.0 + '@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree/5.43.0_typescript@4.8.3 debug: registry.npmjs.org/debug/4.3.4 eslint: registry.npmjs.org/eslint/8.23.1 typescript: registry.npmjs.org/typescript/4.8.3 @@ -1773,21 +1804,21 @@ packages: - supports-color dev: true - registry.npmjs.org/@typescript-eslint/scope-manager/5.42.0: - resolution: {integrity: sha512-l5/3IBHLH0Bv04y+H+zlcLiEMEMjWGaCX6WyHE5Uk2YkSGAMlgdUPsT/ywTSKgu9D1dmmKMYgYZijObfA39Wow==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.42.0.tgz} + registry.npmjs.org/@typescript-eslint/scope-manager/5.43.0: + resolution: {integrity: sha512-XNWnGaqAtTJsUiZaoiGIrdJYHsUOd3BZ3Qj5zKp9w6km6HsrjPk/TGZv0qMTWyWj0+1QOqpHQ2gZOLXaGA9Ekw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.43.0.tgz} name: '@typescript-eslint/scope-manager' - version: 5.42.0 + version: 5.43.0 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.42.0 - '@typescript-eslint/visitor-keys': registry.npmjs.org/@typescript-eslint/visitor-keys/5.42.0 + '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.43.0 + '@typescript-eslint/visitor-keys': registry.npmjs.org/@typescript-eslint/visitor-keys/5.43.0 dev: true - registry.npmjs.org/@typescript-eslint/type-utils/5.42.0_irgkl5vooow2ydyo6aokmferha: - resolution: {integrity: sha512-HW14TXC45dFVZxnVW8rnUGnvYyRC0E/vxXShFCthcC9VhVTmjqOmtqj6H5rm9Zxv+ORxKA/1aLGD7vmlLsdlOg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.42.0.tgz} - id: registry.npmjs.org/@typescript-eslint/type-utils/5.42.0 + registry.npmjs.org/@typescript-eslint/type-utils/5.43.0_irgkl5vooow2ydyo6aokmferha: + resolution: {integrity: sha512-K21f+KY2/VvYggLf5Pk4tgBOPs2otTaIHy2zjclo7UZGLyFH86VfUOm5iq+OtDtxq/Zwu2I3ujDBykVW4Xtmtg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.43.0.tgz} + id: registry.npmjs.org/@typescript-eslint/type-utils/5.43.0 name: '@typescript-eslint/type-utils' - version: 5.42.0 + version: 5.43.0 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '*' @@ -1796,8 +1827,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree/5.42.0_typescript@4.8.3 - '@typescript-eslint/utils': registry.npmjs.org/@typescript-eslint/utils/5.42.0_irgkl5vooow2ydyo6aokmferha + '@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree/5.43.0_typescript@4.8.3 + '@typescript-eslint/utils': registry.npmjs.org/@typescript-eslint/utils/5.43.0_irgkl5vooow2ydyo6aokmferha debug: registry.npmjs.org/debug/4.3.4 eslint: registry.npmjs.org/eslint/8.23.1 tsutils: registry.npmjs.org/tsutils/3.21.0_typescript@4.8.3 @@ -1806,18 +1837,18 @@ packages: - supports-color dev: true - registry.npmjs.org/@typescript-eslint/types/5.42.0: - resolution: {integrity: sha512-t4lzO9ZOAUcHY6bXQYRuu+3SSYdD9TS8ooApZft4WARt4/f2Cj/YpvbTe8A4GuhT4bNW72goDMOy7SW71mZwGw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/types/-/types-5.42.0.tgz} + registry.npmjs.org/@typescript-eslint/types/5.43.0: + resolution: {integrity: sha512-jpsbcD0x6AUvV7tyOlyvon0aUsQpF8W+7TpJntfCUWU1qaIKu2K34pMwQKSzQH8ORgUrGYY6pVIh1Pi8TNeteg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/types/-/types-5.43.0.tgz} name: '@typescript-eslint/types' - version: 5.42.0 + version: 5.43.0 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - registry.npmjs.org/@typescript-eslint/typescript-estree/5.42.0_typescript@4.8.3: - resolution: {integrity: sha512-2O3vSq794x3kZGtV7i4SCWZWCwjEtkWfVqX4m5fbUBomOsEOyd6OAD1qU2lbvV5S8tgy/luJnOYluNyYVeOTTg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.42.0.tgz} - id: registry.npmjs.org/@typescript-eslint/typescript-estree/5.42.0 + registry.npmjs.org/@typescript-eslint/typescript-estree/5.43.0_typescript@4.8.3: + resolution: {integrity: sha512-BZ1WVe+QQ+igWal2tDbNg1j2HWUkAa+CVqdU79L4HP9izQY6CNhXfkNwd1SS4+sSZAP/EthI1uiCSY/+H0pROg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.43.0.tgz} + id: registry.npmjs.org/@typescript-eslint/typescript-estree/5.43.0 name: '@typescript-eslint/typescript-estree' - version: 5.42.0 + version: 5.43.0 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' @@ -1825,8 +1856,8 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.42.0 - '@typescript-eslint/visitor-keys': registry.npmjs.org/@typescript-eslint/visitor-keys/5.42.0 + '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.43.0 + '@typescript-eslint/visitor-keys': registry.npmjs.org/@typescript-eslint/visitor-keys/5.43.0 debug: registry.npmjs.org/debug/4.3.4 globby: registry.npmjs.org/globby/11.1.0 is-glob: registry.npmjs.org/is-glob/4.0.3 @@ -1837,20 +1868,20 @@ packages: - supports-color dev: true - registry.npmjs.org/@typescript-eslint/utils/5.42.0_irgkl5vooow2ydyo6aokmferha: - resolution: {integrity: sha512-JZ++3+h1vbeG1NUECXQZE3hg0kias9kOtcQr3+JVQ3whnjvKuMyktJAAIj6743OeNPnGBmjj7KEmiDL7qsdnCQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.42.0.tgz} - id: registry.npmjs.org/@typescript-eslint/utils/5.42.0 + registry.npmjs.org/@typescript-eslint/utils/5.43.0_irgkl5vooow2ydyo6aokmferha: + resolution: {integrity: sha512-8nVpA6yX0sCjf7v/NDfeaOlyaIIqL7OaIGOWSPFqUKK59Gnumd3Wa+2l8oAaYO2lk0sO+SbWFWRSvhu8gLGv4A==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.43.0.tgz} + id: registry.npmjs.org/@typescript-eslint/utils/5.43.0 name: '@typescript-eslint/utils' - version: 5.42.0 + version: 5.43.0 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: '@types/json-schema': registry.npmjs.org/@types/json-schema/7.0.11 '@types/semver': registry.npmjs.org/@types/semver/7.3.13 - '@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager/5.42.0 - '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.42.0 - '@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree/5.42.0_typescript@4.8.3 + '@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager/5.43.0 + '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.43.0 + '@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree/5.43.0_typescript@4.8.3 eslint: registry.npmjs.org/eslint/8.23.1 eslint-scope: registry.npmjs.org/eslint-scope/5.1.1 eslint-utils: registry.npmjs.org/eslint-utils/3.0.0_eslint@8.23.1 @@ -1860,13 +1891,13 @@ packages: - typescript dev: true - registry.npmjs.org/@typescript-eslint/visitor-keys/5.42.0: - resolution: {integrity: sha512-QHbu5Hf/2lOEOwy+IUw0GoSCuAzByTAWWrOTKzTzsotiUnWFpuKnXcAhC9YztAf2EElQ0VvIK+pHJUPkM0q7jg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.42.0.tgz} + registry.npmjs.org/@typescript-eslint/visitor-keys/5.43.0: + resolution: {integrity: sha512-icl1jNH/d18OVHLfcwdL3bWUKsBeIiKYTGxMJCoGe7xFht+E4QgzOqoWYrU8XSLJWhVw8nTacbm03v23J/hFTg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.43.0.tgz} name: '@typescript-eslint/visitor-keys' - version: 5.42.0 + version: 5.43.0 engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.42.0 + '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.43.0 eslint-visitor-keys: registry.npmjs.org/eslint-visitor-keys/3.3.0 dev: true From 20a6653577f806cab5af93d8e11fa187ace40f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christopher=20M=C3=B6ller?= Date: Wed, 16 Nov 2022 09:56:34 +0100 Subject: [PATCH 2/8] feat(node-toolbar): use z-index of the node for the toolbar --- packages/node-toolbar/src/NodeToolbar.tsx | 15 +++++++++++++-- packages/node-toolbar/src/NodeToolbarPortal.tsx | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/node-toolbar/src/NodeToolbar.tsx b/packages/node-toolbar/src/NodeToolbar.tsx index 696b490e..c8085ecf 100644 --- a/packages/node-toolbar/src/NodeToolbar.tsx +++ b/packages/node-toolbar/src/NodeToolbar.tsx @@ -1,5 +1,14 @@ import { useCallback, CSSProperties } from 'react'; -import { Node, ReactFlowState, useStore, getRectOfNodes, Transform, Rect, Position } from '@reactflow/core'; +import { + Node, + ReactFlowState, + useStore, + getRectOfNodes, + Transform, + Rect, + Position, + internalsSymbol, +} from '@reactflow/core'; import cc from 'classcat'; import shallow from 'zustand/shallow'; @@ -13,7 +22,8 @@ const nodeEqualityFn = (a: SelectedNode, b: SelectedNode) => a?.positionAbsolute?.y === b?.positionAbsolute?.y && a?.width === b?.width && a?.height === b?.height && - a?.selected === b?.selected; + a?.selected === b?.selected && + a?.[internalsSymbol]?.z === b?.[internalsSymbol]?.z; const transformSelector = (state: ReactFlowState) => state.transform; @@ -68,6 +78,7 @@ function NodeToolbar({ const wrapperStyle: CSSProperties = { transform: getTransform(nodeRect, transform, position, offset), + zIndex: node[internalsSymbol]?.z, ...style, }; diff --git a/packages/node-toolbar/src/NodeToolbarPortal.tsx b/packages/node-toolbar/src/NodeToolbarPortal.tsx index fa1509a4..f899352f 100644 --- a/packages/node-toolbar/src/NodeToolbarPortal.tsx +++ b/packages/node-toolbar/src/NodeToolbarPortal.tsx @@ -3,7 +3,7 @@ import { createPortal } from 'react-dom'; import { ReactFlowState, useStore } from '@reactflow/core'; function NodeToolbarPortal({ children }: { children: ReactNode }) { - const wrapperRef = useStore((state: ReactFlowState) => state.domNode?.querySelector('.react-flow__pane')); + const wrapperRef = useStore((state: ReactFlowState) => state.domNode?.querySelector('.react-flow__renderer')); if (!wrapperRef) { return null; From ccbffeb139897ea984066bd77a02f442f9ff6a8c Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 16 Nov 2022 10:53:26 +0100 Subject: [PATCH 3/8] fix(node-toolbar): handle nodeOrigin --- examples/vite-app/src/examples/NodeToolbar/index.tsx | 3 +++ packages/node-toolbar/src/NodeToolbar.tsx | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/vite-app/src/examples/NodeToolbar/index.tsx b/examples/vite-app/src/examples/NodeToolbar/index.tsx index 13dba39b..424ee202 100644 --- a/examples/vite-app/src/examples/NodeToolbar/index.tsx +++ b/examples/vite-app/src/examples/NodeToolbar/index.tsx @@ -7,6 +7,7 @@ import ReactFlow, { Edge, NodeTypes, Position, + NodeOrigin, } from 'reactflow'; import CustomNode from './CustomNode'; @@ -53,6 +54,7 @@ const initialEdges: Edge[] = [ ]; const defaultEdgeOptions = { zIndex: 0 }; +const nodeOrigin: NodeOrigin = [0.5, 0.5]; export default function NodeToolbarExample() { return ( @@ -65,6 +67,7 @@ export default function NodeToolbarExample() { fitView defaultEdgeOptions={defaultEdgeOptions} nodeTypes={nodeTypes} + nodeOrigin={nodeOrigin} > diff --git a/packages/node-toolbar/src/NodeToolbar.tsx b/packages/node-toolbar/src/NodeToolbar.tsx index c8085ecf..c413eb30 100644 --- a/packages/node-toolbar/src/NodeToolbar.tsx +++ b/packages/node-toolbar/src/NodeToolbar.tsx @@ -25,7 +25,7 @@ const nodeEqualityFn = (a: SelectedNode, b: SelectedNode) => a?.selected === b?.selected && a?.[internalsSymbol]?.z === b?.[internalsSymbol]?.z; -const transformSelector = (state: ReactFlowState) => state.transform; +const transformSelector = (state: ReactFlowState) => ({ transform: state.transform, nodeOrigin: state.nodeOrigin }); function getTransform(nodeRect: Rect, transform: Transform, position: Position, offset: number): string { // position === Position.Top @@ -68,13 +68,13 @@ function NodeToolbar({ }: NodeToolbarProps) { const nodeSelector = useCallback((state: ReactFlowState): SelectedNode => state.nodeInternals.get(nodeId), [nodeId]); const node = useStore(nodeSelector, nodeEqualityFn); - const transform = useStore(transformSelector, shallow); + const { transform, nodeOrigin } = useStore(transformSelector, shallow); if (!isActive || !node) { return null; } - const nodeRect: Rect = getRectOfNodes([node]); + const nodeRect: Rect = getRectOfNodes([node], nodeOrigin); const wrapperStyle: CSSProperties = { transform: getTransform(nodeRect, transform, position, offset), From be8f22e5f3ccde5bf63feab145ec4cf3d8568f4e Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 16 Nov 2022 10:59:20 +0100 Subject: [PATCH 4/8] chore(node-toolbar): cleanup --- packages/node-toolbar/src/NodeToolbar.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/node-toolbar/src/NodeToolbar.tsx b/packages/node-toolbar/src/NodeToolbar.tsx index c413eb30..1b98682e 100644 --- a/packages/node-toolbar/src/NodeToolbar.tsx +++ b/packages/node-toolbar/src/NodeToolbar.tsx @@ -25,7 +25,7 @@ const nodeEqualityFn = (a: SelectedNode, b: SelectedNode) => a?.selected === b?.selected && a?.[internalsSymbol]?.z === b?.[internalsSymbol]?.z; -const transformSelector = (state: ReactFlowState) => ({ transform: state.transform, nodeOrigin: state.nodeOrigin }); +const selector = (state: ReactFlowState) => ({ transform: state.transform, nodeOrigin: state.nodeOrigin }); function getTransform(nodeRect: Rect, transform: Transform, position: Position, offset: number): string { // position === Position.Top @@ -68,7 +68,7 @@ function NodeToolbar({ }: NodeToolbarProps) { const nodeSelector = useCallback((state: ReactFlowState): SelectedNode => state.nodeInternals.get(nodeId), [nodeId]); const node = useStore(nodeSelector, nodeEqualityFn); - const { transform, nodeOrigin } = useStore(transformSelector, shallow); + const { transform, nodeOrigin } = useStore(selector, shallow); if (!isActive || !node) { return null; From edbf894350bc3aa47e8fe7d8fbd4dfe487055500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christopher=20M=C3=B6ller?= Date: Wed, 16 Nov 2022 13:49:15 +0100 Subject: [PATCH 5/8] feat(node-toolbar): change isActive to isVisible and implement default behavior --- .../vite-app/src/examples/NodeToolbar/CustomNode.tsx | 4 ++-- examples/vite-app/src/examples/NodeToolbar/index.tsx | 9 ++++++++- packages/node-toolbar/src/NodeToolbar.tsx | 8 ++++++-- packages/node-toolbar/src/types.ts | 2 +- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/examples/vite-app/src/examples/NodeToolbar/CustomNode.tsx b/examples/vite-app/src/examples/NodeToolbar/CustomNode.tsx index 221b0034..4f8ab270 100644 --- a/examples/vite-app/src/examples/NodeToolbar/CustomNode.tsx +++ b/examples/vite-app/src/examples/NodeToolbar/CustomNode.tsx @@ -1,10 +1,10 @@ import { memo, FC } from 'react'; import { Handle, Position, NodeProps, NodeToolbar } from 'reactflow'; -const CustomNode: FC = ({ id, data, selected }) => { +const CustomNode: FC = ({ id, data }) => { return ( <> - + diff --git a/examples/vite-app/src/examples/NodeToolbar/index.tsx b/examples/vite-app/src/examples/NodeToolbar/index.tsx index 13dba39b..4389873c 100644 --- a/examples/vite-app/src/examples/NodeToolbar/index.tsx +++ b/examples/vite-app/src/examples/NodeToolbar/index.tsx @@ -20,7 +20,7 @@ const initialNodes: Node[] = [ id: '1', type: 'custom', data: { label: 'toolbar top', toolbarPosition: Position.Top }, - position: { x: 0, y: 100 }, + position: { x: 0, y: 0 }, className: 'react-flow__node-default', }, { @@ -44,6 +44,13 @@ const initialNodes: Node[] = [ position: { x: 400, y: 200 }, className: 'react-flow__node-default', }, + { + id: '5', + type: 'custom', + data: { label: 'toolbar always open', toolbarPosition: Position.Top, toolbarVisible: true }, + position: { x: 0, y: 150 }, + className: 'react-flow__node-default', + }, ]; const initialEdges: Edge[] = [ diff --git a/packages/node-toolbar/src/NodeToolbar.tsx b/packages/node-toolbar/src/NodeToolbar.tsx index c8085ecf..50207dda 100644 --- a/packages/node-toolbar/src/NodeToolbar.tsx +++ b/packages/node-toolbar/src/NodeToolbar.tsx @@ -25,7 +25,9 @@ const nodeEqualityFn = (a: SelectedNode, b: SelectedNode) => a?.selected === b?.selected && a?.[internalsSymbol]?.z === b?.[internalsSymbol]?.z; -const transformSelector = (state: ReactFlowState) => state.transform; +const transformSelector = (state: ReactFlowState): Transform => state.transform; +const selectedNodesCountSelector = (state: ReactFlowState): number => + Array.from(state.nodeInternals.values()).filter((node) => node.selected).length; function getTransform(nodeRect: Rect, transform: Transform, position: Position, offset: number): string { // position === Position.Top @@ -61,7 +63,7 @@ function NodeToolbar({ children, className, style, - isActive, + isVisible, position = Position.Top, offset = 10, ...rest @@ -69,6 +71,8 @@ function NodeToolbar({ const nodeSelector = useCallback((state: ReactFlowState): SelectedNode => state.nodeInternals.get(nodeId), [nodeId]); const node = useStore(nodeSelector, nodeEqualityFn); const transform = useStore(transformSelector, shallow); + const selectedNodesCount = useStore(selectedNodesCountSelector); + const isActive = typeof isVisible === 'boolean' ? isVisible : node?.selected && selectedNodesCount === 1; if (!isActive || !node) { return null; diff --git a/packages/node-toolbar/src/types.ts b/packages/node-toolbar/src/types.ts index c8720df7..1e6576b6 100644 --- a/packages/node-toolbar/src/types.ts +++ b/packages/node-toolbar/src/types.ts @@ -3,7 +3,7 @@ import type { HTMLAttributes } from 'react'; export type NodeToolbarProps = HTMLAttributes & { nodeId: string; - isActive?: boolean; + isVisible?: boolean; position?: Position; offset?: number; }; From 1841dfa2cae93e2ab4eb05d63f3a832a095983da Mon Sep 17 00:00:00 2001 From: moklick Date: Wed, 16 Nov 2022 18:28:25 +0100 Subject: [PATCH 6/8] refactor(node-toolbar): define zustand selector outside of the component --- packages/node-toolbar/src/NodeToolbarPortal.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/node-toolbar/src/NodeToolbarPortal.tsx b/packages/node-toolbar/src/NodeToolbarPortal.tsx index f899352f..732362e5 100644 --- a/packages/node-toolbar/src/NodeToolbarPortal.tsx +++ b/packages/node-toolbar/src/NodeToolbarPortal.tsx @@ -2,8 +2,10 @@ import { ReactNode } from 'react'; import { createPortal } from 'react-dom'; import { ReactFlowState, useStore } from '@reactflow/core'; +const selector = (state: ReactFlowState) => state.domNode?.querySelector('.react-flow__renderer'); + function NodeToolbarPortal({ children }: { children: ReactNode }) { - const wrapperRef = useStore((state: ReactFlowState) => state.domNode?.querySelector('.react-flow__renderer')); + const wrapperRef = useStore(selector); if (!wrapperRef) { return null; From b31d8e9dc20e94f916d8d098d08066811958eb14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christopher=20M=C3=B6ller?= Date: Thu, 17 Nov 2022 09:59:28 +0100 Subject: [PATCH 7/8] feat(node-toolbar): remove css from node-toolbar component, set version to 1.0.0 --- packages/node-toolbar/package.json | 6 ++---- packages/node-toolbar/src/NodeToolbar.tsx | 3 ++- packages/node-toolbar/src/style.css | 4 ---- packages/reactflow/src/style.css | 1 - 4 files changed, 4 insertions(+), 10 deletions(-) delete mode 100644 packages/node-toolbar/src/style.css diff --git a/packages/node-toolbar/package.json b/packages/node-toolbar/package.json index 01cfd4f3..ad15e213 100644 --- a/packages/node-toolbar/package.json +++ b/packages/node-toolbar/package.json @@ -1,6 +1,6 @@ { "name": "@reactflow/node-toolbar", - "version": "0.0.1", + "version": "1.0.0", "description": "A toolbar component for React Flow that can be attached to a node.", "keywords": [ "react", @@ -31,9 +31,7 @@ }, "scripts": { "dev": "concurrently \"rollup --config node:@reactflow/rollup-config --watch\" pnpm:css-watch", - "build": "rollup --config node:@reactflow/rollup-config --environment NODE_ENV:production && npm run css", - "css": "postcss src/*.css --config ../../tooling/postcss-config/postcss.config.js --dir dist", - "css-watch": "pnpm css --watch", + "build": "rollup --config node:@reactflow/rollup-config --environment NODE_ENV:production", "lint": "eslint --ext .js,.jsx,.ts,.tsx src", "typecheck": "tsc --noEmit" }, diff --git a/packages/node-toolbar/src/NodeToolbar.tsx b/packages/node-toolbar/src/NodeToolbar.tsx index 1dc5b4a8..caadf257 100644 --- a/packages/node-toolbar/src/NodeToolbar.tsx +++ b/packages/node-toolbar/src/NodeToolbar.tsx @@ -82,8 +82,9 @@ function NodeToolbar({ const nodeRect: Rect = getRectOfNodes([node], nodeOrigin); const wrapperStyle: CSSProperties = { + position: 'absolute', transform: getTransform(nodeRect, transform, position, offset), - zIndex: node[internalsSymbol]?.z, + zIndex: (node[internalsSymbol]?.z || 1) + 1, ...style, }; diff --git a/packages/node-toolbar/src/style.css b/packages/node-toolbar/src/style.css deleted file mode 100644 index 2f59ab13..00000000 --- a/packages/node-toolbar/src/style.css +++ /dev/null @@ -1,4 +0,0 @@ -.react-flow__node-toolbar { - position: absolute; - z-index: 1000; -} diff --git a/packages/reactflow/src/style.css b/packages/reactflow/src/style.css index f2d7c76c..96c6e6a1 100644 --- a/packages/reactflow/src/style.css +++ b/packages/reactflow/src/style.css @@ -1,4 +1,3 @@ @import '@reactflow/core/dist/style.css'; @import '@reactflow/controls/dist/style.css'; @import '@reactflow/minimap/dist/style.css'; -@import '@reactflow/node-toolbar/dist/style.css'; From 98116d431f9fcdcc9b23a5b606a94ec0740b64cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christopher=20M=C3=B6ller?= Date: Thu, 17 Nov 2022 11:28:41 +0100 Subject: [PATCH 8/8] chore(reactflow): add changeset for reactflow package --- .changeset/cuddly-books-kiss.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/cuddly-books-kiss.md diff --git a/.changeset/cuddly-books-kiss.md b/.changeset/cuddly-books-kiss.md new file mode 100644 index 00000000..bda976f5 --- /dev/null +++ b/.changeset/cuddly-books-kiss.md @@ -0,0 +1,5 @@ +--- +'reactflow': minor +--- + +Export a new component "NodeToolbar" that renders a fixed element attached to a node