Skip to content

Commit ceaa2da

Browse files
authored
Search Block: Add border color support (#31783)
1 parent 90fd29e commit ceaa2da

File tree

3 files changed

+121
-52
lines changed

3 files changed

+121
-52
lines changed

packages/block-library/src/search/block.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
"supports": {
4343
"align": [ "left", "center", "right" ],
4444
"__experimentalBorder": {
45+
"color": true,
4546
"radius": true,
4647
"__experimentalSkipSerialization": true
4748
},

packages/block-library/src/search/edit.js

Lines changed: 57 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ export default function SearchEdit( {
7272
} = attributes;
7373

7474
const borderRadius = style?.border?.radius;
75+
const borderColor = style?.border?.color;
7576
const borderProps = useBorderProps( attributes );
7677

7778
// Check for old deprecated numerical border radius. Done as a separate
@@ -83,6 +84,10 @@ export default function SearchEdit( {
8384

8485
const unitControlInstanceId = useInstanceId( UnitControl );
8586
const unitControlInputId = `wp-block-search__width-${ unitControlInstanceId }`;
87+
const isButtonPositionInside = 'button-inside' === buttonPosition;
88+
const isButtonPositionOutside = 'button-outside' === buttonPosition;
89+
const hasNoButton = 'no-button' === buttonPosition;
90+
const hasOnlyButton = 'button-only' === buttonPosition;
8691

8792
const units = useCustomUnits( {
8893
availableUnits: [ '%', 'px' ],
@@ -92,22 +97,19 @@ export default function SearchEdit( {
9297
const getBlockClassNames = () => {
9398
return classnames(
9499
className,
95-
'button-inside' === buttonPosition
100+
! isButtonPositionInside ? borderProps.className : undefined,
101+
isButtonPositionInside
96102
? 'wp-block-search__button-inside'
97103
: undefined,
98-
'button-outside' === buttonPosition
104+
isButtonPositionOutside
99105
? 'wp-block-search__button-outside'
100106
: undefined,
101-
'no-button' === buttonPosition
102-
? 'wp-block-search__no-button'
103-
: undefined,
104-
'button-only' === buttonPosition
105-
? 'wp-block-search__button-only'
106-
: undefined,
107-
! buttonUseIcon && 'no-button' !== buttonPosition
107+
hasNoButton ? 'wp-block-search__no-button' : undefined,
108+
hasOnlyButton ? 'wp-block-search__button-only' : undefined,
109+
! buttonUseIcon && ! hasNoButton
108110
? 'wp-block-search__text-button'
109111
: undefined,
110-
buttonUseIcon && 'no-button' !== buttonPosition
112+
buttonUseIcon && ! hasNoButton
111113
? 'wp-block-search__icon-button'
112114
: undefined
113115
);
@@ -163,21 +165,30 @@ export default function SearchEdit( {
163165
};
164166

165167
const getResizableSides = () => {
166-
if ( 'button-only' === buttonPosition ) {
168+
if ( hasOnlyButton ) {
167169
return {};
168170
}
169171

170172
return {
171-
right: align === 'right' ? false : true,
172-
left: align === 'right' ? true : false,
173+
right: align !== 'right',
174+
left: align === 'right',
173175
};
174176
};
175177

176178
const renderTextField = () => {
179+
// If the input is inside the wrapper, the wrapper gets the border color styles/classes, not the input control.
180+
const textFieldClasses = classnames(
181+
'wp-block-search__input',
182+
isButtonPositionInside ? undefined : borderProps.className
183+
);
184+
const textFieldStyles = isButtonPositionInside
185+
? { borderRadius }
186+
: borderProps.style;
187+
177188
return (
178189
<input
179-
className="wp-block-search__input"
180-
style={ borderProps.style }
190+
className={ textFieldClasses }
191+
style={ textFieldStyles }
181192
aria-label={ __( 'Optional placeholder text' ) }
182193
// We hide the placeholder field's placeholder when there is a value. This
183194
// stops screen readers from reading the placeholder field's placeholder
@@ -194,20 +205,29 @@ export default function SearchEdit( {
194205
};
195206

196207
const renderButton = () => {
208+
// If the button is inside the wrapper, the wrapper gets the border color styles/classes, not the button.
209+
const buttonClasses = classnames(
210+
'wp-block-search__button',
211+
isButtonPositionInside ? undefined : borderProps.className
212+
);
213+
const buttonStyles = isButtonPositionInside
214+
? { borderRadius }
215+
: borderProps.style;
216+
197217
return (
198218
<>
199219
{ buttonUseIcon && (
200220
<Button
201221
icon={ search }
202-
className="wp-block-search__button"
203-
style={ borderProps.style }
222+
className={ buttonClasses }
223+
style={ buttonStyles }
204224
/>
205225
) }
206226

207227
{ ! buttonUseIcon && (
208228
<RichText
209-
className="wp-block-search__button"
210-
style={ borderProps.style }
229+
className={ buttonClasses }
230+
style={ buttonStyles }
211231
aria-label={ __( 'Button text' ) }
212232
placeholder={ __( 'Add button text…' ) }
213233
withoutInteractiveFormatting
@@ -240,7 +260,7 @@ export default function SearchEdit( {
240260
label={ __( 'Change button position' ) }
241261
controls={ buttonPositionControls }
242262
/>
243-
{ 'no-button' !== buttonPosition && (
263+
{ ! hasNoButton && (
244264
<ToolbarButton
245265
title={ __( 'Use button with icon' ) }
246266
icon={ buttonWithIcon }
@@ -329,13 +349,18 @@ export default function SearchEdit( {
329349
radius ? `calc(${ radius } + ${ DEFAULT_INNER_PADDING })` : undefined;
330350

331351
const getWrapperStyles = () => {
352+
const styles = {
353+
borderColor,
354+
};
355+
332356
const isNonZeroBorderRadius = parseInt( borderRadius, 10 ) !== 0;
333357

334-
if ( 'button-inside' === buttonPosition && isNonZeroBorderRadius ) {
358+
if ( isButtonPositionInside && isNonZeroBorderRadius ) {
335359
// We have button inside wrapper and a border radius value to apply.
336360
// Add default padding so we don't get "fat" corners.
337361
//
338-
// CSS calc() is used here to support non-pixel units.
362+
// CSS calc() is used here to support non-pixel units. The inline
363+
// style using calc() will only apply if both values have units.
339364

340365
if ( typeof borderRadius === 'object' ) {
341366
// Individual corner border radii present.
@@ -351,6 +376,7 @@ export default function SearchEdit( {
351376
borderTopRightRadius: padBorderRadius( topRight ),
352377
borderBottomLeftRadius: padBorderRadius( bottomLeft ),
353378
borderBottomRightRadius: padBorderRadius( bottomRight ),
379+
...styles,
354380
};
355381
}
356382

@@ -361,12 +387,10 @@ export default function SearchEdit( {
361387
? `${ borderRadius }px`
362388
: borderRadius;
363389

364-
return {
365-
borderRadius: `calc(${ radius } + ${ DEFAULT_INNER_PADDING })`,
366-
};
390+
styles.borderRadius = `calc(${ radius } + ${ DEFAULT_INNER_PADDING })`;
367391
}
368392

369-
return undefined;
393+
return styles;
370394
};
371395

372396
const blockProps = useBlockProps( {
@@ -392,7 +416,10 @@ export default function SearchEdit( {
392416
size={ {
393417
width: `${ width }${ widthUnit }`,
394418
} }
395-
className="wp-block-search__inside-wrapper"
419+
className={ classnames(
420+
'wp-block-search__inside-wrapper',
421+
isButtonPositionInside ? borderProps.className : undefined
422+
) }
396423
style={ getWrapperStyles() }
397424
minWidth={ MIN_WIDTH }
398425
enable={ getResizableSides() }
@@ -411,16 +438,15 @@ export default function SearchEdit( {
411438
} }
412439
showHandle={ isSelected }
413440
>
414-
{ ( 'button-inside' === buttonPosition ||
415-
'button-outside' === buttonPosition ) && (
441+
{ ( isButtonPositionInside || isButtonPositionOutside ) && (
416442
<>
417443
{ renderTextField() }
418444
{ renderButton() }
419445
</>
420446
) }
421447

422-
{ 'button-only' === buttonPosition && renderButton() }
423-
{ 'no-button' === buttonPosition && renderTextField() }
448+
{ hasOnlyButton && renderButton() }
449+
{ hasNoButton && renderTextField() }
424450
</ResizableBox>
425451
</div>
426452
);

packages/block-library/src/search/index.php

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,20 @@ function render_block_core_search( $attributes ) {
2727
)
2828
);
2929

30-
$input_id = 'wp-block-search__input-' . ++$instance_id;
31-
$classnames = classnames_for_block_core_search( $attributes );
32-
$show_label = ( ! empty( $attributes['showLabel'] ) ) ? true : false;
33-
$use_icon_button = ( ! empty( $attributes['buttonUseIcon'] ) ) ? true : false;
34-
$show_input = ( ! empty( $attributes['buttonPosition'] ) && 'button-only' === $attributes['buttonPosition'] ) ? false : true;
35-
$show_button = ( ! empty( $attributes['buttonPosition'] ) && 'no-button' === $attributes['buttonPosition'] ) ? false : true;
36-
$label_markup = '';
37-
$input_markup = '';
38-
$button_markup = '';
39-
$inline_styles = styles_for_block_core_search( $attributes );
30+
$input_id = 'wp-block-search__input-' . ++$instance_id;
31+
$classnames = classnames_for_block_core_search( $attributes );
32+
$show_label = ( ! empty( $attributes['showLabel'] ) ) ? true : false;
33+
$use_icon_button = ( ! empty( $attributes['buttonUseIcon'] ) ) ? true : false;
34+
$show_input = ( ! empty( $attributes['buttonPosition'] ) && 'button-only' === $attributes['buttonPosition'] ) ? false : true;
35+
$show_button = ( ! empty( $attributes['buttonPosition'] ) && 'no-button' === $attributes['buttonPosition'] ) ? false : true;
36+
$label_markup = '';
37+
$input_markup = '';
38+
$button_markup = '';
39+
$inline_styles = styles_for_block_core_search( $attributes );
40+
$is_button_inside = ! empty( $attributes['buttonPosition'] ) &&
41+
'button-inside' === $attributes['buttonPosition'];
42+
// Border color classes need to be applied to the elements that have a border color.
43+
$border_color_classes = get_border_color_classes_for_block_core_search( $attributes );
4044

4145
if ( $show_label ) {
4246
if ( ! empty( $attributes['label'] ) ) {
@@ -55,9 +59,11 @@ function render_block_core_search( $attributes ) {
5559
}
5660

5761
if ( $show_input ) {
58-
$input_markup = sprintf(
59-
'<input type="search" id="%s" class="wp-block-search__input" name="s" value="%s" placeholder="%s" %s required />',
62+
$input_classes = ! $is_button_inside ? $border_color_classes : '';
63+
$input_markup = sprintf(
64+
'<input type="search" id="%s" class="wp-block-search__input %s" name="s" value="%s" placeholder="%s" %s required />',
6065
$input_id,
66+
$input_classes,
6167
esc_attr( get_search_query() ),
6268
esc_attr( $attributes['placeholder'] ),
6369
$inline_styles['shared']
@@ -66,34 +72,36 @@ function render_block_core_search( $attributes ) {
6672

6773
if ( $show_button ) {
6874
$button_internal_markup = '';
69-
$button_classes = '';
75+
$button_classes = ! $is_button_inside ? $border_color_classes : '';
7076

7177
if ( ! $use_icon_button ) {
7278
if ( ! empty( $attributes['buttonText'] ) ) {
7379
$button_internal_markup = $attributes['buttonText'];
7480
}
7581
} else {
76-
$button_classes .= 'has-icon';
82+
$button_classes .= ' has-icon';
7783
$button_internal_markup =
7884
'<svg id="search-icon" class="search-icon" viewBox="0 0 24 24" width="24" height="24">
7985
<path d="M13.5 6C10.5 6 8 8.5 8 11.5c0 1.1.3 2.1.9 3l-3.4 3 1 1.1 3.4-2.9c1 .9 2.2 1.4 3.6 1.4 3 0 5.5-2.5 5.5-5.5C19 8.5 16.5 6 13.5 6zm0 9.5c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z"></path>
8086
</svg>';
8187
}
8288

8389
$button_markup = sprintf(
84-
'<button type="submit" class="wp-block-search__button %s"%s>%s</button>',
90+
'<button type="submit" class="wp-block-search__button %s" %s>%s</button>',
8591
$button_classes,
8692
$inline_styles['shared'],
8793
$button_internal_markup
8894
);
8995
}
9096

91-
$field_markup = sprintf(
92-
'<div class="wp-block-search__inside-wrapper"%s>%s</div>',
97+
$field_markup_classes = $is_button_inside ? $border_color_classes : '';
98+
$field_markup = sprintf(
99+
'<div class="wp-block-search__inside-wrapper %s" %s>%s</div>',
100+
$field_markup_classes,
93101
$inline_styles['wrapper'],
94102
$input_markup . $button_markup
95103
);
96-
$wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $classnames ) );
104+
$wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $classnames ) );
97105

98106
return sprintf(
99107
'<form role="search" method="get" action="%s" %s>%s</form>',
@@ -190,7 +198,8 @@ function styles_for_block_core_search( $attributes ) {
190198
if ( $has_border_radius ) {
191199
$default_padding = '4px';
192200
$border_radius = $attributes['style']['border']['radius'];
193-
$button_inside = ! empty( $attributes['buttonPosition'] ) &&
201+
// Apply wrapper border radius if button placed inside.
202+
$is_button_inside = ! empty( $attributes['buttonPosition'] ) &&
194203
'button-inside' === $attributes['buttonPosition'];
195204

196205
if ( is_array( $border_radius ) ) {
@@ -209,7 +218,7 @@ function styles_for_block_core_search( $attributes ) {
209218

210219
// Add adjusted border radius styles for the wrapper element
211220
// if button is positioned inside.
212-
if ( $button_inside && intval( $value ) !== 0 ) {
221+
if ( $is_button_inside && intval( $value ) !== 0 ) {
213222
$wrapper_styles[] = sprintf(
214223
'border-%s-radius: calc(%s + %s);',
215224
esc_attr( $name ),
@@ -224,7 +233,7 @@ function styles_for_block_core_search( $attributes ) {
224233
$border_radius = is_numeric( $border_radius ) ? $border_radius . 'px' : $border_radius;
225234
$shared_styles[] = sprintf( 'border-radius: %s;', esc_attr( $border_radius ) );
226235

227-
if ( $button_inside && intval( $border_radius ) !== 0 ) {
236+
if ( $is_button_inside && intval( $border_radius ) !== 0 ) {
228237
// Adjust wrapper border radii to maintain visual consistency
229238
// with inner elements when button is positioned inside.
230239
$wrapper_styles[] = sprintf(
@@ -236,8 +245,41 @@ function styles_for_block_core_search( $attributes ) {
236245
}
237246
}
238247

248+
// Add border color styles.
249+
$has_border_color = ! empty( $attributes['style']['border']['color'] );
250+
251+
if ( $has_border_color ) {
252+
$border_color = $attributes['style']['border']['color'];
253+
$is_button_inside = ! empty( $attributes['buttonPosition'] ) &&
254+
'button-inside' === $attributes['buttonPosition'];
255+
256+
// Apply wrapper border color if button placed inside.
257+
if ( $is_button_inside ) {
258+
$wrapper_styles[] = sprintf( 'border-color: %s;', esc_attr( $border_color ) );
259+
} else {
260+
$shared_styles[] = sprintf( 'border-color: %s;', esc_attr( $border_color ) );
261+
}
262+
}
263+
239264
return array(
240265
'shared' => ! empty( $shared_styles ) ? sprintf( ' style="%s"', implode( ' ', $shared_styles ) ) : '',
241266
'wrapper' => ! empty( $wrapper_styles ) ? sprintf( ' style="%s"', implode( ' ', $wrapper_styles ) ) : '',
242267
);
243268
}
269+
270+
/**
271+
* Returns border color classnames depending on whether there are named or custom border colors.
272+
*
273+
* @param array $attributes The block attributes.
274+
*
275+
* @return string The border color classnames to be applied to the block elements.
276+
*/
277+
function get_border_color_classes_for_block_core_search( $attributes ) {
278+
$has_custom_border_color = ! empty( $attributes['style']['border']['color'] );
279+
$border_color_classes = ! empty( $attributes['borderColor'] ) ? sprintf( 'has-border-color has-%s-border-color', $attributes['borderColor'] ) : '';
280+
// If there's a border color style and no `borderColor` text string, we still want to add the generic `has-border-color` class name to the element.
281+
if ( $has_custom_border_color && empty( $attributes['borderColor'] ) ) {
282+
$border_color_classes = 'has-border-color';
283+
}
284+
return $border_color_classes;
285+
}

0 commit comments

Comments
 (0)