diff --git a/examples/react-rich/src/plugins/ToolbarPlugin.tsx b/examples/react-rich/src/plugins/ToolbarPlugin.tsx index 69061072306..1ace522d99f 100644 --- a/examples/react-rich/src/plugins/ToolbarPlugin.tsx +++ b/examples/react-rich/src/plugins/ToolbarPlugin.tsx @@ -37,7 +37,7 @@ export default function ToolbarPlugin() { const [isUnderline, setIsUnderline] = useState(false); const [isStrikethrough, setIsStrikethrough] = useState(false); - const updateToolbar = useCallback(() => { + const $updateToolbar = useCallback(() => { const selection = $getSelection(); if ($isRangeSelection(selection)) { // Update text format @@ -52,13 +52,13 @@ export default function ToolbarPlugin() { return mergeRegister( editor.registerUpdateListener(({editorState}) => { editorState.read(() => { - updateToolbar(); + $updateToolbar(); }); }), editor.registerCommand( SELECTION_CHANGE_COMMAND, (_payload, newEditor) => { - updateToolbar(); + $updateToolbar(); return false; }, LowPriority, @@ -80,7 +80,7 @@ export default function ToolbarPlugin() { LowPriority, ), ); - }, [editor, updateToolbar]); + }, [editor, $updateToolbar]); return (
diff --git a/package-lock.json b/package-lock.json index 5bf364b35e9..1a3d1c6260e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1072,12 +1072,12 @@ } }, "node_modules/@babel/plugin-syntax-flow": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.1.tgz", - "integrity": "sha512-sxi2kLTI5DeW5vDtMUsk4mTPwvlUDbjOnoWayhynCwrw4QXRld4QEYwqzY8JmQXaJUtgUuCIurtSRH5sn4c7mA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz", + "integrity": "sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -1504,13 +1504,13 @@ } }, "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.1.tgz", - "integrity": "sha512-iIYPIWt3dUmUKKE10s3W+jsQ3icFkw0JyRVyY1B7G4yK/nngAOHLVx8xlhA6b/Jzl/Y0nis8gjqhqKtRDQqHWQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.18.6.tgz", + "integrity": "sha512-wE0xtA7csz+hw4fKPwxmu5jnzAsXPIO57XnRwzXP3T19jWh1BODnPGoG9xKYwvAwusP7iUktHayRFbMPGtODaQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-flow": "^7.24.1" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-flow": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -2264,14 +2264,14 @@ } }, "node_modules/@babel/preset-flow": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.24.1.tgz", - "integrity": "sha512-sWCV2G9pcqZf+JHyv/RyqEIpFypxdCSxWIxQjpdaQxenNog7cN1pr76hg8u0Fz8Qgg0H4ETkGcJnXL8d4j0PPA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.18.6.tgz", + "integrity": "sha512-E7BDhL64W6OUqpuyHnSroLnqyRTcG6ZdOBl1OKI/QK/HJfplqK/S3sq1Cckx7oTodJ5yOXyfw7rEADJ6UjoQDQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-validator-option": "^7.23.5", - "@babel/plugin-transform-flow-strip-types": "^7.24.1" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-flow-strip-types": "^7.18.6" }, "engines": { "node": ">=6.9.0" @@ -3562,18 +3562,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, - "node_modules/@eduardoac-skimlinks/webext-redux": { - "version": "3.0.1-release-candidate", - "resolved": "https://registry.npmjs.org/@eduardoac-skimlinks/webext-redux/-/webext-redux-3.0.1-release-candidate.tgz", - "integrity": "sha512-Gv7LOjiqye+umkR4v0FqcWo8goqP333Lr2kqtMIWJMs5S12T5b3G87PoxuVqZByJk2Ebc6mJ/v7f3HMVzgFT+w==", - "dependencies": { - "lodash.assignin": "^4.2.0", - "lodash.clonedeep": "^4.5.0" - }, - "peerDependencies": { - "redux": ">= 3 <= 4" - } - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", @@ -6800,8 +6788,7 @@ "node_modules/@types/webextension-polyfill": { "version": "0.10.7", "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.10.7.tgz", - "integrity": "sha512-10ql7A0qzBmFB+F+qAke/nP1PIonS0TXZAOMVOxEUsm+lGSW6uwVcISFNa0I4Oyj0884TZVWGGMIWeXOVSNFHw==", - "dev": true + "integrity": "sha512-10ql7A0qzBmFB+F+qAke/nP1PIonS0TXZAOMVOxEUsm+lGSW6uwVcISFNa0I4Oyj0884TZVWGGMIWeXOVSNFHw==" }, "node_modules/@types/ws": { "version": "8.5.10", @@ -7327,6 +7314,61 @@ "integrity": "sha512-NY39ACqCxdKBmHgw361M9pfJma8e4AZo20w9AY+5ZjIj1W2dvXC8J31G5fjfOGbulW9w4WKpT8fPooi0mLkn9A==", "dev": true }, + "node_modules/@webext-pegasus/rpc": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@webext-pegasus/rpc/-/rpc-0.0.4.tgz", + "integrity": "sha512-PjfJ1vQgwKS/XJBZC3xvbx/i1cljm2x3pb1osFbAbPs4Tnmv2FewdVC2hhBTBNy9i27KyHTsMvd42rttZQvRoA==", + "dependencies": { + "@webext-pegasus/transport": "^0.0.4", + "type-fest": "^0.21.3" + } + }, + "node_modules/@webext-pegasus/store": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@webext-pegasus/store/-/store-0.0.4.tgz", + "integrity": "sha512-nvfwxlglcGDie0b3pd2WZVLnYbll24tzBVSQ+0XgKa5tL6ntAMjRPqQWO3QNlUJANbmcXabzAd5R+7dxCTrTyw==", + "dependencies": { + "@webext-pegasus/rpc": "^0.0.4", + "@webext-pegasus/transport": "^0.0.4", + "type-fest": "^0.21.3" + } + }, + "node_modules/@webext-pegasus/store-zustand": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@webext-pegasus/store-zustand/-/store-zustand-0.0.4.tgz", + "integrity": "sha512-5M/ZRwSzno8ebWZeu+A1GplVTVc/ruU/whWCyOkJNtKkCyuKwFZBWLBUfzKKIgNhCqSeGqxwi4F/ggvS42glPQ==", + "dependencies": { + "@webext-pegasus/store": "^0.0.4", + "type-fest": "^0.21.3" + }, + "peerDependencies": { + "zustand": "^4" + } + }, + "node_modules/@webext-pegasus/transport": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@webext-pegasus/transport/-/transport-0.0.4.tgz", + "integrity": "sha512-s6iWeo3vpoEa7d3UZtNVDWFQjT3OAdgxN064Z7P0fJNbfIMVa/Twvo8dJtcsSg5VGxxoxIqwLJ7FX6LgmBAmpg==", + "dependencies": { + "@types/webextension-polyfill": "^0.10.7", + "nanoevents": "^6.0.2", + "serialize-error": "^9.0.0", + "tiny-uid": "^1.1.1", + "type-fest": "^2.11.1", + "webextension-polyfill": "0.10.0" + } + }, + "node_modules/@webext-pegasus/transport/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -18274,22 +18316,12 @@ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, - "node_modules/lodash.assignin": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", - "integrity": "sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg==" - }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", "dev": true }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" - }, "node_modules/lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -22476,9 +22508,9 @@ } }, "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true, "engines": { "node": ">= 6" @@ -27750,7 +27782,6 @@ "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, "engines": { "node": ">=10" }, @@ -28995,33 +29026,10 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/webext-bridge": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webext-bridge/-/webext-bridge-6.0.1.tgz", - "integrity": "sha512-GruIrN+vNwbxVCi8UW4Dqk5YkcGA9V0ZfJ57jXP9JXHbrsDs5k2N6NNYQR5e+wSCnQpGYOGAGihwUpKlhg8QIw==", - "dependencies": { - "@types/webextension-polyfill": "^0.8.3", - "nanoevents": "^6.0.2", - "serialize-error": "^9.0.0", - "tiny-uid": "^1.1.1", - "webextension-polyfill": "^0.9.0" - } - }, - "node_modules/webext-bridge/node_modules/@types/webextension-polyfill": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.8.3.tgz", - "integrity": "sha512-GN+Hjzy9mXjWoXKmaicTegv3FJ0WFZ3aYz77Wk8TMp1IY3vEzvzj1vnsa0ggV7vMI1i+PUxe4qqnIJKCzf9aTg==" - }, - "node_modules/webext-bridge/node_modules/webextension-polyfill": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.9.0.tgz", - "integrity": "sha512-LTtHb0yR49xa9irkstDxba4GATDAcDw3ncnFH9RImoFwDlW47U95ME5sn5IiQX2ghfaECaf6xyXM8yvClIBkkw==" - }, "node_modules/webextension-polyfill": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", - "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==", - "dev": true + "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==" }, "node_modules/webidl-conversions": { "version": "7.0.0", @@ -31165,10 +31173,11 @@ "version": "0.14.5", "hasInstallScript": true, "dependencies": { - "@eduardoac-skimlinks/webext-redux": "3.0.1-release-candidate", + "@webext-pegasus/rpc": "^0.0.4", + "@webext-pegasus/store-zustand": "^0.0.4", + "@webext-pegasus/transport": "^0.0.4", "react": "^18.2.0", "react-dom": "^18.2.0", - "webext-bridge": "~6.0.1", "zustand": "^4.5.1" }, "devDependencies": { @@ -32471,12 +32480,12 @@ } }, "@babel/plugin-syntax-flow": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.1.tgz", - "integrity": "sha512-sxi2kLTI5DeW5vDtMUsk4mTPwvlUDbjOnoWayhynCwrw4QXRld4QEYwqzY8JmQXaJUtgUuCIurtSRH5sn4c7mA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz", + "integrity": "sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.0" + "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-syntax-import-assertions": { @@ -32741,13 +32750,13 @@ } }, "@babel/plugin-transform-flow-strip-types": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.1.tgz", - "integrity": "sha512-iIYPIWt3dUmUKKE10s3W+jsQ3icFkw0JyRVyY1B7G4yK/nngAOHLVx8xlhA6b/Jzl/Y0nis8gjqhqKtRDQqHWQ==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.18.6.tgz", + "integrity": "sha512-wE0xtA7csz+hw4fKPwxmu5jnzAsXPIO57XnRwzXP3T19jWh1BODnPGoG9xKYwvAwusP7iUktHayRFbMPGtODaQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/plugin-syntax-flow": "^7.24.1" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-flow": "^7.18.6" } }, "@babel/plugin-transform-for-of": { @@ -33235,14 +33244,14 @@ } }, "@babel/preset-flow": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.24.1.tgz", - "integrity": "sha512-sWCV2G9pcqZf+JHyv/RyqEIpFypxdCSxWIxQjpdaQxenNog7cN1pr76hg8u0Fz8Qgg0H4ETkGcJnXL8d4j0PPA==", + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.18.6.tgz", + "integrity": "sha512-E7BDhL64W6OUqpuyHnSroLnqyRTcG6ZdOBl1OKI/QK/HJfplqK/S3sq1Cckx7oTodJ5yOXyfw7rEADJ6UjoQDQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.24.0", - "@babel/helper-validator-option": "^7.23.5", - "@babel/plugin-transform-flow-strip-types": "^7.24.1" + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-transform-flow-strip-types": "^7.18.6" } }, "@babel/preset-modules": { @@ -34255,15 +34264,6 @@ } } }, - "@eduardoac-skimlinks/webext-redux": { - "version": "3.0.1-release-candidate", - "resolved": "https://registry.npmjs.org/@eduardoac-skimlinks/webext-redux/-/webext-redux-3.0.1-release-candidate.tgz", - "integrity": "sha512-Gv7LOjiqye+umkR4v0FqcWo8goqP333Lr2kqtMIWJMs5S12T5b3G87PoxuVqZByJk2Ebc6mJ/v7f3HMVzgFT+w==", - "requires": { - "lodash.assignin": "^4.2.0", - "lodash.clonedeep": "^4.5.0" - } - }, "@esbuild/aix-ppc64": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", @@ -35142,18 +35142,19 @@ "@lexical/devtools": { "version": "file:packages/lexical-devtools", "requires": { - "@eduardoac-skimlinks/webext-redux": "3.0.1-release-candidate", "@lexical/devtools-core": "0.14.5", "@rollup/plugin-babel": "^6.0.4", "@types/react": "^18.2.46", "@types/react-dom": "^18.2.18", "@vitejs/plugin-react": "^4.2.1", + "@webext-pegasus/rpc": "^0.0.4", + "@webext-pegasus/store-zustand": "^0.0.4", + "@webext-pegasus/transport": "^0.0.4", "lexical": "0.14.5", "react": "^18.2.0", "react-dom": "^18.2.0", "typescript": "^5.3.3", "vite": "^5.2.2", - "webext-bridge": "~6.0.1", "wxt": "^0.17.0", "zustand": "^4.5.1" }, @@ -36792,8 +36793,7 @@ "@types/webextension-polyfill": { "version": "0.10.7", "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.10.7.tgz", - "integrity": "sha512-10ql7A0qzBmFB+F+qAke/nP1PIonS0TXZAOMVOxEUsm+lGSW6uwVcISFNa0I4Oyj0884TZVWGGMIWeXOVSNFHw==", - "dev": true + "integrity": "sha512-10ql7A0qzBmFB+F+qAke/nP1PIonS0TXZAOMVOxEUsm+lGSW6uwVcISFNa0I4Oyj0884TZVWGGMIWeXOVSNFHw==" }, "@types/ws": { "version": "8.5.10", @@ -37182,6 +37182,54 @@ "integrity": "sha512-NY39ACqCxdKBmHgw361M9pfJma8e4AZo20w9AY+5ZjIj1W2dvXC8J31G5fjfOGbulW9w4WKpT8fPooi0mLkn9A==", "dev": true }, + "@webext-pegasus/rpc": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@webext-pegasus/rpc/-/rpc-0.0.4.tgz", + "integrity": "sha512-PjfJ1vQgwKS/XJBZC3xvbx/i1cljm2x3pb1osFbAbPs4Tnmv2FewdVC2hhBTBNy9i27KyHTsMvd42rttZQvRoA==", + "requires": { + "@webext-pegasus/transport": "^0.0.4", + "type-fest": "^0.21.3" + } + }, + "@webext-pegasus/store": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@webext-pegasus/store/-/store-0.0.4.tgz", + "integrity": "sha512-nvfwxlglcGDie0b3pd2WZVLnYbll24tzBVSQ+0XgKa5tL6ntAMjRPqQWO3QNlUJANbmcXabzAd5R+7dxCTrTyw==", + "requires": { + "@webext-pegasus/rpc": "^0.0.4", + "@webext-pegasus/transport": "^0.0.4", + "type-fest": "^0.21.3" + } + }, + "@webext-pegasus/store-zustand": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@webext-pegasus/store-zustand/-/store-zustand-0.0.4.tgz", + "integrity": "sha512-5M/ZRwSzno8ebWZeu+A1GplVTVc/ruU/whWCyOkJNtKkCyuKwFZBWLBUfzKKIgNhCqSeGqxwi4F/ggvS42glPQ==", + "requires": { + "@webext-pegasus/store": "^0.0.4", + "type-fest": "^0.21.3" + } + }, + "@webext-pegasus/transport": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/@webext-pegasus/transport/-/transport-0.0.4.tgz", + "integrity": "sha512-s6iWeo3vpoEa7d3UZtNVDWFQjT3OAdgxN064Z7P0fJNbfIMVa/Twvo8dJtcsSg5VGxxoxIqwLJ7FX6LgmBAmpg==", + "requires": { + "@types/webextension-polyfill": "^0.10.7", + "nanoevents": "^6.0.2", + "serialize-error": "^9.0.0", + "tiny-uid": "^1.1.1", + "type-fest": "^2.11.1", + "webextension-polyfill": "0.10.0" + }, + "dependencies": { + "type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==" + } + } + }, "@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -45060,22 +45108,12 @@ "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, - "lodash.assignin": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", - "integrity": "sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg==" - }, "lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", "dev": true }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" - }, "lodash.debounce": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", @@ -47843,9 +47881,9 @@ "dev": true }, "pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true }, "pkg-dir": { @@ -51603,8 +51641,7 @@ "type-fest": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" }, "type-is": { "version": "1.6.18", @@ -52498,35 +52535,10 @@ "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==" }, - "webext-bridge": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/webext-bridge/-/webext-bridge-6.0.1.tgz", - "integrity": "sha512-GruIrN+vNwbxVCi8UW4Dqk5YkcGA9V0ZfJ57jXP9JXHbrsDs5k2N6NNYQR5e+wSCnQpGYOGAGihwUpKlhg8QIw==", - "requires": { - "@types/webextension-polyfill": "^0.8.3", - "nanoevents": "^6.0.2", - "serialize-error": "^9.0.0", - "tiny-uid": "^1.1.1", - "webextension-polyfill": "^0.9.0" - }, - "dependencies": { - "@types/webextension-polyfill": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.8.3.tgz", - "integrity": "sha512-GN+Hjzy9mXjWoXKmaicTegv3FJ0WFZ3aYz77Wk8TMp1IY3vEzvzj1vnsa0ggV7vMI1i+PUxe4qqnIJKCzf9aTg==" - }, - "webextension-polyfill": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.9.0.tgz", - "integrity": "sha512-LTtHb0yR49xa9irkstDxba4GATDAcDw3ncnFH9RImoFwDlW47U95ME5sn5IiQX2ghfaECaf6xyXM8yvClIBkkw==" - } - } - }, "webextension-polyfill": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", - "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==", - "dev": true + "integrity": "sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==" }, "webidl-conversions": { "version": "7.0.0", diff --git a/packages/lexical-devtools/package.json b/packages/lexical-devtools/package.json index cdf69bd060f..89e08125c57 100644 --- a/packages/lexical-devtools/package.json +++ b/packages/lexical-devtools/package.json @@ -7,6 +7,7 @@ "scripts": { "dev": "wxt", "dev:firefox": "wxt -b firefox", + "dev:edge": "wxt -b edge", "build": "wxt build", "build:firefox": "wxt build -b firefox", "zip": "wxt zip", @@ -15,21 +16,23 @@ "postinstall": "wxt prepare" }, "dependencies": { - "@eduardoac-skimlinks/webext-redux": "3.0.1-release-candidate", + "@webext-pegasus/rpc": "^0.0.4", + "@webext-pegasus/store-zustand": "^0.0.4", + "@webext-pegasus/transport": "^0.0.4", "react": "^18.2.0", "react-dom": "^18.2.0", - "webext-bridge": "~6.0.1", "zustand": "^4.5.1" }, "devDependencies": { - "@lexical/devtools-core": "0.14.5", - "@rollup/plugin-babel": "^6.0.4", "@types/react": "^18.2.46", "@types/react-dom": "^18.2.18", "@vitejs/plugin-react": "^4.2.1", - "lexical": "0.14.5", "typescript": "^5.3.3", + "lexical": "0.14.5", + "@lexical/devtools-core": "0.14.5", + "wxt": "^0.17.0", "vite": "^5.2.2", - "wxt": "^0.17.0" - } + "@rollup/plugin-babel": "^6.0.4" + }, + "sideEffects": false } diff --git a/packages/lexical-devtools/src/entrypoints/devtools/main.ts b/packages/lexical-devtools/src/entrypoints/devtools/main.ts index f8b60cb0cf7..34a845df7f0 100644 --- a/packages/lexical-devtools/src/entrypoints/devtools/main.ts +++ b/packages/lexical-devtools/src/entrypoints/devtools/main.ts @@ -9,6 +9,6 @@ // Create the panel which appears within the browser devtools browser.devtools.panels.create( 'Lexical', - 'icon/128.png', + '/icon/logo.svg', 'devtools-panel.html', ); diff --git a/packages/lexical-devtools/src/public/icon/logo.svg b/packages/lexical-devtools/src/public/icon/logo.svg new file mode 100644 index 00000000000..74ddb15d8a9 --- /dev/null +++ b/packages/lexical-devtools/src/public/icon/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/lexical-devtools/wxt.config.ts b/packages/lexical-devtools/wxt.config.ts index 383cb658650..40916d1fd82 100644 --- a/packages/lexical-devtools/wxt.config.ts +++ b/packages/lexical-devtools/wxt.config.ts @@ -53,6 +53,9 @@ export default defineConfig({ return manifestConf; }, runner: { + binaries: { + edge: '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge', + }, chromiumArgs: [ '--auto-open-devtools-for-tabs', // Open chrome://version to validate it works diff --git a/packages/lexical-playground/__tests__/e2e/Extensions.spec.mjs b/packages/lexical-playground/__tests__/e2e/Extensions.spec.mjs index e054da712e3..ba54a73aae1 100644 --- a/packages/lexical-playground/__tests__/e2e/Extensions.spec.mjs +++ b/packages/lexical-playground/__tests__/e2e/Extensions.spec.mjs @@ -6,6 +6,10 @@ * */ +import { + moveToEditorBeginning, + moveToEditorEnd, +} from '../keyboardShortcuts/index.mjs'; import { assertHTML, assertSelection, @@ -255,4 +259,90 @@ test.describe('Extensions', () => { focusPath: [1, 0, 0], }); }); + + test('document.execCommand("insertText") with all text backward selection', async ({ + page, + }) => { + await focusEditor(page); + + await page.keyboard.type('Paragraph 1'); + await moveToEditorEnd(page); + await page.keyboard.down('Shift'); + await moveToEditorBeginning(page); + await page.keyboard.up('Shift'); + + await assertSelection(page, { + anchorOffset: 11, + anchorPath: [0, 0, 0], + focusOffset: 0, + focusPath: [0, 0, 0], + }); + + await evaluate( + page, + () => { + document.execCommand('insertText', false, 'New text'); + }, + [], + ); + await assertHTML( + page, + html` +

+ New text +

+ `, + ); + await assertSelection(page, { + anchorOffset: 8, + anchorPath: [0, 0, 0], + focusOffset: 8, + focusPath: [0, 0, 0], + }); + }); + + test('document.execCommand("insertText") with all text forward selection', async ({ + page, + }) => { + await focusEditor(page); + + await page.keyboard.type('Paragraph 1'); + await moveToEditorBeginning(page); + await page.keyboard.down('Shift'); + await moveToEditorEnd(page); + await page.keyboard.up('Shift'); + + await assertSelection(page, { + anchorOffset: 0, + anchorPath: [0, 0, 0], + focusOffset: 11, + focusPath: [0, 0, 0], + }); + + await evaluate( + page, + () => { + document.execCommand('insertText', false, 'New text'); + }, + [], + ); + await assertHTML( + page, + html` +

+ New text +

+ `, + ); + await assertSelection(page, { + anchorOffset: 8, + anchorPath: [0, 0, 0], + focusOffset: 8, + focusPath: [0, 0, 0], + }); + }); }); diff --git a/packages/lexical-playground/src/plugins/ListMaxIndentLevelPlugin/index.ts b/packages/lexical-playground/src/plugins/ListMaxIndentLevelPlugin/index.ts index b8f3b3ce976..3feb82b9f96 100644 --- a/packages/lexical-playground/src/plugins/ListMaxIndentLevelPlugin/index.ts +++ b/packages/lexical-playground/src/plugins/ListMaxIndentLevelPlugin/index.ts @@ -6,7 +6,7 @@ * */ -import type {RangeSelection} from 'lexical'; +import type {ElementNode, RangeSelection} from 'lexical'; import {$getListDepth, $isListItemNode, $isListNode} from '@lexical/list'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; @@ -15,15 +15,10 @@ import { $isElementNode, $isRangeSelection, COMMAND_PRIORITY_CRITICAL, - ElementNode, INDENT_CONTENT_COMMAND, } from 'lexical'; import {useEffect} from 'react'; -type Props = Readonly<{ - maxDepth: number | null | undefined; -}>; - function getElementNodesInSelection( selection: RangeSelection, ): Set { @@ -41,7 +36,7 @@ function getElementNodesInSelection( ); } -function isIndentPermitted(maxDepth: number): boolean { +function shouldPreventIndent(maxDepth: number): boolean { const selection = $getSelection(); if (!$isRangeSelection(selection)) { @@ -69,16 +64,20 @@ function isIndentPermitted(maxDepth: number): boolean { } } - return totalDepth <= maxDepth; + return totalDepth > maxDepth; } -export default function ListMaxIndentLevelPlugin({maxDepth}: Props): null { +export default function ListMaxIndentLevelPlugin({ + maxDepth = 7, +}: { + maxDepth?: number; +}): null { const [editor] = useLexicalComposerContext(); useEffect(() => { return editor.registerCommand( INDENT_CONTENT_COMMAND, - () => !isIndentPermitted(maxDepth ?? 7), + () => shouldPreventIndent(maxDepth), COMMAND_PRIORITY_CRITICAL, ); }, [editor, maxDepth]); diff --git a/packages/lexical-react/src/LexicalTablePlugin.ts b/packages/lexical-react/src/LexicalTablePlugin.ts index 3363d6e6423..e237e67b339 100644 --- a/packages/lexical-react/src/LexicalTablePlugin.ts +++ b/packages/lexical-react/src/LexicalTablePlugin.ts @@ -16,6 +16,7 @@ import type {NodeKey} from 'lexical'; import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext'; import { $computeTableMap, + $computeTableMapSkipCellCheck, $createTableCellNode, $createTableNodeWithDimensions, $getNodeTriplet, @@ -28,8 +29,13 @@ import { TableNode, TableRowNode, } from '@lexical/table'; -import {$insertFirst, $insertNodeToNearestRoot} from '@lexical/utils'; import { + $insertFirst, + $insertNodeToNearestRoot, + mergeRegister, +} from '@lexical/utils'; +import { + $createParagraphNode, $getNodeByKey, $isTextNode, $nodesOfType, @@ -57,24 +63,50 @@ export function TablePlugin({ ); } - return editor.registerCommand( - INSERT_TABLE_COMMAND, - ({columns, rows, includeHeaders}) => { - const tableNode = $createTableNodeWithDimensions( - Number(rows), - Number(columns), - includeHeaders, - ); - $insertNodeToNearestRoot(tableNode); + return mergeRegister( + editor.registerCommand( + INSERT_TABLE_COMMAND, + ({columns, rows, includeHeaders}) => { + const tableNode = $createTableNodeWithDimensions( + Number(rows), + Number(columns), + includeHeaders, + ); + $insertNodeToNearestRoot(tableNode); + + const firstDescendant = tableNode.getFirstDescendant(); + if ($isTextNode(firstDescendant)) { + firstDescendant.select(); + } - const firstDescendant = tableNode.getFirstDescendant(); - if ($isTextNode(firstDescendant)) { - firstDescendant.select(); + return true; + }, + COMMAND_PRIORITY_EDITOR, + ), + editor.registerNodeTransform(TableNode, (node) => { + const [gridMap] = $computeTableMapSkipCellCheck(node, null, null); + const maxRowLength = gridMap.reduce((curLength, row) => { + return Math.max(curLength, row.length); + }, 0); + for (let i = 0; i < gridMap.length; ++i) { + const rowLength = gridMap[i].length; + if (rowLength === maxRowLength) { + continue; + } + const lastCellMap = gridMap[i][rowLength - 1]; + const lastRowCell = lastCellMap.cell; + for (let j = rowLength; j < maxRowLength; ++j) { + // TODO: inherit header state from another header or body + const newCell = $createTableCellNode(0); + newCell.append($createParagraphNode()); + if (lastRowCell !== null) { + lastRowCell.insertAfter(newCell); + } else { + $insertFirst(lastRowCell, newCell); + } + } } - - return true; - }, - COMMAND_PRIORITY_EDITOR, + }), ); }, [editor]); diff --git a/packages/lexical-table/src/LexicalTableSelectionHelpers.ts b/packages/lexical-table/src/LexicalTableSelectionHelpers.ts index cf6db409f0b..ed443fc3f17 100644 --- a/packages/lexical-table/src/LexicalTableSelectionHelpers.ts +++ b/packages/lexical-table/src/LexicalTableSelectionHelpers.ts @@ -102,15 +102,18 @@ export function applyTableHandlers( }; const onMouseMove = (moveEvent: MouseEvent) => { - const focusCell = getDOMCellFromTarget(moveEvent.target as Node); - if ( - focusCell !== null && - (tableObserver.anchorX !== focusCell.x || - tableObserver.anchorY !== focusCell.y) - ) { - moveEvent.preventDefault(); - tableObserver.setFocusCellForSelection(focusCell); - } + // delaying mousemove handler to allow selectionchange handler from LexicalEvents.ts to be executed first + setTimeout(() => { + const focusCell = getDOMCellFromTarget(moveEvent.target as Node); + if ( + focusCell !== null && + (tableObserver.anchorX !== focusCell.x || + tableObserver.anchorY !== focusCell.y) + ) { + moveEvent.preventDefault(); + tableObserver.setFocusCellForSelection(focusCell); + } + }, 0); }; return {onMouseMove: onMouseMove, onMouseUp: onMouseUp}; }; diff --git a/packages/lexical-table/src/LexicalTableUtils.ts b/packages/lexical-table/src/LexicalTableUtils.ts index e6e507ba16c..07f366982d8 100644 --- a/packages/lexical-table/src/LexicalTableUtils.ts +++ b/packages/lexical-table/src/LexicalTableUtils.ts @@ -720,6 +720,21 @@ export function $computeTableMap( cellA: TableCellNode, cellB: TableCellNode, ): [TableMapType, TableMapValueType, TableMapValueType] { + const [tableMap, cellAValue, cellBValue] = $computeTableMapSkipCellCheck( + grid, + cellA, + cellB, + ); + invariant(cellAValue !== null, 'Anchor not found in Grid'); + invariant(cellBValue !== null, 'Focus not found in Grid'); + return [tableMap, cellAValue, cellBValue]; +} + +export function $computeTableMapSkipCellCheck( + grid: TableNode, + cellA: null | TableCellNode, + cellB: null | TableCellNode, +): [TableMapType, TableMapValueType | null, TableMapValueType | null] { const tableMap: TableMapType = []; let cellAValue: null | TableMapValueType = null; let cellBValue: null | TableMapValueType = null; @@ -739,10 +754,10 @@ export function $computeTableMap( tableMap[startRow + i][startColumn + j] = value; } } - if (cellA.is(cell)) { + if (cellA !== null && cellA.is(cell)) { cellAValue = value; } - if (cellB.is(cell)) { + if (cellB !== null && cellB.is(cell)) { cellBValue = value; } } @@ -771,8 +786,6 @@ export function $computeTableMap( j += cell.__colSpan; } } - invariant(cellAValue !== null, 'Anchor not found in Grid'); - invariant(cellBValue !== null, 'Focus not found in Grid'); return [tableMap, cellAValue, cellBValue]; } diff --git a/packages/lexical-table/src/index.ts b/packages/lexical-table/src/index.ts index 9c723b483e7..c9f3964cf07 100644 --- a/packages/lexical-table/src/index.ts +++ b/packages/lexical-table/src/index.ts @@ -49,6 +49,7 @@ export { } from './LexicalTableSelectionHelpers'; export { $computeTableMap, + $computeTableMapSkipCellCheck, $createTableNodeWithDimensions, $deleteTableColumn, $deleteTableColumn__EXPERIMENTAL, diff --git a/packages/lexical/src/LexicalEvents.ts b/packages/lexical/src/LexicalEvents.ts index edc9dca080b..96cf9ad7c86 100644 --- a/packages/lexical/src/LexicalEvents.ts +++ b/packages/lexical/src/LexicalEvents.ts @@ -826,7 +826,13 @@ function onInput(event: InputEvent, editor: LexicalEditor): void { if (domSelection === null) { return; } - const offset = anchor.offset; + const isBackward = selection.isBackward(); + const startOffset = isBackward + ? selection.anchor.offset + : selection.focus.offset; + const endOffset = isBackward + ? selection.focus.offset + : selection.anchor.offset; // If the content is the same as inserted, then don't dispatch an insertion. // Given onInput doesn't take the current selection (it uses the previous) // we can compare that against what the DOM currently says. @@ -835,9 +841,9 @@ function onInput(event: InputEvent, editor: LexicalEditor): void { selection.isCollapsed() || !$isTextNode(anchorNode) || domSelection.anchorNode === null || - anchorNode.getTextContent().slice(0, offset) + + anchorNode.getTextContent().slice(0, startOffset) + data + - anchorNode.getTextContent().slice(offset + selection.focus.offset) !== + anchorNode.getTextContent().slice(startOffset + endOffset) !== getAnchorTextFromDOM(domSelection.anchorNode) ) { dispatchCommand(editor, CONTROLLED_TEXT_INSERTION_COMMAND, data);