{ isLoading && (
diff --git a/packages/block-library/src/navigation/style.scss b/packages/block-library/src/navigation/style.scss
index 842d84108e1930..ddb065f68aca93 100644
--- a/packages/block-library/src/navigation/style.scss
+++ b/packages/block-library/src/navigation/style.scss
@@ -18,3 +18,7 @@
.items-justified-right > ul {
justify-content: flex-end;
}
+
+.items-justified-space-between > ul {
+ justify-content: space-between;
+}
diff --git a/packages/block-library/src/paragraph/style.scss b/packages/block-library/src/paragraph/style.scss
index 87761b95ee1229..8a750a271cdd4e 100644
--- a/packages/block-library/src/paragraph/style.scss
+++ b/packages/block-library/src/paragraph/style.scss
@@ -35,3 +35,8 @@ p.has-background {
p.has-text-color a {
color: inherit;
}
+
+// Prevent an empty P tag from collapsing, so it matches the backend.
+p:empty::before {
+ content: "\200B";
+}
diff --git a/packages/block-library/src/spacer/editor.scss b/packages/block-library/src/spacer/editor.scss
index ae05db13812be2..66aa8ef55bb069 100644
--- a/packages/block-library/src/spacer/editor.scss
+++ b/packages/block-library/src/spacer/editor.scss
@@ -10,6 +10,7 @@
}
}
+.wp-block-spacer.is-hovered .block-library-spacer__resize-container,
.block-library-spacer__resize-container.has-show-handle {
background: rgba($black, 0.1);
diff --git a/packages/block-serialization-default-parser/parser.php b/packages/block-serialization-default-parser/parser.php
index ee73b1f071c4e7..27c85cfcd2ac2e 100644
--- a/packages/block-serialization-default-parser/parser.php
+++ b/packages/block-serialization-default-parser/parser.php
@@ -300,7 +300,7 @@ function proceed() {
*/
if ( 0 === $stack_depth ) {
if ( isset( $leading_html_start ) ) {
- $this->output[] = (array) self::freeform(
+ $this->output[] = (array) $this->freeform(
substr(
$this->document,
$leading_html_start,
@@ -492,7 +492,7 @@ function add_freeform( $length = null ) {
return;
}
- $this->output[] = (array) self::freeform( substr( $this->document, $this->offset, $length ) );
+ $this->output[] = (array) $this->freeform( substr( $this->document, $this->offset, $length ) );
}
/**
@@ -541,7 +541,7 @@ function add_block_from_stack( $end_offset = null ) {
}
if ( isset( $stack_top->leading_html_start ) ) {
- $this->output[] = (array) self::freeform(
+ $this->output[] = (array) $this->freeform(
substr(
$this->document,
$stack_top->leading_html_start,
diff --git a/packages/components/src/button/index.js b/packages/components/src/button/index.js
index 698c52e453b8a8..869f4279a99487 100644
--- a/packages/components/src/button/index.js
+++ b/packages/components/src/button/index.js
@@ -2,7 +2,7 @@
* External dependencies
*/
import classnames from 'classnames';
-import { isArray } from 'lodash';
+import { isArray, uniqueId } from 'lodash';
/**
* WordPress dependencies
@@ -15,6 +15,7 @@ import { forwardRef } from '@wordpress/element';
*/
import Tooltip from '../tooltip';
import Icon from '../icon';
+import VisuallyHidden from '../visually-hidden';
const disabledEventsOnDisabledButton = [ 'onMouseDown', 'onClick' ];
@@ -43,6 +44,7 @@ export function Button( props, ref ) {
children,
text,
__experimentalIsFocusable: isFocusable,
+ describedBy,
...additionalProps
} = props;
@@ -104,12 +106,18 @@ export function Button( props, ref ) {
// the tooltip is not explicitly disabled.
false !== showTooltip ) );
+ const descriptionId = describedBy ? uniqueId() : null;
+
+ const describedById =
+ additionalProps[ 'aria-describedby' ] || descriptionId;
+
const element = (
{ icon && iconPosition === 'left' && (
@@ -124,17 +132,33 @@ export function Button( props, ref ) {
);
if ( ! shouldShowTooltip ) {
- return element;
+ return (
+ <>
+ { element }
+ { describedBy && (
+
+ { describedBy }
+
+ ) }
+ >
+ );
}
return (
-
- { element }
-
+ <>
+
+ { element }
+
+ { describedBy && (
+
+ { describedBy }
+
+ ) }
+ >
);
}
diff --git a/packages/components/src/button/style.scss b/packages/components/src/button/style.scss
index e7165338fe6ee4..f578a1b7beebe0 100644
--- a/packages/components/src/button/style.scss
+++ b/packages/components/src/button/style.scss
@@ -298,6 +298,8 @@
.dashicon {
display: inline-block;
flex: 0 0 auto;
+ margin-left: 2px;
+ margin-right: 10px;
}
&.has-text {
diff --git a/packages/components/src/button/test/index.js b/packages/components/src/button/test/index.js
index 49de9ef1d59ad2..de027bbe41fed8 100644
--- a/packages/components/src/button/test/index.js
+++ b/packages/components/src/button/test/index.js
@@ -3,7 +3,6 @@
*/
import { shallow } from 'enzyme';
import TestUtils from 'react-dom/test-utils';
-
/**
* WordPress dependencies
*/
@@ -18,7 +17,7 @@ import ButtonWithForwardedRef, { Button } from '../';
describe( 'Button', () => {
describe( 'basic rendering', () => {
it( 'should render a button element with only one class', () => {
- const button = shallow( );
+ const button = shallow( ).find( 'button' );
expect( button.hasClass( 'components-button' ) ).toBe( true );
expect( button.hasClass( 'is-large' ) ).toBe( false );
expect( button.hasClass( 'is-primary' ) ).toBe( false );
@@ -30,13 +29,15 @@ describe( 'Button', () => {
} );
it( 'should render a button element with is-primary class', () => {
- const button = shallow( );
+ const button = shallow( ).find( 'button' );
expect( button.hasClass( 'is-large' ) ).toBe( false );
expect( button.hasClass( 'is-primary' ) ).toBe( true );
} );
it( 'should render a button element with is-small class', () => {
- const button = shallow( );
+ const button = shallow( ).find(
+ 'button'
+ );
expect( button.hasClass( 'is-secondary' ) ).toBe( true );
expect( button.hasClass( 'is-large' ) ).toBe( false );
expect( button.hasClass( 'is-small' ) ).toBe( true );
@@ -44,48 +45,58 @@ describe( 'Button', () => {
} );
it( 'should render a button element with is-pressed without button class', () => {
- const button = shallow( );
+ const button = shallow( ).find( 'button' );
expect( button.hasClass( 'is-pressed' ) ).toBe( true );
} );
it( 'should add a disabled prop to the button', () => {
- const button = shallow( );
+ const button = shallow( ).find( 'button' );
expect( button.prop( 'disabled' ) ).toBe( true );
} );
it( 'should add only aria-disabled attribute when disabled and isFocusable are true', () => {
const button = shallow(
- );
+ ).find( 'button' );
expect( button.prop( 'disabled' ) ).toBe( false );
expect( button.prop( 'aria-disabled' ) ).toBe( true );
} );
it( 'should not poss the prop target into the element', () => {
- const button = shallow( );
+ const button = shallow( ).find(
+ 'button'
+ );
expect( button.prop( 'target' ) ).toBeUndefined();
} );
it( 'should render with an additional className', () => {
- const button = shallow( );
+ const button = shallow( ).find(
+ 'button'
+ );
expect( button.hasClass( 'gutenberg' ) ).toBe( true );
} );
it( 'should render and additional WordPress prop of value awesome', () => {
- const button = shallow( );
+ const button = shallow( ).find(
+ 'button'
+ );
expect( button.prop( 'WordPress' ) ).toBe( 'awesome' );
} );
it( 'should render an icon button', () => {
- const iconButton = shallow( );
+ const iconButton = shallow( ).find(
+ 'button'
+ );
expect( iconButton.hasClass( 'has-icon' ) ).toBe( true );
expect( iconButton.prop( 'aria-label' ) ).toBeUndefined();
} );
it( 'should render a Dashicon component matching the wordpress icon', () => {
- const iconButton = shallow( );
+ const iconButton = shallow( ).find(
+ 'button'
+ );
expect( iconButton.find( 'Icon' ).dive() ).not.toBeNull();
} );
@@ -95,7 +106,7 @@ describe( 'Button', () => {
icon={ plusCircle }
children={ Test
}
/>
- );
+ ).find( 'button' );
expect( iconButton.find( 'Icon' ).dive() ).not.toBeNull();
expect( iconButton.find( '.test' ).shallow().text() ).toBe(
'Test'
@@ -105,7 +116,7 @@ describe( 'Button', () => {
it( 'should add an aria-label when the label property is used, with Tooltip wrapper', () => {
const iconButton = shallow(
- );
+ ).find( 'Tooltip' );
expect( iconButton.name() ).toBe( 'Tooltip' );
expect( iconButton.prop( 'text' ) ).toBe( 'WordPress' );
expect( iconButton.find( 'button' ).prop( 'aria-label' ) ).toBe(
@@ -114,10 +125,34 @@ describe( 'Button', () => {
} );
it( 'should support explicit aria-label override', () => {
- const iconButton = shallow( );
+ const iconButton = shallow( ).find(
+ 'button'
+ );
expect( iconButton.prop( 'aria-label' ) ).toBe( 'Custom' );
} );
+ it( 'should support adding aria-describedby text', () => {
+ const buttonDescription = shallow(
+
+ )
+ .find( 'VisuallyHidden' )
+ .shallow()
+ .text();
+ expect( buttonDescription ).toBe( 'Description text' );
+ } );
+
+ it( 'should populate tooltip with describedBy content', () => {
+ const buttonTooltip = shallow(
+
+ ).find( 'Tooltip' );
+
+ expect( buttonTooltip.prop( 'text' ) ).toBe( 'Description text' );
+ } );
+
it( 'should allow tooltip disable', () => {
const iconButton = shallow(