UNPKG

@hashicorp/react-subnav

Version:

Displays a navigation bar, with links and a call-to-action.

83 lines (57 loc) 2.01 kB
/** * Copyright (c) HashiCorp, Inc. * SPDX-License-Identifier: MPL-2.0 */ import { useCallback, useState } from 'react' const MutationObserver = (typeof window !== 'undefined' && window.MutationObserver) || null const mutationOpts = { attributes: true, childList: true, subtree: true } /* Overflow is determined by whether the width of a target element’s content is greater than the width of its layout. Overflow is checked on viewport resize and on a target element’s DOM mutation. Both are throttled by animation frame requests. MutationObserver Compatibility (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver): - Chrome 26+ - Edge 12+ - Firefox 14+ - Internet Explorer 11+ - Safari 17+ */ export default function useOverflowRef(deps) { const [[hasOverflow, scrollWidth], setState] = useState([false, 0]) const overflowRef = useCallback((target) => { var viewport let requestId let mutationObserver if (target) { viewport = target.ownerDocument.defaultView viewport.addEventListener('resize', requestOverflow) if (MutationObserver) { mutationObserver = new MutationObserver(requestOverflow) mutationObserver.observe(target, mutationOpts) } requestOverflow() return cleanup } function requestOverflow() { if (!requestId) requestId = requestAnimationFrame(checkOverflow) } function checkOverflow() { requestId = null const nowScrollWidth = target.scrollWidth const nowOffsetWidth = target.offsetWidth const nowHasOverflow = (scrollWidth || nowScrollWidth) > nowOffsetWidth if (hasOverflow !== nowHasOverflow) { cleanup() setState([nowHasOverflow, nowScrollWidth]) } } function cleanup() { cancelAnimationFrame(requestId) viewport.removeEventListener('resize', requestOverflow) if (MutationObserver) mutationObserver.disconnect() } }, deps) return [hasOverflow, overflowRef] }