diff --git a/.release-it.json b/.release-it.json index 93f9ec7b..2521416c 100644 --- a/.release-it.json +++ b/.release-it.json @@ -7,6 +7,6 @@ }, "hooks": { "after:bump": "npm run build", - "after:release": "echo Successfully released ${name} v${version} to ${repo.repository}." + "after:release": "echo Successfully released ${name} v${version}." } } diff --git a/example/.gitignore b/example/.gitignore index 4d29575d..43d022f7 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -21,3 +21,5 @@ npm-debug.log* yarn-debug.log* yarn-error.log* + +/src_oldapi \ No newline at end of file diff --git a/example/package-lock.json b/example/package-lock.json index 3560909a..520b9afe 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -27,7 +27,7 @@ }, "..": { "name": "react-flow-renderer", - "version": "9.6.7", + "version": "9.6.8", "license": "MIT", "dependencies": { "@babel/runtime": "^7.15.4", diff --git a/example/src/FloatingEdges/FloatingConnectionLine.tsx b/example/src/FloatingEdges/FloatingConnectionLine.tsx new file mode 100644 index 00000000..ef202589 --- /dev/null +++ b/example/src/FloatingEdges/FloatingConnectionLine.tsx @@ -0,0 +1,42 @@ +import { FC } from 'react'; +import { getBezierPath, ConnectionLineComponentProps, Node } from 'react-flow-renderer'; + +import { getEdgeParams } from './utils'; + +const FloatingConnectionLine: FC = ({ + targetX, + targetY, + sourcePosition, + targetPosition, + sourceNode, +}) => { + if (!sourceNode) { + return null; + } + + const targetNode = { + id: 'connection-target', + width: 1, + height: 1, + position: { x: targetX, y: targetY }, + } as Node; + + const { sx, sy } = getEdgeParams(sourceNode, targetNode); + const d = getBezierPath({ + sourceX: sx, + sourceY: sy, + sourcePosition, + targetPosition, + targetX, + targetY, + }); + + return ( + + + + + ); +}; + +export default FloatingConnectionLine; diff --git a/example/src/FloatingEdges/FloatingEdge.tsx b/example/src/FloatingEdges/FloatingEdge.tsx new file mode 100644 index 00000000..a163fcbe --- /dev/null +++ b/example/src/FloatingEdges/FloatingEdge.tsx @@ -0,0 +1,36 @@ +import { FC, useMemo, CSSProperties } from 'react'; +import { EdgeProps, useStore, getBezierPath, ReactFlowState } from 'react-flow-renderer'; + +import { getEdgeParams } from './utils'; + +const nodeSelector = (s: ReactFlowState) => s.nodes; + +const FloatingEdge: FC = ({ id, source, target, style }) => { + const nodes = useStore(nodeSelector); + + const sourceNode = useMemo(() => nodes.find((n) => n.id === source), [source, nodes]); + const targetNode = useMemo(() => nodes.find((n) => n.id === target), [target, nodes]); + + if (!sourceNode || !targetNode) { + return null; + } + + const { sx, sy, tx, ty, sourcePos, targetPos } = getEdgeParams(sourceNode, targetNode); + + const d = getBezierPath({ + sourceX: sx, + sourceY: sy, + sourcePosition: sourcePos, + targetPosition: targetPos, + targetX: tx, + targetY: ty, + }); + + return ( + + + + ); +}; + +export default FloatingEdge; diff --git a/example/src/FloatingEdges/index.tsx b/example/src/FloatingEdges/index.tsx new file mode 100644 index 00000000..8ec3ebc2 --- /dev/null +++ b/example/src/FloatingEdges/index.tsx @@ -0,0 +1,65 @@ +import { useState, useCallback } from 'react'; + +import ReactFlow, { + addEdge, + Background, + OnLoadParams, + EdgeTypesType, + Node, + Connection, + Edge, + applyNodeChanges, + applyEdgeChanges, + NodeChange, + EdgeChange, +} from 'react-flow-renderer'; + +import './style.css'; + +import FloatingEdge from './FloatingEdge'; +import FloatingConnectionLine from './FloatingConnectionLine'; +import { createElements } from './utils'; + +const onLoad = (reactFlowInstance: OnLoadParams) => reactFlowInstance.fitView(); + +const { nodes: initialNodes, edges: initialEdges } = createElements(); + +const edgeTypes: EdgeTypesType = { + floating: FloatingEdge, +}; + +const FloatingEdges = () => { + const [nodes, setNodes] = useState(initialNodes); + const [edges, setEdges] = useState(initialEdges); + + const onConnect = useCallback((params: Edge | Connection) => { + setEdges((eds) => addEdge(params, eds)); + }, []); + + const onNodesChange = useCallback((changes: NodeChange[]) => { + setNodes((ns) => applyNodeChanges(changes, ns)); + }, []); + + const onEdgesChange = useCallback((changes: EdgeChange[]) => { + setEdges((es) => applyEdgeChanges(changes, es)); + }, []); + + return ( +
+ + + +
+ ); +}; + +export default FloatingEdges; diff --git a/example/src/FloatingEdges/style.css b/example/src/FloatingEdges/style.css new file mode 100644 index 00000000..052fedb8 --- /dev/null +++ b/example/src/FloatingEdges/style.css @@ -0,0 +1,9 @@ +.floatingedges { + flex-direction: column; + display: flex; + height: 100%; +} + +.floatingedges .react-flow__handle { + opacity: 0; +} diff --git a/example/src/FloatingEdges/utils.ts b/example/src/FloatingEdges/utils.ts new file mode 100644 index 00000000..eb8797d2 --- /dev/null +++ b/example/src/FloatingEdges/utils.ts @@ -0,0 +1,106 @@ +import { Position, ArrowHeadType, XYPosition, Node, Edge } from 'react-flow-renderer'; + +// this helper function returns the intersection point +// of the line between the center of the intersectionNode and the target node +function getNodeIntersection(intersectionNode: Node, targetNode: Node): XYPosition { + // https://math.stackexchange.com/questions/1724792/an-algorithm-for-finding-the-intersection-point-between-a-center-of-vision-and-a + + const { + width: intersectionNodeWidth, + height: intersectionNodeHeight, + position: intersectionNodePosition, + } = intersectionNode; + const targetPosition = targetNode.position; + + const w = (intersectionNodeWidth ?? 0) / 2; + const h = (intersectionNodeHeight ?? 0) / 2; + + const x2 = intersectionNodePosition.x + w; + const y2 = intersectionNodePosition.y + h; + const x1 = targetPosition.x + w; + const y1 = targetPosition.y + h; + + const xx1 = (x1 - x2) / (2 * w) - (y1 - y2) / (2 * h); + const yy1 = (x1 - x2) / (2 * w) + (y1 - y2) / (2 * h); + const a = 1 / (Math.abs(xx1) + Math.abs(yy1)); + const xx3 = a * xx1; + const yy3 = a * yy1; + const x = w * (xx3 + yy3) + x2; + const y = h * (-xx3 + yy3) + y2; + + return { x, y }; +} + +// returns the position (top,right,bottom or right) passed node compared to the intersection point +function getEdgePosition(node: Node, intersectionPoint: XYPosition) { + const n = { ...node.position, ...node }; + const nx = Math.round(n.x); + const ny = Math.round(n.y); + const px = Math.round(intersectionPoint.x); + const py = Math.round(intersectionPoint.y); + + if (px <= nx + 1) { + return Position.Left; + } + if (px >= nx + (n.width ?? 0) - 1) { + return Position.Right; + } + if (py <= ny + 1) { + return Position.Top; + } + if (py >= n.y + (n.height ?? 0) - 1) { + return Position.Bottom; + } + + return Position.Top; +} + +// returns the parameters (sx, sy, tx, ty, sourcePos, targetPos) you need to create an edge +export function getEdgeParams(source: Node, target: Node) { + const sourceIntersectionPoint = getNodeIntersection(source, target); + const targetIntersectionPoint = getNodeIntersection(target, source); + + const sourcePos = getEdgePosition(source, sourceIntersectionPoint); + const targetPos = getEdgePosition(target, targetIntersectionPoint); + + return { + sx: sourceIntersectionPoint.x, + sy: sourceIntersectionPoint.y, + tx: targetIntersectionPoint.x, + ty: targetIntersectionPoint.y, + sourcePos, + targetPos, + }; +} + +type NodesAndEdges = { + nodes: Node[]; + edges: Edge[]; +}; + +export function createElements(): NodesAndEdges { + const nodes: Node[] = []; + const edges: Edge[] = []; + + const center = { x: window.innerWidth / 2, y: window.innerHeight / 2 }; + + nodes.push({ id: 'target', data: { label: 'Target' }, position: center }); + + for (let i = 0; i < 8; i++) { + const degrees = i * (360 / 8); + const radians = degrees * (Math.PI / 180); + const x = 250 * Math.cos(radians) + center.x; + const y = 250 * Math.sin(radians) + center.y; + + nodes.push({ id: `${i}`, data: { label: 'Source' }, position: { x, y } }); + + edges.push({ + id: `edge-${i}`, + target: 'target', + source: `${i}`, + type: 'floating', + }); + } + + return { nodes, edges }; +} diff --git a/example/src/index.tsx b/example/src/index.tsx index 6e08eabd..60faf4c0 100644 --- a/example/src/index.tsx +++ b/example/src/index.tsx @@ -6,6 +6,7 @@ import Basic from './Basic'; import UpdateNode from './UpdateNode'; import Stress from './Stress'; import CustomNode from './CustomNode'; +import FloatingEdges from './FloatingEdges'; import './index.css'; @@ -26,6 +27,10 @@ const routes = [ path: '/custom-node', component: CustomNode, }, + { + path: '/floating-edges', + component: FloatingEdges, + }, ]; const Header = withRouter(({ history, location }) => { diff --git a/example/src_oldapi/Edges/CustomEdge.tsx b/example/src_oldapi/Edges/CustomEdge.tsx index f72ff831..9a3c4230 100644 --- a/example/src_oldapi/Edges/CustomEdge.tsx +++ b/example/src_oldapi/Edges/CustomEdge.tsx @@ -1,5 +1,5 @@ import { FC } from 'react'; -import { EdgeProps, getBezierPath, getMarkerEnd } from 'react-flow-renderer'; +import { EdgeProps, getBezierPath } from 'react-flow-renderer'; const CustomEdge: FC = ({ id, @@ -10,15 +10,12 @@ const CustomEdge: FC = ({ sourcePosition, targetPosition, data, - arrowHeadType, - markerEndId, }) => { const edgePath = getBezierPath({ sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition }); - const markerEnd = getMarkerEnd(arrowHeadType, markerEndId); return ( <> - + {data.text} diff --git a/example/src_oldapi/Edges/CustomEdge2.tsx b/example/src_oldapi/Edges/CustomEdge2.tsx index 361b7f92..63b010a9 100644 --- a/example/src_oldapi/Edges/CustomEdge2.tsx +++ b/example/src_oldapi/Edges/CustomEdge2.tsx @@ -1,5 +1,5 @@ import { FC } from 'react'; -import { EdgeProps, getBezierPath, getMarkerEnd, EdgeText, getEdgeCenter } from 'react-flow-renderer'; +import { EdgeProps, getBezierPath, EdgeText, getEdgeCenter } from 'react-flow-renderer'; const CustomEdge: FC = ({ id, @@ -10,11 +10,8 @@ const CustomEdge: FC = ({ sourcePosition, targetPosition, data, - arrowHeadType, - markerEndId, }) => { const edgePath = getBezierPath({ sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition }); - const markerEnd = getMarkerEnd(arrowHeadType, markerEndId); const [centerX, centerY] = getEdgeCenter({ sourceX, sourceY, @@ -24,7 +21,7 @@ const CustomEdge: FC = ({ return ( <> - + ), labelStyle: { fill: 'red', fontWeight: 700 }, - arrowHeadType: ArrowHeadType.Arrow, - }, - { - id: 'e5-7', - source: '5', - target: '7', - label: 'label with styled bg', - labelBgPadding: [8, 4], - labelBgBorderRadius: 4, - labelBgStyle: { fill: '#FFCC00', color: '#fff', fillOpacity: 0.7 }, - arrowHeadType: ArrowHeadType.ArrowClosed, - }, - { - id: 'e5-8', - source: '5', - target: '8', - type: 'custom', - data: { text: 'custom edge' }, - arrowHeadType: ArrowHeadType.ArrowClosed, - }, - { - id: 'e5-9', - source: '5', - target: '9', - type: 'custom2', - data: { text: 'custom edge 2' }, + style: { stroke: '#ffcc00' }, + markerEnd: { + type: ArrowHeadType.Arrow, + color: '#FFCC00', + units: 'userSpaceOnUse', + width: 20, + height: 20, + strokeWidth: 2, + }, + markerStart: { + type: ArrowHeadType.ArrowClosed, + color: '#FFCC00', + orient: 'auto-start-reverse', + units: 'userSpaceOnUse', + width: 20, + height: 20, + }, }, ]; diff --git a/example/src_oldapi/Overview/index.tsx b/example/src_oldapi/Overview/index.tsx index ee13f916..17e0c9b5 100644 --- a/example/src_oldapi/Overview/index.tsx +++ b/example/src_oldapi/Overview/index.tsx @@ -13,7 +13,6 @@ import ReactFlow, { OnLoadParams, FlowTransform, SnapGrid, - ArrowHeadType, Connection, Edge, } from 'react-flow-renderer'; @@ -125,7 +124,7 @@ const initialElements: Elements = [ { id: 'e1-2', source: '1', target: '2', label: 'this is an edge label' }, { id: 'e1-3', source: '1', target: '3' }, { id: 'e3-4', source: '3', target: '4', animated: true, label: 'animated edge' }, - { id: 'e4-5', source: '4', target: '5', arrowHeadType: ArrowHeadType.Arrow, label: 'edge with arrow head' }, + { id: 'e4-5', source: '4', target: '5', label: 'edge with arrow head' }, { id: 'e5-6', source: '5', target: '6', type: 'smoothstep', label: 'smooth step edge' }, { id: 'e5-7', diff --git a/example/src_oldapi/Undirectional/index.tsx b/example/src_oldapi/Undirectional/index.tsx index f05ad21e..7687f4b0 100644 --- a/example/src_oldapi/Undirectional/index.tsx +++ b/example/src_oldapi/Undirectional/index.tsx @@ -12,7 +12,6 @@ import ReactFlow, { ConnectionLineType, ConnectionMode, updateEdge, - ArrowHeadType, } from 'react-flow-renderer'; import CustomNode from './CustomNode'; @@ -68,8 +67,7 @@ const initialElements: Elements = [ target: '01', sourceHandle: 'left', targetHandle: 'bottom', - type: 'smoothstep', - arrowHeadType: ArrowHeadType.Arrow, + type: 'default', }, { id: 'e0-1b', @@ -77,8 +75,7 @@ const initialElements: Elements = [ target: '01', sourceHandle: 'top', targetHandle: 'right', - type: 'smoothstep', - arrowHeadType: ArrowHeadType.Arrow, + type: 'default', }, { id: 'e0-2a', @@ -86,8 +83,7 @@ const initialElements: Elements = [ target: '02', sourceHandle: 'top', targetHandle: 'left', - type: 'smoothstep', - arrowHeadType: ArrowHeadType.Arrow, + type: 'default', }, { id: 'e0-2b', @@ -95,8 +91,7 @@ const initialElements: Elements = [ target: '02', sourceHandle: 'right', targetHandle: 'bottom', - type: 'smoothstep', - arrowHeadType: ArrowHeadType.Arrow, + type: 'default', }, { id: 'e0-3a', @@ -104,8 +99,7 @@ const initialElements: Elements = [ target: '03', sourceHandle: 'right', targetHandle: 'top', - type: 'smoothstep', - arrowHeadType: ArrowHeadType.Arrow, + type: 'default', }, { id: 'e0-3b', @@ -113,8 +107,7 @@ const initialElements: Elements = [ target: '03', sourceHandle: 'bottom', targetHandle: 'left', - type: 'smoothstep', - arrowHeadType: ArrowHeadType.Arrow, + type: 'default', }, { id: 'e0-4a', @@ -122,8 +115,7 @@ const initialElements: Elements = [ target: '04', sourceHandle: 'bottom', targetHandle: 'right', - type: 'smoothstep', - arrowHeadType: ArrowHeadType.Arrow, + type: 'default', }, { id: 'e0-4b', @@ -131,8 +123,7 @@ const initialElements: Elements = [ target: '04', sourceHandle: 'left', targetHandle: 'top', - type: 'smoothstep', - arrowHeadType: ArrowHeadType.Arrow, + type: 'default', }, { id: 'e0-10', @@ -140,8 +131,7 @@ const initialElements: Elements = [ target: '10', sourceHandle: 'top', targetHandle: 'bottom', - type: 'smoothstep', - arrowHeadType: ArrowHeadType.Arrow, + type: 'default', }, { id: 'e0-20', @@ -149,8 +139,7 @@ const initialElements: Elements = [ target: '20', sourceHandle: 'right', targetHandle: 'left', - type: 'smoothstep', - arrowHeadType: ArrowHeadType.Arrow, + type: 'default', }, { id: 'e0-30', @@ -158,8 +147,7 @@ const initialElements: Elements = [ target: '30', sourceHandle: 'bottom', targetHandle: 'top', - type: 'smoothstep', - arrowHeadType: ArrowHeadType.Arrow, + type: 'default', }, { id: 'e0-40', @@ -167,8 +155,7 @@ const initialElements: Elements = [ target: '40', sourceHandle: 'left', targetHandle: 'right', - type: 'smoothstep', - arrowHeadType: ArrowHeadType.Arrow, + type: 'default', }, ]; @@ -181,8 +168,7 @@ const getId = (): ElementId => `${id++}`; const UpdateNodeInternalsFlow = () => { const [elements, setElements] = useState(initialElements); - const onConnect = (params: Connection | Edge) => - setElements((els) => addEdge({ ...params, type: 'smoothstep' }, els)); + const onConnect = (params: Connection | Edge) => setElements((els) => addEdge({ ...params, type: 'default' }, els)); const { project } = useZoomPanHelper(); const onEdgeUpdate = (oldEdge: Edge, newConnection: Connection) => setElements((els) => updateEdge(oldEdge, newConnection, els)); diff --git a/package-lock.json b/package-lock.json index 76eefe19..f4030c88 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,17 @@ { "name": "react-flow-renderer", - "version": "9.6.8", + "version": "10.0.0-next.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "react-flow-renderer", - "version": "9.6.8", + "version": "10.0.0-next.2", "license": "MIT", "dependencies": { "@babel/runtime": "^7.15.4", "@types/d3": "^7.0.0", - "@types/react-redux": "^7.1.18", + "@types/react-redux": "^7.1.19", "classcat": "^5.0.3", "d3-selection": "^3.0.0", "d3-zoom": "^3.0.0", @@ -22,9 +22,9 @@ "zustand": "^3.5.13" }, "devDependencies": { - "@babel/core": "^7.15.5", - "@babel/plugin-transform-runtime": "^7.15.0", - "@babel/preset-env": "^7.15.6", + "@babel/core": "^7.15.8", + "@babel/plugin-transform-runtime": "^7.15.8", + "@babel/preset-env": "^7.15.8", "@babel/preset-react": "^7.14.5", "@rollup/plugin-babel": "^5.3.0", "@rollup/plugin-commonjs": "^21.0.0", @@ -37,7 +37,7 @@ "autoprefixer": "^10.3.6", "babel-preset-react-app": "^10.0.0", "cypress": "^8.5.0", - "postcss": "^8.3.8", + "postcss": "^8.3.9", "postcss-cli": "^9.0.1", "postcss-nested": "^5.0.6", "prettier": "2.4.1", @@ -63,9 +63,9 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", + "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", "dev": true, "dependencies": { "@babel/highlight": "^7.14.5" @@ -84,20 +84,20 @@ } }, "node_modules/@babel/core": { - "version": "7.15.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.5.tgz", - "integrity": "sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.8.tgz", + "integrity": "sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", + "@babel/code-frame": "^7.15.8", + "@babel/generator": "^7.15.8", "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-module-transforms": "^7.15.4", + "@babel/helper-module-transforms": "^7.15.8", "@babel/helpers": "^7.15.4", - "@babel/parser": "^7.15.5", + "@babel/parser": "^7.15.8", "@babel/template": "^7.15.4", "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4", + "@babel/types": "^7.15.6", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -114,12 +114,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.4.tgz", - "integrity": "sha512-d3itta0tu+UayjEORPNz6e1T3FtvWlP5N4V5M+lhp/CxT4oAA7/NcScnpRyspUMLK6tu9MNHmQHxRykuN2R7hw==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", + "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", "dev": true, "dependencies": { - "@babel/types": "^7.15.4", + "@babel/types": "^7.15.6", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, @@ -300,19 +300,19 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.4.tgz", - "integrity": "sha512-9fHHSGE9zTC++KuXLZcB5FKgvlV83Ox+NLUmQTawovwlJ85+QMhk1CnVk406CQVj97LaWod6KVjl2Sfgw9Aktw==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz", + "integrity": "sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==", "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.15.4", "@babel/helper-replace-supers": "^7.15.4", "@babel/helper-simple-access": "^7.15.4", "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-validator-identifier": "^7.15.7", "@babel/template": "^7.15.4", "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/types": "^7.15.6" }, "engines": { "node": ">=6.9.0" @@ -405,9 +405,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", "dev": true, "engines": { "node": ">=6.9.0" @@ -466,9 +466,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.6.tgz", - "integrity": "sha512-S/TSCcsRuCkmpUuoWijua0Snt+f3ewU/8spLo+4AXJCZfT0bVCzLD5MuOKdrx0mlAptbKzn5AdgEIIKXxXkz9Q==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", + "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -495,9 +495,9 @@ } }, "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.4.tgz", - "integrity": "sha512-2zt2g5vTXpMC3OmK6uyjvdXptbhBXfA77XGrd3gh93zwG8lZYBLOBImiGBEG0RANu3JqKEACCz5CGk73OJROBw==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.8.tgz", + "integrity": "sha512-2Z5F2R2ibINTc63mY7FLqGfEbmofrHU9FitJW1Q7aPaKFhiPvSq6QEt/BoWN5oME3GVyjcRuNNSRbb9LC0CSWA==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5", @@ -1514,15 +1514,15 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.15.0.tgz", - "integrity": "sha512-sfHYkLGjhzWTq6xsuQ01oEsUYjkHRux9fW1iUA68dC7Qd8BS1Unq4aZ8itmQp95zUzIcyR2EbNMTzAicFj+guw==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.15.8.tgz", + "integrity": "sha512-+6zsde91jMzzvkzuEA3k63zCw+tm/GvuuabkpisgbDMTPQsIMHllE3XczJFFtEHLjjhKQFZmGQVRdELetlWpVw==", "dev": true, "dependencies": { - "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-module-imports": "^7.15.4", "@babel/helper-plugin-utils": "^7.14.5", "babel-plugin-polyfill-corejs2": "^0.2.2", - "babel-plugin-polyfill-corejs3": "^0.2.2", + "babel-plugin-polyfill-corejs3": "^0.2.5", "babel-plugin-polyfill-regenerator": "^0.2.2", "semver": "^6.3.0" }, @@ -1549,13 +1549,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz", - "integrity": "sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.15.8.tgz", + "integrity": "sha512-/daZ8s2tNaRekl9YJa9X4bzjpeRZLt122cpgFnQPLGUe61PH8zMEBmYqKkW5xF5JUEh5buEGXJoQpqBmIbpmEQ==", "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers": "^7.15.4" }, "engines": { "node": ">=6.9.0" @@ -1658,9 +1658,9 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.15.6.tgz", - "integrity": "sha512-L+6jcGn7EWu7zqaO2uoTDjjMBW+88FXzV8KvrBl2z6MtRNxlsmUNRlZPaNNPUTgqhyC5DHNFk/2Jmra+ublZWw==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.15.8.tgz", + "integrity": "sha512-rCC0wH8husJgY4FPbHsiYyiLxSY8oMDJH7Rl6RQMknbN9oDDHhM9RDFvnGM2MgkbUJzSQB4gtuwygY5mCqGSsA==", "dev": true, "dependencies": { "@babel/compat-data": "^7.15.0", @@ -1668,7 +1668,7 @@ "@babel/helper-plugin-utils": "^7.14.5", "@babel/helper-validator-option": "^7.14.5", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.15.4", - "@babel/plugin-proposal-async-generator-functions": "^7.15.4", + "@babel/plugin-proposal-async-generator-functions": "^7.15.8", "@babel/plugin-proposal-class-properties": "^7.14.5", "@babel/plugin-proposal-class-static-block": "^7.15.4", "@babel/plugin-proposal-dynamic-import": "^7.14.5", @@ -1723,7 +1723,7 @@ "@babel/plugin-transform-regenerator": "^7.14.5", "@babel/plugin-transform-reserved-words": "^7.14.5", "@babel/plugin-transform-shorthand-properties": "^7.14.5", - "@babel/plugin-transform-spread": "^7.14.6", + "@babel/plugin-transform-spread": "^7.15.8", "@babel/plugin-transform-sticky-regex": "^7.14.5", "@babel/plugin-transform-template-literals": "^7.14.5", "@babel/plugin-transform-typeof-symbol": "^7.14.5", @@ -1732,7 +1732,7 @@ "@babel/preset-modules": "^0.1.4", "@babel/types": "^7.15.6", "babel-plugin-polyfill-corejs2": "^0.2.2", - "babel-plugin-polyfill-corejs3": "^0.2.2", + "babel-plugin-polyfill-corejs3": "^0.2.5", "babel-plugin-polyfill-regenerator": "^0.2.2", "core-js-compat": "^3.16.0", "semver": "^6.3.0" @@ -2771,9 +2771,9 @@ } }, "node_modules/@types/react-redux": { - "version": "7.1.18", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.18.tgz", - "integrity": "sha512-9iwAsPyJ9DLTRH+OFeIrm9cAbIj1i2ANL3sKQFATqnPWRbg+jEFXyZOKHiQK/N86pNRXbb4HRxAxo0SIX1XwzQ==", + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.19.tgz", + "integrity": "sha512-L37dSCT0aoJnCgpR8Iuginlbxoh7qhWOXiaDqEsxVMrER1CmVhFD+63NxgJeT4pkmEM28oX0NH4S4f+sXHTZjA==", "dependencies": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", @@ -3098,16 +3098,16 @@ } }, "node_modules/autoprefixer": { - "version": "10.3.6", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.3.6.tgz", - "integrity": "sha512-3bDjTfF0MfZntwVCSd18XAT2Zndufh3Mep+mafbzdIQEeWbncVRUVDjH8/EPANV9Hq40seJ24QcYAyhUsFz7gQ==", + "version": "10.3.7", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.3.7.tgz", + "integrity": "sha512-EmGpu0nnQVmMhX8ROoJ7Mx8mKYPlcUHuxkwrRYEYMz85lu7H09v8w6R1P0JPdn/hKU32GjpLBFEOuIlDWCRWvg==", "dev": true, "dependencies": { - "browserslist": "^4.17.1", - "caniuse-lite": "^1.0.30001260", + "browserslist": "^4.17.3", + "caniuse-lite": "^1.0.30001264", "fraction.js": "^4.1.1", - "nanocolors": "^0.2.8", "normalize-range": "^0.1.2", + "picocolors": "^0.2.1", "postcss-value-parser": "^4.1.0" }, "bin": { @@ -3199,13 +3199,13 @@ } }, "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.3.tgz", - "integrity": "sha512-rCOFzEIJpJEAU14XCcV/erIf/wZQMmMT5l5vXOpL5uoznyOGfDIjPj6FVytMvtzaKSTSVKouOCTPJ5OMUZH30g==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.5.tgz", + "integrity": "sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw==", "dev": true, "dependencies": { "@babel/helper-define-polyfill-provider": "^0.2.2", - "core-js-compat": "^3.14.0" + "core-js-compat": "^3.16.2" }, "peerDependencies": { "@babel/core": "^7.0.0-0" @@ -3691,16 +3691,16 @@ } }, "node_modules/browserslist": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.1.tgz", - "integrity": "sha512-aLD0ZMDSnF4lUt4ZDNgqi5BUn9BZ7YdQdI/cYlILrhdSSZJLU9aNZoD5/NBmM4SK34APB2e83MOsRt1EnkuyaQ==", + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.3.tgz", + "integrity": "sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ==", "dev": true, "dependencies": { - "caniuse-lite": "^1.0.30001259", - "electron-to-chromium": "^1.3.846", + "caniuse-lite": "^1.0.30001264", + "electron-to-chromium": "^1.3.857", "escalade": "^3.1.1", - "nanocolors": "^0.1.5", - "node-releases": "^1.1.76" + "node-releases": "^1.1.77", + "picocolors": "^0.2.1" }, "bin": { "browserslist": "cli.js" @@ -3713,12 +3713,6 @@ "url": "https://opencollective.com/browserslist" } }, - "node_modules/browserslist/node_modules/nanocolors": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/nanocolors/-/nanocolors-0.1.12.tgz", - "integrity": "sha512-2nMHqg1x5PU+unxX7PGY7AuYxl2qDx7PSrTRjizr8sxdd3l/3hBuWWaki62qmtYm2U5i4Z5E7GbjlyDFhs9/EQ==", - "dev": true - }, "node_modules/buffer": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", @@ -3847,24 +3841,15 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001260", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001260.tgz", - "integrity": "sha512-Fhjc/k8725ItmrvW5QomzxLeojewxvqiYCKeFcfFEhut28IVLdpHU19dneOmltZQIE5HNbawj1HYD+1f2bM1Dg==", + "version": "1.0.30001265", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz", + "integrity": "sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw==", "dev": true, - "dependencies": { - "nanocolors": "^0.1.0" - }, "funding": { "type": "opencollective", "url": "https://opencollective.com/browserslist" } }, - "node_modules/caniuse-lite/node_modules/nanocolors": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/nanocolors/-/nanocolors-0.1.12.tgz", - "integrity": "sha512-2nMHqg1x5PU+unxX7PGY7AuYxl2qDx7PSrTRjizr8sxdd3l/3hBuWWaki62qmtYm2U5i4Z5E7GbjlyDFhs9/EQ==", - "dev": true - }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -4997,9 +4982,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.3.850", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.850.tgz", - "integrity": "sha512-ZzkDcdzePeF4dhoGZQT77V2CyJOpwfTZEOg4h0x6R/jQhGt/rIRpbRyVreWLtD7B/WsVxo91URm2WxMKR9JQZA==", + "version": "1.3.864", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.864.tgz", + "integrity": "sha512-v4rbad8GO6/yVI92WOeU9Wgxc4NA0n4f6P1FvZTY+jyY7JHEhw3bduYu60v3Q1h81Cg6eo4ApZrFPuycwd5hGw==", "dev": true }, "node_modules/emoji-regex": { @@ -7325,9 +7310,9 @@ } }, "node_modules/node-releases": { - "version": "1.1.76", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.76.tgz", - "integrity": "sha512-9/IECtNr8dXNmPWmFXepT0/7o5eolGesHUa3mtr0KlgnCvnZxwh2qensKL42JJY2vQKC3nIBXetFAqR+PW1CmA==", + "version": "1.1.77", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", + "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==", "dev": true }, "node_modules/normalize-path": { @@ -8015,6 +8000,12 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, + "node_modules/picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true + }, "node_modules/picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", @@ -8101,13 +8092,13 @@ } }, "node_modules/postcss": { - "version": "8.3.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.8.tgz", - "integrity": "sha512-GT5bTjjZnwDifajzczOC+r3FI3Cu+PgPvrsjhQdRqa2kTJ4968/X9CUce9xttIB0xOs5c6xf0TCWZo/y9lF6bA==", + "version": "8.3.9", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.9.tgz", + "integrity": "sha512-f/ZFyAKh9Dnqytx5X62jgjhhzttjZS7hMsohcI7HEI5tjELX/HxCy3EFhsRxyzGvrzFF+82XPvCS8T9TFleVJw==", "dev": true, "dependencies": { - "nanocolors": "^0.2.2", - "nanoid": "^3.1.25", + "nanoid": "^3.1.28", + "picocolors": "^0.2.1", "source-map-js": "^0.6.2" }, "engines": { @@ -11278,9 +11269,9 @@ }, "dependencies": { "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", + "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", "dev": true, "requires": { "@babel/highlight": "^7.14.5" @@ -11293,20 +11284,20 @@ "dev": true }, "@babel/core": { - "version": "7.15.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.5.tgz", - "integrity": "sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.8.tgz", + "integrity": "sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og==", "dev": true, "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", + "@babel/code-frame": "^7.15.8", + "@babel/generator": "^7.15.8", "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-module-transforms": "^7.15.4", + "@babel/helper-module-transforms": "^7.15.8", "@babel/helpers": "^7.15.4", - "@babel/parser": "^7.15.5", + "@babel/parser": "^7.15.8", "@babel/template": "^7.15.4", "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4", + "@babel/types": "^7.15.6", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -11316,12 +11307,12 @@ } }, "@babel/generator": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.4.tgz", - "integrity": "sha512-d3itta0tu+UayjEORPNz6e1T3FtvWlP5N4V5M+lhp/CxT4oAA7/NcScnpRyspUMLK6tu9MNHmQHxRykuN2R7hw==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", + "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", "dev": true, "requires": { - "@babel/types": "^7.15.4", + "@babel/types": "^7.15.6", "jsesc": "^2.5.1", "source-map": "^0.5.0" } @@ -11454,19 +11445,19 @@ } }, "@babel/helper-module-transforms": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.4.tgz", - "integrity": "sha512-9fHHSGE9zTC++KuXLZcB5FKgvlV83Ox+NLUmQTawovwlJ85+QMhk1CnVk406CQVj97LaWod6KVjl2Sfgw9Aktw==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz", + "integrity": "sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==", "dev": true, "requires": { "@babel/helper-module-imports": "^7.15.4", "@babel/helper-replace-supers": "^7.15.4", "@babel/helper-simple-access": "^7.15.4", "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-validator-identifier": "^7.15.7", "@babel/template": "^7.15.4", "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/types": "^7.15.6" } }, "@babel/helper-optimise-call-expression": { @@ -11535,9 +11526,9 @@ } }, "@babel/helper-validator-identifier": { - "version": "7.14.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", "dev": true }, "@babel/helper-validator-option": { @@ -11581,9 +11572,9 @@ } }, "@babel/parser": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.6.tgz", - "integrity": "sha512-S/TSCcsRuCkmpUuoWijua0Snt+f3ewU/8spLo+4AXJCZfT0bVCzLD5MuOKdrx0mlAptbKzn5AdgEIIKXxXkz9Q==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", + "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", "dev": true }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { @@ -11598,9 +11589,9 @@ } }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.4.tgz", - "integrity": "sha512-2zt2g5vTXpMC3OmK6uyjvdXptbhBXfA77XGrd3gh93zwG8lZYBLOBImiGBEG0RANu3JqKEACCz5CGk73OJROBw==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.8.tgz", + "integrity": "sha512-2Z5F2R2ibINTc63mY7FLqGfEbmofrHU9FitJW1Q7aPaKFhiPvSq6QEt/BoWN5oME3GVyjcRuNNSRbb9LC0CSWA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.14.5", @@ -12254,15 +12245,15 @@ } }, "@babel/plugin-transform-runtime": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.15.0.tgz", - "integrity": "sha512-sfHYkLGjhzWTq6xsuQ01oEsUYjkHRux9fW1iUA68dC7Qd8BS1Unq4aZ8itmQp95zUzIcyR2EbNMTzAicFj+guw==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.15.8.tgz", + "integrity": "sha512-+6zsde91jMzzvkzuEA3k63zCw+tm/GvuuabkpisgbDMTPQsIMHllE3XczJFFtEHLjjhKQFZmGQVRdELetlWpVw==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-module-imports": "^7.15.4", "@babel/helper-plugin-utils": "^7.14.5", "babel-plugin-polyfill-corejs2": "^0.2.2", - "babel-plugin-polyfill-corejs3": "^0.2.2", + "babel-plugin-polyfill-corejs3": "^0.2.5", "babel-plugin-polyfill-regenerator": "^0.2.2", "semver": "^6.3.0" } @@ -12277,13 +12268,13 @@ } }, "@babel/plugin-transform-spread": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.14.6.tgz", - "integrity": "sha512-Zr0x0YroFJku7n7+/HH3A2eIrGMjbmAIbJSVv0IZ+t3U2WUQUA64S/oeied2e+MaGSjmt4alzBCsK9E8gh+fag==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.15.8.tgz", + "integrity": "sha512-/daZ8s2tNaRekl9YJa9X4bzjpeRZLt122cpgFnQPLGUe61PH8zMEBmYqKkW5xF5JUEh5buEGXJoQpqBmIbpmEQ==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.14.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5" + "@babel/helper-skip-transparent-expression-wrappers": "^7.15.4" } }, "@babel/plugin-transform-sticky-regex": { @@ -12344,9 +12335,9 @@ } }, "@babel/preset-env": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.15.6.tgz", - "integrity": "sha512-L+6jcGn7EWu7zqaO2uoTDjjMBW+88FXzV8KvrBl2z6MtRNxlsmUNRlZPaNNPUTgqhyC5DHNFk/2Jmra+ublZWw==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.15.8.tgz", + "integrity": "sha512-rCC0wH8husJgY4FPbHsiYyiLxSY8oMDJH7Rl6RQMknbN9oDDHhM9RDFvnGM2MgkbUJzSQB4gtuwygY5mCqGSsA==", "dev": true, "requires": { "@babel/compat-data": "^7.15.0", @@ -12354,7 +12345,7 @@ "@babel/helper-plugin-utils": "^7.14.5", "@babel/helper-validator-option": "^7.14.5", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.15.4", - "@babel/plugin-proposal-async-generator-functions": "^7.15.4", + "@babel/plugin-proposal-async-generator-functions": "^7.15.8", "@babel/plugin-proposal-class-properties": "^7.14.5", "@babel/plugin-proposal-class-static-block": "^7.15.4", "@babel/plugin-proposal-dynamic-import": "^7.14.5", @@ -12409,7 +12400,7 @@ "@babel/plugin-transform-regenerator": "^7.14.5", "@babel/plugin-transform-reserved-words": "^7.14.5", "@babel/plugin-transform-shorthand-properties": "^7.14.5", - "@babel/plugin-transform-spread": "^7.14.6", + "@babel/plugin-transform-spread": "^7.15.8", "@babel/plugin-transform-sticky-regex": "^7.14.5", "@babel/plugin-transform-template-literals": "^7.14.5", "@babel/plugin-transform-typeof-symbol": "^7.14.5", @@ -12418,7 +12409,7 @@ "@babel/preset-modules": "^0.1.4", "@babel/types": "^7.15.6", "babel-plugin-polyfill-corejs2": "^0.2.2", - "babel-plugin-polyfill-corejs3": "^0.2.2", + "babel-plugin-polyfill-corejs3": "^0.2.5", "babel-plugin-polyfill-regenerator": "^0.2.2", "core-js-compat": "^3.16.0", "semver": "^6.3.0" @@ -13268,9 +13259,9 @@ } }, "@types/react-redux": { - "version": "7.1.18", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.18.tgz", - "integrity": "sha512-9iwAsPyJ9DLTRH+OFeIrm9cAbIj1i2ANL3sKQFATqnPWRbg+jEFXyZOKHiQK/N86pNRXbb4HRxAxo0SIX1XwzQ==", + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.19.tgz", + "integrity": "sha512-L37dSCT0aoJnCgpR8Iuginlbxoh7qhWOXiaDqEsxVMrER1CmVhFD+63NxgJeT4pkmEM28oX0NH4S4f+sXHTZjA==", "requires": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", @@ -13531,16 +13522,16 @@ "dev": true }, "autoprefixer": { - "version": "10.3.6", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.3.6.tgz", - "integrity": "sha512-3bDjTfF0MfZntwVCSd18XAT2Zndufh3Mep+mafbzdIQEeWbncVRUVDjH8/EPANV9Hq40seJ24QcYAyhUsFz7gQ==", + "version": "10.3.7", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.3.7.tgz", + "integrity": "sha512-EmGpu0nnQVmMhX8ROoJ7Mx8mKYPlcUHuxkwrRYEYMz85lu7H09v8w6R1P0JPdn/hKU32GjpLBFEOuIlDWCRWvg==", "dev": true, "requires": { - "browserslist": "^4.17.1", - "caniuse-lite": "^1.0.30001260", + "browserslist": "^4.17.3", + "caniuse-lite": "^1.0.30001264", "fraction.js": "^4.1.1", - "nanocolors": "^0.2.8", "normalize-range": "^0.1.2", + "picocolors": "^0.2.1", "postcss-value-parser": "^4.1.0" } }, @@ -13612,13 +13603,13 @@ } }, "babel-plugin-polyfill-corejs3": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.3.tgz", - "integrity": "sha512-rCOFzEIJpJEAU14XCcV/erIf/wZQMmMT5l5vXOpL5uoznyOGfDIjPj6FVytMvtzaKSTSVKouOCTPJ5OMUZH30g==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.5.tgz", + "integrity": "sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw==", "dev": true, "requires": { "@babel/helper-define-polyfill-provider": "^0.2.2", - "core-js-compat": "^3.14.0" + "core-js-compat": "^3.16.2" } }, "babel-plugin-polyfill-regenerator": { @@ -14012,24 +14003,16 @@ } }, "browserslist": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.1.tgz", - "integrity": "sha512-aLD0ZMDSnF4lUt4ZDNgqi5BUn9BZ7YdQdI/cYlILrhdSSZJLU9aNZoD5/NBmM4SK34APB2e83MOsRt1EnkuyaQ==", + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.3.tgz", + "integrity": "sha512-59IqHJV5VGdcJZ+GZ2hU5n4Kv3YiASzW6Xk5g9tf5a/MAzGeFwgGWU39fVzNIOVcgB3+Gp+kiQu0HEfTVU/3VQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001259", - "electron-to-chromium": "^1.3.846", + "caniuse-lite": "^1.0.30001264", + "electron-to-chromium": "^1.3.857", "escalade": "^3.1.1", - "nanocolors": "^0.1.5", - "node-releases": "^1.1.76" - }, - "dependencies": { - "nanocolors": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/nanocolors/-/nanocolors-0.1.12.tgz", - "integrity": "sha512-2nMHqg1x5PU+unxX7PGY7AuYxl2qDx7PSrTRjizr8sxdd3l/3hBuWWaki62qmtYm2U5i4Z5E7GbjlyDFhs9/EQ==", - "dev": true - } + "node-releases": "^1.1.77", + "picocolors": "^0.2.1" } }, "buffer": { @@ -14116,21 +14099,10 @@ } }, "caniuse-lite": { - "version": "1.0.30001260", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001260.tgz", - "integrity": "sha512-Fhjc/k8725ItmrvW5QomzxLeojewxvqiYCKeFcfFEhut28IVLdpHU19dneOmltZQIE5HNbawj1HYD+1f2bM1Dg==", - "dev": true, - "requires": { - "nanocolors": "^0.1.0" - }, - "dependencies": { - "nanocolors": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/nanocolors/-/nanocolors-0.1.12.tgz", - "integrity": "sha512-2nMHqg1x5PU+unxX7PGY7AuYxl2qDx7PSrTRjizr8sxdd3l/3hBuWWaki62qmtYm2U5i4Z5E7GbjlyDFhs9/EQ==", - "dev": true - } - } + "version": "1.0.30001265", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001265.tgz", + "integrity": "sha512-YzBnspggWV5hep1m9Z6sZVLOt7vrju8xWooFAgN6BA5qvy98qPAPb7vNUzypFaoh2pb3vlfzbDO8tB57UPGbtw==", + "dev": true }, "caseless": { "version": "0.12.0", @@ -14997,9 +14969,9 @@ } }, "electron-to-chromium": { - "version": "1.3.850", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.850.tgz", - "integrity": "sha512-ZzkDcdzePeF4dhoGZQT77V2CyJOpwfTZEOg4h0x6R/jQhGt/rIRpbRyVreWLtD7B/WsVxo91URm2WxMKR9JQZA==", + "version": "1.3.864", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.864.tgz", + "integrity": "sha512-v4rbad8GO6/yVI92WOeU9Wgxc4NA0n4f6P1FvZTY+jyY7JHEhw3bduYu60v3Q1h81Cg6eo4ApZrFPuycwd5hGw==", "dev": true }, "emoji-regex": { @@ -16733,9 +16705,9 @@ } }, "node-releases": { - "version": "1.1.76", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.76.tgz", - "integrity": "sha512-9/IECtNr8dXNmPWmFXepT0/7o5eolGesHUa3mtr0KlgnCvnZxwh2qensKL42JJY2vQKC3nIBXetFAqR+PW1CmA==", + "version": "1.1.77", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.77.tgz", + "integrity": "sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ==", "dev": true }, "normalize-path": { @@ -17253,6 +17225,12 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "dev": true }, + "picocolors": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz", + "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==", + "dev": true + }, "picomatch": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", @@ -17314,13 +17292,13 @@ } }, "postcss": { - "version": "8.3.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.8.tgz", - "integrity": "sha512-GT5bTjjZnwDifajzczOC+r3FI3Cu+PgPvrsjhQdRqa2kTJ4968/X9CUce9xttIB0xOs5c6xf0TCWZo/y9lF6bA==", + "version": "8.3.9", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.9.tgz", + "integrity": "sha512-f/ZFyAKh9Dnqytx5X62jgjhhzttjZS7hMsohcI7HEI5tjELX/HxCy3EFhsRxyzGvrzFF+82XPvCS8T9TFleVJw==", "dev": true, "requires": { - "nanocolors": "^0.2.2", - "nanoid": "^3.1.25", + "nanoid": "^3.1.28", + "picocolors": "^0.2.1", "source-map-js": "^0.6.2" } }, diff --git a/package.json b/package.json index 1aaa2461..33eb1308 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-flow-renderer", - "version": "9.6.8", + "version": "10.0.0-next.2", "engines": { "node": ">=12" }, @@ -28,12 +28,12 @@ "cy:open": "cypress open", "release": "npm run test && release-it", "release:notest": "release-it", - "release:next": "release-it --preRelease=next" + "release:next": "release-it --preRelease=next --no-git" }, "dependencies": { "@babel/runtime": "^7.15.4", "@types/d3": "^7.0.0", - "@types/react-redux": "^7.1.18", + "@types/react-redux": "^7.1.19", "classcat": "^5.0.3", "d3-selection": "^3.0.0", "d3-zoom": "^3.0.0", @@ -44,9 +44,9 @@ "zustand": "^3.5.13" }, "devDependencies": { - "@babel/core": "^7.15.5", - "@babel/plugin-transform-runtime": "^7.15.0", - "@babel/preset-env": "^7.15.6", + "@babel/core": "^7.15.8", + "@babel/plugin-transform-runtime": "^7.15.8", + "@babel/preset-env": "^7.15.8", "@babel/preset-react": "^7.14.5", "@rollup/plugin-babel": "^5.3.0", "@rollup/plugin-commonjs": "^21.0.0", @@ -59,7 +59,7 @@ "autoprefixer": "^10.3.6", "babel-preset-react-app": "^10.0.0", "cypress": "^8.5.0", - "postcss": "^8.3.8", + "postcss": "^8.3.9", "postcss-cli": "^9.0.1", "postcss-nested": "^5.0.6", "prettier": "2.4.1", diff --git a/src/components/Edges/BezierEdge.tsx b/src/components/Edges/BezierEdge.tsx index b75eb949..7edb5a42 100644 --- a/src/components/Edges/BezierEdge.tsx +++ b/src/components/Edges/BezierEdge.tsx @@ -1,7 +1,7 @@ import React, { memo } from 'react'; import EdgeText from './EdgeText'; -import { getMarkerEnd, getCenter } from './utils'; +import { getCenter } from './utils'; import { EdgeProps, Position } from '../../types'; interface GetBezierPathParams { @@ -36,9 +36,9 @@ export function getBezierPath({ if (leftAndRight.includes(sourcePosition) && leftAndRight.includes(targetPosition)) { path = `M${sourceX},${sourceY} C${cX},${sourceY} ${cX},${targetY} ${targetX},${targetY}`; } else if (leftAndRight.includes(targetPosition)) { - path = `M${sourceX},${sourceY} C${sourceX},${targetY} ${sourceX},${targetY} ${targetX},${targetY}`; + path = `M${sourceX},${sourceY} Q${sourceX},${targetY} ${targetX},${targetY}`; } else if (leftAndRight.includes(sourcePosition)) { - path = `M${sourceX},${sourceY} C${targetX},${sourceY} ${targetX},${sourceY} ${targetX},${targetY}`; + path = `M${sourceX},${sourceY} Q${targetX},${sourceY} ${targetX},${targetY}`; } return path; @@ -59,8 +59,8 @@ export default memo( labelBgPadding, labelBgBorderRadius, style, - arrowHeadType, - markerEndId, + markerEnd, + markerStart, }: EdgeProps) => { const [centerX, centerY] = getCenter({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }); const path = getBezierPath({ @@ -85,11 +85,15 @@ export default memo( /> ) : null; - const markerEnd = getMarkerEnd(arrowHeadType, markerEndId); - return ( <> - + {text} ); diff --git a/src/components/Edges/SmoothStepEdge.tsx b/src/components/Edges/SmoothStepEdge.tsx index 0c42410a..3bb087dd 100644 --- a/src/components/Edges/SmoothStepEdge.tsx +++ b/src/components/Edges/SmoothStepEdge.tsx @@ -1,7 +1,7 @@ import React, { memo } from 'react'; import EdgeText from './EdgeText'; -import { getMarkerEnd, getCenter } from './utils'; +import { getCenter } from './utils'; import { EdgeSmoothStepProps, Position } from '../../types'; // These are some helper methods for drawing the round corners @@ -73,8 +73,8 @@ export function getSmoothStepPath({ sourceY <= targetY ? rightTopCorner(cX, sourceY, cornerSize) : rightBottomCorner(cX, sourceY, cornerSize); secondCornerPath = sourceY <= targetY ? bottomLeftCorner(cX, targetY, cornerSize) : topLeftCorner(cX, targetY, cornerSize); - } else if (sourcePosition === Position.Right && targetPosition === Position.Left){ - // and sourceX > targetX + } else if (sourcePosition === Position.Right && targetPosition === Position.Left) { + // and sourceX > targetX firstCornerPath = sourceY <= targetY ? leftTopCorner(cX, sourceY, cornerSize) : leftBottomCorner(cX, sourceY, cornerSize); secondCornerPath = @@ -126,8 +126,8 @@ export default memo( style, sourcePosition = Position.Bottom, targetPosition = Position.Top, - arrowHeadType, - markerEndId, + markerEnd, + markerStart, borderRadius = 5, }: EdgeSmoothStepProps) => { const [centerX, centerY] = getCenter({ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition }); @@ -142,8 +142,6 @@ export default memo( borderRadius, }); - const markerEnd = getMarkerEnd(arrowHeadType, markerEndId); - const text = label ? ( - + {text} ); diff --git a/src/components/Edges/StraightEdge.tsx b/src/components/Edges/StraightEdge.tsx index 1bd3dedf..b7f0fac1 100644 --- a/src/components/Edges/StraightEdge.tsx +++ b/src/components/Edges/StraightEdge.tsx @@ -1,7 +1,6 @@ import React, { memo } from 'react'; import EdgeText from './EdgeText'; -import { getMarkerEnd } from './utils'; import { EdgeProps } from '../../types'; export default memo( @@ -17,15 +16,14 @@ export default memo( labelBgPadding, labelBgBorderRadius, style, - arrowHeadType, - markerEndId, + markerEnd, + markerStart, }: EdgeProps) => { const yOffset = Math.abs(targetY - sourceY) / 2; const centerY = targetY < sourceY ? targetY + yOffset : targetY - yOffset; const xOffset = Math.abs(targetX - sourceX) / 2; const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset; - const markerEnd = getMarkerEnd(arrowHeadType, markerEndId); const text = label ? ( {text} diff --git a/src/components/Edges/wrapEdge.tsx b/src/components/Edges/wrapEdge.tsx index 8bb9caae..0e9555e1 100644 --- a/src/components/Edges/wrapEdge.tsx +++ b/src/components/Edges/wrapEdge.tsx @@ -6,6 +6,7 @@ import { useStore, useStoreApi } from '../../store'; import { Edge, EdgeProps, WrapEdgeProps, ReactFlowState } from '../../types'; import { onMouseDown } from '../../components/Handle/handler'; import { EdgeAnchor } from './EdgeAnchor'; +import { getMarkerId } from '../../utils/graph'; const selector = (s: ReactFlowState) => ({ addSelectedElements: s.addSelectedElements, @@ -32,7 +33,6 @@ export default (EdgeComponent: ComponentType) => { labelBgPadding, labelBgBorderRadius, style, - arrowHeadType, source, target, sourceX, @@ -42,7 +42,6 @@ export default (EdgeComponent: ComponentType) => { sourcePosition, targetPosition, elementsSelectable, - markerEndId, isHidden, sourceHandleId, targetHandleId, @@ -55,6 +54,8 @@ export default (EdgeComponent: ComponentType) => { edgeUpdaterRadius, onEdgeUpdateStart, onEdgeUpdateEnd, + markerEnd, + markerStart, }: WrapEdgeProps): JSX.Element | null => { const store = useStoreApi(); const { addSelectedElements, setConnectionNodeId, unsetNodesSelection, setPosition, connectionMode } = useStore( @@ -200,6 +201,8 @@ export default (EdgeComponent: ComponentType) => { const onEdgeUpdaterMouseEnter = useCallback(() => setUpdating(true), [setUpdating]); const onEdgeUpdaterMouseOut = useCallback(() => setUpdating(false), [setUpdating]); + const markerStartUrl = useMemo(() => `url(#${getMarkerId(markerStart)})`, [markerStart]); + const markerEndUrl = useMemo(() => `url(#${getMarkerId(markerEnd)})`, [markerEnd]); if (isHidden) { return null; @@ -229,16 +232,16 @@ export default (EdgeComponent: ComponentType) => { labelBgBorderRadius={labelBgBorderRadius} data={data} style={style} - arrowHeadType={arrowHeadType} sourceX={sourceX} sourceY={sourceY} targetX={targetX} targetY={targetY} sourcePosition={sourcePosition} targetPosition={targetPosition} - markerEndId={markerEndId} sourceHandleId={sourceHandleId} targetHandleId={targetHandleId} + markerStart={markerStartUrl} + markerEnd={markerEndUrl} /> {handleEdgeUpdate && ( ( - - {children} - -); - interface MarkerDefinitionsProps { - color: string; + defaultColor: string; } -const MarkerDefinitions = ({ color }: MarkerDefinitionsProps) => { +type SymbolProps = Omit; + +const ArrowSymbol = ({ color = 'none', strokeWidth = 1 }: SymbolProps) => { + return ( + + ); +}; + +const ArrowClosedSymbol = ({ color = 'none', strokeWidth = 1 }: SymbolProps) => { + return ( + + ); +}; + +const markerSymbols = { + [ArrowHeadType.Arrow]: ArrowSymbol, + [ArrowHeadType.ArrowClosed]: ArrowClosedSymbol, +}; + +const Marker = ({ + id, + type, + color, + width = 12.5, + height = 12.5, + units = 'strokeWidth', + strokeWidth, + orient = 'auto', +}: MarkerProps) => { + const Symbol = markerSymbols[type]; + + return ( + + + + ); +}; + +const edgesSelector = (s: ReactFlowState) => s.edges; + +const MarkerDefinitions = ({ defaultColor }: MarkerDefinitionsProps) => { + const edges = useStore(edgesSelector); + const markers = useMemo(() => { + const ids: string[] = []; + + return edges.reduce((markers, edge) => { + [edge.markerStart, edge.markerEnd].forEach((marker) => { + if (marker && typeof marker === 'object') { + const markerId = getMarkerId(marker); + if (!ids.includes(markerId)) { + markers.push({ id: markerId, color: marker.color || defaultColor, ...marker }); + ids.push(markerId); + } + } + }); + return markers.sort((a, b) => a.id.localeCompare(b.id)); + }, []); + }, [edges, defaultColor]); + return ( - - ( + - - - - + ))} ); }; diff --git a/src/container/EdgeRenderer/index.tsx b/src/container/EdgeRenderer/index.tsx index 8abe99a5..4b707b98 100644 --- a/src/container/EdgeRenderer/index.tsx +++ b/src/container/EdgeRenderer/index.tsx @@ -24,8 +24,7 @@ interface EdgeRendererProps { connectionLineComponent?: ConnectionLineComponent; onEdgeClick?: (event: React.MouseEvent, node: Edge) => void; onEdgeDoubleClick?: (event: React.MouseEvent, edge: Edge) => void; - arrowHeadColor: string; - markerEndId?: string; + defaultMarkerColor: string; onlyRenderVisibleElements: boolean; onEdgeUpdate?: OnEdgeUpdateFunc; onEdgeContextMenu?: (event: React.MouseEvent, edge: Edge) => void; @@ -176,11 +175,12 @@ const Edge = memo( labelBgPadding={edge.labelBgPadding} labelBgBorderRadius={edge.labelBgBorderRadius} style={edge.style} - arrowHeadType={edge.arrowHeadType} source={edge.source} target={edge.target} sourceHandleId={sourceHandleId} targetHandleId={targetHandleId} + markerEnd={edge.markerEnd} + markerStart={edge.markerStart} sourceX={sourceX} sourceY={sourceY} targetX={targetX} @@ -271,12 +271,12 @@ const EdgeRenderer = (props: EdgeRendererProps) => { return null; } - const { connectionLineType, arrowHeadColor, connectionLineStyle, connectionLineComponent } = props; + const { connectionLineType, defaultMarkerColor, connectionLineStyle, connectionLineComponent } = props; const renderConnectionLine = connectionNodeId && connectionHandleType; return ( - + {edges.map((edge: Edge) => { const { sourceNode, targetNode } = getSourceTargetNodes(edge, nodes); @@ -295,7 +295,6 @@ const EdgeRenderer = (props: EdgeRendererProps) => { targetNodeY={targetNode?.position.y} targetNodeHandleBounds={targetNode?.handleBounds} elementsSelectable={elementsSelectable} - markerEndId={props.markerEndId} onEdgeContextMenu={props.onEdgeContextMenu} onEdgeMouseEnter={props.onEdgeMouseEnter} onEdgeMouseMove={props.onEdgeMouseMove} diff --git a/src/container/FlowRenderer/index.tsx b/src/container/FlowRenderer/index.tsx index 1864927f..91f6681d 100644 --- a/src/container/FlowRenderer/index.tsx +++ b/src/container/FlowRenderer/index.tsx @@ -21,6 +21,7 @@ interface FlowRendererProps | 'arrowHeadColor' | 'onlyRenderVisibleElements' | 'selectNodesOnDrag' + | 'defaultMarkerColor' > { children: ReactNode; } diff --git a/src/container/GraphView/index.tsx b/src/container/GraphView/index.tsx index 24938a74..df89027a 100644 --- a/src/container/GraphView/index.tsx +++ b/src/container/GraphView/index.tsx @@ -21,7 +21,7 @@ export interface GraphViewProps extends Omit ); diff --git a/src/container/ReactFlow/index.tsx b/src/container/ReactFlow/index.tsx index 1e7ba986..c9c184cb 100644 --- a/src/container/ReactFlow/index.tsx +++ b/src/container/ReactFlow/index.tsx @@ -114,8 +114,7 @@ export interface ReactFlowProps extends Omit, 'on translateExtent?: TranslateExtent; preventScrolling?: boolean; nodeExtent?: NodeExtent; - arrowHeadColor?: string; - markerEndId?: string; + defaultMarkerColor?: string; zoomOnScroll?: boolean; zoomOnPinch?: boolean; panOnScroll?: boolean; @@ -191,8 +190,7 @@ const ReactFlow = forwardRef( translateExtent, preventScrolling = true, nodeExtent, - arrowHeadColor = '#b1b1b7', - markerEndId, + defaultMarkerColor = '#b1b1b7', zoomOnScroll = true, zoomOnPinch = true, panOnScroll = false, @@ -255,8 +253,6 @@ const ReactFlow = forwardRef( defaultZoom={defaultZoom} defaultPosition={defaultPosition} preventScrolling={preventScrolling} - arrowHeadColor={arrowHeadColor} - markerEndId={markerEndId} zoomOnScroll={zoomOnScroll} zoomOnPinch={zoomOnPinch} zoomOnDoubleClick={zoomOnDoubleClick} @@ -280,6 +276,7 @@ const ReactFlow = forwardRef( onEdgeUpdateStart={onEdgeUpdateStart} onEdgeUpdateEnd={onEdgeUpdateEnd} edgeUpdaterRadius={edgeUpdaterRadius} + defaultMarkerColor={defaultMarkerColor} /> { id: ElementId; type?: string; @@ -108,13 +120,14 @@ export interface Edge { labelBgBorderRadius?: number; style?: CSSProperties; animated?: boolean; - arrowHeadType?: ArrowHeadType; isHidden?: boolean; data?: T; className?: string; sourceNode?: Node; targetNode?: Node; isSelected?: boolean; + markerStart?: EdgeMarkerType; + markerEnd?: EdgeMarkerType; } export enum BackgroundVariant { @@ -150,7 +163,6 @@ export interface WrapEdgeProps { labelBgPadding?: [number, number]; labelBgBorderRadius?: number; style?: CSSProperties; - arrowHeadType?: ArrowHeadType; source: ElementId; target: ElementId; sourceHandleId: ElementId | null; @@ -162,7 +174,6 @@ export interface WrapEdgeProps { sourcePosition: Position; targetPosition: Position; elementsSelectable?: boolean; - markerEndId?: string; isHidden?: boolean; handleEdgeUpdate: boolean; onConnectEdge: OnConnectFunc; @@ -173,6 +184,8 @@ export interface WrapEdgeProps { edgeUpdaterRadius?: number; onEdgeUpdateStart?: (event: React.MouseEvent, edge: Edge) => void; onEdgeUpdateEnd?: (event: MouseEvent, edge: Edge) => void; + markerStart?: EdgeMarkerType; + markerEnd?: EdgeMarkerType; } export interface EdgeProps { @@ -194,11 +207,11 @@ export interface EdgeProps { labelBgPadding?: [number, number]; labelBgBorderRadius?: number; style?: CSSProperties; - arrowHeadType?: ArrowHeadType; - markerEndId?: string; data?: T; sourceHandleId?: ElementId | null; targetHandleId?: ElementId | null; + markerStart?: string; + markerEnd?: string; } export interface EdgeSmoothStepProps extends EdgeProps { borderRadius?: number; diff --git a/src/utils/graph.ts b/src/utils/graph.ts index 07ff0662..cda69ca1 100644 --- a/src/utils/graph.ts +++ b/src/utils/graph.ts @@ -16,6 +16,7 @@ import { EdgeChange, NodeChange, ReactFlowState, + EdgeMarkerType, } from '../types'; export const isEdge = (element: Node | Connection | Edge): element is Edge => @@ -45,13 +46,29 @@ export const getIncomers = (node: Node, nodes: Node[], edges: Edge[]): Node[] => const getEdgeId = ({ source, sourceHandle, target, targetHandle }: Connection): ElementId => `reactflow__edge-${source}${sourceHandle}-${target}${targetHandle}`; -const connectionExists = (edge: Edge, edges: Edge[]) => { - return edges.some( - (e) => - edge.source === e.source && - edge.target === e.target && - (edge.sourceHandle === e.sourceHandle || (!edge.sourceHandle && !e.sourceHandle)) && - (edge.targetHandle === e.targetHandle || (!edge.targetHandle && !e.targetHandle)) +export const getMarkerId = (marker: EdgeMarkerType | undefined): string => { + if (typeof marker === 'undefined') { + return ''; + } + + if (typeof marker === 'string') { + return marker; + } + + return Object.keys(marker) + .sort() + .map((key: string) => `${key}=${(marker as any)[key]}`) + .join('&'); +}; + +const connectionExists = (edge: Edge, elements: Elements) => { + return elements.some( + (el) => + isEdge(el) && + el.source === edge.source && + el.target === edge.target && + (el.sourceHandle === edge.sourceHandle || (!el.sourceHandle && !edge.sourceHandle)) && + (el.targetHandle === edge.targetHandle || (!el.targetHandle && !edge.targetHandle)) ); };