'use client'; import { useEffect, useState } from 'react'; /** * Returns the combined height (px) of the sticky page header and announcement * bar (if present), updated live via ResizeObserver / MutationObserver. * Useful for offsetting fixed/absolute-positioned panels so they don't * overlap the header. */ export function useHeaderHeight( // First-paint fallback = the unified top-navigation `big` bar (72px), the // size every hub/marketing site renders; replaced by the live measurement. defaultHeight = 72, options: { /** * When false, no observers are attached and the default height is * returned — for consumers that stay mounted on every page but only need * the measurement while an overlay is open (avoids an always-on * document-wide MutationObserver + forced reflow). * @default true */ enabled?: boolean; } = {}, ): number { const { enabled = true } = options; const [height, setHeight] = useState(defaultHeight); useEffect(() => { if (!enabled) return undefined; const measure = () => { let total = 0; const header = document.querySelector('header'); if (header) total += header.offsetHeight; const bar = document.querySelector('[data-announcement-bar]'); if (bar instanceof HTMLElement) total += bar.offsetHeight; setHeight(total > 0 ? total : defaultHeight); }; measure(); const resizeObserver = new ResizeObserver(measure); const header = document.querySelector('header'); if (header) resizeObserver.observe(header); const bar = document.querySelector('[data-announcement-bar]'); if (bar) resizeObserver.observe(bar); const mutationObserver = new MutationObserver(mutations => { for (const mutation of mutations) { if (mutation.type === 'childList' || mutation.type === 'attributes') { measure(); const newBar = document.querySelector('[data-announcement-bar]'); if (newBar) resizeObserver.observe(newBar); } } }); mutationObserver.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['data-announcement-bar'], }); return () => { resizeObserver.disconnect(); mutationObserver.disconnect(); }; }, [defaultHeight, enabled]); return height; }