diff --git a/package-lock.json b/package-lock.json index cf66bab374..90f794ad0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,9 @@ "version": "2.0.0", "license": "Apache-2.0", "dependencies": { - "@blockly/continuous-toolbox": "^5.0.15", + "@blockly/continuous-toolbox": "^7.0.0-beta.1", "@blockly/field-colour": "^4.0.2", - "blockly": "^11.0.0" + "blockly": "^12.0.0-beta.1" }, "devDependencies": { "@commitlint/cli": "^17.8.1", @@ -125,14 +125,15 @@ } }, "node_modules/@blockly/continuous-toolbox": { - "version": "5.0.17", - "resolved": "https://registry.npmjs.org/@blockly/continuous-toolbox/-/continuous-toolbox-5.0.17.tgz", - "integrity": "sha512-3JCSimCo5KEWvvN4qC66vs2L/WtJIHepoIfkPNcbvMwjwYxJ484UPK2LKdlyI1842mgFfcYM3nTERjfa+Q4rXA==", + "version": "7.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@blockly/continuous-toolbox/-/continuous-toolbox-7.0.0-beta.1.tgz", + "integrity": "sha512-IKu0whdtRTmdXSB11efSJ5fCNzQtAp98fv+7KnZk/V7Q/xAhVAutWWQE+FJvr9lKJlkeYqm9m+cxDhOBtlVP1w==", + "license": "Apache-2.0", "engines": { "node": ">=8.17.0" }, "peerDependencies": { - "blockly": "^10.0.0" + "blockly": "^12.0.0-beta.0" } }, "node_modules/@blockly/field-colour": { @@ -1341,11 +1342,12 @@ } }, "node_modules/blockly": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/blockly/-/blockly-11.0.0.tgz", - "integrity": "sha512-6Ie7HuZWZLaETIVKFEP4FPDz267Pubn6+weQNZvXzqnkOYp9sKPSsPue8QIMCV9Qb5F4wYhqivgiDcZJcE1UlQ==", + "version": "12.0.0-beta.1", + "resolved": "https://registry.npmjs.org/blockly/-/blockly-12.0.0-beta.1.tgz", + "integrity": "sha512-lECwZ4K+YuLXMM0yxWTz1lwkmDl424sst7h/dhtSefuCki8afjI/F87byYK/ZIZsMKBEz2+8wEJ1Wlx5cYWIAg==", + "license": "Apache-2.0", "dependencies": { - "jsdom": "23.0.0" + "jsdom": "25.0.1" }, "engines": { "node": ">=18" @@ -2023,14 +2025,14 @@ } }, "node_modules/cssstyle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", - "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", + "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", "dependencies": { - "rrweb-cssom": "^0.6.0" + "rrweb-cssom": "^0.7.1" }, "engines": { - "node": ">=14" + "node": ">=18" } }, "node_modules/dargs": { @@ -3043,9 +3045,9 @@ } }, "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.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -3522,9 +3524,9 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -4006,37 +4008,37 @@ } }, "node_modules/jsdom": { - "version": "23.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.0.0.tgz", - "integrity": "sha512-cbL/UCtohJguhFC7c2/hgW6BeZCNvP7URQGnx9tSJRYKCdnfbfWOrtuLTMfiB2VxKsx5wPHVsh/J0aBy9lIIhQ==", + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", + "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", "dependencies": { - "cssstyle": "^3.0.0", + "cssstyle": "^4.1.0", "data-urls": "^5.0.0", "decimal.js": "^10.4.3", "form-data": "^4.0.0", "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.7", + "nwsapi": "^2.2.12", "parse5": "^7.1.2", - "rrweb-cssom": "^0.6.0", + "rrweb-cssom": "^0.7.1", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.3", + "tough-cookie": "^5.0.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^7.0.0", "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0", - "ws": "^8.14.2", + "ws": "^8.18.0", "xml-name-validator": "^5.0.0" }, "engines": { "node": ">=18" }, "peerDependencies": { - "canvas": "^3.0.0" + "canvas": "^2.11.2" }, "peerDependenciesMeta": { "canvas": { @@ -4551,9 +4553,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.9", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz", - "integrity": "sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==" + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", + "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==" }, "node_modules/object-assign": { "version": "4.1.1", @@ -4747,11 +4749,11 @@ } }, "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", "dependencies": { - "entities": "^4.4.0" + "entities": "^4.5.0" }, "funding": { "url": "https://github.com/inikulin/parse5?sponsor=1" @@ -4911,11 +4913,6 @@ "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", "dev": true }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -4939,11 +4936,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, "node_modules/quick-lru": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", @@ -5187,7 +5179,8 @@ "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true }, "node_modules/resolve": { "version": "1.22.8", @@ -5298,9 +5291,9 @@ } }, "node_modules/rrweb-cssom": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", - "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==" + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==" }, "node_modules/run-async": { "version": "2.4.1", @@ -6157,6 +6150,22 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, + "node_modules/tldts": { + "version": "6.1.65", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.65.tgz", + "integrity": "sha512-xU9gLTfAGsADQ2PcWee6Hg8RFAv0DnjMGVJmDnUmI8a9+nYmapMQix4afwrdaCtT+AqP4MaxEzu7cCrYmBPbzQ==", + "dependencies": { + "tldts-core": "^6.1.65" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.65", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.65.tgz", + "integrity": "sha512-Uq5t0N0Oj4nQSbU8wFN1YYENvMthvwU13MQrMJRspYCGLSAZjAfoBOJki5IQpnBM/WFskxxC/gIOTwaedmHaSg==" + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -6191,17 +6200,14 @@ } }, "node_modules/tough-cookie": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz", + "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==", "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" + "tldts": "^6.1.32" }, "engines": { - "node": ">=6" + "node": ">=16" } }, "node_modules/tr46": { @@ -6358,14 +6364,6 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, - "node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -6414,15 +6412,6 @@ "punycode": "^2.1.0" } }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -6870,9 +6859,9 @@ } }, "node_modules/whatwg-url": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", - "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", + "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", "dependencies": { "tr46": "^5.0.0", "webidl-conversions": "^7.0.0" @@ -6947,9 +6936,9 @@ } }, "node_modules/ws": { - "version": "8.15.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.15.1.tgz", - "integrity": "sha512-W5OZiCjXEmk0yZ66ZN82beM5Sz7l7coYxpRkzS+p9PP+ToQry8szKh+61eNktr7EA9DOwvFGhfC605jDHbP6QQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "engines": { "node": ">=10.0.0" }, @@ -7134,9 +7123,9 @@ } }, "@blockly/continuous-toolbox": { - "version": "5.0.17", - "resolved": "https://registry.npmjs.org/@blockly/continuous-toolbox/-/continuous-toolbox-5.0.17.tgz", - "integrity": "sha512-3JCSimCo5KEWvvN4qC66vs2L/WtJIHepoIfkPNcbvMwjwYxJ484UPK2LKdlyI1842mgFfcYM3nTERjfa+Q4rXA==", + "version": "7.0.0-beta.1", + "resolved": "https://registry.npmjs.org/@blockly/continuous-toolbox/-/continuous-toolbox-7.0.0-beta.1.tgz", + "integrity": "sha512-IKu0whdtRTmdXSB11efSJ5fCNzQtAp98fv+7KnZk/V7Q/xAhVAutWWQE+FJvr9lKJlkeYqm9m+cxDhOBtlVP1w==", "requires": {} }, "@blockly/field-colour": { @@ -8160,11 +8149,11 @@ "dev": true }, "blockly": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/blockly/-/blockly-11.0.0.tgz", - "integrity": "sha512-6Ie7HuZWZLaETIVKFEP4FPDz267Pubn6+weQNZvXzqnkOYp9sKPSsPue8QIMCV9Qb5F4wYhqivgiDcZJcE1UlQ==", + "version": "12.0.0-beta.1", + "resolved": "https://registry.npmjs.org/blockly/-/blockly-12.0.0-beta.1.tgz", + "integrity": "sha512-lECwZ4K+YuLXMM0yxWTz1lwkmDl424sst7h/dhtSefuCki8afjI/F87byYK/ZIZsMKBEz2+8wEJ1Wlx5cYWIAg==", "requires": { - "jsdom": "23.0.0" + "jsdom": "25.0.1" } }, "body-parser": { @@ -8677,11 +8666,11 @@ } }, "cssstyle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", - "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", + "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", "requires": { - "rrweb-cssom": "^0.6.0" + "rrweb-cssom": "^0.7.1" } }, "dargs": { @@ -9484,9 +9473,9 @@ "dev": true }, "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.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -9842,9 +9831,9 @@ } }, "https-proxy-agent": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", - "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", "requires": { "agent-base": "^7.0.2", "debug": "4" @@ -10207,30 +10196,30 @@ } }, "jsdom": { - "version": "23.0.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.0.0.tgz", - "integrity": "sha512-cbL/UCtohJguhFC7c2/hgW6BeZCNvP7URQGnx9tSJRYKCdnfbfWOrtuLTMfiB2VxKsx5wPHVsh/J0aBy9lIIhQ==", + "version": "25.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.1.tgz", + "integrity": "sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==", "requires": { - "cssstyle": "^3.0.0", + "cssstyle": "^4.1.0", "data-urls": "^5.0.0", "decimal.js": "^10.4.3", "form-data": "^4.0.0", "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.7", + "nwsapi": "^2.2.12", "parse5": "^7.1.2", - "rrweb-cssom": "^0.6.0", + "rrweb-cssom": "^0.7.1", "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.3", + "tough-cookie": "^5.0.0", "w3c-xmlserializer": "^5.0.0", "webidl-conversions": "^7.0.0", "whatwg-encoding": "^3.1.1", "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0", - "ws": "^8.14.2", + "ws": "^8.18.0", "xml-name-validator": "^5.0.0" } }, @@ -10641,9 +10630,9 @@ } }, "nwsapi": { - "version": "2.2.9", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.9.tgz", - "integrity": "sha512-2f3F0SEEer8bBu0dsNCFF50N0cTThV1nWFYcEYFZttdW0lDAoybv9cQoK7X7/68Z89S7FoRrVjP1LPX4XRf9vg==" + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", + "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==" }, "object-assign": { "version": "4.1.1", @@ -10783,11 +10772,11 @@ } }, "parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", "requires": { - "entities": "^4.4.0" + "entities": "^4.5.0" } }, "parseurl": { @@ -10907,11 +10896,6 @@ "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", "dev": true }, - "psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" - }, "punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -10926,11 +10910,6 @@ "side-channel": "^1.0.4" } }, - "querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" - }, "quick-lru": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", @@ -11122,7 +11101,8 @@ "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true }, "resolve": { "version": "1.22.8", @@ -11202,9 +11182,9 @@ } }, "rrweb-cssom": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", - "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==" + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==" }, "run-async": { "version": "2.4.1", @@ -11885,6 +11865,19 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, + "tldts": { + "version": "6.1.65", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.65.tgz", + "integrity": "sha512-xU9gLTfAGsADQ2PcWee6Hg8RFAv0DnjMGVJmDnUmI8a9+nYmapMQix4afwrdaCtT+AqP4MaxEzu7cCrYmBPbzQ==", + "requires": { + "tldts-core": "^6.1.65" + } + }, + "tldts-core": { + "version": "6.1.65", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.65.tgz", + "integrity": "sha512-Uq5t0N0Oj4nQSbU8wFN1YYENvMthvwU13MQrMJRspYCGLSAZjAfoBOJki5IQpnBM/WFskxxC/gIOTwaedmHaSg==" + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -11910,14 +11903,11 @@ "dev": true }, "tough-cookie": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", - "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz", + "integrity": "sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==", "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" + "tldts": "^6.1.32" } }, "tr46": { @@ -12019,11 +12009,6 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, - "universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==" - }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -12049,15 +12034,6 @@ "punycode": "^2.1.0" } }, - "url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "requires": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -12371,9 +12347,9 @@ "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==" }, "whatwg-url": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", - "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", + "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", "requires": { "tr46": "^5.0.0", "webidl-conversions": "^7.0.0" @@ -12427,9 +12403,9 @@ } }, "ws": { - "version": "8.15.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.15.1.tgz", - "integrity": "sha512-W5OZiCjXEmk0yZ66ZN82beM5Sz7l7coYxpRkzS+p9PP+ToQry8szKh+61eNktr7EA9DOwvFGhfC605jDHbP6QQ==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "requires": {} }, "xml-name-validator": { diff --git a/package.json b/package.json index cfc9274a1f..2cdb08ac5f 100644 --- a/package.json +++ b/package.json @@ -29,8 +29,8 @@ "webpack-dev-server": "^4.11.1" }, "dependencies": { - "@blockly/continuous-toolbox": "^5.0.15", + "@blockly/continuous-toolbox": "^7.0.0-beta.1", "@blockly/field-colour": "^4.0.2", - "blockly": "^11.0.0" + "blockly": "^12.0.0-beta.1" } } diff --git a/src/checkable_continuous_flyout.js b/src/checkable_continuous_flyout.js deleted file mode 100644 index c228131504..0000000000 --- a/src/checkable_continuous_flyout.js +++ /dev/null @@ -1,138 +0,0 @@ -/** - * @license - * Copyright 2024 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import * as Blockly from "blockly/core"; -import { ContinuousFlyout } from "@blockly/continuous-toolbox"; -import { RecyclableBlockFlyoutInflater } from "./recyclable_block_flyout_inflater"; -import { StatusIndicatorLabel } from "./status_indicator_label"; - -export class CheckableContinuousFlyout extends ContinuousFlyout { - /** - * Creates a new CheckableContinuousFlyout. - * - * @param {!Blockly.Options} workspaceOptions Configuration options for the - * flyout workspace. - */ - constructor(workspaceOptions) { - workspaceOptions.modalInputs = false; - super(workspaceOptions); - this.tabWidth_ = -2; - this.MARGIN = 12; - this.GAP_Y = 12; - } - - /** - * Displays the given contents in the flyout. - * - * @param {!Object} flyoutDef The new contents to show in the flyout. - */ - show(flyoutDef) { - super.show(flyoutDef); - const inflater = this.getInflaterForType("block"); - if (inflater instanceof RecyclableBlockFlyoutInflater) { - inflater.emptyRecycledBlocks(); - } - } - - /** - * Serializes a block to JSON in order to copy it to the main workspace. - * - * @param {!Blockly.BlockSvg} block The block to serialize. - * @returns {!Object} A JSON representation of the block. - */ - serializeBlock(block) { - const json = super.serializeBlock(block); - // Delete the serialized block's ID so that a new one is generated when it is - // placed on the workspace. Otherwise, the block on the workspace may be - // indistinguishable from the one in the flyout, which can cause reporter blocks - // to have their value dropdown shown in the wrong place. - delete json.id; - return json; - } - - /** - * Set the state of a checkbox by block ID. - * @param {string} blockId ID of the block whose checkbox should be set - * @param {boolean} value Value to set the checkbox to. - * @public - */ - setCheckboxState(blockId, value) { - this.getWorkspace() - .getBlockById(blockId) - ?.getIcon("checkbox") - ?.setChecked(value); - } - - getFlyoutScale() { - return 0.675; - } - - getWidth() { - return 250; - } - - /** - * Sets whether or not block recycling is enabled in the flyout. - * - * @param {boolean} enabled True if recycling should be enabled. - */ - setRecyclingEnabled(enabled) { - const inflater = this.getInflaterForType("block"); - if (inflater instanceof RecyclableBlockFlyoutInflater) { - inflater.setRecyclingEnabled(enabled); - } - } - - /** - * Records scroll position for each category in the toolbox. - * The scroll position is determined by the coordinates of each category's - * label after the entire flyout has been rendered. - * @package - */ - recordScrollPositions() { - // TODO(#211) Remove this once the continuous toolbox has been updated. - this.scrollPositions = []; - const categoryLabels = this.getContents() - .filter( - (item) => - (item.type === "label" || item.type === "status_indicator_label") && - item.element.isLabel() && - this.getParentToolbox_().getCategoryByName( - item.element.getButtonText() - ) - ) - .map((item) => item.element); - for (const [index, label] of categoryLabels.entries()) { - this.scrollPositions.push({ - name: label.getButtonText(), - position: label.getPosition(), - }); - } - } - - /** - * Positions the contents of the flyout. - * - * @param {!Blockly.FlyoutItem[]} The flyout items to position. - */ - layout_(contents) { - // TODO(#211) Remove this once the continuous toolbox has been updated. - // Bypass the continuous flyout's layout method until the plugin is - // updated for the new flyout API. - Blockly.VerticalFlyout.prototype.layout_.call(this, contents); - } - - /** - * Updates the state of status indicators for hardware-based extensions. - */ - refreshStatusButtons() { - for (const item of this.contents) { - if (item.element instanceof StatusIndicatorLabel) { - item.element.refreshStatus(); - } - } - } -} diff --git a/src/checkable_continuous_flyout.ts b/src/checkable_continuous_flyout.ts new file mode 100644 index 0000000000..8a337d88d7 --- /dev/null +++ b/src/checkable_continuous_flyout.ts @@ -0,0 +1,112 @@ +/** + * @license + * Copyright 2024 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import * as Blockly from "blockly/core"; +import { ContinuousFlyout } from "@blockly/continuous-toolbox"; +import { CheckboxBubble } from "./checkbox_bubble"; +import { StatusIndicatorLabel } from "./status_indicator_label"; +import { STATUS_INDICATOR_LABEL_TYPE } from "./status_indicator_label_flyout_inflater"; + +export class CheckableContinuousFlyout extends ContinuousFlyout { + /** + * Creates a new CheckableContinuousFlyout. + * + * @param workspaceOptions Configuration options for the flyout workspace. + */ + constructor(workspaceOptions: Blockly.Options) { + workspaceOptions.modalInputs = false; + super(workspaceOptions); + this.tabWidth_ = 0; + this.MARGIN = 12; + this.GAP_Y = 12; + } + + /** + * Serializes a block to JSON in order to copy it to the main workspace. + * + * @param block The block to serialize. + * @returns A JSON representation of the block. + */ + protected serializeBlock(block: Blockly.BlockSvg) { + const json = super.serializeBlock(block); + // Delete the serialized block's ID so that a new one is generated when it is + // placed on the workspace. Otherwise, the block on the workspace may be + // indistinguishable from the one in the flyout, which can cause reporter blocks + // to have their value dropdown shown in the wrong place. + delete json.id; + return json; + } + + /** + * Set the state of a checkbox by block ID. + * + * @param blockId ID of the block whose checkbox should be set + * @param value Value to set the checkbox to. + */ + setCheckboxState(blockId: string, value: boolean) { + this.getWorkspace() + .getBlockById(blockId) + ?.getIcon("checkbox") + ?.setChecked(value); + } + + getFlyoutScale() { + return 0.675; + } + + getWidth() { + return 250; + } + + protected reflowInternal_() { + super.reflowInternal_(); + + if (this.RTL) { + // The parent implementation assumes that the flyout grows to fit its + // contents, and adjusts blocks in RTL mode accordingly. In Scratch, the + // flyout width is fixed (and blocks may exceed it), so re-adjust blocks + // accordingly based on the actual fixed width. + for (const item of this.getContents()) { + const oldX = item.getElement().getBoundingRectangle().left; + let newX = + this.getWidth() / this.workspace_.scale - + item.getElement().getBoundingRectangle().getWidth() - + this.MARGIN; + if ( + "checkboxInFlyout" in item.getElement() && + item.getElement().checkboxInFlyout + ) { + newX -= CheckboxBubble.CHECKBOX_SIZE + CheckboxBubble.CHECKBOX_MARGIN; + } + item.getElement().moveBy(newX - oldX, 0); + } + } + } + + /** + * Validates that the given toolbox item represents a label. + * + * @param item The toolbox item to check. + * @returns True if the item represents a label in the flyout. + */ + protected toolboxItemIsLabel(item: Blockly.FlyoutItem) { + return ( + item.getType() === STATUS_INDICATOR_LABEL_TYPE || + super.toolboxItemIsLabel(item) + ); + } + + /** + * Updates the state of status indicators for hardware-based extensions. + */ + refreshStatusButtons() { + for (const item of this.contents) { + if (item.element instanceof StatusIndicatorLabel) { + item.element.refreshStatus(); + } + } + } +} diff --git a/src/checkbox_bubble.ts b/src/checkbox_bubble.ts index 30349d0da0..1b6bc69bb0 100644 --- a/src/checkbox_bubble.ts +++ b/src/checkbox_bubble.ts @@ -203,15 +203,14 @@ export class CheckboxBubble * Recalculates this bubble's location, keeping it adjacent to its block. */ updateLocation() { - const blockLocation = this.sourceBlock.getRelativeToSurfaceXY(); - const blockBounds = this.sourceBlock.getHeightWidth(); + const bounds = this.sourceBlock.getBoundingRectangle(); const x = this.sourceBlock.workspace.RTL - ? blockLocation.x + blockBounds.width + CheckboxBubble.CHECKBOX_MARGIN - : blockLocation.x - + ? bounds.right + CheckboxBubble.CHECKBOX_MARGIN + : bounds.left - CheckboxBubble.CHECKBOX_MARGIN - CheckboxBubble.CHECKBOX_SIZE; const y = - blockLocation.y + (blockBounds.height - CheckboxBubble.CHECKBOX_SIZE) / 2; + bounds.top + (bounds.getHeight() - CheckboxBubble.CHECKBOX_SIZE) / 2; this.moveTo(x, y); } diff --git a/src/css.ts b/src/css.ts index 589f876ec1..fbabbce4eb 100644 --- a/src/css.ts +++ b/src/css.ts @@ -751,8 +751,9 @@ const styles = ` } /* Category tree in Toolbox. */ - .blocklyToolboxDiv { + .blocklyToolbox { background-color: var(--colour-toolbox); + border-right: 1px solid #ddd; color: var(--colour-toolboxText); overflow-x: visible; overflow-y: auto; @@ -763,6 +764,11 @@ const styles = ` padding: 0; } + .blocklyToolbox[dir="RTL"] { + border-right: none; + border-left: 1px solid #ddd; + } + .blocklyTreeRoot { padding: 4px 0; } @@ -771,7 +777,7 @@ const styles = ` outline: none; } - .blocklyToolboxDiv .blocklyTreeRow { + .blocklyToolbox .blocklyToolboxCategory { line-height: 22px; margin: 0; padding: 0.375rem 0px; @@ -789,11 +795,11 @@ const styles = ` margin: 1px 0 8px 5px; } - .blocklyToolboxDiv[dir="RTL"] .blocklyTreeRow { - margin-left: 8px; + .blocklyToolbox[dir="RTL"] .blocklyToolboxCategory { + margin-left: 0px; } - .blocklyTreeRow:hover { + .blocklyToolboxCategory:hover { color: var(--colour-toolboxHover); } @@ -844,7 +850,7 @@ const styles = ` background-position: -48px -1px; } - .blocklyTreeLabel { + .blocklyToolboxCategoryLabel { cursor: default; font-family: "Helvetica Neue", Helvetica, sans-serif; font-size: .65rem; @@ -855,7 +861,7 @@ const styles = ` text-wrap: wrap; } - .blocklyTreeSelected .blocklyTreeLabel { + .blocklyToolboxSelected .blocklyToolboxCategoryLabel { color: inherit; } diff --git a/src/fields/field_matrix.ts b/src/fields/field_matrix.ts index 1ac385328c..336527af19 100644 --- a/src/fields/field_matrix.ts +++ b/src/fields/field_matrix.ts @@ -70,7 +70,7 @@ class FieldMatrix extends Blockly.Field { * Touch event wrapper. * Runs when the field is selected. */ - private mouseDownWrapper: Blockly.browserEvents.Data | null = null; + private mouseDownWrapper_: Blockly.browserEvents.Data | null = null; /** * Touch event wrapper. @@ -558,8 +558,8 @@ class FieldMatrix extends Blockly.Field { dispose() { super.dispose(); this.matrixStage_ = null; - if (this.mouseDownWrapper) { - Blockly.browserEvents.unbind(this.mouseDownWrapper); + if (this.mouseDownWrapper_) { + Blockly.browserEvents.unbind(this.mouseDownWrapper_); } if (this.matrixTouchWrapper_) { Blockly.browserEvents.unbind(this.matrixTouchWrapper_); diff --git a/src/fields/scratch_field_angle.ts b/src/fields/scratch_field_angle.ts index 749c4e2498..9a058e242d 100644 --- a/src/fields/scratch_field_angle.ts +++ b/src/fields/scratch_field_angle.ts @@ -51,7 +51,7 @@ class ScratchFieldAngle extends Blockly.FieldNumber { /** * Opaque identifier used to unbind event listener in dispose(). */ - private mouseDownWrapper: Blockly.browserEvents.Data; + private mouseDownWrapper_: Blockly.browserEvents.Data; /** * Opaque identifier used to unbind event listener in dispose(). @@ -142,8 +142,8 @@ class ScratchFieldAngle extends Blockly.FieldNumber { dispose() { super.dispose(); this.gauge = null; - if (this.mouseDownWrapper) { - Blockly.browserEvents.unbind(this.mouseDownWrapper); + if (this.mouseDownWrapper_) { + Blockly.browserEvents.unbind(this.mouseDownWrapper_); } if (this.mouseUpWrapper) { Blockly.browserEvents.unbind(this.mouseUpWrapper); @@ -286,7 +286,7 @@ class ScratchFieldAngle extends Blockly.FieldNumber { this.getSourceBlock() as Blockly.BlockSvg ); - this.mouseDownWrapper = Blockly.browserEvents.bind( + this.mouseDownWrapper_ = Blockly.browserEvents.bind( this.handle, "mousedown", this, diff --git a/src/index.ts b/src/index.ts index eeeac8aa32..b57312ec98 100644 --- a/src/index.ts +++ b/src/index.ts @@ -26,11 +26,10 @@ import "./css"; import "./renderer/renderer"; import * as contextMenuItems from "./context_menu_items"; import { - ContinuousToolbox, - ContinuousFlyout, + registerContinuousToolbox, ContinuousMetrics, } from "@blockly/continuous-toolbox"; -import { CheckableContinuousFlyout } from "./checkable_continuous_flyout.js"; +import { CheckableContinuousFlyout } from "./checkable_continuous_flyout"; import { buildGlowFilter, glowStack } from "./glows"; import { ScratchContinuousToolbox } from "./scratch_continuous_toolbox"; import "./scratch_comment_icon"; @@ -120,6 +119,7 @@ export function inject(container: Element, options: Blockly.BlocklyOptions) { return workspace; } +registerContinuousToolbox(); Blockly.Scrollbar.scrollbarThickness = Blockly.Touch.TOUCH_ENABLED ? 14 : 11; Blockly.FlyoutButton.TEXT_MARGIN_X = 40; Blockly.FlyoutButton.TEXT_MARGIN_Y = 10; diff --git a/src/recyclable_block_flyout_inflater.ts b/src/recyclable_block_flyout_inflater.ts index 63dce02773..96c22a46fe 100644 --- a/src/recyclable_block_flyout_inflater.ts +++ b/src/recyclable_block_flyout_inflater.ts @@ -6,21 +6,12 @@ import * as Blockly from "blockly/core"; import { CheckboxBubble } from "./checkbox_bubble"; +import { RecyclableBlockFlyoutInflater as BlocklyRecyclableBlockFlyoutInflater } from "@blockly/continuous-toolbox"; /** * A block inflater that caches and reuses blocks to improve performance. */ -export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { - /** - * Whether or not block recycling is enabled. - */ - recyclingEnabled = true; - - /** - * Map from block type to block instance. - */ - recycledBlocks = new Map(); - +export class RecyclableBlockFlyoutInflater extends BlocklyRecyclableBlockFlyoutInflater { /** * Creates a block on the flyout workspace from the given block definition. * @@ -31,152 +22,18 @@ export class RecyclableBlockFlyoutInflater extends Blockly.BlockFlyoutInflater { load( state: Blockly.utils.toolbox.BlockInfo, flyoutWorkspace: Blockly.WorkspaceSvg - ): Blockly.IBoundedElement { - const block = super.load(state, flyoutWorkspace); + ): Blockly.FlyoutItem { + const flyoutItem = super.load(state, flyoutWorkspace); + const block = flyoutItem.getElement(); if ("checkboxInFlyout" in block && block.checkboxInFlyout) { block.moveBy( - CheckboxBubble.CHECKBOX_SIZE + CheckboxBubble.CHECKBOX_MARGIN, + (flyoutWorkspace.RTL ? -1 : 1) * + (CheckboxBubble.CHECKBOX_SIZE + CheckboxBubble.CHECKBOX_MARGIN), 0 ); } - return block; - } - - /** - * Toggles whether or not recycling is enabled. - * - * @param enabled True if recycling should be enabled. - */ - setRecyclingEnabled(enabled: boolean) { - this.recyclingEnabled = enabled; - } - - /** - * Creates a new block from the given block definition. - * - * @param blockDefinition The definition to create a block from. - * @returns The newly created block. - */ - createBlock( - blockDefinition: Blockly.utils.toolbox.BlockInfo - ): Blockly.BlockSvg { - const blockType = this.getTypeFromDefinition(blockDefinition); - return ( - this.getRecycledBlock(blockType) ?? - super.createBlock(blockDefinition, this.flyoutWorkspace) - ); - } - - /** - * Returns the type of a block from an XML or JSON block definition. - * - * @param blockDefinition The block definition to parse. - * @returns The block type. - */ - getTypeFromDefinition( - blockDefinition: Blockly.utils.toolbox.BlockInfo - ): string { - if (blockDefinition["blockxml"]) { - const xml = - typeof blockDefinition["blockxml"] === "string" - ? Blockly.utils.xml.textToDom(blockDefinition["blockxml"]) - : (blockDefinition["blockxml"] as Element); - return xml.getAttribute("type"); - } else { - return blockDefinition["type"]; - } - } - - /** - * Puts a previously created block into the recycle bin and moves it to the - * top of the workspace. Used during large workspace swaps to limit the number - * of new DOM elements we need to create. - * - * @param block The block to recycle. - */ - recycleBlock(block: Blockly.BlockSvg) { - const xy = block.getRelativeToSurfaceXY(); - block.moveBy(-xy.x, -xy.y); - this.recycledBlocks.set(block.type, block); - } - - /** - * Returns a block from the cache of recycled blocks with the given type, or - * undefined if one cannot be found. - * - * @param blockType The type of the block to try to recycle. - * @returns The recycled block, or undefined if one could not be recycled. - */ - getRecycledBlock(blockType: string): Blockly.BlockSvg | undefined { - const block = this.recycledBlocks.get(blockType); - this.recycledBlocks.delete(blockType); - return block; - } - - /** - * Returns whether the given block can be recycled or not. - * - * @param block The block to check for recyclability. - * @returns True if the block can be recycled. False otherwise. - */ - blockIsRecyclable(block: Blockly.Block): boolean { - if (!this.recyclingEnabled) { - return false; - } - - // If the block needs to parse mutations, never recycle. - if (block.mutationToDom && block.domToMutation) { - return false; - } - - if (!block.isEnabled()) { - return false; - } - - for (const input of block.inputList) { - for (const field of input.fieldRow) { - // No variables. - if (field.referencesVariables()) { - return false; - } - if (field instanceof Blockly.FieldDropdown) { - if (field.isOptionListDynamic()) { - return false; - } - } - } - // Check children. - if (input.connection) { - const targetBlock = input.connection.targetBlock(); - if (targetBlock && !this.blockIsRecyclable(targetBlock)) { - return false; - } - } - } - return true; - } - - /** - * Disposes of the provided block. - * - * @param element The block to dispose of. - */ - disposeElement(element: Blockly.BlockSvg) { - if (this.blockIsRecyclable(element)) { - this.removeListeners(element.id); - this.recycleBlock(element); - } else { - super.disposeElement(element); - } - } - - /** - * Clears the cache of recycled blocks. - */ - emptyRecycledBlocks() { - this.recycledBlocks.forEach((block) => block.dispose(false, false)); - this.recycledBlocks.clear(); + return flyoutItem; } } diff --git a/src/scratch_continuous_toolbox.ts b/src/scratch_continuous_toolbox.ts index 3104191368..76cc73b1c2 100644 --- a/src/scratch_continuous_toolbox.ts +++ b/src/scratch_continuous_toolbox.ts @@ -7,6 +7,7 @@ import * as Blockly from "blockly/core"; import { ContinuousToolbox } from "@blockly/continuous-toolbox"; import { ScratchContinuousCategory } from "./scratch_continuous_category"; +import { STATUS_INDICATOR_LABEL_TYPE } from "./status_indicator_label_flyout_inflater"; /** * A toolbox that displays items from all categories in one scrolling list. @@ -23,36 +24,25 @@ export class ScratchContinuousToolbox extends ContinuousToolbox { } /** - * Gets the contents that should be shown in the flyout. + * Converts the given toolbox item to a corresponding array of items that + * should appear in the flyout. * - * @returns Flyout contents. + * @param toolboxItem The toolbox item to convert. + * @returns An array of flyout item definitions. */ - getInitialFlyoutContents_(): Blockly.utils.toolbox.FlyoutItemInfoArray { - // TODO(#211) Clean this up when the continuous toolbox plugin is updated. - let contents: Blockly.utils.toolbox.FlyoutItemInfoArray = []; - for (const toolboxItem of this.getToolboxItems()) { - if (toolboxItem instanceof ScratchContinuousCategory) { - if (toolboxItem.shouldShowStatusButton()) { - contents.push({ - kind: "STATUS_INDICATOR_LABEL", - id: toolboxItem.getId(), - text: toolboxItem.getName(), - }); - } else { - // Create a label node to go at the top of the category - contents.push({ kind: "LABEL", text: toolboxItem.getName() }); - } - let itemContents = toolboxItem.getContents(); - - // Handle custom categories (e.g. variables and functions) - if (typeof itemContents === "string") { - itemContents = { - custom: itemContents, - kind: "CATEGORY", - }; - } - contents = contents.concat(itemContents); - } + protected convertToolboxItemToFlyoutItems( + toolboxItem: Blockly.IToolboxItem + ): Blockly.utils.toolbox.FlyoutItemInfoArray { + const contents = super.convertToolboxItemToFlyoutItems(toolboxItem); + if ( + toolboxItem instanceof ScratchContinuousCategory && + toolboxItem.shouldShowStatusButton() + ) { + contents.splice(0, 1, { + kind: STATUS_INDICATOR_LABEL_TYPE, + id: toolboxItem.getId(), + text: toolboxItem.getName(), + }); } return contents; } @@ -62,12 +52,12 @@ export class ScratchContinuousToolbox extends ContinuousToolbox { */ forceRerender() { const selectedCategoryName = this.selectedItem_?.getName(); - super.refreshSelection(); + this.getFlyout().show(this.getInitialFlyoutContents()); + this.selectCategoryByName(selectedCategoryName); let callback; while ((callback = this.postRenderCallbacks.shift())) { callback(); } - this.selectCategoryByName(selectedCategoryName); } /** diff --git a/src/status_indicator_label_flyout_inflater.ts b/src/status_indicator_label_flyout_inflater.ts index 2b9de6584e..7ed8a63eae 100644 --- a/src/status_indicator_label_flyout_inflater.ts +++ b/src/status_indicator_label_flyout_inflater.ts @@ -7,6 +7,8 @@ import * as Blockly from "blockly/core"; import { StatusIndicatorLabel } from "./status_indicator_label"; +export const STATUS_INDICATOR_LABEL_TYPE = "status_indicator_label"; + /** * Flyout inflater responsible for creating status indicator labels. */ @@ -21,14 +23,14 @@ class StatusIndicatorLabelFlyoutInflater extends Blockly.LabelFlyoutInflater { load( state: Blockly.utils.toolbox.LabelInfo, flyoutWorkspace: Blockly.WorkspaceSvg - ): StatusIndicatorLabel { + ): Blockly.FlyoutItem { const label = new StatusIndicatorLabel( flyoutWorkspace, flyoutWorkspace.targetWorkspace, state ); label.show(); - return label; + return new Blockly.FlyoutItem(label, STATUS_INDICATOR_LABEL_TYPE, true); } } @@ -38,7 +40,7 @@ class StatusIndicatorLabelFlyoutInflater extends Blockly.LabelFlyoutInflater { export function registerStatusIndicatorLabelFlyoutInflater() { Blockly.registry.register( Blockly.registry.Type.FLYOUT_INFLATER, - "status_indicator_label", + STATUS_INDICATOR_LABEL_TYPE, StatusIndicatorLabelFlyoutInflater ); } diff --git a/src/variables.ts b/src/variables.ts index 2d27dbaf0e..68e0b2ac3f 100644 --- a/src/variables.ts +++ b/src/variables.ts @@ -29,7 +29,7 @@ import { } from "./constants"; import { ScratchVariableModel } from "./scratch_variable_model"; import { ScratchContinuousToolbox } from "./scratch_continuous_toolbox"; -import { CheckableContinuousFlyout } from "./checkable_continuous_flyout.js"; +import { CheckableContinuousFlyout } from "./checkable_continuous_flyout"; /** * Constant prefix to differentiate cloud variable names from other types of