diff --git a/package-lock.json b/package-lock.json index 90050bb..77813be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,15 @@ { "name": "interactions", - "version": "1.3.2", + "version": "1.3.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "interactions", - "version": "1.3.2", + "version": "1.3.3", "license": "GPL-2.0-or-later", "dependencies": { + "@wordpress/components": "^33.0.0", "@wordpress/icons": "^10.31.0", "canvas-confetti": "^1.9.3", "classnames": "^2.5.1", @@ -53,11 +54,48 @@ "node": ">=6.0.0" } }, + "node_modules/@ariakit/core": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/@ariakit/core/-/core-0.4.20.tgz", + "integrity": "sha512-DJbUnui0fM+2ZgiWLOMuFOmlWSJDNV3f6tqghIYRTWEm51TN/LoU6uM8og6/g7Nrwl4Uo5l8AoQT9Kkr/i/uRg==", + "license": "MIT" + }, + "node_modules/@ariakit/react": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/@ariakit/react/-/react-0.4.26.tgz", + "integrity": "sha512-NcoPrYE4vgwyODAhdpNNuA7ldwODDuFqZl6jORPVDY3l+oRjl/OYwtQyyC3ZhC/4mjntYBYuKKrPJEizLmoxpg==", + "license": "MIT", + "dependencies": { + "@ariakit/react-core": "0.4.26" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ariakit" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@ariakit/react-core": { + "version": "0.4.26", + "resolved": "https://registry.npmjs.org/@ariakit/react-core/-/react-core-0.4.26.tgz", + "integrity": "sha512-/Peh1KiVpjj79nCJIa6lEdzSTT9P9FZoy+CxByIFKL3YKdlXmDIIhS1E/tAqKbDq4ODVdynnqmrIDxE5wCoZYw==", + "license": "MIT", + "dependencies": { + "@ariakit/core": "0.4.20", + "@floating-ui/dom": "^1.0.0", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", "js-tokens": "^4.0.0", @@ -128,7 +166,6 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", - "dev": true, "dependencies": { "@babel/parser": "^7.28.3", "@babel/types": "^7.28.2", @@ -226,7 +263,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -248,7 +284,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, "dependencies": { "@babel/traverse": "^7.27.1", "@babel/types": "^7.27.1" @@ -346,7 +381,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -355,7 +389,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -400,7 +433,6 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", - "dev": true, "dependencies": { "@babel/types": "^7.28.4" }, @@ -1874,7 +1906,6 @@ "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/parser": "^7.27.2", @@ -1888,7 +1919,6 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.3", @@ -1906,7 +1936,6 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", - "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.27.1" @@ -2022,6 +2051,18 @@ "@csstools/css-tokenizer": "^3.0.1" } }, + "node_modules/@date-fns/tz": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.4.1.tgz", + "integrity": "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA==", + "license": "MIT" + }, + "node_modules/@date-fns/utc": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@date-fns/utc/-/utc-2.1.1.tgz", + "integrity": "sha512-SlJDfG6RPeEX8wEVv6ZB3kak4MmbtyiI2qX/5zuKdordbrhB/iaJ58GVMZgJ6P1sJaM1gMgENFYYeg1JWrCFrA==", + "license": "MIT" + }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -2041,6 +2082,180 @@ "url": "https://github.com/sponsors/JounQin" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/css": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/css/-/css-11.13.5.tgz", + "integrity": "sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w==", + "license": "MIT", + "dependencies": { + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.13.5", + "@emotion/serialize": "^1.3.3", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", + "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/styled": { + "version": "11.14.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", + "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, "node_modules/@es-joy/jsdoccomment": { "version": "0.41.0", "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", @@ -2166,6 +2381,44 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", + "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.6.1" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "license": "MIT" + }, "node_modules/@formatjs/ecma402-abstract": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.4.tgz", @@ -2709,7 +2962,6 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" @@ -2729,7 +2981,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -2747,14 +2998,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -4401,6 +4650,52 @@ "url": "https://github.com/sponsors/gregberge" } }, + "node_modules/@tabby_ai/hijri-converter": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@tabby_ai/hijri-converter/-/hijri-converter-1.0.5.tgz", + "integrity": "sha512-r5bClKrcIusDoo049dSL8CawnHR6mRdDwhlQuIgZRNty68q0x8k3Lf1BtPAMxRf/GgnHBnIO4ujd3+GQdLWzxQ==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@tannin/compile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@tannin/compile/-/compile-1.1.0.tgz", + "integrity": "sha512-n8m9eNDfoNZoxdvWiTfW/hSPhehzLJ3zW7f8E7oT6mCROoMNWCB4TYtv041+2FMAxweiE0j7i1jubQU4MEC/Gg==", + "license": "MIT", + "dependencies": { + "@tannin/evaluate": "^1.2.0", + "@tannin/postfix": "^1.1.0" + } + }, + "node_modules/@tannin/evaluate": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tannin/evaluate/-/evaluate-1.2.0.tgz", + "integrity": "sha512-3ioXvNowbO/wSrxsDG5DKIMxC81P0QrQTYai8zFNY+umuoHWRPbQ/TuuDEOju9E+jQDXmj6yI5GyejNuh8I+eg==", + "license": "MIT" + }, + "node_modules/@tannin/plural-forms": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@tannin/plural-forms/-/plural-forms-1.1.0.tgz", + "integrity": "sha512-xl9R2mDZO/qiHam1AgMnAES6IKIg7OBhcXqy6eDsRCdXuxAFPcjrej9HMjyCLE0DJ/8cHf0i5OQTstuBRhpbHw==", + "license": "MIT", + "dependencies": { + "@tannin/compile": "^1.1.0" + } + }, + "node_modules/@tannin/postfix": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@tannin/postfix/-/postfix-1.1.0.tgz", + "integrity": "sha512-oocsqY7g0cR+Gur5jRQLSrX2OtpMLMse1I10JQBm8CdGMrDkh1Mg2gjsiquMHRtBs4Qwu5wgEp5GgIYHk4SNPw==", + "license": "MIT" + }, + "node_modules/@tannin/sprintf": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@tannin/sprintf/-/sprintf-1.3.3.tgz", + "integrity": "sha512-RwARl+hFwhzy0tg9atWcchLFvoQiOh4rrP7uG2N5E4W80BPCUX0ElcUR9St43fxB9EfjsW2df9Qp+UsTbvQDjA==", + "license": "MIT" + }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -4575,6 +4870,18 @@ "@types/node": "*" } }, + "node_modules/@types/gradient-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/gradient-parser/-/gradient-parser-1.1.0.tgz", + "integrity": "sha512-SaEcbgQscHtGJ1QL+ajgDTmmqU2f6T+00jZRcFlVHUW2Asivc84LNUev/UQFyu117AsdyrtI+qpwLvgjJXJxmw==", + "license": "MIT" + }, + "node_modules/@types/highlight-words-core": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/highlight-words-core/-/highlight-words-core-1.2.1.tgz", + "integrity": "sha512-9VZUA5omXBfn+hDxFjUDu1FOJTBM3LmvqfDey+Z6Aa8B8/JmF5SMj6FBrjfgJ/Q3YXOZd3qyTDfJyMZSs/wCUA==", + "license": "MIT" + }, "node_modules/@types/http-errors": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", @@ -4649,6 +4956,12 @@ "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", "dev": true }, + "node_modules/@types/mousetrap": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/@types/mousetrap/-/mousetrap-1.6.15.tgz", + "integrity": "sha512-qL0hyIMNPow317QWW/63RvL1x5MVMV+Ru3NaY9f/CuEpCqrmb7WeuK2071ZY5hczOnm38qExWM2i2WtkXLSqFw==", + "license": "MIT" + }, "node_modules/@types/mysql": { "version": "2.15.26", "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.26.tgz", @@ -4685,8 +4998,7 @@ "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", - "dev": true + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" }, "node_modules/@types/pg": { "version": "8.6.1", @@ -4726,12 +5038,13 @@ "dev": true }, "node_modules/@types/react": { - "version": "18.3.24", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.24.tgz", - "integrity": "sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==", + "version": "18.3.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz", + "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", + "license": "MIT", "dependencies": { "@types/prop-types": "*", - "csstype": "^3.0.2" + "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { @@ -5098,6 +5411,24 @@ "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "dev": true }, + "node_modules/@use-gesture/core": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz", + "integrity": "sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==", + "license": "MIT" + }, + "node_modules/@use-gesture/react": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz", + "integrity": "sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==", + "license": "MIT", + "dependencies": { + "@use-gesture/core": "10.3.1" + }, + "peerDependencies": { + "react": ">= 16.8.0" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", @@ -5288,6 +5619,20 @@ } } }, + "node_modules/@wordpress/a11y": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/a11y/-/a11y-4.45.0.tgz", + "integrity": "sha512-KOgdBsZP34nAi+UfrhIAZDt2I1ZDb3DXAgIeQk7QxTIc9OlQKMNfrYwPG0jidgfKwmjFxh8vV8HbZcBzTD29Rw==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@wordpress/dom-ready": "^4.45.0", + "@wordpress/i18n": "^6.18.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, "node_modules/@wordpress/babel-preset-default": { "version": "8.31.0", "resolved": "https://registry.npmjs.org/@wordpress/babel-preset-default/-/babel-preset-default-8.31.0.tgz", @@ -5361,6 +5706,199 @@ "npm": ">=8.19.2" } }, + "node_modules/@wordpress/components": { + "version": "33.0.0", + "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-33.0.0.tgz", + "integrity": "sha512-VeLDtfz8612bdRqgQiSMtIIEGDi4ZByj0XUvjT7E6RVLgczQyV9DTpGOPyL6PbTyAluIx6hjt9bzsaC+bM6G+w==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@ariakit/react": "^0.4.22", + "@date-fns/utc": "^2.1.1", + "@emotion/cache": "^11.14.0", + "@emotion/css": "^11.13.5", + "@emotion/react": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/styled": "^11.14.1", + "@emotion/utils": "^1.4.2", + "@floating-ui/react-dom": "2.0.8", + "@types/gradient-parser": "1.1.0", + "@types/highlight-words-core": "1.2.1", + "@types/react": "^18.3.27", + "@use-gesture/react": "^10.3.1", + "@wordpress/a11y": "^4.45.0", + "@wordpress/base-styles": "^7.0.0", + "@wordpress/compose": "^7.45.0", + "@wordpress/date": "^5.45.0", + "@wordpress/deprecated": "^4.45.0", + "@wordpress/dom": "^4.45.0", + "@wordpress/element": "^6.45.0", + "@wordpress/escape-html": "^3.45.0", + "@wordpress/hooks": "^4.45.0", + "@wordpress/html-entities": "^4.45.0", + "@wordpress/i18n": "^6.18.0", + "@wordpress/icons": "^13.0.0", + "@wordpress/is-shallow-equal": "^5.45.0", + "@wordpress/keycodes": "^4.45.0", + "@wordpress/primitives": "^4.45.0", + "@wordpress/private-apis": "^1.45.0", + "@wordpress/rich-text": "^7.45.0", + "@wordpress/warning": "^3.45.0", + "change-case": "^4.1.2", + "clsx": "^2.1.1", + "colord": "^2.7.0", + "csstype": "^3.2.3", + "date-fns": "^3.6.0", + "deepmerge": "^4.3.0", + "fast-deep-equal": "^3.1.3", + "framer-motion": "^11.15.0", + "gradient-parser": "1.1.1", + "highlight-words-core": "^1.2.2", + "is-plain-object": "^5.0.0", + "memize": "^2.1.0", + "path-to-regexp": "^6.2.1", + "re-resizable": "^6.4.0", + "react-colorful": "^5.6.1", + "react-day-picker": "^9.7.0", + "remove-accents": "^0.5.0", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@wordpress/components/node_modules/@wordpress/base-styles": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@wordpress/base-styles/-/base-styles-7.0.0.tgz", + "integrity": "sha512-Q0BbZzfeYbQZKHnyNT4RF8RGVugN5jStGtpRKhBYQW7ut7sS61LbbpP7jR0D0sDPYoEEC8jKZQSZwSM23B4jow==", + "license": "GPL-2.0-or-later", + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/components/node_modules/@wordpress/icons": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-13.0.0.tgz", + "integrity": "sha512-+CLbvNdzMUHxQK5I6gFdHb3X6EVAH6SOSIj0xtMWm6PZO+Nnf7tXHfNBuxqTnGfxT5grtfb6D3A9ZMBU+Tpv+Q==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@wordpress/element": "^6.45.0", + "@wordpress/primitives": "^4.45.0", + "change-case": "4.1.2" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/@wordpress/components/node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/@wordpress/components/node_modules/path-to-regexp": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "license": "MIT" + }, + "node_modules/@wordpress/components/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@wordpress/compose": { + "version": "7.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-7.45.0.tgz", + "integrity": "sha512-/keWdRFUe7bnzh2ZtOYLexknpj0K0G56WFw7RLZehl54a9EmzjYjAODBOF9DB3c07pJuNuy7c5QgqMPi0cqLlw==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@types/mousetrap": "^1.6.8", + "@wordpress/deprecated": "^4.45.0", + "@wordpress/dom": "^4.45.0", + "@wordpress/element": "^6.45.0", + "@wordpress/is-shallow-equal": "^5.45.0", + "@wordpress/keycodes": "^4.45.0", + "@wordpress/priority-queue": "^3.45.0", + "@wordpress/undo-manager": "^1.45.0", + "change-case": "^4.1.2", + "mousetrap": "^1.6.5", + "use-memo-one": "^1.1.1" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/@wordpress/data": { + "version": "10.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-10.45.0.tgz", + "integrity": "sha512-OR/uMpcEbCh1aBkbzateXffNrL829M+N92qtuD+Gt08Mey129WIEVR9kBC2Tf02VtXs644OKZD6cz77KlxH8XA==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@wordpress/compose": "^7.45.0", + "@wordpress/deprecated": "^4.45.0", + "@wordpress/element": "^6.45.0", + "@wordpress/is-shallow-equal": "^5.45.0", + "@wordpress/priority-queue": "^3.45.0", + "@wordpress/private-apis": "^1.45.0", + "@wordpress/redux-routine": "^5.45.0", + "deepmerge": "^4.3.0", + "equivalent-key-map": "^0.2.2", + "is-plain-object": "^5.0.0", + "is-promise": "^4.0.0", + "redux": "^5.0.1", + "rememo": "^4.0.2", + "use-memo-one": "^1.1.1" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, + "node_modules/@wordpress/date": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/date/-/date-5.45.0.tgz", + "integrity": "sha512-34v3hCxn68kYzWs8bhuAt8cfMxdFX9ukKn3a3FB+tAJXpxafnPCcZoWfJHn4I8hepCbreFrf3UiGdA+id2kQ4A==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@wordpress/deprecated": "^4.45.0", + "moment": "^2.29.4", + "moment-timezone": "^0.5.40" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, "node_modules/@wordpress/dependency-extraction-webpack-plugin": { "version": "6.31.0", "resolved": "https://registry.npmjs.org/@wordpress/dependency-extraction-webpack-plugin/-/dependency-extraction-webpack-plugin-6.31.0.tgz", @@ -5383,6 +5921,42 @@ "integrity": "sha512-dnSoUiLAoVaMXxFsVi4CrPVYMKOuDBXTghXSmMINX44RZ8WM9cXlY7UqrQnlAcODCVO7FV3+8t/5nDKAjimLfg==", "dev": true }, + "node_modules/@wordpress/deprecated": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-4.45.0.tgz", + "integrity": "sha512-qer/fk/lgmmisb8/hj1xZtsbJbZhCoOblhyxI2k7RRul7rQDdk+fm28LJYV+eIF0ldSVX30f4dmz1pvcVHQEEg==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@wordpress/hooks": "^4.45.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/dom": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/dom/-/dom-4.45.0.tgz", + "integrity": "sha512-6RObr/KEZS1FnZwpcDAsKlJ3qw2KLF5+A/LsxlM9fSWDGSO05CEaTp+VmWgx9pwjQWbPEa7N73ijEy8cCNSZWA==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@wordpress/deprecated": "^4.45.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/dom-ready": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-4.45.0.tgz", + "integrity": "sha512-0lFImpg9DGXcGCDQePdoU8haz7QYsKOFXUMTpRvi/Te38LFXzgZtOUBQbY8fRBlLxrgrj4FsAIc7bzdLn73wNQ==", + "license": "GPL-2.0-or-later", + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, "node_modules/@wordpress/e2e-test-utils-playwright": { "version": "1.31.0", "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-1.31.0.tgz", @@ -5405,14 +5979,14 @@ } }, "node_modules/@wordpress/element": { - "version": "6.31.0", - "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.31.0.tgz", - "integrity": "sha512-KOier6Y4b4Y5yEV1GYen81R9gCEOvJT6eVbsc93w2fFEKi2FK/oI7IKzGv9GeJMkoCWvTSX6C/ZYTWk6fCUfeA==", + "version": "6.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.45.0.tgz", + "integrity": "sha512-WFrGNPEnj8uE+XhFW9NVbxvqraYpConaEokLv9IszFYVfyg8juXSQcHOAfEnxjC08HBPfVcayr2igu/XUgGOAw==", + "license": "GPL-2.0-or-later", "dependencies": { - "@babel/runtime": "7.25.7", - "@types/react": "^18.2.79", - "@types/react-dom": "^18.2.25", - "@wordpress/escape-html": "^3.31.0", + "@types/react": "^18.3.27", + "@types/react-dom": "^18.3.1", + "@wordpress/escape-html": "^3.45.0", "change-case": "^4.1.2", "is-plain-object": "^5.0.0", "react": "^18.3.0", @@ -5424,12 +5998,10 @@ } }, "node_modules/@wordpress/escape-html": { - "version": "3.31.0", - "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-3.31.0.tgz", - "integrity": "sha512-9g9qd7Q16PWDeYEa2dU+84d1SvjP4LfS7n7AuXkwl5+F7KfL2nZTmDTHWutw9jVjdDAGmjm1VNIj4ydQk9vaLA==", - "dependencies": { - "@babel/runtime": "7.25.7" - }, + "version": "3.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-3.45.0.tgz", + "integrity": "sha512-IW4mnA+65XKhABuBkwrQNAlbq97luC6ZIBfdSq0Tkq+AFPqE1lJTMlLo7iBkTpsHsBLyznViPXultq40fz8L7w==", + "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" @@ -5478,6 +6050,46 @@ } } }, + "node_modules/@wordpress/hooks": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-4.45.0.tgz", + "integrity": "sha512-+gOlu8TdohqL1INQNxS/7CxhM4T4MuYnKietWV9zWDmNQV2ysM0SdamNk5pWERJ4w0yY9XhtMBcwR/piJtePZg==", + "license": "GPL-2.0-or-later", + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/html-entities": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-4.45.0.tgz", + "integrity": "sha512-7W95xaOv4UgMSWlEmyO7YkBsUae3QlQu3GKENVH7Pt/osbJGSPInAJ1ruO4oeUwGPygWOL7b7IzRsgTNP0M/Wg==", + "license": "GPL-2.0-or-later", + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/i18n": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-6.18.0.tgz", + "integrity": "sha512-6dYCih4wUwi7Csu4RNfHiAKkgWhpSQdl8YthvQUF59Sfsoia3RCdtd4K2l7W4f18ldFA/RXjShMjvSexWy6OyQ==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@tannin/sprintf": "^1.3.2", + "@wordpress/hooks": "^4.45.0", + "gettext-parser": "^1.3.1", + "memize": "^2.1.0", + "tannin": "^1.2.0" + }, + "bin": { + "pot-to-php": "tools/pot-to-php.js" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, "node_modules/@wordpress/icons": { "version": "10.31.0", "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-10.31.0.tgz", @@ -5492,6 +6104,16 @@ "npm": ">=8.19.2" } }, + "node_modules/@wordpress/is-shallow-equal": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-5.45.0.tgz", + "integrity": "sha512-saamGjAuhZOiFOyznsriPGrO8GRDremImMO4q92qjQqmDqssC+FRDQnwr9D8BaedSnVvUDcriGeYBObEEnIJ2A==", + "license": "GPL-2.0-or-later", + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, "node_modules/@wordpress/jest-console": { "version": "8.31.0", "resolved": "https://registry.npmjs.org/@wordpress/jest-console/-/jest-console-8.31.0.tgz", @@ -5527,6 +6149,19 @@ "jest": ">=29" } }, + "node_modules/@wordpress/keycodes": { + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.45.0.tgz", + "integrity": "sha512-N+Wp572xZovLM45cYo6HfUNTQNDfEqakAYIOcY8bUqA2iFelN6AUkNfUIkIxmrE0EqkQAQ5odES03g8ym7e1IA==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@wordpress/i18n": "^6.18.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, "node_modules/@wordpress/npm-package-json-lint-config": { "version": "5.31.0", "resolved": "https://registry.npmjs.org/@wordpress/npm-package-json-lint-config/-/npm-package-json-lint-config-5.31.0.tgz", @@ -5571,12 +6206,12 @@ } }, "node_modules/@wordpress/primitives": { - "version": "4.31.0", - "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-4.31.0.tgz", - "integrity": "sha512-cY4EKYQRqHu9NZuoWchxc/KWiofwGskzxz0oCfgbdkRlfTag8yBjWMayz+fRNaenw0l5pzLyIg3rcNDN8xLezw==", + "version": "4.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-4.45.0.tgz", + "integrity": "sha512-x+i6EKUvz96EkUb2KuBTLNGm8d5+ZS0FYjUEnIhp5dtWxjMe8dJT6LS+n363vg+K28LVvjptiTAaByccnNKc9w==", + "license": "GPL-2.0-or-later", "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/element": "^6.31.0", + "@wordpress/element": "^6.45.0", "clsx": "^2.1.1" }, "engines": { @@ -5587,6 +6222,74 @@ "react": "^18.0.0" } }, + "node_modules/@wordpress/priority-queue": { + "version": "3.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-3.45.0.tgz", + "integrity": "sha512-0sIX2PRPzo5nk252f60xpPj3/BUZxEOLcabCC7FuvQDYPGZrRyS6Dy0vDDzozZxHGuUYCT65t8ubBwXx37wXCw==", + "license": "GPL-2.0-or-later", + "dependencies": { + "requestidlecallback": "^0.3.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/private-apis": { + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-1.45.0.tgz", + "integrity": "sha512-UjhIDpoyKKUghPM0tkqd5Whsuk4kqfAfhb5VYGoEYtunDs0rB8IxgFO7hE0PhimHL74QVgaJOlprRZVRCCoQ6w==", + "license": "GPL-2.0-or-later", + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/redux-routine": { + "version": "5.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/redux-routine/-/redux-routine-5.45.0.tgz", + "integrity": "sha512-6ShpBns4jIBFXrYFBcKA5pnFm/kjr1SqFvLj5DwLgMV61eI3Rr9LyZwIzNR2BGg067ryxu4W172Uqjke/mZjcQ==", + "license": "GPL-2.0-or-later", + "dependencies": { + "is-plain-object": "^5.0.0", + "is-promise": "^4.0.0", + "rungen": "^0.3.2" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "redux": ">=4" + } + }, + "node_modules/@wordpress/rich-text": { + "version": "7.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-7.45.0.tgz", + "integrity": "sha512-C5+JQqNzA3fiQq0hN9pQPKsjcwO/fczouHqubq3847kAUrClROqqI1GJHE34WLl1Vp+/tWQuBkIjQ/95olKteA==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@wordpress/a11y": "^4.45.0", + "@wordpress/compose": "^7.45.0", + "@wordpress/data": "^10.45.0", + "@wordpress/deprecated": "^4.45.0", + "@wordpress/dom": "^4.45.0", + "@wordpress/element": "^6.45.0", + "@wordpress/escape-html": "^3.45.0", + "@wordpress/i18n": "^6.18.0", + "@wordpress/keycodes": "^4.45.0", + "@wordpress/private-apis": "^1.45.0", + "colord": "2.9.3", + "memize": "^2.1.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "react": "^18.0.0" + } + }, "node_modules/@wordpress/scripts": { "version": "30.24.0", "resolved": "https://registry.npmjs.org/@wordpress/scripts/-/scripts-30.24.0.tgz", @@ -5777,11 +6480,24 @@ "stylelint-scss": "^6.4.0" } }, + "node_modules/@wordpress/undo-manager": { + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/undo-manager/-/undo-manager-1.45.0.tgz", + "integrity": "sha512-BqclZIPjzBYIjLqLZFihs+Ce+w+yBQuj44VYSrRDOj56AbMtwmClIUqgIVBZAe2En/2ncixTTWOZG9KluvEXfA==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@wordpress/is-shallow-equal": "^5.45.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, "node_modules/@wordpress/warning": { - "version": "3.31.0", - "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-3.31.0.tgz", - "integrity": "sha512-Npw1Apa6r+K+jtX40ABWAXv7J1bVnOi6h9VPiMY8l/iZoRHBXao8HTgQnIoCm+GzymaQs6NQoH4X8UAClggeXA==", - "dev": true, + "version": "3.45.0", + "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-3.45.0.tgz", + "integrity": "sha512-NQ9tAhPdwhfceVIzWra1rbumvgAFAEDTgZlWsX880zLiq1F8JTwBouwW6wfIhA3XLcY6Yj7cBBYLa8vnNiDZDw==", + "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" @@ -6547,6 +7263,21 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.14", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", @@ -7046,7 +7777,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -7415,8 +8145,7 @@ "node_modules/colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", - "dev": true + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==" }, "node_modules/colorette": { "version": "2.0.20", @@ -7760,7 +8489,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dev": true, "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -8093,9 +8821,10 @@ "dev": true }, "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" }, "node_modules/cwd": { "version": "0.10.0", @@ -8206,6 +8935,12 @@ "url": "https://opencollective.com/date-fns" } }, + "node_modules/date-fns-jalali": { + "version": "4.1.0-0", + "resolved": "https://registry.npmjs.org/date-fns-jalali/-/date-fns-jalali-4.1.0-0.tgz", + "integrity": "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg==", + "license": "MIT" + }, "node_modules/debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", @@ -8216,7 +8951,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "dependencies": { "ms": "^2.1.3" }, @@ -8302,7 +9036,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -8655,6 +9388,15 @@ "node": ">= 0.8" } }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, "node_modules/end-of-stream": { "version": "1.4.5", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", @@ -8723,11 +9465,16 @@ "node": ">=4" } }, + "node_modules/equivalent-key-map": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/equivalent-key-map/-/equivalent-key-map-0.2.2.tgz", + "integrity": "sha512-xvHeyCDbZzkpN4VHQj/n+j2lOwL0VWszG30X4cOrc9Y7Tuo2qCdZK/0AMod23Z5dCtNUbaju6p0rwOhHUk05ew==", + "license": "MIT" + }, "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "dev": true, "dependencies": { "is-arrayish": "^0.2.1" } @@ -8935,7 +9682,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "engines": { "node": ">=10" }, @@ -10049,8 +10795,7 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-diff": { "version": "1.3.0", @@ -10350,6 +11095,12 @@ "find-process": "bin/find-process.js" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -10524,6 +11275,33 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/framer-motion": { + "version": "11.18.2", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz", + "integrity": "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==", + "license": "MIT", + "dependencies": { + "motion-dom": "^11.18.1", + "motion-utils": "^11.18.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -10572,7 +11350,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -10737,6 +11514,16 @@ "node": ">= 14" } }, + "node_modules/gettext-parser": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.4.0.tgz", + "integrity": "sha512-sedZYLHlHeBop/gZ1jdg59hlUEcpcZJofLq2JFwJT1zTqAU3l2wFv6IsuwFHGqbiT9DWzMUW4/em2+hspnmMMA==", + "license": "MIT", + "dependencies": { + "encoding": "^0.1.12", + "safe-buffer": "^5.1.1" + } + }, "node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -10902,6 +11689,14 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, + "node_modules/gradient-parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/gradient-parser/-/gradient-parser-1.1.1.tgz", + "integrity": "sha512-Hu0YfNU+38EsTmnUfLXUKFMXq9yz7htGYpF4x+dlbBhUCvIvzLt0yVLT/gJRmvLKFJdqNFrz4eKkIUjIXSr7Tw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -11017,7 +11812,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "dependencies": { "function-bind": "^1.1.2" }, @@ -11034,6 +11828,27 @@ "tslib": "^2.0.3" } }, + "node_modules/highlight-words-core": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/highlight-words-core/-/highlight-words-core-1.2.3.tgz", + "integrity": "sha512-m1O9HW3/GNHxzSIXWw1wCNXXsgLlxrP0OI6+ycGUhiUHkikqW3OrwVHz+lxeNBe5yqLESdIcj8PowHQ2zLvUvQ==", + "license": "MIT" + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, "node_modules/homedir-polyfill": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", @@ -11291,7 +12106,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -11390,7 +12204,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -11406,7 +12219,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "engines": { "node": ">=4" } @@ -11577,8 +12389,7 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "node_modules/is-async-function": { "version": "2.1.1", @@ -11679,7 +12490,6 @@ "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, "dependencies": { "hasown": "^2.0.2" }, @@ -11903,6 +12713,12 @@ "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, "node_modules/is-regex": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", @@ -12992,7 +13808,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, "bin": { "jsesc": "bin/jsesc" }, @@ -13009,8 +13824,7 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema-traverse": { "version": "0.4.1", @@ -13416,8 +14230,7 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/linkify-it": { "version": "3.0.3", @@ -13844,6 +14657,12 @@ "node": ">= 4.0.0" } }, + "node_modules/memize": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/memize/-/memize-2.1.1.tgz", + "integrity": "sha512-8Nl+i9S5D6KXnruM03Jgjb+LwSupvR13WBr4hJegaaEyobvowCVupi79y2WSiWvO1mzBWxPwEYE5feCe8vyA5w==", + "license": "MIT" + }, "node_modules/meow": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", @@ -14145,6 +14964,48 @@ "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", "dev": true }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.48.tgz", + "integrity": "sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==", + "license": "MIT", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/motion-dom": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", + "integrity": "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==", + "license": "MIT", + "dependencies": { + "motion-utils": "^11.18.1" + } + }, + "node_modules/motion-utils": { + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.18.1.tgz", + "integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==", + "license": "MIT" + }, + "node_modules/mousetrap": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/mousetrap/-/mousetrap-1.6.5.tgz", + "integrity": "sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA==", + "license": "Apache-2.0 WITH LLVM-exception" + }, "node_modules/mrmime": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", @@ -14157,8 +15018,7 @@ "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/multicast-dns": { "version": "7.2.5", @@ -14899,7 +15759,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "dependencies": { "callsites": "^3.0.0" }, @@ -14917,7 +15776,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -15021,8 +15879,7 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { "version": "1.11.1", @@ -15065,7 +15922,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, "engines": { "node": ">=8" } @@ -15110,8 +15966,7 @@ "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -16359,6 +17214,16 @@ "node": ">=0.10.0" } }, + "node_modules/re-resizable": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/re-resizable/-/re-resizable-6.11.2.tgz", + "integrity": "sha512-2xI2P3OHs5qw7K0Ud1aLILK6MQxW50TcO+DetD9eIV58j84TqYeHoZcL9H4GXFXXIh7afhH8mv5iUCXII7OW7A==", + "license": "MIT", + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -16370,6 +17235,48 @@ "node": ">=0.10.0" } }, + "node_modules/react-colorful": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", + "integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/react-day-picker": { + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-9.14.0.tgz", + "integrity": "sha512-tBaoDWjPwe0M5pGrum4H0SR6Lyk+BO9oHnp9JbKpGKW2mlraNPgP9BMfsg5pWpwrssARmeqk7YBl2oXutZTaHA==", + "license": "MIT", + "dependencies": { + "@date-fns/tz": "^1.4.1", + "@tabby_ai/hijri-converter": "1.0.5", + "date-fns": "^4.1.0", + "date-fns-jalali": "4.1.0-0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/gpbl" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/react-day-picker/node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/react-dom": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", @@ -16546,6 +17453,12 @@ "node": ">=8" } }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -16658,6 +17571,24 @@ "node": ">=6" } }, + "node_modules/rememo": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/rememo/-/rememo-4.0.2.tgz", + "integrity": "sha512-NVfSP9NstE3QPNs/TnegQY0vnJnstKQSpcrsI2kBTB3dB2PkdfKdTa+abbjMIDqpc63fE5LfjLgfMst0ULMFxQ==", + "license": "MIT" + }, + "node_modules/remove-accents": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", + "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==", + "license": "MIT" + }, + "node_modules/requestidlecallback": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/requestidlecallback/-/requestidlecallback-0.3.0.tgz", + "integrity": "sha512-TWHFkT7S9p7IxLC5A1hYmAYQx2Eb9w1skrXmQ+dS1URyvR8tenMLl4lHbqEOUnpEYxNKpkVMXUgknVpBZWXXfQ==", + "license": "MIT" + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -16709,7 +17640,6 @@ "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", - "dev": true, "dependencies": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", @@ -16929,6 +17859,12 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rungen": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/rungen/-/rungen-0.3.2.tgz", + "integrity": "sha512-zWl10xu2D7zoR8zSC2U6bg5bYF6T/Wk7rxwp8IPaJH7f0Ge21G03kNHVgHR7tyVkSSfAOG0Rqf/Cl38JftSmtw==", + "license": "MIT" + }, "node_modules/rxjs": { "version": "7.8.2", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", @@ -16961,7 +17897,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, "funding": [ { "type": "github", @@ -17013,8 +17948,7 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sass": { "version": "1.92.1", @@ -18581,6 +19515,12 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -18613,7 +19553,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -18745,6 +19684,15 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, + "node_modules/tannin": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tannin/-/tannin-1.2.0.tgz", + "integrity": "sha512-U7GgX/RcSeUETbV7gYgoz8PD7Ni4y95pgIP/Z6ayI3CfhSujwKEBlGFTCRN+Aqnuyf4AN2yHL+L8x+TCGjb9uA==", + "license": "MIT", + "dependencies": { + "@tannin/plural-forms": "^1.1.0" + } + }, "node_modules/tapable": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.3.tgz", @@ -19555,6 +20503,24 @@ "requires-port": "^1.0.0" } }, + "node_modules/use-memo-one": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.3.tgz", + "integrity": "sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -20314,7 +21280,6 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, "engines": { "node": ">= 6" } diff --git a/package.json b/package.json index 65b5d93..c7e050a 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "build": "node scripts/update-build-type.js free && node scripts/sync-version.js ${npm_config_suffix} && npx wp-scripts build && npm run build:css && npm run build:frontend-php && npm run optimize-videos && BUILD_TYPE=free npm run package ${npm_config_suffix}", "build:frontend-php": "node scripts/generate-frontend-php-scripts.mjs production free", "build:frontend-php:premium": "node scripts/generate-frontend-php-scripts.mjs production premium", - "build:css": "webpack --config webpack.css.config.js && npm run clean:css-js", + "build:css": "webpack --config webpack.css.config.js && npm run build:css:wp-components-scoped && npm run clean:css-js", + "build:css:wp-components-scoped": "node scripts/build-scoped-wp-components-css.mjs", "clean:css-js": "rm -f dist/*.css.js", "start": "node scripts/update-build-type.js free && concurrently \"wp-scripts start\" \"webpack --config webpack.css.config.js --watch\"", "lint:js": "wp-scripts lint-js", @@ -25,7 +26,7 @@ "optimize-videos": "node scripts/optimize-videos.js", "package": "node scripts/package.js", "sync-version": "node scripts/sync-version.js", - "build:premium": "node scripts/update-build-type.js premium && node scripts/sync-version.js ${npm_config_suffix} && npm run clean:css-js && npx wp-scripts build --config pro__premium_only/webpack.config.js && npx webpack --config pro__premium_only/webpack.css.config.js && npm run build:frontend-php:premium && npm run optimize-videos && BUILD_TYPE=premium npm run package ${npm_config_suffix}", + "build:premium": "node scripts/update-build-type.js premium && node scripts/sync-version.js ${npm_config_suffix} && npm run clean:css-js && npx wp-scripts build --config pro__premium_only/webpack.config.js && npx webpack --config pro__premium_only/webpack.css.config.js && npm run build:css:wp-components-scoped && npm run build:frontend-php:premium && npm run optimize-videos && BUILD_TYPE=premium npm run package ${npm_config_suffix}", "start:premium": "cd pro__premium_only && npm run start", "lint:premium": "cd pro__premium_only && npm run lint", "lint:premium:fix": "cd pro__premium_only && npm run lint:fix" @@ -34,28 +35,29 @@ "extends @wordpress/browserslist-config" ], "devDependencies": { + "@node-minify/core": "^8.0.6", + "@node-minify/uglify-js": "^8.0.6", + "@svgr/webpack": "^8.1.0", + "@wordpress/babel-preset-default": "^8.19.0", "@wordpress/eslint-plugin": "^22.15.0", "@wordpress/prettier-config": "^4.29.0", "@wordpress/scripts": "^30.0.0", "@wordpress/stylelint-config": "^23.21.0", - "@wordpress/babel-preset-default": "^8.19.0", - "@svgr/webpack": "^8.1.0", - "@node-minify/core": "^8.0.6", - "@node-minify/uglify-js": "^8.0.6", + "archiver": "^6.0.1", "babel-loader": "^9.2.1", "concurrently": "^8.2.2", + "eslint": "^8.57.0", + "eslint-plugin-compat": "^6.0.2", "file-loader": "^6.2.0", "fluent-ffmpeg": "^2.1.3", "mini-css-extract-plugin": "^2.7.6", + "prettier": "^3.3.3", "sass": "^1.69.0", "sass-loader": "^14.0.0", - "style-loader": "^3.3.3", - "archiver": "^6.0.1", - "eslint": "^8.57.0", - "eslint-plugin-compat": "^6.0.2", - "prettier": "^3.3.3" + "style-loader": "^3.3.3" }, "dependencies": { + "@wordpress/components": "^33.0.0", "@wordpress/icons": "^10.31.0", "canvas-confetti": "^1.9.3", "classnames": "^2.5.1", diff --git a/scripts/build-scoped-wp-components-css.mjs b/scripts/build-scoped-wp-components-css.mjs new file mode 100644 index 0000000..a208c6d --- /dev/null +++ b/scripts/build-scoped-wp-components-css.mjs @@ -0,0 +1,101 @@ +import fs from 'fs' +import path from 'path' +import postcss from 'postcss' + +const ROOT = process.cwd() +const INPUT_CSS = path.join( + ROOT, + 'node_modules', + '@wordpress', + 'components', + 'build-style', + 'style.css' +) +const OUTPUT_CSS = path.join( ROOT, 'dist', 'wp-components-scoped.css' ) + +const COMPONENT_SCOPES = [ + '#interact-elementor-root', + '.interact-popover', +] +const BODY_SCOPE = 'body.interact-elementor-editor' +const PORTAL_PATTERNS = [ + '.components-modal', + '.components-snackbar', + '.components-tooltip', + '.components-guide', +] + +// Wrap scope selectors in :where() so scoping does not increase specificity. +const wrapScope = scope => `:where(${ scope })` + +// Some WordPress component UI is rendered in portals outside our sidebar root. +const isPortalSelector = selector => { + return PORTAL_PATTERNS.some( pattern => selector.includes( pattern ) ) +} + +// Check if a rule is inside a keyframes block, which should not be scoped. +const isInsideKeyframes = rule => { + let current = rule.parent + while ( current ) { + if ( current.type === 'atrule' && current.name.includes( 'keyframes' ) ) { + return true + } + current = current.parent + } + return false +} + +// Scope each selector to the Interactions Elementor UI while keeping popovers +// and other portal-based components reachable outside the sidebar root. +const scopeRootSelector = selector => { + if ( selector.startsWith( ':root' ) ) { + return [ ...COMPONENT_SCOPES.map( wrapScope ), wrapScope( BODY_SCOPE ) ] + } + + if ( selector.startsWith( 'body' ) ) { + return [ selector.replace( /^body\b/, wrapScope( BODY_SCOPE ) ) ] + } + + if ( selector.startsWith( 'html' ) ) { + return [ `${ wrapScope( BODY_SCOPE ) } ${ selector }` ] + } + + if ( isPortalSelector( selector ) ) { + return [ `${ wrapScope( BODY_SCOPE ) } ${ selector }` ] + } + + if ( /(^|[\s>+~])\.components-popover(?![a-zA-Z0-9_-])/.test( selector ) ) { + return [ selector.replace( /(^|[\s>+~])\.components-popover(?![a-zA-Z0-9_-])/g, `$1${ wrapScope( '.interact-popover.components-popover' ) }` ) ] + } + + return COMPONENT_SCOPES.map( scope => `${ wrapScope( scope ) } ${ selector }` ) +} + +const css = fs.readFileSync( INPUT_CSS, 'utf8' ) +const root = postcss.parse( css ) + +root.walkRules( rule => { + if ( ! Array.isArray( rule.selectors ) ) { + return + } + + if ( isInsideKeyframes( rule ) ) { + return + } + + rule.selectors = rule.selectors.flatMap( selector => scopeRootSelector( selector ) ) +} ) + +fs.mkdirSync( path.dirname( OUTPUT_CSS ), { recursive: true } ) +fs.writeFileSync( OUTPUT_CSS, root.toString() ) + +process.stdout.write( + JSON.stringify( + { + input: path.relative( ROOT, INPUT_CSS ), + output: path.relative( ROOT, OUTPUT_CSS ), + }, + null, + 2 + ) + '\n' +) diff --git a/src/editor/app.js b/src/editor/app.js new file mode 100644 index 0000000..f263317 --- /dev/null +++ b/src/editor/app.js @@ -0,0 +1,423 @@ +import ElementSVG from './assets/element.svg' +import PageSVG from './assets/page.svg' +import { + AddInteractionButton, + InteractionButton, + InteractionPanel, + ImportExportModal, +} from './components' +import { createNewInteraction, createNewAction } from './util' +import { useInteractions } from './hooks' +import { interactions as interactionsConfig, manageInteractionsUrl } from 'interactions' +import { InteractionLibrary } from './interaction-library' +import { isGutenbergEditor } from '~interact/editor/editors' + +import { __ } from '@wordpress/i18n' +import { upload } from '@wordpress/icons' +import { + PanelBody, + Button, + BaseControl, + Notice, +} from '@wordpress/components' +import { + useState, + useCallback, + useRef, + useEffect, + createInterpolateElement, +} from '@wordpress/element' +import { useSelect, useDispatch } from '@wordpress/data' + +import useOnPostPreview from './use-on-post-save' + +// Get dismissed errors from localStorage with error handling. +const getDismissedErrors = () => { + try { + const dismissedErrors = JSON.parse( localStorage.getItem( 'interact-dismissed-errors' ) || '[]' ) + return Array.isArray( dismissedErrors ) ? dismissedErrors : [] + } catch ( error ) { + return [] + } +} + +// Normalize imported interaction data to ensure it has the expected structure, even if some fields are missing. +const normalizeImportedInteraction = data => { + const timelines = data.timelines || [] + + return { + ...data, + timelines: timelines.map( timeline => { + const actionsToImport = timeline.actions || [] + const actions = actionsToImport.map( action => ( + createNewAction( { + actionType: action.type ?? '', + start: action.timing?.start ?? 0, + targetType: action.target?.type ?? '', + props: { ...action }, + } ) + ) ) + + return { + ...timeline, + actions, + } + } ), + } +} + +const InteractionsApp = ( { + selectedBlockAnchor = null, + enablePostPreviewGuard = true, +} ) => { + const isGutenberg = isGutenbergEditor() + const interactionLibraryMode = useSelect( select => + select( 'interact/interaction-library-modal' ).getMode(), + [] ) + // Interaction library open modal and set target function. + const { + setMode: setInteractionLibraryMode, + } = useDispatch( 'interact/interaction-library-modal' ) + + const [ selectedInteraction, setSelectedInteraction ] = useState( null ) + const [ editPropsPassed, setEditPropsPassed ] = useState( {} ) + const [ editMode, setEditMode ] = useState( 'edit' ) + const [ isShowingError, setIsShowingError ] = useState( true ) + const [ importExportModalProps, setImportExportModalProps ] = useState( null ) + + const sidebarRef = useRef() + // This gets updated when the current interaction being edited is dirty. + const isDirtyRef = useRef( false ) + + const { + interactions: allInteractions, + interactionsFiltered: interactions, + loadingError, + updateInteraction, + deleteInteraction, + } = useInteractions() + + // This listens to the post preview button and publish button and asks the + // user to save the interaction if it's dirty. + const onPostSaveCallback = proceedSaveCallback => { + if ( isDirtyRef.current ) { + // eslint-disable-next-line no-alert + if ( confirm( __( 'You have unsaved changes in your interaction. Do you want to save it before continuing?', 'interactions' ) ) ) { + window?.dispatchEvent( new CustomEvent( 'interact/save-interaction', { + detail: { + // This callback will be called after the interaction is saved. + callback: proceedSaveCallback, + }, + } ) ) + return true + } + } + } + + useOnPostPreview( enablePostPreviewGuard ? onPostSaveCallback : () => {} ) + + const getInteractionFromKey = useCallback( key => { + return allInteractions.find( interaction => interaction.key === key ) + }, [ allInteractions ] ) + + const onAddInteractionHandler = useCallback( ( interactionType, target = null, props = {} ) => { + if ( selectedInteraction && isDirtyRef.current ) { + alert( __( 'You are currently editing an interaction, please save or discard your changes first.', 'interactions' ) )// eslint-disable-line no-alert + return + } + setEditMode( 'new' ) + const newInteraction = createNewInteraction( interactionType, target, props ) + setSelectedInteraction( newInteraction ) + }, [ selectedInteraction ] ) + + const onEditInteractionHandler = useCallback( ( keyOrInteraction, editProps ) => { + if ( selectedInteraction && isDirtyRef.current ) { + alert( __( 'You are currently editing an interaction, please save or discard your changes first.', 'interactions' ) )// eslint-disable-line no-alert + return + } + // If editMode is provided (e.g. when duplicating), set the editMode state accordingly. + if ( typeof editProps.editMode !== 'undefined' ) { + setEditMode( editProps.editMode ) + } + setEditPropsPassed( editProps ) + setSelectedInteraction( typeof keyOrInteraction === 'string' ? getInteractionFromKey( keyOrInteraction ) : keyOrInteraction ) + }, [ getInteractionFromKey, selectedInteraction ] ) + + // Listen to external adds of interactions from the main toolbar button. + useEffect( () => { + const onAddInteractionEventHandler = event => { + onAddInteractionHandler( event.detail.type, event.detail.target, event.detail.props ) + } + const onEditInteractionEventHandler = event => { + const { + key, interaction, ...editProps + } = event.detail + onEditInteractionHandler( key || interaction, editProps ) + } + + window?.addEventListener( 'interact/add-interaction', onAddInteractionEventHandler ) + window?.addEventListener( 'interact/edit-interaction', onEditInteractionEventHandler ) + + return () => { + window?.removeEventListener( 'interact/add-interaction', onAddInteractionEventHandler ) + window?.removeEventListener( 'interact/edit-interaction', onEditInteractionEventHandler ) + } + }, [ onAddInteractionHandler, onEditInteractionHandler ] ) + + useEffect( () => { + if ( ! selectedInteraction ) { + setEditPropsPassed( {} ) + } + }, [ selectedInteraction ] ) + + useEffect( () => { + const dismissedErrors = getDismissedErrors() + const errorKey = loadingError?.interactionKey + + if ( ! loadingError?.interactionKey ) { + return + } + + if ( dismissedErrors.includes( errorKey ) ) { + setIsShowingError( false ) + } else { + setIsShowingError( true ) + } + }, [ loadingError ] ) + + // Interaction library can only be opened if the current interaction is not dirty. + useEffect( () => { + if ( ! isGutenberg ) { + return + } + + if ( selectedInteraction && isDirtyRef.current && interactionLibraryMode ) { + setInteractionLibraryMode( null ) + alert( __( 'You are currently editing an interaction, please save or discard your changes first.', 'interactions' ) )// eslint-disable-line no-alert + } + }, [ isGutenberg, selectedInteraction, isDirtyRef, interactionLibraryMode, setInteractionLibraryMode ] ) + + const { elementInteractions, pageInteractions } = interactions.reduce( ( acc, interaction ) => { + const interactionConfig = interactionsConfig[ interaction.type ] + if ( interactionConfig?.type === 'element' ) { + acc.elementInteractions.push( interaction ) + } else if ( interactionConfig?.type === 'page' ) { + acc.pageInteractions.push( interaction ) + } + return acc + }, { elementInteractions: [], pageInteractions: [] } ) + + const onOpenImportExportModal = props => { + setImportExportModalProps( props ) + } + + const onCloseImportExportModal = () => { + setImportExportModalProps( null ) + } + + return <> + { selectedInteraction === null && loadingError && isShowingError && + + setIsShowingError( false ) } + isDismissible={ false } + > +

{ loadingError.message }

+

{ __( 'Check the browser console for more details.', 'interactions' ) }

+
+ +
+
+
+ } + { allInteractions.length > 0 && selectedInteraction === null && + + { interactions.length > 0 &&

{ __( 'These interactions are on this page because of their location rules.', 'interactions' ) }

} + { interactions.length === 0 &&

{ __( 'There are no interactions on this page because no matches were found in the location rules.', 'interactions' ) }

} + +
+ } + { selectedInteraction === null && +
+ +

+ { __( 'Animate or trigger actions on any button, image, text or widget.', 'interactions' ) } +   + + { __( 'Learn more', 'interactions' ) } + +

+ +
+
+
+ { elementInteractions.map( interaction => { + return ( + { + setSelectedInteraction( interaction ) + } } + onDelete={ () => { + deleteInteraction( interaction.key ) + } } + /> + ) + } ) } + { ! elementInteractions.length && ( +
+ +

{ __( 'Define actions that occur when user interacts with elements on your page', 'interactions' ) }

+
+ ) } +
+
+
+ +

+ { __( 'Launch page-wide transitions, backgrounds or state-based effects.', 'interactions' ) } +   + + { __( 'Learn more', 'interactions' ) } + +

+ +
+
+
+ { pageInteractions.map( interaction => { + return ( + { + setSelectedInteraction( interaction ) + } } + onDelete={ () => { + deleteInteraction( interaction.key ) + } } + /> + ) + } ) } + { ! pageInteractions.length && ( +
+ +

{ __( 'Define actions that occur when there\'s a change in your page\'s state', 'interactions' ) }

+
+ ) } +
+
+ +
+ } + { selectedInteraction !== null && + { + return updateInteraction( newInteraction ).then( () => { + setEditMode( 'edit' ) + } ) + } } + onClose={ ( focusOnInteractionButton = false ) => { + if ( focusOnInteractionButton ) { + setTimeout( () => { + sidebarRef.current?.querySelector( `.interact-list__item-button--${ selectedInteraction.key }` )?.focus() + } ) + } + setSelectedInteraction( null ) + setEditMode( 'edit' ) + } } + onDelete={ () => deleteInteraction( selectedInteraction.key ) } + onDirtyChange={ isDirty => isDirtyRef.current = isDirty } + onOpenImportExportModal={ onOpenImportExportModal } + /> + } + { importExportModalProps && + + } + { isGutenberg && interactionLibraryMode && } + +} + +export default InteractionsApp diff --git a/src/editor/components/add-interaction-popover/index.js b/src/editor/components/add-interaction-popover/index.js index 0301258..74f3ed8 100644 --- a/src/editor/components/add-interaction-popover/index.js +++ b/src/editor/components/add-interaction-popover/index.js @@ -16,6 +16,10 @@ import { setBlockAnchorIfPossible, openInteractionsSidebar, } from '~interact/editor/util' +import { + getCurrentSelectedTarget, + isElementorEditor, +} from '~interact/editor/editors' import { cloneDeep, first } from 'lodash' import { @@ -56,21 +60,29 @@ const AddInteractionPopover = props => { const [ selected, setSelected ] = useState( initialSelected ) const [ showDescription, setShowDescription ] = useState( null ) const [ hidden, setHidden ] = useState( false ) + const isElementor = isElementorEditor() const { getBlockNamesByClientId, getSelectedBlockClientId, } = useSelect( select => { + const blockEditorStore = select( 'core/block-editor' ) return { - getBlockNamesByClientId: select( 'core/block-editor' ).getBlockNamesByClientId, - getSelectedBlockClientId: select( 'core/block-editor' ).getSelectedBlockClientId, + getBlockNamesByClientId: blockEditorStore?.getBlockNamesByClientId || ( () => [] ), + getSelectedBlockClientId: blockEditorStore?.getSelectedBlockClientId || ( () => null ), } } ) - const [ target, setTarget ] = useState( { - type: 'block', - value: getOrGenerateBlockAnchor( getSelectedBlockClientId(), false ) || '', - blockName: first( getBlockNamesByClientId( getSelectedBlockClientId() ) ) || '', + const [ target, setTarget ] = useState( () => { + const current = getCurrentSelectedTarget() + const clientId = getSelectedBlockClientId() + + return { + type: current?.type || ( isElementor ? 'selector' : 'block' ), + value: current?.value || getOrGenerateBlockAnchor( clientId, false ) || '', + blockName: current?.blockName || first( getBlockNamesByClientId( clientId ) ) || '', + options: current?.options || '', + } } ) const libraryTitle = ! showElementOption && showPageOption ? __( 'My Page Interactions', 'interactions' ) @@ -94,7 +106,7 @@ const AddInteractionPopover = props => { return acc }, { elementInteractions: [], pageInteractions: [] } ) - if ( hidden ) { + if ( hidden && ! isElementor ) { return ( { setHidden( true ) } + hasPickerPopover={ ! isElementor } + onBlockSelectClick={ () => { + if ( ! isElementor ) { + setHidden( true ) + } + } } /> ) } diff --git a/src/editor/components/import-export-modal/index.js b/src/editor/components/import-export-modal/index.js index e092f85..44727f7 100644 --- a/src/editor/components/import-export-modal/index.js +++ b/src/editor/components/import-export-modal/index.js @@ -6,6 +6,7 @@ * External deprendencies */ import { getOrGenerateBlockAnchor } from '~interact/editor/util' +import { getCurrentSelectedTarget } from '~interact/editor/editors' import { first } from 'lodash' /** @@ -52,9 +53,10 @@ const ImportExportModal = props => { getBlockNamesByClientId, getSelectedBlockClientId, } = useSelect( select => { + const blockEditorStore = select( 'core/block-editor' ) return { - getBlockNamesByClientId: select( 'core/block-editor' ).getBlockNamesByClientId, - getSelectedBlockClientId: select( 'core/block-editor' ).getSelectedBlockClientId, + getBlockNamesByClientId: blockEditorStore?.getBlockNamesByClientId || ( () => [] ), + getSelectedBlockClientId: blockEditorStore?.getSelectedBlockClientId || ( () => null ), } } ) @@ -83,9 +85,14 @@ const ImportExportModal = props => { target = null, } = data + const selectedTarget = getCurrentSelectedTarget() + if ( selectedTarget ) { + target = selectedTarget + } + // If the currently selected block is valid, overwrite the interaction trigger. const clientId = getSelectedBlockClientId() - if ( clientId ) { + if ( clientId && ! selectedTarget ) { target = { type: 'block', value: getOrGenerateBlockAnchor( clientId, true ) || '', diff --git a/src/editor/components/location-rules/index.js b/src/editor/components/location-rules/index.js index f9bb975..3bf05ba 100644 --- a/src/editor/components/location-rules/index.js +++ b/src/editor/components/location-rules/index.js @@ -9,12 +9,15 @@ import { import { Fragment, useEffect, useState, } from '@wordpress/element' -import { select } from '@wordpress/data' import { __, sprintf } from '@wordpress/i18n' import apiFetch from '@wordpress/api-fetch' +import { getCurrentEditorPostContext } from '~interact/editor/editors' const NOOP = () => {} +const getCurrentPostId = () => getCurrentEditorPostContext().postId +const getCurrentPostType = () => getCurrentEditorPostContext().postType + const updateLocation = ( locations, index1, index2, newLocation ) => { const newLocations = cloneDeep( locations ) newLocations[ index1 ][ index2 ] = newLocation @@ -94,7 +97,7 @@ const LocationRules = props => { onChange( removeLocation( locations, i, k ) ) } } onClickAnd={ () => { - const value = locations.length === 0 ? select( 'core/editor' ).getCurrentPostId() : '' + const value = locations.length === 0 ? getCurrentPostId() : '' onChange( addLocation( locations, i, k + 1, { param: 'post', operator: '==', @@ -111,7 +114,7 @@ const LocationRules = props => { label={ __( 'Add rule group', 'interactions' ) } variant="secondary" onClick={ () => { - const value = locations.length === 0 ? select( 'core/editor' ).getCurrentPostId() : '' + const value = locations.length === 0 ? getCurrentPostId() : '' onChange( addLocation( locations, locations.length, 0, { param: 'post', operator: '==', @@ -151,10 +154,10 @@ const LocationRule = props => { // If param is a post/page, then the post_id doesn't exist yet, then we need to add it near the top as "Current Post" or "Current Page" if ( param === 'post' || param === 'page' ) { - const postType = select( 'core/editor' ).getCurrentPostType() + const postType = getCurrentPostType() options.some( ( { post_type, options } ) => { if ( post_type === postType ) { - const currentPostId = select( 'core/editor' ).getCurrentPostId() + const currentPostId = getCurrentPostId() // Check if the current post is already in the list const exists = options.some( ( { value } ) => { return value === currentPostId diff --git a/src/editor/components/target-selector/index.js b/src/editor/components/target-selector/index.js index ca37d6b..7f4ba10 100644 --- a/src/editor/components/target-selector/index.js +++ b/src/editor/components/target-selector/index.js @@ -1,6 +1,11 @@ import TargetSVG from '~interact/editor/assets/target.svg' import { GridLayout, FlexLayout } from '~interact/editor/components' +import { + getSelectedBlockAnchor, + isElementorEditor, + startElementorElementPicker, +} from '~interact/editor/editors' import { getOrGenerateBlockAnchor, getOrGenerateBlockClass } from '~interact/editor/util' import { SelectControl, @@ -40,6 +45,9 @@ const TargetSelector = props => { const [ isPopoverOpen, setIsPopoverOpen ] = useState( false ) const [ buttonRef, setButtonRef ] = useState( null ) const prevValueRef = useRef( {} ) + const elementPickerStopRef = useRef( null ) + const isElementor = isElementorEditor() + const hasBlockEditor = !! select( 'core/block-editor' )?.getSelectedBlockClientId const targetButton = ( <> @@ -50,14 +58,24 @@ const TargetSelector = props => { ref={ setButtonRef } onClick={ () => { onBlockSelectClick() - if ( hasPickerPopover && ! isPopoverOpen ) { + if ( isElementor ) { + elementPickerStopRef.current?.() + elementPickerStopRef.current = startElementorElementPicker( { + targetType: value.type === 'class' ? 'class' : 'selector', + onPick: target => { + onChange( target ) + onBlockSelectDone() + }, + onCancel: onBlockSelectDone, + } ) + } else if ( hasPickerPopover && ! isPopoverOpen ) { setIsPopoverOpen( true ) } else if ( hasPickerPopover && isPopoverOpen ) { setIsPopoverOpen( false ) } } } /> - { hasPickerPopover && isPopoverOpen && ( + { hasPickerPopover && isPopoverOpen && ! isElementor && ( { targetOptions = targetOptions.filter( target => target.value !== 'trigger' ) } + if ( isElementor ) { + targetOptions = targetOptions.filter( target => + [ 'trigger', 'class', 'selector' ].includes( target.value ) + ) + } + + useEffect( () => { + return () => { + elementPickerStopRef.current?.() + } + }, [] ) + // Watch for warnings, we need to throttle this because we are subscribed to // the editor and changes can be fast. const [ targetWarning, setTargetWarning ] = useState( getTargetSelectorWarning( value.type, value.value ) ) @@ -176,7 +206,7 @@ const TargetSelector = props => { const newTarget = { ...value, type } // Use any previous values we may have already entered. - if ( type === 'block-name' ) { + if ( type === 'block-name' && hasBlockEditor ) { if ( prevValueRef.current[ type ] ) { newTarget.value = prevValueRef.current[ type ] } else { @@ -207,7 +237,7 @@ const TargetSelector = props => { className="interact-target-block-input" id="interact-target-block-input" label={ __( 'Block Anchor / ID', 'interactions' ) } - value={ value.value } + value={ value.value || ( isElementor ? '' : getSelectedBlockAnchor() || '' ) } // When typing, the previous blockName should be invalid onChange={ targetValue => onChange( { ...value, blockName: '', value: targetValue, diff --git a/src/editor/components/timeline/class-runner.js b/src/editor/components/timeline/class-runner.js index a06d812..d197467 100644 --- a/src/editor/components/timeline/class-runner.js +++ b/src/editor/components/timeline/class-runner.js @@ -1,6 +1,7 @@ import InteractRunner from '../../../frontend/scripts/class-runner' import { actions as actionsConfig, interactions as interactionsConfig } from 'interactions' import { getBlockClientId } from './with-tracked-anchors' +import { getEditorCanvasElement } from '~interact/editor/editors' const NOOP = () => {} @@ -48,12 +49,7 @@ class InteractEditorRunner extends InteractRunner { * @return {DOMElement} The document where the interactions are being previewed. */ getDocument() { - const iframe = document.querySelector( 'iframe[name="editor-canvas"]' ) - let editorEl = document.querySelector( '.editor-styles-wrapper' ) - if ( iframe ) { - editorEl = iframe.contentDocument.querySelector( '.editor-styles-wrapper' ) - } - return editorEl + return getEditorCanvasElement() } getTimelineType( interaction ) { diff --git a/src/editor/components/timeline/index.js b/src/editor/components/timeline/index.js index 0c04d38..ab84b81 100644 --- a/src/editor/components/timeline/index.js +++ b/src/editor/components/timeline/index.js @@ -1165,13 +1165,15 @@ const ActionDropGap = props => { const [ isHighlighted, setIsHighlighted ] = useState( false ) - const onDragOverHandler = () => { + const onDragOverHandler = ev => { + ev.preventDefault() setIsHighlighted( true ) } const onDragLeaveHandler = () => { setIsHighlighted( false ) } const onDragDropHandler = ev => { + ev.preventDefault() const actionKeyDrop = ev.dataTransfer.getData( 'text/plain' ) onDrop( actionKeyDrop ) setIsHighlighted( false ) @@ -1270,6 +1272,7 @@ const ActionItem = props => { } const onDragOverHandler = ev => { + ev.preventDefault() const rect = dragItemRef.current.getBoundingClientRect() if ( ev.clientY < rect.top + ( rect.height / 2 ) ) { setHighlightLocation( 'top' ) @@ -1283,6 +1286,7 @@ const ActionItem = props => { } const onDragDropHandler = ev => { + ev.preventDefault() const actionKeyDrop = ev.dataTransfer.getData( 'text/plain' ) onDrop( actionKeyDrop, highlightLocation ) setHighlightLocation( null ) diff --git a/src/editor/components/timeline/runner.js b/src/editor/components/timeline/runner.js index b2a23ac..39f4523 100644 --- a/src/editor/components/timeline/runner.js +++ b/src/editor/components/timeline/runner.js @@ -9,6 +9,7 @@ import { cloneDeep } from 'lodash' import { getBlockClientId } from './with-tracked-anchors' import { doAction } from '@wordpress/hooks' import { select } from '@wordpress/data' +import { getEditorMode } from '~interact/editor/editors' // Create the runner. const runner = new InteractEditorRunner() @@ -41,7 +42,7 @@ export const useTimelineRunnerRef = ( interaction, actions, timelineIndex ) => { const runnerRef = useRef( null ) const [ initialStyles, setInitialStyles ] = useState( '' ) - const renderingMode = select( 'core/editor' ).getRenderingMode() + const renderingMode = select( 'core/editor' )?.getRenderingMode?.() || getEditorMode() const prevRenderingMode = useRef( renderingMode ) // Initialize the runner diff --git a/src/editor/components/timeline/use-initial-style-tag.js b/src/editor/components/timeline/use-initial-style-tag.js index d5ce48f..19e6aa1 100644 --- a/src/editor/components/timeline/use-initial-style-tag.js +++ b/src/editor/components/timeline/use-initial-style-tag.js @@ -4,16 +4,9 @@ import { useEffect, useRef } from '@wordpress/element' import { debounce } from 'lodash' +import { getEditorCanvasElement } from '~interact/editor/editors' -// Gets the main editor element, either the iframe or the main document. -const getEditorEl = () => { - const iframe = document.querySelector( 'iframe[name="editor-canvas"]' ) - let editorEl = document.querySelector( '.editor-styles-wrapper' ) - if ( iframe ) { - editorEl = iframe.contentDocument.querySelector( '.editor-styles-wrapper' ) - } - return editorEl -} +const getEditorEl = () => getEditorCanvasElement() // Creates a style tag inside the editor to hold the initial interaction styles export const useInitialStyleTag = style => { diff --git a/src/editor/editor.js b/src/editor/editor.js index ede9876..8b9741c 100644 --- a/src/editor/editor.js +++ b/src/editor/editor.js @@ -1,453 +1,7 @@ -import IconSVG from './assets/icon.svg' -import ElementSVG from './assets/element.svg' -import PageSVG from './assets/page.svg' -import { - AddInteractionButton, - InteractionButton, - InteractionPanel, - ImportExportModal, -} from './components' -import { createNewInteraction, createNewAction } from './util' -import { useInteractions } from './hooks' -import { interactions as interactionsConfig, manageInteractionsUrl } from 'interactions' -import { InteractionLibrary } from './interaction-library' - -import { registerPlugin } from '@wordpress/plugins' -import { __ } from '@wordpress/i18n' -import { upload } from '@wordpress/icons' -import { - PanelBody, - Button, - BaseControl, - Notice, -} from '@wordpress/components' -import { - useState, - useCallback, - useRef, - useEffect, - createInterpolateElement, -} from '@wordpress/element' -import { useSelect, useDispatch } from '@wordpress/data' - import './plugins' -import useOnPostPreview from './use-on-post-save' - -const InteractionsEditor = () => { - // We need to to this for both, because one might be disabled. E.g. in - // WooCommerce, editSite is loaded and stops the sidebar from showing up. - const SideEditorPluginSidebar = window.wp.editSite?.PluginSidebar - const PostEditorPluginSidebar = window.wp.editPost?.PluginSidebar - - const SideBar = SideEditorPluginSidebar ? SideEditorPluginSidebar - : PostEditorPluginSidebar ? PostEditorPluginSidebar : null - - const selectedBlockAnchor = useSelect( select => { - const clientId = select( 'core/block-editor' ).getSelectedBlockClientId() - return clientId ? select( 'core/block-editor' ).getBlockAttributes( clientId )?.anchor : null - } ) - - const interactionLibraryMode = useSelect( select => - select( 'interact/interaction-library-modal' ).getMode(), - [] ) - // Interaction library open modal and set target function - const { - setMode: setInteractionLibraryMode, - } = useDispatch( 'interact/interaction-library-modal' ) - - const [ selectedInteraction, setSelectedInteraction ] = useState( null ) - const [ editPropsPassed, setEditPropsPassed ] = useState( {} ) - const [ editMode, setEditMode ] = useState( 'edit' ) - const [ isShowingError, setIsShowingError ] = useState( true ) - const [ importExportModalProps, setImportExportModalProps ] = useState( null ) - - const sidebarRef = useRef() - const isDirtyRef = useRef( false ) // This gets updated when the current interaction being edited is dirty. - - const { - interactions: allInteractions, - interactionsFiltered: interactions, - loadingError, - updateInteraction, - deleteInteraction, - } = useInteractions() - - // This listens to the post preview button and publish button and asks the - // user to save the interaction if it's dirty. - const onPostSaveCallback = proceedSaveCallback => { - if ( isDirtyRef.current ) { - // eslint-disable-next-line no-alert - if ( confirm( __( 'You have unsaved changes in your interaction. Do you want to save it before continuing?', 'interactions' ) ) ) { - // Save the interaction, give the callback as the detail. - window?.dispatchEvent( new CustomEvent( 'interact/save-interaction', { - detail: { - // This callback will be called after the interaction is saved. - callback: proceedSaveCallback, - }, - } ) ) - // Return true to stop the preview. - return true - } - } - } - useOnPostPreview( onPostSaveCallback ) - - const getInteractionFromKey = useCallback( key => { - return allInteractions.find( interaction => interaction.key === key ) - }, [ allInteractions ] ) - - const onAddInteractionHandler = useCallback( ( interactionType, target = null, props = {} ) => { - if ( selectedInteraction && isDirtyRef.current ) { - alert( __( 'You are currently editing an interaction, please save or discard your changes first.', 'interactions' ) )// eslint-disable-line no-alert - return - } - setEditMode( 'new' ) - const newInteraction = createNewInteraction( interactionType, target, props ) - setSelectedInteraction( newInteraction ) - }, [ selectedInteraction ] ) - - const onEditInteractionHandler = useCallback( ( keyOrInteraction, editProps ) => { - if ( selectedInteraction && isDirtyRef.current ) { - alert( __( 'You are currently editing an interaction, please save or discard your changes first.', 'interactions' ) )// eslint-disable-line no-alert - return - } - // If editMode is provided (e.g. when duplicating), set the editMode state accordingly - if ( typeof editProps.editMode !== 'undefined' ) { - setEditMode( editProps.editMode ) - } - setEditPropsPassed( editProps ) - setSelectedInteraction( typeof keyOrInteraction === 'string' ? getInteractionFromKey( keyOrInteraction ) : keyOrInteraction ) - }, [ getInteractionFromKey, selectedInteraction ] ) - - // Listen to external adds of interactions from the main toolbar button. - useEffect( () => { - const onAddInteractionEventHandler = event => { - onAddInteractionHandler( event.detail.type, event.detail.target, event.detail.props ) - } - const onEditInteractionEventHandler = event => { - const { - key, interaction, ...editProps - } = event.detail - onEditInteractionHandler( key || interaction, editProps ) - } - - window?.addEventListener( 'interact/add-interaction', onAddInteractionEventHandler ) - window?.addEventListener( 'interact/edit-interaction', onEditInteractionEventHandler ) - - return () => { - window?.removeEventListener( 'interact/add-interaction', onAddInteractionEventHandler ) - window?.removeEventListener( 'interact/edit-interaction', onEditInteractionEventHandler ) - } - }, [ onAddInteractionHandler, onEditInteractionHandler ] ) - - useEffect( () => { - if ( ! selectedInteraction ) { - setEditPropsPassed( {} ) - } - }, [ selectedInteraction ] ) - - useEffect( () => { - const dismissedErrors = JSON.parse( localStorage.getItem( 'interact-dismissed-errors' ) || '[]' ) - const errorKey = loadingError?.interactionKey - - if ( ! loadingError?.interactionKey ) { - return - } - - if ( dismissedErrors.includes( errorKey ) ) { - setIsShowingError( false ) - } else { - setIsShowingError( true ) - } - }, [ loadingError ] ) - - // Interaction library can only be opened if the current interaction is not dirty. - useEffect( () => { - if ( selectedInteraction && isDirtyRef.current && interactionLibraryMode ) { - setInteractionLibraryMode( null ) - alert( __( 'You are currently editing an interaction, please save or discard your changes first.', 'interactions' ) )// eslint-disable-line no-alert - } - }, [ selectedInteraction, isDirtyRef, interactionLibraryMode, setInteractionLibraryMode ] ) - - const { elementInteractions, pageInteractions } = interactions - // Sort alphabetically by title - // .sort( ( a, b ) => { - // if ( a.title < b.title ) { - // return -1 - // } - // if ( a.title > b.title ) { - // return 1 - // } - // return 0 - // } ) - .reduce( ( acc, interaction ) => { - const interactionConfig = interactionsConfig[ interaction.type ] - if ( interactionConfig?.type === 'element' ) { - acc.elementInteractions.push( interaction ) - } else if ( interactionConfig?.type === 'page' ) { - acc.pageInteractions.push( interaction ) - } - return acc - }, { elementInteractions: [], pageInteractions: [] } ) - - const onOpenImportExportModal = props => { - setImportExportModalProps( props ) - } - - const onCloseImportExportModal = () => { - setImportExportModalProps( null ) - } - - // If the sidebar is not available (like in the Widgets editor), then do nothing. - if ( ! SideBar ) { - return null - } - - return <> - } - > - { selectedInteraction === null && loadingError && isShowingError && - - setIsShowingError( false ) } - isDismissible={ false } - > -

{ loadingError.message }

-

{ __( 'Check the browser console for more details.', 'interactions' ) }

-
- -
-
-
- } - { allInteractions.length > 0 && selectedInteraction === null && - - { interactions.length > 0 &&

{ __( 'These interactions are on this page because of their location rules.', 'interactions' ) }

} - { interactions.length === 0 &&

{ __( 'There are no interactions on this page because no matches were found in the location rules.', 'interactions' ) }

} - -
- } - { selectedInteraction === null && -
- -

- { __( 'Animate or trigger actions on any button, image, text or widget.', 'interactions' ) } -   - - { __( 'Learn more', 'interactions' ) } - -

- -
-
-
- { elementInteractions - .map( interaction => { - return ( - { - setSelectedInteraction( interaction ) - } } - onDelete={ () => { - deleteInteraction( interaction.key ) - } } - /> - ) - } ) } - { ! elementInteractions.length && ( -
- -

{ __( 'Define actions that occur when user interacts with elements on your page', 'interactions' ) }

-
- ) } -
-
- - - -

- { __( 'Launch page‑wide transitions, backgrounds or state‑based effects.', 'interactions' ) } -   - - { __( 'Learn more', 'interactions' ) } - -

- -
-
-
- { pageInteractions - .map( interaction => { - return ( - { - setSelectedInteraction( interaction ) - } } - onDelete={ () => { - deleteInteraction( interaction.key ) - } } - /> - ) - } ) } - { ! pageInteractions.length && ( -
- -

{ __( 'Define actions that occur when there\'s a change in your page\'s state', 'interactions' ) }

-
- ) } -
-
- - { /* - - */ } -
- } - { selectedInteraction !== null && - { - return updateInteraction( newInteraction ).then( () => { - setEditMode( 'edit' ) - } ) - } } - onClose={ ( focusOnInteractionButton = false ) => { - if ( focusOnInteractionButton ) { - // Focus on the previous interaction button so we can go back to it. - setTimeout( () => { - sidebarRef.current?.querySelector( `.interact-list__item-button--${ selectedInteraction.key }` )?.focus() - } ) - } - setSelectedInteraction( null ) - setEditMode( 'edit' ) - } } - onDelete={ () => deleteInteraction( selectedInteraction.key ) } - onDirtyChange={ isDirty => isDirtyRef.current = isDirty } - onOpenImportExportModal={ onOpenImportExportModal } - /> - } - { importExportModalProps && - - } - - { /* Render the Interaction Library modal in the root editor component */ - interactionLibraryMode && - } - -} +import { getInteractionsEditor } from './editors' +import { domReady } from '~interact/shared/dom-ready.js' -registerPlugin( 'interact-editor', { - render: InteractionsEditor, +domReady( () => { + getInteractionsEditor().init() } ) diff --git a/src/editor/editor.php b/src/editor/editor.php index a964602..a505bd6 100644 --- a/src/editor/editor.php +++ b/src/editor/editor.php @@ -18,17 +18,45 @@ class Interact_Editor { */ function __construct() { if ( is_admin() ) { - add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_editor' ) ); + add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_gutenberg_editor' ) ); add_action( 'enqueue_block_assets', array( $this, 'enqueue_assets' ) ); } + add_action( 'elementor/editor/after_enqueue_scripts', array( $this, 'enqueue_elementor_editor' ) ); + } + + /** + * Loads the editor script inside the Gutenberg editor. + * + * @return void + */ + public function enqueue_gutenberg_editor() { + $this->enqueue_editor( 'gutenberg' ); + } + + /** + * Loads the editor script inside the Elementor editor. + * + * @return void + */ + public function enqueue_elementor_editor() { + wp_enqueue_style( + 'interact-editor-wp-components-scoped', + plugins_url( 'dist/wp-components-scoped.css', INTERACT_FILE ), + array(), + INTERACT_VERSION + ); + + $this->enqueue_editor( 'elementor' ); } /** * Loads the editor script. * + * @param string $editor_mode Current editor mode. + * * @return void */ - public function enqueue_editor() { + public function enqueue_editor( $editor_mode = 'gutenberg' ) { // Load the required interaciton and action types. interact_require_types(); @@ -63,6 +91,7 @@ public function enqueue_editor() { [ $actions, $action_categories ] = $this->get_action_types_config(); global $wp_version; + $post = get_post(); $args = apply_filters( 'interact/localize_script', array( 'interactions' => $interactions, 'interactionCategories' => $interaction_categories, @@ -77,6 +106,14 @@ public function enqueue_editor() { 'restNonce' => wp_create_nonce( 'wp_rest' ), // This needs to be 'wp_rest' to use the built-in nonce verification. 'srcUrl' => untrailingslashit( plugins_url( '/', INTERACT_FILE ) ), 'currentUserCanUnfilteredHtml' => current_user_can( 'unfiltered_html' ), + // Keep the current editor and document context available to the + // shared editor app so integrations can resolve targets and + // location rules correctly. + 'editorMode' => $editor_mode, + 'currentPostId' => $post ? (int) $post->ID : 0, + 'currentPostType' => $post ? $post->post_type : '', + 'currentPostTemplate' => $post ? get_page_template_slug( $post->ID ) : '', + 'currentPostParent' => $post ? (int) $post->post_parent : 0, ) ); wp_localize_script( 'interact-editor', 'interactions', $args ); } diff --git a/src/editor/editor.scss b/src/editor/editor.scss index a07a736..0d3ad7c 100644 --- a/src/editor/editor.scss +++ b/src/editor/editor.scss @@ -139,6 +139,86 @@ --wp-components-color-accent: #05f; } +/* Interaction Elementor Editor Panel Styles */ + +.interact-elementor-launcher { + position: fixed !important; + right: 32px; + bottom: 32px; + z-index: 100000; + border-radius: 999px !important; + box-shadow: 0 16px 40px rgba(0, 0, 0, 0.18); +} + +.interact-elementor-panel { + position: fixed; + top: 0; + right: 0; + bottom: 0; + width: 280px; + background: #fff; + color: #1e1e1e; + line-height: 18px; + box-shadow: -24px 0 48px rgba(15, 23, 42, 0.18); + transform: translateX(100%); + transition: transform 180ms ease; + z-index: 99999; + display: flex; + flex-direction: column; + + h2 { + font-size: 13px; + margin: 1.33em; + } + + p { + margin: 1em 0; + } +} + +.interact-elementor-panel.is-open { + transform: translateX(0); +} + +.interact-elementor-panel__header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 16px 18px; + border-bottom: 1px solid #e5e7eb; + background: #f8fafc; +} + +.interact-elementor-panel__title { + display: flex; + align-items: center; + gap: 8px; + font-weight: 600; +} + +.interact-elementor-panel__body { + flex: 1; + overflow: auto; +} + +.interact-elementor-sidebar { + min-height: 100%; +} + +.interact-popover { + color: #3c434a; + line-height: 1.4em; + + h2 { + font-size: 13px; + margin: 1.33em; + } + + p { + margin: 1em 0; + } +} + /* Wordpress 7.0 compatibility */ .interact-sidebar, .interact-popover { @@ -160,4 +240,4 @@ .interact-property-control .components-base-control__field { margin-bottom: 8px; } -} \ No newline at end of file +} diff --git a/src/editor/editors/abstract.js b/src/editor/editors/abstract.js new file mode 100644 index 0000000..e8e5052 --- /dev/null +++ b/src/editor/editors/abstract.js @@ -0,0 +1,87 @@ +import { + currentPostId, + currentPostParent, + currentPostTemplate, + currentPostType, +} from 'interactions' +import { select } from '@wordpress/data' + +const NOOP = () => {} + +// Base editor adapter that defines the shared editor contract. +class InteractionsEditorAbstract { + constructor() { + this.initialized = false + } + + // Boot the current editor integration. + init() { + this.initialized = true + return this + } + + // Return the current editor mode. + getEditorMode() { + throw new Error( 'InteractionsEditorAbstract#getEditorMode must be implemented.' ) + } + + isElementor() { + return this.getEditorMode() === 'elementor' + } + + isGutenberg() { + return ! this.isElementor() + } + + // Return the current document context for location rule matching. + getCurrentPostContext() { + const editorStore = select( 'core/editor' ) + return { + postId: editorStore?.getCurrentPostId?.() || currentPostId || 0, + postType: editorStore?.getCurrentPostType?.() || currentPostType || '', + postTemplate: editorStore?.getCurrentPost?.()?.template || currentPostTemplate || '', + postParent: editorStore?.getCurrentPost?.()?.parent || currentPostParent || 0, + } + } + + getCanvasDocument() { + return document + } + + getCanvasElement() { + const canvasDocument = this.getCanvasDocument() + return canvasDocument?.querySelector( '.editor-styles-wrapper' ) || canvasDocument?.body || document.body + } + + // Open the editor panel when supported by the current integration. + openPanel() { + return null + } + + openInteractionsPanel() { + return this.openPanel() + } + + getSelectedBlockAnchor() { + return null + } + + getCurrentSelectedTarget() { + return null + } + + registerSelectionTracking() { + return NOOP + } + + // Start an editor-specific target picker. + startElementPicker( args = {} ) { + const { + onCancel = NOOP, + } = args + onCancel() + return NOOP + } +} + +export default InteractionsEditorAbstract diff --git a/src/editor/editors/elementor.js b/src/editor/editors/elementor.js new file mode 100644 index 0000000..f8097c4 --- /dev/null +++ b/src/editor/editors/elementor.js @@ -0,0 +1,277 @@ +import IconSVG from '../assets/icon.svg' +import InteractionsApp from '../app' +import InteractionsEditorAbstract from './abstract' + +import { __ } from '@wordpress/i18n' +import { Button } from '@wordpress/components' +import { + useEffect, + useState, + createRoot, +} from '@wordpress/element' + +const NOOP = () => {} + +// Elementor editor adapter. +class ElementorInteractionsEditor extends InteractionsEditorAbstract { + constructor() { + super() + this.selectedElement = null + } + + getEditorMode() { + return 'elementor' + } + + // Mount the Elementor launcher and side panel shell. + init() { + if ( this.initialized ) { + return this + } + + const mountNodeId = 'interact-elementor-root' + if ( document.getElementById( mountNodeId ) ) { + return super.init() + } + + const ElementorInteractionsEditorComponent = () => { + const [ isOpen, setIsOpen ] = useState( false ) + + useEffect( () => { + const openHandler = () => setIsOpen( true ) + window.addEventListener( 'interact/open-elementor-sidebar', openHandler ) + return () => window.removeEventListener( 'interact/open-elementor-sidebar', openHandler ) + }, [] ) + + return ( + <> + + { /* { isOpen && ( +
setIsOpen( false ) } + aria-hidden="true" + /> + ) } */ } +
+
+
+ + { __( 'Interactions', 'interactions' ) } +
+
+
+
+ +
+
+
+ + ) + } + + const mountNode = document.createElement( 'div' ) + mountNode.id = mountNodeId + document.body.appendChild( mountNode ) + this.registerSelectionTracking() + createRoot( mountNode ).render( ) + + return super.init() + } + + // Return the Elementor preview canvas document. + getCanvasDocument() { + const iframe = document.querySelector( '#elementor-preview-iframe' ) + return iframe?.contentDocument || null + } + + // Open the Interactions sidebar in Elementor. + openPanel() { + window.dispatchEvent( new CustomEvent( 'interact/open-elementor-sidebar' ) ) + return null + } + + // Build an interaction target from a selected Elementor element. + buildTargetFromElement( element, targetType = 'selector' ) { + if ( ! element ) { + return null + } + + const targetElement = element.closest( '.elementor-element[data-id]' ) + if ( ! targetElement ) { + return null + } + + const elementId = targetElement.getAttribute( 'data-id' ) + if ( ! elementId ) { + return null + } + + const elementType = targetElement.getAttribute( 'data-element_type' ) || '' + const widgetType = targetElement.getAttribute( 'data-widget_type' ) || '' + const label = widgetType || elementType || 'elementor-element' + const wrapperSelector = `.elementor-element.elementor-element-${ elementId }` + const classValue = `elementor-element-${ elementId }` + const targetValue = targetType === 'class' + ? classValue + : elementType === 'widget' + ? `${ wrapperSelector } > *` + : wrapperSelector + + return { + type: targetType, + value: targetValue, + blockName: label, + } + } + + getHighlightElement( element ) { + if ( ! element ) { + return null + } + + const targetElement = element.closest( '.elementor-element[data-id]' ) + if ( ! targetElement ) { + return null + } + + const elementType = targetElement.getAttribute( 'data-element_type' ) || '' + if ( elementType !== 'widget' ) { + return targetElement + } + + return targetElement.firstElementChild || targetElement + } + + // Return the currently selected Elementor target. + getCurrentSelectedTarget() { + return this.buildTargetFromElement( this.selectedElement?.element || null ) + } + + // Track the current Elementor selection from the editor panel. + registerSelectionTracking() { + if ( ! window.elementor?.hooks?.addAction ) { + return NOOP + } + + const register = action => { + window.elementor.hooks.addAction( action, ( panel, model, view ) => { + this.selectedElement = { + model, + view, + element: view?.$el?.get?.( 0 ) || null, + } + } ) + } + + const actions = [ + 'panel/open_editor/section', + 'panel/open_editor/column', + 'panel/open_editor/container', + 'panel/open_editor/widget', + ] + actions.forEach( register ) + + return NOOP + } + + // Start an Elementor preview picker for selector or class targets. + startElementPicker( { + targetType = 'selector', + onPick = NOOP, + onCancel = NOOP, + } = {} ) { + const previewDocument = this.getCanvasDocument() + if ( ! previewDocument ) { + onCancel() + return NOOP + } + + let highlightedElement = null + + // Restore the previously highlighted element back to its original outline. + const clearHighlight = () => { + if ( highlightedElement ) { + highlightedElement.style.outline = highlightedElement.dataset.interactPrevOutline || '' + highlightedElement.style.outlineOffset = highlightedElement.dataset.interactPrevOutlineOffset || '' + delete highlightedElement.dataset.interactPrevOutline + delete highlightedElement.dataset.interactPrevOutlineOffset + } + highlightedElement = null + } + + // Follow the pointer inside the preview and visually mark the current pick candidate. + const mouseMoveHandler = event => { + const candidate = event.target.closest( '.elementor-element[data-id]' ) + const highlightCandidate = this.getHighlightElement( candidate ) + if ( highlightCandidate === highlightedElement ) { + return + } + clearHighlight() + if ( highlightCandidate ) { + highlightedElement = highlightCandidate + highlightedElement.dataset.interactPrevOutline = highlightedElement.style.outline || '' + highlightedElement.dataset.interactPrevOutlineOffset = highlightedElement.style.outlineOffset || '' + highlightedElement.style.outline = '2px solid #05f' + highlightedElement.style.outlineOffset = '2px' + } + } + + // Convert the clicked Elementor element into an interaction target and stop pick mode. + const clickHandler = event => { + const candidate = event.target.closest( '.elementor-element[data-id]' ) + if ( ! candidate ) { + return + } + event.preventDefault() + event.stopPropagation() + const target = this.buildTargetFromElement( candidate, targetType ) + stop() + if ( target ) { + onPick( target ) + } else { + onCancel() + } + } + + // Allow canceling the picker with Escape. + const keyHandler = event => { + if ( event.key === 'Escape' ) { + stop() + onCancel() + } + } + + // Remove all temporary picker listeners and preview highlighting. + const stop = () => { + clearHighlight() + previewDocument.removeEventListener( 'mousemove', mouseMoveHandler, true ) + previewDocument.removeEventListener( 'click', clickHandler, true ) + previewDocument.removeEventListener( 'keydown', keyHandler, true ) + document.removeEventListener( 'keydown', keyHandler, true ) + } + + previewDocument.addEventListener( 'mousemove', mouseMoveHandler, true ) + previewDocument.addEventListener( 'click', clickHandler, true ) + previewDocument.addEventListener( 'keydown', keyHandler, true ) + document.addEventListener( 'keydown', keyHandler, true ) + + return stop + } +} + +export default ElementorInteractionsEditor diff --git a/src/editor/editors/gutenberg.js b/src/editor/editors/gutenberg.js new file mode 100644 index 0000000..4edf85d --- /dev/null +++ b/src/editor/editors/gutenberg.js @@ -0,0 +1,119 @@ +import IconSVG from '../assets/icon.svg' +import InteractionsApp from '../app' +import InteractionsEditorAbstract from './abstract' + +import { registerPlugin } from '@wordpress/plugins' +import { __ } from '@wordpress/i18n' +import { + useSelect, + dispatch, + select, +} from '@wordpress/data' + +// Gutenberg editor adapter. +class GutenbergInteractionsEditor extends InteractionsEditorAbstract { + getEditorMode() { + return 'gutenberg' + } + + // Register the Gutenberg sidebar plugin. + init() { + if ( this.initialized ) { + return this + } + + const GutenbergInteractionsEditorComponent = () => { + const SideEditorPluginSidebar = window.wp.editSite?.PluginSidebar + const PostEditorPluginSidebar = window.wp.editPost?.PluginSidebar + const SideBar = SideEditorPluginSidebar ? SideEditorPluginSidebar + : PostEditorPluginSidebar ? PostEditorPluginSidebar : null + + const selectedBlockAnchor = useSelect( select => { + const clientId = select( 'core/block-editor' )?.getSelectedBlockClientId?.() + return clientId ? select( 'core/block-editor' ).getBlockAttributes( clientId )?.anchor : null + }, [] ) + + if ( ! SideBar ) { + return null + } + + return ( + } + > + + + ) + } + + registerPlugin( 'interact-editor', { + render: GutenbergInteractionsEditorComponent, + } ) + + return super.init() + } + + // Return the Gutenberg editor canvas document. + getCanvasDocument() { + const iframe = document.querySelector( 'iframe[name="editor-canvas"]' ) + return iframe?.contentDocument || document + } + + // Open the Interactions sidebar in Gutenberg. + openPanel() { + if ( dispatch( 'core/edit-post' ) ) { + return dispatch( 'core/edit-post' ).openGeneralSidebar( 'interact-editor/sidebar' ) + } + return dispatch( 'core/edit-site' ).openGeneralSidebar( 'interact-editor/sidebar' ) + } + + // Return the currently selected block anchor. + getSelectedBlockAnchor() { + const blockEditorStore = select( 'core/block-editor' ) + if ( ! blockEditorStore?.getSelectedBlockClientId ) { + return null + } + const clientId = blockEditorStore.getSelectedBlockClientId() + return clientId ? blockEditorStore.getBlockAttributes( clientId )?.anchor : null + } + + // Return the current Gutenberg selection as an interaction target. + getCurrentSelectedTarget() { + const blockEditorStore = select( 'core/block-editor' ) + const clientId = blockEditorStore?.getSelectedBlockClientId?.() + if ( ! clientId ) { + return null + } + + const block = blockEditorStore.getBlock?.( clientId ) + if ( ! block ) { + return null + } + + const hasAnchorAttribute = !! select( 'core/blocks' ).getBlockType( block.name )?.attributes?.anchor + if ( hasAnchorAttribute ) { + return { + type: 'block', + value: this.getSelectedBlockAnchor() || '', + blockName: block.name || '', + options: { clientId }, + } + } + + const className = block.attributes?.className?.split( ' ' )?.[ 0 ] || '' + return { + type: 'class', + value: className, + blockName: block.name || '', + options: { clientId }, + } + } +} + +export default GutenbergInteractionsEditor diff --git a/src/editor/editors/index.js b/src/editor/editors/index.js new file mode 100644 index 0000000..259a301 --- /dev/null +++ b/src/editor/editors/index.js @@ -0,0 +1,42 @@ +import { editorMode } from 'interactions' +import GutenbergInteractionsEditor from './gutenberg' +import ElementorInteractionsEditor from './elementor' + +let activeEditor = null + +// Create the active editor adapter for the current editor environment. +const createInteractionsEditor = () => { + return editorMode === 'elementor' + ? new ElementorInteractionsEditor() + : new GutenbergInteractionsEditor() +} + +// Return the memoized editor adapter instance. +export const getInteractionsEditor = () => { + if ( ! activeEditor ) { + activeEditor = createInteractionsEditor() + } + return activeEditor +} + +export const getEditorMode = () => getInteractionsEditor().getEditorMode() + +export const isElementorEditor = () => getInteractionsEditor().isElementor() + +export const isGutenbergEditor = () => getInteractionsEditor().isGutenberg() + +export const getCurrentEditorPostContext = () => getInteractionsEditor().getCurrentPostContext() + +export const getSelectedBlockAnchor = () => getInteractionsEditor().getSelectedBlockAnchor() + +export const getEditorCanvasDocument = () => getInteractionsEditor().getCanvasDocument() + +export const getEditorCanvasElement = () => getInteractionsEditor().getCanvasElement() + +export const openInteractionsSidebar = () => getInteractionsEditor().openInteractionsPanel() + +export const getCurrentSelectedTarget = () => getInteractionsEditor().getCurrentSelectedTarget() + +export const registerElementorSelectionTracking = () => getInteractionsEditor().registerSelectionTracking() + +export const startElementorElementPicker = args => getInteractionsEditor().startElementPicker( args ) diff --git a/src/editor/hooks/use-interactions.js b/src/editor/hooks/use-interactions.js index 10d6c85..553e80e 100644 --- a/src/editor/hooks/use-interactions.js +++ b/src/editor/hooks/use-interactions.js @@ -10,6 +10,7 @@ import { domReady } from '~interact/shared/dom-ready.js' import apiFetch from '@wordpress/api-fetch' import { __ } from '@wordpress/i18n' import { ensureInteractionDefaults } from '../util' +import { getCurrentEditorPostContext, getEditorMode } from '~interact/editor/editors' const DEFAULT_STATE = { interactions: [], @@ -92,16 +93,12 @@ register( createReduxStore( 'interact/interactions', { * Whether or not the interaction should be shown in the editor based on what's * currently beign edited in the Block Editor. * - * @param {Array} interaction - * @param {Object} select wp.data.select + * @param {Array} interaction * * @return {boolean} Whether or not the interaction should be shown in the editor. */ -export const isInteractionShown = ( interaction, select ) => { - // If the editor is not available (e.g. in Widgets editor), don't do anything. - if ( ! select( 'core/editor' ) ) { - return false - } +export const isInteractionShown = interaction => { + const currentContext = getCurrentEditorPostContext() return interaction.locations.some( locationGroup => { return locationGroup.every( location => { const { @@ -113,15 +110,15 @@ export const isInteractionShown = ( interaction, select ) => { case 'page': { // If blank, then it's all posts/pages. if ( ! value || isNaN( +value ) ) { - const postType = select( 'core/editor' ).getCurrentPostType() + const postType = currentContext.postType const postTypeParam = value || param return operator === '==' ? postType === postTypeParam : postType !== postTypeParam } - const match = value.toString() === select( 'core/editor' ).getCurrentPostId()?.toString() + const match = value.toString() === currentContext.postId?.toString() return operator === '==' ? match : ! match } case 'post_type': { - const match = value.toString() === select( 'core/editor' ).getCurrentPostType()?.toString() + const match = value.toString() === currentContext.postType?.toString() return operator === '==' ? match : ! match } case 'post_status': @@ -131,20 +128,20 @@ export const isInteractionShown = ( interaction, select ) => { return true case 'post_template': case 'page_template': { - const match = value.toString() === select( 'core/editor' ).getCurrentPost()?.template.toString() + const match = value.toString() === currentContext.postTemplate?.toString() return operator === '==' ? match : ! match } case 'post_parent': case 'page_parent': { - const match = value.toString() === select( 'core/editor' ).getCurrentPost()?.parent.toString() + const match = value.toString() === currentContext.postParent?.toString() return operator === '==' ? match : ! match } case 'all': // Entire website return true case 'wp_template': // Site editor templates: home, 404, etc - const currentPostType = select( 'core/editor' ).getCurrentPostType() + const currentPostType = currentContext.postType if ( currentPostType === 'wp_template' ) { - const match = value.toString() === select( 'core/editor' ).getCurrentPostId()?.toString() + const match = value.toString() === currentContext.postId?.toString() return operator === '==' ? match : ! match } break @@ -177,7 +174,7 @@ const useInteractions = () => { const updateInteraction = newInteraction => { // Check if we updated any anchors/attributes, if we did, then we need to ask whether to also update the post. const didModifyPostContent = select( 'interact/interactions' ).didModifyPostContent() - if ( didModifyPostContent ) { + if ( didModifyPostContent && getEditorMode() !== 'elementor' ) { if ( confirm( __( 'Some block anchors have been updated for your interactions to work correctly. Do you want to save these post changes? (Any modified synced patterns will also be saved)', 'interactions' ) ) ) { // eslint-disable-line no-alert dispatch( 'interact/interactions' ).setDidModifyPostContent( false ) // Save the post. @@ -244,7 +241,7 @@ const useInteractions = () => { } const interactions = select( 'interact/interactions' ).getInteractions() - const interactionsFiltered = interactions.filter( interaction => isInteractionShown( interaction, select ) ) + const interactionsFiltered = interactions.filter( interaction => isInteractionShown( interaction ) ) return { interactions, diff --git a/src/editor/plugins/index.js b/src/editor/plugins/index.js index c448b35..1039a02 100644 --- a/src/editor/plugins/index.js +++ b/src/editor/plugins/index.js @@ -1,4 +1,8 @@ -import './block-toolbar-button' -import './top-toolbar-button' -import './block-highlight' -import './block-select' +import { editorMode } from 'interactions' + +if ( editorMode !== 'elementor' ) { + require( './block-toolbar-button' ) + require( './top-toolbar-button' ) + require( './block-highlight' ) + require( './block-select' ) +} diff --git a/src/editor/util/index.js b/src/editor/util/index.js index d34bf05..c2356e5 100644 --- a/src/editor/util/index.js +++ b/src/editor/util/index.js @@ -6,6 +6,10 @@ import { import { select, dispatch } from '@wordpress/data' import { sprintf, __ } from '@wordpress/i18n' import { addClientIdAnchorPair } from '../components/timeline/with-tracked-anchors' +import { + getCurrentEditorPostContext, + openInteractionsSidebar, +} from '~interact/editor/editors' const getUniqueTitle = title => { const interactions = select( 'interact/interactions' ).getInteractions() @@ -52,12 +56,17 @@ const getBlockNameFromAnchor = anchor => { // Returns the current page export const getLocationForCurrentPage = () => { - const currentPostType = select( 'core/editor' ).getCurrentPostType() + const { + postId, + postType, + } = getCurrentEditorPostContext() + + const currentPostType = postType let locationParam = currentPostType === 'page' ? 'page' : currentPostType === 'wp_template' ? 'wp_template' // Site editor templates : !! currentPostType ? 'post' : null - let locationValue = select( 'core/editor' ).getCurrentPostId() + let locationValue = postId if ( ! locationParam ) { locationParam = 'all' @@ -382,14 +391,4 @@ export const getOrGenerateBlockClass = ( clientId, updateAttribute = true ) => { return className } -/** - * Utility function to open the Interactions sidebar. - * - * @return {Object} Dispatch action object - */ -export const openInteractionsSidebar = () => { - if ( dispatch( 'core/edit-post' ) ) { - return dispatch( 'core/edit-post' ).openGeneralSidebar( 'interact-editor/sidebar' ) - } - return dispatch( 'core/edit-site' ).openGeneralSidebar( 'interact-editor/sidebar' ) -} +export { openInteractionsSidebar }