diff --git a/engine/src/tools/PathCursor.js b/engine/src/tools/PathCursor.js index 4a037e15a..7d2d9cd2f 100644 --- a/engine/src/tools/PathCursor.js +++ b/engine/src/tools/PathCursor.js @@ -122,7 +122,7 @@ Wick.Tools.PathCursor = class extends Wick.Tool { onDoubleClick (e) { this.hitResult = this._updateHitResult(e); - if (this.detailedEditing == null) { + if (this.detailedEditing == null && this.hitResult.item) { // If detailed editing is off, turn it on for this path. this.detailedEditing = this.hitResult.item; this.detailedEditing.setFullySelected(true); diff --git a/package-lock.json b/package-lock.json index 0dfbdae63..de55503b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,7 +33,7 @@ "react-modal": "^3.16.3", "react-numeric-input": "^2.2.3", "react-reflex": "^3.0.6", - "react-resize-detector": "^12.3.0", + "react-resize-detector": "^9.1.1", "react-rnd": "^10.5.2", "react-scripts": "^5.0.1", "react-select": "^5.9.0", @@ -2498,6 +2498,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@emotion/babel-plugin/node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/@emotion/cache": { "version": "10.0.29", "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", @@ -3085,6 +3094,18 @@ "node": ">=8.6" } }, + "node_modules/@jest/core/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@jest/core/node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3333,6 +3354,18 @@ "node": ">=8.6" } }, + "node_modules/@jest/transform/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@jest/transform/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -3766,7 +3799,6 @@ "version": "2.5.6", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -3806,7 +3838,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3827,7 +3858,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3848,7 +3878,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3869,7 +3898,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3890,7 +3918,6 @@ "cpu": [ "arm" ], - "dev": true, "libc": [ "glibc" ], @@ -3914,7 +3941,6 @@ "cpu": [ "arm" ], - "dev": true, "libc": [ "musl" ], @@ -3938,7 +3964,6 @@ "cpu": [ "arm64" ], - "dev": true, "libc": [ "glibc" ], @@ -3962,7 +3987,6 @@ "cpu": [ "arm64" ], - "dev": true, "libc": [ "musl" ], @@ -3986,7 +4010,6 @@ "cpu": [ "x64" ], - "dev": true, "libc": [ "glibc" ], @@ -4010,7 +4033,6 @@ "cpu": [ "x64" ], - "dev": true, "libc": [ "musl" ], @@ -4034,7 +4056,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4055,7 +4076,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4076,7 +4096,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -4090,20 +4109,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/watcher/node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.17", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.17.tgz", @@ -4258,6 +4263,18 @@ "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", "license": "MIT" }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -4467,6 +4484,15 @@ "node": ">=10" } }, + "node_modules/@svgr/core/node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/@svgr/hast-util-to-babel-ast": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz", @@ -4536,6 +4562,15 @@ "node": ">=10" } }, + "node_modules/@svgr/plugin-svgo/node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/@svgr/webpack": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-5.5.0.tgz", @@ -5070,6 +5105,16 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "license": "MIT" }, + "node_modules/@types/react": { + "version": "19.2.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", + "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, "node_modules/@types/react-transition-group": { "version": "4.4.12", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz", @@ -5079,6 +5124,13 @@ "@types/react": "*" } }, + "node_modules/@types/react/node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT", + "peer": true + }, "node_modules/@types/resolve": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", @@ -6822,6 +6874,15 @@ "node": ">=10" } }, + "node_modules/babel-preset-react-app/node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/bach": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", @@ -7996,6 +8057,15 @@ "node": ">=8" } }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -8336,6 +8406,15 @@ "postcss": "^8.2.15" } }, + "node_modules/cssnano/node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/csso": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz", @@ -8715,7 +8794,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, "license": "Apache-2.0", "optional": true, "engines": { @@ -9348,16 +9426,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/es-toolkit": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.49.0.tgz", - "integrity": "sha512-G5iZ6Pc/FNRY/soKZHC+TxGDD83rHUDXxzaWhGCX44vAv/tMs56WMusnm/KMNK+luUPsgA9U28cGr4RDlSzL2g==", - "license": "MIT", - "workspaces": [ - "docs", - "benchmarks" - ] - }, "node_modules/es5-ext": { "version": "0.10.64", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", @@ -9954,6 +10022,18 @@ "node": ">=8.6" } }, + "node_modules/eslint-webpack-plugin/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/eslint-webpack-plugin/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -10593,6 +10673,18 @@ "node": ">=8.6" } }, + "node_modules/fast-glob/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/fast-glob/node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -11246,6 +11338,18 @@ "node": ">=0.12.0" } }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -12550,6 +12654,18 @@ "node": ">=8.6" } }, + "node_modules/http-proxy-middleware/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/http-proxy-middleware/node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -12649,7 +12765,7 @@ "version": "5.1.9", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz", "integrity": "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/import-fresh": { @@ -13928,6 +14044,18 @@ "node": ">=8.6" } }, + "node_modules/jest-config/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/jest-config/node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -14126,6 +14254,18 @@ "node": ">=8.6" } }, + "node_modules/jest-haste-map/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/jest-haste-map/node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -14260,6 +14400,18 @@ "node": ">=8.6" } }, + "node_modules/jest-message-util/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/jest-message-util/node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -14486,6 +14638,18 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/jest-validate": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", @@ -14760,6 +14924,18 @@ "node": ">=8.6" } }, + "node_modules/jest-watch-typeahead/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/jest-watch-typeahead/node_modules/pretty-format": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", @@ -14913,6 +15089,13 @@ "jiti": "bin/jiti.js" } }, + "node_modules/jquery": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", + "license": "MIT", + "peer": true + }, "node_modules/js-binary-schema-parser": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/js-binary-schema-parser/-/js-binary-schema-parser-2.0.3.tgz", @@ -16208,7 +16391,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "dev": true, "license": "MIT", "optional": true }, @@ -17018,12 +17200,12 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -17822,6 +18004,15 @@ "node": ">=10" } }, + "node_modules/postcss-loader/node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/postcss-logical": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", @@ -19278,15 +19469,16 @@ } }, "node_modules/react-resize-detector": { - "version": "12.3.0", - "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-12.3.0.tgz", - "integrity": "sha512-mIDOVrTHKGnKe6qEUWi8dFdfHM5CPyTOpqoHctdMQf89Ljm/0qqDIzkP3vTRZZJi9/raaMiRxDEOqO4you5x+A==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/react-resize-detector/-/react-resize-detector-9.1.1.tgz", + "integrity": "sha512-siLzop7i4xIvZIACE/PHTvRegA8QRCEt0TfmvJ/qCIFQJ4U+3NuYcF8tNDmDWxfIn+X1eNCyY2rauH4KRxge8w==", "license": "MIT", "dependencies": { - "es-toolkit": "^1.39.6" + "lodash": "^4.17.21" }, "peerDependencies": { - "react": "^18.0.0 || ^19.0.0" + "react": "^16.0.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-rnd": { @@ -20514,7 +20706,7 @@ "version": "1.101.0", "resolved": "https://registry.npmjs.org/sass/-/sass-1.101.0.tgz", "integrity": "sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "chokidar": "^5.0.0", @@ -20573,7 +20765,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "readdirp": "^5.0.0" @@ -20589,7 +20781,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 20.19.0" @@ -22462,6 +22654,18 @@ "node": ">=8.6" } }, + "node_modules/tailwindcss/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tailwindcss/node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -22750,18 +22954,6 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -23163,6 +23355,20 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/ua-parser-js": { "version": "1.0.41", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz", @@ -24056,6 +24262,18 @@ "node": ">=0.12.0" } }, + "node_modules/webpack-dev-server/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/webpack-dev-server/node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -24766,15 +24984,6 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "license": "ISC" }, - "node_modules/yaml": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", - "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", - "license": "ISC", - "engines": { - "node": ">= 6" - } - }, "node_modules/yargs": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz", diff --git a/package.json b/package.json index 0020c9524..d842969e4 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "react-modal": "^3.16.3", "react-numeric-input": "^2.2.3", "react-reflex": "^3.0.6", - "react-resize-detector": "^12.3.0", + "react-resize-detector": "^9.1.1", "react-rnd": "^10.5.2", "react-scripts": "^5.0.1", "react-select": "^5.9.0", diff --git a/src/Editor/Editor.jsx b/src/Editor/Editor.jsx index 7d9594408..663803ff5 100644 --- a/src/Editor/Editor.jsx +++ b/src/Editor/Editor.jsx @@ -52,6 +52,7 @@ import AssetLibrary from './Panels/AssetLibrary/AssetLibrary'; import Outliner from './Panels/Outliner/Outliner'; import OutlinerExpandButton from './Panels/OutlinerExpandButton/OutlinerExpandButton'; import WickCodeEditor from './PopOuts/WickCodeEditor/WickCodeEditor'; +import ModifiersPanel from './PopOuts/ModifiersPanel/ModifiersPanel'; import EditorWrapper from './EditorWrapper'; @@ -163,6 +164,7 @@ class Editor extends EditorCore { this.project = null; this.paper = null; this.editorVersion = version + ''; + this.modifierKeys = { ctrlKey: false, altKey: false, shiftKey: false }; // GUI state this.state = { @@ -171,6 +173,7 @@ class Editor extends EditorCore { activeModalName: window.localStorage.skipWelcomeMessage ? null : "WelcomeMessage", activeModalQueue: [], codeEditorOpen: false, + modifiersPanelOpen: false, scriptToEdit: "default", showCanvasActions: false, showBooleanCanvasActions: false, @@ -284,6 +287,7 @@ class Editor extends EditorCore { onStopAssetLibraryResize: throttle(this.onStopAssetLibraryResize, this.resizeThrottleAmount), onStopTimelineResize: throttle(this.onStopTimelineResize, this.resizeThrottleAmount), onStopCodeEditorResize: throttle(this.onStopCodeEditorResize, this.resizeThrottleAmount), + onStopModifiersPanelResize: throttle(this.onStopModifiersPanelResize, this.resizeThrottleAmount), onResize: throttle(this.onResize, this.resizeThrottleAmount), onWindowResize: throttle(this.onWindowResize, this.windowResizeThrottleAmount), }; @@ -342,6 +346,7 @@ class Editor extends EditorCore { ...this.state, project: this.project.serialize(), codeEditorWindowProperties: this.getDefaultCodeEditorProperties(), + modifiersPanelWindowProperties: this.getDefaultModifiersPanelProperties(), }); // Leave Page warning. @@ -541,6 +546,7 @@ class Editor extends EditorCore { // reset the code window if we resize the window. this.setState({ codeEditorWindowProperties: this.getDefaultCodeEditorProperties(), + modifiersPanelWindowProperties: this.getDefaultModifiersPanelProperties(), }); // re-render project to avoid incorrect pan @@ -565,6 +571,20 @@ class Editor extends EditorCore { ); } + getDefaultModifiersPanelProperties = () => { + return ( + { + width: 260, + height: 160, + x: 0, + y: 40, + minWidth: 200, + minHeight: 125, + fontSize: 16, + } + ); + } + updateLastColors = (color, edit) => { let newArray = this.state.lastColorsUsed.concat([]); // make a deep copy. @@ -630,6 +650,21 @@ class Editor extends EditorCore { }); } + /** + * Updates the modifiers panel properties in the state. + * @param {object} newProperties object with new modifiers panel properties. Can include width, height, x, y. + */ + updateModifiersPanelWindowProperties = (newProperties) => { + let finalProperties = this.state.modifiersPanelWindowProperties; + Object.keys(newProperties).forEach(key => { + finalProperties[key] = newProperties[key]; + }); + + this.setState({ + modifiersPanelWindowProperties: finalProperties, + }); + } + /** * Called when any script is updated. @@ -751,6 +786,45 @@ class Editor extends EditorCore { }); } + /** + * Opens and closes the modifiers panel depending on the state of the panel. + * @param {boolean} state - Optional. True will open the modifiers panel, false will close. + */ + toggleModifiersPanel = (state) => { + if (state === undefined || (typeof state !== "boolean")) { + state = !this.state.modifiersPanelOpen; + } + + this.setState({ + modifiersPanelOpen: state, + }); + } + + // Maps our modifier key names to the values paper.js' listens for. + static MODIFIER_KEY_DOM_NAMES = { ctrl: 'Control', alt: 'Alt', shift: 'Shift' }; + + /** + * Toggles a modifier key on or off. Toggled-on keys are applied to every mouse event + * dispatched through the editor (see EditorWrapper's onMouseDown), and are also reflected + * as real keydown/keyup events so Paper.js tools (which track modifiers via their own + * Key module, not the mouse event) pick up the change too. + * @param {string} key - The key to toggle. Should be one of 'ctrl', 'alt', or 'shift'. + */ + toggleModifierKey = (key) => { + let propName = key.toLowerCase() + 'Key'; + let isDown = this.modifierKeys[propName] = !this.modifierKeys[propName]; + + let domKey = Editor.MODIFIER_KEY_DOM_NAMES[key.toLowerCase()]; + document.dispatchEvent(new KeyboardEvent(isDown ? 'keydown' : 'keyup', { + key: domKey, + bubbles: true, + cancelable: true, + [propName]: isDown, + })); + + this.forceUpdate(); + } + /** * Opens and closes the canvas actions popover. * @param {boolean} state - Optional. True will open the canvas actions menu, false will close. @@ -1151,6 +1225,7 @@ class Editor extends EditorCore { toast={this.toast} openExportMedia={() => { this.openModal('ExportMedia') }} openExportOptions={() => { this.openModal('ExportOptions') }} + toggleModifiersPanel={this.toggleModifiersPanel} /> @@ -1459,6 +1534,15 @@ class Editor extends EditorCore { setConsoleLogs={this.setConsoleLogs} renderSize={renderSize} />} + {this.state.modifiersPanelOpen && + } diff --git a/src/Editor/EditorWrapper.jsx b/src/Editor/EditorWrapper.jsx index 84aebb8d7..a69fa41e9 100644 --- a/src/Editor/EditorWrapper.jsx +++ b/src/Editor/EditorWrapper.jsx @@ -40,11 +40,29 @@ export default function EditorWrapper(props) { // eslint-disable-next-line react-hooks/exhaustive-deps }, []) + useEffect(() => { + let editorElem = document.getElementById('editor'); + + // Merge the virtual modifier-key state onto the real, trusted mousedown event + // instead of replacing it. ctrlKey/altKey/shiftKey are accessor properties + // inherited from MouseEvent.prototype, so Object.defineProperty is needed to define them on the instance. + let onMouseDownCapture = (e) => { + if (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA") return; + + Object.defineProperty(e, 'ctrlKey', { value: e.ctrlKey || props.editor.modifierKeys.ctrlKey, configurable: true }); + Object.defineProperty(e, 'altKey', { value: e.altKey || props.editor.modifierKeys.altKey, configurable: true }); + Object.defineProperty(e, 'shiftKey', { value: e.shiftKey || props.editor.modifierKeys.shiftKey, configurable: true }); + }; + + editorElem.addEventListener('mousedown', onMouseDownCapture, true); + return () => editorElem.removeEventListener('mousedown', onMouseDownCapture, true); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); return ( { props.editor.autoSaveProject(() => { "Project Autosaved" }) }} + processError={(_error, _errorInfo) => { props.editor.autoSaveProject(() => { "Project Autosaved" }) }} > ) -} +} \ No newline at end of file diff --git a/src/Editor/Panels/MenuBar/MenuBar.jsx b/src/Editor/Panels/MenuBar/MenuBar.jsx index d65cc0285..baf4761df 100644 --- a/src/Editor/Panels/MenuBar/MenuBar.jsx +++ b/src/Editor/Panels/MenuBar/MenuBar.jsx @@ -61,6 +61,11 @@ class MenuBar extends Component { useClickEvent={true} /> + + {this.props.exporting ? this.props.openExportMedia() : this.props.openExportOptions()}} @@ -99,6 +104,11 @@ class MenuBar extends Component {
+ + . + */ + +import { Rnd } from 'react-rnd'; +import ActionButton from 'Editor/Util/ActionButton/ActionButton'; + +import classNames from 'classnames'; + +import 'Editor/styles/PopOuts/_modifierspanel.scss'; + +const MODIFIER_KEYS = ['ctrl', 'alt', 'shift']; + +export default function ModifiersPanel(props) { + + /** + * Renders the ctrl/alt/shift toggle buttons. + */ + function renderModifierKeyButtons() { + return MODIFIER_KEYS.map((key) => ( + + )); + } + + /** + * To be called when the modifiers popout is repositioned. + */ + function onDragHandler(_e, d) { + props.updateModifiersPanelWindowProperties({ + x: d.x, + y: d.y, + }); + } + + /** + * To be called when the modifiers popout is resized. + */ + function onResizeHandler(_e, _dir, ref, _delta, _position) { + props.updateModifiersPanelWindowProperties({ + width: ref.style.width, + height: ref.style.height, + }); + } + + if (props.renderSize === 'small') { + return ( + +
+
+
+ Modifier Keys +
+ +
+
+ {renderModifierKeyButtons()} +
+
+
) + } + else return ( + + +
+
Modifiers
+ +
+
+ {renderModifierKeyButtons()} +
+
+ ) +} \ No newline at end of file diff --git a/src/Editor/styles/PopOuts/_modifierspanel.scss b/src/Editor/styles/PopOuts/_modifierspanel.scss new file mode 100644 index 000000000..224fa0436 --- /dev/null +++ b/src/Editor/styles/PopOuts/_modifierspanel.scss @@ -0,0 +1,128 @@ +/* + * Copyright 2026 Candlestickers + * + * This file is part of Candlestick. + * + * Candlestick is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Candlestick is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Candlestick. If not, see . + */ + +@use 'sass:color'; +@use 'Editor/_wickbrand.scss' as *; + +#cs-modifiers-panel-resizeable, +#cs-modifiers-panel-resizeable-small { + --handle-height: 40px; + display: flex; + box-shadow: var(--wick-box-shadow); + border-radius: var(--border-radius-primary); +} + +.cs-modifiers-panel-small { + --handle-height: 40px; + display: flex; + flex-direction: column; + height: 100%; +} + +.cs-modifiers-panel-drag-handle { + position: relative; + width: 100%; + height: var(--handle-height); + background-color: var(--wick-primary); + color: var(--wick-text-primary); + cursor: move; + + display: flex; + flex-direction: row; + align-items: center; + border-top-right-radius: var(--border-radius-primary); + border-top-left-radius: var(--border-radius-primary); +} + +.cs-modifiers-panel-title { + padding-left: 8px; + color: white; + margin-right: auto; + white-space: nowrap; +} + +.cs-modifiers-panel-title.small { + font-size: 20px; + font-weight: normal; + padding-left: 4px; +} + +.cs-modifiers-panel-icon { + display: flex; + align-items: center; + justify-content: center; + padding-left: 8px; + color: white; +} + +.cs-modifiers-close-button { + width: 36px; + height: 36px; + min-width: 36px; + min-height: 36px; + margin-right: 4px; + margin-left: auto; +} + +.cs-modifiers-panel-content { + background-color: var(--wick-secondary); + color: var(--wick-text-secondary); + width: 100%; + height: calc(100% - var(--handle-height)); + flex: 1; + + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-items: center; + justify-content: center; + gap: 12px; + padding: 12px; +} + +.cs-modifier-key-button { + display: inline-block; + min-width: 2.4em; + padding: 6px 10px; + + background-color: #eee; + border-radius: 3px; + border: 1px solid #b4b4b4; + box-shadow: 0 1px 1px rgba(0, 0, 0, .2), 0 2px 0 0 rgba(255, 255, 255, .7) inset; + color: #333; + font-size: 1.1em; + font-weight: 700; + line-height: 1; + white-space: nowrap; + cursor: pointer; +} + +.cs-modifier-key-button:hover { + background-color: #e0e0e0; +} + +.cs-modifier-key-button:active { + box-shadow: 0 1px 1px rgba(0, 0, 0, .2) inset; +} + +.cs-modifier-key-button.active { + background-color: $wick-cs-yellow; + border-color: color.adjust($wick-cs-yellow, $lightness: -10%); + box-shadow: 0 1px 1px rgba(0, 0, 0, .2) inset; +} \ No newline at end of file