Skip to content

Commit

Permalink
Search Block: add button only with expandable input (WordPress#50487)
Browse files Browse the repository at this point in the history
* Build docs.

* Fix lint errors.

* Fix php lint.

* Remove duplicate call to view script.

* List all dependencies in useEffect calls.

* Add isSearchFieldHidden and buttonBehavior attributes to fixtures.

* Allow input to expand on button focus and clean up CSS.

* Add hidden class on initial block rendering.

* Remove unneeded CSS.

* Allow focus and blur to toggle search field, and simplify logic.

* Handle keyboard navigation, event handling, and refactor.

* Escape to close input, and do not allow focus to expand invisible element.

* Add aria attributes to describe hidden / expanded states.

* Fix lint warnings.

* Fix php warnings.

* Add and remove relevant ARIA attributes when input state changes.

* Make strict comparison.

* Clean up aria and take input out of taborder by default.

* Fix label clicking behavior, remove unneeded event listeners.

* Fix comparison bug.

* Add and remove type and aria-label attributes to reflect form state.

* Fix conditional on useEffect to show input on width change.
  • Loading branch information
jffng authored and sethrubenstein committed Jul 13, 2023
1 parent b505b50 commit c0b3e90
Show file tree
Hide file tree
Showing 8 changed files with 215 additions and 29 deletions.
2 changes: 1 addition & 1 deletion docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,7 @@ Help visitors find your content. ([Source](https://github.com/WordPress/gutenber
- **Name:** core/search
- **Category:** widgets
- **Supports:** align (center, left, right), anchor, color (background, gradients, text), typography (fontSize, lineHeight), ~~html~~
- **Attributes:** buttonPosition, buttonText, buttonUseIcon, label, placeholder, query, showLabel, width, widthUnit
- **Attributes:** buttonBehavior, buttonPosition, buttonText, buttonUseIcon, isSearchFieldHidden, label, placeholder, query, showLabel, width, widthUnit

## Separator

Expand Down
8 changes: 8 additions & 0 deletions packages/block-library/src/search/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@
"query": {
"type": "object",
"default": {}
},
"buttonBehavior": {
"type": "string",
"default": "expand-searchfield"
},
"isSearchFieldHidden": {
"type": "boolean",
"default": false
}
},
"supports": {
Expand Down
64 changes: 61 additions & 3 deletions packages/block-library/src/search/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
useSetting,
} from '@wordpress/block-editor';
import { useDispatch, useSelect } from '@wordpress/data';
import { useEffect } from '@wordpress/element';
import { useEffect, useRef } from '@wordpress/element';
import {
ToolbarDropdownMenu,
ToolbarGroup,
Expand Down Expand Up @@ -59,6 +59,8 @@ import {
// button is placed inside wrapper.
const DEFAULT_INNER_PADDING = '4px';

const BUTTON_BEHAVIOR_EXPAND = 'expand-searchfield';

export default function SearchEdit( {
className,
attributes,
Expand All @@ -77,6 +79,8 @@ export default function SearchEdit( {
buttonText,
buttonPosition,
buttonUseIcon,
buttonBehavior,
isSearchFieldHidden,
style,
} = attributes;

Expand Down Expand Up @@ -130,12 +134,33 @@ export default function SearchEdit( {
const isButtonPositionOutside = 'button-outside' === buttonPosition;
const hasNoButton = 'no-button' === buttonPosition;
const hasOnlyButton = 'button-only' === buttonPosition;
const searchFieldRef = useRef();
const buttonRef = useRef();

const units = useCustomUnits( {
availableUnits: [ '%', 'px' ],
defaultValues: { '%': PC_WIDTH_DEFAULT, px: PX_WIDTH_DEFAULT },
} );

useEffect( () => {
if ( hasOnlyButton && ! isSelected ) {
setAttributes( {
isSearchFieldHidden: true,
} );
}
}, [ hasOnlyButton, isSelected, setAttributes ] );

// Show the search field when width changes.
useEffect( () => {
if ( ! hasOnlyButton || ! isSelected ) {
return;
}

setAttributes( {
isSearchFieldHidden: false,
} );
}, [ hasOnlyButton, isSelected, setAttributes, width ] );

const getBlockClassNames = () => {
return classnames(
className,
Expand All @@ -152,6 +177,12 @@ export default function SearchEdit( {
: undefined,
buttonUseIcon && ! hasNoButton
? 'wp-block-search__icon-button'
: undefined,
hasOnlyButton && BUTTON_BEHAVIOR_EXPAND === buttonBehavior
? 'wp-block-search__button-behavior-expand'
: undefined,
hasOnlyButton && isSearchFieldHidden
? 'wp-block-search__searchfield-hidden'
: undefined
);
};
Expand All @@ -165,6 +196,7 @@ export default function SearchEdit( {
onClick: () => {
setAttributes( {
buttonPosition: 'button-outside',
isSearchFieldHidden: false,
} );
},
},
Expand All @@ -176,6 +208,7 @@ export default function SearchEdit( {
onClick: () => {
setAttributes( {
buttonPosition: 'button-inside',
isSearchFieldHidden: false,
} );
},
},
Expand All @@ -187,6 +220,19 @@ export default function SearchEdit( {
onClick: () => {
setAttributes( {
buttonPosition: 'no-button',
isSearchFieldHidden: false,
} );
},
},
{
role: 'menuitemradio',
title: __( 'Button Only' ),
isActive: buttonPosition === 'button-only',
icon: buttonOnly,
onClick: () => {
setAttributes( {
buttonPosition: 'button-only',
isSearchFieldHidden: true,
} );
},
},
Expand Down Expand Up @@ -247,6 +293,7 @@ export default function SearchEdit( {
onChange={ ( event ) =>
setAttributes( { placeholder: event.target.value } )
}
ref={ searchFieldRef }
/>
);
};
Expand All @@ -268,6 +315,13 @@ export default function SearchEdit( {
? { borderRadius }
: borderProps.style ),
};
const handleButtonClick = () => {
if ( hasOnlyButton && BUTTON_BEHAVIOR_EXPAND === buttonBehavior ) {
setAttributes( {
isSearchFieldHidden: ! isSearchFieldHidden,
} );
}
};

return (
<>
Expand All @@ -281,6 +335,8 @@ export default function SearchEdit( {
? stripHTML( buttonText )
: __( 'Search' )
}
onClick={ handleButtonClick }
ref={ buttonRef }
>
<Icon icon={ search } />
</button>
Expand All @@ -297,6 +353,7 @@ export default function SearchEdit( {
onChange={ ( html ) =>
setAttributes( { buttonText: html } )
}
onClick={ handleButtonClick }
/>
) }
</>
Expand Down Expand Up @@ -516,14 +573,15 @@ export default function SearchEdit( {
} }
showHandle={ isSelected }
>
{ ( isButtonPositionInside || isButtonPositionOutside ) && (
{ ( isButtonPositionInside ||
isButtonPositionOutside ||
hasOnlyButton ) && (
<>
{ renderTextField() }
{ renderButton() }
</>
) }

{ hasOnlyButton && renderButton() }
{ hasNoButton && renderTextField() }
</ResizableBox>
</div>
Expand Down
57 changes: 34 additions & 23 deletions packages/block-library/src/search/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@ function render_block_core_search( $attributes ) {
$classnames = classnames_for_block_core_search( $attributes );
$show_label = ( ! empty( $attributes['showLabel'] ) ) ? true : false;
$use_icon_button = ( ! empty( $attributes['buttonUseIcon'] ) ) ? true : false;
$show_input = ( ! empty( $attributes['buttonPosition'] ) && 'button-only' === $attributes['buttonPosition'] ) ? false : true;
$show_button = ( ! empty( $attributes['buttonPosition'] ) && 'no-button' === $attributes['buttonPosition'] ) ? false : true;
$button_position = $show_button ? $attributes['buttonPosition'] : null;
$query_params = ( ! empty( $attributes['query'] ) ) ? $attributes['query'] : array();
$button_behavior = ( ! empty( $attributes['buttonBehavior'] ) ) ? $attributes['buttonBehavior'] : 'default';
$input_markup = '';
$button_markup = '';
$input_aria = '';
$button_aria = '';
$query_params_markup = '';
$inline_styles = styles_for_block_core_search( $attributes );
$color_classes = get_color_classes_for_block_core_search( $attributes );
Expand Down Expand Up @@ -64,24 +67,28 @@ function render_block_core_search( $attributes ) {
);
}

if ( $show_input ) {
$input_classes = array( 'wp-block-search__input' );
if ( ! $is_button_inside && ! empty( $border_color_classes ) ) {
$input_classes[] = $border_color_classes;
}
if ( ! empty( $typography_classes ) ) {
$input_classes[] = $typography_classes;
}
$input_markup = sprintf(
'<input type="search" id="%s" class="%s" name="s" value="%s" placeholder="%s" %s required />',
$input_id,
esc_attr( implode( ' ', $input_classes ) ),
get_search_query(),
esc_attr( $attributes['placeholder'] ),
$inline_styles['input']
);
if ( 'button-only' === $button_position && 'expand-searchfield' === $button_behavior ) {
$input_aria = 'aria-hidden="true" tabindex="-1"';
wp_enqueue_script( 'wp-block--search-view', plugins_url( 'search/view.min.js', __FILE__ ) );
}

$input_classes = array( 'wp-block-search__input' );
if ( ! $is_button_inside && ! empty( $border_color_classes ) ) {
$input_classes[] = $border_color_classes;
}
if ( ! empty( $typography_classes ) ) {
$input_classes[] = $typography_classes;
}
$input_markup = sprintf(
'<input type="search" id="%s" class="%s" name="s" value="%s" placeholder="%s" %s required %s/>',
$input_id,
esc_attr( implode( ' ', $input_classes ) ),
get_search_query(),
esc_attr( $attributes['placeholder'] ),
$inline_styles['input'],
$input_aria
);

if ( count( $query_params ) > 0 ) {
foreach ( $query_params as $param => $value ) {
$query_params_markup .= sprintf(
Expand All @@ -101,7 +108,6 @@ function render_block_core_search( $attributes ) {
if ( ! empty( $typography_classes ) ) {
$button_classes[] = $typography_classes;
}
$aria_label = '';

if ( ! $is_button_inside && ! empty( $border_color_classes ) ) {
$button_classes[] = $border_color_classes;
Expand All @@ -111,22 +117,25 @@ function render_block_core_search( $attributes ) {
$button_internal_markup = wp_kses_post( $attributes['buttonText'] );
}
} else {
$aria_label = sprintf( 'aria-label="%s"', esc_attr( wp_strip_all_tags( $attributes['buttonText'] ) ) );
$button_aria = sprintf( 'aria-label="%s"', esc_attr( wp_strip_all_tags( $attributes['buttonText'] ) ) );
$button_classes[] = 'has-icon';

$button_internal_markup =
'<svg class="search-icon" viewBox="0 0 24 24" width="24" height="24">
<path d="M13 5c-3.3 0-6 2.7-6 6 0 1.4.5 2.7 1.3 3.7l-3.8 3.8 1.1 1.1 3.8-3.8c1 .8 2.3 1.3 3.7 1.3 3.3 0 6-2.7 6-6S16.3 5 13 5zm0 10.5c-2.5 0-4.5-2-4.5-4.5s2-4.5 4.5-4.5 4.5 2 4.5 4.5-2 4.5-4.5 4.5z"></path>
</svg>';
}
if ( 'expand-searchfield' === $attributes['buttonBehavior'] ) {
$button_aria = sprintf( 'aria-label="%s" aria-expanded="false" aria-controls="wp-block-search__input-%s"', __( 'Expand search field' ), esc_attr( $input_id ) );
}

// Include the button element class.
$button_classes[] = wp_theme_get_element_class_name( 'button' );
$button_markup = sprintf(
'<button type="submit" class="%s" %s %s>%s</button>',
esc_attr( implode( ' ', $button_classes ) ),
$inline_styles['button'],
$aria_label,
$button_aria,
$button_internal_markup
);
}
Expand Down Expand Up @@ -188,6 +197,9 @@ function classnames_for_block_core_search( $attributes ) {

if ( 'button-only' === $attributes['buttonPosition'] ) {
$classnames[] = 'wp-block-search__button-only';
if ( ! empty( $attributes['buttonBehavior'] ) && 'expand-searchfield' === $attributes['buttonBehavior'] ) {
$classnames[] = 'wp-block-search__button-behavior-expand wp-block-search__searchfield-hidden';
}
}
}

Expand Down Expand Up @@ -294,10 +306,9 @@ function styles_for_block_core_search( $attributes ) {
$show_label = ( isset( $attributes['showLabel'] ) ) && false !== $attributes['showLabel'];

// Add width styles.
$has_width = ! empty( $attributes['width'] ) && ! empty( $attributes['widthUnit'] );
$button_only = ! empty( $attributes['buttonPosition'] ) && 'button-only' === $attributes['buttonPosition'];
$has_width = ! empty( $attributes['width'] ) && ! empty( $attributes['widthUnit'] );

if ( $has_width && ! $button_only ) {
if ( $has_width ) {
$wrapper_styles[] = sprintf(
'width: %d%s;',
esc_attr( $attributes['width'] ),
Expand Down
39 changes: 39 additions & 0 deletions packages/block-library/src/search/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,42 @@ $button-spacing-y: math.div($grid-unit-15, 2); // 6px
.wp-block-search.aligncenter .wp-block-search__inside-wrapper {
margin: auto;
}

.wp-block-search__button-behavior-expand {
.wp-block-search__inside-wrapper {
transition-property: width;
min-width: 0 !important;
}

.wp-block-search__input {
transition-duration: 300ms;
flex-basis: 100%;
}

// !important here to override inline styles on button only deselected view.
&.wp-block-search__searchfield-hidden {
overflow: hidden;

.wp-block-search__inside-wrapper {
overflow: hidden;
}

.wp-block-search__input {
width: 0 !important;
min-width: 0 !important;
padding-left: 0 !important;
padding-right: 0 !important;
border-left-width: 0 !important;
border-right-width: 0 !important;
flex-grow: 0;
margin: 0;
flex-basis: 0;
}
}
}

.wp-block[data-align="right"] .wp-block-search__button-behavior-expand {
.wp-block-search__inside-wrapper {
float: right;
}
}
Loading

0 comments on commit c0b3e90

Please sign in to comment.