diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 57ddf040..88667189 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,18 +1,18 @@ -name: '🐛 Bug report' +name: '🐛 Bug Report' description: Create a report to help us improve React Flow body: - type: markdown attributes: value: | Thank you for reporting an issue :pray:. - + **Please only file issues for v10. Will will no longer fix issues for v9.** This issue tracker is for reporting bugs found in react-flow (https://github.com/wbkd/react-flow) If you have a question about how to achieve something and are struggling, please post a question inside of react-flow's Discussion's tab: https://github.com/wbkd/react-flow/discussions If it's an issue about the docs please go to the react-flow-docs (https://github.com/wbkd/react-flow-docs) - + Before submitting a new bug/issue, please check the links below to see if there is a solution or question posted there already: - react-flow's Open Issue's tab: https://github.com/wbkd/react-flow/issues?q=is%3Aissue+sort%3Aupdated-desc+position - react-flow's Closed Issues tab: https://github.com/wbkd/react-flow/issues?q=is%3Aissue+sort%3Aupdated-desc+position+is%3Aclosed diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000..5d9ec8fa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,11 @@ +name: 🛠 Feature Request +description: Suggest a new feature or idea for React Flow +labels: feature request +body: + - type: textarea + id: description + attributes: + label: Please describe the feature that you want to propose + description: A clear and concise description of what you want to happen. + validations: + required: true diff --git a/examples/nextjs/pages/CustomNode/index.tsx b/examples/nextjs/pages/CustomNode/index.tsx index 84e7894f..40f2add1 100644 --- a/examples/nextjs/pages/CustomNode/index.tsx +++ b/examples/nextjs/pages/CustomNode/index.tsx @@ -26,7 +26,6 @@ const initBgColor = '#1A192B'; const connectionLineStyle = { stroke: '#fff' }; const snapGrid: SnapGrid = [16, 16]; -const defaultViewport = { x: 0, y: 0, zoom: 1.5 }; const nodeTypes = { selectorNode: ColorSelectorNode, @@ -137,8 +136,9 @@ const CustomNodeFlow = () => { connectionLineStyle={connectionLineStyle} snapToGrid={true} snapGrid={snapGrid} - defaultViewport={defaultViewport} fitView + minZoom={0.3} + maxZoom={2} > { diff --git a/examples/nextjs/pages/UseReactFlow/index.tsx b/examples/nextjs/pages/UseReactFlow/index.tsx index e60428d4..0d1b5f97 100644 --- a/examples/nextjs/pages/UseReactFlow/index.tsx +++ b/examples/nextjs/pages/UseReactFlow/index.tsx @@ -110,7 +110,7 @@ const UseZoomPanHelperFlow = () => { const logNodes = useCallback(() => { console.log('nodes', getNodes()); console.log('edges', getEdges()); - }, [getNodes]); + }, [getNodes, getEdges]); useEffect(() => { addEdges({ id: 'e3-4', source: '3', target: '4' }); diff --git a/examples/nextjs/pages/UseUpdateNodeInternals/CustomNode.tsx b/examples/nextjs/pages/UseUpdateNodeInternals/CustomNode.tsx index 38ee4af1..8e9a91d1 100644 --- a/examples/nextjs/pages/UseUpdateNodeInternals/CustomNode.tsx +++ b/examples/nextjs/pages/UseUpdateNodeInternals/CustomNode.tsx @@ -1,30 +1,33 @@ -import React, { memo, FC, useMemo, CSSProperties } from 'react'; -import { Handle, Position, NodeProps } from '@react-flow/bundle'; +import React, { useState, memo, FC, useMemo, CSSProperties } from 'react'; +import { Handle, Position, NodeProps, useUpdateNodeInternals } from '@react-flow/bundle'; const nodeStyles: CSSProperties = { padding: 10, border: '1px solid #ddd' }; -const CustomNode: FC = ({ data }) => { +const CustomNode: FC = ({ id }) => { + const [handleCount, setHandleCount] = useState(1); + const updateNodeInternals = useUpdateNodeInternals(); + const handles = useMemo( () => - Array.from({ length: data.handleCount }, (x, i) => { + Array.from({ length: handleCount }, (x, i) => { const handleId = `handle-${i}`; - return ( - - ); + return ; }), - [data.handleCount, data.handlePosition] + [handleCount] ); return (
-
output handle count: {data.handleCount}
+
output handle count: {handleCount}
+ {handles}
); diff --git a/examples/nextjs/pages/UseUpdateNodeInternals/index.tsx b/examples/nextjs/pages/UseUpdateNodeInternals/index.tsx index 2598665e..ac188a9c 100644 --- a/examples/nextjs/pages/UseUpdateNodeInternals/index.tsx +++ b/examples/nextjs/pages/UseUpdateNodeInternals/index.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, CSSProperties, MouseEvent } from 'react'; +import { useCallback, MouseEvent } from 'react'; import { ReactFlow, NodeTypes, @@ -8,7 +8,6 @@ import { Node, Connection, Edge, - useUpdateNodeInternals, Position, useNodesState, useEdgesState, @@ -16,28 +15,15 @@ import { import CustomNode from './CustomNode'; -const initialHandleCount = 1; - const initialNodes: Node[] = [ { id: '1', type: 'custom', - data: { - label: 'Node 1', - handleCount: initialHandleCount, - handlePosition: 0, - }, + data: { label: 'Node 1' }, position: { x: 250, y: 5 }, }, ]; -const buttonWrapperStyles: CSSProperties = { - position: 'absolute', - right: 10, - top: 10, - zIndex: 10, -}; - const nodeTypes: NodeTypes = { custom: CustomNode, }; @@ -50,7 +36,6 @@ const UpdateNodeInternalsFlow = () => { const [edges, setEdges, onEdgesChange] = useEdgesState([]); const onConnect = useCallback((params: Edge | Connection) => setEdges((els) => addEdge(params, els)), [setEdges]); - const updateNodeInternals = useUpdateNodeInternals(); const { project } = useReactFlow(); const onPaneClick = useCallback( @@ -67,36 +52,6 @@ const UpdateNodeInternalsFlow = () => { [project, setNodes] ); - const toggleHandleCount = useCallback(() => { - setNodes((nds) => - nds.map((node) => { - return { - ...node, - data: { - ...node.data, - handleCount: node.data?.handleCount === 1 ? 2 : 1, - }, - }; - }) - ); - }, [setNodes]); - - const toggleHandlePosition = useCallback(() => { - setNodes((nds) => - nds.map((node) => { - return { - ...node, - data: { - ...node.data, - handlePosition: node.data?.handlePosition === 0 ? 1 : 0, - }, - }; - }) - ); - }, [setNodes]); - - const updateNode = useCallback(() => updateNodeInternals('1'), [updateNodeInternals]); - return ( { nodeTypes={nodeTypes} onConnect={onConnect} onPaneClick={onPaneClick} - > -
- - - -
-
+ /> ); }; diff --git a/package.json b/package.json index 86c41241..af2b1f65 100644 --- a/package.json +++ b/package.json @@ -52,4 +52,4 @@ "packages/*" ] } -} +} \ No newline at end of file diff --git a/packages/core/src/hooks/useReactFlow.ts b/packages/core/src/hooks/useReactFlow.ts index 4e0efb81..ba826ddf 100644 --- a/packages/core/src/hooks/useReactFlow.ts +++ b/packages/core/src/hooks/useReactFlow.ts @@ -1,4 +1,4 @@ -import { useCallback } from 'react'; +import { useCallback, useMemo } from 'react'; import useViewportHelper from './useViewportHelper'; import { useStoreApi } from '../hooks/useStore'; @@ -15,7 +15,7 @@ import { /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ export default function useReactFlow(): ReactFlowInstance { - const { initialized: viewportInitialized, ...viewportHelperFunctions } = useViewportHelper(); + const viewportHelper = useViewportHelper(); const store = useStoreApi(); const getNodes = useCallback>(() => { @@ -111,17 +111,18 @@ export default function useReactFlow(): ReactFlo }; }, []); - return { - ...viewportHelperFunctions, - viewportInitialized, - getNodes, - getNode, - getEdges, - getEdge, - setNodes, - setEdges, - addNodes, - addEdges, - toObject, - }; + return useMemo(() => { + return { + ...viewportHelper, + getNodes, + getNode, + getEdges, + getEdge, + setNodes, + setEdges, + addNodes, + addEdges, + toObject, + }; + }, [viewportHelper, getNodes, getNode, getEdges, getEdge, setNodes, setEdges, addNodes, addEdges, toObject]); } diff --git a/packages/core/src/hooks/useUpdateNodeInternals.ts b/packages/core/src/hooks/useUpdateNodeInternals.ts index 8165eb77..bca6b416 100644 --- a/packages/core/src/hooks/useUpdateNodeInternals.ts +++ b/packages/core/src/hooks/useUpdateNodeInternals.ts @@ -10,15 +10,10 @@ function useUpdateNodeInternals(): UpdateNodeInternals { const updateNodeDimensions = useStore(selector); return useCallback((id: string) => { - const { domNode } = store.getState(); - if (!domNode) { - return; - } - - const nodeElement = domNode.querySelector(`.react-flow__node[data-id="${id}"]`) as HTMLDivElement; + const nodeElement = store.getState().domNode?.querySelector(`.react-flow__node[data-id="${id}"]`) as HTMLDivElement; if (nodeElement) { - updateNodeDimensions([{ id, nodeElement, forceUpdate: true }]); + requestAnimationFrame(() => updateNodeDimensions([{ id, nodeElement, forceUpdate: true }])); } }, []); } diff --git a/packages/core/src/hooks/useViewportHelper.ts b/packages/core/src/hooks/useViewportHelper.ts index 01520089..ea79f044 100644 --- a/packages/core/src/hooks/useViewportHelper.ts +++ b/packages/core/src/hooks/useViewportHelper.ts @@ -21,7 +21,7 @@ const initialViewportHelper: ViewportHelperFunctions = { setCenter: noop, fitBounds: noop, project: (position: XYPosition) => position, - initialized: false, + viewportInitialized: false, }; const selector = (s: ReactFlowState) => ({ @@ -72,7 +72,7 @@ const useViewportHelper = (): ViewportHelperFunctions => { const { transform, snapToGrid, snapGrid } = store.getState(); return pointToRendererPoint(position, transform, snapToGrid, snapGrid); }, - initialized: true, + viewportInitialized: true, }; } diff --git a/packages/core/src/types/general.ts b/packages/core/src/types/general.ts index 02c9bd8c..44097968 100644 --- a/packages/core/src/types/general.ts +++ b/packages/core/src/types/general.ts @@ -125,7 +125,7 @@ export interface ViewportHelperFunctions { setCenter: SetCenter; fitBounds: FitBounds; project: Project; - initialized: boolean; + viewportInitialized: boolean; } export type ReactFlowStore = {