Merge pull request #2935 from wbkd/next-release

Next release
This commit is contained in:
Moritz Klack
2023-03-28 13:36:42 +02:00
committed by GitHub
60 changed files with 603 additions and 202 deletions
@@ -26,7 +26,7 @@ describe('useNodesInitialized.cy.tsx', () => {
</ReactFlow> </ReactFlow>
); );
cy.get('@initSpy').should('to.be.calledOnce'); // cy.get('@initSpy').should('to.be.calledOnce');
cy.get('@initSpy').should('have.be.calledWith', false); cy.get('@initSpy').should('have.be.calledWith', false);
}); });
+2 -1
View File
@@ -21,7 +21,8 @@
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-router-dom": "^6.3.0", "react-router-dom": "^6.3.0",
"reactflow": "workspace:*" "reactflow": "workspace:*",
"zustand": "^4.3.1"
}, },
"devDependencies": { "devDependencies": {
"@cypress/skip-test": "^2.6.1", "@cypress/skip-test": "^2.6.1",
+6
View File
@@ -45,6 +45,7 @@ import CancelConnection from '../examples/CancelConnection';
import InteractiveMinimap from '../examples/InteractiveMinimap'; import InteractiveMinimap from '../examples/InteractiveMinimap';
import UseOnSelectionChange from '../examples/UseOnSelectionChange'; import UseOnSelectionChange from '../examples/UseOnSelectionChange';
import NodeToolbar from '../examples/NodeToolbar'; import NodeToolbar from '../examples/NodeToolbar';
import useNodesInitialized from '../examples/UseNodesInit';
interface IRoute { interface IRoute {
name: string; name: string;
@@ -248,6 +249,11 @@ const routes: IRoute[] = [
path: '/update-node', path: '/update-node',
component: UpdateNode, component: UpdateNode,
}, },
{
name: 'useNodesInitialized',
path: '/use-nodes-initialized',
component: useNodesInitialized,
},
{ {
name: 'useOnSelectionChange', name: 'useOnSelectionChange',
path: '/use-on-selection-change', path: '/use-on-selection-change',
@@ -19,13 +19,15 @@ const initialNodes: Node[] = [
}, },
]; ];
const Flow: FC<{ id: string; bgProps: BackgroundProps }> = ({ id, bgProps }) => { const Flow: FC<{ id: string; bgProps: BackgroundProps[] }> = ({ id, bgProps }) => {
const [nodes, , onNodesChange] = useNodesState(initialNodes); const [nodes, , onNodesChange] = useNodesState(initialNodes);
return ( return (
<ReactFlowProvider> <ReactFlowProvider>
<ReactFlow nodes={nodes} onNodesChange={onNodesChange} id={id}> <ReactFlow nodes={nodes} onNodesChange={onNodesChange} id={id}>
<Background {...bgProps} /> {bgProps.map((props, idx) => (
<Background key={idx} id={idx.toString()} {...props} />
))}
</ReactFlow> </ReactFlow>
</ReactFlowProvider> </ReactFlowProvider>
); );
@@ -33,9 +35,16 @@ const Flow: FC<{ id: string; bgProps: BackgroundProps }> = ({ id, bgProps }) =>
const Backgrounds: FC = () => ( const Backgrounds: FC = () => (
<div className={styles.wrapper}> <div className={styles.wrapper}>
<Flow id="flow-a" bgProps={{ variant: BackgroundVariant.Dots }} /> <Flow id="flow-a" bgProps={[{ variant: BackgroundVariant.Dots }]} />
<Flow id="flow-b" bgProps={{ variant: BackgroundVariant.Lines, gap: [50, 50] }} /> <Flow id="flow-b" bgProps={[{ variant: BackgroundVariant.Lines, gap: [50, 50] }]} />
<Flow id="flow-c" bgProps={{ variant: BackgroundVariant.Cross, gap: [100, 50] }} /> <Flow id="flow-c" bgProps={[{ variant: BackgroundVariant.Cross, gap: [100, 50] }]} />
<Flow
id="flow-d"
bgProps={[
{ variant: BackgroundVariant.Lines, gap: 10 },
{ variant: BackgroundVariant.Lines, gap: 100, offset: 2, color: '#ccc' },
]}
/>
</div> </div>
); );
@@ -1,4 +1,4 @@
import { MouseEvent, useCallback } from 'react'; import { MouseEvent, useCallback, useState } from 'react';
import ReactFlow, { import ReactFlow, {
MiniMap, MiniMap,
Background, Background,
@@ -87,6 +87,7 @@ const defaultEdgeOptions = { zIndex: 0 };
const BasicFlow = () => { const BasicFlow = () => {
const instance = useReactFlow(); const instance = useReactFlow();
const [inverse, setInverse] = useState(false);
const updatePos = () => { const updatePos = () => {
instance.setNodes((nodes) => instance.setNodes((nodes) =>
@@ -103,6 +104,7 @@ const BasicFlow = () => {
const logToObject = () => console.log(instance.toObject()); const logToObject = () => console.log(instance.toObject());
const resetTransform = () => instance.setViewport({ x: 0, y: 0, zoom: 1 }); const resetTransform = () => instance.setViewport({ x: 0, y: 0, zoom: 1 });
const toggleInverse = () => setInverse(!inverse);
const toggleClassnames = () => { const toggleClassnames = () => {
instance.setNodes((nodes) => instance.setNodes((nodes) =>
@@ -137,7 +139,8 @@ const BasicFlow = () => {
fitView fitView
> >
<Background variant={BackgroundVariant.Dots} /> <Background variant={BackgroundVariant.Dots} />
<MiniMap onClick={onMiniMapClick} onNodeClick={onMiniMapNodeClick} pannable zoomable /> <MiniMap onClick={onMiniMapClick} onNodeClick={onMiniMapNodeClick} pannable zoomable
inversePan={inverse}/>
<Controls /> <Controls />
<div style={{ position: 'absolute', right: 10, top: 10, zIndex: 4 }}> <div style={{ position: 'absolute', right: 10, top: 10, zIndex: 4 }}>
@@ -150,7 +153,12 @@ const BasicFlow = () => {
<button onClick={toggleClassnames} style={{ marginRight: 5 }}> <button onClick={toggleClassnames} style={{ marginRight: 5 }}>
toggle classnames toggle classnames
</button> </button>
<button onClick={logToObject}>toObject</button> <button onClick={logToObject} style={{ marginRight: 5 }}>
toObject
</button>
<button onClick={toggleInverse} style={{ marginRight: 5 }}>
{inverse ? 'un-inverse pan' : 'inverse pan'}
</button>
</div> </div>
</ReactFlow> </ReactFlow>
); );
@@ -1,8 +1,6 @@
import { memo, FC } from 'react'; import { memo, FC } from 'react';
import { Handle, Position, NodeProps } from 'reactflow'; import { Handle, Position, NodeProps, NodeResizeControl } from 'reactflow';
import { NodeResizeControl } from '@reactflow/node-resizer';
import '@reactflow/node-resizer/dist/style.css';
import ResizeIcon from './ResizeIcon'; import ResizeIcon from './ResizeIcon';
const controlStyle = { const controlStyle = {
@@ -1,8 +1,5 @@
import { memo, FC } from 'react'; import { memo, FC } from 'react';
import { Handle, Position, NodeProps } from 'reactflow'; import { Handle, Position, NodeProps, NodeResizer } from 'reactflow';
import { NodeResizer } from '@reactflow/node-resizer';
import '@reactflow/node-resizer/dist/style.css';
const DefaultResizerNode: FC<NodeProps> = ({ data, selected }) => { const DefaultResizerNode: FC<NodeProps> = ({ data, selected }) => {
return ( return (
@@ -1,8 +1,5 @@
import { memo, FC } from 'react'; import { memo, FC } from 'react';
import { Handle, Position, NodeProps } from 'reactflow'; import { Handle, Position, NodeProps, NodeResizeControl } from 'reactflow';
import { NodeResizeControl } from '@reactflow/node-resizer';
import '@reactflow/node-resizer/dist/style.css';
const HorizontalResizerNode: FC<NodeProps> = ({ data }) => { const HorizontalResizerNode: FC<NodeProps> = ({ data }) => {
return ( return (
@@ -1,8 +1,5 @@
import { memo, FC } from 'react'; import { memo, FC } from 'react';
import { Handle, Position, NodeProps } from 'reactflow'; import { Handle, Position, NodeProps, NodeResizeControl } from 'reactflow';
import { NodeResizeControl } from '@reactflow/node-resizer';
import '@reactflow/node-resizer/dist/style.css';
const CustomNode: FC<NodeProps> = ({ id, data }) => { const CustomNode: FC<NodeProps> = ({ id, data }) => {
return ( return (
@@ -6,6 +6,8 @@ import CustomResizer from './CustomResizer';
import VerticalResizer from './VerticalResizer'; import VerticalResizer from './VerticalResizer';
import HorizontalResizer from './HorizontalResizer'; import HorizontalResizer from './HorizontalResizer';
import 'reactflow/dist/style.css';
const nodeTypes = { const nodeTypes = {
defaultResizer: DefaultResizer, defaultResizer: DefaultResizer,
customResizer: CustomResizer, customResizer: CustomResizer,
@@ -36,7 +36,7 @@ const initialNodes: Node[] = [
</> </>
), ),
}, },
position: { x: 100, y: 100 }, position: { x: 75, y: 0 },
}, },
{ {
id: '3', id: '3',
@@ -55,9 +55,46 @@ const initialNodes: Node[] = [
width: 180, width: 180,
}, },
}, },
{
id: '4',
data: {
label: (
<>
Node <strong>D</strong>
</>
),
},
position: { x: -75, y: 100 },
},
{
id: '5',
data: {
label: (
<>
Node <strong>E</strong>
</>
),
},
position: { x: 150, y: 100 },
},
{
id: '6',
data: {
label: (
<>
Node <strong>F</strong>
</>
),
},
position: { x: 150, y: 250 },
},
]; ];
const initialEdges = [{ id: 'e1-2', source: '1', target: '2', label: 'This is a draggable edge' }]; const initialEdges: Edge[] = [
{ id: 'e1-3', source: '1', target: '3', label: 'This edge can only be updated from source', updatable: 'source' },
{ id: 'e2-4', source: '2', target: '4', label: 'This edge can only be updated from target', updatable: 'target' },
{ id: 'e5-6', source: '5', target: '6', label: 'This edge can be updated from both sides' },
];
const onInit = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView(); const onInit = (reactFlowInstance: ReactFlowInstance) => reactFlowInstance.fitView();
const onEdgeUpdateStart = (_: ReactMouseEvent, edge: Edge, handleType: HandleType) => const onEdgeUpdateStart = (_: ReactMouseEvent, edge: Edge, handleType: HandleType) =>
@@ -0,0 +1,83 @@
import { useCallback, useEffect } from 'react';
import ReactFlow, {
Background,
MiniMap,
Node,
addEdge,
ReactFlowProvider,
Edge,
useNodesState,
useEdgesState,
OnConnect,
useNodesInitialized,
} from 'reactflow';
const initialNodes: Node[] = [
{
id: '1',
type: 'input',
data: { label: 'Node 1' },
position: { x: 250, y: 5 },
className: 'light',
},
{
id: '2',
data: { label: 'Node 2' },
position: { x: 100, y: 100 },
className: 'light',
},
{
id: '3',
data: { label: 'Node 3' },
position: { x: 400, y: 100 },
className: 'light',
},
{
id: '4',
data: { label: 'Node 4' },
position: { x: 400, y: 200 },
className: 'light',
hidden: true,
},
];
const initialEdges: Edge[] = [
{ id: 'e1-2', source: '1', target: '2', animated: true },
{ id: 'e1-3', source: '1', target: '3' },
// { id: 'e3-4', source: '3', target: '4' }
];
const UseZoomPanHelperFlow = () => {
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onConnect: OnConnect = useCallback((params) => setEdges((eds) => addEdge(params, eds)), []);
const initialized = useNodesInitialized();
useEffect(() => {
console.log('initialized', initialized);
}, [initialized]);
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
onConnect={onConnect}
fitView
maxZoom={Infinity}
>
<Background />
<MiniMap />
</ReactFlow>
);
};
const WrappedFlow = () => (
<ReactFlowProvider>
<UseZoomPanHelperFlow />
</ReactFlowProvider>
);
export default WrappedFlow;
@@ -0,0 +1,50 @@
import { ReactFlowState, useStore } from 'reactflow';
import { shallow } from 'zustand/shallow';
import styles from './validation.module.css';
const selector = (state: ReactFlowState) => ({
connectionPosition: state.connectionPosition,
connectionStatus: state.connectionStatus,
connectionStartNodeId: state.connectionStartHandle?.nodeId,
connectionStartHandleType: state.connectionStartHandle?.type,
connectionEndNodeId: state.connectionEndHandle?.nodeId,
connectionEndHandleType: state.connectionEndHandle?.type,
});
function ConnectionStatus() {
const {
connectionPosition,
connectionStatus,
connectionStartNodeId,
connectionStartHandleType,
connectionEndNodeId,
connectionEndHandleType,
} = useStore(selector, shallow);
if (!connectionPosition) {
return null;
}
return (
<div className={styles.connectionstatus}>
{connectionStartNodeId ? (
<>
<div>
<strong>connection info</strong>
</div>
<div>position: {JSON.stringify(connectionPosition)}</div>
<div>status: {connectionStatus}</div>
<div>from node id: {connectionStartNodeId}</div>
<div>from handle type: {connectionStartHandleType}</div>
<div>to node id: {connectionEndNodeId}</div>
<div>to handle type: {connectionEndHandleType}</div>
</>
) : (
'no connection data'
)}
</div>
);
}
export default ConnectionStatus;
@@ -16,6 +16,8 @@ import ReactFlow, {
Edge, Edge,
} from 'reactflow'; } from 'reactflow';
import ConnectionStatus from './ConnectionStatus';
import styles from './validation.module.css'; import styles from './validation.module.css';
const initialNodes: Node[] = [ const initialNodes: Node[] = [
@@ -36,7 +38,7 @@ const CustomInput: FC<NodeProps> = () => (
const CustomNode: FC<NodeProps> = ({ id }) => ( const CustomNode: FC<NodeProps> = ({ id }) => (
<> <>
<Handle type="target" position={Position.Left} /> <Handle type="target" position={Position.Left} isConnectableStart={false} />
<div>{id}</div> <div>{id}</div>
<Handle type="source" position={Position.Right} /> <Handle type="source" position={Position.Right} />
</> </>
@@ -96,7 +98,9 @@ const ValidationFlow = () => {
onEdgeUpdate={onEdgeUpdate} onEdgeUpdate={onEdgeUpdate}
isValidConnection={isValidConnection} isValidConnection={isValidConnection}
fitView fitView
/> >
<ConnectionStatus />
</ReactFlow>
); );
}; };
@@ -39,3 +39,10 @@
.validationflow :global .invalid .react-flow__connection-path { .validationflow :global .invalid .react-flow__connection-path {
stroke: #ff6060; stroke: #ff6060;
} }
.connectionstatus {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
}
+11
View File
@@ -1,5 +1,16 @@
# @reactflow/background # @reactflow/background
## 11.2.0
### Minor Changes
- [#2941](https://github.com/wbkd/react-flow/pull/2941) Thanks [@Elringus](https://github.com/Elringus)! - add `id` and `offset` props
### 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), [`923a54c4`](https://github.com/wbkd/react-flow/commit/923a54c481b90954806202817ba844cfa7203a38), [`4d97a0ed`](https://github.com/wbkd/react-flow/commit/4d97a0ed168ce643fc0c99fa6b47cf1296d66065), [`c22e1c28`](https://github.com/wbkd/react-flow/commit/c22e1c28c5555a638c2a8e82c3bfc986b3965d36)]:
- @reactflow/core@11.7.0
## 11.1.10 ## 11.1.10
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@reactflow/background", "name": "@reactflow/background",
"version": "11.1.10", "version": "11.2.0",
"description": "Background component with different variants for React Flow", "description": "Background component with different variants for React Flow",
"keywords": [ "keywords": [
"react", "react",
+9 -7
View File
@@ -21,12 +21,14 @@ const defaultSize = {
const selector = (s: ReactFlowState) => ({ transform: s.transform, patternId: `pattern-${s.rfId}` }); const selector = (s: ReactFlowState) => ({ transform: s.transform, patternId: `pattern-${s.rfId}` });
function Background({ function Background({
id,
variant = BackgroundVariant.Dots, variant = BackgroundVariant.Dots,
gap = 20,
// only used for dots and cross // only used for dots and cross
size, gap = 20,
// only used for lines and cross // only used for lines and cross
size,
lineWidth = 1, lineWidth = 1,
offset = 2,
color, color,
style, style,
className, className,
@@ -44,8 +46,8 @@ function Background({
const patternDimensions: [number, number] = isCross ? [scaledSize, scaledSize] : scaledGap; const patternDimensions: [number, number] = isCross ? [scaledSize, scaledSize] : scaledGap;
const patternOffset = isDots const patternOffset = isDots
? [scaledSize / 2, scaledSize / 2] ? [scaledSize / offset, scaledSize / offset]
: [patternDimensions[0] / 2, patternDimensions[1] / 2]; : [patternDimensions[0] / offset, patternDimensions[1] / offset];
return ( return (
<svg <svg
@@ -62,7 +64,7 @@ function Background({
data-testid="rf__background" data-testid="rf__background"
> >
<pattern <pattern
id={patternId} id={patternId+id}
x={transform[0] % scaledGap[0]} x={transform[0] % scaledGap[0]}
y={transform[1] % scaledGap[1]} y={transform[1] % scaledGap[1]}
width={scaledGap[0]} width={scaledGap[0]}
@@ -71,12 +73,12 @@ function Background({
patternTransform={`translate(-${patternOffset[0]},-${patternOffset[1]})`} patternTransform={`translate(-${patternOffset[0]},-${patternOffset[1]})`}
> >
{isDots ? ( {isDots ? (
<DotPattern color={patternColor} radius={scaledSize / 2} /> <DotPattern color={patternColor} radius={scaledSize / offset} />
) : ( ) : (
<LinePattern dimensions={patternDimensions} color={patternColor} lineWidth={lineWidth} /> <LinePattern dimensions={patternDimensions} color={patternColor} lineWidth={lineWidth} />
)} )}
</pattern> </pattern>
<rect x="0" y="0" width="100%" height="100%" fill={`url(#${patternId})`} /> <rect x="0" y="0" width="100%" height="100%" fill={`url(#${patternId+id})`} />
</svg> </svg>
); );
} }
+2
View File
@@ -7,10 +7,12 @@ export enum BackgroundVariant {
} }
export type BackgroundProps = { export type BackgroundProps = {
id?: string
color?: string; color?: string;
className?: string; className?: string;
gap?: number | [number, number]; gap?: number | [number, number];
size?: number; size?: number;
offset?: number;
lineWidth?: number; lineWidth?: number;
variant?: BackgroundVariant; variant?: BackgroundVariant;
style?: CSSProperties; style?: CSSProperties;
+7
View File
@@ -1,5 +1,12 @@
# @reactflow/controls # @reactflow/controls
## 11.1.11
### 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), [`923a54c4`](https://github.com/wbkd/react-flow/commit/923a54c481b90954806202817ba844cfa7203a38), [`4d97a0ed`](https://github.com/wbkd/react-flow/commit/4d97a0ed168ce643fc0c99fa6b47cf1296d66065), [`c22e1c28`](https://github.com/wbkd/react-flow/commit/c22e1c28c5555a638c2a8e82c3bfc986b3965d36)]:
- @reactflow/core@11.7.0
## 11.1.10 ## 11.1.10
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@reactflow/controls", "name": "@reactflow/controls",
"version": "11.1.10", "version": "11.1.11",
"description": "Component to control the viewport of a React Flow instance", "description": "Component to control the viewport of a React Flow instance",
"keywords": [ "keywords": [
"react", "react",
+21
View File
@@ -1,5 +1,26 @@
# @reactflow/core # @reactflow/core
## 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)
### Minor Changes
- [#2960](https://github.com/wbkd/react-flow/pull/2960) Thanks [@bcakmakoglu](https://github.com/bcakmakoglu)! - edges: add `updatable` option
- [#2958](https://github.com/wbkd/react-flow/pull/2958) [`4d97a0ed`](https://github.com/wbkd/react-flow/commit/4d97a0ed168ce643fc0c99fa6b47cf1296d66065) - handles: add `isConnectableStart` and `isConnectableEnd` props
- [#2956](https://github.com/wbkd/react-flow/pull/2956) [`923a54c4`](https://github.com/wbkd/react-flow/commit/923a54c481b90954806202817ba844cfa7203a38) - add options for `useNodesInitialized`, ignore hidden nodes by default
### 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
## 11.6.1 ## 11.6.1
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@reactflow/core", "name": "@reactflow/core",
"version": "11.6.1", "version": "11.7.0",
"description": "Core components and util functions of React Flow.", "description": "Core components and util functions of React Flow.",
"keywords": [ "keywords": [
"react", "react",
+26 -22
View File
@@ -55,6 +55,7 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
rfId, rfId,
ariaLabel, ariaLabel,
isFocusable, isFocusable,
isUpdatable,
pathOptions, pathOptions,
interactionWidth, interactionWidth,
}: WrapEdgeProps): JSX.Element | null => { }: WrapEdgeProps): JSX.Element | null => {
@@ -138,7 +139,6 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
const onEdgeUpdaterMouseOut = () => setUpdateHover(false); const onEdgeUpdaterMouseOut = () => setUpdateHover(false);
const inactive = !elementsSelectable && !onClick; const inactive = !elementsSelectable && !onClick;
const handleEdgeUpdate = typeof onEdgeUpdate !== 'undefined';
const onKeyDown = (event: KeyboardEvent) => { const onKeyDown = (event: KeyboardEvent) => {
if (elementSelectionKeys.includes(event.key) && elementsSelectable) { if (elementSelectionKeys.includes(event.key) && elementsSelectable) {
@@ -205,28 +205,32 @@ export default (EdgeComponent: ComponentType<EdgeProps>) => {
interactionWidth={interactionWidth} interactionWidth={interactionWidth}
/> />
)} )}
{handleEdgeUpdate && ( {isUpdatable && (
<> <>
<EdgeAnchor {(isUpdatable === 'source' || isUpdatable === true) && (
position={sourcePosition} <EdgeAnchor
centerX={sourceX} position={sourcePosition}
centerY={sourceY} centerX={sourceX}
radius={edgeUpdaterRadius} centerY={sourceY}
onMouseDown={onEdgeUpdaterSourceMouseDown} radius={edgeUpdaterRadius}
onMouseEnter={onEdgeUpdaterMouseEnter} onMouseDown={onEdgeUpdaterSourceMouseDown}
onMouseOut={onEdgeUpdaterMouseOut} onMouseEnter={onEdgeUpdaterMouseEnter}
type="source" onMouseOut={onEdgeUpdaterMouseOut}
/> type="source"
<EdgeAnchor />
position={targetPosition} )}
centerX={targetX} {(isUpdatable === 'target' || isUpdatable === true) && (
centerY={targetY} <EdgeAnchor
radius={edgeUpdaterRadius} position={targetPosition}
onMouseDown={onEdgeUpdaterTargetMouseDown} centerX={targetX}
onMouseEnter={onEdgeUpdaterMouseEnter} centerY={targetY}
onMouseOut={onEdgeUpdaterMouseOut} radius={edgeUpdaterRadius}
type="target" onMouseDown={onEdgeUpdaterTargetMouseDown}
/> onMouseEnter={onEdgeUpdaterMouseEnter}
onMouseOut={onEdgeUpdaterMouseOut}
type="target"
/>
)}
</> </>
)} )}
</g> </g>
@@ -89,10 +89,17 @@ export function handlePointerDown({
setState({ setState({
connectionPosition, connectionPosition,
connectionStatus: null,
// connectionNodeId etc will be removed in the next major in favor of connectionStartHandle
connectionNodeId: nodeId, connectionNodeId: nodeId,
connectionHandleId: handleId, connectionHandleId: handleId,
connectionHandleType: handleType, connectionHandleType: handleType,
connectionStatus: null, connectionStartHandle: {
nodeId,
handleId,
type: handleType,
},
connectionEndHandle: null,
}); });
onConnectStart?.(event, { nodeId, handleId, handleType }); onConnectStart?.(event, { nodeId, handleId, handleType });
@@ -139,6 +146,7 @@ export function handlePointerDown({
) )
: connectionPosition, : connectionPosition,
connectionStatus: getConnectionStatus(!!prevClosestHandle, isValid), connectionStatus: getConnectionStatus(!!prevClosestHandle, isValid),
connectionEndHandle: result.endHandle,
}); });
if (!prevClosestHandle && !isValid && !handleDomNode) { if (!prevClosestHandle && !isValid && !handleDomNode) {
+51 -24
View File
@@ -7,8 +7,7 @@ import { useNodeId } from '../../contexts/NodeIdContext';
import { handlePointerDown } from './handler'; import { handlePointerDown } from './handler';
import { getHostForElement, isMouseEvent } from '../../utils'; import { getHostForElement, isMouseEvent } from '../../utils';
import { addEdge } from '../../utils/graph'; import { addEdge } from '../../utils/graph';
import { Position } from '../../types'; import { type HandleProps, type Connection, type ReactFlowState, HandleType, Position } from '../../types';
import type { HandleProps, Connection, ReactFlowState } from '../../types';
import { isValidHandle } from './utils'; import { isValidHandle } from './utils';
import { errorMessages } from '../../contants'; import { errorMessages } from '../../contants';
@@ -22,6 +21,23 @@ const selector = (s: ReactFlowState) => ({
noPanClassName: s.noPanClassName, noPanClassName: s.noPanClassName,
}); });
const connectingSelector =
(nodeId: string | null, handleId: string | null, type: HandleType) => (state: ReactFlowState) => {
const {
connectionStartHandle: startHandle,
connectionEndHandle: endHandle,
connectionClickStartHandle: clickHandle,
} = state;
return {
connecting:
(startHandle?.nodeId === nodeId && startHandle?.handleId === handleId && startHandle?.type === type) ||
(endHandle?.nodeId === nodeId && endHandle?.handleId === handleId && endHandle?.type === type),
clickConnecting:
clickHandle?.nodeId === nodeId && clickHandle?.handleId === handleId && clickHandle?.type === type,
};
};
const Handle = forwardRef<HTMLDivElement, HandleComponentProps>( const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
( (
{ {
@@ -29,6 +45,8 @@ const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
position = Position.Top, position = Position.Top,
isValidConnection, isValidConnection,
isConnectable = true, isConnectable = true,
isConnectableStart = true,
isConnectableEnd = true,
id, id,
onConnect, onConnect,
children, children,
@@ -39,19 +57,16 @@ const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
}, },
ref ref
) => { ) => {
const store = useStoreApi();
const nodeId = useNodeId();
if (!nodeId) {
store.getState().onError?.('010', errorMessages['010']());
return null;
}
const { connectionStartHandle, connectOnClick, noPanClassName } = useStore(selector, shallow);
const handleId = id || null; const handleId = id || null;
const isTarget = type === 'target'; const isTarget = type === 'target';
const store = useStoreApi();
const nodeId = useNodeId();
const { connectOnClick, noPanClassName } = useStore(selector, shallow);
const { connecting, clickConnecting } = useStore(connectingSelector(nodeId, handleId, type));
if (!nodeId) {
store.getState().onError?.('010', errorMessages['error010']());
}
const onConnectExtended = (params: Connection) => { const onConnectExtended = (params: Connection) => {
const { defaultEdgeOptions, onConnect: onConnectAction, hasDefaultEdges } = store.getState(); const { defaultEdgeOptions, onConnect: onConnectAction, hasDefaultEdges } = store.getState();
@@ -70,9 +85,13 @@ const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
}; };
const onPointerDown = (event: ReactMouseEvent<HTMLDivElement> | ReactTouchEvent<HTMLDivElement>) => { const onPointerDown = (event: ReactMouseEvent<HTMLDivElement> | ReactTouchEvent<HTMLDivElement>) => {
if (!nodeId) {
return;
}
const isMouseTriggered = isMouseEvent(event); const isMouseTriggered = isMouseEvent(event);
if ((isMouseTriggered && event.button === 0) || !isMouseTriggered) { if (isConnectableStart && ((isMouseTriggered && event.button === 0) || !isMouseTriggered)) {
handlePointerDown({ handlePointerDown({
event, event,
handleId, handleId,
@@ -96,12 +115,18 @@ const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
const { const {
onClickConnectStart, onClickConnectStart,
onClickConnectEnd, onClickConnectEnd,
connectionClickStartHandle,
connectionMode, connectionMode,
isValidConnection: isValidConnectionStore, isValidConnection: isValidConnectionStore,
} = store.getState(); } = store.getState();
if (!connectionStartHandle) {
if (!nodeId || (!connectionClickStartHandle && !isConnectableStart)) {
return;
}
if (!connectionClickStartHandle) {
onClickConnectStart?.(event, { nodeId, handleId, handleType: type }); onClickConnectStart?.(event, { nodeId, handleId, handleType: type });
store.setState({ connectionStartHandle: { nodeId, type, handleId } }); store.setState({ connectionClickStartHandle: { nodeId, type, handleId } });
return; return;
} }
@@ -115,9 +140,9 @@ const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
type, type,
}, },
connectionMode, connectionMode,
connectionStartHandle.nodeId, connectionClickStartHandle.nodeId,
connectionStartHandle.handleId || null, connectionClickStartHandle.handleId || null,
connectionStartHandle.type, connectionClickStartHandle.type,
isValidConnectionHandler, isValidConnectionHandler,
doc doc
); );
@@ -128,7 +153,7 @@ const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
onClickConnectEnd?.(event as unknown as MouseEvent); onClickConnectEnd?.(event as unknown as MouseEvent);
store.setState({ connectionStartHandle: null }); store.setState({ connectionClickStartHandle: null });
}; };
return ( return (
@@ -147,10 +172,12 @@ const Handle = forwardRef<HTMLDivElement, HandleComponentProps>(
source: !isTarget, source: !isTarget,
target: isTarget, target: isTarget,
connectable: isConnectable, connectable: isConnectable,
connecting: connectablestart: isConnectableStart,
connectionStartHandle?.nodeId === nodeId && connectableend: isConnectableEnd,
connectionStartHandle?.handleId === handleId && connecting: clickConnecting,
connectionStartHandle?.type === type, // this class is used to style the handle when the user is connecting
connectionindicator:
isConnectable && ((isConnectableStart && !connecting) || (isConnectableEnd && connecting)),
}, },
])} ])}
onMouseDown={onPointerDown} onMouseDown={onPointerDown}
+14 -3
View File
@@ -1,6 +1,6 @@
import { MouseEvent as ReactMouseEvent, TouchEvent as ReactTouchEvent } from 'react'; import { MouseEvent as ReactMouseEvent, TouchEvent as ReactTouchEvent } from 'react';
import { ConnectionMode, ConnectionStatus } from '../../types'; import { ConnectingHandle, ConnectionMode, ConnectionStatus } from '../../types';
import { getEventPosition, internalsSymbol } from '../../utils'; import { getEventPosition, internalsSymbol } from '../../utils';
import type { Connection, HandleType, XYPosition, Node, NodeHandleBounds } from '../../types'; import type { Connection, HandleType, XYPosition, Node, NodeHandleBounds } from '../../types';
@@ -59,6 +59,7 @@ type Result = {
handleDomNode: Element | null; handleDomNode: Element | null;
isValid: boolean; isValid: boolean;
connection: Connection; connection: Connection;
endHandle: ConnectingHandle | null;
}; };
const nullConnection: Connection = { source: null, target: null, sourceHandle: null, targetHandle: null }; const nullConnection: Connection = { source: null, target: null, sourceHandle: null, targetHandle: null };
@@ -70,7 +71,7 @@ export function isValidHandle(
connectionMode: ConnectionMode, connectionMode: ConnectionMode,
fromNodeId: string, fromNodeId: string,
fromHandleId: string | null, fromHandleId: string | null,
fromType: string, fromType: HandleType,
isValidConnection: ValidConnectionFunc, isValidConnection: ValidConnectionFunc,
doc: Document | ShadowRoot doc: Document | ShadowRoot
) { ) {
@@ -86,12 +87,15 @@ export function isValidHandle(
handleDomNode: handleToCheck, handleDomNode: handleToCheck,
isValid: false, isValid: false,
connection: nullConnection, connection: nullConnection,
endHandle: null,
}; };
if (handleToCheck) { if (handleToCheck) {
const handleType = getHandleType(undefined, handleToCheck); const handleType = getHandleType(undefined, handleToCheck);
const handleNodeId = handleToCheck.getAttribute('data-nodeid'); const handleNodeId = handleToCheck.getAttribute('data-nodeid');
const handleId = handleToCheck.getAttribute('data-handleid'); const handleId = handleToCheck.getAttribute('data-handleid');
const connectable = handleToCheck.classList.contains('connectable');
const connectableEnd = handleToCheck.classList.contains('connectableend');
const connection: Connection = { const connection: Connection = {
source: isTarget ? handleNodeId : fromNodeId, source: isTarget ? handleNodeId : fromNodeId,
@@ -102,14 +106,21 @@ export function isValidHandle(
result.connection = connection; result.connection = connection;
const isConnectable = connectable && connectableEnd;
// in strict mode we don't allow target to target or source to source connections // in strict mode we don't allow target to target or source to source connections
const isValid = const isValid =
handleToCheck.classList.contains('connectable') && isConnectable &&
(connectionMode === ConnectionMode.Strict (connectionMode === ConnectionMode.Strict
? (isTarget && handleType === 'source') || (!isTarget && handleType === 'target') ? (isTarget && handleType === 'source') || (!isTarget && handleType === 'target')
: handleNodeId !== fromNodeId || handleId !== fromHandleId); : handleNodeId !== fromNodeId || handleId !== fromHandleId);
if (isValid) { if (isValid) {
result.endHandle = {
nodeId: handleNodeId as string,
handleId,
type: handleType as HandleType,
};
result.isValid = isValidConnection(connection); result.isValid = isValidConnection(connection);
} }
} }
@@ -20,6 +20,7 @@ type StoreUpdaterProps = Pick<
| 'nodesConnectable' | 'nodesConnectable'
| 'nodesFocusable' | 'nodesFocusable'
| 'edgesFocusable' | 'edgesFocusable'
| 'edgesUpdatable'
| 'minZoom' | 'minZoom'
| 'maxZoom' | 'maxZoom'
| 'nodeExtent' | 'nodeExtent'
@@ -98,6 +99,7 @@ const StoreUpdater = ({
nodesConnectable, nodesConnectable,
nodesFocusable, nodesFocusable,
edgesFocusable, edgesFocusable,
edgesUpdatable,
elevateNodesOnSelect, elevateNodesOnSelect,
minZoom, minZoom,
maxZoom, maxZoom,
@@ -162,6 +164,7 @@ const StoreUpdater = ({
useDirectStoreUpdater('nodesConnectable', nodesConnectable, store.setState); useDirectStoreUpdater('nodesConnectable', nodesConnectable, store.setState);
useDirectStoreUpdater('nodesFocusable', nodesFocusable, store.setState); useDirectStoreUpdater('nodesFocusable', nodesFocusable, store.setState);
useDirectStoreUpdater('edgesFocusable', edgesFocusable, store.setState); useDirectStoreUpdater('edgesFocusable', edgesFocusable, store.setState);
useDirectStoreUpdater('edgesUpdatable', edgesUpdatable, store.setState);
useDirectStoreUpdater('elementsSelectable', elementsSelectable, store.setState); useDirectStoreUpdater('elementsSelectable', elementsSelectable, store.setState);
useDirectStoreUpdater('elevateNodesOnSelect', elevateNodesOnSelect, store.setState); useDirectStoreUpdater('elevateNodesOnSelect', elevateNodesOnSelect, store.setState);
useDirectStoreUpdater('snapToGrid', snapToGrid, store.setState); useDirectStoreUpdater('snapToGrid', snapToGrid, store.setState);
@@ -45,7 +45,7 @@ export function useMarkerSymbol(type: MarkerType) {
const symbolExists = Object.prototype.hasOwnProperty.call(MarkerSymbols, type); const symbolExists = Object.prototype.hasOwnProperty.call(MarkerSymbols, type);
if (!symbolExists) { if (!symbolExists) {
store.getState().onError?.('009', errorMessages['009'](type)); store.getState().onError?.('009', errorMessages['error009'](type));
return null; return null;
} }
@@ -39,6 +39,7 @@ type EdgeRendererProps = Pick<
const selector = (s: ReactFlowState) => ({ const selector = (s: ReactFlowState) => ({
nodesConnectable: s.nodesConnectable, nodesConnectable: s.nodesConnectable,
edgesFocusable: s.edgesFocusable, edgesFocusable: s.edgesFocusable,
edgesUpdatable: s.edgesUpdatable,
elementsSelectable: s.elementsSelectable, elementsSelectable: s.elementsSelectable,
width: s.width, width: s.width,
height: s.height, height: s.height,
@@ -66,10 +67,8 @@ const EdgeRenderer = ({
onEdgeUpdateEnd, onEdgeUpdateEnd,
children, children,
}: EdgeRendererProps) => { }: EdgeRendererProps) => {
const { edgesFocusable, elementsSelectable, width, height, connectionMode, nodeInternals, onError } = useStore( const { edgesFocusable, edgesUpdatable, elementsSelectable, width, height, connectionMode, nodeInternals, onError } =
selector, useStore(selector, shallow);
shallow
);
const edgeTree = useVisibleEdges(onlyRenderVisibleElements, nodeInternals, elevateEdgesOnSelect); const edgeTree = useVisibleEdges(onlyRenderVisibleElements, nodeInternals, elevateEdgesOnSelect);
if (!width) { if (!width) {
@@ -99,7 +98,7 @@ const EdgeRenderer = ({
let edgeType = edge.type || 'default'; let edgeType = edge.type || 'default';
if (!edgeTypes[edgeType]) { if (!edgeTypes[edgeType]) {
onError?.('011', errorMessages['011'](edgeType)); onError?.('011', errorMessages['error011'](edgeType));
edgeType = 'default'; edgeType = 'default';
} }
@@ -114,9 +113,12 @@ const EdgeRenderer = ({
const sourcePosition = sourceHandle?.position || Position.Bottom; const sourcePosition = sourceHandle?.position || Position.Bottom;
const targetPosition = targetHandle?.position || Position.Top; const targetPosition = targetHandle?.position || Position.Top;
const isFocusable = !!(edge.focusable || (edgesFocusable && typeof edge.focusable === 'undefined')); const isFocusable = !!(edge.focusable || (edgesFocusable && typeof edge.focusable === 'undefined'));
const isUpdatable =
typeof onEdgeUpdate !== 'undefined' &&
(edge.updatable || (edgesUpdatable && typeof edge.updatable === 'undefined'));
if (!sourceHandle || !targetHandle) { if (!sourceHandle || !targetHandle) {
onError?.('008', errorMessages['008'](sourceHandle, edge)); onError?.('008', errorMessages['error008'](sourceHandle, edge));
return null; return null;
} }
@@ -173,6 +175,7 @@ const EdgeRenderer = ({
rfId={rfId} rfId={rfId}
ariaLabel={edge.ariaLabel} ariaLabel={edge.ariaLabel}
isFocusable={isFocusable} isFocusable={isFocusable}
isUpdatable={isUpdatable}
pathOptions={'pathOptions' in edge ? edge.pathOptions : undefined} pathOptions={'pathOptions' in edge ? edge.pathOptions : undefined}
interactionWidth={edge.interactionWidth} interactionWidth={edge.interactionWidth}
/> />
@@ -78,7 +78,7 @@ const NodeRenderer = (props: NodeRendererProps) => {
let nodeType = node.type || 'default'; let nodeType = node.type || 'default';
if (!props.nodeTypes[nodeType]) { if (!props.nodeTypes[nodeType]) {
onError?.('003', errorMessages['003'](nodeType)); onError?.('003', errorMessages['error003'](nodeType));
nodeType = 'default'; nodeType = 'default';
} }
@@ -115,6 +115,7 @@ const ReactFlow = forwardRef<ReactFlowRefType, ReactFlowProps>(
nodesFocusable, nodesFocusable,
nodeOrigin = initNodeOrigin, nodeOrigin = initNodeOrigin,
edgesFocusable, edgesFocusable,
edgesUpdatable,
elementsSelectable, elementsSelectable,
defaultViewport = initDefaultViewport, defaultViewport = initDefaultViewport,
minZoom = 0.5, minZoom = 0.5,
@@ -266,6 +267,7 @@ const ReactFlow = forwardRef<ReactFlowRefType, ReactFlowProps>(
nodesConnectable={nodesConnectable} nodesConnectable={nodesConnectable}
nodesFocusable={nodesFocusable} nodesFocusable={nodesFocusable}
edgesFocusable={edgesFocusable} edgesFocusable={edgesFocusable}
edgesUpdatable={edgesUpdatable}
elementsSelectable={elementsSelectable} elementsSelectable={elementsSelectable}
elevateNodesOnSelect={elevateNodesOnSelect} elevateNodesOnSelect={elevateNodesOnSelect}
minZoom={minZoom} minZoom={minZoom}
@@ -17,7 +17,7 @@ export function useNodeOrEdgeTypes(nodeOrEdgeTypes: any, createTypes: any): any
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
const typeKeys = Object.keys(nodeOrEdgeTypes); const typeKeys = Object.keys(nodeOrEdgeTypes);
if (shallow(typesKeysRef.current, typeKeys)) { if (shallow(typesKeysRef.current, typeKeys)) {
devWarn('002', errorMessages['002']()); devWarn('002', errorMessages['error002']());
} }
typesKeysRef.current = typeKeys; typesKeysRef.current = typeKeys;
@@ -140,7 +140,7 @@ const ZoomPane = ({
-(deltaX / currentZoom) * panOnScrollSpeed, -(deltaX / currentZoom) * panOnScrollSpeed,
-(deltaY / currentZoom) * panOnScrollSpeed -(deltaY / currentZoom) * panOnScrollSpeed
); );
}); }, { passive: false });
} else if (typeof d3ZoomHandler !== 'undefined') { } else if (typeof d3ZoomHandler !== 'undefined') {
d3Selection.on('wheel.zoom', function (event: any, d: any) { d3Selection.on('wheel.zoom', function (event: any, d: any) {
if (!preventScrolling || isWrappedWithClass(event, noWheelClassName)) { if (!preventScrolling || isWrappedWithClass(event, noWheelClassName)) {
@@ -149,7 +149,7 @@ const ZoomPane = ({
event.preventDefault(); event.preventDefault();
d3ZoomHandler.call(this, event, d); d3ZoomHandler.call(this, event, d);
}); }, { passive: false });
} }
} }
}, [ }, [
+11 -11
View File
@@ -1,20 +1,20 @@
import { Edge, HandleElement } from './types'; import { Edge, HandleElement } from './types';
export const errorMessages = { export const errorMessages = {
'001': () => error001: () =>
'[React Flow]: Seems like you have not used zustand provider as an ancestor. Help: https://reactflow.dev/error#001', '[React Flow]: Seems like you have not used zustand provider as an ancestor. Help: https://reactflow.dev/error#001',
'002': () => error002: () =>
"It looks like you've created a new nodeTypes or edgeTypes object. If this wasn't on purpose please define the nodeTypes/edgeTypes outside of the component or memoize them.", "It looks like you've created a new nodeTypes or edgeTypes object. If this wasn't on purpose please define the nodeTypes/edgeTypes outside of the component or memoize them.",
'003': (nodeType: string) => `Node type "${nodeType}" not found. Using fallback type "default".`, error003: (nodeType: string) => `Node type "${nodeType}" not found. Using fallback type "default".`,
'004': () => 'The React Flow parent container needs a width and a height to render the graph.', error004: () => 'The React Flow parent container needs a width and a height to render the graph.',
'005': () => 'Only child nodes can use a parent extent.', error005: () => 'Only child nodes can use a parent extent.',
'006': () => "Can't create edge. An edge needs a source and a target.", error006: () => "Can't create edge. An edge needs a source and a target.",
'007': (id: string) => `The old edge with id=${id} does not exist.`, error007: (id: string) => `The old edge with id=${id} does not exist.`,
'009': (type: string) => `Marker type "${type}" doesn't exist.`, error009: (type: string) => `Marker type "${type}" doesn't exist.`,
'008': (sourceHandle: HandleElement | null, edge: Edge) => error008: (sourceHandle: HandleElement | null, edge: Edge) =>
`Couldn't create edge for ${!sourceHandle ? 'source' : 'target'} handle id: "${ `Couldn't create edge for ${!sourceHandle ? 'source' : 'target'} handle id: "${
!sourceHandle ? edge.sourceHandle : edge.targetHandle !sourceHandle ? edge.sourceHandle : edge.targetHandle
}", edge id: ${edge.id}.`, }", edge id: ${edge.id}.`,
'010': () => 'Handle: No node id found. Make sure to only use a Handle inside a custom Node.', error010: () => 'Handle: No node id found. Make sure to only use a Handle inside a custom Node.',
'011': (edgeType: string) => `Edge type "${edgeType}" not found. Using fallback type "default".`, error011: (edgeType: string) => `Edge type "${edgeType}" not found. Using fallback type "default".`,
}; };
+1 -1
View File
@@ -93,7 +93,7 @@ export function calcNextPosition(
] ]
: currentExtent; : currentExtent;
} else { } else {
onError?.('005', errorMessages['005']()); onError?.('005', errorMessages['error005']());
currentExtent = nodeExtent; currentExtent = nodeExtent;
} }
+15 -4
View File
@@ -2,16 +2,27 @@ import { internalsSymbol } from '../utils';
import { useStore } from './useStore'; import { useStore } from './useStore';
import type { ReactFlowState } from '../types'; import type { ReactFlowState } from '../types';
const selector = (s: ReactFlowState) => { export type UseNodesInitializedOptions = {
includeHiddenNodes?: boolean;
};
const selector = (options: UseNodesInitializedOptions) => (s: ReactFlowState) => {
if (s.nodeInternals.size === 0) { if (s.nodeInternals.size === 0) {
return false; return false;
} }
return s.getNodes().every((n) => n[internalsSymbol]?.handleBounds !== undefined); return s
.getNodes()
.filter((n) => (options.includeHiddenNodes ? true : !n.hidden))
.every((n) => n[internalsSymbol]?.handleBounds !== undefined);
}; };
function useNodesInitialized(): boolean { const defaultOptions = {
const initialized = useStore(selector); includeHiddenNodes: false,
};
function useNodesInitialized(options: UseNodesInitializedOptions = defaultOptions): boolean {
const initialized = useStore(selector(options));
return initialized; return initialized;
} }
+1 -1
View File
@@ -19,7 +19,7 @@ function useResizeHandler(rendererNode: MutableRefObject<HTMLDivElement | null>)
const size = getDimensions(rendererNode.current); const size = getDimensions(rendererNode.current);
if (size.height === 0 || size.width === 0) { if (size.height === 0 || size.width === 0) {
store.getState().onError?.('004', errorMessages['004']()); store.getState().onError?.('004', errorMessages['error004']());
} }
store.setState({ width: size.width || 500, height: size.height || 500 }); store.setState({ width: size.width || 500, height: size.height || 500 });
+1 -1
View File
@@ -6,7 +6,7 @@ import StoreContext from '../contexts/RFStoreContext';
import { errorMessages } from '../contants'; import { errorMessages } from '../contants';
import type { ReactFlowState } from '../types'; import type { ReactFlowState } from '../types';
const zustandErrorMessage = errorMessages['001'](); const zustandErrorMessage = errorMessages['error001']();
type ExtractState = StoreApi<ReactFlowState> extends { getState: () => infer T } ? T : never; type ExtractState = StoreApi<ReactFlowState> extends { getState: () => infer T } ? T : never;
+3 -3
View File
@@ -35,9 +35,9 @@ export { default as useViewport } from './hooks/useViewport';
export { default as useKeyPress } from './hooks/useKeyPress'; export { default as useKeyPress } from './hooks/useKeyPress';
export * from './hooks/useNodesEdgesState'; export * from './hooks/useNodesEdgesState';
export { useStore, useStoreApi } from './hooks/useStore'; export { useStore, useStoreApi } from './hooks/useStore';
export { default as useOnViewportChange } from './hooks/useOnViewportChange'; export { default as useOnViewportChange, type UseOnViewportChangeOptions } from './hooks/useOnViewportChange';
export { default as useOnSelectionChange } from './hooks/useOnSelectionChange'; export { default as useOnSelectionChange, type UseOnSelectionChangeOptions } from './hooks/useOnSelectionChange';
export { default as useNodesInitialized } from './hooks/useNodesInitialized'; export { default as useNodesInitialized, type UseNodesInitializedOptions } from './hooks/useNodesInitialized';
export { default as useGetPointerPosition } from './hooks/useGetPointerPosition'; export { default as useGetPointerPosition } from './hooks/useGetPointerPosition';
export { useNodeId } from './contexts/NodeIdContext'; export { useNodeId } from './contexts/NodeIdContext';
+2
View File
@@ -275,6 +275,8 @@ const createRFStore = () =>
connectionHandleId: initialState.connectionHandleId, connectionHandleId: initialState.connectionHandleId,
connectionHandleType: initialState.connectionHandleType, connectionHandleType: initialState.connectionHandleType,
connectionStatus: initialState.connectionStatus, connectionStatus: initialState.connectionStatus,
connectionStartHandle: initialState.connectionStartHandle,
connectionEndHandle: initialState.connectionEndHandle,
}), }),
reset: () => set({ ...initialState }), reset: () => set({ ...initialState }),
})); }));
+3
View File
@@ -46,6 +46,7 @@ const initialState: ReactFlowStore = {
nodesConnectable: true, nodesConnectable: true,
nodesFocusable: true, nodesFocusable: true,
edgesFocusable: true, edgesFocusable: true,
edgesUpdatable: true,
elementsSelectable: true, elementsSelectable: true,
elevateNodesOnSelect: true, elevateNodesOnSelect: true,
fitViewOnInit: false, fitViewOnInit: false,
@@ -55,6 +56,8 @@ const initialState: ReactFlowStore = {
multiSelectionActive: false, multiSelectionActive: false,
connectionStartHandle: null, connectionStartHandle: null,
connectionEndHandle: null,
connectionClickStartHandle: null,
connectOnClick: true, connectOnClick: true,
ariaLiveMessage: '', ariaLiveMessage: '',
+1 -1
View File
@@ -144,7 +144,7 @@
min-width: 5px; min-width: 5px;
min-height: 5px; min-height: 5px;
&.connectable { &.connectionindicator {
pointer-events: all; pointer-events: all;
cursor: crosshair; cursor: crosshair;
} }
@@ -112,6 +112,7 @@ export type ReactFlowProps = HTMLAttributes<HTMLDivElement> & {
nodesFocusable?: boolean; nodesFocusable?: boolean;
nodeOrigin?: NodeOrigin; nodeOrigin?: NodeOrigin;
edgesFocusable?: boolean; edgesFocusable?: boolean;
edgesUpdatable?: boolean;
initNodeOrigin?: NodeOrigin; initNodeOrigin?: NodeOrigin;
elementsSelectable?: boolean; elementsSelectable?: boolean;
selectNodesOnDrag?: boolean; selectNodesOnDrag?: boolean;
+4
View File
@@ -36,8 +36,11 @@ type DefaultEdge<T = any> = {
ariaLabel?: string; ariaLabel?: string;
interactionWidth?: number; interactionWidth?: number;
focusable?: boolean; focusable?: boolean;
updatable?: EdgeUpdatable;
} & EdgeLabelOptions; } & EdgeLabelOptions;
export type EdgeUpdatable = boolean | HandleType;
export type SmoothStepPathOptions = { export type SmoothStepPathOptions = {
offset?: number; offset?: number;
borderRadius?: number; borderRadius?: number;
@@ -88,6 +91,7 @@ export type WrapEdgeProps<T = any> = Omit<Edge<T>, 'sourceHandle' | 'targetHandl
onEdgeUpdateEnd?: (event: MouseEvent | TouchEvent, edge: Edge, handleType: HandleType) => void; onEdgeUpdateEnd?: (event: MouseEvent | TouchEvent, edge: Edge, handleType: HandleType) => void;
rfId?: string; rfId?: string;
isFocusable: boolean; isFocusable: boolean;
isUpdatable: EdgeUpdatable;
pathOptions?: BezierPathOptions | SmoothStepPathOptions; pathOptions?: BezierPathOptions | SmoothStepPathOptions;
}; };
+7 -2
View File
@@ -21,7 +21,7 @@ import type {
NodeOrigin, NodeOrigin,
} from './nodes'; } from './nodes';
import type { Edge, EdgeProps, WrapEdgeProps } from './edges'; import type { Edge, EdgeProps, WrapEdgeProps } from './edges';
import type { HandleType, StartHandle } from './handles'; import type { HandleType, ConnectingHandle } from './handles';
import type { DefaultEdgeOptions } from '.'; import type { DefaultEdgeOptions } from '.';
import type { ReactFlowInstance } from './instance'; import type { ReactFlowInstance } from './instance';
@@ -167,6 +167,7 @@ export type ReactFlowStore = {
userSelectionActive: boolean; userSelectionActive: boolean;
userSelectionRect: SelectionRect | null; userSelectionRect: SelectionRect | null;
// @todo remove this in next major version in favor of connectionStartHandle
connectionNodeId: string | null; connectionNodeId: string | null;
connectionHandleId: string | null; connectionHandleId: string | null;
connectionHandleType: HandleType | null; connectionHandleType: HandleType | null;
@@ -181,12 +182,16 @@ export type ReactFlowStore = {
nodesConnectable: boolean; nodesConnectable: boolean;
nodesFocusable: boolean; nodesFocusable: boolean;
edgesFocusable: boolean; edgesFocusable: boolean;
edgesUpdatable: boolean;
elementsSelectable: boolean; elementsSelectable: boolean;
elevateNodesOnSelect: boolean; elevateNodesOnSelect: boolean;
multiSelectionActive: boolean; multiSelectionActive: boolean;
connectionStartHandle: StartHandle | null; connectionStartHandle: ConnectingHandle | null;
connectionEndHandle: ConnectingHandle | null;
// @todo this is only used for the click connection - we might remove this in the next major version
connectionClickStartHandle: ConnectingHandle | null;
onNodeDragStart?: NodeDragHandler; onNodeDragStart?: NodeDragHandler;
onNodeDrag?: NodeDragHandler; onNodeDrag?: NodeDragHandler;
+11 -8
View File
@@ -2,22 +2,25 @@ import type { XYPosition, Position, Dimensions, OnConnect, Connection } from '.'
export type HandleType = 'source' | 'target'; export type HandleType = 'source' | 'target';
export interface HandleElement extends XYPosition, Dimensions { export type HandleElement = XYPosition &
id?: string | null; Dimensions & {
position: Position; id?: string | null;
} position: Position;
};
export interface StartHandle { export type ConnectingHandle = {
nodeId: string; nodeId: string;
type: HandleType; type: HandleType;
handleId?: string | null; handleId?: string | null;
} };
export interface HandleProps { export type HandleProps = {
type: HandleType; type: HandleType;
position: Position; position: Position;
isConnectable?: boolean; isConnectable?: boolean;
isConnectableStart?: boolean;
isConnectableEnd?: boolean;
onConnect?: OnConnect; onConnect?: OnConnect;
isValidConnection?: (connection: Connection) => boolean; isValidConnection?: (connection: Connection) => boolean;
id?: string; id?: string;
} };
+9 -4
View File
@@ -72,7 +72,7 @@ const connectionExists = (edge: Edge, edges: Edge[]) => {
export const addEdge = (edgeParams: Edge | Connection, edges: Edge[]): Edge[] => { export const addEdge = (edgeParams: Edge | Connection, edges: Edge[]): Edge[] => {
if (!edgeParams.source || !edgeParams.target) { if (!edgeParams.source || !edgeParams.target) {
devWarn('006', errorMessages['006']()); devWarn('006', errorMessages['error006']());
return edges; return edges;
} }
@@ -94,11 +94,16 @@ export const addEdge = (edgeParams: Edge | Connection, edges: Edge[]): Edge[] =>
return edges.concat(edge); return edges.concat(edge);
}; };
export const updateEdge = (oldEdge: Edge, newConnection: Connection, edges: Edge[], options: UpdateEdgeOptions = { shouldReplaceId: true }): Edge[] => { export const updateEdge = (
oldEdge: Edge,
newConnection: Connection,
edges: Edge[],
options: UpdateEdgeOptions = { shouldReplaceId: true }
): Edge[] => {
const { id: oldEdgeId, ...rest } = oldEdge; const { id: oldEdgeId, ...rest } = oldEdge;
if (!newConnection.source || !newConnection.target) { if (!newConnection.source || !newConnection.target) {
devWarn('006', errorMessages['006']()); devWarn('006', errorMessages['error006']());
return edges; return edges;
} }
@@ -106,7 +111,7 @@ export const updateEdge = (oldEdge: Edge, newConnection: Connection, edges: Edge
const foundEdge = edges.find((e) => e.id === oldEdgeId) as Edge; const foundEdge = edges.find((e) => e.id === oldEdgeId) as Edge;
if (!foundEdge) { if (!foundEdge) {
devWarn('007', errorMessages['007'](oldEdgeId)); devWarn('007', errorMessages['error007'](oldEdgeId));
return edges; return edges;
} }
+11
View File
@@ -1,5 +1,16 @@
# @reactflow/minimap # @reactflow/minimap
## 11.5.0
### Minor Changes
- [#2944](https://github.com/wbkd/react-flow/pull/2944) Thanks [@Elringus](https://github.com/Elringus)! - add `inversePan` and `zoomStep` props
### 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), [`923a54c4`](https://github.com/wbkd/react-flow/commit/923a54c481b90954806202817ba844cfa7203a38), [`4d97a0ed`](https://github.com/wbkd/react-flow/commit/4d97a0ed168ce643fc0c99fa6b47cf1296d66065), [`c22e1c28`](https://github.com/wbkd/react-flow/commit/c22e1c28c5555a638c2a8e82c3bfc986b3965d36)]:
- @reactflow/core@11.7.0
## 11.4.1 ## 11.4.1
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@reactflow/minimap", "name": "@reactflow/minimap",
"version": "11.4.1", "version": "11.5.0",
"description": "Minimap component for React Flow.", "description": "Minimap component for React Flow.",
"keywords": [ "keywords": [
"react", "react",
+7 -4
View File
@@ -67,6 +67,8 @@ function MiniMap({
pannable = false, pannable = false,
zoomable = false, zoomable = false,
ariaLabel = 'React Flow mini map', ariaLabel = 'React Flow mini map',
inversePan = false,
zoomStep = 10
}: MiniMapProps) { }: MiniMapProps) {
const store = useStoreApi(); const store = useStoreApi();
const svg = useRef<SVGSVGElement>(null); const svg = useRef<SVGSVGElement>(null);
@@ -106,7 +108,7 @@ function MiniMap({
const pinchDelta = const pinchDelta =
-event.sourceEvent.deltaY * -event.sourceEvent.deltaY *
(event.sourceEvent.deltaMode === 1 ? 0.05 : event.sourceEvent.deltaMode ? 1 : 0.002) * (event.sourceEvent.deltaMode === 1 ? 0.05 : event.sourceEvent.deltaMode ? 1 : 0.002) *
10; zoomStep;
const zoom = transform[2] * Math.pow(2, pinchDelta); const zoom = transform[2] * Math.pow(2, pinchDelta);
d3Zoom.scaleTo(d3Selection, zoom); d3Zoom.scaleTo(d3Selection, zoom);
@@ -120,9 +122,10 @@ function MiniMap({
} }
// @TODO: how to calculate the correct next position? Math.max(1, transform[2]) is a workaround. // @TODO: how to calculate the correct next position? Math.max(1, transform[2]) is a workaround.
const moveScale = viewScaleRef.current * Math.max(1, transform[2]) * (inversePan ? -1 : 1);
const position = { const position = {
x: transform[0] - event.sourceEvent.movementX * viewScaleRef.current * Math.max(1, transform[2]), x: transform[0] - event.sourceEvent.movementX * moveScale,
y: transform[1] - event.sourceEvent.movementY * viewScaleRef.current * Math.max(1, transform[2]), y: transform[1] - event.sourceEvent.movementY * moveScale,
}; };
const extent: CoordinateExtent = [ const extent: CoordinateExtent = [
[0, 0], [0, 0],
@@ -147,7 +150,7 @@ function MiniMap({
selection.on('zoom', null); selection.on('zoom', null);
}; };
} }
}, [pannable, zoomable]); }, [pannable, zoomable, inversePan, zoomStep]);
const onSvgClick = onClick const onSvgClick = onClick
? (event: MouseEvent) => { ? (event: MouseEvent) => {
+2
View File
@@ -20,6 +20,8 @@ export type MiniMapProps<NodeData = any> = Omit<HTMLAttributes<SVGSVGElement>, '
pannable?: boolean; pannable?: boolean;
zoomable?: boolean; zoomable?: boolean;
ariaLabel?: string | null; ariaLabel?: string | null;
inversePan?: boolean;
zoomStep?: number;
}; };
export interface MiniMapNodeProps { export interface MiniMapNodeProps {
+7
View File
@@ -1,5 +1,12 @@
# @reactflow/node-toolbar # @reactflow/node-toolbar
## 1.1.11
### 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), [`923a54c4`](https://github.com/wbkd/react-flow/commit/923a54c481b90954806202817ba844cfa7203a38), [`4d97a0ed`](https://github.com/wbkd/react-flow/commit/4d97a0ed168ce643fc0c99fa6b47cf1296d66065), [`c22e1c28`](https://github.com/wbkd/react-flow/commit/c22e1c28c5555a638c2a8e82c3bfc986b3965d36)]:
- @reactflow/core@11.7.0
## 1.1.10 ## 1.1.10
### Patch Changes ### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@reactflow/node-toolbar", "name": "@reactflow/node-toolbar",
"version": "1.1.10", "version": "1.1.11",
"description": "A toolbar component for React Flow that can be attached to a node.", "description": "A toolbar component for React Flow that can be attached to a node.",
"keywords": [ "keywords": [
"react", "react",
+39
View File
@@ -1,5 +1,44 @@
# reactflow # reactflow
## 11.7.0
Most notable updates:
- `@reactflow/node-resizer` is now part of this package. No need to install it separately anymore.
- 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
- 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)
Big thanks to [@Elringus](https://github.com/Elringus) and [@bcakmakoglu](https://github.com/bcakmakoglu)!
### Minor Changes
- [#2964](https://github.com/wbkd/react-flow/pull/2964) [`2fb4c2c8`](https://github.com/wbkd/react-flow/commit/2fb4c2c82343751ff536da262de74bd9080321b4) - add @reactflow/node-resizer package
- [#2960](https://github.com/wbkd/react-flow/pull/2960) Thanks [@bcakmakoglu](https://github.com/bcakmakoglu)! - edges: add `updatable` option
- [#2958](https://github.com/wbkd/react-flow/pull/2958) [`4d97a0ed`](https://github.com/wbkd/react-flow/commit/4d97a0ed168ce643fc0c99fa6b47cf1296d66065) - handles: add `isConnectableStart` and `isConnectableEnd` props
- [#2956](https://github.com/wbkd/react-flow/pull/2956) [`923a54c4`](https://github.com/wbkd/react-flow/commit/923a54c481b90954806202817ba844cfa7203a38) - add options for `useNodesInitialized`, ignore hidden nodes by default
- [#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)]:
- @reactflow/core@11.7.0
- @reactflow/minimap@11.5.0
- @reactflow/background@11.2.0
- @reactflow/controls@11.1.11
- @reactflow/node-toolbar@1.1.11
## 11.6.1 ## 11.6.1
### Patch Changes ### Patch Changes
+2 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "reactflow", "name": "reactflow",
"version": "11.6.1", "version": "11.7.0",
"description": "A highly customizable React library for building node-based editors and interactive flow charts", "description": "A highly customizable React library for building node-based editors and interactive flow charts",
"keywords": [ "keywords": [
"react", "react",
@@ -39,6 +39,7 @@
"@reactflow/controls": "workspace:*", "@reactflow/controls": "workspace:*",
"@reactflow/core": "workspace:*", "@reactflow/core": "workspace:*",
"@reactflow/minimap": "workspace:*", "@reactflow/minimap": "workspace:*",
"@reactflow/node-resizer": "workspace:*",
"@reactflow/node-toolbar": "workspace:*" "@reactflow/node-toolbar": "workspace:*"
}, },
"peerDependencies": { "peerDependencies": {
+1
View File
@@ -1,3 +1,4 @@
@import '@reactflow/core/dist/base.css'; @import '@reactflow/core/dist/base.css';
@import '@reactflow/controls/dist/style.css'; @import '@reactflow/controls/dist/style.css';
@import '@reactflow/minimap/dist/style.css'; @import '@reactflow/minimap/dist/style.css';
@import '@reactflow/node-resizer/dist/style.css';
+1
View File
@@ -3,5 +3,6 @@ export * from '@reactflow/minimap';
export * from '@reactflow/controls'; export * from '@reactflow/controls';
export * from '@reactflow/background'; export * from '@reactflow/background';
export * from '@reactflow/node-toolbar'; export * from '@reactflow/node-toolbar';
export * from '@reactflow/node-resizer';
export { ReactFlow as default } from '@reactflow/core'; export { ReactFlow as default } from '@reactflow/core';
+1
View File
@@ -1,3 +1,4 @@
@import '@reactflow/core/dist/style.css'; @import '@reactflow/core/dist/style.css';
@import '@reactflow/controls/dist/style.css'; @import '@reactflow/controls/dist/style.css';
@import '@reactflow/minimap/dist/style.css'; @import '@reactflow/minimap/dist/style.css';
@import '@reactflow/node-resizer/dist/style.css';
+62 -58
View File
@@ -32,8 +32,8 @@ importers:
'@changesets/changelog-github': registry.npmjs.org/@changesets/changelog-github/0.4.7 '@changesets/changelog-github': registry.npmjs.org/@changesets/changelog-github/0.4.7
'@changesets/cli': registry.npmjs.org/@changesets/cli/2.25.0 '@changesets/cli': registry.npmjs.org/@changesets/cli/2.25.0
'@preconstruct/cli': registry.npmjs.org/@preconstruct/cli/2.2.1 '@preconstruct/cli': registry.npmjs.org/@preconstruct/cli/2.2.1
'@typescript-eslint/eslint-plugin': registry.npmjs.org/@typescript-eslint/eslint-plugin/5.55.0_yarhzymb3lojuq6uyipzo3xllu '@typescript-eslint/eslint-plugin': registry.npmjs.org/@typescript-eslint/eslint-plugin/5.57.0_mc6km5pjrfw7q236yimvgyb62m
'@typescript-eslint/parser': registry.npmjs.org/@typescript-eslint/parser/5.55.0_id2eilsndvzhjjktb64trvy3gu '@typescript-eslint/parser': registry.npmjs.org/@typescript-eslint/parser/5.57.0_id2eilsndvzhjjktb64trvy3gu
autoprefixer: registry.npmjs.org/autoprefixer/10.4.9_postcss@8.4.21 autoprefixer: registry.npmjs.org/autoprefixer/10.4.9_postcss@8.4.21
concurrently: registry.npmjs.org/concurrently/7.6.0 concurrently: registry.npmjs.org/concurrently/7.6.0
cypress: registry.npmjs.org/cypress/10.7.0 cypress: registry.npmjs.org/cypress/10.7.0
@@ -74,6 +74,7 @@ importers:
start-server-and-test: ^1.14.0 start-server-and-test: ^1.14.0
typescript: ^4.9.4 typescript: ^4.9.4
vite: ^4.0.4 vite: ^4.0.4
zustand: ^4.3.1
dependencies: dependencies:
'@reactflow/node-resizer': link:../../packages/node-resizer '@reactflow/node-resizer': link:../../packages/node-resizer
classcat: registry.npmjs.org/classcat/5.0.4 classcat: registry.npmjs.org/classcat/5.0.4
@@ -83,6 +84,7 @@ importers:
react-dom: registry.npmjs.org/react-dom/18.2.0_react@18.2.0 react-dom: registry.npmjs.org/react-dom/18.2.0_react@18.2.0
react-router-dom: registry.npmjs.org/react-router-dom/6.3.0_biqbaboplfbrettd7655fr4n2y react-router-dom: registry.npmjs.org/react-router-dom/6.3.0_biqbaboplfbrettd7655fr4n2y
reactflow: link:../../packages/reactflow reactflow: link:../../packages/reactflow
zustand: registry.npmjs.org/zustand/4.3.1_react@18.2.0
devDependencies: devDependencies:
'@cypress/skip-test': registry.npmjs.org/@cypress/skip-test/2.6.1 '@cypress/skip-test': registry.npmjs.org/@cypress/skip-test/2.6.1
'@types/dagre': registry.npmjs.org/@types/dagre/0.7.48 '@types/dagre': registry.npmjs.org/@types/dagre/0.7.48
@@ -282,6 +284,7 @@ importers:
'@reactflow/core': workspace:* '@reactflow/core': workspace:*
'@reactflow/eslint-config': workspace:* '@reactflow/eslint-config': workspace:*
'@reactflow/minimap': workspace:* '@reactflow/minimap': workspace:*
'@reactflow/node-resizer': workspace:*
'@reactflow/node-toolbar': workspace:* '@reactflow/node-toolbar': workspace:*
'@reactflow/rollup-config': workspace:* '@reactflow/rollup-config': workspace:*
'@reactflow/tsconfig': workspace:* '@reactflow/tsconfig': workspace:*
@@ -294,6 +297,7 @@ importers:
'@reactflow/controls': link:../controls '@reactflow/controls': link:../controls
'@reactflow/core': link:../core '@reactflow/core': link:../core
'@reactflow/minimap': link:../minimap '@reactflow/minimap': link:../minimap
'@reactflow/node-resizer': link:../node-resizer
'@reactflow/node-toolbar': link:../node-toolbar '@reactflow/node-toolbar': link:../node-toolbar
devDependencies: devDependencies:
'@reactflow/eslint-config': link:../../tooling/eslint-config '@reactflow/eslint-config': link:../../tooling/eslint-config
@@ -313,7 +317,7 @@ importers:
devDependencies: devDependencies:
eslint: registry.npmjs.org/eslint/8.23.1 eslint: registry.npmjs.org/eslint/8.23.1
eslint-config-prettier: registry.npmjs.org/eslint-config-prettier/8.5.0_eslint@8.23.1 eslint-config-prettier: registry.npmjs.org/eslint-config-prettier/8.5.0_eslint@8.23.1
eslint-config-turbo: registry.npmjs.org/eslint-config-turbo/0.0.9_eslint@8.23.1 eslint-config-turbo: registry.npmjs.org/eslint-config-turbo/1.8.6_eslint@8.23.1
eslint-plugin-react: registry.npmjs.org/eslint-plugin-react/7.32.2_eslint@8.23.1 eslint-plugin-react: registry.npmjs.org/eslint-plugin-react/7.32.2_eslint@8.23.1
tooling/rollup-config: tooling/rollup-config:
@@ -2214,11 +2218,11 @@ packages:
dev: true dev: true
optional: true optional: true
registry.npmjs.org/@typescript-eslint/eslint-plugin/5.55.0_yarhzymb3lojuq6uyipzo3xllu: registry.npmjs.org/@typescript-eslint/eslint-plugin/5.57.0_mc6km5pjrfw7q236yimvgyb62m:
resolution: {integrity: sha512-IZGc50rtbjk+xp5YQoJvmMPmJEYoC53SiKPXyqWfv15XoD2Y5Kju6zN0DwlmaGJp1Iw33JsWJcQ7nw0lGCGjVg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz} resolution: {integrity: sha512-itag0qpN6q2UMM6Xgk6xoHa0D0/P+M17THnr4SVgqn9Rgam5k/He33MA7/D7QoJcdMxHFyX7U9imaBonAX/6qA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.57.0.tgz}
id: registry.npmjs.org/@typescript-eslint/eslint-plugin/5.55.0 id: registry.npmjs.org/@typescript-eslint/eslint-plugin/5.57.0
name: '@typescript-eslint/eslint-plugin' name: '@typescript-eslint/eslint-plugin'
version: 5.55.0 version: 5.57.0
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
'@typescript-eslint/parser': ^5.0.0 '@typescript-eslint/parser': ^5.0.0
@@ -2229,10 +2233,10 @@ packages:
optional: true optional: true
dependencies: dependencies:
'@eslint-community/regexpp': registry.npmjs.org/@eslint-community/regexpp/4.4.0 '@eslint-community/regexpp': registry.npmjs.org/@eslint-community/regexpp/4.4.0
'@typescript-eslint/parser': registry.npmjs.org/@typescript-eslint/parser/5.55.0_id2eilsndvzhjjktb64trvy3gu '@typescript-eslint/parser': registry.npmjs.org/@typescript-eslint/parser/5.57.0_id2eilsndvzhjjktb64trvy3gu
'@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager/5.55.0 '@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager/5.57.0
'@typescript-eslint/type-utils': registry.npmjs.org/@typescript-eslint/type-utils/5.55.0_id2eilsndvzhjjktb64trvy3gu '@typescript-eslint/type-utils': registry.npmjs.org/@typescript-eslint/type-utils/5.57.0_id2eilsndvzhjjktb64trvy3gu
'@typescript-eslint/utils': registry.npmjs.org/@typescript-eslint/utils/5.55.0_id2eilsndvzhjjktb64trvy3gu '@typescript-eslint/utils': registry.npmjs.org/@typescript-eslint/utils/5.57.0_id2eilsndvzhjjktb64trvy3gu
debug: registry.npmjs.org/debug/4.3.4 debug: registry.npmjs.org/debug/4.3.4
eslint: registry.npmjs.org/eslint/8.23.1 eslint: registry.npmjs.org/eslint/8.23.1
grapheme-splitter: registry.npmjs.org/grapheme-splitter/1.0.4 grapheme-splitter: registry.npmjs.org/grapheme-splitter/1.0.4
@@ -2245,11 +2249,11 @@ packages:
- supports-color - supports-color
dev: true dev: true
registry.npmjs.org/@typescript-eslint/parser/5.55.0_id2eilsndvzhjjktb64trvy3gu: registry.npmjs.org/@typescript-eslint/parser/5.57.0_id2eilsndvzhjjktb64trvy3gu:
resolution: {integrity: sha512-ppvmeF7hvdhUUZWSd2EEWfzcFkjJzgNQzVST22nzg958CR+sphy8A6K7LXQZd6V75m1VKjp+J4g/PCEfSCmzhw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.55.0.tgz} resolution: {integrity: sha512-orrduvpWYkgLCyAdNtR1QIWovcNZlEm6yL8nwH/eTxWLd8gsP+25pdLHYzL2QdkqrieaDwLpytHqycncv0woUQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.57.0.tgz}
id: registry.npmjs.org/@typescript-eslint/parser/5.55.0 id: registry.npmjs.org/@typescript-eslint/parser/5.57.0
name: '@typescript-eslint/parser' name: '@typescript-eslint/parser'
version: 5.55.0 version: 5.57.0
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
@@ -2258,9 +2262,9 @@ packages:
typescript: typescript:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager/5.55.0 '@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager/5.57.0
'@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.55.0 '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.57.0
'@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree/5.55.0_typescript@4.9.4 '@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree/5.57.0_typescript@4.9.4
debug: registry.npmjs.org/debug/4.3.4 debug: registry.npmjs.org/debug/4.3.4
eslint: registry.npmjs.org/eslint/8.23.1 eslint: registry.npmjs.org/eslint/8.23.1
typescript: registry.npmjs.org/typescript/4.9.4 typescript: registry.npmjs.org/typescript/4.9.4
@@ -2268,21 +2272,21 @@ packages:
- supports-color - supports-color
dev: true dev: true
registry.npmjs.org/@typescript-eslint/scope-manager/5.55.0: registry.npmjs.org/@typescript-eslint/scope-manager/5.57.0:
resolution: {integrity: sha512-OK+cIO1ZGhJYNCL//a3ROpsd83psf4dUJ4j7pdNVzd5DmIk+ffkuUIX2vcZQbEW/IR41DYsfJTB19tpCboxQuw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.55.0.tgz} resolution: {integrity: sha512-NANBNOQvllPlizl9LatX8+MHi7bx7WGIWYjPHDmQe5Si/0YEYfxSljJpoTyTWFTgRy3X8gLYSE4xQ2U+aCozSw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.57.0.tgz}
name: '@typescript-eslint/scope-manager' name: '@typescript-eslint/scope-manager'
version: 5.55.0 version: 5.57.0
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies: dependencies:
'@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.55.0 '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.57.0
'@typescript-eslint/visitor-keys': registry.npmjs.org/@typescript-eslint/visitor-keys/5.55.0 '@typescript-eslint/visitor-keys': registry.npmjs.org/@typescript-eslint/visitor-keys/5.57.0
dev: true dev: true
registry.npmjs.org/@typescript-eslint/type-utils/5.55.0_id2eilsndvzhjjktb64trvy3gu: registry.npmjs.org/@typescript-eslint/type-utils/5.57.0_id2eilsndvzhjjktb64trvy3gu:
resolution: {integrity: sha512-ObqxBgHIXj8rBNm0yh8oORFrICcJuZPZTqtAFh0oZQyr5DnAHZWfyw54RwpEEH+fD8suZaI0YxvWu5tYE/WswA==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.55.0.tgz} resolution: {integrity: sha512-kxXoq9zOTbvqzLbdNKy1yFrxLC6GDJFE2Yuo3KqSwTmDOFjUGeWSakgoXT864WcK5/NAJkkONCiKb1ddsqhLXQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.57.0.tgz}
id: registry.npmjs.org/@typescript-eslint/type-utils/5.55.0 id: registry.npmjs.org/@typescript-eslint/type-utils/5.57.0
name: '@typescript-eslint/type-utils' name: '@typescript-eslint/type-utils'
version: 5.55.0 version: 5.57.0
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
eslint: '*' eslint: '*'
@@ -2291,8 +2295,8 @@ packages:
typescript: typescript:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree/5.55.0_typescript@4.9.4 '@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree/5.57.0_typescript@4.9.4
'@typescript-eslint/utils': registry.npmjs.org/@typescript-eslint/utils/5.55.0_id2eilsndvzhjjktb64trvy3gu '@typescript-eslint/utils': registry.npmjs.org/@typescript-eslint/utils/5.57.0_id2eilsndvzhjjktb64trvy3gu
debug: registry.npmjs.org/debug/4.3.4 debug: registry.npmjs.org/debug/4.3.4
eslint: registry.npmjs.org/eslint/8.23.1 eslint: registry.npmjs.org/eslint/8.23.1
tsutils: registry.npmjs.org/tsutils/3.21.0_typescript@4.9.4 tsutils: registry.npmjs.org/tsutils/3.21.0_typescript@4.9.4
@@ -2301,18 +2305,18 @@ packages:
- supports-color - supports-color
dev: true dev: true
registry.npmjs.org/@typescript-eslint/types/5.55.0: registry.npmjs.org/@typescript-eslint/types/5.57.0:
resolution: {integrity: sha512-M4iRh4AG1ChrOL6Y+mETEKGeDnT7Sparn6fhZ5LtVJF1909D5O4uqK+C5NPbLmpfZ0XIIxCdwzKiijpZUOvOug==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/types/-/types-5.55.0.tgz} resolution: {integrity: sha512-mxsod+aZRSyLT+jiqHw1KK6xrANm19/+VFALVFP5qa/aiJnlP38qpyaTd0fEKhWvQk6YeNZ5LGwI1pDpBRBhtQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/types/-/types-5.57.0.tgz}
name: '@typescript-eslint/types' name: '@typescript-eslint/types'
version: 5.55.0 version: 5.57.0
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true dev: true
registry.npmjs.org/@typescript-eslint/typescript-estree/5.55.0_typescript@4.9.4: registry.npmjs.org/@typescript-eslint/typescript-estree/5.57.0_typescript@4.9.4:
resolution: {integrity: sha512-I7X4A9ovA8gdpWMpr7b1BN9eEbvlEtWhQvpxp/yogt48fy9Lj3iE3ild/1H3jKBBIYj5YYJmS2+9ystVhC7eaQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.55.0.tgz} resolution: {integrity: sha512-LTzQ23TV82KpO8HPnWuxM2V7ieXW8O142I7hQTxWIHDcCEIjtkat6H96PFkYBQqGFLW/G/eVVOB9Z8rcvdY/Vw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.57.0.tgz}
id: registry.npmjs.org/@typescript-eslint/typescript-estree/5.55.0 id: registry.npmjs.org/@typescript-eslint/typescript-estree/5.57.0
name: '@typescript-eslint/typescript-estree' name: '@typescript-eslint/typescript-estree'
version: 5.55.0 version: 5.57.0
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
typescript: '*' typescript: '*'
@@ -2320,8 +2324,8 @@ packages:
typescript: typescript:
optional: true optional: true
dependencies: dependencies:
'@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.55.0 '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.57.0
'@typescript-eslint/visitor-keys': registry.npmjs.org/@typescript-eslint/visitor-keys/5.55.0 '@typescript-eslint/visitor-keys': registry.npmjs.org/@typescript-eslint/visitor-keys/5.57.0
debug: registry.npmjs.org/debug/4.3.4 debug: registry.npmjs.org/debug/4.3.4
globby: registry.npmjs.org/globby/11.1.0 globby: registry.npmjs.org/globby/11.1.0
is-glob: registry.npmjs.org/is-glob/4.0.3 is-glob: registry.npmjs.org/is-glob/4.0.3
@@ -2332,11 +2336,11 @@ packages:
- supports-color - supports-color
dev: true dev: true
registry.npmjs.org/@typescript-eslint/utils/5.55.0_id2eilsndvzhjjktb64trvy3gu: registry.npmjs.org/@typescript-eslint/utils/5.57.0_id2eilsndvzhjjktb64trvy3gu:
resolution: {integrity: sha512-FkW+i2pQKcpDC3AY6DU54yl8Lfl14FVGYDgBTyGKB75cCwV3KpkpTMFi9d9j2WAJ4271LR2HeC5SEWF/CZmmfw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.55.0.tgz} resolution: {integrity: sha512-ps/4WohXV7C+LTSgAL5CApxvxbMkl9B9AUZRtnEFonpIxZDIT7wC1xfvuJONMidrkB9scs4zhtRyIwHh4+18kw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.57.0.tgz}
id: registry.npmjs.org/@typescript-eslint/utils/5.55.0 id: registry.npmjs.org/@typescript-eslint/utils/5.57.0
name: '@typescript-eslint/utils' name: '@typescript-eslint/utils'
version: 5.55.0 version: 5.57.0
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies: peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
@@ -2344,9 +2348,9 @@ packages:
'@eslint-community/eslint-utils': registry.npmjs.org/@eslint-community/eslint-utils/4.2.0_eslint@8.23.1 '@eslint-community/eslint-utils': registry.npmjs.org/@eslint-community/eslint-utils/4.2.0_eslint@8.23.1
'@types/json-schema': registry.npmjs.org/@types/json-schema/7.0.11 '@types/json-schema': registry.npmjs.org/@types/json-schema/7.0.11
'@types/semver': registry.npmjs.org/@types/semver/7.3.13 '@types/semver': registry.npmjs.org/@types/semver/7.3.13
'@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager/5.55.0 '@typescript-eslint/scope-manager': registry.npmjs.org/@typescript-eslint/scope-manager/5.57.0
'@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.55.0 '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.57.0
'@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree/5.55.0_typescript@4.9.4 '@typescript-eslint/typescript-estree': registry.npmjs.org/@typescript-eslint/typescript-estree/5.57.0_typescript@4.9.4
eslint: registry.npmjs.org/eslint/8.23.1 eslint: registry.npmjs.org/eslint/8.23.1
eslint-scope: registry.npmjs.org/eslint-scope/5.1.1 eslint-scope: registry.npmjs.org/eslint-scope/5.1.1
semver: registry.npmjs.org/semver/7.3.8 semver: registry.npmjs.org/semver/7.3.8
@@ -2355,13 +2359,13 @@ packages:
- typescript - typescript
dev: true dev: true
registry.npmjs.org/@typescript-eslint/visitor-keys/5.55.0: registry.npmjs.org/@typescript-eslint/visitor-keys/5.57.0:
resolution: {integrity: sha512-q2dlHHwWgirKh1D3acnuApXG+VNXpEY5/AwRxDVuEQpxWaB0jCDe0jFMVMALJ3ebSfuOVE8/rMS+9ZOYGg1GWw==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.55.0.tgz} resolution: {integrity: sha512-ery2g3k0hv5BLiKpPuwYt9KBkAp2ugT6VvyShXdLOkax895EC55sP0Tx5L0fZaQueiK3fBLvHVvEl3jFS5ia+g==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.57.0.tgz}
name: '@typescript-eslint/visitor-keys' name: '@typescript-eslint/visitor-keys'
version: 5.55.0 version: 5.57.0
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies: dependencies:
'@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.55.0 '@typescript-eslint/types': registry.npmjs.org/@typescript-eslint/types/5.57.0
eslint-visitor-keys: registry.npmjs.org/eslint-visitor-keys/3.3.0 eslint-visitor-keys: registry.npmjs.org/eslint-visitor-keys/3.3.0
dev: true dev: true
@@ -3720,16 +3724,16 @@ packages:
eslint: registry.npmjs.org/eslint/8.23.1 eslint: registry.npmjs.org/eslint/8.23.1
dev: true dev: true
registry.npmjs.org/eslint-config-turbo/0.0.9_eslint@8.23.1: registry.npmjs.org/eslint-config-turbo/1.8.6_eslint@8.23.1:
resolution: {integrity: sha512-j1cTdx3tRmKo0csyfQKhpuT8dynK9oddbK5nmrShoMpXI2qMbxHLYH7MWAid4FmJN8rYympy3VKw5U63Yazycg==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/eslint-config-turbo/-/eslint-config-turbo-0.0.9.tgz} resolution: {integrity: sha512-LSMqrHmFeQcYRuBnzrzw+B2bJ3+o8wxPkRwfK0Y+SSLsq2F/niRJ2kqB8j4uOSCfxybHHpFEB2CgUpQiiyfeoQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/eslint-config-turbo/-/eslint-config-turbo-1.8.6.tgz}
id: registry.npmjs.org/eslint-config-turbo/0.0.9 id: registry.npmjs.org/eslint-config-turbo/1.8.6
name: eslint-config-turbo name: eslint-config-turbo
version: 0.0.9 version: 1.8.6
peerDependencies: peerDependencies:
eslint: '>6.6.0' eslint: '>6.6.0'
dependencies: dependencies:
eslint: registry.npmjs.org/eslint/8.23.1 eslint: registry.npmjs.org/eslint/8.23.1
eslint-plugin-turbo: registry.npmjs.org/eslint-plugin-turbo/0.0.9_eslint@8.23.1 eslint-plugin-turbo: registry.npmjs.org/eslint-plugin-turbo/1.8.6_eslint@8.23.1
dev: true dev: true
registry.npmjs.org/eslint-plugin-prettier/4.2.1_cabrci5exjdaojcvd6xoxgeowu: registry.npmjs.org/eslint-plugin-prettier/4.2.1_cabrci5exjdaojcvd6xoxgeowu:
@@ -3779,11 +3783,11 @@ packages:
string.prototype.matchall: registry.npmjs.org/string.prototype.matchall/4.0.8 string.prototype.matchall: registry.npmjs.org/string.prototype.matchall/4.0.8
dev: true dev: true
registry.npmjs.org/eslint-plugin-turbo/0.0.9_eslint@8.23.1: registry.npmjs.org/eslint-plugin-turbo/1.8.6_eslint@8.23.1:
resolution: {integrity: sha512-fEsuSnYU3GLtT+s66mUuzDL1LaSieIx5uk3tPO0ToGv7hI2XzOfP24aPkQItTBGl7kq2JaVkRzPwcnfz8hkp0w==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/eslint-plugin-turbo/-/eslint-plugin-turbo-0.0.9.tgz} resolution: {integrity: sha512-LieXzur+4XtIsLst8GdupTMhvGn2ebFetG3AVErh2jHBy1EobPHbatjcdNZQMy5EsdG35axQVB8KFF3jo4u+OQ==, registry: https://registry.npmjs.com/, tarball: https://registry.npmjs.org/eslint-plugin-turbo/-/eslint-plugin-turbo-1.8.6.tgz}
id: registry.npmjs.org/eslint-plugin-turbo/0.0.9 id: registry.npmjs.org/eslint-plugin-turbo/1.8.6
name: eslint-plugin-turbo name: eslint-plugin-turbo
version: 0.0.9 version: 1.8.6
peerDependencies: peerDependencies:
eslint: '>6.6.0' eslint: '>6.6.0'
dependencies: dependencies: