diff --git a/changelog.txt b/changelog.txt index 33f9362058578..4cdd8690b3740 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,27 @@ == Changelog == += 15.9.1 = + + + +## Changelog + +### Bug Fixes + +#### Fonts API +- [Fonts API] Make local font asset file URL absolute. ([51178](https://github.com/WordPress/gutenberg/pull/51178)) + +#### Block Library +- Social Icons: Add color classes so icon colors correctly reflect changes in Global Styles. ([51020](https://github.com/WordPress/gutenberg/pull/51020)) + + +## Contributors + +The following contributors merged PRs in this release: + +@hellofromtonya @ndiego + + = 15.9.0 = ## Changelog diff --git a/docs/getting-started/create-block/block-anatomy.md b/docs/getting-started/create-block/block-anatomy.md index 83dbcf1469632..d53b1c9d6f5eb 100644 --- a/docs/getting-started/create-block/block-anatomy.md +++ b/docs/getting-started/create-block/block-anatomy.md @@ -44,7 +44,7 @@ Most of the properties are set in the `src/block.json` file. ```json { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "create-block/gutenpride", "version": "0.1.0", "title": "Gutenpride", diff --git a/docs/getting-started/create-block/wp-plugin.md b/docs/getting-started/create-block/wp-plugin.md index 33142659680b9..465060daba7c3 100644 --- a/docs/getting-started/create-block/wp-plugin.md +++ b/docs/getting-started/create-block/wp-plugin.md @@ -104,7 +104,7 @@ The `register_block_type` function registers the block we are going to create an ```json { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "create-block/gutenpride", "version": "0.1.0", "title": "Gutenpride", 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 19598965bb7dc..fc8dc01531c5d 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 @@ -205,7 +205,7 @@ For example: ```json { - "apiVersion": 2, + "apiVersion": 3, "name": "gutenberg-examples/example-02-stylesheets", "title": "Example: Stylesheets", "icon": "universal-access-alt", 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 cd110973b124f..93e5e54d84869 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 @@ -24,7 +24,7 @@ import { } from '@wordpress/block-editor'; registerBlockType( 'gutenberg-examples/example-04-controls-esnext', { - apiVersion: 2, + apiVersion: 3, title: 'Example: Controls (esnext)', icon: 'universal-access-alt', category: 'design', @@ -208,7 +208,7 @@ import { } from '@wordpress/block-editor'; registerBlockType( 'create-block/gutenpride', { - apiVersion: 2, + apiVersion: 3, attributes: { message: { type: 'string', diff --git a/docs/how-to-guides/block-tutorial/block-supports-in-dynamic-blocks.md b/docs/how-to-guides/block-tutorial/block-supports-in-dynamic-blocks.md index b458b135104f9..dc022622c80c2 100644 --- a/docs/how-to-guides/block-tutorial/block-supports-in-dynamic-blocks.md +++ b/docs/how-to-guides/block-tutorial/block-supports-in-dynamic-blocks.md @@ -20,7 +20,7 @@ import { } from '@wordpress/block-editor'; registerBlockType( 'gutenberg-examples/example-dynamic', { - apiVersion: 2, + apiVersion: 3, title: 'Example: last post title', icon: 'megaphone', category: 'widgets', @@ -119,7 +119,7 @@ function gutenberg_examples_dynamic() { register_block_type( 'gutenberg-examples/example-dynamic', array( - 'api_version' => 2, + 'api_version' => 3, 'category' => 'widgets', 'attributes' => array( 'bgColor' => array( 'type' => 'string' ), @@ -144,7 +144,7 @@ import { useSelect } from '@wordpress/data'; import { useBlockProps } from '@wordpress/block-editor'; registerBlockType( 'gutenberg-examples/example-dynamic-block-supports', { - apiVersion: 2, + apiVersion: 3, title: 'Example: last post title(block supports)', icon: 'megaphone', category: 'widgets', @@ -195,7 +195,7 @@ function gutenberg_examples_dynamic_block_supports() { register_block_type( 'gutenberg-examples/example-dynamic-block-supports', array( - 'api_version' => 2, + 'api_version' => 3, 'category' => 'widgets', 'supports' => array( 'color' => true ), 'render_callback' => 'gutenberg_examples_dynamic_block_supports_render_callback', 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 ee478602fd1e9..b343280cae43f 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 @@ -16,7 +16,7 @@ import { registerBlockType } from '@wordpress/blocks'; import { useBlockProps, RichText } from '@wordpress/block-editor'; registerBlockType( 'gutenberg-examples/example-03-editable-esnext', { - apiVersion: 2, + apiVersion: 3, title: 'Example: Basic with block supports', icon: 'universal-access-alt', category: 'design', @@ -73,7 +73,7 @@ registerBlockType( 'gutenberg-examples/example-03-editable-esnext', { var useBlockProps = blockEditor.useBlockProps; blocks.registerBlockType( 'gutenberg-examples/example-03-editable', { - apiVersion: 2, + apiVersion: 3, title: 'Example: Basic with block supports', icon: 'universal-access-alt', category: 'design', @@ -127,7 +127,7 @@ Now, let's alter the block.json file for that block, and add the supports key. ( ```json { - "apiVersion": 2, + "apiVersion": 3, "name": "gutenberg-examples/example-03-editable-esnext", "title": "Example: Basic with block supports", "icon": "universal-access-alt", 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 9f5eff3883b6a..9d1e4dbdf5255 100644 --- a/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md +++ b/docs/how-to-guides/block-tutorial/creating-dynamic-blocks.md @@ -26,7 +26,7 @@ import { useSelect } from '@wordpress/data'; import { useBlockProps } from '@wordpress/block-editor'; registerBlockType( 'gutenberg-examples/example-dynamic', { - apiVersion: 2, + apiVersion: 3, title: 'Example: last post', icon: 'megaphone', category: 'widgets', @@ -62,7 +62,7 @@ registerBlockType( 'gutenberg-examples/example-dynamic', { useBlockProps = blockEditor.useBlockProps; registerBlockType( 'gutenberg-examples/example-dynamic', { - apiVersion: 2, + apiVersion: 3, title: 'Example: last post', icon: 'megaphone', category: 'widgets', @@ -132,7 +132,7 @@ function gutenberg_examples_dynamic() { ); register_block_type( 'gutenberg-examples/example-dynamic', array( - 'api_version' => 2, + 'api_version' => 3, 'editor_script' => 'gutenberg-examples-dynamic', 'render_callback' => 'gutenberg_examples_dynamic_render_callback' ) ); @@ -165,7 +165,7 @@ import ServerSideRender from '@wordpress/server-side-render'; import { useBlockProps } from '@wordpress/block-editor'; registerBlockType( 'gutenberg-examples/example-dynamic', { - apiVersion: 2, + apiVersion: 3, title: 'Example: last post', icon: 'megaphone', category: 'widgets', @@ -194,7 +194,7 @@ registerBlockType( 'gutenberg-examples/example-dynamic', { useBlockProps = blockEditor.useBlockProps; registerBlockType( 'gutenberg-examples/example-dynamic', { - apiVersion: 2, + apiVersion: 3, title: 'Example: last post', icon: 'megaphone', category: 'widgets', 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 b0def1aff4d08..8f4c54451cdb2 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 @@ -60,7 +60,7 @@ import { registerBlockType } from '@wordpress/blocks'; import { useBlockProps, RichText } from '@wordpress/block-editor'; registerBlockType( 'gutenberg-examples/example-03-editable-esnext', { - apiVersion: 2, + apiVersion: 3, title: 'Example: Editable (esnext)', icon: 'universal-access-alt', category: 'design', @@ -117,7 +117,7 @@ registerBlockType( 'gutenberg-examples/example-03-editable-esnext', { var useBlockProps = blockEditor.useBlockProps; blocks.registerBlockType( 'gutenberg-examples/example-03-editable', { - apiVersion: 2, + apiVersion: 3, title: 'Example: Editable', icon: 'universal-access-alt', category: 'design', 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 83a3cd156251b..40f9dcfcfb5fd 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 @@ -43,7 +43,7 @@ Create a basic `block.json` file there: ```json { - "apiVersion": 2, + "apiVersion": 3, "title": "Example: Basic (ESNext)", "name": "gutenberg-examples/example-01-basic-esnext", "category": "layout", @@ -56,7 +56,7 @@ Create a basic `block.json` file there: ```json { - "apiVersion": 2, + "apiVersion": 3, "title": "Example: Basic", "name": "gutenberg-examples/example-01-basic", "category": "layout", diff --git a/docs/how-to-guides/internationalization.md b/docs/how-to-guides/internationalization.md index fa28b78b37690..af68da2719335 100644 --- a/docs/how-to-guides/internationalization.md +++ b/docs/how-to-guides/internationalization.md @@ -28,7 +28,7 @@ function myguten_block_init() { ); register_block_type( 'myguten/simple', array( - 'api_version' => 2, + 'api_version' => 3, 'editor_script' => 'myguten-script', ) ); } @@ -46,7 +46,7 @@ import { registerBlockType } from '@wordpress/blocks'; import { useBlockProps } from '@wordpress/block-editor'; registerBlockType( 'myguten/simple', { - apiVersion: 2, + apiVersion: 3, title: __( 'Simple Block', 'myguten' ), category: 'widgets', diff --git a/docs/how-to-guides/metabox.md b/docs/how-to-guides/metabox.md index 382afd602ed3d..7a8686968d2cf 100644 --- a/docs/how-to-guides/metabox.md +++ b/docs/how-to-guides/metabox.md @@ -152,7 +152,7 @@ function myguten_render_paragraph( $block_attributes, $content ) { } register_block_type( 'core/paragraph', array( - 'api_version' => 2, + 'api_version' => 3, 'render_callback' => 'myguten_render_paragraph', ) ); ``` diff --git a/docs/reference-guides/block-api/block-edit-save.md b/docs/reference-guides/block-api/block-edit-save.md index f585d73454727..843a8d5be12d3 100644 --- a/docs/reference-guides/block-api/block-edit-save.md +++ b/docs/reference-guides/block-api/block-edit-save.md @@ -14,7 +14,7 @@ import { useBlockProps } from '@wordpress/block-editor'; // ... const blockSettings = { - apiVersion: 2, + apiVersion: 3, // ... @@ -30,7 +30,7 @@ const blockSettings = { ```js var blockSettings = { - apiVersion: 2, + apiVersion: 3, // ... @@ -58,7 +58,7 @@ import { useBlockProps } from '@wordpress/block-editor'; // ... const blockSettings = { - apiVersion: 2, + apiVersion: 3, // ... @@ -76,7 +76,7 @@ const blockSettings = { ```js var blockSettings = { - apiVersion: 2, + apiVersion: 3, // ... diff --git a/docs/reference-guides/block-api/block-metadata.md b/docs/reference-guides/block-api/block-metadata.md index 9bfdce9279ff2..216509ab1df13 100644 --- a/docs/reference-guides/block-api/block-metadata.md +++ b/docs/reference-guides/block-api/block-metadata.md @@ -7,7 +7,7 @@ Starting in WordPress 5.8 release, we recommend using the `block.json` metadata ```json { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "my-plugin/notice", "title": "Notice", "category": "text", @@ -150,10 +150,10 @@ This section describes all the properties that can be added to the `block.json` - Default: `1` ```json -{ "apiVersion": 2 } +{ "apiVersion": 3 } ``` -The version of the Block API used by the block. The most recent version is `2` and it was introduced in WordPress 5.6. +The version of the Block API used by the block. The most recent version is `3` and it was introduced in WordPress 6.3. See the [the API versions documentation](/docs/reference-guides/block-api/block-api-versions.md) for more details. diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index c9fa11d078ef0..bf0d3bf71d06f 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -600,7 +600,7 @@ Contains the block elements used to render a post, like the title, date, feature - **Name:** core/post-template - **Category:** theme - **Parent:** core/query -- **Supports:** align (full, wide), anchor, color (background, gradients, link, text), typography (fontSize, lineHeight), ~~html~~, ~~reusable~~ +- **Supports:** align (full, wide), anchor, color (background, gradients, link, text), spacing (blockGap), typography (fontSize, lineHeight), ~~html~~, ~~reusable~~ - **Attributes:** ## Post Terms @@ -656,7 +656,7 @@ An advanced block that allows displaying post types based on different query par - **Name:** core/query - **Category:** theme - **Supports:** align (full, wide), anchor, ~~html~~ -- **Attributes:** displayLayout, namespace, query, queryId, tagName +- **Attributes:** namespace, query, queryId, tagName ## No results diff --git a/docs/reference-guides/data/data-core-edit-site.md b/docs/reference-guides/data/data-core-edit-site.md index 0dad03bbc8ca2..523bb8d2bbff5 100644 --- a/docs/reference-guides/data/data-core-edit-site.md +++ b/docs/reference-guides/data/data-core-edit-site.md @@ -131,6 +131,18 @@ _Returns_ - `Object`: Settings. +### hasPageContentLock + +Whether or not the editor is locked so that only page content can be edited. + +_Parameters_ + +- _state_ `Object`: Global application state. + +_Returns_ + +- `boolean`: Whether or not the editor is locked. + ### isFeatureActive > **Deprecated** @@ -174,6 +186,22 @@ _Returns_ > **Deprecated** +### isPage + +Whether or not the editor has a page loaded into it. + +_Related_ + +- setPage + +_Parameters_ + +- _state_ `Object`: Global application state. + +_Returns_ + +- `boolean`: Whether or not the editor has a page loaded into it. + ### isSaveViewOpened Returns the current opened/closed state of the save panel. @@ -252,6 +280,14 @@ _Returns_ - `number`: The resolved template ID for the page route. +### setHasPageContentLock + +Sets whether or not the editor is locked so that only page content can be edited. + +_Parameters_ + +- _hasPageContentLock_ `boolean`: True to enable lock, false to disable. + ### setHomeTemplateId > **Deprecated** diff --git a/gutenberg.php b/gutenberg.php index d240d53701e92..08813fbb24fee 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.1 * Requires PHP: 5.6 - * Version: 15.9.0 + * Version: 15.9.1 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 5a23573dd1dfa..fb3098d06f743 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -280,12 +280,19 @@ function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support } } } elseif ( 'grid' === $layout_type ) { - $minimum_column_width = ! empty( $layout['minimumColumnWidth'] ) ? $layout['minimumColumnWidth'] : '12rem'; + if ( ! empty( $layout['columnCount'] ) ) { + $layout_styles[] = array( + 'selector' => $selector, + 'declarations' => array( 'grid-template-columns' => 'repeat(' . $layout['columnCount'] . ', minmax(0, 1fr))' ), + ); + } else { + $minimum_column_width = ! empty( $layout['minimumColumnWidth'] ) ? $layout['minimumColumnWidth'] : '12rem'; - $layout_styles[] = array( - 'selector' => $selector, - 'declarations' => array( 'grid-template-columns' => 'repeat(auto-fill, minmax(min(' . $minimum_column_width . ', 100%), 1fr))' ), - ); + $layout_styles[] = array( + 'selector' => $selector, + 'declarations' => array( 'grid-template-columns' => 'repeat(auto-fill, minmax(min(' . $minimum_column_width . ', 100%), 1fr))' ), + ); + } if ( $has_block_gap_support && isset( $gap_value ) ) { $combined_gap_value = ''; diff --git a/lib/blocks.php b/lib/blocks.php index 5c1d81f120c4a..fdbc555a2f944 100644 --- a/lib/blocks.php +++ b/lib/blocks.php @@ -77,6 +77,7 @@ function gutenberg_reregister_core_block_types() { 'navigation-link.php' => 'core/navigation-link', 'navigation-submenu.php' => 'core/navigation-submenu', 'page-list.php' => 'core/page-list', + 'page-list-item.php' => 'core/page-list-item', 'pattern.php' => 'core/pattern', 'post-author.php' => 'core/post-author', 'post-author-name.php' => 'core/post-author-name', diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 8fbd3ea6e70df..5cb11c2d7aaf9 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -1073,11 +1073,13 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' } $stylesheet .= $this->get_block_classes( $style_nodes ); } elseif ( in_array( 'base-layout-styles', $types, true ) ) { - $root_selector = static::ROOT_BLOCK_SELECTOR; - $columns_selector = '.wp-block-columns'; + $root_selector = static::ROOT_BLOCK_SELECTOR; + $columns_selector = '.wp-block-columns'; + $post_template_selector = '.wp-block-post-template'; if ( ! empty( $options['scope'] ) ) { - $root_selector = static::scope_selector( $options['scope'], $root_selector ); - $columns_selector = static::scope_selector( $options['scope'], $columns_selector ); + $root_selector = static::scope_selector( $options['scope'], $root_selector ); + $columns_selector = static::scope_selector( $options['scope'], $columns_selector ); + $post_template_selector = static::scope_selector( $options['scope'], $post_template_selector ); } if ( ! empty( $options['root_selector'] ) ) { $root_selector = $options['root_selector']; @@ -1094,6 +1096,11 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets' 'selector' => $columns_selector, 'name' => 'core/columns', ), + array( + 'path' => array( 'styles', 'blocks', 'core/post-template' ), + 'selector' => $post_template_selector, + 'name' => 'core/post-template', + ), ); foreach ( $base_styles_nodes as $base_style_node ) { @@ -1298,7 +1305,7 @@ protected function get_layout_styles( $block_metadata ) { if ( null !== $block_gap_value && false !== $block_gap_value && '' !== $block_gap_value ) { foreach ( $layout_definitions as $layout_definition_key => $layout_definition ) { // Allow outputting fallback gap styles for flex layout type when block gap support isn't available. - if ( ! $has_block_gap_support && 'flex' !== $layout_definition_key ) { + if ( ! $has_block_gap_support && 'flex' !== $layout_definition_key && 'grid' !== $layout_definition_key ) { continue; } diff --git a/lib/compat/wordpress-6.3/script-loader.php b/lib/compat/wordpress-6.3/script-loader.php index 9b7ace36802cc..c515eb10fdc6b 100644 --- a/lib/compat/wordpress-6.3/script-loader.php +++ b/lib/compat/wordpress-6.3/script-loader.php @@ -42,8 +42,12 @@ function _gutenberg_get_iframed_editor_assets() { $wp_styles->registered = $current_wp_styles->registered; $wp_scripts->registered = $current_wp_scripts->registered; - // We do not need reset styles for the iframed editor. - $wp_styles->done = array( 'wp-reset-editor-styles' ); + // We generally do not need reset styles for the iframed editor. + // However, if it's a classic theme, margins will be added to every block, + // which is reset specifically for list items, so classic themes rely on + // these reset styles. + $wp_styles->done = + wp_theme_has_theme_json() ? array( 'wp-reset-editor-styles' ) : array(); wp_enqueue_script( 'wp-polyfill' ); // Enqueue the `editorStyle` handles for all core block, and dependencies. diff --git a/lib/experimental/fonts-api/class-wp-fonts-provider-local.php b/lib/experimental/fonts-api/class-wp-fonts-provider-local.php index a5dbdb707e41f..019861a9ae191 100644 --- a/lib/experimental/fonts-api/class-wp-fonts-provider-local.php +++ b/lib/experimental/fonts-api/class-wp-fonts-provider-local.php @@ -207,11 +207,6 @@ private function compile_src( array $value ) { $src = ''; foreach ( $value as $item ) { - - if ( str_starts_with( $item['url'], get_site_url() ) ) { - $item['url'] = wp_make_link_relative( $item['url'] ); - } - $src .= ( 'data' === $item['format'] ) ? ", url({$item['url']})" : ", url('{$item['url']}') format('{$item['format']}')"; diff --git a/package-lock.json b/package-lock.json index e9c3db13b74ca..f26c7edec3055 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "15.9.0", + "version": "15.9.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index b9e67c0013ae7..fb9c09649f476 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "15.9.0", + "version": "15.9.1", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", diff --git a/packages/block-editor/src/components/block-draggable/index.js b/packages/block-editor/src/components/block-draggable/index.js index 02844e8899397..1e4048c90ab61 100644 --- a/packages/block-editor/src/components/block-draggable/index.js +++ b/packages/block-editor/src/components/block-draggable/index.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { getBlockType } from '@wordpress/blocks'; +import { store as blocksStore } from '@wordpress/blocks'; import { Draggable } from '@wordpress/components'; import { useSelect, useDispatch } from '@wordpress/data'; import { useEffect, useRef } from '@wordpress/element'; @@ -24,6 +24,7 @@ const BlockDraggable = ( { ( select ) => { const { canMoveBlocks, getBlockRootClientId, getBlockName } = select( blockEditorStore ); + const { getBlockType } = select( blocksStore ); const rootClientId = getBlockRootClientId( clientIds[ 0 ] ); const blockName = getBlockName( clientIds[ 0 ] ); diff --git a/packages/block-editor/src/components/block-edit/test/edit.js b/packages/block-editor/src/components/block-edit/test/edit.js index 26d90bcd5b281..0eb4c72cbbfc9 100644 --- a/packages/block-editor/src/components/block-edit/test/edit.js +++ b/packages/block-editor/src/components/block-edit/test/edit.js @@ -107,7 +107,7 @@ describe( 'Edit', () => { it( 'should assign context', () => { const edit = ( { context } ) => context.value; registerBlockType( 'core/test-block', { - apiVersion: 2, + apiVersion: 3, category: 'text', title: 'block title', usesContext: [ 'value' ], diff --git a/packages/block-editor/src/components/block-inspector/index.js b/packages/block-editor/src/components/block-inspector/index.js index 199f4f4628b4b..b6ac55afa6712 100644 --- a/packages/block-editor/src/components/block-inspector/index.js +++ b/packages/block-editor/src/components/block-inspector/index.js @@ -356,6 +356,7 @@ const BlockInspectorSingleBlock = ( { clientId, blockName } ) => { ) } + @@ -46,13 +47,15 @@ function useAppender( rootClientId, CustomAppender ) { getTemplateLock, getSelectedBlockClientId, __unstableGetEditorMode, - } = select( blockEditorStore ); + getBlockEditingMode, + } = unlock( select( blockEditorStore ) ); const selectedBlockClientId = getSelectedBlockClientId(); return { hideInserter: !! getTemplateLock( rootClientId ) || + getBlockEditingMode( rootClientId ) === 'disabled' || __unstableGetEditorMode() === 'zoom-out', isParentSelected: rootClientId === selectedBlockClientId || diff --git a/packages/block-editor/src/components/block-list/content.scss b/packages/block-editor/src/components/block-list/content.scss index dab07ced873e9..a163ddaa78955 100644 --- a/packages/block-editor/src/components/block-list/content.scss +++ b/packages/block-editor/src/components/block-list/content.scss @@ -161,15 +161,6 @@ padding: 0; } -.block-editor-block-list__layout, -.block-editor-block-list__block { - pointer-events: initial; - - &.is-editing-disabled { - pointer-events: none; - } -} - .block-editor-block-list__layout .block-editor-block-list__block { // With `position: static`, Safari marks a full-width selection rectangle, including margins. // With `position: relative`, Safari marks an inline selection rectangle, similar to that of @@ -178,12 +169,17 @@ // We choose relative, as that matches the multi-selection, which is limited to the block footprint. position: relative; - // Re-enable text-selection on editable blocks. - user-select: text; - // Break long strings of text without spaces so they don't overflow the block. overflow-wrap: break-word; + pointer-events: auto; + user-select: text; + + &.is-editing-disabled { + pointer-events: none; + user-select: none; + } + .reusable-block-edit-panel * { z-index: z-index(".block-editor-block-list__block .reusable-block-edit-panel *"); } diff --git a/packages/block-editor/src/components/block-list/use-block-props/index.js b/packages/block-editor/src/components/block-list/use-block-props/index.js index acc2bd7f510ed..ab65e120024d6 100644 --- a/packages/block-editor/src/components/block-list/use-block-props/index.js +++ b/packages/block-editor/src/components/block-list/use-block-props/index.js @@ -36,6 +36,7 @@ import { useBlockRefProvider } from './use-block-refs'; import { useIntersectionObserver } from './use-intersection-observer'; import { store as blockEditorStore } from '../../../store'; import useBlockOverlayActive from '../../block-content-overlay'; +import { unlock } from '../../../lock-unlock'; /** * If the block count exceeds the threshold, we disable the reordering animation @@ -75,6 +76,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) { isPartOfSelection, adjustScrolling, enableAnimation, + isSubtreeDisabled, } = useSelect( ( select ) => { const { @@ -88,7 +90,8 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) { isBlockMultiSelected, isAncestorMultiSelected, isFirstMultiSelectedBlock, - } = select( blockEditorStore ); + isBlockSubtreeDisabled, + } = unlock( select( blockEditorStore ) ); const { getActiveBlockVariation } = select( blocksStore ); const isSelected = isBlockSelected( clientId ); const isPartOfMultiSelection = @@ -111,6 +114,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) { enableAnimation: ! isTyping() && getGlobalBlockCount() <= BLOCK_ANIMATION_THRESHOLD, + isSubtreeDisabled: isBlockSubtreeDisabled( clientId ), }; }, [ clientId ] @@ -158,6 +162,7 @@ export function useBlockProps( props = {}, { __unstableIsHtml } = {} ) { 'data-block': clientId, 'data-type': name, 'data-title': blockTitle, + inert: isSubtreeDisabled ? 'true' : undefined, className: classnames( // The wp-block className is important for editor styles. classnames( 'block-editor-block-list__block', { diff --git a/packages/block-editor/src/components/global-styles/use-global-styles-output.js b/packages/block-editor/src/components/global-styles/use-global-styles-output.js index 0b82c40f6803f..b20ddd0f02f54 100644 --- a/packages/block-editor/src/components/global-styles/use-global-styles-output.js +++ b/packages/block-editor/src/components/global-styles/use-global-styles-output.js @@ -460,7 +460,11 @@ export function getLayoutStyles( { Object.values( tree.settings.layout.definitions ).forEach( ( { className, name, spacingStyles } ) => { // Allow outputting fallback gap styles for flex layout type when block gap support isn't available. - if ( ! hasBlockGapSupport && 'flex' !== name ) { + if ( + ! hasBlockGapSupport && + 'flex' !== name && + 'grid' !== name + ) { return; } diff --git a/packages/block-editor/src/components/iframe/use-compatibility-styles.js b/packages/block-editor/src/components/iframe/use-compatibility-styles.js index 92e755b318ec4..bebdf388bcb25 100644 --- a/packages/block-editor/src/components/iframe/use-compatibility-styles.js +++ b/packages/block-editor/src/components/iframe/use-compatibility-styles.js @@ -38,12 +38,6 @@ export function useCompatibilityStyles() { return accumulator; } - // Generally, ignore inline styles. We add inline styles belonging to a - // stylesheet later, which may or may not match the selectors. - if ( ownerNode.tagName !== 'LINK' ) { - return accumulator; - } - // Don't try to add the reset styles, which were removed as a dependency // from `edit-blocks` for the iframe since we don't need to reset admin // styles. @@ -76,20 +70,25 @@ export function useCompatibilityStyles() { } if ( matchFromRules( cssRules ) ) { - // Display warning once we have a way to add style dependencies to the editor. - // See: https://github.com/WordPress/gutenberg/pull/37466. - accumulator.push( ownerNode.cloneNode( true ) ); + const isInline = ownerNode.tagName === 'STYLE'; // Add inline styles belonging to the stylesheet. const inlineCssId = ownerNode.id.replace( - '-css', - '-inline-css' + isInline ? '-inline-css' : '-css', + isInline ? '-css' : '-inline-css' ); - const inlineCssElement = - document.getElementById( inlineCssId ); + const otherElement = document.getElementById( inlineCssId ); + + // If the matched stylesheet is inline, add the main + // stylesheet before the inline style element. + if ( otherElement && isInline ) { + accumulator.push( otherElement.cloneNode( true ) ); + } + + accumulator.push( ownerNode.cloneNode( true ) ); - if ( inlineCssElement ) { - accumulator.push( inlineCssElement.cloneNode( true ) ); + if ( otherElement && ! isInline ) { + accumulator.push( otherElement.cloneNode( true ) ); } } diff --git a/packages/block-editor/src/components/inspector-controls-tabs/index.js b/packages/block-editor/src/components/inspector-controls-tabs/index.js index a02aa7cc208a6..de192050d05cb 100644 --- a/packages/block-editor/src/components/inspector-controls-tabs/index.js +++ b/packages/block-editor/src/components/inspector-controls-tabs/index.js @@ -26,7 +26,6 @@ export default function InspectorControlsTabs( { const initialTabName = ! useIsListViewTabDisabled( blockName ) ? TAB_LIST_VIEW.name : undefined; - return ( { return ( props ) => { const hasAnchor = hasBlockSupport( props.name, 'anchor' ); + const blockEditingMode = useBlockEditingMode(); if ( hasAnchor && props.isSelected ) { const isWeb = Platform.OS === 'web'; @@ -104,7 +106,7 @@ export const withInspectorControl = createHigherOrderComponent( return ( <> - { isWeb && ( + { isWeb && blockEditingMode === 'default' && ( { textControl } diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index 706d3638e345a..63230b6ee273f 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -18,7 +18,12 @@ import { store as blockEditorStore } from '../store'; */ import merge from 'deepmerge'; -function BehaviorsControl( { blockName, blockBehaviors, onChange } ) { +function BehaviorsControl( { + blockName, + blockBehaviors, + onChange, + disabled = false, +} ) { const { settings, themeBehaviors } = useSelect( ( select ) => { const { getBehaviors, getSettings } = select( blockEditorStore ); @@ -61,6 +66,10 @@ function BehaviorsControl( { blockName, blockBehaviors, onChange } ) { const options = [ noBehaviorsOption, ...behaviorsOptions ]; + const helpText = disabled + ? __( 'The lightbox behavior is disabled for linked images.' ) + : __( 'Add behaviors.' ); + return ( ); @@ -95,7 +105,9 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { if ( props.name !== 'core/image' ) { return blockEdit; } - + const blockHasLink = + typeof props.attributes?.linkDestination !== 'undefined' && + props.attributes?.linkDestination !== 'none'; return ( <> { blockEdit } @@ -111,6 +123,7 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { }, } ); } } + disabled={ blockHasLink } /> ); diff --git a/packages/block-editor/src/hooks/custom-class-name.js b/packages/block-editor/src/hooks/custom-class-name.js index fa1a1cadc5712..5505c5fcae2cc 100644 --- a/packages/block-editor/src/hooks/custom-class-name.js +++ b/packages/block-editor/src/hooks/custom-class-name.js @@ -16,6 +16,7 @@ import { createHigherOrderComponent } from '@wordpress/compose'; * Internal dependencies */ import { InspectorControls } from '../components'; +import { useBlockEditingMode } from '../components/block-editing-mode'; /** * Filters registered block settings, extending attributes to include `className`. @@ -50,6 +51,7 @@ export function addAttribute( settings ) { export const withInspectorControl = createHigherOrderComponent( ( BlockEdit ) => { return ( props ) => { + const blockEditingMode = useBlockEditingMode(); const hasCustomClassName = hasBlockSupport( props.name, 'customClassName', @@ -59,25 +61,27 @@ export const withInspectorControl = createHigherOrderComponent( return ( <> - - { - props.setAttributes( { - className: - nextValue !== '' - ? nextValue - : undefined, - } ); - } } - help={ __( - 'Separate multiple classes with spaces.' - ) } - /> - + { blockEditingMode === 'default' && ( + + { + props.setAttributes( { + className: + nextValue !== '' + ? nextValue + : undefined, + } ); + } } + help={ __( + 'Separate multiple classes with spaces.' + ) } + /> + + ) } ); } diff --git a/packages/block-editor/src/hooks/layout.js b/packages/block-editor/src/hooks/layout.js index 815b36e785a81..e02e34caf8291 100644 --- a/packages/block-editor/src/hooks/layout.js +++ b/packages/block-editor/src/hooks/layout.js @@ -329,8 +329,11 @@ export const withInspectorControls = createHigherOrderComponent( layoutBlockSupportKey ); + const blockEditingMode = useBlockEditingMode(); return [ - supportLayout && , + supportLayout && blockEditingMode === 'default' && ( + + ), , ]; }, diff --git a/packages/block-editor/src/hooks/style.js b/packages/block-editor/src/hooks/style.js index edf28773e14d5..11946ff53a6de 100644 --- a/packages/block-editor/src/hooks/style.js +++ b/packages/block-editor/src/hooks/style.js @@ -34,6 +34,7 @@ import { } from './dimensions'; import useDisplayBlockControls from '../components/use-display-block-controls'; import { shouldSkipSerialization } from './utils'; +import { useBlockEditingMode } from '../components/block-editing-mode'; const styleSupportKeys = [ ...TYPOGRAPHY_SUPPORT_KEYS, @@ -347,10 +348,11 @@ export function addEditProps( settings ) { export const withBlockControls = createHigherOrderComponent( ( BlockEdit ) => ( props ) => { const shouldDisplayControls = useDisplayBlockControls(); + const blockEditingMode = useBlockEditingMode(); return ( <> - { shouldDisplayControls && ( + { shouldDisplayControls && blockEditingMode === 'default' && ( <> diff --git a/packages/block-editor/src/layouts/grid.js b/packages/block-editor/src/layouts/grid.js index 69347123fd421..c2cda643baa70 100644 --- a/packages/block-editor/src/layouts/grid.js +++ b/packages/block-editor/src/layouts/grid.js @@ -35,7 +35,9 @@ export default { layout = {}, onChange, } ) { - return ( + return layout?.columnCount ? ( + + ) : ( ); } + +// Enables setting number of grid columns +function GridLayoutColumnsControl( { layout, onChange } ) { + const { columnCount = 3 } = layout; + + return ( + + onChange( { + ...layout, + columnCount: value, + } ) + } + min={ 1 } + max={ 6 } + /> + ); +} diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js index ce7802036184e..ff85b4fb3f20b 100644 --- a/packages/block-editor/src/store/private-selectors.js +++ b/packages/block-editor/src/store/private-selectors.js @@ -6,7 +6,7 @@ import createSelector from 'rememo'; /** * WordPress dependencies */ -import { createRegistrySelector } from '@wordpress/data'; +import { select } from '@wordpress/data'; import { store as blocksStore } from '@wordpress/blocks'; /** @@ -16,6 +16,7 @@ import { getBlockRootClientId, getTemplateLock, getBlockName, + getBlockOrder, } from './selectors'; /** @@ -71,45 +72,66 @@ export function getLastInsertedBlocksClientIds( state ) { * @return {BlockEditingMode} The block editing mode. One of `'disabled'`, * `'contentOnly'`, or `'default'`. */ -export const getBlockEditingMode = createRegistrySelector( - ( select ) => - ( state, clientId = '' ) => { - const explicitEditingMode = getExplcitBlockEditingMode( - state, - clientId - ); - const rootClientId = getBlockRootClientId( state, clientId ); - const templateLock = getTemplateLock( state, rootClientId ); +export const getBlockEditingMode = createSelector( + ( state, clientId = '' ) => { + if ( state.blockEditingModes.has( clientId ) ) { + return state.blockEditingModes.get( clientId ); + } + if ( ! clientId ) { + return 'default'; + } + const rootClientId = getBlockRootClientId( state, clientId ); + const templateLock = getTemplateLock( state, rootClientId ); + if ( templateLock === 'contentOnly' ) { const name = getBlockName( state, clientId ); + // TODO: Terrible hack! We're calling the global select() function + // here instead of using createRegistrySelector(). The problem with + // using createRegistrySelector() is that then the public + // block-editor selectors (e.g. canInsertBlockTypeUnmemoized) can't + // call this private block-editor selector due to a bug in + // @wordpress/data. See + // https://github.com/WordPress/gutenberg/pull/50985. const isContent = select( blocksStore ).__experimentalHasContentRoleAttribute( name ); - if ( - explicitEditingMode === 'disabled' || - ( templateLock === 'contentOnly' && ! isContent ) - ) { - return 'disabled'; - } - if ( - explicitEditingMode === 'contentOnly' || - ( templateLock === 'contentOnly' && isContent ) - ) { - return 'contentOnly'; - } - return 'default'; + return isContent ? 'contentOnly' : 'disabled'; } + const parentMode = getBlockEditingMode( state, rootClientId ); + return parentMode === 'contentOnly' ? 'default' : parentMode; + }, + ( state ) => [ + state.blockEditingModes, + state.blocks.parents, + state.settings.templateLock, + state.blockListSettings, + ] ); -const getExplcitBlockEditingMode = createSelector( - ( state, clientId = '' ) => { - while ( - ! state.blockEditingModes.has( clientId ) && - state.blocks.parents.has( clientId ) - ) { - clientId = state.blocks.parents.get( clientId ); - } - return state.blockEditingModes.get( clientId ) ?? 'default'; +/** + * Returns true if the block with the given client ID and all of its descendants + * have an editing mode of 'disabled', or false otherwise. + * + * @param {Object} state Global application state. + * @param {string} clientId The block client ID. + * + * @return {boolean} Whether the block and its descendants are disabled. + */ +export const isBlockSubtreeDisabled = createSelector( + ( state, clientId ) => { + const isChildSubtreeDisabled = ( childClientId ) => { + const mode = state.blockEditingModes.get( childClientId ); + return ( + ( mode === undefined || mode === 'disabled' ) && + getBlockOrder( state, childClientId ).every( + isChildSubtreeDisabled + ) + ); + }; + return ( + getBlockEditingMode( state, clientId ) === 'disabled' && + getBlockOrder( state, clientId ).every( isChildSubtreeDisabled ) + ); }, ( state ) => [ state.blockEditingModes, state.blocks.parents ] ); diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 487d13db811d8..5b615f67defbd 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -26,6 +26,7 @@ import deprecated from '@wordpress/deprecated'; */ import { mapRichTextSettings } from './utils'; import { orderBy } from '../utils/sorting'; +import { getBlockEditingMode } from './private-selectors'; /** * A block selection object. @@ -1539,6 +1540,10 @@ const canInsertBlockTypeUnmemoized = ( return false; } + if ( getBlockEditingMode( state, rootClientId ?? '' ) === 'disabled' ) { + return false; + } + const parentBlockListSettings = getBlockListSettings( state, rootClientId ); // The parent block doesn't have settings indicating it doesn't support @@ -1633,6 +1638,7 @@ export const canInsertBlockType = createSelector( state.blocks.byClientId.get( rootClientId ), state.settings.allowedBlockTypes, state.settings.templateLock, + state.blockEditingModes, ] ); @@ -1663,21 +1669,19 @@ export function canInsertBlocks( state, clientIds, rootClientId = null ) { */ export function canRemoveBlock( state, clientId, rootClientId = null ) { const attributes = getBlockAttributes( state, clientId ); - - // attributes can be null if the block is already deleted. if ( attributes === null ) { return true; } - - const { lock } = attributes; - const parentIsLocked = !! getTemplateLock( state, rootClientId ); - // If we don't have a lock on the blockType level, we defer to the parent templateLock. - if ( lock === undefined || lock?.remove === undefined ) { - return ! parentIsLocked; + if ( attributes.lock?.remove ) { + return false; } - - // When remove is true, it means we cannot remove it. - return ! lock?.remove; + if ( getTemplateLock( state, rootClientId ) ) { + return false; + } + if ( getBlockEditingMode( state, rootClientId ) === 'disabled' ) { + return false; + } + return true; } /** @@ -1709,16 +1713,16 @@ export function canMoveBlock( state, clientId, rootClientId = null ) { if ( attributes === null ) { return; } - - const { lock } = attributes; - const parentIsLocked = getTemplateLock( state, rootClientId ) === 'all'; - // If we don't have a lock on the blockType level, we defer to the parent templateLock. - if ( lock === undefined || lock?.move === undefined ) { - return ! parentIsLocked; + if ( attributes.lock?.move ) { + return false; } - - // When move is true, it means we cannot move it. - return ! lock?.move; + if ( getTemplateLock( state, rootClientId ) === 'all' ) { + return false; + } + if ( getBlockEditingMode( state, rootClientId ) === 'disabled' ) { + return false; + } + return true; } /** @@ -2812,6 +2816,13 @@ export function __unstableGetTemporarilyEditingAsBlocks( state ) { } export function __unstableHasActiveBlockOverlayActive( state, clientId ) { + // Prevent overlay on disabled blocks. It's redundant since disabled blocks + // can't be selected, and prevents non-disabled nested blocks from being + // selected. + if ( getBlockEditingMode( state, clientId ) === 'disabled' ) { + return false; + } + // If the block editing is locked, the block overlay is always active. if ( ! canEditBlock( state, clientId ) ) { return true; diff --git a/packages/block-editor/src/store/test/private-selectors.js b/packages/block-editor/src/store/test/private-selectors.js index 954c8c94c1379..ecae342317ce1 100644 --- a/packages/block-editor/src/store/test/private-selectors.js +++ b/packages/block-editor/src/store/test/private-selectors.js @@ -1,3 +1,8 @@ +/** + * WordPress dependencies + */ +import { select } from '@wordpress/data'; + /** * Internal dependencies */ @@ -5,8 +10,13 @@ import { isBlockInterfaceHidden, getLastInsertedBlocksClientIds, getBlockEditingMode, + isBlockSubtreeDisabled, } from '../private-selectors'; +jest.mock( '@wordpress/data/src/select', () => ( { + select: jest.fn(), +} ) ); + describe( 'private selectors', () => { describe( 'isBlockInterfaceHidden', () => { it( 'should return the true if toggled true in state', () => { @@ -51,7 +61,7 @@ describe( 'private selectors', () => { } ); } ); - describe( 'getBlockEditingMode', () => { + describe( 'block editing mode selectors', () => { const baseState = { settings: {}, blocks: { @@ -63,6 +73,27 @@ describe( 'private selectors', () => { [ 'b3247f75-fd94-4fef-97f9-5bfd162cc416', {} ], // | | Paragraph [ 'e178812d-ce5e-48c7-a945-8ae4ffcbbb7c', {} ], // | | Paragraph ] ), + order: new Map( [ + [ '', [ '6cf70164-9097-4460-bcbf-200560546988' ] ], + [ '6cf70164-9097-4460-bcbf-200560546988', [] ], + [ + 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', + [ + 'b26fc763-417d-4f01-b81c-2ec61e14a972', + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', + ], + ], + [ 'b26fc763-417d-4f01-b81c-2ec61e14a972', [] ], + [ + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', + [ + 'b3247f75-fd94-4fef-97f9-5bfd162cc416', + 'e178812d-ce5e-48c7-a945-8ae4ffcbbb7c', + ], + ], + [ 'b3247f75-fd94-4fef-97f9-5bfd162cc416', [] ], + [ 'e178812d-ce5e-48c7-a945-8ae4ffcbbb7c', [] ], + ] ), parents: new Map( [ [ '6cf70164-9097-4460-bcbf-200560546988', '' ], [ 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', '' ], @@ -91,28 +122,28 @@ describe( 'private selectors', () => { blockEditingModes: new Map( [] ), }; - const __experimentalHasContentRoleAttribute = jest.fn( () => false ); - getBlockEditingMode.registry = { - select: jest.fn( () => ( { + describe( 'getBlockEditingMode', () => { + const __experimentalHasContentRoleAttribute = jest.fn( + () => false + ); + select.mockReturnValue( { __experimentalHasContentRoleAttribute, - } ) ), - }; + } ); - it( 'should return default by default', () => { - expect( - getBlockEditingMode( - baseState, - 'b3247f75-fd94-4fef-97f9-5bfd162cc416' - ) - ).toBe( 'default' ); - } ); + it( 'should return default by default', () => { + expect( + getBlockEditingMode( + baseState, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'default' ); + } ); - [ 'disabled', 'contentOnly' ].forEach( ( mode ) => { - it( `should return ${ mode } if explicitly set`, () => { + it( 'should return disabled if explicitly set', () => { const state = { ...baseState, blockEditingModes: new Map( [ - [ 'b3247f75-fd94-4fef-97f9-5bfd162cc416', mode ], + [ 'b3247f75-fd94-4fef-97f9-5bfd162cc416', 'disabled' ], ] ), }; expect( @@ -120,14 +151,17 @@ describe( 'private selectors', () => { state, 'b3247f75-fd94-4fef-97f9-5bfd162cc416' ) - ).toBe( mode ); + ).toBe( 'disabled' ); } ); - it( `should return ${ mode } if explicitly set on a parent`, () => { + it( 'should return contentOnly if explicitly set', () => { const state = { ...baseState, blockEditingModes: new Map( [ - [ 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', mode ], + [ + 'b3247f75-fd94-4fef-97f9-5bfd162cc416', + 'contentOnly', + ], ] ), }; expect( @@ -135,16 +169,49 @@ describe( 'private selectors', () => { state, 'b3247f75-fd94-4fef-97f9-5bfd162cc416' ) - ).toBe( mode ); + ).toBe( 'contentOnly' ); } ); - it( `should return ${ mode } if overridden by a parent`, () => { + it( 'should return disabled if explicitly set on a parent', () => { const state = { ...baseState, blockEditingModes: new Map( [ - [ '', mode ], + [ 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', 'disabled' ], + ] ), + }; + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'disabled' ); + } ); + + it( 'should return default if parent is set to contentOnly', () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ + [ + 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', + 'contentOnly', + ], + ] ), + }; + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'default' ); + } ); + + it( 'should return disabled if overridden by a parent', () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ + [ '', 'disabled' ], [ 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', 'default' ], - [ '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', mode ], + [ '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f', 'disabled' ], ] ), }; expect( @@ -152,59 +219,167 @@ describe( 'private selectors', () => { state, 'b3247f75-fd94-4fef-97f9-5bfd162cc416' ) - ).toBe( mode ); + ).toBe( 'disabled' ); } ); - it( `should return ${ mode } if explicitly set on root`, () => { + it( 'should return disabled if explicitly set on root', () => { const state = { ...baseState, - blockEditingModes: new Map( [ [ '', mode ] ] ), + blockEditingModes: new Map( [ [ '', 'disabled' ] ] ), }; expect( getBlockEditingMode( state, 'b3247f75-fd94-4fef-97f9-5bfd162cc416' ) - ).toBe( mode ); + ).toBe( 'disabled' ); } ); - } ); - it( 'should return disabled if parent is locked and the block has no content role', () => { - const state = { - ...baseState, - blockListSettings: { - ...baseState.blockListSettings, - '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f': { - templateLock: 'contentOnly', + it( 'should return default if root is contentOnly', () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ [ '', 'contentOnly' ] ] ), + }; + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'default' ); + } ); + + it( 'should return disabled if parent is locked and the block has no content role', () => { + const state = { + ...baseState, + blockListSettings: { + ...baseState.blockListSettings, + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f': { + templateLock: 'contentOnly', + }, }, - }, - }; - __experimentalHasContentRoleAttribute.mockReturnValueOnce( false ); - expect( - getBlockEditingMode( - state, - 'b3247f75-fd94-4fef-97f9-5bfd162cc416' - ) - ).toBe( 'disabled' ); - } ); + }; + __experimentalHasContentRoleAttribute.mockReturnValueOnce( + false + ); + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'disabled' ); + } ); - it( 'should return contentOnly if parent is locked and the block has a content role', () => { - const state = { - ...baseState, - blockListSettings: { - ...baseState.blockListSettings, - '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f': { - templateLock: 'contentOnly', + it( 'should return contentOnly if parent is locked and the block has a content role', () => { + const state = { + ...baseState, + blockListSettings: { + ...baseState.blockListSettings, + '9b9c5c3f-2e46-4f02-9e14-9fe9515b958f': { + templateLock: 'contentOnly', + }, }, - }, - }; - __experimentalHasContentRoleAttribute.mockReturnValueOnce( true ); - expect( - getBlockEditingMode( - state, - 'b3247f75-fd94-4fef-97f9-5bfd162cc416' - ) - ).toBe( 'contentOnly' ); + }; + __experimentalHasContentRoleAttribute.mockReturnValueOnce( + true + ); + expect( + getBlockEditingMode( + state, + 'b3247f75-fd94-4fef-97f9-5bfd162cc416' + ) + ).toBe( 'contentOnly' ); + } ); + } ); + + describe( 'isBlockSubtreeDisabled', () => { + it( 'should return false when top level block is not disabled', () => { + const state = { + ...baseState, + blockEditingModes: new Map( [] ), + }; + expect( + isBlockSubtreeDisabled( + state, + 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337' + ) + ).toBe( false ); + } ); + + it( 'should return true when top level block is disabled and there are no editing modes within it', () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ + [ 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', 'disabled' ], + ] ), + }; + expect( + isBlockSubtreeDisabled( + state, + 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337' + ) + ).toBe( true ); + } ); + + it( 'should return true when top level block is disabled via inheritence and there are no editing modes within it', () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ [ '', 'disabled' ] ] ), + }; + expect( + isBlockSubtreeDisabled( + state, + 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337' + ) + ).toBe( true ); + } ); + + it( 'should return true when top level block is disabled and there are disabled editing modes within it', () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ + [ 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', 'disabled' ], + [ 'b3247f75-fd94-4fef-97f9-5bfd162cc416', 'disabled' ], + ] ), + }; + expect( + isBlockSubtreeDisabled( + state, + 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337' + ) + ).toBe( true ); + } ); + + it( 'should return false when top level block is disabled and there are non-disabled editing modes within it', () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ + [ 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337', 'disabled' ], + [ 'b3247f75-fd94-4fef-97f9-5bfd162cc416', 'default' ], + ] ), + }; + expect( + isBlockSubtreeDisabled( + state, + 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337' + ) + ).toBe( false ); + } ); + + it( 'should return false when top level block is disabled via inheritence and there are non-disabled editing modes within it', () => { + const state = { + ...baseState, + blockEditingModes: new Map( [ + [ '', 'disabled' ], + [ 'b3247f75-fd94-4fef-97f9-5bfd162cc416', 'default' ], + ] ), + }; + expect( + isBlockSubtreeDisabled( + state, + 'ef45d5fd-5234-4fd5-ac4f-c3736c7f9337' + ) + ).toBe( false ); + } ); } ); } ); } ); diff --git a/packages/block-editor/src/store/test/selectors.js b/packages/block-editor/src/store/test/selectors.js index 60d90d80b9d41..5cc17fc08b314 100644 --- a/packages/block-editor/src/store/test/selectors.js +++ b/packages/block-editor/src/store/test/selectors.js @@ -2693,11 +2693,13 @@ describe( 'selectors', () => { blocks: { byClientId: new Map(), attributes: new Map(), + parents: new Map(), }, blockListSettings: {}, settings: { allowedBlockTypes: [ 'core/test-block-a' ], }, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-a' ) ).toBe( true @@ -2720,14 +2722,36 @@ describe( 'selectors', () => { ); } ); + it( 'should deny blocks when the editor has a disabled editing mode', () => { + const state = { + blocks: { + byClientId: new Map(), + attributes: new Map(), + parents: new Map(), + }, + blockListSettings: {}, + settings: {}, + blockEditingModes: new Map( + Object.entries( { + '': 'disabled', + } ) + ), + }; + expect( canInsertBlockType( state, 'core/test-block-a' ) ).toBe( + false + ); + } ); + it( 'should deny blocks that restrict parent from being inserted into the root', () => { const state = { blocks: { byClientId: new Map(), attributes: new Map(), + parents: new Map(), }, blockListSettings: {}, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-c' ) ).toBe( false @@ -2747,9 +2771,11 @@ describe( 'selectors', () => { block1: {}, } ) ), + parents: new Map(), }, blockListSettings: {}, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-c', 'block1' ) @@ -2769,11 +2795,13 @@ describe( 'selectors', () => { block1: {}, } ) ), + parents: new Map(), }, blockListSettings: { block1: {}, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-c', 'block1' ) @@ -2793,11 +2821,13 @@ describe( 'selectors', () => { block1: {}, } ) ), + parents: new Map(), }, blockListSettings: { block1: {}, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-c', 'block1' ) @@ -2817,6 +2847,7 @@ describe( 'selectors', () => { block1: {}, } ) ), + parents: new Map(), }, blockListSettings: { block1: { @@ -2824,6 +2855,7 @@ describe( 'selectors', () => { }, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-b', 'block1' ) @@ -2843,6 +2875,7 @@ describe( 'selectors', () => { block1: {}, } ) ), + parents: new Map(), }, blockListSettings: { block1: { @@ -2850,12 +2883,41 @@ describe( 'selectors', () => { }, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-b', 'block1' ) ).toBe( true ); } ); + it( 'should deny blocks from being inserted into a block that has a disabled editing mode', () => { + const state = { + blocks: { + byClientId: new Map( + Object.entries( { + block1: { name: 'core/test-block-a' }, + } ) + ), + attributes: new Map( + Object.entries( { + block1: {}, + } ) + ), + parents: new Map(), + }, + blockListSettings: {}, + settings: {}, + blockEditingModes: new Map( + Object.entries( { + block1: 'disabled', + } ) + ), + }; + expect( + canInsertBlockType( state, 'core/test-block-b', 'block1' ) + ).toBe( false ); + } ); + it( 'should prioritise parent over allowedBlocks', () => { const state = { blocks: { @@ -2869,6 +2931,7 @@ describe( 'selectors', () => { block1: {}, } ) ), + parents: new Map(), }, blockListSettings: { block1: { @@ -2876,6 +2939,7 @@ describe( 'selectors', () => { }, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/test-block-c', 'block1' ) @@ -2895,9 +2959,11 @@ describe( 'selectors', () => { block1: {}, } ) ), + parents: new Map(), }, blockListSettings: {}, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/post-content-child', 'block1' ) @@ -2909,9 +2975,11 @@ describe( 'selectors', () => { blocks: { byClientId: new Map(), attributes: new Map(), + parents: new Map(), }, blockListSettings: {}, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( state, 'core/post-content-child' ) @@ -2944,6 +3012,7 @@ describe( 'selectors', () => { block2: {}, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -2984,6 +3053,7 @@ describe( 'selectors', () => { block3: {}, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -3023,6 +3093,7 @@ describe( 'selectors', () => { block3: {}, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -3062,6 +3133,7 @@ describe( 'selectors', () => { block3: {}, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -3100,6 +3172,7 @@ describe( 'selectors', () => { }, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -3136,6 +3209,7 @@ describe( 'selectors', () => { block2: {}, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlockType( @@ -3165,6 +3239,7 @@ describe( 'selectors', () => { 3: {}, } ) ), + parents: new Map(), }, blockListSettings: { 1: { @@ -3175,6 +3250,7 @@ describe( 'selectors', () => { }, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlocks( state, [ '2', '3' ], '1' ) ).toBe( true ); } ); @@ -3196,6 +3272,7 @@ describe( 'selectors', () => { 3: {}, } ) ), + parents: new Map(), }, blockListSettings: { 1: { @@ -3203,6 +3280,7 @@ describe( 'selectors', () => { }, }, settings: {}, + blockEditingModes: new Map(), }; expect( canInsertBlocks( state, [ '2', '3' ], '1' ) ).toBe( false ); } ); @@ -3241,6 +3319,7 @@ describe( 'selectors', () => { // See: https://github.com/WordPress/gutenberg/issues/14580 preferences: {}, blockListSettings: {}, + blockEditingModes: new Map(), }; const items = getInserterItems( state ); const testBlockAItem = items.find( @@ -3349,6 +3428,7 @@ describe( 'selectors', () => { block3: {}, block4: {}, }, + blockEditingModes: new Map(), }; const stateSecondBlockRestricted = { @@ -3436,6 +3516,7 @@ describe( 'selectors', () => { }, blockListSettings: {}, settings: {}, + blockEditingModes: new Map(), }; const items = getInserterItems( state ); const testBlockBItem = items.find( @@ -3460,6 +3541,7 @@ describe( 'selectors', () => { }, blockListSettings: {}, settings: {}, + blockEditingModes: new Map(), }; const items = getInserterItems( state ); const reusableBlock2Item = items.find( @@ -3551,6 +3633,7 @@ describe( 'selectors', () => { settings: {}, preferences: {}, blockListSettings: {}, + blockEditingModes: new Map(), }; const blocks = [ { name: 'core/with-tranforms-a' } ]; const items = getBlockTransformItems( state, blocks ); @@ -3591,6 +3674,7 @@ describe( 'selectors', () => { settings: {}, preferences: {}, blockListSettings: {}, + blockEditingModes: new Map(), }; const block = { name: 'core/with-tranforms-a' }; const items = getBlockTransformItems( state, block ); @@ -3629,6 +3713,7 @@ describe( 'selectors', () => { }, block2: {}, }, + blockEditingModes: new Map(), }; const blocks = [ { clientId: 'block2', name: 'core/with-tranforms-a' }, @@ -3676,6 +3761,7 @@ describe( 'selectors', () => { }, blockListSettings: {}, settings: {}, + blockEditingModes: new Map(), }; const blocks = [ { name: 'core/with-tranforms-a' } ]; const items = getBlockTransformItems( state, blocks ); @@ -3709,6 +3795,7 @@ describe( 'selectors', () => { }, blockListSettings: {}, settings: {}, + blockEditingModes: new Map(), }; const blocks = [ { name: 'core/with-tranforms-c' } ]; const items = getBlockTransformItems( state, blocks ); @@ -4121,6 +4208,12 @@ describe( 'selectors', () => { block2: {}, } ) ), + parents: new Map( + Object.entries( { + block1: '', + block2: '', + } ) + ), }, blockListSettings: { block1: { @@ -4152,6 +4245,7 @@ describe( 'selectors', () => { }, ], }, + blockEditingModes: new Map(), }; it( 'should return all patterns for root level', () => { @@ -4249,6 +4343,7 @@ describe( 'selectors', () => { block1: { name: 'core/test-block-a' }, } ) ), + parents: new Map(), }, blockListSettings: { block1: { @@ -4279,6 +4374,7 @@ describe( 'selectors', () => { }, ], }, + blockEditingModes: new Map(), }; it( 'should return empty array if no block name is provided', () => { expect( getPatternsByBlockTypes( state ) ).toEqual( [] ); @@ -4329,6 +4425,7 @@ describe( 'selectors', () => { block2: { name: 'core/test-block-b' }, } ) ), + parents: new Map(), controlledInnerBlocks: { 'block2-clientId': true }, }, blockListSettings: { @@ -4371,6 +4468,7 @@ describe( 'selectors', () => { }, ], }, + blockEditingModes: new Map(), }; describe( 'should return empty array', () => { it( 'when no blocks are selected', () => { @@ -4591,6 +4689,7 @@ describe( 'getInserterItems with core blocks prioritization', () => { settings: {}, preferences: {}, blockListSettings: {}, + blockEditingModes: new Map(), }; const items = getInserterItems( state ); const expectedResult = [ diff --git a/packages/block-library/src/archives/block.json b/packages/block-library/src/archives/block.json index edc6895e14b06..ec0d926281d2e 100644 --- a/packages/block-library/src/archives/block.json +++ b/packages/block-library/src/archives/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/archives", "title": "Archives", "category": "widgets", diff --git a/packages/block-library/src/audio/block.json b/packages/block-library/src/audio/block.json index 13aed788968fb..adcf67e4dc10c 100644 --- a/packages/block-library/src/audio/block.json +++ b/packages/block-library/src/audio/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/audio", "title": "Audio", "category": "media", diff --git a/packages/block-library/src/avatar/block.json b/packages/block-library/src/avatar/block.json index 3fbb6dd9221ae..b39a9bedc82cf 100644 --- a/packages/block-library/src/avatar/block.json +++ b/packages/block-library/src/avatar/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/avatar", "title": "Avatar", "category": "theme", diff --git a/packages/block-library/src/block/block.json b/packages/block-library/src/block/block.json index f472fd0f4760a..78fed058a5bd1 100644 --- a/packages/block-library/src/block/block.json +++ b/packages/block-library/src/block/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/block", "title": "Reusable block", "category": "reusable", diff --git a/packages/block-library/src/button/block.json b/packages/block-library/src/button/block.json index a8d7caaba6e0c..e337aa857fc17 100644 --- a/packages/block-library/src/button/block.json +++ b/packages/block-library/src/button/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/button", "title": "Button", "category": "design", diff --git a/packages/block-library/src/buttons/block.json b/packages/block-library/src/buttons/block.json index 71d5aa302cfc9..26bce09b17840 100644 --- a/packages/block-library/src/buttons/block.json +++ b/packages/block-library/src/buttons/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/buttons", "title": "Buttons", "category": "design", diff --git a/packages/block-library/src/calendar/block.json b/packages/block-library/src/calendar/block.json index c772cf58411f0..c74003cc8ba65 100644 --- a/packages/block-library/src/calendar/block.json +++ b/packages/block-library/src/calendar/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/calendar", "title": "Calendar", "category": "widgets", diff --git a/packages/block-library/src/categories/block.json b/packages/block-library/src/categories/block.json index a90a527e35c45..9ad4be3a96fd3 100644 --- a/packages/block-library/src/categories/block.json +++ b/packages/block-library/src/categories/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/categories", "title": "Categories List", "category": "widgets", diff --git a/packages/block-library/src/code/block.json b/packages/block-library/src/code/block.json index 660a2faafaf92..7f58e79d22175 100644 --- a/packages/block-library/src/code/block.json +++ b/packages/block-library/src/code/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/code", "title": "Code", "category": "text", diff --git a/packages/block-library/src/column/block.json b/packages/block-library/src/column/block.json index 6c032d347248e..1ff0bb8935167 100644 --- a/packages/block-library/src/column/block.json +++ b/packages/block-library/src/column/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/column", "title": "Column", "category": "design", diff --git a/packages/block-library/src/columns/block.json b/packages/block-library/src/columns/block.json index d4198afeda11f..91230ef739eb9 100644 --- a/packages/block-library/src/columns/block.json +++ b/packages/block-library/src/columns/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/columns", "title": "Columns", "category": "design", diff --git a/packages/block-library/src/comment-author-avatar/block.json b/packages/block-library/src/comment-author-avatar/block.json index 2b6cefd6db998..b0c8c322410d2 100644 --- a/packages/block-library/src/comment-author-avatar/block.json +++ b/packages/block-library/src/comment-author-avatar/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "__experimental": "fse", "name": "core/comment-author-avatar", "title": "Comment Author Avatar (deprecated)", diff --git a/packages/block-library/src/comment-author-name/block.json b/packages/block-library/src/comment-author-name/block.json index cfa036fa80e2d..8b8f972218928 100644 --- a/packages/block-library/src/comment-author-name/block.json +++ b/packages/block-library/src/comment-author-name/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/comment-author-name", "title": "Comment Author Name", "category": "theme", diff --git a/packages/block-library/src/comment-content/block.json b/packages/block-library/src/comment-content/block.json index 69917ccce6aea..a7cce6bd58f4f 100644 --- a/packages/block-library/src/comment-content/block.json +++ b/packages/block-library/src/comment-content/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/comment-content", "title": "Comment Content", "category": "theme", diff --git a/packages/block-library/src/comment-date/block.json b/packages/block-library/src/comment-date/block.json index ea1e263338139..16af1f2c2ca95 100644 --- a/packages/block-library/src/comment-date/block.json +++ b/packages/block-library/src/comment-date/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/comment-date", "title": "Comment Date", "category": "theme", diff --git a/packages/block-library/src/comment-edit-link/block.json b/packages/block-library/src/comment-edit-link/block.json index e695ddc3801f7..e9a74429ec6e3 100644 --- a/packages/block-library/src/comment-edit-link/block.json +++ b/packages/block-library/src/comment-edit-link/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/comment-edit-link", "title": "Comment Edit Link", "category": "theme", diff --git a/packages/block-library/src/comment-reply-link/block.json b/packages/block-library/src/comment-reply-link/block.json index 7ed60f34f581f..2f23a2b87a2d0 100644 --- a/packages/block-library/src/comment-reply-link/block.json +++ b/packages/block-library/src/comment-reply-link/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/comment-reply-link", "title": "Comment Reply Link", "category": "theme", diff --git a/packages/block-library/src/comment-template/block.json b/packages/block-library/src/comment-template/block.json index 9d0eb98684f14..2e51e06b7e357 100644 --- a/packages/block-library/src/comment-template/block.json +++ b/packages/block-library/src/comment-template/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/comment-template", "title": "Comment Template", "category": "design", diff --git a/packages/block-library/src/comments-pagination-next/block.json b/packages/block-library/src/comments-pagination-next/block.json index f0cee1a1cdbe6..d0137546182ee 100644 --- a/packages/block-library/src/comments-pagination-next/block.json +++ b/packages/block-library/src/comments-pagination-next/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/comments-pagination-next", "title": "Comments Next Page", "category": "theme", diff --git a/packages/block-library/src/comments-pagination-numbers/block.json b/packages/block-library/src/comments-pagination-numbers/block.json index 0ab4f965ff1cd..9118f2fd79ca2 100644 --- a/packages/block-library/src/comments-pagination-numbers/block.json +++ b/packages/block-library/src/comments-pagination-numbers/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/comments-pagination-numbers", "title": "Comments Page Numbers", "category": "theme", diff --git a/packages/block-library/src/comments-pagination-previous/block.json b/packages/block-library/src/comments-pagination-previous/block.json index 211e1a33305a0..255bd2b271a17 100644 --- a/packages/block-library/src/comments-pagination-previous/block.json +++ b/packages/block-library/src/comments-pagination-previous/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/comments-pagination-previous", "title": "Comments Previous Page", "category": "theme", diff --git a/packages/block-library/src/comments-pagination/block.json b/packages/block-library/src/comments-pagination/block.json index d7c8be4b8eaa2..cd9f60f8c7463 100644 --- a/packages/block-library/src/comments-pagination/block.json +++ b/packages/block-library/src/comments-pagination/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/comments-pagination", "title": "Comments Pagination", "category": "theme", diff --git a/packages/block-library/src/comments-title/block.json b/packages/block-library/src/comments-title/block.json index 3c5db438a3fe6..12b105afe9a31 100644 --- a/packages/block-library/src/comments-title/block.json +++ b/packages/block-library/src/comments-title/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/comments-title", "title": "Comments Title", "category": "theme", diff --git a/packages/block-library/src/comments/block.json b/packages/block-library/src/comments/block.json index 19490f6e99eb4..06d6c28e5ad2c 100644 --- a/packages/block-library/src/comments/block.json +++ b/packages/block-library/src/comments/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/comments", "title": "Comments", "category": "theme", diff --git a/packages/block-library/src/comments/deprecated.js b/packages/block-library/src/comments/deprecated.js index bba13be11e754..67a1640859289 100644 --- a/packages/block-library/src/comments/deprecated.js +++ b/packages/block-library/src/comments/deprecated.js @@ -12,7 +12,7 @@ const v1 = { default: 'div', }, }, - apiVersion: 2, + apiVersion: 3, supports: { align: [ 'wide', 'full' ], html: false, diff --git a/packages/block-library/src/cover/block.json b/packages/block-library/src/cover/block.json index f7e117add4065..8b4c706a332cc 100644 --- a/packages/block-library/src/cover/block.json +++ b/packages/block-library/src/cover/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/cover", "title": "Cover", "category": "media", diff --git a/packages/block-library/src/details/block.json b/packages/block-library/src/details/block.json index 4eb7af8d5ce62..f3a0c00defdc3 100644 --- a/packages/block-library/src/details/block.json +++ b/packages/block-library/src/details/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/details", "title": "Details", "category": "text", diff --git a/packages/block-library/src/embed/block.json b/packages/block-library/src/embed/block.json index e56c5b894dabe..9ca54db871db1 100644 --- a/packages/block-library/src/embed/block.json +++ b/packages/block-library/src/embed/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/embed", "title": "Embed", "category": "embed", diff --git a/packages/block-library/src/file/block.json b/packages/block-library/src/file/block.json index 08a78f3a94ce4..12edc20630d1e 100644 --- a/packages/block-library/src/file/block.json +++ b/packages/block-library/src/file/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/file", "title": "File", "category": "media", diff --git a/packages/block-library/src/freeform/block.json b/packages/block-library/src/freeform/block.json index 809b7319c1888..d40e8ea13dc11 100644 --- a/packages/block-library/src/freeform/block.json +++ b/packages/block-library/src/freeform/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/freeform", "title": "Classic", "category": "text", diff --git a/packages/block-library/src/gallery/block.json b/packages/block-library/src/gallery/block.json index 0400430b95ee6..d352acd2833b8 100644 --- a/packages/block-library/src/gallery/block.json +++ b/packages/block-library/src/gallery/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/gallery", "title": "Gallery", "category": "media", diff --git a/packages/block-library/src/group/block.json b/packages/block-library/src/group/block.json index d9411b75a90a3..9a2d61056fb30 100644 --- a/packages/block-library/src/group/block.json +++ b/packages/block-library/src/group/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/group", "title": "Group", "category": "design", diff --git a/packages/block-library/src/heading/block.json b/packages/block-library/src/heading/block.json index f9d701eace964..ff2a5d267511b 100644 --- a/packages/block-library/src/heading/block.json +++ b/packages/block-library/src/heading/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/heading", "title": "Heading", "category": "text", diff --git a/packages/block-library/src/home-link/block.json b/packages/block-library/src/home-link/block.json index df964ad76bc68..0929dee8aaa4c 100644 --- a/packages/block-library/src/home-link/block.json +++ b/packages/block-library/src/home-link/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/home-link", "category": "design", "parent": [ "core/navigation" ], diff --git a/packages/block-library/src/html/block.json b/packages/block-library/src/html/block.json index c1e1e94b87496..b1a2ad60625d1 100644 --- a/packages/block-library/src/html/block.json +++ b/packages/block-library/src/html/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/html", "title": "Custom HTML", "category": "widgets", diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index 791e09f73c800..d51d70dd711f0 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/image", "title": "Image", "category": "media", diff --git a/packages/block-library/src/image/index.php b/packages/block-library/src/image/index.php index 3c90f0fbc21cf..70a40f4b59db9 100644 --- a/packages/block-library/src/image/index.php +++ b/packages/block-library/src/image/index.php @@ -75,8 +75,17 @@ function render_block_core_image( $attributes, $content ) { ''; $body_content = preg_replace( '/]+>/', $button, $body_content ); - $background_color = esc_attr( wp_get_global_styles( array( 'color', 'background' ) ) ); - $close_button_icon = ''; + // Add directive to expand modal image if appropriate. + $m = new WP_HTML_Tag_Processor( $content ); + $m->next_tag( 'img' ); + $m->set_attribute( 'data-wp-context', '{ "core": { "image": { "imageSrc": "' . wp_get_attachment_url( $attributes['id'] ) . '"} } }' ); + $m->set_attribute( 'data-wp-bind--src', 'selectors.core.image.imageSrc' ); + $modal_content = $m->get_updated_html(); + + $background_color = esc_attr( wp_get_global_styles( array( 'color', 'background' ) ) ); + + $close_button_icon = ''; + $close_button_color = esc_attr( wp_get_global_styles( array( 'color', 'text' ) ) ); $dialog_label = $alt_attribute ? esc_attr( $alt_attribute ) : esc_attr__( 'Image' ); $close_button_label = esc_attr__( 'Close' ); @@ -94,10 +103,10 @@ function render_block_core_image( $attributes, $content ) { data-wp-on--mousewheel="actions.core.image.hideLightbox" data-wp-on--click="actions.core.image.hideLightbox" > - - $content + $modal_content
HTML; diff --git a/packages/block-library/src/image/interactivity.js b/packages/block-library/src/image/interactivity.js index 6b6f246b83025..a4eb79cf50974 100644 --- a/packages/block-library/src/image/interactivity.js +++ b/packages/block-library/src/image/interactivity.js @@ -89,6 +89,11 @@ store( { roleAttribute: ( { context } ) => { return context.core.image.lightboxEnabled ? 'dialog' : ''; }, + imageSrc: ( { context } ) => { + return context.core.image.initialized + ? context.core.image.imageSrc + : ''; + }, }, }, }, @@ -96,6 +101,7 @@ store( { core: { image: { initLightbox: async ( { context, ref } ) => { + context.core.image.imageRef = ref.querySelector( 'img' ); if ( context.core.image.lightboxEnabled ) { const focusableElements = ref.querySelectorAll( focusableSelectors ); diff --git a/packages/block-library/src/image/style.scss b/packages/block-library/src/image/style.scss index e6ad33308bc94..43aab303beb14 100644 --- a/packages/block-library/src/image/style.scss +++ b/packages/block-library/src/image/style.scss @@ -186,23 +186,36 @@ visibility: hidden; .close-button { - font-size: 40px; position: absolute; - top: 20px; - right: 20px; + top: 12.5px; + right: 12.5px; + padding: 0; cursor: pointer; z-index: 5000000; } .wp-block-image { - display: flex; - justify-content: center; - align-items: center; width: 100%; height: 100%; - z-index: 3000000; position: absolute; + z-index: 3000000; + box-sizing: border-box; + display: flex; + justify-content: center; + align-items: center; flex-direction: column; + padding: 30px; + + figcaption { + margin: 10px 0 0 0; + display: none; + } + + img { + max-width: 100%; + max-height: 100%; + width: auto; + } } button { diff --git a/packages/block-library/src/latest-comments/block.json b/packages/block-library/src/latest-comments/block.json index 80fa4f5d2d063..b7a91ebf13746 100644 --- a/packages/block-library/src/latest-comments/block.json +++ b/packages/block-library/src/latest-comments/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/latest-comments", "title": "Latest Comments", "category": "widgets", diff --git a/packages/block-library/src/latest-posts/block.json b/packages/block-library/src/latest-posts/block.json index 9b451f5875c73..56cdc7af46087 100644 --- a/packages/block-library/src/latest-posts/block.json +++ b/packages/block-library/src/latest-posts/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/latest-posts", "title": "Latest Posts", "category": "widgets", diff --git a/packages/block-library/src/list-item/block.json b/packages/block-library/src/list-item/block.json index 745d6e30b4dd6..41221f1c31772 100644 --- a/packages/block-library/src/list-item/block.json +++ b/packages/block-library/src/list-item/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/list-item", "title": "List item", "category": "text", diff --git a/packages/block-library/src/list/block.json b/packages/block-library/src/list/block.json index 4e1089b088738..e7ef850d29ba5 100644 --- a/packages/block-library/src/list/block.json +++ b/packages/block-library/src/list/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/list", "title": "List", "category": "text", diff --git a/packages/block-library/src/loginout/block.json b/packages/block-library/src/loginout/block.json index 3ba18dcf17143..b2a91da8eda67 100644 --- a/packages/block-library/src/loginout/block.json +++ b/packages/block-library/src/loginout/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/loginout", "title": "Login/out", "category": "theme", diff --git a/packages/block-library/src/media-text/block.json b/packages/block-library/src/media-text/block.json index ac88c9ca6d4df..8ffc653d68414 100644 --- a/packages/block-library/src/media-text/block.json +++ b/packages/block-library/src/media-text/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/media-text", "title": "Media & Text", "category": "media", diff --git a/packages/block-library/src/missing/block.json b/packages/block-library/src/missing/block.json index 9a44caa248509..0bc512bbbf709 100644 --- a/packages/block-library/src/missing/block.json +++ b/packages/block-library/src/missing/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/missing", "title": "Unsupported", "category": "text", diff --git a/packages/block-library/src/more/block.json b/packages/block-library/src/more/block.json index 25f1df23771f3..bfd95652ea176 100644 --- a/packages/block-library/src/more/block.json +++ b/packages/block-library/src/more/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/more", "title": "More", "category": "design", diff --git a/packages/block-library/src/navigation-link/block.json b/packages/block-library/src/navigation-link/block.json index ae151a279e5ac..b2cbeaed63d3e 100644 --- a/packages/block-library/src/navigation-link/block.json +++ b/packages/block-library/src/navigation-link/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/navigation-link", "title": "Custom Link", "category": "design", diff --git a/packages/block-library/src/navigation-submenu/block.json b/packages/block-library/src/navigation-submenu/block.json index f311a9f36e41a..91364109ea740 100644 --- a/packages/block-library/src/navigation-submenu/block.json +++ b/packages/block-library/src/navigation-submenu/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/navigation-submenu", "title": "Submenu", "category": "design", diff --git a/packages/block-library/src/navigation/block.json b/packages/block-library/src/navigation/block.json index ce2bed0d8837f..ba84263013ab5 100644 --- a/packages/block-library/src/navigation/block.json +++ b/packages/block-library/src/navigation/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/navigation", "title": "Navigation", "category": "theme", diff --git a/packages/block-library/src/navigation/editor.scss b/packages/block-library/src/navigation/editor.scss index 949a7c773eb6e..4a6a6fe6b4395 100644 --- a/packages/block-library/src/navigation/editor.scss +++ b/packages/block-library/src/navigation/editor.scss @@ -508,20 +508,22 @@ body.editor-styles-wrapper .wp-block-navigation__responsive-container.is-menu-op // so focus is applied naturally on the block container. // It's important the right container has focus, otherwise you can't press // "Delete" to remove the block. -.wp-block-navigation__responsive-container, -.wp-block-navigation__responsive-close { - @include break-small() { - pointer-events: none; - - .wp-block-navigation__responsive-container-close, - .block-editor-block-list__layout * { - pointer-events: all; +.wp-block-navigation:not(.is-editing-disabled) { + .wp-block-navigation__responsive-container, + .wp-block-navigation__responsive-close { + @include break-small() { + pointer-events: none; + + .wp-block-navigation__responsive-container-close, + .block-editor-block-list__layout * { + pointer-events: all; + } } - } - // Page List items should remain inert. - .wp-block-pages-list__item__link { - pointer-events: none; + // Page List items should remain inert. + .wp-block-pages-list__item__link { + pointer-events: none; + } } } diff --git a/packages/block-library/src/nextpage/block.json b/packages/block-library/src/nextpage/block.json index 6a133264d6747..ab88d4a7be4f0 100644 --- a/packages/block-library/src/nextpage/block.json +++ b/packages/block-library/src/nextpage/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/nextpage", "title": "Page Break", "category": "design", diff --git a/packages/block-library/src/page-list-item/block.json b/packages/block-library/src/page-list-item/block.json index 04e7f7f574dd2..abd86924949ab 100644 --- a/packages/block-library/src/page-list-item/block.json +++ b/packages/block-library/src/page-list-item/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/page-list-item", "title": "Page List Item", "category": "widgets", diff --git a/packages/block-library/src/page-list-item/index.php b/packages/block-library/src/page-list-item/index.php new file mode 100644 index 0000000000000..2955c795aec2b --- /dev/null +++ b/packages/block-library/src/page-list-item/index.php @@ -0,0 +1,14 @@ + 1; + const blockProps = useBlockProps( { - className: classnames( __unstableLayoutClassNames, { - 'is-flex-container': hasLayoutFlex, - [ `columns-${ columns }` ]: hasLayoutFlex, - } ), + className: classnames( __unstableLayoutClassNames ), } ); if ( ! posts ) { @@ -235,35 +237,67 @@ export default function PostTemplateEdit( { return

{ __( 'No results found.' ) }

; } + const setDisplayLayout = ( newDisplayLayout ) => + setAttributes( { + layout: { ...layout, ...newDisplayLayout }, + } ); + + const displayLayoutControls = [ + { + icon: list, + title: __( 'List view' ), + onClick: () => setDisplayLayout( { type: 'default' } ), + isActive: layoutType === 'default' || layoutType === 'constrained', + }, + { + icon: grid, + title: __( 'Grid view' ), + onClick: () => + setDisplayLayout( { + type: 'grid', + columnCount, + } ), + isActive: layoutType === 'grid', + }, + ]; + // To avoid flicker when switching active block contexts, a preview is rendered // for each block context, but the preview for the active block context is hidden. // This ensures that when it is displayed again, the cached rendering of the // block preview is used, instead of having to re-render the preview from scratch. return ( -
    - { blockContexts && - blockContexts.map( ( blockContext ) => ( - - { blockContext.postId === - ( activeBlockContextId || - blockContexts[ 0 ]?.postId ) ? ( - - ) : null } - - - ) ) } -
+ <> + + + + +
    + { blockContexts && + blockContexts.map( ( blockContext ) => ( + + { blockContext.postId === + ( activeBlockContextId || + blockContexts[ 0 ]?.postId ) ? ( + + ) : null } + + + ) ) } +
+ ); } diff --git a/packages/block-library/src/post-template/style.scss b/packages/block-library/src/post-template/style.scss index b1cdcf385e223..00305a1712336 100644 --- a/packages/block-library/src/post-template/style.scss +++ b/packages/block-library/src/post-template/style.scss @@ -9,7 +9,7 @@ &.wp-block-post-template { background: none; } - + // These rules no longer apply but should be kept for backwards compatibility. &.is-flex-container { flex-direction: row; display: flex; @@ -30,3 +30,10 @@ } } } + +@media ( max-width: $break-small ) { + // Temporary specificity bump until "wp-container" layout specificity is revisited. + .wp-block-post-template-is-layout-grid.wp-block-post-template-is-layout-grid.wp-block-post-template-is-layout-grid.wp-block-post-template-is-layout-grid { + grid-template-columns: 1fr; + } +} diff --git a/packages/block-library/src/post-terms/block.json b/packages/block-library/src/post-terms/block.json index 1633c7c01b82c..99cddb19c2bc1 100644 --- a/packages/block-library/src/post-terms/block.json +++ b/packages/block-library/src/post-terms/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/post-terms", "title": "Post Terms", "category": "theme", diff --git a/packages/block-library/src/post-time-to-read/block.json b/packages/block-library/src/post-time-to-read/block.json index 2b7d7936094f7..8f88db46d51ae 100644 --- a/packages/block-library/src/post-time-to-read/block.json +++ b/packages/block-library/src/post-time-to-read/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "__experimental": true, "name": "core/post-time-to-read", "title": "Time To Read", diff --git a/packages/block-library/src/post-title/block.json b/packages/block-library/src/post-title/block.json index 66377292db68c..fc008ee77d3c1 100644 --- a/packages/block-library/src/post-title/block.json +++ b/packages/block-library/src/post-title/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/post-title", "title": "Title", "category": "theme", diff --git a/packages/block-library/src/post-title/edit.js b/packages/block-library/src/post-title/edit.js index d7e8e2788ebe9..96fd62178b974 100644 --- a/packages/block-library/src/post-title/edit.js +++ b/packages/block-library/src/post-title/edit.js @@ -12,6 +12,7 @@ import { InspectorControls, useBlockProps, PlainText, + privateApis as blockEditorPrivateApis, } from '@wordpress/block-editor'; import { ToggleControl, TextControl, PanelBody } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; @@ -23,6 +24,9 @@ import { useEntityProp } from '@wordpress/core-data'; */ import HeadingLevelDropdown from '../heading/heading-level-dropdown'; import { useCanEditEntity } from '../utils/hooks'; +import { unlock } from '../private-apis'; + +const { useBlockEditingMode } = unlock( blockEditorPrivateApis ); export default function PostTitleEdit( { attributes: { level, textAlign, isLink, rel, linkTarget }, @@ -58,6 +62,7 @@ export default function PostTitleEdit( { [ `has-text-align-${ textAlign }` ]: textAlign, } ), } ); + const blockEditingMode = useBlockEditingMode(); let titleElement = { __( 'Title' ) }; @@ -112,20 +117,22 @@ export default function PostTitleEdit( { return ( <> - - - setAttributes( { level: newLevel } ) - } - /> - { - setAttributes( { textAlign: nextAlign } ); - } } - /> - + { blockEditingMode === 'default' && ( + + + setAttributes( { level: newLevel } ) + } + /> + { + setAttributes( { textAlign: nextAlign } ); + } } + /> + + ) } { const hasSingleInnerGroupBlock = ( innerBlocks = [] ) => innerBlocks.length === 1 && innerBlocks[ 0 ].name === 'core/group'; +const migrateToConstrainedLayout = ( attributes ) => { + const { layout = null } = attributes; + if ( ! layout ) { + return attributes; + } + const { inherit = null, contentSize = null, ...newLayout } = layout; + + if ( inherit || contentSize ) { + return { + ...attributes, + layout: { + ...newLayout, + contentSize, + type: 'constrained', + }, + }; + } +}; + +const findPostTemplateBlock = ( innerBlocks = [] ) => { + let foundBlock = null; + for ( const block of innerBlocks ) { + if ( block.name === 'core/post-template' ) { + foundBlock = block; + break; + } else if ( block.innerBlocks.length ) { + foundBlock = findPostTemplateBlock( block.innerBlocks ); + } + } + return foundBlock; +}; + +const replacePostTemplateBlock = ( innerBlocks = [], replacementBlock ) => { + innerBlocks.forEach( ( block, index ) => { + if ( block.name === 'core/post-template' ) { + innerBlocks.splice( index, 1, replacementBlock ); + } else if ( block.innerBlocks.length ) { + block.innerBlocks = replacePostTemplateBlock( + block.innerBlocks, + replacementBlock + ); + } + } ); + return innerBlocks; +}; + +const migrateDisplayLayout = ( attributes, innerBlocks ) => { + const { displayLayout = null, ...newAttributes } = attributes; + if ( ! displayLayout ) { + return [ attributes, innerBlocks ]; + } + const postTemplateBlock = findPostTemplateBlock( innerBlocks ); + if ( ! postTemplateBlock ) { + return [ attributes, innerBlocks ]; + } + + const { type, columns } = displayLayout; + + // Convert custom displayLayout values to canonical layout types. + const updatedLayoutType = type === 'flex' ? 'grid' : 'default'; + + const newPostTemplateBlock = createBlock( + 'core/post-template', + { + ...postTemplateBlock.attributes, + layout: { + type: updatedLayoutType, + ...( columns && { columnCount: columns } ), + }, + }, + postTemplateBlock.innerBlocks + ); + return [ + newAttributes, + replacePostTemplateBlock( innerBlocks, newPostTemplateBlock ), + ]; +}; + // Version with NO wrapper `div` element. const v1 = { attributes: { @@ -160,13 +238,14 @@ const v1 = { supports: { html: false, }, - migrate( attributes ) { + migrate( attributes, innerBlocks ) { const withTaxQuery = migrateToTaxQuery( attributes ); const { layout, ...restWithTaxQuery } = withTaxQuery; - return { + const newAttributes = { ...restWithTaxQuery, displayLayout: withTaxQuery.layout, }; + return migrateDisplayLayout( newAttributes, innerBlocks ); }, save() { return ; @@ -221,7 +300,16 @@ const v2 = { categoryIds || tagIds, migrate( attributes, innerBlocks ) { const withTaxQuery = migrateToTaxQuery( attributes ); - return migrateColors( withTaxQuery, innerBlocks ); + const [ withColorAttributes, withColorInnerBlocks ] = migrateColors( + withTaxQuery, + innerBlocks + ); + const withConstrainedLayoutAttributes = + migrateToConstrainedLayout( withColorAttributes ); + return migrateDisplayLayout( + withConstrainedLayoutAttributes, + withColorInnerBlocks + ); }, save( { attributes: { tagName: Tag = 'div' } } ) { const blockProps = useBlockProps.save(); @@ -291,7 +379,18 @@ const v3 = { style?.elements?.link ); }, - migrate: migrateColors, + migrate( attributes, innerBlocks ) { + const [ withColorAttributes, withColorInnerBlocks ] = migrateColors( + attributes, + innerBlocks + ); + const withConstrainedLayoutAttributes = + migrateToConstrainedLayout( withColorAttributes ); + return migrateDisplayLayout( + withConstrainedLayoutAttributes, + withColorInnerBlocks + ); + }, save( { attributes: { tagName: Tag = 'div' } } ) { const blockProps = useBlockProps.save(); const innerBlocksProps = useInnerBlocksProps.save( blockProps ); @@ -355,26 +454,72 @@ const v4 = { return ; }, isEligible: ( { layout } ) => - ! layout || - layout.inherit || - ( layout.contentSize && layout.type !== 'constrained' ), - migrate: ( attributes ) => { - const { layout = null } = attributes; - if ( ! layout ) { - return attributes; - } - if ( layout.inherit || layout.contentSize ) { - return { - ...attributes, - layout: { - ...layout, - type: 'constrained', - }, - }; - } + layout?.inherit || + ( layout?.contentSize && layout?.type !== 'constrained' ), + migrate( attributes, innerBlocks ) { + const withConstrainedLayoutAttributes = + migrateToConstrainedLayout( attributes ); + return migrateDisplayLayout( + withConstrainedLayoutAttributes, + innerBlocks + ); + }, +}; + +const v5 = { + attributes: { + queryId: { + type: 'number', + }, + query: { + type: 'object', + default: { + perPage: null, + pages: 0, + offset: 0, + postType: 'post', + order: 'desc', + orderBy: 'date', + author: '', + search: '', + exclude: [], + sticky: '', + inherit: true, + taxQuery: null, + parents: [], + }, + }, + tagName: { + type: 'string', + default: 'div', + }, + displayLayout: { + type: 'object', + default: { + type: 'list', + }, + }, + namespace: { + type: 'string', + }, + }, + supports: { + align: [ 'wide', 'full' ], + anchor: true, + html: false, + __experimentalLayout: true, + }, + save( { attributes: { tagName: Tag = 'div' } } ) { + const blockProps = useBlockProps.save(); + const innerBlocksProps = useInnerBlocksProps.save( blockProps ); + return ; + }, + isEligible: ( { displayLayout } ) => { + return !! displayLayout; }, + migrate: migrateDisplayLayout, }; -const deprecated = [ v4, v3, v2, v1 ]; +const deprecated = [ v5, v4, v3, v2, v1 ]; export default deprecated; diff --git a/packages/block-library/src/query/edit/inspector-controls/index.js b/packages/block-library/src/query/edit/inspector-controls/index.js index 2222f7d2d1eff..0061429f4af3b 100644 --- a/packages/block-library/src/query/edit/inspector-controls/index.js +++ b/packages/block-library/src/query/edit/inspector-controls/index.js @@ -101,7 +101,7 @@ export default function QueryInspectorControls( props ) { const showInheritControl = isControlAllowed( allowedControls, 'inherit' ); const showPostTypeControl = ! inherit && isControlAllowed( allowedControls, 'postType' ); - const showColumnsControl = displayLayout?.type === 'flex'; + const showColumnsControl = false; const showOrderControl = ! inherit && isControlAllowed( allowedControls, 'order' ); const showStickyControl = @@ -169,7 +169,9 @@ export default function QueryInspectorControls( props ) { label={ __( 'Columns' ) } value={ displayLayout.columns } onChange={ ( value ) => - setDisplayLayout( { columns: value } ) + setDisplayLayout( { + columns: value, + } ) } min={ 2 } max={ Math.max( 6, displayLayout.columns ) } diff --git a/packages/block-library/src/query/edit/query-content.js b/packages/block-library/src/query/edit/query-content.js index 9563673917f57..567199f38e1b3 100644 --- a/packages/block-library/src/query/edit/query-content.js +++ b/packages/block-library/src/query/edit/query-content.js @@ -107,7 +107,6 @@ export default function QueryContent( { clientId={ clientId } attributes={ attributes } setQuery={ updateQuery } - setDisplayLayout={ updateDisplayLayout } openPatternSelectionModal={ openPatternSelectionModal } /> diff --git a/packages/block-library/src/query/edit/query-toolbar.js b/packages/block-library/src/query/edit/query-toolbar.js index 1d079eb399fb8..7b02290ae4c76 100644 --- a/packages/block-library/src/query/edit/query-toolbar.js +++ b/packages/block-library/src/query/edit/query-toolbar.js @@ -10,7 +10,7 @@ import { } from '@wordpress/components'; import { useInstanceId } from '@wordpress/compose'; import { __ } from '@wordpress/i18n'; -import { settings, list, grid } from '@wordpress/icons'; +import { settings } from '@wordpress/icons'; /** * Internal dependencies @@ -18,9 +18,8 @@ import { settings, list, grid } from '@wordpress/icons'; import { usePatterns } from '../utils'; export default function QueryToolbar( { - attributes: { query, displayLayout }, + attributes: { query }, setQuery, - setDisplayLayout, openPatternSelectionModal, name, clientId, @@ -30,24 +29,7 @@ export default function QueryToolbar( { QueryToolbar, 'blocks-query-pagination-max-page-input' ); - const displayLayoutControls = [ - { - icon: list, - title: __( 'List view' ), - onClick: () => setDisplayLayout( { type: 'list' } ), - isActive: displayLayout?.type === 'list', - }, - { - icon: grid, - title: __( 'Grid view' ), - onClick: () => - setDisplayLayout( { - type: 'flex', - columns: displayLayout?.columns || 3, - } ), - isActive: displayLayout?.type === 'flex', - }, - ]; + return ( <> { ! query.inherit && ( @@ -144,7 +126,6 @@ export default function QueryToolbar( { ) } - ); } diff --git a/packages/block-library/src/quote/block.json b/packages/block-library/src/quote/block.json index 485774ceb0a9c..49ee925794ce2 100644 --- a/packages/block-library/src/quote/block.json +++ b/packages/block-library/src/quote/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/quote", "title": "Quote", "category": "text", diff --git a/packages/block-library/src/read-more/block.json b/packages/block-library/src/read-more/block.json index ed2b23c3b7f0f..b7c29d860db10 100644 --- a/packages/block-library/src/read-more/block.json +++ b/packages/block-library/src/read-more/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/read-more", "title": "Read More", "category": "theme", diff --git a/packages/block-library/src/rss/block.json b/packages/block-library/src/rss/block.json index 2e3fd4b2d385e..4ba98236125e8 100644 --- a/packages/block-library/src/rss/block.json +++ b/packages/block-library/src/rss/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/rss", "title": "RSS", "category": "widgets", diff --git a/packages/block-library/src/search/block.json b/packages/block-library/src/search/block.json index 387295ebb36de..935fac4318deb 100644 --- a/packages/block-library/src/search/block.json +++ b/packages/block-library/src/search/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/search", "title": "Search", "category": "widgets", diff --git a/packages/block-library/src/separator/block.json b/packages/block-library/src/separator/block.json index bee358d208516..970f6b5cbb582 100644 --- a/packages/block-library/src/separator/block.json +++ b/packages/block-library/src/separator/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/separator", "title": "Separator", "category": "design", diff --git a/packages/block-library/src/shortcode/block.json b/packages/block-library/src/shortcode/block.json index 04444fb292c80..22d838a7198e1 100644 --- a/packages/block-library/src/shortcode/block.json +++ b/packages/block-library/src/shortcode/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/shortcode", "title": "Shortcode", "category": "widgets", diff --git a/packages/block-library/src/site-logo/block.json b/packages/block-library/src/site-logo/block.json index 8eba39b91c7ad..33a5216d767be 100644 --- a/packages/block-library/src/site-logo/block.json +++ b/packages/block-library/src/site-logo/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/site-logo", "title": "Site Logo", "category": "theme", diff --git a/packages/block-library/src/site-tagline/block.json b/packages/block-library/src/site-tagline/block.json index a11eab4fbc243..9f77584dfd0af 100644 --- a/packages/block-library/src/site-tagline/block.json +++ b/packages/block-library/src/site-tagline/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/site-tagline", "title": "Site Tagline", "category": "theme", diff --git a/packages/block-library/src/site-title/block.json b/packages/block-library/src/site-title/block.json index b69acda934fda..63eaf1cc7f69a 100644 --- a/packages/block-library/src/site-title/block.json +++ b/packages/block-library/src/site-title/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/site-title", "title": "Site Title", "category": "theme", diff --git a/packages/block-library/src/social-link/block.json b/packages/block-library/src/social-link/block.json index 140cc123ec484..16d99303156e2 100644 --- a/packages/block-library/src/social-link/block.json +++ b/packages/block-library/src/social-link/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/social-link", "title": "Social Icon", "category": "widgets", diff --git a/packages/block-library/src/social-links/block.json b/packages/block-library/src/social-links/block.json index 0e47209f0b8b1..3b1500ab8e70d 100644 --- a/packages/block-library/src/social-links/block.json +++ b/packages/block-library/src/social-links/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/social-links", "title": "Social Icons", "category": "widgets", diff --git a/packages/block-library/src/spacer/block.json b/packages/block-library/src/spacer/block.json index 021ff9f4a2de3..a9da8d537f1b6 100644 --- a/packages/block-library/src/spacer/block.json +++ b/packages/block-library/src/spacer/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/spacer", "title": "Spacer", "category": "design", diff --git a/packages/block-library/src/style.scss b/packages/block-library/src/style.scss index 8fe8b904c23f5..c5277995d10da 100644 --- a/packages/block-library/src/style.scss +++ b/packages/block-library/src/style.scss @@ -51,6 +51,7 @@ @import "./spacer/style.scss"; @import "./tag-cloud/style.scss"; @import "./table/style.scss"; +@import "./term-description/style.scss"; @import "./text-columns/style.scss"; @import "./verse/style.scss"; @import "./video/style.scss"; diff --git a/packages/block-library/src/table-of-contents/block.json b/packages/block-library/src/table-of-contents/block.json index f095a2e2e5cdb..9623263166916 100644 --- a/packages/block-library/src/table-of-contents/block.json +++ b/packages/block-library/src/table-of-contents/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "__experimental": true, "name": "core/table-of-contents", "title": "Table of Contents", diff --git a/packages/block-library/src/table/block.json b/packages/block-library/src/table/block.json index adac1e9c2130e..54e4bc26cac7d 100644 --- a/packages/block-library/src/table/block.json +++ b/packages/block-library/src/table/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/table", "title": "Table", "category": "text", diff --git a/packages/block-library/src/tag-cloud/block.json b/packages/block-library/src/tag-cloud/block.json index ec1e333512719..82ec96417b30e 100644 --- a/packages/block-library/src/tag-cloud/block.json +++ b/packages/block-library/src/tag-cloud/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/tag-cloud", "title": "Tag Cloud", "category": "widgets", diff --git a/packages/block-library/src/template-part/block.json b/packages/block-library/src/template-part/block.json index 282ac2ca22127..711c8dd44269d 100644 --- a/packages/block-library/src/template-part/block.json +++ b/packages/block-library/src/template-part/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/template-part", "title": "Template Part", "category": "theme", diff --git a/packages/block-library/src/term-description/block.json b/packages/block-library/src/term-description/block.json index bd96f3405f54f..f736194500df5 100644 --- a/packages/block-library/src/term-description/block.json +++ b/packages/block-library/src/term-description/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/term-description", "title": "Term Description", "category": "theme", diff --git a/packages/block-library/src/term-description/style.scss b/packages/block-library/src/term-description/style.scss new file mode 100644 index 0000000000000..bd455f7a68d3d --- /dev/null +++ b/packages/block-library/src/term-description/style.scss @@ -0,0 +1,11 @@ +// Lowest specificity on wrapper margins to avoid overriding layout styles. +:where(.wp-block-term-description) { + margin-top: var(--wp--style--block-gap); + margin-bottom: var(--wp--style--block-gap); +} + +// Zero out the margin on the description paragraph. +.wp-block-term-description p { + margin-top: 0; + margin-bottom: 0; +} diff --git a/packages/block-library/src/text-columns/block.json b/packages/block-library/src/text-columns/block.json index 84d5ccece038a..3af169fadbb3b 100644 --- a/packages/block-library/src/text-columns/block.json +++ b/packages/block-library/src/text-columns/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/text-columns", "title": "Text Columns (deprecated)", "icon": "columns", diff --git a/packages/block-library/src/verse/block.json b/packages/block-library/src/verse/block.json index 4f023d716b5c5..5fabf49adec7b 100644 --- a/packages/block-library/src/verse/block.json +++ b/packages/block-library/src/verse/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/verse", "title": "Verse", "category": "text", diff --git a/packages/block-library/src/video/block.json b/packages/block-library/src/video/block.json index 6f53246cc8801..df2d2075375ff 100644 --- a/packages/block-library/src/video/block.json +++ b/packages/block-library/src/video/block.json @@ -1,6 +1,6 @@ { "$schema": "https://schemas.wp.org/trunk/block.json", - "apiVersion": 2, + "apiVersion": 3, "name": "core/video", "title": "Video", "category": "media", diff --git a/packages/blocks/src/api/test/registration.js b/packages/blocks/src/api/test/registration.js index dbb11e4d23001..ff75590b40007 100644 --- a/packages/blocks/src/api/test/registration.js +++ b/packages/blocks/src/api/test/registration.js @@ -362,7 +362,7 @@ describe( 'blocks', () => { const blockName = 'core/test-block-with-incompatible-keys'; unstable__bootstrapServerSideBlockDefinitions( { [ blockName ]: { - api_version: 2, + api_version: 3, provides_context: { fontSize: 'fontSize', }, @@ -375,7 +375,7 @@ describe( 'blocks', () => { }; registerBlockType( blockName, blockType ); expect( getBlockType( blockName ) ).toEqual( { - apiVersion: 2, + apiVersion: 3, name: blockName, save: expect.any( Function ), title: 'block title', @@ -403,7 +403,7 @@ describe( 'blocks', () => { } ); unstable__bootstrapServerSideBlockDefinitions( { [ blockName ]: { - apiVersion: 2, + apiVersion: 3, category: 'ignored', }, } ); @@ -413,7 +413,7 @@ describe( 'blocks', () => { }; registerBlockType( blockName, blockType ); expect( getBlockType( blockName ) ).toEqual( { - apiVersion: 2, + apiVersion: 3, name: blockName, save: expect.any( Function ), title: 'block title', diff --git a/packages/commands/README.md b/packages/commands/README.md index 0e0afdce394c9..130812664368f 100644 --- a/packages/commands/README.md +++ b/packages/commands/README.md @@ -24,6 +24,18 @@ Undocumented declaration. Undocumented declaration. +### store + +Store definition for the commands namespace. + +_Related_ + +- + +_Type_ + +- `Object` + ### useCommand Attach a command to the Global command menu. diff --git a/packages/commands/src/hooks/use-command-context.js b/packages/commands/src/hooks/use-command-context.js index c53e4131890c7..e0efde0ec8759 100644 --- a/packages/commands/src/hooks/use-command-context.js +++ b/packages/commands/src/hooks/use-command-context.js @@ -8,6 +8,7 @@ import { useDispatch, useSelect } from '@wordpress/data'; * Internal dependencies */ import { store as commandsStore } from '../store'; +import { unlock } from '../lock-unlock'; /** * Sets the active context of the command center @@ -17,7 +18,7 @@ import { store as commandsStore } from '../store'; export default function useCommandContext( context ) { const { getContext } = useSelect( commandsStore ); const initialContext = useRef( getContext() ); - const { setContext } = useDispatch( commandsStore ); + const { setContext } = unlock( useDispatch( commandsStore ) ); useEffect( () => { setContext( context ); diff --git a/packages/commands/src/index.js b/packages/commands/src/index.js index afc7ac27b7d5f..b62166f6afc44 100644 --- a/packages/commands/src/index.js +++ b/packages/commands/src/index.js @@ -2,3 +2,4 @@ export { CommandMenu } from './components/command-menu'; export { privateApis } from './private-apis'; export { default as useCommand } from './hooks/use-command'; export { default as useCommandLoader } from './hooks/use-command-loader'; +export { store } from './store'; diff --git a/packages/commands/src/lock-unlock.js b/packages/commands/src/lock-unlock.js new file mode 100644 index 0000000000000..0665114d842c3 --- /dev/null +++ b/packages/commands/src/lock-unlock.js @@ -0,0 +1,10 @@ +/** + * WordPress dependencies + */ +import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/private-apis'; + +export const { lock, unlock } = + __dangerousOptInToUnstableAPIsOnlyForCoreModules( + 'I know using unstable features means my plugin or theme will inevitably break on the next WordPress release.', + '@wordpress/commands' + ); diff --git a/packages/commands/src/private-apis.js b/packages/commands/src/private-apis.js index 7348711efd351..cf37423a8da36 100644 --- a/packages/commands/src/private-apis.js +++ b/packages/commands/src/private-apis.js @@ -1,22 +1,10 @@ -/** - * WordPress dependencies - */ -import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/private-apis'; - /** * Internal dependencies */ import { default as useCommandContext } from './hooks/use-command-context'; -import { store } from './store'; - -export const { lock, unlock } = - __dangerousOptInToUnstableAPIsOnlyForCoreModules( - 'I know using unstable features means my plugin or theme will inevitably break on the next WordPress release.', - '@wordpress/commands' - ); +import { lock } from './lock-unlock'; export const privateApis = {}; lock( privateApis, { useCommandContext, - store, } ); diff --git a/packages/commands/src/store/actions.js b/packages/commands/src/store/actions.js index 6162f1497cf0a..f461914a7cef6 100644 --- a/packages/commands/src/store/actions.js +++ b/packages/commands/src/store/actions.js @@ -104,17 +104,3 @@ export function close() { type: 'CLOSE', }; } - -/** - * Sets the active context. - * - * @param {string} context Context. - * - * @return {Object} action. - */ -export function setContext( context ) { - return { - type: 'SET_CONTEXT', - context, - }; -} diff --git a/packages/commands/src/store/index.js b/packages/commands/src/store/index.js index 38db89576ab87..b8260017fe5a6 100644 --- a/packages/commands/src/store/index.js +++ b/packages/commands/src/store/index.js @@ -9,6 +9,8 @@ import { createReduxStore, register } from '@wordpress/data'; import reducer from './reducer'; import * as actions from './actions'; import * as selectors from './selectors'; +import * as privateActions from './private-actions'; +import { unlock } from '../lock-unlock'; const STORE_NAME = 'core/commands'; @@ -26,3 +28,4 @@ export const store = createReduxStore( STORE_NAME, { } ); register( store ); +unlock( store ).registerPrivateActions( privateActions ); diff --git a/packages/commands/src/store/private-actions.js b/packages/commands/src/store/private-actions.js new file mode 100644 index 0000000000000..57dba53451e65 --- /dev/null +++ b/packages/commands/src/store/private-actions.js @@ -0,0 +1,13 @@ +/** + * Sets the active context. + * + * @param {string} context Context. + * + * @return {Object} action. + */ +export function setContext( context ) { + return { + type: 'SET_CONTEXT', + context, + }; +} diff --git a/packages/components/src/view/README.md b/packages/components/src/view/README.md index 794d7b49a0d38..c1e04ebd8cfff 100644 --- a/packages/components/src/view/README.md +++ b/packages/components/src/view/README.md @@ -27,13 +27,13 @@ function Example() { ## Props -##### as +### as **Type**: `string`,`E` Render the component as another React Component or HTML Element. -##### css +### css **Type**: `InterpolatedCSS` diff --git a/packages/create-block/lib/templates.js b/packages/create-block/lib/templates.js index 48649527ecc84..018385c9fde82 100644 --- a/packages/create-block/lib/templates.js +++ b/packages/create-block/lib/templates.js @@ -220,7 +220,7 @@ const getPluginTemplate = async ( templateName ) => { const getDefaultValues = ( pluginTemplate, variant ) => { return { $schema: 'https://schemas.wp.org/trunk/block.json', - apiVersion: 2, + apiVersion: 3, namespace: 'create-block', category: 'widgets', author: 'The WordPress Contributors', diff --git a/packages/e2e-test-utils-playwright/src/page-utils/drag-files.ts b/packages/e2e-test-utils-playwright/src/page-utils/drag-files.ts index ea59c4602b1f6..f6378b73e33ec 100644 --- a/packages/e2e-test-utils-playwright/src/page-utils/drag-files.ts +++ b/packages/e2e-test-utils-playwright/src/page-utils/drag-files.ts @@ -9,7 +9,7 @@ import { getType } from 'mime'; * Internal dependencies */ import type { PageUtils } from './index'; -import type { Locator } from '@playwright/test'; +import type { ElementHandle, Locator } from '@playwright/test'; type FileObject = { name: string; @@ -141,21 +141,25 @@ async function dragFiles( /** * Drop the files at the current position. + * + * @param locator */ - drop: async () => { - const topMostElement = await this.page.evaluateHandle( - ( { x, y } ) => { - return document.elementFromPoint( x, y ); - }, - position - ); - const elementHandle = topMostElement.asElement(); + drop: async ( locator: Locator | ElementHandle | null ) => { + if ( ! locator ) { + const topMostElement = await this.page.evaluateHandle( + ( { x, y } ) => { + return document.elementFromPoint( x, y ); + }, + position + ); + locator = topMostElement.asElement(); + } - if ( ! elementHandle ) { + if ( ! locator ) { throw new Error( 'Element not found.' ); } - await elementHandle.dispatchEvent( 'drop', { dataTransfer } ); + await locator.dispatchEvent( 'drop', { dataTransfer } ); await cdpSession.detach(); }, diff --git a/packages/e2e-test-utils-playwright/src/page-utils/press-keys.ts b/packages/e2e-test-utils-playwright/src/page-utils/press-keys.ts index 2d93a184913bb..9929ebf19d01a 100644 --- a/packages/e2e-test-utils-playwright/src/page-utils/press-keys.ts +++ b/packages/e2e-test-utils-playwright/src/page-utils/press-keys.ts @@ -49,6 +49,9 @@ export function setClipboardData( async function emulateClipboard( page: Page, type: 'copy' | 'cut' | 'paste' ) { clipboardDataHolder = await page.evaluate( ( [ _type, _clipboardData ] ) => { + const canvasDoc = + // @ts-ignore + document.activeElement?.contentDocument ?? document; const clipboardDataTransfer = new DataTransfer(); if ( _type === 'paste' ) { @@ -61,7 +64,7 @@ async function emulateClipboard( page: Page, type: 'copy' | 'cut' | 'paste' ) { _clipboardData.html ); } else { - const selection = window.getSelection()!; + const selection = canvasDoc.defaultView.getSelection()!; const plainText = selection.toString(); let html = plainText; if ( selection.rangeCount ) { @@ -70,7 +73,8 @@ async function emulateClipboard( page: Page, type: 'copy' | 'cut' | 'paste' ) { html = Array.from( fragment.childNodes ) .map( ( node ) => - ( node as Element ).outerHTML ?? node.nodeValue + ( node as Element ).outerHTML ?? + ( node as Element ).nodeValue ) .join( '' ); } @@ -78,7 +82,7 @@ async function emulateClipboard( page: Page, type: 'copy' | 'cut' | 'paste' ) { clipboardDataTransfer.setData( 'text/html', html ); } - document.activeElement?.dispatchEvent( + canvasDoc.activeElement?.dispatchEvent( new ClipboardEvent( _type, { bubbles: true, cancelable: true, diff --git a/packages/e2e-test-utils/src/click-block-appender.js b/packages/e2e-test-utils/src/click-block-appender.js index caae3dbf11dc7..b1c69789544c7 100644 --- a/packages/e2e-test-utils/src/click-block-appender.js +++ b/packages/e2e-test-utils/src/click-block-appender.js @@ -1,3 +1,8 @@ +/** + * Internal dependencies + */ +import { canvas } from './canvas'; + /** * Clicks the default block appender. */ @@ -6,7 +11,7 @@ export async function clickBlockAppender() { await page.evaluate( () => window.wp.data.dispatch( 'core/block-editor' ).clearSelectedBlock() ); - const appender = await page.waitForSelector( + const appender = await canvas().waitForSelector( '.block-editor-default-block-appender__content' ); await appender.click(); diff --git a/packages/e2e-test-utils/src/inserter.js b/packages/e2e-test-utils/src/inserter.js index 84521728160be..58f6d01a66514 100644 --- a/packages/e2e-test-utils/src/inserter.js +++ b/packages/e2e-test-utils/src/inserter.js @@ -261,7 +261,7 @@ export async function insertFromGlobalInserter( category, searchTerm ) { // Extra wait for the reusable block to be ready. if ( category === 'Reusable' ) { - await page.waitForSelector( + await canvas().waitForSelector( '.block-library-block__reusable-block-container' ); } diff --git a/packages/e2e-test-utils/src/press-key-with-modifier.js b/packages/e2e-test-utils/src/press-key-with-modifier.js index 265c186752f8d..71d8ed72e8de7 100644 --- a/packages/e2e-test-utils/src/press-key-with-modifier.js +++ b/packages/e2e-test-utils/src/press-key-with-modifier.js @@ -24,8 +24,9 @@ import { modifiers, SHIFT, ALT, CTRL } from '@wordpress/keycodes'; async function emulateSelectAll() { await page.evaluate( () => { const isMac = /Mac|iPod|iPhone|iPad/.test( window.navigator.platform ); + const canvasDoc = document.activeElement.contentDocument ?? document; - document.activeElement.dispatchEvent( + canvasDoc.activeElement.dispatchEvent( new KeyboardEvent( 'keydown', { bubbles: true, cancelable: true, @@ -58,14 +59,14 @@ async function emulateSelectAll() { } ); const wasPrevented = - ! document.activeElement.dispatchEvent( preventableEvent ) || + ! canvasDoc.activeElement.dispatchEvent( preventableEvent ) || preventableEvent.defaultPrevented; if ( ! wasPrevented ) { - document.execCommand( 'selectall', false, null ); + canvasDoc.execCommand( 'selectall', false, null ); } - document.activeElement.dispatchEvent( + canvasDoc.activeElement.dispatchEvent( new KeyboardEvent( 'keyup', { bubbles: true, cancelable: true, @@ -103,10 +104,12 @@ export async function setClipboardData( { plainText = '', html = '' } ) { async function emulateClipboard( type ) { await page.evaluate( ( _type ) => { + const canvasDoc = document.activeElement.contentDocument ?? document; + if ( _type !== 'paste' ) { window._clipboardData = new DataTransfer(); - const selection = window.getSelection(); + const selection = canvasDoc.defaultView.getSelection(); const plainText = selection.toString(); let html = plainText; @@ -123,7 +126,7 @@ async function emulateClipboard( type ) { window._clipboardData.setData( 'text/html', html ); } - document.activeElement.dispatchEvent( + canvasDoc.activeElement.dispatchEvent( new ClipboardEvent( _type, { bubbles: true, cancelable: true, diff --git a/packages/e2e-tests/plugins/iframed-block/block.json b/packages/e2e-tests/plugins/iframed-block/block.json index f1110534e27dc..85f86dea8131d 100644 --- a/packages/e2e-tests/plugins/iframed-block/block.json +++ b/packages/e2e-tests/plugins/iframed-block/block.json @@ -1,5 +1,5 @@ { - "apiVersion": 2, + "apiVersion": 3, "name": "test/iframed-block", "title": "Iframed Block", "category": "text", diff --git a/packages/e2e-tests/plugins/iframed-inline-styles/block.json b/packages/e2e-tests/plugins/iframed-inline-styles/block.json index 9e30ecfd6ca54..293b5af5e971f 100644 --- a/packages/e2e-tests/plugins/iframed-inline-styles/block.json +++ b/packages/e2e-tests/plugins/iframed-inline-styles/block.json @@ -1,5 +1,5 @@ { - "apiVersion": 2, + "apiVersion": 3, "name": "test/iframed-inline-styles", "title": "Iframed Inline Styles", "category": "text", diff --git a/packages/e2e-tests/plugins/iframed-inline-styles/editor.js b/packages/e2e-tests/plugins/iframed-inline-styles/editor.js index 1898e63075895..719c36a912b5d 100644 --- a/packages/e2e-tests/plugins/iframed-inline-styles/editor.js +++ b/packages/e2e-tests/plugins/iframed-inline-styles/editor.js @@ -4,7 +4,7 @@ const { useBlockProps } = blockEditor; registerBlockType( 'test/iframed-inline-styles', { - apiVersion: 2, + apiVersion: 3, edit: function Edit() { return el( 'div', useBlockProps(), 'Edit' ); }, diff --git a/packages/e2e-tests/plugins/iframed-masonry-block/block.json b/packages/e2e-tests/plugins/iframed-masonry-block/block.json index 6b7c995df9649..b9b3f17234e30 100644 --- a/packages/e2e-tests/plugins/iframed-masonry-block/block.json +++ b/packages/e2e-tests/plugins/iframed-masonry-block/block.json @@ -1,5 +1,5 @@ { - "apiVersion": 2, + "apiVersion": 3, "name": "test/iframed-masonry-block", "title": "Iframed Masonry Block", "category": "text", diff --git a/packages/e2e-tests/plugins/iframed-masonry-block/editor.js b/packages/e2e-tests/plugins/iframed-masonry-block/editor.js index 82b0c8d83a7da..eebd7d370e085 100644 --- a/packages/e2e-tests/plugins/iframed-masonry-block/editor.js +++ b/packages/e2e-tests/plugins/iframed-masonry-block/editor.js @@ -31,7 +31,7 @@ ]; registerBlockType( 'test/iframed-masonry-block', { - apiVersion: 2, + apiVersion: 3, edit: function Edit() { const ref = useRefEffect( ( node ) => { const { ownerDocument } = node; diff --git a/packages/e2e-tests/plugins/iframed-multiple-stylesheets/block.json b/packages/e2e-tests/plugins/iframed-multiple-stylesheets/block.json index fbd2e65e13397..4db03f471177d 100644 --- a/packages/e2e-tests/plugins/iframed-multiple-stylesheets/block.json +++ b/packages/e2e-tests/plugins/iframed-multiple-stylesheets/block.json @@ -1,5 +1,5 @@ { - "apiVersion": 2, + "apiVersion": 3, "name": "test/iframed-multiple-stylesheets", "title": "Iframed Multiple Stylesheets", "category": "text", diff --git a/packages/e2e-tests/plugins/iframed-multiple-stylesheets/editor.js b/packages/e2e-tests/plugins/iframed-multiple-stylesheets/editor.js index be3ded2d9e2b7..fce08fadff850 100644 --- a/packages/e2e-tests/plugins/iframed-multiple-stylesheets/editor.js +++ b/packages/e2e-tests/plugins/iframed-multiple-stylesheets/editor.js @@ -4,7 +4,7 @@ const { useBlockProps } = blockEditor; registerBlockType( 'test/iframed-multiple-stylesheets', { - apiVersion: 2, + apiVersion: 3, edit: function Edit() { return el( 'div', useBlockProps(), 'Edit' ); }, diff --git a/packages/e2e-tests/specs/editor/blocks/post-title.test.js b/packages/e2e-tests/specs/editor/blocks/post-title.test.js index 19def877290c1..0f9fc610be3ee 100644 --- a/packages/e2e-tests/specs/editor/blocks/post-title.test.js +++ b/packages/e2e-tests/specs/editor/blocks/post-title.test.js @@ -5,6 +5,7 @@ import { createNewPost, insertBlock, saveDraft, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Post Title block', () => { @@ -17,8 +18,8 @@ describe( 'Post Title block', () => { await insertBlock( 'Title' ); const editablePostTitleSelector = '.wp-block-post-title[contenteditable="true"]'; - await page.waitForSelector( editablePostTitleSelector ); - await page.focus( editablePostTitleSelector ); + await canvas().waitForSelector( editablePostTitleSelector ); + await canvas().focus( editablePostTitleSelector ); // Create a second list item. await page.keyboard.type( 'Just tweaking the post title' ); @@ -26,7 +27,7 @@ describe( 'Post Title block', () => { await saveDraft(); await page.reload(); await page.waitForSelector( '.edit-post-layout' ); - const title = await page.$eval( + const title = await canvas().$eval( '.editor-post-title__input', ( element ) => element.textContent ); diff --git a/packages/e2e-tests/specs/editor/blocks/site-title.test.js b/packages/e2e-tests/specs/editor/blocks/site-title.test.js index 32428a73c8e20..d24b79b6bb372 100644 --- a/packages/e2e-tests/specs/editor/blocks/site-title.test.js +++ b/packages/e2e-tests/specs/editor/blocks/site-title.test.js @@ -9,6 +9,7 @@ import { pressKeyWithModifier, setOption, openDocumentSettingsSidebar, + canvas, } from '@wordpress/e2e-test-utils'; const saveEntities = async () => { @@ -45,8 +46,8 @@ describe( 'Site Title block', () => { await insertBlock( 'Site Title' ); const editableSiteTitleSelector = '[aria-label="Block: Site Title"] a[contenteditable="true"]'; - await page.waitForSelector( editableSiteTitleSelector ); - await page.focus( editableSiteTitleSelector ); + await canvas().waitForSelector( editableSiteTitleSelector ); + await canvas().focus( editableSiteTitleSelector ); await pressKeyWithModifier( 'primary', 'a' ); await page.keyboard.type( 'New Site Title' ); diff --git a/packages/e2e-tests/specs/editor/plugins/annotations.test.js b/packages/e2e-tests/specs/editor/plugins/annotations.test.js index 85265bf424abc..f0134812d4a7e 100644 --- a/packages/e2e-tests/specs/editor/plugins/annotations.test.js +++ b/packages/e2e-tests/specs/editor/plugins/annotations.test.js @@ -8,6 +8,7 @@ import { clickOnMoreMenuItem, createNewPost, deactivatePlugin, + canvas, } from '@wordpress/e2e-test-utils'; const clickOnBlockSettingsMenuItem = async ( buttonLabel ) => { @@ -28,6 +29,13 @@ describe( 'Annotations', () => { beforeEach( async () => { await createNewPost(); + // To do: run with iframe. + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); } ); /** @@ -51,7 +59,7 @@ describe( 'Annotations', () => { await page.$x( "//button[contains(text(), 'Add annotation')]" ) )[ 0 ]; await addAnnotationButton.click(); - await page.evaluate( () => + await canvas().evaluate( () => document.querySelector( '.wp-block-paragraph' ).focus() ); } @@ -67,7 +75,7 @@ describe( 'Annotations', () => { await page.$x( "//button[contains(text(), 'Remove annotations')]" ) )[ 0 ]; await addAnnotationButton.click(); - await page.evaluate( () => + await canvas().evaluate( () => document.querySelector( '[contenteditable]' ).focus() ); } @@ -78,11 +86,11 @@ describe( 'Annotations', () => { * @return {Promise} The annotated text. */ async function getAnnotatedText() { - const annotations = await page.$$( ANNOTATIONS_SELECTOR ); + const annotations = await canvas().$$( ANNOTATIONS_SELECTOR ); const annotation = annotations[ 0 ]; - return await page.evaluate( ( el ) => el.innerText, annotation ); + return await canvas().evaluate( ( el ) => el.innerText, annotation ); } /** @@ -91,7 +99,7 @@ describe( 'Annotations', () => { * @return {Promise} Inner HTML. */ async function getRichTextInnerHTML() { - const htmlContent = await page.$$( '.wp-block-paragraph' ); + const htmlContent = await canvas().$$( '.wp-block-paragraph' ); return await page.evaluate( ( el ) => { return el.innerHTML; }, htmlContent[ 0 ] ); @@ -102,12 +110,12 @@ describe( 'Annotations', () => { await clickOnMoreMenuItem( 'Annotations' ); - let annotations = await page.$$( ANNOTATIONS_SELECTOR ); + let annotations = await canvas().$$( ANNOTATIONS_SELECTOR ); expect( annotations ).toHaveLength( 0 ); await annotateFirstBlock( 9, 13 ); - annotations = await page.$$( ANNOTATIONS_SELECTOR ); + annotations = await canvas().$$( ANNOTATIONS_SELECTOR ); expect( annotations ).toHaveLength( 1 ); const text = await getAnnotatedText(); @@ -115,7 +123,7 @@ describe( 'Annotations', () => { await clickOnBlockSettingsMenuItem( 'Edit as HTML' ); - const htmlContent = await page.$$( + const htmlContent = await canvas().$$( '.block-editor-block-list__block-html-textarea' ); const html = await page.evaluate( ( el ) => { @@ -136,7 +144,7 @@ describe( 'Annotations', () => { await page.keyboard.type( 'D' ); await removeAnnotations(); - const htmlContent = await page.$$( '.wp-block-paragraph' ); + const htmlContent = await canvas().$$( '.wp-block-paragraph' ); const html = await page.evaluate( ( el ) => { return el.innerHTML; }, htmlContent[ 0 ] ); diff --git a/packages/e2e-tests/specs/editor/plugins/block-variations.test.js b/packages/e2e-tests/specs/editor/plugins/block-variations.test.js index 886382a4667b1..4a24cd3f478d2 100644 --- a/packages/e2e-tests/specs/editor/plugins/block-variations.test.js +++ b/packages/e2e-tests/specs/editor/plugins/block-variations.test.js @@ -11,6 +11,7 @@ import { openDocumentSettingsSidebar, togglePreferencesOption, toggleMoreMenu, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Block variations', () => { @@ -45,7 +46,7 @@ describe( 'Block variations', () => { await insertBlock( 'Large Quote' ); expect( - await page.$( + await canvas().$( '.wp-block[data-type="core/quote"] blockquote.is-style-large' ) ).toBeDefined(); @@ -58,7 +59,7 @@ describe( 'Block variations', () => { await page.keyboard.press( 'Enter' ); expect( - await page.$( + await canvas().$( '.wp-block[data-type="core/quote"] blockquote.is-style-large' ) ).toBeDefined(); @@ -75,7 +76,7 @@ describe( 'Block variations', () => { test( 'Insert the Success Message block variation', async () => { await insertBlock( 'Success Message' ); - const successMessageBlock = await page.$( + const successMessageBlock = await canvas().$( '.wp-block[data-type="core/paragraph"]' ); expect( successMessageBlock ).toBeDefined(); @@ -86,12 +87,12 @@ describe( 'Block variations', () => { test( 'Pick the additional variation in the inserted Columns block', async () => { await insertBlock( 'Columns' ); - const fourColumnsVariation = await page.waitForSelector( + const fourColumnsVariation = await canvas().waitForSelector( '.wp-block[data-type="core/columns"] .block-editor-block-variation-picker__variation[aria-label="Four columns"]' ); await fourColumnsVariation.click(); expect( - await page.$$( + await canvas().$$( '.wp-block[data-type="core/columns"] .wp-block[data-type="core/column"]' ) ).toHaveLength( 4 ); diff --git a/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js b/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js index 1a4d8e2b6d433..447be0793fafb 100644 --- a/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js +++ b/packages/e2e-tests/specs/editor/plugins/cpt-locking.test.js @@ -12,6 +12,7 @@ import { pressKeyTimes, pressKeyWithModifier, setPostContent, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'cpt locking', () => { @@ -35,7 +36,7 @@ describe( 'cpt locking', () => { }; const shouldNotAllowBlocksToBeRemoved = async () => { - await page.type( + await canvas().type( '.block-editor-rich-text__editable[data-type="core/paragraph"]', 'p1' ); @@ -46,12 +47,12 @@ describe( 'cpt locking', () => { }; const shouldAllowBlocksToBeMoved = async () => { - await page.click( + await canvas().click( 'div > .block-editor-rich-text__editable[data-type="core/paragraph"]' ); expect( await page.$( 'button[aria-label="Move up"]' ) ).not.toBeNull(); await page.click( 'button[aria-label="Move up"]' ); - await page.type( + await canvas().type( 'div > .block-editor-rich-text__editable[data-type="core/paragraph"]', 'p1' ); @@ -71,14 +72,14 @@ describe( 'cpt locking', () => { ); it( 'should not allow blocks to be moved', async () => { - await page.click( + await canvas().click( '.block-editor-rich-text__editable[data-type="core/paragraph"]' ); expect( await page.$( 'button[aria-label="Move up"]' ) ).toBeNull(); } ); it( 'should not error when deleting the cotents of a paragraph', async () => { - await page.click( + await canvas().click( '.block-editor-block-list__block[data-type="core/paragraph"]' ); const textToType = 'Paragraph'; @@ -88,7 +89,7 @@ describe( 'cpt locking', () => { } ); it( 'should insert line breaks when using enter and shift-enter', async () => { - await page.click( + await canvas().click( '.block-editor-block-list__block[data-type="core/paragraph"]' ); await page.keyboard.type( 'First line' ); @@ -118,12 +119,14 @@ describe( 'cpt locking', () => { } ); it( 'should not allow blocks to be inserted in inner blocks', async () => { - await page.click( 'button[aria-label="Two columns; equal split"]' ); + await canvas().click( + 'button[aria-label="Two columns; equal split"]' + ); await page.evaluate( () => new Promise( window.requestIdleCallback ) ); expect( - await page.$( + await canvas().$( '.wp-block-column .block-editor-button-block-appender' ) ).toBeNull(); @@ -173,7 +176,7 @@ describe( 'cpt locking', () => { } ); it( 'should allow blocks to be removed', async () => { - await page.type( + await canvas().type( '.block-editor-rich-text__editable[data-type="core/paragraph"]', 'p1' ); @@ -193,7 +196,7 @@ describe( 'cpt locking', () => { } ); it( 'should allow blocks to be removed', async () => { - await page.type( + await canvas().type( 'div > .block-editor-rich-text__editable[data-type="core/paragraph"]', 'p1' ); @@ -219,7 +222,7 @@ describe( 'cpt locking', () => { ); it( 'should not allow blocks to be moved', async () => { - await page.click( + await canvas().click( '.block-editor-rich-text__editable[data-type="core/paragraph"]' ); expect( await page.$( 'button[aria-label="Move up"]' ) ).toBeNull(); @@ -239,7 +242,7 @@ describe( 'cpt locking', () => { ); it( 'should not allow blocks to be moved', async () => { - await page.click( + await canvas().click( '.block-editor-rich-text__editable[data-type="core/paragraph"]' ); expect( await page.$( 'button[aria-label="Move up"]' ) ).toBeNull(); diff --git a/packages/e2e-tests/specs/editor/plugins/iframed-inline-styles.test.js b/packages/e2e-tests/specs/editor/plugins/iframed-inline-styles.test.js index 3dff32c0843c4..eafc0b1f48b61 100644 --- a/packages/e2e-tests/specs/editor/plugins/iframed-inline-styles.test.js +++ b/packages/e2e-tests/specs/editor/plugins/iframed-inline-styles.test.js @@ -35,8 +35,10 @@ describe( 'iframed inline styles', () => { await insertBlock( 'Iframed Inline Styles' ); expect( await getEditedPostContent() ).toMatchSnapshot(); - expect( await getComputedStyle( page, 'padding' ) ).toBe( '20px' ); - expect( await getComputedStyle( page, 'border-width' ) ).toBe( '2px' ); + expect( await getComputedStyle( canvas(), 'padding' ) ).toBe( '20px' ); + expect( await getComputedStyle( canvas(), 'border-width' ) ).toBe( + '2px' + ); await createNewTemplate( 'Iframed Test' ); diff --git a/packages/e2e-tests/specs/editor/plugins/iframed-masonry-block.test.js b/packages/e2e-tests/specs/editor/plugins/iframed-masonry-block.test.js index 47767edc8e5d2..503beeb92e164 100644 --- a/packages/e2e-tests/specs/editor/plugins/iframed-masonry-block.test.js +++ b/packages/e2e-tests/specs/editor/plugins/iframed-masonry-block.test.js @@ -39,7 +39,7 @@ describe( 'iframed masonry block', () => { await insertBlock( 'Iframed Masonry Block' ); expect( await getEditedPostContent() ).toMatchSnapshot(); - expect( await didMasonryLoadCorrectly( page ) ).toBe( true ); + expect( await didMasonryLoadCorrectly( canvas() ) ).toBe( true ); await createNewTemplate( 'Iframed Test' ); await canvas().waitForSelector( '.grid-item[style]' ); diff --git a/packages/e2e-tests/specs/editor/plugins/iframed-multiple-block-stylesheets.test.js b/packages/e2e-tests/specs/editor/plugins/iframed-multiple-block-stylesheets.test.js index 9d8e5975d3f2e..23058b48b8da4 100644 --- a/packages/e2e-tests/specs/editor/plugins/iframed-multiple-block-stylesheets.test.js +++ b/packages/e2e-tests/specs/editor/plugins/iframed-multiple-block-stylesheets.test.js @@ -35,7 +35,7 @@ describe( 'iframed multiple block stylesheets', () => { it( 'should load multiple block stylesheets in iframe', async () => { await insertBlock( 'Iframed Multiple Stylesheets' ); - await page.waitForSelector( + await canvas().waitForSelector( '.wp-block-test-iframed-multiple-stylesheets' ); await createNewTemplate( 'Iframed Test' ); diff --git a/packages/e2e-tests/specs/editor/plugins/inner-blocks-allowed-blocks.test.js b/packages/e2e-tests/specs/editor/plugins/inner-blocks-allowed-blocks.test.js index 4431d3bd5802f..aec9987f596a8 100644 --- a/packages/e2e-tests/specs/editor/plugins/inner-blocks-allowed-blocks.test.js +++ b/packages/e2e-tests/specs/editor/plugins/inner-blocks-allowed-blocks.test.js @@ -10,6 +10,7 @@ import { openGlobalBlockInserter, closeGlobalBlockInserter, clickBlockToolbarButton, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Allowed Blocks Setting on InnerBlocks', () => { @@ -32,8 +33,8 @@ describe( 'Allowed Blocks Setting on InnerBlocks', () => { const childParagraphSelector = `${ parentBlockSelector } ${ paragraphSelector }`; await insertBlock( 'Allowed Blocks Unset' ); await closeGlobalBlockInserter(); - await page.waitForSelector( childParagraphSelector ); - await page.click( childParagraphSelector ); + await canvas().waitForSelector( childParagraphSelector ); + await canvas().click( childParagraphSelector ); await openGlobalBlockInserter(); await expect( ( @@ -47,8 +48,8 @@ describe( 'Allowed Blocks Setting on InnerBlocks', () => { const childParagraphSelector = `${ parentBlockSelector } ${ paragraphSelector }`; await insertBlock( 'Allowed Blocks Set' ); await closeGlobalBlockInserter(); - await page.waitForSelector( childParagraphSelector ); - await page.click( childParagraphSelector ); + await canvas().waitForSelector( childParagraphSelector ); + await canvas().click( childParagraphSelector ); await openGlobalBlockInserter(); const allowedBlocks = await getAllBlockInserterItemTitles(); expect( allowedBlocks.sort() ).toEqual( [ @@ -66,8 +67,8 @@ describe( 'Allowed Blocks Setting on InnerBlocks', () => { const parentBlockSelector = '[data-type="test/allowed-blocks-dynamic"]'; const blockAppender = '.block-list-appender button'; const appenderSelector = `${ parentBlockSelector } ${ blockAppender }`; - await page.waitForSelector( appenderSelector ); - await page.click( appenderSelector ); + await canvas().waitForSelector( appenderSelector ); + await canvas().click( appenderSelector ); expect( await getAllBlockInserterItemTitles() ).toEqual( [ 'Image', 'List', diff --git a/packages/e2e-tests/specs/editor/plugins/inner-blocks-prioritized-inserter-blocks.test.js b/packages/e2e-tests/specs/editor/plugins/inner-blocks-prioritized-inserter-blocks.test.js index 77ae8d3827432..7621fbea12140 100644 --- a/packages/e2e-tests/specs/editor/plugins/inner-blocks-prioritized-inserter-blocks.test.js +++ b/packages/e2e-tests/specs/editor/plugins/inner-blocks-prioritized-inserter-blocks.test.js @@ -8,6 +8,7 @@ import { getAllBlockInserterItemTitles, insertBlock, closeGlobalBlockInserter, + canvas, } from '@wordpress/e2e-test-utils'; const QUICK_INSERTER_RESULTS_SELECTOR = @@ -108,7 +109,7 @@ describe( 'Prioritized Inserter Blocks Setting on InnerBlocks', () => { describe( 'Slash inserter', () => { it( 'uses the priority ordering if prioritzed blocks setting is set', async () => { await insertBlock( 'Prioritized Inserter Blocks Set' ); - await page.click( '[data-type="core/image"]' ); + await canvas().click( '[data-type="core/image"]' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( '/' ); // Wait for the results to display. diff --git a/packages/e2e-tests/specs/editor/various/adding-inline-tokens.test.js b/packages/e2e-tests/specs/editor/various/adding-inline-tokens.test.js index 513a9fa7af27b..7c04bae1f95dd 100644 --- a/packages/e2e-tests/specs/editor/various/adding-inline-tokens.test.js +++ b/packages/e2e-tests/specs/editor/various/adding-inline-tokens.test.js @@ -68,7 +68,6 @@ describe( 'adding inline tokens', () => { '.block-editor-format-toolbar__image-popover' ); await page.keyboard.press( 'Tab' ); - await page.keyboard.press( 'Tab' ); await page.keyboard.type( '20' ); await page.keyboard.press( 'Enter' ); diff --git a/packages/e2e-tests/specs/editor/various/autosave.test.js b/packages/e2e-tests/specs/editor/various/autosave.test.js index abf4ad8b83e68..528efc2d46316 100644 --- a/packages/e2e-tests/specs/editor/various/autosave.test.js +++ b/packages/e2e-tests/specs/editor/various/autosave.test.js @@ -9,6 +9,7 @@ import { publishPost, saveDraft, toggleOfflineMode, + canvas, } from '@wordpress/e2e-test-utils'; // Constant to override editor preference @@ -258,7 +259,7 @@ describe( 'autosave', () => { await page.keyboard.type( 'before publish' ); await publishPost(); - await page.click( '[data-type="core/paragraph"]' ); + await canvas().click( '[data-type="core/paragraph"]' ); await page.keyboard.type( ' after publish' ); // Trigger remote autosave. diff --git a/packages/e2e-tests/specs/editor/various/block-editor-keyboard-shortcuts.test.js b/packages/e2e-tests/specs/editor/various/block-editor-keyboard-shortcuts.test.js index e6e156ca8ee15..f1e6be7b816ab 100644 --- a/packages/e2e-tests/specs/editor/various/block-editor-keyboard-shortcuts.test.js +++ b/packages/e2e-tests/specs/editor/various/block-editor-keyboard-shortcuts.test.js @@ -9,6 +9,7 @@ import { clickBlockToolbarButton, clickMenuItem, clickOnCloseModalButton, + canvas, } from '@wordpress/e2e-test-utils'; const createTestParagraphBlocks = async () => { @@ -51,7 +52,7 @@ describe( 'block editor keyboard shortcuts', () => { await createTestParagraphBlocks(); expect( await getEditedPostContent() ).toMatchSnapshot(); await pressKeyWithModifier( 'shift', 'ArrowUp' ); - await page.waitForSelector( + await canvas().waitForSelector( '[aria-label="Multiple selected blocks"]' ); await moveUp(); @@ -63,7 +64,7 @@ describe( 'block editor keyboard shortcuts', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); await page.keyboard.press( 'ArrowUp' ); await pressKeyWithModifier( 'shift', 'ArrowUp' ); - await page.waitForSelector( + await canvas().waitForSelector( '[aria-label="Multiple selected blocks"]' ); await moveDown(); diff --git a/packages/e2e-tests/specs/editor/various/block-grouping.test.js b/packages/e2e-tests/specs/editor/various/block-grouping.test.js index 07dcabcbf0526..f67273a550d1c 100644 --- a/packages/e2e-tests/specs/editor/various/block-grouping.test.js +++ b/packages/e2e-tests/specs/editor/various/block-grouping.test.js @@ -14,6 +14,7 @@ import { activatePlugin, deactivatePlugin, createReusableBlock, + canvas, } from '@wordpress/e2e-test-utils'; async function insertBlocksOfSameType() { @@ -115,8 +116,8 @@ describe( 'Block Grouping', () => { const getParagraphText = async () => { const paragraphInReusableSelector = '.block-editor-block-list__block[data-type="core/block"] p'; - await page.waitForSelector( paragraphInReusableSelector ); - return page.$eval( + await canvas().waitForSelector( paragraphInReusableSelector ); + return canvas().$eval( paragraphInReusableSelector, ( element ) => element.innerText ); @@ -128,14 +129,14 @@ describe( 'Block Grouping', () => { await clickBlockToolbarButton( 'Options' ); await clickMenuItem( 'Group' ); - let group = await page.$$( '[data-type="core/group"]' ); + let group = await canvas().$$( '[data-type="core/group"]' ); expect( group ).toHaveLength( 1 ); // Make sure the paragraph in reusable block exists. expect( await getParagraphText() ).toMatch( paragraphText ); await clickBlockToolbarButton( 'Options' ); await clickMenuItem( 'Ungroup' ); - group = await page.$$( '[data-type="core/group"]' ); + group = await canvas().$$( '[data-type="core/group"]' ); expect( group ).toHaveLength( 0 ); // Make sure the paragraph in reusable block exists. expect( await getParagraphText() ).toEqual( paragraphText ); diff --git a/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js b/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js index 2d05fc08baf7f..9737007ce656e 100644 --- a/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js +++ b/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js @@ -10,6 +10,7 @@ import { openDocumentSettingsSidebar, getListViewBlocks, switchBlockInspectorTab, + canvas, } from '@wordpress/e2e-test-utils'; async function openListViewSidebar() { @@ -53,7 +54,7 @@ describe( 'Navigating the block hierarchy', () => { it( 'should navigate using the list view sidebar', async () => { await insertBlock( 'Columns' ); - await page.click( '[aria-label="Two columns; equal split"]' ); + await canvas().click( '[aria-label="Two columns; equal split"]' ); // Add a paragraph in the first column. await page.keyboard.press( 'ArrowDown' ); // Navigate to inserter. @@ -114,7 +115,7 @@ describe( 'Navigating the block hierarchy', () => { it( 'should navigate block hierarchy using only the keyboard', async () => { await insertBlock( 'Columns' ); await openDocumentSettingsSidebar(); - await page.click( '[aria-label="Two columns; equal split"]' ); + await canvas().click( '[aria-label="Two columns; equal split"]' ); // Add a paragraph in the first column. await page.keyboard.press( 'ArrowDown' ); // Navigate to inserter. @@ -143,11 +144,13 @@ describe( 'Navigating the block hierarchy', () => { await pressKeyWithModifier( 'ctrlShift', '`' ); await pressKeyTimes( 'Tab', 3 ); await pressKeyTimes( 'ArrowDown', 4 ); - await page.waitForSelector( + await canvas().waitForSelector( '.is-highlighted[aria-label="Block: Column (3 of 3)"]' ); await page.keyboard.press( 'Enter' ); - await page.waitForSelector( '.is-selected[data-type="core/column"]' ); + await canvas().waitForSelector( + '.is-selected[data-type="core/column"]' + ); // Insert text in the last column block. await page.keyboard.press( 'ArrowDown' ); // Navigate to inserter. @@ -190,12 +193,12 @@ describe( 'Navigating the block hierarchy', () => { // Insert a group block. await insertBlock( 'Group' ); // Select the default, selected Group layout from the variation picker. - await page.click( + await canvas().click( 'button[aria-label="Group: Gather blocks in a container."]' ); // Insert some random blocks. // The last block shouldn't be a textual block. - await page.click( '.block-list-appender .block-editor-inserter' ); + await canvas().click( '.block-list-appender .block-editor-inserter' ); const paragraphMenuItem = ( await page.$x( `//button//span[contains(text(), 'Paragraph')]` ) )[ 0 ]; @@ -207,7 +210,7 @@ describe( 'Navigating the block hierarchy', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); // Unselect the blocks. - await page.click( '.editor-post-title' ); + await canvas().click( '.editor-post-title' ); // Try selecting the group block using the Outline. await page.click( @@ -217,7 +220,7 @@ describe( 'Navigating the block hierarchy', () => { await groupMenuItem.click(); // The group block's wrapper should be selected. - const isGroupBlockSelected = await page.evaluate( + const isGroupBlockSelected = await canvas().evaluate( () => document.activeElement.getAttribute( 'data-type' ) === 'core/group' diff --git a/packages/e2e-tests/specs/editor/various/change-detection.test.js b/packages/e2e-tests/specs/editor/various/change-detection.test.js index dab3765ef0d14..97157060d3624 100644 --- a/packages/e2e-tests/specs/editor/various/change-detection.test.js +++ b/packages/e2e-tests/specs/editor/various/change-detection.test.js @@ -11,6 +11,7 @@ import { openDocumentSettingsSidebar, isCurrentURL, openTypographyToolsPanelMenu, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Change detection', () => { @@ -78,7 +79,7 @@ describe( 'Change detection', () => { } ); it( 'Should autosave post', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Force autosave to occur immediately. await Promise.all( [ @@ -94,7 +95,7 @@ describe( 'Change detection', () => { } ); it( 'Should prompt to confirm unsaved changes for autosaved draft for non-content fields', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Toggle post as needing review (not persisted for autosave). await ensureSidebarOpened(); @@ -117,7 +118,7 @@ describe( 'Change detection', () => { } ); it( 'Should prompt to confirm unsaved changes for autosaved published post', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); await publishPost(); @@ -130,7 +131,7 @@ describe( 'Change detection', () => { ] ); // Should be dirty after autosave change of published post. - await page.type( '.editor-post-title__input', '!' ); + await canvas().type( '.editor-post-title__input', '!' ); await Promise.all( [ page.waitForSelector( @@ -162,7 +163,7 @@ describe( 'Change detection', () => { } ); it( 'Should prompt if property changed without save', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); await assertIsDirty( true ); } ); @@ -175,7 +176,7 @@ describe( 'Change detection', () => { } ); it( 'Should not prompt if changes saved', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); await saveDraft(); @@ -192,7 +193,7 @@ describe( 'Change detection', () => { } ); it( 'Should not save if all changes saved', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); await saveDraft(); @@ -205,7 +206,7 @@ describe( 'Change detection', () => { } ); it( 'Should prompt if save failed', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); await page.setOfflineMode( true ); @@ -231,7 +232,7 @@ describe( 'Change detection', () => { } ); it( 'Should prompt if changes and save is in-flight', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Hold the posts request so we don't deal with race conditions of the // save completing early. Other requests should be allowed to continue, @@ -247,7 +248,7 @@ describe( 'Change detection', () => { } ); it( 'Should prompt if changes made while save is in-flight', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Hold the posts request so we don't deal with race conditions of the // save completing early. Other requests should be allowed to continue, @@ -257,7 +258,7 @@ describe( 'Change detection', () => { // Keyboard shortcut Ctrl+S save. await pressKeyWithModifier( 'primary', 'S' ); - await page.type( '.editor-post-title__input', '!' ); + await canvas().type( '.editor-post-title__input', '!' ); await page.waitForSelector( '.editor-post-save-draft' ); await releaseSaveIntercept(); @@ -266,7 +267,7 @@ describe( 'Change detection', () => { } ); it( 'Should prompt if property changes made while save is in-flight, and save completes', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Hold the posts request so we don't deal with race conditions of the // save completing early. @@ -282,7 +283,7 @@ describe( 'Change detection', () => { ); // Dirty post while save is in-flight. - await page.type( '.editor-post-title__input', '!' ); + await canvas().type( '.editor-post-title__input', '!' ); // Allow save to complete. Disabling interception flushes pending. await Promise.all( [ savedPromise, releaseSaveIntercept() ] ); @@ -291,7 +292,7 @@ describe( 'Change detection', () => { } ); it( 'Should prompt if block revision is made while save is in-flight, and save completes', async () => { - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Hold the posts request so we don't deal with race conditions of the // save completing early. @@ -324,7 +325,7 @@ describe( 'Change detection', () => { await saveDraft(); // Verify that the title is empty. - const title = await page.$eval( + const title = await canvas().$eval( '.editor-post-title__input', // Trim padding non-breaking space. ( element ) => element.textContent.trim() @@ -337,7 +338,7 @@ describe( 'Change detection', () => { it( 'should not prompt to confirm unsaved changes when trashing an existing post', async () => { // Enter title. - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Save. await saveDraft(); @@ -381,7 +382,7 @@ describe( 'Change detection', () => { ] ); // Change the paragraph's `drop cap`. - await page.click( '[data-type="core/paragraph"]' ); + await canvas().click( '[data-type="core/paragraph"]' ); await openTypographyToolsPanelMenu(); await page.click( 'button[aria-label="Show Drop cap"]' ); @@ -390,7 +391,7 @@ describe( 'Change detection', () => { "//label[contains(text(), 'Drop cap')]" ); await dropCapToggle.click(); - await page.click( '[data-type="core/paragraph"]' ); + await canvas().click( '[data-type="core/paragraph"]' ); // Check that the post is dirty. await page.waitForSelector( '.editor-post-save-draft' ); @@ -402,7 +403,7 @@ describe( 'Change detection', () => { ] ); // Change the paragraph's `drop cap` again. - await page.click( '[data-type="core/paragraph"]' ); + await canvas().click( '[data-type="core/paragraph"]' ); await dropCapToggle.click(); // Check that the post is dirty. diff --git a/packages/e2e-tests/specs/editor/various/editor-modes.test.js b/packages/e2e-tests/specs/editor/various/editor-modes.test.js index de328b87f736d..81878ebf7208e 100644 --- a/packages/e2e-tests/specs/editor/various/editor-modes.test.js +++ b/packages/e2e-tests/specs/editor/various/editor-modes.test.js @@ -11,6 +11,7 @@ import { pressKeyTimes, pressKeyWithModifier, openTypographyToolsPanelMenu, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Editing modes (visual/HTML)', () => { @@ -22,7 +23,7 @@ describe( 'Editing modes (visual/HTML)', () => { it( 'should switch between visual and HTML modes', async () => { // This block should be in "visual" mode by default. - let visualBlock = await page.$$( '[data-block].rich-text' ); + let visualBlock = await canvas().$$( '[data-block].rich-text' ); expect( visualBlock ).toHaveLength( 1 ); // Change editing mode from "Visual" to "HTML". @@ -30,7 +31,7 @@ describe( 'Editing modes (visual/HTML)', () => { await clickMenuItem( 'Edit as HTML' ); // Wait for the block to be converted to HTML editing mode. - const htmlBlock = await page.$$( + const htmlBlock = await canvas().$$( '[data-block] .block-editor-block-list__block-html-textarea' ); expect( htmlBlock ).toHaveLength( 1 ); @@ -40,7 +41,7 @@ describe( 'Editing modes (visual/HTML)', () => { await clickMenuItem( 'Edit visually' ); // This block should be in "visual" mode by default. - visualBlock = await page.$$( '[data-block].rich-text' ); + visualBlock = await canvas().$$( '[data-block].rich-text' ); expect( visualBlock ).toHaveLength( 1 ); } ); @@ -67,7 +68,7 @@ describe( 'Editing modes (visual/HTML)', () => { await clickMenuItem( 'Edit as HTML' ); // Make sure the paragraph content is rendered as expected. - let htmlBlockContent = await page.$eval( + let htmlBlockContent = await canvas().$eval( '.block-editor-block-list__layout .block-editor-block-list__block .block-editor-block-list__block-html-textarea', ( node ) => node.textContent ); @@ -83,7 +84,7 @@ describe( 'Editing modes (visual/HTML)', () => { await dropCapToggle.click(); // Make sure the HTML content updated. - htmlBlockContent = await page.$eval( + htmlBlockContent = await canvas().$eval( '.block-editor-block-list__layout .block-editor-block-list__block .block-editor-block-list__block-html-textarea', ( node ) => node.textContent ); @@ -138,7 +139,7 @@ describe( 'Editing modes (visual/HTML)', () => { const editPosition = textContent.indexOf( 'Hello' ); // Replace the word 'Hello' with 'Hi'. - await page.click( '.editor-post-title__input' ); + await canvas().click( '.editor-post-title__input' ); await page.keyboard.press( 'Tab' ); await pressKeyTimes( 'ArrowRight', editPosition ); await pressKeyTimes( 'Delete', 5 ); diff --git a/packages/e2e-tests/specs/editor/various/embedding.test.js b/packages/e2e-tests/specs/editor/various/embedding.test.js index a7522b88e7729..4461fc6233053 100644 --- a/packages/e2e-tests/specs/editor/various/embedding.test.js +++ b/packages/e2e-tests/specs/editor/various/embedding.test.js @@ -3,7 +3,6 @@ */ import { clickBlockAppender, - clickButton, createEmbeddingMatcher, createJSONResponse, createNewPost, @@ -12,6 +11,7 @@ import { insertBlock, publishPost, setUpResponseMocking, + canvas, } from '@wordpress/e2e-test-utils'; const MOCK_EMBED_WORDPRESS_SUCCESS_RESPONSE = { @@ -178,24 +178,24 @@ describe( 'Embedding content', () => { it( 'should render embeds in the correct state', async () => { // Valid embed. Should render valid figure element. await insertEmbed( 'https://twitter.com/notnownikki' ); - await page.waitForSelector( 'figure.wp-block-embed' ); + await canvas().waitForSelector( 'figure.wp-block-embed' ); // Valid provider; invalid content. Should render failed, edit state. await insertEmbed( 'https://twitter.com/wooyaygutenberg123454312' ); - await page.waitForSelector( + await canvas().waitForSelector( 'input[value="https://twitter.com/wooyaygutenberg123454312"]' ); // WordPress invalid content. Should render failed, edit state. await insertEmbed( 'https://wordpress.org/gutenberg/handbook/' ); - await page.waitForSelector( + await canvas().waitForSelector( 'input[value="https://wordpress.org/gutenberg/handbook/"]' ); // Provider whose oembed API has gone wrong. Should render failed, edit // state. await insertEmbed( 'https://twitter.com/thatbunty' ); - await page.waitForSelector( + await canvas().waitForSelector( 'input[value="https://twitter.com/thatbunty"]' ); @@ -204,18 +204,18 @@ describe( 'Embedding content', () => { await insertEmbed( 'https://wordpress.org/gutenberg/handbook/block-api/attributes/' ); - await page.waitForSelector( 'figure.wp-block-embed' ); + await canvas().waitForSelector( 'figure.wp-block-embed' ); // Video content. Should render valid figure element, and include the // aspect ratio class. await insertEmbed( 'https://www.youtube.com/watch?v=lXMskKTw3Bc' ); - await page.waitForSelector( + await canvas().waitForSelector( 'figure.wp-block-embed.is-type-video.wp-embed-aspect-16-9' ); // Photo content. Should render valid figure element. await insertEmbed( 'https://cloudup.com/cQFlxqtY4ob' ); - await page.waitForSelector( + await canvas().waitForSelector( 'iframe[title="Embedded content from cloudup"' ); @@ -230,18 +230,21 @@ describe( 'Embedding content', () => { // has styles applied which depend on resize observer, wait for the // expected size class to settle before clicking, since otherwise a race // condition could occur on the placeholder layout vs. click intent. - await page.waitForSelector( + await canvas().waitForSelector( '.components-placeholder.is-large .components-placeholder__error' ); - await clickButton( 'Convert to link' ); + const button = await canvas().waitForXPath( + `//button[contains(text(), 'Convert to link')]` + ); + await button.click(); expect( await getEditedPostContent() ).toMatchSnapshot(); } ); it( 'should retry embeds that could not be embedded with trailing slashes, without the trailing slashes', async () => { await insertEmbed( 'https://twitter.com/notnownikki/' ); // The twitter block should appear correctly. - await page.waitForSelector( 'figure.wp-block-embed' ); + await canvas().waitForSelector( 'figure.wp-block-embed' ); expect( await getEditedPostContent() ).toMatchSnapshot(); } ); @@ -253,7 +256,7 @@ describe( 'Embedding content', () => { // has styles applied which depend on resize observer, wait for the // expected size class to settle before clicking, since otherwise a race // condition could occur on the placeholder layout vs. click intent. - await page.waitForSelector( + await canvas().waitForSelector( '.components-placeholder.is-large .components-placeholder__error' ); @@ -268,8 +271,11 @@ describe( 'Embedding content', () => { ), }, ] ); - await clickButton( 'Try again' ); - await page.waitForSelector( 'figure.wp-block-embed' ); + const button = await canvas().waitForXPath( + `//button[contains(text(), 'Try again')]` + ); + await button.click(); + await canvas().waitForSelector( 'figure.wp-block-embed' ); expect( await getEditedPostContent() ).toMatchSnapshot(); } ); @@ -292,6 +298,6 @@ describe( 'Embedding content', () => { await insertEmbed( postUrl ); // Check the block has become a WordPress block. - await page.waitForSelector( 'figure.wp-block-embed' ); + await canvas().waitForSelector( 'figure.wp-block-embed' ); } ); } ); diff --git a/packages/e2e-tests/specs/editor/various/inserting-blocks.test.js b/packages/e2e-tests/specs/editor/various/inserting-blocks.test.js index 918737e2b3899..84c251d653468 100644 --- a/packages/e2e-tests/specs/editor/various/inserting-blocks.test.js +++ b/packages/e2e-tests/specs/editor/various/inserting-blocks.test.js @@ -11,6 +11,7 @@ import { searchForBlock, setBrowserViewport, pressKeyWithModifier, + canvas, } from '@wordpress/e2e-test-utils'; /** @typedef {import('puppeteer-core').ElementHandle} ElementHandle */ @@ -165,7 +166,7 @@ describe( 'Inserting blocks', () => { await page.keyboard.press( 'Enter' ); expect( - await page.waitForSelector( '[data-type="core/tag-cloud"]' ) + await canvas().waitForSelector( '[data-type="core/tag-cloud"]' ) ).not.toBeNull(); } ); @@ -175,7 +176,7 @@ describe( 'Inserting blocks', () => { await page.keyboard.type( '1.1' ); // After inserting the Buttons block the inner button block should be selected. - const selectedButtonBlocks = await page.$$( + const selectedButtonBlocks = await canvas().$$( '.wp-block-button.is-selected' ); expect( selectedButtonBlocks.length ).toBe( 1 ); @@ -185,7 +186,7 @@ describe( 'Inserting blocks', () => { window.wp.data.dispatch( 'core/block-editor' ).clearSelectedBlock() ); // Specifically click the root container appender. - await page.click( + await canvas().click( '.block-editor-block-list__layout.is-root-container > .block-list-appender .block-editor-inserter__toggle' ); @@ -222,7 +223,7 @@ describe( 'Inserting blocks', () => { expect( await getEditedPostContent() ).toMatchSnapshot(); // Using the between inserter. - const insertionPoint = await page.$( '[data-type="core/heading"]' ); + const insertionPoint = await canvas().$( '[data-type="core/heading"]' ); const rect = await insertionPoint.boundingBox(); await page.mouse.move( rect.x + rect.width / 2, rect.y - 10, { steps: 10, @@ -247,7 +248,7 @@ describe( 'Inserting blocks', () => { await insertBlock( 'Paragraph' ); await page.keyboard.type( 'First paragraph' ); await insertBlock( 'Image' ); - const paragraphBlock = await page.$( + const paragraphBlock = await canvas().$( 'p[aria-label="Paragraph block"]' ); paragraphBlock.click(); @@ -278,14 +279,16 @@ describe( 'Inserting blocks', () => { it( 'inserts a block in proper place after having clicked `Browse All` from block appender', async () => { await insertBlock( 'Group' ); // Select the default, selected Group layout from the variation picker. - await page.click( + await canvas().click( 'button[aria-label="Group: Gather blocks in a container."]' ); await insertBlock( 'Paragraph' ); await page.keyboard.type( 'Paragraph after group' ); // Click the Group first to make the appender inside it clickable. - await page.click( '[data-type="core/group"]' ); - await page.click( '[data-type="core/group"] [aria-label="Add block"]' ); + await canvas().click( '[data-type="core/group"]' ); + await canvas().click( + '[data-type="core/group"] [aria-label="Add block"]' + ); const browseAll = await page.waitForXPath( '//button[text()="Browse all"]' ); @@ -300,14 +303,16 @@ describe( 'Inserting blocks', () => { '.block-editor-inserter__search input,.block-editor-inserter__search-input,input.block-editor-inserter__search'; await insertBlock( 'Group' ); // Select the default, selected Group layout from the variation picker. - await page.click( + await canvas().click( 'button[aria-label="Group: Gather blocks in a container."]' ); await insertBlock( 'Paragraph' ); await page.keyboard.type( 'Text' ); // Click the Group first to make the appender inside it clickable. - await page.click( '[data-type="core/group"]' ); - await page.click( '[data-type="core/group"] [aria-label="Add block"]' ); + await canvas().click( '[data-type="core/group"]' ); + await canvas().click( + '[data-type="core/group"] [aria-label="Add block"]' + ); await page.waitForSelector( INSERTER_SEARCH_SELECTOR ); await page.focus( INSERTER_SEARCH_SELECTOR ); await pressKeyWithModifier( 'primary', 'a' ); @@ -337,7 +342,7 @@ describe( 'Inserting blocks', () => { expect( inserterPanels.length ).toBe( 0 ); // The editable 'Read More' text should be focused. - const isFocusInBlock = await page.evaluate( () => + const isFocusInBlock = await canvas().evaluate( () => document .querySelector( '[data-type="core/more"]' ) .contains( document.activeElement ) @@ -366,14 +371,14 @@ describe( 'Inserting blocks', () => { async ( viewport ) => { await setBrowserViewport( viewport ); - await page.type( + await canvas().type( '.block-editor-default-block-appender__content', 'Testing inserted block focus' ); await insertBlock( 'Image' ); - await page.waitForSelector( 'figure[data-type="core/image"]' ); + await canvas().waitForSelector( 'figure[data-type="core/image"]' ); const selectedBlock = await page.evaluate( () => { return wp.data.select( 'core/block-editor' ).getSelectedBlock(); diff --git a/packages/e2e-tests/specs/editor/various/invalid-block.test.js b/packages/e2e-tests/specs/editor/various/invalid-block.test.js index 2f24db5e067b7..354c370434be9 100644 --- a/packages/e2e-tests/specs/editor/various/invalid-block.test.js +++ b/packages/e2e-tests/specs/editor/various/invalid-block.test.js @@ -7,6 +7,7 @@ import { clickBlockAppender, clickBlockToolbarButton, setPostContent, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'invalid blocks', () => { @@ -25,7 +26,7 @@ describe( 'invalid blocks', () => { await clickMenuItem( 'Edit as HTML' ); // Focus on the textarea and enter an invalid paragraph - await page.click( + await canvas().click( '.block-editor-block-list__layout .block-editor-block-list__block .block-editor-block-list__block-html-textarea' ); await page.keyboard.type( '

invalid paragraph' ); @@ -34,7 +35,7 @@ describe( 'invalid blocks', () => { await page.click( '.editor-post-save-draft' ); // Click on the 'three-dots' menu toggle. - await page.click( + await canvas().click( '.block-editor-warning__actions button[aria-label="More options"]' ); diff --git a/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js b/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js index b19c4cb93f3e7..b3dccdf8bf20a 100644 --- a/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js +++ b/packages/e2e-tests/specs/editor/various/keyboard-navigable-blocks.test.js @@ -8,13 +8,16 @@ import { clickBlockAppender, getEditedPostContent, showBlockToolbar, + canvas, } from '@wordpress/e2e-test-utils'; async function getActiveLabel() { return await page.evaluate( () => { + const { activeElement } = + document.activeElement.contentDocument ?? document; return ( - document.activeElement.getAttribute( 'aria-label' ) || - document.activeElement.innerHTML + activeElement.getAttribute( 'aria-label' ) || + activeElement.innerHTML ); } ); } @@ -34,7 +37,11 @@ const tabThroughParagraphBlock = async ( paragraphText ) => { await page.keyboard.press( 'Tab' ); await expect( await getActiveLabel() ).toBe( 'Paragraph block' ); await expect( - await page.evaluate( () => document.activeElement.innerHTML ) + await page.evaluate( () => { + const { activeElement } = + document.activeElement.contentDocument ?? document; + return activeElement.innerHTML; + } ) ).toBe( paragraphText ); await page.keyboard.press( 'Tab' ); @@ -113,16 +120,12 @@ describe( 'Order of block keyboard navigation', () => { } // Clear the selected block. - const paragraph = await page.$( '[data-type="core/paragraph"]' ); + const paragraph = await canvas().$( '[data-type="core/paragraph"]' ); const box = await paragraph.boundingBox(); await page.mouse.click( box.x - 1, box.y ); await page.keyboard.press( 'Tab' ); - await expect( - await page.evaluate( () => { - return document.activeElement.getAttribute( 'aria-label' ); - } ) - ).toBe( 'Add title' ); + await expect( await getActiveLabel() ).toBe( 'Add title' ); await page.keyboard.press( 'Tab' ); await expect( await getActiveLabel() ).toBe( @@ -148,7 +151,7 @@ describe( 'Order of block keyboard navigation', () => { } // Clear the selected block. - const paragraph = await page.$( '[data-type="core/paragraph"]' ); + const paragraph = await canvas().$( '[data-type="core/paragraph"]' ); const box = await paragraph.boundingBox(); await page.mouse.click( box.x - 1, box.y ); @@ -176,11 +179,7 @@ describe( 'Order of block keyboard navigation', () => { ); await pressKeyWithModifier( 'shift', 'Tab' ); - await expect( - await page.evaluate( () => { - return document.activeElement.getAttribute( 'aria-label' ); - } ) - ).toBe( 'Add title' ); + await expect( await getActiveLabel() ).toBe( 'Add title' ); } ); it( 'should navigate correctly with multi selection', async () => { @@ -217,7 +216,7 @@ describe( 'Order of block keyboard navigation', () => { await insertBlock( 'Image' ); // Make sure the upload button has focus. - const uploadButton = await page.waitForXPath( + const uploadButton = await canvas().waitForXPath( '//button[contains( text(), "Upload" ) ]' ); await expect( uploadButton ).toHaveFocus(); @@ -231,7 +230,7 @@ describe( 'Order of block keyboard navigation', () => { // Insert a group block. await insertBlock( 'Group' ); // Select the default, selected Group layout from the variation picker. - await page.click( + await canvas().click( 'button[aria-label="Group: Gather blocks in a container."]' ); // If active label matches, that means focus did not change from group block wrapper. diff --git a/packages/e2e-tests/specs/editor/various/links.test.js b/packages/e2e-tests/specs/editor/various/links.test.js index fdcb7c5f793ad..33d3a08732ccf 100644 --- a/packages/e2e-tests/specs/editor/various/links.test.js +++ b/packages/e2e-tests/specs/editor/various/links.test.js @@ -9,6 +9,7 @@ import { pressKeyWithModifier, showBlockToolbar, pressKeyTimes, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Links', () => { @@ -57,7 +58,7 @@ describe( 'Links', () => { await page.keyboard.press( 'Enter' ); - const actualText = await page.evaluate( + const actualText = await canvas().evaluate( () => document.querySelector( '.block-editor-rich-text__editable a' ) .textContent @@ -172,7 +173,7 @@ describe( 'Links', () => { await page.keyboard.type( 'https://wordpress.org/gutenberg' ); // Click somewhere else - it doesn't really matter where. - await page.click( '.editor-post-title' ); + await canvas().click( '.editor-post-title' ); } ); const createAndReselectLink = async () => { @@ -311,7 +312,7 @@ describe( 'Links', () => { const createPostWithTitle = async ( titleText ) => { await createNewPost(); - await page.type( '.editor-post-title__input', titleText ); + await canvas().type( '.editor-post-title__input', titleText ); await page.click( '.editor-post-publish-panel__toggle' ); // Disable reason: Wait for the animation to complete, since otherwise the @@ -630,7 +631,7 @@ describe( 'Links', () => { await page.keyboard.press( 'Enter' ); // Check the created link reflects the link text. - const actualLinkText = await page.evaluate( + const actualLinkText = await canvas().evaluate( () => document.querySelector( '.block-editor-rich-text__editable a' @@ -880,7 +881,7 @@ describe( 'Links', () => { await page.keyboard.press( 'Enter' ); - const richTextText = await page.evaluate( + const richTextText = await canvas().evaluate( () => document.querySelector( '.block-editor-rich-text__editable' @@ -889,7 +890,7 @@ describe( 'Links', () => { // Check that the correct (i.e. last) instance of "a" was replaced with "z". expect( richTextText ).toBe( 'a b c z' ); - const richTextLink = await page.evaluate( + const richTextLink = await canvas().evaluate( () => document.querySelector( '.block-editor-rich-text__editable a' diff --git a/packages/e2e-tests/specs/editor/various/navigable-toolbar.test.js b/packages/e2e-tests/specs/editor/various/navigable-toolbar.test.js index 8fb2edf4f6768..c2735f8fbf75c 100644 --- a/packages/e2e-tests/specs/editor/various/navigable-toolbar.test.js +++ b/packages/e2e-tests/specs/editor/various/navigable-toolbar.test.js @@ -20,9 +20,10 @@ describe( 'Block Toolbar', () => { it( 'should not scroll page', async () => { while ( await page.evaluate( () => { - const scrollable = wp.dom.getScrollContainer( - document.activeElement - ); + const { activeElement } = + document.activeElement?.contentDocument ?? document; + const scrollable = + wp.dom.getScrollContainer( activeElement ); return ! scrollable || scrollable.scrollTop === 0; } ) ) { @@ -31,21 +32,20 @@ describe( 'Block Toolbar', () => { await page.keyboard.type( 'a' ); - const scrollTopBefore = await page.evaluate( - () => - wp.dom.getScrollContainer( document.activeElement ) - .scrollTop - ); + const scrollTopBefore = await page.evaluate( () => { + const { activeElement } = + document.activeElement?.contentDocument ?? document; + window.scrollContainer = + wp.dom.getScrollContainer( activeElement ); + return window.scrollContainer.scrollTop; + } ); await pressKeyWithModifier( 'alt', 'F10' ); expect( await isInBlockToolbar() ).toBe( true ); - const scrollTopAfter = await page.evaluate( - () => - wp.dom.getScrollContainer( document.activeElement ) - .scrollTop - ); - + const scrollTopAfter = await page.evaluate( () => { + return window.scrollContainer.scrollTop; + } ); expect( scrollTopBefore ).toBe( scrollTopAfter ); } ); diff --git a/packages/e2e-tests/specs/editor/various/nux.test.js b/packages/e2e-tests/specs/editor/various/nux.test.js index 1edc92e9e8575..8ea151686d2eb 100644 --- a/packages/e2e-tests/specs/editor/various/nux.test.js +++ b/packages/e2e-tests/specs/editor/various/nux.test.js @@ -1,7 +1,11 @@ /** * WordPress dependencies */ -import { createNewPost, clickOnMoreMenuItem } from '@wordpress/e2e-test-utils'; +import { + createNewPost, + clickOnMoreMenuItem, + canvas, +} from '@wordpress/e2e-test-utils'; describe( 'New User Experience (NUX)', () => { it( 'should show the guide to first-time users', async () => { @@ -128,7 +132,7 @@ describe( 'New User Experience (NUX)', () => { await page.click( '[role="dialog"] button[aria-label="Close"]' ); // Focus should be in post title field. - const postTitle = await page.waitForSelector( + const postTitle = await canvas().waitForSelector( 'h1[aria-label="Add title"' ); await expect( postTitle ).toHaveFocus(); diff --git a/packages/e2e-tests/specs/editor/various/publish-button.test.js b/packages/e2e-tests/specs/editor/various/publish-button.test.js index 2db6608331cb3..b6461ef11bc5b 100644 --- a/packages/e2e-tests/specs/editor/various/publish-button.test.js +++ b/packages/e2e-tests/specs/editor/various/publish-button.test.js @@ -6,6 +6,7 @@ import { disablePrePublishChecks, enablePrePublishChecks, createNewPost, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'PostPublishButton', () => { @@ -32,7 +33,7 @@ describe( 'PostPublishButton', () => { } ); it( 'should be disabled when post is being saved', async () => { - await page.type( '.editor-post-title__input', 'E2E Test Post' ); // Make it saveable. + await canvas().type( '.editor-post-title__input', 'E2E Test Post' ); // Make it saveable. expect( await page.$( '.editor-post-publish-button[aria-disabled="true"]' ) ).toBeNull(); @@ -44,7 +45,7 @@ describe( 'PostPublishButton', () => { } ); it( 'should be disabled when metabox is being saved', async () => { - await page.type( '.editor-post-title__input', 'E2E Test Post' ); // Make it saveable. + await canvas().type( '.editor-post-title__input', 'E2E Test Post' ); // Make it saveable. expect( await page.$( '.editor-post-publish-button[aria-disabled="true"]' ) ).toBeNull(); diff --git a/packages/e2e-tests/specs/editor/various/publish-panel.test.js b/packages/e2e-tests/specs/editor/various/publish-panel.test.js index 3a6aefd8f6687..333f2f1c2a8b3 100644 --- a/packages/e2e-tests/specs/editor/various/publish-panel.test.js +++ b/packages/e2e-tests/specs/editor/various/publish-panel.test.js @@ -9,6 +9,7 @@ import { openPublishPanel, pressKeyWithModifier, publishPost, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'PostPublishPanel', () => { @@ -28,7 +29,7 @@ describe( 'PostPublishPanel', () => { } ); it( 'PrePublish: publish button should have the focus', async () => { - await page.type( '.editor-post-title__input', 'E2E Test Post' ); + await canvas().type( '.editor-post-title__input', 'E2E Test Post' ); await openPublishPanel(); const focusedElementClassList = await page.$eval( @@ -44,7 +45,7 @@ describe( 'PostPublishPanel', () => { it( 'PostPublish: post link should have the focus', async () => { const postTitle = 'E2E Test Post'; - await page.type( '.editor-post-title__input', postTitle ); + await canvas().type( '.editor-post-title__input', postTitle ); await publishPost(); const focusedElementTag = await page.$eval( @@ -64,7 +65,7 @@ describe( 'PostPublishPanel', () => { } ); it( 'should retain focus within the panel', async () => { - await page.type( '.editor-post-title__input', 'E2E Test Post' ); + await canvas().type( '.editor-post-title__input', 'E2E Test Post' ); await openPublishPanel(); await pressKeyWithModifier( 'shift', 'Tab' ); diff --git a/packages/e2e-tests/specs/editor/various/publishing.test.js b/packages/e2e-tests/specs/editor/various/publishing.test.js index 88c0d2b993db3..fbac8cf98638b 100644 --- a/packages/e2e-tests/specs/editor/various/publishing.test.js +++ b/packages/e2e-tests/specs/editor/various/publishing.test.js @@ -11,6 +11,7 @@ import { setBrowserViewport, openPublishPanel, pressKeyWithModifier, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'Publishing', () => { @@ -22,7 +23,7 @@ describe( 'Publishing', () => { } ); it( `disables the publish button when a ${ postType } is locked`, async () => { - await page.type( + await canvas().type( '.editor-post-title__input', 'E2E Test Post lock check publish button' ); @@ -42,7 +43,7 @@ describe( 'Publishing', () => { } ); it( `disables the save shortcut when a ${ postType } is locked`, async () => { - await page.type( + await canvas().type( '.editor-post-title__input', 'E2E Test Post check save shortcut' ); @@ -79,7 +80,7 @@ describe( 'Publishing', () => { } ); it( `should publish the ${ postType } and close the panel once we start editing again.`, async () => { - await page.type( '.editor-post-title__input', 'E2E Test Post' ); + await canvas().type( '.editor-post-title__input', 'E2E Test Post' ); await publishPost(); @@ -89,7 +90,7 @@ describe( 'Publishing', () => { ).not.toBeNull(); // Start editing again. - await page.type( '.editor-post-title__input', ' (Updated)' ); + await canvas().type( '.editor-post-title__input', ' (Updated)' ); // The post-publishing panel is not visible anymore. expect( await page.$( '.editor-post-publish-panel' ) ).toBeNull(); @@ -117,7 +118,10 @@ describe( 'Publishing', () => { } ); it( `should publish the ${ postType } without opening the post-publish sidebar.`, async () => { - await page.type( '.editor-post-title__input', 'E2E Test Post' ); + await canvas().type( + '.editor-post-title__input', + 'E2E Test Post' + ); // The "Publish" button should be shown instead of the "Publish..." toggle. expect( diff --git a/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js b/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js index a94cb1f721426..3215e4185c08f 100644 --- a/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js +++ b/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js @@ -16,6 +16,7 @@ import { saveDraft, createReusableBlock, publishPost, + canvas, } from '@wordpress/e2e-test-utils'; const reusableBlockNameInputSelector = @@ -83,7 +84,7 @@ describe( 'Reusable blocks', () => { await page.keyboard.type( 'Surprised greeting block' ); // Quickly focus the paragraph block. - await page.click( + await canvas().click( '.block-editor-block-list__block[data-type="core/block"] p' ); await page.keyboard.press( 'Escape' ); // Enter navigation mode. @@ -96,7 +97,7 @@ describe( 'Reusable blocks', () => { await saveAllButDontPublish(); // Check that its content is up to date. - const text = await page.$eval( + const text = await canvas().$eval( '.block-editor-block-list__block[data-type="core/block"] p', ( element ) => element.innerText ); @@ -111,13 +112,13 @@ describe( 'Reusable blocks', () => { await clickBlockToolbarButton( 'Convert to regular block' ); // Check that we have a paragraph block on the page. - const paragraphBlock = await page.$( + const paragraphBlock = await canvas().$( '.block-editor-block-list__block[data-type="core/paragraph"]' ); expect( paragraphBlock ).not.toBeNull(); // Check that its content is up to date. - const paragraphContent = await page.$eval( + const paragraphContent = await canvas().$eval( '.block-editor-block-list__block[data-type="core/paragraph"]', ( element ) => element.innerText ); @@ -132,7 +133,7 @@ describe( 'Reusable blocks', () => { ); // Make sure the reusable block has loaded properly before attempting to publish the post. - await page.waitForSelector( 'p[aria-label="Paragraph block"]' ); + await canvas().waitForSelector( 'p[aria-label="Paragraph block"]' ); await publishPost(); @@ -142,8 +143,8 @@ describe( 'Reusable blocks', () => { await page.waitForSelector( closePublishPanelSelector ); await page.click( closePublishPanelSelector ); - await page.waitForSelector( 'p[aria-label="Paragraph block"]' ); - await page.focus( 'p[aria-label="Paragraph block"]' ); + await canvas().waitForSelector( 'p[aria-label="Paragraph block"]' ); + await canvas().focus( 'p[aria-label="Paragraph block"]' ); // Change the block's content. await page.keyboard.type( 'Einen ' ); @@ -152,7 +153,7 @@ describe( 'Reusable blocks', () => { await saveAll(); // Check that its content is up to date. - const paragraphContent = await page.$eval( + const paragraphContent = await canvas().$eval( 'p[aria-label="Paragraph block"]', ( element ) => element.innerText ); @@ -235,11 +236,12 @@ describe( 'Reusable blocks', () => { await editButton.click(); await page.waitForNavigation(); + await page.waitForSelector( 'iframe[name="editor-canvas"]' ); // Click the block to give it focus. const blockSelector = 'p[data-title="Paragraph"]'; - await page.waitForSelector( blockSelector ); - await page.click( blockSelector ); + await canvas().waitForSelector( blockSelector ); + await canvas().click( blockSelector ); // Delete the block, leaving the reusable block empty. await clickBlockToolbarButton( 'Options' ); @@ -277,7 +279,7 @@ describe( 'Reusable blocks', () => { ] ); } ); - await page.waitForXPath( + await canvas().waitForXPath( '//*[contains(@class, "block-editor-warning")]/*[text()="Block has been deleted or is unavailable."]' ); @@ -295,15 +297,16 @@ describe( 'Reusable blocks', () => { await insertReusableBlock( 'Duplicated reusable block' ); await saveDraft(); await page.reload(); + await page.waitForSelector( 'iframe[name="editor-canvas"]' ); // Wait for the paragraph to be loaded. - await page.waitForSelector( + await canvas().waitForSelector( '.block-editor-block-list__block[data-type="core/paragraph"]' ); // The first click selects the reusable block wrapper. // The second click selects the actual paragraph block. - await page.click( '.wp-block-block' ); - await page.focus( + await canvas().click( '.wp-block-block' ); + await canvas().focus( '.block-editor-block-list__block[data-type="core/paragraph"]' ); await pressKeyWithModifier( 'primary', 'a' ); @@ -333,8 +336,8 @@ describe( 'Reusable blocks', () => { // Make an edit to the reusable block and assert that there's only a // paragraph in a reusable block. - await page.waitForSelector( 'p[aria-label="Paragraph block"]' ); - await page.click( 'p[aria-label="Paragraph block"]' ); + await canvas().waitForSelector( 'p[aria-label="Paragraph block"]' ); + await canvas().click( 'p[aria-label="Paragraph block"]' ); await page.keyboard.type( '2' ); const selector = '//div[@aria-label="Block: Reusable block"]//p[@aria-label="Paragraph block"][.="12"]'; @@ -358,9 +361,10 @@ describe( 'Reusable blocks', () => { insertBlock( 'Quote' ); await saveDraft(); await page.reload(); + await page.waitForSelector( 'iframe[name="editor-canvas"]' ); // The quote block should have a visible preview in the sidebar for this test to be valid. - const quoteBlock = await page.waitForSelector( + const quoteBlock = await canvas().waitForSelector( '.block-editor-block-list__block[aria-label="Block: Quote"]' ); // Select the quote block. @@ -379,7 +383,7 @@ describe( 'Reusable blocks', () => { await nameInput.click(); await page.keyboard.type( 'Block with styles' ); await page.keyboard.press( 'Enter' ); - const reusableBlock = await page.waitForSelector( + const reusableBlock = await canvas().waitForSelector( '.block-editor-block-list__block[aria-label="Block: Reusable block"]' ); expect( reusableBlock ).toBeTruthy(); diff --git a/packages/e2e-tests/specs/editor/various/rich-text.test.js b/packages/e2e-tests/specs/editor/various/rich-text.test.js index ca7eac55471b1..c2098098d9cc7 100644 --- a/packages/e2e-tests/specs/editor/various/rich-text.test.js +++ b/packages/e2e-tests/specs/editor/various/rich-text.test.js @@ -9,6 +9,7 @@ import { pressKeyWithModifier, showBlockToolbar, clickBlockToolbarButton, + canvas, } from '@wordpress/e2e-test-utils'; describe( 'RichText', () => { @@ -74,7 +75,7 @@ describe( 'RichText', () => { await pressKeyWithModifier( 'shift', 'ArrowLeft' ); await pressKeyWithModifier( 'primary', 'b' ); - const count = await page.evaluate( + const count = await canvas().evaluate( () => document.querySelectorAll( '*[data-rich-text-format-boundary]' ) .length @@ -173,7 +174,7 @@ describe( 'RichText', () => { await pressKeyWithModifier( 'primary', 'b' ); await page.keyboard.type( '3' ); - await page.evaluate( () => { + await canvas().evaluate( () => { let called; const { body } = document; const config = { @@ -233,7 +234,7 @@ describe( 'RichText', () => { await page.keyboard.type( '4' ); - await page.evaluate( () => { + await canvas().evaluate( () => { // The selection change event should be called once. If there's only // one item in `window.unsubscribes`, it means that only one // function is present to disconnect the `mutationObserver`. @@ -274,7 +275,7 @@ describe( 'RichText', () => { await page.keyboard.press( 'Enter' ); // Wait for rich text editor to load. - await page.waitForSelector( '.block-editor-rich-text__editable' ); + await canvas().waitForSelector( '.block-editor-rich-text__editable' ); await pressKeyWithModifier( 'primary', 'b' ); await page.keyboard.type( '12' ); @@ -305,7 +306,7 @@ describe( 'RichText', () => { await page.keyboard.type( '1' ); // Simulate moving focus to a different app, then moving focus back, // without selection being changed. - await page.evaluate( () => { + await canvas().evaluate( () => { const activeElement = document.activeElement; activeElement.blur(); activeElement.focus(); @@ -515,7 +516,7 @@ describe( 'RichText', () => { // text in the DOM directly, setting selection in the right place, and // firing `compositionend`. // See https://github.com/puppeteer/puppeteer/issues/4981. - await page.evaluate( async () => { + await canvas().evaluate( async () => { document.activeElement.textContent = '`a`'; const selection = window.getSelection(); // The `selectionchange` and `compositionend` events should run in separate event diff --git a/packages/e2e-tests/specs/editor/various/sidebar-permalink.test.js b/packages/e2e-tests/specs/editor/various/sidebar-permalink.test.js index a89ac0469f27a..e23bd830cee4f 100644 --- a/packages/e2e-tests/specs/editor/various/sidebar-permalink.test.js +++ b/packages/e2e-tests/specs/editor/various/sidebar-permalink.test.js @@ -6,6 +6,7 @@ import { createNewPost, deactivatePlugin, publishPost, + canvas, } from '@wordpress/e2e-test-utils'; const urlButtonSelector = '*[aria-label^="Change URL"]'; @@ -28,7 +29,7 @@ describe( 'Sidebar Permalink', () => { await page.keyboard.type( 'aaaaa' ); await publishPost(); // Start editing again. - await page.type( '.editor-post-title__input', ' (Updated)' ); + await canvas().type( '.editor-post-title__input', ' (Updated)' ); expect( await page.$( urlButtonSelector ) ).toBeNull(); } ); @@ -37,7 +38,7 @@ describe( 'Sidebar Permalink', () => { await page.keyboard.type( 'aaaaa' ); await publishPost(); // Start editing again. - await page.type( '.editor-post-title__input', ' (Updated)' ); + await canvas().type( '.editor-post-title__input', ' (Updated)' ); expect( await page.$( urlButtonSelector ) ).toBeNull(); } ); @@ -46,7 +47,7 @@ describe( 'Sidebar Permalink', () => { await page.keyboard.type( 'aaaaa' ); await publishPost(); // Start editing again. - await page.type( '.editor-post-title__input', ' (Updated)' ); + await canvas( 0 ).type( '.editor-post-title__input', ' (Updated)' ); expect( await page.$( urlButtonSelector ) ).not.toBeNull(); } ); } ); diff --git a/packages/e2e-tests/specs/editor/various/taxonomies.test.js b/packages/e2e-tests/specs/editor/various/taxonomies.test.js index 551187d654dd9..a1804307fe74e 100644 --- a/packages/e2e-tests/specs/editor/various/taxonomies.test.js +++ b/packages/e2e-tests/specs/editor/various/taxonomies.test.js @@ -6,6 +6,7 @@ import { findSidebarPanelWithTitle, openDocumentSettingsSidebar, publishPost, + canvas, } from '@wordpress/e2e-test-utils'; /** @@ -113,7 +114,7 @@ describe( 'Taxonomies', () => { expect( selectedCategories[ 0 ] ).toEqual( 'z rand category 1' ); // Type something in the title so we can publish the post. - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Publish the post. await publishPost(); @@ -171,7 +172,7 @@ describe( 'Taxonomies', () => { expect( tags[ 0 ] ).toEqual( tagName ); // Type something in the title so we can publish the post. - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Publish the post. await publishPost(); @@ -230,7 +231,7 @@ describe( 'Taxonomies', () => { expect( tags[ 0 ] ).toEqual( tagName ); // Type something in the title so we can publish the post. - await page.type( '.editor-post-title__input', 'Hello World' ); + await canvas().type( '.editor-post-title__input', 'Hello World' ); // Publish the post. await publishPost(); diff --git a/packages/e2e-tests/specs/editor/various/typewriter.test.js b/packages/e2e-tests/specs/editor/various/typewriter.test.js index f1eb0c7b68934..d935197b14f87 100644 --- a/packages/e2e-tests/specs/editor/various/typewriter.test.js +++ b/packages/e2e-tests/specs/editor/various/typewriter.test.js @@ -9,7 +9,12 @@ describe( 'TypeWriter', () => { } ); const getCaretPosition = async () => - await page.evaluate( () => wp.dom.computeCaretRect( window ).y ); + await page.evaluate( + () => + wp.dom.computeCaretRect( + document.activeElement?.contentWindow ?? window + ).y + ); // Allow the scroll position to be 1px off. const BUFFER = 1; @@ -33,11 +38,13 @@ describe( 'TypeWriter', () => { // Create blocks until the typewriter effect kicks in. while ( - await page.evaluate( - () => - wp.dom.getScrollContainer( document.activeElement ) - .scrollTop === 0 - ) + await page.evaluate( () => { + const { activeElement } = + document.activeElement?.contentDocument ?? document; + return ( + wp.dom.getScrollContainer( activeElement ).scrollTop === 0 + ); + } ) ) { await page.keyboard.press( 'Enter' ); } @@ -51,14 +58,14 @@ describe( 'TypeWriter', () => { // Type until the text wraps. while ( - await page.evaluate( - () => - document.activeElement.clientHeight <= - parseInt( - getComputedStyle( document.activeElement ).lineHeight, - 10 - ) - ) + await page.evaluate( () => { + const { activeElement } = + document.activeElement?.contentDocument ?? document; + return ( + activeElement.clientHeight <= + parseInt( getComputedStyle( activeElement ).lineHeight, 10 ) + ); + } ) ) { await page.keyboard.type( 'a' ); } @@ -93,32 +100,35 @@ describe( 'TypeWriter', () => { // Create zero or more blocks until there is a scrollable container. // No blocks should be created if there's already a scrollbar. while ( - await page.evaluate( - () => ! wp.dom.getScrollContainer( document.activeElement ) - ) + await page.evaluate( () => { + const { activeElement } = + document.activeElement?.contentDocument ?? document; + const scrollContainer = + wp.dom.getScrollContainer( activeElement ); + return ( + scrollContainer.scrollHeight === + scrollContainer.clientHeight + ); + } ) ) { await page.keyboard.press( 'Enter' ); } - const scrollPosition = await page.evaluate( - () => wp.dom.getScrollContainer( document.activeElement ).scrollTop - ); + const scrollPosition = await page.evaluate( () => { + const { activeElement } = + document.activeElement?.contentDocument ?? document; + return wp.dom.getScrollContainer( activeElement ).scrollTop; + } ); // Expect scrollbar to be at the top. expect( scrollPosition ).toBe( 0 ); // Move the mouse to the scroll container, and scroll down // a small amount to trigger the typewriter mode. - const mouseMovePosition = await page.evaluate( () => { - const caretRect = wp.dom.computeCaretRect( window ); - return [ Math.floor( caretRect.x ), Math.floor( caretRect.y ) ]; + await page.evaluate( () => { + const { activeElement } = + document.activeElement?.contentDocument ?? document; + wp.dom.getScrollContainer( activeElement ).scrollTop += 2; } ); - await page.mouse.move( ...mouseMovePosition ); - await page.mouse.wheel( { deltaY: 2 } ); - await page.waitForFunction( - () => - wp.dom.getScrollContainer( document.activeElement ) - .scrollTop === 2 - ); // Wait for the caret rectangle to be recalculated. await page.evaluate( () => new Promise( window.requestAnimationFrame ) @@ -128,12 +138,12 @@ describe( 'TypeWriter', () => { // coordinates should be the same. const initialPosition = await getCaretPosition(); await page.keyboard.press( 'Enter' ); - await page.waitForFunction( - () => - // Wait for the Typewriter to scroll down past the initial position. - wp.dom.getScrollContainer( document.activeElement ).scrollTop > - 2 - ); + await page.waitForFunction( () => { + const { activeElement } = + document.activeElement?.contentDocument ?? document; + // Wait for the Typewriter to scroll down past the initial position. + return wp.dom.getScrollContainer( activeElement ).scrollTop > 2; + } ); expect( await getDiff( initialPosition ) ).toBe( 0 ); } ); @@ -164,9 +174,11 @@ describe( 'TypeWriter', () => { // Create blocks until there is a scrollable container. while ( - await page.evaluate( - () => ! wp.dom.getScrollContainer( document.activeElement ) - ) + await page.evaluate( () => { + const { activeElement } = + document.activeElement?.contentDocument ?? document; + return ! wp.dom.getScrollContainer( activeElement ); + } ) ) { await page.keyboard.press( 'Enter' ); } @@ -176,11 +188,13 @@ describe( 'TypeWriter', () => { // Create blocks until the typewriter effect kicks in, create at // least 10 blocks to properly test the . while ( - ( await page.evaluate( - () => - wp.dom.getScrollContainer( document.activeElement ) - .scrollTop === 0 - ) ) || + ( await page.evaluate( () => { + const { activeElement } = + document.activeElement?.contentDocument ?? document; + return ( + wp.dom.getScrollContainer( activeElement ).scrollTop === 0 + ); + } ) ) || count < 10 ) { await page.keyboard.press( 'Enter' ); @@ -190,9 +204,11 @@ describe( 'TypeWriter', () => { // Scroll the active element to the very bottom of the scroll container, // then scroll up, so the caret is partially hidden. await page.evaluate( () => { - document.activeElement.scrollIntoView( false ); - wp.dom.getScrollContainer( document.activeElement ).scrollTop -= - document.activeElement.offsetHeight + 10; + const { activeElement } = + document.activeElement?.contentDocument ?? document; + activeElement.scrollIntoView( false ); + wp.dom.getScrollContainer( activeElement ).scrollTop -= + activeElement.offsetHeight + 10; } ); const bottomPostition = await getCaretPosition(); @@ -220,9 +236,11 @@ describe( 'TypeWriter', () => { // Scroll the active element to the very top of the scroll container, // then scroll down, so the caret is partially hidden. await page.evaluate( () => { - document.activeElement.scrollIntoView(); - wp.dom.getScrollContainer( document.activeElement ).scrollTop += - document.activeElement.offsetHeight + 10; + const { activeElement } = + document.activeElement?.contentDocument ?? document; + activeElement.scrollIntoView(); + wp.dom.getScrollContainer( activeElement ).scrollTop += + activeElement.offsetHeight + 10; } ); const topPostition = await getCaretPosition(); diff --git a/packages/e2e-tests/specs/performance/site-editor.test.js b/packages/e2e-tests/specs/performance/site-editor.test.js index 22c1af35ff716..e8f705c6dc0d7 100644 --- a/packages/e2e-tests/specs/performance/site-editor.test.js +++ b/packages/e2e-tests/specs/performance/site-editor.test.js @@ -151,7 +151,8 @@ describe( 'Site Editor Performance', () => { await enterEditMode(); // Insert a new paragraph right under the first one. - await firstParagraph.focus(); + await firstParagraph.click(); // Once to select the block overlay. + await firstParagraph.click(); // Once again to select the paragraph. await insertBlock( 'Paragraph' ); // Start tracing. diff --git a/packages/e2e-tests/specs/site-editor/settings-sidebar.test.js b/packages/e2e-tests/specs/site-editor/settings-sidebar.test.js index 88bf954e86ce2..ae28019cf0d99 100644 --- a/packages/e2e-tests/specs/site-editor/settings-sidebar.test.js +++ b/packages/e2e-tests/specs/site-editor/settings-sidebar.test.js @@ -27,11 +27,11 @@ async function getActiveTabLabel() { async function getTemplateCard() { return { title: await page.$eval( - '.edit-site-template-card__title', + '.edit-site-sidebar-card__title', ( element ) => element.innerText ), description: await page.$eval( - '.edit-site-template-card__description', + '.edit-site-sidebar-card__description', ( element ) => element.innerText ), }; diff --git a/packages/edit-post/src/components/header/document-title/index.js b/packages/edit-post/src/components/header/document-title/index.js index 1b27a0bacf014..619fa4ef29014 100644 --- a/packages/edit-post/src/components/header/document-title/index.js +++ b/packages/edit-post/src/components/header/document-title/index.js @@ -11,17 +11,14 @@ import { __experimentalText as Text, } from '@wordpress/components'; import { layout, chevronLeftSmall, chevronRightSmall } from '@wordpress/icons'; -import { privateApis as commandsPrivateApis } from '@wordpress/commands'; +import { store as commandsStore } from '@wordpress/commands'; import { displayShortcut } from '@wordpress/keycodes'; /** * Internal dependencies */ -import { unlock } from '../../../private-apis'; import { store as editPostStore } from '../../../store'; -const { store: commandsStore } = unlock( commandsPrivateApis ); - function DocumentTitle() { const { template, isEditing } = useSelect( ( select ) => { const { isEditingTemplate, getEditedPostTemplate } = diff --git a/packages/edit-post/src/components/visual-editor/index.js b/packages/edit-post/src/components/visual-editor/index.js index 638a869aa8350..0f4363070ac57 100644 --- a/packages/edit-post/src/components/visual-editor/index.js +++ b/packages/edit-post/src/components/visual-editor/index.js @@ -34,7 +34,7 @@ import { useEffect, useRef, useMemo } from '@wordpress/element'; import { __unstableMotion as motion } from '@wordpress/components'; import { useSelect } from '@wordpress/data'; import { useMergeRefs } from '@wordpress/compose'; -import { parse } from '@wordpress/blocks'; +import { parse, store as blocksStore } from '@wordpress/blocks'; import { store as coreStore } from '@wordpress/core-data'; /** @@ -112,6 +112,7 @@ export default function VisualEditor( { styles } ) { wrapperBlockName, wrapperUniqueId, isBlockBasedTheme, + hasV3BlocksOnly, } = useSelect( ( select ) => { const { isFeatureActive, @@ -121,6 +122,7 @@ export default function VisualEditor( { styles } ) { } = select( editPostStore ); const { getCurrentPostId, getCurrentPostType, getEditorSettings } = select( editorStore ); + const { getBlockTypes } = select( blocksStore ); const _isTemplateMode = isEditingTemplate(); let _wrapperBlockName; @@ -151,6 +153,9 @@ export default function VisualEditor( { styles } ) { wrapperBlockName: _wrapperBlockName, wrapperUniqueId: getCurrentPostId(), isBlockBasedTheme: editorSettings.__unstableIsBlockBasedTheme, + hasV3BlocksOnly: getBlockTypes().every( ( type ) => { + return type.apiVersion >= 3; + } ), }; }, [] ); const { isCleanNewPost } = useSelect( editorStore ); @@ -352,8 +357,8 @@ export default function VisualEditor( { styles } ) { > { - const { getSettings, getEditedPostType, getCanvasMode } = unlock( - select( editSiteStore ) - ); - - return { - storedSettings: getSettings( setIsInserterOpened ), - templateType: getEditedPostType(), - canvasMode: getCanvasMode(), - }; - }, - [ setIsInserterOpened ] - ); + const { storedSettings, templateType, canvasMode, hasPageContentLock } = + useSelect( + ( select ) => { + const { + getSettings, + getEditedPostType, + getCanvasMode, + hasPageContentLock: _hasPageContentLock, + } = unlock( select( editSiteStore ) ); + + return { + storedSettings: getSettings( setIsInserterOpened ), + templateType: getEditedPostType(), + canvasMode: getCanvasMode(), + hasPageContentLock: _hasPageContentLock(), + }; + }, + [ setIsInserterOpened ] + ); const settingsBlockPatterns = storedSettings.__experimentalAdditionalBlockPatterns ?? // WP 6.0 @@ -137,6 +146,7 @@ export default function BlockEditor() { contentRef, useClipboardHandler(), useTypingObserver(), + usePageContentLockNotifications(), ] ); const isMobileViewport = useViewportMatch( 'small', '<' ); const { clearSelectedBlock } = useDispatch( blockEditorStore ); @@ -162,6 +172,7 @@ export default function BlockEditor() { onChange={ onChange } useSubRegistry={ false } > + { hasPageContentLock && } diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 72a8d41fb22f0..f70c6abd787d4 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -37,7 +37,6 @@ import WelcomeGuide from '../welcome-guide'; import StartTemplateOptions from '../start-template-options'; import { store as editSiteStore } from '../../store'; import { GlobalStylesRenderer } from '../global-styles-renderer'; - import useTitle from '../routes/use-title'; import CanvasSpinner from '../canvas-spinner'; import { unlock } from '../../private-apis'; @@ -74,6 +73,7 @@ export default function Editor( { isLoading } ) { isListViewOpen, showIconLabels, showBlockBreadcrumbs, + hasPageContentLock, } = useSelect( ( select ) => { const { getEditedPostContext, @@ -81,6 +81,7 @@ export default function Editor( { isLoading } ) { getCanvasMode, isInserterOpened, isListViewOpened, + hasPageContentLock: _hasPageContentLock, } = unlock( select( editSiteStore ) ); const { __unstableGetEditorMode } = select( blockEditorStore ); const { getActiveComplementaryArea } = select( interfaceStore ); @@ -105,6 +106,7 @@ export default function Editor( { isLoading } ) { 'core/edit-site', 'showBlockBreadcrumbs' ), + hasPageContentLock: _hasPageContentLock(), }; }, [] ); const { setEditedPostContext } = useDispatch( editSiteStore ); @@ -122,9 +124,10 @@ export default function Editor( { isLoading } ) { const secondarySidebarLabel = isListViewOpen ? __( 'List View' ) : __( 'Block Library' ); - const blockContext = useMemo( - () => ( { - ...context, + const blockContext = useMemo( () => { + const { postType, postId, ...nonPostFields } = context ?? {}; + return { + ...( hasPageContentLock ? context : nonPostFields ), queryContext: [ context?.queryContext || { page: 1 }, ( newQueryContext ) => @@ -136,9 +139,8 @@ export default function Editor( { isLoading } ) { }, } ), ], - } ), - [ context, setEditedPostContext ] - ); + }; + }, [ hasPageContentLock, context, setEditedPostContext ] ); let title; if ( hasLoadedPost ) { @@ -227,7 +229,11 @@ export default function Editor( { isLoading } ) { footer={ shouldShowBlockBreakcrumbs && ( ) } diff --git a/packages/edit-site/src/components/header-edit-mode/document-actions/index.js b/packages/edit-site/src/components/header-edit-mode/document-actions/index.js index 94f8358fda993..5f14445ccefcd 100644 --- a/packages/edit-site/src/components/header-edit-mode/document-actions/index.js +++ b/packages/edit-site/src/components/header-edit-mode/document-actions/index.js @@ -1,8 +1,13 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ import { sprintf, __ } from '@wordpress/i18n'; -import { useDispatch } from '@wordpress/data'; +import { useSelect, useDispatch } from '@wordpress/data'; import { Button, VisuallyHidden, @@ -10,27 +15,72 @@ import { __experimentalHStack as HStack, } from '@wordpress/components'; import { BlockIcon } from '@wordpress/block-editor'; -import { privateApis as commandsPrivateApis } from '@wordpress/commands'; +import { store as commandsStore } from '@wordpress/commands'; +import { + chevronLeftSmall as chevronLeftSmallIcon, + page as pageIcon, +} from '@wordpress/icons'; +import { useEntityRecord } from '@wordpress/core-data'; import { displayShortcut } from '@wordpress/keycodes'; /** * Internal dependencies */ import useEditedEntityRecord from '../../use-edited-entity-record'; -import { unlock } from '../../../private-apis'; - -const { store: commandsStore } = unlock( commandsPrivateApis ); +import { store as editSiteStore } from '../../../store'; export default function DocumentActions() { - const { open: openCommandCenter } = useDispatch( commandsStore ); + const isPage = useSelect( ( select ) => select( editSiteStore ).isPage() ); + return isPage ? : ; +} + +function PageDocumentActions() { + const { hasPageContentLock, context } = useSelect( + ( select ) => ( { + hasPageContentLock: select( editSiteStore ).hasPageContentLock(), + context: select( editSiteStore ).getEditedPostContext(), + } ), + [] + ); + + const { hasResolved, editedRecord } = useEntityRecord( + 'postType', + context.postType, + context.postId + ); + + const { setHasPageContentLock } = useDispatch( editSiteStore ); + + if ( ! hasResolved ) { + return null; + } + + if ( ! editedRecord ) { + return ( +

+ { __( 'Document not found' ) } +
+ ); + } + + return hasPageContentLock ? ( + + { editedRecord.title } + + ) : ( + setHasPageContentLock( true ) } + /> + ); +} + +function TemplateDocumentActions( { onBack } ) { const { isLoaded, record, getTitle, icon } = useEditedEntityRecord(); - // Return a simple loading indicator until we have information to show. if ( ! isLoaded ) { return null; } - // Return feedback that the template does not seem to exist. if ( ! record ) { return (
@@ -45,31 +95,58 @@ export default function DocumentActions() { : __( 'template' ); return ( - + ) } + + + + + { children } + + + + { displayShortcut.primary( 'k' ) } + + +
); } diff --git a/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss b/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss index 247b901975fd8..8bd3475de6956 100644 --- a/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss +++ b/packages/edit-site/src/components/header-edit-mode/document-actions/style.scss @@ -1,10 +1,7 @@ .edit-site-document-actions { - display: flex; - align-items: center; - gap: $grid-unit; + display: grid; + grid-template-columns: 1fr 2fr 1fr; height: $button-size; - padding: $grid-unit; - justify-content: space-between; // Flex items will, by default, refuse to shrink below a minimum // intrinsic width. In order to shrink this flexbox item, and // subsequently truncate child text, we set an explicit min-width. @@ -20,29 +17,46 @@ } } +.edit-site-document-actions__command { + grid-column: 1 / -1; + display: grid; + grid-template-columns: 1fr 2fr 1fr; + grid-row: 1; +} + + .edit-site-document-actions__title { flex-grow: 1; color: var(--wp-block-synced-color); overflow: hidden; + grid-column: 2 / 3; + &.is-page { + color: $gray-800; + h1 { + color: $gray-800; + } + } h1 { - color: var(--wp-block-synced-color); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + color: var(--wp-block-synced-color); } } .edit-site-document-actions__shortcut { - flex-shrink: 0; color: $gray-700; - width: #{$grid-unit * 4.5}; + text-align: right; &:hover { color: $gray-700; } } -.edit-site-document-actions__left { +.edit-site-document-actions__back { min-width: $button-size; flex-shrink: 0; + grid-column: 1 / 2; + grid-row: 1; + z-index: 1; } diff --git a/packages/edit-site/src/components/page-content-lock/constants.js b/packages/edit-site/src/components/page-content-lock/constants.js new file mode 100644 index 0000000000000..668fe8af00d69 --- /dev/null +++ b/packages/edit-site/src/components/page-content-lock/constants.js @@ -0,0 +1,5 @@ +export const CONTENT_BLOCK_TYPES = [ + 'core/post-title', + 'core/post-featured-image', + 'core/post-content', +]; diff --git a/packages/edit-site/src/components/page-content-lock/index.js b/packages/edit-site/src/components/page-content-lock/index.js new file mode 100644 index 0000000000000..83d096fb39f5d --- /dev/null +++ b/packages/edit-site/src/components/page-content-lock/index.js @@ -0,0 +1,14 @@ +/** + * Internal dependencies + */ +import { useDisableNonContentBlocks } from './use-disable-non-content-blocks'; + +/** + * Component that when rendered, locks the site editor so that only page content + * can be edited. + */ +export function PageContentLock() { + useDisableNonContentBlocks(); +} + +export { usePageContentLockNotifications } from './use-page-content-lock-notifications'; diff --git a/packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js b/packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js new file mode 100644 index 0000000000000..ce198909877f6 --- /dev/null +++ b/packages/edit-site/src/components/page-content-lock/use-disable-non-content-blocks.js @@ -0,0 +1,44 @@ +/** + * WordPress dependencies + */ +import { createHigherOrderComponent } from '@wordpress/compose'; +import { addFilter, removeFilter } from '@wordpress/hooks'; +import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor'; +import { useEffect } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { unlock } from '../../private-apis'; +import { CONTENT_BLOCK_TYPES } from './constants'; + +const { useBlockEditingMode } = unlock( blockEditorPrivateApis ); + +/** + * Disables non-content blocks using the `useBlockEditingMode` hook. + */ +export function useDisableNonContentBlocks() { + useBlockEditingMode( 'disabled' ); + useEffect( () => { + addFilter( + 'editor.BlockEdit', + 'core/edit-site/disable-non-content-blocks', + withDisableNonContentBlocks + ); + return () => + removeFilter( + 'editor.BlockEdit', + 'core/edit-site/disable-non-content-blocks' + ); + }, [] ); +} + +const withDisableNonContentBlocks = createHigherOrderComponent( + ( BlockEdit ) => ( props ) => { + const isContent = CONTENT_BLOCK_TYPES.includes( props.name ); + const mode = isContent ? 'contentOnly' : undefined; + useBlockEditingMode( mode ); + return ; + }, + 'withBlockEditingMode' +); diff --git a/packages/edit-site/src/components/page-content-lock/use-page-content-lock-notifications.js b/packages/edit-site/src/components/page-content-lock/use-page-content-lock-notifications.js new file mode 100644 index 0000000000000..2a800317a33a9 --- /dev/null +++ b/packages/edit-site/src/components/page-content-lock/use-page-content-lock-notifications.js @@ -0,0 +1,128 @@ +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { useEffect, useRef } from '@wordpress/element'; +import { store as noticesStore } from '@wordpress/notices'; +import { __ } from '@wordpress/i18n'; +import { useRefEffect } from '@wordpress/compose'; + +/** + * Internal dependencies + */ +import { store as editSiteStore } from '../../store'; + +/** + * Hook that displays notifications that guide the user towards using the + * content vs. template editing modes. + * + * @return {import('react').RefObject} Ref which should be passed + * (using useMergeRefs()) to + * the editor iframe canvas. + */ +export function usePageContentLockNotifications() { + const ref = useEditTemplateNotification(); + useBackToPageNotification(); + return ref; +} + +/** + * Hook that displays a 'Edit your template to edit this block' notification + * when the user is focusing on editing page content and clicks on a locked + * template block. + * + * @return {import('react').RefObject} Ref which should be passed + * (using useMergeRefs()) to + * the editor iframe canvas. + */ +function useEditTemplateNotification() { + const hasPageContentLock = useSelect( + ( select ) => select( editSiteStore ).hasPageContentLock(), + [] + ); + + const alreadySeen = useRef( false ); + + const { createInfoNotice } = useDispatch( noticesStore ); + const { setHasPageContentLock } = useDispatch( editSiteStore ); + + return useRefEffect( + ( node ) => { + const handleClick = ( event ) => { + if ( + ! alreadySeen.current && + hasPageContentLock && + event.target.classList.contains( 'is-root-container' ) + ) { + createInfoNotice( + __( 'Edit your template to edit this block' ), + { + isDismissible: true, + type: 'snackbar', + actions: [ + { + label: __( 'Edit template' ), + onClick: () => + setHasPageContentLock( false ), + }, + ], + } + ); + alreadySeen.current = true; + } + }; + node.addEventListener( 'click', handleClick ); + return () => node.removeEventListener( 'click', handleClick ); + }, + [ + hasPageContentLock, + alreadySeen, + createInfoNotice, + setHasPageContentLock, + ] + ); +} + +/** + * Hook that displays a 'You are editing a template' notification when the user + * switches from focusing on editing page content to editing a template. + */ +function useBackToPageNotification() { + const hasPageContentLock = useSelect( + ( select ) => select( editSiteStore ).hasPageContentLock(), + [] + ); + + const alreadySeen = useRef( false ); + const prevHasPageContentLock = useRef( false ); + + const { createInfoNotice } = useDispatch( noticesStore ); + const { setHasPageContentLock } = useDispatch( editSiteStore ); + + useEffect( () => { + if ( + ! alreadySeen.current && + prevHasPageContentLock.current && + ! hasPageContentLock + ) { + createInfoNotice( __( 'You are editing a template' ), { + isDismissible: true, + type: 'snackbar', + actions: [ + { + label: __( 'Back to page' ), + onClick: () => setHasPageContentLock( true ), + }, + ], + } ); + alreadySeen.current = true; + } + prevHasPageContentLock.current = hasPageContentLock; + }, [ + alreadySeen, + prevHasPageContentLock, + hasPageContentLock, + createInfoNotice, + setHasPageContentLock, + ] ); +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/index.js b/packages/edit-site/src/components/sidebar-edit-mode/index.js index 5086981f87144..78ada88a4d5fa 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/index.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { createSlotFill, PanelBody, PanelRow } from '@wordpress/components'; +import { createSlotFill } from '@wordpress/components'; import { isRTL, __ } from '@wordpress/i18n'; import { drawerLeft, drawerRight } from '@wordpress/icons'; import { useEffect } from '@wordpress/element'; @@ -16,8 +16,8 @@ import DefaultSidebar from './default-sidebar'; import GlobalStylesSidebar from './global-styles-sidebar'; import { STORE_NAME } from '../../store/constants'; import SettingsHeader from './settings-header'; -import LastRevision from './template-revisions'; -import TemplateCard from './template-card'; +import PagePanels from './page-panels'; +import TemplatePanel from './template-panel'; import PluginTemplateSettingPanel from '../plugin-template-setting-panel'; import { SIDEBAR_BLOCK, SIDEBAR_TEMPLATE } from './constants'; import { store as editSiteStore } from '../../store'; @@ -33,6 +33,7 @@ export function SidebarComplementaryAreaFills() { isEditorSidebarOpened, hasBlockSelection, supportsGlobalStyles, + hasPageContentLock, } = useSelect( ( select ) => { const _sidebar = select( interfaceStore ).getActiveComplementaryArea( STORE_NAME ); @@ -47,18 +48,23 @@ export function SidebarComplementaryAreaFills() { hasBlockSelection: !! select( blockEditorStore ).getBlockSelectionStart(), supportsGlobalStyles: ! settings?.supportsTemplatePartsMode, + hasPageContentLock: select( editSiteStore ).hasPageContentLock(), }; }, [] ); const { enableComplementaryArea } = useDispatch( interfaceStore ); useEffect( () => { - if ( ! isEditorSidebarOpened ) return; + // Don't automatically switch tab when the sidebar is closed or when we + // are focused on page content. + if ( ! isEditorSidebarOpened || hasPageContentLock ) { + return; + } if ( hasBlockSelection ) { enableComplementaryArea( STORE_NAME, SIDEBAR_BLOCK ); } else { enableComplementaryArea( STORE_NAME, SIDEBAR_TEMPLATE ); } - }, [ hasBlockSelection, isEditorSidebarOpened ] ); + }, [ hasBlockSelection, isEditorSidebarOpened, hasPageContentLock ] ); let sidebarName = sidebar; if ( ! isEditorSidebarOpened ) { @@ -77,15 +83,11 @@ export function SidebarComplementaryAreaFills() { > { sidebarName === SIDEBAR_TEMPLATE && ( <> - - - - - - + { hasPageContentLock ? ( + + ) : ( + + ) } ) } diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js new file mode 100644 index 0000000000000..9035c5677f91a --- /dev/null +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/content-blocks-list.js @@ -0,0 +1,77 @@ +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { + Button, + __experimentalVStack as VStack, + __experimentalHStack as HStack, + FlexItem, +} from '@wordpress/components'; +import { getBlockType, __experimentalGetBlockLabel } from '@wordpress/blocks'; +import { store as blockEditorStore, BlockIcon } from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import { CONTENT_BLOCK_TYPES } from '../../page-content-lock/constants'; + +// TODO: This overlaps a lot with BlockInspectorLockedBlocks in +// @wordpress/block-editor. DRY them into a single component. +export default function ContentBlocksList() { + const contentBlocks = useSelect( ( select ) => { + const { + getClientIdsWithDescendants, + getBlockName, + getBlock, + isBlockSelected, + hasSelectedInnerBlock, + } = select( blockEditorStore ); + return getClientIdsWithDescendants().flatMap( ( clientId ) => { + const blockName = getBlockName( clientId ); + if ( ! CONTENT_BLOCK_TYPES.includes( blockName ) ) { + return []; + } + return [ + { + block: getBlock( clientId ), + isSelected: + isBlockSelected( clientId ) || + hasSelectedInnerBlock( clientId, /* deep: */ true ), + }, + ]; + } ); + }, [] ); + + const { selectBlock } = useDispatch( blockEditorStore ); + + if ( ! contentBlocks.length ) { + return null; + } + + return ( + + { contentBlocks.map( ( { block, isSelected } ) => { + const blockType = getBlockType( block.name ); + return ( + + ); + } ) } + + ); +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js new file mode 100644 index 0000000000000..c913a689d54dc --- /dev/null +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/index.js @@ -0,0 +1,89 @@ +/** + * WordPress dependencies + */ +import { + PanelBody, + __experimentalVStack as VStack, + Button, +} from '@wordpress/components'; +import { page as pageIcon } from '@wordpress/icons'; +import { __, sprintf } from '@wordpress/i18n'; +import { humanTimeDiff } from '@wordpress/date'; +import { useSelect, useDispatch } from '@wordpress/data'; +import { useEntityRecord } from '@wordpress/core-data'; +import { BlockContextProvider, BlockPreview } from '@wordpress/block-editor'; +import { useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { store as editSiteStore } from '../../../store'; +import useEditedEntityRecord from '../../use-edited-entity-record'; +import SidebarCard from '../sidebar-card'; +import ContentBlocksList from './content-blocks-list'; + +export default function PagePanels() { + const context = useSelect( + ( select ) => select( editSiteStore ).getEditedPostContext(), + [] + ); + + const { hasResolved: hasPageResolved, editedRecord: page } = + useEntityRecord( 'postType', context.postType, context.postId ); + + const { + isLoaded: isTemplateLoaded, + getTitle: getTemplateTitle, + record: template, + } = useEditedEntityRecord(); + + const { setHasPageContentLock } = useDispatch( editSiteStore ); + + const blockContext = useMemo( + () => ( { ...context, postType: null, postId: null } ), + [ context ] + ); + + if ( ! hasPageResolved || ! isTemplateLoaded ) { + return null; + } + + return ( + <> + + + + + + + + +
{ getTemplateTitle() }
+
+ + + +
+ +
+
+ + ); +} 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 new file mode 100644 index 0000000000000..58178303e48e5 --- /dev/null +++ b/packages/edit-site/src/components/sidebar-edit-mode/page-panels/style.scss @@ -0,0 +1,10 @@ +.edit-site-page-panels__edit-template-preview { + border: 1px solid $gray-200; + height: 200px; + max-height: 200px; + overflow: hidden; +} + +.edit-site-page-panels__edit-template-button { + justify-content: center; +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/settings-header/index.js b/packages/edit-site/src/components/sidebar-edit-mode/settings-header/index.js index 8e5e80d9fecc5..b11d9acb2314f 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/settings-header/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/settings-header/index.js @@ -1,9 +1,14 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + /** * WordPress dependencies */ import { Button } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useDispatch } from '@wordpress/data'; +import { useSelect, useDispatch } from '@wordpress/data'; import { store as interfaceStore } from '@wordpress/interface'; /** @@ -11,27 +16,35 @@ import { store as interfaceStore } from '@wordpress/interface'; */ import { STORE_NAME } from '../../../store/constants'; import { SIDEBAR_BLOCK, SIDEBAR_TEMPLATE } from '../constants'; +import { store as editSiteStore } from '../../../store'; const SettingsHeader = ( { sidebarName } ) => { + const hasPageContentLock = useSelect( ( select ) => + select( editSiteStore ).hasPageContentLock() + ); + const { enableComplementaryArea } = useDispatch( interfaceStore ); const openTemplateSettings = () => enableComplementaryArea( STORE_NAME, SIDEBAR_TEMPLATE ); const openBlockSettings = () => enableComplementaryArea( STORE_NAME, SIDEBAR_BLOCK ); - const [ templateAriaLabel, templateActiveClass ] = - sidebarName === SIDEBAR_TEMPLATE - ? // translators: ARIA label for the Template sidebar tab, selected. - [ __( 'Template (selected)' ), 'is-active' ] - : // translators: ARIA label for the Template Settings Sidebar tab, not selected. - [ __( 'Template' ), '' ]; - - const [ blockAriaLabel, blockActiveClass ] = - sidebarName === SIDEBAR_BLOCK - ? // translators: ARIA label for the Block Settings Sidebar tab, selected. - [ __( 'Block (selected)' ), 'is-active' ] - : // translators: ARIA label for the Block Settings Sidebar tab, not selected. - [ __( 'Block' ), '' ]; + let templateAriaLabel; + if ( hasPageContentLock ) { + templateAriaLabel = + sidebarName === SIDEBAR_TEMPLATE + ? // translators: ARIA label for the Template sidebar tab, selected. + __( 'Page (selected)' ) + : // translators: ARIA label for the Template Settings Sidebar tab, not selected. + __( 'Page' ); + } else { + templateAriaLabel = + sidebarName === SIDEBAR_TEMPLATE + ? // translators: ARIA label for the Template sidebar tab, selected. + __( 'Template (selected)' ) + : // translators: ARIA label for the Template Settings Sidebar tab, not selected. + __( 'Template' ); + } /* Use a list so screen readers will announce how many tabs there are. */ return ( @@ -39,29 +52,39 @@ const SettingsHeader = ( { sidebarName } ) => {
  • diff --git a/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/index.js b/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/index.js new file mode 100644 index 0000000000000..04e8d5667a2c2 --- /dev/null +++ b/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/index.js @@ -0,0 +1,34 @@ +/** + * External dependencies + */ +import classnames from 'classnames'; + +/** + * WordPress dependencies + */ +import { Icon } from '@wordpress/components'; + +export default function SidebarCard( { + className, + title, + icon, + description, + actions, + children, +} ) { + return ( +
    + +
    +
    +

    { title }

    + { actions } +
    +
    + { description } +
    + { children } +
    +
    + ); +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/style.scss b/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/style.scss new file mode 100644 index 0000000000000..718fe8fb5a0fb --- /dev/null +++ b/packages/edit-site/src/components/sidebar-edit-mode/sidebar-card/style.scss @@ -0,0 +1,34 @@ +.edit-site-sidebar-card { + display: flex; + align-items: flex-start; + + &__content { + flex-grow: 1; + margin-bottom: $grid-unit-05; + } + + &__title { + font-weight: 500; + line-height: $icon-size; + &.edit-site-sidebar-card__title { + margin: 0; + } + } + + &__description { + font-size: $default-font-size; + } + + &__icon { + flex: 0 0 $icon-size; + margin-right: $grid-unit-15; + width: $icon-size; + height: $icon-size; + } + + &__header { + display: flex; + justify-content: space-between; + margin: 0 0 $grid-unit-05; + } +} diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-card/index.js b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/index.js similarity index 60% rename from packages/edit-site/src/components/sidebar-edit-mode/template-card/index.js rename to packages/edit-site/src/components/sidebar-edit-mode/template-panel/index.js index d43dca3b803f5..1c369703be5d7 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/template-card/index.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/index.js @@ -2,10 +2,11 @@ * WordPress dependencies */ import { useSelect } from '@wordpress/data'; -import { Icon } from '@wordpress/components'; +import { PanelRow, PanelBody } from '@wordpress/components'; import { store as editorStore } from '@wordpress/editor'; import { store as coreStore } from '@wordpress/core-data'; import { decodeEntities } from '@wordpress/html-entities'; +import { __ } from '@wordpress/i18n'; /** * Internal dependencies @@ -13,8 +14,10 @@ import { decodeEntities } from '@wordpress/html-entities'; import { store as editSiteStore } from '../../../store'; import TemplateActions from './template-actions'; import TemplateAreas from './template-areas'; +import LastRevision from './last-revision'; +import SidebarCard from '../sidebar-card'; -export default function TemplateCard() { +export default function TemplatePanel() { const { info: { title, description, icon }, template, @@ -38,22 +41,22 @@ export default function TemplateCard() { } return ( - <> -
    - -
    -
    -

    - { decodeEntities( title ) } -

    - -
    -
    - { decodeEntities( description ) } -
    - -
    -
    - + + } + > + + + + + + ); } diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-revisions/index.js b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/last-revision.js similarity index 100% rename from packages/edit-site/src/components/sidebar-edit-mode/template-revisions/index.js rename to packages/edit-site/src/components/sidebar-edit-mode/template-panel/last-revision.js diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-card/style.scss b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/style.scss similarity index 50% rename from packages/edit-site/src/components/sidebar-edit-mode/template-card/style.scss rename to packages/edit-site/src/components/sidebar-edit-mode/template-panel/style.scss index 67054c25d2476..4c8ef94855dcb 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/template-card/style.scss +++ b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/style.scss @@ -1,30 +1,6 @@ .edit-site-template-card { - display: flex; - align-items: flex-start; - - &__content { - flex-grow: 1; - margin-bottom: $grid-unit-05; - } - - &__title { - font-weight: 500; - line-height: $icon-size; - &.edit-site-template-card__title { - margin: 0; - } - } - - &__description { - font-size: $default-font-size; - margin: 0 0 $grid-unit-20; - } - - &__icon { - flex: 0 0 $icon-size; - margin-right: $grid-unit-15; - width: $icon-size; - height: $icon-size; + &__template-areas { + margin-top: $grid-unit-20; } &__template-areas-list { @@ -44,12 +20,6 @@ } } - &__header { - display: flex; - justify-content: space-between; - margin: 0 0 $grid-unit-05; - } - &__actions { line-height: 0; > .components-button.is-small.has-icon { diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-card/template-actions.js b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/template-actions.js similarity index 100% rename from packages/edit-site/src/components/sidebar-edit-mode/template-card/template-actions.js rename to packages/edit-site/src/components/sidebar-edit-mode/template-panel/template-actions.js diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-card/template-areas.js b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/template-areas.js similarity index 100% rename from packages/edit-site/src/components/sidebar-edit-mode/template-card/template-areas.js rename to packages/edit-site/src/components/sidebar-edit-mode/template-panel/template-areas.js diff --git a/packages/edit-site/src/components/site-hub/index.js b/packages/edit-site/src/components/site-hub/index.js index 520ff5db2c2dd..dd184286f7d9b 100644 --- a/packages/edit-site/src/components/site-hub/index.js +++ b/packages/edit-site/src/components/site-hub/index.js @@ -20,7 +20,7 @@ import { store as coreStore } from '@wordpress/core-data'; import { decodeEntities } from '@wordpress/html-entities'; import { forwardRef } from '@wordpress/element'; import { search, external } from '@wordpress/icons'; -import { privateApis as commandsPrivateApis } from '@wordpress/commands'; +import { store as commandsStore } from '@wordpress/commands'; /** * Internal dependencies @@ -29,8 +29,6 @@ import { store as editSiteStore } from '../../store'; import SiteIcon from '../site-icon'; import { unlock } from '../../private-apis'; -const { store: commandsStore } = unlock( commandsPrivateApis ); - const HUB_ANIMATION_DURATION = 0.3; const SiteHub = forwardRef( ( props, ref ) => { diff --git a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js index 5ee0efcd6fa7c..11a765b9807d6 100644 --- a/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js +++ b/packages/edit-site/src/hooks/push-changes-to-global-styles/index.js @@ -29,7 +29,9 @@ import { store as noticesStore } from '@wordpress/notices'; import { useSupportedStyles } from '../../components/global-styles/hooks'; import { unlock } from '../../private-apis'; -const { GlobalStylesContext } = unlock( blockEditorPrivateApis ); +const { GlobalStylesContext, useBlockEditingMode } = unlock( + blockEditorPrivateApis +); // TODO: Temporary duplication of constant in @wordpress/block-editor. Can be // removed by moving PushChangesToGlobalStylesControl to @@ -208,15 +210,19 @@ function PushChangesToGlobalStylesControl( { } const withPushChangesToGlobalStyles = createHigherOrderComponent( - ( BlockEdit ) => ( props ) => - ( + ( BlockEdit ) => ( props ) => { + const blockEditingMode = useBlockEditingMode(); + return ( <> - - - + { blockEditingMode === 'default' && ( + + + + ) } - ) + ); + } ); addFilter( diff --git a/packages/edit-site/src/store/actions.js b/packages/edit-site/src/store/actions.js index a67406349e164..67fbec4811db4 100644 --- a/packages/edit-site/src/store/actions.js +++ b/packages/edit-site/src/store/actions.js @@ -530,3 +530,21 @@ export const switchEditorMode = speak( __( 'Code editor selected' ), 'assertive' ); } }; + +/** + * Sets whether or not the editor is locked so that only page content can be + * edited. + * + * @param {boolean} hasPageContentLock True to enable lock, false to disable. + */ +export const setHasPageContentLock = + ( hasPageContentLock ) => + ( { dispatch, registry } ) => { + if ( hasPageContentLock ) { + registry.dispatch( blockEditorStore ).clearSelectedBlock(); + } + dispatch( { + type: 'SET_HAS_PAGE_CONTENT_LOCK', + hasPageContentLock, + } ); + }; diff --git a/packages/edit-site/src/store/reducer.js b/packages/edit-site/src/store/reducer.js index a46d215f90507..a003ee958894e 100644 --- a/packages/edit-site/src/store/reducer.js +++ b/packages/edit-site/src/store/reducer.js @@ -157,6 +157,25 @@ function editorCanvasContainerView( state = undefined, action ) { return state; } +/** + * Reducer used to track whether the page content is locked. + * + * @param {boolean} state Current state. + * @param {Object} action Dispatched action. + * + * @return {boolean} Updated state. + */ +export function hasPageContentLock( state = false, action ) { + switch ( action.type ) { + case 'SET_EDITED_POST': + return !! action.context?.postId; + case 'SET_HAS_PAGE_CONTENT_LOCK': + return action.hasPageContentLock; + } + + return state; +} + export default combineReducers( { deviceType, settings, @@ -166,4 +185,5 @@ export default combineReducers( { saveViewPanel, canvasMode, editorCanvasContainerView, + hasPageContentLock, } ); diff --git a/packages/edit-site/src/store/selectors.js b/packages/edit-site/src/store/selectors.js index 583f37b55241b..16b6dc588ea26 100644 --- a/packages/edit-site/src/store/selectors.js +++ b/packages/edit-site/src/store/selectors.js @@ -321,3 +321,27 @@ export function isNavigationOpened() { version: '6.4', } ); } + +/** + * Whether or not the editor has a page loaded into it. + * + * @see setPage + * + * @param {Object} state Global application state. + * + * @return {boolean} Whether or not the editor has a page loaded into it. + */ +export function isPage( state ) { + return !! state.editedPost.context?.postId; +} + +/** + * Whether or not the editor is locked so that only page content can be edited. + * + * @param {Object} state Global application state. + * + * @return {boolean} Whether or not the editor is locked. + */ +export function hasPageContentLock( state ) { + return isPage( state ) ? state.hasPageContentLock : false; +} diff --git a/packages/edit-site/src/store/test/actions.js b/packages/edit-site/src/store/test/actions.js index 2df1cc72b6611..cca479e277662 100644 --- a/packages/edit-site/src/store/test/actions.js +++ b/packages/edit-site/src/store/test/actions.js @@ -13,6 +13,7 @@ import { store as preferencesStore } from '@wordpress/preferences'; * Internal dependencies */ import { store as editSiteStore } from '..'; +import { setHasPageContentLock } from '../actions'; const ENTITY_TYPES = { wp_template: { @@ -215,4 +216,34 @@ describe( 'actions', () => { ); } ); } ); + + describe( 'setHasPageContentLock', () => { + it( 'toggles the page content lock on', () => { + const dispatch = jest.fn(); + const clearSelectedBlock = jest.fn(); + const registry = { + dispatch: () => ( { clearSelectedBlock } ), + }; + setHasPageContentLock( true )( { dispatch, registry } ); + expect( clearSelectedBlock ).toHaveBeenCalled(); + expect( dispatch ).toHaveBeenCalledWith( { + type: 'SET_HAS_PAGE_CONTENT_LOCK', + hasPageContentLock: true, + } ); + } ); + + it( 'toggles the page content lock off', () => { + const dispatch = jest.fn(); + const clearSelectedBlock = jest.fn(); + const registry = { + dispatch: () => ( { clearSelectedBlock } ), + }; + setHasPageContentLock( false )( { dispatch, registry } ); + expect( clearSelectedBlock ).not.toHaveBeenCalled(); + expect( dispatch ).toHaveBeenCalledWith( { + type: 'SET_HAS_PAGE_CONTENT_LOCK', + hasPageContentLock: false, + } ); + } ); + } ); } ); diff --git a/packages/edit-site/src/store/test/reducer.js b/packages/edit-site/src/store/test/reducer.js index f6ce205ad6353..1ddc6bfb6fa7b 100644 --- a/packages/edit-site/src/store/test/reducer.js +++ b/packages/edit-site/src/store/test/reducer.js @@ -11,6 +11,7 @@ import { editedPost, blockInserterPanel, listViewPanel, + hasPageContentLock, } from '../reducer'; import { setIsInserterOpened, setIsListViewOpened } from '../actions'; @@ -135,4 +136,47 @@ describe( 'state', () => { ); } ); } ); + + describe( 'hasPageContentLocked()', () => { + it( 'defaults to false', () => { + expect( hasPageContentLock( undefined, {} ) ).toBe( false ); + } ); + + it( 'becomes false when editing a template', () => { + expect( + hasPageContentLock( true, { + type: 'SET_EDITED_POST', + postType: 'wp_template', + } ) + ).toBe( false ); + } ); + + it( 'becomes true when editing a page', () => { + expect( + hasPageContentLock( false, { + type: 'SET_EDITED_POST', + postType: 'wp_template', + context: { + postType: 'page', + postId: 123, + }, + } ) + ).toBe( true ); + } ); + + it( 'can be set', () => { + expect( + hasPageContentLock( false, { + type: 'SET_HAS_PAGE_CONTENT_LOCK', + hasPageContentLock: true, + } ) + ).toBe( true ); + expect( + hasPageContentLock( true, { + type: 'SET_HAS_PAGE_CONTENT_LOCK', + hasPageContentLock: false, + } ) + ).toBe( false ); + } ); + } ); } ); diff --git a/packages/edit-site/src/store/test/selectors.js b/packages/edit-site/src/store/test/selectors.js index 223bcd1f0ba04..d9ed31411ffcc 100644 --- a/packages/edit-site/src/store/test/selectors.js +++ b/packages/edit-site/src/store/test/selectors.js @@ -15,6 +15,8 @@ import { isInserterOpened, isListViewOpened, __unstableGetPreference, + isPage, + hasPageContentLock, } from '../selectors'; describe( 'selectors', () => { @@ -145,4 +147,59 @@ describe( 'selectors', () => { expect( isListViewOpened( state ) ).toBe( false ); } ); } ); + + describe( 'isPage', () => { + it( 'returns true if the edited post type is a page', () => { + const state = { + editedPost: { + postType: 'wp_template', + context: { postType: 'page', postId: 123 }, + }, + }; + expect( isPage( state ) ).toBe( true ); + } ); + + it( 'returns false if the edited post type is a template', () => { + const state = { + editedPost: { + postType: 'wp_template', + }, + }; + expect( isPage( state ) ).toBe( false ); + } ); + } ); + + describe( 'hasPageContentLock', () => { + it( 'returns true if locked and the edited post type is a page', () => { + const state = { + editedPost: { + postType: 'wp_template', + context: { postType: 'page', postId: 123 }, + }, + hasPageContentLock: true, + }; + expect( hasPageContentLock( state ) ).toBe( true ); + } ); + + it( 'returns false if not locked and the edited post type is a page', () => { + const state = { + editedPost: { + postType: 'wp_template', + context: { postType: 'page', postId: 123 }, + }, + hasPageContentLock: false, + }; + expect( hasPageContentLock( state ) ).toBe( false ); + } ); + + it( 'returns false if locked and the edited post type is a template', () => { + const state = { + editedPost: { + postType: 'wp_template', + }, + hasPageContentLock: true, + }; + expect( hasPageContentLock( state ) ).toBe( false ); + } ); + } ); } ); diff --git a/packages/edit-site/src/style.scss b/packages/edit-site/src/style.scss index 3e2b34ea65f5f..e31978cf0f45d 100644 --- a/packages/edit-site/src/style.scss +++ b/packages/edit-site/src/style.scss @@ -10,8 +10,10 @@ @import "./components/header-edit-mode/document-actions/style.scss"; @import "./components/list/style.scss"; @import "./components/sidebar-edit-mode/style.scss"; +@import "./components/sidebar-edit-mode/page-panels/style.scss"; @import "./components/sidebar-edit-mode/settings-header/style.scss"; -@import "./components/sidebar-edit-mode/template-card/style.scss"; +@import "./components/sidebar-edit-mode/sidebar-card/style.scss"; +@import "./components/sidebar-edit-mode/template-panel/style.scss"; @import "./components/editor/style.scss"; @import "./components/create-template-part-modal/style.scss"; @import "./components/secondary-sidebar/style.scss"; diff --git a/packages/editor/src/components/post-saved-state/index.js b/packages/editor/src/components/post-saved-state/index.js index d3c15b5596e3d..24b88d4d96dee 100644 --- a/packages/editor/src/components/post-saved-state/index.js +++ b/packages/editor/src/components/post-saved-state/index.js @@ -47,8 +47,10 @@ export default function PostSavedState( { isDirty, isNew, isPending, + isPublished, isSaveable, isSaving, + isScheduled, hasPublishAction, } = useSelect( ( select ) => { @@ -103,6 +105,10 @@ export default function PostSavedState( { return null; } + if ( isPublished || isScheduled ) { + return null; + } + /* translators: button label text should, if possible, be under 16 characters. */ const label = isPending ? __( 'Save as pending' ) : __( 'Save draft' ); diff --git a/packages/editor/src/components/post-title/index.js b/packages/editor/src/components/post-title/index.js index b9143a29ff3c0..b9cc0adaa275c 100644 --- a/packages/editor/src/components/post-title/index.js +++ b/packages/editor/src/components/post-title/index.js @@ -74,7 +74,8 @@ function PostTitle( _, forwardedRef ) { return; } - const { ownerDocument } = ref.current; + const ownerDocument = + ref.current.ownerDocument.defaultView.top.document; const { activeElement, body } = ownerDocument; // Only autofocus the title when the post is entirely empty. This should diff --git a/packages/react-native-aztec/package.json b/packages/react-native-aztec/package.json index d8c8cc9d0b301..b25575de05e8c 100644 --- a/packages/react-native-aztec/package.json +++ b/packages/react-native-aztec/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/react-native-aztec", - "version": "1.96.0", + "version": "1.96.1", "description": "Aztec view for react-native.", "private": true, "author": "The WordPress Contributors", diff --git a/packages/react-native-bridge/package.json b/packages/react-native-bridge/package.json index 11745b50ae143..ec7cdadba56b4 100644 --- a/packages/react-native-bridge/package.json +++ b/packages/react-native-bridge/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/react-native-bridge", - "version": "1.96.0", + "version": "1.96.1", "description": "Native bridge library used to integrate the block editor into a native App.", "private": true, "author": "The WordPress Contributors", diff --git a/packages/react-native-editor/CHANGELOG.md b/packages/react-native-editor/CHANGELOG.md index c9f1b9409d9d7..e575e5ebe6e06 100644 --- a/packages/react-native-editor/CHANGELOG.md +++ b/packages/react-native-editor/CHANGELOG.md @@ -11,6 +11,8 @@ For each user feature we should also add a importance categorization label to i ## Unreleased - [*] [internal] Upgrade compile and target sdk version to Android API 33 [#50731] + +## 1.96.1 - [**] Fix Android-only issue related to block toolbar not being displayed on some blocks in UBE [#51131] ## 1.96.0 diff --git a/packages/react-native-editor/ios/Podfile.lock b/packages/react-native-editor/ios/Podfile.lock index 07c9a5c9068b8..bcb1231b9c488 100644 --- a/packages/react-native-editor/ios/Podfile.lock +++ b/packages/react-native-editor/ios/Podfile.lock @@ -13,7 +13,7 @@ PODS: - ReactCommon/turbomodule/core (= 0.69.4) - fmt (6.2.1) - glog (0.3.5) - - Gutenberg (1.96.0): + - Gutenberg (1.96.1): - React-Core (= 0.69.4) - React-CoreModules (= 0.69.4) - React-RCTImage (= 0.69.4) @@ -360,7 +360,7 @@ PODS: - React-Core - RNSVG (9.13.6): - React-Core - - RNTAztecView (1.96.0): + - RNTAztecView (1.96.1): - React-Core - WordPress-Aztec-iOS (~> 1.19.8) - SDWebImage (5.11.1): @@ -540,7 +540,7 @@ SPEC CHECKSUMS: FBReactNativeSpec: 2ff441cbe6e58c1778d8a5cf3311831a6a8c0809 fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 glog: 3d02b25ca00c2d456734d0bcff864cbc62f6ae1a - Gutenberg: baeb5202bdcc71526ae04505a54e72255a7260ce + Gutenberg: 5cd4d25aa41b725c7802394e4f3b8eeddf90f370 libwebp: 60305b2e989864154bd9be3d772730f08fc6a59c RCT-Folly: b9d9fe1fc70114b751c076104e52f3b1b5e5a95a RCTRequired: bd9d2ab0fda10171fcbcf9ba61a7df4dc15a28f4 @@ -582,7 +582,7 @@ SPEC CHECKSUMS: RNReanimated: 5740ec9926f80bccd404bacd3e71108e87c94afa RNScreens: 953633729a42e23ad0c93574d676b361e3335e8b RNSVG: 36a7359c428dcb7c6bce1cc546fbfebe069809b0 - RNTAztecView: 61e0a2f69770f30e01f21991c79861be70a8d8bc + RNTAztecView: 59e8ceb3dd9473ad7f1e6cca3232caf3cd620009 SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d WordPress-Aztec-iOS: 7d11d598f14c82c727c08b56bd35fbeb7dafb504 diff --git a/packages/react-native-editor/package.json b/packages/react-native-editor/package.json index ab7dd809666d9..9aca508d859f3 100644 --- a/packages/react-native-editor/package.json +++ b/packages/react-native-editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/react-native-editor", - "version": "1.96.0", + "version": "1.96.1", "description": "Mobile WordPress gutenberg editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md index dadafda617cd4..48b96674fd3ef 100644 --- a/packages/scripts/CHANGELOG.md +++ b/packages/scripts/CHANGELOG.md @@ -5,6 +5,11 @@ ### Enhancements - The bundled `terser-webpack-plugin` dependency has been updated from requiring `^5.1.4` to requiring `^5.3.9` ([#50994](https://github.com/WordPress/gutenberg/pull/50994)). +- Optimize updating render paths when developing blocks with the `start` command ([#51162](https://github.com/WordPress/gutenberg/pull/51162)). + +### Bug Fixes + +- Ensure files listed in `render` field of `block.json` files are always copied to the build folder when using the `start` command ([#50939](https://github.com/WordPress/gutenberg/pull/50939)). ## 26.5.0 (2023-05-24) diff --git a/packages/scripts/config/webpack.config.js b/packages/scripts/config/webpack.config.js index bc3cb0d8d5cc2..c02fbfcbea2c9 100644 --- a/packages/scripts/config/webpack.config.js +++ b/packages/scripts/config/webpack.config.js @@ -38,8 +38,27 @@ if ( ! browserslist.findConfig( '.' ) ) { } const hasReactFastRefresh = hasArgInCLI( '--hot' ) && ! isProduction; -// Get paths of the `render` props included in `block.json` files -let renderPaths = getRenderPropPaths(); +/** + * The plugin recomputes the render paths once on each compilation. It is necessary to avoid repeating processing + * when filtering every discovered PHP file in the source folder. This is the most performant way to ensure that + * changes in `block.json` files are picked up in watch mode. + */ +class RenderPathsPlugin { + /** + * Paths with the `render` props included in `block.json` files. + * + * @type {string[]} + */ + static renderPaths; + + apply( compiler ) { + const pluginName = this.constructor.name; + + compiler.hooks.thisCompilation.tap( pluginName, () => { + this.constructor.renderPaths = getRenderPropPaths(); + } ); + } +} const cssLoaders = [ { @@ -234,6 +253,7 @@ const config = { // multiple configurations returned in the webpack config. cleanStaleWebpackAssets: false, } ), + new RenderPathsPlugin(), new CopyWebpackPlugin( { patterns: [ { @@ -275,10 +295,9 @@ const config = { context: getWordPressSrcDirectory(), noErrorOnMissing: true, filter: ( filepath ) => { - renderPaths = getRenderPropPaths(); return ( process.env.WP_COPY_PHP_FILES_TO_DIST || - renderPaths.includes( filepath ) + RenderPathsPlugin.renderPaths.includes( filepath ) ); }, }, diff --git a/packages/server-side-render/README.md b/packages/server-side-render/README.md index 9c78086893147..ba6fae302ca0a 100644 --- a/packages/server-side-render/README.md +++ b/packages/server-side-render/README.md @@ -170,7 +170,7 @@ If you pass `attributes` to `ServerSideRender`, the block must also be registere register_block_type( 'core/archives', array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'showPostCounts' => array( 'type' => 'boolean', diff --git a/packages/widgets/src/blocks/legacy-widget/block.json b/packages/widgets/src/blocks/legacy-widget/block.json index 30b60c6448835..6b0c1e2a916fd 100644 --- a/packages/widgets/src/blocks/legacy-widget/block.json +++ b/packages/widgets/src/blocks/legacy-widget/block.json @@ -1,5 +1,5 @@ { - "apiVersion": 2, + "apiVersion": 3, "name": "core/legacy-widget", "title": "Legacy Widget", "category": "widgets", diff --git a/packages/widgets/src/blocks/widget-group/block.json b/packages/widgets/src/blocks/widget-group/block.json index ec48d90eda5ca..c29e811554ac1 100644 --- a/packages/widgets/src/blocks/widget-group/block.json +++ b/packages/widgets/src/blocks/widget-group/block.json @@ -1,5 +1,5 @@ { - "apiVersion": 2, + "apiVersion": 3, "name": "core/widget-group", "category": "widgets", "attributes": { diff --git a/phpunit/block-supports/border-test.php b/phpunit/block-supports/border-test.php index 7c8bd9975d35b..858e4e92cc174 100644 --- a/phpunit/block-supports/border-test.php +++ b/phpunit/block-supports/border-test.php @@ -36,7 +36,7 @@ private function register_bordered_block_with_support( $block_name, $supports = register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'borderColor' => array( 'type' => 'string', diff --git a/phpunit/block-supports/colors-test.php b/phpunit/block-supports/colors-test.php index f21f6477f4162..310b7e6c525cb 100644 --- a/phpunit/block-supports/colors-test.php +++ b/phpunit/block-supports/colors-test.php @@ -28,7 +28,7 @@ public function test_color_slugs_with_numbers_are_kebab_cased_properly() { register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'textColor' => array( 'type' => 'string', @@ -69,7 +69,7 @@ public function test_color_with_skipped_serialization_block_supports() { register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'style' => array( 'type' => 'object', @@ -107,7 +107,7 @@ public function test_gradient_with_individual_skipped_serialization_block_suppor register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'style' => array( 'type' => 'object', diff --git a/phpunit/block-supports/dimensions-test.php b/phpunit/block-supports/dimensions-test.php index 2ec0859b7cb7f..d428977c2c0a6 100644 --- a/phpunit/block-supports/dimensions-test.php +++ b/phpunit/block-supports/dimensions-test.php @@ -28,7 +28,7 @@ public function test_dimensions_style_is_applied() { register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'style' => array( 'type' => 'object', @@ -64,7 +64,7 @@ public function test_dimensions_with_skipped_serialization_block_supports() { register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'style' => array( 'type' => 'object', @@ -99,7 +99,7 @@ public function test_min_height_with_individual_skipped_serialization_block_supp register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'style' => array( 'type' => 'object', diff --git a/phpunit/block-supports/position-test.php b/phpunit/block-supports/position-test.php index c304ffa68e7de..d9f97060cf647 100644 --- a/phpunit/block-supports/position-test.php +++ b/phpunit/block-supports/position-test.php @@ -78,7 +78,7 @@ public function test_position_block_support( $theme_name, $block_name, $position register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'style' => array( 'type' => 'object', diff --git a/phpunit/block-supports/spacing-test.php b/phpunit/block-supports/spacing-test.php index 1ac0c86e62042..93df6f55ac109 100644 --- a/phpunit/block-supports/spacing-test.php +++ b/phpunit/block-supports/spacing-test.php @@ -28,7 +28,7 @@ public function test_spacing_style_is_applied() { register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'style' => array( 'type' => 'object', @@ -73,7 +73,7 @@ public function test_spacing_with_skipped_serialization_block_supports() { register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'style' => array( 'type' => 'object', @@ -117,7 +117,7 @@ public function test_margin_with_individual_skipped_serialization_block_supports register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'style' => array( 'type' => 'object', diff --git a/phpunit/block-supports/typography-test.php b/phpunit/block-supports/typography-test.php index cfb3f19a1a7ae..5a2f52f780f1d 100644 --- a/phpunit/block-supports/typography-test.php +++ b/phpunit/block-supports/typography-test.php @@ -78,7 +78,7 @@ public function test_should_kebab_case_font_size_slug_with_numbers() { register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'fontSize' => array( 'type' => 'string', @@ -112,7 +112,7 @@ public function test_should_generate_font_family_with_legacy_inline_styles_using register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'style' => array( 'type' => 'object', @@ -145,7 +145,7 @@ public function test_should_skip_serialization_for_typography_block_supports() { register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'style' => array( 'type' => 'object', @@ -191,7 +191,7 @@ public function test_should_skip_serialization_for_letter_spacing_block_supports register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'style' => array( 'type' => 'object', @@ -227,7 +227,7 @@ public function test_should_generate_css_var_for_font_family_with_legacy_inline_ register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'style' => array( 'type' => 'object', @@ -260,7 +260,7 @@ public function test_should_generate_classname_for_font_family() { register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'style' => array( 'type' => 'object', @@ -625,7 +625,7 @@ public function test_should_covert_font_sizes_to_fluid_values( $font_size_value, register_block_type( $this->test_block_name, array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'style' => array( 'type' => 'object', diff --git a/phpunit/bootstrap.php b/phpunit/bootstrap.php index e15509e43143e..c11233b1e8952 100644 --- a/phpunit/bootstrap.php +++ b/phpunit/bootstrap.php @@ -105,7 +105,7 @@ function gutenberg_register_test_block_for_feature_selectors() { WP_Block_Type_Registry::get_instance()->register( 'test/test', array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'textColor' => array( 'type' => 'string', diff --git a/phpunit/class-wp-theme-json-resolver-test.php b/phpunit/class-wp-theme-json-resolver-test.php index 4cc34bf97b32c..1588aa4d60326 100644 --- a/phpunit/class-wp-theme-json-resolver-test.php +++ b/phpunit/class-wp-theme-json-resolver-test.php @@ -396,7 +396,7 @@ public function test_get_merged_data_returns_origin( $origin, $core_palette, $co register_block_type( 'my/block-with-styles', array( - 'api_version' => 2, + 'api_version' => 3, 'attributes' => array( 'borderColor' => array( 'type' => 'string', diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index 7d63f62a2c1f0..043cd4916eac8 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -215,7 +215,7 @@ public function test_get_stylesheet_generates_base_fallback_gap_layout_styles( $ // Note the `base-layout-styles` includes a fallback gap for the Columns block for backwards compatibility. $this->assertEquals( - ':where(.is-layout-flex){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-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}', + ':where(.is-layout-flex){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-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}', $stylesheet ); } diff --git a/phpunit/fixtures/block.json b/phpunit/fixtures/block.json index 41904ae811962..2ab91788dc0d4 100644 --- a/phpunit/fixtures/block.json +++ b/phpunit/fixtures/block.json @@ -1,5 +1,5 @@ { - "apiVersion": 2, + "apiVersion": 3, "name": "my-plugin/notice", "title": "Notice", "category": "common", diff --git a/schemas/json/block.json b/schemas/json/block.json index 5b92a654fbc4a..6ca40ba90f961 100644 --- a/schemas/json/block.json +++ b/schemas/json/block.json @@ -17,9 +17,9 @@ }, "apiVersion": { "type": "integer", - "description": "The version of the Block API used by the block. The most recent version is 2 and it was introduced in WordPress 5.6.\n\n See the API versions documentation at https://developer.wordpress.org/block-editor/reference-guides/block-api/block-api-versions/ for more details.", + "description": "The version of the Block API used by the block. The most recent version is 3 and it was introduced in WordPress 6.3.\n\n See the API versions documentation at https://developer.wordpress.org/block-editor/reference-guides/block-api/block-api-versions/ for more details.", "default": 1, - "enum": [ 1, 2 ] + "enum": [ 1, 2, 3 ] }, "name": { "type": "string", diff --git a/test/e2e/specs/editor/blocks/avatar.spec.js b/test/e2e/specs/editor/blocks/avatar.spec.js index bbce1eede94da..8bf39a7a60dba 100644 --- a/test/e2e/specs/editor/blocks/avatar.spec.js +++ b/test/e2e/specs/editor/blocks/avatar.spec.js @@ -37,7 +37,7 @@ test.describe( 'Avatar', () => { const username = 'Gravatar Gravatar'; - const avatarBlock = page.locator( + const avatarBlock = editor.canvas.locator( 'role=document[name="Block: Avatar"i]' ); diff --git a/test/e2e/specs/editor/blocks/buttons.spec.js b/test/e2e/specs/editor/blocks/buttons.spec.js index 13d5759ee7db9..8eacb7e2bed2e 100644 --- a/test/e2e/specs/editor/blocks/buttons.spec.js +++ b/test/e2e/specs/editor/blocks/buttons.spec.js @@ -27,7 +27,7 @@ test.describe( 'Buttons', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '/buttons' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'Content' ); @@ -56,7 +56,7 @@ test.describe( 'Buttons', () => { ).toBeFocused(); await page.keyboard.press( 'Escape' ); await expect( - page.locator( 'role=textbox[name="Button text"i]' ) + editor.canvas.locator( 'role=textbox[name="Button text"i]' ) ).toBeFocused(); await page.keyboard.type( 'WordPress' ); @@ -91,7 +91,7 @@ test.describe( 'Buttons', () => { // Focus should move from the link control to the button block's text. await expect( - page.locator( 'role=textbox[name="Button text"i]' ) + editor.canvas.locator( 'role=textbox[name="Button text"i]' ) ).toBeFocused(); // The link control should still be visible when a URL is set. diff --git a/test/e2e/specs/editor/blocks/classic.spec.js b/test/e2e/specs/editor/blocks/classic.spec.js index cba1472caf916..4403706444a7e 100644 --- a/test/e2e/specs/editor/blocks/classic.spec.js +++ b/test/e2e/specs/editor/blocks/classic.spec.js @@ -18,8 +18,15 @@ test.use( { } ); test.describe( 'Classic', () => { - test.beforeEach( async ( { admin } ) => { + test.beforeEach( async ( { admin, page } ) => { await admin.createNewPost(); + // To do: run with iframe. + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); } ); test.afterAll( async ( { requestUtils } ) => { @@ -126,6 +133,14 @@ test.describe( 'Classic', () => { await page.reload(); await page.unroute( '**' ); + // To do: run with iframe. + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); + const errors = []; page.on( 'pageerror', ( exception ) => { errors.push( exception ); diff --git a/test/e2e/specs/editor/blocks/code.spec.js b/test/e2e/specs/editor/blocks/code.spec.js index 80f41779b9131..c4037d50b7dd5 100644 --- a/test/e2e/specs/editor/blocks/code.spec.js +++ b/test/e2e/specs/editor/blocks/code.spec.js @@ -12,7 +12,7 @@ test.describe( 'Code', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '```' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( ' { } ) => { // Open Columns await editor.insertBlock( { name: 'core/columns' } ); - await page.locator( '[aria-label="Two columns; equal split"]' ).click(); + await editor.canvas + .locator( '[aria-label="Two columns; equal split"]' ) + .click(); // Open List view toggle await page.locator( 'role=button[name="Document Overview"i]' ).click(); @@ -51,13 +53,15 @@ test.describe( 'Columns', () => { } ) => { // Open Columns await editor.insertBlock( { name: 'core/columns' } ); - await page + await editor.canvas .locator( '[aria-label="Three columns; equal split"]' ) .click(); // Lock last column block await editor.selectBlocks( - page.locator( 'role=document[name="Block: Column (3 of 3)"i]' ) + editor.canvas.locator( + 'role=document[name="Block: Column (3 of 3)"i]' + ) ); await editor.clickBlockToolbarButton( 'Options' ); await page.click( 'role=menuitem[name="Lock"i]' ); @@ -66,7 +70,7 @@ test.describe( 'Columns', () => { // Select columns block await editor.selectBlocks( - page.locator( 'role=document[name="Block: Columns"i]' ) + editor.canvas.locator( 'role=document[name="Block: Columns"i]' ) ); await editor.openDocumentSettingsSidebar(); diff --git a/test/e2e/specs/editor/blocks/comments.spec.js b/test/e2e/specs/editor/blocks/comments.spec.js index 55a4cdca8c1c0..4b0dbf66b2a30 100644 --- a/test/e2e/specs/editor/blocks/comments.spec.js +++ b/test/e2e/specs/editor/blocks/comments.spec.js @@ -169,7 +169,7 @@ test.describe( 'Comments', () => { 'role=button[name="Switch to editable mode"i]' ); - const commentTemplate = block.locator( + const commentTemplate = editor.canvas.locator( 'role=document[name="Block: Comment Template"i]' ); await expect( block ).toHaveClass( /has-vivid-purple-color/ ); diff --git a/test/e2e/specs/editor/blocks/cover.spec.js b/test/e2e/specs/editor/blocks/cover.spec.js index 0217616781345..90555eca548c2 100644 --- a/test/e2e/specs/editor/blocks/cover.spec.js +++ b/test/e2e/specs/editor/blocks/cover.spec.js @@ -25,12 +25,11 @@ test.describe( 'Cover', () => { } ); test( 'can set overlay color using color picker on block placeholder', async ( { - page, editor, coverBlockUtils, } ) => { await editor.insertBlock( { name: 'core/cover' } ); - const coverBlock = page.getByRole( 'document', { + const coverBlock = editor.canvas.getByRole( 'document', { name: 'Block: Cover', } ); @@ -56,12 +55,11 @@ test.describe( 'Cover', () => { } ); test( 'can set background image using image upload on block placeholder', async ( { - page, editor, coverBlockUtils, } ) => { await editor.insertBlock( { name: 'core/cover' } ); - const coverBlock = page.getByRole( 'document', { + const coverBlock = editor.canvas.getByRole( 'document', { name: 'Block: Cover', } ); @@ -80,12 +78,11 @@ test.describe( 'Cover', () => { } ); test( 'dims background image down by 50% by default', async ( { - page, editor, coverBlockUtils, } ) => { await editor.insertBlock( { name: 'core/cover' } ); - const coverBlock = page.getByRole( 'document', { + const coverBlock = editor.canvas.getByRole( 'document', { name: 'Block: Cover', } ); @@ -104,11 +101,11 @@ test.describe( 'Cover', () => { expect( backgroundDimOpacity ).toBe( '0.5' ); } ); - test( 'can have the title edited', async ( { page, editor } ) => { + test( 'can have the title edited', async ( { editor } ) => { const titleText = 'foo'; await editor.insertBlock( { name: 'core/cover' } ); - const coverBlock = page.getByRole( 'document', { + const coverBlock = editor.canvas.getByRole( 'document', { name: 'Block: Cover', } ); @@ -134,7 +131,7 @@ test.describe( 'Cover', () => { test( 'can be resized using drag & drop', async ( { page, editor } ) => { await editor.insertBlock( { name: 'core/cover' } ); - const coverBlock = page.getByRole( 'document', { + const coverBlock = editor.canvas.getByRole( 'document', { name: 'Block: Cover', } ); await coverBlock @@ -205,13 +202,12 @@ test.describe( 'Cover', () => { } ); test( 'dims the background image down by 50% when transformed from the Image block', async ( { - page, editor, coverBlockUtils, } ) => { await editor.insertBlock( { name: 'core/image' } ); - const imageBlock = page.getByRole( 'document', { + const imageBlock = editor.canvas.getByRole( 'document', { name: 'Block: Image', } ); @@ -220,14 +216,14 @@ test.describe( 'Cover', () => { ); await expect( - page + editor.canvas .getByRole( 'document', { name: 'Block: Image' } ) .locator( 'img' ) ).toBeVisible(); await editor.transformBlockTo( 'core/cover' ); - const coverBlock = page.getByRole( 'document', { + const coverBlock = editor.canvas.getByRole( 'document', { name: 'Block: Cover', } ); diff --git a/test/e2e/specs/editor/blocks/gallery.spec.js b/test/e2e/specs/editor/blocks/gallery.spec.js index 1a71d3e46e6dd..f950036539c11 100644 --- a/test/e2e/specs/editor/blocks/gallery.spec.js +++ b/test/e2e/specs/editor/blocks/gallery.spec.js @@ -51,10 +51,10 @@ test.describe( 'Gallery', () => { plainText: `[gallery ids="${ uploadedMedia.id }"]`, } ); - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await pageUtils.pressKeys( 'primary+v' ); - const img = page.locator( + const img = editor.canvas.locator( 'role=document[name="Block: Image"i] >> role=img' ); @@ -87,12 +87,11 @@ test.describe( 'Gallery', () => { test( 'can be created using uploaded images', async ( { admin, editor, - page, galleryBlockUtils, } ) => { await admin.createNewPost(); await editor.insertBlock( { name: 'core/gallery' } ); - const galleryBlock = page.locator( + const galleryBlock = editor.canvas.locator( 'role=document[name="Block: Gallery"i]' ); await expect( galleryBlock ).toBeVisible(); @@ -132,7 +131,9 @@ test.describe( 'Gallery', () => { ], } ); - const gallery = page.locator( 'role=document[name="Block: Gallery"i]' ); + const gallery = editor.canvas.locator( + 'role=document[name="Block: Gallery"i]' + ); await expect( gallery ).toBeVisible(); await editor.selectBlocks( gallery ); @@ -173,7 +174,7 @@ test.describe( 'Gallery', () => { ], } ); - const galleryImage = page.locator( + const galleryImage = editor.canvas.locator( 'role=document[name="Block: Gallery"i] >> role=document[name="Block: Image"i]' ); const imageCaption = galleryImage.locator( @@ -203,7 +204,7 @@ test.describe( 'Gallery', () => { } ) => { await admin.createNewPost(); await editor.insertBlock( { name: 'core/gallery' } ); - await page.click( 'role=button[name="Media Library"i]' ); + await editor.canvas.click( 'role=button[name="Media Library"i]' ); const mediaLibrary = page.locator( 'role=dialog[name="Create gallery"i]' diff --git a/test/e2e/specs/editor/blocks/group.spec.js b/test/e2e/specs/editor/blocks/group.spec.js index 4cf284a0cdf69..2de22245eb5b0 100644 --- a/test/e2e/specs/editor/blocks/group.spec.js +++ b/test/e2e/specs/editor/blocks/group.spec.js @@ -29,7 +29,7 @@ test.describe( 'Group', () => { ); // Select the default, selected Group layout from the variation picker. - await page.click( + await editor.canvas.click( 'role=button[name="Group: Gather blocks in a container."i]' ); @@ -40,7 +40,7 @@ test.describe( 'Group', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '/group' ); await expect( page.locator( 'role=option[name="Group"i][selected]' ) @@ -48,7 +48,7 @@ test.describe( 'Group', () => { await page.keyboard.press( 'Enter' ); // Select the default, selected Group layout from the variation picker. - await page.click( + await editor.canvas.click( 'role=button[name="Group: Gather blocks in a container."i]' ); @@ -60,10 +60,10 @@ test.describe( 'Group', () => { page, } ) => { await editor.insertBlock( { name: 'core/group' } ); - await page.click( + await editor.canvas.click( 'button[aria-label="Group: Gather blocks in a container."]' ); - await page.click( 'role=button[name="Add block"i]' ); + await editor.canvas.click( 'role=button[name="Add block"i]' ); await page.click( 'role=listbox[name="Blocks"i] >> role=option[name="Paragraph"i]' ); diff --git a/test/e2e/specs/editor/blocks/heading.spec.js b/test/e2e/specs/editor/blocks/heading.spec.js index e1b97d780f292..1413b4cad9e9d 100644 --- a/test/e2e/specs/editor/blocks/heading.spec.js +++ b/test/e2e/specs/editor/blocks/heading.spec.js @@ -12,7 +12,7 @@ test.describe( 'Heading', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '### 3' ); await expect.poll( editor.getBlocks ).toMatchObject( [ @@ -27,7 +27,7 @@ test.describe( 'Heading', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '4' ); await page.keyboard.press( 'ArrowLeft' ); await page.keyboard.type( '#### ' ); @@ -44,7 +44,7 @@ test.describe( 'Heading', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '## 1. H' ); await expect.poll( editor.getBlocks ).toMatchObject( [ @@ -59,7 +59,7 @@ test.describe( 'Heading', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '## `code`' ); await expect.poll( editor.getBlocks ).toMatchObject( [ @@ -115,7 +115,7 @@ test.describe( 'Heading', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '### Heading' ); await editor.openDocumentSettingsSidebar(); @@ -147,7 +147,7 @@ test.describe( 'Heading', () => { } ); test( 'should correctly apply named colors', async ( { editor, page } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '## Heading' ); await editor.openDocumentSettingsSidebar(); @@ -185,7 +185,7 @@ test.describe( 'Heading', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '## Heading' ); // Change text alignment @@ -216,7 +216,7 @@ test.describe( 'Heading', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'Paragraph' ); // Change text alignment @@ -247,7 +247,7 @@ test.describe( 'Heading', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '## Heading' ); // Change text alignment diff --git a/test/e2e/specs/editor/blocks/html.spec.js b/test/e2e/specs/editor/blocks/html.spec.js index 77e9d2a9186a7..99a875f081018 100644 --- a/test/e2e/specs/editor/blocks/html.spec.js +++ b/test/e2e/specs/editor/blocks/html.spec.js @@ -10,7 +10,7 @@ test.describe( 'HTML block', () => { test( 'can be created by typing "/html"', async ( { editor, page } ) => { // Create a Custom HTML block with the slash shortcut. - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '/html' ); await expect( page.locator( 'role=option[name="Custom HTML"i][selected]' ) @@ -33,7 +33,7 @@ test.describe( 'HTML block', () => { test( 'should not encode <', async ( { editor, page } ) => { // Create a Custom HTML block with the slash shortcut. - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '/html' ); await expect( page.locator( 'role=option[name="Custom HTML"i][selected]' ) @@ -42,8 +42,9 @@ test.describe( 'HTML block', () => { await page.keyboard.type( '1 < 2' ); await editor.publishPost(); await page.reload(); + await page.waitForSelector( '[name="editor-canvas"]' ); await expect( - page.locator( '[data-type="core/html"] textarea' ) + editor.canvas.locator( '[data-type="core/html"] textarea' ) ).toBeVisible(); } ); } ); diff --git a/test/e2e/specs/editor/blocks/image.spec.js b/test/e2e/specs/editor/blocks/image.spec.js index 48ece12d8f347..2516a6d9c5cea 100644 --- a/test/e2e/specs/editor/blocks/image.spec.js +++ b/test/e2e/specs/editor/blocks/image.spec.js @@ -32,10 +32,10 @@ test.describe( 'Image', () => { await requestUtils.deleteAllMedia(); } ); - test( 'can be inserted', async ( { editor, page, imageBlockUtils } ) => { + test( 'can be inserted', async ( { editor, imageBlockUtils } ) => { await editor.insertBlock( { name: 'core/image' } ); - const imageBlock = page.locator( + const imageBlock = editor.canvas.locator( 'role=document[name="Block: Image"i]' ); await expect( imageBlock ).toBeVisible(); @@ -63,7 +63,7 @@ test.describe( 'Image', () => { } ) => { await editor.insertBlock( { name: 'core/image' } ); - const imageBlock = page.locator( + const imageBlock = editor.canvas.locator( 'role=document[name="Block: Image"i]' ); const image = imageBlock.locator( 'role=img' ); @@ -134,7 +134,7 @@ test.describe( 'Image', () => { { // Focus outside the block to avoid the image caption being selected // It can happen on CI specially. - await page.click( 'role=textbox[name="Add title"i]' ); + await editor.canvas.click( 'role=textbox[name="Add title"i]' ); await image.click(); await page.keyboard.press( 'Backspace' ); @@ -149,7 +149,7 @@ test.describe( 'Image', () => { } ) => { await editor.insertBlock( { name: 'core/image' } ); - const imageBlock = page.locator( + const imageBlock = editor.canvas.locator( 'role=document[name="Block: Image"i]' ); const image = imageBlock.locator( 'role=img' ); @@ -165,7 +165,9 @@ test.describe( 'Image', () => { await page.keyboard.type( '2' ); expect( - await page.evaluate( () => document.activeElement.innerHTML ) + await editor.canvas.evaluate( + () => document.activeElement.innerHTML + ) ).toBe( '12' ); } ); @@ -176,7 +178,7 @@ test.describe( 'Image', () => { } ) => { await editor.insertBlock( { name: 'core/image' } ); - const imageBlock = page.locator( + const imageBlock = editor.canvas.locator( 'role=document[name="Block: Image"i]' ); const image = imageBlock.locator( 'role=img' ); @@ -193,7 +195,9 @@ test.describe( 'Image', () => { await page.keyboard.press( 'Enter' ); expect( - await page.evaluate( () => document.activeElement.innerHTML ) + await editor.canvas.evaluate( + () => document.activeElement.innerHTML + ) ).toBe( '1
    2' ); } ); @@ -205,7 +209,7 @@ test.describe( 'Image', () => { } ) => { await editor.insertBlock( { name: 'core/image' } ); - const imageBlock = page.locator( + const imageBlock = editor.canvas.locator( 'role=document[name="Block: Image"i]' ); const image = imageBlock.locator( 'role=img' ); @@ -245,7 +249,9 @@ test.describe( 'Image', () => { await page.keyboard.press( 'ArrowRight' ); expect( - await page.evaluate( () => document.activeElement.innerHTML ) + await editor.canvas.evaluate( + () => document.activeElement.innerHTML + ) ).toBe( 'a' ); } ); @@ -256,7 +262,7 @@ test.describe( 'Image', () => { } ) => { await editor.insertBlock( { name: 'core/image' } ); - const imageBlock = page.locator( + const imageBlock = editor.canvas.locator( 'role=document[name="Block: Image"i]' ); const image = imageBlock.locator( 'role=img' ); @@ -300,7 +306,7 @@ test.describe( 'Image', () => { // Insert the block, upload a file and crop. await editor.insertBlock( { name: 'core/image' } ); - const imageBlock = page.locator( + const imageBlock = editor.canvas.locator( 'role=document[name="Block: Image"i]' ); const image = imageBlock.locator( 'role=img' ); @@ -366,7 +372,7 @@ test.describe( 'Image', () => { // Insert the block, upload a file and crop. await editor.insertBlock( { name: 'core/image' } ); - const imageBlock = page.locator( + const imageBlock = editor.canvas.locator( 'role=document[name="Block: Image"i]' ); const image = imageBlock.locator( 'role=img' ); @@ -423,7 +429,7 @@ test.describe( 'Image', () => { // Insert the block, upload a file and crop. await editor.insertBlock( { name: 'core/image' } ); - const imageBlock = page.locator( + const imageBlock = editor.canvas.locator( 'role=document[name="Block: Image"i]' ); const image = imageBlock.locator( 'role=img' ); @@ -459,7 +465,7 @@ test.describe( 'Image', () => { } ) => { await editor.insertBlock( { name: 'core/image' } ); - const imageBlock = page.locator( + const imageBlock = editor.canvas.locator( 'role=document[name="Block: Image"i]' ); const image = imageBlock.locator( 'role=img' ); @@ -513,13 +519,12 @@ test.describe( 'Image', () => { test( 'should undo without broken temporary state', async ( { editor, - page, pageUtils, imageBlockUtils, } ) => { await editor.insertBlock( { name: 'core/image' } ); - const imageBlock = page.locator( + const imageBlock = editor.canvas.locator( 'role=document[name="Block: Image"i]' ); const image = imageBlock.locator( 'role=img' ); @@ -529,7 +534,7 @@ test.describe( 'Image', () => { ); await expect( image ).toHaveAttribute( 'src', new RegExp( filename ) ); - await page.focus( '.wp-block-image' ); + await editor.canvas.focus( '.wp-block-image' ); await pageUtils.pressKeys( 'primary+z' ); // Expect an empty image block (placeholder) rather than one with a @@ -543,8 +548,15 @@ test.describe( 'Image', () => { page, editor, } ) => { + // To do: run with iframe. + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); await editor.insertBlock( { name: 'core/image' } ); - const imageBlock = page.getByRole( 'document', { + const imageBlock = editor.canvas.getByRole( 'document', { name: 'Block: Image', } ); const blockLibrary = page.getByRole( 'region', { @@ -637,7 +649,7 @@ test.describe( 'Image', () => { editor, } ) => { await editor.insertBlock( { name: 'core/image' } ); - const imageBlock = page.getByRole( 'document', { + const imageBlock = editor.canvas.getByRole( 'document', { name: 'Block: Image', } ); @@ -698,7 +710,7 @@ test.describe( 'Image', () => { page, } ) => { await editor.insertBlock( { name: 'core/image' } ); - const imageBlock = page.locator( + const imageBlock = editor.canvas.locator( 'role=document[name="Block: Image"i]' ); await expect( imageBlock ).toBeVisible(); @@ -756,7 +768,7 @@ test.describe( 'Image - interactivity', () => { await admin.createNewPost(); await editor.insertBlock( { name: 'core/image' } ); - const imageBlock = page.locator( + const imageBlock = editor.canvas.locator( 'role=document[name="Block: Image"i]' ); await expect( imageBlock ).toBeVisible(); @@ -828,11 +840,11 @@ test.describe( 'Image - interactivity', () => { const lightbox = page.locator( '.wp-lightbox-overlay' ); await expect( lightbox ).toBeHidden(); + await page.getByRole( 'button', { name: 'Enlarge image' } ).click(); + const image = lightbox.locator( 'img' ); await expect( image ).toHaveAttribute( 'src', new RegExp( filename ) ); - await page.getByRole( 'button', { name: 'Enlarge image' } ).click(); - await expect( lightbox ).toBeVisible(); const closeButton = lightbox.getByRole( 'button', { diff --git a/test/e2e/specs/editor/blocks/list.spec.js b/test/e2e/specs/editor/blocks/list.spec.js index a4af98f0ba057..c8be29ac2a64e 100644 --- a/test/e2e/specs/editor/blocks/list.spec.js +++ b/test/e2e/specs/editor/blocks/list.spec.js @@ -13,7 +13,7 @@ test.describe( 'List (@firefox)', () => { page, } ) => { // Create a block with some text that will trigger a list creation. - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '* A list item' ); // Create a second list item. @@ -38,7 +38,7 @@ test.describe( 'List (@firefox)', () => { pageUtils, } ) => { // Create a list with the slash block shortcut. - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'test' ); await pageUtils.pressKeys( 'ArrowLeft', { times: 4 } ); await page.keyboard.type( '* ' ); @@ -56,7 +56,7 @@ test.describe( 'List (@firefox)', () => { page, } ) => { // Create a block with some text that will trigger a list creation. - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '1) A list item' ); await expect.poll( editor.getEditedPostContent ).toBe( @@ -73,7 +73,7 @@ test.describe( 'List (@firefox)', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '1. ' ); await pageUtils.pressKeys( 'primary+z' ); @@ -88,7 +88,7 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '* ' ); await page.keyboard.press( 'Backspace' ); @@ -103,9 +103,11 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '* ' ); - await expect( page.locator( '[data-type="core/list"]' ) ).toBeVisible(); + await expect( + editor.canvas.locator( '[data-type="core/list"]' ) + ).toBeVisible(); await page.keyboard.press( 'Backspace' ); await expect.poll( editor.getEditedPostContent ).toBe( @@ -119,7 +121,7 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '* ' ); await editor.showBlockToolbar(); await page.keyboard.press( 'Backspace' ); @@ -135,10 +137,12 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.evaluate( () => delete window.requestIdleCallback ); await page.keyboard.type( '* ' ); - await expect( page.locator( '[data-type="core/list"]' ) ).toBeVisible(); + await expect( + editor.canvas.locator( '[data-type="core/list"]' ) + ).toBeVisible(); await page.keyboard.press( 'Backspace' ); await expect.poll( editor.getEditedPostContent ).toBe( @@ -152,7 +156,7 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '* ' ); await page.keyboard.press( 'Escape' ); @@ -167,7 +171,7 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '* a' ); await page.keyboard.press( 'Backspace' ); await page.keyboard.press( 'Backspace' ); @@ -179,9 +183,11 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '* ' ); - await expect( page.locator( '[data-type="core/list"]' ) ).toBeVisible(); + await expect( + editor.canvas.locator( '[data-type="core/list"]' ) + ).toBeVisible(); // Wait until the automatic change is marked as "final", which is done // with an idle callback, see __unstableMarkAutomaticChange. await page.evaluate( () => new Promise( window.requestIdleCallback ) ); @@ -194,7 +200,7 @@ test.describe( 'List (@firefox)', () => { test( 'can be created by typing "/list"', async ( { editor, page } ) => { // Create a list with the slash block shortcut. - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '/list' ); await expect( page.locator( 'role=option[name="List"i][selected]' ) @@ -215,7 +221,7 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'test' ); await editor.transformBlockTo( 'core/list' ); @@ -232,12 +238,12 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'one' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'two' ); await page.keyboard.down( 'Shift' ); - await page.click( '[data-type="core/paragraph"] >> nth=0' ); + await editor.canvas.click( '[data-type="core/paragraph"] >> nth=0' ); await page.keyboard.up( 'Shift' ); await editor.transformBlockTo( 'core/list' ); @@ -259,7 +265,7 @@ test.describe( 'List (@firefox)', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'one' ); await pageUtils.pressKeys( 'shift+Enter' ); await page.keyboard.type( 'two' ); @@ -283,14 +289,14 @@ test.describe( 'List (@firefox)', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'one' ); await pageUtils.pressKeys( 'shift+Enter' ); await page.keyboard.type( '...' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'two' ); await page.keyboard.down( 'Shift' ); - await page.click( '[data-type="core/paragraph"] >> nth=0' ); + await editor.canvas.click( '[data-type="core/paragraph"] >> nth=0' ); await page.keyboard.up( 'Shift' ); await editor.transformBlockTo( 'core/list' ); @@ -555,7 +561,7 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '1. one' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'two' ); @@ -729,6 +735,13 @@ test.describe( 'List (@firefox)', () => { } ); test( 'should indent and outdent level 2', async ( { editor, page } ) => { + // To do: run with iframe. + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); await editor.insertBlock( { name: 'core/list' } ); await page.keyboard.type( 'a' ); await page.keyboard.press( 'Enter' ); @@ -897,7 +910,7 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '* 1' ); // Should be at level 0. await page.keyboard.press( 'Enter' ); @@ -1011,7 +1024,7 @@ test.describe( 'List (@firefox)', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '* 1' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( ' a' ); @@ -1042,7 +1055,7 @@ test.describe( 'List (@firefox)', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '* 1' ); await page.keyboard.press( 'Enter' ); @@ -1065,7 +1078,7 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); // Tests the shortcut with a non breaking space. await page.keyboard.type( '*\u00a0' ); @@ -1081,7 +1094,7 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); // Tests the shortcut with a non breaking space. await page.keyboard.type( '* 1' ); @@ -1145,7 +1158,7 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '* 1' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( '2' ); @@ -1170,7 +1183,7 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '* 1' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( '2' ); @@ -1200,7 +1213,7 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '1. a' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'b' ); @@ -1255,7 +1268,7 @@ test.describe( 'List (@firefox)', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '* a' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'b' ); @@ -1298,7 +1311,7 @@ test.describe( 'List (@firefox)', () => { } ); test( 'can be exited to selected paragraph', async ( { editor, page } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '* ' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( '1' ); @@ -1324,7 +1337,7 @@ test.describe( 'List (@firefox)', () => { } ); await editor.selectBlocks( - page.locator( 'role=document[name="Block: List"i]' ) + editor.canvas.locator( 'role=document[name="Block: List"i]' ) ); await page.getByRole( 'button', { name: 'List', exact: true } ).click(); diff --git a/test/e2e/specs/editor/blocks/paragraph.spec.js b/test/e2e/specs/editor/blocks/paragraph.spec.js index ecade19a1aaa4..1c35f6ddc8958 100644 --- a/test/e2e/specs/editor/blocks/paragraph.spec.js +++ b/test/e2e/specs/editor/blocks/paragraph.spec.js @@ -28,7 +28,7 @@ test.describe( 'Paragraph', () => { } ); await page.keyboard.type( '1' ); - const firstBlockTagName = await page.evaluate( () => { + const firstBlockTagName = await editor.canvas.evaluate( () => { return document.querySelector( '[data-block]' ).tagName; } ); @@ -59,10 +59,16 @@ test.describe( 'Paragraph', () => { test( 'should allow dropping an image on an empty paragraph block', async ( { editor, - page, pageUtils, draggingUtils, + page, } ) => { + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); await editor.insertBlock( { name: 'core/paragraph' } ); const testImageName = '10x10_e2e_test_image_z9T8jK.png'; @@ -76,14 +82,18 @@ test.describe( 'Paragraph', () => { testImagePath ); - await dragOver( '[data-type="core/paragraph"]' ); + await dragOver( + editor.canvas.locator( '[data-type="core/paragraph"]' ) + ); await expect( draggingUtils.dropZone ).toBeVisible(); await expect( draggingUtils.insertionIndicator ).not.toBeVisible(); - await drop(); + await drop( + editor.canvas.locator( '[data-type="core/paragraph"]' ) + ); - const imageBlock = page.locator( + const imageBlock = editor.canvas.locator( 'role=document[name="Block: Image"i]' ); await expect( imageBlock ).toBeVisible(); @@ -103,7 +113,7 @@ test.describe( 'Paragraph', () => { attributes: { content: 'My Heading' }, } ); await editor.insertBlock( { name: 'core/paragraph' } ); - await page.focus( 'text=My Heading' ); + await editor.canvas.focus( 'text=My Heading' ); await editor.showBlockToolbar(); const dragHandle = page.locator( @@ -112,7 +122,7 @@ test.describe( 'Paragraph', () => { await dragHandle.hover(); await page.mouse.down(); - const emptyParagraph = page.locator( + const emptyParagraph = editor.canvas.locator( '[data-type="core/paragraph"][data-empty="true"]' ); const boundingBox = await emptyParagraph.boundingBox(); @@ -140,7 +150,7 @@ test.describe( 'Paragraph', () => { '

    My Heading

    ' ); - const emptyParagraph = page.locator( + const emptyParagraph = editor.canvas.locator( '[data-type="core/paragraph"][data-empty="true"]' ); const boundingBox = await emptyParagraph.boundingBox(); @@ -160,7 +170,6 @@ test.describe( 'Paragraph', () => { test.describe( 'Dragging positions', () => { test( 'Only the first block is an empty paragraph block', async ( { editor, - page, draggingUtils, } ) => { await editor.setContent( ` @@ -173,10 +182,10 @@ test.describe( 'Paragraph', () => { ` ); - const emptyParagraph = page.locator( + const emptyParagraph = editor.canvas.locator( '[data-type="core/paragraph"]' ); - const heading = page.locator( 'text=Heading' ); + const heading = editor.canvas.locator( 'text=Heading' ); await draggingUtils.simulateDraggingHTML( '

    Draggable

    ' @@ -271,7 +280,6 @@ test.describe( 'Paragraph', () => { test( 'Only the second block is an empty paragraph block', async ( { editor, - page, draggingUtils, } ) => { await editor.setContent( ` @@ -284,10 +292,10 @@ test.describe( 'Paragraph', () => { ` ); - const emptyParagraph = page.locator( + const emptyParagraph = editor.canvas.locator( '[data-type="core/paragraph"]' ); - const heading = page.locator( 'text=Heading' ); + const heading = editor.canvas.locator( 'text=Heading' ); await draggingUtils.simulateDraggingHTML( '

    Draggable

    ' @@ -382,7 +390,6 @@ test.describe( 'Paragraph', () => { test( 'Both blocks are empty paragraph blocks', async ( { editor, - page, draggingUtils, } ) => { await editor.setContent( ` @@ -395,10 +402,10 @@ test.describe( 'Paragraph', () => { ` ); - const firstEmptyParagraph = page + const firstEmptyParagraph = editor.canvas .locator( '[data-type="core/paragraph"]' ) .first(); - const secondEmptyParagraph = page + const secondEmptyParagraph = editor.canvas .locator( '[data-type="core/paragraph"]' ) .nth( 1 ); diff --git a/test/e2e/specs/editor/blocks/pullquote.spec.js b/test/e2e/specs/editor/blocks/pullquote.spec.js index 9b20204a624ec..f2a6698f5065f 100644 --- a/test/e2e/specs/editor/blocks/pullquote.spec.js +++ b/test/e2e/specs/editor/blocks/pullquote.spec.js @@ -12,7 +12,7 @@ test.describe( 'Quote', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'test' ); await editor.transformBlockTo( 'core/quote' ); diff --git a/test/e2e/specs/editor/blocks/quote.spec.js b/test/e2e/specs/editor/blocks/quote.spec.js index bff5bb6968535..44645005ff05e 100644 --- a/test/e2e/specs/editor/blocks/quote.spec.js +++ b/test/e2e/specs/editor/blocks/quote.spec.js @@ -33,7 +33,7 @@ test.describe( 'Quote', () => { page, } ) => { // Create a block with some text that will trigger a paragraph creation. - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '> A quote' ); // Create a second paragraph. await page.keyboard.press( 'Enter' ); @@ -56,7 +56,7 @@ test.describe( 'Quote', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'test' ); await pageUtils.pressKeys( 'ArrowLeft', { times: 'test'.length } ); await page.keyboard.type( '> ' ); @@ -71,7 +71,7 @@ test.describe( 'Quote', () => { test( 'can be created by typing "/quote"', async ( { editor, page } ) => { // Create a list with the slash block shortcut. - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '/quote' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'I’m a quote' ); @@ -88,7 +88,7 @@ test.describe( 'Quote', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'test' ); await editor.transformBlockTo( 'core/quote' ); expect( await editor.getEditedPostContent() ).toBe( @@ -104,12 +104,12 @@ test.describe( 'Quote', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'one' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'two' ); await page.keyboard.down( 'Shift' ); - await page.click( + await editor.canvas.click( 'role=document[name="Paragraph block"i] >> text=one' ); await page.keyboard.up( 'Shift' ); diff --git a/test/e2e/specs/editor/blocks/separator.spec.js b/test/e2e/specs/editor/blocks/separator.spec.js index 8f195392641c8..a2e088e14c398 100644 --- a/test/e2e/specs/editor/blocks/separator.spec.js +++ b/test/e2e/specs/editor/blocks/separator.spec.js @@ -12,7 +12,7 @@ test.describe( 'Separator', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '---' ); await page.keyboard.press( 'Enter' ); diff --git a/test/e2e/specs/editor/blocks/spacer.spec.js b/test/e2e/specs/editor/blocks/spacer.spec.js index 41e63c2e4e9de..77e978a0df302 100644 --- a/test/e2e/specs/editor/blocks/spacer.spec.js +++ b/test/e2e/specs/editor/blocks/spacer.spec.js @@ -10,7 +10,7 @@ test.describe( 'Spacer', () => { test( 'can be created by typing "/spacer"', async ( { editor, page } ) => { // Create a spacer with the slash block shortcut. - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '/spacer' ); await page.keyboard.press( 'Enter' ); @@ -22,11 +22,11 @@ test.describe( 'Spacer', () => { editor, } ) => { // Create a spacer with the slash block shortcut. - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '/spacer' ); await page.keyboard.press( 'Enter' ); - const resizableHandle = page.locator( + const resizableHandle = editor.canvas.locator( // Use class name selector until we have `data-testid` for the resize handles. 'role=document[name="Block: Spacer"i] >> css=.components-resizable-box__handle' ); @@ -39,7 +39,7 @@ test.describe( 'Spacer', () => { expect( await editor.getEditedPostContent() ).toMatchSnapshot(); await expect( - page.locator( 'role=document[name="Block: Spacer"i]' ) + editor.canvas.locator( 'role=document[name="Block: Spacer"i]' ) ).toBeFocused(); } ); } ); diff --git a/test/e2e/specs/editor/blocks/table.spec.js b/test/e2e/specs/editor/blocks/table.spec.js index d206089e3f4e3..689989f9022a3 100644 --- a/test/e2e/specs/editor/blocks/table.spec.js +++ b/test/e2e/specs/editor/blocks/table.spec.js @@ -15,7 +15,7 @@ test.describe( 'Table', () => { await editor.insertBlock( { name: 'core/table' } ); // Check for existence of the column count field. - const columnCountInput = page.locator( + const columnCountInput = editor.canvas.locator( 'role=spinbutton[name="Column count"i]' ); await expect( columnCountInput ).toBeVisible(); @@ -27,7 +27,7 @@ test.describe( 'Table', () => { await page.keyboard.type( '5' ); // Check for existence of the row count field. - const rowCountInput = page.locator( + const rowCountInput = editor.canvas.locator( 'role=spinbutton[name="Row count"i]' ); await expect( rowCountInput ).toBeVisible(); @@ -39,7 +39,7 @@ test.describe( 'Table', () => { await page.keyboard.type( '10' ); // Create the table. - await page.click( 'role=button[name="Create Table"i]' ); + await editor.canvas.click( 'role=button[name="Create Table"i]' ); // Expect the post content to have a correctly sized table. expect( await editor.getEditedPostContent() ).toMatchSnapshot(); @@ -49,10 +49,12 @@ test.describe( 'Table', () => { await editor.insertBlock( { name: 'core/table' } ); // Create the table. - await page.click( 'role=button[name="Create Table"i]' ); + await editor.canvas.click( 'role=button[name="Create Table"i]' ); // Click the first cell and add some text. - await page.click( 'role=textbox[name="Body cell text"i] >> nth=0' ); + await editor.canvas.click( + 'role=textbox[name="Body cell text"i] >> nth=0' + ); await page.keyboard.type( 'This' ); // Navigate to the next cell and add some text. @@ -90,7 +92,7 @@ test.describe( 'Table', () => { await expect( footerSwitch ).toBeHidden(); // // Create the table. - await page.click( 'role=button[name="Create Table"i]' ); + await editor.canvas.click( 'role=button[name="Create Table"i]' ); // Expect the header and footer switches to be present now that the table has been created. await page.click( @@ -103,17 +105,17 @@ test.describe( 'Table', () => { await headerSwitch.check(); await footerSwitch.check(); - await page.click( + await editor.canvas.click( 'role=rowgroup >> nth=0 >> role=textbox[name="Header cell text"i] >> nth=0' ); await page.keyboard.type( 'header' ); - await page.click( + await editor.canvas.click( 'role=rowgroup >> nth=1 >> role=textbox[name="Body cell text"i] >> nth=0' ); await page.keyboard.type( 'body' ); - await page.click( + await editor.canvas.click( 'role=rowgroup >> nth=2 >> role=textbox[name="Footer cell text"i] >> nth=0' ); await page.keyboard.type( 'footer' ); @@ -137,7 +139,7 @@ test.describe( 'Table', () => { await editor.openDocumentSettingsSidebar(); // Create the table. - await page.click( 'role=button[name="Create Table"i]' ); + await editor.canvas.click( 'role=button[name="Create Table"i]' ); // Toggle on the switches and add some content. await page.click( @@ -145,7 +147,9 @@ test.describe( 'Table', () => { ); await page.locator( 'role=checkbox[name="Header section"i]' ).check(); await page.locator( 'role=checkbox[name="Footer section"i]' ).check(); - await page.click( 'role=textbox[name="Body cell text"i] >> nth=0' ); + await editor.canvas.click( + 'role=textbox[name="Body cell text"i] >> nth=0' + ); // Add a column. await editor.clickBlockToolbarButton( 'Edit table' ); @@ -154,7 +158,9 @@ test.describe( 'Table', () => { // Expect the table to have 3 columns across the header, body and footer. expect( await editor.getEditedPostContent() ).toMatchSnapshot(); - await page.click( 'role=textbox[name="Body cell text"i] >> nth=0' ); + await editor.canvas.click( + 'role=textbox[name="Body cell text"i] >> nth=0' + ); // Delete a column. await editor.clickBlockToolbarButton( 'Edit table' ); @@ -167,15 +173,17 @@ test.describe( 'Table', () => { test( 'allows columns to be aligned', async ( { editor, page } ) => { await editor.insertBlock( { name: 'core/table' } ); - await page.click( 'role=spinbutton[name="Column count"i]' ); + await editor.canvas.click( 'role=spinbutton[name="Column count"i]' ); await page.keyboard.press( 'Backspace' ); await page.keyboard.type( '4' ); // Create the table. - await page.click( 'role=button[name="Create Table"i]' ); + await editor.canvas.click( 'role=button[name="Create Table"i]' ); // Click the first cell and add some text. Don't align. - const cells = page.locator( 'role=textbox[name="Body cell text"i]' ); + const cells = editor.canvas.locator( + 'role=textbox[name="Body cell text"i]' + ); await cells.nth( 0 ).click(); await page.keyboard.type( 'None' ); @@ -210,7 +218,7 @@ test.describe( 'Table', () => { await editor.openDocumentSettingsSidebar(); // Create the table. - await page.click( 'role=button[name="Create Table"i]' ); + await editor.canvas.click( 'role=button[name="Create Table"i]' ); // Enable fixed width as it exacerbates the amount of empty space around the RichText. await page.click( @@ -221,11 +229,13 @@ test.describe( 'Table', () => { .check(); // Add multiple new lines to the first cell to make it taller. - await page.click( 'role=textbox[name="Body cell text"i] >> nth=0' ); + await editor.canvas.click( + 'role=textbox[name="Body cell text"i] >> nth=0' + ); await page.keyboard.type( '\n\n\n\n' ); // Get the bounding client rect for the second cell. - const { x: secondCellX, y: secondCellY } = await page + const { x: secondCellX, y: secondCellY } = await editor.canvas .locator( 'role=textbox[name="Body cell text"] >> nth=1' ) .boundingBox(); @@ -241,10 +251,12 @@ test.describe( 'Table', () => { await editor.insertBlock( { name: 'core/table' } ); // Create the table. - await page.click( 'role=button[name="Create Table"i]' ); + await editor.canvas.click( 'role=button[name="Create Table"i]' ); // Click the first cell and add some text. - await page.click( 'role=document[name="Block: Table"i] >> figcaption' ); + await editor.canvas.click( + 'role=document[name="Block: Table"i] >> figcaption' + ); await page.keyboard.type( 'Caption!' ); expect( await editor.getEditedPostContent() ).toMatchSnapshot(); } ); @@ -252,7 +264,7 @@ test.describe( 'Table', () => { test( 'up and down arrow navigation', async ( { editor, page } ) => { await editor.insertBlock( { name: 'core/table' } ); // Create the table. - await page.click( 'role=button[name="Create Table"i]' ); + await editor.canvas.click( 'role=button[name="Create Table"i]' ); await page.keyboard.type( '1' ); await page.keyboard.press( 'ArrowDown' ); await page.keyboard.type( '2' ); @@ -263,19 +275,18 @@ test.describe( 'Table', () => { expect( await editor.getEditedPostContent() ).toMatchSnapshot(); } ); - test( 'should not have focus loss after creation', async ( { - editor, - page, - } ) => { + test( 'should not have focus loss after creation', async ( { editor } ) => { // Insert table block. await editor.insertBlock( { name: 'core/table' } ); // Create the table. - await page.click( 'role=button[name="Create Table"i]' ); + await editor.canvas.click( 'role=button[name="Create Table"i]' ); // Focus should be in first td. await expect( - page.locator( 'role=textbox[name="Body cell text"i] >> nth=0' ) + editor.canvas.locator( + 'role=textbox[name="Body cell text"i] >> nth=0' + ) ).toBeFocused(); } ); } ); diff --git a/test/e2e/specs/editor/plugins/custom-post-types.spec.js b/test/e2e/specs/editor/plugins/custom-post-types.spec.js index 07d3275563282..55207df05175b 100644 --- a/test/e2e/specs/editor/plugins/custom-post-types.spec.js +++ b/test/e2e/specs/editor/plugins/custom-post-types.spec.js @@ -20,7 +20,7 @@ test.describe( 'Test Custom Post Types', () => { page, } ) => { await admin.createNewPost( { postType: 'hierar-no-title' } ); - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'Parent Post' ); await editor.publishPost(); @@ -53,7 +53,7 @@ test.describe( 'Test Custom Post Types', () => { await page.getByRole( 'listbox' ).getByRole( 'option' ).first().click(); const parentPage = await parentPageLocator.inputValue(); - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'Child Post' ); await editor.publishPost(); await page.reload(); @@ -68,7 +68,7 @@ test.describe( 'Test Custom Post Types', () => { page, } ) => { await admin.createNewPost( { postType: 'leg_block_in_tpl' } ); - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'Hello there' ); await expect.poll( editor.getBlocks ).toMatchObject( [ diff --git a/test/e2e/specs/editor/plugins/format-api.spec.js b/test/e2e/specs/editor/plugins/format-api.spec.js index 21e942ddc2199..f98d8292ea8f6 100644 --- a/test/e2e/specs/editor/plugins/format-api.spec.js +++ b/test/e2e/specs/editor/plugins/format-api.spec.js @@ -21,7 +21,7 @@ test.describe( 'Using Format API', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'First paragraph' ); await pageUtils.pressKeys( 'shiftAlt+ArrowLeft' ); await editor.clickBlockToolbarButton( 'More' ); diff --git a/test/e2e/specs/editor/plugins/hooks-api.spec.js b/test/e2e/specs/editor/plugins/hooks-api.spec.js index 675b3861ee2a2..7257ccde72964 100644 --- a/test/e2e/specs/editor/plugins/hooks-api.spec.js +++ b/test/e2e/specs/editor/plugins/hooks-api.spec.js @@ -19,8 +19,9 @@ test.describe( 'Using Hooks API', () => { test( 'Should contain a reset block button on the sidebar', async ( { page, + editor, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'First paragraph' ); await page.click( `role=region[name="Editor settings"i] >> role=tab[name="Settings"i]` @@ -34,10 +35,10 @@ test.describe( 'Using Hooks API', () => { editor, page, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'First paragraph' ); - const paragraphBlock = page.locator( + const paragraphBlock = editor.canvas.locator( 'role=document[name="Paragraph block"i]' ); await expect( paragraphBlock ).toHaveText( 'First paragraph' ); diff --git a/test/e2e/specs/editor/plugins/iframed-block.spec.js b/test/e2e/specs/editor/plugins/iframed-block.spec.js index 55b67cb70fe86..c5529d9108e9f 100644 --- a/test/e2e/specs/editor/plugins/iframed-block.spec.js +++ b/test/e2e/specs/editor/plugins/iframed-block.spec.js @@ -18,7 +18,9 @@ test.describe( 'Iframed block', () => { expect( await editor.getEditedPostContent() ).toMatchSnapshot(); await expect( - page.locator( 'role=document[name="Block: Iframed Block"i]' ) + editor.canvas.locator( + 'role=document[name="Block: Iframed Block"i]' + ) ).toContainText( 'Iframed Block (set with jQuery)' ); // open page from sidebar settings diff --git a/test/e2e/specs/editor/plugins/image-size.spec.js b/test/e2e/specs/editor/plugins/image-size.spec.js index a7502c93a2476..f2ba0e91b6733 100644 --- a/test/e2e/specs/editor/plugins/image-size.spec.js +++ b/test/e2e/specs/editor/plugins/image-size.spec.js @@ -52,7 +52,7 @@ test.describe( 'changing image size', () => { // Verify that the custom size was applied to the image. await expect( - page.locator( `role=img[name="${ filename }"]` ) + editor.canvas.locator( `role=img[name="${ filename }"]` ) ).toHaveCSS( 'width', '499px' ); await expect( page.locator( 'role=spinbutton[name="Width"i]' ) diff --git a/test/e2e/specs/editor/plugins/post-type-templates.spec.js b/test/e2e/specs/editor/plugins/post-type-templates.spec.js index 2caffdf52abe2..c743d08d8ae68 100644 --- a/test/e2e/specs/editor/plugins/post-type-templates.spec.js +++ b/test/e2e/specs/editor/plugins/post-type-templates.spec.js @@ -35,7 +35,7 @@ test.describe( 'Post type templates', () => { // Remove a block from the template to verify that it's not // re-added after saving and reloading the editor. - await page.focus( 'role=textbox[name="Add title"i]' ); + await editor.canvas.focus( 'role=textbox[name="Add title"i]' ); await page.keyboard.press( 'ArrowDown' ); await page.keyboard.press( 'Backspace' ); await page.click( 'role=button[name="Save draft"i]' ); @@ -64,7 +64,7 @@ test.describe( 'Post type templates', () => { } ) => { // Remove all blocks from the template to verify that they're not // re-added after saving and reloading the editor. - await page.fill( + await editor.canvas.fill( 'role=textbox[name="Add title"i]', 'My Empty Book' ); @@ -125,11 +125,11 @@ test.describe( 'Post type templates', () => { // Remove the default block template to verify that it's not // re-added after saving and reloading the editor. - await page.fill( + await editor.canvas.fill( 'role=textbox[name="Add title"i]', 'My Image Format' ); - await page.focus( 'role=document[name="Block: Image"i]' ); + await editor.canvas.focus( 'role=document[name="Block: Image"i]' ); await page.keyboard.press( 'Backspace' ); await page.click( 'role=button[name="Save draft"i]' ); await expect( diff --git a/test/e2e/specs/editor/plugins/wp-editor-meta-box.spec.js b/test/e2e/specs/editor/plugins/wp-editor-meta-box.spec.js index 27cf0b7b160bd..13720de509e3c 100644 --- a/test/e2e/specs/editor/plugins/wp-editor-meta-box.spec.js +++ b/test/e2e/specs/editor/plugins/wp-editor-meta-box.spec.js @@ -20,7 +20,10 @@ test.describe( 'WP Editor Meta Boxes', () => { await admin.createNewPost(); // Add title to enable valid non-empty post save. - await page.type( 'role=textbox[name="Add title"i]', 'Hello Meta' ); + await editor.canvas.type( + 'role=textbox[name="Add title"i]', + 'Hello Meta' + ); // Type something. await page.click( 'role=button[name="Text"i]' ); diff --git a/test/e2e/specs/editor/various/a11y.spec.js b/test/e2e/specs/editor/various/a11y.spec.js index 5725f216d1cf2..8b819d3866b6c 100644 --- a/test/e2e/specs/editor/various/a11y.spec.js +++ b/test/e2e/specs/editor/various/a11y.spec.js @@ -20,10 +20,18 @@ test.describe( 'a11y (@firefox, @webkit)', () => { test( 'navigating through the Editor regions four times should land on the Editor top bar region', async ( { page, pageUtils, + editor, } ) => { + // To do: run with iframe. + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); // On a new post, initial focus is set on the Post title. await expect( - page.locator( 'role=textbox[name=/Add title/i]' ) + editor.canvas.locator( 'role=textbox[name=/Add title/i]' ) ).toBeFocused(); // Navigate to the 'Editor settings' region. await pageUtils.pressKeys( 'ctrl+`' ); @@ -47,6 +55,13 @@ test.describe( 'a11y (@firefox, @webkit)', () => { page, pageUtils, } ) => { + // To do: run with iframe. + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); // Open keyboard shortcuts modal. await pageUtils.pressKeys( 'access+h' ); diff --git a/test/e2e/specs/editor/various/behaviors.spec.js b/test/e2e/specs/editor/various/behaviors.spec.js index 12be68b8f9479..519b6f8713e87 100644 --- a/test/e2e/specs/editor/various/behaviors.spec.js +++ b/test/e2e/specs/editor/various/behaviors.spec.js @@ -216,6 +216,43 @@ test.describe( 'Testing behaviors functionality', () => { await select.selectOption( { label: 'No behaviors' } ); await expect( select ).toHaveValue( '' ); } ); + + test( 'Lightbox behavior is disabled if the Image has a link', async ( { + admin, + editor, + requestUtils, + page, + behaviorUtils, + } ) => { + // In this theme, the default value for settings.behaviors.blocks.core/image.lightbox is `true`. + await requestUtils.activateTheme( 'behaviors-enabled' ); + await admin.createNewPost(); + const media = await behaviorUtils.createMedia(); + + await editor.insertBlock( { + name: 'core/image', + attributes: { + alt: filename, + id: media.id, + url: media.source_url, + linkDestination: 'custom', + }, + } ); + + await editor.openDocumentSettingsSidebar(); + const editorSettings = page.getByRole( 'region', { + name: 'Editor settings', + } ); + await editorSettings + .getByRole( 'button', { name: 'Advanced' } ) + .click(); + const select = editorSettings.getByRole( 'combobox', { + name: 'Behavior', + } ); + + // The behaviors dropdown should be present but disabled. + await expect( select ).toBeDisabled(); + } ); } ); class BehaviorUtils { diff --git a/test/e2e/specs/editor/various/block-deletion.spec.js b/test/e2e/specs/editor/various/block-deletion.spec.js index d02a9167c0c3a..9fcacae05b63f 100644 --- a/test/e2e/specs/editor/various/block-deletion.spec.js +++ b/test/e2e/specs/editor/various/block-deletion.spec.js @@ -37,7 +37,7 @@ test.describe( 'Block deletion', () => { // Remove the current paragraph via the Block Toolbar options menu. await editor.showBlockToolbar(); - await editor.canvas + await page .getByRole( 'toolbar', { name: 'Block tools' } ) .getByRole( 'button', { name: 'Options' } ) .click(); @@ -84,7 +84,7 @@ test.describe( 'Block deletion', () => { // Remove the current paragraph via the Block Toolbar options menu. await editor.showBlockToolbar(); - await editor.canvas + await page .getByRole( 'toolbar', { name: 'Block tools' } ) .getByRole( 'button', { name: 'Options' } ) .click(); @@ -313,7 +313,7 @@ test.describe( 'Block deletion', () => { // Remove that paragraph via its options menu. await editor.showBlockToolbar(); - await editor.canvas + await page .getByRole( 'toolbar', { name: 'Block tools' } ) .getByRole( 'button', { name: 'Options' } ) .click(); diff --git a/test/e2e/specs/editor/various/block-mover.spec.js b/test/e2e/specs/editor/various/block-mover.spec.js index e90ee5f7f0122..4ed90191f2558 100644 --- a/test/e2e/specs/editor/various/block-mover.spec.js +++ b/test/e2e/specs/editor/various/block-mover.spec.js @@ -23,7 +23,7 @@ test.describe( 'block mover', () => { } ); // Select a block so the block mover is rendered. - await page.focus( 'text=First Paragraph' ); + await editor.canvas.focus( 'text=First Paragraph' ); await editor.showBlockToolbar(); const moveDownButton = page.locator( @@ -47,7 +47,7 @@ test.describe( 'block mover', () => { attributes: { content: 'First Paragraph' }, } ); // Select a block so the block mover has the possibility of being rendered. - await page.focus( 'text=First Paragraph' ); + await editor.canvas.focus( 'text=First Paragraph' ); await editor.showBlockToolbar(); // Ensure no block mover exists when only one block exists on the page. diff --git a/test/e2e/specs/editor/various/compatibility-classic-editor.spec.js b/test/e2e/specs/editor/various/compatibility-classic-editor.spec.js index 0ea1908cd90ef..a1efbfa579b9a 100644 --- a/test/e2e/specs/editor/various/compatibility-classic-editor.spec.js +++ b/test/e2e/specs/editor/various/compatibility-classic-editor.spec.js @@ -17,7 +17,7 @@ test.describe( 'Compatibility with classic editor', () => { editor, } ) => { await editor.insertBlock( { name: 'core/html' } ); - await page.focus( 'role=textbox[name="HTML"i]' ); + await editor.canvas.focus( 'role=textbox[name="HTML"i]' ); await page.keyboard.type( '' ); await page.keyboard.type( 'Random Link' ); await page.keyboard.type( ' ' ); diff --git a/test/e2e/specs/editor/various/content-only-lock.spec.js b/test/e2e/specs/editor/various/content-only-lock.spec.js index c215da33f3ec5..962fe0a627909 100644 --- a/test/e2e/specs/editor/various/content-only-lock.spec.js +++ b/test/e2e/specs/editor/various/content-only-lock.spec.js @@ -23,8 +23,8 @@ test.describe( 'Content-only lock', () => { ` ); await pageUtils.pressKeys( 'secondary+M' ); - - await page.click( 'role=document[name="Paragraph block"i]' ); + await page.waitForSelector( 'iframe[name="editor-canvas"]' ); + await editor.canvas.click( 'role=document[name="Paragraph block"i]' ); await page.keyboard.type( ' World' ); expect( await editor.getEditedPostContent() ).toMatchSnapshot(); } ); diff --git a/test/e2e/specs/editor/various/copy-cut-paste.spec.js b/test/e2e/specs/editor/various/copy-cut-paste.spec.js index cb040504de4c8..823926c1121a0 100644 --- a/test/e2e/specs/editor/various/copy-cut-paste.spec.js +++ b/test/e2e/specs/editor/various/copy-cut-paste.spec.js @@ -13,7 +13,7 @@ test.describe( 'Copy/cut/paste', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'Copy - collapsed selection' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( '2' ); @@ -31,7 +31,14 @@ test.describe( 'Copy/cut/paste', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + // To do: run with iframe. + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'Cut - collapsed selection' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( '2' ); @@ -59,7 +66,7 @@ test.describe( 'Copy/cut/paste', () => { await page.evaluate( () => { window.wp.data.dispatch( 'core/block-editor' ).clearSelectedBlock(); } ); - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await pageUtils.pressKeys( 'primary+v' ); expect( await editor.getEditedPostContent() ).toMatchSnapshot(); } ); @@ -78,7 +85,7 @@ test.describe( 'Copy/cut/paste', () => { await page.evaluate( () => { window.wp.data.dispatch( 'core/block-editor' ).clearSelectedBlock(); } ); - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await pageUtils.pressKeys( 'primary+v' ); expect( await editor.getEditedPostContent() ).toMatchSnapshot(); } ); @@ -88,7 +95,7 @@ test.describe( 'Copy/cut/paste', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'First block' ); await page.keyboard.press( 'Enter' ); @@ -240,7 +247,7 @@ test.describe( 'Copy/cut/paste', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'A block' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'B block' ); @@ -252,7 +259,7 @@ test.describe( 'Copy/cut/paste', () => { await pageUtils.pressKeys( 'primary+ArrowLeft' ); // Sometimes the caret has not moved to the correct position before pressing Enter. // @see https://github.com/WordPress/gutenberg/issues/40303#issuecomment-1109434887 - await page.waitForFunction( + await editor.canvas.waitForFunction( () => window.getSelection().type === 'Caret' ); // Create a new block at the top of the document to paste there. @@ -267,7 +274,7 @@ test.describe( 'Copy/cut/paste', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'A block' ); await editor.insertBlock( { name: 'core/spacer' } ); await page.keyboard.press( 'Enter' ); @@ -280,7 +287,7 @@ test.describe( 'Copy/cut/paste', () => { await pageUtils.pressKeys( 'primary+ArrowLeft' ); // Sometimes the caret has not moved to the correct position before pressing Enter. // @see https://github.com/WordPress/gutenberg/issues/40303#issuecomment-1109434887 - await page.waitForFunction( + await editor.canvas.waitForFunction( () => window.getSelection().type === 'Caret' ); // Create a new block at the top of the document to paste there. @@ -295,7 +302,7 @@ test.describe( 'Copy/cut/paste', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'A block' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'B block' ); @@ -307,7 +314,7 @@ test.describe( 'Copy/cut/paste', () => { await pageUtils.pressKeys( 'primary+ArrowLeft' ); // Sometimes the caret has not moved to the correct position before pressing Enter. // @see https://github.com/WordPress/gutenberg/issues/40303#issuecomment-1109434887 - await page.waitForFunction( + await editor.canvas.waitForFunction( () => window.getSelection().type === 'Caret' ); // Create a new block at the top of the document to paste there. @@ -322,7 +329,7 @@ test.describe( 'Copy/cut/paste', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'A block' ); await editor.insertBlock( { name: 'core/spacer' } ); await page.keyboard.press( 'Enter' ); @@ -335,7 +342,7 @@ test.describe( 'Copy/cut/paste', () => { await pageUtils.pressKeys( 'primary+ArrowLeft' ); // Sometimes the caret has not moved to the correct position before pressing Enter. // @see https://github.com/WordPress/gutenberg/issues/40303#issuecomment-1109434887 - await page.waitForFunction( + await editor.canvas.waitForFunction( () => window.getSelection().type === 'Caret' ); // Create a new block at the top of the document to paste there. @@ -362,7 +369,7 @@ test.describe( 'Copy/cut/paste', () => { await pageUtils.pressKeys( 'primary+ArrowLeft' ); // Sometimes the caret has not moved to the correct position before pressing Enter. // @see https://github.com/WordPress/gutenberg/issues/40303#issuecomment-1109434887 - await page.waitForFunction( + await editor.canvas.waitForFunction( () => window.getSelection().type === 'Caret' ); // Create a new block at the top of the document to paste there. @@ -389,7 +396,7 @@ test.describe( 'Copy/cut/paste', () => { await pageUtils.pressKeys( 'primary+ArrowLeft' ); // Sometimes the caret has not moved to the correct position before pressing Enter. // @see https://github.com/WordPress/gutenberg/issues/40303#issuecomment-1109434887 - await page.waitForFunction( + await editor.canvas.waitForFunction( () => window.getSelection().type === 'Caret' ); // Create a new code block to paste there. @@ -399,8 +406,8 @@ test.describe( 'Copy/cut/paste', () => { } ); test( 'should paste single line in post title', async ( { - page, pageUtils, + editor, } ) => { // This test checks whether we are correctly handling single line // pasting in the post title. Previously we were accidentally falling @@ -413,13 +420,16 @@ test.describe( 'Copy/cut/paste', () => { await pageUtils.pressKeys( 'primary+v' ); // Expect the span to be filtered out. expect( - await page.evaluate( () => document.activeElement.innerHTML ) + await editor.canvas.evaluate( + () => document.activeElement.innerHTML + ) ).toMatchSnapshot(); } ); test( 'should paste single line in post title with existing content', async ( { page, pageUtils, + editor, } ) => { await page.keyboard.type( 'ab' ); await page.keyboard.press( 'ArrowLeft' ); @@ -430,7 +440,9 @@ test.describe( 'Copy/cut/paste', () => { // Ensure the selection is correct. await page.keyboard.type( 'y' ); expect( - await page.evaluate( () => document.activeElement.innerHTML ) + await editor.canvas.evaluate( + () => document.activeElement.innerHTML + ) ).toBe( 'axyb' ); } ); diff --git a/test/e2e/specs/editor/various/draggable-blocks.spec.js b/test/e2e/specs/editor/various/draggable-blocks.spec.js index d73040bafa48c..a66efe4540f38 100644 --- a/test/e2e/specs/editor/various/draggable-blocks.spec.js +++ b/test/e2e/specs/editor/various/draggable-blocks.spec.js @@ -42,7 +42,9 @@ test.describe( 'Draggable block', () => {

    2

    ` ); - await page.focus( 'role=document[name="Paragraph block"i] >> text=2' ); + await editor.canvas.focus( + 'role=document[name="Paragraph block"i] >> text=2' + ); await editor.showBlockToolbar(); const dragHandle = page.locator( @@ -54,7 +56,7 @@ test.describe( 'Draggable block', () => { await page.mouse.down(); // Move to and hover on the upper half of the paragraph block to trigger the indicator. - const firstParagraph = page.locator( + const firstParagraph = editor.canvas.locator( 'role=document[name="Paragraph block"i] >> text=1' ); const firstParagraphBound = await firstParagraph.boundingBox(); @@ -112,7 +114,9 @@ test.describe( 'Draggable block', () => {

    2

    ` ); - await page.focus( 'role=document[name="Paragraph block"i] >> text=1' ); + await editor.canvas.focus( + 'role=document[name="Paragraph block"i] >> text=1' + ); await editor.showBlockToolbar(); const dragHandle = page.locator( @@ -124,7 +128,7 @@ test.describe( 'Draggable block', () => { await page.mouse.down(); // Move to and hover on the bottom half of the paragraph block to trigger the indicator. - const secondParagraph = page.locator( + const secondParagraph = editor.canvas.locator( 'role=document[name="Paragraph block"i] >> text=2' ); const secondParagraphBound = await secondParagraph.boundingBox(); @@ -193,7 +197,9 @@ test.describe( 'Draggable block', () => { ], } ); - await page.focus( 'role=document[name="Paragraph block"i] >> text=2' ); + await editor.canvas.focus( + 'role=document[name="Paragraph block"i] >> text=2' + ); await editor.showBlockToolbar(); const dragHandle = page.locator( @@ -205,7 +211,7 @@ test.describe( 'Draggable block', () => { await page.mouse.down(); // Move to and hover on the left half of the paragraph block to trigger the indicator. - const firstParagraph = page.locator( + const firstParagraph = editor.canvas.locator( 'role=document[name="Paragraph block"i] >> text=1' ); const firstParagraphBound = await firstParagraph.boundingBox(); @@ -272,7 +278,9 @@ test.describe( 'Draggable block', () => { ], } ); - await page.focus( 'role=document[name="Paragraph block"i] >> text=1' ); + await editor.canvas.focus( + 'role=document[name="Paragraph block"i] >> text=1' + ); await editor.showBlockToolbar(); const dragHandle = page.locator( @@ -284,7 +292,7 @@ test.describe( 'Draggable block', () => { await page.mouse.down(); // Move to and hover on the right half of the paragraph block to trigger the indicator. - const secondParagraph = page.locator( + const secondParagraph = editor.canvas.locator( 'role=document[name="Paragraph block"i] >> text=2' ); const secondParagraphBound = await secondParagraph.boundingBox(); @@ -334,6 +342,13 @@ test.describe( 'Draggable block', () => { editor, pageUtils, } ) => { + // To do: run with iframe. + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); // Insert a row. await editor.insertBlock( { name: 'core/group', diff --git a/test/e2e/specs/editor/various/font-size-picker.spec.js b/test/e2e/specs/editor/various/font-size-picker.spec.js index e63a5984443bc..ddc47e3ee6de6 100644 --- a/test/e2e/specs/editor/various/font-size-picker.spec.js +++ b/test/e2e/specs/editor/various/font-size-picker.spec.js @@ -24,7 +24,9 @@ test.describe( 'Font Size Picker', () => { page, } ) => { await editor.openDocumentSettingsSidebar(); - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( + 'role=button[name="Add default block"i]' + ); await page.keyboard.type( 'Paragraph to be made "small"' ); await page.click( 'role=region[name="Editor settings"i] >> role=button[name="Set custom size"i]' @@ -45,7 +47,9 @@ test.describe( 'Font Size Picker', () => { pageUtils, } ) => { await editor.openDocumentSettingsSidebar(); - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( + 'role=button[name="Add default block"i]' + ); await page.keyboard.type( 'Paragraph reset - custom size' ); await page.click( 'role=region[name="Editor settings"i] >> role=button[name="Set custom size"i]' @@ -135,7 +139,9 @@ test.describe( 'Font Size Picker', () => { pageUtils, } ) => { await editor.openDocumentSettingsSidebar(); - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( + 'role=button[name="Add default block"i]' + ); await page.keyboard.type( 'Paragraph to be made "large"' ); await page.click( 'role=group[name="Font size"i] >> role=button[name="Font size"i]' @@ -155,7 +161,9 @@ test.describe( 'Font Size Picker', () => { pageUtils, } ) => { await editor.openDocumentSettingsSidebar(); - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( + 'role=button[name="Add default block"i]' + ); await page.keyboard.type( 'Paragraph with font size reset using tools panel menu' ); @@ -186,7 +194,9 @@ test.describe( 'Font Size Picker', () => { pageUtils, } ) => { await editor.openDocumentSettingsSidebar(); - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( + 'role=button[name="Add default block"i]' + ); await page.keyboard.type( 'Paragraph with font size reset using input field' ); @@ -221,7 +231,9 @@ test.describe( 'Font Size Picker', () => { page, } ) => { await editor.openDocumentSettingsSidebar(); - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( + 'role=button[name="Add default block"i]' + ); await page.keyboard.type( 'Paragraph to be made "large"' ); await page.click( 'role=radiogroup[name="Font size"i] >> role=radio[name="Large"i]' @@ -238,7 +250,9 @@ test.describe( 'Font Size Picker', () => { page, } ) => { await editor.openDocumentSettingsSidebar(); - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( + 'role=button[name="Add default block"i]' + ); await page.keyboard.type( 'Paragraph with font size reset using tools panel menu' ); @@ -267,7 +281,9 @@ test.describe( 'Font Size Picker', () => { pageUtils, } ) => { await editor.openDocumentSettingsSidebar(); - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( + 'role=button[name="Add default block"i]' + ); await page.keyboard.type( 'Paragraph with font size reset using input field' ); diff --git a/test/e2e/specs/editor/various/inner-blocks-templates.spec.js b/test/e2e/specs/editor/various/inner-blocks-templates.spec.js index 87ad260428198..e1588e57beb10 100644 --- a/test/e2e/specs/editor/various/inner-blocks-templates.spec.js +++ b/test/e2e/specs/editor/various/inner-blocks-templates.spec.js @@ -28,7 +28,7 @@ test.describe( 'Inner blocks templates', () => { name: 'test/test-inner-blocks-async-template', } ); - const blockWithTemplateContent = page.locator( + const blockWithTemplateContent = editor.canvas.locator( 'role=document[name="Block: Test Inner Blocks Async Template"i] >> text=OneTwo' ); diff --git a/test/e2e/specs/editor/various/inserting-blocks.spec.js b/test/e2e/specs/editor/various/inserting-blocks.spec.js index 0ddb2b6b59228..39c159b00b75c 100644 --- a/test/e2e/specs/editor/various/inserting-blocks.spec.js +++ b/test/e2e/specs/editor/various/inserting-blocks.spec.js @@ -15,8 +15,16 @@ test.use( { } ); test.describe( 'Inserting blocks (@firefox, @webkit)', () => { - test.beforeEach( async ( { admin } ) => { + test.beforeEach( async ( { admin, page } ) => { await admin.createNewPost(); + // To do: some drag an drop tests are failing, so run them without + // iframe for now. + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); } ); test.afterAll( async ( { requestUtils } ) => { @@ -39,7 +47,7 @@ test.describe( 'Inserting blocks (@firefox, @webkit)', () => { name: 'core/paragraph', attributes: { content: 'Dummy text' }, } ); - const paragraphBlock = page.locator( + const paragraphBlock = editor.canvas.locator( '[data-type="core/paragraph"] >> text=Dummy text' ); @@ -116,7 +124,7 @@ test.describe( 'Inserting blocks (@firefox, @webkit)', () => { const beforeContent = await editor.getEditedPostContent(); - const paragraphBlock = page.locator( + const paragraphBlock = editor.canvas.locator( '[data-type="core/paragraph"] >> text=Dummy text' ); @@ -176,7 +184,7 @@ test.describe( 'Inserting blocks (@firefox, @webkit)', () => { attributes: { content: 'Dummy text' }, } ); - const paragraphBlock = page.locator( + const paragraphBlock = editor.canvas.locator( '[data-type="core/paragraph"] >> text=Dummy text' ); @@ -244,7 +252,7 @@ test.describe( 'Inserting blocks (@firefox, @webkit)', () => { const beforeContent = await editor.getEditedPostContent(); - const paragraphBlock = page.locator( + const paragraphBlock = editor.canvas.locator( '[data-type="core/paragraph"] >> text=Dummy text' ); diff --git a/test/e2e/specs/editor/various/keep-styles-on-block-transforms.spec.js b/test/e2e/specs/editor/various/keep-styles-on-block-transforms.spec.js index e4857f84d46c3..35895f05209be 100644 --- a/test/e2e/specs/editor/various/keep-styles-on-block-transforms.spec.js +++ b/test/e2e/specs/editor/various/keep-styles-on-block-transforms.spec.js @@ -12,7 +12,7 @@ test.describe( 'Keep styles on block transforms', () => { page, editor, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '## Heading' ); await editor.openDocumentSettingsSidebar(); await page.click( 'role=button[name="Color Text styles"i]' ); @@ -37,8 +37,15 @@ test.describe( 'Keep styles on block transforms', () => { pageUtils, editor, } ) => { + // To do: run with iframe. + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); // Create a paragraph block with some content. - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'Line 1 to be made large' ); await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'Line 2 to be made large' ); @@ -71,7 +78,7 @@ test.describe( 'Keep styles on block transforms', () => { editor, } ) => { // Create a paragraph block with some content. - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'Line 1 to be made large' ); await page.click( 'role=radio[name="Large"i]' ); await editor.showBlockToolbar(); diff --git a/test/e2e/specs/editor/various/list-view.spec.js b/test/e2e/specs/editor/various/list-view.spec.js index 2dc138e781918..40f7cce283210 100644 --- a/test/e2e/specs/editor/various/list-view.spec.js +++ b/test/e2e/specs/editor/various/list-view.spec.js @@ -261,6 +261,13 @@ test.describe( 'List View', () => { page, pageUtils, } ) => { + // To do: run with iframe. + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); await editor.insertBlock( { name: 'core/image' } ); await editor.insertBlock( { name: 'core/paragraph', @@ -336,7 +343,7 @@ test.describe( 'List View', () => { await pageUtils.pressKeys( 'shift+Tab' ); await pageUtils.pressKeys( 'shift+Tab' ); await expect( - editor.canvas + page .getByRole( 'region', { name: 'Document Overview' } ) .getByRole( 'button', { name: 'Close', @@ -354,7 +361,7 @@ test.describe( 'List View', () => { // tab receives similar focus events based on the shortcut. await pageUtils.pressKeys( 'shift+Tab' ); await page.keyboard.press( 'ArrowRight' ); - const outlineButton = editor.canvas.getByRole( 'tab', { + const outlineButton = page.getByRole( 'tab', { name: 'Outline', } ); await expect( outlineButton ).toBeFocused(); diff --git a/test/e2e/specs/editor/various/mentions.spec.js b/test/e2e/specs/editor/various/mentions.spec.js index b7e75e046c471..061b8d67a0801 100644 --- a/test/e2e/specs/editor/various/mentions.spec.js +++ b/test/e2e/specs/editor/various/mentions.spec.js @@ -23,7 +23,7 @@ test.describe( 'autocomplete mentions', () => { } ); test( 'should insert mention', async ( { page, editor } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'I am @ad' ); await expect( page.locator( 'role=listbox >> role=option[name=/admin/i]' ) @@ -42,7 +42,7 @@ test.describe( 'autocomplete mentions', () => { editor, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'Stuck in the middle with you' ); await pageUtils.pressKeys( 'ArrowLeft', { times: 'you'.length } ); await page.keyboard.type( '@j' ); @@ -62,7 +62,7 @@ test.describe( 'autocomplete mentions', () => { page, editor, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'I am @j' ); await expect( page.locator( 'role=listbox >> role=option[name=/testuser/i]' ) diff --git a/test/e2e/specs/editor/various/multi-block-selection.spec.js b/test/e2e/specs/editor/various/multi-block-selection.spec.js index d72ab2c6bf7db..26dee1291ba2f 100644 --- a/test/e2e/specs/editor/various/multi-block-selection.spec.js +++ b/test/e2e/specs/editor/various/multi-block-selection.spec.js @@ -247,6 +247,13 @@ test.describe( 'Multi-block selection', () => { editor, multiBlockSelectionUtils, } ) => { + // To do: run with iframe. + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); await editor.canvas .getByRole( 'button', { name: 'Add default block' } ) .click(); @@ -292,6 +299,13 @@ test.describe( 'Multi-block selection', () => { editor, pageUtils, } ) => { + // To do: run with iframe. + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); await editor.insertBlock( { name: 'core/paragraph', attributes: { content: 'test' }, @@ -304,6 +318,13 @@ test.describe( 'Multi-block selection', () => { .filter( { hasText: 'Draft saved' } ) ).toBeVisible(); await page.reload(); + // To do: run with iframe. + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); await editor.canvas .getByRole( 'document', { name: 'Paragraph block' } ) @@ -867,7 +888,6 @@ test.describe( 'Multi-block selection', () => { } ); test( 'should select title if the cursor is on title', async ( { - page, editor, pageUtils, multiBlockSelectionUtils, @@ -890,7 +910,7 @@ test.describe( 'Multi-block selection', () => { .toEqual( [] ); await expect .poll( () => - page.evaluate( () => window.getSelection().toString() ) + editor.canvas.evaluate( () => window.getSelection().toString() ) ) .toBe( 'Post title' ); } ); @@ -1142,6 +1162,13 @@ test.describe( 'Multi-block selection', () => { page, editor, } ) => { + // To do: run with iframe. + await page.evaluate( () => { + window.wp.blocks.registerBlockType( 'test/v2', { + apiVersion: '2', + title: 'test', + } ); + } ); await editor.insertBlock( { name: 'core/paragraph', attributes: { content: '1[' }, diff --git a/test/e2e/specs/editor/various/new-post-default-content.spec.js b/test/e2e/specs/editor/various/new-post-default-content.spec.js index 82c8e3a948f31..db9e3c38dc296 100644 --- a/test/e2e/specs/editor/various/new-post-default-content.spec.js +++ b/test/e2e/specs/editor/various/new-post-default-content.spec.js @@ -27,7 +27,7 @@ test.describe( 'new editor filtered state', () => { // Assert they match what the plugin set. await expect( - page.locator( 'role=textbox[name="Add title"i]' ) + editor.canvas.locator( 'role=textbox[name="Add title"i]' ) ).toHaveText( 'My default title' ); await expect .poll( editor.getEditedPostContent ) diff --git a/test/e2e/specs/editor/various/new-post.spec.js b/test/e2e/specs/editor/various/new-post.spec.js index e58e8ed94ffc5..4b192693c07b0 100644 --- a/test/e2e/specs/editor/various/new-post.spec.js +++ b/test/e2e/specs/editor/various/new-post.spec.js @@ -26,7 +26,9 @@ test.describe( 'new editor state', () => { await expect( page ).toHaveURL( /post-new.php/ ); // Should display the blank title. - const title = page.locator( 'role=textbox[name="Add title"i]' ); + const title = editor.canvas.locator( + 'role=textbox[name="Add title"i]' + ); await expect( title ).toBeEditable(); await expect( title ).toHaveText( '' ); @@ -55,23 +57,24 @@ test.describe( 'new editor state', () => { test( 'should focus the title if the title is empty', async ( { admin, - page, + editor, } ) => { await admin.createNewPost(); await expect( - page.locator( 'role=textbox[name="Add title"i]' ) + editor.canvas.locator( 'role=textbox[name="Add title"i]' ) ).toBeFocused(); } ); test( 'should not focus the title if the title exists', async ( { admin, page, + editor, } ) => { await admin.createNewPost(); // Enter a title for this post. - await page.type( + await editor.canvas.type( 'role=textbox[name="Add title"i]', 'Here is the title' ); diff --git a/test/e2e/specs/editor/various/post-visibility.spec.js b/test/e2e/specs/editor/various/post-visibility.spec.js index 611e260e17de5..3f83221c27b81 100644 --- a/test/e2e/specs/editor/various/post-visibility.spec.js +++ b/test/e2e/specs/editor/various/post-visibility.spec.js @@ -78,7 +78,7 @@ test.describe( 'Post visibility', () => { await admin.createNewPost(); // Enter a title for this post. - await page.type( 'role=textbox[name="Add title"i]', 'Title' ); + await editor.canvas.type( 'role=textbox[name="Add title"i]', 'Title' ); await editor.openDocumentSettingsSidebar(); diff --git a/test/e2e/specs/editor/various/preview.spec.js b/test/e2e/specs/editor/various/preview.spec.js index d71d9ada9b510..3f5e6eef60d3d 100644 --- a/test/e2e/specs/editor/various/preview.spec.js +++ b/test/e2e/specs/editor/various/preview.spec.js @@ -27,7 +27,7 @@ test.describe( 'Preview', () => { editorPage.locator( 'role=button[name="Preview"i]' ) ).toBeDisabled(); - await editorPage.type( + await editor.canvas.type( 'role=textbox[name="Add title"i]', 'Hello World' ); @@ -48,7 +48,7 @@ test.describe( 'Preview', () => { // Return to editor to change title. await editorPage.bringToFront(); - await editorPage.type( 'role=textbox[name="Add title"i]', '!' ); + await editor.canvas.type( 'role=textbox[name="Add title"i]', '!' ); await previewUtils.waitForPreviewNavigation( previewPage ); // Title in preview should match updated input. @@ -70,7 +70,7 @@ test.describe( 'Preview', () => { // Return to editor to change title. await editorPage.bringToFront(); - await editorPage.fill( + await editor.canvas.fill( 'role=textbox[name="Add title"i]', 'Hello World! And more.' ); @@ -107,7 +107,7 @@ test.describe( 'Preview', () => { const editorPage = page; // Type aaaaa in the title field. - await editorPage.type( 'role=textbox[name="Add title"]', 'aaaaa' ); + await editor.canvas.type( 'role=textbox[name="Add title"]', 'aaaaa' ); await editorPage.keyboard.press( 'Tab' ); // Save the post as a draft. @@ -127,7 +127,7 @@ test.describe( 'Preview', () => { await editorPage.bringToFront(); // Append bbbbb to the title, and tab away from the title so blur event is triggered. - await editorPage.fill( + await editor.canvas.fill( 'role=textbox[name="Add title"i]', 'aaaaabbbbb' ); @@ -155,7 +155,7 @@ test.describe( 'Preview', () => { const editorPage = page; // Type Lorem in the title field. - await editorPage.type( 'role=textbox[name="Add title"i]', 'Lorem' ); + await editor.canvas.type( 'role=textbox[name="Add title"i]', 'Lorem' ); // Open the preview page. const previewPage = await editor.openPreviewPage( editorPage ); @@ -172,7 +172,7 @@ test.describe( 'Preview', () => { await page.click( 'role=button[name="Close panel"i]' ); // Change the title and preview again. - await editorPage.type( 'role=textbox[name="Add title"i]', ' Ipsum' ); + await editor.canvas.type( 'role=textbox[name="Add title"i]', ' Ipsum' ); await previewUtils.waitForPreviewNavigation( previewPage ); // Title in preview should match updated input. @@ -191,7 +191,7 @@ test.describe( 'Preview', () => { ).toBeVisible(); // Change the title. - await editorPage.type( 'role=textbox[name="Add title"i]', ' Draft' ); + await editor.canvas.type( 'role=textbox[name="Add title"i]', ' Draft' ); // Open the preview page. await previewUtils.waitForPreviewNavigation( previewPage ); @@ -222,7 +222,10 @@ test.describe( 'Preview with Custom Fields enabled', () => { const editorPage = page; // Add an initial title and content. - await editorPage.type( 'role=textbox[name="Add title"i]', 'title 1' ); + await editor.canvas.type( + 'role=textbox[name="Add title"i]', + 'title 1' + ); await editor.insertBlock( { name: 'core/paragraph', attributes: { content: 'content 1' }, @@ -246,8 +249,11 @@ test.describe( 'Preview with Custom Fields enabled', () => { // Return to editor and modify the title and content. await editorPage.bringToFront(); - await editorPage.fill( 'role=textbox[name="Add title"i]', 'title 2' ); - await editorPage.fill( + await editor.canvas.fill( + 'role=textbox[name="Add title"i]', + 'title 2' + ); + await editor.canvas.fill( 'role=document >> text="content 1"', 'content 2' ); diff --git a/test/e2e/specs/editor/various/rtl.spec.js b/test/e2e/specs/editor/various/rtl.spec.js index 899dfd3c87dde..8475605e339fc 100644 --- a/test/e2e/specs/editor/various/rtl.spec.js +++ b/test/e2e/specs/editor/various/rtl.spec.js @@ -150,7 +150,7 @@ test.describe( 'RTL', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await pageUtils.pressKeys( 'primary+b' ); await page.keyboard.type( ARABIC_ONE ); await pageUtils.pressKeys( 'primary+b' ); diff --git a/test/e2e/specs/editor/various/splitting-merging.spec.js b/test/e2e/specs/editor/various/splitting-merging.spec.js index 08aa33ec09552..16b5225cfc8d3 100644 --- a/test/e2e/specs/editor/various/splitting-merging.spec.js +++ b/test/e2e/specs/editor/various/splitting-merging.spec.js @@ -306,11 +306,11 @@ test.describe( 'splitting and merging blocks', () => { // There is a default block and post title: await expect( - page.locator( 'role=document[name=/Empty block/i]' ) + editor.canvas.locator( 'role=document[name=/Empty block/i]' ) ).toBeVisible(); await expect( - page.locator( 'role=textbox[name="Add title"i]' ) + editor.canvas.locator( 'role=textbox[name="Add title"i]' ) ).toBeVisible(); // But the effective saved content is still empty: @@ -318,7 +318,7 @@ test.describe( 'splitting and merging blocks', () => { // And focus is retained: await expect( - page.locator( 'role=document[name=/Empty block/i]' ) + editor.canvas.locator( 'role=document[name=/Empty block/i]' ) ).toBeFocused(); } ); diff --git a/test/e2e/specs/editor/various/toolbar-roving-tabindex.spec.js b/test/e2e/specs/editor/various/toolbar-roving-tabindex.spec.js index ccb5952a57125..834bed77e8742 100644 --- a/test/e2e/specs/editor/various/toolbar-roving-tabindex.spec.js +++ b/test/e2e/specs/editor/various/toolbar-roving-tabindex.spec.js @@ -104,7 +104,7 @@ test.describe( 'Toolbar roving tabindex', () => { // Move focus to the first toolbar item. await page.keyboard.press( 'Home' ); await ToolbarRovingTabindexUtils.expectLabelToHaveFocus( 'Table' ); - await page.click( `role=button[name="Create Table"i]` ); + await editor.canvas.click( `role=button[name="Create Table"i]` ); await pageUtils.pressKeys( 'Tab' ); await ToolbarRovingTabindexUtils.testBlockToolbarKeyboardNavigation( 'Body cell text', @@ -188,15 +188,19 @@ class ToolbarRovingTabindexUtils { } async expectLabelToHaveFocus( label ) { - let ariaLabel = await this.page.evaluate( () => - document.activeElement.getAttribute( 'aria-label' ) - ); + let ariaLabel = await this.page.evaluate( () => { + const { activeElement } = + document.activeElement.contentDocument ?? document; + return activeElement.getAttribute( 'aria-label' ); + } ); // If the labels don't match, try pressing Up Arrow to focus the block wrapper in non-content editable block. if ( ariaLabel !== label ) { await this.page.keyboard.press( 'ArrowUp' ); - ariaLabel = await this.page.evaluate( () => - document.activeElement.getAttribute( 'aria-label' ) - ); + ariaLabel = await this.page.evaluate( () => { + const { activeElement } = + document.activeElement.contentDocument ?? document; + return activeElement.getAttribute( 'aria-label' ); + } ); } expect( ariaLabel ).toBe( label ); } diff --git a/test/e2e/specs/editor/various/undo.spec.js b/test/e2e/specs/editor/various/undo.spec.js index a4b68e1036dcf..5c4355882ee89 100644 --- a/test/e2e/specs/editor/various/undo.spec.js +++ b/test/e2e/specs/editor/various/undo.spec.js @@ -20,7 +20,7 @@ test.describe( 'undo', () => { pageUtils, undoUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'before pause' ); await editor.page.waitForTimeout( 1000 ); await page.keyboard.type( ' after pause' ); @@ -88,7 +88,7 @@ test.describe( 'undo', () => { pageUtils, undoUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'before keyboard ' ); await pageUtils.pressKeys( 'primary+b' ); @@ -159,8 +159,8 @@ test.describe( 'undo', () => { } ); } ); - test( 'should undo bold', async ( { page, pageUtils } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + test( 'should undo bold', async ( { page, pageUtils, editor } ) => { + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'test' ); await page.click( 'role=button[name="Save draft"i]' ); await expect( @@ -169,11 +169,12 @@ test.describe( 'undo', () => { ) ).toBeVisible(); await page.reload(); - await page.click( '[data-type="core/paragraph"]' ); + await page.waitForSelector( 'iframe[name="editor-canvas"]' ); + await editor.canvas.click( '[data-type="core/paragraph"]' ); await pageUtils.pressKeys( 'primary+a' ); await pageUtils.pressKeys( 'primary+b' ); await pageUtils.pressKeys( 'primary+z' ); - const activeElementLocator = page.locator( ':focus' ); + const activeElementLocator = editor.canvas.locator( ':focus' ); await expect( activeElementLocator ).toHaveText( 'test' ); } ); @@ -183,7 +184,7 @@ test.describe( 'undo', () => { pageUtils, undoUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); const firstBlock = await editor.getEditedPostContent(); @@ -326,7 +327,7 @@ test.describe( 'undo', () => { // See: https://github.com/WordPress/gutenberg/issues/14950 // Issue is demonstrated from an edited post: create, save, and reload. - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( 'original' ); await page.click( 'role=button[name="Save draft"i]' ); await expect( @@ -335,10 +336,11 @@ test.describe( 'undo', () => { ) ).toBeVisible(); await page.reload(); + await page.waitForSelector( 'iframe[name="editor-canvas"]' ); // Issue is demonstrated by forcing state merges (multiple inputs) on // an existing text after a fresh reload. - await page.click( '[data-type="core/paragraph"] >> nth=0' ); + await editor.canvas.click( '[data-type="core/paragraph"] >> nth=0' ); await page.keyboard.type( 'modified' ); // The issue is demonstrated after the one second delay to trigger the @@ -351,7 +353,7 @@ test.describe( 'undo', () => { // regression present was accurate, it would produce the correct // content. The issue had manifested in the form of what was shown to // the user since the blocks state failed to sync to block editor. - const activeElementLocator = page.locator( ':focus' ); + const activeElementLocator = editor.canvas.locator( ':focus' ); await expect( activeElementLocator ).toHaveText( 'original' ); } ); @@ -360,7 +362,7 @@ test.describe( 'undo', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '1' ); await page.click( 'role=button[name="Save draft"i]' ); await expect( @@ -378,7 +380,7 @@ test.describe( 'undo', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '1' ); await editor.publishPost(); await pageUtils.pressKeys( 'primary+z' ); @@ -391,7 +393,7 @@ test.describe( 'undo', () => { page, pageUtils, } ) => { - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( '1' ); await page.click( 'role=button[name="Save draft"i]' ); @@ -406,7 +408,7 @@ test.describe( 'undo', () => { await expect( page.locator( 'role=button[name="Undo"]' ) ).toBeDisabled(); - await page.click( '[data-type="core/paragraph"]' ); + await editor.canvas.click( '[data-type="core/paragraph"]' ); await page.keyboard.type( '2' ); @@ -436,7 +438,7 @@ test.describe( 'undo', () => { // block attribute as in the previous action and results in transient edits // and skipping `undo` history steps. const text = 'tonis'; - await page.click( 'role=button[name="Add default block"i]' ); + await editor.canvas.click( 'role=button[name="Add default block"i]' ); await page.keyboard.type( text ); await editor.publishPost(); await pageUtils.pressKeys( 'primary+z' ); @@ -460,14 +462,19 @@ test.describe( 'undo', () => { test( 'should be able to undo and redo property cross property changes', async ( { page, pageUtils, + editor, } ) => { - await page.getByRole( 'textbox', { name: 'Add title' } ).type( 'a' ); // First step. + await editor.canvas + .getByRole( 'textbox', { name: 'Add title' } ) + .type( 'a' ); // First step. await page.keyboard.press( 'Backspace' ); // Second step. - await page.getByRole( 'button', { name: 'Add default block' } ).click(); // third step. + await editor.canvas + .getByRole( 'button', { name: 'Add default block' } ) + .click(); // third step. // Title should be empty await expect( - page.getByRole( 'textbox', { name: 'Add title' } ) + editor.canvas.getByRole( 'textbox', { name: 'Add title' } ) ).toHaveText( '' ); // First undo removes the block. @@ -475,13 +482,13 @@ test.describe( 'undo', () => { await pageUtils.pressKeys( 'primary+z' ); await pageUtils.pressKeys( 'primary+z' ); await expect( - page.getByRole( 'textbox', { name: 'Add title' } ) + editor.canvas.getByRole( 'textbox', { name: 'Add title' } ) ).toHaveText( 'a' ); // Redoing the "backspace" should clear the title again. await pageUtils.pressKeys( 'primaryShift+z' ); await expect( - page.getByRole( 'textbox', { name: 'Add title' } ) + editor.canvas.getByRole( 'textbox', { name: 'Add title' } ) ).toHaveText( '' ); } ); } ); diff --git a/test/e2e/specs/editor/various/writing-flow.spec.js b/test/e2e/specs/editor/various/writing-flow.spec.js index 80e3fb3b12682..99de69819d9f3 100644 --- a/test/e2e/specs/editor/various/writing-flow.spec.js +++ b/test/e2e/specs/editor/various/writing-flow.spec.js @@ -4,8 +4,8 @@ const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); test.use( { - writingFlowUtils: async ( { page }, use ) => { - await use( new WritingFlowUtils( { page } ) ); + writingFlowUtils: async ( { page, editor }, use ) => { + await use( new WritingFlowUtils( { page, editor } ) ); }, } ); @@ -29,7 +29,7 @@ test.describe( 'Writing Flow', () => { // See: https://github.com/WordPress/gutenberg/issues/18928 await writingFlowUtils.addDemoContent(); - const activeElementLocator = page.locator( ':focus' ); + const activeElementLocator = editor.canvas.locator( ':focus' ); // Arrow up into nested context focuses last text input. await page.keyboard.press( 'ArrowUp' ); @@ -46,7 +46,7 @@ test.describe( 'Writing Flow', () => { .poll( writingFlowUtils.getActiveBlockName ) .toBe( 'core/column' ); await page.keyboard.press( 'ArrowUp' ); - const activeElementBlockType = await page.evaluate( () => + const activeElementBlockType = await editor.canvas.evaluate( () => document.activeElement.getAttribute( 'data-type' ) ); expect( activeElementBlockType ).toBe( 'core/columns' ); @@ -317,25 +317,25 @@ test.describe( 'Writing Flow', () => { await editor.insertBlock( { name: 'core/paragraph' } ); await page.keyboard.type( 'abc' ); // Need content to remove placeholder label. await editor.selectBlocks( - page.locator( 'role=document[name="Block: Shortcode"i]' ) + editor.canvas.locator( 'role=document[name="Block: Shortcode"i]' ) ); // Should remain in title upon ArrowRight: await page.keyboard.press( 'ArrowRight' ); await expect( - page.locator( 'role=document[name="Block: Shortcode"i]' ) + editor.canvas.locator( 'role=document[name="Block: Shortcode"i]' ) ).toHaveClass( /is-selected/ ); // Should remain in title upon modifier + ArrowDown: await pageUtils.pressKeys( 'primary+ArrowDown' ); await expect( - page.locator( 'role=document[name="Block: Shortcode"i]' ) + editor.canvas.locator( 'role=document[name="Block: Shortcode"i]' ) ).toHaveClass( /is-selected/ ); // Should navigate to the next block. await page.keyboard.press( 'ArrowDown' ); await expect( - page.locator( 'role=document[name="Paragraph block"i]' ) + editor.canvas.locator( 'role=document[name="Paragraph block"i]' ) ).toHaveClass( /is-selected/ ); } ); @@ -447,12 +447,12 @@ test.describe( 'Writing Flow', () => { } ) => { await page.keyboard.press( 'Enter' ); await page.keyboard.press( 'Enter' ); - await page.evaluate( () => { + await editor.canvas.evaluate( () => { document.activeElement.style.paddingTop = '100px'; } ); await page.keyboard.press( 'ArrowUp' ); await page.keyboard.type( '1' ); - await page.evaluate( () => { + await editor.canvas.evaluate( () => { document.activeElement.style.paddingBottom = '100px'; } ); await page.keyboard.press( 'ArrowDown' ); @@ -467,7 +467,7 @@ test.describe( 'Writing Flow', () => { } ) => { await page.keyboard.press( 'Enter' ); await page.keyboard.press( 'Enter' ); - await page.evaluate( () => { + await editor.canvas.evaluate( () => { document.activeElement.style.lineHeight = 'normal'; } ); await page.keyboard.press( 'ArrowUp' ); @@ -650,7 +650,7 @@ test.describe( 'Writing Flow', () => { } ) => { await page.keyboard.press( 'Enter' ); await page.keyboard.press( 'Enter' ); - await page.evaluate( () => { + await editor.canvas.evaluate( () => { document.activeElement.style.paddingLeft = '100px'; } ); await page.keyboard.press( 'Enter' ); @@ -696,7 +696,7 @@ test.describe( 'Writing Flow', () => { await page.keyboard.type( '2' ); await page.keyboard.press( 'ArrowUp' ); - const paragraphBlock = page + const paragraphBlock = editor.canvas .locator( 'role=document[name="Paragraph block"i]' ) .first(); const paragraphRect = await paragraphBlock.boundingBox(); @@ -761,7 +761,7 @@ test.describe( 'Writing Flow', () => {
    ` ); - const paragraphBlock = page.locator( + const paragraphBlock = editor.canvas.locator( 'role=document[name="Paragraph block"i]' ); @@ -784,7 +784,7 @@ test.describe( 'Writing Flow', () => { await page.mouse.click( x, lowerInserterY ); await expect( - page.locator( 'role=document[name="Block: Image"i]' ) + editor.canvas.locator( 'role=document[name="Block: Image"i]' ) ).toHaveClass( /is-selected/ ); } ); @@ -802,7 +802,7 @@ test.describe( 'Writing Flow', () => { // Create the table. await page.keyboard.press( 'Space' ); await expect( - page.locator( 'role=document[name="Block: Table"i]' ) + editor.canvas.locator( 'role=document[name="Block: Table"i]' ) ).toBeVisible(); // Navigate to the second cell. await page.keyboard.press( 'ArrowRight' ); @@ -867,7 +867,7 @@ test.describe( 'Writing Flow', () => { await page.mouse.up(); await expect( - page.locator( 'role=document[name="Paragraph block"i]' ) + editor.canvas.locator( 'role=document[name="Paragraph block"i]' ) ).toHaveClass( /is-selected/ ); } ); @@ -901,12 +901,13 @@ test.describe( 'Writing Flow', () => { test( 'should move to the start of the first line on ArrowUp', async ( { page, + editor, } ) => { await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'a' ); async function getHeight() { - return await page.evaluate( + return await editor.canvas.evaluate( () => document.activeElement.offsetHeight ); } @@ -928,18 +929,19 @@ test.describe( 'Writing Flow', () => { // Expect the "." to be added at the start of the paragraph await expect( - page.locator( 'role=document[name="Paragraph block"i]' ) + editor.canvas.locator( 'role=document[name="Paragraph block"i]' ) ).toHaveText( /^\.a+$/ ); } ); test( 'should vertically move the caret from corner to corner', async ( { page, + editor, } ) => { await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'a' ); async function getHeight() { - return await page.evaluate( + return await editor.canvas.evaluate( () => document.activeElement.offsetHeight ); } @@ -961,19 +963,20 @@ test.describe( 'Writing Flow', () => { // Expect the "." to be added at the start of the paragraph await expect( - page.locator( 'role=document[name="Paragraph block"i]' ) + editor.canvas.locator( 'role=document[name="Paragraph block"i]' ) ).toHaveText( /^a+\.a$/ ); } ); test( 'should vertically move the caret when pressing Alt', async ( { page, pageUtils, + editor, } ) => { await page.keyboard.press( 'Enter' ); await page.keyboard.type( 'a' ); async function getHeight() { - return await page.evaluate( + return await editor.canvas.evaluate( () => document.activeElement.offsetHeight ); } @@ -995,14 +998,17 @@ test.describe( 'Writing Flow', () => { // Expect the "." to be added at the start of the paragraph await expect( - page.locator( 'role=document[name="Paragraph block"i] >> nth = 0' ) + editor.canvas.locator( + 'role=document[name="Paragraph block"i] >> nth = 0' + ) ).toHaveText( /^.a+$/ ); } ); } ); class WritingFlowUtils { - constructor( { page } ) { + constructor( { page, editor } ) { this.page = page; + this.editor = editor; this.getActiveBlockName = this.getActiveBlockName.bind( this ); } @@ -1021,19 +1027,19 @@ class WritingFlowUtils { await this.page.keyboard.press( 'Enter' ); await this.page.keyboard.type( '/columns' ); await this.page.keyboard.press( 'Enter' ); - await this.page.click( + await this.editor.canvas.click( 'role=button[name="Two columns; equal split"i]' ); - await this.page.click( 'role=button[name="Add block"i]' ); + await this.editor.canvas.click( 'role=button[name="Add block"i]' ); await this.page.click( 'role=listbox[name="Blocks"i] >> role=option[name="Paragraph"i]' ); await this.page.keyboard.type( '1st col' ); // If this text is too long, it may wrap to a new line and cause test failure. That's why we're using "1st" instead of "First" here. - await this.page.focus( + await this.editor.canvas.focus( 'role=document[name="Block: Column (2 of 2)"i]' ); - await this.page.click( 'role=button[name="Add block"i]' ); + await this.editor.canvas.click( 'role=button[name="Add block"i]' ); await this.page.click( 'role=listbox[name="Blocks"i] >> role=option[name="Paragraph"i]' ); diff --git a/test/e2e/specs/widgets/customizing-widgets.spec.js b/test/e2e/specs/widgets/customizing-widgets.spec.js index 110ce28948f22..8b2a585dc4e66 100644 --- a/test/e2e/specs/widgets/customizing-widgets.spec.js +++ b/test/e2e/specs/widgets/customizing-widgets.spec.js @@ -36,7 +36,11 @@ test.describe( 'Widgets Customizer', () => { await requestUtils.activateTheme( 'twentytwentyone' ); } ); - test( 'should add blocks', async ( { page, widgetsCustomizerPage } ) => { + test( 'should add blocks', async ( { + page, + widgetsCustomizerPage, + editor, + } ) => { const previewFrame = widgetsCustomizerPage.previewFrame; await widgetsCustomizerPage.visitCustomizerPage(); @@ -82,7 +86,7 @@ test.describe( 'Widgets Customizer', () => { await page.click( 'role=option[name="Search"i]' ); - await page.focus( + await editor.canvas.focus( 'role=document[name="Block: Search"i] >> role=textbox[name="Label text"i]' ); @@ -229,6 +233,7 @@ test.describe( 'Widgets Customizer', () => { page, requestUtils, widgetsCustomizerPage, + editor, } ) => { await requestUtils.addWidgetBlock( `\n

    First Paragraph

    \n`, @@ -277,7 +282,7 @@ test.describe( 'Widgets Customizer', () => { await headingWidget.click(); // noop click on the widget text to unfocus the editor and hide toolbar await editHeadingWidget.click(); - const headingBlock = page.locator( + const headingBlock = editor.canvas.locator( 'role=document[name="Block: Heading"i] >> text="First Heading"' ); await expect( headingBlock ).toBeFocused(); @@ -583,12 +588,13 @@ test.describe( 'Widgets Customizer', () => { test( 'preserves content in the Custom HTML block', async ( { page, widgetsCustomizerPage, + editor, } ) => { await widgetsCustomizerPage.visitCustomizerPage(); await widgetsCustomizerPage.expandWidgetArea( 'Footer #1' ); await widgetsCustomizerPage.addBlock( 'Custom HTML' ); - const HTMLBlockTextarea = page.locator( + const HTMLBlockTextarea = editor.canvas.locator( 'role=document[name="Block: Custom HTML"i] >> role=textbox[name="HTML"i]' ); await HTMLBlockTextarea.type( 'hello' ); diff --git a/test/integration/fixtures/blocks/core__query.json b/test/integration/fixtures/blocks/core__query.json index 4c7ce920a0450..fb545c16ea695 100644 --- a/test/integration/fixtures/blocks/core__query.json +++ b/test/integration/fixtures/blocks/core__query.json @@ -18,10 +18,7 @@ "taxQuery": null, "parents": [] }, - "tagName": "div", - "displayLayout": { - "type": "list" - } + "tagName": "div" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__query.serialized.html b/test/integration/fixtures/blocks/core__query.serialized.html index 049ea7dd2bb73..3bc4085f4f090 100644 --- a/test/integration/fixtures/blocks/core__query.serialized.html +++ b/test/integration/fixtures/blocks/core__query.serialized.html @@ -1,3 +1,3 @@ - +
    diff --git a/test/integration/fixtures/blocks/core__query__deprecated-1.serialized.html b/test/integration/fixtures/blocks/core__query__deprecated-1.serialized.html index 39f889cfae97e..915726d992a8f 100644 --- a/test/integration/fixtures/blocks/core__query__deprecated-1.serialized.html +++ b/test/integration/fixtures/blocks/core__query__deprecated-1.serialized.html @@ -1,3 +1,3 @@ - +
    diff --git a/test/integration/fixtures/blocks/core__query__deprecated-2-with-colors.json b/test/integration/fixtures/blocks/core__query__deprecated-2-with-colors.json index 82bc41a40fb1b..8a048667f55af 100644 --- a/test/integration/fixtures/blocks/core__query__deprecated-2-with-colors.json +++ b/test/integration/fixtures/blocks/core__query__deprecated-2-with-colors.json @@ -21,10 +21,7 @@ "post_tag": [ 6 ] } }, - "tagName": "div", - "displayLayout": { - "type": "list" - } + "tagName": "div" }, "innerBlocks": [ { @@ -50,7 +47,11 @@ { "name": "core/post-template", "isValid": true, - "attributes": {}, + "attributes": { + "layout": { + "type": "default" + } + }, "innerBlocks": [ { "name": "core/post-title", diff --git a/test/integration/fixtures/blocks/core__query__deprecated-2-with-colors.serialized.html b/test/integration/fixtures/blocks/core__query__deprecated-2-with-colors.serialized.html index f86b4f26ecc1d..b9e6b50deb067 100644 --- a/test/integration/fixtures/blocks/core__query__deprecated-2-with-colors.serialized.html +++ b/test/integration/fixtures/blocks/core__query__deprecated-2-with-colors.serialized.html @@ -1,6 +1,6 @@ - +
    - diff --git a/test/integration/fixtures/blocks/core__query__deprecated-2.json b/test/integration/fixtures/blocks/core__query__deprecated-2.json index a63ad1c007b6b..b0a1aea41ea50 100644 --- a/test/integration/fixtures/blocks/core__query__deprecated-2.json +++ b/test/integration/fixtures/blocks/core__query__deprecated-2.json @@ -21,16 +21,17 @@ "post_tag": [ 6 ] } }, - "tagName": "div", - "displayLayout": { - "type": "list" - } + "tagName": "div" }, "innerBlocks": [ { "name": "core/post-template", "isValid": true, - "attributes": {}, + "attributes": { + "layout": { + "type": "default" + } + }, "innerBlocks": [ { "name": "core/post-title", diff --git a/test/integration/fixtures/blocks/core__query__deprecated-2.serialized.html b/test/integration/fixtures/blocks/core__query__deprecated-2.serialized.html index 5804c54e577f1..2016bea963592 100644 --- a/test/integration/fixtures/blocks/core__query__deprecated-2.serialized.html +++ b/test/integration/fixtures/blocks/core__query__deprecated-2.serialized.html @@ -1,5 +1,5 @@ - -
    + +
    diff --git a/test/integration/fixtures/blocks/core__query__deprecated-3.json b/test/integration/fixtures/blocks/core__query__deprecated-3.json index 6b3327eacdc3f..bb9a9de34a4b7 100644 --- a/test/integration/fixtures/blocks/core__query__deprecated-3.json +++ b/test/integration/fixtures/blocks/core__query__deprecated-3.json @@ -18,10 +18,6 @@ "inherit": false }, "tagName": "div", - "displayLayout": { - "type": "flex", - "columns": 3 - }, "align": "wide" }, "innerBlocks": [ @@ -49,7 +45,11 @@ "name": "core/post-template", "isValid": true, "attributes": { - "fontSize": "large" + "fontSize": "large", + "layout": { + "type": "grid", + "columnCount": 3 + } }, "innerBlocks": [ { diff --git a/test/integration/fixtures/blocks/core__query__deprecated-3.serialized.html b/test/integration/fixtures/blocks/core__query__deprecated-3.serialized.html index edbf5b1a0557b..86c87dde71c3b 100644 --- a/test/integration/fixtures/blocks/core__query__deprecated-3.serialized.html +++ b/test/integration/fixtures/blocks/core__query__deprecated-3.serialized.html @@ -1,6 +1,6 @@ - +
    -