diff --git a/blocks/hooks/align.js b/blocks/hooks/align.js index c323fb57073de0..b724a6ef4f45d1 100644 --- a/blocks/hooks/align.js +++ b/blocks/hooks/align.js @@ -7,7 +7,7 @@ import { assign, includes } from 'lodash'; /** * WordPress dependencies */ -import { getWrapperDisplayName } from '@wordpress/element'; +import { createHigherOrderComponent } from '@wordpress/element'; import { addFilter } from '@wordpress/hooks'; import BlockControls from '../block-controls'; import BlockAlignmentToolbar from '../block-alignment-toolbar'; @@ -71,8 +71,8 @@ export function getBlockValidAlignments( blockName ) { * @param {Function} BlockEdit Original component * @return {Function} Wrapped component */ -export function withToolbarControls( BlockEdit ) { - const WrappedBlockEdit = ( props ) => { +export const withToolbarControls = createHigherOrderComponent( ( BlockEdit ) => { + return ( props ) => { const validAlignments = getBlockValidAlignments( props.name ); const updateAlignment = ( nextAlign ) => props.setAttributes( { align: nextAlign } ); @@ -90,10 +90,7 @@ export function withToolbarControls( BlockEdit ) { , ]; }; - WrappedBlockEdit.displayName = getWrapperDisplayName( BlockEdit, 'align' ); - - return WrappedBlockEdit; -} +}, 'withToolbarControls' ); /** * Override the default block element to add alignment wrapper props. @@ -101,8 +98,8 @@ export function withToolbarControls( BlockEdit ) { * @param {Function} BlockListBlock Original component * @return {Function} Wrapped component */ -export function withAlign( BlockListBlock ) { - const WrappedComponent = ( props ) => { +export const withAlign = createHigherOrderComponent( ( BlockListBlock ) => { + return ( props ) => { const { align } = props.block.attributes; const validAlignments = getBlockValidAlignments( props.block.name ); @@ -113,11 +110,7 @@ export function withAlign( BlockListBlock ) { return ; }; - - WrappedComponent.displayName = getWrapperDisplayName( BlockListBlock, 'align' ); - - return WrappedComponent; -} +}, 'withAlign' ); /** * Override props assigned to save component to inject alignment class name if diff --git a/blocks/hooks/anchor.js b/blocks/hooks/anchor.js index bc1dd47b401c46..65371a4088c433 100644 --- a/blocks/hooks/anchor.js +++ b/blocks/hooks/anchor.js @@ -6,7 +6,7 @@ import { assign } from 'lodash'; /** * WordPress dependencies */ -import { getWrapperDisplayName } from '@wordpress/element'; +import { createHigherOrderComponent } from '@wordpress/element'; import { addFilter } from '@wordpress/hooks'; import { TextControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; @@ -56,8 +56,8 @@ export function addAttribute( settings ) { * * @return {string} Wrapped component. */ -export function withInspectorControl( BlockEdit ) { - const WrappedBlockEdit = ( props ) => { +export const withInspectorControl = createHigherOrderComponent( ( BlockEdit ) => { + return ( props ) => { const hasAnchor = hasBlockSupport( props.name, 'anchor' ) && props.isSelected; return [ , @@ -75,10 +75,7 @@ export function withInspectorControl( BlockEdit ) { , ]; }; - WrappedBlockEdit.displayName = getWrapperDisplayName( BlockEdit, 'anchor' ); - - return WrappedBlockEdit; -} +}, 'withInspectorControl' ); /** * Override props assigned to save component to inject anchor ID, if block diff --git a/blocks/hooks/custom-class-name.js b/blocks/hooks/custom-class-name.js index c0a5bc29c1feb3..a8a8fa07591e76 100644 --- a/blocks/hooks/custom-class-name.js +++ b/blocks/hooks/custom-class-name.js @@ -7,7 +7,7 @@ import classnames from 'classnames'; /** * WordPress dependencies */ -import { getWrapperDisplayName } from '@wordpress/element'; +import { createHigherOrderComponent } from '@wordpress/element'; import { addFilter } from '@wordpress/hooks'; import { TextControl } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; @@ -47,8 +47,8 @@ export function addAttribute( settings ) { * * @return {string} Wrapped component. */ -export function withInspectorControl( BlockEdit ) { - const WrappedBlockEdit = ( props ) => { +export const withInspectorControl = createHigherOrderComponent( ( BlockEdit ) => { + return ( props ) => { const hasCustomClassName = hasBlockSupport( props.name, 'customClassName', true ) && props.isSelected; return [ @@ -66,10 +66,7 @@ export function withInspectorControl( BlockEdit ) { , ]; }; - WrappedBlockEdit.displayName = getWrapperDisplayName( BlockEdit, 'customClassName' ); - - return WrappedBlockEdit; -} +}, 'withInspectorControl' ); /** * Override props assigned to save component to inject anchor ID, if block diff --git a/components/higher-order/if-condition/index.js b/components/higher-order/if-condition/index.js index efab3a30359ca1..0ae3099810a1c4 100644 --- a/components/higher-order/if-condition/index.js +++ b/components/higher-order/if-condition/index.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { getWrapperDisplayName } from '@wordpress/element'; +import { createHigherOrderComponent } from '@wordpress/element'; /** * Higher-order component creator, creating a new component which renders if @@ -11,18 +11,15 @@ import { getWrapperDisplayName } from '@wordpress/element'; * * @return {Function} Higher-order component. */ -const ifCondition = ( predicate ) => ( WrappedComponent ) => { - const EnhancedComponent = ( props ) => { +const ifCondition = ( predicate ) => createHigherOrderComponent( + ( WrappedComponent ) => ( props ) => { if ( ! predicate( props ) ) { return null; } return ; - }; - - EnhancedComponent.displayName = getWrapperDisplayName( WrappedComponent, 'ifCondition' ); - - return EnhancedComponent; -}; + }, + 'ifCondition' +); export default ifCondition; diff --git a/components/higher-order/with-api-data/index.js b/components/higher-order/with-api-data/index.js index 19c4e4910c19f4..29a24791ad854a 100644 --- a/components/higher-order/with-api-data/index.js +++ b/components/higher-order/with-api-data/index.js @@ -6,7 +6,7 @@ import { mapValues, reduce, forEach, noop } from 'lodash'; /** * WordPress dependencies */ -import { Component, getWrapperDisplayName } from '@wordpress/element'; +import { Component, createHigherOrderComponent } from '@wordpress/element'; /** * Internal dependencies @@ -14,7 +14,7 @@ import { Component, getWrapperDisplayName } from '@wordpress/element'; import request, { getCachedResponse } from './request'; import { getRoute } from './routes'; -export default ( mapPropsToData ) => ( WrappedComponent ) => { +export default ( mapPropsToData ) => createHigherOrderComponent( ( WrappedComponent ) => { class APIDataComponent extends Component { constructor( props, context ) { super( ...arguments ); @@ -221,8 +221,6 @@ export default ( mapPropsToData ) => ( WrappedComponent ) => { } } - APIDataComponent.displayName = getWrapperDisplayName( WrappedComponent, 'apiData' ); - APIDataComponent.contextTypes = { getAPISchema: noop, getAPIPostTypeRestBaseMapping: noop, @@ -230,4 +228,4 @@ export default ( mapPropsToData ) => ( WrappedComponent ) => { }; return APIDataComponent; -}; +}, 'withAPIData' ); diff --git a/components/higher-order/with-filters/index.js b/components/higher-order/with-filters/index.js index 522e7bb358a20c..278bb325c76abf 100644 --- a/components/higher-order/with-filters/index.js +++ b/components/higher-order/with-filters/index.js @@ -6,7 +6,7 @@ import { debounce, uniqueId } from 'lodash'; /** * WordPress dependencies */ -import { Component, getWrapperDisplayName } from '@wordpress/element'; +import { Component, createHigherOrderComponent } from '@wordpress/element'; import { addAction, applyFilters, removeAction } from '@wordpress/hooks'; const ANIMATION_FRAME_PERIOD = 16; @@ -22,8 +22,8 @@ const ANIMATION_FRAME_PERIOD = 16; * @return {Function} Higher-order component factory. */ export default function withFilters( hookName ) { - return ( OriginalComponent ) => { - class FilteredComponent extends Component { + return createHigherOrderComponent( ( OriginalComponent ) => { + return class FilteredComponent extends Component { /** @inheritdoc */ constructor( props ) { super( props ); @@ -62,9 +62,6 @@ export default function withFilters( hookName ) { render() { return ; } - } - FilteredComponent.displayName = getWrapperDisplayName( OriginalComponent, 'filters' ); - - return FilteredComponent; - }; + }; + }, 'withFilters' ); } diff --git a/components/higher-order/with-state/index.js b/components/higher-order/with-state/index.js index b2c47819ed259f..4328407b268313 100644 --- a/components/higher-order/with-state/index.js +++ b/components/higher-order/with-state/index.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { Component, getWrapperDisplayName } from '@wordpress/element'; +import { Component, createHigherOrderComponent } from '@wordpress/element'; /** * A Higher Order Component used to provide and manage internal component state @@ -11,9 +11,9 @@ import { Component, getWrapperDisplayName } from '@wordpress/element'; * * @return {Component} Wrapped component. */ -function withState( initialState = {} ) { - return ( OriginalComponent ) => { - class WrappedComponent extends Component { +export default function withState( initialState = {} ) { + return createHigherOrderComponent( ( OriginalComponent ) => { + return class WrappedComponent extends Component { constructor() { super( ...arguments ); @@ -31,12 +31,6 @@ function withState( initialState = {} ) { /> ); } - } - - WrappedComponent.displayName = getWrapperDisplayName( WrappedComponent, 'state' ); - - return WrappedComponent; - }; + }; + } ); } - -export default withState; diff --git a/data/index.js b/data/index.js index a6db5e8e908707..3b0f9638636163 100644 --- a/data/index.js +++ b/data/index.js @@ -9,7 +9,7 @@ import memoize from 'memize'; /** * WordPress dependencies */ -import { Component, getWrapperDisplayName } from '@wordpress/element'; +import { Component, createHigherOrderComponent } from '@wordpress/element'; /** * Internal dependencies @@ -231,8 +231,8 @@ export function dispatch( reducerKey ) { * * @return {Component} Enhanced component with merged state data props. */ -export const withSelect = ( mapStateToProps ) => ( WrappedComponent ) => { - class ComponentWithSelect extends Component { +export const withSelect = ( mapStateToProps ) => createHigherOrderComponent( ( WrappedComponent ) => { + return class ComponentWithSelect extends Component { constructor() { super( ...arguments ); @@ -286,12 +286,8 @@ export const withSelect = ( mapStateToProps ) => ( WrappedComponent ) => { render() { return ; } - } - - ComponentWithSelect.displayName = getWrapperDisplayName( WrappedComponent, 'select' ); - - return ComponentWithSelect; -}; + }; +}, 'withSelect' ); /** * Higher-order component used to add dispatch props using registered action @@ -305,8 +301,8 @@ export const withSelect = ( mapStateToProps ) => ( WrappedComponent ) => { * * @return {Component} Enhanced component with merged dispatcher props. */ -export const withDispatch = ( mapDispatchToProps ) => ( WrappedComponent ) => { - class ComponentWithDispatch extends Component { +export const withDispatch = ( mapDispatchToProps ) => createHigherOrderComponent( ( WrappedComponent ) => { + return class ComponentWithDispatch extends Component { constructor() { super( ...arguments ); @@ -345,12 +341,8 @@ export const withDispatch = ( mapDispatchToProps ) => ( WrappedComponent ) => { render() { return ; } - } - - ComponentWithDispatch.displayName = getWrapperDisplayName( WrappedComponent, 'dispatch' ); - - return ComponentWithDispatch; -}; + }; +}, 'withDispatch' ); /** * Returns true if the given argument appears to be a dispatchable action. diff --git a/docs/deprecated.md b/docs/deprecated.md index 2961419094e322..3e66262ce46a95 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -1,5 +1,9 @@ Gutenberg's deprecation policy is intended to support backwards-compatibility for two minor releases, when possible. The current deprecations are listed below and are grouped by _the version at which they will be removed completely_. If your plugin depends on these behaviors, you must update to the recommended alternative before the noted version. +## 2.7.0 + +- `wp.element.getWrapperDisplayName` function removed. Please use `wp.element.createHigherOrderComponent` instead. + ## 2.6.0 - `wp.blocks.getBlockDefaultClassname` function removed. Please use `wp.blocks.getBlockDefaultClassName` instead. diff --git a/edit-post/hooks/validate-use-once/index.js b/edit-post/hooks/validate-use-once/index.js index 0efdbb5b1c1f77..6317a28971aff9 100644 --- a/edit-post/hooks/validate-use-once/index.js +++ b/edit-post/hooks/validate-use-once/index.js @@ -10,7 +10,7 @@ import { createBlock, getBlockType, findTransform, getBlockTransforms } from '@w import { Button } from '@wordpress/components'; import { withSelect, withDispatch } from '@wordpress/data'; import { Warning } from '@wordpress/editor'; -import { compose, getWrapperDisplayName } from '@wordpress/element'; +import { compose, createHigherOrderComponent } from '@wordpress/element'; import { addFilter } from '@wordpress/hooks'; import { __ } from '@wordpress/i18n'; @@ -49,8 +49,8 @@ const enhance = compose( } ) ), ); -function withUseOnceValidation( BlockEdit ) { - const WrappedBlockEdit = ( { +const withUseOnceValidation = createHigherOrderComponent( ( BlockEdit ) => { + return enhance( ( { originalBlockUid, selectFirst, ...props @@ -93,12 +93,8 @@ function withUseOnceValidation( BlockEdit ) { { __( 'This block may not be used more than once.' ) } , ]; - }; - - WrappedBlockEdit.displayName = getWrapperDisplayName( BlockEdit, 'useOnceValidation' ); - - return enhance( WrappedBlockEdit ); -} + } ); +}, 'withUseOnceValidation' ); /** * Given a base block name, returns the default block type to which to offer diff --git a/editor/components/default-block-appender/test/__snapshots__/index.js.snap b/editor/components/default-block-appender/test/__snapshots__/index.js.snap index ee1a646214cf18..f29565682dc3b5 100644 --- a/editor/components/default-block-appender/test/__snapshots__/index.js.snap +++ b/editor/components/default-block-appender/test/__snapshots__/index.js.snap @@ -36,7 +36,7 @@ exports[`DefaultBlockAppender should append a default block when input focused 1 value="Write your story" /> - @@ -60,7 +60,7 @@ exports[`DefaultBlockAppender should match snapshot 1`] = ` value="Write your story" /> - @@ -84,7 +84,7 @@ exports[`DefaultBlockAppender should optionally show without prompt 1`] = ` value="" /> - diff --git a/element/index.js b/element/index.js index 5f296bac93a6c6..d03da01bf1a15f 100644 --- a/element/index.js +++ b/element/index.js @@ -11,6 +11,11 @@ import { isEmpty, } from 'lodash'; +/** + * WordPress dependencies + */ +import { deprecated } from '@wordpress/utils'; + /** * Internal dependencies */ @@ -164,11 +169,38 @@ export { flowRight as compose }; * @return {string} Wrapped display name. */ export function getWrapperDisplayName( BaseComponent, wrapperName ) { + deprecated( 'getWrapperDisplayName', { + version: '2.7', + alternative: 'wp.element.createHigherOrderComponent', + plugin: 'Gutenberg', + } ); + const { displayName = BaseComponent.name || 'Component' } = BaseComponent; return `${ upperFirst( camelCase( wrapperName ) ) }(${ displayName })`; } +/** + * Given a function mapping a component to an enhanced component and modifier + * name, returns the enhanced component augmented with a generated displayName. + * + * @param {Function} mapComponentToEnhancedComponent Function mapping component + * to enhanced component. + * @param {string} modifierName Seed name from which to + * generated display name. + * + * @return {WPComponent} Component class with generated display name assigned. + */ +export function createHigherOrderComponent( mapComponentToEnhancedComponent, modifierName ) { + return ( OriginalComponent ) => { + const EnhancedComponent = mapComponentToEnhancedComponent( OriginalComponent ); + const { displayName = OriginalComponent.name || 'Component' } = OriginalComponent; + EnhancedComponent.displayName = `${ upperFirst( camelCase( modifierName ) ) }(${ displayName })`; + + return EnhancedComponent; + }; +} + /** * Component used as equivalent of Fragment with unescaped HTML, in cases where * it is desirable to render dangerous HTML without needing a wrapper element. diff --git a/element/test/index.js b/element/test/index.js index 7c0e2ed7e190c1..ee7396c5b5e2d8 100644 --- a/element/test/index.js +++ b/element/test/index.js @@ -9,10 +9,10 @@ import { shallow } from 'enzyme'; import { Component, createElement, + createHigherOrderComponent, concatChildren, renderToString, switchChildrenNodeName, - getWrapperDisplayName, RawHTML, } from '../'; @@ -123,42 +123,64 @@ describe( 'element', () => { } ); } ); - describe( 'getWrapperDisplayName()', () => { + describe( 'createHigherOrderComponent', () => { it( 'should use default name for anonymous function', () => { - expect( getWrapperDisplayName( () =>
, 'test' ) ).toBe( 'Test(Component)' ); + const TestComponent = createHigherOrderComponent( + OriginalComponent => OriginalComponent, + 'withTest' + )( () =>
); + + expect( TestComponent.displayName ).toBe( 'WithTest(Component)' ); } ); it( 'should use camel case starting with upper for wrapper prefix ', () => { - expect( getWrapperDisplayName( () =>
, 'one-two_threeFOUR' ) ).toBe( 'OneTwoThreeFour(Component)' ); + const TestComponent = createHigherOrderComponent( + OriginalComponent => OriginalComponent, + 'with-one-two_threeFOUR' + )( () =>
); + + expect( TestComponent.displayName ).toBe( 'WithOneTwoThreeFour(Component)' ); } ); it( 'should use function name', () => { function SomeComponent() { return
; } + const TestComponent = createHigherOrderComponent( + OriginalComponent => OriginalComponent, + 'withTest' + )( SomeComponent ); - expect( getWrapperDisplayName( SomeComponent, 'test' ) ).toBe( 'Test(SomeComponent)' ); + expect( TestComponent.displayName ).toBe( 'WithTest(SomeComponent)' ); } ); it( 'should use component class name', () => { - class SomeComponent extends Component { + class SomeAnotherComponent extends Component { render() { return
; } } + const TestComponent = createHigherOrderComponent( + OriginalComponent => OriginalComponent, + 'withTest' + )( SomeAnotherComponent ); - expect( getWrapperDisplayName( SomeComponent, 'test' ) ).toBe( 'Test(SomeComponent)' ); + expect( TestComponent.displayName ).toBe( 'WithTest(SomeAnotherComponent)' ); } ); it( 'should use displayName property', () => { - class SomeComponent extends Component { + class SomeYetAnotherComponent extends Component { render() { return
; } } - SomeComponent.displayName = 'CustomDisplayName'; + SomeYetAnotherComponent.displayName = 'CustomDisplayName'; + const TestComponent = createHigherOrderComponent( + OriginalComponent => OriginalComponent, + 'withTest' + )( SomeYetAnotherComponent ); - expect( getWrapperDisplayName( SomeComponent, 'test' ) ).toBe( 'Test(CustomDisplayName)' ); + expect( TestComponent.displayName ).toBe( 'WithTest(CustomDisplayName)' ); } ); } ); diff --git a/lib/client-assets.php b/lib/client-assets.php index 1694f971df4a10..ed348f0a6ad743 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -141,7 +141,7 @@ function gutenberg_register_scripts_and_styles() { wp_register_script( 'wp-element', gutenberg_url( 'element/build/index.js' ), - array( 'react', 'react-dom' ), + array( 'react', 'react-dom', 'wp-utils' ), filemtime( gutenberg_dir_path() . 'element/build/index.js' ) ); wp_register_script( diff --git a/viewport/if-viewport-matches.js b/viewport/if-viewport-matches.js index 4fb9c4daf190d0..6df11907fcbaf9 100644 --- a/viewport/if-viewport-matches.js +++ b/viewport/if-viewport-matches.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { compose, getWrapperDisplayName } from '@wordpress/element'; +import { compose, createHigherOrderComponent } from '@wordpress/element'; import { ifCondition } from '@wordpress/components'; /** @@ -19,17 +19,14 @@ import withViewportMatch from './with-viewport-match'; * * @return {Function} Higher-order component. */ -const ifViewportMatches = ( query ) => ( WrappedComponent ) => { - const EnhancedComponent = compose( [ +const ifViewportMatches = ( query ) => createHigherOrderComponent( + compose( [ withViewportMatch( { isViewportMatch: query, } ), ifCondition( ( props ) => props.isViewportMatch ), - ] )( WrappedComponent ); - - EnhancedComponent.displayName = getWrapperDisplayName( WrappedComponent, 'ifViewportMatches' ); - - return EnhancedComponent; -}; + ] ), + 'ifViewportMatches' +); export default ifViewportMatches; diff --git a/viewport/with-viewport-match.js b/viewport/with-viewport-match.js index 129708a59ecfa0..238d2082ec730c 100644 --- a/viewport/with-viewport-match.js +++ b/viewport/with-viewport-match.js @@ -6,31 +6,27 @@ import { mapValues } from 'lodash'; /** * WordPress dependencies */ -import { getWrapperDisplayName } from '@wordpress/element'; +import { createHigherOrderComponent } from '@wordpress/element'; import { withSelect } from '@wordpress/data'; /** * Higher-order component creator, creating a new component which renders with - * the given prop names, where the value passed to the underlying compoennt is + * the given prop names, where the value passed to the underlying component is * the result of the query assigned as the object's value. * * @param {Object} queries Object of prop name to viewport query. - * @param {string} propName Optional prop name to which result is assigned. * * @see isViewportMatch * * @return {Function} Higher-order component. */ -const withViewportMatch = ( queries ) => ( WrappedComponent ) => { - const EnhancedComponent = withSelect( ( select ) => { +const withViewportMatch = ( queries ) => createHigherOrderComponent( + withSelect( ( select ) => { return mapValues( queries, ( query ) => { return select( 'core/viewport' ).isViewportMatch( query ); } ); - } )( WrappedComponent ); - - EnhancedComponent.displayName = getWrapperDisplayName( WrappedComponent, 'withViewportMatch' ); - - return EnhancedComponent; -}; + } ), + 'withViewportMatch' +); export default withViewportMatch;