UNPKG

@primer/react

Version:

An implementation of GitHub's Primer Design System using React

87 lines (81 loc) 2.53 kB
import { c } from 'react-compiler-runtime'; import 'react'; /** * Combine two refs of matching type (typically an external or forwarded ref and an internal `useRef` object or * callback ref). * * If you need to combine more than two refs (what are you doing?) just nest the hook: * `useMergedRefs(refA, useMergedRefs(refB, refC))` * * @param refA First ref to merge. The order is not important. * @param refB Second ref to merge. The order is not important. * @returns A new ref which must be passed to the relevant child component. **Important**: do not pass `refA` or * `refB` to the component! * * @example * // React 18 * const Example = forwardRef<HTMLButtonElement, {}>((props, forwardedRef) => { * const ref = useRef<HTMLButtonElement>(null) * const combinedRef = useMergedRefs(forwardedRef, ref) * * return <button ref={combinedRef} /> * }) * * @example * // React 19 * const Example = ({ref: externalRef}: {ref?: Ref<HTMLButtonElement>}) => { * const ref = useRef<HTMLButtonElement>(null) * const combinedRef = useMergedRefs(externalRef, ref) * * return <button ref={combinedRef} /> * } */ function useMergedRefs(refA, refB) { const $ = c(3); let t0; if ($[0] !== refA || $[1] !== refB) { t0 = value => { const cleanupA = setRef(refA, value); const cleanupB = setRef(refB, value); return () => { if (cleanupA) { cleanupA(); } else { setRef(refA, null); } if (cleanupB) { cleanupB(); } else { setRef(refB, null); } }; }; $[0] = refA; $[1] = refB; $[2] = t0; } else { t0 = $[2]; } return t0; } /** * React 19 supports callback refs that can return a cleanup function. If a cleanup function is returned, the * cleanup is called on unmount **instead** of setting the ref to null. */ // bivarianceHack copied from React types /** * Supporting React 18 and 19 while alleviating the need for any hacks or casts in consumers: * - `ForwardedRef` from the React 18 `forwardRef` HOC * - `React19RefCallback` for callback refs that can return a cleanup function (this is included in `Ref` in React 19 * but not in 18) * - `Ref` for standard refs from `useRef` or passed in as React 19 prop * - `undefined` to allow for easy use of optional `ref` props in React 19 */ function setRef(ref, value) { if (typeof ref === 'function') { return ref(value); } else if (ref) { ref.current = value; } } export { useMergedRefs };