From bd53de2a2873432161cdd54882264f0a53ff4200 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 20 Apr 2023 21:03:45 -0500 Subject: [PATCH 001/125] Add behaviors to the core theme.json --- lib/theme.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/theme.json b/lib/theme.json index 88befe6dff2ed0..09949e539dcf53 100644 --- a/lib/theme.json +++ b/lib/theme.json @@ -450,6 +450,11 @@ "style": true, "width": true } + }, + "core/image": { + "behaviors": { + "lightbox": true + } } } }, From bd43bf6b12129d7bf70f8b69b20b3905b522ac8d Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 20 Apr 2023 21:12:03 -0500 Subject: [PATCH 002/125] Add behaviors to json schemas for theme.json --- schemas/json/theme.json | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/schemas/json/theme.json b/schemas/json/theme.json index 5f9fd13c041575..3bac7cb795396a 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -675,7 +675,8 @@ "shadow": {}, "spacing": {}, "typography": {}, - "custom": {} + "custom": {}, + "behaviors": {} }, "additionalProperties": false } @@ -796,7 +797,28 @@ "$ref": "#/definitions/settingsPropertiesComplete" }, "core/image": { - "$ref": "#/definitions/settingsPropertiesComplete" + "type": "object", + "allOf": [ + { + "$ref": "#/definitions/settingsPropertiesComplete" + }, + { + "type": "object", + "properties": { + "behaviors": { + "description": "Allows users to set named behaviors for a block.\nGutenberg plugin required.", + "type": "object", + "properties": { + "lightbox": { + "description": "Show a lightbox for the image.\nGutenberg plugin required.", + "type": "boolean", + "default": true + } + } + } + } + } + ] }, "core/latest-comments": { "$ref": "#/definitions/settingsPropertiesComplete" From e1dd73759f24449587fd15af6acf4185d8797f16 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 3 May 2023 18:50:57 -0500 Subject: [PATCH 003/125] Add a behaviors panel --- packages/block-editor/src/hooks/behaviors.js | 70 ++++++++++++++++++++ packages/block-editor/src/hooks/index.js | 1 + 2 files changed, 71 insertions(+) create mode 100644 packages/block-editor/src/hooks/behaviors.js diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js new file mode 100644 index 00000000000000..90dbee8ffc245a --- /dev/null +++ b/packages/block-editor/src/hooks/behaviors.js @@ -0,0 +1,70 @@ +/** + * WordPress dependencies + */ +import { addFilter } from '@wordpress/hooks'; +import { TextControl } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { createHigherOrderComponent } from '@wordpress/compose'; +import { useSettings } from '@wordpress/block-editor'; + +/** + * Internal dependencies + */ +import { InspectorControls } from '../components'; + +/** + * Override the default edit UI to include a new block inspector control for + * assigning the custom class name, if block supports custom class name. + * The control is displayed within the Advanced panel in the block inspector. + * + * @param {WPComponent} BlockEdit Original component. + * + * @return {WPComponent} Wrapped component. + */ +export const withInspectorControl = createHigherOrderComponent( + ( BlockEdit ) => { + return ( props ) => { + const { behaviors } = props.attributes; + const { behaviors: behaviorsSupport } = props.blockType.attributes; + + const settings = useSettings(); + + // eslint-disable-next-line no-console + console.log( 'behaviors', behaviors ); + // eslint-disable-next-line no-console + console.log( 'behaviorsSupport', behaviorsSupport ); + // eslint-disable-next-line no-console + console.log( settings ); + + return ( + <> + + + { + props.setAttributes( { + behaviors: + nextValue !== '' + ? nextValue + : undefined, + } ); + } } + help={ __( 'Add behaviors' ) } + /> + + + ); + }; + }, + 'withInspectorControl' +); + +addFilter( + 'editor.BlockEdit', + 'core/behaviors/with-inspector-control', + withInspectorControl +); diff --git a/packages/block-editor/src/hooks/index.js b/packages/block-editor/src/hooks/index.js index 2077c143952f59..a66aa0a73ed411 100644 --- a/packages/block-editor/src/hooks/index.js +++ b/packages/block-editor/src/hooks/index.js @@ -20,6 +20,7 @@ import './layout'; import './content-lock-ui'; import './metadata'; import './metadata-name'; +import './behaviors'; export { useCustomSides } from './dimensions'; export { useLayoutClasses, useLayoutStyles } from './layout'; From 8b84a22c7f340d954f28b72da7a966695d2f9cf8 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 4 May 2023 21:49:59 -0500 Subject: [PATCH 004/125] Remove the changes to theme.json schema --- schemas/json/theme.json | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/schemas/json/theme.json b/schemas/json/theme.json index 3bac7cb795396a..5f9fd13c041575 100644 --- a/schemas/json/theme.json +++ b/schemas/json/theme.json @@ -675,8 +675,7 @@ "shadow": {}, "spacing": {}, "typography": {}, - "custom": {}, - "behaviors": {} + "custom": {} }, "additionalProperties": false } @@ -797,28 +796,7 @@ "$ref": "#/definitions/settingsPropertiesComplete" }, "core/image": { - "type": "object", - "allOf": [ - { - "$ref": "#/definitions/settingsPropertiesComplete" - }, - { - "type": "object", - "properties": { - "behaviors": { - "description": "Allows users to set named behaviors for a block.\nGutenberg plugin required.", - "type": "object", - "properties": { - "lightbox": { - "description": "Show a lightbox for the image.\nGutenberg plugin required.", - "type": "boolean", - "default": true - } - } - } - } - } - ] + "$ref": "#/definitions/settingsPropertiesComplete" }, "core/latest-comments": { "$ref": "#/definitions/settingsPropertiesComplete" From d5dbc1c9c0afcf6b36a06453055159be8906b766 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 4 May 2023 23:08:51 -0500 Subject: [PATCH 005/125] Add behaviors to the VALID_SETTINGS in class-wp-theme-json-gutenberg.php --- lib/class-wp-theme-json-gutenberg.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 9e7a7316ffdd29..91783a746ebf27 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -404,6 +404,9 @@ class WP_Theme_JSON_Gutenberg { 'textDecoration' => null, 'textTransform' => null, ), + 'behaviors' => array( + 'lightbox' => null, + ), ); /** From 037d6692c4b618812c55be591b5ff999eb1ca17c Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 4 May 2023 23:14:45 -0500 Subject: [PATCH 006/125] Add the first (still broken) version of the lightbox settings --- packages/block-editor/src/hooks/behaviors.js | 86 ++++++++++---------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index 90dbee8ffc245a..deb8ad08267d15 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -5,66 +5,66 @@ import { addFilter } from '@wordpress/hooks'; import { TextControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { createHigherOrderComponent } from '@wordpress/compose'; -import { useSettings } from '@wordpress/block-editor'; +import { select } from '@wordpress/data'; /** * Internal dependencies */ import { InspectorControls } from '../components'; +import { store as blockEditorStore } from '../store'; /** - * Override the default edit UI to include a new block inspector control for - * assigning the custom class name, if block supports custom class name. - * The control is displayed within the Advanced panel in the block inspector. + * TODO: Add description. * * @param {WPComponent} BlockEdit Original component. * * @return {WPComponent} Wrapped component. */ -export const withInspectorControl = createHigherOrderComponent( - ( BlockEdit ) => { - return ( props ) => { - const { behaviors } = props.attributes; - const { behaviors: behaviorsSupport } = props.blockType.attributes; +export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { + return ( props ) => { + const { behaviors: blockBehaviors } = props.attributes; + const settings = select( blockEditorStore ).getSettings(); + const themeBehaviors = + settings?.__experimentalFeatures?.blocks?.[ 'core/image' ] + .behaviors; - const settings = useSettings(); + if ( ! blockBehaviors && ! themeBehaviors ) { + return ; + } - // eslint-disable-next-line no-console - console.log( 'behaviors', behaviors ); - // eslint-disable-next-line no-console - console.log( 'behaviorsSupport', behaviorsSupport ); - // eslint-disable-next-line no-console - console.log( settings ); + if ( ! blockBehaviors && themeBehaviors ) { + props.attributes.behaviors = themeBehaviors; + } - return ( - <> - - - { - props.setAttributes( { - behaviors: - nextValue !== '' - ? nextValue - : undefined, - } ); - } } - help={ __( 'Add behaviors' ) } - /> - - - ); - }; - }, - 'withInspectorControl' -); + return ( + <> + + + { + props.setAttributes( { + behaviors: + nextValue !== '' ? nextValue : undefined, + } ); + } } + help={ __( 'Add behaviors' ) } + /> + + + ); + }; +}, 'withBehaviors' ); addFilter( 'editor.BlockEdit', 'core/behaviors/with-inspector-control', - withInspectorControl + withBehaviors ); From 8f62d34b29d2109e625d752e7fa1b061a02ee8a6 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 8 May 2023 20:21:43 -0500 Subject: [PATCH 007/125] WIP: Added a SelectControl for the behaviors --- packages/block-editor/src/hooks/behaviors.js | 39 ++++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index deb8ad08267d15..7c0227c7163aa6 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { addFilter } from '@wordpress/hooks'; -import { TextControl } from '@wordpress/components'; +import { SelectControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { createHigherOrderComponent } from '@wordpress/compose'; import { select } from '@wordpress/data'; @@ -22,6 +22,11 @@ import { store as blockEditorStore } from '../store'; */ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { return ( props ) => { + // Only add behaviors to the core/image block. + if ( props.name !== 'core/image' ) { + return ; + } + const { behaviors: blockBehaviors } = props.attributes; const settings = select( blockEditorStore ).getSettings(); const themeBehaviors = @@ -32,30 +37,42 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { return ; } + // By default, use the block behaviors. + let behaviors = blockBehaviors; + + // If the theme has behaviors, but the block does not, use the theme behaviors. if ( ! blockBehaviors && themeBehaviors ) { - props.attributes.behaviors = themeBehaviors; + behaviors = themeBehaviors; } return ( <> - ( { + value: behavior, + label: behavior.toUpperCase(), + } ) ) + .concat( { + value: '', + label: __( 'None' ), + } ) } onChange={ ( nextValue ) => { props.setAttributes( { - behaviors: - nextValue !== '' ? nextValue : undefined, + behaviors: { + lightbox: nextValue === '' ? false : true, + }, } ); } } + hideCancelButton={ true } help={ __( 'Add behaviors' ) } + size="__unstable-large" /> From 62b6217860e41d5b112ec59662425289225e1529 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 9 May 2023 13:27:21 -0500 Subject: [PATCH 008/125] Format PHP --- lib/class-wp-theme-json-gutenberg.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 91783a746ebf27..614f0dd2c9c4e0 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -404,8 +404,8 @@ class WP_Theme_JSON_Gutenberg { 'textDecoration' => null, 'textTransform' => null, ), - 'behaviors' => array( - 'lightbox' => null, + 'behaviors' => array( + 'lightbox' => null, ), ); From edfd7d19523ac88e3db804a4735c29890ed187fa Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 9 May 2023 15:08:23 -0500 Subject: [PATCH 009/125] Format correctly again --- lib/class-wp-theme-json-gutenberg.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 614f0dd2c9c4e0..5eb65062d5a5c5 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -405,7 +405,7 @@ class WP_Theme_JSON_Gutenberg { 'textTransform' => null, ), 'behaviors' => array( - 'lightbox' => null, + 'lightbox' => null, ), ); From 8ee4065a867c94f85e3041654c556cb875a9ede8 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 9 May 2023 21:07:51 -0500 Subject: [PATCH 010/125] Use the props.name when getting the behaviors --- packages/block-editor/src/hooks/behaviors.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index 7c0227c7163aa6..1e58797cf697a3 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -30,8 +30,7 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { const { behaviors: blockBehaviors } = props.attributes; const settings = select( blockEditorStore ).getSettings(); const themeBehaviors = - settings?.__experimentalFeatures?.blocks?.[ 'core/image' ] - .behaviors; + settings?.__experimentalFeatures?.blocks?.[ props.name ]?.behaviors; if ( ! blockBehaviors && ! themeBehaviors ) { return ; From 594224be51cf8cece4224505b2fd216efc0a0adb Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Wed, 10 May 2023 18:08:04 +0200 Subject: [PATCH 011/125] Add initial e2e tests --- .../specs/editor/various/behaviors.spec.js | 76 +++++++++++++++++++ .../gutenberg-test-themes/behaviors/index.php | 0 .../gutenberg-test-themes/behaviors/style.css | 15 ++++ .../behaviors/theme.json | 12 +++ 4 files changed, 103 insertions(+) create mode 100644 test/e2e/specs/editor/various/behaviors.spec.js create mode 100644 test/gutenberg-test-themes/behaviors/index.php create mode 100644 test/gutenberg-test-themes/behaviors/style.css create mode 100644 test/gutenberg-test-themes/behaviors/theme.json diff --git a/test/e2e/specs/editor/various/behaviors.spec.js b/test/e2e/specs/editor/various/behaviors.spec.js new file mode 100644 index 00000000000000..c9b01e50740121 --- /dev/null +++ b/test/e2e/specs/editor/various/behaviors.spec.js @@ -0,0 +1,76 @@ +/** + * External dependencies + */ +const path = require( 'path' ); + +/** + * WordPress dependencies + */ +const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); + +test.describe( 'Testing behaviors functionality', () => { + test.afterAll( async ( { requestUtils } ) => { + await requestUtils.activateTheme( 'twentytwentyone' ); + await requestUtils.deleteAllPosts(); + } ); + + test.afterEach( async ( { requestUtils } ) => { + await requestUtils.deleteAllMedia(); + } ); + + test( 'Lightbox option should be selected in an image block, as defined in theme.json', async ( { + admin, + editor, + requestUtils, + page, + } ) => { + await admin.createNewPost(); + const filename = '1024x768_e2e_test_image_size.jpeg'; + const filepath = path.join( './test/e2e/assets', filename ); + + await admin.createNewPost(); + const media = await requestUtils.uploadMedia( filepath ); + + await editor.insertBlock( { + name: 'core/image', + attributes: { + alt: filename, + id: media.id, + url: media.source_url, + }, + } ); + + await page.getByRole( 'button', { name: 'Advanced' } ).click(); + await expect( page.getByLabel( 'Behavior' ) ).toHaveValue( 'lightbox' ); + } ); + + test( 'None option should be selected in an image block, as defined in theme.json', async ( { + admin, + editor, + requestUtils, + page, + } ) => { + // Lightbox is the default behavior, so we need a theme that has it disabled. Change if we change the default. + await requestUtils.activateTheme( 'behaviors' ); + await admin.createNewPost(); + + const filename = '1024x768_e2e_test_image_size.jpeg'; + const filepath = path.join( './test/e2e/assets', filename ); + + await admin.createNewPost(); + const media = await requestUtils.uploadMedia( filepath ); + + await editor.insertBlock( { + name: 'core/image', + attributes: { + alt: filename, + id: media.id, + url: media.source_url, + }, + } ); + + await page.getByRole( 'button', { name: 'Advanced' } ).click(); + // Right now the selector has an empty value. + await expect( page.getByLabel( 'Behavior' ) ).toHaveValue( '' ); + } ); +} ); diff --git a/test/gutenberg-test-themes/behaviors/index.php b/test/gutenberg-test-themes/behaviors/index.php new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/test/gutenberg-test-themes/behaviors/style.css b/test/gutenberg-test-themes/behaviors/style.css new file mode 100644 index 00000000000000..972dbacbb5cabd --- /dev/null +++ b/test/gutenberg-test-themes/behaviors/style.css @@ -0,0 +1,15 @@ +/* +Theme Name: Behaviors +Theme URI: https://github.com/wordpress/theme-experiments/ +Author: the WordPress team +Description: Behaviors test theme. +Requires at least: 5.3 +Tested up to: 6.2 +Requires PHP: 5.6 +Version: 1.0 +License: GNU General Public License v2 or later +License URI: http://www.gnu.org/licenses/gpl-2.0.html +Text Domain: behaviors +Behaviors WordPress Theme, (C) 2023 WordPress.org +Behaviors is distributed under the terms of the GNU GPL. +*/ \ No newline at end of file diff --git a/test/gutenberg-test-themes/behaviors/theme.json b/test/gutenberg-test-themes/behaviors/theme.json new file mode 100644 index 00000000000000..a9f920f6dd0abc --- /dev/null +++ b/test/gutenberg-test-themes/behaviors/theme.json @@ -0,0 +1,12 @@ +{ + "version": 2, + "settings": { + "blocks": { + "core/image": { + "behaviors": { + "lightbox": false + } + } + } + } +} From fd6fe36aa5323daca2a938fb095cfe07baeb6a17 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 10 May 2023 17:03:13 -0500 Subject: [PATCH 012/125] Update the withBehaviors description --- packages/block-editor/src/hooks/behaviors.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index 1e58797cf697a3..2b6201873fc7be 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -14,7 +14,10 @@ import { InspectorControls } from '../components'; import { store as blockEditorStore } from '../store'; /** - * TODO: Add description. + * Override the default edit UI to include a new block inspector control for + * assigning behaviors to blocks if behaviors are enabled in the theme.json. + * + * Currently, only the `core/image` block is supported. * * @param {WPComponent} BlockEdit Original component. * From da4a5ad5a72e1fe942f1a40c71a16a8d928b940c Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Wed, 10 May 2023 22:31:34 -0500 Subject: [PATCH 013/125] Cleaned up behaviors.js --- packages/block-editor/src/hooks/behaviors.js | 20 ++++++++++++++------ packages/block-library/src/image/block.json | 6 ++++++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index 2b6201873fc7be..0aae8fdbea48ba 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -30,15 +30,21 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { return ; } - const { behaviors: blockBehaviors } = props.attributes; + // Check the value of `settings.blocks.core/image.behavior.lightbox` in the + // theme.json. If false, do not add the behaviors inspector control. const settings = select( blockEditorStore ).getSettings(); - const themeBehaviors = - settings?.__experimentalFeatures?.blocks?.[ props.name ]?.behaviors; - - if ( ! blockBehaviors && ! themeBehaviors ) { + if ( + ! settings?.__experimentalFeatures?.blocks?.[ props.name ] + ?.behaviors?.lightbox + ) { return ; } + const { behaviors: blockBehaviors } = props.attributes; + + // TODO: Here we should get the theme behaviors but it doesn't work ATM. + const themeBehaviors = settings?.behaviors; + // By default, use the block behaviors. let behaviors = blockBehaviors; @@ -55,7 +61,7 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { __nextHasNoMarginBottom label={ __( 'Behaviors' ) } // At the moment we are only supporting one behavior (lightbox) - value={ behaviors?.lightbox || '' } + value={ behaviors?.lightbox ? 'LIGHTBOX' : '' } options={ Object.keys( behaviors ) .map( ( behavior ) => ( { value: behavior, @@ -66,6 +72,8 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { label: __( 'None' ), } ) } onChange={ ( nextValue ) => { + // If the user selects something, it means that they want to + // change the default value (true) so we save it in the attributes. props.setAttributes( { behaviors: { lightbox: nextValue === '' ? false : true, diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index 92931455c1144c..f2e9be4e10e06d 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -80,6 +80,12 @@ "source": "attribute", "selector": "figure > a", "attribute": "target" + }, + "behaviors": { + "type": "object", + "default": { + "lightbox": true + } } }, "supports": { From 2958fd16e88411c1c0adfefc70fd763386fcfd51 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Fri, 12 May 2023 13:20:12 +0200 Subject: [PATCH 014/125] Update e2e tests to check visibility --- test/e2e/specs/editor/various/behaviors.spec.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/e2e/specs/editor/various/behaviors.spec.js b/test/e2e/specs/editor/various/behaviors.spec.js index c9b01e50740121..5866721a05d5dc 100644 --- a/test/e2e/specs/editor/various/behaviors.spec.js +++ b/test/e2e/specs/editor/various/behaviors.spec.js @@ -41,6 +41,7 @@ test.describe( 'Testing behaviors functionality', () => { } ); await page.getByRole( 'button', { name: 'Advanced' } ).click(); + await expect( page.getByLabel( 'Behavior' ) ).toHaveCount( 1 ); await expect( page.getByLabel( 'Behavior' ) ).toHaveValue( 'lightbox' ); } ); @@ -70,7 +71,7 @@ test.describe( 'Testing behaviors functionality', () => { } ); await page.getByRole( 'button', { name: 'Advanced' } ).click(); - // Right now the selector has an empty value. - await expect( page.getByLabel( 'Behavior' ) ).toHaveValue( '' ); + // Right now the selector should not appear. + await expect( page.getByLabel( 'Behavior' ) ).toHaveCount( 0 ); } ); } ); From 0a68bea257d4d8dd334469670f0837d622042729 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Fri, 12 May 2023 14:23:57 +0200 Subject: [PATCH 015/125] Update core-blocks doc with behaviors attribute --- docs/reference-guides/core-blocks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index 423676e2afe320..df852bf97b6664 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -321,7 +321,7 @@ Insert an image to make a visual statement. ([Source](https://github.com/WordPre - **Name:** core/image - **Category:** media - **Supports:** anchor, color (~~background~~, ~~text~~), filter (duotone) -- **Attributes:** align, alt, caption, height, href, id, linkClass, linkDestination, linkTarget, rel, sizeSlug, title, url, width +- **Attributes:** align, alt, behaviors, caption, height, href, id, linkClass, linkDestination, linkTarget, rel, sizeSlug, title, url, width ## Latest Comments From fd089285f89e7b1904b3547fa86e2ef9ca149408 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Sat, 13 May 2023 11:26:18 +0200 Subject: [PATCH 016/125] Update fixtures with new lightbox attribute --- .../blocks/core__gallery-with-caption.json | 10 +++++-- .../fixtures/blocks/core__gallery.json | 10 +++++-- .../blocks/core__gallery__columns.json | 10 +++++-- .../blocks/core__gallery__deprecated-1.json | 10 +++++-- .../blocks/core__gallery__deprecated-2.json | 10 +++++-- .../blocks/core__gallery__deprecated-3.json | 10 +++++-- .../blocks/core__gallery__deprecated-4.json | 15 ++++++++-- .../blocks/core__gallery__deprecated-5.json | 15 ++++++++-- .../blocks/core__gallery__deprecated-6.json | 15 ++++++++-- .../blocks/core__gallery__deprecated-7.json | 30 +++++++++++++++---- .../fixtures/blocks/core__image.json | 5 +++- .../blocks/core__image__attachment-link.json | 5 +++- .../blocks/core__image__center-caption.json | 5 +++- .../core__image__custom-link-class.json | 5 +++- .../blocks/core__image__custom-link-rel.json | 5 +++- .../blocks/core__image__custom-link.json | 5 +++- .../blocks/core__image__deprecated-3.json | 5 +++- .../blocks/core__image__media-link.json | 5 +++- 18 files changed, 140 insertions(+), 35 deletions(-) diff --git a/test/integration/fixtures/blocks/core__gallery-with-caption.json b/test/integration/fixtures/blocks/core__gallery-with-caption.json index 12b516606641d4..ac7adb1267d0c9 100644 --- a/test/integration/fixtures/blocks/core__gallery-with-caption.json +++ b/test/integration/fixtures/blocks/core__gallery-with-caption.json @@ -24,7 +24,10 @@ "caption": "", "id": 1421, "sizeSlug": "large", - "linkDestination": "none" + "linkDestination": "none", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] }, @@ -37,7 +40,10 @@ "caption": "", "id": 1440, "sizeSlug": "large", - "linkDestination": "none" + "linkDestination": "none", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery.json b/test/integration/fixtures/blocks/core__gallery.json index 8b7a1000d37ccc..009e8c076fd08f 100644 --- a/test/integration/fixtures/blocks/core__gallery.json +++ b/test/integration/fixtures/blocks/core__gallery.json @@ -24,7 +24,10 @@ "caption": "", "id": 1421, "sizeSlug": "large", - "linkDestination": "none" + "linkDestination": "none", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] }, @@ -37,7 +40,10 @@ "caption": "", "id": 1440, "sizeSlug": "large", - "linkDestination": "none" + "linkDestination": "none", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__columns.json b/test/integration/fixtures/blocks/core__gallery__columns.json index d0c40b3d3a9a93..f464f7664abfd6 100644 --- a/test/integration/fixtures/blocks/core__gallery__columns.json +++ b/test/integration/fixtures/blocks/core__gallery__columns.json @@ -24,7 +24,10 @@ "caption": "", "id": 1421, "sizeSlug": "large", - "linkDestination": "none" + "linkDestination": "none", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] }, @@ -37,7 +40,10 @@ "caption": "", "id": 1440, "sizeSlug": "large", - "linkDestination": "none" + "linkDestination": "none", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-1.json b/test/integration/fixtures/blocks/core__gallery__deprecated-1.json index 9e15ee7f1c7149..9a7f8bef587daa 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-1.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-1.json @@ -16,7 +16,10 @@ "attributes": { "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", "alt": "title", - "linkDestination": "none" + "linkDestination": "none", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] }, @@ -26,7 +29,10 @@ "attributes": { "url": "data:image/jpeg;base64,/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=", "alt": "title", - "linkDestination": "none" + "linkDestination": "none", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-2.json b/test/integration/fixtures/blocks/core__gallery__deprecated-2.json index a60776801eb337..f38d799d8c28f6 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-2.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-2.json @@ -18,7 +18,10 @@ "alt": "title", "caption": "", "id": 1, - "linkDestination": "none" + "linkDestination": "none", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] }, @@ -30,7 +33,10 @@ "alt": "title", "caption": "", "id": 2, - "linkDestination": "none" + "linkDestination": "none", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-3.json b/test/integration/fixtures/blocks/core__gallery__deprecated-3.json index 9ac2c197819ce5..8df5a76cf1a3d4 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-3.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-3.json @@ -16,7 +16,10 @@ "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", "alt": "title", "caption": "", - "linkDestination": "none" + "linkDestination": "none", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] }, @@ -27,7 +30,10 @@ "url": "data:image/jpeg;base64,/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=", "alt": "title", "caption": "", - "linkDestination": "none" + "linkDestination": "none", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-4.json b/test/integration/fixtures/blocks/core__gallery__deprecated-4.json index dad150cc96b48b..1849374547c6c2 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-4.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-4.json @@ -18,7 +18,10 @@ "alt": "", "caption": "", "id": 1421, - "linkDestination": "none" + "linkDestination": "none", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] }, @@ -30,7 +33,10 @@ "alt": "", "caption": "", "id": 1440, - "linkDestination": "none" + "linkDestination": "none", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] }, @@ -42,7 +48,10 @@ "alt": "", "caption": "", "id": 1362, - "linkDestination": "none" + "linkDestination": "none", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-5.json b/test/integration/fixtures/blocks/core__gallery__deprecated-5.json index 9ef1f03ba09349..78719d37808f2e 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-5.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-5.json @@ -20,7 +20,10 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1-682x1024.jpg", "id": 705, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] }, @@ -34,7 +37,10 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1024x682.jpg", "id": 704, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] }, @@ -48,7 +54,10 @@ "href": "http://wptest.local/wp-content/uploads/2020/04/test-image-1024x683.jpg", "id": 703, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-6.json b/test/integration/fixtures/blocks/core__gallery__deprecated-6.json index 9ef1f03ba09349..78719d37808f2e 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-6.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-6.json @@ -20,7 +20,10 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1-682x1024.jpg", "id": 705, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] }, @@ -34,7 +37,10 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1024x682.jpg", "id": 704, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] }, @@ -48,7 +54,10 @@ "href": "http://wptest.local/wp-content/uploads/2020/04/test-image-1024x683.jpg", "id": 703, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-7.json b/test/integration/fixtures/blocks/core__gallery__deprecated-7.json index 4eaf85b46906d6..440087e65fd55d 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-7.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-7.json @@ -24,7 +24,10 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1-682x1024.jpg", "id": 705, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] }, @@ -38,7 +41,10 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1024x682.jpg", "id": 704, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] }, @@ -52,7 +58,10 @@ "href": "http://wptest.local/wp-content/uploads/2020/04/test-image-1024x683.jpg", "id": 703, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } @@ -83,7 +92,10 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1-682x1024.jpg", "id": 705, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] }, @@ -97,7 +109,10 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1024x682.jpg", "id": 704, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] }, @@ -111,7 +126,10 @@ "href": "http://wptest.local/wp-content/uploads/2020/04/test-image-1024x683.jpg", "id": 703, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image.json b/test/integration/fixtures/blocks/core__image.json index 3da5557bb05cad..1a7d3ea108b15a 100644 --- a/test/integration/fixtures/blocks/core__image.json +++ b/test/integration/fixtures/blocks/core__image.json @@ -5,7 +5,10 @@ "attributes": { "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", "alt": "", - "caption": "" + "caption": "", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__attachment-link.json b/test/integration/fixtures/blocks/core__image__attachment-link.json index 055e4a61d2f383..ff29c929692a8f 100644 --- a/test/integration/fixtures/blocks/core__image__attachment-link.json +++ b/test/integration/fixtures/blocks/core__image__attachment-link.json @@ -7,7 +7,10 @@ "alt": "", "caption": "", "href": "http://localhost:8888/?attachment_id=7", - "linkDestination": "attachment" + "linkDestination": "attachment", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__center-caption.json b/test/integration/fixtures/blocks/core__image__center-caption.json index a369e433b4028e..527df0a23af3b4 100644 --- a/test/integration/fixtures/blocks/core__image__center-caption.json +++ b/test/integration/fixtures/blocks/core__image__center-caption.json @@ -6,7 +6,10 @@ "align": "center", "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", "alt": "", - "caption": "Give it a try. Press the \"really wide\" button on the image toolbar." + "caption": "Give it a try. Press the \"really wide\" button on the image toolbar.", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__custom-link-class.json b/test/integration/fixtures/blocks/core__image__custom-link-class.json index 2b5a36e78bdb8b..51cf778064dc01 100644 --- a/test/integration/fixtures/blocks/core__image__custom-link-class.json +++ b/test/integration/fixtures/blocks/core__image__custom-link-class.json @@ -8,7 +8,10 @@ "caption": "", "href": "https://wordpress.org/", "linkClass": "custom-link", - "linkDestination": "custom" + "linkDestination": "custom", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__custom-link-rel.json b/test/integration/fixtures/blocks/core__image__custom-link-rel.json index dc3a04a932c415..ab4811c1beda57 100644 --- a/test/integration/fixtures/blocks/core__image__custom-link-rel.json +++ b/test/integration/fixtures/blocks/core__image__custom-link-rel.json @@ -8,7 +8,10 @@ "caption": "", "href": "https://wordpress.org/", "rel": "external", - "linkDestination": "custom" + "linkDestination": "custom", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__custom-link.json b/test/integration/fixtures/blocks/core__image__custom-link.json index 54cfa81f72b148..ad0dba78def177 100644 --- a/test/integration/fixtures/blocks/core__image__custom-link.json +++ b/test/integration/fixtures/blocks/core__image__custom-link.json @@ -7,7 +7,10 @@ "alt": "", "caption": "", "href": "https://wordpress.org/", - "linkDestination": "custom" + "linkDestination": "custom", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__deprecated-3.json b/test/integration/fixtures/blocks/core__image__deprecated-3.json index bae213510011ac..0fcb09638eef8b 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-3.json +++ b/test/integration/fixtures/blocks/core__image__deprecated-3.json @@ -8,7 +8,10 @@ "alt": "", "caption": "", "width": 100, - "height": 100 + "height": 100, + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__media-link.json b/test/integration/fixtures/blocks/core__image__media-link.json index 0d411f713203de..300f4ba7dadfa4 100644 --- a/test/integration/fixtures/blocks/core__image__media-link.json +++ b/test/integration/fixtures/blocks/core__image__media-link.json @@ -7,7 +7,10 @@ "alt": "", "caption": "", "href": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", - "linkDestination": "media" + "linkDestination": "media", + "behaviors": { + "lightbox": true + } }, "innerBlocks": [] } From 4e03e0d0c4902d047221b979f816f2b42bb67d4a Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 15 May 2023 23:37:37 -0500 Subject: [PATCH 017/125] Add a new theme for e2e tests --- .../{behaviors => behaviors-disabled}/index.php | 0 .../{behaviors => behaviors-disabled}/style.css | 0 .../{behaviors => behaviors-disabled}/theme.json | 0 .../behaviors-false/index.php | 0 .../behaviors-false/style.css | 15 +++++++++++++++ .../behaviors-false/theme.json | 8 ++++++++ 6 files changed, 23 insertions(+) rename test/gutenberg-test-themes/{behaviors => behaviors-disabled}/index.php (100%) rename test/gutenberg-test-themes/{behaviors => behaviors-disabled}/style.css (100%) rename test/gutenberg-test-themes/{behaviors => behaviors-disabled}/theme.json (100%) create mode 100644 test/gutenberg-test-themes/behaviors-false/index.php create mode 100644 test/gutenberg-test-themes/behaviors-false/style.css create mode 100644 test/gutenberg-test-themes/behaviors-false/theme.json diff --git a/test/gutenberg-test-themes/behaviors/index.php b/test/gutenberg-test-themes/behaviors-disabled/index.php similarity index 100% rename from test/gutenberg-test-themes/behaviors/index.php rename to test/gutenberg-test-themes/behaviors-disabled/index.php diff --git a/test/gutenberg-test-themes/behaviors/style.css b/test/gutenberg-test-themes/behaviors-disabled/style.css similarity index 100% rename from test/gutenberg-test-themes/behaviors/style.css rename to test/gutenberg-test-themes/behaviors-disabled/style.css diff --git a/test/gutenberg-test-themes/behaviors/theme.json b/test/gutenberg-test-themes/behaviors-disabled/theme.json similarity index 100% rename from test/gutenberg-test-themes/behaviors/theme.json rename to test/gutenberg-test-themes/behaviors-disabled/theme.json diff --git a/test/gutenberg-test-themes/behaviors-false/index.php b/test/gutenberg-test-themes/behaviors-false/index.php new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/test/gutenberg-test-themes/behaviors-false/style.css b/test/gutenberg-test-themes/behaviors-false/style.css new file mode 100644 index 00000000000000..972dbacbb5cabd --- /dev/null +++ b/test/gutenberg-test-themes/behaviors-false/style.css @@ -0,0 +1,15 @@ +/* +Theme Name: Behaviors +Theme URI: https://github.com/wordpress/theme-experiments/ +Author: the WordPress team +Description: Behaviors test theme. +Requires at least: 5.3 +Tested up to: 6.2 +Requires PHP: 5.6 +Version: 1.0 +License: GNU General Public License v2 or later +License URI: http://www.gnu.org/licenses/gpl-2.0.html +Text Domain: behaviors +Behaviors WordPress Theme, (C) 2023 WordPress.org +Behaviors is distributed under the terms of the GNU GPL. +*/ \ No newline at end of file diff --git a/test/gutenberg-test-themes/behaviors-false/theme.json b/test/gutenberg-test-themes/behaviors-false/theme.json new file mode 100644 index 00000000000000..6b06b08098a9df --- /dev/null +++ b/test/gutenberg-test-themes/behaviors-false/theme.json @@ -0,0 +1,8 @@ +{ + "version": 2, + "settings": { + "behaviors": { + "lightbox": false + } + } +} From 92b6e6c67c9e28609f4f7a734130078733232b2e Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 15 May 2023 23:39:57 -0500 Subject: [PATCH 018/125] Change theme.json to include `settings.behaviors` --- lib/theme.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/theme.json b/lib/theme.json index 09949e539dcf53..c62fa3b7f28c19 100644 --- a/lib/theme.json +++ b/lib/theme.json @@ -1,6 +1,9 @@ { "version": 2, "settings": { + "behaviors": { + "lightbox": true + }, "appearanceTools": false, "useRootPaddingAwareAlignments": false, "border": { From ffa881e3e8f99d607fd5eb8163ae937c6b2693a3 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 15 May 2023 23:41:09 -0500 Subject: [PATCH 019/125] Remove default behavior value from block.json --- packages/block-library/src/image/block.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index f2e9be4e10e06d..791e09f73c8009 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -82,10 +82,7 @@ "attribute": "target" }, "behaviors": { - "type": "object", - "default": { - "lightbox": true - } + "type": "object" } }, "supports": { From 99c964b639f651220a7cd6f7ad8c3440b3be8ca4 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 15 May 2023 23:41:58 -0500 Subject: [PATCH 020/125] Minor fix to the implementation --- packages/block-editor/src/hooks/behaviors.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index 0aae8fdbea48ba..3724bd126b759c 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -42,16 +42,15 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { const { behaviors: blockBehaviors } = props.attributes; - // TODO: Here we should get the theme behaviors but it doesn't work ATM. - const themeBehaviors = settings?.behaviors; + // Get the theme behaviors from the theme.json. + // + // TODO: We probably want to use a top-level `behaviors` property of + // `theme.json` instead of `settings.behaviors` like we do now. + const themeBehaviors = settings?.__experimentalFeatures?.behaviors; // By default, use the block behaviors. - let behaviors = blockBehaviors; - // If the theme has behaviors, but the block does not, use the theme behaviors. - if ( ! blockBehaviors && themeBehaviors ) { - behaviors = themeBehaviors; - } + const behaviors = blockBehaviors || themeBehaviors || {}; return ( <> From 7f7db2c8394073f01158e3c6f58c88a9c457f03f Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 15 May 2023 23:42:14 -0500 Subject: [PATCH 021/125] Add more e2e tests --- .../specs/editor/various/behaviors.spec.js | 89 +++++++++++++++---- 1 file changed, 71 insertions(+), 18 deletions(-) diff --git a/test/e2e/specs/editor/various/behaviors.spec.js b/test/e2e/specs/editor/various/behaviors.spec.js index 5866721a05d5dc..97aa6300103a6c 100644 --- a/test/e2e/specs/editor/various/behaviors.spec.js +++ b/test/e2e/specs/editor/various/behaviors.spec.js @@ -9,6 +9,15 @@ const path = require( 'path' ); const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); test.describe( 'Testing behaviors functionality', () => { + const filename = '1024x768_e2e_test_image_size.jpeg'; + const filepath = path.join( './test/e2e/assets', filename ); + + const createMedia = async ( { admin, requestUtils } ) => { + await admin.createNewPost(); + const media = await requestUtils.uploadMedia( filepath ); + return media; + }; + test.afterAll( async ( { requestUtils } ) => { await requestUtils.activateTheme( 'twentytwentyone' ); await requestUtils.deleteAllPosts(); @@ -18,19 +27,14 @@ test.describe( 'Testing behaviors functionality', () => { await requestUtils.deleteAllMedia(); } ); - test( 'Lightbox option should be selected in an image block, as defined in theme.json', async ( { + test( 'Lightbox behavior should be selected by default as defined in the core theme.json', async ( { admin, editor, requestUtils, page, } ) => { - await admin.createNewPost(); - const filename = '1024x768_e2e_test_image_size.jpeg'; - const filepath = path.join( './test/e2e/assets', filename ); - - await admin.createNewPost(); - const media = await requestUtils.uploadMedia( filepath ); - + await requestUtils.activateTheme( 'twentytwentyone' ); + const media = await createMedia( { admin, requestUtils } ); await editor.insertBlock( { name: 'core/image', attributes: { @@ -45,21 +49,41 @@ test.describe( 'Testing behaviors functionality', () => { await expect( page.getByLabel( 'Behavior' ) ).toHaveValue( 'lightbox' ); } ); - test( 'None option should be selected in an image block, as defined in theme.json', async ( { + test( 'Behaviors UI can be disabled in the `theme.json`', async ( { admin, editor, requestUtils, page, } ) => { - // Lightbox is the default behavior, so we need a theme that has it disabled. Change if we change the default. - await requestUtils.activateTheme( 'behaviors' ); - await admin.createNewPost(); + // { "lightbox": true } is the default behavior, so we activate the + // `behaviors` theme where it is disabled by default. Change if we change + // the default value in the core theme.json file. + await requestUtils.activateTheme( 'behaviors-disabled' ); + const media = await createMedia( { admin, requestUtils } ); - const filename = '1024x768_e2e_test_image_size.jpeg'; - const filepath = path.join( './test/e2e/assets', filename ); + await editor.insertBlock( { + name: 'core/image', + attributes: { + alt: filename, + id: media.id, + url: media.source_url, + }, + } ); - await admin.createNewPost(); - const media = await requestUtils.uploadMedia( filepath ); + await page.getByRole( 'button', { name: 'Advanced' } ).click(); + + // No behaviors dropdown should be present. + await expect( page.getByLabel( 'Behavior' ) ).toHaveCount( 0 ); + } ); + + test( "Block's value for behaviors takes precedence over the theme's value", async ( { + admin, + editor, + requestUtils, + page, + } ) => { + await requestUtils.activateTheme( 'twentytwentyone' ); + const media = await createMedia( { admin, requestUtils } ); await editor.insertBlock( { name: 'core/image', @@ -67,11 +91,40 @@ test.describe( 'Testing behaviors functionality', () => { alt: filename, id: media.id, url: media.source_url, + // Explicitly set the value for behaviors to false. + behaviors: { lightbox: false }, }, } ); await page.getByRole( 'button', { name: 'Advanced' } ).click(); - // Right now the selector should not appear. - await expect( page.getByLabel( 'Behavior' ) ).toHaveCount( 0 ); + await expect( page.getByLabel( 'Behavior' ) ).toHaveCount( 1 ); + await expect( page.getByLabel( 'Behavior' ) ).toHaveValue( '' ); + } ); + + test( 'You can set the default value for the behaviors in the theme.json', async ( { + admin, + editor, + requestUtils, + page, + } ) => { + // In this theme, the default value for settings.behaviors.lightbox is `false`. + await requestUtils.activateTheme( 'behaviors-false' ); + const media = await createMedia( { admin, requestUtils } ); + + await editor.insertBlock( { + name: 'core/image', + attributes: { + alt: filename, + id: media.id, + url: media.source_url, + }, + } ); + + await page.getByRole( 'button', { name: 'Advanced' } ).click(); + await expect( page.getByLabel( 'Behavior' ) ).toHaveCount( 1 ); + + // The default value for behaviors in `theme.json` is `false`, so the + // dropdown should be present, but the value should be `""` (None). + await expect( page.getByLabel( 'Behavior' ) ).toHaveValue( '' ); } ); } ); From 5e5ff9a028daa940570baf9710a456ce53ee13f1 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 16 May 2023 19:47:03 -0500 Subject: [PATCH 022/125] Create a selector for behaviors --- packages/block-editor/src/store/selectors.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 59c36dca2b8237..1e4fb921275508 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -2490,6 +2490,17 @@ export function getSettings( state ) { return state.settings; } +/** + * Returns the behaviors. + * + * @param {Object} state Editor state. + * + * @return {Object} The editor behaviors object. + */ +export function getBehaviors( state ) { + return state.settings.behaviors; +} + /** * Returns true if the most recent block change is be considered persistent, or * false otherwise. A persistent change is one committed by BlockEditorProvider From ad20b642119eef5a6d73a2709617149f6a7e0204 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 16 May 2023 19:47:57 -0500 Subject: [PATCH 023/125] Add a filter to load behaviors on the server from the theme.json --- lib/class-wp-theme-json-gutenberg.php | 1 + lib/compat/wordpress-6.3/behaviors.php | 17 +++++++++++++++++ lib/load.php | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 lib/compat/wordpress-6.3/behaviors.php diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 5eb65062d5a5c5..ef69437b95142b 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -323,6 +323,7 @@ class WP_Theme_JSON_Gutenberg { 'templateParts', 'title', 'version', + 'behaviors', ); /** diff --git a/lib/compat/wordpress-6.3/behaviors.php b/lib/compat/wordpress-6.3/behaviors.php new file mode 100644 index 00000000000000..e4348948bebfd7 --- /dev/null +++ b/lib/compat/wordpress-6.3/behaviors.php @@ -0,0 +1,17 @@ +get_data()['behaviors']; + return $settings; + }, + PHP_INT_MAX +); diff --git a/lib/load.php b/lib/load.php index a97a7cdc881f5e..c99e0ec9e98b79 100644 --- a/lib/load.php +++ b/lib/load.php @@ -93,6 +93,7 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/compat/wordpress-6.3/html-api/class-gutenberg-html-tag-processor-6-3.php'; require __DIR__ . '/compat/wordpress-6.3/script-loader.php'; require __DIR__ . '/compat/wordpress-6.3/blocks.php'; +require __DIR__ . '/compat/wordpress-6.3/behaviors.php'; // Experimental features. remove_action( 'plugins_loaded', '_wp_theme_json_webfonts_handler' ); // Turns off WP 6.0's stopgap handler for Webfonts API. @@ -165,4 +166,3 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/block-supports/duotone.php'; require __DIR__ . '/block-supports/anchor.php'; require __DIR__ . '/block-supports/shadow.php'; - From d16266b4f5ad3c827e669c3c3b4899f6303abaf7 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 16 May 2023 19:48:40 -0500 Subject: [PATCH 024/125] Add behaviors on the top-level in core theme.json --- lib/theme.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/theme.json b/lib/theme.json index c62fa3b7f28c19..c030305314ba0b 100644 --- a/lib/theme.json +++ b/lib/theme.json @@ -1,9 +1,9 @@ { "version": 2, + "behaviors": { + "lightbox": true + }, "settings": { - "behaviors": { - "lightbox": true - }, "appearanceTools": false, "useRootPaddingAwareAlignments": false, "border": { From 0982d9f8988d1830f7580051e95ab62031cee574 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 16 May 2023 19:49:26 -0500 Subject: [PATCH 025/125] Use the behaviors in the hooks --- packages/block-editor/src/hooks/behaviors.js | 2 +- .../editor/src/components/provider/use-block-editor-settings.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index 3724bd126b759c..6cfac1936ff053 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -46,7 +46,7 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { // // TODO: We probably want to use a top-level `behaviors` property of // `theme.json` instead of `settings.behaviors` like we do now. - const themeBehaviors = settings?.__experimentalFeatures?.behaviors; + const themeBehaviors = select( blockEditorStore ).getBehaviors(); // By default, use the block behaviors. // If the theme has behaviors, but the block does not, use the theme behaviors. diff --git a/packages/editor/src/components/provider/use-block-editor-settings.js b/packages/editor/src/components/provider/use-block-editor-settings.js index d8035f4f54fca1..33a28460c39cdc 100644 --- a/packages/editor/src/components/provider/use-block-editor-settings.js +++ b/packages/editor/src/components/provider/use-block-editor-settings.js @@ -194,6 +194,7 @@ function useBlockEditorSettings( settings, hasTemplate ) { BLOCK_EDITOR_SETTINGS.includes( key ) ) ), + behaviors: settings.behaviors, mediaUpload: hasUploadPermissions ? mediaUpload : undefined, __experimentalReusableBlocks: reusableBlocks, __experimentalBlockPatterns: blockPatterns, From 0ef7b5e0e709962d24ba66368394482303de7ef2 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 16 May 2023 19:51:22 -0500 Subject: [PATCH 026/125] Update the comment --- lib/compat/wordpress-6.3/behaviors.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compat/wordpress-6.3/behaviors.php b/lib/compat/wordpress-6.3/behaviors.php index e4348948bebfd7..401a94bf338445 100644 --- a/lib/compat/wordpress-6.3/behaviors.php +++ b/lib/compat/wordpress-6.3/behaviors.php @@ -9,7 +9,7 @@ 'block_editor_settings_all', function( $settings ) { - // Make sure to also get the value from the core theme.json file. + // TODO: Make sure to also get the value from the core theme.json file. $settings['behaviors'] = WP_Theme_JSON_Resolver_Gutenberg::get_theme_data()->get_data()['behaviors']; return $settings; }, From e75fd87a30b38572cd4c064509a745b4404e5faf Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 16 May 2023 19:52:25 -0500 Subject: [PATCH 027/125] Update the comment in behaviors.js --- packages/block-editor/src/hooks/behaviors.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index 6cfac1936ff053..d3ea7938d28846 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -43,9 +43,6 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { const { behaviors: blockBehaviors } = props.attributes; // Get the theme behaviors from the theme.json. - // - // TODO: We probably want to use a top-level `behaviors` property of - // `theme.json` instead of `settings.behaviors` like we do now. const themeBehaviors = select( blockEditorStore ).getBehaviors(); // By default, use the block behaviors. From f6414f98964fb8b8da21965fdb0963d1caa20675 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Wed, 17 May 2023 14:56:25 +0200 Subject: [PATCH 028/125] Update fixtures and e2e --- .../data/data-core-block-editor.md | 12 ++++++++ .../specs/editor/various/behaviors.spec.js | 2 +- .../blocks/core__gallery-with-caption.json | 10 ++----- .../fixtures/blocks/core__gallery.json | 10 ++----- .../blocks/core__gallery__columns.json | 10 ++----- .../blocks/core__gallery__deprecated-1.json | 10 ++----- .../blocks/core__gallery__deprecated-2.json | 10 ++----- .../blocks/core__gallery__deprecated-3.json | 10 ++----- .../blocks/core__gallery__deprecated-4.json | 15 ++-------- .../blocks/core__gallery__deprecated-5.json | 15 ++-------- .../blocks/core__gallery__deprecated-6.json | 15 ++-------- .../blocks/core__gallery__deprecated-7.json | 30 ++++--------------- .../fixtures/blocks/core__image.json | 5 +--- .../blocks/core__image__attachment-link.json | 5 +--- .../blocks/core__image__center-caption.json | 5 +--- .../core__image__custom-link-class.json | 5 +--- .../blocks/core__image__custom-link-rel.json | 5 +--- .../blocks/core__image__custom-link.json | 5 +--- .../blocks/core__image__deprecated-3.json | 5 +--- .../blocks/core__image__media-link.json | 5 +--- 20 files changed, 48 insertions(+), 141 deletions(-) diff --git a/docs/reference-guides/data/data-core-block-editor.md b/docs/reference-guides/data/data-core-block-editor.md index a3d6fa25e97c89..d8a3e2259c36d9 100644 --- a/docs/reference-guides/data/data-core-block-editor.md +++ b/docs/reference-guides/data/data-core-block-editor.md @@ -168,6 +168,18 @@ _Returns_ - `Array?`: The list of allowed block types. +### getBehaviors + +Returns the behaviors. + +_Parameters_ + +- _state_ `Object`: Editor state. + +_Returns_ + +- `Object`: The editor behaviors object. + ### getBlock Returns a block given its client ID. This is a parsed copy of the block, containing its `blockName`, `clientId`, and current `attributes` state. This is not the block's registration settings, which must be retrieved from the blocks module registration store. diff --git a/test/e2e/specs/editor/various/behaviors.spec.js b/test/e2e/specs/editor/various/behaviors.spec.js index 97aa6300103a6c..c1babb6b846b72 100644 --- a/test/e2e/specs/editor/various/behaviors.spec.js +++ b/test/e2e/specs/editor/various/behaviors.spec.js @@ -46,7 +46,7 @@ test.describe( 'Testing behaviors functionality', () => { await page.getByRole( 'button', { name: 'Advanced' } ).click(); await expect( page.getByLabel( 'Behavior' ) ).toHaveCount( 1 ); - await expect( page.getByLabel( 'Behavior' ) ).toHaveValue( 'lightbox' ); + await expect( page.getByLabel( 'Behavior' ) ).toHaveValue( '' ); } ); test( 'Behaviors UI can be disabled in the `theme.json`', async ( { diff --git a/test/integration/fixtures/blocks/core__gallery-with-caption.json b/test/integration/fixtures/blocks/core__gallery-with-caption.json index ac7adb1267d0c9..12b516606641d4 100644 --- a/test/integration/fixtures/blocks/core__gallery-with-caption.json +++ b/test/integration/fixtures/blocks/core__gallery-with-caption.json @@ -24,10 +24,7 @@ "caption": "", "id": 1421, "sizeSlug": "large", - "linkDestination": "none", - "behaviors": { - "lightbox": true - } + "linkDestination": "none" }, "innerBlocks": [] }, @@ -40,10 +37,7 @@ "caption": "", "id": 1440, "sizeSlug": "large", - "linkDestination": "none", - "behaviors": { - "lightbox": true - } + "linkDestination": "none" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery.json b/test/integration/fixtures/blocks/core__gallery.json index 009e8c076fd08f..8b7a1000d37ccc 100644 --- a/test/integration/fixtures/blocks/core__gallery.json +++ b/test/integration/fixtures/blocks/core__gallery.json @@ -24,10 +24,7 @@ "caption": "", "id": 1421, "sizeSlug": "large", - "linkDestination": "none", - "behaviors": { - "lightbox": true - } + "linkDestination": "none" }, "innerBlocks": [] }, @@ -40,10 +37,7 @@ "caption": "", "id": 1440, "sizeSlug": "large", - "linkDestination": "none", - "behaviors": { - "lightbox": true - } + "linkDestination": "none" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__columns.json b/test/integration/fixtures/blocks/core__gallery__columns.json index f464f7664abfd6..d0c40b3d3a9a93 100644 --- a/test/integration/fixtures/blocks/core__gallery__columns.json +++ b/test/integration/fixtures/blocks/core__gallery__columns.json @@ -24,10 +24,7 @@ "caption": "", "id": 1421, "sizeSlug": "large", - "linkDestination": "none", - "behaviors": { - "lightbox": true - } + "linkDestination": "none" }, "innerBlocks": [] }, @@ -40,10 +37,7 @@ "caption": "", "id": 1440, "sizeSlug": "large", - "linkDestination": "none", - "behaviors": { - "lightbox": true - } + "linkDestination": "none" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-1.json b/test/integration/fixtures/blocks/core__gallery__deprecated-1.json index 9a7f8bef587daa..9e15ee7f1c7149 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-1.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-1.json @@ -16,10 +16,7 @@ "attributes": { "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", "alt": "title", - "linkDestination": "none", - "behaviors": { - "lightbox": true - } + "linkDestination": "none" }, "innerBlocks": [] }, @@ -29,10 +26,7 @@ "attributes": { "url": "data:image/jpeg;base64,/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=", "alt": "title", - "linkDestination": "none", - "behaviors": { - "lightbox": true - } + "linkDestination": "none" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-2.json b/test/integration/fixtures/blocks/core__gallery__deprecated-2.json index f38d799d8c28f6..a60776801eb337 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-2.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-2.json @@ -18,10 +18,7 @@ "alt": "title", "caption": "", "id": 1, - "linkDestination": "none", - "behaviors": { - "lightbox": true - } + "linkDestination": "none" }, "innerBlocks": [] }, @@ -33,10 +30,7 @@ "alt": "title", "caption": "", "id": 2, - "linkDestination": "none", - "behaviors": { - "lightbox": true - } + "linkDestination": "none" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-3.json b/test/integration/fixtures/blocks/core__gallery__deprecated-3.json index 8df5a76cf1a3d4..9ac2c197819ce5 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-3.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-3.json @@ -16,10 +16,7 @@ "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", "alt": "title", "caption": "", - "linkDestination": "none", - "behaviors": { - "lightbox": true - } + "linkDestination": "none" }, "innerBlocks": [] }, @@ -30,10 +27,7 @@ "url": "data:image/jpeg;base64,/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=", "alt": "title", "caption": "", - "linkDestination": "none", - "behaviors": { - "lightbox": true - } + "linkDestination": "none" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-4.json b/test/integration/fixtures/blocks/core__gallery__deprecated-4.json index 1849374547c6c2..dad150cc96b48b 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-4.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-4.json @@ -18,10 +18,7 @@ "alt": "", "caption": "", "id": 1421, - "linkDestination": "none", - "behaviors": { - "lightbox": true - } + "linkDestination": "none" }, "innerBlocks": [] }, @@ -33,10 +30,7 @@ "alt": "", "caption": "", "id": 1440, - "linkDestination": "none", - "behaviors": { - "lightbox": true - } + "linkDestination": "none" }, "innerBlocks": [] }, @@ -48,10 +42,7 @@ "alt": "", "caption": "", "id": 1362, - "linkDestination": "none", - "behaviors": { - "lightbox": true - } + "linkDestination": "none" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-5.json b/test/integration/fixtures/blocks/core__gallery__deprecated-5.json index 78719d37808f2e..9ef1f03ba09349 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-5.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-5.json @@ -20,10 +20,7 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1-682x1024.jpg", "id": 705, "sizeSlug": "large", - "linkDestination": "media", - "behaviors": { - "lightbox": true - } + "linkDestination": "media" }, "innerBlocks": [] }, @@ -37,10 +34,7 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1024x682.jpg", "id": 704, "sizeSlug": "large", - "linkDestination": "media", - "behaviors": { - "lightbox": true - } + "linkDestination": "media" }, "innerBlocks": [] }, @@ -54,10 +48,7 @@ "href": "http://wptest.local/wp-content/uploads/2020/04/test-image-1024x683.jpg", "id": 703, "sizeSlug": "large", - "linkDestination": "media", - "behaviors": { - "lightbox": true - } + "linkDestination": "media" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-6.json b/test/integration/fixtures/blocks/core__gallery__deprecated-6.json index 78719d37808f2e..9ef1f03ba09349 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-6.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-6.json @@ -20,10 +20,7 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1-682x1024.jpg", "id": 705, "sizeSlug": "large", - "linkDestination": "media", - "behaviors": { - "lightbox": true - } + "linkDestination": "media" }, "innerBlocks": [] }, @@ -37,10 +34,7 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1024x682.jpg", "id": 704, "sizeSlug": "large", - "linkDestination": "media", - "behaviors": { - "lightbox": true - } + "linkDestination": "media" }, "innerBlocks": [] }, @@ -54,10 +48,7 @@ "href": "http://wptest.local/wp-content/uploads/2020/04/test-image-1024x683.jpg", "id": 703, "sizeSlug": "large", - "linkDestination": "media", - "behaviors": { - "lightbox": true - } + "linkDestination": "media" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-7.json b/test/integration/fixtures/blocks/core__gallery__deprecated-7.json index 440087e65fd55d..4eaf85b46906d6 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-7.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-7.json @@ -24,10 +24,7 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1-682x1024.jpg", "id": 705, "sizeSlug": "large", - "linkDestination": "media", - "behaviors": { - "lightbox": true - } + "linkDestination": "media" }, "innerBlocks": [] }, @@ -41,10 +38,7 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1024x682.jpg", "id": 704, "sizeSlug": "large", - "linkDestination": "media", - "behaviors": { - "lightbox": true - } + "linkDestination": "media" }, "innerBlocks": [] }, @@ -58,10 +52,7 @@ "href": "http://wptest.local/wp-content/uploads/2020/04/test-image-1024x683.jpg", "id": 703, "sizeSlug": "large", - "linkDestination": "media", - "behaviors": { - "lightbox": true - } + "linkDestination": "media" }, "innerBlocks": [] } @@ -92,10 +83,7 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1-682x1024.jpg", "id": 705, "sizeSlug": "large", - "linkDestination": "media", - "behaviors": { - "lightbox": true - } + "linkDestination": "media" }, "innerBlocks": [] }, @@ -109,10 +97,7 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1024x682.jpg", "id": 704, "sizeSlug": "large", - "linkDestination": "media", - "behaviors": { - "lightbox": true - } + "linkDestination": "media" }, "innerBlocks": [] }, @@ -126,10 +111,7 @@ "href": "http://wptest.local/wp-content/uploads/2020/04/test-image-1024x683.jpg", "id": 703, "sizeSlug": "large", - "linkDestination": "media", - "behaviors": { - "lightbox": true - } + "linkDestination": "media" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image.json b/test/integration/fixtures/blocks/core__image.json index 1a7d3ea108b15a..3da5557bb05cad 100644 --- a/test/integration/fixtures/blocks/core__image.json +++ b/test/integration/fixtures/blocks/core__image.json @@ -5,10 +5,7 @@ "attributes": { "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", "alt": "", - "caption": "", - "behaviors": { - "lightbox": true - } + "caption": "" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__attachment-link.json b/test/integration/fixtures/blocks/core__image__attachment-link.json index ff29c929692a8f..055e4a61d2f383 100644 --- a/test/integration/fixtures/blocks/core__image__attachment-link.json +++ b/test/integration/fixtures/blocks/core__image__attachment-link.json @@ -7,10 +7,7 @@ "alt": "", "caption": "", "href": "http://localhost:8888/?attachment_id=7", - "linkDestination": "attachment", - "behaviors": { - "lightbox": true - } + "linkDestination": "attachment" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__center-caption.json b/test/integration/fixtures/blocks/core__image__center-caption.json index 527df0a23af3b4..a369e433b4028e 100644 --- a/test/integration/fixtures/blocks/core__image__center-caption.json +++ b/test/integration/fixtures/blocks/core__image__center-caption.json @@ -6,10 +6,7 @@ "align": "center", "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", "alt": "", - "caption": "Give it a try. Press the \"really wide\" button on the image toolbar.", - "behaviors": { - "lightbox": true - } + "caption": "Give it a try. Press the \"really wide\" button on the image toolbar." }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__custom-link-class.json b/test/integration/fixtures/blocks/core__image__custom-link-class.json index 51cf778064dc01..2b5a36e78bdb8b 100644 --- a/test/integration/fixtures/blocks/core__image__custom-link-class.json +++ b/test/integration/fixtures/blocks/core__image__custom-link-class.json @@ -8,10 +8,7 @@ "caption": "", "href": "https://wordpress.org/", "linkClass": "custom-link", - "linkDestination": "custom", - "behaviors": { - "lightbox": true - } + "linkDestination": "custom" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__custom-link-rel.json b/test/integration/fixtures/blocks/core__image__custom-link-rel.json index ab4811c1beda57..dc3a04a932c415 100644 --- a/test/integration/fixtures/blocks/core__image__custom-link-rel.json +++ b/test/integration/fixtures/blocks/core__image__custom-link-rel.json @@ -8,10 +8,7 @@ "caption": "", "href": "https://wordpress.org/", "rel": "external", - "linkDestination": "custom", - "behaviors": { - "lightbox": true - } + "linkDestination": "custom" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__custom-link.json b/test/integration/fixtures/blocks/core__image__custom-link.json index ad0dba78def177..54cfa81f72b148 100644 --- a/test/integration/fixtures/blocks/core__image__custom-link.json +++ b/test/integration/fixtures/blocks/core__image__custom-link.json @@ -7,10 +7,7 @@ "alt": "", "caption": "", "href": "https://wordpress.org/", - "linkDestination": "custom", - "behaviors": { - "lightbox": true - } + "linkDestination": "custom" }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__deprecated-3.json b/test/integration/fixtures/blocks/core__image__deprecated-3.json index 0fcb09638eef8b..bae213510011ac 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-3.json +++ b/test/integration/fixtures/blocks/core__image__deprecated-3.json @@ -8,10 +8,7 @@ "alt": "", "caption": "", "width": 100, - "height": 100, - "behaviors": { - "lightbox": true - } + "height": 100 }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__media-link.json b/test/integration/fixtures/blocks/core__image__media-link.json index 300f4ba7dadfa4..0d411f713203de 100644 --- a/test/integration/fixtures/blocks/core__image__media-link.json +++ b/test/integration/fixtures/blocks/core__image__media-link.json @@ -7,10 +7,7 @@ "alt": "", "caption": "", "href": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", - "linkDestination": "media", - "behaviors": { - "lightbox": true - } + "linkDestination": "media" }, "innerBlocks": [] } From 31c0623d9cefd130591662bc92136819c06a31f3 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Thu, 18 May 2023 16:13:38 +0200 Subject: [PATCH 029/125] Prevent mobile test gutenberg error (temporary - not the best solution) --- lib/compat/wordpress-6.3/behaviors.php | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/compat/wordpress-6.3/behaviors.php b/lib/compat/wordpress-6.3/behaviors.php index 401a94bf338445..c83f1158deb3ac 100644 --- a/lib/compat/wordpress-6.3/behaviors.php +++ b/lib/compat/wordpress-6.3/behaviors.php @@ -8,10 +8,19 @@ add_filter( 'block_editor_settings_all', function( $settings ) { - + // Prevents testing error 'Undefined index: behaviors' in Gutenberg_REST_Block_Editor_Settings_Controller_Test. + // This should be removed once the REST API is updated to use the new theme.json file. + $is_mobile_context = ( + defined( 'REST_REQUEST' ) && + REST_REQUEST && + isset( $_GET['context'] ) && + 'mobile' === $_GET['context'] + ); + if (! $is_mobile_context) { + $settings['behaviors'] = WP_Theme_JSON_Resolver_Gutenberg::get_theme_data()->get_data()['behaviors']; + } // TODO: Make sure to also get the value from the core theme.json file. - $settings['behaviors'] = WP_Theme_JSON_Resolver_Gutenberg::get_theme_data()->get_data()['behaviors']; return $settings; }, - PHP_INT_MAX + 'post-editor' ); From ee3701f486d8ecd39592157b53ed0343f43b25a5 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Thu, 18 May 2023 16:14:10 +0200 Subject: [PATCH 030/125] Add priority on filter --- lib/compat/wordpress-6.3/behaviors.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compat/wordpress-6.3/behaviors.php b/lib/compat/wordpress-6.3/behaviors.php index c83f1158deb3ac..6f85cd20fb6e6f 100644 --- a/lib/compat/wordpress-6.3/behaviors.php +++ b/lib/compat/wordpress-6.3/behaviors.php @@ -22,5 +22,5 @@ function( $settings ) { // TODO: Make sure to also get the value from the core theme.json file. return $settings; }, - 'post-editor' + PHP_INT_MAX ); From a0ac74806af4e04917e823616c2c353dd6662ad7 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Thu, 18 May 2023 16:28:58 +0200 Subject: [PATCH 031/125] Fix php standards --- lib/compat/wordpress-6.3/behaviors.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compat/wordpress-6.3/behaviors.php b/lib/compat/wordpress-6.3/behaviors.php index 6f85cd20fb6e6f..cab95d11b9753e 100644 --- a/lib/compat/wordpress-6.3/behaviors.php +++ b/lib/compat/wordpress-6.3/behaviors.php @@ -16,7 +16,7 @@ function( $settings ) { isset( $_GET['context'] ) && 'mobile' === $_GET['context'] ); - if (! $is_mobile_context) { + if ( ! $is_mobile_context ) { $settings['behaviors'] = WP_Theme_JSON_Resolver_Gutenberg::get_theme_data()->get_data()['behaviors']; } // TODO: Make sure to also get the value from the core theme.json file. From 1dd6df1397c00b4634ac4feeee7b098f6fc64dad Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Thu, 18 May 2023 17:47:47 +0200 Subject: [PATCH 032/125] Found a much better way to fix php tests --- lib/compat/wordpress-6.3/behaviors.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/compat/wordpress-6.3/behaviors.php b/lib/compat/wordpress-6.3/behaviors.php index cab95d11b9753e..da73d82a6c0ff5 100644 --- a/lib/compat/wordpress-6.3/behaviors.php +++ b/lib/compat/wordpress-6.3/behaviors.php @@ -8,15 +8,8 @@ add_filter( 'block_editor_settings_all', function( $settings ) { - // Prevents testing error 'Undefined index: behaviors' in Gutenberg_REST_Block_Editor_Settings_Controller_Test. - // This should be removed once the REST API is updated to use the new theme.json file. - $is_mobile_context = ( - defined( 'REST_REQUEST' ) && - REST_REQUEST && - isset( $_GET['context'] ) && - 'mobile' === $_GET['context'] - ); - if ( ! $is_mobile_context ) { + $theme_data = WP_Theme_JSON_Resolver_Gutenberg::get_theme_data()->get_data(); + if ( array_key_exists( 'behaviors', $theme_data ) ) { $settings['behaviors'] = WP_Theme_JSON_Resolver_Gutenberg::get_theme_data()->get_data()['behaviors']; } // TODO: Make sure to also get the value from the core theme.json file. From a7372007ef1492ef84cca90c7ef381c9d4cd48ac Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Thu, 18 May 2023 20:42:00 +0200 Subject: [PATCH 033/125] Small refactor --- lib/compat/wordpress-6.3/behaviors.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compat/wordpress-6.3/behaviors.php b/lib/compat/wordpress-6.3/behaviors.php index da73d82a6c0ff5..c2c51e9a92a778 100644 --- a/lib/compat/wordpress-6.3/behaviors.php +++ b/lib/compat/wordpress-6.3/behaviors.php @@ -10,7 +10,7 @@ function( $settings ) { $theme_data = WP_Theme_JSON_Resolver_Gutenberg::get_theme_data()->get_data(); if ( array_key_exists( 'behaviors', $theme_data ) ) { - $settings['behaviors'] = WP_Theme_JSON_Resolver_Gutenberg::get_theme_data()->get_data()['behaviors']; + $settings['behaviors'] = $theme_data['behaviors']; } // TODO: Make sure to also get the value from the core theme.json file. return $settings; From 3fd9270c9f0a4701c7a87baef24b0231b47f111a Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 18 May 2023 15:42:44 -0500 Subject: [PATCH 034/125] Add `behaviors` as an allowed key to BLOCK_EDITOR_SETTINGS --- .../editor/src/components/provider/use-block-editor-settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/src/components/provider/use-block-editor-settings.js b/packages/editor/src/components/provider/use-block-editor-settings.js index 33a28460c39cdc..8a71fb5deca65f 100644 --- a/packages/editor/src/components/provider/use-block-editor-settings.js +++ b/packages/editor/src/components/provider/use-block-editor-settings.js @@ -75,6 +75,7 @@ const BLOCK_EDITOR_SETTINGS = [ '__unstableIsPreviewMode', '__unstableResolvedAssets', '__unstableIsBlockBasedTheme', + 'behaviors', ]; /** @@ -194,7 +195,6 @@ function useBlockEditorSettings( settings, hasTemplate ) { BLOCK_EDITOR_SETTINGS.includes( key ) ) ), - behaviors: settings.behaviors, mediaUpload: hasUploadPermissions ? mediaUpload : undefined, __experimentalReusableBlocks: reusableBlocks, __experimentalBlockPatterns: blockPatterns, From 5a9748cac61ebe3e23bfa8968ee6d9b7130aaab4 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 18 May 2023 17:04:17 -0500 Subject: [PATCH 035/125] Move the behaviors to top level in the e2e test theme.json file --- test/gutenberg-test-themes/behaviors-false/theme.json | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/test/gutenberg-test-themes/behaviors-false/theme.json b/test/gutenberg-test-themes/behaviors-false/theme.json index 6b06b08098a9df..b448f0972deb72 100644 --- a/test/gutenberg-test-themes/behaviors-false/theme.json +++ b/test/gutenberg-test-themes/behaviors-false/theme.json @@ -1,8 +1,6 @@ { "version": 2, - "settings": { - "behaviors": { - "lightbox": false - } + "behaviors": { + "lightbox": false } } From 9a6b1f211c4cff9df032717b944474ca7556c08e Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 18 May 2023 17:06:03 -0500 Subject: [PATCH 036/125] Rename the `behaviors` setting to `behaviorsUIEnabled` --- lib/class-wp-theme-json-gutenberg.php | 4 +--- lib/theme.json | 4 +--- packages/block-editor/src/hooks/behaviors.js | 4 ++-- test/gutenberg-test-themes/behaviors-disabled/theme.json | 4 +--- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index ef69437b95142b..afd4825b627bb5 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -405,9 +405,7 @@ class WP_Theme_JSON_Gutenberg { 'textDecoration' => null, 'textTransform' => null, ), - 'behaviors' => array( - 'lightbox' => null, - ), + 'behaviorsUIEnabled' => null, ); /** diff --git a/lib/theme.json b/lib/theme.json index c030305314ba0b..2c42f4cef04b3b 100644 --- a/lib/theme.json +++ b/lib/theme.json @@ -455,9 +455,7 @@ } }, "core/image": { - "behaviors": { - "lightbox": true - } + "behaviorsUIEnabled": true } } }, diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index d3ea7938d28846..76d04d20680d4f 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -30,12 +30,12 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { return ; } - // Check the value of `settings.blocks.core/image.behavior.lightbox` in the + // Check the value of `settings.blocks.core/image.behaviorsUIEnabled` in the // theme.json. If false, do not add the behaviors inspector control. const settings = select( blockEditorStore ).getSettings(); if ( ! settings?.__experimentalFeatures?.blocks?.[ props.name ] - ?.behaviors?.lightbox + ?.behaviorsUIEnabled ) { return ; } diff --git a/test/gutenberg-test-themes/behaviors-disabled/theme.json b/test/gutenberg-test-themes/behaviors-disabled/theme.json index a9f920f6dd0abc..c137f7a7223926 100644 --- a/test/gutenberg-test-themes/behaviors-disabled/theme.json +++ b/test/gutenberg-test-themes/behaviors-disabled/theme.json @@ -3,9 +3,7 @@ "settings": { "blocks": { "core/image": { - "behaviors": { - "lightbox": false - } + "behaviorsUIEnabled": false } } } From 1c7f6d5b55a99d460f8b974e0217324a5f7be1c8 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 18 May 2023 17:07:16 -0500 Subject: [PATCH 037/125] Change "None" to "No behaviors" --- packages/block-editor/src/hooks/behaviors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index 76d04d20680d4f..832480c79236cf 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -65,7 +65,7 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { } ) ) .concat( { value: '', - label: __( 'None' ), + label: __( 'No behaviors' ), } ) } onChange={ ( nextValue ) => { // If the user selects something, it means that they want to From 470f74fa2563e4104634e607b0cc858ba6a806ff Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 18 May 2023 17:45:19 -0500 Subject: [PATCH 038/125] Behaviors -> behavior --- packages/block-editor/src/hooks/behaviors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index 832480c79236cf..c74b8259d07c5d 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -65,7 +65,7 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { } ) ) .concat( { value: '', - label: __( 'No behaviors' ), + label: __( 'No behavior' ), } ) } onChange={ ( nextValue ) => { // If the user selects something, it means that they want to From bba7c2dff98b4d3d3e89f262061ab13e57a9c392 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 18 May 2023 17:54:37 -0500 Subject: [PATCH 039/125] Fix redundant ternary --- packages/block-editor/src/hooks/behaviors.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index c74b8259d07c5d..457347461100b6 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -65,14 +65,14 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { } ) ) .concat( { value: '', - label: __( 'No behavior' ), + label: __( 'No behaviors' ), } ) } onChange={ ( nextValue ) => { // If the user selects something, it means that they want to // change the default value (true) so we save it in the attributes. props.setAttributes( { behaviors: { - lightbox: nextValue === '' ? false : true, + lightbox: nextValue === 'lightbox', }, } ); } } From 2cb348c04ab368311ce0991a9abc761a53259158 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 18 May 2023 18:45:12 -0500 Subject: [PATCH 040/125] Improve the JSDoc for behaviors selector --- .../data/data-core-block-editor.md | 13 ++++++++++++- packages/block-editor/src/store/selectors.js | 15 ++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/docs/reference-guides/data/data-core-block-editor.md b/docs/reference-guides/data/data-core-block-editor.md index d8a3e2259c36d9..8b0f24e60fb7bf 100644 --- a/docs/reference-guides/data/data-core-block-editor.md +++ b/docs/reference-guides/data/data-core-block-editor.md @@ -170,7 +170,18 @@ _Returns_ ### getBehaviors -Returns the behaviors. +Returns the behaviors registered with the editor. + +Behaviors are named, reusable pieces of functionality that can be attached to blocks. They are registered with the editor using the `theme.json` file. + +_Usage_ + +```js +const behaviors = select( blockEditorStore ).getBehaviors(); +if ( behaviors?.lightbox ) { + // Do something with the lightbox. +} +``` _Parameters_ diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 1e4fb921275508..487d13db811d84 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -2491,7 +2491,20 @@ export function getSettings( state ) { } /** - * Returns the behaviors. + * Returns the behaviors registered with the editor. + * + * Behaviors are named, reusable pieces of functionality that can be + * attached to blocks. They are registered with the editor using the + * `theme.json` file. + * + * @example + * + * ```js + * const behaviors = select( blockEditorStore ).getBehaviors(); + * if ( behaviors?.lightbox ) { + * // Do something with the lightbox. + * } + *``` * * @param {Object} state Editor state. * From c65bc57f5a9ed1ddd47330e94bc115f236ed1742 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Thu, 18 May 2023 19:27:55 -0500 Subject: [PATCH 041/125] Rename the test themes to make more sense --- test/e2e/specs/editor/various/behaviors.spec.js | 2 +- test/gutenberg-test-themes/behaviors-false/style.css | 4 ++-- .../{behaviors-disabled => behaviors-ui-disabled}/index.php | 0 .../{behaviors-disabled => behaviors-ui-disabled}/style.css | 4 ++-- .../{behaviors-disabled => behaviors-ui-disabled}/theme.json | 0 5 files changed, 5 insertions(+), 5 deletions(-) rename test/gutenberg-test-themes/{behaviors-disabled => behaviors-ui-disabled}/index.php (100%) rename test/gutenberg-test-themes/{behaviors-disabled => behaviors-ui-disabled}/style.css (92%) rename test/gutenberg-test-themes/{behaviors-disabled => behaviors-ui-disabled}/theme.json (100%) diff --git a/test/e2e/specs/editor/various/behaviors.spec.js b/test/e2e/specs/editor/various/behaviors.spec.js index c1babb6b846b72..ab45012a6ebbfb 100644 --- a/test/e2e/specs/editor/various/behaviors.spec.js +++ b/test/e2e/specs/editor/various/behaviors.spec.js @@ -58,7 +58,7 @@ test.describe( 'Testing behaviors functionality', () => { // { "lightbox": true } is the default behavior, so we activate the // `behaviors` theme where it is disabled by default. Change if we change // the default value in the core theme.json file. - await requestUtils.activateTheme( 'behaviors-disabled' ); + await requestUtils.activateTheme( 'behaviors-ui-disabled' ); const media = await createMedia( { admin, requestUtils } ); await editor.insertBlock( { diff --git a/test/gutenberg-test-themes/behaviors-false/style.css b/test/gutenberg-test-themes/behaviors-false/style.css index 972dbacbb5cabd..9d093e7cd73bcc 100644 --- a/test/gutenberg-test-themes/behaviors-false/style.css +++ b/test/gutenberg-test-themes/behaviors-false/style.css @@ -1,5 +1,5 @@ /* -Theme Name: Behaviors +Theme Name: Behaviors (False) Theme URI: https://github.com/wordpress/theme-experiments/ Author: the WordPress team Description: Behaviors test theme. @@ -12,4 +12,4 @@ License URI: http://www.gnu.org/licenses/gpl-2.0.html Text Domain: behaviors Behaviors WordPress Theme, (C) 2023 WordPress.org Behaviors is distributed under the terms of the GNU GPL. -*/ \ No newline at end of file +*/ diff --git a/test/gutenberg-test-themes/behaviors-disabled/index.php b/test/gutenberg-test-themes/behaviors-ui-disabled/index.php similarity index 100% rename from test/gutenberg-test-themes/behaviors-disabled/index.php rename to test/gutenberg-test-themes/behaviors-ui-disabled/index.php diff --git a/test/gutenberg-test-themes/behaviors-disabled/style.css b/test/gutenberg-test-themes/behaviors-ui-disabled/style.css similarity index 92% rename from test/gutenberg-test-themes/behaviors-disabled/style.css rename to test/gutenberg-test-themes/behaviors-ui-disabled/style.css index 972dbacbb5cabd..2cf6387b490e91 100644 --- a/test/gutenberg-test-themes/behaviors-disabled/style.css +++ b/test/gutenberg-test-themes/behaviors-ui-disabled/style.css @@ -1,5 +1,5 @@ /* -Theme Name: Behaviors +Theme Name: Behaviors UI Disabled Theme URI: https://github.com/wordpress/theme-experiments/ Author: the WordPress team Description: Behaviors test theme. @@ -12,4 +12,4 @@ License URI: http://www.gnu.org/licenses/gpl-2.0.html Text Domain: behaviors Behaviors WordPress Theme, (C) 2023 WordPress.org Behaviors is distributed under the terms of the GNU GPL. -*/ \ No newline at end of file +*/ diff --git a/test/gutenberg-test-themes/behaviors-disabled/theme.json b/test/gutenberg-test-themes/behaviors-ui-disabled/theme.json similarity index 100% rename from test/gutenberg-test-themes/behaviors-disabled/theme.json rename to test/gutenberg-test-themes/behaviors-ui-disabled/theme.json From 1c655f7975f7d48ac4dbc9618e23d479cb432134 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 22 May 2023 14:51:13 -0500 Subject: [PATCH 042/125] Remove definition of `behaviors` attribute in core/image --- docs/reference-guides/core-blocks.md | 2 +- packages/block-library/src/image/block.json | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index df852bf97b6664..423676e2afe320 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -321,7 +321,7 @@ Insert an image to make a visual statement. ([Source](https://github.com/WordPre - **Name:** core/image - **Category:** media - **Supports:** anchor, color (~~background~~, ~~text~~), filter (duotone) -- **Attributes:** align, alt, behaviors, caption, height, href, id, linkClass, linkDestination, linkTarget, rel, sizeSlug, title, url, width +- **Attributes:** align, alt, caption, height, href, id, linkClass, linkDestination, linkTarget, rel, sizeSlug, title, url, width ## Latest Comments diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index 791e09f73c8009..92931455c1144c 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -80,9 +80,6 @@ "source": "attribute", "selector": "figure > a", "attribute": "target" - }, - "behaviors": { - "type": "object" } }, "supports": { From 697c04fde2a1710abce8a72cf9bb3fd99d0849f6 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 22 May 2023 16:49:31 -0500 Subject: [PATCH 043/125] Change default value for `behaviors.lightbox` to false and update e2e tests accordingly --- lib/theme.json | 2 +- .../specs/editor/various/behaviors.spec.js | 23 +++++++++++++------ .../index.php | 0 .../style.css | 3 ++- .../theme.json | 2 +- 5 files changed, 20 insertions(+), 10 deletions(-) rename test/gutenberg-test-themes/{behaviors-false => behaviors-enabled}/index.php (100%) rename test/gutenberg-test-themes/{behaviors-false => behaviors-enabled}/style.css (93%) rename test/gutenberg-test-themes/{behaviors-false => behaviors-enabled}/theme.json (65%) diff --git a/lib/theme.json b/lib/theme.json index 2c42f4cef04b3b..1672382f6d4d96 100644 --- a/lib/theme.json +++ b/lib/theme.json @@ -1,7 +1,7 @@ { "version": 2, "behaviors": { - "lightbox": true + "lightbox": false }, "settings": { "appearanceTools": false, diff --git a/test/e2e/specs/editor/various/behaviors.spec.js b/test/e2e/specs/editor/various/behaviors.spec.js index ab45012a6ebbfb..566acd3d69548d 100644 --- a/test/e2e/specs/editor/various/behaviors.spec.js +++ b/test/e2e/specs/editor/various/behaviors.spec.js @@ -27,7 +27,7 @@ test.describe( 'Testing behaviors functionality', () => { await requestUtils.deleteAllMedia(); } ); - test( 'Lightbox behavior should be selected by default as defined in the core theme.json', async ( { + test( 'Lightbox behavior should be false by default as defined in the core theme.json', async ( { admin, editor, requestUtils, @@ -91,14 +91,17 @@ test.describe( 'Testing behaviors functionality', () => { alt: filename, id: media.id, url: media.source_url, - // Explicitly set the value for behaviors to false. - behaviors: { lightbox: false }, + // Explicitly set the value for behaviors to true. + behaviors: { lightbox: true }, }, } ); await page.getByRole( 'button', { name: 'Advanced' } ).click(); await expect( page.getByLabel( 'Behavior' ) ).toHaveCount( 1 ); await expect( page.getByLabel( 'Behavior' ) ).toHaveValue( '' ); + + // Here we should also check that the block renders on the frontend with the + // lightbox even though the theme.json has it set to false. } ); test( 'You can set the default value for the behaviors in the theme.json', async ( { @@ -107,8 +110,8 @@ test.describe( 'Testing behaviors functionality', () => { requestUtils, page, } ) => { - // In this theme, the default value for settings.behaviors.lightbox is `false`. - await requestUtils.activateTheme( 'behaviors-false' ); + // In this theme, the default value for settings.behaviors.lightbox is `true`. + await requestUtils.activateTheme( 'behaviors-enabled' ); const media = await createMedia( { admin, requestUtils } ); await editor.insertBlock( { @@ -121,10 +124,16 @@ test.describe( 'Testing behaviors functionality', () => { } ); await page.getByRole( 'button', { name: 'Advanced' } ).click(); + + // The behaviors dropdown should be present and the value should be set to + // `lightbox`. await expect( page.getByLabel( 'Behavior' ) ).toHaveCount( 1 ); + await expect( page.getByLabel( 'Behavior' ) ).toHaveValue( 'lightbox' ); - // The default value for behaviors in `theme.json` is `false`, so the - // dropdown should be present, but the value should be `""` (None). + // Check that we can change the value of the behaviors dropdown to `No behavior`. + await page + .getByLabel( 'Behavior' ) + .selectOption( { label: 'No behaviors' } ); await expect( page.getByLabel( 'Behavior' ) ).toHaveValue( '' ); } ); } ); diff --git a/test/gutenberg-test-themes/behaviors-false/index.php b/test/gutenberg-test-themes/behaviors-enabled/index.php similarity index 100% rename from test/gutenberg-test-themes/behaviors-false/index.php rename to test/gutenberg-test-themes/behaviors-enabled/index.php diff --git a/test/gutenberg-test-themes/behaviors-false/style.css b/test/gutenberg-test-themes/behaviors-enabled/style.css similarity index 93% rename from test/gutenberg-test-themes/behaviors-false/style.css rename to test/gutenberg-test-themes/behaviors-enabled/style.css index 9d093e7cd73bcc..c8ae349f915bef 100644 --- a/test/gutenberg-test-themes/behaviors-false/style.css +++ b/test/gutenberg-test-themes/behaviors-enabled/style.css @@ -1,5 +1,6 @@ /* -Theme Name: Behaviors (False) +Theme Name: Behaviors Enabled + Theme URI: https://github.com/wordpress/theme-experiments/ Author: the WordPress team Description: Behaviors test theme. diff --git a/test/gutenberg-test-themes/behaviors-false/theme.json b/test/gutenberg-test-themes/behaviors-enabled/theme.json similarity index 65% rename from test/gutenberg-test-themes/behaviors-false/theme.json rename to test/gutenberg-test-themes/behaviors-enabled/theme.json index b448f0972deb72..436c60e1dc441b 100644 --- a/test/gutenberg-test-themes/behaviors-false/theme.json +++ b/test/gutenberg-test-themes/behaviors-enabled/theme.json @@ -1,6 +1,6 @@ { "version": 2, "behaviors": { - "lightbox": false + "lightbox": true } } From d4fd9d9b8efb87784259071e93d605df1ddd627b Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 22 May 2023 19:02:22 -0500 Subject: [PATCH 044/125] Change the way we get the data from `theme.json` and adjust e2e --- docs/reference-guides/core-blocks.md | 2 +- lib/compat/wordpress-6.3/behaviors.php | 2 +- packages/block-editor/src/hooks/behaviors.js | 9 ++-- packages/block-library/src/image/block.json | 3 ++ .../specs/editor/various/behaviors.spec.js | 48 ++++++++++++++----- 5 files changed, 45 insertions(+), 19 deletions(-) diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index 423676e2afe320..df852bf97b6664 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -321,7 +321,7 @@ Insert an image to make a visual statement. ([Source](https://github.com/WordPre - **Name:** core/image - **Category:** media - **Supports:** anchor, color (~~background~~, ~~text~~), filter (duotone) -- **Attributes:** align, alt, caption, height, href, id, linkClass, linkDestination, linkTarget, rel, sizeSlug, title, url, width +- **Attributes:** align, alt, behaviors, caption, height, href, id, linkClass, linkDestination, linkTarget, rel, sizeSlug, title, url, width ## Latest Comments diff --git a/lib/compat/wordpress-6.3/behaviors.php b/lib/compat/wordpress-6.3/behaviors.php index c2c51e9a92a778..ba92a4d9bcb764 100644 --- a/lib/compat/wordpress-6.3/behaviors.php +++ b/lib/compat/wordpress-6.3/behaviors.php @@ -8,7 +8,7 @@ add_filter( 'block_editor_settings_all', function( $settings ) { - $theme_data = WP_Theme_JSON_Resolver_Gutenberg::get_theme_data()->get_data(); + $theme_data = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_data(); if ( array_key_exists( 'behaviors', $theme_data ) ) { $settings['behaviors'] = $theme_data['behaviors']; } diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index 457347461100b6..b38e11f8d863ee 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -58,10 +58,11 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { label={ __( 'Behaviors' ) } // At the moment we are only supporting one behavior (lightbox) value={ behaviors?.lightbox ? 'LIGHTBOX' : '' } - options={ Object.keys( behaviors ) - .map( ( behavior ) => ( { - value: behavior, - label: behavior.toUpperCase(), + options={ Object.entries( behaviors ) + .filter( ( [ , behaviorValue ] ) => behaviorValue ) // Filter out falsey values + .map( ( [ behaviorName ] ) => ( { + value: behaviorName, + label: behaviorName.toUpperCase(), } ) ) .concat( { value: '', diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index 92931455c1144c..791e09f73c8009 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -80,6 +80,9 @@ "source": "attribute", "selector": "figure > a", "attribute": "target" + }, + "behaviors": { + "type": "object" } }, "supports": { diff --git a/test/e2e/specs/editor/various/behaviors.spec.js b/test/e2e/specs/editor/various/behaviors.spec.js index 566acd3d69548d..030a31b1b3f669 100644 --- a/test/e2e/specs/editor/various/behaviors.spec.js +++ b/test/e2e/specs/editor/various/behaviors.spec.js @@ -27,7 +27,7 @@ test.describe( 'Testing behaviors functionality', () => { await requestUtils.deleteAllMedia(); } ); - test( 'Lightbox behavior should be false by default as defined in the core theme.json', async ( { + test( 'By default, thel Lightbox behavior should be false as defined in the core theme.json', async ( { admin, editor, requestUtils, @@ -45,8 +45,15 @@ test.describe( 'Testing behaviors functionality', () => { } ); await page.getByRole( 'button', { name: 'Advanced' } ).click(); - await expect( page.getByLabel( 'Behavior' ) ).toHaveCount( 1 ); - await expect( page.getByLabel( 'Behavior' ) ).toHaveValue( '' ); + const select = page.getByLabel( 'Behavior' ); + + // By default, no behaviors should be available. + await expect( select ).toHaveCount( 1 ); + await expect( select ).toHaveValue( '' ); + + // By default, you cannot select any behaviors. + const options = select.locator( 'option' ); + await expect( options ).toHaveCount( 1 ); } ); test( 'Behaviors UI can be disabled in the `theme.json`', async ( { @@ -97,8 +104,20 @@ test.describe( 'Testing behaviors functionality', () => { } ); await page.getByRole( 'button', { name: 'Advanced' } ).click(); - await expect( page.getByLabel( 'Behavior' ) ).toHaveCount( 1 ); - await expect( page.getByLabel( 'Behavior' ) ).toHaveValue( '' ); + const select = page.getByLabel( 'Behavior' ); + + // The lightbox should be selected because the value from the block's + // attributes takes precedence over the theme's value. + await expect( select ).toHaveCount( 1 ); + await expect( select ).toHaveValue( 'lightbox' ); + + // There should be 2 options available: `No behaviors` and `Lightbox`. + const options = select.locator( 'option' ); + await expect( options ).toHaveCount( 2 ); + + // We can change the value of the behaviors dropdown to `No behavior`. + await select.selectOption( { label: 'No behaviors' } ); + await expect( select ).toHaveValue( '' ); // Here we should also check that the block renders on the frontend with the // lightbox even though the theme.json has it set to false. @@ -124,16 +143,19 @@ test.describe( 'Testing behaviors functionality', () => { } ); await page.getByRole( 'button', { name: 'Advanced' } ).click(); + const select = page.getByLabel( 'Behavior' ); // The behaviors dropdown should be present and the value should be set to // `lightbox`. - await expect( page.getByLabel( 'Behavior' ) ).toHaveCount( 1 ); - await expect( page.getByLabel( 'Behavior' ) ).toHaveValue( 'lightbox' ); - - // Check that we can change the value of the behaviors dropdown to `No behavior`. - await page - .getByLabel( 'Behavior' ) - .selectOption( { label: 'No behaviors' } ); - await expect( page.getByLabel( 'Behavior' ) ).toHaveValue( '' ); + await expect( select ).toHaveCount( 1 ); + await expect( select ).toHaveValue( 'lightbox' ); + + // There should be 2 options available: `No behaviors` and `Lightbox`. + const options = select.locator( 'option' ); + await expect( options ).toHaveCount( 2 ); + + // We can change the value of the behaviors dropdown to `No behavior`. + await select.selectOption( { label: 'No behaviors' } ); + await expect( select ).toHaveValue( '' ); } ); } ); From a57d634d5a4f32ef15539b10bcc3b09fdbde26c6 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 22 May 2023 19:39:10 -0500 Subject: [PATCH 045/125] Capitalize behaviors' labels --- packages/block-editor/src/hooks/behaviors.js | 9 ++++++--- test/e2e/specs/editor/various/behaviors.spec.js | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index b38e11f8d863ee..7a2896348cfa42 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -56,13 +56,16 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { behaviorValue ) // Filter out falsey values .map( ( [ behaviorName ] ) => ( { value: behaviorName, - label: behaviorName.toUpperCase(), + label: + // Capitalize the first letter of the behavior name. + behaviorName[ 0 ].toUpperCase() + + behaviorName.slice( 1 ).toLowerCase(), } ) ) .concat( { value: '', diff --git a/test/e2e/specs/editor/various/behaviors.spec.js b/test/e2e/specs/editor/various/behaviors.spec.js index 030a31b1b3f669..25290954bc040f 100644 --- a/test/e2e/specs/editor/various/behaviors.spec.js +++ b/test/e2e/specs/editor/various/behaviors.spec.js @@ -115,7 +115,7 @@ test.describe( 'Testing behaviors functionality', () => { const options = select.locator( 'option' ); await expect( options ).toHaveCount( 2 ); - // We can change the value of the behaviors dropdown to `No behavior`. + // We can change the value of the behaviors dropdown to `No behaviors`. await select.selectOption( { label: 'No behaviors' } ); await expect( select ).toHaveValue( '' ); @@ -154,7 +154,7 @@ test.describe( 'Testing behaviors functionality', () => { const options = select.locator( 'option' ); await expect( options ).toHaveCount( 2 ); - // We can change the value of the behaviors dropdown to `No behavior`. + // We can change the value of the behaviors dropdown to `No behaviors`. await select.selectOption( { label: 'No behaviors' } ); await expect( select ).toHaveValue( '' ); } ); From 234a8b666e8867382db402fdb419e5df5cde1a6b Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 22 May 2023 20:18:18 -0500 Subject: [PATCH 046/125] Move PHP code adding `theme.json` behaviors to `block-editor-settings` --- lib/block-editor-settings.php | 8 +++++++- lib/compat/wordpress-6.3/behaviors.php | 19 ------------------- 2 files changed, 7 insertions(+), 20 deletions(-) delete mode 100644 lib/compat/wordpress-6.3/behaviors.php diff --git a/lib/block-editor-settings.php b/lib/block-editor-settings.php index 53668e114e04cb..eff4c80d67359c 100644 --- a/lib/block-editor-settings.php +++ b/lib/block-editor-settings.php @@ -6,7 +6,7 @@ */ /** - * Replaces core 'styles' and '__experimentalFeatures' block editor settings from + * Replaces core 'styles', '__experimentalFeatures' and 'behaviors' block editor settings from * wordpress-develop/block-editor.php with the Gutenberg versions. Much of the * code is copied from get_block_editor_settings() in that file. * @@ -146,6 +146,12 @@ function gutenberg_get_block_editor_settings( $settings ) { ); } + // Add theme.json behaviors. + $theme_data = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_data(); + if ( array_key_exists( 'behaviors', $theme_data ) ) { + $settings['behaviors'] = $theme_data['behaviors']; + } + return $settings; } add_filter( 'block_editor_settings_all', 'gutenberg_get_block_editor_settings', 0 ); diff --git a/lib/compat/wordpress-6.3/behaviors.php b/lib/compat/wordpress-6.3/behaviors.php deleted file mode 100644 index ba92a4d9bcb764..00000000000000 --- a/lib/compat/wordpress-6.3/behaviors.php +++ /dev/null @@ -1,19 +0,0 @@ -get_data(); - if ( array_key_exists( 'behaviors', $theme_data ) ) { - $settings['behaviors'] = $theme_data['behaviors']; - } - // TODO: Make sure to also get the value from the core theme.json file. - return $settings; - }, - PHP_INT_MAX -); From 4bef633dd52856247e7b05229c62191dc85a09f9 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 22 May 2023 20:19:31 -0500 Subject: [PATCH 047/125] Update comment --- lib/block-editor-settings.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/block-editor-settings.php b/lib/block-editor-settings.php index eff4c80d67359c..4456f2fddd7682 100644 --- a/lib/block-editor-settings.php +++ b/lib/block-editor-settings.php @@ -146,7 +146,8 @@ function gutenberg_get_block_editor_settings( $settings ) { ); } - // Add theme.json behaviors. + // Add the behaviors from the theme.json to the block editor settings. + // Behaviors are specific, named pieces of interactivity that can be applied to blocks. $theme_data = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_data(); if ( array_key_exists( 'behaviors', $theme_data ) ) { $settings['behaviors'] = $theme_data['behaviors']; From 7aa72317e03155e1cd8ca75e62f7e592eec2f843 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 22 May 2023 20:22:35 -0500 Subject: [PATCH 048/125] Remove the behaviors require from load.php --- lib/load.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/load.php b/lib/load.php index c99e0ec9e98b79..8edd2dd321e60e 100644 --- a/lib/load.php +++ b/lib/load.php @@ -93,7 +93,6 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/compat/wordpress-6.3/html-api/class-gutenberg-html-tag-processor-6-3.php'; require __DIR__ . '/compat/wordpress-6.3/script-loader.php'; require __DIR__ . '/compat/wordpress-6.3/blocks.php'; -require __DIR__ . '/compat/wordpress-6.3/behaviors.php'; // Experimental features. remove_action( 'plugins_loaded', '_wp_theme_json_webfonts_handler' ); // Turns off WP 6.0's stopgap handler for Webfonts API. From 1d923ab2a8a919fa9010e397f05666f5a23ca99b Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 22 May 2023 20:41:37 -0500 Subject: [PATCH 049/125] Revert "Update comment" This reverts commit fc812bc6c04e8b3c5c7fe3450c1e39d1dd6f6f3b. --- lib/block-editor-settings.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/block-editor-settings.php b/lib/block-editor-settings.php index 4456f2fddd7682..eff4c80d67359c 100644 --- a/lib/block-editor-settings.php +++ b/lib/block-editor-settings.php @@ -146,8 +146,7 @@ function gutenberg_get_block_editor_settings( $settings ) { ); } - // Add the behaviors from the theme.json to the block editor settings. - // Behaviors are specific, named pieces of interactivity that can be applied to blocks. + // Add theme.json behaviors. $theme_data = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_data(); if ( array_key_exists( 'behaviors', $theme_data ) ) { $settings['behaviors'] = $theme_data['behaviors']; From aee908a3a5e2778a96767e3879173b26b6b5be23 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Mon, 22 May 2023 20:41:44 -0500 Subject: [PATCH 050/125] Revert "Move PHP code adding `theme.json` behaviors to `block-editor-settings`" This reverts commit e8d16c8bb4977d1e27b758a067066a78fc21f794. --- lib/block-editor-settings.php | 6 ------ lib/compat/wordpress-6.3/behaviors.php | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 lib/compat/wordpress-6.3/behaviors.php diff --git a/lib/block-editor-settings.php b/lib/block-editor-settings.php index eff4c80d67359c..fe8d78ccc29130 100644 --- a/lib/block-editor-settings.php +++ b/lib/block-editor-settings.php @@ -146,12 +146,6 @@ function gutenberg_get_block_editor_settings( $settings ) { ); } - // Add theme.json behaviors. - $theme_data = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_data(); - if ( array_key_exists( 'behaviors', $theme_data ) ) { - $settings['behaviors'] = $theme_data['behaviors']; - } - return $settings; } add_filter( 'block_editor_settings_all', 'gutenberg_get_block_editor_settings', 0 ); diff --git a/lib/compat/wordpress-6.3/behaviors.php b/lib/compat/wordpress-6.3/behaviors.php new file mode 100644 index 00000000000000..ba92a4d9bcb764 --- /dev/null +++ b/lib/compat/wordpress-6.3/behaviors.php @@ -0,0 +1,19 @@ +get_data(); + if ( array_key_exists( 'behaviors', $theme_data ) ) { + $settings['behaviors'] = $theme_data['behaviors']; + } + // TODO: Make sure to also get the value from the core theme.json file. + return $settings; + }, + PHP_INT_MAX +); From 33cb62d65483f80433fdc962407b99d61a1c439c Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 23 May 2023 11:33:20 -0500 Subject: [PATCH 051/125] Remove the comment that was added previously --- lib/block-editor-settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/block-editor-settings.php b/lib/block-editor-settings.php index fe8d78ccc29130..53668e114e04cb 100644 --- a/lib/block-editor-settings.php +++ b/lib/block-editor-settings.php @@ -6,7 +6,7 @@ */ /** - * Replaces core 'styles', '__experimentalFeatures' and 'behaviors' block editor settings from + * Replaces core 'styles' and '__experimentalFeatures' block editor settings from * wordpress-develop/block-editor.php with the Gutenberg versions. Much of the * code is copied from get_block_editor_settings() in that file. * From 55e37a3ae85b0b5e4e3d0ca199cb9a4ba0ead0ff Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 23 May 2023 11:33:42 -0500 Subject: [PATCH 052/125] Update comments in `behaviors.php` --- lib/compat/wordpress-6.3/behaviors.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/compat/wordpress-6.3/behaviors.php b/lib/compat/wordpress-6.3/behaviors.php index ba92a4d9bcb764..62e7be7a252d49 100644 --- a/lib/compat/wordpress-6.3/behaviors.php +++ b/lib/compat/wordpress-6.3/behaviors.php @@ -2,6 +2,8 @@ /** * Behaviors. * + * Updates the block editor settings with the theme's behaviors. + * * @package gutenberg */ @@ -12,7 +14,6 @@ function( $settings ) { if ( array_key_exists( 'behaviors', $theme_data ) ) { $settings['behaviors'] = $theme_data['behaviors']; } - // TODO: Make sure to also get the value from the core theme.json file. return $settings; }, PHP_INT_MAX From d4d657ba98d7b9c676522879a67f2c07527fdcf0 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 23 May 2023 12:18:09 -0500 Subject: [PATCH 053/125] Add back the require_once in load.php --- lib/load.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/load.php b/lib/load.php index 8edd2dd321e60e..f66fe7f474b961 100644 --- a/lib/load.php +++ b/lib/load.php @@ -51,6 +51,7 @@ function gutenberg_is_experiment_enabled( $name ) { require_once __DIR__ . '/compat/wordpress-6.3/theme-previews.php'; require_once __DIR__ . '/compat/wordpress-6.3/navigation-block-preloading.php'; require_once __DIR__ . '/compat/wordpress-6.3/link-template.php'; + require_once __DIR__ . '/compat/wordpress-6.3/behaviors.php'; // Experimental. if ( ! class_exists( 'WP_Rest_Customizer_Nonces' ) ) { From 8d6b0d0c61f0787bde345644fbac6e58480f5832 Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 23 May 2023 15:18:35 -0500 Subject: [PATCH 054/125] Use `settings.blocks.core/image.behaviors.lightbox` --- lib/class-wp-theme-json-gutenberg.php | 2 +- lib/theme.json | 4 +++- packages/block-editor/src/hooks/behaviors.js | 16 +++++++++------- test/e2e/specs/editor/various/behaviors.spec.js | 12 ++++++------ .../behaviors-ui-disabled/theme.json | 4 +++- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index afd4825b627bb5..c27572e735ee1e 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -405,7 +405,7 @@ class WP_Theme_JSON_Gutenberg { 'textDecoration' => null, 'textTransform' => null, ), - 'behaviorsUIEnabled' => null, + 'behaviors' => null, ); /** diff --git a/lib/theme.json b/lib/theme.json index 1672382f6d4d96..6b3e63d20dd026 100644 --- a/lib/theme.json +++ b/lib/theme.json @@ -455,7 +455,9 @@ } }, "core/image": { - "behaviorsUIEnabled": true + "behaviors": { + "lightbox": true + } } } }, diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index 7a2896348cfa42..c072eb8383411a 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -30,12 +30,14 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { return ; } - // Check the value of `settings.blocks.core/image.behaviorsUIEnabled` in the - // theme.json. If false, do not add the behaviors inspector control. - const settings = select( blockEditorStore ).getSettings(); + const settings = + select( blockEditorStore ).getSettings()?.__experimentalFeatures + ?.blocks?.[ props.name ]?.behaviors; + if ( - ! settings?.__experimentalFeatures?.blocks?.[ props.name ] - ?.behaviorsUIEnabled + ! settings || + // If every behavior is disabled, do not show the behaviors inspector control. + Object.entries( settings ).every( ( [ , value ] ) => ! value ) ) { return ; } @@ -58,8 +60,8 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { label={ __( 'Behaviors' ) } // At the moment we are only supporting one behavior (Lightbox) value={ behaviors?.lightbox ? 'lightbox' : '' } - options={ Object.entries( behaviors ) - .filter( ( [ , behaviorValue ] ) => behaviorValue ) // Filter out falsey values + options={ Object.entries( settings ) + .filter( ( [ , behaviorValue ] ) => behaviorValue ) // Filter out behaviors that are disabled. .map( ( [ behaviorName ] ) => ( { value: behaviorName, label: diff --git a/test/e2e/specs/editor/various/behaviors.spec.js b/test/e2e/specs/editor/various/behaviors.spec.js index 25290954bc040f..b5d80f8703ab90 100644 --- a/test/e2e/specs/editor/various/behaviors.spec.js +++ b/test/e2e/specs/editor/various/behaviors.spec.js @@ -27,7 +27,7 @@ test.describe( 'Testing behaviors functionality', () => { await requestUtils.deleteAllMedia(); } ); - test( 'By default, thel Lightbox behavior should be false as defined in the core theme.json', async ( { + test( '`No Behaviors` should be the default as defined in the core theme.json', async ( { admin, editor, requestUtils, @@ -47,13 +47,13 @@ test.describe( 'Testing behaviors functionality', () => { await page.getByRole( 'button', { name: 'Advanced' } ).click(); const select = page.getByLabel( 'Behavior' ); - // By default, no behaviors should be available. + // By default, no behaviors should be selected. await expect( select ).toHaveCount( 1 ); await expect( select ).toHaveValue( '' ); - // By default, you cannot select any behaviors. + // By default, you should be able to select the Lightbox behavior. const options = select.locator( 'option' ); - await expect( options ).toHaveCount( 1 ); + await expect( options ).toHaveCount( 2 ); } ); test( 'Behaviors UI can be disabled in the `theme.json`', async ( { @@ -62,8 +62,8 @@ test.describe( 'Testing behaviors functionality', () => { requestUtils, page, } ) => { - // { "lightbox": true } is the default behavior, so we activate the - // `behaviors` theme where it is disabled by default. Change if we change + // { "lightbox": true } is the default behavior setting, so we activate the + // `behaviors-ui-disabled` theme where it is disabled by default. Change if we change // the default value in the core theme.json file. await requestUtils.activateTheme( 'behaviors-ui-disabled' ); const media = await createMedia( { admin, requestUtils } ); diff --git a/test/gutenberg-test-themes/behaviors-ui-disabled/theme.json b/test/gutenberg-test-themes/behaviors-ui-disabled/theme.json index c137f7a7223926..a9f920f6dd0abc 100644 --- a/test/gutenberg-test-themes/behaviors-ui-disabled/theme.json +++ b/test/gutenberg-test-themes/behaviors-ui-disabled/theme.json @@ -3,7 +3,9 @@ "settings": { "blocks": { "core/image": { - "behaviorsUIEnabled": false + "behaviors": { + "lightbox": false + } } } } From 76b2a752994b2d3b3173ddb5967e484c8689214a Mon Sep 17 00:00:00 2001 From: Michal Czaplinski Date: Tue, 23 May 2023 18:12:12 -0500 Subject: [PATCH 055/125] Use `behaviors.blocks.core/image.lightbox` --- lib/theme.json | 6 +++++- package-lock.json | 21 ++++++++++++++++--- packages/block-editor/package.json | 1 + packages/block-editor/src/hooks/behaviors.js | 15 ++++++++----- .../specs/editor/various/behaviors.spec.js | 2 +- .../behaviors-enabled/theme.json | 6 +++++- 6 files changed, 40 insertions(+), 11 deletions(-) diff --git a/lib/theme.json b/lib/theme.json index 6b3e63d20dd026..6955d8f2f3016e 100644 --- a/lib/theme.json +++ b/lib/theme.json @@ -1,7 +1,11 @@ { "version": 2, "behaviors": { - "lightbox": false + "blocks": { + "core/image": { + "lightbox": false + } + } }, "settings": { "appearanceTools": false, diff --git a/package-lock.json b/package-lock.json index 5833c451c403be..2f674821f32951 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17195,6 +17195,7 @@ "change-case": "^4.1.2", "classnames": "^2.3.1", "colord": "^2.7.0", + "deepmerge": "^4.3.0", "diff": "^4.0.2", "dom-scroll-into-view": "^1.2.1", "fast-deep-equal": "^3.1.3", @@ -17205,6 +17206,13 @@ "rememo": "^4.0.2", "remove-accents": "^0.4.2", "traverse": "^0.6.6" + }, + "dependencies": { + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==" + } } }, "@wordpress/block-library": { @@ -17298,6 +17306,13 @@ "showdown": "^1.9.1", "simple-html-tokenizer": "^0.5.7", "uuid": "^8.3.0" + }, + "dependencies": { + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==" + } } }, "@wordpress/browserslist-config": { @@ -29227,7 +29242,7 @@ "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true }, "code-point-at": { @@ -30804,7 +30819,7 @@ "css.escape": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=", "dev": true }, "cssesc": { @@ -41365,7 +41380,7 @@ "lz-string": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz", - "integrity": "sha512-0ckx7ZHRPqb0oUm8zNr+90mtf9DQB60H1wMCjBtfi62Kl3a7JbHob6gA2bC+xRvZoOL+1hzUK8jeuEIQE8svEQ==", + "integrity": "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY=", "dev": true }, "macos-release": { diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index efd980cba06c66..9e934a68662c2e 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -65,6 +65,7 @@ "change-case": "^4.1.2", "classnames": "^2.3.1", "colord": "^2.7.0", + "deepmerge": "^4.3.0", "diff": "^4.0.2", "dom-scroll-into-view": "^1.2.1", "fast-deep-equal": "^3.1.3", diff --git a/packages/block-editor/src/hooks/behaviors.js b/packages/block-editor/src/hooks/behaviors.js index c072eb8383411a..e47e47b7b610ae 100644 --- a/packages/block-editor/src/hooks/behaviors.js +++ b/packages/block-editor/src/hooks/behaviors.js @@ -13,6 +13,11 @@ import { select } from '@wordpress/data'; import { InspectorControls } from '../components'; import { store as blockEditorStore } from '../store'; +/** + * External dependencies + */ +import merge from 'deepmerge'; + /** * Override the default edit UI to include a new block inspector control for * assigning behaviors to blocks if behaviors are enabled in the theme.json. @@ -44,12 +49,12 @@ export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => { const { behaviors: blockBehaviors } = props.attributes; - // Get the theme behaviors from the theme.json. - const themeBehaviors = select( blockEditorStore ).getBehaviors(); + // Get the theme behaviors for the block from the theme.json. + const themeBehaviors = + select( blockEditorStore ).getBehaviors()?.blocks?.[ props.name ]; - // By default, use the block behaviors. - // If the theme has behaviors, but the block does not, use the theme behaviors. - const behaviors = blockBehaviors || themeBehaviors || {}; + // Block behaviors take precedence over theme behaviors. + const behaviors = merge( themeBehaviors, blockBehaviors || {} ); return ( <> diff --git a/test/e2e/specs/editor/various/behaviors.spec.js b/test/e2e/specs/editor/various/behaviors.spec.js index b5d80f8703ab90..b219ebfb809c13 100644 --- a/test/e2e/specs/editor/various/behaviors.spec.js +++ b/test/e2e/specs/editor/various/behaviors.spec.js @@ -129,7 +129,7 @@ test.describe( 'Testing behaviors functionality', () => { requestUtils, page, } ) => { - // In this theme, the default value for settings.behaviors.lightbox is `true`. + // In this theme, the default value for settings.behaviors.blocks.core/image.lightbox is `true`. await requestUtils.activateTheme( 'behaviors-enabled' ); const media = await createMedia( { admin, requestUtils } ); diff --git a/test/gutenberg-test-themes/behaviors-enabled/theme.json b/test/gutenberg-test-themes/behaviors-enabled/theme.json index 436c60e1dc441b..f49129622d9f6d 100644 --- a/test/gutenberg-test-themes/behaviors-enabled/theme.json +++ b/test/gutenberg-test-themes/behaviors-enabled/theme.json @@ -1,6 +1,10 @@ { "version": 2, "behaviors": { - "lightbox": true + "blocks": { + "core/image": { + "lightbox": true + } + } } } From 70e51cd684d186668eea9ff9c3786f38209ffcd5 Mon Sep 17 00:00:00 2001 From: Carlos Bravo Date: Wed, 24 May 2023 12:44:06 +0200 Subject: [PATCH 056/125] Remove experimental setting for interactivity API --- lib/experiments-page.php | 12 ------------ lib/load.php | 6 ++---- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/lib/experiments-page.php b/lib/experiments-page.php index 9e31815f3f50ff..725aa1efcf0e28 100644 --- a/lib/experiments-page.php +++ b/lib/experiments-page.php @@ -101,18 +101,6 @@ function gutenberg_initialize_experiments_settings() { ) ); - add_settings_field( - 'gutenberg-interactivity-api-core-blocks', - __( 'Core blocks', 'gutenberg' ), - 'gutenberg_display_experiment_field', - 'gutenberg-experiments', - 'gutenberg_experiments_section', - array( - 'label' => __( 'Test the core blocks using the Interactivity API', 'gutenberg' ), - 'id' => 'gutenberg-interactivity-api-core-blocks', - ) - ); - add_settings_field( 'gutenberg-pattern-enhancements', __( 'Pattern enhancements', 'gutenberg' ), diff --git a/lib/load.php b/lib/load.php index f66fe7f474b961..1cfb13c54f2146 100644 --- a/lib/load.php +++ b/lib/load.php @@ -104,10 +104,8 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/experimental/kses.php'; require __DIR__ . '/experimental/l10n.php'; require __DIR__ . '/experimental/navigation-fallback.php'; -if ( gutenberg_is_experiment_enabled( 'gutenberg-interactivity-api-core-blocks' ) ) { - require __DIR__ . '/experimental/interactivity-api/script-loader.php'; - require __DIR__ . '/experimental/interactivity-api/blocks.php'; -} +require __DIR__ . '/experimental/interactivity-api/script-loader.php'; +require __DIR__ . '/experimental/interactivity-api/blocks.php'; // Fonts API. if ( ! class_exists( 'WP_Fonts' ) ) { From e69833b7fff89b6353e74ca08113d12a2b0e9b11 Mon Sep 17 00:00:00 2001 From: Artemio Morales Date: Mon, 3 Apr 2023 16:38:15 +0200 Subject: [PATCH 057/125] Add lightbox to image block First pass at adding lightbox. Note: Added custom implementation of Preact Portal because the children[0] declaration in the render method was erroneous and undefined, preventing it from working as expected. --- package.json | 2 + packages/block-library/package.json | 3 - packages/block-library/src/image/block.json | 4 +- packages/block-library/src/image/index.php | 9 +- .../src/image/runtime/constants.js | 3 + .../src/image/runtime/directives.js | 256 ++++++++++++++++++ .../block-library/src/image/runtime/hooks.js | 85 ++++++ .../block-library/src/image/runtime/index.js | 2 + .../block-library/src/image/runtime/init.js | 11 + .../block-library/src/image/runtime/portal.js | 73 +++++ .../block-library/src/image/runtime/router.js | 171 ++++++++++++ .../block-library/src/image/runtime/store.js | 46 ++++ .../block-library/src/image/runtime/utils.js | 20 ++ .../block-library/src/image/runtime/vdom.js | 71 +++++ packages/block-library/src/image/style.scss | 20 ++ packages/block-library/src/image/view.js | 38 +++ 16 files changed, 809 insertions(+), 5 deletions(-) create mode 100644 packages/block-library/src/image/runtime/constants.js create mode 100644 packages/block-library/src/image/runtime/directives.js create mode 100644 packages/block-library/src/image/runtime/hooks.js create mode 100644 packages/block-library/src/image/runtime/index.js create mode 100644 packages/block-library/src/image/runtime/init.js create mode 100644 packages/block-library/src/image/runtime/portal.js create mode 100644 packages/block-library/src/image/runtime/router.js create mode 100644 packages/block-library/src/image/runtime/store.js create mode 100644 packages/block-library/src/image/runtime/utils.js create mode 100644 packages/block-library/src/image/runtime/vdom.js create mode 100644 packages/block-library/src/image/view.js diff --git a/package.json b/package.json index e67cb21cfaf44b..c3d1ae824f190f 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,8 @@ "@wordpress/warning": "file:packages/warning", "@wordpress/widgets": "file:packages/widgets", "@wordpress/wordcount": "file:packages/wordcount", + "deepsignal": "1.3.0", + "preact": "10.13.2", "wicg-inert": "3.1.2" }, "devDependencies": { diff --git a/packages/block-library/package.json b/packages/block-library/package.json index 17f5ce6d8f242e..a0a05b5a44bc8a 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -32,7 +32,6 @@ ], "dependencies": { "@babel/runtime": "^7.16.0", - "@preact/signals": "^1.1.3", "@wordpress/a11y": "file:../a11y", "@wordpress/api-fetch": "file:../api-fetch", "@wordpress/autop": "file:../autop", @@ -65,14 +64,12 @@ "change-case": "^4.1.2", "classnames": "^2.3.1", "colord": "^2.7.0", - "deepsignal": "^1.3.0", "escape-html": "^1.0.3", "fast-average-color": "^9.1.1", "fast-deep-equal": "^3.1.3", "lodash": "^4.17.21", "memize": "^2.1.0", "micromodal": "^0.4.10", - "preact": "^10.13.2", "remove-accents": "^0.4.2" }, "peerDependencies": { diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index 791e09f73c8009..478ae38c26d24a 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -86,6 +86,7 @@ } }, "supports": { + "interactivity": true, "anchor": true, "color": { "text": false, @@ -121,5 +122,6 @@ { "name": "rounded", "label": "Rounded" } ], "editorStyle": "wp-block-image-editor", - "style": "wp-block-image" + "style": "wp-block-image", + "viewScript": [ "file:./view.min.js" ] } diff --git a/packages/block-library/src/image/index.php b/packages/block-library/src/image/index.php index e05939a4d0feac..8d7182fdb34319 100644 --- a/packages/block-library/src/image/index.php +++ b/packages/block-library/src/image/index.php @@ -15,6 +15,9 @@ */ function render_block_core_image( $attributes, $content ) { $processor = new WP_HTML_Tag_Processor( $content ); + $processor->next_tag( 'figure' ); + $processor->set_attribute( 'data-wp-context', '{ "core": { "isZoomed": false } }' ); + $processor->next_tag( 'img' ); if ( $processor->get_attribute( 'src' ) === null ) { @@ -29,7 +32,11 @@ function render_block_core_image( $attributes, $content ) { $processor->set_attribute( 'data-id', $attributes['data-id'] ); $content = $processor->get_updated_html(); } - return $content; + $processor->set_attribute( 'data-wp-on.click', 'actions.core.imageZoom'); + $processor->set_attribute( 'data-wp-class.isZoomed', 'context.core.isZoomed'); + $content = $processor->get_updated_html(); + + return $content . '
'; } diff --git a/packages/block-library/src/image/runtime/constants.js b/packages/block-library/src/image/runtime/constants.js new file mode 100644 index 00000000000000..66aa781744c5e7 --- /dev/null +++ b/packages/block-library/src/image/runtime/constants.js @@ -0,0 +1,3 @@ +export const csnMetaTagItemprop = 'wp-client-side-navigation'; +export const componentPrefix = 'wp-'; +export const directivePrefix = 'data-wp-'; diff --git a/packages/block-library/src/image/runtime/directives.js b/packages/block-library/src/image/runtime/directives.js new file mode 100644 index 00000000000000..91ec1a32004b18 --- /dev/null +++ b/packages/block-library/src/image/runtime/directives.js @@ -0,0 +1,256 @@ +/** @jsx h */ + +/** + * External dependencies + */ +import { h } from 'preact'; + +import { useContext, useMemo, useEffect } from 'preact/hooks'; +import { useSignalEffect } from '@preact/signals'; +import { deepSignal, peek } from 'deepsignal'; +/** + * Internal dependencies + */ +import { directive } from './hooks'; +import { prefetch, navigate, canDoClientSideNavigation } from './router'; +import Portal from './portal.js'; + +// Until useSignalEffects is fixed: +// https://github.com/preactjs/signals/issues/228 +const raf = window.requestAnimationFrame; +const tick = () => new Promise( ( r ) => raf( () => raf( r ) ) ); + +// Check if current page can do client-side navigation. +const clientSideNavigation = canDoClientSideNavigation( document.head ); + +const isObject = ( item ) => + item && typeof item === 'object' && ! Array.isArray( item ); + +const mergeDeepSignals = ( target, source ) => { + for ( const k in source ) { + if ( typeof peek( target, k ) === 'undefined' ) { + target[ `$${ k }` ] = source[ `$${ k }` ]; + } else if ( + isObject( peek( target, k ) ) && + isObject( peek( source, k ) ) + ) { + mergeDeepSignals( + target[ `$${ k }` ].peek(), + source[ `$${ k }` ].peek() + ); + } + } +}; + +export default () => { + // data-wp-context + directive( + 'context', + ( { + directives: { + context: { default: context }, + }, + props: { children }, + context: inherited, + } ) => { + const { Provider } = inherited; + const inheritedValue = useContext( inherited ); + const value = useMemo( () => { + const localValue = deepSignal( context ); + mergeDeepSignals( localValue, inheritedValue ); + return localValue; + }, [ context, inheritedValue ] ); + + return { children }; + } + ); + + directive( + 'portal', + ( { + directives: { + portal: { default: portal }, + }, + props: { children }, + } ) => { + return { children }; + } + ); + + // data-wp-effect.[name] + directive( 'effect', ( { directives: { effect }, context, evaluate } ) => { + const contextValue = useContext( context ); + Object.values( effect ).forEach( ( path ) => { + useSignalEffect( () => { + evaluate( path, { context: contextValue } ); + } ); + } ); + } ); + + // data-wp-on.[event] + directive( 'on', ( { directives: { on }, element, evaluate, context } ) => { + const contextValue = useContext( context ); + Object.entries( on ).forEach( ( [ name, path ] ) => { + element.props[ `on${ name }` ] = ( event ) => { + evaluate( path, { event, context: contextValue } ); + }; + } ); + } ); + + // data-wp-class.[classname] + directive( + 'class', + ( { + directives: { class: className }, + element, + evaluate, + context, + } ) => { + const contextValue = useContext( context ); + Object.keys( className ) + .filter( ( n ) => n !== 'default' ) + .forEach( ( name ) => { + const result = evaluate( className[ name ], { + className: name, + context: contextValue, + } ); + const currentClass = element.props.class || ''; + const classFinder = new RegExp( + `(^|\\s)${ name }(\\s|$)`, + 'g' + ); + if ( ! result ) + element.props.class = currentClass + .replace( classFinder, ' ' ) + .trim(); + else if ( ! classFinder.test( currentClass ) ) + element.props.class = currentClass + ? `${ currentClass } ${ name }` + : name; + + useEffect( () => { + // This seems necessary because Preact doesn't change the class names + // on the hydration, so we have to do it manually. It doesn't need + // deps because it only needs to do it the first time. + if ( ! result ) { + element.ref.current.classList.remove( name ); + } else { + element.ref.current.classList.add( name ); + } + }, [] ); + } ); + } + ); + + // data-wp-bind.[attribute] + directive( + 'bind', + ( { directives: { bind }, element, context, evaluate } ) => { + const contextValue = useContext( context ); + Object.entries( bind ) + .filter( ( n ) => n !== 'default' ) + .forEach( ( [ attribute, path ] ) => { + element.props[ attribute ] = evaluate( path, { + context: contextValue, + } ); + } ); + } + ); + + // data-wp-link + directive( + 'link', + ( { + directives: { + link: { default: link }, + }, + props: { href }, + element, + } ) => { + useEffect( () => { + // Prefetch the page if it is in the directive options. + if ( clientSideNavigation && link?.prefetch ) { + prefetch( href ); + } + } ); + + // Don't do anything if it's falsy. + if ( clientSideNavigation && link !== false ) { + element.props.onclick = async ( event ) => { + event.preventDefault(); + + // Fetch the page (or return it from cache). + await navigate( href ); + + // Update the scroll, depending on the option. True by default. + if ( link?.scroll === 'smooth' ) { + window.scrollTo( { + top: 0, + left: 0, + behavior: 'smooth', + } ); + } else if ( link?.scroll !== false ) { + window.scrollTo( 0, 0 ); + } + }; + } + } + ); + + // data-wp-show + directive( + 'show', + ( { + directives: { + show: { default: show }, + }, + element, + evaluate, + context, + } ) => { + const contextValue = useContext( context ); + if ( ! evaluate( show, { context: contextValue } ) ) + element.props.children = ( + + ); + } + ); + + // data-wp-ignore + directive( + 'ignore', + ( { + element: { + type: Type, + props: { innerHTML, ...rest }, + }, + } ) => { + // Preserve the initial inner HTML. + const cached = useMemo( () => innerHTML, [] ); + return ( + + ); + } + ); + + // data-wp-text + directive( + 'text', + ( { + directives: { + text: { default: text }, + }, + element, + evaluate, + context, + } ) => { + const contextValue = useContext( context ); + element.props.children = evaluate( text, { + context: contextValue, + } ); + } + ); +}; diff --git a/packages/block-library/src/image/runtime/hooks.js b/packages/block-library/src/image/runtime/hooks.js new file mode 100644 index 00000000000000..40b9f320952e1c --- /dev/null +++ b/packages/block-library/src/image/runtime/hooks.js @@ -0,0 +1,85 @@ +import { h, options, createContext } from 'preact'; +import { useRef } from 'preact/hooks'; +import { rawStore as store } from './store'; +import { componentPrefix } from './constants'; + +// Main context. +const context = createContext({}); + +// WordPress Directives. +const directiveMap = {}; +export const directive = (name, cb) => { + directiveMap[name] = cb; +}; + +// WordPress Components. +const componentMap = {}; +export const component = (name, Comp) => { + componentMap[name] = Comp; +}; + +// Resolve the path to some property of the store object. +const resolve = (path, context) => { + let current = { ...store, context }; + path.split('.').forEach((p) => (current = current[p])); + return current; +}; + +// Generate the evaluate function. +const getEvaluate = + ({ ref } = {}) => + (path, extraArgs = {}) => { + const value = resolve(path, extraArgs.context); + return typeof value === 'function' + ? value({ + state: store.state, + ...(ref !== undefined ? { ref } : {}), + ...extraArgs, + }) + : value; + }; + +// Directive wrapper. +const Directive = ({ type, directives, props: originalProps }) => { + const ref = useRef(null); + const element = h(type, { ...originalProps, ref, _wrapped: true }); + const props = { ...originalProps, children: element }; + const evaluate = getEvaluate({ ref: ref.current }); + const directiveArgs = { directives, props, element, context, evaluate }; + + for (const d in directives) { + const wrapper = directiveMap[d]?.(directiveArgs); + if (wrapper !== undefined) props.children = wrapper; + } + + return props.children; +}; + +// Preact Options Hook called each time a vnode is created. +const old = options.vnode; +options.vnode = (vnode) => { + const type = vnode.type; + const { directives } = vnode.props; + + if ( + typeof type === 'string' && + type.slice(0, componentPrefix.length) === componentPrefix + ) { + vnode.props.children = h( + componentMap[type.slice(componentPrefix.length)], + { ...vnode.props, context, evaluate: getEvaluate() }, + vnode.props.children + ); + } else if (directives) { + const props = vnode.props; + delete props.directives; + if (!props._wrapped) { + vnode.props = { type: vnode.type, directives, props }; + vnode.type = Directive; + } else { + delete props._wrapped; + } + } + + if (old) old(vnode); +}; diff --git a/packages/block-library/src/image/runtime/index.js b/packages/block-library/src/image/runtime/index.js new file mode 100644 index 00000000000000..926021bb579790 --- /dev/null +++ b/packages/block-library/src/image/runtime/index.js @@ -0,0 +1,2 @@ +export { store } from './store'; +export { navigate } from './router'; diff --git a/packages/block-library/src/image/runtime/init.js b/packages/block-library/src/image/runtime/init.js new file mode 100644 index 00000000000000..772a690c3279fd --- /dev/null +++ b/packages/block-library/src/image/runtime/init.js @@ -0,0 +1,11 @@ +/** + * Internal dependencies + */ +import registerDirectives from './directives'; +import { init } from './router'; + +document.addEventListener( 'DOMContentLoaded', async () => { + registerDirectives(); + await init(); + console.log( 'hydrated!' ); +} ); diff --git a/packages/block-library/src/image/runtime/portal.js b/packages/block-library/src/image/runtime/portal.js new file mode 100644 index 00000000000000..4b7cf67693dbc7 --- /dev/null +++ b/packages/block-library/src/image/runtime/portal.js @@ -0,0 +1,73 @@ +/** @jsx h */ + +/** + * External dependencies + */ +import { h, Component, render } from 'preact'; + +/** Redirect rendering of descendants into the given CSS selector. + * @example + * + *
I am rendered into document.body
+ *
+ */ +export default class Portal extends Component { + componentDidUpdate(props) { + for (let i in props) { + if (props[i]!==this.props[i]) { + return setTimeout(this.renderLayer); + } + } + } + + componentDidMount() { + this.isMounted=true; + this.renderLayer = this.renderLayer.bind(this); + this.renderLayer(); + } + + componentWillUnmount() { + this.renderLayer(false); + this.isMounted=false; + if (this.remote) this.remote.parentNode.removeChild(this.remote); + } + + findNode(node) { + return typeof node==='string' ? document.querySelector(node) : node; + } + + renderLayer(show=true) { + if (!this.isMounted) return; + + // clean up old node if moving bases: + if (this.props.into!==this.intoPointer) { + this.intoPointer = this.props.into; + if (this.into && this.remote) { + this.remote = render(, this.into, this.remote); + } + this.into = this.findNode(this.props.into); + } + + this.remote = render(( + + { show && this.props.children || null } + + ), this.into, this.remote); + } + + render() { + return null; + } +} + + +// high-order component that renders its first child if it exists. +// used as a conditional rendering proxy. +class PortalProxy extends Component { + getChildContext() { + return this.props.context; + } + render({ children }) { + return children || null; + } +} diff --git a/packages/block-library/src/image/runtime/router.js b/packages/block-library/src/image/runtime/router.js new file mode 100644 index 00000000000000..e813e1c1f19b92 --- /dev/null +++ b/packages/block-library/src/image/runtime/router.js @@ -0,0 +1,171 @@ +/** + * External dependencies + */ +import { hydrate, render } from 'preact'; +/** + * Internal dependencies + */ +import { toVdom, hydratedIslands } from './vdom'; +import { createRootFragment } from './utils'; +import { csnMetaTagItemprop, directivePrefix } from './constants'; + +// The root to render the vdom (document.body). +let rootFragment; + +// The cache of visited and prefetched pages, stylesheets and scripts. +const pages = new Map(); +const stylesheets = new Map(); +const scripts = new Map(); + +// Helper to remove domain and hash from the URL. We are only interesting in +// caching the path and the query. +const cleanUrl = ( url ) => { + const u = new URL( url, window.location ); + return u.pathname + u.search; +}; + +// Helper to check if a page can do client-side navigation. +export const canDoClientSideNavigation = ( dom ) => + dom + .querySelector( `meta[itemprop='${ csnMetaTagItemprop }']` ) + ?.getAttribute( 'content' ) === 'active'; + +/** + * Finds the elements in the document that match the selector and fetch them. + * For each element found, fetch the content and store it in the cache. + * Returns an array of elements to add to the document. + * + * @param document + * @param {string} selector - CSS selector used to find the elements. + * @param {'href'|'src'} attribute - Attribute that determines where to fetch + * the styles or scripts from. Also used as the key for the cache. + * @param {Map} cache - Cache to use for the elements. Can be `stylesheets` or `scripts`. + * @param {'style'|'script'} elementToCreate - Element to create for each fetched + * item. Can be 'style' or 'script'. + * @return {Promise>} - Array of elements to add to the document. + */ +const fetchScriptOrStyle = async ( + document, + selector, + attribute, + cache, + elementToCreate +) => { + const fetchedItems = await Promise.all( + [].map.call( document.querySelectorAll( selector ), ( el ) => { + const attributeValue = el.getAttribute( attribute ); + if ( ! cache.has( attributeValue ) ) + cache.set( + attributeValue, + fetch( attributeValue ).then( ( r ) => r.text() ) + ); + return cache.get( attributeValue ); + } ) + ); + + return fetchedItems.map( ( item ) => { + const element = document.createElement( elementToCreate ); + element.textContent = item; + return element; + } ); +}; + +// Fetch styles of a new page. +const fetchAssets = async ( document ) => { + const stylesFromSheets = await fetchScriptOrStyle( + document, + 'link[rel=stylesheet]', + 'href', + stylesheets, + 'style' + ); + const scriptTags = await fetchScriptOrStyle( + document, + 'script[src]', + 'src', + scripts, + 'script' + ); + const moduleScripts = await fetchScriptOrStyle( + document, + 'script[type=module]', + 'src', + scripts, + 'script' + ); + moduleScripts.forEach( ( script ) => + script.setAttribute( 'type', 'module' ) + ); + + return [ + ...scriptTags, + document.querySelector( 'title' ), + ...document.querySelectorAll( 'style' ), + ...stylesFromSheets, + ]; +}; + +// Fetch a new page and convert it to a static virtual DOM. +const fetchPage = async ( url, options = {} ) => { + const html = + options.html || ( await window.fetch( url ).then( ( r ) => r.text() ) ); + const dom = new window.DOMParser().parseFromString( html, 'text/html' ); + const head = await fetchAssets( dom ); + return { head, body: toVdom( dom.body ) }; +}; + +// Prefetch a page. We store the promise to avoid triggering a second fetch for +// a page if a fetching has already started. +export const prefetch = ( url, options = {} ) => { + url = cleanUrl( url ); + if ( options.force || ! pages.has( url ) ) { + pages.set( url, fetchPage( url, options ) ); + } +}; + +// Navigate to a new page. +export const navigate = async ( href, options = {} ) => { + const url = cleanUrl( href ); + prefetch( url, options ); + const page = await pages.get( url ); + if ( page ) { + document.head.replaceChildren( ...page.head ); + render( page.body, rootFragment ); + window.history.pushState( {}, '', href ); + } else { + window.location.assign( href ); + } +}; + +// Listen to the back and forward buttons and restore the page if it's in the +// cache. +window.addEventListener( 'popstate', async () => { + const url = cleanUrl( window.location ); // Remove hash. + const page = pages.has( url ) && ( await pages.get( url ) ); + if ( page ) { + document.head.replaceChildren( ...page.head ); + render( page.body, rootFragment ); + } else { + window.location.reload(); + } +} ); + +// Initialize the router with the initial DOM. +export const init = async () => { + // Create the root fragment to hydrate everything. + rootFragment = createRootFragment( + document.documentElement, + document.body + ); + + const body = toVdom( document.body ); + hydrate( body, rootFragment ); + + // Cache the scripts. Has to be called before fetching the assets. + [].map.call( document.querySelectorAll( 'script[src]' ), ( script ) => { + scripts.set( script.getAttribute( 'src' ), script.textContent ); + } ); + + const head = await fetchAssets( document ); + pages.set( cleanUrl( window.location ), Promise.resolve( { body, head } ) ); +}; diff --git a/packages/block-library/src/image/runtime/store.js b/packages/block-library/src/image/runtime/store.js new file mode 100644 index 00000000000000..eca682a194e844 --- /dev/null +++ b/packages/block-library/src/image/runtime/store.js @@ -0,0 +1,46 @@ +/** + * External dependencies + */ +import { deepSignal } from 'deepsignal'; + +const isObject = ( item ) => + item && typeof item === 'object' && ! Array.isArray( item ); + +export const deepMerge = ( target, source ) => { + if ( isObject( target ) && isObject( source ) ) { + for ( const key in source ) { + if ( isObject( source[ key ] ) ) { + if ( ! target[ key ] ) Object.assign( target, { [ key ]: {} } ); + deepMerge( target[ key ], source[ key ] ); + } else { + Object.assign( target, { [ key ]: source[ key ] } ); + } + } + } +}; + +const getSerializedState = () => { + // TODO: change the store tag ID for a better one. + const storeTag = document.querySelector( + `script[type="application/json"]#store` + ); + if ( ! storeTag ) return {}; + try { + const { state } = JSON.parse( storeTag.textContent ); + if ( isObject( state ) ) return state; + throw Error( 'Parsed state is not an object' ); + } catch ( e ) { + console.log( e ); + } + return {}; +}; + +const rawState = getSerializedState(); +export const rawStore = { state: deepSignal( rawState ) }; + +if ( typeof window !== 'undefined' ) window.store = rawStore; + +export const store = ( { state, ...block } ) => { + deepMerge( rawStore, block ); + deepMerge( rawState, state ); +}; diff --git a/packages/block-library/src/image/runtime/utils.js b/packages/block-library/src/image/runtime/utils.js new file mode 100644 index 00000000000000..f1748293cad99f --- /dev/null +++ b/packages/block-library/src/image/runtime/utils.js @@ -0,0 +1,20 @@ +// For wrapperless hydration of document.body. +// See https://gist.github.com/developit/f4c67a2ede71dc2fab7f357f39cff28c +export const createRootFragment = (parent, replaceNode) => { + replaceNode = [].concat(replaceNode); + const s = replaceNode[replaceNode.length - 1].nextSibling; + function insert(c, r) { + parent.insertBefore(c, r || s); + } + return (parent.__k = { + nodeType: 1, + parentNode: parent, + firstChild: replaceNode[0], + childNodes: replaceNode, + insertBefore: insert, + appendChild: insert, + removeChild(c) { + parent.removeChild(c); + }, + }); +}; diff --git a/packages/block-library/src/image/runtime/vdom.js b/packages/block-library/src/image/runtime/vdom.js new file mode 100644 index 00000000000000..f1cd54420a86a4 --- /dev/null +++ b/packages/block-library/src/image/runtime/vdom.js @@ -0,0 +1,71 @@ +import { h } from 'preact'; +import { directivePrefix as p } from './constants'; + +const ignoreAttr = `${p}ignore`; +const islandAttr = `${p}island`; +const directiveParser = new RegExp(`${p}([^.]+)\.?(.*)$`); + +export const hydratedIslands = new WeakSet(); + +// Recursive function that transfoms a DOM tree into vDOM. +export function toVdom(node) { + const props = {}; + const { attributes, childNodes } = node; + const directives = {}; + let hasDirectives = false; + let ignore = false; + let island = false; + + if (node.nodeType === 3) return node.data; + if (node.nodeType === 4) { + node.replaceWith(new Text(node.nodeValue)); + return node.nodeValue; + } + + for (let i = 0; i < attributes.length; i++) { + const n = attributes[i].name; + if (n[p.length] && n.slice(0, p.length) === p) { + if (n === ignoreAttr) { + ignore = true; + } else if (n === islandAttr) { + island = true; + } else { + hasDirectives = true; + let val = attributes[i].value; + try { + val = JSON.parse(val); + } catch (e) {} + const [, prefix, suffix] = directiveParser.exec(n); + directives[prefix] = directives[prefix] || {}; + directives[prefix][suffix || 'default'] = val; + } + } else if (n === 'ref') { + continue; + } else { + props[n] = attributes[i].value; + } + } + + if (ignore && !island) + return h(node.localName, { + ...props, + innerHTML: node.innerHTML, + directives: { ignore: true }, + }); + if (island) hydratedIslands.add(node); + + if (hasDirectives) props.directives = directives; + + const children = []; + for (let i = 0; i < childNodes.length; i++) { + const child = childNodes[i]; + if (child.nodeType === 8 || child.nodeType === 7) { + child.remove(); + i--; + } else { + children.push(toVdom(child)); + } + } + + return h(node.localName, props, children); +} diff --git a/packages/block-library/src/image/style.scss b/packages/block-library/src/image/style.scss index 2dfb86228567a2..16015eed7c9107 100644 --- a/packages/block-library/src/image/style.scss +++ b/packages/block-library/src/image/style.scss @@ -4,6 +4,12 @@ max-width: 100%; vertical-align: bottom; box-sizing: border-box; + + &.iszoomed { + z-index: 200000; + position: absolute; + width: 100vw; + } } // The following style maintains border radius application for deprecated @@ -151,3 +157,17 @@ .wp-block-image figure { margin: 0; } + +.overlay { + position: fixed; + top: 0; + left: 0; + background: rgba(255, 255, 255, .95); + z-index: 100000; + overflow: hidden; + + div { + width: 100vw; + height: 100vh; + } +} diff --git a/packages/block-library/src/image/view.js b/packages/block-library/src/image/view.js new file mode 100644 index 00000000000000..992005c4cbbbab --- /dev/null +++ b/packages/block-library/src/image/view.js @@ -0,0 +1,38 @@ +import './runtime/init.js'; +import { store } from './runtime'; + +store({ + state: { + core: { + isZoomed: false, + }, + }, + actions: { + core: { + imageZoom: ( { context, state } ) => { + context.core.isZoomed = !context.core.isZoomed; + state.core.isZoomed = context.core.isZoomed; + context.core.handleScroll = () => { + context.core.isZoomed = false; + state.core.isZoomed = context.core.isZoomed; + window.removeEventListener( + 'scroll', + context.core.handleScroll + ); + } + + if ( context.core.isZoomed ) { + window.addEventListener( + 'scroll', + context.core.handleScroll + ); + } else if ( context.core.handleScroll ) { + window.removeEventListener( + 'scroll', + context.core.handleScroll + ); + } + }, + }, + }, +}); From 9ca29188c64afc01738c9c91323d5776829e1863 Mon Sep 17 00:00:00 2001 From: Artemio Morales Date: Mon, 3 Apr 2023 17:46:00 +0200 Subject: [PATCH 058/125] Add logic for hiding lightbox on esc key press and overlay click --- packages/block-library/src/image/index.php | 14 ++++++-- .../src/image/runtime/directives.js | 19 +++++++++- packages/block-library/src/image/style.scss | 27 ++++++++++---- packages/block-library/src/image/view.js | 36 ++++++++++++------- 4 files changed, 74 insertions(+), 22 deletions(-) diff --git a/packages/block-library/src/image/index.php b/packages/block-library/src/image/index.php index 8d7182fdb34319..3edf2db37e655d 100644 --- a/packages/block-library/src/image/index.php +++ b/packages/block-library/src/image/index.php @@ -16,7 +16,8 @@ function render_block_core_image( $attributes, $content ) { $processor = new WP_HTML_Tag_Processor( $content ); $processor->next_tag( 'figure' ); - $processor->set_attribute( 'data-wp-context', '{ "core": { "isZoomed": false } }' ); + $processor->set_attribute( 'data-wp-class.isZoomed', 'context.core.isZoomed'); + $processor->set_attribute( 'data-wp-init', 'actions.core.closeZoomOnEsc'); $processor->next_tag( 'img' ); @@ -33,10 +34,17 @@ function render_block_core_image( $attributes, $content ) { $content = $processor->get_updated_html(); } $processor->set_attribute( 'data-wp-on.click', 'actions.core.imageZoom'); - $processor->set_attribute( 'data-wp-class.isZoomed', 'context.core.isZoomed'); + $content = $processor->get_updated_html(); - return $content . '
'; + return << + $content +
+
+
+ + HTML; } diff --git a/packages/block-library/src/image/runtime/directives.js b/packages/block-library/src/image/runtime/directives.js index 91ec1a32004b18..fb24aa20e3684e 100644 --- a/packages/block-library/src/image/runtime/directives.js +++ b/packages/block-library/src/image/runtime/directives.js @@ -72,11 +72,28 @@ export default () => { portal: { default: portal }, }, props: { children }, + context: inherited, } ) => { - return { children }; + const { Provider } = inherited; + const inheritedValue = useContext( inherited ); + return ( + + { children } + + ); } ); + // data-wp-init.[name] + directive( 'init', ( { directives: { init }, context, evaluate } ) => { + const contextValue = useContext( context ); + Object.values( init ).forEach( ( path ) => { + useEffect( () => { + evaluate( path, { context: contextValue } ); + }, [] ); + } ); + } ); + // data-wp-effect.[name] directive( 'effect', ( { directives: { effect }, context, evaluate } ) => { const contextValue = useContext( context ); diff --git a/packages/block-library/src/image/style.scss b/packages/block-library/src/image/style.scss index 16015eed7c9107..2f1b7fbc976a46 100644 --- a/packages/block-library/src/image/style.scss +++ b/packages/block-library/src/image/style.scss @@ -4,12 +4,6 @@ max-width: 100%; vertical-align: bottom; box-sizing: border-box; - - &.iszoomed { - z-index: 200000; - position: absolute; - width: 100vw; - } } // The following style maintains border radius application for deprecated @@ -158,6 +152,27 @@ margin: 0; } +figure.wp-block-image { + margin: 0; + + img { + transition: transform 300ms cubic-bezier(0.2, 0, 0.2, 1); + } + + &.iszoomed { + z-index: 200000; + position: absolute; + + display: flex; + justify-content: center; + align-items: center; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + } +} + .overlay { position: fixed; top: 0; diff --git a/packages/block-library/src/image/view.js b/packages/block-library/src/image/view.js index 992005c4cbbbab..2ecb4e87e70e60 100644 --- a/packages/block-library/src/image/view.js +++ b/packages/block-library/src/image/view.js @@ -1,25 +1,18 @@ import './runtime/init.js'; import { store } from './runtime'; -store({ - state: { - core: { - isZoomed: false, - }, - }, +store( { actions: { core: { - imageZoom: ( { context, state } ) => { - context.core.isZoomed = !context.core.isZoomed; - state.core.isZoomed = context.core.isZoomed; + imageZoom: ( { context } ) => { + context.core.isZoomed = ! context.core.isZoomed; context.core.handleScroll = () => { context.core.isZoomed = false; - state.core.isZoomed = context.core.isZoomed; window.removeEventListener( 'scroll', context.core.handleScroll ); - } + }; if ( context.core.isZoomed ) { window.addEventListener( @@ -33,6 +26,25 @@ store({ ); } }, + closeZoom: ( { context } ) => { + console.log( 'closing zoom' ); + context.core.isZoomed = false; + }, + closeZoomOnEsc: ( { context } ) => { + // Function to handle the ESC key press + function handleEscKey( event ) { + if ( event.key === 'Escape' || event.keyCode === 27 ) { + console.log( 'ESC key pressed' ); + // Add any custom logic you want to execute when the ESC key is pressed + context.core.isZoomed = false; + } + } + // Add the event listener for the 'keydown' event on the document + document.addEventListener( 'keydown', handleEscKey ); + return () => { + document.removeEventListener( 'keydown', handleEscKey ); + }; + }, }, }, -}); +} ); From dca1b363fae3a1b6bfe1b0953fcb7cc5f6bb91e4 Mon Sep 17 00:00:00 2001 From: Artemio Morales Date: Wed, 5 Apr 2023 18:20:10 +0200 Subject: [PATCH 059/125] Improve styles and add note to add conditional for lightbox markup --- packages/block-library/src/image/index.php | 10 ++++--- packages/block-library/src/image/style.scss | 33 +++++++++++---------- packages/block-library/src/image/view.js | 1 - 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/packages/block-library/src/image/index.php b/packages/block-library/src/image/index.php index 3edf2db37e655d..d9702cdddb18d0 100644 --- a/packages/block-library/src/image/index.php +++ b/packages/block-library/src/image/index.php @@ -16,8 +16,10 @@ function render_block_core_image( $attributes, $content ) { $processor = new WP_HTML_Tag_Processor( $content ); $processor->next_tag( 'figure' ); + + /// Include conditional to detect if user has activated lightbox in settings #1 $processor->set_attribute( 'data-wp-class.isZoomed', 'context.core.isZoomed'); - $processor->set_attribute( 'data-wp-init', 'actions.core.closeZoomOnEsc'); + $processor->set_attribute( 'data-wp-init.closeZoomOnEsc', 'actions.core.closeZoomOnEsc'); $processor->next_tag( 'img' ); @@ -33,12 +35,12 @@ function render_block_core_image( $attributes, $content ) { $processor->set_attribute( 'data-id', $attributes['data-id'] ); $content = $processor->get_updated_html(); } - $processor->set_attribute( 'data-wp-on.click', 'actions.core.imageZoom'); + /// Include conditional to detect if user has activated lightbox in settings #2 + $processor->set_attribute( 'data-wp-on.click', 'actions.core.imageZoom'); $content = $processor->get_updated_html(); - return << + @@ -83,7 +84,7 @@ function register_block_core_image() { wp_enqueue_script( 'interactivity-image', - plugins_url('../interactive-blocks/image.min.js', __FILE__ ), + plugins_url( '../interactive-blocks/image.min.js', __FILE__ ), array( 'interactivity-runtime' ) ); diff --git a/packages/block-library/src/image/interactivity.js b/packages/block-library/src/image/interactivity.js index 26865ba0a99711..b74c745944cd12 100644 --- a/packages/block-library/src/image/interactivity.js +++ b/packages/block-library/src/image/interactivity.js @@ -8,92 +8,55 @@ const raf = window.requestAnimationFrame; const tick = () => new Promise( ( r ) => raf( () => raf( r ) ) ); store( { - effects: { - alert: ( { context } ) => { - // eslint-disable-next-line no-console - console.log( context.text ); - }, - }, actions: { core: { - showLightbox: ( { context, event } ) => { + showLightbox: ( { context } ) => { context.core.initialized = true; - context.core.lightboxEnabled = ! context.core.lightboxEnabled; - context.core.lastFocusedElement = - event.target.ownerDocument.activeElement; - - context.core.handleScroll = () => { - context.core.lightboxEnabled = false; - window.removeEventListener( - 'scroll', - context.core.handleScroll - ); - }; - - if ( context.core.lightboxEnabled ) { - window.addEventListener( - 'scroll', - context.core.handleScroll - ); - } else if ( context.core.handleScroll ) { - window.removeEventListener( - 'scroll', - context.core.handleScroll - ); - } + context.core.lightboxEnabled = true; + context.core.lastFocusedElement = window.document.activeElement; }, hideLightbox: ( { context, event } ) => { - context.core.lightboxEnabled = false; - if ( event.pointerType === '' ) { - context.core.lastFocusedElement.focus(); - } - }, - hideLightboxOnEsc: ( { context } ) => { - function handleEscKey( event ) { + if ( context.core.lightboxEnabled ) { + context.core.lightboxEnabled = false; + + // We only want to focus the last focused element + // if the lightbox was closed by the keyboard. + // Note: Pressing enter on a button will trigger + // a click event with a blank pointerType. if ( - context.core.lightboxEnabled && - ( event.key === 'Escape' || event.keyCode === 27 ) + ( event.key && event.type === 'keydown' ) || + ( event.type === 'click' && event.pointerType === '' ) ) { - context.core.lightboxEnabled = false; context.core.lastFocusedElement.focus(); } } - // Add the event listener for the 'keydown' event on the document - document.addEventListener( 'keydown', handleEscKey ); - return () => { - document.removeEventListener( 'keydown', handleEscKey ); - }; }, - hideLightboxOnTab: ( { context } ) => { - async function handleTab( event ) { - if ( - context.core.lightboxEnabled && - ( event.key === 'Tab' || event.keyCode === 9 ) - ) { + handleKeydown: ( { context, actions, event } ) => { + if ( context.core.lightboxEnabled ) { + const isTabKeyPressed = + event.key === 'Tab' || event.keyCode === 9; + const escapeKeyPressed = + event.key === 'Escape' || event.keyCode === 27; + + if ( isTabKeyPressed ) { event.preventDefault(); - context.core.lightboxEnabled = false; - context.core.lastFocusedElement.focus(); + } + + if ( escapeKeyPressed || isTabKeyPressed ) { + actions.core.hideLightbox( { context, event } ); } } - // Add the event listener for the 'keydown' event on the document - document.addEventListener( 'keydown', handleTab ); - return () => { - document.removeEventListener( 'keydown', handleTab ); - }; }, - toggleAriaHidden: ( { context, ref } ) => { - ref.setAttribute( - 'aria-hidden', - ! context.core.lightboxEnabled - ); - }, - focusOnClose: async ( { context, ref } ) => { + }, + }, + effects: { + core: { + initLightbox: async ( { context, ref } ) => { if ( context.core.lightboxEnabled ) { - // We need to wait until the DOM is updated and able + // We need to wait until the DOM is able // to receive focus updates for accessibility await tick(); - await tick(); - ref.focus(); + ref.querySelector( '.close-button' ).focus(); } }, }, From 910706f7a343c4d7a9260ee471833f6d3d61d4fe Mon Sep 17 00:00:00 2001 From: Artemio Morales Date: Wed, 3 May 2023 12:49:51 +0200 Subject: [PATCH 071/125] Fix formatting in SCSS file --- packages/block-library/src/image/style.scss | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/block-library/src/image/style.scss b/packages/block-library/src/image/style.scss index 7ddfe7bae41c31..86d6252c0f0005 100644 --- a/packages/block-library/src/image/style.scss +++ b/packages/block-library/src/image/style.scss @@ -155,7 +155,7 @@ .wp-lightbox-container { button { border: none; - background: none; + background: none; cursor: zoom-in; } } @@ -206,22 +206,21 @@ .scrim { width: 100%; height: 100%; - opacity: 0; position: absolute; z-index: 2000000; - background-color:rgb(255, 255, 255); - opacity: .9; + background-color: rgb(255, 255, 255); + opacity: 0.9; } &.initialized { animation: both turn-off-visibility 300ms; img { - animation: both turn-off-visibility 250ms; + animation: both turn-off-visibility 250ms; } &.active { - animation: both turn-on-visibility 250ms; + animation: both turn-on-visibility 250ms; img { animation: both turn-on-visibility 300ms; From 1ebe07b3343b8fd759bb56d402b24ec2e2485eb8 Mon Sep 17 00:00:00 2001 From: Artemio Morales Date: Wed, 3 May 2023 13:00:48 +0200 Subject: [PATCH 072/125] Change CheckboxControl to a ToggleControl; update API docs --- docs/reference-guides/core-blocks.md | 18 +++++++++--------- packages/block-library/src/image/image.js | 9 ++++----- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index df852bf97b6664..1af8cb6c028714 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -60,7 +60,7 @@ Prompt visitors to take action with a group of button-style links. ([Source](htt - **Name:** core/buttons - **Category:** design - **Supports:** align (full, wide), anchor, spacing (blockGap, margin), typography (fontSize, lineHeight), ~~html~~ -- **Attributes:** +- **Attributes:** ## Calendar @@ -168,7 +168,7 @@ Contains the block elements used to display a comment, like the title, date, aut - **Name:** core/comment-template - **Category:** design - **Supports:** align, anchor, spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~, ~~reusable~~ -- **Attributes:** +- **Attributes:** ## Comments @@ -204,7 +204,7 @@ Displays a list of page numbers for comments pagination. ([Source](https://githu - **Name:** core/comments-pagination-numbers - **Category:** theme - **Supports:** anchor, color (background, gradients, ~~text~~), typography (fontSize, lineHeight), ~~html~~, ~~reusable~~ -- **Attributes:** +- **Attributes:** ## Comments Previous Page @@ -321,7 +321,7 @@ Insert an image to make a visual statement. ([Source](https://github.com/WordPre - **Name:** core/image - **Category:** media - **Supports:** anchor, color (~~background~~, ~~text~~), filter (duotone) -- **Attributes:** align, alt, behaviors, caption, height, href, id, linkClass, linkDestination, linkTarget, rel, sizeSlug, title, url, width +- **Attributes:** align, alt, behaviors, caption, enableLightbox, height, href, id, linkClass, linkDestination, linkTarget, rel, sizeSlug, title, url, width ## Latest Comments @@ -429,7 +429,7 @@ Separate your content into a multi-page experience. ([Source](https://github.com - **Name:** core/nextpage - **Category:** design - **Supports:** ~~className~~, ~~customClassName~~, ~~html~~ -- **Attributes:** +- **Attributes:** ## Page List @@ -537,7 +537,7 @@ Displays the contents of a post or page. ([Source](https://github.com/WordPress/ - **Name:** core/post-content - **Category:** theme - **Supports:** align (full, wide), anchor, dimensions (minHeight), typography (fontSize, lineHeight), ~~html~~ -- **Attributes:** +- **Attributes:** ## Post Date @@ -582,7 +582,7 @@ Contains the block elements used to render a post, like the title, date, feature - **Name:** core/post-template - **Category:** theme - **Supports:** align (full, wide), anchor, color (background, gradients, link, text), typography (fontSize, lineHeight), ~~html~~, ~~reusable~~ -- **Attributes:** +- **Attributes:** ## Post Terms @@ -645,7 +645,7 @@ Contains the block elements used to render content when no query results are fou - **Name:** core/query-no-results - **Category:** theme - **Supports:** align, anchor, color (background, gradients, link, text), typography (fontSize, lineHeight), ~~html~~, ~~reusable~~ -- **Attributes:** +- **Attributes:** ## Pagination @@ -672,7 +672,7 @@ Displays a list of page numbers for pagination ([Source](https://github.com/Word - **Name:** core/query-pagination-numbers - **Category:** theme - **Supports:** anchor, color (background, gradients, ~~text~~), typography (fontSize, lineHeight), ~~html~~, ~~reusable~~ -- **Attributes:** +- **Attributes:** ## Previous Page diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js index 6f55ec022ae2c9..676c9694ebc9a6 100644 --- a/packages/block-library/src/image/image.js +++ b/packages/block-library/src/image/image.js @@ -10,7 +10,7 @@ import { TextareaControl, TextControl, ToolbarButton, - CheckboxControl, + ToggleControl, __experimentalHeading as Heading, } from '@wordpress/components'; import { useViewportMatch, usePrevious } from '@wordpress/compose'; @@ -465,13 +465,12 @@ export default function Image( { > Behaviors - { + onChange={ () => { setAttributes( { - enableLightbox: value, + enableLightbox: ! enableLightbox, } ); } } /> From 10cdc07b2b4d2727e7f157b243a19d523a083c73 Mon Sep 17 00:00:00 2001 From: Artemio Morales Date: Wed, 3 May 2023 13:29:58 +0200 Subject: [PATCH 073/125] Update wp_enqueue_script to correctly add interactivity runtime --- packages/block-library/src/image/index.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/image/index.php b/packages/block-library/src/image/index.php index fcdd36133db173..688a5ce27ebc03 100644 --- a/packages/block-library/src/image/index.php +++ b/packages/block-library/src/image/index.php @@ -83,9 +83,9 @@ function render_block_core_image( $attributes, $content ) { function register_block_core_image() { wp_enqueue_script( - 'interactivity-image', + 'wp-interactivity-image', plugins_url( '../interactive-blocks/image.min.js', __FILE__ ), - array( 'interactivity-runtime' ) + array( 'wp-interactivity-runtime' ) ); register_block_type_from_metadata( From d035dc498cd8a91c605faa907fa06776679af5bb Mon Sep 17 00:00:00 2001 From: Artemio Morales Date: Thu, 4 May 2023 10:48:00 +0200 Subject: [PATCH 074/125] Fix linter errors --- packages/block-library/src/image/index.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/block-library/src/image/index.php b/packages/block-library/src/image/index.php index 688a5ce27ebc03..1dc7f6429c2364 100644 --- a/packages/block-library/src/image/index.php +++ b/packages/block-library/src/image/index.php @@ -31,16 +31,16 @@ function render_block_core_image( $attributes, $content ) { } $link_destination = isset( $attributes['linkDestination'] ) ? $attributes['linkDestination'] : 'none'; - $enable_lightbox = isset( $attributes['enableLightbox'] ) ? $attributes['enableLightbox'] : false; + $enable_lightbox = isset( $attributes['enableLightbox'] ) ? $attributes['enableLightbox'] : false; - if ( $link_destination === 'none' && $enable_lightbox ) { + if ( 'none' === $link_destination && $enable_lightbox ) { $aria_label = 'Open image lightbox'; - if($processor->get_attribute( 'alt' )) { + if ( $processor->get_attribute( 'alt' ) ) { $aria_label .= ' - ' . $processor->get_attribute( 'alt' ); } - $background_color = wp_get_global_styles(['color', 'background']); + $background_color = wp_get_global_styles( array( 'color', 'background' ) ); $close_button_icon = ''; $content = $processor->get_updated_html(); From aa267c0ead5a034bafe05d7fb7b6aca859f8b08c Mon Sep 17 00:00:00 2001 From: Artemio Morales Date: Thu, 4 May 2023 12:55:14 +0200 Subject: [PATCH 075/125] Update to use core.image namespace --- packages/block-library/src/image/index.php | 18 ++-- .../block-library/src/image/interactivity.js | 82 ++++++++++--------- 2 files changed, 53 insertions(+), 47 deletions(-) diff --git a/packages/block-library/src/image/index.php b/packages/block-library/src/image/index.php index 1dc7f6429c2364..b02986c93e03c8 100644 --- a/packages/block-library/src/image/index.php +++ b/packages/block-library/src/image/index.php @@ -49,22 +49,22 @@ function render_block_core_image( $attributes, $content ) { << - HTML; } From 7f2cfe5078bba3d3b009321cfeaa92306af040e0 Mon Sep 17 00:00:00 2001 From: Ricardo Artemio Morales Date: Mon, 8 May 2023 10:05:43 +0200 Subject: [PATCH 084/125] Revise package-lock.json to match trunk --- package-lock.json | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/package-lock.json b/package-lock.json index 6f28bfd012b3a9..2f674821f32951 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7095,6 +7095,28 @@ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz", "integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==" }, + "@preact/signals": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@preact/signals/-/signals-1.1.3.tgz", + "integrity": "sha512-N09DuAVvc90bBZVRwD+aFhtGyHAmJLhS3IFoawO/bYJRcil4k83nBOchpCEoS0s5+BXBpahgp0Mjf+IOqP57Og==", + "requires": { + "@preact/signals-core": "^1.2.3" + } + }, + "@preact/signals-core": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.3.0.tgz", + "integrity": "sha512-M+M3ZOtd1dtV/uasyk4SZu1vbfEJ4NeENv0F7F12nijZYedB5wSgbtZcuACyssnTznhF4ctUyrR0dZHuHfyWKA==" + }, + "@preact/signals-react": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@preact/signals-react/-/signals-react-1.3.1.tgz", + "integrity": "sha512-YHWoGAT2Mmv2OGlGx7CCCbaLjAH/InV9ytGAR+esX8Y0HJmMAw51QlqGYOD5GPA5LwimV7Ht1x7KEIegDZIoxg==", + "requires": { + "@preact/signals-core": "^1.3.0", + "use-sync-external-store": "^1.2.0" + } + }, "@radix-ui/primitive": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.0.tgz", From effd38996ef12c0a487eed5329a72c5d21122e14 Mon Sep 17 00:00:00 2001 From: Ricardo Artemio Morales Date: Mon, 8 May 2023 10:06:32 +0200 Subject: [PATCH 085/125] Fix linter errors in portals.js --- .../src/utils/interactivity/portals.js | 62 ++++++++++++------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/packages/block-library/src/utils/interactivity/portals.js b/packages/block-library/src/utils/interactivity/portals.js index 80d70e76e9249b..ccb293d6c20e80 100644 --- a/packages/block-library/src/utils/interactivity/portals.js +++ b/packages/block-library/src/utils/interactivity/portals.js @@ -1,40 +1,44 @@ +/** + * External dependencies + */ import { createElement, render } from 'preact'; /** * @param {import('../../src/index').RenderableProps<{ context: any }>} props */ -function ContextProvider(props) { +function ContextProvider( props ) { this.getChildContext = () => props.context; return props.children; } /** * Portal component + * * @this {import('./internal').Component} * @param {object | null | undefined} props * - * TODO: use createRoot() instead of fake root + * TODO: use createRoot() instead of fake root */ -function Portal(props) { +function Portal( props ) { const _this = this; - let container = props._container; + const container = props._container; _this.componentWillUnmount = function () { - render(null, _this._temp); + render( null, _this._temp ); _this._temp = null; _this._container = null; }; // When we change container we should clear our old container and // indicate a new mount. - if (_this._container && _this._container !== container) { + if ( _this._container && _this._container !== container ) { _this.componentWillUnmount(); } // When props.vnode is undefined/false/null we are dealing with some kind of // conditional vnode. This should not trigger a render. - if (props._vnode) { - if (!_this._temp) { + if ( props._vnode ) { + if ( ! _this._temp ) { _this._container = container; // Create a fake DOM parent node that manages a subset of `container`'s children: @@ -42,41 +46,53 @@ function Portal(props) { nodeType: 1, parentNode: container, childNodes: [], - appendChild(child) { - this.childNodes.push(child); - _this._container.appendChild(child); + appendChild( child ) { + this.childNodes.push( child ); + _this._container.appendChild( child ); }, - insertBefore(child, before) { - this.childNodes.push(child); - _this._container.appendChild(child); + insertBefore( child ) { + this.childNodes.push( child ); + _this._container.appendChild( child ); + }, + removeChild( child ) { + this.childNodes.splice( + // eslint-disable-next-line no-bitwise + this.childNodes.indexOf( child ) >>> 1, + 1 + ); + _this._container.removeChild( child ); }, - removeChild(child) { - this.childNodes.splice(this.childNodes.indexOf(child) >>> 1, 1); - _this._container.removeChild(child); - } }; } // Render our wrapping element into temp. render( - createElement(ContextProvider, { context: _this.context }, props._vnode), + createElement( + ContextProvider, + { context: _this.context }, + props._vnode + ), _this._temp ); } // When we come from a conditional render, on a mounted // portal we should clear the DOM. - else if (_this._temp) { + else if ( _this._temp ) { _this.componentWillUnmount(); } } /** * Create a `Portal` to continue rendering the vnode tree at a different DOM node - * @param {import('./internal').VNode} vnode The vnode to render + * + * @param {import('./internal').VNode} vnode The vnode to render * @param {import('./internal').PreactElement} container The DOM node to continue rendering in to. */ -export function createPortal(vnode, container) { - const el = createElement(Portal, { _vnode: vnode, _container: container }); +export function createPortal( vnode, container ) { + const el = createElement( Portal, { + _vnode: vnode, + _container: container, + } ); el.containerInfo = container; return el; } From 8c7adaed99a3059a7a818bcf7d3bf279efc9d1db Mon Sep 17 00:00:00 2001 From: Ricardo Artemio Morales Date: Mon, 8 May 2023 10:58:23 +0200 Subject: [PATCH 086/125] Update fixtures --- .../blocks/core__gallery-with-caption.json | 6 ++++-- .../fixtures/blocks/core__gallery.json | 6 ++++-- .../blocks/core__gallery__columns.json | 6 ++++-- .../blocks/core__gallery__deprecated-1.json | 6 ++++-- .../blocks/core__gallery__deprecated-2.json | 6 ++++-- .../blocks/core__gallery__deprecated-3.json | 6 ++++-- .../blocks/core__gallery__deprecated-4.json | 9 ++++++--- .../blocks/core__gallery__deprecated-5.json | 9 ++++++--- .../blocks/core__gallery__deprecated-6.json | 9 ++++++--- .../blocks/core__gallery__deprecated-7.json | 18 ++++++++++++------ .../fixtures/blocks/core__image.json | 3 ++- .../blocks/core__image__attachment-link.json | 3 ++- .../blocks/core__image__center-caption.json | 3 ++- .../blocks/core__image__custom-link-class.json | 3 ++- .../blocks/core__image__custom-link-rel.json | 3 ++- .../blocks/core__image__custom-link.json | 3 ++- .../blocks/core__image__deprecated-3.json | 3 ++- .../blocks/core__image__media-link.json | 3 ++- 18 files changed, 70 insertions(+), 35 deletions(-) diff --git a/test/integration/fixtures/blocks/core__gallery-with-caption.json b/test/integration/fixtures/blocks/core__gallery-with-caption.json index 12b516606641d4..c2f60b590c5fab 100644 --- a/test/integration/fixtures/blocks/core__gallery-with-caption.json +++ b/test/integration/fixtures/blocks/core__gallery-with-caption.json @@ -24,7 +24,8 @@ "caption": "", "id": 1421, "sizeSlug": "large", - "linkDestination": "none" + "linkDestination": "none", + "enableLightbox": true }, "innerBlocks": [] }, @@ -37,7 +38,8 @@ "caption": "", "id": 1440, "sizeSlug": "large", - "linkDestination": "none" + "linkDestination": "none", + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery.json b/test/integration/fixtures/blocks/core__gallery.json index 8b7a1000d37ccc..7e3407a996075b 100644 --- a/test/integration/fixtures/blocks/core__gallery.json +++ b/test/integration/fixtures/blocks/core__gallery.json @@ -24,7 +24,8 @@ "caption": "", "id": 1421, "sizeSlug": "large", - "linkDestination": "none" + "linkDestination": "none", + "enableLightbox": true }, "innerBlocks": [] }, @@ -37,7 +38,8 @@ "caption": "", "id": 1440, "sizeSlug": "large", - "linkDestination": "none" + "linkDestination": "none", + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__columns.json b/test/integration/fixtures/blocks/core__gallery__columns.json index d0c40b3d3a9a93..b7168e1e680f35 100644 --- a/test/integration/fixtures/blocks/core__gallery__columns.json +++ b/test/integration/fixtures/blocks/core__gallery__columns.json @@ -24,7 +24,8 @@ "caption": "", "id": 1421, "sizeSlug": "large", - "linkDestination": "none" + "linkDestination": "none", + "enableLightbox": true }, "innerBlocks": [] }, @@ -37,7 +38,8 @@ "caption": "", "id": 1440, "sizeSlug": "large", - "linkDestination": "none" + "linkDestination": "none", + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-1.json b/test/integration/fixtures/blocks/core__gallery__deprecated-1.json index 9e15ee7f1c7149..852dfb49d67394 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-1.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-1.json @@ -16,7 +16,8 @@ "attributes": { "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", "alt": "title", - "linkDestination": "none" + "linkDestination": "none", + "enableLightbox": true }, "innerBlocks": [] }, @@ -26,7 +27,8 @@ "attributes": { "url": "data:image/jpeg;base64,/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=", "alt": "title", - "linkDestination": "none" + "linkDestination": "none", + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-2.json b/test/integration/fixtures/blocks/core__gallery__deprecated-2.json index a60776801eb337..79a541b281f25e 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-2.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-2.json @@ -18,7 +18,8 @@ "alt": "title", "caption": "", "id": 1, - "linkDestination": "none" + "linkDestination": "none", + "enableLightbox": true }, "innerBlocks": [] }, @@ -30,7 +31,8 @@ "alt": "title", "caption": "", "id": 2, - "linkDestination": "none" + "linkDestination": "none", + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-3.json b/test/integration/fixtures/blocks/core__gallery__deprecated-3.json index 9ac2c197819ce5..f67ae86a2ae765 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-3.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-3.json @@ -16,7 +16,8 @@ "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", "alt": "title", "caption": "", - "linkDestination": "none" + "linkDestination": "none", + "enableLightbox": true }, "innerBlocks": [] }, @@ -27,7 +28,8 @@ "url": "data:image/jpeg;base64,/9j/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=", "alt": "title", "caption": "", - "linkDestination": "none" + "linkDestination": "none", + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-4.json b/test/integration/fixtures/blocks/core__gallery__deprecated-4.json index dad150cc96b48b..421a93789c4ee2 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-4.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-4.json @@ -18,7 +18,8 @@ "alt": "", "caption": "", "id": 1421, - "linkDestination": "none" + "linkDestination": "none", + "enableLightbox": true }, "innerBlocks": [] }, @@ -30,7 +31,8 @@ "alt": "", "caption": "", "id": 1440, - "linkDestination": "none" + "linkDestination": "none", + "enableLightbox": true }, "innerBlocks": [] }, @@ -42,7 +44,8 @@ "alt": "", "caption": "", "id": 1362, - "linkDestination": "none" + "linkDestination": "none", + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-5.json b/test/integration/fixtures/blocks/core__gallery__deprecated-5.json index 9ef1f03ba09349..4362765a1f1d61 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-5.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-5.json @@ -20,7 +20,8 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1-682x1024.jpg", "id": 705, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "enableLightbox": true }, "innerBlocks": [] }, @@ -34,7 +35,8 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1024x682.jpg", "id": 704, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "enableLightbox": true }, "innerBlocks": [] }, @@ -48,7 +50,8 @@ "href": "http://wptest.local/wp-content/uploads/2020/04/test-image-1024x683.jpg", "id": 703, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-6.json b/test/integration/fixtures/blocks/core__gallery__deprecated-6.json index 9ef1f03ba09349..4362765a1f1d61 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-6.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-6.json @@ -20,7 +20,8 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1-682x1024.jpg", "id": 705, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "enableLightbox": true }, "innerBlocks": [] }, @@ -34,7 +35,8 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1024x682.jpg", "id": 704, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "enableLightbox": true }, "innerBlocks": [] }, @@ -48,7 +50,8 @@ "href": "http://wptest.local/wp-content/uploads/2020/04/test-image-1024x683.jpg", "id": 703, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__gallery__deprecated-7.json b/test/integration/fixtures/blocks/core__gallery__deprecated-7.json index 4eaf85b46906d6..b82070ac95a208 100644 --- a/test/integration/fixtures/blocks/core__gallery__deprecated-7.json +++ b/test/integration/fixtures/blocks/core__gallery__deprecated-7.json @@ -24,7 +24,8 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1-682x1024.jpg", "id": 705, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "enableLightbox": true }, "innerBlocks": [] }, @@ -38,7 +39,8 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1024x682.jpg", "id": 704, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "enableLightbox": true }, "innerBlocks": [] }, @@ -52,7 +54,8 @@ "href": "http://wptest.local/wp-content/uploads/2020/04/test-image-1024x683.jpg", "id": 703, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "enableLightbox": true }, "innerBlocks": [] } @@ -83,7 +86,8 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1-682x1024.jpg", "id": 705, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "enableLightbox": true }, "innerBlocks": [] }, @@ -97,7 +101,8 @@ "href": "http://wptest.local/wp-content/uploads/2020/09/test-image-edited-1024x682.jpg", "id": 704, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "enableLightbox": true }, "innerBlocks": [] }, @@ -111,7 +116,8 @@ "href": "http://wptest.local/wp-content/uploads/2020/04/test-image-1024x683.jpg", "id": 703, "sizeSlug": "large", - "linkDestination": "media" + "linkDestination": "media", + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image.json b/test/integration/fixtures/blocks/core__image.json index 3da5557bb05cad..5c1567c390f2c3 100644 --- a/test/integration/fixtures/blocks/core__image.json +++ b/test/integration/fixtures/blocks/core__image.json @@ -5,7 +5,8 @@ "attributes": { "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", "alt": "", - "caption": "" + "caption": "", + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__attachment-link.json b/test/integration/fixtures/blocks/core__image__attachment-link.json index 055e4a61d2f383..c8392b8f423c67 100644 --- a/test/integration/fixtures/blocks/core__image__attachment-link.json +++ b/test/integration/fixtures/blocks/core__image__attachment-link.json @@ -7,7 +7,8 @@ "alt": "", "caption": "", "href": "http://localhost:8888/?attachment_id=7", - "linkDestination": "attachment" + "linkDestination": "attachment", + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__center-caption.json b/test/integration/fixtures/blocks/core__image__center-caption.json index a369e433b4028e..61bfc56aa75051 100644 --- a/test/integration/fixtures/blocks/core__image__center-caption.json +++ b/test/integration/fixtures/blocks/core__image__center-caption.json @@ -6,7 +6,8 @@ "align": "center", "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", "alt": "", - "caption": "Give it a try. Press the \"really wide\" button on the image toolbar." + "caption": "Give it a try. Press the \"really wide\" button on the image toolbar.", + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__custom-link-class.json b/test/integration/fixtures/blocks/core__image__custom-link-class.json index 2b5a36e78bdb8b..5604111146f05d 100644 --- a/test/integration/fixtures/blocks/core__image__custom-link-class.json +++ b/test/integration/fixtures/blocks/core__image__custom-link-class.json @@ -8,7 +8,8 @@ "caption": "", "href": "https://wordpress.org/", "linkClass": "custom-link", - "linkDestination": "custom" + "linkDestination": "custom", + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__custom-link-rel.json b/test/integration/fixtures/blocks/core__image__custom-link-rel.json index dc3a04a932c415..bd3f41b516f9f3 100644 --- a/test/integration/fixtures/blocks/core__image__custom-link-rel.json +++ b/test/integration/fixtures/blocks/core__image__custom-link-rel.json @@ -8,7 +8,8 @@ "caption": "", "href": "https://wordpress.org/", "rel": "external", - "linkDestination": "custom" + "linkDestination": "custom", + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__custom-link.json b/test/integration/fixtures/blocks/core__image__custom-link.json index 54cfa81f72b148..76c1ef98ab8d47 100644 --- a/test/integration/fixtures/blocks/core__image__custom-link.json +++ b/test/integration/fixtures/blocks/core__image__custom-link.json @@ -7,7 +7,8 @@ "alt": "", "caption": "", "href": "https://wordpress.org/", - "linkDestination": "custom" + "linkDestination": "custom", + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__deprecated-3.json b/test/integration/fixtures/blocks/core__image__deprecated-3.json index bae213510011ac..f6d4bdadd1b079 100644 --- a/test/integration/fixtures/blocks/core__image__deprecated-3.json +++ b/test/integration/fixtures/blocks/core__image__deprecated-3.json @@ -8,7 +8,8 @@ "alt": "", "caption": "", "width": 100, - "height": 100 + "height": 100, + "enableLightbox": true }, "innerBlocks": [] } diff --git a/test/integration/fixtures/blocks/core__image__media-link.json b/test/integration/fixtures/blocks/core__image__media-link.json index 0d411f713203de..90abcd4c55d8da 100644 --- a/test/integration/fixtures/blocks/core__image__media-link.json +++ b/test/integration/fixtures/blocks/core__image__media-link.json @@ -7,7 +7,8 @@ "alt": "", "caption": "", "href": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==", - "linkDestination": "media" + "linkDestination": "media", + "enableLightbox": true }, "innerBlocks": [] } From 4558d2921357b73cee8d577bac828e1e2fe69e8f Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Tue, 9 May 2023 11:39:00 +0200 Subject: [PATCH 087/125] Tests: Add e2e specs for Image block on the frontend --- test/e2e/specs/editor/blocks/image.spec.js | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/e2e/specs/editor/blocks/image.spec.js b/test/e2e/specs/editor/blocks/image.spec.js index 82a7e1ac71cce5..e85b06eab61d02 100644 --- a/test/e2e/specs/editor/blocks/image.spec.js +++ b/test/e2e/specs/editor/blocks/image.spec.js @@ -727,6 +727,32 @@ test.describe( 'Image', () => { new RegExp( filename ) ); } ); + + test.describe.only( 'Image - frontend interactivity', () => { + test.beforeEach( async ( { editor, imageBlockUtils, page } ) => { + await editor.insertBlock( { name: 'core/image' } ); + + const imageBlock = page.locator( + 'role=document[name="Block: Image"i]' + ); + await expect( imageBlock ).toBeVisible(); + + await imageBlockUtils.upload( + imageBlock.locator( 'data-testid=form-file-upload-input' ) + ); + + const image = imageBlock.locator( 'role=img' ); + await expect( image ).toBeVisible(); + + await editor.publishPost(); + } ); + + test( 'should open the image in a lightbox when clicked', async ( { + page, + } ) => { + await page.goto( '/' ); + } ); + } ); } ); class ImageBlockUtils { From 6629975699027ac3ef59aed78ca5106d00b2a50f Mon Sep 17 00:00:00 2001 From: Ricardo Artemio Morales Date: Wed, 10 May 2023 15:02:04 +0200 Subject: [PATCH 088/125] Disable lightbox by default --- packages/block-library/src/image/block.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/image/block.json b/packages/block-library/src/image/block.json index e3604c7b75bde6..5652b5ee82078b 100644 --- a/packages/block-library/src/image/block.json +++ b/packages/block-library/src/image/block.json @@ -86,7 +86,7 @@ }, "enableLightbox": { "type": "boolean", - "default": true + "default": false } }, "supports": { From 409941edefbd6fa3adf4e3e480c7dd42d4c948e6 Mon Sep 17 00:00:00 2001 From: Ricardo Artemio Morales Date: Wed, 10 May 2023 15:02:32 +0200 Subject: [PATCH 089/125] Add aria-role attribute to lightbox markup --- packages/block-library/src/image/index.php | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/block-library/src/image/index.php b/packages/block-library/src/image/index.php index b8f6628dacd568..805bcab1913696 100644 --- a/packages/block-library/src/image/index.php +++ b/packages/block-library/src/image/index.php @@ -54,6 +54,7 @@ function render_block_core_image( $attributes, $content ) { $content '; + $body_content = preg_replace('/]+>/', $button, $content); + + // For the modal, set an ID on the image to be used for an aria-labelledby attribute + $modal_content = new WP_HTML_Tag_Processor( $content ); + $modal_content->next_tag('img'); + $image_lightbox_id = $modal_content->get_attribute( 'class' ) . '-lightbox'; + $modal_content->set_attribute('id', $image_lightbox_id); + $modal_content = $modal_content->get_updated_html(); $background_color = wp_get_global_styles( array( 'color', 'background' ) ); $close_button_icon = ''; - $content = $processor->get_updated_html(); - return << - + $body_content diff --git a/packages/block-library/src/image/interactivity.js b/packages/block-library/src/image/interactivity.js index 54d271340785a9..665752061ced10 100644 --- a/packages/block-library/src/image/interactivity.js +++ b/packages/block-library/src/image/interactivity.js @@ -18,7 +18,7 @@ store( { window.document.activeElement; context.core.image.scrollPosition = window.scrollY; }, - hideLightbox: ( { context, event } ) => { + hideLightbox: async ( { context, event } ) => { if ( context.core.image.lightboxEnabled ) { // If scrolling, wait a moment before closing the lightbox. if ( @@ -31,32 +31,16 @@ store( { return; } context.core.image.lightboxEnabled = false; - - // We only want to focus the last focused element - // if the lightbox was closed by the keyboard. - // Note: Pressing Enter on a button will trigger - // a click event with a blank pointerType. - if ( - ( event.key && event.type === 'keydown' ) || - ( event.type === 'click' && - event.pointerType === '' ) - ) { - context.core.image.lastFocusedElement.focus(); - } + context.core.image.lastFocusedElement.focus(); } }, handleKeydown: ( { context, actions, event } ) => { if ( context.core.image.lightboxEnabled ) { - const isTabKeyPressed = - event.key === 'Tab' || event.keyCode === 9; - const escapeKeyPressed = - event.key === 'Escape' || event.keyCode === 27; - - if ( isTabKeyPressed ) { + if ( event.key === 'Tab' || event.keyCode === 9 ) { event.preventDefault(); } - if ( escapeKeyPressed || isTabKeyPressed ) { + if ( event.key === 'Escape' || event.keyCode === 27 ) { actions.core.image.hideLightbox( { context, event, diff --git a/packages/block-library/src/image/style.scss b/packages/block-library/src/image/style.scss index ddb420de63ea39..ab39a7f96e2984 100644 --- a/packages/block-library/src/image/style.scss +++ b/packages/block-library/src/image/style.scss @@ -153,10 +153,25 @@ } .wp-lightbox-container { + + .img-container { + position: relative; + } + button { border: none; background: none; cursor: zoom-in; + width: 100%; + height: 100%; + position: absolute; + z-index: 100; + + &:focus-visible { + outline: 5px auto #212121; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: 5px; + } } } @@ -187,6 +202,7 @@ height: 100%; z-index: 3000000; position: absolute; + flex-direction: column; } button { From f8aa92fff137526f4122f6063b0a5693b2004ec6 Mon Sep 17 00:00:00 2001 From: Ricardo Artemio Morales Date: Fri, 19 May 2023 06:39:01 +0200 Subject: [PATCH 093/125] Add focus trap --- .../block-library/src/image/interactivity.js | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/image/interactivity.js b/packages/block-library/src/image/interactivity.js index 665752061ced10..3adbd6d94ea8b1 100644 --- a/packages/block-library/src/image/interactivity.js +++ b/packages/block-library/src/image/interactivity.js @@ -7,6 +7,20 @@ const raf = window.requestAnimationFrame; // Until useSignalEffects is fixed: https://github.com/preactjs/signals/issues/228 const tick = () => new Promise( ( r ) => raf( () => raf( r ) ) ); +const focusableSelectors = [ + 'a[href]', + 'area[href]', + 'input:not([disabled]):not([type="hidden"]):not([aria-hidden])', + 'select:not([disabled]):not([aria-hidden])', + 'textarea:not([disabled]):not([aria-hidden])', + 'button:not([disabled]):not([aria-hidden])', + 'iframe', + 'object', + 'embed', + '[contenteditable]', + '[tabindex]:not([tabindex^="-"])', +]; + store( { actions: { core: { @@ -37,7 +51,23 @@ store( { handleKeydown: ( { context, actions, event } ) => { if ( context.core.image.lightboxEnabled ) { if ( event.key === 'Tab' || event.keyCode === 9 ) { - event.preventDefault(); + // If shift + tab it change the direction + if ( + event.shiftKey && + window.document.activeElement === + context.core.navigation + .firstFocusableElement + ) { + event.preventDefault(); + context.core.image.lastFocusableElement.focus(); + } else if ( + ! event.shiftKey && + window.document.activeElement === + context.core.image.lastFocusableElement + ) { + event.preventDefault(); + context.core.image.firstFocusableElement.focus(); + } } if ( event.key === 'Escape' || event.keyCode === 27 ) { @@ -60,6 +90,13 @@ store( { // to receive focus updates for accessibility await tick(); ref.querySelector( '.close-button' ).focus(); + + const focusableElements = + ref.querySelectorAll( focusableSelectors ); + context.core.image.firstFocusableElement = + focusableElements[ 0 ]; + context.core.image.lastFocusableElement = + focusableElements[ focusableElements.length - 1 ]; } }, }, From 5558e8d9a34cd3dfdcf3fde884318b1f08d429f5 Mon Sep 17 00:00:00 2001 From: Ricardo Artemio Morales Date: Fri, 19 May 2023 11:15:49 +0200 Subject: [PATCH 094/125] Label elements as 'inert' when lightbox is open --- packages/block-library/src/image/index.php | 2 + .../block-library/src/image/interactivity.js | 50 +++++++++++++++---- packages/block-library/src/image/style.scss | 4 ++ 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/packages/block-library/src/image/index.php b/packages/block-library/src/image/index.php index fefc25331aa603..8ddb2d4226e599 100644 --- a/packages/block-library/src/image/index.php +++ b/packages/block-library/src/image/index.php @@ -70,10 +70,12 @@ function render_block_core_image( $attributes, $content ) {