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
Changes from 20 commits
1101255
2f84e4d
8093bb0
7028b57
f356798
462edb0
99f681b
ff5eb0d
d23428d
80eaa0c
afc0b70
b75bd40
e9294a5
39b1630
6d01ab8
347685f
00d1b4c
3533cb0
ab3fe06
abb18f6
7d17805
262bca8
3f8bbdc
ae7d054
72426b0
5a605d1
bf0938e
128ae33
a7686f6
e498b4c
f040f3b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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. | ||
* | ||
|
@@ -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 ) ); | ||
|
@@ -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. | ||
|
@@ -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', | ||
), | ||
), | ||
), | ||
) | ||
); | ||
$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' ); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we need to specify There was a problem hiding this comment. Choose a reason for hiding this commentThe 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'] ) ); | ||
} | ||
|
@@ -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 | ||
); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 ); | ||
} | ||
}, | ||
}, | ||
}, | ||
}, | ||
} ); |
There was a problem hiding this comment.
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 befalse
on this line and never changed as far as I can see, then why do we still need those conditionals?There was a problem hiding this comment.
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.There was a problem hiding this comment.
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.There was a problem hiding this comment.
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 🙂