feat: allows custom node labels (with example)

This commit is contained in:
Mark Mankarious
2023-07-29 09:57:10 +01:00
committed by GitHub
parent f027170b0e
commit 55f9b37c56
18 changed files with 1004 additions and 214 deletions

661
package-lock.json generated
View File

@@ -57,6 +57,7 @@
"prettier": "^3.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"recharts": "^2.7.2",
"style-loader": "^3.3.3",
"ts-jest": "^29.0.5",
"ts-loader": "^9.4.2",
@@ -2579,6 +2580,69 @@
"@types/node": "*"
}
},
"node_modules/@types/d3-array": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.5.tgz",
"integrity": "sha512-Qk7fpJ6qFp+26VeQ47WY0mkwXaiq8+76RJcncDEfMc2ocRzXLO67bLFRNI4OX1aGBoPzsM5Y2T+/m1pldOgD+A==",
"dev": true
},
"node_modules/@types/d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==",
"dev": true
},
"node_modules/@types/d3-ease": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz",
"integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==",
"dev": true
},
"node_modules/@types/d3-interpolate": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
"integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==",
"dev": true,
"dependencies": {
"@types/d3-color": "*"
}
},
"node_modules/@types/d3-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz",
"integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==",
"dev": true
},
"node_modules/@types/d3-scale": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.3.tgz",
"integrity": "sha512-PATBiMCpvHJSMtZAMEhc2WyL+hnzarKzI6wAHYjhsonjWJYGq5BXTzQjv4l8m2jO183/4wZ90rKvSeT7o72xNQ==",
"dev": true,
"dependencies": {
"@types/d3-time": "*"
}
},
"node_modules/@types/d3-shape": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.1.tgz",
"integrity": "sha512-6Uh86YFF7LGg4PQkuO2oG6EMBRLuW9cbavUW46zkIO5kuS2PfTqo2o9SkgtQzguBHbLgNnU90UNsITpsX1My+A==",
"dev": true,
"dependencies": {
"@types/d3-path": "*"
}
},
"node_modules/@types/d3-time": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz",
"integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==",
"dev": true
},
"node_modules/@types/d3-timer": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz",
"integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==",
"dev": true
},
"node_modules/@types/eslint": {
"version": "8.21.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.1.tgz",
@@ -4282,6 +4346,12 @@
"integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==",
"dev": true
},
"node_modules/classnames": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==",
"dev": true
},
"node_modules/clean-css": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz",
@@ -4696,6 +4766,12 @@
"url": "https://github.com/sponsors/fb55"
}
},
"node_modules/css-unit-converter": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==",
"dev": true
},
"node_modules/css-what": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
@@ -4749,6 +4825,127 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
},
"node_modules/d3-array": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
"integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
"dev": true,
"dependencies": {
"internmap": "1 - 2"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
"dev": true,
"engines": {
"node": ">=12"
}
},
"node_modules/d3-ease": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
"dev": true,
"engines": {
"node": ">=12"
}
},
"node_modules/d3-format": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
"integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
"dev": true,
"engines": {
"node": ">=12"
}
},
"node_modules/d3-interpolate": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
"dev": true,
"dependencies": {
"d3-color": "1 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-path": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
"integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
"dev": true,
"engines": {
"node": ">=12"
}
},
"node_modules/d3-scale": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
"integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
"dev": true,
"dependencies": {
"d3-array": "2.10.0 - 3",
"d3-format": "1 - 3",
"d3-interpolate": "1.2.0 - 3",
"d3-time": "2.1.1 - 3",
"d3-time-format": "2 - 4"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-shape": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
"integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
"dev": true,
"dependencies": {
"d3-path": "^3.1.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-time": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
"integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
"dev": true,
"dependencies": {
"d3-array": "2 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-time-format": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
"integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
"dev": true,
"dependencies": {
"d3-time": "1 - 3"
},
"engines": {
"node": ">=12"
}
},
"node_modules/d3-timer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
"dev": true,
"engines": {
"node": ">=12"
}
},
"node_modules/damerau-levenshtein": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
@@ -4806,6 +5003,12 @@
"integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==",
"dev": true
},
"node_modules/decimal.js-light": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
"integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==",
"dev": true
},
"node_modules/dedent": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
@@ -6546,6 +6749,15 @@
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz",
"integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig=="
},
"node_modules/fast-equals": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz",
"integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/fast-glob": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz",
@@ -7506,6 +7718,15 @@
"node": ">= 0.4"
}
},
"node_modules/internmap": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
"integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
"dev": true,
"engines": {
"node": ">=12"
}
},
"node_modules/interpret": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz",
@@ -11700,6 +11921,12 @@
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true
},
"node_modules/react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==",
"dev": true
},
"node_modules/react-quill": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0.tgz",
@@ -11714,6 +11941,19 @@
"react-dom": "^16 || ^17 || ^18"
}
},
"node_modules/react-resize-detector": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-8.1.0.tgz",
"integrity": "sha512-S7szxlaIuiy5UqLhLL1KY3aoyGHbZzsTpYal9eYMwCyKqoqoVLCmIgAgNyIM1FhnP2KyBygASJxdhejrzjMb+w==",
"dev": true,
"dependencies": {
"lodash": "^4.17.21"
},
"peerDependencies": {
"react": "^16.0.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-router": {
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.1.tgz",
@@ -11744,6 +11984,46 @@
"react-dom": ">=16.8"
}
},
"node_modules/react-smooth": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.3.tgz",
"integrity": "sha512-yl4y3XiMorss7ayF5QnBiSprig0+qFHui8uh7Hgg46QX5O+aRMRKlfGGNGLHno35JkQSvSYY8eCWkBfHfrSHfg==",
"dev": true,
"dependencies": {
"fast-equals": "^5.0.0",
"react-transition-group": "2.9.0"
},
"peerDependencies": {
"prop-types": "^15.6.0",
"react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-smooth/node_modules/dom-helpers": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
"integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.1.2"
}
},
"node_modules/react-smooth/node_modules/react-transition-group": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
"integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
"dev": true,
"dependencies": {
"dom-helpers": "^3.4.0",
"loose-envify": "^1.4.0",
"prop-types": "^15.6.2",
"react-lifecycles-compat": "^3.0.4"
},
"peerDependencies": {
"react": ">=15.0.0",
"react-dom": ">=15.0.0"
}
},
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
@@ -11785,6 +12065,46 @@
"node": ">=8.10.0"
}
},
"node_modules/recharts": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/recharts/-/recharts-2.7.2.tgz",
"integrity": "sha512-HMKRBkGoOXHW+7JcRa6+MukPSifNtJlqbc+JreGVNA407VLE/vOP+8n3YYjprDVVIF9E2ZgwWnL3D7K/LUFzBg==",
"dev": true,
"dependencies": {
"classnames": "^2.2.5",
"eventemitter3": "^4.0.1",
"lodash": "^4.17.19",
"react-is": "^16.10.2",
"react-resize-detector": "^8.0.4",
"react-smooth": "^2.0.2",
"recharts-scale": "^0.4.4",
"reduce-css-calc": "^2.1.8",
"victory-vendor": "^36.6.8"
},
"engines": {
"node": ">=12"
},
"peerDependencies": {
"prop-types": "^15.6.0",
"react": "^16.0.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/recharts-scale": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz",
"integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==",
"dev": true,
"dependencies": {
"decimal.js-light": "^2.4.1"
}
},
"node_modules/recharts/node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"dev": true
},
"node_modules/rechoir": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
@@ -11810,6 +12130,22 @@
"node": ">=8"
}
},
"node_modules/reduce-css-calc": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
"integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
"dev": true,
"dependencies": {
"css-unit-converter": "^1.1.1",
"postcss-value-parser": "^3.3.0"
}
},
"node_modules/reduce-css-calc/node_modules/postcss-value-parser": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
"dev": true
},
"node_modules/regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
@@ -13440,6 +13776,28 @@
"node": ">= 0.8"
}
},
"node_modules/victory-vendor": {
"version": "36.6.11",
"resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.6.11.tgz",
"integrity": "sha512-nT8kCiJp8dQh8g991J/R5w5eE2KnO8EAIP0xocWlh9l2okngMWglOPoMZzJvek8Q1KUc4XE/mJxTZnvOB1sTYg==",
"dev": true,
"dependencies": {
"@types/d3-array": "^3.0.3",
"@types/d3-ease": "^3.0.0",
"@types/d3-interpolate": "^3.0.1",
"@types/d3-scale": "^4.0.2",
"@types/d3-shape": "^3.1.0",
"@types/d3-time": "^3.0.0",
"@types/d3-timer": "^3.0.0",
"d3-array": "^3.1.6",
"d3-ease": "^3.0.1",
"d3-interpolate": "^3.0.1",
"d3-scale": "^4.0.2",
"d3-shape": "^3.1.0",
"d3-time": "^3.0.0",
"d3-timer": "^3.0.1"
}
},
"node_modules/w3c-xmlserializer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
@@ -16009,6 +16367,69 @@
"@types/node": "*"
}
},
"@types/d3-array": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.5.tgz",
"integrity": "sha512-Qk7fpJ6qFp+26VeQ47WY0mkwXaiq8+76RJcncDEfMc2ocRzXLO67bLFRNI4OX1aGBoPzsM5Y2T+/m1pldOgD+A==",
"dev": true
},
"@types/d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==",
"dev": true
},
"@types/d3-ease": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz",
"integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA==",
"dev": true
},
"@types/d3-interpolate": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
"integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==",
"dev": true,
"requires": {
"@types/d3-color": "*"
}
},
"@types/d3-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz",
"integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg==",
"dev": true
},
"@types/d3-scale": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.3.tgz",
"integrity": "sha512-PATBiMCpvHJSMtZAMEhc2WyL+hnzarKzI6wAHYjhsonjWJYGq5BXTzQjv4l8m2jO183/4wZ90rKvSeT7o72xNQ==",
"dev": true,
"requires": {
"@types/d3-time": "*"
}
},
"@types/d3-shape": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.1.tgz",
"integrity": "sha512-6Uh86YFF7LGg4PQkuO2oG6EMBRLuW9cbavUW46zkIO5kuS2PfTqo2o9SkgtQzguBHbLgNnU90UNsITpsX1My+A==",
"dev": true,
"requires": {
"@types/d3-path": "*"
}
},
"@types/d3-time": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz",
"integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==",
"dev": true
},
"@types/d3-timer": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz",
"integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g==",
"dev": true
},
"@types/eslint": {
"version": "8.21.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.1.tgz",
@@ -17334,6 +17755,12 @@
"integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==",
"dev": true
},
"classnames": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==",
"dev": true
},
"clean-css": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz",
@@ -17655,6 +18082,12 @@
"nth-check": "^2.0.1"
}
},
"css-unit-converter": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==",
"dev": true
},
"css-what": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
@@ -17693,6 +18126,94 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
"integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
},
"d3-array": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
"integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
"dev": true,
"requires": {
"internmap": "1 - 2"
}
},
"d3-color": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
"dev": true
},
"d3-ease": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
"integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
"dev": true
},
"d3-format": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
"integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
"dev": true
},
"d3-interpolate": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
"dev": true,
"requires": {
"d3-color": "1 - 3"
}
},
"d3-path": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
"integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
"dev": true
},
"d3-scale": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
"integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
"dev": true,
"requires": {
"d3-array": "2.10.0 - 3",
"d3-format": "1 - 3",
"d3-interpolate": "1.2.0 - 3",
"d3-time": "2.1.1 - 3",
"d3-time-format": "2 - 4"
}
},
"d3-shape": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
"integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
"dev": true,
"requires": {
"d3-path": "^3.1.0"
}
},
"d3-time": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
"integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
"dev": true,
"requires": {
"d3-array": "2 - 3"
}
},
"d3-time-format": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
"integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
"dev": true,
"requires": {
"d3-time": "1 - 3"
}
},
"d3-timer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
"integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
"dev": true
},
"damerau-levenshtein": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
@@ -17732,6 +18253,12 @@
"integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==",
"dev": true
},
"decimal.js-light": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz",
"integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==",
"dev": true
},
"dedent": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
@@ -19020,6 +19547,12 @@
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz",
"integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig=="
},
"fast-equals": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.0.1.tgz",
"integrity": "sha512-WF1Wi8PwwSY7/6Kx0vKXtw8RwuSGoM1bvDaJbu7MxDlR1vovZjIAKrnzyrThgAjm6JDTu0fVgWXDlMGspodfoQ==",
"dev": true
},
"fast-glob": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.0.tgz",
@@ -19745,6 +20278,12 @@
"side-channel": "^1.0.4"
}
},
"internmap": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
"integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
"dev": true
},
"interpret": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz",
@@ -22834,6 +23373,12 @@
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==",
"dev": true
},
"react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==",
"dev": true
},
"react-quill": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0.tgz",
@@ -22844,6 +23389,15 @@
"quill": "^1.3.7"
}
},
"react-resize-detector": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-8.1.0.tgz",
"integrity": "sha512-S7szxlaIuiy5UqLhLL1KY3aoyGHbZzsTpYal9eYMwCyKqoqoVLCmIgAgNyIM1FhnP2KyBygASJxdhejrzjMb+w==",
"dev": true,
"requires": {
"lodash": "^4.17.21"
}
},
"react-router": {
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.8.1.tgz",
@@ -22861,6 +23415,39 @@
"react-router": "6.8.1"
}
},
"react-smooth": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/react-smooth/-/react-smooth-2.0.3.tgz",
"integrity": "sha512-yl4y3XiMorss7ayF5QnBiSprig0+qFHui8uh7Hgg46QX5O+aRMRKlfGGNGLHno35JkQSvSYY8eCWkBfHfrSHfg==",
"dev": true,
"requires": {
"fast-equals": "^5.0.0",
"react-transition-group": "2.9.0"
},
"dependencies": {
"dom-helpers": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz",
"integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==",
"dev": true,
"requires": {
"@babel/runtime": "^7.1.2"
}
},
"react-transition-group": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz",
"integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==",
"dev": true,
"requires": {
"dom-helpers": "^3.4.0",
"loose-envify": "^1.4.0",
"prop-types": "^15.6.2",
"react-lifecycles-compat": "^3.0.4"
}
}
}
},
"react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
@@ -22892,6 +23479,40 @@
"picomatch": "^2.2.1"
}
},
"recharts": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/recharts/-/recharts-2.7.2.tgz",
"integrity": "sha512-HMKRBkGoOXHW+7JcRa6+MukPSifNtJlqbc+JreGVNA407VLE/vOP+8n3YYjprDVVIF9E2ZgwWnL3D7K/LUFzBg==",
"dev": true,
"requires": {
"classnames": "^2.2.5",
"eventemitter3": "^4.0.1",
"lodash": "^4.17.19",
"react-is": "^16.10.2",
"react-resize-detector": "^8.0.4",
"react-smooth": "^2.0.2",
"recharts-scale": "^0.4.4",
"reduce-css-calc": "^2.1.8",
"victory-vendor": "^36.6.8"
},
"dependencies": {
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"dev": true
}
}
},
"recharts-scale": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/recharts-scale/-/recharts-scale-0.4.5.tgz",
"integrity": "sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==",
"dev": true,
"requires": {
"decimal.js-light": "^2.4.1"
}
},
"rechoir": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
@@ -22911,6 +23532,24 @@
"strip-indent": "^3.0.0"
}
},
"reduce-css-calc": {
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
"integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
"dev": true,
"requires": {
"css-unit-converter": "^1.1.1",
"postcss-value-parser": "^3.3.0"
},
"dependencies": {
"postcss-value-parser": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
"dev": true
}
}
},
"regenerator-runtime": {
"version": "0.13.11",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
@@ -24105,6 +24744,28 @@
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
"dev": true
},
"victory-vendor": {
"version": "36.6.11",
"resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.6.11.tgz",
"integrity": "sha512-nT8kCiJp8dQh8g991J/R5w5eE2KnO8EAIP0xocWlh9l2okngMWglOPoMZzJvek8Q1KUc4XE/mJxTZnvOB1sTYg==",
"dev": true,
"requires": {
"@types/d3-array": "^3.0.3",
"@types/d3-ease": "^3.0.0",
"@types/d3-interpolate": "^3.0.1",
"@types/d3-scale": "^4.0.2",
"@types/d3-shape": "^3.1.0",
"@types/d3-time": "^3.0.0",
"@types/d3-timer": "^3.0.0",
"d3-array": "^3.1.6",
"d3-ease": "^3.0.1",
"d3-interpolate": "^3.0.1",
"d3-scale": "^4.0.2",
"d3-shape": "^3.1.0",
"d3-time": "^3.0.0",
"d3-timer": "^3.0.1"
}
},
"w3c-xmlserializer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",

View File

@@ -49,6 +49,7 @@
"prettier": "^3.0.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"recharts": "^2.7.2",
"style-loader": "^3.3.3",
"ts-jest": "^29.0.5",
"ts-loader": "^9.4.2",

View File

@@ -3,18 +3,25 @@ import { ThemeProvider } from '@mui/material/styles';
import { Box } from '@mui/material';
import { theme } from 'src/styles/theme';
import { ToolMenu } from 'src/components/ToolMenu/ToolMenu';
import { SceneInput } from 'src/validation/SceneInput';
import {
SceneInput,
IconInput,
NodeInput,
ConnectorInput,
GroupInput
} from 'src/validation/SceneInput';
import { useSceneStore, Scene } from 'src/stores/useSceneStore';
import { GlobalStyles } from 'src/styles/GlobalStyles';
import { Renderer } from 'src/renderer/Renderer';
import { sceneInputtoScene, sceneToSceneInput } from 'src/utils';
import { DefaultLabelContainer } from 'src/renderer/components/Node/DefaultLabelContainer';
import { ItemControlsManager } from './components/ItemControls/ItemControlsManager';
interface Props {
initialScene: SceneInput;
onSceneUpdated?: (scene: SceneInput, prevScene: SceneInput) => void;
width?: number | string;
height: number | string;
height?: number | string;
}
const InnerApp = React.memo(
@@ -39,7 +46,12 @@ const InnerApp = React.memo(
}
);
const App = ({ initialScene, width, height, onSceneUpdated }: Props) => {
const Isoflow = ({
initialScene,
width,
height = 500,
onSceneUpdated
}: Props) => {
const sceneActions = useSceneStore((state) => {
return state.actions;
});
@@ -68,5 +80,15 @@ const useIsoflow = () => {
};
};
export { Scene, SceneInput, useIsoflow };
export default App;
export {
Scene,
SceneInput,
IconInput,
NodeInput,
GroupInput,
ConnectorInput,
useIsoflow,
DefaultLabelContainer
};
export default Isoflow;

View File

@@ -0,0 +1,17 @@
import React from 'react';
import Isoflow from 'src/Isoflow';
import { icons } from '../icons';
export const BasicEditor = () => {
return (
<Isoflow
initialScene={{
icons,
connectors: [],
groups: [],
nodes: []
}}
height="100%"
/>
);
};

View File

@@ -0,0 +1,74 @@
import React from 'react';
import Isoflow, { DefaultLabelContainer } from 'src/Isoflow';
import { Box, useTheme } from '@mui/material';
// eslint-disable-next-line import/no-extraneous-dependencies
import {
AreaChart,
Area,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer
} from 'recharts';
import { icons } from '../icons';
import graphData from './graphData';
const CustomLabel = () => {
const theme = useTheme();
return (
<Box
sx={{
width: '300px',
height: '125px',
pt: 2
}}
>
<ResponsiveContainer width="100%" height="100%">
<AreaChart
data={graphData}
margin={{
top: 0,
right: 0,
left: 0,
bottom: 0
}}
>
<CartesianGrid strokeDasharray="3 3" />
<YAxis width={25} />
<Tooltip />
<Area
type="monotone"
dataKey="uv"
fill={theme.customVars.diagramPalette.blue}
/>
</AreaChart>
</ResponsiveContainer>
</Box>
);
};
export const CustomNode = () => {
return (
<Isoflow
initialScene={{
icons,
connectors: [],
groups: [],
nodes: [
{
id: 'Node1',
label: 'Requests per minute',
labelElement: <CustomLabel />,
iconId: 'server',
position: {
x: 0,
y: 0
}
}
]
}}
height="100%"
/>
);
};

View File

@@ -0,0 +1,23 @@
export default [
{
uv: 40
},
{
uv: 30
},
{
uv: 20
},
{
uv: 27
},
{
uv: 18
},
{
uv: 23
},
{
uv: 34
}
];

16
src/examples/icons.ts Normal file
View File

@@ -0,0 +1,16 @@
import { IconInput } from 'src/Isoflow';
export const icons: IconInput[] = [
{
id: 'block',
name: 'Block',
url: 'https://isoflow.io/static/assets/icons/networking/primitive.svg',
category: 'Networking'
},
{
id: 'server',
name: 'Server',
url: 'https://isoflow.io/static/assets/icons/networking/server.svg',
category: 'Networking'
}
];

44
src/examples/index.tsx Normal file
View File

@@ -0,0 +1,44 @@
import React, { useState, useMemo } from 'react';
import { Box, Select, MenuItem, useTheme } from '@mui/material';
import { BasicEditor } from './BasicEditor/BasicEditor';
import { CustomNode } from './CustomNode/CustomNode';
const examples = [
{ name: 'Basic Editor', component: BasicEditor },
{ name: 'Custom Node Label', component: CustomNode }
];
export const Examples = () => {
const theme = useTheme();
const [currentExample, setCurrentExample] = useState(0);
const Example = useMemo(() => {
return examples[currentExample].component;
}, [currentExample]);
return (
<Box sx={{ width: '100vw', height: '100vh' }}>
<Box sx={{ width: '100%', height: '100%' }}>{Example && <Example />}</Box>
<Select
sx={{
position: 'absolute',
bottom: theme.customVars.appPadding.y,
right: theme.customVars.appPadding.x,
bgcolor: 'common.white'
}}
value={currentExample}
onChange={(e) => {
setCurrentExample(e.target.value as number);
}}
>
{examples.map((example, i) => {
return (
<MenuItem key={example.name} value={i}>
{example.name}
</MenuItem>
);
})}
</Select>
</Box>
);
};

View File

@@ -1,155 +1,27 @@
// This is a development entry point for the app.
// It is not used in production or included in the build.
import React, { useEffect, useCallback } from 'react';
import React from 'react';
import ReactDOM from 'react-dom/client';
import GlobalStyles from '@mui/material/GlobalStyles';
import type {
SceneInput,
NodeInput,
ConnectorInput,
IconInput,
GroupInput
} from 'src/validation/SceneInput';
import Isoflow, { useIsoflow } from './App';
const icons: IconInput[] = [
{
id: 'block',
name: 'Block',
url: 'https://isoflow.io/static/assets/icons/networking/primitive.svg',
category: 'Networking'
},
{
id: 'pyramid',
name: 'Pyramid',
url: 'https://isoflow.io/static/assets/icons/networking/pyramid.svg',
category: 'Networking'
},
{
id: 'sphere',
name: 'Sphere',
url: 'https://isoflow.io/static/assets/icons/networking/sphere.svg',
category: 'Networking'
},
{
id: 'diamond',
name: 'Diamond',
url: 'https://isoflow.io/static/assets/icons/networking/diamond.svg',
category: 'Networking'
},
{
id: 'cube',
name: 'Cube',
url: 'https://isoflow.io/static/assets/icons/networking/cube.svg'
},
{
id: 'pyramid',
name: 'Pyramid',
url: 'https://isoflow.io/static/assets/icons/networking/pyramid.svg',
category: 'Generic'
},
{
id: 'sphere',
name: 'Sphere',
url: 'https://isoflow.io/static/assets/icons/networking/sphere.svg',
category: 'Generic'
},
{
id: 'diamond',
name: 'Diamond',
url: 'https://isoflow.io/static/assets/icons/networking/diamond.svg',
category: 'Generic'
}
];
const connectors: ConnectorInput[] = [
{
id: 'Connector1',
label: 'Connector 1',
from: 'Node1',
to: 'Node2'
}
];
const groups: GroupInput[] = [
{
id: 'Group1',
label: 'Group 1',
nodeIds: ['Node1', 'Node2']
}
];
const nodes: NodeInput[] = [
{
id: 'Node1',
label: 'Node 1',
iconId: 'block',
position: {
x: 0,
y: 0
}
},
{
id: 'Node2',
label: 'Node 2',
iconId: 'pyramid',
position: {
x: 3,
y: 0
}
}
];
import { ThemeProvider, createTheme } from '@mui/material';
import { Examples } from './examples';
import { themeConfig } from './styles/theme';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
const DataLayer = () => {
const { updateNode } = useIsoflow();
const onSceneUpdated = useCallback((scene: SceneInput) => {
// console.log(scene);
}, []);
useEffect(() => {
const timer = setInterval(() => {
updateNode('Node1', { label: Date.now().toString() });
}, 1000);
return () => {
clearInterval(timer);
};
}, [updateNode]);
return (
<>
<GlobalStyles
styles={{
body: {
margin: 0
}
}}
/>
<Isoflow
initialScene={{
icons,
nodes,
connectors,
groups,
gridSize: {
width: 51,
height: 51
}
}}
height="100vh"
onSceneUpdated={onSceneUpdated}
/>
</>
);
};
root.render(
<React.StrictMode>
<DataLayer />
<GlobalStyles
styles={{
body: {
margin: 0
}
}}
/>
<ThemeProvider theme={createTheme({ ...themeConfig, palette: {} })}>
<Examples />
</ThemeProvider>
</React.StrictMode>
);

View File

@@ -0,0 +1,52 @@
import React, { useEffect } from 'react';
import { Box } from '@mui/material';
import { useLabelConnector } from './useLabelConnector';
interface Props {
labelHeight: number;
children: React.ReactNode;
parentContainer: paper.Group;
}
// TODO: Rename all `parentContainer` to `groupContainer`
export const DefaultLabelContainer = ({
children,
labelHeight,
parentContainer
}: Props) => {
const labelConnector = useLabelConnector();
const {
init: initLabelConnector,
updateHeight: updateLabelHeight,
destroy: destroyLabelConnector
} = labelConnector;
useEffect(() => {
const labelConnectorContainer = initLabelConnector();
parentContainer.addChild(labelConnectorContainer);
return () => {
destroyLabelConnector();
};
}, [initLabelConnector, destroyLabelConnector, parentContainer]);
useEffect(() => {
updateLabelHeight(labelHeight);
}, [labelHeight, updateLabelHeight]);
return (
<Box
sx={{
bgcolor: 'common.white',
border: '1px solid',
borderColor: 'grey.500',
borderRadius: 2,
overflow: 'hidden',
py: 1,
px: 1.5
}}
>
{children}
</Box>
);
};

View File

@@ -0,0 +1,20 @@
import React from 'react';
import { Box } from '@mui/material';
import { MarkdownEditor } from 'src/components/MarkdownEditor/MarkdownEditor';
interface Props {
label: string;
}
export const MarkdownLabel = ({ label }: Props) => {
return (
<Box
sx={{
maxWidth: 200,
maxHeight: 150
}}
>
<MarkdownEditor readOnly value={label} />
</Box>
);
};

View File

@@ -6,31 +6,35 @@ import { Coords } from 'src/utils/Coords';
import { useUiStateStore } from 'src/stores/useUiStateStore';
import { Node as NodeInterface } from 'src/stores/useSceneStore';
import { useNodeIcon } from './useNodeIcon';
import { NodeLabel } from './NodeLabel';
import { DefaultLabelContainer } from './DefaultLabelContainer';
import { useNodeTile } from './useNodeTile';
import { MarkdownLabel } from './LabelTypes/MarkdownLabel';
import {
getTilePosition,
getTileScreenPosition
} from '../../utils/gridHelpers';
import { useLabelConnector } from './useLabelConnector';
export interface NodeProps {
node: NodeInterface;
parentContainer: paper.Group;
}
const isEmptyLabel = (label: string) => label === '<p><br></p>' || label === '';
export const Node = ({ node, parentContainer }: NodeProps) => {
const [isFirstDisplay, setIsFirstDisplay] = useState(true);
const groupRef = useRef(new Group());
const labelRef = useRef<HTMLDivElement>();
const labelConnectorContainer = useRef(new Group());
const nodeIcon = useNodeIcon();
const labelConnector = useLabelConnector();
const nodeTile = useNodeTile();
const scroll = useUiStateStore((state) => state.scroll);
const zoom = useUiStateStore((state) => state.zoom);
const mode = useUiStateStore((state) => state.mode);
const scroll = useUiStateStore((state) => {
return state.scroll;
});
const zoom = useUiStateStore((state) => {
return state.zoom;
});
const mode = useUiStateStore((state) => {
return state.mode;
});
const [labelSize, setLabelSize] = useState({ width: 0, height: 0 });
const {
@@ -38,25 +42,19 @@ export const Node = ({ node, parentContainer }: NodeProps) => {
update: updateNodeIcon,
isLoaded: isIconLoaded
} = nodeIcon;
const {
init: initLabelConnector,
updateHeight: updateLabelHeight,
setVisible: setLabelConnectorVisible
} = labelConnector;
const { init: initNodeTile, updateColor, setActive } = nodeTile;
useEffect(() => {
const nodeIconContainer = initNodeIcon();
const labelConnectorContainer = initLabelConnector();
const nodeTileContainer = initNodeTile();
groupRef.current.removeChildren();
groupRef.current.addChild(nodeTileContainer);
groupRef.current.addChild(labelConnectorContainer);
groupRef.current.addChild(labelConnectorContainer.current);
groupRef.current.addChild(nodeIconContainer);
groupRef.current.pivot = nodeIconContainer.bounds.bottomCenter;
parentContainer.addChild(groupRef.current);
}, [initNodeIcon, parentContainer, initLabelConnector, initNodeTile]);
}, [initNodeIcon, parentContainer, initNodeTile]);
useEffect(() => {
updateNodeIcon(node.iconId);
@@ -98,19 +96,13 @@ export const Node = ({ node, parentContainer }: NodeProps) => {
}, [node.position, node.labelHeight, zoom, scroll.position, mode, labelSize]);
useEffect(() => {
setLabelConnectorVisible(!isEmptyLabel(node.label));
if (!labelRef.current) return;
setLabelSize({
width: labelRef.current.clientWidth ?? 0,
height: labelRef.current.clientHeight ?? 0
});
}, [node.label, setLabelConnectorVisible]);
useEffect(() => {
updateLabelHeight(node.labelHeight);
}, [node.labelHeight, updateLabelHeight]);
}, [node.label, node.labelElement]);
useEffect(() => {
updateColor(node.color);
@@ -120,8 +112,6 @@ export const Node = ({ node, parentContainer }: NodeProps) => {
setActive(node.isSelected);
}, [setActive, node.isSelected]);
if (!node.label) return null;
return (
<Box
ref={labelRef}
@@ -130,7 +120,15 @@ export const Node = ({ node, parentContainer }: NodeProps) => {
transformOrigin: 'bottom center'
}}
>
<NodeLabel label={node.label} />
{(node.labelElement || node.label) && (
<DefaultLabelContainer
labelHeight={node.labelHeight}
parentContainer={labelConnectorContainer.current}
>
{node.label && <MarkdownLabel label={node.label} />}
{node.labelElement !== undefined && node.labelElement}
</DefaultLabelContainer>
)}
</Box>
);
};

View File

@@ -1,25 +0,0 @@
import React from 'react';
import { Box } from '@mui/material';
import { MarkdownEditor } from 'src/components/MarkdownEditor/MarkdownEditor';
interface Props {
label: string;
}
export const NodeLabel = ({ label }: Props) => (
<Box
sx={{
bgcolor: 'common.white',
border: '1px solid',
borderColor: 'grey.500',
maxWidth: 200,
maxHeight: 150,
borderRadius: 2,
overflow: 'hidden',
py: 1,
px: 1.5
}}
>
<MarkdownEditor readOnly value={label} />
</Box>
);

View File

@@ -20,10 +20,6 @@ export const useLabelConnector = () => {
);
}, []);
const setVisible = useCallback((state: boolean) => {
containerRef.current.visible = state;
}, []);
const init = useCallback(() => {
containerRef.current.removeChildren();
@@ -42,10 +38,14 @@ export const useLabelConnector = () => {
return containerRef.current;
}, [theme.palette.grey]);
const destroy = useCallback(() => {
return containerRef.current.remove();
}, []);
return {
containerRef,
init,
updateHeight,
setVisible
destroy
};
};

View File

@@ -22,6 +22,7 @@ export interface Node {
labelHeight: number;
position: Coords;
isSelected: boolean;
labelElement?: React.ReactNode;
}
export interface Connector {

View File

@@ -1,4 +1,4 @@
import { createTheme } from '@mui/material';
import { createTheme, ThemeOptions } from '@mui/material';
interface CustomThemeVars {
appPadding: {
@@ -47,7 +47,7 @@ export const customVars: CustomThemeVars = {
}
};
export const theme = createTheme({
export const themeConfig: ThemeOptions = {
customVars,
typography: {
h5: {
@@ -88,4 +88,6 @@ export const theme = createTheme({
}
}
}
});
};
export const theme = createTheme(themeConfig);

View File

@@ -65,6 +65,7 @@ export const nodeInputToNode = (nodeInput: NodeInput): Node => {
type: SceneItemTypeEnum.NODE,
id: nodeInput.id,
label: nodeInput.label ?? NODE_DEFAULTS.label,
labelElement: nodeInput.labelElement,
labelHeight: nodeInput.labelHeight ?? NODE_DEFAULTS.labelHeight,
color: nodeInput.color ?? NODE_DEFAULTS.color,
iconId: nodeInput.iconId,

View File

@@ -34,10 +34,20 @@ export const groupInput = z.object({
nodeIds: z.array(z.string())
});
export const gridSizeInput = z
.object({
width: z.number(),
height: z.number()
})
.optional();
export type IconInput = z.infer<typeof iconInput>;
export type NodeInput = z.infer<typeof nodeInput>;
export type NodeInput = z.infer<typeof nodeInput> & {
labelElement?: React.ReactNode;
};
export type ConnectorInput = z.infer<typeof connectorInput>;
export type GroupInput = z.infer<typeof groupInput>;
export type GridSizeInput = z.infer<typeof gridSizeInput>;
export const findInvalidNode = (nodes: NodeInput[], icons: IconInput[]) => {
return nodes.find((node) => {
@@ -81,12 +91,7 @@ export const sceneInput = z
nodes: z.array(nodeInput),
connectors: z.array(connectorInput),
groups: z.array(groupInput),
gridSize: z
.object({
width: z.number(),
height: z.number()
})
.optional()
gridSize: gridSizeInput
})
.superRefine((scene, ctx) => {
const invalidNode = findInvalidNode(scene.nodes, scene.icons);
@@ -127,4 +132,10 @@ export const sceneInput = z
}
});
export type SceneInput = z.infer<typeof sceneInput>;
export type SceneInput = {
icons: IconInput[];
nodes: NodeInput[];
connectors: ConnectorInput[];
groups: GroupInput[];
gridSize?: GridSizeInput;
};