diff --git a/.eslintrc.cjs b/.eslintrc.cjs
index 13ac012..33736e7 100644
--- a/.eslintrc.cjs
+++ b/.eslintrc.cjs
@@ -19,7 +19,6 @@ module.exports = {
plugins: [
'only-warn',
'react',
- 'react-hooks',
'@typescript-eslint'
],
rules: {
@@ -30,7 +29,5 @@ module.exports = {
'@typescript-eslint/semi': ['warn', 'always'],
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'error',
- 'react-hooks/rules-of-hooks': 'error', // Checks rules of Hooks
- 'react-hooks/exhaustive-deps': 'warn' // Checks effect dependencies
}
};
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 2def8a6..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-*.drawio filter=lfs diff=lfs merge=lfs -text
diff --git a/docs/ComponentStructure.drawio b/docs/ComponentStructure.drawio
deleted file mode 100644
index 2fdcefc..0000000
--- a/docs/ComponentStructure.drawio
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:59a34bc3428280ecd661efa7b4756bf9f4930f36c077984a40e7fdc6983aeeff
-size 2063
diff --git a/index.html b/index.html
index d9f5a08..e0d1c84 100644
--- a/index.html
+++ b/index.html
@@ -3,7 +3,6 @@
-
Vite + React + TS
diff --git a/package-lock.json b/package-lock.json
index b7e9f41..285432c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,20 +9,18 @@
"version": "0.0.0",
"dependencies": {
"@heroicons/react": "^1.0.6",
+ "framer-motion": "^6.5.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
- "react-svg-pan-zoom": "^3.11.0",
- "react-window": "^1.8.7"
+ "react-svg-pan-zoom": "^3.11.0"
},
"devDependencies": {
- "@testing-library/dom": "^8.16.1",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^14.4.1",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"@types/react-svg-pan-zoom": "^3.3.5",
- "@types/react-window": "^1.8.5",
"@typescript-eslint/eslint-plugin": "^5.31.0",
"@typescript-eslint/parser": "^5.31.0",
"@vitejs/plugin-react": "^2.0.0",
@@ -33,10 +31,8 @@
"eslint-config-standard-with-typescript": "^22.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.2.4",
- "eslint-plugin-only-warn": "^1.0.3",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-react": "^7.30.1",
- "eslint-plugin-react-hooks": "^4.6.0",
"jsdom": "^20.0.0",
"postcss": "^8.4.14",
"sass": "^1.54.0",
@@ -425,6 +421,7 @@
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz",
"integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==",
+ "dev": true,
"dependencies": {
"regenerator-runtime": "^0.13.4"
},
@@ -480,6 +477,21 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@emotion/is-prop-valid": {
+ "version": "0.8.8",
+ "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
+ "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
+ "optional": true,
+ "dependencies": {
+ "@emotion/memoize": "0.7.4"
+ }
+ },
+ "node_modules/@emotion/memoize": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
+ "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
+ "optional": true
+ },
"node_modules/@eslint/eslintrc": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
@@ -602,6 +614,89 @@
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
+ "node_modules/@motionone/animation": {
+ "version": "10.13.1",
+ "resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.13.1.tgz",
+ "integrity": "sha512-dxQ+1wWxL6iFHDy1uv6hhcPjIdOg36eDT56jN4LI7Z5HZRyLpq8x1t7JFQclo/IEIb+6Bk4atmyinGFdXVECuA==",
+ "dependencies": {
+ "@motionone/easing": "^10.13.1",
+ "@motionone/types": "^10.13.0",
+ "@motionone/utils": "^10.13.1",
+ "tslib": "^2.3.1"
+ }
+ },
+ "node_modules/@motionone/animation/node_modules/tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ },
+ "node_modules/@motionone/dom": {
+ "version": "10.12.0",
+ "resolved": "https://registry.npmjs.org/@motionone/dom/-/dom-10.12.0.tgz",
+ "integrity": "sha512-UdPTtLMAktHiqV0atOczNYyDd/d8Cf5fFsd1tua03PqTwwCe/6lwhLSQ8a7TbnQ5SN0gm44N1slBfj+ORIhrqw==",
+ "dependencies": {
+ "@motionone/animation": "^10.12.0",
+ "@motionone/generators": "^10.12.0",
+ "@motionone/types": "^10.12.0",
+ "@motionone/utils": "^10.12.0",
+ "hey-listen": "^1.0.8",
+ "tslib": "^2.3.1"
+ }
+ },
+ "node_modules/@motionone/dom/node_modules/tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ },
+ "node_modules/@motionone/easing": {
+ "version": "10.13.1",
+ "resolved": "https://registry.npmjs.org/@motionone/easing/-/easing-10.13.1.tgz",
+ "integrity": "sha512-INEsInHHDHVgx0dp5qlXi1lMXBqYicgLMMSn3zfGzaIvcaEbI1Uz8BoyNV4BiclTupG7RYIh+T6BU83ZcEe74g==",
+ "dependencies": {
+ "@motionone/utils": "^10.13.1",
+ "tslib": "^2.3.1"
+ }
+ },
+ "node_modules/@motionone/easing/node_modules/tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ },
+ "node_modules/@motionone/generators": {
+ "version": "10.13.1",
+ "resolved": "https://registry.npmjs.org/@motionone/generators/-/generators-10.13.1.tgz",
+ "integrity": "sha512-+HK5u2YcNJCckTTqfOLgSVcrWv2z1dVwrSZEMVJuAh0EnWEWGDJRvMBoPc0cFf/osbkA2Rq9bH2+vP0Ex/D8uw==",
+ "dependencies": {
+ "@motionone/types": "^10.13.0",
+ "@motionone/utils": "^10.13.1",
+ "tslib": "^2.3.1"
+ }
+ },
+ "node_modules/@motionone/generators/node_modules/tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ },
+ "node_modules/@motionone/types": {
+ "version": "10.13.0",
+ "resolved": "https://registry.npmjs.org/@motionone/types/-/types-10.13.0.tgz",
+ "integrity": "sha512-qegk4qg8U1N9ZwAJ187BG3TkZz1k9LP/pvNtCSlqdq/PMUDKlCFG4ZnjJ481P0IOH/vIw1OzIbKIuyg0A3rk9g=="
+ },
+ "node_modules/@motionone/utils": {
+ "version": "10.13.1",
+ "resolved": "https://registry.npmjs.org/@motionone/utils/-/utils-10.13.1.tgz",
+ "integrity": "sha512-TjDPTIppaf3ofBXQv4ZzAketJgN0sclALXfZ6mfrkjJkOy83mLls9744F+6S+VKCpBmvbZcBY4PQfrfhAfeMtA==",
+ "dependencies": {
+ "@motionone/types": "^10.13.0",
+ "hey-listen": "^1.0.8",
+ "tslib": "^2.3.1"
+ }
+ },
+ "node_modules/@motionone/utils/node_modules/tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -650,9 +745,9 @@
"dev": true
},
"node_modules/@testing-library/dom": {
- "version": "8.17.1",
- "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.17.1.tgz",
- "integrity": "sha512-KnH2MnJUzmFNPW6RIKfd+zf2Wue8mEKX0M3cpX6aKl5ZXrJM1/c/Pc8c2xDNYQCnJO48Sm5ITbMXgqTr3h4jxQ==",
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.16.0.tgz",
+ "integrity": "sha512-uxF4zmnLHHDlmW4l+0WDjcgLVwCvH+OVLpD8Dfp+Bjfz85prwxWGbwXgJdLtkgjD0qfOzkJF9SmA6YZPsMYX4w==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.10.4",
@@ -984,15 +1079,6 @@
"@types/react": "*"
}
},
- "node_modules/@types/react-window": {
- "version": "1.8.5",
- "resolved": "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.5.tgz",
- "integrity": "sha512-V9q3CvhC9Jk9bWBOysPGaWy/Z0lxYcTXLtLipkt2cnRj1JOSFNF7wqGpkScSXMgBwC+fnVRg/7shwgddBG5ICw==",
- "dev": true,
- "dependencies": {
- "@types/react": "*"
- }
- },
"node_modules/@types/scheduler": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
@@ -2793,15 +2879,6 @@
"eslint": ">=7.0.0"
}
},
- "node_modules/eslint-plugin-only-warn": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/eslint-plugin-only-warn/-/eslint-plugin-only-warn-1.0.3.tgz",
- "integrity": "sha512-XQOX/TfLoLw6h8ky51d29uUjXRTQHqBGXPylDEmy5fe/w7LIOnp8MA24b1OSMEn9BQoKow1q3g1kLe5/9uBTvw==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/eslint-plugin-promise": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.0.tgz",
@@ -2842,18 +2919,6 @@
"eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
}
},
- "node_modules/eslint-plugin-react-hooks": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz",
- "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "peerDependencies": {
- "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
- }
- },
"node_modules/eslint-plugin-react/node_modules/doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
@@ -3266,6 +3331,44 @@
"url": "https://www.patreon.com/infusion"
}
},
+ "node_modules/framer-motion": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-6.5.1.tgz",
+ "integrity": "sha512-o1BGqqposwi7cgDrtg0dNONhkmPsUFDaLcKXigzuTFC5x58mE8iyTazxSudFzmT6MEyJKfjjU8ItoMe3W+3fiw==",
+ "dependencies": {
+ "@motionone/dom": "10.12.0",
+ "framesync": "6.0.1",
+ "hey-listen": "^1.0.8",
+ "popmotion": "11.0.3",
+ "style-value-types": "5.0.0",
+ "tslib": "^2.1.0"
+ },
+ "optionalDependencies": {
+ "@emotion/is-prop-valid": "^0.8.2"
+ },
+ "peerDependencies": {
+ "react": ">=16.8 || ^17.0.0 || ^18.0.0",
+ "react-dom": ">=16.8 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/framer-motion/node_modules/tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ },
+ "node_modules/framesync": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz",
+ "integrity": "sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/framesync/node_modules/tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -3503,6 +3606,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/hey-listen": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
+ "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
+ },
"node_modules/html-encoding-sniffer": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
@@ -4320,11 +4428,6 @@
"node": ">=12"
}
},
- "node_modules/memoize-one": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
- "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
- },
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -4733,6 +4836,22 @@
"node": ">=0.10.0"
}
},
+ "node_modules/popmotion": {
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.3.tgz",
+ "integrity": "sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==",
+ "dependencies": {
+ "framesync": "6.0.1",
+ "hey-listen": "^1.0.8",
+ "style-value-types": "5.0.0",
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/popmotion/node_modules/tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ },
"node_modules/postcss": {
"version": "8.4.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
@@ -5010,22 +5129,6 @@
"react": ">=17.0.0"
}
},
- "node_modules/react-window": {
- "version": "1.8.7",
- "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.7.tgz",
- "integrity": "sha512-JHEZbPXBpKMmoNO1bNhoXOOLg/ujhL/BU4IqVU9r8eQPcy5KQnGHIHDRkJ0ns9IM5+Aq5LNwt3j8t3tIrePQzA==",
- "dependencies": {
- "@babel/runtime": "^7.0.0",
- "memoize-one": ">=3.1.1 <6"
- },
- "engines": {
- "node": ">8.0.0"
- },
- "peerDependencies": {
- "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/read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@@ -5063,7 +5166,8 @@
"node_modules/regenerator-runtime": {
"version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
- "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
+ "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
+ "dev": true
},
"node_modules/regexp.prototype.flags": {
"version": "1.4.3",
@@ -5432,6 +5536,20 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/style-value-types": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-5.0.0.tgz",
+ "integrity": "sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA==",
+ "dependencies": {
+ "hey-listen": "^1.0.8",
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/style-value-types/node_modules/tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ },
"node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -6301,6 +6419,7 @@
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz",
"integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==",
+ "dev": true,
"requires": {
"regenerator-runtime": "^0.13.4"
}
@@ -6344,6 +6463,21 @@
"to-fast-properties": "^2.0.0"
}
},
+ "@emotion/is-prop-valid": {
+ "version": "0.8.8",
+ "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
+ "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
+ "optional": true,
+ "requires": {
+ "@emotion/memoize": "0.7.4"
+ }
+ },
+ "@emotion/memoize": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
+ "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
+ "optional": true
+ },
"@eslint/eslintrc": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
@@ -6442,6 +6576,99 @@
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
+ "@motionone/animation": {
+ "version": "10.13.1",
+ "resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.13.1.tgz",
+ "integrity": "sha512-dxQ+1wWxL6iFHDy1uv6hhcPjIdOg36eDT56jN4LI7Z5HZRyLpq8x1t7JFQclo/IEIb+6Bk4atmyinGFdXVECuA==",
+ "requires": {
+ "@motionone/easing": "^10.13.1",
+ "@motionone/types": "^10.13.0",
+ "@motionone/utils": "^10.13.1",
+ "tslib": "^2.3.1"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ }
+ }
+ },
+ "@motionone/dom": {
+ "version": "10.12.0",
+ "resolved": "https://registry.npmjs.org/@motionone/dom/-/dom-10.12.0.tgz",
+ "integrity": "sha512-UdPTtLMAktHiqV0atOczNYyDd/d8Cf5fFsd1tua03PqTwwCe/6lwhLSQ8a7TbnQ5SN0gm44N1slBfj+ORIhrqw==",
+ "requires": {
+ "@motionone/animation": "^10.12.0",
+ "@motionone/generators": "^10.12.0",
+ "@motionone/types": "^10.12.0",
+ "@motionone/utils": "^10.12.0",
+ "hey-listen": "^1.0.8",
+ "tslib": "^2.3.1"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ }
+ }
+ },
+ "@motionone/easing": {
+ "version": "10.13.1",
+ "resolved": "https://registry.npmjs.org/@motionone/easing/-/easing-10.13.1.tgz",
+ "integrity": "sha512-INEsInHHDHVgx0dp5qlXi1lMXBqYicgLMMSn3zfGzaIvcaEbI1Uz8BoyNV4BiclTupG7RYIh+T6BU83ZcEe74g==",
+ "requires": {
+ "@motionone/utils": "^10.13.1",
+ "tslib": "^2.3.1"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ }
+ }
+ },
+ "@motionone/generators": {
+ "version": "10.13.1",
+ "resolved": "https://registry.npmjs.org/@motionone/generators/-/generators-10.13.1.tgz",
+ "integrity": "sha512-+HK5u2YcNJCckTTqfOLgSVcrWv2z1dVwrSZEMVJuAh0EnWEWGDJRvMBoPc0cFf/osbkA2Rq9bH2+vP0Ex/D8uw==",
+ "requires": {
+ "@motionone/types": "^10.13.0",
+ "@motionone/utils": "^10.13.1",
+ "tslib": "^2.3.1"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ }
+ }
+ },
+ "@motionone/types": {
+ "version": "10.13.0",
+ "resolved": "https://registry.npmjs.org/@motionone/types/-/types-10.13.0.tgz",
+ "integrity": "sha512-qegk4qg8U1N9ZwAJ187BG3TkZz1k9LP/pvNtCSlqdq/PMUDKlCFG4ZnjJ481P0IOH/vIw1OzIbKIuyg0A3rk9g=="
+ },
+ "@motionone/utils": {
+ "version": "10.13.1",
+ "resolved": "https://registry.npmjs.org/@motionone/utils/-/utils-10.13.1.tgz",
+ "integrity": "sha512-TjDPTIppaf3ofBXQv4ZzAketJgN0sclALXfZ6mfrkjJkOy83mLls9744F+6S+VKCpBmvbZcBY4PQfrfhAfeMtA==",
+ "requires": {
+ "@motionone/types": "^10.13.0",
+ "hey-listen": "^1.0.8",
+ "tslib": "^2.3.1"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ }
+ }
+ },
"@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -6481,9 +6708,9 @@
"dev": true
},
"@testing-library/dom": {
- "version": "8.17.1",
- "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.17.1.tgz",
- "integrity": "sha512-KnH2MnJUzmFNPW6RIKfd+zf2Wue8mEKX0M3cpX6aKl5ZXrJM1/c/Pc8c2xDNYQCnJO48Sm5ITbMXgqTr3h4jxQ==",
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.16.0.tgz",
+ "integrity": "sha512-uxF4zmnLHHDlmW4l+0WDjcgLVwCvH+OVLpD8Dfp+Bjfz85prwxWGbwXgJdLtkgjD0qfOzkJF9SmA6YZPsMYX4w==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.10.4",
@@ -6749,15 +6976,6 @@
"@types/react": "*"
}
},
- "@types/react-window": {
- "version": "1.8.5",
- "resolved": "https://registry.npmjs.org/@types/react-window/-/react-window-1.8.5.tgz",
- "integrity": "sha512-V9q3CvhC9Jk9bWBOysPGaWy/Z0lxYcTXLtLipkt2cnRj1JOSFNF7wqGpkScSXMgBwC+fnVRg/7shwgddBG5ICw==",
- "dev": true,
- "requires": {
- "@types/react": "*"
- }
- },
"@types/scheduler": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
@@ -8036,12 +8254,6 @@
"semver": "^7.3.7"
}
},
- "eslint-plugin-only-warn": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/eslint-plugin-only-warn/-/eslint-plugin-only-warn-1.0.3.tgz",
- "integrity": "sha512-XQOX/TfLoLw6h8ky51d29uUjXRTQHqBGXPylDEmy5fe/w7LIOnp8MA24b1OSMEn9BQoKow1q3g1kLe5/9uBTvw==",
- "dev": true
- },
"eslint-plugin-promise": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.0.tgz",
@@ -8099,13 +8311,6 @@
}
}
},
- "eslint-plugin-react-hooks": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz",
- "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
- "dev": true,
- "requires": {}
- },
"eslint-scope": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
@@ -8305,6 +8510,42 @@
"integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
"dev": true
},
+ "framer-motion": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-6.5.1.tgz",
+ "integrity": "sha512-o1BGqqposwi7cgDrtg0dNONhkmPsUFDaLcKXigzuTFC5x58mE8iyTazxSudFzmT6MEyJKfjjU8ItoMe3W+3fiw==",
+ "requires": {
+ "@emotion/is-prop-valid": "^0.8.2",
+ "@motionone/dom": "10.12.0",
+ "framesync": "6.0.1",
+ "hey-listen": "^1.0.8",
+ "popmotion": "11.0.3",
+ "style-value-types": "5.0.0",
+ "tslib": "^2.1.0"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ }
+ }
+ },
+ "framesync": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/framesync/-/framesync-6.0.1.tgz",
+ "integrity": "sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==",
+ "requires": {
+ "tslib": "^2.1.0"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ }
+ }
+ },
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -8469,6 +8710,11 @@
"has-symbols": "^1.0.2"
}
},
+ "hey-listen": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
+ "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
+ },
"html-encoding-sniffer": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz",
@@ -9067,11 +9313,6 @@
"sourcemap-codec": "^1.4.8"
}
},
- "memoize-one": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
- "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q=="
- },
"merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -9369,6 +9610,24 @@
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
"dev": true
},
+ "popmotion": {
+ "version": "11.0.3",
+ "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.3.tgz",
+ "integrity": "sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==",
+ "requires": {
+ "framesync": "6.0.1",
+ "hey-listen": "^1.0.8",
+ "style-value-types": "5.0.0",
+ "tslib": "^2.1.0"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ }
+ }
+ },
"postcss": {
"version": "8.4.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
@@ -9537,15 +9796,6 @@
"transformation-matrix": "^2.11.1"
}
},
- "react-window": {
- "version": "1.8.7",
- "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.7.tgz",
- "integrity": "sha512-JHEZbPXBpKMmoNO1bNhoXOOLg/ujhL/BU4IqVU9r8eQPcy5KQnGHIHDRkJ0ns9IM5+Aq5LNwt3j8t3tIrePQzA==",
- "requires": {
- "@babel/runtime": "^7.0.0",
- "memoize-one": ">=3.1.1 <6"
- }
- },
"read-cache": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
@@ -9577,7 +9827,8 @@
"regenerator-runtime": {
"version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
- "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
+ "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
+ "dev": true
},
"regexp.prototype.flags": {
"version": "1.4.3",
@@ -9834,6 +10085,22 @@
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true
},
+ "style-value-types": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-5.0.0.tgz",
+ "integrity": "sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA==",
+ "requires": {
+ "hey-listen": "^1.0.8",
+ "tslib": "^2.1.0"
+ },
+ "dependencies": {
+ "tslib": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz",
+ "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
+ }
+ }
+ },
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
diff --git a/package.json b/package.json
index 5fdcfa7..1c45135 100644
--- a/package.json
+++ b/package.json
@@ -14,10 +14,10 @@
},
"dependencies": {
"@heroicons/react": "^1.0.6",
+ "framer-motion": "^6.5.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
- "react-svg-pan-zoom": "^3.11.0",
- "react-window": "^1.8.7"
+ "react-svg-pan-zoom": "^3.11.0"
},
"devDependencies": {
"@testing-library/dom": "^8.16.1",
@@ -27,7 +27,6 @@
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"@types/react-svg-pan-zoom": "^3.3.5",
- "@types/react-window": "^1.8.5",
"@typescript-eslint/eslint-plugin": "^5.31.0",
"@typescript-eslint/parser": "^5.31.0",
"@vitejs/plugin-react": "^2.0.0",
@@ -41,7 +40,6 @@
"eslint-plugin-only-warn": "^1.0.3",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-react": "^7.30.1",
- "eslint-plugin-react-hooks": "^4.6.0",
"jsdom": "^20.0.0",
"postcss": "^8.4.14",
"sass": "^1.54.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index be1cc19..10ead3b 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -9,7 +9,6 @@ specifiers:
'@types/react': ^18.0.15
'@types/react-dom': ^18.0.6
'@types/react-svg-pan-zoom': ^3.3.5
- '@types/react-window': ^1.8.5
'@typescript-eslint/eslint-plugin': ^5.31.0
'@typescript-eslint/parser': ^5.31.0
'@vitejs/plugin-react': ^2.0.0
@@ -23,13 +22,12 @@ specifiers:
eslint-plugin-only-warn: ^1.0.3
eslint-plugin-promise: ^6.0.0
eslint-plugin-react: ^7.30.1
- eslint-plugin-react-hooks: ^4.6.0
+ framer-motion: ^6.5.1
jsdom: ^20.0.0
postcss: ^8.4.14
react: ^18.2.0
react-dom: ^18.2.0
react-svg-pan-zoom: ^3.11.0
- react-window: ^1.8.7
sass: ^1.54.0
tailwindcss: ^3.1.7
typescript: ^4.6.4
@@ -38,10 +36,10 @@ specifiers:
dependencies:
'@heroicons/react': 1.0.6_react@18.2.0
+ framer-motion: 6.5.1_biqbaboplfbrettd7655fr4n2y
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
react-svg-pan-zoom: 3.11.0_react@18.2.0
- react-window: 1.8.7_biqbaboplfbrettd7655fr4n2y
devDependencies:
'@testing-library/dom': 8.16.1
@@ -51,7 +49,6 @@ devDependencies:
'@types/react': 18.0.17
'@types/react-dom': 18.0.6
'@types/react-svg-pan-zoom': 3.3.5
- '@types/react-window': 1.8.5
'@typescript-eslint/eslint-plugin': 5.32.0_iosr3hrei2tubxveewluhu5lhy
'@typescript-eslint/parser': 5.32.0_qugx7qdu5zevzvxaiqyxfiwquq
'@vitejs/plugin-react': 2.0.0_vite@3.0.4
@@ -65,7 +62,6 @@ devDependencies:
eslint-plugin-only-warn: 1.0.3
eslint-plugin-promise: 6.0.0_eslint@8.21.0
eslint-plugin-react: 7.30.1_eslint@8.21.0
- eslint-plugin-react-hooks: 4.6.0_eslint@8.21.0
jsdom: 20.0.0
postcss: 8.4.16
sass: 1.54.3
@@ -316,6 +312,7 @@ packages:
engines: {node: '>=6.9.0'}
dependencies:
regenerator-runtime: 0.13.9
+ dev: true
/@babel/template/7.18.10:
resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==}
@@ -353,6 +350,19 @@ packages:
to-fast-properties: 2.0.0
dev: true
+ /@emotion/is-prop-valid/0.8.8:
+ resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==}
+ requiresBuild: true
+ dependencies:
+ '@emotion/memoize': 0.7.4
+ dev: false
+ optional: true
+
+ /@emotion/memoize/0.7.4:
+ resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==}
+ dev: false
+ optional: true
+
/@esbuild/linux-loong64/0.14.54:
resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==}
engines: {node: '>=12'}
@@ -451,6 +461,53 @@ packages:
'@jridgewell/sourcemap-codec': 1.4.14
dev: true
+ /@motionone/animation/10.13.2:
+ resolution: {integrity: sha512-YGWss58IR2X4lOjW89rv1Q+/Nq/QhfltaggI7i8sZTpKC1yUvM+XYDdvlRpWc6dk8LviMBrddBJAlLdbaqeRmw==}
+ dependencies:
+ '@motionone/easing': 10.13.2
+ '@motionone/types': 10.13.2
+ '@motionone/utils': 10.13.2
+ tslib: 2.4.0
+ dev: false
+
+ /@motionone/dom/10.12.0:
+ resolution: {integrity: sha512-UdPTtLMAktHiqV0atOczNYyDd/d8Cf5fFsd1tua03PqTwwCe/6lwhLSQ8a7TbnQ5SN0gm44N1slBfj+ORIhrqw==}
+ dependencies:
+ '@motionone/animation': 10.13.2
+ '@motionone/generators': 10.13.2
+ '@motionone/types': 10.13.2
+ '@motionone/utils': 10.13.2
+ hey-listen: 1.0.8
+ tslib: 2.4.0
+ dev: false
+
+ /@motionone/easing/10.13.2:
+ resolution: {integrity: sha512-3HqctS5NyDfDQ+8+cZqc3Pu7I6amFCt9zDUjcozHyFXHh4PKYHK4+GJDFjJIS8bCAF2BrJmpmduDQ2V7lFEYeQ==}
+ dependencies:
+ '@motionone/utils': 10.13.2
+ tslib: 2.4.0
+ dev: false
+
+ /@motionone/generators/10.13.2:
+ resolution: {integrity: sha512-QMoXV1MXEEhR6D3dct/RMMS1FwJlAsW+kMPbFGzBA4NbweblgeYQCft9DcDAVpV9wIwD6qvlBG9u99sOXLfHiA==}
+ dependencies:
+ '@motionone/types': 10.13.2
+ '@motionone/utils': 10.13.2
+ tslib: 2.4.0
+ dev: false
+
+ /@motionone/types/10.13.2:
+ resolution: {integrity: sha512-yYV4q5v5F0iADhab4wHfqaRJnM/eVtQLjUPhyEcS72aUz/xyOzi09GzD/Gu+K506BDfqn5eULIilUI77QNaqhw==}
+ dev: false
+
+ /@motionone/utils/10.13.2:
+ resolution: {integrity: sha512-6Lw5bDA/w7lrPmT/jYWQ76lkHlHs9fl2NZpJ22cVy1kKDdEH+Cl1U6hMTpdphO6VQktQ6v2APngag91WBKLqlA==}
+ dependencies:
+ '@motionone/types': 10.13.2
+ hey-listen: 1.0.8
+ tslib: 2.4.0
+ dev: false
+
/@nodelib/fs.scandir/2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@@ -586,12 +643,6 @@ packages:
'@types/react': 18.0.17
dev: true
- /@types/react-window/1.8.5:
- resolution: {integrity: sha512-V9q3CvhC9Jk9bWBOysPGaWy/Z0lxYcTXLtLipkt2cnRj1JOSFNF7wqGpkScSXMgBwC+fnVRg/7shwgddBG5ICw==}
- dependencies:
- '@types/react': 18.0.17
- dev: true
-
/@types/react/18.0.17:
resolution: {integrity: sha512-38ETy4tL+rn4uQQi7mB81G7V1g0u2ryquNmsVIOKUAEIDK+3CUjZ6rSRpdvS99dNBnkLFL83qfmtLacGOTIhwQ==}
dependencies:
@@ -1689,15 +1740,6 @@ packages:
eslint: 8.21.0
dev: true
- /eslint-plugin-react-hooks/4.6.0_eslint@8.21.0:
- resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==}
- engines: {node: '>=10'}
- peerDependencies:
- eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0
- dependencies:
- eslint: 8.21.0
- dev: true
-
/eslint-plugin-react/7.30.1_eslint@8.21.0:
resolution: {integrity: sha512-NbEvI9jtqO46yJA3wcRF9Mo0lF9T/jhdHqhCHXiXtD+Zcb98812wvokjWpU7Q4QH5edo6dmqrukxVvWWXHlsUg==}
engines: {node: '>=4'}
@@ -1944,6 +1986,30 @@ packages:
resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
dev: true
+ /framer-motion/6.5.1_biqbaboplfbrettd7655fr4n2y:
+ resolution: {integrity: sha512-o1BGqqposwi7cgDrtg0dNONhkmPsUFDaLcKXigzuTFC5x58mE8iyTazxSudFzmT6MEyJKfjjU8ItoMe3W+3fiw==}
+ peerDependencies:
+ react: '>=16.8 || ^17.0.0 || ^18.0.0'
+ react-dom: '>=16.8 || ^17.0.0 || ^18.0.0'
+ dependencies:
+ '@motionone/dom': 10.12.0
+ framesync: 6.0.1
+ hey-listen: 1.0.8
+ popmotion: 11.0.3
+ react: 18.2.0
+ react-dom: 18.2.0_react@18.2.0
+ style-value-types: 5.0.0
+ tslib: 2.4.0
+ optionalDependencies:
+ '@emotion/is-prop-valid': 0.8.8
+ dev: false
+
+ /framesync/6.0.1:
+ resolution: {integrity: sha512-fUY88kXvGiIItgNC7wcTOl0SNRCVXMKSWW2Yzfmn7EKNc+MpCzcz9DhdHcdjbrtN3c6R4H5dTY2jiCpPdysEjA==}
+ dependencies:
+ tslib: 2.4.0
+ dev: false
+
/fs.realpath/1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
dev: true
@@ -2095,6 +2161,10 @@ packages:
function-bind: 1.1.1
dev: true
+ /hey-listen/1.0.8:
+ resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==}
+ dev: false
+
/html-encoding-sniffer/3.0.0:
resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==}
engines: {node: '>=12'}
@@ -2479,10 +2549,6 @@ packages:
sourcemap-codec: 1.4.8
dev: true
- /memoize-one/5.2.1:
- resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==}
- dev: false
-
/merge2/1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
@@ -2753,6 +2819,15 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
+ /popmotion/11.0.3:
+ resolution: {integrity: sha512-Y55FLdj3UxkR7Vl3s7Qr4e9m0onSnP8W7d/xQLsoJM40vs6UKHFdygs6SWryasTZYqugMjm3BepCF4CWXDiHgA==}
+ dependencies:
+ framesync: 6.0.1
+ hey-listen: 1.0.8
+ style-value-types: 5.0.0
+ tslib: 2.4.0
+ dev: false
+
/postcss-import/14.1.0_postcss@8.4.16:
resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==}
engines: {node: '>=10.0.0'}
@@ -2912,19 +2987,6 @@ packages:
transformation-matrix: 2.12.0
dev: false
- /react-window/1.8.7_biqbaboplfbrettd7655fr4n2y:
- resolution: {integrity: sha512-JHEZbPXBpKMmoNO1bNhoXOOLg/ujhL/BU4IqVU9r8eQPcy5KQnGHIHDRkJ0ns9IM5+Aq5LNwt3j8t3tIrePQzA==}
- engines: {node: '>8.0.0'}
- peerDependencies:
- 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
- dependencies:
- '@babel/runtime': 7.18.9
- memoize-one: 5.2.1
- react: 18.2.0
- react-dom: 18.2.0_react@18.2.0
- dev: false
-
/react/18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
engines: {node: '>=0.10.0'}
@@ -2954,6 +3016,7 @@ packages:
/regenerator-runtime/0.13.9:
resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==}
+ dev: true
/regexp.prototype.flags/1.4.3:
resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==}
@@ -3164,6 +3227,13 @@ packages:
engines: {node: '>=8'}
dev: true
+ /style-value-types/5.0.0:
+ resolution: {integrity: sha512-08yq36Ikn4kx4YU6RD7jWEv27v4V+PUsOGa4n/as8Et3CuODMJQ00ENeAVXAeydX4Z2j1XHZF1K2sX4mGl18fA==}
+ dependencies:
+ hey-listen: 1.0.8
+ tslib: 2.4.0
+ dev: false
+
/supports-color/5.5.0:
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
engines: {node: '>=4'}
@@ -3282,6 +3352,10 @@ packages:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
dev: true
+ /tslib/2.4.0:
+ resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==}
+ dev: false
+
/tsutils/3.21.0_typescript@4.7.4:
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'}
diff --git a/public/Interfaces.d.ts b/public/Interfaces.d.ts
deleted file mode 100644
index 5a466a1..0000000
--- a/public/Interfaces.d.ts
+++ /dev/null
@@ -1,65 +0,0 @@
-declare interface IHistoryState {
- LastAction: string
- MainContainer: IContainerModel
- SelectedContainer: IContainerModel | null
- SelectedContainerId: string
- TypeCounters: Record
-}
-
-declare interface IAvailableContainer {
- Type: string
- Width: number
- Height: number
- XPositionReference?: XPositionReference
- Style: React.CSSProperties
-}
-
-declare interface IEditorState {
- history: IHistoryState[]
- historyCurrentStep: number
- configuration: IConfiguration
-}
-
-declare interface IConfiguration {
- AvailableContainers: IAvailableContainer[]
- AvailableSymbols: IAvailableSymbol[]
- MainContainer: IAvailableContainer
-}
-
-declare interface IContainerModel {
- children: IContainerModel[]
- parent: IContainerModel | null
- properties: IProperties
- userData: Record
-}
-
-declare interface IProperties extends React.CSSProperties {
- id: string
- parentId: string | null
- x: number
- y: number
- isRigidBody: boolean
- XPositionReference?: XPositionReference
-}
-
-declare enum XPositionReference {
- Left,
- Center,
- Right
-}
-
-declare interface IAvailableSymbol {
- Name: string
- XPositionReference: XPositionReference
- Image: IImage
- Width: number
- Height: number
-}
-
-declare interface IImage {
- Name: string
- Url: string
- Base64Image: string
- Svg: string
-}
-
diff --git a/public/style.css b/public/style.css
deleted file mode 100644
index a732b5f..0000000
--- a/public/style.css
+++ /dev/null
@@ -1,6 +0,0 @@
-html,
-body,
-#root {
- width: 100%;
- height: 100%;
-}
diff --git a/src/Components/API/api.ts b/src/Components/API/api.ts
index 9acea24..e113cc9 100644
--- a/src/Components/API/api.ts
+++ b/src/Components/API/api.ts
@@ -1,10 +1,10 @@
-import { IConfiguration } from '../../Interfaces/IConfiguration';
+import { Configuration } from '../../Interfaces/Configuration';
/**
* Fetch the configuration from the API
* @returns {Configation} The model of the configuration for the application
*/
-export async function fetchConfiguration(): Promise {
+export async function fetchConfiguration(): Promise {
const url = `${import.meta.env.VITE_API_URL}`;
// The test library cannot use the Fetch API
// @ts-expect-error
@@ -15,7 +15,7 @@ export async function fetchConfiguration(): Promise {
})
.then(async(response) =>
await response.json()
- ) as IConfiguration;
+ ) as Configuration;
}
return await new Promise((resolve) => {
const xhr = new XMLHttpRequest();
diff --git a/src/Components/App/App.scss b/src/Components/App/App.scss
index e69de29..2cb61ee 100644
--- a/src/Components/App/App.scss
+++ b/src/Components/App/App.scss
@@ -0,0 +1,6 @@
+html,
+body,
+#root {
+ width: 100%;
+ height: 100%;
+}
\ No newline at end of file
diff --git a/src/Components/App/App.tsx b/src/Components/App/App.tsx
index c85d322..c25c37e 100644
--- a/src/Components/App/App.tsx
+++ b/src/Components/App/App.tsx
@@ -1,9 +1,8 @@
import React, { useEffect, useState } from 'react';
import './App.scss';
import { MainMenu } from '../MainMenu/MainMenu';
-import { ContainerModel } from '../../Interfaces/IContainerModel';
-import Editor from '../Editor/Editor';
-import { IEditorState } from '../../Interfaces/IEditorState';
+import { ContainerModel } from '../../Interfaces/ContainerModel';
+import Editor, { IEditorState } from '../Editor/Editor';
import { LoadState } from './Load';
import { LoadEditor, NewEditor } from './MenuActions';
import { DEFAULT_CONFIG, DEFAULT_MAINCONTAINER_PROPS } from '../../utils/default';
diff --git a/src/Components/App/Load.ts b/src/Components/App/Load.ts
index 909dfc9..b5459c7 100644
--- a/src/Components/App/Load.ts
+++ b/src/Components/App/Load.ts
@@ -1,6 +1,6 @@
import { Dispatch, SetStateAction } from 'react';
import { Revive } from '../../utils/saveload';
-import { IEditorState } from '../../Interfaces/IEditorState';
+import { IEditorState } from '../Editor/Editor';
export function LoadState(
editorState: IEditorState,
diff --git a/src/Components/App/MenuActions.ts b/src/Components/App/MenuActions.ts
index c144acc..2669c1a 100644
--- a/src/Components/App/MenuActions.ts
+++ b/src/Components/App/MenuActions.ts
@@ -1,8 +1,8 @@
import { Dispatch, SetStateAction } from 'react';
-import { IConfiguration } from '../../Interfaces/IConfiguration';
-import { ContainerModel } from '../../Interfaces/IContainerModel';
+import { Configuration } from '../../Interfaces/Configuration';
+import { ContainerModel } from '../../Interfaces/ContainerModel';
import { fetchConfiguration } from '../API/api';
-import { IEditorState } from '../../Interfaces/IEditorState';
+import { IEditorState } from '../Editor/Editor';
import { LoadState } from './Load';
export function NewEditor(
@@ -11,7 +11,7 @@ export function NewEditor(
): void {
// Fetch the configuration from the API
fetchConfiguration()
- .then((configuration: IConfiguration) => {
+ .then((configuration: Configuration) => {
// Set the main container from the given properties of the API
const MainContainer = new ContainerModel(
null,
@@ -23,7 +23,6 @@ export function NewEditor(
width: configuration.MainContainer.Width,
height: configuration.MainContainer.Height,
isRigidBody: false,
- isAnchor: false,
fillOpacity: 0,
stroke: 'black'
}
diff --git a/src/Components/Bar/Bar.tsx b/src/Components/Bar/Bar.tsx
index 77cb259..1738a3f 100644
--- a/src/Components/Bar/Bar.tsx
+++ b/src/Components/Bar/Bar.tsx
@@ -15,7 +15,7 @@ export const BAR_WIDTH = 64; // 4rem
export const Bar: React.FC = (props) => {
return (
-
+
child.properties.isRigidBody && !child.properties.isAnchor
- );
-
- const overlappingContainers = getOverlappingContainers(container, rigidBodies);
- for (const overlappingContainer of overlappingContainers) {
- constraintBodyInsideUnallocatedWidth(overlappingContainer);
- }
- return container;
-}
-
-/**
- * Returns the overlapping containers with container
- * @param container A container
- * @param containers A list of containers
- * @returns A list of overlapping containers
- */
-function getOverlappingContainers(
- container: IContainerModel,
- containers: IContainerModel[]
-): IContainerModel[] {
- const min1 = container.properties.x;
- const max1 = container.properties.x + Number(container.properties.width);
- const overlappingContainers: IContainerModel[] = [];
- for (const other of containers) {
- if (other === container) {
- continue;
- }
-
- const min2 = other.properties.x;
- const max2 = other.properties.x + Number(other.properties.width);
- const isOverlapping = Math.min(max1, max2) - Math.max(min1, min2) > 0;
-
- if (!isOverlapping) {
- continue;
- }
-
- overlappingContainers.push(other);
- }
- return overlappingContainers;
-}
diff --git a/src/Components/Editor/Behaviors/RigidBodyBehaviors.ts b/src/Components/Editor/Behaviors/RigidBodyBehaviors.ts
deleted file mode 100644
index eabec85..0000000
--- a/src/Components/Editor/Behaviors/RigidBodyBehaviors.ts
+++ /dev/null
@@ -1,312 +0,0 @@
-/**
- * @module RigidBodyBehaviors
- * Apply the following contraints to the `container` :
- * - The container must be kept inside its parent
- * - The container must find an unallocated space within the parent
- * If the contraints fails, an error message will be returned
- */
-
-import { IContainerModel } from '../../../Interfaces/IContainerModel';
-import { ISizePointer } from '../../../Interfaces/ISizePointer';
-
-/**
- * "Transform the container into a rigid body"
- * Apply the following contraints to the `container` :
- * - The container must be kept inside its parent
- * - The container must find an unallocated space within the parent
- * If the contraints fails, an error message will be returned
- * @param container Container to apply its rigid body properties
- * @returns A rigid body container
- */
-export function RecalculatePhysics(
- container: IContainerModel
-): IContainerModel {
- container = constraintBodyInsideParent(container);
- container = constraintBodyInsideUnallocatedWidth(container);
- return container;
-}
-
-/**
- * Limit a rect inside a parent rect by applying the following rules :
- * it cannot be bigger than the parent
- * it cannot go out of bound
- * Mutates and returns the container
- * @param container
- * @returns Updated container
- */
-function constraintBodyInsideParent(
- container: IContainerModel
-): IContainerModel {
- if (container.parent === null || container.parent === undefined) {
- return container;
- }
-
- const parentProperties = container.parent.properties;
- const parentWidth = Number(parentProperties.width);
- const parentHeight = Number(parentProperties.height);
-
- return constraintBodyInsideSpace(container, 0, 0, parentWidth, parentHeight);
-}
-
-/**
- * Limit a container inside a rectangle
- * Mutates and returns the container
- * @param container A container
- * @param x x of top left of the rectangle
- * @param y y of top left of the rectangle
- * @param width width of the rectangle
- * @param height height of the rectangle
- * @returns Updated container
- */
-function constraintBodyInsideSpace(
- container: IContainerModel,
- x: number,
- y: number,
- width: number,
- height: number
-): IContainerModel {
- const containerProperties = container.properties;
- const containerX = Number(containerProperties.x);
- const containerY = Number(containerProperties.y);
- const containerWidth = Number(containerProperties.width);
- const containerHeight = Number(containerProperties.height);
-
- // Check size bigger than parent
- const isBodyLargerThanParent = containerWidth > width;
- const isBodyTallerThanParentHeight = containerHeight > height;
- if (isBodyLargerThanParent || isBodyTallerThanParentHeight) {
- if (isBodyLargerThanParent) {
- containerProperties.x = x;
- containerProperties.width = width;
- }
- if (isBodyTallerThanParentHeight) {
- containerProperties.y = y;
- containerProperties.height = height;
- }
- return container;
- }
-
- // Check horizontal out of bound
- if (containerX < x) {
- containerProperties.x = x;
- }
- if (containerX + containerWidth > x + width) {
- containerProperties.x = x + width - containerWidth;
- }
-
- // Check vertical out of bound
- if (containerY < y) {
- containerProperties.y = y;
- }
- if (containerY + containerHeight > y + height) {
- containerProperties.y = y + height - containerHeight;
- }
-
- return container;
-}
-
-/**
- * Constraint the container inside unallocated width/space of the parent container
- * If there is no unalloacted width/space, an error will be thrown
- * Mutates and returns the container
- * @param container
- * @returns Updated container
- */
-export function constraintBodyInsideUnallocatedWidth(
- container: IContainerModel
-): IContainerModel {
- if (container.parent === null) {
- return container;
- }
-
- // Get the available spaces of the parent
- const availableWidths = getAvailableWidths(container.parent, container);
- const containerX = Number(container.properties.x);
- const containerWidth = Number(container.properties.width);
-
- // Check if there is still some space
- if (availableWidths.length === 0) {
- throw new Error(
- 'No available space found on the parent container. Try to free the parent a little before placing it inside.'
- );
- }
-
- const middle = containerX + containerWidth / 2;
- // Sort the available width to find the space with the closest position
- availableWidths.sort(
- (width1, width2) => {
- let compared1X = width1.x;
- if (width1.x < containerX) {
- compared1X = width1.x + width1.width - containerWidth;
- }
-
- let compared2X = width2.x;
- if (width2.x < containerX) {
- compared2X = width2.x + width2.width - containerWidth;
- }
-
- return Math.abs(compared1X - middle) - Math.abs(compared2X - middle);
- }
- );
-
- // Check if the container actually fit inside
- // It will usually fit if it was alrady fitting
- const availableWidthFound = availableWidths.find((width) =>
- isFitting(container, width)
- );
-
- if (availableWidthFound === undefined) {
- // Otherwise, it is possible that it does not fit
- // There is two way to reach this part of the code
- // 1) Enable isRigidBody such as width > availableWidth.width
- // 2) Resize a container such as width > availableWidth.width
-
- // We want the container to fit automatically inside the available space
- // even if it means to resize the container
- // The end goal is that the code never show the error message no matter what action is done
- // TODO: Actually give an option to not fit and show the error message shown below
- const availableWidth = availableWidths[0];
- container.properties.x = availableWidth.x;
- container.properties.width = availableWidth.width;
- // throw new Error('[constraintBodyInsideUnallocatedWidth] BIGERR: No available space found on the parent container, even though there is some.');
- return container;
- }
-
- return constraintBodyInsideSpace(
- container,
- availableWidthFound.x,
- 0,
- availableWidthFound.width,
- Number(container.parent.properties.height)
- );
-}
-
-/**
- * Get the unallocated widths inside a container
- * An allocated width is defined by its the widths of the children that are rigid bodies.
- * An example of this allocation system is the disk space of an hard drive
- * (except the fact that disk space is divided by block).
- * @param container Container where to find an available width
- * @param exception Container to exclude of the widths (since a container will be moved, it might need to be excluded)
- * @returns {ISizePointer[]} Array of unallocated widths (x=position of the unallocated space, width=size of the allocated space)
- */
-function getAvailableWidths(
- container: IContainerModel,
- exception: IContainerModel
-): ISizePointer[] {
- // Initialize the first size pointer
- // which takes full width of the available space
- const x = 0;
- const width = Number(container.properties.width);
- let unallocatedSpaces: ISizePointer[] = [{ x, width }];
-
- // We will only uses containers that also are rigid or are anchors
- const solidBodies = container.children.filter(
- (child) => child.properties.isRigidBody || child.properties.isAnchor
- );
-
- for (const child of solidBodies) {
- // Ignore the exception
- if (child === exception) {
- continue;
- }
- const childX = child.properties.x;
- const childWidth = Number(child.properties.width);
-
- // get the space of the child that is inside the parent
- let newUnallocatedSpace: ISizePointer[] = [];
-
- // We will iterate on a mutable variable in order to divide it
- for (const unallocatedSpace of unallocatedSpaces) {
- // In order to find unallocated space,
- // We need to calculate the overlap between the two containers
- // We only works with widths meaning in 1D (with lines)
- const newUnallocatedWidths = getAvailableWidthsTwoLines(
- unallocatedSpace.x,
- unallocatedSpace.x + unallocatedSpace.width,
- childX,
- childX + childWidth
- );
-
- // Concat the new list of SizePointer pointing to availables spaces
- newUnallocatedSpace = newUnallocatedSpace.concat(newUnallocatedWidths);
- }
- // Finally update the availables spaces found, loop again with it
- unallocatedSpaces = newUnallocatedSpace;
- }
-
- return unallocatedSpaces;
-}
-
-/**
- * Returns the unallocated widths between two lines in 1D
- * @param unalloctedSpaceLeft left of the first line
- * @param unallocatedSpaceRight rigth of the first line
- * @param rectLeft left of the second line
- * @param rectRight right of the second line
- * @returns Available widths
- */
-function getAvailableWidthsTwoLines(
- unalloctedSpaceLeft: number,
- unallocatedSpaceRight: number,
- rectLeft: number,
- rectRight: number
-): ISizePointer[] {
- if (unallocatedSpaceRight < rectLeft ||
- unalloctedSpaceLeft > rectRight
- ) {
- // object 1 and 2 are not overlapping
- return [{
- x: unalloctedSpaceLeft,
- width: unallocatedSpaceRight - unalloctedSpaceLeft
- }];
- }
-
- if (rectLeft < unalloctedSpaceLeft && rectRight > unallocatedSpaceRight) {
- // object 2 is overlapping full width
- return [];
- }
-
- if (unalloctedSpaceLeft >= rectLeft) {
- // object 2 is partially overlapping on the left
- return [
- {
- x: rectRight,
- width: unallocatedSpaceRight - rectRight
- }
- ];
- }
-
- if (rectRight >= unallocatedSpaceRight) {
- // object 2 is partially overlapping on the right
- return [
- {
- x: unalloctedSpaceLeft,
- width: rectRight - unalloctedSpaceLeft
- }
- ];
- }
-
- // object 2 is overlapping in the middle
- return [
- {
- x: unalloctedSpaceLeft,
- width: rectLeft - unalloctedSpaceLeft
- },
- {
- x: rectRight,
- width: unallocatedSpaceRight - rectRight
- }
- ];
-}
-
-/**
- * Check if a container can fit inside a size space
- * @param container Container to check
- * @param sizePointer Size space to check
- * @returns
- */
-const isFitting = (
- container: IContainerModel,
- sizePointer: ISizePointer
-): boolean => Number(container.properties.width) <= sizePointer.width;
diff --git a/src/Components/Editor/ContainerOperations.ts b/src/Components/Editor/ContainerOperations.ts
index f1736fc..ea4db42 100644
--- a/src/Components/Editor/ContainerOperations.ts
+++ b/src/Components/Editor/ContainerOperations.ts
@@ -1,10 +1,10 @@
import { Dispatch, SetStateAction } from 'react';
-import { IHistoryState } from '../../Interfaces/IHistoryState';
-import { IConfiguration } from '../../Interfaces/IConfiguration';
-import { ContainerModel, IContainerModel } from '../../Interfaces/IContainerModel';
+import { HistoryState } from '../../Interfaces/HistoryState';
+import { Configuration } from '../../Interfaces/Configuration';
+import { ContainerModel, IContainerModel } from '../../Interfaces/ContainerModel';
import { findContainerById } from '../../utils/itertools';
import { getCurrentHistory } from './Editor';
-import IProperties from '../../Interfaces/IProperties';
+import { SizePointer } from '../../Interfaces/SizePointer';
/**
* Select a container
@@ -12,9 +12,9 @@ import IProperties from '../../Interfaces/IProperties';
*/
export function SelectContainer(
container: ContainerModel,
- fullHistory: IHistoryState[],
+ fullHistory: HistoryState[],
historyCurrentStep: number,
- setHistory: Dispatch>,
+ setHistory: Dispatch>,
setHistoryCurrentStep: Dispatch>
): void {
const history = getCurrentHistory(fullHistory, historyCurrentStep);
@@ -27,30 +27,21 @@ export function SelectContainer(
throw new Error('[SelectContainer] Cannot find container among children of main container!');
}
- history.push({
- LastAction: `Select ${selectedContainer.properties.id}`,
+ setHistory(history.concat([{
+ LastAction: `Select container ${selectedContainer.properties.id}`,
MainContainer: mainContainerClone,
SelectedContainer: selectedContainer,
SelectedContainerId: selectedContainer.properties.id,
TypeCounters: Object.assign({}, current.TypeCounters)
- });
- setHistory(history);
- setHistoryCurrentStep(history.length - 1);
+ }]));
+ setHistoryCurrentStep(history.length);
}
-/**
- * Delete a container
- * @param containerId containerId of the container to delete
- * @param fullHistory History of the editor
- * @param historyCurrentStep Current step
- * @param setHistory State setter for History
- * @param setHistoryCurrentStep State setter for current step
- */
export function DeleteContainer(
containerId: string,
- fullHistory: IHistoryState[],
+ fullHistory: HistoryState[],
historyCurrentStep: number,
- setHistory: Dispatch>,
+ setHistory: Dispatch>,
setHistoryCurrentStep: Dispatch>
): void {
const history = getCurrentHistory(fullHistory, historyCurrentStep);
@@ -63,58 +54,43 @@ export function DeleteContainer(
throw new Error(`[DeleteContainer] Tried to delete a container that is not present in the main container: ${containerId}`);
}
- if (container === mainContainerClone ||
- container.parent === undefined ||
- container.parent === null) {
+ if (container === mainContainerClone) {
// TODO: Implement alert
throw new Error('[DeleteContainer] Tried to delete the main container! Deleting the main container is not allowed!');
}
if (container === null || container === undefined) {
- throw new Error('[DeleteContainer] Container model was not found among children of the main container!');
+ throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
}
- const index = container.parent.children.indexOf(container);
- if (index > -1) {
- container.parent.children.splice(index, 1);
- } else {
- throw new Error('[DeleteContainer] Could not find container among parent\'s children');
+ if (container.parent != null) {
+ const index = container.parent.children.indexOf(container);
+ if (index > -1) {
+ container.parent.children.splice(index, 1);
+ }
}
- // Select the previous container
- // or select the one above
- const SelectedContainer = findContainerById(mainContainerClone, current.SelectedContainerId) ??
- container.parent.children.at(index - 1) ??
- container.parent;
- const SelectedContainerId = SelectedContainer.properties.id;
-
- history.push({
- LastAction: `Delete ${containerId}`,
+ setHistory(history.concat([{
+ LastAction: `Delete container ${containerId}`,
MainContainer: mainContainerClone,
- SelectedContainer,
- SelectedContainerId,
+ SelectedContainer: null,
+ SelectedContainerId: '',
TypeCounters: Object.assign({}, current.TypeCounters)
- });
- setHistory(history);
- setHistoryCurrentStep(history.length - 1);
+ }]));
+ setHistoryCurrentStep(history.length);
}
/**
* Add a new container to a selected container
* @param type The type of container
- * @param configuration Configuration of the App
- * @param fullHistory History of the editor
- * @param historyCurrentStep Current step
- * @param setHistory State setter for History
- * @param setHistoryCurrentStep State setter for current step
* @returns void
*/
export function AddContainerToSelectedContainer(
type: string,
- configuration: IConfiguration,
- fullHistory: IHistoryState[],
+ configuration: Configuration,
+ fullHistory: HistoryState[],
historyCurrentStep: number,
- setHistory: Dispatch>,
+ setHistory: Dispatch>,
setHistoryCurrentStep: Dispatch>
): void {
const history = getCurrentHistory(fullHistory, historyCurrentStep);
@@ -138,26 +114,14 @@ export function AddContainerToSelectedContainer(
);
}
-/**
- * Create and add a new container at `index` in children of parent of `parentId`
- * @param index Index where to insert to the new container
- * @param type Type of container
- * @param parentId Parent in which to insert the new container
- * @param configuration Configuration of the app
- * @param fullHistory History of the editor
- * @param historyCurrentStep Current step
- * @param setHistory State setter of History
- * @param setHistoryCurrentStep State setter of the current step
- * @returns void
- */
export function AddContainer(
index: number,
type: string,
parentId: string,
- configuration: IConfiguration,
- fullHistory: IHistoryState[],
+ configuration: Configuration,
+ fullHistory: HistoryState[],
historyCurrentStep: number,
- setHistory: Dispatch>,
+ setHistory: Dispatch>,
setHistoryCurrentStep: Dispatch>
): void {
const history = getCurrentHistory(fullHistory, historyCurrentStep);
@@ -206,23 +170,19 @@ export function AddContainer(
}
}
- const defaultProperties: IProperties = {
- id: `${type}-${count}`,
- parentId: parentClone.properties.id,
- x,
- y: 0,
- width: properties.Width,
- height: parentClone.properties.height,
- isRigidBody: false,
- isAnchor: false,
- XPositionReference: properties.XPositionReference,
- ...properties.Style
- };
-
// Create the container
const newContainer = new ContainerModel(
parentClone,
- defaultProperties,
+ {
+ id: `${type}-${count}`,
+ parentId: parentClone.properties.id,
+ x,
+ y: 0,
+ width: properties?.Width,
+ height: parentClone.properties.height,
+ isRigidBody: false,
+ ...properties.Style
+ },
[],
{
type
@@ -237,13 +197,278 @@ export function AddContainer(
}
// Update the state
- history.push({
+ setHistory(history.concat([{
LastAction: 'Add container',
MainContainer: clone,
SelectedContainer: parentClone,
SelectedContainerId: parentClone.properties.id,
TypeCounters: newCounters
- });
- setHistory(history);
- setHistoryCurrentStep(history.length - 1);
+ }]));
+ setHistoryCurrentStep(history.length);
+}
+
+/**
+ * Handled the property change event in the properties form
+ * @param key Property name
+ * @param value New value of the property
+ * @returns void
+ */
+export function OnPropertyChange(
+ key: string,
+ value: string | number | boolean,
+ fullHistory: HistoryState[],
+ historyCurrentStep: number,
+ setHistory: Dispatch>,
+ setHistoryCurrentStep: Dispatch>
+): void {
+ const history = getCurrentHistory(fullHistory, historyCurrentStep);
+ const current = history[history.length - 1];
+
+ if (current.SelectedContainer === null ||
+ current.SelectedContainer === undefined) {
+ throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
+ }
+
+ if (parent === null) {
+ const selectedContainerClone: IContainerModel = structuredClone(current.SelectedContainer);
+ (selectedContainerClone.properties as any)[key] = value;
+ setHistory(history.concat([{
+ LastAction: 'Change property of main',
+ MainContainer: selectedContainerClone,
+ SelectedContainer: selectedContainerClone,
+ SelectedContainerId: selectedContainerClone.properties.id,
+ TypeCounters: Object.assign({}, current.TypeCounters)
+ }]));
+ setHistoryCurrentStep(history.length);
+ return;
+ }
+
+ const mainContainerClone: IContainerModel = structuredClone(current.MainContainer);
+ const container: ContainerModel | undefined = findContainerById(mainContainerClone, current.SelectedContainer.properties.id);
+
+ if (container === null || container === undefined) {
+ throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
+ }
+
+ (container.properties as any)[key] = value;
+
+ if (container.properties.isRigidBody) {
+ RecalculatePhysics(container);
+ }
+
+ setHistory(history.concat([{
+ LastAction: `Change property of container ${container.properties.id}`,
+ MainContainer: mainContainerClone,
+ SelectedContainer: container,
+ SelectedContainerId: container.properties.id,
+ TypeCounters: Object.assign({}, current.TypeCounters)
+ }]));
+ setHistoryCurrentStep(history.length);
+}
+
+// TODO put this in a different file
+
+export function RecalculatePhysics(container: IContainerModel): IContainerModel {
+ container = constraintBodyInsideParent(container);
+ container = constraintBodyInsideUnallocatedWidth(container);
+ return container;
+}
+
+/**
+ * Limit a rect inside a parent rect by applying the following rules :
+ * it cannot be bigger than the parent
+ * it cannot go out of bound
+ * @param container
+ * @returns
+ */
+function constraintBodyInsideParent(container: IContainerModel): IContainerModel {
+ if (container.parent === null || container.parent === undefined) {
+ return container;
+ }
+
+ const parentProperties = container.parent.properties;
+ const parentWidth = Number(parentProperties.width);
+ const parentHeight = Number(parentProperties.height);
+
+ return constraintBodyInsideSpace(container, 0, 0, parentWidth, parentHeight);
+}
+
+function constraintBodyInsideSpace(
+ container: IContainerModel,
+ x: number,
+ y: number,
+ width: number,
+ height: number
+): IContainerModel {
+ const containerProperties = container.properties;
+ const containerX = Number(containerProperties.x);
+ const containerY = Number(containerProperties.y);
+ const containerWidth = Number(containerProperties.width);
+ const containerHeight = Number(containerProperties.height);
+
+ // Check size bigger than parent
+ const isBodyLargerThanParent = containerWidth > width;
+ const isBodyTallerThanParentHeight = containerHeight > height;
+ if (isBodyLargerThanParent || isBodyTallerThanParentHeight) {
+ if (isBodyLargerThanParent) {
+ containerProperties.x = x;
+ containerProperties.width = width;
+ }
+ if (isBodyTallerThanParentHeight) {
+ containerProperties.y = y;
+ containerProperties.height = height;
+ }
+ return container;
+ }
+
+ // Check horizontal out of bound
+ if (containerX < x) {
+ containerProperties.x = x;
+ }
+ if (containerX + containerWidth > width) {
+ containerProperties.x = x + width - containerWidth;
+ }
+
+ // Check vertical out of bound
+ if (containerY < y) {
+ containerProperties.y = y;
+ }
+ if (containerY + containerHeight > height) {
+ containerProperties.y = y + height - containerHeight;
+ }
+
+ return container;
+}
+
+/**
+ * Get the unallocated widths inside a container
+ * An allocated width is defined by its the widths of the children that are rigid bodies.
+ * An example of this allocation system is the disk space
+ * (except the fact that disk space is divided by block).
+ * @param container
+ * @returns {SizePointer[]} Array of unallocated widths (x=position of the unallocated space, width=size of the allocated space)
+ */
+function getAvailableWidths(container: IContainerModel, exception: IContainerModel): SizePointer[] {
+ const x = 0;
+ const width = Number(container.properties.width);
+ let unallocatedSpaces: SizePointer[] = [{ x, width }];
+
+ const rigidBodies = container.children.filter(child => child.properties.isRigidBody);
+ for (const child of rigidBodies) {
+ if (child === exception) {
+ continue;
+ }
+
+ // get the space of the child that is inside the parent
+ let newUnallocatedSpace: SizePointer[] = [];
+ for (const unallocatedSpace of unallocatedSpaces) {
+ const newUnallocatedWidths = getAvailableWidthsTwoLines(
+ unallocatedSpace.x,
+ unallocatedSpace.x + unallocatedSpace.width,
+ child.properties.x,
+ child.properties.x + Number(child.properties.width));
+ newUnallocatedSpace = newUnallocatedSpace.concat(newUnallocatedWidths);
+ }
+ unallocatedSpaces = newUnallocatedSpace;
+ }
+
+ return unallocatedSpaces;
+}
+
+/**
+ * Returns the unallocated widths between two lines in 1D
+ * @param min1 left of the first line
+ * @param max1 rigth of the first line
+ * @param min2 left of the second line
+ * @param max2 right of the second line
+ * @returns Available widths
+ */
+function getAvailableWidthsTwoLines(min1: number, max1: number, min2: number, max2: number): SizePointer[] {
+ if (min2 < min1 && max2 > max1) {
+ // object 2 is overlapping full width
+ return [];
+ }
+
+ if (min1 >= min2) {
+ // object 2 is partially overlapping on the left
+ return [{
+ x: max2,
+ width: max1 - max2
+ }];
+ }
+
+ if (max2 >= max1) {
+ // object 2 is partially overlapping on the right
+ return [{
+ x: min2,
+ width: max2 - min1
+ }];
+ }
+
+ // object 2 is overlapping in the middle
+ return [
+ {
+ x: min1,
+ width: min2 - min1
+ },
+ {
+ x: min2,
+ width: max1 - max2
+ }
+ ];
+}
+
+/**
+ *
+ * @param container
+ * @returns
+ */
+function constraintBodyInsideUnallocatedWidth(container: IContainerModel): IContainerModel {
+ if (container.parent === null) {
+ return container;
+ }
+
+ const availableWidths = getAvailableWidths(container.parent, container);
+ const containerX = Number(container.properties.x);
+
+ // Sort the available width
+ availableWidths
+ .sort((width1, width2) => Math.abs(width1.x - containerX) - Math.abs(width2.x - containerX));
+
+ if (availableWidths.length === 0) {
+ throw new Error('No available space found on the parent container. Try to free the parent a little before placing it inside.');
+ }
+
+ const availableWidthFound = availableWidths.find(
+ width => isFitting(container, width)
+ );
+
+ if (availableWidthFound === undefined) {
+ // There is two way to reach this part of the code
+ // 1) toggle the isRigidBody such as width > availableWidth.width
+ // 2) resize a container such as width > availableWidth.width
+ // We want the container to fit automatically inside the available space
+ // even if it means to resize the container
+ // The end goal is that the code never show the error message no matter what action is done
+ // TODO: Actually give an option to not fit and show the error message shown below
+ const availableWidth = availableWidths[0];
+ container.properties.x = availableWidth.x;
+ container.properties.width = availableWidth.width;
+ // throw new Error('[constraintBodyInsideUnallocatedWidth] BIGERR: No available space found on the parent container, even though there is some.');
+ return container;
+ }
+
+ return constraintBodyInsideSpace(
+ container,
+ availableWidthFound.x,
+ 0,
+ availableWidthFound.width,
+ Number(container.parent.properties.height)
+ );
+}
+
+function isFitting(container: IContainerModel, sizePointer: SizePointer): boolean {
+ const containerWidth = Number(container.properties.width);
+
+ return containerWidth <= sizePointer.width;
}
diff --git a/src/Components/Editor/Editor.tsx b/src/Components/Editor/Editor.tsx
index 3a728e3..ad27c22 100644
--- a/src/Components/Editor/Editor.tsx
+++ b/src/Components/Editor/Editor.tsx
@@ -1,35 +1,31 @@
-import React, { useRef } from 'react';
+import React from 'react';
import './Editor.scss';
-import { IConfiguration } from '../../Interfaces/IConfiguration';
+import { Configuration } from '../../Interfaces/Configuration';
import { SVG } from '../SVG/SVG';
-import { IHistoryState } from '../../Interfaces/IHistoryState';
+import { HistoryState } from '../../Interfaces/HistoryState';
import { UI } from '../UI/UI';
-import { SelectContainer, DeleteContainer, AddContainerToSelectedContainer, AddContainer } from './ContainerOperations';
+import { SelectContainer, DeleteContainer, OnPropertyChange, AddContainerToSelectedContainer, AddContainer } from './ContainerOperations';
import { SaveEditorAsJSON, SaveEditorAsSVG } from './Save';
import { onKeyDown } from './Shortcuts';
-import { OnPropertyChange, OnPropertiesSubmit } from './PropertiesOperations';
-import EditorEvents from '../../Events/EditorEvents';
-import { IEditorState } from '../../Interfaces/IEditorState';
-import { MAX_HISTORY } from '../../utils/default';
interface IEditorProps {
- configuration: IConfiguration
- history: IHistoryState[]
+ configuration: Configuration
+ history: HistoryState[]
historyCurrentStep: number
}
-export const getCurrentHistory = (history: IHistoryState[], historyCurrentStep: number): IHistoryState[] =>
- history.slice(
- Math.max(0, history.length - MAX_HISTORY), // change this to 0 for unlimited (not recommanded because of overflow)
- historyCurrentStep + 1
- );
+export interface IEditorState {
+ history: HistoryState[]
+ historyCurrentStep: number
+ configuration: Configuration
+}
-export const getCurrentHistoryState = (history: IHistoryState[], historyCurrentStep: number): IHistoryState => history[historyCurrentStep];
+export const getCurrentHistory = (history: HistoryState[], historyCurrentStep: number): HistoryState[] => history.slice(0, historyCurrentStep + 1);
+export const getCurrentHistoryState = (history: HistoryState[], historyCurrentStep: number): HistoryState => history[historyCurrentStep];
const Editor: React.FunctionComponent = (props) => {
- const [history, setHistory] = React.useState(structuredClone(props.history));
+ const [history, setHistory] = React.useState(structuredClone(props.history));
const [historyCurrentStep, setHistoryCurrentStep] = React.useState(props.historyCurrentStep);
- const editorRef = useRef(null);
React.useEffect(() => {
const onKeyUp = (event: KeyboardEvent): void => onKeyDown(
@@ -41,37 +37,15 @@ const Editor: React.FunctionComponent = (props) => {
window.addEventListener('keyup', onKeyUp);
- const events = EditorEvents;
- const editorState: IEditorState = {
- history,
- historyCurrentStep,
- configuration: props.configuration
- };
-
- const funcs = new Map void>();
- for (const event of events) {
- const func = (): void => event.func(editorState);
- editorRef.current?.addEventListener(event.name, func);
- funcs.set(event.name, func);
- }
-
return () => {
window.removeEventListener('keyup', onKeyUp);
-
- for (const event of events) {
- const func = funcs.get(event.name);
- if (func === undefined) {
- continue;
- }
- editorRef.current?.removeEventListener(event.name, func);
- }
};
});
const configuration = props.configuration;
const current = getCurrentHistoryState(history, historyCurrentStep);
return (
-
+
= (props) => {
setHistory,
setHistoryCurrentStep
)}
- OnPropertiesSubmit={(event, properties) => OnPropertiesSubmit(
- event,
- properties,
- history,
- historyCurrentStep,
- setHistory,
- setHistoryCurrentStep
- )}
AddContainerToSelectedContainer={(type) => AddContainerToSelectedContainer(
type,
configuration,
diff --git a/src/Components/Editor/PropertiesOperations.ts b/src/Components/Editor/PropertiesOperations.ts
deleted file mode 100644
index 4bd4c2d..0000000
--- a/src/Components/Editor/PropertiesOperations.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-import { Dispatch, SetStateAction } from 'react';
-import { IContainerModel, ContainerModel } from '../../Interfaces/IContainerModel';
-import { IHistoryState } from '../../Interfaces/IHistoryState';
-import IProperties from '../../Interfaces/IProperties';
-import { findContainerById } from '../../utils/itertools';
-import { getCurrentHistory } from './Editor';
-import { RecalculatePhysics } from './Behaviors/RigidBodyBehaviors';
-import { INPUT_TYPES } from '../Properties/PropertiesInputTypes';
-import { ImposePosition } from './Behaviors/AnchorBehaviors';
-
-/**
- * Handled the property change event in the properties form
- * @param key Property name
- * @param value New value of the property
- * @returns void
- */
-export function OnPropertyChange(
- key: string,
- value: string | number | boolean,
- fullHistory: IHistoryState[],
- historyCurrentStep: number,
- setHistory: Dispatch>,
- setHistoryCurrentStep: Dispatch>
-): void {
- const history = getCurrentHistory(fullHistory, historyCurrentStep);
- const current = history[history.length - 1];
-
- if (current.SelectedContainer === null ||
- current.SelectedContainer === undefined) {
- throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
- }
-
- const mainContainerClone: IContainerModel = structuredClone(current.MainContainer);
- const container: ContainerModel | undefined = findContainerById(mainContainerClone, current.SelectedContainer.properties.id);
-
- if (container === null || container === undefined) {
- throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
- }
-
- if (INPUT_TYPES[key] === 'number') {
- (container.properties as any)[key] = Number(value);
- } else {
- (container.properties as any)[key] = value;
- }
-
- if (container.properties.isAnchor) {
- ImposePosition(container);
- }
-
- if (container.properties.isRigidBody) {
- RecalculatePhysics(container);
- }
-
- history.push({
- LastAction: `Change ${key} of ${container.properties.id}`,
- MainContainer: mainContainerClone,
- SelectedContainer: container,
- SelectedContainerId: container.properties.id,
- TypeCounters: Object.assign({}, current.TypeCounters)
- });
- setHistory(history);
- setHistoryCurrentStep(history.length - 1);
-}
-
-/**
- * Handled the property change event in the properties form
- * @param key Property name
- * @param properties Properties of the selected container
- * @returns void
- */
-export function OnPropertiesSubmit(
- event: React.SyntheticEvent,
- properties: IProperties,
- fullHistory: IHistoryState[],
- historyCurrentStep: number,
- setHistory: Dispatch>,
- setHistoryCurrentStep: Dispatch>
-): void {
- event.preventDefault();
- const history = getCurrentHistory(fullHistory, historyCurrentStep);
- const current = history[history.length - 1];
-
- if (current.SelectedContainer === null ||
- current.SelectedContainer === undefined) {
- throw new Error('[OnPropertyChange] Property was changed before selecting a Container');
- }
-
- const mainContainerClone: IContainerModel = structuredClone(current.MainContainer);
- const container: ContainerModel | undefined = findContainerById(mainContainerClone, current.SelectedContainer.properties.id);
-
- if (container === null || container === undefined) {
- throw new Error('[OnPropertyChange] Container model was not found among children of the main container!');
- }
-
- for (const property in properties) {
- const input = (event.target as HTMLFormElement).querySelector(`#${property}`);
- if (input instanceof HTMLInputElement) {
- (container.properties as any)[property] = input.value;
- if (INPUT_TYPES[property] === 'number') {
- (container.properties as any)[property] = Number(input.value);
- } else {
- (container.properties as any)[property] = input.value;
- }
- }
- }
-
- if (container.properties.isRigidBody) {
- RecalculatePhysics(container);
- }
-
- history.push({
- LastAction: `Change properties of ${container.properties.id}`,
- MainContainer: mainContainerClone,
- SelectedContainer: container,
- SelectedContainerId: container.properties.id,
- TypeCounters: Object.assign({}, current.TypeCounters)
- });
- setHistory(history);
- setHistoryCurrentStep(history.length - 1);
-}
diff --git a/src/Components/Editor/Save.ts b/src/Components/Editor/Save.ts
index 159959a..91cee2f 100644
--- a/src/Components/Editor/Save.ts
+++ b/src/Components/Editor/Save.ts
@@ -1,40 +1,29 @@
-import { IHistoryState } from '../../Interfaces/IHistoryState';
-import { IConfiguration } from '../../Interfaces/IConfiguration';
+import { HistoryState } from "../../Interfaces/HistoryState";
+import { Configuration } from '../../Interfaces/Configuration';
import { getCircularReplacer } from '../../utils/saveload';
import { ID } from '../SVG/SVG';
-import { IEditorState } from '../../Interfaces/IEditorState';
-import Worker from '../../workers/worker?worker';
+import { IEditorState } from './Editor';
export function SaveEditorAsJSON(
- history: IHistoryState[],
+ history: HistoryState[],
historyCurrentStep: number,
- configuration: IConfiguration
+ configuration: Configuration
): void {
- const exportName = 'state.json';
+ const exportName = 'state';
const spaces = import.meta.env.DEV ? 4 : 0;
const editorState: IEditorState = {
history,
historyCurrentStep,
configuration
};
-
- // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
- if (window.Worker) {
- // use webworker for the stringify to avoid freezing
- const myWorker = new Worker();
- myWorker.postMessage({ editorState, spaces });
- myWorker.onmessage = (event) => {
- const data = event.data;
- const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent(data)}`;
- createDownloadNode(exportName, dataStr);
- myWorker.terminate();
- };
- return;
- }
-
const data = JSON.stringify(editorState, getCircularReplacer(), spaces);
const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent(data)}`;
- createDownloadNode(exportName, dataStr);
+ const downloadAnchorNode = document.createElement('a');
+ downloadAnchorNode.setAttribute('href', dataStr);
+ downloadAnchorNode.setAttribute('download', `${exportName}.json`);
+ document.body.appendChild(downloadAnchorNode); // required for firefox
+ downloadAnchorNode.click();
+ downloadAnchorNode.remove();
}
export function SaveEditorAsSVG(): void {
@@ -43,14 +32,10 @@ export function SaveEditorAsSVG(): void {
const preface = '\r\n';
const svgBlob = new Blob([preface, svg.outerHTML], { type: 'image/svg+xml;charset=utf-8' });
const svgUrl = URL.createObjectURL(svgBlob);
- createDownloadNode('state.svg', svgUrl);
-}
-
-function createDownloadNode(filename: string, datastring: string) {
- const downloadAnchorNode = document.createElement('a');
- downloadAnchorNode.href = datastring;
- downloadAnchorNode.download = filename;
- document.body.appendChild(downloadAnchorNode); // required for firefox
- downloadAnchorNode.click();
- downloadAnchorNode.remove();
+ const downloadLink = document.createElement('a');
+ downloadLink.href = svgUrl;
+ downloadLink.download = 'newesttree.svg';
+ document.body.appendChild(downloadLink);
+ downloadLink.click();
+ document.body.removeChild(downloadLink);
}
diff --git a/src/Components/Editor/Shortcuts.ts b/src/Components/Editor/Shortcuts.ts
index aa20d96..8ac6790 100644
--- a/src/Components/Editor/Shortcuts.ts
+++ b/src/Components/Editor/Shortcuts.ts
@@ -1,9 +1,9 @@
import { Dispatch, SetStateAction } from 'react';
-import { IHistoryState } from '../../Interfaces/IHistoryState';
+import { HistoryState } from '../../Interfaces/HistoryState';
export function onKeyDown(
event: KeyboardEvent,
- history: IHistoryState[],
+ history: HistoryState[],
historyCurrentStep: number,
setHistoryCurrentStep: Dispatch>
): void {
diff --git a/src/Components/ElementsSidebar/ElementsSidebar.test.tsx b/src/Components/ElementsSidebar/ElementsSidebar.test.tsx
index 8d34480..c1372b1 100644
--- a/src/Components/ElementsSidebar/ElementsSidebar.test.tsx
+++ b/src/Components/ElementsSidebar/ElementsSidebar.test.tsx
@@ -2,7 +2,7 @@ import { describe, expect, it, vi } from 'vitest';
import * as React from 'react';
import { fireEvent, render, screen } from '../../utils/test-utils';
import { ElementsSidebar } from './ElementsSidebar';
-import { IContainerModel } from '../../Interfaces/IContainerModel';
+import { IContainerModel } from '../../Interfaces/ContainerModel';
describe.concurrent('Elements sidebar', () => {
it('With a MainContainer', () => {
@@ -17,8 +17,7 @@ describe.concurrent('Elements sidebar', () => {
y: 0,
width: 2000,
height: 100,
- isRigidBody: false,
- isAnchor: false
+ isRigidBody: false
},
userData: {}
}}
@@ -26,7 +25,6 @@ describe.concurrent('Elements sidebar', () => {
isHistoryOpen={false}
SelectedContainer={null}
OnPropertyChange={() => {}}
- OnPropertiesSubmit={() => {}}
SelectContainer={() => {}}
DeleteContainer={() => {}}
AddContainer={() => {}}
@@ -48,8 +46,7 @@ describe.concurrent('Elements sidebar', () => {
y: 0,
width: 2000,
height: 100,
- isRigidBody: false,
- isAnchor: false
+ isRigidBody: false
},
userData: {}
};
@@ -60,7 +57,6 @@ describe.concurrent('Elements sidebar', () => {
isHistoryOpen={false}
SelectedContainer={MainContainer}
OnPropertyChange={() => {}}
- OnPropertiesSubmit={() => {}}
SelectContainer={() => {}}
DeleteContainer={() => {}}
AddContainer={() => {}}
@@ -74,12 +70,12 @@ describe.concurrent('Elements sidebar', () => {
expect(screen.queryByText('y')).toBeDefined();
expect(screen.queryByText('width')).toBeDefined();
expect(screen.queryByText('height')).toBeDefined();
- const propertyId = container.querySelector('#id');
- const propertyParentId = container.querySelector('#parentId');
- const propertyX = container.querySelector('#x');
- const propertyY = container.querySelector('#y');
- const propertyWidth = container.querySelector('#width');
- const propertyHeight = container.querySelector('#height');
+ const propertyId = container.querySelector('#property-id');
+ const propertyParentId = container.querySelector('#property-parentId');
+ const propertyX = container.querySelector('#property-x');
+ const propertyY = container.querySelector('#property-y');
+ const propertyWidth = container.querySelector('#property-width');
+ const propertyHeight = container.querySelector('#property-height');
expect((propertyId as HTMLInputElement).value).toBe(MainContainer.properties.id.toString());
expect(propertyParentId).toBeDefined();
expect((propertyParentId as HTMLInputElement).value).toBe('');
@@ -105,8 +101,7 @@ describe.concurrent('Elements sidebar', () => {
y: 0,
width: 2000,
height: 100,
- isRigidBody: false,
- isAnchor: false
+ isRigidBody: false
},
userData: {}
};
@@ -122,8 +117,7 @@ describe.concurrent('Elements sidebar', () => {
y: 0,
width: 0,
height: 0,
- isRigidBody: false,
- isAnchor: false
+ isRigidBody: false
},
userData: {}
}
@@ -140,8 +134,7 @@ describe.concurrent('Elements sidebar', () => {
y: 0,
width: 0,
height: 0,
- isRigidBody: false,
- isAnchor: false
+ isRigidBody: false
},
userData: {}
}
@@ -153,7 +146,6 @@ describe.concurrent('Elements sidebar', () => {
isHistoryOpen={false}
SelectedContainer={MainContainer}
OnPropertyChange={() => {}}
- OnPropertiesSubmit={() => {}}
SelectContainer={() => {}}
DeleteContainer={() => {}}
AddContainer={() => {}}
@@ -178,8 +170,7 @@ describe.concurrent('Elements sidebar', () => {
y: 0,
width: 2000,
height: 100,
- isRigidBody: false,
- isAnchor: false
+ isRigidBody: false
},
userData: {}
};
@@ -194,8 +185,7 @@ describe.concurrent('Elements sidebar', () => {
y: 0,
width: 0,
height: 0,
- isRigidBody: false,
- isAnchor: false
+ isRigidBody: false
},
userData: {}
};
@@ -212,7 +202,6 @@ describe.concurrent('Elements sidebar', () => {
isHistoryOpen={false}
SelectedContainer={SelectedContainer}
OnPropertyChange={() => {}}
- OnPropertiesSubmit={() => {}}
SelectContainer={selectContainer}
DeleteContainer={() => {}}
AddContainer={() => {}}
@@ -223,8 +212,8 @@ describe.concurrent('Elements sidebar', () => {
expect(screen.getByText(/main/i));
const child1 = screen.getByText(/child-1/i);
expect(child1);
- const propertyId = container.querySelector('#id');
- const propertyParentId = container.querySelector('#parentId');
+ const propertyId = container.querySelector('#property-id');
+ const propertyParentId = container.querySelector('#property-parentId');
expect((propertyId as HTMLInputElement).value).toBe(MainContainer.properties.id.toString());
expect((propertyParentId as HTMLInputElement).value).toBe('');
@@ -236,7 +225,6 @@ describe.concurrent('Elements sidebar', () => {
isHistoryOpen={false}
SelectedContainer={SelectedContainer}
OnPropertyChange={() => {}}
- OnPropertiesSubmit={() => {}}
SelectContainer={selectContainer}
DeleteContainer={() => {}}
AddContainer={() => {}}
diff --git a/src/Components/ElementsSidebar/ElementsSidebar.tsx b/src/Components/ElementsSidebar/ElementsSidebar.tsx
index 30f1617..873161d 100644
--- a/src/Components/ElementsSidebar/ElementsSidebar.tsx
+++ b/src/Components/ElementsSidebar/ElementsSidebar.tsx
@@ -1,13 +1,12 @@
import * as React from 'react';
-import { FixedSizeList as List } from 'react-window';
+import { motion } from 'framer-motion';
import { Properties } from '../Properties/Properties';
-import ContainerProperties from '../../Interfaces/IProperties';
-import { IContainerModel } from '../../Interfaces/IContainerModel';
+import { IContainerModel } from '../../Interfaces/ContainerModel';
import { getDepth, MakeIterator } from '../../utils/itertools';
import { Menu } from '../Menu/Menu';
import { MenuItem } from '../Menu/MenuItem';
import { handleDragLeave, handleDragOver, handleLeftClick, handleOnDrop, handleRightClick } from './MouseEventHandlers';
-import { IPoint } from '../../Interfaces/IPoint';
+import { Point } from '../../Interfaces/Point';
interface IElementsSidebarProps {
MainContainer: IContainerModel
@@ -15,17 +14,55 @@ interface IElementsSidebarProps {
isHistoryOpen: boolean
SelectedContainer: IContainerModel | null
OnPropertyChange: (key: string, value: string | number | boolean) => void
- OnPropertiesSubmit: (event: React.FormEvent, properties: ContainerProperties) => void
SelectContainer: (container: IContainerModel) => void
DeleteContainer: (containerid: string) => void
AddContainer: (index: number, type: string, parent: string) => void
}
+function createRows(
+ container: IContainerModel,
+ props: IElementsSidebarProps,
+ containerRows: React.ReactNode[]
+): void {
+ const depth: number = getDepth(container);
+ const key = container.properties.id.toString();
+ const text = '|\t'.repeat(depth) + key;
+ const selectedClass: string = props.SelectedContainer !== undefined &&
+ props.SelectedContainer !== null &&
+ props.SelectedContainer.properties.id === container.properties.id
+ ? 'border-l-4 bg-slate-400/60 hover:bg-slate-400'
+ : 'bg-slate-300/60 hover:bg-slate-300';
+
+ containerRows.push(
+ handleOnDrop(event, props.MainContainer, props.AddContainer)}
+ onDragOver={(event) => handleDragOver(event, props.MainContainer)}
+ onDragLeave={(event) => handleDragLeave(event)}
+ onClick={() => props.SelectContainer(container)}
+ >
+ { text }
+
+ );
+};
+
export const ElementsSidebar: React.FC = (props: IElementsSidebarProps): JSX.Element => {
// States
const [isContextMenuOpen, setIsContextMenuOpen] = React.useState(false);
const [onClickContainerId, setOnClickContainerId] = React.useState('');
- const [contextMenuPosition, setContextMenuPosition] = React.useState({
+ const [contextMenuPosition, setContextMenuPosition] = React.useState({
x: 0,
y: 0
});
@@ -68,7 +105,7 @@ export const ElementsSidebar: React.FC = (props: IElement
onLeftClick
);
};
- });
+ }, []);
// Render
let isOpenClasses = '-right-64';
@@ -78,55 +115,24 @@ export const ElementsSidebar: React.FC = (props: IElement
: 'right-0';
}
+ const containerRows: React.ReactNode[] = [];
+
const it = MakeIterator(props.MainContainer);
- const containers = [...it];
- const Row = ({ index, style }: {index: number, style: React.CSSProperties}): JSX.Element => {
- const container = containers[index];
- const depth: number = getDepth(container);
- const key = container.properties.id.toString();
- const text = '|\t'.repeat(depth) + key;
- const selectedClass: string = props.SelectedContainer !== undefined &&
- props.SelectedContainer !== null &&
- props.SelectedContainer.properties.id === container.properties.id
- ? 'border-l-4 bg-slate-400/60 hover:bg-slate-400'
- : 'bg-slate-300/60 hover:bg-slate-300';
-
- return (
- handleOnDrop(event, props.MainContainer, props.AddContainer)}
- onDragOver={(event) => handleDragOver(event, props.MainContainer)}
- onDragLeave={(event) => handleDragLeave(event)}
- onClick={() => props.SelectContainer(container)}
- >
- { text }
-
+ for (const container of it) {
+ createRows(
+ container,
+ props,
+ containerRows
);
- };
+ }
- const ROW_HEIGHT = 35;
- const NUMBERS_OF_ROWS = 10;
return (
-
+
Elements
-
-
- { Row }
-
+
+ { containerRows }
= (props: IElement
props.DeleteContainer(onClickContainerId);
}} />
-
+
);
};
diff --git a/src/Components/ElementsSidebar/MouseEventHandlers.ts b/src/Components/ElementsSidebar/MouseEventHandlers.ts
index 1a814d2..53fb14e 100644
--- a/src/Components/ElementsSidebar/MouseEventHandlers.ts
+++ b/src/Components/ElementsSidebar/MouseEventHandlers.ts
@@ -1,12 +1,12 @@
-import { IContainerModel } from '../../Interfaces/IContainerModel';
-import { IPoint } from '../../Interfaces/IPoint';
+import { IContainerModel } from '../../Interfaces/ContainerModel';
+import { Point } from '../../Interfaces/Point';
import { findContainerById } from '../../utils/itertools';
export function handleRightClick(
event: MouseEvent,
setIsContextMenuOpen: React.Dispatch
>,
setOnClickContainerId: React.Dispatch>,
- setContextMenuPosition: React.Dispatch>
+ setContextMenuPosition: React.Dispatch>
): void {
event.preventDefault();
@@ -16,7 +16,7 @@ export function handleRightClick(
return;
}
- const contextMenuPosition: IPoint = { x: event.pageX, y: event.pageY };
+ const contextMenuPosition: Point = { x: event.pageX, y: event.pageY };
setIsContextMenuOpen(true);
setOnClickContainerId(event.target.id);
setContextMenuPosition(contextMenuPosition);
diff --git a/src/Components/History/History.tsx b/src/Components/History/History.tsx
index 36e8e80..067a867 100644
--- a/src/Components/History/History.tsx
+++ b/src/Components/History/History.tsx
@@ -1,9 +1,8 @@
import * as React from 'react';
-import { FixedSizeList as List } from 'react-window';
-import { IHistoryState } from '../../Interfaces/IHistoryState';
+import { HistoryState } from "../../Interfaces/HistoryState";
interface IHistoryProps {
- history: IHistoryState[]
+ history: HistoryState[]
historyCurrentStep: number
isOpen: boolean
jumpTo: (move: number) => void
@@ -11,45 +10,47 @@ interface IHistoryProps {
export const History: React.FC = (props: IHistoryProps) => {
const isOpenClasses = props.isOpen ? 'right-0' : '-right-64';
- const Row = ({ index, style }: {index: number, style: React.CSSProperties}): JSX.Element => {
- const reversedIndex = (props.history.length - 1) - index;
- const step = props.history[reversedIndex];
- const desc = step.LastAction;
- const selectedClass = reversedIndex === props.historyCurrentStep
+ const states = props.history.map((step, move) => {
+ const desc = move > 0
+ ? `Go to modification n°${move}`
+ : 'Go to the beginning';
+
+ const isCurrent = move === props.historyCurrentStep;
+
+ const selectedClass = isCurrent
? 'bg-blue-500 hover:bg-blue-600'
: 'bg-slate-500 hover:bg-slate-700';
+ const isCurrentText = isCurrent
+ ? ' (current)'
+ : '';
return (
+
props.jumpTo(reversedIndex)}
- title={step.LastAction}
+ key={move}
+ onClick={() => props.jumpTo(move)}
className={
- `w-full elements-sidebar-row whitespace-pre overflow-hidden
+ `w-full elements-sidebar-row whitespace-pre
text-left text-sm font-medium transition-all ${selectedClass}`
}
>
- {desc}
+ {desc}{isCurrentText}
);
- };
+ });
+
+ // recent first
+ states.reverse();
return (
-
+
Timeline
-
- { Row }
-
+
+ { states }
+
);
};
diff --git a/src/Components/MainMenu/MainMenu.tsx b/src/Components/MainMenu/MainMenu.tsx
index 9c8b27f..1d84f9a 100644
--- a/src/Components/MainMenu/MainMenu.tsx
+++ b/src/Components/MainMenu/MainMenu.tsx
@@ -38,8 +38,13 @@ export const MainMenu: React.FC
= (props) => {
setWindowState(WindowState.MAIN)}
- className='normal-btn block
- mt-8 '
+ className='block text-sm
+ mt-8 py-2 px-4
+ rounded-full border-0
+ font-semibold
+ transition-all
+ bg-blue-100 text-blue-700
+ hover:bg-blue-200'
>
Go back
diff --git a/src/Components/Properties/Properties.test.tsx b/src/Components/Properties/Properties.test.tsx
index 9fbef37..9f0fe13 100644
--- a/src/Components/Properties/Properties.test.tsx
+++ b/src/Components/Properties/Properties.test.tsx
@@ -8,7 +8,6 @@ describe.concurrent('Properties', () => {
render( {}}
- onSubmit={() => {}}
/>);
expect(screen.queryByText('id')).toBeNull();
@@ -17,14 +16,13 @@ describe.concurrent('Properties', () => {
expect(screen.queryByText('y')).toBeNull();
});
- it('Some properties, change values with dynamic input', () => {
+ it('Some properties', () => {
const prop = {
id: 'stuff',
parentId: 'parentId',
x: 1,
y: 1,
- isRigidBody: false,
- isAnchor: false
+ isRigidBody: false
};
const handleChange = vi.fn((key, value) => {
@@ -34,7 +32,6 @@ describe.concurrent('Properties', () => {
const { container, rerender } = render( {}}
/>);
expect(screen.queryByText('id')).toBeDefined();
@@ -42,10 +39,10 @@ describe.concurrent('Properties', () => {
expect(screen.queryByText('x')).toBeDefined();
expect(screen.queryByText('y')).toBeDefined();
- let propertyId = container.querySelector('#id');
- let propertyParentId = container.querySelector('#parentId');
- let propertyX = container.querySelector('#x');
- let propertyY = container.querySelector('#y');
+ let propertyId = container.querySelector('#property-id');
+ let propertyParentId = container.querySelector('#property-parentId');
+ let propertyX = container.querySelector('#property-x');
+ let propertyY = container.querySelector('#property-y');
expect(propertyId).toBeDefined();
expect((propertyId as HTMLInputElement).value).toBe('stuff');
expect(propertyParentId).toBeDefined();
@@ -68,13 +65,12 @@ describe.concurrent('Properties', () => {
rerender( {}}
/>);
- propertyId = container.querySelector('#id');
- propertyParentId = container.querySelector('#parentId');
- propertyX = container.querySelector('#x');
- propertyY = container.querySelector('#y');
+ propertyId = container.querySelector('#property-id');
+ propertyParentId = container.querySelector('#property-parentId');
+ propertyX = container.querySelector('#property-x');
+ propertyY = container.querySelector('#property-y');
expect(propertyId).toBeDefined();
expect((propertyId as HTMLInputElement).value).toBe('stuffed');
expect(propertyParentId).toBeDefined();
diff --git a/src/Components/Properties/Properties.tsx b/src/Components/Properties/Properties.tsx
index 516f23d..c1ac966 100644
--- a/src/Components/Properties/Properties.tsx
+++ b/src/Components/Properties/Properties.tsx
@@ -1,17 +1,13 @@
-import React, { useState } from 'react';
-import ContainerProperties from '../../Interfaces/IProperties';
-import { ToggleButton } from '../ToggleButton/ToggleButton';
+import * as React from 'react';
+import ContainerProperties from '../../Interfaces/Properties';
import { INPUT_TYPES } from './PropertiesInputTypes';
interface IPropertiesProps {
properties?: ContainerProperties
onChange: (key: string, value: string | number | boolean) => void
- onSubmit: (event: React.FormEvent, properties: ContainerProperties) => void
}
export const Properties: React.FC = (props: IPropertiesProps) => {
- const [isDynamicInput, setIsDynamicInput] = useState(true);
-
if (props.properties === undefined) {
return
;
}
@@ -19,33 +15,11 @@ export const Properties: React.FC = (props: IPropertiesProps)
const groupInput: React.ReactNode[] = [];
Object
.entries(props.properties)
- .forEach((pair) => handleProperties(pair, groupInput, isDynamicInput, props.onChange));
-
- const form = isDynamicInput
- ?
- { groupInput }
-
- :
- ;
+ .forEach((pair) => handleProperties(pair, groupInput, props.onChange));
return (
-
-
setIsDynamicInput(!isDynamicInput)}
- />
- { form }
+
+ { groupInput }
);
};
@@ -53,7 +27,6 @@ export const Properties: React.FC = (props: IPropertiesProps)
const handleProperties = (
[key, value]: [string, string | number],
groupInput: React.ReactNode[],
- isDynamicInput: boolean,
onChange: (key: string, value: string | number | boolean) => void
): void => {
const id = `property-${key}`;
@@ -69,48 +42,31 @@ const handleProperties = (
type = INPUT_TYPES[key];
}
- const className = `
- w-full
- text-xs font-medium transition-all text-gray-800 mt-1 px-3 py-2
- bg-white border-2 border-white rounded-lg placeholder-gray-800
- focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500
- disabled:bg-slate-300 disabled:text-gray-500 disabled:border-slate-300 disabled:shadow-none`;
const isDisabled = ['id', 'parentId'].includes(key);
- const input = isDynamicInput
- ? {
- if (type === 'checkbox') {
- onChange(key, event.target.checked);
- return;
- }
- onChange(key, event.target.value);
- }}
- disabled={isDisabled}
- />
- : ;
+ ///
groupInput.push(
-
- {key}
-
+
+ {key}
+ {
+ if (type === 'checkbox') {
+ onChange(key, event.target.checked);
+ return;
+ }
+ onChange(key, event.target.value);
+ }}
+ disabled={isDisabled}
+ />
+
);
- groupInput.push(input);
};
diff --git a/src/Components/Properties/PropertiesInputTypes.tsx b/src/Components/Properties/PropertiesInputTypes.tsx
index d91ddbc..c62a8fd 100644
--- a/src/Components/Properties/PropertiesInputTypes.tsx
+++ b/src/Components/Properties/PropertiesInputTypes.tsx
@@ -3,6 +3,5 @@ export const INPUT_TYPES: Record = {
y: 'number',
width: 'number',
height: 'number',
- isRigidBody: 'checkbox',
- isAnchor: 'checkbox'
+ isRigidBody: 'checkbox'
};
diff --git a/src/Components/SVG/Elements/Container.tsx b/src/Components/SVG/Elements/Container.tsx
index 6417570..02dea6f 100644
--- a/src/Components/SVG/Elements/Container.tsx
+++ b/src/Components/SVG/Elements/Container.tsx
@@ -1,10 +1,9 @@
import * as React from 'react';
-import { XPositionReference } from '../../../Enums/XPositionReference';
-import { IContainerModel } from '../../../Interfaces/IContainerModel';
+import { IContainerModel } from '../../../Interfaces/ContainerModel';
import { getDepth } from '../../../utils/itertools';
import { Dimension } from './Dimension';
-interface IContainerProps {
+export interface IContainerProps {
model: IContainerModel
}
@@ -18,14 +17,7 @@ export const Container: React.FC = (props: IContainerProps) =>
const containersElements = props.model.children.map(child => );
const xText = Number(props.model.properties.width) / 2;
const yText = Number(props.model.properties.height) / 2;
-
- const [transformedX, transformedY] = transformPosition(
- Number(props.model.properties.x),
- Number(props.model.properties.y),
- Number(props.model.properties.width),
- props.model.properties.XPositionReference
- );
- const transform = `translate(${transformedX}, ${transformedY})`;
+ const transform = `translate(${Number(props.model.properties.x)}, ${Number(props.model.properties.y)})`;
// g style
const defaultStyle: React.CSSProperties = {
@@ -62,8 +54,7 @@ export const Container: React.FC = (props: IContainerProps) =>
id={id}
xStart={xStart}
xEnd={xEnd}
- yStart={y}
- yEnd={y}
+ y={y}
strokeWidth={strokeWidth}
text={text}
/>
@@ -83,13 +74,3 @@ export const Container: React.FC = (props: IContainerProps) =>
);
};
-
-function transformPosition(x: number, y: number, width: number, xPositionReference = XPositionReference.Left): [number, number] {
- let transformedX = x;
- if (xPositionReference === XPositionReference.Center) {
- transformedX -= width / 2;
- } else if (xPositionReference === XPositionReference.Right) {
- transformedX -= width;
- }
- return [transformedX, y];
-}
diff --git a/src/Components/SVG/Elements/Dimension.tsx b/src/Components/SVG/Elements/Dimension.tsx
index c5f6f86..ec51873 100644
--- a/src/Components/SVG/Elements/Dimension.tsx
+++ b/src/Components/SVG/Elements/Dimension.tsx
@@ -1,83 +1,47 @@
import * as React from 'react';
-import { NOTCHES_LENGTH } from '../../../utils/default';
interface IDimensionProps {
id: string
xStart: number
- yStart: number
xEnd: number
- yEnd: number
+ y: number
text: string
strokeWidth: number
}
-/**
- * 2D Parametric function. Returns a new coordinate from the origin coordinate
- * See for more details https://en.wikipedia.org/wiki/Parametric_equation.
- * TL;DR a parametric function is a function with a parameter
- * @param x0 Origin coordinate
- * @param t The parameter
- * @param vx Transform vector
- * @returns Returns a new coordinate from the origin coordinate
- */
-const applyParametric = (x0: number, t: number, vx: number): number => x0 + t * vx;
-
export const Dimension: React.FC = (props: IDimensionProps) => {
const style: React.CSSProperties = {
stroke: 'black'
};
-
- /// We need to find the points of the notches
- // Get the vector of the line
- const [deltaX, deltaY] = [(props.xEnd - props.xStart), (props.yEnd - props.yStart)];
-
- // Get the unit vector
- const norm = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
- const [unitX, unitY] = [deltaX / norm, deltaY / norm];
-
- // Get the perpandicular vector
- const [perpVecX, perpVecY] = [unitY, -unitX];
-
- // Use the parametric function to get the coordinates (x = x0 + t * v.x)
- const startTopX = applyParametric(props.xStart, NOTCHES_LENGTH, perpVecX);
- const startTopY = applyParametric(props.yStart, NOTCHES_LENGTH, perpVecY);
- const startBottomX = applyParametric(props.xStart, -NOTCHES_LENGTH, perpVecX);
- const startBottomY = applyParametric(props.yStart, -NOTCHES_LENGTH, perpVecY);
-
- const endTopX = applyParametric(props.xEnd, NOTCHES_LENGTH, perpVecX);
- const endTopY = applyParametric(props.yEnd, NOTCHES_LENGTH, perpVecY);
- const endBottomX = applyParametric(props.xEnd, -NOTCHES_LENGTH, perpVecX);
- const endBottomY = applyParametric(props.yEnd, -NOTCHES_LENGTH, perpVecY);
-
return (
{props.text}
diff --git a/src/Components/SVG/Elements/DimensionLayer.tsx b/src/Components/SVG/Elements/DimensionLayer.tsx
new file mode 100644
index 0000000..85f1a43
--- /dev/null
+++ b/src/Components/SVG/Elements/DimensionLayer.tsx
@@ -0,0 +1,66 @@
+import * as React from 'react';
+import { ContainerModel } from '../../../Interfaces/ContainerModel';
+import { getDepth, MakeIterator } from '../../../utils/itertools';
+import { Dimension } from './Dimension';
+
+interface IDimensionLayerProps {
+ isHidden: boolean
+ roots: ContainerModel | ContainerModel[] | null
+}
+
+const GAP: number = 50;
+
+const getDimensionsNodes = (root: ContainerModel): React.ReactNode[] => {
+ const it = MakeIterator(root);
+ const dimensions: React.ReactNode[] = [];
+ for (const container of it) {
+ // WARN: this might be dangerous later when using other units/rules
+ const width = Number(container.properties.width);
+
+ const id = `dim-${container.properties.id}`;
+ const xStart: number = container.properties.x;
+ const xEnd = xStart + width;
+ const y = -(GAP * (getDepth(container) + 1));
+ const strokeWidth = 1;
+ const text = width.toString();
+ dimensions.push(
+
+ );
+ }
+ return dimensions;
+};
+
+/**
+ * A layer containing all dimension
+ *
+ * @deprecated In order to avoid adding complexity
+ * with computing the position in a group hierarchy,
+ * use Dimension directly inside the Container,
+ * Currently it is glitched as
+ * it does not take parents into account,
+ * and will not work correctly
+ * @param props
+ * @returns
+ */
+export const DimensionLayer: React.FC = (props: IDimensionLayerProps) => {
+ let dimensions: React.ReactNode[] = [];
+ if (Array.isArray(props.roots)) {
+ props.roots.forEach(child => {
+ dimensions.concat(getDimensionsNodes(child));
+ });
+ } else if (props.roots !== null) {
+ dimensions = getDimensionsNodes(props.roots);
+ }
+ return (
+
+ { dimensions }
+
+ );
+};
diff --git a/src/Components/SVG/Elements/Selector.tsx b/src/Components/SVG/Elements/Selector.tsx
index e70ca79..c5937e0 100644
--- a/src/Components/SVG/Elements/Selector.tsx
+++ b/src/Components/SVG/Elements/Selector.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { IContainerModel } from '../../../Interfaces/IContainerModel';
+import { IContainerModel } from '../../../Interfaces/ContainerModel';
import { getAbsolutePosition } from '../../../utils/itertools';
interface ISelectorProps {
diff --git a/src/Components/SVG/SVG.tsx b/src/Components/SVG/SVG.tsx
index 652258f..94fb746 100644
--- a/src/Components/SVG/SVG.tsx
+++ b/src/Components/SVG/SVG.tsx
@@ -1,7 +1,7 @@
import * as React from 'react';
import { UncontrolledReactSVGPanZoom } from 'react-svg-pan-zoom';
import { Container } from './Elements/Container';
-import { ContainerModel } from '../../Interfaces/IContainerModel';
+import { ContainerModel } from '../../Interfaces/ContainerModel';
import { Selector } from './Elements/Selector';
import { BAR_WIDTH } from '../Bar/Bar';
@@ -30,7 +30,7 @@ function resizeViewBox(
export const SVG: React.FC = (props: ISVGProps) => {
const [viewer, setViewer] = React.useState({
- viewerWidth: window.innerWidth - BAR_WIDTH,
+ viewerWidth: window.innerWidth,
viewerHeight: window.innerHeight
});
diff --git a/src/Components/Sidebar/Sidebar.tsx b/src/Components/Sidebar/Sidebar.tsx
index c39b235..dc2f1a7 100644
--- a/src/Components/Sidebar/Sidebar.tsx
+++ b/src/Components/Sidebar/Sidebar.tsx
@@ -1,9 +1,9 @@
import * as React from 'react';
-import { IAvailableContainer } from '../../Interfaces/IAvailableContainer';
+import { AvailableContainer } from '../../Interfaces/AvailableContainer';
import { truncateString } from '../../utils/stringtools';
interface ISidebarProps {
- componentOptions: IAvailableContainer[]
+ componentOptions: AvailableContainer[]
isOpen: boolean
buttonOnClick: (type: string) => void
}
@@ -30,7 +30,7 @@ export const Sidebar: React.FC = (props: ISidebarProps) => {
const isOpenClasses = props.isOpen ? 'left-16' : '-left-64';
return (
Components
diff --git a/src/Components/ToggleButton/ToggleButton.scss b/src/Components/ToggleButton/ToggleButton.scss
deleted file mode 100644
index 0948f52..0000000
--- a/src/Components/ToggleButton/ToggleButton.scss
+++ /dev/null
@@ -1,8 +0,0 @@
-input:checked ~ .dot {
- transform: translateX(100%);
-}
-input:checked ~ .line {
- background-color: #3B82F6;
-}
-
-
diff --git a/src/Components/ToggleButton/ToggleButton.tsx b/src/Components/ToggleButton/ToggleButton.tsx
deleted file mode 100644
index 198bf99..0000000
--- a/src/Components/ToggleButton/ToggleButton.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import React, { FC } from 'react';
-import './ToggleButton.scss';
-
-interface IToggleButtonProps {
- id: string
- text: string
- type?: TOGGLE_TYPE
- title: string
- checked: boolean
- onChange: React.ChangeEventHandler
-}
-
-export enum TOGGLE_TYPE {
- MATERIAL,
- IOS
-}
-
-export const ToggleButton: FC = (props) => {
- const id = `toggle-${props.id}`;
- const type = props.type ?? TOGGLE_TYPE.MATERIAL;
- let classLine = 'line w-10 h-4 bg-gray-400 rounded-full shadow-inner';
- let classDot = 'dot absolute w-6 h-6 bg-white rounded-full shadow -left-1 -top-1 transition';
- if (type === TOGGLE_TYPE.IOS) {
- classLine = 'line block bg-gray-600 w-14 h-8 rounded-full';
- classDot = 'dot absolute left-1 top-1 bg-white w-6 h-6 rounded-full transition';
- }
-
- return (
-
-
-
-
-
- { props.text }
-
-
-
-
- );
-};
diff --git a/src/Components/UI/UI.tsx b/src/Components/UI/UI.tsx
index 4fa36e6..6d6adbe 100644
--- a/src/Components/UI/UI.tsx
+++ b/src/Components/UI/UI.tsx
@@ -2,23 +2,21 @@ import * as React from 'react';
import { ElementsSidebar } from '../ElementsSidebar/ElementsSidebar';
import { Sidebar } from '../Sidebar/Sidebar';
import { History } from '../History/History';
-import { IAvailableContainer } from '../../Interfaces/IAvailableContainer';
-import { ContainerModel } from '../../Interfaces/IContainerModel';
-import { IHistoryState } from '../../Interfaces/IHistoryState';
+import { AvailableContainer } from '../../Interfaces/AvailableContainer';
+import { ContainerModel } from '../../Interfaces/ContainerModel';
+import { HistoryState } from '../../Interfaces/HistoryState';
import { PhotographIcon, UploadIcon } from '@heroicons/react/outline';
import { FloatingButton } from '../FloatingButton/FloatingButton';
import { Bar } from '../Bar/Bar';
-import IProperties from '../../Interfaces/IProperties';
interface IUIProps {
- current: IHistoryState
- history: IHistoryState[]
+ current: HistoryState
+ history: HistoryState[]
historyCurrentStep: number
- AvailableContainers: IAvailableContainer[]
+ AvailableContainers: AvailableContainer[]
SelectContainer: (container: ContainerModel) => void
DeleteContainer: (containerId: string) => void
OnPropertyChange: (key: string, value: string | number | boolean) => void
- OnPropertiesSubmit: (event: React.FormEvent, properties: IProperties) => void
AddContainerToSelectedContainer: (type: string) => void
AddContainer: (index: number, type: string, parentId: string) => void
SaveEditorAsJSON: () => void
@@ -61,7 +59,6 @@ export const UI: React.FunctionComponent = (props: IUIProps) => {
isOpen={isElementsSidebarOpen}
isHistoryOpen={isHistoryOpen}
OnPropertyChange={props.OnPropertyChange}
- OnPropertiesSubmit={props.OnPropertiesSubmit}
SelectContainer={props.SelectContainer}
DeleteContainer={props.DeleteContainer}
AddContainer={props.AddContainer}
diff --git a/src/Enums/AddingBehavior.ts b/src/Enums/AddingBehavior.ts
new file mode 100644
index 0000000..fb6ae67
--- /dev/null
+++ b/src/Enums/AddingBehavior.ts
@@ -0,0 +1,4 @@
+export enum AddingBehavior {
+ InsertInto,
+ Replace
+}
diff --git a/src/Events/EditorEvents.ts b/src/Events/EditorEvents.ts
deleted file mode 100644
index 316b7b8..0000000
--- a/src/Events/EditorEvents.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { IEditorState } from '../Interfaces/IEditorState';
-import { IHistoryState } from '../Interfaces/IHistoryState';
-
-const getEditorState = (editorState: IEditorState): void => {
- const customEvent = new CustomEvent('getEditorState', { detail: editorState });
- document.dispatchEvent(customEvent);
-};
-
-const getCurrentHistoryState = (editorState: IEditorState): void => {
- const customEvent = new CustomEvent(
- 'getCurrentHistoryState',
- { detail: editorState.history[editorState.historyCurrentStep] });
- document.dispatchEvent(customEvent);
-};
-
-export interface IEditorEvent {
- name: string
- func: (editorState: IEditorState) => void
-}
-
-const events: IEditorEvent[] = [
- { name: 'getEditorState', func: getEditorState },
- { name: 'getCurrentHistoryState', func: getCurrentHistoryState }
-];
-
-export default events;
diff --git a/src/Interfaces/IAvailableContainer.ts b/src/Interfaces/AvailableContainer.ts
similarity index 54%
rename from src/Interfaces/IAvailableContainer.ts
rename to src/Interfaces/AvailableContainer.ts
index c7ad3c1..d7bb22f 100644
--- a/src/Interfaces/IAvailableContainer.ts
+++ b/src/Interfaces/AvailableContainer.ts
@@ -1,11 +1,9 @@
import React from 'react';
-import { XPositionReference } from '../Enums/XPositionReference';
/** Model of available container used in application configuration */
-export interface IAvailableContainer {
+export interface AvailableContainer {
Type: string
Width: number
Height: number
- XPositionReference?: XPositionReference
Style: React.CSSProperties
}
diff --git a/src/Interfaces/IAvailableSymbol.ts b/src/Interfaces/AvailableSymbol.ts
similarity index 71%
rename from src/Interfaces/IAvailableSymbol.ts
rename to src/Interfaces/AvailableSymbol.ts
index 3f3176a..e1d518d 100644
--- a/src/Interfaces/IAvailableSymbol.ts
+++ b/src/Interfaces/AvailableSymbol.ts
@@ -1,12 +1,12 @@
import { XPositionReference } from '../Enums/XPositionReference';
-import { IImage } from './IImage';
+import { Image } from './Image';
/**
* Model of available symbol to configure the application */
-export interface IAvailableSymbol {
+export interface AvailableSymbolModel {
Name: string
XPositionReference: XPositionReference
- Image: IImage
+ Image: Image
Width: number
Height: number
}
diff --git a/src/Interfaces/Configuration.ts b/src/Interfaces/Configuration.ts
new file mode 100644
index 0000000..f8d4854
--- /dev/null
+++ b/src/Interfaces/Configuration.ts
@@ -0,0 +1,9 @@
+import { AvailableContainer } from './AvailableContainer';
+import { AvailableSymbolModel } from './AvailableSymbol';
+
+/** Model of configuration for the application to configure it */
+export interface Configuration {
+ AvailableContainers: AvailableContainer[]
+ AvailableSymbols: AvailableSymbolModel[]
+ MainContainer: AvailableContainer
+}
diff --git a/src/Interfaces/IContainerModel.ts b/src/Interfaces/ContainerModel.ts
similarity index 81%
rename from src/Interfaces/IContainerModel.ts
rename to src/Interfaces/ContainerModel.ts
index b180486..1c70ae3 100644
--- a/src/Interfaces/IContainerModel.ts
+++ b/src/Interfaces/ContainerModel.ts
@@ -1,21 +1,21 @@
-import IProperties from './IProperties';
+import Properties from './Properties';
export interface IContainerModel {
children: IContainerModel[]
parent: IContainerModel | null
- properties: IProperties
+ properties: Properties
userData: Record
}
export class ContainerModel implements IContainerModel {
public children: IContainerModel[];
public parent: IContainerModel | null;
- public properties: IProperties;
+ public properties: Properties;
public userData: Record;
constructor(
parent: IContainerModel | null,
- properties: IProperties,
+ properties: Properties,
children: IContainerModel[] = [],
userData = {}) {
this.parent = parent;
diff --git a/src/Interfaces/IHistoryState.ts b/src/Interfaces/HistoryState.ts
similarity index 66%
rename from src/Interfaces/IHistoryState.ts
rename to src/Interfaces/HistoryState.ts
index fd46fbc..da1d74b 100644
--- a/src/Interfaces/IHistoryState.ts
+++ b/src/Interfaces/HistoryState.ts
@@ -1,6 +1,6 @@
-import { IContainerModel } from './IContainerModel';
+import { IContainerModel } from './ContainerModel';
-export interface IHistoryState {
+export interface HistoryState {
LastAction: string
MainContainer: IContainerModel
SelectedContainer: IContainerModel | null
diff --git a/src/Interfaces/IConfiguration.ts b/src/Interfaces/IConfiguration.ts
deleted file mode 100644
index a37647d..0000000
--- a/src/Interfaces/IConfiguration.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { IAvailableContainer } from './IAvailableContainer';
-import { IAvailableSymbol } from './IAvailableSymbol';
-
-/** Model of configuration for the application to configure it */
-export interface IConfiguration {
- AvailableContainers: IAvailableContainer[]
- AvailableSymbols: IAvailableSymbol[]
- MainContainer: IAvailableContainer
-}
diff --git a/src/Interfaces/IEditorState.ts b/src/Interfaces/IEditorState.ts
deleted file mode 100644
index 495a868..0000000
--- a/src/Interfaces/IEditorState.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { IConfiguration } from './IConfiguration';
-import { IHistoryState } from './IHistoryState';
-
-export interface IEditorState {
- history: IHistoryState[]
- historyCurrentStep: number
- configuration: IConfiguration
-}
diff --git a/src/Interfaces/IProperties.ts b/src/Interfaces/IProperties.ts
deleted file mode 100644
index ef2db7e..0000000
--- a/src/Interfaces/IProperties.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import * as React from 'react';
-import { XPositionReference } from '../Enums/XPositionReference';
-
-/**
- * Properties of a container
- * @property id id of the container
- * @property parentId id of the parent container
- * @property x horizontal offset of the container
- * @property y vertical offset of the container
- * @property isRigidBody if true apply rigid body behaviors
- * @property isAnchor if true apply anchor behaviors
- */
-export default interface IProperties extends React.CSSProperties {
- id: string
- parentId: string | null
- x: number
- y: number
- isRigidBody: boolean
- isAnchor: boolean
- XPositionReference?: XPositionReference
-}
diff --git a/src/Interfaces/ISizePointer.ts b/src/Interfaces/ISizePointer.ts
deleted file mode 100644
index 05f880c..0000000
--- a/src/Interfaces/ISizePointer.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * A SizePointer is a pointer in a 1 dimensional array of width/space
- * x being the address where the pointer is pointing
- * width being the overall (un)allocated space affected to the address
- */
-export interface ISizePointer {
- x: number
- width: number
-}
diff --git a/src/Interfaces/IImage.ts b/src/Interfaces/Image.ts
similarity index 81%
rename from src/Interfaces/IImage.ts
rename to src/Interfaces/Image.ts
index 7432440..b839b09 100644
--- a/src/Interfaces/IImage.ts
+++ b/src/Interfaces/Image.ts
@@ -1,5 +1,5 @@
/** Model of an image with multiple source */
-export interface IImage {
+export interface Image {
Name: string
Url: string
Base64Image: string
diff --git a/src/Interfaces/IPoint.ts b/src/Interfaces/Point.ts
similarity index 50%
rename from src/Interfaces/IPoint.ts
rename to src/Interfaces/Point.ts
index d2e202a..43fd673 100644
--- a/src/Interfaces/IPoint.ts
+++ b/src/Interfaces/Point.ts
@@ -1,4 +1,4 @@
-export interface IPoint {
+export interface Point {
x: number
y: number
}
diff --git a/src/Interfaces/Properties.ts b/src/Interfaces/Properties.ts
new file mode 100644
index 0000000..ea5f54e
--- /dev/null
+++ b/src/Interfaces/Properties.ts
@@ -0,0 +1,9 @@
+import * as React from 'react';
+
+export default interface Properties extends React.CSSProperties {
+ id: string
+ parentId: string | null
+ x: number
+ y: number
+ isRigidBody: boolean
+}
diff --git a/src/Interfaces/SizePointer.ts b/src/Interfaces/SizePointer.ts
new file mode 100644
index 0000000..9a80057
--- /dev/null
+++ b/src/Interfaces/SizePointer.ts
@@ -0,0 +1,4 @@
+export interface SizePointer {
+ x: number
+ width: number
+}
diff --git a/src/index.scss b/src/index.scss
index f653990..1bc3361 100644
--- a/src/index.scss
+++ b/src/index.scss
@@ -23,16 +23,6 @@
@apply transition-all bg-blue-100 hover:bg-blue-200 text-blue-700 text-lg font-semibold p-8 rounded-lg
}
- .normal-btn {
- @apply text-sm
- py-2 px-4
- rounded-full border-0
- font-semibold
- transition-all
- bg-blue-100 text-blue-700
- hover:bg-blue-200
- }
-
.floating-btn {
@apply h-full w-full text-white align-middle items-center justify-center
}
diff --git a/src/utils/default.ts b/src/utils/default.ts
index 027c540..552b8a0 100644
--- a/src/utils/default.ts
+++ b/src/utils/default.ts
@@ -1,7 +1,7 @@
-import { IConfiguration } from '../Interfaces/IConfiguration';
-import IProperties from '../Interfaces/IProperties';
+import { Configuration } from '../Interfaces/Configuration';
+import Properties from '../Interfaces/Properties';
-export const DEFAULT_CONFIG: IConfiguration = {
+export const DEFAULT_CONFIG: Configuration = {
AvailableContainers: [
{
Type: 'Container',
@@ -25,19 +25,14 @@ export const DEFAULT_CONFIG: IConfiguration = {
}
};
-export const DEFAULT_MAINCONTAINER_PROPS: IProperties = {
+export const DEFAULT_MAINCONTAINER_PROPS: Properties = {
id: 'main',
parentId: 'null',
x: 0,
y: 0,
+ isRigidBody: false,
width: DEFAULT_CONFIG.MainContainer.Width,
height: DEFAULT_CONFIG.MainContainer.Height,
- isRigidBody: false,
- isAnchor: false,
fillOpacity: 0,
stroke: 'black'
};
-
-export const NOTCHES_LENGTH = 4;
-
-export const MAX_HISTORY = 200;
diff --git a/src/utils/itertools.ts b/src/utils/itertools.ts
index d50a089..67cd40c 100644
--- a/src/utils/itertools.ts
+++ b/src/utils/itertools.ts
@@ -1,4 +1,4 @@
-import { IContainerModel } from '../Interfaces/IContainerModel';
+import { IContainerModel } from '../Interfaces/ContainerModel';
/**
* Returns a Generator iterating of over the children depth-first
diff --git a/src/utils/saveload.ts b/src/utils/saveload.ts
index 356dd50..a33652e 100644
--- a/src/utils/saveload.ts
+++ b/src/utils/saveload.ts
@@ -1,5 +1,5 @@
import { findContainerById, MakeIterator } from './itertools';
-import { IEditorState } from '../Interfaces/IEditorState';
+import { IEditorState } from '../Components/Editor/Editor';
/**
* Revive the Editor state
diff --git a/src/workers/worker.js b/src/workers/worker.js
deleted file mode 100644
index c11fa7d..0000000
--- a/src/workers/worker.js
+++ /dev/null
@@ -1,25 +0,0 @@
-onmessage = (e) => {
- const data = JSON.stringify(e.data.editorState, getCircularReplacer(), e.data.spaces);
- postMessage(data);
-};
-
-const getCircularReplacer = () => {
- const seen = new WeakSet();
- return (key, value) => {
- if (key === 'parent') {
- return;
- }
-
- if (key === 'SelectedContainer') {
- return;
- }
-
- if (typeof value === 'object' && value !== null) {
- if (seen.has(value)) {
- return;
- }
- seen.add(value);
- }
- return value;
- };
-};
diff --git a/test-server/http.js b/test-server/http.js
index 69088c9..c4f3238 100644
--- a/test-server/http.js
+++ b/test-server/http.js
@@ -76,6 +76,9 @@ const GetSVGLayoutConfiguration = () => {
fillOpacity: 0,
borderWidth: 2,
stroke: 'blue',
+ transform: 'translateX(-50%)',
+ transformOrigin: 'center',
+ transformBox: 'fill-box'
}
}
],
diff --git a/tsconfig.json b/tsconfig.json
index 2fe4d5a..034ee0e 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -16,7 +16,7 @@
"noEmit": true,
"jsx": "react-jsx"
},
- "include": ["src", "src/workers"],
+ "include": ["src"],
"exclude": ["test-server"],
"references": [{ "path": "./tsconfig.node.json" }]
}