From bee2ca5c0cd2fba728d22ac5d085290006104f7e Mon Sep 17 00:00:00 2001 From: jasonpul Date: Thu, 1 Oct 2020 12:48:56 -0400 Subject: [PATCH 1/4] initial working mod with nodeId and handleId split up in Connection type so that target-target and source-source connections cannot be made --- example/package-lock.json | 195 +++++++++++---------------- example/src/Validation/index.js | 13 +- example/src/index.js | 23 ++-- package-lock.json | 42 +----- src/components/Handle/BaseHandle.tsx | 46 ++++--- src/types/index.ts | 2 + 6 files changed, 130 insertions(+), 191 deletions(-) diff --git a/example/package-lock.json b/example/package-lock.json index 631169fb..7b2fde9e 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -1844,6 +1844,14 @@ "@xtuc/long": "4.2.2" } }, + "@welldone-software/why-did-you-render": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@welldone-software/why-did-you-render/-/why-did-you-render-4.3.2.tgz", + "integrity": "sha512-pzaFmUUH+FjbsDgcMB1xNPncIaxibvo0FLbGySLIh+v+7Bp5pqSJFO6zlqo4orPLm3nAdYEgL2vrlj8befoypg==", + "requires": { + "lodash": "^4" + } + }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -3118,9 +3126,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001116", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001116.tgz", - "integrity": "sha512-f2lcYnmAI5Mst9+g0nkMIznFGsArRmZ0qU+dnq8l91hymdc2J3SFbiPhOJEeDqC1vtE8nc1qNQyklzB8veJefQ==" + "version": "1.0.30001141", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001141.tgz", + "integrity": "sha512-EHfInJHoQTmlMdVZrEc5gmwPc0zyN/hVufmGHPbVNQwlk7tJfCmQ2ysRZMY2MeleBivALUTyyxXnQjK18XrVpA==" }, "capture-exit": { "version": "2.0.0", @@ -3996,10 +4004,71 @@ "type": "^1.0.1" } }, + "d3-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-2.0.0.tgz", + "integrity": "sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ==" + }, + "d3-dispatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-2.0.0.tgz", + "integrity": "sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA==" + }, + "d3-drag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-2.0.0.tgz", + "integrity": "sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w==", + "requires": { + "d3-dispatch": "1 - 2", + "d3-selection": "2" + } + }, + "d3-ease": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-2.0.0.tgz", + "integrity": "sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ==" + }, + "d3-interpolate": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-2.0.1.tgz", + "integrity": "sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ==", + "requires": { + "d3-color": "1 - 2" + } + }, "d3-selection": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", - "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-2.0.0.tgz", + "integrity": "sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA==" + }, + "d3-timer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-2.0.0.tgz", + "integrity": "sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA==" + }, + "d3-transition": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-2.0.0.tgz", + "integrity": "sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog==", + "requires": { + "d3-color": "1 - 2", + "d3-dispatch": "1 - 2", + "d3-ease": "1 - 2", + "d3-interpolate": "1 - 2", + "d3-timer": "1 - 2" + } + }, + "d3-zoom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-2.0.0.tgz", + "integrity": "sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw==", + "requires": { + "d3-dispatch": "1 - 2", + "d3-drag": "2", + "d3-interpolate": "1 - 2", + "d3-selection": "2", + "d3-transition": "2" + } }, "damerau-levenshtein": { "version": "1.0.6", @@ -10497,11 +10566,6 @@ "pkg-up": "^2.0.0" } }, - "caniuse-lite": { - "version": "1.0.30001038", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001038.tgz", - "integrity": "sha512-zii9quPo96XfOiRD4TrfYGs+QsGZpb2cGiMAzPjtf/hpFgB6zCPZgJb7I1+EATeMw/o+lG8FyRAnI+CWStHcaQ==" - }, "electron-to-chromium": { "version": "1.3.392", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.392.tgz", @@ -10705,11 +10769,6 @@ "pkg-up": "^2.0.0" } }, - "caniuse-lite": { - "version": "1.0.30001038", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001038.tgz", - "integrity": "sha512-zii9quPo96XfOiRD4TrfYGs+QsGZpb2cGiMAzPjtf/hpFgB6zCPZgJb7I1+EATeMw/o+lG8FyRAnI+CWStHcaQ==" - }, "electron-to-chromium": { "version": "1.3.392", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.392.tgz", @@ -12616,11 +12675,6 @@ "pkg-up": "^2.0.0" } }, - "caniuse-lite": { - "version": "1.0.30001038", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001038.tgz", - "integrity": "sha512-zii9quPo96XfOiRD4TrfYGs+QsGZpb2cGiMAzPjtf/hpFgB6zCPZgJb7I1+EATeMw/o+lG8FyRAnI+CWStHcaQ==" - }, "electron-to-chromium": { "version": "1.3.392", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.392.tgz", @@ -13929,21 +13983,6 @@ "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz", "integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==" }, - "@welldone-software/why-did-you-render": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@welldone-software/why-did-you-render/-/why-did-you-render-4.3.1.tgz", - "integrity": "sha512-1Axk7YWHbXlOgMJ1Wmal7Nmd8a7k+VLr7YFwQsY7CB4SsjJCOyyjbnLLZQ4t6ojw4Wn1suqhcj8leBPMwKjzmA==", - "requires": { - "lodash": "^4" - }, - "dependencies": { - "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" - } - } - }, "ajv": { "version": "6.10.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", @@ -14102,13 +14141,6 @@ "num2fraction": "^1.2.2", "postcss": "^7.0.27", "postcss-value-parser": "^4.0.3" - }, - "dependencies": { - "caniuse-lite": { - "version": "1.0.30001043", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001043.tgz", - "integrity": "sha512-MrBDRPJPDBYwACtSQvxg9+fkna5jPXhJlKmuxenl/ml9uf8LHKlDmLpElu+zTW/bEz7lC1m0wTDD7jiIB+hgFg==" - } } }, "aws-sign2": { @@ -14508,11 +14540,6 @@ "pkg-up": "^2.0.0" } }, - "caniuse-lite": { - "version": "1.0.30001038", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001038.tgz", - "integrity": "sha512-zii9quPo96XfOiRD4TrfYGs+QsGZpb2cGiMAzPjtf/hpFgB6zCPZgJb7I1+EATeMw/o+lG8FyRAnI+CWStHcaQ==" - }, "convert-source-map": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", @@ -14758,11 +14785,6 @@ "lodash.uniq": "^4.5.0" } }, - "caniuse-lite": { - "version": "1.0.30001038", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001038.tgz", - "integrity": "sha512-zii9quPo96XfOiRD4TrfYGs+QsGZpb2cGiMAzPjtf/hpFgB6zCPZgJb7I1+EATeMw/o+lG8FyRAnI+CWStHcaQ==" - }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", @@ -15679,11 +15701,6 @@ "pkg-up": "^2.0.0" } }, - "caniuse-lite": { - "version": "1.0.30001038", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001038.tgz", - "integrity": "sha512-zii9quPo96XfOiRD4TrfYGs+QsGZpb2cGiMAzPjtf/hpFgB6zCPZgJb7I1+EATeMw/o+lG8FyRAnI+CWStHcaQ==" - }, "electron-to-chromium": { "version": "1.3.392", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.392.tgz", @@ -16072,68 +16089,6 @@ } } }, - "d3-color": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.0.tgz", - "integrity": "sha512-TzNPeJy2+iEepfiL92LAAB7fvnp/dV2YwANPVHdDWmYMm23qIJBYww3qT8I8C1wXrmrg4UWs7BKc2tKIgyjzHg==" - }, - "d3-dispatch": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.5.tgz", - "integrity": "sha512-vwKx+lAqB1UuCeklr6Jh1bvC4SZgbSqbkGBLClItFBIYH4vqDJCA7qfoy14lXmJdnBOdxndAMxjCbImJYW7e6g==" - }, - "d3-drag": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.4.tgz", - "integrity": "sha512-ICPurDETFAelF1CTHdIyiUM4PsyZLaM+7oIBhmyP+cuVjze5vDZ8V//LdOFjg0jGnFIZD/Sfmk0r95PSiu78rw==", - "requires": { - "d3-dispatch": "1", - "d3-selection": "1" - } - }, - "d3-ease": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.5.tgz", - "integrity": "sha512-Ct1O//ly5y5lFM9YTdu+ygq7LleSgSE4oj7vUt9tPLHUi8VCV7QoizGpdWRWAwCO9LdYzIrQDg97+hGVdsSGPQ==" - }, - "d3-interpolate": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.3.2.tgz", - "integrity": "sha512-NlNKGopqaz9qM1PXh9gBF1KSCVh+jSFErrSlD/4hybwoNX/gt1d8CDbDW+3i+5UOHhjC6s6nMvRxcuoMVNgL2w==", - "requires": { - "d3-color": "1" - } - }, - "d3-timer": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.9.tgz", - "integrity": "sha512-rT34J5HnQUHhcLvhSB9GjCkN0Ddd5Y8nCwDBG2u6wQEeYxT/Lf51fTFFkldeib/sE/J0clIe0pnCfs6g/lRbyg==" - }, - "d3-transition": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.2.0.tgz", - "integrity": "sha512-VJ7cmX/FPIPJYuaL2r1o1EMHLttvoIuZhhuAlRoOxDzogV8iQS6jYulDm3xEU3TqL80IZIhI551/ebmCMrkvhw==", - "requires": { - "d3-color": "1", - "d3-dispatch": "1", - "d3-ease": "1", - "d3-interpolate": "1", - "d3-selection": "^1.1.0", - "d3-timer": "1" - } - }, - "d3-zoom": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.8.3.tgz", - "integrity": "sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==", - "requires": { - "d3-dispatch": "1", - "d3-drag": "1", - "d3-interpolate": "1", - "d3-selection": "1", - "d3-transition": "1" - } - }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", diff --git a/example/src/Validation/index.js b/example/src/Validation/index.js index 02d4bc57..7fe81cbe 100644 --- a/example/src/Validation/index.js +++ b/example/src/Validation/index.js @@ -20,15 +20,18 @@ const onConnectEnd = (event) => console.log('on connect end', event); const CustomInput = () => ( <>
Only connectable with B
- + + {/* */} ); const CustomNode = ({ id }) => ( <> + {/* */}
{id}
+ {/* */} ); @@ -40,7 +43,7 @@ const nodeTypes = { const HorizontalFlow = () => { const [elements, setElements] = useState(initialElements); const onConnect = (params) => { - console.log('on connect', params); + // console.log('on connect', params); setElements((els) => addEdge(params, els)); }; @@ -52,9 +55,9 @@ const HorizontalFlow = () => { onLoad={onLoad} className="validationflow" nodeTypes={nodeTypes} - onConnectStart={onConnectStart} - onConnectStop={onConnectStop} - onConnectEnd={onConnectEnd} + // onConnectStart={onConnectStart} + // onConnectStop={onConnectStop} + // onConnectEnd={onConnectEnd} /> ); }; diff --git a/example/src/index.js b/example/src/index.js index f90eee35..f0c9a95a 100644 --- a/example/src/index.js +++ b/example/src/index.js @@ -117,14 +117,19 @@ const Header = () => { }; ReactDOM.render( - -
- - - {routes.map((route) => ( - } key={route.path} /> - ))} - - , + , document.getElementById('root') ); + +// ReactDOM.render( +// +//
+// +// +// {routes.map((route) => ( +// } key={route.path} /> +// ))} +// +// , +// document.getElementById('root') +// ); diff --git a/package-lock.json b/package-lock.json index 60a31d66..633a230b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,12 +36,6 @@ "node-releases": "^1.1.60" } }, - "caniuse-lite": { - "version": "1.0.30001123", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001123.tgz", - "integrity": "sha512-03dJDoa4YC4332jq0rqwiM+Hw6tA5RJtrnZKvOQy7ASoIUv8CinkcmGhYpCvCjedvkBQrrKnkcELxrUSW/XwNQ==", - "dev": true - }, "electron-to-chromium": { "version": "1.3.559", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.559.tgz", @@ -388,12 +382,6 @@ "node-releases": "^1.1.60" } }, - "caniuse-lite": { - "version": "1.0.30001123", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001123.tgz", - "integrity": "sha512-03dJDoa4YC4332jq0rqwiM+Hw6tA5RJtrnZKvOQy7ASoIUv8CinkcmGhYpCvCjedvkBQrrKnkcELxrUSW/XwNQ==", - "dev": true - }, "electron-to-chromium": { "version": "1.3.559", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.559.tgz", @@ -3557,12 +3545,6 @@ "node-releases": "^1.1.60" } }, - "caniuse-lite": { - "version": "1.0.30001123", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001123.tgz", - "integrity": "sha512-03dJDoa4YC4332jq0rqwiM+Hw6tA5RJtrnZKvOQy7ASoIUv8CinkcmGhYpCvCjedvkBQrrKnkcELxrUSW/XwNQ==", - "dev": true - }, "electron-to-chromium": { "version": "1.3.559", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.559.tgz", @@ -5331,12 +5313,6 @@ "node-releases": "^1.1.58" } }, - "caniuse-lite": { - "version": "1.0.30001109", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001109.tgz", - "integrity": "sha512-4JIXRodHzdS3HdK8nSgIqXYLExOvG+D2/EenSvcub2Kp3QEADjo2v2oUn5g0n0D+UNwG9BtwKOyGcSq2qvQXvQ==", - "dev": true - }, "electron-to-chromium": { "version": "1.3.516", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.516.tgz", @@ -5791,12 +5767,6 @@ "pkg-up": "^2.0.0" } }, - "caniuse-lite": { - "version": "1.0.30001038", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001038.tgz", - "integrity": "sha512-zii9quPo96XfOiRD4TrfYGs+QsGZpb2cGiMAzPjtf/hpFgB6zCPZgJb7I1+EATeMw/o+lG8FyRAnI+CWStHcaQ==", - "dev": true - }, "convert-source-map": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", @@ -6087,9 +6057,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001038", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001038.tgz", - "integrity": "sha512-zii9quPo96XfOiRD4TrfYGs+QsGZpb2cGiMAzPjtf/hpFgB6zCPZgJb7I1+EATeMw/o+lG8FyRAnI+CWStHcaQ==", + "version": "1.0.30001141", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001141.tgz", + "integrity": "sha512-EHfInJHoQTmlMdVZrEc5gmwPc0zyN/hVufmGHPbVNQwlk7tJfCmQ2ysRZMY2MeleBivALUTyyxXnQjK18XrVpA==", "dev": true }, "caseless": { @@ -6451,12 +6421,6 @@ "pkg-up": "^2.0.0" } }, - "caniuse-lite": { - "version": "1.0.30001038", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001038.tgz", - "integrity": "sha512-zii9quPo96XfOiRD4TrfYGs+QsGZpb2cGiMAzPjtf/hpFgB6zCPZgJb7I1+EATeMw/o+lG8FyRAnI+CWStHcaQ==", - "dev": true - }, "electron-to-chromium": { "version": "1.3.392", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.392.tgz", diff --git a/src/components/Handle/BaseHandle.tsx b/src/components/Handle/BaseHandle.tsx index 4b432557..263d6289 100644 --- a/src/components/Handle/BaseHandle.tsx +++ b/src/components/Handle/BaseHandle.tsx @@ -42,6 +42,7 @@ type Result = { function onMouseDown( event: ReactMouseEvent, + handleId: ElementId, nodeId: ElementId, setConnectionNodeId: SetSourceIdFunc, setPosition: (pos: XYPosition) => void, @@ -84,30 +85,36 @@ function onMouseDown( // checks if element below mouse is a handle and returns connection in form of an object { source: 123, target: 312 } function checkElementBelowIsValid(event: MouseEvent) { const elementBelow = document.elementFromPoint(event.clientX, event.clientY); + // console.log(elementBelow) + // console.log(handleId) const result: Result = { elementBelow, isValid: false, - connection: { source: null, target: null }, + connection: { source: null, target: null, sourceHandle: null, targetHandle: null }, isHoveringHandle: false, }; if (elementBelow && (elementBelow.classList.contains('target') || elementBelow.classList.contains('source'))) { - let connection: Connection = { source: null, target: null }; - - if (isTarget) { - const sourceId = elementBelow.getAttribute('data-nodeid'); - connection = { source: sourceId, target: nodeId }; - } else { - const targetId = elementBelow.getAttribute('data-nodeid'); - connection = { source: nodeId, target: targetId }; - } - - const isValid = isValidConnection(connection); - - result.connection = connection; - result.isValid = isValid; result.isHoveringHandle = true; + if ((isTarget && elementBelow.classList.contains('source')) || (!isTarget && elementBelow.classList.contains('target'))) { + let connection: Connection = { source: null, target: null, sourceHandle: null, targetHandle: null }; + + if (isTarget) { + const sourceId = elementBelow.getAttribute('data-nodeid'); + const sourcehandleId = elementBelow.getAttribute('data-handleid'); + connection = { source: sourceId, sourceHandle: sourcehandleId, target: nodeId, targetHandle: handleId }; + } else { + const targetId = elementBelow.getAttribute('data-nodeid'); + const targetHandleId = elementBelow.getAttribute('data-handleid'); + connection = { source: nodeId, sourceHandle: handleId, target: targetId , targetHandle: targetHandleId}; + } + + const isValid = isValidConnection(connection); + + result.connection = connection; + result.isValid = isValid; + } } return result; @@ -187,17 +194,20 @@ const BaseHandle = ({ }, ]); - const nodeIdWithHandleId = id ? `${nodeId}__${id}` : nodeId; + // const nodeIdWithHandleId = id ? `${nodeId}__${id}` : nodeId; + const handleId = id ? `${id}`: '' return (
onMouseDown( event, - nodeIdWithHandleId, + handleId, + nodeId, setConnectionNodeId, setPosition, onConnect, diff --git a/src/types/index.ts b/src/types/index.ts index 4fd58470..721d2e96 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -239,6 +239,8 @@ export type OnLoadFunc = (params: OnLoadParams) => void; export interface Connection { source: ElementId | null; target: ElementId | null; + sourceHandle: ElementId | null; + targetHandle: ElementId | null; } export enum ConnectionLineType { From d9ba18d49c022d534c9509ccf9cd376d5edb6274 Mon Sep 17 00:00:00 2001 From: jasonpul Date: Thu, 1 Oct 2020 15:47:37 -0400 Subject: [PATCH 2/4] broke out handleId by itself rather than joined with nodeID, modded necessary functions to give handles not assigned IDs an empty string for backwards compadibility. Also modded handles so that only target-source and source-target connections are allowed, and no repeat connections are allowed. --- example/src/CustomNode/ColorSelectorNode.js | 4 +- example/src/CustomNode/index.js | 4 +- example/src/Validation/index.js | 8 ++-- example/src/index.js | 23 +++++------ src/components/Handle/BaseHandle.tsx | 4 -- src/components/Nodes/utils.ts | 9 +---- src/container/EdgeRenderer/index.tsx | 6 ++- src/types/index.ts | 2 + src/utils/graph.ts | 43 +++++++++++++++------ 9 files changed, 55 insertions(+), 48 deletions(-) diff --git a/example/src/CustomNode/ColorSelectorNode.js b/example/src/CustomNode/ColorSelectorNode.js index 1b6381f3..cd76d3b0 100644 --- a/example/src/CustomNode/ColorSelectorNode.js +++ b/example/src/CustomNode/ColorSelectorNode.js @@ -15,8 +15,8 @@ export default memo(({ data }) => { Custom Color Picker Node: {data.color}
- - + + ); }); diff --git a/example/src/CustomNode/index.js b/example/src/CustomNode/index.js index 6fa29443..7f184011 100644 --- a/example/src/CustomNode/index.js +++ b/example/src/CustomNode/index.js @@ -56,8 +56,8 @@ const CustomNodeFlow = () => { { id: '4', type: 'output', data: { label: 'Output B' }, position: { x: 550, y: 100 }, targetPosition: 'left' }, { id: 'e1-2', source: '1', target: '2', animated: true, style: { stroke: '#fff' } }, - { id: 'e2a-3', source: '2__a', target: '3', animated: true, style: { stroke: '#fff' } }, - { id: 'e2b-4', source: '2__b', target: '4', animated: true, style: { stroke: '#fff' } }, + { id: 'e2a-3', source: '2', sourceHandle: '0', target: '3', animated: true, style: { stroke: '#fff' } }, + { id: 'e2b-4', source: '2', sourceHandle: '1', target: '4', animated: true, style: { stroke: '#fff' } }, ]); }, []); diff --git a/example/src/Validation/index.js b/example/src/Validation/index.js index 7fe81cbe..eac2a998 100644 --- a/example/src/Validation/index.js +++ b/example/src/Validation/index.js @@ -43,7 +43,7 @@ const nodeTypes = { const HorizontalFlow = () => { const [elements, setElements] = useState(initialElements); const onConnect = (params) => { - // console.log('on connect', params); + console.log('on connect', params); setElements((els) => addEdge(params, els)); }; @@ -55,9 +55,9 @@ const HorizontalFlow = () => { onLoad={onLoad} className="validationflow" nodeTypes={nodeTypes} - // onConnectStart={onConnectStart} - // onConnectStop={onConnectStop} - // onConnectEnd={onConnectEnd} + onConnectStart={onConnectStart} + onConnectStop={onConnectStop} + onConnectEnd={onConnectEnd} /> ); }; diff --git a/example/src/index.js b/example/src/index.js index f0c9a95a..f90eee35 100644 --- a/example/src/index.js +++ b/example/src/index.js @@ -117,19 +117,14 @@ const Header = () => { }; ReactDOM.render( - , + +
+ + + {routes.map((route) => ( + } key={route.path} /> + ))} + + , document.getElementById('root') ); - -// ReactDOM.render( -// -//
-// -// -// {routes.map((route) => ( -// } key={route.path} /> -// ))} -// -// , -// document.getElementById('root') -// ); diff --git a/src/components/Handle/BaseHandle.tsx b/src/components/Handle/BaseHandle.tsx index 263d6289..6810ec35 100644 --- a/src/components/Handle/BaseHandle.tsx +++ b/src/components/Handle/BaseHandle.tsx @@ -85,8 +85,6 @@ function onMouseDown( // checks if element below mouse is a handle and returns connection in form of an object { source: 123, target: 312 } function checkElementBelowIsValid(event: MouseEvent) { const elementBelow = document.elementFromPoint(event.clientX, event.clientY); - // console.log(elementBelow) - // console.log(handleId) const result: Result = { elementBelow, @@ -194,9 +192,7 @@ const BaseHandle = ({ }, ]); - // const nodeIdWithHandleId = id ? `${nodeId}__${id}` : nodeId; const handleId = id ? `${id}`: '' - return (
{ const bounds = handle.getBoundingClientRect(); const dimensions = getDimensions(handle); - const nodeIdAttr = handle.getAttribute('data-nodeid'); + const handleId = handle.getAttribute('data-handleid'); const handlePosition = (handle.getAttribute('data-handlepos') as unknown) as Position; - const nodeIdSplitted = nodeIdAttr ? nodeIdAttr.split('__') : null; - - let handleId = null; - - if (nodeIdSplitted) { - handleId = (nodeIdSplitted.length ? nodeIdSplitted[1] : nodeIdSplitted) as string; - } return { id: handleId, diff --git a/src/container/EdgeRenderer/index.tsx b/src/container/EdgeRenderer/index.tsx index e3ba07bd..2c4de04a 100644 --- a/src/container/EdgeRenderer/index.tsx +++ b/src/container/EdgeRenderer/index.tsx @@ -132,8 +132,10 @@ function renderEdge( selectedElements: Elements | null, elementsSelectable: boolean ) { - const [sourceId, sourceHandleId] = edge.source.split('__'); - const [targetId, targetHandleId] = edge.target.split('__'); + const sourceId = edge.source + const sourceHandleId = edge.sourceHandle! + const targetId = edge.target + const targetHandleId = edge.targetHandle! const sourceNode = nodes.find((n) => n.id === sourceId); const targetNode = nodes.find((n) => n.id === targetId); diff --git a/src/types/index.ts b/src/types/index.ts index 721d2e96..1037b63e 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -58,6 +58,8 @@ export interface Edge { type?: string; source: ElementId; target: ElementId; + sourceHandle?: ElementId; + targetHandle?: ElementId; label?: string; labelStyle?: CSSProperties; labelShowBg?: boolean; diff --git a/src/utils/graph.ts b/src/utils/graph.ts index a1dfdfab..700f982b 100644 --- a/src/utils/graph.ts +++ b/src/utils/graph.ts @@ -40,7 +40,19 @@ export const removeElements = (elementsToRemove: Elements, elements: Elements): }); }; -const getEdgeId = ({ source, target }: Connection): ElementId => `reactflow__edge-${source}-${target}`; +const getEdgeId = ({ source, sourceHandle, target, targetHandle }: Connection): ElementId => `reactflow__edge-${source}${sourceHandle}-${target}${targetHandle}`; + +const existingConnection = (edge: Edge, elements: Elements) => { + for (const element of elements) { + if (isEdge(element)) { + if (element.source === edge.source && element.sourceHandle === edge.sourceHandle && element.target === edge.target && element.targetHandle === edge.targetHandle) { + return true + } + } + } + return false +} + export const addEdge = (edgeParams: Edge | Connection, elements: Elements): Elements => { if (!edgeParams.source || !edgeParams.target) { @@ -49,22 +61,27 @@ export const addEdge = (edgeParams: Edge | Connection, elements: Elements): Elem // make sure that there is node with the target and one with the source id [edgeParams.source, edgeParams.target].forEach((id) => { - const nodeId = id.includes('__') ? id.split('__')[0] : id; - if (!elements.find((e) => isNode(e) && e.id === nodeId)) { - throw new Error(`Can't create edge. Node with id=${nodeId} does not exist.`); + if (!elements.find((e) => isNode(e) && e.id === id)) { + throw new Error(`Can't create edge. Node with id=${id} does not exist.`); } }); + // need to check if handles exist + // + // + // + let edge: Edge if (isEdge(edgeParams)) { - return elements.concat({ ...edgeParams }); + edge = {...edgeParams} + } else { + edge = { + ...edgeParams, + id: getEdgeId(edgeParams), + } as Edge; } - - const edge = { - ...edgeParams, - id: getEdgeId(edgeParams), - } as Edge; - - return elements.concat(edge); + + if (existingConnection(edge, elements)) {return elements} + return elements.concat(edge) }; export const pointToRendererPoint = ( @@ -112,6 +129,8 @@ export const parseElement = (element: Node | Edge): Node | Edge => { ...element, source: element.source.toString(), target: element.target.toString(), + sourceHandle: element.sourceHandle ? element.sourceHandle.toString() : '', + targetHandle: element.targetHandle ? element.targetHandle.toString() : '', id: element.id.toString(), type: element.type || 'default', }; From 8742fa5cb8be9c4e5ffb8f724b053cbb4de09555 Mon Sep 17 00:00:00 2001 From: jasonpul <61257274+jasonpul@users.noreply.github.com> Date: Sun, 11 Oct 2020 16:34:17 -0400 Subject: [PATCH 3/4] Update index.js removed unneeded comments, switched to double quotes --- example/src/Validation/index.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/example/src/Validation/index.js b/example/src/Validation/index.js index eac2a998..713f3dbb 100644 --- a/example/src/Validation/index.js +++ b/example/src/Validation/index.js @@ -20,18 +20,15 @@ const onConnectEnd = (event) => console.log('on connect end', event); const CustomInput = () => ( <>
Only connectable with B
- - {/* */} + ); const CustomNode = ({ id }) => ( <> - {/* */}
{id}
- {/* */} ); From abf00187bb89b1de6ea7a8b45e0920d7766d91a3 Mon Sep 17 00:00:00 2001 From: jasonpul <61257274+jasonpul@users.noreply.github.com> Date: Sun, 11 Oct 2020 17:51:08 -0400 Subject: [PATCH 4/4] Update graph.ts added check to verify handle exists in node --- src/utils/graph.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/utils/graph.ts b/src/utils/graph.ts index 700f982b..9c427786 100644 --- a/src/utils/graph.ts +++ b/src/utils/graph.ts @@ -65,10 +65,14 @@ export const addEdge = (edgeParams: Edge | Connection, elements: Elements): Elem throw new Error(`Can't create edge. Node with id=${id} does not exist.`); } }); - // need to check if handles exist - // - // - // + + // make sure that the handles exists in each node + const handleElements = Array.from(document.getElementsByClassName("react-flow__handle")) as HTMLDivElement[] + [[edgeParams.source, edgeParams.sourceHandle], [edgeParams.target, edgeParams.targetHandle]].forEach(([nodeId, handleId]) => { + if (!handleElements.find((he) => he.getAttribute('data-nodeid') === nodeId && he.getAttribute('data-handleid') === handleId)) { + throw new Error(`Can't create edge. Handle with id=${handleId} does not exist within Node with id=${nodeId}.`); + } + }) let edge: Edge if (isEdge(edgeParams)) {