From 39c1b0f8d199cadc58c42d002b28ac97204d2e4e Mon Sep 17 00:00:00 2001
From: Yury Molodov <yurymolodov@gmail.com>
Date: Tue, 16 May 2023 15:41:06 +0200
Subject: [PATCH] vmui: refactor code using custom hooks  (#4145)

* refactor: replace boolean useState with useBoolean

* refactor: replace useResize with useWindowSize/useElementSize

* refactor: replace addEventListener with useEventListener

* refactor: replace navigator.clipboard.writeText with useCopyToClipboard

* fix: prevent redirect loop
---
 app/vmui/packages/vmui/package-lock.json      | 1882 +++++++++--------
 .../components/Chart/BarChart/BarChart.tsx    |    4 +-
 .../src/components/Chart/BarChart/types.ts    |    3 +-
 .../ChartTooltipHeatmap.tsx                   |   28 +-
 .../Heatmap/HeatmapChart/HeatmapChart.tsx     |   60 +-
 .../Chart/Line/ChartTooltip/ChartTooltip.tsx  |   26 +-
 .../Line/Legend/LegendItem/LegendItem.tsx     |    7 +-
 .../Chart/Line/LineChart/LineChart.tsx        |   50 +-
 .../Chart/SimpleBarChart/style.scss           |    4 +-
 .../AdditionalSettings/AdditionalSettings.tsx |   16 +-
 .../GlobalSettings/GlobalSettings.tsx         |   22 +-
 .../TenantsConfiguration.tsx                  |   16 +-
 .../GlobalSettings/Timezones/Timezones.tsx    |   16 +-
 .../GraphSettings/GraphSettings.tsx           |   16 +-
 .../StepConfigurator/StepConfigurator.tsx     |   16 +-
 .../ExecutionControls/ExecutionControls.tsx   |   21 +-
 .../TimeSelector/TimeSelector.tsx             |   28 +-
 .../ExploreMetricItemGraph.tsx                |   10 +-
 .../ExploreMetricItem/ExploreMetricItem.tsx   |    4 +-
 .../ExploreMetricItemHeader.tsx               |   18 +-
 .../src/components/Layout/Header/Header.tsx   |    4 +-
 .../Header/HeaderControls/HeaderControls.tsx  |   18 +-
 .../Layout/Header/HeaderNav/NavSubItem.tsx    |   16 +-
 .../Header/SidebarNav/SidebarHeader.tsx       |   16 +-
 .../vmui/src/components/Layout/Layout.tsx     |   11 +-
 .../Main/Autocomplete/Autocomplete.tsx        |   29 +-
 .../components/Main/DatePicker/DatePicker.tsx |   34 +-
 .../components/Main/Icons/PreviewIcons.tsx    |   13 +-
 .../vmui/src/components/Main/Modal/Modal.tsx  |   27 +-
 .../src/components/Main/Popper/Popper.tsx     |   47 +-
 .../src/components/Main/Select/Select.tsx     |    9 +-
 .../Main/ShortcutKeys/ShortcutKeys.tsx        |   29 +-
 .../components/Main/ShortcutKeys/style.scss   |    1 +
 .../vmui/src/components/Main/Tabs/Tabs.tsx    |    4 +-
 .../Main/ThemeProvider/ThemeProvider.ts       |    4 +-
 .../src/components/Main/Tooltip/Tooltip.tsx   |   10 +-
 .../components/Views/GraphView/GraphView.tsx  |   13 +-
 .../components/Views/JsonView/JsonView.tsx    |    9 +-
 .../components/Views/TableView/TableView.tsx  |   32 +-
 .../vmui/src/hooks/useClickOutside.ts         |   33 +-
 .../vmui/src/hooks/useCopyToClipboard.ts      |   32 +
 .../vmui/src/hooks/useDeviceDetect.ts         |    4 +-
 .../packages/vmui/src/hooks/useDropzone.ts    |   27 +-
 .../packages/vmui/src/hooks/useElementSize.ts |   36 +
 .../vmui/src/hooks/useEventListener.ts        |   81 +
 .../src/hooks/useIsomorphicLayoutEffect.ts    |    5 +
 app/vmui/packages/vmui/src/hooks/useResize.ts |   21 -
 .../packages/vmui/src/hooks/useWindowSize.ts  |   31 +
 .../Table/TableSettings/TableSettings.tsx     |   19 +-
 .../vmui/src/pages/CustomPanel/index.tsx      |   16 +-
 .../PredefinedDashboard.tsx                   |   30 +-
 .../PredefinedDashboard/style.scss            |    2 +-
 .../src/pages/TracePage/JsonForm/JsonForm.tsx |    7 +-
 .../vmui/src/pages/TracePage/index.tsx        |   16 +-
 54 files changed, 1572 insertions(+), 1361 deletions(-)
 create mode 100644 app/vmui/packages/vmui/src/hooks/useCopyToClipboard.ts
 create mode 100644 app/vmui/packages/vmui/src/hooks/useElementSize.ts
 create mode 100644 app/vmui/packages/vmui/src/hooks/useEventListener.ts
 create mode 100644 app/vmui/packages/vmui/src/hooks/useIsomorphicLayoutEffect.ts
 delete mode 100644 app/vmui/packages/vmui/src/hooks/useResize.ts
 create mode 100644 app/vmui/packages/vmui/src/hooks/useWindowSize.ts

diff --git a/app/vmui/packages/vmui/package-lock.json b/app/vmui/packages/vmui/package-lock.json
index e697d80303..d5c3590baf 100644
--- a/app/vmui/packages/vmui/package-lock.json
+++ b/app/vmui/packages/vmui/package-lock.json
@@ -46,18 +46,18 @@
       }
     },
     "node_modules/@adobe/css-tools": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.0.2.tgz",
-      "integrity": "sha512-Fx6tYjk2wKUgLi8uMANZr8GNZx05u44ArIJldn9VxLvolzlJVgHbTUCbwhMd6bcYky178+WUSxPHO3DAtGLWpw=="
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.2.0.tgz",
+      "integrity": "sha512-E09FiIft46CmH5Qnjb0wsW54/YQd69LsxeKUOWawmws1XWvyFGURnAChH0mlr7YPFR1ofwvUQfcL0J3lMxXqPA=="
     },
     "node_modules/@ampproject/remapping": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
-      "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
+      "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@jridgewell/gen-mapping": "^0.1.0",
+        "@jridgewell/gen-mapping": "^0.3.0",
         "@jridgewell/trace-mapping": "^0.3.9"
       },
       "engines": {
@@ -65,9 +65,9 @@
       }
     },
     "node_modules/@babel/code-frame": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
-      "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
+      "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==",
       "dependencies": {
         "@babel/highlight": "^7.18.6"
       },
@@ -76,9 +76,9 @@
       }
     },
     "node_modules/@babel/compat-data": {
-      "version": "7.20.10",
-      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz",
-      "integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz",
+      "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==",
       "dev": true,
       "peer": true,
       "engines": {
@@ -86,22 +86,22 @@
       }
     },
     "node_modules/@babel/core": {
-      "version": "7.20.12",
-      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz",
-      "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz",
+      "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@ampproject/remapping": "^2.1.0",
-        "@babel/code-frame": "^7.18.6",
-        "@babel/generator": "^7.20.7",
-        "@babel/helper-compilation-targets": "^7.20.7",
-        "@babel/helper-module-transforms": "^7.20.11",
-        "@babel/helpers": "^7.20.7",
-        "@babel/parser": "^7.20.7",
+        "@ampproject/remapping": "^2.2.0",
+        "@babel/code-frame": "^7.21.4",
+        "@babel/generator": "^7.21.4",
+        "@babel/helper-compilation-targets": "^7.21.4",
+        "@babel/helper-module-transforms": "^7.21.2",
+        "@babel/helpers": "^7.21.0",
+        "@babel/parser": "^7.21.4",
         "@babel/template": "^7.20.7",
-        "@babel/traverse": "^7.20.12",
-        "@babel/types": "^7.20.7",
+        "@babel/traverse": "^7.21.4",
+        "@babel/types": "^7.21.4",
         "convert-source-map": "^1.7.0",
         "debug": "^4.1.0",
         "gensync": "^1.0.0-beta.2",
@@ -117,9 +117,9 @@
       }
     },
     "node_modules/@babel/eslint-parser": {
-      "version": "7.19.1",
-      "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz",
-      "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==",
+      "version": "7.21.3",
+      "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.21.3.tgz",
+      "integrity": "sha512-kfhmPimwo6k4P8zxNs8+T7yR44q1LdpsZdE1NkCsVlfiuTPRfnGgjaF8Qgug9q9Pou17u6wneYF0lDCZJATMFg==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -146,35 +146,21 @@
       }
     },
     "node_modules/@babel/generator": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz",
-      "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz",
+      "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/types": "^7.20.7",
+        "@babel/types": "^7.21.4",
         "@jridgewell/gen-mapping": "^0.3.2",
+        "@jridgewell/trace-mapping": "^0.3.17",
         "jsesc": "^2.5.1"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
-    "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
-      "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
-      "dev": true,
-      "peer": true,
-      "dependencies": {
-        "@jridgewell/set-array": "^1.0.1",
-        "@jridgewell/sourcemap-codec": "^1.4.10",
-        "@jridgewell/trace-mapping": "^0.3.9"
-      },
-      "engines": {
-        "node": ">=6.0.0"
-      }
-    },
     "node_modules/@babel/helper-annotate-as-pure": {
       "version": "7.18.6",
       "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz",
@@ -203,14 +189,14 @@
       }
     },
     "node_modules/@babel/helper-compilation-targets": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz",
-      "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz",
+      "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/compat-data": "^7.20.5",
-        "@babel/helper-validator-option": "^7.18.6",
+        "@babel/compat-data": "^7.21.4",
+        "@babel/helper-validator-option": "^7.21.0",
         "browserslist": "^4.21.3",
         "lru-cache": "^5.1.1",
         "semver": "^6.3.0"
@@ -223,16 +209,16 @@
       }
     },
     "node_modules/@babel/helper-create-class-features-plugin": {
-      "version": "7.20.12",
-      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz",
-      "integrity": "sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.21.4.tgz",
+      "integrity": "sha512-46QrX2CQlaFRF4TkwfTt6nJD7IHq8539cCL7SDpqWSDeJKY1xylKKY5F/33mJhLZ3mFvKv2gGrVS6NkyF6qs+Q==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "@babel/helper-annotate-as-pure": "^7.18.6",
         "@babel/helper-environment-visitor": "^7.18.9",
-        "@babel/helper-function-name": "^7.19.0",
-        "@babel/helper-member-expression-to-functions": "^7.20.7",
+        "@babel/helper-function-name": "^7.21.0",
+        "@babel/helper-member-expression-to-functions": "^7.21.0",
         "@babel/helper-optimise-call-expression": "^7.18.6",
         "@babel/helper-replace-supers": "^7.20.7",
         "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0",
@@ -246,14 +232,14 @@
       }
     },
     "node_modules/@babel/helper-create-regexp-features-plugin": {
-      "version": "7.20.5",
-      "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz",
-      "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.21.4.tgz",
+      "integrity": "sha512-M00OuhU+0GyZ5iBBN9czjugzWrEq2vDpf/zCYHxxf93ul/Q5rv+a5h+/+0WnI1AebHNVtl5bFV0qsJoH23DbfA==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "@babel/helper-annotate-as-pure": "^7.18.6",
-        "regexpu-core": "^5.2.1"
+        "regexpu-core": "^5.3.1"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -281,13 +267,13 @@
       }
     },
     "node_modules/@babel/helper-define-polyfill-provider/node_modules/resolve": {
-      "version": "1.22.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
-      "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+      "version": "1.22.3",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz",
+      "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "is-core-module": "^2.9.0",
+        "is-core-module": "^2.12.0",
         "path-parse": "^1.0.7",
         "supports-preserve-symlinks-flag": "^1.0.0"
       },
@@ -322,14 +308,14 @@
       }
     },
     "node_modules/@babel/helper-function-name": {
-      "version": "7.19.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
-      "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz",
+      "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/template": "^7.18.10",
-        "@babel/types": "^7.19.0"
+        "@babel/template": "^7.20.7",
+        "@babel/types": "^7.21.0"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -349,35 +335,35 @@
       }
     },
     "node_modules/@babel/helper-member-expression-to-functions": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz",
-      "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.21.0.tgz",
+      "integrity": "sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/types": "^7.20.7"
+        "@babel/types": "^7.21.0"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-module-imports": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
-      "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz",
+      "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/types": "^7.18.6"
+        "@babel/types": "^7.21.4"
       },
       "engines": {
         "node": ">=6.9.0"
       }
     },
     "node_modules/@babel/helper-module-transforms": {
-      "version": "7.20.11",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz",
-      "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==",
+      "version": "7.21.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz",
+      "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -387,8 +373,8 @@
         "@babel/helper-split-export-declaration": "^7.18.6",
         "@babel/helper-validator-identifier": "^7.19.1",
         "@babel/template": "^7.20.7",
-        "@babel/traverse": "^7.20.10",
-        "@babel/types": "^7.20.7"
+        "@babel/traverse": "^7.21.2",
+        "@babel/types": "^7.21.2"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -511,9 +497,9 @@
       }
     },
     "node_modules/@babel/helper-validator-option": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
-      "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz",
+      "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==",
       "dev": true,
       "peer": true,
       "engines": {
@@ -537,15 +523,15 @@
       }
     },
     "node_modules/@babel/helpers": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz",
-      "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz",
+      "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "@babel/template": "^7.20.7",
-        "@babel/traverse": "^7.20.7",
-        "@babel/types": "^7.20.7"
+        "@babel/traverse": "^7.21.0",
+        "@babel/types": "^7.21.0"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -565,9 +551,9 @@
       }
     },
     "node_modules/@babel/parser": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz",
-      "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz",
+      "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==",
       "dev": true,
       "peer": true,
       "bin": {
@@ -648,13 +634,13 @@
       }
     },
     "node_modules/@babel/plugin-proposal-class-static-block": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.20.7.tgz",
-      "integrity": "sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.21.0.tgz",
+      "integrity": "sha512-XP5G9MWNUskFuP30IfFSEFB0Z6HzLIUcjYM4bYOPHXl7eiJ9HFv8tWj6TXTN5QODiEhDZAeI4hLok2iHFFV4hw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/helper-create-class-features-plugin": "^7.20.7",
+        "@babel/helper-create-class-features-plugin": "^7.21.0",
         "@babel/helper-plugin-utils": "^7.20.2",
         "@babel/plugin-syntax-class-static-block": "^7.14.5"
       },
@@ -666,17 +652,17 @@
       }
     },
     "node_modules/@babel/plugin-proposal-decorators": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.20.7.tgz",
-      "integrity": "sha512-JB45hbUweYpwAGjkiM7uCyXMENH2lG+9r3G2E+ttc2PRXAoEkpfd/KW5jDg4j8RS6tLtTG1jZi9LbHZVSfs1/A==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.21.0.tgz",
+      "integrity": "sha512-MfgX49uRrFUTL/HvWtmx3zmpyzMMr4MTj3d527MLlr/4RTT9G/ytFFP7qet2uM2Ve03b+BkpWUpK+lRXnQ+v9w==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/helper-create-class-features-plugin": "^7.20.7",
+        "@babel/helper-create-class-features-plugin": "^7.21.0",
         "@babel/helper-plugin-utils": "^7.20.2",
         "@babel/helper-replace-supers": "^7.20.7",
         "@babel/helper-split-export-declaration": "^7.18.6",
-        "@babel/plugin-syntax-decorators": "^7.19.0"
+        "@babel/plugin-syntax-decorators": "^7.21.0"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -824,9 +810,9 @@
       }
     },
     "node_modules/@babel/plugin-proposal-optional-chaining": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz",
-      "integrity": "sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz",
+      "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -859,14 +845,14 @@
       }
     },
     "node_modules/@babel/plugin-proposal-private-property-in-object": {
-      "version": "7.20.5",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz",
-      "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0.tgz",
+      "integrity": "sha512-ha4zfehbJjc5MmXBlHec1igel5TJXXLDDRbuJ4+XT2TJcyD9/V1919BA8gMvsdHcNMBy4WBUBiRb3nw/EQUtBw==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "@babel/helper-annotate-as-pure": "^7.18.6",
-        "@babel/helper-create-class-features-plugin": "^7.20.5",
+        "@babel/helper-create-class-features-plugin": "^7.21.0",
         "@babel/helper-plugin-utils": "^7.20.2",
         "@babel/plugin-syntax-private-property-in-object": "^7.14.5"
       },
@@ -950,13 +936,13 @@
       }
     },
     "node_modules/@babel/plugin-syntax-decorators": {
-      "version": "7.19.0",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.19.0.tgz",
-      "integrity": "sha512-xaBZUEDntt4faL1yN8oIFlhfXeQAWJW7CLKYsHTUqriCUbj8xOra8bfxxKGi/UwExPFBuPdH4XfHc9rGQhrVkQ==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.21.0.tgz",
+      "integrity": "sha512-tIoPpGBR8UuM4++ccWN3gifhVvQu7ZizuR1fklhRJrd5ewgbkUS+0KVFeWWxELtn18NTLoW32XV7zyOgIAiz+w==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/helper-plugin-utils": "^7.19.0"
+        "@babel/helper-plugin-utils": "^7.20.2"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -992,13 +978,13 @@
       }
     },
     "node_modules/@babel/plugin-syntax-flow": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz",
-      "integrity": "sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.21.4.tgz",
+      "integrity": "sha512-l9xd3N+XG4fZRxEP3vXdK6RW7vN1Uf5dxzRC/09wV86wqZ/YYQooBIGNsiRdfNR3/q2/5pPzV4B54J/9ctX5jw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/helper-plugin-utils": "^7.18.6"
+        "@babel/helper-plugin-utils": "^7.20.2"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -1050,13 +1036,13 @@
       }
     },
     "node_modules/@babel/plugin-syntax-jsx": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz",
-      "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz",
+      "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/helper-plugin-utils": "^7.18.6"
+        "@babel/helper-plugin-utils": "^7.20.2"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -1175,13 +1161,13 @@
       }
     },
     "node_modules/@babel/plugin-syntax-typescript": {
-      "version": "7.20.0",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz",
-      "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz",
+      "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/helper-plugin-utils": "^7.19.0"
+        "@babel/helper-plugin-utils": "^7.20.2"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -1241,9 +1227,9 @@
       }
     },
     "node_modules/@babel/plugin-transform-block-scoping": {
-      "version": "7.20.11",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.11.tgz",
-      "integrity": "sha512-tA4N427a7fjf1P0/2I4ScsHGc5jcHPbb30xMbaTke2gxDuWpUfXDuX1FEymJwKk4tuGUvGcejAR6HdZVqmmPyw==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.21.0.tgz",
+      "integrity": "sha512-Mdrbunoh9SxwFZapeHVrwFmri16+oYotcZysSzhNIVDwIAb1UV+kvnxULSYq9J3/q5MDG+4X6w8QVgD1zhBXNQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -1257,16 +1243,16 @@
       }
     },
     "node_modules/@babel/plugin-transform-classes": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.7.tgz",
-      "integrity": "sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.21.0.tgz",
+      "integrity": "sha512-RZhbYTCEUAe6ntPehC4hlslPWosNHDox+vAs4On/mCLRLfoDVHf6hVEd7kuxr1RnHwJmxFfUM3cZiZRmPxJPXQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "@babel/helper-annotate-as-pure": "^7.18.6",
         "@babel/helper-compilation-targets": "^7.20.7",
         "@babel/helper-environment-visitor": "^7.18.9",
-        "@babel/helper-function-name": "^7.19.0",
+        "@babel/helper-function-name": "^7.21.0",
         "@babel/helper-optimise-call-expression": "^7.18.6",
         "@babel/helper-plugin-utils": "^7.20.2",
         "@babel/helper-replace-supers": "^7.20.7",
@@ -1298,9 +1284,9 @@
       }
     },
     "node_modules/@babel/plugin-transform-destructuring": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz",
-      "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==",
+      "version": "7.21.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.21.3.tgz",
+      "integrity": "sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -1364,13 +1350,13 @@
       }
     },
     "node_modules/@babel/plugin-transform-flow-strip-types": {
-      "version": "7.19.0",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.19.0.tgz",
-      "integrity": "sha512-sgeMlNaQVbCSpgLSKP4ZZKfsJVnFnNQlUSk6gPYzR/q7tzCgQF2t8RBKAP6cKJeZdveei7Q7Jm527xepI8lNLg==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.21.0.tgz",
+      "integrity": "sha512-FlFA2Mj87a6sDkW4gfGrQQqwY/dLlBAyJa2dJEZ+FHXUVHBflO2wyKvg+OOEzXfrKYIa4HWl0mgmbCzt0cMb7w==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/helper-plugin-utils": "^7.19.0",
+        "@babel/helper-plugin-utils": "^7.20.2",
         "@babel/plugin-syntax-flow": "^7.18.6"
       },
       "engines": {
@@ -1381,13 +1367,13 @@
       }
     },
     "node_modules/@babel/plugin-transform-for-of": {
-      "version": "7.18.8",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz",
-      "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.21.0.tgz",
+      "integrity": "sha512-LlUYlydgDkKpIY7mcBWvyPPmMcOphEyYA27Ef4xpbh1IiDNLr0kZsos2nf92vz3IccvJI25QUwp86Eo5s6HmBQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/helper-plugin-utils": "^7.18.6"
+        "@babel/helper-plugin-utils": "^7.20.2"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -1464,13 +1450,13 @@
       }
     },
     "node_modules/@babel/plugin-transform-modules-commonjs": {
-      "version": "7.20.11",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz",
-      "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==",
+      "version": "7.21.2",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.2.tgz",
+      "integrity": "sha512-Cln+Yy04Gxua7iPdj6nOV96smLGjpElir5YwzF0LBPKoPlLDNJePNlrGGaybAJkd0zKRnOVXOgizSqPYMNYkzA==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/helper-module-transforms": "^7.20.11",
+        "@babel/helper-module-transforms": "^7.21.2",
         "@babel/helper-plugin-utils": "^7.20.2",
         "@babel/helper-simple-access": "^7.20.2"
       },
@@ -1568,9 +1554,9 @@
       }
     },
     "node_modules/@babel/plugin-transform-parameters": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz",
-      "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==",
+      "version": "7.21.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.21.3.tgz",
+      "integrity": "sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -1600,9 +1586,9 @@
       }
     },
     "node_modules/@babel/plugin-transform-react-constant-elements": {
-      "version": "7.20.2",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.20.2.tgz",
-      "integrity": "sha512-KS/G8YI8uwMGKErLFOHS/ekhqdHhpEloxs43NecQHVgo2QuQSyJhGIY1fL8UGl9wy5ItVwwoUL4YxVqsplGq2g==",
+      "version": "7.21.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.21.3.tgz",
+      "integrity": "sha512-4DVcFeWe/yDYBLp0kBmOGFJ6N2UYg7coGid1gdxb4co62dy/xISDMaYBXBVXEDhfgMk7qkbcYiGtwd5Q/hwDDQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -1632,9 +1618,9 @@
       }
     },
     "node_modules/@babel/plugin-transform-react-jsx": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.20.7.tgz",
-      "integrity": "sha512-Tfq7qqD+tRj3EoDhY00nn2uP2hsRxgYGi5mLQ5TimKav0a9Lrpd4deE+fcLXU8zFYRjlKPHZhpCvfEA6qnBxqQ==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.21.0.tgz",
+      "integrity": "sha512-6OAWljMvQrZjR2DaNhVfRz6dkCAVV+ymcLUmaf8bccGOHn2v5rHJK3tTpij0BuhdYWP4LLaqj5lwcdlpAAPuvg==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -1642,7 +1628,7 @@
         "@babel/helper-module-imports": "^7.18.6",
         "@babel/helper-plugin-utils": "^7.20.2",
         "@babel/plugin-syntax-jsx": "^7.18.6",
-        "@babel/types": "^7.20.7"
+        "@babel/types": "^7.21.0"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -1718,14 +1704,14 @@
       }
     },
     "node_modules/@babel/plugin-transform-runtime": {
-      "version": "7.19.6",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz",
-      "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.21.4.tgz",
+      "integrity": "sha512-1J4dhrw1h1PqnNNpzwxQ2UBymJUF8KuPjAAnlLwZcGhHAIqUigFW7cdK6GHoB64ubY4qXQNYknoUeks4Wz7CUA==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/helper-module-imports": "^7.18.6",
-        "@babel/helper-plugin-utils": "^7.19.0",
+        "@babel/helper-module-imports": "^7.21.4",
+        "@babel/helper-plugin-utils": "^7.20.2",
         "babel-plugin-polyfill-corejs2": "^0.3.3",
         "babel-plugin-polyfill-corejs3": "^0.6.0",
         "babel-plugin-polyfill-regenerator": "^0.4.1",
@@ -1820,13 +1806,14 @@
       }
     },
     "node_modules/@babel/plugin-transform-typescript": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.7.tgz",
-      "integrity": "sha512-m3wVKEvf6SoszD8pu4NZz3PvfKRCMgk6D6d0Qi9hNnlM5M6CFS92EgF4EiHVLKbU0r/r7ty1hg7NPZwE7WRbYw==",
+      "version": "7.21.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.3.tgz",
+      "integrity": "sha512-RQxPz6Iqt8T0uw/WsJNReuBpWpBqs/n7mNo18sKLoTbMp+UrEekhH+pKSVC7gWz+DNjo9gryfV8YzCiT45RgMw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/helper-create-class-features-plugin": "^7.20.7",
+        "@babel/helper-annotate-as-pure": "^7.18.6",
+        "@babel/helper-create-class-features-plugin": "^7.21.0",
         "@babel/helper-plugin-utils": "^7.20.2",
         "@babel/plugin-syntax-typescript": "^7.20.0"
       },
@@ -1871,32 +1858,32 @@
       }
     },
     "node_modules/@babel/preset-env": {
-      "version": "7.20.2",
-      "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz",
-      "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.21.4.tgz",
+      "integrity": "sha512-2W57zHs2yDLm6GD5ZpvNn71lZ0B/iypSdIeq25OurDKji6AdzV07qp4s3n1/x5BqtiGaTrPN3nerlSCaC5qNTw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/compat-data": "^7.20.1",
-        "@babel/helper-compilation-targets": "^7.20.0",
+        "@babel/compat-data": "^7.21.4",
+        "@babel/helper-compilation-targets": "^7.21.4",
         "@babel/helper-plugin-utils": "^7.20.2",
-        "@babel/helper-validator-option": "^7.18.6",
+        "@babel/helper-validator-option": "^7.21.0",
         "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6",
-        "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9",
-        "@babel/plugin-proposal-async-generator-functions": "^7.20.1",
+        "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.20.7",
+        "@babel/plugin-proposal-async-generator-functions": "^7.20.7",
         "@babel/plugin-proposal-class-properties": "^7.18.6",
-        "@babel/plugin-proposal-class-static-block": "^7.18.6",
+        "@babel/plugin-proposal-class-static-block": "^7.21.0",
         "@babel/plugin-proposal-dynamic-import": "^7.18.6",
         "@babel/plugin-proposal-export-namespace-from": "^7.18.9",
         "@babel/plugin-proposal-json-strings": "^7.18.6",
-        "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9",
+        "@babel/plugin-proposal-logical-assignment-operators": "^7.20.7",
         "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
         "@babel/plugin-proposal-numeric-separator": "^7.18.6",
-        "@babel/plugin-proposal-object-rest-spread": "^7.20.2",
+        "@babel/plugin-proposal-object-rest-spread": "^7.20.7",
         "@babel/plugin-proposal-optional-catch-binding": "^7.18.6",
-        "@babel/plugin-proposal-optional-chaining": "^7.18.9",
+        "@babel/plugin-proposal-optional-chaining": "^7.21.0",
         "@babel/plugin-proposal-private-methods": "^7.18.6",
-        "@babel/plugin-proposal-private-property-in-object": "^7.18.6",
+        "@babel/plugin-proposal-private-property-in-object": "^7.21.0",
         "@babel/plugin-proposal-unicode-property-regex": "^7.18.6",
         "@babel/plugin-syntax-async-generators": "^7.8.4",
         "@babel/plugin-syntax-class-properties": "^7.12.13",
@@ -1913,40 +1900,40 @@
         "@babel/plugin-syntax-optional-chaining": "^7.8.3",
         "@babel/plugin-syntax-private-property-in-object": "^7.14.5",
         "@babel/plugin-syntax-top-level-await": "^7.14.5",
-        "@babel/plugin-transform-arrow-functions": "^7.18.6",
-        "@babel/plugin-transform-async-to-generator": "^7.18.6",
+        "@babel/plugin-transform-arrow-functions": "^7.20.7",
+        "@babel/plugin-transform-async-to-generator": "^7.20.7",
         "@babel/plugin-transform-block-scoped-functions": "^7.18.6",
-        "@babel/plugin-transform-block-scoping": "^7.20.2",
-        "@babel/plugin-transform-classes": "^7.20.2",
-        "@babel/plugin-transform-computed-properties": "^7.18.9",
-        "@babel/plugin-transform-destructuring": "^7.20.2",
+        "@babel/plugin-transform-block-scoping": "^7.21.0",
+        "@babel/plugin-transform-classes": "^7.21.0",
+        "@babel/plugin-transform-computed-properties": "^7.20.7",
+        "@babel/plugin-transform-destructuring": "^7.21.3",
         "@babel/plugin-transform-dotall-regex": "^7.18.6",
         "@babel/plugin-transform-duplicate-keys": "^7.18.9",
         "@babel/plugin-transform-exponentiation-operator": "^7.18.6",
-        "@babel/plugin-transform-for-of": "^7.18.8",
+        "@babel/plugin-transform-for-of": "^7.21.0",
         "@babel/plugin-transform-function-name": "^7.18.9",
         "@babel/plugin-transform-literals": "^7.18.9",
         "@babel/plugin-transform-member-expression-literals": "^7.18.6",
-        "@babel/plugin-transform-modules-amd": "^7.19.6",
-        "@babel/plugin-transform-modules-commonjs": "^7.19.6",
-        "@babel/plugin-transform-modules-systemjs": "^7.19.6",
+        "@babel/plugin-transform-modules-amd": "^7.20.11",
+        "@babel/plugin-transform-modules-commonjs": "^7.21.2",
+        "@babel/plugin-transform-modules-systemjs": "^7.20.11",
         "@babel/plugin-transform-modules-umd": "^7.18.6",
-        "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1",
+        "@babel/plugin-transform-named-capturing-groups-regex": "^7.20.5",
         "@babel/plugin-transform-new-target": "^7.18.6",
         "@babel/plugin-transform-object-super": "^7.18.6",
-        "@babel/plugin-transform-parameters": "^7.20.1",
+        "@babel/plugin-transform-parameters": "^7.21.3",
         "@babel/plugin-transform-property-literals": "^7.18.6",
-        "@babel/plugin-transform-regenerator": "^7.18.6",
+        "@babel/plugin-transform-regenerator": "^7.20.5",
         "@babel/plugin-transform-reserved-words": "^7.18.6",
         "@babel/plugin-transform-shorthand-properties": "^7.18.6",
-        "@babel/plugin-transform-spread": "^7.19.0",
+        "@babel/plugin-transform-spread": "^7.20.7",
         "@babel/plugin-transform-sticky-regex": "^7.18.6",
         "@babel/plugin-transform-template-literals": "^7.18.9",
         "@babel/plugin-transform-typeof-symbol": "^7.18.9",
         "@babel/plugin-transform-unicode-escapes": "^7.18.10",
         "@babel/plugin-transform-unicode-regex": "^7.18.6",
         "@babel/preset-modules": "^0.1.5",
-        "@babel/types": "^7.20.2",
+        "@babel/types": "^7.21.4",
         "babel-plugin-polyfill-corejs2": "^0.3.3",
         "babel-plugin-polyfill-corejs3": "^0.6.0",
         "babel-plugin-polyfill-regenerator": "^0.4.1",
@@ -1999,15 +1986,17 @@
       }
     },
     "node_modules/@babel/preset-typescript": {
-      "version": "7.18.6",
-      "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz",
-      "integrity": "sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.21.4.tgz",
+      "integrity": "sha512-sMLNWY37TCdRH/bJ6ZeeOH1nPuanED7Ai9Y/vH31IPqalioJ6ZNFUWONsakhv4r4n+I6gm5lmoE0olkgib/j/A==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/helper-plugin-utils": "^7.18.6",
-        "@babel/helper-validator-option": "^7.18.6",
-        "@babel/plugin-transform-typescript": "^7.18.6"
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-validator-option": "^7.21.0",
+        "@babel/plugin-syntax-jsx": "^7.21.4",
+        "@babel/plugin-transform-modules-commonjs": "^7.21.2",
+        "@babel/plugin-transform-typescript": "^7.21.3"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -2016,10 +2005,17 @@
         "@babel/core": "^7.0.0-0"
       }
     },
+    "node_modules/@babel/regjsgen": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz",
+      "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==",
+      "dev": true,
+      "peer": true
+    },
     "node_modules/@babel/runtime": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz",
-      "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz",
+      "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==",
       "dependencies": {
         "regenerator-runtime": "^0.13.11"
       },
@@ -2043,20 +2039,20 @@
       }
     },
     "node_modules/@babel/traverse": {
-      "version": "7.20.12",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz",
-      "integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz",
+      "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@babel/code-frame": "^7.18.6",
-        "@babel/generator": "^7.20.7",
+        "@babel/code-frame": "^7.21.4",
+        "@babel/generator": "^7.21.4",
         "@babel/helper-environment-visitor": "^7.18.9",
-        "@babel/helper-function-name": "^7.19.0",
+        "@babel/helper-function-name": "^7.21.0",
         "@babel/helper-hoist-variables": "^7.18.6",
         "@babel/helper-split-export-declaration": "^7.18.6",
-        "@babel/parser": "^7.20.7",
-        "@babel/types": "^7.20.7",
+        "@babel/parser": "^7.21.4",
+        "@babel/types": "^7.21.4",
         "debug": "^4.1.0",
         "globals": "^11.1.0"
       },
@@ -2065,9 +2061,9 @@
       }
     },
     "node_modules/@babel/types": {
-      "version": "7.20.7",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz",
-      "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==",
+      "version": "7.21.4",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz",
+      "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -2372,33 +2368,56 @@
       }
     },
     "node_modules/@csstools/selector-specificity": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz",
-      "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==",
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz",
+      "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==",
       "dev": true,
       "peer": true,
       "engines": {
-        "node": "^12 || ^14 || >=16"
+        "node": "^14 || ^16 || >=18"
       },
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/csstools"
       },
       "peerDependencies": {
-        "postcss": "^8.2",
         "postcss-selector-parser": "^6.0.10"
       }
     },
+    "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==",
+      "dev": true,
+      "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.0",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz",
+      "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==",
+      "dev": true,
+      "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.0.2",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz",
+      "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "ajv": "^6.12.4",
         "debug": "^4.3.2",
-        "espree": "^9.4.0",
+        "espree": "^9.5.1",
         "globals": "^13.19.0",
         "ignore": "^5.2.0",
         "import-fresh": "^3.2.1",
@@ -2414,9 +2433,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==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -2442,6 +2461,16 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/@eslint/js": {
+      "version": "8.38.0",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.38.0.tgz",
+      "integrity": "sha512-IoD2MfUnOV58ghIHCiil01PcohxjbYR/qCxsoC+xNgUwh1EY8jOOrYmu3d3a71+tJJ23uscEV4X2HJWMsPJu4g==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
     "node_modules/@humanwhocodes/config-array": {
       "version": "0.11.8",
       "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
@@ -3280,14 +3309,15 @@
       }
     },
     "node_modules/@jridgewell/gen-mapping": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
-      "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
+      "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@jridgewell/set-array": "^1.0.0",
-        "@jridgewell/sourcemap-codec": "^1.4.10"
+        "@jridgewell/set-array": "^1.0.1",
+        "@jridgewell/sourcemap-codec": "^1.4.10",
+        "@jridgewell/trace-mapping": "^0.3.9"
       },
       "engines": {
         "node": ">=6.0.0"
@@ -3314,9 +3344,9 @@
       }
     },
     "node_modules/@jridgewell/source-map": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
-      "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz",
+      "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -3324,32 +3354,17 @@
         "@jridgewell/trace-mapping": "^0.3.9"
       }
     },
-    "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
-      "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
-      "dev": true,
-      "peer": true,
-      "dependencies": {
-        "@jridgewell/set-array": "^1.0.1",
-        "@jridgewell/sourcemap-codec": "^1.4.10",
-        "@jridgewell/trace-mapping": "^0.3.9"
-      },
-      "engines": {
-        "node": ">=6.0.0"
-      }
-    },
     "node_modules/@jridgewell/sourcemap-codec": {
-      "version": "1.4.14",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
-      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+      "version": "1.4.15",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
+      "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
       "dev": true,
       "peer": true
     },
     "node_modules/@jridgewell/trace-mapping": {
-      "version": "0.3.17",
-      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
-      "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
+      "version": "0.3.18",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz",
+      "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -3357,6 +3372,13 @@
         "@jridgewell/sourcemap-codec": "1.4.14"
       }
     },
+    "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.4.14",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==",
+      "dev": true,
+      "peer": true
+    },
     "node_modules/@leichtgewicht/ip-codec": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
@@ -3461,9 +3483,9 @@
       }
     },
     "node_modules/@remix-run/router": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.3.0.tgz",
-      "integrity": "sha512-nwQoYb3m4DDpHTeOwpJEuDt8lWVcujhYYSFGLluC+9es2PyLjm+jjq3IeRBQbwBtPLJE/lkuHuGHr8uQLgmJRA==",
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.5.0.tgz",
+      "integrity": "sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==",
       "engines": {
         "node": ">=14"
       }
@@ -3514,13 +3536,13 @@
       }
     },
     "node_modules/@rollup/plugin-node-resolve/node_modules/resolve": {
-      "version": "1.22.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
-      "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+      "version": "1.22.3",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz",
+      "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "is-core-module": "^2.9.0",
+        "is-core-module": "^2.12.0",
         "path-parse": "^1.0.7",
         "supports-preserve-symlinks-flag": "^1.0.0"
       },
@@ -3853,9 +3875,10 @@
       }
     },
     "node_modules/@testing-library/dom": {
-      "version": "8.20.0",
-      "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.0.tgz",
-      "integrity": "sha512-d9ULIT+a4EXLX3UU8FBjauG9NnsZHkHztXoIcTsOKoOw030fyjheN9svkTULjJxtYag9DZz5Jz5qkWZDPxTFwA==",
+      "version": "9.2.0",
+      "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.2.0.tgz",
+      "integrity": "sha512-xTEnpUKiV/bMyEsE5bT4oYA0x0Z/colMtxzUY8bKyPXBNLn/e0V4ZjBZkEhms0xE4pv9QsPfSRu9AWS4y5wGvA==",
+      "peer": true,
       "dependencies": {
         "@babel/code-frame": "^7.10.4",
         "@babel/runtime": "^7.12.5",
@@ -3863,17 +3886,18 @@
         "aria-query": "^5.0.0",
         "chalk": "^4.1.0",
         "dom-accessibility-api": "^0.5.9",
-        "lz-string": "^1.4.4",
+        "lz-string": "^1.5.0",
         "pretty-format": "^27.0.2"
       },
       "engines": {
-        "node": ">=12"
+        "node": ">=14"
       }
     },
     "node_modules/@testing-library/dom/node_modules/ansi-styles": {
       "version": "4.3.0",
       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
       "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "peer": true,
       "dependencies": {
         "color-convert": "^2.0.1"
       },
@@ -3888,6 +3912,7 @@
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
       "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "peer": true,
       "dependencies": {
         "ansi-styles": "^4.1.0",
         "supports-color": "^7.1.0"
@@ -3903,6 +3928,7 @@
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
       "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "peer": true,
       "dependencies": {
         "color-name": "~1.1.4"
       },
@@ -3913,12 +3939,14 @@
     "node_modules/@testing-library/dom/node_modules/color-name": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "peer": true
     },
     "node_modules/@testing-library/dom/node_modules/has-flag": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
       "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "peer": true,
       "engines": {
         "node": ">=8"
       }
@@ -3927,6 +3955,7 @@
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
       "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "peer": true,
       "dependencies": {
         "has-flag": "^4.0.0"
       },
@@ -4033,6 +4062,88 @@
         "react-dom": "^18.0.0"
       }
     },
+    "node_modules/@testing-library/react/node_modules/@testing-library/dom": {
+      "version": "8.20.0",
+      "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.0.tgz",
+      "integrity": "sha512-d9ULIT+a4EXLX3UU8FBjauG9NnsZHkHztXoIcTsOKoOw030fyjheN9svkTULjJxtYag9DZz5Jz5qkWZDPxTFwA==",
+      "dependencies": {
+        "@babel/code-frame": "^7.10.4",
+        "@babel/runtime": "^7.12.5",
+        "@types/aria-query": "^5.0.1",
+        "aria-query": "^5.0.0",
+        "chalk": "^4.1.0",
+        "dom-accessibility-api": "^0.5.9",
+        "lz-string": "^1.4.4",
+        "pretty-format": "^27.0.2"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@testing-library/react/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/@testing-library/react/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/@testing-library/react/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/@testing-library/react/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    },
+    "node_modules/@testing-library/react/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@testing-library/react/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/@testing-library/user-event": {
       "version": "14.4.3",
       "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.4.3.tgz",
@@ -4158,9 +4269,9 @@
       }
     },
     "node_modules/@types/eslint": {
-      "version": "8.4.10",
-      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz",
-      "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==",
+      "version": "8.37.0",
+      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz",
+      "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -4187,22 +4298,22 @@
       "peer": true
     },
     "node_modules/@types/express": {
-      "version": "4.17.15",
-      "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.15.tgz",
-      "integrity": "sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==",
+      "version": "4.17.17",
+      "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
+      "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "@types/body-parser": "*",
-        "@types/express-serve-static-core": "^4.17.31",
+        "@types/express-serve-static-core": "^4.17.33",
         "@types/qs": "*",
         "@types/serve-static": "*"
       }
     },
     "node_modules/@types/express-serve-static-core": {
-      "version": "4.17.32",
-      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.32.tgz",
-      "integrity": "sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==",
+      "version": "4.17.33",
+      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz",
+      "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -4234,9 +4345,9 @@
       "peer": true
     },
     "node_modules/@types/http-proxy": {
-      "version": "1.17.9",
-      "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz",
-      "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==",
+      "version": "1.17.10",
+      "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.10.tgz",
+      "integrity": "sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -4293,9 +4404,9 @@
       "peer": true
     },
     "node_modules/@types/lodash": {
-      "version": "4.14.191",
-      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
-      "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ=="
+      "version": "4.14.194",
+      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.194.tgz",
+      "integrity": "sha512-r22s9tAS7imvBt2lyHC9B8AGwWnXaYb1tY09oyLkXDs4vArpYJzw09nj8MLx5VfciBPGIb+ZwG0ssYnEPJxn/g=="
     },
     "node_modules/@types/lodash.debounce": {
       "version": "4.0.7",
@@ -4377,9 +4488,9 @@
       "peer": true
     },
     "node_modules/@types/react": {
-      "version": "18.0.27",
-      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.27.tgz",
-      "integrity": "sha512-3vtRKHgVxu3Jp9t718R9BuzoD4NcQ8YJ5XRzsSKxNDiDonD2MXIT1TmSkenxuCycZJoQT5d2vE8LwWJxBC1gmA==",
+      "version": "18.0.35",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.35.tgz",
+      "integrity": "sha512-6Laome31HpetaIUGFWl1VQ3mdSImwxtFZ39rh059a1MNnKGqBpC88J6NJ8n/Is3Qx7CefDGLgf/KhN/sYCf7ag==",
       "dependencies": {
         "@types/prop-types": "*",
         "@types/scheduler": "*",
@@ -4387,9 +4498,9 @@
       }
     },
     "node_modules/@types/react-dom": {
-      "version": "18.0.10",
-      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.10.tgz",
-      "integrity": "sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==",
+      "version": "18.0.11",
+      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.11.tgz",
+      "integrity": "sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==",
       "dependencies": {
         "@types/react": "*"
       }
@@ -4439,9 +4550,9 @@
       "peer": true
     },
     "node_modules/@types/scheduler": {
-      "version": "0.16.2",
-      "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
-      "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
+      "version": "0.16.3",
+      "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
+      "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ=="
     },
     "node_modules/@types/semver": {
       "version": "7.3.13",
@@ -4460,9 +4571,9 @@
       }
     },
     "node_modules/@types/serve-static": {
-      "version": "1.15.0",
-      "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz",
-      "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==",
+      "version": "1.15.1",
+      "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz",
+      "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -4496,9 +4607,9 @@
       }
     },
     "node_modules/@types/trusted-types": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz",
-      "integrity": "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg==",
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz",
+      "integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==",
       "dev": true,
       "peer": true
     },
@@ -4535,18 +4646,19 @@
       "peer": true
     },
     "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==",
+      "version": "5.58.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.58.0.tgz",
+      "integrity": "sha512-vxHvLhH0qgBd3/tW6/VccptSfc8FxPQIkmNTVLWcCOVqSBvqpnKkBTYrhcGlXfSnd78azwe+PsjYFj0X34/njA==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "5.48.2",
-        "@typescript-eslint/type-utils": "5.48.2",
-        "@typescript-eslint/utils": "5.48.2",
+        "@eslint-community/regexpp": "^4.4.0",
+        "@typescript-eslint/scope-manager": "5.58.0",
+        "@typescript-eslint/type-utils": "5.58.0",
+        "@typescript-eslint/utils": "5.58.0",
         "debug": "^4.3.4",
+        "grapheme-splitter": "^1.0.4",
         "ignore": "^5.2.0",
         "natural-compare-lite": "^1.4.0",
-        "regexpp": "^3.2.0",
         "semver": "^7.3.7",
         "tsutils": "^3.21.0"
       },
@@ -4580,9 +4692,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.4.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz",
+      "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==",
       "dev": true,
       "dependencies": {
         "lru-cache": "^6.0.0"
@@ -4601,13 +4713,13 @@
       "dev": true
     },
     "node_modules/@typescript-eslint/experimental-utils": {
-      "version": "5.48.2",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.48.2.tgz",
-      "integrity": "sha512-Iwx8De8dwl6qPaPZWIaEfP1feN/YFlA5FlCxF3zUIm+2AG92C5Tefkugj2L9ytOFrmTYkTE/CqvJFZbYoVZQMg==",
+      "version": "5.58.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.58.0.tgz",
+      "integrity": "sha512-LA/sRPaynZlrlYxdefrZbMx8dqs/1Kc0yNG+XOk5CwwZx7tTv263ix3AJNioF0YBVt7hADpAUR20owl6pv4MIQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@typescript-eslint/utils": "5.48.2"
+        "@typescript-eslint/utils": "5.58.0"
       },
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -4621,14 +4733,14 @@
       }
     },
     "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.58.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.58.0.tgz",
+      "integrity": "sha512-ixaM3gRtlfrKzP8N6lRhBbjTow1t6ztfBvQNGuRM8qH1bjFFXIJ35XY+FC0RRBKn3C6cT+7VW1y8tNm7DwPHDQ==",
       "dev": true,
       "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.58.0",
+        "@typescript-eslint/types": "5.58.0",
+        "@typescript-eslint/typescript-estree": "5.58.0",
         "debug": "^4.3.4"
       },
       "engines": {
@@ -4648,13 +4760,13 @@
       }
     },
     "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.58.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.58.0.tgz",
+      "integrity": "sha512-b+w8ypN5CFvrXWQb9Ow9T4/6LC2MikNf1viLkYTiTbkQl46CnR69w7lajz1icW0TBsYmlpg+mRzFJ4LEJ8X9NA==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "5.48.2",
-        "@typescript-eslint/visitor-keys": "5.48.2"
+        "@typescript-eslint/types": "5.58.0",
+        "@typescript-eslint/visitor-keys": "5.58.0"
       },
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -4665,13 +4777,13 @@
       }
     },
     "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.58.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.58.0.tgz",
+      "integrity": "sha512-FF5vP/SKAFJ+LmR9PENql7fQVVgGDOS+dq3j+cKl9iW/9VuZC/8CFmzIP0DLKXfWKpRHawJiG70rVH+xZZbp8w==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/typescript-estree": "5.48.2",
-        "@typescript-eslint/utils": "5.48.2",
+        "@typescript-eslint/typescript-estree": "5.58.0",
+        "@typescript-eslint/utils": "5.58.0",
         "debug": "^4.3.4",
         "tsutils": "^3.21.0"
       },
@@ -4692,9 +4804,9 @@
       }
     },
     "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.58.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.58.0.tgz",
+      "integrity": "sha512-JYV4eITHPzVQMnHZcYJXl2ZloC7thuUHrcUmxtzvItyKPvQ50kb9QXBkgNAt90OYMqwaodQh2kHutWZl1fc+1g==",
       "dev": true,
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -4705,13 +4817,13 @@
       }
     },
     "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.58.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.58.0.tgz",
+      "integrity": "sha512-cRACvGTodA+UxnYM2uwA2KCwRL7VAzo45syNysqlMyNyjw0Z35Icc9ihPJZjIYuA5bXJYiJ2YGUB59BqlOZT1Q==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "5.48.2",
-        "@typescript-eslint/visitor-keys": "5.48.2",
+        "@typescript-eslint/types": "5.58.0",
+        "@typescript-eslint/visitor-keys": "5.58.0",
         "debug": "^4.3.4",
         "globby": "^11.1.0",
         "is-glob": "^4.0.3",
@@ -4744,9 +4856,9 @@
       }
     },
     "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
-      "version": "7.3.8",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
-      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "version": "7.4.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz",
+      "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==",
       "dev": true,
       "dependencies": {
         "lru-cache": "^6.0.0"
@@ -4765,18 +4877,18 @@
       "dev": true
     },
     "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.58.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.58.0.tgz",
+      "integrity": "sha512-gAmLOTFXMXOC+zP1fsqm3VceKSBQJNzV385Ok3+yzlavNHZoedajjS4UyS21gabJYcobuigQPs/z71A9MdJFqQ==",
       "dev": true,
       "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.58.0",
+        "@typescript-eslint/types": "5.58.0",
+        "@typescript-eslint/typescript-estree": "5.58.0",
         "eslint-scope": "^5.1.1",
-        "eslint-utils": "^3.0.0",
         "semver": "^7.3.7"
       },
       "engines": {
@@ -4803,9 +4915,9 @@
       }
     },
     "node_modules/@typescript-eslint/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.4.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz",
+      "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==",
       "dev": true,
       "dependencies": {
         "lru-cache": "^6.0.0"
@@ -4824,12 +4936,12 @@
       "dev": true
     },
     "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.58.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.58.0.tgz",
+      "integrity": "sha512-/fBraTlPj0jwdyTwLyrRTxv/3lnU2H96pNTVM6z3esTWLtA5MZ9ghSMJ7Rb+TtUAdtEw9EyJzJ0EydIMKxQ9gA==",
       "dev": true,
       "dependencies": {
-        "@typescript-eslint/types": "5.48.2",
+        "@typescript-eslint/types": "5.58.0",
         "eslint-visitor-keys": "^3.3.0"
       },
       "engines": {
@@ -5037,9 +5149,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.8.2",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
+      "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
       "dev": true,
       "peer": true,
       "bin": {
@@ -5093,31 +5205,6 @@
         "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
       }
     },
-    "node_modules/acorn-node": {
-      "version": "1.8.2",
-      "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz",
-      "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
-      "dev": true,
-      "peer": true,
-      "dependencies": {
-        "acorn": "^7.0.0",
-        "acorn-walk": "^7.0.0",
-        "xtend": "^4.0.2"
-      }
-    },
-    "node_modules/acorn-node/node_modules/acorn": {
-      "version": "7.4.1",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
-      "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
-      "dev": true,
-      "peer": true,
-      "bin": {
-        "acorn": "bin/acorn"
-      },
-      "engines": {
-        "node": ">=0.4.0"
-      }
-    },
     "node_modules/acorn-walk": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
@@ -5282,6 +5369,13 @@
         "node": ">=4"
       }
     },
+    "node_modules/any-promise": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+      "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
+      "dev": true,
+      "peer": true
+    },
     "node_modules/anymatch": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
@@ -5316,6 +5410,19 @@
         "deep-equal": "^2.0.5"
       }
     },
+    "node_modules/array-buffer-byte-length": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz",
+      "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "is-array-buffer": "^3.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/array-flatten": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
@@ -5460,9 +5567,9 @@
       }
     },
     "node_modules/autoprefixer": {
-      "version": "10.4.13",
-      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz",
-      "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==",
+      "version": "10.4.14",
+      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz",
+      "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==",
       "dev": true,
       "funding": [
         {
@@ -5476,8 +5583,8 @@
       ],
       "peer": true,
       "dependencies": {
-        "browserslist": "^4.21.4",
-        "caniuse-lite": "^1.0.30001426",
+        "browserslist": "^4.21.5",
+        "caniuse-lite": "^1.0.30001464",
         "fraction.js": "^4.2.0",
         "normalize-range": "^0.1.2",
         "picocolors": "^1.0.0",
@@ -5505,9 +5612,9 @@
       }
     },
     "node_modules/axe-core": {
-      "version": "4.6.2",
-      "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.6.2.tgz",
-      "integrity": "sha512-b1WlTV8+XKLj9gZy2DZXgQiyDp9xkkoe2a6U6UbYccScq2wgH/YwCeI2/Jq2mgo0HzQxqJOjWZBLeA/mqsk5Mg==",
+      "version": "4.6.3",
+      "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.6.3.tgz",
+      "integrity": "sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg==",
       "dev": true,
       "peer": true,
       "engines": {
@@ -5712,13 +5819,13 @@
       }
     },
     "node_modules/babel-plugin-macros/node_modules/resolve": {
-      "version": "1.22.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
-      "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+      "version": "1.22.3",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz",
+      "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "is-core-module": "^2.9.0",
+        "is-core-module": "^2.12.0",
         "path-parse": "^1.0.7",
         "supports-preserve-symlinks-flag": "^1.0.0"
       },
@@ -5973,10 +6080,26 @@
       "dev": true,
       "peer": true
     },
+    "node_modules/body-parser/node_modules/qs": {
+      "version": "6.11.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+      "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "side-channel": "^1.0.4"
+      },
+      "engines": {
+        "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/bonjour-service": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.0.tgz",
-      "integrity": "sha512-LVRinRB3k1/K0XzZ2p58COnWvkQknIY6sf0zF2rpErvcJXpMBttEPQSxK+HEXSS9VmpZlDoDnQWv8ftJT20B0Q==",
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.1.tgz",
+      "integrity": "sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -6022,9 +6145,9 @@
       "peer": true
     },
     "node_modules/browserslist": {
-      "version": "4.21.4",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz",
-      "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==",
+      "version": "4.21.5",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
+      "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==",
       "dev": true,
       "funding": [
         {
@@ -6038,10 +6161,10 @@
       ],
       "peer": true,
       "dependencies": {
-        "caniuse-lite": "^1.0.30001400",
-        "electron-to-chromium": "^1.4.251",
-        "node-releases": "^2.0.6",
-        "update-browserslist-db": "^1.0.9"
+        "caniuse-lite": "^1.0.30001449",
+        "electron-to-chromium": "^1.4.284",
+        "node-releases": "^2.0.8",
+        "update-browserslist-db": "^1.0.10"
       },
       "bin": {
         "browserslist": "cli.js"
@@ -6160,9 +6283,9 @@
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001446",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001446.tgz",
-      "integrity": "sha512-fEoga4PrImGcwUUGEol/PoFCSBnSkA9drgdkxXkJLsUBOnJ8rs3zDv6ApqYXGQFOyMPsjh79naWhF4DAxbF8rw==",
+      "version": "1.0.30001480",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001480.tgz",
+      "integrity": "sha512-q7cpoPPvZYgtyC4VaBSN0Bt+PJ4c4EYRf0DrduInOz2SkFpHD5p3LnvEpqBp7UnJn+8x1Ogl1s38saUxe+ihQQ==",
       "dev": true,
       "funding": [
         {
@@ -6172,6 +6295,10 @@
         {
           "type": "tidelift",
           "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
         }
       ],
       "peer": true
@@ -6264,9 +6391,9 @@
       }
     },
     "node_modules/ci-info": {
-      "version": "3.7.1",
-      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.1.tgz",
-      "integrity": "sha512-4jYS4MOAaCIStSRwiuxc4B8MYhIe676yO1sYGzARnjXkWpmzZMMYxY6zu8WYWDhSuth5zhrQ1rhNSibyyvv4/w==",
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz",
+      "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==",
       "dev": true,
       "funding": [
         {
@@ -6292,9 +6419,9 @@
       "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
     },
     "node_modules/clean-css": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.1.tgz",
-      "integrity": "sha512-lCr8OHhiWCTw4v8POJovCoh4T7I9U11yVsPjMWWnnMmp9ZowCxyad1Pathle/9HjaDp+fdQKjO9fQydE6RHTZg==",
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz",
+      "integrity": "sha512-JVJbM+f3d3Q704rF4bqQ5UUyTtuJ0JRKNbTKVEeujCCBoMdkEi+V+e8oktO9qGQNSvHrFTM6JZRXrUvGR1czww==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -6380,9 +6507,9 @@
       "peer": true
     },
     "node_modules/colorette": {
-      "version": "2.0.19",
-      "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
-      "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
+      "version": "2.0.20",
+      "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
+      "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
       "dev": true,
       "peer": true
     },
@@ -6526,9 +6653,9 @@
       }
     },
     "node_modules/content-type": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
-      "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+      "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
       "dev": true,
       "peer": true,
       "engines": {
@@ -6560,9 +6687,9 @@
       "peer": true
     },
     "node_modules/core-js": {
-      "version": "3.27.2",
-      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.27.2.tgz",
-      "integrity": "sha512-9ashVQskuh5AZEZ1JdQWp1GqSoC1e1G87MzRqg2gIfVAQ7Qn9K+uFj8EcniUFA4P2NLZfV+TOlX1SzoKfo+s7w==",
+      "version": "3.30.1",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.30.1.tgz",
+      "integrity": "sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ==",
       "dev": true,
       "hasInstallScript": true,
       "peer": true,
@@ -6572,13 +6699,13 @@
       }
     },
     "node_modules/core-js-compat": {
-      "version": "3.27.2",
-      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.2.tgz",
-      "integrity": "sha512-welaYuF7ZtbYKGrIy7y3eb40d37rG1FvzEOfe7hSLd2iD6duMDqUhRfSvCGyC46HhR6Y8JXXdZ2lnRUMkPBpvg==",
+      "version": "3.30.1",
+      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.30.1.tgz",
+      "integrity": "sha512-d690npR7MC6P0gq4npTl5n2VQeNAmUrJ90n+MHiKS7W2+xno4o3F5GDEuylSdi6EJ3VssibSGXOa1r3YXD3Mhw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "browserslist": "^4.21.4"
+        "browserslist": "^4.21.5"
       },
       "funding": {
         "type": "opencollective",
@@ -6586,9 +6713,9 @@
       }
     },
     "node_modules/core-js-pure": {
-      "version": "3.27.2",
-      "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.27.2.tgz",
-      "integrity": "sha512-Cf2jqAbXgWH3VVzjyaaFkY1EBazxugUepGymDoeteyYr9ByX51kD2jdHZlsEF/xnJMyN3Prua7mQuzwMg6Zc9A==",
+      "version": "3.30.1",
+      "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.30.1.tgz",
+      "integrity": "sha512-nXBEVpmUnNRhz83cHd9JRQC52cTMcuXAmR56+9dSMpRdpeA4I1PX6yjmhd71Eyc/wXNsdBdUDIj1QTIeZpU5Tg==",
       "dev": true,
       "hasInstallScript": true,
       "peer": true,
@@ -6666,9 +6793,9 @@
       }
     },
     "node_modules/css-declaration-sorter": {
-      "version": "6.3.1",
-      "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.3.1.tgz",
-      "integrity": "sha512-fBffmak0bPAnyqc/HO8C3n2sHrp9wcqQz6ES9koRF2/mLOVAx9zIQ3Y7R29sYCteTPqMCwns4WYQoCX91Xl3+w==",
+      "version": "6.4.0",
+      "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz",
+      "integrity": "sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==",
       "dev": true,
       "peer": true,
       "engines": {
@@ -6738,9 +6865,9 @@
       }
     },
     "node_modules/css-loader/node_modules/semver": {
-      "version": "7.3.8",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
-      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "version": "7.4.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz",
+      "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -6837,16 +6964,16 @@
       "peer": true
     },
     "node_modules/css-minimizer-webpack-plugin/node_modules/schema-utils": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
-      "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz",
+      "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "@types/json-schema": "^7.0.9",
-        "ajv": "^8.8.0",
+        "ajv": "^8.9.0",
         "ajv-formats": "^2.1.1",
-        "ajv-keywords": "^5.0.0"
+        "ajv-keywords": "^5.1.0"
       },
       "engines": {
         "node": ">= 12.13.0"
@@ -6949,9 +7076,9 @@
       "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg=="
     },
     "node_modules/cssdb": {
-      "version": "7.2.1",
-      "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.2.1.tgz",
-      "integrity": "sha512-btohrCpVaLqOoMt90aumHe6HU4c06duiYA8ymwtpGfwuZAhWKDBve/c2k+E85Jeq5iojPkeonqiKV+aLeY8QlA==",
+      "version": "7.5.4",
+      "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.5.4.tgz",
+      "integrity": "sha512-fGD+J6Jlq+aurfE1VDXlLS4Pt0VtNlu2+YgfGOdMxRyl/HQ9bDiHTwSck1Yz8A97Dt/82izSK6Bp/4nVqacOsg==",
       "dev": true,
       "peer": true,
       "funding": {
@@ -6973,13 +7100,13 @@
       }
     },
     "node_modules/cssnano": {
-      "version": "5.1.14",
-      "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.14.tgz",
-      "integrity": "sha512-Oou7ihiTocbKqi0J1bB+TRJIQX5RMR3JghA8hcWSw9mjBLQ5Y3RWqEDoYG3sRNlAbCIXpqMoZGbq5KDR3vdzgw==",
+      "version": "5.1.15",
+      "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-5.1.15.tgz",
+      "integrity": "sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "cssnano-preset-default": "^5.2.13",
+        "cssnano-preset-default": "^5.2.14",
         "lilconfig": "^2.0.3",
         "yaml": "^1.10.2"
       },
@@ -6995,23 +7122,23 @@
       }
     },
     "node_modules/cssnano-preset-default": {
-      "version": "5.2.13",
-      "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.13.tgz",
-      "integrity": "sha512-PX7sQ4Pb+UtOWuz8A1d+Rbi+WimBIxJTRyBdgGp1J75VU0r/HFQeLnMYgHiCAp6AR4rqrc7Y4R+1Rjk3KJz6DQ==",
+      "version": "5.2.14",
+      "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz",
+      "integrity": "sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "css-declaration-sorter": "^6.3.1",
         "cssnano-utils": "^3.1.0",
         "postcss-calc": "^8.2.3",
-        "postcss-colormin": "^5.3.0",
+        "postcss-colormin": "^5.3.1",
         "postcss-convert-values": "^5.1.3",
         "postcss-discard-comments": "^5.1.2",
         "postcss-discard-duplicates": "^5.1.0",
         "postcss-discard-empty": "^5.1.1",
         "postcss-discard-overridden": "^5.1.0",
         "postcss-merge-longhand": "^5.1.7",
-        "postcss-merge-rules": "^5.1.3",
+        "postcss-merge-rules": "^5.1.4",
         "postcss-minify-font-values": "^5.1.0",
         "postcss-minify-gradients": "^5.1.1",
         "postcss-minify-params": "^5.1.4",
@@ -7026,7 +7153,7 @@
         "postcss-normalize-url": "^5.1.0",
         "postcss-normalize-whitespace": "^5.1.1",
         "postcss-ordered-values": "^5.1.3",
-        "postcss-reduce-initial": "^5.1.1",
+        "postcss-reduce-initial": "^5.1.2",
         "postcss-reduce-transforms": "^5.1.0",
         "postcss-svgo": "^5.1.0",
         "postcss-unique-selectors": "^5.1.1"
@@ -7123,9 +7250,9 @@
       "peer": true
     },
     "node_modules/csstype": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
-      "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
+      "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
     },
     "node_modules/customize-cra": {
       "version": "1.0.0",
@@ -7229,9 +7356,9 @@
       "peer": true
     },
     "node_modules/deepmerge": {
-      "version": "4.2.2",
-      "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
-      "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+      "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
       "dev": true,
       "peer": true,
       "engines": {
@@ -7262,9 +7389,9 @@
       }
     },
     "node_modules/define-properties": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
-      "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz",
+      "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==",
       "dependencies": {
         "has-property-descriptors": "^1.0.0",
         "object-keys": "^1.1.1"
@@ -7276,16 +7403,6 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
-    "node_modules/defined": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz",
-      "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==",
-      "dev": true,
-      "peer": true,
-      "funding": {
-        "url": "https://github.com/sponsors/ljharb"
-      }
-    },
     "node_modules/delayed-stream": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -7369,24 +7486,6 @@
       "dev": true,
       "peer": true
     },
-    "node_modules/detective": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz",
-      "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==",
-      "dev": true,
-      "peer": true,
-      "dependencies": {
-        "acorn-node": "^1.8.2",
-        "defined": "^1.0.0",
-        "minimist": "^1.2.6"
-      },
-      "bin": {
-        "detective": "bin/detective.js"
-      },
-      "engines": {
-        "node": ">=0.8.0"
-      }
-    },
     "node_modules/didyoumean": {
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
@@ -7429,9 +7528,9 @@
       "peer": true
     },
     "node_modules/dns-packet": {
-      "version": "5.4.0",
-      "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz",
-      "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==",
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.5.0.tgz",
+      "integrity": "sha512-USawdAUzRkV6xrqTjiAEp6M9YagZEzWcSUaZTcIFAiyQWW1SoI6KyId8y2+/71wbgHKQAKd+iupLv4YvEwYWvA==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -7594,9 +7693,9 @@
       "peer": true
     },
     "node_modules/ejs": {
-      "version": "3.1.8",
-      "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz",
-      "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==",
+      "version": "3.1.9",
+      "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.9.tgz",
+      "integrity": "sha512-rC+QVNMJWv+MtPgkt0y+0rVEIdbtxVADApW9JXrUVlzHetgcyczP/E7DJmWJ4fJCZF2cPcBk0laWO9ZHMG3DmQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -7610,9 +7709,9 @@
       }
     },
     "node_modules/electron-to-chromium": {
-      "version": "1.4.284",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
-      "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
+      "version": "1.4.365",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.365.tgz",
+      "integrity": "sha512-FRHZO+1tUNO4TOPXmlxetkoaIY8uwHzd1kKopK/Gx2SKn1L47wJXWD44wxP5CGRyyP98z/c8e1eBzJrgPeiBOg==",
       "dev": true,
       "peer": true
     },
@@ -7701,18 +7800,18 @@
       }
     },
     "node_modules/es-abstract": {
-      "version": "1.21.1",
-      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz",
-      "integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==",
+      "version": "1.21.2",
+      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz",
+      "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==",
       "dev": true,
       "dependencies": {
+        "array-buffer-byte-length": "^1.0.0",
         "available-typed-arrays": "^1.0.5",
         "call-bind": "^1.0.2",
         "es-set-tostringtag": "^2.0.1",
         "es-to-primitive": "^1.2.1",
-        "function-bind": "^1.1.1",
         "function.prototype.name": "^1.1.5",
-        "get-intrinsic": "^1.1.3",
+        "get-intrinsic": "^1.2.0",
         "get-symbol-description": "^1.0.0",
         "globalthis": "^1.0.3",
         "gopd": "^1.0.1",
@@ -7720,8 +7819,8 @@
         "has-property-descriptors": "^1.0.0",
         "has-proto": "^1.0.1",
         "has-symbols": "^1.0.3",
-        "internal-slot": "^1.0.4",
-        "is-array-buffer": "^3.0.1",
+        "internal-slot": "^1.0.5",
+        "is-array-buffer": "^3.0.2",
         "is-callable": "^1.2.7",
         "is-negative-zero": "^2.0.2",
         "is-regex": "^1.1.4",
@@ -7729,11 +7828,12 @@
         "is-string": "^1.0.7",
         "is-typed-array": "^1.1.10",
         "is-weakref": "^1.0.2",
-        "object-inspect": "^1.12.2",
+        "object-inspect": "^1.12.3",
         "object-keys": "^1.1.1",
         "object.assign": "^4.1.4",
         "regexp.prototype.flags": "^1.4.3",
         "safe-regex-test": "^1.0.0",
+        "string.prototype.trim": "^1.2.7",
         "string.prototype.trimend": "^1.0.6",
         "string.prototype.trimstart": "^1.0.6",
         "typed-array-length": "^1.0.4",
@@ -7774,9 +7874,9 @@
       }
     },
     "node_modules/es-module-lexer": {
-      "version": "0.9.3",
-      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
-      "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz",
+      "integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==",
       "dev": true,
       "peer": true
     },
@@ -7935,13 +8035,16 @@
       }
     },
     "node_modules/eslint": {
-      "version": "8.32.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.32.0.tgz",
-      "integrity": "sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==",
+      "version": "8.38.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.38.0.tgz",
+      "integrity": "sha512-pIdsD2jwlUGf/U38Jv97t8lq6HpaU/G9NKbYmpWpZGw3LdTNhZLbJePqxOXGB5+JEKfOPU/XLxYxFh03nr1KTg==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@eslint/eslintrc": "^1.4.1",
+        "@eslint-community/eslint-utils": "^4.2.0",
+        "@eslint-community/regexpp": "^4.4.0",
+        "@eslint/eslintrc": "^2.0.2",
+        "@eslint/js": "8.38.0",
         "@humanwhocodes/config-array": "^0.11.8",
         "@humanwhocodes/module-importer": "^1.0.1",
         "@nodelib/fs.walk": "^1.2.8",
@@ -7952,10 +8055,9 @@
         "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-visitor-keys": "^3.4.0",
+        "espree": "^9.5.1",
+        "esquery": "^1.4.2",
         "esutils": "^2.0.2",
         "fast-deep-equal": "^3.1.3",
         "file-entry-cache": "^6.0.1",
@@ -7976,7 +8078,6 @@
         "minimatch": "^3.1.2",
         "natural-compare": "^1.4.0",
         "optionator": "^0.9.1",
-        "regexpp": "^3.2.0",
         "strip-ansi": "^6.0.1",
         "strip-json-comments": "^3.1.0",
         "text-table": "^0.2.0"
@@ -8043,13 +8144,13 @@
       }
     },
     "node_modules/eslint-import-resolver-node/node_modules/resolve": {
-      "version": "1.22.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
-      "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+      "version": "1.22.3",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz",
+      "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "is-core-module": "^2.9.0",
+        "is-core-module": "^2.12.0",
         "path-parse": "^1.0.7",
         "supports-preserve-symlinks-flag": "^1.0.0"
       },
@@ -8061,9 +8162,9 @@
       }
     },
     "node_modules/eslint-module-utils": {
-      "version": "2.7.4",
-      "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz",
-      "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==",
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz",
+      "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -8161,13 +8262,13 @@
       }
     },
     "node_modules/eslint-plugin-import/node_modules/resolve": {
-      "version": "1.22.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
-      "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+      "version": "1.22.3",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz",
+      "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "is-core-module": "^2.9.0",
+        "is-core-module": "^2.12.0",
         "path-parse": "^1.0.7",
         "supports-preserve-symlinks-flag": "^1.0.0"
       },
@@ -8235,9 +8336,9 @@
       }
     },
     "node_modules/eslint-plugin-react": {
-      "version": "7.32.1",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.1.tgz",
-      "integrity": "sha512-vOjdgyd0ZHBXNsmvU+785xY8Bfe57EFbTYYk8XrROzWpr9QBvpjITvAXt9xqcE6+8cjR/g1+mfumPToxsl1www==",
+      "version": "7.32.2",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz",
+      "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==",
       "dev": true,
       "dependencies": {
         "array-includes": "^3.1.6",
@@ -8289,13 +8390,13 @@
       }
     },
     "node_modules/eslint-plugin-testing-library": {
-      "version": "5.9.1",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.9.1.tgz",
-      "integrity": "sha512-6BQp3tmb79jLLasPHJmy8DnxREe+2Pgf7L+7o09TSWPfdqqtQfRZmZNetr5mOs3yqZk/MRNxpN3RUpJe0wB4LQ==",
+      "version": "5.10.3",
+      "resolved": "https://registry.npmjs.org/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.10.3.tgz",
+      "integrity": "sha512-0yhsKFsjHLud5PM+f2dWr9K3rqYzMy4cSHs3lcmFYMa1CdSzRvHGgXvsFarBjZ41gU8jhTdMIkg8jHLxGJqLqw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@typescript-eslint/utils": "^5.13.0"
+        "@typescript-eslint/utils": "^5.58.0"
       },
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0",
@@ -8327,40 +8428,16 @@
         "node": ">=4.0"
       }
     },
-    "node_modules/eslint-utils": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
-      "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
-      "dev": true,
-      "dependencies": {
-        "eslint-visitor-keys": "^2.0.0"
-      },
-      "engines": {
-        "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/mysticatea"
-      },
-      "peerDependencies": {
-        "eslint": ">=5"
-      }
-    },
-    "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
-      "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
-      "dev": true,
-      "engines": {
-        "node": ">=10"
-      }
-    },
     "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.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz",
+      "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==",
       "dev": true,
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
       }
     },
     "node_modules/eslint-webpack-plugin": {
@@ -8451,16 +8528,16 @@
       "peer": true
     },
     "node_modules/eslint-webpack-plugin/node_modules/schema-utils": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
-      "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz",
+      "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "@types/json-schema": "^7.0.9",
-        "ajv": "^8.8.0",
+        "ajv": "^8.9.0",
         "ajv-formats": "^2.1.1",
-        "ajv-keywords": "^5.0.0"
+        "ajv-keywords": "^5.1.0"
       },
       "engines": {
         "node": ">= 12.13.0"
@@ -8553,9 +8630,9 @@
       }
     },
     "node_modules/eslint/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==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -8564,12 +8641,15 @@
       },
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
       }
     },
     "node_modules/eslint/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==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -8619,15 +8699,15 @@
       }
     },
     "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.5.1",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz",
+      "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "acorn": "^8.8.0",
         "acorn-jsx": "^5.3.2",
-        "eslint-visitor-keys": "^3.3.0"
+        "eslint-visitor-keys": "^3.4.0"
       },
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -8651,9 +8731,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==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -8844,6 +8924,22 @@
       "dev": true,
       "peer": true
     },
+    "node_modules/express/node_modules/qs": {
+      "version": "6.11.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+      "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "side-channel": "^1.0.4"
+      },
+      "engines": {
+        "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/fast-deep-equal": {
       "version": "3.1.3",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -9135,9 +9231,9 @@
       }
     },
     "node_modules/fork-ts-checker-webpack-plugin": {
-      "version": "6.5.2",
-      "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.2.tgz",
-      "integrity": "sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA==",
+      "version": "6.5.3",
+      "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz",
+      "integrity": "sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -9303,9 +9399,9 @@
       }
     },
     "node_modules/fork-ts-checker-webpack-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.4.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz",
+      "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -9491,9 +9587,9 @@
       }
     },
     "node_modules/get-intrinsic": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
-      "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
+      "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
       "dependencies": {
         "function-bind": "^1.1.1",
         "has": "^1.0.3",
@@ -9688,9 +9784,9 @@
       }
     },
     "node_modules/graceful-fs": {
-      "version": "4.2.10",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
-      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
       "dev": true,
       "peer": true
     },
@@ -9698,8 +9794,7 @@
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
       "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
-      "dev": true,
-      "peer": true
+      "dev": true
     },
     "node_modules/gzip-size": {
       "version": "6.0.0",
@@ -9847,9 +9942,9 @@
       "peer": true
     },
     "node_modules/hpack.js/node_modules/readable-stream": {
-      "version": "2.3.7",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
-      "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+      "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -9929,9 +10024,9 @@
       }
     },
     "node_modules/html-webpack-plugin": {
-      "version": "5.5.0",
-      "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz",
-      "integrity": "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw==",
+      "version": "5.5.1",
+      "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.1.tgz",
+      "integrity": "sha512-cTUzZ1+NqjGEKjmVgZKLMdiFg3m9MdRXkZW2OEe69WYVi5ONLMmlnSZdXzGGMOq0C8jGDrL6EWyEDDUioHO/pA==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -10138,9 +10233,9 @@
       }
     },
     "node_modules/immer": {
-      "version": "9.0.18",
-      "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.18.tgz",
-      "integrity": "sha512-eAPNpsj7Ax1q6Y/3lm2PmlwRcFzpON7HSNQ3ru5WQH1/PSpnyed/HpNOELl2CxLKoj4r+bAHgdyKqW5gc2Se1A==",
+      "version": "9.0.21",
+      "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
+      "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==",
       "dev": true,
       "peer": true,
       "funding": {
@@ -10149,9 +10244,9 @@
       }
     },
     "node_modules/immutable": {
-      "version": "4.2.2",
-      "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.2.tgz",
-      "integrity": "sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og=="
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz",
+      "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg=="
     },
     "node_modules/import-fresh": {
       "version": "3.3.0",
@@ -10234,11 +10329,11 @@
       "peer": true
     },
     "node_modules/internal-slot": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz",
-      "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==",
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz",
+      "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==",
       "dependencies": {
-        "get-intrinsic": "^1.1.3",
+        "get-intrinsic": "^1.2.0",
         "has": "^1.0.3",
         "side-channel": "^1.0.4"
       },
@@ -10280,12 +10375,12 @@
       }
     },
     "node_modules/is-array-buffer": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.1.tgz",
-      "integrity": "sha512-ASfLknmY8Xa2XtB4wmbz13Wu202baeA18cJBCeCy0wXUHZF0IPyVEXqKEcd+t2fNSLLL1vC6k7lxZEojNbISXQ==",
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
+      "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==",
       "dependencies": {
         "call-bind": "^1.0.2",
-        "get-intrinsic": "^1.1.3",
+        "get-intrinsic": "^1.2.0",
         "is-typed-array": "^1.1.10"
       },
       "funding": {
@@ -10348,9 +10443,9 @@
       }
     },
     "node_modules/is-core-module": {
-      "version": "2.11.0",
-      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
-      "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
+      "version": "2.12.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz",
+      "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==",
       "dev": true,
       "dependencies": {
         "has": "^1.0.3"
@@ -11965,13 +12060,13 @@
       }
     },
     "node_modules/jest-resolve/node_modules/resolve": {
-      "version": "1.22.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
-      "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+      "version": "1.22.3",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz",
+      "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "is-core-module": "^2.9.0",
+        "is-core-module": "^2.12.0",
         "path-parse": "^1.0.7",
         "supports-preserve-symlinks-flag": "^1.0.0"
       },
@@ -12339,9 +12434,9 @@
       }
     },
     "node_modules/jest-snapshot/node_modules/semver": {
-      "version": "7.3.8",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
-      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "version": "7.4.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz",
+      "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -12647,9 +12742,9 @@
       }
     },
     "node_modules/jest-watch-typeahead/node_modules/@types/yargs": {
-      "version": "17.0.20",
-      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.20.tgz",
-      "integrity": "sha512-eknWrTHofQuPk2iuqDm1waA7V6xPlbgBoaaXEgYkClhLOnB0TtbW+srJaOToAgawPxPlHQzwypFA2bhZaUGP5A==",
+      "version": "17.0.24",
+      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz",
+      "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -13092,10 +13187,20 @@
         "url": "https://github.com/chalk/supports-color?sponsor=1"
       }
     },
+    "node_modules/jiti": {
+      "version": "1.18.2",
+      "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz",
+      "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==",
+      "dev": true,
+      "peer": true,
+      "bin": {
+        "jiti": "bin/jiti.js"
+      }
+    },
     "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==",
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz",
+      "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==",
       "dev": true,
       "peer": true,
       "funding": {
@@ -13305,6 +13410,17 @@
         "language-subtag-registry": "~0.3.2"
       }
     },
+    "node_modules/launch-editor": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz",
+      "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "picocolors": "^1.0.0",
+        "shell-quote": "^1.7.3"
+      }
+    },
     "node_modules/leven": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@@ -13330,9 +13446,9 @@
       }
     },
     "node_modules/lilconfig": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz",
-      "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
+      "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
       "dev": true,
       "peer": true,
       "engines": {
@@ -13473,9 +13589,9 @@
       }
     },
     "node_modules/lz-string": {
-      "version": "1.4.4",
-      "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz",
-      "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==",
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
+      "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
       "bin": {
         "lz-string": "bin/bin.js"
       }
@@ -13517,9 +13633,9 @@
       }
     },
     "node_modules/marked": {
-      "version": "4.2.12",
-      "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz",
-      "integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==",
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
+      "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
       "bin": {
         "marked": "bin/marked.js"
       },
@@ -13545,9 +13661,9 @@
       }
     },
     "node_modules/memfs": {
-      "version": "3.4.13",
-      "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.13.tgz",
-      "integrity": "sha512-omTM41g3Skpvx5dSYeZIbXKcXoAVc/AoMNwn9TKx++L/gaen/+4TTttmu8ZSch5vfVJ8uJvGbroTsIlslRg6lg==",
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.0.tgz",
+      "integrity": "sha512-yK6o8xVJlQerz57kvPROwTMgx5WtGwC2ZxDtOUsnGl49rHjYkfQoPNZPCKH73VdLE1BwBu/+Fx/NL8NYMUw2aA==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -13658,9 +13774,9 @@
       }
     },
     "node_modules/mini-css-extract-plugin": {
-      "version": "2.7.2",
-      "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz",
-      "integrity": "sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==",
+      "version": "2.7.5",
+      "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.5.tgz",
+      "integrity": "sha512-9HaR++0mlgom81s95vvNjxkg52n2b5s//3ZTI1EtzFb98awsLSivs2LMsVqnQ3ay0PVhqWcGNyDaTE961FOcjQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -13715,16 +13831,16 @@
       "peer": true
     },
     "node_modules/mini-css-extract-plugin/node_modules/schema-utils": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
-      "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz",
+      "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "@types/json-schema": "^7.0.9",
-        "ajv": "^8.8.0",
+        "ajv": "^8.9.0",
         "ajv-formats": "^2.1.1",
-        "ajv-keywords": "^5.0.0"
+        "ajv-keywords": "^5.1.0"
       },
       "engines": {
         "node": ">= 12.13.0"
@@ -13754,9 +13870,9 @@
       }
     },
     "node_modules/minimist": {
-      "version": "1.2.7",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
-      "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
       "dev": true,
       "peer": true,
       "funding": {
@@ -13796,12 +13912,30 @@
         "multicast-dns": "cli.js"
       }
     },
-    "node_modules/nanoid": {
-      "version": "3.3.4",
-      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
-      "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
+    "node_modules/mz": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
+      "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
       "dev": true,
       "peer": true,
+      "dependencies": {
+        "any-promise": "^1.0.0",
+        "object-assign": "^4.0.1",
+        "thenify-all": "^1.0.0"
+      }
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.6",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
+      "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "peer": true,
       "bin": {
         "nanoid": "bin/nanoid.cjs"
       },
@@ -13868,9 +14002,9 @@
       "peer": true
     },
     "node_modules/node-releases": {
-      "version": "2.0.8",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz",
-      "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==",
+      "version": "2.0.10",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
+      "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==",
       "dev": true,
       "peer": true
     },
@@ -13932,9 +14066,9 @@
       }
     },
     "node_modules/nwsapi": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz",
-      "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==",
+      "version": "2.2.4",
+      "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.4.tgz",
+      "integrity": "sha512-NHj4rzRo0tQdijE9ZqAx6kYDcoRwYwSYzCA8MY3JzfxlrvEU0jhnhJT9BhqhJs7I/dKcrDm6TyulaRqZPIhN5g==",
       "dev": true,
       "peer": true
     },
@@ -14142,9 +14276,9 @@
       }
     },
     "node_modules/open": {
-      "version": "8.4.0",
-      "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz",
-      "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==",
+      "version": "8.4.2",
+      "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
+      "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -14550,9 +14684,9 @@
       }
     },
     "node_modules/postcss": {
-      "version": "8.4.21",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
-      "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
+      "version": "8.4.22",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.22.tgz",
+      "integrity": "sha512-XseknLAfRHzVWjCEtdviapiBtfLdgyzExD50Rg2ePaucEesyh8Wv4VPdW0nbyDa1ydbrAxV19jvMT4+LFmcNUA==",
       "dev": true,
       "funding": [
         {
@@ -14562,11 +14696,15 @@
         {
           "type": "tidelift",
           "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
         }
       ],
       "peer": true,
       "dependencies": {
-        "nanoid": "^3.3.4",
+        "nanoid": "^3.3.6",
         "picocolors": "^1.0.0",
         "source-map-js": "^1.0.2"
       },
@@ -14699,13 +14837,13 @@
       }
     },
     "node_modules/postcss-colormin": {
-      "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.0.tgz",
-      "integrity": "sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg==",
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.3.1.tgz",
+      "integrity": "sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "browserslist": "^4.16.6",
+        "browserslist": "^4.21.4",
         "caniuse-api": "^3.0.0",
         "colord": "^2.9.1",
         "postcss-value-parser": "^4.2.0"
@@ -15011,13 +15149,13 @@
       }
     },
     "node_modules/postcss-import/node_modules/resolve": {
-      "version": "1.22.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
-      "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+      "version": "1.22.3",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz",
+      "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "is-core-module": "^2.9.0",
+        "is-core-module": "^2.12.0",
         "path-parse": "^1.0.7",
         "supports-preserve-symlinks-flag": "^1.0.0"
       },
@@ -15039,9 +15177,9 @@
       }
     },
     "node_modules/postcss-js": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz",
-      "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
+      "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -15055,7 +15193,7 @@
         "url": "https://opencollective.com/postcss/"
       },
       "peerDependencies": {
-        "postcss": "^8.3.3"
+        "postcss": "^8.4.21"
       }
     },
     "node_modules/postcss-lab-function": {
@@ -15146,9 +15284,9 @@
       }
     },
     "node_modules/postcss-loader/node_modules/semver": {
-      "version": "7.3.8",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
-      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "version": "7.4.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz",
+      "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -15212,9 +15350,9 @@
       }
     },
     "node_modules/postcss-merge-rules": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.3.tgz",
-      "integrity": "sha512-LbLd7uFC00vpOuMvyZop8+vvhnfRGpp2S+IMQKeuOZZapPRY4SMq5ErjQeHbHsjCUgJkRNrlU+LmxsKIqPKQlA==",
+      "version": "5.1.4",
+      "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz",
+      "integrity": "sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -15743,9 +15881,9 @@
       }
     },
     "node_modules/postcss-reduce-initial": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.1.tgz",
-      "integrity": "sha512-//jeDqWcHPuXGZLoolFrUXBDyuEGbr9S2rMo19bkTIjBQ4PqkaO+oI8wua5BOUxpfi97i3PCoInsiFIEBfkm9w==",
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz",
+      "integrity": "sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -15923,9 +16061,9 @@
       "peer": true
     },
     "node_modules/preact": {
-      "version": "10.11.3",
-      "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.3.tgz",
-      "integrity": "sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==",
+      "version": "10.13.2",
+      "resolved": "https://registry.npmjs.org/preact/-/preact-10.13.2.tgz",
+      "integrity": "sha512-q44QFLhOhty2Bd0Y46fnYW0gD/cbVM9dUVtNTDKPcdXSMA7jfY+Jpd6rk3GB0lcQss0z5s/6CmVP0Z/hV+g6pw==",
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/preact"
@@ -16069,9 +16207,9 @@
       "peer": true
     },
     "node_modules/punycode": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz",
-      "integrity": "sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==",
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
+      "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
       "dev": true,
       "peer": true,
       "engines": {
@@ -16090,9 +16228,9 @@
       }
     },
     "node_modules/qs": {
-      "version": "6.11.0",
-      "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
-      "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+      "version": "6.11.1",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.1.tgz",
+      "integrity": "sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ==",
       "dependencies": {
         "side-channel": "^1.0.4"
       },
@@ -16450,11 +16588,11 @@
       }
     },
     "node_modules/react-router": {
-      "version": "6.7.0",
-      "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.7.0.tgz",
-      "integrity": "sha512-KNWlG622ddq29MAM159uUsNMdbX8USruoKnwMMQcs/QWZgFUayICSn2oB7reHce1zPj6CG18kfkZIunSSRyGHg==",
+      "version": "6.10.0",
+      "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.10.0.tgz",
+      "integrity": "sha512-Nrg0BWpQqrC3ZFFkyewrflCud9dio9ME3ojHCF/WLsprJVzkq3q3UeEhMCAW1dobjeGbWgjNn/PVF6m46ANxXQ==",
       "dependencies": {
-        "@remix-run/router": "1.3.0"
+        "@remix-run/router": "1.5.0"
       },
       "engines": {
         "node": ">=14"
@@ -16464,12 +16602,12 @@
       }
     },
     "node_modules/react-router-dom": {
-      "version": "6.7.0",
-      "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.7.0.tgz",
-      "integrity": "sha512-jQtXUJyhso3kFw430+0SPCbmCmY1/kJv8iRffGHwHy3CkoomGxeYzMkmeSPYo6Egzh3FKJZRAL22yg5p2tXtfg==",
+      "version": "6.10.0",
+      "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.10.0.tgz",
+      "integrity": "sha512-E5dfxRPuXKJqzwSe/qGcqdwa18QiWC6f3H3cWXM24qj4N0/beCIf/CWTipop2xm7mR0RCS99NnaqPNjHtrAzCg==",
       "dependencies": {
-        "@remix-run/router": "1.3.0",
-        "react-router": "6.7.0"
+        "@remix-run/router": "1.5.0",
+        "react-router": "6.10.0"
       },
       "engines": {
         "node": ">=14"
@@ -16567,13 +16705,13 @@
       }
     },
     "node_modules/react-scripts/node_modules/resolve": {
-      "version": "1.22.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
-      "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+      "version": "1.22.3",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz",
+      "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "is-core-module": "^2.9.0",
+        "is-core-module": "^2.12.0",
         "path-parse": "^1.0.7",
         "supports-preserve-symlinks-flag": "^1.0.0"
       },
@@ -16585,9 +16723,9 @@
       }
     },
     "node_modules/react-scripts/node_modules/semver": {
-      "version": "7.3.8",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
-      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "version": "7.4.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.4.0.tgz",
+      "integrity": "sha512-RgOxM8Mw+7Zus0+zcLEUn8+JfoLpj/huFTItQy2hsM4khuC1HYRDp0cU482Ewn/Fcy6bCjufD8vAj7voC66KQw==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -16618,9 +16756,9 @@
       }
     },
     "node_modules/readable-stream": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
-      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+      "version": "3.6.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -16726,28 +16864,16 @@
         "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==",
-      "dev": true,
-      "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",
-      "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==",
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz",
+      "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
+        "@babel/regjsgen": "^0.8.0",
         "regenerate": "^1.4.2",
         "regenerate-unicode-properties": "^10.1.0",
-        "regjsgen": "^0.7.1",
         "regjsparser": "^0.9.1",
         "unicode-match-property-ecmascript": "^2.0.0",
         "unicode-match-property-value-ecmascript": "^2.1.0"
@@ -16756,13 +16882,6 @@
         "node": ">=4"
       }
     },
-    "node_modules/regjsgen": {
-      "version": "0.7.1",
-      "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz",
-      "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==",
-      "dev": true,
-      "peer": true
-    },
     "node_modules/regjsparser": {
       "version": "0.9.1",
       "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz",
@@ -17151,9 +17270,9 @@
       "peer": true
     },
     "node_modules/sass": {
-      "version": "1.57.1",
-      "resolved": "https://registry.npmjs.org/sass/-/sass-1.57.1.tgz",
-      "integrity": "sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==",
+      "version": "1.62.0",
+      "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.0.tgz",
+      "integrity": "sha512-Q4USplo4pLYgCi+XlipZCWUQz5pkg/ruSSgJ0WRDSb/+3z9tXUOkQ7QPYn4XrhZKYAK4HlpaQecRwKLJX6+DBg==",
       "dependencies": {
         "chokidar": ">=3.0.0 <4.0.0",
         "immutable": "^4.0.0",
@@ -17163,7 +17282,7 @@
         "sass": "sass.js"
       },
       "engines": {
-        "node": ">=12.0.0"
+        "node": ">=14.0.0"
       }
     },
     "node_modules/sass-loader": {
@@ -17235,9 +17354,9 @@
       }
     },
     "node_modules/schema-utils": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
-      "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz",
+      "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -17474,9 +17593,9 @@
       }
     },
     "node_modules/shell-quote": {
-      "version": "1.7.4",
-      "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.4.tgz",
-      "integrity": "sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==",
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz",
+      "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==",
       "dev": true,
       "peer": true,
       "funding": {
@@ -17777,6 +17896,23 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/string.prototype.trim": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz",
+      "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.2",
+        "define-properties": "^1.1.4",
+        "es-abstract": "^1.20.4"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
     "node_modules/string.prototype.trimend": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz",
@@ -17888,9 +18024,9 @@
       }
     },
     "node_modules/style-loader": {
-      "version": "3.3.1",
-      "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz",
-      "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==",
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.2.tgz",
+      "integrity": "sha512-RHs/vcrKdQK8wZliteNK4NKzxvLBzpuHMqYmUVWeKa6MkaIQ97ZTOS0b+zapZhy6GcrgWnvWYCMHRirC3FsUmw==",
       "dev": true,
       "peer": true,
       "engines": {
@@ -17921,6 +18057,60 @@
         "postcss": "^8.2.15"
       }
     },
+    "node_modules/sucrase": {
+      "version": "3.32.0",
+      "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz",
+      "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.2",
+        "commander": "^4.0.0",
+        "glob": "7.1.6",
+        "lines-and-columns": "^1.1.6",
+        "mz": "^2.7.0",
+        "pirates": "^4.0.1",
+        "ts-interface-checker": "^0.1.9"
+      },
+      "bin": {
+        "sucrase": "bin/sucrase",
+        "sucrase-node": "bin/sucrase-node"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/sucrase/node_modules/commander": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
+      "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+      "dev": true,
+      "peer": true,
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/sucrase/node_modules/glob": {
+      "version": "7.1.6",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+      "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
     "node_modules/supports-color": {
       "version": "5.5.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -18104,35 +18294,36 @@
       "peer": true
     },
     "node_modules/tailwindcss": {
-      "version": "3.2.4",
-      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.4.tgz",
-      "integrity": "sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==",
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.1.tgz",
+      "integrity": "sha512-Vkiouc41d4CEq0ujXl6oiGFQ7bA3WEhUZdTgXAhtKxSy49OmKs8rEfQmupsfF0IGW8fv2iQkp1EVUuapCFrZ9g==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "arg": "^5.0.2",
         "chokidar": "^3.5.3",
         "color-name": "^1.1.4",
-        "detective": "^5.2.1",
         "didyoumean": "^1.2.2",
         "dlv": "^1.1.3",
         "fast-glob": "^3.2.12",
         "glob-parent": "^6.0.2",
         "is-glob": "^4.0.3",
+        "jiti": "^1.17.2",
         "lilconfig": "^2.0.6",
         "micromatch": "^4.0.5",
         "normalize-path": "^3.0.0",
         "object-hash": "^3.0.0",
         "picocolors": "^1.0.0",
-        "postcss": "^8.4.18",
+        "postcss": "^8.0.9",
         "postcss-import": "^14.1.0",
         "postcss-js": "^4.0.0",
         "postcss-load-config": "^3.1.4",
         "postcss-nested": "6.0.0",
-        "postcss-selector-parser": "^6.0.10",
+        "postcss-selector-parser": "^6.0.11",
         "postcss-value-parser": "^4.2.0",
         "quick-lru": "^5.1.1",
-        "resolve": "^1.22.1"
+        "resolve": "^1.22.1",
+        "sucrase": "^3.29.0"
       },
       "bin": {
         "tailwind": "lib/cli.js",
@@ -18153,13 +18344,13 @@
       "peer": true
     },
     "node_modules/tailwindcss/node_modules/resolve": {
-      "version": "1.22.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
-      "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
+      "version": "1.22.3",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz",
+      "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "is-core-module": "^2.9.0",
+        "is-core-module": "^2.12.0",
         "path-parse": "^1.0.7",
         "supports-preserve-symlinks-flag": "^1.0.0"
       },
@@ -18240,9 +18431,9 @@
       }
     },
     "node_modules/terser": {
-      "version": "5.16.1",
-      "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz",
-      "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==",
+      "version": "5.16.9",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.9.tgz",
+      "integrity": "sha512-HPa/FdTB9XGI2H1/keLFZHxl6WNvAI4YalHGtDQTlMnJcoqSab1UwL4l1hGEhs6/GmLHBZIg/YgB++jcbzoOEg==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -18259,17 +18450,17 @@
       }
     },
     "node_modules/terser-webpack-plugin": {
-      "version": "5.3.6",
-      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz",
-      "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==",
+      "version": "5.3.7",
+      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz",
+      "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==",
       "dev": true,
       "peer": true,
       "dependencies": {
-        "@jridgewell/trace-mapping": "^0.3.14",
+        "@jridgewell/trace-mapping": "^0.3.17",
         "jest-worker": "^27.4.5",
         "schema-utils": "^3.1.1",
-        "serialize-javascript": "^6.0.0",
-        "terser": "^5.14.1"
+        "serialize-javascript": "^6.0.1",
+        "terser": "^5.16.5"
       },
       "engines": {
         "node": ">= 10.13.0"
@@ -18322,6 +18513,29 @@
       "dev": true,
       "peer": true
     },
+    "node_modules/thenify": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
+      "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "any-promise": "^1.0.0"
+      }
+    },
+    "node_modules/thenify-all": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
+      "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "thenify": ">= 3.1.0 < 4"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
     "node_modules/throat": {
       "version": "6.0.2",
       "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz",
@@ -18420,15 +18634,22 @@
       "dev": true,
       "peer": true
     },
+    "node_modules/ts-interface-checker": {
+      "version": "0.1.13",
+      "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
+      "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
+      "dev": true,
+      "peer": true
+    },
     "node_modules/tsconfig-paths": {
-      "version": "3.14.1",
-      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
-      "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==",
+      "version": "3.14.2",
+      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
+      "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "@types/json5": "^0.0.29",
-        "json5": "^1.0.1",
+        "json5": "^1.0.2",
         "minimist": "^1.2.6",
         "strip-bom": "^3.0.0"
       }
@@ -18457,9 +18678,9 @@
       }
     },
     "node_modules/tslib": {
-      "version": "2.4.1",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
-      "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==",
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+      "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
       "dev": true,
       "peer": true
     },
@@ -18681,9 +18902,9 @@
       }
     },
     "node_modules/update-browserslist-db": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
-      "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
+      "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==",
       "dev": true,
       "funding": [
         {
@@ -18693,6 +18914,10 @@
         {
           "type": "tidelift",
           "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
         }
       ],
       "peer": true,
@@ -18701,16 +18926,16 @@
         "picocolors": "^1.0.0"
       },
       "bin": {
-        "browserslist-lint": "cli.js"
+        "update-browserslist-db": "cli.js"
       },
       "peerDependencies": {
         "browserslist": ">= 4.21.0"
       }
     },
     "node_modules/uplot": {
-      "version": "1.6.23",
-      "resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.23.tgz",
-      "integrity": "sha512-zERH8HUbHE6kYyAqfP58SYuESp9M5jphSrMjsyckAM0DJ8C39SEI19YrpVvTCTLZB5joFUBPOwueRnJCdV2OdQ=="
+      "version": "1.6.24",
+      "resolved": "https://registry.npmjs.org/uplot/-/uplot-1.6.24.tgz",
+      "integrity": "sha512-WpH2BsrFrqxkMu+4XBvc0eCDsRBhzoq9crttYeSI0bfxpzR5YoSVzZXOKFVWcVC7sp/aDXrdDPbDZGCtck2PVg=="
     },
     "node_modules/uri-js": {
       "version": "4.4.1",
@@ -18890,14 +19115,14 @@
       }
     },
     "node_modules/webpack": {
-      "version": "5.76.2",
-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.2.tgz",
-      "integrity": "sha512-Th05ggRm23rVzEOlX8y67NkYCHa9nTNcwHPBhdg+lKG+mtiW7XgggjAeeLnADAe7mLjJ6LUNfgHAuRRh+Z6J7w==",
+      "version": "5.79.0",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.79.0.tgz",
+      "integrity": "sha512-3mN4rR2Xq+INd6NnYuL9RC9GAmc1ROPKJoHhrZ4pAjdMFEkJJWrsPw8o2JjCIyQyTu7rTXYn4VG6OpyB3CobZg==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "@types/eslint-scope": "^3.7.3",
-        "@types/estree": "^0.0.51",
+        "@types/estree": "^1.0.0",
         "@webassemblyjs/ast": "1.11.1",
         "@webassemblyjs/wasm-edit": "1.11.1",
         "@webassemblyjs/wasm-parser": "1.11.1",
@@ -18906,7 +19131,7 @@
         "browserslist": "^4.14.5",
         "chrome-trace-event": "^1.0.2",
         "enhanced-resolve": "^5.10.0",
-        "es-module-lexer": "^0.9.0",
+        "es-module-lexer": "^1.2.1",
         "eslint-scope": "5.1.1",
         "events": "^3.2.0",
         "glob-to-regexp": "^0.4.1",
@@ -18917,7 +19142,7 @@
         "neo-async": "^2.6.2",
         "schema-utils": "^3.1.0",
         "tapable": "^2.1.1",
-        "terser-webpack-plugin": "^5.1.3",
+        "terser-webpack-plugin": "^5.3.7",
         "watchpack": "^2.4.0",
         "webpack-sources": "^3.2.3"
       },
@@ -18999,16 +19224,16 @@
       "peer": true
     },
     "node_modules/webpack-dev-middleware/node_modules/schema-utils": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
-      "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz",
+      "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "@types/json-schema": "^7.0.9",
-        "ajv": "^8.8.0",
+        "ajv": "^8.9.0",
         "ajv-formats": "^2.1.1",
-        "ajv-keywords": "^5.0.0"
+        "ajv-keywords": "^5.1.0"
       },
       "engines": {
         "node": ">= 12.13.0"
@@ -19019,9 +19244,9 @@
       }
     },
     "node_modules/webpack-dev-server": {
-      "version": "4.11.1",
-      "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz",
-      "integrity": "sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==",
+      "version": "4.13.3",
+      "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.13.3.tgz",
+      "integrity": "sha512-KqqzrzMRSRy5ePz10VhjyL27K2dxqwXQLP5rAKwRJBPUahe7Z2bBWzHw37jeb8GCPKxZRO79ZdQUAPesMh/Nug==",
       "dev": true,
       "peer": true,
       "dependencies": {
@@ -19044,6 +19269,7 @@
         "html-entities": "^2.3.2",
         "http-proxy-middleware": "^2.0.3",
         "ipaddr.js": "^2.0.1",
+        "launch-editor": "^2.6.0",
         "open": "^8.0.9",
         "p-retry": "^4.5.0",
         "rimraf": "^3.0.2",
@@ -19053,7 +19279,7 @@
         "sockjs": "^0.3.24",
         "spdy": "^4.0.2",
         "webpack-dev-middleware": "^5.3.1",
-        "ws": "^8.4.2"
+        "ws": "^8.13.0"
       },
       "bin": {
         "webpack-dev-server": "bin/webpack-dev-server.js"
@@ -19069,6 +19295,9 @@
         "webpack": "^4.37.0 || ^5.0.0"
       },
       "peerDependenciesMeta": {
+        "webpack": {
+          "optional": true
+        },
         "webpack-cli": {
           "optional": true
         }
@@ -19112,16 +19341,16 @@
       "peer": true
     },
     "node_modules/webpack-dev-server/node_modules/schema-utils": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
-      "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.1.tgz",
+      "integrity": "sha512-lELhBAAly9NowEsX0yZBlw9ahZG+sK/1RJ21EpzdYHKEs13Vku3LJ+MIPhh4sMs0oCCeufZQEQbMekiA4vuVIQ==",
       "dev": true,
       "peer": true,
       "dependencies": {
         "@types/json-schema": "^7.0.9",
-        "ajv": "^8.8.0",
+        "ajv": "^8.9.0",
         "ajv-formats": "^2.1.1",
-        "ajv-keywords": "^5.0.0"
+        "ajv-keywords": "^5.1.0"
       },
       "engines": {
         "node": ">= 12.13.0"
@@ -19132,9 +19361,9 @@
       }
     },
     "node_modules/webpack-dev-server/node_modules/ws": {
-      "version": "8.12.0",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz",
-      "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==",
+      "version": "8.13.0",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
+      "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
       "dev": true,
       "peer": true,
       "engines": {
@@ -19204,13 +19433,6 @@
         "node": ">=10.13.0"
       }
     },
-    "node_modules/webpack/node_modules/@types/estree": {
-      "version": "0.0.51",
-      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz",
-      "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==",
-      "dev": true,
-      "peer": true
-    },
     "node_modules/websocket-driver": {
       "version": "0.7.4",
       "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
@@ -19820,16 +20042,6 @@
       "dev": true,
       "peer": true
     },
-    "node_modules/xtend": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
-      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
-      "dev": true,
-      "peer": true,
-      "engines": {
-        "node": ">=0.4"
-      }
-    },
     "node_modules/y18n": {
       "version": "5.0.8",
       "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
diff --git a/app/vmui/packages/vmui/src/components/Chart/BarChart/BarChart.tsx b/app/vmui/packages/vmui/src/components/Chart/BarChart/BarChart.tsx
index 6f1a7a465c..fe1a3429db 100644
--- a/app/vmui/packages/vmui/src/components/Chart/BarChart/BarChart.tsx
+++ b/app/vmui/packages/vmui/src/components/Chart/BarChart/BarChart.tsx
@@ -1,19 +1,17 @@
 import React, { FC, useEffect, useRef, useState } from "preact/compat";
 import uPlot, { Options as uPlotOptions } from "uplot";
-import useResize from "../../../hooks/useResize";
 import { BarChartProps } from "./types";
 import "./style.scss";
 import { useAppState } from "../../../state/common/StateContext";
 
 const BarChart: FC<BarChartProps> = ({
   data,
-  container,
+  layoutSize,
   configs }) => {
   const { isDarkTheme } = useAppState();
 
   const uPlotRef = useRef<HTMLDivElement>(null);
   const [uPlotInst, setUPlotInst] = useState<uPlot>();
-  const layoutSize = useResize(container);
 
   const options: uPlotOptions ={
     ...configs,
diff --git a/app/vmui/packages/vmui/src/components/Chart/BarChart/types.ts b/app/vmui/packages/vmui/src/components/Chart/BarChart/types.ts
index 50377534cb..2dfeedbc4d 100644
--- a/app/vmui/packages/vmui/src/components/Chart/BarChart/types.ts
+++ b/app/vmui/packages/vmui/src/components/Chart/BarChart/types.ts
@@ -1,7 +1,8 @@
 import { AlignedData as uPlotData, Options as uPlotOptions } from "uplot";
+import { ElementSize } from "../../../hooks/useElementSize";
 
 export interface BarChartProps {
   data: uPlotData;
-  container: HTMLDivElement | null,
+  layoutSize: ElementSize,
   configs: uPlotOptions,
 }
diff --git a/app/vmui/packages/vmui/src/components/Chart/Heatmap/ChartTooltipHeatmap/ChartTooltipHeatmap.tsx b/app/vmui/packages/vmui/src/components/Chart/Heatmap/ChartTooltipHeatmap/ChartTooltipHeatmap.tsx
index 3cfeb5a355..3995aa2c9e 100644
--- a/app/vmui/packages/vmui/src/components/Chart/Heatmap/ChartTooltipHeatmap/ChartTooltipHeatmap.tsx
+++ b/app/vmui/packages/vmui/src/components/Chart/Heatmap/ChartTooltipHeatmap/ChartTooltipHeatmap.tsx
@@ -1,4 +1,4 @@
-import React, { FC, useEffect, useMemo, useRef, useState } from "preact/compat";
+import React, { FC, useCallback, useEffect, useRef, useState } from "preact/compat";
 import uPlot from "uplot";
 import ReactDOM from "react-dom";
 import Button from "../../../Main/Button/Button";
@@ -6,6 +6,7 @@ import { CloseIcon, DragIcon } from "../../../Main/Icons";
 import classNames from "classnames";
 import { MouseEvent as ReactMouseEvent } from "react";
 import "../../Line/ChartTooltip/style.scss";
+import useEventListener from "../../../../hooks/useEventListener";
 
 export interface TooltipHeatmapProps  {
   cursor: {left: number, top: number}
@@ -45,24 +46,22 @@ const ChartTooltipHeatmap: FC<ChartTooltipHeatmapProps> = ({
   const [moving, setMoving] = useState(false);
   const [moved, setMoved] = useState(false);
 
-  const targetPortal = useMemo(() => u.root.querySelector(".u-wrap"), [u]);
-
   const handleClose = () => {
     onClose && onClose(id);
   };
 
-  const handleMouseDown = (e: ReactMouseEvent<HTMLButtonElement, MouseEvent>) => {
+  const handleMouseDown = (e: ReactMouseEvent) => {
     setMoved(true);
     setMoving(true);
     const { clientX, clientY } = e;
     setPosition({ top: clientY, left: clientX });
   };
 
-  const handleMouseMove = (e: MouseEvent) => {
+  const handleMouseMove = useCallback((e: MouseEvent) => {
     if (!moving) return;
     const { clientX, clientY } = e;
     setPosition({ top: clientY, left: clientX });
-  };
+  }, [moving]);
 
   const handleMouseUp = () => {
     setMoving(false);
@@ -88,19 +87,10 @@ const ChartTooltipHeatmap: FC<ChartTooltipHeatmapProps> = ({
 
   useEffect(calcPosition, [u, cursor, tooltipOffset, tooltipRef]);
 
-  useEffect(() => {
-    if (moving) {
-      document.addEventListener("mousemove", handleMouseMove);
-      document.addEventListener("mouseup", handleMouseUp);
-    }
+  useEventListener("mousemove", handleMouseMove);
+  useEventListener("mouseup", handleMouseUp);
 
-    return () => {
-      document.removeEventListener("mousemove", handleMouseMove);
-      document.removeEventListener("mouseup", handleMouseUp);
-    };
-  }, [moving]);
-
-  if (!targetPortal || !cursor.left || !cursor.top || !value) return null;
+  if (!cursor?.left || !cursor?.top || !value) return null;
 
   return ReactDOM.createPortal((
     <div
@@ -146,7 +136,7 @@ const ChartTooltipHeatmap: FC<ChartTooltipHeatmapProps> = ({
         {bucket}
       </div>
     </div>
-  ), targetPortal);
+  ), u.root);
 };
 
 export default ChartTooltipHeatmap;
diff --git a/app/vmui/packages/vmui/src/components/Chart/Heatmap/HeatmapChart/HeatmapChart.tsx b/app/vmui/packages/vmui/src/components/Chart/Heatmap/HeatmapChart/HeatmapChart.tsx
index cdbe20fc58..f483ff83b8 100644
--- a/app/vmui/packages/vmui/src/components/Chart/Heatmap/HeatmapChart/HeatmapChart.tsx
+++ b/app/vmui/packages/vmui/src/components/Chart/Heatmap/HeatmapChart/HeatmapChart.tsx
@@ -10,7 +10,6 @@ import { getAxes } from "../../../../utils/uplot/axes";
 import { MetricResult } from "../../../../api/types";
 import { dateFromSeconds, formatDateForNativeInput, limitsDurations } from "../../../../utils/time";
 import throttle from "lodash.throttle";
-import useResize from "../../../../hooks/useResize";
 import { TimeParams } from "../../../../types";
 import { YaxisState } from "../../../../state/graph/reducer";
 import "uplot/dist/uPlot.min.css";
@@ -23,6 +22,8 @@ import ChartTooltipHeatmap, {
   ChartTooltipHeatmapProps,
   TooltipHeatmapProps
 } from "../ChartTooltipHeatmap/ChartTooltipHeatmap";
+import { ElementSize } from "../../../../hooks/useElementSize";
+import useEventListener from "../../../../hooks/useEventListener";
 
 export interface HeatmapChartProps {
   metrics: MetricResult[];
@@ -31,7 +32,7 @@ export interface HeatmapChartProps {
   yaxis: YaxisState;
   unit?: string;
   setPeriod: ({ from, to }: {from: Date, to: Date}) => void;
-  container: HTMLDivElement | null;
+  layoutSize: ElementSize,
   height?: number;
   onChangeLegend: (val: TooltipHeatmapProps) => void;
 }
@@ -45,7 +46,7 @@ const HeatmapChart: FC<HeatmapChartProps> = ({
   yaxis,
   unit,
   setPeriod,
-  container,
+  layoutSize,
   height,
   onChangeLegend,
 }) => {
@@ -56,7 +57,6 @@ const HeatmapChart: FC<HeatmapChartProps> = ({
   const [xRange, setXRange] = useState({ min: period.start, max: period.end });
   const [uPlotInst, setUPlotInst] = useState<uPlot>();
   const [startTouchDistance, setStartTouchDistance] = useState(0);
-  const layoutSize = useResize(container);
 
   const [tooltipProps, setTooltipProps] = useState<TooltipHeatmapProps | null>(null);
   const [tooltipOffset, setTooltipOffset] = useState({ left: 0, top: 0 });
@@ -116,7 +116,7 @@ const HeatmapChart: FC<HeatmapChartProps> = ({
     });
   };
 
-  const handleKeyDown = (e: KeyboardEvent) => {
+  const handleKeyDown = useCallback((e: KeyboardEvent) => {
     const { target, ctrlKey, metaKey, key } = e;
     const isInput = target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement;
     if (!uPlotInst || isInput) return;
@@ -131,10 +131,10 @@ const HeatmapChart: FC<HeatmapChartProps> = ({
         max: xRange.max - factor
       });
     }
-  };
+  }, [uPlotInst, xRange]);
 
-  const handleClick = () => {
-    if (!tooltipProps) return;
+  const handleClick = useCallback(() => {
+    if (!tooltipProps?.value) return;
     const id = `${tooltipProps?.bucket}_${tooltipProps?.startDate}`;
     const props = {
       id,
@@ -147,13 +147,12 @@ const HeatmapChart: FC<HeatmapChartProps> = ({
       const res = JSON.parse(JSON.stringify(props));
       setStickyToolTips(prev => [...prev, res]);
     }
-  };
+  }, [stickyTooltips, tooltipProps, tooltipOffset, unit]);
 
-  const handleUnStick = (id:string) => {
+  const handleUnStick = (id: string) => {
     setStickyToolTips(prev => prev.filter(t => t.id !== id));
   };
 
-
   const setCursor = (u: uPlot) => {
     const left = u.cursor.left && u.cursor.left > 0 ? u.cursor.left : 0;
     const top = u.cursor.top && u.cursor.top > 0 ? u.cursor.top : 0;
@@ -263,21 +262,14 @@ const HeatmapChart: FC<HeatmapChartProps> = ({
   useEffect(() => {
     setStickyToolTips([]);
     setTooltipProps(null);
-    if (!uPlotRef.current || !layoutSize.width || !layoutSize.height) return;
+    const isValidData = data[0] === null && Array.isArray(data[1]);
+    if (!uPlotRef.current || !layoutSize.width || !layoutSize.height || !isValidData) return;
     const u = new uPlot(options, data, uPlotRef.current);
     setUPlotInst(u);
     setXRange({ min: period.start, max: period.end });
     return u.destroy;
   }, [uPlotRef.current, layoutSize, height, isDarkTheme, data]);
 
-  useEffect(() => {
-    window.addEventListener("keydown", handleKeyDown);
-
-    return () => {
-      window.removeEventListener("keydown", handleKeyDown);
-    };
-  }, [xRange]);
-
   const handleTouchStart = (e: TouchEvent) => {
     if (e.touches.length !== 2) return;
     e.preventDefault();
@@ -287,7 +279,7 @@ const HeatmapChart: FC<HeatmapChartProps> = ({
     setStartTouchDistance(Math.sqrt(dx * dx + dy * dy));
   };
 
-  const handleTouchMove = (e: TouchEvent) => {
+  const handleTouchMove = useCallback((e: TouchEvent) => {
     if (e.touches.length !== 2 || !uPlotInst) return;
     e.preventDefault();
 
@@ -307,34 +299,20 @@ const HeatmapChart: FC<HeatmapChartProps> = ({
       min: min + zoomFactor,
       max: max - zoomFactor
     }));
-  };
-
-  useEffect(() => {
-    window.addEventListener("touchmove", handleTouchMove);
-    window.addEventListener("touchstart", handleTouchStart);
-
-    return () => {
-      window.removeEventListener("touchmove", handleTouchMove);
-      window.removeEventListener("touchstart", handleTouchStart);
-    };
-  }, [uPlotInst, startTouchDistance]);
+  }, [uPlotInst, startTouchDistance, xRange]);
 
   useEffect(() => updateChart(typeChartUpdate.xRange), [xRange]);
   useEffect(() => updateChart(typeChartUpdate.yRange), [yaxis]);
 
-  useEffect(() => {
-    const show = !!tooltipProps?.value;
-    if (show) window.addEventListener("click", handleClick);
-
-    return () => {
-      window.removeEventListener("click", handleClick);
-    };
-  }, [tooltipProps, stickyTooltips]);
-
   useEffect(() => {
     if (tooltipProps) onChangeLegend(tooltipProps);
   }, [tooltipProps]);
 
+  useEventListener("click", handleClick);
+  useEventListener("keydown", handleKeyDown);
+  useEventListener("touchmove", handleTouchMove);
+  useEventListener("touchstart", handleTouchStart);
+
   return (
     <div
       className={classNames({
diff --git a/app/vmui/packages/vmui/src/components/Chart/Line/ChartTooltip/ChartTooltip.tsx b/app/vmui/packages/vmui/src/components/Chart/Line/ChartTooltip/ChartTooltip.tsx
index 23c2a434a3..1c7e21d473 100644
--- a/app/vmui/packages/vmui/src/components/Chart/Line/ChartTooltip/ChartTooltip.tsx
+++ b/app/vmui/packages/vmui/src/components/Chart/Line/ChartTooltip/ChartTooltip.tsx
@@ -1,4 +1,4 @@
-import React, { FC, useEffect, useMemo, useRef, useState } from "preact/compat";
+import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from "preact/compat";
 import uPlot from "uplot";
 import { MetricResult } from "../../../../api/types";
 import { formatPrettyNumber } from "../../../../utils/uplot/helpers";
@@ -12,6 +12,7 @@ import classNames from "classnames";
 import { MouseEvent as ReactMouseEvent } from "react";
 import "./style.scss";
 import { SeriesItem } from "../../../../utils/uplot/series";
+import useEventListener from "../../../../hooks/useEventListener";
 
 export interface ChartTooltipProps {
   id: string,
@@ -47,8 +48,6 @@ const ChartTooltip: FC<ChartTooltipProps> = ({
   const [seriesIdx, setSeriesIdx] = useState(tooltipIdx.seriesIdx);
   const [dataIdx, setDataIdx] = useState(tooltipIdx.dataIdx);
 
-  const targetPortal = useMemo(() => u.root.querySelector(".u-wrap"), [u]);
-
   const value = get(u, ["data", seriesIdx, dataIdx], 0);
   const valueFormat = formatPrettyNumber(value, get(yRange, [0]), get(yRange, [1]));
   const dataTime = u.data[0][dataIdx];
@@ -85,11 +84,11 @@ const ChartTooltip: FC<ChartTooltipProps> = ({
     setPosition({ top: clientY, left: clientX });
   };
 
-  const handleMouseMove = (e: MouseEvent) => {
+  const handleMouseMove = useCallback((e: MouseEvent) => {
     if (!moving) return;
     const { clientX, clientY } = e;
     setPosition({ top: clientY, left: clientX });
-  };
+  }, [moving]);
 
   const handleMouseUp = () => {
     setMoving(false);
@@ -125,19 +124,10 @@ const ChartTooltip: FC<ChartTooltipProps> = ({
     setDataIdx(tooltipIdx.dataIdx);
   }, [tooltipIdx]);
 
-  useEffect(() => {
-    if (moving) {
-      document.addEventListener("mousemove", handleMouseMove);
-      document.addEventListener("mouseup", handleMouseUp);
-    }
+  useEventListener("mousemove", handleMouseMove);
+  useEventListener("mouseup", handleMouseUp);
 
-    return () => {
-      document.removeEventListener("mousemove", handleMouseMove);
-      document.removeEventListener("mouseup", handleMouseUp);
-    };
-  }, [moving]);
-
-  if (!targetPortal || tooltipIdx.seriesIdx < 0 || tooltipIdx.dataIdx < 0) return null;
+  if (tooltipIdx.seriesIdx < 0 || tooltipIdx.dataIdx < 0) return null;
 
   return ReactDOM.createPortal((
     <div
@@ -190,7 +180,7 @@ const ChartTooltip: FC<ChartTooltipProps> = ({
         {fullMetricName}
       </div>
     </div>
-  ), targetPortal);
+  ), u.root);
 };
 
 export default ChartTooltip;
diff --git a/app/vmui/packages/vmui/src/components/Chart/Line/Legend/LegendItem/LegendItem.tsx b/app/vmui/packages/vmui/src/components/Chart/Line/Legend/LegendItem/LegendItem.tsx
index ebc080825d..7893d7ab7d 100644
--- a/app/vmui/packages/vmui/src/components/Chart/Line/Legend/LegendItem/LegendItem.tsx
+++ b/app/vmui/packages/vmui/src/components/Chart/Line/Legend/LegendItem/LegendItem.tsx
@@ -5,6 +5,7 @@ import "./style.scss";
 import classNames from "classnames";
 import Tooltip from "../../../../Main/Tooltip/Tooltip";
 import { getFreeFields } from "./helpers";
+import useCopyToClipboard from "../../../../../hooks/useCopyToClipboard";
 
 interface LegendItemProps {
   legend: LegendItemType;
@@ -13,16 +14,20 @@ interface LegendItemProps {
 }
 
 const LegendItem: FC<LegendItemProps> = ({ legend, onChange, isHeatmap }) => {
+  const copyToClipboard = useCopyToClipboard();
   const [copiedValue, setCopiedValue] = useState("");
+
   const freeFormFields = useMemo(() => {
     const result = getFreeFields(legend);
     return isHeatmap ? result.filter(f => f.key !== "vmrange") : result;
   }, [legend, isHeatmap]);
+
   const calculations = legend.calculations;
   const showCalculations = Object.values(calculations).some(v => v);
 
   const handleClickFreeField = async (val: string, id: string) => {
-    await navigator.clipboard.writeText(val);
+    const copied = await copyToClipboard(val);
+    if (!copied) return;
     setCopiedValue(id);
     setTimeout(() => setCopiedValue(""), 2000);
   };
diff --git a/app/vmui/packages/vmui/src/components/Chart/Line/LineChart/LineChart.tsx b/app/vmui/packages/vmui/src/components/Chart/Line/LineChart/LineChart.tsx
index 7fab79c11e..e47d6cfba0 100644
--- a/app/vmui/packages/vmui/src/components/Chart/Line/LineChart/LineChart.tsx
+++ b/app/vmui/packages/vmui/src/components/Chart/Line/LineChart/LineChart.tsx
@@ -13,7 +13,6 @@ import { getAxes, getMinMaxBuffer } from "../../../../utils/uplot/axes";
 import { MetricResult } from "../../../../api/types";
 import { dateFromSeconds, formatDateForNativeInput, limitsDurations } from "../../../../utils/time";
 import throttle from "lodash.throttle";
-import useResize from "../../../../hooks/useResize";
 import { TimeParams } from "../../../../types";
 import { YaxisState } from "../../../../state/graph/reducer";
 import "uplot/dist/uPlot.min.css";
@@ -23,6 +22,8 @@ import ChartTooltip, { ChartTooltipProps } from "../ChartTooltip/ChartTooltip";
 import dayjs from "dayjs";
 import { useAppState } from "../../../../state/common/StateContext";
 import { SeriesItem } from "../../../../utils/uplot/series";
+import { ElementSize } from "../../../../hooks/useElementSize";
+import useEventListener from "../../../../hooks/useEventListener";
 
 export interface LineChartProps {
   metrics: MetricResult[];
@@ -32,7 +33,7 @@ export interface LineChartProps {
   series: uPlotSeries[];
   unit?: string;
   setPeriod: ({ from, to }: {from: Date, to: Date}) => void;
-  container: HTMLDivElement | null;
+  layoutSize: ElementSize;
   height?: number;
 }
 
@@ -46,7 +47,7 @@ const LineChart: FC<LineChartProps> = ({
   yaxis,
   unit,
   setPeriod,
-  container,
+  layoutSize,
   height
 }) => {
   const { isDarkTheme } = useAppState();
@@ -57,7 +58,6 @@ const LineChart: FC<LineChartProps> = ({
   const [yRange, setYRange] = useState([0, 1]);
   const [uPlotInst, setUPlotInst] = useState<uPlot>();
   const [startTouchDistance, setStartTouchDistance] = useState(0);
-  const layoutSize = useResize(container);
 
   const [showTooltip, setShowTooltip] = useState(false);
   const [tooltipIdx, setTooltipIdx] = useState({ seriesIdx: -1, dataIdx: -1 });
@@ -115,7 +115,7 @@ const LineChart: FC<LineChartProps> = ({
     });
   };
 
-  const handleKeyDown = (e: KeyboardEvent) => {
+  const handleKeyDown = useCallback((e: KeyboardEvent) => {
     const { target, ctrlKey, metaKey, key } = e;
     const isInput = target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement;
     if (!uPlotInst || isInput) return;
@@ -130,9 +130,10 @@ const LineChart: FC<LineChartProps> = ({
         max: xRange.max - factor
       });
     }
-  };
+  }, [uPlotInst, xRange]);
 
-  const handleClick = () => {
+  const handleClick = useCallback(() => {
+    if (!showTooltip) return;
     const id = `${tooltipIdx.seriesIdx}_${tooltipIdx.dataIdx}`;
     const props = {
       id,
@@ -148,7 +149,7 @@ const LineChart: FC<LineChartProps> = ({
       const tooltipProps = JSON.parse(JSON.stringify(props));
       setStickyToolTips(prev => [...prev, tooltipProps]);
     }
-  };
+  }, [metrics, series, stickyTooltips, tooltipIdx, tooltipOffset, showTooltip, unit, yRange]);
 
   const handleUnStick = (id:string) => {
     setStickyToolTips(prev => prev.filter(t => t.id !== id));
@@ -231,14 +232,6 @@ const LineChart: FC<LineChartProps> = ({
     return u.destroy;
   }, [uPlotRef.current, series, layoutSize, height, isDarkTheme]);
 
-  useEffect(() => {
-    window.addEventListener("keydown", handleKeyDown);
-
-    return () => {
-      window.removeEventListener("keydown", handleKeyDown);
-    };
-  }, [xRange]);
-
   const handleTouchStart = (e: TouchEvent) => {
     if (e.touches.length !== 2) return;
     e.preventDefault();
@@ -248,7 +241,7 @@ const LineChart: FC<LineChartProps> = ({
     setStartTouchDistance(Math.sqrt(dx * dx + dy * dy));
   };
 
-  const handleTouchMove = (e: TouchEvent) => {
+  const handleTouchMove = useCallback((e: TouchEvent) => {
     if (e.touches.length !== 2 || !uPlotInst) return;
     e.preventDefault();
 
@@ -268,17 +261,7 @@ const LineChart: FC<LineChartProps> = ({
       min: min + zoomFactor,
       max: max - zoomFactor
     }));
-  };
-
-  useEffect(() => {
-    window.addEventListener("touchmove", handleTouchMove);
-    window.addEventListener("touchstart", handleTouchStart);
-
-    return () => {
-      window.removeEventListener("touchmove", handleTouchMove);
-      window.removeEventListener("touchstart", handleTouchStart);
-    };
-  }, [uPlotInst, startTouchDistance]);
+  }, [uPlotInst, startTouchDistance, xRange]);
 
   useEffect(() => updateChart(typeChartUpdate.xRange), [xRange]);
   useEffect(() => updateChart(typeChartUpdate.yRange), [yaxis]);
@@ -286,14 +269,13 @@ const LineChart: FC<LineChartProps> = ({
   useEffect(() => {
     const show = tooltipIdx.dataIdx !== -1 && tooltipIdx.seriesIdx !== -1;
     setShowTooltip(show);
-
-    if (show) window.addEventListener("click", handleClick);
-
-    return () => {
-      window.removeEventListener("click", handleClick);
-    };
   }, [tooltipIdx, stickyTooltips]);
 
+  useEventListener("click", handleClick);
+  useEventListener("keydown", handleKeyDown);
+  useEventListener("touchmove", handleTouchMove);
+  useEventListener("touchstart", handleTouchStart);
+
   return (
     <div
       className={classNames({
diff --git a/app/vmui/packages/vmui/src/components/Chart/SimpleBarChart/style.scss b/app/vmui/packages/vmui/src/components/Chart/SimpleBarChart/style.scss
index a274c1cfe8..135feac615 100644
--- a/app/vmui/packages/vmui/src/components/Chart/SimpleBarChart/style.scss
+++ b/app/vmui/packages/vmui/src/components/Chart/SimpleBarChart/style.scss
@@ -7,13 +7,13 @@ $color-bar-highest: #F79420;
   display: grid;
   grid-template-columns: auto 1fr;
   height: 100%;
-  padding-bottom: #{$font-size-small/2};
+  padding-bottom: calc($font-size-small/2);
   overflow: hidden;
 
   &-y-axis {
     position: relative;
     display: grid;
-    transform: translateY(#{$font-size-small});
+    transform: translateY($font-size-small);
 
     &__tick {
       position: relative;
diff --git a/app/vmui/packages/vmui/src/components/Configurators/AdditionalSettings/AdditionalSettings.tsx b/app/vmui/packages/vmui/src/components/Configurators/AdditionalSettings/AdditionalSettings.tsx
index 1ea20aeaac..f4b7b66947 100644
--- a/app/vmui/packages/vmui/src/components/Configurators/AdditionalSettings/AdditionalSettings.tsx
+++ b/app/vmui/packages/vmui/src/components/Configurators/AdditionalSettings/AdditionalSettings.tsx
@@ -1,4 +1,4 @@
-import React, { FC, useRef, useState } from "preact/compat";
+import React, { FC, useRef } from "preact/compat";
 import { useCustomPanelDispatch, useCustomPanelState } from "../../../state/customPanel/CustomPanelStateContext";
 import { useQueryDispatch, useQueryState } from "../../../state/query/QueryStateContext";
 import "./style.scss";
@@ -8,6 +8,7 @@ import Popper from "../../Main/Popper/Popper";
 import { TuneIcon } from "../../Main/Icons";
 import Button from "../../Main/Button/Button";
 import classNames from "classnames";
+import useBoolean from "../../../hooks/useBoolean";
 
 const AdditionalSettingsControls: FC<{isMobile?: boolean}> = ({ isMobile }) => {
   const { autocomplete } = useQueryState();
@@ -59,16 +60,13 @@ const AdditionalSettingsControls: FC<{isMobile?: boolean}> = ({ isMobile }) => {
 
 const AdditionalSettings: FC = () => {
   const { isMobile } = useDeviceDetect();
-  const [openList, setOpenList] = useState(false);
   const targetRef = useRef<HTMLDivElement>(null);
 
-  const handleToggleList = () => {
-    setOpenList(prev => !prev);
-  };
-
-  const handleCloseList = () => {
-    setOpenList(false);
-  };
+  const {
+    value: openList,
+    toggle: handleToggleList,
+    setFalse: handleCloseList,
+  } = useBoolean(false);
 
   if (isMobile) {
     return (
diff --git a/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/GlobalSettings.tsx b/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/GlobalSettings.tsx
index 4751a112eb..420a048bee 100644
--- a/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/GlobalSettings.tsx
+++ b/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/GlobalSettings.tsx
@@ -15,6 +15,7 @@ import Timezones from "./Timezones/Timezones";
 import { useTimeDispatch, useTimeState } from "../../../state/time/TimeStateContext";
 import ThemeControl from "../ThemeControl/ThemeControl";
 import useDeviceDetect from "../../../hooks/useDeviceDetect";
+import useBoolean from "../../../hooks/useBoolean";
 
 const title = "Settings";
 
@@ -40,15 +41,14 @@ const GlobalSettings: FC = () => {
     setTimezone(stateTimezone);
   };
 
-  const [open, setOpen] = useState(false);
-  const handleOpen = () => setOpen(true);
-  const handleClose = () => {
-    setOpen(false);
-    setDefaultsValues();
-  };
+  const {
+    value: open,
+    setTrue: handleOpen,
+    setFalse: handleClose,
+  } = useBoolean(false);
 
-  const handleCloseForce = () => {
-    setOpen(false);
+  const handleCloseAndReset = () => {
+    handleClose();
     setDefaultsValues();
   };
 
@@ -60,7 +60,7 @@ const GlobalSettings: FC = () => {
     dispatch({ type: "SET_SERVER", payload: serverUrl });
     timeDispatch({ type: "SET_TIMEZONE", payload: timezone });
     customPanelDispatch({ type: "SET_SERIES_LIMITS", payload: limits });
-    setOpen(false);
+    handleClose();
   };
 
   useEffect(() => {
@@ -97,7 +97,7 @@ const GlobalSettings: FC = () => {
     {open && (
       <Modal
         title={title}
-        onClose={handleClose}
+        onClose={handleCloseAndReset}
       >
         <div
           className={classNames({
@@ -140,7 +140,7 @@ const GlobalSettings: FC = () => {
             <Button
               color="error"
               variant="outlined"
-              onClick={handleCloseForce}
+              onClick={handleCloseAndReset}
             >
               Cancel
             </Button>
diff --git a/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/TenantsConfiguration/TenantsConfiguration.tsx b/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/TenantsConfiguration/TenantsConfiguration.tsx
index 5f32aa2d31..dd0dfd6c42 100644
--- a/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/TenantsConfiguration/TenantsConfiguration.tsx
+++ b/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/TenantsConfiguration/TenantsConfiguration.tsx
@@ -11,6 +11,7 @@ import Tooltip from "../../../Main/Tooltip/Tooltip";
 import useDeviceDetect from "../../../../hooks/useDeviceDetect";
 import TextField from "../../../Main/TextField/TextField";
 import { getTenantIdFromUrl, replaceTenantId } from "../../../../utils/tenants";
+import useBoolean from "../../../../hooks/useBoolean";
 
 const TenantsConfiguration: FC<{accountIds: string[]}> = ({ accountIds }) => {
   const appModeEnable = getAppModeEnable();
@@ -21,9 +22,14 @@ const TenantsConfiguration: FC<{accountIds: string[]}> = ({ accountIds }) => {
   const timeDispatch = useTimeDispatch();
 
   const [search, setSearch] = useState("");
-  const [openOptions, setOpenOptions] = useState(false);
   const optionsButtonRef = useRef<HTMLDivElement>(null);
 
+  const {
+    value: openOptions,
+    toggle: toggleOpenOptions,
+    setFalse: handleCloseOptions,
+  } = useBoolean(false);
+
   const accountIdsFiltered = useMemo(() => {
     if (!search) return accountIds;
     try {
@@ -37,14 +43,6 @@ const TenantsConfiguration: FC<{accountIds: string[]}> = ({ accountIds }) => {
 
   const showTenantSelector = useMemo(() => accountIds.length > 1, [accountIds]);
 
-  const toggleOpenOptions = () => {
-    setOpenOptions(prev => !prev);
-  };
-
-  const handleCloseOptions = () => {
-    setOpenOptions(false);
-  };
-
   const createHandlerChange = (value: string) => () => {
     const tenant = value;
     dispatch({ type: "SET_TENANT_ID", payload: tenant });
diff --git a/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/Timezones/Timezones.tsx b/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/Timezones/Timezones.tsx
index 1af4e1c980..6bb0372ea6 100644
--- a/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/Timezones/Timezones.tsx
+++ b/app/vmui/packages/vmui/src/components/Configurators/GlobalSettings/Timezones/Timezones.tsx
@@ -9,6 +9,7 @@ import TextField from "../../../Main/TextField/TextField";
 import { Timezone } from "../../../../types";
 import "./style.scss";
 import useDeviceDetect from "../../../../hooks/useDeviceDetect";
+import useBoolean from "../../../../hooks/useBoolean";
 
 interface TimezonesProps {
   timezoneState: string
@@ -19,10 +20,15 @@ const Timezones: FC<TimezonesProps> = ({ timezoneState, onChange }) => {
   const { isMobile } = useDeviceDetect();
   const timezones = getTimezoneList();
 
-  const [openList, setOpenList] = useState(false);
   const [search, setSearch] = useState("");
   const targetRef = useRef<HTMLDivElement>(null);
 
+  const {
+    value: openList,
+    toggle: toggleOpenList,
+    setFalse: handleCloseList,
+  } = useBoolean(false);
+
   const searchTimezones = useMemo(() => {
     if (!search) return timezones;
     try {
@@ -44,14 +50,6 @@ const Timezones: FC<TimezonesProps> = ({ timezoneState, onChange }) => {
     utc: getUTCByTimezone(timezoneState)
   }), [timezoneState]);
 
-  const toggleOpenList = () => {
-    setOpenList(prev => !prev);
-  };
-
-  const handleCloseList = () => {
-    setOpenList(false);
-  };
-
   const handleChangeSearch = (val: string) => {
     setSearch(val);
   };
diff --git a/app/vmui/packages/vmui/src/components/Configurators/GraphSettings/GraphSettings.tsx b/app/vmui/packages/vmui/src/components/Configurators/GraphSettings/GraphSettings.tsx
index d46de83fda..129d28bffb 100644
--- a/app/vmui/packages/vmui/src/components/Configurators/GraphSettings/GraphSettings.tsx
+++ b/app/vmui/packages/vmui/src/components/Configurators/GraphSettings/GraphSettings.tsx
@@ -1,4 +1,4 @@
-import React, { FC, useRef, useState } from "preact/compat";
+import React, { FC, useRef } from "preact/compat";
 import AxesLimitsConfigurator from "./AxesLimitsConfigurator/AxesLimitsConfigurator";
 import { AxisRange, YaxisState } from "../../../state/graph/reducer";
 import { SettingsIcon } from "../../Main/Icons";
@@ -6,6 +6,7 @@ import Button from "../../Main/Button/Button";
 import Popper from "../../Main/Popper/Popper";
 import "./style.scss";
 import Tooltip from "../../Main/Tooltip/Tooltip";
+import useBoolean from "../../../hooks/useBoolean";
 
 const title = "Axes settings";
 
@@ -17,16 +18,13 @@ interface GraphSettingsProps {
 
 const GraphSettings: FC<GraphSettingsProps> = ({ yaxis, setYaxisLimits, toggleEnableLimits }) => {
   const popperRef = useRef<HTMLDivElement>(null);
-  const [openPopper, setOpenPopper] = useState(false);
   const buttonRef = useRef<HTMLDivElement>(null);
 
-  const toggleOpen = () => {
-    setOpenPopper(prev => !prev);
-  };
-
-  const handleClose = () => {
-    setOpenPopper(false);
-  };
+  const {
+    value: openPopper,
+    toggle: toggleOpen,
+    setFalse: handleClose,
+  } = useBoolean(false);
 
   return (
     <div className="vm-graph-settings">
diff --git a/app/vmui/packages/vmui/src/components/Configurators/StepConfigurator/StepConfigurator.tsx b/app/vmui/packages/vmui/src/components/Configurators/StepConfigurator/StepConfigurator.tsx
index 5372568f28..42b1a16402 100644
--- a/app/vmui/packages/vmui/src/components/Configurators/StepConfigurator/StepConfigurator.tsx
+++ b/app/vmui/packages/vmui/src/components/Configurators/StepConfigurator/StepConfigurator.tsx
@@ -13,6 +13,7 @@ import { getAppModeEnable } from "../../../utils/app-mode";
 import Popper from "../../Main/Popper/Popper";
 import useDeviceDetect from "../../../hooks/useDeviceDetect";
 import classNames from "classnames";
+import useBoolean from "../../../hooks/useBoolean";
 
 const StepConfigurator: FC = () => {
   const appModeEnable = getAppModeEnable();
@@ -28,20 +29,17 @@ const StepConfigurator: FC = () => {
     return getStepFromDuration(end - start, isHistogram);
   }, [step, isHistogram]);
 
-  const [openOptions, setOpenOptions] = useState(false);
   const [customStep, setCustomStep] = useState(value || defaultStep);
   const [error, setError] = useState("");
 
+  const {
+    value: openOptions,
+    toggle: toggleOpenOptions,
+    setFalse: handleCloseOptions,
+  } = useBoolean(false);
+
   const buttonRef = useRef<HTMLDivElement>(null);
 
-  const toggleOpenOptions = () => {
-    setOpenOptions(prev => !prev);
-  };
-
-  const handleCloseOptions = () => {
-    setOpenOptions(false);
-  };
-
   const handleApply = (value?: string) => {
     const step = value || customStep || defaultStep || "1s";
     const durations = step.match(/[a-zA-Z]+/g) || [];
diff --git a/app/vmui/packages/vmui/src/components/Configurators/TimeRangeSettings/ExecutionControls/ExecutionControls.tsx b/app/vmui/packages/vmui/src/components/Configurators/TimeRangeSettings/ExecutionControls/ExecutionControls.tsx
index 168c1dfd7c..87b5743003 100644
--- a/app/vmui/packages/vmui/src/components/Configurators/TimeRangeSettings/ExecutionControls/ExecutionControls.tsx
+++ b/app/vmui/packages/vmui/src/components/Configurators/TimeRangeSettings/ExecutionControls/ExecutionControls.tsx
@@ -8,6 +8,7 @@ import "./style.scss";
 import classNames from "classnames";
 import Tooltip from "../../../Main/Tooltip/Tooltip";
 import useDeviceDetect from "../../../../hooks/useDeviceDetect";
+import useBoolean from "../../../../hooks/useBoolean";
 
 interface AutoRefreshOption {
   seconds: number
@@ -38,12 +39,19 @@ export const ExecutionControls: FC = () => {
 
   const [selectedDelay, setSelectedDelay] = useState<AutoRefreshOption>(delayOptions[0]);
 
+  const {
+    value: openOptions,
+    toggle: toggleOpenOptions,
+    setFalse: handleCloseOptions,
+  } = useBoolean(false);
+  const optionsButtonRef = useRef<HTMLDivElement>(null);
+
   const handleChange = (d: AutoRefreshOption) => {
     if ((autoRefresh && !d.seconds) || (!autoRefresh && d.seconds)) {
       setAutoRefresh(prev => !prev);
     }
     setSelectedDelay(d);
-    setOpenOptions(false);
+    handleCloseOptions();
   };
 
   const handleUpdate = () => {
@@ -65,17 +73,6 @@ export const ExecutionControls: FC = () => {
     };
   }, [selectedDelay, autoRefresh]);
 
-  const [openOptions, setOpenOptions] = useState(false);
-  const optionsButtonRef = useRef<HTMLDivElement>(null);
-
-  const toggleOpenOptions = () => {
-    setOpenOptions(prev => !prev);
-  };
-
-  const handleCloseOptions = () => {
-    setOpenOptions(false);
-  };
-
   const createHandlerChange = (d: AutoRefreshOption) => () => {
     handleChange(d);
   };
diff --git a/app/vmui/packages/vmui/src/components/Configurators/TimeRangeSettings/TimeSelector/TimeSelector.tsx b/app/vmui/packages/vmui/src/components/Configurators/TimeRangeSettings/TimeSelector/TimeSelector.tsx
index 368545f89d..1909f27d10 100644
--- a/app/vmui/packages/vmui/src/components/Configurators/TimeRangeSettings/TimeSelector/TimeSelector.tsx
+++ b/app/vmui/packages/vmui/src/components/Configurators/TimeRangeSettings/TimeSelector/TimeSelector.tsx
@@ -9,20 +9,21 @@ import Button from "../../../Main/Button/Button";
 import Popper from "../../../Main/Popper/Popper";
 import Tooltip from "../../../Main/Tooltip/Tooltip";
 import { DATE_TIME_FORMAT } from "../../../../constants/date";
-import useResize from "../../../../hooks/useResize";
 import "./style.scss";
 import useClickOutside from "../../../../hooks/useClickOutside";
 import classNames from "classnames";
 import { useAppState } from "../../../../state/common/StateContext";
 import useDeviceDetect from "../../../../hooks/useDeviceDetect";
 import DateTimeInput from "../../../Main/DatePicker/DateTimeInput/DateTimeInput";
+import useBoolean from "../../../../hooks/useBoolean";
+import useWindowSize from "../../../../hooks/useWindowSize";
 
 export const TimeSelector: FC = () => {
   const { isMobile } = useDeviceDetect();
   const { isDarkTheme } = useAppState();
   const wrapperRef = useRef<HTMLDivElement>(null);
-  const documentSize = useResize(document.body);
-  const displayFullDate = useMemo(() => documentSize.width > 1280, [documentSize]);
+  const documentSize = useWindowSize();
+  const displayFullDate = useMemo(() => documentSize.width > 1120, [documentSize]);
 
   const [until, setUntil] = useState<string>();
   const [from, setFrom] = useState<string>();
@@ -31,6 +32,12 @@ export const TimeSelector: FC = () => {
   const dispatch = useTimeDispatch();
   const appModeEnable = getAppModeEnable();
 
+  const {
+    value: openOptions,
+    toggle: toggleOpenOptions,
+    setFalse: handleCloseOptions,
+  } = useBoolean(false);
+
   const activeTimezone = useMemo(() => ({
     region: timezone,
     utc: getUTCByTimezone(timezone)
@@ -46,7 +53,7 @@ export const TimeSelector: FC = () => {
 
   const setDuration = ({ duration, until, id }: {duration: string, until: Date, id: string}) => {
     dispatch({ type: "SET_RELATIVE_TIME", payload: { duration, until, id } });
-    setOpenOptions(false);
+    handleCloseOptions();
   };
 
   const formatRange = useMemo(() => {
@@ -62,7 +69,6 @@ export const TimeSelector: FC = () => {
 
   const fromPickerRef = useRef<HTMLDivElement>(null);
   const untilPickerRef = useRef<HTMLDivElement>(null);
-  const [openOptions, setOpenOptions] = useState(false);
   const buttonRef = useRef<HTMLDivElement>(null);
 
   const setTimeAndClosePicker = () => {
@@ -72,7 +78,7 @@ export const TimeSelector: FC = () => {
         to: dayjs.tz(until).toDate()
       } });
     }
-    setOpenOptions(false);
+    handleCloseOptions();
   };
 
   const onSwitchToNow = () => dispatch({ type: "RUN_QUERY_TO_NOW" });
@@ -80,15 +86,7 @@ export const TimeSelector: FC = () => {
   const onCancelClick = () => {
     setUntil(formatDateForNativeInput(dateFromSeconds(end)));
     setFrom(formatDateForNativeInput(dateFromSeconds(start)));
-    setOpenOptions(false);
-  };
-
-  const toggleOpenOptions = () => {
-    setOpenOptions(prev => !prev);
-  };
-
-  const handleCloseOptions = () => {
-    setOpenOptions(false);
+    handleCloseOptions();
   };
 
   useEffect(() => {
diff --git a/app/vmui/packages/vmui/src/components/ExploreMetrics/ExploreMetricGraph/ExploreMetricItemGraph.tsx b/app/vmui/packages/vmui/src/components/ExploreMetrics/ExploreMetricGraph/ExploreMetricItemGraph.tsx
index 0b6279f78e..936504372a 100644
--- a/app/vmui/packages/vmui/src/components/ExploreMetrics/ExploreMetricGraph/ExploreMetricItemGraph.tsx
+++ b/app/vmui/packages/vmui/src/components/ExploreMetrics/ExploreMetricGraph/ExploreMetricItemGraph.tsx
@@ -11,6 +11,7 @@ import "./style.scss";
 import classNames from "classnames";
 import useDeviceDetect from "../../../hooks/useDeviceDetect";
 import { getDurationFromMilliseconds, getSecondsFromDuration, getStepFromDuration } from "../../../utils/time";
+import useBoolean from "../../../hooks/useBoolean";
 
 interface ExploreMetricItemGraphProps {
   name: string,
@@ -41,7 +42,10 @@ const ExploreMetricItem: FC<ExploreMetricItemGraphProps> = ({
   const [isHeatmap, setIsHeatmap] = useState(false);
   const step = isHeatmap && customStep === defaultStep ? heatmapStep : customStep;
 
-  const [showAllSeries, setShowAllSeries] = useState(false);
+  const {
+    value: showAllSeries,
+    setTrue: handleShowAll,
+  } = useBoolean(false);
 
   const query = useMemo(() => {
     const params = Object.entries({ job, instance })
@@ -81,10 +85,6 @@ with (q = ${queryBase}) (
     timeDispatch({ type: "SET_PERIOD", payload: { from, to } });
   };
 
-  const handleShowAll = () => {
-    setShowAllSeries(true);
-  };
-
   useEffect(() => {
     setIsHeatmap(isHistogram);
   }, [isHistogram]);
diff --git a/app/vmui/packages/vmui/src/components/ExploreMetrics/ExploreMetricItem/ExploreMetricItem.tsx b/app/vmui/packages/vmui/src/components/ExploreMetrics/ExploreMetricItem/ExploreMetricItem.tsx
index 4f07c68d1e..bd8e48c0ca 100644
--- a/app/vmui/packages/vmui/src/components/ExploreMetrics/ExploreMetricItem/ExploreMetricItem.tsx
+++ b/app/vmui/packages/vmui/src/components/ExploreMetrics/ExploreMetricItem/ExploreMetricItem.tsx
@@ -2,8 +2,8 @@ import React, { FC, useEffect, useMemo, useState } from "preact/compat";
 import ExploreMetricItemGraph from "../ExploreMetricGraph/ExploreMetricItemGraph";
 import ExploreMetricItemHeader from "../ExploreMetricItemHeader/ExploreMetricItemHeader";
 import "./style.scss";
-import useResize from "../../../hooks/useResize";
 import { GraphSize } from "../../../types";
+import useWindowSize from "../../../hooks/useWindowSize";
 
 interface ExploreMetricItemProps {
   name: string
@@ -32,7 +32,7 @@ const ExploreMetricItem: FC<ExploreMetricItemProps> = ({
 
   const [rateEnabled, setRateEnabled] = useState(isCounter);
 
-  const windowSize = useResize(document.body);
+  const windowSize = useWindowSize();
   const graphHeight = useMemo(size.height, [size, windowSize]);
 
   useEffect(() => {
diff --git a/app/vmui/packages/vmui/src/components/ExploreMetrics/ExploreMetricItemHeader/ExploreMetricItemHeader.tsx b/app/vmui/packages/vmui/src/components/ExploreMetrics/ExploreMetricItemHeader/ExploreMetricItemHeader.tsx
index d135266c23..1dc00078d6 100644
--- a/app/vmui/packages/vmui/src/components/ExploreMetrics/ExploreMetricItemHeader/ExploreMetricItemHeader.tsx
+++ b/app/vmui/packages/vmui/src/components/ExploreMetrics/ExploreMetricItemHeader/ExploreMetricItemHeader.tsx
@@ -1,4 +1,4 @@
-import React, { FC, useState } from "preact/compat";
+import React, { FC } from "preact/compat";
 import "./style.scss";
 import Switch from "../../Main/Switch/Switch";
 import Tooltip from "../../Main/Tooltip/Tooltip";
@@ -6,6 +6,7 @@ import Button from "../../Main/Button/Button";
 import { ArrowDownIcon, CloseIcon, MinusIcon, MoreIcon, PlusIcon } from "../../Main/Icons";
 import useDeviceDetect from "../../../hooks/useDeviceDetect";
 import Modal from "../../Main/Modal/Modal";
+import useBoolean from "../../../hooks/useBoolean";
 
 interface ExploreMetricItemControlsProps {
   name: string
@@ -30,7 +31,12 @@ const ExploreMetricItemHeader: FC<ExploreMetricItemControlsProps> = ({
   onChangeOrder,
 }) => {
   const { isMobile } = useDeviceDetect();
-  const [openOptions, setOpenOptions] = useState(false);
+
+  const {
+    value: openOptions,
+    setTrue: handleOpenOptions,
+    setFalse: handleCloseOptions,
+  } = useBoolean(false);
 
   const handleClickRemove = () => {
     onRemoveItem(name);
@@ -44,14 +50,6 @@ const ExploreMetricItemHeader: FC<ExploreMetricItemControlsProps> = ({
     onChangeOrder(name, index, index - 1);
   };
 
-  const handleOpenOptions = () => {
-    setOpenOptions(true);
-  };
-
-  const handleCloseOptions = () => {
-    setOpenOptions(false);
-  };
-
   if (isMobile) {
     return (
       <div className="vm-explore-metrics-item-header vm-explore-metrics-item-header_mobile">
diff --git a/app/vmui/packages/vmui/src/components/Layout/Header/Header.tsx b/app/vmui/packages/vmui/src/components/Layout/Header/Header.tsx
index b64be06a09..5b826bc57c 100644
--- a/app/vmui/packages/vmui/src/components/Layout/Header/Header.tsx
+++ b/app/vmui/packages/vmui/src/components/Layout/Header/Header.tsx
@@ -8,15 +8,15 @@ import "./style.scss";
 import classNames from "classnames";
 import { useAppState } from "../../../state/common/StateContext";
 import HeaderNav from "./HeaderNav/HeaderNav";
-import useResize from "../../../hooks/useResize";
 import SidebarHeader from "./SidebarNav/SidebarHeader";
 import HeaderControls from "./HeaderControls/HeaderControls";
 import useDeviceDetect from "../../../hooks/useDeviceDetect";
+import useWindowSize from "../../../hooks/useWindowSize";
 
 const Header: FC = () => {
   const { isMobile } = useDeviceDetect();
 
-  const windowSize = useResize(document.body);
+  const windowSize = useWindowSize();
   const displaySidebar = useMemo(() => window.innerWidth < 1000, [windowSize]);
 
   const { isDarkTheme } = useAppState();
diff --git a/app/vmui/packages/vmui/src/components/Layout/Header/HeaderControls/HeaderControls.tsx b/app/vmui/packages/vmui/src/components/Layout/Header/HeaderControls/HeaderControls.tsx
index 51f746a637..c8dc27f865 100644
--- a/app/vmui/packages/vmui/src/components/Layout/Header/HeaderControls/HeaderControls.tsx
+++ b/app/vmui/packages/vmui/src/components/Layout/Header/HeaderControls/HeaderControls.tsx
@@ -1,4 +1,4 @@
-import React, { FC, useMemo, useState } from "preact/compat";
+import React, { FC, useMemo } from "preact/compat";
 import { RouterOptions, routerOptions, RouterOptionsHeader } from "../../../../router";
 import TenantsConfiguration from "../../../Configurators/GlobalSettings/TenantsConfiguration/TenantsConfiguration";
 import StepConfigurator from "../../../Configurators/StepConfigurator/StepConfigurator";
@@ -15,6 +15,7 @@ import "./style.scss";
 import classNames from "classnames";
 import { getAppModeEnable } from "../../../../utils/app-mode";
 import Modal from "../../../Main/Modal/Modal";
+import useBoolean from "../../../../hooks/useBoolean";
 
 interface HeaderControlsProp {
   displaySidebar: boolean
@@ -50,22 +51,19 @@ const Controls: FC<HeaderControlsProp> = ({
 
 const HeaderControls: FC<HeaderControlsProp> = (props) => {
   const appModeEnable = getAppModeEnable();
-  const [openList, setOpenList] = useState(false);
   const { pathname } = useLocation();
   const { accountIds } = useFetchAccountIds();
 
+  const {
+    value: openList,
+    toggle: handleToggleList,
+    setFalse: handleCloseList,
+  } = useBoolean(false);
+
   const headerSetup = useMemo(() => {
     return ((routerOptions[pathname] || {}) as RouterOptions).header || {};
   }, [pathname]);
 
-  const handleToggleList = () => {
-    setOpenList(prev => !prev);
-  };
-
-  const handleCloseList = () => {
-    setOpenList(false);
-  };
-
   if (props.isMobile) {
     return (
       <>
diff --git a/app/vmui/packages/vmui/src/components/Layout/Header/HeaderNav/NavSubItem.tsx b/app/vmui/packages/vmui/src/components/Layout/Header/HeaderNav/NavSubItem.tsx
index 19928b3fb5..462bb71dd9 100644
--- a/app/vmui/packages/vmui/src/components/Layout/Header/HeaderNav/NavSubItem.tsx
+++ b/app/vmui/packages/vmui/src/components/Layout/Header/HeaderNav/NavSubItem.tsx
@@ -5,6 +5,7 @@ import { ArrowDropDownIcon } from "../../../Main/Icons";
 import Popper from "../../../Main/Popper/Popper";
 import NavItem from "./NavItem";
 import { useEffect } from "react";
+import useBoolean from "../../../../hooks/useBoolean";
 
 interface NavItemProps {
   activeMenu: string,
@@ -25,17 +26,18 @@ const NavSubItem: FC<NavItemProps> = ({
 }) => {
   const { pathname } = useLocation();
 
-  const [openSubmenu, setOpenSubmenu] = useState(false);
   const [menuTimeout, setMenuTimeout] = useState<NodeJS.Timeout | null>(null);
   const buttonRef = useRef<HTMLDivElement>(null);
 
-  const handleOpenSubmenu = () => {
-    setOpenSubmenu(true);
-    if (menuTimeout) clearTimeout(menuTimeout);
-  };
+  const {
+    value: openSubmenu,
+    setFalse: handleCloseSubmenu,
+    setTrue: setOpenSubmenu,
+  } = useBoolean(false);
 
-  const handleCloseSubmenu = () => {
-    setOpenSubmenu(false);
+  const handleOpenSubmenu = () => {
+    setOpenSubmenu();
+    if (menuTimeout) clearTimeout(menuTimeout);
   };
 
   const handleMouseLeave = () => {
diff --git a/app/vmui/packages/vmui/src/components/Layout/Header/SidebarNav/SidebarHeader.tsx b/app/vmui/packages/vmui/src/components/Layout/Header/SidebarNav/SidebarHeader.tsx
index fc845ca033..92fa9eb848 100644
--- a/app/vmui/packages/vmui/src/components/Layout/Header/SidebarNav/SidebarHeader.tsx
+++ b/app/vmui/packages/vmui/src/components/Layout/Header/SidebarNav/SidebarHeader.tsx
@@ -1,4 +1,4 @@
-import React, { FC, useEffect, useRef, useState } from "preact/compat";
+import React, { FC, useEffect, useRef } from "preact/compat";
 import { useLocation } from "react-router-dom";
 import ShortcutKeys from "../../../Main/ShortcutKeys/ShortcutKeys";
 import classNames from "classnames";
@@ -7,6 +7,7 @@ import useClickOutside from "../../../../hooks/useClickOutside";
 import MenuBurger from "../../../Main/MenuBurger/MenuBurger";
 import useDeviceDetect from "../../../../hooks/useDeviceDetect";
 import "./style.scss";
+import useBoolean from "../../../../hooks/useBoolean";
 
 interface SidebarHeaderProps {
   background: string
@@ -21,15 +22,12 @@ const SidebarHeader: FC<SidebarHeaderProps> = ({
   const { isMobile } = useDeviceDetect();
 
   const sidebarRef = useRef<HTMLDivElement>(null);
-  const [openMenu, setOpenMenu] = useState(false);
 
-  const handleToggleMenu = () => {
-    setOpenMenu(prev => !prev);
-  };
-
-  const handleCloseMenu = () => {
-    setOpenMenu(false);
-  };
+  const {
+    value: openMenu,
+    toggle: handleToggleMenu,
+    setFalse: handleCloseMenu,
+  } = useBoolean(false);
 
   useEffect(handleCloseMenu, [pathname]);
 
diff --git a/app/vmui/packages/vmui/src/components/Layout/Layout.tsx b/app/vmui/packages/vmui/src/components/Layout/Layout.tsx
index 7a34cac181..db5e3fd1af 100644
--- a/app/vmui/packages/vmui/src/components/Layout/Layout.tsx
+++ b/app/vmui/packages/vmui/src/components/Layout/Layout.tsx
@@ -26,16 +26,15 @@ const Layout: FC = () => {
 
   // for support old links with search params
   const redirectSearchToHashParams = () => {
-    const { search } = window.location;
+    const { search, href } = window.location;
     if (search) {
       const query = qs.parse(search, { ignoreQueryPrefix: true });
-      Object.entries(query).forEach(([key, value]) => {
-        searchParams.set(key, value as string);
-        setSearchParams(searchParams);
-      });
+      Object.entries(query).forEach(([key, value]) => searchParams.set(key, value as string));
+      setSearchParams(searchParams);
       window.location.search = "";
     }
-    window.location.replace(window.location.href.replace(/\/\?#\//, "/#/"));
+    const newHref = href.replace(/\/\?#\//, "/#/");
+    if (newHref !== href) window.location.replace(newHref);
   };
 
   useEffect(setDocumentTitle, [pathname]);
diff --git a/app/vmui/packages/vmui/src/components/Main/Autocomplete/Autocomplete.tsx b/app/vmui/packages/vmui/src/components/Main/Autocomplete/Autocomplete.tsx
index e65a51beab..a53feacf1a 100644
--- a/app/vmui/packages/vmui/src/components/Main/Autocomplete/Autocomplete.tsx
+++ b/app/vmui/packages/vmui/src/components/Main/Autocomplete/Autocomplete.tsx
@@ -1,9 +1,11 @@
-import React, { FC, Ref, useEffect, useMemo, useRef, useState } from "preact/compat";
+import React, { FC, Ref, useCallback, useEffect, useMemo, useRef, useState } from "preact/compat";
 import classNames from "classnames";
 import Popper from "../Popper/Popper";
 import "./style.scss";
 import { DoneIcon } from "../Icons";
 import useDeviceDetect from "../../../hooks/useDeviceDetect";
+import useBoolean from "../../../hooks/useBoolean";
+import useEventListener from "../../../hooks/useEventListener";
 
 interface AutocompleteProps {
   value: string
@@ -39,9 +41,14 @@ const Autocomplete: FC<AutocompleteProps> = ({
   const { isMobile } = useDeviceDetect();
   const wrapperEl = useRef<HTMLDivElement>(null);
 
-  const [openAutocomplete, setOpenAutocomplete] = useState(false);
   const [focusOption, setFocusOption] = useState(-1);
 
+  const {
+    value: openAutocomplete,
+    setValue: setOpenAutocomplete,
+    setFalse: handleCloseAutocomplete,
+  } = useBoolean(false);
+
   const foundOptions = useMemo(() => {
     if (!openAutocomplete) return [];
     try {
@@ -57,10 +64,6 @@ const Autocomplete: FC<AutocompleteProps> = ({
     return noOptionsText && !foundOptions.length;
   }, [noOptionsText,foundOptions]);
 
-  const handleCloseAutocomplete = () => {
-    setOpenAutocomplete(false);
-  };
-
   const createHandlerSelect = (item: string) => () => {
     if (disabled) return;
     onSelect(item);
@@ -73,7 +76,7 @@ const Autocomplete: FC<AutocompleteProps> = ({
     if (target?.scrollIntoView) target.scrollIntoView({ block: "center" });
   };
 
-  const handleKeyDown = (e: KeyboardEvent) => {
+  const handleKeyDown = useCallback((e: KeyboardEvent) => {
     const { key, ctrlKey, metaKey, shiftKey } = e;
     const modifiers = ctrlKey || metaKey || shiftKey;
     const hasOptions = foundOptions.length;
@@ -98,22 +101,16 @@ const Autocomplete: FC<AutocompleteProps> = ({
     if (key === "Escape") {
       handleCloseAutocomplete();
     }
-  };
+  }, [focusOption, foundOptions, handleCloseAutocomplete, onSelect, selected]);
 
   useEffect(() => {
     const words = (value.match(/[a-zA-Z_:.][a-zA-Z0-9_:.]*/gm) || []).length;
     setOpenAutocomplete(value.length > minLength && words <= maxWords);
   }, [value]);
 
-  useEffect(() => {
-    scrollToValue();
+  useEventListener("keydown", handleKeyDown);
 
-    window.addEventListener("keydown", handleKeyDown);
-
-    return () => {
-      window.removeEventListener("keydown", handleKeyDown);
-    };
-  }, [focusOption, foundOptions]);
+  useEffect(scrollToValue, [focusOption, foundOptions]);
 
   useEffect(() => {
     setFocusOption(-1);
diff --git a/app/vmui/packages/vmui/src/components/Main/DatePicker/DatePicker.tsx b/app/vmui/packages/vmui/src/components/Main/DatePicker/DatePicker.tsx
index 92a61fee68..cb41a99d92 100644
--- a/app/vmui/packages/vmui/src/components/Main/DatePicker/DatePicker.tsx
+++ b/app/vmui/packages/vmui/src/components/Main/DatePicker/DatePicker.tsx
@@ -1,9 +1,11 @@
-import React, { Ref, useEffect, useMemo, useState, forwardRef } from "preact/compat";
+import React, { Ref, useMemo, forwardRef } from "preact/compat";
 import Calendar from "../../Main/DatePicker/Calendar/Calendar";
 import dayjs, { Dayjs } from "dayjs";
 import Popper from "../../Main/Popper/Popper";
 import { DATE_TIME_FORMAT } from "../../../constants/date";
 import useDeviceDetect from "../../../hooks/useDeviceDetect";
+import useBoolean from "../../../hooks/useBoolean";
+import useEventListener from "../../../hooks/useEventListener";
 
 interface DatePickerProps {
   date: string | Date | Dayjs,
@@ -20,17 +22,14 @@ const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(({
   onChange,
   label
 }, ref) => {
-  const [openCalendar, setOpenCalendar] = useState(false);
   const dateDayjs = useMemo(() => dayjs(date).isValid() ? dayjs.tz(date) : dayjs().tz(), [date]);
   const { isMobile } = useDeviceDetect();
 
-  const toggleOpenCalendar = () => {
-    setOpenCalendar(prev => !prev);
-  };
-
-  const handleCloseCalendar = () => {
-    setOpenCalendar(false);
-  };
+  const {
+    value: openCalendar,
+    toggle: toggleOpenCalendar,
+    setFalse: handleCloseCalendar,
+  } = useBoolean(false);
 
   const handleChangeDate = (val: string) => {
     onChange(val);
@@ -41,21 +40,8 @@ const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(({
     if (e.key === "Escape" || e.key === "Enter") handleCloseCalendar();
   };
 
-  useEffect(() => {
-    targetRef.current?.addEventListener("click", toggleOpenCalendar);
-
-    return () => {
-      targetRef.current?.removeEventListener("click", toggleOpenCalendar);
-    };
-  }, [targetRef]);
-
-  useEffect(() => {
-    window.addEventListener("keyup", handleKeyUp);
-
-    return () => {
-      window.removeEventListener("keyup", handleKeyUp);
-    };
-  }, []);
+  useEventListener("click", toggleOpenCalendar, targetRef);
+  useEventListener("keyup", handleKeyUp);
 
   return (<>
     <Popper
diff --git a/app/vmui/packages/vmui/src/components/Main/Icons/PreviewIcons.tsx b/app/vmui/packages/vmui/src/components/Main/Icons/PreviewIcons.tsx
index 23bbc69244..7d6e533a8a 100644
--- a/app/vmui/packages/vmui/src/components/Main/Icons/PreviewIcons.tsx
+++ b/app/vmui/packages/vmui/src/components/Main/Icons/PreviewIcons.tsx
@@ -1,18 +1,13 @@
 import React, { FC } from "preact/compat";
 import * as icons from "./index";
-import { useSnack } from "../../../contexts/Snackbar";
+import useCopyToClipboard from "../../../hooks/useCopyToClipboard";
 import "./style.scss";
 
 const PreviewIcons: FC = () => {
-  const { showInfoMessage } = useSnack();
+  const copyToClipboard = useCopyToClipboard();
 
-  const handleClickIcon = (copyValue: string) => {
-    navigator.clipboard.writeText(`<${copyValue}/>`);
-    showInfoMessage({ text: `<${copyValue}/> has been copied`, type: "success" });
-  };
-
-  const createHandlerClickIcon = (key: string) => () => {
-    handleClickIcon(key);
+  const createHandlerClickIcon = (key: string) => async () => {
+    await copyToClipboard(`<${key}/>`, `<${key}/> has been copied`);
   };
 
   return (
diff --git a/app/vmui/packages/vmui/src/components/Main/Modal/Modal.tsx b/app/vmui/packages/vmui/src/components/Main/Modal/Modal.tsx
index 6fbbaeb137..1cbeb524bf 100644
--- a/app/vmui/packages/vmui/src/components/Main/Modal/Modal.tsx
+++ b/app/vmui/packages/vmui/src/components/Main/Modal/Modal.tsx
@@ -1,4 +1,4 @@
-import React, { FC, useEffect } from "preact/compat";
+import React, { FC, useCallback, useEffect } from "preact/compat";
 import ReactDOM from "react-dom";
 import { CloseIcon } from "../Icons";
 import Button from "../Button/Button";
@@ -7,6 +7,7 @@ import "./style.scss";
 import useDeviceDetect from "../../../hooks/useDeviceDetect";
 import classNames from "classnames";
 import { useLocation, useNavigate } from "react-router-dom";
+import useEventListener from "../../../hooks/useEventListener";
 
 interface ModalProps {
   title?: string
@@ -21,48 +22,42 @@ const Modal: FC<ModalProps> = ({
   children,
   onClose,
   className,
-  isOpen= true
+  isOpen = true
 }) => {
   const { isMobile } = useDeviceDetect();
   const navigate = useNavigate();
   const location = useLocation();
 
-  const handleKeyUp = (e: KeyboardEvent) => {
+  const handleKeyUp = useCallback((e: KeyboardEvent) => {
+    if (!isOpen) return;
     if (e.key === "Escape") onClose();
-  };
+  }, [isOpen]);
 
   const handleMouseDown = (e: MouseEvent<HTMLDivElement>) => {
     e.stopPropagation();
   };
 
-  const handlePopstate = () => {
+  const handlePopstate = useCallback(() => {
     if (isOpen) {
       navigate(location, { replace: true });
       onClose();
     }
-  };
-
-  useEffect(() => {
-    window.addEventListener("popstate", handlePopstate);
-
-    return () => {
-      window.removeEventListener("popstate", handlePopstate);
-    };
-  }, [isOpen, location]);
+  }, [isOpen, location, onClose]);
 
   const handleDisplayModal = () => {
     if (!isOpen) return;
     document.body.style.overflow = "hidden";
-    window.addEventListener("keyup", handleKeyUp);
 
     return () => {
       document.body.style.overflow = "auto";
-      window.removeEventListener("keyup", handleKeyUp);
     };
   };
 
   useEffect(handleDisplayModal, [isOpen]);
 
+  useEventListener("popstate", handlePopstate);
+  useEventListener("keyup", handleKeyUp);
+
   return ReactDOM.createPortal((
     <div
       className={classNames({
diff --git a/app/vmui/packages/vmui/src/components/Main/Popper/Popper.tsx b/app/vmui/packages/vmui/src/components/Main/Popper/Popper.tsx
index 3e7f79de3a..9caee30e3f 100644
--- a/app/vmui/packages/vmui/src/components/Main/Popper/Popper.tsx
+++ b/app/vmui/packages/vmui/src/components/Main/Popper/Popper.tsx
@@ -7,6 +7,9 @@ import useDeviceDetect from "../../../hooks/useDeviceDetect";
 import Button from "../Button/Button";
 import { CloseIcon } from "../Icons";
 import { useLocation, useNavigate } from "react-router-dom";
+import useBoolean from "../../../hooks/useBoolean";
+import useEventListener from "../../../hooks/useEventListener";
+import { useCallback } from "preact/compat";
 
 interface PopperProps {
   children: ReactNode
@@ -37,23 +40,16 @@ const Popper: FC<PopperProps> = ({
   const { isMobile } = useDeviceDetect();
   const navigate = useNavigate();
   const location = useLocation();
-  const [isOpen, setIsOpen] = useState(false);
   const [popperSize, setPopperSize] = useState({ width: 0, height: 0 });
 
+  const {
+    value: isOpen,
+    setValue: setIsOpen,
+    setFalse: handleClose,
+  } = useBoolean(false);
+
   const popperRef = useRef<HTMLDivElement>(null);
 
-  const onScrollWindow = () => {
-    setIsOpen(false);
-  };
-
-  useEffect(() => {
-    window.addEventListener("scroll", onScrollWindow);
-
-    return () => {
-      window.removeEventListener("scroll", onScrollWindow);
-    };
-  }, []);
-
   useEffect(() => {
     setIsOpen(open);
   }, [open]);
@@ -137,32 +133,25 @@ const Popper: FC<PopperProps> = ({
     }
   }, [isOpen, popperRef]);
 
-  const handlePopstate = () => {
+  const handlePopstate = useCallback(() => {
     if (isOpen && isMobile && !disabledFullScreen) {
       navigate(location, { replace: true });
       onClose();
     }
-  };
+  }, [isOpen, isMobile, disabledFullScreen, location, onClose]);
 
-  useEffect(() => {
-    window.addEventListener("popstate", handlePopstate);
-
-    return () => {
-      window.removeEventListener("popstate", handlePopstate);
-    };
-  }, [isOpen, isMobile, disabledFullScreen, location]);
-
-  const popperClasses = classNames({
-    "vm-popper": true,
-    "vm-popper_mobile": isMobile && !disabledFullScreen,
-    "vm-popper_open": (isMobile || Object.keys(popperStyle).length) && isOpen,
-  });
+  useEventListener("scroll", handleClose);
+  useEventListener("popstate", handlePopstate);
 
   return (
     <>
       {(isOpen || !popperSize.width) && ReactDOM.createPortal((
         <div
-          className={popperClasses}
+          className={classNames({
+            "vm-popper": true,
+            "vm-popper_mobile": isMobile && !disabledFullScreen,
+            "vm-popper_open": (isMobile || Object.keys(popperStyle).length) && isOpen,
+          })}
           ref={popperRef}
           style={(isMobile && !disabledFullScreen) ? {} : popperStyle}
         >
diff --git a/app/vmui/packages/vmui/src/components/Main/Select/Select.tsx b/app/vmui/packages/vmui/src/components/Main/Select/Select.tsx
index dba043960e..906df1a035 100644
--- a/app/vmui/packages/vmui/src/components/Main/Select/Select.tsx
+++ b/app/vmui/packages/vmui/src/components/Main/Select/Select.tsx
@@ -7,6 +7,7 @@ import { useAppState } from "../../../state/common/StateContext";
 import "./style.scss";
 import useDeviceDetect from "../../../hooks/useDeviceDetect";
 import MultipleSelectedValue from "./MultipleSelectedValue/MultipleSelectedValue";
+import useEventListener from "../../../hooks/useEventListener";
 
 interface SelectProps {
   value: string | string[]
@@ -105,13 +106,7 @@ const Select: FC<SelectProps> = ({
     inputRef.current.focus();
   }, [autofocus, inputRef]);
 
-  useEffect(() => {
-    window.addEventListener("keyup", handleKeyUp);
-
-    return () => {
-      window.removeEventListener("keyup", handleKeyUp);
-    };
-  }, []);
+  useEventListener("keyup", handleKeyUp);
 
   return (
     <div
diff --git a/app/vmui/packages/vmui/src/components/Main/ShortcutKeys/ShortcutKeys.tsx b/app/vmui/packages/vmui/src/components/Main/ShortcutKeys/ShortcutKeys.tsx
index 3da26c0340..171d730834 100644
--- a/app/vmui/packages/vmui/src/components/Main/ShortcutKeys/ShortcutKeys.tsx
+++ b/app/vmui/packages/vmui/src/components/Main/ShortcutKeys/ShortcutKeys.tsx
@@ -1,4 +1,4 @@
-import React, { FC, useEffect, useState } from "preact/compat";
+import React, { FC, useCallback } from "preact/compat";
 import { getAppModeEnable } from "../../../utils/app-mode";
 import Button from "../Button/Button";
 import { KeyboardIcon } from "../Icons";
@@ -7,38 +7,31 @@ import "./style.scss";
 import Tooltip from "../Tooltip/Tooltip";
 import keyList from "./constants/keyList";
 import { isMacOs } from "../../../utils/detect-device";
+import useBoolean from "../../../hooks/useBoolean";
+import useEventListener from "../../../hooks/useEventListener";
 
 const title = "Shortcut keys";
 const isMac = isMacOs();
 const keyOpenHelp = isMac ? "Cmd + /" : "F1";
 
 const ShortcutKeys: FC<{ showTitle?: boolean }> = ({ showTitle }) => {
-  const [openList, setOpenList] = useState(false);
   const appModeEnable = getAppModeEnable();
 
-  const handleOpen = () => {
-    setOpenList(true);
-  };
+  const {
+    value: openList,
+    setTrue: handleOpen,
+    setFalse: handleClose,
+  } = useBoolean(false);
 
-  const handleClose = () => {
-    setOpenList(false);
-  };
-
-  const handleKeyDown = (e: KeyboardEvent) => {
+  const handleKeyDown = useCallback((e: KeyboardEvent) => {
     const openOnMac = isMac && e.key === "/" && e.metaKey;
     const openOnOther = !isMac && e.key === "F1" && !e.metaKey;
     if (openOnMac || openOnOther) {
       handleOpen();
     }
-  };
+  }, [handleOpen]);
 
-  useEffect(() => {
-    window.addEventListener("keydown", handleKeyDown);
-
-    return () => {
-      window.removeEventListener("keydown", handleKeyDown);
-    };
-  }, []);
+  useEventListener("keydown", handleKeyDown);
 
   return <>
     <Tooltip
diff --git a/app/vmui/packages/vmui/src/components/Main/ShortcutKeys/style.scss b/app/vmui/packages/vmui/src/components/Main/ShortcutKeys/style.scss
index 2d1c32a67b..b9da067f06 100644
--- a/app/vmui/packages/vmui/src/components/Main/ShortcutKeys/style.scss
+++ b/app/vmui/packages/vmui/src/components/Main/ShortcutKeys/style.scss
@@ -64,6 +64,7 @@
           svg {
             width: 24px;
             padding: 4px;
+            color: $color-primary;
           }
         }
 
diff --git a/app/vmui/packages/vmui/src/components/Main/Tabs/Tabs.tsx b/app/vmui/packages/vmui/src/components/Main/Tabs/Tabs.tsx
index ea8bf74554..ec319cb25b 100644
--- a/app/vmui/packages/vmui/src/components/Main/Tabs/Tabs.tsx
+++ b/app/vmui/packages/vmui/src/components/Main/Tabs/Tabs.tsx
@@ -1,9 +1,9 @@
 import React, { Component, FC, useRef, useState } from "preact/compat";
 import { ReactNode, useEffect } from "react";
 import { getCssVariable } from "../../../utils/theme";
-import useResize from "../../../hooks/useResize";
 import TabItem from "./TabItem";
 import "./style.scss";
+import useWindowSize from "../../../hooks/useWindowSize";
 
 export interface TabItemType {
   value: string
@@ -29,7 +29,7 @@ const Tabs: FC<TabsProps> = ({
   indicatorPlacement = "bottom",
   isNavLink,
 }) => {
-  const windowSize = useResize(document.body);
+  const windowSize = useWindowSize();
   const activeNavRef = useRef<Component>(null);
   const [indicatorPosition, setIndicatorPosition] = useState({ left: 0, width: 0, bottom: 0 });
 
diff --git a/app/vmui/packages/vmui/src/components/Main/ThemeProvider/ThemeProvider.ts b/app/vmui/packages/vmui/src/components/Main/ThemeProvider/ThemeProvider.ts
index c0905fe0e5..4ea1c65a80 100644
--- a/app/vmui/packages/vmui/src/components/Main/ThemeProvider/ThemeProvider.ts
+++ b/app/vmui/packages/vmui/src/components/Main/ThemeProvider/ThemeProvider.ts
@@ -7,7 +7,7 @@ import { darkPalette, lightPalette } from "../../../constants/palette";
 import { Theme } from "../../../types";
 import { useAppDispatch, useAppState } from "../../../state/common/StateContext";
 import useSystemTheme from "../../../hooks/useSystemTheme";
-import useResize from "../../../hooks/useResize";
+import useWindowSize from "../../../hooks/useWindowSize";
 
 interface ThemeProviderProps {
   onLoaded: (val: boolean) => void
@@ -29,7 +29,7 @@ export const ThemeProvider: FC<ThemeProviderProps> = ({ onLoaded }) => {
   const { theme } = useAppState();
   const isDarkTheme = useSystemTheme();
   const dispatch = useAppDispatch();
-  const windowSize = useResize(document.body);
+  const windowSize = useWindowSize();
 
   const [palette, setPalette] = useState({
     [Theme.dark]: darkPalette,
diff --git a/app/vmui/packages/vmui/src/components/Main/Tooltip/Tooltip.tsx b/app/vmui/packages/vmui/src/components/Main/Tooltip/Tooltip.tsx
index 3eef672f92..30ad88f1b8 100644
--- a/app/vmui/packages/vmui/src/components/Main/Tooltip/Tooltip.tsx
+++ b/app/vmui/packages/vmui/src/components/Main/Tooltip/Tooltip.tsx
@@ -4,6 +4,7 @@ import "./style.scss";
 import { ReactNode } from "react";
 import { ExoticComponent } from "react";
 import useDeviceDetect from "../../../hooks/useDeviceDetect";
+import useEventListener from "../../../hooks/useEventListener";
 
 interface TooltipProps {
   children: ReactNode
@@ -29,14 +30,7 @@ const Tooltip: FC<TooltipProps> = ({
   const popperRef = useRef<HTMLDivElement>(null);
 
   const onScrollWindow = () => setIsOpen(false);
-
-  useEffect(() => {
-    window.addEventListener("scroll", onScrollWindow);
-
-    return () => {
-      window.removeEventListener("scroll", onScrollWindow);
-    };
-  }, []);
+  useEventListener("scroll", onScrollWindow);
 
   useEffect(() => {
     if (!popperRef.current || !isOpen) return;
diff --git a/app/vmui/packages/vmui/src/components/Views/GraphView/GraphView.tsx b/app/vmui/packages/vmui/src/components/Views/GraphView/GraphView.tsx
index cdd95003d1..1cdab1387c 100644
--- a/app/vmui/packages/vmui/src/components/Views/GraphView/GraphView.tsx
+++ b/app/vmui/packages/vmui/src/components/Views/GraphView/GraphView.tsx
@@ -1,4 +1,4 @@
-import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from "preact/compat";
+import React, { FC, useCallback, useEffect, useMemo, useState } from "preact/compat";
 import { MetricResult } from "../../../api/types";
 import LineChart from "../../Chart/Line/LineChart/LineChart";
 import { AlignedData as uPlotData, Series as uPlotSeries } from "uplot";
@@ -18,6 +18,7 @@ import { promValueToNumber } from "../../../utils/metric";
 import { normalizeData } from "../../../utils/uplot/heatmap";
 import useDeviceDetect from "../../../hooks/useDeviceDetect";
 import { TooltipHeatmapProps } from "../../Chart/Heatmap/ChartTooltipHeatmap/ChartTooltipHeatmap";
+import useElementSize from "../../../hooks/useElementSize";
 
 export interface GraphViewProps {
   data?: MetricResult[];
@@ -164,7 +165,7 @@ const GraphView: FC<GraphViewProps> = ({
     setLegend(tempLegend);
   }, [hideSeries]);
 
-  const containerRef = useRef<HTMLDivElement>(null);
+  const [containerRef, containerSize] = useElementSize();
 
   return (
     <div
@@ -175,7 +176,7 @@ const GraphView: FC<GraphViewProps> = ({
       })}
       ref={containerRef}
     >
-      {containerRef?.current && !isHistogram && (
+      {!isHistogram && (
         <LineChart
           data={dataChart}
           series={series}
@@ -184,11 +185,11 @@ const GraphView: FC<GraphViewProps> = ({
           yaxis={yaxis}
           unit={unit}
           setPeriod={setPeriod}
-          container={containerRef?.current}
+          layoutSize={containerSize}
           height={height}
         />
       )}
-      {containerRef?.current && isHistogram && (
+      {isHistogram && (
         <HeatmapChart
           data={dataChart}
           metrics={data}
@@ -196,7 +197,7 @@ const GraphView: FC<GraphViewProps> = ({
           yaxis={yaxis}
           unit={unit}
           setPeriod={setPeriod}
-          container={containerRef?.current}
+          layoutSize={containerSize}
           height={height}
           onChangeLegend={handleChangeLegend}
         />
diff --git a/app/vmui/packages/vmui/src/components/Views/JsonView/JsonView.tsx b/app/vmui/packages/vmui/src/components/Views/JsonView/JsonView.tsx
index d1496c8460..d569b817f9 100644
--- a/app/vmui/packages/vmui/src/components/Views/JsonView/JsonView.tsx
+++ b/app/vmui/packages/vmui/src/components/Views/JsonView/JsonView.tsx
@@ -1,6 +1,6 @@
 import React, { FC, useMemo } from "preact/compat";
 import { InstantMetricResult } from "../../../api/types";
-import { useSnack } from "../../../contexts/Snackbar";
+import useCopyToClipboard from "../../../hooks/useCopyToClipboard";
 import { TopQuery } from "../../../types";
 import Button from "../../Main/Button/Button";
 import "./style.scss";
@@ -10,13 +10,12 @@ export interface JsonViewProps {
 }
 
 const JsonView: FC<JsonViewProps> = ({ data }) => {
-  const { showInfoMessage } = useSnack();
+  const copyToClipboard = useCopyToClipboard();
 
   const formattedJson = useMemo(() => JSON.stringify(data, null, 2), [data]);
 
-  const handlerCopy = () => {
-    navigator.clipboard.writeText(formattedJson);
-    showInfoMessage({ text: "Formatted JSON has been copied", type: "success" });
+  const handlerCopy = async () => {
+    await copyToClipboard(formattedJson, "Formatted JSON has been copied");
   };
 
   return (
diff --git a/app/vmui/packages/vmui/src/components/Views/TableView/TableView.tsx b/app/vmui/packages/vmui/src/components/Views/TableView/TableView.tsx
index 94d90feebc..41e3aa1dbe 100644
--- a/app/vmui/packages/vmui/src/components/Views/TableView/TableView.tsx
+++ b/app/vmui/packages/vmui/src/components/Views/TableView/TableView.tsx
@@ -1,4 +1,4 @@
-import React, { FC, useEffect, useMemo, useRef, useState } from "preact/compat";
+import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from "preact/compat";
 import { InstantMetricResult } from "../../../api/types";
 import { InstantDataSeries } from "../../../types";
 import { useSortedCategories } from "../../../hooks/useSortedCategories";
@@ -7,12 +7,13 @@ import classNames from "classnames";
 import { ArrowDropDownIcon, CopyIcon } from "../../Main/Icons";
 import Tooltip from "../../Main/Tooltip/Tooltip";
 import Button from "../../Main/Button/Button";
-import { useSnack } from "../../../contexts/Snackbar";
+import useCopyToClipboard from "../../../hooks/useCopyToClipboard";
 import { getNameForMetric } from "../../../utils/metric";
 import { useCustomPanelState } from "../../../state/customPanel/CustomPanelStateContext";
 import "./style.scss";
-import useResize from "../../../hooks/useResize";
 import useDeviceDetect from "../../../hooks/useDeviceDetect";
+import useWindowSize from "../../../hooks/useWindowSize";
+import useEventListener from "../../../hooks/useEventListener";
 
 export interface GraphViewProps {
   data: InstantMetricResult[];
@@ -20,11 +21,11 @@ export interface GraphViewProps {
 }
 
 const TableView: FC<GraphViewProps> = ({ data, displayColumns }) => {
-  const { showInfoMessage } = useSnack();
+  const copyToClipboard = useCopyToClipboard();
   const { isMobile } = useDeviceDetect();
 
   const { tableCompact } = useCustomPanelState();
-  const windowSize = useResize(document.body);
+  const windowSize = useWindowSize();
   const tableRef = useRef<HTMLTableElement>(null);
   const [tableTop, setTableTop] = useState(0);
   const [headTop, setHeadTop] = useState(0);
@@ -74,33 +75,22 @@ const TableView: FC<GraphViewProps> = ({ data, displayColumns }) => {
     setOrderBy(key);
   };
 
-  const copyHandler = async (copyValue: string) => {
-    await navigator.clipboard.writeText(copyValue);
-    showInfoMessage({ text: "Row has been copied", type: "success" });
-  };
-
   const createSortHandler = (key: string) => () => {
     sortHandler(key);
   };
 
-  const createCopyHandler = (copyValue: string) => () => {
-    copyHandler(copyValue);
+  const createCopyHandler = (copyValue: string) => async () => {
+    await copyToClipboard(copyValue, "Row has been copied");
   };
 
-  const handleScroll = () => {
+  const handleScroll = useCallback(() => {
     if (!tableRef.current) return;
     const { top } = tableRef.current.getBoundingClientRect();
     setHeadTop(top < 0 ? window.scrollY - tableTop : 0);
-  };
-
-  useEffect(() => {
-    window.addEventListener("scroll", handleScroll);
-
-    return () => {
-      window.removeEventListener("scroll", handleScroll);
-    };
   }, [tableRef, tableTop, windowSize]);
 
+  useEventListener("scroll", handleScroll);
+
   useEffect(() => {
     if (!tableRef.current) return;
     const { top } = tableRef.current.getBoundingClientRect();
diff --git a/app/vmui/packages/vmui/src/hooks/useClickOutside.ts b/app/vmui/packages/vmui/src/hooks/useClickOutside.ts
index 5f39e15261..912a477e04 100644
--- a/app/vmui/packages/vmui/src/hooks/useClickOutside.ts
+++ b/app/vmui/packages/vmui/src/hooks/useClickOutside.ts
@@ -1,4 +1,6 @@
-import { useEffect, RefObject } from "react";
+import { RefObject } from "react";
+import useEventListener from "./useEventListener";
+import { useCallback } from "preact/compat";
 
 type Event = MouseEvent | TouchEvent;
 
@@ -7,26 +9,19 @@ const useClickOutside = <T extends HTMLElement = HTMLElement>(
   handler: (event: Event) => void,
   preventRef?: RefObject<T>
 ) => {
-  useEffect(() => {
-    const listener = (event: Event) => {
-      const el = ref?.current;
-      const target = event.target as HTMLElement;
-      const isPreventRef = preventRef?.current && preventRef.current.contains(target);
-      if (!el || el.contains((event?.target as Node) || null) || isPreventRef) {
-        return;
-      }
+  const listener = useCallback((event: Event) => {
+    const el = ref?.current;
+    const target = event.target as HTMLElement;
+    const isPreventRef = preventRef?.current && preventRef.current.contains(target);
+    if (!el || el.contains((event?.target as Node) || null) || isPreventRef) {
+      return;
+    }
 
-      handler(event); // Call the handler only if the click is outside of the element passed.
-    };
+    handler(event); // Call the handler only if the click is outside of the element passed.
+  }, [ref, handler]);
 
-    document.addEventListener("mousedown", listener);
-    document.addEventListener("touchstart", listener);
-
-    return () => {
-      document.removeEventListener("mousedown", listener);
-      document.removeEventListener("touchstart", listener);
-    };
-  }, [ref, handler]); // Reload only if ref or handler changes
+  useEventListener("mousedown", listener);
+  useEventListener("touchstart", listener);
 };
 
 export default useClickOutside;
diff --git a/app/vmui/packages/vmui/src/hooks/useCopyToClipboard.ts b/app/vmui/packages/vmui/src/hooks/useCopyToClipboard.ts
new file mode 100644
index 0000000000..970417f549
--- /dev/null
+++ b/app/vmui/packages/vmui/src/hooks/useCopyToClipboard.ts
@@ -0,0 +1,32 @@
+import { useSnack } from "../contexts/Snackbar";
+
+type CopyFn = (text: string, msgInfo?: string) => Promise<boolean> // Return success
+
+const useCopyToClipboard = (): CopyFn => {
+  const { showInfoMessage } = useSnack();
+
+  return async (text, msgInfo) => {
+    if (!navigator?.clipboard) {
+      showInfoMessage({ text: "Clipboard not supported", type: "error" });
+      console.warn("Clipboard not supported");
+      return false;
+    }
+
+    // Try to save to clipboard then save it in the state if worked
+    try {
+      await navigator.clipboard.writeText(text);
+      if (msgInfo) {
+        showInfoMessage({ text: msgInfo, type: "success" });
+      }
+      return true;
+    } catch (error) {
+      if (error instanceof Error) {
+        showInfoMessage({ text: `${error.name}: ${error.message}`, type: "error" });
+      }
+      console.warn("Copy failed", error);
+      return false;
+    }
+  };
+};
+
+export default useCopyToClipboard;
diff --git a/app/vmui/packages/vmui/src/hooks/useDeviceDetect.ts b/app/vmui/packages/vmui/src/hooks/useDeviceDetect.ts
index 8b8608a2ec..7d26cdb89f 100644
--- a/app/vmui/packages/vmui/src/hooks/useDeviceDetect.ts
+++ b/app/vmui/packages/vmui/src/hooks/useDeviceDetect.ts
@@ -1,9 +1,9 @@
 import { useEffect, useState } from "react";
 import { isMobileAgent } from "../utils/detect-device";
-import useResize from "./useResize";
+import useWindowSize from "./useWindowSize";
 
 export default function useDeviceDetect() {
-  const windowSize = useResize(document.body);
+  const windowSize = useWindowSize();
 
   const getIsMobile = () => {
     const mobileAgent = isMobileAgent();
diff --git a/app/vmui/packages/vmui/src/hooks/useDropzone.ts b/app/vmui/packages/vmui/src/hooks/useDropzone.ts
index 7395a53bd9..9af2f2a386 100644
--- a/app/vmui/packages/vmui/src/hooks/useDropzone.ts
+++ b/app/vmui/packages/vmui/src/hooks/useDropzone.ts
@@ -1,8 +1,11 @@
-import { useState, useEffect } from "preact/compat";
+import { useState } from "preact/compat";
+import useEventListener from "./useEventListener";
+import { useRef } from "react";
 
-const useDropzone = (node: HTMLElement | null): {dragging: boolean, files: File[]} => {
+const useDropzone = (): { dragging: boolean, files: File[] } => {
   const [files, setFiles] = useState<File[]>([]);
   const [dragging, setDragging] = useState(false);
+  const bodyRef = useRef(document.body);
 
   const handleAddFiles = (fileList: FileList) => {
     const filesArray = Array.from(fileList || []);
@@ -43,21 +46,11 @@ const useDropzone = (node: HTMLElement | null): {dragging: boolean, files: File[
     setFiles(jsonFiles);
   };
 
-  useEffect(() => {
-    node?.addEventListener("dragenter", handleDrag);
-    node?.addEventListener("dragleave", handleDrag);
-    node?.addEventListener("dragover", handleDrag);
-    node?.addEventListener("drop", handleDrop);
-    node?.addEventListener("paste", handlePaste);
-
-    return () => {
-      node?.removeEventListener("dragenter", handleDrag);
-      node?.removeEventListener("dragleave", handleDrag);
-      node?.removeEventListener("dragover", handleDrag);
-      node?.removeEventListener("drop", handleDrop);
-      node?.removeEventListener("paste", handlePaste);
-    };
-  }, [node]);
+  useEventListener("dragenter", handleDrag, bodyRef);
+  useEventListener("dragleave", handleDrag, bodyRef);
+  useEventListener("dragover", handleDrag, bodyRef);
+  useEventListener("drop", handleDrop, bodyRef);
+  useEventListener("paste", handlePaste, bodyRef);
 
   return {
     files,
diff --git a/app/vmui/packages/vmui/src/hooks/useElementSize.ts b/app/vmui/packages/vmui/src/hooks/useElementSize.ts
new file mode 100644
index 0000000000..603b328e4b
--- /dev/null
+++ b/app/vmui/packages/vmui/src/hooks/useElementSize.ts
@@ -0,0 +1,36 @@
+import { useCallback, useState } from "react";
+import useIsomorphicLayoutEffect from "./useIsomorphicLayoutEffect";
+import useEventListener from "./useEventListener";
+
+export interface ElementSize {
+    width: number
+    height: number
+}
+
+const useElementSize = <T extends HTMLElement = HTMLDivElement>(): [(node: T | null) => void, ElementSize] => {
+  // Mutable values like 'ref.current' aren't valid dependencies
+  // because mutating them doesn't re-render the component.
+  // Instead, we use a state as a ref to be reactive.
+  const [ref, setRef] = useState<T | null>(null);
+  const [size, setSize] = useState<ElementSize>({
+    width: 0,
+    height: 0,
+  });
+
+  // Prevent too many rendering using useCallback
+  const handleSize = useCallback(() => {
+    setSize({
+      width: ref?.offsetWidth || 0,
+      height: ref?.offsetHeight || 0,
+    });
+
+  }, [ref?.offsetHeight, ref?.offsetWidth]);
+
+  useEventListener("resize", handleSize);
+
+  useIsomorphicLayoutEffect(handleSize, [ref?.offsetHeight, ref?.offsetWidth]);
+
+  return [setRef, size];
+};
+
+export default useElementSize;
diff --git a/app/vmui/packages/vmui/src/hooks/useEventListener.ts b/app/vmui/packages/vmui/src/hooks/useEventListener.ts
new file mode 100644
index 0000000000..f97ce2d852
--- /dev/null
+++ b/app/vmui/packages/vmui/src/hooks/useEventListener.ts
@@ -0,0 +1,81 @@
+import { RefObject, useEffect, useRef } from "react";
+import useIsomorphicLayoutEffect from "./useIsomorphicLayoutEffect";
+
+// MediaQueryList Event based useEventListener interface
+function useEventListener<K extends keyof MediaQueryListEventMap>(
+    eventName: K,
+    handler: (event: MediaQueryListEventMap[K]) => void,
+    element: RefObject<MediaQueryList>,
+    options?: boolean | AddEventListenerOptions,
+): void
+
+// Window Event based useEventListener interface
+function useEventListener<K extends keyof WindowEventMap>(
+    eventName: K,
+    handler: (event: WindowEventMap[K]) => void,
+    element?: undefined,
+    options?: boolean | AddEventListenerOptions,
+): void
+
+// Element Event based useEventListener interface
+function useEventListener<
+    K extends keyof HTMLElementEventMap,
+    T extends HTMLElement = HTMLDivElement,
+>(
+    eventName: K,
+    handler: (event: HTMLElementEventMap[K]) => void,
+    element: RefObject<T>,
+    options?: boolean | AddEventListenerOptions,
+): void
+
+// Document Event based useEventListener interface
+function useEventListener<K extends keyof DocumentEventMap>(
+    eventName: K,
+    handler: (event: DocumentEventMap[K]) => void,
+    element: RefObject<Document>,
+    options?: boolean | AddEventListenerOptions,
+): void
+
+function useEventListener<
+    KW extends keyof WindowEventMap,
+    KH extends keyof HTMLElementEventMap,
+    KM extends keyof MediaQueryListEventMap,
+    T extends HTMLElement | MediaQueryList | void = void,
+>(
+  eventName: KW | KH | KM,
+  handler: (
+        event:
+            | WindowEventMap[KW]
+            | HTMLElementEventMap[KH]
+            | MediaQueryListEventMap[KM]
+            | Event,
+    ) => void,
+  element?: RefObject<T>,
+  options?: boolean | AddEventListenerOptions,
+) {
+  // Create a ref that stores handler
+  const savedHandler = useRef(handler);
+
+  useIsomorphicLayoutEffect(() => {
+    savedHandler.current = handler;
+  }, [handler]);
+
+  useEffect(() => {
+    // Define the listening target
+    const targetElement: T | Window = element?.current ?? window;
+
+    if (!(targetElement && targetElement.addEventListener)) return;
+
+    // Create event listener that calls handler function stored in ref
+    const listener: typeof handler = event => savedHandler.current(event);
+
+    targetElement.addEventListener(eventName, listener, options);
+
+    // Remove event listener on cleanup
+    return () => {
+      targetElement.removeEventListener(eventName, listener, options);
+    };
+  }, [eventName, element, options]);
+}
+
+export default useEventListener;
diff --git a/app/vmui/packages/vmui/src/hooks/useIsomorphicLayoutEffect.ts b/app/vmui/packages/vmui/src/hooks/useIsomorphicLayoutEffect.ts
new file mode 100644
index 0000000000..8ccca8a63e
--- /dev/null
+++ b/app/vmui/packages/vmui/src/hooks/useIsomorphicLayoutEffect.ts
@@ -0,0 +1,5 @@
+import { useEffect, useLayoutEffect } from "react";
+
+const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
+
+export default useIsomorphicLayoutEffect;
diff --git a/app/vmui/packages/vmui/src/hooks/useResize.ts b/app/vmui/packages/vmui/src/hooks/useResize.ts
deleted file mode 100644
index c3b10ca484..0000000000
--- a/app/vmui/packages/vmui/src/hooks/useResize.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import { useState, useEffect } from "preact/compat";
-
-const useResize = (node: HTMLElement | null): {width: number, height: number} => {
-  const [windowSize, setWindowSize] = useState({
-    width: 0,
-    height: 0,
-  });
-  useEffect(() => {
-    const observer = new ResizeObserver((entries) => {
-      const { width, height } = entries[0].contentRect;
-      setWindowSize({ width, height });
-    });
-    if (node) observer.observe(node);
-    return () => {
-      if (node) observer.unobserve(node);
-    };
-  }, [node]);
-  return windowSize;
-};
-
-export default useResize;
diff --git a/app/vmui/packages/vmui/src/hooks/useWindowSize.ts b/app/vmui/packages/vmui/src/hooks/useWindowSize.ts
new file mode 100644
index 0000000000..1b1e1021f3
--- /dev/null
+++ b/app/vmui/packages/vmui/src/hooks/useWindowSize.ts
@@ -0,0 +1,31 @@
+import { useState } from "react";
+import useIsomorphicLayoutEffect from "./useIsomorphicLayoutEffect";
+import useEventListener from "./useEventListener";
+
+interface WindowSize {
+    width: number
+    height: number
+}
+
+const useWindowSize = (): WindowSize => {
+  const [windowSize, setWindowSize] = useState<WindowSize>({
+    width: 0,
+    height: 0,
+  });
+
+  const handleSize = () => {
+    setWindowSize({
+      width: window.innerWidth,
+      height: window.innerHeight,
+    });
+  };
+
+  useEventListener("resize", handleSize);
+
+  // Set size at the first client-side load
+  useIsomorphicLayoutEffect(handleSize, []);
+
+  return windowSize;
+};
+
+export default useWindowSize;
diff --git a/app/vmui/packages/vmui/src/pages/CardinalityPanel/Table/TableSettings/TableSettings.tsx b/app/vmui/packages/vmui/src/pages/CardinalityPanel/Table/TableSettings/TableSettings.tsx
index 7f3765932e..6b231fa49f 100644
--- a/app/vmui/packages/vmui/src/pages/CardinalityPanel/Table/TableSettings/TableSettings.tsx
+++ b/app/vmui/packages/vmui/src/pages/CardinalityPanel/Table/TableSettings/TableSettings.tsx
@@ -1,4 +1,4 @@
-import React, { FC, useEffect, useState, useRef, useMemo } from "preact/compat";
+import React, { FC, useEffect, useRef, useMemo } from "preact/compat";
 import { useSortedCategories } from "../../../../hooks/useSortedCategories";
 import { InstantMetricResult } from "../../../../api/types";
 import Button from "../../../../components/Main/Button/Button";
@@ -12,6 +12,7 @@ import Switch from "../../../../components/Main/Switch/Switch";
 import { arrayEquals } from "../../../../utils/array";
 import classNames from "classnames";
 import useDeviceDetect from "../../../../hooks/useDeviceDetect";
+import useBoolean from "../../../../hooks/useBoolean";
 
 const title = "Table settings";
 
@@ -30,7 +31,11 @@ const TableSettings: FC<TableSettingsProps> = ({ data, defaultColumns = [], onCh
 
   const buttonRef = useRef<HTMLDivElement>(null);
 
-  const [openSettings, setOpenSettings] = useState(false);
+  const {
+    value: openSettings,
+    toggle: toggleOpenSettings,
+    setFalse: handleClose,
+  } = useBoolean(false);
 
   const disabledButton = useMemo(() => !columns.length, [columns]);
 
@@ -38,16 +43,12 @@ const TableSettings: FC<TableSettingsProps> = ({ data, defaultColumns = [], onCh
     onChange(defaultColumns.includes(key) ? defaultColumns.filter(col => col !== key) : [...defaultColumns, key]);
   };
 
-  const handleClose = () => {
-    setOpenSettings(false);
-  };
-
   const toggleTableCompact = () => {
     customPanelDispatch({ type: "TOGGLE_TABLE_COMPACT" });
   };
 
   const handleResetColumns = () => {
-    setOpenSettings(false);
+    handleClose();
     onChange(columns.map(col => col.key));
   };
 
@@ -55,10 +56,6 @@ const TableSettings: FC<TableSettingsProps> = ({ data, defaultColumns = [], onCh
     handleChange(key);
   };
 
-  const toggleOpenSettings = () => {
-    setOpenSettings(prev => !prev);
-  };
-
   useEffect(() => {
     const values = columns.map(col => col.key);
     if (arrayEquals(values, defaultColumns)) return;
diff --git a/app/vmui/packages/vmui/src/pages/CustomPanel/index.tsx b/app/vmui/packages/vmui/src/pages/CustomPanel/index.tsx
index dcca302636..b493557360 100644
--- a/app/vmui/packages/vmui/src/pages/CustomPanel/index.tsx
+++ b/app/vmui/packages/vmui/src/pages/CustomPanel/index.tsx
@@ -24,6 +24,7 @@ import classNames from "classnames";
 import useDeviceDetect from "../../hooks/useDeviceDetect";
 import GraphTips from "../../components/Chart/GraphTips/GraphTips";
 import InstantQueryTip from "./InstantQueryTip/InstantQueryTip";
+import useBoolean from "../../hooks/useBoolean";
 
 const CustomPanel: FC = () => {
   const { displayType, isTracingEnabled } = useCustomPanelState();
@@ -36,9 +37,14 @@ const CustomPanel: FC = () => {
   const [displayColumns, setDisplayColumns] = useState<string[]>();
   const [tracesState, setTracesState] = useState<Trace[]>([]);
   const [hideQuery, setHideQuery] = useState<number[]>([]);
-  const [showAllSeries, setShowAllSeries] = useState(false);
   const [hideError, setHideError] = useState(!query[0]);
 
+  const {
+    value: showAllSeries,
+    setTrue: handleShowAll,
+    setFalse: handleHideSeries,
+  } = useBoolean(false);
+
   const { customStep, yaxis } = useGraphState();
   const graphDispatch = useGraphDispatch();
 
@@ -72,10 +78,6 @@ const CustomPanel: FC = () => {
     timeDispatch({ type: "SET_PERIOD", payload: { from, to } });
   };
 
-  const handleShowAll = () => {
-    setShowAllSeries(true);
-  };
-
   const handleTraceDelete = (trace: Trace) => {
     const updatedTraces = tracesState.filter((data) => data.idValue !== trace.idValue);
     setTracesState([...updatedTraces]);
@@ -99,9 +101,7 @@ const CustomPanel: FC = () => {
     setTracesState([]);
   }, [displayType]);
 
-  useEffect(() => {
-    setShowAllSeries(false);
-  }, [query]);
+  useEffect(handleHideSeries, [query]);
 
   useEffect(() => {
     graphDispatch({ type: "SET_IS_HISTOGRAM", payload: isHistogram });
diff --git a/app/vmui/packages/vmui/src/pages/PredefinedPanels/PredefinedDashboard/PredefinedDashboard.tsx b/app/vmui/packages/vmui/src/pages/PredefinedPanels/PredefinedDashboard/PredefinedDashboard.tsx
index 21cbed41b9..d9e7291213 100644
--- a/app/vmui/packages/vmui/src/pages/PredefinedPanels/PredefinedDashboard/PredefinedDashboard.tsx
+++ b/app/vmui/packages/vmui/src/pages/PredefinedPanels/PredefinedDashboard/PredefinedDashboard.tsx
@@ -1,12 +1,13 @@
 import React, { FC, useEffect, useMemo, useState } from "preact/compat";
-import { MouseEvent as ReactMouseEvent } from "react";
+import { MouseEvent as ReactMouseEvent, useCallback } from "react";
 import { DashboardRow } from "../../../types";
 import PredefinedPanel from "../PredefinedPanel/PredefinedPanel";
-import useResize from "../../../hooks/useResize";
 import Accordion from "../../../components/Main/Accordion/Accordion";
 import "./style.scss";
 import classNames from "classnames";
 import Alert from "../../../components/Main/Alert/Alert";
+import useWindowSize from "../../../hooks/useWindowSize";
+import useEventListener from "../../../hooks/useEventListener";
 
 export interface PredefinedDashboardProps extends DashboardRow {
   filename: string;
@@ -20,7 +21,7 @@ const PredefinedDashboard: FC<PredefinedDashboardProps> = ({
   filename
 }) => {
 
-  const windowSize = useResize(document.body);
+  const windowSize = useWindowSize();
   const sizeSection = useMemo(() => {
     return windowSize.width / 12;
   }, [windowSize]);
@@ -34,16 +35,14 @@ const PredefinedDashboard: FC<PredefinedDashboardProps> = ({
 
   const [resize, setResize] = useState({ start: 0, target: 0, enable: false });
 
-  const handleMouseMove = (e: MouseEvent) => {
+  const handleMouseMove = useCallback((e: MouseEvent) => {
     if (!resize.enable) return;
     const { start } = resize;
     const sectionCount = Math.ceil((start - e.clientX)/sizeSection);
     if (Math.abs(sectionCount) >= 12) return;
-    const width = panelsWidth.map((p, i) => {
-      return p - (i === resize.target ? sectionCount : 0);
-    });
+    const width = panelsWidth.map((p, i) => p - (i === resize.target ? sectionCount : 0));
     setPanelsWidth(width);
-  };
+  }, [resize, sizeSection]);
 
   const handleMouseDown = (e: ReactMouseEvent<HTMLButtonElement, MouseEvent>, i: number) => {
     setResize({
@@ -52,12 +51,13 @@ const PredefinedDashboard: FC<PredefinedDashboardProps> = ({
       enable: true,
     });
   };
-  const handleMouseUp = () => {
+
+  const handleMouseUp = useCallback(() => {
     setResize({
       ...resize,
       enable: false
     });
-  };
+  }, [resize]);
 
   const handleChangeExpanded = (val: boolean) => setExpanded(val);
 
@@ -65,14 +65,8 @@ const PredefinedDashboard: FC<PredefinedDashboardProps> = ({
     handleMouseDown(e, index);
   };
 
-  useEffect(() => {
-    window.addEventListener("mousemove", handleMouseMove);
-    window.addEventListener("mouseup", handleMouseUp);
-    return () => {
-      window.removeEventListener("mousemove", handleMouseMove);
-      window.removeEventListener("mouseup", handleMouseUp);
-    };
-  }, [resize]);
+  useEventListener("mousemove", handleMouseMove);
+  useEventListener("mouseup", handleMouseUp);
 
   const HeaderAccordion = () => (
     <div
diff --git a/app/vmui/packages/vmui/src/pages/PredefinedPanels/PredefinedDashboard/style.scss b/app/vmui/packages/vmui/src/pages/PredefinedPanels/PredefinedDashboard/style.scss
index ee042864de..f3da4853a0 100644
--- a/app/vmui/packages/vmui/src/pages/PredefinedPanels/PredefinedDashboard/style.scss
+++ b/app/vmui/packages/vmui/src/pages/PredefinedPanels/PredefinedDashboard/style.scss
@@ -61,7 +61,7 @@
         height: 20px;
         transform: scale(0);
         transition: transform 200ms ease-in-out;
-        cursor: se-resize;
+        cursor: ew-resize;
         z-index: 1;
 
         &:after {
diff --git a/app/vmui/packages/vmui/src/pages/TracePage/JsonForm/JsonForm.tsx b/app/vmui/packages/vmui/src/pages/TracePage/JsonForm/JsonForm.tsx
index 5bec4a98f5..b34764138b 100644
--- a/app/vmui/packages/vmui/src/pages/TracePage/JsonForm/JsonForm.tsx
+++ b/app/vmui/packages/vmui/src/pages/TracePage/JsonForm/JsonForm.tsx
@@ -5,7 +5,7 @@ import Button from "../../../components/Main/Button/Button";
 import Trace from "../../../components/TraceQuery/Trace";
 import { ErrorTypes } from "../../../types";
 import classNames from "classnames";
-import { useSnack } from "../../../contexts/Snackbar";
+import useCopyToClipboard from "../../../hooks/useCopyToClipboard";
 import { CopyIcon, RestartIcon } from "../../../components/Main/Icons";
 import useDeviceDetect from "../../../hooks/useDeviceDetect";
 
@@ -28,7 +28,7 @@ const JsonForm: FC<JsonFormProps> = ({
   onClose,
   onUpload,
 }) => {
-  const { showInfoMessage } = useSnack();
+  const copyToClipboard = useCopyToClipboard();
   const { isMobile } = useDeviceDetect();
 
   const [json, setJson] = useState(defaultJson);
@@ -58,8 +58,7 @@ const JsonForm: FC<JsonFormProps> = ({
   };
 
   const handlerCopy = async () => {
-    await navigator.clipboard.writeText(json);
-    showInfoMessage({ text: "Formatted JSON has been copied", type: "success" });
+    await copyToClipboard(json, "Formatted JSON has been copied");
   };
 
   const handleReset = () => {
diff --git a/app/vmui/packages/vmui/src/pages/TracePage/index.tsx b/app/vmui/packages/vmui/src/pages/TracePage/index.tsx
index b3e6429a0b..088f336ec7 100644
--- a/app/vmui/packages/vmui/src/pages/TracePage/index.tsx
+++ b/app/vmui/packages/vmui/src/pages/TracePage/index.tsx
@@ -12,21 +12,19 @@ import { ErrorTypes } from "../../types";
 import { useSearchParams } from "react-router-dom";
 import useDropzone from "../../hooks/useDropzone";
 import TraceUploadButtons from "./TraceUploadButtons/TraceUploadButtons";
+import useBoolean from "../../hooks/useBoolean";
 
 const TracePage: FC = () => {
-  const [openModal, setOpenModal] = useState(false);
   const [tracesState, setTracesState] = useState<Trace[]>([]);
   const [errors, setErrors] = useState<{filename: string, text: string}[]>([]);
   const hasTraces = useMemo(() => !!tracesState.length, [tracesState]);
   const [, setSearchParams] = useSearchParams();
 
-  const handleOpenModal = () => {
-    setOpenModal(true);
-  };
-
-  const handleCloseModal = () => {
-    setOpenModal(false);
-  };
+  const {
+    value: openModal,
+    setTrue: handleOpenModal,
+    setFalse: handleCloseModal,
+  } = useBoolean(false);
 
   const handleError = (e: Error, filename = "") => {
     setErrors(prev => [{ filename, text: `: ${e.message}` }, ...prev]);
@@ -84,7 +82,7 @@ const TracePage: FC = () => {
   }, []);
 
 
-  const { files, dragging } = useDropzone(document.body);
+  const { files, dragging } = useDropzone();
 
   useEffect(() => {
     handleReadFiles(files);