diff --git a/.eslintrc b/.eslintrc index ed794d41..f46a9be7 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,7 +1,9 @@ { "extends": [ "airbnb", - "plugin:@typescript-eslint/recommended" + "plugin:@typescript-eslint/recommended", + "plugin:react/jsx-runtime", + "prettier" ], "parser": "@typescript-eslint/parser", "plugins": ["@typescript-eslint", "import"], @@ -28,17 +30,13 @@ }], "react/jsx-indent": ["error", 4], "react/jsx-indent-props": ["error", 4], - "react/jsx-filename-extension": ["error", {"extensions": [".jsx", ".js"]}], + "react/jsx-filename-extension": ["error", {"extensions": [".jsx", ".js", "tsx"]}], // I would like us to consider this in the future, but for now it is too sweeping of a change to be feasible // It also may make code less readable in a lot of places where we use both props and state in the same functions // (although this may be symptomatic of a bigger issue with naming things) "max-len": 0, "react/destructuring-assignment": ["off", "never"], "no-plusplus": ["off"], - "react/jsx-curly-newline": ["error", { - "singleline": "forbid", - "multiline": "require" - }], "operator-linebreak": ["error", "after", { "overrides": { "?": "before", @@ -61,7 +59,10 @@ "js": "never", "ts": "never", "tsx": "never" - }] + }], + "react/require-default-props": ["off"], + "react/function-component-definition": ["off"] , + "lines-between-class-members": ["error", "always", { "exceptAfterSingleLine": true }] } } ], diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..710965c7 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,26 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build + +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +package-lock.json +/public \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 69e286d2..59738712 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -306,6 +306,19 @@ - Stone of trials is now part of Sky Keep - Added semi-logical support for Batreaux's checks (by YourAverageLink) - Checks will be semi-logical if you have access to enough loose crystals to get the reward +- Added map layout (by YourAverageLink) + - If the map layout is enabled, the entire tracker is rearranged to make room for a large map display. + - Most notably, the dungeon block is completely redesigned, containing just the keys and dungeon abbreviations, and it has been moved with the rest of the items. + - A world map is shown, containing markers for the Thunderhead and Sky regions, as well as markers for four submaps (Skyloft, Faron, Eldin, and Lanayru) + - Hovering over a map marker displays the region name, how many checks are accessible, and how many are remaining. If a hint has been assigned to a region, it is also shown in the tooltip. Hovering over a submap displays the sum of all accessible and remaining checks in the province, as well as any hints marked in the submap's regions. + - The marker itself has the 'checked' color if no locations remain, the 'outLogic' color if no locations are accessible, the 'semiLogic' color with a number displaying how many checks are accessible if some are, and the 'inLogic' color plus how many locations are accessible if every location remainijg in the region is accessible. Markers have a 'squircle' shape (a square with rounded corners) + - Submaps + - When a submap marker is clicked, the map changes to the map for the selected submap. Its own regions are added, along with a button to return to the world map. + - Special markers + - Silent realms have circular markers on the map. + - Dungeon entrances have square markers on the map. If dungeon entrance rando is off, they are bound to their vanilla dungeon by default. + - If the entrance has no assigned dungeon, it displays '?', and when clicked, opens a context menu to select a dungeon to bind. + - Once a dungeon is bound, it is treated as a region in the containing submap (counts towards check total). It can be clicked on to open the check list, and it can be right-clicked to assign hints or to change which dungeon is bound there. ## Changes diff --git a/package-lock.json b/package-lock.json index 7b1dedd6..0e83e927 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,26 +23,41 @@ "react-router-dom": "^6.6.2", "react-scripts": "^5.0.1", "react-select": "^5.7.0", + "react-virtualized-auto-sizer": "^1.0.20", "react-window": "^1.8.8", "tippy.js": "^6.3.7" }, "devDependencies": { + "@types/js-yaml": "^4.0.5", + "@types/lodash": "^4.14.195", "@types/node": "^18.11.18", "@types/react": "^18.0.26", + "@types/react-bootstrap": "^0.32.32", "@types/react-dom": "^18.0.10", - "@typescript-eslint/eslint-plugin": "^5.48.2", - "@typescript-eslint/parser": "^5.48.2", - "eslint": "^8.31.0", + "@types/react-window": "^1.8.5", + "@typescript-eslint/eslint-plugin": "^5.56.0", + "@typescript-eslint/parser": "^5.56.0", + "eslint": "^8.36.0", "eslint-config-airbnb": "^19.0.4", + "eslint-config-prettier": "^8.8.0", "eslint-import-resolver-typescript": "^3.5.3", "eslint-plugin-import": "^2.27.5", - "eslint-plugin-jsx-a11y": "^6.7.0", - "eslint-plugin-react": "^7.31.11", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-react": "^7.32.2", "eslint-plugin-react-hooks": "^4.6.0", "gh-pages": "^4.0.0", + "prettier": "2.8.6", "typescript": "^4.9.4" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", @@ -2227,14 +2242,36 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", + "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -2250,9 +2287,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dependencies": { "type-fest": "^0.20.2" }, @@ -2274,6 +2311,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/js": { + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@floating-ui/core": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.1.0.tgz", @@ -2288,9 +2333,9 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -3784,6 +3829,12 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/js-yaml": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz", + "integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==", + "dev": true + }, "node_modules/@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -3794,6 +3845,12 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, + "node_modules/@types/lodash": { + "version": "4.14.195", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz", + "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==", + "dev": true + }, "node_modules/@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", @@ -3844,6 +3901,15 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-bootstrap": { + "version": "0.32.32", + "resolved": "https://registry.npmjs.org/@types/react-bootstrap/-/react-bootstrap-0.32.32.tgz", + "integrity": "sha512-GM9UtV7v+C2F0rbqgIpMWdCKBMdX3PQURoJQobPO4vDAeFadcExNtKffi13/MjaAks+riJKVGyiMe+6OmDYT2w==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-dom": { "version": "18.0.10", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz", @@ -3861,6 +3927,15 @@ "@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/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -3946,17 +4021,18 @@ "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.2.tgz", - "integrity": "sha512-sR0Gja9Ky1teIq4qJOl0nC+Tk64/uYdX+mi+5iB//MH8gwyx8e3SOyhEzeLZEFEEfCaLf8KJq+Bd/6je1t+CAg==", - "dependencies": { - "@typescript-eslint/scope-manager": "5.48.2", - "@typescript-eslint/type-utils": "5.48.2", - "@typescript-eslint/utils": "5.48.2", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", "debug": "^4.3.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" }, @@ -3978,12 +4054,12 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz", - "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dependencies": { - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/visitor-keys": "5.48.2" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3994,9 +4070,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz", - "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -4006,12 +4082,12 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz", - "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "dependencies": { - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/visitor-keys": "5.48.2", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4032,17 +4108,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz", - "integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.2", - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/typescript-estree": "5.48.2", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", "semver": "^7.3.7" }, "engines": { @@ -4057,11 +4133,11 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz", - "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dependencies": { - "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/types": "5.62.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -4131,9 +4207,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -4168,13 +4244,13 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.2.tgz", - "integrity": "sha512-38zMsKsG2sIuM5Oi/olurGwYJXzmtdsHhn5mI/pQogP+BjYVkK5iRazCQ8RGS0V+YLk282uWElN70zAAUmaYHw==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dependencies": { - "@typescript-eslint/scope-manager": "5.48.2", - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/typescript-estree": "5.48.2", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", "debug": "^4.3.4" }, "engines": { @@ -4194,12 +4270,12 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz", - "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dependencies": { - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/visitor-keys": "5.48.2" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -4210,9 +4286,9 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz", - "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -4222,12 +4298,12 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz", - "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "dependencies": { - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/visitor-keys": "5.48.2", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4248,11 +4324,11 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz", - "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dependencies": { - "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/types": "5.62.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -4302,9 +4378,9 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -4337,12 +4413,12 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.2.tgz", - "integrity": "sha512-QVWx7J5sPMRiOMJp5dYshPxABRoZV1xbRirqSk8yuIIsu0nvMTZesKErEA3Oix1k+uvsk8Cs8TGJ6kQ0ndAcew==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", "dependencies": { - "@typescript-eslint/typescript-estree": "5.48.2", - "@typescript-eslint/utils": "5.48.2", + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -4363,12 +4439,12 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz", - "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dependencies": { - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/visitor-keys": "5.48.2" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -4379,9 +4455,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz", - "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -4391,12 +4467,12 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz", - "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "dependencies": { - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/visitor-keys": "5.48.2", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4417,17 +4493,17 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz", - "integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.2", - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/typescript-estree": "5.48.2", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", "semver": "^7.3.7" }, "engines": { @@ -4442,11 +4518,11 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz", - "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dependencies": { - "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/types": "5.62.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -4516,9 +4592,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -4879,9 +4955,9 @@ } }, "node_modules/acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "bin": { "acorn": "bin/acorn" }, @@ -7388,12 +7464,15 @@ } }, "node_modules/eslint": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", - "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", - "dependencies": { - "@eslint/eslintrc": "^1.4.1", - "@humanwhocodes/config-array": "^0.11.8", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", + "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -7402,32 +7481,29 @@ "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.6.0", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -7482,6 +7558,18 @@ "eslint-plugin-import": "^2.25.2" } }, + "node_modules/eslint-config-prettier": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, "node_modules/eslint-config-react-app": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", @@ -7695,9 +7783,9 @@ } }, "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.0.tgz", - "integrity": "sha512-EGGRKhzejSzXKtjmEjWNtr4SK/DkMkSzkBH7g7e7moBDXZXrqaUIxkmD7uF93upMysc4dKYEJwupu7Dff+ShwA==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", + "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", "dependencies": { "@babel/runtime": "^7.20.7", "aria-query": "^5.1.3", @@ -7724,9 +7812,9 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.31.11", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz", - "integrity": "sha512-TTvq5JsT5v56wPa9OYHzsrOlHzKZKjV+aLgS+55NJP/cuzdiQPC7PfYoUjMoxlffKtvijpk7vA/jmuqRb9nohw==", + "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", "dependencies": { "array-includes": "^3.1.6", "array.prototype.flatmap": "^1.3.1", @@ -7740,7 +7828,7 @@ "object.hasown": "^1.1.2", "object.values": "^1.1.6", "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.3", + "resolve": "^2.0.0-next.4", "semver": "^6.3.0", "string.prototype.matchall": "^4.0.8" }, @@ -7805,15 +7893,18 @@ } }, "node_modules/eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-utils": { @@ -7842,11 +7933,14 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-webpack-plugin": { @@ -8057,13 +8151,13 @@ } }, "node_modules/espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.0.tgz", + "integrity": "sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==", "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -8085,9 +8179,9 @@ } }, "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dependencies": { "estraverse": "^5.1.0" }, @@ -9079,10 +9173,10 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" }, "node_modules/gzip-size": { "version": "6.0.0", @@ -12059,15 +12153,6 @@ "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.4.tgz", "integrity": "sha512-wpM/wi20Tl+3ifTyi0RdDckS4YTD4Lf953mBRrpG8547T7hInHNPEj8+ck4gB8VDcGyeAWFK++Wb/fU1BeavKQ==" }, - "node_modules/js-sdsl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -12942,16 +13027,16 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -14495,6 +14580,21 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.6.tgz", + "integrity": "sha512-mtuzdiBbHwPEgl7NxWlqOkithPyp4VN93V7VeHVWBF+ad3I5avc0RVDT4oImXQy9H/AqxA2NSQH8pSxHW6FYbQ==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -15202,6 +15302,15 @@ "react-dom": ">=16.6.0" } }, + "node_modules/react-virtualized-auto-sizer": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.20.tgz", + "integrity": "sha512-OdIyHwj4S4wyhbKHOKM1wLSj/UDXm839Z3Cvfg2a9j+He6yDa6i5p0qQvEiCnyQlGO/HyfSnigQwuxvYalaAXA==", + "peerDependencies": { + "react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0-rc", + "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0-rc" + } + }, "node_modules/react-window": { "version": "1.8.8", "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.8.tgz", @@ -15324,17 +15433,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, "node_modules/regexpu-core": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", @@ -18117,6 +18215,11 @@ } }, "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==" + }, "@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", @@ -19540,14 +19643,27 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.0.tgz", "integrity": "sha512-AHPmaAx+RYfZz0eYu6Gviiagpmiyw98ySSlQvCUhVGDRtDFe4DBS0x1bSjdF3gqUDYOczB+yYvBTtEylYSdRhg==" }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==" + }, "@eslint/eslintrc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", - "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz", + "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==", "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.4.0", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -19557,9 +19673,9 @@ }, "dependencies": { "globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "requires": { "type-fest": "^0.20.2" } @@ -19571,6 +19687,11 @@ } } }, + "@eslint/js": { + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz", + "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==" + }, "@floating-ui/core": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.1.0.tgz", @@ -19585,9 +19706,9 @@ } }, "@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "requires": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -20674,6 +20795,12 @@ "@types/istanbul-lib-report": "*" } }, + "@types/js-yaml": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz", + "integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==", + "dev": true + }, "@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -20684,6 +20811,12 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, + "@types/lodash": { + "version": "4.14.195", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.195.tgz", + "integrity": "sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==", + "dev": true + }, "@types/mime": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", @@ -20734,6 +20867,15 @@ "csstype": "^3.0.2" } }, + "@types/react-bootstrap": { + "version": "0.32.32", + "resolved": "https://registry.npmjs.org/@types/react-bootstrap/-/react-bootstrap-0.32.32.tgz", + "integrity": "sha512-GM9UtV7v+C2F0rbqgIpMWdCKBMdX3PQURoJQobPO4vDAeFadcExNtKffi13/MjaAks+riJKVGyiMe+6OmDYT2w==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/react-dom": { "version": "18.0.10", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz", @@ -20751,6 +20893,15 @@ "@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/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -20836,42 +20987,43 @@ "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" }, "@typescript-eslint/eslint-plugin": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.2.tgz", - "integrity": "sha512-sR0Gja9Ky1teIq4qJOl0nC+Tk64/uYdX+mi+5iB//MH8gwyx8e3SOyhEzeLZEFEEfCaLf8KJq+Bd/6je1t+CAg==", - "requires": { - "@typescript-eslint/scope-manager": "5.48.2", - "@typescript-eslint/type-utils": "5.48.2", - "@typescript-eslint/utils": "5.48.2", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "requires": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", "debug": "^4.3.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", - "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" }, "dependencies": { "@typescript-eslint/scope-manager": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz", - "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "requires": { - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/visitor-keys": "5.48.2" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" } }, "@typescript-eslint/types": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz", - "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==" + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==" }, "@typescript-eslint/typescript-estree": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz", - "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "requires": { - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/visitor-keys": "5.48.2", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -20880,26 +21032,26 @@ } }, "@typescript-eslint/utils": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz", - "integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "requires": { + "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.2", - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/typescript-estree": "5.48.2", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", "semver": "^7.3.7" } }, "@typescript-eslint/visitor-keys": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz", - "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "requires": { - "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/types": "5.62.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -20944,9 +21096,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -20967,37 +21119,37 @@ } }, "@typescript-eslint/parser": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.2.tgz", - "integrity": "sha512-38zMsKsG2sIuM5Oi/olurGwYJXzmtdsHhn5mI/pQogP+BjYVkK5iRazCQ8RGS0V+YLk282uWElN70zAAUmaYHw==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "requires": { - "@typescript-eslint/scope-manager": "5.48.2", - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/typescript-estree": "5.48.2", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", "debug": "^4.3.4" }, "dependencies": { "@typescript-eslint/scope-manager": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz", - "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "requires": { - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/visitor-keys": "5.48.2" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" } }, "@typescript-eslint/types": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz", - "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==" + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==" }, "@typescript-eslint/typescript-estree": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz", - "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "requires": { - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/visitor-keys": "5.48.2", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -21006,11 +21158,11 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz", - "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "requires": { - "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/types": "5.62.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -21041,9 +21193,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -21065,37 +21217,37 @@ } }, "@typescript-eslint/type-utils": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.2.tgz", - "integrity": "sha512-QVWx7J5sPMRiOMJp5dYshPxABRoZV1xbRirqSk8yuIIsu0nvMTZesKErEA3Oix1k+uvsk8Cs8TGJ6kQ0ndAcew==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", "requires": { - "@typescript-eslint/typescript-estree": "5.48.2", - "@typescript-eslint/utils": "5.48.2", + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, "dependencies": { "@typescript-eslint/scope-manager": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.2.tgz", - "integrity": "sha512-zEUFfonQid5KRDKoI3O+uP1GnrFd4tIHlvs+sTJXiWuypUWMuDaottkJuR612wQfOkjYbsaskSIURV9xo4f+Fw==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "requires": { - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/visitor-keys": "5.48.2" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" } }, "@typescript-eslint/types": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.2.tgz", - "integrity": "sha512-hE7dA77xxu7ByBc6KCzikgfRyBCTst6dZQpwaTy25iMYOnbNljDT4hjhrGEJJ0QoMjrfqrx+j1l1B9/LtKeuqA==" + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==" }, "@typescript-eslint/typescript-estree": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.2.tgz", - "integrity": "sha512-bibvD3z6ilnoVxUBFEgkO0k0aFvUc4Cttt0dAreEr+nrAHhWzkO83PEVVuieK3DqcgL6VAK5dkzK8XUVja5Zcg==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "requires": { - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/visitor-keys": "5.48.2", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -21104,26 +21256,26 @@ } }, "@typescript-eslint/utils": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.2.tgz", - "integrity": "sha512-2h18c0d7jgkw6tdKTlNaM7wyopbLRBiit8oAxoP89YnuBOzCZ8g8aBCaCqq7h208qUTroL7Whgzam7UY3HVLow==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "requires": { + "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.48.2", - "@typescript-eslint/types": "5.48.2", - "@typescript-eslint/typescript-estree": "5.48.2", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0", "semver": "^7.3.7" } }, "@typescript-eslint/visitor-keys": { - "version": "5.48.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.2.tgz", - "integrity": "sha512-z9njZLSkwmjFWUelGEwEbdf4NwKvfHxvGC0OcGN1Hp/XNDIcJ7D5DpPNPv6x6/mFvc1tQHsaWmpD/a4gOvvCJQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "requires": { - "@typescript-eslint/types": "5.48.2", + "@typescript-eslint/types": "5.62.0", "eslint-visitor-keys": "^3.3.0" } }, @@ -21168,9 +21320,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -21459,9 +21611,9 @@ } }, "acorn": { - "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==" + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==" }, "acorn-globals": { "version": "6.0.0", @@ -23294,12 +23446,15 @@ } }, "eslint": { - "version": "8.31.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", - "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", - "requires": { - "@eslint/eslintrc": "^1.4.1", - "@humanwhocodes/config-array": "^0.11.8", + "version": "8.44.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.44.0.tgz", + "integrity": "sha512-0wpHoUbDUHgNCyvFB5aXLiQVfK9B0at6gUvzy83k4kAsQ/u769TQDX6iKC+aO4upIHO9WSaA3QoXYQDHbNwf1A==", + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.1.0", + "@eslint/js": "8.44.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -23308,32 +23463,29 @@ "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.1.1", - "eslint-utils": "^3.0.0", - "eslint-visitor-keys": "^3.3.0", - "espree": "^9.4.0", - "esquery": "^1.4.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.6.0", + "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "regexpp": "^3.2.0", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" @@ -23425,6 +23577,13 @@ "semver": "^6.3.0" } }, + "eslint-config-prettier": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", + "dev": true, + "requires": {} + }, "eslint-config-react-app": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz", @@ -23578,9 +23737,9 @@ } }, "eslint-plugin-jsx-a11y": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.0.tgz", - "integrity": "sha512-EGGRKhzejSzXKtjmEjWNtr4SK/DkMkSzkBH7g7e7moBDXZXrqaUIxkmD7uF93upMysc4dKYEJwupu7Dff+ShwA==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.7.1.tgz", + "integrity": "sha512-63Bog4iIethyo8smBklORknVjB0T2dwB8Mr/hIC+fBS0uyHdYYpzM/Ed+YC8VxTjlXHEWFOdmgwcDn1U2L9VCA==", "requires": { "@babel/runtime": "^7.20.7", "aria-query": "^5.1.3", @@ -23601,9 +23760,9 @@ } }, "eslint-plugin-react": { - "version": "7.31.11", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.11.tgz", - "integrity": "sha512-TTvq5JsT5v56wPa9OYHzsrOlHzKZKjV+aLgS+55NJP/cuzdiQPC7PfYoUjMoxlffKtvijpk7vA/jmuqRb9nohw==", + "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", "requires": { "array-includes": "^3.1.6", "array.prototype.flatmap": "^1.3.1", @@ -23617,7 +23776,7 @@ "object.hasown": "^1.1.2", "object.values": "^1.1.6", "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.3", + "resolve": "^2.0.0-next.4", "semver": "^6.3.0", "string.prototype.matchall": "^4.0.8" }, @@ -23657,9 +23816,9 @@ } }, "eslint-scope": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", "requires": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -23681,9 +23840,9 @@ } }, "eslint-visitor-keys": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==" + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==" }, "eslint-webpack-plugin": { "version": "3.2.0", @@ -23758,13 +23917,13 @@ } }, "espree": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", - "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.0.tgz", + "integrity": "sha512-1FH/IiruXZ84tpUlm0aCUEwMl2Ho5ilqVh0VvQXw+byAz/4SAciyHLlfmL5WYqsvD38oymdUwBss0LtK8m4s/A==", "requires": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.1" } }, "esprima": { @@ -23773,9 +23932,9 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "requires": { "estraverse": "^5.1.0" } @@ -24503,10 +24662,10 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, - "grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" }, "gzip-size": { "version": "6.0.0", @@ -26647,11 +26806,6 @@ "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.4.tgz", "integrity": "sha512-wpM/wi20Tl+3ifTyi0RdDckS4YTD4Lf953mBRrpG8547T7hInHNPEj8+ck4gB8VDcGyeAWFK++Wb/fU1BeavKQ==" }, - "js-sdsl": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==" - }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -27295,16 +27449,16 @@ } }, "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" } }, "p-limit": { @@ -28227,6 +28381,12 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" }, + "prettier": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.6.tgz", + "integrity": "sha512-mtuzdiBbHwPEgl7NxWlqOkithPyp4VN93V7VeHVWBF+ad3I5avc0RVDT4oImXQy9H/AqxA2NSQH8pSxHW6FYbQ==", + "dev": true + }, "pretty-bytes": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", @@ -28746,6 +28906,12 @@ "prop-types": "^15.6.2" } }, + "react-virtualized-auto-sizer": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.20.tgz", + "integrity": "sha512-OdIyHwj4S4wyhbKHOKM1wLSj/UDXm839Z3Cvfg2a9j+He6yDa6i5p0qQvEiCnyQlGO/HyfSnigQwuxvYalaAXA==", + "requires": {} + }, "react-window": { "version": "1.8.8", "resolved": "https://registry.npmjs.org/react-window/-/react-window-1.8.8.tgz", @@ -28845,11 +29011,6 @@ "functions-have-names": "^1.2.2" } }, - "regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==" - }, "regexpu-core": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", diff --git a/package.json b/package.json index 5d66243f..b823083f 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "react-router-dom": "^6.6.2", "react-scripts": "^5.0.1", "react-select": "^5.7.0", + "react-virtualized-auto-sizer": "^1.0.20", "react-window": "^1.8.8", "tippy.js": "^6.3.7" }, @@ -44,19 +45,25 @@ ] }, "devDependencies": { + "@types/js-yaml": "^4.0.5", + "@types/lodash": "^4.14.195", "@types/node": "^18.11.18", "@types/react": "^18.0.26", + "@types/react-bootstrap": "^0.32.32", "@types/react-dom": "^18.0.10", - "@typescript-eslint/eslint-plugin": "^5.48.2", - "@typescript-eslint/parser": "^5.48.2", - "eslint": "^8.31.0", + "@types/react-window": "^1.8.5", + "@typescript-eslint/eslint-plugin": "^5.56.0", + "@typescript-eslint/parser": "^5.56.0", + "eslint": "^8.36.0", "eslint-config-airbnb": "^19.0.4", + "eslint-config-prettier": "^8.8.0", "eslint-import-resolver-typescript": "^3.5.3", "eslint-plugin-import": "^2.27.5", - "eslint-plugin-jsx-a11y": "^6.7.0", - "eslint-plugin-react": "^7.31.11", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-react": "^7.32.2", "eslint-plugin-react-hooks": "^4.6.0", "gh-pages": "^4.0.0", + "prettier": "2.8.6", "typescript": "^4.9.4" } } diff --git a/prettierrc.json b/prettierrc.json new file mode 100644 index 00000000..c0295ee5 --- /dev/null +++ b/prettierrc.json @@ -0,0 +1,5 @@ +{ + "tabWidth": 4, + "singleQuote": true, + "trailingComma": "all" +} \ No newline at end of file diff --git a/src/App.js b/src/App.js index 0b8ab120..5125b475 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,3 @@ -import React from 'react'; import './App.css'; import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; import Tracker from './Tracker'; diff --git a/src/BasicCounters.js b/src/BasicCounters.js index 8fedd492..3efa72ed 100644 --- a/src/BasicCounters.js +++ b/src/BasicCounters.js @@ -4,8 +4,9 @@ import ColorScheme from './customization/ColorScheme'; class BasicCounters extends React.Component { render() { + const leftPad = `${this.props.mapMode ? 2 : 0}%`; return ( -
+

{`Locations Checked: ${this.props.locationsChecked}`}

@@ -25,5 +26,9 @@ BasicCounters.propTypes = { totalAccessible: PropTypes.number.isRequired, checksRemaining: PropTypes.number.isRequired, colorScheme: PropTypes.instanceOf(ColorScheme).isRequired, + mapMode: PropTypes.bool, }; +BasicCounters.defaultProps = { + mapMode: false, +} export default BasicCounters; diff --git a/src/Tracker.js b/src/Tracker.js index b82cd262..b481e239 100644 --- a/src/Tracker.js +++ b/src/Tracker.js @@ -11,12 +11,14 @@ import GridTracker from './itemTracker/GridTracker'; import BasicCounters from './BasicCounters'; import ImportExport from './ImportExport'; import DungeonTracker from './itemTracker/DungeonTracker'; +import MapDungeonTracker from './itemTracker/MapDungeonTracker'; import CubeTracker from './locationTracker/CubeTracker'; import ColorScheme from './customization/ColorScheme'; import CustomizationModal from './customization/CustomizationModal'; import Logic from './logic/Logic'; import Settings from './permalink/Settings'; import EntranceTracker from './entranceTracker/EntranceTracker'; +import WorldMap from './locationTracker/mapTracker/WorldMap'; class Tracker extends React.Component { constructor(props) { @@ -28,9 +30,13 @@ class Tracker extends React.Component { if (!colorScheme) { colorScheme = new ColorScheme(); } - let layout = localStorage.getItem('ssrTrackerLayout'); - if (!layout) { - layout = 'inventory'; + let itemLayout = localStorage.getItem('ssrTrackerItemLayout'); + if (!itemLayout) { + itemLayout = 'inventory'; + } + let locationLayout = localStorage.getItem('ssrTrackerLocationLayout'); + if (!locationLayout) { + locationLayout = 'map'; } this.state = { settings: new Settings(), @@ -38,7 +44,8 @@ class Tracker extends React.Component { height: window.innerHeight, showCustomizationDialog: false, colorScheme, - layout, + itemLayout, + locationLayout, showEntranceDialog: false, source, }; @@ -46,6 +53,7 @@ class Tracker extends React.Component { // access to this.state and this.props this.handleGroupClick = this.handleGroupClick.bind(this); this.handleLocationClick = this.handleLocationClick.bind(this); + this.handleSubmapClick = this.handleSubmapClick.bind(this); this.handleItemClick = this.handleItemClick.bind(this); this.handleCubeClick = this.handleCubeClick.bind(this); this.handleDungeonClick = this.handleDungeonClick.bind(this); @@ -54,7 +62,10 @@ class Tracker extends React.Component { this.importState = this.importState.bind(this); this.updateColorScheme = this.updateColorScheme.bind(this); this.reset = this.reset.bind(this); - this.updateLayout = this.updateLayout.bind(this); + this.updateItemLayout = this.updateItemLayout.bind(this); + this.updateLocationLayout = this.updateLocationLayout.bind(this); + this.handleHintClick = this.handleHintClick.bind(this); + this.handleEntranceBind = this.handleEntranceBind.bind(this); // const storedState = JSON.parse(localStorage.getItem('ssrTrackerState')); // if (storedState) { // this.importState(storedState); @@ -78,7 +89,8 @@ class Tracker extends React.Component { componentDidUpdate() { localStorage.setItem('ssrTrackerState', JSON.stringify(this.state)); localStorage.setItem('ssrTrackerColorScheme', JSON.stringify(this.state.colorScheme)); - localStorage.setItem('ssrTrackerLayout', this.state.layout); + localStorage.setItem('ssrTrackerItemLayout', this.state.itemLayout); + localStorage.setItem('ssrTrackerLocationLayout', this.state.locationLayout); } componentWillUnmount() { @@ -93,6 +105,15 @@ class Tracker extends React.Component { } } + handleSubmapClick(submap) { + if (this.state.activeSubmap === submap) { + this.setState({ activeSubmap: '' }); // deselection if the opened group is clicked again + } else { + this.setState({ activeSubmap: submap }); + } + this.setState({ expandedGroup: '' }); // close active group as well + } + handleLocationClick(group, location, forceState) { if (forceState !== undefined) { if (location.checked !== forceState) { @@ -105,7 +126,6 @@ class Tracker extends React.Component { } // handle any locations that contribute to additional factors, such as // dungeon tracking - console.log(group); const { name } = location; if (name === 'Strike Crest') { if (group === 'Skyview') { @@ -161,8 +181,37 @@ class Tracker extends React.Component { this.forceUpdate(); } + handleHintClick(region, hint) { + this.state.logic.regionHints[region] = hint; + this.forceUpdate(); + } + + handleEntranceBind(entrance, region) { + const connections = (entrance.includes('Trial Gate') ? this.state.logic.trialConnections : this.state.logic.dungeonConnections); + const previousRegion = connections[entrance]; + connections[entrance] = region; + // this.state.logic.updateAccessibleEntrances(); + if (previousRegion !== '') { + this.state.logic.takeItem(_.camelCase(`Entered ${previousRegion}`)); + } + if (region !== '') { + this.state.logic.giveItem(_.camelCase(`Entered ${region}`)); + } + this.forceUpdate(); + } + handleCheckAllClick(region, checked) { + const finalChecks = [ + 'Strike Crest', + 'Exit Hall of Ancient Robots', + 'Farore\'s Flame', + 'Nayru\'s Flame', + 'Din\'s Flame', + ]; _.forEach(this.state.logic.locationsForArea(region), (location) => { + if (finalChecks.includes(location.name) && location.checked !== checked) { + this.state.logic.toggleDungeonCompleted(region) + } location.checked = checked; }); this.state.logic.updateAllCounters(); @@ -230,9 +279,14 @@ class Tracker extends React.Component { this.setState({ colorScheme }); } - updateLayout(e) { + updateItemLayout(e) { + const { value } = e.target; + this.setState({ itemLayout: value }); + } + + updateLocationLayout(e) { const { value } = e.target; - this.setState({ layout: value }); + this.setState({ locationLayout: value }); } async importState(state) { @@ -275,29 +329,35 @@ class Tracker extends React.Component { if (this.state.itemClicked) { this.itemClickedCounterUpdate(); } + const mapOn = this.state.locationLayout === 'map'; const itemTrackerStyle = { position: 'fixed', width: 12 * this.state.width / 30, // this is supposed to be *a bit* more than 1/3. Min keeps it visible when the window is short - height: this.state.height, - left: 0, + height: this.state.height * (mapOn ? 0.9 : 1), + left: '1%', top: 0, margin: '1%', }; const gridTrackerStyle = { - position: 'fixed', + position: 'relative', width: 2 * this.state.width / 5, height: this.state.height, left: 0, - top: 0, margin: '1%', }; const dungeonTrackerStyle = { - width: this.state.widthwidth / 3, + width: this.state.width / 3, + position: 'fixed', + }; + const dungeonMapTrackerStyle = { + width: this.state.width / 3.3, + height: this.state.height, + position: 'fixed', + bottom: 0, }; - let itemTracker; - if (this.state.layout === 'inventory') { + if (this.state.itemLayout === 'inventory') { itemTracker = ( ); - } else if (this.state.layout === 'grid') { + } else if (this.state.itemLayout === 'grid') { itemTracker = ( ); } - - return ( -
+ let mainTracker; + if (!mapOn) { + mainTracker = ( - - + {itemTracker} - - + - + - + + ) + } else { + const dungeonTracker = ( + + ) + mainTracker = ( + + + + {dungeonTracker} + {itemTracker} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) + } + + + + return ( +
+ {mainTracker} this.setState({ showCustomizationDialog: false })} colorScheme={this.state.colorScheme} updateColorScheme={this.updateColorScheme} - updateLayout={this.updateLayout} - selectedLayout={this.state.layout} + updateItemLayout={this.updateItemLayout} + updateLocationLayout={this.updateLocationLayout} + selectedItemLayout={this.state.itemLayout} + selectedLocationLayout={this.state.locationLayout} /> void; +export type LocationClickCallback = (group: stirng, location: ItemLocation, forceState?: boolean) => void; +export type DungeonClickCallback = (dungeon: string) => void; +export type CubeClickCallback = (location: string) => void; +export type ItemClickCallback = (item: string, take: boolean) => void; +export type ModalCloseCallback = () => void; +export type MarkerClickCallback = (region: string) => void; +export type HintClickCallback = (region: string, hint: string) => void; +export type EntranceBindCallback = (entrance: string, region: string) => void; +export type CheckAllClickCallback = (region: string, checked: boolean) => void; \ No newline at end of file diff --git a/src/customization/CustomizationModal.js b/src/customization/CustomizationModal.js index 26a6d2a7..7310ea2b 100644 --- a/src/customization/CustomizationModal.js +++ b/src/customization/CustomizationModal.js @@ -60,12 +60,21 @@ class CustomizationModal extends React.Component { -

Tracker Settings

+

Item Tracker Settings

- - - + + + + + + +

Location Tracker Settings

+
+ + + + @@ -83,8 +92,10 @@ CustomizationModal.propTypes = { onHide: PropTypes.func.isRequired, colorScheme: PropTypes.instanceOf(ColorScheme).isRequired, updateColorScheme: PropTypes.func.isRequired, - updateLayout: PropTypes.func.isRequired, - selectedLayout: PropTypes.string.isRequired, + updateItemLayout: PropTypes.func.isRequired, + updateLocationLayout: PropTypes.func.isRequired, + selectedItemLayout: PropTypes.string.isRequired, + selectedLocationLayout: PropTypes.string.isRequired, }; export default CustomizationModal; diff --git a/src/data/mapData.json b/src/data/mapData.json new file mode 100644 index 00000000..0571ceac --- /dev/null +++ b/src/data/mapData.json @@ -0,0 +1,221 @@ +{ + "skyloftSubmap": { + "name": "Skyloft", + "markerX": 48, + "markerY": 49, + "map": "skyloftMap", + "exitParams": { + "image": "leaveSkyloft", + "width": 15, + "left": 2, + "top": 1 + }, + "markers": [ + { + "region": "Upper Skyloft", + "markerX": 38, + "markerY": 35 + }, + { + "region": "Central Skyloft", + "markerX": 43.5, + "markerY": 57.5 + }, + { + "region": "Skyloft Village", + "markerX": 63.5, + "markerY": 70 + }, + { + "region": "Batreaux's House", + "markerX": 58, + "markerY": 85 + }, + { + "region": "Beedle's Shop", + "markerX": 80, + "markerY": 53 + } + ], + "entranceMarkers": [ + { + "region": "Dungeon Entrance on Skyloft", + "markerX": 50, + "markerY": 24 + }, + { + "region": "Trial Gate on Skyloft", + "markerX": 45, + "markerY": 85 + } + ] + }, + "faronSubmap": { + "name": "Faron Province", + "markerX": 67.6, + "markerY": 58, + "map": "faronMap", + "exitParams": { + "image": "leaveFaron", + "width": 12, + "left": 1, + "top": 1 + }, + "markers": [ + { + "region": "Sealed Grounds", + "markerX": 23, + "markerY": 62 + }, + { + "region": "Faron Woods", + "markerX": 45, + "markerY": 49 + }, + { + "region": "Lake Floria", + "markerX": 58, + "markerY": 77 + }, + { + "region": "Flooded Faron Woods", + "markerX": 80, + "markerY": 31 + } + ], + "entranceMarkers": [ + { + "region": "Dungeon Entrance in Deep Woods", + "markerX": 58.5, + "markerY": 14 + }, + { + "region": "Dungeon Entrance in Lake Floria", + "markerX": 45, + "markerY": 72 + }, + { + "region": "Trial Gate in Faron Woods", + "markerX": 58, + "markerY": 40 + } + ] + }, + "eldinSubmap": { + "name": "Eldin Province", + "markerX": 48, + "markerY": 22, + "map": "eldinMap", + "exitParams": { + "image": "leaveEldin", + "width": 14, + "left": 0, + "top": 14 + }, + "markers": [ + { + "region": "Eldin Volcano", + "markerX": 28, + "markerY": 73 + }, + { + "region": "Mogma Turf", + "markerX": 40, + "markerY": 72 + }, + { + "region": "Volcano Summit", + "markerX": 60, + "markerY": 40 + }, + { + "region": "Bokoblin Base", + "markerX": 80.7, + "markerY": 72 + } + ], + "entranceMarkers": [ + { + "region": "Dungeon Entrance in Eldin Volcano", + "markerX": 41.5, + "markerY": 57 + }, + { + "region": "Dungeon Entrance in Volcano Summit", + "markerX": 72, + "markerY": 30 + }, + { + "region": "Trial Gate in Eldin Volcano", + "markerX": 36, + "markerY": 62 + } + ] + }, + "lanayruSubmap": { + "name": "Lanayru Province", + "markerX": 27, + "markerY": 50, + "map": "lanayruMap", + "exitParams": { + "image": "leaveLanayru", + "width": 12, + "left": 7, + "top": 1 + }, + "markers": [ + { + "region": "Lanayru Mine", + "markerX": 72, + "markerY": 61.5 + }, + { + "region": "Lanayru Desert", + "markerX": 64, + "markerY": 38 + }, + { + "region": "Lanayru Caves", + "markerX": 55, + "markerY": 40 + }, + { + "region": "Lanayru Sand Sea", + "markerX": 36, + "markerY": 50 + }, + { + "region": "Lanayru Gorge", + "markerX": 55, + "markerY": 70 + } + ], + "entranceMarkers": [ + { + "region": "Dungeon Entrance in Lanayru Desert", + "markerX": 64, + "markerY": 26 + }, + { + "region": "Dungeon Entrance in Lanayru Sand Sea", + "markerX": 27, + "markerY": 45 + }, + { + "region": "Trial Gate in Lanayru Desert", + "markerX": 64, + "markerY": 14 + } + ] + }, + "thunderhead": { + "region": "Thunderhead", + "markerX": 16, + "markerY": 11 + }, + "sky": { + "region": "Sky", + "markerX": 85, + "markerY": 11 + } +} diff --git a/src/entranceTracker/EntranceTracker.js b/src/entranceTracker/EntranceTracker.js index 338ed974..80d83bc4 100644 --- a/src/entranceTracker/EntranceTracker.js +++ b/src/entranceTracker/EntranceTracker.js @@ -1,5 +1,5 @@ import _ from 'lodash'; -import React, { useEffect, useState } from 'react'; +import { useEffect, useState } from 'react'; import PropTypes from 'prop-types'; import { Modal, Button, Row, Col, FormCheck, FormControl } from 'react-bootstrap'; import { FixedSizeList as List } from 'react-window'; diff --git a/src/itemTracker/DungeonTracker.js b/src/itemTracker/DungeonTracker.js index 420c878b..da419b8b 100644 --- a/src/itemTracker/DungeonTracker.js +++ b/src/itemTracker/DungeonTracker.js @@ -100,9 +100,6 @@ class DungeonTracker extends React.Component { left: '2%', top: '-2%', }; - const keyColStyle = { - width: '25%', - }; return ( @@ -175,6 +173,7 @@ class DungeonTracker extends React.Component { parent={this.props.styleProps} dungeonChange={this.props.handleDungeonUpdate} colorScheme={this.props.colorScheme} + groupClicked={this.props.groupClicked} /> @@ -214,6 +213,7 @@ class DungeonTracker extends React.Component { parent={this.props.styleProps} dungeonChange={this.props.handleDungeonUpdate} colorScheme={this.props.colorScheme} + groupClicked={this.props.groupClicked} /> @@ -253,6 +253,7 @@ class DungeonTracker extends React.Component { parent={this.props.styleProps} dungeonChange={this.props.handleDungeonUpdate} colorScheme={this.props.colorScheme} + groupClicked={this.props.groupClicked} /> @@ -292,6 +293,7 @@ class DungeonTracker extends React.Component { parent={this.props.styleProps} dungeonChange={this.props.handleDungeonUpdate} colorScheme={this.props.colorScheme} + groupClicked={this.props.groupClicked} /> @@ -331,6 +333,7 @@ class DungeonTracker extends React.Component { parent={this.props.styleProps} dungeonChange={this.props.handleDungeonUpdate} colorScheme={this.props.colorScheme} + groupClicked={this.props.groupClicked} /> @@ -372,6 +375,7 @@ class DungeonTracker extends React.Component { parent={this.props.styleProps} dungeonChange={this.props.handleDungeonUpdate} colorScheme={this.props.colorScheme} + groupClicked={this.props.groupClicked} /> diff --git a/src/itemTracker/GridTracker.js b/src/itemTracker/GridTracker.js index 66096760..dd64cc25 100644 --- a/src/itemTracker/GridTracker.js +++ b/src/itemTracker/GridTracker.js @@ -52,147 +52,154 @@ class GridTracker extends React.Component { let imgWidth = this.props.styleProps.width / 10; const maxHeight = this.props.styleProps.height; - if (maxHeight < imgWidth * 8) { - imgWidth = maxHeight / 8; + const fraction = (this.props.mapMode ? 10 : 8) + if (maxHeight < imgWidth * fraction) { + imgWidth = maxHeight / fraction; + } + + const tableStyle = { + marginTop: (this.props.mapMode ? (imgWidth / 1.5) + 50 : 0), } const emptyTabWidth = imgWidth * 2.5; const emeraldWidth = emptyTabWidth * 0.54; const rubyWidth = emptyTabWidth * 0.74; const amberWidth = emptyTabWidth * 0.505; return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - -
- - - - -
-
- - - - - - - -
-

Caves

- -
- - - - - - - - -
- -
-
- -
-
- -
- - - - - - - - - - -
- -
-
- -
- - - - - - - - - - -
- -
-
- -
-
- -
- - - -
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+ + + + +
+
+ + + + + + + +
+

Caves

+ +
+ + + + + + + + +
+ +
+
+ +
+
+ +
+ + + + + + + + + + +
+ +
+
+ +
+ + + + + + + + + + +
+ +
+
+ +
+
+ +
+ + + +
+
); } } @@ -202,6 +209,10 @@ GridTracker.propTypes = { handleItemClick: PropTypes.func.isRequired, styleProps: PropTypes.shape().isRequired, colorScheme: PropTypes.instanceOf(ColorScheme).isRequired, + mapMode: PropTypes.bool, }; +GridTracker.propTypes = { + mapMode: false, +} export default GridTracker; diff --git a/src/itemTracker/ItemTracker.js b/src/itemTracker/ItemTracker.js index 55d07a0b..0b269796 100644 --- a/src/itemTracker/ItemTracker.js +++ b/src/itemTracker/ItemTracker.js @@ -12,6 +12,7 @@ import ColorScheme from '../customization/ColorScheme'; class ItemTracker extends React.Component { render() { const maxHeight = this.props.styleProps.height; + const map = this.props.mapMode; const aspectRatio = 0.65; let wid = this.props.styleProps.width; if (wid > maxHeight * aspectRatio) { @@ -22,40 +23,41 @@ class ItemTracker extends React.Component { height: 0, width: wid / 2.5, left: 0, - top: 0, - margin: '1%', + top: (map ? wid / 9 + this.props.styleProps.width / 50 + 10 : 0), // scaling here is complicated + margin: '0.5%', }; const songBlockStyle = { position: 'fixed', width: wid / 2.5, left: swordBlockStyle.width * 1.1, - margin: '1%', + margin: '0.5%', + top: swordBlockStyle.top, // border: '3px solid #73AD21', }; const bWheelStyle = { position: 'fixed', width: 2 * wid / 3, - left: swordBlockStyle.width * 0.3, // don't ask, this has to be like this so the b-wheel is somewhat centered - top: wid * 0.8, + left: swordBlockStyle.width * 0.28, // don't ask, this has to be like this so the b-wheel is somewhat centered + top: swordBlockStyle.top + wid * 0.8, margin: '0%', }; const additionalItemsStyle = { position: 'fixed', width: wid / 2.5, - top: wid * 0.55, + top: swordBlockStyle.top + wid * 0.55, left: wid * 0.44, - margin: '1%', + margin: '0.5%', }; const questItemsStyle = { position: 'fixed', width: wid / 2.5, - top: additionalItemsStyle.top + additionalItemsStyle.top / 12, + top: additionalItemsStyle.top + additionalItemsStyle.top / 14, left: 0, - margin: '1%', + margin: '0.5%', }; return ( @@ -99,5 +101,9 @@ ItemTracker.propTypes = { handleItemClick: PropTypes.func.isRequired, styleProps: PropTypes.shape().isRequired, colorScheme: PropTypes.instanceOf(ColorScheme).isRequired, + mapMode: PropTypes.bool, }; +ItemTracker.defaultProps = { + mapMode: false, +} export default ItemTracker; diff --git a/src/itemTracker/MapDungeonTracker.js b/src/itemTracker/MapDungeonTracker.js new file mode 100644 index 00000000..9e986670 --- /dev/null +++ b/src/itemTracker/MapDungeonTracker.js @@ -0,0 +1,243 @@ +import React from 'react'; +import Col from 'react-bootstrap/Col'; +// import { Stack } from 'react-bootstrap'; +import PropTypes from 'prop-types'; +import Item from './Item'; + +import noSmallKey from '../assets/dungeons/noSmallKey.png'; +import oneSmallKey from '../assets/dungeons/1_smallKey.png'; +import twoSmallKey from '../assets/dungeons/2_smallKey.png'; +import threeSmallKey from '../assets/dungeons/3_smallKey.png'; +import noEntrance from '../assets/No_Entrance.png'; +import entrance from '../assets/Entrance.png'; +import DungeonName from './items/dungeons/DungeonName'; +import ColorScheme from '../customization/ColorScheme'; +import Logic from '../logic/Logic'; + +class MapDungeonTracker extends React.Component { + constructor(props) { + super(props); + + this.smallKeyImages = [ + noSmallKey, + oneSmallKey, + twoSmallKey, + threeSmallKey, + ]; + this.dungeonEnteredImages = [ + noEntrance, + entrance, + ]; + } + + render() { + // eslint-disable-next-line react/destructuring-assignment + const wid = this.props.styleProps.width; + // const aspectRatio = 0.0; + const numDungeons = this.props.skyKeep ? 7 : 6; + const iconsPerDungeon = 2; + // scale icons differently with sky keep to keep things fitted all at once + const scaleFactor = (this.props.skyKeep ? 1.05 : 1); + const colWidth = wid / (numDungeons * iconsPerDungeon * scaleFactor); + const keysStyle = { + position: 'fixed', + margin: '0%', + left: '0.25%', + top: '0%', + width: wid, + }; + const dungeonStyle = { + position: 'relative', + top: wid * -0.015, + }; + return ( + { this.divElement = divElement; }} + style={{width: wid}} + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { + this.props.skyKeep && ( + + + + + + + + + ) + } +
+
+ + + +
+ +
+
+ + + +
+ +
+
+ + + +
+ +
+
+ + + +
+ +
+
+ + + +
+ +
+
+ + + +
+ +
+
+ + + +
+ +
+ + ); + } +} + +MapDungeonTracker.propTypes = { + skyKeep: PropTypes.bool.isRequired, + logic: PropTypes.instanceOf(Logic).isRequired, + styleProps: PropTypes.shape().isRequired, + handleDungeonUpdate: PropTypes.func.isRequired, + colorScheme: PropTypes.instanceOf(ColorScheme).isRequired, + handleItemClick: PropTypes.func.isRequired, + groupClicked: PropTypes.func.isRequired, +}; + +export default MapDungeonTracker; diff --git a/src/itemTracker/QuestItems.js b/src/itemTracker/QuestItems.js index 108faf9b..2d1b3793 100644 --- a/src/itemTracker/QuestItems.js +++ b/src/itemTracker/QuestItems.js @@ -10,23 +10,9 @@ import Logic from '../logic/Logic'; import ColorScheme from '../customization/ColorScheme'; class QuestItems extends React.Component { - constructor(props) { - super(props); - this.state = { - height: 0, - }; - } - - componentDidMount() { - this.setState({ height: this.divElement.clientHeight }); - } render() { const { width } = this.props.styleProps; - let { height } = this.state; - if (this.divElement !== undefined) { - height = this.divElement.clientHeight; - } const letterStyle = { position: 'relative', bottom: width * 0.18 + 900 / width, diff --git a/src/itemTracker/SongBlock.js b/src/itemTracker/SongBlock.js index 7a8486c9..4879aee3 100644 --- a/src/itemTracker/SongBlock.js +++ b/src/itemTracker/SongBlock.js @@ -70,7 +70,7 @@ class SongBlock extends React.Component { const triforceStyle = { position: 'relative', - bottom: (wid / 0.770 + 600 / wid), + bottom: (wid / 0.770 + 300 / wid), left: wid / 1.85, }; diff --git a/src/itemTracker/items/dungeons/DungeonName.js b/src/itemTracker/items/dungeons/DungeonName.js index 12f57cba..e6d28a54 100644 --- a/src/itemTracker/items/dungeons/DungeonName.js +++ b/src/itemTracker/items/dungeons/DungeonName.js @@ -11,8 +11,13 @@ class DungeonName extends React.Component { this.handleClick = this.handleClick.bind(this); } - handleClick() { - this.props.dungeonChange(this.props.dungeonName); + handleClick(e) { + if (e.type === 'contextmenu') { + this.props.groupClicked(this.props.dungeonName); + e.preventDefault(); + } else { + this.props.dungeonChange(this.props.dungeonName); + } } render() { @@ -21,7 +26,7 @@ class DungeonName extends React.Component { }; const completedState = this.props.logic.isDungeonCompleted(this.props.dungeonName) ? 'complete' : 'incomplete'; return ( -
+

{this.props.dungeon}

@@ -35,7 +40,9 @@ DungeonName.propTypes = { dungeon: PropTypes.string.isRequired, dungeonName: PropTypes.string.isRequired, dungeonChange: PropTypes.func.isRequired, + groupClicked: PropTypes.func.isRequired, logic: PropTypes.instanceOf(Logic).isRequired, }; + export default DungeonName; diff --git a/src/locationTracker/CubeTracker.js b/src/locationTracker/CubeTracker.js index a06c568c..750f96f9 100644 --- a/src/locationTracker/CubeTracker.js +++ b/src/locationTracker/CubeTracker.js @@ -13,10 +13,12 @@ class CubeTracker extends React.Component { return (
); } const filteredLocations = _.filter(this.props.locations, (location) => !location.nonprogress); - const locationChunks = _.chunk(filteredLocations, Math.ceil((_.size(filteredLocations) / 2))); + const numCols = (this.props.mapMode ? 1 : 2); + const rowStyle = (this.props.mapMode ? { paddingTop: '2%', paddingBottom: '2%', border: `1px solid ${this.props.colorScheme.text}` } : {}); + const locationChunks = _.chunk(filteredLocations, Math.ceil((_.size(filteredLocations) / numCols))); const arrangedLocations = _.zip(...locationChunks); const locationRows = _.map(arrangedLocations, (locationRow, index) => ( - + { _.map(locationRow, (location) => ( !_.isNil(location) && ( @@ -98,5 +100,9 @@ CubeTracker.propTypes = { logic: PropTypes.instanceOf(Logic).isRequired, colorScheme: PropTypes.instanceOf(ColorScheme).isRequired, containerHeight: PropTypes.number.isRequired, + mapMode: PropTypes.bool, }; +CubeTracker.defaultProps = { + mapMode: false, +} export default CubeTracker; diff --git a/src/locationTracker/Location.js b/src/locationTracker/Location.js index be9f3d4e..430fc2fd 100644 --- a/src/locationTracker/Location.js +++ b/src/locationTracker/Location.js @@ -1,4 +1,4 @@ -import React, { useCallback, useState } from 'react'; +import { useCallback, useState } from 'react'; import PropTypes from 'prop-types'; import { useContextMenu } from 'react-contexify'; import { Row, Col } from 'react-bootstrap'; @@ -16,7 +16,7 @@ import 'react-contexify/dist/ReactContexify.css'; import 'tippy.js/dist/tippy.css'; function Location(props) { - // eslint-disable-next-line no-unused-vars + // eslint-disable-next-line @typescript-eslint/no-unused-vars const [toggle, setToggle] = useState(false); function onClick(e) { diff --git a/src/locationTracker/LocationContextMenu.js b/src/locationTracker/LocationContextMenu.js index 7a06dd90..37ecb5b3 100644 --- a/src/locationTracker/LocationContextMenu.js +++ b/src/locationTracker/LocationContextMenu.js @@ -1,5 +1,5 @@ import _ from 'lodash'; -import React, { useCallback } from 'react'; +import { useCallback } from 'react'; import { Menu, Item, Separator, Submenu } from 'react-contexify'; import hintItems from '../data/hintItems.json'; diff --git a/src/locationTracker/LocationGroup.js b/src/locationTracker/LocationGroup.js index ad16b9f1..414ea22b 100644 --- a/src/locationTracker/LocationGroup.js +++ b/src/locationTracker/LocationGroup.js @@ -44,10 +44,13 @@ class LocationGroup extends React.Component { } )); - return ( + const numColumns = (this.props.mapMode ? 2 : 1); + const locationColumns = _.chunk(locationRows, Math.ceil((_.size(locationRows)) / numColumns)); + return (_.map(locationColumns, (locRows) => ( - {locationRows} + {locRows} + )) ); // return ( //
@@ -116,5 +119,9 @@ LocationGroup.propTypes = { meetsRequirement: PropTypes.func.isRequired, colorScheme: PropTypes.instanceOf(ColorScheme).isRequired, containerHeight: PropTypes.number.isRequired, + mapMode: PropTypes.bool, }; +LocationGroup.defaultProps = { + mapMode: false, +} export default LocationGroup; diff --git a/src/locationTracker/LocationGroupContextMenu.js b/src/locationTracker/LocationGroupContextMenu.js index 7e815a74..d241ef05 100644 --- a/src/locationTracker/LocationGroupContextMenu.js +++ b/src/locationTracker/LocationGroupContextMenu.js @@ -1,17 +1,36 @@ import _ from 'lodash'; -import React, { useCallback } from 'react'; +import { useCallback } from 'react'; import { Menu, Item, Separator, Submenu } from 'react-contexify'; +import PropTypes from 'prop-types'; +import Logic from '../logic/Logic'; -const bosses = { - 0: 'Ghirahim 1', - 1: 'Scaldera', - 2: 'Moldarach', - 3: 'Koloktos', - 4: 'Tentalus', - 5: 'Ghirahim 2', -}; +const bosses = [ + 'Ghirahim 1', + 'Scaldera', + 'Moldarach', + 'Koloktos', + 'Tentalus', + 'Ghirahim 2', +] -function LocationGroupContextMenu() { +const dungeons = [ + 'Skyview', + 'Earth Temple', + 'Lanayru Mining Facility', + 'Ancient Cistern', + 'Sandship', + 'Fire Sanctuary', + 'Sky Keep', +] + +const trials = [ + 'Skyloft Silent Realm', + 'Faron Silent Realm', + 'Eldin Silent Realm', + 'Lanayru Silent Realm', +] + +function LocationGroupContextMenu(props) { const checkAll = useCallback((params) => { const locProps = params.props; locProps.setAllLocationsChecked(true); @@ -24,43 +43,120 @@ function LocationGroupContextMenu() { const handlePathClick = useCallback((params) => { const locProps = params.props; - locProps.setPath(params.data.boss); + locProps.setHint(`Path to ${params.data.boss}`); }); const handleSotsClick = useCallback((params) => { const locProps = params.props; - locProps.setSots(true); + locProps.setHint('Spirit of the Sword'); }); const handleBarrenClick = useCallback((params) => { const locProps = params.props; - locProps.setBarren(true); + locProps.setHint('Barren'); }); const handleClearCheck = useCallback((params) => { const locProps = params.props; - locProps.setSots(false); - locProps.setBarren(false); - locProps.setPath(6); + locProps.setHint(''); }); + const handleEntranceBindClick = useCallback((params) => { + const locProps = params.props; + locProps.bindEntrance(params.data.region); + }); + + const dungeonsAlreadyConnected = Object.values(props.logic.dungeonConnections); + const trialsAlreadyConnected = Object.values(props.logic.trialConnections); + return ( - - Check All - Uncheck All - - - { - _.map(bosses, (bossName, bossIndex) => ( - {bossName} - )) - } - - Set SotS - Set Barren - Clear Hint - +
+ + Check All + Uncheck All + + + { + _.map(bosses, (bossName) => ( + {bossName} + )) + } + + Set SotS + Set Barren + Clear Hint + + + Check All + Uncheck All + + + { + _.map(bosses, (bossName) => ( + {bossName} + )) + } + + Set SotS + Set Barren + Clear Hint + + { + _.map(dungeons, (dungeonName) => ( + {dungeonName} + )) + } + Unbind Dungeon + + + + + { + _.map(dungeons, (dungeonName) => ( + {dungeonName} + )) + } + Unbind Dungeon + + + + Check All + Uncheck All + + + { + _.map(bosses, (bossName) => ( + {bossName} + )) + } + + Set SotS + Set Barren + Clear Hint + + { + _.map(trials, (trialName) => ( + {trialName} + )) + } + Unbind Silent Realm + + + + + { + _.map(trials, (trialName) => ( + {trialName} + )) + } + Unbind Silent Realm + + +
); } +LocationGroupContextMenu.propTypes = { + logic: PropTypes.instanceOf(Logic).isRequired, +} export default LocationGroupContextMenu; diff --git a/src/locationTracker/LocationGroupHeader.js b/src/locationTracker/LocationGroupHeader.js index 5837529a..b74431c4 100644 --- a/src/locationTracker/LocationGroupHeader.js +++ b/src/locationTracker/LocationGroupHeader.js @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useState } from 'react'; +import { useCallback } from 'react'; import PropTypes from 'prop-types'; import { useContextMenu } from 'react-contexify'; import { Col, Row } from 'react-bootstrap'; @@ -19,20 +19,20 @@ import g2 from '../assets/hints/g2.png'; import 'react-contexify/dist/ReactContexify.css'; -const pathImages = [ - g1, - scaldera, - moldarach, - koloktos, - tentalus, - g2, -]; +const pathImages = { + 'Ghirahim 1': g1, + 'Scaldera': scaldera, + 'Moldarach': moldarach, + 'Koloktos': koloktos, + 'Tentalus': tentalus, + 'Ghirahim 2': g2, +}; function LocationGroupHeader(props) { - const [sots, setSots] = useState(false); - const [barren, setBarren] = useState(false); - const [inEffect, setInEffect] = useState(false); - const [pathIndex, setPath] = useState(6); + const setHint = (value) => { + props.onHintClick(props.title, value); + }; + const setAllLocationsChecked = (value) => { props.onCheckAll(props.title, value); }; @@ -42,46 +42,21 @@ function LocationGroupHeader(props) { }); const displayMenu = useCallback((e) => { - show({ event: e, props: { setAllLocationsChecked, setSots, setBarren, setPath } }); + show({ event: e, props: { setAllLocationsChecked, setHint } }); }); - useEffect(() => { - if (inEffect) { - setInEffect(false); - } else { - setBarren(false); - setSots(false); - setInEffect(true); - } - }, [pathIndex]); - - useEffect(() => { - if (inEffect) { - setInEffect(false); - } else { - setBarren(false); - setPath(6); - setInEffect(true); - } - }, [sots]); - - useEffect(() => { - if (inEffect) { - setInEffect(false); - } else { - setSots(false); - setPath(6); - setInEffect(true); - } - }, [barren]); + let hint = ''; + if (props.logic.regionHints !== undefined) { + hint = props.logic.regionHints[props.title]; + }; let image; - if (pathIndex < 6) { - image = path; - } else if (sots) { - image = sots; - } else if (barren) { - image = barren; + if (hint.includes('Path')) { + image = {hint}; + } else if (hint === 'Spirit of the Sword') { + image = {hint}; + } else if (hint === 'Barren') { + image = {hint}; } return ( @@ -119,6 +94,7 @@ LocationGroupHeader.propTypes = { colorScheme: PropTypes.instanceOf(ColorScheme).isRequired, title: PropTypes.string.isRequired, onClick: PropTypes.func.isRequired, + onHintClick: PropTypes.func.isRequired, onCheckAll: PropTypes.func.isRequired, }; diff --git a/src/locationTracker/LocationTracker.js b/src/locationTracker/LocationTracker.js index 647e4b3a..5f59cb41 100644 --- a/src/locationTracker/LocationTracker.js +++ b/src/locationTracker/LocationTracker.js @@ -27,12 +27,12 @@ class LocationTracker extends React.Component { return ( - +
    { this.props.logic.areas().filter((area) => !areaBlacklist.includes(area)).map((value) => ( - + )) }
@@ -64,6 +64,7 @@ LocationTracker.propTypes = { expandedGroup: PropTypes.string, handleGroupClick: PropTypes.func.isRequired, handleLocationClick: PropTypes.func.isRequired, + handleHintClick: PropTypes.func.isRequired, handleCheckAllClick: PropTypes.func.isRequired, colorScheme: PropTypes.instanceOf(ColorScheme).isRequired, containerHeight: PropTypes.number.isRequired, diff --git a/src/locationTracker/mapTracker/EntranceMarker.tsx b/src/locationTracker/mapTracker/EntranceMarker.tsx new file mode 100644 index 00000000..9fb62508 --- /dev/null +++ b/src/locationTracker/mapTracker/EntranceMarker.tsx @@ -0,0 +1,226 @@ +import { CSSProperties, MouseEvent, useCallback } from 'react'; +import Tippy from '@tippyjs/react'; +import { followCursor } from 'tippy.js'; +import 'react-contexify/dist/ReactContexify.css'; +import { useContextMenu } from 'react-contexify'; +import AreaCounters from '../AreaCounters'; +import Logic from '../../logic/Logic'; +import LogicHelper from '../../logic/LogicHelper'; +import ColorScheme from '../../customization/ColorScheme'; +import { MarkerClickCallback, HintClickCallback, EntranceBindCallback, CheckAllClickCallback } from '../../callbacks'; +import keyDownWrapper from '../../KeyDownWrapper'; + +import sotsImage from '../../assets/hints/sots.png'; +import barrenImage from '../../assets/hints/barren.png'; + +import g1 from '../../assets/hints/g1.png'; +import scaldera from '../../assets/hints/scaldera.png'; +import moldarach from '../../assets/hints/moldarach.png'; +import koloktos from '../../assets/hints/koloktos.png'; +import tentalus from '../../assets/hints/tentalus.png'; +import g2 from '../../assets/hints/g2.png'; + + + +const pathImages: {[key: string]: string} = { + 'Ghirahim 1': g1, + 'Scaldera': scaldera, + 'Moldarach': moldarach, + 'Koloktos': koloktos, + 'Tentalus': tentalus, + 'Ghirahim 2': g2, +}; + +type EntranceMarkerProps = { + logic: Logic; + markerX: number; + markerY: number; + title: string; + onChange: MarkerClickCallback; + onHintClick: HintClickCallback; + onEntranceBind: EntranceBindCallback; + onCheckAll: CheckAllClickCallback; + mapWidth: number; + colorScheme: ColorScheme; + expandedGroup: string; +}; + +const EntranceMarker = (props: EntranceMarkerProps) => { + + const { onChange, onHintClick, onEntranceBind, onCheckAll, title, logic, markerX, markerY, mapWidth, colorScheme, expandedGroup} = props; + const isDungeon = !(title.includes('Trial Gate')); + let connections; + if (isDungeon) { + connections = logic.dungeonConnections; + } else { + connections = logic.trialConnections; + } + let region = ''; + if (connections !== undefined) { + region = connections[title as keyof typeof connections]; + } + const hasConnection = region !== '' && region !== undefined; + let remainingChecks = 0; + let accessibleChecks = 0; + if (hasConnection) { + remainingChecks = logic.getTotalCountForArea(region); + accessibleChecks = logic.getInLogicCountForArea(region); + } + const rawReq = logic.getRequirement(`Can ${isDungeon ? 'Access' : 'Open'} ${title}`); + const canReach = logic.areRequirementsMet(LogicHelper.booleanExpressionForRequirements(rawReq)); + let markerColor: string = colorScheme.outLogic; + if (hasConnection) { + if (accessibleChecks !== 0) { + markerColor = colorScheme.semiLogic; + } + if (accessibleChecks === remainingChecks) { + markerColor = colorScheme.inLogic; + } + if (remainingChecks === 0) { + markerColor = colorScheme.checked; + } + } else if (canReach) { + markerColor = colorScheme.inLogic; + } else { + markerColor = colorScheme.checked; + } + const setHint = (value: string) => { + if (hasConnection) { + onHintClick(region, value); + } + } + const bindEntrance = (exit: string) => { + onEntranceBind(title, exit) + } + + const showUnbound = useContextMenu({ + id: (isDungeon ? 'unbound-dungeon-context' : 'unbound-trial-context'), + }).show; + + const showBound = useContextMenu({ + id: (isDungeon ? 'dungeon-context' : 'trial-context'), + }).show; + + const setAllLocationsChecked = (value: boolean) => { + onCheckAll(region, value); + }; + + const displayMenu = useCallback((e: MouseEvent) => { + if (hasConnection) { + showBound({ event: e, props: { setHint, bindEntrance, setAllLocationsChecked } }); + } else { + showUnbound({ event: e, props: { setHint, bindEntrance } }); + } + }, [showBound, showUnbound]); + + let hint = ''; + if (logic.regionHints !== undefined && hasConnection) { + hint = logic.regionHints[region]; + } + + let image; + let hintColor = colorScheme.checked; + if (hint.includes('Path')) { + image = {hint}; + hintColor = colorScheme.inLogic; + } else if (hint === 'Spirit of the Sword') { + image = {hint}; + hintColor = colorScheme.inLogic; + } else if (hint === 'Barren') { + image = {hint}; + } + + const markerStyle: CSSProperties = { + position: 'absolute', + top: `${markerY}%`, + left: `${markerX}%`, + borderRadius: (isDungeon ? '0px' : '200px'), + background: markerColor, + width: mapWidth / 18, + height: mapWidth / 18, + border: '2px solid #000000', + textAlign: 'center', + fontSize: mapWidth / 27, + lineHeight: '1.2', + }; + + let tooltip; + + if (hasConnection) { + tooltip = ( +
+
{title}
+
{region} ({accessibleChecks}/{remainingChecks})
+
{hint}
+
+ ) + } else { + tooltip = ( +
+
{title} ({(canReach ? 'Accessible' : 'Inaccessible')})
+
Click to Attach {isDungeon ? 'Dungeon' : 'Silent Realm'}
+
+ ) + } + + const handleClick = (e: MouseEvent) => { + if (e.type === 'contextmenu') { + onChange(region); + e.preventDefault(); + } else if (!hasConnection) { + displayMenu(e); + } else { + onChange(region); + } + }; + + return ( +
+ +
+ + {(accessibleChecks > 0) && accessibleChecks} + {!hasConnection && '?'} + +
+
+ {expandedGroup === region && hasConnection && ( +
+
+

+ {region} +

+
+
+ {image} +
+
+

+ +

+
+
+ )} +
+ ); +}; + +export default EntranceMarker; \ No newline at end of file diff --git a/src/locationTracker/mapTracker/MapMarker.tsx b/src/locationTracker/mapTracker/MapMarker.tsx new file mode 100644 index 00000000..1c70ea4c --- /dev/null +++ b/src/locationTracker/mapTracker/MapMarker.tsx @@ -0,0 +1,173 @@ +import { CSSProperties, MouseEvent, useCallback } from 'react'; +import Tippy from '@tippyjs/react'; +import { followCursor } from 'tippy.js'; +import 'react-contexify/dist/ReactContexify.css'; +import { useContextMenu } from 'react-contexify'; +import AreaCounters from '../AreaCounters'; +import Logic from '../../logic/Logic'; +import ColorScheme from '../../customization/ColorScheme'; +import { CheckAllClickCallback, MarkerClickCallback, HintClickCallback } from '../../callbacks'; +import keyDownWrapper from '../../KeyDownWrapper'; + +import sotsImage from '../../assets/hints/sots.png'; +import barrenImage from '../../assets/hints/barren.png'; + +import g1 from '../../assets/hints/g1.png'; +import scaldera from '../../assets/hints/scaldera.png'; +import moldarach from '../../assets/hints/moldarach.png'; +import koloktos from '../../assets/hints/koloktos.png'; +import tentalus from '../../assets/hints/tentalus.png'; +import g2 from '../../assets/hints/g2.png'; + + + +const pathImages: {[key: string]: string} = { + 'Ghirahim 1': g1, + 'Scaldera': scaldera, + 'Moldarach': moldarach, + 'Koloktos': koloktos, + 'Tentalus': tentalus, + 'Ghirahim 2': g2, +}; + +type MapMarkerProps = { + logic: Logic; + markerX: number; + markerY: number; + title: string; + onChange: MarkerClickCallback; + onHintClick: HintClickCallback; + onCheckAll: CheckAllClickCallback; + mapWidth: number; + colorScheme: ColorScheme; + expandedGroup: string; +}; + +const MapMarker = (props: MapMarkerProps) => { + + const { onChange, onHintClick, onCheckAll, title, logic, markerX, markerY, mapWidth, colorScheme, expandedGroup} = props; + const remainingChecks: number = logic.getTotalCountForArea(title); + const accessibleChecks: number = logic.getInLogicCountForArea(title); + let markerColor: string = colorScheme.outLogic; + if (accessibleChecks !== 0) { + markerColor = colorScheme.semiLogic; + } + if (accessibleChecks === remainingChecks) { + markerColor = colorScheme.inLogic; + } + if (remainingChecks === 0) { + markerColor = colorScheme.checked; + } + + const setHint = (value: string) => { + onHintClick(title, value); + }; + + const setAllLocationsChecked = (value: boolean) => { + onCheckAll(title, value); + }; + + const { show } = useContextMenu({ + id: 'group-context', + }); + + const displayMenu = useCallback((e: MouseEvent) => { + show({ event: e, props: { setAllLocationsChecked, setHint } }); + }, [show]); + + let hint = ''; + if (logic.regionHints !== undefined) { + hint = logic.regionHints[title]; + }; + + let image; + let hintColor = colorScheme.checked; + if (hint.includes('Path')) { + image = {hint}; + hintColor = colorScheme.inLogic; + } else if (hint === 'Spirit of the Sword') { + image = {hint}; + hintColor = colorScheme.inLogic; + } else if (hint === 'Barren') { + image = {hint}; + }; + + const markerStyle: CSSProperties = { + position: 'absolute', + top: `${markerY}%`, + left: `${markerX}%`, + borderRadius: (title.includes('Silent Realm') ? '200px' : '8px'), + background: markerColor, + width: mapWidth / 18, + height: mapWidth / 18, + border: '2px solid #000000', + textAlign: 'center', + fontSize: mapWidth / 27, + lineHeight: '1.2', + }; + + const tooltip = ( +
+
{title} ({accessibleChecks}/{remainingChecks})
+
{hint}
+
+ ) + + const handleClick = (e: MouseEvent) => { + if (e.type === 'contextmenu') { + onChange(title); + e.preventDefault(); + } else { + onChange(title); + } + }; + + return ( +
+ +
+ + {(accessibleChecks > 0) && accessibleChecks} + +
+
+ {expandedGroup === title && ( +
+
+

+ {title} +

+
+
+ {image} +
+
+

+ +

+
+
+ )} +
+ ); +}; + +export default MapMarker; \ No newline at end of file diff --git a/src/locationTracker/mapTracker/Submap.tsx b/src/locationTracker/mapTracker/Submap.tsx new file mode 100644 index 00000000..5049d963 --- /dev/null +++ b/src/locationTracker/mapTracker/Submap.tsx @@ -0,0 +1,213 @@ +import { CSSProperties, MouseEvent, ReactNode } from 'react'; +import Tippy from '@tippyjs/react'; +import { followCursor } from 'tippy.js'; +import _ from 'lodash'; +import Logic from '../../logic/Logic'; +import ColorScheme from '../../customization/ColorScheme'; +import MapMarker from './MapMarker'; +import EntranceMarker from './EntranceMarker'; +import { MarkerClickCallback, HintClickCallback, EntranceBindCallback, CheckAllClickCallback } from '../../callbacks'; +import keyDownWrapper from '../../KeyDownWrapper'; +import leaveSkyloft from '../../assets/maps/leaveSkyloft.png'; +import leaveFaron from '../../assets/maps/leaveFaron.png'; +import leaveEldin from '../../assets/maps/leaveEldin.png'; +import leaveLanayru from '../../assets/maps/leaveLanayru.png'; + +export type MarkerParams = { + region: string, + markerX: number, + markerY: number, +}; + +export type ExitParams = { + image: string, + width: number, + left: number, + top: number +} + +type SubmapProps = { + logic: Logic; + markerX: number; + markerY: number; + title: string; + colorScheme: ColorScheme; + onSubmapChange: MarkerClickCallback; + onMarkerChange: MarkerClickCallback; + onHintClick: HintClickCallback; + onEntranceBind: EntranceBindCallback; + onCheckAll: CheckAllClickCallback; + markers: Array; + entranceMarkers: Array; + activeSubmap: string; + map: string; + mapWidth: number; + exitParams: ExitParams; + expandedGroup: string; +}; + +const images = new Map([ + ['leaveSkyloft', leaveSkyloft], + ['leaveFaron', leaveFaron], + ['leaveEldin', leaveEldin], + ['leaveLanayru', leaveLanayru], +]); + +const Submap = (props: SubmapProps) => { + let remainingChecks = 0 + let accessibleChecks = 0; + const subregionHints: Array = []; + const { onSubmapChange, onMarkerChange, onHintClick, onEntranceBind, onCheckAll, title, logic, markerX, markerY, mapWidth, activeSubmap, colorScheme, markers, entranceMarkers, exitParams, expandedGroup} = props; + _.forEach(markers, (marker) => { + remainingChecks += logic.getTotalCountForArea(marker.region); + accessibleChecks += logic.getInLogicCountForArea(marker.region); + if (logic.regionHints !== undefined) { + const hint = logic.regionHints[marker.region]; + if (hint) { + const hintColor: string = ((hint.includes('Path') || hint.includes('Spirit')) ? colorScheme.inLogic : colorScheme.checked) + subregionHints.push( +
{`${marker.region} is ${hint}`}
+ ) + } + } + }) + let connections; + _.forEach(entranceMarkers, (entrance) => { + if (!entrance.region.includes('Trial Gate')) { + connections = logic.dungeonConnections; + } else { + connections = logic.trialConnections; + } + if (connections !== undefined) { + const region = connections[entrance.region as keyof typeof connections]; + if (region !== '' && region !== undefined) { + remainingChecks += logic.getTotalCountForArea(region); + accessibleChecks += logic.getInLogicCountForArea(region); + if (logic.regionHints !== undefined) { + const hint = logic.regionHints[region]; + if (hint) { + const hintColor: string = ((hint.includes('Path') || hint.includes('Spirit')) ? colorScheme.inLogic : colorScheme.checked) + subregionHints.push( +
{`${region} is ${hint}`}
+ ) + } + } + } + } + }) + + let markerColor: string = colorScheme.outLogic; + if (accessibleChecks !== 0) { + markerColor = colorScheme.semiLogic; + } + if (accessibleChecks === remainingChecks) { + markerColor = colorScheme.inLogic; + } + if (remainingChecks === 0) { + markerColor = colorScheme.checked; + } + + const markerStyle: CSSProperties = { + position: 'absolute', + top: `${markerY}%`, + left: `${markerX}%`, + borderRadius: '5px', + background: markerColor, + width: mapWidth / 18, + height: mapWidth / 18, + border: '2px solid #000000', + textAlign: 'center', + fontSize: mapWidth / 27, + lineHeight: '1.2', + }; + + const tooltip = ( +
+
{title} ({accessibleChecks}/{remainingChecks})
+
Click to Expand
+ {subregionHints} +
+ ) + + const handleClick = (e: MouseEvent) => { + if (e.type === 'contextmenu') { + onSubmapChange(title); + e.preventDefault(); + } else { + onSubmapChange(title); + } + }; + + const markerElement = ( + +
+ + {(accessibleChecks > 0) && accessibleChecks} + +
+
+ ); + + const mapElement = ( +
+ {`${title} + {markers.map((marker) => ( + + ))} + {entranceMarkers.map((entrance) => ( + + ))} +
+ Back to Sky +
+
+ ); + + return ( +
+
+ {mapElement} +
+
+ {markerElement} +
+
+ ); +}; + +export default Submap; diff --git a/src/locationTracker/mapTracker/WorldMap.tsx b/src/locationTracker/mapTracker/WorldMap.tsx new file mode 100644 index 00000000..76c64c49 --- /dev/null +++ b/src/locationTracker/mapTracker/WorldMap.tsx @@ -0,0 +1,155 @@ +import { Row, Col } from 'react-bootstrap'; +import Logic from '../../logic/Logic'; +import skyMap from '../../assets/maps/Sky.png'; +import faronMap from '../../assets/maps/Faron.png'; +import eldinMap from '../../assets/maps/Eldin.png'; +import lanayruMap from '../../assets/maps/Lanayru.png'; +import skyloftMap from '../../assets/maps/Skyloft.png'; +import MapMarker from './MapMarker'; +import ColorScheme from '../../customization/ColorScheme'; +import LocationGroup from '../LocationGroup'; +import Submap from './Submap'; +import { MarkerClickCallback, LocationClickCallback, HintClickCallback, EntranceBindCallback, CheckAllClickCallback } from '../../callbacks'; +import mapData from '../../data/mapData.json'; +import LocationContextMenu from '../LocationContextMenu'; +import LocationGroupContextMenu from '../LocationGroupContextMenu'; + +type WorldMapProps = { + logic: Logic, + imgWidth: number, + colorScheme: ColorScheme, + handleGroupClick: MarkerClickCallback + handleSubmapClick: MarkerClickCallback, + handleLocationClick: LocationClickCallback, + handleHintClick: HintClickCallback, + handleEntranceBind: EntranceBindCallback, + handleCheckAllClick: CheckAllClickCallback, + containerHeight: number, + expandedGroup: string, + activeSubmap: string, +}; + +const images = new Map([ + ['skyloftMap', skyloftMap], + ['faronMap', faronMap], + ['eldinMap', eldinMap], + ['lanayruMap', lanayruMap], +]); + +const WorldMap = (props: WorldMapProps) => { + const {containerHeight, activeSubmap, expandedGroup, logic, colorScheme, handleGroupClick, handleSubmapClick, handleHintClick, handleLocationClick, handleEntranceBind, handleCheckAllClick} = props; + let { imgWidth } = props; + // original image dimensions + const aspectRatio = 843/465; + let imgHeight = imgWidth / aspectRatio; + if (imgHeight > containerHeight * 0.55) { + imgHeight = containerHeight * 0.55; + imgWidth = imgHeight * aspectRatio; + } + const { + skyloftSubmap, + faronSubmap, + eldinSubmap, + lanayruSubmap, + thunderhead, + sky, + } = mapData; + + const submaps = [ + faronSubmap, + skyloftSubmap, + eldinSubmap, + lanayruSubmap, + ]; + + const markers = [ + thunderhead, + sky, + ]; + + const worldMap = ( +
+
+ {!activeSubmap && + World Map + } + {markers.map((marker) => ( +
+ +
+ ))} + {submaps.map((submap) => ( + + ))} +
+ + +
+ ); + const locationList = ( +
+ { + expandedGroup && ( + + + + + + ) + } +
+ ); + + + return ( +
+ {worldMap} + {locationList} +
+ ); +} + +export default WorldMap; diff --git a/src/logic/Logic.js b/src/logic/Logic.js index 05003755..d78ff47f 100644 --- a/src/logic/Logic.js +++ b/src/logic/Logic.js @@ -122,6 +122,24 @@ class Logic { this.additionalLocations = {}; this.cubeList = {}; this.crystalList = {}; + this.regionHints = Object.fromEntries(this.locations.allAreas().map(k => [k, ''])); + this.entranceRando = this.settings.options.randomizeEntrances; + this.trialRando = this.settings.getOption('Randomize Silent Realms'); + this.dungeonConnections = { + 'Dungeon Entrance in Deep Woods': (this.entranceRando !== 'None' ? '' : 'Skyview'), + 'Dungeon Entrance in Eldin Volcano': (this.entranceRando !== 'None' ? '' : 'Earth Temple'), + 'Dungeon Entrance in Lanayru Desert': (this.entranceRando !== 'None' ? '' : 'Lanayru Mining Facility'), + 'Dungeon Entrance in Lake Floria': (this.entranceRando !== 'None' ? '' : 'Ancient Cistern'), + 'Dungeon Entrance in Lanayru Sand Sea': (this.entranceRando !== 'None' ? '' : 'Sandship'), + 'Dungeon Entrance in Volcano Summit': (this.entranceRando !== 'None' ? '' : 'Fire Sanctuary'), + 'Dungeon Entrance on Skyloft': (this.entranceRando === 'All Surface Dungeons + Sky Keep' ? '' : 'Sky Keep'), + }; + this.trialConnections = { + 'Trial Gate on Skyloft': (this.trialRando ? '' : 'Skyloft Silent Realm'), + 'Trial Gate in Faron Woods': (this.trialRando ? '' : 'Faron Silent Realm'), + 'Trial Gate in Eldin Volcano': (this.trialRando ? '' : 'Eldin Silent Realm'), + 'Trial Gate in Lanayru Desert': (this.trialRando ? '' : 'Lanayru Silent Realm'), + }; _.forEach(goddessCubes, (cube, cubeRequirementName) => { const nonprogress = false; @@ -208,6 +226,8 @@ class Logic { this.fivePacks = logic.fivePacks; this.maxFivePacks = logic.maxFivePacks; this.cubeList = logic.cubeList; + this.regionHints = logic.regionHints; + this.dungeonConnections = logic.dungeonConnections; _.forEach(this.cubeList, (cube) => { cube.booleanExpression = LogicHelper.booleanExpressionForRequirements(cube.logicSentence); const simplifiedExpression = cube.booleanExpression.simplify({ diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts new file mode 100644 index 00000000..6889c6b3 --- /dev/null +++ b/src/react-app-env.d.ts @@ -0,0 +1 @@ +/// \ No newline at end of file