diff --git a/docs/designers-developers/developers/data/data-core-block-editor.md b/docs/designers-developers/developers/data/data-core-block-editor.md
index 588b1f27e32499..e69090f3c6503f 100644
--- a/docs/designers-developers/developers/data/data-core-block-editor.md
+++ b/docs/designers-developers/developers/data/data-core-block-editor.md
@@ -32,6 +32,20 @@ _Returns_
- `boolean`: Whether the last change was automatic.
+# **getAccessibleBlockLabel**
+
+Get a label for the block for use by screenreaders, this can include the block title, the
+position of the block, and the value of the `getAccessibilityLabel` function if it's specified.
+
+_Parameters_
+
+- _state_ `Object`: Store state.
+- _clientId_ `string`: ClientId for the block.
+
+_Returns_
+
+- `string`: The accessibility label for the block.
+
# **getAdjacentBlockClientId**
Returns the client ID of the block adjacent one at the given reference
@@ -133,6 +147,20 @@ _Returns_
- `Object`: Insertion point object with `rootClientId`, `index`.
+# **getBlockLabel**
+
+Get the label for the block, usually this is either the block title,
+or the value of the attribute denoted by the block's `label` property.
+
+_Parameters_
+
+- _state_ `Object`: Store state.
+- _clientId_ `string`: ClientId for the block.
+
+_Returns_
+
+- `string`: The block label.
+
# **getBlockListSettings**
Returns the Block List settings of a block, if any exist.
diff --git a/packages/block-editor/src/components/block-list/block-popover.js b/packages/block-editor/src/components/block-list/block-popover.js
index 2a70b80c2dafa6..9be114b7a0ff78 100644
--- a/packages/block-editor/src/components/block-list/block-popover.js
+++ b/packages/block-editor/src/components/block-list/block-popover.js
@@ -206,8 +206,6 @@ function BlockPopover( {
{ shouldShowBreadcrumb && (
) }
diff --git a/packages/block-editor/src/components/block-list/block.native.js b/packages/block-editor/src/components/block-list/block.native.js
index 6a165a59aee5d8..755499674abc23 100644
--- a/packages/block-editor/src/components/block-list/block.native.js
+++ b/packages/block-editor/src/components/block-list/block.native.js
@@ -13,7 +13,6 @@ import { compose, withPreferredColorScheme } from '@wordpress/compose';
import {
getBlockType,
getUnregisteredTypeHandlerName,
- __experimentalGetAccessibleBlockLabel as getAccessibleBlockLabel,
} from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
@@ -194,25 +193,17 @@ class BlockListBlock extends Component {
render() {
const {
- attributes,
- blockType,
+ accessibilityLabel,
clientId,
icon,
isSelected,
isValid,
- order,
title,
showFloatingToolbar,
parentId,
isTouchable,
} = this.props;
- const accessibilityLabel = getAccessibleBlockLabel(
- blockType,
- attributes,
- order + 1
- );
-
return (
<>
{ showFloatingToolbar && (
@@ -263,6 +254,7 @@ class BlockListBlock extends Component {
export default compose( [
withSelect( ( select, { clientId, rootClientId } ) => {
const {
+ getAccessibleBlockLabel,
getBlockIndex,
isBlockSelected,
__unstableGetBlockWithoutInnerBlocks,
@@ -281,7 +273,7 @@ export default compose( [
const isSelected = isBlockSelected( clientId );
const isLastBlock = order === getBlockCount( rootClientId ) - 1;
const block = __unstableGetBlockWithoutInnerBlocks( clientId );
- const { name, attributes, isValid } = block || {};
+ const { name, isValid } = block || {};
const isUnregisteredBlock = name === getUnregisteredTypeHandlerName();
const blockType = getBlockType( name || 'core/missing' );
@@ -341,13 +333,13 @@ export default compose( [
const isRootListInnerBlockHolder =
! isSelectedBlockNested && isInnerBlockHolder;
+ const accessibilityLabel = getAccessibleBlockLabel( clientId );
+
return {
icon,
name: name || 'core/missing',
- order,
+ accessibilityLabel,
title,
- attributes,
- blockType,
isLastBlock,
isSelected,
isValid,
diff --git a/packages/block-editor/src/components/block-list/breadcrumb.js b/packages/block-editor/src/components/block-list/breadcrumb.js
index a47db75152663e..5c2af840e9653b 100644
--- a/packages/block-editor/src/components/block-list/breadcrumb.js
+++ b/packages/block-editor/src/components/block-list/breadcrumb.js
@@ -5,10 +5,6 @@ import { Toolbar, Button } from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
import { useEffect, useRef } from '@wordpress/element';
import { BACKSPACE, DELETE } from '@wordpress/keycodes';
-import {
- getBlockType,
- __experimentalGetAccessibleBlockLabel as getAccessibleBlockLabel,
-} from '@wordpress/blocks';
/**
* Internal dependencies
@@ -25,27 +21,12 @@ import BlockTitle from '../block-title';
*
* @return {WPComponent} The component to be rendered.
*/
-function BlockBreadcrumb( {
- clientId,
- rootClientId,
- moverDirection,
- ...props
-} ) {
- const selected = useSelect(
- ( select ) => {
- const {
- __unstableGetBlockWithoutInnerBlocks,
- getBlockIndex,
- } = select( 'core/block-editor' );
- const index = getBlockIndex( clientId, rootClientId );
- const { name, attributes } = __unstableGetBlockWithoutInnerBlocks(
- clientId
- );
- return { index, name, attributes };
- },
- [ clientId, rootClientId ]
+function BlockBreadcrumb( { clientId, ...props } ) {
+ const label = useSelect(
+ ( select ) =>
+ select( 'core/block-editor' ).getAccessibleBlockLabel( clientId ),
+ [ clientId ]
);
- const { index, name, attributes } = selected;
const { setNavigationMode, removeBlock } = useDispatch(
'core/block-editor'
);
@@ -65,14 +46,6 @@ function BlockBreadcrumb( {
}
}
- const blockType = getBlockType( name );
- const label = getAccessibleBlockLabel(
- blockType,
- attributes,
- index + 1,
- moverDirection
- );
-
return (
diff --git a/packages/block-editor/src/components/block-navigation/item.js b/packages/block-editor/src/components/block-navigation/item.js
new file mode 100644
index 00000000000000..c205f2d1171c69
--- /dev/null
+++ b/packages/block-editor/src/components/block-navigation/item.js
@@ -0,0 +1,60 @@
+/**
+ * External dependencies
+ */
+import classnames from 'classnames';
+
+/**
+ * WordPress dependencies
+ */
+import { Button } from '@wordpress/components';
+import {
+ getBlockType,
+} from '@wordpress/blocks';
+import { useSelect } from '@wordpress/data';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import BlockIcon from '../block-icon';
+import ButtonBlockAppender from '../button-block-appender';
+
+export default function BlockNavigationItem( { block, isSelected, onClick, children } ) {
+ const { clientId, name } = block;
+ const blockIcon = getBlockType( name ).icon;
+ const blockLabel = useSelect(
+ ( select ) => select( 'core/block-editor' ).getBlockLabel( clientId ),
+ [ clientId ]
+ );
+
+ return (
+
+
+
+
+ { children }
+
+ );
+}
+
+BlockNavigationItem.Appender = function( { parentBlockClientId } ) {
+ return (
+
+
+
+
+
+ );
+};
diff --git a/packages/block-editor/src/components/block-navigation/list.js b/packages/block-editor/src/components/block-navigation/list.js
index 32c8eba5049e89..da0e2c6a338e47 100644
--- a/packages/block-editor/src/components/block-navigation/list.js
+++ b/packages/block-editor/src/components/block-navigation/list.js
@@ -2,23 +2,11 @@
* External dependencies
*/
import { isNil, map, omitBy } from 'lodash';
-import classnames from 'classnames';
-
-/**
- * WordPress dependencies
- */
-import { Button } from '@wordpress/components';
-import {
- __experimentalGetBlockLabel as getBlockLabel,
- getBlockType,
-} from '@wordpress/blocks';
-import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
-import BlockIcon from '../block-icon';
-import ButtonBlockAppender from '../button-block-appender';
+import BlockNavigationItem from './item';
export default function BlockNavigationList( {
blocks,
@@ -40,30 +28,13 @@ export default function BlockNavigationList( {
/* eslint-disable jsx-a11y/no-redundant-roles */
/* eslint-enable jsx-a11y/no-redundant-roles */
diff --git a/packages/block-editor/src/components/block-navigation/style.scss b/packages/block-editor/src/components/block-navigation/style.scss
index 737353fedf67bc..21eb94d9cab0f6 100644
--- a/packages/block-editor/src/components/block-navigation/style.scss
+++ b/packages/block-editor/src/components/block-navigation/style.scss
@@ -43,7 +43,8 @@ $tree-item-height: 36px;
margin-left: 1.5em;
}
- .block-editor-block-navigation__item {
+ .block-editor-block-navigation-item__block,
+ .block-editor-block-navigation-item__appender {
position: relative;
&::before {
@@ -57,7 +58,7 @@ $tree-item-height: 36px;
}
}
- .block-editor-block-navigation__item-button {
+ .block-editor-block-navigation-item__button {
margin-left: 0.8em;
width: calc(100% - 0.8em);
}
@@ -76,7 +77,7 @@ $tree-item-height: 36px;
}
}
-.block-editor-block-navigation__item-button {
+.block-editor-block-navigation-item__button {
display: flex;
align-items: center;
width: 100%;
diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js
index 9d71c1c29c3fd2..3ac773fae0d01b 100644
--- a/packages/block-editor/src/store/selectors.js
+++ b/packages/block-editor/src/store/selectors.js
@@ -29,6 +29,8 @@ import {
parse,
} from '@wordpress/blocks';
import { SVG, Rect, G, Path } from '@wordpress/components';
+import { toPlainText } from '@wordpress/rich-text';
+import { __, sprintf } from '@wordpress/i18n';
/**
* A block selection object.
@@ -1623,3 +1625,128 @@ export function isNavigationMode( state ) {
export function didAutomaticChange( state ) {
return !! state.automaticChangeStatus;
}
+
+/**
+ * Get the label for the block, usually this is either the block title,
+ * or the value of the attribute denoted by the block's `label` property.
+ *
+ * @param {Object} state Store state.
+ * @param {string} clientId ClientId for the block.
+ *
+ * @return {string} The block label.
+ */
+export function getBlockLabel( state, clientId ) {
+ const blockName = getBlockName( state, clientId );
+
+ const { __experimentalLabel: labelAttribute, title } = getBlockType(
+ blockName
+ );
+
+ if ( ! labelAttribute ) {
+ return title;
+ }
+
+ const attributes = getBlockAttributes( state, clientId );
+ const label = attributes[ labelAttribute ];
+
+ if ( ! label ) {
+ return title;
+ }
+
+ // Strip any HTML (i.e. RichText formatting) before returning.
+ return toPlainText( label );
+}
+
+/**
+ * Get a label for the block for use by screenreaders, this can include the block title, the
+ * position of the block, and the value of the `getAccessibilityLabel` function if it's specified.
+ *
+ * @param {Object} state Store state.
+ * @param {string} clientId ClientId for the block.
+ *
+ * @return {string} The accessibility label for the block.
+ */
+export function getAccessibleBlockLabel( state, clientId ) {
+ const blockName = getBlockName( state, clientId );
+
+ const {
+ __experimentalGetAccessibilityLabel: getAccessibilityLabel,
+ title,
+ } = getBlockType( blockName );
+
+ const rootClientId = getBlockRootClientId( state, clientId );
+ const attributes = getBlockAttributes( state, clientId );
+ const { __experimentalMoverDirection: direction = 'vertical' } =
+ getBlockListSettings( state, rootClientId ) || {};
+
+ // First, attempt to get the accessibility label if the block has one defined.
+ let label = getAccessibilityLabel
+ ? toPlainText( getAccessibilityLabel( attributes ) )
+ : undefined;
+
+ // If there's no accessibility label, use the block label.
+ if ( ! label ) {
+ label = getBlockLabel( state, clientId );
+ }
+
+ const position = getBlockIndex( state, clientId, rootClientId ) + 1;
+
+ // getBlockLabel returns the block title as a fallback when there's no label,
+ // if it did return the title, this function needs to avoid adding the
+ // title twice within the accessible label. Use this `hasLabel` boolean to
+ // handle that.
+ const hasLabel = !! label && label !== title;
+
+ const hasPosition = position !== undefined;
+
+ if ( hasPosition && direction === 'vertical' ) {
+ if ( hasLabel ) {
+ return sprintf(
+ /* translators: accessibility text. %1: The block title, %2: The block row number, %3: The block label.. */
+ __( '%1$s Block. Row %2$d. %3$s' ),
+ title,
+ position,
+ label
+ );
+ }
+
+ return sprintf(
+ /* translators: accessibility text. %s: The block title, %d The block row number. */
+ __( '%s Block. Row %d' ),
+ title,
+ position
+ );
+ } else if ( hasPosition && direction === 'horizontal' ) {
+ if ( hasLabel ) {
+ return sprintf(
+ /* translators: accessibility text. %1: The block title, %2: The block column number, %3: The block label.. */
+ __( '%1$s Block. Column %2$d. %3$s' ),
+ title,
+ position,
+ label
+ );
+ }
+
+ return sprintf(
+ /* translators: accessibility text. %s: The block title, %d The block column number. */
+ __( '%s Block. Column %d' ),
+ title,
+ position
+ );
+ }
+
+ if ( hasLabel ) {
+ return sprintf(
+ /* translators: accessibility text. %1: The block title. %2: The block label. */
+ __( '%1$s Block. %2$s' ),
+ title,
+ label
+ );
+ }
+
+ return sprintf(
+ /* translators: accessibility text. %s: The block title. */
+ __( '%s Block' ),
+ title
+ );
+}
diff --git a/packages/block-editor/src/store/test/selectors.js b/packages/block-editor/src/store/test/selectors.js
index d6f4cfaac20e17..3efb9c8062da07 100644
--- a/packages/block-editor/src/store/test/selectors.js
+++ b/packages/block-editor/src/store/test/selectors.js
@@ -64,6 +64,8 @@ const {
INSERTER_UTILITY_MEDIUM,
INSERTER_UTILITY_LOW,
getLowestCommonAncestorWithSelectedBlock,
+ getBlockLabel,
+ getAccessibleBlockLabel,
} = selectors;
describe( 'selectors', () => {
@@ -100,6 +102,10 @@ describe( 'selectors', () => {
supports: {
multiple: false,
},
+ __experimentalLabel: 'title',
+ __experimentalGetAccessibilityLabel( { content } ) {
+ return content;
+ },
} );
registerBlockType( 'core/test-block-c', {
@@ -2679,4 +2685,140 @@ describe( 'selectors', () => {
).toBe( 'a' );
} );
} );
+
+ describe( 'getLabel', () => {
+ const state = {
+ blocks: {
+ byClientId: {
+ 123: { clientId: 123, name: 'core/test-block-a' },
+ 456: { clientId: 456, name: 'core/test-block-b' },
+ },
+ attributes: {
+ 123: {},
+ 456: { title: 'A title', content: 'Some content' },
+ },
+ },
+ };
+
+ it( 'returns only the block title when the block has no `label` attribute', () => {
+ expect( getBlockLabel( state, 123 ) ).toBe( 'Test Block A' );
+ } );
+
+ it( 'returns the label when the `label` attribute is defined', () => {
+ expect( getBlockLabel( state, 456 ) ).toBe( 'A title' );
+ } );
+
+ it( 'returns the block title when the label attribute is defined but does not match an attribute', () => {
+ const stateWithEmptyAttributes = {
+ blocks: {
+ ...state.blocks,
+ attributes: {
+ ...state.blocks.attributes,
+ 456: {},
+ },
+ },
+ };
+ expect( getBlockLabel( stateWithEmptyAttributes, 456 ) ).toBe( 'Test Block B' );
+ } );
+
+ it( 'removes any html elements from the attribute', () => {
+ const stateWithHTMLContent = {
+ blocks: {
+ ...state.blocks,
+ attributes: {
+ ...state.blocks.attributes,
+ 456: { title: 'A title' },
+ },
+ },
+ };
+ expect( getBlockLabel( stateWithHTMLContent, 456 ) ).toBe( 'A title' );
+ } );
+ } );
+
+ describe( 'getAccessibleBlockLabel', () => {
+ const state = {
+ blocks: {
+ byClientId: {
+ 123: { clientId: 123, name: 'core/test-block-a' },
+ 456: { clientId: 456, name: 'core/test-block-b' },
+ },
+ attributes: {
+ 123: {},
+ 456: { title: 'A title', content: 'Some content' },
+ },
+ order: {
+ '': [ 123, 456 ],
+ },
+ parents: {
+ 123: '',
+ 456: '',
+ },
+ },
+ blockListSettings: {
+ '': {},
+ },
+ };
+
+ it( 'returns the block title and row when the block has no `getAccessibilityLabel` function', () => {
+ expect( getAccessibleBlockLabel( state, 123 ) ).toBe( 'Test Block A Block. Row 1' );
+ } );
+
+ it( 'returns the block title with the row and label when the `getAccessibilityLabel` function returns a value', () => {
+ expect( getAccessibleBlockLabel( state, 456 ) ).toBe( 'Test Block B Block. Row 2. Some content' );
+ } );
+
+ it( 'returns column instead of row when the direction is horizontal', () => {
+ const stateWithHorizontalBlockList = {
+ ...state,
+ blockListSettings: {
+ '': {
+ __experimentalMoverDirection: 'horizontal',
+ },
+ },
+ };
+ expect( getAccessibleBlockLabel( stateWithHorizontalBlockList, 456 ) ).toBe( 'Test Block B Block. Column 2. Some content' );
+ } );
+
+ it( 'returns the block title and row when attributes are undefined', () => {
+ const stateWithEmptyAttributes = {
+ ...state,
+ blocks: {
+ ...state.blocks,
+ attributes: {
+ ...state.blocks.attributes,
+ 456: {},
+ },
+ },
+ };
+ expect( getAccessibleBlockLabel( stateWithEmptyAttributes, 456 ) ).toBe( 'Test Block B Block. Row 2' );
+ } );
+
+ it( 'falls back to using the `label` when the accessibility label is undefined', () => {
+ const stateWithMissingAttribute = {
+ ...state,
+ blocks: {
+ ...state.blocks,
+ attributes: {
+ ...state.blocks.attributes,
+ 456: { title: 'A title' },
+ },
+ },
+ };
+ expect( getAccessibleBlockLabel( stateWithMissingAttribute, 456 ) ).toBe( 'Test Block B Block. Row 2. A title' );
+ } );
+
+ it( 'removes any html elements from the output of the `getLabel` function', () => {
+ const stateWithHTMLContent = {
+ ...state,
+ blocks: {
+ ...state.blocks,
+ attributes: {
+ ...state.blocks.attributes,
+ 456: { content: 'Some content' },
+ },
+ },
+ };
+ expect( getAccessibleBlockLabel( stateWithHTMLContent, 456 ) ).toBe( 'Test Block B Block. Row 2. Some content' );
+ } );
+ } );
} );
diff --git a/packages/block-library/src/heading/index.js b/packages/block-library/src/heading/index.js
index c5b3cd4e8a9c1d..a4837676d0ccaf 100644
--- a/packages/block-library/src/heading/index.js
+++ b/packages/block-library/src/heading/index.js
@@ -40,23 +40,21 @@ export const settings = {
level: 2,
},
},
- __experimentalLabel( attributes, { context } ) {
- if ( context === 'accessibility' ) {
- const { content, level } = attributes;
-
- return isEmpty( content )
- ? sprintf(
- /* translators: accessibility text. %s: heading level. */
- __( 'Level %s. Empty.' ),
- level
- )
- : sprintf(
- /* translators: accessibility text. 1: heading level. 2: heading content. */
- __( 'Level %1$s. %2$s' ),
- level,
- content
- );
+ __experimentalGetAccessibilityLabel( { content, level } ) {
+ if ( isEmpty( content ) ) {
+ return sprintf(
+ /* translators: accessibility text. %s: heading level. */
+ __( 'Level %s. Empty.' ),
+ level
+ );
}
+
+ return sprintf(
+ /* translators: accessibility text. 1: heading level. 2: heading content. */
+ __( 'Level %1$s. %2$s' ),
+ level,
+ content
+ );
},
transforms,
deprecated,
diff --git a/packages/block-library/src/image/index.js b/packages/block-library/src/image/index.js
index 332ab1afb062ca..0988b863757af4 100644
--- a/packages/block-library/src/image/index.js
+++ b/packages/block-library/src/image/index.js
@@ -41,22 +41,18 @@ export const settings = {
},
{ name: 'rounded', label: _x( 'Rounded', 'block style' ) },
],
- __experimentalLabel( attributes, { context } ) {
- if ( context === 'accessibility' ) {
- const { caption, alt, url } = attributes;
-
- if ( ! url ) {
- return __( 'Empty' );
- }
-
- if ( ! alt ) {
- return caption || '';
- }
+ __experimentalGetAccessibilityLabel( { caption, alt, url } ) {
+ if ( ! url ) {
+ return __( 'Empty' );
+ }
- // This is intended to be read by a screen reader.
- // A period simply means a pause, no need to translate it.
- return alt + ( caption ? '. ' + caption : '' );
+ if ( ! alt ) {
+ return caption || '';
}
+
+ // This is intended to be read by a screen reader.
+ // A period simply means a pause, no need to translate it.
+ return alt + ( caption ? '. ' + caption : '' );
},
transforms,
getEditWrapperProps( attributes ) {
diff --git a/packages/block-library/src/missing/index.js b/packages/block-library/src/missing/index.js
index d399dc470946c2..4d82fd099182c3 100644
--- a/packages/block-library/src/missing/index.js
+++ b/packages/block-library/src/missing/index.js
@@ -26,20 +26,16 @@ export const settings = {
html: false,
reusable: false,
},
- __experimentalLabel( attributes, { context } ) {
- if ( context === 'accessibility' ) {
- const { originalName } = attributes;
+ __experimentalGetAccessibilityLabel( { originalName } ) {
+ const originalBlockType = originalName
+ ? getBlockType( originalName )
+ : undefined;
- const originalBlockType = originalName
- ? getBlockType( originalName )
- : undefined;
-
- if ( originalBlockType ) {
- return originalBlockType.settings.title || originalName;
- }
-
- return '';
+ if ( originalBlockType ) {
+ return originalBlockType.settings.title || originalName;
}
+
+ return '';
},
edit,
save,
diff --git a/packages/block-library/src/more/index.js b/packages/block-library/src/more/index.js
index c70c5b5412e556..a3baa46446b7ef 100644
--- a/packages/block-library/src/more/index.js
+++ b/packages/block-library/src/more/index.js
@@ -29,10 +29,8 @@ export const settings = {
multiple: false,
},
example: {},
- __experimentalLabel( attributes, { context } ) {
- if ( context === 'accessibility' ) {
- return attributes.customText;
- }
+ __experimentalGetAccessibilityLabel( { customText } ) {
+ return customText;
},
transforms,
edit,
diff --git a/packages/block-library/src/navigation-link/index.js b/packages/block-library/src/navigation-link/index.js
index b53e4003c0ec01..7bcc5f6d4123dc 100644
--- a/packages/block-library/src/navigation-link/index.js
+++ b/packages/block-library/src/navigation-link/index.js
@@ -28,7 +28,11 @@ export const settings = {
html: false,
},
- __experimentalLabel: ( { label } ) => label,
+ __experimentalLabel: 'label',
+
+ __experimentalGetAccessibilityLabel( { label } ) {
+ return label;
+ },
edit,
save,
diff --git a/packages/block-library/src/paragraph/index.js b/packages/block-library/src/paragraph/index.js
index 1e70972e29d112..d5bddcbffdfe64 100644
--- a/packages/block-library/src/paragraph/index.js
+++ b/packages/block-library/src/paragraph/index.js
@@ -40,11 +40,8 @@ export const settings = {
className: false,
__unstablePasteTextInline: true,
},
- __experimentalLabel( attributes, { context } ) {
- if ( context === 'accessibility' ) {
- const { content } = attributes;
- return isEmpty( content ) ? __( 'Empty' ) : content;
- }
+ __experimentalGetAccessibilityLabel( { content } ) {
+ return isEmpty( content ) ? __( 'Empty' ) : content;
},
transforms,
deprecated,
diff --git a/packages/blocks/src/api/index.js b/packages/blocks/src/api/index.js
index 131175c89568e4..885d98bac5d348 100644
--- a/packages/blocks/src/api/index.js
+++ b/packages/blocks/src/api/index.js
@@ -57,8 +57,6 @@ export {
isUnmodifiedDefaultBlock,
normalizeIconObject,
isValidIcon,
- getBlockLabel as __experimentalGetBlockLabel,
- getAccessibleBlockLabel as __experimentalGetAccessibleBlockLabel,
} from './utils';
export {
doBlocksMatchTemplate,
diff --git a/packages/blocks/src/api/test/utils.js b/packages/blocks/src/api/test/utils.js
index c00f22cf28b6ea..3fe75a6cf4e9c9 100644
--- a/packages/blocks/src/api/test/utils.js
+++ b/packages/blocks/src/api/test/utils.js
@@ -13,11 +13,7 @@ import {
registerBlockType,
setDefaultBlockName,
} from '../registration';
-import {
- isUnmodifiedDefaultBlock,
- getAccessibleBlockLabel,
- getBlockLabel,
-} from '../utils';
+import { isUnmodifiedDefaultBlock } from '../utils';
describe( 'block helpers', () => {
beforeAll( () => {
@@ -107,108 +103,3 @@ describe( 'block helpers', () => {
} );
} );
} );
-
-describe( 'getBlockLabel', () => {
- it( 'returns only the block title when the block has no `getLabel` function', () => {
- const blockType = { title: 'Recipe' };
- const attributes = {};
-
- expect( getBlockLabel( blockType, attributes ) ).toBe( 'Recipe' );
- } );
-
- it( 'returns only the block title when the block has a `getLabel` function, but it returns a falsey value', () => {
- const blockType = { title: 'Recipe', __experimentalLabel: () => '' };
- const attributes = {};
-
- expect( getBlockLabel( blockType, attributes ) ).toBe( 'Recipe' );
- } );
-
- it( 'returns the block title with the label when the `getLabel` function returns a value', () => {
- const blockType = {
- title: 'Recipe',
- __experimentalLabel: ( { heading } ) => heading,
- };
- const attributes = { heading: 'Cupcakes!' };
-
- expect( getBlockLabel( blockType, attributes ) ).toBe( 'Cupcakes!' );
- } );
-
- it( 'removes any html elements from the output of the `getLabel` function', () => {
- const blockType = {
- title: 'Recipe',
- __experimentalLabel: ( { heading } ) => heading,
- };
- const attributes = {
- heading: 'Cupcakes!',
- };
-
- expect( getBlockLabel( blockType, attributes ) ).toBe( 'Cupcakes!' );
- } );
-} );
-
-describe( 'getAccessibleBlockLabel', () => {
- it( 'returns only the block title when the block has no `getLabel` function', () => {
- const blockType = { title: 'Recipe' };
- const attributes = {};
-
- expect( getAccessibleBlockLabel( blockType, attributes ) ).toBe(
- 'Recipe Block'
- );
- } );
-
- it( 'returns only the block title when the block has a `getLabel` function, but it returns a falsey value', () => {
- const blockType = { title: 'Recipe', __experimentalLabel: () => '' };
- const attributes = {};
-
- expect( getAccessibleBlockLabel( blockType, attributes ) ).toBe(
- 'Recipe Block'
- );
- } );
-
- it( 'returns the block title with the label when the `getLabel` function returns a value', () => {
- const blockType = {
- title: 'Recipe',
- __experimentalLabel: ( { heading } ) => heading,
- };
- const attributes = { heading: 'Cupcakes!' };
-
- expect( getAccessibleBlockLabel( blockType, attributes ) ).toBe(
- 'Recipe Block. Cupcakes!'
- );
- } );
-
- it( 'removes any html elements from the output of the `getLabel` function', () => {
- const blockType = {
- title: 'Recipe',
- __experimentalLabel: ( { heading } ) => heading,
- };
- const attributes = {
- heading: 'Cupcakes!',
- };
-
- expect( getAccessibleBlockLabel( blockType, attributes ) ).toBe(
- 'Recipe Block. Cupcakes!'
- );
- } );
-
- it( 'outputs the block title and label with a row number indicating the position of the block, when the optional third parameter is provided', () => {
- const blockType = {
- title: 'Recipe',
- __experimentalLabel: ( { heading } ) => heading,
- };
- const attributes = { heading: 'Cupcakes!' };
-
- expect( getAccessibleBlockLabel( blockType, attributes, 3 ) ).toBe(
- 'Recipe Block. Row 3. Cupcakes!'
- );
- } );
-
- it( 'outputs just the block title and row number when there no label is available for the block', () => {
- const blockType = { title: 'Recipe' };
- const attributes = {};
-
- expect( getAccessibleBlockLabel( blockType, attributes, 3 ) ).toBe(
- 'Recipe Block. Row 3'
- );
- } );
-} );
diff --git a/packages/blocks/src/api/utils.js b/packages/blocks/src/api/utils.js
index 11b333d8bdef23..7ec2499645e586 100644
--- a/packages/blocks/src/api/utils.js
+++ b/packages/blocks/src/api/utils.js
@@ -8,8 +8,6 @@ import { default as tinycolor, mostReadable } from 'tinycolor2';
* WordPress dependencies
*/
import { Component, isValidElement } from '@wordpress/element';
-import { __, sprintf } from '@wordpress/i18n';
-import { __unstableStripHTML as stripHTML } from '@wordpress/dom';
/**
* Internal dependencies
@@ -128,107 +126,3 @@ export function normalizeBlockType( blockTypeOrName ) {
return blockTypeOrName;
}
-
-/**
- * Get the label for the block, usually this is either the block title,
- * or the value of the block's `label` function when that's specified.
- *
- * @param {Object} blockType The block type.
- * @param {Object} attributes The values of the block's attributes.
- * @param {Object} context The intended use for the label.
- *
- * @return {string} The block label.
- */
-export function getBlockLabel( blockType, attributes, context = 'visual' ) {
- const { __experimentalLabel: getLabel, title } = blockType;
-
- const label = getLabel && getLabel( attributes, { context } );
-
- if ( ! label ) {
- return title;
- }
-
- // Strip any HTML (i.e. RichText formatting) before returning.
- return stripHTML( label );
-}
-
-/**
- * Get a label for the block for use by screenreaders, this is more descriptive
- * than the visual label and includes the block title and the value of the
- * `getLabel` function if it's specified.
- *
- * @param {Object} blockType The block type.
- * @param {Object} attributes The values of the block's attributes.
- * @param {?number} position The position of the block in the block list.
- * @param {string} [direction='vertical'] The direction of the block layout.
- *
- * @return {string} The block label.
- */
-export function getAccessibleBlockLabel(
- blockType,
- attributes,
- position,
- direction = 'vertical'
-) {
- // `title` is already localized, `label` is a user-supplied value.
- const { title } = blockType;
- const label = getBlockLabel( blockType, attributes, 'accessibility' );
- const hasPosition = position !== undefined;
-
- // getBlockLabel returns the block title as a fallback when there's no label,
- // if it did return the title, this function needs to avoid adding the
- // title twice within the accessible label. Use this `hasLabel` boolean to
- // handle that.
- const hasLabel = label && label !== title;
-
- if ( hasPosition && direction === 'vertical' ) {
- if ( hasLabel ) {
- return sprintf(
- /* translators: accessibility text. %1: The block title, %2: The block row number, %3: The block label.. */
- __( '%1$s Block. Row %2$d. %3$s' ),
- title,
- position,
- label
- );
- }
-
- return sprintf(
- /* translators: accessibility text. %s: The block title, %d The block row number. */
- __( '%s Block. Row %d' ),
- title,
- position
- );
- } else if ( hasPosition && direction === 'horizontal' ) {
- if ( hasLabel ) {
- return sprintf(
- /* translators: accessibility text. %1: The block title, %2: The block column number, %3: The block label.. */
- __( '%1$s Block. Column %2$d. %3$s' ),
- title,
- position,
- label
- );
- }
-
- return sprintf(
- /* translators: accessibility text. %s: The block title, %d The block column number. */
- __( '%s Block. Column %d' ),
- title,
- position
- );
- }
-
- if ( hasLabel ) {
- return sprintf(
- /* translators: accessibility text. %1: The block title. %2: The block label. */
- __( '%1$s Block. %2$s' ),
- title,
- label
- );
- }
-
- return sprintf(
- /* translators: accessibility text. %s: The block title. */
- __( '%s Block' ),
- title
- );
-}
diff --git a/packages/dom/src/dom.js b/packages/dom/src/dom.js
index c1ae1fbc17395d..e4fcf79eb64720 100644
--- a/packages/dom/src/dom.js
+++ b/packages/dom/src/dom.js
@@ -7,7 +7,7 @@ import { includes } from 'lodash';
* Browser dependencies
*/
-const { DOMParser, getComputedStyle } = window;
+const { getComputedStyle } = window;
const {
TEXT_NODE,
ELEMENT_NODE,
@@ -678,15 +678,3 @@ export function wrap( newNode, referenceNode ) {
referenceNode.parentNode.insertBefore( newNode, referenceNode );
newNode.appendChild( referenceNode );
}
-
-/**
- * Removes any HTML tags from the provided string.
- *
- * @param {string} html The string containing html.
- *
- * @return {string} The text content with any html removed.
- */
-export function __unstableStripHTML( html ) {
- const document = new DOMParser().parseFromString( html, 'text/html' );
- return document.body.textContent || '';
-}
diff --git a/packages/dom/src/test/dom.js b/packages/dom/src/test/dom.js
index a2352d75efbd8a..71725bea36c0b4 100644
--- a/packages/dom/src/test/dom.js
+++ b/packages/dom/src/test/dom.js
@@ -5,7 +5,6 @@ import {
isHorizontalEdge,
placeCaretAtHorizontalEdge,
isTextField,
- __unstableStripHTML as stripHTML,
} from '../dom';
describe( 'DOM', () => {
@@ -157,18 +156,4 @@ describe( 'DOM', () => {
);
} );
} );
-
- describe( 'stripHTML', () => {
- it( 'removes any HTML from a text string', () => {
- expect( stripHTML( 'This is emphasized' ) ).toBe(
- 'This is emphasized'
- );
- } );
-
- it( 'removes script tags, but does not execute them', () => {
- const html = 'This will not ';
- expect( stripHTML( html ) ).toBe( 'This will not throw "Error"' );
- expect( () => stripHTML( html ) ).not.toThrow();
- } );
- } );
} );
diff --git a/packages/e2e-tests/specs/editor/blocks/columns.test.js b/packages/e2e-tests/specs/editor/blocks/columns.test.js
index 6255f6c5c5ac8d..2427c1d6f80e07 100644
--- a/packages/e2e-tests/specs/editor/blocks/columns.test.js
+++ b/packages/e2e-tests/specs/editor/blocks/columns.test.js
@@ -20,7 +20,7 @@ describe( 'Columns', () => {
await page.click( '[aria-label="Block navigation"]' );
const columnBlockMenuItem = (
await page.$x(
- '//button[contains(concat(" ", @class, " "), " block-editor-block-navigation__item-button ")][text()="Column"]'
+ '//button[contains(concat(" ", @class, " "), " block-editor-block-navigation-item__button ")][text()="Column"]'
)
)[ 0 ];
await columnBlockMenuItem.click();
diff --git a/packages/e2e-tests/specs/editor/plugins/block-icons.test.js b/packages/e2e-tests/specs/editor/plugins/block-icons.test.js
index 517340e987b80a..8755d171f678b1 100644
--- a/packages/e2e-tests/specs/editor/plugins/block-icons.test.js
+++ b/packages/e2e-tests/specs/editor/plugins/block-icons.test.js
@@ -39,7 +39,7 @@ async function getFirstInserterIcon() {
async function selectFirstBlock() {
await pressKeyWithModifier( 'access', 'o' );
const navButtons = await page.$$(
- '.block-editor-block-navigation__item-button'
+ '.block-editor-block-navigation-item__button'
);
await navButtons[ 0 ].click();
}
diff --git a/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js b/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js
index 643998905e00e3..b45a7aa8f721f1 100644
--- a/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js
+++ b/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js
@@ -12,7 +12,7 @@ import {
async function openBlockNavigator() {
await pressKeyWithModifier( 'access', 'o' );
await page.waitForSelector(
- '.block-editor-block-navigation__item-button.is-selected'
+ '.block-editor-block-navigation-item__button.is-selected'
);
}
@@ -37,7 +37,7 @@ describe( 'Navigating the block hierarchy', () => {
await page.click( '[aria-label="Block navigation"]' );
const columnsBlockMenuItem = (
await page.$x(
- "//button[contains(@class,'block-editor-block-navigation__item') and contains(text(), 'Columns')]"
+ "//button[contains(@class,'block-editor-block-navigation-item__button') and contains(text(), 'Columns')]"
)
)[ 0 ];
await columnsBlockMenuItem.click();
@@ -55,7 +55,7 @@ describe( 'Navigating the block hierarchy', () => {
await page.click( '[aria-label="Block navigation"]' );
const lastColumnsBlockMenuItem = (
await page.$x(
- "//button[contains(@class,'block-editor-block-navigation__item') and contains(text(), 'Column')]"
+ "//button[contains(@class,'block-editor-block-navigation-item__button') and contains(text(), 'Column')]"
)
)[ 3 ];
await lastColumnsBlockMenuItem.click();
diff --git a/packages/rich-text/README.md b/packages/rich-text/README.md
index 30ed4296d162f7..67cf1548e8deac 100644
--- a/packages/rich-text/README.md
+++ b/packages/rich-text/README.md
@@ -335,6 +335,18 @@ _Returns_
- `string`: HTML string.
+# **toPlainText**
+
+Removes any HTML tags from the provided string.
+
+_Parameters_
+
+- _html_ `string`: The string containing html.
+
+_Returns_
+
+- `string`: The text content with any html removed.
+
# **unregisterFormatType**
Unregisters a format.
diff --git a/packages/rich-text/src/index.js b/packages/rich-text/src/index.js
index ac4cea67d4757c..014d010f464e6a 100644
--- a/packages/rich-text/src/index.js
+++ b/packages/rich-text/src/index.js
@@ -26,6 +26,7 @@ export { slice } from './slice';
export { split } from './split';
export { toDom as __unstableToDom } from './to-dom';
export { toHTMLString } from './to-html-string';
+export { toPlainText } from './to-plain-text';
export { toggleFormat } from './toggle-format';
export { LINE_SEPARATOR as __UNSTABLE_LINE_SEPARATOR } from './special-characters';
export { unregisterFormatType } from './unregister-format-type';
diff --git a/packages/rich-text/src/test/to-plain-text.js b/packages/rich-text/src/test/to-plain-text.js
new file mode 100644
index 00000000000000..bc5883903f906f
--- /dev/null
+++ b/packages/rich-text/src/test/to-plain-text.js
@@ -0,0 +1,27 @@
+/**
+ * Internal dependencies
+ */
+import { toPlainText } from '../to-plain-text';
+
+describe( 'toPlainText', () => {
+ beforeAll( () => {
+ // Initialize the rich-text store.
+ require( '../store' );
+ } );
+
+ it( 'removes any HTML from a text string', () => {
+ expect( toPlainText( 'This is emphasized' ) ).toBe( 'This is emphasized' );
+ } );
+
+ it( 'removes script tags, but does not execute them', () => {
+ const html = 'This will not ';
+ expect( toPlainText( html ) ).toBe( 'This will not throw "Error"' );
+ expect( () => toPlainText( html ) ).not.toThrow();
+ } );
+
+ it( 'expects strings and an empty string for falsey values', () => {
+ expect( toPlainText( '' ) ).toBe( '' );
+ expect( toPlainText( undefined ) ).toBe( '' );
+ expect( toPlainText( null ) ).toBe( '' );
+ } );
+} );
diff --git a/packages/rich-text/src/to-plain-text.js b/packages/rich-text/src/to-plain-text.js
new file mode 100644
index 00000000000000..6bc12442a56967
--- /dev/null
+++ b/packages/rich-text/src/to-plain-text.js
@@ -0,0 +1,19 @@
+/**
+ * Internal dependencies
+ */
+import { create } from './create';
+
+/**
+ * Removes any HTML tags from the provided string.
+ *
+ * @param {string} html The string containing html.
+ *
+ * @return {string} The text content with any html removed.
+ */
+export function toPlainText( html ) {
+ if ( ! html ) {
+ return '';
+ }
+
+ return create( { html } ).text;
+}