Skip to content

Commit

Permalink
compose: Add types to useRefEffect and clipboard hooks (#31603)
Browse files Browse the repository at this point in the history
* compose: Add types to useRefEffect and clipboard hooks

* Use `RefCallback` type

* Node can be null

* Use HTMLElement for useRefCallback

* compose: Make `useRefEffect` generic; also fix docgen for default exports

* Update CHANGELOG for docgen

* Mark timeout as optional
  • Loading branch information
sarayourfriend authored May 27, 2021
1 parent 45e1997 commit 33d709b
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 28 deletions.
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"@testing-library/react": "11.2.2",
"@testing-library/react-native": "7.1.0",
"@types/classnames": "2.2.10",
"@types/clipboard": "2.0.1",
"@types/eslint": "6.8.0",
"@types/estree": "0.0.44",
"@types/highlight-words-core": "1.2.0",
Expand Down
14 changes: 7 additions & 7 deletions packages/compose/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@ Copies the text to the clipboard when the element is clicked.

_Parameters_

- _ref_ `Object`: Reference with the element.
- _ref_ `import('react').RefObject<string | Element | NodeListOf<Element>>`: Reference with the element.
- _text_ `string|Function`: The text to copy.
- _timeout_ `number`: Optional timeout to reset the returned state. 4 seconds by default.
- _timeout_ `[number]`: Optional timeout to reset the returned state. 4 seconds by default.

_Returns_

Expand All @@ -180,12 +180,12 @@ Copies the given text to the clipboard when the element is clicked.

_Parameters_

- _text_ `text|Function`: The text to copy. Use a function if not already available and expensive to compute.
- _text_ `string | (() => string)`: The text to copy. Use a function if not already available and expensive to compute.
- _onSuccess_ `Function`: Called when to text is copied.

_Returns_

- `RefObject`: A ref to assign to the target element.
- `import('react').Ref<HTMLElement>`: A ref to assign to the target element.

<a name="useDebounce" href="#useDebounce">#</a> **useDebounce**

Expand Down Expand Up @@ -398,12 +398,12 @@ callback will be called multiple times for the same node.

_Parameters_

- _callback_ `Function`: Callback with ref as argument.
- _dependencies_ `Array`: Dependencies of the callback.
- _callback_ `( node: TElement ) => ( () => void ) | undefined`: Callback with ref as argument.
- _dependencies_ `DependencyList`: Dependencies of the callback.

_Returns_

- `Function`: Ref callback.
- `RefCallback< TElement | null >`: Ref callback.

<a name="useResizeObserver" href="#useResizeObserver">#</a> **useResizeObserver**

Expand Down
20 changes: 15 additions & 5 deletions packages/compose/src/hooks/use-copy-on-click/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,32 +9,40 @@ import Clipboard from 'clipboard';
import { useRef, useEffect, useState } from '@wordpress/element';
import deprecated from '@wordpress/deprecated';

/* eslint-disable jsdoc/no-undefined-types */
/**
* Copies the text to the clipboard when the element is clicked.
*
* @deprecated
*
* @param {Object} ref Reference with the element.
* @param {string|Function} text The text to copy.
* @param {number} timeout Optional timeout to reset the returned
* @param {import('react').RefObject<string | Element | NodeListOf<Element>>} ref Reference with the element.
* @param {string|Function} text The text to copy.
* @param {number} [timeout] Optional timeout to reset the returned
* state. 4 seconds by default.
*
* @return {boolean} Whether or not the text has been copied. Resets after the
* timeout.
*/
export default function useCopyOnClick( ref, text, timeout = 4000 ) {
/* eslint-enable jsdoc/no-undefined-types */
deprecated( 'wp.compose.useCopyOnClick', {
since: '10.3',
plugin: 'Gutenberg',
alternative: 'wp.compose.useCopyToClipboard',
} );

/** @type {import('react').MutableRefObject<Clipboard | undefined>} */
const clipboard = useRef();
const [ hasCopied, setHasCopied ] = useState( false );

useEffect( () => {
/** @type {number | undefined} */
let timeoutId;

if ( ! ref.current ) {
return;
}

// Clipboard listens to click events.
clipboard.current = new Clipboard( ref.current, {
text: () => ( typeof text === 'function' ? text() : text ),
Expand All @@ -48,7 +56,7 @@ export default function useCopyOnClick( ref, text, timeout = 4000 ) {

// Handle ClipboardJS focus bug, see https://github.com/zenorocha/clipboard.js/issues/680
if ( trigger ) {
trigger.focus();
/** @type {HTMLElement} */ ( trigger ).focus();
}

if ( timeout ) {
Expand All @@ -59,7 +67,9 @@ export default function useCopyOnClick( ref, text, timeout = 4000 ) {
} );

return () => {
clipboard.current.destroy();
if ( clipboard.current ) {
clipboard.current.destroy();
}
clearTimeout( timeoutId );
};
}, [ text, timeout, setHasCopied ] );
Expand Down
21 changes: 12 additions & 9 deletions packages/compose/src/hooks/use-copy-to-clipboard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ import { useRef } from '@wordpress/element';
*/
import useRefEffect from '../use-ref-effect';

/** @typedef {import('@wordpress/element').RefObject} RefObject */

/**
* @template T
* @param {T} value
* @return {import('react').RefObject<T>} The updated ref
*/
function useUpdatedRef( value ) {
const ref = useRef( value );
ref.current = value;
Expand All @@ -24,24 +27,24 @@ function useUpdatedRef( value ) {
/**
* Copies the given text to the clipboard when the element is clicked.
*
* @param {text|Function} text The text to copy. Use a function if not
* @param {string | (() => string)} text The text to copy. Use a function if not
* already available and expensive to compute.
* @param {Function} onSuccess Called when to text is copied.
* @param {Function} onSuccess Called when to text is copied.
*
* @return {RefObject} A ref to assign to the target element.
* @return {import('react').Ref<HTMLElement>} A ref to assign to the target element.
*/
export default function useCopyToClipboard( text, onSuccess ) {
// Store the dependencies as refs and continuesly update them so they're
// fresh when the callback is called.
const textRef = useUpdatedRef( text );
const onSuccesRef = useUpdatedRef( onSuccess );
const onSuccessRef = useUpdatedRef( onSuccess );
return useRefEffect( ( node ) => {
// Clipboard listens to click events.
const clipboard = new Clipboard( node, {
text() {
return typeof textRef.current === 'function'
? textRef.current()
: textRef.current;
: textRef.current || '';
},
} );

Expand All @@ -54,8 +57,8 @@ export default function useCopyToClipboard( text, onSuccess ) {
// https://github.com/zenorocha/clipboard.js/issues/680
node.focus();

if ( onSuccesRef.current ) {
onSuccesRef.current();
if ( onSuccessRef.current ) {
onSuccessRef.current();
}
} );

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
/**
* External dependencies
*/
// eslint-disable-next-line no-restricted-imports
import type { DependencyList, RefCallback } from 'react';

/**
* WordPress dependencies
*/
Expand All @@ -17,14 +23,17 @@ import { useCallback, useRef } from '@wordpress/element';
* to be removed. It *is* necessary if you add dependencies because the ref
* callback will be called multiple times for the same node.
*
* @param {Function} callback Callback with ref as argument.
* @param {Array} dependencies Dependencies of the callback.
* @param callback Callback with ref as argument.
* @param dependencies Dependencies of the callback.
*
* @return {Function} Ref callback.
* @return Ref callback.
*/
export default function useRefEffect( callback, dependencies ) {
const cleanup = useRef();
return useCallback( ( node ) => {
export default function useRefEffect< TElement = Node >(
callback: ( node: TElement ) => ( () => void ) | undefined,
dependencies: DependencyList
): RefCallback< TElement | null > {
const cleanup = useRef< ( () => void ) | undefined >();
return useCallback( ( node: TElement | null ) => {
if ( node ) {
cleanup.current = callback( node );
} else if ( cleanup.current ) {
Expand Down
3 changes: 3 additions & 0 deletions packages/compose/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
"src/hooks/use-async-list/**/*",
"src/hooks/use-constrained-tabbing/**/*",
"src/hooks/use-debounce/**/*",
"src/hooks/use-copy-on-click/**/*",
"src/hooks/use-copy-to-clipboard/**/*",
"src/hooks/use-focus-return/**/*",
"src/hooks/use-ref-effect/**/*",
"src/hooks/use-instance-id/**/*",
"src/hooks/use-isomorphic-layout-effect/**/*",
"src/hooks/use-keyboard-shortcut/**/*",
Expand Down
4 changes: 4 additions & 0 deletions packages/docgen/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

### Bug Fixes

- Fix getting param annotations for default exported functions. ([#31603](https://github.com/WordPress/gutenberg/pull/31603))

## 1.17.0 (2021-04-29)

### New Features
Expand Down
8 changes: 7 additions & 1 deletion packages/docgen/lib/get-type-annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ function getFunctionTypeAnnotation( typeAnnotation, returnIndicator ) {
typeAnnotation.typeAnnotation.typeAnnotation
);

return `( ${ params } )${ returnIndicator }${ returnType }`;
const paramsWithParens = params.length ? `( ${ params } )` : `()`;

return `${ paramsWithParens }${ returnIndicator }${ returnType }`;
}

/**
Expand Down Expand Up @@ -376,6 +378,10 @@ function getTypeAnnotation( typeAnnotation ) {
*/
function getFunctionToken( token ) {
let resolvedToken = token;
if ( babelTypes.isExportDefaultDeclaration( resolvedToken ) ) {
resolvedToken = resolvedToken.declaration;
}

if ( babelTypes.isExportNamedDeclaration( resolvedToken ) ) {
resolvedToken = resolvedToken.declaration;
}
Expand Down

0 comments on commit 33d709b

Please sign in to comment.