diff --git a/examples/vite-app/src/examples/EasyConnect/CustomNode.tsx b/examples/vite-app/src/examples/EasyConnect/CustomNode.tsx index 989df5fa..bd107c93 100644 --- a/examples/vite-app/src/examples/EasyConnect/CustomNode.tsx +++ b/examples/vite-app/src/examples/EasyConnect/CustomNode.tsx @@ -2,8 +2,9 @@ import { Handle, NodeProps, Position, ReactFlowState, useStore } from 'reactflow const connectionNodeIdSelector = (state: ReactFlowState) => state.connectionNodeId; -export default function CustomNode({ id, isConnectable }: NodeProps) { +export default function CustomNode({ id }: NodeProps) { const connectionNodeId = useStore(connectionNodeIdSelector); + const isConnecting = !!connectionNodeId; const isTarget = connectionNodeId && connectionNodeId !== id; const targetHandleStyle = { zIndex: isTarget ? 3 : 1 }; @@ -18,19 +19,16 @@ export default function CustomNode({ id, isConnectable }: NodeProps) { backgroundColor: isTarget ? '#ffcce3' : '#ccd9f6', }} > + {!isConnecting && ( + + )} + - {label} diff --git a/examples/vite-app/src/examples/EasyConnect/style.css b/examples/vite-app/src/examples/EasyConnect/style.css index c2ebc0a2..8e06c4ea 100644 --- a/examples/vite-app/src/examples/EasyConnect/style.css +++ b/examples/vite-app/src/examples/EasyConnect/style.css @@ -28,19 +28,7 @@ border: 2px solid #222138; } -div.sourceHandle { - width: 100%; - height: 100%; - position: absolute; - top: 0; - left: 0; - border-radius: 0; - transform: none; - border: none; - opacity: 0; -} - -div.targetHandle { +div.customHandle { width: 100%; height: 100%; background: blue; diff --git a/examples/vite-app/src/examples/Edges/CustomEdge.tsx b/examples/vite-app/src/examples/Edges/CustomEdge.tsx index ec7dfb74..ff700413 100644 --- a/examples/vite-app/src/examples/Edges/CustomEdge.tsx +++ b/examples/vite-app/src/examples/Edges/CustomEdge.tsx @@ -1,5 +1,5 @@ import { FC } from 'react'; -import { EdgeProps, getBezierPath } from 'reactflow'; +import { BaseEdge, EdgeProps, getBezierPath } from 'reactflow'; const CustomEdge: FC = ({ id, @@ -22,7 +22,7 @@ const CustomEdge: FC = ({ return ( <> - + {data.text} diff --git a/examples/vite-app/src/examples/Edges/CustomEdge2.tsx b/examples/vite-app/src/examples/Edges/CustomEdge2.tsx index 0ad41920..b40f12cb 100644 --- a/examples/vite-app/src/examples/Edges/CustomEdge2.tsx +++ b/examples/vite-app/src/examples/Edges/CustomEdge2.tsx @@ -1,5 +1,5 @@ import { FC } from 'react'; -import { EdgeProps, getBezierPath, EdgeText } from 'reactflow'; +import { EdgeProps, getBezierPath, EdgeText, BaseEdge } from 'reactflow'; const CustomEdge: FC = ({ id, @@ -22,7 +22,7 @@ const CustomEdge: FC = ({ return ( <> - + = ({ labelBgBorderRadius={2} onClick={() => console.log(data)} /> - ; ); }; diff --git a/examples/vite-app/src/examples/NodeToolbar/CustomNode.tsx b/examples/vite-app/src/examples/NodeToolbar/CustomNode.tsx index ca2ac0b7..7d179b7e 100644 --- a/examples/vite-app/src/examples/NodeToolbar/CustomNode.tsx +++ b/examples/vite-app/src/examples/NodeToolbar/CustomNode.tsx @@ -4,7 +4,7 @@ import { Handle, Position, NodeProps, NodeToolbar } from 'reactflow'; 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 601d8618..b4d3d1c5 100644 --- a/examples/vite-app/src/examples/NodeToolbar/index.tsx +++ b/examples/vite-app/src/examples/NodeToolbar/index.tsx @@ -17,49 +17,38 @@ const nodeTypes: NodeTypes = { custom: CustomNode, }; +const positions = ['top', 'right', 'bottom', 'left']; +const alignments = ['start', 'center', 'end']; + const initialNodes: Node[] = [ - { - id: '1', - type: 'custom', - data: { label: 'toolbar top', toolbarPosition: Position.Top }, - position: { x: 0, y: 50 }, - className: 'react-flow__node-default', - }, - { - id: '2', - type: 'custom', - data: { label: 'toolbar right', toolbarPosition: Position.Right }, - position: { x: 300, 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', - }, - { - id: '5', - type: 'custom', - data: { label: 'toolbar always open', toolbarPosition: Position.Top, toolbarVisible: true }, - position: { x: 0, y: 200 }, + data: { label: 'toolbar top', toolbarPosition: Position.Top }, + position: { x: 0, 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' }, -]; +positions.forEach((position, posIndex) => { + alignments.forEach((align, alignIndex) => { + const id = `node-${align}-${position}`; + initialNodes.push({ + id, + type: 'custom', + data: { + label: `toolbar ${position} ${align}`, + toolbarPosition: position as Position, + toolbarAlign: align, + toolbarVisible: true, + }, + className: 'react-flow__node-default', + position: { x: posIndex * 300, y: alignIndex * 100 }, + }); + }); +}); + +const initialEdges: Edge[] = []; const defaultEdgeOptions = { zIndex: 0 }; const nodeOrigin: NodeOrigin = [0.5, 0.5]; diff --git a/packages/background/CHANGELOG.md b/packages/background/CHANGELOG.md index 60978e3d..d5b1691f 100644 --- a/packages/background/CHANGELOG.md +++ b/packages/background/CHANGELOG.md @@ -1,5 +1,12 @@ # @reactflow/background +## 11.2.1 + +### Patch Changes + +- Updated dependencies [[`cf7a7d3d`](https://github.com/wbkd/react-flow/commit/cf7a7d3dad1e73215a72a5dc72e21fd50208cdbb), [`07b975bb`](https://github.com/wbkd/react-flow/commit/07b975bbee3580249e36a19582213b250f78093c), [`c80d269b`](https://github.com/wbkd/react-flow/commit/c80d269b85a0054221f4639c328fc36a3befbe70), [`a3fa164c`](https://github.com/wbkd/react-flow/commit/a3fa164c34cc820c79bb031c9fd97b72a3546614)]: + - @reactflow/core@11.7.1 + ## 11.2.0 ### Minor Changes diff --git a/packages/background/package.json b/packages/background/package.json index 6f378c30..3f2bb0a2 100644 --- a/packages/background/package.json +++ b/packages/background/package.json @@ -1,6 +1,6 @@ { "name": "@reactflow/background", - "version": "11.2.0", + "version": "11.2.1", "description": "Background component with different variants for React Flow", "keywords": [ "react", diff --git a/packages/controls/CHANGELOG.md b/packages/controls/CHANGELOG.md index e4815ed6..31a54565 100644 --- a/packages/controls/CHANGELOG.md +++ b/packages/controls/CHANGELOG.md @@ -1,5 +1,14 @@ # @reactflow/controls +## 11.1.12 + +### Patch Changes + +- [#3054](https://github.com/wbkd/react-flow/pull/3054) [`46526b4e`](https://github.com/wbkd/react-flow/commit/46526b4e02b83d74726701e3ba73d0be8cf80787) - fix(icons): show correct lock icon + +- Updated dependencies [[`cf7a7d3d`](https://github.com/wbkd/react-flow/commit/cf7a7d3dad1e73215a72a5dc72e21fd50208cdbb), [`07b975bb`](https://github.com/wbkd/react-flow/commit/07b975bbee3580249e36a19582213b250f78093c), [`c80d269b`](https://github.com/wbkd/react-flow/commit/c80d269b85a0054221f4639c328fc36a3befbe70), [`a3fa164c`](https://github.com/wbkd/react-flow/commit/a3fa164c34cc820c79bb031c9fd97b72a3546614)]: + - @reactflow/core@11.7.1 + ## 11.1.11 ### Patch Changes diff --git a/packages/controls/package.json b/packages/controls/package.json index 777fbd6c..271d2967 100644 --- a/packages/controls/package.json +++ b/packages/controls/package.json @@ -1,6 +1,6 @@ { "name": "@reactflow/controls", - "version": "11.1.11", + "version": "11.1.12", "description": "Component to control the viewport of a React Flow instance", "keywords": [ "react", diff --git a/packages/controls/src/Controls.tsx b/packages/controls/src/Controls.tsx index 73234606..7c529a9e 100644 --- a/packages/controls/src/Controls.tsx +++ b/packages/controls/src/Controls.tsx @@ -1,8 +1,6 @@ -import { memo, useEffect, useState } from 'react'; -import type { FC, PropsWithChildren } from 'react'; +import { memo, useEffect, useState, type FC, type PropsWithChildren } from 'react'; import cc from 'classcat'; -import { useStore, useStoreApi, useReactFlow, Panel } from '@reactflow/core'; -import type { ReactFlowState } from '@reactflow/core'; +import { useStore, useStoreApi, useReactFlow, Panel, type ReactFlowState } from '@reactflow/core'; import PlusIcon from './Icons/Plus'; import MinusIcon from './Icons/Minus'; @@ -13,7 +11,7 @@ import ControlButton from './ControlButton'; import type { ControlProps } from './types'; -const isInteractiveSelector = (s: ReactFlowState) => s.nodesDraggable && s.nodesConnectable && s.elementsSelectable; +const isInteractiveSelector = (s: ReactFlowState) => s.nodesDraggable || s.nodesConnectable || s.elementsSelectable; const Controls: FC> = ({ style, diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 576d20ab..6c1b6932 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,12 +1,21 @@ # @reactflow/core +## 11.7.1 + +### Patch Changes + +- [#3043](https://github.com/wbkd/react-flow/pull/3043) [`cf7a7d3d`](https://github.com/wbkd/react-flow/commit/cf7a7d3dad1e73215a72a5dc72e21fd50208cdbb) - handles: handles on top of each other, reduce re-renderings +- [#3046](https://github.com/wbkd/react-flow/pull/3046) [`07b975bb`](https://github.com/wbkd/react-flow/commit/07b975bbee3580249e36a19582213b250f78093c) - base-edge: pass id to base edge path +- [#3007](https://github.com/wbkd/react-flow/pull/3007) [`c80d269b`](https://github.com/wbkd/react-flow/commit/c80d269b85a0054221f4639c328fc36a3befbe70) Thanks [@bcakmakoglu](https://github.com/bcakmakoglu)! - allow array of ids as updateNodeInternals arg +- [#3029](https://github.com/wbkd/react-flow/pull/3029) [`a3fa164c`](https://github.com/wbkd/react-flow/commit/a3fa164c34cc820c79bb031c9fd97b72a3546614) Thanks [@bcakmakoglu](https://github.com/bcakmakoglu)! - autopan: only update nodes when transform change happen + ## 11.7.0 Most notable updates: - Handles: `isConnectableStart` and `isConnectableEnd` props to configure if you can start or end a connection at a certain handle - Edges: `updatable` option to enable updates for specific edges -- useNodesInitialized: options to configure if hidden nodes should be included (false by default) +- useNodesInitialized: options to configure if hidden nodes should be included (false by default) ### Minor Changes @@ -20,7 +29,6 @@ Most notable updates: - [#2933](https://github.com/wbkd/react-flow/pull/2933) [`fe8cac0a`](https://github.com/wbkd/react-flow/commit/fe8cac0adb359109e0e9eafe8b9261ba354076bb) - prefix error keys with "error" - [#2939](https://github.com/wbkd/react-flow/pull/2939) [`4a4ca171`](https://github.com/wbkd/react-flow/commit/4a4ca171955f5c8d58b23e3ad48406f1a21dc402) - add connection result to store - ## 11.6.1 ### Patch Changes diff --git a/packages/core/package.json b/packages/core/package.json index bc4e0b59..632b2cee 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@reactflow/core", - "version": "11.7.0", + "version": "11.7.1", "description": "Core components and util functions of React Flow.", "keywords": [ "react", diff --git a/packages/core/src/components/Edges/BaseEdge.tsx b/packages/core/src/components/Edges/BaseEdge.tsx index dc60493c..a9202820 100644 --- a/packages/core/src/components/Edges/BaseEdge.tsx +++ b/packages/core/src/components/Edges/BaseEdge.tsx @@ -3,6 +3,7 @@ import { isNumeric } from '../../utils'; import type { BaseEdgeProps } from '../../types'; const BaseEdge = ({ + id, path, labelX, labelY, @@ -20,6 +21,7 @@ const BaseEdge = ({ return ( <> ( const store = useStoreApi(); const nodeId = useNodeId(); const { connectOnClick, noPanClassName } = useStore(selector, shallow); - const { connecting, clickConnecting } = useStore(connectingSelector(nodeId, handleId, type)); + const { connecting, clickConnecting } = useStore(connectingSelector(nodeId, handleId, type), shallow); if (!nodeId) { store.getState().onError?.('010', errorMessages['error010']()); diff --git a/packages/core/src/components/Handle/utils.ts b/packages/core/src/components/Handle/utils.ts index b8e8cf6a..353b249a 100644 --- a/packages/core/src/components/Handle/utils.ts +++ b/packages/core/src/components/Handle/utils.ts @@ -41,18 +41,30 @@ export function getClosestHandle( connectionRadius: number, handles: ConnectionHandle[] ): ConnectionHandle | null { - let closestHandle: ConnectionHandle | null = null; + let closestHandles: ConnectionHandle[] = []; let minDistance = Infinity; handles.forEach((handle) => { const distance = Math.sqrt(Math.pow(handle.x - pos.x, 2) + Math.pow(handle.y - pos.y, 2)); - if (distance <= connectionRadius && distance < minDistance) { + if (distance <= connectionRadius) { + if (distance < minDistance) { + closestHandles = [handle]; + } else if (distance === minDistance) { + // when multiple handles are on the same distance we collect all of them + closestHandles.push(handle); + } minDistance = distance; - closestHandle = handle; } }); - return closestHandle; + if (!closestHandles.length) { + return null; + } + + return closestHandles.length === 1 + ? closestHandles[0] + : // if multiple handles are layouted on top of each other we take the one with type = target because it's more likely that the user wants to connect to this one + closestHandles.find((handle) => handle.type === 'target') || closestHandles[0]; } type Result = { @@ -81,6 +93,8 @@ export function isValidHandle( ); const { x, y } = getEventPosition(event); const handleBelow = doc.elementFromPoint(x, y); + // we always want to prioritize the handle below the mouse cursor over the closest distance handle, + // because it could be that the center of another handle is closer to the mouse pointer than the handle below the cursor const handleToCheck = handleBelow?.classList.contains('react-flow__handle') ? handleBelow : handleDomNode; const result: Result = { diff --git a/packages/core/src/hooks/useDrag/index.ts b/packages/core/src/hooks/useDrag/index.ts index 8821ab4a..346828fb 100644 --- a/packages/core/src/hooks/useDrag/index.ts +++ b/packages/core/src/hooks/useDrag/index.ts @@ -119,8 +119,9 @@ function useDrag({ lastPos.current.x = (lastPos.current.x ?? 0) - xMovement / transform[2]; lastPos.current.y = (lastPos.current.y ?? 0) - yMovement / transform[2]; - updateNodes(lastPos.current as XYPosition); - panBy({ x: xMovement, y: yMovement }); + if (panBy({ x: xMovement, y: yMovement })) { + updateNodes(lastPos.current as XYPosition); + } } autoPanId.current = requestAnimationFrame(autoPan); }; diff --git a/packages/core/src/hooks/useUpdateNodeInternals.ts b/packages/core/src/hooks/useUpdateNodeInternals.ts index 849d76b6..9786c65c 100644 --- a/packages/core/src/hooks/useUpdateNodeInternals.ts +++ b/packages/core/src/hooks/useUpdateNodeInternals.ts @@ -6,13 +6,20 @@ import type { UpdateNodeInternals } from '../types'; function useUpdateNodeInternals(): UpdateNodeInternals { const store = useStoreApi(); - return useCallback((id: string) => { + return useCallback((id: string | string[]) => { const { domNode, updateNodeDimensions } = store.getState(); - const nodeElement = domNode?.querySelector(`.react-flow__node[data-id="${id}"]`) as HTMLDivElement; - if (nodeElement) { - requestAnimationFrame(() => updateNodeDimensions([{ id, nodeElement, forceUpdate: true }])); - } + const updateIds = Array.isArray(id) ? id : [id]; + + requestAnimationFrame(() => { + updateIds.forEach((updateId) => { + const nodeElement = domNode?.querySelector(`.react-flow__node[data-id="${updateId}"]`) as HTMLDivElement; + + if (nodeElement) { + updateNodeDimensions([{ id: updateId, nodeElement, forceUpdate: true }]); + } + }); + }); }, []); } diff --git a/packages/core/src/store/index.ts b/packages/core/src/store/index.ts index f4365d45..5c152969 100644 --- a/packages/core/src/store/index.ts +++ b/packages/core/src/store/index.ts @@ -252,11 +252,11 @@ const createRFStore = () => nodeInternals: new Map(nodeInternals), }); }, - panBy: (delta: XYPosition) => { + panBy: (delta: XYPosition): boolean => { const { transform, width, height, d3Zoom, d3Selection, translateExtent } = get(); if (!d3Zoom || !d3Selection || (!delta.x && !delta.y)) { - return; + return false; } const nextTransform = zoomIdentity.translate(transform[0] + delta.x, transform[1] + delta.y).scale(transform[2]); @@ -268,6 +268,13 @@ const createRFStore = () => const constrainedTransform = d3Zoom?.constrain()(nextTransform, extent, translateExtent); d3Zoom.transform(d3Selection, constrainedTransform); + + const transformChanged = + transform[0] !== constrainedTransform.x || + transform[1] !== constrainedTransform.y || + transform[2] !== constrainedTransform.k; + + return transformChanged; }, cancelConnection: () => set({ diff --git a/packages/core/src/types/edges.ts b/packages/core/src/types/edges.ts index 7358b0e8..1899dcc5 100644 --- a/packages/core/src/types/edges.ts +++ b/packages/core/src/types/edges.ts @@ -121,6 +121,7 @@ export type EdgeProps = Pick< export type BaseEdgeProps = Pick & EdgeLabelOptions & { + id?: string; labelX?: number; labelY?: number; path: string; diff --git a/packages/core/src/types/general.ts b/packages/core/src/types/general.ts index f57a1ea7..9803d4a0 100644 --- a/packages/core/src/types/general.ts +++ b/packages/core/src/types/general.ts @@ -252,7 +252,7 @@ export type ReactFlowActions = { cancelConnection: () => void; reset: () => void; triggerNodeChanges: (changes: NodeChange[]) => void; - panBy: (delta: XYPosition) => void; + panBy: (delta: XYPosition) => boolean; }; export type ReactFlowState = ReactFlowStore & ReactFlowActions; diff --git a/packages/minimap/CHANGELOG.md b/packages/minimap/CHANGELOG.md index 3b2f9d44..3a2ade73 100644 --- a/packages/minimap/CHANGELOG.md +++ b/packages/minimap/CHANGELOG.md @@ -1,5 +1,12 @@ # @reactflow/minimap +## 11.5.1 + +### Patch Changes + +- Updated dependencies [[`cf7a7d3d`](https://github.com/wbkd/react-flow/commit/cf7a7d3dad1e73215a72a5dc72e21fd50208cdbb), [`07b975bb`](https://github.com/wbkd/react-flow/commit/07b975bbee3580249e36a19582213b250f78093c), [`c80d269b`](https://github.com/wbkd/react-flow/commit/c80d269b85a0054221f4639c328fc36a3befbe70), [`a3fa164c`](https://github.com/wbkd/react-flow/commit/a3fa164c34cc820c79bb031c9fd97b72a3546614)]: + - @reactflow/core@11.7.1 + ## 11.5.0 ### Minor Changes diff --git a/packages/minimap/package.json b/packages/minimap/package.json index e0766dab..db5861b6 100644 --- a/packages/minimap/package.json +++ b/packages/minimap/package.json @@ -1,6 +1,6 @@ { "name": "@reactflow/minimap", - "version": "11.5.0", + "version": "11.5.1", "description": "Minimap component for React Flow.", "keywords": [ "react", diff --git a/packages/node-toolbar/CHANGELOG.md b/packages/node-toolbar/CHANGELOG.md index e5fce14b..5298148d 100644 --- a/packages/node-toolbar/CHANGELOG.md +++ b/packages/node-toolbar/CHANGELOG.md @@ -1,5 +1,16 @@ # @reactflow/node-toolbar +## 1.2.0 + +### Minor Changes + +- [#3052](https://github.com/wbkd/react-flow/pull/3052) [`55e05cf7`](https://github.com/wbkd/react-flow/commit/55e05cf76ae21863691153e76dbd51d1eecd2c60) Thanks [@Noam3kCH](https://github.com/Noam3kCH)! - feat(align): add prop to align bar at start, center or end + +### Patch Changes + +- Updated dependencies [[`cf7a7d3d`](https://github.com/wbkd/react-flow/commit/cf7a7d3dad1e73215a72a5dc72e21fd50208cdbb), [`07b975bb`](https://github.com/wbkd/react-flow/commit/07b975bbee3580249e36a19582213b250f78093c), [`c80d269b`](https://github.com/wbkd/react-flow/commit/c80d269b85a0054221f4639c328fc36a3befbe70), [`a3fa164c`](https://github.com/wbkd/react-flow/commit/a3fa164c34cc820c79bb031c9fd97b72a3546614)]: + - @reactflow/core@11.7.1 + ## 1.1.11 ### Patch Changes diff --git a/packages/node-toolbar/package.json b/packages/node-toolbar/package.json index 71dad7ca..b0e2d3f7 100644 --- a/packages/node-toolbar/package.json +++ b/packages/node-toolbar/package.json @@ -1,6 +1,6 @@ { "name": "@reactflow/node-toolbar", - "version": "1.1.11", + "version": "1.2.0", "description": "A toolbar component for React Flow that can be attached to a node.", "keywords": [ "react", diff --git a/packages/node-toolbar/src/NodeToolbar.tsx b/packages/node-toolbar/src/NodeToolbar.tsx index 428708da..3b02b8bf 100644 --- a/packages/node-toolbar/src/NodeToolbar.tsx +++ b/packages/node-toolbar/src/NodeToolbar.tsx @@ -14,7 +14,7 @@ import cc from 'classcat'; import { shallow } from 'zustand/shallow'; import NodeToolbarPortal from './NodeToolbarPortal'; -import { NodeToolbarProps } from './types'; +import { Align, NodeToolbarProps } from './types'; const nodeEqualityFn = (a: Node | undefined, b: Node | undefined) => a?.positionAbsolute?.x === b?.positionAbsolute?.x && @@ -34,33 +34,46 @@ const storeSelector = (state: ReactFlowState) => ({ selectedNodesCount: state.getNodes().filter((node) => node.selected).length, }); -function getTransform(nodeRect: Rect, transform: Transform, position: Position, offset: number): string { +function getTransform(nodeRect: Rect, transform: Transform, position: Position, offset: number, align: Align): string { + let alignmentOffset = 0.5; + + if (align === 'start') { + alignmentOffset = 0; + } else if (align === 'end') { + alignmentOffset = 1; + } + // 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; + // we set the x any y position of the toolbar based on the nodes position + let pos = [ + (nodeRect.x + nodeRect.width * alignmentOffset) * transform[2] + transform[0], + nodeRect.y * transform[2] + transform[1] - offset, + ]; + // and than shift it based on the alignment. The shift values are in %. + let shift = [-100 * alignmentOffset, -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; + pos = [ + (nodeRect.x + nodeRect.width) * transform[2] + transform[0] + offset, + (nodeRect.y + nodeRect.height * alignmentOffset) * transform[2] + transform[1], + ]; + shift = [0, -100 * alignmentOffset]; break; case Position.Bottom: - yPos = (nodeRect.y + nodeRect.height) * transform[2] + transform[1] + offset; - yShift = 0; + pos[1] = (nodeRect.y + nodeRect.height) * transform[2] + transform[1] + offset; + shift[1] = 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; + pos = [ + nodeRect.x * transform[2] + transform[0] - offset, + (nodeRect.y + nodeRect.height * alignmentOffset) * transform[2] + transform[1], + ]; + shift = [-100, -100 * alignmentOffset]; break; } - return `translate(${xPos}px, ${yPos}px) translate(${xShift}%, ${yShift}%)`; + return `translate(${pos[0]}px, ${pos[1]}px) translate(${shift[0]}%, ${shift[1]}%)`; } function NodeToolbar({ @@ -71,6 +84,7 @@ function NodeToolbar({ isVisible, position = Position.Top, offset = 10, + align = 'center', ...rest }: NodeToolbarProps) { const contextNodeId = useNodeId(); @@ -103,7 +117,7 @@ function NodeToolbar({ const wrapperStyle: CSSProperties = { position: 'absolute', - transform: getTransform(nodeRect, transform, position, offset), + transform: getTransform(nodeRect, transform, position, offset, align), zIndex, ...style, }; diff --git a/packages/node-toolbar/src/types.ts b/packages/node-toolbar/src/types.ts index e2b0d73c..7ff2087b 100644 --- a/packages/node-toolbar/src/types.ts +++ b/packages/node-toolbar/src/types.ts @@ -6,4 +6,7 @@ export type NodeToolbarProps = HTMLAttributes & { isVisible?: boolean; position?: Position; offset?: number; + align?: Align; }; + +export type Align = 'center' | 'start' | 'end'; diff --git a/packages/reactflow/CHANGELOG.md b/packages/reactflow/CHANGELOG.md index f5eebcf3..aa8a801b 100644 --- a/packages/reactflow/CHANGELOG.md +++ b/packages/reactflow/CHANGELOG.md @@ -1,5 +1,22 @@ # reactflow +## 11.7.1 + +### Patch Changes + +- [#3043](https://github.com/wbkd/react-flow/pull/3043) [`cf7a7d3d`](https://github.com/wbkd/react-flow/commit/cf7a7d3dad1e73215a72a5dc72e21fd50208cdbb) - handles: handles on top of each other, reduce re-renderings +- [#3046](https://github.com/wbkd/react-flow/pull/3046) [`07b975bb`](https://github.com/wbkd/react-flow/commit/07b975bbee3580249e36a19582213b250f78093c) - base-edge: pass id to base edge path +- [#3007](https://github.com/wbkd/react-flow/pull/3007) [`c80d269b`](https://github.com/wbkd/react-flow/commit/c80d269b85a0054221f4639c328fc36a3befbe70) Thanks [@bcakmakoglu](https://github.com/bcakmakoglu)! - allow array of ids as updateNodeInternals arg +- [#3029](https://github.com/wbkd/react-flow/pull/3029) [`a3fa164c`](https://github.com/wbkd/react-flow/commit/a3fa164c34cc820c79bb031c9fd97b72a3546614) Thanks [@bcakmakoglu](https://github.com/bcakmakoglu)! - autopan: only update nodes when transform change happen +- [#3052](https://github.com/wbkd/react-flow/pull/3052) [`55e05cf7`](https://github.com/wbkd/react-flow/commit/55e05cf76ae21863691153e76dbd51d1eecd2c60) Thanks [@Noam3kCH](https://github.com/Noam3kCH)! - node-toolbar: add prop to align bar at start, center or end + +- Updated dependencies [[`cf7a7d3d`](https://github.com/wbkd/react-flow/commit/cf7a7d3dad1e73215a72a5dc72e21fd50208cdbb), [`07b975bb`](https://github.com/wbkd/react-flow/commit/07b975bbee3580249e36a19582213b250f78093c), [`55e05cf7`](https://github.com/wbkd/react-flow/commit/55e05cf76ae21863691153e76dbd51d1eecd2c60), [`c80d269b`](https://github.com/wbkd/react-flow/commit/c80d269b85a0054221f4639c328fc36a3befbe70), [`46526b4e`](https://github.com/wbkd/react-flow/commit/46526b4e02b83d74726701e3ba73d0be8cf80787), [`a3fa164c`](https://github.com/wbkd/react-flow/commit/a3fa164c34cc820c79bb031c9fd97b72a3546614)]: + - @reactflow/core@11.7.1 + - @reactflow/node-toolbar@1.2.0 + - @reactflow/controls@11.1.12 + - @reactflow/background@11.2.1 + - @reactflow/minimap@11.5.1 + ## 11.7.0 Most notable updates: @@ -9,7 +26,7 @@ Most notable updates: - Edges: `updatable` option to enable updates for specific edges - MiniMap: `inversePan` and `zoomStep` props - Background: `id` and `offset` props - this enables you to combine different patterns (useful if you want a graph paper like background for example) -- useNodesInitialized: options to configure if hidden nodes should be included (false by default) +- useNodesInitialized: options to configure if hidden nodes should be included (false by default) Big thanks to [@Elringus](https://github.com/Elringus) and [@bcakmakoglu](https://github.com/bcakmakoglu)! @@ -22,14 +39,12 @@ Big thanks to [@Elringus](https://github.com/Elringus) and [@bcakmakoglu](https: - [#2944](https://github.com/wbkd/react-flow/pull/2944) Thanks [@Elringus](https://github.com/Elringus)! - add `inversePan` and `zoomStep` props - [#2941](https://github.com/wbkd/react-flow/pull/2941) Thanks [@Elringus](https://github.com/Elringus)! - background: add `id` and `offset` props - ### Patch Changes - [#2926](https://github.com/wbkd/react-flow/pull/2926) Thanks [@Elringus](https://github.com/Elringus)! - fix non-passive wheel event listener violation - [#2933](https://github.com/wbkd/react-flow/pull/2933) [`fe8cac0a`](https://github.com/wbkd/react-flow/commit/fe8cac0adb359109e0e9eafe8b9261ba354076bb) - prefix error keys with "error" - [#2939](https://github.com/wbkd/react-flow/pull/2939) [`4a4ca171`](https://github.com/wbkd/react-flow/commit/4a4ca171955f5c8d58b23e3ad48406f1a21dc402) - add connection result to store - ### Patch Changes - Updated dependencies [[`098eee3d`](https://github.com/wbkd/react-flow/commit/098eee3d41dabc870777b081796401ff13b5a776), [`fe8cac0a`](https://github.com/wbkd/react-flow/commit/fe8cac0adb359109e0e9eafe8b9261ba354076bb), [`4a4ca171`](https://github.com/wbkd/react-flow/commit/4a4ca171955f5c8d58b23e3ad48406f1a21dc402), [`c1448c2f`](https://github.com/wbkd/react-flow/commit/c1448c2f7415dd3b4b2c54e05404c5ab24e8978d), [`923a54c4`](https://github.com/wbkd/react-flow/commit/923a54c481b90954806202817ba844cfa7203a38), [`4d97a0ed`](https://github.com/wbkd/react-flow/commit/4d97a0ed168ce643fc0c99fa6b47cf1296d66065), [`771c7a5d`](https://github.com/wbkd/react-flow/commit/771c7a5d133ce96e9f7471394c15189e0657ce01), [`c22e1c28`](https://github.com/wbkd/react-flow/commit/c22e1c28c5555a638c2a8e82c3bfc986b3965d36)]: diff --git a/packages/reactflow/package.json b/packages/reactflow/package.json index ad4b8ed7..1cbab90d 100644 --- a/packages/reactflow/package.json +++ b/packages/reactflow/package.json @@ -1,6 +1,6 @@ { "name": "reactflow", - "version": "11.7.0", + "version": "11.7.1", "description": "A highly customizable React library for building node-based editors and interactive flow charts", "keywords": [ "react",