From 32c6fb59de62edf2c92f873b71a5065495c33568 Mon Sep 17 00:00:00 2001 From: Shekhar Wagh Date: Mon, 3 Feb 2025 18:52:22 +0530 Subject: [PATCH 01/16] v0.8.0 (#351) --- remote-data-blocks.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/remote-data-blocks.php b/remote-data-blocks.php index 8601c472..996feaf1 100644 --- a/remote-data-blocks.php +++ b/remote-data-blocks.php @@ -7,7 +7,7 @@ * Author: WPVIP * Author URI: https://wpvip.com * Text Domain: remote-data-blocks - * Version: 0.7.3 + * Version: 0.8.0 * Requires at least: 6.7 * Requires PHP: 8.1 */ @@ -18,7 +18,7 @@ define( 'REMOTE_DATA_BLOCKS__PLUGIN_ROOT', __FILE__ ); define( 'REMOTE_DATA_BLOCKS__PLUGIN_DIRECTORY', untrailingslashit( plugin_dir_path( __FILE__ ) ) ); -define( 'REMOTE_DATA_BLOCKS__PLUGIN_VERSION', '0.7.3' ); +define( 'REMOTE_DATA_BLOCKS__PLUGIN_VERSION', '0.8.0' ); define( 'REMOTE_DATA_BLOCKS__REST_NAMESPACE', 'remote-data-blocks/v1' ); From 9178ccd67e3767530783448e19981e8e972bf15d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:21:13 -0500 Subject: [PATCH 02/16] Bump the wordpress group across 1 directory with 24 updates (#344) Bumps the wordpress group with 24 updates in the / directory: | Package | From | To | | --- | --- | --- | | [@wordpress/dataviews](https://github.com/WordPress/gutenberg/tree/HEAD/packages/dataviews) | `4.10.0` | `4.13.0` | | [@wordpress/api-fetch](https://github.com/WordPress/gutenberg/tree/HEAD/packages/api-fetch) | `7.14.0` | `7.17.0` | | [@wordpress/block-editor](https://github.com/WordPress/gutenberg/tree/HEAD/packages/block-editor) | `14.9.0` | `14.12.0` | | [@wordpress/blocks](https://github.com/WordPress/gutenberg/tree/HEAD/packages/blocks) | `14.3.0` | `14.6.0` | | [@wordpress/components](https://github.com/WordPress/gutenberg/tree/HEAD/packages/components) | `29.0.0` | `29.3.0` | | [@wordpress/compose](https://github.com/WordPress/gutenberg/tree/HEAD/packages/compose) | `7.14.0` | `7.17.0` | | [@wordpress/core-data](https://github.com/WordPress/gutenberg/tree/HEAD/packages/core-data) | `7.14.0` | `7.17.0` | | [@wordpress/data](https://github.com/WordPress/gutenberg/tree/HEAD/packages/data) | `10.14.0` | `10.17.0` | | [@wordpress/dependency-extraction-webpack-plugin](https://github.com/WordPress/gutenberg/tree/HEAD/packages/dependency-extraction-webpack-plugin) | `6.14.0` | `6.17.0` | | [@wordpress/dom-ready](https://github.com/WordPress/gutenberg/tree/HEAD/packages/dom-ready) | `4.14.0` | `4.17.0` | | [@wordpress/e2e-test-utils-playwright](https://github.com/WordPress/gutenberg/tree/HEAD/packages/e2e-test-utils-playwright) | `1.14.0` | `1.17.0` | | [@wordpress/editor](https://github.com/WordPress/gutenberg/tree/HEAD/packages/editor) | `14.14.0` | `14.17.0` | | [@wordpress/element](https://github.com/WordPress/gutenberg/tree/HEAD/packages/element) | `6.14.0` | `6.17.0` | | [@wordpress/env](https://github.com/WordPress/gutenberg/tree/HEAD/packages/env) | `10.14.0` | `10.17.0` | | [@wordpress/hooks](https://github.com/WordPress/gutenberg/tree/HEAD/packages/hooks) | `4.14.0` | `4.17.0` | | [@wordpress/i18n](https://github.com/WordPress/gutenberg/tree/HEAD/packages/i18n) | `5.14.0` | `5.17.0` | | [@wordpress/icons](https://github.com/WordPress/gutenberg/tree/HEAD/packages/icons) | `10.14.0` | `10.17.0` | | [@wordpress/interactivity](https://github.com/WordPress/gutenberg/tree/HEAD/packages/interactivity) | `6.14.0` | `6.17.0` | | [@wordpress/notices](https://github.com/WordPress/gutenberg/tree/HEAD/packages/notices) | `5.14.0` | `5.17.0` | | [@wordpress/plugins](https://github.com/WordPress/gutenberg/tree/HEAD/packages/plugins) | `7.14.0` | `7.17.0` | | [@wordpress/primitives](https://github.com/WordPress/gutenberg/tree/HEAD/packages/primitives) | `4.14.0` | `4.17.0` | | [@wordpress/rich-text](https://github.com/WordPress/gutenberg/tree/HEAD/packages/rich-text) | `7.14.0` | `7.17.0` | | [@wordpress/server-side-render](https://github.com/WordPress/gutenberg/tree/HEAD/packages/server-side-render) | `5.16.0` | `5.17.0` | | [@wordpress/url](https://github.com/WordPress/gutenberg/tree/HEAD/packages/url) | `4.14.0` | `4.17.0` | Updates `@wordpress/dataviews` from 4.10.0 to 4.13.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/dataviews/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/dataviews@4.13.0/packages/dataviews) Updates `@wordpress/api-fetch` from 7.14.0 to 7.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/api-fetch/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/api-fetch@7.17.0/packages/api-fetch) Updates `@wordpress/block-editor` from 14.9.0 to 14.12.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-editor/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/block-editor@14.12.0/packages/block-editor) Updates `@wordpress/blocks` from 14.3.0 to 14.6.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/blocks/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/blocks@14.6.0/packages/blocks) Updates `@wordpress/components` from 29.0.0 to 29.3.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/components/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/components@29.3.0/packages/components) Updates `@wordpress/compose` from 7.14.0 to 7.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/compose/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/compose@7.17.0/packages/compose) Updates `@wordpress/core-data` from 7.14.0 to 7.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/core-data/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/core-data@7.17.0/packages/core-data) Updates `@wordpress/data` from 10.14.0 to 10.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/data/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/data@10.17.0/packages/data) Updates `@wordpress/dependency-extraction-webpack-plugin` from 6.14.0 to 6.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/dependency-extraction-webpack-plugin/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/dependency-extraction-webpack-plugin@6.17.0/packages/dependency-extraction-webpack-plugin) Updates `@wordpress/dom-ready` from 4.14.0 to 4.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/dom-ready/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/dom-ready@4.17.0/packages/dom-ready) Updates `@wordpress/e2e-test-utils-playwright` from 1.14.0 to 1.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/e2e-test-utils-playwright/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/e2e-test-utils-playwright@1.17.0/packages/e2e-test-utils-playwright) Updates `@wordpress/editor` from 14.14.0 to 14.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/editor/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/editor@14.17.0/packages/editor) Updates `@wordpress/element` from 6.14.0 to 6.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/element/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/element@6.17.0/packages/element) Updates `@wordpress/env` from 10.14.0 to 10.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/env/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/env@10.17.0/packages/env) Updates `@wordpress/hooks` from 4.14.0 to 4.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/hooks/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/hooks@4.17.0/packages/hooks) Updates `@wordpress/i18n` from 5.14.0 to 5.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/i18n/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/i18n@5.17.0/packages/i18n) Updates `@wordpress/icons` from 10.14.0 to 10.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/icons/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/icons@10.17.0/packages/icons) Updates `@wordpress/interactivity` from 6.14.0 to 6.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/interactivity/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/interactivity@6.17.0/packages/interactivity) Updates `@wordpress/notices` from 5.14.0 to 5.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/notices/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/notices@5.17.0/packages/notices) Updates `@wordpress/plugins` from 7.14.0 to 7.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/plugins/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/plugins@7.17.0/packages/plugins) Updates `@wordpress/primitives` from 4.14.0 to 4.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/primitives/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/primitives@4.17.0/packages/primitives) Updates `@wordpress/rich-text` from 7.14.0 to 7.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/rich-text/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/rich-text@7.17.0/packages/rich-text) Updates `@wordpress/server-side-render` from 5.16.0 to 5.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/server-side-render/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/server-side-render@5.17.0/packages/server-side-render) Updates `@wordpress/url` from 4.14.0 to 4.17.0 - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/url/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/url@4.17.0/packages/url) --- updated-dependencies: - dependency-name: "@wordpress/dataviews" dependency-type: direct:production update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/api-fetch" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/block-editor" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/blocks" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/components" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/compose" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/core-data" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/data" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/dependency-extraction-webpack-plugin" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/dom-ready" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/e2e-test-utils-playwright" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/editor" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/element" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/env" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/hooks" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/i18n" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/icons" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/interactivity" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/notices" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/plugins" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/primitives" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/rich-text" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/server-side-render" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress - dependency-name: "@wordpress/url" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: wordpress ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 3649 +++++++++++++++------------------------------ package.json | 48 +- 2 files changed, 1223 insertions(+), 2474 deletions(-) diff --git a/package-lock.json b/package-lock.json index c01eb735..321f6767 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "GPL-2.0-or-later", "dependencies": { "@automattic/calypso-analytics": "^1.1.3", - "@wordpress/dataviews": "^4.10.0", + "@wordpress/dataviews": "^4.13.0", "react-syntax-highlighter": "^15.6.1" }, "devDependencies": { @@ -23,30 +23,30 @@ "@types/wordpress__block-editor": "11.5.16", "@types/wordpress__blocks": "12.5.16", "@vitest/coverage-v8": "3.0.4", - "@wordpress/api-fetch": "7.14.0", - "@wordpress/block-editor": "14.9.0", - "@wordpress/blocks": "14.3.0", - "@wordpress/components": "29.0.0", - "@wordpress/compose": "7.14.0", - "@wordpress/core-data": "7.14.0", - "@wordpress/data": "10.14.0", - "@wordpress/dependency-extraction-webpack-plugin": "^6.14.0", - "@wordpress/dom-ready": "4.14.0", - "@wordpress/e2e-test-utils-playwright": "^1.14.0", - "@wordpress/editor": "14.14.0", - "@wordpress/element": "6.14.0", - "@wordpress/env": "10.14.0", - "@wordpress/hooks": "4.14.0", - "@wordpress/i18n": "5.14.0", - "@wordpress/icons": "10.14.0", - "@wordpress/interactivity": "6.14.0", - "@wordpress/notices": "5.14.0", - "@wordpress/plugins": "7.14.0", - "@wordpress/primitives": "4.14.0", - "@wordpress/rich-text": "7.14.0", + "@wordpress/api-fetch": "7.17.0", + "@wordpress/block-editor": "14.12.0", + "@wordpress/blocks": "14.6.0", + "@wordpress/components": "29.3.0", + "@wordpress/compose": "7.17.0", + "@wordpress/core-data": "7.17.0", + "@wordpress/data": "10.17.0", + "@wordpress/dependency-extraction-webpack-plugin": "^6.17.0", + "@wordpress/dom-ready": "4.17.0", + "@wordpress/e2e-test-utils-playwright": "^1.17.0", + "@wordpress/editor": "14.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/env": "10.17.0", + "@wordpress/hooks": "4.17.0", + "@wordpress/i18n": "5.17.0", + "@wordpress/icons": "10.17.0", + "@wordpress/interactivity": "6.17.0", + "@wordpress/notices": "5.17.0", + "@wordpress/plugins": "7.17.0", + "@wordpress/primitives": "4.17.0", + "@wordpress/rich-text": "7.17.0", "@wordpress/scripts": "30.1.0", - "@wordpress/server-side-render": "5.16.0", - "@wordpress/url": "4.14.0", + "@wordpress/server-side-render": "5.17.0", + "@wordpress/url": "4.17.0", "eslint": "8.57.1", "fork-ts-checker-webpack-plugin": "9.0.2", "happy-dom": "16.7.3", @@ -2993,6 +2993,330 @@ "deprecated": "Use @eslint/object-schema instead", "dev": true }, + "node_modules/@inquirer/checkbox": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.0.7.tgz", + "integrity": "sha512-lyoF4uYdBBTnqeB1gjPdYkiQ++fz/iYKaP9DON1ZGlldkvAEJsjaOBRdbl5UW1pOSslBRd701jxhAG0MlhHd2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.5", + "@inquirer/figures": "^1.0.10", + "@inquirer/type": "^3.0.3", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.4.tgz", + "integrity": "sha512-EsiT7K4beM5fN5Mz6j866EFA9+v9d5o9VUra3hrg8zY4GHmCS8b616FErbdo5eyKoVotBQkHzMIeeKYsKDStDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.5", + "@inquirer/type": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/core": { + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.5.tgz", + "integrity": "sha512-/vyCWhET0ktav/mUeBqJRYTwmjFPIKPRYb3COAw7qORULgipGSUO2vL32lQKki3UxDKJ8BvuEbokaoyCA6YlWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/figures": "^1.0.10", + "@inquirer/type": "^3.0.3", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@inquirer/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@inquirer/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@inquirer/core/node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@inquirer/core/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/core/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/editor": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.4.tgz", + "integrity": "sha512-S8b6+K9PLzxiFGGc02m4syhEu5JsH0BukzRsuZ+tpjJ5aDsDX1WfNfOil2fmsO36Y1RMcpJGxlfQ1yh4WfU28Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.5", + "@inquirer/type": "^3.0.3", + "external-editor": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/expand": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.7.tgz", + "integrity": "sha512-PsUQ5t7r+DPjW0VVEHzssOTBM2UPHnvBNse7hzuki7f6ekRL94drjjfBLrGEDe7cgj3pguufy/cuFwMeWUWHXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.5", + "@inquirer/type": "^3.0.3", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.10.tgz", + "integrity": "sha512-Ey6176gZmeqZuY/W/nZiUyvmb1/qInjcpiZjXWi6nON+nxJpD1bxtSoBxNliGISae32n6OwbY+TSXPZ1CfS4bw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.1.4.tgz", + "integrity": "sha512-CKKF8otRBdIaVnRxkFLs00VNA9HWlEh3x4SqUfC3A8819TeOZpTYG/p+4Nqu3hh97G+A0lxkOZNYE7KISgU8BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.5", + "@inquirer/type": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/number": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.7.tgz", + "integrity": "sha512-uU2nmXGC0kD8+BLgwZqcgBD1jcw2XFww2GmtP6b4504DkOp+fFAhydt7JzRR1TAI2dmj175p4SZB0lxVssNreA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.5", + "@inquirer/type": "^3.0.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/password": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.7.tgz", + "integrity": "sha512-DFpqWLx+C5GV5zeFWuxwDYaeYnTWYphO07pQ2VnP403RIqRIpwBG0ATWf7pF+3IDbaXEtWatCJWxyDrJ+rkj2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.5", + "@inquirer/type": "^3.0.3", + "ansi-escapes": "^4.3.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/prompts": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.2.4.tgz", + "integrity": "sha512-Zn2XZL2VZl76pllUjeDnS6Poz2Oiv9kmAZdSZw1oFya985+/JXZ3GZ2JUWDokAPDhvuhkv9qz0Z7z/U80G8ztA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.0.7", + "@inquirer/confirm": "^5.1.4", + "@inquirer/editor": "^4.2.4", + "@inquirer/expand": "^4.0.7", + "@inquirer/input": "^4.1.4", + "@inquirer/number": "^3.0.7", + "@inquirer/password": "^4.0.7", + "@inquirer/rawlist": "^4.0.7", + "@inquirer/search": "^3.0.7", + "@inquirer/select": "^4.0.7" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/rawlist": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.0.7.tgz", + "integrity": "sha512-ZeBca+JCCtEIwQMvhuROT6rgFQWWvAImdQmIIP3XoyDFjrp2E0gZlEn65sWIoR6pP2EatYK96pvx0887OATWQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.5", + "@inquirer/type": "^3.0.3", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/search": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.0.7.tgz", + "integrity": "sha512-Krq925SDoLh9AWSNee8mbSIysgyWtcPnSAp5YtPBGCQ+OCO+5KGC8FwLpyxl8wZ2YAov/8Tp21stTRK/fw5SGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.5", + "@inquirer/figures": "^1.0.10", + "@inquirer/type": "^3.0.3", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/select": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.0.7.tgz", + "integrity": "sha512-ejGBMDSD+Iqk60u5t0Zf2UQhGlJWDM78Ep70XpNufIfc+f4VOTeybYKXu9pDjz87FkRzLiVsGpQG2SzuGlhaJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.1.5", + "@inquirer/figures": "^1.0.10", + "@inquirer/type": "^3.0.3", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.3.tgz", + "integrity": "sha512-I4VIHFxUuY1bshGbXZTxCmhwaaEst9s/lll3ekok+o1Z26/ZUKdx8y1b7lsoG6rtsBDwEGfiBJ2SfirjoISLpg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -4185,6 +4509,13 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, + "node_modules/@remote-ui/rpc": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@remote-ui/rpc/-/rpc-1.4.5.tgz", + "integrity": "sha512-Cr+06niG/vmE4A9YsmaKngRuuVSWKMY42NMwtZfy+gctRWGu6Wj9BWuMJg5CEp+JTkRBPToqT5rqnrg1G/Wvow==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.32.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.32.0.tgz", @@ -4536,6 +4867,35 @@ "node": ">=8" } }, + "node_modules/@shopify/web-worker": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@shopify/web-worker/-/web-worker-6.4.0.tgz", + "integrity": "sha512-RvY1mgRyAqawFiYBvsBkek2pVK4GVpV9mmhWFCZXwx01usxXd2HMhKNTFeRYhSp29uoUcfBlKZAwCwQzt826tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@remote-ui/rpc": "^1.2.5" + }, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": "^5.38.0", + "webpack-virtual-modules": "^0.4.3 || ^0.5.0 || ^0.6.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "webpack": { + "optional": true + }, + "webpack-virtual-modules": { + "optional": true + } + } + }, "node_modules/@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", @@ -5449,6 +5809,7 @@ "resolved": "https://registry.npmjs.org/@types/simple-peer/-/simple-peer-9.11.8.tgz", "integrity": "sha512-rvqefdp2rvIA6wiomMgKWd2UZNPe6LM2EV5AuY3CPQJF+8TbdrL5TjYdMf0VAjGczzlkH4l1NjDkihwbj3Xodw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -7141,35 +7502,42 @@ } }, "node_modules/@wordpress/a11y": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/a11y/-/a11y-4.16.0.tgz", - "integrity": "sha512-i3zrNFx+N+dNivQxUeQXWKGT1ccWePXcqPkVTqjdO+lACv+MtJoyE9PXZCmaxHWq00g1RTvIpLtrzV5L4gzZkA==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/a11y/-/a11y-4.17.0.tgz", + "integrity": "sha512-TCQ/PGC0Me3yzPUrmY2FpECl7GUcUcx6kVGUugmlMxNwxeZRYUOEMxsHGm07iKV5l7zbi3y5c/i5bbYwJfXA4g==", + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/dom-ready": "^4.16.0", - "@wordpress/i18n": "^5.16.0" + "@wordpress/dom-ready": "4.17.0", + "@wordpress/i18n": "5.17.0" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" } }, - "node_modules/@wordpress/a11y/node_modules/@wordpress/dom-ready": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-4.16.0.tgz", - "integrity": "sha512-rlp7gZRRPsob8z+//tS8bHHRTlkRiOfbKA1SJmyfakU/p4fcEXskLfdq/0wGPZtoHnia6kLKUyFMWhIBe8SuYQ==", + "node_modules/@wordpress/api-fetch": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-7.17.0.tgz", + "integrity": "sha512-L3iT/K41R6KResTy/7EOsTD+KKO20U3B4lPz/jQMRNgFdq4MOxtalEMjrRoj1mG+qiYGYdvGmpSgOzSx9o3eRg==", + "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { - "@babel/runtime": "7.25.7" + "@babel/runtime": "7.25.7", + "@wordpress/i18n": "5.17.0", + "@wordpress/url": "4.17.0" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" } }, - "node_modules/@wordpress/a11y/node_modules/@wordpress/hooks": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-4.16.0.tgz", - "integrity": "sha512-W82L1PdIhJPNpEb2F+0NWzrDoUqZo6NnYID7qHCexBiagq4+QS4uydM6anyFvUNrpL51CmkCNu31Xi8HjpSTGg==", + "node_modules/@wordpress/autop": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/autop/-/autop-4.17.0.tgz", + "integrity": "sha512-6O9Eo/S02OHIa4GflfcWHANHpuy5/SifaWiprWYTrhIt6L6DyVxr1AErSWfDXIrkNNVXuhhykYDHAtApKqpqsQ==", + "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7" }, @@ -7178,59 +7546,11 @@ "npm": ">=8.19.2" } }, - "node_modules/@wordpress/a11y/node_modules/@wordpress/i18n": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.16.0.tgz", - "integrity": "sha512-O4ZUvjS8AlYzTxvw7fmp3xk51rpKv1h2/dGFc/L+IB97UrCBAiC9HBv6FIHRF1gci4Vdu/QnCDw3qpC+N/2gCw==", - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/hooks": "^4.16.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "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/api-fetch": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-7.14.0.tgz", - "integrity": "sha512-BrQbF/CVF+un1KToBXr9UpebPS9gvW6vqVV7dc1Atsh3uiLeesU0GOwJ0Z+ZzAr8vNQx8pjFRWZGp7xdO+hygA==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/i18n": "*", - "@wordpress/url": "*" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/autop": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/autop/-/autop-4.16.0.tgz", - "integrity": "sha512-5/XBRZ7Y731moR/hzZ+/k9tavHMHvshi+IdsJAecgUcqYC45YMLmqOmA4DOzfzCjBkuVvoy+6itMHQ+Q87Gb9g==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/babel-preset-default": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/@wordpress/babel-preset-default/-/babel-preset-default-8.9.0.tgz", - "integrity": "sha512-qkhnRyku8FeiUGXfcMYfr/u2SG6NIj/9hWoe5Ubpay7gpX2A1H9+rLrTvABRiip7zit88JJ6b4VUqLL9Cr23bg==", - "dev": true, + "node_modules/@wordpress/babel-preset-default": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/@wordpress/babel-preset-default/-/babel-preset-default-8.9.0.tgz", + "integrity": "sha512-qkhnRyku8FeiUGXfcMYfr/u2SG6NIj/9hWoe5Ubpay7gpX2A1H9+rLrTvABRiip7zit88JJ6b4VUqLL9Cr23bg==", + "dev": true, "dependencies": { "@babel/core": "^7.16.0", "@babel/plugin-transform-react-jsx": "^7.16.0", @@ -7260,10 +7580,11 @@ } }, "node_modules/@wordpress/blob": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/blob/-/blob-4.16.0.tgz", - "integrity": "sha512-vhaEhh0jqSZG+LPrLL6wco4kmw4lYC6OLTOspeOWuAEPMKOs4YyfF8x2iA8p6CZiWjVcahwZlcP7DnZDIwowsQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/blob/-/blob-4.17.0.tgz", + "integrity": "sha512-qH0Q48clM+UTdTMWUsCyyAuy4J+koNGLz4oXyJZCrUvUQ31Hpj6VwQulM2lSXYQyzOWJEKf3deHM47Uz1JYhhg==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7" }, @@ -7273,46 +7594,48 @@ } }, "node_modules/@wordpress/block-editor": { - "version": "14.9.0", - "resolved": "https://registry.npmjs.org/@wordpress/block-editor/-/block-editor-14.9.0.tgz", - "integrity": "sha512-Q+91Aip8aG0aslOhGDYfaU6CzM7OA2F2xNHi+6hBixBa++b2jy5WZamLkyot2/7qbCNSS7TPlCFZLyA6UFCtdg==", + "version": "14.12.0", + "resolved": "https://registry.npmjs.org/@wordpress/block-editor/-/block-editor-14.12.0.tgz", + "integrity": "sha512-i8tUlPiRgLqUFVnAHDjS7MNHZMFDYMkm5gR2xsNryzhsvoAndUYJiktftbXNaQVki/EMoDf1zHicHZ2g2AQy5Q==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", "@emotion/react": "^11.7.1", "@emotion/styled": "^11.6.0", "@react-spring/web": "^9.4.5", - "@wordpress/a11y": "*", - "@wordpress/api-fetch": "*", - "@wordpress/blob": "*", - "@wordpress/block-serialization-default-parser": "*", - "@wordpress/blocks": "*", - "@wordpress/commands": "*", - "@wordpress/components": "*", - "@wordpress/compose": "*", - "@wordpress/data": "*", - "@wordpress/date": "*", - "@wordpress/deprecated": "*", - "@wordpress/dom": "*", - "@wordpress/element": "*", - "@wordpress/escape-html": "*", - "@wordpress/hooks": "*", - "@wordpress/html-entities": "*", - "@wordpress/i18n": "*", - "@wordpress/icons": "*", - "@wordpress/is-shallow-equal": "*", - "@wordpress/keyboard-shortcuts": "*", - "@wordpress/keycodes": "*", - "@wordpress/notices": "*", - "@wordpress/preferences": "*", - "@wordpress/priority-queue": "*", - "@wordpress/private-apis": "*", - "@wordpress/rich-text": "*", - "@wordpress/style-engine": "*", - "@wordpress/token-list": "*", - "@wordpress/url": "*", - "@wordpress/warning": "*", - "@wordpress/wordcount": "*", + "@wordpress/a11y": "^4.17.0", + "@wordpress/api-fetch": "^7.17.0", + "@wordpress/blob": "^4.17.0", + "@wordpress/block-serialization-default-parser": "^5.17.0", + "@wordpress/blocks": "14.6.0", + "@wordpress/commands": "^1.17.0", + "@wordpress/components": "29.3.0", + "@wordpress/compose": "7.17.0", + "@wordpress/data": "10.17.0", + "@wordpress/date": "^5.17.0", + "@wordpress/deprecated": "^4.17.0", + "@wordpress/dom": "^4.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/escape-html": "^3.17.0", + "@wordpress/hooks": "4.17.0", + "@wordpress/html-entities": "^4.17.0", + "@wordpress/i18n": "5.17.0", + "@wordpress/icons": "10.17.0", + "@wordpress/is-shallow-equal": "^5.17.0", + "@wordpress/keyboard-shortcuts": "^5.17.0", + "@wordpress/keycodes": "^4.17.0", + "@wordpress/notices": "5.17.0", + "@wordpress/preferences": "^4.17.0", + "@wordpress/priority-queue": "^3.17.0", + "@wordpress/private-apis": "^1.17.0", + "@wordpress/rich-text": "7.17.0", + "@wordpress/style-engine": "^2.17.0", + "@wordpress/token-list": "^3.17.0", + "@wordpress/upload-media": "^0.2.0", + "@wordpress/url": "4.17.0", + "@wordpress/warning": "^3.17.0", + "@wordpress/wordcount": "^4.17.0", "change-case": "^4.1.2", "clsx": "^2.1.1", "colord": "^2.7.0", @@ -7337,35 +7660,15 @@ "react-dom": "^18.0.0" } }, - "node_modules/@wordpress/block-editor/node_modules/@wordpress/i18n": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.10.0.tgz", - "integrity": "sha512-HZ6UcMHsjOocDI0zVAuP4JIl97LRmpGo/lVxzVIreaLoYitmYVDUzji02u1o7sEdRWc1Hpkm2/oO/9275rJg1w==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/hooks": "^4.10.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "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/block-editor/node_modules/@wordpress/keycodes": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.10.0.tgz", - "integrity": "sha512-2i+N90HBMqQegtGqeVB8pJz8ZgKAY1eZmQegE9MXczYVac85DDOoxhY/41c44s6Kwl3waJ2Zght6UXE0OUFMxw==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.17.0.tgz", + "integrity": "sha512-6aZ28uoCmzjXONpRVtDPjevkw834fhIRBnn2KQdzENMnPiQCNbiG71mPNxkTw1yRHRRT5ptHvOe49ztWm9KMcA==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/i18n": "5.10.0" + "@wordpress/i18n": "5.17.0" }, "engines": { "node": ">=18.12.0", @@ -7373,10 +7676,11 @@ } }, "node_modules/@wordpress/block-serialization-default-parser": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/block-serialization-default-parser/-/block-serialization-default-parser-5.16.0.tgz", - "integrity": "sha512-F8n8GMeVAepWl9nuA9Ly/WWaqvZ9Lg0KI/OUd0Bm0Y3Ssz65UNRf6DT+ScN35OCAOklf1bQ1PGaq9JdVmC43mg==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/block-serialization-default-parser/-/block-serialization-default-parser-5.17.0.tgz", + "integrity": "sha512-4oVgm6f/kRqersuTH1SS85x89P4foPAo2xwjoXvHdjy1Rp0UQ86uxyKn0j0A6k7uQEXc5BJeUevk/Z1AT1Z9bQ==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7" }, @@ -7386,27 +7690,28 @@ } }, "node_modules/@wordpress/blocks": { - "version": "14.3.0", - "resolved": "https://registry.npmjs.org/@wordpress/blocks/-/blocks-14.3.0.tgz", - "integrity": "sha512-2Y3JZcFq1yplRf0VWHDnxlxIFYn5v327zspkM6QkExbm0eMcDDf7dw482PVlF0a+6S7OD7Om1B8hY0Gpo3q8Kw==", + "version": "14.6.0", + "resolved": "https://registry.npmjs.org/@wordpress/blocks/-/blocks-14.6.0.tgz", + "integrity": "sha512-9FkjXHRTXIaOU7BJfoeRUe1snh+5H8rypOTJoDpiMCoXMfGKyBVpacRMzbltQiK7SrzmHbzst4EuxHoK7a/TVw==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/autop": "*", - "@wordpress/blob": "*", - "@wordpress/block-serialization-default-parser": "*", - "@wordpress/data": "*", - "@wordpress/deprecated": "*", - "@wordpress/dom": "*", - "@wordpress/element": "*", - "@wordpress/hooks": "*", - "@wordpress/html-entities": "*", - "@wordpress/i18n": "*", - "@wordpress/is-shallow-equal": "*", - "@wordpress/private-apis": "*", - "@wordpress/rich-text": "*", - "@wordpress/shortcode": "*", - "@wordpress/warning": "*", + "@wordpress/autop": "^4.17.0", + "@wordpress/blob": "^4.17.0", + "@wordpress/block-serialization-default-parser": "^5.17.0", + "@wordpress/data": "10.17.0", + "@wordpress/deprecated": "^4.17.0", + "@wordpress/dom": "^4.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/hooks": "4.17.0", + "@wordpress/html-entities": "^4.17.0", + "@wordpress/i18n": "5.17.0", + "@wordpress/is-shallow-equal": "^5.17.0", + "@wordpress/private-apis": "^1.17.0", + "@wordpress/rich-text": "7.17.0", + "@wordpress/shortcode": "^4.17.0", + "@wordpress/warning": "^3.17.0", "change-case": "^4.1.2", "colord": "^2.7.0", "fast-deep-equal": "^3.1.3", @@ -7438,19 +7743,20 @@ } }, "node_modules/@wordpress/commands": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/commands/-/commands-1.10.0.tgz", - "integrity": "sha512-WgqkUTQ4bAOBZEj4s59PSLJPn0n6KfHvZaVnD5KRR4j1WbI359eFbInzkYyvzKq4LEGWbT6/AadY4GEY32a7/A==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/commands/-/commands-1.17.0.tgz", + "integrity": "sha512-oZLv9pi0iiIO7DXRijK9gze5+iktoUyfDVipAmbmxAVEqptfWuPP3BRSkZxf+ccoIWpz0EhNKShsbQM86FwVbg==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/components": "28.10.0", - "@wordpress/data": "10.10.0", - "@wordpress/element": "6.10.0", - "@wordpress/i18n": "5.10.0", - "@wordpress/icons": "10.10.0", - "@wordpress/keyboard-shortcuts": "^5.10.0", - "@wordpress/private-apis": "^1.10.0", + "@wordpress/components": "29.3.0", + "@wordpress/data": "10.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/i18n": "5.17.0", + "@wordpress/icons": "10.17.0", + "@wordpress/keyboard-shortcuts": "^5.17.0", + "@wordpress/private-apis": "^1.17.0", "clsx": "^2.1.1", "cmdk": "^1.0.0" }, @@ -7463,171 +7769,11 @@ "react-dom": "^18.0.0" } }, - "node_modules/@wordpress/commands/node_modules/@wordpress/components": { - "version": "28.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-28.10.0.tgz", - "integrity": "sha512-w5mteCe9qOBMgD8d80QBVOPk0YAquUkMD9o3jDvdqUwiTcVgxn4QSKjh65NGYotvMhDsgsMTq+qgifAB+ubepg==", - "dev": true, - "dependencies": { - "@ariakit/react": "^0.4.10", - "@babel/runtime": "7.25.7", - "@emotion/cache": "^11.7.1", - "@emotion/css": "^11.7.1", - "@emotion/react": "^11.7.1", - "@emotion/serialize": "^1.0.2", - "@emotion/styled": "^11.6.0", - "@emotion/utils": "^1.0.0", - "@floating-ui/react-dom": "^2.0.8", - "@types/gradient-parser": "0.1.3", - "@types/highlight-words-core": "1.2.1", - "@use-gesture/react": "^10.3.1", - "@wordpress/a11y": "^4.10.0", - "@wordpress/compose": "^7.10.0", - "@wordpress/date": "^5.10.0", - "@wordpress/deprecated": "^4.10.0", - "@wordpress/dom": "^4.10.0", - "@wordpress/element": "^6.10.0", - "@wordpress/escape-html": "^3.10.0", - "@wordpress/hooks": "^4.10.0", - "@wordpress/html-entities": "^4.10.0", - "@wordpress/i18n": "^5.10.0", - "@wordpress/icons": "^10.10.0", - "@wordpress/is-shallow-equal": "^5.10.0", - "@wordpress/keycodes": "^4.10.0", - "@wordpress/primitives": "^4.10.0", - "@wordpress/private-apis": "^1.10.0", - "@wordpress/rich-text": "^7.10.0", - "@wordpress/warning": "^3.10.0", - "change-case": "^4.1.2", - "clsx": "^2.1.1", - "colord": "^2.7.0", - "date-fns": "^3.6.0", - "deepmerge": "^4.3.0", - "fast-deep-equal": "^3.1.3", - "framer-motion": "^11.1.9", - "gradient-parser": "^0.1.5", - "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.3.1", - "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/commands/node_modules/@wordpress/data": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-10.10.0.tgz", - "integrity": "sha512-oyYl89p86+U9W6vKDqScKhUGKKzsnETj9rg8zOnT4K9ceOScjGCgdCE+XxcY9exeRg33aSYDjmvnsXXYStBYmA==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/compose": "^7.10.0", - "@wordpress/deprecated": "^4.10.0", - "@wordpress/element": "^6.10.0", - "@wordpress/is-shallow-equal": "^5.10.0", - "@wordpress/priority-queue": "^3.10.0", - "@wordpress/private-apis": "^1.10.0", - "@wordpress/redux-routine": "^5.10.0", - "deepmerge": "^4.3.0", - "equivalent-key-map": "^0.2.2", - "is-plain-object": "^5.0.0", - "is-promise": "^4.0.0", - "redux": "^4.1.2", - "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/commands/node_modules/@wordpress/element": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.10.0.tgz", - "integrity": "sha512-7zW+14vHqEn45nszSLMUqE5IbzOtvgUUgF56qlMhwabpG4l/zhaj3gO3wLDI19C13ih1vOdSjzPc3At4fB3tRQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@types/react": "^18.2.79", - "@types/react-dom": "^18.2.25", - "@wordpress/escape-html": "^3.10.0", - "change-case": "^4.1.2", - "is-plain-object": "^5.0.0", - "react": "^18.3.0", - "react-dom": "^18.3.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/commands/node_modules/@wordpress/i18n": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.10.0.tgz", - "integrity": "sha512-HZ6UcMHsjOocDI0zVAuP4JIl97LRmpGo/lVxzVIreaLoYitmYVDUzji02u1o7sEdRWc1Hpkm2/oO/9275rJg1w==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/hooks": "^4.10.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "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/commands/node_modules/@wordpress/icons": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-10.10.0.tgz", - "integrity": "sha512-41HaxMtq0WZF37mpZ1RQ1s1J3ia5gHFUd/uGhP9p1dhzEFYALxKVTB0Gy3cJhT0CslKeEwYx2XQIP1ZaCKNakQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/element": "^6.10.0", - "@wordpress/primitives": "^4.10.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/commands/node_modules/@wordpress/keycodes": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.14.0.tgz", - "integrity": "sha512-vZpK+NbhC+3/JK8S5I/PuJMNYhfn7X8pupTPuEiKIXZgcnXAy3mORgirBeZJNkNUXRl3vfcsq0qFnIovI96fHA==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/i18n": "*" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, "node_modules/@wordpress/components": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-29.0.0.tgz", - "integrity": "sha512-Dx8ou9+07RGD6KzOdDDHc8lyE0WVjuARmeD87NtutQWZTpJMc0TXR1eM/7ssgEeSOwXaqvFFuYKTAQajNrrQWQ==", + "version": "29.3.0", + "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-29.3.0.tgz", + "integrity": "sha512-9lQIXsbgFeGY1QXEhNHQ6mq+6sS1TGGdZdaGSoQoP682WWgdjshnyq/0yhGULY9ReDKnZF2mHJ/J3FvleyYMcg==", + "license": "GPL-2.0-or-later", "dependencies": { "@ariakit/react": "^0.4.15", "@babel/runtime": "7.25.7", @@ -7641,23 +7787,23 @@ "@types/gradient-parser": "0.1.3", "@types/highlight-words-core": "1.2.1", "@use-gesture/react": "^10.3.1", - "@wordpress/a11y": "*", - "@wordpress/compose": "*", - "@wordpress/date": "*", - "@wordpress/deprecated": "*", - "@wordpress/dom": "*", - "@wordpress/element": "*", - "@wordpress/escape-html": "*", - "@wordpress/hooks": "*", - "@wordpress/html-entities": "*", - "@wordpress/i18n": "*", - "@wordpress/icons": "*", - "@wordpress/is-shallow-equal": "*", - "@wordpress/keycodes": "*", - "@wordpress/primitives": "*", - "@wordpress/private-apis": "*", - "@wordpress/rich-text": "*", - "@wordpress/warning": "*", + "@wordpress/a11y": "^4.17.0", + "@wordpress/compose": "7.17.0", + "@wordpress/date": "^5.17.0", + "@wordpress/deprecated": "^4.17.0", + "@wordpress/dom": "^4.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/escape-html": "^3.17.0", + "@wordpress/hooks": "4.17.0", + "@wordpress/html-entities": "^4.17.0", + "@wordpress/i18n": "5.17.0", + "@wordpress/icons": "10.17.0", + "@wordpress/is-shallow-equal": "^5.17.0", + "@wordpress/keycodes": "^4.17.0", + "@wordpress/primitives": "4.17.0", + "@wordpress/private-apis": "^1.17.0", + "@wordpress/rich-text": "7.17.0", + "@wordpress/warning": "^3.17.0", "change-case": "^4.1.2", "clsx": "^2.1.1", "colord": "^2.7.0", @@ -7684,33 +7830,14 @@ "react-dom": "^18.0.0" } }, - "node_modules/@wordpress/components/node_modules/@wordpress/i18n": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.10.0.tgz", - "integrity": "sha512-HZ6UcMHsjOocDI0zVAuP4JIl97LRmpGo/lVxzVIreaLoYitmYVDUzji02u1o7sEdRWc1Hpkm2/oO/9275rJg1w==", - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/hooks": "^4.10.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "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/components/node_modules/@wordpress/keycodes": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.10.0.tgz", - "integrity": "sha512-2i+N90HBMqQegtGqeVB8pJz8ZgKAY1eZmQegE9MXczYVac85DDOoxhY/41c44s6Kwl3waJ2Zght6UXE0OUFMxw==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.17.0.tgz", + "integrity": "sha512-6aZ28uoCmzjXONpRVtDPjevkw834fhIRBnn2KQdzENMnPiQCNbiG71mPNxkTw1yRHRRT5ptHvOe49ztWm9KMcA==", + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/i18n": "5.10.0" + "@wordpress/i18n": "5.17.0" }, "engines": { "node": ">=18.12.0", @@ -7718,19 +7845,20 @@ } }, "node_modules/@wordpress/compose": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-7.14.0.tgz", - "integrity": "sha512-V8llRKmEWfrHWdZVnZFeyM5VAB40MyjVxm+bCwgBO65Tv8yeVi+ZipQ+Nk5abIeQWp3G0BDYybG1gmVwuCik2g==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-7.17.0.tgz", + "integrity": "sha512-jn5uCw08HHLfOpIDp0pKBDZh1oZiMwjiK3c3IZdZo6eoWZjpOr3ecsMa4RBl/4HbqnUoeFDD6Lj83IEKPuzHQg==", + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", "@types/mousetrap": "^1.6.8", - "@wordpress/deprecated": "*", - "@wordpress/dom": "*", - "@wordpress/element": "*", - "@wordpress/is-shallow-equal": "*", - "@wordpress/keycodes": "*", - "@wordpress/priority-queue": "*", - "@wordpress/undo-manager": "*", + "@wordpress/deprecated": "^4.17.0", + "@wordpress/dom": "^4.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/is-shallow-equal": "^5.17.0", + "@wordpress/keycodes": "^4.17.0", + "@wordpress/priority-queue": "^3.17.0", + "@wordpress/undo-manager": "^1.17.0", "change-case": "^4.1.2", "clipboard": "^2.0.11", "mousetrap": "^1.6.5", @@ -7744,33 +7872,14 @@ "react": "^18.0.0" } }, - "node_modules/@wordpress/compose/node_modules/@wordpress/i18n": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.10.0.tgz", - "integrity": "sha512-HZ6UcMHsjOocDI0zVAuP4JIl97LRmpGo/lVxzVIreaLoYitmYVDUzji02u1o7sEdRWc1Hpkm2/oO/9275rJg1w==", - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/hooks": "^4.10.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "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/compose/node_modules/@wordpress/keycodes": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.10.0.tgz", - "integrity": "sha512-2i+N90HBMqQegtGqeVB8pJz8ZgKAY1eZmQegE9MXczYVac85DDOoxhY/41c44s6Kwl3waJ2Zght6UXE0OUFMxw==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.17.0.tgz", + "integrity": "sha512-6aZ28uoCmzjXONpRVtDPjevkw834fhIRBnn2KQdzENMnPiQCNbiG71mPNxkTw1yRHRRT5ptHvOe49ztWm9KMcA==", + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/i18n": "5.10.0" + "@wordpress/i18n": "5.17.0" }, "engines": { "node": ">=18.12.0", @@ -7778,28 +7887,29 @@ } }, "node_modules/@wordpress/core-data": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/core-data/-/core-data-7.14.0.tgz", - "integrity": "sha512-NTUS7MHK489oDuQfnw2NY8I+bx29JTR1VzrUpSLGjCzkAcXk+NxDP+MHLAuQQ1MGcKuPzP/CmSnM0aq/fRR6og==", + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/core-data/-/core-data-7.17.0.tgz", + "integrity": "sha512-khNm8SDsIwXr1297e3j3Y/KHZmtRmouRgn+AWzlmlgdArsk8IlIwe9W+KE1tg+VoZJ5f3p0B7rqBUQfD7qbXQg==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/api-fetch": "*", - "@wordpress/block-editor": "*", - "@wordpress/blocks": "*", - "@wordpress/compose": "*", - "@wordpress/data": "*", - "@wordpress/deprecated": "*", - "@wordpress/element": "*", - "@wordpress/html-entities": "*", - "@wordpress/i18n": "*", - "@wordpress/is-shallow-equal": "*", - "@wordpress/private-apis": "*", - "@wordpress/rich-text": "*", - "@wordpress/sync": "*", - "@wordpress/undo-manager": "*", - "@wordpress/url": "*", - "@wordpress/warning": "*", + "@wordpress/api-fetch": "^7.17.0", + "@wordpress/block-editor": "^14.12.0", + "@wordpress/blocks": "^14.6.0", + "@wordpress/compose": "^7.17.0", + "@wordpress/data": "10.17.0", + "@wordpress/deprecated": "^4.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/html-entities": "^4.17.0", + "@wordpress/i18n": "5.17.0", + "@wordpress/is-shallow-equal": "^5.17.0", + "@wordpress/private-apis": "^1.17.0", + "@wordpress/rich-text": "7.17.0", + "@wordpress/sync": "^1.17.0", + "@wordpress/undo-manager": "^1.17.0", + "@wordpress/url": "4.17.0", + "@wordpress/warning": "^3.17.0", "change-case": "^4.1.2", "equivalent-key-map": "^0.2.2", "fast-deep-equal": "^3.1.3", @@ -7816,18 +7926,19 @@ } }, "node_modules/@wordpress/data": { - "version": "10.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-10.14.0.tgz", - "integrity": "sha512-oKBLj7alGmlD7/lFwK7hwt+Db393yX6hIBpXT/zPDeUsIl0/DXFlHOs2c/UJTZxnyHow44gy7ksLVHc8I4y8ZQ==", + "version": "10.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-10.17.0.tgz", + "integrity": "sha512-NezfpsRH3BIV2i10wFohsGfOQ+pp9TvSHFuVK/AlQmnAogoMpFOxAumXCI7rvDoH1X4rEPiX2ggRnxP2+Z6jwQ==", + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/compose": "*", - "@wordpress/deprecated": "*", - "@wordpress/element": "*", - "@wordpress/is-shallow-equal": "*", - "@wordpress/priority-queue": "*", - "@wordpress/private-apis": "*", - "@wordpress/redux-routine": "*", + "@wordpress/compose": "^7.17.0", + "@wordpress/deprecated": "^4.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/is-shallow-equal": "^5.17.0", + "@wordpress/priority-queue": "^3.17.0", + "@wordpress/private-apis": "^1.17.0", + "@wordpress/redux-routine": "^5.17.0", "deepmerge": "^4.3.0", "equivalent-key-map": "^0.2.2", "is-plain-object": "^5.0.0", @@ -7850,22 +7961,22 @@ "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" }, "node_modules/@wordpress/dataviews": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/dataviews/-/dataviews-4.10.0.tgz", - "integrity": "sha512-Rsp5wUTTGAJlbWdkdFHGXq06LU6F/Kvki6IT9byexu+984h3F+VNIyVCP1BQPqNAWhsUHD4o0gIZKzH17zrCbw==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@wordpress/dataviews/-/dataviews-4.13.0.tgz", + "integrity": "sha512-fJyHzNBvI/mivZh5z5+XC3tOSHojNOYVbSA9ifPB6hNcZjFJ+fsNt/I8tmOQdmOOb4dUESkOOKmk6RlPKCjErg==", "license": "GPL-2.0-or-later", "dependencies": { "@ariakit/react": "^0.4.15", "@babel/runtime": "7.25.7", - "@wordpress/components": "*", - "@wordpress/compose": "*", - "@wordpress/data": "*", - "@wordpress/element": "*", - "@wordpress/i18n": "*", - "@wordpress/icons": "*", - "@wordpress/primitives": "*", - "@wordpress/private-apis": "*", - "@wordpress/warning": "*", + "@wordpress/components": "29.3.0", + "@wordpress/compose": "7.17.0", + "@wordpress/data": "10.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/i18n": "5.17.0", + "@wordpress/icons": "10.17.0", + "@wordpress/primitives": "4.17.0", + "@wordpress/private-apis": "^1.17.0", + "@wordpress/warning": "^3.17.0", "clsx": "^2.1.1", "remove-accents": "^0.5.0" }, @@ -7878,12 +7989,13 @@ } }, "node_modules/@wordpress/date": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/date/-/date-5.16.0.tgz", - "integrity": "sha512-Sb2eJ7S7bn7ODfe0WVgNEqLpilgwpKIoJjVxMxT8wtJpx4rEs25+BAyQ6Bpj6lxX9P99ZmPsdrq5YavxP9NKHg==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/date/-/date-5.17.0.tgz", + "integrity": "sha512-vFi+h+YpiicfDHtp1SKkFmgQR0PI9I76Dqoi7lBP95BPTGC/adQ3u2ee5wGd5uVUlR+ca+TfR6siC4Igau73oA==", + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/deprecated": "^4.16.0", + "@wordpress/deprecated": "^4.17.0", "moment": "^2.29.4", "moment-timezone": "^0.5.40" }, @@ -7893,9 +8005,9 @@ } }, "node_modules/@wordpress/dependency-extraction-webpack-plugin": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/dependency-extraction-webpack-plugin/-/dependency-extraction-webpack-plugin-6.14.0.tgz", - "integrity": "sha512-gLiY07oJT5ejkQwca9kni+iamiWIKF+iadIrzfCTB+34jc8xXVT3ENmydLPcAY5toAejwJ+UmlCxCV8kXFatmA==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/dependency-extraction-webpack-plugin/-/dependency-extraction-webpack-plugin-6.17.0.tgz", + "integrity": "sha512-aRiYH1lcgxnvo0dvhEd5dxjBiWQokRdzSHFSF5flZ4vmHVvDRSgj5V0CQTuCG4fr77PwEJNjPHOm+s1JbmmQJw==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -7910,24 +8022,13 @@ } }, "node_modules/@wordpress/deprecated": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-4.16.0.tgz", - "integrity": "sha512-apv94cskjvWqkanqNn3vP7lugJODkSkPlLqjKPY5iBXI0RATaKuxcTNxuO9/Gn5QcuM89fjhsGTcZ4X/SZTGNQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-4.17.0.tgz", + "integrity": "sha512-7IlFpQ6tNkUbOuuxm6kBCR2R6C9Etlzojgh0ykJ/OmwgRMrosH/m6/zAmaA15oRYpd6dvO7ozJN+ArPz7LSOiQ==", + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/hooks": "^4.16.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/deprecated/node_modules/@wordpress/hooks": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-4.16.0.tgz", - "integrity": "sha512-W82L1PdIhJPNpEb2F+0NWzrDoUqZo6NnYID7qHCexBiagq4+QS4uydM6anyFvUNrpL51CmkCNu31Xi8HjpSTGg==", - "dependencies": { - "@babel/runtime": "7.25.7" + "@wordpress/hooks": "4.17.0" }, "engines": { "node": ">=18.12.0", @@ -7935,12 +8036,13 @@ } }, "node_modules/@wordpress/dom": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/dom/-/dom-4.16.0.tgz", - "integrity": "sha512-iT9D8BnoSgD9w+viDCKtO7lfMmzku3tC7oLEakH6LNZRas0jQuTC46cfokMAz6HTchxiAnuXoPYHsCPhGzWy8Q==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/dom/-/dom-4.17.0.tgz", + "integrity": "sha512-raAeub1L/a2yHd9rwCGs67yDSUsafcpERi9rJCeHiaBE/+h7gZn7Li+Pya+DMk7tGxoIHNpPuGVTAyVhQbjWdQ==", + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/deprecated": "^4.16.0" + "@wordpress/deprecated": "^4.17.0" }, "engines": { "node": ">=18.12.0", @@ -7948,10 +8050,10 @@ } }, "node_modules/@wordpress/dom-ready": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-4.14.0.tgz", - "integrity": "sha512-VeLZZJwKM+Y1d9KPXJ7IQFWwxrND8Xlu+XHpEesudn2kxYE/F5E1uGwS+8LjuprKW+ZEBzgmzZRraKG+KbGFWg==", - "dev": true, + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-4.17.0.tgz", + "integrity": "sha512-u/ocyrPV4MJIKxM1OJg+Q6yOBD0pIYi1jcXE1HVYnc/9Mte0IFlfovYRJj6oGUc7u4dM6AVE2BUCQMJgmG406Q==", + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7" }, @@ -7961,10 +8063,11 @@ } }, "node_modules/@wordpress/e2e-test-utils-playwright": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-1.14.0.tgz", - "integrity": "sha512-G9r3ZysgzAmUbR4bjGAEEP6P2RCIAG8uMU7yyzxOAHegINSbF3shEZKvVNBeKxNwHKAVa9koh/niGN3U4Kr6Rw==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-1.17.0.tgz", + "integrity": "sha512-KhS+HyduYVHWbB/uHxQUC1wHMACx2BpP+4euMN8Kimy/rIsyOFrav9ueVGn7fHu9wu++swk8nUWFBip3GdsliA==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "change-case": "^4.1.2", "form-data": "^4.0.0", @@ -7982,47 +8085,48 @@ } }, "node_modules/@wordpress/editor": { - "version": "14.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/editor/-/editor-14.14.0.tgz", - "integrity": "sha512-VHCHc2JBnt3kBhtLwzEt5Fb/Z8U3UuZdKu1N2voGLB+HQ8ns2/qe1jiSHomBrZLyxbHtbJ7ioirUpJaYVYvbpw==", + "version": "14.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/editor/-/editor-14.17.0.tgz", + "integrity": "sha512-sAeXBvg22o74v7acuYOyHcoALwOs/yzLdXZ8mqT/oi9kBiXSW7kWaPg/q10Mqst0Y6F+prVjNVxcUqHx+tcT5g==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/a11y": "*", - "@wordpress/api-fetch": "*", - "@wordpress/blob": "*", - "@wordpress/block-editor": "*", - "@wordpress/blocks": "*", - "@wordpress/commands": "*", - "@wordpress/components": "*", - "@wordpress/compose": "*", - "@wordpress/core-data": "*", - "@wordpress/data": "*", - "@wordpress/dataviews": "*", - "@wordpress/date": "*", - "@wordpress/deprecated": "*", - "@wordpress/dom": "*", - "@wordpress/element": "*", - "@wordpress/fields": "*", - "@wordpress/hooks": "*", - "@wordpress/html-entities": "*", - "@wordpress/i18n": "*", - "@wordpress/icons": "*", - "@wordpress/interface": "*", - "@wordpress/keyboard-shortcuts": "*", - "@wordpress/keycodes": "*", - "@wordpress/media-utils": "*", - "@wordpress/notices": "*", - "@wordpress/patterns": "*", - "@wordpress/plugins": "*", - "@wordpress/preferences": "*", - "@wordpress/private-apis": "*", - "@wordpress/reusable-blocks": "*", - "@wordpress/rich-text": "*", - "@wordpress/server-side-render": "*", - "@wordpress/url": "*", - "@wordpress/warning": "*", - "@wordpress/wordcount": "*", + "@wordpress/a11y": "^4.17.0", + "@wordpress/api-fetch": "^7.17.0", + "@wordpress/blob": "^4.17.0", + "@wordpress/block-editor": "^14.12.0", + "@wordpress/blocks": "^14.6.0", + "@wordpress/commands": "^1.17.0", + "@wordpress/components": "^29.3.0", + "@wordpress/compose": "^7.17.0", + "@wordpress/core-data": "^7.17.0", + "@wordpress/data": "^10.17.0", + "@wordpress/dataviews": "^4.13.0", + "@wordpress/date": "^5.17.0", + "@wordpress/deprecated": "^4.17.0", + "@wordpress/dom": "^4.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/fields": "^0.9.0", + "@wordpress/hooks": "4.17.0", + "@wordpress/html-entities": "^4.17.0", + "@wordpress/i18n": "5.17.0", + "@wordpress/icons": "10.17.0", + "@wordpress/interface": "^9.2.0", + "@wordpress/keyboard-shortcuts": "^5.17.0", + "@wordpress/keycodes": "^4.17.0", + "@wordpress/media-utils": "^5.17.0", + "@wordpress/notices": "5.17.0", + "@wordpress/patterns": "^2.17.0", + "@wordpress/plugins": "7.17.0", + "@wordpress/preferences": "^4.17.0", + "@wordpress/private-apis": "^1.17.0", + "@wordpress/reusable-blocks": "^5.17.0", + "@wordpress/rich-text": "7.17.0", + "@wordpress/server-side-render": "5.17.0", + "@wordpress/url": "4.17.0", + "@wordpress/warning": "^3.17.0", + "@wordpress/wordcount": "^4.17.0", "change-case": "^4.1.2", "client-zip": "^2.4.5", "clsx": "^2.1.1", @@ -8044,35 +8148,15 @@ "react-dom": "^18.0.0" } }, - "node_modules/@wordpress/editor/node_modules/@wordpress/i18n": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.10.0.tgz", - "integrity": "sha512-HZ6UcMHsjOocDI0zVAuP4JIl97LRmpGo/lVxzVIreaLoYitmYVDUzji02u1o7sEdRWc1Hpkm2/oO/9275rJg1w==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/hooks": "^4.10.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "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/editor/node_modules/@wordpress/keycodes": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.10.0.tgz", - "integrity": "sha512-2i+N90HBMqQegtGqeVB8pJz8ZgKAY1eZmQegE9MXczYVac85DDOoxhY/41c44s6Kwl3waJ2Zght6UXE0OUFMxw==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.17.0.tgz", + "integrity": "sha512-6aZ28uoCmzjXONpRVtDPjevkw834fhIRBnn2KQdzENMnPiQCNbiG71mPNxkTw1yRHRRT5ptHvOe49ztWm9KMcA==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/i18n": "5.10.0" + "@wordpress/i18n": "5.17.0" }, "engines": { "node": ">=18.12.0", @@ -8080,14 +8164,15 @@ } }, "node_modules/@wordpress/element": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.14.0.tgz", - "integrity": "sha512-vZPm2ekv9B7fMcv/slyu/p8lV44EPa6RRHOk04ldNUpsrjC6ph6Q4wpuI5WzLEX7p1u71c8ZOuroEuRvdFxMcA==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.17.0.tgz", + "integrity": "sha512-mRLFDPmZiI3+POi/iUGoof/9fQi4YTJ/RAuIUipr7yG7l4SwOoQy4eSJy6QTyqtJxZ+/7qA+b/+Ek15UzFst5Q==", + "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": "*", + "@wordpress/escape-html": "^3.17.0", "change-case": "^4.1.2", "is-plain-object": "^5.0.0", "react": "^18.3.0", @@ -8099,17 +8184,18 @@ } }, "node_modules/@wordpress/env": { - "version": "10.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-10.14.0.tgz", - "integrity": "sha512-tDJyW6KaaEs9jz2XMTjY0RpGWdsjEfOCx5jeCMWtzkgrDY5N9iZr1BFjNzmFzY1BcXQshnFsrecsnYdyIfvsTA==", + "version": "10.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-10.17.0.tgz", + "integrity": "sha512-Wy0DpOwOy2gtmtad9inkEydAfBm5+TMulCfh22oi5hFVy6BaPpS+Dm9yjgzd9YtO13CR1Y/WjcqYJxEMOFVEJA==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { + "@inquirer/prompts": "^7.2.0", "chalk": "^4.0.0", "copy-dir": "^1.3.0", "docker-compose": "^0.24.3", "extract-zip": "^1.6.7", "got": "^11.8.5", - "inquirer": "^7.1.0", "js-yaml": "^3.13.1", "ora": "^4.0.2", "rimraf": "^5.0.10", @@ -8161,9 +8247,10 @@ } }, "node_modules/@wordpress/escape-html": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-3.16.0.tgz", - "integrity": "sha512-Rb3nUsqK2tzLpKhSRO5IID5O+gvNlyHRkKVmTszTB+0vjK+yh0Mc4UPzdHksPo8K7KnlAFt3SgjcfWYo3LYyUA==", + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-3.17.0.tgz", + "integrity": "sha512-yOfJwgmrtIXQDwX6zTC0L7ymYBXz3K3hlW0nDdtYy+bCw5z0gbrEOnBotOD6YdXlejAgnaAH+K1VSf0xxG5uGA==", + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7" }, @@ -8173,33 +8260,40 @@ } }, "node_modules/@wordpress/fields": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@wordpress/fields/-/fields-0.2.0.tgz", - "integrity": "sha512-3gkziRXCpw1xjcN1XK2G/SBWrww3tB1ZZy0S4C8aVasJYgRXZugdLEjdzI1l4ZPOPR1PCiCzw1uItF72TrNpSQ==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@wordpress/fields/-/fields-0.9.0.tgz", + "integrity": "sha512-PgfXdLu22ZKSz4Ro9sDrKjINS0nCLb4EOLGhyN7RxuXXVW9v+UAhnIX/WCpzoixRX5s7uycDbntt5fklfCTiVg==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/api-fetch": "^7.10.0", - "@wordpress/blob": "^4.10.0", - "@wordpress/blocks": "^13.10.0", - "@wordpress/components": "^28.10.0", - "@wordpress/compose": "^7.10.0", - "@wordpress/core-data": "^7.10.0", - "@wordpress/data": "^10.10.0", - "@wordpress/dataviews": "^4.6.0", - "@wordpress/element": "6.10.0", - "@wordpress/hooks": "4.10.0", - "@wordpress/html-entities": "^4.10.0", - "@wordpress/i18n": "5.10.0", - "@wordpress/icons": "10.10.0", - "@wordpress/notices": "5.10.0", - "@wordpress/patterns": "^2.10.0", - "@wordpress/primitives": "4.10.0", - "@wordpress/private-apis": "^1.10.0", - "@wordpress/url": "4.10.0", - "@wordpress/warning": "^3.10.0", + "@wordpress/api-fetch": "^7.17.0", + "@wordpress/blob": "^4.17.0", + "@wordpress/block-editor": "^14.12.0", + "@wordpress/blocks": "^14.6.0", + "@wordpress/components": "^29.3.0", + "@wordpress/compose": "^7.17.0", + "@wordpress/core-data": "^7.17.0", + "@wordpress/data": "^10.17.0", + "@wordpress/dataviews": "^4.13.0", + "@wordpress/date": "^5.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/hooks": "4.17.0", + "@wordpress/html-entities": "^4.17.0", + "@wordpress/i18n": "5.17.0", + "@wordpress/icons": "10.17.0", + "@wordpress/media-utils": "^5.17.0", + "@wordpress/notices": "5.17.0", + "@wordpress/patterns": "^2.17.0", + "@wordpress/primitives": "4.17.0", + "@wordpress/private-apis": "^1.17.0", + "@wordpress/router": "^1.17.0", + "@wordpress/url": "4.17.0", + "@wordpress/warning": "^3.17.0", "change-case": "4.1.2", - "client-zip": "^2.4.5" + "client-zip": "^2.4.5", + "clsx": "2.1.1", + "remove-accents": "^0.5.0" }, "engines": { "node": ">=18.12.0", @@ -8209,205 +8303,172 @@ "react": "^18.0.0" } }, - "node_modules/@wordpress/fields/node_modules/@wordpress/blocks": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/blocks/-/blocks-13.10.0.tgz", - "integrity": "sha512-Csfw4BgrPEry1OGE0iHSHJlSbao1IA8ujaE8H0LjAXCvMHXET11avSVvFwuYOaDbeSVi2TD50xA+UpMiJnEo4A==", - "dev": true, + "node_modules/@wordpress/hooks": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-4.17.0.tgz", + "integrity": "sha512-LGOHGuwCXCevuzaFpM2sgyPZxf3H7tWaSKzlvDzx2kmwiWIrFug/yebywv4Cxsl82I5DfZkDpxXRpqTxXrC0Nw==", + "license": "GPL-2.0-or-later", "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/autop": "^4.10.0", - "@wordpress/blob": "^4.10.0", - "@wordpress/block-serialization-default-parser": "^5.10.0", - "@wordpress/data": "^10.10.0", - "@wordpress/deprecated": "^4.10.0", - "@wordpress/dom": "^4.10.0", - "@wordpress/element": "^6.10.0", - "@wordpress/hooks": "^4.10.0", - "@wordpress/html-entities": "^4.10.0", - "@wordpress/i18n": "^5.10.0", - "@wordpress/is-shallow-equal": "^5.10.0", - "@wordpress/private-apis": "^1.10.0", - "@wordpress/rich-text": "^7.10.0", - "@wordpress/shortcode": "^4.10.0", - "@wordpress/warning": "^3.10.0", - "change-case": "^4.1.2", - "colord": "^2.7.0", - "fast-deep-equal": "^3.1.3", - "hpq": "^1.3.0", - "is-plain-object": "^5.0.0", - "memize": "^2.1.0", - "react-is": "^18.3.0", - "remove-accents": "^0.5.0", - "showdown": "^1.9.1", - "simple-html-tokenizer": "^0.5.7", - "uuid": "^9.0.1" + "@babel/runtime": "7.25.7" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/html-entities": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-4.17.0.tgz", + "integrity": "sha512-8cVD8KTxsKLHA9r6Lt3fkQoNBUQ6zMWdgaK1VNRYRJgTfx8C6FlNBjvHrIIgS0nJ43k9iAmAObGQiL3GkGVI1g==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "7.25.7" }, - "peerDependencies": { - "react": "^18.0.0" + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" } }, - "node_modules/@wordpress/fields/node_modules/@wordpress/components": { - "version": "28.13.0", - "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-28.13.0.tgz", - "integrity": "sha512-JaGcXYtFCvHqa62dtxMAMhu6afvefFOuwfUTNiLYg60CA4UDITt6gf+qhpvKNOzVg4qQRw10o/nryrOMoMAEEg==", - "dev": true, + "node_modules/@wordpress/i18n": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.17.0.tgz", + "integrity": "sha512-aAsYls8sTTSEimsvjxBl9mCYbZYD3BddHVpuHgbBxzC+2SZE+JYJ+IpcwEghC712qo0jEkG8Vdzhqae1PL6vCQ==", + "license": "GPL-2.0-or-later", "dependencies": { - "@ariakit/react": "^0.4.10", "@babel/runtime": "7.25.7", - "@emotion/cache": "^11.7.1", - "@emotion/css": "^11.7.1", - "@emotion/react": "^11.7.1", - "@emotion/serialize": "^1.0.2", - "@emotion/styled": "^11.6.0", - "@emotion/utils": "^1.0.0", - "@floating-ui/react-dom": "^2.0.8", - "@types/gradient-parser": "0.1.3", - "@types/highlight-words-core": "1.2.1", - "@use-gesture/react": "^10.3.1", - "@wordpress/a11y": "*", - "@wordpress/compose": "*", - "@wordpress/date": "*", - "@wordpress/deprecated": "*", - "@wordpress/dom": "*", - "@wordpress/element": "*", - "@wordpress/escape-html": "*", - "@wordpress/hooks": "*", - "@wordpress/html-entities": "*", - "@wordpress/i18n": "*", - "@wordpress/icons": "*", - "@wordpress/is-shallow-equal": "*", - "@wordpress/keycodes": "*", - "@wordpress/primitives": "*", - "@wordpress/private-apis": "*", - "@wordpress/rich-text": "*", - "@wordpress/warning": "*", - "change-case": "^4.1.2", - "clsx": "^2.1.1", - "colord": "^2.7.0", - "date-fns": "^3.6.0", - "deepmerge": "^4.3.0", - "fast-deep-equal": "^3.1.3", - "framer-motion": "^11.1.9", - "gradient-parser": "^0.1.5", - "highlight-words-core": "^1.2.2", - "is-plain-object": "^5.0.0", + "@wordpress/hooks": "^4.17.0", + "gettext-parser": "^1.3.1", "memize": "^2.1.0", - "path-to-regexp": "^6.2.1", - "re-resizable": "^6.4.0", - "react-colorful": "^5.3.1", - "remove-accents": "^0.5.0", - "uuid": "^9.0.1" + "sprintf-js": "^1.1.1", + "tannin": "^1.2.0" + }, + "bin": { + "pot-to-php": "tools/pot-to-php.js" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" } }, - "node_modules/@wordpress/fields/node_modules/@wordpress/element": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.10.0.tgz", - "integrity": "sha512-7zW+14vHqEn45nszSLMUqE5IbzOtvgUUgF56qlMhwabpG4l/zhaj3gO3wLDI19C13ih1vOdSjzPc3At4fB3tRQ==", - "dev": true, + "node_modules/@wordpress/icons": { + "version": "10.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-10.17.0.tgz", + "integrity": "sha512-qzWFrMfa5HZdGxGq7I+s9bmUJqZrFfx6ow/slY1USKJqp1uRHRekAbq6UrOrJscs8rSUQiV/aNNPDgSfqBEM6A==", + "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.10.0", - "change-case": "^4.1.2", - "is-plain-object": "^5.0.0", - "react": "^18.3.0", - "react-dom": "^18.3.0" + "@wordpress/element": "^6.17.0", + "@wordpress/primitives": "4.17.0" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" } }, - "node_modules/@wordpress/fields/node_modules/@wordpress/hooks": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-4.10.0.tgz", - "integrity": "sha512-LcorV5Z9XoJCKyj5Ulgw1HPHyM2mxsSInC7wl5cuIgDFmuwPTfRndUDGWz/v86GX1GnUIB0h/ggd53vx1HiW4A==", + "node_modules/@wordpress/interactivity": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/interactivity/-/interactivity-6.17.0.tgz", + "integrity": "sha512-lhDqh0iyfG6DXwYXfg4u0EP9EofRBiVt7Lszn1LIgFFuThHBDyNgePKW6WxZhW9Nrwq9pan7gvCWIx6IKZkg8Q==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { - "@babel/runtime": "7.25.7" + "@preact/signals": "^1.3.0", + "preact": "^10.24.2" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" } }, - "node_modules/@wordpress/fields/node_modules/@wordpress/i18n": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.10.0.tgz", - "integrity": "sha512-HZ6UcMHsjOocDI0zVAuP4JIl97LRmpGo/lVxzVIreaLoYitmYVDUzji02u1o7sEdRWc1Hpkm2/oO/9275rJg1w==", + "node_modules/@wordpress/interface": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@wordpress/interface/-/interface-9.2.0.tgz", + "integrity": "sha512-WO4aWZYFlrqchKpgWttK9PB4xIicdatp4cUX7Diw3b/Zltq4+aE+DddTDeRvqLoi+NdgPlJK/tNxBaU4UoiBlQ==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/hooks": "^4.10.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "tannin": "^1.2.0" + "@wordpress/a11y": "^4.17.0", + "@wordpress/components": "^29.3.0", + "@wordpress/compose": "^7.17.0", + "@wordpress/data": "^10.17.0", + "@wordpress/deprecated": "^4.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/i18n": "5.17.0", + "@wordpress/icons": "10.17.0", + "@wordpress/plugins": "7.17.0", + "@wordpress/preferences": "^4.17.0", + "@wordpress/viewport": "^6.17.0", + "clsx": "^2.1.1" }, - "bin": { - "pot-to-php": "tools/pot-to-php.js" + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, + "node_modules/@wordpress/is-shallow-equal": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-5.17.0.tgz", + "integrity": "sha512-PRykD6MgDkptKsKwETjNHiQUVtaegXkREX6UetN1iL6u+2la4XC/naDHByq7TL+Cg4snyR+PlNdw45Y4dgMf5w==", + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "7.25.7" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" } }, - "node_modules/@wordpress/fields/node_modules/@wordpress/icons": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-10.10.0.tgz", - "integrity": "sha512-41HaxMtq0WZF37mpZ1RQ1s1J3ia5gHFUd/uGhP9p1dhzEFYALxKVTB0Gy3cJhT0CslKeEwYx2XQIP1ZaCKNakQ==", + "node_modules/@wordpress/jest-console": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/@wordpress/jest-console/-/jest-console-8.9.0.tgz", + "integrity": "sha512-0swK5WONAx7y5oPDMBbr38e1R7JR+jPCt6CGFoOEwsVGiSRGa5WqJo09/ysCVjDmJn8po/lBaUp9f+fJSVARDQ==", "dev": true, "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/element": "^6.10.0", - "@wordpress/primitives": "^4.10.0" + "@babel/runtime": "^7.16.0", + "jest-matcher-utils": "^29.6.2" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" + }, + "peerDependencies": { + "jest": ">=29" } }, - "node_modules/@wordpress/fields/node_modules/@wordpress/notices": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/notices/-/notices-5.10.0.tgz", - "integrity": "sha512-7FNcLsX2yV6VHtiJa+Hv++LnC9MgGT5VFHiufnBy6dUmEglwuI7cAgTeWqkL9HY2+eZcwEPU/0zoImCF93Lx+A==", + "node_modules/@wordpress/jest-preset-default": { + "version": "12.9.0", + "resolved": "https://registry.npmjs.org/@wordpress/jest-preset-default/-/jest-preset-default-12.9.0.tgz", + "integrity": "sha512-qWON30SuU9JVZg5+SjExbv8XZVYDCvHGCV3jf5DOtYFw9kfpDZqnePTlroRvUMiD3ksKsKiAAYOOnBOiJUR/bA==", "dev": true, "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/a11y": "^4.10.0", - "@wordpress/data": "^10.10.0" + "@wordpress/jest-console": "^8.9.0", + "babel-jest": "^29.6.2" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" }, "peerDependencies": { - "react": "^18.0.0" + "@babel/core": ">=7", + "jest": ">=29" } }, - "node_modules/@wordpress/fields/node_modules/@wordpress/primitives": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-4.10.0.tgz", - "integrity": "sha512-dmck1VSKbxy7yA5VZhi+jOyb0Hc6QqOxIZ4R139a/Zuzr0xHuuKurh94At/R9UHYP8Dr9YxAlgiF/uQChFzKQg==", + "node_modules/@wordpress/keyboard-shortcuts": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/keyboard-shortcuts/-/keyboard-shortcuts-5.17.0.tgz", + "integrity": "sha512-XQbtiTSq6rsP/5KYMMDCmZegABlqcq7IpLtymrbeQNSPjyAP4aflU0rCcNWaXhBbdWWDRmaU9u/X1/fI5wGxUQ==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/element": "^6.10.0", - "clsx": "^2.1.1" + "@wordpress/data": "10.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/keycodes": "^4.17.0" }, "engines": { "node": ">=18.12.0", @@ -8417,51 +8478,54 @@ "react": "^18.0.0" } }, - "node_modules/@wordpress/fields/node_modules/@wordpress/url": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-4.10.0.tgz", - "integrity": "sha512-SKlXocsTlaSee2trXcB0N3jdIfEGMnPiqNxxvTjeeBmsP/47MMXu5lXYslYyYlQbluhAR5/RMf0o3WqZAF2uOg==", + "node_modules/@wordpress/keyboard-shortcuts/node_modules/@wordpress/keycodes": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.17.0.tgz", + "integrity": "sha512-6aZ28uoCmzjXONpRVtDPjevkw834fhIRBnn2KQdzENMnPiQCNbiG71mPNxkTw1yRHRRT5ptHvOe49ztWm9KMcA==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "remove-accents": "^0.5.0" + "@wordpress/i18n": "5.17.0" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" } }, - "node_modules/@wordpress/hooks": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-4.14.0.tgz", - "integrity": "sha512-Z1JWYBHnYNS5HMF7vAxWO8syGZWEEVtXra/6FtI7Do7rSXleTh2T/j06CqETE7QD47oMIhZOHz+jM8ttR4UlJA==", + "node_modules/@wordpress/keycodes": { + "version": "3.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-3.58.0.tgz", + "integrity": "sha512-Q/LRKpx8ndzuHlkxSQ2BD+NTYYKQPIneNNMng8hTAfyU7RFwXpqj06HpeOFGh4XIdPKCs/8hmucoLJRmmLmZJA==", + "dev": true, "dependencies": { - "@babel/runtime": "7.25.7" + "@babel/runtime": "^7.16.0", + "@wordpress/i18n": "^4.58.0" }, "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" + "node": ">=12" } }, - "node_modules/@wordpress/html-entities": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-4.16.0.tgz", - "integrity": "sha512-wnCtif4GsQ3gZgINN2GK6+yLH+vIsW3ASvUfdUlxYMcvMagNhJsqaE6dqsnKkezD8q/WNL7zv82BDyGSLKeHNQ==", + "node_modules/@wordpress/keycodes/node_modules/@wordpress/hooks": { + "version": "3.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.58.0.tgz", + "integrity": "sha512-9LB0ZHnZRQlORttux9t/xbAskF+dk2ujqzPGsVzc92mSKpQP3K2a5Wy74fUnInguB1vLUNHT6nrNdkVom5qX1Q==", + "dev": true, "dependencies": { - "@babel/runtime": "7.25.7" + "@babel/runtime": "^7.16.0" }, "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" + "node": ">=12" } }, - "node_modules/@wordpress/i18n": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.14.0.tgz", - "integrity": "sha512-2KHyQ+zoyQggokmoTqfVhl2DOM4E11pF/M1+5Q0kUDAHLIAVDhKCzHNPZreHjJld4Tm7hl2HUOutfPmCVudj7g==", + "node_modules/@wordpress/keycodes/node_modules/@wordpress/i18n": { + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.58.0.tgz", + "integrity": "sha512-VfvS3BWv/RDjRKD6PscIcvYfWKnGJcI/DEqyDgUMhxCM6NRwoL478CsUKTiGJIymeyRodNRfprdcF086DpGKYw==", + "dev": true, "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/hooks": "*", + "@babel/runtime": "^7.16.0", + "@wordpress/hooks": "^3.58.0", "gettext-parser": "^1.3.1", "memize": "^2.1.0", "sprintf-js": "^1.1.1", @@ -8471,119 +8535,82 @@ "pot-to-php": "tools/pot-to-php.js" }, "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" + "node": ">=12" } }, - "node_modules/@wordpress/icons": { - "version": "10.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-10.14.0.tgz", - "integrity": "sha512-4S1AaBeqvTpsTC23y0+4WPiSyz7j+b7vJ4vQ4nqnPeBF7ZeC8J/UXWQnEuKY38n8TiutXljgagkEqGNC9pF2Mw==", + "node_modules/@wordpress/media-utils": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/media-utils/-/media-utils-5.17.0.tgz", + "integrity": "sha512-AyTz5C0NxZ69v+rQ3I/g7cPBa9DL8+pBufHZ5Ewz47q6hwSSb3j8+xTgfl/ndKCc/Taqvr4Sgd4QijOUR+iQ3A==", + "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/element": "*", - "@wordpress/primitives": "*" + "@wordpress/api-fetch": "^7.17.0", + "@wordpress/blob": "^4.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/i18n": "5.17.0", + "@wordpress/private-apis": "^1.17.0" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" } }, - "node_modules/@wordpress/interactivity": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/interactivity/-/interactivity-6.14.0.tgz", - "integrity": "sha512-3CuCWxXbbK9nxGoR+2jgSNKYQPnvR6q3+y8cUVVIp61b8a37SWwN6Gxlnea+Sk6CVfY/VJNnt8i4MqFm3O70+Q==", + "node_modules/@wordpress/notices": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/notices/-/notices-5.17.0.tgz", + "integrity": "sha512-1qsRcxE2dnvIJO9IQHnK9D/U/RgRmccDhbNrBxcgOqEVHTFwDambuxte4JXOmJZVr+uqh8Z3ggr+4H6zCjs/9Q==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { - "@preact/signals": "^1.3.0", - "preact": "^10.24.2" + "@babel/runtime": "7.25.7", + "@wordpress/a11y": "^4.17.0", + "@wordpress/data": "^10.17.0" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" + }, + "peerDependencies": { + "react": "^18.0.0" } }, - "node_modules/@wordpress/interface": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@wordpress/interface/-/interface-7.0.0.tgz", - "integrity": "sha512-3MvKLUB00Tzo8sOQeqyqzve3pBR0ajxcsncP9lGzF/JMvS6GUhnvtWXkGQp7RmAUkWE5vE6+i/z4sSIzJad2IA==", + "node_modules/@wordpress/npm-package-json-lint-config": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/@wordpress/npm-package-json-lint-config/-/npm-package-json-lint-config-5.9.0.tgz", + "integrity": "sha512-4sQBUlUzjtYtrM5OC5P4lcyyYbvTDBsPwBk+u11lUI1h/EOOl36TYioEvLut2AGylqzFJKsnbzlL873tfd/5aQ==", "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/a11y": "^4.10.0", - "@wordpress/components": "^28.10.0", - "@wordpress/compose": "^7.10.0", - "@wordpress/data": "^10.10.0", - "@wordpress/deprecated": "^4.10.0", - "@wordpress/element": "6.10.0", - "@wordpress/i18n": "5.10.0", - "@wordpress/icons": "10.10.0", - "@wordpress/plugins": "7.10.0", - "@wordpress/preferences": "^4.10.0", - "@wordpress/private-apis": "^1.10.0", - "@wordpress/viewport": "^6.10.0", - "clsx": "^2.1.1" - }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "npm-package-json-lint": ">=6.0.0" } }, - "node_modules/@wordpress/interface/node_modules/@wordpress/components": { - "version": "28.13.0", - "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-28.13.0.tgz", - "integrity": "sha512-JaGcXYtFCvHqa62dtxMAMhu6afvefFOuwfUTNiLYg60CA4UDITt6gf+qhpvKNOzVg4qQRw10o/nryrOMoMAEEg==", + "node_modules/@wordpress/patterns": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/patterns/-/patterns-2.17.0.tgz", + "integrity": "sha512-NPTYVeBVl7+wcXDP1YJbubVYo3xroExrgbWsH6kpl4sK6f7ZvCa7Ka/Na8WL0MXJbhhpw3S+zeUL8QOxKKeWGg==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { - "@ariakit/react": "^0.4.10", "@babel/runtime": "7.25.7", - "@emotion/cache": "^11.7.1", - "@emotion/css": "^11.7.1", - "@emotion/react": "^11.7.1", - "@emotion/serialize": "^1.0.2", - "@emotion/styled": "^11.6.0", - "@emotion/utils": "^1.0.0", - "@floating-ui/react-dom": "^2.0.8", - "@types/gradient-parser": "0.1.3", - "@types/highlight-words-core": "1.2.1", - "@use-gesture/react": "^10.3.1", - "@wordpress/a11y": "*", - "@wordpress/compose": "*", - "@wordpress/date": "*", - "@wordpress/deprecated": "*", - "@wordpress/dom": "*", - "@wordpress/element": "*", - "@wordpress/escape-html": "*", - "@wordpress/hooks": "*", - "@wordpress/html-entities": "*", - "@wordpress/i18n": "*", - "@wordpress/icons": "*", - "@wordpress/is-shallow-equal": "*", - "@wordpress/keycodes": "*", - "@wordpress/primitives": "*", - "@wordpress/private-apis": "*", - "@wordpress/rich-text": "*", - "@wordpress/warning": "*", - "change-case": "^4.1.2", - "clsx": "^2.1.1", - "colord": "^2.7.0", - "date-fns": "^3.6.0", - "deepmerge": "^4.3.0", - "fast-deep-equal": "^3.1.3", - "framer-motion": "^11.1.9", - "gradient-parser": "^0.1.5", - "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.3.1", - "remove-accents": "^0.5.0", - "uuid": "^9.0.1" + "@wordpress/a11y": "^4.17.0", + "@wordpress/block-editor": "^14.12.0", + "@wordpress/blocks": "^14.6.0", + "@wordpress/components": "^29.3.0", + "@wordpress/compose": "^7.17.0", + "@wordpress/core-data": "^7.17.0", + "@wordpress/data": "^10.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/html-entities": "^4.17.0", + "@wordpress/i18n": "5.17.0", + "@wordpress/icons": "10.17.0", + "@wordpress/notices": "5.17.0", + "@wordpress/private-apis": "^1.17.0", + "@wordpress/url": "4.17.0" }, "engines": { "node": ">=18.12.0", @@ -8594,875 +8621,103 @@ "react-dom": "^18.0.0" } }, - "node_modules/@wordpress/interface/node_modules/@wordpress/element": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.10.0.tgz", - "integrity": "sha512-7zW+14vHqEn45nszSLMUqE5IbzOtvgUUgF56qlMhwabpG4l/zhaj3gO3wLDI19C13ih1vOdSjzPc3At4fB3tRQ==", + "node_modules/@wordpress/plugins": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/plugins/-/plugins-7.17.0.tgz", + "integrity": "sha512-CoVDWqUq3gXiv8TFJz+vFvTuAvbq2h0Ct8ciH+tGi7SykhA35GqnCcfR/aKDOlAXHGpD0vwxV0iv08kmhIVQ/A==", "dev": true, + "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.10.0", - "change-case": "^4.1.2", - "is-plain-object": "^5.0.0", - "react": "^18.3.0", - "react-dom": "^18.3.0" + "@wordpress/components": "^29.3.0", + "@wordpress/compose": "^7.17.0", + "@wordpress/deprecated": "^4.17.0", + "@wordpress/element": "^6.17.0", + "@wordpress/hooks": "^4.17.0", + "@wordpress/icons": "^10.17.0", + "@wordpress/is-shallow-equal": "^5.17.0", + "memize": "^2.0.1" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, - "node_modules/@wordpress/interface/node_modules/@wordpress/i18n": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.10.0.tgz", - "integrity": "sha512-HZ6UcMHsjOocDI0zVAuP4JIl97LRmpGo/lVxzVIreaLoYitmYVDUzji02u1o7sEdRWc1Hpkm2/oO/9275rJg1w==", + "node_modules/@wordpress/postcss-plugins-preset": { + "version": "5.9.0", + "resolved": "https://registry.npmjs.org/@wordpress/postcss-plugins-preset/-/postcss-plugins-preset-5.9.0.tgz", + "integrity": "sha512-OOK5UU2CG+9ilzo1b8ySwVvtZddF+q+PTTFHcxFrcK23sg5XT1DCBm3WU7bSfzOBF2cd4FIVOFVpwvb07mn8Iw==", "dev": true, "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/hooks": "^4.10.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "tannin": "^1.2.0" - }, - "bin": { - "pot-to-php": "tools/pot-to-php.js" + "@wordpress/base-styles": "^5.9.0", + "autoprefixer": "^10.2.5" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" + }, + "peerDependencies": { + "postcss": "^8.0.0" } }, - "node_modules/@wordpress/interface/node_modules/@wordpress/icons": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-10.10.0.tgz", - "integrity": "sha512-41HaxMtq0WZF37mpZ1RQ1s1J3ia5gHFUd/uGhP9p1dhzEFYALxKVTB0Gy3cJhT0CslKeEwYx2XQIP1ZaCKNakQ==", + "node_modules/@wordpress/preferences": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/preferences/-/preferences-4.17.0.tgz", + "integrity": "sha512-jNyHhuar2RflBJ9JqGs0ZQXnU86URCQXlR4syXzZdVU75Sm1fPByqKDtR9/F/bWnPxLlU1uP89SKv54kGpSM4Q==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/element": "^6.10.0", - "@wordpress/primitives": "^4.10.0" + "@wordpress/a11y": "^4.17.0", + "@wordpress/components": "29.3.0", + "@wordpress/compose": "7.17.0", + "@wordpress/data": "10.17.0", + "@wordpress/deprecated": "^4.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/i18n": "5.17.0", + "@wordpress/icons": "10.17.0", + "@wordpress/private-apis": "^1.17.0", + "clsx": "^2.1.1" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, - "node_modules/@wordpress/interface/node_modules/@wordpress/plugins": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/plugins/-/plugins-7.10.0.tgz", - "integrity": "sha512-CwE9ze9SZWvqddWL81j/DybTHWyGJNd9hi6ss0WLtEP0UghaYTVgO2TF8GbxSZv9yjXtrRhBXe56stavK35L5A==", - "dev": true, + "node_modules/@wordpress/primitives": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-4.17.0.tgz", + "integrity": "sha512-O1dysI/Y9xv5uUMllH2VIxuBDCOVUX8WmouE9KKr11Yv4gkHzxzaU2M5rFtu7RbUCv6jtkvjidy2cuZuNpEIHQ==", + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/components": "^28.10.0", - "@wordpress/compose": "^7.10.0", - "@wordpress/element": "^6.10.0", - "@wordpress/hooks": "^4.10.0", - "@wordpress/icons": "^10.10.0", - "@wordpress/is-shallow-equal": "^5.10.0", - "memize": "^2.0.1" + "@wordpress/element": "^6.17.0", + "clsx": "^2.1.1" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" }, "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^18.0.0" } }, - "node_modules/@wordpress/is-shallow-equal": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-5.16.0.tgz", - "integrity": "sha512-9JI0bz7bQ9PdXPtXSnZXtbkyh0h7ZtojeG0lFtf9xtFkA56JUuMALa623v1YeuHKYbYmCc03/pqtpDKc/8QfVQ==", + "node_modules/@wordpress/priority-queue": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-3.17.0.tgz", + "integrity": "sha512-WzQHNx6wjgbxhuaKErjIRLSL9E9La8slsAXRTQPmkgvKqa11Rh4RYl2FLUh8tABK3xo5HzaHCplkZSm2q5wlbg==", + "license": "GPL-2.0-or-later", "dependencies": { - "@babel/runtime": "7.25.7" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/jest-console": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/@wordpress/jest-console/-/jest-console-8.9.0.tgz", - "integrity": "sha512-0swK5WONAx7y5oPDMBbr38e1R7JR+jPCt6CGFoOEwsVGiSRGa5WqJo09/ysCVjDmJn8po/lBaUp9f+fJSVARDQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.16.0", - "jest-matcher-utils": "^29.6.2" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "jest": ">=29" - } - }, - "node_modules/@wordpress/jest-preset-default": { - "version": "12.9.0", - "resolved": "https://registry.npmjs.org/@wordpress/jest-preset-default/-/jest-preset-default-12.9.0.tgz", - "integrity": "sha512-qWON30SuU9JVZg5+SjExbv8XZVYDCvHGCV3jf5DOtYFw9kfpDZqnePTlroRvUMiD3ksKsKiAAYOOnBOiJUR/bA==", - "dev": true, - "dependencies": { - "@wordpress/jest-console": "^8.9.0", - "babel-jest": "^29.6.2" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "@babel/core": ">=7", - "jest": ">=29" - } - }, - "node_modules/@wordpress/keyboard-shortcuts": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/keyboard-shortcuts/-/keyboard-shortcuts-5.10.0.tgz", - "integrity": "sha512-TEzKDfbRWNemcPeujFg88oYgqk8M0Edc+mzVG52O3ydAfPdd7Q5QKlDtjXJyOM4egaSmDs/j1kzbjwkTFw+zLA==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/data": "10.10.0", - "@wordpress/element": "6.10.0", - "@wordpress/keycodes": "^4.10.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "react": "^18.0.0" - } - }, - "node_modules/@wordpress/keyboard-shortcuts/node_modules/@wordpress/data": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-10.10.0.tgz", - "integrity": "sha512-oyYl89p86+U9W6vKDqScKhUGKKzsnETj9rg8zOnT4K9ceOScjGCgdCE+XxcY9exeRg33aSYDjmvnsXXYStBYmA==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/compose": "^7.10.0", - "@wordpress/deprecated": "^4.10.0", - "@wordpress/element": "^6.10.0", - "@wordpress/is-shallow-equal": "^5.10.0", - "@wordpress/priority-queue": "^3.10.0", - "@wordpress/private-apis": "^1.10.0", - "@wordpress/redux-routine": "^5.10.0", - "deepmerge": "^4.3.0", - "equivalent-key-map": "^0.2.2", - "is-plain-object": "^5.0.0", - "is-promise": "^4.0.0", - "redux": "^4.1.2", - "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/keyboard-shortcuts/node_modules/@wordpress/element": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.10.0.tgz", - "integrity": "sha512-7zW+14vHqEn45nszSLMUqE5IbzOtvgUUgF56qlMhwabpG4l/zhaj3gO3wLDI19C13ih1vOdSjzPc3At4fB3tRQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@types/react": "^18.2.79", - "@types/react-dom": "^18.2.25", - "@wordpress/escape-html": "^3.10.0", - "change-case": "^4.1.2", - "is-plain-object": "^5.0.0", - "react": "^18.3.0", - "react-dom": "^18.3.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/keyboard-shortcuts/node_modules/@wordpress/i18n": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.10.0.tgz", - "integrity": "sha512-HZ6UcMHsjOocDI0zVAuP4JIl97LRmpGo/lVxzVIreaLoYitmYVDUzji02u1o7sEdRWc1Hpkm2/oO/9275rJg1w==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/hooks": "^4.10.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "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/keyboard-shortcuts/node_modules/@wordpress/keycodes": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.10.0.tgz", - "integrity": "sha512-2i+N90HBMqQegtGqeVB8pJz8ZgKAY1eZmQegE9MXczYVac85DDOoxhY/41c44s6Kwl3waJ2Zght6UXE0OUFMxw==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/i18n": "5.10.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/keycodes": { - "version": "3.58.0", - "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-3.58.0.tgz", - "integrity": "sha512-Q/LRKpx8ndzuHlkxSQ2BD+NTYYKQPIneNNMng8hTAfyU7RFwXpqj06HpeOFGh4XIdPKCs/8hmucoLJRmmLmZJA==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.16.0", - "@wordpress/i18n": "^4.58.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@wordpress/keycodes/node_modules/@wordpress/hooks": { - "version": "3.58.0", - "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.58.0.tgz", - "integrity": "sha512-9LB0ZHnZRQlORttux9t/xbAskF+dk2ujqzPGsVzc92mSKpQP3K2a5Wy74fUnInguB1vLUNHT6nrNdkVom5qX1Q==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.16.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@wordpress/keycodes/node_modules/@wordpress/i18n": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.58.0.tgz", - "integrity": "sha512-VfvS3BWv/RDjRKD6PscIcvYfWKnGJcI/DEqyDgUMhxCM6NRwoL478CsUKTiGJIymeyRodNRfprdcF086DpGKYw==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.16.0", - "@wordpress/hooks": "^3.58.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "tannin": "^1.2.0" - }, - "bin": { - "pot-to-php": "tools/pot-to-php.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@wordpress/media-utils": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/media-utils/-/media-utils-5.10.0.tgz", - "integrity": "sha512-esHDnXZ5QJ+EftRL56td7aomBvPvlTRGbb1JauQaquYVm7Fr8br+qBRpFG1hXlCAp7dpUnXN/aTnrazO2rbh9g==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/api-fetch": "^7.10.0", - "@wordpress/blob": "^4.10.0", - "@wordpress/element": "6.10.0", - "@wordpress/i18n": "5.10.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/media-utils/node_modules/@wordpress/element": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.10.0.tgz", - "integrity": "sha512-7zW+14vHqEn45nszSLMUqE5IbzOtvgUUgF56qlMhwabpG4l/zhaj3gO3wLDI19C13ih1vOdSjzPc3At4fB3tRQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@types/react": "^18.2.79", - "@types/react-dom": "^18.2.25", - "@wordpress/escape-html": "^3.10.0", - "change-case": "^4.1.2", - "is-plain-object": "^5.0.0", - "react": "^18.3.0", - "react-dom": "^18.3.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/media-utils/node_modules/@wordpress/i18n": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.10.0.tgz", - "integrity": "sha512-HZ6UcMHsjOocDI0zVAuP4JIl97LRmpGo/lVxzVIreaLoYitmYVDUzji02u1o7sEdRWc1Hpkm2/oO/9275rJg1w==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/hooks": "^4.10.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "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/notices": { - "version": "5.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/notices/-/notices-5.14.0.tgz", - "integrity": "sha512-Lo6KQJcIFZkHZv8qep5w8bETqmWAjnq6GFk8DZvKfaQQgxkjfAVNTjegQ0huR70BBlk/ICaL5o/4DCZ23gtnxw==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/a11y": "*", - "@wordpress/data": "*" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "react": "^18.0.0" - } - }, - "node_modules/@wordpress/npm-package-json-lint-config": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@wordpress/npm-package-json-lint-config/-/npm-package-json-lint-config-5.9.0.tgz", - "integrity": "sha512-4sQBUlUzjtYtrM5OC5P4lcyyYbvTDBsPwBk+u11lUI1h/EOOl36TYioEvLut2AGylqzFJKsnbzlL873tfd/5aQ==", - "dev": true, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "npm-package-json-lint": ">=6.0.0" - } - }, - "node_modules/@wordpress/patterns": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/patterns/-/patterns-2.10.0.tgz", - "integrity": "sha512-HHyy05h/WdqMRJGZeocWWvqeVd616mFXEetvXJtaOEdwWuaDjLonXEvQe0St8SfNQ5KiWpkUEoz4tWsy24VD8A==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/a11y": "^4.10.0", - "@wordpress/block-editor": "^14.5.0", - "@wordpress/blocks": "^13.10.0", - "@wordpress/components": "^28.10.0", - "@wordpress/compose": "^7.10.0", - "@wordpress/core-data": "^7.10.0", - "@wordpress/data": "^10.10.0", - "@wordpress/element": "6.10.0", - "@wordpress/html-entities": "^4.10.0", - "@wordpress/i18n": "5.10.0", - "@wordpress/icons": "10.10.0", - "@wordpress/notices": "5.10.0", - "@wordpress/private-apis": "^1.10.0", - "@wordpress/url": "4.10.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@wordpress/patterns/node_modules/@wordpress/blocks": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/blocks/-/blocks-13.10.0.tgz", - "integrity": "sha512-Csfw4BgrPEry1OGE0iHSHJlSbao1IA8ujaE8H0LjAXCvMHXET11avSVvFwuYOaDbeSVi2TD50xA+UpMiJnEo4A==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/autop": "^4.10.0", - "@wordpress/blob": "^4.10.0", - "@wordpress/block-serialization-default-parser": "^5.10.0", - "@wordpress/data": "^10.10.0", - "@wordpress/deprecated": "^4.10.0", - "@wordpress/dom": "^4.10.0", - "@wordpress/element": "^6.10.0", - "@wordpress/hooks": "^4.10.0", - "@wordpress/html-entities": "^4.10.0", - "@wordpress/i18n": "^5.10.0", - "@wordpress/is-shallow-equal": "^5.10.0", - "@wordpress/private-apis": "^1.10.0", - "@wordpress/rich-text": "^7.10.0", - "@wordpress/shortcode": "^4.10.0", - "@wordpress/warning": "^3.10.0", - "change-case": "^4.1.2", - "colord": "^2.7.0", - "fast-deep-equal": "^3.1.3", - "hpq": "^1.3.0", - "is-plain-object": "^5.0.0", - "memize": "^2.1.0", - "react-is": "^18.3.0", - "remove-accents": "^0.5.0", - "showdown": "^1.9.1", - "simple-html-tokenizer": "^0.5.7", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "react": "^18.0.0" - } - }, - "node_modules/@wordpress/patterns/node_modules/@wordpress/components": { - "version": "28.13.0", - "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-28.13.0.tgz", - "integrity": "sha512-JaGcXYtFCvHqa62dtxMAMhu6afvefFOuwfUTNiLYg60CA4UDITt6gf+qhpvKNOzVg4qQRw10o/nryrOMoMAEEg==", - "dev": true, - "dependencies": { - "@ariakit/react": "^0.4.10", - "@babel/runtime": "7.25.7", - "@emotion/cache": "^11.7.1", - "@emotion/css": "^11.7.1", - "@emotion/react": "^11.7.1", - "@emotion/serialize": "^1.0.2", - "@emotion/styled": "^11.6.0", - "@emotion/utils": "^1.0.0", - "@floating-ui/react-dom": "^2.0.8", - "@types/gradient-parser": "0.1.3", - "@types/highlight-words-core": "1.2.1", - "@use-gesture/react": "^10.3.1", - "@wordpress/a11y": "*", - "@wordpress/compose": "*", - "@wordpress/date": "*", - "@wordpress/deprecated": "*", - "@wordpress/dom": "*", - "@wordpress/element": "*", - "@wordpress/escape-html": "*", - "@wordpress/hooks": "*", - "@wordpress/html-entities": "*", - "@wordpress/i18n": "*", - "@wordpress/icons": "*", - "@wordpress/is-shallow-equal": "*", - "@wordpress/keycodes": "*", - "@wordpress/primitives": "*", - "@wordpress/private-apis": "*", - "@wordpress/rich-text": "*", - "@wordpress/warning": "*", - "change-case": "^4.1.2", - "clsx": "^2.1.1", - "colord": "^2.7.0", - "date-fns": "^3.6.0", - "deepmerge": "^4.3.0", - "fast-deep-equal": "^3.1.3", - "framer-motion": "^11.1.9", - "gradient-parser": "^0.1.5", - "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.3.1", - "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/patterns/node_modules/@wordpress/element": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.10.0.tgz", - "integrity": "sha512-7zW+14vHqEn45nszSLMUqE5IbzOtvgUUgF56qlMhwabpG4l/zhaj3gO3wLDI19C13ih1vOdSjzPc3At4fB3tRQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@types/react": "^18.2.79", - "@types/react-dom": "^18.2.25", - "@wordpress/escape-html": "^3.10.0", - "change-case": "^4.1.2", - "is-plain-object": "^5.0.0", - "react": "^18.3.0", - "react-dom": "^18.3.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/patterns/node_modules/@wordpress/i18n": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.10.0.tgz", - "integrity": "sha512-HZ6UcMHsjOocDI0zVAuP4JIl97LRmpGo/lVxzVIreaLoYitmYVDUzji02u1o7sEdRWc1Hpkm2/oO/9275rJg1w==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/hooks": "^4.10.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "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/patterns/node_modules/@wordpress/icons": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-10.10.0.tgz", - "integrity": "sha512-41HaxMtq0WZF37mpZ1RQ1s1J3ia5gHFUd/uGhP9p1dhzEFYALxKVTB0Gy3cJhT0CslKeEwYx2XQIP1ZaCKNakQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/element": "^6.10.0", - "@wordpress/primitives": "^4.10.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/patterns/node_modules/@wordpress/notices": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/notices/-/notices-5.10.0.tgz", - "integrity": "sha512-7FNcLsX2yV6VHtiJa+Hv++LnC9MgGT5VFHiufnBy6dUmEglwuI7cAgTeWqkL9HY2+eZcwEPU/0zoImCF93Lx+A==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/a11y": "^4.10.0", - "@wordpress/data": "^10.10.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "react": "^18.0.0" - } - }, - "node_modules/@wordpress/patterns/node_modules/@wordpress/url": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-4.10.0.tgz", - "integrity": "sha512-SKlXocsTlaSee2trXcB0N3jdIfEGMnPiqNxxvTjeeBmsP/47MMXu5lXYslYyYlQbluhAR5/RMf0o3WqZAF2uOg==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "remove-accents": "^0.5.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/plugins": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/plugins/-/plugins-7.14.0.tgz", - "integrity": "sha512-c8ncDg1pKcCv1Ba9U+kBmlC1t9iqg+I0LJXL6Sj0ZY4fB0DgFhg3bZYK8rwjI7tUQU+VCK28bu4gnd2B/R0nUA==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/components": "*", - "@wordpress/compose": "*", - "@wordpress/deprecated": "*", - "@wordpress/element": "*", - "@wordpress/hooks": "*", - "@wordpress/icons": "*", - "@wordpress/is-shallow-equal": "*", - "memize": "^2.0.1" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@wordpress/postcss-plugins-preset": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/@wordpress/postcss-plugins-preset/-/postcss-plugins-preset-5.9.0.tgz", - "integrity": "sha512-OOK5UU2CG+9ilzo1b8ySwVvtZddF+q+PTTFHcxFrcK23sg5XT1DCBm3WU7bSfzOBF2cd4FIVOFVpwvb07mn8Iw==", - "dev": true, - "dependencies": { - "@wordpress/base-styles": "^5.9.0", - "autoprefixer": "^10.2.5" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/@wordpress/preferences": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/preferences/-/preferences-4.10.0.tgz", - "integrity": "sha512-QrqsJXJsu7BcHWgH/QCnjOSfDRg50NFcHQpBrsnULumPgUGlkZZraqkuCMKss57N1dqPjQWnc3819JmxzqZBaQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/a11y": "^4.10.0", - "@wordpress/components": "28.10.0", - "@wordpress/compose": "7.10.0", - "@wordpress/data": "10.10.0", - "@wordpress/deprecated": "^4.10.0", - "@wordpress/element": "6.10.0", - "@wordpress/i18n": "5.10.0", - "@wordpress/icons": "10.10.0", - "@wordpress/private-apis": "^1.10.0", - "clsx": "^2.1.1" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@wordpress/preferences/node_modules/@wordpress/components": { - "version": "28.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-28.10.0.tgz", - "integrity": "sha512-w5mteCe9qOBMgD8d80QBVOPk0YAquUkMD9o3jDvdqUwiTcVgxn4QSKjh65NGYotvMhDsgsMTq+qgifAB+ubepg==", - "dev": true, - "dependencies": { - "@ariakit/react": "^0.4.10", - "@babel/runtime": "7.25.7", - "@emotion/cache": "^11.7.1", - "@emotion/css": "^11.7.1", - "@emotion/react": "^11.7.1", - "@emotion/serialize": "^1.0.2", - "@emotion/styled": "^11.6.0", - "@emotion/utils": "^1.0.0", - "@floating-ui/react-dom": "^2.0.8", - "@types/gradient-parser": "0.1.3", - "@types/highlight-words-core": "1.2.1", - "@use-gesture/react": "^10.3.1", - "@wordpress/a11y": "^4.10.0", - "@wordpress/compose": "^7.10.0", - "@wordpress/date": "^5.10.0", - "@wordpress/deprecated": "^4.10.0", - "@wordpress/dom": "^4.10.0", - "@wordpress/element": "^6.10.0", - "@wordpress/escape-html": "^3.10.0", - "@wordpress/hooks": "^4.10.0", - "@wordpress/html-entities": "^4.10.0", - "@wordpress/i18n": "^5.10.0", - "@wordpress/icons": "^10.10.0", - "@wordpress/is-shallow-equal": "^5.10.0", - "@wordpress/keycodes": "^4.10.0", - "@wordpress/primitives": "^4.10.0", - "@wordpress/private-apis": "^1.10.0", - "@wordpress/rich-text": "^7.10.0", - "@wordpress/warning": "^3.10.0", - "change-case": "^4.1.2", - "clsx": "^2.1.1", - "colord": "^2.7.0", - "date-fns": "^3.6.0", - "deepmerge": "^4.3.0", - "fast-deep-equal": "^3.1.3", - "framer-motion": "^11.1.9", - "gradient-parser": "^0.1.5", - "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.3.1", - "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/preferences/node_modules/@wordpress/compose": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-7.10.0.tgz", - "integrity": "sha512-/j4+wXthaV/KMt0VANvhhRJEJfPc21c7Tq1ZeLxgsbkq4xmi9qXeDT91cvP/U+Ta3phf15K8vdxMr8MqHHiFoQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@types/mousetrap": "^1.6.8", - "@wordpress/deprecated": "^4.10.0", - "@wordpress/dom": "^4.10.0", - "@wordpress/element": "^6.10.0", - "@wordpress/is-shallow-equal": "^5.10.0", - "@wordpress/keycodes": "^4.10.0", - "@wordpress/priority-queue": "^3.10.0", - "@wordpress/undo-manager": "^1.10.0", - "change-case": "^4.1.2", - "clipboard": "^2.0.11", - "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/preferences/node_modules/@wordpress/data": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-10.10.0.tgz", - "integrity": "sha512-oyYl89p86+U9W6vKDqScKhUGKKzsnETj9rg8zOnT4K9ceOScjGCgdCE+XxcY9exeRg33aSYDjmvnsXXYStBYmA==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/compose": "^7.10.0", - "@wordpress/deprecated": "^4.10.0", - "@wordpress/element": "^6.10.0", - "@wordpress/is-shallow-equal": "^5.10.0", - "@wordpress/priority-queue": "^3.10.0", - "@wordpress/private-apis": "^1.10.0", - "@wordpress/redux-routine": "^5.10.0", - "deepmerge": "^4.3.0", - "equivalent-key-map": "^0.2.2", - "is-plain-object": "^5.0.0", - "is-promise": "^4.0.0", - "redux": "^4.1.2", - "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/preferences/node_modules/@wordpress/element": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.10.0.tgz", - "integrity": "sha512-7zW+14vHqEn45nszSLMUqE5IbzOtvgUUgF56qlMhwabpG4l/zhaj3gO3wLDI19C13ih1vOdSjzPc3At4fB3tRQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@types/react": "^18.2.79", - "@types/react-dom": "^18.2.25", - "@wordpress/escape-html": "^3.10.0", - "change-case": "^4.1.2", - "is-plain-object": "^5.0.0", - "react": "^18.3.0", - "react-dom": "^18.3.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/preferences/node_modules/@wordpress/i18n": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.10.0.tgz", - "integrity": "sha512-HZ6UcMHsjOocDI0zVAuP4JIl97LRmpGo/lVxzVIreaLoYitmYVDUzji02u1o7sEdRWc1Hpkm2/oO/9275rJg1w==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/hooks": "^4.10.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "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/preferences/node_modules/@wordpress/icons": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-10.10.0.tgz", - "integrity": "sha512-41HaxMtq0WZF37mpZ1RQ1s1J3ia5gHFUd/uGhP9p1dhzEFYALxKVTB0Gy3cJhT0CslKeEwYx2XQIP1ZaCKNakQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/element": "^6.10.0", - "@wordpress/primitives": "^4.10.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/preferences/node_modules/@wordpress/keycodes": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.14.0.tgz", - "integrity": "sha512-vZpK+NbhC+3/JK8S5I/PuJMNYhfn7X8pupTPuEiKIXZgcnXAy3mORgirBeZJNkNUXRl3vfcsq0qFnIovI96fHA==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/i18n": "*" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/primitives": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-4.14.0.tgz", - "integrity": "sha512-IZibRVbvWoIQ+uynH0N5bmfWz83hD8lJj6jJFhSFuALK+4U5mRGg6tl0ZV0YllR6cjheD9UhTmfrAcOx+gQAjA==", - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/element": "*", - "clsx": "^2.1.1" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "react": "^18.0.0" - } - }, - "node_modules/@wordpress/priority-queue": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-3.16.0.tgz", - "integrity": "sha512-YmVPE/kHmAIEYiSnnfxQI7JBAvXxlCyVoGlfWxCJ/IH8W7gbZtl1R+iuRvT8L4Cdr+sUybT68Ry+o4o39OqURg==", - "dependencies": { - "@babel/runtime": "7.25.7", - "requestidlecallback": "^0.3.0" + "@babel/runtime": "7.25.7", + "requestidlecallback": "^0.3.0" }, "engines": { "node": ">=18.12.0", @@ -9470,9 +8725,10 @@ } }, "node_modules/@wordpress/private-apis": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-1.16.0.tgz", - "integrity": "sha512-k/AQ11+vlbpSWhyOU5t8huoGdN+PursA8bUxVfhEnqcKRWTK+LKSmSEpdyL1sv6XJqznWYjgaNSdIxTkadsPpg==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-1.17.0.tgz", + "integrity": "sha512-9NGPyuUvtJD0OjWJ/Cn+6Qhjb8hXhiJH4i80W7MFVHRgUZLc/Tu5BOg2+OnXMRSePbgYivo1NLEukqdXqse5IA==", + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7" }, @@ -9482,9 +8738,10 @@ } }, "node_modules/@wordpress/redux-routine": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/redux-routine/-/redux-routine-5.16.0.tgz", - "integrity": "sha512-piLnJnV+tzWOEPJPdp431TcaKRoCpgGJ309W+UxM7fRHrYH/XZcXD8a+0pq56Dh/1QFO1elXXhPzhZQknwtyYw==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/redux-routine/-/redux-routine-5.17.0.tgz", + "integrity": "sha512-RBUNOp+wSweymRB0+fThv1HKUf1c8GVMUT/Xv0kqtrRsGFD70ciwnnfVXnPY0V6po9Uzj5Bb4+2qO/l/e2IwXw==", + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", "is-plain-object": "^5.0.0", @@ -9500,126 +8757,24 @@ } }, "node_modules/@wordpress/reusable-blocks": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/reusable-blocks/-/reusable-blocks-5.10.0.tgz", - "integrity": "sha512-B9T1nJWTVbtgbvrbsmoBvhDLz9VSSdt62Ttej8o3HfphqmWTu9OGkdk5TcHiWzDDro/PZc/X7yhI4Vzk+ihWkg==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/block-editor": "^14.5.0", - "@wordpress/blocks": "^13.10.0", - "@wordpress/components": "^28.10.0", - "@wordpress/core-data": "^7.10.0", - "@wordpress/data": "^10.10.0", - "@wordpress/element": "6.10.0", - "@wordpress/i18n": "5.10.0", - "@wordpress/icons": "10.10.0", - "@wordpress/notices": "5.10.0", - "@wordpress/private-apis": "^1.10.0", - "@wordpress/url": "4.10.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@wordpress/reusable-blocks/node_modules/@wordpress/blocks": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/blocks/-/blocks-13.10.0.tgz", - "integrity": "sha512-Csfw4BgrPEry1OGE0iHSHJlSbao1IA8ujaE8H0LjAXCvMHXET11avSVvFwuYOaDbeSVi2TD50xA+UpMiJnEo4A==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/autop": "^4.10.0", - "@wordpress/blob": "^4.10.0", - "@wordpress/block-serialization-default-parser": "^5.10.0", - "@wordpress/data": "^10.10.0", - "@wordpress/deprecated": "^4.10.0", - "@wordpress/dom": "^4.10.0", - "@wordpress/element": "^6.10.0", - "@wordpress/hooks": "^4.10.0", - "@wordpress/html-entities": "^4.10.0", - "@wordpress/i18n": "^5.10.0", - "@wordpress/is-shallow-equal": "^5.10.0", - "@wordpress/private-apis": "^1.10.0", - "@wordpress/rich-text": "^7.10.0", - "@wordpress/shortcode": "^4.10.0", - "@wordpress/warning": "^3.10.0", - "change-case": "^4.1.2", - "colord": "^2.7.0", - "fast-deep-equal": "^3.1.3", - "hpq": "^1.3.0", - "is-plain-object": "^5.0.0", - "memize": "^2.1.0", - "react-is": "^18.3.0", - "remove-accents": "^0.5.0", - "showdown": "^1.9.1", - "simple-html-tokenizer": "^0.5.7", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "react": "^18.0.0" - } - }, - "node_modules/@wordpress/reusable-blocks/node_modules/@wordpress/components": { - "version": "28.13.0", - "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-28.13.0.tgz", - "integrity": "sha512-JaGcXYtFCvHqa62dtxMAMhu6afvefFOuwfUTNiLYg60CA4UDITt6gf+qhpvKNOzVg4qQRw10o/nryrOMoMAEEg==", + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/reusable-blocks/-/reusable-blocks-5.17.0.tgz", + "integrity": "sha512-VxKBz1KZCTSnhdiaoNbcQrFW9dqRNEkGP60guWqqFlSYl5SpPqulwhtNCpfIw2Z9z8oYMGa7/2JO64WiVeYwGA==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { - "@ariakit/react": "^0.4.10", "@babel/runtime": "7.25.7", - "@emotion/cache": "^11.7.1", - "@emotion/css": "^11.7.1", - "@emotion/react": "^11.7.1", - "@emotion/serialize": "^1.0.2", - "@emotion/styled": "^11.6.0", - "@emotion/utils": "^1.0.0", - "@floating-ui/react-dom": "^2.0.8", - "@types/gradient-parser": "0.1.3", - "@types/highlight-words-core": "1.2.1", - "@use-gesture/react": "^10.3.1", - "@wordpress/a11y": "*", - "@wordpress/compose": "*", - "@wordpress/date": "*", - "@wordpress/deprecated": "*", - "@wordpress/dom": "*", - "@wordpress/element": "*", - "@wordpress/escape-html": "*", - "@wordpress/hooks": "*", - "@wordpress/html-entities": "*", - "@wordpress/i18n": "*", - "@wordpress/icons": "*", - "@wordpress/is-shallow-equal": "*", - "@wordpress/keycodes": "*", - "@wordpress/primitives": "*", - "@wordpress/private-apis": "*", - "@wordpress/rich-text": "*", - "@wordpress/warning": "*", - "change-case": "^4.1.2", - "clsx": "^2.1.1", - "colord": "^2.7.0", - "date-fns": "^3.6.0", - "deepmerge": "^4.3.0", - "fast-deep-equal": "^3.1.3", - "framer-motion": "^11.1.9", - "gradient-parser": "^0.1.5", - "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.3.1", - "remove-accents": "^0.5.0", - "uuid": "^9.0.1" + "@wordpress/block-editor": "^14.12.0", + "@wordpress/blocks": "^14.6.0", + "@wordpress/components": "^29.3.0", + "@wordpress/core-data": "^7.17.0", + "@wordpress/data": "^10.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/i18n": "5.17.0", + "@wordpress/icons": "10.17.0", + "@wordpress/notices": "5.17.0", + "@wordpress/private-apis": "^1.17.0", + "@wordpress/url": "4.17.0" }, "engines": { "node": ">=18.12.0", @@ -9630,71 +8785,22 @@ "react-dom": "^18.0.0" } }, - "node_modules/@wordpress/reusable-blocks/node_modules/@wordpress/element": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.10.0.tgz", - "integrity": "sha512-7zW+14vHqEn45nszSLMUqE5IbzOtvgUUgF56qlMhwabpG4l/zhaj3gO3wLDI19C13ih1vOdSjzPc3At4fB3tRQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@types/react": "^18.2.79", - "@types/react-dom": "^18.2.25", - "@wordpress/escape-html": "^3.10.0", - "change-case": "^4.1.2", - "is-plain-object": "^5.0.0", - "react": "^18.3.0", - "react-dom": "^18.3.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/reusable-blocks/node_modules/@wordpress/i18n": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.10.0.tgz", - "integrity": "sha512-HZ6UcMHsjOocDI0zVAuP4JIl97LRmpGo/lVxzVIreaLoYitmYVDUzji02u1o7sEdRWc1Hpkm2/oO/9275rJg1w==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/hooks": "^4.10.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "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/reusable-blocks/node_modules/@wordpress/icons": { - "version": "10.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-10.10.0.tgz", - "integrity": "sha512-41HaxMtq0WZF37mpZ1RQ1s1J3ia5gHFUd/uGhP9p1dhzEFYALxKVTB0Gy3cJhT0CslKeEwYx2XQIP1ZaCKNakQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/element": "^6.10.0", - "@wordpress/primitives": "^4.10.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/reusable-blocks/node_modules/@wordpress/notices": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/notices/-/notices-5.10.0.tgz", - "integrity": "sha512-7FNcLsX2yV6VHtiJa+Hv++LnC9MgGT5VFHiufnBy6dUmEglwuI7cAgTeWqkL9HY2+eZcwEPU/0zoImCF93Lx+A==", - "dev": true, + "node_modules/@wordpress/rich-text": { + "version": "7.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-7.17.0.tgz", + "integrity": "sha512-HEmApVDjConxYe3cP8P+Zs0xLJZPMhfWal38MQmFelQtCNk+kT0IBg5SkFAcWYY+c4gzhK+dMKawc72uWDfm8w==", + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/a11y": "^4.10.0", - "@wordpress/data": "^10.10.0" + "@wordpress/a11y": "^4.17.0", + "@wordpress/compose": "^7.17.0", + "@wordpress/data": "^10.17.0", + "@wordpress/deprecated": "^4.17.0", + "@wordpress/element": "^6.17.0", + "@wordpress/escape-html": "^3.17.0", + "@wordpress/i18n": "^5.17.0", + "@wordpress/keycodes": "^4.17.0", + "memize": "^2.1.0" }, "engines": { "node": ">=18.12.0", @@ -9704,35 +8810,34 @@ "react": "^18.0.0" } }, - "node_modules/@wordpress/reusable-blocks/node_modules/@wordpress/url": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-4.10.0.tgz", - "integrity": "sha512-SKlXocsTlaSee2trXcB0N3jdIfEGMnPiqNxxvTjeeBmsP/47MMXu5lXYslYyYlQbluhAR5/RMf0o3WqZAF2uOg==", - "dev": true, + "node_modules/@wordpress/rich-text/node_modules/@wordpress/keycodes": { + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.17.0.tgz", + "integrity": "sha512-6aZ28uoCmzjXONpRVtDPjevkw834fhIRBnn2KQdzENMnPiQCNbiG71mPNxkTw1yRHRRT5ptHvOe49ztWm9KMcA==", + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "remove-accents": "^0.5.0" + "@wordpress/i18n": "^5.17.0" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" } }, - "node_modules/@wordpress/rich-text": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-7.14.0.tgz", - "integrity": "sha512-Y7LERZVgOza2itTNn848Mv+O7v2SEE/fdCkXqxE/r3cuEA0hirc68ygiCh4ufAe1Itnd8H7VTTUQouuMXFeBKA==", + "node_modules/@wordpress/router": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/router/-/router-1.17.0.tgz", + "integrity": "sha512-hzc3Hdbnje7Bl/MHCfDnTbjVwyoVR6Cp05H1N1f6pAbqSTgHTyefMkkK4CPtwplpYcsY+yvEfPij1GejcFaAgg==", + "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/a11y": "*", - "@wordpress/compose": "*", - "@wordpress/data": "*", - "@wordpress/deprecated": "*", - "@wordpress/element": "*", - "@wordpress/escape-html": "*", - "@wordpress/i18n": "*", - "@wordpress/keycodes": "*", - "memize": "^2.1.0" + "@wordpress/compose": "^7.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/private-apis": "^1.17.0", + "@wordpress/url": "4.17.0", + "history": "^5.3.0", + "route-recognizer": "^0.3.4" }, "engines": { "node": ">=18.12.0", @@ -9742,19 +8847,6 @@ "react": "^18.0.0" } }, - "node_modules/@wordpress/rich-text/node_modules/@wordpress/keycodes": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.10.0.tgz", - "integrity": "sha512-2i+N90HBMqQegtGqeVB8pJz8ZgKAY1eZmQegE9MXczYVac85DDOoxhY/41c44s6Kwl3waJ2Zght6UXE0OUFMxw==", - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/i18n": "^5.10.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, "node_modules/@wordpress/scripts": { "version": "30.1.0", "resolved": "https://registry.npmjs.org/@wordpress/scripts/-/scripts-30.1.0.tgz", @@ -10303,457 +9395,137 @@ "resolved": "https://registry.npmjs.org/wp-prettier/-/wp-prettier-3.0.3.tgz", "integrity": "sha512-X4UlrxDTH8oom9qXlcjnydsjAOD2BmB6yFmvS4Z2zdTzqqpRWb+fbqrH412+l+OUXmbzJlSXjlMFYPgYG12IAA==", "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/@wordpress/scripts/node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@wordpress/scripts/node_modules/stylelint-config-recommended": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.1.tgz", - "integrity": "sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/stylelint" - }, - { - "type": "github", - "url": "https://github.com/sponsors/stylelint" - } - ], - "engines": { - "node": ">=18.12.0" - }, - "peerDependencies": { - "stylelint": "^16.1.0" - } - }, - "node_modules/@wordpress/scripts/node_modules/stylelint-config-recommended-scss": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-14.1.0.tgz", - "integrity": "sha512-bhaMhh1u5dQqSsf6ri2GVWWQW5iUjBYgcHkh7SgDDn92ijoItC/cfO/W+fpXshgTQWhwFkP1rVcewcv4jaftRg==", - "dev": true, - "dependencies": { - "postcss-scss": "^4.0.9", - "stylelint-config-recommended": "^14.0.1", - "stylelint-scss": "^6.4.0" - }, - "engines": { - "node": ">=18.12.0" - }, - "peerDependencies": { - "postcss": "^8.3.3", - "stylelint": "^16.6.1" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - } - } - }, - "node_modules/@wordpress/scripts/node_modules/stylelint-scss": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-6.7.0.tgz", - "integrity": "sha512-RFIa2A+pVWS5wjNT+whtK7wsbZEWazyqesCuSaPbPlZ8lh2TujwVJSnCYJijg6ChZzwI8pZPRZS1L6A9aCbXDg==", - "dev": true, - "dependencies": { - "css-tree": "2.3.1", - "is-plain-object": "5.0.0", - "known-css-properties": "^0.34.0", - "postcss-media-query-parser": "^0.2.3", - "postcss-resolve-nested-selector": "^0.1.6", - "postcss-selector-parser": "^6.1.2", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": ">=18.12.0" - }, - "peerDependencies": { - "stylelint": "^16.0.2" - } - }, - "node_modules/@wordpress/scripts/node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@wordpress/server-side-render": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/server-side-render/-/server-side-render-5.16.0.tgz", - "integrity": "sha512-OB6Omav6X4yciYGNQHHJpw/psKyAO2Z7ab9UGvlaST/YnmBD+9IZYtp9boo3D3zfOjB5aeD+2shRpt9zOBYEbw==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/api-fetch": "^7.16.0", - "@wordpress/blocks": "^14.5.0", - "@wordpress/components": "^29.2.0", - "@wordpress/compose": "^7.16.0", - "@wordpress/data": "^10.16.0", - "@wordpress/deprecated": "^4.16.0", - "@wordpress/element": "^6.16.0", - "@wordpress/i18n": "^5.16.0", - "@wordpress/url": "^4.16.0", - "fast-deep-equal": "^3.1.3" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@wordpress/server-side-render/node_modules/@wordpress/api-fetch": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-7.16.0.tgz", - "integrity": "sha512-JMHUUWQQnuFDYQfWtOBPxbB8YEefew3fnGwwDrdOAN7drkZ7ob7fJ2H1tY6iV5i+wIEl/5em3f0jXD3zcwkBDw==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/i18n": "^5.16.0", - "@wordpress/url": "^4.16.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/server-side-render/node_modules/@wordpress/blocks": { - "version": "14.5.0", - "resolved": "https://registry.npmjs.org/@wordpress/blocks/-/blocks-14.5.0.tgz", - "integrity": "sha512-RsX8hWsTegbkUaYcqIfYE2k1OEkF3hOV3PZFsm9Zn1ZN0/ESUQGRXxUCQvr/7yZIjMRxVNnakYlln2OMrXt1rQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/autop": "^4.16.0", - "@wordpress/blob": "^4.16.0", - "@wordpress/block-serialization-default-parser": "^5.16.0", - "@wordpress/data": "^10.16.0", - "@wordpress/deprecated": "^4.16.0", - "@wordpress/dom": "^4.16.0", - "@wordpress/element": "^6.16.0", - "@wordpress/hooks": "^4.16.0", - "@wordpress/html-entities": "^4.16.0", - "@wordpress/i18n": "^5.16.0", - "@wordpress/is-shallow-equal": "^5.16.0", - "@wordpress/private-apis": "^1.16.0", - "@wordpress/rich-text": "^7.16.0", - "@wordpress/shortcode": "^4.16.0", - "@wordpress/warning": "^3.16.0", - "change-case": "^4.1.2", - "colord": "^2.7.0", - "fast-deep-equal": "^3.1.3", - "hpq": "^1.3.0", - "is-plain-object": "^5.0.0", - "memize": "^2.1.0", - "react-is": "^18.3.0", - "remove-accents": "^0.5.0", - "showdown": "^1.9.1", - "simple-html-tokenizer": "^0.5.7", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "react": "^18.0.0" - } - }, - "node_modules/@wordpress/server-side-render/node_modules/@wordpress/components": { - "version": "29.2.0", - "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-29.2.0.tgz", - "integrity": "sha512-a7vUL4oUGu4Jicqf0cFSdQvGtZVw9h4Gvxr53o8yJYmXY8YRVrbeEsZjA/twaqRa8WxGzzWnWNQ/XwtMEXNG0w==", - "dev": true, - "dependencies": { - "@ariakit/react": "^0.4.15", - "@babel/runtime": "7.25.7", - "@emotion/cache": "^11.7.1", - "@emotion/css": "^11.7.1", - "@emotion/react": "^11.7.1", - "@emotion/serialize": "^1.0.2", - "@emotion/styled": "^11.6.0", - "@emotion/utils": "^1.0.0", - "@floating-ui/react-dom": "^2.0.8", - "@types/gradient-parser": "0.1.3", - "@types/highlight-words-core": "1.2.1", - "@use-gesture/react": "^10.3.1", - "@wordpress/a11y": "^4.16.0", - "@wordpress/compose": "^7.16.0", - "@wordpress/date": "^5.16.0", - "@wordpress/deprecated": "^4.16.0", - "@wordpress/dom": "^4.16.0", - "@wordpress/element": "^6.16.0", - "@wordpress/escape-html": "^3.16.0", - "@wordpress/hooks": "^4.16.0", - "@wordpress/html-entities": "^4.16.0", - "@wordpress/i18n": "^5.16.0", - "@wordpress/icons": "^10.16.0", - "@wordpress/is-shallow-equal": "^5.16.0", - "@wordpress/keycodes": "^4.16.0", - "@wordpress/primitives": "^4.16.0", - "@wordpress/private-apis": "^1.16.0", - "@wordpress/rich-text": "^7.16.0", - "@wordpress/warning": "^3.16.0", - "change-case": "^4.1.2", - "clsx": "^2.1.1", - "colord": "^2.7.0", - "date-fns": "^3.6.0", - "deepmerge": "^4.3.0", - "fast-deep-equal": "^3.1.3", - "framer-motion": "^11.1.9", - "gradient-parser": "^0.1.5", - "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.3.1", - "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/server-side-render/node_modules/@wordpress/compose": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-7.16.0.tgz", - "integrity": "sha512-FTpfEUeEyH3LnVRlNZxRwce3sEUPDAVI1P+AaF7ZrbzcV2ita4WamCoEHFDS4OMOnvISnSbVh2Rz3gF9oLvomQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@types/mousetrap": "^1.6.8", - "@wordpress/deprecated": "^4.16.0", - "@wordpress/dom": "^4.16.0", - "@wordpress/element": "^6.16.0", - "@wordpress/is-shallow-equal": "^5.16.0", - "@wordpress/keycodes": "^4.16.0", - "@wordpress/priority-queue": "^3.16.0", - "@wordpress/undo-manager": "^1.16.0", - "change-case": "^4.1.2", - "clipboard": "^2.0.11", - "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/server-side-render/node_modules/@wordpress/data": { - "version": "10.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-10.16.0.tgz", - "integrity": "sha512-5Gx0Hb1VsnvACQJBJhgaFf0xn6cf1s0Wqv3q2DRnRShuSQTNxkUxA41+eZsPxC1JrnVXg0vPRCu5GpqwPO4O9g==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/compose": "^7.16.0", - "@wordpress/deprecated": "^4.16.0", - "@wordpress/element": "^6.16.0", - "@wordpress/is-shallow-equal": "^5.16.0", - "@wordpress/priority-queue": "^3.16.0", - "@wordpress/private-apis": "^1.16.0", - "@wordpress/redux-routine": "^5.16.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/server-side-render/node_modules/@wordpress/element": { - "version": "6.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.16.0.tgz", - "integrity": "sha512-1Db9jeu7dxil/fJqAiLN5dA6gwoHWcgMSqZJ4dmZ0kMDMs40rtm6o60GFmAQGlrj+mmUvhOHTTwrBdpyfuv4bA==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@types/react": "^18.2.79", - "@types/react-dom": "^18.2.25", - "@wordpress/escape-html": "^3.16.0", - "change-case": "^4.1.2", - "is-plain-object": "^5.0.0", - "react": "^18.3.0", - "react-dom": "^18.3.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, - "node_modules/@wordpress/server-side-render/node_modules/@wordpress/hooks": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-4.16.0.tgz", - "integrity": "sha512-W82L1PdIhJPNpEb2F+0NWzrDoUqZo6NnYID7qHCexBiagq4+QS4uydM6anyFvUNrpL51CmkCNu31Xi8HjpSTGg==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7" + "bin": { + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/@wordpress/server-side-render/node_modules/@wordpress/i18n": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.16.0.tgz", - "integrity": "sha512-O4ZUvjS8AlYzTxvw7fmp3xk51rpKv1h2/dGFc/L+IB97UrCBAiC9HBv6FIHRF1gci4Vdu/QnCDw3qpC+N/2gCw==", + "node_modules/@wordpress/scripts/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/hooks": "^4.16.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "tannin": "^1.2.0" - }, "bin": { - "pot-to-php": "tools/pot-to-php.js" + "semver": "bin/semver.js" }, "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" + "node": ">=10" } }, - "node_modules/@wordpress/server-side-render/node_modules/@wordpress/icons": { - "version": "10.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-10.16.0.tgz", - "integrity": "sha512-fHZujKpOkYD3JnPGCYqB1VafUiqsUOnpdVGdBd7En5ELwRg189a0NcI4EmM8OkeItNDml4LU/4nCCkypSy29eA==", + "node_modules/@wordpress/scripts/node_modules/stylelint-config-recommended": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.1.tgz", + "integrity": "sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg==", "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/element": "^6.16.0", - "@wordpress/primitives": "^4.16.0" - }, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" + "node": ">=18.12.0" + }, + "peerDependencies": { + "stylelint": "^16.1.0" } }, - "node_modules/@wordpress/server-side-render/node_modules/@wordpress/keycodes": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.16.0.tgz", - "integrity": "sha512-T4kaFkw6R1VkcBk+F7B4gmzEhSPRJwpMdkP7roNvENzKGtXs49K4xO0koOZhWUlGpZvhPJ1WWERyoub8S7rX2A==", + "node_modules/@wordpress/scripts/node_modules/stylelint-config-recommended-scss": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-14.1.0.tgz", + "integrity": "sha512-bhaMhh1u5dQqSsf6ri2GVWWQW5iUjBYgcHkh7SgDDn92ijoItC/cfO/W+fpXshgTQWhwFkP1rVcewcv4jaftRg==", "dev": true, "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/i18n": "^5.16.0" + "postcss-scss": "^4.0.9", + "stylelint-config-recommended": "^14.0.1", + "stylelint-scss": "^6.4.0" }, "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" + "node": ">=18.12.0" + }, + "peerDependencies": { + "postcss": "^8.3.3", + "stylelint": "^16.6.1" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + } } }, - "node_modules/@wordpress/server-side-render/node_modules/@wordpress/primitives": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-4.16.0.tgz", - "integrity": "sha512-mf5LPcA500KOo/UPiwNanNlH6Satwf4xBB1DPzw4InE67eACvAlde3oSYsoE6Uce6+7URRIefg9j47yXP2jkxw==", + "node_modules/@wordpress/scripts/node_modules/stylelint-scss": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-6.7.0.tgz", + "integrity": "sha512-RFIa2A+pVWS5wjNT+whtK7wsbZEWazyqesCuSaPbPlZ8lh2TujwVJSnCYJijg6ChZzwI8pZPRZS1L6A9aCbXDg==", "dev": true, "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/element": "^6.16.0", - "clsx": "^2.1.1" + "css-tree": "2.3.1", + "is-plain-object": "5.0.0", + "known-css-properties": "^0.34.0", + "postcss-media-query-parser": "^0.2.3", + "postcss-resolve-nested-selector": "^0.1.6", + "postcss-selector-parser": "^6.1.2", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" + "node": ">=18.12.0" }, "peerDependencies": { - "react": "^18.0.0" + "stylelint": "^16.0.2" } }, - "node_modules/@wordpress/server-side-render/node_modules/@wordpress/rich-text": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-7.16.0.tgz", - "integrity": "sha512-p+9WPzVo5pXLr1Xt04gQ1kdYQYmw05r2Kp42tgIfFNjgCBH1plpSrzjCyV/dyHrZ7APpJFg8sNjlOJmyLQiCFg==", + "node_modules/@wordpress/scripts/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@wordpress/a11y": "^4.16.0", - "@wordpress/compose": "^7.16.0", - "@wordpress/data": "^10.16.0", - "@wordpress/deprecated": "^4.16.0", - "@wordpress/element": "^6.16.0", - "@wordpress/escape-html": "^3.16.0", - "@wordpress/i18n": "^5.16.0", - "@wordpress/keycodes": "^4.16.0", - "memize": "^2.1.0" - }, "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - }, - "peerDependencies": { - "react": "^18.0.0" + "node": ">= 6" } }, - "node_modules/@wordpress/server-side-render/node_modules/@wordpress/url": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-4.16.0.tgz", - "integrity": "sha512-A9kkw/ye2qL9ZHvm1Eew8bvGVnNMq4fW0t5dakdDuVXyXtSOvZVT268JhP9QaD0FYzOFrmxL5Ks8Z6ufP1yLwg==", + "node_modules/@wordpress/server-side-render": { + "version": "5.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/server-side-render/-/server-side-render-5.17.0.tgz", + "integrity": "sha512-xJWABbtCZmkO6+Xa1DS3Mq+f2ZKH540aj5xeN7M1W1meAFdcZlEAbQI+Kn1PuXI9VpHIh5K+JOybHD06TI4hZQ==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "remove-accents": "^0.5.0" + "@wordpress/api-fetch": "^7.17.0", + "@wordpress/blocks": "^14.6.0", + "@wordpress/components": "^29.3.0", + "@wordpress/compose": "^7.17.0", + "@wordpress/data": "^10.17.0", + "@wordpress/deprecated": "^4.17.0", + "@wordpress/element": "^6.17.0", + "@wordpress/i18n": "^5.17.0", + "@wordpress/url": "4.17.0", + "fast-deep-equal": "^3.1.3" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0" } }, - "node_modules/@wordpress/server-side-render/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==", - "dev": true - }, "node_modules/@wordpress/shortcode": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/shortcode/-/shortcode-4.16.0.tgz", - "integrity": "sha512-T3KLZq5SYGigltEQumCKExKBJqnI2IF2elnJpd5+CFxQQAb9/gsrZ4TBG7ommOlXHZKn5hwD2YIEEM/ZAkGQ4A==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/shortcode/-/shortcode-4.17.0.tgz", + "integrity": "sha512-sNPUmeeK/dxK5z8BWSsk5OqRSf2UzfczpKu3upRn9eIdgG31SCXPgzvps73upIrxZNDCTQVVFhq47KADX8TiUA==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", "memize": "^2.0.1" @@ -10764,10 +9536,11 @@ } }, "node_modules/@wordpress/style-engine": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/style-engine/-/style-engine-2.10.0.tgz", - "integrity": "sha512-LNKaAmSURtZSdmv7MhGk936pzMO6gtVTZnqL3NYFLJriFxJnMLI8kLV5KKWmJA/p1TPUmnxkABTI6qZjsM36Mg==", + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/style-engine/-/style-engine-2.17.0.tgz", + "integrity": "sha512-6eIdeQH0t7va1AjZIGo8sEW8NE+dcz//KXp+HsW/2XhATAIPjUjFJ2/SVRNCj3JHFKSjKpxnZi26xalfET0PqA==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", "change-case": "^4.1.2" @@ -10778,14 +9551,15 @@ } }, "node_modules/@wordpress/sync": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/sync/-/sync-1.10.0.tgz", - "integrity": "sha512-tRtEd0CB8wgQR6CuW4j/1gH9Eug65DdAoONZAhIqgxEZD22+lzQU2frMSVxIPXOwAtcGSFuzpMek9LKgo+jNmw==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/sync/-/sync-1.17.0.tgz", + "integrity": "sha512-otylLNYzW0Tu5NIgLwGwE2rvjikyB3KCFlpqIl4otR1XxqFM7obHG7VU+e0LKQdlg6NIdCZdWyv2nNGnz5cjFg==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", "@types/simple-peer": "^9.11.5", - "@wordpress/url": "4.10.0", + "@wordpress/url": "4.17.0", "import-locals": "^2.0.0", "lib0": "^0.2.42", "simple-peer": "^9.11.0", @@ -10799,51 +9573,69 @@ "npm": ">=8.19.2" } }, - "node_modules/@wordpress/sync/node_modules/@wordpress/url": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-4.10.0.tgz", - "integrity": "sha512-SKlXocsTlaSee2trXcB0N3jdIfEGMnPiqNxxvTjeeBmsP/47MMXu5lXYslYyYlQbluhAR5/RMf0o3WqZAF2uOg==", + "node_modules/@wordpress/token-list": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/token-list/-/token-list-3.17.0.tgz", + "integrity": "sha512-TO224Seolfy/eapbOg15poz1Ws44xW3KHrqeo7Jp+6hmqQh/5OJE5wDFTzgsbdnAXFzy3DAGJxxxrCv0qpf+YA==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { - "@babel/runtime": "7.25.7", - "remove-accents": "^0.5.0" + "@babel/runtime": "7.25.7" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" } }, - "node_modules/@wordpress/token-list": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/token-list/-/token-list-3.10.0.tgz", - "integrity": "sha512-BSdvKCQLRQFV/cjsibfiuKdbBVYy7k3X3NHB8ojzZUScEOpnjV5PWnnZ0TJK0hZUPnLEiBsMEaUIqUw+VKXX0g==", - "dev": true, + "node_modules/@wordpress/undo-manager": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/undo-manager/-/undo-manager-1.17.0.tgz", + "integrity": "sha512-inSOCUneGMmFq3jRTB9uIws/+6VWpz0zvY2IPW/vjWbz7Gg1YbJ+lmbbgtJCoiJ7Ei00b4sagvzI00TNUXe9mg==", + "license": "GPL-2.0-or-later", "dependencies": { - "@babel/runtime": "7.25.7" + "@babel/runtime": "7.25.7", + "@wordpress/is-shallow-equal": "^5.17.0" }, "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" } }, - "node_modules/@wordpress/undo-manager": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/undo-manager/-/undo-manager-1.16.0.tgz", - "integrity": "sha512-IE3u5Yk8QzUhiLAiGmYostsygxQExs9mVWlZ1BAXniEGCAcVdvDv7IB16dIgQxCYG3/idvmFdNbN8aQGX+nEIg==", + "node_modules/@wordpress/upload-media": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@wordpress/upload-media/-/upload-media-0.2.0.tgz", + "integrity": "sha512-xPPru9rSDTKWpFMMM5dOaPQIkf38L3gNinjSHkU7arFyK14G60HklvZJ/MTk7RjjgQ7h1sYe8tvdiTvI8CQZyQ==", + "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/is-shallow-equal": "^5.16.0" + "@shopify/web-worker": "^6.4.0", + "@wordpress/api-fetch": "^7.17.0", + "@wordpress/blob": "^4.17.0", + "@wordpress/compose": "7.17.0", + "@wordpress/data": "10.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/i18n": "5.17.0", + "@wordpress/preferences": "^4.17.0", + "@wordpress/private-apis": "^1.17.0", + "@wordpress/url": "4.17.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/url": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-4.14.0.tgz", - "integrity": "sha512-9KkU5eMQoA8cwuJHVZtDJAhrjoFN02jDuWRJgilb7rx2g3zlTWLNSLEKXV3FNuVCmgapAlh3EbB9yyXNhzQ+jw==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-4.17.0.tgz", + "integrity": "sha512-aFU1w2Wcz2/YdapPYozeXbb7C7LzfYZmAg4Bu28zTSxxrpKYocr/oYH7D8V13uHzfBoqTzL8XYM7wj17Dlcdag==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", "remove-accents": "^0.5.0" @@ -10854,15 +9646,16 @@ } }, "node_modules/@wordpress/viewport": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/viewport/-/viewport-6.10.0.tgz", - "integrity": "sha512-KHI6lThOHeSCIXXFZPY3TEj8vE4DlSnSIUZLTxSIro6B6gcSn6vy3cJgoR6a9VJ7V14Y5gIWpTnZAOfPj8Zh7A==", + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/viewport/-/viewport-6.17.0.tgz", + "integrity": "sha512-xhTOdRjA2bjmuWOYoJtq9Tdnjle7u0bCkJyyuCVrMWxqAunxcI8QxSTXm9OqvuAVbvGfhH9i/BIeeTQjFYPxPA==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7", - "@wordpress/compose": "^7.10.0", - "@wordpress/data": "^10.10.0", - "@wordpress/element": "6.10.0" + "@wordpress/compose": "^7.17.0", + "@wordpress/data": "^10.17.0", + "@wordpress/element": "6.17.0" }, "engines": { "node": ">=18.12.0", @@ -10872,40 +9665,22 @@ "react": "^18.0.0" } }, - "node_modules/@wordpress/viewport/node_modules/@wordpress/element": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.10.0.tgz", - "integrity": "sha512-7zW+14vHqEn45nszSLMUqE5IbzOtvgUUgF56qlMhwabpG4l/zhaj3gO3wLDI19C13ih1vOdSjzPc3At4fB3tRQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "7.25.7", - "@types/react": "^18.2.79", - "@types/react-dom": "^18.2.25", - "@wordpress/escape-html": "^3.10.0", - "change-case": "^4.1.2", - "is-plain-object": "^5.0.0", - "react": "^18.3.0", - "react-dom": "^18.3.0" - }, - "engines": { - "node": ">=18.12.0", - "npm": ">=8.19.2" - } - }, "node_modules/@wordpress/warning": { - "version": "3.16.0", - "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-3.16.0.tgz", - "integrity": "sha512-XsgqRPvB+VSecXnD3VfvJJxhcdTTX4EkgdzvWspmQnw0rNCV636KByZVgolzYhvr3La9EgqO+MqXzwvPHg/xfQ==", + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-3.17.0.tgz", + "integrity": "sha512-dmEjDbYtfPD8rMRtSrLxoW3g8CLKl+vK5pdXvDvG0lBoRjqwtRPP4cgNBOC8cq8gXRCwh5NDDtM2C8MTjGjVsQ==", + "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", "npm": ">=8.19.2" } }, "node_modules/@wordpress/wordcount": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/wordcount/-/wordcount-4.10.0.tgz", - "integrity": "sha512-RtdSPRnSwS7U6JRa4YtnqCO2iWNU6kpyvRWpsjr6U/Xrg632vIv4Q8qcHMxbZRVgAMtzdiUDlDEOy4JPXZI1eQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@wordpress/wordcount/-/wordcount-4.17.0.tgz", + "integrity": "sha512-lT4NmbK0fMX+mqm/1XSoTsW7VqmxApZcZFPtWvT5UH6js1XcDrQa9liIUv6RyMlrrLHTTDrq+e4mNVeND68o5A==", "dev": true, + "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "7.25.7" }, @@ -12035,6 +10810,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -12366,7 +11142,8 @@ "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/check-error": { "version": "2.1.1", @@ -12689,19 +11466,21 @@ } }, "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, + "license": "ISC", "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/client-zip": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/client-zip/-/client-zip-2.4.5.tgz", - "integrity": "sha512-4y4d5ZeTH/szIAMQeC8ju67pxtvj+3u20wMGwOFrZk+pegy3aSEA2JkwgC8XVDTXP/Iqn1gyqNQXmkyBp4KLEQ==", - "dev": true + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/client-zip/-/client-zip-2.4.6.tgz", + "integrity": "sha512-e7t1u14h/yT0A12qBwFsaus8UZZ8+MCaNAEn/z53mrukLq/LFcKX7TkbntAppGu8he2p8pz9vc5NEGE/h4ohlw==", + "dev": true, + "license": "MIT" }, "node_modules/clipboard": { "version": "2.0.11", @@ -14344,7 +13123,8 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/error-ex": { "version": "1.3.2", @@ -15671,6 +14451,7 @@ "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", "dev": true, + "license": "MIT", "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", @@ -15685,6 +14466,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -15846,30 +14628,6 @@ "pend": "~1.2.0" } }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -16450,7 +15208,8 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/get-browser-rtc/-/get-browser-rtc-1.1.0.tgz", "integrity": "sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/get-caller-file": { "version": "2.0.5", @@ -17010,6 +15769,16 @@ "integrity": "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==", "license": "CC0-1.0" }, + "node_modules/history": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", + "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.6" + } + }, "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", @@ -17424,7 +16193,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-locals/-/import-locals-2.0.0.tgz", "integrity": "sha512-1/bPE89IZhyf7dr5Pkz7b4UyVXy5pEt7PTEfye15UEn3AK8+2zwcDCfKk9Pwun4ltfhOSszOrReSsFcDKw/yoA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/imurmurhash": { "version": "0.1.4", @@ -17466,30 +16236,6 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, - "node_modules/inquirer": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.19", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.6.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/internal-slot": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", @@ -18196,6 +16942,7 @@ "resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz", "integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==", "dev": true, + "license": "MIT", "funding": { "type": "GitHub Sponsors ❤", "url": "https://github.com/sponsors/dmonad" @@ -19458,10 +18205,11 @@ } }, "node_modules/lib0": { - "version": "0.2.98", - "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.98.tgz", - "integrity": "sha512-XteTiNO0qEXqqweWx+b21p/fBnNHUA1NwAtJNJek1oPrewEZs2uiT4gWivHKr9GqCjDPAhchz0UQO8NwU3bBNA==", + "version": "0.2.99", + "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.99.tgz", + "integrity": "sha512-vwztYuUf1uf/1zQxfzRfO5yzfNKhTtgOByCruuiQQxWQXnPb8Itaube5ylofcV0oM0aKal9Mv+S1s1Ky0UYP1w==", "dev": true, + "license": "MIT", "dependencies": { "isomorphic.js": "^0.2.4" }, @@ -21629,6 +20377,7 @@ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -23990,6 +22739,13 @@ "fsevents": "~2.3.2" } }, + "node_modules/route-recognizer": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/route-recognizer/-/route-recognizer-0.3.4.tgz", + "integrity": "sha512-2+MhsfPhvauN1O8KaXpXAOfR/fwe8dnUXVM+xw7yt40lJRfPVQxV6yryZm0cgRvAj5fMF/mdRZbL2ptwbs5i2g==", + "dev": true, + "license": "MIT" + }, "node_modules/rtlcss": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-3.5.0.tgz", @@ -24061,15 +22817,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/run-con": { "version": "1.2.12", "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.2.12.tgz", @@ -24122,24 +22869,6 @@ "resolved": "https://registry.npmjs.org/rungen/-/rungen-0.3.2.tgz", "integrity": "sha512-zWl10xu2D7zoR8zSC2U6bg5bYF6T/Wk7rxwp8IPaJH7f0Ge21G03kNHVgHR7tyVkSSfAOG0Rqf/Cl38JftSmtw==" }, - "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/rxjs/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/safe-array-concat": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", @@ -24919,6 +23648,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "buffer": "^6.0.3", "debug": "^4.3.2", @@ -24934,6 +23664,7 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -26384,6 +25115,7 @@ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, + "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.2" }, @@ -28208,6 +26940,7 @@ "resolved": "https://registry.npmjs.org/y-indexeddb/-/y-indexeddb-9.0.12.tgz", "integrity": "sha512-9oCFRSPPzBK7/w5vOkJBaVCQZKHXB/v6SIT+WYhnJxlEC61juqG0hBrAf+y3gmSMLFLwICNH9nQ53uscuse6Hg==", "dev": true, + "license": "MIT", "dependencies": { "lib0": "^0.2.74" }, @@ -28228,6 +26961,7 @@ "resolved": "https://registry.npmjs.org/y-protocols/-/y-protocols-1.0.6.tgz", "integrity": "sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==", "dev": true, + "license": "MIT", "dependencies": { "lib0": "^0.2.85" }, @@ -28248,6 +26982,7 @@ "resolved": "https://registry.npmjs.org/y-webrtc/-/y-webrtc-10.2.6.tgz", "integrity": "sha512-1kZ4YYwksFZi8+l8mTebVX9vW6Q5MnqxMkvNU700X5dBE38usurt/JgeXSIQRpK3NwUYYb9y63Jn9FMpMH6/vA==", "dev": true, + "license": "MIT", "dependencies": { "lib0": "^0.2.42", "simple-peer": "^9.11.0", @@ -28336,12 +27071,13 @@ } }, "node_modules/yjs": { - "version": "13.6.20", - "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.20.tgz", - "integrity": "sha512-Z2YZI+SYqK7XdWlloI3lhMiKnCdFCVC4PchpdO+mCYwtiTwncjUbnRK9R1JmkNfdmHyDXuWN3ibJAt0wsqTbLQ==", + "version": "13.6.23", + "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.23.tgz", + "integrity": "sha512-ExtnT5WIOVpkL56bhLeisG/N5c4fmzKn4k0ROVfJa5TY2QHbH7F0Wu2T5ZhR7ErsFWQEFafyrnSI8TPKVF9Few==", "dev": true, + "license": "MIT", "dependencies": { - "lib0": "^0.2.98" + "lib0": "^0.2.99" }, "engines": { "node": ">=16.0.0", @@ -28364,6 +27100,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zod": { "version": "3.23.8", "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", diff --git a/package.json b/package.json index 1e3b3a8e..c16e782c 100644 --- a/package.json +++ b/package.json @@ -65,30 +65,30 @@ "@types/wordpress__block-editor": "11.5.16", "@types/wordpress__blocks": "12.5.16", "@vitest/coverage-v8": "3.0.4", - "@wordpress/api-fetch": "7.14.0", - "@wordpress/block-editor": "14.9.0", - "@wordpress/blocks": "14.3.0", - "@wordpress/components": "29.0.0", - "@wordpress/compose": "7.14.0", - "@wordpress/core-data": "7.14.0", - "@wordpress/data": "10.14.0", - "@wordpress/dependency-extraction-webpack-plugin": "^6.14.0", - "@wordpress/dom-ready": "4.14.0", - "@wordpress/e2e-test-utils-playwright": "^1.14.0", - "@wordpress/editor": "14.14.0", - "@wordpress/element": "6.14.0", - "@wordpress/env": "10.14.0", - "@wordpress/hooks": "4.14.0", - "@wordpress/i18n": "5.14.0", - "@wordpress/icons": "10.14.0", - "@wordpress/interactivity": "6.14.0", - "@wordpress/notices": "5.14.0", - "@wordpress/plugins": "7.14.0", - "@wordpress/primitives": "4.14.0", - "@wordpress/rich-text": "7.14.0", + "@wordpress/api-fetch": "7.17.0", + "@wordpress/block-editor": "14.12.0", + "@wordpress/blocks": "14.6.0", + "@wordpress/components": "29.3.0", + "@wordpress/compose": "7.17.0", + "@wordpress/core-data": "7.17.0", + "@wordpress/data": "10.17.0", + "@wordpress/dependency-extraction-webpack-plugin": "^6.17.0", + "@wordpress/dom-ready": "4.17.0", + "@wordpress/e2e-test-utils-playwright": "^1.17.0", + "@wordpress/editor": "14.17.0", + "@wordpress/element": "6.17.0", + "@wordpress/env": "10.17.0", + "@wordpress/hooks": "4.17.0", + "@wordpress/i18n": "5.17.0", + "@wordpress/icons": "10.17.0", + "@wordpress/interactivity": "6.17.0", + "@wordpress/notices": "5.17.0", + "@wordpress/plugins": "7.17.0", + "@wordpress/primitives": "4.17.0", + "@wordpress/rich-text": "7.17.0", "@wordpress/scripts": "30.1.0", - "@wordpress/server-side-render": "5.16.0", - "@wordpress/url": "4.14.0", + "@wordpress/server-side-render": "5.17.0", + "@wordpress/url": "4.17.0", "eslint": "8.57.1", "fork-ts-checker-webpack-plugin": "9.0.2", "happy-dom": "16.7.3", @@ -112,7 +112,7 @@ }, "dependencies": { "@automattic/calypso-analytics": "^1.1.3", - "@wordpress/dataviews": "^4.10.0", + "@wordpress/dataviews": "^4.13.0", "react-syntax-highlighter": "^15.6.1" } } From d5fab4eabeef575e366e87e8af734cff75b02bd4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:21:51 -0500 Subject: [PATCH 03/16] Bump psalm/phar from 6.0.0 to 6.1.0 (#348) Bumps [psalm/phar](https://github.com/psalm/phar) from 6.0.0 to 6.1.0. - [Release notes](https://github.com/psalm/phar/releases) - [Commits](https://github.com/psalm/phar/compare/6.0.0...6.1.0) --- updated-dependencies: - dependency-name: psalm/phar dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/composer.lock b/composer.lock index b942fd3c..70559b28 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b184d8f857e638c0ec1f15e9ce90ee7a", + "content-hash": "1502305afc876f94cb1e3a76cbbeb1ec", "packages": [ { "name": "erusev/parsedown", @@ -2459,16 +2459,16 @@ }, { "name": "psalm/phar", - "version": "6.0.0", + "version": "6.1.0", "source": { "type": "git", "url": "https://github.com/psalm/phar.git", - "reference": "859187f245d76b38d1b320bb9f976fb48bfe5213" + "reference": "65011fc1453292b88c79dd09549d8d04c4e06c75" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/psalm/phar/zipball/859187f245d76b38d1b320bb9f976fb48bfe5213", - "reference": "859187f245d76b38d1b320bb9f976fb48bfe5213", + "url": "https://api.github.com/repos/psalm/phar/zipball/65011fc1453292b88c79dd09549d8d04c4e06c75", + "reference": "65011fc1453292b88c79dd09549d8d04c4e06c75", "shasum": "" }, "require": { @@ -2488,9 +2488,9 @@ "description": "Composer-based Psalm Phar", "support": { "issues": "https://github.com/psalm/phar/issues", - "source": "https://github.com/psalm/phar/tree/6.0.0" + "source": "https://github.com/psalm/phar/tree/6.1.0" }, - "time": "2025-01-26T12:07:59+00:00" + "time": "2025-01-30T19:46:07+00:00" }, { "name": "sebastian/cli-parser", @@ -3888,7 +3888,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { From 6951c71bad3a396df7de149be7721dc0ff087e22 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:22:44 -0500 Subject: [PATCH 04/16] Bump @playwright/test from 1.50.0 to 1.50.1 (#349) Bumps [@playwright/test](https://github.com/microsoft/playwright) from 1.50.0 to 1.50.1. - [Release notes](https://github.com/microsoft/playwright/releases) - [Commits](https://github.com/microsoft/playwright/compare/v1.50.0...v1.50.1) --- updated-dependencies: - dependency-name: "@playwright/test" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 24 ++++++++++++------------ package.json | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 321f6767..2f65ed92 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "devDependencies": { "@automattic/eslint-plugin-wpvip": "0.13.0", "@babel/preset-react": "7.26.3", - "@playwright/test": "^1.50.0", + "@playwright/test": "^1.50.1", "@testing-library/jest-dom": "6.6.3", "@testing-library/react": "16.2.0", "@types/react-syntax-highlighter": "^15.5.13", @@ -3923,13 +3923,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.0.tgz", - "integrity": "sha512-ZGNXbt+d65EGjBORQHuYKj+XhCewlwpnSd/EDuLPZGSiEWmgOJB5RmMCCYGy5aMfTs9wx61RivfDKi8H/hcMvw==", + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.50.1.tgz", + "integrity": "sha512-Jii3aBg+CEDpgnuDxEp/h7BimHcUTDlpEtce89xEumlJ5ef2hqepZ+PWp1DDpYC/VO9fmWVI1IlEaoI5fK9FXQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.50.0" + "playwright": "1.50.1" }, "bin": { "playwright": "cli.js" @@ -20829,13 +20829,13 @@ } }, "node_modules/playwright": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.0.tgz", - "integrity": "sha512-+GinGfGTrd2IfX1TA4N2gNmeIksSb+IAe589ZH+FlmpV3MYTx6+buChGIuDLQwrGNCw2lWibqV50fU510N7S+w==", + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.50.1.tgz", + "integrity": "sha512-G8rwsOQJ63XG6BbKj2w5rHeavFjy5zynBA9zsJMMtBoe/Uf757oG12NXz6e6OirF7RCrTVAKFXbLmn1RbL7Qaw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.50.0" + "playwright-core": "1.50.1" }, "bin": { "playwright": "cli.js" @@ -20848,9 +20848,9 @@ } }, "node_modules/playwright-core": { - "version": "1.50.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.0.tgz", - "integrity": "sha512-CXkSSlr4JaZs2tZHI40DsZUN/NIwgaUPsyLuOAaIZp2CyF2sN5MM5NJsyB188lFSSozFxQ5fPT4qM+f0tH/6wQ==", + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.1.tgz", + "integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/package.json b/package.json index c16e782c..fdef5c58 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "devDependencies": { "@automattic/eslint-plugin-wpvip": "0.13.0", "@babel/preset-react": "7.26.3", - "@playwright/test": "^1.50.0", + "@playwright/test": "^1.50.1", "@testing-library/jest-dom": "6.6.3", "@testing-library/react": "16.2.0", "@types/react-syntax-highlighter": "^15.5.13", From 15f1b4037be8cd96d9b362e1100078160b410c19 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:34:48 -0500 Subject: [PATCH 05/16] Bump happy-dom from 16.7.3 to 16.8.1 (#350) Bumps [happy-dom](https://github.com/capricorn86/happy-dom) from 16.7.3 to 16.8.1. - [Release notes](https://github.com/capricorn86/happy-dom/releases) - [Commits](https://github.com/capricorn86/happy-dom/compare/v16.7.3...v16.8.1) --- updated-dependencies: - dependency-name: happy-dom dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2f65ed92..9e4f748d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,7 +49,7 @@ "@wordpress/url": "4.17.0", "eslint": "8.57.1", "fork-ts-checker-webpack-plugin": "9.0.2", - "happy-dom": "16.7.3", + "happy-dom": "16.8.1", "husky": "9.1.7", "lint-staged": "15.4.3", "prettier": "npm:wp-prettier@2.8.5", @@ -15593,9 +15593,9 @@ "dev": true }, "node_modules/happy-dom": { - "version": "16.7.3", - "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-16.7.3.tgz", - "integrity": "sha512-76uiE9jCpC849cOyYZ8YBROpPcstW/hwCKoQYd3aiZaxHeR9zdjpup4z7qYEWbt+lY8Rb3efW2gmrckyoBftKg==", + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-16.8.1.tgz", + "integrity": "sha512-n0QrmT9lD81rbpKsyhnlz3DgnMZlaOkJPpgi746doA+HvaMC79bdWkwjrNnGJRvDrWTI8iOcJiVTJ5CdT/AZRw==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index fdef5c58..fa950dfe 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "@wordpress/url": "4.17.0", "eslint": "8.57.1", "fork-ts-checker-webpack-plugin": "9.0.2", - "happy-dom": "16.7.3", + "happy-dom": "16.8.1", "husky": "9.1.7", "lint-staged": "15.4.3", "prettier": "npm:wp-prettier@2.8.5", From d2f7239bcd220a66f8a5c2d67b97796a112839e5 Mon Sep 17 00:00:00 2001 From: Chris Zarate Date: Mon, 3 Feb 2025 16:13:41 -0500 Subject: [PATCH 06/16] Update useRemoteData to be more explicit about state management (#325) --- .../FieldShortcodeSelection.tsx | 7 +- .../pattern-selection/PatternSelection.tsx | 4 +- .../components/placeholders/Placeholder.tsx | 10 +- src/blocks/remote-data-container/edit.tsx | 133 ++++++++---------- .../hooks/usePatterns.ts | 17 +-- .../hooks/useRemoteData.ts | 61 ++++++-- .../hooks/useSearchResults.ts | 4 +- 7 files changed, 117 insertions(+), 119 deletions(-) diff --git a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelection.tsx b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelection.tsx index 83eab6a0..242ed7be 100644 --- a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelection.tsx +++ b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelection.tsx @@ -110,14 +110,17 @@ interface FieldShortcodeSelectFieldProps { } export function FieldShortcodeSelectField( props: FieldShortcodeSelectFieldProps ) { - const { data, execute, loading } = useRemoteData( props.blockName, DISPLAY_QUERY_KEY ); + const { data, fetch, loading } = useRemoteData( { + blockName: props.blockName, + queryKey: DISPLAY_QUERY_KEY, + } ); useEffect( () => { if ( loading || data ) { return; } - void execute( props.queryInput ); + void fetch( props.queryInput ); }, [ loading, data ] ); if ( ! data || loading ) { diff --git a/src/blocks/remote-data-container/components/pattern-selection/PatternSelection.tsx b/src/blocks/remote-data-container/components/pattern-selection/PatternSelection.tsx index 2b16d369..91e530d5 100644 --- a/src/blocks/remote-data-container/components/pattern-selection/PatternSelection.tsx +++ b/src/blocks/remote-data-container/components/pattern-selection/PatternSelection.tsx @@ -10,8 +10,8 @@ import { getBlockDataSourceType } from '@/utils/localized-block-data'; interface PatternSelectionProps { blockName: string; - insertPatternBlocks: ( pattern: BlockPattern ) => void; onCancel: () => void; + onSelectPattern: ( pattern: BlockPattern ) => void; supportedPatterns: BlockPattern[]; } @@ -19,7 +19,7 @@ export function PatternSelection( props: PatternSelectionProps ) { const [ showModal, setShowModal ] = useState< boolean >( false ); function onClickPattern( pattern: BlockPattern ) { - props.insertPatternBlocks( pattern ); + props.onSelectPattern( pattern ); setShowModal( false ); sendTracksEvent( 'remotedatablocks_add_block', { action: 'select_pattern', diff --git a/src/blocks/remote-data-container/components/placeholders/Placeholder.tsx b/src/blocks/remote-data-container/components/placeholders/Placeholder.tsx index a7d045c5..c077d8e9 100644 --- a/src/blocks/remote-data-container/components/placeholders/Placeholder.tsx +++ b/src/blocks/remote-data-container/components/placeholders/Placeholder.tsx @@ -3,19 +3,15 @@ import { PlaceholderSingle } from '@/blocks/remote-data-container/components/pla export interface PlaceholderProps { blockConfig: BlockConfig; - fetchRemoteData: ( input: RemoteDataQueryInput ) => void; + onSelect: ( input: RemoteDataQueryInput ) => void; } export function Placeholder( props: PlaceholderProps ) { const { loop } = props.blockConfig; - const placeholderProps = { - blockConfig: props.blockConfig, - onSelect: props.fetchRemoteData, - }; if ( loop ) { - return ; + return ; } - return ; + return ; } diff --git a/src/blocks/remote-data-container/edit.tsx b/src/blocks/remote-data-container/edit.tsx index 11ae5a9c..81e91bbd 100644 --- a/src/blocks/remote-data-container/edit.tsx +++ b/src/blocks/remote-data-container/edit.tsx @@ -1,7 +1,7 @@ -import { InspectorControls, useBlockProps } from '@wordpress/block-editor'; +import { BlockPattern, InspectorControls, useBlockProps } from '@wordpress/block-editor'; import { BlockEditProps } from '@wordpress/blocks'; import { Spinner } from '@wordpress/components'; -import { useEffect, useState } from '@wordpress/element'; +import { useState } from '@wordpress/element'; import { InnerBlocks } from '@/blocks/remote-data-container/components/InnerBlocks'; import { DataPanel } from '@/blocks/remote-data-container/components/panels/DataPanel'; @@ -32,101 +32,78 @@ export function Edit( props: BlockEditProps< RemoteDataBlockAttributes > ) { const { getInnerBlocks, getSupportedPatterns, + innerBlocksPattern, insertPatternBlocks, - markReadyForInsertion, - resetReadyForInsertion, - showPatternSelection, + resetInnerBlocks, } = usePatterns( blockName, rootClientId ); - const { execute } = useRemoteData( blockName, DISPLAY_QUERY_KEY ); - const [ initialLoad, setInitialLoad ] = useState< boolean >( true ); - - function fetchRemoteData( input: RemoteDataQueryInput, insertBlocks = true ) { - execute( input, true ) - .then( remoteData => { - if ( remoteData ) { - updateRemoteData( - { - enabledOverrides: props.attributes.remoteData?.enabledOverrides ?? [], - ...remoteData, - }, - insertBlocks - ); - } - } ) - .catch( () => {} ) - .finally( () => { - setInitialLoad( false ); - } ); + + const { data, fetch, loading, reset } = useRemoteData( { + blockName, + externallyManagedRemoteData: props.attributes.remoteData, + externallyManagedUpdateRemoteData: updateRemoteData, + queryKey: DISPLAY_QUERY_KEY, + } ); + + const [ showPatternSelection, setShowPatternSelection ] = useState< boolean >( false ); + + function refreshRemoteData(): void { + void fetch( props.attributes.remoteData?.queryInput ?? {} ); } - // Update the remote data in the block attributes, which is passed via context - // to children blocks. If this is the initial load of remote data, show the - // pattern selection modal so that we can insert the blocks from the pattern. - function updateRemoteData( remoteData: RemoteData, insertBlocks = false ) { - if ( hasRemoteDataChanged( props.attributes.remoteData, remoteData ) ) { - props.setAttributes( { remoteData } ); - } + function resetPatternSelection(): void { + resetInnerBlocks(); + setShowPatternSelection( false ); + } - if ( insertBlocks ) { - markReadyForInsertion(); - } + function resetRemoteData(): void { + reset(); + resetPatternSelection(); } - const hasInputVariables = Boolean( - blockConfig.selectors.find( selector => selector.query_key === DISPLAY_QUERY_KEY )?.inputs - ?.length - ); + function onSelectPattern( pattern: BlockPattern ): void { + insertPatternBlocks( pattern ); + setShowPatternSelection( false ); + } - function refreshRemoteData() { - if ( ! props.attributes.remoteData?.queryInput ) { - if ( hasInputVariables ) { + function onSelectRemoteData( queryInput: RemoteDataQueryInput ): void { + void fetch( queryInput ).then( () => { + if ( innerBlocksPattern ) { + insertPatternBlocks( innerBlocksPattern ); return; } - fetchRemoteData( {}, true ); - } else { - fetchRemoteData( props.attributes.remoteData.queryInput, false ); - } + setShowPatternSelection( true ); + } ); } - function resetRemoteData() { - props.setAttributes( { remoteData: undefined } ); - resetReadyForInsertion(); + function updateRemoteData( remoteData?: RemoteData ): void { + if ( hasRemoteDataChanged( props.attributes.remoteData, remoteData ) ) { + props.setAttributes( { remoteData } ); + } } - useEffect( () => { - // Refetch remote data for initial load - refreshRemoteData(); - }, [] ); - // No remote data has been selected yet, show a placeholder. - if ( ! props.attributes.remoteData ) { - if ( ! hasInputVariables ) { - return null; - } - + if ( ! data ) { return (
- +
); } if ( showPatternSelection ) { - const supportedPatterns = getSupportedPatterns( props.attributes.remoteData?.results[ 0 ] ); - - if ( supportedPatterns.length ) { - return ( -
- -
- ); - } + const supportedPatterns = getSupportedPatterns( data.results[ 0 ] ); + + return ( +
+ +
+ ); } return ( @@ -134,18 +111,18 @@ export function Edit( props: BlockEditProps< RemoteDataBlockAttributes > ) {
- { initialLoad && ( + { loading && (
) {
diff --git a/src/blocks/remote-data-container/hooks/usePatterns.ts b/src/blocks/remote-data-container/hooks/usePatterns.ts index 336c3414..0a7e52d4 100644 --- a/src/blocks/remote-data-container/hooks/usePatterns.ts +++ b/src/blocks/remote-data-container/hooks/usePatterns.ts @@ -6,7 +6,6 @@ import { } from '@wordpress/block-editor'; import { BlockInstance, cloneBlock, createBlock } from '@wordpress/blocks'; import { useDispatch, useSelect } from '@wordpress/data'; -import { useState } from '@wordpress/element'; import { getBoundAttributeEntries, @@ -41,7 +40,6 @@ export function usePatterns( remoteDataBlockName: string, rootClientId: string = remoteDataBlockName, [ remoteDataBlockName, rootClientId ], ] ); - const [ showPatternSelection, setShowPatternSelection ] = useState< boolean >( false ); // Extract patterns with defined roles. const patternsByBlockTypes = getPatternsByBlockTypes( remoteDataBlockName ); @@ -80,9 +78,8 @@ export function usePatterns( remoteDataBlockName: string, rootClientId: string = ), } ) ); }, + innerBlocksPattern, insertPatternBlocks: ( pattern: BlockPattern ): void => { - setShowPatternSelection( false ); - // If the pattern is a synced pattern, insert it directly. if ( isSyncedPattern( pattern ) ) { const syncedPattern = createBlock( 'core/block', { ref: pattern.id } ); @@ -107,19 +104,9 @@ export function usePatterns( remoteDataBlockName: string, rootClientId: string = replaceInnerBlocks( rootClientId, patternBlocks ).catch( () => {} ); }, - markReadyForInsertion: (): void => { - if ( innerBlocksPattern ) { - returnValue.insertPatternBlocks( innerBlocksPattern ); - return; - } - - setShowPatternSelection( true ); - }, - resetReadyForInsertion: (): void => { + resetInnerBlocks: (): void => { replaceInnerBlocks( rootClientId, [] ).catch( () => {} ); - setShowPatternSelection( false ); }, - showPatternSelection, }; return returnValue; diff --git a/src/blocks/remote-data-container/hooks/useRemoteData.ts b/src/blocks/remote-data-container/hooks/useRemoteData.ts index b34c698d..816a897a 100644 --- a/src/blocks/remote-data-container/hooks/useRemoteData.ts +++ b/src/blocks/remote-data-container/hooks/useRemoteData.ts @@ -32,21 +32,45 @@ async function fetchRemoteData( requestData: RemoteDataApiRequest ): Promise< Re }; } -// This hook fetches remote data and provides state for the data and loading -// status. If you do not need a separate state update for the data, you can -// instruct the `execute` function to skip it. +interface UseRemoteData { + data?: RemoteData; + fetch: ( queryInput: RemoteDataQueryInput ) => Promise< void >; + loading: boolean; + reset: () => void; +} + +interface UseRemoteDataInput { + blockName: string; + enabledOverrides?: string[]; + externallyManagedRemoteData?: RemoteData; + externallyManagedUpdateRemoteData?: ( remoteData?: RemoteData ) => void; + onSuccess?: () => void; + queryKey: string; +} + +// This hook fetches remote data and manages state for the requests. +// +// If you have another way to manage the state of the remote data, then you must +// pass in the data and a state updater function. // // Use case: You might be fetching data only to provide it to setAttributes, // which is already reactive. Or you might be chaining multiple calls and // don't need an intermediate state update / re-render. -export function useRemoteData( blockName: string, queryKey: string ) { - const [ data, setData ] = useState< RemoteData | null >( null ); +export function useRemoteData( { + blockName, + enabledOverrides = [], + externallyManagedRemoteData, + externallyManagedUpdateRemoteData, + onSuccess, + queryKey, +}: UseRemoteDataInput ): UseRemoteData { + const [ data, setData ] = useState< RemoteData >(); const [ loading, setLoading ] = useState< boolean >( false ); - async function execute( - queryInput: RemoteDataQueryInput, - updateDataState = true - ): Promise< RemoteData | null > { + const resolvedData = externallyManagedRemoteData ?? data; + const resolvedUpdater = externallyManagedUpdateRemoteData ?? setData; + + async function fetch( queryInput: RemoteDataQueryInput ): Promise< void > { setLoading( true ); const requestData: RemoteDataApiRequest = { @@ -57,14 +81,25 @@ export function useRemoteData( blockName: string, queryKey: string ) { const remoteData = await fetchRemoteData( requestData ).catch( () => null ); - if ( updateDataState ) { - setData( remoteData ); + if ( ! remoteData ) { + resolvedUpdater( undefined ); + setLoading( false ); + return; } + resolvedUpdater( { enabledOverrides, ...remoteData } ); setLoading( false ); + onSuccess?.(); + } - return remoteData; + function reset(): void { + resolvedUpdater( undefined ); } - return { data, execute, loading }; + return { + data: resolvedData, + fetch, + loading, + reset, + }; } diff --git a/src/blocks/remote-data-container/hooks/useSearchResults.ts b/src/blocks/remote-data-container/hooks/useSearchResults.ts index 707da7e0..c4570db9 100644 --- a/src/blocks/remote-data-container/hooks/useSearchResults.ts +++ b/src/blocks/remote-data-container/hooks/useSearchResults.ts @@ -15,11 +15,11 @@ export function useSearchResults( { queryKey, }: UseSearchResultsInput ) { const [ searchTerms, setSearchTerms ] = useState< string >( '' ); - const { data, execute, loading } = useRemoteData( blockName, queryKey ); + const { data, fetch, loading } = useRemoteData( { blockName, queryKey } ); const timer = useRef< NodeJS.Timeout >(); function onSubmit(): void { - void execute( { search_terms: searchTerms } ); + void fetch( { search_terms: searchTerms } ); } function onKeyDown( event: React.KeyboardEvent< HTMLInputElement > ): void { From 64af67de2a0c7ba427792d05f954e694c39ddb88 Mon Sep 17 00:00:00 2001 From: Brooke Date: Thu, 6 Feb 2025 08:36:37 -0800 Subject: [PATCH 07/16] Update field shortcode UI (#352) * Replace shortcode modal with dropdown Signed-off-by: brookewp * Avoid nesting single menu item Signed-off-by: brookewp * Swap out main dropdown for toolbardropdown Signed-off-by: brookewp * Update styles Signed-off-by: brookewp * Add classname prop to refine styles Signed-off-by: brookewp * Update field popover Signed-off-by: brookewp * Potential fix for fatal metadata issue Signed-off-by: brookewp * Correctly provide context to both BlockBindings::get_value and ::execute_query --------- Signed-off-by: brookewp Co-authored-by: chriszarate --- inc/Editor/DataBinding/FieldShortcode.php | 13 +- .../field-shortcode/FieldShortcode.scss | 49 ++++++ .../field-shortcode/FieldShortcodeButton.tsx | 140 ++++++++---------- .../FieldShortcodeSelectExisting.tsx | 58 ++++---- .../FieldShortcodeSelectFieldPopover.tsx | 5 +- .../FieldShortcodeSelectMeta.tsx | 58 ++++---- .../FieldShortcodeSelectNew.tsx | 74 ++++++--- .../FieldShortcodeSelectTabs.tsx | 44 ------ .../FieldShortcodeSelection.tsx | 55 ++++--- .../components/item-list/ItemList.tsx | 127 ++++++++++++---- .../components/modals/DataViewsModal.tsx | 83 ++++++----- .../placeholders/ItemSelectQueryType.tsx | 8 +- src/blocks/remote-data-container/editor.scss | 2 +- .../hooks/useSearchResults.ts | 2 +- 14 files changed, 421 insertions(+), 297 deletions(-) create mode 100644 src/blocks/remote-data-container/components/field-shortcode/FieldShortcode.scss delete mode 100644 src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectTabs.tsx diff --git a/inc/Editor/DataBinding/FieldShortcode.php b/inc/Editor/DataBinding/FieldShortcode.php index 3738d5b0..1ac0dcf5 100644 --- a/inc/Editor/DataBinding/FieldShortcode.php +++ b/inc/Editor/DataBinding/FieldShortcode.php @@ -9,7 +9,7 @@ public static function init(): void { add_action( 'the_content', [ __CLASS__, 'render_frontend_fields' ] ); } - private static function get_meta_field_value( array $context, string $field ): string|null { + private static function get_meta_field_value( array $context, string $field ): string|int|null { $query_results = BlockBindings::execute_query( $context, $field ); if ( isset( $query_results['metadata'][ $field ]['value'] ) ) { @@ -46,19 +46,20 @@ public static function render_frontend_fields( string $content ): string { $status = 'parse-error'; $value = $fallback_value; } else { + $context = [ + 'blockName' => $query_data['remoteData']['blockName'], + 'queryInput' => $query_data['remoteData']['queryInput'], + ]; $block = [ 'context' => [ - BlockBindings::$context_name => [ - 'blockName' => $query_data['remoteData']['blockName'], - 'queryInput' => $query_data['remoteData']['queryInput'], - ], + BlockBindings::$context_name => $context, ], ]; $field = $query_data['selectedField']; $type = $query_data['type'] ?? 'field'; if ( 'meta' === $type ) { - $value = self::get_meta_field_value( $block['context'], $field ); + $value = self::get_meta_field_value( $context, $field ); } else { $value = BlockBindings::get_value( [ 'field' => $field ], $block ); } diff --git a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcode.scss b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcode.scss new file mode 100644 index 00000000..e56f65b9 --- /dev/null +++ b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcode.scss @@ -0,0 +1,49 @@ + +.rdb-field-shortcode_dropdown, +.remote-data-blocks-field-shortcode-dropdown { + + .components-popover__content { + width: unset; + min-width: 160px; + max-width: 320px; + } +} + +.rdb-field-shortcode_dropdown { + + .components-toolbar-group { + display: flex; + flex-direction: column; + border-right: none; + + .components-dropdown-menu { + + .components-dropdown-menu__toggle { + display: flex; + flex-direction: row-reverse; + justify-content: space-between; + width: 100%; + } + } + } +} + +.remote-data-blocks-inline-field { + + span.components-menu-item__item { + width: 100%; + + .remote-data-blocks-inline-field-choice { + + width: 100%; + + .components-base-control__field { + display: flex; + flex-direction: row; + justify-content: space-between; + } + } + + } +} + diff --git a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeButton.tsx b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeButton.tsx index 3be0959a..13456f4f 100644 --- a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeButton.tsx +++ b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeButton.tsx @@ -1,18 +1,21 @@ import { BlockControls } from '@wordpress/block-editor'; -import { Modal, ToolbarButton, ToolbarGroup } from '@wordpress/components'; +import { ToolbarDropdownMenu, ToolbarGroup } from '@wordpress/components'; import { useEffect, useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { RichTextFormat, insertObject, WPFormatEditProps } from '@wordpress/rich-text'; +import { FieldShortcodeSelectExisting } from './FieldShortcodeSelectExisting'; +import { FieldShortcodeSelectMeta } from './FieldShortcodeSelectMeta'; +import { FieldShortcodeSelectNew } from './FieldShortcodeSelectNew'; +import { useExistingRemoteData } from '../../hooks/useExistingRemoteData'; import { formatName, formatTypeSettings, } from '@/blocks/remote-data-container/components/field-shortcode'; import { FieldShortcodeSelectFieldPopover } from '@/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectFieldPopover'; -import { FieldShortcodeSelectTabs } from '@/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectTabs'; -import { FieldShortcodeSelectField } from '@/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelection'; import { sendTracksEvent } from '@/blocks/remote-data-container/utils/tracks'; import { getBlockDataSourceType } from '@/utils/localized-block-data'; +import './FieldShortcode.scss'; function parseDataQuery( dataQuery?: string ): FieldSelection | null { if ( ! dataQuery ) { @@ -26,36 +29,18 @@ function parseDataQuery( dataQuery?: string ): FieldSelection | null { } } -interface QueryInput { - blockName: string; - queryInput: RemoteDataQueryInput; -} - export function FieldShortcodeButton( props: WPFormatEditProps ) { const { onChange, onFocus, value, isObjectActive, activeObjectAttributes, contentRef } = props; const fieldSelection = parseDataQuery( activeObjectAttributes?.[ 'data-query' ] ); - - const [ queryInput, setQueryInput ] = useState< QueryInput | null >( null ); const [ showUI, setShowUI ] = useState< boolean >( false ); - function onClick() { - setShowUI( ! showUI ); - sendTracksEvent( 'remotedatablocks_field_shortcode', { action: 'toolbar_icon_clicked' } ); - } - - function onClose() { - setShowUI( false ); - onFocus(); - } - - function onSelectItem( config: BlockConfig, data: RemoteDataQueryInput ) { - setQueryInput( { - blockName: config.name, - queryInput: data, - } ); - } + useEffect( () => { + if ( isObjectActive ) { + setShowUI( true ); + } + }, [ isObjectActive ] ); - function updateOrInsertField( data: FieldSelection | null, fieldValue: string ) { + const updateOrInsertField = ( data: FieldSelection | null, fieldValue: string ) => { const format: RichTextFormat = { attributes: { ...activeObjectAttributes, @@ -65,86 +50,79 @@ export function FieldShortcodeButton( props: WPFormatEditProps ) { type: formatName, }; - if ( Object.keys( activeObjectAttributes ).length ) { - const replacements = value.replacements.slice(); - replacements[ value.start ] = format; - - onChange( { ...value, replacements } ); - return; - } - - onChange( insertObject( value, format ) ); - } - - function onSelectField( data: FieldSelection, fieldValue: string ) { + onChange( + Object.keys( activeObjectAttributes ).length + ? { + ...value, + replacements: value.replacements.map( ( replacement, index ) => + index === value.start ? format : replacement + ), + } + : insertObject( value, format ) + ); + }; + + const onSelectField = ( data: FieldSelection, fieldValue: string ) => { updateOrInsertField( data, fieldValue ); - onClose(); + setShowUI( false ); + onFocus(); sendTracksEvent( 'remotedatablocks_field_shortcode', { action: data.action, data_source_type: getBlockDataSourceType( data.remoteData?.blockName ), selection_path: data.selectionPath, } ); - } + }; - function resetField( blockName?: string ): void { + const resetField = ( blockName?: string ): void => { updateOrInsertField( null, 'Unbound field' ); - setQueryInput( null ); sendTracksEvent( 'remotedatablocks_field_shortcode', { action: 'reset_field_shortcode', data_source_type: getBlockDataSourceType( blockName ), } ); - } + }; - useEffect( () => { - if ( isObjectActive ) { - setShowUI( true ); - } - }, [ isObjectActive ] ); + const remoteData = useExistingRemoteData(); return ( <> - - - - - { showUI && ! fieldSelection && ( - - { ! queryInput && ( - 0 ? ( + + { () => ( + + + + + + ) } + + ) : ( + - ) } - { queryInput && ( - - onSelectField( { ...data, selectionPath: 'select_new_tab' }, fieldValue ) - } - queryInput={ queryInput.queryInput } - fieldType="field" + icon="shortcode" + label={ __( 'Select block bindings', 'remote-data-blocks' ) } + popoverProps={ { offset: 8, placement: 'bottom-start' } } + text={ undefined } /> ) } - - ) } + + + { showUI && fieldSelection && ( { + setShowUI( false ); + onFocus(); + } } onSelectField={ ( data, fieldValue ) => onSelectField( { ...data, selectionPath: 'popover' }, fieldValue ) } diff --git a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectExisting.tsx b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectExisting.tsx index 1abd6270..52880326 100644 --- a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectExisting.tsx +++ b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectExisting.tsx @@ -1,4 +1,6 @@ -import { __experimentalHeading as Heading } from '@wordpress/components'; +import { DropdownMenu, MenuGroup } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { chevronRightSmall } from '@wordpress/icons'; import { FieldSelectionFromAvailableBindings } from '@/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelection'; import { useExistingRemoteData } from '@/blocks/remote-data-container/hooks/useExistingRemoteData'; @@ -14,30 +16,32 @@ export function FieldShortcodeSelectExisting( props: FieldShortcodeSelectExistin remoteData => ! remoteData.isCollection ); - if ( remoteDatas.length === 0 ) { - return ( -
-

No existing items.

-
- ); - } - - return ( -
- { remoteDatas.map( remoteData => ( -
- - { blockConfigs[ remoteData.blockName ]?.settings.title ?? remoteData.blockName } - - - - props.onSelectField( { ...data, selectionPath: 'select_existing_tab' }, fieldValue ) - } - remoteData={ remoteData } - /> -
- ) ) } -
- ); + return remoteDatas.length > 0 ? ( + + { () => + remoteDatas.map( remoteData => ( + + + props.onSelectField( { ...data, selectionPath: 'select_existing_tab' }, fieldValue ) + } + remoteData={ remoteData } + /> + + ) ) + } + + ) : undefined; } diff --git a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectFieldPopover.tsx b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectFieldPopover.tsx index 743ae59a..5e535b8f 100644 --- a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectFieldPopover.tsx +++ b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectFieldPopover.tsx @@ -7,6 +7,7 @@ import { __experimentalHeading as Heading, Popover, } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; import { WPFormat, useAnchor } from '@wordpress/rich-text'; import { FieldShortcodeSelectField } from '@/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelection'; @@ -40,7 +41,7 @@ export function FieldShortcodeSelectFieldPopover( props: FieldShortcodeSelectFie > - Select a field to bind + { __( 'Select a field to bind', 'remote-data-blocks' ) } diff --git a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectMeta.tsx b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectMeta.tsx index 6892c471..57b36a1a 100644 --- a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectMeta.tsx +++ b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectMeta.tsx @@ -1,4 +1,6 @@ -import { __experimentalHeading as Heading } from '@wordpress/components'; +import { DropdownMenu, MenuGroup } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { chevronRightSmall } from '@wordpress/icons'; import { FieldSelectionFromMetaFields } from '@/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelection'; import { useExistingRemoteData } from '@/blocks/remote-data-container/hooks/useExistingRemoteData'; @@ -12,30 +14,32 @@ export function FieldShortcodeSelectMeta( props: FieldShortcodeSelectMetaProps ) const blockConfigs = getBlocksConfig(); const remoteDatas: RemoteData[] = useExistingRemoteData(); - if ( remoteDatas.length === 0 ) { - return ( -
-

No query metadata avaialble.

-
- ); - } - - return ( -
- { remoteDatas.map( remoteData => ( -
- - { blockConfigs[ remoteData.blockName ]?.settings.title ?? remoteData.blockName } - - - - props.onSelectField( { ...data, selectionPath: 'select_meta_tab' }, fieldValue ) - } - remoteData={ remoteData } - /> -
- ) ) } -
- ); + return remoteDatas.length > 0 ? ( + + { () => + remoteDatas.map( remoteData => ( + + + props.onSelectField( { ...data, selectionPath: 'select_meta_tab' }, fieldValue ) + } + remoteData={ remoteData } + /> + + ) ) + } + + ) : undefined; } diff --git a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectNew.tsx b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectNew.tsx index dd189ac9..bcd72592 100644 --- a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectNew.tsx +++ b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectNew.tsx @@ -1,28 +1,62 @@ -import { __experimentalHeading as Heading } from '@wordpress/components'; +import { DropdownMenu, MenuGroup, MenuItem } from '@wordpress/components'; +import { DropdownMenuProps } from '@wordpress/components/build-types/dropdown-menu/types'; +import { __ } from '@wordpress/i18n'; +import { chevronRightSmall } from '@wordpress/icons'; -import { ItemSelectQueryType } from '@/blocks/remote-data-container/components/placeholders/ItemSelectQueryType'; +import { DataViewsModal } from '../modals/DataViewsModal'; import { getBlocksConfig } from '@/utils/localized-block-data'; -interface FieldShortcodeSelectNewProps { - onSelectItem: ( config: BlockConfig, data: RemoteDataQueryInput ) => void; -} +type FieldShortcodeSelectNewProps = Omit< DropdownMenuProps, 'label' > & { + onSelectField: ( data: FieldSelection, fieldValue: string ) => void; + label?: string; +}; export function FieldShortcodeSelectNew( props: FieldShortcodeSelectNewProps ) { + const { onSelectField, ...restProps } = props; + const blockConfigs = getBlocksConfig(); + const nonLoopBlocks = Object.values( blockConfigs ).filter( ( { loop } ) => ! loop ); + const blocksByType = nonLoopBlocks.reduce< + Record< string, Array< BlocksConfig[ keyof BlocksConfig ] > > + >( ( source, blockConfig ) => { + const type = blockConfig.dataSourceType; + if ( ! source[ type ] ) { + source[ type ] = []; + } + source[ type ].push( blockConfig ); + return source; + }, {} ); + return ( -
- { Object.values( getBlocksConfig() ) - .filter( ( { loop } ) => ! loop ) - .map( blockConfig => ( -
- - { blockConfig.settings.title } - - props.onSelectItem( blockConfig, data ) } - /> -
- ) ) } -
+ + { () => + Object.entries( blocksByType ).map( ( [ dataSourceType, configs ] ) => ( + + { configs.map( blockConfig => ( + ( + + { blockConfig.settings?.title ?? blockConfig.name } + + ) } + /> + ) ) } + + ) ) + } + ); } diff --git a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectTabs.tsx b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectTabs.tsx deleted file mode 100644 index fe463df3..00000000 --- a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectTabs.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { TabPanel } from '@wordpress/components'; - -import { FieldShortcodeSelectExisting } from '@/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectExisting'; -import { FieldShortcodeSelectMeta } from '@/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectMeta'; -import { FieldShortcodeSelectNew } from '@/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectNew'; - -interface FieldShortcodeSelectTabsProps { - onSelectField: ( data: FieldSelection, fieldValue: string ) => void; - onSelectItem: ( config: BlockConfig, data: RemoteDataQueryInput ) => void; -} - -export function FieldShortcodeSelectTabs( props: FieldShortcodeSelectTabsProps ) { - return ( - - { tab => { - switch ( tab.name ) { - case 'existing': - return ; - - case 'new': - return ; - - case 'meta': - return ; - } - } } - - ); -} diff --git a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelection.tsx b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelection.tsx index 242ed7be..22f18b44 100644 --- a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelection.tsx +++ b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelection.tsx @@ -1,4 +1,4 @@ -import { Spinner } from '@wordpress/components'; +import { BaseControl, Icon, MenuItem, Spinner } from '@wordpress/components'; import { useEffect } from '@wordpress/element'; import { check } from '@wordpress/icons'; @@ -30,28 +30,41 @@ export function FieldSelection( props: FieldSelectionProps ) { }; return ( -
- { fieldDetails.name }:{ ' ' } - { - evt.preventDefault(); + { + evt.preventDefault(); + props.onSelectField( fieldSelection, fieldDetails.value ); + } } + onKeyDown={ evt => { + if ( evt.key.toLowerCase() === 'enter' ) { props.onSelectField( fieldSelection, fieldDetails.value ); - } } - onKeyDown={ evt => { - if ( evt.key.toLowerCase() === 'enter' ) { - props.onSelectField( fieldSelection, fieldDetails.value ); - } - } } - > + } + } } + suffix={ + props.selectedField === fieldName ? ( + + ) : undefined + } + > + + + { fieldDetails.name }: + { fieldDetails.value } - { props.selectedField === fieldName && ( - { check } - ) } - -
+ + ); } ) } diff --git a/src/blocks/remote-data-container/components/item-list/ItemList.tsx b/src/blocks/remote-data-container/components/item-list/ItemList.tsx index 7ce1d91f..53912e00 100644 --- a/src/blocks/remote-data-container/components/item-list/ItemList.tsx +++ b/src/blocks/remote-data-container/components/item-list/ItemList.tsx @@ -1,3 +1,4 @@ +import { Button } from '@wordpress/components'; import { useInstanceId } from '@wordpress/compose'; import { DataViews, filterSortAndPaginate, View } from '@wordpress/dataviews/wp'; import { useEffect, useMemo, useState } from '@wordpress/element'; @@ -10,14 +11,49 @@ interface ItemListProps { blockName: string; loading: boolean; onSelect: ( data: RemoteDataQueryInput ) => void; - results?: RemoteDataResult[]; + onSelectField?: ( data: FieldSelection, fieldValue: string ) => void; + remoteData?: RemoteData; searchTerms: string; setSearchTerms: ( newValue: string ) => void; } +const createFieldSelection = ( + field: string, + item: RemoteDataResult, + blockName: string, + remoteData: RemoteData +): FieldSelection => ( { + action: 'add_field_shortcode', + remoteData: { + ...remoteData, + blockName, + queryInput: { + ...item, + field: { + field, + value: item[ field ] as string, + }, + }, + resultId: item.id?.toString() ?? '', + results: [ item ], + }, + selectedField: field, + selectionPath: 'select_new_tab', + type: 'field', +} ); + export function ItemList( props: ItemListProps ) { - const { availableBindings, blockName, loading, onSelect, results, searchTerms, setSearchTerms } = - props; + const { + availableBindings, + blockName, + loading, + onSelect, + onSelectField, + remoteData, + searchTerms, + setSearchTerms, + } = props; + const results = remoteData?.results ?? []; const { defaultPattern: pattern } = usePatterns( blockName ); const instanceId = useInstanceId( ItemList, blockName ); @@ -68,26 +104,50 @@ export function ItemList( props: ItemListProps ) { ( [ _, binding ] ) => binding.type === 'image_url' )?.[ 0 ]; - const fieldObject = getFields.map( field => { - return { - id: field, - label: availableBindings[ field ]?.name ?? field, - enableGlobalSearch: true, - getValue: ( { item }: { item: RemoteDataResult } ) => item[ field ] as string, - render: - field === media - ? ( { item }: { item: RemoteDataResult } ) => { - return ( - { - ); - } - : undefined, - enableSorting: field !== media, - }; - } ); + const renderField = ( field: string, item: RemoteDataResult ) => { + if ( field === media ) { + return {; + } + + if ( onSelectField && remoteData ) { + const queryInput: RemoteDataQueryInput = { + ...item, + field: { + field, + value: item[ field ] as string, + }, + }; + + return ( + + ); + } + + return item[ field ] as string; + }; + + const fieldObject = getFields.map( field => ( { + id: field, + label: availableBindings[ field ]?.name ?? field, + enableGlobalSearch: true, + getValue: ( { item }: { item: RemoteDataResult } ) => item[ field ] as string, + render: ( { item }: { item: RemoteDataResult } ) => renderField( field, item ), + enableSorting: field !== media, + } ) ); return { fields: fieldObject, tableFields: getFields, titleField: title, mediaField: media }; - }, [ availableBindings, data ] ); + }, [ availableBindings, data, onSelectField, remoteData ] ); const [ view, setView ] = useState< View >( { type: 'table' as const, @@ -130,17 +190,20 @@ export function ItemList( props: ItemListProps ) { return filterSortAndPaginate( data ?? [], view, fields ); }, [ data, view ] ); - const actions = [ - { - id: 'choose', - icon: <>{ __( 'Choose' ) }, - isPrimary: true, - label: '', - callback: ( items: RemoteDataResult[] ) => { - items.map( item => onSelect( item ) ); - }, - }, - ]; + // Hide actions for field shortcode selection + const actions = ! onSelectField + ? [ + { + id: 'choose', + icon: <>{ __( 'Choose' ) }, + isPrimary: true, + label: '', + callback: ( items: RemoteDataResult[] ) => { + items.map( item => onSelect( item ) ); + }, + }, + ] + : []; return ( void; + onSelect?: ( data: RemoteDataQueryInput ) => void; + onSelectField?: ( data: FieldSelection, fieldValue: string ) => void; queryKey: string; - title: string; + renderTrigger?: ( props: { onClick: () => void } ) => React.ReactNode; + title?: string; } export const DataViewsModal: React.FC< DataViewsModalProps > = props => { - const { blockName, onSelect, queryKey, title } = props; + const { className, blockName, onSelect, onSelectField, queryKey, renderTrigger, title } = props; + + const blockConfig = getBlockConfig( blockName ); + const availableBindings = getBlockAvailableBindings( blockName ); - const { loading, results, searchTerms, setSearchTerms } = useSearchResults( { + const { + loading, + data: remoteData, + searchTerms, + setSearchTerms, + } = useSearchResults( { blockName, queryKey, } ); const { close, isOpen, open } = useModalState(); - function onSelectItem( data: RemoteDataQueryInput ): void { - onSelect( data ); - sendTracksEvent( 'remotedatablocks_add_block', { - action: 'select_item', - selected_option: 'search_from_list', - data_source_type: getBlockDataSourceType( blockName ), - } ); - close(); - } + const handleSelect = ( data: RemoteDataQueryInput ): void => { + onSelect?.( data ); + }; + const triggerElement = renderTrigger ? ( + renderTrigger( { onClick: open } ) + ) : ( + + ); return ( - - - + <> + { triggerElement } + { isOpen && ( + + + + ) } + ); }; diff --git a/src/blocks/remote-data-container/components/placeholders/ItemSelectQueryType.tsx b/src/blocks/remote-data-container/components/placeholders/ItemSelectQueryType.tsx index ae31a187..04abcdfa 100644 --- a/src/blocks/remote-data-container/components/placeholders/ItemSelectQueryType.tsx +++ b/src/blocks/remote-data-container/components/placeholders/ItemSelectQueryType.tsx @@ -29,7 +29,13 @@ export function ItemSelectQueryType( props: ItemSelectQueryTypeProps ) { switch ( selector.type ) { case 'search': case 'list': - return ; + return ( + + ); case 'input': return ; } diff --git a/src/blocks/remote-data-container/editor.scss b/src/blocks/remote-data-container/editor.scss index f5bd0d16..8b3034ec 100644 --- a/src/blocks/remote-data-container/editor.scss +++ b/src/blocks/remote-data-container/editor.scss @@ -82,7 +82,7 @@ remote-data-blocks-inline-field { box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1); } -.dataviews-view-table tbody .dataviews-view-table__cell-content-wrapper:not(.dataviews-column-primary__media) { +.rdb-editor_dataviews-modal-item-select .dataviews-view-table tbody .dataviews-view-table__cell-content-wrapper:not(.dataviews-column-primary__media) { white-space: normal; width: 250px; max-width: 100%; diff --git a/src/blocks/remote-data-container/hooks/useSearchResults.ts b/src/blocks/remote-data-container/hooks/useSearchResults.ts index c4570db9..fcf01a47 100644 --- a/src/blocks/remote-data-container/hooks/useSearchResults.ts +++ b/src/blocks/remote-data-container/hooks/useSearchResults.ts @@ -45,7 +45,7 @@ export function useSearchResults( { return { loading, onKeyDown, - results: data?.results, + data, searchTerms, setSearchTerms, }; From 243d6ea3f82b8d863d593479a9b22bf2fb434c82 Mon Sep 17 00:00:00 2001 From: Chris Zarate Date: Fri, 7 Feb 2025 19:17:05 -0500 Subject: [PATCH 08/16] Add `ui:search_input` input variable (#337) * Update useRemoteData to be more explicit about state management * Add ui:search input variable * Update useRemoteData to implement search * Update Art Institute example with ui:search variable * Update search documentation * Update useDebouncedState to avoid need for ref * Revert "Update useDebouncedState to avoid need for ref" This reverts commit 77656a05386dec8562a39d44c0fe8e0c39f406f3. * Fix selector in FieldShortcodeSelectNew * Implement query pagination (#338) * Implement pagination * Update documentation for pagination * Update Art Institute example * Update Query docs * Fix a few schema references * Move field filter to useful place * Move removeNullValues to util * Refactor ItemList to remove memos * Tighten up Co-authored-by: Max Schmeling --------- Co-authored-by: Max Schmeling --------- Co-authored-by: Max Schmeling --- docs/concepts/index.md | 8 +- docs/extending/block-registration.md | 12 +- docs/extending/query.md | 67 ++++- .../rest-api/art-institute/art-institute.php | 36 ++- inc/Config/Query/HttpQuery.php | 8 + inc/Config/Query/QueryInterface.php | 1 + .../QueryRunner/QueryResponseParser.php | 5 + inc/Config/QueryRunner/QueryRunner.php | 16 ++ inc/Editor/BlockManagement/ConfigRegistry.php | 19 +- .../SalesforceB2CIntegration.php | 6 +- .../Shopify/ShopifyIntegration.php | 4 +- inc/Validation/ConfigSchemas.php | 86 +++++- .../FieldShortcodeSelectNew.tsx | 40 ++- .../components/item-list/ItemList.tsx | 271 +++++++----------- .../components/item-list/ItemListField.tsx | 71 +++++ .../components/modals/DataViewsModal.tsx | 73 +++-- .../placeholders/ItemSelectQueryType.tsx | 1 + .../remote-data-container/config/constants.ts | 7 + .../hooks/usePaginationVariables.ts | 137 +++++++++ .../hooks/useRemoteData.ts | 82 +++++- .../hooks/useSearchResults.ts | 52 ---- .../hooks/useSearchVariables.ts | 41 +++ src/hooks/useDebouncedState.ts | 21 ++ src/utils/type-narrowing.ts | 8 + tests/inc/Functions/FunctionsTest.php | 4 +- tests/src/utils/type-narrowing.test.ts | 15 +- types/remote-data.d.ts | 12 + 27 files changed, 823 insertions(+), 280 deletions(-) create mode 100644 src/blocks/remote-data-container/components/item-list/ItemListField.tsx create mode 100644 src/blocks/remote-data-container/hooks/usePaginationVariables.ts delete mode 100644 src/blocks/remote-data-container/hooks/useSearchResults.ts create mode 100644 src/blocks/remote-data-container/hooks/useSearchVariables.ts create mode 100644 src/hooks/useDebouncedState.ts diff --git a/docs/concepts/index.md b/docs/concepts/index.md index e7066668..9f04e676 100644 --- a/docs/concepts/index.md +++ b/docs/concepts/index.md @@ -18,8 +18,8 @@ Below, you'll find specific use cases where Remote Data Blocks shines. We are wo - **Example:** Create a page and rewrite rule for /products/{product_id}/ and configure a Remote Data Block on that page to display the referenced product. - Your presentation of remote data aligns with the capabilities of Block Bindings. - **Example:** Display an item of clothing using a core paragraph, heading, image, and button blocks. -- You do not require complex filtering or pagination. - - **Example:** To select an item of clothing, load a finite list of top-selling products or search all products by a specific term. +- You do not require complex filtering. + - **Example:** To select an item of clothing, load a list of top-selling products or search all products by a specific term. - Your data is denormalized and relatively flat. - **Example:** A row from a Google Sheet with no references to external entities. @@ -35,8 +35,8 @@ Below, you'll find specific use cases where Remote Data Blocks shines. We are wo - You have multiple remote data sources that require interaction. Or, you want to implement a complex content architecture using Remote Data Blocks instead of leveraging WordPress custom post types and/or taxonomies. - These two challenges are directly related to the issues with normalized data. If you have data sources that relate to one another, you have to write custom code to query missing data and stitch them together. - Judging complexity is difficult, but implementing large applications using Remote Data Blocks is not advisable. -- You require complex filtering or rely heavily on pagination. - - Our UI components for filtering and pagination are still under development. +- You require complex filtering or have complex pagination needs. + - Our UI components for filtering are pagination still under development. Over time, Remote Data Blocks will grow and improve and these guidelines will change. diff --git a/docs/extending/block-registration.md b/docs/extending/block-registration.md index 8451909a..90f9ba75 100644 --- a/docs/extending/block-registration.md +++ b/docs/extending/block-registration.md @@ -95,21 +95,21 @@ Example: #### Search queries -Search queries must return a collection and must accept a string input variable of `search_terms`. The [Art Institute of Chicago](https://github.com/Automattic/remote-data-blocks/blob/trunk/example/rest-api/art-institute/README.md) example looks like this: +Search queries must return a collection and must accept one input variable with the special type `ui:search_input`. The [Art Institute of Chicago](https://github.com/Automattic/remote-data-blocks/blob/trunk/example/rest-api/art-institute/README.md) example looks like this: ```php $search_art_query = HttpQuery::from_array([ 'data_source' => $aic_data_source, 'endpoint' => function ( array $input_variables ) use ( $aic_data_source ): string { - $query = $input_variables['search_terms']; + $query = $input_variables['search']; $endpoint = $aic_data_source->get_endpoint() . '/search'; return add_query_arg( [ 'q' => $query ], $endpoint ); }, 'input_schema' => [ - 'search_terms' => [ - 'name' => 'Search Terms', - 'type' => 'string', + 'search' => [ + 'name' => 'Search terms', + 'type' => 'ui:search_input', ], ], 'output_schema' => [ @@ -129,7 +129,7 @@ $search_art_query = HttpQuery::from_array([ ]); ``` -Here you can see the input variable of `search_terms` is used in the endpoint method to populate a query string. You can read more about [queries](./query.md) and how to construct them. End users enter the search term to find the specific item. +Here you can see the `search` input variable has a special type of `ui:search_input` and is used in the endpoint method to populate a query string. You can read more about [queries](./query.md) and how to construct them. End users enter the search term to find the specific item. ![Screenshot showing the search inputin the WordPress Editor](https://raw.githubusercontent.com/Automattic/remote-data-blocks/trunk/docs/extending/search-input.png) diff --git a/docs/extending/query.md b/docs/extending/query.md index 7ff6649e..52002d15 100644 --- a/docs/extending/query.md +++ b/docs/extending/query.md @@ -84,7 +84,7 @@ The `endpoint` property defines the query endpoint. It can be a string or a call ### input_schema: array -The `input_schema` property defines the input variables expected by the query. The method should return an associative array of input variable definitions. The keys of the array are machine-friendly input variable names, and the values are associative arrays with the following structure: +The `input_schema` property defines the input variables expected by the query. The property should be an associative array of input variable definitions. The keys of the array are machine-friendly input variable names, and the values are associative arrays with the following structure: - `name` (optional): The human-friendly display name of the input variable - `default_value` (optional): The default value for the input variable. @@ -107,11 +107,40 @@ The `input_schema` property defines the input variables expected by the query. T ], ``` -If omitted, it defaults to an empty array. +There are also some special input variable types: + +- `ui:search_input`: A variable with this type indicates that the query supports searching. It must accept a `string` containing search terms. +- `ui:pagination_offset`: A variable with this type indicates that the query supports offset pagination. It must accept an `integer` containing the requested offset. See `pagination_schema` for additional information and requirements. +- `ui:pagination_page`: A variable with this type indicates that the query supports page-based pagination. It must accept an `integer` containing the requested results page. See `pagination_schema` for additional information and requirements. +- `ui:pagination_per_page`: A variable with this type indicates that the query supports controlling the number of resultsper page. It must accept an `integer` containing the number of requested results. +- `ui:pagination_cursor_next` and `ui_pagination_cursor_previous`: Variables with these types indicate that the query supports cursor pagination. They accept `strings` containing the requested cursor. See `pagination_schema` for additional information and requirements. + +#### Example with search and pagination input variables + +```php +'input_schema' => [ + 'search' => [ + 'name' => 'Search terms', + 'type' => 'ui:search_input', + ], + 'limit' => [ + 'default_value' => 10, + 'name' => 'Pagination limit', + 'type' => 'ui:pagination_per_page', + ], + 'page' => [ + 'default_value' => 1, + 'name' => 'Pagination page', + 'type' => 'ui:pagination_page', + ], +], +``` + +If omitted, `input_schema` defaults to an empty array. ### output_schema: array (required) -The `output_schema` property defines how to extract data from the API response. The method should return an associative array with the following structure: +The `output_schema` property defines how to extract data from the API response. The property should be an associative array with the following structure: - `format` (optional): A callable function that formats the output variable value. - `generate` (optional): A callable function that generates or extracts the output variable value from the response, as an alternative to `path`. @@ -163,6 +192,38 @@ Accepted primitive types are: We have more in-depth [`output_schema`](./query-output_schema.md) examples. +### pagination_schema: array + +If your query supports pagination, the `pagination_schema` property defines how to extract pagination-related values from the query response. If defined, the property should be an associative array with the following structure: + +- `total_items` (required): A variable definition that extracts the total number of items across every page of results. +- `cursor_next`: If your query supports cursor pagination, a variable definition that extracts the cursor for the next page of results. +- `cursor_previous`: If your query supports cursor pagination, a variable definition that extracts the cursor for the previous page of results. + +Note that the `total_items` variable is required for all types of pagination. + +#### Example + +```php +'pagination_schema' => [ + 'total_items' => [ + 'name' => 'Total items', + 'path' => '$.pagination.totalItems', + 'type' => 'integer', + ], + 'cursor_next' => [ + 'name' => 'Next page cursor', + 'path' => '$.pagination.nextCursor', + 'type' => 'string', + ], + 'cursor_previous' => [ + 'name' => 'Previous page cursor', + 'path' => '$.pagination.previousCursor', + 'type' => 'string', + ], +], +``` + ### request_method: string The `request_method` property defines the HTTP request method used by the query. By default, it is `'GET'`. diff --git a/example/rest-api/art-institute/art-institute.php b/example/rest-api/art-institute/art-institute.php index 28cc0af2..f0e9c418 100644 --- a/example/rest-api/art-institute/art-institute.php +++ b/example/rest-api/art-institute/art-institute.php @@ -69,15 +69,32 @@ function register_aic_block(): void { $search_art_query = HttpQuery::from_array([ 'data_source' => $aic_data_source, 'endpoint' => function ( array $input_variables ) use ( $aic_data_source ): string { - $query = $input_variables['search_terms']; - $endpoint = $aic_data_source->get_endpoint() . '/search'; + $endpoint = $aic_data_source->get_endpoint(); + $search_terms = $input_variables['search'] ?? ''; - return add_query_arg( [ 'q' => $query ], $endpoint ); + if ( ! empty( $search_terms ) ) { + $endpoint = add_query_arg( [ 'q' => $search_terms ], $endpoint . '/search' ); + } + + return add_query_arg( [ + 'limit' => $input_variables['limit'], + 'page' => $input_variables['page'], + ], $endpoint ); }, 'input_schema' => [ - 'search_terms' => [ - 'name' => 'Search Terms', - 'type' => 'string', + 'search' => [ + 'name' => 'Search terms', + 'type' => 'ui:search_input', + ], + 'limit' => [ + 'default_value' => 10, + 'name' => 'Pagination limit', + 'type' => 'ui:pagination_per_page', + ], + 'page' => [ + 'default_value' => 1, + 'name' => 'Pagination page', + 'type' => 'ui:pagination_page', ], ], 'output_schema' => [ @@ -94,6 +111,13 @@ function register_aic_block(): void { ], ], ], + 'pagination_schema' => [ + 'total_items' => [ + 'name' => 'Total items', + 'path' => '$.pagination.total', + 'type' => 'integer', + ], + ], ]); register_remote_data_block([ diff --git a/inc/Config/Query/HttpQuery.php b/inc/Config/Query/HttpQuery.php index f6d021b1..b4e77ae5 100644 --- a/inc/Config/Query/HttpQuery.php +++ b/inc/Config/Query/HttpQuery.php @@ -86,6 +86,14 @@ public function get_output_schema(): array { return $this->config['output_schema']; } + /** + * Get the pagination schema for this query. If null, pagination will be + * disabled. + */ + public function get_pagination_schema(): ?array { + return $this->config['pagination_schema']; + } + /** * Get the request body for the current query execution. Any non-null result * will be converted to JSON using `wp_json_encode`. diff --git a/inc/Config/Query/QueryInterface.php b/inc/Config/Query/QueryInterface.php index 14ea646e..f09c2032 100644 --- a/inc/Config/Query/QueryInterface.php +++ b/inc/Config/Query/QueryInterface.php @@ -16,4 +16,5 @@ public function get_data_source(): DataSourceInterface; public function get_image_url(): ?string; public function get_input_schema(): array; public function get_output_schema(): array; + public function get_pagination_schema(): ?array; } diff --git a/inc/Config/QueryRunner/QueryResponseParser.php b/inc/Config/QueryRunner/QueryResponseParser.php index e79795d0..622bdfe4 100644 --- a/inc/Config/QueryRunner/QueryResponseParser.php +++ b/inc/Config/QueryRunner/QueryResponseParser.php @@ -83,6 +83,11 @@ private function parse_response_objects( mixed $objects, array $type ): array { // Loop over the defined fields in the schema type and extract the values from the object. foreach ( $type as $field_name => $mapping ) { + // Skip null values. + if ( null === $mapping ) { + continue; + } + // A generate function accepts the current object and returns the field value. if ( isset( $mapping['generate'] ) && is_callable( $mapping['generate'] ) ) { $field_value = call_user_func( $mapping['generate'], json_decode( $json_obj->getJson(), true ) ); diff --git a/inc/Config/QueryRunner/QueryRunner.php b/inc/Config/QueryRunner/QueryRunner.php index 8df508d4..436ef480 100644 --- a/inc/Config/QueryRunner/QueryRunner.php +++ b/inc/Config/QueryRunner/QueryRunner.php @@ -226,9 +226,25 @@ public function execute( HttpQueryInterface $query, array $input_variables ): ar $results = $is_collection ? $results : [ $results ]; $metadata = $this->get_response_metadata( $query, $raw_response_data['metadata'], $results ); + // Pagination schema defines how to extract pagination data from the response. + $pagination = null; + $pagination_schema = $query->get_pagination_schema(); + + if ( is_array( $pagination_schema ) ) { + $pagination_data = $parser->parse( $response_data, [ 'type' => $pagination_schema ] )['result'] ?? null; + + if ( is_array( $pagination_data ) ) { + $pagination = []; + foreach ( $pagination_data as $key => $value ) { + $pagination[ $key ] = $value['value']; + } + } + } + return [ 'is_collection' => $is_collection, 'metadata' => $metadata, + 'pagination' => $pagination, 'results' => $results, ]; } diff --git a/inc/Editor/BlockManagement/ConfigRegistry.php b/inc/Editor/BlockManagement/ConfigRegistry.php index a0cea711..288329cf 100644 --- a/inc/Editor/BlockManagement/ConfigRegistry.php +++ b/inc/Editor/BlockManagement/ConfigRegistry.php @@ -98,8 +98,14 @@ public static function register_block( array $user_config = [] ): bool|WP_Error } } - if ( self::SEARCH_QUERY_KEY === $from_query_type && ! isset( $from_input_schema['search_terms'] ) ) { - return self::create_error( $block_title, 'A search query must have a "search_terms" input variable' ); + if ( self::SEARCH_QUERY_KEY === $from_query_type ) { + $search_input_count = count( array_filter( $from_input_schema, function ( array $input_var ): bool { + return 'ui:search_input' === $input_var['type']; + } ) ); + + if ( 1 !== $search_input_count ) { + return self::create_error( $block_title, 'A search query must have one input variable with type "ui:search_input"' ); + } } // Add the selector to the configuration. @@ -107,7 +113,14 @@ public static function register_block( array $user_config = [] ): bool|WP_Error $config['selectors'], [ 'image_url' => $from_query->get_image_url(), - 'inputs' => [], + 'inputs' => array_map( function ( $slug, $input_var ) { + return [ + 'name' => $input_var['name'] ?? $slug, + 'required' => $input_var['required'] ?? false, + 'slug' => $slug, + 'type' => $input_var['type'] ?? 'string', + ]; + }, array_keys( $from_input_schema ), array_values( $from_input_schema ) ), 'name' => $selection_query['display_name'] ?? ucfirst( $from_query_type ), 'query_key' => $from_query::class, 'type' => $from_query_type, diff --git a/inc/Integrations/SalesforceB2C/SalesforceB2CIntegration.php b/inc/Integrations/SalesforceB2C/SalesforceB2CIntegration.php index c386fe02..dd4eafba 100644 --- a/inc/Integrations/SalesforceB2C/SalesforceB2CIntegration.php +++ b/inc/Integrations/SalesforceB2C/SalesforceB2CIntegration.php @@ -108,12 +108,12 @@ private static function get_queries( SalesforceB2CDataSource $data_source ): arr '%s/search/shopper-search/v1/organizations/%s/product-search?siteId=RefArchGlobal&q=%s', $base_endpoint, $service_config['organization_id'], - urlencode( $input_variables['search_terms'] ) + urlencode( $input_variables['search'] ) ); }, 'input_schema' => [ - 'search_terms' => [ - 'type' => 'string', + 'search' => [ + 'type' => 'ui:search_input', ], ], 'output_schema' => [ diff --git a/inc/Integrations/Shopify/ShopifyIntegration.php b/inc/Integrations/Shopify/ShopifyIntegration.php index dbb17735..75f63edf 100644 --- a/inc/Integrations/Shopify/ShopifyIntegration.php +++ b/inc/Integrations/Shopify/ShopifyIntegration.php @@ -84,8 +84,8 @@ public static function get_queries( ShopifyDataSource $data_source ): array { 'shopify_search_products' => GraphqlQuery::from_array( [ 'data_source' => $data_source, 'input_schema' => [ - 'search_terms' => [ - 'type' => 'string', + 'search' => [ + 'type' => 'ui:search_input', ], ], 'output_schema' => [ diff --git a/inc/Validation/ConfigSchemas.php b/inc/Validation/ConfigSchemas.php index f92f0b59..ff3f543f 100644 --- a/inc/Validation/ConfigSchemas.php +++ b/inc/Validation/ConfigSchemas.php @@ -169,7 +169,54 @@ private static function generate_http_query_config_schema(): array { // NOTE: These values are string references to the "core primitive // types" from our formal schema. Referencing these types allows us // to use the same validation and sanitization logic. - 'type' => Types::enum( 'boolean', 'id', 'integer', 'null', 'number', 'string' ), + // + // There are also special types that are not core primitives, with + // accompanying notes. + 'type' => Types::enum( + 'boolean', + 'id', + 'integer', + 'null', + 'number', + 'string', + // Special non-primitive types + // + // A string that represents search query input. An input variable + // with this type must be present for the query to be considered a + // search query. + 'ui:search_input', + // + // An integer that represents the requested offset for paginated + // results. Providing this input variable enables offset-based + // pagination. + // + // Note that a `total_items` pagination variable is also required + // for pagination to be enabled. + 'ui:pagination_offset', + // + // An integer that represents the requested page of paginated + // results. Providing this input variable enables page-based + // pagination. + // + // Note that a `total_items` pagination variable is also required + // for pagination to be enabled. + 'ui:pagination_page', + // + // An integer that represents the number of items to request in + // paginated results. This variable can be used in any pagination + // scheme. Often, this variable is named `limit` or `count`. + 'ui:pagination_per_page', + // + // A string that represents the pagination cursor used to request + // the next or previous page. Both must be specified to opt-in to + // cursor-based pagination, with corresponding fields defined in + // the `pagination_schema`. + // + // If specified, these variables take precedence over page-based + // and offset-based pagination variables. + 'ui:pagination_cursor_next', + 'ui:pagination_cursor_previous', + ), ] ), ) ), @@ -223,6 +270,43 @@ private static function generate_http_query_config_schema(): array { ), ] ), ), + // NOTE: The "pagination schema" for a query is not a formal schema like + // the ones generated by this class. It is a simple object structure that + // defines how the query response can inform subsequent requests for + // paginated data. + 'pagination_schema' => Types::nullable( + Types::object( [ + // This field provides an integer representing the total number of + // items available in paginated results. This field must be defined + // in order present to enable pagination support of any type, + // including cursor-based pagination. + 'total_items' => Types::object( [ + 'name' => Types::nullable( Types::string() ), + 'path' => Types::json_path(), + 'type' => Types::enum( 'integer' ), + ] ), + // This field provides a pagination cursor for the next page of + // paginated results, or a null value if there is no next page. This + // field must be defined in order to enable cursor-based pagination. + 'cursor_next' => Types::nullable( + Types::object( [ + 'name' => Types::nullable( Types::string() ), + 'path' => Types::json_path(), + 'type' => Types::enum( 'string' ), + ] ), + ), + // This field provides a pagination cursor for the previous page of + // paginated results, or a null value if there is no previous page. This + // field must be defined in order to enable cursor-based pagination. + 'cursor_previous' => Types::nullable( + Types::object( [ + 'name' => Types::nullable( Types::string() ), + 'path' => Types::json_path(), + 'type' => Types::enum( 'string' ), + ] ), + ), + ] ) + ), 'preprocess_response' => Types::nullable( Types::callable() ), 'query_runner' => Types::nullable( Types::instance_of( QueryRunnerInterface::class ) ), 'request_body' => Types::nullable( diff --git a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectNew.tsx b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectNew.tsx index bcd72592..4a6d68dc 100644 --- a/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectNew.tsx +++ b/src/blocks/remote-data-container/components/field-shortcode/FieldShortcodeSelectNew.tsx @@ -41,19 +41,33 @@ export function FieldShortcodeSelectNew( props: FieldShortcodeSelectNewProps ) { { () => Object.entries( blocksByType ).map( ( [ dataSourceType, configs ] ) => ( - { configs.map( blockConfig => ( - ( - - { blockConfig.settings?.title ?? blockConfig.name } - - ) } - /> - ) ) } + { configs.map( blockConfig => { + // For now, we will use the first compatible selector, but this + // should be improved. + const compatibleSelector = blockConfig.selectors.find( selector => + [ 'list', 'search' ].includes( selector.type ) + ); + + if ( ! compatibleSelector ) { + return null; + } + + return ( + ( + + { blockConfig.settings?.title ?? blockConfig.name } + + ) } + /> + ); + } ) } ) ) } diff --git a/src/blocks/remote-data-container/components/item-list/ItemList.tsx b/src/blocks/remote-data-container/components/item-list/ItemList.tsx index 53912e00..6ba90c70 100644 --- a/src/blocks/remote-data-container/components/item-list/ItemList.tsx +++ b/src/blocks/remote-data-container/components/item-list/ItemList.tsx @@ -1,10 +1,28 @@ -import { Button } from '@wordpress/components'; import { useInstanceId } from '@wordpress/compose'; -import { DataViews, filterSortAndPaginate, View } from '@wordpress/dataviews/wp'; -import { useEffect, useMemo, useState } from '@wordpress/element'; +import { Action, DataViews, View } from '@wordpress/dataviews/wp'; +import { useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; +import { ItemListField } from '@/blocks/remote-data-container/components/item-list/ItemListField'; import { usePatterns } from '@/blocks/remote-data-container/hooks/usePatterns'; +import { removeNullValuesFromObject } from '@/utils/type-narrowing'; + +function getResultsWithId( results: RemoteDataResult[], instanceId: string ): RemoteDataResult[] { + return ( results ?? [] ).map( ( result: RemoteDataResult ) => { + const parsedItem = removeNullValuesFromObject( result ); + + if ( parsedItem.id ) { + return parsedItem; + } + + // ensure each result has an 'id' key + const idKey = Object.keys( parsedItem ).find( key => /(^|_)(id)$/i.test( key ) ); + return { + ...parsedItem, + id: idKey ? parsedItem[ idKey ] : instanceId, + }; + } ); +} interface ItemListProps { availableBindings: Record< string, RemoteDataBinding >; @@ -12,36 +30,17 @@ interface ItemListProps { loading: boolean; onSelect: ( data: RemoteDataQueryInput ) => void; onSelectField?: ( data: FieldSelection, fieldValue: string ) => void; + page: number; + perPage?: number; remoteData?: RemoteData; - searchTerms: string; - setSearchTerms: ( newValue: string ) => void; + searchInput: string; + setPage: ( newPage: number ) => void; + setSearchInput: ( newValue: string ) => void; + supportsSearch: boolean; + totalItems?: number; + totalPages?: number; } -const createFieldSelection = ( - field: string, - item: RemoteDataResult, - blockName: string, - remoteData: RemoteData -): FieldSelection => ( { - action: 'add_field_shortcode', - remoteData: { - ...remoteData, - blockName, - queryInput: { - ...item, - field: { - field, - value: item[ field ] as string, - }, - }, - resultId: item.id?.toString() ?? '', - results: [ item ], - }, - selectedField: field, - selectionPath: 'select_new_tab', - type: 'field', -} ); - export function ItemList( props: ItemListProps ) { const { availableBindings, @@ -49,118 +48,83 @@ export function ItemList( props: ItemListProps ) { loading, onSelect, onSelectField, + page, + perPage, remoteData, - searchTerms, - setSearchTerms, + searchInput, + setPage, + setSearchInput, + supportsSearch, + totalItems, + totalPages, } = props; - const results = remoteData?.results ?? []; const { defaultPattern: pattern } = usePatterns( blockName ); - const instanceId = useInstanceId( ItemList, blockName ); - const data = useMemo( () => { - // remove null values from the data to prevent errors in filterSortAndPaginate - const removeNullValues = ( obj: Record< string, unknown > ): Record< string, unknown > => { - return Object.fromEntries( - Object.entries( obj ).filter( ( [ _, value ] ) => value !== null ) - ); - }; - - return ( results ?? [] ).map( ( item: Record< string, unknown > ) => { - const parsedItem = removeNullValues( item ); - - if ( parsedItem.id ) { - return parsedItem; - } - - // ensure each result has an 'id' key - const idKey = Object.keys( parsedItem ).find( key => /(^|_)(id)$/i.test( key ) ); - return { - ...parsedItem, - id: idKey ? parsedItem[ idKey ] : instanceId, - }; - } ) as RemoteDataResult[]; - }, [ results ] ); + const results = remoteData?.results ?? []; + const data = loading ? [] : getResultsWithId( results ?? [], instanceId ); // get fields from results data to use as columns - const { fields, mediaField, tableFields, titleField } = useMemo( () => { - const getFields: string[] = Array.from( - new Set( - data - ?.flatMap( item => Object.keys( item ) ) - .filter( - key => key in availableBindings && availableBindings[ key ]?.type !== 'id' // filter out ID fields to hide from table - ) - ) - ); - - // Find title field from availableBindings by checking type - const title = Object.entries( availableBindings ).find( - ( [ _, binding ] ) => binding.type === 'string' && binding.name.toLowerCase() === 'title' - )?.[ 0 ]; - - // Find media field from availableBindings by checking type - const media = Object.entries( availableBindings ).find( - ( [ _, binding ] ) => binding.type === 'image_url' - )?.[ 0 ]; - - const renderField = ( field: string, item: RemoteDataResult ) => { - if ( field === media ) { - return {; - } - - if ( onSelectField && remoteData ) { - const queryInput: RemoteDataQueryInput = { - ...item, - field: { - field, - value: item[ field ] as string, - }, - }; - - return ( - - ); - } - - return item[ field ] as string; - }; - - const fieldObject = getFields.map( field => ( { - id: field, - label: availableBindings[ field ]?.name ?? field, - enableGlobalSearch: true, - getValue: ( { item }: { item: RemoteDataResult } ) => item[ field ] as string, - render: ( { item }: { item: RemoteDataResult } ) => renderField( field, item ), - enableSorting: field !== media, - } ) ); + const fieldNames: string[] = Array.from( + new Set( + data + ?.flatMap( item => Object.keys( item ) ) + .filter( + key => key in availableBindings && availableBindings[ key ]?.type !== 'id' // filter out ID fields to hide from table + ) + ) + ); - return { fields: fieldObject, tableFields: getFields, titleField: title, mediaField: media }; - }, [ availableBindings, data, onSelectField, remoteData ] ); + // Find title field from availableBindings by checking type + const titleField = Object.entries( availableBindings ).find( + ( [ _, binding ] ) => binding.type === 'string' && binding.name.toLowerCase() === 'title' + )?.[ 0 ]; + + // Find media field from availableBindings by checking type + const mediaField = Object.entries( availableBindings ).find( + ( [ _, binding ] ) => binding.type === 'image_url' + )?.[ 0 ]; + + const fields = fieldNames.map( field => ( { + id: field, + label: availableBindings[ field ]?.name ?? field, + enableGlobalSearch: true, + getValue: ( { item }: { item: RemoteDataResult } ) => item[ field ]?.toString() ?? '', + render: ( { item }: { item: RemoteDataResult } ) => ( + + ), + enableSorting: field !== mediaField, + } ) ); + + // hide media and title fields from table view if defined to avoid duplication + const tableFields = fieldNames.filter( field => field !== mediaField && field !== titleField ); const [ view, setView ] = useState< View >( { type: 'table' as const, - perPage: 8, - page: 1, - search: '', - fields: [], + perPage: perPage ?? data.length, + page, + search: searchInput, + fields: tableFields, filters: [], layout: {}, titleField, mediaField, } ); + function onChangeView( newView: View ) { + setPage( newView.page ?? 1 ); + setSearchInput( newView.search ?? '' ); + setView( newView ); + } + const defaultLayouts = mediaField ? { table: {}, @@ -168,55 +132,34 @@ export function ItemList( props: ItemListProps ) { } : { table: {} }; - // this prevents just an empty table rendering - useEffect( () => { - if ( tableFields.length > 0 ) { - setView( prevView => ( { - ...prevView, - // hide media and title fields from table view if defined to avoid duplication - fields: tableFields.filter( field => field !== mediaField && field !== titleField ), - } ) ); - } - }, [ mediaField, tableFields, titleField ] ); - - useEffect( () => { - if ( view.search !== searchTerms ) { - setSearchTerms( view.search ?? '' ); - } - }, [ view, searchTerms ] ); - - // filter, sort and paginate data - const { data: filteredData, paginationInfo } = useMemo( () => { - return filterSortAndPaginate( data ?? [], view, fields ); - }, [ data, view ] ); - // Hide actions for field shortcode selection - const actions = ! onSelectField - ? [ - { - id: 'choose', - icon: <>{ __( 'Choose' ) }, - isPrimary: true, - label: '', - callback: ( items: RemoteDataResult[] ) => { - items.map( item => onSelect( item ) ); - }, - }, - ] - : []; + const chooseItemAction = { + id: 'choose', + icon: <>{ __( 'Choose' ) }, + isPrimary: true, + label: '', + callback: ( items: RemoteDataResult[] ) => { + items.map( item => onSelect( item ) ); + }, + }; + const actions: Action< RemoteDataResult >[] = onSelectField ? [] : [ chooseItemAction ]; return ( - actions={ actions } - data={ filteredData } + data={ data } defaultLayouts={ defaultLayouts } fields={ fields } getItemId={ ( item: { id?: string } ) => item.id || '' } isLoading={ loading || ! pattern || ! results } isItemClickable={ () => true } onClickItem={ item => onSelect( item ) } - onChangeView={ setView } - paginationInfo={ paginationInfo } + onChangeView={ onChangeView } + paginationInfo={ { + totalItems: totalItems ?? data.length, + totalPages: totalPages ?? 1, + } } + search={ supportsSearch } view={ view } /> ); diff --git a/src/blocks/remote-data-container/components/item-list/ItemListField.tsx b/src/blocks/remote-data-container/components/item-list/ItemListField.tsx new file mode 100644 index 00000000..f63b8642 --- /dev/null +++ b/src/blocks/remote-data-container/components/item-list/ItemListField.tsx @@ -0,0 +1,71 @@ +import { Button } from '@wordpress/components'; + +function createFieldSelection( + field: string, + item: RemoteDataResult, + blockName: string, + remoteData: RemoteData +): FieldSelection { + return { + action: 'add_field_shortcode', + remoteData: { + ...remoteData, + blockName, + queryInput: { + ...item, + field: { + field, + value: item[ field ], + }, + }, + resultId: item.id?.toString() ?? '', + results: [ item ], + }, + selectedField: field, + selectionPath: 'select_new_tab', + type: 'field', + }; +} + +interface ItemListFieldProps { + blockName: string; + field: string; + item: RemoteDataResult; + mediaField?: string; + onSelect: ( data: RemoteDataQueryInput ) => void; + onSelectField?: ( data: FieldSelection, fieldValue: string ) => void; + remoteData?: RemoteData; +} + +export function ItemListField( props: ItemListFieldProps ) { + const { blockName, field, item, mediaField, onSelect, onSelectField, remoteData } = props; + const value = item[ field ]?.toString() ?? ''; + + if ( field === mediaField ) { + return {; + } + + if ( onSelectField && remoteData ) { + const queryInput: RemoteDataQueryInput = { + ...item, + field: { + field, + value: item[ field ] as string, + }, + }; + + return ( + + ); + } + + return value; +} diff --git a/src/blocks/remote-data-container/components/modals/DataViewsModal.tsx b/src/blocks/remote-data-container/components/modals/DataViewsModal.tsx index 0696acc7..0e4b1cea 100644 --- a/src/blocks/remote-data-container/components/modals/DataViewsModal.tsx +++ b/src/blocks/remote-data-container/components/modals/DataViewsModal.tsx @@ -1,15 +1,22 @@ import { Button, Modal } from '@wordpress/components'; +import { useEffect } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; -import { useModalState } from '../../hooks/useModalState'; -import { ItemList } from '../item-list/ItemList'; -import { useSearchResults } from '@/blocks/remote-data-container/hooks/useSearchResults'; -import { getBlockAvailableBindings, getBlockConfig } from '@/utils/localized-block-data'; +import { ItemList } from '@/blocks/remote-data-container/components/item-list/ItemList'; +import { useModalState } from '@/blocks/remote-data-container/hooks/useModalState'; +import { useRemoteData } from '@/blocks/remote-data-container/hooks/useRemoteData'; +import { sendTracksEvent } from '@/blocks/remote-data-container/utils/tracks'; +import { + getBlockAvailableBindings, + getBlockConfig, + getBlockDataSourceType, +} from '@/utils/localized-block-data'; interface DataViewsModalProps { className?: string; blockName: string; headerImage?: string; + inputVariables: InputVariable[]; onSelect?: ( data: RemoteDataQueryInput ) => void; onSelectField?: ( data: FieldSelection, fieldValue: string ) => void; queryKey: string; @@ -18,27 +25,51 @@ interface DataViewsModalProps { } export const DataViewsModal: React.FC< DataViewsModalProps > = props => { - const { className, blockName, onSelect, onSelectField, queryKey, renderTrigger, title } = props; + const { + className, + blockName, + inputVariables, + onSelect, + onSelectField, + queryKey, + renderTrigger, + title, + } = props; const blockConfig = getBlockConfig( blockName ); - const availableBindings = getBlockAvailableBindings( blockName ); + const { close, isOpen, open } = useModalState(); const { + data, + fetch, loading, - data: remoteData, - searchTerms, - setSearchTerms, - } = useSearchResults( { + page, + searchInput, + setPage, + setSearchInput, + supportsSearch, + totalItems, + totalPages, + } = useRemoteData( { blockName, + inputVariables, queryKey, } ); - const { close, isOpen, open } = useModalState(); + useEffect( () => { + void fetch( {} ); + }, [] ); - const handleSelect = ( data: RemoteDataQueryInput ): void => { - onSelect?.( data ); - }; + function onSelectItem( input: RemoteDataQueryInput ): void { + onSelect?.( input ); + sendTracksEvent( 'remotedatablocks_add_block', { + action: 'select_item', + selected_option: 'search_from_list', + data_source_type: getBlockDataSourceType( blockName ), + } ); + close(); + } const triggerElement = renderTrigger ? ( renderTrigger( { onClick: open } ) @@ -47,6 +78,7 @@ export const DataViewsModal: React.FC< DataViewsModalProps > = props => { { __( 'Choose' ) } ); + return ( <> { triggerElement } @@ -61,11 +93,16 @@ export const DataViewsModal: React.FC< DataViewsModalProps > = props => { availableBindings={ availableBindings } blockName={ blockName } loading={ loading } - onSelect={ handleSelect } + onSelect={ onSelect ? onSelectItem : close } onSelectField={ onSelectField } - remoteData={ remoteData ?? undefined } - searchTerms={ searchTerms } - setSearchTerms={ setSearchTerms } + page={ page } + remoteData={ data } + searchInput={ searchInput } + setPage={ setPage } + setSearchInput={ setSearchInput } + supportsSearch={ supportsSearch } + totalItems={ totalItems } + totalPages={ totalPages } /> ) } diff --git a/src/blocks/remote-data-container/components/placeholders/ItemSelectQueryType.tsx b/src/blocks/remote-data-container/components/placeholders/ItemSelectQueryType.tsx index 04abcdfa..99c3c259 100644 --- a/src/blocks/remote-data-container/components/placeholders/ItemSelectQueryType.tsx +++ b/src/blocks/remote-data-container/components/placeholders/ItemSelectQueryType.tsx @@ -21,6 +21,7 @@ export function ItemSelectQueryType( props: ItemSelectQueryTypeProps ) { const selectorProps = { blockName, headerImage: selector.image_url, + inputVariables: selector.inputs, onSelect, queryKey: selector.query_key, title, diff --git a/src/blocks/remote-data-container/config/constants.ts b/src/blocks/remote-data-container/config/constants.ts index 315735c0..4b77256e 100644 --- a/src/blocks/remote-data-container/config/constants.ts +++ b/src/blocks/remote-data-container/config/constants.ts @@ -14,6 +14,13 @@ export const REMOTE_DATA_REST_API_URL = getRestUrl(); export const CONTAINER_CLASS_NAME = getClassName( 'container' ); +export const PAGINATION_CURSOR_NEXT_VARIABLE_TYPE = 'ui:pagination_cursor_next'; +export const PAGINATION_CURSOR_PREVIOUS_VARIABLE_TYPE = 'ui:pagination_cursor_previous'; +export const PAGINATION_OFFSET_VARIABLE_TYPE = 'ui:pagination_offset'; +export const PAGINATION_PAGE_VARIABLE_TYPE = 'ui:pagination_page'; +export const PAGINATION_PER_PAGE_VARIABLE_TYPE = 'ui:pagination_per_page'; +export const SEARCH_INPUT_VARIABLE_TYPE = 'ui:search_input'; + export const BUTTON_TEXT_FIELD_TYPES = [ 'button_text' ]; export const BUTTON_URL_FIELD_TYPES = [ 'button_url' ]; export const HTML_FIELD_TYPES = [ 'html' ]; diff --git a/src/blocks/remote-data-container/hooks/usePaginationVariables.ts b/src/blocks/remote-data-container/hooks/usePaginationVariables.ts new file mode 100644 index 00000000..d4cdf536 --- /dev/null +++ b/src/blocks/remote-data-container/hooks/usePaginationVariables.ts @@ -0,0 +1,137 @@ +import { useState } from '@wordpress/element'; + +import { + PAGINATION_CURSOR_NEXT_VARIABLE_TYPE, + PAGINATION_CURSOR_PREVIOUS_VARIABLE_TYPE, + PAGINATION_OFFSET_VARIABLE_TYPE, + PAGINATION_PAGE_VARIABLE_TYPE, + PAGINATION_PER_PAGE_VARIABLE_TYPE, +} from '@/blocks/remote-data-container/config/constants'; + +interface UsePaginationVariables { + onFetch: ( remoteData: RemoteData ) => void; + page: number; + paginationQueryInput: RemoteDataQueryInput; + perPage?: number; + setPage: ( page: number ) => void; + setPerPage: ( perPage: number ) => void; + supportsCursorPagination: boolean; + supportsOffsetPagination: boolean; + supportsPagePagination: boolean; + supportsPagination: boolean; + supportsPerPage: boolean; + totalItems?: number; + totalPages?: number; +} + +interface UsePaginationVariablesInput { + initialPage?: number; + initialPerPage?: number; + inputVariables: InputVariable[]; +} + +export function usePaginationVariables( { + initialPage = 1, + initialPerPage, + inputVariables, +}: UsePaginationVariablesInput ): UsePaginationVariables { + const [ paginationData, setPaginationData ] = useState< RemoteDataPagination >(); + const [ page, setPage ] = useState< number >( initialPage ); + const [ perPage, setPerPage ] = useState< number | null >( initialPerPage ?? null ); + + const cursorNextVariable = inputVariables?.find( + input => input.type === PAGINATION_CURSOR_NEXT_VARIABLE_TYPE + ); + const cursorPreviousVariable = inputVariables?.find( + input => input.type === PAGINATION_CURSOR_PREVIOUS_VARIABLE_TYPE + ); + const offsetVariable = inputVariables?.find( + input => input.type === PAGINATION_OFFSET_VARIABLE_TYPE + ); + const pageVariable = inputVariables?.find( + input => input.type === PAGINATION_PAGE_VARIABLE_TYPE + ); + const perPageVariable = inputVariables?.find( + input => input.type === PAGINATION_PER_PAGE_VARIABLE_TYPE + ); + + const paginationQueryInput: RemoteDataQueryInput = {}; + + // These will be amended below. + let supportsCursorPagination = false; + let supportsOffsetPagination = false; + let supportsPagePagination = false; + let setPageFn: ( page: number ) => void = () => {}; + + if ( cursorNextVariable && cursorPreviousVariable ) { + setPageFn = setPageForCursorPagination; + supportsCursorPagination = true; + Object.assign( paginationQueryInput, { + [ cursorNextVariable.slug ]: paginationData?.cursorNext, + [ cursorPreviousVariable.slug ]: paginationData?.cursorPrevious, + } ); + } else if ( offsetVariable && perPage ) { + setPageFn = setPage; + supportsOffsetPagination = true; + Object.assign( paginationQueryInput, { [ offsetVariable.slug ]: page * perPage } ); + } else if ( pageVariable ) { + setPageFn = setPage; + supportsPagePagination = true; + Object.assign( paginationQueryInput, { [ pageVariable.slug ]: page } ); + } + + if ( perPageVariable && perPage ) { + Object.assign( paginationQueryInput, { [ perPageVariable.slug ]: perPage } ); + } + + const supportsPagination = + supportsCursorPagination || supportsPagePagination || supportsOffsetPagination; + const totalItems = paginationData?.totalItems; + const totalPages = totalItems && perPage ? Math.ceil( totalItems / perPage ) : undefined; + + function onFetch( remoteData: RemoteData ): void { + if ( ! supportsPagination ) { + return; + } + + setPaginationData( remoteData.pagination ); + + // We need a perPage value to calculate the total pages, so inpsect the results. + if ( ! perPage && remoteData.results.length ) { + setPerPage( remoteData.results.length ); + } + } + + // With cursor pagination, we can only go one page at a time. + function setPageForCursorPagination( newPage: number ): void { + if ( newPage > page ) { + if ( totalPages ) { + setPage( Math.min( totalPages, page + 1 ) ); + return; + } + + setPage( page + 1 ); + return; + } + + if ( newPage < page ) { + setPage( Math.max( 1, page - 1 ) ); + } + } + + return { + onFetch, + page, + paginationQueryInput, + perPage: perPage ?? undefined, + setPage: setPageFn, + setPerPage: supportsPagination ? setPerPage : () => {}, + supportsCursorPagination, + supportsOffsetPagination, + supportsPagePagination, + supportsPagination, + supportsPerPage: Boolean( perPageVariable ), + totalItems, + totalPages, + }; +} diff --git a/src/blocks/remote-data-container/hooks/useRemoteData.ts b/src/blocks/remote-data-container/hooks/useRemoteData.ts index 816a897a..1b88da27 100644 --- a/src/blocks/remote-data-container/hooks/useRemoteData.ts +++ b/src/blocks/remote-data-container/hooks/useRemoteData.ts @@ -1,7 +1,9 @@ import apiFetch from '@wordpress/api-fetch'; -import { useState } from '@wordpress/element'; +import { useEffect, useState } from '@wordpress/element'; import { REMOTE_DATA_REST_API_URL } from '@/blocks/remote-data-container/config/constants'; +import { usePaginationVariables } from '@/blocks/remote-data-container/hooks/usePaginationVariables'; +import { useSearchVariables } from '@/blocks/remote-data-container/hooks/useSearchVariables'; async function fetchRemoteData( requestData: RemoteDataApiRequest ): Promise< RemoteData | null > { const { body } = await apiFetch< RemoteDataApiResponse >( { @@ -18,6 +20,11 @@ async function fetchRemoteData( requestData: RemoteDataApiRequest ): Promise< Re blockName: body.block_name, isCollection: body.is_collection, metadata: body.metadata, + pagination: body.pagination && { + cursorNext: body.pagination.cursor_next, + cursorPrevious: body.pagination.cursor_previous, + totalItems: body.pagination.total_items, + }, queryInput: body.query_input, resultId: body.result_id, results: body.results.map( result => @@ -35,8 +42,25 @@ async function fetchRemoteData( requestData: RemoteDataApiRequest ): Promise< Re interface UseRemoteData { data?: RemoteData; fetch: ( queryInput: RemoteDataQueryInput ) => Promise< void >; + hasNextPage: boolean; + hasPreviousPage: boolean; loading: boolean; + page: number; + perPage?: number; reset: () => void; + searchAllowsEmptyInput: boolean; + searchInput: string; + setPage: ( page: number ) => void; + setPerPage: ( perPage: number ) => void; + setSearchInput: ( searchInput: string ) => void; + supportsCursorPagination: boolean; + supportsOffsetPagination: boolean; + supportsPagePagination: boolean; + supportsPagination: boolean; + supportsPerPage: boolean; + supportsSearch: boolean; + totalItems?: number; + totalPages?: number; } interface UseRemoteDataInput { @@ -44,6 +68,10 @@ interface UseRemoteDataInput { enabledOverrides?: string[]; externallyManagedRemoteData?: RemoteData; externallyManagedUpdateRemoteData?: ( remoteData?: RemoteData ) => void; + initialPage?: number; + initialPerPage?: number; + initialSearchInput?: string; + inputVariables?: InputVariable[]; onSuccess?: () => void; queryKey: string; } @@ -61,6 +89,10 @@ export function useRemoteData( { enabledOverrides = [], externallyManagedRemoteData, externallyManagedUpdateRemoteData, + initialPage, + initialPerPage, + initialSearchInput, + inputVariables = [], onSuccess, queryKey, }: UseRemoteDataInput ): UseRemoteData { @@ -69,6 +101,35 @@ export function useRemoteData( { const resolvedData = externallyManagedRemoteData ?? data; const resolvedUpdater = externallyManagedUpdateRemoteData ?? setData; + const hasResolvedData = Boolean( resolvedData ); + + const { + onFetch: onFetchForPagination, + page, + perPage, + paginationQueryInput, + supportsPagination, + totalItems, + totalPages, + ...paginationVariables + } = usePaginationVariables( { + initialPage, + initialPerPage, + inputVariables, + } ); + const { searchQueryInput, searchAllowsEmptyInput, searchInput, setSearchInput, supportsSearch } = + useSearchVariables( { + initialSearchInput, + inputVariables, + } ); + + useEffect( () => { + if ( ! hasResolvedData ) { + return; + } + + void fetch( resolvedData?.queryInput ?? {} ); + }, [ hasResolvedData, page, perPage, searchInput ] ); async function fetch( queryInput: RemoteDataQueryInput ): Promise< void > { setLoading( true ); @@ -76,7 +137,11 @@ export function useRemoteData( { const requestData: RemoteDataApiRequest = { block_name: blockName, query_key: queryKey, - query_input: queryInput, + query_input: { + ...queryInput, + ...paginationQueryInput, + ...searchQueryInput, + }, }; const remoteData = await fetchRemoteData( requestData ).catch( () => null ); @@ -87,6 +152,7 @@ export function useRemoteData( { return; } + onFetchForPagination( remoteData ); resolvedUpdater( { enabledOverrides, ...remoteData } ); setLoading( false ); onSuccess?.(); @@ -99,7 +165,19 @@ export function useRemoteData( { return { data: resolvedData, fetch, + hasNextPage: totalPages ? page < totalPages : supportsPagination, + hasPreviousPage: page > 1, loading, + page, + perPage, reset, + searchAllowsEmptyInput, + searchInput, + setSearchInput, + supportsPagination, + supportsSearch, + totalItems: resolvedData?.pagination?.totalItems, + totalPages, + ...paginationVariables, }; } diff --git a/src/blocks/remote-data-container/hooks/useSearchResults.ts b/src/blocks/remote-data-container/hooks/useSearchResults.ts deleted file mode 100644 index fcf01a47..00000000 --- a/src/blocks/remote-data-container/hooks/useSearchResults.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { useEffect, useRef, useState } from '@wordpress/element'; - -import { useRemoteData } from '@/blocks/remote-data-container/hooks/useRemoteData'; - -export interface UseSearchResultsInput { - allowEmptySearchTerms?: boolean; - blockName: string; - debounceInMs?: number; - queryKey: string; -} -export function useSearchResults( { - allowEmptySearchTerms = true, - blockName, - debounceInMs = 200, - queryKey, -}: UseSearchResultsInput ) { - const [ searchTerms, setSearchTerms ] = useState< string >( '' ); - const { data, fetch, loading } = useRemoteData( { blockName, queryKey } ); - const timer = useRef< NodeJS.Timeout >(); - - function onSubmit(): void { - void fetch( { search_terms: searchTerms } ); - } - - function onKeyDown( event: React.KeyboardEvent< HTMLInputElement > ): void { - if ( event.code !== 'Enter' ) { - return; - } - - event.preventDefault(); - onSubmit(); - } - - useEffect( () => { - if ( allowEmptySearchTerms || searchTerms ) { - // Debounce the search term input. - const newTimer = setTimeout( onSubmit, debounceInMs ); - clearTimeout( timer.current ); - timer.current = newTimer; - } - - return () => clearTimeout( timer.current ); - }, [ allowEmptySearchTerms, searchTerms ] ); - - return { - loading, - onKeyDown, - data, - searchTerms, - setSearchTerms, - }; -} diff --git a/src/blocks/remote-data-container/hooks/useSearchVariables.ts b/src/blocks/remote-data-container/hooks/useSearchVariables.ts new file mode 100644 index 00000000..074b2005 --- /dev/null +++ b/src/blocks/remote-data-container/hooks/useSearchVariables.ts @@ -0,0 +1,41 @@ +import { SEARCH_INPUT_VARIABLE_TYPE } from '@/blocks/remote-data-container/config/constants'; +import { useDebouncedState } from '@/hooks/useDebouncedState'; + +interface UseSearchVariables { + searchAllowsEmptyInput: boolean; + searchInput: string; + searchQueryInput: RemoteDataQueryInput; + setSearchInput: ( searchInput: string ) => void; + supportsSearch: boolean; +} + +interface UseSearchVariablesInput { + initialSearchInput?: string; + inputVariables: InputVariable[]; + searchInputDelayInMs?: number; +} + +export function useSearchVariables( { + initialSearchInput = '', + inputVariables, + searchInputDelayInMs = 500, +}: UseSearchVariablesInput ): UseSearchVariables { + const [ searchInput, setSearchInput ] = useDebouncedState< string >( + searchInputDelayInMs, + initialSearchInput + ); + + const inputVariable = inputVariables?.find( input => input.type === SEARCH_INPUT_VARIABLE_TYPE ); + const supportsSearch = Boolean( inputVariable ); + const searchAllowsEmptyInput = supportsSearch && ! inputVariable?.required; + const hasSearchInput = supportsSearch && ( searchInput || searchAllowsEmptyInput ); + + return { + searchAllowsEmptyInput, + searchInput, + searchQueryInput: + hasSearchInput && inputVariable ? { [ inputVariable.slug ]: searchInput } : {}, + setSearchInput: supportsSearch ? setSearchInput : () => {}, + supportsSearch, + }; +} diff --git a/src/hooks/useDebouncedState.ts b/src/hooks/useDebouncedState.ts new file mode 100644 index 00000000..5a9299e4 --- /dev/null +++ b/src/hooks/useDebouncedState.ts @@ -0,0 +1,21 @@ +import { useCallback, useRef, useState } from '@wordpress/element'; + +export function useDebouncedState< T >( + delayInMs: number, + initialValue: T +): [ T, ( value: T ) => void ] { + const timer = useRef< NodeJS.Timeout | null >( null ); + const [ value, setValue ] = useState< T >( initialValue ); + + const debouncedSetValue = useCallback( ( newValue: T ) => { + if ( timer.current ) { + clearTimeout( timer.current ); + } + + timer.current = setTimeout( () => { + setValue( newValue ); + }, delayInMs ); + }, [] ); + + return [ value, debouncedSetValue ]; +} diff --git a/src/utils/type-narrowing.ts b/src/utils/type-narrowing.ts index 1874eba2..32edb84a 100644 --- a/src/utils/type-narrowing.ts +++ b/src/utils/type-narrowing.ts @@ -1,3 +1,11 @@ export function isObjectWithStringKeys( value: unknown ): value is Record< string, unknown > { return typeof value === 'object' && value !== null && ! Array.isArray( value ); } + +export function removeNullValuesFromObject< ValueType >( + obj: Record< string, ValueType | null > +): Record< string, ValueType > { + return Object.fromEntries< ValueType >( + Object.entries( obj ).filter( ( entry ): entry is [ string, ValueType ] => entry[ 1 ] !== null ) + ); +} diff --git a/tests/inc/Functions/FunctionsTest.php b/tests/inc/Functions/FunctionsTest.php index ebc75c79..3ba87bb9 100644 --- a/tests/inc/Functions/FunctionsTest.php +++ b/tests/inc/Functions/FunctionsTest.php @@ -28,7 +28,7 @@ protected function setUp(): void { ] ); $this->mock_search_query = MockQuery::from_array( [ 'input_schema' => [ - 'search_terms' => [ 'type' => 'string' ], + 'search' => [ 'type' => 'ui:search_input' ], ], ] ); @@ -165,6 +165,6 @@ public function testRegisterSearchQueryWithoutSearchTerms(): void { $this->assertTrue( $this->mock_logger->hasLoggedLevel( LogLevel::ERROR ) ); $error_logs = $this->mock_logger->getLogsByLevel( LogLevel::ERROR ); - $this->assertStringContainsString( 'search_terms', $error_logs[0]['message'] ); + $this->assertStringContainsString( 'ui:search_input', $error_logs[0]['message'] ); } } diff --git a/tests/src/utils/type-narrowing.test.ts b/tests/src/utils/type-narrowing.test.ts index 705e2d78..d6fbee40 100644 --- a/tests/src/utils/type-narrowing.test.ts +++ b/tests/src/utils/type-narrowing.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import { isObjectWithStringKeys } from '@/utils/type-narrowing'; +import { isObjectWithStringKeys, removeNullValuesFromObject } from '@/utils/type-narrowing'; describe( 'type-narrowing utils', () => { describe( 'isObjectWithStringKeys', () => { @@ -35,4 +35,17 @@ describe( 'type-narrowing utils', () => { expect( isObjectWithStringKeys( obj ) ).toBe( true ); } ); } ); + + describe( 'removeNullValuesFromObject', () => { + it( 'should remove null values from object', () => { + const obj = { + aaa: 1, + bbb: null, + ccc: 'three', + ddd: null, + }; + + expect( removeNullValuesFromObject( obj ) ).toEqual( { aaa: 1, ccc: 'three' } ); + } ); + } ); } ); diff --git a/types/remote-data.d.ts b/types/remote-data.d.ts index 4a878358..082e1f82 100644 --- a/types/remote-data.d.ts +++ b/types/remote-data.d.ts @@ -2,6 +2,12 @@ interface InnerBlockContext { index: number; } +interface RemoteDataPagination { + cursorNext?: string; + cursorPrevious?: string; + totalItems: number; +} + interface RemoteDataResultFields { name: string; type: string; @@ -16,6 +22,7 @@ interface RemoteData { enabledOverrides?: string[]; isCollection: boolean; metadata: Record< string, RemoteDataResultFields >; + pagination?: RemoteDataPagination; queryInput: RemoteDataQueryInput; resultId: string; results: RemoteDataResult[]; @@ -77,6 +84,11 @@ interface RemoteDataApiResponseBody { block_name: string; is_collection: boolean; metadata: Record< string, RemoteDataResultFields >; + pagination?: { + cursor_next?: string; + cursor_previous?: string; + total_items: number; + }; query_input: RemoteDataQueryInput; result_id: string; results: RemoteDataApiResult[]; From b4732efc81480fece068b09a0856339d7dbbbe8e Mon Sep 17 00:00:00 2001 From: Chris Zarate Date: Wed, 12 Feb 2025 13:47:49 -0500 Subject: [PATCH 09/16] Schema bugfixes (#356) * Bugfix: Markdown type uses json_path type * Improvement: Allow numeric values to be stringified in validation errors * Bugfix: Require button_text and id to be non-empty * Improve tests --- inc/Validation/Types.php | 2 +- inc/Validation/Validator.php | 8 +- tests/inc/Validation/ValidatorTest.php | 372 ++++++++++++++++++------- 3 files changed, 279 insertions(+), 103 deletions(-) diff --git a/inc/Validation/Types.php b/inc/Validation/Types.php index aa848368..e3635edd 100644 --- a/inc/Validation/Types.php +++ b/inc/Validation/Types.php @@ -97,7 +97,7 @@ public static function json_path(): array { } public static function markdown(): array { - return self::generate_primitive_type( 'json_path' ); + return self::generate_primitive_type( 'markdown' ); } public static function url(): array { diff --git a/inc/Validation/Validator.php b/inc/Validation/Validator.php index cc5fbce0..8b585906 100644 --- a/inc/Validation/Validator.php +++ b/inc/Validation/Validator.php @@ -196,13 +196,15 @@ private function check_primitive_type( string $type_name, mixed $value ): bool { case 'email_address': return false !== is_email( $value ); - case 'button_text': case 'html': - case 'id': case 'image_alt': case 'markdown': return is_string( $value ); + case 'button_text': + case 'id': + return is_string( $value ) && ! empty( $value ); + case 'json_path': return is_string( $value ) && str_starts_with( $value, '$' ); @@ -229,7 +231,7 @@ public static function check_iterable_object( mixed $value ): bool { } private function create_error( string $message, mixed $value, ?WP_Error $child_error = null ): WP_Error { - $serialized_value = is_string( $value ) ? $value : wp_json_encode( $value ); + $serialized_value = is_string( $value ) || is_numeric( $value ) ? strval( $value ) : wp_json_encode( $value ); $message = sprintf( '%s: %s', esc_html( $message ), $serialized_value ); return new WP_Error( 'invalid_type', $message, [ 'child' => $child_error ] ); } diff --git a/tests/inc/Validation/ValidatorTest.php b/tests/inc/Validation/ValidatorTest.php index 59a0b03e..c8afccb6 100644 --- a/tests/inc/Validation/ValidatorTest.php +++ b/tests/inc/Validation/ValidatorTest.php @@ -17,13 +17,16 @@ public function testValidPrimitiveTypes(): void { 'number' => Types::number(), 'string' => Types::string(), + 'button_text' => Types::button_text(), + 'button_url' => Types::button_url(), + 'currency_in_current_locale' => Types::currency_in_current_locale(), 'email_address' => Types::email_address(), 'html' => Types::html(), 'id' => Types::id(), 'image_alt' => Types::image_alt(), 'image_url' => Types::image_url(), 'json_path' => Types::json_path(), - 'markdown' => Types::html(), + 'markdown' => Types::markdown(), 'url' => Types::url(), 'uuid' => Types::uuid(), ] ); @@ -37,6 +40,9 @@ public function testValidPrimitiveTypes(): void { 'number' => 3.14, 'string' => 'foo', + 'button_text' => 'Click me', + 'button_url' => 'https://example.com/action', + 'currency_in_current_locale' => '$42.00', 'email_address' => 'me@example.com', 'html' => '

Hello, world!

', 'id' => '123', @@ -49,133 +55,300 @@ public function testValidPrimitiveTypes(): void { ] ) ); } - public function testInvalidBooleans(): void { - $invalid_booleans = [ - null, - 42, - 3.14, - '', - 'foo', - [], - (object) [], + public static function provideBooleans(): array { + return [ + [ true ], + [ false ], ]; - - $validator = new Validator( Types::boolean() ); - - foreach ( $invalid_booleans as $invalid_boolean ) { - $result = $validator->validate( $invalid_boolean ); - $this->assertInstanceOf( WP_Error::class, $result ); - $this->assertStringStartsWith( 'Value must be a boolean:', $result->get_error_message() ); - } } - public function testInvalidIntegers(): void { - $invalid_integers = [ - null, - true, - 3.14, - '', - 'foo', - [], - (object) [], + public static function provideBooleanLikeStrings(): array { + return [ + [ 'true' ], + [ 'false' ], ]; + } - $validator = new Validator( Types::integer() ); + public static function provideEmptyStrings(): array { + return [ + [ '' ], + ]; + } - foreach ( $invalid_integers as $invalid_integer ) { - $result = $validator->validate( $invalid_integer ); - $this->assertInstanceOf( WP_Error::class, $result ); - $this->assertStringStartsWith( 'Value must be a integer:', $result->get_error_message() ); - } + public static function provideFloats(): array { + return [ + [ 3.14 ], + [ -3.14 ], + [ 0.0 ], + [ INF ], + [ -INF ], + [ NAN ], + ]; } - public function testInvalidNulls(): void { - $invalid_nulls = [ - true, - 42, - 3.14, - '', - 'foo', - [], - (object) [], + public static function provideInvalidEmailAddresses(): array { + return [ + [ 'me@example' ], + [ '@example.com' ], + [ 'me@.com' ], + [ 'me@example.' ], + [ 'me@.example.com' ], + [ 'me@ex ample.com' ], + [ 'me@ex' . str_repeat( 'a', 64 ) . '.com' ], ]; + } - $validator = new Validator( Types::null() ); + public static function provideInvalidUrls(): array { + return [ + [ 'example.com' ], + [ '127.0.0.1' ], + [ 'http:\\\\example.com' ], + [ 'http:///example.com' ], + [ 'http:://example.com' ], + [ 'tel:5551234567' ], + ]; + } - foreach ( $invalid_nulls as $invalid_null ) { - $result = $validator->validate( $invalid_null ); - $this->assertInstanceOf( WP_Error::class, $result ); - $this->assertStringStartsWith( 'Value must be a null:', $result->get_error_message() ); - } + public static function provideIntegers(): array { + return [ + [ 0 ], + [ -1 ], + [ 42 ], + [ PHP_INT_MAX ], + [ PHP_INT_MIN ], + [ 0x7FFFFFFF ], + [ 0x80000000 ], + [ 0x7FFFFFFFFFFFFFFF ], + [ 0x8000000000000000 ], + ]; } - public function testInvalidNumbers(): void { - $invalid_numbers = [ - null, - true, - '', - 'foo', - [], - (object) [], + public static function provideNulls(): array { + return [ + [ null ], ]; + } - $validator = new Validator( Types::number() ); + public static function provideNumericStrings(): array { + return [ + [ '-1' ], + [ '0' ], + [ '1' ], + [ '3.14' ], + ]; + } - foreach ( $invalid_numbers as $invalid_number ) { - $result = $validator->validate( $invalid_number ); - $this->assertInstanceOf( WP_Error::class, $result ); - $this->assertStringStartsWith( 'Value must be a number:', $result->get_error_message() ); - } + public static function provideObjectLikes(): array { + return [ + [ [] ], + [ [ 'foo' => 'bar' ] ], + [ (object) [] ], + [ (object) [ 'foo' => 'bar' ] ], + ]; } - public function testInvalidStrings(): void { - $invalid_strings = [ - null, - true, - 42, - 3.14, + public static function provideStrings(): array { + return [ [ 'foo' ], - (object) [], + [ '

Hello, world!

' ], + [ 'https://example.com/foo' ], + [ 'alice@example.com' ], + [ '123e4567-e89b-12d3-a456-426614174000' ], ]; + } + + /** + * @dataProvider provideBooleanLikeStrings + * @dataProvider provideEmptyStrings + * @dataProvider provideFloats + * @dataProvider provideIntegers + * @dataProvider provideInvalidEmailAddresses + * @dataProvider provideInvalidUrls + * @dataProvider provideNulls + * @dataProvider provideNumericStrings + * @dataProvider provideObjectLikes + * @dataProvider provideStrings + */ + public function testInvalidBooleans( mixed $invalid_value ): void { + $validator = new Validator( Types::boolean() ); + + $result = $validator->validate( $invalid_value ); + $this->assertInstanceOf( WP_Error::class, $result ); + $this->assertStringStartsWith( 'Value must be a boolean:', $result->get_error_message() ); + } + + /** + * @dataProvider provideBooleanLikeStrings + * @dataProvider provideBooleans + * @dataProvider provideEmptyStrings + * @dataProvider provideFloats + * @dataProvider provideInvalidEmailAddresses + * @dataProvider provideInvalidUrls + * @dataProvider provideNulls + * @dataProvider provideNumericStrings + * @dataProvider provideObjectLikes + * @dataProvider provideStrings + */ + public function testInvalidIntegers( mixed $invalid_value ): void { + $validator = new Validator( Types::integer() ); + $result = $validator->validate( $invalid_value ); + $this->assertInstanceOf( WP_Error::class, $result ); + $this->assertStringStartsWith( 'Value must be a integer:', $result->get_error_message() ); + } + + /** + * @dataProvider provideBooleanLikeStrings + * @dataProvider provideBooleans + * @dataProvider provideEmptyStrings + * @dataProvider provideFloats + * @dataProvider provideIntegers + * @dataProvider provideInvalidEmailAddresses + * @dataProvider provideInvalidUrls + * @dataProvider provideNumericStrings + * @dataProvider provideObjectLikes + * @dataProvider provideStrings + */ + public function testInvalidNulls( mixed $invalid_value ): void { + $validator = new Validator( Types::null() ); + + $result = $validator->validate( $invalid_value ); + $this->assertInstanceOf( WP_Error::class, $result ); + $this->assertStringStartsWith( 'Value must be a null:', $result->get_error_message() ); + } + + /** + * @dataProvider provideBooleanLikeStrings + * @dataProvider provideBooleans + * @dataProvider provideEmptyStrings + * @dataProvider provideInvalidEmailAddresses + * @dataProvider provideInvalidUrls + * @dataProvider provideNulls + * @dataProvider provideObjectLikes + * @dataProvider provideStrings + */ + public function testInvalidNumbers( mixed $invalid_value ): void { + $validator = new Validator( Types::number() ); + + $result = $validator->validate( $invalid_value ); + $this->assertInstanceOf( WP_Error::class, $result ); + $this->assertStringStartsWith( 'Value must be a number:', $result->get_error_message() ); + } + + /** + * @dataProvider provideBooleans + * @dataProvider provideFloats + * @dataProvider provideIntegers + * @dataProvider provideNulls + * @dataProvider provideObjectLikes + */ + public function testInvalidStrings( mixed $invalid_value ): void { $validator = new Validator( Types::string() ); - foreach ( $invalid_strings as $invalid_string ) { - $result = $validator->validate( $invalid_string ); - $this->assertInstanceOf( WP_Error::class, $result ); - $this->assertStringStartsWith( 'Value must be a string:', $result->get_error_message() ); - } + $result = $validator->validate( $invalid_value ); + $this->assertInstanceOf( WP_Error::class, $result ); + $this->assertStringStartsWith( 'Value must be a string:', $result->get_error_message() ); } - public function testInvalidEmailAddresses(): void { - $invalid_email_addresses = [ - null, - true, - 42, - 3.14, - '', - 'foo', - [], - (object) [], - 'me@example', - '@example.com', - 'me@.com', - 'me@example.', - 'me@.example.com', - 'me@ex ample.com', - 'me@ex' . str_repeat( 'a', 64 ) . '.com', - ]; + /** + * @dataProvider provideBooleans + * @dataProvider provideEmptyStrings + * @dataProvider provideFloats + * @dataProvider provideIntegers + * @dataProvider provideNulls + * @dataProvider provideObjectLikes + */ + public function testInvalidButtonTexts( mixed $invalid_value ): void { + $validator = new Validator( Types::button_text() ); + + $result = $validator->validate( $invalid_value ); + $this->assertInstanceOf( WP_Error::class, $result ); + $this->assertStringStartsWith( 'Value must be a button_text:', $result->get_error_message() ); + } + + /** + * @dataProvider provideBooleanLikeStrings + * @dataProvider provideBooleans + * @dataProvider provideEmptyStrings + * @dataProvider provideFloats + * @dataProvider provideIntegers + * @dataProvider provideInvalidEmailAddresses + * @dataProvider provideInvalidUrls + * @dataProvider provideNulls + * @dataProvider provideNumericStrings + * @dataProvider provideObjectLikes + */ + public function testInvalidButtonUrls( mixed $invalid_value ): void { + $validator = new Validator( Types::button_url() ); + + $result = $validator->validate( $invalid_value ); + $this->assertInstanceOf( WP_Error::class, $result ); + $this->assertStringStartsWith( 'Value must be a button_url:', $result->get_error_message() ); + } + /** + * @dataProvider provideBooleans + * @dataProvider provideNulls + * @dataProvider provideObjectLikes + */ + public function testInvalidCurrencyInCurrentLocales( mixed $invalid_value ): void { + $validator = new Validator( Types::currency_in_current_locale() ); + + $result = $validator->validate( $invalid_value ); + $this->assertInstanceOf( WP_Error::class, $result ); + $this->assertStringStartsWith( 'Value must be a currency_in_current_locale:', $result->get_error_message() ); + } + + /** + * @dataProvider provideBooleanLikeStrings + * @dataProvider provideBooleans + * @dataProvider provideEmptyStrings + * @dataProvider provideFloats + * @dataProvider provideIntegers + * @dataProvider provideInvalidEmailAddresses + * @dataProvider provideInvalidUrls + * @dataProvider provideNulls + * @dataProvider provideNumericStrings + * @dataProvider provideObjectLikes + */ + public function testInvalidEmailAddresses( mixed $invalid_value ): void { $validator = new Validator( Types::email_address() ); - foreach ( $invalid_email_addresses as $invalid_email_address ) { - $result = $validator->validate( $invalid_email_address ); - $this->assertInstanceOf( WP_Error::class, $result ); - $this->assertStringStartsWith( 'Value must be a email_address:', $result->get_error_message() ); - } + $result = $validator->validate( $invalid_value ); + $this->assertinstanceof( wp_error::class, $result ); + $this->assertstringstartswith( 'Value must be a email_address:', $result->get_error_message() ); } - // TODO additional invalid primitive tests + /** + * @dataProvider provideBooleans + * @dataProvider provideFloats + * @dataProvider provideIntegers + * @dataProvider provideNulls + * @dataProvider provideObjectLikes + */ + public function testInvalidHtmls( mixed $invalid_value ): void { + $validator = new Validator( Types::html() ); + + $result = $validator->validate( $invalid_value ); + $this->assertInstanceOf( WP_Error::class, $result ); + $this->assertStringStartsWith( 'Value must be a html:', $result->get_error_message() ); + } + + /** + * @dataProvider provideBooleans + * @dataProvider provideEmptyStrings + * @dataProvider provideFloats + * @dataProvider provideIntegers + * @dataProvider provideNulls + * @dataProvider provideObjectLikes + */ + public function testInvalidIds( mixed $invalid_value ): void { + $validator = new Validator( Types::id() ); + + $result = $validator->validate( $invalid_value ); + $this->assertInstanceOf( WP_Error::class, $result ); + $this->assertStringStartsWith( 'Value must be a id:', $result->get_error_message() ); + } public function testCallable(): void { $schema = Types::callable(); @@ -375,7 +548,7 @@ public function testRecord(): void { $this->assertSame( 'Record must have valid value: 123', $result->get_error_message() ); } - public function testRef(): void { + public function testObjectRef(): void { $schema = Types::object( [ 'foo' => Types::create_ref( 'my-ref', @@ -395,6 +568,7 @@ public function testRef(): void { $result = $validator->validate( [ 'foo' => [ 'a_string' => 'foo' ], + // Missing 'bar' ] ); $this->assertInstanceOf( WP_Error::class, $result ); From 669d3105847c750d38dbde59183b8dd29794804e Mon Sep 17 00:00:00 2001 From: Chris Zarate Date: Wed, 12 Feb 2025 22:53:49 -0500 Subject: [PATCH 10/16] Upgrade Psalm to 6.5 and allow global constants and functions (#368) * Add php-version to psalm GitHub action config * Upgrade Psalm to 6.5 and use global constants and functions --- .github/workflows/lint.yml | 1 + composer.json | 2 +- composer.lock | 20 ++++++++++---------- psalm.xml | 2 ++ 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index b5c1c18e..1ef41ee9 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -64,6 +64,7 @@ jobs: uses: docker://ghcr.io/psalm/psalm-github-actions with: composer_require_dev: true + php-version: '8.1' dependaban: name: Dependaban diff --git a/composer.json b/composer.json index d44b22fd..4706cda2 100644 --- a/composer.json +++ b/composer.json @@ -42,7 +42,7 @@ "phpunit/phpunit": "^9", "slevomat/coding-standard": "^8.15", "php-stubs/wordpress-stubs": "^6.6", - "psalm/phar": "^6.0", + "psalm/phar": "^6.5", "mockery/mockery": "^1.6", "wp-phpunit/wp-phpunit": "^6.7", "yoast/phpunit-polyfills": "^3.1", diff --git a/composer.lock b/composer.lock index 70559b28..7678e33b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1502305afc876f94cb1e3a76cbbeb1ec", + "content-hash": "0313acfc48efaccad68091d4f7b99964", "packages": [ { "name": "erusev/parsedown", @@ -2459,16 +2459,16 @@ }, { "name": "psalm/phar", - "version": "6.1.0", + "version": "6.5.1", "source": { "type": "git", "url": "https://github.com/psalm/phar.git", - "reference": "65011fc1453292b88c79dd09549d8d04c4e06c75" + "reference": "f7ecaf8740f32d58695cee5ac11663e02b44b223" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/psalm/phar/zipball/65011fc1453292b88c79dd09549d8d04c4e06c75", - "reference": "65011fc1453292b88c79dd09549d8d04c4e06c75", + "url": "https://api.github.com/repos/psalm/phar/zipball/f7ecaf8740f32d58695cee5ac11663e02b44b223", + "reference": "f7ecaf8740f32d58695cee5ac11663e02b44b223", "shasum": "" }, "require": { @@ -2488,9 +2488,9 @@ "description": "Composer-based Psalm Phar", "support": { "issues": "https://github.com/psalm/phar/issues", - "source": "https://github.com/psalm/phar/tree/6.1.0" + "source": "https://github.com/psalm/phar/tree/6.5.1" }, - "time": "2025-01-30T19:46:07+00:00" + "time": "2025-02-10T10:05:10+00:00" }, { "name": "sebastian/cli-parser", @@ -3888,12 +3888,12 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { "php": ">=8.1" }, - "platform-dev": [], - "plugin-api-version": "2.3.0" + "platform-dev": {}, + "plugin-api-version": "2.6.0" } diff --git a/psalm.xml b/psalm.xml index cb3c4c74..eb2a5307 100644 --- a/psalm.xml +++ b/psalm.xml @@ -3,6 +3,8 @@ errorLevel="7" resolveFromConfigFile="true" phpVersion="8.1" + allConstantsGlobal="true" + allFunctionsGlobal="true" findUnusedCode="true" findUnusedBaselineEntry="true" findUnusedPsalmSuppress="true" From c94277ae24996fc4f36bffe7e8650b43cabbe2be Mon Sep 17 00:00:00 2001 From: Chris Zarate Date: Thu, 13 Feb 2025 13:31:40 -0500 Subject: [PATCH 11/16] Update schema to allow nested serialized config (#367) * Add serialized_config_for Type to allow nested schemas * Improve errors reported for one_of type --- inc/Config/ArraySerializable.php | 38 ++++++++- inc/Config/ArraySerializableInterface.php | 21 ++++- inc/Config/DataSource/HttpDataSource.php | 25 +++--- inc/Config/Query/GraphqlQuery.php | 2 +- inc/Config/Query/HttpQuery.php | 7 +- inc/Editor/BlockManagement/ConfigRegistry.php | 14 ++- inc/Validation/ConfigSchemas.php | 16 +++- inc/Validation/Types.php | 7 ++ inc/Validation/Validator.php | 51 ++++++++++- tests/inc/Config/HttpDataSourceTest.php | 3 +- tests/inc/Functions/FunctionsTest.php | 31 +++++++ tests/inc/Mocks/MockDataSource.php | 2 +- tests/inc/Mocks/MockQuery.php | 2 +- tests/inc/Mocks/MockSerializableClass.php | 16 ++++ tests/inc/Mocks/MockSerializableSubclass.php | 16 ++++ tests/inc/Validation/ValidatorTest.php | 85 +++++++++++++++++++ 16 files changed, 306 insertions(+), 30 deletions(-) create mode 100644 tests/inc/Mocks/MockSerializableClass.php create mode 100644 tests/inc/Mocks/MockSerializableSubclass.php diff --git a/inc/Config/ArraySerializable.php b/inc/Config/ArraySerializable.php index e3373c5c..9b9c3214 100644 --- a/inc/Config/ArraySerializable.php +++ b/inc/Config/ArraySerializable.php @@ -28,7 +28,17 @@ protected function get_or_call_from_config( string $property_name, mixed ...$cal /** * @inheritDoc */ - public static function from_array( array $config, ?ValidatorInterface $validator = null ): self|WP_Error { + public static function from_array( array $config, ?ValidatorInterface $validator = null ): static|WP_Error { + $subclass = static::get_subclass( $config ); + if ( null !== $subclass ) { + return $subclass::from_array( $config, $validator ); + } + + $config = static::preprocess_config( $config ); + if ( is_wp_error( $config ) ) { + return $config; + } + $schema = static::get_config_schema(); $validator = $validator ?? new Validator( $schema, static::class ); @@ -51,5 +61,29 @@ public function to_array(): array { return $this->config; } - abstract protected static function get_config_schema(): array; + /** + * @inheritDoc + */ + public static function preprocess_config( array $config ): array|WP_Error { + return $config; + } + + /** + * The config can provide a `__subclass` property that indicates that we should + * inflate using a subclass of this class. + */ + protected static function get_subclass( array $config ): ?string { + $subclass = $config['__subclass'] ?? null; + + if ( null !== $subclass && static::class !== $subclass && is_subclass_of( $subclass, static::class, true ) ) { + return $subclass; + } + + return null; + } + + /** + * @inheritDoc + */ + abstract public static function get_config_schema(): array; } diff --git a/inc/Config/ArraySerializableInterface.php b/inc/Config/ArraySerializableInterface.php index 42fc2491..4fc27cf4 100644 --- a/inc/Config/ArraySerializableInterface.php +++ b/inc/Config/ArraySerializableInterface.php @@ -3,6 +3,7 @@ namespace RemoteDataBlocks\Config; use RemoteDataBlocks\Validation\ValidatorInterface; +use WP_Error; interface ArraySerializableInterface { /** @@ -16,7 +17,25 @@ interface ArraySerializableInterface { * @param ValidatorInterface|null $validator An optional validator instance to use for validating the configuration. * @return mixed Returns a new instance of the implementing class. */ - public static function from_array( array $config, ?ValidatorInterface $validator ): mixed; + public static function from_array( array $config, ?ValidatorInterface $validator ): static|WP_Error; + + /** + * This method will be called by ::from_array() to prior to validating the + * config. This allows you to modify the config before it's validated, perhaps + * because you want to inflate it with additional or computed values. + * + * @param array $config The configuration to process. + * @return array The processed configuration. + */ + public static function preprocess_config( array $config ): array|WP_Error; + + /** + * Provides the schema that will be use the validate the config passed to + * from_array(). + * + * @return array An associative array representing the configuration schema. + */ + public static function get_config_schema(): array; /** * Converts the current object to an array representation. diff --git a/inc/Config/DataSource/HttpDataSource.php b/inc/Config/DataSource/HttpDataSource.php index 9942a168..ad42d419 100644 --- a/inc/Config/DataSource/HttpDataSource.php +++ b/inc/Config/DataSource/HttpDataSource.php @@ -5,7 +5,6 @@ use RemoteDataBlocks\Config\ArraySerializable; use RemoteDataBlocks\Validation\ConfigSchemas; use RemoteDataBlocks\Validation\Validator; -use RemoteDataBlocks\Validation\ValidatorInterface; use RemoteDataBlocks\WpdbStorage\DataSourceCrud; use WP_Error; @@ -44,25 +43,23 @@ final public function get_service_name(): string { * NOTE: This method uses late static bindings to allow child classes to * define their own validation schema. */ - public static function from_array( array $config, ?ValidatorInterface $validator = null ): self|WP_Error { + public static function preprocess_config( array $config ): array|WP_Error { $service_config = $config['service_config'] ?? []; - $validator = $validator ?? new Validator( static::get_service_config_schema() ); + $validator = new Validator( static::get_service_config_schema() ); $validated = $validator->validate( $service_config ); if ( is_wp_error( $validated ) ) { return $validated; } - return parent::from_array( - array_merge( - static::map_service_config( $service_config ), - [ - // Store the exact data used to create the instance to preserve determinism. - 'service' => static::SERVICE_NAME, - 'service_config' => $service_config, - 'uuid' => $config['uuid'] ?? null, - ] - ) + return array_merge( + static::map_service_config( $service_config ), + [ + // Store the exact data used to create the instance to preserve determinism. + 'service' => static::SERVICE_NAME, + 'service_config' => $service_config, + 'uuid' => $config['uuid'] ?? null, + ] ); } @@ -92,7 +89,7 @@ final public function to_array(): array { /** * @inheritDoc */ - protected static function get_config_schema(): array { + public static function get_config_schema(): array { return ConfigSchemas::get_http_data_source_config_schema(); } diff --git a/inc/Config/Query/GraphqlQuery.php b/inc/Config/Query/GraphqlQuery.php index 291f17cb..ac61d222 100644 --- a/inc/Config/Query/GraphqlQuery.php +++ b/inc/Config/Query/GraphqlQuery.php @@ -31,7 +31,7 @@ public function get_request_body( array $input_variables ): array { /** * @inheritDoc */ - protected static function get_config_schema(): array { + public static function get_config_schema(): array { return ConfigSchemas::get_graphql_query_config_schema(); } } diff --git a/inc/Config/Query/HttpQuery.php b/inc/Config/Query/HttpQuery.php index b4e77ae5..c28270c4 100644 --- a/inc/Config/Query/HttpQuery.php +++ b/inc/Config/Query/HttpQuery.php @@ -3,6 +3,7 @@ namespace RemoteDataBlocks\Config\Query; use RemoteDataBlocks\Config\ArraySerializable; +use RemoteDataBlocks\Config\DataSource\HttpDataSource; use RemoteDataBlocks\Config\DataSource\HttpDataSourceInterface; use RemoteDataBlocks\Config\QueryRunner\QueryRunner; use RemoteDataBlocks\Validation\ConfigSchemas; @@ -54,6 +55,10 @@ public function get_cache_ttl( array $input_variables ): null|int { * Get the data source associated with this query. */ public function get_data_source(): HttpDataSourceInterface { + if ( is_array( $this->config['data_source'] ) ) { + $this->config['data_source'] = HttpDataSource::from_array( $this->config['data_source'] ); + } + return $this->config['data_source']; } @@ -123,7 +128,7 @@ public function get_request_method(): string { /** * @inheritDoc */ - protected static function get_config_schema(): array { + public static function get_config_schema(): array { return ConfigSchemas::get_http_query_config_schema(); } diff --git a/inc/Editor/BlockManagement/ConfigRegistry.php b/inc/Editor/BlockManagement/ConfigRegistry.php index 288329cf..4802120a 100644 --- a/inc/Editor/BlockManagement/ConfigRegistry.php +++ b/inc/Editor/BlockManagement/ConfigRegistry.php @@ -6,6 +6,8 @@ use RemoteDataBlocks\Logging\LoggerManager; use Psr\Log\LoggerInterface; +use RemoteDataBlocks\Config\Query\HttpQuery; +use RemoteDataBlocks\Config\Query\QueryInterface; use RemoteDataBlocks\Editor\BlockPatterns\BlockPatterns; use RemoteDataBlocks\Validation\ConfigSchemas; use RemoteDataBlocks\Validation\Validator; @@ -46,7 +48,7 @@ public static function register_block( array $user_config = [] ): bool|WP_Error return self::create_error( $block_title, sprintf( 'Block %s has already been registered', $block_name ) ); } - $display_query = $user_config[ self::RENDER_QUERY_KEY ]['query']; + $display_query = self::inflate_query( $user_config[ self::RENDER_QUERY_KEY ]['query'] ); $input_schema = $display_query->get_input_schema(); // Build the base configuration for the block. This is our own internal @@ -83,7 +85,7 @@ public static function register_block( array $user_config = [] ): bool|WP_Error // Register "selectors" which allow the user to use a query to assist in // selecting data for display by the block. foreach ( $user_config[ self::SELECTION_QUERIES_KEY ] ?? [] as $selection_query ) { - $from_query = $selection_query['query']; + $from_query = self::inflate_query( $selection_query['query'] ); $from_query_type = $selection_query['type']; $to_query = $display_query; @@ -173,4 +175,12 @@ private static function create_error( string $block_title, string $message ): WP self::$logger->error( $error_message ); return new WP_Error( 'block_registration_error', $error_message ); } + + private static function inflate_query( array|QueryInterface $config ): QueryInterface { + if ( is_array( $config ) ) { + return HttpQuery::from_array( $config ); + } + + return $config; + } } diff --git a/inc/Validation/ConfigSchemas.php b/inc/Validation/ConfigSchemas.php index ff3f543f..ab0b10c1 100644 --- a/inc/Validation/ConfigSchemas.php +++ b/inc/Validation/ConfigSchemas.php @@ -4,6 +4,7 @@ use RemoteDataBlocks\Validation\Types; use RemoteDataBlocks\Config\DataSource\HttpDataSourceInterface; +use RemoteDataBlocks\Config\Query\HttpQueryInterface; use RemoteDataBlocks\Config\Query\QueryInterface; use RemoteDataBlocks\Config\QueryRunner\QueryRunnerInterface; use RemoteDataBlocks\Editor\BlockManagement\ConfigRegistry; @@ -74,14 +75,20 @@ private static function generate_remote_data_block_config_schema(): array { ) ), 'render_query' => Types::object( [ - 'query' => Types::instance_of( QueryInterface::class ), + 'query' => Types::one_of( + Types::instance_of( QueryInterface::class ), + Types::serialized_config_for( HttpQueryInterface::class ), + ), 'loop' => Types::nullable( Types::boolean() ), ] ), 'selection_queries' => Types::nullable( Types::list_of( Types::object( [ 'display_name' => Types::nullable( Types::string() ), - 'query' => Types::instance_of( QueryInterface::class ), + 'query' => Types::one_of( + Types::instance_of( QueryInterface::class ), + Types::serialized_config_for( HttpQueryInterface::class ), + ), 'type' => Types::enum( ConfigRegistry::LIST_QUERY_KEY, ConfigRegistry::SEARCH_QUERY_KEY @@ -148,7 +155,10 @@ private static function generate_http_data_source_service_config_schema(): array private static function generate_http_query_config_schema(): array { return Types::object( [ 'cache_ttl' => Types::nullable( Types::one_of( Types::callable(), Types::integer(), Types::null() ) ), - 'data_source' => Types::instance_of( HttpDataSourceInterface::class ), + 'data_source' => Types::one_of( + Types::instance_of( HttpDataSourceInterface::class ), + Types::serialized_config_for( HttpDataSourceInterface::class ), + ), 'endpoint' => Types::nullable( Types::one_of( Types::callable(), Types::url() ) ), 'image_url' => Types::nullable( Types::image_url() ), // NOTE: The "input schema" for a query is not a formal schema like the diff --git a/inc/Validation/Types.php b/inc/Validation/Types.php index e3635edd..8b4b285b 100644 --- a/inc/Validation/Types.php +++ b/inc/Validation/Types.php @@ -184,6 +184,7 @@ public static function one_of( array ...$member_types ): array { 'object', 'record', 'ref', + 'serialized_config_for', 'string_matching', ]; $is_primitive = self::is_primitive( $member_type ); @@ -210,6 +211,12 @@ public static function record( array $key_type, array $value_type ): array { return self::generate_non_primitive_type( 'record', [ $key_type, $value_type ] ); } + // This type indicates that the value is a serialized array that can be used + // to inflate a class instance, e.g., HttpQuery::from_array( $value ). + public static function serialized_config_for( string $class_ref ): array { + return self::generate_non_primitive_type( 'serialized_config_for', $class_ref ); + } + public static function string_matching( string $regex ): array { return self::generate_non_primitive_type( 'string_matching', $regex ); } diff --git a/inc/Validation/Validator.php b/inc/Validation/Validator.php index 8b585906..3e41ae5d 100644 --- a/inc/Validation/Validator.php +++ b/inc/Validation/Validator.php @@ -2,6 +2,7 @@ namespace RemoteDataBlocks\Validation; +use RemoteDataBlocks\Config\ArraySerializableInterface; use RemoteDataBlocks\Validation\Types; use RemoteDataBlocks\Logging\LoggerManager; use WP_Error; @@ -112,13 +113,23 @@ private function check_non_primitive_type( array $type, mixed $value ): bool|WP_ return true; case 'one_of': + // Keep track of all failed validations. Since one_of is a union type, + // if none of the types match, we will return all of the errors so that + // the caller can inspect each of them. + $errors = []; + foreach ( Types::get_type_args( $type ) as $member_type ) { - if ( true === $this->check_type( $member_type, $value ) ) { + $validated = $this->check_type( $member_type, $value ); + if ( true === $validated ) { return true; } + + $errors[] = $validated; } - return $this->create_error( 'Value must be one of the specified types', $value ); + $error = new WP_Error( 'invalid_one_of_type', 'Validation errors for each of the specified types', [ 'errors' => $errors ] ); + + return $this->create_error( 'Value must be one of the specified types', $value, $error ); case 'object': if ( ! self::check_iterable_object( $value ) ) { @@ -161,6 +172,40 @@ private function check_non_primitive_type( array $type, mixed $value ): bool|WP_ case 'ref': return $this->check_type( Types::load_ref_type( $type ), $value ); + case 'serialized_config_for': + if ( ! self::check_iterable_object( $value ) ) { + return $this->create_error( 'Value must be an associative array', $value ); + } + + $class_ref = Types::get_type_args( $type ); + + if ( ! class_exists( $class_ref ) && ! interface_exists( $class_ref ) ) { + return $this->create_error( 'Class does not exist', $class_ref ); + } + + $implements = class_implements( $class_ref ); + if ( ! in_array( ArraySerializableInterface::class, $implements, true ) ) { + return $this->create_error( 'Class does not implement ArraySerializableInterface', $class_ref ); + } + + // The config can provide a `__subclass` property that indicates that we + // should inflate using a subclass of the specified class. + $subclass = $value['__subclass'] ?? null; + if ( null !== $subclass ) { + if ( ! is_subclass_of( $subclass, $class_ref, true ) ) { + return $this->create_error( 'Class specified by __subclass must be a subclass of the specified class', $subclass ); + } + + $class_ref = $subclass; + } + + // Validate the schema for the class we want to instantiate. Call the + // config prepocessor since some classes inflate their own config. + $config_validator = new Validator( $class_ref::get_config_schema(), $class_ref ); + $config = $class_ref::preprocess_config( $value ); + + return $config_validator->validate( $config ); + case 'string_matching': $regex = Types::get_type_args( $type ); @@ -236,7 +281,7 @@ private function create_error( string $message, mixed $value, ?WP_Error $child_e return new WP_Error( 'invalid_type', $message, [ 'child' => $child_error ] ); } - private function get_object_key( mixed $data, string $key ): mixed { + private function get_object_key( mixed $data, string|int $key ): mixed { return is_array( $data ) && array_key_exists( $key, $data ) ? $data[ $key ] : null; } } diff --git a/tests/inc/Config/HttpDataSourceTest.php b/tests/inc/Config/HttpDataSourceTest.php index 340fd493..197221e7 100644 --- a/tests/inc/Config/HttpDataSourceTest.php +++ b/tests/inc/Config/HttpDataSourceTest.php @@ -10,8 +10,9 @@ class HttpDataSourceTest extends TestCase { public function testGetServiceMethodCannotBeOverriddenl(): void { $config = [ - 'service' => 'mock', 'service_config' => [ + '__version' => 1, + 'display_name' => 'Mock Data Source', 'endpoint' => 'http://example.com', ], ]; diff --git a/tests/inc/Functions/FunctionsTest.php b/tests/inc/Functions/FunctionsTest.php index 3ba87bb9..88cf3ba0 100644 --- a/tests/inc/Functions/FunctionsTest.php +++ b/tests/inc/Functions/FunctionsTest.php @@ -70,6 +70,37 @@ public function testRegisterLoopBlock(): void { $this->assertTrue( $config['loop'] ); } + public function testRegisterBlockWithNestedConfig(): void { + register_remote_data_block( [ + 'title' => 'Test Block with Nested Config', + 'render_query' => [ + 'query' => [ + '__subclass' => 'RemoteDataBlocks\Tests\Mocks\MockQuery', + 'data_source' => [ + '__subclass' => 'RemoteDataBlocks\Tests\Mocks\MockDataSource', + 'service_config' => [ + '__version' => 1, + 'display_name' => 'Mock Data Source', + 'endpoint' => 'https://example.com/api', + ], + ], + 'display_name' => 'Mock Query', + 'input_schema' => [], + 'output_schema' => [ 'type' => 'string' ], + ], + ], + ] ); + + $block_name = 'remote-data-blocks/test-block-with-nested-config'; + $this->assertTrue( ConfigStore::is_registered_block( $block_name ) ); + + $config = ConfigStore::get_block_configuration( $block_name ); + $this->assertIsArray( $config ); + $this->assertSame( $block_name, $config['name'] ); + $this->assertSame( 'Test Block with Nested Config', $config['title'] ); + $this->assertFalse( $config['loop'] ); + } + public function testRegisterListQuery(): void { register_remote_data_block( [ 'title' => 'Test Block with List Query', diff --git a/tests/inc/Mocks/MockDataSource.php b/tests/inc/Mocks/MockDataSource.php index ec8005fa..be90eb22 100644 --- a/tests/inc/Mocks/MockDataSource.php +++ b/tests/inc/Mocks/MockDataSource.php @@ -20,7 +20,7 @@ class MockDataSource extends HttpDataSource { ], ]; - public static function from_array( ?array $config = self::MOCK_CONFIG, ?ValidatorInterface $validator = null ): self|WP_Error { + public static function from_array( ?array $config = self::MOCK_CONFIG, ?ValidatorInterface $validator = null ): static|WP_Error { return parent::from_array( $config, $validator ?? new MockValidator() ); } diff --git a/tests/inc/Mocks/MockQuery.php b/tests/inc/Mocks/MockQuery.php index ea4b17e9..9cf9c93a 100644 --- a/tests/inc/Mocks/MockQuery.php +++ b/tests/inc/Mocks/MockQuery.php @@ -11,7 +11,7 @@ class MockQuery extends HttpQuery { private mixed $response_data = null; - public static function from_array( array $config = [], ?ValidatorInterface $validator = null ): self|WP_Error { + public static function from_array( array $config = [], ?ValidatorInterface $validator = null ): static|WP_Error { return parent::from_array( [ 'data_source' => $config['data_source'] ?? MockDataSource::from_array(), 'display_name' => 'Mock Query', diff --git a/tests/inc/Mocks/MockSerializableClass.php b/tests/inc/Mocks/MockSerializableClass.php new file mode 100644 index 00000000..da708401 --- /dev/null +++ b/tests/inc/Mocks/MockSerializableClass.php @@ -0,0 +1,16 @@ + Types::boolean(), + 'enum_value' => Types::enum( 'foo', 'bar' ), + 'string_value' => Types::string(), + ] ); + } +} diff --git a/tests/inc/Mocks/MockSerializableSubclass.php b/tests/inc/Mocks/MockSerializableSubclass.php new file mode 100644 index 00000000..f294c52a --- /dev/null +++ b/tests/inc/Mocks/MockSerializableSubclass.php @@ -0,0 +1,16 @@ + Types::boolean(), + 'enum_value' => Types::enum( 'foo', 'bar' ), + 'string_value' => Types::string(), + 'extra_value' => Types::string(), + ] ); + } +} diff --git a/tests/inc/Validation/ValidatorTest.php b/tests/inc/Validation/ValidatorTest.php index c8afccb6..be962624 100644 --- a/tests/inc/Validation/ValidatorTest.php +++ b/tests/inc/Validation/ValidatorTest.php @@ -3,6 +3,8 @@ namespace RemoteDataBlocks\Tests\Validation; use PHPUnit\Framework\TestCase; +use RemoteDataBlocks\Tests\Mocks\MockSerializableClass; +use RemoteDataBlocks\Tests\Mocks\MockSerializableSubclass; use RemoteDataBlocks\Validation\Types; use RemoteDataBlocks\Validation\Validator; use stdClass; @@ -583,6 +585,89 @@ public function testObjectRef(): void { $this->assertSame( 'Object must have valid property: bar', $result->get_error_message() ); } + public function testSerializedConfigFor(): void { + $schema = Types::object( [ + 'config' => Types::serialized_config_for( MockSerializableClass::class ), + ] ); + + $validator = new Validator( $schema ); + + $this->assertTrue( $validator->validate( [ + 'config' => [ + 'boolean_value' => true, + 'enum_value' => 'foo', + 'string_value' => 'hello, world!', + ], + ] ) ); + + $result = $validator->validate( [ + 'config' => [ + 'boolean_value' => 'NOT A BOOLEAN', + 'enum_value' => 'foo', + 'string_value' => 'hello, world!', + ], + ] ); + + $this->assertInstanceOf( WP_Error::class, $result ); + $this->assertSame( 'Object must have valid property: config', $result->get_error_message() ); + $this->assertSame( 'Object must have valid property: boolean_value', $result->get_error_data()['child']->get_error_message() ); + + $result = $validator->validate( [ + 'config' => null, + ] ); + + $this->assertInstanceOf( WP_Error::class, $result ); + $this->assertSame( 'Object must have valid property: config', $result->get_error_message() ); + $this->assertSame( 'Value must be an associative array: null', $result->get_error_data()['child']->get_error_message() ); + + $result = $validator->validate( [ + 'config' => new stdClass(), + ] ); + + $this->assertInstanceOf( WP_Error::class, $result ); + $this->assertSame( 'Object must have valid property: config', $result->get_error_message() ); + $this->assertSame( 'Value must be an associative array: {}', $result->get_error_data()['child']->get_error_message() ); + + $result = $validator->validate( [ + 'config' => [], + ] ); + + $this->assertInstanceOf( WP_Error::class, $result ); + $this->assertSame( 'Object must have valid property: config', $result->get_error_message() ); + $this->assertSame( 'Object must have valid property: boolean_value', $result->get_error_data()['child']->get_error_message() ); + } + + public function testSerializedConfigForSubclass(): void { + $schema = Types::object( [ + 'config' => Types::serialized_config_for( MockSerializableClass::class ), + ] ); + + $validator = new Validator( $schema ); + + $this->assertTrue( $validator->validate( [ + 'config' => [ + '__subclass' => MockSerializableSubclass::class, + 'boolean_value' => true, + 'enum_value' => 'foo', + 'string_value' => 'hello, world!', + 'extra_value' => 'required for subclass', + ], + ] ) ); + + $result = $validator->validate( [ + 'config' => [ + '__subclass' => MockSerializableSubclass::class, + 'boolean_value' => true, + 'enum_value' => 'foo', + 'string_value' => 'hello, world!', + ], + ] ); + + $this->assertInstanceOf( WP_Error::class, $result ); + $this->assertSame( 'Object must have valid property: config', $result->get_error_message() ); + $this->assertSame( 'Object must have valid property: extra_value', $result->get_error_data()['child']->get_error_message() ); + } + public function testStringMatching(): void { $schema = Types::string_matching( '/^foo$/' ); From 25e76ff49b413c135087d0b4aa5ecf0e83756096 Mon Sep 17 00:00:00 2001 From: Brooke Date: Thu, 13 Feb 2025 12:51:08 -0800 Subject: [PATCH 12/16] Update Manual Input UI in block editor (#355) * Create InputPopover to replace InputModal Signed-off-by: brookewp * Clean up modal for potential multiple inputs Signed-off-by: brookewp * CSS spacing fix Signed-off-by: brookewp --------- Signed-off-by: brookewp --- .../components/modals/InputModal.tsx | 19 +++- .../placeholders/ItemSelectQueryType.tsx | 9 +- .../components/popovers/InputPopover.tsx | 98 +++++++++++++++++++ .../components/popovers/style.scss | 17 ++++ 4 files changed, 136 insertions(+), 7 deletions(-) create mode 100644 src/blocks/remote-data-container/components/popovers/InputPopover.tsx create mode 100644 src/blocks/remote-data-container/components/popovers/style.scss diff --git a/src/blocks/remote-data-container/components/modals/InputModal.tsx b/src/blocks/remote-data-container/components/modals/InputModal.tsx index cd47c1d4..ebd406b9 100644 --- a/src/blocks/remote-data-container/components/modals/InputModal.tsx +++ b/src/blocks/remote-data-container/components/modals/InputModal.tsx @@ -1,4 +1,9 @@ -import { Button, TextControl } from '@wordpress/components'; +import { + Button, + TextControl, + __experimentalHStack as HStack, + __experimentalSpacer as Spacer, +} from '@wordpress/components'; import { useState } from '@wordpress/element'; import { ModalWithButtonTrigger } from '@/blocks/remote-data-container/components/modals/BaseModal'; @@ -42,11 +47,11 @@ export function InputModal( props: InputModalProps ) {
onChange( input.slug, value ) } __nextHasNoMarginBottom + __next40pxDefaultSize style={ { marginBottom: '8px' } } /> ) ) } - + + + +
); diff --git a/src/blocks/remote-data-container/components/placeholders/ItemSelectQueryType.tsx b/src/blocks/remote-data-container/components/placeholders/ItemSelectQueryType.tsx index 99c3c259..898f1bec 100644 --- a/src/blocks/remote-data-container/components/placeholders/ItemSelectQueryType.tsx +++ b/src/blocks/remote-data-container/components/placeholders/ItemSelectQueryType.tsx @@ -1,7 +1,8 @@ import { ButtonGroup } from '@wordpress/components'; +import { InputModal } from '../modals/InputModal'; +import { InputPopover } from '../popovers/InputPopover'; import { DataViewsModal } from '@/blocks/remote-data-container/components/modals/DataViewsModal'; -import { InputModal } from '@/blocks/remote-data-container/components/modals/InputModal'; interface ItemSelectQueryTypeProps { blockConfig: BlockConfig; @@ -38,7 +39,11 @@ export function ItemSelectQueryType( props: ItemSelectQueryTypeProps ) { /> ); case 'input': - return ; + return selector.inputs.length === 1 && selector.inputs[ 0 ] ? ( + + ) : ( + + ); } return null; diff --git a/src/blocks/remote-data-container/components/popovers/InputPopover.tsx b/src/blocks/remote-data-container/components/popovers/InputPopover.tsx new file mode 100644 index 00000000..9f50f8a1 --- /dev/null +++ b/src/blocks/remote-data-container/components/popovers/InputPopover.tsx @@ -0,0 +1,98 @@ +import { + Button, + Popover, + __experimentalInputControl as InputControl, + ExternalLink, +} from '@wordpress/components'; +import { useState } from '@wordpress/element'; +import { keyboardReturn } from '@wordpress/icons'; + +import { useModalState } from '@/blocks/remote-data-container/hooks/useModalState'; +import { sendTracksEvent } from '@/blocks/remote-data-container/utils/tracks'; +import { __ } from '@/utils/i18n'; +import { getBlockDataSourceType } from '@/utils/localized-block-data'; + +import './style.scss'; + +interface InputPopoverProps { + blockName: string; + headerImage?: string; + input: InputVariable; + onSelect: ( data: RemoteDataQueryInput ) => void; + title: string; +} + +export function InputPopover( props: InputPopoverProps ) { + const { input, onSelect } = props; + + const dataSourceType = getBlockDataSourceType( props.blockName ); + + const initialInputState = { [ input.slug ]: '' }; + + const [ inputState, setInputState ] = useState< Record< string, string > >( initialInputState ); + const { close, isOpen, open } = useModalState(); + + function onChange( field: string, value: string ): void { + setInputState( { ...inputState, [ field ]: value } ); + } + + function onSelectItem(): void { + onSelect( inputState ); + close(); + sendTracksEvent( 'remotedatablocks_add_block', { + action: 'select_item', + selected_option: 'manual_input', + data_source_type: getBlockDataSourceType( props.blockName ), + } ); + } + + function getDataSourceLabels( sourceType: string ): { + buttonText: string; + helpText?: JSX.Element; + } { + switch ( sourceType ) { + case 'airtable': + return { + buttonText: __( 'Enter record ID' ), + helpText: ( + + { __( 'How do I get the Record ID?' ) } + + ), + }; + default: + return { + buttonText: __( 'Provide manual input' ), + }; + } + } + + return ( + <> + + { isOpen && ( + +
{ + event.preventDefault(); + onSelectItem(); + } } + > + onChange( input.slug, value ?? '' ) } + help={ getDataSourceLabels( dataSourceType ).helpText } + suffix={