From e2204eab98ba2a1e9067991cb212a3ca1acbf7e8 Mon Sep 17 00:00:00 2001 From: Birgit Pauli-Haack Date: Mon, 13 Nov 2023 17:02:46 +0100 Subject: [PATCH 001/116] corrected + updated links (#56084) changed two links in create block scaffolding tool documentation props to @juanmaguitar for review --- packages/create-block/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/create-block/README.md b/packages/create-block/README.md index 88ac97c34c2cf7..51c36ca91b0145 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-tutorial-template/) for information on External Project Templates ## Contributing to this package From 8ecddc93c5ec438c8cf18419a5f4ec0d5b68474f Mon Sep 17 00:00:00 2001 From: Nick Diego Date: Mon, 13 Nov 2023 10:16:53 -0600 Subject: [PATCH 002/116] Add new block development "Quick Start Guide" and update the `create-block-tutorial-template` (#56056) * Add the new quick start guide. * Update the create-block tutorial template to work with the new quick start guide. * Remove the quick start guide from the create block tutorial. * Add back ABSPATH check. * Revert change to package version number. * Update readme. * Remove @wordpress/icons dependency and add custom icon. * Fix title in manifest. * Fix heading in Quick Start Guide. --- docs/getting-started/create-block/README.md | 18 ---- docs/getting-started/quick-start-guide.md | 44 ++++++++ docs/manifest.json | 6 ++ docs/toc.json | 1 + .../CHANGELOG.md | 4 + .../create-block-tutorial-template/README.md | 4 +- .../assets/gilbert-color.otf | Bin 626352 -> 0 bytes .../block-templates/edit.js.mustache | 95 +++++++++++++++--- .../block-templates/editor.scss.mustache | 13 --- .../block-templates/index.js.mustache | 40 +++----- .../block-templates/render.php.mustache | 35 +++++-- .../block-templates/save.js.mustache | 24 ++++- .../block-templates/style.scss.mustache | 17 ---- .../create-block-tutorial-template/index.js | 40 ++++---- .../package.json | 7 +- .../plugin-templates/$slug.php.mustache | 6 +- .../plugin-templates/readme.txt.mustache | 2 +- 17 files changed, 233 insertions(+), 123 deletions(-) create mode 100644 docs/getting-started/quick-start-guide.md delete mode 100644 packages/create-block-tutorial-template/assets/gilbert-color.otf delete mode 100644 packages/create-block-tutorial-template/block-templates/editor.scss.mustache delete mode 100644 packages/create-block-tutorial-template/block-templates/style.scss.mustache diff --git a/docs/getting-started/create-block/README.md b/docs/getting-started/create-block/README.md index 2b87f09f1f903c..22a28560c76a81 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 00000000000000..4ad3998e7c27d3 --- /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 bc4d8bd7c3b28d..ba345e7716ee37 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 cbabf3d3b737c6..8a29d2d4f10aff 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/packages/create-block-tutorial-template/CHANGELOG.md b/packages/create-block-tutorial-template/CHANGELOG.md index d395b408d86c56..20f2a56d366431 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 a4143312948e50..f883ff5fb79d47 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 f21f9a173f2fe0b53a02723ce7fae62fca7cb897..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 626352 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 { + 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 5d0b2deea6c10e..00000000000000 --- 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 fa35fbf2729220..117d08b8669807 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 b971a023985e55..1d31cdbed2836b 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 a11ee432a4d442..944ae4c29254c4 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 b1f1241345cbb9..00000000000000 --- 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 514918e70ad8b9..12c073d841fe55 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 5fd4d71fd4cd8c..33eb73835bfaee 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 52c9c4966646fa..6de24df94c8d83 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 f069906fb19fa5..d2b31bed6c0e60 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}} From 901dc7de57974179aa95382e52aab0a736eded5a Mon Sep 17 00:00:00 2001 From: Artemio Morales Date: Mon, 13 Nov 2023 18:12:43 +0100 Subject: [PATCH 003/116] Add check for lightbox values during image block migration (#56057) --- packages/block-library/src/image/deprecated.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/block-library/src/image/deprecated.js b/packages/block-library/src/image/deprecated.js index 4205da8e117b91..0365ddcfff5d17 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 }, From f803a8f718e3c3ba8e11820b0d1a9dc515609cce Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Tue, 14 Nov 2023 01:27:18 +0800 Subject: [PATCH 004/116] Remove extraneous template part title in replace control (#55603) --- .../block-library/src/template-part/edit/index.js | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/packages/block-library/src/template-part/edit/index.js b/packages/block-library/src/template-part/edit/index.js index 64c8db5e3bc151..4152280bf73362 100644 --- a/packages/block-library/src/template-part/edit/index.js +++ b/packages/block-library/src/template-part/edit/index.js @@ -4,7 +4,6 @@ import { useSelect } from '@wordpress/data'; import { BlockSettingsMenuControls, - BlockTitle, useBlockProps, Warning, store as blockEditorStore, @@ -14,7 +13,7 @@ import { import { Spinner, Modal, MenuItem } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; import { store as coreStore } from '@wordpress/core-data'; -import { useState, createInterpolateElement } from '@wordpress/element'; +import { useState } from '@wordpress/element'; /** * Internal dependencies @@ -174,17 +173,7 @@ export default function TemplatePartEdit( { } aria-haspopup="dialog" > - { createInterpolateElement( - __( 'Replace ' ), - { - BlockTitle: ( - - ), - } - ) } + { __( 'Replace' ) } ); } } From 3c17bb21753e72fab52021e7926a9d440e95f942 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Nov 2023 13:33:39 -0500 Subject: [PATCH 005/116] Bump shivammathur/setup-php from 2.26.0 to 2.27.1 (#55930) Bumps [shivammathur/setup-php](https://github.com/shivammathur/setup-php) from 2.26.0 to 2.27.1. - [Release notes](https://github.com/shivammathur/setup-php/releases) - [Commits](https://github.com/shivammathur/setup-php/compare/7fdd3ece872ec7ec4c098ae5ab7637d5e0a96067...a36e1e52ff4a1c9e9c9be31551ee4712a6cb6bd0) --- updated-dependencies: - dependency-name: shivammathur/setup-php dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/unit-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 39f7caf6f806e7..65ba01d0b70e89 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -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 @@ -226,7 +226,7 @@ jobs: 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 From ec688be162096eb059038b8333ab21e696318e75 Mon Sep 17 00:00:00 2001 From: Rich Tabor Date: Mon, 13 Nov 2023 14:26:43 -0500 Subject: [PATCH 006/116] Another round of __next40pxDefaultSize controls (#56022) * ReusableBlockEdit * __next40pxDefaultSize for block-library * __next40pxDefaultSize for PageAttributesOrder --- packages/block-editor/src/hooks/anchor.js | 1 + packages/block-editor/src/hooks/block-rename-ui.js | 2 ++ packages/block-editor/src/hooks/custom-class-name.js | 1 + packages/block-library/src/block/edit.js | 3 ++- .../src/comments/edit/comments-inspector-controls.js | 1 + packages/block-library/src/cover/edit/inspector-controls.js | 1 + packages/block-library/src/group/edit.js | 1 + packages/block-library/src/query/edit/query-content.js | 1 + .../block-library/src/template-part/edit/advanced-controls.js | 1 + packages/editor/src/components/page-attributes/order.js | 1 + 10 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/hooks/anchor.js b/packages/block-editor/src/hooks/anchor.js index 7a8f507d9674e0..3d404c4a868116 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 = ( 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 5dd7afab431ce7..1a33cb68ea38a6 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 3ed0ae872f9337..38757f90c2deec 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/group/edit.js b/packages/block-library/src/group/edit.js index 4d5354eff0180f..277fa6872fa82e 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/query/edit/query-content.js b/packages/block-library/src/query/edit/query-content.js index 6fef2c43b4affc..4d9b8885cb15ea 100644 --- a/packages/block-library/src/query/edit/query-content.js +++ b/packages/block-library/src/query/edit/query-content.js @@ -131,6 +131,7 @@ export default function QueryContent( { )' ), 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 b879b46638face..8ad4b4bdbeb1da 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( { ) } Date: Tue, 14 Nov 2023 04:47:30 +0900 Subject: [PATCH 007/116] Light box: Fix button misalignment in gallery image (#56060) --- packages/block-library/src/image/view.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/block-library/src/image/view.js b/packages/block-library/src/image/view.js index 30967a2de92c3d..ef46e932d2490b 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; From 4d3b14823b8f4751badfdca432a57113b0d2c0fb Mon Sep 17 00:00:00 2001 From: Dean Sas Date: Mon, 13 Nov 2023 22:49:53 +0000 Subject: [PATCH 008/116] Process embeds inside patterns (#55979) Embed blocks inside patterns were not being processed when viewing a site. This focused change addresses that issue. --- packages/block-library/src/pattern/index.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/pattern/index.php b/packages/block-library/src/pattern/index.php index f05bb333bd186d..436452f6853001 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' ); From f927f2d348be9e23739496ff69c49b1fae2cfa7b Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Tue, 14 Nov 2023 09:53:07 +1100 Subject: [PATCH 009/116] List View: Add keyboard shortcut to select all blocks (#54899) * List View: Try adding keyboard shortcut to select all blocks * Move up each leve of the hierarchy incrementally * Fix bug if focused on a different part of the list view from the block selection * Add e2e tests * Simplify e2e tests * Clarify the group block state a little more in the e2e test --- .../list-view/block-select-button.js | 45 ++++++- .../src/components/list-view/index.js | 2 + .../specs/editor/various/list-view.spec.js | 112 +++++++++++++++++- 3 files changed, 157 insertions(+), 2 deletions(-) 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 cec5d4699c7a2f..25de5483f5192e 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 1d21c28643a73c..315a6153839d16 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/test/e2e/specs/editor/various/list-view.spec.js b/test/e2e/specs/editor/various/list-view.spec.js index 222d743acdf395..f05b7760c4cc7a 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 From d27ffba8c58f0f975e80c48b1dcba1e5816663a5 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Tue, 14 Nov 2023 09:43:52 +0400 Subject: [PATCH 010/116] Fix flaky 'Meta boxes' e2e tests (#56083) * Fix flaky 'Meta boxes' e2e tests * Just swap the expected text order --- test/e2e/specs/editor/plugins/meta-boxes.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/specs/editor/plugins/meta-boxes.spec.js b/test/e2e/specs/editor/plugins/meta-boxes.spec.js index b901201ff6c1de..5999dc07aeafe0 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 ( { From b09e9bd32c4bd8740833d7b15ca814ce3c7c1608 Mon Sep 17 00:00:00 2001 From: Ramon Date: Tue, 14 Nov 2023 17:51:25 +1100 Subject: [PATCH 011/116] Site editor template preview: add E2E test and aria-pressed attribute to template preview toggle (#56096) * This PR adds a follow up E2E test for https://github.com/WordPress/gutenberg/pull/52674 It also adds an aria label to the edit template button to indicate its state (pressed or not pressed). * Refactor test to account for order of page content blocks * remove saving from tests. unnecessary to the test --- .../page-panels/edit-template.js | 1 + .../sidebar-edit-mode/page-panels/style.scss | 6 + test/e2e/specs/site-editor/pages.spec.js | 123 ++++++++++++++++++ 3 files changed, 130 insertions(+) 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 8067453a518217..fde2b63d6e8330 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 e1a8e4acb72273..64d72db4e15fd7 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/test/e2e/specs/site-editor/pages.spec.js b/test/e2e/specs/site-editor/pages.spec.js index d1f32b9f209d75..8008109be15eee 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, From 0ee99bb1af39d9a6585d23a6db842ec42339c7d6 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Tue, 14 Nov 2023 10:09:51 +0000 Subject: [PATCH 012/116] Update: DataViews add rename functionality to custom views. (#55997) --- .../custom-dataviews-list.js | 165 +++++++++++++----- 1 file changed, 122 insertions(+), 43 deletions(-) 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 f11c63653205fa..12659a36bbf9b8 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/custom-dataviews-list.js +++ b/packages/edit-site/src/components/sidebar-dataviews/custom-dataviews-list.js @@ -9,8 +9,13 @@ import { DropdownMenu, MenuGroup, MenuItem, + TextControl, + __experimentalHStack as HStack, + __experimentalVStack as VStack, + Button, + Modal, } from '@wordpress/components'; -import { useMemo } from '@wordpress/element'; +import { useMemo, useState } from '@wordpress/element'; import { moreVertical } from '@wordpress/icons'; import { __ } from '@wordpress/i18n'; import { privateApis as routerPrivateApis } from '@wordpress/router'; @@ -26,6 +31,55 @@ const { useHistory, useLocation } = unlock( routerPrivateApis ); const EMPTY_ARRAY = []; +function RenameItemModalContent( { dataviewId, currentTitle, setIsRenaming } ) { + const { editEntityRecord } = useDispatch( coreStore ); + const [ title, setTitle ] = useState( currentTitle ); + return ( +
{ + event.preventDefault(); + await editEntityRecord( + 'postType', + 'wp_dataviews', + dataviewId, + { + title, + } + ); + setIsRenaming( false ); + } } + > + + + + + + + +
+ ); +} + function CustomDataViewItem( { dataviewId, isActive } ) { const { params: { path }, @@ -49,51 +103,76 @@ function CustomDataViewItem( { dataviewId, isActive } ) { const viewContent = JSON.parse( dataview.content ); return viewContent.type; }, [ dataview.content ] ); + const [ isRenaming, setIsRenaming ] = useState( false ); return ( - + + { ( { onClose } ) => ( + + { + setIsRenaming( true ); + onClose(); + } } + > + { __( 'Rename' ) } + + { + await deleteEntityRecord( + 'postType', + 'wp_dataviews', + dataview.id, + { + force: true, + } + ); + if ( isActive ) { + history.replace( { + path, + } ); + } + onClose(); + } } + isDestructive + > + { __( 'Delete' ) } + + + ) } + + } + /> + { isRenaming && ( + { + setIsRenaming( false ); } } > - { ( { onClose } ) => ( - - { - await deleteEntityRecord( - 'postType', - 'wp_dataviews', - dataview.id, - { - force: true, - } - ); - if ( isActive ) { - history.replace( { - path, - } ); - } - onClose(); - } } - isDestructive - > - { __( 'Delete' ) } - - - ) } - - } - /> + + + ) } + ); } From 8c29767d60f450d581f6f31ab17a525b57114a53 Mon Sep 17 00:00:00 2001 From: Birgit Pauli-Haack Date: Tue, 14 Nov 2023 11:22:03 +0100 Subject: [PATCH 013/116] fixes wrong link in #56084 (#56106) props to @gziolo for review --- packages/create-block/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/create-block/README.md b/packages/create-block/README.md index 51c36ca91b0145..20bb6c62ccf66c 100644 --- a/packages/create-block/README.md +++ b/packages/create-block/README.md @@ -141,7 +141,7 @@ For example, running the `start` script from inside the generated folder (`npm s ## External Project Templates -[Click here](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-create-block-tutorial-template/) 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 From 560c38df911672b5802d60dab0fc099096fc80a0 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Tue, 14 Nov 2023 11:25:41 +0100 Subject: [PATCH 014/116] SiteEditor: Optimize BackToPageNotification component (#56102) --- .../back-to-page-notification.js | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) 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 a2990c56a673cf..9bf9ac33b1d198 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, From 71a6fb60994e252a5675bdc8d32c3dcda5287da6 Mon Sep 17 00:00:00 2001 From: Ella <4710635+ellatrix@users.noreply.github.com> Date: Tue, 14 Nov 2023 12:59:25 +0200 Subject: [PATCH 015/116] Rich text: highlight format: gracefully handle old span format (#56071) --- .../format-library/src/text-color/index.js | 18 --------- .../src/text-color/index.native.js | 22 ----------- packages/rich-text/src/component/index.js | 38 ------------------- packages/rich-text/src/create.js | 8 ---- 4 files changed, 86 deletions(-) diff --git a/packages/format-library/src/text-color/index.js b/packages/format-library/src/text-color/index.js index 630431dc50fa0e..8a28cb69549cdc 100644 --- a/packages/format-library/src/text-color/index.js +++ b/packages/format-library/src/text-color/index.js @@ -135,23 +135,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 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 21db4c2a444f30..7c44e4efc001aa 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/rich-text/src/component/index.js b/packages/rich-text/src/component/index.js index 17cf17e2e3154c..87e57e49e4333e 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 63aac8c076b8b8..a23baf70078bc9 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 ]; From b04f4d35358d418bc2316c09fb655091f842e54a Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Tue, 14 Nov 2023 15:43:59 +0400 Subject: [PATCH 016/116] Block Editor: Optimize 'Block Hooks' inspector controls (#56101) --- packages/block-editor/src/hooks/block-hooks.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/hooks/block-hooks.js b/packages/block-editor/src/hooks/block-hooks.js index fc08090b49889c..0d75999192e5bf 100644 --- a/packages/block-editor/src/hooks/block-hooks.js +++ b/packages/block-editor/src/hooks/block-hooks.js @@ -238,14 +238,15 @@ function BlockHooksControl( props ) { export const withBlockHooksControls = createHigherOrderComponent( ( BlockEdit ) => { return ( props ) => { - const blockEdit = ; return ( <> - { blockEdit } - + + { props.isSelected && ( + + ) } ); }; From 4d7b66f02e02b766c5756e7bc3ece73a157ae397 Mon Sep 17 00:00:00 2001 From: Ella <4710635+ellatrix@users.noreply.github.com> Date: Tue, 14 Nov 2023 14:18:30 +0200 Subject: [PATCH 017/116] Block lib: remove multiline=false (deprecated) (#56113) --- packages/block-library/src/details/edit.js | 1 - packages/block-library/src/post-author/edit.js | 1 - packages/block-library/src/post-terms/edit.js | 2 -- 3 files changed, 4 deletions(-) diff --git a/packages/block-library/src/details/edit.js b/packages/block-library/src/details/edit.js index 81e4d7a52056a7..0d1d675893900f 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/post-author/edit.js b/packages/block-library/src/post-author/edit.js index 4ee353fdd9bdc0..05797fcc8250a1 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 ) && ( Date: Tue, 14 Nov 2023 13:30:10 +0100 Subject: [PATCH 018/116] DataViews: add 10 as a new page size option (#56112) --- packages/edit-site/src/components/dataviews/view-actions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/dataviews/view-actions.js b/packages/edit-site/src/components/dataviews/view-actions.js index 5f808e99beeae0..e1e85a3e56d09f 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 ( Date: Tue, 14 Nov 2023 14:19:02 +0100 Subject: [PATCH 019/116] Template Part: Add fallback to the current theme when not provided (#55965) --- .../src/navigation/use-template-part-area-label.js | 6 ++++-- packages/block-library/src/pattern/edit.js | 3 ++- packages/block-library/src/template-part/edit/index.js | 6 +++++- packages/block-library/src/template-part/index.js | 5 +++-- packages/block-library/src/template-part/variations.js | 6 ++++-- packages/edit-site/src/hooks/template-part-edit.js | 6 ++++-- 6 files changed, 22 insertions(+), 10 deletions(-) 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 91838b268b47d6..48763a38ac62d1 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 43d78755304814..5fd1b427a5e3e9 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/template-part/edit/index.js b/packages/block-library/src/template-part/edit/index.js index 4152280bf73362..163dfa5403ce61 100644 --- a/packages/block-library/src/template-part/edit/index.js +++ b/packages/block-library/src/template-part/edit/index.js @@ -34,7 +34,11 @@ export default function TemplatePartEdit( { setAttributes, clientId, } ) { - const { slug, theme, tagName, layout = {} } = attributes; + const currentTheme = useSelect( + ( select ) => select( coreStore ).getCurrentTheme()?.stylesheet, + [] + ); + const { slug, theme = currentTheme, tagName, layout = {} } = attributes; const templatePartId = createTemplatePartId( theme, slug ); const hasAlreadyRendered = useHasRecursion( templatePartId ); const [ isTemplatePartSelectionOpen, setIsTemplatePartSelectionOpen ] = diff --git a/packages/block-library/src/template-part/index.js b/packages/block-library/src/template-part/index.js index a68dd2301be22c..c9b5e33a1c9598 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 866cf15d56c125..79881ee5f89e4c 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/edit-site/src/hooks/template-part-edit.js b/packages/edit-site/src/hooks/template-part-edit.js index 66f54967c55e22..0b14bbbbd77121 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 ] From f137d97936cac3a0095019fa3eafeef1467c98a9 Mon Sep 17 00:00:00 2001 From: Ella <4710635+ellatrix@users.noreply.github.com> Date: Tue, 14 Nov 2023 16:06:01 +0200 Subject: [PATCH 020/116] Missing block: use raw source for originalContent (#56014) --- packages/block-library/src/missing/block.json | 2 +- test/integration/fixtures/blocks/core__form-input.json | 2 +- .../fixtures/blocks/core__form-input.serialized.html | 2 +- test/integration/fixtures/blocks/core__form.json | 10 +++++----- .../fixtures/blocks/core__form.serialized.html | 8 ++++---- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/block-library/src/missing/block.json b/packages/block-library/src/missing/block.json index 0bc512bbbf709d..242a1d2c6b21a8 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/test/integration/fixtures/blocks/core__form-input.json b/test/integration/fixtures/blocks/core__form-input.json index 33802bbcc2088d..68dfb9a36e4e63 100644 --- a/test/integration/fixtures/blocks/core__form-input.json +++ b/test/integration/fixtures/blocks/core__form-input.json @@ -5,7 +5,7 @@ "attributes": { "originalName": "core/form-input", "originalUndelimitedContent": "", - "originalContent": "\n\n" + "originalContent": "\n\n" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__form-input.serialized.html b/test/integration/fixtures/blocks/core__form-input.serialized.html index 4e1f6b77998de9..718c592641bc32 100644 --- a/test/integration/fixtures/blocks/core__form-input.serialized.html +++ b/test/integration/fixtures/blocks/core__form-input.serialized.html @@ -1,3 +1,3 @@ - + diff --git a/test/integration/fixtures/blocks/core__form.json b/test/integration/fixtures/blocks/core__form.json index ba07b17e4d00c6..6bad568b12c26d 100644 --- a/test/integration/fixtures/blocks/core__form.json +++ b/test/integration/fixtures/blocks/core__form.json @@ -5,7 +5,7 @@ "attributes": { "originalName": "core/form", "originalUndelimitedContent": "
\n\n\n\n\n
\n
", - "originalContent": "\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n
\n\n
\n" + "originalContent": "\n
\n\n\n\n\n\n\n\n\n\n\n\n\n\n
\n\n
\n" }, "innerBlocks": [ { @@ -14,7 +14,7 @@ "attributes": { "originalName": "core/form-input", "originalUndelimitedContent": "", - "originalContent": "\n\n" + "originalContent": "\n\n" }, "innerBlocks": [] }, @@ -24,7 +24,7 @@ "attributes": { "originalName": "core/form-input", "originalUndelimitedContent": "", - "originalContent": "\n\n" + "originalContent": "\n\n" }, "innerBlocks": [] }, @@ -34,7 +34,7 @@ "attributes": { "originalName": "core/form-input", "originalUndelimitedContent": "", - "originalContent": "\n\n" + "originalContent": "\n\n" }, "innerBlocks": [] }, @@ -44,7 +44,7 @@ "attributes": { "originalName": "core/form-input", "originalUndelimitedContent": "", - "originalContent": "\n\n" + "originalContent": "\n\n" }, "innerBlocks": [] }, diff --git a/test/integration/fixtures/blocks/core__form.serialized.html b/test/integration/fixtures/blocks/core__form.serialized.html index 58a2a49967eb56..585a50868b85e0 100644 --- a/test/integration/fixtures/blocks/core__form.serialized.html +++ b/test/integration/fixtures/blocks/core__form.serialized.html @@ -1,16 +1,16 @@
- + - + - + - +
From 5bcb30933846450ed25b3c9d0da39ccc95307b54 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Tue, 14 Nov 2023 14:59:28 +0000 Subject: [PATCH 021/116] Fix: Nested button tags on dataviews sidebar. (#56089) * Fix: Nested button tags on dataviews sidebar. * Fix lint issue --- .../sidebar-dataviews/dataview-item.js | 30 ++++++++++++++----- .../components/sidebar-dataviews/style.scss | 14 +++++++++ 2 files changed, 37 insertions(+), 7 deletions(-) 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 fdd3272fbc24a6..c6d7bbe4a231ba 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 3e8812267b076d..526670ee1e5627 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; + } +} From 065188feb9200558e3ede4557c3acf7072114154 Mon Sep 17 00:00:00 2001 From: Marin Atanasov <8436925+tyxla@users.noreply.github.com> Date: Wed, 15 Nov 2023 00:27:26 +0300 Subject: [PATCH 022/116] Block Editor: Optimize BlockListAppender (#56116) --- .../components/block-list-appender/index.js | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) 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 7b37b93d8be8d1..68f36f7dd25058 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( From c64d93b59162f0757fe64c87837884c1c06c8cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Santiago=20Cerro=20L=C3=B3pez?= Date: Tue, 14 Nov 2023 22:35:16 +0100 Subject: [PATCH 023/116] Styles: More descriptive text for revisions timeline (#55868) * Styles: More descriptive text for revisions timeline Fixes https://github.com/WordPress/gutenberg/issues/55648 * Add more descriptive text * Replace by suggested text Co-authored-by: Ramon * Update packages/edit-site/src/components/global-styles/screen-revisions/index.js --------- Co-authored-by: Ramon --- .../src/components/global-styles/screen-revisions/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/global-styles/screen-revisions/index.js b/packages/edit-site/src/components/global-styles/screen-revisions/index.js index ca580edd12a2fa..d5c884f9d20cfe 100644 --- a/packages/edit-site/src/components/global-styles/screen-revisions/index.js +++ b/packages/edit-site/src/components/global-styles/screen-revisions/index.js @@ -121,7 +121,7 @@ function ScreenRevisions() { { isLoading && ( From 8850bfbf93c0683dfb0d20d884ee41aa4f48d456 Mon Sep 17 00:00:00 2001 From: Ramon Date: Wed, 15 Nov 2023 08:40:29 +1100 Subject: [PATCH 024/116] Download blob: remove downloadjs dependency (#56024) * Create a new function in the blob package: downloadBlob Removes downloadjs dependency Adds tests * Use new function in reusable blocks package Whoops * Update package json deps * - fileName var all to lower case - changed a var to anchorElement - regenerate docs * Removing HTMLElement return value and updating tests Updated docs * Updated test description * Set a default value of `''` for contentType, which matches the Web API spec for Blob Updates tests --- package-lock.json | 16 ++--- packages/blob/CHANGELOG.md | 4 ++ packages/blob/README.md | 25 ++++++++ packages/blob/src/index.js | 40 +++++++++++++ packages/blob/src/test/index.js | 59 ++++++++++++++++++- packages/edit-site/package.json | 2 +- .../header-edit-mode/more-menu/site-export.js | 8 +-- .../src/components/page-patterns/grid-item.js | 22 +------ packages/list-reusable-blocks/package.json | 1 + .../list-reusable-blocks/src/utils/export.js | 4 +- .../list-reusable-blocks/src/utils/file.js | 26 -------- 11 files changed, 139 insertions(+), 68 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9439981c29d7dc..8a548f1e830312 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25835,11 +25835,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", @@ -55321,6 +55316,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 +55357,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 +55887,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", @@ -70398,6 +70394,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 +70435,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 +70781,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", @@ -76857,11 +76854,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", diff --git a/packages/blob/CHANGELOG.md b/packages/blob/CHANGELOG.md index 8d88b3cc4062a3..680d53971c018d 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 0305c4784d6cbd..ff28e8879602f3 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 496869703d2dac..edc2e43729a23f 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 4e59917522b519..47dcb5019ee25e 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/edit-site/package.json b/packages/edit-site/package.json index 03d1ea851ff9a8..d7007e1d88fece 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/header-edit-mode/more-menu/site-export.js b/packages/edit-site/src/components/header-edit-mode/more-menu/site-export.js index ec9492081a42b3..85ec4f0dd7335e 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-patterns/grid-item.js b/packages/edit-site/src/components/page-patterns/grid-item.js index 64b70fb87de62d..b394ef8eb6e76c 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/list-reusable-blocks/package.json b/packages/list-reusable-blocks/package.json index b004d5fe803eea..9cc27c6911a91c 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 4075c7576f1340..4d7e76afcaa8fd 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 f4cff155c591fb..d31e54ae41896a 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. * From db508a2b74133cbcf8ba9260484ce7133f3b4a58 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Wed, 15 Nov 2023 08:51:19 +1100 Subject: [PATCH 025/116] Iframe: Bubble events from html element instead of body element to fix drag chip positioning (#56099) --- packages/block-editor/src/components/iframe/index.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/iframe/index.js b/packages/block-editor/src/components/iframe/index.js index 28697324aa8b83..1939f75811c8c5 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 ] ); } }; } ); From c131cd00872b05fe067c6bd95326a3ca84ff066e Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 15 Nov 2023 09:36:52 +0400 Subject: [PATCH 026/116] Disable 'no-conditional-in-test' ESLint rule for Playwright (#56088) --- .eslintrc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintrc.js b/.eslintrc.js index 8a44b5ef74a1e6..122ec45369c224 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', From a042badf8baf5bf7cbf3af84a9cfb27fb10a1192 Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Wed, 15 Nov 2023 15:01:49 +0900 Subject: [PATCH 027/116] Post Featured Image: Handling correctly when uploading a file without mime type (#56133) --- packages/editor/src/components/post-featured-image/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/editor/src/components/post-featured-image/index.js b/packages/editor/src/components/post-featured-image/index.js index 9304115b0b7f11..96eb164696228f 100644 --- a/packages/editor/src/components/post-featured-image/index.js +++ b/packages/editor/src/components/post-featured-image/index.js @@ -115,7 +115,9 @@ function PostFeaturedImage( { setIsLoading( true ); return; } - onUpdateImage( image ); + if ( image ) { + onUpdateImage( image ); + } setIsLoading( false ); }, onError( message ) { From 52e9eb2950647c2439d4365fcae867dc01ea0b15 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 15 Nov 2023 08:09:25 +0100 Subject: [PATCH 028/116] SiteEditor: Refactor disable non page content blocks (#56103) Co-authored-by: Kai Hao --- .../disable-non-page-content-blocks.js | 71 ++++++++++--------- 1 file changed, 38 insertions(+), 33 deletions(-) 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 f3e021ba885244..2f81f80d0ce63d 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 ; + } ); +} From 1d1abd2505b75715fabcf3914b98857f4239c8ce Mon Sep 17 00:00:00 2001 From: Brad Jorsch Date: Wed, 15 Nov 2023 03:54:19 -0500 Subject: [PATCH 029/116] Package `@ariakit/test` should be a dev dependency (#56091) * Package `@ariakit/test` should be a dev dependency In #54939 a new test was added that depends on `@ariakit/test`. But, even though that package is not needed in the production code, it was (accidentally?) added to `dependencies` instead of `devDependencies`. This means everyone using `@wordpress/components` winds up having to install this package. Let's move it to devDependencies where it belongs. * Add PR link to changelog * Remove extraneous `.` --- package-lock.json | 169 ++++++++++++++++++++++++++----- package.json | 1 + packages/components/CHANGELOG.md | 4 + packages/components/package.json | 1 - 4 files changed, 149 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8a548f1e830312..28f51a1408f64d 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", @@ -26305,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", @@ -26323,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", @@ -28711,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" } @@ -29097,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" } @@ -29330,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", @@ -29820,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" }, @@ -29981,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" } @@ -29997,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" }, @@ -30008,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" }, @@ -30019,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" }, @@ -30030,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" }, @@ -31203,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", @@ -31332,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" @@ -31347,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", @@ -31365,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" }, @@ -31388,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" @@ -31423,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" }, @@ -31485,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" }, @@ -31678,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" } @@ -31725,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" }, @@ -31835,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" @@ -31859,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" } @@ -31867,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" }, @@ -31895,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" }, @@ -31909,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" }, @@ -31935,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" }, @@ -31966,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" } @@ -31986,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" @@ -36650,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" } @@ -41602,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" } @@ -41610,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" @@ -41625,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" } @@ -41644,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", @@ -46379,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", @@ -48142,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", @@ -48978,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" }, @@ -53616,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", @@ -53631,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", @@ -53650,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", @@ -54781,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", @@ -57742,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": { @@ -67420,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", @@ -67434,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" } @@ -67448,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", @@ -67472,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", @@ -67487,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 } } }, @@ -67642,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", @@ -70019,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", @@ -72279,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" @@ -72544,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", @@ -73678,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" @@ -76289,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" @@ -76734,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", @@ -77239,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", @@ -77254,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 } } }, @@ -79087,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" } @@ -79386,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", @@ -79565,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", @@ -79948,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" } @@ -80077,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", @@ -80088,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" } @@ -80095,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" } @@ -80988,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", @@ -81090,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" @@ -81099,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", @@ -81114,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" } @@ -81131,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" @@ -81153,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", @@ -81202,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" } @@ -81329,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", @@ -81369,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" } @@ -81438,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" @@ -81452,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" } @@ -81480,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" } @@ -81488,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" } @@ -81505,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" } @@ -81523,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", @@ -81538,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" @@ -85114,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", @@ -88993,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" @@ -89007,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", @@ -89021,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", @@ -92577,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", @@ -93969,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", @@ -94618,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" } @@ -98075,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", @@ -98087,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", @@ -98103,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 9f456f359a741b..2c3313b9337d41 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/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 0ca8fb69cde4fd..be179d3b2251dd 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 f616b261c8ec4f..2980553f5a2846 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", From b7f2740d0e730a480da7a8ae8e700134c7b2a1c6 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 15 Nov 2023 11:49:53 +0100 Subject: [PATCH 030/116] Documentation: Add a first block type page to the platform docs (#56109) Co-authored-by: Ramon Co-authored-by: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> --- .../docs/create-block/first-block-type.md | 53 ++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/platform-docs/docs/create-block/first-block-type.md b/platform-docs/docs/create-block/first-block-type.md index 26925aab519876..437f4ec43b3e53 100644 --- a/platform-docs/docs/create-block/first-block-type.md +++ b/platform-docs/docs/create-block/first-block-type.md @@ -2,4 +2,55 @@ sidebar_position: 1 --- -# Your first block type \ No newline at end of file +# Your first block type + +In addition to the built-in block types, Gutenberg offers a flexible API to build any kind of block type you can imagine. + +The `registerBlockType` function registers the block we are going to create and specifies the block type settings. + +```js +import { createElement } from 'react'; +import { registerBlockType } from '@wordpress/blocks'; + +registerBlockType( 'create-block/gutenpride', { + // This is just a flag that tells the block editor that this block + // is using the API version 3 (the latest block type API). + apiVersion: 3, + + // This is the display title for your block type. + title: 'Gutenpride', + + // This is the category this block type will be listed in. + // Default categories include: text, media, design, widgets, theme and embed. + category: 'widgets', + + // This is a short description for your block type. + // It will be shown in various places in the Gutenberg user interface. + description: 'Example static block scaffolded with Create Block tool.', + + // This is an icon for your block type. + icon: ( + + + + ), + + edit() { + return

Hello from the editor!

; + }, + + save() { + return

Hello from the saved content!

; + }, +} ); +``` + +The first parameter in the **registerBlockType** function is the block name. It's composed of two segments: a namespace and a specific name. The namespace is used to avoid collisions with other block types from different sources. The specific name is the name of the block type. The namespace and the specific name are separated by a slash. + +The second parameter to the function is the block type object. Two common object properties are **edit** and **save** — these are the key parts of a block. + +The result of the edit function is what the editor will render to the editor page when the block is inserted. + +The result of the save function is what the editor will produce as HTML when calling the `serialize` function. + +The `create-block/gutenpride` block type produces a static block at the moment, in the following sections of the tutorial, we will see how to make it editable. From 8f3405f9726793ed355df84ba190f52c8347c27e Mon Sep 17 00:00:00 2001 From: Marco Ciampini Date: Wed, 15 Nov 2023 12:42:49 +0100 Subject: [PATCH 031/116] DropdownMenu: remove extra vertical space around the toggle button (#56136) * DropdownMenu: add default vertical-align for the toggle button * CHANGELOG --- packages/components/CHANGELOG.md | 1 + packages/components/src/dropdown-menu/style.scss | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index be179d3b2251dd..a96c5dc5827c5c 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -22,6 +22,7 @@ ### Bug Fix +- `DropdownMenu`: remove extra vertical space around the toggle button ([#56136](https://github.com/WordPress/gutenberg/pull/56136)). - 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) diff --git a/packages/components/src/dropdown-menu/style.scss b/packages/components/src/dropdown-menu/style.scss index 7d9e1b997f7804..261662ab7256dc 100644 --- a/packages/components/src/dropdown-menu/style.scss +++ b/packages/components/src/dropdown-menu/style.scss @@ -1,3 +1,7 @@ +.components-dropdown-menu__toggle { + vertical-align: top; +} + .components-dropdown-menu__menu { width: 100%; font-family: $default-font; From 90aa9bd9ae808dca6c37d5bd6c3a09ca00602a26 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 15 Nov 2023 16:28:49 +0400 Subject: [PATCH 032/116] Migrate 'Plugins API' e2e tests to Playwright (#55958) * Migrate 'Plugins API' e2e tests to Playwright * Remove old test file and snapshot --- .../__snapshots__/plugins-api.test.js.snap | 7 - .../specs/editor/plugins/plugins-api.test.js | 189 -------------- .../plugins-api-error-boundary.spec.js | 38 +++ .../specs/editor/plugins/plugins-api.spec.js | 233 ++++++++++++++++++ 4 files changed, 271 insertions(+), 196 deletions(-) delete mode 100644 packages/e2e-tests/specs/editor/plugins/__snapshots__/plugins-api.test.js.snap delete mode 100644 packages/e2e-tests/specs/editor/plugins/plugins-api.test.js create mode 100644 test/e2e/specs/editor/plugins/plugins-api-error-boundary.spec.js create mode 100644 test/e2e/specs/editor/plugins/plugins-api.spec.js diff --git a/packages/e2e-tests/specs/editor/plugins/__snapshots__/plugins-api.test.js.snap b/packages/e2e-tests/specs/editor/plugins/__snapshots__/plugins-api.test.js.snap deleted file mode 100644 index 9e4a5ac3ad6f61..00000000000000 --- a/packages/e2e-tests/specs/editor/plugins/__snapshots__/plugins-api.test.js.snap +++ /dev/null @@ -1,7 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Using Plugins API Document Setting Custom Panel Should render a custom panel inside Document Setting sidebar 1`] = `"My Custom Panel"`; - -exports[`Using Plugins API Sidebar Medium screen Should open plugins sidebar using More Menu item and render content 1`] = `"
(no title)
Plugin title
"`; - -exports[`Using Plugins API Sidebar Should open plugins sidebar using More Menu item and render content 1`] = `"
(no title)
Plugin title
"`; diff --git a/packages/e2e-tests/specs/editor/plugins/plugins-api.test.js b/packages/e2e-tests/specs/editor/plugins/plugins-api.test.js deleted file mode 100644 index 4ad8d0e634204f..00000000000000 --- a/packages/e2e-tests/specs/editor/plugins/plugins-api.test.js +++ /dev/null @@ -1,189 +0,0 @@ -/** - * WordPress dependencies - */ -import { - activatePlugin, - clickBlockAppender, - clickOnMoreMenuItem, - createNewPost, - deactivatePlugin, - openDocumentSettingsSidebar, - openPublishPanel, - publishPost, - setBrowserViewport, -} from '@wordpress/e2e-test-utils'; - -describe( 'Using Plugins API', () => { - beforeAll( async () => { - await activatePlugin( 'gutenberg-test-plugin-plugins-api' ); - } ); - - afterAll( async () => { - await deactivatePlugin( 'gutenberg-test-plugin-plugins-api' ); - } ); - - beforeEach( async () => { - await createNewPost(); - } ); - - describe( 'Post Status Info', () => { - it( 'Should render post status info inside Document Setting sidebar', async () => { - await openDocumentSettingsSidebar(); - - const pluginPostStatusInfoText = await page.$eval( - '.edit-post-post-status .my-post-status-info-plugin', - ( el ) => el.innerText - ); - expect( pluginPostStatusInfoText ).toBe( 'My post status info' ); - } ); - } ); - - describe( 'Publish Panel', () => { - beforeEach( async () => { - // Type something first to activate Publish button. - await clickBlockAppender(); - await page.keyboard.type( 'First paragraph' ); - } ); - - it( 'Should render publish panel inside Pre-publish sidebar', async () => { - await openPublishPanel(); - - const pluginPublishPanelText = await page.$eval( - '.editor-post-publish-panel .my-publish-panel-plugin__pre', - ( el ) => el.innerText - ); - expect( pluginPublishPanelText ).toMatch( 'My pre publish panel' ); - } ); - - it( 'Should render publish panel inside Post-publish sidebar', async () => { - await publishPost(); - const pluginPublishPanel = await page.waitForSelector( - '.editor-post-publish-panel .my-publish-panel-plugin__post' - ); - const pluginPublishPanelText = await pluginPublishPanel.evaluate( - ( node ) => node.innerText - ); - expect( pluginPublishPanelText ).toMatch( 'My post publish panel' ); - } ); - } ); - - describe( 'Sidebar', () => { - const SIDEBAR_PINNED_ITEM_BUTTON = - '.interface-pinned-items button[aria-label="Plugin title"]'; - const SIDEBAR_PANEL_SELECTOR = '.sidebar-title-plugin-panel'; - it( 'Should open plugins sidebar using More Menu item and render content', async () => { - await clickOnMoreMenuItem( 'Plugin more menu title' ); - - const pluginSidebarContent = await page.$eval( - '.edit-post-sidebar', - ( el ) => el.innerHTML - ); - expect( pluginSidebarContent ).toMatchSnapshot(); - } ); - - it( 'Should be pinned by default and can be opened and closed using pinned items', async () => { - const sidebarPinnedItem = await page.$( - SIDEBAR_PINNED_ITEM_BUTTON - ); - expect( sidebarPinnedItem ).not.toBeNull(); - await sidebarPinnedItem.click(); - expect( await page.$( SIDEBAR_PANEL_SELECTOR ) ).not.toBeNull(); - await sidebarPinnedItem.click(); - expect( await page.$( SIDEBAR_PANEL_SELECTOR ) ).toBeNull(); - } ); - - it( 'Can be pinned and unpinned', async () => { - await ( await page.$( SIDEBAR_PINNED_ITEM_BUTTON ) ).click(); - const unpinButton = await page.$( - 'button[aria-label="Unpin from toolbar"]' - ); - await unpinButton.click(); - expect( await page.$( SIDEBAR_PINNED_ITEM_BUTTON ) ).toBeNull(); - await page.click( - '.interface-complementary-area-header button[aria-label="Close plugin"]' - ); - await page.reload(); - await page.waitForSelector( '.edit-post-layout' ); - expect( await page.$( SIDEBAR_PINNED_ITEM_BUTTON ) ).toBeNull(); - await clickOnMoreMenuItem( 'Plugin more menu title' ); - await page.click( 'button[aria-label="Pin to toolbar"]' ); - expect( await page.$( SIDEBAR_PINNED_ITEM_BUTTON ) ).not.toBeNull(); - await page.reload(); - await page.waitForSelector( '.edit-post-layout' ); - expect( await page.$( SIDEBAR_PINNED_ITEM_BUTTON ) ).not.toBeNull(); - } ); - - it( 'Should close plugins sidebar using More Menu item', async () => { - await clickOnMoreMenuItem( 'Plugin more menu title' ); - - const pluginSidebarOpened = await page.$( '.edit-post-sidebar' ); - expect( pluginSidebarOpened ).not.toBeNull(); - - await clickOnMoreMenuItem( 'Plugin more menu title' ); - - const pluginSidebarClosed = await page.$( '.edit-post-sidebar' ); - expect( pluginSidebarClosed ).toBeNull(); - } ); - - describe( 'Medium screen', () => { - beforeAll( async () => { - await setBrowserViewport( 'medium' ); - } ); - - afterAll( async () => { - await setBrowserViewport( 'large' ); - } ); - - it( 'Should open plugins sidebar using More Menu item and render content', async () => { - await clickOnMoreMenuItem( 'Plugin more menu title' ); - - const pluginSidebarContent = await page.$eval( - '.edit-post-sidebar', - ( el ) => el.innerHTML - ); - expect( pluginSidebarContent ).toMatchSnapshot(); - } ); - } ); - } ); - - describe( 'Document Setting Custom Panel', () => { - it( 'Should render a custom panel inside Document Setting sidebar', async () => { - await openDocumentSettingsSidebar(); - const pluginDocumentSettingsText = await page.$eval( - '.edit-post-sidebar .my-document-setting-plugin', - ( el ) => el.innerText - ); - expect( pluginDocumentSettingsText ).toMatchSnapshot(); - } ); - } ); - - describe( 'Error Boundary', () => { - beforeAll( async () => { - await activatePlugin( - 'gutenberg-test-plugin-plugins-error-boundary' - ); - } ); - - afterAll( async () => { - await deactivatePlugin( - 'gutenberg-test-plugin-plugins-error-boundary' - ); - } ); - - it( 'Should create notice using plugin error boundary callback', async () => { - const noticeContent = await page.waitForSelector( - '.is-error .components-notice__content' - ); - expect( - await page.evaluate( - ( _noticeContent ) => _noticeContent.firstChild.nodeValue, - noticeContent - ) - ).toEqual( - 'The "my-error-plugin" plugin has encountered an error and cannot be rendered.' - ); - - expect( console ).toHaveErrored(); - } ); - } ); -} ); diff --git a/test/e2e/specs/editor/plugins/plugins-api-error-boundary.spec.js b/test/e2e/specs/editor/plugins/plugins-api-error-boundary.spec.js new file mode 100644 index 00000000000000..25f528be8a0083 --- /dev/null +++ b/test/e2e/specs/editor/plugins/plugins-api-error-boundary.spec.js @@ -0,0 +1,38 @@ +/** + * WordPress dependencies + */ +const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); + +test.describe( 'Plugins API Error Boundary', () => { + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.activatePlugin( + 'gutenberg-test-plugin-plugins-error-boundary' + ); + } ); + + test.afterAll( async ( { requestUtils } ) => { + await requestUtils.deactivatePlugin( + 'gutenberg-test-plugin-plugins-error-boundary' + ); + } ); + + test( 'Should create notice using plugin error boundary callback', async ( { + admin, + page, + } ) => { + let hasError = false; + page.on( 'console', ( msg ) => { + if ( msg.type() === 'error' && msg.text().includes( 'Whoops!' ) ) + hasError = true; + } ); + + await admin.createNewPost(); + + expect( hasError ).toBe( true ); + await expect( + page.locator( '.is-error .components-notice__content' ) + ).toContainText( + 'The "my-error-plugin" plugin has encountered an error and cannot be rendered.' + ); + } ); +} ); diff --git a/test/e2e/specs/editor/plugins/plugins-api.spec.js b/test/e2e/specs/editor/plugins/plugins-api.spec.js new file mode 100644 index 00000000000000..c71b49e3c4d815 --- /dev/null +++ b/test/e2e/specs/editor/plugins/plugins-api.spec.js @@ -0,0 +1,233 @@ +/** + * WordPress dependencies + */ +const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); + +test.describe( 'Plugins API', () => { + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.activatePlugin( + 'gutenberg-test-plugin-plugins-api' + ); + } ); + + test.beforeEach( async ( { admin } ) => { + await admin.createNewPost(); + } ); + + test.afterAll( async ( { requestUtils } ) => { + await requestUtils.deactivatePlugin( + 'gutenberg-test-plugin-plugins-api' + ); + } ); + + test.describe( 'Post Status Info', () => { + test( 'Should render post status info inside Document Setting sidebar', async ( { + editor, + page, + } ) => { + await editor.openDocumentSettingsSidebar(); + + await expect( + page + .getByRole( 'region', { name: 'Editor settings' } ) + .locator( '.my-post-status-info-plugin' ) + ).toHaveText( 'My post status info' ); + } ); + } ); + + test.describe( 'Publish Panel', () => { + test( 'Should render publish panel inside Pre-publish sidebar', async ( { + editor, + page, + } ) => { + await editor.canvas + .getByRole( 'textbox', { name: 'Add title' } ) + .fill( 'A post' ); + + // Open pre-publish panel. + await page + .getByRole( 'region', { name: 'Editor top bar' } ) + .getByRole( 'button', { name: 'Publish' } ) + .click(); + + await expect( + page + .getByRole( 'region', { name: 'Editor publish' } ) + .getByRole( 'button', { name: 'My pre publish panel' } ) + ).toBeVisible(); + } ); + + test( 'Should render publish panel inside Post-publish sidebar', async ( { + editor, + page, + } ) => { + await editor.canvas + .getByRole( 'textbox', { name: 'Add title' } ) + .fill( 'A post' ); + await editor.publishPost(); + + await expect( + page + .getByRole( 'region', { name: 'Editor publish' } ) + .getByRole( 'button', { name: 'My post publish panel' } ) + ).toBeVisible(); + } ); + } ); + + test.describe( 'Sidebar', () => { + test( 'Should open plugins sidebar using More Menu item and render content', async ( { + page, + } ) => { + await page + .getByRole( 'region', { name: 'Editor top bar' } ) + .getByRole( 'button', { name: 'Options' } ) + .click(); + await page + .getByRole( 'menuitemcheckbox', { + name: 'Plugin more menu title', + } ) + .click(); + + const settingsSidebar = page.getByRole( 'region', { + name: 'Editor settings', + } ); + + await expect( + settingsSidebar.getByRole( 'textbox', { + name: 'Title', + } ) + ).toBeVisible(); + await expect( + settingsSidebar.getByRole( 'button', { + name: 'Reset', + } ) + ).toBeVisible(); + } ); + + test( 'Should be pinned by default and can be opened and closed using pinned items', async ( { + page, + } ) => { + const pinnedButton = page + .getByRole( 'region', { name: 'Editor top bar' } ) + .getByRole( 'button', { name: 'Plugin title' } ); + const pluginField = page + .getByRole( 'region', { + name: 'Editor settings', + } ) + .getByRole( 'textbox', { + name: 'Title', + } ); + + await pinnedButton.click(); + await expect( pluginField ).toBeVisible(); + + await pinnedButton.click(); + await expect( pluginField ).toBeHidden(); + } ); + + test( 'Can be pinned and unpinned', async ( { page } ) => { + const pinnedButton = page + .getByRole( 'region', { name: 'Editor top bar' } ) + .getByRole( 'button', { name: 'Plugin title' } ); + + await pinnedButton.click(); + await page + .getByRole( 'button', { name: 'Unpin from toolbar' } ) + .click(); + + await expect( pinnedButton ).toBeHidden(); + + await page.getByRole( 'button', { name: 'Close plugin' } ).click(); + await page.reload(); + + await expect( pinnedButton ).toBeHidden(); + + await page + .getByRole( 'region', { name: 'Editor top bar' } ) + .getByRole( 'button', { name: 'Options' } ) + .click(); + await page + .getByRole( 'menuitemcheckbox', { + name: 'Plugin more menu title', + } ) + .click(); + await page + .getByRole( 'button', { name: 'Pin to toolbar' } ) + .click(); + + await expect( pinnedButton ).toBeVisible(); + await page.reload(); + await expect( pinnedButton ).toBeVisible(); + } ); + + test( 'Should close plugins sidebar using More Menu item', async ( { + page, + } ) => { + const options = page + .getByRole( 'region', { name: 'Editor top bar' } ) + .getByRole( 'button', { name: 'Options' } ); + const moreMenuItem = page.getByRole( 'menuitemcheckbox', { + name: 'Plugin more menu title', + } ); + const pluginField = page + .getByRole( 'region', { + name: 'Editor settings', + } ) + .getByRole( 'textbox', { + name: 'Title', + } ); + + await options.click(); + await moreMenuItem.click(); + await expect( pluginField ).toBeVisible(); + + await options.click(); + await moreMenuItem.click(); + await expect( pluginField ).toBeHidden(); + } ); + + test( 'Should open plugins sidebar using More Menu item on smaller screens', async ( { + page, + pageUtils, + } ) => { + await pageUtils.setBrowserViewport( 'medium' ); + + await page + .getByRole( 'region', { name: 'Editor top bar' } ) + .getByRole( 'button', { name: 'Options' } ) + .click(); + await page + .getByRole( 'menuitemcheckbox', { + name: 'Plugin more menu title', + } ) + .click(); + + await expect( + page + .getByRole( 'region', { + name: 'Editor settings', + } ) + .getByRole( 'textbox', { + name: 'Title', + } ) + ).toBeVisible(); + + await pageUtils.setBrowserViewport( 'large' ); + } ); + } ); + + test.describe( 'Document Setting Custom Panel', () => { + test( 'Should render a custom panel inside Document Setting sidebar', async ( { + editor, + page, + } ) => { + await editor.openDocumentSettingsSidebar(); + + await expect( + page + .getByRole( 'region', { name: 'Editor settings' } ) + .getByRole( 'button', { name: 'My Custom Panel' } ) + ).toBeVisible(); + } ); + } ); +} ); From 1bf654b6c7f794d598fc6980789185924168ee2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Wed, 15 Nov 2023 15:18:04 +0100 Subject: [PATCH 033/116] DataViews: allow users to add filters dynamically (#55992) --- .../src/components/dataviews/README.md | 5 +- .../src/components/dataviews/add-filter.js | 111 ++++++++++++++++++ .../src/components/dataviews/filters.js | 66 ++++++----- .../src/components/dataviews/in-filter.js | 14 +-- .../src/components/dataviews/reset-filters.js | 34 +++--- .../src/components/dataviews/search.js | 1 + .../sidebar-dataviews/default-views.js | 1 - 7 files changed, 171 insertions(+), 61 deletions(-) create mode 100644 packages/edit-site/src/components/dataviews/add-filter.js diff --git a/packages/edit-site/src/components/dataviews/README.md b/packages/edit-site/src/components/dataviews/README.md index 5502165f0cfdc5..8f1349044d6cf5 100644 --- a/packages/edit-site/src/components/dataviews/README.md +++ b/packages/edit-site/src/components/dataviews/README.md @@ -47,7 +47,6 @@ Example: { field: 'author', operator: 'in', value: 2 }, { field: 'status', operator: 'in', value: 'publish,draft' } ], - visibleFilters: [ 'author', 'status' ], hiddenFields: [ 'date', 'featured-image' ], layout: {}, } @@ -62,8 +61,7 @@ Example: - `filters`: the filters applied to the dataset. Each item describes: - `field`: which field this filter is bound to. - `operator`: which type of filter it is. Only `in` available at the moment. - - `vaule`: the actual value selected by the user. -- `visibleFilters`: the `id` of the filters that are visible in the UI. + - `value`: the actual value selected by the user. - `hiddenFields`: the `id` of the fields that are hidden in the UI. - `layout`: ... @@ -88,7 +86,6 @@ function MyCustomPageList() { { field: 'author', operator: 'in', value: 2 }, { field: 'status', operator: 'in', value: 'publish,draft' } ], - visibleFilters: [ 'author', 'status' ], hiddenFields: [ 'date', 'featured-image' ], layout: {}, } ); diff --git a/packages/edit-site/src/components/dataviews/add-filter.js b/packages/edit-site/src/components/dataviews/add-filter.js new file mode 100644 index 00000000000000..2cc0051f0f2d49 --- /dev/null +++ b/packages/edit-site/src/components/dataviews/add-filter.js @@ -0,0 +1,111 @@ +/** + * WordPress dependencies + */ +import { + privateApis as componentsPrivateApis, + Button, + Icon, +} from '@wordpress/components'; +import { chevronRightSmall, plus } from '@wordpress/icons'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import { unlock } from '../../lock-unlock'; +import { OPERATOR_IN } from './in-filter'; + +const { + DropdownMenuV2, + DropdownSubMenuV2, + DropdownSubMenuTriggerV2, + DropdownMenuItemV2, +} = unlock( componentsPrivateApis ); + +const VALID_OPERATORS = [ OPERATOR_IN ]; + +export default function AddFilter( { fields, view, onChangeView } ) { + const filters = []; + fields.forEach( ( field ) => { + if ( ! field.filters ) { + return; + } + + field.filters.forEach( ( filter ) => { + if ( VALID_OPERATORS.some( ( operator ) => operator === filter ) ) { + filters.push( { + field: field.id, + name: field.header, + operator: filter, + elements: field.elements || [], + isVisible: view.filters.some( + ( f ) => f.field === field.id && f.operator === filter + ), + } ); + } + } ); + } ); + + if ( filters.length === 0 ) { + return null; + } + + return ( + + { __( 'Add filter' ) } + + } + > + { filters.map( ( filter ) => { + if ( filter.isVisible ) { + return null; + } + + return ( + } + > + { filter.name } + + } + > + { filter.elements.map( ( element ) => ( + { + onChangeView( ( currentView ) => ( { + ...currentView, + page: 1, + filters: [ + ...currentView.filters, + { + field: filter.field, + operator: 'in', + value: element.value, + }, + ], + } ) ); + } } + role="menuitemcheckbox" + > + { element.label } + + ) ) } + + ); + } ) } + + ); +} diff --git a/packages/edit-site/src/components/dataviews/filters.js b/packages/edit-site/src/components/dataviews/filters.js index e34ba84040a95d..dc268845df5c0e 100644 --- a/packages/edit-site/src/components/dataviews/filters.js +++ b/packages/edit-site/src/components/dataviews/filters.js @@ -7,12 +7,13 @@ import { __ } from '@wordpress/i18n'; * Internal dependencies */ import { default as InFilter, OPERATOR_IN } from './in-filter'; +import AddFilter from './add-filter'; import ResetFilters from './reset-filters'; const VALID_OPERATORS = [ OPERATOR_IN ]; export default function Filters( { fields, view, onChangeView } ) { - const filtersRegistered = []; + const filters = []; fields.forEach( ( field ) => { if ( ! field.filters ) { return; @@ -20,7 +21,7 @@ export default function Filters( { fields, view, onChangeView } ) { field.filters.forEach( ( filter ) => { if ( VALID_OPERATORS.some( ( operator ) => operator === filter ) ) { - filtersRegistered.push( { + filters.push( { field: field.id, name: field.header, operator: filter, @@ -31,46 +32,47 @@ export default function Filters( { fields, view, onChangeView } ) { }, ...( field.elements || [] ), ], + isVisible: view.filters.some( + ( f ) => f.field === field.id && f.operator === filter + ), } ); } } ); } ); - const visibleFilters = view.visibleFilters - ?.map( ( fieldName ) => { - const visibleFiltersForField = filtersRegistered.filter( - ( f ) => f.field === fieldName + const filterComponents = filters?.map( ( filter ) => { + if ( ! filter.isVisible ) { + return null; + } + + if ( OPERATOR_IN === filter.operator ) { + return ( + ); + } - if ( visibleFiltersForField.length === 0 ) { - return null; - } + return null; + } ); - return visibleFiltersForField.map( ( filter ) => { - if ( OPERATOR_IN === filter.operator ) { - return ( - - ); - } - return null; - } ); - } ) - .filter( Boolean ); + filterComponents.push( + + ); - if ( visibleFilters?.length > 0 ) { - visibleFilters.push( - + if ( filterComponents.length > 1 ) { + filterComponents.push( + ); } - return visibleFilters; + return filterComponents; } diff --git a/packages/edit-site/src/components/dataviews/in-filter.js b/packages/edit-site/src/components/dataviews/in-filter.js index 9642169335aafa..4154e0576101c1 100644 --- a/packages/edit-site/src/components/dataviews/in-filter.js +++ b/packages/edit-site/src/components/dataviews/in-filter.js @@ -24,6 +24,7 @@ export default ( { filter, view, onChangeView } ) => { return ( { ( f ) => f.field !== filter.field || f.operator !== OPERATOR_IN ); - if ( value !== '' ) { - filters.push( { - field: filter.field, - operator: OPERATOR_IN, - value, - } ); - } + + filters.push( { + field: filter.field, + operator: OPERATOR_IN, + value, + } ); onChangeView( ( currentView ) => ( { ...currentView, diff --git a/packages/edit-site/src/components/dataviews/reset-filters.js b/packages/edit-site/src/components/dataviews/reset-filters.js index 68b5c17590c977..d78c06624087a7 100644 --- a/packages/edit-site/src/components/dataviews/reset-filters.js +++ b/packages/edit-site/src/components/dataviews/reset-filters.js @@ -1,26 +1,26 @@ /** * WordPress dependencies */ -import { BaseControl, Button } from '@wordpress/components'; +import { Button } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; export default ( { view, onChangeView } ) => { return ( - - - + ); }; diff --git a/packages/edit-site/src/components/dataviews/search.js b/packages/edit-site/src/components/dataviews/search.js index 3ade147922ac99..17a882637a7183 100644 --- a/packages/edit-site/src/components/dataviews/search.js +++ b/packages/edit-site/src/components/dataviews/search.js @@ -31,6 +31,7 @@ export default function Search( { label, view, onChangeView } ) { const searchLabel = label || __( 'Filter list' ); return (
} - className={ `${ baseClassName }-list__item` } onClick={ () => onSelect( pattern.transformedBlocks ) } > Date: Thu, 16 Nov 2023 10:37:00 +0900 Subject: [PATCH 039/116] Lightbox: Fix close button position. (#56125) * use width 100% * remove scroll bar width * refactor * use documentElement --- packages/block-library/src/image/style.scss | 6 +++--- packages/block-library/src/image/view.js | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/image/style.scss b/packages/block-library/src/image/style.scss index 2b8631fffe3c93..303f43ce4ed5f1 100644 --- a/packages/block-library/src/image/style.scss +++ b/packages/block-library/src/image/style.scss @@ -215,7 +215,7 @@ left: 0; z-index: 100000; overflow: hidden; - width: 100vw; + width: 100%; height: 100vh; box-sizing: border-box; visibility: hidden; @@ -372,7 +372,7 @@ @keyframes lightbox-zoom-in { 0% { - transform: translate(calc(-50vw + var(--wp--lightbox-initial-left-position)), calc(-50vh + var(--wp--lightbox-initial-top-position))) scale(var(--wp--lightbox-scale)); + transform: translate(calc((-100vw + var(--wp--lightbox-scrollbar-width)) / 2 + var(--wp--lightbox-initial-left-position)), calc(-50vh + var(--wp--lightbox-initial-top-position))) scale(var(--wp--lightbox-scale)); } 100% { transform: translate(-50%, -50%) scale(1, 1); @@ -389,6 +389,6 @@ } 100% { visibility: hidden; - transform: translate(calc(-50vw + var(--wp--lightbox-initial-left-position)), calc(-50vh + var(--wp--lightbox-initial-top-position))) scale(var(--wp--lightbox-scale)); + transform: translate(calc((-100vw + var(--wp--lightbox-scrollbar-width)) / 2 + var(--wp--lightbox-initial-left-position)), calc(-50vh + var(--wp--lightbox-initial-top-position))) scale(var(--wp--lightbox-scale)); } } diff --git a/packages/block-library/src/image/view.js b/packages/block-library/src/image/view.js index ef46e932d2490b..74ed649a0df126 100644 --- a/packages/block-library/src/image/view.js +++ b/packages/block-library/src/image/view.js @@ -568,6 +568,9 @@ function setStyles( context, ref ) { --wp--lightbox-image-width: ${ lightboxImgWidth }px; --wp--lightbox-image-height: ${ lightboxImgHeight }px; --wp--lightbox-scale: ${ containerScale }; + --wp--lightbox-scrollbar-width: ${ + window.innerWidth - document.documentElement.clientWidth + }px; } `; } From 57ef059aabad25d730d04dff131b337e88d44699 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Thu, 16 Nov 2023 18:04:15 +1100 Subject: [PATCH 040/116] Update docs to clarify workflow branch for release package publishing. (#56183) --- docs/contributors/code/release.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributors/code/release.md b/docs/contributors/code/release.md index 83868f95ce184d..8c8ed3ff3c334e 100644 --- a/docs/contributors/code/release.md +++ b/docs/contributors/code/release.md @@ -422,7 +422,7 @@ Now, the `wp/X.Y` branch is ready for publishing npm packages. In order to start ![Run workflow dropdown for npm publishing](https://developer.wordpress.org/files/2023/07/image-2.png) -To publish packages to npm for the WordPress major release, select `wp` from the "Release type" dropdown and enter `X.Y` (example `5.2`) in the "WordPress major release" input field. Finally, press the green "Run workflow" button. It triggers the npm publishing job, and this needs to be approved by a Gutenberg Core team member. Locate the ["Publish npm packages" action](https://github.com/WordPress/gutenberg/actions/workflows/publish-npm-packages.yml) for the current publishing, and have it [approved](https://docs.github.com/en/actions/managing-workflow-runs/reviewing-deployments#approving-or-rejecting-a-job). +To publish packages to npm for the WordPress major release, select `trunk` as the branch to run the workflow from (this means that the script used to run the workflow comes from the trunk branch, though the packages themselves will published from the release branch as long as the correct "Release type" is selected below), then select `wp` from the "Release type" dropdown and enter `X.Y` (example `5.2`) in the "WordPress major release" input field. Finally, press the green "Run workflow" button. It triggers the npm publishing job, and this needs to be approved by a Gutenberg Core team member. Locate the ["Publish npm packages" action](https://github.com/WordPress/gutenberg/actions/workflows/publish-npm-packages.yml) for the current publishing, and have it [approved](https://docs.github.com/en/actions/managing-workflow-runs/reviewing-deployments#approving-or-rejecting-a-job). For the record, the manual process would look like the following: From 506da3f4dc545b35e61964bc6905e125ec6ef4f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Thu, 16 Nov 2023 08:51:11 +0100 Subject: [PATCH 041/116] DataViews: fix spacing issue in top-level bar (#56151) --- packages/edit-site/src/components/dataviews/dataviews.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/dataviews/dataviews.js b/packages/edit-site/src/components/dataviews/dataviews.js index 40bc87bed200c4..e2e392f8fd95b6 100644 --- a/packages/edit-site/src/components/dataviews/dataviews.js +++ b/packages/edit-site/src/components/dataviews/dataviews.js @@ -70,7 +70,7 @@ export default function DataViews( { onChangeView={ onChangeView } /> - + Date: Thu, 16 Nov 2023 08:00:59 +0000 Subject: [PATCH 042/116] Update data views 'View' button (#56144) * Update data views 'View' button * small tweaks and linter fix --------- Co-authored-by: ntsekouras --- .../src/components/dataviews/view-actions.js | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/edit-site/src/components/dataviews/view-actions.js b/packages/edit-site/src/components/dataviews/view-actions.js index e1e85a3e56d09f..8953e70242af60 100644 --- a/packages/edit-site/src/components/dataviews/view-actions.js +++ b/packages/edit-site/src/components/dataviews/view-actions.js @@ -10,9 +10,10 @@ import { chevronRightSmall, check, blockTable, - chevronDown, arrowUp, arrowDown, + grid, + columns, } from '@wordpress/icons'; import { __ } from '@wordpress/i18n'; @@ -274,6 +275,8 @@ function SortMenu( { fields, view, onChangeView } ) { ); } +const VIEW_TYPE_ICONS = { list: blockTable, grid, 'side-by-side': columns }; + export default function ViewActions( { fields, view, @@ -284,9 +287,14 @@ export default function ViewActions( { + } > From c5b12496d67320ddcad2d8f43a991f01390bf2d1 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Thu, 16 Nov 2023 10:24:48 +0200 Subject: [PATCH 043/116] [Data views]: Update author and title fields in template's list (#56029) * [Data views]: Update author and title fields in template's list * add the icon in author for every case --- .../edit-site/src/components/list/added-by.js | 2 +- .../page-templates/dataviews-templates.js | 78 ++++++++++++------- 2 files changed, 53 insertions(+), 27 deletions(-) diff --git a/packages/edit-site/src/components/list/added-by.js b/packages/edit-site/src/components/list/added-by.js index da6111e0b29bd5..e9c8df0fa7f263 100644 --- a/packages/edit-site/src/components/list/added-by.js +++ b/packages/edit-site/src/components/list/added-by.js @@ -152,7 +152,7 @@ export function useAddedBy( postType, postId ) { * @param {Object} props * @param {string} props.imageUrl */ -function AvatarImage( { imageUrl } ) { +export function AvatarImage( { imageUrl } ) { const [ isImageLoaded, setIsImageLoaded ] = useState( false ); return ( diff --git a/packages/edit-site/src/components/page-templates/dataviews-templates.js b/packages/edit-site/src/components/page-templates/dataviews-templates.js index 8f8a052b79b948..ce4927895b29be 100644 --- a/packages/edit-site/src/components/page-templates/dataviews-templates.js +++ b/packages/edit-site/src/components/page-templates/dataviews-templates.js @@ -7,11 +7,13 @@ import removeAccents from 'remove-accents'; * WordPress dependencies */ import { + Icon, __experimentalHeading as Heading, __experimentalText as Text, + __experimentalHStack as HStack, __experimentalVStack as VStack, } from '@wordpress/components'; -import { __ } from '@wordpress/i18n'; +import { __, _x } from '@wordpress/i18n'; import { useState, useMemo, useCallback } from '@wordpress/element'; import { useEntityRecords } from '@wordpress/core-data'; import { decodeEntities } from '@wordpress/html-entities'; @@ -21,7 +23,7 @@ import { decodeEntities } from '@wordpress/html-entities'; */ import Page from '../page'; import Link from '../routes/link'; -import AddedBy from '../list/added-by'; +import { useAddedBy, AvatarImage } from '../list/added-by'; import { TEMPLATE_POST_TYPE } from '../../utils/constants'; import { DataViews } from '../dataviews'; import { @@ -47,6 +49,51 @@ function normalizeSearchInput( input = '' ) { return removeAccents( input.trim().toLowerCase() ); } +// TODO: these are going to be reused in the template part list. +// That's the reason for leaving the template parts code for now. +function TemplateTitle( { item } ) { + const { isCustomized } = useAddedBy( item.type, item.id ); + return ( + + + + { decodeEntities( item.title?.rendered || item.slug ) || + __( '(no title)' ) } + + + { isCustomized && ( + + { item.type === TEMPLATE_POST_TYPE + ? _x( 'Customized', 'template' ) + : _x( 'Customized', 'template part' ) } + + ) } + + ); +} + +function AuthorField( { item } ) { + const { text, icon, imageUrl } = useAddedBy( item.type, item.id ); + return ( + + { imageUrl ? ( + + ) : ( +
+ +
+ ) } + { text } +
+ ); +} + export default function DataviewsTemplates() { const [ view, setView ] = useState( DEFAULT_VIEW ); const { records: allTemplates, isResolving: isLoadingData } = @@ -110,25 +157,7 @@ export default function DataviewsTemplates() { header: __( 'Template' ), id: 'title', getValue: ( { item } ) => item.title?.rendered || item.slug, - render: ( { item } ) => { - return ( - - - - { decodeEntities( - item.title?.rendered || item.slug - ) || __( '(no title)' ) } - - - - ); - }, + render: ( { item } ) => , maxWidth: 400, enableHiding: false, }, @@ -145,17 +174,14 @@ export default function DataviewsTemplates() { ) ); }, + maxWidth: 200, enableSorting: false, }, { header: __( 'Author' ), id: 'author', getValue: () => {}, - render: ( { item } ) => { - return ( - - ); - }, + render: ( { item } ) => , enableHiding: false, enableSorting: false, }, From f9b544db9a372a7db6fbcd2eecc6cc4d84d398df Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 16 Nov 2023 09:26:33 +0100 Subject: [PATCH 044/116] Site Editor: use EditorProvider instead of custom logic (#56000) --- .../src/components/provider/use-block-sync.js | 23 +- packages/core-data/src/entity-provider.js | 9 +- .../default-block-editor-provider.js | 75 ----- .../block-editor-provider/index.js | 29 -- .../navigation-block-editor-provider.js | 114 -------- .../test/use-page-content-blocks.js | 116 -------- .../use-page-content-blocks.js | 90 ------ .../src/components/block-editor/index.js | 28 -- .../block-editor/use-site-editor-settings.js | 22 +- .../edit-site/src/components/editor/index.js | 262 ++++++++++-------- .../page-panels/edit-template.js | 34 +-- .../editor/src/components/provider/README.md | 50 ++++ .../editor/src/components/provider/index.js | 201 +++++++++++++- .../provider/use-block-editor-settings.js | 8 +- .../components/interface-skeleton/index.js | 2 - .../specs/site-editor/template-part.spec.js | 16 +- 16 files changed, 444 insertions(+), 635 deletions(-) delete mode 100644 packages/edit-site/src/components/block-editor/block-editor-provider/default-block-editor-provider.js delete mode 100644 packages/edit-site/src/components/block-editor/block-editor-provider/index.js delete mode 100644 packages/edit-site/src/components/block-editor/block-editor-provider/navigation-block-editor-provider.js delete mode 100644 packages/edit-site/src/components/block-editor/block-editor-provider/test/use-page-content-blocks.js delete mode 100644 packages/edit-site/src/components/block-editor/block-editor-provider/use-page-content-blocks.js delete mode 100644 packages/edit-site/src/components/block-editor/index.js create mode 100644 packages/editor/src/components/provider/README.md diff --git a/packages/block-editor/src/components/provider/use-block-sync.js b/packages/block-editor/src/components/provider/use-block-sync.js index 58aca847d80de0..4f2300f380892e 100644 --- a/packages/block-editor/src/components/provider/use-block-sync.js +++ b/packages/block-editor/src/components/provider/use-block-sync.js @@ -76,18 +76,11 @@ export default function useBlockSync( { resetBlocks, resetSelection, replaceInnerBlocks, - selectBlock, setHasControlledInnerBlocks, __unstableMarkNextChangeAsNotPersistent, } = registry.dispatch( blockEditorStore ); - const { - hasSelectedBlock, - getBlockName, - getBlocks, - getSelectionStart, - getSelectionEnd, - getBlock, - } = registry.select( blockEditorStore ); + const { getBlockName, getBlocks, getSelectionStart, getSelectionEnd } = + registry.select( blockEditorStore ); const isControlled = useSelect( ( select ) => { return ( @@ -180,9 +173,6 @@ export default function useBlockSync( { // bound sync, unset the outbound value to avoid considering it in // subsequent renders. pendingChanges.current.outgoing = []; - const hadSelection = hasSelectedBlock(); - const selectionAnchor = getSelectionStart(); - const selectionFocus = getSelectionEnd(); setControlledBlocks(); if ( controlledSelection ) { @@ -191,15 +181,6 @@ export default function useBlockSync( { controlledSelection.selectionEnd, controlledSelection.initialPosition ); - } else { - const selectionStillExists = getBlock( - selectionAnchor.clientId - ); - if ( hadSelection && ! selectionStillExists ) { - selectBlock( clientId ); - } else { - resetSelection( selectionAnchor, selectionFocus ); - } } } }, [ controlledBlocks, clientId ] ); diff --git a/packages/core-data/src/entity-provider.js b/packages/core-data/src/entity-provider.js index e2274629006ee2..4b82b62e318bc9 100644 --- a/packages/core-data/src/entity-provider.js +++ b/packages/core-data/src/entity-provider.js @@ -155,6 +155,9 @@ export function useEntityBlockEditor( kind, name, { id: _id } = {} ) { const id = _id ?? providerId; const { content, editedBlocks, meta } = useSelect( ( select ) => { + if ( ! id ) { + return {}; + } const { getEditedEntityRecord } = select( STORE_NAME ); const editedRecord = getEditedEntityRecord( kind, name, id ); return { @@ -169,6 +172,10 @@ export function useEntityBlockEditor( kind, name, { id: _id } = {} ) { useDispatch( STORE_NAME ); const blocks = useMemo( () => { + if ( ! id ) { + return undefined; + } + if ( editedBlocks ) { return editedBlocks; } @@ -176,7 +183,7 @@ export function useEntityBlockEditor( kind, name, { id: _id } = {} ) { return content && typeof content !== 'function' ? parse( content ) : EMPTY_ARRAY; - }, [ editedBlocks, content ] ); + }, [ id, editedBlocks, content ] ); const updateFootnotes = useCallback( ( _blocks ) => updateFootnotesFromMeta( _blocks, meta ), diff --git a/packages/edit-site/src/components/block-editor/block-editor-provider/default-block-editor-provider.js b/packages/edit-site/src/components/block-editor/block-editor-provider/default-block-editor-provider.js deleted file mode 100644 index c91c687ce5284c..00000000000000 --- a/packages/edit-site/src/components/block-editor/block-editor-provider/default-block-editor-provider.js +++ /dev/null @@ -1,75 +0,0 @@ -/** - * WordPress dependencies - */ -import { useEntityBlockEditor } from '@wordpress/core-data'; -import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; -import { useSelect } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import { store as editSiteStore } from '../../../store'; -import { unlock } from '../../../lock-unlock'; -import useSiteEditorSettings from '../use-site-editor-settings'; -import usePageContentBlocks from './use-page-content-blocks'; - -const { ExperimentalBlockEditorProvider } = unlock( blockEditorPrivateApis ); - -const noop = () => {}; - -/** - * The default block editor provider for the site editor. Typically used when - * the post type is `'wp_template_part'` or `'wp_template'` and allows editing - * of the template and its nested entities. - * - * If the page content focus type is `'hideTemplate'`, the provider will provide - * a set of page content blocks wrapped in a container that, together, - * mimic the look and feel of the post editor and - * allow editing of the page content only. - * - * @param {Object} props - * @param {Element} props.children - */ -export default function DefaultBlockEditorProvider( { children } ) { - const settings = useSiteEditorSettings(); - - const { templateType, isTemplateHidden } = useSelect( ( select ) => { - const { getEditedPostType } = select( editSiteStore ); - const { getPageContentFocusType, getCanvasMode } = unlock( - select( editSiteStore ) - ); - return { - templateType: getEditedPostType(), - isTemplateHidden: - getCanvasMode() === 'edit' && - getPageContentFocusType() === 'hideTemplate', - canvasMode: unlock( select( editSiteStore ) ).getCanvasMode(), - }; - }, [] ); - - const [ blocks, onInput, onChange ] = useEntityBlockEditor( - 'postType', - templateType - ); - const pageContentBlocks = usePageContentBlocks( { - blocks, - isPageContentFocused: isTemplateHidden, - wrapPageContent: true, - } ); - - return ( - - { children } - - ); -} diff --git a/packages/edit-site/src/components/block-editor/block-editor-provider/index.js b/packages/edit-site/src/components/block-editor/block-editor-provider/index.js deleted file mode 100644 index ab07a3fefc5d31..00000000000000 --- a/packages/edit-site/src/components/block-editor/block-editor-provider/index.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * WordPress dependencies - */ -import { useSelect } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import { store as editSiteStore } from '../../../store'; -import DefaultBlockEditorProvider from './default-block-editor-provider'; -import NavigationBlockEditorProvider from './navigation-block-editor-provider'; -import { NAVIGATION_POST_TYPE } from '../../../utils/constants'; - -export default function BlockEditorProvider( { children } ) { - const entityType = useSelect( - ( select ) => select( editSiteStore ).getEditedPostType(), - [] - ); - if ( entityType === NAVIGATION_POST_TYPE ) { - return ( - - { children } - - ); - } - return ( - { children } - ); -} diff --git a/packages/edit-site/src/components/block-editor/block-editor-provider/navigation-block-editor-provider.js b/packages/edit-site/src/components/block-editor/block-editor-provider/navigation-block-editor-provider.js deleted file mode 100644 index 9927cbb040c7bc..00000000000000 --- a/packages/edit-site/src/components/block-editor/block-editor-provider/navigation-block-editor-provider.js +++ /dev/null @@ -1,114 +0,0 @@ -/** - * WordPress dependencies - */ -import { useSelect, useDispatch } from '@wordpress/data'; -import { useMemo, useEffect } from '@wordpress/element'; -import { useEntityId } from '@wordpress/core-data'; -import { - store as blockEditorStore, - privateApis as blockEditorPrivateApis, -} from '@wordpress/block-editor'; -import { createBlock } from '@wordpress/blocks'; - -/** - * Internal dependencies - */ -import { unlock } from '../../../lock-unlock'; -import useSiteEditorSettings from '../use-site-editor-settings'; -import { store as editSiteStore } from '../../../store'; -import { NAVIGATION_POST_TYPE } from '../../../utils/constants'; - -const { ExperimentalBlockEditorProvider } = unlock( blockEditorPrivateApis ); - -const noop = () => {}; - -/** - * Block editor component for editing navigation menus. - * - * Note: Navigation entities require a wrapping Navigation block to provide - * them with some basic layout and styling. Therefore we create a "ghost" block - * and provide it will a reference to the navigation entity ID being edited. - * - * In this scenario it is the **block** that handles syncing the entity content - * whereas for other entities this is handled by entity block editor. - * - * @param {number} navigationMenuId the navigation menu ID - * @return {[WPBlock[], Function, Function]} The block array and setters. - */ -export default function NavigationBlockEditorProvider( { children } ) { - const defaultSettings = useSiteEditorSettings(); - - const navigationMenuId = useEntityId( 'postType', NAVIGATION_POST_TYPE ); - - const blocks = useMemo( () => { - return [ - createBlock( 'core/navigation', { - ref: navigationMenuId, - // As the parent editor is locked with `templateLock`, the template locking - // must be explicitly "unset" on the block itself to allow the user to modify - // the block's content. - templateLock: false, - } ), - ]; - }, [ navigationMenuId ] ); - - const { isEditMode } = useSelect( ( select ) => { - const { getCanvasMode } = unlock( select( editSiteStore ) ); - - return { - isEditMode: getCanvasMode() === 'edit', - }; - }, [] ); - - const { selectBlock, setBlockEditingMode, unsetBlockEditingMode } = - useDispatch( blockEditorStore ); - - const navigationBlockClientId = blocks && blocks[ 0 ]?.clientId; - - const settings = useMemo( () => { - return { - ...defaultSettings, - // Lock the editor to allow the root ("ghost") Navigation block only. - templateLock: 'insert', - template: [ [ 'core/navigation', {}, [] ] ], - }; - }, [ defaultSettings ] ); - - // Auto-select the Navigation block when entering Navigation focus mode. - useEffect( () => { - if ( navigationBlockClientId && isEditMode ) { - selectBlock( navigationBlockClientId ); - } - }, [ navigationBlockClientId, isEditMode, selectBlock ] ); - - // Set block editing mode to contentOnly when entering Navigation focus mode. - // This ensures that non-content controls on the block will be hidden and thus - // the user can focus on editing the Navigation Menu content only. - useEffect( () => { - if ( ! navigationBlockClientId ) { - return; - } - - setBlockEditingMode( navigationBlockClientId, 'contentOnly' ); - - return () => { - unsetBlockEditingMode( navigationBlockClientId ); - }; - }, [ - navigationBlockClientId, - unsetBlockEditingMode, - setBlockEditingMode, - ] ); - - return ( - - { children } - - ); -} diff --git a/packages/edit-site/src/components/block-editor/block-editor-provider/test/use-page-content-blocks.js b/packages/edit-site/src/components/block-editor/block-editor-provider/test/use-page-content-blocks.js deleted file mode 100644 index 775aea0bdb391e..00000000000000 --- a/packages/edit-site/src/components/block-editor/block-editor-provider/test/use-page-content-blocks.js +++ /dev/null @@ -1,116 +0,0 @@ -/** - * External dependencies - */ -import { renderHook } from '@testing-library/react'; -/** - * WordPress dependencies - */ -import { createBlock } from '@wordpress/blocks'; - -/** - * Internal dependencies - */ -import usePageContentBlocks from '../use-page-content-blocks'; - -jest.mock( '@wordpress/blocks', () => { - return { - __esModule: true, - ...jest.requireActual( '@wordpress/blocks' ), - createBlock( name, attributes = {}, innerBlocks = [] ) { - return { - name, - attributes, - innerBlocks, - }; - }, - }; -} ); - -describe( 'usePageContentBlocks', () => { - const blocksList = [ - createBlock( 'core/group', {}, [ - createBlock( 'core/post-title' ), - createBlock( 'core/post-featured-image' ), - createBlock( 'core/query', {}, [ - createBlock( 'core/post-title' ), - createBlock( 'core/post-featured-image' ), - createBlock( 'core/post-content' ), - ] ), - createBlock( 'core/post-content' ), - ] ), - createBlock( 'core/query' ), - createBlock( 'core/paragraph' ), - createBlock( 'core/post-content' ), - ]; - it( 'should return empty array if `isPageContentFocused` is `false`', () => { - const { result } = renderHook( () => - usePageContentBlocks( { - blocks: blocksList, - isPageContentFocused: false, - } ) - ); - expect( result.current ).toEqual( [] ); - } ); - it( 'should return empty array if `blocks` is undefined', () => { - const { result } = renderHook( () => - usePageContentBlocks( { - blocks: undefined, - isPageContentFocused: true, - } ) - ); - expect( result.current ).toEqual( [] ); - } ); - it( 'should return empty array if `blocks` is an empty array', () => { - const { result } = renderHook( () => - usePageContentBlocks( { - blocks: [], - isPageContentFocused: true, - } ) - ); - expect( result.current ).toEqual( [] ); - } ); - it( 'should return new block list', () => { - const { result } = renderHook( () => - usePageContentBlocks( { - blocks: blocksList, - isPageContentFocused: true, - } ) - ); - expect( result.current ).toEqual( [ - createBlock( 'core/post-title' ), - createBlock( 'core/post-featured-image' ), - createBlock( 'core/post-content' ), - createBlock( 'core/post-content' ), - ] ); - } ); - it( 'should return new block list wrapped in a Group block', () => { - const { result } = renderHook( () => - usePageContentBlocks( { - blocks: blocksList, - isPageContentFocused: true, - wrapPageContent: true, - } ) - ); - expect( result.current ).toEqual( [ - { - name: 'core/group', - attributes: { - layout: { type: 'constrained' }, - style: { - spacing: { - margin: { - top: '4em', // Mimics the post editor. - }, - }, - }, - }, - innerBlocks: [ - createBlock( 'core/post-title' ), - createBlock( 'core/post-featured-image' ), - createBlock( 'core/post-content' ), - createBlock( 'core/post-content' ), - ], - }, - ] ); - } ); -} ); diff --git a/packages/edit-site/src/components/block-editor/block-editor-provider/use-page-content-blocks.js b/packages/edit-site/src/components/block-editor/block-editor-provider/use-page-content-blocks.js deleted file mode 100644 index dd05f90a56bbbb..00000000000000 --- a/packages/edit-site/src/components/block-editor/block-editor-provider/use-page-content-blocks.js +++ /dev/null @@ -1,90 +0,0 @@ -/** - * WordPress dependencies - */ -import { useMemo } from '@wordpress/element'; -import { createBlock } from '@wordpress/blocks'; - -/** - * Internal dependencies - */ -import { PAGE_CONTENT_BLOCK_TYPES } from '../../../utils/constants'; - -/** - * Helper method to iterate through all blocks, recursing into allowed inner blocks. - * Returns a flattened object of transformed blocks. - * - * @param {Array} blocks Blocks to flatten. - * @param {Function} transform Transforming function to be applied to each block. If transform returns `undefined`, the block is skipped. - * - * @return {Array} Flattened object. - */ -function flattenBlocks( blocks, transform ) { - const result = []; - for ( let i = 0; i < blocks.length; i++ ) { - // Since the Query Block could contain PAGE_CONTENT_BLOCK_TYPES block types, - // we skip it because we only want to render stand-alone page content blocks in the block list. - if ( [ 'core/query' ].includes( blocks[ i ].name ) ) { - continue; - } - const transformedBlock = transform( blocks[ i ] ); - if ( transformedBlock ) { - result.push( transformedBlock ); - } - result.push( ...flattenBlocks( blocks[ i ].innerBlocks, transform ) ); - } - - return result; -} - -/** - * Returns a memoized array of blocks that contain only page content blocks, - * surrounded by an optional group block to mimic the post editor. - * - * @param {Object} props The argument for the function. - * @param {Array} props.blocks Block list. - * @param {boolean} props.isPageContentFocused Whether the page content has focus (and the surrounding template is inert). If `true` return page content blocks. Default `false`. - * @param {boolean} props.wrapPageContent Whether to wrap the page content blocks in a group block to mimic the post editor. Default `false`. - * @return {Array} Page content blocks. - */ -export default function usePageContentBlocks( { - blocks = [], - isPageContentFocused = false, - wrapPageContent = false, -} ) { - return useMemo( () => { - if ( ! isPageContentFocused || ! blocks?.length ) { - return []; - } - - const innerBlocks = flattenBlocks( blocks, ( block ) => - PAGE_CONTENT_BLOCK_TYPES[ block.name ] - ? createBlock( block.name ) - : undefined - ); - - if ( ! innerBlocks.length ) { - return []; - } - - if ( ! wrapPageContent ) { - return innerBlocks; - } - - return [ - createBlock( - 'core/group', - { - layout: { type: 'constrained' }, - style: { - spacing: { - margin: { - top: '4em', // Mimics the post editor. - }, - }, - }, - }, - innerBlocks - ), - ]; - }, [ blocks, isPageContentFocused ] ); -} diff --git a/packages/edit-site/src/components/block-editor/index.js b/packages/edit-site/src/components/block-editor/index.js deleted file mode 100644 index 2c635ff860a5bd..00000000000000 --- a/packages/edit-site/src/components/block-editor/index.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * WordPress dependencies - */ -import { BlockInspector } from '@wordpress/block-editor'; -import { privateApis as editPatternsPrivateApis } from '@wordpress/patterns'; - -/** - * Internal dependencies - */ -import TemplatePartConverter from '../template-part-converter'; -import { SidebarInspectorFill } from '../sidebar-edit-mode'; -import SiteEditorCanvas from './site-editor-canvas'; -import BlockEditorProvider from './block-editor-provider'; - -import { unlock } from '../../lock-unlock'; -const { PatternsMenuItems } = unlock( editPatternsPrivateApis ); -export default function BlockEditor() { - return ( - - - - - - - - - ); -} diff --git a/packages/edit-site/src/components/block-editor/use-site-editor-settings.js b/packages/edit-site/src/components/block-editor/use-site-editor-settings.js index f597abee0726d6..cb3fb3f1cb3336 100644 --- a/packages/edit-site/src/components/block-editor/use-site-editor-settings.js +++ b/packages/edit-site/src/components/block-editor/use-site-editor-settings.js @@ -87,7 +87,7 @@ function useArchiveLabel( templateSlug ) { ); } -export default function useSiteEditorSettings() { +export function useSpecificEditorSettings() { const { setIsInserterOpened } = useDispatch( editSiteStore ); const { templateSlug, @@ -97,8 +97,6 @@ export default function useSiteEditorSettings() { keepCaretInsideBlock, canvasMode, settings, - postType, - postId, } = useSelect( ( select ) => { const { getEditedPostType, @@ -132,8 +130,6 @@ export default function useSiteEditorSettings() { ), canvasMode: getCanvasMode(), settings: getSettings(), - postType: usedPostType, - postId: usedPostId, }; }, [] ); const archiveLabels = useArchiveLabel( templateSlug ); @@ -164,5 +160,21 @@ export default function useSiteEditorSettings() { archiveLabels.archiveNameLabel, ] ); + return defaultEditorSettings; +} + +export default function useSiteEditorSettings() { + const defaultEditorSettings = useSpecificEditorSettings(); + const { postType, postId } = useSelect( ( select ) => { + const { getEditedPostType, getEditedPostId } = unlock( + select( editSiteStore ) + ); + const usedPostType = getEditedPostType(); + const usedPostId = getEditedPostId(); + return { + postType: usedPostType, + postId: usedPostId, + }; + }, [] ); return useBlockEditorSettings( defaultEditorSettings, postType, postId ); } diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 70d033d14188c7..110e891cc1858a 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -6,31 +6,37 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { useMemo } from '@wordpress/element'; import { useSelect } from '@wordpress/data'; import { Notice } from '@wordpress/components'; import { useInstanceId } from '@wordpress/compose'; -import { EntityProvider } from '@wordpress/core-data'; import { store as preferencesStore } from '@wordpress/preferences'; import { - BlockContextProvider, BlockBreadcrumb, store as blockEditorStore, privateApis as blockEditorPrivateApis, + BlockInspector, } from '@wordpress/block-editor'; import { InterfaceSkeleton, ComplementaryArea, store as interfaceStore, } from '@wordpress/interface'; -import { EditorNotices, EditorSnackbars } from '@wordpress/editor'; +import { + EditorNotices, + EditorSnackbars, + privateApis as editorPrivateApis, +} from '@wordpress/editor'; import { __, sprintf } from '@wordpress/i18n'; +import { store as coreDataStore } from '@wordpress/core-data'; +import { useMemo } from '@wordpress/element'; /** * Internal dependencies */ -import { SidebarComplementaryAreaFills } from '../sidebar-edit-mode'; -import BlockEditor from '../block-editor'; +import { + SidebarComplementaryAreaFills, + SidebarInspectorFill, +} from '../sidebar-edit-mode'; import CodeEditor from '../code-editor'; import KeyboardShortcutsEditMode from '../keyboard-shortcuts/edit-mode'; import InserterSidebar from '../secondary-sidebar/inserter-sidebar'; @@ -46,8 +52,13 @@ import useEditedEntityRecord from '../use-edited-entity-record'; import { SidebarFixedBottomSlot } from '../sidebar-edit-mode/sidebar-fixed-bottom'; import PatternModal from '../pattern-modal'; import { POST_TYPE_LABELS, TEMPLATE_POST_TYPE } from '../../utils/constants'; +import SiteEditorCanvas from '../block-editor/site-editor-canvas'; +import TemplatePartConverter from '../template-part-converter'; +import { useSpecificEditorSettings } from '../block-editor/use-site-editor-settings'; const { BlockRemovalWarningModal } = unlock( blockEditorPrivateApis ); +const { ExperimentalEditorProvider: EditorProvider } = + unlock( editorPrivateApis ); const interfaceLabels = { /* translators: accessibility text for the editor content landmark region. */ @@ -79,10 +90,11 @@ export default function Editor( { listViewToggleElement, isLoading } ) { isLoaded: hasLoadedPost, } = useEditedEntityRecord(); - const { id: editedPostId, type: editedPostType } = editedPost; + const { type: editedPostType } = editedPost; const { context, + contextPost, editorMode, canvasMode, blockEditorMode, @@ -92,6 +104,7 @@ export default function Editor( { listViewToggleElement, isLoading } ) { showIconLabels, showBlockBreadcrumbs, hasPageContentFocus, + pageContentFocusType, } = useSelect( ( select ) => { const { getEditedPostContext, @@ -100,14 +113,24 @@ export default function Editor( { listViewToggleElement, isLoading } ) { isInserterOpened, isListViewOpened, hasPageContentFocus: _hasPageContentFocus, + getPageContentFocusType, } = unlock( select( editSiteStore ) ); const { __unstableGetEditorMode } = select( blockEditorStore ); const { getActiveComplementaryArea } = select( interfaceStore ); + const { getEntityRecord } = select( coreDataStore ); + const _context = getEditedPostContext(); // The currently selected entity to display. // Typically template or template part in the site editor. return { - context: getEditedPostContext(), + context: _context, + contextPost: _context?.postId + ? getEntityRecord( + 'postType', + _context.postType, + _context.postId + ) + : undefined, editorMode: getEditorMode(), canvasMode: getCanvasMode(), blockEditorMode: __unstableGetEditorMode(), @@ -125,6 +148,7 @@ export default function Editor( { listViewToggleElement, isLoading } ) { 'showBlockBreadcrumbs' ), hasPageContentFocus: _hasPageContentFocus(), + pageContentFocusType: getPageContentFocusType(), }; }, [] ); @@ -141,18 +165,7 @@ export default function Editor( { listViewToggleElement, isLoading } ) { const secondarySidebarLabel = isListViewOpen ? __( 'List View' ) : __( 'Block Library' ); - const blockContext = useMemo( () => { - const { postType, postId, ...nonPostFields } = context ?? {}; - - return { - ...( hasPageContentFocus ? context : nonPostFields ), - // Ideally this context should be removed. However, it is currently used by the Query Loop block. - templateSlug: - editedPostType === TEMPLATE_POST_TYPE - ? editedPost.slug - : undefined, - }; - }, [ editedPost.slug, editedPostType, hasPageContentFocus, context ] ); + const postWithTemplate = context?.postId; let title; if ( hasLoadedPost ) { @@ -174,110 +187,131 @@ export default function Editor( { listViewToggleElement, isLoading } ) { 'edit-site-editor__loading-progress' ); - const contentProps = isLoading - ? { - 'aria-busy': 'true', - 'aria-describedby': loadingProgressId, - } - : undefined; + const settings = useSpecificEditorSettings(); + const isReady = + ! isLoading && + ( ( postWithTemplate && !! contextPost && !! editedPost ) || + ( ! postWithTemplate && !! editedPost ) ); + const mode = useMemo( () => { + if ( isViewMode ) { + return postWithTemplate ? 'template-locked' : 'all'; + } + + if ( isEditMode && pageContentFocusType === 'hideTemplate' ) { + return 'post-only'; + } + + if ( postWithTemplate && hasPageContentFocus ) { + return 'template-locked'; + } + + if ( postWithTemplate && ! hasPageContentFocus ) { + return 'template-only'; + } + + return 'all'; + }, [ + isViewMode, + isEditMode, + postWithTemplate, + pageContentFocusType, + hasPageContentFocus, + ] ); return ( <> - { isLoading ? : null } + { ! isReady ? : null } { isEditMode && } - - + { __( + "You attempted to edit an item that doesn't exist. Perhaps it was deleted?" + ) } + + ) } + { isReady && ( + - - - { isEditMode && } - } - content={ - <> - - { isEditMode && } - { showVisualEditor && editedPost && ( - <> - - - - - ) } - { editorMode === 'text' && - editedPost && - isEditMode && } - { hasLoadedPost && ! editedPost && ( - - { __( - "You attempted to edit an item that doesn't exist. Perhaps it was deleted?" - ) } - - ) } - { isEditMode && ( - - ) } - - } - contentProps={ contentProps } - secondarySidebar={ - isEditMode && - ( ( shouldShowInserter && ( - - ) ) || - ( shouldShowListView && ( - - ) ) ) + + { isEditMode && } + } + content={ + <> + + { isEditMode && } + { showVisualEditor && ( <> - - + + + + + + + - ) - } - footer={ - shouldShowBlockBreadcrumbs && ( - + ) } + { isEditMode && } + + } + secondarySidebar={ + isEditMode && + ( ( shouldShowInserter && ) || + ( shouldShowListView && ( + - ) - } - labels={ { - ...interfaceLabels, - secondarySidebar: secondarySidebarLabel, - } } - /> - - - + ) ) ) + } + sidebar={ + isEditMode && + isRightSidebarOpen && ( + <> + + + + ) + } + footer={ + shouldShowBlockBreadcrumbs && ( + + ) + } + labels={ { + ...interfaceLabels, + secondarySidebar: secondarySidebarLabel, + } } + /> + + ) } ); } 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 fde2b63d6e8330..1ee382420a7d9a 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 @@ -11,8 +11,9 @@ import { __experimentalText as Text, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { store as coreStore, useEntityBlockEditor } from '@wordpress/core-data'; +import { store as coreStore } from '@wordpress/core-data'; import { check } from '@wordpress/icons'; +import { store as blockEditorStore } from '@wordpress/block-editor'; /** * Internal dependencies @@ -21,7 +22,7 @@ import { store as editSiteStore } from '../../../store'; import SwapTemplateButton from './swap-template-button'; import ResetDefaultTemplate from './reset-default-template'; import { unlock } from '../../../lock-unlock'; -import usePageContentBlocks from '../../block-editor/block-editor-provider/use-page-content-blocks'; +import { PAGE_CONTENT_BLOCK_TYPES } from '../../../utils/constants'; const POPOVER_PROPS = { className: 'edit-site-page-panels-edit-template__dropdown', @@ -29,8 +30,8 @@ const POPOVER_PROPS = { }; export default function EditTemplate() { - const { hasResolved, template, isTemplateHidden, postType } = useSelect( - ( select ) => { + const { hasPostContentBlocks, hasResolved, template, isTemplateHidden } = + useSelect( ( select ) => { const { getEditedPostContext, getEditedPostType, getEditedPostId } = select( editSiteStore ); const { getCanvasMode, getPageContentFocusType } = unlock( @@ -38,15 +39,15 @@ export default function EditTemplate() { ); const { getEditedEntityRecord, hasFinishedResolution } = select( coreStore ); + const { __experimentalGetGlobalBlocksByName } = + select( blockEditorStore ); const _context = getEditedPostContext(); const _postType = getEditedPostType(); - const queryArgs = [ - 'postType', - getEditedPostType(), - getEditedPostId(), - ]; - + const queryArgs = [ 'postType', _postType, getEditedPostId() ]; return { + hasPostContentBlocks: !! __experimentalGetGlobalBlocksByName( + Object.keys( PAGE_CONTENT_BLOCK_TYPES ) + ).length, context: _context, hasResolved: hasFinishedResolution( 'getEditedEntityRecord', @@ -58,21 +59,12 @@ export default function EditTemplate() { getPageContentFocusType() === 'hideTemplate', postType: _postType, }; - }, - [] - ); - - const [ blocks ] = useEntityBlockEditor( 'postType', postType ); + }, [] ); const { setHasPageContentFocus } = useDispatch( editSiteStore ); // Disable reason: `useDispatch` can't be called conditionally. // eslint-disable-next-line @wordpress/no-unused-vars-before-return const { setPageContentFocusType } = unlock( useDispatch( editSiteStore ) ); - // Check if there are any post content block types in the blocks tree. - const pageContentBlocks = usePageContentBlocks( { - blocks, - isPageContentFocused: true, - } ); if ( ! hasResolved ) { return null; @@ -108,7 +100,7 @@ export default function EditTemplate() { - { !! pageContentBlocks?.length && ( + { hasPostContentBlocks && ( {}; +export const PAGE_CONTENT_BLOCK_TYPES = [ + 'core/post-title', + 'core/post-featured-image', + 'core/post-content', +]; + +/** + * For the Navigation block editor, we need to force the block editor to contentOnly for that block. + * + * Set block editing mode to contentOnly when entering Navigation focus mode. + * this ensures that non-content controls on the block will be hidden and thus + * the user can focus on editing the Navigation Menu content only. + * + * @param {string} navigationBlockClientId ClientId. + */ +function useForceFocusModeForNavigation( navigationBlockClientId ) { + const { setBlockEditingMode, unsetBlockEditingMode } = + useDispatch( blockEditorStore ); + + useEffect( () => { + if ( ! navigationBlockClientId ) { + return; + } + + setBlockEditingMode( navigationBlockClientId, 'contentOnly' ); + + return () => { + unsetBlockEditingMode( navigationBlockClientId ); + }; + }, [ + navigationBlockClientId, + unsetBlockEditingMode, + setBlockEditingMode, + ] ); +} + +/** + * Helper method to extract the post content block types from a template. + * + * @param {Array} blocks Template blocks. + * + * @return {Array} Flattened object. + */ +function extractPageContentBlockTypesFromTemplateBlocks( blocks ) { + const result = []; + for ( let i = 0; i < blocks.length; i++ ) { + // Since the Query Block could contain PAGE_CONTENT_BLOCK_TYPES block types, + // we skip it because we only want to render stand-alone page content blocks in the block list. + if ( blocks[ i ].name === 'core/query' ) { + continue; + } + if ( PAGE_CONTENT_BLOCK_TYPES.includes( blocks[ i ].name ) ) { + result.push( createBlock( blocks[ i ].name ) ); + } + if ( blocks[ i ].innerBlocks.length ) { + result.push( + ...extractPageContentBlockTypesFromTemplateBlocks( + blocks[ i ].innerBlocks + ) + ); + } + } + + return result; +} + +/** + * Depending on the post, template and template mode, + * returns the appropriate blocks and change handlers for the block editor provider. + * + * @param {Array} post Block list. + * @param {boolean} template Whether the page content has focus (and the surrounding template is inert). If `true` return page content blocks. Default `false`. + * @param {string} mode Rendering mode. + * @return {Array} Block editor props. + */ +function useBlockEditorProps( post, template, mode ) { + const rootLevelPost = + mode === 'post-only' || ! template ? 'post' : 'template'; + const [ postBlocks, onInput, onChange ] = useEntityBlockEditor( + 'postType', + post.type, + { id: post.id } + ); + const [ templateBlocks, onInputTemplate, onChangeTemplate ] = + useEntityBlockEditor( 'postType', template?.type, { + id: template?.id, + } ); + const blocks = useMemo( () => { + if ( post.type === 'wp_navigation' ) { + return [ + createBlock( 'core/navigation', { + ref: post.id, + // As the parent editor is locked with `templateLock`, the template locking + // must be explicitly "unset" on the block itself to allow the user to modify + // the block's content. + templateLock: false, + } ), + ]; + } + + if ( mode === 'post-only' ) { + return [ + createBlock( + 'core/group', + { + layout: { type: 'constrained' }, + style: { + spacing: { + margin: { + top: '4em', // Mimics the post editor. + }, + }, + }, + }, + extractPageContentBlockTypesFromTemplateBlocks( + templateBlocks + ) + ), + ]; + } + + if ( rootLevelPost === 'template' ) { + return templateBlocks; + } + + return postBlocks; + }, [ + templateBlocks, + postBlocks, + rootLevelPost, + post.type, + post.id, + mode, + ] ); + const disableRootLevelChanges = + ( !! template && mode === 'template-locked' ) || + post.type === 'wp_navigation' || + mode === 'post-only'; + const navigationBlockClientId = + post.type === 'wp_navigation' && blocks && blocks[ 0 ]?.clientId; + useForceFocusModeForNavigation( navigationBlockClientId ); + if ( disableRootLevelChanges ) { + return [ blocks, noop, noop ]; + } + + return [ + blocks, + rootLevelPost === 'post' ? onInput : onInputTemplate, + rootLevelPost === 'post' ? onChange : onChangeTemplate, + ]; +} + export const ExperimentalEditorProvider = withRegistryProvider( ( { - __unstableTemplate, + mode = 'all', post, settings, recovery, initialEdits, children, BlockEditorProviderComponent = ExperimentalBlockEditorProvider, + __unstableTemplate: template, } ) => { + const shouldRenderTemplate = !! template && mode !== 'post-only'; + const rootLevelPost = shouldRenderTemplate ? template : post; const defaultBlockContext = useMemo( () => { - if ( post.type === 'wp_template' ) { - return {}; - } - return { postId: post.id, postType: post.type }; - }, [ post.id, post.type ] ); + const postContext = + rootLevelPost.type !== 'wp_template' || + ( shouldRenderTemplate && mode !== 'template-only' ) + ? { postId: post.id, postType: post.type } + : {}; + + return { + ...postContext, + templateSlug: + rootLevelPost.type === 'wp_template' + ? rootLevelPost.slug + : undefined, + }; + }, [ + mode, + post.id, + post.type, + rootLevelPost.type, + rootLevelPost?.slug, + shouldRenderTemplate, + ] ); const { editorSettings, selection, isReady } = useSelect( ( select ) => { const { @@ -55,17 +229,18 @@ export const ExperimentalEditorProvider = withRegistryProvider( }, [] ); - const { id, type } = __unstableTemplate ?? post; - const [ blocks, onInput, onChange ] = useEntityBlockEditor( - 'postType', - type, - { id } - ); + const { id, type } = rootLevelPost; const blockEditorSettings = useBlockEditorSettings( editorSettings, type, id ); + const [ blocks, onInput, onChange ] = useBlockEditorProps( + post, + template, + mode + ); + const { updatePostLock, setupEditor, @@ -109,7 +284,7 @@ export const ExperimentalEditorProvider = withRegistryProvider( // Synchronize the editor settings as they change. useEffect( () => { updateEditorSettings( settings ); - }, [ settings ] ); + }, [ settings, updateEditorSettings ] ); if ( ! isReady ) { return null; diff --git a/packages/editor/src/components/provider/use-block-editor-settings.js b/packages/editor/src/components/provider/use-block-editor-settings.js index c0804febab0db5..e2cbba7e6a7571 100644 --- a/packages/editor/src/components/provider/use-block-editor-settings.js +++ b/packages/editor/src/components/provider/use-block-editor-settings.js @@ -67,8 +67,6 @@ const BLOCK_EDITOR_SETTINGS = [ 'postsPerPage', 'readOnly', 'styles', - 'template', - 'templateLock', 'titlePlaceholder', 'supportsLayout', 'widgetTypesToHideFromLegacyWidgetBlock', @@ -237,6 +235,12 @@ function useBlockEditorSettings( settings, postType, postId ) { pageOnFront, pageForPosts, __experimentalPreferPatternsOnRoot: postType === 'wp_template', + templateLock: + postType === 'wp_navigation' ? 'insert' : settings.templateLock, + template: + postType === 'wp_navigation' + ? [ [ 'core/navigation', {}, [] ] ] + : settings.template, } ), [ settings, diff --git a/packages/interface/src/components/interface-skeleton/index.js b/packages/interface/src/components/interface-skeleton/index.js index 58684ebaddd7e8..baf98d153ed870 100644 --- a/packages/interface/src/components/interface-skeleton/index.js +++ b/packages/interface/src/components/interface-skeleton/index.js @@ -52,7 +52,6 @@ function InterfaceSkeleton( secondarySidebar, notices, content, - contentProps, actions, labels, className, @@ -151,7 +150,6 @@ function InterfaceSkeleton( { content } diff --git a/test/e2e/specs/site-editor/template-part.spec.js b/test/e2e/specs/site-editor/template-part.spec.js index ff4610a57ba27b..9d4e1385627e79 100644 --- a/test/e2e/specs/site-editor/template-part.spec.js +++ b/test/e2e/specs/site-editor/template-part.spec.js @@ -382,9 +382,19 @@ test.describe( 'Template Part', () => { // Insert a group block with a Site Title block inside. await editor.insertBlock( { name: 'core/group', - innerBlocks: [ { name: 'core/site-title' } ], + innerBlocks: [ + { name: 'core/paragraph', attributes: { content: 'Hello' } }, + { name: 'core/site-title' }, + ], } ); + // Type within a first block. + const paragraph = editor.canvas.getByRole( 'document', { + name: 'Paragraph', + } ); + await editor.selectBlocks( paragraph ); + await page.keyboard.type( 'Modify' ); + // Select the Site Title block inside the group. const siteTitleInGroup = editor.canvas.getByRole( 'document', { name: 'Site title', @@ -401,8 +411,6 @@ test.describe( 'Template Part', () => { // Undo the change. await pageUtils.pressKeys( 'primary+z' ); - await expect( - page.locator( 'role=button[name="Change level"i]' ) - ).toBeFocused(); + await expect( paragraph ).toBeFocused(); } ); } ); From 8fa043bae1265a37ab27fc1cd25fb612feae26e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Thu, 16 Nov 2023 10:22:54 +0100 Subject: [PATCH 045/116] DataViews: add missing key to ResetFilters component (#56189) --- packages/edit-site/src/components/dataviews/filters.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/dataviews/filters.js b/packages/edit-site/src/components/dataviews/filters.js index dc268845df5c0e..9c37a7501a155d 100644 --- a/packages/edit-site/src/components/dataviews/filters.js +++ b/packages/edit-site/src/components/dataviews/filters.js @@ -70,7 +70,11 @@ export default function Filters( { fields, view, onChangeView } ) { if ( filterComponents.length > 1 ) { filterComponents.push( - + ); } From eb0a6f56a505d6bd84500504e8c778bf93eef1d6 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 16 Nov 2023 11:41:40 +0100 Subject: [PATCH 046/116] Button block: support double enter to skip to default block (#56134) --- packages/block-library/src/button/edit.js | 74 +++++++++++++++++++++-- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js index 81861e44997a4a..8400dabddad348 100644 --- a/packages/block-library/src/button/edit.js +++ b/packages/block-library/src/button/edit.js @@ -33,11 +33,17 @@ import { __experimentalGetSpacingClassesAndStyles as useSpacingProps, __experimentalLinkControl as LinkControl, __experimentalGetElementClassName, + store as blockEditorStore, } from '@wordpress/block-editor'; -import { displayShortcut, isKeyboardEvent } from '@wordpress/keycodes'; +import { displayShortcut, isKeyboardEvent, ENTER } from '@wordpress/keycodes'; import { link, linkOff } from '@wordpress/icons'; -import { createBlock } from '@wordpress/blocks'; -import { useMergeRefs } from '@wordpress/compose'; +import { + createBlock, + cloneBlock, + getDefaultBlockName, +} from '@wordpress/blocks'; +import { useMergeRefs, useRefEffect } from '@wordpress/compose'; +import { useSelect, useDispatch } from '@wordpress/data'; const LINK_SETTINGS = [ ...LinkControl.DEFAULT_LINK_SETTINGS, @@ -47,6 +53,62 @@ const LINK_SETTINGS = [ }, ]; +function useEnter( props ) { + const { replaceBlocks, selectionChange } = useDispatch( blockEditorStore ); + const { getBlock, getBlockRootClientId, getBlockIndex } = + useSelect( blockEditorStore ); + const propsRef = useRef( props ); + propsRef.current = props; + return useRefEffect( ( element ) => { + function onKeyDown( event ) { + if ( event.defaultPrevented || event.keyCode !== ENTER ) { + return; + } + const { content, clientId } = propsRef.current; + if ( content.length ) { + return; + } + event.preventDefault(); + const topParentListBlock = getBlock( + getBlockRootClientId( clientId ) + ); + const blockIndex = getBlockIndex( clientId ); + const head = cloneBlock( { + ...topParentListBlock, + innerBlocks: topParentListBlock.innerBlocks.slice( + 0, + blockIndex + ), + } ); + const middle = createBlock( getDefaultBlockName() ); + const after = topParentListBlock.innerBlocks.slice( + blockIndex + 1 + ); + const tail = after.length + ? [ + cloneBlock( { + ...topParentListBlock, + innerBlocks: after, + } ), + ] + : []; + replaceBlocks( + topParentListBlock.clientId, + [ head, middle, ...tail ], + 1 + ); + // We manually change the selection here because we are replacing + // a different block than the selected one. + selectionChange( middle.clientId ); + } + + element.addEventListener( 'keydown', onKeyDown ); + return () => { + element.removeEventListener( 'keydown', onKeyDown ); + }; + }, [] ); +} + function WidthPanel( { selectedWidth, setAttributes } ) { function handleChange( newWidth ) { // Check if we are toggling the width off @@ -88,6 +150,7 @@ function ButtonEdit( props ) { isSelected, onReplace, mergeBlocks, + clientId, } = props; const { tagName, @@ -164,6 +227,9 @@ function ButtonEdit( props ) { [ url, opensInNewTab, nofollow ] ); + const useEnterRef = useEnter( { content: text, clientId } ); + const mergedRef = useMergeRefs( [ useEnterRef, richTextRef ] ); + return ( <>
Date: Thu, 16 Nov 2023 11:03:34 +0000 Subject: [PATCH 047/116] Update 'All pages' sidebar heading (#56148) * Update 'All pages' sidebar heading * Remove description --- packages/edit-site/src/components/sidebar/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/edit-site/src/components/sidebar/index.js b/packages/edit-site/src/components/sidebar/index.js index cbedbabfc3af81..b66bf4390a6bcf 100644 --- a/packages/edit-site/src/components/sidebar/index.js +++ b/packages/edit-site/src/components/sidebar/index.js @@ -59,8 +59,7 @@ function SidebarScreens() { { window?.__experimentalAdminViews && ( } /> From e3e9dd04d4092c051d79bdf06b6997f3266dec3e Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Thu, 16 Nov 2023 14:37:22 +0100 Subject: [PATCH 048/116] Heading level dropdown: remove obtrusive tooltips in favor of visible text (#56035) * Remove heading level dropdown tooltip in favor of visible text. * Adjust test. * Remove CSS changes. --- .../src/components/block-heading-level-dropdown/index.js | 2 +- test/e2e/specs/editor/various/rich-text.spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/block-heading-level-dropdown/index.js b/packages/block-editor/src/components/block-heading-level-dropdown/index.js index be580042bb85e1..a8296d48ad2683 100644 --- a/packages/block-editor/src/components/block-heading-level-dropdown/index.js +++ b/packages/block-editor/src/components/block-heading-level-dropdown/index.js @@ -56,7 +56,7 @@ export default function HeadingLevelDropdown( { isPressed={ isActive } /> ), - label: + title: targetLevel === 0 ? __( 'Paragraph' ) : sprintf( diff --git a/test/e2e/specs/editor/various/rich-text.spec.js b/test/e2e/specs/editor/various/rich-text.spec.js index 2969a33d254852..1a307b2bc54379 100644 --- a/test/e2e/specs/editor/various/rich-text.spec.js +++ b/test/e2e/specs/editor/various/rich-text.spec.js @@ -20,7 +20,7 @@ test.describe( 'RichText', () => { // See: https://github.com/WordPress/gutenberg/issues/3091 await editor.insertBlock( { name: 'core/heading' } ); await editor.clickBlockToolbarButton( 'Change level' ); - await page.locator( 'button[aria-label="Heading 3"]' ).click(); + await page.locator( 'role=menuitemradio[name="Heading 3"]' ).click(); expect( await editor.getBlocks() ).toMatchObject( [ { From 9df15f77d7f0b914d58dbe2ce07ad03d738cd8a9 Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Thu, 16 Nov 2023 15:09:14 +0100 Subject: [PATCH 049/116] Fix the image link button pressed state. (#56123) * Fix image link button pressed state. * Add changelog entry. --- .../src/components/url-popover/image-url-input-ui.js | 1 + packages/components/CHANGELOG.md | 4 ++++ packages/components/src/toolbar/toolbar-button/style.scss | 5 ----- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/components/url-popover/image-url-input-ui.js b/packages/block-editor/src/components/url-popover/image-url-input-ui.js index 2f849eaad78847..7caa218658b24c 100644 --- a/packages/block-editor/src/components/url-popover/image-url-input-ui.js +++ b/packages/block-editor/src/components/url-popover/image-url-input-ui.js @@ -249,6 +249,7 @@ const ImageURLInputUI = ( { aria-expanded={ isOpen } onClick={ openLinkUI } ref={ setPopoverAnchor } + isActive={ !! url } /> { isOpen && ( Date: Thu, 16 Nov 2023 15:17:46 +0100 Subject: [PATCH 050/116] Unify the PageUrl and PageSlug components between site and post editors (#56203) --- .../components/sidebar/post-schedule/index.js | 1 + .../sidebar/post-schedule/style.scss | 10 +- .../components/sidebar/post-status/index.js | 9 +- .../sidebar/post-template/style.scss | 5 +- .../components/sidebar/post-url/style.scss | 26 --- .../sidebar/post-visibility/style.scss | 5 +- packages/edit-post/src/style.scss | 1 - .../page-panels/page-slug.js | 161 ------------------ .../page-panels/page-summary.js | 5 +- .../sidebar-edit-mode/page-panels/style.scss | 8 - packages/editor/src/components/index.js | 1 + .../components/post-sync-status/style.scss | 5 +- .../src/components/post-url/panel.js} | 32 ++-- .../editor/src/components/post-url/style.scss | 30 ++++ 14 files changed, 72 insertions(+), 227 deletions(-) delete mode 100644 packages/edit-post/src/components/sidebar/post-url/style.scss delete mode 100644 packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-slug.js rename packages/{edit-post/src/components/sidebar/post-url/index.js => editor/src/components/post-url/panel.js} (68%) diff --git a/packages/edit-post/src/components/sidebar/post-schedule/index.js b/packages/edit-post/src/components/sidebar/post-schedule/index.js index dca0dd12c6d6be..3b20880d736471 100644 --- a/packages/edit-post/src/components/sidebar/post-schedule/index.js +++ b/packages/edit-post/src/components/sidebar/post-schedule/index.js @@ -29,6 +29,7 @@ export default function PostSchedule() { { __( 'Publish' ) } ( diff --git a/packages/edit-post/src/components/sidebar/post-schedule/style.scss b/packages/edit-post/src/components/sidebar/post-schedule/style.scss index 056c2e68dbb5f1..46fcd819640045 100644 --- a/packages/edit-post/src/components/sidebar/post-schedule/style.scss +++ b/packages/edit-post/src/components/sidebar/post-schedule/style.scss @@ -6,13 +6,15 @@ span { display: block; - width: 45%; - flex-shrink: 0; - // Match padding on tertiary buttons for alignment. - padding: $grid-unit-15 * 0.5 0; + width: 30%; + margin-right: 8px; } } +.edit-post-post-schedule__dropdown { + width: 70%; +} + .components-button.edit-post-post-schedule__toggle { text-align: left; white-space: normal; diff --git a/packages/edit-post/src/components/sidebar/post-status/index.js b/packages/edit-post/src/components/sidebar/post-status/index.js index 59fdc5d189c946..d903cbb2fa12bc 100644 --- a/packages/edit-post/src/components/sidebar/post-status/index.js +++ b/packages/edit-post/src/components/sidebar/post-status/index.js @@ -7,7 +7,11 @@ import { PanelBody, } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; -import { PostSwitchToDraftButton, PostSyncStatus } from '@wordpress/editor'; +import { + PostSwitchToDraftButton, + PostSyncStatus, + PostURLPanel, +} from '@wordpress/editor'; /** * Internal dependencies @@ -23,7 +27,6 @@ import PostPendingStatus from '../post-pending-status'; import PluginPostStatusInfo from '../plugin-post-status-info'; import { store as editPostStore } from '../../../store'; import PostTemplate from '../post-template'; -import PostURL from '../post-url'; /** * Module Constants @@ -60,7 +63,7 @@ export default function PostStatus() { - + diff --git a/packages/edit-post/src/components/sidebar/post-template/style.scss b/packages/edit-post/src/components/sidebar/post-template/style.scss index caafabbe4227cc..2746fc2eeec4f0 100644 --- a/packages/edit-post/src/components/sidebar/post-template/style.scss +++ b/packages/edit-post/src/components/sidebar/post-template/style.scss @@ -4,9 +4,8 @@ span { display: block; - width: 45%; - // Match padding on tertiary buttons for alignment. - padding: $grid-unit-15 * 0.5 0; + width: 30%; + margin-right: 8px; } } diff --git a/packages/edit-post/src/components/sidebar/post-url/style.scss b/packages/edit-post/src/components/sidebar/post-url/style.scss deleted file mode 100644 index 73a93d477df588..00000000000000 --- a/packages/edit-post/src/components/sidebar/post-url/style.scss +++ /dev/null @@ -1,26 +0,0 @@ -.edit-post-post-url { - width: 100%; - justify-content: flex-start; - align-items: flex-start; - - span { - display: block; - width: 45%; - flex-shrink: 0; - // Match padding on tertiary buttons for alignment. - padding: $grid-unit-15 * 0.5 0; - } -} - -.components-button.edit-post-post-url__toggle { - text-align: left; - white-space: normal; - height: auto; - word-break: break-word; -} - -.edit-post-post-url__dialog .editor-post-url { - // sidebar width - popover padding - form margin - min-width: $sidebar-width - $grid-unit-20 - $grid-unit-20; - margin: $grid-unit-10; -} diff --git a/packages/edit-post/src/components/sidebar/post-visibility/style.scss b/packages/edit-post/src/components/sidebar/post-visibility/style.scss index d578905a482ac1..b3876c8403aa06 100644 --- a/packages/edit-post/src/components/sidebar/post-visibility/style.scss +++ b/packages/edit-post/src/components/sidebar/post-visibility/style.scss @@ -4,9 +4,8 @@ span { display: block; - width: 45%; - // Match padding on tertiary buttons for alignment. - padding: $grid-unit-15 * 0.5 0; + width: 30%; + margin-right: 8px; } } diff --git a/packages/edit-post/src/style.scss b/packages/edit-post/src/style.scss index 60544e7fc3a8ab..7a71d20ba0f1f4 100644 --- a/packages/edit-post/src/style.scss +++ b/packages/edit-post/src/style.scss @@ -15,7 +15,6 @@ @import "./components/sidebar/post-schedule/style.scss"; @import "./components/sidebar/post-slug/style.scss"; @import "./components/sidebar/post-template/style.scss"; -@import "./components/sidebar/post-url/style.scss"; @import "./components/sidebar/post-visibility/style.scss"; @import "./components/sidebar/settings-header/style.scss"; @import "./components/sidebar/template-summary/style.scss"; diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-slug.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-slug.js deleted file mode 100644 index d6ffa1991333ec..00000000000000 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-slug.js +++ /dev/null @@ -1,161 +0,0 @@ -/** - * WordPress dependencies - */ -import { useSelect, useDispatch } from '@wordpress/data'; -import { - safeDecodeURIComponent, - filterURLForDisplay, - cleanForSlug, -} from '@wordpress/url'; -import { useState, useMemo } from '@wordpress/element'; -import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from '@wordpress/block-editor'; -import { __ } from '@wordpress/i18n'; -import { - __experimentalInputControl as InputControl, - __experimentalHStack as HStack, - __experimentalVStack as VStack, - __experimentalText as Text, - Dropdown, - Button, -} from '@wordpress/components'; -import { store as coreStore } from '@wordpress/core-data'; - -export const PERMALINK_POSTNAME_REGEX = /%(?:postname|pagename)%/; - -function getPostPermalink( record, isEditable ) { - if ( ! record?.permalink_template ) { - return; - } - const slug = record?.slug || record?.generated_slug; - const [ prefix, suffix ] = record.permalink_template.split( - PERMALINK_POSTNAME_REGEX - ); - const permalink = isEditable ? prefix + slug + suffix : record.link; - return filterURLForDisplay( safeDecodeURIComponent( permalink ) ); -} - -export default function PageSlug( { postType, postId } ) { - const { editEntityRecord } = useDispatch( coreStore ); - const { record, savedSlug } = useSelect( - ( select ) => { - const { getEntityRecord, getEditedEntityRecord } = - select( coreStore ); - const savedRecord = getEntityRecord( 'postType', postType, postId ); - return { - record: getEditedEntityRecord( 'postType', postType, postId ), - savedSlug: savedRecord?.slug || savedRecord?.generated_slug, - }; - }, - [ postType, postId ] - ); - const [ popoverAnchor, setPopoverAnchor ] = useState( null ); - const [ forceEmptyField, setForceEmptyField ] = useState( false ); - const isEditable = - PERMALINK_POSTNAME_REGEX.test( record?.permalink_template ) && - record?._links?.[ 'wp:action-publish' ]; - const popoverProps = useMemo( - () => ( { - // Anchor the popover to the middle of the entire row so that it doesn't - // move around when the label changes. - anchor: popoverAnchor, - 'aria-label': __( 'Change slug' ), - placement: 'bottom-end', - } ), - [ popoverAnchor ] - ); - if ( ! record || ! isEditable ) { - return null; - } - const recordSlug = safeDecodeURIComponent( - record?.slug || record?.generated_slug - ); - const permaLink = getPostPermalink( record, isEditable ); - const onSlugChange = ( newValue ) => { - editEntityRecord( 'postType', postType, postId, { - slug: newValue, - } ); - }; - return ( - - - { __( 'URL' ) } - - { - if ( forceEmptyField ) { - onSlugChange( cleanForSlug( savedSlug ) ); - setForceEmptyField( false ); - } - } } - renderToggle={ ( { onToggle } ) => ( - - ) } - renderContent={ ( { onClose } ) => { - return ( - <> - - - - { - onSlugChange( newValue ); - // When we delete the field the permalink gets - // reverted to the original value. - // The forceEmptyField logic allows the user to have - // the field temporarily empty while typing. - if ( ! newValue ) { - if ( ! forceEmptyField ) { - setForceEmptyField( true ); - } - return; - } - if ( forceEmptyField ) { - setForceEmptyField( false ); - } - } } - onBlur={ ( event ) => { - onSlugChange( - cleanForSlug( - event.target.value || - savedSlug - ) - ); - if ( forceEmptyField ) { - setForceEmptyField( false ); - } - } } - /> - - - - ); - } } - /> - - ); -} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js index 25b69985bcbd6e..26fa86c933f115 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js @@ -2,13 +2,14 @@ * WordPress dependencies */ import { __experimentalVStack as VStack } from '@wordpress/components'; +import { PostURLPanel } from '@wordpress/editor'; + /** * Internal dependencies */ import PageStatus from './page-status'; import PublishDate from './publish-date'; import EditTemplate from './edit-template'; -import PageSlug from './page-slug'; export default function PageSummary( { status, @@ -33,7 +34,7 @@ export default function PageSummary( { postType={ postType } /> - + ); } 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 64d72db4e15fd7..acaf5cbfe35dde 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 @@ -90,11 +90,3 @@ color: inherit; } } - -.edit-site-page-panels-edit-slug__dropdown { - .components-popover__content { - min-width: 320px; - padding: $grid-unit-20; - } -} - diff --git a/packages/editor/src/components/index.js b/packages/editor/src/components/index.js index 39b562806c109a..bcfccc026ff727 100644 --- a/packages/editor/src/components/index.js +++ b/packages/editor/src/components/index.js @@ -71,6 +71,7 @@ export { default as PostTypeSupportCheck } from './post-type-support-check'; export { default as PostURL } from './post-url'; export { default as PostURLCheck } from './post-url/check'; export { default as PostURLLabel, usePostURLLabel } from './post-url/label'; +export { default as PostURLPanel } from './post-url/panel'; export { default as PostVisibility } from './post-visibility'; export { default as PostVisibilityLabel, diff --git a/packages/editor/src/components/post-sync-status/style.scss b/packages/editor/src/components/post-sync-status/style.scss index 90a75c86bf466d..e18eead94ac835 100644 --- a/packages/editor/src/components/post-sync-status/style.scss +++ b/packages/editor/src/components/post-sync-status/style.scss @@ -6,9 +6,8 @@ > span { display: block; - width: 45%; - flex-shrink: 0; - padding: $grid-unit-15 * 0.5 0; + width: 30%; + margin-right: 8px; word-break: break-word; } diff --git a/packages/edit-post/src/components/sidebar/post-url/index.js b/packages/editor/src/components/post-url/panel.js similarity index 68% rename from packages/edit-post/src/components/sidebar/post-url/index.js rename to packages/editor/src/components/post-url/panel.js index 1dc1b8d804cd77..1fddc7df9922c4 100644 --- a/packages/edit-post/src/components/sidebar/post-url/index.js +++ b/packages/editor/src/components/post-url/panel.js @@ -2,15 +2,21 @@ * WordPress dependencies */ import { useMemo, useState } from '@wordpress/element'; -import { PanelRow, Dropdown, Button } from '@wordpress/components'; -import { __, sprintf } from '@wordpress/i18n'; import { - PostURLCheck, - PostURL as PostURLForm, - usePostURLLabel, -} from '@wordpress/editor'; + __experimentalHStack as HStack, + Dropdown, + Button, +} from '@wordpress/components'; +import { __, sprintf } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import PostURLCheck from './check'; +import PostURL from './index'; +import { usePostURLLabel } from './label'; -export default function PostURL() { +export default function PostURLPanel() { // Use internal state instead of a ref to make sure that the component // re-renders when the popover's anchor updates. const [ popoverAnchor, setPopoverAnchor ] = useState( null ); @@ -22,21 +28,21 @@ export default function PostURL() { return ( - + { __( 'URL' ) } ( ) } renderContent={ ( { onClose } ) => ( - + ) } /> - + ); } @@ -45,7 +51,7 @@ function PostURLToggle( { isOpen, onClick } ) { const label = usePostURLLabel(); return (
) } From 3875618390ccf37c2df36d2ab4b7e249bc161660 Mon Sep 17 00:00:00 2001 From: Siobhan Bamber Date: Thu, 16 Nov 2023 14:44:07 +0000 Subject: [PATCH 052/116] [RNMobile] Ensure uploaded audio is always visible within Audio block (#55627) Ensure the Audio block is always visible when media's been uploaded to it. --- packages/components/src/index.native.js | 1 + .../src/mobile/audio-player/index.native.js | 22 ++++------ .../global-styles-context/utils.native.js | 44 +++++++++++++++++++ packages/react-native-editor/CHANGELOG.md | 1 + 4 files changed, 55 insertions(+), 13 deletions(-) diff --git a/packages/components/src/index.native.js b/packages/components/src/index.native.js index 9a66a62f98e187..f88399fbee2878 100644 --- a/packages/components/src/index.native.js +++ b/packages/components/src/index.native.js @@ -141,4 +141,5 @@ export { getGlobalStyles, getColorsAndGradients, useMobileGlobalStylesColors, + useEditorColorScheme, } from './mobile/global-styles-context/utils'; diff --git a/packages/components/src/mobile/audio-player/index.native.js b/packages/components/src/mobile/audio-player/index.native.js index ad8f0dcb2e9e8d..c5d7c0e8132c1e 100644 --- a/packages/components/src/mobile/audio-player/index.native.js +++ b/packages/components/src/mobile/audio-player/index.native.js @@ -14,7 +14,7 @@ import { default as VideoPlayer } from 'react-native-video'; * WordPress dependencies */ import { View } from '@wordpress/primitives'; -import { Icon } from '@wordpress/components'; +import { Icon, useEditorColorScheme } from '@wordpress/components'; import { withPreferredColorScheme } from '@wordpress/compose'; import { __ } from '@wordpress/i18n'; import { audio, warning } from '@wordpress/icons'; @@ -34,7 +34,6 @@ import { parseAudioUrl } from './audio-url-parser.native'; const isIOS = Platform.OS === 'ios'; function Player( { - getStylesFromColorScheme, isUploadInProgress, isUploadFailed, attributes, @@ -70,14 +69,14 @@ function Player( { } }; - const containerStyle = getStylesFromColorScheme( + const containerStyle = useEditorColorScheme( styles.container, styles.containerDark ); - const iconStyle = getStylesFromColorScheme( styles.icon, styles.iconDark ); + const iconStyle = useEditorColorScheme( styles.icon, styles.iconDark ); - const iconDisabledStyle = getStylesFromColorScheme( + const iconDisabledStyle = useEditorColorScheme( styles.iconDisabled, styles.iconDisabledDark ); @@ -89,7 +88,7 @@ function Player( { ...( isDisabled && iconDisabledStyle ), }; - const iconContainerStyle = getStylesFromColorScheme( + const iconContainerStyle = useEditorColorScheme( styles.iconContainer, styles.iconContainerDark ); @@ -99,17 +98,14 @@ function Player( { ...( isIOS ? styles.titleContainerIOS : styles.titleContainerAndroid ), }; - const titleStyle = getStylesFromColorScheme( - styles.title, - styles.titleDark - ); + const titleStyle = useEditorColorScheme( styles.title, styles.titleDark ); - const uploadFailedStyle = getStylesFromColorScheme( + const uploadFailedStyle = useEditorColorScheme( styles.uploadFailed, styles.uploadFailedDark ); - const subtitleStyle = getStylesFromColorScheme( + const subtitleStyle = useEditorColorScheme( styles.subtitle, styles.subtitleDark ); @@ -119,7 +115,7 @@ function Player( { ...( isUploadFailed && uploadFailedStyle ), }; - const buttonBackgroundStyle = getStylesFromColorScheme( + const buttonBackgroundStyle = useEditorColorScheme( styles.buttonBackground, styles.buttonBackgroundDark ); diff --git a/packages/components/src/mobile/global-styles-context/utils.native.js b/packages/components/src/mobile/global-styles-context/utils.native.js index f7ce110060eb4a..f2cbcae9c3f3e7 100644 --- a/packages/components/src/mobile/global-styles-context/utils.native.js +++ b/packages/components/src/mobile/global-styles-context/utils.native.js @@ -3,6 +3,7 @@ */ import { camelCase } from 'change-case'; import { Dimensions } from 'react-native'; +import { colord } from 'colord'; /** * WordPress dependencies @@ -13,6 +14,12 @@ import { useMultipleOriginColorsAndGradients, SETTINGS_DEFAULTS, } from '@wordpress/block-editor'; +import { usePreferredColorSchemeStyle } from '@wordpress/compose'; + +/** + * Internal dependencies + */ +import { useGlobalStyles } from './index.native'; export const BLOCK_STYLE_ATTRIBUTES = [ 'textColor', @@ -441,3 +448,40 @@ export function getGlobalStyles( rawStyles, rawFeatures ) { __experimentalGlobalStylesBaseStyles: globalStyles, }; } + +/** + * Determine and apply appropriate color scheme based on global styles or device's light/dark mode. + * + * The function first attempts to retrieve the editor's background color from global styles. + * If the detected background color is light, light styles are applied, and dark styles otherwise. + * If no custom background color is defined, styles are applied using the device's dark/light setting. + * + * @param {Object} baseStyle - An object representing the base (light theme) styles for the editor. + * @param {Object} darkStyle - An object representing the additional styles to apply when the editor is in dark mode. + * + * @return {Object} - The combined style object that should be applied to the editor. + */ +export const useEditorColorScheme = ( baseStyle, darkStyle ) => { + const globalStyles = useGlobalStyles(); + + const deviceColorScheme = usePreferredColorSchemeStyle( + baseStyle, + darkStyle + ); + + const editorColors = globalStyles?.baseColors?.color; + const editorBackgroundColor = editorColors?.background; + + const isBackgroundColorDefined = + typeof editorBackgroundColor !== 'undefined' && + editorBackgroundColor !== 'undefined'; + + if ( isBackgroundColorDefined ) { + const isEditorBackgroundDark = colord( editorBackgroundColor ).isDark(); + return isEditorBackgroundDark + ? { ...baseStyle, ...darkStyle } + : baseStyle; + } + + return deviceColorScheme; +}; diff --git a/packages/react-native-editor/CHANGELOG.md b/packages/react-native-editor/CHANGELOG.md index 1a7de1314288bc..2fef3d50be3389 100644 --- a/packages/react-native-editor/CHANGELOG.md +++ b/packages/react-native-editor/CHANGELOG.md @@ -10,6 +10,7 @@ For each user feature we should also add a importance categorization label to i --> ## Unreleased +- [*] Audio block: Improve legibility of audio file details on various background colors [#55627] ## 1.108.0 - [*] Fix error when pasting deeply nested structure content [#55613] From 7cde29293f8a09b868c31e17598f5f961e6a6176 Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Thu, 16 Nov 2023 16:01:02 +0000 Subject: [PATCH 053/116] Bump plugin version to 17.1.0-rc.1 --- gutenberg.php | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gutenberg.php b/gutenberg.php index 8a8b1db6f85b92..3ccde2667f03aa 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -5,7 +5,7 @@ * Description: Printing since 1440. This is the development plugin for the block editor, site editor, and other future WordPress core functionality. * Requires at least: 6.2 * Requires PHP: 7.0 - * Version: 17.0.2 + * Version: 17.1.0-rc.1 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/package-lock.json b/package-lock.json index 28f51a1408f64d..158d3ab9e25c14 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gutenberg", - "version": "17.0.2", + "version": "17.1.0-rc.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "gutenberg", - "version": "17.0.2", + "version": "17.1.0-rc.1", "hasInstallScript": true, "license": "GPL-2.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 2c3313b9337d41..eea10b3180540b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "17.0.2", + "version": "17.1.0-rc.1", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", From bc73a3d3461f8db4f705c137da9ef909d068649f Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Thu, 16 Nov 2023 16:31:31 +0000 Subject: [PATCH 054/116] Update Changelog for 17.1.0-rc.1 --- changelog.txt | 328 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) diff --git a/changelog.txt b/changelog.txt index 8159928bd84fb4..2435ab1eceb4ab 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,333 @@ == Changelog == += 17.1.0-rc.1 = + + + +## Changelog + +### Enhancements + +#### Block Library +- Navigation block: Fix Inaccurate description of the Show icon button setting. ([55429](https://github.com/WordPress/gutenberg/pull/55429)) +- Query Loop: Add accesibility markup at the end of the loop in all cases. ([55890](https://github.com/WordPress/gutenberg/pull/55890)) +- Template Part: Add fallback to the current theme when not provided. ([55965](https://github.com/WordPress/gutenberg/pull/55965)) +- Update components to use __next40pxDefaultSize. ([56022](https://github.com/WordPress/gutenberg/pull/56022)) + +#### Components +- Tabs: Improve focus behavior. ([55287](https://github.com/WordPress/gutenberg/pull/55287)) +- Tabs: Update subcomponents to accept full HTML element props. ([55860](https://github.com/WordPress/gutenberg/pull/55860)) +- TextControl: Add opt-in prop for 40px default size. ([55471](https://github.com/WordPress/gutenberg/pull/55471)) +- ToggleGroupControl: Add opt-in prop for 40px default size. ([55789](https://github.com/WordPress/gutenberg/pull/55789)) + +#### Patterns +- Move "Manage patterns" below "Detach pattern". ([56018](https://github.com/WordPress/gutenberg/pull/56018)) +- Show theme patterns from directory in site editor. ([55877](https://github.com/WordPress/gutenberg/pull/55877)) + +#### Global Styles +- Global Style Revisions: Ensure consistent back button behaviour. ([55881](https://github.com/WordPress/gutenberg/pull/55881)) +- Global Styles Revisions: More descriptive text timeline. ([55868](https://github.com/WordPress/gutenberg/pull/55868)) +- Global styles revisions: Add route for single styles revisions. ([55827](https://github.com/WordPress/gutenberg/pull/55827)) + +#### Block Locking +- Block Quick Navigation: Truncate text. ([56142](https://github.com/WordPress/gutenberg/pull/56142)) + +#### Block Editor +- Button block: Support double enter to skip to default block. ([56134](https://github.com/WordPress/gutenberg/pull/56134)) + +#### Design Tools +- Add block gap support to Quote block. ([56064](https://github.com/WordPress/gutenberg/pull/56064)) + +#### Post Editor +- "Detach" text change in template options. ([55870](https://github.com/WordPress/gutenberg/pull/55870)) + +#### Site Editor +- Site editor: Add edit page slug field. ([55767](https://github.com/WordPress/gutenberg/pull/55767)) + +#### Interactivity API +- Server directive processing: Process only root blocks. ([55739](https://github.com/WordPress/gutenberg/pull/55739)) + +#### Block settings menu +- Remove the extraneous template part title in replace control. ([55603](https://github.com/WordPress/gutenberg/pull/55603)) + +#### List View +- Add keyboard shortcut to select all blocks. ([54899](https://github.com/WordPress/gutenberg/pull/54899)) + + +### New APIs + +- Download blob: Remove downloadjs dependency. ([56024](https://github.com/WordPress/gutenberg/pull/56024)) + + +### Bug Fixes + +#### Block Library +- Background Image Support: Hide the background image reset button when there's no image. ([55973](https://github.com/WordPress/gutenberg/pull/55973)) +- Background image support: Fix focus loss when resetting background image. ([55984](https://github.com/WordPress/gutenberg/pull/55984)) +- Custom Link: Decode value in URL input field. ([55549](https://github.com/WordPress/gutenberg/pull/55549)) +- Fix lightbox trigger styles. ([55859](https://github.com/WordPress/gutenberg/pull/55859)) +- Form block: Use `type="submit"` for buttons. ([55690](https://github.com/WordPress/gutenberg/pull/55690)) +- Image block: Add check for lightbox values during image block migration. ([56057](https://github.com/WordPress/gutenberg/pull/56057)) +- Image block: Don't show pointer cursor on linked image in the editor. ([55882](https://github.com/WordPress/gutenberg/pull/55882)) +- Lightbox: Fix button misalignment in gallery image. ([56060](https://github.com/WordPress/gutenberg/pull/56060)) +- Lightbox: Fix close button position. ([56125](https://github.com/WordPress/gutenberg/pull/56125)) +- Missing block: Use raw source for originalContent. ([56014](https://github.com/WordPress/gutenberg/pull/56014)) +- Navigation Link block: Register variations on post type / taxonomy registration. ([54801](https://github.com/WordPress/gutenberg/pull/54801)) +- Pattern: Fix regression error in post type templates. ([55858](https://github.com/WordPress/gutenberg/pull/55858)) +- Pattern: Process embeds. ([55979](https://github.com/WordPress/gutenberg/pull/55979)) +- Post feature image block: Wrap images with hrefs in an A tag. ([55498](https://github.com/WordPress/gutenberg/pull/55498)) +- Quote Block: Fix the Quote block layout supports. ([55240](https://github.com/WordPress/gutenberg/pull/55240)) +- Read More block: Reduce text decoration specificity. ([56038](https://github.com/WordPress/gutenberg/pull/56038)) + +#### Data Views +- DataViews: Add missing key to `ResetFilters` component. ([56189](https://github.com/WordPress/gutenberg/pull/56189)) +- DataViews: Fix issue with irrelevant statuses. ([55967](https://github.com/WordPress/gutenberg/pull/55967)) +- DataViews: Fix nested button tags on sidebar. ([56089](https://github.com/WordPress/gutenberg/pull/56089)) +- DataViews: Fix pagination on manual input. ([55940](https://github.com/WordPress/gutenberg/pull/55940)) +- DataViews: Fix spacing issue in top-level bar. ([56151](https://github.com/WordPress/gutenberg/pull/56151)) +- DataViews: Fix status filter upon switching the default views from the sidebar. ([55856](https://github.com/WordPress/gutenberg/pull/55856)) +- DataViews: Make items per page an even number. ([55906](https://github.com/WordPress/gutenberg/pull/55906)) +- DataViews: Make used taxonomy private. ([55918](https://github.com/WordPress/gutenberg/pull/55918)) +- DataViews: Reset pagination upon filter change. ([55797](https://github.com/WordPress/gutenberg/pull/55797)) +- Dataviews: Add a missing icon for the side by side view. ([55925](https://github.com/WordPress/gutenberg/pull/55925)) + +#### Components +- DropdownMenu: Remove extra vertical space around the toggle button. ([56136](https://github.com/WordPress/gutenberg/pull/56136)) +- DropdownMenuV2: Prevent default on Escape key presses. ([55962](https://github.com/WordPress/gutenberg/pull/55962)) +- DropdownMenuV2: Use the `Icon` component to render radio checks. ([55964](https://github.com/WordPress/gutenberg/pull/55964)) + +#### Typography +- Fix fatal error in WP_Fonts_Resolver::Get_settings(). ([55981](https://github.com/WordPress/gutenberg/pull/55981)) +- Font Library: Create fonts dir if a font face needs to use the filesystem. ([56120](https://github.com/WordPress/gutenberg/pull/56120)) +- Font Library: Fix font installation failure. ([55893](https://github.com/WordPress/gutenberg/pull/55893)) + +#### Block Editor +- Iframe: Bubble events from html element instead of body element to fix drag chip positioning. ([56099](https://github.com/WordPress/gutenberg/pull/56099)) +- Post Featured Image: Handling correctly when uploading a file without mime type. ([56133](https://github.com/WordPress/gutenberg/pull/56133)) +- Block Editor: Fix Block editor crash. ([56051](https://github.com/WordPress/gutenberg/pull/56051)) +- Move clientId key to BlockContextualToolbar. ([56008](https://github.com/WordPress/gutenberg/pull/56008)) + +#### Patterns +- Add context for translators to any unclear usage of "synced". ([55935](https://github.com/WordPress/gutenberg/pull/55935)) +- Use existing download function for JSON downloads to fix non-ASCII encoding. ([55912](https://github.com/WordPress/gutenberg/pull/55912)) + +#### Inspector Controls +- Global Styles: Don't show "Apply Styles Globally" button in non-block based themes. ([56033](https://github.com/WordPress/gutenberg/pull/56033)) + +#### Template Editor +- Templates: Update filter to call all of the individual methods. ([55980](https://github.com/WordPress/gutenberg/pull/55980)) + +#### Global Styles +- Global styles revisions: Load unsaved revision item into the revisions preview. ([55880](https://github.com/WordPress/gutenberg/pull/55880)) + +#### Post Editor +- Edit Post: Fix pattern modal reopening when making the title empty again. ([55873](https://github.com/WordPress/gutenberg/pull/55873)) + +#### Data Layer +- Core data: Fix wrong store results when page receives less items that what is stored. ([55832](https://github.com/WordPress/gutenberg/pull/55832)) + + +### Accessibility + +#### Data Views +- DataViews: Add labels to "in-filters". ([56001](https://github.com/WordPress/gutenberg/pull/56001)) +- DataViews: Show actions label. ([56027](https://github.com/WordPress/gutenberg/pull/56027)) + +#### Components +- Fix the image link button pressed state. ([56123](https://github.com/WordPress/gutenberg/pull/56123)) + +#### Block Editor +- Fix mismatching link control action buttons visual order and DOM order. ([56042](https://github.com/WordPress/gutenberg/pull/56042)) +- Escape on Block Toolbar returns focus to Editor Canvas. ([55712](https://github.com/WordPress/gutenberg/pull/55712)) + +#### Site Editor +- Prevent sidebar focus in site editor on small screens. ([55934](https://github.com/WordPress/gutenberg/pull/55934)) + +#### Block Library +- Heading level dropdown: Remove obtrusive tooltips in favor of visible text. ([56035](https://github.com/WordPress/gutenberg/pull/56035)) + + +### Performance + +#### Tooling +- Add a metric to trace template navigation in the site editor. ([55796](https://github.com/WordPress/gutenberg/pull/55796)) + +#### List View +- ListViewBlock: Combine 'useSelect' hooks. ([55889](https://github.com/WordPress/gutenberg/pull/55889)) + +#### Block Editor +- Block Editor: Optimize 'Block Hooks' inspector controls. ([56101](https://github.com/WordPress/gutenberg/pull/56101)) +- Block Editor: Optimize BlockListAppender. ([56116](https://github.com/WordPress/gutenberg/pull/56116)) + +#### Site Editor +- Avoid rerendering the sitehub unnecessarily. ([55818](https://github.com/WordPress/gutenberg/pull/55818)) + +#### Layout +- Block Editor: Optimize layout style renderer subscription. ([55762](https://github.com/WordPress/gutenberg/pull/55762)) + + +### Experiments + +#### Data Views +- DataViews: Add ability to create custom views. ([55773](https://github.com/WordPress/gutenberg/pull/55773)) +- DataViews: Add control to reset all filters at once. ([55955](https://github.com/WordPress/gutenberg/pull/55955)) +- DataViews: Add delete and restore actions. ([55781](https://github.com/WordPress/gutenberg/pull/55781)) +- DataViews: Add initial "Side by side" prototype. ([55343](https://github.com/WordPress/gutenberg/pull/55343)) +- DataViews: Add new page size option. ([56112](https://github.com/WordPress/gutenberg/pull/56112)) +- DataViews: Add rename functionality to custom views. ([55997](https://github.com/WordPress/gutenberg/pull/55997)) +- DataViews: Allow users to add filters dynamically. ([55992](https://github.com/WordPress/gutenberg/pull/55992)) +- DataViews: Update 'All pages' sidebar heading. ([56148](https://github.com/WordPress/gutenberg/pull/56148)) +- DataViews: Update 'View' button. ([56144](https://github.com/WordPress/gutenberg/pull/56144)) +- DataViews: Update `all templates` page. ([55848](https://github.com/WordPress/gutenberg/pull/55848)) +- DataViews: Update author and title fields in template's list. ([56029](https://github.com/WordPress/gutenberg/pull/56029)) +- DataViews: Update filters in view configuration. ([55735](https://github.com/WordPress/gutenberg/pull/55735)) +- DataViews: Add filters to table columns. ([55508](https://github.com/WordPress/gutenberg/pull/55508)) +- DataViews: Add: Ability to delete custom views. ([55924](https://github.com/WordPress/gutenberg/pull/55924)) +- DataViews: Add: Custom views header indication. ([55926](https://github.com/WordPress/gutenberg/pull/55926)) +- DataViews: Remove unnecessary label when no visible filters exist. ([55838](https://github.com/WordPress/gutenberg/pull/55838)) + + +### Documentation + +- Add a first block type page to the platform documentation. ([56109](https://github.com/WordPress/gutenberg/pull/56109)) +- Add new block development "Quick Start Guide" and update the `create-block-tutorial-template`. ([56056](https://github.com/WordPress/gutenberg/pull/56056)) +- Clean up DataViews docs: `filter.id` is not used. ([55833](https://github.com/WordPress/gutenberg/pull/55833)) +- DataViews: Document `enableSorting` and `enableHiding`. ([55988](https://github.com/WordPress/gutenberg/pull/55988)) +- DataViews: Document actions. ([55959](https://github.com/WordPress/gutenberg/pull/55959)) +- Doc: Corrected + updated links. ([56084](https://github.com/WordPress/gutenberg/pull/56084)) +- Doc: Fixes wrong link in #56084. ([56106](https://github.com/WordPress/gutenberg/pull/56106)) +- Docs: Changes imports from `wp.editor` to `wp.blockEditor` for PlainText and RichText. ([55841](https://github.com/WordPress/gutenberg/pull/55841)) +- Fix formatting issue in the "Get started with create-block" doc. ([55872](https://github.com/WordPress/gutenberg/pull/55872)) +- Fix: 404 Link on git workflow docs. ([55897](https://github.com/WordPress/gutenberg/pull/55897)) +- Fix: 404 link in get-started-with-create-block docs. ([55932](https://github.com/WordPress/gutenberg/pull/55932)) +- Fix: Create meta block link in block attributes documentation. ([55804](https://github.com/WordPress/gutenberg/pull/55804)) +- Fix: Filter duotone link on block-supports documentation. ([55896](https://github.com/WordPress/gutenberg/pull/55896)) +- Fix: Two invalid links on docs/contributors/documentation/README.md. ([55843](https://github.com/WordPress/gutenberg/pull/55843)) +- New additional resource for wp-env. ([55987](https://github.com/WordPress/gutenberg/pull/55987)) +- Update documentation to clarify workflow branch for release package publishing. ([56183](https://github.com/WordPress/gutenberg/pull/56183)) +- Update jest links to the new site. ([55802](https://github.com/WordPress/gutenberg/pull/55802)) + + +### Code Quality + +- Block lib: Remove multiline=false (deprecated). ([56113](https://github.com/WordPress/gutenberg/pull/56113)) +- Delete unused `SelectedBlockPopover` component. ([55821](https://github.com/WordPress/gutenberg/pull/55821)) +- Fix: Remove unrequired nullish coalescing. ([55854](https://github.com/WordPress/gutenberg/pull/55854)) +- Fix: Use of integer value in a conditional rendering condition on Gradients. ([55855](https://github.com/WordPress/gutenberg/pull/55855)) +- Give nice unique names to block controls HOCs. ([55795](https://github.com/WordPress/gutenberg/pull/55795)) +- Migrating `PatternTransformationsMenu`. ([56122](https://github.com/WordPress/gutenberg/pull/56122)) +- Migrating block inserter media tab components. ([56195](https://github.com/WordPress/gutenberg/pull/56195)) +- Move document tools motion to header-edit-mode layout level. ([55904](https://github.com/WordPress/gutenberg/pull/55904)) +- Only render block toolbar if blockType has value. ([55861](https://github.com/WordPress/gutenberg/pull/55861)) +- Refactor Edit Widgets Document Tools Navigation to own component. ([55778](https://github.com/WordPress/gutenberg/pull/55778)) +- Refactor Selected Block Tools. ([55737](https://github.com/WordPress/gutenberg/pull/55737)) +- Refactor Site Editor Document Tools Navigation to own component. ([55770](https://github.com/WordPress/gutenberg/pull/55770)) +- Remove BlockStyles.Slot empty component. ([55991](https://github.com/WordPress/gutenberg/pull/55991)) +- Remove obsolete `queryContext`. ([56034](https://github.com/WordPress/gutenberg/pull/56034)) +- Remove unnecessary empty className. ([55998](https://github.com/WordPress/gutenberg/pull/55998)) +- Rename Unforward to Unforwarded and export the named const. ([55820](https://github.com/WordPress/gutenberg/pull/55820)) +- Render Selected Block Tools in Header when using Top Toolbar. ([55787](https://github.com/WordPress/gutenberg/pull/55787)) +- Reusable Blocks: Unlock a private hook and a component at the file level. ([55809](https://github.com/WordPress/gutenberg/pull/55809)) +- Server directive processing: Improve how block references are saved. ([56107](https://github.com/WordPress/gutenberg/pull/56107)) +- Share the editor settings between the post and site editors. ([55970](https://github.com/WordPress/gutenberg/pull/55970)) +- Site Editor: Fix deprecation console error in top toolbar. ([55678](https://github.com/WordPress/gutenberg/pull/55678)) +- Site Editor: Unlock global styles' private hooks at the file level. ([55800](https://github.com/WordPress/gutenberg/pull/55800)) +- Site Editor: Update edited entity sync logic. ([55928](https://github.com/WordPress/gutenberg/pull/55928)) +- Site Editor: Use EditorProvider instead of custom logic. ([56000](https://github.com/WordPress/gutenberg/pull/56000)) +- SiteEditor: Optimize BackToPageNotification component. ([56102](https://github.com/WordPress/gutenberg/pull/56102)) +- SiteEditor: Refactor disable non page content blocks. ([56103](https://github.com/WordPress/gutenberg/pull/56103)) +- Unify the PageUrl and PageSlug components between site and post editors. ([56203](https://github.com/WordPress/gutenberg/pull/56203)) + +#### Data Views +- DataViews: Fix translatable string. ([56075](https://github.com/WordPress/gutenberg/pull/56075)) +- DataViews: Remove `filter.name`. ([55834](https://github.com/WordPress/gutenberg/pull/55834)) +- DataViews: Remove reset values from filters. ([55839](https://github.com/WordPress/gutenberg/pull/55839)) +- DataViews: Remove unnecessary `sortingFn` prop from field description. ([55989](https://github.com/WordPress/gutenberg/pull/55989)) +- DataViews: Simplify filters API. ([55917](https://github.com/WordPress/gutenberg/pull/55917)) +- DataViews: Update actions API. ([56026](https://github.com/WordPress/gutenberg/pull/56026)) + +#### Block Editor +- Rich text: Remove preserveWhiteSpace serialisation differences. ([55999](https://github.com/WordPress/gutenberg/pull/55999)) +- Rich text: highlight format: Gracefully handle old span format. ([56071](https://github.com/WordPress/gutenberg/pull/56071)) +- Update Link Control labels to use gray-900. ([55867](https://github.com/WordPress/gutenberg/pull/55867)) + +#### Components +- `DisclosureContent`: Migrate from `reakit` to `@ariakit/react`. ([55639](https://github.com/WordPress/gutenberg/pull/55639)) +- `Divider`: Migrate from `reakit` to `@ariakit/react`. ([55622](https://github.com/WordPress/gutenberg/pull/55622)) +- `RadioGroup`: Migrate from `reakit` to `ariakit`. ([55580](https://github.com/WordPress/gutenberg/pull/55580)) + +#### Site Editor +- Core Data: Move the template lookup to core-data selectors/resolvers. ([55883](https://github.com/WordPress/gutenberg/pull/55883)) +- Don't use 'useEntityRecord' to only dispatch actions. ([56076](https://github.com/WordPress/gutenberg/pull/56076)) + +#### Block Library +- Navigation: Refactor the PHP render function to make it easier to make changes in the future. ([55605](https://github.com/WordPress/gutenberg/pull/55605)) +- Update `blockEditor.__unstableCanInsertBlockType` hook namespace. ([55845](https://github.com/WordPress/gutenberg/pull/55845)) + +#### Data Layer +- Data: Fix ESLint warnings for the 'useSelect' hook. ([55916](https://github.com/WordPress/gutenberg/pull/55916)) + +#### Post Editor +- Edit Post: Use a single 'useSelect' hook for getting selectors. ([55902](https://github.com/WordPress/gutenberg/pull/55902)) + +#### Colors +- Add Unit testing for duotone enhanced pagination. ([55542](https://github.com/WordPress/gutenberg/pull/55542)) + +#### Patterns +- Split up the block editor inserter patterns tab into separate component files. ([55315](https://github.com/WordPress/gutenberg/pull/55315)) + +#### Design Tools +- Block styles: Remove __unstableElementContext in favour of useStyleOverride. ([54493](https://github.com/WordPress/gutenberg/pull/54493)) + + +### Tools + +- Issue Templates: Add default type labels to issue templates. ([55826](https://github.com/WordPress/gutenberg/pull/55826)) +- Label enforcer: Make the warning message less scary for new contributors. ([55900](https://github.com/WordPress/gutenberg/pull/55900)) +- Quote feature request label. ([55862](https://github.com/WordPress/gutenberg/pull/55862)) + +#### Testing +- Disable 'no-conditional-in-test' ESLint rule for Playwright. ([56088](https://github.com/WordPress/gutenberg/pull/56088)) +- Fix 'Block Switcher' test file name for Playwright end-to-end tests. ([55840](https://github.com/WordPress/gutenberg/pull/55840)) +- Fix flaky 'Meta boxes' end-to-end tests. ([56083](https://github.com/WordPress/gutenberg/pull/56083)) +- Migrate 'CPT locking' end-to-end tests to Playwright. ([55929](https://github.com/WordPress/gutenberg/pull/55929)) +- Migrate 'Meta boxes' end-to-end tests to Playwright. ([55915](https://github.com/WordPress/gutenberg/pull/55915)) +- Migrate 'Plugins API' end-to-end tests to Playwright. ([55958](https://github.com/WordPress/gutenberg/pull/55958)) +- Migrate 'annotations' end-to-end tests to Playwright. ([55966](https://github.com/WordPress/gutenberg/pull/55966)) +- Migrate 'container blocks' end-to-end tests to Playwright. ([56141](https://github.com/WordPress/gutenberg/pull/56141)) +- Migrate 'inner-blocks-prioritized-inserter-blocks' end-to-end tests to Playwright. ([55828](https://github.com/WordPress/gutenberg/pull/55828)) +- Migrate 'inner-blocks-render-appender' end-to-end tests to Playwright. ([55814](https://github.com/WordPress/gutenberg/pull/55814)) +- Migrate 'meta-attribute-block' end-to-end tests to Playwright. ([55830](https://github.com/WordPress/gutenberg/pull/55830)) +- Migrate Child Block Test to Playwright. ([55199](https://github.com/WordPress/gutenberg/pull/55199)) +- Migrate flaky PostPublishButton end-to-end tests to Playwright. ([52285](https://github.com/WordPress/gutenberg/pull/52285)) +- Perf Tests: Stabilise the Site Editor metrics. ([55922](https://github.com/WordPress/gutenberg/pull/55922)) +- Playwright Utils: Fix 'clickBlockOptionsMenuItem' helper. ([55923](https://github.com/WordPress/gutenberg/pull/55923)) +- Query block enhanced pagination: Simplify test setup. ([55805](https://github.com/WordPress/gutenberg/pull/55805)) +- Site editor template preview: Add end-to-end test and aria-pressed attribute to template preview toggle. ([56096](https://github.com/WordPress/gutenberg/pull/56096)) +- Upgrade Playwright to 1.39.0. ([54051](https://github.com/WordPress/gutenberg/pull/54051)) +- end-to-end Utils: Add setPreferences and editPost utils. ([55099](https://github.com/WordPress/gutenberg/pull/55099)) +- end-to-end Utils: Add support for web-vitals.js. ([55660](https://github.com/WordPress/gutenberg/pull/55660)) + +#### Build Tooling +- Package `@ariakit/test` should be a dev dependency. ([56091](https://github.com/WordPress/gutenberg/pull/56091)) + + +## First time contributors + +The following PRs were merged by first time contributors: + +- @joanrodas: Update Link Control labels to use gray-900. ([55867](https://github.com/WordPress/gutenberg/pull/55867)) +- @JorgeVilchez95: "Detach" text change in template options. ([55870](https://github.com/WordPress/gutenberg/pull/55870)) +- @sacerro: Styles: More descriptive text for revisions timeline. ([55868](https://github.com/WordPress/gutenberg/pull/55868)) + + +## Contributors + +The following contributors merged PRs in this release: + +@afercia @andrewhayward @andrewserong @anomiex @anton-vlasenko @aristath @artemiomorales @bph @brookewp @c4rl0sbr4v0 @chad1008 @ciampo @DAreRodz @dcalhoun @dsas @ellatrix @flootr @fluiddot @gaambo @glendaviesnz @gziolo @jameskoster @jeryj @jhnstn @joanrodas @jorgefilipecosta @JorgeVilchez95 @jsnajdr @juanmaguitar @kevin940726 @Mamaduka @masteradhoc @matiasbenedetto @ndiego @ntsekouras @oandregal @peterwilsoncc @pooja-muchandikar @priethor @ramonjd @renatho @richtabor @sacerro @scruffian @shimotmk @SiobhyB @Soean @swissspidy @t-hamano @talldan @tellthemachines @torounit @tyxla @WunderBart @youknowriad + + = 17.0.2 = From 55c6741fa53338c9b695a0ceab3567faaea58f0b Mon Sep 17 00:00:00 2001 From: annezazu Date: Thu, 16 Nov 2023 09:08:37 -0800 Subject: [PATCH 055/116] Update for 6.4.1 for versions in WP (#56216) --- docs/contributors/versions-in-wordpress.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/contributors/versions-in-wordpress.md b/docs/contributors/versions-in-wordpress.md index 649fe10d439aa6..4449f13996c629 100644 --- a/docs/contributors/versions-in-wordpress.md +++ b/docs/contributors/versions-in-wordpress.md @@ -6,6 +6,7 @@ If anything looks incorrect here, please bring it up in #core-editor in [WordPre | Gutenberg Versions | WordPress Version | | ------------------ | ----------------- | +| 16.2-16.7 | 6.4.1 | | 16.2-16.7 | 6.4 | | 15.2-16.1 | 6.3.1 | | 15.2-16.1 | 6.3 | From f55b2dc1ec046005dd06c29f7a18751db27b8c3e Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Thu, 16 Nov 2023 23:40:23 +0400 Subject: [PATCH 056/116] Global Styles: Make search more responsive for block type list (#56139) * Global Styles: Make search more responsive for block type list * Update selector getter method * No need to memoize filteredBlockTypes * Fix typo --- .../global-styles/screen-block-list.js | 63 +++++++++++-------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/screen-block-list.js b/packages/edit-site/src/components/global-styles/screen-block-list.js index 1db81377ff9a3b..b4adcd64e41361 100644 --- a/packages/edit-site/src/components/global-styles/screen-block-list.js +++ b/packages/edit-site/src/components/global-styles/screen-block-list.js @@ -9,7 +9,13 @@ import { __experimentalHStack as HStack, } from '@wordpress/components'; import { useSelect } from '@wordpress/data'; -import { useState, useMemo, useEffect, useRef } from '@wordpress/element'; +import { + useState, + useEffect, + useRef, + useDeferredValue, + memo, +} from '@wordpress/element'; import { BlockIcon, privateApis as blockEditorPrivateApis, @@ -99,22 +105,16 @@ function BlockMenuItem( { block } ) { ); } -function ScreenBlockList() { +function BlockList( { filterValue } ) { const sortedBlockTypes = useSortedBlockTypes(); - const [ filterValue, setFilterValue ] = useState( '' ); const debouncedSpeak = useDebounce( speak, 500 ); - const isMatchingSearchTerm = useSelect( - ( select ) => select( blocksStore ).isMatchingSearchTerm, - [] - ); - const filteredBlockTypes = useMemo( () => { - if ( ! filterValue ) { - return sortedBlockTypes; - } - return sortedBlockTypes.filter( ( blockType ) => - isMatchingSearchTerm( blockType, filterValue ) - ); - }, [ filterValue, sortedBlockTypes, isMatchingSearchTerm ] ); + const { isMatchingSearchTerm } = useSelect( blocksStore ); + + const filteredBlockTypes = ! filterValue + ? sortedBlockTypes + : sortedBlockTypes.filter( ( blockType ) => + isMatchingSearchTerm( blockType, filterValue ) + ); const blockTypesListRef = useRef(); @@ -140,6 +140,27 @@ function ScreenBlockList() { debouncedSpeak( resultsFoundMessage, count ); }, [ filterValue, debouncedSpeak ] ); + return ( +
+ { filteredBlockTypes.map( ( block ) => ( + + ) ) } +
+ ); +} + +const MemoizedBlockList = memo( BlockList ); + +function ScreenBlockList() { + const [ filterValue, setFilterValue ] = useState( '' ); + const deferredFilterValue = useDeferredValue( filterValue ); + return ( <> -
- { filteredBlockTypes.map( ( block ) => ( - - ) ) } -
+ ); } From d9995074b1b6de574a6e31ac269325778c0d8b54 Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Thu, 16 Nov 2023 19:35:47 +0000 Subject: [PATCH 057/116] Update changelog files --- packages/a11y/CHANGELOG.md | 2 ++ packages/a11y/package.json | 2 +- packages/annotations/CHANGELOG.md | 2 ++ packages/annotations/package.json | 2 +- packages/api-fetch/CHANGELOG.md | 2 ++ packages/api-fetch/package.json | 2 +- packages/autop/CHANGELOG.md | 2 ++ packages/autop/package.json | 2 +- packages/babel-plugin-import-jsx-pragma/CHANGELOG.md | 2 ++ packages/babel-plugin-import-jsx-pragma/package.json | 2 +- packages/babel-plugin-makepot/CHANGELOG.md | 2 ++ packages/babel-plugin-makepot/package.json | 2 +- packages/babel-preset-default/CHANGELOG.md | 2 ++ packages/babel-preset-default/package.json | 2 +- packages/base-styles/CHANGELOG.md | 2 ++ packages/base-styles/package.json | 2 +- packages/blob/CHANGELOG.md | 2 ++ packages/blob/package.json | 2 +- packages/block-directory/CHANGELOG.md | 2 ++ packages/block-directory/package.json | 2 +- packages/block-editor/CHANGELOG.md | 2 ++ packages/block-editor/package.json | 2 +- packages/block-library/CHANGELOG.md | 2 ++ packages/block-library/package.json | 2 +- packages/block-serialization-default-parser/CHANGELOG.md | 2 ++ packages/block-serialization-default-parser/package.json | 2 +- packages/block-serialization-spec-parser/CHANGELOG.md | 2 ++ packages/block-serialization-spec-parser/package.json | 2 +- packages/blocks/CHANGELOG.md | 2 ++ packages/blocks/package.json | 2 +- packages/browserslist-config/CHANGELOG.md | 2 ++ packages/browserslist-config/package.json | 2 +- packages/commands/CHANGELOG.md | 2 ++ packages/commands/package.json | 2 +- packages/components/CHANGELOG.md | 2 ++ packages/components/package.json | 2 +- packages/compose/CHANGELOG.md | 2 ++ packages/compose/package.json | 2 +- packages/core-commands/CHANGELOG.md | 2 ++ packages/core-commands/package.json | 2 +- packages/core-data/CHANGELOG.md | 2 ++ packages/core-data/package.json | 2 +- packages/create-block-interactive-template/CHANGELOG.md | 2 ++ packages/create-block-interactive-template/package.json | 2 +- packages/create-block-tutorial-template/CHANGELOG.md | 2 ++ packages/create-block-tutorial-template/package.json | 2 +- packages/create-block/CHANGELOG.md | 2 ++ packages/create-block/package.json | 2 +- packages/customize-widgets/CHANGELOG.md | 2 ++ packages/customize-widgets/package.json | 2 +- packages/data-controls/CHANGELOG.md | 2 ++ packages/data-controls/package.json | 2 +- packages/data/CHANGELOG.md | 2 ++ packages/data/package.json | 2 +- packages/date/CHANGELOG.md | 2 ++ packages/date/package.json | 2 +- packages/dependency-extraction-webpack-plugin/CHANGELOG.md | 2 ++ packages/dependency-extraction-webpack-plugin/package.json | 2 +- packages/deprecated/CHANGELOG.md | 2 ++ packages/deprecated/package.json | 2 +- packages/docgen/CHANGELOG.md | 2 ++ packages/docgen/package.json | 2 +- packages/dom-ready/CHANGELOG.md | 2 ++ packages/dom-ready/package.json | 2 +- packages/dom/CHANGELOG.md | 2 ++ packages/dom/package.json | 2 +- packages/e2e-test-utils-playwright/CHANGELOG.md | 2 ++ packages/e2e-test-utils-playwright/package.json | 2 +- packages/e2e-test-utils/CHANGELOG.md | 2 ++ packages/e2e-test-utils/package.json | 2 +- packages/e2e-tests/CHANGELOG.md | 2 ++ packages/e2e-tests/package.json | 2 +- packages/edit-post/CHANGELOG.md | 2 ++ packages/edit-post/package.json | 2 +- packages/edit-site/CHANGELOG.md | 2 ++ packages/edit-site/package.json | 2 +- packages/edit-widgets/CHANGELOG.md | 2 ++ packages/edit-widgets/package.json | 2 +- packages/editor/CHANGELOG.md | 2 ++ packages/editor/package.json | 2 +- packages/element/CHANGELOG.md | 2 ++ packages/element/package.json | 2 +- packages/env/CHANGELOG.md | 2 ++ packages/env/package.json | 2 +- packages/escape-html/CHANGELOG.md | 2 ++ packages/escape-html/package.json | 2 +- packages/eslint-plugin/CHANGELOG.md | 2 ++ packages/eslint-plugin/package.json | 2 +- packages/format-library/CHANGELOG.md | 2 ++ packages/format-library/package.json | 2 +- packages/hooks/CHANGELOG.md | 2 ++ packages/hooks/package.json | 2 +- packages/html-entities/CHANGELOG.md | 2 ++ packages/html-entities/package.json | 2 +- packages/i18n/CHANGELOG.md | 2 ++ packages/i18n/package.json | 2 +- packages/icons/CHANGELOG.md | 2 ++ packages/icons/package.json | 2 +- packages/interactivity/CHANGELOG.md | 2 ++ packages/interactivity/package.json | 2 +- packages/interface/CHANGELOG.md | 2 ++ packages/interface/package.json | 2 +- packages/is-shallow-equal/CHANGELOG.md | 2 ++ packages/is-shallow-equal/package.json | 2 +- packages/jest-console/CHANGELOG.md | 2 ++ packages/jest-console/package.json | 2 +- packages/jest-preset-default/CHANGELOG.md | 2 ++ packages/jest-preset-default/package.json | 2 +- packages/jest-puppeteer-axe/CHANGELOG.md | 2 ++ packages/jest-puppeteer-axe/package.json | 2 +- packages/keyboard-shortcuts/CHANGELOG.md | 2 ++ packages/keyboard-shortcuts/package.json | 2 +- packages/keycodes/CHANGELOG.md | 2 ++ packages/keycodes/package.json | 2 +- packages/lazy-import/CHANGELOG.md | 2 ++ packages/lazy-import/package.json | 2 +- packages/list-reusable-blocks/CHANGELOG.md | 2 ++ packages/list-reusable-blocks/package.json | 2 +- packages/media-utils/CHANGELOG.md | 2 ++ packages/media-utils/package.json | 2 +- packages/notices/CHANGELOG.md | 2 ++ packages/notices/package.json | 2 +- packages/npm-package-json-lint-config/CHANGELOG.md | 2 ++ packages/npm-package-json-lint-config/package.json | 2 +- packages/nux/CHANGELOG.md | 2 ++ packages/nux/package.json | 2 +- packages/patterns/CHANGELOG.md | 2 ++ packages/patterns/package.json | 2 +- packages/plugins/CHANGELOG.md | 2 ++ packages/plugins/package.json | 2 +- packages/postcss-plugins-preset/CHANGELOG.md | 2 ++ packages/postcss-plugins-preset/package.json | 2 +- packages/postcss-themes/CHANGELOG.md | 2 ++ packages/postcss-themes/package.json | 2 +- packages/preferences-persistence/CHANGELOG.md | 2 ++ packages/preferences-persistence/package.json | 2 +- packages/preferences/CHANGELOG.md | 2 ++ packages/preferences/package.json | 2 +- packages/prettier-config/CHANGELOG.md | 2 ++ packages/prettier-config/package.json | 2 +- packages/primitives/CHANGELOG.md | 2 ++ packages/primitives/package.json | 2 +- packages/priority-queue/CHANGELOG.md | 2 ++ packages/priority-queue/package.json | 2 +- packages/private-apis/CHANGELOG.md | 2 ++ packages/private-apis/package.json | 2 +- packages/project-management-automation/CHANGELOG.md | 2 ++ packages/project-management-automation/package.json | 2 +- packages/react-i18n/CHANGELOG.md | 2 ++ packages/react-i18n/package.json | 2 +- packages/readable-js-assets-webpack-plugin/CHANGELOG.md | 2 ++ packages/readable-js-assets-webpack-plugin/package.json | 2 +- packages/redux-routine/CHANGELOG.md | 2 ++ packages/redux-routine/package.json | 2 +- packages/reusable-blocks/CHANGELOG.md | 2 ++ packages/reusable-blocks/package.json | 2 +- packages/rich-text/CHANGELOG.md | 2 ++ packages/rich-text/package.json | 2 +- packages/router/CHANGELOG.md | 2 ++ packages/router/package.json | 2 +- packages/scripts/CHANGELOG.md | 2 ++ packages/scripts/package.json | 2 +- packages/server-side-render/CHANGELOG.md | 2 ++ packages/server-side-render/package.json | 2 +- packages/shortcode/CHANGELOG.md | 2 ++ packages/shortcode/package.json | 2 +- packages/style-engine/CHANGELOG.md | 2 ++ packages/style-engine/package.json | 2 +- packages/stylelint-config/CHANGELOG.md | 2 ++ packages/stylelint-config/package.json | 2 +- packages/sync/CHANGELOG.md | 2 ++ packages/sync/package.json | 2 +- packages/token-list/CHANGELOG.md | 2 ++ packages/token-list/package.json | 2 +- packages/undo-manager/CHANGELOG.md | 2 ++ packages/undo-manager/package.json | 2 +- packages/url/CHANGELOG.md | 2 ++ packages/url/package.json | 2 +- packages/viewport/CHANGELOG.md | 2 ++ packages/viewport/package.json | 2 +- packages/warning/CHANGELOG.md | 2 ++ packages/warning/package.json | 2 +- packages/widgets/CHANGELOG.md | 2 ++ packages/widgets/package.json | 2 +- packages/wordcount/CHANGELOG.md | 2 ++ packages/wordcount/package.json | 2 +- 186 files changed, 279 insertions(+), 93 deletions(-) diff --git a/packages/a11y/CHANGELOG.md b/packages/a11y/CHANGELOG.md index 2be0c0b64bb149..ef2826ea2f87bc 100644 --- a/packages/a11y/CHANGELOG.md +++ b/packages/a11y/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/a11y/package.json b/packages/a11y/package.json index a48168ac575783..60bd6f5e7fbf18 100644 --- a/packages/a11y/package.json +++ b/packages/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/a11y", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "Accessibility (a11y) utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/annotations/CHANGELOG.md b/packages/annotations/CHANGELOG.md index a45627849418b3..ccb8a4eb3b22f9 100644 --- a/packages/annotations/CHANGELOG.md +++ b/packages/annotations/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.46.0 (2023-11-16) + ## 2.45.0 (2023-11-02) ## 2.44.0 (2023-10-18) diff --git a/packages/annotations/package.json b/packages/annotations/package.json index 32b3eee0e2ecb6..a8aee11f46fabe 100644 --- a/packages/annotations/package.json +++ b/packages/annotations/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/annotations", - "version": "2.45.0", + "version": "2.46.0-prerelease", "description": "Annotate content in the Gutenberg editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/api-fetch/CHANGELOG.md b/packages/api-fetch/CHANGELOG.md index 5806a41860d5c9..07e50ad2cb451f 100644 --- a/packages/api-fetch/CHANGELOG.md +++ b/packages/api-fetch/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.43.0 (2023-11-16) + ## 6.42.0 (2023-11-02) ## 6.41.0 (2023-10-18) diff --git a/packages/api-fetch/package.json b/packages/api-fetch/package.json index e5413887a61ceb..cb5a477a706fe4 100644 --- a/packages/api-fetch/package.json +++ b/packages/api-fetch/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/api-fetch", - "version": "6.42.0", + "version": "6.43.0-prerelease", "description": "Utility to make WordPress REST API requests.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/autop/CHANGELOG.md b/packages/autop/CHANGELOG.md index a3cba5718404ba..c3ffd7dd4bb171 100644 --- a/packages/autop/CHANGELOG.md +++ b/packages/autop/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/autop/package.json b/packages/autop/package.json index 13eb7cac02d54c..d6231e72dcd9d5 100644 --- a/packages/autop/package.json +++ b/packages/autop/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/autop", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "WordPress's automatic paragraph functions `autop` and `removep`.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md b/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md index 292314b1c9fe10..8070de13c5955d 100644 --- a/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md +++ b/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.29.0 (2023-11-16) + ## 4.28.0 (2023-11-02) ## 4.27.0 (2023-10-18) diff --git a/packages/babel-plugin-import-jsx-pragma/package.json b/packages/babel-plugin-import-jsx-pragma/package.json index 00a621f31b1e06..4e5fe879f84990 100644 --- a/packages/babel-plugin-import-jsx-pragma/package.json +++ b/packages/babel-plugin-import-jsx-pragma/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-plugin-import-jsx-pragma", - "version": "4.28.0", + "version": "4.29.0-prerelease", "description": "Babel transform plugin for automatically injecting an import to be used as the pragma for the React JSX Transform plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-plugin-makepot/CHANGELOG.md b/packages/babel-plugin-makepot/CHANGELOG.md index 0b57ac2d9b0a1d..1b8137ab96e7fe 100644 --- a/packages/babel-plugin-makepot/CHANGELOG.md +++ b/packages/babel-plugin-makepot/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.30.0 (2023-11-16) + ## 5.29.0 (2023-11-02) ## 5.28.0 (2023-10-18) diff --git a/packages/babel-plugin-makepot/package.json b/packages/babel-plugin-makepot/package.json index 4acc61c4819e63..c70ebc70085915 100644 --- a/packages/babel-plugin-makepot/package.json +++ b/packages/babel-plugin-makepot/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-plugin-makepot", - "version": "5.29.0", + "version": "5.30.0-prerelease", "description": "WordPress Babel internationalization (i18n) plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-preset-default/CHANGELOG.md b/packages/babel-preset-default/CHANGELOG.md index e5a4c06b4c92b6..20ff5b49dbebe9 100644 --- a/packages/babel-preset-default/CHANGELOG.md +++ b/packages/babel-preset-default/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 7.30.0 (2023-11-16) + ## 7.29.0 (2023-11-02) ## 7.28.0 (2023-10-18) diff --git a/packages/babel-preset-default/package.json b/packages/babel-preset-default/package.json index dd38c349bb1716..fc8de1a030c610 100644 --- a/packages/babel-preset-default/package.json +++ b/packages/babel-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-preset-default", - "version": "7.29.0", + "version": "7.30.0-prerelease", "description": "Default Babel preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/base-styles/CHANGELOG.md b/packages/base-styles/CHANGELOG.md index b6135581dbd731..bac407def2873b 100644 --- a/packages/base-styles/CHANGELOG.md +++ b/packages/base-styles/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.37.0 (2023-11-16) + ## 4.36.0 (2023-11-02) ## 4.35.0 (2023-10-18) diff --git a/packages/base-styles/package.json b/packages/base-styles/package.json index fe604a7cb02115..d747036f1bebdf 100644 --- a/packages/base-styles/package.json +++ b/packages/base-styles/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/base-styles", - "version": "4.36.0", + "version": "4.37.0-prerelease", "description": "Base SCSS utilities and variables for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blob/CHANGELOG.md b/packages/blob/CHANGELOG.md index 680d53971c018d..7fae8a61cabb1f 100644 --- a/packages/blob/CHANGELOG.md +++ b/packages/blob/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ### New feature - Add `downloadBlob` function and remove `downloadjs` dependency ([#56024](https://github.com/WordPress/gutenberg/pull/56024)). diff --git a/packages/blob/package.json b/packages/blob/package.json index c3e89fb9918237..8779cf36199474 100644 --- a/packages/blob/package.json +++ b/packages/blob/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/blob", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "Blob utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-directory/CHANGELOG.md b/packages/block-directory/CHANGELOG.md index eb3a68dd24cc81..7cebd71db2fbc3 100644 --- a/packages/block-directory/CHANGELOG.md +++ b/packages/block-directory/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.23.0 (2023-11-16) + ## 4.22.0 (2023-11-02) ## 4.21.0 (2023-10-18) diff --git a/packages/block-directory/package.json b/packages/block-directory/package.json index 71018738fac083..86f94996843ea2 100644 --- a/packages/block-directory/package.json +++ b/packages/block-directory/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-directory", - "version": "4.22.0", + "version": "4.23.0-prerelease", "description": "Extend editor with block directory features to search, download and install blocks.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-editor/CHANGELOG.md b/packages/block-editor/CHANGELOG.md index 94e0306e175659..497e419453f6a2 100644 --- a/packages/block-editor/CHANGELOG.md +++ b/packages/block-editor/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 12.14.0 (2023-11-16) + ## 12.13.0 (2023-11-02) - Deprecated the `useSetting` function in favor of new `useSettings` one that can retrieve multiple settings at once ([#55337](https://github.com/WordPress/gutenberg/pull/55337)). diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index baebc824086525..baf9929585751c 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-editor", - "version": "12.13.0", + "version": "12.14.0-prerelease", "description": "Generic block editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-library/CHANGELOG.md b/packages/block-library/CHANGELOG.md index 22f02cfcd62885..da6f0fa75152cf 100644 --- a/packages/block-library/CHANGELOG.md +++ b/packages/block-library/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 8.23.0 (2023-11-16) + ## 8.22.0 (2023-11-02) ## 8.21.0 (2023-10-18) diff --git a/packages/block-library/package.json b/packages/block-library/package.json index 5fdec495443efa..5e2e0e40cfc7b0 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-library", - "version": "8.22.0", + "version": "8.23.0-prerelease", "description": "Block library for the WordPress editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-serialization-default-parser/CHANGELOG.md b/packages/block-serialization-default-parser/CHANGELOG.md index 7d8b2b6b582ae7..38fbb2b327d63b 100644 --- a/packages/block-serialization-default-parser/CHANGELOG.md +++ b/packages/block-serialization-default-parser/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.46.0 (2023-11-16) + ## 4.45.0 (2023-11-02) ## 4.44.0 (2023-10-18) diff --git a/packages/block-serialization-default-parser/package.json b/packages/block-serialization-default-parser/package.json index 3072546e446d19..3c0b3e5b8f6987 100644 --- a/packages/block-serialization-default-parser/package.json +++ b/packages/block-serialization-default-parser/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-serialization-default-parser", - "version": "4.45.0", + "version": "4.46.0-prerelease", "description": "Block serialization specification parser for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-serialization-spec-parser/CHANGELOG.md b/packages/block-serialization-spec-parser/CHANGELOG.md index f4a3dea0b491bf..5e44a000908e5d 100644 --- a/packages/block-serialization-spec-parser/CHANGELOG.md +++ b/packages/block-serialization-spec-parser/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.46.0 (2023-11-16) + ## 4.45.0 (2023-11-02) ## 4.44.0 (2023-10-18) diff --git a/packages/block-serialization-spec-parser/package.json b/packages/block-serialization-spec-parser/package.json index 1056d871489c33..429caf6f66bf57 100644 --- a/packages/block-serialization-spec-parser/package.json +++ b/packages/block-serialization-spec-parser/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-serialization-spec-parser", - "version": "4.45.0", + "version": "4.46.0-prerelease", "description": "Block serialization specification parser for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blocks/CHANGELOG.md b/packages/blocks/CHANGELOG.md index a0f9d61e0b4c2e..3b04d680cb3aa2 100644 --- a/packages/blocks/CHANGELOG.md +++ b/packages/blocks/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 12.23.0 (2023-11-16) + ## 12.22.0 (2023-11-02) ## 12.21.0 (2023-10-18) diff --git a/packages/blocks/package.json b/packages/blocks/package.json index 813272be7ef6e3..e88532e8501465 100644 --- a/packages/blocks/package.json +++ b/packages/blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/blocks", - "version": "12.22.0", + "version": "12.23.0-prerelease", "description": "Block API for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/browserslist-config/CHANGELOG.md b/packages/browserslist-config/CHANGELOG.md index 28f88c40569bf8..1b32704cfd5776 100644 --- a/packages/browserslist-config/CHANGELOG.md +++ b/packages/browserslist-config/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.29.0 (2023-11-16) + ## 5.28.0 (2023-11-02) ## 5.27.0 (2023-10-18) diff --git a/packages/browserslist-config/package.json b/packages/browserslist-config/package.json index c7813290dedf5d..69b1f02f9eb086 100644 --- a/packages/browserslist-config/package.json +++ b/packages/browserslist-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/browserslist-config", - "version": "5.28.0", + "version": "5.29.0-prerelease", "description": "WordPress Browserslist shared configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/commands/CHANGELOG.md b/packages/commands/CHANGELOG.md index a858b5af26543b..6641cb29ca6724 100644 --- a/packages/commands/CHANGELOG.md +++ b/packages/commands/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.17.0 (2023-11-16) + ## 0.16.0 (2023-11-02) ## 0.15.0 (2023-10-18) diff --git a/packages/commands/package.json b/packages/commands/package.json index 0acd14f3de8ad7..bb74b5c238fd55 100644 --- a/packages/commands/package.json +++ b/packages/commands/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/commands", - "version": "0.16.0", + "version": "0.17.0-prerelease", "description": "Handles the commands menu.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 856926988089a3..37ad2a65da28af 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 25.12.0 (2023-11-16) + ### Bug Fix - `Toolbar`: Remove CSS rule that prevented focus outline to be visible for toolbar buttons in the `:active` state. ([#56123](https://github.com/WordPress/gutenberg/pull/56123)). diff --git a/packages/components/package.json b/packages/components/package.json index 2980553f5a2846..1eaf7e27ed3a68 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/components", - "version": "25.11.0", + "version": "25.12.0-prerelease", "description": "UI components for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/compose/CHANGELOG.md b/packages/compose/CHANGELOG.md index 519a4b7b98d9c1..550b2ab057bd60 100644 --- a/packages/compose/CHANGELOG.md +++ b/packages/compose/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.23.0 (2023-11-16) + ## 6.22.0 (2023-11-02) ## 6.21.0 (2023-10-18) diff --git a/packages/compose/package.json b/packages/compose/package.json index 17c5ae01ccfb5a..b55a73f976e29e 100644 --- a/packages/compose/package.json +++ b/packages/compose/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/compose", - "version": "6.22.0", + "version": "6.23.0-prerelease", "description": "WordPress higher-order components (HOCs).", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/core-commands/CHANGELOG.md b/packages/core-commands/CHANGELOG.md index 6da22ab229627d..420ab39a97fd14 100644 --- a/packages/core-commands/CHANGELOG.md +++ b/packages/core-commands/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.15.0 (2023-11-16) + ## 0.14.0 (2023-11-02) ## 0.13.0 (2023-10-18) diff --git a/packages/core-commands/package.json b/packages/core-commands/package.json index 1ca3d5d25d4d6a..b91feb0ecb4f7f 100644 --- a/packages/core-commands/package.json +++ b/packages/core-commands/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/core-commands", - "version": "0.14.0", + "version": "0.15.0-prerelease", "description": "WordPress core reusable commands.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/core-data/CHANGELOG.md b/packages/core-data/CHANGELOG.md index d6ee7486934332..d20f8bd6c9d667 100644 --- a/packages/core-data/CHANGELOG.md +++ b/packages/core-data/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.23.0 (2023-11-16) + ## 6.22.0 (2023-11-02) ## 6.21.0 (2023-10-18) diff --git a/packages/core-data/package.json b/packages/core-data/package.json index 6ab22b7ca9a69d..ef109392491505 100644 --- a/packages/core-data/package.json +++ b/packages/core-data/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/core-data", - "version": "6.22.0", + "version": "6.23.0-prerelease", "description": "Access to and manipulation of core WordPress entities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/create-block-interactive-template/CHANGELOG.md b/packages/create-block-interactive-template/CHANGELOG.md index 9a446ed2cfa7ec..46e2a04014e6c0 100644 --- a/packages/create-block-interactive-template/CHANGELOG.md +++ b/packages/create-block-interactive-template/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.9.0 (2023-11-16) + ## 1.8.0 (2023-11-02) ## 1.7.0 (2023-10-18) diff --git a/packages/create-block-interactive-template/package.json b/packages/create-block-interactive-template/package.json index 579ad04f6c2513..ab2053e4dc8609 100644 --- a/packages/create-block-interactive-template/package.json +++ b/packages/create-block-interactive-template/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block-interactive-template", - "version": "1.8.0", + "version": "1.9.0-prerelease", "description": "Template for @wordpress/create-block to create interactive blocks with the Interactivity API.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/create-block-tutorial-template/CHANGELOG.md b/packages/create-block-tutorial-template/CHANGELOG.md index 20f2a56d366431..12d8de954281d0 100644 --- a/packages/create-block-tutorial-template/CHANGELOG.md +++ b/packages/create-block-tutorial-template/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.0.0 (2023-11-16) + ### Breaking Change - Update the block example scaffolded by the template. diff --git a/packages/create-block-tutorial-template/package.json b/packages/create-block-tutorial-template/package.json index 33eb73835bfaee..a1a733b3e8a57c 100644 --- a/packages/create-block-tutorial-template/package.json +++ b/packages/create-block-tutorial-template/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block-tutorial-template", - "version": "2.33.0", + "version": "3.0.0-prerelease", "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", diff --git a/packages/create-block/CHANGELOG.md b/packages/create-block/CHANGELOG.md index 7b48fe15b9f2ba..2a3a522feebdf1 100644 --- a/packages/create-block/CHANGELOG.md +++ b/packages/create-block/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.30.0 (2023-11-16) + ## 4.29.0 (2023-11-02) ## 4.28.0 (2023-10-18) diff --git a/packages/create-block/package.json b/packages/create-block/package.json index aad739e1038043..2ed37c112c7a14 100644 --- a/packages/create-block/package.json +++ b/packages/create-block/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block", - "version": "4.29.0", + "version": "4.30.0-prerelease", "description": "Generates PHP, JS and CSS code for registering a block for a WordPress plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/customize-widgets/CHANGELOG.md b/packages/customize-widgets/CHANGELOG.md index 3165744b7a6a19..80eb09e9b4fe79 100644 --- a/packages/customize-widgets/CHANGELOG.md +++ b/packages/customize-widgets/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.23.0 (2023-11-16) + ## 4.22.0 (2023-11-02) ## 4.21.0 (2023-10-18) diff --git a/packages/customize-widgets/package.json b/packages/customize-widgets/package.json index 5f84578f6c6ca6..2384f06a1253c0 100644 --- a/packages/customize-widgets/package.json +++ b/packages/customize-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/customize-widgets", - "version": "4.22.0", + "version": "4.23.0-prerelease", "description": "Widgets blocks in Customizer Module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/data-controls/CHANGELOG.md b/packages/data-controls/CHANGELOG.md index 3068808b6e0284..48ed94498657cf 100644 --- a/packages/data-controls/CHANGELOG.md +++ b/packages/data-controls/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.15.0 (2023-11-16) + ## 3.14.0 (2023-11-02) ## 3.13.0 (2023-10-18) diff --git a/packages/data-controls/package.json b/packages/data-controls/package.json index 58ffc687664147..b86b70577e7e43 100644 --- a/packages/data-controls/package.json +++ b/packages/data-controls/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/data-controls", - "version": "3.14.0", + "version": "3.15.0-prerelease", "description": "A set of common controls for the @wordpress/data api.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/data/CHANGELOG.md b/packages/data/CHANGELOG.md index 630a9b01d0dda4..4c7ec318971058 100644 --- a/packages/data/CHANGELOG.md +++ b/packages/data/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 9.16.0 (2023-11-16) + ## 9.15.0 (2023-11-02) ## 9.14.0 (2023-10-18) diff --git a/packages/data/package.json b/packages/data/package.json index b3f4c6b0dd9224..2698c27f0091a9 100644 --- a/packages/data/package.json +++ b/packages/data/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/data", - "version": "9.15.0", + "version": "9.16.0-prerelease", "description": "Data module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/date/CHANGELOG.md b/packages/date/CHANGELOG.md index 5d7eca2da82e47..b43273077d2e81 100644 --- a/packages/date/CHANGELOG.md +++ b/packages/date/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.46.0 (2023-11-16) + ## 4.45.0 (2023-11-02) ## 4.44.0 (2023-10-18) diff --git a/packages/date/package.json b/packages/date/package.json index 6b2e2dfe4280cf..3d85c7f446d620 100644 --- a/packages/date/package.json +++ b/packages/date/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/date", - "version": "4.45.0", + "version": "4.46.0-prerelease", "description": "Date module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dependency-extraction-webpack-plugin/CHANGELOG.md b/packages/dependency-extraction-webpack-plugin/CHANGELOG.md index 4bc08d6a386b37..29bf83987880e6 100644 --- a/packages/dependency-extraction-webpack-plugin/CHANGELOG.md +++ b/packages/dependency-extraction-webpack-plugin/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.29.0 (2023-11-16) + ## 4.28.0 (2023-11-02) ## 4.27.0 (2023-10-18) diff --git a/packages/dependency-extraction-webpack-plugin/package.json b/packages/dependency-extraction-webpack-plugin/package.json index 36eadbaff63350..b1370b1c359afe 100644 --- a/packages/dependency-extraction-webpack-plugin/package.json +++ b/packages/dependency-extraction-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dependency-extraction-webpack-plugin", - "version": "4.28.0", + "version": "4.29.0-prerelease", "description": "Extract WordPress script dependencies from webpack bundles.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/deprecated/CHANGELOG.md b/packages/deprecated/CHANGELOG.md index 6bd3185175ee7c..841f3cfd5dcfd7 100644 --- a/packages/deprecated/CHANGELOG.md +++ b/packages/deprecated/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/deprecated/package.json b/packages/deprecated/package.json index 5f13accb2e27bc..e596db980e8ecd 100644 --- a/packages/deprecated/package.json +++ b/packages/deprecated/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/deprecated", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "Deprecation utility for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/docgen/CHANGELOG.md b/packages/docgen/CHANGELOG.md index 0b45b27df3ccbc..d72a476531feea 100644 --- a/packages/docgen/CHANGELOG.md +++ b/packages/docgen/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.55.0 (2023-11-16) + ## 1.54.0 (2023-11-02) ## 1.53.0 (2023-10-18) diff --git a/packages/docgen/package.json b/packages/docgen/package.json index c8610b86d2cb8e..ec282a093f1d84 100644 --- a/packages/docgen/package.json +++ b/packages/docgen/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/docgen", - "version": "1.54.0", + "version": "1.55.0-prerelease", "description": "Autogenerate public API documentation from exports and JSDoc comments.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dom-ready/CHANGELOG.md b/packages/dom-ready/CHANGELOG.md index 61b414f50d8c3f..e0ae85e3cac5cf 100644 --- a/packages/dom-ready/CHANGELOG.md +++ b/packages/dom-ready/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/dom-ready/package.json b/packages/dom-ready/package.json index fc7043e2c950f5..763f21e3172362 100644 --- a/packages/dom-ready/package.json +++ b/packages/dom-ready/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dom-ready", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "Execute callback after the DOM is loaded.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dom/CHANGELOG.md b/packages/dom/CHANGELOG.md index 5a1567021b1eaf..df938d2fa57996 100644 --- a/packages/dom/CHANGELOG.md +++ b/packages/dom/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/dom/package.json b/packages/dom/package.json index b40a161d683b43..f80a508f23b253 100644 --- a/packages/dom/package.json +++ b/packages/dom/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dom", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "DOM utilities module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-test-utils-playwright/CHANGELOG.md b/packages/e2e-test-utils-playwright/CHANGELOG.md index cd7425c68eeff2..9f5c2a199ff0f7 100644 --- a/packages/e2e-test-utils-playwright/CHANGELOG.md +++ b/packages/e2e-test-utils-playwright/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.14.0 (2023-11-16) + ## 0.13.0 (2023-11-02) ## 0.12.0 (2023-10-18) diff --git a/packages/e2e-test-utils-playwright/package.json b/packages/e2e-test-utils-playwright/package.json index f8d9b7cd2f0171..553ad9ad158342 100644 --- a/packages/e2e-test-utils-playwright/package.json +++ b/packages/e2e-test-utils-playwright/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-test-utils-playwright", - "version": "0.13.0", + "version": "0.14.0-prerelease", "description": "End-To-End (E2E) test utils for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-test-utils/CHANGELOG.md b/packages/e2e-test-utils/CHANGELOG.md index bf5d32bb6cc94d..617315dbfaa6c1 100644 --- a/packages/e2e-test-utils/CHANGELOG.md +++ b/packages/e2e-test-utils/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 10.17.0 (2023-11-16) + ## 10.16.0 (2023-11-02) ## 10.15.0 (2023-10-18) diff --git a/packages/e2e-test-utils/package.json b/packages/e2e-test-utils/package.json index f4bd86e15f1ee3..58506c9686d602 100644 --- a/packages/e2e-test-utils/package.json +++ b/packages/e2e-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-test-utils", - "version": "10.16.0", + "version": "10.17.0-prerelease", "description": "End-To-End (E2E) test utils for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-tests/CHANGELOG.md b/packages/e2e-tests/CHANGELOG.md index 66ab34e8267590..76363c3fda1023 100644 --- a/packages/e2e-tests/CHANGELOG.md +++ b/packages/e2e-tests/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 7.17.0 (2023-11-16) + ## 7.16.0 (2023-11-02) ## 7.15.0 (2023-10-18) diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json index 001f395dec6083..6c444d161f65f9 100644 --- a/packages/e2e-tests/package.json +++ b/packages/e2e-tests/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-tests", - "version": "7.16.0", + "version": "7.17.0-prerelease", "description": "End-To-End (E2E) tests for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-post/CHANGELOG.md b/packages/edit-post/CHANGELOG.md index 6417fcc4454c6f..e8e0fa1632a7da 100644 --- a/packages/edit-post/CHANGELOG.md +++ b/packages/edit-post/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 7.23.0 (2023-11-16) + ## 7.22.0 (2023-11-02) ## 7.21.0 (2023-10-18) diff --git a/packages/edit-post/package.json b/packages/edit-post/package.json index ed9b4541103c94..d0a8c78ca436b2 100644 --- a/packages/edit-post/package.json +++ b/packages/edit-post/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-post", - "version": "7.22.0", + "version": "7.23.0-prerelease", "description": "Edit Post module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-site/CHANGELOG.md b/packages/edit-site/CHANGELOG.md index ad970d703cb43e..b8814356b2b6b4 100644 --- a/packages/edit-site/CHANGELOG.md +++ b/packages/edit-site/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.23.0 (2023-11-16) + ## 5.22.0 (2023-11-02) ## 5.21.0 (2023-10-18) diff --git a/packages/edit-site/package.json b/packages/edit-site/package.json index d7007e1d88fece..bea0abb0ef0c84 100644 --- a/packages/edit-site/package.json +++ b/packages/edit-site/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-site", - "version": "5.22.0", + "version": "5.23.0-prerelease", "description": "Edit Site Page module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-widgets/CHANGELOG.md b/packages/edit-widgets/CHANGELOG.md index e1d1c915a2ad21..65b83144691eb1 100644 --- a/packages/edit-widgets/CHANGELOG.md +++ b/packages/edit-widgets/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.23.0 (2023-11-16) + ## 5.22.0 (2023-11-02) ## 5.21.0 (2023-10-18) diff --git a/packages/edit-widgets/package.json b/packages/edit-widgets/package.json index 754e83f54a5f20..1e68aecf8321fd 100644 --- a/packages/edit-widgets/package.json +++ b/packages/edit-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-widgets", - "version": "5.22.0", + "version": "5.23.0-prerelease", "description": "Widgets Page module for WordPress..", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/editor/CHANGELOG.md b/packages/editor/CHANGELOG.md index 0e99e83f464181..1012c6163ec292 100644 --- a/packages/editor/CHANGELOG.md +++ b/packages/editor/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 13.23.0 (2023-11-16) + ## 13.22.0 (2023-11-02) ## 13.21.0 (2023-10-18) diff --git a/packages/editor/package.json b/packages/editor/package.json index b45a28c982ee4c..d9d0afcdf1656a 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/editor", - "version": "13.22.0", + "version": "13.23.0-prerelease", "description": "Enhanced block editor for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/element/CHANGELOG.md b/packages/element/CHANGELOG.md index abc424112d60c3..a3d999401c24be 100644 --- a/packages/element/CHANGELOG.md +++ b/packages/element/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.23.0 (2023-11-16) + ## 5.22.0 (2023-11-02) ## 5.21.0 (2023-10-18) diff --git a/packages/element/package.json b/packages/element/package.json index f1c60680fd1565..fa6b5e1ab5ce70 100644 --- a/packages/element/package.json +++ b/packages/element/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/element", - "version": "5.22.0", + "version": "5.23.0-prerelease", "description": "Element React module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/env/CHANGELOG.md b/packages/env/CHANGELOG.md index 67f674c4b6a57c..b1dd4f778334f7 100644 --- a/packages/env/CHANGELOG.md +++ b/packages/env/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 8.12.0 (2023-11-16) + ## 8.11.0 (2023-11-02) ### Enhancement diff --git a/packages/env/package.json b/packages/env/package.json index 42ebbdc9a821f6..7e2cee5596a2b3 100644 --- a/packages/env/package.json +++ b/packages/env/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/env", - "version": "8.11.0", + "version": "8.12.0-prerelease", "description": "A zero-config, self contained local WordPress environment for development and testing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/escape-html/CHANGELOG.md b/packages/escape-html/CHANGELOG.md index d6fa0a8963e1a0..9f62bcec394e90 100644 --- a/packages/escape-html/CHANGELOG.md +++ b/packages/escape-html/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.46.0 (2023-11-16) + ## 2.45.0 (2023-11-02) ## 2.44.0 (2023-10-18) diff --git a/packages/escape-html/package.json b/packages/escape-html/package.json index 473a3bd5511caf..742813826477e5 100644 --- a/packages/escape-html/package.json +++ b/packages/escape-html/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/escape-html", - "version": "2.45.0", + "version": "2.46.0-prerelease", "description": "Escape HTML utils.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index 9b2b7e2bb7173c..203f5246c10f46 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 17.3.0 (2023-11-16) + ## 17.2.0 (2023-11-02) ## 17.1.0 (2023-10-18) diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index b262f8801c4221..e1fb50b5414251 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/eslint-plugin", - "version": "17.2.0", + "version": "17.3.0-prerelease", "description": "ESLint plugin for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/format-library/CHANGELOG.md b/packages/format-library/CHANGELOG.md index 9d74bfe94817ec..ca29a28fd3a4c0 100644 --- a/packages/format-library/CHANGELOG.md +++ b/packages/format-library/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.23.0 (2023-11-16) + ## 4.22.0 (2023-11-02) ## 4.21.0 (2023-10-18) diff --git a/packages/format-library/package.json b/packages/format-library/package.json index 37672549d0b1d5..687be3963fb432 100644 --- a/packages/format-library/package.json +++ b/packages/format-library/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/format-library", - "version": "4.22.0", + "version": "4.23.0-prerelease", "description": "Format library for the WordPress editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/hooks/CHANGELOG.md b/packages/hooks/CHANGELOG.md index 6ec9ae13bd9bd0..d2f43c203979c3 100644 --- a/packages/hooks/CHANGELOG.md +++ b/packages/hooks/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/hooks/package.json b/packages/hooks/package.json index 879a513e893a6f..4595c47aa29a36 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/hooks", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "WordPress hooks library.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/html-entities/CHANGELOG.md b/packages/html-entities/CHANGELOG.md index 4cb861f9ad09e4..bf89467f2154e8 100644 --- a/packages/html-entities/CHANGELOG.md +++ b/packages/html-entities/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/html-entities/package.json b/packages/html-entities/package.json index 5ff780e4b5cb1c..9d72d46f7a5ff2 100644 --- a/packages/html-entities/package.json +++ b/packages/html-entities/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/html-entities", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "HTML entity utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/i18n/CHANGELOG.md b/packages/i18n/CHANGELOG.md index e34507334f2aa5..dfc007b50cd076 100644 --- a/packages/i18n/CHANGELOG.md +++ b/packages/i18n/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.46.0 (2023-11-16) + ## 4.45.0 (2023-11-02) ## 4.44.0 (2023-10-18) diff --git a/packages/i18n/package.json b/packages/i18n/package.json index 2b53debe4f79af..bb82d509684fea 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/i18n", - "version": "4.45.0", + "version": "4.46.0-prerelease", "description": "WordPress internationalization (i18n) library.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/icons/CHANGELOG.md b/packages/icons/CHANGELOG.md index d99b95eb4bf371..a906ef9f569d21 100644 --- a/packages/icons/CHANGELOG.md +++ b/packages/icons/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 9.37.0 (2023-11-16) + ### New features - Add new `funnel` icon. diff --git a/packages/icons/package.json b/packages/icons/package.json index b0117b28edca00..ecc11b411c828a 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/icons", - "version": "9.36.0", + "version": "9.37.0-prerelease", "description": "WordPress Icons package, based on dashicon.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/interactivity/CHANGELOG.md b/packages/interactivity/CHANGELOG.md index 7b5faaeefa1b2c..089280cee21448 100644 --- a/packages/interactivity/CHANGELOG.md +++ b/packages/interactivity/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.7.0 (2023-11-16) + ## 2.6.0 (2023-11-02) ### Bug Fix diff --git a/packages/interactivity/package.json b/packages/interactivity/package.json index 0580868b7d7149..791ed276db6b3f 100644 --- a/packages/interactivity/package.json +++ b/packages/interactivity/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/interactivity", - "version": "2.6.0", + "version": "2.7.0-prerelease", "description": "Package that provides a standard and simple way to handle the frontend interactivity of Gutenberg blocks.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/interface/CHANGELOG.md b/packages/interface/CHANGELOG.md index 73737f3ed99e93..9c7370291eef60 100644 --- a/packages/interface/CHANGELOG.md +++ b/packages/interface/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.23.0 (2023-11-16) + ## 5.22.0 (2023-11-02) ## 5.21.0 (2023-10-18) diff --git a/packages/interface/package.json b/packages/interface/package.json index 28b11d1cbee5f1..8142df4fd443b7 100644 --- a/packages/interface/package.json +++ b/packages/interface/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/interface", - "version": "5.22.0", + "version": "5.23.0-prerelease", "description": "Interface module for WordPress. The package contains shared functionality across the modern JavaScript-based WordPress screens.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/is-shallow-equal/CHANGELOG.md b/packages/is-shallow-equal/CHANGELOG.md index 9eef05af9f1d68..9f5db485bb5405 100644 --- a/packages/is-shallow-equal/CHANGELOG.md +++ b/packages/is-shallow-equal/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.46.0 (2023-11-16) + ## 4.45.0 (2023-11-02) ## 4.44.0 (2023-10-18) diff --git a/packages/is-shallow-equal/package.json b/packages/is-shallow-equal/package.json index e6b553baaceb70..b7202d19a87e3d 100644 --- a/packages/is-shallow-equal/package.json +++ b/packages/is-shallow-equal/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/is-shallow-equal", - "version": "4.45.0", + "version": "4.46.0-prerelease", "description": "Test for shallow equality between two objects or arrays.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/jest-console/CHANGELOG.md b/packages/jest-console/CHANGELOG.md index 463bfd52db437b..4032ec50a5ebfd 100644 --- a/packages/jest-console/CHANGELOG.md +++ b/packages/jest-console/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 7.17.0 (2023-11-16) + ## 7.16.0 (2023-11-02) ## 7.15.0 (2023-10-18) diff --git a/packages/jest-console/package.json b/packages/jest-console/package.json index 40981febe941f6..2152ff6a5c0ddd 100644 --- a/packages/jest-console/package.json +++ b/packages/jest-console/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-console", - "version": "7.16.0", + "version": "7.17.0-prerelease", "description": "Custom Jest matchers for the Console object.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/jest-preset-default/CHANGELOG.md b/packages/jest-preset-default/CHANGELOG.md index a56d34dddad385..30db9b59cca7c3 100644 --- a/packages/jest-preset-default/CHANGELOG.md +++ b/packages/jest-preset-default/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 11.17.0 (2023-11-16) + ## 11.16.0 (2023-11-02) ## 11.15.0 (2023-10-18) diff --git a/packages/jest-preset-default/package.json b/packages/jest-preset-default/package.json index ecc07690603568..4fbd174c512c5e 100644 --- a/packages/jest-preset-default/package.json +++ b/packages/jest-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-preset-default", - "version": "11.16.0", + "version": "11.17.0-prerelease", "description": "Default Jest preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/jest-puppeteer-axe/CHANGELOG.md b/packages/jest-puppeteer-axe/CHANGELOG.md index acf19522a59bc9..6755f2d3f41365 100644 --- a/packages/jest-puppeteer-axe/CHANGELOG.md +++ b/packages/jest-puppeteer-axe/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.17.0 (2023-11-16) + ## 6.16.0 (2023-11-02) ## 6.15.0 (2023-10-18) diff --git a/packages/jest-puppeteer-axe/package.json b/packages/jest-puppeteer-axe/package.json index 68af3143838f38..5e87a4a542e335 100644 --- a/packages/jest-puppeteer-axe/package.json +++ b/packages/jest-puppeteer-axe/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-puppeteer-axe", - "version": "6.16.0", + "version": "6.17.0-prerelease", "description": "Axe API integration with Jest and Puppeteer.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/keyboard-shortcuts/CHANGELOG.md b/packages/keyboard-shortcuts/CHANGELOG.md index b5988c7102d039..f6fb39c60931c0 100644 --- a/packages/keyboard-shortcuts/CHANGELOG.md +++ b/packages/keyboard-shortcuts/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.23.0 (2023-11-16) + ## 4.22.0 (2023-11-02) ## 4.21.0 (2023-10-18) diff --git a/packages/keyboard-shortcuts/package.json b/packages/keyboard-shortcuts/package.json index 03100a616bc4ad..43e4d11af5cbbe 100644 --- a/packages/keyboard-shortcuts/package.json +++ b/packages/keyboard-shortcuts/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/keyboard-shortcuts", - "version": "4.22.0", + "version": "4.23.0-prerelease", "description": "Handling keyboard shortcuts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/keycodes/CHANGELOG.md b/packages/keycodes/CHANGELOG.md index 3ab5dc90aa8581..382510e52e3676 100644 --- a/packages/keycodes/CHANGELOG.md +++ b/packages/keycodes/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/keycodes/package.json b/packages/keycodes/package.json index f3705c6e523c17..9ecc81007b71a1 100644 --- a/packages/keycodes/package.json +++ b/packages/keycodes/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/keycodes", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "Keycodes utilities for WordPress. Used to check for keyboard events across browsers/operating systems.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/lazy-import/CHANGELOG.md b/packages/lazy-import/CHANGELOG.md index e96828769051f3..a092b101c7fe43 100644 --- a/packages/lazy-import/CHANGELOG.md +++ b/packages/lazy-import/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.33.0 (2023-11-16) + ## 1.32.0 (2023-11-02) ## 1.31.0 (2023-10-18) diff --git a/packages/lazy-import/package.json b/packages/lazy-import/package.json index f697a2c2595980..7e5561e2b6d182 100644 --- a/packages/lazy-import/package.json +++ b/packages/lazy-import/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/lazy-import", - "version": "1.32.0", + "version": "1.33.0-prerelease", "description": "Lazily import a module, installing it automatically if missing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/list-reusable-blocks/CHANGELOG.md b/packages/list-reusable-blocks/CHANGELOG.md index bb86ca45b59654..3c16e7ca341d0a 100644 --- a/packages/list-reusable-blocks/CHANGELOG.md +++ b/packages/list-reusable-blocks/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.23.0 (2023-11-16) + ## 4.22.0 (2023-11-02) ## 4.21.0 (2023-10-18) diff --git a/packages/list-reusable-blocks/package.json b/packages/list-reusable-blocks/package.json index 9cc27c6911a91c..70a3ae145a799f 100644 --- a/packages/list-reusable-blocks/package.json +++ b/packages/list-reusable-blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/list-reusable-blocks", - "version": "4.22.0", + "version": "4.23.0-prerelease", "description": "Adding Export/Import support to the reusable blocks listing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/media-utils/CHANGELOG.md b/packages/media-utils/CHANGELOG.md index bc1ea49c74c866..791752726da0e9 100644 --- a/packages/media-utils/CHANGELOG.md +++ b/packages/media-utils/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.37.0 (2023-11-16) + ## 4.36.0 (2023-11-02) ## 4.35.0 (2023-10-18) diff --git a/packages/media-utils/package.json b/packages/media-utils/package.json index 16477d6546ad7c..2f2e4f454f9eab 100644 --- a/packages/media-utils/package.json +++ b/packages/media-utils/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/media-utils", - "version": "4.36.0", + "version": "4.37.0-prerelease", "description": "WordPress Media Upload Utils.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/notices/CHANGELOG.md b/packages/notices/CHANGELOG.md index f22d214e00037b..0bb727268bc07b 100644 --- a/packages/notices/CHANGELOG.md +++ b/packages/notices/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.14.0 (2023-11-16) + ## 4.13.0 (2023-11-02) ## 4.12.0 (2023-10-18) diff --git a/packages/notices/package.json b/packages/notices/package.json index 798f2120b94df6..38c7fac68afbcb 100644 --- a/packages/notices/package.json +++ b/packages/notices/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/notices", - "version": "4.13.0", + "version": "4.14.0-prerelease", "description": "State management for notices.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/npm-package-json-lint-config/CHANGELOG.md b/packages/npm-package-json-lint-config/CHANGELOG.md index 1242e51b295a68..c4c811e7396d7e 100644 --- a/packages/npm-package-json-lint-config/CHANGELOG.md +++ b/packages/npm-package-json-lint-config/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.31.0 (2023-11-16) + ## 4.30.0 (2023-11-02) ## 4.29.0 (2023-10-18) diff --git a/packages/npm-package-json-lint-config/package.json b/packages/npm-package-json-lint-config/package.json index a3f4a0dfcc9305..3ad54a8a2a93a9 100644 --- a/packages/npm-package-json-lint-config/package.json +++ b/packages/npm-package-json-lint-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/npm-package-json-lint-config", - "version": "4.30.0", + "version": "4.31.0-prerelease", "description": "WordPress npm-package-json-lint shareable configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/nux/CHANGELOG.md b/packages/nux/CHANGELOG.md index fa995b4dbcf54c..d3fbfa4a703809 100644 --- a/packages/nux/CHANGELOG.md +++ b/packages/nux/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 8.8.0 (2023-11-16) + ## 8.7.0 (2023-11-02) ## 8.6.0 (2023-10-18) diff --git a/packages/nux/package.json b/packages/nux/package.json index f03f91dcf4c8b0..124d3cfacd9600 100644 --- a/packages/nux/package.json +++ b/packages/nux/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/nux", - "version": "8.7.0", + "version": "8.8.0-prerelease", "description": "NUX (New User eXperience) module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/patterns/CHANGELOG.md b/packages/patterns/CHANGELOG.md index 3a9c684d01b04e..30df46641ff4cd 100644 --- a/packages/patterns/CHANGELOG.md +++ b/packages/patterns/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.7.0 (2023-11-16) + ## 1.6.0 (2023-11-02) ## 1.5.0 (2023-10-18) diff --git a/packages/patterns/package.json b/packages/patterns/package.json index 41846c1047d931..8f417dc1aa5928 100644 --- a/packages/patterns/package.json +++ b/packages/patterns/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/patterns", - "version": "1.6.0", + "version": "1.7.0-prerelease", "description": "Management of user pattern editing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/plugins/CHANGELOG.md b/packages/plugins/CHANGELOG.md index fd5dd315e0f874..7d6ad16901b7b2 100644 --- a/packages/plugins/CHANGELOG.md +++ b/packages/plugins/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.14.0 (2023-11-16) + ## 6.13.0 (2023-11-02) ## 6.12.0 (2023-10-18) diff --git a/packages/plugins/package.json b/packages/plugins/package.json index 17d06c6b63e62c..e9ffee30feba87 100644 --- a/packages/plugins/package.json +++ b/packages/plugins/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/plugins", - "version": "6.13.0", + "version": "6.14.0-prerelease", "description": "Plugins module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/postcss-plugins-preset/CHANGELOG.md b/packages/postcss-plugins-preset/CHANGELOG.md index d38ea1a8b87695..28088d4cfa0ae2 100644 --- a/packages/postcss-plugins-preset/CHANGELOG.md +++ b/packages/postcss-plugins-preset/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.30.0 (2023-11-16) + ## 4.29.0 (2023-11-02) ## 4.28.0 (2023-10-18) diff --git a/packages/postcss-plugins-preset/package.json b/packages/postcss-plugins-preset/package.json index 83526a9fabb21f..ffd3230b90bd78 100644 --- a/packages/postcss-plugins-preset/package.json +++ b/packages/postcss-plugins-preset/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/postcss-plugins-preset", - "version": "4.29.0", + "version": "4.30.0-prerelease", "description": "PostCSS sharable plugins preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/postcss-themes/CHANGELOG.md b/packages/postcss-themes/CHANGELOG.md index ac7fea38014d92..1b26ac952c41e0 100644 --- a/packages/postcss-themes/CHANGELOG.md +++ b/packages/postcss-themes/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.29.0 (2023-11-16) + ## 5.28.0 (2023-11-02) ## 5.27.0 (2023-10-18) diff --git a/packages/postcss-themes/package.json b/packages/postcss-themes/package.json index 27f3fd4b586eab..2b65ddefc795a5 100644 --- a/packages/postcss-themes/package.json +++ b/packages/postcss-themes/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/postcss-themes", - "version": "5.28.0", + "version": "5.29.0-prerelease", "description": "PostCSS plugin to generate theme colors.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/preferences-persistence/CHANGELOG.md b/packages/preferences-persistence/CHANGELOG.md index d713e87f8b8300..531a57d6130204 100644 --- a/packages/preferences-persistence/CHANGELOG.md +++ b/packages/preferences-persistence/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.38.0 (2023-11-16) + ## 1.37.0 (2023-11-02) ## 1.36.0 (2023-10-18) diff --git a/packages/preferences-persistence/package.json b/packages/preferences-persistence/package.json index 82749616cfd3f8..6a76d6094bac5a 100644 --- a/packages/preferences-persistence/package.json +++ b/packages/preferences-persistence/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/preferences-persistence", - "version": "1.37.0", + "version": "1.38.0-prerelease", "description": "Persistence utilities for `wordpress/preferences`.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/preferences/CHANGELOG.md b/packages/preferences/CHANGELOG.md index 30fdb20745de06..29c48cd51c787a 100644 --- a/packages/preferences/CHANGELOG.md +++ b/packages/preferences/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.23.0 (2023-11-16) + ## 3.22.0 (2023-11-02) ## 3.21.0 (2023-10-18) diff --git a/packages/preferences/package.json b/packages/preferences/package.json index 3f11fbcdfd9a75..0ba849dc9787a2 100644 --- a/packages/preferences/package.json +++ b/packages/preferences/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/preferences", - "version": "3.22.0", + "version": "3.23.0-prerelease", "description": "Utilities for managing WordPress preferences.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/prettier-config/CHANGELOG.md b/packages/prettier-config/CHANGELOG.md index 69b5e5cec92d6c..3fb6aa431973fb 100644 --- a/packages/prettier-config/CHANGELOG.md +++ b/packages/prettier-config/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.3.0 (2023-11-16) + ## 3.2.0 (2023-11-02) ## 3.1.0 (2023-10-18) diff --git a/packages/prettier-config/package.json b/packages/prettier-config/package.json index a6f46e47f2bf30..7e4168c931d8ed 100644 --- a/packages/prettier-config/package.json +++ b/packages/prettier-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/prettier-config", - "version": "3.2.0", + "version": "3.3.0-prerelease", "description": "WordPress Prettier shared configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/primitives/CHANGELOG.md b/packages/primitives/CHANGELOG.md index 14c4937b0b8fe2..0c24a126097eea 100644 --- a/packages/primitives/CHANGELOG.md +++ b/packages/primitives/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.44.0 (2023-11-16) + ## 3.43.0 (2023-11-02) ## 3.42.0 (2023-10-18) diff --git a/packages/primitives/package.json b/packages/primitives/package.json index fc7e91899106fc..274755ff59b2d5 100644 --- a/packages/primitives/package.json +++ b/packages/primitives/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/primitives", - "version": "3.43.0", + "version": "3.44.0-prerelease", "description": "WordPress cross-platform primitives.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/priority-queue/CHANGELOG.md b/packages/priority-queue/CHANGELOG.md index 19fe7c317c8111..c9e8b4c7e566cf 100644 --- a/packages/priority-queue/CHANGELOG.md +++ b/packages/priority-queue/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.46.0 (2023-11-16) + ## 2.45.0 (2023-11-02) ## 2.44.0 (2023-10-18) diff --git a/packages/priority-queue/package.json b/packages/priority-queue/package.json index 5888f6512d7476..2290bceeb8cc3d 100644 --- a/packages/priority-queue/package.json +++ b/packages/priority-queue/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/priority-queue", - "version": "2.45.0", + "version": "2.46.0-prerelease", "description": "Generic browser priority queue.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/private-apis/CHANGELOG.md b/packages/private-apis/CHANGELOG.md index 35b6922652f0f1..65380c088560dd 100644 --- a/packages/private-apis/CHANGELOG.md +++ b/packages/private-apis/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.28.0 (2023-11-16) + ## 0.27.0 (2023-11-02) ## 0.26.0 (2023-10-18) diff --git a/packages/private-apis/package.json b/packages/private-apis/package.json index 4fafa6a3300a6e..ccc4999d2fb177 100644 --- a/packages/private-apis/package.json +++ b/packages/private-apis/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/private-apis", - "version": "0.27.0", + "version": "0.28.0-prerelease", "description": "Internal experimental APIs for WordPress core.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/project-management-automation/CHANGELOG.md b/packages/project-management-automation/CHANGELOG.md index 6a627754e9d95a..945fac3a5cb1b0 100644 --- a/packages/project-management-automation/CHANGELOG.md +++ b/packages/project-management-automation/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.45.0 (2023-11-16) + ## 1.44.0 (2023-11-02) ## 1.43.0 (2023-10-18) diff --git a/packages/project-management-automation/package.json b/packages/project-management-automation/package.json index 7c6d127547e68f..a75b111d795cdc 100644 --- a/packages/project-management-automation/package.json +++ b/packages/project-management-automation/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/project-management-automation", - "version": "1.44.0", + "version": "1.45.0-prerelease", "description": "GitHub Action that implements various automation to assist with managing the Gutenberg GitHub repository.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/react-i18n/CHANGELOG.md b/packages/react-i18n/CHANGELOG.md index 8182887ba32119..2ec98e2ed0eae4 100644 --- a/packages/react-i18n/CHANGELOG.md +++ b/packages/react-i18n/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.44.0 (2023-11-16) + ## 3.43.0 (2023-11-02) ## 3.42.0 (2023-10-18) diff --git a/packages/react-i18n/package.json b/packages/react-i18n/package.json index 4f0ad12a58bf70..3a08d14983bc22 100644 --- a/packages/react-i18n/package.json +++ b/packages/react-i18n/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/react-i18n", - "version": "3.43.0", + "version": "3.44.0-prerelease", "description": "React bindings for @wordpress/i18n.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/readable-js-assets-webpack-plugin/CHANGELOG.md b/packages/readable-js-assets-webpack-plugin/CHANGELOG.md index 1dcd6ffe2286c8..73466451aaad3d 100644 --- a/packages/readable-js-assets-webpack-plugin/CHANGELOG.md +++ b/packages/readable-js-assets-webpack-plugin/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.29.0 (2023-11-16) + ## 2.28.0 (2023-11-02) ## 2.27.0 (2023-10-18) diff --git a/packages/readable-js-assets-webpack-plugin/package.json b/packages/readable-js-assets-webpack-plugin/package.json index 34d4acff7dc7e6..646b8999d34414 100644 --- a/packages/readable-js-assets-webpack-plugin/package.json +++ b/packages/readable-js-assets-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/readable-js-assets-webpack-plugin", - "version": "2.28.0", + "version": "2.29.0-prerelease", "description": "Generate a readable JS file for each JS asset.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/redux-routine/CHANGELOG.md b/packages/redux-routine/CHANGELOG.md index e7fd714fdf8579..0bd8a9e3143f61 100644 --- a/packages/redux-routine/CHANGELOG.md +++ b/packages/redux-routine/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.46.0 (2023-11-16) + ## 4.45.0 (2023-11-02) ## 4.44.0 (2023-10-18) diff --git a/packages/redux-routine/package.json b/packages/redux-routine/package.json index 1929ddaf9e2e7e..b6a8fe417da8d5 100644 --- a/packages/redux-routine/package.json +++ b/packages/redux-routine/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/redux-routine", - "version": "4.45.0", + "version": "4.46.0-prerelease", "description": "Redux middleware for generator coroutines.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/reusable-blocks/CHANGELOG.md b/packages/reusable-blocks/CHANGELOG.md index c6905ac3ea5672..c8208c76e0b747 100644 --- a/packages/reusable-blocks/CHANGELOG.md +++ b/packages/reusable-blocks/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.23.0 (2023-11-16) + ## 4.22.0 (2023-11-02) ## 4.21.0 (2023-10-18) diff --git a/packages/reusable-blocks/package.json b/packages/reusable-blocks/package.json index ebf4f7f7d9551d..8ffdb18e598116 100644 --- a/packages/reusable-blocks/package.json +++ b/packages/reusable-blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/reusable-blocks", - "version": "4.22.0", + "version": "4.23.0-prerelease", "description": "Reusable blocks utilities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/rich-text/CHANGELOG.md b/packages/rich-text/CHANGELOG.md index 6abaf8c9c50b1b..46275b44ca2a97 100644 --- a/packages/rich-text/CHANGELOG.md +++ b/packages/rich-text/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.23.0 (2023-11-16) + ## 6.22.0 (2023-11-02) ## 6.21.0 (2023-10-18) diff --git a/packages/rich-text/package.json b/packages/rich-text/package.json index 4cfa58cbf1e0a9..0d805777e2d4f7 100644 --- a/packages/rich-text/package.json +++ b/packages/rich-text/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/rich-text", - "version": "6.22.0", + "version": "6.23.0-prerelease", "description": "Rich text value and manipulation API.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/router/CHANGELOG.md b/packages/router/CHANGELOG.md index 3c16003e012312..e2766c9819b3ef 100644 --- a/packages/router/CHANGELOG.md +++ b/packages/router/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.15.0 (2023-11-16) + ## 0.14.0 (2023-11-02) ## 0.13.0 (2023-10-18) diff --git a/packages/router/package.json b/packages/router/package.json index ec7f3d68f23759..a27be42a33cd48 100644 --- a/packages/router/package.json +++ b/packages/router/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/router", - "version": "0.14.0", + "version": "0.15.0-prerelease", "description": "Router API for WordPress pages.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md index 7bc907d1466140..bf48542f5fc019 100644 --- a/packages/scripts/CHANGELOG.md +++ b/packages/scripts/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 26.17.0 (2023-11-16) + ## 26.16.0 (2023-11-02) ## 26.15.0 (2023-10-18) diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 8cfd0a6e614cdb..21194afad7cdde 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/scripts", - "version": "26.16.0", + "version": "26.17.0-prerelease", "description": "Collection of reusable scripts for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/server-side-render/CHANGELOG.md b/packages/server-side-render/CHANGELOG.md index 81dd8ffe397284..739fa28341ef16 100644 --- a/packages/server-side-render/CHANGELOG.md +++ b/packages/server-side-render/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.23.0 (2023-11-16) + ## 4.22.0 (2023-11-02) ## 4.21.0 (2023-10-18) diff --git a/packages/server-side-render/package.json b/packages/server-side-render/package.json index 647ee48df2438b..74d84e29e28ada 100644 --- a/packages/server-side-render/package.json +++ b/packages/server-side-render/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/server-side-render", - "version": "4.22.0", + "version": "4.23.0-prerelease", "description": "The component used with WordPress to server-side render a preview of dynamic blocks to display in the editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/shortcode/CHANGELOG.md b/packages/shortcode/CHANGELOG.md index b97c6725a71f5f..7c2ff99196b597 100644 --- a/packages/shortcode/CHANGELOG.md +++ b/packages/shortcode/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/shortcode/package.json b/packages/shortcode/package.json index 6de5a6d67650ad..3a59b60a29918e 100644 --- a/packages/shortcode/package.json +++ b/packages/shortcode/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/shortcode", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "Shortcode module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/style-engine/CHANGELOG.md b/packages/style-engine/CHANGELOG.md index 037bd3fd280afd..ddb01f0b2fdaec 100644 --- a/packages/style-engine/CHANGELOG.md +++ b/packages/style-engine/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.29.0 (2023-11-16) + ## 1.28.0 (2023-11-02) ## 1.27.0 (2023-10-18) diff --git a/packages/style-engine/package.json b/packages/style-engine/package.json index b1bc0e7f4826d1..19c15d261898af 100644 --- a/packages/style-engine/package.json +++ b/packages/style-engine/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/style-engine", - "version": "1.28.0", + "version": "1.29.0-prerelease", "description": "A suite of parsers and compilers for WordPress styles.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/stylelint-config/CHANGELOG.md b/packages/stylelint-config/CHANGELOG.md index f8343e6e3a8a6a..c7c0ab1a036f45 100644 --- a/packages/stylelint-config/CHANGELOG.md +++ b/packages/stylelint-config/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 21.29.0 (2023-11-16) + ## 21.28.0 (2023-11-02) ## 21.27.0 (2023-10-18) diff --git a/packages/stylelint-config/package.json b/packages/stylelint-config/package.json index e3a5a9527b3e3b..f82b2cee235029 100644 --- a/packages/stylelint-config/package.json +++ b/packages/stylelint-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/stylelint-config", - "version": "21.28.0", + "version": "21.29.0-prerelease", "description": "stylelint config for WordPress development.", "author": "The WordPress Contributors", "license": "MIT", diff --git a/packages/sync/CHANGELOG.md b/packages/sync/CHANGELOG.md index dff982dd59a4e6..4465921540906f 100644 --- a/packages/sync/CHANGELOG.md +++ b/packages/sync/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.8.0 (2023-11-16) + ## 0.7.0 (2023-11-02) ## 0.6.0 (2023-10-18) diff --git a/packages/sync/package.json b/packages/sync/package.json index bf2c2432979a80..cd48de011a183c 100644 --- a/packages/sync/package.json +++ b/packages/sync/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/sync", - "version": "0.7.0", + "version": "0.8.0-prerelease", "description": "Sync Data.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/token-list/CHANGELOG.md b/packages/token-list/CHANGELOG.md index 6ef90fbbabd948..920705623ca7be 100644 --- a/packages/token-list/CHANGELOG.md +++ b/packages/token-list/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.46.0 (2023-11-16) + ## 2.45.0 (2023-11-02) ## 2.44.0 (2023-10-18) diff --git a/packages/token-list/package.json b/packages/token-list/package.json index 0c7e4c0cc8a79c..cb7f13dceeec61 100644 --- a/packages/token-list/package.json +++ b/packages/token-list/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/token-list", - "version": "2.45.0", + "version": "2.46.0-prerelease", "description": "Constructable, plain JavaScript DOMTokenList implementation, supporting non-browser runtimes.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/undo-manager/CHANGELOG.md b/packages/undo-manager/CHANGELOG.md index 67cc197b926e14..9c7fc9d98f62c5 100644 --- a/packages/undo-manager/CHANGELOG.md +++ b/packages/undo-manager/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.6.0 (2023-11-16) + ## 0.5.0 (2023-11-02) ## 0.4.0 (2023-10-18) diff --git a/packages/undo-manager/package.json b/packages/undo-manager/package.json index 212338276f4a1e..f8b8401774dbfe 100644 --- a/packages/undo-manager/package.json +++ b/packages/undo-manager/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/undo-manager", - "version": "0.5.0", + "version": "0.6.0-prerelease", "description": "A small package to manage undo/redo.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/url/CHANGELOG.md b/packages/url/CHANGELOG.md index e42e0e039647cc..66632d73e945d5 100644 --- a/packages/url/CHANGELOG.md +++ b/packages/url/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.47.0 (2023-11-16) + ## 3.46.0 (2023-11-02) ## 3.45.0 (2023-10-18) diff --git a/packages/url/package.json b/packages/url/package.json index 2d248f25ab8044..af28dea0b4444f 100644 --- a/packages/url/package.json +++ b/packages/url/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/url", - "version": "3.46.0", + "version": "3.47.0-prerelease", "description": "WordPress URL utilities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/viewport/CHANGELOG.md b/packages/viewport/CHANGELOG.md index fccff866614894..02c093f466c674 100644 --- a/packages/viewport/CHANGELOG.md +++ b/packages/viewport/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.23.0 (2023-11-16) + ## 5.22.0 (2023-11-02) ## 5.21.0 (2023-10-18) diff --git a/packages/viewport/package.json b/packages/viewport/package.json index e08791592ef654..0809dee6f1d9ab 100644 --- a/packages/viewport/package.json +++ b/packages/viewport/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/viewport", - "version": "5.22.0", + "version": "5.23.0-prerelease", "description": "Viewport module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/warning/CHANGELOG.md b/packages/warning/CHANGELOG.md index dc65344a4af5c8..68504579d3188f 100644 --- a/packages/warning/CHANGELOG.md +++ b/packages/warning/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.46.0 (2023-11-16) + ## 2.45.0 (2023-11-02) ## 2.44.0 (2023-10-18) diff --git a/packages/warning/package.json b/packages/warning/package.json index 69f21eb47967e5..899d36d9cafc0c 100644 --- a/packages/warning/package.json +++ b/packages/warning/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/warning", - "version": "2.45.0", + "version": "2.46.0-prerelease", "description": "Warning utility for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/widgets/CHANGELOG.md b/packages/widgets/CHANGELOG.md index 8c1952f5669393..97fd6909b10adf 100644 --- a/packages/widgets/CHANGELOG.md +++ b/packages/widgets/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.23.0 (2023-11-16) + ## 3.22.0 (2023-11-02) ## 3.21.0 (2023-10-18) diff --git a/packages/widgets/package.json b/packages/widgets/package.json index afdd9bb5e4fac7..06e7e9a788f206 100644 --- a/packages/widgets/package.json +++ b/packages/widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/widgets", - "version": "3.22.0", + "version": "3.23.0-prerelease", "description": "Functionality used by the widgets block editor in the Widgets screen and the Customizer.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/wordcount/CHANGELOG.md b/packages/wordcount/CHANGELOG.md index 99501b5aec4329..7b2a56464d0832 100644 --- a/packages/wordcount/CHANGELOG.md +++ b/packages/wordcount/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.46.0 (2023-11-16) + ## 3.45.0 (2023-11-02) ## 3.44.0 (2023-10-18) diff --git a/packages/wordcount/package.json b/packages/wordcount/package.json index e87b45e895f3c4..504e5c0b84bfc2 100644 --- a/packages/wordcount/package.json +++ b/packages/wordcount/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/wordcount", - "version": "3.45.0", + "version": "3.46.0-prerelease", "description": "WordPress word count utility.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", From ca5c86db2fb2a2ff63d20c409ad709969bb7fd2e Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Thu, 16 Nov 2023 19:37:35 +0000 Subject: [PATCH 058/116] chore(release): publish - @wordpress/a11y@3.46.0 - @wordpress/annotations@2.46.0 - @wordpress/api-fetch@6.43.0 - @wordpress/autop@3.46.0 - @wordpress/babel-plugin-import-jsx-pragma@4.29.0 - @wordpress/babel-plugin-makepot@5.30.0 - @wordpress/babel-preset-default@7.30.0 - @wordpress/base-styles@4.37.0 - @wordpress/blob@3.46.0 - @wordpress/block-directory@4.23.0 - @wordpress/block-editor@12.14.0 - @wordpress/block-library@8.23.0 - @wordpress/block-serialization-default-parser@4.46.0 - @wordpress/block-serialization-spec-parser@4.46.0 - @wordpress/blocks@12.23.0 - @wordpress/browserslist-config@5.29.0 - @wordpress/commands@0.17.0 - @wordpress/components@25.12.0 - @wordpress/compose@6.23.0 - @wordpress/core-commands@0.15.0 - @wordpress/core-data@6.23.0 - @wordpress/create-block@4.30.0 - @wordpress/create-block-interactive-template@1.9.0 - @wordpress/create-block-tutorial-template@3.0.0 - @wordpress/customize-widgets@4.23.0 - @wordpress/data@9.16.0 - @wordpress/data-controls@3.15.0 - @wordpress/date@4.46.0 - @wordpress/dependency-extraction-webpack-plugin@4.29.0 - @wordpress/deprecated@3.46.0 - @wordpress/docgen@1.55.0 - @wordpress/dom@3.46.0 - @wordpress/dom-ready@3.46.0 - @wordpress/e2e-test-utils@10.17.0 - @wordpress/e2e-test-utils-playwright@0.14.0 - @wordpress/e2e-tests@7.17.0 - @wordpress/edit-post@7.23.0 - @wordpress/edit-site@5.23.0 - @wordpress/edit-widgets@5.23.0 - @wordpress/editor@13.23.0 - @wordpress/element@5.23.0 - @wordpress/env@8.12.0 - @wordpress/escape-html@2.46.0 - @wordpress/eslint-plugin@17.3.0 - @wordpress/format-library@4.23.0 - @wordpress/hooks@3.46.0 - @wordpress/html-entities@3.46.0 - @wordpress/i18n@4.46.0 - @wordpress/icons@9.37.0 - @wordpress/interactivity@2.7.0 - @wordpress/interface@5.23.0 - @wordpress/is-shallow-equal@4.46.0 - @wordpress/jest-console@7.17.0 - @wordpress/jest-preset-default@11.17.0 - @wordpress/jest-puppeteer-axe@6.17.0 - @wordpress/keyboard-shortcuts@4.23.0 - @wordpress/keycodes@3.46.0 - @wordpress/lazy-import@1.33.0 - @wordpress/list-reusable-blocks@4.23.0 - @wordpress/media-utils@4.37.0 - @wordpress/notices@4.14.0 - @wordpress/npm-package-json-lint-config@4.31.0 - @wordpress/nux@8.8.0 - @wordpress/patterns@1.7.0 - @wordpress/plugins@6.14.0 - @wordpress/postcss-plugins-preset@4.30.0 - @wordpress/postcss-themes@5.29.0 - @wordpress/preferences@3.23.0 - @wordpress/preferences-persistence@1.38.0 - @wordpress/prettier-config@3.3.0 - @wordpress/primitives@3.44.0 - @wordpress/priority-queue@2.46.0 - @wordpress/private-apis@0.28.0 - @wordpress/project-management-automation@1.45.0 - @wordpress/react-i18n@3.44.0 - @wordpress/readable-js-assets-webpack-plugin@2.29.0 - @wordpress/redux-routine@4.46.0 - @wordpress/reusable-blocks@4.23.0 - @wordpress/rich-text@6.23.0 - @wordpress/router@0.15.0 - @wordpress/scripts@26.17.0 - @wordpress/server-side-render@4.23.0 - @wordpress/shortcode@3.46.0 - @wordpress/style-engine@1.29.0 - @wordpress/stylelint-config@21.29.0 - @wordpress/sync@0.8.0 - @wordpress/token-list@2.46.0 - @wordpress/undo-manager@0.6.0 - @wordpress/url@3.47.0 - @wordpress/viewport@5.23.0 - @wordpress/warning@2.46.0 - @wordpress/widgets@3.23.0 - @wordpress/wordcount@3.46.0 --- package-lock.json | 184 +++++++++--------- packages/a11y/package.json | 2 +- packages/annotations/package.json | 2 +- packages/api-fetch/package.json | 2 +- packages/autop/package.json | 2 +- .../package.json | 2 +- packages/babel-plugin-makepot/package.json | 2 +- packages/babel-preset-default/package.json | 2 +- packages/base-styles/package.json | 2 +- packages/blob/package.json | 2 +- packages/block-directory/package.json | 2 +- packages/block-editor/package.json | 2 +- packages/block-library/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- packages/blocks/package.json | 2 +- packages/browserslist-config/package.json | 2 +- packages/commands/package.json | 2 +- packages/components/package.json | 2 +- packages/compose/package.json | 2 +- packages/core-commands/package.json | 2 +- packages/core-data/package.json | 2 +- .../package.json | 2 +- .../package.json | 2 +- packages/create-block/package.json | 2 +- packages/customize-widgets/package.json | 2 +- packages/data-controls/package.json | 2 +- packages/data/package.json | 2 +- packages/date/package.json | 2 +- .../package.json | 2 +- packages/deprecated/package.json | 2 +- packages/docgen/package.json | 2 +- packages/dom-ready/package.json | 2 +- packages/dom/package.json | 2 +- .../e2e-test-utils-playwright/package.json | 2 +- packages/e2e-test-utils/package.json | 2 +- packages/e2e-tests/package.json | 2 +- packages/edit-post/package.json | 2 +- packages/edit-site/package.json | 2 +- packages/edit-widgets/package.json | 2 +- packages/editor/package.json | 2 +- packages/element/package.json | 2 +- packages/env/package.json | 2 +- packages/escape-html/package.json | 2 +- packages/eslint-plugin/package.json | 2 +- packages/format-library/package.json | 2 +- packages/hooks/package.json | 2 +- packages/html-entities/package.json | 2 +- packages/i18n/package.json | 2 +- packages/icons/package.json | 2 +- packages/interactivity/package.json | 2 +- packages/interface/package.json | 2 +- packages/is-shallow-equal/package.json | 2 +- packages/jest-console/package.json | 2 +- packages/jest-preset-default/package.json | 2 +- packages/jest-puppeteer-axe/package.json | 2 +- packages/keyboard-shortcuts/package.json | 2 +- packages/keycodes/package.json | 2 +- packages/lazy-import/package.json | 2 +- packages/list-reusable-blocks/package.json | 2 +- packages/media-utils/package.json | 2 +- packages/notices/package.json | 2 +- .../npm-package-json-lint-config/package.json | 2 +- packages/nux/package.json | 2 +- packages/patterns/package.json | 2 +- packages/plugins/package.json | 2 +- packages/postcss-plugins-preset/package.json | 2 +- packages/postcss-themes/package.json | 2 +- packages/preferences-persistence/package.json | 2 +- packages/preferences/package.json | 2 +- packages/prettier-config/package.json | 2 +- packages/primitives/package.json | 2 +- packages/priority-queue/package.json | 2 +- packages/private-apis/package.json | 2 +- .../package.json | 2 +- packages/react-i18n/package.json | 2 +- .../package.json | 2 +- packages/redux-routine/package.json | 2 +- packages/reusable-blocks/package.json | 2 +- packages/rich-text/package.json | 2 +- packages/router/package.json | 2 +- packages/scripts/package.json | 2 +- packages/server-side-render/package.json | 2 +- packages/shortcode/package.json | 2 +- packages/style-engine/package.json | 2 +- packages/stylelint-config/package.json | 2 +- packages/sync/package.json | 2 +- packages/token-list/package.json | 2 +- packages/undo-manager/package.json | 2 +- packages/url/package.json | 2 +- packages/viewport/package.json | 2 +- packages/warning/package.json | 2 +- packages/widgets/package.json | 2 +- packages/wordcount/package.json | 2 +- 94 files changed, 185 insertions(+), 185 deletions(-) diff --git a/package-lock.json b/package-lock.json index 158d3ab9e25c14..8382dd2413d46a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54404,7 +54404,7 @@ }, "packages/a11y": { "name": "@wordpress/a11y", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54417,7 +54417,7 @@ }, "packages/annotations": { "name": "@wordpress/annotations", - "version": "2.45.0", + "version": "2.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54445,7 +54445,7 @@ }, "packages/api-fetch": { "name": "@wordpress/api-fetch", - "version": "6.42.0", + "version": "6.43.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54458,7 +54458,7 @@ }, "packages/autop": { "name": "@wordpress/autop", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -54469,7 +54469,7 @@ }, "packages/babel-plugin-import-jsx-pragma": { "name": "@wordpress/babel-plugin-import-jsx-pragma", - "version": "4.28.0", + "version": "4.29.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -54481,7 +54481,7 @@ }, "packages/babel-plugin-makepot": { "name": "@wordpress/babel-plugin-makepot", - "version": "5.29.0", + "version": "5.30.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -54498,7 +54498,7 @@ }, "packages/babel-preset-default": { "name": "@wordpress/babel-preset-default", - "version": "7.29.0", + "version": "7.30.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -54521,13 +54521,13 @@ }, "packages/base-styles": { "name": "@wordpress/base-styles", - "version": "4.36.0", + "version": "4.37.0", "dev": true, "license": "GPL-2.0-or-later" }, "packages/blob": { "name": "@wordpress/blob", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -54538,7 +54538,7 @@ }, "packages/block-directory": { "name": "@wordpress/block-directory", - "version": "4.22.0", + "version": "4.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54573,7 +54573,7 @@ }, "packages/block-editor": { "name": "@wordpress/block-editor", - "version": "12.13.0", + "version": "12.14.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54670,7 +54670,7 @@ }, "packages/block-library": { "name": "@wordpress/block-library", - "version": "8.22.0", + "version": "8.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54732,7 +54732,7 @@ }, "packages/block-serialization-default-parser": { "name": "@wordpress/block-serialization-default-parser", - "version": "4.45.0", + "version": "4.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -54743,7 +54743,7 @@ }, "packages/block-serialization-spec-parser": { "name": "@wordpress/block-serialization-spec-parser", - "version": "4.45.0", + "version": "4.46.0", "license": "GPL-2.0-or-later", "dependencies": { "pegjs": "^0.10.0", @@ -54755,7 +54755,7 @@ }, "packages/blocks": { "name": "@wordpress/blocks", - "version": "12.22.0", + "version": "12.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54803,7 +54803,7 @@ }, "packages/browserslist-config": { "name": "@wordpress/browserslist-config", - "version": "5.28.0", + "version": "5.29.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -54812,7 +54812,7 @@ }, "packages/commands": { "name": "@wordpress/commands", - "version": "0.16.0", + "version": "0.17.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54837,7 +54837,7 @@ }, "packages/components": { "name": "@wordpress/components", - "version": "25.11.0", + "version": "25.12.0", "license": "GPL-2.0-or-later", "dependencies": { "@ariakit/react": "^0.3.5", @@ -54943,7 +54943,7 @@ }, "packages/compose": { "name": "@wordpress/compose", - "version": "6.22.0", + "version": "6.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54969,7 +54969,7 @@ }, "packages/core-commands": { "name": "@wordpress/core-commands", - "version": "0.14.0", + "version": "0.15.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -54994,7 +54994,7 @@ }, "packages/core-data": { "name": "@wordpress/core-data", - "version": "6.22.0", + "version": "6.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55038,7 +55038,7 @@ }, "packages/create-block": { "name": "@wordpress/create-block", - "version": "4.29.0", + "version": "4.30.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55066,13 +55066,13 @@ }, "packages/create-block-tutorial-template": { "name": "@wordpress/create-block-tutorial-template", - "version": "2.33.0", + "version": "3.0.0", "dev": true, "license": "GPL-2.0-or-later" }, "packages/customize-widgets": { "name": "@wordpress/customize-widgets", - "version": "4.22.0", + "version": "4.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55109,7 +55109,7 @@ }, "packages/data": { "name": "@wordpress/data", - "version": "9.15.0", + "version": "9.16.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55137,7 +55137,7 @@ }, "packages/data-controls": { "name": "@wordpress/data-controls", - "version": "3.14.0", + "version": "3.15.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55154,7 +55154,7 @@ }, "packages/date": { "name": "@wordpress/date", - "version": "4.45.0", + "version": "4.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55168,7 +55168,7 @@ }, "packages/dependency-extraction-webpack-plugin": { "name": "@wordpress/dependency-extraction-webpack-plugin", - "version": "4.28.0", + "version": "4.29.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55184,7 +55184,7 @@ }, "packages/deprecated": { "name": "@wordpress/deprecated", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55196,7 +55196,7 @@ }, "packages/docgen": { "name": "@wordpress/docgen", - "version": "1.54.0", + "version": "1.55.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55214,7 +55214,7 @@ }, "packages/dom": { "name": "@wordpress/dom", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55226,7 +55226,7 @@ }, "packages/dom-ready": { "name": "@wordpress/dom-ready", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -55237,7 +55237,7 @@ }, "packages/e2e-test-utils": { "name": "@wordpress/e2e-test-utils", - "version": "10.16.0", + "version": "10.17.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55259,7 +55259,7 @@ }, "packages/e2e-test-utils-playwright": { "name": "@wordpress/e2e-test-utils-playwright", - "version": "0.13.0", + "version": "0.14.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55282,7 +55282,7 @@ }, "packages/e2e-tests": { "name": "@wordpress/e2e-tests", - "version": "7.16.0", + "version": "7.17.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55320,7 +55320,7 @@ }, "packages/edit-post": { "name": "@wordpress/edit-post", - "version": "7.22.0", + "version": "7.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55368,7 +55368,7 @@ }, "packages/edit-site": { "name": "@wordpress/edit-site", - "version": "5.22.0", + "version": "5.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55433,7 +55433,7 @@ }, "packages/edit-widgets": { "name": "@wordpress/edit-widgets", - "version": "5.22.0", + "version": "5.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55475,7 +55475,7 @@ }, "packages/editor": { "name": "@wordpress/editor", - "version": "13.22.0", + "version": "13.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55525,7 +55525,7 @@ }, "packages/element": { "name": "@wordpress/element", - "version": "5.22.0", + "version": "5.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55543,7 +55543,7 @@ }, "packages/env": { "name": "@wordpress/env", - "version": "8.11.0", + "version": "8.12.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55656,7 +55656,7 @@ }, "packages/escape-html": { "name": "@wordpress/escape-html", - "version": "2.45.0", + "version": "2.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -55667,7 +55667,7 @@ }, "packages/eslint-plugin": { "name": "@wordpress/eslint-plugin", - "version": "17.2.0", + "version": "17.3.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55710,7 +55710,7 @@ }, "packages/format-library": { "name": "@wordpress/format-library", - "version": "4.22.0", + "version": "4.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55736,7 +55736,7 @@ }, "packages/hooks": { "name": "@wordpress/hooks", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -55747,7 +55747,7 @@ }, "packages/html-entities": { "name": "@wordpress/html-entities", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -55758,7 +55758,7 @@ }, "packages/i18n": { "name": "@wordpress/i18n", - "version": "4.45.0", + "version": "4.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55777,7 +55777,7 @@ }, "packages/icons": { "name": "@wordpress/icons", - "version": "9.36.0", + "version": "9.37.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55790,7 +55790,7 @@ }, "packages/interactivity": { "name": "@wordpress/interactivity", - "version": "2.6.0", + "version": "2.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@preact/signals": "^1.1.3", @@ -55803,7 +55803,7 @@ }, "packages/interface": { "name": "@wordpress/interface", - "version": "5.22.0", + "version": "5.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55830,7 +55830,7 @@ }, "packages/is-shallow-equal": { "name": "@wordpress/is-shallow-equal", - "version": "4.45.0", + "version": "4.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -55841,7 +55841,7 @@ }, "packages/jest-console": { "name": "@wordpress/jest-console", - "version": "7.16.0", + "version": "7.17.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55857,7 +55857,7 @@ }, "packages/jest-preset-default": { "name": "@wordpress/jest-preset-default", - "version": "11.16.0", + "version": "11.17.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55874,7 +55874,7 @@ }, "packages/jest-puppeteer-axe": { "name": "@wordpress/jest-puppeteer-axe", - "version": "6.16.0", + "version": "6.17.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55896,7 +55896,7 @@ }, "packages/keyboard-shortcuts": { "name": "@wordpress/keyboard-shortcuts", - "version": "4.22.0", + "version": "4.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55914,7 +55914,7 @@ }, "packages/keycodes": { "name": "@wordpress/keycodes", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55927,7 +55927,7 @@ }, "packages/lazy-import": { "name": "@wordpress/lazy-import", - "version": "1.32.0", + "version": "1.33.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -55941,7 +55941,7 @@ }, "packages/list-reusable-blocks": { "name": "@wordpress/list-reusable-blocks", - "version": "4.22.0", + "version": "4.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55963,7 +55963,7 @@ }, "packages/media-utils": { "name": "@wordpress/media-utils", - "version": "4.36.0", + "version": "4.37.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55978,7 +55978,7 @@ }, "packages/notices": { "name": "@wordpress/notices", - "version": "4.13.0", + "version": "4.14.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -55994,7 +55994,7 @@ }, "packages/npm-package-json-lint-config": { "name": "@wordpress/npm-package-json-lint-config", - "version": "4.30.0", + "version": "4.31.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -56006,7 +56006,7 @@ }, "packages/nux": { "name": "@wordpress/nux", - "version": "8.7.0", + "version": "8.8.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56029,7 +56029,7 @@ }, "packages/patterns": { "name": "@wordpress/patterns", - "version": "1.6.0", + "version": "1.7.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56058,7 +56058,7 @@ }, "packages/plugins": { "name": "@wordpress/plugins", - "version": "6.13.0", + "version": "6.14.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56080,7 +56080,7 @@ }, "packages/postcss-plugins-preset": { "name": "@wordpress/postcss-plugins-preset", - "version": "4.29.0", + "version": "4.30.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -56096,7 +56096,7 @@ }, "packages/postcss-themes": { "name": "@wordpress/postcss-themes", - "version": "5.28.0", + "version": "5.29.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -56108,7 +56108,7 @@ }, "packages/preferences": { "name": "@wordpress/preferences", - "version": "3.22.0", + "version": "3.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56130,7 +56130,7 @@ }, "packages/preferences-persistence": { "name": "@wordpress/preferences-persistence", - "version": "1.37.0", + "version": "1.38.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56142,7 +56142,7 @@ }, "packages/prettier-config": { "name": "@wordpress/prettier-config", - "version": "3.2.0", + "version": "3.3.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -56154,7 +56154,7 @@ }, "packages/primitives": { "name": "@wordpress/primitives", - "version": "3.43.0", + "version": "3.44.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56167,7 +56167,7 @@ }, "packages/priority-queue": { "name": "@wordpress/priority-queue", - "version": "2.45.0", + "version": "2.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56179,7 +56179,7 @@ }, "packages/private-apis": { "name": "@wordpress/private-apis", - "version": "0.27.0", + "version": "0.28.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -56190,7 +56190,7 @@ }, "packages/project-management-automation": { "name": "@wordpress/project-management-automation", - "version": "1.44.0", + "version": "1.45.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -56203,7 +56203,7 @@ }, "packages/react-i18n": { "name": "@wordpress/react-i18n", - "version": "3.43.0", + "version": "3.44.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56351,7 +56351,7 @@ }, "packages/readable-js-assets-webpack-plugin": { "name": "@wordpress/readable-js-assets-webpack-plugin", - "version": "2.28.0", + "version": "2.29.0", "dev": true, "license": "GPL-2.0-or-later", "engines": { @@ -56363,7 +56363,7 @@ }, "packages/redux-routine": { "name": "@wordpress/redux-routine", - "version": "4.45.0", + "version": "4.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56407,7 +56407,7 @@ }, "packages/reusable-blocks": { "name": "@wordpress/reusable-blocks", - "version": "4.22.0", + "version": "4.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56433,7 +56433,7 @@ }, "packages/rich-text": { "name": "@wordpress/rich-text", - "version": "6.22.0", + "version": "6.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56457,7 +56457,7 @@ }, "packages/router": { "name": "@wordpress/router", - "version": "0.14.0", + "version": "0.15.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56475,7 +56475,7 @@ }, "packages/scripts": { "name": "@wordpress/scripts", - "version": "26.16.0", + "version": "26.17.0", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -56565,7 +56565,7 @@ }, "packages/server-side-render": { "name": "@wordpress/server-side-render", - "version": "4.22.0", + "version": "4.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56590,7 +56590,7 @@ }, "packages/shortcode": { "name": "@wordpress/shortcode", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56602,7 +56602,7 @@ }, "packages/style-engine": { "name": "@wordpress/style-engine", - "version": "1.28.0", + "version": "1.29.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56614,7 +56614,7 @@ }, "packages/stylelint-config": { "name": "@wordpress/stylelint-config", - "version": "21.28.0", + "version": "21.29.0", "dev": true, "license": "MIT", "dependencies": { @@ -56630,7 +56630,7 @@ }, "packages/sync": { "name": "@wordpress/sync", - "version": "0.7.0", + "version": "0.8.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56650,7 +56650,7 @@ }, "packages/token-list": { "name": "@wordpress/token-list", - "version": "2.45.0", + "version": "2.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" @@ -56661,7 +56661,7 @@ }, "packages/undo-manager": { "name": "@wordpress/undo-manager", - "version": "0.5.0", + "version": "0.6.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56673,7 +56673,7 @@ }, "packages/url": { "name": "@wordpress/url", - "version": "3.46.0", + "version": "3.47.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56685,7 +56685,7 @@ }, "packages/viewport": { "name": "@wordpress/viewport", - "version": "5.22.0", + "version": "5.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56702,7 +56702,7 @@ }, "packages/warning": { "name": "@wordpress/warning", - "version": "2.45.0", + "version": "2.46.0", "license": "GPL-2.0-or-later", "engines": { "node": ">=12" @@ -56710,7 +56710,7 @@ }, "packages/widgets": { "name": "@wordpress/widgets", - "version": "3.22.0", + "version": "3.23.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0", @@ -56734,7 +56734,7 @@ }, "packages/wordcount": { "name": "@wordpress/wordcount", - "version": "3.45.0", + "version": "3.46.0", "license": "GPL-2.0-or-later", "dependencies": { "@babel/runtime": "^7.16.0" diff --git a/packages/a11y/package.json b/packages/a11y/package.json index 60bd6f5e7fbf18..10964d4f47800a 100644 --- a/packages/a11y/package.json +++ b/packages/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/a11y", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "Accessibility (a11y) utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/annotations/package.json b/packages/annotations/package.json index a8aee11f46fabe..653414da29014e 100644 --- a/packages/annotations/package.json +++ b/packages/annotations/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/annotations", - "version": "2.46.0-prerelease", + "version": "2.46.0", "description": "Annotate content in the Gutenberg editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/api-fetch/package.json b/packages/api-fetch/package.json index cb5a477a706fe4..c572e343edab86 100644 --- a/packages/api-fetch/package.json +++ b/packages/api-fetch/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/api-fetch", - "version": "6.43.0-prerelease", + "version": "6.43.0", "description": "Utility to make WordPress REST API requests.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/autop/package.json b/packages/autop/package.json index d6231e72dcd9d5..d444d2d5a4779f 100644 --- a/packages/autop/package.json +++ b/packages/autop/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/autop", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "WordPress's automatic paragraph functions `autop` and `removep`.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-plugin-import-jsx-pragma/package.json b/packages/babel-plugin-import-jsx-pragma/package.json index 4e5fe879f84990..a49af835b912fc 100644 --- a/packages/babel-plugin-import-jsx-pragma/package.json +++ b/packages/babel-plugin-import-jsx-pragma/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-plugin-import-jsx-pragma", - "version": "4.29.0-prerelease", + "version": "4.29.0", "description": "Babel transform plugin for automatically injecting an import to be used as the pragma for the React JSX Transform plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-plugin-makepot/package.json b/packages/babel-plugin-makepot/package.json index c70ebc70085915..298a05f3f4425f 100644 --- a/packages/babel-plugin-makepot/package.json +++ b/packages/babel-plugin-makepot/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-plugin-makepot", - "version": "5.30.0-prerelease", + "version": "5.30.0", "description": "WordPress Babel internationalization (i18n) plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-preset-default/package.json b/packages/babel-preset-default/package.json index fc8de1a030c610..d53a2603593233 100644 --- a/packages/babel-preset-default/package.json +++ b/packages/babel-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-preset-default", - "version": "7.30.0-prerelease", + "version": "7.30.0", "description": "Default Babel preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/base-styles/package.json b/packages/base-styles/package.json index d747036f1bebdf..8af7e6b7e3db17 100644 --- a/packages/base-styles/package.json +++ b/packages/base-styles/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/base-styles", - "version": "4.37.0-prerelease", + "version": "4.37.0", "description": "Base SCSS utilities and variables for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blob/package.json b/packages/blob/package.json index 8779cf36199474..ba0a355e19a47d 100644 --- a/packages/blob/package.json +++ b/packages/blob/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/blob", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "Blob utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-directory/package.json b/packages/block-directory/package.json index 86f94996843ea2..438b0680db283b 100644 --- a/packages/block-directory/package.json +++ b/packages/block-directory/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-directory", - "version": "4.23.0-prerelease", + "version": "4.23.0", "description": "Extend editor with block directory features to search, download and install blocks.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index baf9929585751c..a80fd2f9bca969 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-editor", - "version": "12.14.0-prerelease", + "version": "12.14.0", "description": "Generic block editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-library/package.json b/packages/block-library/package.json index 5e2e0e40cfc7b0..558566bccaae0a 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-library", - "version": "8.23.0-prerelease", + "version": "8.23.0", "description": "Block library for the WordPress editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-serialization-default-parser/package.json b/packages/block-serialization-default-parser/package.json index 3c0b3e5b8f6987..93fcef93acdd97 100644 --- a/packages/block-serialization-default-parser/package.json +++ b/packages/block-serialization-default-parser/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-serialization-default-parser", - "version": "4.46.0-prerelease", + "version": "4.46.0", "description": "Block serialization specification parser for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-serialization-spec-parser/package.json b/packages/block-serialization-spec-parser/package.json index 429caf6f66bf57..d5818b926323bc 100644 --- a/packages/block-serialization-spec-parser/package.json +++ b/packages/block-serialization-spec-parser/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-serialization-spec-parser", - "version": "4.46.0-prerelease", + "version": "4.46.0", "description": "Block serialization specification parser for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blocks/package.json b/packages/blocks/package.json index e88532e8501465..abfed4b763e7e4 100644 --- a/packages/blocks/package.json +++ b/packages/blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/blocks", - "version": "12.23.0-prerelease", + "version": "12.23.0", "description": "Block API for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/browserslist-config/package.json b/packages/browserslist-config/package.json index 69b1f02f9eb086..315594a8bda1bc 100644 --- a/packages/browserslist-config/package.json +++ b/packages/browserslist-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/browserslist-config", - "version": "5.29.0-prerelease", + "version": "5.29.0", "description": "WordPress Browserslist shared configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/commands/package.json b/packages/commands/package.json index bb74b5c238fd55..3d18b9f47a7ed7 100644 --- a/packages/commands/package.json +++ b/packages/commands/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/commands", - "version": "0.17.0-prerelease", + "version": "0.17.0", "description": "Handles the commands menu.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/components/package.json b/packages/components/package.json index 1eaf7e27ed3a68..7e8c237b700244 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/components", - "version": "25.12.0-prerelease", + "version": "25.12.0", "description": "UI components for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/compose/package.json b/packages/compose/package.json index b55a73f976e29e..24576ec7f2b501 100644 --- a/packages/compose/package.json +++ b/packages/compose/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/compose", - "version": "6.23.0-prerelease", + "version": "6.23.0", "description": "WordPress higher-order components (HOCs).", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/core-commands/package.json b/packages/core-commands/package.json index b91feb0ecb4f7f..c46789e5fc6987 100644 --- a/packages/core-commands/package.json +++ b/packages/core-commands/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/core-commands", - "version": "0.15.0-prerelease", + "version": "0.15.0", "description": "WordPress core reusable commands.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/core-data/package.json b/packages/core-data/package.json index ef109392491505..0d8fa19ec6be91 100644 --- a/packages/core-data/package.json +++ b/packages/core-data/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/core-data", - "version": "6.23.0-prerelease", + "version": "6.23.0", "description": "Access to and manipulation of core WordPress entities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/create-block-interactive-template/package.json b/packages/create-block-interactive-template/package.json index ab2053e4dc8609..fa196823e5ad6c 100644 --- a/packages/create-block-interactive-template/package.json +++ b/packages/create-block-interactive-template/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block-interactive-template", - "version": "1.9.0-prerelease", + "version": "1.9.0", "description": "Template for @wordpress/create-block to create interactive blocks with the Interactivity API.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/create-block-tutorial-template/package.json b/packages/create-block-tutorial-template/package.json index a1a733b3e8a57c..c180069b8263e4 100644 --- a/packages/create-block-tutorial-template/package.json +++ b/packages/create-block-tutorial-template/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block-tutorial-template", - "version": "3.0.0-prerelease", + "version": "3.0.0", "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", diff --git a/packages/create-block/package.json b/packages/create-block/package.json index 2ed37c112c7a14..94249456e48c94 100644 --- a/packages/create-block/package.json +++ b/packages/create-block/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block", - "version": "4.30.0-prerelease", + "version": "4.30.0", "description": "Generates PHP, JS and CSS code for registering a block for a WordPress plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/customize-widgets/package.json b/packages/customize-widgets/package.json index 2384f06a1253c0..be21e250b7f06b 100644 --- a/packages/customize-widgets/package.json +++ b/packages/customize-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/customize-widgets", - "version": "4.23.0-prerelease", + "version": "4.23.0", "description": "Widgets blocks in Customizer Module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/data-controls/package.json b/packages/data-controls/package.json index b86b70577e7e43..919e3479f326ec 100644 --- a/packages/data-controls/package.json +++ b/packages/data-controls/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/data-controls", - "version": "3.15.0-prerelease", + "version": "3.15.0", "description": "A set of common controls for the @wordpress/data api.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/data/package.json b/packages/data/package.json index 2698c27f0091a9..ebfccdc75819fd 100644 --- a/packages/data/package.json +++ b/packages/data/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/data", - "version": "9.16.0-prerelease", + "version": "9.16.0", "description": "Data module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/date/package.json b/packages/date/package.json index 3d85c7f446d620..092eb7a1f234f3 100644 --- a/packages/date/package.json +++ b/packages/date/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/date", - "version": "4.46.0-prerelease", + "version": "4.46.0", "description": "Date module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dependency-extraction-webpack-plugin/package.json b/packages/dependency-extraction-webpack-plugin/package.json index b1370b1c359afe..87267a8a593ad4 100644 --- a/packages/dependency-extraction-webpack-plugin/package.json +++ b/packages/dependency-extraction-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dependency-extraction-webpack-plugin", - "version": "4.29.0-prerelease", + "version": "4.29.0", "description": "Extract WordPress script dependencies from webpack bundles.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/deprecated/package.json b/packages/deprecated/package.json index e596db980e8ecd..f0a823074c0475 100644 --- a/packages/deprecated/package.json +++ b/packages/deprecated/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/deprecated", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "Deprecation utility for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/docgen/package.json b/packages/docgen/package.json index ec282a093f1d84..87d92d25e80535 100644 --- a/packages/docgen/package.json +++ b/packages/docgen/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/docgen", - "version": "1.55.0-prerelease", + "version": "1.55.0", "description": "Autogenerate public API documentation from exports and JSDoc comments.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dom-ready/package.json b/packages/dom-ready/package.json index 763f21e3172362..542be436e09c6c 100644 --- a/packages/dom-ready/package.json +++ b/packages/dom-ready/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dom-ready", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "Execute callback after the DOM is loaded.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dom/package.json b/packages/dom/package.json index f80a508f23b253..263ee6d5a04aec 100644 --- a/packages/dom/package.json +++ b/packages/dom/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dom", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "DOM utilities module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-test-utils-playwright/package.json b/packages/e2e-test-utils-playwright/package.json index 553ad9ad158342..9c7401c5346f14 100644 --- a/packages/e2e-test-utils-playwright/package.json +++ b/packages/e2e-test-utils-playwright/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-test-utils-playwright", - "version": "0.14.0-prerelease", + "version": "0.14.0", "description": "End-To-End (E2E) test utils for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-test-utils/package.json b/packages/e2e-test-utils/package.json index 58506c9686d602..8fad38623a6855 100644 --- a/packages/e2e-test-utils/package.json +++ b/packages/e2e-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-test-utils", - "version": "10.17.0-prerelease", + "version": "10.17.0", "description": "End-To-End (E2E) test utils for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json index 6c444d161f65f9..f3cabf4d6a2c92 100644 --- a/packages/e2e-tests/package.json +++ b/packages/e2e-tests/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-tests", - "version": "7.17.0-prerelease", + "version": "7.17.0", "description": "End-To-End (E2E) tests for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-post/package.json b/packages/edit-post/package.json index d0a8c78ca436b2..31c5c209fa96c2 100644 --- a/packages/edit-post/package.json +++ b/packages/edit-post/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-post", - "version": "7.23.0-prerelease", + "version": "7.23.0", "description": "Edit Post module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-site/package.json b/packages/edit-site/package.json index bea0abb0ef0c84..072dc0b1c027a8 100644 --- a/packages/edit-site/package.json +++ b/packages/edit-site/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-site", - "version": "5.23.0-prerelease", + "version": "5.23.0", "description": "Edit Site Page module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-widgets/package.json b/packages/edit-widgets/package.json index 1e68aecf8321fd..33c7f9d75dd619 100644 --- a/packages/edit-widgets/package.json +++ b/packages/edit-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-widgets", - "version": "5.23.0-prerelease", + "version": "5.23.0", "description": "Widgets Page module for WordPress..", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/editor/package.json b/packages/editor/package.json index d9d0afcdf1656a..5a4bf3ba7bf216 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/editor", - "version": "13.23.0-prerelease", + "version": "13.23.0", "description": "Enhanced block editor for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/element/package.json b/packages/element/package.json index fa6b5e1ab5ce70..b8753b952909b6 100644 --- a/packages/element/package.json +++ b/packages/element/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/element", - "version": "5.23.0-prerelease", + "version": "5.23.0", "description": "Element React module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/env/package.json b/packages/env/package.json index 7e2cee5596a2b3..28373f4f391b6a 100644 --- a/packages/env/package.json +++ b/packages/env/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/env", - "version": "8.12.0-prerelease", + "version": "8.12.0", "description": "A zero-config, self contained local WordPress environment for development and testing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/escape-html/package.json b/packages/escape-html/package.json index 742813826477e5..e45800c248dfc3 100644 --- a/packages/escape-html/package.json +++ b/packages/escape-html/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/escape-html", - "version": "2.46.0-prerelease", + "version": "2.46.0", "description": "Escape HTML utils.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index e1fb50b5414251..f3009f7a584f64 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/eslint-plugin", - "version": "17.3.0-prerelease", + "version": "17.3.0", "description": "ESLint plugin for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/format-library/package.json b/packages/format-library/package.json index 687be3963fb432..f7b9dc90224e64 100644 --- a/packages/format-library/package.json +++ b/packages/format-library/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/format-library", - "version": "4.23.0-prerelease", + "version": "4.23.0", "description": "Format library for the WordPress editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/hooks/package.json b/packages/hooks/package.json index 4595c47aa29a36..6b9a3fccd3c7ad 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/hooks", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "WordPress hooks library.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/html-entities/package.json b/packages/html-entities/package.json index 9d72d46f7a5ff2..8d30d7c48173c0 100644 --- a/packages/html-entities/package.json +++ b/packages/html-entities/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/html-entities", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "HTML entity utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/i18n/package.json b/packages/i18n/package.json index bb82d509684fea..47414963190cdf 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/i18n", - "version": "4.46.0-prerelease", + "version": "4.46.0", "description": "WordPress internationalization (i18n) library.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/icons/package.json b/packages/icons/package.json index ecc11b411c828a..5cef81d4bc67b6 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/icons", - "version": "9.37.0-prerelease", + "version": "9.37.0", "description": "WordPress Icons package, based on dashicon.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/interactivity/package.json b/packages/interactivity/package.json index 791ed276db6b3f..fd2491695be5ad 100644 --- a/packages/interactivity/package.json +++ b/packages/interactivity/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/interactivity", - "version": "2.7.0-prerelease", + "version": "2.7.0", "description": "Package that provides a standard and simple way to handle the frontend interactivity of Gutenberg blocks.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/interface/package.json b/packages/interface/package.json index 8142df4fd443b7..429d2ad59d0fdb 100644 --- a/packages/interface/package.json +++ b/packages/interface/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/interface", - "version": "5.23.0-prerelease", + "version": "5.23.0", "description": "Interface module for WordPress. The package contains shared functionality across the modern JavaScript-based WordPress screens.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/is-shallow-equal/package.json b/packages/is-shallow-equal/package.json index b7202d19a87e3d..ffc4e97590bc97 100644 --- a/packages/is-shallow-equal/package.json +++ b/packages/is-shallow-equal/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/is-shallow-equal", - "version": "4.46.0-prerelease", + "version": "4.46.0", "description": "Test for shallow equality between two objects or arrays.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/jest-console/package.json b/packages/jest-console/package.json index 2152ff6a5c0ddd..1dfb50d5bd59c2 100644 --- a/packages/jest-console/package.json +++ b/packages/jest-console/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-console", - "version": "7.17.0-prerelease", + "version": "7.17.0", "description": "Custom Jest matchers for the Console object.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/jest-preset-default/package.json b/packages/jest-preset-default/package.json index 4fbd174c512c5e..7e3b0812e3d067 100644 --- a/packages/jest-preset-default/package.json +++ b/packages/jest-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-preset-default", - "version": "11.17.0-prerelease", + "version": "11.17.0", "description": "Default Jest preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/jest-puppeteer-axe/package.json b/packages/jest-puppeteer-axe/package.json index 5e87a4a542e335..eed831e07d801f 100644 --- a/packages/jest-puppeteer-axe/package.json +++ b/packages/jest-puppeteer-axe/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-puppeteer-axe", - "version": "6.17.0-prerelease", + "version": "6.17.0", "description": "Axe API integration with Jest and Puppeteer.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/keyboard-shortcuts/package.json b/packages/keyboard-shortcuts/package.json index 43e4d11af5cbbe..dfe02e60773679 100644 --- a/packages/keyboard-shortcuts/package.json +++ b/packages/keyboard-shortcuts/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/keyboard-shortcuts", - "version": "4.23.0-prerelease", + "version": "4.23.0", "description": "Handling keyboard shortcuts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/keycodes/package.json b/packages/keycodes/package.json index 9ecc81007b71a1..4ca561d68b83d1 100644 --- a/packages/keycodes/package.json +++ b/packages/keycodes/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/keycodes", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "Keycodes utilities for WordPress. Used to check for keyboard events across browsers/operating systems.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/lazy-import/package.json b/packages/lazy-import/package.json index 7e5561e2b6d182..62320482ae15bf 100644 --- a/packages/lazy-import/package.json +++ b/packages/lazy-import/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/lazy-import", - "version": "1.33.0-prerelease", + "version": "1.33.0", "description": "Lazily import a module, installing it automatically if missing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/list-reusable-blocks/package.json b/packages/list-reusable-blocks/package.json index 70a3ae145a799f..0feaddf684b5fc 100644 --- a/packages/list-reusable-blocks/package.json +++ b/packages/list-reusable-blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/list-reusable-blocks", - "version": "4.23.0-prerelease", + "version": "4.23.0", "description": "Adding Export/Import support to the reusable blocks listing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/media-utils/package.json b/packages/media-utils/package.json index 2f2e4f454f9eab..93ed96c45246a9 100644 --- a/packages/media-utils/package.json +++ b/packages/media-utils/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/media-utils", - "version": "4.37.0-prerelease", + "version": "4.37.0", "description": "WordPress Media Upload Utils.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/notices/package.json b/packages/notices/package.json index 38c7fac68afbcb..9250d196365c46 100644 --- a/packages/notices/package.json +++ b/packages/notices/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/notices", - "version": "4.14.0-prerelease", + "version": "4.14.0", "description": "State management for notices.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/npm-package-json-lint-config/package.json b/packages/npm-package-json-lint-config/package.json index 3ad54a8a2a93a9..a62009f5d88a03 100644 --- a/packages/npm-package-json-lint-config/package.json +++ b/packages/npm-package-json-lint-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/npm-package-json-lint-config", - "version": "4.31.0-prerelease", + "version": "4.31.0", "description": "WordPress npm-package-json-lint shareable configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/nux/package.json b/packages/nux/package.json index 124d3cfacd9600..12f659accc9503 100644 --- a/packages/nux/package.json +++ b/packages/nux/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/nux", - "version": "8.8.0-prerelease", + "version": "8.8.0", "description": "NUX (New User eXperience) module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/patterns/package.json b/packages/patterns/package.json index 8f417dc1aa5928..bab11059bf92c9 100644 --- a/packages/patterns/package.json +++ b/packages/patterns/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/patterns", - "version": "1.7.0-prerelease", + "version": "1.7.0", "description": "Management of user pattern editing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/plugins/package.json b/packages/plugins/package.json index e9ffee30feba87..98448a216daeab 100644 --- a/packages/plugins/package.json +++ b/packages/plugins/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/plugins", - "version": "6.14.0-prerelease", + "version": "6.14.0", "description": "Plugins module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/postcss-plugins-preset/package.json b/packages/postcss-plugins-preset/package.json index ffd3230b90bd78..bee5573d2f8832 100644 --- a/packages/postcss-plugins-preset/package.json +++ b/packages/postcss-plugins-preset/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/postcss-plugins-preset", - "version": "4.30.0-prerelease", + "version": "4.30.0", "description": "PostCSS sharable plugins preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/postcss-themes/package.json b/packages/postcss-themes/package.json index 2b65ddefc795a5..1fd640b1b3f25e 100644 --- a/packages/postcss-themes/package.json +++ b/packages/postcss-themes/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/postcss-themes", - "version": "5.29.0-prerelease", + "version": "5.29.0", "description": "PostCSS plugin to generate theme colors.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/preferences-persistence/package.json b/packages/preferences-persistence/package.json index 6a76d6094bac5a..8137c703d6f336 100644 --- a/packages/preferences-persistence/package.json +++ b/packages/preferences-persistence/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/preferences-persistence", - "version": "1.38.0-prerelease", + "version": "1.38.0", "description": "Persistence utilities for `wordpress/preferences`.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/preferences/package.json b/packages/preferences/package.json index 0ba849dc9787a2..78a0ed29aa3547 100644 --- a/packages/preferences/package.json +++ b/packages/preferences/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/preferences", - "version": "3.23.0-prerelease", + "version": "3.23.0", "description": "Utilities for managing WordPress preferences.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/prettier-config/package.json b/packages/prettier-config/package.json index 7e4168c931d8ed..f97e04f7fee6c5 100644 --- a/packages/prettier-config/package.json +++ b/packages/prettier-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/prettier-config", - "version": "3.3.0-prerelease", + "version": "3.3.0", "description": "WordPress Prettier shared configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/primitives/package.json b/packages/primitives/package.json index 274755ff59b2d5..e3e99b3d6d0288 100644 --- a/packages/primitives/package.json +++ b/packages/primitives/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/primitives", - "version": "3.44.0-prerelease", + "version": "3.44.0", "description": "WordPress cross-platform primitives.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/priority-queue/package.json b/packages/priority-queue/package.json index 2290bceeb8cc3d..3e3ecb57872b1f 100644 --- a/packages/priority-queue/package.json +++ b/packages/priority-queue/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/priority-queue", - "version": "2.46.0-prerelease", + "version": "2.46.0", "description": "Generic browser priority queue.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/private-apis/package.json b/packages/private-apis/package.json index ccc4999d2fb177..be77c8334dcb42 100644 --- a/packages/private-apis/package.json +++ b/packages/private-apis/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/private-apis", - "version": "0.28.0-prerelease", + "version": "0.28.0", "description": "Internal experimental APIs for WordPress core.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/project-management-automation/package.json b/packages/project-management-automation/package.json index a75b111d795cdc..b4c0389872dcdf 100644 --- a/packages/project-management-automation/package.json +++ b/packages/project-management-automation/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/project-management-automation", - "version": "1.45.0-prerelease", + "version": "1.45.0", "description": "GitHub Action that implements various automation to assist with managing the Gutenberg GitHub repository.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/react-i18n/package.json b/packages/react-i18n/package.json index 3a08d14983bc22..662d8e288bcc07 100644 --- a/packages/react-i18n/package.json +++ b/packages/react-i18n/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/react-i18n", - "version": "3.44.0-prerelease", + "version": "3.44.0", "description": "React bindings for @wordpress/i18n.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/readable-js-assets-webpack-plugin/package.json b/packages/readable-js-assets-webpack-plugin/package.json index 646b8999d34414..93a525c127bc0c 100644 --- a/packages/readable-js-assets-webpack-plugin/package.json +++ b/packages/readable-js-assets-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/readable-js-assets-webpack-plugin", - "version": "2.29.0-prerelease", + "version": "2.29.0", "description": "Generate a readable JS file for each JS asset.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/redux-routine/package.json b/packages/redux-routine/package.json index b6a8fe417da8d5..09d7b16795ae28 100644 --- a/packages/redux-routine/package.json +++ b/packages/redux-routine/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/redux-routine", - "version": "4.46.0-prerelease", + "version": "4.46.0", "description": "Redux middleware for generator coroutines.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/reusable-blocks/package.json b/packages/reusable-blocks/package.json index 8ffdb18e598116..f21c486014fc8c 100644 --- a/packages/reusable-blocks/package.json +++ b/packages/reusable-blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/reusable-blocks", - "version": "4.23.0-prerelease", + "version": "4.23.0", "description": "Reusable blocks utilities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/rich-text/package.json b/packages/rich-text/package.json index 0d805777e2d4f7..4c2fe8e32adc9c 100644 --- a/packages/rich-text/package.json +++ b/packages/rich-text/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/rich-text", - "version": "6.23.0-prerelease", + "version": "6.23.0", "description": "Rich text value and manipulation API.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/router/package.json b/packages/router/package.json index a27be42a33cd48..ae8eb364202e27 100644 --- a/packages/router/package.json +++ b/packages/router/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/router", - "version": "0.15.0-prerelease", + "version": "0.15.0", "description": "Router API for WordPress pages.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 21194afad7cdde..2a740ec41c6ab8 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/scripts", - "version": "26.17.0-prerelease", + "version": "26.17.0", "description": "Collection of reusable scripts for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/server-side-render/package.json b/packages/server-side-render/package.json index 74d84e29e28ada..3e8f81b1476fd8 100644 --- a/packages/server-side-render/package.json +++ b/packages/server-side-render/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/server-side-render", - "version": "4.23.0-prerelease", + "version": "4.23.0", "description": "The component used with WordPress to server-side render a preview of dynamic blocks to display in the editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/shortcode/package.json b/packages/shortcode/package.json index 3a59b60a29918e..6646c98fe46e0f 100644 --- a/packages/shortcode/package.json +++ b/packages/shortcode/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/shortcode", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "Shortcode module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/style-engine/package.json b/packages/style-engine/package.json index 19c15d261898af..cdbb5d8f272519 100644 --- a/packages/style-engine/package.json +++ b/packages/style-engine/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/style-engine", - "version": "1.29.0-prerelease", + "version": "1.29.0", "description": "A suite of parsers and compilers for WordPress styles.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/stylelint-config/package.json b/packages/stylelint-config/package.json index f82b2cee235029..6d6ce676bbce3c 100644 --- a/packages/stylelint-config/package.json +++ b/packages/stylelint-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/stylelint-config", - "version": "21.29.0-prerelease", + "version": "21.29.0", "description": "stylelint config for WordPress development.", "author": "The WordPress Contributors", "license": "MIT", diff --git a/packages/sync/package.json b/packages/sync/package.json index cd48de011a183c..0110a281d46aeb 100644 --- a/packages/sync/package.json +++ b/packages/sync/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/sync", - "version": "0.8.0-prerelease", + "version": "0.8.0", "description": "Sync Data.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/token-list/package.json b/packages/token-list/package.json index cb7f13dceeec61..de2e1d0c4d2a58 100644 --- a/packages/token-list/package.json +++ b/packages/token-list/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/token-list", - "version": "2.46.0-prerelease", + "version": "2.46.0", "description": "Constructable, plain JavaScript DOMTokenList implementation, supporting non-browser runtimes.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/undo-manager/package.json b/packages/undo-manager/package.json index f8b8401774dbfe..b1f75f83d59788 100644 --- a/packages/undo-manager/package.json +++ b/packages/undo-manager/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/undo-manager", - "version": "0.6.0-prerelease", + "version": "0.6.0", "description": "A small package to manage undo/redo.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/url/package.json b/packages/url/package.json index af28dea0b4444f..6acd999314b151 100644 --- a/packages/url/package.json +++ b/packages/url/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/url", - "version": "3.47.0-prerelease", + "version": "3.47.0", "description": "WordPress URL utilities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/viewport/package.json b/packages/viewport/package.json index 0809dee6f1d9ab..2357182bdfd8d7 100644 --- a/packages/viewport/package.json +++ b/packages/viewport/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/viewport", - "version": "5.23.0-prerelease", + "version": "5.23.0", "description": "Viewport module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/warning/package.json b/packages/warning/package.json index 899d36d9cafc0c..a4c0f7df23070f 100644 --- a/packages/warning/package.json +++ b/packages/warning/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/warning", - "version": "2.46.0-prerelease", + "version": "2.46.0", "description": "Warning utility for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/widgets/package.json b/packages/widgets/package.json index 06e7e9a788f206..06dc5604703929 100644 --- a/packages/widgets/package.json +++ b/packages/widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/widgets", - "version": "3.23.0-prerelease", + "version": "3.23.0", "description": "Functionality used by the widgets block editor in the Widgets screen and the Customizer.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/wordcount/package.json b/packages/wordcount/package.json index 504e5c0b84bfc2..dbb3fdd3bc1f42 100644 --- a/packages/wordcount/package.json +++ b/packages/wordcount/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/wordcount", - "version": "3.46.0-prerelease", + "version": "3.46.0", "description": "WordPress word count utility.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", From fb2a2cfd5cbe413ddf3d62f0bacd5d3f2bc97a68 Mon Sep 17 00:00:00 2001 From: Ramon Date: Fri, 17 Nov 2023 08:06:27 +1100 Subject: [PATCH 059/116] Page spec: merging create page and toggle preview tests (#56129) * Merging create page and toggle preview tests * Disable no assertion linting rule Update commentszz * Undo test assertion abstraction --- test/e2e/specs/site-editor/pages.spec.js | 175 +++++++++++------------ 1 file changed, 87 insertions(+), 88 deletions(-) diff --git a/test/e2e/specs/site-editor/pages.spec.js b/test/e2e/specs/site-editor/pages.spec.js index 8008109be15eee..af58daeaedbe40 100644 --- a/test/e2e/specs/site-editor/pages.spec.js +++ b/test/e2e/specs/site-editor/pages.spec.js @@ -18,6 +18,53 @@ async function draftNewPage( page ) { ).toBeVisible(); } +async function addPageContent( editor, page ) { + await editor.canvas + .getByRole( 'document', { + name: 'Block: Content', + } ) + .getByRole( 'document', { + name: 'Empty block; start writing or type forward slash to choose a block', + } ) + .click(); + + // Insert into Page Content using default block. + await editor.canvas + .getByRole( 'document', { + name: 'Empty block; start writing or type forward slash to choose a block', + } ) + .fill( 'Lorem ipsum dolor sit amet' ); + + // Insert into Page Content using global inserter. + await page.getByRole( 'button', { name: 'Toggle block inserter' } ).click(); + await page.getByRole( 'option', { name: 'Heading', exact: true } ).click(); + await editor.canvas + .getByRole( 'document', { + name: 'Block: Heading', + } ) + .fill( 'A sweet heading 1' ); + + // Add some regular content blocks. + await page.keyboard.press( 'Enter' ); + await editor.insertBlock( { name: 'core/paragraph' } ); + await page.keyboard.type( 'A sweet paragraph 1' ); + await page.keyboard.press( 'Enter' ); + await editor.insertBlock( { name: 'core/paragraph' } ); + await page.keyboard.type( 'A sweet paragraph 2' ); + + // Insert into Page Content using appender. + await page + .getByRole( 'region', { name: 'Editor footer' } ) + .getByRole( 'button', { name: 'Content' } ) + .click(); + await editor.canvas.getByRole( 'button', { name: 'Add block' } ).click(); + await page.getByPlaceholder( 'Search' ).fill( 'list' ); + await page.getByRole( 'option', { name: 'List', exact: true } ).click(); + await page.keyboard.type( 'Sweet list 1' ); + await page.keyboard.press( 'Enter' ); + await page.keyboard.type( 'Sweet list 2' ); +} + test.describe( 'Pages', () => { test.beforeAll( async ( { requestUtils } ) => { await requestUtils.activateTheme( 'emptytheme' ); @@ -43,43 +90,17 @@ test.describe( 'Pages', () => { await admin.visitSiteEditor(); } ); - test( 'create a new page', async ( { page, editor } ) => { + test( 'create a new page, edit template and toggle page template preview', async ( { + page, + editor, + } ) => { + // Set up await draftNewPage( page ); + await addPageContent( editor, page ); - // Insert into Page Content using default block. - await editor.canvas - .getByRole( 'document', { - name: 'Empty block; start writing or type forward slash to choose a block', - } ) - .fill( 'Lorem ipsum dolor sit amet' ); - - // Insert into Page Content using global inserter. - await page - .getByRole( 'button', { name: 'Toggle block inserter' } ) - .click(); - await page - .getByRole( 'option', { name: 'Heading', exact: true } ) - .click(); - await editor.canvas - .getByRole( 'document', { - name: 'Block: Heading', - } ) - .fill( 'Lorem ipsum' ); - - // Insert into Page Content using appender. - await page - .getByRole( 'region', { name: 'Editor footer' } ) - .getByRole( 'button', { name: 'Content' } ) - .click(); - await editor.canvas - .getByRole( 'button', { name: 'Add block' } ) - .click(); - await page.getByPlaceholder( 'Search' ).fill( 'list' ); - await page.getByRole( 'option', { name: 'List', exact: true } ).click(); - await page.keyboard.type( 'Lorem ipsum' ); - await page.keyboard.press( 'Enter' ); - await page.keyboard.type( 'Dolor sit amet' ); - + /* + * Test create page.Test creating a new page and editing the template. + */ // Selecting a block in the template should display a notice. await editor.canvas .getByRole( 'document', { @@ -112,7 +133,14 @@ test.describe( 'Pages', () => { ) ).toBeVisible(); - // Edit a block that's in the template. + // Edit blocks that are in the template. + await editor.canvas + .getByRole( 'document', { name: 'Block: Title' } ) + .click(); + await page + .getByRole( 'button', { name: 'Move down', exact: true } ) + .click(); + await editor.canvas .getByRole( 'textbox', { name: 'Site title text' } ) .fill( 'New Site Title' ); @@ -135,47 +163,32 @@ test.describe( 'Pages', () => { 'role=region[name="Save panel"] >> role=checkbox[name="Test Page"]' ) ).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', - } ) + await page + .getByRole( 'button', { name: 'Cancel', exact: true } ) .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. + /* + * Test toggling preview mode. + */ 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', + name: 'Block: Content', } ) ).toBeVisible(); + // Ensure order is preserved between toggling. + await page + .locator( + '[aria-label="Block: Content"] + [aria-label="Block: Title"]' + ) + .isVisible(); + + await editor.openDocumentSettingsSidebar(); // Toggle template preview to "off". const templateOptionsButton = page .getByRole( 'region', { name: 'Editor settings' } ) @@ -202,36 +215,24 @@ test.describe( 'Pages', () => { } ) ).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' - ); + // Content blocks are wrapped in a Group block by default. await expect( editor.canvas .getByRole( 'document', { name: 'Block: Group', } ) .getByRole( 'document', { - name: 'Block: Title', + name: 'Block: Content', } ) ).toBeVisible(); + // Ensure order is preserved between toggling. + await page + .locator( + '[aria-label="Block: Content"] + [aria-label="Block: Title"]' + ) + .isVisible(); + // Remove focus from templateOptionsButton button. await editor.canvas.locator( 'body' ).click(); @@ -249,8 +250,6 @@ test.describe( 'Pages', () => { 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', From 093d52cbfd3e2c140843d3fb91ad3d03330320a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Wrede?= Date: Thu, 16 Nov 2023 22:35:43 +0100 Subject: [PATCH 060/116] Docs: Improve downloadBlob example (#56225) --- packages/blob/README.md | 4 ++-- packages/blob/src/index.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/blob/README.md b/packages/blob/README.md index ff28e8879602f3..64520a98bd6a79 100644 --- a/packages/blob/README.md +++ b/packages/blob/README.md @@ -40,9 +40,9 @@ const fileContent = JSON.stringify( null, 2 ); -const fileName = 'file.json'; +const filename = 'file.json'; -downloadBlob( 'file.json', fileContent, 'application/json' ); +downloadBlob( filename, fileContent, 'application/json' ); ``` _Parameters_ diff --git a/packages/blob/src/index.js b/packages/blob/src/index.js index edc2e43729a23f..2493f81fc4c65b 100644 --- a/packages/blob/src/index.js +++ b/packages/blob/src/index.js @@ -85,9 +85,9 @@ export function isBlobURL( url ) { * null, * 2 * ); - * const fileName = 'file.json'; + * const filename = 'file.json'; * - * downloadBlob( 'file.json', fileContent, 'application/json' ); + * downloadBlob( filename, fileContent, 'application/json' ); * ``` * * @param {string} filename File name. From d39d2dddfd888a8ddd174aa16630626d21ce5f81 Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Fri, 17 Nov 2023 09:42:21 +1100 Subject: [PATCH 061/116] Add layout classes to legacy Group inner container (#56130) * Add layout classes to legacy Group inner container * Fix lint issues * fix lint warning * Add some tests for inner container function * Add fallback for `class_list` * Fix selectors for legacy group placeholder. * Add explanatory comments. --- lib/block-supports/layout.php | 52 ++++++++++- .../button-block-appender/content.scss | 4 +- packages/block-library/src/group/edit.js | 14 +-- phpunit/block-supports/layout-test.php | 88 +++++++++++++++++++ 4 files changed, 142 insertions(+), 16 deletions(-) diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 80be02db68360e..0908f649bd5a91 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -865,17 +865,63 @@ function gutenberg_restore_group_inner_container( $block_content, $block ) { return $block_content; } - $replace_regex = sprintf( + /** + * This filter runs after the layout classnames have been added to the block, so they + * have to be removed from the outer wrapper and then added to the inner. + */ + $layout_classes = array(); + $processor = new WP_HTML_Tag_Processor( $block_content ); + + if ( $processor->next_tag( array( 'class_name' => 'wp-block-group' ) ) ) { + if ( method_exists( $processor, 'class_list' ) ) { + foreach ( $processor->class_list() as $class_name ) { + if ( str_contains( $class_name, 'layout' ) ) { + array_push( $layout_classes, $class_name ); + $processor->remove_class( $class_name ); + } + } + } else { + /** + * The class_list method was only added in 6.4 so this needs a temporary fallback. + * This fallback should be removed when the minimum supported version is 6.4. + */ + $classes = $processor->get_attribute( 'class' ); + if ( $classes ) { + $classes = explode( ' ', $classes ); + foreach ( $classes as $class_name ) { + if ( str_contains( $class_name, 'layout' ) ) { + array_push( $layout_classes, $class_name ); + $processor->remove_class( $class_name ); + } + } + } + } + } + + $content_without_layout_classes = $processor->get_updated_html(); + $replace_regex = sprintf( '/(^\s*<%1$s\b[^>]*wp-block-group[^>]*>)(.*)(<\/%1$s>\s*$)/ms', preg_quote( $tag_name, '/' ) ); - $updated_content = preg_replace_callback( + $updated_content = preg_replace_callback( $replace_regex, static function ( $matches ) { return $matches[1] . '
' . $matches[2] . '
' . $matches[3]; }, - $block_content + $content_without_layout_classes ); + + // Add layout classes to inner wrapper. + if ( ! empty( $layout_classes ) ) { + $processor = new WP_HTML_Tag_Processor( $updated_content ); + if ( $processor->next_tag( array( 'class_name' => 'wp-block-group__inner-container' ) ) ) { + foreach ( $layout_classes as $class_name ) { + $processor->add_class( $class_name ); + } + } + $updated_content = $processor->get_updated_html(); + } + return $updated_content; } diff --git a/packages/block-editor/src/components/button-block-appender/content.scss b/packages/block-editor/src/components/button-block-appender/content.scss index 941ccb7dd1ad3a..50d93234b93f5b 100644 --- a/packages/block-editor/src/components/button-block-appender/content.scss +++ b/packages/block-editor/src/components/button-block-appender/content.scss @@ -39,8 +39,8 @@ .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > &, .is-layout-flow.block-editor-block-list__block:not(.is-selected) > &, // Legacy groups have an inner container so need to be targeted separately - .is-layout-constrained.block-editor-block-list__block:not(.is-selected) > .wp-block-group__inner-container > &, - .is-layout-flow.block-editor-block-list__block:not(.is-selected) > .wp-block-group__inner-container > & { + .block-editor-block-list__block:not(.is-selected) > .is-layout-constrained.wp-block-group__inner-container > &, + .block-editor-block-list__block:not(.is-selected) > .is-layout-flow.wp-block-group__inner-container > & { pointer-events: none; &::after { diff --git a/packages/block-library/src/group/edit.js b/packages/block-library/src/group/edit.js index 277fa6872fa82e..9c8690c4e0e8e2 100644 --- a/packages/block-library/src/group/edit.js +++ b/packages/block-library/src/group/edit.js @@ -71,13 +71,7 @@ function GroupEditControls( { tagName, onSelectTagName } ) { ); } -function GroupEdit( { - attributes, - name, - setAttributes, - clientId, - __unstableLayoutClassNames: layoutClassNames, -} ) { +function GroupEdit( { attributes, name, setAttributes, clientId } ) { const { hasInnerBlocks, themeSupportsLayout } = useSelect( ( select ) => { const { getBlock, getSettings } = select( blockEditorStore ); @@ -103,9 +97,8 @@ function GroupEdit( { themeSupportsLayout || type === 'flex' || type === 'grid'; // Hooks. - const blockProps = useBlockProps( { - className: ! layoutSupportEnabled ? layoutClassNames : null, - } ); + const blockProps = useBlockProps(); + const [ showPlaceholder, setShowPlaceholder ] = useShouldShowPlaceHolder( { attributes, usedLayoutType: type, @@ -134,7 +127,6 @@ function GroupEdit( { templateLock, allowedBlocks, renderAppender, - __unstableDisableLayoutClassNames: ! layoutSupportEnabled, } ); diff --git a/phpunit/block-supports/layout-test.php b/phpunit/block-supports/layout-test.php index c29899e3f4d1b8..41735fdc0939e2 100644 --- a/phpunit/block-supports/layout-test.php +++ b/phpunit/block-supports/layout-test.php @@ -464,4 +464,92 @@ public function data_layout_support_flag_renders_classnames_on_wrapper() { ), ); } + + /** + * Check that gutenberg_restore_group_inner_container() restores the legacy inner container on the Group block. + * + * @dataProvider data_restore_group_inner_container + * + * @covers ::gutenberg_restore_group_inner_container + * + * @param array $args Dataset to test. + * @param string $expected_output The expected output. + */ + public function test_restore_group_inner_container( $args, $expected_output ) { + $actual_output = gutenberg_restore_group_inner_container( $args['block_content'], $args['block'] ); + $this->assertEquals( $expected_output, $actual_output ); + } + + /** + * Data provider for test_restore_group_inner_container. + * + * @return array + */ + public function data_restore_group_inner_container() { + return array( + 'group block with existing inner container' => array( + 'args' => array( + 'block_content' => '
', + 'block' => array( + 'blockName' => 'core/group', + 'attrs' => array( + 'layout' => array( + 'type' => 'default', + ), + ), + 'innerBlocks' => array(), + 'innerHTML' => '
', + 'innerContent' => array( + '
', + ' ', + '
', + ), + ), + ), + 'expected_output' => '
', + ), + 'group block with no existing inner container' => array( + 'args' => array( + 'block_content' => '
', + 'block' => array( + 'blockName' => 'core/group', + 'attrs' => array( + 'layout' => array( + 'type' => 'default', + ), + ), + 'innerBlocks' => array(), + 'innerHTML' => '
', + 'innerContent' => array( + '
', + ' ', + '
', + ), + ), + ), + 'expected_output' => '
', + ), + 'group block with layout classnames' => array( + 'args' => array( + 'block_content' => '
', + 'block' => array( + 'blockName' => 'core/group', + 'attrs' => array( + 'layout' => array( + 'type' => 'default', + ), + ), + 'innerBlocks' => array(), + 'innerHTML' => '
', + 'innerContent' => array( + '
', + ' ', + '
', + ), + ), + ), + 'expected_output' => '
', + ), + ); + } } From 802c7a5a6d46c7bbd95d5e05bf64c9483103a98c Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Fri, 17 Nov 2023 10:02:24 +1100 Subject: [PATCH 062/116] Layout: Fix issue where layout classnames are injected for blocks without layout support (#56187) * Layout: Fix issue where layout classnames were sometimes injected for blocks without layout support * Simplify comment --- lib/block-supports/layout.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 0908f649bd5a91..d35c963d0bed48 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -617,6 +617,9 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { $processor->add_class( $class_name ); } return $processor->get_updated_html(); + } elseif ( ! $block_supports_layout ) { + // Ensure layout classnames are not injected if there is no layout support. + return $block_content; } $global_settings = gutenberg_get_global_settings(); From 178ca846d5c92e6a62ea3163fa883c0ff35df82a Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Fri, 17 Nov 2023 13:13:34 +1100 Subject: [PATCH 063/116] Drag and drop: allow dragging to the beginning and end of a document (#56070) * Try passing in a ref to allow dragging to the top and bottom of the editor canvas * Update naming * Implement in the site editor * Fix gap between post title and top of iframe * Add __unstable prefix in useInnerBlocksProps * Fix typo in comment --- .../block-editor/src/components/inner-blocks/index.js | 8 ++++++-- .../src/components/use-block-drop-zone/index.js | 5 ++++- packages/edit-post/src/components/visual-editor/index.js | 7 +++++++ .../src/components/block-editor/site-editor-canvas.js | 6 ++++++ 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/block-editor/src/components/inner-blocks/index.js b/packages/block-editor/src/components/inner-blocks/index.js index f5f216d6072e4b..abcde9f096e812 100644 --- a/packages/block-editor/src/components/inner-blocks/index.js +++ b/packages/block-editor/src/components/inner-blocks/index.js @@ -169,8 +169,11 @@ const ForwardedInnerBlocks = forwardRef( ( props, ref ) => { * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/inner-blocks/README.md */ export function useInnerBlocksProps( props = {}, options = {} ) { - const { __unstableDisableLayoutClassNames, __unstableDisableDropZone } = - options; + const { + __unstableDisableLayoutClassNames, + __unstableDisableDropZone, + __unstableDropZoneElement, + } = options; const { clientId, layout = null, @@ -211,6 +214,7 @@ export function useInnerBlocksProps( props = {}, options = {} ) { ); const blockDropZoneRef = useBlockDropZone( { + dropZoneElement: __unstableDropZoneElement, rootClientId: clientId, } ); diff --git a/packages/block-editor/src/components/use-block-drop-zone/index.js b/packages/block-editor/src/components/use-block-drop-zone/index.js index ba33e8ef8e74f3..25dc6ee408982f 100644 --- a/packages/block-editor/src/components/use-block-drop-zone/index.js +++ b/packages/block-editor/src/components/use-block-drop-zone/index.js @@ -127,7 +127,8 @@ export function getDropTargetPosition( /** * @typedef {Object} WPBlockDropZoneConfig - * @property {string} rootClientId The root client id for the block list. + * @property {?HTMLElement} dropZoneElement Optional element to be used as the drop zone. + * @property {string} rootClientId The root client id for the block list. */ /** @@ -136,6 +137,7 @@ export function getDropTargetPosition( * @param {WPBlockDropZoneConfig} dropZoneConfig configuration data for the drop zone. */ export default function useBlockDropZone( { + dropZoneElement, // An undefined value represents a top-level block. Default to an empty // string for this so that `targetRootClientId` can be easily compared to // values returned by the `getRootBlockClientId` selector, which also uses @@ -235,6 +237,7 @@ export default function useBlockDropZone( { ); return useDropZone( { + dropZoneElement, isDisabled, onDrop: onBlockDrop, onDragOver( event ) { diff --git a/packages/edit-post/src/components/visual-editor/index.js b/packages/edit-post/src/components/visual-editor/index.js index bd236551c7cf14..98fb302ce29c9f 100644 --- a/packages/edit-post/src/components/visual-editor/index.js +++ b/packages/edit-post/src/components/visual-editor/index.js @@ -411,6 +411,13 @@ export default function VisualEditor( { styles } ) { : `${ blockListLayoutClass } wp-block-post-content` // Ensure root level blocks receive default/flow blockGap styling rules. } layout={ blockListLayout } + __unstableDropZoneElement={ + // When iframed, pass in the html element of the iframe to + // ensure the drop zone extends to the edges of the iframe. + isToBeIframed + ? ref.current?.parentNode + : ref.current + } /> diff --git a/packages/edit-site/src/components/block-editor/site-editor-canvas.js b/packages/edit-site/src/components/block-editor/site-editor-canvas.js index e715587891c0a5..d3bc2ec56dfd84 100644 --- a/packages/edit-site/src/components/block-editor/site-editor-canvas.js +++ b/packages/edit-site/src/components/block-editor/site-editor-canvas.js @@ -134,6 +134,12 @@ export default function SiteEditorCanvas() { isTemplateTypeNavigation, } ) } + __unstableDropZoneElement={ + // Pass in the html element of the iframe to ensure that + // the drop zone extends to the very edges of the iframe, + // even if the template is shorter than the viewport. + contentRef.current?.parentNode + } layout={ LAYOUT } renderAppender={ showBlockAppender } /> From c9cad59cffb1fb7fef4786f3e157af032e629906 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Fri, 17 Nov 2023 15:46:58 +0800 Subject: [PATCH 064/116] Fix focus loss after converting to a synced pattern (#55473) * Fix focus lost after converting to a synced pattern * Fix for jsx --- packages/block-library/src/block/edit.js | 37 ++++---- packages/patterns/src/components/index.js | 3 +- .../src/components/pattern-convert-button.js | 14 ++- .../e2e/specs/editor/various/patterns.spec.js | 87 +++++++++++++++++++ 4 files changed, 117 insertions(+), 24 deletions(-) diff --git a/packages/block-library/src/block/edit.js b/packages/block-library/src/block/edit.js index 395e4bff4680bd..979ae04c62282c 100644 --- a/packages/block-library/src/block/edit.js +++ b/packages/block-library/src/block/edit.js @@ -114,33 +114,28 @@ export default function ReusableBlockEdit( { : InnerBlocks.ButtonBlockAppender, } ); + let children = null; if ( hasAlreadyRendered ) { - return ( -
- - { __( 'Block cannot be rendered inside itself.' ) } - -
+ children = ( + + { __( 'Block cannot be rendered inside itself.' ) } + ); } if ( isMissing ) { - return ( -
- - { __( 'Block has been deleted or is unavailable.' ) } - -
+ children = ( + + { __( 'Block has been deleted or is unavailable.' ) } + ); } if ( ! hasResolved ) { - return ( -
- - - -
+ children = ( + + + ); } @@ -157,7 +152,11 @@ export default function ReusableBlockEdit( { /> -
+ { children === null ? ( +
+ ) : ( +
{ children }
+ ) } ); } diff --git a/packages/patterns/src/components/index.js b/packages/patterns/src/components/index.js index a00d2d2bd262e2..6fddc593911f46 100644 --- a/packages/patterns/src/components/index.js +++ b/packages/patterns/src/components/index.js @@ -12,11 +12,12 @@ import PatternsManageButton from './patterns-manage-button'; export default function PatternsMenuItems( { rootClientId } ) { return ( - { ( { selectedClientIds } ) => ( + { ( { selectedClientIds, onClose } ) => ( <> { selectedClientIds.length === 1 && ( void} props.closeBlockSettingsMenu Callback to close the block settings menu dropdown. * @return {import('react').ComponentType} The menu control or null. */ -export default function PatternConvertButton( { clientIds, rootClientId } ) { +export default function PatternConvertButton( { + clientIds, + rootClientId, + closeBlockSettingsMenu, +} ) { const { createSuccessNotice } = useDispatch( noticesStore ); const { replaceBlocks } = useDispatch( blockEditorStore ); // Ignore reason: false positive of the lint rule. @@ -104,6 +109,7 @@ export default function PatternConvertButton( { clientIds, rootClientId } ) { replaceBlocks( clientIds, newBlock ); setEditingPattern( newBlock.clientId, true ); + closeBlockSettingsMenu(); } createSuccessNotice( diff --git a/test/e2e/specs/editor/various/patterns.spec.js b/test/e2e/specs/editor/various/patterns.spec.js index 941ae7e910a9b2..4b47b2dd70a358 100644 --- a/test/e2e/specs/editor/various/patterns.spec.js +++ b/test/e2e/specs/editor/various/patterns.spec.js @@ -81,3 +81,90 @@ test.describe( 'Unsynced pattern', () => { .toEqual( [ ...before, ...before ] ); } ); } ); + +test.describe( 'Synced pattern', () => { + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.deleteAllBlocks(); + await requestUtils.deleteAllPatternCategories(); + } ); + + test.beforeEach( async ( { admin } ) => { + await admin.createNewPost(); + } ); + + test.afterEach( async ( { requestUtils } ) => { + await requestUtils.deleteAllBlocks(); + await requestUtils.deleteAllPatternCategories(); + } ); + + test( 'create a new synced pattern via the block options menu', async ( { + editor, + page, + } ) => { + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'A useful paragraph to reuse' }, + } ); + + // Create a synced pattern from the paragraph block. + await editor.showBlockToolbar(); + await page + .getByRole( 'toolbar', { name: 'Block tools' } ) + .getByRole( 'button', { name: 'Options' } ) + .click(); + await page.getByRole( 'menuitem', { name: 'Create pattern' } ).click(); + + const createPatternDialog = page.getByRole( 'dialog', { + name: 'Create pattern', + } ); + await createPatternDialog + .getByRole( 'textbox', { name: 'Name' } ) + .fill( 'My synced pattern' ); + const newCategory = 'Contact details'; + await createPatternDialog + .getByRole( 'combobox', { name: 'Categories' } ) + .fill( newCategory ); + await createPatternDialog + .getByRole( 'checkbox', { name: 'Synced' } ) + .setChecked( true ); + + await createPatternDialog + .getByRole( 'button', { name: 'Create' } ) + .click(); + + await expect + .poll( + editor.getBlocks, + 'The block content should be wrapped by a pattern block wrapper' + ) + .toEqual( [ + { + name: 'core/block', + attributes: { ref: expect.any( Number ) }, + innerBlocks: [], + }, + ] ); + const after = await editor.getBlocks(); + + const patternBlock = editor.canvas.getByRole( 'document', { + name: 'Block: Pattern', + } ); + await expect( patternBlock ).toBeFocused(); + + // Check that the new pattern is available in the inserter. + await page.getByLabel( 'Toggle block inserter' ).click(); + await page + .getByRole( 'tab', { + name: 'Patterns', + } ) + .click(); + await page + .getByRole( 'button', { + name: newCategory, + } ) + .click(); + await page.getByRole( 'option', { name: 'My synced pattern' } ).click(); + + await expect.poll( editor.getBlocks ).toEqual( [ ...after, ...after ] ); + } ); +} ); From 71f29d0f43dc32a7d51a9d778155164905da8faa Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Fri, 17 Nov 2023 12:43:11 +0400 Subject: [PATCH 065/116] useEntityRecord: Do not trigger REST API requests when disabled (#56108) * useEntityRecord: Do not trigger REST API requests when disabled * Adjust tests --- .../src/hooks/test/use-entity-record.js | 38 +++++++++++++++ .../core-data/src/hooks/use-entity-record.ts | 48 ++++++++++++------- 2 files changed, 68 insertions(+), 18 deletions(-) diff --git a/packages/core-data/src/hooks/test/use-entity-record.js b/packages/core-data/src/hooks/test/use-entity-record.js index d78a64d5f2b628..1fe68c84a951b7 100644 --- a/packages/core-data/src/hooks/test/use-entity-record.js +++ b/packages/core-data/src/hooks/test/use-entity-record.js @@ -23,6 +23,7 @@ describe( 'useEntityRecord', () => { beforeEach( () => { registry = createRegistry(); registry.register( coreDataStore ); + triggerFetch.mockReset(); } ); const TEST_RECORD = { id: 1, hello: 'world' }; @@ -113,4 +114,41 @@ describe( 'useEntityRecord', () => { expect( widget.editedRecord ).toEqual( { hello: 'foo', id: 1 } ); expect( widget.edits ).toEqual( { hello: 'foo' } ); } ); + + it( 'does not resolve entity record when disabled via options', async () => { + // Provide response + triggerFetch.mockImplementation( () => TEST_RECORD ); + + let data; + const TestComponent = () => { + data = useEntityRecord( 'root', 'widget', 2, { + options: { enabled: false }, + } ); + return
; + }; + render( + + + + ); + + expect( data ).toEqual( { + edit: expect.any( Function ), + editedRecord: {}, + hasEdits: false, + edits: {}, + record: null, + save: expect.any( Function ), + } ); + + // Fetch request should have been issued. + await waitFor( () => { + expect( triggerFetch ).not.toHaveBeenCalled(); + } ); + await waitFor( () => + expect( triggerFetch ).not.toHaveBeenCalledWith( { + path: '/wp/v2/widgets/2?context=edit', + } ) + ); + } ); } ); diff --git a/packages/core-data/src/hooks/use-entity-record.ts b/packages/core-data/src/hooks/use-entity-record.ts index 6c755c7bad6a60..60228893e5102e 100644 --- a/packages/core-data/src/hooks/use-entity-record.ts +++ b/packages/core-data/src/hooks/use-entity-record.ts @@ -56,6 +56,8 @@ export interface Options { enabled: boolean; } +const EMPTY_OBJECT = {}; + /** * Resolves the specified entity record. * @@ -167,24 +169,34 @@ export default function useEntityRecord< RecordType >( ); const { editedRecord, hasEdits, edits } = useSelect( - ( select ) => ( { - editedRecord: select( coreStore ).getEditedEntityRecord( - kind, - name, - recordId - ), - hasEdits: select( coreStore ).hasEditsForEntityRecord( - kind, - name, - recordId - ), - edits: select( coreStore ).getEntityRecordNonTransientEdits( - kind, - name, - recordId - ), - } ), - [ kind, name, recordId ] + ( select ) => { + if ( ! options.enabled ) { + return { + editedRecord: EMPTY_OBJECT, + hasEdits: false, + edits: EMPTY_OBJECT, + }; + } + + return { + editedRecord: select( coreStore ).getEditedEntityRecord( + kind, + name, + recordId + ), + hasEdits: select( coreStore ).hasEditsForEntityRecord( + kind, + name, + recordId + ), + edits: select( coreStore ).getEntityRecordNonTransientEdits( + kind, + name, + recordId + ), + }; + }, + [ kind, name, recordId, options.enabled ] ); const { data: record, ...querySelectRest } = useQuerySelect( From 7aa1c8876a0bfca19490aadf9a21142e56c51d94 Mon Sep 17 00:00:00 2001 From: Marco Ciampini Date: Fri, 17 Nov 2023 10:53:41 +0100 Subject: [PATCH 066/116] Site Editor Sidebar: fix actions vertical alignment (#56218) --- .../src/components/sidebar-navigation-screen/style.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/edit-site/src/components/sidebar-navigation-screen/style.scss b/packages/edit-site/src/components/sidebar-navigation-screen/style.scss index f658083cc19f4e..b856837b7c6b6a 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen/style.scss +++ b/packages/edit-site/src/components/sidebar-navigation-screen/style.scss @@ -72,6 +72,7 @@ } .edit-site-sidebar-navigation-screen__actions { + display: flex; flex-shrink: 0; } From 903778cb8b2d450c3ca0ba8a872c1f233b2f5c88 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Fri, 17 Nov 2023 11:21:10 +0100 Subject: [PATCH 067/116] Unify the PostSchedule component between site and post editors (#56196) --- .../specs/editor/various/datepicker.test.js | 16 ++-- .../specs/editor/various/scheduling.test.js | 2 +- .../components/sidebar/post-schedule/index.js | 67 ------------- .../sidebar/post-schedule/style.scss | 36 ------- .../components/sidebar/post-status/index.js | 4 +- packages/edit-post/src/style.scss | 1 - .../page-panels/page-summary.js | 10 +- .../page-panels/publish-date.js | 94 ------------------- packages/editor/src/components/index.js | 1 + .../src/components/post-schedule/panel.js | 72 ++++++++++++++ .../src/components/post-schedule/style.scss | 30 ++++++ packages/editor/src/style.scss | 1 + 12 files changed, 117 insertions(+), 217 deletions(-) delete mode 100644 packages/edit-post/src/components/sidebar/post-schedule/index.js delete mode 100644 packages/edit-post/src/components/sidebar/post-schedule/style.scss delete mode 100644 packages/edit-site/src/components/sidebar-edit-mode/page-panels/publish-date.js create mode 100644 packages/editor/src/components/post-schedule/panel.js create mode 100644 packages/editor/src/components/post-schedule/style.scss diff --git a/packages/e2e-tests/specs/editor/various/datepicker.test.js b/packages/e2e-tests/specs/editor/various/datepicker.test.js index b0fc3bf898d4a4..6838fd56a2ba9a 100644 --- a/packages/e2e-tests/specs/editor/various/datepicker.test.js +++ b/packages/e2e-tests/specs/editor/various/datepicker.test.js @@ -56,7 +56,7 @@ function formatDatePickerValues( async function getPublishingDate() { return page.$eval( - '.edit-post-post-schedule__toggle', + '.editor-post-schedule__dialog-toggle', ( dateLabel ) => dateLabel.textContent ); } @@ -83,7 +83,7 @@ describe.each( [ [ 'UTC-10' ], [ 'UTC' ], [ 'UTC+10' ] ] )( it( 'should show the publishing date if the date is in the past', async () => { // Open the datepicker. - await page.click( '.edit-post-post-schedule__toggle' ); + await page.click( '.editor-post-schedule__dialog-toggle' ); // Change the publishing date to a year in the past. await page.click( '.components-datetime__time-field-year' ); @@ -91,7 +91,7 @@ describe.each( [ [ 'UTC-10' ], [ 'UTC' ], [ 'UTC+10' ] ] )( const datePickerValues = await getDatePickerValues(); // Close the datepicker. - await page.click( '.edit-post-post-schedule__toggle' ); + await page.click( '.editor-post-schedule__dialog-toggle' ); const publishingDate = await getPublishingDate(); @@ -102,7 +102,7 @@ describe.each( [ [ 'UTC-10' ], [ 'UTC' ], [ 'UTC+10' ] ] )( it( 'should show the publishing date if the date is in the future', async () => { // Open the datepicker. - await page.click( '.edit-post-post-schedule__toggle' ); + await page.click( '.editor-post-schedule__dialog-toggle' ); // Change the publishing date to a year in the future. await page.click( '.components-datetime__time-field-year' ); @@ -110,7 +110,7 @@ describe.each( [ [ 'UTC-10' ], [ 'UTC' ], [ 'UTC+10' ] ] )( const datePickerValues = await getDatePickerValues(); // Close the datepicker. - await page.click( '.edit-post-post-schedule__toggle' ); + await page.click( '.editor-post-schedule__dialog-toggle' ); const publishingDate = await getPublishingDate(); @@ -123,17 +123,17 @@ describe.each( [ [ 'UTC-10' ], [ 'UTC' ], [ 'UTC+10' ] ] )( it( `should show the publishing date as "Immediately" if the date is cleared`, async () => { // Open the datepicker. - await page.click( '.edit-post-post-schedule__toggle' ); + await page.click( '.editor-post-schedule__dialog-toggle' ); // Change the publishing date to a year in the future. await page.click( '.components-datetime__time-field-year' ); await page.keyboard.press( 'ArrowUp' ); // Close the datepicker. - await page.click( '.edit-post-post-schedule__toggle' ); + await page.click( '.editor-post-schedule__dialog-toggle' ); // Open the datepicker. - await page.click( '.edit-post-post-schedule__toggle' ); + await page.click( '.editor-post-schedule__dialog-toggle' ); // Clear the date. await page.click( diff --git a/packages/e2e-tests/specs/editor/various/scheduling.test.js b/packages/e2e-tests/specs/editor/various/scheduling.test.js index 61c3541c1f47e5..df75dcb92f2820 100644 --- a/packages/e2e-tests/specs/editor/various/scheduling.test.js +++ b/packages/e2e-tests/specs/editor/various/scheduling.test.js @@ -46,7 +46,7 @@ describe( 'Scheduling', () => { await page.keyboard.press( 'ArrowUp' ); // Close the datepicker. - await page.click( '.edit-post-post-schedule__toggle' ); + await page.click( '.editor-post-schedule__dialog-toggle' ); expect( await getPublishButtonText() ).toBe( 'Schedule…' ); } ); diff --git a/packages/edit-post/src/components/sidebar/post-schedule/index.js b/packages/edit-post/src/components/sidebar/post-schedule/index.js deleted file mode 100644 index 3b20880d736471..00000000000000 --- a/packages/edit-post/src/components/sidebar/post-schedule/index.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * WordPress dependencies - */ -import { __, sprintf } from '@wordpress/i18n'; -import { PanelRow, Dropdown, Button } from '@wordpress/components'; -import { useState, useMemo } from '@wordpress/element'; -import { - PostSchedule as PostScheduleForm, - PostScheduleCheck, - usePostScheduleLabel, -} from '@wordpress/editor'; - -export default function PostSchedule() { - // Use internal state instead of a ref to make sure that the component - // re-renders when the popover's anchor updates. - const [ popoverAnchor, setPopoverAnchor ] = useState( null ); - // Memoize popoverProps to avoid returning a new object every time. - const popoverProps = useMemo( - () => ( { anchor: popoverAnchor, placement: 'bottom-end' } ), - [ popoverAnchor ] - ); - - return ( - - - { __( 'Publish' ) } - ( - - ) } - renderContent={ ( { onClose } ) => ( - - ) } - /> - - - ); -} - -function PostScheduleToggle( { isOpen, onClick } ) { - const label = usePostScheduleLabel(); - const fullLabel = usePostScheduleLabel( { full: true } ); - return ( - - ); -} diff --git a/packages/edit-post/src/components/sidebar/post-schedule/style.scss b/packages/edit-post/src/components/sidebar/post-schedule/style.scss deleted file mode 100644 index 46fcd819640045..00000000000000 --- a/packages/edit-post/src/components/sidebar/post-schedule/style.scss +++ /dev/null @@ -1,36 +0,0 @@ -.edit-post-post-schedule { - width: 100%; - position: relative; - justify-content: flex-start; - align-items: flex-start; - - span { - display: block; - width: 30%; - margin-right: 8px; - } -} - -.edit-post-post-schedule__dropdown { - width: 70%; -} - -.components-button.edit-post-post-schedule__toggle { - text-align: left; - white-space: normal; - height: auto; - - // This span is added by the Popover in Tooltip when no anchor is - // provided. We set its width to 0 so that it does not cause the button text - // to wrap to a new line when displaying the tooltip. A better fix would be - // to pass anchorRef and avoid the need for a span alltogether, which is - // what this PR allows us to do: - // https://github.com/WordPress/gutenberg/pull/41268. - span { - width: 0; - } -} - -.edit-post-post-schedule__dialog .block-editor-publish-date-time-picker { - margin: $grid-unit-10; -} diff --git a/packages/edit-post/src/components/sidebar/post-status/index.js b/packages/edit-post/src/components/sidebar/post-status/index.js index d903cbb2fa12bc..c8c5a20adcfab1 100644 --- a/packages/edit-post/src/components/sidebar/post-status/index.js +++ b/packages/edit-post/src/components/sidebar/post-status/index.js @@ -8,6 +8,7 @@ import { } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; import { + PostSchedulePanel, PostSwitchToDraftButton, PostSyncStatus, PostURLPanel, @@ -18,7 +19,6 @@ import { */ import PostVisibility from '../post-visibility'; import PostTrash from '../post-trash'; -import PostSchedule from '../post-schedule'; import PostSticky from '../post-sticky'; import PostAuthor from '../post-author'; import PostSlug from '../post-slug'; @@ -61,7 +61,7 @@ export default function PostStatus() { { ( fills ) => ( <> - + diff --git a/packages/edit-post/src/style.scss b/packages/edit-post/src/style.scss index 7a71d20ba0f1f4..89a5c4483b97ee 100644 --- a/packages/edit-post/src/style.scss +++ b/packages/edit-post/src/style.scss @@ -12,7 +12,6 @@ @import "./components/sidebar/last-revision/style.scss"; @import "./components/sidebar/post-author/style.scss"; @import "./components/sidebar/post-format/style.scss"; -@import "./components/sidebar/post-schedule/style.scss"; @import "./components/sidebar/post-slug/style.scss"; @import "./components/sidebar/post-template/style.scss"; @import "./components/sidebar/post-visibility/style.scss"; diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js index 26fa86c933f115..e847ec11953b12 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-summary.js @@ -2,13 +2,12 @@ * WordPress dependencies */ import { __experimentalVStack as VStack } from '@wordpress/components'; -import { PostURLPanel } from '@wordpress/editor'; +import { PostURLPanel, PostSchedulePanel } from '@wordpress/editor'; /** * Internal dependencies */ import PageStatus from './page-status'; -import PublishDate from './publish-date'; import EditTemplate from './edit-template'; export default function PageSummary( { @@ -27,12 +26,7 @@ export default function PageSummary( { postId={ postId } postType={ postType } /> - + diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/publish-date.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/publish-date.js deleted file mode 100644 index d000394f6816ba..00000000000000 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/publish-date.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * WordPress dependencies - */ -import { - Button, - Dropdown, - __experimentalText as Text, - __experimentalHStack as HStack, -} from '@wordpress/components'; -import { __ } from '@wordpress/i18n'; -import { useDispatch } from '@wordpress/data'; -import { useState, useMemo } from '@wordpress/element'; -import { store as coreStore } from '@wordpress/core-data'; -import { store as noticesStore } from '@wordpress/notices'; -import { __experimentalPublishDateTimePicker as PublishDateTimePicker } from '@wordpress/block-editor'; -import { humanTimeDiff } from '@wordpress/date'; - -export default function ChangeStatus( { postType, postId, status, date } ) { - const { editEntityRecord } = useDispatch( coreStore ); - const { createErrorNotice } = useDispatch( noticesStore ); - - const [ popoverAnchor, setPopoverAnchor ] = useState( null ); - // Memoize popoverProps to avoid returning a new object every time. - const popoverProps = useMemo( - () => ( { - // Anchor the popover to the middle of the entire row so that it doesn't - // move around when the label changes. - anchor: popoverAnchor, - 'aria-label': __( 'Change publish date' ), - placement: 'bottom-end', - } ), - [ popoverAnchor ] - ); - - const saveDate = async ( newDate ) => { - try { - let newStatus = status; - if ( status === 'future' && new Date( newDate ) < new Date() ) { - newStatus = 'publish'; - } else if ( - status === 'publish' && - new Date( newDate ) > new Date() - ) { - newStatus = 'future'; - } - await editEntityRecord( 'postType', postType, postId, { - status: newStatus, - date: newDate, - } ); - } catch ( error ) { - const errorMessage = - error.message && error.code !== 'unknown_error' - ? error.message - : __( 'An error occurred while updating the status' ); - - createErrorNotice( errorMessage, { - type: 'snackbar', - } ); - } - }; - - const relateToNow = date ? humanTimeDiff( date ) : __( 'Immediately' ); - - return ( - - - { __( 'Publish' ) } - - ( - - ) } - renderContent={ ( { onClose } ) => ( - - ) } - /> - - ); -} diff --git a/packages/editor/src/components/index.js b/packages/editor/src/components/index.js index bcfccc026ff727..a5a4fc7fcac365 100644 --- a/packages/editor/src/components/index.js +++ b/packages/editor/src/components/index.js @@ -50,6 +50,7 @@ export { default as PostScheduleLabel, usePostScheduleLabel, } from './post-schedule/label'; +export { default as PostSchedulePanel } from './post-schedule/panel'; export { default as PostSlug } from './post-slug'; export { default as PostSlugCheck } from './post-slug/check'; export { default as PostSticky } from './post-sticky'; diff --git a/packages/editor/src/components/post-schedule/panel.js b/packages/editor/src/components/post-schedule/panel.js new file mode 100644 index 00000000000000..834e7237e0e946 --- /dev/null +++ b/packages/editor/src/components/post-schedule/panel.js @@ -0,0 +1,72 @@ +/** + * WordPress dependencies + */ +import { + Button, + Dropdown, + __experimentalHStack as HStack, +} from '@wordpress/components'; +import { __, sprintf } from '@wordpress/i18n'; +import { useState, useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import PostScheduleCheck from './check'; +import PostScheduleForm from './index'; +import { usePostScheduleLabel } from './label'; + +export default function PostSchedulePanel() { + const [ popoverAnchor, setPopoverAnchor ] = useState( null ); + // Memoize popoverProps to avoid returning a new object every time. + const popoverProps = useMemo( + () => ( { + // Anchor the popover to the middle of the entire row so that it doesn't + // move around when the label changes. + anchor: popoverAnchor, + 'aria-label': __( 'Change publish date' ), + placement: 'bottom-end', + } ), + [ popoverAnchor ] + ); + + const label = usePostScheduleLabel(); + const fullLabel = usePostScheduleLabel( { full: true } ); + + return ( + + + { __( 'Publish' ) } + ( + + ) } + renderContent={ ( { onClose } ) => ( + + ) } + /> + + + ); +} diff --git a/packages/editor/src/components/post-schedule/style.scss b/packages/editor/src/components/post-schedule/style.scss new file mode 100644 index 00000000000000..d70a9e9576fbbe --- /dev/null +++ b/packages/editor/src/components/post-schedule/style.scss @@ -0,0 +1,30 @@ +.editor-post-schedule__panel { + width: 100%; + justify-content: flex-start; + align-items: flex-start; + + span { + display: block; + width: 30%; + } +} + +.editor-post-schedule__panel-dropdown { + width: 70%; +} + +.editor-post-schedule__dialog { + .components-popover__content { + min-width: 320px; + padding: $grid-unit-20; + } +} + +.editor-post-schedule__dialog-toggle { + display: block; + max-width: 100%; + overflow: hidden; + text-align: left; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/packages/editor/src/style.scss b/packages/editor/src/style.scss index dbffbbef4d5212..5428bf5cb1f151 100644 --- a/packages/editor/src/style.scss +++ b/packages/editor/src/style.scss @@ -11,6 +11,7 @@ @import "./components/post-publish-button/style.scss"; @import "./components/post-publish-panel/style.scss"; @import "./components/post-saved-state/style.scss"; +@import "./components/post-schedule/style.scss"; @import "./components/post-sync-status/style.scss"; @import "./components/post-taxonomies/style.scss"; @import "./components/post-text-editor/style.scss"; From cc426adab1b187298b32dbb8cb4e10dca44ae40d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Fri, 17 Nov 2023 13:43:24 +0100 Subject: [PATCH 068/116] DataViews: update field API to generate filters based on type (#55996) --- .../src/components/dataviews/README.md | 4 +- .../src/components/dataviews/add-filter.js | 18 ++++----- .../src/components/dataviews/filters.js | 37 ++++++++----------- .../src/components/dataviews/in-filter.js | 1 + .../src/components/dataviews/view-list.js | 15 ++++---- .../src/components/page-pages/index.js | 4 +- 6 files changed, 38 insertions(+), 41 deletions(-) diff --git a/packages/edit-site/src/components/dataviews/README.md b/packages/edit-site/src/components/dataviews/README.md index 8f1349044d6cf5..0645f22821cb9e 100644 --- a/packages/edit-site/src/components/dataviews/README.md +++ b/packages/edit-site/src/components/dataviews/README.md @@ -154,11 +154,11 @@ Example: { item.author } ); }, + type: 'enumeration', elements: [ { value: 1, label: 'Admin' } { value: 2, label: 'User' } ] - filters: [ 'in' ], enableSorting: false } ] @@ -169,7 +169,7 @@ Example: - `getValue`: function that returns the value of the field. - `render`: function that renders the field. - `elements`: the set of valid values for the field's value. -- `filters`: what filter operators are available for the user to use over this field. Only `in` available at the moment. +- `type`: the type of the field. Used to generate the proper filters. Only `enumeration` available at the moment. - `enableSorting`: whether the data can be sorted by the given field. True by default. - `enableHiding`: whether the field can be hidden. True by default. diff --git a/packages/edit-site/src/components/dataviews/add-filter.js b/packages/edit-site/src/components/dataviews/add-filter.js index 2cc0051f0f2d49..374a90eab9df03 100644 --- a/packages/edit-site/src/components/dataviews/add-filter.js +++ b/packages/edit-site/src/components/dataviews/add-filter.js @@ -22,28 +22,28 @@ const { DropdownMenuItemV2, } = unlock( componentsPrivateApis ); -const VALID_OPERATORS = [ OPERATOR_IN ]; +// TODO: find a place where these constants can be shared across components. +const ENUMERATION_TYPE = 'enumeration'; export default function AddFilter( { fields, view, onChangeView } ) { const filters = []; fields.forEach( ( field ) => { - if ( ! field.filters ) { + if ( ! field.type ) { return; } - field.filters.forEach( ( filter ) => { - if ( VALID_OPERATORS.some( ( operator ) => operator === filter ) ) { + switch ( field.type ) { + case ENUMERATION_TYPE: filters.push( { field: field.id, name: field.header, - operator: filter, elements: field.elements || [], isVisible: view.filters.some( - ( f ) => f.field === field.id && f.operator === filter + ( f ) => + f.field === field.id && f.operator === OPERATOR_IN ), } ); - } - } ); + } } ); if ( filters.length === 0 ) { @@ -92,7 +92,7 @@ export default function AddFilter( { fields, view, onChangeView } ) { ...currentView.filters, { field: filter.field, - operator: 'in', + operator: OPERATOR_IN, value: element.value, }, ], diff --git a/packages/edit-site/src/components/dataviews/filters.js b/packages/edit-site/src/components/dataviews/filters.js index 9c37a7501a155d..72ba28fd063263 100644 --- a/packages/edit-site/src/components/dataviews/filters.js +++ b/packages/edit-site/src/components/dataviews/filters.js @@ -10,21 +10,20 @@ import { default as InFilter, OPERATOR_IN } from './in-filter'; import AddFilter from './add-filter'; import ResetFilters from './reset-filters'; -const VALID_OPERATORS = [ OPERATOR_IN ]; +const ENUMERATION_TYPE = 'enumeration'; export default function Filters( { fields, view, onChangeView } ) { const filters = []; fields.forEach( ( field ) => { - if ( ! field.filters ) { + if ( ! field.type ) { return; } - field.filters.forEach( ( filter ) => { - if ( VALID_OPERATORS.some( ( operator ) => operator === filter ) ) { + switch ( field.type ) { + case ENUMERATION_TYPE: filters.push( { field: field.id, name: field.header, - operator: filter, elements: [ { value: '', @@ -33,30 +32,26 @@ export default function Filters( { fields, view, onChangeView } ) { ...( field.elements || [] ), ], isVisible: view.filters.some( - ( f ) => f.field === field.id && f.operator === filter + ( f ) => + f.field === field.id && f.operator === OPERATOR_IN ), } ); - } - } ); + } } ); - const filterComponents = filters?.map( ( filter ) => { + const filterComponents = filters.map( ( filter ) => { if ( ! filter.isVisible ) { return null; } - if ( OPERATOR_IN === filter.operator ) { - return ( - - ); - } - - return null; + return ( + + ); } ); filterComponents.push( diff --git a/packages/edit-site/src/components/dataviews/in-filter.js b/packages/edit-site/src/components/dataviews/in-filter.js index 4154e0576101c1..cb76bab0f870a9 100644 --- a/packages/edit-site/src/components/dataviews/in-filter.js +++ b/packages/edit-site/src/components/dataviews/in-filter.js @@ -7,6 +7,7 @@ import { } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; +// TODO: find a place where these constants can be shared across components. export const OPERATOR_IN = 'in'; export default ( { filter, view, onChangeView } ) => { diff --git a/packages/edit-site/src/components/dataviews/view-list.js b/packages/edit-site/src/components/dataviews/view-list.js index 2fec3286314231..fc8b4075025792 100644 --- a/packages/edit-site/src/components/dataviews/view-list.js +++ b/packages/edit-site/src/components/dataviews/view-list.js @@ -52,6 +52,11 @@ const sortingItemsInfo = { desc: { icon: arrowDown, label: __( 'Sort descending' ) }, }; const sortIcons = { asc: chevronUp, desc: chevronDown }; + +// TODO: find a place where these constants can be shared across components. +const ENUMERATION_TYPE = 'enumeration'; +const OPERATOR_IN = 'in'; + function HeaderMenu( { dataView, header } ) { if ( header.isPlaceholder ) { return null; @@ -68,12 +73,7 @@ function HeaderMenu( { dataView, header } ) { const sortedDirection = header.column.getIsSorted(); let filter; - if ( - header.column.columnDef.filters?.length > 0 && - header.column.columnDef.filters.some( - ( f ) => 'string' === typeof f && f === 'in' - ) - ) { + if ( header.column.columnDef.type === ENUMERATION_TYPE ) { filter = { field: header.column.columnDef.id, elements: [ @@ -202,7 +202,8 @@ function HeaderMenu( { dataView, header } ) { return ( field !== filter.field || - operator !== 'in' + operator !== + OPERATOR_IN ); } ); diff --git a/packages/edit-site/src/components/page-pages/index.js b/packages/edit-site/src/components/page-pages/index.js index c2461adc34f8d0..d6c295dc72ff0f 100644 --- a/packages/edit-site/src/components/page-pages/index.js +++ b/packages/edit-site/src/components/page-pages/index.js @@ -227,7 +227,7 @@ export default function PagePages() { ); }, - filters: [ 'in' ], + type: 'enumeration', elements: authors?.map( ( { id, name } ) => ( { value: id, @@ -240,7 +240,7 @@ export default function PagePages() { getValue: ( { item } ) => STATUSES.find( ( { value } ) => value === item.status ) ?.label ?? item.status, - filters: [ 'in' ], + type: 'enumeration', elements: STATUSES, enableSorting: false, }, From 22dcbde7c2f61d7534f262c3c38fe277063821ea Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Fri, 17 Nov 2023 22:01:32 +0900 Subject: [PATCH 069/116] Image Block: Enable image block to be selected correctly when clicked (#56043) * Image Block: Enable image blocks to be selected correctly when clicked * Add tabIndex * Update packages/block-library/src/image/editor.scss Co-authored-by: Ramon * Wrap img element directly to make the image resizable * Use `display:inline` instead of `display:inline-block` --------- Co-authored-by: Ramon --- packages/block-library/src/image/editor.scss | 7 -- packages/block-library/src/image/image.js | 77 ++++++++++++-------- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/packages/block-library/src/image/editor.scss b/packages/block-library/src/image/editor.scss index e1721928362149..934682ed91b7de 100644 --- a/packages/block-library/src/image/editor.scss +++ b/packages/block-library/src/image/editor.scss @@ -62,13 +62,6 @@ figure.wp-block-image:not(.wp-block) { left: 50%; transform: translate(-50%, -50%); } - - // When the Image block is linked, - // it's wrapped with a disabled tag. - // Restore cursor style so it doesn't appear 'clickable'. - > a { - cursor: default; - } } // This is necessary for the editor resize handles to accurately work on a non-floated, non-resized, small image. diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index ae5f749fff3b5f..64eb03adedb32b 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -83,9 +83,29 @@ const scaleOptions = [ }, ]; -const disabledClickProps = { - onClick: ( event ) => event.preventDefault(), - 'aria-disabled': true, +// If the image has a href, wrap in an tag to trigger any inherited link element styles. +const ImageWrapper = ( { href, children } ) => { + if ( ! href ) { + return children; + } + return ( + event.preventDefault() } + aria-disabled={ true } + style={ { + // When the Image block is linked, + // it's wrapped with a disabled tag. + // Restore cursor style so it doesn't appear 'clickable' + // and remove pointer events. Safari needs the display property. + pointerEvents: 'none', + cursor: 'default', + display: 'inline', + } } + > + { children } + + ); }; export default function Image( { @@ -653,25 +673,31 @@ export default function Image( { if ( canEditImage && isEditingImage ) { img = ( - - setAttributes( imageAttributes ) - } - onFinishEditing={ () => { - setIsEditingImage( false ); - } } - borderProps={ isRounded ? undefined : borderProps } - /> + + + setAttributes( imageAttributes ) + } + onFinishEditing={ () => { + setIsEditingImage( false ); + } } + borderProps={ isRounded ? undefined : borderProps } + /> + ); } else if ( ! isResizable ) { - img =
{ img }
; + img = ( +
+ { img } +
+ ); } else { const numericRatio = aspectRatio && evalAspectRatio( aspectRatio ); const customRatio = numericWidth / numericHeight; @@ -774,7 +800,7 @@ export default function Image( { } } resizeRatio={ align === 'center' ? 2 : 1 } > - { img } + { img } ); } @@ -788,14 +814,7 @@ export default function Image( { { /* Hide controls during upload to avoid component remount, which causes duplicated image upload. */ } { ! temporaryURL && controls } - { /* If the image has a href, wrap in an tag to trigger any inherited link element styles */ } - { !! href ? ( - - { img } - - ) : ( - img - ) } + { img } { showCaption && ( ! RichText.isEmpty( caption ) || isSelected ) && ( Date: Fri, 17 Nov 2023 08:26:46 -0500 Subject: [PATCH 070/116] Update reference to the gutenberg-examples repo to the new block-development-examples repo. (#56119) --- docs/README.md | 4 ++-- docs/how-to-guides/block-tutorial/README.md | 4 ++-- .../block-tutorial/applying-styles-with-stylesheets.md | 4 ++-- .../block-tutorial/creating-dynamic-blocks.md | 2 +- .../block-tutorial/writing-your-first-block-type.md | 8 ++++---- docs/how-to-guides/data-basics/1-data-basics-setup.md | 2 +- .../data-basics/2-building-a-list-of-pages.md | 2 +- docs/how-to-guides/data-basics/3-building-an-edit-form.md | 2 +- .../data-basics/4-building-a-create-page-form.md | 2 +- .../how-to-guides/data-basics/5-adding-a-delete-button.md | 2 +- docs/how-to-guides/data-basics/README.md | 2 +- docs/how-to-guides/format-api.md | 4 ++-- docs/how-to-guides/javascript/js-build-setup.md | 4 ++-- docs/how-to-guides/metabox.md | 2 +- docs/how-to-guides/plugin-sidebar-0.md | 4 ++-- 15 files changed, 24 insertions(+), 24 deletions(-) diff --git a/docs/README.md b/docs/README.md index d04df59e957529..219c622dc3d73c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -58,7 +58,7 @@ This handbook should be considered the canonical resource for all things related - [**WordPress Developer Blog**](https://developer.wordpress.org/news/) - An ever-growing resource of technical articles covering specific topics related to block development and a wide variety of use cases. The blog is also an excellent way to [keep up with the latest developments in WordPress](https://developer.wordpress.org/news/tag/roundup/). - [**Learn WordPress**](https://learn.wordpress.org/) - The WordPress hub for learning resources where you can find courses like [Introduction to Block Development: Build your first custom block](https://learn.wordpress.org/course/introduction-to-block-development-build-your-first-custom-block/), [Converting a Shortcode to a Block](https://learn.wordpress.org/course/converting-a-shortcode-to-a-block/) or [Using the WordPress Data Layer](https://learn.wordpress.org/course/using-the-wordpress-data-layer/) - [**WordPress.tv**](https://wordpress.tv/) - A hub of WordPress-related videos (from talks at WordCamps to recordings of online workshops) curated and moderated by the WordPress.org community. You’re sure to find something to aid your learning about [block development](https://wordpress.tv/?s=block%20development&sort=newest) or the [block-editor](https://wordpress.tv/?s=block%20editor&sort=relevance) here. -- [**Gutenberg repository**](https://github.com/WordPress/gutenberg/) - Development of the block editor project is carried out in this GitHub repository. It contains the code of interesting packages such as [`block-library`](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src) (core blocks) or [`components`](https://github.com/WordPress/gutenberg/tree/trunk/packages/components) (common UI elements). _The [gutenberg-examples](https://github.com/WordPress/gutenberg-examples) repository is another useful reference._ +- [**Gutenberg repository**](https://github.com/WordPress/gutenberg/) - Development of the block editor project is carried out in this GitHub repository. It contains the code of interesting packages such as [`block-library`](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src) (core blocks) or [`components`](https://github.com/WordPress/gutenberg/tree/trunk/packages/components) (common UI elements). _The [block-development-examples](https://github.com/WordPress/block-development-examples) repository is another useful reference._ ## Are you in the right place? @@ -70,4 +70,4 @@ This handbook should be considered the canonical resource for all things related - [/apis](https://developer.wordpress.org/apis) - Common APIs Handbook - [/advanced-administration](https://developer.wordpress.org/advanced-administration) - WP Advanced Administration Handbook - [/rest-api](https://developer.wordpress.org/rest-api/) - REST API Handbook -- [/coding-standards](https://developer.wordpress.org/coding-standards) - Best practices for WordPress developers \ No newline at end of file +- [/coding-standards](https://developer.wordpress.org/coding-standards) - Best practices for WordPress developers diff --git a/docs/how-to-guides/block-tutorial/README.md b/docs/how-to-guides/block-tutorial/README.md index 95aa4182430c07..8688bd09416d7b 100644 --- a/docs/how-to-guides/block-tutorial/README.md +++ b/docs/how-to-guides/block-tutorial/README.md @@ -2,9 +2,9 @@ The purpose of this tutorial is to step through the fundamentals of creating a new block type. Beginning with the simplest possible example, each new section will incrementally build upon the last to include more of the common functionality you could expect to need when implementing your own block types. -To follow along with this tutorial, you can download the [accompanying WordPress plugin](https://github.com/WordPress/gutenberg-examples) which includes all of the examples for you to try on your own site. At each step along the way, experiment by modifying the examples with your own ideas, and observe the effects they have on the block's behavior. +To follow along with this tutorial, you can download the [accompanying WordPress plugin](https://github.com/WordPress/block-development-examples) which includes all of the examples for you to try on your own site. At each step along the way, experiment by modifying the examples with your own ideas, and observe the effects they have on the block's behavior. -> To find the latest version of the .zip file go to the repo's [releases page](https://github.com/WordPress/gutenberg-examples/releases) and look in the latest release under 'Assets'. +> To find the latest version of the .zip file go to the repo's [releases page](https://github.com/WordPress/block-development-examples/releases) and look in the latest release under 'Assets'. Code snippets are provided in two formats "JSX" and "Plain". JSX refers to JavaScript code that uses JSX syntax which requires a build step. Plain refers to "classic" JavaScript that does not require building. You can change between them using tabs found above each code example. Using JSX, does require you to run [the JavaScript build step](/docs/how-to-guides/javascript/js-build-setup/) to compile your code to a browser compatible format. diff --git a/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md b/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md index 2cd79198b70b9f..e24231c5cf13a0 100644 --- a/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md +++ b/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md @@ -199,7 +199,7 @@ Use the `editorStyle` property to a CSS file you want to load in the editor view It is worth noting that, if the editor content is iframed, both of these will load in the iframe. `editorStyle` will also load outside the iframe, so it can -be used for editor content as well as UI. +be used for editor content as well as UI. For example: @@ -249,4 +249,4 @@ The files will automatically be enqueued when specified in the block.json. This guide showed a couple of different ways to apply styles to your block, by either inline or in its own style sheet. Both of these methods use the `useBlockProps` hook, see the [block wrapper reference documentation](/docs/reference-guides/block-api/block-edit-save.md#block-wrapper-props) for additional details. -See the complete [example-02-stylesheets](https://github.com/WordPress/gutenberg-examples/tree/trunk/blocks-non-jsx/02-stylesheets) code in the [gutenberg-examples repository](https://github.com/WordPress/gutenberg-examples). +See the complete [stylesheets-79a4c3](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/stylesheets-79a4c3) code in the [block-development-examples repository](https://github.com/WordPress/block-development-examples). diff --git a/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md b/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md index f8d4041c4542e4..b70d1956d681bf 100644 --- a/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md +++ b/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md @@ -221,4 +221,4 @@ registerBlockType( 'gutenberg-examples/example-dynamic', { {% end %} -Note that this code uses the `wp-server-side-render` package but not `wp-data`. Make sure to update the dependencies in the PHP code. You can use wp-scripts to automatically build dependencies (see the [gutenberg-examples repo](https://github.com/WordPress/gutenberg-examples/tree/trunk/blocks-jsx/01-basic-esnext) for PHP code setup). +Note that this code uses the `wp-server-side-render` package but not `wp-data`. Make sure to update the dependencies in the PHP code. You can use wp-scripts to automatically build dependencies (see the [block-development-examples repo](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/basic-esnext-a2ab62) for PHP code setup). diff --git a/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md b/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md index a9dfc0d51a682c..c17045372a65ea 100644 --- a/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md +++ b/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md @@ -207,11 +207,11 @@ When you save the post and view it published, you will see the `Hola mundo (from ## Conclusion -This shows the most basic static block. The [gutenberg-examples](https://github.com/WordPress/gutenberg-examples) repository has complete examples for both. +This shows the most basic static block. The [block-development-examples](https://github.com/WordPress/block-development-examples) repository has complete examples for both. -- [Basic Example with JSX build](https://github.com/WordPress/gutenberg-examples/tree/trunk/blocks-jsx/01-basic-esnext) +- [Basic Example with JSX build](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/basic-esnext-a2ab62) -- [Basic Example Plain JavaScript](https://github.com/WordPress/gutenberg-examples/tree/trunk/blocks-non-jsx/01-basic), +- [Basic Example Plain JavaScript](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/minimal-block-no-build-e621a6), **NOTE:** The examples include a more complete block setup with translation features included, it is recommended to follow those examples for a production block. The internationalization features were left out of this guide for simplicity and focusing on the very basics of a block. @@ -219,7 +219,7 @@ This shows the most basic static block. The [gutenberg-examples](https://github. A couple of things to note when creating your blocks: -- A block name must be prefixed with a namespace specific to your plugin. This helps prevent conflicts when more than one plugin registers a block with the same name. In this example, the namespace is `gutenberg-examples`. +- A block name must be prefixed with a namespace specific to your plugin. This helps prevent conflicts when more than one plugin registers a block with the same name. In this example, the namespace is `block-development-examples`. - Block names _must_ include only lowercase alphanumeric characters or dashes and start with a letter. Example: `my-plugin/my-custom-block`. diff --git a/docs/how-to-guides/data-basics/1-data-basics-setup.md b/docs/how-to-guides/data-basics/1-data-basics-setup.md index 3657b65791a658..e61db83c4ecbd5 100644 --- a/docs/how-to-guides/data-basics/1-data-basics-setup.md +++ b/docs/how-to-guides/data-basics/1-data-basics-setup.md @@ -212,4 +212,4 @@ Congratulations! You are now ready to start building the app! - Previous part: [Introduction](/docs/how-to-guides/data-basics/README.md) - Next part: [Building a basic list of pages](/docs/how-to-guides/data-basics/2-building-a-list-of-pages.md) -- (optional) Review the [finished app](https://github.com/WordPress/gutenberg-examples/tree/trunk/non-block-examples/09-code-data-basics-esnext) in the gutenberg-examples repository +- (optional) Review the [finished app](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) in the block-development-examples repository diff --git a/docs/how-to-guides/data-basics/2-building-a-list-of-pages.md b/docs/how-to-guides/data-basics/2-building-a-list-of-pages.md index aee5575cdb5adb..8a0d172e45f453 100644 --- a/docs/how-to-guides/data-basics/2-building-a-list-of-pages.md +++ b/docs/how-to-guides/data-basics/2-building-a-list-of-pages.md @@ -446,4 +446,4 @@ All that’s left is to refresh the page and enjoy the brand new status indicato * **Previous part:** [Setup](/docs/how-to-guides/data-basics/1-data-basics-setup.md) * **Next part:** [Building an edit form](/docs/how-to-guides/data-basics/3-building-an-edit-form.md) -* (optional) Review the [finished app](https://github.com/WordPress/gutenberg-examples/tree/trunk/non-block-examples/09-code-data-basics-esnext) in the gutenberg-examples repository +* (optional) Review the [finished app](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) in the block-development-examples repository diff --git a/docs/how-to-guides/data-basics/3-building-an-edit-form.md b/docs/how-to-guides/data-basics/3-building-an-edit-form.md index 754a31f1bc4921..68c87381701515 100644 --- a/docs/how-to-guides/data-basics/3-building-an-edit-form.md +++ b/docs/how-to-guides/data-basics/3-building-an-edit-form.md @@ -540,4 +540,4 @@ function EditPageForm( { pageId, onCancel, onSaveFinished } ) { * **Previous part:** [Building a list of pages](/docs/how-to-guides/data-basics/2-building-a-list-of-pages.md) * **Next part:** Building a *New Page* form (coming soon) -* (optional) Review the [finished app](https://github.com/WordPress/gutenberg-examples/tree/trunk/non-block-examples/09-code-data-basics-esnext) in the gutenberg-examples repository +* (optional) Review the [finished app](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) in the block-development-examples repository diff --git a/docs/how-to-guides/data-basics/4-building-a-create-page-form.md b/docs/how-to-guides/data-basics/4-building-a-create-page-form.md index 19aada07c2fc78..33c6e9a5ccff5b 100644 --- a/docs/how-to-guides/data-basics/4-building-a-create-page-form.md +++ b/docs/how-to-guides/data-basics/4-building-a-create-page-form.md @@ -389,4 +389,4 @@ All that’s left is to refresh the page and enjoy the form: * **Next part:** [Adding a delete button](/docs/how-to-guides/data-basics/5-adding-a-delete-button.md) * **Previous part:** [Building an edit form](/docs/how-to-guides/data-basics/3-building-an-edit-form.md) -* (optional) Review the [finished app](https://github.com/WordPress/gutenberg-examples/tree/trunk/non-block-examples/09-code-data-basics-esnext) in the gutenberg-examples repository +* (optional) Review the [finished app](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) in the block-development-examples repository diff --git a/docs/how-to-guides/data-basics/5-adding-a-delete-button.md b/docs/how-to-guides/data-basics/5-adding-a-delete-button.md index 07b10ac822c546..e0a0b0d1e93370 100644 --- a/docs/how-to-guides/data-basics/5-adding-a-delete-button.md +++ b/docs/how-to-guides/data-basics/5-adding-a-delete-button.md @@ -446,4 +446,4 @@ function DeletePageButton( { pageId } ) { ## What's next? * **Previous part:** [Building a *Create page form*](/docs/how-to-guides/data-basics/4-building-a-create-page-form.md) -* (optional) Review the [finished app](https://github.com/WordPress/gutenberg-examples/tree/trunk/non-block-examples/09-code-data-basics-esnext) in the gutenberg-examples repository +* (optional) Review the [finished app](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) in the block-development-examples repository diff --git a/docs/how-to-guides/data-basics/README.md b/docs/how-to-guides/data-basics/README.md index 88e901a90e11db..3cb07eae2b6594 100644 --- a/docs/how-to-guides/data-basics/README.md +++ b/docs/how-to-guides/data-basics/README.md @@ -4,7 +4,7 @@ This tutorial aims to get you comfortable with the Gutenberg data layer. It guid ![](https://raw.githubusercontent.com/WordPress/gutenberg/HEAD/docs/how-to-guides/data-basics/media/list-of-pages/part1-finished.jpg) -You may review the [finished app](https://github.com/WordPress/gutenberg-examples/tree/trunk/non-block-examples/09-code-data-basics-esnext) in the gutenberg-examples repository. +You may review the [finished app](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) in the block-development-examples repository. ### Table of Contents diff --git a/docs/how-to-guides/format-api.md b/docs/how-to-guides/format-api.md index a23293bbb27e3f..00e1b82675c006 100644 --- a/docs/how-to-guides/format-api.md +++ b/docs/how-to-guides/format-api.md @@ -18,7 +18,7 @@ You will need: - A minimal plugin activated and setup ready to edit - JavaScript setup for building and enqueuing -The [complete format-api example](https://github.com/WordPress/gutenberg-examples/tree/trunk/non-block-examples/format-api) is available that you can use as a reference for your setup. +The [complete format-api example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/format-api-f14b86) is available that you can use as a reference for your setup. ## Step-by-step guide @@ -234,4 +234,4 @@ Reference documentation used in this guide: The guide showed you how to add a button to the toolbar and have it apply a format to the selected text. Try it out and see what you can build with it in your next plugin. -Download the [format-api example](https://github.com/WordPress/gutenberg-examples/tree/trunk/non-block-examples/format-api) from the [gutenberg-examples](https://github.com/WordPress/gutenberg-examples) repository. +Download the [format-api example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/format-api-f14b86) from the [block-development-examples](https://github.com/WordPress/block-development-examples) repository. diff --git a/docs/how-to-guides/javascript/js-build-setup.md b/docs/how-to-guides/javascript/js-build-setup.md index b915f4dd444f90..cf49154b590a96 100644 --- a/docs/how-to-guides/javascript/js-build-setup.md +++ b/docs/how-to-guides/javascript/js-build-setup.md @@ -22,7 +22,7 @@ The [@wordpress/scripts](https://www.npmjs.com/package/@wordpress/scripts) packa ## Quick Start -If you prefer a quick start, you can use one of the examples from the [Gutenberg Examples repository](https://github.com/wordpress/gutenberg-examples/) and skip below. Each one of the `-esnext` directories in the examples repository contain the necessary files for working with ESNext and JSX. +If you prefer a quick start, you can use one of the examples from the [Block Development Examples repository](https://github.com/wordpress/block-development-examples/) and skip below. Each one of the `-esnext` directories in the examples repository contain the necessary files for working with ESNext and JSX. ## Setup @@ -168,7 +168,7 @@ wp_register_script( ); ``` -See [ESNext blocks in gutenberg-examples repo](https://github.com/WordPress/gutenberg-examples) for full examples. +See [blocks in the block-development-examples repo](https://github.com/WordPress/block-development-examples) for full examples. ## Summary diff --git a/docs/how-to-guides/metabox.md b/docs/how-to-guides/metabox.md index 7a8686968d2cf2..e0402b1180c1c3 100644 --- a/docs/how-to-guides/metabox.md +++ b/docs/how-to-guides/metabox.md @@ -26,7 +26,7 @@ You will need: - A minimal plugin activated and ready to edit - JavaScript setup for building and enqueuing -A [complete meta-block example](https://github.com/WordPress/gutenberg-examples/tree/trunk/blocks-jsx/meta-block) is available that you can use as a reference for your setup. +A [complete meta-block example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/meta-block-bb1e55) is available that you can use as a reference for your setup. ## Step-by-step guide diff --git a/docs/how-to-guides/plugin-sidebar-0.md b/docs/how-to-guides/plugin-sidebar-0.md index 9543eaf8761549..bf084680c3d1b7 100644 --- a/docs/how-to-guides/plugin-sidebar-0.md +++ b/docs/how-to-guides/plugin-sidebar-0.md @@ -379,7 +379,7 @@ Functions used in this guide: You now have a custom sidebar that you can use to update `post_meta` content. -A complete example is available, download the [plugin-sidebar example](https://github.com/WordPress/gutenberg-examples/tree/trunk/blocks-non-jsx/plugin-sidebar) from the [gutenberg-examples](https://github.com/WordPress/gutenberg-examples) repository. +A complete example is available, download the [plugin-sidebar example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/plugin-sidebar-9ee4a6) from the [block-development-examples](https://github.com/WordPress/block-development-examples) repository. ### Note @@ -407,4 +407,4 @@ return el( TextControl, { document.querySelector( {the-value-textarea} ).innerHTML = content; }, } ); -``` \ No newline at end of file +``` From b827bed9a850d318f84d7ab114fc999e1c0489c5 Mon Sep 17 00:00:00 2001 From: Ryan Welcher Date: Fri, 17 Nov 2023 08:27:03 -0500 Subject: [PATCH 071/116] Remove all {% codetabs %} instances and any vanilla JS references. (#56121) --- .../applying-styles-with-stylesheets.md | 100 ------- .../block-controls-toolbar-and-sidebar.md | 92 ------- .../block-supports-in-static-blocks.md | 61 ----- .../block-tutorial/creating-dynamic-blocks.md | 81 +----- ...roducing-attributes-and-editable-fields.md | 61 ----- .../nested-blocks-inner-blocks.md | 161 +----------- .../writing-your-first-block-type.md | 60 +---- docs/how-to-guides/internationalization.md | 30 --- docs/how-to-guides/themes/theme-json.md | 72 ++--- .../block-api/block-attributes.md | 18 +- .../block-api/block-deprecation.md | 135 ---------- .../block-api/block-edit-save.md | 248 ------------------ .../filters/autocomplete-filters.md | 48 +--- .../reference-guides/filters/block-filters.md | 102 ------- docs/reference-guides/richtext.md | 43 +-- .../src/components/editable-text/README.md | 36 --- .../src/components/plain-text/README.md | 28 -- .../src/components/rich-text/README.md | 58 ---- .../src/components/url-input/README.md | 73 ------ 19 files changed, 35 insertions(+), 1472 deletions(-) diff --git a/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md b/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md index e24231c5cf13a0..697984c9456e02 100644 --- a/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md +++ b/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md @@ -18,9 +18,6 @@ The first method shows adding the style inline. This transforms the defined styl The `useBlockProps` React hook is used to set and apply properties on the block's wrapper element. The following example shows how: -{% codetabs %} -{% JSX %} - ```jsx import { registerBlockType } from '@wordpress/blocks'; import { useBlockProps } from '@wordpress/block-editor'; @@ -55,49 +52,6 @@ registerBlockType( 'gutenberg-examples/example-02-stylesheets', { } ); ``` -{% Plain %} - -```js -( function ( blocks, React, blockEditor ) { - var el = React.createElement; - - blocks.registerBlockType( 'gutenberg-examples/example-02-stylesheets', { - edit: function ( props ) { - const greenBackground = { - backgroundColor: '#090', - color: '#fff', - padding: '20px', - }; - const blockProps = blockEditor.useBlockProps( { - style: greenBackground, - } ); - return el( - 'p', - blockProps, - 'Hello World (from the editor, in green).' - ); - }, - save: function () { - const redBackground = { - backgroundColor: '#090', - color: '#fff', - padding: '20px', - }; - const blockProps = blockEditor.useBlockProps.save( { - style: redBackground, - } ); - return el( - 'p', - blockProps, - 'Hello World (from the frontend, in red).' - ); - }, - } ); -} )( window.wp.blocks, window.React, window.wp.blockEditor ); -``` - -{% end %} - ## Method 2: Block classname The inline style works well for a small amount of CSS to apply. If you have much more than the above you will likely find that it is easier to manage with them in a separate stylesheet file. @@ -106,9 +60,6 @@ The `useBlockProps` hooks includes the classname for the block automatically, it For example the block name: `gutenberg-examples/example-02-stylesheets` would get the classname: `wp-block-gutenberg-examples-example-02-stylesheets`. It might be a bit long but best to avoid conflicts with other blocks. -{% codetabs %} -{% JSX %} - ```jsx import { registerBlockType } from '@wordpress/blocks'; import { useBlockProps } from '@wordpress/block-editor'; @@ -131,66 +82,15 @@ registerBlockType( 'gutenberg-examples/example-02-stylesheets', { } ); ``` -{% Plain %} - -```js -( function ( blocks, React, blockEditor ) { - var el = React.createElement; - - blocks.registerBlockType( 'gutenberg-examples/example-02-stylesheets', { - edit: function ( props ) { - var blockProps = blockEditor.useBlockProps(); - return el( - 'p', - blockProps, - 'Hello World (from the editor, in green).' - ); - }, - save: function () { - var blockProps = blockEditor.useBlockProps.save(); - return el( - 'p', - blockProps, - 'Hello World (from the frontend, in red).' - ); - }, - } ); -} )( window.wp.blocks, window.React, window.wp.blockEditor ); -``` - -{% end %} - ### Build or add dependency In order to include the blockEditor as a dependency, make sure to run the build step, or update the asset php file. -{% codetabs %} -{% JSX %} - Build the scripts and update the asset file which is used to keep track of dependencies and the build version. ```bash npm run build ``` -{% Plain %} - -Edit the asset file to include the block-editor dependency for the scripts. - -```php - - array( - 'react', - 'wp-blocks', - 'wp-block-editor', - 'wp-polyfill' - ), - 'version' => '0.1' - ); -``` - -{% end %} - ### Enqueue stylesheets Like scripts, you can enqueue your block's styles using the `block.json` file. diff --git a/docs/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar.md b/docs/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar.md index 1b3a54592b9967..4436696b552619 100644 --- a/docs/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar.md +++ b/docs/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar.md @@ -10,9 +10,6 @@ When the user selects a block, a number of control buttons may be shown in a too You can also customize the toolbar to include controls specific to your block type. If the return value of your block type's `edit` function includes a `BlockControls` element, those controls will be shown in the selected block's toolbar. -{% codetabs %} -{% JSX %} - ```jsx import { registerBlockType } from '@wordpress/blocks'; @@ -92,95 +89,6 @@ registerBlockType( 'gutenberg-examples/example-04-controls-esnext', { } ); ``` -{% Plain %} - -```js -( function ( blocks, blockEditor, React ) { - var el = React.createElement; - var RichText = blockEditor.RichText; - var AlignmentToolbar = blockEditor.AlignmentToolbar; - var BlockControls = blockEditor.BlockControls; - var useBlockProps = blockEditor.useBlockProps; - - blocks.registerBlockType( 'gutenberg-examples/example-04-controls', { - title: 'Example: Controls', - icon: 'universal-access-alt', - category: 'design', - - attributes: { - content: { - type: 'string', - source: 'html', - selector: 'p', - }, - alignment: { - type: 'string', - default: 'none', - }, - }, - example: { - attributes: { - content: 'Hello World', - alignment: 'right', - }, - }, - edit: function ( props ) { - var content = props.attributes.content; - var alignment = props.attributes.alignment; - - function onChangeContent( newContent ) { - props.setAttributes( { content: newContent } ); - } - - function onChangeAlignment( newAlignment ) { - props.setAttributes( { - alignment: - newAlignment === undefined ? 'none' : newAlignment, - } ); - } - - return el( - 'div', - useBlockProps(), - el( - BlockControls, - { key: 'controls' }, - el( AlignmentToolbar, { - value: alignment, - onChange: onChangeAlignment, - } ) - ), - el( RichText, { - key: 'richtext', - tagName: 'p', - style: { textAlign: alignment }, - onChange: onChangeContent, - value: content, - } ) - ); - }, - - save: function ( props ) { - var blockProps = useBlockProps.save(); - - return el( - 'div', - blockProps, - el( RichText.Content, { - tagName: 'p', - className: - 'gutenberg-examples-align-' + - props.attributes.alignment, - value: props.attributes.content, - } ) - ); - }, - } ); -} )( window.wp.blocks, window.wp.blockEditor, window.React ); -``` - -{% end %} - Note that `BlockControls` is only visible when the block is currently selected and in visual editing mode. `BlockControls` are not shown when editing a block in HTML editing mode. ## Settings Sidebar diff --git a/docs/how-to-guides/block-tutorial/block-supports-in-static-blocks.md b/docs/how-to-guides/block-tutorial/block-supports-in-static-blocks.md index a6350470bb797c..47fa3a86b75eb9 100644 --- a/docs/how-to-guides/block-tutorial/block-supports-in-static-blocks.md +++ b/docs/how-to-guides/block-tutorial/block-supports-in-static-blocks.md @@ -8,8 +8,6 @@ Let's take the block we wrote in the previous chapter (example 3) and with just Here's the exact same code we used to register the block previously. -{% codetabs %} -{% JSX %} ```jsx import { registerBlockType } from '@wordpress/blocks'; @@ -64,65 +62,6 @@ registerBlockType( 'gutenberg-examples/example-03-editable-esnext', { } ); ``` -{% Plain %} - -```js -( function ( blocks, blockEditor, React ) { - var el = React.createElement; - var RichText = blockEditor.RichText; - var useBlockProps = blockEditor.useBlockProps; - - blocks.registerBlockType( 'gutenberg-examples/example-03-editable', { - apiVersion: 3, - title: 'Example: Basic with block supports', - icon: 'universal-access-alt', - category: 'design', - - attributes: { - content: { - type: 'string', - source: 'html', - selector: 'p', - }, - }, - example: { - attributes: { - content: 'Hello World', - }, - }, - edit: function ( props ) { - var blockProps = useBlockProps(); - var content = props.attributes.content; - function onChangeContent( newContent ) { - props.setAttributes( { content: newContent } ); - } - - return el( - RichText, - Object.assign( blockProps, { - tagName: 'p', - onChange: onChangeContent, - value: content, - } ) - ); - }, - - save: function ( props ) { - var blockProps = useBlockProps.save(); - return el( - RichText.Content, - Object.assign( blockProps, { - tagName: 'p', - value: props.attributes.content, - } ) - ); - }, - } ); -} )( window.wp.blocks, window.wp.blockEditor, window.React ); -``` - -{% end %} - Now, let's alter the block.json file for that block, and add the supports key. (If you're not using a block.json file, you can also add the key to the `registerBlockType` function call) ```json diff --git a/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md b/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md index b70d1956d681bf..89ef666abe494f 100644 --- a/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md +++ b/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md @@ -17,8 +17,7 @@ Block attributes can be used for any content or setting you want to save for tha The following code example shows how to create a dynamic block that shows only the last post as a link. -{% codetabs %} -{% JSX %} + ```jsx import { registerBlockType } from '@wordpress/blocks'; @@ -52,47 +51,7 @@ registerBlockType( 'gutenberg-examples/example-dynamic', { } ); ``` -{% Plain %} - -```js -( function ( blocks, React, data, blockEditor ) { - var el = React.createElement, - registerBlockType = blocks.registerBlockType, - useSelect = data.useSelect, - useBlockProps = blockEditor.useBlockProps; - - registerBlockType( 'gutenberg-examples/example-dynamic', { - apiVersion: 3, - title: 'Example: last post', - icon: 'megaphone', - category: 'widgets', - edit: function () { - var content; - var blockProps = useBlockProps(); - var posts = useSelect( function ( select ) { - return select( 'core' ).getEntityRecords( 'postType', 'post' ); - }, [] ); - if ( ! posts ) { - content = 'Loading...'; - } else if ( posts.length === 0 ) { - content = 'No posts'; - } else { - var post = posts[ 0 ]; - content = el( 'a', { href: post.link }, post.title.rendered ); - } - - return el( 'div', blockProps, content ); - }, - } ); -} )( - window.wp.blocks, - window.React, - window.wp.data, - window.wp.blockEditor -); -``` -{% end %} Because it is a dynamic block it doesn't need to override the default `save` implementation on the client. Instead, it needs a server component. The contents in the front of your site depend on the function called by the `render_callback` property of `register_block_type`. @@ -156,8 +115,7 @@ Gutenberg 2.8 added the [``](/packages/server-side-render/READ _Server-side render is meant as a fallback; client-side rendering in JavaScript is always preferred (client rendering is faster and allows better editor manipulation)._ -{% codetabs %} -{% JSX %} + ```jsx import { registerBlockType } from '@wordpress/blocks'; @@ -184,41 +142,6 @@ registerBlockType( 'gutenberg-examples/example-dynamic', { } ); ``` -{% Plain %} - -```js -( function ( blocks, React, serverSideRender, blockEditor ) { - var el = React.createElement, - registerBlockType = blocks.registerBlockType, - ServerSideRender = serverSideRender, - useBlockProps = blockEditor.useBlockProps; - - registerBlockType( 'gutenberg-examples/example-dynamic', { - apiVersion: 3, - title: 'Example: last post', - icon: 'megaphone', - category: 'widgets', - - edit: function ( props ) { - var blockProps = useBlockProps(); - return el( - 'div', - blockProps, - el( ServerSideRender, { - block: 'gutenberg-examples/example-dynamic', - attributes: props.attributes, - } ) - ); - }, - } ); -} )( - window.wp.blocks, - window.React, - window.wp.serverSideRender, - window.wp.blockEditor -); -``` -{% end %} Note that this code uses the `wp-server-side-render` package but not `wp-data`. Make sure to update the dependencies in the PHP code. You can use wp-scripts to automatically build dependencies (see the [block-development-examples repo](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/basic-esnext-a2ab62) for PHP code setup). diff --git a/docs/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields.md b/docs/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields.md index 7586081af4216d..3d8e10cae7ab2a 100644 --- a/docs/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields.md +++ b/docs/how-to-guides/block-tutorial/introducing-attributes-and-editable-fields.md @@ -52,8 +52,6 @@ Because `RichText` allows for nested nodes, you'll most often use it in conjunct Here is the complete block definition for Example 03. -{% codetabs %} -{% JSX %} ```jsx import { registerBlockType } from '@wordpress/blocks'; @@ -107,62 +105,3 @@ registerBlockType( 'gutenberg-examples/example-03-editable-esnext', { }, } ); ``` - -{% Plain %} - -```js -( function ( blocks, blockEditor, React ) { - var el = React.createElement; - var RichText = blockEditor.RichText; - var useBlockProps = blockEditor.useBlockProps; - - blocks.registerBlockType( 'gutenberg-examples/example-03-editable', { - apiVersion: 3, - title: 'Example: Editable', - icon: 'universal-access-alt', - category: 'design', - - attributes: { - content: { - type: 'string', - source: 'html', - selector: 'p', - }, - }, - example: { - attributes: { - content: 'Hello World', - }, - }, - edit: function ( props ) { - var blockProps = useBlockProps(); - var content = props.attributes.content; - function onChangeContent( newContent ) { - props.setAttributes( { content: newContent } ); - } - - return el( - RichText, - Object.assign( blockProps, { - tagName: 'p', - onChange: onChangeContent, - value: content, - } ) - ); - }, - - save: function ( props ) { - var blockProps = useBlockProps.save(); - return el( - RichText.Content, - Object.assign( blockProps, { - tagName: 'p', - value: props.attributes.content, - } ) - ); - }, - } ); -} )( window.wp.blocks, window.wp.blockEditor, window.React ); -``` - -{% end %} diff --git a/docs/how-to-guides/block-tutorial/nested-blocks-inner-blocks.md b/docs/how-to-guides/block-tutorial/nested-blocks-inner-blocks.md index e2c37f341427e5..9dc7f1f324743f 100644 --- a/docs/how-to-guides/block-tutorial/nested-blocks-inner-blocks.md +++ b/docs/how-to-guides/block-tutorial/nested-blocks-inner-blocks.md @@ -6,8 +6,6 @@ Note: A single block can only contain one `InnerBlocks` component. Here is the basic InnerBlocks usage. -{% codetabs %} -{% JSX %} ```js import { registerBlockType } from '@wordpress/blocks'; @@ -38,35 +36,6 @@ registerBlockType( 'gutenberg-examples/example-06', { } ); ``` -{% Plain %} - -```js -( function ( blocks, React, blockEditor ) { - var el = React.createElement; - var InnerBlocks = blockEditor.InnerBlocks; - var useBlockProps = blockEditor.useBlockProps; - - blocks.registerBlockType( 'gutenberg-examples/example-06', { - title: 'Example: Inner Blocks', - category: 'design', - - edit: function () { - var blockProps = useBlockProps(); - - return el( 'div', blockProps, el( InnerBlocks ) ); - }, - - save: function () { - var blockProps = useBlockProps.save(); - - return el( 'div', blockProps, el( InnerBlocks.Content ) ); - }, - } ); -} )( window.wp.blocks, window.React, window.wp.blockEditor ); -``` - -{% end %} - ## Allowed Blocks Using the `allowedBlocks` property, you can define the set of blocks allowed in your InnerBlock. This restricts the blocks that can be included only to those listed, all other blocks will not show in the inserter. @@ -101,8 +70,6 @@ By default this behavior is disabled until the `directInsert` prop is set to `tr Use the template property to define a set of blocks that prefill the InnerBlocks component when inserted. You can set attributes on the blocks to define their use. The example below shows a book review template using InnerBlocks component and setting placeholders values to show the block usage. -{% codetabs %} -{% JSX %} ```js const MY_TEMPLATE = [ @@ -123,29 +90,6 @@ const MY_TEMPLATE = [ }, ``` -{% Plain %} - -```js -const MY_TEMPLATE = [ - [ 'core/image', {} ], - [ 'core/heading', { placeholder: 'Book Title' } ], - [ 'core/paragraph', { placeholder: 'Summary' } ], -]; - -//... - - edit: function( props ) { - return el( - InnerBlocks, - { - template: MY_TEMPLATE, - templateLock: "all", - } - ); - }, -``` - -{% end %} Use the `templateLock` property to lock down the template. Using `all` locks the template completely so no changes can be made. Using `insert` prevents additional blocks from being inserted, but existing blocks can be reordered. See [templateLock documentation](https://github.com/WordPress/gutenberg/tree/HEAD/packages/block-editor/src/components/inner-blocks/README.md#templatelock) for additional information. @@ -167,7 +111,7 @@ add_action( 'init', function() { ## Using Parent and Ancestor Relationships in Blocks -A common pattern for using InnerBlocks is to create a custom block that will be only be available if its parent block is inserted. This allows builders to establish a relationship between blocks, while limiting a nested block's discoverability. Currently, there are two relationships builders can use: `parent` and `ancestor`. The differences are: +A common pattern for using InnerBlocks is to create a custom block that will be only be available if its parent block is inserted. This allows builders to establish a relationship between blocks, while limiting a nested block's discoverability. Currently, there are two relationships builders can use: `parent` and `ancestor`. The differences are: - If you assign a `parent` then you’re stating that the nested block can only be used and inserted as a __direct descendant of the parent__. - If you assign an `ancestor` then you’re stating that the nested block can only be used and inserted as a __descendent of the parent__. @@ -214,8 +158,7 @@ The `useInnerBlocksProps` is exported from the `@wordpress/block-editor` package Here is the basic `useInnerBlocksProps` hook usage. -{% codetabs %} -{% JSX %} + ```js import { registerBlockType } from '@wordpress/blocks'; @@ -248,42 +191,9 @@ registerBlockType( 'gutenberg-examples/example-06', { } ); ``` -{% Plain %} - -```js -( function ( blocks, React, blockEditor ) { - var el = React.createElement; - var InnerBlocks = blockEditor.InnerBlocks; - var useBlockProps = blockEditor.useBlockProps; - var useInnerBlocksProps = blockEditor.useInnerBlocksProps; - - blocks.registerBlockType( 'gutenberg-examples/example-06', { - title: 'Example: Inner Blocks', - category: 'design', - - edit: function () { - var blockProps = useBlockProps(); - var innerBlocksProps = useInnerBlocksProps(); - - return el( 'div', blockProps, el( 'div', innerBlocksProps ) ); - }, - - save: function () { - var blockProps = useBlockProps.save(); - var innerBlocksProps = useInnerBlocksProps.save(); - - return el( 'div', blockProps, el( 'div', innerBlocksProps ) ); - }, - } ); -} )( window.wp.blocks, window.React, window.wp.blockEditor ); -``` - -{% end %} - This hook can also pass objects returned from the `useBlockProps` hook to the `useInnerBlocksProps` hook. This reduces the number of elements we need to create. -{% codetabs %} -{% JSX %} + ```js import { registerBlockType } from '@wordpress/blocks'; @@ -312,36 +222,6 @@ registerBlockType( 'gutenberg-examples/example-06', { } ); ``` -{% Plain %} - -```js -( function ( blocks, React, blockEditor ) { - var el = React.createElement; - var InnerBlocks = blockEditor.InnerBlocks; - var useBlockProps = blockEditor.useBlockProps; - var useInnerBlocksProps = blockEditor.useInnerBlocksProps; - - blocks.registerBlockType( 'gutenberg-examples/example-06', { - // ... - - edit: function () { - var blockProps = useBlockProps(); - var innerBlocksProps = useInnerBlocksProps(); - - return el( 'div', innerBlocksProps ); - }, - - save: function () { - var blockProps = useBlockProps.save(); - var innerBlocksProps = useInnerBlocksProps.save(); - - return el( 'div', innerBlocksProps ); - }, - } ); -} )( window.wp.blocks, window.React, window.wp.blockEditor ); -``` - -{% end %} The above code will render to the following markup in the editor: @@ -353,8 +233,6 @@ The above code will render to the following markup in the editor: Another benefit to using the hook approach is using the returned value, which is just an object, and deconstruct to get the react children from the object. This property contains the actual child inner blocks thus we can place elements on the same level as our inner blocks. -{% codetabs %} -{% JSX %} ```js import { registerBlockType } from '@wordpress/blocks'; @@ -379,39 +257,6 @@ registerBlockType( 'gutenberg-examples/example-06', { } ); ``` -{% Plain %} - -```js -( function ( blocks, React, blockEditor ) { - var el = React.createElement; - var InnerBlocks = blockEditor.InnerBlocks; - var useBlockProps = blockEditor.useBlockProps; - var useInnerBlocksProps = blockEditor.useInnerBlocksProps; - - blocks.registerBlockType( 'gutenberg-examples/example-06', { - // ... - - edit: function () { - var blockProps = useBlockProps(); - var { children, ...innerBlocksProps } = useInnerBlocksProps( blockProps ); - - return el( - 'div', - innerBlocksProps, - children, - el( - 'div', - {}, - '', - ) - ); - }, - // ... - } ); -} )( window.wp.blocks, window.React, window.wp.blockEditor ); -``` - -{% end %} ```html
diff --git a/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md b/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md index c17045372a65ea..4a690984011e0f 100644 --- a/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md +++ b/docs/how-to-guides/block-tutorial/writing-your-first-block-type.md @@ -64,8 +64,6 @@ The `block.json` file should be added to your plugin. To start a new plugin, cre Create a basic `block.json` file there: -{% codetabs %} -{% JSX %} ```json { @@ -77,22 +75,6 @@ Create a basic `block.json` file there: "editorScript": "file:./build/index.js" } ``` - -{% Plain %} - -```json -{ - "apiVersion": 3, - "title": "Example: Basic", - "name": "gutenberg-examples/example-01-basic", - "category": "layout", - "icon": "universal-access-alt", - "editorScript": "file:./block.js" -} -``` - -{% end %} - ### Step 2: Register block in plugin With the `block.json` in place, the registration for the block is a single function call in PHP, this will setup the block and JavaScript file specified in the `editorScript` property to load in the editor. @@ -118,8 +100,6 @@ The `edit` function is a component that is shown in the editor when the block is The `save` function is a component that defines the final markup returned by the block and saved in `post_content`. -{% codetabs %} -{% JSX %} Add the following in `src/index.js` @@ -140,33 +120,12 @@ registerBlockType( 'gutenberg-examples/example-01-basic-esnext', { } ); ``` -{% Plain %} - -Add the following to `block.js` - -```js -( function ( blocks, React ) { - var el = React.createElement; - - blocks.registerBlockType( 'gutenberg-examples/example-01-basic', { - edit: function () { - return el( 'p', {}, 'Hello World (from the editor).' ); - }, - save: function () { - return el( 'p', {}, 'Hola mundo (from the frontend).' ); - }, - } ); -} )( window.wp.blocks, window.React ); -``` - -{% end %} ### Step 4: Build or add dependency In order to register the block, an asset php file is required in the same directory as the directory used in `register_block_type()` and must begin with the script's filename. -{% codetabs %} -{% JSX %} + Build the scripts and asset file which is used to keep track of dependencies and the build version. @@ -174,23 +133,6 @@ Build the scripts and asset file which is used to keep track of dependencies and npm run build ``` -{% Plain %} - -Create the asset file to load the dependencies for the scripts. The name of this file should be the name of the js file then .asset.php. For this example, create `block.asset.php` with the following: - -```php - - array( - 'react', - 'wp-blocks', - 'wp-polyfill' - ), - 'version' => '0.1' - ); -``` - -{% end %} ### Step 5: Confirm diff --git a/docs/how-to-guides/internationalization.md b/docs/how-to-guides/internationalization.md index c3194f309fca63..08ce46edb3f581 100644 --- a/docs/how-to-guides/internationalization.md +++ b/docs/how-to-guides/internationalization.md @@ -37,9 +37,6 @@ add_action( 'init', 'myguten_block_init' ); In your code, you can include the i18n functions. The most common function is **\_\_** (a double underscore) which provides translation of a simple string. Here is a basic block example: -{% codetabs %} -{% JSX %} - ```js import { __ } from '@wordpress/i18n'; import { registerBlockType } from '@wordpress/blocks'; @@ -64,33 +61,6 @@ registerBlockType( 'myguten/simple', { } ); ``` -{% Plain %} - -```js -const el = React.createElement; -const { __ } = wp.i18n; -const { registerBlockType } = wp.blocks; -const { useBlockProps } = wp.blockEditor; - -registerBlockType( 'myguten/simple', { - title: __( 'Simple Block', 'myguten' ), - category: 'widgets', - - edit: function () { - const blockProps = useBlockProps( { style: { color: 'red' } } ); - - return el( 'p', blockProps, __( 'Hello World', 'myguten' ) ); - }, - - save: function () { - const blockProps = useBlockProps.save( { style: { color: 'red' } } ); - return el( 'p', blockProps, __( 'Hello World', 'myguten' ) ); - }, -} ); -``` - -{% end %} - In the above example, the function will use the first argument for the string to be translated. The second argument is the text domain which must match the text domain slug specified by your plugin. Common functions available, these mirror their PHP counterparts are: diff --git a/docs/how-to-guides/themes/theme-json.md b/docs/how-to-guides/themes/theme-json.md index 024564b7c9eaeb..2a1161827c1369 100644 --- a/docs/how-to-guides/themes/theme-json.md +++ b/docs/how-to-guides/themes/theme-json.md @@ -69,8 +69,7 @@ To address this need, we've started to experiment with CSS Custom Properties, ak - **Presets**: [color palettes](/docs/how-to-guides/themes/theme-support.md#block-color-palettes), [font sizes](/docs/how-to-guides/themes/theme-support.md#block-font-sizes), or [gradients](/docs/how-to-guides/themes/theme-support.md#block-gradient-presets) declared by the theme are converted to CSS Custom Properties and enqueued both the front-end and the editors. -{% codetabs %} -{% Input %} +#### Input ```json { @@ -94,7 +93,7 @@ To address this need, we've started to experiment with CSS Custom Properties, ak } ``` -{% Output %} +#### Output ```css body { @@ -103,12 +102,10 @@ body { } ``` -{% end %} - - **Custom properties**: there's also a mechanism to create your own CSS Custom Properties. -{% codetabs %} -{% Input %} + +#### Input ```json { @@ -124,7 +121,7 @@ body { } ``` -{% Output %} +#### Output ```css body { @@ -133,8 +130,6 @@ body { } ``` -{% end %} - ## Specification This specification is the same for the three different origins that use this format: core, themes, and users. Themes can override core's defaults by creating a file called `theme.json`. Users, via the site editor, will also be able to override theme's or core's preferences via an user interface that is being worked on. @@ -166,8 +161,8 @@ The tabs below show WordPress 5.8 supported settings and the ones supported by t The settings section has the following structure: -{% codetabs %} -{% WordPress %} + +#### WordPress ```json { @@ -231,7 +226,7 @@ The settings section has the following structure: } ``` -{% Gutenberg %} +#### Gutenberg ```json { @@ -310,8 +305,6 @@ The settings section has the following structure: } ``` -{% end %} - Each block can configure any of these settings separately, providing a more fine-grained control over what exists via `add_theme_support`. The settings declared at the top-level affect to all blocks, unless a particular block overwrites it. It's a way to provide inheritance and configure all blocks at once. Note, however, that not all settings are relevant for all blocks. The settings section provides an opt-in/opt-out mechanism for themes, but it's the block's responsibility to add support for the features that are relevant to it. For example, if a block doesn't implement the `dropCap` feature, a theme can't enable it for such a block through `theme.json`. @@ -376,8 +369,8 @@ The naming schema for the classes and the custom properties is as follows: - Custom Properties: `--wp--preset--{preset-category}--{preset-slug}` such as `--wp--preset--color--black` - Classes: `.has-{preset-slug}-{preset-category}` such as `.has-black-color`. -{% codetabs %} -{% Input %} + +#### Input ```json { @@ -490,7 +483,7 @@ The naming schema for the classes and the custom properties is as follows: } ``` -{% Output %} +#### Output ```css /* Top-level custom properties */ @@ -540,8 +533,6 @@ body { ``` -{% end %} - To maintain backward compatibility, the presets declared via `add_theme_support` will also generate the CSS Custom Properties. If the `theme.json` contains any presets, these will take precedence over the ones declared via `add_theme_support`. Preset classes are attached to the content of a post by some user action. That's why the engine will add `!important` to these, because user styles should take precedence over theme styles. @@ -552,8 +543,7 @@ In addition to create CSS Custom Properties for the presets, the `theme.json` al For example: -{% codetabs %} -{% Input %} +#### Input ```json { @@ -578,7 +568,7 @@ For example: } ``` -{% Output %} +#### Output ```css body { @@ -592,7 +582,6 @@ body { } ``` -{% end %} Note that the name of the variable is created by adding `--` in between each nesting level and `camelCase` fields are transformed to `kebab-case`. @@ -702,9 +691,9 @@ The tabs below show WordPress 5.8 supported styles and the ones supported by the Each block declares which style properties it exposes via the [block supports mechanism](/docs/reference-guides/block-api/block-supports.md). The support declarations are used to automatically generate the UI controls for the block in the editor. Themes can use any style property via the `theme.json` for any block ― it's the theme's responsibility to verify that it works properly according to the block markup, etc. -{% codetabs %} -{% WordPress %} + +#### WordPress ```json { @@ -784,7 +773,7 @@ Each block declares which style properties it exposes via the [block supports me } ``` -{% Gutenberg %} +#### Gutenberg ```json { @@ -873,14 +862,11 @@ Each block declares which style properties it exposes via the [block supports me } ``` -{% end %} - ### Top-level styles Styles found at the top-level will be enqueued using the `body` selector. -{% codetabs %} -{% Input %} +#### Input ```json { @@ -893,7 +879,7 @@ Styles found at the top-level will be enqueued using the `body` selector. } ``` -{% Output %} +#### Output ```css body { @@ -901,7 +887,6 @@ body { } ``` -{% end %} ### Block styles @@ -909,8 +894,7 @@ Styles found within a block will be enqueued using the block selector. By default, the block selector is generated based on its name such as `.wp-block-`. For example, `.wp-block-group` for the `core/group` block. There are some blocks that want to opt-out from this default behavior. They can do so by explicitly telling the system which selector to use for them via the `__experimentalSelector` key within the `supports` section of its `block.json` file. Note that the block needs to be registered server-side for the `__experimentalSelector` field to be available to the style engine. -{% codetabs %} -{% Input %} +#### Input ```json { @@ -935,7 +919,7 @@ By default, the block selector is generated based on its name such as `.wp-block } ``` -{% Output %} +#### Output ```css body { @@ -949,7 +933,6 @@ p { /* The core/paragraph opts out from the default behaviour and uses p as a se } ``` -{% end %} #### Referencing a style @@ -996,8 +979,8 @@ Supported by WordPress: If they're found in the top-level the element selector will be used. If they're found within a block, the selector to be used will be the element's appended to the corresponding block. -{% codetabs %} -{% Input %} + +#### Input ```json { @@ -1043,7 +1026,7 @@ If they're found in the top-level the element selector will be used. If they're } ``` -{% Output %} +#### Output ```css body { @@ -1066,8 +1049,6 @@ h3 { } ``` -{% end %} - ##### Element pseudo selectors Pseudo selectors `:hover`, `:focus`, `:visited`, `:active`, `:link`, `:any-link` are supported by Gutenberg. @@ -1236,8 +1217,8 @@ This is for clarity, but also because we want a mechanism to parse back a variab For example: -{% codetabs %} -{% Input %} + +#### Input ```json { @@ -1253,7 +1234,7 @@ For example: } ``` -{% Output %} +#### Output ```css body { @@ -1262,7 +1243,6 @@ body { } ``` -{% end %} A few notes about this process: diff --git a/docs/reference-guides/block-api/block-attributes.md b/docs/reference-guides/block-api/block-attributes.md index 765d69584a6690..35ec1c1e7c64e4 100644 --- a/docs/reference-guides/block-api/block-attributes.md +++ b/docs/reference-guides/block-api/block-attributes.md @@ -375,7 +375,7 @@ Attribute definition: From here, meta attributes can be read and written by a block using the same interface as any attribute: -{% codetabs %} + {% JSX %} ```js @@ -388,22 +388,6 @@ edit( { attributes, setAttributes } ) { }, ``` -{% Plain %} - -```js -edit: function( props ) { - function onChange( event ) { - props.setAttributes( { author: event.target.value } ); - } - - return el( 'input', { - value: props.attributes.author, - onChange: onChange, - } ); -}, -``` - -{% end %} #### Considerations diff --git a/docs/reference-guides/block-api/block-deprecation.md b/docs/reference-guides/block-api/block-deprecation.md index a1497ec346936d..4d69d9d46843cd 100644 --- a/docs/reference-guides/block-api/block-deprecation.md +++ b/docs/reference-guides/block-api/block-deprecation.md @@ -61,9 +61,6 @@ It's important to note that attributes, supports, and ### Example: -{% codetabs %} -{% JSX %} - ```js const { registerBlockType } = wp.blocks; const attributes = { @@ -101,46 +98,6 @@ registerBlockType( 'gutenberg/block-with-deprecated-version', { } ); ``` -{% Plain %} - -```js -var el = React.createElement, - registerBlockType = wp.blocks.registerBlockType, - attributes = { - text: { - type: 'string', - default: 'some random value', - }, - }, - supports = { - className: false, - }; - -registerBlockType( 'gutenberg/block-with-deprecated-version', { - // ... other block properties go here - - attributes: attributes, - - supports: supports, - - save: function ( props ) { - return el( 'div', {}, props.attributes.text ); - }, - - deprecated: [ - { - attributes: attributes, - - save: function ( props ) { - return el( 'p', {}, props.attributes.text ); - }, - }, - ], -} ); -``` - -{% end %} - In the example above we updated the markup of the block to use a `div` instead of `p`. ## Changing the attributes set @@ -149,8 +106,6 @@ Sometimes, you need to update the attributes set to rename or modify old attribu ### Example: -{% codetabs %} -{% JSX %} ```js const { registerBlockType } = wp.blocks; @@ -192,50 +147,6 @@ registerBlockType( 'gutenberg/block-with-deprecated-version', { } ); ``` -{% Plain %} - -```js -var el = React.createElement, - registerBlockType = wp.blocks.registerBlockType; - -registerBlockType( 'gutenberg/block-with-deprecated-version', { - // ... other block properties go here - - attributes: { - content: { - type: 'string', - default: 'some random value', - }, - }, - - save: function ( props ) { - return el( 'div', {}, props.attributes.content ); - }, - - deprecated: [ - { - attributes: { - text: { - type: 'string', - default: 'some random value', - }, - }, - - migrate: function ( attributes ) { - return { - content: attributes.text, - }; - }, - - save: function ( props ) { - return el( 'p', {}, props.attributes.text ); - }, - }, - ], -} ); -``` - -{% end %} In the example above we updated the markup of the block to use a `div` instead of `p` and rename the `text` attribute to `content`. @@ -246,9 +157,6 @@ E.g: a block wants to migrate a title attribute to a paragraph innerBlock. ### Example: -{% codetabs %} -{% JSX %} - ```js const { registerBlockType } = wp.blocks; @@ -292,49 +200,6 @@ registerBlockType( 'gutenberg/block-with-deprecated-version', { } ); ``` -{% Plain %} - -```js -var el = React.createElement, - registerBlockType = wp.blocks.registerBlockType; - -registerBlockType( 'gutenberg/block-with-deprecated-version', { - // ... block properties go here - - deprecated: [ - { - attributes: { - title: { - type: 'string', - source: 'html', - selector: 'p', - }, - }, - - migrate: function ( attributes, innerBlocks ) { - const { title, ...restAttributes } = attributes; - - return [ - restAttributes, - [ - createBlock( 'core/paragraph', { - content: attributes.title, - fontSize: 'large', - } ), - ].concat( innerBlocks ), - ]; - }, - - save: function ( props ) { - return el( 'p', {}, props.attributes.title ); - }, - }, - ], -} ); -``` - -{% end %} - In the example above we updated the block to use an inner Paragraph block with a title instead of a title attribute. _Above are example cases of block deprecation. For more, real-world examples, check for deprecations in the [core block library](https://github.com/WordPress/gutenberg/tree/HEAD/packages/block-library/src). Core blocks have been updated across releases and contain simple and complex deprecations._ diff --git a/docs/reference-guides/block-api/block-edit-save.md b/docs/reference-guides/block-api/block-edit-save.md index 35bbd5ae13e1e0..a8b6f9171bdef3 100644 --- a/docs/reference-guides/block-api/block-edit-save.md +++ b/docs/reference-guides/block-api/block-edit-save.md @@ -6,8 +6,6 @@ When registering a block with JavaScript on the client, the `edit` and `save` fu The `edit` function describes the structure of your block in the context of the editor. This represents what the editor will render when the block is used. -{% codetabs %} -{% JSX %} ```jsx import { useBlockProps } from '@wordpress/block-editor'; @@ -26,32 +24,12 @@ const blockSettings = { }; ``` -{% Plain %} - -```js -var blockSettings = { - apiVersion: 3, - - // ... - - edit: function () { - var blockProps = wp.blockEditor.useBlockProps(); - - return React.createElement( 'div', blockProps, 'Your block.' ); - }, -}; -``` - -{% end %} - ### block wrapper props The first thing to notice here is the use of the `useBlockProps` React hook on the block wrapper element. In the example above, the block wrapper renders a "div" in the editor, but in order for the Gutenberg editor to know how to manipulate the block, add any extra classNames that are needed for the block... the block wrapper element should apply props retrieved from the `useBlockProps` react hook call. The block wrapper element should be a native DOM element, like `
` and ``, or a React component that forwards any additional props to native DOM elements. Using a `` or `` component, for instance, would be invalid. If the element wrapper needs any extra custom HTML attributes, these need to be passed as an argument to the `useBlockProps` hook. For example to add a `my-random-classname` className to the wrapper, you can use the following code: -{% codetabs %} -{% JSX %} ```jsx import { useBlockProps } from '@wordpress/block-editor'; @@ -72,25 +50,6 @@ const blockSettings = { }; ``` -{% Plain %} - -```js -var blockSettings = { - apiVersion: 3, - - // ... - - edit: function () { - var blockProps = wp.blockEditor.useBlockProps( { - className: 'my-random-classname', - } ); - - return React.createElement( 'div', blockProps, 'Your block.' ); - }, -}; -``` - -{% end %} ### attributes @@ -100,8 +59,6 @@ The `attributes` property surfaces all the available attributes and their corres In this case, assuming we had defined an attribute of `content` during block registration, we would receive and use that value in our edit function: -{% codetabs %} -{% JSX %} ```js edit: ( { attributes } ) => { @@ -111,21 +68,6 @@ edit: ( { attributes } ) => { }; ``` -{% Plain %} - -```js -edit: function( props ) { - var blockProps = wp.blockEditor.useBlockProps(); - - return React.createElement( - 'div', - blockProps, - props.attributes.content - ); -} -``` - -{% end %} The value of `attributes.content` will be displayed inside the `div` when inserting the block in the editor. @@ -133,8 +75,6 @@ The value of `attributes.content` will be displayed inside the `div` when insert The isSelected property is an boolean that communicates whether the block is currently selected. -{% codetabs %} -{% JSX %} ```jsx edit: ( { attributes, isSelected } ) => { @@ -151,35 +91,10 @@ edit: ( { attributes, isSelected } ) => { }; ``` -{% Plain %} - -```js -edit: function( props ) { - var blockProps = wp.blockEditor.useBlockProps(); - - return React.createElement( - 'div', - blockProps, - [ - 'Your block.', - props.isSelected ? React.createElement( - 'span', - null, - 'Shows only when the block is selected.' - ) - ] - ); -} -``` - -{% end %} - ### setAttributes This function allows the block to update individual attributes based on user interactions. -{% codetabs %} -{% JSX %} ```jsx edit: ( { attributes, setAttributes, isSelected } ) => { @@ -201,40 +116,8 @@ edit: ( { attributes, setAttributes, isSelected } ) => { }; ``` -{% Plain %} - -```js -edit: function( props ) { - var blockProps = wp.blockEditor.useBlockProps(); - - // Simplify access to attributes - let content = props.attributes.content; - let mySetting = props.attributes.mySetting; - - // Toggle a setting when the user clicks the button - let toggleSetting = () => props.setAttributes( { mySetting: ! mySetting } ); - return React.createElement( - 'div', - blockProps, - [ - content, - props.isSelected ? React.createElement( - 'button', - { onClick: toggleSetting }, - 'Toggle setting' - ) : null - ] - ); -}, -``` - -{% end %} - When using attributes that are objects or arrays it's a good idea to copy or clone the attribute prior to updating it: -{% codetabs %} -{% JSX %} - ```js // Good - a new array is created from the old list attribute and a new list item: const { list } = attributes; @@ -249,25 +132,6 @@ const addListItem = ( newListItem ) => { }; ``` -{% Plain %} - -```js -// Good - cloning the old list -var newList = attributes.list.slice(); - -var addListItem = function ( newListItem ) { - setAttributes( { list: newList.concat( [ newListItem ] ) } ); -}; - -// Bad - the list from the existing attribute is modified directly to add the new list item: -var list = attributes.list; -var addListItem = function ( newListItem ) { - list.push( newListItem ); - setAttributes( { list: list } ); -}; -``` - -{% end %} Why do this? In JavaScript, arrays and objects are passed by reference, so this practice ensures changes won't affect other code that might hold references to the same data. Furthermore, the Gutenberg project follows the philosophy of the Redux library that [state should be immutable](https://redux.js.org/faq/immutable-data#what-are-the-benefits-of-immutability)—data should not be changed directly, but instead a new version of the data created containing the changes. @@ -275,8 +139,6 @@ Why do this? In JavaScript, arrays and objects are passed by reference, so this The `save` function defines the way in which the different attributes should be combined into the final markup, which is then serialized into `post_content`. -{% codetabs %} -{% JSX %} ```jsx save: () => { @@ -286,21 +148,6 @@ save: () => { }; ``` -{% Plain %} - -```js -save: function() { - var blockProps = wp.blockEditor.useBlockProps.save(); - - return React.createElement( - 'div', - blockProps, - 'Your block.' - ); -} -``` - -{% end %} For most blocks, the return value of `save` should be an [instance of WordPress Element](/packages/element/README.md) representing how the block is to appear on the front of the site. @@ -326,8 +173,6 @@ Like the `edit` function, when rendering static blocks, it's important to add th As with `edit`, the `save` function also receives an object argument including attributes which can be inserted into the markup. -{% codetabs %} -{% JSX %} ```jsx save: ( { attributes } ) => { @@ -337,21 +182,7 @@ save: ( { attributes } ) => { }; ``` -{% Plain %} -```js -save: function( props ) { - var blockProps = wp.blockEditor.useBlockProps.save(); - - return React.createElement( - 'div', - blockProps, - props.attributes.content - ); -} -``` - -{% end %} When saving your block, you want to save the attributes in the same format specified by the attribute source definition. If no attribute source is specified, the attribute will be saved to the block's comment delimiter. See the [Block Attributes documentation](/docs/reference-guides/block-api/block-attributes.md) for more details. @@ -361,8 +192,6 @@ Here are a couple examples of using attributes, edit, and save all together. For ### Saving Attributes to Child Elements -{% codetabs %} -{% JSX %} ```jsx attributes: { @@ -396,46 +225,6 @@ save: ( { attributes } ) => { }, ``` -{% Plain %} - -```js -attributes: { - content: { - type: 'string', - source: 'html', - selector: 'p' - } -}, - -edit: function( props ) { - var blockProps = wp.blockEditor.useBlockProps(); - var updateFieldValue = function( val ) { - props.setAttributes( { content: val } ); - } - - return React.createElement( - 'div', - blockProps, - React.createElement( - wp.components.TextControl, - { - label: 'My Text Field', - value: props.attributes.content, - onChange: updateFieldValue, - - } - ) - ); -}, - -save: function( props ) { - var blockProps = wp.blockEditor.useBlockProps.save(); - - return React.createElement( 'div', blockProps, props.attributes.content ); -}, -``` - -{% end %} ### Saving Attributes via Serialization @@ -443,8 +232,6 @@ Ideally, the attributes saved should be included in the markup. However, there a This example could be for a dynamic block, such as the [Latest Posts block](https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-library/src/latest-posts/index.js), which renders the markup server-side. The save function is still required, however in this case it simply returns null since the block is not saving content from the editor. -{% codetabs %} -{% JSX %} ```jsx attributes: { @@ -474,41 +261,6 @@ save: () => { } ``` -{% Plain %} - -```js -attributes: { - postsToShow: { - type: 'number', - } -}, - -edit: function( props ) { - var blockProps = wp.blockEditor.useBlockProps(); - - return React.createEleement( - 'div', - blockProps, - React.createElement( - wp.components.TextControl, - { - label: 'Number Posts to Show', - value: props.attributes.postsToShow, - onChange: function( val ) { - props.setAttributes( { postsToShow: parseInt( val ) } ); - }, - } - ) - ); -}, - -save: function() { - return null; -} -``` - -{% end %} - ## Validation When the editor loads, all blocks within post content are validated to determine their accuracy in order to protect against content loss. This is closely related to the saving implementation of a block, as a user may unintentionally remove or modify their content if the editor is unable to restore a block correctly. During editor initialization, the saved markup for each block is regenerated using the attributes that were parsed from the post's content. If the newly-generated markup does not match what was already stored in post content, the block is marked as invalid. This is because we assume that unless the user makes edits, the markup should remain identical to the saved content. diff --git a/docs/reference-guides/filters/autocomplete-filters.md b/docs/reference-guides/filters/autocomplete-filters.md index 1ce47219529181..85581f62e4af01 100644 --- a/docs/reference-guides/filters/autocomplete-filters.md +++ b/docs/reference-guides/filters/autocomplete-filters.md @@ -8,8 +8,7 @@ The `Autocomplete` component found in `@wordpress/block-editor` applies this fil Here is an example of using the `editor.Autocomplete.completers` filter to add an acronym completer. You can find full documentation for the autocompleter interface with the `Autocomplete` component in the `@wordpress/components` package. -{% codetabs %} -{% JSX %} + ```jsx // Our completer @@ -45,48 +44,3 @@ wp.hooks.addFilter( appendAcronymCompleter ); ``` - -{% Plain %} - -```js -// Our completer -var acronymCompleter = { - name: 'acronyms', - triggerPrefix: '::', - options: [ - { letters: 'FYI', expansion: 'For Your Information' }, - { letters: 'AFAIK', expansion: 'As Far As I Know' }, - { letters: 'IIRC', expansion: 'If I Recall Correctly' }, - ], - getOptionKeywords: function ( abbr ) { - var expansionWords = abbr.expansion.split( /\s+/ ); - return [ abbr.letters ].concat( expansionWords ); - }, - getOptionLabel: function ( acronym ) { - return acronym.letters; - }, - getOptionCompletion: function ( abbr ) { - return React.createElement( - 'abbr', - { title: abbr.expansion }, - abbr.letters - ); - }, -}; - -// Our filter function -function appendAcronymCompleter( completers, blockName ) { - return blockName === 'my-plugin/foo' - ? completers.concat( acronymCompleter ) - : completers; -} - -// Adding the filter -wp.hooks.addFilter( - 'editor.Autocomplete.completers', - 'my-plugin/autocompleters/acronyms', - appendAcronymCompleter -); -``` - -{% end %} diff --git a/docs/reference-guides/filters/block-filters.md b/docs/reference-guides/filters/block-filters.md index 912403c4838941..e269ba9ef19917 100644 --- a/docs/reference-guides/filters/block-filters.md +++ b/docs/reference-guides/filters/block-filters.md @@ -179,8 +179,6 @@ Used to modify the block's `edit` component. It receives the original block `Blo _Example:_ -{% codetabs %} -{% JSX %} ```js const { createHigherOrderComponent } = wp.compose; @@ -207,36 +205,6 @@ wp.hooks.addFilter( ); ``` -{% Plain %} - -```js -var el = React.createElement; - -var withMyPluginControls = wp.compose.createHigherOrderComponent( function ( - BlockEdit -) { - return function ( props ) { - return el( - React.Fragment, - {}, - el( BlockEdit, props ), - el( - wp.blockEditor.InspectorControls, - {}, - el( wp.components.PanelBody, {}, 'My custom control' ) - ) - ); - }; -}, 'withMyPluginControls' ); - -wp.hooks.addFilter( - 'editor.BlockEdit', - 'my-plugin/with-inspector-controls', - withMyPluginControls -); -``` - -{% end %} Note that as this hook is run for _all blocks_, consuming it has potential for performance regressions particularly around block selection metrics. @@ -267,9 +235,6 @@ Used to modify the block's wrapper component containing the block's `edit` compo _Example:_ -{% codetabs %} -{% JSX %} - ```js const { createHigherOrderComponent } = wp.compose; @@ -294,39 +259,10 @@ wp.hooks.addFilter( ); ``` -{% Plain %} - -```js -var el = React.createElement; - -var withClientIdClassName = wp.compose.createHigherOrderComponent( function ( - BlockListBlock -) { - return function ( props ) { - var newProps = { - ...props, - className: 'block-' + props.clientId, - }; - - return el( BlockListBlock, newProps ); - }; -}, 'withClientIdClassName' ); - -wp.hooks.addFilter( - 'editor.BlockListBlock', - 'my-plugin/with-client-id-class-name', - withClientIdClassName -); -``` - -{% end %} - Adding new properties to the block's wrapper component can be achieved by adding them to the `wrapperProps` property of the returned component. _Example:_ -{% codetabs %} -{% JSX %} ```js const { createHigherOrderComponent } = wp.compose; @@ -346,32 +282,6 @@ wp.hooks.addFilter( ); ``` -{% Plain %} - -```js -var el = React.createElement; -var hoc = wp.compose.createHigherOrderComponent; - -var withMyWrapperProp = hoc( function ( BlockListBlock ) { - return function ( props ) { - var newProps = { - ...props, - wrapperProps: { - ...props.wrapperProps, - 'data-my-property': 'the-value', - }, - }; - return el( BlockListBlock, newProps ); - }; -}, 'withMyWrapperProp' ); -wp.hooks.addFilter( - 'editor.BlockListBlock', - 'my-plugin/with-my-wrapper-prop', - withMyWrapperProp -); -``` - -{% end %} ## Removing Blocks @@ -379,8 +289,6 @@ wp.hooks.addFilter( Adding blocks is easy enough, removing them is as easy. Plugin or theme authors have the possibility to "unregister" blocks. -{% codetabs %} -{% JSX %} ```js // my-plugin.js @@ -392,16 +300,6 @@ domReady( function () { } ); ``` -{% Plain %} - -```js -// my-plugin.js -wp.domReady( function () { - wp.blocks.unregisterBlockType( 'core/verse' ); -} ); -``` - -{% end %} and load this script in the Editor diff --git a/docs/reference-guides/richtext.md b/docs/reference-guides/richtext.md index f908c7585bc1b8..1a4509318b72b7 100644 --- a/docs/reference-guides/richtext.md +++ b/docs/reference-guides/richtext.md @@ -25,8 +25,7 @@ There are a number of core blocks using the RichText component. The JavaScript e ## Example -{% codetabs %} -{% JSX %} + ```jsx import { registerBlockType } from '@wordpress/blocks'; @@ -66,46 +65,6 @@ registerBlockType( /* ... */, { } ); ``` -{% Plain %} - -```js -wp.blocks.registerBlockType( /* ... */, { - // ... - - attributes: { - content: { - type: 'string', - source: 'html', - selector: 'h2', - }, - }, - - edit: function( props ) { - var blockProps = wp.blockEditor.useBlockProps(); - - return React.createElement( wp.blockEditor.RichText, Object.assign( blockProps, { - tagName: 'h2', // The tag here is the element output and editable in the admin - value: props.attributes.content, // Any existing content, either from the database or an attribute default - allowedFormats: [ 'core/bold', 'core/italic' ], // Allow the content to be made bold or italic, but do not allow other formatting options - onChange: function( content ) { - props.setAttributes( { content: content } ); // Store updated content as a block attribute - }, - placeholder: __( 'Heading...' ), // Display this text before any content has been added by the user - } ) ); - }, - - save: function( props ) { - var blockProps = wp.blockEditor.useBlockProps.save(); - - return React.createElement( wp.blockEditor.RichText.Content, Object.assign( blockProps, { - tagName: 'h2', value: props.attributes.content // Saves

Content added in the editor...

to the database for frontend display - } ) ); - } -} ); -``` - -{% end %} - ## Common Issues & Solutions While using the RichText component a number of common issues tend to appear. diff --git a/packages/block-editor/src/components/editable-text/README.md b/packages/block-editor/src/components/editable-text/README.md index 86607349ae8176..aa5a2f4b1962b8 100644 --- a/packages/block-editor/src/components/editable-text/README.md +++ b/packages/block-editor/src/components/editable-text/README.md @@ -47,40 +47,6 @@ _Optional._ Called when the block can be removed. `forward` is true when the sel ## Example -{% codetabs %} -{% ES5 %} - -```js -wp.blocks.registerBlockType( /* ... */, { - // ... - - attributes: { - content: { - source: 'html', - selector: 'div', - }, - }, - - edit: function( props ) { - return React.createElement( wp.editor.EditableText, { - className: props.className, - value: props.attributes.content, - onChange: function( content ) { - props.setAttributes( { content: content } ); - } - } ); - }, - - save: function( props ) { - return React.createElement( wp.editor.EditableText.Content, { - value: props.attributes.content - } ); - } -} ); -``` - -{% ESNext %} - ```js const { registerBlockType } = wp.blocks; const { EditableText } = wp.editor; @@ -110,5 +76,3 @@ registerBlockType( /* ... */, { } } ); ``` - -{% end %} diff --git a/packages/block-editor/src/components/plain-text/README.md b/packages/block-editor/src/components/plain-text/README.md index 4e59789fd612c7..aa15758118afdc 100644 --- a/packages/block-editor/src/components/plain-text/README.md +++ b/packages/block-editor/src/components/plain-text/README.md @@ -20,33 +20,6 @@ _Optional._ The component forwards the `ref` property to the `TextareaAutosize` ## Example -{% codetabs %} -{% ES5 %} - -```js -wp.blocks.registerBlockType( /* ... */, { - // ... - - attributes: { - content: { - type: 'string', - }, - }, - - edit: function( props ) { - return React.createElement( wp.blockEditor.PlainText, { - className: props.className, - value: props.attributes.content, - onChange: function( content ) { - props.setAttributes( { content: content } ); - }, - } ); - }, -} ); -``` - -{% ESNext %} - ```js import { registerBlockType } from '@wordpress/blocks'; import { PlainText } from '@wordpress/block-editor'; @@ -72,4 +45,3 @@ registerBlockType( /* ... */, { } ); ``` -{% end %} diff --git a/packages/block-editor/src/components/rich-text/README.md b/packages/block-editor/src/components/rich-text/README.md index d17f987a34cf0e..4251debfa16c54 100644 --- a/packages/block-editor/src/components/rich-text/README.md +++ b/packages/block-editor/src/components/rich-text/README.md @@ -80,41 +80,6 @@ trimmed. ## Example -{% codetabs %} -{% ES5 %} - -```js -wp.blocks.registerBlockType( /* ... */, { - // ... - - attributes: { - content: { - source: 'html', - selector: 'h2', - }, - }, - - edit: function( props ) { - return React.createElement( wp.blockEditor.RichText, { - tagName: 'h2', - className: props.className, - value: props.attributes.content, - onChange: function( content ) { - props.setAttributes( { content: content } ); - } - } ); - }, - - save: function( props ) { - return React.createElement( wp.blockEditor.RichText.Content, { - tagName: 'h2', value: props.attributes.content - } ); - } -} ); -``` - -{% ESNext %} - ```js import { registerBlockType } from '@wordpress/blocks'; import { RichText } from '@wordpress/block-editor'; @@ -146,7 +111,6 @@ registerBlockType( /* ... */, { } ); ``` -{% end %} ## RichTextToolbarButton @@ -154,26 +118,6 @@ Slot to extend the format toolbar. Use it in the edit function of a `registerFor ### Example -{% codetabs %} -{% ES5 %} - -```js -wp.richText.registerFormatType( /* ... */, { - /* ... */ - edit: function( props ) { - return React.createElement( - wp.blockEditor.RichTextToolbarButton, { - icon: 'editor-code', - title: 'My formatting button', - onClick: function() { /* ... */ } - isActive: props.isActive, - } ); - }, - /* ... */ -} ); -``` - -{% ESNext %} ```js import { registerFormatType } from '@wordpress/rich-text'; @@ -194,5 +138,3 @@ registerFormatType( /* ... */, { /* ... */ } ); ``` - -{% end %} diff --git a/packages/block-editor/src/components/url-input/README.md b/packages/block-editor/src/components/url-input/README.md index 46f673ecd35545..b7c48c191cc282 100644 --- a/packages/block-editor/src/components/url-input/README.md +++ b/packages/block-editor/src/components/url-input/README.md @@ -36,41 +36,6 @@ This prop is passed directly to the `URLInput` component. ## Example -{% codetabs %} -{% ES5 %} - -```js -wp.blocks.registerBlockType( /* ... */, { - // ... - - attributes: { - url: { - type: 'string' - }, - text: { - type: 'string' - } - }, - - edit: function( props ) { - return React.createElement( wp.blockEditor.URLInputButton, { - className: props.className, - url: props.attributes.url, - onChange: function( url, post ) { - props.setAttributes( { url: url, text: (post && post.title) || 'Click here' } ); - } - } ); - }, - - save: function( props ) { - return React.createElement( 'a', { - href: props.attributes.url, - }, props.attributes.text ); - } -} ); -``` - -{% ESNext %} ```js import { registerBlockType } from '@wordpress/blocks'; @@ -103,7 +68,6 @@ registerBlockType( /* ... */, { } ); ``` -{% end %} # `URLInput` @@ -172,41 +136,6 @@ Start opting into the new margin-free styles that will become the default in a f ## Example -{% codetabs %} -{% ES5 %} - -```js -wp.blocks.registerBlockType( /* ... */, { - // ... - - attributes: { - url: { - type: 'string' - }, - text: { - type: 'string' - } - }, - - edit: function( props ) { - return React.createElement( wp.blockEditor.URLInput, { - className: props.className, - value: props.attributes.url, - onChange: function( url, post ) { - props.setAttributes( { url: url, text: (post && post.title) || 'Click here' } ); - } - } ); - }, - - save: function( props ) { - return React.createElement( 'a', { - href: props.attributes.url, - }, props.attributes.text ); - } -} ); -``` - -{% ESNext %} ```js import { registerBlockType } from '@wordpress/blocks'; @@ -240,5 +169,3 @@ registerBlockType( /* ... */, { } } ); ``` - -{% end %} From 55285a8c85b3d802b894571fd616fddbdbb6dbbe Mon Sep 17 00:00:00 2001 From: Chad Chadbourne <13856531+chad1008@users.noreply.github.com> Date: Fri, 17 Nov 2023 10:18:58 -0500 Subject: [PATCH 072/116] Tabs: Fix flaky unit tests (#55950) --- packages/components/src/tabs/test/index.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/components/src/tabs/test/index.tsx b/packages/components/src/tabs/test/index.tsx index d2a035e436c194..fac8127c4cc0d8 100644 --- a/packages/components/src/tabs/test/index.tsx +++ b/packages/components/src/tabs/test/index.tsx @@ -524,6 +524,15 @@ describe( 'Tabs', () => { await screen.findByRole( 'tab', { name: 'Alpha' } ) ).toHaveFocus(); + // This assertion ensures the component has had time to fully + // render, preventing flakiness. + // see https://github.com/WordPress/gutenberg/pull/55950 + await waitFor( () => + expect( + screen.getByRole( 'tab', { name: 'Beta' } ) + ).toHaveAttribute( 'tabindex', '-1' ) + ); + // Because all other tabs should have `tabindex=-1`, pressing Tab // should NOT move the focus to the next tab, which is Beta. // Instead, focus should go to the currently selected tabpanel (alpha). @@ -847,6 +856,16 @@ describe( 'Tabs', () => { // onSelect should not be called since the disabled tab is // highlighted, but not selected. await user.keyboard( '[Tab]' ); + + // This assertion ensures focus has time to move to the first + // tab before the test proceeds, preventing flakiness. + // see https://github.com/WordPress/gutenberg/pull/55950 + await waitFor( () => + expect( + screen.getByRole( 'tab', { name: 'Alpha' } ) + ).toHaveFocus() + ); + await user.keyboard( '[ArrowLeft]' ); expect( mockOnSelect ).toHaveBeenCalledTimes( 1 ); From bb8adcd41cea151b3529204249b899c3a53abada Mon Sep 17 00:00:00 2001 From: Chad Chadbourne <13856531+chad1008@users.noreply.github.com> Date: Fri, 17 Nov 2023 11:04:25 -0500 Subject: [PATCH 073/116] Tabs: cleanup and improvements (#56224) --- packages/components/CHANGELOG.md | 4 ++++ packages/components/src/tabs/index.tsx | 14 ++++++++++++-- .../components/src/tabs/stories/index.story.tsx | 8 ++++++++ packages/components/src/tabs/tab.tsx | 8 ++++---- packages/components/src/tabs/tabpanel.tsx | 6 +++--- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index 37ad2a65da28af..eb6e595e304ecf 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Experimental + +- `Tabs`: Memoize and expose the component context ([#56224](https://github.com/WordPress/gutenberg/pull/56224)). + ## 25.12.0 (2023-11-16) ### Bug Fix diff --git a/packages/components/src/tabs/index.tsx b/packages/components/src/tabs/index.tsx index 59eb83f5240590..12dd0b4fcc83f4 100644 --- a/packages/components/src/tabs/index.tsx +++ b/packages/components/src/tabs/index.tsx @@ -8,7 +8,7 @@ import * as Ariakit from '@ariakit/react'; * WordPress dependencies */ import { useInstanceId } from '@wordpress/compose'; -import { useLayoutEffect, useRef } from '@wordpress/element'; +import { useLayoutEffect, useMemo, useRef } from '@wordpress/element'; /** * Internal dependencies @@ -154,8 +154,16 @@ function Tabs( { setSelectedId, ] ); + const contextValue = useMemo( + () => ( { + store, + instanceId, + } ), + [ store, instanceId ] + ); + return ( - + { children } ); @@ -164,4 +172,6 @@ function Tabs( { Tabs.TabList = TabList; Tabs.Tab = Tab; Tabs.TabPanel = TabPanel; +Tabs.Context = TabsContext; + export default Tabs; diff --git a/packages/components/src/tabs/stories/index.story.tsx b/packages/components/src/tabs/stories/index.story.tsx index 08e29589881707..ce8c8324edaee4 100644 --- a/packages/components/src/tabs/stories/index.story.tsx +++ b/packages/components/src/tabs/stories/index.story.tsx @@ -20,6 +20,14 @@ import Button from '../../button'; const meta: Meta< typeof Tabs > = { title: 'Components (Experimental)/Tabs', component: Tabs, + subcomponents: { + // @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170 + 'Tabs.TabList': Tabs.TabList, + // @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170 + 'Tabs.Tab': Tabs.Tab, + // @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170 + 'Tabs.TabPanel': Tabs.TabPanel, + }, parameters: { actions: { argTypesRegex: '^on.*' }, controls: { expanded: true }, diff --git a/packages/components/src/tabs/tab.tsx b/packages/components/src/tabs/tab.tsx index 03e5d80871c56a..4bfc99e8ef43b1 100644 --- a/packages/components/src/tabs/tab.tsx +++ b/packages/components/src/tabs/tab.tsx @@ -2,14 +2,14 @@ * WordPress dependencies */ -import { useContext, forwardRef } from '@wordpress/element'; +import { forwardRef } from '@wordpress/element'; /** * Internal dependencies */ import type { TabProps } from './types'; import warning from '@wordpress/warning'; -import { TabsContext } from './context'; +import { useTabsContext } from './context'; import { Tab as StyledTab } from './styles'; import type { WordPressComponentProps } from '../context'; @@ -17,9 +17,9 @@ export const Tab = forwardRef< HTMLButtonElement, WordPressComponentProps< TabProps, 'button', false > >( function Tab( { children, id, disabled, render, ...otherProps }, ref ) { - const context = useContext( TabsContext ); + const context = useTabsContext(); if ( ! context ) { - warning( '`Tabs.TabList` must be wrapped in a `Tabs` component.' ); + warning( '`Tabs.Tab` must be wrapped in a `Tabs` component.' ); return null; } const { store, instanceId } = context; diff --git a/packages/components/src/tabs/tabpanel.tsx b/packages/components/src/tabs/tabpanel.tsx index f477d1d3b4b437..8e8d72280a4935 100644 --- a/packages/components/src/tabs/tabpanel.tsx +++ b/packages/components/src/tabs/tabpanel.tsx @@ -6,7 +6,7 @@ * WordPress dependencies */ -import { forwardRef, useContext } from '@wordpress/element'; +import { forwardRef } from '@wordpress/element'; /** * Internal dependencies @@ -15,14 +15,14 @@ import type { TabPanelProps } from './types'; import { TabPanel as StyledTabPanel } from './styles'; import warning from '@wordpress/warning'; -import { TabsContext } from './context'; +import { useTabsContext } from './context'; import type { WordPressComponentProps } from '../context'; export const TabPanel = forwardRef< HTMLDivElement, WordPressComponentProps< TabPanelProps, 'div', false > >( function TabPanel( { children, id, focusable = true, ...otherProps }, ref ) { - const context = useContext( TabsContext ); + const context = useTabsContext(); if ( ! context ) { warning( '`Tabs.TabPanel` must be wrapped in a `Tabs` component.' ); return null; From 2969b5910ad2a88c18914db645cb540d1ec0250f Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Sat, 18 Nov 2023 13:36:29 -0500 Subject: [PATCH 074/116] Font Library: remove insecure properties (#56230) * Add additional sanitization to fonts. * Add test case to remove insecure font family. * Format php. --- .../font-library/class-wp-font-family.php | 7 ++- phpunit/class-wp-theme-json-test.php | 46 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/lib/experimental/fonts/font-library/class-wp-font-family.php b/lib/experimental/fonts/font-library/class-wp-font-family.php index a4f55d8c0cece7..309b1c8b7902b5 100644 --- a/lib/experimental/fonts/font-library/class-wp-font-family.php +++ b/lib/experimental/fonts/font-library/class-wp-font-family.php @@ -300,12 +300,17 @@ private function sanitize() { 'version' => '2', 'settings' => array( 'typography' => array( - 'fontFamilies' => array( $this->data ), + 'fontFamilies' => array( + 'custom' => array( + $this->data, + ), + ), ), ), ); // Creates a new WP_Theme_JSON object with the new fonts to // leverage sanitization and validation. + $fonts_json = WP_Theme_JSON_Gutenberg::remove_insecure_properties( $fonts_json ); $theme_json = new WP_Theme_JSON_Gutenberg( $fonts_json ); $theme_data = $theme_json->get_data(); $sanitized_font = ! empty( $theme_data['settings']['typography']['fontFamilies'] ) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 6ccbe2fb1d03ba..e0c11766eaaae3 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -896,6 +896,52 @@ public function test_remove_invalid_element_pseudo_selectors() { $this->assertEqualSetsWithIndex( $expected, $actual ); } + public function test_remove_invalid_font_family_settings() { + $actual = WP_Theme_JSON_Gutenberg::remove_insecure_properties( + array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'settings' => array( + 'typography' => array( + 'fontFamilies' => array( + 'custom' => array( + array( + 'name' => 'Open Sans', + 'slug' => 'open-sans', + 'fontFamily' => '"Open Sans", sans-serif', + ), + array( + 'name' => 'Arial', + 'slug' => 'arial', + 'fontFamily' => 'Arial, serif', + ), + ), + ), + ), + ), + ), + true + ); + + $expected = array( + 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA, + 'settings' => array( + 'typography' => array( + 'fontFamilies' => array( + 'custom' => array( + array( + 'name' => 'Arial', + 'slug' => 'arial', + 'fontFamily' => 'Arial, serif', + ), + ), + ), + ), + ), + ); + + $this->assertEqualSetsWithIndex( $expected, $actual ); + } + public function test_get_element_class_name_button() { $expected = 'wp-element-button'; $actual = WP_Theme_JSON_Gutenberg::get_element_class_name( 'button' ); From 1646cd81faae808cd3eff0e3ee11dddb7c754b07 Mon Sep 17 00:00:00 2001 From: JuanMa Date: Sun, 19 Nov 2023 12:36:25 +0000 Subject: [PATCH 075/116] Update quick-start-guide.md (#56281) Update proper link for template --- docs/getting-started/quick-start-guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/getting-started/quick-start-guide.md b/docs/getting-started/quick-start-guide.md index 4ad3998e7c27d3..e978b250ab8aff 100644 --- a/docs/getting-started/quick-start-guide.md +++ b/docs/getting-started/quick-start-guide.md @@ -16,7 +16,7 @@ Next, use the [`@wordpress/create-block`](https://developer.wordpress.org/block- 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 +npx @wordpress/create-block copyright-date-block --template @wordpress/create-block-tutorial-template ``` The `slug` provided (`copyright-date-block`) defines the folder name for the scaffolded plugin and the internal block name. @@ -41,4 +41,4 @@ When you are finished making changes, run the `npm run build` command. This opti - [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 +- [Get started with wp-env](https://developer.wordpress.org/block-editor/getting-started/devenv/get-started-with-wp-env/) From d11351f104288de28233f67fdfac8d4d66ac174c Mon Sep 17 00:00:00 2001 From: Ramon Date: Mon, 20 Nov 2023 09:13:31 +1100 Subject: [PATCH 076/116] Global style revisions: add details and redesign style revision items (#55913) * First commit: - add basic function to return translated labels of top-level changes - showing humantime diff for changes < 1 day - rearranging elements * - timeline redesign - minor optimization refactoring * There is no "colors" property * Some style tweaks * Tweak font sizes * Display Unsaved for unsaved changes * Remove revision changes labels. To be done in a follow up * Moving date format setting call into the comoponent rejigging getLabel function adding css var --- .../screen-revisions/revisions-buttons.js | 110 +++++++++++------- .../global-styles/screen-revisions/style.scss | 80 ++++++++----- 2 files changed, 117 insertions(+), 73 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/screen-revisions/revisions-buttons.js b/packages/edit-site/src/components/global-styles/screen-revisions/revisions-buttons.js index feec0f25ac8823..2786bf6d791212 100644 --- a/packages/edit-site/src/components/global-styles/screen-revisions/revisions-buttons.js +++ b/packages/edit-site/src/components/global-styles/screen-revisions/revisions-buttons.js @@ -12,20 +12,28 @@ import { dateI18n, getDate, humanTimeDiff, getSettings } from '@wordpress/date'; import { store as coreStore } from '@wordpress/core-data'; import { useSelect } from '@wordpress/data'; +const DAY_IN_MILLISECONDS = 60 * 60 * 1000 * 24; + /** * Returns a button label for the revision. * - * @param {Object} revision A revision object. + * @param {string|number} id A revision object. + * @param {boolean} isLatest Whether the revision is the most current. + * @param {string} authorDisplayName Author name. + * @param {string} formattedModifiedDate Revision modified date formatted. * @return {string} Translated label. */ -function getRevisionLabel( revision ) { - const authorDisplayName = revision?.author?.name || __( 'User' ); - - if ( 'parent' === revision?.id ) { +function getRevisionLabel( + id, + isLatest, + authorDisplayName, + formattedModifiedDate +) { + if ( 'parent' === id ) { return __( 'Reset the styles to the theme defaults' ); } - if ( 'unsaved' === revision?.id ) { + if ( 'unsaved' === id ) { return sprintf( /* translators: %s author display name */ __( 'Unsaved changes by %s' ), @@ -33,23 +41,18 @@ function getRevisionLabel( revision ) { ); } - const formattedDate = dateI18n( - getSettings().formats.datetimeAbbreviated, - getDate( revision?.modified ) - ); - - return revision?.isLatest + return isLatest ? sprintf( /* translators: %1$s author display name, %2$s: revision creation date */ __( 'Changes saved by %1$s on %2$s (current)' ), authorDisplayName, - formattedDate + formattedModifiedDate ) : sprintf( /* translators: %1$s author display name, %2$s: revision creation date */ __( 'Changes saved by %1$s on %2$s' ), authorDisplayName, - formattedDate + formattedModifiedDate ); } @@ -65,10 +68,18 @@ function getRevisionLabel( revision ) { * @return {JSX.Element} The modal component. */ function RevisionsButtons( { userRevisions, selectedRevisionId, onChange } ) { - const currentTheme = useSelect( - ( select ) => select( coreStore ).getCurrentTheme(), - [] - ); + const { currentThemeName, currentUser } = useSelect( ( select ) => { + const { getCurrentTheme, getCurrentUser } = select( coreStore ); + const currentTheme = getCurrentTheme(); + return { + currentThemeName: + currentTheme?.name?.rendered || currentTheme?.stylesheet, + currentUser: getCurrentUser(), + }; + }, [] ); + const dateNowInMs = getDate().getTime(); + const { date: dateFormat, datetimeAbbreviated } = getSettings().formats; + return (
    { userRevisions.map( ( revision, index ) => { - const { id, author, modified } = revision; - const authorDisplayName = author?.name || __( 'User' ); - const authorAvatar = author?.avatar_urls?.[ '48' ]; - const isUnsaved = 'unsaved' === revision?.id; + const { id, isLatest, author, modified } = revision; + const isUnsaved = 'unsaved' === id; + // Unsaved changes are created by the current user. + const revisionAuthor = isUnsaved ? currentUser : author; + const authorDisplayName = revisionAuthor?.name || __( 'User' ); + const authorAvatar = revisionAuthor?.avatar_urls?.[ '48' ]; const isSelected = selectedRevisionId - ? selectedRevisionId === revision?.id + ? selectedRevisionId === id : index === 0; - const isReset = 'parent' === revision?.id; + const isReset = 'parent' === id; + const modifiedDate = getDate( modified ); + const displayDate = + modified && + dateNowInMs - modifiedDate.getTime() > DAY_IN_MILLISECONDS + ? dateI18n( dateFormat, modifiedDate ) + : humanTimeDiff( modified ); + const revisionLabel = getRevisionLabel( + id, + isLatest, + authorDisplayName, + dateI18n( datetimeAbbreviated, modifiedDate ) + ); return (
  1. { onChange( revision ); } } - label={ getRevisionLabel( revision ) } + label={ revisionLabel } > { isReset ? ( { __( 'Default styles' ) } - { currentTheme?.name?.rendered || - currentTheme?.stylesheet } + { currentThemeName } ) : ( - + { isUnsaved ? ( + + { __( '(Unsaved)' ) } + + ) : ( + + ) } - { isUnsaved - ? sprintf( - /* translators: %s author display name */ - __( - 'Unsaved changes by %s' - ), - authorDisplayName - ) - : sprintf( - /* translators: %s author display name */ - __( 'Changes saved by %s' ), - authorDisplayName - ) } - { + { authorDisplayName } ) } diff --git a/packages/edit-site/src/components/global-styles/screen-revisions/style.scss b/packages/edit-site/src/components/global-styles/screen-revisions/style.scss index 238f3f7d116e19..6598fcb5ce1c74 100644 --- a/packages/edit-site/src/components/global-styles/screen-revisions/style.scss +++ b/packages/edit-site/src/components/global-styles/screen-revisions/style.scss @@ -8,62 +8,80 @@ margin: 0; li { margin-bottom: 0; - border-left: 1px solid $gray-300; } } .edit-site-global-styles-screen-revisions__revision-item { position: relative; - padding: $grid-unit-10 0 $grid-unit-10 $grid-unit-15; + padding-left: $grid-unit-20; + overflow: hidden; + cursor: pointer; - &:first-child { - padding-top: 0; + &:hover { + background: rgba(var(--wp-admin-theme-color--rgb), 0.04); + .edit-site-global-styles-screen-revisions__date { + color: var(--wp-admin-theme-color); + } } - &:last-child { - padding-bottom: 0; + &::before, + &::after { + position: absolute; + content: "\a"; + display: block; } &::before { background: $gray-300; border-radius: 50%; - content: "\a"; - display: inline-block; height: $grid-unit-10; width: $grid-unit-10; - position: absolute; - top: 50%; - left: 0; + top: $grid-unit-20 + 2; + left: $grid-unit-20 + 1; // So the circle is centered on the line. transform: translate(-50%, -50%); + z-index: 1; } &.is-selected::before { background: var(--wp-components-color-accent, var(--wp-admin-theme-color, #007cba)); } -} -.edit-site-global-styles-screen-revisions__revision-button { - width: 100%; - height: auto; - display: block; - padding: $grid-unit-10 $grid-unit-15; + &::after { + height: 100%; + left: $grid-unit-20; + top: 0; + width: 0; + border: 0.5px solid $gray-300; + } - &:hover { - background: rgba(var(--wp-admin-theme-color--rgb), 0.04); + &:first-child::after { + top: $grid-unit-20 + 2; + } - .edit-site-global-styles-screen-revisions__date { - color: var(--wp-admin-theme-color); + &:last-child::after { + height: $grid-unit-20 + 2; + } + + // Nested to override specificity of .components-button. + .edit-site-global-styles-screen-revisions__revision-button { + width: 100%; + height: auto; + display: block; + padding: $grid-unit-15 $grid-unit-15 $grid-unit-15 $grid-unit-30; + &:focus, + &:active { + outline: 0; + box-shadow: none; } } } .is-selected { + color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #007cba)); + background: rgba(var(--wp-admin-theme-color--rgb), 0.04); .edit-site-global-styles-screen-revisions__revision-button { - color: var(--wp-components-color-accent, var(--wp-admin-theme-color, #007cba)); opacity: 1; - background: rgba(var(--wp-admin-theme-color--rgb), 0.04); } - - .edit-site-global-styles-screen-revisions__meta { + .edit-site-global-styles-screen-revisions__date { color: var(--wp-admin-theme-color); } } @@ -78,20 +96,26 @@ flex-direction: column; align-items: flex-start; gap: $grid-unit-10; + .edit-site-global-styles-screen-revisions__date { + text-transform: uppercase; + font-weight: 600; + font-size: 12px; + } } .edit-site-global-styles-screen-revisions__meta { - color: $gray-700; + color: $gray-600; display: flex; - justify-content: space-between; + justify-content: start; width: 100%; align-items: center; - text-align: left; + font-size: 12px; img { width: $grid-unit-20; height: $grid-unit-20; border-radius: 100%; + margin-right: $grid-unit-10; } } From 272d0a9c61551ab2da8d682896e6baec0fdcb93d Mon Sep 17 00:00:00 2001 From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com> Date: Mon, 20 Nov 2023 17:48:39 +1000 Subject: [PATCH 077/116] Fix: Theme.json font settings in unit test (#56309) --- phpunit/class-wp-theme-json-test.php | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index e0c11766eaaae3..07bec961553c9a 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -221,12 +221,19 @@ public function test_get_stylesheet() { 'typography' => array( 'fontFamilies' => array( array( - 'slug' => 'small', - 'fontFamily' => '14px', + 'name' => 'Arial', + 'slug' => 'arial', + 'fontFamily' => 'Arial, serif', + ), + ), + 'fontSizes' => array( + array( + 'slug' => 'small', + 'size' => '14px', ), array( - 'slug' => 'big', - 'fontFamily' => '41px', + 'slug' => 'big', + 'size' => '41px', ), ), ), @@ -329,10 +336,11 @@ public function test_get_stylesheet() { ) ); - $variables = 'body{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}'; + $variables = 'body{--wp--preset--color--grey: grey;--wp--preset--font-size--small: 14px;--wp--preset--font-size--big: 41px;--wp--preset--font-family--arial: Arial, serif;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}'; $styles = 'body { margin: 0;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}body{color: var(--wp--preset--color--grey);}a:where(:not(.wp-element-button)){background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;min-height: 50vh;padding: 24px;}.wp-block-group a:where(:not(.wp-element-button)){color: #111;}.wp-block-heading{color: #123456;}.wp-block-heading a:where(:not(.wp-element-button)){background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a:where(:not(.wp-element-button)){background-color: #777;color: #555;}.wp-block-post-excerpt{column-count: 2;}.wp-block-image{margin-bottom: 30px;}.wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder{border-top-left-radius: 10px;border-bottom-right-radius: 1em;}'; - $presets = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-small-font-family{font-family: var(--wp--preset--font-family--small) !important;}.has-big-font-family{font-family: var(--wp--preset--font-family--big) !important;}'; - $all = $variables . $styles . $presets; + $presets = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-big-font-size{font-size: var(--wp--preset--font-size--big) !important;}.has-arial-font-family{font-family: var(--wp--preset--font-family--arial) !important;}'; + + $all = $variables . $styles . $presets; $this->assertEquals( $all, $theme_json->get_stylesheet() ); $this->assertEquals( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) ); From 8863b49b7e686f555e8b8adf70cc588c4feebfbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Mon, 20 Nov 2023 11:05:41 +0100 Subject: [PATCH 078/116] DataViews: extract common constants to file (#56251) --- .../edit-site/src/components/dataviews/README.md | 14 +++++++------- .../src/components/dataviews/add-filter.js | 5 +---- .../src/components/dataviews/constants.js | 5 +++++ .../edit-site/src/components/dataviews/filters.js | 5 ++--- .../src/components/dataviews/in-filter.js | 6 ++++-- .../src/components/dataviews/view-list.js | 5 +---- .../edit-site/src/components/page-pages/index.js | 15 +++++++++++---- .../components/sidebar-dataviews/default-views.js | 9 +++++++-- 8 files changed, 38 insertions(+), 26 deletions(-) create mode 100644 packages/edit-site/src/components/dataviews/constants.js diff --git a/packages/edit-site/src/components/dataviews/README.md b/packages/edit-site/src/components/dataviews/README.md index 0645f22821cb9e..5e01c17dcd9407 100644 --- a/packages/edit-site/src/components/dataviews/README.md +++ b/packages/edit-site/src/components/dataviews/README.md @@ -44,8 +44,8 @@ Example: }, search: '', filters: [ - { field: 'author', operator: 'in', value: 2 }, - { field: 'status', operator: 'in', value: 'publish,draft' } + { field: 'author', operator: OPERATOR_IN, value: 2 }, + { field: 'status', operator: OPERATOR_IN, value: 'publish,draft' } ], hiddenFields: [ 'date', 'featured-image' ], layout: {}, @@ -83,8 +83,8 @@ function MyCustomPageList() { }, search: '', filters: [ - { field: 'author', operator: 'in', value: 2 }, - { field: 'status', operator: 'in', value: 'publish,draft' } + { field: 'author', operator: OPERATOR_IN, value: 2 }, + { field: 'status', operator: OPERATOR_IN, value: 'publish,draft' } ], hiddenFields: [ 'date', 'featured-image' ], layout: {}, @@ -93,10 +93,10 @@ function MyCustomPageList() { const queryArgs = useMemo( () => { const filters = {}; view.filters.forEach( ( filter ) => { - if ( filter.field === 'status' && filter.operator === 'in' ) { + if ( filter.field === 'status' && filter.operator === OPERATOR_IN ) { filters.status = filter.value; } - if ( filter.field === 'author' && filter.operator === 'in' ) { + if ( filter.field === 'author' && filter.operator === OPERATOR_IN ) { filters.author = filter.value; } } ); @@ -154,7 +154,7 @@ Example: { item.author } ); }, - type: 'enumeration', + type: ENUMERATION_TYPE, elements: [ { value: 1, label: 'Admin' } { value: 2, label: 'User' } diff --git a/packages/edit-site/src/components/dataviews/add-filter.js b/packages/edit-site/src/components/dataviews/add-filter.js index 374a90eab9df03..147b5a09ca59ac 100644 --- a/packages/edit-site/src/components/dataviews/add-filter.js +++ b/packages/edit-site/src/components/dataviews/add-filter.js @@ -13,7 +13,7 @@ import { __ } from '@wordpress/i18n'; * Internal dependencies */ import { unlock } from '../../lock-unlock'; -import { OPERATOR_IN } from './in-filter'; +import { ENUMERATION_TYPE, OPERATOR_IN } from './constants'; const { DropdownMenuV2, @@ -22,9 +22,6 @@ const { DropdownMenuItemV2, } = unlock( componentsPrivateApis ); -// TODO: find a place where these constants can be shared across components. -const ENUMERATION_TYPE = 'enumeration'; - export default function AddFilter( { fields, view, onChangeView } ) { const filters = []; fields.forEach( ( field ) => { diff --git a/packages/edit-site/src/components/dataviews/constants.js b/packages/edit-site/src/components/dataviews/constants.js new file mode 100644 index 00000000000000..2af12b04c559d7 --- /dev/null +++ b/packages/edit-site/src/components/dataviews/constants.js @@ -0,0 +1,5 @@ +// Field types. +export const ENUMERATION_TYPE = 'enumeration'; + +// Filter operators. +export const OPERATOR_IN = 'in'; diff --git a/packages/edit-site/src/components/dataviews/filters.js b/packages/edit-site/src/components/dataviews/filters.js index 72ba28fd063263..72ca0eb35bd873 100644 --- a/packages/edit-site/src/components/dataviews/filters.js +++ b/packages/edit-site/src/components/dataviews/filters.js @@ -6,11 +6,10 @@ import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ -import { default as InFilter, OPERATOR_IN } from './in-filter'; +import { default as InFilter } from './in-filter'; import AddFilter from './add-filter'; import ResetFilters from './reset-filters'; - -const ENUMERATION_TYPE = 'enumeration'; +import { ENUMERATION_TYPE, OPERATOR_IN } from './constants'; export default function Filters( { fields, view, onChangeView } ) { const filters = []; diff --git a/packages/edit-site/src/components/dataviews/in-filter.js b/packages/edit-site/src/components/dataviews/in-filter.js index cb76bab0f870a9..4f4170fdcbb0b4 100644 --- a/packages/edit-site/src/components/dataviews/in-filter.js +++ b/packages/edit-site/src/components/dataviews/in-filter.js @@ -7,8 +7,10 @@ import { } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; -// TODO: find a place where these constants can be shared across components. -export const OPERATOR_IN = 'in'; +/** + * Internal dependencies + */ +import { OPERATOR_IN } from './constants'; export default ( { filter, view, onChangeView } ) => { const valueFound = view.filters.find( diff --git a/packages/edit-site/src/components/dataviews/view-list.js b/packages/edit-site/src/components/dataviews/view-list.js index fc8b4075025792..07190663de02b9 100644 --- a/packages/edit-site/src/components/dataviews/view-list.js +++ b/packages/edit-site/src/components/dataviews/view-list.js @@ -36,6 +36,7 @@ import { useMemo, Children, Fragment } from '@wordpress/element'; */ import { unlock } from '../../lock-unlock'; import ItemActions from './item-actions'; +import { ENUMERATION_TYPE, OPERATOR_IN } from './constants'; const { DropdownMenuV2, @@ -53,10 +54,6 @@ const sortingItemsInfo = { }; const sortIcons = { asc: chevronUp, desc: chevronDown }; -// TODO: find a place where these constants can be shared across components. -const ENUMERATION_TYPE = 'enumeration'; -const OPERATOR_IN = 'in'; - function HeaderMenu( { dataView, header } ) { if ( header.isPlaceholder ) { return null; diff --git a/packages/edit-site/src/components/page-pages/index.js b/packages/edit-site/src/components/page-pages/index.js index d6c295dc72ff0f..ea29d29335e27d 100644 --- a/packages/edit-site/src/components/page-pages/index.js +++ b/packages/edit-site/src/components/page-pages/index.js @@ -31,6 +31,7 @@ import { import SideEditor from './side-editor'; import Media from '../media'; import { unlock } from '../../lock-unlock'; +import { ENUMERATION_TYPE, OPERATOR_IN } from '../dataviews/constants'; const { useLocation } = unlock( routerPrivateApis ); const EMPTY_ARRAY = []; @@ -120,10 +121,16 @@ export default function PagePages() { const queryArgs = useMemo( () => { const filters = {}; view.filters.forEach( ( filter ) => { - if ( filter.field === 'status' && filter.operator === 'in' ) { + if ( + filter.field === 'status' && + filter.operator === OPERATOR_IN + ) { filters.status = filter.value; } - if ( filter.field === 'author' && filter.operator === 'in' ) { + if ( + filter.field === 'author' && + filter.operator === OPERATOR_IN + ) { filters.author = filter.value; } } ); @@ -227,7 +234,7 @@ export default function PagePages() { ); }, - type: 'enumeration', + type: ENUMERATION_TYPE, elements: authors?.map( ( { id, name } ) => ( { value: id, @@ -240,7 +247,7 @@ export default function PagePages() { getValue: ( { item } ) => STATUSES.find( ( { value } ) => value === item.status ) ?.label ?? item.status, - type: 'enumeration', + type: ENUMERATION_TYPE, elements: STATUSES, enableSorting: false, }, diff --git a/packages/edit-site/src/components/sidebar-dataviews/default-views.js b/packages/edit-site/src/components/sidebar-dataviews/default-views.js index a1557e3b8a3445..d853b6cde112f0 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/default-views.js +++ b/packages/edit-site/src/components/sidebar-dataviews/default-views.js @@ -4,6 +4,11 @@ import { __ } from '@wordpress/i18n'; import { trash } from '@wordpress/icons'; +/** + * Internal dependencies + */ +import { OPERATOR_IN } from '../dataviews/constants'; + const DEFAULT_PAGE_BASE = { type: 'list', search: '', @@ -33,7 +38,7 @@ const DEFAULT_VIEWS = { view: { ...DEFAULT_PAGE_BASE, filters: [ - { field: 'status', operator: 'in', value: 'draft' }, + { field: 'status', operator: OPERATOR_IN, value: 'draft' }, ], }, }, @@ -44,7 +49,7 @@ const DEFAULT_VIEWS = { view: { ...DEFAULT_PAGE_BASE, filters: [ - { field: 'status', operator: 'in', value: 'trash' }, + { field: 'status', operator: OPERATOR_IN, value: 'trash' }, ], }, }, From 447a6de8eb79f307921a22fb8814cc01affded46 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 20 Nov 2023 14:05:51 +0100 Subject: [PATCH 079/116] Extract a PostPanelRow component from the different sidebar panels (#56238) --- .../sidebar/post-pending-status/index.js | 13 +++++-- .../components/sidebar/post-status/index.js | 2 +- .../components/sidebar/post-sticky/index.js | 13 +++++-- .../components/sidebar/post-template/index.js | 16 +++++---- .../sidebar/post-template/style.scss | 15 -------- .../sidebar/post-visibility/index.js | 17 +++++++--- .../sidebar/post-visibility/style.scss | 11 ------ .../page-panels/edit-template.js | 18 ++++------ .../page-panels/page-status.js | 12 +++---- .../sidebar-edit-mode/page-panels/style.scss | 28 +++++---------- .../src/components/post-panel-row/index.js | 34 +++++++++++++++++++ .../src/components/post-panel-row/style.scss | 15 ++++++++ .../src/components/post-schedule/panel.js | 15 +++----- .../src/components/post-schedule/style.scss | 13 +------ .../src/components/post-sync-status/index.js | 9 +++-- .../components/post-sync-status/style.scss | 20 ++--------- .../editor/src/components/post-url/panel.js | 12 +++---- .../editor/src/components/post-url/style.scss | 13 +------ packages/editor/src/private-apis.js | 2 ++ packages/editor/src/style.scss | 1 + 20 files changed, 133 insertions(+), 146 deletions(-) create mode 100644 packages/editor/src/components/post-panel-row/index.js create mode 100644 packages/editor/src/components/post-panel-row/style.scss diff --git a/packages/edit-post/src/components/sidebar/post-pending-status/index.js b/packages/edit-post/src/components/sidebar/post-pending-status/index.js index 739aff6034b509..de1f02b00d746b 100644 --- a/packages/edit-post/src/components/sidebar/post-pending-status/index.js +++ b/packages/edit-post/src/components/sidebar/post-pending-status/index.js @@ -1,18 +1,25 @@ /** * WordPress dependencies */ -import { PanelRow } from '@wordpress/components'; import { PostPendingStatus as PostPendingStatusForm, PostPendingStatusCheck, + privateApis as editorPrivateApis, } from '@wordpress/editor'; +/** + * Internal dependencies + */ +import { unlock } from '../../../lock-unlock'; + +const { PostPanelRow } = unlock( editorPrivateApis ); + export function PostPendingStatus() { return ( - + - + ); } diff --git a/packages/edit-post/src/components/sidebar/post-status/index.js b/packages/edit-post/src/components/sidebar/post-status/index.js index c8c5a20adcfab1..ba6afa2ae9f275 100644 --- a/packages/edit-post/src/components/sidebar/post-status/index.js +++ b/packages/edit-post/src/components/sidebar/post-status/index.js @@ -64,12 +64,12 @@ export default function PostStatus() { + - { fills } - + - + ); } diff --git a/packages/edit-post/src/components/sidebar/post-template/index.js b/packages/edit-post/src/components/sidebar/post-template/index.js index 88809294f17db8..fa1579fa3a82a2 100644 --- a/packages/edit-post/src/components/sidebar/post-template/index.js +++ b/packages/edit-post/src/components/sidebar/post-template/index.js @@ -2,10 +2,13 @@ * WordPress dependencies */ import { useState, useMemo } from '@wordpress/element'; -import { PanelRow, Dropdown, Button } from '@wordpress/components'; +import { Dropdown, Button } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; import { useSelect } from '@wordpress/data'; -import { store as editorStore } from '@wordpress/editor'; +import { + store as editorStore, + privateApis as editorPrivateApis, +} from '@wordpress/editor'; import { store as coreStore } from '@wordpress/core-data'; /** @@ -13,6 +16,9 @@ import { store as coreStore } from '@wordpress/core-data'; */ import PostTemplateForm from './form'; import { store as editPostStore } from '../../../store'; +import { unlock } from '../../../lock-unlock'; + +const { PostPanelRow } = unlock( editorPrivateApis ); export default function PostTemplate() { // Use internal state instead of a ref to make sure that the component @@ -53,11 +59,9 @@ export default function PostTemplate() { } return ( - - { __( 'Template' ) } + ( @@ -70,7 +74,7 @@ export default function PostTemplate() { ) } /> - + ); } diff --git a/packages/edit-post/src/components/sidebar/post-template/style.scss b/packages/edit-post/src/components/sidebar/post-template/style.scss index 2746fc2eeec4f0..91f82d4d0f9f30 100644 --- a/packages/edit-post/src/components/sidebar/post-template/style.scss +++ b/packages/edit-post/src/components/sidebar/post-template/style.scss @@ -1,18 +1,3 @@ -.edit-post-post-template { - width: 100%; - justify-content: flex-start; - - span { - display: block; - width: 30%; - margin-right: 8px; - } -} - -.edit-post-post-template__dropdown { - max-width: 55%; -} - .components-button.edit-post-post-template__toggle { display: inline-block; width: 100%; diff --git a/packages/edit-post/src/components/sidebar/post-visibility/index.js b/packages/edit-post/src/components/sidebar/post-visibility/index.js index 080737c431f1e0..9a70d636388af7 100644 --- a/packages/edit-post/src/components/sidebar/post-visibility/index.js +++ b/packages/edit-post/src/components/sidebar/post-visibility/index.js @@ -2,15 +2,23 @@ * WordPress dependencies */ import { __, sprintf } from '@wordpress/i18n'; -import { PanelRow, Dropdown, Button } from '@wordpress/components'; +import { Dropdown, Button } from '@wordpress/components'; import { PostVisibility as PostVisibilityForm, PostVisibilityLabel, PostVisibilityCheck, usePostVisibilityLabel, + privateApis as editorPrivateApis, } from '@wordpress/editor'; import { useMemo, useState } from '@wordpress/element'; +/** + * Internal dependencies + */ +import { unlock } from '../../../lock-unlock'; + +const { PostPanelRow } = unlock( editorPrivateApis ); + export function PostVisibility() { // Use internal state instead of a ref to make sure that the component // re-renders when the popover's anchor updates. @@ -29,11 +37,10 @@ export function PostVisibility() { return ( ( - - { __( 'Visibility' ) } { ! canEdit && ( @@ -55,7 +62,7 @@ export function PostVisibility() { ) } /> ) } - + ) } /> ); diff --git a/packages/edit-post/src/components/sidebar/post-visibility/style.scss b/packages/edit-post/src/components/sidebar/post-visibility/style.scss index b3876c8403aa06..0dd9824e5bde76 100644 --- a/packages/edit-post/src/components/sidebar/post-visibility/style.scss +++ b/packages/edit-post/src/components/sidebar/post-visibility/style.scss @@ -1,14 +1,3 @@ -.edit-post-post-visibility { - width: 100%; - justify-content: flex-start; - - span { - display: block; - width: 30%; - margin-right: 8px; - } -} - .edit-post-post-visibility__dialog .editor-post-visibility { // sidebar width - popover padding - form margin min-width: $sidebar-width - $grid-unit-20 - $grid-unit-20; 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 1ee382420a7d9a..4bc81b8c7a2921 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 @@ -3,17 +3,12 @@ */ import { useSelect, useDispatch } from '@wordpress/data'; import { decodeEntities } from '@wordpress/html-entities'; -import { - DropdownMenu, - MenuGroup, - MenuItem, - __experimentalHStack as HStack, - __experimentalText as Text, -} from '@wordpress/components'; +import { DropdownMenu, MenuGroup, MenuItem } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { store as coreStore } from '@wordpress/core-data'; import { check } from '@wordpress/icons'; import { store as blockEditorStore } from '@wordpress/block-editor'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; /** * Internal dependencies @@ -24,6 +19,8 @@ import ResetDefaultTemplate from './reset-default-template'; import { unlock } from '../../../lock-unlock'; import { PAGE_CONTENT_BLOCK_TYPES } from '../../../utils/constants'; +const { PostPanelRow } = unlock( editorPrivateApis ); + const POPOVER_PROPS = { className: 'edit-site-page-panels-edit-template__dropdown', placement: 'bottom-start', @@ -71,10 +68,7 @@ export default function EditTemplate() { } return ( - - - { __( 'Template' ) } - + ) } - + ); } diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-status.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-status.js index f80ed4d3fe8204..1d74b09db773e6 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-status.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/page-status.js @@ -6,7 +6,6 @@ import { ToggleControl, Dropdown, __experimentalText as Text, - __experimentalHStack as HStack, __experimentalVStack as VStack, TextControl, RadioControl, @@ -19,11 +18,15 @@ import { store as coreStore } from '@wordpress/core-data'; import { store as noticesStore } from '@wordpress/notices'; import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from '@wordpress/block-editor'; import { useInstanceId } from '@wordpress/compose'; +import { privateApis as editorPrivateApis } from '@wordpress/editor'; /** * Internal dependencies */ import StatusLabel from '../../sidebar-navigation-screen-page/status-label'; +import { unlock } from '../../../lock-unlock'; + +const { PostPanelRow } = unlock( editorPrivateApis ); const STATUS_OPTIONS = [ { @@ -159,10 +162,7 @@ export default function PageStatus( { }; return ( - - - { __( 'Status' ) } - + ) } /> - + ); } 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 acaf5cbfe35dde..f3da54c244bd1b 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 @@ -59,25 +59,15 @@ } } -.edit-site-summary-field { - .components-dropdown { - width: 70%; - } - - .edit-site-summary-field__trigger { - max-width: 100%; - - // Truncate - display: block; - text-align: left; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - .edit-site-summary-field__label { - width: 30%; - } +.edit-site-summary-field__trigger { + max-width: 100%; + + // Truncate + display: block; + text-align: left; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } .edit-site-page-panels-edit-template__dropdown { diff --git a/packages/editor/src/components/post-panel-row/index.js b/packages/editor/src/components/post-panel-row/index.js new file mode 100644 index 00000000000000..a746486ea25f64 --- /dev/null +++ b/packages/editor/src/components/post-panel-row/index.js @@ -0,0 +1,34 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { __experimentalHStack as HStack } from '@wordpress/components'; +import { forwardRef } from '@wordpress/element'; + +const PostPanelRow = forwardRef( ( { className, label, children }, ref ) => { + return ( + + { label ? ( + <> +
    + { label } +
    +
    + { children } +
    + + ) : ( + children + ) } +
    + ); +} ); + +export default PostPanelRow; diff --git a/packages/editor/src/components/post-panel-row/style.scss b/packages/editor/src/components/post-panel-row/style.scss new file mode 100644 index 00000000000000..b21679e9b9697c --- /dev/null +++ b/packages/editor/src/components/post-panel-row/style.scss @@ -0,0 +1,15 @@ +.editor-post-panel__row { + width: 100%; + justify-content: flex-start; + align-items: flex-start; + min-height: $button-size; +} + +.editor-post-panel__row-label { + width: 30%; + flex-shrink: 0; +} + +.editor-post-panel__row-control { + flex-grow: 1; +} diff --git a/packages/editor/src/components/post-schedule/panel.js b/packages/editor/src/components/post-schedule/panel.js index 834e7237e0e946..2e725a06bc9fd7 100644 --- a/packages/editor/src/components/post-schedule/panel.js +++ b/packages/editor/src/components/post-schedule/panel.js @@ -1,11 +1,7 @@ /** * WordPress dependencies */ -import { - Button, - Dropdown, - __experimentalHStack as HStack, -} from '@wordpress/components'; +import { Button, Dropdown } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; import { useState, useMemo } from '@wordpress/element'; @@ -15,6 +11,7 @@ import { useState, useMemo } from '@wordpress/element'; import PostScheduleCheck from './check'; import PostScheduleForm from './index'; import { usePostScheduleLabel } from './label'; +import PostPanelRow from '../post-panel-row'; export default function PostSchedulePanel() { const [ popoverAnchor, setPopoverAnchor ] = useState( null ); @@ -35,11 +32,7 @@ export default function PostSchedulePanel() { return ( - - { __( 'Publish' ) } + ) } /> - + ); } diff --git a/packages/editor/src/components/post-schedule/style.scss b/packages/editor/src/components/post-schedule/style.scss index d70a9e9576fbbe..fb8503962f7cdf 100644 --- a/packages/editor/src/components/post-schedule/style.scss +++ b/packages/editor/src/components/post-schedule/style.scss @@ -1,16 +1,5 @@ -.editor-post-schedule__panel { - width: 100%; - justify-content: flex-start; - align-items: flex-start; - - span { - display: block; - width: 30%; - } -} - .editor-post-schedule__panel-dropdown { - width: 70%; + width: 100%; } .editor-post-schedule__dialog { diff --git a/packages/editor/src/components/post-sync-status/index.js b/packages/editor/src/components/post-sync-status/index.js index abc45146c36af1..c1a317e8e18129 100644 --- a/packages/editor/src/components/post-sync-status/index.js +++ b/packages/editor/src/components/post-sync-status/index.js @@ -4,7 +4,6 @@ import { useSelect, useDispatch } from '@wordpress/data'; import { __, _x } from '@wordpress/i18n'; import { - PanelRow, Modal, Button, __experimentalHStack as HStack, @@ -17,6 +16,7 @@ import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; /** * Internal dependencies */ +import PostPanelRow from '../post-panel-row'; import { store as editorStore } from '../../store'; import { unlock } from '../../lock-unlock'; @@ -44,14 +44,13 @@ export default function PostSyncStatus() { } return ( - - { __( 'Sync status' ) } -
    + +
    { syncStatus === 'unsynced' ? __( 'Not synced' ) : __( 'Fully synced' ) }
    - +
    ); } diff --git a/packages/editor/src/components/post-sync-status/style.scss b/packages/editor/src/components/post-sync-status/style.scss index e18eead94ac835..d5ee21cad8ee46 100644 --- a/packages/editor/src/components/post-sync-status/style.scss +++ b/packages/editor/src/components/post-sync-status/style.scss @@ -1,18 +1,4 @@ -.edit-post-sync-status { - width: 100%; - position: relative; - justify-content: flex-start; - align-items: flex-start; - - > span { - display: block; - width: 30%; - margin-right: 8px; - word-break: break-word; - } - - > div { - // Match padding on tertiary buttons for alignment. - padding: $grid-unit-15 * 0.5 0 $grid-unit-15 * 0.5 $grid-unit-15; - } +.editor-post-sync-status__value { + // Match padding on tertiary buttons for alignment. + padding: $grid-unit-15 * 0.5 0 $grid-unit-15 * 0.5 $grid-unit-15; } diff --git a/packages/editor/src/components/post-url/panel.js b/packages/editor/src/components/post-url/panel.js index 1fddc7df9922c4..4c4fc38d3e2df3 100644 --- a/packages/editor/src/components/post-url/panel.js +++ b/packages/editor/src/components/post-url/panel.js @@ -2,11 +2,7 @@ * WordPress dependencies */ import { useMemo, useState } from '@wordpress/element'; -import { - __experimentalHStack as HStack, - Dropdown, - Button, -} from '@wordpress/components'; +import { Dropdown, Button } from '@wordpress/components'; import { __, sprintf } from '@wordpress/i18n'; /** @@ -15,6 +11,7 @@ import { __, sprintf } from '@wordpress/i18n'; import PostURLCheck from './check'; import PostURL from './index'; import { usePostURLLabel } from './label'; +import PostPanelRow from '../post-panel-row'; export default function PostURLPanel() { // Use internal state instead of a ref to make sure that the component @@ -28,8 +25,7 @@ export default function PostURLPanel() { return ( - - { __( 'URL' ) } + ) } /> - + ); } diff --git a/packages/editor/src/components/post-url/style.scss b/packages/editor/src/components/post-url/style.scss index dbc68d7eda77d2..4a3e8e1b39c9f7 100644 --- a/packages/editor/src/components/post-url/style.scss +++ b/packages/editor/src/components/post-url/style.scss @@ -1,16 +1,5 @@ -.editor-post-url__panel { - width: 100%; - justify-content: flex-start; - align-items: flex-start; - - span { - display: block; - width: 30%; - } -} - .editor-post-url__panel-dropdown { - width: 70%; + width: 100%; } .components-button.editor-post-url__panel-toggle { diff --git a/packages/editor/src/private-apis.js b/packages/editor/src/private-apis.js index b599278f872ddf..a44720eb93ac83 100644 --- a/packages/editor/src/private-apis.js +++ b/packages/editor/src/private-apis.js @@ -5,11 +5,13 @@ import { ExperimentalEditorProvider } from './components/provider'; import { lock } from './lock-unlock'; import { EntitiesSavedStatesExtensible } from './components/entities-saved-states'; import useBlockEditorSettings from './components/provider/use-block-editor-settings'; +import PostPanelRow from './components/post-panel-row'; export const privateApis = {}; lock( privateApis, { ExperimentalEditorProvider, EntitiesSavedStatesExtensible, + PostPanelRow, // This is a temporary private API while we're updating the site editor to use EditorProvider. useBlockEditorSettings, diff --git a/packages/editor/src/style.scss b/packages/editor/src/style.scss index 5428bf5cb1f151..5861764ff8737f 100644 --- a/packages/editor/src/style.scss +++ b/packages/editor/src/style.scss @@ -8,6 +8,7 @@ @import "./components/post-format/style.scss"; @import "./components/post-last-revision/style.scss"; @import "./components/post-locked-modal/style.scss"; +@import "./components/post-panel-row/style.scss"; @import "./components/post-publish-button/style.scss"; @import "./components/post-publish-panel/style.scss"; @import "./components/post-saved-state/style.scss"; From d4dc45f014a052cd7ece453872d83dfae7450337 Mon Sep 17 00:00:00 2001 From: JuanMa Date: Mon, 20 Nov 2023 14:14:25 +0000 Subject: [PATCH 080/116] Added clarifications and examples to "Get started with wp-scripts" (#56298) --- .../devenv/get-started-with-wp-scripts.md | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/docs/getting-started/devenv/get-started-with-wp-scripts.md b/docs/getting-started/devenv/get-started-with-wp-scripts.md index 8a7d100c8921fa..6416adc081e70a 100644 --- a/docs/getting-started/devenv/get-started-with-wp-scripts.md +++ b/docs/getting-started/devenv/get-started-with-wp-scripts.md @@ -20,7 +20,7 @@ The package abstracts away much of the initial setup, configuration, and boilerp ## Quick start
    - If you want to build a custom block, the @wordpress/create-block package allows you to scaffold the structure of files needed to create and register a block. It generates all the necessary code to start a project and integrates a modern JavaScript build setup (using wp-scripts) with no configuration required. Refer to Get started with create-block for more details. + If you use @wordpress/create-block package to scaffold the structure of files needed to create and register a block, you'll also get a modern JavaScript build setup (using wp-scripts) with no configuration required, so you don't need to worry about installing wp-scripts or enqueuing assets. Refer to Get started with create-block for more details.
    ### Installation @@ -64,15 +64,25 @@ Once installed, you can run the predefined scripts provided with `wp-scripts` by } ``` -These scripts can then be run using the command `npm run {script name}`. The two scripts you will use most often are `start` and `build` since they handle the build step. See the [package documentation](https://developer.wordpress.org/block-editor/packages/packages-scripts/) for all options. +These scripts can then be run using the command `npm run {script name}`. + +### The build process with `wp-scripts` + +The two scripts you will use most often are `start` and `build` since they handle the build step. See the [package documentation](https://developer.wordpress.org/block-editor/packages/packages-scripts/) for all options. When working on your project, use the `npm run start` command. This will start a development server and automatically rebuild the project whenever any change is detected. Note that the compiled code in `build/index.js` will not be optimized. When you are ready to deploy your project, use the `npm run build` command. This optimizes your code and makes it production-ready. -After the build finishes, you will see the compiled JavaScript file created at `build/index.js`. A `build/index.asset.php` file will also be created, which contains an array of dependencies and a version number (for cache busting). +After the build finishes, you will see the compiled JavaScript file created at `build/index.js`. + +A `build/index.asset.php` file will also be created in the build process, which contains an array of dependencies and a version number (for cache busting). Please, note that to register a block without this `wp-scripts` build process you'll need to manually create `*.asset.php` dependencies files (see [example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/minimal-block-no-build-e621a6)). -Enqueue the file in the Editor using PHP as you would any other JavaScript file. You can refer to the [Enqueueing assets in the Editor](https://developer.wordpress.org/block-editor/how-to-guides/enqueueing-assets-in-the-editor/) guide for more information, but here's a typical implementation. +### Enqueuing assets + +If you register a block via `register_block_type` the scripts defined in `block.json` will be automatically enqueued (see [example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/minimal-block-ca6eda)) + +To manually enqueue files in the editor, in any other context, you can refer to the [Enqueueing assets in the Editor](https://developer.wordpress.org/block-editor/how-to-guides/enqueueing-assets-in-the-editor/) guide for more information, but here's a typical implementation. ```php /** @@ -91,6 +101,8 @@ function example_project_enqueue_editor_assets() { add_action( 'enqueue_block_editor_assets', 'example_project_enqueue_editor_assets' ); ``` +Here's [an example](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) of manually enqueuing files in the editor. + ## Next steps While `start` and `build` will be the two most used scripts, several other useful tools come with `wp-scripts` that are worth exploring. Here's a look at a few. From 02c0fc6452475b6cfdbdf8f6cf8ac4b0d216a800 Mon Sep 17 00:00:00 2001 From: JuanMa Date: Mon, 20 Nov 2023 15:05:50 +0000 Subject: [PATCH 081/116] Link preview image to live example using WordPress Playground (#56292) * Embed preview of the example using iframe and WordPress Playground Embed preview of the example using iframe and WordPress Playground * Add link to live preview * Update docs/how-to-guides/data-basics/README.md Co-authored-by: Alex Stine * proper alt and titles attributes added * proper alt and titles attributes added * Update docs/how-to-guides/data-basics/README.md Co-authored-by: Alex Stine --------- Co-authored-by: Alex Stine --- docs/how-to-guides/data-basics/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/how-to-guides/data-basics/README.md b/docs/how-to-guides/data-basics/README.md index 3cb07eae2b6594..3e92a216b60c55 100644 --- a/docs/how-to-guides/data-basics/README.md +++ b/docs/how-to-guides/data-basics/README.md @@ -2,7 +2,8 @@ This tutorial aims to get you comfortable with the Gutenberg data layer. It guides you through building a simple React application that enables the user to manage their WordPress pages. The finished app will look like this: -![](https://raw.githubusercontent.com/WordPress/gutenberg/HEAD/docs/how-to-guides/data-basics/media/list-of-pages/part1-finished.jpg) + +[![Open demo in WordPress Playground](https://raw.githubusercontent.com/WordPress/gutenberg/HEAD/docs/how-to-guides/data-basics/media/list-of-pages/part1-finished.jpg)](https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/WordPress/block-development-examples/trunk/plugins/data-basics-59c8f8/_playground/blueprint.json "Opens demo in WordPress Playground") You may review the [finished app](https://github.com/WordPress/block-development-examples/tree/trunk/plugins/data-basics-59c8f8) in the block-development-examples repository. From 0ba206b88120ef93da94cd7df6e427cf918700e9 Mon Sep 17 00:00:00 2001 From: Joen A <1204802+jasmussen@users.noreply.github.com> Date: Mon, 20 Nov 2023 16:35:19 +0100 Subject: [PATCH 082/116] Try: Change "Detach pattern" to "Detach" (#56323) * Update: Change "Detach patterns" to singular. * Try: "Detach" instead of "Detach pattern". --- .../block-toolbar-menu.native.js | 5 +- .../block-library/src/block/edit.native.js | 18 ++--- .../editor/various/pattern-blocks.test.js | 6 +- .../src/components/patterns-manage-button.js | 71 +++++++++---------- .../reusable-blocks-manage-button.js | 71 +++++++++---------- 5 files changed, 77 insertions(+), 94 deletions(-) diff --git a/packages/block-editor/src/components/block-toolbar/block-toolbar-menu.native.js b/packages/block-editor/src/components/block-toolbar/block-toolbar-menu.native.js index b579de1f046d9b..c8d220fedfb35c 100644 --- a/packages/block-editor/src/components/block-toolbar/block-toolbar-menu.native.js +++ b/packages/block-editor/src/components/block-toolbar/block-toolbar-menu.native.js @@ -212,10 +212,7 @@ const BlockActionsMenu = ( { }, convertToRegularBlocks: { id: 'convertToRegularBlocksOption', - label: - innerBlockCount > 1 - ? __( 'Detach patterns' ) - : __( 'Detach pattern' ), + label: __( 'Detach' ), value: 'convertToRegularBlocksOption', onSelect: () => { /* translators: %s: name of the synced block */ diff --git a/packages/block-library/src/block/edit.native.js b/packages/block-library/src/block/edit.native.js index ddc22c01e40def..9ab6ccf86a1e19 100644 --- a/packages/block-library/src/block/edit.native.js +++ b/packages/block-library/src/block/edit.native.js @@ -78,7 +78,7 @@ export default function ReusableBlockEdit( { styles.spinnerDark ); - const { hasResolved, isEditing, isMissing, innerBlockCount } = useSelect( + const { hasResolved, isEditing, isMissing } = useSelect( ( select ) => { const persistedBlock = select( coreStore ).getEntityRecord( 'postType', @@ -176,20 +176,12 @@ export default function ReusableBlockEdit( { { infoTitle } - { innerBlockCount > 1 - ? __( - 'Alternatively, you can detach and edit these blocks separately by tapping “Detach patterns”.' - ) - : __( - 'Alternatively, you can detach and edit this block separately by tapping “Detach pattern”.' - ) } + { __( + 'Alternatively, you can detach and edit this block separately by tapping “Detach”.' + ) } 1 - ? __( 'Detach patterns' ) - : __( 'Detach pattern' ) - } + label={ __( 'Detach' ) } separatorType="topFullWidth" onPress={ onConvertToRegularBlocks } labelStyle={ actionButtonStyle } diff --git a/packages/e2e-tests/specs/editor/various/pattern-blocks.test.js b/packages/e2e-tests/specs/editor/various/pattern-blocks.test.js index 442ed2b21915a5..cb5187a390e8b1 100644 --- a/packages/e2e-tests/specs/editor/various/pattern-blocks.test.js +++ b/packages/e2e-tests/specs/editor/various/pattern-blocks.test.js @@ -112,7 +112,7 @@ describe( 'Pattern blocks', () => { // Convert block to a regular block. await clickBlockToolbarButton( 'Options' ); - await clickMenuItem( 'Detach pattern' ); + await clickMenuItem( 'Detach' ); // Check that we have a paragraph block on the page. const paragraphBlock = await canvas().$( @@ -219,7 +219,7 @@ describe( 'Pattern blocks', () => { // Convert block to a regular block. await clickBlockToolbarButton( 'Options' ); - await clickMenuItem( 'Detach patterns' ); + await clickMenuItem( 'Detach' ); // Check that we have two paragraph blocks on the page. expect( await getEditedPostContent() ).toMatchSnapshot(); @@ -352,7 +352,7 @@ describe( 'Pattern blocks', () => { // Convert back to regular blocks. await clickBlockToolbarButton( 'Select Edited block' ); await clickBlockToolbarButton( 'Options' ); - await clickMenuItem( 'Detach pattern' ); + await clickMenuItem( 'Detach' ); await page.waitForXPath( selector, { hidden: true, } ); diff --git a/packages/patterns/src/components/patterns-manage-button.js b/packages/patterns/src/components/patterns-manage-button.js index a86208a04b6011..45ad96d8d8aae6 100644 --- a/packages/patterns/src/components/patterns-manage-button.js +++ b/packages/patterns/src/components/patterns-manage-button.js @@ -16,41 +16,40 @@ import { store as patternsStore } from '../store'; import { unlock } from '../lock-unlock'; function PatternsManageButton( { clientId } ) { - const { canRemove, isVisible, innerBlockCount, managePatternsUrl } = - useSelect( - ( select ) => { - const { getBlock, canRemoveBlock, getBlockCount, getSettings } = - select( blockEditorStore ); - const { canUser } = select( coreStore ); - const reusableBlock = getBlock( clientId ); - const isBlockTheme = getSettings().__unstableIsBlockBasedTheme; + const { canRemove, isVisible, managePatternsUrl } = useSelect( + ( select ) => { + const { getBlock, canRemoveBlock, getBlockCount, getSettings } = + select( blockEditorStore ); + const { canUser } = select( coreStore ); + const reusableBlock = getBlock( clientId ); + const isBlockTheme = getSettings().__unstableIsBlockBasedTheme; - return { - canRemove: canRemoveBlock( clientId ), - isVisible: - !! reusableBlock && - isReusableBlock( reusableBlock ) && - !! canUser( - 'update', - 'blocks', - reusableBlock.attributes.ref - ), - innerBlockCount: getBlockCount( clientId ), - // The site editor and templates both check whether the user - // has edit_theme_options capabilities. We can leverage that here - // and omit the manage patterns link if the user can't access it. - managePatternsUrl: - isBlockTheme && canUser( 'read', 'templates' ) - ? addQueryArgs( 'site-editor.php', { - path: '/patterns', - } ) - : addQueryArgs( 'edit.php', { - post_type: 'wp_block', - } ), - }; - }, - [ clientId ] - ); + return { + canRemove: canRemoveBlock( clientId ), + isVisible: + !! reusableBlock && + isReusableBlock( reusableBlock ) && + !! canUser( + 'update', + 'blocks', + reusableBlock.attributes.ref + ), + innerBlockCount: getBlockCount( clientId ), + // The site editor and templates both check whether the user + // has edit_theme_options capabilities. We can leverage that here + // and omit the manage patterns link if the user can't access it. + managePatternsUrl: + isBlockTheme && canUser( 'read', 'templates' ) + ? addQueryArgs( 'site-editor.php', { + path: '/patterns', + } ) + : addQueryArgs( 'edit.php', { + post_type: 'wp_block', + } ), + }; + }, + [ clientId ] + ); // Ignore reason: false positive of the lint rule. // eslint-disable-next-line @wordpress/no-unused-vars-before-return @@ -68,9 +67,7 @@ function PatternsManageButton( { clientId } ) { convertSyncedPatternToStatic( clientId ) } > - { innerBlockCount > 1 - ? __( 'Detach patterns' ) - : __( 'Detach pattern' ) } + { __( 'Detach' ) } ) } diff --git a/packages/reusable-blocks/src/components/reusable-blocks-menu-items/reusable-blocks-manage-button.js b/packages/reusable-blocks/src/components/reusable-blocks-menu-items/reusable-blocks-manage-button.js index 6ca19269d40f64..cf03c2a07b7a0c 100644 --- a/packages/reusable-blocks/src/components/reusable-blocks-menu-items/reusable-blocks-manage-button.js +++ b/packages/reusable-blocks/src/components/reusable-blocks-menu-items/reusable-blocks-manage-button.js @@ -15,41 +15,40 @@ import { store as coreStore } from '@wordpress/core-data'; import { store as reusableBlocksStore } from '../../store'; function ReusableBlocksManageButton( { clientId } ) { - const { canRemove, isVisible, innerBlockCount, managePatternsUrl } = - useSelect( - ( select ) => { - const { getBlock, canRemoveBlock, getBlockCount, getSettings } = - select( blockEditorStore ); - const { canUser } = select( coreStore ); - const reusableBlock = getBlock( clientId ); - const isBlockTheme = getSettings().__unstableIsBlockBasedTheme; + const { canRemove, isVisible, managePatternsUrl } = useSelect( + ( select ) => { + const { getBlock, canRemoveBlock, getBlockCount, getSettings } = + select( blockEditorStore ); + const { canUser } = select( coreStore ); + const reusableBlock = getBlock( clientId ); + const isBlockTheme = getSettings().__unstableIsBlockBasedTheme; - return { - canRemove: canRemoveBlock( clientId ), - isVisible: - !! reusableBlock && - isReusableBlock( reusableBlock ) && - !! canUser( - 'update', - 'blocks', - reusableBlock.attributes.ref - ), - innerBlockCount: getBlockCount( clientId ), - // The site editor and templates both check whether the user - // has edit_theme_options capabilities. We can leverage that here - // and omit the manage patterns link if the user can't access it. - managePatternsUrl: - isBlockTheme && canUser( 'read', 'templates' ) - ? addQueryArgs( 'site-editor.php', { - path: '/patterns', - } ) - : addQueryArgs( 'edit.php', { - post_type: 'wp_block', - } ), - }; - }, - [ clientId ] - ); + return { + canRemove: canRemoveBlock( clientId ), + isVisible: + !! reusableBlock && + isReusableBlock( reusableBlock ) && + !! canUser( + 'update', + 'blocks', + reusableBlock.attributes.ref + ), + innerBlockCount: getBlockCount( clientId ), + // The site editor and templates both check whether the user + // has edit_theme_options capabilities. We can leverage that here + // and omit the manage patterns link if the user can't access it. + managePatternsUrl: + isBlockTheme && canUser( 'read', 'templates' ) + ? addQueryArgs( 'site-editor.php', { + path: '/patterns', + } ) + : addQueryArgs( 'edit.php', { + post_type: 'wp_block', + } ), + }; + }, + [ clientId ] + ); const { __experimentalConvertBlockToStatic: convertBlockToStatic } = useDispatch( reusableBlocksStore ); @@ -65,9 +64,7 @@ function ReusableBlocksManageButton( { clientId } ) { { canRemove && ( convertBlockToStatic( clientId ) }> - { innerBlockCount > 1 - ? __( 'Detach patterns' ) - : __( 'Detach pattern' ) } + { __( 'Detach' ) } ) } From 5cfe09466314a46dba814629341c552cc5adc8dd Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 20 Nov 2023 18:28:44 +0100 Subject: [PATCH 083/116] Post Schedule Panel: Remove text overflow ellipsis (#56319) --- .../editor/src/components/post-panel-row/style.scss | 7 +++++-- .../editor/src/components/post-schedule/style.scss | 10 +++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/editor/src/components/post-panel-row/style.scss b/packages/editor/src/components/post-panel-row/style.scss index b21679e9b9697c..b3dfc8c6bcf6b0 100644 --- a/packages/editor/src/components/post-panel-row/style.scss +++ b/packages/editor/src/components/post-panel-row/style.scss @@ -1,13 +1,16 @@ .editor-post-panel__row { width: 100%; - justify-content: flex-start; - align-items: flex-start; min-height: $button-size; + justify-content: flex-start !important; + align-items: flex-start !important; } .editor-post-panel__row-label { width: 30%; flex-shrink: 0; + min-height: $button-size; + display: flex; + align-items: center; } .editor-post-panel__row-control { diff --git a/packages/editor/src/components/post-schedule/style.scss b/packages/editor/src/components/post-schedule/style.scss index fb8503962f7cdf..ca5bc19ae7d5ca 100644 --- a/packages/editor/src/components/post-schedule/style.scss +++ b/packages/editor/src/components/post-schedule/style.scss @@ -9,11 +9,15 @@ } } -.editor-post-schedule__dialog-toggle { +.editor-post-schedule__dialog-toggle.components-button { display: block; max-width: 100%; overflow: hidden; text-align: left; - text-overflow: ellipsis; - white-space: nowrap; + white-space: unset; + height: auto; + + // The line height + the padding should be the same as the button size. + padding: ( ( $button-size - $grid-unit-20 ) / 2 ) 12px; + line-height: $grid-unit-20; } From 0253471becaf06274b0de4ece9d986b60191108c Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Tue, 21 Nov 2023 03:23:19 +0900 Subject: [PATCH 084/116] Duotone: Backport from Core to fix filters in classic themes (#54778) Co-authored-by: Alex Lende --- lib/class-wp-duotone-gutenberg.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/class-wp-duotone-gutenberg.php b/lib/class-wp-duotone-gutenberg.php index 11f6c6dcccdd93..93714e59740063 100644 --- a/lib/class-wp-duotone-gutenberg.php +++ b/lib/class-wp-duotone-gutenberg.php @@ -938,9 +938,17 @@ public static function output_footer_assets() { echo self::get_svg_definitions( self::$used_svg_filter_data ); } - // This is for classic themes - in block themes, the CSS is added in the head via wp_add_inline_style in the wp_enqueue_scripts action. - if ( ! wp_is_block_theme() && ! empty( self::$used_global_styles_presets ) ) { - wp_add_inline_style( 'core-block-supports', self::get_global_styles_presets( self::$used_global_styles_presets ) ); + // In block themes, the CSS is added in the head via wp_add_inline_style in the wp_enqueue_scripts action. + if ( ! wp_is_block_theme() ) { + $style_tag_id = 'core-block-supports-duotone'; + wp_register_style( $style_tag_id, false ); + if ( ! empty( self::$used_global_styles_presets ) ) { + wp_add_inline_style( $style_tag_id, self::get_global_styles_presets( self::$used_global_styles_presets ) ); + } + if ( ! empty( self::$block_css_declarations ) ) { + wp_add_inline_style( $style_tag_id, gutenberg_style_engine_get_stylesheet_from_css_rules( self::$block_css_declarations ) ); + } + wp_enqueue_style( $style_tag_id ); } } From d7f8cff991435546e097fa8348298b6ffd774d43 Mon Sep 17 00:00:00 2001 From: JuanMa Date: Mon, 20 Nov 2023 18:37:26 +0000 Subject: [PATCH 085/116] Docs - Block Editor Handbook - Add end user documentation about Block Editor as a resource on the Landing Page of the Block Editor Handbook (#49854) * add end user documentation as a resource * Update docs/README.md Co-authored-by: Nick Diego * Moved End User Documentation to the end of the list --------- Co-authored-by: Nick Diego --- docs/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 219c622dc3d73c..b94a8d78d41a75 100644 --- a/docs/README.md +++ b/docs/README.md @@ -58,8 +58,8 @@ This handbook should be considered the canonical resource for all things related - [**WordPress Developer Blog**](https://developer.wordpress.org/news/) - An ever-growing resource of technical articles covering specific topics related to block development and a wide variety of use cases. The blog is also an excellent way to [keep up with the latest developments in WordPress](https://developer.wordpress.org/news/tag/roundup/). - [**Learn WordPress**](https://learn.wordpress.org/) - The WordPress hub for learning resources where you can find courses like [Introduction to Block Development: Build your first custom block](https://learn.wordpress.org/course/introduction-to-block-development-build-your-first-custom-block/), [Converting a Shortcode to a Block](https://learn.wordpress.org/course/converting-a-shortcode-to-a-block/) or [Using the WordPress Data Layer](https://learn.wordpress.org/course/using-the-wordpress-data-layer/) - [**WordPress.tv**](https://wordpress.tv/) - A hub of WordPress-related videos (from talks at WordCamps to recordings of online workshops) curated and moderated by the WordPress.org community. You’re sure to find something to aid your learning about [block development](https://wordpress.tv/?s=block%20development&sort=newest) or the [block-editor](https://wordpress.tv/?s=block%20editor&sort=relevance) here. -- [**Gutenberg repository**](https://github.com/WordPress/gutenberg/) - Development of the block editor project is carried out in this GitHub repository. It contains the code of interesting packages such as [`block-library`](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src) (core blocks) or [`components`](https://github.com/WordPress/gutenberg/tree/trunk/packages/components) (common UI elements). _The [block-development-examples](https://github.com/WordPress/block-development-examples) repository is another useful reference._ - +- [**Gutenberg repository**](https://github.com/WordPress/gutenberg/) - Development of the block editor project is carried out in this GitHub repository. It contains the code of interesting packages such as [`block-library`](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src) (core blocks) or [`components`](https://github.com/WordPress/gutenberg/tree/trunk/packages/components) (common UI elements). _The [gutenberg-examples](https://github.com/WordPress/gutenberg-examples) repository is another useful reference._ +- [**End User Documentation**](https://wordpress.org/documentation/) - Documentation site targeted to the end user (not developers) where you can also find documentation about the [Block Editor](https://wordpress.org/documentation/category/block-editor/) and [working with blocks](https://wordpress.org/documentation/article/work-with-blocks/). ## Are you in the right place? From 59c0356f5282745ddbbda0e0852dde00a70cf9fb Mon Sep 17 00:00:00 2001 From: JuanMa Date: Mon, 20 Nov 2023 19:09:23 +0000 Subject: [PATCH 086/116] Update webpack options for wp-scripts in README.md (#56314) * Update webpack options in README.md * Add support for custom output directory in build process --- packages/scripts/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/scripts/README.md b/packages/scripts/README.md index 89ae3f1fff05c5..4a3c13b27445a2 100644 --- a/packages/scripts/README.md +++ b/packages/scripts/README.md @@ -48,7 +48,7 @@ It might also be a good idea to get familiar with the [JavaScript Build Setup tu ## Automatic block.json detection and the source code directory -When using the `start` or `build` commands, the source code directory ( the default is `./src`) and its subdirectories are scanned for the existence of `block.json` files. If one or more are found, they are treated a entry points and will be output into corresponding folders in the `build` directory. This allows for the creation of multiple blocks that use a single build process. The source directory can be customized using the `--webpack-src-dir` flag. +When using the `start` or `build` commands, the source code directory ( the default is `./src`) and its subdirectories are scanned for the existence of `block.json` files. If one or more are found, they are treated a entry points and will be output into corresponding folders in the `build` directory. This allows for the creation of multiple blocks that use a single build process. The source directory can be customized using the `--webpack-src-dir` flag and the output directory with the `--output-path` flag. ## Updating to New Release @@ -106,6 +106,7 @@ This script automatically use the optimized config but sometimes you may want to - `--webpack-copy-php` – enables copying all PHP files from the source directory ( default is `src` ) and its subfolders to the output directory. - `--webpack-no-externals` – disables scripts' assets generation, and omits the list of default externals. - `--webpack-src-dir` – Allows customization of the source code directory. Default is `src`. +- `--output-path` – Allows customization of the output directory. Default is `build`. #### Advanced information @@ -388,6 +389,7 @@ This script automatically use the optimized config but sometimes you may want to - `--webpack-devtool` – controls how source maps are generated. See options at https://webpack.js.org/configuration/devtool/#devtool. - `--webpack-no-externals` – disables scripts' assets generation, and omits the list of default externals. - `--webpack-src-dir` – Allows customization of the source code directory. Default is `src`. +- `--output-path` – Allows customization of the output directory. Default is `build`. #### Advanced information From 8eb63ddb51525164860e785900d7d86544f37afc Mon Sep 17 00:00:00 2001 From: Ramon Date: Tue, 21 Nov 2023 09:43:59 +1100 Subject: [PATCH 087/116] Revisions: add new selectors to fetch entity revisions (#54046) * Fetching entity revisions using loaded name argument e.g., post:id:revisions Revisions loaded into state tree under revisions[parent] Invalidate revisions after saved entity Revisions url params are contained in entity config Testing with global styles - modifying CPT to show in rest Implementing thin API layer for Revisions over the getEntityRecords implementation Duplicated the logic in the selectors for revisions functions Added tests * Revert edit context query param when fetching post types Reverting timeout in performance tests. * Tidying up reducer, allowing revisions for posts and pages only * Adding types to the base entity records for revisions and global styles revisions. * Removed unnecessary REST API change for global styles: it was to pull in the CPT in the /types response, which we don't need for core-data since it's a root entity. * Remove duplicated queried-data reducer functions for revisions, and use them in the main reducer Create dedicated resolvers for getRevision/s, thereby removing the split name parsing required (name:id:revisions) Create dedicated action receivers for revisions Rename from getEntityRevisions to getRevisions Fully remove parseEntityName Updated selector tests Use queriedDataReducer shape for revisions. The queriedDataReducer doesn't need to know about the revisions action type. Update doc comments Updated CHANGELOG.md * This commit: - removes `hasRevisions` because it has no noticeable benefit, at least as far as I can see. I'm probably wrong. - removes the default revisions query context for the API call (the default is 'view' anyway) - fixes the revisions reducer - Add _fields logic to resolvers and selectors Adds basic reducer tests * updated variable names: parentId > recordKey, key > revisionKey removing lock-related code deleting `recordKey` from action object before sending to queriedDataReducer updating docs * Removing revisions when items are removed. --- docs/reference-guides/data/data-core.md | 51 ++++ packages/core-data/CHANGELOG.md | 1 + packages/core-data/README.md | 55 +++- packages/core-data/src/actions.js | 33 +++ packages/core-data/src/entities.js | 21 ++ .../entity-types/global-styles-revision.ts | 47 ++++ packages/core-data/src/entity-types/index.ts | 6 + .../src/entity-types/post-revision.ts | 93 +++++++ packages/core-data/src/reducer.js | 47 +++- packages/core-data/src/resolvers.js | 147 ++++++++++- packages/core-data/src/selectors.ts | 111 +++++++++ packages/core-data/src/test/entities.js | 9 + packages/core-data/src/test/reducer.js | 235 ++++++++++++++++++ packages/core-data/src/test/selectors.js | 96 +++++++ 14 files changed, 947 insertions(+), 5 deletions(-) create mode 100644 packages/core-data/src/entity-types/global-styles-revision.ts create mode 100644 packages/core-data/src/entity-types/post-revision.ts diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md index ea97ce28e4d85c..6084eff930394a 100644 --- a/docs/reference-guides/data/data-core.md +++ b/docs/reference-guides/data/data-core.md @@ -420,6 +420,39 @@ _Returns_ - A value whose reference will change only when an edit occurs. +### getRevision + +Returns a single, specific revision of a parent entity. + +_Parameters_ + +- _state_ `State`: State tree +- _kind_ `string`: Entity kind. +- _name_ `string`: Entity name. +- _recordKey_ `EntityRecordKey`: The key of the entity record whose revisions you want to fetch. +- _revisionKey_ `EntityRecordKey`: The revision's key. +- _query_ `GetRecordsHttpQuery`: Optional query. If requesting specific fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [entity kind]". + +_Returns_ + +- `RevisionRecord | Record< PropertyKey, never > | undefined`: Record. + +### getRevisions + +Returns an entity's revisions. + +_Parameters_ + +- _state_ `State`: State tree +- _kind_ `string`: Entity kind. +- _name_ `string`: Entity name. +- _recordKey_ `EntityRecordKey`: The key of the entity record whose revisions you want to fetch. +- _query_ `GetRecordsHttpQuery`: Optional query. If requesting specific fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [Entity kind]". + +_Returns_ + +- `RevisionRecord[] | null`: Record. + ### getThemeSupports Return theme supports data in the index. @@ -704,6 +737,24 @@ _Returns_ - `Object`: Action object. +### receiveRevisions + +Returns an action object used in signalling that revisions have been received. + +_Parameters_ + +- _kind_ `string`: Kind of the received entity record revisions. +- _name_ `string`: Name of the received entity record revisions. +- _recordKey_ `number|string`: The key of the entity record whose revisions you want to fetch. +- _records_ `Array|Object`: Revisions received. +- _query_ `?Object`: Query Object. +- _invalidateCache_ `?boolean`: Should invalidate query caches. +- _meta_ `?Object`: Meta information about pagination. + +_Returns_ + +- `Object`: Action object. + ### receiveThemeSupports > **Deprecated** since WP 5.9, this is not useful anymore, use the selector direclty. diff --git a/packages/core-data/CHANGELOG.md b/packages/core-data/CHANGELOG.md index d20f8bd6c9d667..b54e8e01e48fb1 100644 --- a/packages/core-data/CHANGELOG.md +++ b/packages/core-data/CHANGELOG.md @@ -11,6 +11,7 @@ ## Enhancements - Add `getEntityRecordsTotalItems` and `getEntityRecordsTotalPages` selectors. [#55164](https://github.com/WordPress/gutenberg/pull/55164). +- Revisions: add new selectors, `getRevisions` and `getRevision`, to fetch entity revisions. [#54046](https://github.com/WordPress/gutenberg/pull/54046). ## 6.20.0 (2023-10-05) diff --git a/packages/core-data/README.md b/packages/core-data/README.md index ef5d9c1197f099..f7a177b5c55872 100644 --- a/packages/core-data/README.md +++ b/packages/core-data/README.md @@ -123,7 +123,7 @@ The package provides general methods to interact with the entities (`getEntityRe ```js // Get the record collection for the user entity. -wp.data.select( 'core' ).getEntityRecords( 'root' 'user' ); +wp.data.select( 'core' ).getEntityRecords( 'root', 'user' ); // Get a single record for the user entity. wp.data.select( 'core' ).getEntityRecord( 'root', 'user', recordId ); @@ -138,7 +138,7 @@ In addition to the general utilities (`getEntityRecords`, `getEntityRecord`, etc ```js // Collection -wp.data.select( 'core' ).getEntityRecords( 'root' 'user' ); +wp.data.select( 'core' ).getEntityRecords( 'root', 'user' ); wp.data.select( 'core' ).getUsers(); // Single record @@ -248,6 +248,24 @@ _Returns_ - `Object`: Action object. +### receiveRevisions + +Returns an action object used in signalling that revisions have been received. + +_Parameters_ + +- _kind_ `string`: Kind of the received entity record revisions. +- _name_ `string`: Name of the received entity record revisions. +- _recordKey_ `number|string`: The key of the entity record whose revisions you want to fetch. +- _records_ `Array|Object`: Revisions received. +- _query_ `?Object`: Query Object. +- _invalidateCache_ `?boolean`: Should invalidate query caches. +- _meta_ `?Object`: Meta information about pagination. + +_Returns_ + +- `Object`: Action object. + ### receiveThemeSupports > **Deprecated** since WP 5.9, this is not useful anymore, use the selector direclty. @@ -727,6 +745,39 @@ _Returns_ - A value whose reference will change only when an edit occurs. +### getRevision + +Returns a single, specific revision of a parent entity. + +_Parameters_ + +- _state_ `State`: State tree +- _kind_ `string`: Entity kind. +- _name_ `string`: Entity name. +- _recordKey_ `EntityRecordKey`: The key of the entity record whose revisions you want to fetch. +- _revisionKey_ `EntityRecordKey`: The revision's key. +- _query_ `GetRecordsHttpQuery`: Optional query. If requesting specific fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [entity kind]". + +_Returns_ + +- `RevisionRecord | Record< PropertyKey, never > | undefined`: Record. + +### getRevisions + +Returns an entity's revisions. + +_Parameters_ + +- _state_ `State`: State tree +- _kind_ `string`: Entity kind. +- _name_ `string`: Entity name. +- _recordKey_ `EntityRecordKey`: The key of the entity record whose revisions you want to fetch. +- _query_ `GetRecordsHttpQuery`: Optional query. If requesting specific fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [Entity kind]". + +_Returns_ + +- `RevisionRecord[] | null`: Record. + ### getThemeSupports Return theme supports data in the index. diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js index 9e7277f35a62a7..d71c5d6120089e 100644 --- a/packages/core-data/src/actions.js +++ b/packages/core-data/src/actions.js @@ -924,3 +924,36 @@ export function receiveDefaultTemplateId( query, templateId ) { templateId, }; } + +/** + * Returns an action object used in signalling that revisions have been received. + * + * @param {string} kind Kind of the received entity record revisions. + * @param {string} name Name of the received entity record revisions. + * @param {number|string} recordKey The key of the entity record whose revisions you want to fetch. + * @param {Array|Object} records Revisions received. + * @param {?Object} query Query Object. + * @param {?boolean} invalidateCache Should invalidate query caches. + * @param {?Object} meta Meta information about pagination. + * @return {Object} Action object. + */ +export function receiveRevisions( + kind, + name, + recordKey, + records, + query, + invalidateCache = false, + meta +) { + return { + type: 'RECEIVE_ITEM_REVISIONS', + items: Array.isArray( records ) ? records : [ records ], + recordKey, + meta, + query, + kind, + name, + invalidateCache, + }; +} diff --git a/packages/core-data/src/entities.js b/packages/core-data/src/entities.js index af8829d0bc852c..e85673492ef56e 100644 --- a/packages/core-data/src/entities.js +++ b/packages/core-data/src/entities.js @@ -19,6 +19,10 @@ export const DEFAULT_ENTITY_KEY = 'id'; const POST_RAW_ATTRIBUTES = [ 'title', 'excerpt', 'content' ]; +// A hardcoded list of post types that support revisions. +// @TODO: Ideally this should be fetched from the `/types` REST API's view context. +const POST_TYPES_WITH_REVISIONS_SUPPORT = [ 'post', 'page' ]; + export const rootEntitiesConfig = [ { label: __( 'Base' ), @@ -207,6 +211,12 @@ export const rootEntitiesConfig = [ baseURLParams: { context: 'edit' }, plural: 'globalStylesVariations', // Should be different than name. getTitle: ( record ) => record?.title?.rendered || record?.title, + getRevisionsUrl: ( parentId ) => + `/wp/v2/global-styles/${ parentId }/revisions`, + supports: { + revisions: true, + }, + supportsPagination: true, }, { label: __( 'Themes' ), @@ -295,6 +305,11 @@ async function loadPostTypeEntities() { selection: true, }, mergedEdits: { meta: true }, + supports: { + revisions: POST_TYPES_WITH_REVISIONS_SUPPORT.includes( + postType?.slug + ), + }, rawAttributes: POST_RAW_ATTRIBUTES, getTitle: ( record ) => record?.title?.rendered || @@ -328,6 +343,12 @@ async function loadPostTypeEntities() { syncObjectType: 'postType/' + postType.name, getSyncObjectId: ( id ) => id, supportsPagination: true, + getRevisionsUrl: ( parentId, revisionId ) => + `/${ namespace }/${ + postType.rest_base + }/${ parentId }/revisions${ + revisionId ? '/' + revisionId : '' + }`, }; } ); } diff --git a/packages/core-data/src/entity-types/global-styles-revision.ts b/packages/core-data/src/entity-types/global-styles-revision.ts new file mode 100644 index 00000000000000..1a89c164e313b0 --- /dev/null +++ b/packages/core-data/src/entity-types/global-styles-revision.ts @@ -0,0 +1,47 @@ +/** + * Internal dependencies + */ +import type { Context, ContextualField, OmitNevers } from './helpers'; + +import type { BaseEntityRecords as _BaseEntityRecords } from './base-entity-records'; + +declare module './base-entity-records' { + export namespace BaseEntityRecords { + export interface GlobalStylesRevision< C extends Context > { + /** + * The ID for the author of the global styles revision. + */ + author: number; + /** + * The date the post global styles revision published, in the site's timezone. + */ + date: string | null; + /** + * The date the global styles revision was published, as GMT. + */ + date_gmt: ContextualField< string | null, 'view' | 'edit', C >; + /** + * Unique identifier for the revision. + */ + id: number; + /** + * The date the global styles revision was last modified, in the site's timezone. + */ + modified: ContextualField< string, 'view' | 'edit', C >; + /** + * The date the global styles revision was last modified, as GMT. + */ + modified_gmt: ContextualField< string, 'view' | 'edit', C >; + /** + * Identifier for the parent of the revision. + */ + parent: number; + styles: Record< string, Object >; + settings: Record< string, Object >; + } + } +} + +export type GlobalStylesRevision< C extends Context = 'view' > = OmitNevers< + _BaseEntityRecords.GlobalStylesRevision< C > +>; diff --git a/packages/core-data/src/entity-types/index.ts b/packages/core-data/src/entity-types/index.ts index 19d10a28ad698e..0e601137cbcb6c 100644 --- a/packages/core-data/src/entity-types/index.ts +++ b/packages/core-data/src/entity-types/index.ts @@ -4,12 +4,14 @@ import type { Context, Updatable } from './helpers'; import type { Attachment } from './attachment'; import type { Comment } from './comment'; +import type { GlobalStylesRevision } from './global-styles-revision'; import type { MenuLocation } from './menu-location'; import type { NavMenu } from './nav-menu'; import type { NavMenuItem } from './nav-menu-item'; import type { Page } from './page'; import type { Plugin } from './plugin'; import type { Post } from './post'; +import type { PostRevision } from './post-revision'; import type { Settings } from './settings'; import type { Sidebar } from './sidebar'; import type { Taxonomy } from './taxonomy'; @@ -27,12 +29,14 @@ export type { Attachment, Comment, Context, + GlobalStylesRevision, MenuLocation, NavMenu, NavMenuItem, Page, Plugin, Post, + PostRevision, Settings, Sidebar, Taxonomy, @@ -82,12 +86,14 @@ export interface PerPackageEntityRecords< C extends Context > { core: | Attachment< C > | Comment< C > + | GlobalStylesRevision< C > | MenuLocation< C > | NavMenu< C > | NavMenuItem< C > | Page< C > | Plugin< C > | Post< C > + | PostRevision< C > | Settings< C > | Sidebar< C > | Taxonomy< C > diff --git a/packages/core-data/src/entity-types/post-revision.ts b/packages/core-data/src/entity-types/post-revision.ts new file mode 100644 index 00000000000000..354a3fc02af704 --- /dev/null +++ b/packages/core-data/src/entity-types/post-revision.ts @@ -0,0 +1,93 @@ +/** + * Internal dependencies + */ +import type { + Context, + ContextualField, + RenderedText, + OmitNevers, +} from './helpers'; + +import type { BaseEntityRecords as _BaseEntityRecords } from './base-entity-records'; + +declare module './base-entity-records' { + export namespace BaseEntityRecords { + export interface PostRevision< C extends Context > { + /** + * The ID for the author of the post revision. + */ + author: number; + /** + * The content for the post. + */ + content: ContextualField< + RenderedText< C > & { + /** + * Whether the content is protected with a password. + */ + is_protected: boolean; + /** + * Version of the content block format used by the post. + */ + block_version: ContextualField< string, 'edit', C >; + }, + 'view' | 'edit', + C + >; + /** + * The date the post was published, in the site's timezone. + */ + date: string | null; + /** + * The date the post was published, as GMT. + */ + date_gmt: ContextualField< string | null, 'view' | 'edit', C >; + /** + * The excerpt for the post revision. + */ + excerpt: RenderedText< C > & { + protected: boolean; + }; + /** + * The globally unique identifier for the post. + */ + guid: ContextualField< RenderedText< C >, 'view' | 'edit', C >; + /** + * Unique identifier for the revision. + */ + id: number; + /** + * Meta fields. + */ + meta: ContextualField< + Record< string, string >, + 'view' | 'edit', + C + >; + /** + * The date the post was last modified, in the site's timezone. + */ + modified: ContextualField< string, 'view' | 'edit', C >; + /** + * The date the post revision was last modified, as GMT. + */ + modified_gmt: ContextualField< string, 'view' | 'edit', C >; + /** + * Identifier for the parent of the revision. + */ + parent: number; + /** + * An alphanumeric identifier for the post unique to its type. + */ + slug: string; + /** + * The title for the post revision. + */ + title: RenderedText< C >; + } + } +} + +export type PostRevision< C extends Context = 'view' > = OmitNevers< + _BaseEntityRecords.PostRevision< C > +>; diff --git a/packages/core-data/src/reducer.js b/packages/core-data/src/reducer.js index a21623d8ba89d3..34558fcfbb142e 100644 --- a/packages/core-data/src/reducer.js +++ b/packages/core-data/src/reducer.js @@ -245,7 +245,6 @@ function entity( entityConfig ) { ] )( combineReducers( { queriedData: queriedDataReducer, - edits: ( state = {}, action ) => { switch ( action.type ) { case 'RECEIVE_ITEMS': @@ -355,6 +354,52 @@ function entity( entityConfig ) { return state; }, + + // Add revisions to the state tree if the post type supports it. + ...( entityConfig?.supports?.revisions + ? { + revisions: ( state = {}, action ) => { + // Use the same queriedDataReducer shape for revisions. + if ( action.type === 'RECEIVE_ITEM_REVISIONS' ) { + const recordKey = action.recordKey; + delete action.recordKey; + const newState = queriedDataReducer( + state[ recordKey ], + { + ...action, + type: 'RECEIVE_ITEMS', + } + ); + return { + ...state, + [ recordKey ]: newState, + }; + } + + if ( action.type === 'REMOVE_ITEMS' ) { + return Object.fromEntries( + Object.entries( state ).filter( + ( [ id ] ) => + ! action.itemIds.some( + ( itemId ) => { + if ( + Number.isInteger( + itemId + ) + ) { + return itemId === +id; + } + return itemId === id; + } + ) + ) + ); + } + + return state; + }, + } + : {} ), } ) ); } diff --git a/packages/core-data/src/resolvers.js b/packages/core-data/src/resolvers.js index cd2a65a60b0139..8735764a880b8b 100644 --- a/packages/core-data/src/resolvers.js +++ b/packages/core-data/src/resolvers.js @@ -244,7 +244,7 @@ export const getEntityRecords = // If we request fields but the result doesn't contain the fields, // explicitly set these fields as "undefined" - // that way we consider the query "fullfilled". + // that way we consider the query "fulfilled". if ( query._fields ) { records = records.map( ( record ) => { query._fields.split( ',' ).forEach( ( field ) => { @@ -322,7 +322,7 @@ export const getCurrentTheme = export const getThemeSupports = forwardResolver( 'getCurrentTheme' ); /** - * Requests a preview from the from the Embed API. + * Requests a preview from the Embed API. * * @param {string} url URL to get the preview for. */ @@ -718,3 +718,146 @@ export const getDefaultTemplateId = dispatch.receiveDefaultTemplateId( query, template.id ); } }; + +/** + * Requests an entity's revisions from the REST API. + * + * @param {string} kind Entity kind. + * @param {string} name Entity name. + * @param {number|string} recordKey The key of the entity record whose revisions you want to fetch. + * @param {Object|undefined} query Optional object of query parameters to + * include with request. If requesting specific + * fields, fields must always include the ID. + */ +export const getRevisions = + ( kind, name, recordKey, query = {} ) => + async ( { dispatch } ) => { + const configs = await dispatch( getOrLoadEntitiesConfig( kind ) ); + const entityConfig = configs.find( + ( config ) => config.name === name && config.kind === kind + ); + + if ( + ! entityConfig || + entityConfig?.__experimentalNoFetch || + ! entityConfig?.supports?.revisions + ) { + return; + } + + if ( query._fields ) { + // If requesting specific fields, items and query association to said + // records are stored by ID reference. Thus, fields must always include + // the ID. + query = { + ...query, + _fields: [ + ...new Set( [ + ...( getNormalizedCommaSeparable( query._fields ) || + [] ), + DEFAULT_ENTITY_KEY, + ] ), + ].join(), + }; + } + + const path = addQueryArgs( + entityConfig.getRevisionsUrl( recordKey ), + query + ); + + let records, meta; + if ( entityConfig.supportsPagination && query.per_page !== -1 ) { + const response = await apiFetch( { path, parse: false } ); + records = Object.values( await response.json() ); + meta = { + totalItems: parseInt( response.headers.get( 'X-WP-Total' ) ), + }; + } else { + records = Object.values( await apiFetch( { path } ) ); + } + + // If we request fields but the result doesn't contain the fields, + // explicitly set these fields as "undefined" + // that way we consider the query "fulfilled". + if ( query._fields ) { + records = records.map( ( record ) => { + query._fields.split( ',' ).forEach( ( field ) => { + if ( ! record.hasOwnProperty( field ) ) { + record[ field ] = undefined; + } + } ); + + return record; + } ); + } + + dispatch.receiveRevisions( + kind, + name, + recordKey, + records, + query, + false, + meta + ); + }; + +// Invalidate cache when a new revision is created. +getRevisions.shouldInvalidate = ( action, kind, name, recordKey ) => + action.type === 'SAVE_ENTITY_RECORD_FINISH' && + name === action.name && + kind === action.kind && + ! action.error && + recordKey === action.recordId; + +/** + * Requests a specific Entity revision from the REST API. + * + * @param {string} kind Entity kind. + * @param {string} name Entity name. + * @param {number|string} recordKey The key of the entity record whose revisions you want to fetch. + * @param {number|string} revisionKey The revision's key. + * @param {Object|undefined} query Optional object of query parameters to + * include with request. If requesting specific + * fields, fields must always include the ID. + */ +export const getRevision = + ( kind, name, recordKey, revisionKey, query = {} ) => + async ( { dispatch } ) => { + const configs = await dispatch( getOrLoadEntitiesConfig( kind ) ); + const entityConfig = configs.find( + ( config ) => config.name === name && config.kind === kind + ); + + if ( + ! entityConfig || + entityConfig?.__experimentalNoFetch || + ! entityConfig?.supports?.revisions + ) { + return; + } + + if ( query !== undefined && query._fields ) { + // If requesting specific fields, items and query association to said + // records are stored by ID reference. Thus, fields must always include + // the ID. + query = { + ...query, + _fields: [ + ...new Set( [ + ...( getNormalizedCommaSeparable( query._fields ) || + [] ), + DEFAULT_ENTITY_KEY, + ] ), + ].join(), + }; + } + const path = addQueryArgs( + entityConfig.getRevisionsUrl( recordKey, revisionKey ), + query + ); + + const record = await apiFetch( { path } ); + dispatch.receiveRevisions( kind, name, recordKey, record, query ); + }; diff --git a/packages/core-data/src/selectors.ts b/packages/core-data/src/selectors.ts index 2a046941611c7d..4a893f5557d862 100644 --- a/packages/core-data/src/selectors.ts +++ b/packages/core-data/src/selectors.ts @@ -62,6 +62,16 @@ interface QueriedData { queries: Record< ET.Context, Record< string, Array< number > > >; } +type RevisionRecord = + | Record< ET.Context, Record< number, ET.PostRevision > > + | Record< ET.Context, Record< number, ET.GlobalStylesRevision > >; + +interface RevisionsQueriedData { + items: RevisionRecord; + itemIsComplete: Record< ET.Context, Record< number, boolean > >; + queries: Record< ET.Context, Record< string, Array< number > > >; +} + interface EntityState< EntityRecord extends ET.EntityRecord > { edits: Record< string, Partial< EntityRecord > >; saving: Record< @@ -70,6 +80,7 @@ interface EntityState< EntityRecord extends ET.EntityRecord > { >; deleting: Record< string, Partial< { pending: boolean; error: Error } > >; queriedData: QueriedData; + revisions?: RevisionsQueriedData; } interface EntityConfig { @@ -1373,3 +1384,103 @@ export function getDefaultTemplateId( ): string { return state.defaultTemplates[ JSON.stringify( query ) ]; } + +/** + * Returns an entity's revisions. + * + * @param state State tree + * @param kind Entity kind. + * @param name Entity name. + * @param recordKey The key of the entity record whose revisions you want to fetch. + * @param query Optional query. If requesting specific + * fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [Entity kind]". + * + * @return Record. + */ +export const getRevisions = ( + state: State, + kind: string, + name: string, + recordKey: EntityRecordKey, + query?: GetRecordsHttpQuery +): RevisionRecord[] | null => { + const queriedStateRevisions = + state.entities.records?.[ kind ]?.[ name ]?.revisions?.[ recordKey ]; + if ( ! queriedStateRevisions ) { + return null; + } + + return getQueriedItems( queriedStateRevisions, query ); +}; + +/** + * Returns a single, specific revision of a parent entity. + * + * @param state State tree + * @param kind Entity kind. + * @param name Entity name. + * @param recordKey The key of the entity record whose revisions you want to fetch. + * @param revisionKey The revision's key. + * @param query Optional query. If requesting specific + * fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [entity kind]". + * + * @return Record. + */ +export const getRevision = createSelector( + ( + state: State, + kind: string, + name: string, + recordKey: EntityRecordKey, + revisionKey: EntityRecordKey, + query?: GetRecordsHttpQuery + ): RevisionRecord | Record< PropertyKey, never > | undefined => { + const queriedState = + state.entities.records?.[ kind ]?.[ name ]?.revisions?.[ + recordKey + ]; + + if ( ! queriedState ) { + return undefined; + } + + const context = query?.context ?? 'default'; + + if ( query === undefined ) { + // If expecting a complete item, validate that completeness. + if ( ! queriedState.itemIsComplete[ context ]?.[ revisionKey ] ) { + return undefined; + } + + return queriedState.items[ context ][ revisionKey ]; + } + + const item = queriedState.items[ context ]?.[ revisionKey ]; + if ( item && query._fields ) { + const filteredItem = {}; + const fields = getNormalizedCommaSeparable( query._fields ) ?? []; + + for ( let f = 0; f < fields.length; f++ ) { + const field = fields[ f ].split( '.' ); + let value = item; + field.forEach( ( fieldName ) => { + value = value?.[ fieldName ]; + } ); + setNestedValue( filteredItem, field, value ); + } + + return filteredItem; + } + + return item; + }, + ( state: State, kind, name, recordKey, revisionKey, query ) => { + const context = query?.context ?? 'default'; + return [ + state.entities.records?.[ kind ]?.[ name ]?.revisions?.[ recordKey ] + ?.items?.[ context ]?.[ revisionKey ], + state.entities.records?.[ kind ]?.[ name ]?.revisions?.[ recordKey ] + ?.itemIsComplete?.[ context ]?.[ revisionKey ], + ]; + } +); diff --git a/packages/core-data/src/test/entities.js b/packages/core-data/src/test/entities.js index 9afbbb8de055e1..c9a432c92c1442 100644 --- a/packages/core-data/src/test/entities.js +++ b/packages/core-data/src/test/entities.js @@ -80,6 +80,9 @@ describe( 'getKindEntities', () => { labels: { singular_name: 'post', }, + supports: { + revisions: true, + }, }, ]; const dispatch = jest.fn(); @@ -95,6 +98,12 @@ describe( 'getKindEntities', () => { expect( dispatch.mock.calls[ 0 ][ 0 ].entities[ 0 ].baseURL ).toBe( '/wp/v2/posts' ); + expect( + dispatch.mock.calls[ 0 ][ 0 ].entities[ 0 ].getRevisionsUrl( 1 ) + ).toBe( '/wp/v2/posts/1/revisions' ); + expect( + dispatch.mock.calls[ 0 ][ 0 ].entities[ 0 ].getRevisionsUrl( 1, 2 ) + ).toBe( '/wp/v2/posts/1/revisions/2' ); } ); } ); diff --git a/packages/core-data/src/test/reducer.js b/packages/core-data/src/test/reducer.js index 4142f65af4c7c4..d5d5bc5c8692fa 100644 --- a/packages/core-data/src/test/reducer.js +++ b/packages/core-data/src/test/reducer.js @@ -139,6 +139,241 @@ describe( 'entities', () => { .map( ( [ , cfg ] ) => cfg ) ).toEqual( [ { kind: 'postType', name: 'posts' } ] ); } ); + + describe( 'entity revisions', () => { + const stateWithConfig = entities( undefined, { + type: 'ADD_ENTITIES', + entities: [ + { + kind: 'root', + name: 'postType', + supports: { revisions: true }, + }, + ], + } ); + it( 'appends revisions state', () => { + expect( stateWithConfig.records.root.postType ).toHaveProperty( + 'revisions', + {} + ); + } ); + + it( 'returns with received revisions', () => { + const initialState = deepFreeze( { + config: stateWithConfig.config, + records: {}, + } ); + const state = entities( initialState, { + type: 'RECEIVE_ITEM_REVISIONS', + items: [ { id: 1, parent: 2 } ], + kind: 'root', + name: 'postType', + recordKey: 2, + } ); + expect( state.records.root.postType.revisions ).toEqual( { + 2: { + items: { + default: { + 1: { id: 1, parent: 2 }, + }, + }, + itemIsComplete: { + default: { + 1: true, + }, + }, + queries: {}, + }, + } ); + } ); + + it( 'returns with appended received revisions at the parent level', () => { + const initialState = deepFreeze( { + config: stateWithConfig.config, + records: { + root: { + postType: { + revisions: { + 2: { + items: { + default: { + 1: { id: 1, parent: 2 }, + }, + }, + itemIsComplete: { + default: { + 1: true, + }, + }, + queries: {}, + }, + }, + }, + }, + }, + } ); + const state = entities( initialState, { + type: 'RECEIVE_ITEM_REVISIONS', + items: [ { id: 3, parent: 4 } ], + kind: 'root', + name: 'postType', + recordKey: 4, + } ); + expect( state.records.root.postType.revisions ).toEqual( { + 2: { + items: { + default: { + 1: { id: 1, parent: 2 }, + }, + }, + itemIsComplete: { + default: { + 1: true, + }, + }, + queries: {}, + }, + 4: { + items: { + default: { + 3: { id: 3, parent: 4 }, + }, + }, + itemIsComplete: { + default: { + 3: true, + }, + }, + queries: {}, + }, + } ); + } ); + + it( 'returns with appended received revision items', () => { + const initialState = deepFreeze( { + config: stateWithConfig.config, + records: { + root: { + postType: { + revisions: { + 2: { + items: { + default: { + 1: { id: 1, parent: 2 }, + }, + }, + itemIsComplete: { + default: { + 1: true, + }, + }, + queries: {}, + }, + }, + }, + }, + }, + } ); + const state = entities( initialState, { + type: 'RECEIVE_ITEM_REVISIONS', + items: [ { id: 7, parent: 2 } ], + kind: 'root', + name: 'postType', + recordKey: 2, + } ); + expect( state.records.root.postType.revisions ).toEqual( { + 2: { + items: { + default: { + 1: { id: 1, parent: 2 }, + 7: { id: 7, parent: 2 }, + }, + }, + itemIsComplete: { + default: { + 1: true, + 7: true, + }, + }, + queries: {}, + }, + } ); + } ); + + it( 'returns with removed revision items', () => { + const initialState = deepFreeze( { + config: stateWithConfig.config, + records: { + root: { + postType: { + revisions: { + 2: { + items: { + default: { + 1: { id: 1, parent: 2 }, + }, + }, + itemIsComplete: { + default: { + 1: true, + }, + }, + queries: {}, + }, + 4: { + items: { + default: { + 3: { id: 3, parent: 4 }, + }, + }, + itemIsComplete: { + default: { + 3: true, + }, + }, + queries: {}, + }, + 6: { + items: { + default: { + 9: { id: 11, parent: 6 }, + }, + }, + itemIsComplete: { + default: { + 9: true, + }, + }, + queries: {}, + }, + }, + }, + }, + }, + } ); + const state = entities( initialState, { + type: 'REMOVE_ITEMS', + itemIds: [ 4, 6 ], + kind: 'root', + name: 'postType', + } ); + expect( state.records.root.postType.revisions ).toEqual( { + 2: { + items: { + default: { + 1: { id: 1, parent: 2 }, + }, + }, + itemIsComplete: { + default: { + 1: true, + }, + }, + queries: {}, + }, + } ); + } ); + } ); } ); describe( 'embedPreviews()', () => { diff --git a/packages/core-data/src/test/selectors.js b/packages/core-data/src/test/selectors.js index b7c583098c4a5c..43c84a3e978917 100644 --- a/packages/core-data/src/test/selectors.js +++ b/packages/core-data/src/test/selectors.js @@ -22,6 +22,8 @@ import { getAutosave, getAutosaves, getCurrentUser, + getRevisions, + getRevision, } from '../selectors'; // getEntityRecord and __experimentalGetEntityRecordNoResolver selectors share the same tests. describe.each( [ @@ -896,3 +898,97 @@ describe( 'getCurrentUser', () => { expect( getCurrentUser( state ) ).toEqual( currentUser ); } ); } ); + +describe( 'getRevisions', () => { + it( 'should return revisions', () => { + const state = deepFreeze( { + entities: { + records: { + postType: { + post: { + revisions: { + 1: { + items: { + default: { + 10: { + id: 10, + content: 'chicken', + author: 'bob', + parent: 1, + }, + }, + }, + itemIsComplete: { + default: { + 10: true, + }, + }, + queries: { + default: { + '': { itemIds: [ 10 ] }, + }, + }, + }, + }, + }, + }, + }, + }, + } ); + + expect( getRevisions( state, 'postType', 'post', 1 ) ).toEqual( [ + { + id: 10, + content: 'chicken', + author: 'bob', + parent: 1, + }, + ] ); + } ); +} ); + +describe( 'getRevision', () => { + it( 'should return a specific revision', () => { + const state = deepFreeze( { + entities: { + records: { + postType: { + post: { + revisions: { + 1: { + items: { + default: { + 10: { + id: 10, + content: 'chicken', + author: 'bob', + parent: 1, + }, + }, + }, + itemIsComplete: { + default: { + 10: true, + }, + }, + queries: { + default: { + '': [ 10 ], + }, + }, + }, + }, + }, + }, + }, + }, + } ); + + expect( getRevision( state, 'postType', 'post', 1, 10 ) ).toEqual( { + id: 10, + content: 'chicken', + author: 'bob', + parent: 1, + } ); + } ); +} ); From 0b153a408a6e1ba14e84e58845347b3735869a36 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Mon, 20 Nov 2023 22:50:32 +0000 Subject: [PATCH 088/116] Migrating `BlockPatternSetup` to use updated `Composite` implementation (#55425) - Removes `__unstableComposite` imports from `@wordpress/components` - Adds private `Composite*` exports from `@wordpress/components` - Refactors `BlockPatternSetup` and subcomponents to use updated `Composite` components - Additionally adds image semantics, and ensures buttons are available when disabled --- .../components/block-pattern-setup/index.js | 60 ++++++++++++------- .../block-pattern-setup/setup-toolbar.js | 2 + .../components/block-pattern-setup/style.scss | 5 +- 3 files changed, 44 insertions(+), 23 deletions(-) diff --git a/packages/block-editor/src/components/block-pattern-setup/index.js b/packages/block-editor/src/components/block-pattern-setup/index.js index 22d51466b3b6e9..edd55e90dc3e27 100644 --- a/packages/block-editor/src/components/block-pattern-setup/index.js +++ b/packages/block-editor/src/components/block-pattern-setup/index.js @@ -5,9 +5,7 @@ import { useDispatch } from '@wordpress/data'; import { cloneBlock } from '@wordpress/blocks'; import { VisuallyHidden, - __unstableComposite as Composite, - __unstableUseCompositeState as useCompositeState, - __unstableCompositeItem as CompositeItem, + privateApis as componentsPrivateApis, } from '@wordpress/components'; import { useState } from '@wordpress/element'; @@ -22,6 +20,13 @@ import BlockPreview from '../block-preview'; import SetupToolbar from './setup-toolbar'; import usePatternsSetup from './use-patterns-setup'; import { VIEWMODES } from './constants'; +import { unlock } from '../../lock-unlock'; + +const { + CompositeV2: Composite, + CompositeItemV2: CompositeItem, + useCompositeStoreV2: useCompositeStore, +} = unlock( componentsPrivateApis ); const SetupContent = ( { viewMode, @@ -30,8 +35,9 @@ const SetupContent = ( { onBlockPatternSelect, showTitles, } ) => { - const composite = useCompositeState(); + const compositeStore = useCompositeStore(); const containerClass = 'block-editor-block-pattern-setup__container'; + if ( viewMode === VIEWMODES.carousel ) { const slideClass = new Map( [ [ activeSlide, 'active-slide' ], @@ -41,23 +47,25 @@ const SetupContent = ( { return (
    -
      +
      { patterns.map( ( pattern, index ) => ( ) ) } -
    +
    ); } + return (
    ) ) } @@ -76,7 +83,7 @@ const SetupContent = ( { ); }; -function BlockPattern( { pattern, onSelect, composite, showTitles } ) { +function BlockPattern( { pattern, onSelect, showTitles } ) { const baseClassName = 'block-editor-block-pattern-setup-list'; const { blocks, description, viewportWidth = 700 } = pattern; const descriptionId = useInstanceId( @@ -84,16 +91,19 @@ function BlockPattern( { pattern, onSelect, composite, showTitles } ) { `${ baseClassName }__item-description` ); return ( -
    +
    + } + id={ `${ baseClassName }__pattern__${ pattern.name }` } role="option" - as="div" - { ...composite } - className={ `${ baseClassName }__item` } onClick={ () => onSelect( blocks ) } > ) } -
  2. + ); } @@ -178,10 +190,14 @@ const BlockPatternSetup = ( { activeSlide={ activeSlide } totalSlides={ patterns.length } handleNext={ () => { - setActiveSlide( ( active ) => active + 1 ); + setActiveSlide( ( active ) => + Math.min( active + 1, patterns.length - 1 ) + ); } } handlePrevious={ () => { - setActiveSlide( ( active ) => active - 1 ); + setActiveSlide( ( active ) => + Math.max( active - 1, 0 ) + ); } } onBlockPatternSelect={ () => { onPatternSelectCallback( diff --git a/packages/block-editor/src/components/block-pattern-setup/setup-toolbar.js b/packages/block-editor/src/components/block-pattern-setup/setup-toolbar.js index 69922f9560ab0b..91b68456cda71c 100644 --- a/packages/block-editor/src/components/block-pattern-setup/setup-toolbar.js +++ b/packages/block-editor/src/components/block-pattern-setup/setup-toolbar.js @@ -35,12 +35,14 @@ const CarouselNavigation = ( { label={ __( 'Previous pattern' ) } onClick={ handlePrevious } disabled={ activeSlide === 0 } + __experimentalIsFocusable />
{ row.getVisibleCells().map( ( cell ) => (
item.id } isLoading={ isLoadingPages || isLoadingAuthors } view={ view } onChangeView={ onChangeView } diff --git a/packages/edit-site/src/components/page-templates/dataviews-templates.js b/packages/edit-site/src/components/page-templates/dataviews-templates.js index ce4927895b29be..39a9d1b60abad6 100644 --- a/packages/edit-site/src/components/page-templates/dataviews-templates.js +++ b/packages/edit-site/src/components/page-templates/dataviews-templates.js @@ -214,6 +214,7 @@ export default function DataviewsTemplates() { fields={ fields } actions={ actions } data={ shownTemplates } + getItemId={ ( item ) => item.id } isLoading={ isLoadingData } view={ view } onChangeView={ onChangeView } From 3e42c038cbcbcccbe95bade99e1811a951d1ef1e Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Tue, 21 Nov 2023 13:07:10 +0100 Subject: [PATCH 098/116] Site Editor: Add the Post Author component to the Page sidebar (#56368) --- .../components/sidebar/post-author/index.js | 20 ------------------- .../components/sidebar/post-author/style.scss | 5 ----- .../components/sidebar/post-status/index.js | 4 ++-- packages/edit-post/src/style.scss | 1 - .../page-panels/page-summary.js | 9 +++++++-- packages/editor/src/components/index.js | 1 + .../src/components/post-author/panel.js | 18 +++++++++++++++++ .../src/components/post-author/style.scss | 7 +++++++ .../src/components/post-panel-row/index.js | 14 +++---------- .../src/components/post-panel-row/style.scss | 3 +++ packages/editor/src/style.scss | 1 + 11 files changed, 42 insertions(+), 41 deletions(-) delete mode 100644 packages/edit-post/src/components/sidebar/post-author/index.js delete mode 100644 packages/edit-post/src/components/sidebar/post-author/style.scss create mode 100644 packages/editor/src/components/post-author/panel.js create mode 100644 packages/editor/src/components/post-author/style.scss diff --git a/packages/edit-post/src/components/sidebar/post-author/index.js b/packages/edit-post/src/components/sidebar/post-author/index.js deleted file mode 100644 index 8f5eca9aea46b4..00000000000000 --- a/packages/edit-post/src/components/sidebar/post-author/index.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * WordPress dependencies - */ -import { PanelRow } from '@wordpress/components'; -import { - PostAuthor as PostAuthorForm, - PostAuthorCheck, -} from '@wordpress/editor'; - -export function PostAuthor() { - return ( - - - - - - ); -} - -export default PostAuthor; diff --git a/packages/edit-post/src/components/sidebar/post-author/style.scss b/packages/edit-post/src/components/sidebar/post-author/style.scss deleted file mode 100644 index bfc80bdd2cf702..00000000000000 --- a/packages/edit-post/src/components/sidebar/post-author/style.scss +++ /dev/null @@ -1,5 +0,0 @@ -.edit-post-post-author { - display: flex; - flex-direction: column; - align-items: stretch; -} diff --git a/packages/edit-post/src/components/sidebar/post-status/index.js b/packages/edit-post/src/components/sidebar/post-status/index.js index ba6afa2ae9f275..1b24de6082d160 100644 --- a/packages/edit-post/src/components/sidebar/post-status/index.js +++ b/packages/edit-post/src/components/sidebar/post-status/index.js @@ -8,6 +8,7 @@ import { } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; import { + PostAuthorPanel, PostSchedulePanel, PostSwitchToDraftButton, PostSyncStatus, @@ -20,7 +21,6 @@ import { import PostVisibility from '../post-visibility'; import PostTrash from '../post-trash'; import PostSticky from '../post-sticky'; -import PostAuthor from '../post-author'; import PostSlug from '../post-slug'; import PostFormat from '../post-format'; import PostPendingStatus from '../post-pending-status'; @@ -69,7 +69,7 @@ export default function PostStatus() { - + { fills } + + ); } diff --git a/packages/editor/src/components/index.js b/packages/editor/src/components/index.js index a5a4fc7fcac365..a3dfc991523225 100644 --- a/packages/editor/src/components/index.js +++ b/packages/editor/src/components/index.js @@ -26,6 +26,7 @@ export { default as PageAttributesParent } from './page-attributes/parent'; export { default as PageTemplate } from './post-template'; export { default as PostAuthor } from './post-author'; export { default as PostAuthorCheck } from './post-author/check'; +export { default as PostAuthorPanel } from './post-author/panel'; export { default as PostComments } from './post-comments'; export { default as PostExcerpt } from './post-excerpt'; export { default as PostExcerptCheck } from './post-excerpt/check'; diff --git a/packages/editor/src/components/post-author/panel.js b/packages/editor/src/components/post-author/panel.js new file mode 100644 index 00000000000000..78f0e0a5f2cc89 --- /dev/null +++ b/packages/editor/src/components/post-author/panel.js @@ -0,0 +1,18 @@ +/** + * Internal dependencies + */ +import PostAuthorCheck from './check'; +import PostAuthorForm from './index'; +import PostPanelRow from '../post-panel-row'; + +export function PostAuthor() { + return ( + + + + + + ); +} + +export default PostAuthor; diff --git a/packages/editor/src/components/post-author/style.scss b/packages/editor/src/components/post-author/style.scss new file mode 100644 index 00000000000000..349ad712334c8d --- /dev/null +++ b/packages/editor/src/components/post-author/style.scss @@ -0,0 +1,7 @@ +.editor-post-author__panel { + padding-top: $grid-unit-10; +} + +.editor-post-author__panel .editor-post-panel__row-control > div { + width: 100%; +} diff --git a/packages/editor/src/components/post-panel-row/index.js b/packages/editor/src/components/post-panel-row/index.js index a746486ea25f64..f6f0c658cd7240 100644 --- a/packages/editor/src/components/post-panel-row/index.js +++ b/packages/editor/src/components/post-panel-row/index.js @@ -15,18 +15,10 @@ const PostPanelRow = forwardRef( ( { className, label, children }, ref ) => { className={ classnames( 'editor-post-panel__row', className ) } ref={ ref } > - { label ? ( - <> -
- { label } -
-
- { children } -
- - ) : ( - children + { label && ( +
{ label }
) } +
{ children }
); } ); diff --git a/packages/editor/src/components/post-panel-row/style.scss b/packages/editor/src/components/post-panel-row/style.scss index b3dfc8c6bcf6b0..bc1c7fbd000c63 100644 --- a/packages/editor/src/components/post-panel-row/style.scss +++ b/packages/editor/src/components/post-panel-row/style.scss @@ -15,4 +15,7 @@ .editor-post-panel__row-control { flex-grow: 1; + min-height: $button-size; + display: flex; + align-items: center; } diff --git a/packages/editor/src/style.scss b/packages/editor/src/style.scss index 5861764ff8737f..ccc26e23b430b0 100644 --- a/packages/editor/src/style.scss +++ b/packages/editor/src/style.scss @@ -3,6 +3,7 @@ @import "./components/editor-notices/style.scss"; @import "./components/entities-saved-states/style.scss"; @import "./components/error-boundary/style.scss"; +@import "./components/post-author/style.scss"; @import "./components/post-excerpt/style.scss"; @import "./components/post-featured-image/style.scss"; @import "./components/post-format/style.scss"; From e95bb8c9530bbdef1db623eca11b80bd73493197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20K=C3=A4gy?= Date: Tue, 21 Nov 2023 13:48:12 +0100 Subject: [PATCH 099/116] Fix version in useSetting deprecation notice (#56377) --- packages/block-editor/README.md | 2 +- packages/block-editor/src/components/use-settings/index.js | 4 ++-- .../block-editor/src/components/use-settings/test/index.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index 9c7a72f0897143..2d6a5627a52a44 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -954,7 +954,7 @@ _Parameters_ ### useSetting -> **Deprecated** 6.4.0 Use useSettings instead. +> **Deprecated** 6.5.0 Use useSettings instead. Hook that retrieves the given setting for the block instance in use. diff --git a/packages/block-editor/src/components/use-settings/index.js b/packages/block-editor/src/components/use-settings/index.js index 12a442c5c98f37..36be1f914baf26 100644 --- a/packages/block-editor/src/components/use-settings/index.js +++ b/packages/block-editor/src/components/use-settings/index.js @@ -254,7 +254,7 @@ export function useSettings( ...paths ) { * * @param {string} path The path to the setting. * @return {any} Returns the value defined for the setting. - * @deprecated 6.4.0 Use useSettings instead. + * @deprecated 6.5.0 Use useSettings instead. * @example * ```js * const isEnabled = useSetting( 'typography.dropCap' ); @@ -262,7 +262,7 @@ export function useSettings( ...paths ) { */ export function useSetting( path ) { deprecated( 'wp.blockEditor.useSetting', { - since: '6.4', + since: '6.5', alternative: 'wp.blockEditor.useSettings', note: 'The new useSettings function can retrieve multiple settings at once, with better performance.', } ); diff --git a/packages/block-editor/src/components/use-settings/test/index.js b/packages/block-editor/src/components/use-settings/test/index.js index 89de12655338f0..c9174cf35df5f7 100644 --- a/packages/block-editor/src/components/use-settings/test/index.js +++ b/packages/block-editor/src/components/use-settings/test/index.js @@ -135,7 +135,7 @@ describe( 'useSettings', () => { const result = runHook( () => useSetting( 'layout.contentSize' ) ); expect( result ).toBe( '840px' ); expect( console ).toHaveWarnedWith( - 'wp.blockEditor.useSetting is deprecated since version 6.4. Please use wp.blockEditor.useSettings instead.' + 'wp.blockEditor.useSetting is deprecated since version 6.5. Please use wp.blockEditor.useSettings instead.' ); } ); } ); From 68b0d5b1db1a154e1b92f6ca2148a7e8ad0ef6fc Mon Sep 17 00:00:00 2001 From: Ramon Date: Wed, 22 Nov 2023 08:00:19 +1100 Subject: [PATCH 100/116] Global styles revisions: migrate API call to getRevisions() (#56349) * Migrating global styles revisions to new core data API and deprecating *ThemeGlobalStyleRevision selector and action. * Limiting the results to 100 --- docs/reference-guides/data/data-core.md | 2 ++ packages/core-data/README.md | 2 ++ packages/core-data/src/actions.js | 9 +++++++++ packages/core-data/src/selectors.ts | 9 ++++++++- .../screen-revisions/use-global-styles-revisions.js | 12 ++++++++++-- 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md index 6084eff930394a..b2a75638ace9fe 100644 --- a/docs/reference-guides/data/data-core.md +++ b/docs/reference-guides/data/data-core.md @@ -128,6 +128,8 @@ _Returns_ ### getCurrentThemeGlobalStylesRevisions +> **Deprecated** since WordPress 6.5.0. Callers should use `select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )` instead, where `recordKey` is the id of the global styles parent post. + Returns the revisions of the current global styles theme. _Parameters_ diff --git a/packages/core-data/README.md b/packages/core-data/README.md index f7a177b5c55872..ebc467f7fede2d 100644 --- a/packages/core-data/README.md +++ b/packages/core-data/README.md @@ -453,6 +453,8 @@ _Returns_ ### getCurrentThemeGlobalStylesRevisions +> **Deprecated** since WordPress 6.5.0. Callers should use `select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )` instead, where `recordKey` is the id of the global styles parent post. + Returns the revisions of the current global styles theme. _Parameters_ diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js index d71c5d6120089e..4c5622ac780589 100644 --- a/packages/core-data/src/actions.js +++ b/packages/core-data/src/actions.js @@ -218,6 +218,8 @@ export function receiveThemeSupports() { * Returns an action object used in signalling that the theme global styles CPT post revisions have been received. * Ignored from documentation as it's internal to the data store. * + * @deprecated since WordPress 6.5.0. Callers should use `dispatch( 'core' ).receiveRevision` instead. + * * @ignore * * @param {number} currentId The post id. @@ -226,6 +228,13 @@ export function receiveThemeSupports() { * @return {Object} Action object. */ export function receiveThemeGlobalStyleRevisions( currentId, revisions ) { + deprecated( + "wp.data.dispatch( 'core' ).receiveThemeGlobalStyleRevisions()", + { + since: '6.5.0', + alternative: "wp.data.dispatch( 'core' ).receiveRevisions", + } + ); return { type: 'RECEIVE_THEME_GLOBAL_STYLE_REVISIONS', currentId, diff --git a/packages/core-data/src/selectors.ts b/packages/core-data/src/selectors.ts index 4a893f5557d862..5751a80b9106cd 100644 --- a/packages/core-data/src/selectors.ts +++ b/packages/core-data/src/selectors.ts @@ -1353,13 +1353,20 @@ export function getUserPatternCategories( /** * Returns the revisions of the current global styles theme. * - * @param state Data state. + * @deprecated since WordPress 6.5.0. Callers should use `select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )` instead, where `recordKey` is the id of the global styles parent post. + * + * @param state Data state. * * @return The current global styles. */ export function getCurrentThemeGlobalStylesRevisions( state: State ): Array< object > | null { + deprecated( "select( 'core' ).getCurrentThemeGlobalStylesRevisions()", { + since: '6.5.0', + alternative: + "select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )", + } ); const currentGlobalStylesId = __experimentalGetCurrentGlobalStylesId( state ); diff --git a/packages/edit-site/src/components/global-styles/screen-revisions/use-global-styles-revisions.js b/packages/edit-site/src/components/global-styles/screen-revisions/use-global-styles-revisions.js index 6e3573061a4214..0c293e417cf8ef 100644 --- a/packages/edit-site/src/components/global-styles/screen-revisions/use-global-styles-revisions.js +++ b/packages/edit-site/src/components/global-styles/screen-revisions/use-global-styles-revisions.js @@ -32,14 +32,22 @@ export default function useGlobalStylesRevisions() { __experimentalGetDirtyEntityRecords, getCurrentUser, getUsers, - getCurrentThemeGlobalStylesRevisions, + getRevisions, + __experimentalGetCurrentGlobalStylesId, isResolving, } = select( coreStore ); const dirtyEntityRecords = __experimentalGetDirtyEntityRecords(); const _currentUser = getCurrentUser(); const _isDirty = dirtyEntityRecords.length > 0; const globalStylesRevisions = - getCurrentThemeGlobalStylesRevisions() || EMPTY_ARRAY; + getRevisions( + 'root', + 'globalStyles', + __experimentalGetCurrentGlobalStylesId(), + { + per_page: 100, + } + ) || EMPTY_ARRAY; const _authors = getUsers( SITE_EDITOR_AUTHORS_QUERY ) || EMPTY_ARRAY; return { From aa91684eb5e58384e6d9b6244d7d9dd3791ffb52 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 22 Nov 2023 10:21:22 +1300 Subject: [PATCH 101/116] Spacing theme.json - check that the first item in the units array is defined before trying to assign its value (#56306) --- .../input-controls/spacing-input-control.js | 2 +- schemas/json/theme.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/spacing-sizes-control/input-controls/spacing-input-control.js b/packages/block-editor/src/components/spacing-sizes-control/input-controls/spacing-input-control.js index a7efd10bce7125..7ef5c17f82943c 100644 --- a/packages/block-editor/src/components/spacing-sizes-control/input-controls/spacing-input-control.js +++ b/packages/block-editor/src/components/spacing-sizes-control/input-controls/spacing-input-control.js @@ -139,7 +139,7 @@ export default function SpacingInputControl( { useMemo( () => parseQuantityAndUnitFromRawValue( currentValue ), [ currentValue ] - )[ 1 ] || units[ 0 ].value; + )[ 1 ] || units[ 0 ]?.value; const setInitialValue = () => { if ( value === undefined ) { diff --git a/schemas/json/theme.json b/schemas/json/theme.json index 8414c939c8c7ae..5a24f1b16c1a35 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -364,7 +364,8 @@ "items": { "type": "string" }, - "default": [ "px", "em", "rem", "vh", "vw", "%" ] + "default": [ "px", "em", "rem", "vh", "vw", "%" ], + "minItems": 1 }, "customSpacingSize": { "description": "Allow users to set custom space sizes.", From c283c4419e2773203ca84a32901418c9210586f1 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 22 Nov 2023 14:28:46 +1300 Subject: [PATCH 102/116] Patterns: Fix bug with templates in replace template screen showing as synced patterns (#56407) --- .../components/block-patterns-list/index.js | 28 +++++++++++-------- .../block-patterns-explorer/pattern-list.js | 6 +++- .../pattern-category-previews.js | 6 +++- .../use-pattern-categories.js | 7 ++++- .../inserter/block-patterns-tab/utils.js | 8 ++++-- .../inserter/hooks/use-patterns-state.js | 4 ++- packages/block-editor/src/store/selectors.js | 2 ++ .../components/page-patterns/use-patterns.js | 2 +- .../src/components/duplicate-pattern-modal.js | 13 +++++---- 9 files changed, 51 insertions(+), 25 deletions(-) diff --git a/packages/block-editor/src/components/block-patterns-list/index.js b/packages/block-editor/src/components/block-patterns-list/index.js index bebeb1f44184cd..daf07fa5c7fc05 100644 --- a/packages/block-editor/src/components/block-patterns-list/index.js +++ b/packages/block-editor/src/components/block-patterns-list/index.js @@ -25,6 +25,7 @@ import { Icon, symbol } from '@wordpress/icons'; import BlockPreview from '../block-preview'; import InserterDraggableBlocks from '../inserter-draggable-blocks'; import BlockPatternsPaging from '../block-patterns-paging'; +import { PATTERN_TYPES } from '../inserter/block-patterns-tab/utils'; const WithToolTip = ( { showTooltip, title, children } ) => { if ( showTooltip ) { @@ -71,7 +72,9 @@ function BlockPattern( { } } > { @@ -107,15 +111,17 @@ function BlockPattern( { /> - { pattern.id && ! pattern.syncStatus && ( -
- -
- ) } - { ( ! showTooltip || pattern.id ) && ( + { pattern.type === PATTERN_TYPES.user && + ! pattern.syncStatus && ( +
+ +
+ ) } + { ( ! showTooltip || + pattern.type === PATTERN_TYPES.user ) && (
{ pattern.title }
diff --git a/packages/block-editor/src/components/inserter/block-patterns-explorer/pattern-list.js b/packages/block-editor/src/components/inserter/block-patterns-explorer/pattern-list.js index 7cd2320a4fd1f0..bf2867be5cdf3c 100644 --- a/packages/block-editor/src/components/inserter/block-patterns-explorer/pattern-list.js +++ b/packages/block-editor/src/components/inserter/block-patterns-explorer/pattern-list.js @@ -18,6 +18,7 @@ import { searchItems } from '../search-items'; import BlockPatternsPaging from '../../block-patterns-paging'; import usePatternsPaging from '../hooks/use-patterns-paging'; import { + PATTERN_TYPES, allPatternsCategory, myPatternsCategory, } from '../block-patterns-tab/utils'; @@ -70,7 +71,10 @@ function PatternList( { searchValue, selectedCategory, patternCategories } ) { if ( selectedCategory === allPatternsCategory.name ) { return true; } - if ( selectedCategory === myPatternsCategory.name && pattern.id ) { + if ( + selectedCategory === myPatternsCategory.name && + pattern.type === PATTERN_TYPES.user + ) { return true; } if ( selectedCategory === 'uncategorized' ) { diff --git a/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js b/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js index 2fef53cfa2a193..76864a6a00ccc5 100644 --- a/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js +++ b/packages/block-editor/src/components/inserter/block-patterns-tab/pattern-category-previews.js @@ -30,6 +30,7 @@ import { isPatternFiltered, allPatternsCategory, myPatternsCategory, + PATTERN_TYPES, } from './utils'; const noop = () => {}; @@ -69,7 +70,10 @@ export function PatternCategoryPreviews( { if ( category.name === allPatternsCategory.name ) { return true; } - if ( category.name === myPatternsCategory.name && pattern.id ) { + if ( + category.name === myPatternsCategory.name && + pattern.type === PATTERN_TYPES.user + ) { return true; } if ( category.name !== 'uncategorized' ) { diff --git a/packages/block-editor/src/components/inserter/block-patterns-tab/use-pattern-categories.js b/packages/block-editor/src/components/inserter/block-patterns-tab/use-pattern-categories.js index 9c7a7a32a60c07..12e885954f4bf3 100644 --- a/packages/block-editor/src/components/inserter/block-patterns-tab/use-pattern-categories.js +++ b/packages/block-editor/src/components/inserter/block-patterns-tab/use-pattern-categories.js @@ -14,6 +14,7 @@ import { isPatternFiltered, allPatternsCategory, myPatternsCategory, + PATTERN_TYPES, } from './utils'; export function usePatternCategories( rootClientId, sourceFilter = 'all' ) { @@ -69,7 +70,11 @@ export function usePatternCategories( rootClientId, sourceFilter = 'all' ) { label: _x( 'Uncategorized' ), } ); } - if ( filteredPatterns.some( ( pattern ) => pattern.id ) ) { + if ( + filteredPatterns.some( + ( pattern ) => pattern.type === PATTERN_TYPES.user + ) + ) { categories.unshift( myPatternsCategory ); } if ( filteredPatterns.length > 0 ) { diff --git a/packages/block-editor/src/components/inserter/block-patterns-tab/utils.js b/packages/block-editor/src/components/inserter/block-patterns-tab/utils.js index 9f222c6a2f93cd..439955eca92b35 100644 --- a/packages/block-editor/src/components/inserter/block-patterns-tab/utils.js +++ b/packages/block-editor/src/components/inserter/block-patterns-tab/utils.js @@ -53,9 +53,11 @@ export function isPatternFiltered( pattern, sourceFilter, syncFilter ) { return true; } - // If user source selected, filter out theme patterns. Any pattern without - // an id wasn't created by a user. - if ( sourceFilter === PATTERN_TYPES.user && ! pattern.id ) { + // If user source selected, filter out theme patterns. + if ( + sourceFilter === PATTERN_TYPES.user && + pattern.type !== PATTERN_TYPES.user + ) { return true; } diff --git a/packages/block-editor/src/components/inserter/hooks/use-patterns-state.js b/packages/block-editor/src/components/inserter/hooks/use-patterns-state.js index 1924187e04179f..576768c76abca9 100644 --- a/packages/block-editor/src/components/inserter/hooks/use-patterns-state.js +++ b/packages/block-editor/src/components/inserter/hooks/use-patterns-state.js @@ -11,6 +11,7 @@ import { store as noticesStore } from '@wordpress/notices'; * Internal dependencies */ import { store as blockEditorStore } from '../../../store'; +import { PATTERN_TYPES } from '../block-patterns-tab/utils'; /** * Retrieves the block patterns inserter state. @@ -57,7 +58,8 @@ const usePatternsState = ( onInsert, rootClientId ) => { const onClickPattern = useCallback( ( pattern, blocks ) => { const patternBlocks = - pattern.id && pattern.syncStatus !== 'unsynced' + pattern.type === PATTERN_TYPES.user && + pattern.syncStatus !== 'unsynced' ? [ createBlock( 'core/block', { ref: pattern.id } ) ] : blocks; onInsert( diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 548ad71664b5e6..c0441cd3b3755e 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -27,6 +27,7 @@ import { createRegistrySelector } from '@wordpress/data'; * Internal dependencies */ import { orderBy } from '../utils/sorting'; +import { PATTERN_TYPES } from '../components/inserter/block-patterns-tab/utils'; /** * A block selection object. @@ -2287,6 +2288,7 @@ function getUserPatterns( state ) { return { name: `core/block/${ userPattern.id }`, id: userPattern.id, + type: PATTERN_TYPES.user, title: userPattern.title.raw, categories: userPattern.wp_pattern_category.map( ( catId ) => categories && categories.get( catId ) diff --git a/packages/edit-site/src/components/page-patterns/use-patterns.js b/packages/edit-site/src/components/page-patterns/use-patterns.js index 9cb6c8b998c412..be5992bd9b4efe 100644 --- a/packages/edit-site/src/components/page-patterns/use-patterns.js +++ b/packages/edit-site/src/components/page-patterns/use-patterns.js @@ -159,7 +159,7 @@ const selectPatterns = createSelector( // User patterns can have their sync statuses checked directly // Non-user patterns are all unsynced for the time being. patterns = patterns.filter( ( pattern ) => { - return pattern.id + return pattern.type === PATTERN_TYPES.user ? pattern.syncStatus === syncStatus : syncStatus === PATTERN_SYNC_TYPES.unsynced; } ); diff --git a/packages/patterns/src/components/duplicate-pattern-modal.js b/packages/patterns/src/components/duplicate-pattern-modal.js index baf977a7b27e2f..a62e7306dc90e1 100644 --- a/packages/patterns/src/components/duplicate-pattern-modal.js +++ b/packages/patterns/src/components/duplicate-pattern-modal.js @@ -10,11 +10,11 @@ import { store as noticesStore } from '@wordpress/notices'; * Internal dependencies */ import CreatePatternModal from './create-pattern-modal'; -import { PATTERN_SYNC_TYPES } from '../constants'; +import { PATTERN_SYNC_TYPES, PATTERN_TYPES } from '../constants'; function getTermLabels( pattern, categories ) { - // Theme patterns don't have an id and rely on core pattern categories. - if ( ! pattern.id ) { + // Theme patterns rely on core pattern categories. + if ( pattern.type !== PATTERN_TYPES.user ) { return categories.core ?.filter( ( category ) => pattern.categories.includes( category.name ) @@ -52,9 +52,10 @@ export default function DuplicatePatternModal( { const duplicatedProps = { content: pattern.content, defaultCategories: getTermLabels( pattern, categories ), - defaultSyncType: ! pattern.id // Theme patterns don't have an ID. - ? PATTERN_SYNC_TYPES.unsynced - : pattern.wp_pattern_sync_status || PATTERN_SYNC_TYPES.full, + defaultSyncType: + pattern.type !== PATTERN_TYPES.user // Theme patterns are unsynced by default. + ? PATTERN_SYNC_TYPES.unsynced + : pattern.wp_pattern_sync_status || PATTERN_SYNC_TYPES.full, defaultTitle: sprintf( /* translators: %s: Existing pattern title */ __( '%s (Copy)' ), From ae57cac36a9cf661fbb769fac44f9e80911e03a3 Mon Sep 17 00:00:00 2001 From: Andrew Serong <14988353+andrewserong@users.noreply.github.com> Date: Wed, 22 Nov 2023 15:15:06 +1100 Subject: [PATCH 103/116] useMovingAnimation: Clear translate3d rule when animation is finished (#56410) * useMovingAnimation: Clear translate3d rule when animation is finished * Add inline comment for clarity --- .../block-editor/src/components/use-moving-animation/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/use-moving-animation/index.js b/packages/block-editor/src/components/use-moving-animation/index.js index bf49a480bc6b44..e6c888330fca71 100644 --- a/packages/block-editor/src/components/use-moving-animation/index.js +++ b/packages/block-editor/src/components/use-moving-animation/index.js @@ -129,7 +129,7 @@ function useMovingAnimation( { const finishedMoving = x === 0 && y === 0; ref.current.style.transformOrigin = 'center center'; ref.current.style.transform = finishedMoving - ? undefined + ? null // Set to `null` to explicitly remove the transform. : `translate3d(${ x }px,${ y }px,0)`; ref.current.style.zIndex = isSelected ? '1' : ''; From 537fa574e0e9bc18f6bb800d7c673c8fae88c99c Mon Sep 17 00:00:00 2001 From: tellthemachines Date: Wed, 22 Nov 2023 16:32:23 +1100 Subject: [PATCH 104/116] Reduce specificity of default Cover text color styles. (#56411) --- packages/block-library/src/cover/style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/cover/style.scss b/packages/block-library/src/cover/style.scss index d9312a71f0faad..837e3834e2e1ba 100644 --- a/packages/block-library/src/cover/style.scss +++ b/packages/block-library/src/cover/style.scss @@ -123,7 +123,7 @@ h4, h5, h6 { - &:not(.has-text-color) { + &:where(:not(.has-text-color)) { color: inherit; } } From ee6acea556b7475af296e41b6ba3bd38f642901a Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 22 Nov 2023 09:48:09 +0400 Subject: [PATCH 105/116] Pattern placeholder: Remove duplicate 'useDispatch' hook (#56397) --- packages/block-library/src/pattern/edit.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/pattern/edit.js b/packages/block-library/src/pattern/edit.js index 5fd1b427a5e3e9..e01fb37eb849e6 100644 --- a/packages/block-library/src/pattern/edit.js +++ b/packages/block-library/src/pattern/edit.js @@ -24,9 +24,11 @@ const PatternEdit = ( { attributes, clientId } ) => { [] ); - const { replaceBlocks, __unstableMarkNextChangeAsNotPersistent } = - useDispatch( blockEditorStore ); - const { setBlockEditingMode } = useDispatch( blockEditorStore ); + const { + replaceBlocks, + setBlockEditingMode, + __unstableMarkNextChangeAsNotPersistent, + } = useDispatch( blockEditorStore ); const { getBlockRootClientId, getBlockEditingMode } = useSelect( blockEditorStore ); From 10034176c30ae7b9e0d224d9d1aadbadf7963215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20K=C3=A4gy?= Date: Wed, 22 Nov 2023 08:11:17 +0100 Subject: [PATCH 106/116] Fix overly complex code example in ComboboxControl readme (#56365) --- packages/components/src/combobox-control/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/components/src/combobox-control/README.md b/packages/components/src/combobox-control/README.md index 30f1f47e653e87..cc15248678d275 100644 --- a/packages/components/src/combobox-control/README.md +++ b/packages/components/src/combobox-control/README.md @@ -47,9 +47,7 @@ function MyComboboxControl() { onFilterValueChange={ ( inputValue ) => setFilteredOptions( options.filter( ( option ) => - option.label - .toLowerCase() - .startsWith( inputValue.toLowerCase() ) + option.value === inputValue ) ) } From 3861da94ce0f9888b5aacb24a22884586a6961d4 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Wed, 22 Nov 2023 11:13:17 +0400 Subject: [PATCH 107/116] Block Editor: Undeprecate the '__experimentalImageSizeControl' component (#56414) --- .../block-editor/src/components/image-size-control/index.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/block-editor/src/components/image-size-control/index.js b/packages/block-editor/src/components/image-size-control/index.js index d929b129313938..46e87de60f2fc8 100644 --- a/packages/block-editor/src/components/image-size-control/index.js +++ b/packages/block-editor/src/components/image-size-control/index.js @@ -8,7 +8,6 @@ import { __experimentalNumberControl as NumberControl, __experimentalHStack as HStack, } from '@wordpress/components'; -import deprecated from '@wordpress/deprecated'; import { __ } from '@wordpress/i18n'; /** @@ -31,11 +30,6 @@ export default function ImageSizeControl( { onChange, onChangeImage = noop, } ) { - deprecated( 'wp.blockEditor.__experimentalImageSizeControl', { - since: '6.3', - alternative: - 'wp.blockEditor.privateApis.DimensionsTool and wp.blockEditor.privateApis.ResolutionTool', - } ); const { currentHeight, currentWidth, updateDimension, updateDimensions } = useDimensionHandler( height, width, imageHeight, imageWidth, onChange ); From d7d680e7a0f54fa6ef8d961a936327f632853f9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20K=C3=A4gy?= Date: Wed, 22 Nov 2023 09:07:01 +0100 Subject: [PATCH 108/116] Simplify code example in ToggleControl component readme (#56389) --- packages/components/src/toggle-control/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/components/src/toggle-control/README.md b/packages/components/src/toggle-control/README.md index 5e2732fb07416f..3a77ef6942d2e5 100644 --- a/packages/components/src/toggle-control/README.md +++ b/packages/components/src/toggle-control/README.md @@ -22,8 +22,8 @@ const MyToggleControl = () => { : 'No fixed background.' } checked={ hasFixedBackground } - onChange={ () => { - setHasFixedBackground( ( state ) => ! state ); + onChange={ (newValue) => { + setHasFixedBackground( newValue ); } } /> ); From 12f286c4605db3ee2a3640eefb52d3fa894bc766 Mon Sep 17 00:00:00 2001 From: James Koster Date: Wed, 22 Nov 2023 08:53:40 +0000 Subject: [PATCH 109/116] Fix data view menu item radius (#56395) * Fix data view menu item radius * Update packages/edit-site/src/components/sidebar-dataviews/style.scss * fix wrong GH suggestion --------- Co-authored-by: Nik Tsekouras --- packages/edit-site/src/components/sidebar-dataviews/style.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/edit-site/src/components/sidebar-dataviews/style.scss b/packages/edit-site/src/components/sidebar-dataviews/style.scss index 526670ee1e5627..6d8561dc8edca7 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/style.scss +++ b/packages/edit-site/src/components/sidebar-dataviews/style.scss @@ -8,6 +8,8 @@ } .edit-site-sidebar-dataviews-dataview-item { + border-radius: $radius-block-ui; + &:hover, &:focus, &[aria-current] { From de3c98e1bc335b5d727b9b5f4a8f08f02cfee445 Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Wed, 22 Nov 2023 09:18:14 +0000 Subject: [PATCH 110/116] Bump plugin version to 17.1.0 --- gutenberg.php | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gutenberg.php b/gutenberg.php index 3ccde2667f03aa..018c269f4f565d 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -5,7 +5,7 @@ * Description: Printing since 1440. This is the development plugin for the block editor, site editor, and other future WordPress core functionality. * Requires at least: 6.2 * Requires PHP: 7.0 - * Version: 17.1.0-rc.1 + * Version: 17.1.0 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/package-lock.json b/package-lock.json index 8382dd2413d46a..601aafc18b2684 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "gutenberg", - "version": "17.1.0-rc.1", + "version": "17.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "gutenberg", - "version": "17.1.0-rc.1", + "version": "17.1.0", "hasInstallScript": true, "license": "GPL-2.0-or-later", "dependencies": { diff --git a/package.json b/package.json index eea10b3180540b..43ca7f0858f609 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "17.1.0-rc.1", + "version": "17.1.0", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", From 014d1633b6986f54a0dd597d3d751f566a569570 Mon Sep 17 00:00:00 2001 From: Andrew Hayward Date: Wed, 22 Nov 2023 09:23:25 +0000 Subject: [PATCH 111/116] Migrating `InserterListbox` to use updated Composite implementation (#56246) - Removes `__unstableComposite` imports from `@wordpress/components` - Adds private `Composite*` exports from `@wordpress/components` - Refactors `InserterListbox`, `InserterListboxRow` and `InserterListboxItem` to use updated `Composite` components - Additionally updates `BlockTypesList` to ensure listbox items are appropriately grouped --- .../src/components/block-types-list/index.js | 9 ++++---- .../src/components/inserter-listbox/index.js | 18 +++++++++------ .../src/components/inserter-listbox/item.js | 23 +++++++++---------- .../src/components/inserter-listbox/row.js | 18 +++++---------- 4 files changed, 33 insertions(+), 35 deletions(-) diff --git a/packages/block-editor/src/components/block-types-list/index.js b/packages/block-editor/src/components/block-types-list/index.js index 40e04b040d5a80..0be6f82a653d18 100644 --- a/packages/block-editor/src/components/block-types-list/index.js +++ b/packages/block-editor/src/components/block-types-list/index.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { getBlockMenuDefaultClassName } from '@wordpress/blocks'; +import { useInstanceId } from '@wordpress/compose'; /** * Internal dependencies @@ -25,11 +26,10 @@ function BlockTypesList( { label, isDraggable = true, } ) { + const className = 'block-editor-block-types-list'; + const listId = useInstanceId( BlockTypesList, className ); return ( - + { chunk( items, 3 ).map( ( row, i ) => ( { row.map( ( item, j ) => ( @@ -43,6 +43,7 @@ function BlockTypesList( { onHover={ onHover } isDraggable={ isDraggable && ! item.isDisabled } isFirst={ i === 0 && j === 0 } + rowId={ `${ listId }-${ i }` } /> ) ) } diff --git a/packages/block-editor/src/components/inserter-listbox/index.js b/packages/block-editor/src/components/inserter-listbox/index.js index 6345cb38c494ac..6af26a1d746bfb 100644 --- a/packages/block-editor/src/components/inserter-listbox/index.js +++ b/packages/block-editor/src/components/inserter-listbox/index.js @@ -1,26 +1,30 @@ /** * WordPress dependencies */ -import { __unstableUseCompositeState as useCompositeState } from '@wordpress/components'; +import { privateApis as componentsPrivateApis } from '@wordpress/components'; /** * Internal dependencies */ -import InserterListboxContext from './context'; +import { unlock } from '../../lock-unlock'; export { default as InserterListboxGroup } from './group'; export { default as InserterListboxRow } from './row'; export { default as InserterListboxItem } from './item'; +const { CompositeV2: Composite, useCompositeStoreV2: useCompositeStore } = + unlock( componentsPrivateApis ); + function InserterListbox( { children } ) { - const compositeState = useCompositeState( { - shift: true, - wrap: 'horizontal', + const store = useCompositeStore( { + focusShift: true, + focusWrap: 'horizontal', } ); + return ( - + }> { children } - + ); } diff --git a/packages/block-editor/src/components/inserter-listbox/item.js b/packages/block-editor/src/components/inserter-listbox/item.js index 50adb4a7880387..951eb86223ce8f 100644 --- a/packages/block-editor/src/components/inserter-listbox/item.js +++ b/packages/block-editor/src/components/inserter-listbox/item.js @@ -3,32 +3,31 @@ */ import { Button, - __unstableCompositeItem as CompositeItem, + privateApis as componentsPrivateApis, } from '@wordpress/components'; -import { forwardRef, useContext } from '@wordpress/element'; +import { forwardRef } from '@wordpress/element'; /** * Internal dependencies */ -import InserterListboxContext from './context'; +import { unlock } from '../../lock-unlock'; + +const { CompositeItemV2: CompositeItem } = unlock( componentsPrivateApis ); function InserterListboxItem( { isFirst, as: Component, children, ...props }, ref ) { - const state = useContext( InserterListboxContext ); return ( - { ( htmlProps ) => { + render={ ( htmlProps ) => { const propsWithTabIndex = { ...htmlProps, tabIndex: isFirst ? 0 : htmlProps.tabIndex, @@ -45,7 +44,7 @@ function InserterListboxItem( } return ; } } - + /> ); } diff --git a/packages/block-editor/src/components/inserter-listbox/row.js b/packages/block-editor/src/components/inserter-listbox/row.js index 710267660199d7..f9827f08b3fa39 100644 --- a/packages/block-editor/src/components/inserter-listbox/row.js +++ b/packages/block-editor/src/components/inserter-listbox/row.js @@ -1,24 +1,18 @@ /** * WordPress dependencies */ -import { forwardRef, useContext } from '@wordpress/element'; -import { __unstableCompositeGroup as CompositeGroup } from '@wordpress/components'; +import { forwardRef } from '@wordpress/element'; +import { privateApis as componentsPrivateApis } from '@wordpress/components'; /** * Internal dependencies */ -import InserterListboxContext from './context'; +import { unlock } from '../../lock-unlock'; + +const { CompositeGroupV2: CompositeGroup } = unlock( componentsPrivateApis ); function InserterListboxRow( props, ref ) { - const state = useContext( InserterListboxContext ); - return ( - - ); + return ; } export default forwardRef( InserterListboxRow ); From 9c6f6b1738a45f2891b5c7d4fde5c9a5ff80dc7e Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Wed, 22 Nov 2023 09:35:13 +0000 Subject: [PATCH 112/116] Update Changelog for 17.1.0 --- changelog.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 2435ab1eceb4ab..0f86c2d8f593b3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,7 +1,6 @@ == Changelog == -= 17.1.0-rc.1 = - += 17.1.0 = ## Changelog @@ -27,7 +26,7 @@ #### Global Styles - Global Style Revisions: Ensure consistent back button behaviour. ([55881](https://github.com/WordPress/gutenberg/pull/55881)) - Global Styles Revisions: More descriptive text timeline. ([55868](https://github.com/WordPress/gutenberg/pull/55868)) -- Global styles revisions: Add route for single styles revisions. ([55827](https://github.com/WordPress/gutenberg/pull/55827)) +- Global Styles Revisions: Add route for single styles revisions. ([55827](https://github.com/WordPress/gutenberg/pull/55827)) #### Block Locking - Block Quick Navigation: Truncate text. ([56142](https://github.com/WordPress/gutenberg/pull/56142)) @@ -89,7 +88,7 @@ - DataViews: Make items per page an even number. ([55906](https://github.com/WordPress/gutenberg/pull/55906)) - DataViews: Make used taxonomy private. ([55918](https://github.com/WordPress/gutenberg/pull/55918)) - DataViews: Reset pagination upon filter change. ([55797](https://github.com/WordPress/gutenberg/pull/55797)) -- Dataviews: Add a missing icon for the side by side view. ([55925](https://github.com/WordPress/gutenberg/pull/55925)) +- DataViews: Add a missing icon for the side by side view. ([55925](https://github.com/WordPress/gutenberg/pull/55925)) #### Components - DropdownMenu: Remove extra vertical space around the toggle button. ([56136](https://github.com/WordPress/gutenberg/pull/56136)) @@ -328,6 +327,8 @@ The following contributors merged PRs in this release: @afercia @andrewhayward @andrewserong @anomiex @anton-vlasenko @aristath @artemiomorales @bph @brookewp @c4rl0sbr4v0 @chad1008 @ciampo @DAreRodz @dcalhoun @dsas @ellatrix @flootr @fluiddot @gaambo @glendaviesnz @gziolo @jameskoster @jeryj @jhnstn @joanrodas @jorgefilipecosta @JorgeVilchez95 @jsnajdr @juanmaguitar @kevin940726 @Mamaduka @masteradhoc @matiasbenedetto @ndiego @ntsekouras @oandregal @peterwilsoncc @pooja-muchandikar @priethor @ramonjd @renatho @richtabor @sacerro @scruffian @shimotmk @SiobhyB @Soean @swissspidy @t-hamano @talldan @tellthemachines @torounit @tyxla @WunderBart @youknowriad + + = 17.0.2 = From a7911582cda6f11d1ebddcd27ccbb82fb86022c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Wed, 22 Nov 2023 10:39:45 +0100 Subject: [PATCH 113/116] DataViews: update filter component (#56110) --- .../src/components/dataviews/add-filter.js | 2 +- .../src/components/dataviews/filters.js | 13 +-- .../src/components/dataviews/in-filter.js | 105 ++++++++++-------- .../src/components/dataviews/view-list.js | 35 ++---- 4 files changed, 71 insertions(+), 84 deletions(-) diff --git a/packages/edit-site/src/components/dataviews/add-filter.js b/packages/edit-site/src/components/dataviews/add-filter.js index 147b5a09ca59ac..7192a507b2afe8 100644 --- a/packages/edit-site/src/components/dataviews/add-filter.js +++ b/packages/edit-site/src/components/dataviews/add-filter.js @@ -54,10 +54,10 @@ export default function AddFilter( { fields, view, onChangeView } ) { } diff --git a/packages/edit-site/src/components/dataviews/filters.js b/packages/edit-site/src/components/dataviews/filters.js index 72ca0eb35bd873..c7681f53fe0ae8 100644 --- a/packages/edit-site/src/components/dataviews/filters.js +++ b/packages/edit-site/src/components/dataviews/filters.js @@ -1,8 +1,3 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; - /** * Internal dependencies */ @@ -23,13 +18,7 @@ export default function Filters( { fields, view, onChangeView } ) { filters.push( { field: field.id, name: field.header, - elements: [ - { - value: '', - label: __( 'All' ), - }, - ...( field.elements || [] ), - ], + elements: field.elements || [], isVisible: view.filters.some( ( f ) => f.field === field.id && f.operator === OPERATOR_IN diff --git a/packages/edit-site/src/components/dataviews/in-filter.js b/packages/edit-site/src/components/dataviews/in-filter.js index 4f4170fdcbb0b4..9dd85eb1eedb26 100644 --- a/packages/edit-site/src/components/dataviews/in-filter.js +++ b/packages/edit-site/src/components/dataviews/in-filter.js @@ -2,65 +2,78 @@ * WordPress dependencies */ import { - __experimentalInputControlPrefixWrapper as InputControlPrefixWrapper, - SelectControl, + Button, + privateApis as componentsPrivateApis, + Icon, } from '@wordpress/components'; +import { chevronDown } from '@wordpress/icons'; import { __, sprintf } from '@wordpress/i18n'; /** * Internal dependencies */ import { OPERATOR_IN } from './constants'; +import { unlock } from '../../lock-unlock'; + +const { + DropdownMenuV2: DropdownMenu, + DropdownMenuCheckboxItemV2: DropdownMenuCheckboxItem, +} = unlock( componentsPrivateApis ); export default ( { filter, view, onChangeView } ) => { - const valueFound = view.filters.find( - ( f ) => f.field === filter.field && f.operator === OPERATOR_IN + const filterInView = view.filters.find( ( f ) => f.field === filter.field ); + const activeElement = filter.elements.find( + ( element ) => element.value === filterInView?.value ); - const activeValue = - ! valueFound || ! valueFound.hasOwnProperty( 'value' ) - ? '' - : valueFound.value; - - const id = `dataviews__filters-in-${ filter.field }`; - return ( - - { sprintf( - /* translators: filter name. */ - __( '%s:' ), - filter.name - ) } - + + { activeElement !== undefined + ? sprintf( + /* translators: 1: Filter name. 2: filter value. e.g.: "Author is Admin". */ + __( '%1$s is %2$s' ), + filter.name, + activeElement.label + ) + : filter.name } + + } - options={ filter.elements } - onChange={ ( value ) => { - const filters = view.filters.filter( - ( f ) => - f.field !== filter.field || f.operator !== OPERATOR_IN + > + { filter.elements.map( ( element ) => { + return ( + + onChangeView( ( currentView ) => ( { + ...currentView, + page: 1, + filters: [ + ...view.filters.filter( + ( f ) => f.field !== filter.field + ), + { + field: filter.field, + operator: OPERATOR_IN, + value: + activeElement?.value === + element.value + ? undefined + : element.value, + }, + ], + } ) ) + } + > + { element.label } + ); - - filters.push( { - field: filter.field, - operator: OPERATOR_IN, - value, - } ); - - onChangeView( ( currentView ) => ( { - ...currentView, - page: 1, - filters, - } ) ); - } } - /> + } ) } + ); }; diff --git a/packages/edit-site/src/components/dataviews/view-list.js b/packages/edit-site/src/components/dataviews/view-list.js index 0939297e374dfa..8e131a350ac7d9 100644 --- a/packages/edit-site/src/components/dataviews/view-list.js +++ b/packages/edit-site/src/components/dataviews/view-list.js @@ -73,13 +73,7 @@ function HeaderMenu( { dataView, header } ) { if ( header.column.columnDef.type === ENUMERATION_TYPE ) { filter = { field: header.column.columnDef.id, - elements: [ - { - value: '', - label: __( 'All' ), - }, - ...( header.column.columnDef.elements || [] ), - ], + elements: header.column.columnDef.elements || [], }; } const isFilterable = !! filter; @@ -166,11 +160,6 @@ function HeaderMenu( { dataView, header } ) { )[ 0 ] === filter.field ); - // Set the empty item as active if the filter is not set. - if ( ! columnFilter && element.value === '' ) { - isActive = true; - } - if ( columnFilter ) { const value = Object.values( columnFilter )[ 0 ]; @@ -205,19 +194,15 @@ function HeaderMenu( { dataView, header } ) { } ); - if ( element.value === '' ) { - dataView.setColumnFilters( - otherFilters - ); - } else { - dataView.setColumnFilters( [ - ...otherFilters, - { - [ filter.field + - ':in' ]: element.value, - }, - ] ); - } + dataView.setColumnFilters( [ + ...otherFilters, + { + [ filter.field + ':in' ]: + isActive + ? undefined + : element.value, + }, + ] ); } } > { element.label } From 3b380b0917e2b39a1bd30e9228f37669e7c0c7f6 Mon Sep 17 00:00:00 2001 From: Birgit Pauli-Haack Date: Wed, 22 Nov 2023 12:20:06 +0100 Subject: [PATCH 114/116] Update Readme.txt tested up to 6.4 (#56427) * fixes wrong link in #56084 * update 'tested up to' in readme.txt of GB plugin --- readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 668ccca48a5dcf..8ebcfd1406b0d8 100644 --- a/readme.txt +++ b/readme.txt @@ -1,6 +1,6 @@ === Gutenberg === Contributors: matveb, joen, karmatosed -Tested up to: 6.3 +Tested up to: 6.4 Stable tag: V.V.V License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html From 6e532f444a72d997b09441197caade90c49f19f3 Mon Sep 17 00:00:00 2001 From: Andrei Draganescu Date: Wed, 22 Nov 2023 13:31:02 +0200 Subject: [PATCH 115/116] Add align support to the image block - alternative (#55954) * only remove the alignment control * use an effect to reset width, height, aspect ratio and cover when align is wide or full * try a filter on block attributes when align control updates attributes * new fixtures for the default align attribute of core/image * updated snapshots * modify the filter to always return the same shape of object, update naming * remove filter, add undo skip * update the react native component * Remove align from custom image attributes This allows the block supports to add the attribute instead keeping things cleaner. * Fix tests * Fix another fixture --------- Co-authored-by: Alex Lende --- docs/reference-guides/core-blocks.md | 4 +- .../test/__snapshots__/align.native.js.snap | 10 ++--- packages/block-library/src/image/block.json | 4 +- packages/block-library/src/image/edit.js | 37 ++++++++----------- .../block-library/src/image/edit.native.js | 35 +++++++++--------- packages/block-library/src/image/image.js | 22 ----------- .../src/mobile/utils/alignments.native.js | 1 + .../blocks-raw-handling.test.js.snap | 6 +-- .../blocks/core__image__center-caption.json | 4 +- ...ed-v2-add-is-resized-class.serialized.html | 2 +- ...cated-v3-add-align-wrapper.serialized.html | 2 +- ...ed-v4-remove-align-wrapper.serialized.html | 2 +- ...-v6-add-style-width-height.serialized.html | 2 +- .../fixtures/documents/wordpress-out.html | 2 +- 14 files changed, 52 insertions(+), 81 deletions(-) diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index 0ae5979b797047..10f0f76d9eb0d7 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -378,8 +378,8 @@ Insert an image to make a visual statement. ([Source](https://github.com/WordPre - **Name:** core/image - **Category:** media -- **Supports:** anchor, color (~~background~~, ~~text~~), filter (duotone) -- **Attributes:** align, alt, aspectRatio, caption, height, href, id, lightbox, linkClass, linkDestination, linkTarget, rel, scale, sizeSlug, title, url, width +- **Supports:** align (center, full, left, right, wide), anchor, color (~~background~~, ~~text~~), filter (duotone) +- **Attributes:** alt, aspectRatio, caption, height, href, id, lightbox, linkClass, linkDestination, linkTarget, rel, scale, sizeSlug, title, url, width ## Latest Comments diff --git a/packages/block-editor/src/hooks/test/__snapshots__/align.native.js.snap b/packages/block-editor/src/hooks/test/__snapshots__/align.native.js.snap index 2782d6ae0b984b..045fb0e3bd944a 100644 --- a/packages/block-editor/src/hooks/test/__snapshots__/align.native.js.snap +++ b/packages/block-editor/src/hooks/test/__snapshots__/align.native.js.snap @@ -19,25 +19,25 @@ exports[`Align options for group block sets Wide width option 1`] = ` `; exports[`Align options for media block sets Align center option 1`] = ` -" +"
" `; exports[`Align options for media block sets Align left option 1`] = ` -" +"
" `; exports[`Align options for media block sets Align right option 1`] = ` -" +"
" `; exports[`Align options for media block sets Full width option 1`] = ` -" +"
" `; @@ -49,7 +49,7 @@ exports[`Align options for media block sets None option 1`] = ` `; exports[`Align options for media block sets Wide width option 1`] = ` -" +"
" `; diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index d665a8a8f77085..b46829e5059a25 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -9,9 +9,6 @@ "keywords": [ "img", "photo", "picture" ], "textdomain": "default", "attributes": { - "align": { - "type": "string" - }, "url": { "type": "string", "source": "attribute", @@ -95,6 +92,7 @@ } }, "supports": { + "align": [ "left", "center", "right", "wide", "full" ], "anchor": true, "color": { "text": false, diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js index c58a96e5949112..d189af32efcbec 100644 --- a/packages/block-library/src/image/edit.js +++ b/packages/block-library/src/image/edit.js @@ -10,8 +10,6 @@ import { getBlobByURL, isBlobURL, revokeBlobURL } from '@wordpress/blob'; import { Placeholder } from '@wordpress/components'; import { useDispatch, useSelect } from '@wordpress/data'; import { - BlockAlignmentControl, - BlockControls, BlockIcon, MediaPlaceholder, useBlockProps, @@ -106,13 +104,13 @@ export function ImageEdit( { url = '', alt, caption, - align, id, width, height, sizeSlug, aspectRatio, scale, + align, } = attributes; const [ temporaryURL, setTemporaryURL ] = useState(); @@ -126,6 +124,21 @@ export function ImageEdit( { captionRef.current = caption; }, [ caption ] ); + const { __unstableMarkNextChangeAsNotPersistent } = + useDispatch( blockEditorStore ); + + useEffect( () => { + if ( [ 'wide', 'full' ].includes( align ) ) { + __unstableMarkNextChangeAsNotPersistent(); + setAttributes( { + width: undefined, + height: undefined, + aspectRatio: undefined, + scale: undefined, + } ); + } + }, [ align ] ); + const ref = useRef(); const { imageDefaultSize, mediaUpload } = useSelect( ( select ) => { const { getSettings } = select( blockEditorStore ); @@ -255,16 +268,6 @@ export function ImageEdit( { } } - function updateAlignment( nextAlign ) { - const extraUpdatedAttributes = [ 'wide', 'full' ].includes( nextAlign ) - ? { width: undefined, height: undefined } - : {}; - setAttributes( { - ...extraUpdatedAttributes, - align: nextAlign, - } ); - } - let isTemp = isTemporaryImage( id, url ); // Upload a temporary image on mount. @@ -375,14 +378,6 @@ export function ImageEdit( { clientId={ clientId } blockEditingMode={ blockEditingMode } /> - { ! url && blockEditingMode === 'default' && ( - - - - ) } } onSelect={ onSelectImage } diff --git a/packages/block-library/src/image/edit.native.js b/packages/block-library/src/image/edit.native.js index 804ae9e1671f6e..44ebfda67d8750 100644 --- a/packages/block-library/src/image/edit.native.js +++ b/packages/block-library/src/image/edit.native.js @@ -44,7 +44,6 @@ import { MEDIA_TYPE_IMAGE, BlockControls, InspectorControls, - BlockAlignmentToolbar, BlockStyles, store as blockEditorStore, blockSettingsScreens, @@ -212,7 +211,6 @@ export class ImageEdit extends Component { this.onSetFeatured = this.onSetFeatured.bind( this ); this.onFocusCaption = this.onFocusCaption.bind( this ); this.onSelectURL = this.onSelectURL.bind( this ); - this.updateAlignment = this.updateAlignment.bind( this ); this.accessibilityLabelCreator = this.accessibilityLabelCreator.bind( this ); this.setMappedAttributes = this.setMappedAttributes.bind( this ); @@ -305,6 +303,20 @@ export class ImageEdit extends Component { this.replacedFeaturedImage = false; setFeaturedImage( id ); } + + const { align } = attributes; + const { __unstableMarkNextChangeAsNotPersistent } = this.props; + + // Update the attributes if the align is wide or full + if ( [ 'wide', 'full' ].includes( align ) ) { + __unstableMarkNextChangeAsNotPersistent(); + setAttributes( { + width: undefined, + height: undefined, + aspectRatio: undefined, + scale: undefined, + } ); + } } static getDerivedStateFromProps( props, state ) { @@ -391,18 +403,6 @@ export class ImageEdit extends Component { } ); } - updateAlignment( nextAlign ) { - const extraUpdatedAttributes = Object.values( - WIDE_ALIGNMENTS.alignments - ).includes( nextAlign ) - ? { width: undefined, height: undefined } - : {}; - this.props.setAttributes( { - ...extraUpdatedAttributes, - align: nextAlign, - } ); - } - onSetNewTab( value ) { const updatedLinkTarget = getUpdatedLinkTargetSettings( value, @@ -711,10 +711,6 @@ export class ImageEdit extends Component { onClick={ open } /> - ); @@ -941,8 +937,11 @@ export default compose( [ } ), withDispatch( ( dispatch ) => { const { createErrorNotice } = dispatch( noticesStore ); + const { __unstableMarkNextChangeAsNotPersistent } = + dispatch( blockEditorStore ); return { + __unstableMarkNextChangeAsNotPersistent, createErrorNotice, closeSettingsBottomSheet() { dispatch( editPostStore ).closeGeneralSidebar(); diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index 64eb03adedb32b..11d460efd472cb 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -25,7 +25,6 @@ import { MediaReplaceFlow, store as blockEditorStore, useSettings, - BlockAlignmentControl, __experimentalImageEditor as ImageEditor, __experimentalGetElementClassName, __experimentalUseBorderProps as useBorderProps, @@ -353,21 +352,6 @@ export default function Image( { } ); } - function updateAlignment( nextAlign ) { - const extraUpdatedAttributes = [ 'wide', 'full' ].includes( nextAlign ) - ? { - width: undefined, - height: undefined, - aspectRatio: undefined, - scale: undefined, - } - : {}; - setAttributes( { - ...extraUpdatedAttributes, - align: nextAlign, - } ); - } - useEffect( () => { if ( ! isSelected ) { setIsEditingImage( false ); @@ -455,12 +439,6 @@ export default function Image( { const controls = ( <> - { hasNonContentControls && ( - - ) } { hasNonContentControls && ( { diff --git a/packages/components/src/mobile/utils/alignments.native.js b/packages/components/src/mobile/utils/alignments.native.js index 98635ea4681ada..bc42385988a5d1 100644 --- a/packages/components/src/mobile/utils/alignments.native.js +++ b/packages/components/src/mobile/utils/alignments.native.js @@ -10,6 +10,7 @@ export const WIDE_ALIGNMENTS = { }, excludeBlocks: [ 'core/heading' ], notInnerContainers: [ + 'core/image', 'core/separator', 'core/media-text', 'core/pullquote', diff --git a/test/integration/__snapshots__/blocks-raw-handling.test.js.snap b/test/integration/__snapshots__/blocks-raw-handling.test.js.snap index 32f2dab7137666..071870a4208174 100644 --- a/test/integration/__snapshots__/blocks-raw-handling.test.js.snap +++ b/test/integration/__snapshots__/blocks-raw-handling.test.js.snap @@ -158,19 +158,19 @@ exports[`rawHandler should convert HTML post to blocks with minimal content chan `; exports[`rawHandler should convert a caption shortcode 1`] = ` -" +"
test
" `; exports[`rawHandler should convert a caption shortcode with caption 1`] = ` -" +"
test
" `; exports[`rawHandler should convert a caption shortcode with link 1`] = ` -" +"
Bell on Wharf
Bell on wharf in San Francisco
" `; diff --git a/test/integration/fixtures/blocks/core__image__center-caption.json b/test/integration/fixtures/blocks/core__image__center-caption.json index a369e433b4028e..034047c07089b9 100644 --- a/test/integration/fixtures/blocks/core__image__center-caption.json +++ b/test/integration/fixtures/blocks/core__image__center-caption.json @@ -3,10 +3,10 @@ "name": "core/image", "isValid": true, "attributes": { - "align": "center", "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", "alt": "", - "caption": "Give it a try. Press the \"really wide\" button on the image toolbar." + "caption": "Give it a try. Press the \"really wide\" button on the image toolbar.", + "align": "center" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v2-add-is-resized-class.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v2-add-is-resized-class.serialized.html index 9a66da6c018989..c03189e9b456c0 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v2-add-is-resized-class.serialized.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v2-add-is-resized-class.serialized.html @@ -1,3 +1,3 @@ - +
diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v3-add-align-wrapper.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v3-add-align-wrapper.serialized.html index 9a66da6c018989..c03189e9b456c0 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v3-add-align-wrapper.serialized.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v3-add-align-wrapper.serialized.html @@ -1,3 +1,3 @@ - +
diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v4-remove-align-wrapper.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v4-remove-align-wrapper.serialized.html index 99da2155bce88f..b9e58cc24fddb4 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v4-remove-align-wrapper.serialized.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v4-remove-align-wrapper.serialized.html @@ -1,3 +1,3 @@ - +
diff --git a/test/integration/fixtures/blocks/core__image__deprecated-v6-add-style-width-height.serialized.html b/test/integration/fixtures/blocks/core__image__deprecated-v6-add-style-width-height.serialized.html index 807ba3abc9f9ce..57545968847e1b 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-v6-add-style-width-height.serialized.html +++ b/test/integration/fixtures/blocks/core__image__deprecated-v6-add-style-width-height.serialized.html @@ -1,3 +1,3 @@ - +
diff --git a/test/integration/fixtures/documents/wordpress-out.html b/test/integration/fixtures/documents/wordpress-out.html index c394fa232081d1..a0ac4b89ec5520 100644 --- a/test/integration/fixtures/documents/wordpress-out.html +++ b/test/integration/fixtures/documents/wordpress-out.html @@ -28,7 +28,7 @@

Shortcode

- +
From 77d0226badb0769b12e28b19fb439cf6777b672a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20K=C3=A4gy?= Date: Wed, 22 Nov 2023 12:53:32 +0100 Subject: [PATCH 116/116] fix remove removal version from deprecated prop (#56336) --- packages/components/src/angle-picker-control/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/components/src/angle-picker-control/index.tsx b/packages/components/src/angle-picker-control/index.tsx index f90394b12078f4..06178e0b401015 100644 --- a/packages/components/src/angle-picker-control/index.tsx +++ b/packages/components/src/angle-picker-control/index.tsx @@ -41,7 +41,6 @@ function UnforwardedAnglePickerControl( 'Bottom margin styles for wp.components.AnglePickerControl', { since: '6.1', - version: '6.4', hint: 'Set the `__nextHasNoMarginBottom` prop to true to start opting into the new styles, which will become the default in a future version.', } );