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 (
+
+ );
+}
+
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": "Name ",
- "originalContent": "\nName \n"
+ "originalContent": "\nName \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 @@
-Name
+Name
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": "",
- "originalContent": "\n\n\nName \n\n\nEmail \n\n\nWebsite \n\n\nComment \n\n\n\n\n \n"
+ "originalContent": "\n\n\nName \n\n\nEmail \n\n\nWebsite \n\n\nComment \n\n\n\n\n \n"
},
"innerBlocks": [
{
@@ -14,7 +14,7 @@
"attributes": {
"originalName": "core/form-input",
"originalUndelimitedContent": "Name ",
- "originalContent": "\nName \n"
+ "originalContent": "\nName \n"
},
"innerBlocks": []
},
@@ -24,7 +24,7 @@
"attributes": {
"originalName": "core/form-input",
"originalUndelimitedContent": "Email ",
- "originalContent": "\nEmail \n"
+ "originalContent": "\nEmail \n"
},
"innerBlocks": []
},
@@ -34,7 +34,7 @@
"attributes": {
"originalName": "core/form-input",
"originalUndelimitedContent": "Website ",
- "originalContent": "\nWebsite \n"
+ "originalContent": "\nWebsite \n"
},
"innerBlocks": []
},
@@ -44,7 +44,7 @@
"attributes": {
"originalName": "core/form-input",
"originalUndelimitedContent": "Comment ",
- "originalContent": "\nComment \n"
+ "originalContent": "\nComment \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 @@
-Name
+Name
-Email
+Email
-Website
+Website
-Comment
+Comment