diff --git a/packages/block-editor/src/components/link-control/test/__snapshots__/index.js.snap b/packages/block-editor/src/components/link-control/test/__snapshots__/index.js.snap
index feac082de26346..cf0801f4316199 100644
--- a/packages/block-editor/src/components/link-control/test/__snapshots__/index.js.snap
+++ b/packages/block-editor/src/components/link-control/test/__snapshots__/index.js.snap
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`Basic rendering should display with required props 1`] = `""`;
+exports[`Basic rendering should display with required props 1`] = `""`;
diff --git a/packages/components/src/button/index.js b/packages/components/src/button/index.js
index 3987b0b31ac28f..77271b82ebb3b2 100644
--- a/packages/components/src/button/index.js
+++ b/packages/components/src/button/index.js
@@ -2,12 +2,19 @@
* External dependencies
*/
import classnames from 'classnames';
+import { isArray } from 'lodash';
/**
* WordPress dependencies
*/
import deprecated from '@wordpress/deprecated';
-import { createElement, forwardRef } from '@wordpress/element';
+import { forwardRef } from '@wordpress/element';
+
+/**
+ * Internal dependencies
+ */
+import Tooltip from '../tooltip';
+import Icon from '../icon';
export function Button( props, ref ) {
const {
@@ -25,6 +32,13 @@ export function Button( props, ref ) {
isDestructive,
className,
disabled,
+ icon,
+ iconSize,
+ showTooltip,
+ tooltipPosition,
+ shortcut,
+ label,
+ children,
...additionalProps
} = props;
@@ -44,19 +58,54 @@ export function Button( props, ref ) {
'is-busy': isBusy,
'is-link': isLink,
'is-destructive': isDestructive,
+ 'has-text': !! icon && !! children,
+ // Ideally should be has-icon but this is named this way for BC
+ 'components-icon-button': !! icon,
} );
- const tag = href !== undefined && ! disabled ? 'a' : 'button';
- const tagProps = tag === 'a' ?
+ const Tag = href !== undefined && ! disabled ? 'a' : 'button';
+ const tagProps = Tag === 'a' ?
{ href, target } :
{ type: 'button', disabled, 'aria-pressed': isPressed };
- return createElement( tag, {
- ...tagProps,
- ...additionalProps,
- className: classes,
- ref,
- } );
+ // Should show the tooltip if...
+ const shouldShowTooltip = ! disabled && (
+ // an explicit tooltip is passed or...
+ ( showTooltip && label ) ||
+ // there's a shortcut or...
+ shortcut ||
+ (
+ // there's a label and...
+ !! label &&
+ // the children are empty and...
+ ( ! children || ( isArray( children ) && ! children.length ) ) &&
+ // the tooltip is not explicitly disabled.
+ false !== showTooltip
+ )
+ );
+
+ const element = (
+
+ { icon && }
+ { children }
+
+ );
+
+ if ( ! shouldShowTooltip ) {
+ return element;
+ }
+
+ return (
+
+ { element }
+
+ );
}
export default forwardRef( Button );
diff --git a/packages/components/src/button/style.scss b/packages/components/src/button/style.scss
index 154120ffd2c2b1..b33e087b450369 100644
--- a/packages/components/src/button/style.scss
+++ b/packages/components/src/button/style.scss
@@ -228,6 +228,23 @@
}
}
+.components-icon-button {
+ .dashicon {
+ display: inline-block;
+ flex: 0 0 auto;
+ }
+
+ // Ensure that even SVG icons that don't include the .dashicon class are colored.
+ svg {
+ fill: currentColor;
+ outline: none;
+ }
+
+ &.has-text svg {
+ margin-right: 8px;
+ }
+}
+
@keyframes components-button__busy-animation {
0% {
background-position: 200px 0;
diff --git a/packages/components/src/button/test/index.js b/packages/components/src/button/test/index.js
index c0b03149abd2f0..fdb194f6611c44 100644
--- a/packages/components/src/button/test/index.js
+++ b/packages/components/src/button/test/index.js
@@ -74,6 +74,57 @@ describe( 'Button', () => {
expect( button.prop( 'WordPress' ) ).toBe( 'awesome' );
} );
+
+ it( 'should render an icon button', () => {
+ const iconButton = shallow( );
+ expect( iconButton.hasClass( 'components-icon-button' ) ).toBe( true );
+ expect( iconButton.prop( 'aria-label' ) ).toBeUndefined();
+ } );
+
+ it( 'should render a Dashicon component matching the wordpress icon', () => {
+ const iconButton = shallow( );
+ expect( iconButton.find( 'Icon' ).dive().shallow().hasClass( 'dashicons-wordpress' ) ).toBe( true );
+ } );
+
+ it( 'should render child elements and icon', () => {
+ const iconButton = shallow(
} /> );
+ expect( iconButton.find( 'Icon' ).dive().shallow().hasClass( 'dashicons-wordpress' ) ).toBe( true );
+ expect( iconButton.find( '.test' ).shallow().text() ).toBe( 'Test' );
+ } );
+
+ it( 'should add an aria-label when the label property is used, with Tooltip wrapper', () => {
+ const iconButton = shallow( );
+ expect( iconButton.name() ).toBe( 'Tooltip' );
+ expect( iconButton.prop( 'text' ) ).toBe( 'WordPress' );
+ expect( iconButton.find( 'button' ).prop( 'aria-label' ) ).toBe( 'WordPress' );
+ } );
+
+ it( 'should support explicit aria-label override', () => {
+ const iconButton = shallow( );
+ expect( iconButton.prop( 'aria-label' ) ).toBe( 'Custom' );
+ } );
+
+ it( 'should allow tooltip disable', () => {
+ const iconButton = shallow( );
+ expect( iconButton.name() ).toBe( 'button' );
+ expect( iconButton.prop( 'aria-label' ) ).toBe( 'WordPress' );
+ } );
+
+ it( 'should show the tooltip for empty children', () => {
+ const iconButton = shallow( );
+ expect( iconButton.name() ).toBe( 'Tooltip' );
+ expect( iconButton.prop( 'text' ) ).toBe( 'WordPress' );
+ } );
+
+ it( 'should not show the tooltip when icon and children defined', () => {
+ const iconButton = shallow( );
+ expect( iconButton.name() ).toBe( 'button' );
+ } );
+
+ it( 'should force showing the tooltip even if icon and children defined', () => {
+ const iconButton = shallow( );
+ expect( iconButton.name() ).toBe( 'Tooltip' );
+ } );
} );
describe( 'with href property', () => {
diff --git a/packages/components/src/icon-button/index.js b/packages/components/src/icon-button/index.js
index b41b3335b0c3a6..dd2b4ef36d16e7 100644
--- a/packages/components/src/icon-button/index.js
+++ b/packages/components/src/icon-button/index.js
@@ -1,9 +1,3 @@
-/**
- * External dependencies
- */
-import classnames from 'classnames';
-import { isArray } from 'lodash';
-
/**
* WordPress dependencies
*/
@@ -12,64 +6,25 @@ import { forwardRef } from '@wordpress/element';
/**
* Internal dependencies
*/
-import Tooltip from '../tooltip';
import Button from '../button';
-import Icon from '../icon';
-
-function IconButton( props, ref ) {
- const {
- icon,
- children,
- label,
- className,
- tooltip,
- shortcut,
- labelPosition,
- size,
- ...additionalProps
- } = props;
- const classes = classnames( 'components-icon-button', className, {
- 'has-text': children,
- } );
- const tooltipText = tooltip || label;
- // Should show the tooltip if...
- const showTooltip = ! additionalProps.disabled && (
- // an explicit tooltip is passed or...
- tooltip ||
- // there's a shortcut or...
- shortcut ||
- (
- // there's a label and...
- !! label &&
- // the children are empty and...
- ( ! children || ( isArray( children ) && ! children.length ) ) &&
- // the tooltip is not explicitly disabled.
- false !== tooltip
- )
- );
-
- let element = (
+function IconButton( {
+ labelPosition,
+ size,
+ tooltip,
+ label,
+ ...props
+}, ref ) {
+ return (
+ tooltipPosition={ labelPosition }
+ iconSize={ size }
+ showTooltip={ tooltip !== undefined ? !! tooltip : undefined }
+ label={ tooltip || label }
+ />
);
-
- if ( showTooltip ) {
- element = (
-
- { element }
-
- );
- }
-
- return element;
}
export default forwardRef( IconButton );
diff --git a/packages/components/src/icon-button/style.scss b/packages/components/src/icon-button/style.scss
deleted file mode 100644
index 102a361d940885..00000000000000
--- a/packages/components/src/icon-button/style.scss
+++ /dev/null
@@ -1,16 +0,0 @@
-.components-icon-button {
- .dashicon {
- display: inline-block;
- flex: 0 0 auto;
- }
-
- // Ensure that even SVG icons that don't include the .dashicon class are colored.
- svg {
- fill: currentColor;
- outline: none;
- }
-
- &.has-text svg {
- margin-right: 8px;
- }
-}
diff --git a/packages/components/src/icon-button/test/index.js b/packages/components/src/icon-button/test/index.js
deleted file mode 100644
index f4a8d4330d3cc2..00000000000000
--- a/packages/components/src/icon-button/test/index.js
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
- * External dependencies
- */
-import { shallow } from 'enzyme';
-import TestUtils from 'react-dom/test-utils';
-
-/**
- * WordPress dependencies
- */
-import { createRef } from '@wordpress/element';
-
-/**
- * Internal dependencies
- */
-import IconButton from '../';
-
-describe( 'IconButton', () => {
- describe( 'basic rendering', () => {
- it( 'should render an top level element with only a class property', () => {
- const iconButton = shallow( );
- expect( iconButton.hasClass( 'components-icon-button' ) ).toBe( true );
- expect( iconButton.prop( 'aria-label' ) ).toBeUndefined();
- } );
-
- it( 'should render a Dashicon component matching the wordpress icon', () => {
- const iconButton = shallow( );
- expect( iconButton.find( 'Icon' ).dive().shallow().hasClass( 'dashicons-wordpress' ) ).toBe( true );
- } );
-
- it( 'should render child elements when passed as children', () => {
- const iconButton = shallow( Test } /> );
- expect( iconButton.find( '.test' ).shallow().text() ).toBe( 'Test' );
- } );
-
- it( 'should add an aria-label when the label property is used', () => {
- const iconButton = shallow( WordPress );
- expect( iconButton.name() ).toBe( 'ForwardRef(Button)' );
- expect( iconButton.prop( 'aria-label' ) ).toBe( 'WordPress' );
- } );
-
- it( 'should add an aria-label when the label property is used, with Tooltip wrapper', () => {
- const iconButton = shallow( );
- expect( iconButton.name() ).toBe( 'Tooltip' );
- expect( iconButton.prop( 'text' ) ).toBe( 'WordPress' );
- expect( iconButton.find( 'ForwardRef(Button)' ).prop( 'aria-label' ) ).toBe( 'WordPress' );
- } );
-
- it( 'should support explicit aria-label override', () => {
- const iconButton = shallow( );
- expect( iconButton.prop( 'aria-label' ) ).toBe( 'Custom' );
- } );
-
- it( 'should add an additional className', () => {
- const iconButton = shallow( );
- expect( iconButton.hasClass( 'test' ) ).toBe( true );
- } );
-
- it( 'should pass additional props to the underlying button', () => {
- const iconButton = shallow( );
-
- expect( iconButton.find( 'ForwardRef(Button)' ).prop( 'aria-pressed' ) ).toBe( 'true' );
- expect( iconButton.find( 'ForwardRef(Button)' ).prop( 'disabled' ) ).toBe( true );
- } );
-
- it( 'should allow custom tooltip text', () => {
- const iconButton = shallow( );
- expect( iconButton.name() ).toBe( 'Tooltip' );
- expect( iconButton.prop( 'text' ) ).toBe( 'Custom' );
- expect( iconButton.find( 'ForwardRef(Button)' ).prop( 'aria-label' ) ).toBe( 'WordPress' );
- } );
-
- it( 'should allow tooltip disable', () => {
- const iconButton = shallow( );
- expect( iconButton.name() ).toBe( 'ForwardRef(Button)' );
- expect( iconButton.prop( 'aria-label' ) ).toBe( 'WordPress' );
- } );
-
- it( 'should show the tooltip for empty children', () => {
- const iconButton = shallow( );
- expect( iconButton.name() ).toBe( 'Tooltip' );
- expect( iconButton.prop( 'text' ) ).toBe( 'WordPress' );
- } );
-
- it( 'forwards ref', () => {
- const ref = createRef();
-
- TestUtils.renderIntoDocument( );
- expect( ref.current.type ).toBe( 'button' );
- } );
- } );
-} );
diff --git a/packages/components/src/style.scss b/packages/components/src/style.scss
index b429d051bf0204..f99717ec65d84b 100644
--- a/packages/components/src/style.scss
+++ b/packages/components/src/style.scss
@@ -24,7 +24,6 @@
@import "./form-token-field/style.scss";
@import "./guide/style.scss";
@import "./higher-order/navigate-regions/style.scss";
-@import "./icon-button/style.scss";
@import "./menu-group/style.scss";
@import "./menu-item/style.scss";
@import "./menu-items-choice/style.scss";
diff --git a/packages/e2e-tests/specs/editor/plugins/__snapshots__/plugins-api.test.js.snap b/packages/e2e-tests/specs/editor/plugins/__snapshots__/plugins-api.test.js.snap
index 86ce33a736311e..f3f0358fcd0b03 100644
--- a/packages/e2e-tests/specs/editor/plugins/__snapshots__/plugins-api.test.js.snap
+++ b/packages/e2e-tests/specs/editor/plugins/__snapshots__/plugins-api.test.js.snap
@@ -2,6 +2,6 @@
exports[`Using Plugins API Document Setting Custom Panel Should render a custom panel inside Document Setting sidebar 1`] = `"My Custom Panel"`;
-exports[`Using Plugins API Sidebar Medium screen Should open plugins sidebar using More Menu item and render content 1`] = `""`;
+exports[`Using Plugins API Sidebar Medium screen Should open plugins sidebar using More Menu item and render content 1`] = `""`;
-exports[`Using Plugins API Sidebar Should open plugins sidebar using More Menu item and render content 1`] = `""`;
+exports[`Using Plugins API Sidebar Should open plugins sidebar using More Menu item and render content 1`] = `""`;
diff --git a/packages/edit-post/src/components/header/more-menu/test/__snapshots__/index.js.snap b/packages/edit-post/src/components/header/more-menu/test/__snapshots__/index.js.snap
index e0337df629bd3a..71abd65e7b9628 100644
--- a/packages/edit-post/src/components/header/more-menu/test/__snapshots__/index.js.snap
+++ b/packages/edit-post/src/components/header/more-menu/test/__snapshots__/index.js.snap
@@ -43,28 +43,26 @@ exports[`MoreMenu should match snapshot 1`] = `
onKeyDown={[Function]}
tooltip="More tools & options"
>
-
-
-
-
+
+
diff --git a/packages/edit-post/src/components/header/plugin-more-menu-item/test/__snapshots__/index.js.snap b/packages/edit-post/src/components/header/plugin-more-menu-item/test/__snapshots__/index.js.snap
index 0a2564900eda2e..dc576582b3cc73 100644
--- a/packages/edit-post/src/components/header/plugin-more-menu-item/test/__snapshots__/index.js.snap
+++ b/packages/edit-post/src/components/header/plugin-more-menu-item/test/__snapshots__/index.js.snap
@@ -16,7 +16,7 @@ exports[`PluginMoreMenuItem renders menu item as button properly 1`] = `
role="group"
>