Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Behaviors UI #49972

Merged
merged 61 commits into from
May 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
bd53de2
Add behaviors to the core theme.json
michalczaplinski Apr 21, 2023
bd43bf6
Add behaviors to json schemas for theme.json
michalczaplinski Apr 21, 2023
e1dd737
Add a behaviors panel
michalczaplinski May 3, 2023
8b84a22
Remove the changes to theme.json schema
michalczaplinski May 5, 2023
d5dbc1c
Add behaviors to the VALID_SETTINGS in class-wp-theme-json-gutenberg.php
michalczaplinski May 5, 2023
037d669
Add the first (still broken) version of the lightbox settings
michalczaplinski May 5, 2023
8f62d34
WIP: Added a SelectControl for the behaviors
michalczaplinski May 9, 2023
62b6217
Format PHP
michalczaplinski May 9, 2023
edfd7d1
Format correctly again
michalczaplinski May 9, 2023
8ee4065
Use the props.name when getting the behaviors
michalczaplinski May 10, 2023
594224b
Add initial e2e tests
cbravobernal May 10, 2023
fd6fe36
Update the withBehaviors description
michalczaplinski May 10, 2023
da4a5ad
Cleaned up behaviors.js
michalczaplinski May 11, 2023
2958fd1
Update e2e tests to check visibility
cbravobernal May 12, 2023
0a68bea
Update core-blocks doc with behaviors attribute
cbravobernal May 12, 2023
fd08928
Update fixtures with new lightbox attribute
cbravobernal May 13, 2023
4e03e0d
Add a new theme for e2e tests
michalczaplinski May 16, 2023
92b6e6c
Change theme.json to include `settings.behaviors`
michalczaplinski May 16, 2023
ffa881e
Remove default behavior value from block.json
michalczaplinski May 16, 2023
99c964b
Minor fix to the implementation
michalczaplinski May 16, 2023
7f7db2c
Add more e2e tests
michalczaplinski May 16, 2023
5e5ff9a
Create a selector for behaviors
michalczaplinski May 17, 2023
ad20b64
Add a filter to load behaviors on the server from the theme.json
michalczaplinski May 17, 2023
d16266b
Add behaviors on the top-level in core theme.json
michalczaplinski May 17, 2023
0982d9f
Use the behaviors in the hooks
michalczaplinski May 17, 2023
0ef7b5e
Update the comment
michalczaplinski May 17, 2023
e75fd87
Update the comment in behaviors.js
michalczaplinski May 17, 2023
f6414f9
Update fixtures and e2e
cbravobernal May 17, 2023
31c0623
Prevent mobile test gutenberg error (temporary - not the best solution)
cbravobernal May 18, 2023
ee3701f
Add priority on filter
cbravobernal May 18, 2023
a0ac748
Fix php standards
cbravobernal May 18, 2023
1dd6df1
Found a much better way to fix php tests
cbravobernal May 18, 2023
a737200
Small refactor
cbravobernal May 18, 2023
3fd9270
Add `behaviors` as an allowed key to BLOCK_EDITOR_SETTINGS
michalczaplinski May 18, 2023
5a9748c
Move the behaviors to top level in the e2e test theme.json file
michalczaplinski May 18, 2023
9a6b1f2
Rename the `behaviors` setting to `behaviorsUIEnabled`
michalczaplinski May 18, 2023
1c7f6d5
Change "None" to "No behaviors"
michalczaplinski May 18, 2023
470f74f
Behaviors -> behavior
michalczaplinski May 18, 2023
bba7c2d
Fix redundant ternary
michalczaplinski May 18, 2023
2cb348c
Improve the JSDoc for behaviors selector
michalczaplinski May 18, 2023
c65bc57
Rename the test themes to make more sense
michalczaplinski May 19, 2023
1c655f7
Remove definition of `behaviors` attribute in core/image
michalczaplinski May 22, 2023
697c04f
Change default value for `behaviors.lightbox` to false and update e2e…
michalczaplinski May 22, 2023
d4fd9d9
Change the way we get the data from `theme.json` and adjust e2e
michalczaplinski May 23, 2023
a57d634
Capitalize behaviors' labels
michalczaplinski May 23, 2023
234a8b6
Move PHP code adding `theme.json` behaviors to `block-editor-settings`
michalczaplinski May 23, 2023
4bef633
Update comment
michalczaplinski May 23, 2023
7aa7231
Remove the behaviors require from load.php
michalczaplinski May 23, 2023
1d923ab
Revert "Update comment"
michalczaplinski May 23, 2023
aee908a
Revert "Move PHP code adding `theme.json` behaviors to `block-editor-…
michalczaplinski May 23, 2023
33cb62d
Remove the comment that was added previously
michalczaplinski May 23, 2023
55e37a3
Update comments in `behaviors.php`
michalczaplinski May 23, 2023
d4d657b
Add back the require_once in load.php
michalczaplinski May 23, 2023
8d6b0d0
Use `settings.blocks.core/image.behaviors.lightbox`
michalczaplinski May 23, 2023
76b2a75
Use `behaviors.blocks.core/image.lightbox`
michalczaplinski May 23, 2023
70e51cd
Remove experimental setting for interactivity API
cbravobernal May 24, 2023
69ebe6c
Revert "Remove experimental setting for interactivity API"
cbravobernal May 24, 2023
c32be86
Move `interactivity.js` files to `block.json`
SantosGuillamot May 24, 2023
b8dc7dd
Remove experimental flag for the Interactivity API
SantosGuillamot May 24, 2023
4800d91
Revert "Move `interactivity.js` files to `block.json`"
michalczaplinski May 24, 2023
9124b58
Revert "Remove experimental flag for the Interactivity API"
michalczaplinski May 24, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
michalczaplinski marked this conversation as resolved.
Show resolved Hide resolved

## Latest Comments

Expand Down
23 changes: 23 additions & 0 deletions docs/reference-guides/data/data-core-block-editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,29 @@ _Returns_

- `Array?`: The list of allowed block types.

### getBehaviors

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_

- _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.
Expand Down
2 changes: 2 additions & 0 deletions lib/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ class WP_Theme_JSON_Gutenberg {
'templateParts',
'title',
'version',
'behaviors',
);

/**
Expand Down Expand Up @@ -404,6 +405,7 @@ class WP_Theme_JSON_Gutenberg {
'textDecoration' => null,
'textTransform' => null,
),
'behaviors' => null,
);

/**
Expand Down
20 changes: 20 additions & 0 deletions lib/compat/wordpress-6.3/behaviors.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
/**
* Behaviors.
*
* Updates the block editor settings with the theme's behaviors.
*
* @package gutenberg
*/

add_filter(
'block_editor_settings_all',
function( $settings ) {
$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;
},
PHP_INT_MAX
michalczaplinski marked this conversation as resolved.
Show resolved Hide resolved
);
2 changes: 1 addition & 1 deletion lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -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' ) ) {
Expand Down Expand Up @@ -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';

12 changes: 12 additions & 0 deletions lib/theme.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
{
"version": 2,
"behaviors": {
"blocks": {
"core/image": {
"lightbox": false
}
}
},
"settings": {
"appearanceTools": false,
"useRootPaddingAwareAlignments": false,
Expand Down Expand Up @@ -450,6 +457,11 @@
"style": true,
"width": true
}
},
"core/image": {
"behaviors": {
"lightbox": true
}
}
}
},
Expand Down
21 changes: 18 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/block-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
104 changes: 104 additions & 0 deletions packages/block-editor/src/hooks/behaviors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/**
* WordPress dependencies
*/
import { addFilter } from '@wordpress/hooks';
import { SelectControl } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { createHigherOrderComponent } from '@wordpress/compose';
import { select } from '@wordpress/data';

/**
* Internal dependencies
*/
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.
*
* Currently, only the `core/image` block is supported.
*
* @param {WPComponent} BlockEdit Original component.
*
* @return {WPComponent} Wrapped component.
*/
export const withBehaviors = createHigherOrderComponent( ( BlockEdit ) => {
return ( props ) => {
// Only add behaviors to the core/image block.
if ( props.name !== 'core/image' ) {
return <BlockEdit { ...props } />;
}

const settings =
select( blockEditorStore ).getSettings()?.__experimentalFeatures
?.blocks?.[ props.name ]?.behaviors;

if (
! settings ||
// If every behavior is disabled, do not show the behaviors inspector control.
Object.entries( settings ).every( ( [ , value ] ) => ! value )
) {
return <BlockEdit { ...props } />;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a subtile issue that may or may not result in a bug. The fact that we conditionally render BlockEdit can result in a "remount" of the whole component if the condition above changes from "true" to "false" or the opposite.

The remount often create focus loss and issues like that. While this might not always be a problem, it is a problem in general if the condition "can" change when the component is mounted (I'm not sure it's the case here)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That conditional is reading a theme.json value. I don't think that condition can change without a page reload 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, probably fine for now, just something to know as sometimes we used to switch over attribute values (easy to add a check there). Also, maybe at some point in the future, that setting could be editable in the global styles UI in the site editor.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that setting could be editable in the global styles UI in the site editor

That is the next step after merging this PR, so we should then take a look at this issue.


const { behaviors: blockBehaviors } = props.attributes;

// Get the theme behaviors for the block from the theme.json.
const themeBehaviors =
select( blockEditorStore ).getBehaviors()?.blocks?.[ props.name ];

// Block behaviors take precedence over theme behaviors.
const behaviors = merge( themeBehaviors, blockBehaviors || {} );

return (
<>
<BlockEdit { ...props } />
<InspectorControls group="advanced">
<SelectControl
__nextHasNoMarginBottom
label={ __( 'Behaviors' ) }
// At the moment we are only supporting one behavior (Lightbox)
value={ behaviors?.lightbox ? 'lightbox' : '' }
options={ Object.entries( settings )
.filter( ( [ , behaviorValue ] ) => behaviorValue ) // Filter out behaviors that are disabled.
.map( ( [ behaviorName ] ) => ( {
value: behaviorName,
label:
// Capitalize the first letter of the behavior name.
behaviorName[ 0 ].toUpperCase() +
behaviorName.slice( 1 ).toLowerCase(),
} ) )
.concat( {
value: '',
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 === 'lightbox',
},
} );
} }
hideCancelButton={ true }
help={ __( 'Add behaviors' ) }
size="__unstable-large"
/>
</InspectorControls>
</>
);
};
}, 'withBehaviors' );

addFilter(
'editor.BlockEdit',
'core/behaviors/with-inspector-control',
withBehaviors
);
1 change: 1 addition & 0 deletions packages/block-editor/src/hooks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down
24 changes: 24 additions & 0 deletions packages/block-editor/src/store/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -2490,6 +2490,30 @@ export function getSettings( state ) {
return state.settings;
}

/**
* 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.
*
* @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
Expand Down
3 changes: 3 additions & 0 deletions packages/block-library/src/image/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@
"source": "attribute",
"selector": "figure > a",
"attribute": "target"
},
"behaviors": {
"type": "object"
michalczaplinski marked this conversation as resolved.
Show resolved Hide resolved
}
},
"supports": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ const BLOCK_EDITOR_SETTINGS = [
'__unstableIsPreviewMode',
'__unstableResolvedAssets',
'__unstableIsBlockBasedTheme',
'behaviors',
];

/**
Expand Down