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

Search block: switch interactivity to the Interactivity API #53343

Merged
merged 31 commits into from Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
1101255
Fist commit
cbravobernal Aug 4, 2023
2f84e4d
Come back to default style, as we updated wp-class directive
cbravobernal Aug 4, 2023
8093bb0
Remove not needed test
cbravobernal Aug 4, 2023
7028b57
Add interactions
cbravobernal Aug 4, 2023
f356798
Use `wp_store` to handle ARIA label
michalczaplinski Aug 9, 2023
462edb0
Move `FORM` directives directly to the HTML
SantosGuillamot Aug 9, 2023
99f681b
Move `aria-label` directive inside conditional
SantosGuillamot Aug 9, 2023
ff5eb0d
Change context variable name
SantosGuillamot Aug 9, 2023
d23428d
Add search button directives
SantosGuillamot Aug 9, 2023
80eaa0c
Add input directives and needed actions
SantosGuillamot Aug 9, 2023
afc0b70
Remove old functions
SantosGuillamot Aug 9, 2023
b75bd40
Load the search directives only if using Gutenberg
SantosGuillamot Aug 9, 2023
e9294a5
Change PHP formatting
SantosGuillamot Aug 9, 2023
39b1630
Fix PHP coding standard issues
SantosGuillamot Aug 9, 2023
6d01ab8
Remove trailing comma
SantosGuillamot Aug 9, 2023
347685f
Don't submit form when input is closed
SantosGuillamot Aug 9, 2023
00d1b4c
Focus button when closed with ESC key
SantosGuillamot Aug 9, 2023
3533cb0
Merge branch 'trunk' into experiment/move-search-block-interactivity
SantosGuillamot Aug 10, 2023
ab3fe06
Add selector in SSR
SantosGuillamot Aug 10, 2023
abb18f6
Format PHP
SantosGuillamot Aug 10, 2023
7d17805
Fix typo
SantosGuillamot Aug 11, 2023
262bca8
Add comment for `$open_by_default` variable
SantosGuillamot Aug 16, 2023
3f8bbdc
Merge branch 'trunk' into experiment/move-search-block-interactivity
SantosGuillamot Sep 4, 2023
ae7d054
Remove extra space
SantosGuillamot Sep 4, 2023
72426b0
Rename search block function
SantosGuillamot Sep 4, 2023
5a605d1
Add `supports.interactivity`
SantosGuillamot Sep 8, 2023
bf0938e
Remove old files and
SantosGuillamot Sep 8, 2023
128ae33
Add comment to manual SSR for core
SantosGuillamot Sep 11, 2023
a7686f6
Remove wp_store
SantosGuillamot Sep 11, 2023
e498b4c
Use `null` instead of `undefined
SantosGuillamot Sep 11, 2023
f040f3b
Remove unnecessary conditional
SantosGuillamot Sep 11, 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
93 changes: 85 additions & 8 deletions packages/block-library/src/search/index.php
Expand Up @@ -5,6 +5,24 @@
* @package WordPress
*/

if ( gutenberg_should_block_use_interactivity_api( 'core/search' ) ) {
/**
* Replaces view script for the File block with version using Interactivity API.
*
* @param array $metadata Block metadata as read in via block.json.
*
* @return array Filtered block type metadata.
*/
function gutenberg_block_core_search_update_interactive_view_script( $metadata ) {
if ( 'core/search' === $metadata['name'] ) {
$metadata['viewScript'] = array( 'file:./view-interactivity.min.js' );
$metadata['supports']['interactivity'] = true;
}
return $metadata;
}
add_filter( 'block_type_metadata', 'gutenberg_block_core_search_update_interactive_view_script', 10, 1 );
}

/**
* Dynamically renders the `core/search` block.
*
Expand Down Expand Up @@ -46,6 +64,7 @@ function render_block_core_search( $attributes, $content, $block ) {
'button-inside' === $attributes['buttonPosition'];
// Border color classes need to be applied to the elements that have a border color.
$border_color_classes = get_border_color_classes_for_block_core_search( $attributes );
$open_by_default = 'false';

$label_inner_html = empty( $attributes['label'] ) ? __( 'Search' ) : wp_kses_post( $attributes['label'] );
$label = new WP_HTML_Tag_Processor( sprintf( '<label %1$s>%2$s</label>', $inline_styles['label'], $label_inner_html ) );
Expand Down Expand Up @@ -77,8 +96,24 @@ function render_block_core_search( $attributes, $content, $block ) {

$is_expandable_searchfield = 'button-only' === $button_position && 'expand-searchfield' === $button_behavior;
if ( $is_expandable_searchfield ) {
$input->set_attribute( 'aria-hidden', 'true' );
$input->set_attribute( 'tabindex', '-1' );
if ( gutenberg_should_block_use_interactivity_api( 'core/search' ) ) {
wp_store(
array(
'selectors' => array(
'core' => array(
'search' => array(
'tabindex' => 'true' === $open_by_default ? '0' : '-1',
),
),
),
)
);
$input->set_attribute( 'data-wp-bind--aria-hidden', '!context.core.search.isSearchInputVisible' );
$input->set_attribute( 'data-wp-bind--tabindex', 'selectors.core.search.tabindex' );
} else {
$input->set_attribute( 'aria-hidden', 'true' );
$input->set_attribute( 'tabindex', '-1' );
}
}

// If the script already exists, there is no point in removing it from viewScript.
Expand Down Expand Up @@ -139,11 +174,42 @@ function render_block_core_search( $attributes, $content, $block ) {
if ( $button->next_tag() ) {
$button->add_class( implode( ' ', $button_classes ) );
if ( 'expand-searchfield' === $attributes['buttonBehavior'] && 'button-only' === $attributes['buttonPosition'] ) {
$button->set_attribute( 'aria-label', __( 'Expand search field' ) );
$button->set_attribute( 'data-toggled-aria-label', __( 'Submit Search' ) );
$button->set_attribute( 'aria-controls', 'wp-block-search__input-' . $input_id );
$button->set_attribute( 'aria-expanded', 'false' );
$button->set_attribute( 'type', 'button' ); // Will be set to submit after clicking.
if ( gutenberg_should_block_use_interactivity_api( 'core/search' ) ) {
$aria_label_expanded = __( 'Submit Search' );
$aria_label_collapsed = __( 'Expand search field' );
wp_store(
array(
'state' => array(
'core' => array(
'search' => array(
'ariaLabelCollapsed' => $aria_label_collapsed,
'ariaLabelExpanded' => $aria_label_expanded,
),
),
),
'selectors' => array(
'core' => array(
'search' => array(
'ariaLabel' => 'true' === $open_by_default ? $aria_label_expanded : $aria_label_collapsed,
'ariaControls' => 'true' === $open_by_default ? null : $input_id,
'type' => 'true' === $open_by_default ? 'submit' : 'button',
Copy link
Contributor

Choose a reason for hiding this comment

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

One thing's not clear to me:

If $open_by_default is hardcoded to be false on this line and never changed as far as I can see, then why do we still need those conditionals?

Copy link
Contributor

Choose a reason for hiding this comment

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

I added those conditionals so they follow the same logic we have in the client. I thought that this way, if for any reason we decide to change the $open_by_default in some scenarios, it is clear which attributes would be affected.

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, got it. For me, it was slightly confusing because the existence of the $open_by_default variable implies that there are cases when it's not open by default. Just a comment above this line mentioning that, for now, open_by_default is a constant should be enough to clarify that.

Copy link
Contributor

Choose a reason for hiding this comment

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

I just added a comment to reflect that 🙂

),
),
),
)
);
$button->set_attribute( 'data-wp-bind--aria-label', 'selectors.core.search.ariaLabel' );
$button->set_attribute( 'data-wp-bind--aria-controls', 'selectors.core.search.ariaControls' );
$button->set_attribute( 'data-wp-bind--aria-expanded', 'context.core.search.isSearchInputVisible' );
$button->set_attribute( 'data-wp-bind--type', 'selectors.core.search.type' );
$button->set_attribute( 'data-wp-on--click', 'actions.core.search.openSearchInput' );
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we need to specify selectors inside the wp_store call above so the directives using them are initialized. Have you been able to check if the SSRing output is correct?

Copy link
Contributor

Choose a reason for hiding this comment

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

You're right. I added the selectors in the SSR and moved it inside the conditional in this commit.

} else {
$button->set_attribute( 'aria-label', __( 'Expand search field' ) );
$button->set_attribute( 'data-toggled-aria-label', __( 'Submit Search' ) );
$button->set_attribute( 'aria-controls', 'wp-block-search__input-' . $input_id );
$button->set_attribute( 'aria-expanded', 'false' );
$button->set_attribute( 'type', 'button' ); // Will be set to submit after clicking.
}
} else {
$button->set_attribute( 'aria-label', wp_strip_all_tags( $attributes['buttonText'] ) );
}
Expand All @@ -160,11 +226,22 @@ function render_block_core_search( $attributes, $content, $block ) {
$wrapper_attributes = get_block_wrapper_attributes(
array( 'class' => $classnames )
);
$form_directives = '';
if ( gutenberg_should_block_use_interactivity_api( 'core/search' ) ) {
$form_directives = '
data-wp-interactive
data-wp-context=\'{ "core": { "search": { "isSearchInputVisible": ' . $open_by_default . ', "inputId": "' . $input_id . '" } } }\'
data-wp-class--wp-block-search__searchfield-hidden="!context.core.search.isSearchInputVisible"
data-wp-on--keydown="actions.core.search.handleSearchKeydown"
data-wp-on--focusout="actions.core.search.handleSearchFocusout"
';
};

return sprintf(
'<form role="search" method="get" action="%s" %s>%s</form>',
'<form role="search" method="get" action="%1s" %2s %3s>%4s</form>',
esc_url( home_url( '/' ) ),
$wrapper_attributes,
$form_directives,
$label . $field_markup
);
}
Expand Down
75 changes: 75 additions & 0 deletions packages/block-library/src/search/view-interactivity.js
@@ -0,0 +1,75 @@
/**
* WordPress dependencies
*/
import { store as wpStore } from '@wordpress/interactivity';

wpStore( {
selectors: {
core: {
search: {
ariaLabel: ( { state, context } ) => {
const { ariaLabelCollapsed, ariaLabelExpanded } =
state.core.search;
return context.core.search.isSearchInputVisible
? ariaLabelExpanded
: ariaLabelCollapsed;
},
ariaControls: ( { context } ) => {
return context.core.search.isSearchInputVisible
? undefined
: context.core.search.inputId;
},
type: ( { context } ) => {
return context.core.search.isSearchInputVisible
? 'submit'
: 'button';
},
tabindex: ( { context } ) => {
return context.core.search.isSearchInputVisible
? '0'
: '-1';
},
},
},
},
actions: {
core: {
search: {
openSearchInput: ( { context, event, ref } ) => {
if ( ! context.core.search.isSearchInputVisible ) {
event.preventDefault();
context.core.search.isSearchInputVisible = true;
ref.parentElement.querySelector( 'input' ).focus();
}
},
closeSearchInput: ( { context } ) => {
if ( context.core.search.isSearchInputVisible ) {
context.core.search.isSearchInputVisible = false;
}
},
handleSearchKeydown: ( store ) => {
const { actions, event, ref } = store;
// If Escape close the menu.
if ( event?.key === 'Escape' ) {
actions.core.search.closeSearchInput( store );
ref.querySelector( 'button' ).focus();
}
},
handleSearchFocusout: ( store ) => {
const { actions, event, ref } = store;
// If focus is outside search form, and in the document, close menu
// event.target === The element losing focus
// event.relatedTarget === The element receiving focus (if any)
// When focusout is outsite the document,
SantosGuillamot marked this conversation as resolved.
Show resolved Hide resolved
// `window.document.activeElement` doesn't change.
if (
! ref.contains( event.relatedTarget ) &&
event.target !== window.document.activeElement
) {
actions.core.search.closeSearchInput( store );
}
},
},
},
},
} );