From 0caeac2dc2cac0f2fe3a021b9093769400b650d5 Mon Sep 17 00:00:00 2001 From: mohiit1502 Date: Thu, 13 Nov 2025 14:59:41 +0530 Subject: [PATCH] Recovered lost changes that restructured and better organized Layout component --- index.html | 14 + package-lock.json | 2566 +++++++++++++------------ package.json | 23 +- src/BuilderLayout.component.scss | 119 +- src/BuilderLayout.tsx | 826 +------- src/BuilderLayoutCanvas.tsx | 82 + src/BuilderLayoutContainer.tsx | 68 + src/BuilderSlot.component.scss | 54 - src/BuilderSlot.tsx | 156 +- src/Layout.context.tsx | 128 ++ src/Layout.tsx | 111 +- src/LayoutControlPanel.component.scss | 26 +- src/LayoutControlPanel.tsx | 388 ++-- src/LayoutError.tsx | 21 + src/LayoutHelp.tsx | 98 + src/README.md | 8 + src/ReleaseLayout.tsx | 57 +- src/ReleaseSlot.tsx | 39 +- src/Resizable.component.scss | 112 +- src/Resizable.tsx | 150 +- src/Slot.component.scss | 59 + src/Slot.tsx | 178 +- src/SlotTools.tsx | 258 +-- src/Test.tsx | 14 + src/hooks/useLayoutInit.ts | 60 + src/index.ts | 14 +- src/models/ComponentInfo.tsx | 29 + src/models/LayoutDescriptor.ts | 130 ++ src/models/SlotDescriptor.ts | 134 ++ src/models/index.ts | 3 + src/react-app-env.d.ts | 71 - src/services/Events.service.ts | 796 ++++++++ src/services/History.service.ts | 72 + src/services/Layout.service.ts | 593 ++++++ src/services/index.ts | 3 + src/test.scss | 2 + src/types.ts | 222 +++ src/utils.ts | 0 tsconfig.json | 10 +- vite-dev.config.ts | 21 + vite.config.ts | 2 + 41 files changed, 4689 insertions(+), 3028 deletions(-) create mode 100644 index.html mode change 100755 => 100644 src/BuilderLayout.component.scss mode change 100755 => 100644 src/BuilderLayout.tsx create mode 100644 src/BuilderLayoutCanvas.tsx create mode 100644 src/BuilderLayoutContainer.tsx delete mode 100755 src/BuilderSlot.component.scss mode change 100755 => 100644 src/BuilderSlot.tsx create mode 100644 src/Layout.context.tsx mode change 100755 => 100644 src/Layout.tsx mode change 100755 => 100644 src/LayoutControlPanel.component.scss mode change 100755 => 100644 src/LayoutControlPanel.tsx create mode 100644 src/LayoutError.tsx create mode 100644 src/LayoutHelp.tsx create mode 100644 src/README.md mode change 100755 => 100644 src/ReleaseLayout.tsx mode change 100755 => 100644 src/ReleaseSlot.tsx mode change 100755 => 100644 src/Resizable.component.scss mode change 100755 => 100644 src/Resizable.tsx create mode 100644 src/Slot.component.scss mode change 100755 => 100644 src/Slot.tsx mode change 100755 => 100644 src/SlotTools.tsx create mode 100644 src/Test.tsx create mode 100644 src/hooks/useLayoutInit.ts mode change 100755 => 100644 src/index.ts create mode 100644 src/models/ComponentInfo.tsx create mode 100644 src/models/LayoutDescriptor.ts create mode 100644 src/models/SlotDescriptor.ts create mode 100644 src/models/index.ts delete mode 100644 src/react-app-env.d.ts create mode 100644 src/services/Events.service.ts create mode 100644 src/services/History.service.ts create mode 100644 src/services/Layout.service.ts create mode 100644 src/services/index.ts create mode 100644 src/test.scss create mode 100644 src/types.ts create mode 100644 src/utils.ts create mode 100644 vite-dev.config.ts diff --git a/index.html b/index.html new file mode 100644 index 0000000..2d9ef7d --- /dev/null +++ b/index.html @@ -0,0 +1,14 @@ + + + + + + + React Redux App + + + +
+ + + diff --git a/package-lock.json b/package-lock.json index a470a8a..6ff7772 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,23 +1,24 @@ { "name": "@armco/layout", - "version": "0.0.6", + "version": "0.0.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@armco/layout", - "version": "0.0.6", + "version": "0.0.12", "license": "ISC", "dependencies": { - "@armco/icon": "^0.0.6", - "@armco/shared-components": "^0.0.53", - "@armco/types": "^0.0.11", - "@armco/utils": "^0.0.18", + "@armco/icon": "^0.0.13", + "@armco/shared-components": "^0.0.60", + "@armco/utils": "^0.0.31", + "bootstrap": "^5.3.8", "react": ">16.8.0", "react-dom": ">16.8.0", - "uuid": "^10.0.0" + "uuid": "^9.0.1" }, "devDependencies": { + "@armco/types": "^0.0.22", "@testing-library/dom": "^9.2.0", "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^14.0.0", @@ -26,7 +27,7 @@ "@types/react-dom": "^18.0.6", "@types/testing-library__jest-dom": "^5.14.5", "@types/uuid": "^10.0.0", - "@vitejs/plugin-react": "^4.0.0", + "@vitejs/plugin-react": "^5.1.0", "eslint": "^8.0.0", "eslint-config-react-app": "^7.0.1", "eslint-plugin-prettier": "^4.2.1", @@ -36,12 +37,13 @@ "prettier-config-nick": "^1.0.2", "sass": "^1.63.4", "typescript": "^5.0.2", - "vite": "^4.0.0", + "vite": "^7.2.2", "vite-plugin-dts": "^4.2.1", - "vite-plugin-externalize-deps": "^0.8.0", + "vite-plugin-externalize-deps": "^0.10.0", "vite-plugin-lib-inject-css": "^2.1.1", - "vite-plugin-svgr": "^4.2.0", - "vitest": "^0.30.1" + "vite-plugin-svgr": "^4.5.0", + "vite-tsconfig-paths": "^5.1.4", + "vitest": "^4.0.8" }, "peerDependencies": { "react": ">16.8.0", @@ -55,293 +57,77 @@ "dev": true, "license": "MIT" }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@armco/configs": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@armco/configs/-/configs-0.0.6.tgz", - "integrity": "sha512-kRd2+4oYsTJom6OAj0ZcqGgDjHfRyCtRFz9NOFwg7K+pTcHaXeKJ0QjZwB/+IBGn2xmPa+e2nexekkrUPqwBjw==", - "license": "ISC", - "dependencies": { - "@armco/types": "^0.0.10", - "uuid": "^10.0.0" - } - }, - "node_modules/@armco/configs/node_modules/@armco/types": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/@armco/types/-/types-0.0.10.tgz", - "integrity": "sha512-PKmehb5PsX6o6b3yaItCyDJxYy5nyXBduONnWv6slQwBMareFquGUcrCORPQhvnVLprCTs5aIZyPerZdjVuuxg==", - "license": "MIT" + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/@armco/configs/-/configs-0.0.15.tgz", + "integrity": "sha512-3KpjM7hJFvcMHg0Sw9YiRm9atji0+Mw122UAMRi705fchPU6aazogRWGDMZErsjffrwUUPmOZGclJCNu2e2R5g==", + "license": "ISC" }, "node_modules/@armco/icon": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@armco/icon/-/icon-0.0.6.tgz", - "integrity": "sha512-Huz7T6kdOIEXdODW3Ax4mfAkfp5+Fp+nte2lVYMTfBpoj0kbpieydhEZ+4YFwhYT7uLWb4B+OLUP17QHEmldDQ==", + "version": "0.0.13", + "resolved": "https://registry.npmjs.org/@armco/icon/-/icon-0.0.13.tgz", + "integrity": "sha512-ztAKq523Odfp36LH7jZAMyrKzB0rqAh2g2o6dCqpo7tgJ/CznFYhOs6YlXAlJPeg9y9Qt/RClbtcNpFLcu0sow==", "license": "ISC", "dependencies": { - "@armco/types": "^0.0.11", - "@armco/utils": "^0.0.17", - "react": ">16.8.0", - "react-dom": ">16.8.0" + "@armco/utils": "^0.0.31" }, "peerDependencies": { - "react": ">16.8.0", - "react-dom": ">16.8.0" + "react": "^18.2.0", + "react-dom": "^18.3.1" } }, - "node_modules/@armco/icon/node_modules/@armco/configs": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/@armco/configs/-/configs-0.0.7.tgz", - "integrity": "sha512-iniTmpR0kaOmRXAKw7cmXMyVnd1M+gOG/gNEOvmNAxRt8AuvW8WBra96o6oHnk0LFPgZhzmKSHvWzO1ADErxZQ==", - "license": "ISC", - "dependencies": { - "@armco/types": "^0.0.10", - "uuid": "^10.0.0" - } - }, - "node_modules/@armco/icon/node_modules/@armco/configs/node_modules/@armco/types": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/@armco/types/-/types-0.0.10.tgz", - "integrity": "sha512-PKmehb5PsX6o6b3yaItCyDJxYy5nyXBduONnWv6slQwBMareFquGUcrCORPQhvnVLprCTs5aIZyPerZdjVuuxg==", - "license": "MIT" - }, - "node_modules/@armco/icon/node_modules/@armco/utils": { - "version": "0.0.17", - "resolved": "https://registry.npmjs.org/@armco/utils/-/utils-0.0.17.tgz", - "integrity": "sha512-dPP+yJr5XaQdU7f3qRqsv33H0EqthvOkxz1lG5QK+GInqFN3+EjShOLswN2cQ084KZAoURGbhh9QXebrVpezBA==", - "license": "ISC", - "dependencies": { - "@armco/configs": "^0.0.7", - "@armco/types": "^0.0.9", - "d3": "^7.9.0", - "uuid": "^10.0.0" - }, - "peerDependencies": { - "react": ">16.8.1" - } - }, - "node_modules/@armco/icon/node_modules/@armco/utils/node_modules/@armco/types": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/@armco/types/-/types-0.0.9.tgz", - "integrity": "sha512-RLCt0Q20Nm52sTUcKVhjzeq7sbojgryEeqqChATOW6yAkWCL5NrQ2RLXpK4veePz1RLdu1eTsWVy5fMGe85qQw==", - "license": "MIT" - }, "node_modules/@armco/shared-components": { - "version": "0.0.53", - "resolved": "https://registry.npmjs.org/@armco/shared-components/-/shared-components-0.0.53.tgz", - "integrity": "sha512-iTj/BdJpgnGie2ur6zC5iSdATUrxEQ8mGmKdRFbvFgqkyPCB8+YzrqWDDPMm4g1w58jHNkzVABrUPN6ZsjeSQg==", + "version": "0.0.60", + "resolved": "https://registry.npmjs.org/@armco/shared-components/-/shared-components-0.0.60.tgz", + "integrity": "sha512-Jr8sSrIq+YV3LVsPBrh8YZfTbINf7DHNl4kCSeKx/zueXPimINNz8n6Nd8yk++cp+bAjbhuZUX0hG2QLr8dSQA==", "license": "ISC", "dependencies": { - "@armco/configs": "^0.0.6", - "@armco/icon": "^0.0.5", - "@armco/utils": "^0.0.16", - "@popperjs/core": "^2.11.8", + "@armco/configs": "^0.0.15", + "@armco/icon": "^0.0.13", + "@armco/utils": "^0.0.31", + "@tanstack/react-table": "^8.21.2", "bootstrap": "^5.3.0", - "classnames": "^2.3.2", - "d3": "^7.9.0", - "highcharts": "^11.2.0", - "highcharts-react-official": "^3.2.1", - "highlight.js": "^11.8.0", - "js-cookie": "^3.0.5", - "moment": "^2.29.4", + "react": ">=16.8.0", "react-app-polyfill": "^3.0.0", "react-bootstrap": "^2.7.4", "react-dev-utils": "^12.0.1", "react-dnd": ">=16.0.0", "react-dnd-html5-backend": ">=16.0.0", "react-dnd-touch-backend": ">=16.0.0", + "react-dom": "^18.2.0", "react-draggable": "^4.4.6", - "react-redux": "^8.0.1", "react-resizable": "^3.0.5", "react-router-dom": "^6.13.0", - "react-table": "^7.8.0", "resize-observer-polyfill": "^1.5.1", - "svgpath": "^2.6.0", "uuid": "^9.0.0" }, "peerDependencies": { - "react": ">=16.8.0", - "react-dnd": ">=16.0.0", - "react-dnd-html5-backend": ">=16.0.0", - "react-dnd-touch-backend": ">=16.0.0", - "react-redux": "^8.0.1", - "react-router-dom": "^6.13.0" - } - }, - "node_modules/@armco/shared-components/node_modules/@armco/icon": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/@armco/icon/-/icon-0.0.5.tgz", - "integrity": "sha512-4dZtzLcba9QqCLK1sDz+ToUGwHZPm3WgJYLjjsvzNv81cnvEsf5XMknh6YlYvWCrAFTfQkPRN9adTw5sP/k+PQ==", - "license": "ISC", - "dependencies": { - "@armco/types": "^0.0.11", - "@armco/utils": "^0.0.17", - "react": ">16.8.0", - "react-dom": ">16.8.0" - }, - "peerDependencies": { - "react": ">16.8.0", - "react-dom": ">16.8.0" - } - }, - "node_modules/@armco/shared-components/node_modules/@armco/icon/node_modules/@armco/configs": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/@armco/configs/-/configs-0.0.7.tgz", - "integrity": "sha512-iniTmpR0kaOmRXAKw7cmXMyVnd1M+gOG/gNEOvmNAxRt8AuvW8WBra96o6oHnk0LFPgZhzmKSHvWzO1ADErxZQ==", - "license": "ISC", - "dependencies": { - "@armco/types": "^0.0.10", - "uuid": "^10.0.0" - } - }, - "node_modules/@armco/shared-components/node_modules/@armco/icon/node_modules/@armco/configs/node_modules/@armco/types": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/@armco/types/-/types-0.0.10.tgz", - "integrity": "sha512-PKmehb5PsX6o6b3yaItCyDJxYy5nyXBduONnWv6slQwBMareFquGUcrCORPQhvnVLprCTs5aIZyPerZdjVuuxg==", - "license": "MIT" - }, - "node_modules/@armco/shared-components/node_modules/@armco/icon/node_modules/@armco/types": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/@armco/types/-/types-0.0.11.tgz", - "integrity": "sha512-8Z/XWq9VluHMNQmBIcUcZBCS9Pmt6/9DQPo+wau33fvJ2J0nvZBY8LnvohS1Ogvyg3rivZO7qcRhjy1+DJfl3Q==", - "license": "MIT" - }, - "node_modules/@armco/shared-components/node_modules/@armco/icon/node_modules/@armco/utils": { - "version": "0.0.17", - "resolved": "https://registry.npmjs.org/@armco/utils/-/utils-0.0.17.tgz", - "integrity": "sha512-dPP+yJr5XaQdU7f3qRqsv33H0EqthvOkxz1lG5QK+GInqFN3+EjShOLswN2cQ084KZAoURGbhh9QXebrVpezBA==", - "license": "ISC", - "dependencies": { - "@armco/configs": "^0.0.7", - "@armco/types": "^0.0.9", - "d3": "^7.9.0", - "uuid": "^10.0.0" - }, - "peerDependencies": { - "react": ">16.8.1" - } - }, - "node_modules/@armco/shared-components/node_modules/@armco/icon/node_modules/@armco/utils/node_modules/@armco/types": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/@armco/types/-/types-0.0.9.tgz", - "integrity": "sha512-RLCt0Q20Nm52sTUcKVhjzeq7sbojgryEeqqChATOW6yAkWCL5NrQ2RLXpK4veePz1RLdu1eTsWVy5fMGe85qQw==", - "license": "MIT" - }, - "node_modules/@armco/shared-components/node_modules/@armco/icon/node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@armco/shared-components/node_modules/@armco/types": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/@armco/types/-/types-0.0.9.tgz", - "integrity": "sha512-RLCt0Q20Nm52sTUcKVhjzeq7sbojgryEeqqChATOW6yAkWCL5NrQ2RLXpK4veePz1RLdu1eTsWVy5fMGe85qQw==", - "license": "MIT" - }, - "node_modules/@armco/shared-components/node_modules/@armco/utils": { - "version": "0.0.16", - "resolved": "https://registry.npmjs.org/@armco/utils/-/utils-0.0.16.tgz", - "integrity": "sha512-/97W84KiBAWjhd3lxBQxjtd9ufmSxCqjbwSFsBlOsdbjkW1CRsHXfyIw4CWGHyn0F5ncGZVGiu3dzp3iKgwVAw==", - "license": "ISC", - "dependencies": { - "@armco/configs": "^0.0.6", - "@armco/types": "^0.0.9", - "d3": "^7.9.0", - "uuid": "^10.0.0" - }, - "peerDependencies": { - "react": ">16.8.1" - } - }, - "node_modules/@armco/shared-components/node_modules/@armco/utils/node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@armco/shared-components/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" + "highlight.js": "^11.8.0", + "moment": "^2.29.4" } }, "node_modules/@armco/types": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/@armco/types/-/types-0.0.11.tgz", - "integrity": "sha512-8Z/XWq9VluHMNQmBIcUcZBCS9Pmt6/9DQPo+wau33fvJ2J0nvZBY8LnvohS1Ogvyg3rivZO7qcRhjy1+DJfl3Q==", + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/@armco/types/-/types-0.0.22.tgz", + "integrity": "sha512-yy0ppsJGDv+p6g8ClUM9Q+y1+1UWvkMXbK5DeT55f1tX6A7nPoeuVD0KiGAju4pUiBcA7+IVZCYBPQT2+QRagg==", + "dev": true, "license": "MIT" }, "node_modules/@armco/utils": { - "version": "0.0.18", - "resolved": "https://registry.npmjs.org/@armco/utils/-/utils-0.0.18.tgz", - "integrity": "sha512-4gvbDpYdEn0ikKEBdCXLFwjyR6DNBCrPDHiCLJoy2IFrhMktIEXmUn0F5ato9Q5xErs8gtBlHNyU0gPVvz34hg==", + "version": "0.0.31", + "resolved": "https://registry.npmjs.org/@armco/utils/-/utils-0.0.31.tgz", + "integrity": "sha512-K556l+cah6bpsQOK4geX35g9ZhbluG32PG8OZ4kaVMfsrf7UHs7zf5eQL3JUjvy3DVoMiqEj98Hz8Bil1Y8LFw==", "license": "ISC", "dependencies": { - "@armco/configs": "^0.0.7", - "@armco/types": "^0.0.9", - "d3": "^7.9.0", - "uuid": "^10.0.0" + "@armco/configs": "^0.0.15" }, "peerDependencies": { - "react": ">16.8.1" + "d3": "^7.9.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.18.2", + "uuid": "^9.0.0" } }, - "node_modules/@armco/utils/node_modules/@armco/configs": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/@armco/configs/-/configs-0.0.7.tgz", - "integrity": "sha512-iniTmpR0kaOmRXAKw7cmXMyVnd1M+gOG/gNEOvmNAxRt8AuvW8WBra96o6oHnk0LFPgZhzmKSHvWzO1ADErxZQ==", - "license": "ISC", - "dependencies": { - "@armco/types": "^0.0.10", - "uuid": "^10.0.0" - } - }, - "node_modules/@armco/utils/node_modules/@armco/configs/node_modules/@armco/types": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/@armco/types/-/types-0.0.10.tgz", - "integrity": "sha512-PKmehb5PsX6o6b3yaItCyDJxYy5nyXBduONnWv6slQwBMareFquGUcrCORPQhvnVLprCTs5aIZyPerZdjVuuxg==", - "license": "MIT" - }, - "node_modules/@armco/utils/node_modules/@armco/types": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/@armco/types/-/types-0.0.9.tgz", - "integrity": "sha512-RLCt0Q20Nm52sTUcKVhjzeq7sbojgryEeqqChATOW6yAkWCL5NrQ2RLXpK4veePz1RLdu1eTsWVy5fMGe85qQw==", - "license": "MIT" - }, "node_modules/@ast-grep/napi": { "version": "0.22.6", "resolved": "https://registry.npmjs.org/@ast-grep/napi/-/napi-0.22.6.tgz", @@ -499,22 +285,23 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", "license": "MIT", "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { - "version": "7.25.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", - "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", "dev": true, "license": "MIT", "engines": { @@ -522,22 +309,22 @@ } }, "node_modules/@babel/core": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", - "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.0", - "@babel/helper-compilation-targets": "^7.25.2", - "@babel/helper-module-transforms": "^7.25.2", - "@babel/helpers": "^7.25.0", - "@babel/parser": "^7.25.0", - "@babel/template": "^7.25.0", - "@babel/traverse": "^7.25.2", - "@babel/types": "^7.25.2", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -582,16 +369,17 @@ } }, "node_modules/@babel/generator": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", - "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.25.6", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" @@ -625,15 +413,15 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", - "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.25.2", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -698,6 +486,16 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", @@ -713,30 +511,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.25.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", - "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "@babel/traverse": "^7.25.2" + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" }, "engines": { "node": ">=6.9.0" @@ -759,9 +556,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", - "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", "dev": true, "license": "MIT", "engines": { @@ -833,9 +630,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", "engines": { @@ -843,18 +640,18 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "license": "MIT", "engines": { @@ -877,113 +674,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", - "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.6" + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "license": "MIT", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/parser": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", - "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.25.6" + "@babel/types": "^7.28.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -2238,13 +1949,13 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.7.tgz", - "integrity": "sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -2254,13 +1965,13 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.7.tgz", - "integrity": "sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -2670,70 +2381,83 @@ "license": "MIT" }, "node_modules/@babel/runtime": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", - "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", - "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", - "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.6", - "@babel/parser": "^7.25.6", - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.6", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", - "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ "arm" ], @@ -2744,13 +2468,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" ], @@ -2761,13 +2485,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" ], @@ -2778,13 +2502,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], @@ -2795,13 +2519,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], @@ -2812,13 +2536,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" ], @@ -2829,13 +2553,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], @@ -2846,13 +2570,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" ], @@ -2863,13 +2587,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" ], @@ -2880,13 +2604,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ "ia32" ], @@ -2897,13 +2621,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ "loong64" ], @@ -2914,13 +2638,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ "mips64el" ], @@ -2931,13 +2655,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ "ppc64" ], @@ -2948,13 +2672,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ "riscv64" ], @@ -2965,13 +2689,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ "s390x" ], @@ -2982,13 +2706,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" ], @@ -2999,13 +2723,30 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" ], @@ -3016,13 +2757,30 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "cpu": [ "x64" ], @@ -3033,13 +2791,30 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "cpu": [ "x64" ], @@ -3050,13 +2825,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "cpu": [ "arm64" ], @@ -3067,13 +2842,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "cpu": [ "ia32" ], @@ -3084,13 +2859,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "cpu": [ "x64" ], @@ -3101,7 +2876,7 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { @@ -3310,17 +3085,24 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -3332,15 +3114,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/source-map": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", @@ -3353,15 +3126,15 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -3675,16 +3448,23 @@ "react": ">=16.14.0" } }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.43", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.43.tgz", + "integrity": "sha512-5Uxg7fQUCmfhax7FJke2+8B6cqgeUJUD9o2uXIKXhD+mG0mL6NObmVoi9wXEU1tY89mZKgAYA6fTbftx3q2ZPQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/pluginutils": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.2.tgz", - "integrity": "sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", - "picomatch": "^2.3.1" + "picomatch": "^4.0.2" }, "engines": { "node": ">=14.0.0" @@ -3698,6 +3478,327 @@ } } }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.2.tgz", + "integrity": "sha512-yDPzwsgiFO26RJA4nZo8I+xqzh7sJTZIWQOxn+/XOdPE31lAvLIYCKqjV+lNH/vxE2L2iH3plKxDCRK6i+CwhA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.2.tgz", + "integrity": "sha512-k8FontTxIE7b0/OGKeSN5B6j25EuppBcWM33Z19JoVT7UTXFSo3D9CdU39wGTeb29NO3XxpMNauh09B+Ibw+9g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.2.tgz", + "integrity": "sha512-A6s4gJpomNBtJ2yioj8bflM2oogDwzUiMl2yNJ2v9E7++sHrSrsQ29fOfn5DM/iCzpWcebNYEdXpaK4tr2RhfQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.2.tgz", + "integrity": "sha512-e6XqVmXlHrBlG56obu9gDRPW3O3hLxpwHpLsBJvuI8qqnsrtSZ9ERoWUXtPOkY8c78WghyPHZdmPhHLWNdAGEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.2.tgz", + "integrity": "sha512-v0E9lJW8VsrwPux5Qe5CwmH/CF/2mQs6xU1MF3nmUxmZUCHazCjLgYvToOk+YuuUqLQBio1qkkREhxhc656ViA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.2.tgz", + "integrity": "sha512-ClAmAPx3ZCHtp6ysl4XEhWU69GUB1D+s7G9YjHGhIGCSrsg00nEGRRZHmINYxkdoJehde8VIsDC5t9C0gb6yqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.2.tgz", + "integrity": "sha512-EPlb95nUsz6Dd9Qy13fI5kUPXNSljaG9FiJ4YUGU1O/Q77i5DYFW5KR8g1OzTcdZUqQQ1KdDqsTohdFVwCwjqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.2.tgz", + "integrity": "sha512-BOmnVW+khAUX+YZvNfa0tGTEMVVEerOxN0pDk2E6N6DsEIa2Ctj48FOMfNDdrwinocKaC7YXUZ1pHlKpnkja/Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.2.tgz", + "integrity": "sha512-Xt2byDZ+6OVNuREgBXr4+CZDJtrVso5woFtpKdGPhpTPHcNG7D8YXeQzpNbFRxzTVqJf7kvPMCub/pcGUWgBjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.2.tgz", + "integrity": "sha512-+LdZSldy/I9N8+klim/Y1HsKbJ3BbInHav5qE9Iy77dtHC/pibw1SR/fXlWyAk0ThnpRKoODwnAuSjqxFRDHUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.2.tgz", + "integrity": "sha512-8ms8sjmyc1jWJS6WdNSA23rEfdjWB30LH8Wqj0Cqvv7qSHnvw6kgMMXRdop6hkmGPlyYBdRPkjJnj3KCUHV/uQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.2.tgz", + "integrity": "sha512-3HRQLUQbpBDMmzoxPJYd3W6vrVHOo2cVW8RUo87Xz0JPJcBLBr5kZ1pGcQAhdZgX9VV7NbGNipah1omKKe23/g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.2.tgz", + "integrity": "sha512-fMjKi+ojnmIvhk34gZP94vjogXNNUKMEYs+EDaB/5TG/wUkoeua7p7VCHnE6T2Tx+iaghAqQX8teQzcvrYpaQA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.2.tgz", + "integrity": "sha512-XuGFGU+VwUUV5kLvoAdi0Wz5Xbh2SrjIxCtZj6Wq8MDp4bflb/+ThZsVxokM7n0pcbkEr2h5/pzqzDYI7cCgLQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.2.tgz", + "integrity": "sha512-w6yjZF0P+NGzWR3AXWX9zc0DNEGdtvykB03uhonSHMRa+oWA6novflo2WaJr6JZakG2ucsyb+rvhrKac6NIy+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.2.tgz", + "integrity": "sha512-yo8d6tdfdeBArzC7T/PnHd7OypfI9cbuZzPnzLJIyKYFhAQ8SvlkKtKBMbXDxe1h03Rcr7u++nFS7tqXz87Gtw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.2.tgz", + "integrity": "sha512-ah59c1YkCxKExPP8O9PwOvs+XRLKwh/mV+3YdKqQ5AMQ0r4M4ZDuOrpWkUaqO7fzAHdINzV9tEVu8vNw48z0lA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.2.tgz", + "integrity": "sha512-4VEd19Wmhr+Zy7hbUsFZ6YXEiP48hE//KPLCSVNY5RMGX2/7HZ+QkN55a3atM1C/BZCGIgqN+xrVgtdak2S9+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.2.tgz", + "integrity": "sha512-IlbHFYc/pQCgew/d5fslcy1KEaYVCJ44G8pajugd8VoOEI8ODhtb/j8XMhLpwHCMB3yk2J07ctup10gpw2nyMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.2.tgz", + "integrity": "sha512-lNlPEGgdUfSzdCWU176ku/dQRnA7W+Gp8d+cWv73jYrb8uT7HTVVxq62DUYxjbaByuf1Yk0RIIAbDzp+CnOTFg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.2.tgz", + "integrity": "sha512-S6YojNVrHybQis2lYov1sd+uj7K0Q05NxHcGktuMMdIQ2VixGwAfbJ23NnlvvVV1bdpR2m5MsNBViHJKcA4ADw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.2.tgz", + "integrity": "sha512-k+/Rkcyx//P6fetPoLMb8pBeqJBNGx81uuf7iljX9++yNBVRDQgD04L+SVXmXmh5ZP4/WOp4mWF0kmi06PW2tA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -3888,6 +3989,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "dev": true, + "license": "MIT" + }, "node_modules/@svgr/babel-plugin-add-jsx-attribute": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", @@ -4155,6 +4263,39 @@ "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", "license": "0BSD" }, + "node_modules/@tanstack/react-table": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz", + "integrity": "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.21.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/@tanstack/table-core": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.21.3.tgz", + "integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@testing-library/dom": { "version": "9.3.4", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz", @@ -4315,26 +4456,27 @@ } }, "node_modules/@types/chai": { - "version": "4.3.20", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", - "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/chai-subset": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.5.tgz", - "integrity": "sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", "dev": true, "license": "MIT", "dependencies": { - "@types/chai": "*" + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", "license": "MIT" }, "node_modules/@types/hoist-non-react-statics": { @@ -4342,6 +4484,8 @@ "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@types/react": "*", "hoist-non-react-statics": "^3.3.0" @@ -4434,12 +4578,12 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.7.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.3.tgz", - "integrity": "sha512-qXKfhXXqGTyBskvWEzJZPUxSslAiLaB6JGP1ic/XTH9ctGgzdgYguuLP1C601aRTSDNlLb0jbKqXjZ48GNraSA==", + "version": "24.10.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.0.tgz", + "integrity": "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==", "license": "MIT", "dependencies": { - "undici-types": "~6.19.2" + "undici-types": "~7.16.0" } }, "node_modules/@types/parse-json": { @@ -4468,7 +4612,7 @@ "version": "18.3.0", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@types/react": "*" @@ -4507,12 +4651,6 @@ "@types/jest": "*" } }, - "node_modules/@types/use-sync-external-store": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", - "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==", - "license": "MIT" - }, "node_modules/@types/uuid": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", @@ -4830,111 +4968,159 @@ "license": "ISC" }, "node_modules/@vitejs/plugin-react": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz", - "integrity": "sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.0.tgz", + "integrity": "sha512-4LuWrg7EKWgQaMJfnN+wcmbAW+VSsCmqGohftWjuct47bv8uE4n/nPpq4XjJPsxgq00GGG5J8dvBczp8uxScew==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.24.5", - "@babel/plugin-transform-react-jsx-self": "^7.24.5", - "@babel/plugin-transform-react-jsx-source": "^7.24.1", + "@babel/core": "^7.28.4", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.43", "@types/babel__core": "^7.20.5", - "react-refresh": "^0.14.2" + "react-refresh": "^0.18.0" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^20.19.0 || >=22.12.0" }, "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0" + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "node_modules/@vitest/expect": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.30.1.tgz", - "integrity": "sha512-c3kbEtN8XXJSeN81iDGq29bUzSjQhjES2WR3aColsS4lPGbivwLtas4DNUe0jD9gg/FYGIteqOenfU95EFituw==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.8.tgz", + "integrity": "sha512-Rv0eabdP/xjAHQGr8cjBm+NnLHNoL268lMDK85w2aAGLFoVKLd8QGnVon5lLtkXQCoYaNL0wg04EGnyKkkKhPA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "0.30.1", - "@vitest/utils": "0.30.1", - "chai": "^4.3.7" + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.8", + "@vitest/utils": "4.0.8", + "chai": "^6.2.0", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.8.tgz", + "integrity": "sha512-9FRM3MZCedXH3+pIh+ME5Up2NBBHDq0wqwhOKkN4VnvCiKbVxddqH9mSGPZeawjd12pCOGnl+lo/ZGHt0/dQSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.0.8", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/mocker/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.8.tgz", + "integrity": "sha512-qRrjdRkINi9DaZHAimV+8ia9Gq6LeGz2CgIEmMLz3sBDYV53EsnLZbJMR1q84z1HZCMsf7s0orDgZn7ScXsZKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.30.1.tgz", - "integrity": "sha512-W62kT/8i0TF1UBCNMRtRMOBWJKRnNyv9RrjIgdUryEe0wNpGZvvwPDLuzYdxvgSckzjp54DSpv1xUbv4BQ0qVA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.8.tgz", + "integrity": "sha512-mdY8Sf1gsM8hKJUQfiPT3pn1n8RF4QBcJYFslgWh41JTfrK1cbqY8whpGCFzBl45LN028g0njLCYm0d7XxSaQQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "0.30.1", - "concordance": "^5.0.4", - "p-limit": "^4.0.0", - "pathe": "^1.1.0" - } - }, - "node_modules/@vitest/runner/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "@vitest/utils": "4.0.8", + "pathe": "^2.0.3" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/runner/node_modules/yocto-queue": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", - "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "node_modules/@vitest/runner/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, "node_modules/@vitest/snapshot": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.30.1.tgz", - "integrity": "sha512-fJZqKrE99zo27uoZA/azgWyWbFvM1rw2APS05yB0JaLwUIg9aUtvvnBf4q7JWhEcAHmSwbrxKFgyBUga6tq9Tw==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.8.tgz", + "integrity": "sha512-Nar9OTU03KGiubrIOFhcfHg8FYaRaNT+bh5VUlNz8stFhCZPNrJvmZkhsr1jtaYvuefYFwK2Hwrq026u4uPWCw==", "dev": true, "license": "MIT", "dependencies": { - "magic-string": "^0.30.0", - "pathe": "^1.1.0", - "pretty-format": "^27.5.1" + "@vitest/pretty-format": "4.0.8", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, + "node_modules/@vitest/snapshot/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/@vitest/spy": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.30.1.tgz", - "integrity": "sha512-YfJeIf37GvTZe04ZKxzJfnNNuNSmTEGnla2OdL60C8od16f3zOfv9q9K0nNii0NfjDJRt/CVN/POuY5/zTS+BA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.8.tgz", + "integrity": "sha512-nvGVqUunyCgZH7kmo+Ord4WgZ7lN0sOULYXUOYuHr55dvg9YvMz3izfB189Pgp28w0vWFbEEfNc/c3VTrqrXeA==", "dev": true, "license": "MIT", - "dependencies": { - "tinyspy": "^2.1.0" + "funding": { + "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/utils": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.30.1.tgz", - "integrity": "sha512-/c8Xv2zUVc+rnNt84QF0Y0zkfxnaGhp87K2dYJMLtLOIckPzuxLVzAtFCicGFdB4NeBHNzTRr1tNn7rCtQcWFA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.8.tgz", + "integrity": "sha512-pdk2phO5NDvEFfUTxcTP8RFYjVj/kfLSPIN5ebP2Mu9kcIMeAQTbknqcFEyBcC4z2pJlJI9aS5UQjcYfhmKAow==", "dev": true, "license": "MIT", "dependencies": { - "concordance": "^5.0.4", - "loupe": "^2.3.6", - "pretty-format": "^27.5.1" + "@vitest/pretty-format": "4.0.8", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, "node_modules/@volar/language-core": { @@ -5028,9 +5214,9 @@ } }, "node_modules/@vue/language-core/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5616,13 +5802,13 @@ "license": "MIT" }, "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "license": "MIT", "engines": { - "node": "*" + "node": ">=12" } }, "node_modules/ast-types-flow": { @@ -5792,17 +5978,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/blueimp-md5": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.19.0.tgz", - "integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==", - "dev": true, - "license": "MIT" - }, "node_modules/bootstrap": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", - "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz", + "integrity": "sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg==", "funding": [ { "type": "github", @@ -5819,9 +5998,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -5879,16 +6058,6 @@ "license": "MIT", "peer": true }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", @@ -5909,6 +6078,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -5952,22 +6135,13 @@ "license": "CC-BY-4.0" }, "node_modules/chai": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", - "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.0.tgz", + "integrity": "sha512-aUTnJc/JipRzJrNADXVvpVqi6CO0dn3nx4EVPxijri+fj3LUUDyZQOgVeW54Ob3Y1Xh9Iz8f+CgaCl8v0mn9bA==", "dev": true, "license": "MIT", - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.1.0" - }, "engines": { - "node": ">=4" + "node": ">=18" } }, "node_modules/chalk": { @@ -5986,19 +6160,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, "node_modules/chokidar": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", @@ -6092,6 +6253,7 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "license": "MIT", + "peer": true, "engines": { "node": ">= 10" } @@ -6116,39 +6278,6 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, - "node_modules/concordance": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/concordance/-/concordance-5.0.4.tgz", - "integrity": "sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==", - "dev": true, - "license": "ISC", - "dependencies": { - "date-time": "^3.1.0", - "esutils": "^2.0.3", - "fast-diff": "^1.2.0", - "js-string-escape": "^1.0.1", - "lodash": "^4.17.15", - "md5-hex": "^3.0.1", - "semver": "^7.3.2", - "well-known-symbols": "^2.0.0" - }, - "engines": { - "node": ">=10.18.0 <11 || >=12.14.0 <13 || >=14" - } - }, - "node_modules/concordance/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/confbox": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", @@ -6212,10 +6341,20 @@ "node": ">=10" } }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -6257,6 +6396,7 @@ "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", "license": "ISC", + "peer": true, "dependencies": { "d3-array": "3", "d3-axis": "3", @@ -6298,6 +6438,7 @@ "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", "license": "ISC", + "peer": true, "dependencies": { "internmap": "1 - 2" }, @@ -6310,6 +6451,7 @@ "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -6319,6 +6461,7 @@ "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", "license": "ISC", + "peer": true, "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", @@ -6335,6 +6478,7 @@ "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", "license": "ISC", + "peer": true, "dependencies": { "d3-path": "1 - 3" }, @@ -6347,6 +6491,7 @@ "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -6356,6 +6501,7 @@ "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", "license": "ISC", + "peer": true, "dependencies": { "d3-array": "^3.2.0" }, @@ -6368,6 +6514,7 @@ "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", "license": "ISC", + "peer": true, "dependencies": { "delaunator": "5" }, @@ -6380,6 +6527,7 @@ "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -6389,6 +6537,7 @@ "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", "license": "ISC", + "peer": true, "dependencies": { "d3-dispatch": "1 - 3", "d3-selection": "3" @@ -6402,6 +6551,7 @@ "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", "license": "ISC", + "peer": true, "dependencies": { "commander": "7", "iconv-lite": "0.6", @@ -6427,6 +6577,7 @@ "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", "license": "BSD-3-Clause", + "peer": true, "engines": { "node": ">=12" } @@ -6436,6 +6587,7 @@ "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", "license": "ISC", + "peer": true, "dependencies": { "d3-dsv": "1 - 3" }, @@ -6448,6 +6600,7 @@ "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", "license": "ISC", + "peer": true, "dependencies": { "d3-dispatch": "1 - 3", "d3-quadtree": "1 - 3", @@ -6462,6 +6615,7 @@ "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -6471,6 +6625,7 @@ "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", "license": "ISC", + "peer": true, "dependencies": { "d3-array": "2.5.0 - 3" }, @@ -6483,6 +6638,7 @@ "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -6492,6 +6648,7 @@ "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", "license": "ISC", + "peer": true, "dependencies": { "d3-color": "1 - 3" }, @@ -6504,6 +6661,7 @@ "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -6513,6 +6671,7 @@ "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -6522,6 +6681,7 @@ "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -6531,6 +6691,7 @@ "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -6540,6 +6701,7 @@ "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", "license": "ISC", + "peer": true, "dependencies": { "d3-array": "2.10.0 - 3", "d3-format": "1 - 3", @@ -6556,6 +6718,7 @@ "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", "license": "ISC", + "peer": true, "dependencies": { "d3-color": "1 - 3", "d3-interpolate": "1 - 3" @@ -6569,6 +6732,7 @@ "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -6578,6 +6742,7 @@ "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", "license": "ISC", + "peer": true, "dependencies": { "d3-path": "^3.1.0" }, @@ -6590,6 +6755,7 @@ "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", "license": "ISC", + "peer": true, "dependencies": { "d3-array": "2 - 3" }, @@ -6602,6 +6768,7 @@ "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", "license": "ISC", + "peer": true, "dependencies": { "d3-time": "1 - 3" }, @@ -6614,6 +6781,7 @@ "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -6623,6 +6791,7 @@ "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", "license": "ISC", + "peer": true, "dependencies": { "d3-color": "1 - 3", "d3-dispatch": "1 - 3", @@ -6642,6 +6811,7 @@ "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", "license": "ISC", + "peer": true, "dependencies": { "d3-dispatch": "1 - 3", "d3-drag": "2 - 3", @@ -6729,19 +6899,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/date-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/date-time/-/date-time-3.1.0.tgz", - "integrity": "sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "time-zone": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/de-indent": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", @@ -6750,9 +6907,9 @@ "license": "MIT" }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "devOptional": true, "license": "MIT", "dependencies": { @@ -6774,19 +6931,6 @@ "dev": true, "license": "MIT" }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/deep-equal": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", @@ -6886,6 +7030,7 @@ "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz", "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==", "license": "ISC", + "peer": true, "dependencies": { "robust-predicates": "^3.0.2" } @@ -7036,6 +7181,21 @@ "dev": true, "license": "0BSD" }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -7170,14 +7330,11 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, "engines": { "node": ">= 0.4" } @@ -7240,16 +7397,15 @@ } }, "node_modules/es-module-lexer": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", - "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", - "license": "MIT", - "peer": true + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "license": "MIT" }, "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, "license": "MIT", "dependencies": { @@ -7260,15 +7416,16 @@ } }, "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.4", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -7303,9 +7460,9 @@ } }, "node_modules/esbuild": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", - "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -7313,31 +7470,35 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/android-arm": "0.18.20", - "@esbuild/android-arm64": "0.18.20", - "@esbuild/android-x64": "0.18.20", - "@esbuild/darwin-arm64": "0.18.20", - "@esbuild/darwin-x64": "0.18.20", - "@esbuild/freebsd-arm64": "0.18.20", - "@esbuild/freebsd-x64": "0.18.20", - "@esbuild/linux-arm": "0.18.20", - "@esbuild/linux-arm64": "0.18.20", - "@esbuild/linux-ia32": "0.18.20", - "@esbuild/linux-loong64": "0.18.20", - "@esbuild/linux-mips64el": "0.18.20", - "@esbuild/linux-ppc64": "0.18.20", - "@esbuild/linux-riscv64": "0.18.20", - "@esbuild/linux-s390x": "0.18.20", - "@esbuild/linux-x64": "0.18.20", - "@esbuild/netbsd-x64": "0.18.20", - "@esbuild/openbsd-x64": "0.18.20", - "@esbuild/sunos-x64": "0.18.20", - "@esbuild/win32-arm64": "0.18.20", - "@esbuild/win32-ia32": "0.18.20", - "@esbuild/win32-x64": "0.18.20" + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" } }, "node_modules/escalade": { @@ -7921,6 +8082,16 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/expect-type": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", + "integrity": "sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -8262,15 +8433,26 @@ "node": ">= 10.0.0" } }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -8377,28 +8559,23 @@ "node": ">=6.9.0" } }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -8407,6 +8584,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-symbol-description": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", @@ -8470,9 +8661,9 @@ "peer": true }, "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8580,14 +8771,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.3" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8667,9 +8865,9 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "license": "MIT", "engines": { @@ -8718,27 +8916,12 @@ "he": "bin/he" } }, - "node_modules/highcharts": { - "version": "11.4.8", - "resolved": "https://registry.npmjs.org/highcharts/-/highcharts-11.4.8.tgz", - "integrity": "sha512-5Tke9LuzZszC4osaFisxLIcw7xgNGz4Sy3Jc9pRMV+ydm6sYqsPYdU8ELOgpzGNrbrRNDRBtveoR5xS3SzneEA==", - "license": "https://www.highcharts.com/license" - }, - "node_modules/highcharts-react-official": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/highcharts-react-official/-/highcharts-react-official-3.2.1.tgz", - "integrity": "sha512-hyQTX7ezCxl7JqumaWiGsroGWalzh24GedQIgO3vJbkGOZ6ySRAltIYjfxhrq4HszJOySZegotEF7v+haQ75UA==", - "license": "MIT", - "peerDependencies": { - "highcharts": ">=6.0.0", - "react": ">=16.8.0" - } - }, "node_modules/highlight.js": { "version": "11.10.0", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.10.0.tgz", "integrity": "sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==", "license": "BSD-3-Clause", + "peer": true, "engines": { "node": ">=12.0.0" } @@ -8927,6 +9110,7 @@ "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", "license": "ISC", + "peer": true, "engines": { "node": ">=12" } @@ -9667,25 +9851,6 @@ "dev": true, "license": "MIT" }, - "node_modules/js-cookie": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", - "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", - "license": "MIT", - "engines": { - "node": ">=14" - } - }, - "node_modules/js-string-escape": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", - "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -9752,16 +9917,16 @@ } }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-buffer": { @@ -9988,16 +10153,6 @@ "loose-envify": "cli.js" } }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.1" - } - }, "node_modules/lower-case": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", @@ -10036,26 +10191,23 @@ } }, "node_modules/magic-string": { - "version": "0.30.11", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", - "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" + "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/md5-hex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-3.0.1.tgz", - "integrity": "sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==", + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true, "license": "MIT", - "dependencies": { - "blueimp-md5": "^2.10.0" - }, "engines": { - "node": ">=8" + "node": ">= 0.4" } }, "node_modules/memfs": { @@ -10180,6 +10332,7 @@ "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", "license": "MIT", + "peer": true, "engines": { "node": "*" } @@ -10199,9 +10352,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, "funding": [ { @@ -10630,16 +10783,6 @@ "dev": true, "license": "MIT" }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -10647,9 +10790,9 @@ "license": "MIT" }, "node_modules/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "license": "ISC" }, "node_modules/picomatch": { @@ -10760,9 +10903,9 @@ } }, "node_modules/postcss": { - "version": "8.4.47", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", - "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, "funding": [ { @@ -10780,8 +10923,8 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.1.0", + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, "engines": { @@ -11184,55 +11327,10 @@ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", "license": "MIT" }, - "node_modules/react-redux": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.3.tgz", - "integrity": "sha512-n0ZrutD7DaX/j9VscF+uTALI3oUPa/pO4Z3soOBIjuRn/FzVu6aehhysxZCLi6y7duMf52WNZGMl7CtuK5EnRw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.12.1", - "@types/hoist-non-react-statics": "^3.3.1", - "@types/use-sync-external-store": "^0.0.3", - "hoist-non-react-statics": "^3.3.2", - "react-is": "^18.0.0", - "use-sync-external-store": "^1.0.0" - }, - "peerDependencies": { - "@types/react": "^16.8 || ^17.0 || ^18.0", - "@types/react-dom": "^16.8 || ^17.0 || ^18.0", - "react": "^16.8 || ^17.0 || ^18.0", - "react-dom": "^16.8 || ^17.0 || ^18.0", - "react-native": ">=0.59", - "redux": "^4 || ^5.0.0-beta.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - }, - "react-dom": { - "optional": true - }, - "react-native": { - "optional": true - }, - "redux": { - "optional": true - } - } - }, - "node_modules/react-redux/node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "license": "MIT" - }, "node_modules/react-refresh": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", - "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", "dev": true, "license": "MIT", "engines": { @@ -11284,19 +11382,6 @@ "react-dom": ">=16.8" } }, - "node_modules/react-table": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/react-table/-/react-table-7.8.0.tgz", - "integrity": "sha512-hNaz4ygkZO4bESeFfnfOft73iBUj8K5oKi1EcSHPAibEydfsX2MyU6Z8KCr3mv3C9Kqqh71U+DhZkFvibbnPbA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^16.8.3 || ^17.0.0-0 || ^18.0.0" - } - }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -11404,12 +11489,6 @@ "node": ">=4" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "license": "MIT" - }, "node_modules/regenerator-transform": { "version": "0.15.2", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", @@ -11582,22 +11661,48 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==", - "license": "Unlicense" + "license": "Unlicense", + "peer": true }, "node_modules/rollup": { - "version": "3.29.5", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", - "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", + "version": "4.53.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.2.tgz", + "integrity": "sha512-MHngMYwGJVi6Fmnk6ISmnk7JAHRNF0UkuucA0CUW3N3a4KnONPEZz+vUanQP/ZC/iY1Qkf3bwPWzyY84wEks1g==", "dev": true, "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, "bin": { "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=14.18.0", + "node": ">=18.0.0", "npm": ">=8.0.0" }, "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.53.2", + "@rollup/rollup-android-arm64": "4.53.2", + "@rollup/rollup-darwin-arm64": "4.53.2", + "@rollup/rollup-darwin-x64": "4.53.2", + "@rollup/rollup-freebsd-arm64": "4.53.2", + "@rollup/rollup-freebsd-x64": "4.53.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.53.2", + "@rollup/rollup-linux-arm-musleabihf": "4.53.2", + "@rollup/rollup-linux-arm64-gnu": "4.53.2", + "@rollup/rollup-linux-arm64-musl": "4.53.2", + "@rollup/rollup-linux-loong64-gnu": "4.53.2", + "@rollup/rollup-linux-ppc64-gnu": "4.53.2", + "@rollup/rollup-linux-riscv64-gnu": "4.53.2", + "@rollup/rollup-linux-riscv64-musl": "4.53.2", + "@rollup/rollup-linux-s390x-gnu": "4.53.2", + "@rollup/rollup-linux-x64-gnu": "4.53.2", + "@rollup/rollup-linux-x64-musl": "4.53.2", + "@rollup/rollup-openharmony-arm64": "4.53.2", + "@rollup/rollup-win32-arm64-msvc": "4.53.2", + "@rollup/rollup-win32-ia32-msvc": "4.53.2", + "@rollup/rollup-win32-x64-gnu": "4.53.2", + "@rollup/rollup-win32-x64-msvc": "4.53.2", "fsevents": "~2.3.2" } }, @@ -11635,7 +11740,8 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", - "license": "BSD-3-Clause" + "license": "BSD-3-Clause", + "peer": true }, "node_modules/safe-array-concat": { "version": "1.1.2", @@ -11983,9 +12089,9 @@ "license": "MIT" }, "node_modules/std-env": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", - "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", "dev": true, "license": "MIT" }, @@ -12252,19 +12358,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strip-literal": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz", - "integrity": "sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -12297,15 +12390,6 @@ "dev": true, "license": "MIT" }, - "node_modules/svgpath": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/svgpath/-/svgpath-2.6.0.tgz", - "integrity": "sha512-OIWR6bKzXvdXYyO4DK/UWa1VA1JeKq8E+0ug2DG98Y/vOmMpfZNj+TIG988HjfYSqtcy/hFOtZq/n/j5GSESNg==", - "license": "MIT", - "funding": { - "url": "https://github.com/fontello/svg2ttf?sponsor=1" - } - }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -12408,16 +12492,6 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "license": "MIT" }, - "node_modules/time-zone": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz", - "integrity": "sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -12425,36 +12499,71 @@ "dev": true, "license": "MIT" }, - "node_modules/tinypool": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.4.0.tgz", - "integrity": "sha512-2ksntHOKf893wSAH4z/+JbPpi92esw8Gn9N2deXX+B0EO92hexAVI9GIZZPx7P5aYo5KULfeOSt3kMOmSOy6uA==", + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" } }, - "node_modules/tinyspy": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", - "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -12496,6 +12605,27 @@ "node": ">=14" } }, + "node_modules/tsconfck": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", + "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", + "dev": true, + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -12558,16 +12688,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-detect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", - "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -12710,9 +12830,9 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -12819,19 +12939,10 @@ "requires-port": "^1.0.0" } }, - "node_modules/use-sync-external-store": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", - "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, "node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" @@ -12842,41 +12953,51 @@ } }, "node_modules/vite": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.5.tgz", - "integrity": "sha512-ifW3Lb2sMdX+WU91s3R0FyQlAyLxOzCSCP37ujw0+r5POeHPwe6udWVIElKQq8gk3t7b8rkmvqC6IHBpCff4GQ==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.2.tgz", + "integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.18.10", - "postcss": "^8.4.27", - "rollup": "^3.27.1" + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" }, "optionalDependencies": { - "fsevents": "~2.3.2" + "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": ">= 14", - "less": "*", + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -12886,6 +13007,9 @@ "sass": { "optional": true }, + "sass-embedded": { + "optional": true + }, "stylus": { "optional": true }, @@ -12894,33 +13018,15 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, - "node_modules/vite-node": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.30.1.tgz", - "integrity": "sha512-vTikpU/J7e6LU/8iM3dzBo8ZhEiKZEKRznEMm+mJh95XhWaPrJQraT/QsT2NWmuEf+zgAoMe64PKT7hfZ1Njmg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.3.4", - "mlly": "^1.2.0", - "pathe": "^1.1.0", - "picocolors": "^1.0.0", - "vite": "^3.0.0 || ^4.0.0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": ">=v14.18.0" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, "node_modules/vite-plugin-dts": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-4.2.2.tgz", @@ -12952,16 +13058,16 @@ } }, "node_modules/vite-plugin-externalize-deps": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/vite-plugin-externalize-deps/-/vite-plugin-externalize-deps-0.8.0.tgz", - "integrity": "sha512-MdC8kRNQ1ZjhUicU2HcqGVhL0UUFqv83Zp1JZdHjE82PoPR8wsSWZ3axpot7B6img3sW6g8shYJikE0CKA0chA==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/vite-plugin-externalize-deps/-/vite-plugin-externalize-deps-0.10.0.tgz", + "integrity": "sha512-eQrtpT/Do7AvDn76l1yL6ZHyXJ+UWH2LaHVqhAes9go54qaAnPZuMbgxcroQ/7WY3ZyetZzYW2quQnDF0DV5qg==", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/voracious" }, "peerDependencies": { - "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0" + "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, "node_modules/vite-plugin-lib-inject-css": { @@ -12980,78 +13086,136 @@ } }, "node_modules/vite-plugin-svgr": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.2.0.tgz", - "integrity": "sha512-SC7+FfVtNQk7So0XMjrrtLAbEC8qjFPifyD7+fs/E6aaNdVde6umlVVh0QuwDLdOMu7vp5RiGFsB70nj5yo0XA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vite-plugin-svgr/-/vite-plugin-svgr-4.5.0.tgz", + "integrity": "sha512-W+uoSpmVkSmNOGPSsDCWVW/DDAyv+9fap9AZXBvWiQqrboJ08j2vh0tFxTD/LjwqwAd3yYSVJgm54S/1GhbdnA==", "dev": true, "license": "MIT", "dependencies": { - "@rollup/pluginutils": "^5.0.5", + "@rollup/pluginutils": "^5.2.0", "@svgr/core": "^8.1.0", "@svgr/plugin-jsx": "^8.1.0" }, "peerDependencies": { - "vite": "^2.6.0 || 3 || 4 || 5" + "vite": ">=2.6.0" } }, - "node_modules/vitest": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.30.1.tgz", - "integrity": "sha512-y35WTrSTlTxfMLttgQk4rHcaDkbHQwDP++SNwPb+7H8yb13Q3cu2EixrtHzF27iZ8v0XCciSsLg00RkPAzB/aA==", + "node_modules/vite-tsconfig-paths": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz", + "integrity": "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==", "dev": true, "license": "MIT", "dependencies": { - "@types/chai": "^4.3.4", - "@types/chai-subset": "^1.3.3", - "@types/node": "*", - "@vitest/expect": "0.30.1", - "@vitest/runner": "0.30.1", - "@vitest/snapshot": "0.30.1", - "@vitest/spy": "0.30.1", - "@vitest/utils": "0.30.1", - "acorn": "^8.8.2", - "acorn-walk": "^8.2.0", - "cac": "^6.7.14", - "chai": "^4.3.7", - "concordance": "^5.0.4", - "debug": "^4.3.4", - "local-pkg": "^0.4.3", - "magic-string": "^0.30.0", - "pathe": "^1.1.0", - "picocolors": "^1.0.0", - "source-map": "^0.6.1", - "std-env": "^3.3.2", - "strip-literal": "^1.0.1", - "tinybench": "^2.4.0", - "tinypool": "^0.4.0", - "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.30.1", - "why-is-node-running": "^2.2.2" + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^3.0.3" + }, + "peerDependencies": { + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vitest": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.8.tgz", + "integrity": "sha512-urzu3NCEV0Qa0Y2PwvBtRgmNtxhj5t5ULw7cuKhIHh3OrkKTLlut0lnBOv9qe5OvbkMH2g38G7KPDCTpIytBVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.0.8", + "@vitest/mocker": "4.0.8", + "@vitest/pretty-format": "4.0.8", + "@vitest/runner": "4.0.8", + "@vitest/snapshot": "4.0.8", + "@vitest/spy": "4.0.8", + "@vitest/utils": "4.0.8", + "debug": "^4.4.3", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" }, "bin": { "vitest": "vitest.mjs" }, "engines": { - "node": ">=v14.18.0" + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" }, "funding": { - "url": "https://github.com/sponsors/antfu" + "url": "https://opencollective.com/vitest" }, "peerDependencies": { "@edge-runtime/vm": "*", - "@vitest/browser": "*", - "@vitest/ui": "*", + "@types/debug": "^4.1.12", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.8", + "@vitest/browser-preview": "4.0.8", + "@vitest/browser-webdriverio": "4.0.8", + "@vitest/ui": "4.0.8", "happy-dom": "*", - "jsdom": "*", - "playwright": "*", - "safaridriver": "*", - "webdriverio": "*" + "jsdom": "*" }, "peerDependenciesMeta": { "@edge-runtime/vm": { "optional": true }, - "@vitest/browser": { + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { "optional": true }, "@vitest/ui": { @@ -13062,29 +13226,27 @@ }, "jsdom": { "optional": true - }, - "playwright": { - "optional": true - }, - "safaridriver": { - "optional": true - }, - "webdriverio": { - "optional": true } } }, - "node_modules/vitest/node_modules/local-pkg": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", - "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "node_modules/vitest/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=14" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/antfu" + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/vscode-uri": { @@ -13250,16 +13412,6 @@ "node": ">=6" } }, - "node_modules/well-known-symbols": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/well-known-symbols/-/well-known-symbols-2.0.0.tgz", - "integrity": "sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=6" - } - }, "node_modules/whatwg-encoding": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", @@ -13582,12 +13734,18 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "dev": true, "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, "engines": { - "node": ">= 6" + "node": ">= 14.6" } }, "node_modules/yocto-queue": { diff --git a/package.json b/package.json index c67ff9e..5be2eac 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "module": "build/es/index.js", "types": "build/types/index.d.ts", "scripts": { + "dev": "vite --config vite-dev.config.ts", "build": "./build-tools/build.sh", "format": "prettier --write .", "lint": "eslint .", @@ -13,15 +14,16 @@ "publish:local": "./publish-local.sh" }, "dependencies": { - "@armco/icon": "^0.0.6", - "@armco/shared-components": "^0.0.53", - "@armco/types": "^0.0.11", - "@armco/utils": "^0.0.18", + "@armco/icon": "^0.0.13", + "@armco/shared-components": "^0.0.60", + "@armco/utils": "^0.0.31", + "bootstrap": "^5.3.8", "react": ">16.8.0", "react-dom": ">16.8.0", - "uuid": "^10.0.0" + "uuid": "^9.0.1" }, "devDependencies": { + "@armco/types": "^0.0.22", "@testing-library/dom": "^9.2.0", "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^14.0.0", @@ -30,7 +32,7 @@ "@types/react-dom": "^18.0.6", "@types/testing-library__jest-dom": "^5.14.5", "@types/uuid": "^10.0.0", - "@vitejs/plugin-react": "^4.0.0", + "@vitejs/plugin-react": "^5.1.0", "eslint": "^8.0.0", "eslint-config-react-app": "^7.0.1", "eslint-plugin-prettier": "^4.2.1", @@ -40,12 +42,13 @@ "prettier-config-nick": "^1.0.2", "sass": "^1.63.4", "typescript": "^5.0.2", - "vite": "^4.0.0", + "vite": "^7.2.2", "vite-plugin-dts": "^4.2.1", - "vite-plugin-externalize-deps": "^0.8.0", + "vite-plugin-externalize-deps": "^0.10.0", "vite-plugin-lib-inject-css": "^2.1.1", - "vite-plugin-svgr": "^4.2.0", - "vitest": "^0.30.1" + "vite-plugin-svgr": "^4.5.0", + "vite-tsconfig-paths": "^5.1.4", + "vitest": "^4.0.8" }, "eslintConfig": { "extends": [ diff --git a/src/BuilderLayout.component.scss b/src/BuilderLayout.component.scss old mode 100755 new mode 100644 index 9a34915..4d19c0a --- a/src/BuilderLayout.component.scss +++ b/src/BuilderLayout.component.scss @@ -1,55 +1,68 @@ -.ar-BuilderLayout { - &.hide-controls > .ar-Layout__canvas > .ar-Layout__grid-tools { - grid-template: "grid" auto / auto; - } - .ar-Layout__help-panel { - transition: all 0.5s; - max-height: 0; - opacity: 0; - - &.show { - max-height: 2rem; - opacity: 1; - background-color: var(--ar-color-selected); - } - } - +.ar-BuilderLayout.hide-controls { + > .ar-Layout__canvas > .ar-Layout__grid-tools { + grid-template: "grid" auto/auto; + } + .ar-Layout__help-panel { + transition: all 0.5s; + max-height: 0; + opacity: 0; + &.show { + max-height: 2rem; + opacity: 1; + background-color: var(--ar-color-selected); + } + } .ar-Layout__grid-tools { - grid-template: ". colMod" 1.5rem "rowMod grid" 1fr / 1.5rem auto; - - .ar-Layout__row-tools { - grid-area: rowMod; - } - .ar-Layout__col-tools { - grid-area: colMod; - } - .ar-Layout__grid-tools__main, .ar-Layout__col-tools, .ar-Layout__row-tools { - background-color: var(--ar-bg); - } - .ar-Layout__grid { - grid-area: grid; - } - .row-controller-cell, .column-controller-cell { - .delete-row, .delete-column { - display: none; - } - .delete-row { - bottom: 0.25rem; - left: 0.2rem; - } - .delete-column { - right: 0.25rem; - top: 0.2rem; - } - &:hover { - background-color: var(--ar-bg-hover-4); - .delete-row, .delete-column { - display: inline-block; - } - } - &.selected { - background-color: #03a9f4; - } - } - } + grid-template: ". colMod" 1.5rem "rowMod grid" 1fr/1.5rem auto; + .ar-Layout__row-tools { + grid-area: rowMod; + } + .ar-Layout__col-tools { + grid-area: colMod; + } + .ar-Layout__grid-tools__main, + .ar-Layout__col-tools, + .ar-Layout__row-tools { + background-color: var(--ar-bg); + } + .ar-Layout__grid { + grid-area: grid; + } + .row-controller-cell { + .delete-row { + display: none; + } + &:hover { + background-color: var(--ar-bg-hover-4); + .delete-row { + display: inline-block; + } + } + &.selected { + background-color: #03a9f4; + } + } + .column-controller-cell { + .delete-column { + display: none; + } + &:hover { + background-color: var(--ar-bg-hover-4); + .delete-column { + display: inline-block; + } + } + &.selected { + background-color: #03a9f4; + } + } + .delete-row { + bottom: 0.25rem; + left: 0.2rem; + } + .delete-column { + right: 0.25rem; + top: 0.2rem; + } + } } diff --git a/src/BuilderLayout.tsx b/src/BuilderLayout.tsx old mode 100755 new mode 100644 index 2f9bd3e..cdf9d36 --- a/src/BuilderLayout.tsx +++ b/src/BuilderLayout.tsx @@ -1,778 +1,68 @@ -import { useEffect, useMemo, useRef, useState } from "react" -import { v4 as uuid } from "uuid" -import { - ArPopoverSlots, - ArSlotViewMode, - ArThemes, - BuilderLayoutProps, - GridToolbarSpecs, - SlotDescriptor, - SlotProps, -} from "@armco/types" -import Icon from "@armco/icon" -import Tooltip from "@armco/shared-components/Tooltip" -import { useTheme, useStateWithHistory } from "@armco/utils/hooks" -import { calculateRowHeights, checkIfAdjacent, generateGridAreaAndSizes, generateGridTemplate, generateGridToolbarSpecs, generateSlotConfigs, insertDimension, mergeHandler, removeHandler, selectCellsInSelectedRowCol, splitHandler } from "@armco/utils/gridHelper" -import { getDocumentElement, getWindowElement } from "@armco/utils/domHelper" +import { FC } from "react" +import { ArSlotViewMode } from "@armco/shared-components/enums" +import { SlotDescriptor } from "@models" +import { useLayoutContext } from "./Layout.context" +import type { LayoutProps } from "./types" +import BuilderLayoutContainer from "./BuilderLayoutContainer" +import BuilderLayoutCanvas from "./BuilderLayoutCanvas" import Slot from "./Slot" -import LayoutControlPanel from "./LayoutControlPanel" import "./BuilderLayout.component.scss" -const BuilderLayout = ({ - acceptTextOnClick, - classes, - colWidths: externalColWidths, - demo, - displayMode, - hideBuildModePaddings, - isChild, - lastSelected: externalLastSelected, - mode, - slotDropHandler, - onLayoutChange, - onSlotSelect: onExternalSlotSelect, - gridSpecs, - gridTemplate: externalGridTemplate, - rowHeights: externalRowHeights, - showControls: externalShowControls, - showPanels, - slots: externalSlots, - slotRenderer, -}: BuilderLayoutProps) => { - const layoutRef = useRef(null) - const ctrlPanelRef = useRef(null) - const helpPanelRef = useRef(null) - const specUpdateAction = useRef(true) - const [panelsDisplayed, displayPanels] = useState() - const [rowHeights, setRowHeights] = useState>() - const [colWidths, setColWidths] = useState>() - const [showControls, setShowControls] = useState() - const [gridArea, setGridArea] = useState>>() - const [gridTemplate, setGridTemplate] = useState() - const [gridToolbarSpecs, setGridToolbarSpecs] = useState() - const [slots, setSlots, undoSlots, redoSlots, canUndo, canRedo] = - useStateWithHistory>() - const [prevSlotCount, setPrevSlotsCount] = useState() - const [mergeEnabled, enableMerge] = useState() - const [splitEnabled, enableSplit] = useState() - const [lastSelected, setLastSelected] = useState() - const [selectionOnlyModeEnabled, enableSelectionOnlyMode] = - useState() - const [minMaxSelections, setMinMaxSelections] = useState<{ - minRow: number - maxRow: number - minColumn: number - maxColumn: number - }>() - const {theme} = useTheme() - const cmdCtrl = useMemo( - () => ( - <> - / - - - ), - [], - ) - const isGrid = !displayMode || displayMode === "grid" +// Props specific to the BuilderLayout view extracted from runtime function 'k' +export interface BuilderLayoutProps extends Pick { } - useEffect(() => { - const doc = getDocumentElement(demo) - const handleKeyDown = (event: KeyboardEvent) => { - if (showControls) { - if ((event.ctrlKey || event.metaKey) && event.key === "z") { - event.preventDefault() - undoSlots() - } else if ((event.ctrlKey || event.metaKey) && event.key === "y") { - event.preventDefault() - redoSlots() - } else if ((event.ctrlKey || event.metaKey) && event.key === "m") { - if (mergeEnabled && slots && minMaxSelections) { - mergeHandler(setSlots, slots, minMaxSelections) - } - } else if ((event.ctrlKey || event.metaKey) && event.key === "h") { - if (splitEnabled && slots) { - splitHandler(setSlots, slots, "horizontal", "after") - } - } else if ((event.ctrlKey || event.metaKey) && event.key === "v") { - if (splitEnabled && slots) { - splitHandler(setSlots, slots, "vertical", "after") - } - } else if ((event.ctrlKey || event.metaKey) && event.key === "r") { - if (splitEnabled && slots && gridToolbarSpecs) { - insertDimension( - "row", - gridToolbarSpecs, - slots, - setSlots, - "after", - ) - } - } else if ((event.ctrlKey || event.metaKey) && event.key === "c") { - if (splitEnabled && slots && gridToolbarSpecs) { - insertDimension( - "column", - gridToolbarSpecs, - slots, - setSlots, - "after", - ) - } - } - } - } +const BuilderLayout: FC = (props) => { + const { + classes, + displayMode, + hideBuildModePaddings, + isChild, + mode, + slotDropHandler, + onSlotSelect, + slotRenderer, + } = props + const { layoutService, controlsEnabled } = useLayoutContext() - doc?.addEventListener("keydown", handleKeyDown) + // From runtime: displayMode undefined or 'grid' => treat as grid layout + const isGridDisplay = !displayMode || displayMode === "grid" + const slots: SlotDescriptor[] | undefined = layoutService?.slots + const gridToolbarSpecs = layoutService?.gridToolbarSpecs - return () => { - doc?.removeEventListener("keydown", handleKeyDown) - } - }, [ - demo, - gridToolbarSpecs, - mergeEnabled, - minMaxSelections, - redoSlots, - showControls, - slots, - splitEnabled, - undoSlots, - ]) + if (!slots || !gridToolbarSpecs) return null - useEffect(() => { - setRowHeights(externalRowHeights) - setColWidths(externalColWidths || "1fr") - }, [externalRowHeights, externalColWidths]) - - useEffect(() => { - displayPanels(showPanels) - }, [showPanels]) - - useEffect(() => { - setShowControls(externalShowControls) - }, [externalShowControls]) - - useEffect(() => setLastSelected(externalLastSelected), [externalLastSelected]) - - useEffect(() => { - if (externalSlots) { - JSON.stringify(externalSlots) !== JSON.stringify(slots) && - setSlots(externalSlots) - } else if (externalGridTemplate) { - const { slotConfigs } = - generateSlotConfigs(externalGridTemplate) - setSlots(slotConfigs) - } else if (gridSpecs) { - let parsedGridSpecs = gridSpecs - if (typeof gridSpecs === "string") { - try { - parsedGridSpecs = JSON.parse(gridSpecs) - } catch { - console.warn("Grid Specs passed as string but incorrect JSON format") - return - } - } - if ( - typeof parsedGridSpecs === "object" && - "rows" in parsedGridSpecs && - "columns" in parsedGridSpecs - ) { - const slots: Array = [] - for (let i = 0; i < parsedGridSpecs.rows; i++) { - for (let j = 0; j < parsedGridSpecs.columns; j++) { - const slotId = uuid() - const gridArea = `ga-${slotId}` - slots.push({ - slot: slotId, - row: i, - column: j, - rowSpan: 1, - colSpan: 1, - gridArea, - }) - } - } - setSlots(slots) - } - } - }, [gridSpecs, externalGridTemplate, externalSlots]) - - useEffect(() => { - if (slots) { - if (slots.length !== prevSlotCount) { - const { gridArea, rowHeights } = generateGridAreaAndSizes( - slots, - externalRowHeights, - ) - setGridArea(gridArea) - setRowHeights(rowHeights) - setPrevSlotsCount(slots.length) - } - const { areAdjacent, ...rest } = checkIfAdjacent(slots) - setMinMaxSelections(rest) - enableSplit(slots.filter((sc) => sc.isSelected).length >= 1) - enableMerge(areAdjacent) - } - }, [slots, prevSlotCount, externalRowHeights]) - - useEffect(() => { - if (gridArea) { - const gridTemplate = generateGridTemplate( - gridArea, - rowHeights, - colWidths, - ) - setGridTemplate(gridTemplate) - onLayoutChange && onLayoutChange(gridTemplate, slots) - } - }, [gridArea, rowHeights, colWidths]) - - useEffect(() => { - if (gridArea && showControls && slots) { - if (specUpdateAction.current) { - setTimeout(() => { - requestAnimationFrame(() => { - const calculatedRowHeights = calculateRowHeights( - slots, - rowHeights, - demo, - ) - setGridToolbarSpecs( - generateGridToolbarSpecs( - gridArea, - calculatedRowHeights, - colWidths, - ), - ) - }) - }, 10) - } - } - }, [slots, gridArea, showControls, rowHeights, colWidths]) - - useEffect(() => { - if (panelsDisplayed) { - const thisRect = layoutRef.current?.getBoundingClientRect() - if (thisRect) { - if (helpPanelRef.current) { - helpPanelRef.current.style.top = thisRect.bottom + "px" - helpPanelRef.current.style.left = thisRect.left + "px" - helpPanelRef.current.style.width = thisRect.width + "px" - } - if (ctrlPanelRef.current) { - const winObj = getWindowElement(demo) - ctrlPanelRef.current.style.bottom = - (winObj ? winObj.innerHeight - thisRect.top : 0) + "px" - ctrlPanelRef.current.style.left = thisRect.left + "px" - } - } - setTimeout(() => { - const ctrlPanelRect = ctrlPanelRef.current?.getBoundingClientRect() - if (thisRect && ctrlPanelRef.current && helpPanelRef.current) { - if (ctrlPanelRect && ctrlPanelRect.width > thisRect.width) { - ctrlPanelRef.current.style.width = thisRect.width + "px" - ctrlPanelRef.current.style.overflow = "auto" - } - } - }, 500) - } - }, [panelsDisplayed, showControls, demo]) - - const onSlotSelect = (slotConfig: SlotDescriptor) => { - const slotsClone = [...(slots || [])] - specUpdateAction.current = true - const matchedSlotConfig = slots?.find((sc) => sc.slot === slotConfig.slot) - matchedSlotConfig && - (matchedSlotConfig.isSelected = !matchedSlotConfig.isSelected) - setLastSelected(matchedSlotConfig) - // Add Text in empty slot - if (acceptTextOnClick && matchedSlotConfig && !matchedSlotConfig?.content) { - if (!matchedSlotConfig.props) { - matchedSlotConfig.props = {} - } - // matchedSlotConfig.props.classes = "p-2" - matchedSlotConfig.content = { - name: "Text", - description: - "Foundational text component, that accepts classes and style attributes to create varying types of other text components", - source: "stuffle", - componentName: "Text", - props: { - classes: "w-100", - id: matchedSlotConfig.slot, - style: { minHeight: "1.5rem", lineHeight: "1.5rem" }, - isEditable: true, - }, - } - } - setSlots(slotsClone, true) - onExternalSlotSelect && onExternalSlotSelect(slotConfig) - } - - const onRowSelect = ( - slotConfig: SlotDescriptor, - // When cross on a row tool cell is clicked, this flag will be true - selectForDelete?: boolean, - ) => { - specUpdateAction.current = false - if (gridToolbarSpecs) { - const rowSlots = gridToolbarSpecs.rowTools.slots - const selectedRow = rowSlots.find((slot) => slot.slot === slotConfig.slot) - if (selectedRow) { - if (selectForDelete !== undefined) - selectedRow.isSelectedForInlineDelete = selectForDelete - else selectedRow.isSelected = !selectedRow.isSelected - } - setGridToolbarSpecs({ ...gridToolbarSpecs }) - slots && - setTimeout( - () => - setSlots( - selectCellsInSelectedRowCol( - gridToolbarSpecs, - slots, - selectForDelete, - ), - true, - ), - 10, - ) - } - } - - const onColumnSelect = ( - slotConfig: SlotDescriptor, - selectForDelete?: boolean, - ) => { - specUpdateAction.current = false - if (gridToolbarSpecs) { - const colSlots = gridToolbarSpecs.colTools.slots - const selectedColumn = colSlots.find( - (slot) => slot.slot === slotConfig.slot, - ) - if (selectedColumn) { - if (selectForDelete !== undefined) - selectedColumn.isSelectedForInlineDelete = selectForDelete - else selectedColumn.isSelected = !selectedColumn.isSelected - } - setGridToolbarSpecs({ ...gridToolbarSpecs }) - slots && - setSlots( - selectCellsInSelectedRowCol( - gridToolbarSpecs, - slots, - selectForDelete, - ), - true, - ) - } - } - - const onRowDelete = (isInlineDelete?: boolean) => { - specUpdateAction.current = false - slots && - gridToolbarSpecs && - setSlots( - removeHandler( - slots, - gridToolbarSpecs, - "row", - isInlineDelete, - ), - ) - } - - const onColumnDelete = (isInlineDelete?: boolean) => { - specUpdateAction.current = false - slots && - gridToolbarSpecs && - setSlots( - removeHandler( - slots, - gridToolbarSpecs, - "column", - isInlineDelete, - ), - ) - } - - const rowToolSlots = gridToolbarSpecs?.rowTools.slots - const colToolSlots = gridToolbarSpecs?.colTools.slots - - return ( -
{ - e.stopPropagation() - !isChild && isGrid && displayPanels(true) - }} - onMouseLeave={(e) => { - e.stopPropagation() - !isChild && isGrid && displayPanels(false) - }} - > - {!isChild && isGrid && ( - s.isSelected) > -1 - } - columnDeleteEnabled={ - colToolSlots && colToolSlots.findIndex((s) => s.isSelected) > -1 - } - horizontalSplitHandler={() => - slots && - splitHandler(setSlots, slots, "horizontal", "after") - } - verticalSplitHandler={() => - slots && - splitHandler(setSlots, slots, "vertical", "after") - } - mergeHandler={() => { - slots && - minMaxSelections && - mergeHandler(setSlots, slots, minMaxSelections) - enableMerge(false) - }} - rowInsertHandler={(placement: "before" | "after") => - slots && - gridToolbarSpecs && - insertDimension( - "row", - gridToolbarSpecs, - slots, - setSlots, - placement, - ) - } - columnInsertHandler={(placement: "before" | "after") => - slots && - gridToolbarSpecs && - insertDimension( - "column", - gridToolbarSpecs, - slots, - setSlots, - placement, - ) - } - rowDeleteHandler={() => onRowDelete()} - columnDeleteHandler={() => onColumnDelete()} - undoHandler={undoSlots} - redoHandler={redoSlots} - enableSelectionOnlyMode={enableSelectionOnlyMode} - /> - )} -
- {slots && ( -
- {showControls && !isChild && isGrid && ( - <> -
-
- {gridToolbarSpecs?.rowTools.slots.map( - (slotConfig, index, arr) => ( - - { - onRowSelect(slotConfig) - onExternalSlotSelect && - onExternalSlotSelect(slotConfig, "row") - }} - controlsEnabled={showControls} - selectionOnlyModeEnabled={selectionOnlyModeEnabled} - isLast={index === arr.length - 1} - rowDeleteHandler={() => onRowDelete(true)} - rowInsertHandler={(placement: "before" | "after") => - slots && - gridToolbarSpecs && - insertDimension( - "row", - gridToolbarSpecs, - slots, - setSlots, - placement, - ) - } - rowSelectHandler={(isEntering: boolean) => - onRowSelect(slotConfig, isEntering) - } - /> - - ), - )} -
-
- {gridToolbarSpecs?.colTools.slots.map( - (slotConfig, index, arr) => ( - - { - onColumnSelect(slotConfig) - onExternalSlotSelect && - onExternalSlotSelect(slotConfig, "column") - }} - controlsEnabled={showControls} - selectionOnlyModeEnabled={selectionOnlyModeEnabled} - isLast={index === arr.length - 1} - columnDeleteHandler={() => onColumnDelete(true)} - columnInsertHandler={( - placement: "before" | "after", - ) => - slots && - gridToolbarSpecs && - insertDimension( - "column", - gridToolbarSpecs, - slots, - setSlots, - placement, - ) - } - columnSelectHandler={(isEntering: boolean) => - onColumnSelect(slotConfig, isEntering) - } - /> - - ), - )} -
- - )} -
- {slots.map((sConfig) => { - const props: SlotProps = { - demo, - config: sConfig, - containerDisplayMode: displayMode, - controlsEnabled: showControls, - hideBuildModePaddings, - lastSelected, - layoutMode: mode, - mode: ArSlotViewMode.BUILD, - onClick: onSlotSelect, - selectionOnlyModeEnabled, - horizontalSplitHandler: (placement: "before" | "after") => - slots && - splitHandler( - setSlots, - slots, - "horizontal", - placement, - sConfig, - ), - verticalSplitHandler: (placement: "before" | "after") => - slots && - splitHandler( - setSlots, - slots, - "vertical", - placement, - sConfig, - ), - mergeHandler: () => { - slots && - minMaxSelections && - mergeEnabled && - mergeHandler( - setSlots, - slots, - minMaxSelections, - sConfig, - ) - enableMerge(false) - }, - dropHandler: slotDropHandler, - onSlotSelect: onExternalSlotSelect, - } - return slotRenderer ? ( - slotRenderer(props) - ) : ( - - ) - })} -
-
- )} -
- {!isChild && isGrid && ( -
- - Undo: Ctrl/Cmd + z, Redo: Ctrl/Cmd + y - - - - - -
-
{cmdCtrl} + h
-
Split Horizontally
-
-
-
{cmdCtrl} + v
-
Split Vertically
-
-
-
{cmdCtrl} + m
-
Merge Rectangle
-
-
-
{cmdCtrl} + r
-
Insert Row
-
-
-
{cmdCtrl} + c
-
Insert Column
-
-
-
{cmdCtrl} + d
-
Delete
-
-
-
{cmdCtrl} + z
-
Undo
-
-
-
{cmdCtrl} + y
-
Redo
-
-
-
- - - -
Hover on grid to reveal control panel.
-
Click a cell to select it.
-
You may select multiple cells by clicking on them.
-
- Click a row header to select all cells in that row, and column - header to select all cells in that column -
-
- You may hover on any selected cells on specific sections - within cell to split vertical or horizontal. -
-
- For Horizontal: Hover on top center or bottom center region - and click -
-
- For Vertical: Hover on left center or right center region and - click -
-
- You may merge cells too, at least 2 cells should be selected - to merge and the selected cells shouls form a rectangle. -
-
- To delete a row or column, hover on it's corresponding row or - column header to reveal delete button and click on it. -
-
- Undo/Redo layout changes is supported. Use Undo/Redo buttons - in the control panel on top of grid, or use Ctrl/Cmd + z to - undo, Ctrl/Cmd + y to redo -
-
Edit Mode should be enabled to use any shortcuts
-
-
-
-
- )} -
- ) + return ( + + +
+ {slots?.map((slotDesc) => { + const slotProps = { + slotDescriptor: slotDesc, + containerDisplayMode: displayMode, + controlsEnabled, + hideBuildModePaddings, + layoutMode: mode, + mode: ArSlotViewMode.BUILD as const, + dropHandler: slotDropHandler, + onSlotSelect, + slotRenderer, + } + return slotRenderer ? ( + slotRenderer(slotProps) + ) : ( + + ) + })} +
+
+
+ ) } export default BuilderLayout diff --git a/src/BuilderLayoutCanvas.tsx b/src/BuilderLayoutCanvas.tsx new file mode 100644 index 0000000..937332f --- /dev/null +++ b/src/BuilderLayoutCanvas.tsx @@ -0,0 +1,82 @@ +import { FC } from "react" +import { Fragment } from "react" +import { ArSlotViewMode } from "@armco/shared-components/enums" +import type { BuilderLayoutCanvasProps, ISlotDescriptor } from "./types" +import { useLayoutContext } from "./Layout.context" +import Slot from "./Slot" + +const BuilderLayoutCanvas: FC = ({ children, isChild, isGrid }) => { + const { eventsService, layoutService, controlsEnabled } = useLayoutContext() + const slots: ISlotDescriptor[] | undefined = layoutService?.slots + const gridToolbarSpecs = layoutService?.gridToolbarSpecs + const onSlotSelectCB = eventsService?.onSlotSelectCB + + return ( +
+ {slots && ( +
+ {controlsEnabled && !isChild && isGrid && ( + +
+
+ {gridToolbarSpecs?.rowTools?.slots?.map((r: any, h: number, d: any[]) => ( + + { + eventsService.selectRow(e) + onSlotSelectCB && onSlotSelectCB(e, "row") + }} + controlsEnabled={controlsEnabled} + isLast={h === d.length - 1} + rowDeleteHandler={() => eventsService.deleteRow(true)} + rowInsertHandler={(e: any) => eventsService.addRow(e)} + rowSelectHandler={(e: any) => eventsService.selectRow(r, e)} + >{`controller-${r.slot}`} + + ))} +
+
+ {gridToolbarSpecs?.colTools?.slots?.map((r: any, h: number, d: any[]) => ( + + { + eventsService.selectColumn(e) + onSlotSelectCB && onSlotSelectCB(e, "column") + }} + controlsEnabled={controlsEnabled} + isLast={h === d.length - 1} + columnDeleteHandler={() => eventsService.deleteColumn(true)} + columnInsertHandler={(e: any) => eventsService.addColumn(e)} + columnSelectHandler={(e: any) => eventsService.selectColumn(r, e)} + >{`controller-${r.slot}`} + + ))} +
+ + )} + {children} +
+ )} +
+ ) +} + +export default BuilderLayoutCanvas diff --git a/src/BuilderLayoutContainer.tsx b/src/BuilderLayoutContainer.tsx new file mode 100644 index 0000000..26a9d4d --- /dev/null +++ b/src/BuilderLayoutContainer.tsx @@ -0,0 +1,68 @@ +import { FC, useRef, useEffect } from "react" +import { BuilderLayoutContainerProps } from "./types" +import LayoutHelp from "./LayoutHelp" +import LayoutControlPanel from "./LayoutControlPanel" +import { useLayoutContext } from "./Layout.context" + +const BuilderLayoutContainer: FC = ({ children, classes, panelsDisplayable }) => { + const helpRef = useRef(null) + const controlPanelRef = useRef(null) + const containerRef = useRef(null) + const { layoutService, panelsDisplayed, displayPanels, controlsEnabled } = useLayoutContext() + const rowSlots = layoutService?.gridToolbarSpecs?.rowTools?.slots || [] + const colSlots = layoutService?.gridToolbarSpecs?.colTools?.slots || [] + + useEffect(() => { + const updatePanelPositions = () => { + const containerRect = containerRef.current?.getBoundingClientRect() + if (containerRect) { + if (controlPanelRef.current) { + controlPanelRef.current.style.bottom = containerRect.bottom + "px" + controlPanelRef.current.style.left = containerRect.left + "px" + controlPanelRef.current.style.width = containerRect.width + "px" + } + if (helpRef.current) { + helpRef.current.style.top = window.innerHeight - containerRect.top + "px" + helpRef.current.style.left = containerRect.left + "px" + } + setTimeout(() => { + const helpRect = helpRef.current?.getBoundingClientRect() + if (containerRect && helpRef.current && controlPanelRef.current && helpRect && helpRect.width > containerRect.width) { + helpRef.current.style.width = containerRect.width + "px" + helpRef.current.style.overflow = "auto" + } + }, 500) + } + } + const resizeObserver = new window.ResizeObserver(() => { + if (panelsDisplayed) updatePanelPositions() + }) + if (containerRef.current) resizeObserver.observe(containerRef.current) + return () => resizeObserver.disconnect() + }, [panelsDisplayed, controlsEnabled]) + + return ( +
{ e.stopPropagation(); panelsDisplayable && displayPanels(true) }} + onMouseLeave={e => { e.stopPropagation(); panelsDisplayable && displayPanels(false) }} + > + {panelsDisplayable && ( + e.isSelected) > -1} + columnDeleteEnabled={colSlots.findIndex((e: any) => e.isSelected) > -1} + /> + )} + {children} + {panelsDisplayable && ( + + )} +
+ ) +} + +export default BuilderLayoutContainer diff --git a/src/BuilderSlot.component.scss b/src/BuilderSlot.component.scss deleted file mode 100755 index c8beaeb..0000000 --- a/src/BuilderSlot.component.scss +++ /dev/null @@ -1,54 +0,0 @@ -.ar-Slot { - &.build { - &:hover { - border: 1px dashed #86cff1 !important; - } - &.selected { - border: 1px solid #86cff1 !important; - } - &.last-selected { - outline: 4px solid #2e9cfd !important; - } - &.selected-for-delete { - border: 1px solid red !important; - } - .ar-Slot__overlay-btn { - width: calc(100% / 3); - &.slot:hover { - background-color: rgba(85, 189, 237, 0.661); - } - } - } - .ar-SlotTools { - display: none; - } - &:hover .ar-SlotTools { - display: flex; - } - &.row-controller { - .ar-Slot__overlay-btn { - height: calc((100% - 16px) / 3); - &.slot:hover { - background-color: rgba(85, 189, 237, 0.661); - } - &.delete { - height: 1rem; - background-color: red; - } - } - } - - &.col-controller { - .ar-Slot__overlay-btn { - width: calc((100% - 16px) / 3); - &.slot:hover { - background-color: rgb(3, 169, 244, 0.5); - } - &.delete { - width: 1rem; - background-color: red; - } - } - } - -} diff --git a/src/BuilderSlot.tsx b/src/BuilderSlot.tsx old mode 100755 new mode 100644 index 9b829c8..b7858ed --- a/src/BuilderSlot.tsx +++ b/src/BuilderSlot.tsx @@ -1,98 +1,82 @@ -import { useEffect, useRef, useState } from "react" -import { ArDndItemTypes, ArSlotViewMode, BuilderSlotProps } from "@armco/types" +import { CSSProperties, useEffect, useRef, useState } from "react" +import { ArSlotViewMode, ArDndItemTypes } from "@armco/shared-components/enums" import Draggable from "@armco/shared-components/Draggable" import Droppable from "@armco/shared-components/Droppable" import SlotTools from "./SlotTools" -import "./BuilderSlot.component.scss" +import { BuilderSlotProps } from "./types" +import { useLayoutContext } from "./Layout.context" const BuilderSlot = (props: BuilderSlotProps): JSX.Element => { - const { - acceptDropTypes, - containerDisplayMode, - content, - dropHandler, - lastSelected, - onClick, - selectionOnlyModeEnabled, - style, - ...rest - } = props - const [selected, setSelected] = useState() - const slotRef = useRef(null) - const { mode, config } = props - const { slot, props: slotProps } = config - const { classes, style: slotStyles, ...slotRest } = slotProps || {} - const isToolSlot = - mode === ArSlotViewMode.ROWCONTROLLER || - mode === ArSlotViewMode.COLCONTROLLER + const { + acceptDropTypes, + containerDisplayMode, + content, + dropHandler, + activeSlot, + onClick, + ...rest + } = props + const { controlsEnabled, selectionOnlyModeEnabled, eventsService } = useLayoutContext() + const [selected, setSelected] = useState() + const { mode = ArSlotViewMode.BUILD, slotDescriptor } = props + const slotRef = useRef(null) + const { slot, props: slotProps } = slotDescriptor + const { classes, style: slotStyles, ...slotRest } = slotProps || {} + const isToolSlot = + mode === ArSlotViewMode.ROWCONTROLLER || + mode === ArSlotViewMode.COLCONTROLLER - useEffect(() => { - setSelected(config.isSelected) - }, [config.isSelected]) + useEffect(() => { + setSelected(!!slotDescriptor.isSelected) + }, [slotDescriptor.isSelected]) - const finalSlotStyles = { - gridArea: config.gridArea, - ...slotStyles, - ...(style || {}), - } + const finalSlotStyles: CSSProperties = { + gridArea: slotDescriptor.gridArea, + ...slotStyles, + } + if (containerDisplayMode && containerDisplayMode !== "grid" && !content) { + finalSlotStyles.minWidth = "5rem" + finalSlotStyles.minHeight = "5rem" + } - if (containerDisplayMode && containerDisplayMode !== "grid" && !content) { - finalSlotStyles.minWidth = "5rem" - finalSlotStyles.minHeight = "5rem" - } + const slotRender = ( +
{ + e.stopPropagation() + setSelected(!selected) + onClick && onClick(slotDescriptor) + }} + ref={slotRef} + {...slotRest} + > + {content} + {controlsEnabled && !selectionOnlyModeEnabled && ( + + )} +
+ ) - const slotRender = ( -
{ - e.stopPropagation() - setSelected(!selected) - onClick && onClick(config) - }} - ref={slotRef} - {...slotRest} - > - {content} - {props.controlsEnabled && !selectionOnlyModeEnabled && ( - - )} -
- ) - - return isToolSlot ? ( - slotRender - ) : ( - - - dropHandler && dropHandler(sourceData, config) - } - hideHoverEffect - > - {slotRender} - - - ) + return isToolSlot ? ( + slotRender + ) : ( + + dropHandler && dropHandler(sourceData, slotDescriptor)} + hideHoverEffect + > + {slotRender} + + + ) } export default BuilderSlot diff --git a/src/Layout.context.tsx b/src/Layout.context.tsx new file mode 100644 index 0000000..ff103d8 --- /dev/null +++ b/src/Layout.context.tsx @@ -0,0 +1,128 @@ +import { createContext, useContext, useState, useEffect, FC, ReactElement } from "react" +import type { LayoutContextType, LayoutProviderProps } from "./types" +import type LayoutService from "./services/Layout.service" +import type EventsService from "./services/Events.service" +import type HistoryService from "./services/History.service" +import type { SlotDescriptor } from "./models" +import type { FunctionType } from "@armco/types" +import LayoutError, { LayoutErrors } from "./LayoutError" + +const LayoutContext = createContext(null) + +const exampleUsage = ` +Example usage: + + + +` + +export const useLayoutContext = (): LayoutContextType => { + const ctx = useContext(LayoutContext) + if (!ctx) + throw new LayoutError( + "useLayoutContext must be used within a LayoutProvider.", + LayoutErrors.MISSING_LAYOUT_CONTEXT, + exampleUsage, + ) + return ctx +} + +export const useLayoutService = (): LayoutService => { + const ctx = useLayoutContext() + if (!ctx) + throw new LayoutError( + "useLayoutService must be used within a LayoutProvider.", + LayoutErrors.MISSING_LAYOUT_CONTEXT, + exampleUsage, + ) + return ctx.layoutService +} + +export const useEventsService = (): EventsService => { + const ctx = useLayoutContext() + if (!ctx) + throw new LayoutError( + "useEventsService must be used within a LayoutProvider.", + LayoutErrors.MISSING_LAYOUT_CONTEXT, + exampleUsage, + ) + return ctx.eventsService +} + +export const useHistoryService = (): HistoryService> => { + const ctx = useLayoutContext() + if (!ctx) + throw new LayoutError( + "useHistoryService must be used within a LayoutProvider.", + LayoutErrors.MISSING_LAYOUT_CONTEXT, + exampleUsage, + ) + return ctx.historyService +} + +export const useShowControls = (): { controlsEnabled: boolean; enableControls: FunctionType } => { + const ctx = useLayoutContext() + if (!ctx) + throw new LayoutError( + "useShowControls must be used within a LayoutProvider.", + LayoutErrors.MISSING_LAYOUT_CONTEXT, + exampleUsage, + ) + return { controlsEnabled: ctx.controlsEnabled, enableControls: ctx.enableControls as unknown as FunctionType } +} + +export const useSelectionOnlyMode = (): { selectionOnlyModeEnabled: boolean; enableSelectionOnlyMode: FunctionType } => { + const ctx = useLayoutContext() + if (!ctx) + throw new LayoutError( + "useSelectionOnlyMode must be used within a LayoutProvider.", + LayoutErrors.MISSING_LAYOUT_CONTEXT, + exampleUsage, + ) + return { + selectionOnlyModeEnabled: ctx.selectionOnlyModeEnabled, + enableSelectionOnlyMode: ctx.enableSelectionOnlyMode as unknown as FunctionType, + } +} + +const LayoutProvider: FC = ({ + children, + layoutService, + eventsService, + historyService, + showPanels, + showControls, +}): ReactElement => { + const [controlsEnabled, setControlsEnabled] = useState(!!showControls) + const [selectionOnlyModeEnabled, setSelectionOnlyModeEnabled] = useState(false) + const [panelsDisplayed, setPanelsDisplayed] = useState(!!showPanels) + + useEffect(() => setPanelsDisplayed(!!showPanels), [showPanels]) + useEffect(() => setControlsEnabled(!!showControls), [showControls]) + + return ( + + {children} + + ) +} + +export default LayoutProvider diff --git a/src/Layout.tsx b/src/Layout.tsx old mode 100755 new mode 100644 index 2f6140c..859e74f --- a/src/Layout.tsx +++ b/src/Layout.tsx @@ -1,67 +1,64 @@ -import { v4 as uuid } from "uuid" -import { useEffect, useState } from "react" -import { ArAlertType, LayoutProps, SlotDescriptor } from "@armco/types" +import { FC, useEffect, useState } from "react" +import { v4 as uuidv4 } from "uuid" +import { ArAlertType } from "@armco/utils" +import { get as httpGet } from "@armco/utils/network" +import { useNotification } from "@armco/utils/hooks" +import LayoutProvider from "./Layout.context" +import useLayoutInit from "./hooks/useLayoutInit" +import SlotDescriptor from "./models/SlotDescriptor" import BuilderLayout from "./BuilderLayout" import ReleaseLayout from "./ReleaseLayout" -import { get } from "@armco/utils/network" -import { useNotification } from "@armco/utils/hooks" +import type { LayoutProps } from "./types" -const dummyGridSpecs = { rows: 5, columns: 5 } +const Layout: FC = (props) => { + const { classes, displayMode, mode, showPanels, showControls, slotRenderer, url } = props + const { notify } = useNotification() + const [, setTick] = useState(false) + const rerender = () => setTick((v) => !v) -const Layout = (props: LayoutProps) => { - const { mode, demo, gridSpecs, url } = props - const propsClone = { ...props } - propsClone.gridSpecs = demo ? gridSpecs || dummyGridSpecs : gridSpecs - const { notify } = useNotification() - const [localSlots, setLocalSlots] = useState< - Array | undefined - >() - const [localGridTemplate, setLocalGridTemplate] = useState< - string | undefined - >() - propsClone.slots = localSlots - propsClone.gridTemplate = localGridTemplate + const { layoutService, eventsService, historyService } = useLayoutInit({ ...props, rerender }, mode) - useEffect(() => { - JSON.stringify(props.slots) !== JSON.stringify(localSlots) && - setLocalSlots(props.slots) - }, [props.slots]) + useEffect(() => { + if (layoutService && !(layoutService.slots || layoutService.gridTemplate) && url) { + httpGet(url) + .then((res: any) => { + const body = Array.isArray(res.body) ? res.body[0] : res.body + if (body?.descriptor) { + if (body.descriptor.content) + layoutService.slots = body.descriptor.content.map((v: any) => SlotDescriptor.create(v)) + if (body.descriptor.layout) layoutService.gridTemplate = body.descriptor.layout + } + rerender() + }) + .catch(() => + notify({ message: "Failed to fetch descriptor for provided URL", uid: uuidv4(), type: ArAlertType.ERROR }), + ) + } + }, [url, notify, layoutService]) - useEffect(() => { - setLocalGridTemplate(props.gridTemplate) - }, [props.gridTemplate]) + if ((mode ?? "build") === "build") { + return ( + + + + ) + } - useEffect(() => { - !(localSlots || localGridTemplate) && - url && - get(url) - .then((res) => { - const component = Array.isArray(res.body) ? res.body[0] : res.body - component?.descriptor?.content && - setLocalSlots(component.descriptor.content as Array) - component?.descriptor?.gridTemplate && - setLocalGridTemplate(component.descriptor.layout as string) - }) - .catch((e) => - notify({ - message: "Failed to fetch descriptor for provided URL", - uid: uuid(), - type: ArAlertType.ERROR, - }), - ) - }, [url]) - - return mode === "build" || (!mode && demo) ? ( - - ) : ( - - ) + return ( + + ) } export default Layout diff --git a/src/LayoutControlPanel.component.scss b/src/LayoutControlPanel.component.scss old mode 100755 new mode 100644 index aefa926..eaa925f --- a/src/LayoutControlPanel.component.scss +++ b/src/LayoutControlPanel.component.scss @@ -1,18 +1,14 @@ .ar-LayoutControlPanel { - transition: all 0.5s; - max-height: 0; - opacity: 0; + transition: all 0.5s; + max-height: 0; + opacity: 0; - &.show { - max-height: 2.25rem; - max-width: calc(2.25rem - 2px); - opacity: 1; - border-radius: 6px 6px 0 0; - background-color: var(--ar-color-selected); - white-space: nowrap; - - &.show-all-controls { - max-width: 30rem; - } - } + &.show { + max-height: 2.25rem; + max-width: 30rem; + opacity: 1; + border-radius: 6px 6px 0 0; + background-color: var(--ar-color-selected); + white-space: nowrap; + } } diff --git a/src/LayoutControlPanel.tsx b/src/LayoutControlPanel.tsx old mode 100755 new mode 100644 index 643095f..3fcc69b --- a/src/LayoutControlPanel.tsx +++ b/src/LayoutControlPanel.tsx @@ -1,269 +1,135 @@ -import { Ref, forwardRef } from "react" -import { - ArPopoverSlots, - ArThemes, - FunctionType, - LayoutControlPanelProps, -} from "@armco/types" -import Icon from "@armco/icon" -import Tooltip from "@armco/shared-components/Tooltip" +import { forwardRef } from "react" import { useTheme } from "@armco/utils/hooks" +import { ArThemes } from "@armco/utils" +import { ArPopoverSlots } from "@armco/shared-components/enums" +import { Tooltip } from "@armco/shared-components" +import Icon from "@armco/icon" +import { useLayoutContext, useSelectionOnlyMode, useShowControls } from "./Layout.context" +import type { LayoutControlPanelProps } from "./types" import "./LayoutControlPanel.component.scss" -const getControl = ( - theme: string, - icon: string, - handler: FunctionType, - tooltip: string, - demo?: boolean, - color?: string, - isDisabled?: boolean, - toggleColor?: string, - showControls?: boolean, +const actionButton = ( + theme: ArThemes, + icon: string, + onClick: () => void, + tooltip: string, + fillColor?: string, + disabled?: boolean, + backgroundColor?: string, + fillPath?: boolean, ) => { - const iconColor = - theme === ArThemes.DARK1 - ? isDisabled - ? "#7a7aa7" - : color || "black" - : isDisabled - ? "#cfcfcf" - : color || "white" - return ( - - {} : handler} - style={{ backgroundColor: toggleColor }} - > - - - -
{tooltip}
-
-
- ) + const color = theme === ArThemes.DARK1 ? (disabled ? "#7a7aa7" : fillColor || "black") : disabled ? "#cfcfcf" : fillColor || "white" + return ( + + !disabled && onClick()} + style={{ backgroundColor }} + > + + + +
{tooltip}
+
+
+ ) } -const LayoutControlPanel = forwardRef( - (props: LayoutControlPanelProps, ref: Ref): JSX.Element => { - const { - classes, - demo, - showControls, - setShowControls, - slots, - splitEnabled, - mergeEnabled, - rowDeleteEnabled, - columnDeleteEnabled, - undoEnabled, - redoEnabled, - selectionOnlyModeEnabled, - show, - enableSelectionOnlyMode, - horizontalSplitHandler, - verticalSplitHandler, - mergeHandler, - rowInsertHandler, - columnInsertHandler, - rowDeleteHandler, - columnDeleteHandler, - undoHandler, - redoHandler, - } = props - const { theme } = useTheme() - const controls = [ - [ - showControls ? "md.MdEditOff" : "md.MdEdit", - () => setShowControls(!showControls), - "Edit Layout", - "#ffa500", - ], - [ - "ri.RiSplitCellsVertical", - horizontalSplitHandler, - splitEnabled ? "Split Horizontal" : "Select a cell to split", - theme === ArThemes.DARK1 ? "green" : "#17dc81", - !splitEnabled, - ], - [ - "ri.RiSplitCellsHorizontal", - verticalSplitHandler, - splitEnabled ? "Split Vertical" : "Select a cell to split", - theme === ArThemes.DARK1 ? "green" : "#17dc81", - !splitEnabled, - ], - [ - "fa.FaCompressArrowsAlt", - mergeHandler, - mergeEnabled - ? "Merge Selection" - : "Selected at least two adjacent cells to merge", - theme === ArThemes.DARK1 ? "green" : "#17dc81", - !mergeEnabled, - ], - [ - "ri.RiInsertRowTop", - () => rowInsertHandler("before"), - "Insert Row Before", - theme === ArThemes.DARK1 ? "#0299e7" : "#0299ff", - ], - [ - "ri.RiInsertRowBottom", - () => rowInsertHandler("after"), - "Insert Row After", - theme === ArThemes.DARK1 ? "#0299e7" : "#0299ff", - ], - [ - "ri.RiInsertColumnLeft", - () => columnInsertHandler("before"), - "Insert Column Before", - theme === ArThemes.DARK1 ? "#0299e7" : "#0299ff", - ], - [ - "ri.RiInsertColumnRight", - () => columnInsertHandler("after"), - "Insert Column After", - theme === ArThemes.DARK1 ? "#0299e7" : "#0299ff", - ], - [ - "ri.RiDeleteRow", - rowDeleteHandler, - rowDeleteEnabled ? "Delete Row" : "Select a row to delete", - "#ff6666", - !rowDeleteEnabled, - ], - [ - "ri.RiDeleteColumn", - columnDeleteHandler, - columnDeleteEnabled ? "Delete Column" : "Select a column to delete", - "#ff6666", - !columnDeleteEnabled, - ], - [ - "fc.FcUndo", - undoHandler, - undoEnabled ? "Undo Last" : "Nothing to undo", - "", - !undoEnabled, - ], - [ - "fc.FcRedo", - redoHandler, - redoEnabled ? "Redo Last Undone" : "Nothing to redo", - "", - !redoEnabled, - ], - [ - "gr.GrSelect", - () => enableSelectionOnlyMode(!selectionOnlyModeEnabled), - !selectionOnlyModeEnabled - ? "Enable Selection Only Mode" - : "Disable Selection Only Mode", - selectionOnlyModeEnabled ? "" : "#17dc81", - false, - selectionOnlyModeEnabled ? "#17dc81" : "", - ], - ] - return ( -
- {getControl( - theme, - controls[0][0] as string, - controls[0][1] as FunctionType, - controls[0][2] as string, - demo, - controls[0][3] as string, - )} - {showControls && ( - <> - {slots && ( - <> - - {controls - .slice(1, 4) - .map((control) => - getControl( - theme, - control[0] as string, - control[1] as FunctionType, - control[2] as string, - demo, - control[3] as string, - control[4] as boolean, - control[5] as string, - showControls, - ), - )} - - )} - - {controls - .slice(4, 10) - .map((control) => - getControl( - theme, - control[0] as string, - control[1] as FunctionType, - control[2] as string, - demo, - control[3] as string, - control[4] as boolean, - control[5] as string, - showControls, - ), - )} - - {controls - .slice(10, 12) - .map((control) => - getControl( - theme, - control[0] as string, - control[1] as FunctionType, - control[2] as string, - demo, - control[3] as string, - control[4] as boolean, - control[5] as string, - showControls, - ), - )} - - {controls - .slice(12) - .map((control) => - getControl( - theme, - control[0] as string, - control[1] as FunctionType, - control[2] as string, - demo, - control[3] as string, - control[4] as boolean, - control[5] as string, - showControls, - ), - )} - - )} -
- ) - }, -) +const LayoutControlPanel = forwardRef((props, ref) => { + const { classes, rowDeleteEnabled, columnDeleteEnabled, show } = props + const { theme } = useTheme() + const { eventsService, historyService, layoutService } = useLayoutContext() + const { selectionOnlyModeEnabled, enableSelectionOnlyMode } = useSelectionOnlyMode() + const { controlsEnabled, enableControls } = useShowControls() + + const splitEnabled = layoutService.splitEnabled + const mergeEnabled = layoutService.mergeEnabled + + const actions: any[] = [ + [ + controlsEnabled ? "md.MdEditOff" : "md.MdEdit", + () => enableControls(!controlsEnabled), + "Edit Layout", + "#ffa500", + ], + [ + "ri.RiSplitCellsVertical", + eventsService.splitHorizontalAfter, + splitEnabled ? "Split Horizontal" : "Select a cell to split", + theme === ArThemes.DARK1 ? "green" : "#17dc81", + !splitEnabled, + ], + [ + "ri.RiSplitCellsHorizontal", + eventsService.splitVerticalAfter, + splitEnabled ? "Split Vertical" : "Select a cell to split", + theme === ArThemes.DARK1 ? "green" : "#17dc81", + !splitEnabled, + ], + [ + "fa.FaCompressArrowsAlt", + () => { + eventsService.mergeCells() + layoutService.mergeEnabled = false + }, + mergeEnabled ? "Merge Selection" : "Selected at least two adjacent cells to merge", + theme === ArThemes.DARK1 ? "green" : "#17dc81", + !mergeEnabled, + ], + ["ri.RiInsertRowTop", eventsService.addRowBefore, "Insert Row Before", theme === ArThemes.DARK1 ? "#0299e7" : "#0299ff"], + ["ri.RiInsertRowBottom", eventsService.addRowAfter, "Insert Row After", theme === ArThemes.DARK1 ? "#0299e7" : "#0299ff"], + ["ri.RiInsertColumnLeft", eventsService.addColumnBefore, "Insert Column Before", theme === ArThemes.DARK1 ? "#0299e7" : "#0299ff"], + ["ri.RiInsertColumnRight", eventsService.addColumnAfter, "Insert Column After", theme === ArThemes.DARK1 ? "#0299e7" : "#0299ff"], + ["ri.RiDeleteRow", eventsService.deleteRow, rowDeleteEnabled ? "Delete Row" : "Select a row to delete", "#ff6666", !rowDeleteEnabled], + [ + "ri.RiDeleteColumn", + eventsService.deleteColumn, + columnDeleteEnabled ? "Delete Column" : "Select a column to delete", + "#ff6666", + !columnDeleteEnabled, + ], + ["fc.FcUndo", eventsService.undo, historyService.canUndo ? "Undo Last" : "Nothing to undo", "", !historyService.canUndo], + ["fc.FcRedo", eventsService.redo, historyService.canRedo ? "Redo Last Undone" : "Nothing to redo", "", !historyService.canRedo], + [ + "gr.GrSelect", + () => enableSelectionOnlyMode(!selectionOnlyModeEnabled), + selectionOnlyModeEnabled ? "Disable Selection Only Mode" : "Enable Selection Only Mode", + selectionOnlyModeEnabled ? "" : "#17dc81", + false, + selectionOnlyModeEnabled ? "#17dc81" : "", + true, + ], + ] + + return ( +
+ {actionButton(theme, actions[0][0], actions[0][1], actions[0][2], actions[0][3])} + {layoutService.slots && ( + <> + + {actions.slice(1, 4).map((e, idx) => + actionButton(theme, e[0], e[1], e[2], e[3], e[4], e[5]) + )} + + )} + + {actions.slice(4, 10).map((e, idx) => actionButton(theme, e[0], e[1], e[2], e[3], e[4], e[5]))} + + {actions.slice(10, 12).map((e, idx) => actionButton(theme, e[0], e[1], e[2], e[3], e[4], e[5]))} + + {actions.slice(12).map((e, idx) => actionButton(theme, e[0], e[1], e[2], e[3], e[4], e[5], e[6]))} +
+ ) +}) export default LayoutControlPanel diff --git a/src/LayoutError.tsx b/src/LayoutError.tsx new file mode 100644 index 0000000..0ce2d48 --- /dev/null +++ b/src/LayoutError.tsx @@ -0,0 +1,21 @@ +// LayoutError aligned with built artifacts (non-Error class, simple payload fields) +export enum LayoutErrors { + MISSING_SLOTS = "MISSING_SLOTS", + MALFORMED_GRID_SPECS = "MALFORMED_GRID_SPECS", + MISSING_LAYOUT_CONTEXT = "MISSING_LAYOUT_CONTEXT", + MISSING_SLOT_DESCRIPTOR = "MISSING_SLOT_DESCRIPTOR", + MISSING_SLOT_DESCRIPTOR_OBJ = "MISSING_SLOT_DESCRIPTOR_OBJ", + MISSING_SLOT_ID = "MISSING_SLOT_ID", +} + +export default class LayoutError { + error: string + code?: LayoutErrors + description?: string + + constructor(error: string, code?: LayoutErrors, description?: string) { + this.error = error + this.code = code + this.description = description + } +} diff --git a/src/LayoutHelp.tsx b/src/LayoutHelp.tsx new file mode 100644 index 0000000..57cf97e --- /dev/null +++ b/src/LayoutHelp.tsx @@ -0,0 +1,98 @@ +import { forwardRef, useMemo } from "react" +import { ArThemes } from "@armco/utils" +import { useTheme } from "@armco/utils/hooks" +import { ArPopoverSlots } from "@armco/shared-components/enums" +import { Tooltip } from "@armco/shared-components" +import Icon from "@armco/icon" + +type LayoutHelpProps = { + panelsDisplayed?: boolean +} + +const keyBindings = [ + { key: "h", action: "Split Horizontally" }, + { key: "v", action: "Split Vertically" }, + { key: "m", action: "Merge Rectangle" }, + { key: "r", action: "Insert Row" }, + { key: "c", action: "Insert Column" }, + { key: "d", action: "Delete" }, + { key: "z", action: "Undo" }, + { key: "y", action: "Redo" }, +] + +const helpPoints = [ + "Hover on grid to reveal control panel.", + "Click a cell to select it.", + "You may select multiple cells by clicking on them.", + "Click a row header to select all cells in that row, and column header to select all cells in that column", + "You may hover on any selected cells on specific sections within cell to split vertical or horizontal.", + "For Horizontal: Hover on top center or bottom center region and click", + "For Vertical: Hover on left center or right center region and click", + "You may merge cells too, at least 2 cells should be selected to merge and the selected cells should form a rectangle.", + "To delete a row or column, hover on its corresponding row or column header to reveal delete button and click on it.", + "Undo/Redo layout changes is supported. Use Undo/Redo buttons in the control panel on top of grid, or use Ctrl/Cmd + z to undo, Ctrl/Cmd + y to redo", + "Edit Mode should be enabled to use any shortcuts", +] + +const LayoutHelp = forwardRef( + ({ panelsDisplayed }, ref) => { + const { theme } = useTheme() + const cmdIcon = useMemo( + () => ( + <> + {" "} + + + ), + [], + ) + return ( +
+ + Undo: Ctrl/Cmd + z, Redo: Ctrl/Cmd + y + +
+ + + + {keyBindings.map((kb) => ( +
+
+ {cmdIcon} + {kb.key} +
+
{kb.action}
+
+ ))} +
+
+ + + + {helpPoints.map((h, idx) => ( +
{h}
+ ))} +
+
+
+
+ ) + }, +) + +export default LayoutHelp diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000..6d42076 --- /dev/null +++ b/src/README.md @@ -0,0 +1,8 @@ +Recovered skeletons for Layout package + +This directory mirrors the structure of build/es to guide reconstruction of lost sources. + +Conventions: +- .ts for services and utilities +- .tsx for React components +- Each file contains a TODO header describing intended module purpose inferred from build outputs. diff --git a/src/ReleaseLayout.tsx b/src/ReleaseLayout.tsx old mode 100755 new mode 100644 index 5961e71..2b8d3d5 --- a/src/ReleaseLayout.tsx +++ b/src/ReleaseLayout.tsx @@ -1,29 +1,38 @@ -import { ArSlotViewMode, ReleaseLayoutProps, SlotProps } from "@armco/types" +import React from "react" +import { ArSlotViewMode } from "@armco/shared-components/enums" +import type { LayoutProps } from "./types" import Slot from "./Slot" +import { SlotDescriptor } from "@models" -const ReleaseLayout = (props: ReleaseLayoutProps): JSX.Element => { - const { classes, displayMode, gridTemplate, slots, slotRenderer } = props - return ( -
- {slots?.map((sConfig) => { - const props: SlotProps = { - config: sConfig, - containerDisplayMode: displayMode, - mode: ArSlotViewMode.RELEASE, - } - return slotRenderer ? ( - slotRenderer(props) - ) : ( - - ) - })} -
- ) +export interface ReleaseLayoutProps extends Pick { } + +// Release layout simply renders provided slots with a grid template (or displayMode variant) without builder controls. +const ReleaseLayout: React.FC = ({ + classes, + displayMode, + gridTemplate, + slots, + slotRenderer, +}) => { + return ( +
+ {slots?.map((slotDesc: SlotDescriptor) => { + const slotProps = { + slotDescriptor: slotDesc, + containerDisplayMode: displayMode, + mode: ArSlotViewMode.RELEASE as const, + } + return slotRenderer ? ( + slotRenderer(slotProps) + ) : ( + + ) + })} +
+ ) } export default ReleaseLayout diff --git a/src/ReleaseSlot.tsx b/src/ReleaseSlot.tsx old mode 100755 new mode 100644 index e3995f2..87beeef --- a/src/ReleaseSlot.tsx +++ b/src/ReleaseSlot.tsx @@ -1,24 +1,23 @@ -import { ReleaseSlotProps } from "@armco/types" +import type { ReleaseSlotProps } from "./types" +import React from "react" -const ReleaseSlot = (props: ReleaseSlotProps): JSX.Element => { - const { config, content } = props - const { slot, props: slotProps } = config - const { - classes: slotClasses, - style: slotStyles, - ...slotRest - } = slotProps || {} - - return ( -
- {content} -
- ) +const ReleaseSlot: React.FC = (props) => { + const { slotDescriptor, content } = props + const { props: slotProps } = slotDescriptor as any + const { classes, style, ...rest } = (slotProps || {}) as { + classes?: string + style?: React.CSSProperties + [key: string]: any + } + return ( +
+ {content} +
+ ) } export default ReleaseSlot diff --git a/src/Resizable.component.scss b/src/Resizable.component.scss old mode 100755 new mode 100644 index 2287e6c..28cb2d4 --- a/src/Resizable.component.scss +++ b/src/Resizable.component.scss @@ -1,54 +1,60 @@ -.ar-Resizable { - .handle { - &.n, &.s { - left: 0; - width: 100%; - height: 1rem; - cursor: ns-resize; - } - &.e, &.w { - top: 0; - height: 100%; - width: 1rem; - cursor: ew-resize; - } - &.ne, &.nw, &.se, &.sw { - width: 1rem; - height: 1rem; - cursor: nwse-resize; - } - &.n { - bottom: calc(100% - 0.5rem); - } - &.s { - top: calc(100% - 0.5rem); - } - &.e { - left: calc(100% - 0.5rem); - } - &.w { - right: calc(100% - 0.5rem); - } - &.ne { - left: calc(100% - 0.5rem); - bottom: calc(100% - 0.5rem); - } - &.nw { - right: calc(100% - 0.5rem); - bottom: calc(100% - 0.5rem); - } - &.se { - left: calc(100% - 0.5rem); - top: calc(100% - 0.5rem); - } - &.sw { - right: calc(100% - 0.5rem); - top: calc(100% - 0.5rem); - } - &.n, &.s, &.e, &.w, &.ne, &.nw, &.se, &.sw { - &:hover { - background-color: var(--ar-bg-hover-4); - } - } - } +.ar-Resizable .handle.n, +.ar-Resizable .handle.s { + left: 0; + width: 100%; + height: 1rem; + cursor: ns-resize; +} +.ar-Resizable .handle.e, +.ar-Resizable .handle.w { + top: 0; + height: 100%; + width: 1rem; + cursor: ew-resize; +} +.ar-Resizable .handle.ne, +.ar-Resizable .handle.nw, +.ar-Resizable .handle.se, +.ar-Resizable .handle.sw { + width: 1rem; + height: 1rem; + cursor: nwse-resize; +} +.ar-Resizable .handle.n { + bottom: calc(100% - 0.5rem); +} +.ar-Resizable .handle.s { + top: calc(100% - 0.5rem); +} +.ar-Resizable .handle.e { + left: calc(100% - 0.5rem); +} +.ar-Resizable .handle.w { + right: calc(100% - 0.5rem); +} +.ar-Resizable .handle.ne { + left: calc(100% - 0.5rem); + bottom: calc(100% - 0.5rem); +} +.ar-Resizable .handle.nw { + right: calc(100% - 0.5rem); + bottom: calc(100% - 0.5rem); +} +.ar-Resizable .handle.se { + left: calc(100% - 0.5rem); + top: calc(100% - 0.5rem); +} +.ar-Resizable .handle.sw { + right: calc(100% - 0.5rem); + top: calc(100% - 0.5rem); +} +.ar-Resizable .handle.n:hover, +.ar-Resizable .handle.s:hover, +.ar-Resizable .handle.e:hover, +.ar-Resizable .handle.w:hover, +.ar-Resizable .handle.ne:hover, +.ar-Resizable .handle.nw:hover, +.ar-Resizable .handle.se:hover, +.ar-Resizable .handle.sw:hover { + background-color: var(--ar-bg-hover-4); } diff --git a/src/Resizable.tsx b/src/Resizable.tsx old mode 100755 new mode 100644 index 54f9f3d..2a7e47b --- a/src/Resizable.tsx +++ b/src/Resizable.tsx @@ -1,112 +1,66 @@ -import { - ReactElement, - Suspense, - cloneElement, - useCallback, - useEffect, - useRef, - useState, -} from "react" -import { ArDirections, ResizableProps } from "@armco/types" +import React, { Suspense, cloneElement, useCallback, useEffect, useMemo, useRef, useState } from "react" import Slot from "./Slot" +import type { ResizableProps } from "./types" import "./Resizable.component.scss" -const components: { - [key: string]: (props: any) => JSX.Element -} = { - Slot, - // Add more components as needed -} +const Resizable: React.FC = (props) => { + const { reClasses, directions, display, componentName, children, style, ...rest } = props + const [dragging, setDragging] = useState(false) + const lastYRef = useRef(0) + useRef(0) // mimic extra ref from build (unused) + const childRef = useRef(null) -const Resizable = (props: ResizableProps): JSX.Element => { - const { - reClasses, - directions, - display, - componentName, - children, - style, - ...rest - } = props - const [resizing, setResizing] = useState(false) - const mouseDownY = useRef(0) - const mouseDownX = useRef(0) - const childRef = useRef(null) + const registry = useMemo(() => ({ + Slot, + // Add more components as needed + }), []) - const mouseMoveHandler = useCallback( - (e: MouseEvent) => { - if (resizing && childRef.current) { - const childRect = childRef.current.getBoundingClientRect() - // const initialPosition = childRect.left + childRect.width - // const dragOffset = e.clientX - initialPosition + const onMouseMove = useCallback((e: MouseEvent) => { + if (dragging && childRef.current) { + const rect = childRef.current.getBoundingClientRect() + const _ratio = (e.clientX - rect.left) / rect.width + // Placeholder for resize effect, original build does not apply it yet + } + }, [dragging]) - // const newWidth = childRect.width + dragOffset - const newWidth = e.clientX - childRect.left - const newFrValue = newWidth / childRect.width + const onMouseUp = useCallback(() => setDragging(false), []) - // setFrValue(newFrValue) - } - }, - [resizing, childRef], - ) - const mouseUpHandler = useCallback(() => setResizing(false), []) - const mouseDownHandler = useCallback( - ( - e: React.MouseEvent, - direction: ArDirections, - ) => { - setResizing(true) - mouseDownY.current = e.clientY - // TODO: handle direction - }, - [], - ) + const onMouseDown = useCallback((e: React.MouseEvent, _dir: string) => { + setDragging(true) + lastYRef.current = e.clientY + }, []) - useEffect(() => { - document.addEventListener("mousemove", mouseMoveHandler) - document.addEventListener("mouseup", mouseUpHandler) - return () => { - document.removeEventListener("mousemove", mouseMoveHandler) - document.removeEventListener("mouseup", mouseUpHandler) - } - }, [mouseMoveHandler, mouseUpHandler]) + useEffect(() => { + document.addEventListener("mousemove", onMouseMove) + document.addEventListener("mouseup", onMouseUp) + return () => { + document.removeEventListener("mousemove", onMouseMove) + document.removeEventListener("mouseup", onMouseUp) + } + }, [onMouseMove, onMouseUp]) - useEffect(() => { - if (childRef.current) { - const rect = childRef.current.getBoundingClientRect() - } - }, []) + useEffect(() => { + if (childRef.current) { + childRef.current.getBoundingClientRect() + } + }, []) - const Component = (componentName && components[componentName]) as - | React.ComponentType - | undefined + const Dynamic = componentName && (registry as any)[componentName] - return ( -
- {directions?.map((direction) => ( -
mouseDownHandler(e, direction)} - /> - ))} - {Component ? ( - Loading...
}> - - - ) : ( - children && - cloneElement(children as ReactElement, { - childRef: childRef, - }) - )} -
- ) + return ( +
+ {directions?.map((dir) => ( +
onMouseDown(e, dir as any)} /> + ))} + {Dynamic ? ( + Loading...
}> + + + ) : ( + children && cloneElement(children as any, { childRef }) + )} +
+ ) } export default Resizable diff --git a/src/Slot.component.scss b/src/Slot.component.scss new file mode 100644 index 0000000..6581b0b --- /dev/null +++ b/src/Slot.component.scss @@ -0,0 +1,59 @@ +.ar-Droppable:not(.hide-hover-effect) { + &:hover { + border: 1px dashed #1677ff !important; + } + &.drag-over { + border: 2px dashed #1677ff !important; + } +} +.ar-Slot { + .build { + &:hover { + border: 1px dashed #7d31f0 !important; + .ar-SlotTools { + display: flex; + } + } + &.selected { + border: 1px solid #86cff1 !important; + } + &.active { + outline: 4px solid #2e9cfd !important; + } + &.selected-for-delete { + border: 1px solid red !important; + } + .ar-Slot__overlay-btn { + width: 33.3333333333%; + &.slot:hover { + background-color: #55bdeda9; + } + } + } + .ar-SlotTools { + display: none; + } + .row-controller .ar-Slot__overlay-btn { + height: calc((100% - 16px) / 3); + &.delete { + height: 1rem; + } + } + .col-controller .ar-Slot__overlay-btn { + width: calc((100% - 16px) / 3); + &.delete { + width: 1rem; + } + } + .row-controller, + .col-controller { + .ar-Slot__overlay-btn { + &.slot:hover { + background-color: #55bdeda9; + } + &.delete { + background-color: red; + } + } + } +} diff --git a/src/Slot.tsx b/src/Slot.tsx old mode 100755 new mode 100644 index c4475a7..3ef393b --- a/src/Slot.tsx +++ b/src/Slot.tsx @@ -1,98 +1,100 @@ -import { ReactNode, useEffect, useState } from "react" -import { - ArComponentResources, - ArSlotViewMode, - SlotDescriptor, - SlotProps, -} from "@armco/types" -import { - generateGridAreaAndSizes, - generateGridTemplate, -} from "@armco/utils/gridHelper" -import { lazyImport } from "@armco/utils/helper" -import Component_404 from "@armco/shared-components/Component_404" -import BuilderSlot from "./BuilderSlot" +import React, { useEffect, useState } from "react" +import { ArSlotViewMode } from "@armco/shared-components/enums" +import * as Components from "@armco/shared-components" import Layout from "./Layout" +import BuilderSlot from "./BuilderSlot" import ReleaseSlot from "./ReleaseSlot" +import SlotDescriptor from "./models/SlotDescriptor" +import { useLayoutService } from "./Layout.context" +import type { ISlotDescriptor, SlotProps } from "./types" +import "./Slot.component.scss" -const Slot = (props: SlotProps): JSX.Element => { - const { mode = ArSlotViewMode.PREVIEW, layoutMode = "preview" } = props - const [content, setContent] = useState() - const config = props.config +const Slot: React.FC = (props) => { + const { layoutMode = "preview", slotRenderer } = props + const [content, setContent] = useState() + const slotDescriptor = props.slotDescriptor + const layoutService = useLayoutService() + const mode = layoutService.mode as any - useEffect(() => { - const content = config.content as { - componentName?: string - source?: ArComponentResources - descriptor?: { content: Array } - props?: { [key: string]: any } - } - if (content) { - if (content.componentName) { - // const source = content.source || ArComponentResources.STUFFLE - // TODO: In Stuffle use component's source property to specify sources like @armco/icon, @armco/Calendar etc. and use them here - const Component = lazyImport(content.componentName, () => ( - - )) - // repo[content.componentName] - const contentProps = content.props || {} - if (content.componentName === "Layout") { - contentProps.displayMode = config.props?.containerDisplayMode - } - setContent( - , - ) - } else if ( - content.descriptor?.content && - Array.isArray(content.descriptor.content) - ) { - const gaResponse = - content?.descriptor?.content && - generateGridAreaAndSizes(content?.descriptor?.content, "auto") + // Local registry for known local components usable by descriptor.componentName + const localRegistry: Record> = { + Layout, + } - const layout = - gaResponse && generateGridTemplate(gaResponse.gridArea, "auto") + const renderInlineSlot = (desc?: ISlotDescriptor) => { + if (!(desc && (desc as any).slot)) { + console.warn( + "Missing slot ID on trying to create inline slot, Slot descriptor will not be processed:", + desc, + ) + return undefined + } + const nextProps = + mode === ArSlotViewMode.BUILD + ? { ...props, slotDescriptor: desc } + : { slotDescriptor: desc, containerDisplayMode: props.containerDisplayMode } + return slotRenderer ? slotRenderer(nextProps) : ( + + ) + } - setContent( - , - ) - } - } else { - setContent(null) - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ - config.content, - layoutMode, - mode, - props.lastSelected, - props.hideBuildModePaddings, - ]) + const resolveComponent = (data: any): React.ComponentType | null => { + if (data && data.componentName) { + let C: any = (Components as any)[data.componentName] + if (!C) C = localRegistry[data.componentName] + return C || null + } + return null + } - return mode !== ArSlotViewMode.PREVIEW && mode !== ArSlotViewMode.RELEASE ? ( - - ) : ( - - ) + const renderDescriptor = (data: any) => { + const C = resolveComponent(data) + if (C) { + const passedProps: any = data.props || {} + if (data.componentName === "Layout") { + passedProps.displayMode = (slotDescriptor as any).containerDisplayMode + } + return ( + + ) + } else if (data?.descriptor?.content && Array.isArray(data.descriptor.content)) { + return ( + + ) + } + return undefined + } + + useEffect(() => { + const c = (slotDescriptor as any).content + if (!c) return + if (Array.isArray(c)) { + const nodes = c.map((i: any) => { + i = SlotDescriptor.create(i) + return renderInlineSlot(i) + }) + setContent(c.length > 0 ? nodes : []) + } else { + const node = renderDescriptor(c) + setContent(node) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [slotDescriptor.content, layoutMode, layoutService.mode, layoutService.activeSlot, props.hideBuildModePaddings]) + + // Choose builder or release slot based on service mode + return mode !== ArSlotViewMode.PREVIEW && mode !== ArSlotViewMode.RELEASE ? ( + + ) : ( + + ) } export default Slot diff --git a/src/SlotTools.tsx b/src/SlotTools.tsx old mode 100755 new mode 100644 index 7831e9e..9d94cc6 --- a/src/SlotTools.tsx +++ b/src/SlotTools.tsx @@ -1,171 +1,103 @@ -import { useEffect, useState } from "react" -import { - ArPopoverSlots, - ArSlotViewMode, - SlotControlProps, - SlotToolsProps, -} from "@armco/types" -import Tooltip from "@armco/shared-components/Tooltip" +import { FC, useEffect, useState } from "react" +import { ArSlotViewMode, ArPopoverSlots } from "@armco/shared-components/enums" +import { Tooltip } from "@armco/shared-components" +import { useLayoutContext } from "./Layout.context" +import type { SlotToolsProps } from "./types" -const staticSlotTools: Array = [ - { class: "ar-Slot__overlay-btn" }, - { - class: "ar-Slot__overlay-btn slot split-up d-flex cursor-pointer", - tooltip: "Insert Cell Above", - }, - { class: "ar-Slot__overlay-btn" }, - { class: "ar-Slot__overlay-btn cursor-pointer delete", isToolSlotOnly: true }, - { - class: "ar-Slot__overlay-btn slot split-left d-flex cursor-pointer", - tooltip: "Insert Cell Before", - isGridOnly: true, - }, - { - class: "ar-Slot__overlay-btn slot merge d-flex cursor-pointer", - tooltip: "Merge at this cell", - isGridOnly: true, - }, - { - class: "ar-Slot__overlay-btn slot split-right d-flex cursor-pointer", - tooltip: "Insert Cell After", - isGridOnly: true, - }, - { class: "ar-Slot__overlay-btn", isGridOnly: true }, - { - class: "ar-Slot__overlay-btn slot split-down d-flex cursor-pointer", - tooltip: "Insert Cell Below", - isGridOnly: true, - }, - { class: "ar-Slot__overlay-btn", isGridOnly: true }, +const DEFAULT_CONTROLS = [ + { class: "ar-Slot__overlay-btn" }, + { class: "ar-Slot__overlay-btn slot split-up d-flex cursor-pointer", tooltip: "Insert Cell Above" }, + { class: "ar-Slot__overlay-btn" }, + { class: "ar-Slot__overlay-btn cursor-pointer delete", isToolSlotOnly: true }, + { class: "ar-Slot__overlay-btn slot split-left d-flex cursor-pointer", tooltip: "Insert Cell Before", isGridOnly: true }, + { class: "ar-Slot__overlay-btn slot merge d-flex cursor-pointer", tooltip: "Merge at this cell", isGridOnly: true }, + { class: "ar-Slot__overlay-btn slot split-right d-flex cursor-pointer", tooltip: "Insert Cell After", isGridOnly: true }, + { class: "ar-Slot__overlay-btn", isGridOnly: true }, + { class: "ar-Slot__overlay-btn slot split-down d-flex cursor-pointer", tooltip: "Insert Cell Below", isGridOnly: true }, + { class: "ar-Slot__overlay-btn", isGridOnly: true }, ] -const SlotTools = (props: SlotToolsProps): JSX.Element => { - const { - config, - controlsEnabled, - demo, - mode = ArSlotViewMode.PREVIEW, - horizontalSplitHandler, - mergeHandler, - rowInsertHandler, - columnInsertHandler, - rowDeleteHandler, - columnDeleteHandler, - verticalSplitHandler, - rowSelectHandler, - columnSelectHandler, - } = props - const [slotTools, setSlotTools] = - useState>(staticSlotTools) +const SlotTools: FC = (props) => { + const { slotDescriptor, controlsEnabled, demo, mode = ArSlotViewMode.PREVIEW } = props + const { eventsService } = useLayoutContext() + const [controls, setControls] = useState(DEFAULT_CONTROLS) - useEffect(() => { - const slotToolsClone: Array = JSON.parse( - JSON.stringify(slotTools), - ) - if ( - mode === ArSlotViewMode.ROWCONTROLLER || - mode === ArSlotViewMode.COLCONTROLLER - ) { - const isRowController = mode === ArSlotViewMode.ROWCONTROLLER - const handler = isRowController ? rowInsertHandler : columnInsertHandler - slotToolsClone[0].onClick = () => - controlsEnabled && handler && handler("before") - slotToolsClone[0].tooltip = isRowController - ? "Insert Row Above" - : "Insert Column Before" - slotToolsClone[0].class.indexOf("slot") === -1 && - (slotToolsClone[0].class += " slot cursor-pointer") - slotToolsClone[1].tooltip = "" - slotToolsClone[2].onClick = () => - controlsEnabled && handler && handler("after") - slotToolsClone[2].tooltip = isRowController - ? "Insert Row Below" - : "Insert Column After" - slotToolsClone[2].class.indexOf("slot") === -1 && - (slotToolsClone[2].class += " slot cursor-pointer") - slotToolsClone[3].tooltip = isRowController - ? "Delete Row" - : "Delete Column" - slotToolsClone[3].onClick = isRowController - ? rowDeleteHandler - : columnDeleteHandler - slotToolsClone[3].onMouseEnter = isRowController - ? () => rowSelectHandler && rowSelectHandler(true) - : () => columnSelectHandler && columnSelectHandler(true) - slotToolsClone[3].onMouseLeave = isRowController - ? () => rowSelectHandler && rowSelectHandler(false) - : () => columnSelectHandler && columnSelectHandler(false) - } else { - slotToolsClone[1].onClick = () => - controlsEnabled && - horizontalSplitHandler && - horizontalSplitHandler("before") - slotToolsClone[4].onClick = () => - controlsEnabled && - verticalSplitHandler && - verticalSplitHandler("before") - slotToolsClone[5].onClick = () => - controlsEnabled && mergeHandler && mergeHandler() - slotToolsClone[6].onClick = () => - controlsEnabled && verticalSplitHandler && verticalSplitHandler("after") - slotToolsClone[8].onClick = () => - controlsEnabled && - horizontalSplitHandler && - horizontalSplitHandler("after") - } - setSlotTools([...slotToolsClone]) - }, [ - controlsEnabled, - config, - horizontalSplitHandler, - verticalSplitHandler, - mergeHandler, - ]) + const isRowController = mode === ArSlotViewMode.ROWCONTROLLER + const deleteHandler = eventsService[isRowController ? "deleteRow" : "deleteColumn"].bind(eventsService) + const addHandler = eventsService[isRowController ? "addRow" : "addColumn"].bind(eventsService) + const selectHandler = eventsService[isRowController ? "selectRow" : "selectColumn"].bind(eventsService) - return ( -
- {slotTools - .map( - (slotTool, index) => - (!slotTool.isGridOnly || mode === ArSlotViewMode.BUILD) && - (!slotTool.isToolSlotOnly || - [ - ArSlotViewMode.ROWCONTROLLER, - ArSlotViewMode.COLCONTROLLER, - ].indexOf(mode) > -1) && ( - { - slotTool.tooltip && e.stopPropagation() - slotTool.onClick && slotTool.onClick() - }} - onMouseEnter={slotTool.onMouseEnter} - onMouseLeave={slotTool.onMouseLeave} - > - {slotTool.tooltip ? ( - - - - {slotTool.tooltip} - - - ) : ( - - )} - - ), - ) - .filter((s) => s)} -
- ) + useEffect(() => { + // deep clone + const o = JSON.parse(JSON.stringify(controls)) + if (mode === ArSlotViewMode.ROWCONTROLLER || mode === ArSlotViewMode.COLCONTROLLER) { + o[0].onClick = () => controlsEnabled && addHandler("before", undefined as any) + o[0].tooltip = isRowController ? "Insert Row Above" : "Insert Column Before" + if (o[0].class.indexOf("slot") === -1) o[0].class += " slot cursor-pointer" + o[1].tooltip = "" + o[2].onClick = () => controlsEnabled && addHandler("after", undefined as any) + o[2].tooltip = isRowController ? "Insert Row Below" : "Insert Column After" + if (o[2].class.indexOf("slot") === -1) o[2].class += " slot cursor-pointer" + o[3].tooltip = isRowController ? "Delete Row" : "Delete Column" + o[3].onClick = () => deleteHandler(true) + o[3].onMouseEnter = () => selectHandler(slotDescriptor, true) + o[3].onMouseLeave = () => selectHandler(slotDescriptor, false) + } else { + o[1].onClick = () => { + eventsService.clickedSlot = slotDescriptor + controlsEnabled && eventsService.splitHorizontalBefore() + } + o[4].onClick = () => { + eventsService.clickedSlot = slotDescriptor + controlsEnabled && eventsService.splitVerticalBefore() + } + o[5].onClick = () => { + eventsService.clickedSlot = slotDescriptor + controlsEnabled && eventsService.mergeHandler() + } + o[6].onClick = () => { + eventsService.clickedSlot = slotDescriptor + controlsEnabled && eventsService.splitVerticalAfter() + } + o[8].onClick = () => { + eventsService.clickedSlot = slotDescriptor + controlsEnabled && eventsService.splitHorizontalAfter() + } + } + setControls([...o]) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [controlsEnabled, slotDescriptor]) + + return ( +
+ {controls + .map((o, idx) => ( + (!o.isGridOnly || mode === ArSlotViewMode.BUILD) && + (!o.isToolSlotOnly || [ArSlotViewMode.ROWCONTROLLER, ArSlotViewMode.COLCONTROLLER].indexOf(mode) > -1) && ( + { + if (o.tooltip) ev.stopPropagation() + o.onClick && o.onClick() + }} + onMouseEnter={o.onMouseEnter} + onMouseLeave={o.onMouseLeave} + > + {o.tooltip ? ( + + + {o.tooltip} + + ) : ( + + )} + + ) + )) + .filter(Boolean)} +
+ ) } export default SlotTools diff --git a/src/Test.tsx b/src/Test.tsx new file mode 100644 index 0000000..c8e4574 --- /dev/null +++ b/src/Test.tsx @@ -0,0 +1,14 @@ +import ReactDOM from "react-dom/client" +import { DndProvider } from "react-dnd" +import { HTML5Backend } from "react-dnd-html5-backend" +import { TouchBackend } from "react-dnd-touch-backend" +import { isMobile as checkMobile } from "@armco/utils/helper" +import Layout from "./Layout" +import "./test.scss" + +const isMobile = checkMobile() +const backend = isMobile ? TouchBackend : HTML5Backend + +const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement) + +root.render(
) diff --git a/src/hooks/useLayoutInit.ts b/src/hooks/useLayoutInit.ts new file mode 100644 index 0000000..4a54104 --- /dev/null +++ b/src/hooks/useLayoutInit.ts @@ -0,0 +1,60 @@ +import { useRef, useEffect } from "react" +import LayoutService from "@services/Layout.service" +import EventsService from "@services/Events.service" +import HistoryService from "@services/History.service" +import { UseLayoutInitProps, LayoutMode } from "../types" +import type SlotDescriptor from "@models/SlotDescriptor" + +export default function useLayoutInit( + initProps: UseLayoutInitProps, + mode: LayoutMode = "build", +) { + const historyRef = useRef>() + const layoutRef = useRef() + const eventsRef = useRef() + + if (mode === "build" && !historyRef.current) + historyRef.current = new HistoryService() + if (!layoutRef.current) { + layoutRef.current = new LayoutService( + { + colWidths: initProps.colWidths, + gridSpecs: initProps.gridSpecs, + gridTemplate: initProps.gridTemplate, + rowHeights: initProps.rowHeights, + slots: initProps.slots, + acceptTextOnClick: initProps.acceptTextOnClick, + activeSlot: initProps.activeSlot, + mode, + }, + initProps.rerender, + historyRef.current, + initProps.onLayoutChange, + ) + } + if (mode === "build" && !eventsRef.current && historyRef.current) { + eventsRef.current = new (EventsService as any)( + layoutRef.current, + historyRef.current, + initProps.onSlotSelect, + ) + } + + useEffect(() => { + if ( + mode === "build" && + eventsRef.current && + eventsRef.current.handleEvent + ) { + const handler = (e: KeyboardEvent) => eventsRef.current?.handleEvent(e) + document.addEventListener("keydown", handler) + return () => document.removeEventListener("keydown", handler) + } + }, [mode]) + + return { + eventsService: eventsRef.current, + layoutService: layoutRef.current, + historyService: historyRef.current, + } +} diff --git a/src/index.ts b/src/index.ts old mode 100755 new mode 100644 index 161b1c8..a221551 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,17 @@ -export { default } from "./Layout" +export { default as Layout } from "./Layout" export { default as BuilderLayout } from "./BuilderLayout" export { default as ReleaseLayout } from "./ReleaseLayout" + export { default as Slot } from "./Slot" export { default as BuilderSlot } from "./BuilderSlot" export { default as ReleaseSlot } from "./ReleaseSlot" -export { default as Resizable } from "./Resizable" \ No newline at end of file +export { default as SlotTools } from "./SlotTools" + +export { default as Resizable } from "./Resizable" + +export { default as ComponentInfo } from "./models/ComponentInfo" + +export { default as useLayoutInit } from "./hooks/useLayoutInit" +export { default as LayoutProvider } from "./Layout.context" + +export * from "./types" diff --git a/src/models/ComponentInfo.tsx b/src/models/ComponentInfo.tsx new file mode 100644 index 0000000..397a9a9 --- /dev/null +++ b/src/models/ComponentInfo.tsx @@ -0,0 +1,29 @@ +import { ArComponentResources } from "@armco/shared-components/enums" +import { IComponentInfo, ISlotDescriptor } from "../types" + +interface Descriptor { + content: Array + layout: string +} + +class ComponentInfo implements IComponentInfo { + [key: string]: any + componentName: string + source?: ArComponentResources + descriptor?: Descriptor + props?: { [key: string]: any } + + constructor( + componentName: string, + source?: ArComponentResources, + descriptor?: Descriptor, + props?: { [key: string]: any } + ) { + this.componentName = componentName + this.source = source + this.descriptor = descriptor + this.props = props + } +} + +export default ComponentInfo diff --git a/src/models/LayoutDescriptor.ts b/src/models/LayoutDescriptor.ts new file mode 100644 index 0000000..75a8300 --- /dev/null +++ b/src/models/LayoutDescriptor.ts @@ -0,0 +1,130 @@ +import { FunctionType } from "@armco/types" +import { IGridSpecs, ISlotDescriptor, LayoutProps } from "../types" +import SlotDescriptor from "./SlotDescriptor" + +class LayoutDescriptor implements LayoutProps { + acceptTextOnClick?: boolean + colWidths?: string | Array + displayMode?: + | "grid" + | "inline" + | "inline-flex" + | "inline-grid" + | "flex" + | "inline-block" + | "block" + | "table" + hideBuildModePaddings?: boolean + gridSpecs?: string | IGridSpecs + gridTemplate: string = "" + isChild?: boolean + activeSlot?: SlotDescriptor + mode?: "build" | "preview" | "release" + rowHeights?: string | Array + onLayoutChange?: FunctionType + slotDropHandler?: FunctionType + onSlotSelect?: FunctionType + showControls?: boolean + showPanels?: boolean + slotRenderer?: FunctionType + slots: Array = [] + url?: string + + setAcceptTextOnClick(value: boolean): this { + this.acceptTextOnClick = value + return this + } + setColWidths(value: string | Array): this { + this.colWidths = value + return this + } + setDisplayMode( + value: + | "grid" + | "inline" + | "inline-flex" + | "inline-grid" + | "flex" + | "inline-block" + | "block" + | "table", + ): this { + this.displayMode = value + return this + } + setHideBuildModePaddings(value: boolean): this { + this.hideBuildModePaddings = value + return this + } + setGridSpecs(value: string | IGridSpecs): this { + this.gridSpecs = value + return this + } + setGridTemplate(value: string): this { + this.gridTemplate = value + return this + } + setIsChild(value: boolean): this { + this.isChild = value + return this + } + setActiveSlot(value: ISlotDescriptor): this { + this.activeSlot = value ? SlotDescriptor.create(value) : undefined + return this + } + setMode(value: "build" | "preview" | "release"): this { + this.mode = value + return this + } + setRowHeights(value: string | Array): this { + this.rowHeights = value + return this + } + setOnLayoutChange(value: FunctionType): this { + this.onLayoutChange = value + return this + } + setSlotDropHandler(value: FunctionType): this { + this.slotDropHandler = value + return this + } + setOnSlotSelect(value: FunctionType): this { + this.onSlotSelect = value + return this + } + setShowControls(value: boolean): this { + this.showControls = value + return this + } + setShowPanels(value: boolean): this { + this.showPanels = value + return this + } + setSlotRenderer(value: FunctionType): this { + this.slotRenderer = value + return this + } + setSlots(value: Array): this { + this.slots = value + ? value.map((s) => s && SlotDescriptor.create(s)).filter((s) => s) + : [] + return this + } + setUrl(value: string): this { + this.url = value + return this + } + static create(props: LayoutProps): LayoutDescriptor { + const instance = new LayoutDescriptor() + Object.keys(props).forEach((key) => { + const value = (props as any)[key] + const setter = `set${key.charAt(0).toUpperCase()}${key.slice(1)}` + if (typeof (instance as any)[setter] === "function") { + ;(instance as any)[setter](value) + } + }) + return instance + } +} + +export default LayoutDescriptor diff --git a/src/models/SlotDescriptor.ts b/src/models/SlotDescriptor.ts new file mode 100644 index 0000000..6c57e58 --- /dev/null +++ b/src/models/SlotDescriptor.ts @@ -0,0 +1,134 @@ +import { ISlotDescriptor, IComponentInfo, LayoutProps } from "../types" +import LayoutError, { LayoutErrors } from "../LayoutError" + +export interface SlotDescriptorProps extends ISlotDescriptor {} + +export default class SlotDescriptor implements ISlotDescriptor { + colSpan: number = 1 + column: number = -1 + gridArea: string = "" + row: number = -1 + rowSpan: number = 1 + slot: string + content?: Array | IComponentInfo + props?: { + [key: string]: any + containerDisplayMode?: LayoutProps["displayMode"] + style?: React.CSSProperties + } + splitFrom?: string + isSelected?: boolean + isSelectedForInlineDelete?: boolean + + constructor( + slot: string, + content?: Array | IComponentInfo, + props?: { + [key: string]: any + containerDisplayMode?: LayoutProps["displayMode"] + style?: React.CSSProperties + }, + ) { + this.slot = slot + this.content = content + this.props = props + } + + setColSpan(colSpan: number): this { + this.colSpan = colSpan + return this + } + setColumn(column: number): this { + this.column = column + return this + } + setRow(row: number): this { + this.row = row + return this + } + setRowSpan(rowSpan: number): this { + this.rowSpan = rowSpan + return this + } + setGridArea(gridArea: string): this { + this.gridArea = gridArea + return this + } + setSplitFrom(splitFrom?: string): this { + this.splitFrom = splitFrom ?? this.splitFrom + return this + } + setIsSelected(isSelected?: boolean): this { + this.isSelected = isSelected ?? this.isSelected + return this + } + setIsSelectedForInlineDelete(isSelectedForInlineDelete?: boolean): this { + this.isSelectedForInlineDelete = + isSelectedForInlineDelete ?? this.isSelectedForInlineDelete + return this + } + setProps(props?: { + [key: string]: any + containerDisplayMode?: LayoutProps["displayMode"] + style?: React.CSSProperties + }): this { + this.props = props + return this + } + setContent(content?: Array | IComponentInfo): this { + this.content = content + return this + } + setStyle(style: React.CSSProperties): this { + if (this.props && this.props.style) { + this.props.style = { ...this.props.style, ...style } + } else { + this.props = { ...(this.props || {}), style } + } + return this + } + setClasses(classes: string): this { + if (this.props) { + this.props.classes = classes + } else { + this.props = { classes } + } + return this + } + get containerDisplayMode(): LayoutProps["displayMode"] | undefined { + return this.props?.containerDisplayMode + } + static cloneOne(slotDescriptor: SlotDescriptor): SlotDescriptor { + return SlotDescriptor.create({ ...slotDescriptor }) + } + static clone(slotDescriptors: Array): SlotDescriptor[] { + return slotDescriptors.map((e) => SlotDescriptor.cloneOne(e)) + } + static create(args: ISlotDescriptor): SlotDescriptor { + if (!args) + throw new LayoutError( + "Missing SlotDescriptor object", + LayoutErrors.MISSING_SLOT_DESCRIPTOR_OBJ, + "SlotDescriptor.create: Failed to create SlotDescriptor as args is missing", + ) + if (!args.slot) + throw new LayoutError( + "Missing Slot ID", + LayoutErrors.MISSING_SLOT_ID, + "SlotDescriptor.create: Failed to create SlotDescriptor as args.slot is missing", + ) + if (args instanceof SlotDescriptor) return args + const e = new SlotDescriptor(args.slot, args.content, args.props) + return e + .setColSpan(args.colSpan ?? e.colSpan) + .setColumn(args.column ?? e.column) + .setRow(args.row ?? e.row) + .setRowSpan(args.rowSpan ?? e.rowSpan) + .setGridArea(args.gridArea ?? e.gridArea) + .setSplitFrom(args.splitFrom ?? e.splitFrom) + .setIsSelected(args.isSelected ?? e.isSelected) + .setIsSelectedForInlineDelete( + args.isSelectedForInlineDelete ?? e.isSelectedForInlineDelete, + ) + } +} diff --git a/src/models/index.ts b/src/models/index.ts new file mode 100644 index 0000000..e5758e6 --- /dev/null +++ b/src/models/index.ts @@ -0,0 +1,3 @@ +export { default as ComponentInfo } from "./ComponentInfo" +export { default as LayoutDescriptor } from "./LayoutDescriptor" +export { default as SlotDescriptor } from "./SlotDescriptor" diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts deleted file mode 100644 index 461cd0b..0000000 --- a/src/react-app-env.d.ts +++ /dev/null @@ -1,71 +0,0 @@ -/// -/// -/// - -declare namespace NodeJS { - interface ProcessEnv { - readonly NODE_ENV: "development" | "production" | "test" - readonly PUBLIC_URL: string - } -} - -declare module "*.avif" { - const src: string - export default src -} - -declare module "*.bmp" { - const src: string - export default src -} - -declare module "*.gif" { - const src: string - export default src -} - -declare module "*.jpg" { - const src: string - export default src -} - -declare module "*.jpeg" { - const src: string - export default src -} - -declare module "*.png" { - const src: string - export default src -} - -declare module "*.webp" { - const src: string - export default src -} - -declare module "*.svg" { - import * as React from "react" - - export const ReactComponent: React.FunctionComponent & { title?: string }> - - const src: string - export default src -} - -declare module "*.module.css" { - const classes: { readonly [key: string]: string } - export default classes -} - -declare module "*.module.scss" { - const classes: { readonly [key: string]: string } - export default classes -} - -declare module "*.module.sass" { - const classes: { readonly [key: string]: string } - export default classes -} diff --git a/src/services/Events.service.ts b/src/services/Events.service.ts new file mode 100644 index 0000000..7cce7aa --- /dev/null +++ b/src/services/Events.service.ts @@ -0,0 +1,796 @@ +import { v4 as uuid } from "uuid" +import { FunctionType } from "@armco/types" +import { ArComponentResources } from "@armco/shared-components/enums" +import { SlotDescriptor } from "../models" +import LayoutService from "./Layout.service" +import HistoryService from "./History.service" + +/** + * EventsService wires user interactions (keyboard and toolbar actions) + * to Layout state mutations (split/merge/insert/remove/select and undo/redo). + * + * Stage 1: This is a strongly-typed scaffold based on the generated .d.ts. + * Stage 2 will fill in implementations aligned with build/es/Events.service.js. + */ +class EventsService { + layoutService: LayoutService + historyService: HistoryService> + onSlotSelectCB?: FunctionType + clickedSlot: SlotDescriptor | null = null + + constructor( + layoutService: LayoutService, + historyService: HistoryService>, + onSlotSelectCB?: FunctionType, + ) { + this.layoutService = layoutService + this.historyService = historyService + this.onSlotSelectCB = onSlotSelectCB + + // Bind methods to preserve `this` when used as callbacks + this.handleEvent = this.handleEvent.bind(this) + this.call = this.call.bind(this) + this.undo = this.undo.bind(this) + this.redo = this.redo.bind(this) + this.splitCell = this.splitCell.bind(this) + this.mergeCells = this.mergeCells.bind(this) + this.onSlotSelect = this.onSlotSelect.bind(this) + this.onDimSelect = this.onDimSelect.bind(this) + this.addRowBefore = this.addRowBefore.bind(this) + this.addRowAfter = this.addRowAfter.bind(this) + this.deleteRowInline = this.deleteRowInline.bind(this) + this.deleteRowNormal = this.deleteRowNormal.bind(this) + this.addColumnBefore = this.addColumnBefore.bind(this) + this.addColumnAfter = this.addColumnAfter.bind(this) + this.deleteColumnInline = this.deleteColumnInline.bind(this) + this.deleteColumnNormal = this.deleteColumnNormal.bind(this) + this.splitHorizontalBefore = this.splitHorizontalBefore.bind(this) + this.splitHorizontalAfter = this.splitHorizontalAfter.bind(this) + this.splitVerticalBefore = this.splitVerticalBefore.bind(this) + this.splitVerticalAfter = this.splitVerticalAfter.bind(this) + this.splitHorizontal = this.splitHorizontal.bind(this) + this.splitVertical = this.splitVertical.bind(this) + this.splitHandler = this.splitHandler.bind(this) + this.mergeHandler = this.mergeHandler.bind(this) + this.addRow = this.addRow.bind(this) + this.deleteRow = this.deleteRow.bind(this) + this.addColumn = this.addColumn.bind(this) + this.deleteColumn = this.deleteColumn.bind(this) + this.selectSlot = this.selectSlot.bind(this) + this.selectRow = this.selectRow.bind(this) + this.selectColumn = this.selectColumn.bind(this) + this.insertDimension = this.insertDimension.bind(this) + this.removeHandler = this.removeHandler.bind(this) + this.findIntersectingSlots = this.findIntersectingSlots.bind(this) + this.generateInsertionIndexes = this.generateInsertionIndexes.bind(this) + this.selectCellsInSelectedRowCol = + this.selectCellsInSelectedRowCol.bind(this) + } + + // ======================= Event Handler Wrappers ======================= + /** + * Registers keyboard events for undo, redo, merge, split, and add row/column actions. + * This function listens for specific key combinations (Ctrl/Cmd + Z/Y/M/H/V/R/C) + * and triggers the corresponding actions in the layout. + * @param event + */ + handleEvent(event: KeyboardEvent): void { + if (event.ctrlKey || event.metaKey) { + if (event.key === "z") { + event.preventDefault() + this.undo() + } else if (event.key === "y") { + event.preventDefault() + this.redo() + } else if (event.key === "m") { + this.mergeHandler() + } else if (this.layoutService.splitEnabled) { + if (event.key === "h") this.splitHorizontal() + else if (event.key === "v") this.splitVertical() + else if (event.key === "r") this.addRow() + else if (event.key === "c") this.addColumn() + } + } + } + + /** + * Calls a generic event handler with optional pre and post hooks. + * This generic event handler that calls one of the other event handlers in this class + * + * @param eventHandler + * @param preHook + * @param postHook + * @param args + * @returns + */ + call( + func: keyof EventsService, + preHook?: FunctionType, + postHook?: FunctionType, + ...args: any[] + ): any { + if (preHook) preHook() + // @ts-expect-error - index access + const result = this[func](...args) + if (postHook) postHook() + return result + } + + undo(): void { + const slots = this.historyService.undo() + this.layoutService.updateSlots(slots || [], true) + } + + redo(): void { + const slots = this.historyService.redo() + this.layoutService.updateSlots(slots || [], true) + } + + /** + * Adds a new row before the specified selection. + * @param selection - An optional selection index. + */ + addRowBefore(selection?: number): SlotDescriptor[] | undefined { + return this.addRow("before", selection) + } + /** + * Adds a new row after the specified selection. + * @param selection - An optional selection index. + */ + addRowAfter(selection?: number): SlotDescriptor[] | undefined { + return this.addRow("after", selection) + } + /** + * Deletes a row inline. + * @returns The updated slots array or null. + */ + deleteRowInline(): Array | null { + return this.deleteRow(true) + } + /** + * Deletes a row normally. + * @returns The updated slots array or null. + */ + deleteRowNormal(): Array | null { + return this.deleteRow(false) + } + /** + * Adds a new column before the specified selection. + * @param selection - An optional selection index. + */ + addColumnBefore(selection?: number): SlotDescriptor[] | undefined { + return this.addColumn("before", selection) + } + /** + * Adds a new column after the specified selection. + * @param selection - An optional selection index. + */ + addColumnAfter(selection?: number): SlotDescriptor[] | undefined { + return this.addColumn("after", selection) + } + /** + * Deletes a column inline. + * @returns The updated slots array or null. + */ + deleteColumnInline(): Array | null { + return this.deleteColumn(true) + } + /** + * Deletes a column normally. + * @returns The updated slots array or null. + */ + deleteColumnNormal(): Array | null { + return this.deleteColumn(false) + } + + /** + * Adds a new row to the layout. + * @param placement - The placement of the new row ("before" or "after"). + * @param selection - An optional selection index. + */ + addRow( + placement: "before" | "after" = "after", + selection?: number, + ): SlotDescriptor[] | undefined { + return ( + this.layoutService.gridToolbarSpecs && + this.insertDimension("row", placement, selection) + ) + } + /** + * Deletes a row from the layout. + * @param isInlineDelete - A boolean to indicate whether it is an inline delete. + * @returns The updated slots array or null. + */ + deleteRow(isInlineDelete?: boolean): Array | null { + return ( + (this.layoutService.gridToolbarSpecs && + this.removeHandler("row", isInlineDelete)) || + null + ) + } + /** + * Adds a new column to the layout. + * @param placement - The placement of the new column ("before" or "after"). + * @param selection - An optional selection index. + */ + addColumn( + placement: "before" | "after" = "after", + selection?: number, + ): SlotDescriptor[] | undefined { + return ( + this.layoutService.gridToolbarSpecs && + this.insertDimension("column", placement, selection) + ) + } + /** + * Deletes a column from the layout. + * @param isInlineDelete - A boolean to indicate whether it is an inline delete. + * @returns The updated slots array or null. + */ + deleteColumn(isInlineDelete?: boolean): Array | null { + return ( + (this.layoutService.gridToolbarSpecs && + this.removeHandler("column", isInlineDelete)) || + null + ) + } + + /** + * Splits a cell based on orientation and placement. + * @param orientation - The orientation of the split ("horizontal" or "vertical"). + * @param placement - The placement of the split ("before" or "after"). + * @returns The updated slots array. + */ + splitCell( + orientation: "horizontal" | "vertical", + placement: "before" | "after", + ): SlotDescriptor[] { + return this.splitHandler(orientation, placement) + } + /** + * Merges selected cells into a primary cell configuration. + * @returns The updated slots array. + */ + mergeCells(): SlotDescriptor[] | undefined { + return this.mergeHandler() + } + + /** + * Handles slot selection. + * @param slotDescriptor - The slot descriptor to select. + * @returns The updated slots array. + */ + selectSlot(slotDescriptor: SlotDescriptor): SlotDescriptor[] { + return this.onSlotSelect(slotDescriptor) + } + /** + * Handles row selection. + * @param slotDescriptor - The slot descriptor to select. + * @param selectForDelete - A boolean to indicate whether to select for delete. + * @returns The updated slots array. + */ + selectRow( + slotDescriptor: SlotDescriptor, + selectForDelete?: boolean, + ): SlotDescriptor[] | undefined { + return this.onDimSelect(slotDescriptor, "row", selectForDelete) + } + /** + * Handles column selection. + * @param slotDescriptor - The slot descriptor to select. + * @param selectForDelete - A boolean to indicate whether to select for delete. + * @returns The updated slots array. + */ + selectColumn( + slotDescriptor: SlotDescriptor, + selectForDelete?: boolean, + ): SlotDescriptor[] | undefined { + return this.onDimSelect(slotDescriptor, "column", selectForDelete) + } + + /** Splits a slot horizontally and places new slot before the one being split */ + splitHorizontalBefore(): SlotDescriptor[] { + return this.splitHandler("horizontal", "before") + } + /** Splits a slot horizontally and places new slot after the one being split */ + splitHorizontalAfter(): SlotDescriptor[] { + return this.splitHandler("horizontal", "after") + } + /** Splits a slot vertically and places new slot before the one being split */ + splitVerticalBefore(): SlotDescriptor[] { + return this.splitHandler("vertical", "before") + } + /** Splits a slot vertically and places new slot after the one being split */ + splitVerticalAfter(): SlotDescriptor[] { + return this.splitHandler("vertical", "after") + } + /** Split slot horizontally */ + splitHorizontal(placement: "before" | "after" = "after"): SlotDescriptor[] { + return this.splitHandler("horizontal", placement) + } + /** Split slot vertically */ + splitVertical(placement: "before" | "after" = "after"): SlotDescriptor[] { + return this.splitHandler("vertical", placement) + } + + // ================= Event Primaries/Juices ================= + /** + * Inserts a new row or column dimension into the grid. + * @param type - The type of dimension ("row" or "column"). + * @param placement - The placement of the new dimension ("before" or "after"). + * @param selection - An optional selection index. + * @returns An updated slots array. + */ + insertDimension( + type: "row" | "column", + placement: "before" | "after", + selection?: number, + ): SlotDescriptor[] { + let slots: SlotDescriptor[] = [...this.layoutService.slots] + const isRow = type === "row" + const gts = this.layoutService.gridToolbarSpecs! + const toolSlots = gts[isRow ? "colTools" : "rowTools"].slots + let created: SlotDescriptor[] = [] + if (toolSlots.length > 0) { + const insertionIndexes = this.generateInsertionIndexes( + isRow, + placement, + selection, + ) + insertionIndexes.sort() + const spanExtensions: Record< + string, + { d: SlotDescriptor; count: number } + > = {} + insertionIndexes.forEach((idx, loopIdx) => { + const selectedToolSlot = + gts[isRow ? "rowTools" : "colTools"].slots[ + idx - loopIdx - (placement === "after" ? 1 : 0) + ] + const intersectingSlots = this.findIntersectingSlots( + selectedToolSlot, + isRow, + ) + const newOnes = toolSlots + .map((toolSlot) => { + const intersecting = intersectingSlots.find((i) => + this.isIntersecting(toolSlot, i, !isRow), + ) + if (intersecting) { + if ( + this.getCreateOrExtend( + intersecting, + selectedToolSlot, + placement, + isRow, + ) + ) { + const newId = `gsa-${uuid()}` + return SlotDescriptor.create({ + slot: newId, + row: isRow ? idx : toolSlot.row, + column: isRow ? toolSlot.column : idx, + rowSpan: isRow ? 1 : toolSlot.rowSpan, + colSpan: isRow ? toolSlot.colSpan : 1, + gridArea: newId, + }) + } else { + if (spanExtensions[intersecting.slot]) + spanExtensions[intersecting.slot].count += 1 + else + spanExtensions[intersecting.slot] = { + d: intersecting, + count: 1, + } + } + } + return null + }) + .filter((s): s is SlotDescriptor => !!s) + created = created.concat(newOnes) + }) + insertionIndexes.forEach((idx) => { + const dim = isRow ? "row" : "column" + slots.filter((s) => s[dim] >= idx).forEach((s) => s[dim]++) + }) + Object.values(spanExtensions).forEach((ext) => { + if (isRow) ext.d.rowSpan += ext.count + else ext.d.colSpan += ext.count + }) + } else { + const id = `gsa-${crypto.randomUUID()}` + created.push( + SlotDescriptor.create({ + slot: id, + row: 0, + column: 0, + rowSpan: 1, + colSpan: 1, + gridArea: id, + }), + ) + } + slots = slots.concat(created) + this.layoutService.updateSlots(slots) + return slots + } + /** + * Removes slots based on type and grid toolbar specifications. + * @param type - The type of removal ("row" or "column"). + * @param isInlineDelete - A boolean to indicate whether it is an inline delete. + * @returns The updated slots array or null. + */ + removeHandler( + type: "row" | "column", + isInlineDelete?: boolean, + ): Array | null { + const slots: SlotDescriptor[] = [...this.layoutService.slots] + const isRow = type === "row" + const gts = this.layoutService.gridToolbarSpecs! + const toolSlots = isRow ? gts.rowTools.slots : gts.colTools.slots + toolSlots + .filter((s) => + isInlineDelete ? s.isSelectedForInlineDelete : s.isSelected, + ) + .sort((a, b) => (isRow ? a.row - b.row : a.column - b.column)) + .forEach((toolSlot) => { + slots + .filter((slot) => + isRow + ? toolSlot.row >= slot.row && + toolSlot.row < slot.row + slot.rowSpan + : toolSlot.column >= slot.column && + toolSlot.column < slot.column + slot.colSpan, + ) + .forEach((slot) => { + if ( + isRow + ? slot.rowSpan <= toolSlot.rowSpan + : slot.colSpan <= toolSlot.colSpan + ) { + const idx = slots.indexOf(slot) + if (idx !== -1) slots.splice(idx, 1) + } else { + if (isRow) slot.rowSpan -= 1 + else slot.colSpan -= 1 + } + }) + let affected = slots.filter((slot) => + isRow ? slot.row > toolSlot.row : slot.column > toolSlot.column, + ) + affected.forEach((slot) => + isRow ? (slot.row -= 1) : (slot.column -= 1), + ) + affected = toolSlots.filter((slot) => + isRow ? slot.row > toolSlot.row : slot.column > toolSlot.column, + ) + affected.forEach((slot) => + isRow ? (slot.row -= 1) : (slot.column -= 1), + ) + toolSlots.splice(toolSlots.indexOf(toolSlot), 1) + }) + this.layoutService.updateSlots(slots) + return slots + } + /** + * Merges selected slots into a primary slot configuration. + * @returns The updated slots array. + */ + mergeHandler(): SlotDescriptor[] | undefined { + if (this.layoutService.mergeEnabled) { + let clicked = this.clickedSlot + this.clickedSlot = null + const slots = [...this.layoutService.slots] + const selected = slots.filter((s) => s.isSelected) + const minMax = this.layoutService.minMaxSelections + selected.sort((a, b) => + a.row !== b.row ? a.row - b.row : a.column - b.column, + ) + const first = selected[0] + let primary = clicked + ? slots.find((s) => s.slot === clicked?.slot) + : first + if (!primary) return + primary.row = first.row + primary.column = first.column + primary.rowSpan = minMax.maxRow - minMax.minRow + 1 + primary.colSpan = minMax.maxColumn - minMax.minColumn + 1 + selected.forEach((sel) => { + const idx = slots.findIndex((s) => s.slot === sel.slot) + const found = slots[idx] + if (found && found.slot !== primary?.slot) slots.splice(idx, 1) + }) + this.layoutService.mergeEnabled = false + this.layoutService.updateSlots(slots) + return slots + } + } + /** + * Splits a slot based on orientation and placement. + * @param orientation - The orientation of the split ("horizontal" or "vertical"). + * @param placement - The placement of the split ("before" or "after"). + * @returns The updated slots array. + */ + splitHandler( + orientation: "horizontal" | "vertical", + placement: "before" | "after", + ): SlotDescriptor[] { + const slots = [...this.layoutService.slots] + let targets: SlotDescriptor[] = [] + if (this.clickedSlot) { + const found = slots.find((s) => s.slot === this.clickedSlot?.slot) + if (found) targets.push(found) + this.clickedSlot = null + } else { + targets = slots.filter((s) => s.isSelected) + } + targets.forEach((slot) => { + const { row, slot: slotId, column, colSpan, rowSpan } = slot + const isHorizontal = orientation === "horizontal" + const isAfter = placement === "after" + const newId = `gsa-${crypto.randomUUID()}` + const spanProp = isHorizontal ? "rowSpan" : "colSpan" + const dimProp = isHorizontal ? "row" : "column" + let spanVal: number = slot[spanProp] + if (spanVal > 1) { + spanVal = slot[spanProp] - 1 + slot[spanProp] = spanVal + } + const newSlot = SlotDescriptor.create({ + slot: newId, + row: isHorizontal && isAfter ? spanVal + row : row, + column: isHorizontal ? column : isAfter ? spanVal + column : column, + rowSpan: isHorizontal ? 1 : rowSpan, + colSpan: isHorizontal ? colSpan : 1, + gridArea: newId, + splitFrom: slotId, + }) + if (isHorizontal ? rowSpan === 1 : colSpan === 1) { + slots.forEach((s) => { + const { + row: r, + column: c, + slot: sId, + colSpan: sColSpan, + rowSpan: sRowSpan, + } = s + if (isHorizontal) { + if (row >= r && row < r + sRowSpan && sId !== slotId) s.rowSpan += 1 + else if (r > row) s.row += 1 + } else { + if (column >= c && column < c + sColSpan && sId !== slotId) + s.colSpan += 1 + else if (c > column) s.column += 1 + } + }) + } + if (!isAfter) slot[dimProp] += 1 + slots.push(newSlot) + }) + this.layoutService.updateSlots(slots) + return slots + } + /** + * Handles slot selection. + * @param slotDescriptor - The slot descriptor to select. + * @returns The updated slots array. + */ + onSlotSelect(slotDescriptor: SlotDescriptor): SlotDescriptor[] { + const slots = [...this.layoutService.slots] + if (slotDescriptor) slotDescriptor.isSelected = !slotDescriptor.isSelected + if ( + this.layoutService.acceptTextOnClick && + slotDescriptor && + !slotDescriptor?.content + ) { + slotDescriptor.props ||= {} + slotDescriptor.content = { + name: "SamEditor", + description: "Rich text editor", + source: ArComponentResources.STUFFLE ?? "stuffle", + componentName: "SamEditor", + props: { + pmOptions: { menuBar: false }, + classes: "w-100", + id: slotDescriptor.slot, + style: { minHeight: "1.5rem", lineHeight: "1.5rem" }, + isEditable: true, + }, + } + } + this.layoutService.activeSlot = slotDescriptor + if (this.onSlotSelectCB) this.onSlotSelectCB(slotDescriptor) + this.layoutService.updateSlots(slots, true) + return slots + } + /** + * Handles dimension selection. + * @param slotDescriptor - The selected dimension descriptor. + * @param type - "row" | "column". + * @param selectForDelete - Whether to select for inline delete. + * @returns The updated slots array. + */ + onDimSelect( + slotDescriptor: SlotDescriptor, + type: "row" | "column", + selectForDelete?: boolean, + ): SlotDescriptor[] | undefined { + const gts = this.layoutService.gridToolbarSpecs + if (!gts) return + const toolSlot = gts[type === "row" ? "rowTools" : "colTools"].slots.find( + (s) => s.slot === slotDescriptor.slot, + ) + if (toolSlot) { + if (selectForDelete !== undefined) + toolSlot.isSelectedForInlineDelete = selectForDelete + else toolSlot.isSelected = !toolSlot.isSelected + } + const updated = this.selectCellsInSelectedRowCol(selectForDelete) + this.layoutService.updateSlots(updated, true) + return updated + } + + // ======================= Event Helpers ======================= + /** + * Finds intersecting slots based on a tool slot and dimension. + * @param toolSlot - The tool slot descriptor. + * @param isRow - True if row, false if column. + * @returns Intersecting slot descriptors. + */ + findIntersectingSlots( + toolSlot: SlotDescriptor, + isRow: boolean, + ): SlotDescriptor[] { + return this.layoutService.slots.filter((slot) => + this.isIntersecting(toolSlot, slot, isRow), + ) + } + /** + * Generates insertion indexes for a new dimension. + * @param isRow - Whether dimension is row. + * @param placement - "before" | "after". + * @param selection - Optional selected index. + * @returns An array of insertion indexes. + */ + generateInsertionIndexes( + isRow: boolean, + placement: "before" | "after", + selection?: number, + ): number[] { + let indexes: number[] = [] + if (selection !== undefined) + indexes.push(placement === "after" ? selection + 1 : selection) + else + indexes = this.generateInsertionIndexesForDimension( + isRow ? "rowTools" : "colTools", + isRow ? "row" : "column", + placement, + isRow, + ) + indexes.sort() + indexes = indexes.map((v, idx) => v + idx) + return indexes + } + /** + * Generates insertion indexes for a specific dimension. + * @param tools - "rowTools" | "colTools". + * @param dimension - "row" | "column". + * @param placement - "before" | "after". + * @param isRow - Whether dimension is row. + */ + generateInsertionIndexesForDimension( + tools: "rowTools" | "colTools", + dimension: "row" | "column", + placement: "before" | "after", + isRow: boolean, + ): number[] { + let indexes: number[] = [] + const gts = this.layoutService.gridToolbarSpecs! + const against = gts[isRow ? "rowTools" : "colTools"].slots + const selected = gts[tools].slots + .filter((s) => s.isSelected) + .map((s) => s[dimension] + (placement === "before" ? 0 : 1)) + if (selected.length > 0) indexes = indexes.concat(selected) + else if (placement === "before") indexes.push(0) + else indexes.push(Math.max(...against.map((s) => s[dimension])) + 1) + return indexes + } + /** + * Checks if a tool slot intersects with a given slot. + * @param toolSlot - The tool slot descriptor. + * @param slot - The slot descriptor to check. + * @param isRow - Whether the check is for rows. + * @returns True if intersects, otherwise false. + */ + isIntersecting( + toolSlot: SlotDescriptor, + slot: SlotDescriptor, + isRow: boolean, + ): boolean { + const dim = isRow ? "row" : "column" + const span = isRow ? "rowSpan" : "colSpan" + const l = slot[dim] + const c = slot[span] + const r = toolSlot[dim] + const a = toolSlot[span] + return l <= r && l + c >= r + a + } + /** + * Determines if a slot should be created or extended based on placement. + * @param slot - The slot descriptor. + * @param selectedToolSlot - The selected tool slot descriptor. + * @param placement - "before" | "after". + * @param isRow - Whether rows are targeted. + */ + getCreateOrExtend( + slot: SlotDescriptor, + selectedToolSlot: SlotDescriptor, + placement: "before" | "after", + isRow: boolean, + ): boolean { + const dim = isRow ? "row" : "column" + const span = isRow ? "rowSpan" : "colSpan" + if (placement === "before") return slot[dim] === selectedToolSlot[dim] + return ( + slot[dim] + slot[span] === selectedToolSlot[dim] + selectedToolSlot[span] + ) + } + /** + * Selects cells in the selected row or column. + * @param selectForDelete - Whether to select for delete. + * @returns Updated slots with selection flags. + */ + selectCellsInSelectedRowCol(selectForDelete?: boolean): SlotDescriptor[] { + const rowSlots = this.layoutService.gridToolbarSpecs?.rowTools.slots + const colSlots = this.layoutService.gridToolbarSpecs?.colTools.slots + const slots = [...this.layoutService.slots] + slots.forEach((slot) => { + slot[ + selectForDelete !== undefined + ? "isSelectedForInlineDelete" + : "isSelected" + ] = this.isSlotSelected( + slot, + rowSlots || [], + colSlots || [], + selectForDelete, + ) + }) + return slots + } + /** + * Checks if a slot is selected based on row and column slots. + * @param slot - The slot descriptor to check. + * @param rowSlots - Row tool slots. + * @param colSlots - Column tool slots. + * @param selectForDelete - Inline delete mode flag. + */ + isSlotSelected( + slot: SlotDescriptor, + rowSlots: Array, + colSlots: Array, + selectForDelete?: boolean, + ): boolean { + const { row, rowSpan, column, colSpan } = slot + const rowMatch = rowSlots + .filter((r) => r.row < row + rowSpan && r.row + r.rowSpan > row) + .every((r) => + selectForDelete !== undefined + ? r.isSelectedForInlineDelete + : r.isSelected, + ) + const colMatch = colSlots + .filter( + (c) => c.column < column + colSpan && c.column + c.colSpan > column, + ) + .every((c) => + selectForDelete !== undefined + ? c.isSelectedForInlineDelete + : c.isSelected, + ) + return rowMatch || colMatch + } +} + +export default EventsService diff --git a/src/services/History.service.ts b/src/services/History.service.ts new file mode 100644 index 0000000..8b01f21 --- /dev/null +++ b/src/services/History.service.ts @@ -0,0 +1,72 @@ +/** + * HistoryService manages undo/redo for layout state. + */ +class HistoryService { + past: T[] = [] + present: T | null = null + future: T[] = [] + + constructor(initialState?: T) { + if (initialState !== undefined) { + this.present = initialState + } + } + + get get(): T | null { + return this.present + } + + get canUndo(): boolean { + return this.past.length > 0 + } + + get canRedo(): boolean { + return this.future.length > 0 + } + /** + * Reverts to the previous state in the history. + * @returns The previous state or null if there are no past states. + */ + undo(): T | null { + if (!this.canUndo) return this.present + const pastCopy = [...this.past] + const previous = pastCopy.pop() + this.future = [this.present as T, ...this.future] + this.past = pastCopy + this.present = previous ?? null + return this.present + } + + /** + * Reverts to the next state in the future. + * @returns The next state or null if there are no future states. + */ + redo(): T | null { + if (!this.canRedo) return this.present + const futureCopy = [...this.future] + const next = futureCopy.shift() + this.past = [...this.past, this.present as T] + this.future = futureCopy + this.present = next ?? null + return this.present + } + + /** + * Sets the new state and optionally skips history recording. + * @param newState The new state to set. + * @param skipHistory If true, skips recording the current state in history. + * @returns The new state. + */ + set(newState: T, skipHistory = false): T { + if (!skipHistory) { + this.past = this.present ? [...this.past, this.present] : this.past + } + this.present = newState + if (!skipHistory) { + this.future = [] + } + return this.present + } +} + +export default HistoryService diff --git a/src/services/Layout.service.ts b/src/services/Layout.service.ts new file mode 100644 index 0000000..cab4db5 --- /dev/null +++ b/src/services/Layout.service.ts @@ -0,0 +1,593 @@ +import { v4 as uuidv4 } from "uuid" +import { FunctionType } from "@armco/types" +import { LayoutDescriptor, SlotDescriptor } from "@models" +import LayoutError, { LayoutErrors } from "../LayoutError" +import HistoryService from "./History.service" +import { + IGridSpecs, + IGridToolbarSpecs, + IMinMaxSelections, + LayoutMode, +} from "../types" + +const DEFAULT_GRID_SPECS = { rows: 1, columns: 1 } + +class LayoutService { + private readonly layoutDescriptor: LayoutDescriptor + gridTemplate: string = "" + slots: SlotDescriptor[] = [] + gridSpecs?: string | IGridSpecs + gridArea?: Array> + rowHeights?: Array | string + colWidths?: Array | string + gridToolbarSpecs?: IGridToolbarSpecs + acceptTextOnClick?: boolean + minMaxSelections: IMinMaxSelections = { + minRow: -Infinity, + maxRow: Infinity, + minColumn: -Infinity, + maxColumn: Infinity, + } + mergeEnabled: boolean = false + splitEnabled: boolean = false + mode: LayoutMode = "build" + activeSlot?: SlotDescriptor + historyService?: HistoryService> + onLayoutChange?: FunctionType + rerender: FunctionType + + constructor( + descriptor: any, + rerender: FunctionType, + historyService?: HistoryService>, + onLayoutChange?: FunctionType, + ) { + this.layoutDescriptor = LayoutDescriptor.create(descriptor) + this.extract = this.extract.bind(this) + this.rerender = rerender + this.historyService = historyService + this.onLayoutChange = onLayoutChange + this.initLayout = this.initLayout.bind(this) + this.updateSlots = this.updateSlots.bind(this) + this.updateGTS = this.updateGTS.bind(this) + this.SGAtoGTS = this.SGAtoGTS.bind(this) + this.StoGA = this.StoGA.bind(this) + this.GStoS = this.GStoS.bind(this) + this.GAtoGT = this.GAtoGT.bind(this) + this.GTtoS = this.GTtoS.bind(this) + this.checkIfAdjacent = this.checkIfAdjacent.bind(this) + this.calculateRowHeights = this.calculateRowHeights.bind(this) + this.extract() + this.initLayout() + } + + /** + * Extracts properties from the layout descriptor and initializes the layout. + * This method is called in the constructor and should not be called again. + * It initializes grid template, slots, grid area, row heights, column widths, + * and calls initLayout to set up the layout. + */ + extract(): void { + this.gridTemplate = this.layoutDescriptor.gridTemplate + this.slots = this.layoutDescriptor.slots || [] + this.gridSpecs = this.layoutDescriptor.gridSpecs || DEFAULT_GRID_SPECS + this.rowHeights = this.layoutDescriptor.rowHeights + this.colWidths = this.layoutDescriptor.colWidths + this.acceptTextOnClick = this.layoutDescriptor.acceptTextOnClick + this.activeSlot = this.layoutDescriptor.activeSlot + this.mode = this.layoutDescriptor.mode || "build" + } + + /** + * Initializes layout by extracting grid template, slots, grid area, row heights, and column widths. + * If slots are provided, gridArea and gridTemplate is generated using optional rowHeights and colWidths + * If gridTemplate is provided, slots are generated using it + * If gridSpecs is provided, slots are generated using it + * Final outcome: Given optional slots, optional gridTemplate, optional gridSpecs, optional rowHeights, optional colWidths; + * generated gridTemplate, generated gridArea, generated slots, generated rowHeights, generated colWidths + * + * This function is mainly for a clean layout that doesn't have any content in it except basic row and column specifications, + * though it still needs to be called for generating the internal gridArea property which in turn is used for generating gridTemplate + * and gridToolbarSpecs. + * + * If all of slots, gridTemplate and gridSpecs are provided, slots take precedence followed by gridTemplate and then gridSpecs + * If rowHeights and colWidths are provided alongwith gridTemplate, rowHeights and colWidths take precedence + */ + private initLayout(): void { + if (!this.slots || this.slots.length === 0) { + if (this.gridTemplate) { + const parsedTemplate = this.GTtoS() + this.slots = parsedTemplate.slots + this.rowHeights = this.rowHeights || parsedTemplate.rowHeights + this.colWidths = this.colWidths || parsedTemplate.colWidths + } else if (this.gridSpecs) { + this.slots = this.GStoS() + } else { + this.slots = [] + } + } + const gridAreaRowHeights = this.StoGA() + this.gridArea = gridAreaRowHeights.gridArea + this.rowHeights = gridAreaRowHeights.rowHeights + if (!this.gridTemplate) { + this.gridTemplate = this.GAtoGT( + this.gridArea, + this.rowHeights, + this.colWidths, + ) + } + this.historyService?.set(this.slots) + this.rerender() + if (this.mode === "build") this.updateGTS() + } + + /** + * Updates the slots and optionally skips history. + * This function and its callers are all supposed to be used only in build mode. + * Code internal to Layout ensures the same. + * + * @param slots - An array of slot descriptors. + * @param skipHistory - A boolean to indicate whether to skip history. + * @param enforceGTSUpdate - A boolean to enforce grid toolbar specs update. + */ + updateSlots( + slots: SlotDescriptor[], + skipHistory?: boolean, + enforceGTSUpdate?: boolean, + ): void { + const lengthChanged = this.slots.length !== slots.length + if (this.slots !== slots) { + this.slots = slots as any[] + if (lengthChanged) { + this.StoGA() + this.resetRowToolbarHeights() + // Lifecycle guarantee: StoGA() sets gridArea & rowHeights before GAtoGT. + // colWidths may be undefined for layouts initialized via gridSpecs/slots; GAtoGT internally defaults missing columns to 1fr. + this.gridTemplate = this.GAtoGT( + this.gridArea!, + this.rowHeights!, + this.colWidths, + ) + } + this.mergeEnabled = this.checkIfAdjacent() + this.splitEnabled = slots.filter((slot) => slot.isSelected).length >= 1 + this.historyService?.set(SlotDescriptor.clone(slots), !!skipHistory) + this.rerender() + if (lengthChanged || enforceGTSUpdate) this.updateGTS() + } + } + + /** + * Wrapping Grid toolbar specs generator around timeout and animation frame requester + * since GTAtoGTS performs DOM operations to calculate row heights, and + * should be called after the slots have been updated and component has re-rendered. + */ + updateGTS(): void { + setTimeout( + () => + requestAnimationFrame(() => { + this.SGAtoGTS() + this.rerender() + }), + 10, + ) + } + + /** + * Convert grid area, slots and row heights to grid toolbar specs + * Grid toolbars (row and column slots) get messed up when size of cells in their corresponding rows/columns change + * due to content, this function is to calculate the row heights and column widths, based on common height of row and column widths + * after content has been added + * This function relies on grid area generated and saved in Layout service, and doesn't accept + * explicit passed grid area for the sake of simplicity. It generates row tools grid area and column tools grid area + * and uses those to generate their corresponding grid templates. + * + * !IMPORTANT: This function performs a DOM operation to calculate row heights, so it should be called after the slots have been updated + * and component has re-rendered. + * + * ***Calling this function directly may result in incorrect row heights.*** + * + * @param gridArea Grid Area of row tools + * @returns grid toolbar specs + * @sets grid toolbar specs + */ + private SGAtoGTS(): IGridToolbarSpecs { + const gridArea = this.gridArea! + const rowHeights = this.calculateRowHeights() + const rowToolGridAreas = gridArea.map((row: any[]) => [ + row.every((cell) => cell === row[0]) + ? row[0].replace("gsa-", "gtra-") + : "gtra-" + uuidv4(), + ]) + const colToolGridAreas = gridArea[0].map((cell: any, colIdx: number) => + gridArea.every((row: any[]) => row[colIdx] === gridArea[0][colIdx]) + ? gridArea[0][colIdx].replace("gsa-", "gtca-") + : "gtca-" + uuidv4(), + ) + const rowToolSlots = LayoutService.countOccurrences( + rowToolGridAreas.map((row: any[]) => row[0]), + ).map((occurrence: { slotId: string; span: number; location: number }) => + SlotDescriptor.create({ + slot: occurrence.slotId, + gridArea: occurrence.slotId, + row: occurrence.location, + column: 0, + rowSpan: occurrence.span, + colSpan: 1, + props: { style: { gridArea: occurrence.slotId } }, + }), + ) + const colToolSlots = LayoutService.countOccurrences(colToolGridAreas).map( + (occurrence) => + SlotDescriptor.create({ + slot: occurrence.slotId, + gridArea: occurrence.slotId, + row: 0, + column: occurrence.location, + rowSpan: 1, + colSpan: occurrence.span, + props: { style: { gridArea: occurrence.slotId } }, + }), + ) + this.gridToolbarSpecs = { + rowTools: { + slots: rowToolSlots, + gridTemplate: this.GAtoGT( + rowToolGridAreas, + rowHeights || "minmax(auto, 1fr)", + this.colWidths || "1fr", + ), + }, + colTools: { + slots: colToolSlots, + gridTemplate: this.GAtoGT([colToolGridAreas], "1fr", "1fr"), + }, + } + return this.gridToolbarSpecs + } + + /** + * Converts slots and row heights to grid area and processed row heights + * @param currentRowHeights + * @returns + */ + StoGA(): { gridArea: string[][]; rowHeights: string[] } { + const initialRowHeights = this.layoutDescriptor.rowHeights + let gridArea: any[] = [] + const processedRowHeights: any[] = [] + this.slots.forEach((slot: any) => { + let rowEnd = slot.row + slot.rowSpan, + colEnd = slot.column + slot.colSpan + for (let rowIdx = slot.row; rowIdx < rowEnd; rowIdx++) { + const rowHeight = Array.isArray(initialRowHeights) + ? initialRowHeights[rowIdx] + : initialRowHeights + slot.content + ? (processedRowHeights[rowIdx] = rowHeight || "auto") + : (processedRowHeights[rowIdx] = "minmax(2rem, auto)") + gridArea[rowIdx] || (gridArea[rowIdx] = []) + for (let colIdx = slot.column; colIdx < colEnd; colIdx++) + gridArea[rowIdx][colIdx] = slot.gridArea + } + }) + this.gridArea = gridArea + this.rowHeights = processedRowHeights + return { gridArea, rowHeights: processedRowHeights } + } + + /** + * Converts grid specs to slot descriptors. + * @returns Array of SlotDescriptor + */ + GStoS(): SlotDescriptor[] { + if (typeof this.gridSpecs === "string") { + try { + this.gridSpecs = JSON.parse(this.gridSpecs) + } catch { + console.error( + "[COMPONENT:LAYOUT] Grid Specs passed as JSON string but incorrect non-parseable format", + ) + throw new LayoutError( + "Invalid grid specs string", + LayoutErrors.MALFORMED_GRID_SPECS, + ) + } + } + if ( + typeof this.gridSpecs === "object" && + "rows" in this.gridSpecs && + "columns" in this.gridSpecs + ) { + const slotDescriptors: any[] = [] + for (let rowIdx = 0; rowIdx < this.gridSpecs.rows; rowIdx++) { + for (let colIdx = 0; colIdx < this.gridSpecs.columns; colIdx++) { + const slotId = `gsa-${uuidv4()}` + slotDescriptors.push( + SlotDescriptor.create({ + slot: slotId, + row: rowIdx, + column: colIdx, + rowSpan: 1, + colSpan: 1, + gridArea: slotId, + }), + ) + } + } + return slotDescriptors + } + console.error( + "[COMPONENT:LAYOUT] Grid Specs are malformed, should be an object with rows and columns", + ) + throw new LayoutError( + "Invalid grid specs", + LayoutErrors.MALFORMED_GRID_SPECS, + ) + } + + /** + * Converts grid area, row heights and column widths to grid template + * Row Heights at this point are the final processed row heights, and calculated row heights in case of + * grid templates for toolbars + * Calling function should pass gridArea always, not rely on this.gridArea since gridArea is different for main grid + * and for toolbar grids, passing explicitly distinguishes between the two + * + * @param gridArea + * @param rowHeight + * @param colWidth + * @returns grid template string + */ + private GAtoGT( + gridArea: string[][], + rowHeights?: string[] | string, + colWidths?: string[] | string, + ): string { + let gridTemplate = gridArea + .map( + (row, rowIdx) => + `"${row.join(" ")}" ${ + Array.isArray(rowHeights) + ? rowHeights[rowIdx] || "auto" + : rowHeights || "minmax(3rem, 1fr)" + }`, + ) + .join(" ") + const colTemplate = + " / " + + (Array.isArray(colWidths) + ? colWidths.join(" ") + : Array.from( + { length: gridArea[0].length }, + () => colWidths || "1fr", + ).join(" ")) + gridTemplate += colTemplate + const trimmedTemplate = gridTemplate.trim() + if (this.onLayoutChange) this.onLayoutChange(this.gridTemplate, this.slots) + else + console.warn( + "Missing callback onLayoutChange, you may want to pass it as a prop to Layout component in order to capture the updated layout and use it.", + ) + return trimmedTemplate + } + + /** + * Parse slots, row heights and column widths from grid template. + * + * This grid template parser is currently best effort basis and may not support some edge cases, it does + * support calc(), auto, fr, px, rem, %, minmax(), repeat() and other CSS grid properties, but has not been + * tested extensively against all possible grid templates. + * + * Example grid template: + * "ga-1 ga-1 ga-2" 1fr + * "ga-3 ga-4 ga-5" auto + * "ga-6 ga-7 ga-7" 1fr + * / 1fr 1fr 1fr + * + * @param gridTemplate + * @returns + */ + GTtoS(): { + slots: SlotDescriptor[] + rowHeights: string[] + colWidths: string[] + } { + const gridTemplateParts = this.gridTemplate + .split('"') + .map((part: string) => part.trim()) + .filter((part: string) => part) + let colWidths: any[] = [] + const rowHeightsMap: any = {} + gridTemplateParts.forEach((part: string, idx: number) => { + if (part.startsWith("ga-")) rowHeightsMap[part] = "auto" + else if (part.includes("calc(")) { + const closeIdx = part.lastIndexOf(")"), + heightValue = part.substring(0, closeIdx + 1) + rowHeightsMap[gridTemplateParts[idx - 1]] = heightValue + const afterCalc = part.substring(closeIdx + 1).trim() + if (afterCalc.includes("/")) + colWidths = afterCalc + .split("/")[1] + .trim() + .split(" ") + .map((width: string) => width.trim()) + } else { + rowHeightsMap[gridTemplateParts[idx - 1]] = part + } + }) + const rowHeights = Object.values(rowHeightsMap) as string[] + return { + slots: LayoutService.generateSlots(Object.keys(rowHeightsMap)), + rowHeights, + colWidths: colWidths || [], + } + } + + /** + * Generates slot descriptors from grid template rows. + * Rows is an Array of strings extracted from grid template after left after parsing out + * row heights and column widths + * Example: + * "ga-1 ga-1 ga-2" 1fr + * "ga-3 ga-4 ga-5" auto + * "ga-6 ga-7 ga-7" 1fr + * @param rows + * @returns Array of SlotDescriptor + */ + static generateSlots(rows: string[]): SlotDescriptor[] { + const slotDescriptors: any[] = [] + const seenSlots = new Set() + rows.forEach((rowString, rowIdx) => { + const slotNames = rowString.split(" ") + slotNames.forEach((slotName, colIdx) => { + const trimmedSlot = slotName.trim() + if (!seenSlots.has(trimmedSlot)) { + seenSlots.add(trimmedSlot) + const rowSpan = rows.filter((row) => row.includes(trimmedSlot)).length + const colSpan = slotNames.filter( + (name) => name === trimmedSlot, + ).length + slotDescriptors.push( + SlotDescriptor.create({ + slot: trimmedSlot, + gridArea: trimmedSlot, + row: rowIdx, + column: colIdx, + rowSpan, + colSpan, + }), + ) + } + }) + }) + return slotDescriptors + } + + /** + * Checks if selected slots are adjacent. + * @returns true if adjacent, false otherwise + */ + checkIfAdjacent(): boolean { + const selectedSlots = this.slots.filter((slot: any) => slot.isSelected) + let minRow = Infinity, + maxRow = -Infinity, + minCol = Infinity, + maxCol = -Infinity, + totalSpan = 0 + selectedSlots?.forEach((slot: any) => { + if (slot.row !== undefined && slot.column !== undefined) { + minRow = Math.min(minRow, slot.row) + maxRow = Math.max(maxRow, slot.row + (slot.rowSpan - 1)) + minCol = Math.min(minCol, slot.column) + maxCol = Math.max(maxCol, slot.column + (slot.colSpan - 1)) + totalSpan += slot.rowSpan * slot.colSpan + } + }) + const area = (maxRow - minRow + 1) * (maxCol - minCol + 1) + this.minMaxSelections = { + minRow, + maxRow, + minColumn: minCol, + maxColumn: maxCol, + } + return selectedSlots && selectedSlots.length > 1 && area === totalSpan + } + + /** + * Counts the occurrences of each unique string in the given array and returns an array of objects + * representing each unique string, its count (span), and its first occurrence index (location). + * + * @param array - The array of strings to count occurrences in. + * @returns An array of objects, each containing: + * - `slotId`: The unique string from the input array. + * - `span`: The number of times the string appears in the input array. + * - `location`: The index of the first occurrence of the string in the input array. + */ + static countOccurrences( + array: string[], + ): { slotId: string; span: number; location: number }[] { + const occurrences: { slotId: string; span: number; location: number }[] = [] + for (let idx = 0; idx < array.length; idx++) { + const slotId = array[idx] + const found = occurrences.find((entry) => entry.slotId === slotId) + if (found === undefined) + occurrences.push({ slotId, span: 1, location: idx }) + else found.span++ + } + return occurrences + } + + /** + * Resets the heights of the grid template rows of the row tools container to their default values: "minmax(2rem, auto)". + * This function is used to ensure that the row toolbar heights are consistent and do not interfere with the layout of the grid. + * This function is called when the layout is updated (layoutService.updateSlots) and ensures that the row toolbar heights + * do not influence heights of the main layout grid cells. + */ + resetRowToolbarHeights(): void { + if (!this.gridArea) { + console.warn( + "Grid area is not defined. Cannot reset row toolbar heights.", + ) + return + } + const defaultRowHeights = Array.from( + { length: this.gridArea.length }, + () => "minmax(2rem, auto)", + ) + if (this.gridToolbarSpecs && this.gridToolbarSpecs.rowTools) { + this.gridToolbarSpecs.rowTools.gridTemplate = this.GAtoGT( + this.gridArea.map((row: any[]) => [ + row.every((cell: any) => cell === row[0]) + ? row[0].replace("gsa-", "gtra-") + : "gtra-" + uuidv4(), + ]), + defaultRowHeights, + "1fr", + ) + } + } + + /** + * Calculates row heights based on slots and optional row heights. + * @param slots - An array of slot descriptors. + * @param rowHeights - An optional array or string of row heights. + * @param demo - A boolean to indicate whether it is a demo. + * @returns An array of calculated row heights. + */ + calculateRowHeights(): string[] { + const slots = this.slots + const existing = this.rowHeights + const maxRowIdx = Math.max( + ...slots.map((slot: any) => slot.row + slot.rowSpan), + ) + const baseArray: string[] = Array.isArray(existing) + ? [...existing] + : Array.from( + { length: maxRowIdx }, + () => existing || "minmax(2rem, auto)", + ) + const calculatedRowHeights: string[] = [] + for (let rowIdx = 0; rowIdx < maxRowIdx; rowIdx++) { + const current = baseArray[rowIdx] + if (current && current !== "" && current.indexOf("auto") === -1) { + calculatedRowHeights[rowIdx] = current + continue + } + const slotHeights = slots + .filter( + (slot: any) => slot.row <= rowIdx && rowIdx < slot.row + slot.rowSpan, + ) + .map((slot: any) => { + const element = document.getElementById(slot.slot) + return element + ? Math.floor(element.getBoundingClientRect().height / slot.rowSpan) + : 0 + }) + const maxHeight = Math.max(...slotHeights) + calculatedRowHeights[rowIdx] = + maxHeight === 0 ? "minmax(2rem, auto)" : `${maxHeight + 2}px` + } + return calculatedRowHeights + } +} + +export default LayoutService diff --git a/src/services/index.ts b/src/services/index.ts new file mode 100644 index 0000000..ae075f4 --- /dev/null +++ b/src/services/index.ts @@ -0,0 +1,3 @@ +export { default as LayoutService } from "./Layout.service" +export { default as EventsService } from "./Events.service" +export { default as HistoryService } from "./History.service" diff --git a/src/test.scss b/src/test.scss new file mode 100644 index 0000000..dea6ba7 --- /dev/null +++ b/src/test.scss @@ -0,0 +1,2 @@ +@use "bootstrap/scss/bootstrap.scss"; +@use "@armco/shared-components/es/assets/Avatar.css"; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..e3cf5d7 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,222 @@ +// Recovered subset of Layout types (trimmed for initial compilation). Expand as needed. + +import type { ReactNode, RefObject } from "react" +import { BaseProps, FunctionType } from "@armco/types" +import type { + ArComponentResources, + ArDirections, + ArDisplayTypes, + ArSlotViewMode, +} from "@armco/shared-components/enums" +import { EventsService, HistoryService, LayoutService } from "@services" +import { SlotDescriptor } from "@models" + +export interface ISlotDescriptor { + colSpan: number + column: number + content?: Array | IComponentInfo + isSelected?: boolean + isSelectedForInlineDelete?: boolean + gridArea: string + props?: { + containerDisplayMode?: LayoutProps["displayMode"] + style?: React.CSSProperties + [key: string]: any + } + row: number + rowSpan: number + slot: string + splitFrom?: string +} + +export interface IGridSpecs { + rows: number + columns: number +} + +export interface IGridToolbarSpecs { + rowTools: { + slots: Array + gridTemplate: string + } + colTools: { + slots: Array + gridTemplate: string + } +} + +export interface IComponentInfo { + componentName: string + source?: ArComponentResources + descriptor?: { + content: Array + layout: string + } + props?: { + [key: string]: any + } + [key: string]: any +} + +export interface IMinMaxSelections { + minRow: number + maxRow: number + minColumn: number + maxColumn: number +} + +export type LayoutMode = "build" | "preview" | "release" + +export interface ReleaseSlotProps extends BaseProps { + slotDescriptor: SlotDescriptor + containerDisplayMode?: SlotProps["containerDisplayMode"] + content?: ReactNode +} + +export interface BuilderLayoutCanvasProps { + children?: ReactNode + isChild?: boolean + isGrid?: boolean +} + +export interface BuilderLayoutContainerProps { + children?: ReactNode + classes?: string + panelsDisplayable?: boolean +} +export interface BuilderSlotProps extends SlotProps {} + +export interface SlotToolsProps extends BaseProps { + slotDescriptor: SlotDescriptor + mode?: ArSlotViewMode + controlsEnabled?: boolean + horizontalSplitHandler?: FunctionType + verticalSplitHandler?: FunctionType + mergeHandler?: FunctionType + rowInsertHandler?: FunctionType + columnInsertHandler?: FunctionType + rowDeleteHandler?: FunctionType + columnDeleteHandler?: FunctionType + rowSelectHandler?: FunctionType + columnSelectHandler?: FunctionType +} + +export interface ReleaseLayoutProps extends BaseProps { + displayMode?: LayoutProps["displayMode"] + gridTemplate?: string + slots?: Array + slotRenderer?: FunctionType + mode?: LayoutProps["mode"] +} + +export type BuilderLayoutProps = LayoutProps + +export interface SlotControlProps { + class: string + tooltip?: string + isGridOnly?: boolean + isToolSlotOnly?: boolean + onClick?: FunctionType + onMouseEnter?: FunctionType + onMouseLeave?: FunctionType +} + +export interface LayoutControlPanelProps extends BaseProps { + columnDeleteEnabled?: boolean + redoEnabled?: boolean + rowDeleteEnabled?: boolean + show?: boolean + slots?: Array + undoEnabled?: boolean +} + +export interface ResizableProps extends BaseProps { + componentName?: string + children?: ReactNode + display?: ArDisplayTypes + directions?: Array + reClasses?: string + [key: string]: any +} + +export interface LayoutProps extends BaseProps { + acceptTextOnClick?: boolean + colWidths?: string | Array + displayMode?: + | "grid" + | "inline" + | "inline-flex" + | "inline-grid" + | "flex" + | "inline-block" + | "block" + | "table" + hideBuildModePaddings?: boolean + gridSpecs?: string | IGridSpecs + gridTemplate?: string + isChild?: boolean + activeSlot?: SlotDescriptor + readonly mode?: LayoutMode + rowHeights?: string | Array + onLayoutChange?: FunctionType + slotDropHandler?: FunctionType + onSlotSelect?: FunctionType + showControls?: boolean + showPanels?: boolean + slotRenderer?: FunctionType + slots?: Array + url?: string +} + +export interface SlotProps extends Omit { + childRef?: RefObject + slotDescriptor: SlotDescriptor + containerDisplayMode?: LayoutProps["displayMode"] + hideBuildModePaddings?: boolean + isFirst?: boolean + isLast?: boolean + activeSlot?: SlotDescriptor + mode?: ArSlotViewMode + controlsEnabled?: boolean + acceptDropTypes?: Array + layoutMode?: LayoutProps["mode"] + content?: ReactNode + columnDeleteHandler?: FunctionType + columnInsertHandler?: FunctionType + columnSelectHandler?: FunctionType + dropHandler?: FunctionType + horizontalSplitHandler?: FunctionType + mergeHandler?: FunctionType + onClick?: FunctionType + onSlotSelect?: FunctionType + rowDeleteHandler?: FunctionType + rowInsertHandler?: FunctionType + rowSelectHandler?: FunctionType + verticalSplitHandler?: FunctionType + slotRenderer?: FunctionType +} + +export type UseLayoutInitProps = LayoutProps & { + rerender: FunctionType +} + +export interface LayoutContextType { + layoutService: LayoutService + eventsService: EventsService + historyService: HistoryService> + controlsEnabled: boolean + enableControls: FunctionType + selectionOnlyModeEnabled: boolean + enableSelectionOnlyMode: FunctionType + panelsDisplayed: boolean + displayPanels: FunctionType +} + +export interface LayoutProviderProps { + children: ReactNode + layoutService: LayoutService + eventsService: EventsService + historyService: HistoryService> + showPanels?: boolean + showControls?: boolean +} diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..e69de29 diff --git a/tsconfig.json b/tsconfig.json index a951d6b..a8503e0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ "dom.iterable", "esnext" ], + "baseUrl": ".", "outDir": "build", "allowJs": true, "skipLibCheck": true, @@ -19,7 +20,14 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - "jsx": "react-jsx" + "jsx": "react-jsx", + "paths": { + "@models": ["src/models/index.ts"], + "@models/*": ["src/models/*"], + "@hooks/*": ["src/hooks/*"], + "@services": ["src/services/index.ts"], + "@services/*": ["src/services/*"], + } }, "include": [ "src" diff --git a/vite-dev.config.ts b/vite-dev.config.ts new file mode 100644 index 0000000..0da994b --- /dev/null +++ b/vite-dev.config.ts @@ -0,0 +1,21 @@ +import { defineConfig } from "vitest/config" +import react from "@vitejs/plugin-react" +import tsconfigPaths from "vite-tsconfig-paths" + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react(), tsconfigPaths()], + server: { + open: true, + }, + build: { + outDir: "build", + sourcemap: true, + }, + test: { + globals: true, + environment: "jsdom", + setupFiles: "src/setupTests", + mockReset: true, + }, +}) diff --git a/vite.config.ts b/vite.config.ts index 06192d7..7ed5185 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -5,12 +5,14 @@ import react from "@vitejs/plugin-react" import dts from "vite-plugin-dts" import { libInjectCss } from "vite-plugin-lib-inject-css" import { externalizeDeps } from "vite-plugin-externalize-deps" +import tsconfigPaths from "vite-tsconfig-paths" // https://vitejs.dev/config/ export default defineConfig({ plugins: [ react(), libInjectCss(), + tsconfigPaths(), dts({ outDir: "build/types" }), externalizeDeps(), ],