Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | import { useCallback, useRef, useState, type DependencyList, type RefCallback } from 'react'; import { useMergedRef } from '../use-merged-ref/useMergedRef'; import { useResizeObserver, type UseResizeObserverOptions } from '../use-resize-observer/useResizeObserver'; import { useUpdateEffect } from '../use-update-effect/useUpdateEffect'; const isTextCutOff = <TElement extends HTMLElement>(element: TElement | null) => !!element && (element.offsetWidth < element.scrollWidth || element.offsetHeight < element.scrollHeight); export type UseTextOverflowsValue<TElement extends HTMLElement> = { ref: RefCallback<TElement>; doesTextOverflow: boolean; }; /** * Find out if a text overflows (when using text-overflow). This uses ResizeObserver. * * @param deps - Dependencies to update the text overflow state (aka pass the content of the element being observed). */ export const useTextOverflows = <TElement extends HTMLElement>( deps: DependencyList = [], ): UseTextOverflowsValue<TElement> => { const [doesTextOverflow, setDoesTextOverflow] = useState<boolean>(false); const onResize: UseResizeObserverOptions<TElement>['onResize'] = useCallback( (_, element) => setDoesTextOverflow(isTextCutOff(element)), [], ); const observerRef = useResizeObserver({ onResize }); const internalRef = useRef<TElement>(null); const mergedRef = useMergedRef<TElement>(observerRef, internalRef); // eslint-disable-next-line react-hooks/exhaustive-deps -- Array must be static. useUpdateEffect(() => setDoesTextOverflow(isTextCutOff(internalRef.current)), deps); return { ref: mergedRef, doesTextOverflow, }; }; |