1eeb6f10创建于 6 天前历史提交
import { useLayoutEffect, useState } from 'react';

export const MIN_PREVIEW_WIDTH = 320;

const sameFrame = (a, b) =>
  a !== null &&
  b !== null &&
  a.top === b.top &&
  a.left === b.left &&
  a.height === b.height &&
  a.fullWidth === b.fullWidth;

const readFrame = panel => {
  const demo = panel.querySelector('.demo-container');
  const parent = demo?.parentElement;
  if (!demo || !parent) return { demo: null, frame: null };
  const panelRect = panel.getBoundingClientRect();
  const demoRect = demo.getBoundingClientRect();
  if (panelRect.width === 0 || demoRect.width === 0) return { demo, frame: null };
  const parentRect = parent.getBoundingClientRect();
  const contentRight =
    parentRect.left + parent.clientLeft + parent.clientWidth - parseFloat(getComputedStyle(parent).paddingRight);
  return {
    demo,
    frame: {
      top: demoRect.top - panelRect.top - panel.clientTop,
      left: demoRect.left - panelRect.left - panel.clientLeft,
      height: demoRect.height,
      fullWidth: Math.max(MIN_PREVIEW_WIDTH, Math.floor(contentRight - demoRect.left))
    }
  };
};

export const usePreviewFrame = (panelRef, enabled) => {
  const [frame, setFrame] = useState(null);

  useLayoutEffect(() => {
    const panel = panelRef.current;
    if (!enabled || !panel) {
      setFrame(null);
      return undefined;
    }
    let observed = null;
    const measure = () => {
      const { demo, frame: next } = readFrame(panel);
      if (demo !== observed) {
        if (observed) observer.unobserve(observed);
        if (demo) observer.observe(demo);
        observed = demo;
      }
      setFrame(prev => (sameFrame(prev, next) ? prev : next));
    };
    const observer = new ResizeObserver(measure);
    observer.observe(panel);
    measure();
    return () => observer.disconnect();
  }, [enabled, panelRef]);

  return frame;
};