{
const [ resizeObserver, sizes ] = useResizeObserver();
diff --git a/packages/compose/src/hooks/use-resize-observer/index.ts b/packages/compose/src/hooks/use-resize-observer/index.ts
new file mode 100644
index 0000000000000..2a76b2aa6ab59
--- /dev/null
+++ b/packages/compose/src/hooks/use-resize-observer/index.ts
@@ -0,0 +1,119 @@
+/**
+ * WordPress dependencies
+ */
+import { useRef } from '@wordpress/element';
+/**
+ * Internal dependencies
+ */
+import useEvent from '../use-event';
+import type { ObservedSize } from './_legacy';
+import _useLegacyResizeObserver from './_legacy';
+/**
+ * External dependencies
+ */
+import type { ReactElement } from 'react';
+
+// This is the current implementation of `useResizeObserver`.
+//
+// The legacy implementation is still supported for backwards compatibility.
+// This is achieved by overloading the exported function with both signatures,
+// and detecting which API is being used at runtime.
+function _useResizeObserver< T extends HTMLElement >(
+ callback: ResizeObserverCallback,
+ resizeObserverOptions: ResizeObserverOptions = {}
+): ( element?: T | null ) => void {
+ const callbackEvent = useEvent( callback );
+
+ const observedElementRef = useRef< T | null >();
+ const resizeObserverRef = useRef< ResizeObserver >();
+ return useEvent( ( element?: T | null ) => {
+ if ( element === observedElementRef.current ) {
+ return;
+ }
+ observedElementRef.current = element;
+
+ // Set up `ResizeObserver`.
+ resizeObserverRef.current ??= new ResizeObserver( callbackEvent );
+ const { current: resizeObserver } = resizeObserverRef;
+
+ // Unobserve previous element.
+ if ( observedElementRef.current ) {
+ resizeObserver.unobserve( observedElementRef.current );
+ }
+
+ // Observe new element.
+ if ( element ) {
+ resizeObserver.observe( element, resizeObserverOptions );
+ }
+ } );
+}
+
+/**
+ * Sets up a [`ResizeObserver`](https://developer.mozilla.org/en-US/docs/Web/API/Resize_Observer_API)
+ * for an HTML or SVG element.
+ *
+ * Pass the returned setter as a callback ref to the React element you want
+ * to observe, or use it in layout effects for advanced use cases.
+ *
+ * @example
+ *
+ * ```tsx
+ * const setElement = useResizeObserver(
+ * ( resizeObserverEntries ) => console.log( resizeObserverEntries ),
+ * { box: 'border-box' }
+ * );
+ *
;
+ *
+ * // The setter can be used in other ways, for example:
+ * useLayoutEffect( () => {
+ * setElement( document.querySelector( `data-element-id="${ elementId }"` ) );
+ * }, [ elementId ] );
+ * ```
+ *
+ * @param callback The `ResizeObserver` callback - [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/ResizeObserver#callback).
+ * @param options Options passed to `ResizeObserver.observe` when called - [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/observe#options). Changes will be ignored.
+ */
+export default function useResizeObserver< T extends Element >(
+ /**
+ * The `ResizeObserver` callback - [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/ResizeObserver#callback).
+ */
+ callback: ResizeObserverCallback,
+ /**
+ * Options passed to `ResizeObserver.observe` when called - [MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver/observe#options). Changes will be ignored.
+ */
+ options?: ResizeObserverOptions
+): ( element?: T | null ) => void;
+
+/**
+ * **This is a legacy API and should not be used.**
+ *
+ * @deprecated Use the other `useResizeObserver` API instead: `const ref = useResizeObserver( ( entries ) => { ... } )`.
+ *
+ * Hook which allows to listen to the resize event of any target element when it changes size.
+ * _Note: `useResizeObserver` will report `null` sizes until after first render.
+ *
+ * @example
+ *
+ * ```js
+ * const App = () => {
+ * const [ resizeListener, sizes ] = useResizeObserver();
+ *
+ * return (
+ *
+ * { resizeListener }
+ * Your content here
+ *
+ * );
+ * };
+ * ```
+ */
+export default function useResizeObserver(): [ ReactElement, ObservedSize ];
+
+export default function useResizeObserver< T extends HTMLElement >(
+ callback?: ResizeObserverCallback,
+ options: ResizeObserverOptions = {}
+): ( ( element?: T | null ) => void ) | [ ReactElement, ObservedSize ] {
+ return callback
+ ? _useResizeObserver( callback, options )
+ : _useLegacyResizeObserver();
+}
diff --git a/packages/compose/src/index.js b/packages/compose/src/index.js
index f7e1d1618f97f..29a9aa6173744 100644
--- a/packages/compose/src/index.js
+++ b/packages/compose/src/index.js
@@ -25,6 +25,7 @@ export { default as useCopyOnClick } from './hooks/use-copy-on-click';
export { default as useCopyToClipboard } from './hooks/use-copy-to-clipboard';
export { default as __experimentalUseDialog } from './hooks/use-dialog';
export { default as useDisabled } from './hooks/use-disabled';
+export { default as useEvent } from './hooks/use-event';
export { default as __experimentalUseDragging } from './hooks/use-dragging';
export { default as useFocusOnMount } from './hooks/use-focus-on-mount';
export { default as __experimentalUseFocusOutside } from './hooks/use-focus-outside';
diff --git a/packages/docgen/lib/get-type-annotation.js b/packages/docgen/lib/get-type-annotation.js
index b844c86ef7958..5e72724952f29 100644
--- a/packages/docgen/lib/get-type-annotation.js
+++ b/packages/docgen/lib/get-type-annotation.js
@@ -401,6 +401,10 @@ function getTypeAnnotation( typeAnnotation ) {
* TODO: Remove the special-casing here once we're able to infer the types from TypeScript itself.
*/
function unwrapWrappedSelectors( token ) {
+ if ( babelTypes.isTSDeclareFunction( token ) ) {
+ return token;
+ }
+
if ( babelTypes.isFunctionDeclaration( token ) ) {
return token;
}