diff --git a/.eslintrc.js b/.eslintrc.js index 8a44b5ef74a1e..122ec45369c22 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -331,6 +331,7 @@ module.exports = { message: 'Prefer page.locator instead.', }, ], + 'playwright/no-conditional-in-test': 'off', '@typescript-eslint/await-thenable': 'error', '@typescript-eslint/no-floating-promises': 'error', '@typescript-eslint/no-misused-promises': 'error', diff --git a/.github/workflows/build-plugin-zip.yml b/.github/workflows/build-plugin-zip.yml index 0921d1f9fc79c..f0c704e10456c 100644 --- a/.github/workflows/build-plugin-zip.yml +++ b/.github/workflows/build-plugin-zip.yml @@ -69,7 +69,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: token: ${{ secrets.GUTENBERG_TOKEN }} show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} @@ -165,13 +165,13 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ needs.bump-version.outputs.release_branch || github.ref }} show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - name: Use desired version of Node.js - uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 + uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 with: node-version-file: '.nvmrc' cache: npm @@ -221,7 +221,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 2 ref: ${{ needs.bump-version.outputs.release_branch }} @@ -310,14 +310,14 @@ jobs: if: ${{ endsWith( needs.bump-version.outputs.new_version, '-rc.1' ) }} steps: - name: Checkout (for CLI) - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: path: main ref: trunk show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - name: Checkout (for publishing) - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: path: publish # Later, we switch this branch in the script that publishes packages. @@ -332,7 +332,7 @@ jobs: git config user.email gutenberg@wordpress.org - name: Setup Node.js - uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 + uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 with: node-version-file: 'main/.nvmrc' registry-url: 'https://registry.npmjs.org' diff --git a/.github/workflows/bundle-size.yml b/.github/workflows/bundle-size.yml index d6a9ca83bf360..3b4d51bddbda0 100644 --- a/.github/workflows/bundle-size.yml +++ b/.github/workflows/bundle-size.yml @@ -37,13 +37,13 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 1 show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - name: Use desired version of Node.js - uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 + uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 with: node-version-file: '.nvmrc' cache: npm diff --git a/.github/workflows/check-components-changelog.yml b/.github/workflows/check-components-changelog.yml index 5ab89671c1cf6..fece5aa3a9d9a 100644 --- a/.github/workflows/check-components-changelog.yml +++ b/.github/workflows/check-components-changelog.yml @@ -20,7 +20,7 @@ jobs: - name: 'Get PR commit count' run: echo "PR_COMMIT_COUNT=$(( ${{ github.event.pull_request.commits }} + 1 ))" >> "${GITHUB_ENV}" - name: Checkout code - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ github.event.pull_request.head.ref }} repository: ${{ github.event.pull_request.head.repo.full_name }} diff --git a/.github/workflows/create-block.yml b/.github/workflows/create-block.yml index d46a3077ee7c9..0e4325b53f69d 100644 --- a/.github/workflows/create-block.yml +++ b/.github/workflows/create-block.yml @@ -24,7 +24,7 @@ jobs: os: [macos-latest, ubuntu-latest, windows-latest] steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} diff --git a/.github/workflows/end2end-test.yml b/.github/workflows/end2end-test.yml index 9bf85a1ac5363..9bd6ba212f0d8 100644 --- a/.github/workflows/end2end-test.yml +++ b/.github/workflows/end2end-test.yml @@ -27,7 +27,7 @@ jobs: totalParts: [3] steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} @@ -73,7 +73,7 @@ jobs: totalParts: [4] steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} @@ -119,7 +119,7 @@ jobs: steps: # Checkout defaults to using the branch which triggered the event, which # isn't necessarily `trunk` (e.g. in the case of a merge). - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: trunk show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index b4012ffc19fd4..bc457758b8385 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -6,7 +6,7 @@ jobs: name: 'Validation' runs-on: ubuntu-latest steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - uses: gradle/wrapper-validation-action@v1 diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 875ed28c743aa..485668a755b8c 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -32,7 +32,7 @@ jobs: WP_ARTIFACTS_PATH: ${{ github.workspace }}/artifacts steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} diff --git a/.github/workflows/php-changes-detection.yml b/.github/workflows/php-changes-detection.yml index 2078bb4a1ddfe..7e80157d0caf7 100644 --- a/.github/workflows/php-changes-detection.yml +++ b/.github/workflows/php-changes-detection.yml @@ -10,14 +10,14 @@ jobs: if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} steps: - name: Check out code - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: fetch-depth: 0 show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - name: Get changed PHP files id: changed-files-php - uses: tj-actions/changed-files@8238a4103220c636f2dad328ead8a7c8dbe316a3 # v39.2.0 + uses: tj-actions/changed-files@25ef3926d147cd02fc7e931c1ef50772bbb0d25d # v40.1.1 with: files: | *.{php} diff --git a/.github/workflows/publish-npm-packages.yml b/.github/workflows/publish-npm-packages.yml index a93c3ea032fd8..18bdb63a6c377 100644 --- a/.github/workflows/publish-npm-packages.yml +++ b/.github/workflows/publish-npm-packages.yml @@ -31,7 +31,7 @@ jobs: steps: - name: Checkout (for CLI) if: ${{ github.event.inputs.release_type != 'wp' }} - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: path: cli ref: trunk @@ -39,7 +39,7 @@ jobs: - name: Checkout (for publishing) if: ${{ github.event.inputs.release_type != 'wp' }} - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: path: publish # Later, we switch this branch in the script that publishes packages. @@ -49,7 +49,7 @@ jobs: - name: Checkout (for publishing WP major version) if: ${{ github.event.inputs.release_type == 'wp' && github.event.inputs.wp_version }} - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: path: publish ref: wp/${{ github.event.inputs.wp_version }} @@ -67,14 +67,14 @@ jobs: - name: Setup Node.js if: ${{ github.event.inputs.release_type != 'wp' }} - uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 + uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 with: node-version-file: 'cli/.nvmrc' registry-url: 'https://registry.npmjs.org' - name: Setup Node.js (for WP major version) if: ${{ github.event.inputs.release_type == 'wp' && github.event.inputs.wp_version }} - uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 + uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 with: node-version-file: 'publish/.nvmrc' registry-url: 'https://registry.npmjs.org' diff --git a/.github/workflows/pull-request-automation.yml b/.github/workflows/pull-request-automation.yml index 38cf4c66a503f..b8154e335776a 100644 --- a/.github/workflows/pull-request-automation.yml +++ b/.github/workflows/pull-request-automation.yml @@ -15,13 +15,13 @@ jobs: steps: # Checkout defaults to using the branch which triggered the event, which # isn't necessarily `trunk` (e.g. in the case of a merge). - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: trunk show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - name: Use desired version of Node.js - uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 + uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 with: node-version: ${{ matrix.node }} diff --git a/.github/workflows/rnmobile-android-runner.yml b/.github/workflows/rnmobile-android-runner.yml index 5f33870be6879..5620e0f66abe5 100644 --- a/.github/workflows/rnmobile-android-runner.yml +++ b/.github/workflows/rnmobile-android-runner.yml @@ -23,7 +23,7 @@ jobs: steps: - name: checkout - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} @@ -47,7 +47,7 @@ jobs: run: npm run native test:e2e:setup - name: Gradle cache - uses: gradle/gradle-build-action@b5126f31dbc19dd434c3269bf8c28c315e121da2 # v2.8.1 + uses: gradle/gradle-build-action@842c587ad8aa4c68eeba24c396e15af4c2e9f30a # v2.9.0 - name: AVD cache uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 diff --git a/.github/workflows/rnmobile-ios-runner.yml b/.github/workflows/rnmobile-ios-runner.yml index 8f32a9ee9d9dc..fe3b9b3a3c3a5 100644 --- a/.github/workflows/rnmobile-ios-runner.yml +++ b/.github/workflows/rnmobile-ios-runner.yml @@ -23,7 +23,7 @@ jobs: native-test-name: [gutenberg-editor-rendering] steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} diff --git a/.github/workflows/static-checks.yml b/.github/workflows/static-checks.yml index 7fe07bb2ae7bf..ff8c27b14e39e 100644 --- a/.github/workflows/static-checks.yml +++ b/.github/workflows/static-checks.yml @@ -22,12 +22,12 @@ jobs: if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - name: Use desired version of Node.js - uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1 + uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0 with: node-version-file: '.nvmrc' cache: npm diff --git a/.github/workflows/storybook-pages.yml b/.github/workflows/storybook-pages.yml index 32683fac2178c..5117e2fc9fe6e 100644 --- a/.github/workflows/storybook-pages.yml +++ b/.github/workflows/storybook-pages.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: trunk show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 7ce44a6931d9e..65ba01d0b70e8 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -31,7 +31,7 @@ jobs: node: ['16'] steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} @@ -111,7 +111,7 @@ jobs: WP_ENV_CORE: ${{ matrix.wordpress == '' && 'WordPress/WordPress' || format( 'https://wordpress.org/wordpress-{0}.zip', matrix.wordpress ) }} steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} @@ -126,7 +126,7 @@ jobs: # dependency versions are installed and cached. ## - name: Set up PHP - uses: shivammathur/setup-php@7fdd3ece872ec7ec4c098ae5ab7637d5e0a96067 # v2.26.0 + uses: shivammathur/setup-php@a36e1e52ff4a1c9e9c9be31551ee4712a6cb6bd0 # v2.27.1 with: php-version: '${{ matrix.php }}' ini-file: development @@ -221,12 +221,12 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - name: Set up PHP - uses: shivammathur/setup-php@7fdd3ece872ec7ec4c098ae5ab7637d5e0a96067 # v2.26.0 + uses: shivammathur/setup-php@a36e1e52ff4a1c9e9c9be31551ee4712a6cb6bd0 # v2.27.1 with: php-version: '7.4' coverage: none @@ -290,7 +290,7 @@ jobs: if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} steps: - - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} diff --git a/.github/workflows/upload-release-to-plugin-repo.yml b/.github/workflows/upload-release-to-plugin-repo.yml index 11ba57b439b59..c10020be057bc 100644 --- a/.github/workflows/upload-release-to-plugin-repo.yml +++ b/.github/workflows/upload-release-to-plugin-repo.yml @@ -96,7 +96,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0 + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ matrix.branch }} token: ${{ secrets.GUTENBERG_TOKEN }} diff --git a/docs/getting-started/create-block/README.md b/docs/getting-started/create-block/README.md index 2b87f09f1f903..22a28560c76a8 100644 --- a/docs/getting-started/create-block/README.md +++ b/docs/getting-started/create-block/README.md @@ -8,24 +8,6 @@ The tutorial includes setting up your development environment, tools, and gettin The first thing you need is a development environment and tools. This includes setting up your WordPress environment, Node, NPM, and your code editor. If you need help, see the [setting up your development environment documentation](/docs/getting-started/devenv/README.md). -## Quick Start - -The `@wordpress/create-block` package exists to create the necessary block scaffolding to get you started. See [create-block package documentation](https://www.npmjs.com/package/@wordpress/create-block) for additional features. This quick start assumes you have a development environment with node installed, and a WordPress site. - -From your plugins directory, to create your block run: - -```sh -npx @wordpress/create-block gutenpride --template @wordpress/create-block-tutorial-template -``` - -> Remember that you should use Node.js v14. Other versions may result in an error in the terminal. See [Node Development Tools](https://developer.wordpress.org/block-editor/getting-started/devenv/#node-development-tools) for more info. - -The [npx command](https://docs.npmjs.com/cli/v8/commands/npx) runs a command from a remote package, in this case our create-block package that will create a new directory called `gutenpride`, installs the necessary files, and builds the block plugin. If you want an interactive mode that prompts you for details, run the command without the `gutenpride` name. - -You now need to activate the plugin from inside wp-admin plugins page. - -After activation, go to the block editor and use the inserter to search and add your new block. - ## Table of Contents The create a block tutorials breaks down to the following sections. diff --git a/docs/getting-started/quick-start-guide.md b/docs/getting-started/quick-start-guide.md new file mode 100644 index 0000000000000..4ad3998e7c27d --- /dev/null +++ b/docs/getting-started/quick-start-guide.md @@ -0,0 +1,44 @@ +# Quick Start Guide + +This guide is designed to demonstrate the basic principles of block development in WordPress using a hands-on approach. Following the steps below, you will create a custom block plugin that uses modern JavaScript (ESNext and JSX) in a matter of minutes. The example block displays the copyright symbol (©) and the current year, the perfect addition to any website's footer. + +## Scaffold the block plugin + +Start by ensuring you have Node.js and `npm` installed on your computer. Review the [Node.js development environment](https://developer.wordpress.org/block-editor/getting-started/devenv/nodejs-development-environment/) guide if not. + +Next, use the [`@wordpress/create-block`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block/) package and the [`@wordpress/create-block-tutorial-template`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block-tutorial-template/) template to scaffold the complete “Copyright Date Block” plugin. + +
+

You can use create-block to scaffold a block just about anywhere and then use wp-env inside the generated plugin folder. This will create a local WordPress development environment with your new block plugin installed and activated.

+

If you already have your own local WordPress development environment, navigate to the plugins/ folder using the terminal.

+
+ +Choose the folder where you want to create the plugin, and then execute the following command in the terminal from within that folder: + +```sh +npx @wordpress/create-block copyright-date-block --template create-block-tutorial-template +``` + +The `slug` provided (`copyright-date-block`) defines the folder name for the scaffolded plugin and the internal block name. + +Navigate to the Plugins page of your local WordPress installation and activate the “Copyright Date Block” plugin. The example block will then be available in the Editor. + +## Basic usage + +With the plugin activated, you can explore how the block works. Use the following command to move into the newly created plugin folder and start the development process. + +```sh +cd copyright-date-block && npm start +``` + +When `create-block` scaffolds the block, it installs `wp-scripts` and adds the most common scripts to the block’s `package.json` file. Refer to the [Get started with wp-scripts](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-wp-scripts/) article for an introduction to this package. + +The `npm start` command will start a development server and watch for changes in the block’s code, rebuilding the block whenever modifications are made. + +When you are finished making changes, run the `npm run build` command. This optimizes the block code and makes it production-ready. + +## Additional resources + +- [Get started with create-block](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-create-block/) +- [Get started with wp-scripts](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-wp-scripts/) +- [Get started with wp-env](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-wp-env/) \ No newline at end of file diff --git a/docs/manifest.json b/docs/manifest.json index bc4d8bd7c3b28..ba345e7716ee3 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -41,6 +41,12 @@ "markdown_source": "../docs/getting-started/devenv/get-started-with-wp-scripts.md", "parent": "devenv" }, + { + "title": "Quick Start Guide", + "slug": "quick-start-guide", + "markdown_source": "../docs/getting-started/quick-start-guide.md", + "parent": "getting-started" + }, { "title": "Create a Block Tutorial", "slug": "create-block", diff --git a/docs/toc.json b/docs/toc.json index cbabf3d3b737c..8a29d2d4f10af 100644 --- a/docs/toc.json +++ b/docs/toc.json @@ -20,6 +20,7 @@ } ] }, + { "docs/getting-started/quick-start-guide.md": [] }, { "docs/getting-started/create-block/README.md": [ { diff --git a/package-lock.json b/package-lock.json index 9439981c29d7d..28f51a1408f64 100644 --- a/package-lock.json +++ b/package-lock.json @@ -84,6 +84,7 @@ "devDependencies": { "@actions/core": "1.9.1", "@actions/github": "5.0.0", + "@ariakit/test": "^0.3.0", "@babel/core": "7.16.0", "@babel/plugin-proposal-export-namespace-from": "7.18.9", "@babel/plugin-syntax-jsx": "7.16.0", @@ -1664,6 +1665,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/@ariakit/test/-/test-0.3.0.tgz", "integrity": "sha512-fngAzkzCl9zM4O/tzVaUf7ixWUAk779hjTegr/zcegoxaMS5SmaLhNQ7RU0AGx06LrhJse6GYGy8ZtK58HP/EQ==", + "dev": true, "dependencies": { "@ariakit/core": "0.3.3", "@testing-library/dom": "^8.0.0 || ^9.0.0" @@ -1681,6 +1683,12 @@ } } }, + "node_modules/@ariakit/test/node_modules/@ariakit/core": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@ariakit/core/-/core-0.3.3.tgz", + "integrity": "sha512-8x77R0aE9O9pheygg+h/z0oU9Wx/Xdlr7nfkl4klGnkJma8/nAhJ2RrchCTQCUef4WMsRnq/doCz8m/sslP6CA==", + "dev": true + }, "node_modules/@aw-web-design/x-default-browser": { "version": "1.4.126", "resolved": "https://registry.npmjs.org/@aw-web-design/x-default-browser/-/x-default-browser-1.4.126.tgz", @@ -15282,6 +15290,7 @@ "version": "9.3.1", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.1.tgz", "integrity": "sha512-0DGPd9AR3+iDTjGoMpxIkAsUihHZ3Ai6CneU6bRRrffXMgzCdlNk43jTrD2/5LT6CBb3MWTP8v510JzYtahD2w==", + "dev": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -15300,6 +15309,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "engines": { "node": ">=10" }, @@ -15311,6 +15321,7 @@ "version": "5.1.3", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, "dependencies": { "deep-equal": "^2.0.5" } @@ -15319,6 +15330,7 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", "integrity": "sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==", + "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.2", @@ -15346,12 +15358,14 @@ "node_modules/@testing-library/dom/node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true }, "node_modules/@testing-library/dom/node_modules/pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -15364,7 +15378,8 @@ "node_modules/@testing-library/dom/node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true }, "node_modules/@testing-library/jest-dom": { "version": "5.16.5", @@ -15567,7 +15582,8 @@ "node_modules/@types/aria-query": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", - "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==" + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", + "dev": true }, "node_modules/@types/async-lock": { "version": "1.4.0", @@ -19893,6 +19909,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "is-array-buffer": "^3.0.1" @@ -20232,6 +20249,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -21670,6 +21688,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -25107,6 +25126,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, "dependencies": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -25687,7 +25707,8 @@ "node_modules/dom-accessibility-api": { "version": "0.5.14", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz", - "integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==" + "integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==", + "dev": true }, "node_modules/dom-converter": { "version": "0.2.0", @@ -25835,11 +25856,6 @@ "node": ">=12" } }, - "node_modules/downloadjs": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz", - "integrity": "sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q==" - }, "node_modules/downshift": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/downshift/-/downshift-6.1.0.tgz", @@ -26310,6 +26326,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", @@ -26328,7 +26345,8 @@ "node_modules/es-get-iterator/node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true }, "node_modules/es-module-lexer": { "version": "1.3.1", @@ -28716,6 +28734,7 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, "dependencies": { "is-callable": "^1.1.3" } @@ -29102,6 +29121,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -29335,6 +29355,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -29825,6 +29846,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -29986,6 +30008,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -30002,6 +30025,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, "dependencies": { "get-intrinsic": "^1.1.1" }, @@ -30013,6 +30037,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -30024,6 +30049,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -30035,6 +30061,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -31208,6 +31235,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, "dependencies": { "get-intrinsic": "^1.2.0", "has": "^1.0.3", @@ -31337,6 +31365,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -31352,6 +31381,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.0", @@ -31370,6 +31400,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, "dependencies": { "has-bigints": "^1.0.1" }, @@ -31393,6 +31424,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -31428,6 +31460,7 @@ "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -31490,6 +31523,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -31683,6 +31717,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -31730,6 +31765,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -31840,6 +31876,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -31864,6 +31901,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -31872,6 +31910,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, "dependencies": { "call-bind": "^1.0.2" }, @@ -31900,6 +31939,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -31914,6 +31954,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -31940,6 +31981,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, "dependencies": { "which-typed-array": "^1.1.11" }, @@ -31971,6 +32013,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -31991,6 +32034,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -36655,6 +36699,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, "bin": { "lz-string": "bin/bin.js" } @@ -41607,6 +41652,7 @@ "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -41615,6 +41661,7 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -41630,6 +41677,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, "engines": { "node": ">= 0.4" } @@ -41649,6 +41697,7 @@ "version": "4.1.4", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -46384,6 +46433,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -48147,6 +48197,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -48983,6 +49034,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, "dependencies": { "internal-slot": "^1.0.4" }, @@ -53621,6 +53673,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -53636,6 +53689,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, "dependencies": { "is-map": "^2.0.1", "is-set": "^2.0.1", @@ -53655,6 +53709,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", @@ -54786,7 +54841,6 @@ "license": "GPL-2.0-or-later", "dependencies": { "@ariakit/react": "^0.3.5", - "@ariakit/test": "^0.3.0", "@babel/runtime": "^7.16.0", "@emotion/cache": "^11.7.1", "@emotion/css": "^11.7.1", @@ -55321,6 +55375,7 @@ "@tanstack/react-table": "^8.10.3", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", + "@wordpress/blob": "file:../blob", "@wordpress/block-editor": "file:../block-editor", "@wordpress/block-library": "file:../block-library", "@wordpress/blocks": "file:../blocks", @@ -55361,7 +55416,6 @@ "classnames": "^2.3.1", "colord": "^2.9.2", "deepmerge": "^4.3.0", - "downloadjs": "^1.4.7", "fast-deep-equal": "^3.1.3", "is-plain-object": "^5.0.0", "memize": "^2.1.0", @@ -55892,6 +55946,7 @@ "dependencies": { "@babel/runtime": "^7.16.0", "@wordpress/api-fetch": "file:../api-fetch", + "@wordpress/blob": "file:../blob", "@wordpress/components": "file:../components", "@wordpress/compose": "file:../compose", "@wordpress/element": "file:../element", @@ -57746,9 +57801,18 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/@ariakit/test/-/test-0.3.0.tgz", "integrity": "sha512-fngAzkzCl9zM4O/tzVaUf7ixWUAk779hjTegr/zcegoxaMS5SmaLhNQ7RU0AGx06LrhJse6GYGy8ZtK58HP/EQ==", + "dev": true, "requires": { "@ariakit/core": "0.3.3", "@testing-library/dom": "^8.0.0 || ^9.0.0" + }, + "dependencies": { + "@ariakit/core": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@ariakit/core/-/core-0.3.3.tgz", + "integrity": "sha512-8x77R0aE9O9pheygg+h/z0oU9Wx/Xdlr7nfkl4klGnkJma8/nAhJ2RrchCTQCUef4WMsRnq/doCz8m/sslP6CA==", + "dev": true + } } }, "@aw-web-design/x-default-browser": { @@ -67424,6 +67488,7 @@ "version": "9.3.1", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.1.tgz", "integrity": "sha512-0DGPd9AR3+iDTjGoMpxIkAsUihHZ3Ai6CneU6bRRrffXMgzCdlNk43jTrD2/5LT6CBb3MWTP8v510JzYtahD2w==", + "dev": true, "requires": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -67438,12 +67503,14 @@ "ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true }, "aria-query": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, "requires": { "deep-equal": "^2.0.5" } @@ -67452,6 +67519,7 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.2.tgz", "integrity": "sha512-xjVyBf0w5vH0I42jdAZzOKVldmPgSulmiyPRywoyq7HXC9qdgo17kxJE+rdnif5Tz6+pIrpJI8dCpMNLIGkUiA==", + "dev": true, "requires": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.2", @@ -67476,12 +67544,14 @@ "isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true }, "pretty-format": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, "requires": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -67491,7 +67561,8 @@ "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true } } }, @@ -67646,7 +67717,8 @@ "@types/aria-query": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", - "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==" + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", + "dev": true }, "@types/async-lock": { "version": "1.4.0", @@ -70023,7 +70095,6 @@ "version": "file:packages/components", "requires": { "@ariakit/react": "^0.3.5", - "@ariakit/test": "^0.3.0", "@babel/runtime": "^7.16.0", "@emotion/cache": "^11.7.1", "@emotion/css": "^11.7.1", @@ -70398,6 +70469,7 @@ "@tanstack/react-table": "^8.10.3", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", + "@wordpress/blob": "file:../blob", "@wordpress/block-editor": "file:../block-editor", "@wordpress/block-library": "file:../block-library", "@wordpress/blocks": "file:../blocks", @@ -70438,7 +70510,6 @@ "classnames": "^2.3.1", "colord": "^2.9.2", "deepmerge": "^4.3.0", - "downloadjs": "^1.4.7", "fast-deep-equal": "^3.1.3", "is-plain-object": "^5.0.0", "memize": "^2.1.0", @@ -70785,6 +70856,7 @@ "requires": { "@babel/runtime": "^7.16.0", "@wordpress/api-fetch": "file:../api-fetch", + "@wordpress/blob": "file:../blob", "@wordpress/components": "file:../components", "@wordpress/compose": "file:../compose", "@wordpress/element": "file:../element", @@ -72282,6 +72354,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, "requires": { "call-bind": "^1.0.2", "is-array-buffer": "^3.0.1" @@ -72547,7 +72620,8 @@ "available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "dev": true }, "axe-core": { "version": "4.7.2", @@ -73681,6 +73755,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -76292,6 +76367,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, "requires": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -76737,7 +76813,8 @@ "dom-accessibility-api": { "version": "0.5.14", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz", - "integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==" + "integrity": "sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg==", + "dev": true }, "dom-converter": { "version": "0.2.0", @@ -76857,11 +76934,6 @@ "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", "dev": true }, - "downloadjs": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz", - "integrity": "sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q==" - }, "downshift": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/downshift/-/downshift-6.1.0.tgz", @@ -77247,6 +77319,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, "requires": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", @@ -77262,7 +77335,8 @@ "isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true } } }, @@ -79095,6 +79169,7 @@ "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, "requires": { "is-callable": "^1.1.3" } @@ -79394,7 +79469,8 @@ "functions-have-names": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true }, "gauge": { "version": "4.0.4", @@ -79573,6 +79649,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -79956,6 +80033,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, "requires": { "get-intrinsic": "^1.1.3" } @@ -80085,7 +80163,8 @@ "has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true }, "has-flag": { "version": "3.0.0", @@ -80096,6 +80175,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, "requires": { "get-intrinsic": "^1.1.1" } @@ -80103,17 +80183,20 @@ "has-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true }, "has-tostringtag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, "requires": { "has-symbols": "^1.0.2" } @@ -80996,6 +81079,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, "requires": { "get-intrinsic": "^1.2.0", "has": "^1.0.3", @@ -81098,6 +81182,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -81107,6 +81192,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, "requires": { "call-bind": "^1.0.2", "get-intrinsic": "^1.2.0", @@ -81122,6 +81208,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, "requires": { "has-bigints": "^1.0.1" } @@ -81139,6 +81226,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -81161,7 +81249,8 @@ "is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true }, "is-ci": { "version": "2.0.0", @@ -81210,6 +81299,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -81337,7 +81427,8 @@ "is-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "dev": true }, "is-nan": { "version": "1.3.2", @@ -81377,6 +81468,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -81446,6 +81538,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -81460,12 +81553,14 @@ "is-set": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "dev": true }, "is-shared-array-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, "requires": { "call-bind": "^1.0.2" } @@ -81488,6 +81583,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, "requires": { "has-tostringtag": "^1.0.0" } @@ -81496,6 +81592,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, "requires": { "has-symbols": "^1.0.2" } @@ -81513,6 +81610,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dev": true, "requires": { "which-typed-array": "^1.1.11" } @@ -81531,7 +81629,8 @@ "is-weakmap": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==" + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "dev": true }, "is-weakref": { "version": "1.0.2", @@ -81546,6 +81645,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dev": true, "requires": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -85122,7 +85222,8 @@ "lz-string": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==" + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true }, "macos-release": { "version": "2.2.0", @@ -89001,12 +89102,14 @@ "object-inspect": { "version": "1.12.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true }, "object-is": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -89015,7 +89118,8 @@ "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true }, "object-visit": { "version": "1.0.1", @@ -89029,6 +89133,7 @@ "version": "4.1.4", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -92585,6 +92690,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", @@ -93977,6 +94083,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, "requires": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -94626,6 +94733,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, "requires": { "internal-slot": "^1.0.4" } @@ -98083,6 +98191,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, "requires": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -98095,6 +98204,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dev": true, "requires": { "is-map": "^2.0.1", "is-set": "^2.0.1", @@ -98111,6 +98221,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz", "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==", + "dev": true, "requires": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", diff --git a/package.json b/package.json index 9f456f359a741..2c3313b9337d4 100644 --- a/package.json +++ b/package.json @@ -96,6 +96,7 @@ "devDependencies": { "@actions/core": "1.9.1", "@actions/github": "5.0.0", + "@ariakit/test": "^0.3.0", "@babel/core": "7.16.0", "@babel/plugin-proposal-export-namespace-from": "7.18.9", "@babel/plugin-syntax-jsx": "7.16.0", diff --git a/packages/blob/CHANGELOG.md b/packages/blob/CHANGELOG.md index 8d88b3cc4062a..680d53971c018 100644 --- a/packages/blob/CHANGELOG.md +++ b/packages/blob/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### New feature + +- Add `downloadBlob` function and remove `downloadjs` dependency ([#56024](https://github.com/WordPress/gutenberg/pull/56024)). + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/blob/README.md b/packages/blob/README.md index 0305c4784d6cb..ff28e8879602f 100644 --- a/packages/blob/README.md +++ b/packages/blob/README.md @@ -26,6 +26,31 @@ _Returns_ - `string`: The blob URL. +### downloadBlob + +Downloads a file, e.g., a text or readable stream, in the browser. Appropriate for downloading smaller file sizes, e.g., \< 5 MB. + +Example usage: + +```js +const fileContent = JSON.stringify( + { + title: 'My Post', + }, + null, + 2 +); +const fileName = 'file.json'; + +downloadBlob( 'file.json', fileContent, 'application/json' ); +``` + +_Parameters_ + +- _filename_ `string`: File name. +- _content_ `BlobPart`: File content (BufferSource | Blob | string). +- _contentType_ `string`: (Optional) File mime type. Default is `''`. + ### getBlobByURL Retrieve a file based on a blob URL. The file must have been created by `createBlobURL` and not removed by `revokeBlobURL`, otherwise it will return `undefined`. diff --git a/packages/blob/src/index.js b/packages/blob/src/index.js index 496869703d2da..edc2e43729a23 100644 --- a/packages/blob/src/index.js +++ b/packages/blob/src/index.js @@ -70,3 +70,43 @@ export function isBlobURL( url ) { } return url.indexOf( 'blob:' ) === 0; } + +/** + * Downloads a file, e.g., a text or readable stream, in the browser. + * Appropriate for downloading smaller file sizes, e.g., < 5 MB. + * + * Example usage: + * + * ```js + * const fileContent = JSON.stringify( + * { + * "title": "My Post", + * }, + * null, + * 2 + * ); + * const fileName = 'file.json'; + * + * downloadBlob( 'file.json', fileContent, 'application/json' ); + * ``` + * + * @param {string} filename File name. + * @param {BlobPart} content File content (BufferSource | Blob | string). + * @param {string} contentType (Optional) File mime type. Default is `''`. + */ +export function downloadBlob( filename, content, contentType = '' ) { + if ( ! filename || ! content ) { + return; + } + + const file = new window.Blob( [ content ], { type: contentType } ); + const url = window.URL.createObjectURL( file ); + const anchorElement = document.createElement( 'a' ); + anchorElement.href = url; + anchorElement.download = filename; + anchorElement.style.display = 'none'; + document.body.appendChild( anchorElement ); + anchorElement.click(); + document.body.removeChild( anchorElement ); + window.URL.revokeObjectURL( url ); +} diff --git a/packages/blob/src/test/index.js b/packages/blob/src/test/index.js index 4e59917522b51..47dcb5019ee25 100644 --- a/packages/blob/src/test/index.js +++ b/packages/blob/src/test/index.js @@ -1,7 +1,7 @@ /** * Internal dependencies */ -import { isBlobURL, getBlobTypeByURL } from '../'; +import { isBlobURL, getBlobTypeByURL, downloadBlob } from '../'; describe( 'isBlobURL', () => { it( 'returns true if the url starts with "blob:"', () => { @@ -26,3 +26,60 @@ describe( 'getBlobTypeByURL', () => { expect( getBlobTypeByURL() ).toBe( undefined ); } ); } ); + +describe( 'downloadBlob', () => { + const originalURL = window.URL; + const createObjectURL = jest.fn().mockReturnValue( 'blob:pannacotta' ); + const revokeObjectURL = jest.fn().mockReturnValue( false ); + const mockAnchorElement = document.createElement( 'a' ); + mockAnchorElement.click = jest.fn(); + const createElementSpy = jest + .spyOn( global.document, 'createElement' ) + .mockReturnValue( mockAnchorElement ); + const mockBlob = jest.fn(); + const blobSpy = jest.spyOn( window, 'Blob' ).mockReturnValue( mockBlob ); + jest.spyOn( document.body, 'appendChild' ); + jest.spyOn( document.body, 'removeChild' ); + beforeEach( () => { + // Can't seem to spy on these static methods. They are `undefined`. + // Possibly overwritten: https://github.com/WordPress/gutenberg/blob/trunk/packages/jest-preset-default/scripts/setup-globals.js#L5 + window.URL = { + createObjectURL, + revokeObjectURL, + }; + } ); + + afterAll( () => { + window.URL = originalURL; + } ); + + it( 'requires a filename argument', () => { + downloadBlob( '', '{}', 'application/json' ); + expect( blobSpy ).not.toHaveBeenCalled(); + } ); + + it( 'requires a content argument', () => { + downloadBlob( 'text.txt', '', 'text/plain' ); + expect( blobSpy ).not.toHaveBeenCalled(); + } ); + + it( 'constructs an anchor element with attributes and removes it', () => { + downloadBlob( 'filename.json', '{}', 'application/json' ); + expect( blobSpy ).toHaveBeenCalledWith( [ '{}' ], { + type: 'application/json', + } ); + expect( createObjectURL ).toHaveBeenCalledWith( mockBlob ); + expect( createElementSpy ).toHaveBeenCalledWith( 'a' ); + expect( mockAnchorElement.download ).toBe( 'filename.json' ); + expect( mockAnchorElement.href ).toBe( 'blob:pannacotta' ); + expect( mockAnchorElement ).toHaveStyle( 'display:none' ); + expect( document.body.appendChild ).toHaveBeenCalledWith( + mockAnchorElement + ); + expect( mockAnchorElement.click ).toHaveBeenCalledTimes( 1 ); + expect( document.body.removeChild ).toHaveBeenCalledWith( + mockAnchorElement + ); + expect( revokeObjectURL ).toHaveBeenCalled(); + } ); +} ); diff --git a/packages/block-editor/src/components/block-list-appender/index.js b/packages/block-editor/src/components/block-list-appender/index.js index 7b37b93d8be8d..68f36f7dd2505 100644 --- a/packages/block-editor/src/components/block-list-appender/index.js +++ b/packages/block-editor/src/components/block-list-appender/index.js @@ -49,10 +49,6 @@ function useAppender( rootClientId, CustomAppender ) { getBlockEditingMode, } = select( blockEditorStore ); - if ( CustomAppender === false ) { - return false; - } - if ( ! CustomAppender ) { const selectedBlockClientId = getSelectedBlockClientId(); const isParentSelected = @@ -92,6 +88,26 @@ function BlockListAppender( { renderAppender, className, tagName: TagName = 'div', +} ) { + if ( renderAppender === false ) { + return null; + } + + return ( + + ); +} + +function BlockListAppenderInner( { + rootClientId, + renderAppender, + className, + tagName: TagName, } ) { const appender = useAppender( rootClientId, renderAppender ); const isDragOver = useSelect( diff --git a/packages/block-editor/src/components/iframe/index.js b/packages/block-editor/src/components/iframe/index.js index 28697324aa8b8..1939f75811c8c 100644 --- a/packages/block-editor/src/components/iframe/index.js +++ b/packages/block-editor/src/components/iframe/index.js @@ -73,12 +73,13 @@ function bubbleEvent( event, Constructor, frame ) { * @param {Document} iframeDocument Document to attach listeners to. */ function useBubbleEvents( iframeDocument ) { - return useRefEffect( ( body ) => { + return useRefEffect( () => { const { defaultView } = iframeDocument; if ( ! defaultView ) { return; } const { frameElement } = defaultView; + const html = iframeDocument.documentElement; const eventTypes = [ 'dragover', 'mousemove' ]; const handlers = {}; for ( const name of eventTypes ) { @@ -88,12 +89,12 @@ function useBubbleEvents( iframeDocument ) { const Constructor = window[ constructorName ]; bubbleEvent( event, Constructor, frameElement ); }; - body.addEventListener( name, handlers[ name ] ); + html.addEventListener( name, handlers[ name ] ); } return () => { for ( const name of eventTypes ) { - body.removeEventListener( name, handlers[ name ] ); + html.removeEventListener( name, handlers[ name ] ); } }; } ); diff --git a/packages/block-editor/src/components/list-view/block-select-button.js b/packages/block-editor/src/components/list-view/block-select-button.js index cec5d4699c7a2..25de5483f5192 100644 --- a/packages/block-editor/src/components/list-view/block-select-button.js +++ b/packages/block-editor/src/components/list-view/block-select-button.js @@ -19,6 +19,7 @@ import { SPACE, ENTER, BACKSPACE, DELETE } from '@wordpress/keycodes'; import { useSelect, useDispatch } from '@wordpress/data'; import { __unstableUseShortcutEventMatch as useShortcutEventMatch } from '@wordpress/keyboard-shortcuts'; import { __, sprintf } from '@wordpress/i18n'; +import isShallowEqual from '@wordpress/is-shallow-equal'; /** * Internal dependencies @@ -30,6 +31,7 @@ import ListViewExpander from './expander'; import { useBlockLock } from '../block-lock'; import { store as blockEditorStore } from '../../store'; import useListViewImages from './use-list-view-images'; +import { useListViewContext } from './context'; function ListViewBlockSelectButton( { @@ -64,10 +66,12 @@ function ListViewBlockSelectButton( getBlocksByClientId, canRemoveBlocks, } = useSelect( blockEditorStore ); - const { duplicateBlocks, removeBlocks } = useDispatch( blockEditorStore ); + const { duplicateBlocks, multiSelect, removeBlocks } = + useDispatch( blockEditorStore ); const isMatch = useShortcutEventMatch(); const isSticky = blockInformation?.positionType === 'sticky'; const images = useListViewImages( { clientId, isExpanded } ); + const { rootClientId } = useListViewContext(); const positionLabel = blockInformation?.positionLabel ? sprintf( @@ -183,6 +187,45 @@ function ListViewBlockSelectButton( updateFocusAndSelection( updatedBlocks[ 0 ], false ); } } + } else if ( isMatch( 'core/block-editor/select-all', event ) ) { + if ( event.defaultPrevented ) { + return; + } + event.preventDefault(); + + const { firstBlockRootClientId, selectedBlockClientIds } = + getBlocksToUpdate(); + const blockClientIds = getBlockOrder( firstBlockRootClientId ); + if ( ! blockClientIds.length ) { + return; + } + + // If we have selected all sibling nested blocks, try selecting up a level. + // This is a similar implementation to that used by `useSelectAll`. + // `isShallowEqual` is used for the list view instead of a length check, + // as the array of siblings of the currently focused block may be a different + // set of blocks from the current block selection if the user is focused + // on a different part of the list view from the block selection. + if ( isShallowEqual( selectedBlockClientIds, blockClientIds ) ) { + // Only select up a level if the first block is not the root block. + // This ensures that the block selection can't break out of the root block + // used by the list view, if the list view is only showing a partial hierarchy. + if ( + firstBlockRootClientId && + firstBlockRootClientId !== rootClientId + ) { + updateFocusAndSelection( firstBlockRootClientId, true ); + return; + } + } + + // Select all while passing `null` to skip focusing to the editor canvas, + // and retain focus within the list view. + multiSelect( + blockClientIds[ 0 ], + blockClientIds[ blockClientIds.length - 1 ], + null + ); } } diff --git a/packages/block-editor/src/components/list-view/index.js b/packages/block-editor/src/components/list-view/index.js index 1d21c28643a73..315a6153839d1 100644 --- a/packages/block-editor/src/components/list-view/index.js +++ b/packages/block-editor/src/components/list-view/index.js @@ -222,6 +222,7 @@ function ListViewComponent( insertedBlock, setInsertedBlock, treeGridElementRef: elementRef, + rootClientId, } ), [ draggedClientIds, @@ -233,6 +234,7 @@ function ListViewComponent( AdditionalBlockContent, insertedBlock, setInsertedBlock, + rootClientId, ] ); diff --git a/packages/block-editor/src/hooks/anchor.js b/packages/block-editor/src/hooks/anchor.js index 7a8f507d9674e..3d404c4a86811 100644 --- a/packages/block-editor/src/hooks/anchor.js +++ b/packages/block-editor/src/hooks/anchor.js @@ -59,6 +59,7 @@ function BlockEditAnchorControl( { blockName, attributes, setAttributes } ) { const textControl = ( { return ( props ) => { - const blockEdit = ; return ( <> - { blockEdit } - + + { props.isSelected && ( + + ) } ); }; diff --git a/packages/block-editor/src/hooks/block-rename-ui.js b/packages/block-editor/src/hooks/block-rename-ui.js index 6af17da6fad7f..836df953256c1 100644 --- a/packages/block-editor/src/hooks/block-rename-ui.js +++ b/packages/block-editor/src/hooks/block-rename-ui.js @@ -92,6 +92,7 @@ function RenameModal( { blockName, originalBlockName, onClose, onSave } ) { diff --git a/packages/block-library/src/comments/edit/comments-inspector-controls.js b/packages/block-library/src/comments/edit/comments-inspector-controls.js index 5dd7afab431ce..1a33cb68ea38a 100644 --- a/packages/block-library/src/comments/edit/comments-inspector-controls.js +++ b/packages/block-library/src/comments/edit/comments-inspector-controls.js @@ -22,6 +22,7 @@ export default function CommentsInspectorControls( { )' ), value: 'div' }, diff --git a/packages/block-library/src/cover/edit/inspector-controls.js b/packages/block-library/src/cover/edit/inspector-controls.js index 3ed0ae872f933..38757f90c2dee 100644 --- a/packages/block-library/src/cover/edit/inspector-controls.js +++ b/packages/block-library/src/cover/edit/inspector-controls.js @@ -319,6 +319,7 @@ export default function CoverInspectorControls( { )' ), value: 'div' }, diff --git a/packages/block-library/src/details/edit.js b/packages/block-library/src/details/edit.js index 81e4d7a52056a..0d1d675893900 100644 --- a/packages/block-library/src/details/edit.js +++ b/packages/block-library/src/details/edit.js @@ -72,7 +72,6 @@ function DetailsEdit( { attributes, setAttributes, clientId } ) { onChange={ ( newSummary ) => setAttributes( { summary: newSummary } ) } - multiline={ false } /> { innerBlocksProps.children } diff --git a/packages/block-library/src/group/edit.js b/packages/block-library/src/group/edit.js index 4d5354eff0180..277fa6872fa82 100644 --- a/packages/block-library/src/group/edit.js +++ b/packages/block-library/src/group/edit.js @@ -52,6 +52,7 @@ function GroupEditControls( { tagName, onSelectTagName } ) { )' ), value: 'div' }, diff --git a/packages/block-library/src/image/deprecated.js b/packages/block-library/src/image/deprecated.js index 4205da8e117b9..0365ddcfff5d1 100644 --- a/packages/block-library/src/image/deprecated.js +++ b/packages/block-library/src/image/deprecated.js @@ -1047,6 +1047,14 @@ const v8 = { }, }, migrate( { width, height, ...attributes } ) { + // We need to perform a check here because in cases + // where attributes are added dynamically to blocks, + // block invalidation overrides the isEligible() method + // and forces the migration to run, so it's not guaranteed + // that `behaviors` or `behaviors.lightbox` will be defined. + if ( ! attributes.behaviors?.lightbox ) { + return attributes; + } const { behaviors: { lightbox: { enabled }, diff --git a/packages/block-library/src/image/view.js b/packages/block-library/src/image/view.js index 30967a2de92c3..ef46e932d2490 100644 --- a/packages/block-library/src/image/view.js +++ b/packages/block-library/src/image/view.js @@ -313,11 +313,21 @@ store( if ( caption ) { const captionComputedStyle = window.getComputedStyle( caption ); - figureHeight = - figureHeight - - caption.offsetHeight - - parseFloat( captionComputedStyle.marginTop ) - - parseFloat( captionComputedStyle.marginBottom ); + if ( + ! [ 'absolute', 'fixed' ].includes( + captionComputedStyle.position + ) + ) { + figureHeight = + figureHeight - + caption.offsetHeight - + parseFloat( + captionComputedStyle.marginTop + ) - + parseFloat( + captionComputedStyle.marginBottom + ); + } } const buttonOffsetTop = figureHeight - offsetHeight; diff --git a/packages/block-library/src/missing/block.json b/packages/block-library/src/missing/block.json index 0bc512bbbf709..242a1d2c6b21a 100644 --- a/packages/block-library/src/missing/block.json +++ b/packages/block-library/src/missing/block.json @@ -15,7 +15,7 @@ }, "originalContent": { "type": "string", - "source": "html" + "source": "raw" } }, "supports": { diff --git a/packages/block-library/src/navigation/use-template-part-area-label.js b/packages/block-library/src/navigation/use-template-part-area-label.js index 91838b268b47d..48763a38ac62d 100644 --- a/packages/block-library/src/navigation/use-template-part-area-label.js +++ b/packages/block-library/src/navigation/use-template-part-area-label.js @@ -45,14 +45,16 @@ export default function useTemplatePartAreaLabel( clientId ) { 'core/editor' ).__experimentalGetDefaultTemplatePartAreas(); /* eslint-enable @wordpress/data-no-store-string-literals */ - const { getEditedEntityRecord } = select( coreStore ); + const { getCurrentTheme, getEditedEntityRecord } = + select( coreStore ); for ( const templatePartClientId of parentTemplatePartClientIds ) { const templatePartBlock = getBlock( templatePartClientId ); // The 'area' usually isn't stored on the block, but instead // on the entity. - const { theme, slug } = templatePartBlock.attributes; + const { theme = getCurrentTheme()?.stylesheet, slug } = + templatePartBlock.attributes; const templatePartEntityId = createTemplatePartId( theme, slug diff --git a/packages/block-library/src/pattern/edit.js b/packages/block-library/src/pattern/edit.js index 43d7875530481..5fd1b427a5e3e 100644 --- a/packages/block-library/src/pattern/edit.js +++ b/packages/block-library/src/pattern/edit.js @@ -20,7 +20,8 @@ const PatternEdit = ( { attributes, clientId } ) => { ); const currentThemeStylesheet = useSelect( - ( select ) => select( coreStore ).getCurrentTheme()?.stylesheet + ( select ) => select( coreStore ).getCurrentTheme()?.stylesheet, + [] ); const { replaceBlocks, __unstableMarkNextChangeAsNotPersistent } = diff --git a/packages/block-library/src/pattern/index.php b/packages/block-library/src/pattern/index.php index f05bb333bd186..436452f685300 100644 --- a/packages/block-library/src/pattern/index.php +++ b/packages/block-library/src/pattern/index.php @@ -48,7 +48,12 @@ function render_block_core_pattern( $attributes ) { $content = gutenberg_serialize_blocks( $blocks ); } - return do_blocks( $content ); + $content = do_blocks( $content ); + + global $wp_embed; + $content = $wp_embed->autoembed( $content ); + + return $content; } add_action( 'init', 'register_block_core_pattern' ); diff --git a/packages/block-library/src/post-author/edit.js b/packages/block-library/src/post-author/edit.js index 4ee353fdd9bdc..05797fcc8250a 100644 --- a/packages/block-library/src/post-author/edit.js +++ b/packages/block-library/src/post-author/edit.js @@ -196,7 +196,6 @@ function PostAuthorEdit( { { ( ! RichText.isEmpty( byline ) || isSelected ) && ( )' ), value: 'div' }, diff --git a/packages/block-library/src/template-part/edit/advanced-controls.js b/packages/block-library/src/template-part/edit/advanced-controls.js index b879b46638fac..8ad4b4bdbeb1d 100644 --- a/packages/block-library/src/template-part/edit/advanced-controls.js +++ b/packages/block-library/src/template-part/edit/advanced-controls.js @@ -95,6 +95,7 @@ export function TemplatePartAdvancedControls( { ) } select( coreStore ).getCurrentTheme()?.stylesheet, + [] + ); + const { slug, theme = currentTheme, tagName, layout = {} } = attributes; const templatePartId = createTemplatePartId( theme, slug ); const hasAlreadyRendered = useHasRecursion( templatePartId ); const [ isTemplatePartSelectionOpen, setIsTemplatePartSelectionOpen ] = @@ -174,17 +177,7 @@ export default function TemplatePartEdit( { } aria-haspopup="dialog" > - { createInterpolateElement( - __( 'Replace ' ), - { - BlockTitle: ( - - ), - } - ) } + { __( 'Replace' ) } ); } } diff --git a/packages/block-library/src/template-part/index.js b/packages/block-library/src/template-part/index.js index a68dd2301be22..c9b5e33a1c959 100644 --- a/packages/block-library/src/template-part/index.js +++ b/packages/block-library/src/template-part/index.js @@ -32,10 +32,11 @@ export const settings = { return; } - const entity = select( coreDataStore ).getEntityRecord( + const { getCurrentTheme, getEntityRecord } = select( coreDataStore ); + const entity = getEntityRecord( 'postType', 'wp_template_part', - theme + '//' + slug + ( theme || getCurrentTheme()?.stylesheet ) + '//' + slug ); if ( ! entity ) { return; diff --git a/packages/block-library/src/template-part/variations.js b/packages/block-library/src/template-part/variations.js index 866cf15d56c12..79881ee5f89e4 100644 --- a/packages/block-library/src/template-part/variations.js +++ b/packages/block-library/src/template-part/variations.js @@ -35,10 +35,12 @@ export function enhanceTemplatePartVariations( settings, name ) { // Find a matching variation from the created template part // by checking the entity's `area` property. if ( ! slug ) return false; - const entity = select( coreDataStore ).getEntityRecord( + const { getCurrentTheme, getEntityRecord } = + select( coreDataStore ); + const entity = getEntityRecord( 'postType', 'wp_template_part', - `${ theme }//${ slug }` + `${ theme || getCurrentTheme()?.stylesheet }//${ slug }` ); if ( entity?.slug ) { diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 0ca8fb69cde4f..be179d3b2251d 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -20,6 +20,10 @@ - `ToggleGroupControl`: Add opt-in prop for 40px default size ([#55789](https://github.com/WordPress/gutenberg/pull/55789)). - `TextControl`: Add opt-in prop for 40px default size ([#55471](https://github.com/WordPress/gutenberg/pull/55471)). +### Bug Fix + +- Package should not depend on `@ariakit/test`, that package is only needed for testing ([#56091](https://github.com/WordPress/gutenberg/pull/56091)). + ## 25.11.0 (2023-11-02) ### Enhancements diff --git a/packages/components/package.json b/packages/components/package.json index f616b261c8ec4..2980553f5a284 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -31,7 +31,6 @@ "types": "build-types", "dependencies": { "@ariakit/react": "^0.3.5", - "@ariakit/test": "^0.3.0", "@babel/runtime": "^7.16.0", "@emotion/cache": "^11.7.1", "@emotion/css": "^11.7.1", diff --git a/packages/create-block-tutorial-template/CHANGELOG.md b/packages/create-block-tutorial-template/CHANGELOG.md index d395b408d86c5..20f2a56d36643 100644 --- a/packages/create-block-tutorial-template/CHANGELOG.md +++ b/packages/create-block-tutorial-template/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Breaking Change + +- Update the block example scaffolded by the template. + ## 2.33.0 (2023-11-02) ## 2.32.0 (2023-10-18) diff --git a/packages/create-block-tutorial-template/README.md b/packages/create-block-tutorial-template/README.md index a4143312948e5..f883ff5fb79d4 100644 --- a/packages/create-block-tutorial-template/README.md +++ b/packages/create-block-tutorial-template/README.md @@ -1,6 +1,6 @@ # Create Block Tutorial Template -This is a template for [`@wordpress/create-block`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/create-block/README.md) that is the finished version of the block in the official [WordPress Tutorial](https://github.com/WordPress/gutenberg/tree/HEAD/docs/getting-started/create-block/README.md) for the block editor. +This is a template for [`@wordpress/create-block`](https://github.com/WordPress/gutenberg/tree/HEAD/packages/create-block/README.md) that creates an example "Copyright Date" block. This block is used in the official WordPress block development [Quick Start Guide](https://developer.wordpress.org/block-editor/getting-started/quick-start-guide). ## Usage @@ -10,6 +10,8 @@ This block template can be used by running the following command: npx @wordpress/create-block --template @wordpress/create-block-tutorial-template ``` +Use the default options when prompted in the terminal. + ## Contributing to this package This is an individual package that's part of the Gutenberg project. The project is organized as a monorepo. It's made up of multiple self-contained software packages, each with a specific purpose. The packages in this monorepo are published to [npm](https://www.npmjs.com/) and used by [WordPress](https://make.wordpress.org/core/) as well as other software projects. diff --git a/packages/create-block-tutorial-template/assets/gilbert-color.otf b/packages/create-block-tutorial-template/assets/gilbert-color.otf deleted file mode 100644 index f21f9a173f2fe..0000000000000 Binary files a/packages/create-block-tutorial-template/assets/gilbert-color.otf and /dev/null differ diff --git a/packages/create-block-tutorial-template/block-templates/edit.js.mustache b/packages/create-block-tutorial-template/block-templates/edit.js.mustache index fbb6864d869df..69a93b70c3556 100644 --- a/packages/create-block-tutorial-template/block-templates/edit.js.mustache +++ b/packages/create-block-tutorial-template/block-templates/edit.js.mustache @@ -1,17 +1,40 @@ /** - * WordPress components that create the necessary UI elements for the block + * Retrieves the translation of text. * - * @see https://developer.wordpress.org/block-editor/packages/packages-components/ + * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-i18n/ */ -import { TextControl } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; /** - * React hook that is used to mark the block wrapper element. - * It provides all the necessary props like the class name. + * Imports the InspectorControls component, which is used to wrap + * the block's custom controls that will appear in in the Settings + * Sidebar when the block is selected. + * + * Also imports the React hook that is used to mark the block wrapper + * element. It provides all the necessary props like the class name. * + * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#inspectorcontrols * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops */ -import { useBlockProps } from '@wordpress/block-editor'; +import { InspectorControls, useBlockProps } from '@wordpress/block-editor'; + +/** + * Imports the necessary components that will be used to create + * the user interface for the block's settings. + * + * @see https://developer.wordpress.org/block-editor/reference-guides/components/panel/#panelbody + * @see https://developer.wordpress.org/block-editor/reference-guides/components/text-control/ + * @see https://developer.wordpress.org/block-editor/reference-guides/components/toggle-control/ + */ +import { PanelBody, TextControl, ToggleControl } from '@wordpress/components'; + +/** + * Imports the useEffect React Hook. This is used to set an attribute when the + * block is loaded in the Editor. + * + * @see https://react.dev/reference/react/useEffect + */ +import { useEffect } from 'react'; /** * The edit function describes the structure of your block in the context of the @@ -26,13 +49,59 @@ import { useBlockProps } from '@wordpress/block-editor'; * @return {Element} Element to render. */ export default function Edit( { attributes, setAttributes } ) { - const blockProps = useBlockProps(); + const { fallbackCurrentYear, showStartingYear, startingYear } = attributes; + + // Get the current year and make sure it's a string. + const currentYear = new Date().getFullYear().toString(); + + // When the block loads, set the fallbackCurrentYear attribute to the + // current year if it's not already set. + useEffect( () => { + if ( currentYear !== fallbackCurrentYear ) { + setAttributes( { fallbackCurrentYear: currentYear } ); + } + }, [ currentYear, fallbackCurrentYear, setAttributes ] ); + + let displayDate; + + // Display the starting year as well if supplied by the user. + if ( showStartingYear && startingYear ) { + displayDate = startingYear + '–' + currentYear; + } else { + displayDate = currentYear; + } + return ( -
- setAttributes( { message: val } ) } - /> -
+ <> + + + + setAttributes( { + showStartingYear: ! showStartingYear, + } ) + } + /> + { showStartingYear && ( + + setAttributes( { startingYear: value } ) + } + /> + ) } + + +

© { displayDate }

+ ); } diff --git a/packages/create-block-tutorial-template/block-templates/editor.scss.mustache b/packages/create-block-tutorial-template/block-templates/editor.scss.mustache deleted file mode 100644 index 5d0b2deea6c10..0000000000000 --- a/packages/create-block-tutorial-template/block-templates/editor.scss.mustache +++ /dev/null @@ -1,13 +0,0 @@ -/** - * The following styles get applied inside the editor only. - * - * Replace them with your own styles or remove the file completely. - */ - -.wp-block-{{namespace}}-{{slug}} input[type="text"] { - font-family: Gilbert, sans-serif; - font-size: 64px; - color: inherit; - background: inherit; - border: 0; -} diff --git a/packages/create-block-tutorial-template/block-templates/index.js.mustache b/packages/create-block-tutorial-template/block-templates/index.js.mustache index fa35fbf272922..117d08b866980 100644 --- a/packages/create-block-tutorial-template/block-templates/index.js.mustache +++ b/packages/create-block-tutorial-template/block-templates/index.js.mustache @@ -5,49 +5,41 @@ */ import { registerBlockType } from '@wordpress/blocks'; -/** - * Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files. - * All files containing `style` keyword are bundled together. The code used - * gets applied both to the front of your site and to the editor. All other files - * get applied to the editor only. - * - * @see https://www.npmjs.com/package/@wordpress/scripts#using-css - */ -import './style.scss'; -import './editor.scss'; - /** * Internal dependencies */ import Edit from './edit'; -{{#isStaticVariant}} import save from './save'; -{{/isStaticVariant}} import metadata from './block.json'; +/** + * Define a custom SVG icon for the block. This icon will appear in + * the Inserter and when the user selects the block in the Editor. + */ +const calendarIcon = ( + +); + /** * Every block starts by registering a new block type definition. * * @see https://developer.wordpress.org/block-editor/developers/block-api/#registering-a-block */ registerBlockType( metadata.name, { - /** - * Used to construct a preview for the block to be shown in the block inserter. - */ - example: { - attributes: { - message: '{{title}}', - }, - }, + icon: calendarIcon, /** * @see ./edit.js */ edit: Edit, - {{#isStaticVariant}} - /** * @see ./save.js */ save, - {{/isStaticVariant}} } ); diff --git a/packages/create-block-tutorial-template/block-templates/render.php.mustache b/packages/create-block-tutorial-template/block-templates/render.php.mustache index b971a023985e5..1d31cdbed2836 100644 --- a/packages/create-block-tutorial-template/block-templates/render.php.mustache +++ b/packages/create-block-tutorial-template/block-templates/render.php.mustache @@ -1,10 +1,33 @@ -{{#isDynamicVariant}} -

> - -

-{{/isDynamicVariant}} + +// Get the current year. +$current_year = date( "Y" ); + +// Determine which content to display. +if ( isset( $attributes['fallbackCurrentYear'] ) && $attributes['fallbackCurrentYear'] === $current_year ) { + + // The current year is the same as the fallback, so use the block content saved in the database (by the save.js function). + $block_content = $content; +} else { + + // The current year is different from the fallback, so render the updated block content. + if ( ! empty( $attributes['startingYear'] ) && ! empty( $attributes['showStartingYear'] ) ) { + $display_date = $attributes['startingYear'] . '–' . $current_year; + } else { + $display_date = $current_year; + } + + $block_content = '

© ' . esc_html( $display_date ) . '

'; +} + +echo wp_kses_post( $block_content ); diff --git a/packages/create-block-tutorial-template/block-templates/save.js.mustache b/packages/create-block-tutorial-template/block-templates/save.js.mustache index a11ee432a4d44..944ae4c29254c 100644 --- a/packages/create-block-tutorial-template/block-templates/save.js.mustache +++ b/packages/create-block-tutorial-template/block-templates/save.js.mustache @@ -1,4 +1,3 @@ -{{#isStaticVariant}} /** * React hook that is used to mark the block wrapper element. * It provides all the necessary props like the class name. @@ -16,10 +15,27 @@ import { useBlockProps } from '@wordpress/block-editor'; * * @param {Object} props Properties passed to the function. * @param {Object} props.attributes Available block attributes. + * * @return {Element} Element to render. */ export default function save( { attributes } ) { - const blockProps = useBlockProps.save(); - return
{ attributes.message }
; + const { fallbackCurrentYear, showStartingYear, startingYear } = attributes; + + // If there is no fallbackCurrentYear, which could happen if the block + // is loaded from a template/pattern, return null. In this case, block + // rendering will be handled by the render.php file. + if ( ! fallbackCurrentYear ) { + return null; + } + + let displayDate; + + // Display the starting year as well if supplied by the user. + if ( showStartingYear && startingYear ) { + displayDate = startingYear + '–' + fallbackCurrentYear; + } else { + displayDate = fallbackCurrentYear; + } + + return

© { displayDate }

; } -{{/isStaticVariant}} diff --git a/packages/create-block-tutorial-template/block-templates/style.scss.mustache b/packages/create-block-tutorial-template/block-templates/style.scss.mustache deleted file mode 100644 index b1f1241345cbb..0000000000000 --- a/packages/create-block-tutorial-template/block-templates/style.scss.mustache +++ /dev/null @@ -1,17 +0,0 @@ -/** - * The following styles get applied both on the front of your site - * and in the editor. - * - * Replace them with your own styles or remove the file completely. - */ - -@font-face { - font-family: Gilbert; - src: url(../assets/gilbert-color.otf); - font-weight: 700; -} - -.wp-block-{{namespace}}-{{slug}} { - font-family: Gilbert, sans-serif; - font-size: 64px; -} diff --git a/packages/create-block-tutorial-template/index.js b/packages/create-block-tutorial-template/index.js index 514918e70ad8b..12c073d841fe5 100644 --- a/packages/create-block-tutorial-template/index.js +++ b/packages/create-block-tutorial-template/index.js @@ -5,35 +5,35 @@ const { join } = require( 'path' ); module.exports = { defaultValues: { - slug: 'gutenpride', - category: 'text', - title: 'Gutenpride', - description: - 'A Gutenberg block to show your pride! This block enables you to type text and style it with the color font Gilbert from Type with Pride.', - dashicon: 'flag', + slug: 'copyright-date-block', + title: 'Copyright Date', + description: "Display your site's copyright date.", attributes: { - message: { + fallbackCurrentYear: { + type: 'string', + }, + showStartingYear: { + type: 'boolean', + }, + startingYear: { type: 'string', - source: 'text', - selector: 'div', }, }, supports: { + color: { + background: false, + text: true, + }, html: false, - }, - }, - variants: { - static: {}, - dynamic: { - attributes: { - message: { - type: 'string', - }, + typography: { + fontSize: true, }, - render: 'file:./render.php', }, + editorScript: 'file:./index.js', + render: 'file:./render.php', + example: {}, + wpEnv: true, }, pluginTemplatesPath: join( __dirname, 'plugin-templates' ), blockTemplatesPath: join( __dirname, 'block-templates' ), - assetsPath: join( __dirname, 'assets' ), }; diff --git a/packages/create-block-tutorial-template/package.json b/packages/create-block-tutorial-template/package.json index 5fd4d71fd4cd8..33eb73835bfae 100644 --- a/packages/create-block-tutorial-template/package.json +++ b/packages/create-block-tutorial-template/package.json @@ -1,15 +1,16 @@ { "name": "@wordpress/create-block-tutorial-template", "version": "2.33.0", - "description": "Template for @wordpress/create-block used in the official WordPress tutorial.", + "description": "This is a template for @wordpress/create-block that creates an example 'Copyright Date' block. This block is used in the official WordPress block development Quick Start Guide.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", "keywords": [ "wordpress", "create block", - "block template" + "block template", + "quick start" ], - "homepage": "https://github.com/WordPress/gutenberg/tree/HEAD/docs/getting-started/create-block", + "homepage": "https://github.com/WordPress/gutenberg/tree/HEAD/docs/getting-started/quick-start-guide", "repository": { "type": "git", "url": "https://github.com/WordPress/gutenberg.git", diff --git a/packages/create-block-tutorial-template/plugin-templates/$slug.php.mustache b/packages/create-block-tutorial-template/plugin-templates/$slug.php.mustache index 52c9c4966646f..6de24df94c8d8 100644 --- a/packages/create-block-tutorial-template/plugin-templates/$slug.php.mustache +++ b/packages/create-block-tutorial-template/plugin-templates/$slug.php.mustache @@ -8,7 +8,7 @@ * Description: {{description}} {{/description}} * Version: {{version}} - * Requires at least: 6.1 + * Requires at least: 6.2 * Requires PHP: 7.0 {{#author}} * Author: {{author}} @@ -41,7 +41,7 @@ if ( ! defined( 'ABSPATH' ) ) { * * @see https://developer.wordpress.org/reference/functions/register_block_type/ */ -function {{namespaceSnakeCase}}_{{slugSnakeCase}}_block_init() { +function {{namespaceSnakeCase}}_{{slugSnakeCase}}_init() { register_block_type( __DIR__ . '/build' ); } -add_action( 'init', '{{namespaceSnakeCase}}_{{slugSnakeCase}}_block_init' ); +add_action( 'init', '{{namespaceSnakeCase}}_{{slugSnakeCase}}_init' ); diff --git a/packages/create-block-tutorial-template/plugin-templates/readme.txt.mustache b/packages/create-block-tutorial-template/plugin-templates/readme.txt.mustache index f069906fb19fa..d2b31bed6c0e6 100644 --- a/packages/create-block-tutorial-template/plugin-templates/readme.txt.mustache +++ b/packages/create-block-tutorial-template/plugin-templates/readme.txt.mustache @@ -3,7 +3,7 @@ Contributors: {{author}} {{/author}} Tags: block -Tested up to: 6.1 +Tested up to: 6.4 Stable tag: {{version}} {{#license}} License: {{license}} diff --git a/packages/create-block/README.md b/packages/create-block/README.md index 88ac97c34c2cf..20bb6c62ccf66 100644 --- a/packages/create-block/README.md +++ b/packages/create-block/README.md @@ -15,7 +15,7 @@ _It is largely inspired by [create-react-app](https://create-react-app.dev/docs/ - [Interactive Mode](#interactive-mode) - [`slug`](#slug) - [`options`](#options) -- [Available Commands](#available-commands) +- [Available Commands](#available-commands-in-the-scaffolded-project) - [External Project Templates](#external-project-templates) - [Contributing to this package](#contributing-to-this-package) @@ -141,7 +141,7 @@ For example, running the `start` script from inside the generated folder (`npm s ## External Project Templates -[Click here](https://github.com/WordPress/gutenberg/tree/HEAD/packages/create-block/docs/external-template.md) for information on External Project Templates +[Click here](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block/packages-create-block-external-template/) for information on External Project Templates ## Contributing to this package diff --git a/packages/edit-site/package.json b/packages/edit-site/package.json index 03d1ea851ff9a..d7007e1d88fec 100644 --- a/packages/edit-site/package.json +++ b/packages/edit-site/package.json @@ -30,6 +30,7 @@ "@tanstack/react-table": "^8.10.3", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", + "@wordpress/blob": "file:../blob", "@wordpress/block-editor": "file:../block-editor", "@wordpress/block-library": "file:../block-library", "@wordpress/blocks": "file:../blocks", @@ -70,7 +71,6 @@ "classnames": "^2.3.1", "colord": "^2.9.2", "deepmerge": "^4.3.0", - "downloadjs": "^1.4.7", "fast-deep-equal": "^3.1.3", "is-plain-object": "^5.0.0", "memize": "^2.1.0", diff --git a/packages/edit-site/src/components/dataviews/view-actions.js b/packages/edit-site/src/components/dataviews/view-actions.js index 5f808e99beeae..e1e85a3e56d09 100644 --- a/packages/edit-site/src/components/dataviews/view-actions.js +++ b/packages/edit-site/src/components/dataviews/view-actions.js @@ -95,7 +95,7 @@ function ViewTypeMenu( { view, onChangeView, supportedLayouts } ) { ); } -const PAGE_SIZE_VALUES = [ 20, 50, 100 ]; +const PAGE_SIZE_VALUES = [ 10, 20, 50, 100 ]; function PageSizeMenu( { view, onChangeView } ) { return ( { isLoading && ( diff --git a/packages/edit-site/src/components/header-edit-mode/more-menu/site-export.js b/packages/edit-site/src/components/header-edit-mode/more-menu/site-export.js index ec9492081a42b..85ec4f0dd7335 100644 --- a/packages/edit-site/src/components/header-edit-mode/more-menu/site-export.js +++ b/packages/edit-site/src/components/header-edit-mode/more-menu/site-export.js @@ -1,8 +1,3 @@ -/** - * External dependencies - */ -import downloadjs from 'downloadjs'; - /** * WordPress dependencies */ @@ -11,6 +6,7 @@ import { MenuItem } from '@wordpress/components'; import apiFetch from '@wordpress/api-fetch'; import { download } from '@wordpress/icons'; import { useDispatch } from '@wordpress/data'; +import { downloadBlob } from '@wordpress/blob'; import { store as noticesStore } from '@wordpress/notices'; export default function SiteExport() { @@ -35,7 +31,7 @@ export default function SiteExport() { ? contentDispositionMatches[ 1 ] : 'edit-site-export'; - downloadjs( blob, fileName + '.zip', 'application/zip' ); + downloadBlob( fileName + '.zip', blob, 'application/zip' ); } catch ( errorResponse ) { let error = {}; try { diff --git a/packages/edit-site/src/components/page-content-focus-manager/back-to-page-notification.js b/packages/edit-site/src/components/page-content-focus-manager/back-to-page-notification.js index a2990c56a673c..9bf9ac33b1d19 100644 --- a/packages/edit-site/src/components/page-content-focus-manager/back-to-page-notification.js +++ b/packages/edit-site/src/components/page-content-focus-manager/back-to-page-notification.js @@ -25,27 +25,19 @@ export default function BackToPageNotification() { * switches from focusing on editing page content to editing a template. */ export function useBackToPageNotification() { - const { isPage, hasPageContentFocus } = useSelect( - ( select ) => ( { - isPage: select( editSiteStore ).isPage(), - hasPageContentFocus: select( editSiteStore ).hasPageContentFocus(), - } ), + const hasPageContentFocus = useSelect( + ( select ) => select( editSiteStore ).hasPageContentFocus(), [] ); + const { isPage } = useSelect( editSiteStore ); const alreadySeen = useRef( false ); - const prevHasPageContentFocus = useRef( false ); const { createInfoNotice } = useDispatch( noticesStore ); const { setHasPageContentFocus } = useDispatch( editSiteStore ); useEffect( () => { - if ( - ! alreadySeen.current && - isPage && - prevHasPageContentFocus.current && - ! hasPageContentFocus - ) { + if ( isPage() && ! alreadySeen.current && ! hasPageContentFocus ) { createInfoNotice( __( 'You are editing a template.' ), { isDismissible: true, type: 'snackbar', @@ -58,11 +50,8 @@ export function useBackToPageNotification() { } ); alreadySeen.current = true; } - prevHasPageContentFocus.current = hasPageContentFocus; }, [ - alreadySeen, isPage, - prevHasPageContentFocus, hasPageContentFocus, createInfoNotice, setHasPageContentFocus, diff --git a/packages/edit-site/src/components/page-content-focus-manager/disable-non-page-content-blocks.js b/packages/edit-site/src/components/page-content-focus-manager/disable-non-page-content-blocks.js index f3e021ba88524..2f81f80d0ce63 100644 --- a/packages/edit-site/src/components/page-content-focus-manager/disable-non-page-content-blocks.js +++ b/packages/edit-site/src/components/page-content-focus-manager/disable-non-page-content-blocks.js @@ -1,9 +1,11 @@ /** * WordPress dependencies */ -import { createHigherOrderComponent } from '@wordpress/compose'; -import { addFilter, removeFilter } from '@wordpress/hooks'; -import { useBlockEditingMode } from '@wordpress/block-editor'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { + useBlockEditingMode, + store as blockEditorStore, +} from '@wordpress/block-editor'; import { useEffect } from '@wordpress/element'; /** @@ -11,42 +13,45 @@ import { useEffect } from '@wordpress/element'; */ import { PAGE_CONTENT_BLOCK_TYPES } from '../../utils/constants'; +function DisableBlock( { clientId } ) { + const isDescendentOfQueryLoop = useSelect( + ( select ) => { + const { getBlockParentsByBlockName } = select( blockEditorStore ); + return ( + getBlockParentsByBlockName( clientId, 'core/query' ).length !== + 0 + ); + }, + [ clientId ] + ); + const mode = isDescendentOfQueryLoop ? undefined : 'contentOnly'; + const { setBlockEditingMode, unsetBlockEditingMode } = + useDispatch( blockEditorStore ); + useEffect( () => { + if ( mode ) { + setBlockEditingMode( clientId, mode ); + return () => { + unsetBlockEditingMode( clientId ); + }; + } + }, [ clientId, mode, setBlockEditingMode, unsetBlockEditingMode ] ); +} + /** * Component that when rendered, makes it so that the site editor allows only * page content to be edited. */ export default function DisableNonPageContentBlocks() { - useDisableNonPageContentBlocks(); - return null; -} - -/** - * Disables non-content blocks using the `useBlockEditingMode` hook. - */ -export function useDisableNonPageContentBlocks() { useBlockEditingMode( 'disabled' ); - useEffect( () => { - addFilter( - 'editor.BlockEdit', - 'core/edit-site/disable-non-content-blocks', - withDisableNonPageContentBlocks + const clientIds = useSelect( ( select ) => { + const { __experimentalGetGlobalBlocksByName } = + select( blockEditorStore ); + return __experimentalGetGlobalBlocksByName( + Object.keys( PAGE_CONTENT_BLOCK_TYPES ) ); - return () => - removeFilter( - 'editor.BlockEdit', - 'core/edit-site/disable-non-content-blocks' - ); }, [] ); -} -const withDisableNonPageContentBlocks = createHigherOrderComponent( - ( BlockEdit ) => ( props ) => { - const isDescendentOfQueryLoop = props.context.queryId !== undefined; - const isPageContent = - PAGE_CONTENT_BLOCK_TYPES[ props.name ] && ! isDescendentOfQueryLoop; - const mode = isPageContent ? 'contentOnly' : undefined; - useBlockEditingMode( mode ); - return ; - }, - 'withDisableNonPageContentBlocks' -); + return clientIds.map( ( clientId ) => { + return ; + } ); +} diff --git a/packages/edit-site/src/components/page-patterns/grid-item.js b/packages/edit-site/src/components/page-patterns/grid-item.js index 64b70fb87de62..b394ef8eb6e76 100644 --- a/packages/edit-site/src/components/page-patterns/grid-item.js +++ b/packages/edit-site/src/components/page-patterns/grid-item.js @@ -36,6 +36,7 @@ import { } from '@wordpress/icons'; import { store as noticesStore } from '@wordpress/notices'; import { store as reusableBlocksStore } from '@wordpress/reusable-blocks'; +import { downloadBlob } from '@wordpress/blob'; /** * Internal dependencies @@ -51,25 +52,6 @@ import { store as editSiteStore } from '../../store'; import { useLink } from '../routes/link'; import { unlock } from '../../lock-unlock'; -/** - * Downloads a file. - * Also used in packages/list-reusable-blocks/src/utils/file.js. - * - * @param {string} fileName File Name. - * @param {string} content File Content. - * @param {string} contentType File mime type. - */ -function download( fileName, content, contentType ) { - const file = new window.Blob( [ content ], { type: contentType } ); - const a = document.createElement( 'a' ); - a.href = URL.createObjectURL( file ); - a.download = fileName; - a.style.display = 'none'; - document.body.appendChild( a ); - a.click(); - document.body.removeChild( a ); -} - const { useGlobalStyle } = unlock( blockEditorPrivateApis ); const templatePartIcons = { header, footer, uncategorized }; @@ -136,7 +118,7 @@ function GridItem( { categoryId, item, ...props } ) { syncStatus: item.patternBlock.wp_pattern_sync_status, }; - return download( + return downloadBlob( `${ kebabCase( item.title || item.name ) }.json`, JSON.stringify( json, null, 2 ), 'application/json' diff --git a/packages/edit-site/src/components/sidebar-dataviews/custom-dataviews-list.js b/packages/edit-site/src/components/sidebar-dataviews/custom-dataviews-list.js index f11c63653205f..12659a36bbf9b 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/custom-dataviews-list.js +++ b/packages/edit-site/src/components/sidebar-dataviews/custom-dataviews-list.js @@ -9,8 +9,13 @@ import { DropdownMenu, MenuGroup, MenuItem, + TextControl, + __experimentalHStack as HStack, + __experimentalVStack as VStack, + Button, + Modal, } from '@wordpress/components'; -import { useMemo } from '@wordpress/element'; +import { useMemo, useState } from '@wordpress/element'; import { moreVertical } from '@wordpress/icons'; import { __ } from '@wordpress/i18n'; import { privateApis as routerPrivateApis } from '@wordpress/router'; @@ -26,6 +31,55 @@ const { useHistory, useLocation } = unlock( routerPrivateApis ); const EMPTY_ARRAY = []; +function RenameItemModalContent( { dataviewId, currentTitle, setIsRenaming } ) { + const { editEntityRecord } = useDispatch( coreStore ); + const [ title, setTitle ] = useState( currentTitle ); + return ( +
{ + event.preventDefault(); + await editEntityRecord( + 'postType', + 'wp_dataviews', + dataviewId, + { + title, + } + ); + setIsRenaming( false ); + } } + > + + + + + + + +
+ ); +} + function CustomDataViewItem( { dataviewId, isActive } ) { const { params: { path }, @@ -49,51 +103,76 @@ function CustomDataViewItem( { dataviewId, isActive } ) { const viewContent = JSON.parse( dataview.content ); return viewContent.type; }, [ dataview.content ] ); + const [ isRenaming, setIsRenaming ] = useState( false ); return ( - + + { ( { onClose } ) => ( + + { + setIsRenaming( true ); + onClose(); + } } + > + { __( 'Rename' ) } + + { + await deleteEntityRecord( + 'postType', + 'wp_dataviews', + dataview.id, + { + force: true, + } + ); + if ( isActive ) { + history.replace( { + path, + } ); + } + onClose(); + } } + isDestructive + > + { __( 'Delete' ) } + + + ) } + + } + /> + { isRenaming && ( + { + setIsRenaming( false ); } } > - { ( { onClose } ) => ( - - { - await deleteEntityRecord( - 'postType', - 'wp_dataviews', - dataview.id, - { - force: true, - } - ); - if ( isActive ) { - history.replace( { - path, - } ); - } - onClose(); - } } - isDestructive - > - { __( 'Delete' ) } - - - ) } - - } - /> + + + ) } + ); } diff --git a/packages/edit-site/src/components/sidebar-dataviews/dataview-item.js b/packages/edit-site/src/components/sidebar-dataviews/dataview-item.js index fdd3272fbc24a..c6d7bbe4a231b 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/dataview-item.js +++ b/packages/edit-site/src/components/sidebar-dataviews/dataview-item.js @@ -1,8 +1,14 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ import { page, columns, pullRight } from '@wordpress/icons'; import { privateApis as routerPrivateApis } from '@wordpress/router'; +import { __experimentalHStack as HStack } from '@wordpress/components'; /** * Internal dependencies @@ -39,13 +45,23 @@ export default function DataViewItem( { isCustom, } ); return ( - - { title } - + + { title } + + { suffix } + ); } diff --git a/packages/edit-site/src/components/sidebar-dataviews/style.scss b/packages/edit-site/src/components/sidebar-dataviews/style.scss index 3e8812267b076..526670ee1e562 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/style.scss +++ b/packages/edit-site/src/components/sidebar-dataviews/style.scss @@ -6,3 +6,17 @@ text-transform: uppercase; } } + +.edit-site-sidebar-dataviews-dataview-item { + &:hover, + &:focus, + &[aria-current] { + color: $gray-200; + background: $gray-800; + } + + &.is-selected { + background: var(--wp-admin-theme-color); + color: $white; + } +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/edit-template.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/edit-template.js index 8067453a51821..fde2b63d6e833 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/edit-template.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/edit-template.js @@ -114,6 +114,7 @@ export default function EditTemplate() { icon={ ! isTemplateHidden ? check : undefined } + isPressed={ ! isTemplateHidden } onClick={ () => { setPageContentFocusType( isTemplateHidden diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss index e1a8e4acb7227..64d72db4e15fd 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss @@ -84,6 +84,11 @@ .components-popover__content { min-width: 240px; } + .components-button.is-pressed, + .components-button.is-pressed:hover { + background: inherit; + color: inherit; + } } .edit-site-page-panels-edit-slug__dropdown { @@ -92,3 +97,4 @@ padding: $grid-unit-20; } } + diff --git a/packages/edit-site/src/hooks/template-part-edit.js b/packages/edit-site/src/hooks/template-part-edit.js index 66f54967c55e2..0b14bbbbd7712 100644 --- a/packages/edit-site/src/hooks/template-part-edit.js +++ b/packages/edit-site/src/hooks/template-part-edit.js @@ -24,11 +24,13 @@ function EditTemplatePartMenuItem( { attributes } ) { const { params } = useLocation(); const templatePart = useSelect( ( select ) => { - return select( coreStore ).getEntityRecord( + const { getCurrentTheme, getEntityRecord } = select( coreStore ); + + return getEntityRecord( 'postType', TEMPLATE_PART_POST_TYPE, // Ideally this should be an official public API. - `${ theme }//${ slug }` + `${ theme || getCurrentTheme()?.stylesheet }//${ slug }` ); }, [ theme, slug ] diff --git a/packages/editor/src/components/page-attributes/order.js b/packages/editor/src/components/page-attributes/order.js index 416636d14bdbf..4a751c0b151ab 100644 --- a/packages/editor/src/components/page-attributes/order.js +++ b/packages/editor/src/components/page-attributes/order.js @@ -39,6 +39,7 @@ function PageAttributesOrder() { tag, it's important to - * prevent the default yellow background color applied by most - * browsers. The solution is to detect when this format is used with a - * text color but no background color, and in such cases to override - * the default styling with a transparent background. - * - * @see https://github.com/WordPress/gutenberg/pull/35516 - */ - __unstableFilterAttributeValue( key, value ) { - if ( key !== 'style' ) return value; - // We should not add a background-color if it's already set. - if ( value && value.includes( 'background-color' ) ) return value; - const addedCSS = [ 'background-color', transparentValue ].join( ':' ); - // Prepend `addedCSS` to avoid a double `;;` as any the existing CSS - // rules will already include a `;`. - return value ? [ addedCSS, value ].join( ';' ) : addedCSS; - }, edit: TextColorEdit, }; diff --git a/packages/format-library/src/text-color/index.native.js b/packages/format-library/src/text-color/index.native.js index 21db4c2a444f3..7c44e4efc001a 100644 --- a/packages/format-library/src/text-color/index.native.js +++ b/packages/format-library/src/text-color/index.native.js @@ -26,7 +26,6 @@ import { usePreferredColorSchemeStyle } from '@wordpress/compose'; * Internal dependencies */ import { getActiveColors } from './inline.js'; -import { transparentValue } from './index.js'; import { default as InlineColorUI } from './inline'; import styles from './style.scss'; @@ -183,26 +182,5 @@ export const textColor = { style: 'style', class: 'class', }, - /* - * Since this format relies on the tag, it's important to - * prevent the default yellow background color applied by most - * browsers. The solution is to detect when this format is used with a - * text color but no background color, and in such cases to override - * the default styling with a transparent background. - * - * @see https://github.com/WordPress/gutenberg/pull/35516 - */ - __unstableFilterAttributeValue( key, value ) { - if ( key !== 'style' ) return value; - // We need to remove the extra spaces within the styles on mobile - const newValue = value?.replace( / /g, '' ); - // We should not add a background-color if it's already set - if ( newValue && newValue.includes( 'background-color' ) ) - return newValue; - const addedCSS = [ 'background-color', transparentValue ].join( ':' ); - // Prepend `addedCSS` to avoid a double `;;` as any the existing CSS - // rules will already include a `;`. - return newValue ? [ addedCSS, newValue ].join( ';' ) : addedCSS; - }, edit: TextColorEdit, }; diff --git a/packages/list-reusable-blocks/package.json b/packages/list-reusable-blocks/package.json index b004d5fe803ee..9cc27c6911a91 100644 --- a/packages/list-reusable-blocks/package.json +++ b/packages/list-reusable-blocks/package.json @@ -27,6 +27,7 @@ "dependencies": { "@babel/runtime": "^7.16.0", "@wordpress/api-fetch": "file:../api-fetch", + "@wordpress/blob": "file:../blob", "@wordpress/components": "file:../components", "@wordpress/compose": "file:../compose", "@wordpress/element": "file:../element", diff --git a/packages/list-reusable-blocks/src/utils/export.js b/packages/list-reusable-blocks/src/utils/export.js index 4075c7576f134..4d7e76afcaa8f 100644 --- a/packages/list-reusable-blocks/src/utils/export.js +++ b/packages/list-reusable-blocks/src/utils/export.js @@ -11,7 +11,7 @@ import apiFetch from '@wordpress/api-fetch'; /** * Internal dependencies */ -import { download } from './file'; +import { downloadBlob } from '@wordpress/blob'; /** * Export a reusable block as a JSON file. @@ -38,7 +38,7 @@ async function exportReusableBlock( id ) { ); const fileName = kebabCase( title ) + '.json'; - download( fileName, fileContent, 'application/json' ); + downloadBlob( fileName, fileContent, 'application/json' ); } export default exportReusableBlock; diff --git a/packages/list-reusable-blocks/src/utils/file.js b/packages/list-reusable-blocks/src/utils/file.js index f4cff155c591f..d31e54ae41896 100644 --- a/packages/list-reusable-blocks/src/utils/file.js +++ b/packages/list-reusable-blocks/src/utils/file.js @@ -1,29 +1,3 @@ -/** - * Downloads a file. - * - * @param {string} fileName File Name. - * @param {string} content File Content. - * @param {string} contentType File mime type. - */ -export function download( fileName, content, contentType ) { - const file = new window.Blob( [ content ], { type: contentType } ); - - // IE11 can't use the click to download technique - // we use a specific IE11 technique instead. - if ( window.navigator.msSaveOrOpenBlob ) { - window.navigator.msSaveOrOpenBlob( file, fileName ); - } else { - const a = document.createElement( 'a' ); - a.href = URL.createObjectURL( file ); - a.download = fileName; - - a.style.display = 'none'; - document.body.appendChild( a ); - a.click(); - document.body.removeChild( a ); - } -} - /** * Reads the textual content of the given file. * diff --git a/packages/rich-text/src/component/index.js b/packages/rich-text/src/component/index.js index 17cf17e2e3154..87e57e49e4333 100644 --- a/packages/rich-text/src/component/index.js +++ b/packages/rich-text/src/component/index.js @@ -89,21 +89,6 @@ export function useRichText( { if ( ! record.current ) { hadSelectionUpdate.current = isSelected; setRecordFromProps(); - // Sometimes formats are added programmatically and we need to make - // sure it's persisted to the block store / markup. If these formats - // are not applied, they could cause inconsistencies between the data - // in the visual editor and the frontend. Right now, it's only relevant - // to the `core/text-color` format, which is applied at runtime in - // certain circunstances. See the `__unstableFilterAttributeValue` - // function in `packages/format-library/src/text-color/index.js`. - // @todo find a less-hacky way of solving this. - - const hasRelevantInitFormat = - record.current?.formats[ 0 ]?.[ 0 ]?.type === 'core/text-color'; - - if ( hasRelevantInitFormat ) { - handleChangesUponInit( record.current ); - } } else if ( selectionStart !== record.current.start || selectionEnd !== record.current.end @@ -155,29 +140,6 @@ export function useRichText( { forceRender(); } - function handleChangesUponInit( newRecord ) { - record.current = newRecord; - - _value.current = toHTMLString( { - value: __unstableBeforeSerialize - ? { - ...newRecord, - formats: __unstableBeforeSerialize( newRecord ), - } - : newRecord, - } ); - - const { formats, text } = newRecord; - - registry.batch( () => { - onChange( _value.current, { - __unstableFormats: formats, - __unstableText: text, - } ); - } ); - forceRender(); - } - function applyFromProps() { setRecordFromProps(); applyRecord( record.current ); diff --git a/packages/rich-text/src/create.js b/packages/rich-text/src/create.js index 63aac8c076b8b..a23baf70078bc 100644 --- a/packages/rich-text/src/create.js +++ b/packages/rich-text/src/create.js @@ -70,14 +70,6 @@ function toFormat( { tagName, attributes } ) { registeredAttributes[ key ] = _attributes[ name ]; - if ( formatType.__unstableFilterAttributeValue ) { - registeredAttributes[ key ] = - formatType.__unstableFilterAttributeValue( - key, - registeredAttributes[ key ] - ); - } - // delete the attribute and what's left is considered // to be unregistered. delete _attributes[ name ]; diff --git a/test/e2e/specs/editor/plugins/meta-boxes.spec.js b/test/e2e/specs/editor/plugins/meta-boxes.spec.js index b901201ff6c1d..5999dc07aeafe 100644 --- a/test/e2e/specs/editor/plugins/meta-boxes.spec.js +++ b/test/e2e/specs/editor/plugins/meta-boxes.spec.js @@ -62,8 +62,8 @@ test.describe( 'Meta boxes', () => { await page.goto( `/?p=${ postId }` ); await expect( - page.locator( '.wp-block-latest-posts > li' ) - ).toContainText( [ 'A published post', 'Dynamic block test' ] ); + page.locator( '.entry-content .wp-block-latest-posts__post-title' ) + ).toContainText( [ 'Dynamic block test', 'A published post' ] ); } ); test( 'Should render the excerpt in meta based on post content if no explicit excerpt exists', async ( { diff --git a/test/e2e/specs/editor/various/list-view.spec.js b/test/e2e/specs/editor/various/list-view.spec.js index 222d743acdf39..f05b7760c4cc7 100644 --- a/test/e2e/specs/editor/various/list-view.spec.js +++ b/test/e2e/specs/editor/various/list-view.spec.js @@ -421,7 +421,7 @@ test.describe( 'List View', () => { ).toBeFocused(); } ); - test( 'should duplicate, delete, and deselect blocks using keyboard', async ( { + test( 'should select, duplicate, delete, and deselect blocks using keyboard', async ( { editor, page, pageUtils, @@ -464,6 +464,116 @@ test.describe( 'List View', () => { { name: 'core/file', selected: true, focused: true }, ] ); + // Move up to columns block, expand, and then move to the first column block. + await page.keyboard.press( 'ArrowUp' ); + await page.keyboard.press( 'ArrowRight' ); + await page.keyboard.press( 'ArrowDown' ); + + await expect + .poll( + listViewUtils.getBlocksWithA11yAttributes, + 'The last inserted block should be selected, while the first column block should be focused.' + ) + .toMatchObject( [ + { name: 'core/group' }, + { + name: 'core/columns', + innerBlocks: [ + { name: 'core/column', selected: false, focused: true }, + { name: 'core/column' }, + ], + }, + { name: 'core/file', selected: true, focused: false }, + ] ); + + // Select all sibling column blocks at current level. + await pageUtils.pressKeys( 'primary+a' ); + await expect + .poll( + listViewUtils.getBlocksWithA11yAttributes, + 'All column blocks should be selected, with the first one focused.' + ) + .toMatchObject( [ + { name: 'core/group', selected: false, focused: false }, + { + name: 'core/columns', + innerBlocks: [ + { name: 'core/column', selected: true, focused: true }, + { name: 'core/column', selected: true, focused: false }, + ], + selected: false, + }, + { name: 'core/file', selected: false, focused: false }, + ] ); + + // Select next parent (the columns block). + await pageUtils.pressKeys( 'primary+a' ); + await expect + .poll( + listViewUtils.getBlocksWithA11yAttributes, + 'The columns block should be selected and focused.' + ) + .toMatchObject( [ + { name: 'core/group', selected: false, focused: false }, + { + name: 'core/columns', + innerBlocks: [ + { name: 'core/column' }, + { name: 'core/column' }, + ], + selected: true, + focused: true, + }, + { name: 'core/file', selected: false, focused: false }, + ] ); + + // Select all siblings at root level. + await pageUtils.pressKeys( 'primary+a' ); + await expect + .poll( + listViewUtils.getBlocksWithA11yAttributes, + 'All blocks should be selected.' + ) + .toMatchObject( [ + { name: 'core/group', selected: true, focused: false }, + { + name: 'core/columns', + innerBlocks: [ + { name: 'core/column' }, + { name: 'core/column' }, + ], + selected: true, + focused: true, + }, + { name: 'core/file', selected: true, focused: false }, + ] ); + + // Deselect blocks via Escape key. + await page.keyboard.press( 'Escape' ); + // Collapse the columns block. + await page.keyboard.press( 'ArrowLeft' ); + + await expect + .poll( + listViewUtils.getBlocksWithA11yAttributes, + 'All blocks should be deselected, with focus on the Columns block.' + ) + .toMatchObject( [ + { name: 'core/group', selected: false, focused: false }, + { + name: 'core/columns', + selected: false, + focused: true, + }, + { name: 'core/file', selected: false, focused: false }, + ] ); + + // Move focus and selection to the file block to set up for testing duplication. + await listView + .getByRole( 'gridcell', { name: 'File', exact: true } ) + .dblclick(); + + // Test duplication behaviour. await pageUtils.pressKeys( 'primaryShift+d' ); await expect diff --git a/test/e2e/specs/site-editor/pages.spec.js b/test/e2e/specs/site-editor/pages.spec.js index d1f32b9f209d7..8008109be15ee 100644 --- a/test/e2e/specs/site-editor/pages.spec.js +++ b/test/e2e/specs/site-editor/pages.spec.js @@ -136,6 +136,128 @@ test.describe( 'Pages', () => { ) ).toBeVisible(); } ); + + test( 'toggle template preview', async ( { page, editor } ) => { + await draftNewPage( page ); + await editor.openDocumentSettingsSidebar(); + + await editor.canvas + .getByRole( 'document', { + name: 'Block: Content', + } ) + .getByRole( 'document', { + name: 'Empty block; start writing or type forward slash to choose a block', + } ) + .click(); + + // Add some content to the page. + await page.keyboard.type( 'Sweet paragraph 1' ); + await page.keyboard.press( 'Enter' ); + await page.keyboard.type( 'Sweet paragraph 2' ); + + // Header template area and page content are visible. + await expect( + editor.canvas.getByRole( 'document', { + name: 'Block: header', + } ) + ).toBeVisible(); + + const paragraphs = editor.canvas + .getByRole( 'document', { + name: 'Block: Content', + } ) + .getByText( 'Sweet paragraph ' ); + + await expect( paragraphs.nth( 0 ) ).toBeVisible(); + await expect( paragraphs.nth( 1 ) ).toBeVisible(); + await expect( + editor.canvas.getByRole( 'document', { + name: 'Block: Title', + } ) + ).toBeVisible(); + + // Toggle template preview to "off". + const templateOptionsButton = page + .getByRole( 'region', { name: 'Editor settings' } ) + .getByRole( 'button', { name: 'Template options' } ); + await templateOptionsButton.click(); + const templatePreviewButton = page + .getByRole( 'menu', { name: 'Template options' } ) + .getByRole( 'menuitem', { name: 'Template preview' } ); + + await expect( templatePreviewButton ).toHaveAttribute( + 'aria-pressed', + 'true' + ); + await templatePreviewButton.click(); + await expect( templatePreviewButton ).toHaveAttribute( + 'aria-pressed', + 'false' + ); + + // Header template area should be hidden. + await expect( + editor.canvas.getByRole( 'document', { + name: 'Block: header', + } ) + ).toBeHidden(); + + // Content block is still visible and wrapped in a container. + const paragraphsInGroup = editor.canvas + .getByRole( 'document', { + name: 'Block: Group', + } ) + .getByRole( 'document', { + name: 'Block: Content', + } ) + .getByText( 'Sweet paragraph ' ); + + await expect( paragraphsInGroup.nth( 0 ) ).toBeVisible(); + await expect( paragraphsInGroup.nth( 1 ) ).toBeVisible(); + // Check order of paragraphs. + // Important to ensure the blocks are rendered as they are in the template. + await expect( paragraphsInGroup.nth( 0 ) ).toHaveText( + 'Sweet paragraph 1' + ); + await expect( paragraphsInGroup.nth( 1 ) ).toHaveText( + 'Sweet paragraph 2' + ); + await expect( + editor.canvas + .getByRole( 'document', { + name: 'Block: Group', + } ) + .getByRole( 'document', { + name: 'Block: Title', + } ) + ).toBeVisible(); + + // Remove focus from templateOptionsButton button. + await editor.canvas.locator( 'body' ).click(); + + // Toggle template preview to "on". + await templateOptionsButton.click(); + await templatePreviewButton.click(); + await expect( templatePreviewButton ).toHaveAttribute( + 'aria-pressed', + 'true' + ); + + // Header template area and page content are once again visible. + await expect( + editor.canvas.getByRole( 'document', { + name: 'Block: header', + } ) + ).toBeVisible(); + await expect( paragraphs.nth( 0 ) ).toBeVisible(); + await expect( paragraphs.nth( 1 ) ).toBeVisible(); + await expect( + editor.canvas.getByRole( 'document', { + name: 'Block: Title', + } ) + ).toBeVisible(); + } ); + test( 'swap template and reset to default', async ( { admin, page, @@ -195,6 +317,7 @@ test.describe( 'Pages', () => { await resetButton.click(); await expect( templateOptionsButton ).toHaveText( 'Single Entries' ); } ); + test( 'swap template options should respect the declared `postTypes`', async ( { page, editor, diff --git a/test/integration/fixtures/blocks/core__form-input.json b/test/integration/fixtures/blocks/core__form-input.json index 33802bbcc2088..68dfb9a36e4e6 100644 --- a/test/integration/fixtures/blocks/core__form-input.json +++ b/test/integration/fixtures/blocks/core__form-input.json @@ -5,7 +5,7 @@ "attributes": { "originalName": "core/form-input", "originalUndelimitedContent": "", - "originalContent": "\n\n" + "originalContent": "\n\n" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__form-input.serialized.html b/test/integration/fixtures/blocks/core__form-input.serialized.html index 4e1f6b77998de..718c592641bc3 100644 --- a/test/integration/fixtures/blocks/core__form-input.serialized.html +++ b/test/integration/fixtures/blocks/core__form-input.serialized.html @@ -1,3 +1,3 @@ - + diff --git a/test/integration/fixtures/blocks/core__form.json b/test/integration/fixtures/blocks/core__form.json index ba07b17e4d00c..6bad568b12c26 100644 --- a/test/integration/fixtures/blocks/core__form.json +++ b/test/integration/fixtures/blocks/core__form.json @@ -5,7 +5,7 @@ "attributes": { "originalName": "core/form", "originalUndelimitedContent": "
\n\n\n\n\n
\n
", - "originalContent": "\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n
\n\n
\n" + "originalContent": "\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n
\n\n
\n" }, "innerBlocks": [ { @@ -14,7 +14,7 @@ "attributes": { "originalName": "core/form-input", "originalUndelimitedContent": "", - "originalContent": "\n\n" + "originalContent": "\n\n" }, "innerBlocks": [] }, @@ -24,7 +24,7 @@ "attributes": { "originalName": "core/form-input", "originalUndelimitedContent": "", - "originalContent": "\n\n" + "originalContent": "\n\n" }, "innerBlocks": [] }, @@ -34,7 +34,7 @@ "attributes": { "originalName": "core/form-input", "originalUndelimitedContent": "", - "originalContent": "\n\n" + "originalContent": "\n\n" }, "innerBlocks": [] }, @@ -44,7 +44,7 @@ "attributes": { "originalName": "core/form-input", "originalUndelimitedContent": "", - "originalContent": "\n\n" + "originalContent": "\n\n" }, "innerBlocks": [] }, diff --git a/test/integration/fixtures/blocks/core__form.serialized.html b/test/integration/fixtures/blocks/core__form.serialized.html index 58a2a49967eb5..585a50868b85e 100644 --- a/test/integration/fixtures/blocks/core__form.serialized.html +++ b/test/integration/fixtures/blocks/core__form.serialized.html @@ -1,16 +1,16 @@
- + - + - + - +