- { __(
- 'Use your left or right arrow keys or drag and drop with the mouse to change the gradient position. Press the button to change the color or remove the control point.'
- ) }
-
+ { __(
+ 'Use your left or right arrow keys or drag and drop with the mouse to change the gradient position. Press the button to change the color or remove the control point.'
+ ) }
+
+
+ );
+}
export default function ControlPoints( {
gradientPickerDomRef,
diff --git a/packages/components/src/dimension-control/test/__snapshots__/index.test.js.snap b/packages/components/src/dimension-control/test/__snapshots__/index.test.js.snap
index c06662ee862c9..dddc2093bca48 100644
--- a/packages/components/src/dimension-control/test/__snapshots__/index.test.js.snap
+++ b/packages/components/src/dimension-control/test/__snapshots__/index.test.js.snap
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`DimensionControl rendering renders with custom sizes 1`] = `
-
);
}
-
-export default withInstanceId( FontSizePicker );
diff --git a/packages/components/src/form-token-field/token.js b/packages/components/src/form-token-field/token.js
index 0e83faa173309..6597269115d82 100644
--- a/packages/components/src/form-token-field/token.js
+++ b/packages/components/src/form-token-field/token.js
@@ -7,7 +7,7 @@ import { noop } from 'lodash';
/**
* WordPress dependencies
*/
-import { withInstanceId } from '@wordpress/compose';
+import { useInstanceId } from '@wordpress/compose';
import { __, sprintf } from '@wordpress/i18n';
/**
@@ -16,7 +16,7 @@ import { __, sprintf } from '@wordpress/i18n';
import IconButton from '../icon-button';
import VisuallyHidden from '../visually-hidden';
-function Token( {
+export default function Token( {
value,
status,
title,
@@ -29,8 +29,8 @@ function Token( {
messages,
termPosition,
termsCount,
- instanceId,
} ) {
+ const instanceId = useInstanceId( Token );
const tokenClasses = classnames( 'components-form-token-field__token', {
'is-error': 'error' === status,
'is-success': 'success' === status,
@@ -75,5 +75,3 @@ function Token( {
);
}
-
-export default withInstanceId( Token );
diff --git a/packages/components/src/menu-group/index.js b/packages/components/src/menu-group/index.js
index ba98c5fea4fd2..b6bc145440c0c 100644
--- a/packages/components/src/menu-group/index.js
+++ b/packages/components/src/menu-group/index.js
@@ -7,14 +7,15 @@ import classnames from 'classnames';
* WordPress dependencies
*/
import { Children } from '@wordpress/element';
-import { withInstanceId } from '@wordpress/compose';
+import { useInstanceId } from '@wordpress/compose';
export function MenuGroup( {
children,
className = '',
- instanceId,
label,
} ) {
+ const instanceId = useInstanceId( MenuGroup );
+
if ( ! Children.count( children ) ) {
return null;
}
@@ -43,4 +44,4 @@ export function MenuGroup( {
);
}
-export default withInstanceId( MenuGroup );
+export default MenuGroup;
diff --git a/packages/components/src/radio-control/index.js b/packages/components/src/radio-control/index.js
index 2aec3eaca43d4..8565d99d04d96 100644
--- a/packages/components/src/radio-control/index.js
+++ b/packages/components/src/radio-control/index.js
@@ -7,14 +7,15 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
-import { withInstanceId } from '@wordpress/compose';
+import { useInstanceId } from '@wordpress/compose';
/**
* Internal dependencies
*/
import BaseControl from '../base-control';
-function RadioControl( { label, className, selected, help, instanceId, onChange, options = [] } ) {
+export default function RadioControl( { label, className, selected, help, onChange, options = [] } ) {
+ const instanceId = useInstanceId( RadioControl );
const id = `inspector-radio-control-${ instanceId }`;
const onChangeValue = ( event ) => onChange( event.target.value );
@@ -43,5 +44,3 @@ function RadioControl( { label, className, selected, help, instanceId, onChange,
);
}
-
-export default withInstanceId( RadioControl );
diff --git a/packages/components/src/select-control/index.js b/packages/components/src/select-control/index.js
index a10f051face1c..de9b78b2c3c12 100644
--- a/packages/components/src/select-control/index.js
+++ b/packages/components/src/select-control/index.js
@@ -6,16 +6,15 @@ import { isEmpty } from 'lodash';
/**
* WordPress dependencies
*/
-import { withInstanceId } from '@wordpress/compose';
+import { useInstanceId } from '@wordpress/compose';
/**
* Internal dependencies
*/
import BaseControl from '../base-control';
-function SelectControl( {
+export default function SelectControl( {
help,
- instanceId,
label,
multiple = false,
onChange,
@@ -24,6 +23,7 @@ function SelectControl( {
hideLabelFromVision,
...props
} ) {
+ const instanceId = useInstanceId( SelectControl );
const id = `inspector-select-control-${ instanceId }`;
const onChangeValue = ( event ) => {
if ( multiple ) {
@@ -62,5 +62,3 @@ function SelectControl( {
);
/* eslint-enable jsx-a11y/no-onchange */
}
-
-export default withInstanceId( SelectControl );
diff --git a/packages/components/src/text-control/index.js b/packages/components/src/text-control/index.js
index 61504cc7da5cf..c2d0ccdf6711b 100644
--- a/packages/components/src/text-control/index.js
+++ b/packages/components/src/text-control/index.js
@@ -1,14 +1,15 @@
/**
* WordPress dependencies
*/
-import { withInstanceId } from '@wordpress/compose';
+import { useInstanceId } from '@wordpress/compose';
/**
* Internal dependencies
*/
import BaseControl from '../base-control';
-function TextControl( { label, hideLabelFromVision, value, help, className, instanceId, onChange, type = 'text', ...props } ) {
+export default function TextControl( { label, hideLabelFromVision, value, help, className, onChange, type = 'text', ...props } ) {
+ const instanceId = useInstanceId( TextControl );
const id = `inspector-text-control-${ instanceId }`;
const onChangeValue = ( event ) => onChange( event.target.value );
@@ -25,5 +26,3 @@ function TextControl( { label, hideLabelFromVision, value, help, className, inst
);
}
-
-export default withInstanceId( TextControl );
diff --git a/packages/components/src/textarea-control/index.js b/packages/components/src/textarea-control/index.js
index 45158ca2ec747..f2b5d0fa6d804 100644
--- a/packages/components/src/textarea-control/index.js
+++ b/packages/components/src/textarea-control/index.js
@@ -1,14 +1,15 @@
/**
* WordPress dependencies
*/
-import { withInstanceId } from '@wordpress/compose';
+import { useInstanceId } from '@wordpress/compose';
/**
* Internal dependencies
*/
import BaseControl from '../base-control';
-function TextareaControl( { label, hideLabelFromVision, value, help, instanceId, onChange, rows = 4, className, ...props } ) {
+export default function TextareaControl( { label, hideLabelFromVision, value, help, onChange, rows = 4, className, ...props } ) {
+ const instanceId = useInstanceId( TextareaControl );
const id = `inspector-textarea-control-${ instanceId }`;
const onChangeValue = ( event ) => onChange( event.target.value );
@@ -26,5 +27,3 @@ function TextareaControl( { label, hideLabelFromVision, value, help, instanceId,
);
}
-
-export default withInstanceId( TextareaControl );
diff --git a/packages/compose/README.md b/packages/compose/README.md
index b449657f0b1e7..c8d0c348dcb07 100644
--- a/packages/compose/README.md
+++ b/packages/compose/README.md
@@ -119,6 +119,14 @@ _Returns_
- `WPComponent`: Component class with generated display name assigned.
+# **useInstanceId**
+
+Provides a unique instance ID.
+
+_Parameters_
+
+- _object_ `Object`: Object reference to create an id for.
+
# **useMediaQuery**
Runs a media query and returns its value when it changes.
diff --git a/packages/compose/src/higher-order/with-instance-id/index.js b/packages/compose/src/higher-order/with-instance-id/index.js
index 960c6997e8671..a894b8a6c2d8d 100644
--- a/packages/compose/src/higher-order/with-instance-id/index.js
+++ b/packages/compose/src/higher-order/with-instance-id/index.js
@@ -1,12 +1,8 @@
-/**
- * WordPress dependencies
- */
-import { Component } from '@wordpress/element';
-
/**
* Internal dependencies
*/
import createHigherOrderComponent from '../../utils/create-higher-order-component';
+import useInstanceId from '../../hooks/use-instance-id';
/**
* A Higher Order Component used to be provide a unique instance ID by
@@ -17,18 +13,8 @@ import createHigherOrderComponent from '../../utils/create-higher-order-componen
* @return {WPComponent} Component with an instanceId prop.
*/
export default createHigherOrderComponent( ( WrappedComponent ) => {
- let instances = 0;
-
- return class extends Component {
- constructor() {
- super( ...arguments );
- this.instanceId = instances++;
- }
-
- render() {
- return (
-
- );
- }
+ return ( props ) => {
+ const instanceId = useInstanceId( WrappedComponent );
+ return ;
};
}, 'withInstanceId' );
diff --git a/packages/compose/src/hooks/use-instance-id/README.md b/packages/compose/src/hooks/use-instance-id/README.md
new file mode 100644
index 0000000000000..f53d45e788d48
--- /dev/null
+++ b/packages/compose/src/hooks/use-instance-id/README.md
@@ -0,0 +1,22 @@
+useInstanceId
+==============
+
+Some components need to generate a unique id for each instance. This could serve as suffixes to element ID's for example. `useInstanceId` provides a unique `instanceId` to serve this purpose.
+
+## Usage
+
+```jsx
+/**
+ * WordPress dependencies
+ */
+import { useInstanceId } from '@wordpress/compose';
+
+function MyCustomElement() {
+ const instanceId = useInstanceId( MyCustomElement );
+ return (
+
+ content
+
+ );
+}
+```
diff --git a/packages/compose/src/hooks/use-instance-id/index.js b/packages/compose/src/hooks/use-instance-id/index.js
new file mode 100644
index 0000000000000..2b93a5fe1b5a6
--- /dev/null
+++ b/packages/compose/src/hooks/use-instance-id/index.js
@@ -0,0 +1,26 @@
+/**
+ * WordPress dependencies
+ */
+import { useMemo } from '@wordpress/element';
+
+const instanceMap = new WeakMap();
+
+/**
+ * Creates a new id for a given object.
+ *
+ * @param {Object} object Object reference to create an id for.
+ */
+function createId( object ) {
+ const instances = instanceMap.get( object ) || 0;
+ instanceMap.set( object, instances + 1 );
+ return instances;
+}
+
+/**
+ * Provides a unique instance ID.
+ *
+ * @param {Object} object Object reference to create an id for.
+ */
+export default function useInstanceId( object ) {
+ return useMemo( () => createId( object ), [ object ] );
+}
diff --git a/packages/compose/src/hooks/use-instance-id/test/index.js b/packages/compose/src/hooks/use-instance-id/test/index.js
new file mode 100644
index 0000000000000..5dc89e089c78f
--- /dev/null
+++ b/packages/compose/src/hooks/use-instance-id/test/index.js
@@ -0,0 +1,36 @@
+/**
+ * External dependencies
+ */
+import { create, act } from 'react-test-renderer';
+
+/**
+ * Internal dependencies
+ */
+import useInstanceId from '../';
+
+describe( 'useInstanceId', () => {
+ const TestComponent = () => {
+ return useInstanceId( TestComponent );
+ };
+
+ it( 'should manage ids', async () => {
+ let test0;
+
+ await act( async () => {
+ test0 = create( );
+ } );
+
+ expect( test0.toJSON() ).toBe( '0' );
+
+ let test1;
+
+ await act( async () => {
+ test1 = create( );
+ } );
+
+ expect( test1.toJSON() ).toBe( '1' );
+
+ test0.unmount();
+ test1.unmount();
+ } );
+} );
diff --git a/packages/compose/src/index.js b/packages/compose/src/index.js
index aa1d03dcde2f7..7be88558f8b88 100644
--- a/packages/compose/src/index.js
+++ b/packages/compose/src/index.js
@@ -16,3 +16,4 @@ export { default as withState } from './higher-order/with-state';
export { default as useMediaQuery } from './hooks/use-media-query';
export { default as useReducedMotion } from './hooks/use-reduced-motion';
export { default as useViewportMatch } from './hooks/use-viewport-match';
+export { default as useInstanceId } from './hooks/use-instance-id';
diff --git a/packages/edit-post/src/components/manage-blocks-modal/show-all.js b/packages/edit-post/src/components/manage-blocks-modal/show-all.js
index 7aaa206bc626a..d024dfecca208 100644
--- a/packages/edit-post/src/components/manage-blocks-modal/show-all.js
+++ b/packages/edit-post/src/components/manage-blocks-modal/show-all.js
@@ -1,11 +1,12 @@
/**
* WordPress dependencies
*/
-import { withInstanceId } from '@wordpress/compose';
+import { useInstanceId } from '@wordpress/compose';
import { FormToggle } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
-function BlockManagerShowAll( { instanceId, checked, onChange } ) {
+export default function BlockManagerShowAll( { checked, onChange } ) {
+ const instanceId = useInstanceId( BlockManagerShowAll );
const id = 'edit-post-manage-blocks-modal__show-all-' + instanceId;
return (
@@ -27,5 +28,3 @@ function BlockManagerShowAll( { instanceId, checked, onChange } ) {
);
}
-
-export default withInstanceId( BlockManagerShowAll );
diff --git a/packages/editor/src/components/post-publish-panel/test/__snapshots__/index.js.snap b/packages/editor/src/components/post-publish-panel/test/__snapshots__/index.js.snap
index 7cb1c2b47f7b2..e936a3b03a821 100644
--- a/packages/editor/src/components/post-publish-panel/test/__snapshots__/index.js.snap
+++ b/packages/editor/src/components/post-publish-panel/test/__snapshots__/index.js.snap
@@ -28,7 +28,7 @@ exports[`PostPublishPanel should render the post-publish panel if the post is pu
-
@@ -63,7 +63,7 @@ exports[`PostPublishPanel should render the post-publish panel if the post is sc
-
@@ -99,7 +99,7 @@ exports[`PostPublishPanel should render the pre-publish panel if post status is
-
@@ -135,7 +135,7 @@ exports[`PostPublishPanel should render the pre-publish panel if the post is not
-
@@ -171,7 +171,7 @@ exports[`PostPublishPanel should render the spinner if the post is being saved 1