{"version":3,"file":"useResize-Drcue2KL.mjs","names":[],"sources":["../src/react-util/useMergedRef.ts","../src/react-util/useResize.ts"],"sourcesContent":["import { useCallback } from \"react\";\n\n/**\n * Combines several refs into one callback ref, so a component can keep its own internal ref while\n * still handing the element to a caller.\n *\n * The point is composition: a component that owns a ref for its own measurement or event wiring\n * can't simply accept a `ref` prop and forward it, because only one can win. Merging lets both\n * hold the same element, which is what makes a component usable as the child of a primitive that\n * needs the DOM node too — `asChild`-style composition being the usual reason.\n *\n * Nulls are skipped, so an optional incoming `ref` needs no guard at the call site. Callback refs\n * get their cleanup handled by React 19's return-value contract; object refs are assigned directly.\n *\n * The merged callback is stable as long as the refs passed in are, so it does not detach and\n * re-attach the element on every render. Pass a stable `ref` from props (React does this already)\n * rather than a fresh inline arrow.\n */\nexport const useMergedRef = <T>(...refs: (React.Ref<T> | undefined)[]): React.RefCallback<T> =>\n  useCallback(\n    (node: T | null) => {\n      const cleanups: (() => void)[] = [];\n      for (const ref of refs) {\n        if (!ref) continue;\n        if (typeof ref === \"function\") {\n          const cleanup = ref(node);\n          if (typeof cleanup === \"function\") cleanups.push(cleanup);\n        } else {\n          ref.current = node;\n        }\n      }\n      return () => {\n        for (const cleanup of cleanups) cleanup();\n      };\n    },\n    // the ref list *is* the dependency list — a new identity in it should produce a new callback\n    refs,\n  );\n","import { useLayoutEffect, useRef } from \"react\";\n\nexport interface UseResizeOptions {\n  /**\n   * Which box to report. Defaults to `\"content\"`.\n   *\n   * `\"border\"` includes padding and border, and is what you want when the number has to account\n   * for space a *consumer* controls — measuring an element whose padding is part of the layout\n   * budget, for instance. A padding change alters the border-box size, so the observer fires on it\n   * and the measurement stays complete with no extra trigger.\n   *\n   * It still can't see a *margin*, which sits outside the border box. If margins matter, they have\n   * to be part of the contract rather than measured.\n   */\n  box?: \"content\" | \"border\";\n}\n\n/**\n * Reports an element's size whenever it changes, including the initial measurement.\n *\n * The default content box means padding, border and scrollbars are all excluded — so a width fed\n * back into layout math can't feed back into its own overflow, and a gutter appearing or\n * disappearing is reported as a real size change. Pass `{ box: \"border\" }` when padding and border\n * should be included instead. Values are fractional; round at the point of use if you need\n * integers.\n *\n * `onResize` is read through a ref, so passing an inline arrow does not tear down and re-create the\n * observer on every render.\n */\nexport const useResize = (\n  ref: React.RefObject<HTMLElement | null>,\n  onResize: (width: number, height: number) => void,\n  options?: UseResizeOptions,\n): void => {\n  const onResizeRef = useRef(onResize);\n  onResizeRef.current = onResize;\n\n  const box = options?.box ?? \"content\";\n\n  useLayoutEffect(() => {\n    const el = ref.current;\n    if (!el) {\n      return;\n    }\n\n    if (typeof ResizeObserver !== \"function\") {\n      // Fallback for environments without ResizeObserver. `clientWidth`/`clientHeight` are the\n      // padding box (scrollbars already excluded), so the content-box path over-reports by any\n      // padding — close enough for a path no supported browser takes. `offsetWidth`/`offsetHeight`\n      // are the border box exactly.\n      const handleResize = () =>\n        box === \"border\"\n          ? onResizeRef.current(el.offsetWidth, el.offsetHeight)\n          : onResizeRef.current(el.clientWidth, el.clientHeight);\n      handleResize();\n      window.addEventListener(\"resize\", handleResize);\n      return () => window.removeEventListener(\"resize\", handleResize);\n    }\n\n    // The initial observation is delivered before the first paint, so no eager measure is needed.\n    const observer = new ResizeObserver((entries) => {\n      const entry = entries[0];\n      if (!entry) {\n        return;\n      }\n      if (box === \"border\") {\n        // `borderBoxSize` is an array (one entry per fragment); a non-fragmented element has one.\n        // Its inline/block axes map to width/height in the default writing mode. Falling back to\n        // the offset dimensions keeps this correct where the observer predates `borderBoxSize`.\n        const size = entry.borderBoxSize?.[0];\n        onResizeRef.current(size?.inlineSize ?? el.offsetWidth, size?.blockSize ?? el.offsetHeight);\n        return;\n      }\n      onResizeRef.current(entry.contentRect.width, entry.contentRect.height);\n    });\n\n    observer.observe(el, box === \"border\" ? { box: \"border-box\" } : undefined);\n    return () => observer.disconnect();\n  }, [ref, box]);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAkBA,MAAa,gBAAmB,GAAG,SACjC,aACG,SAAmB;CAClB,MAAM,WAA2B,CAAC;CAClC,KAAK,MAAM,OAAO,MAAM;EACtB,IAAI,CAAC,KAAK;EACV,IAAI,OAAO,QAAQ,YAAY;GAC7B,MAAM,UAAU,IAAI,IAAI;GACxB,IAAI,OAAO,YAAY,YAAY,SAAS,KAAK,OAAO;EAC1D,OACE,IAAI,UAAU;CAElB;CACA,aAAa;EACX,KAAK,MAAM,WAAW,UAAU,QAAQ;CAC1C;AACF,GAEA,IACF;;;;;;;;;;;;;;;;ACRF,MAAa,aACX,KACA,UACA,YACS;CACT,MAAM,cAAc,OAAO,QAAQ;CACnC,YAAY,UAAU;CAEtB,MAAM,MAAM,SAAS,OAAO;CAE5B,sBAAsB;EACpB,MAAM,KAAK,IAAI;EACf,IAAI,CAAC,IACH;EAGF,IAAI,OAAO,mBAAmB,YAAY;GAKxC,MAAM,qBACJ,QAAQ,WACJ,YAAY,QAAQ,GAAG,aAAa,GAAG,YAAY,IACnD,YAAY,QAAQ,GAAG,aAAa,GAAG,YAAY;GACzD,aAAa;GACb,OAAO,iBAAiB,UAAU,YAAY;GAC9C,aAAa,OAAO,oBAAoB,UAAU,YAAY;EAChE;EAGA,MAAM,WAAW,IAAI,gBAAgB,YAAY;GAC/C,MAAM,QAAQ,QAAQ;GACtB,IAAI,CAAC,OACH;GAEF,IAAI,QAAQ,UAAU;IAIpB,MAAM,OAAO,MAAM,gBAAgB;IACnC,YAAY,QAAQ,MAAM,cAAc,GAAG,aAAa,MAAM,aAAa,GAAG,YAAY;IAC1F;GACF;GACA,YAAY,QAAQ,MAAM,YAAY,OAAO,MAAM,YAAY,MAAM;EACvE,CAAC;EAED,SAAS,QAAQ,IAAI,QAAQ,WAAW,EAAE,KAAK,aAAa,IAAI,MAAS;EACzE,aAAa,SAAS,WAAW;CACnC,GAAG,CAAC,KAAK,GAAG,CAAC;AACf"}