This commit is contained in:
		
							parent
							
								
									556e0b2336
								
							
						
					
					
						commit
						4958fb1346
					
				
					 1 changed files with 102 additions and 55 deletions
				
			
		| 
						 | 
				
			
			@ -14,29 +14,41 @@ type Props = {
 | 
			
		|||
  anchor: () => DOMRect;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function adjustMenuPosition(
 | 
			
		||||
  rect: DOMRect,
 | 
			
		||||
  [left, top]: [number, number],
 | 
			
		||||
  { width, height }: { width: number; height: number },
 | 
			
		||||
) {
 | 
			
		||||
  const ntop = rect.bottom > height ? top - (rect.bottom - height) : top;
 | 
			
		||||
  const nleft = rect.right > width ? left - (rect.right - width) : left;
 | 
			
		||||
  return [nleft, ntop] as [number, number];
 | 
			
		||||
function px(n?: number) {
 | 
			
		||||
  if (n) {
 | 
			
		||||
    return `${n}px`;
 | 
			
		||||
  } else {
 | 
			
		||||
    return undefined;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const Menu: ParentComponent<Props> = (props) => {
 | 
			
		||||
  let root: HTMLDialogElement;
 | 
			
		||||
  const [pos, setPos] = createSignal<[number, number]>([0, 0]);
 | 
			
		||||
  const windowSize = useWindowSize();
 | 
			
		||||
 | 
			
		||||
  const [anchorPos, setAnchorPos] = createSignal<{
 | 
			
		||||
    left?: number;
 | 
			
		||||
    top?: number;
 | 
			
		||||
  }>({});
 | 
			
		||||
 | 
			
		||||
  let openAnimationOrigin: "lt" | "rt" = "lt";
 | 
			
		||||
 | 
			
		||||
  createEffect(() => {
 | 
			
		||||
    if (props.open) {
 | 
			
		||||
      const a = props.anchor();
 | 
			
		||||
 | 
			
		||||
      if (!root.open) {
 | 
			
		||||
        root.showModal();
 | 
			
		||||
        const rend = root.getBoundingClientRect();
 | 
			
		||||
 | 
			
		||||
        setPos(adjustMenuPosition(rend, [a.left, a.top], windowSize));
 | 
			
		||||
        const { width } = windowSize;
 | 
			
		||||
        const { left, top, right } = a;
 | 
			
		||||
        if (left > width / 2) {
 | 
			
		||||
          openAnimationOrigin = "rt";
 | 
			
		||||
          setAnchorPos({
 | 
			
		||||
            left: right - rend.width,
 | 
			
		||||
            top,
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
          const overflow = root.style.overflow;
 | 
			
		||||
          root.style.overflow = "hidden";
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +57,6 @@ const Menu: ParentComponent<Props> = (props) => {
 | 
			
		|||
          const animation = root.animate(
 | 
			
		||||
            {
 | 
			
		||||
              height: [`${rend.height / 2}px`, `${rend.height}px`],
 | 
			
		||||
            width: [`${rend.width / 4 * 3}px`, `${rend.width}px`],
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              duration,
 | 
			
		||||
| 
						 | 
				
			
			@ -57,13 +68,30 @@ const Menu: ParentComponent<Props> = (props) => {
 | 
			
		|||
            () => (root.style.overflow = overflow),
 | 
			
		||||
          );
 | 
			
		||||
        } else {
 | 
			
		||||
        setPos(
 | 
			
		||||
          adjustMenuPosition(
 | 
			
		||||
            root.getBoundingClientRect(),
 | 
			
		||||
            [a.left, a.top],
 | 
			
		||||
            windowSize,
 | 
			
		||||
          ),
 | 
			
		||||
          openAnimationOrigin = "lt";
 | 
			
		||||
          setAnchorPos({ left, top });
 | 
			
		||||
 | 
			
		||||
          const overflow = root.style.overflow;
 | 
			
		||||
          root.style.overflow = "hidden";
 | 
			
		||||
          const duration = (rend.height / 1600) * 1000;
 | 
			
		||||
          const easing = ANIM_CURVE_STD;
 | 
			
		||||
          const animation = root.animate(
 | 
			
		||||
            {
 | 
			
		||||
              height: [`${rend.height / 2}px`, `${rend.height}px`],
 | 
			
		||||
              width: [`${(rend.width / 4) * 3}px`, `${rend.width}px`],
 | 
			
		||||
            },
 | 
			
		||||
            {
 | 
			
		||||
              duration,
 | 
			
		||||
              easing,
 | 
			
		||||
            },
 | 
			
		||||
          );
 | 
			
		||||
          animation.addEventListener(
 | 
			
		||||
            "finish",
 | 
			
		||||
            () => (root.style.overflow = overflow),
 | 
			
		||||
          );
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        // TODO: update the pos
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      animateClose();
 | 
			
		||||
| 
						 | 
				
			
			@ -72,12 +100,13 @@ const Menu: ParentComponent<Props> = (props) => {
 | 
			
		|||
 | 
			
		||||
  const animateClose = () => {
 | 
			
		||||
    const rend = root.getBoundingClientRect();
 | 
			
		||||
    if (openAnimationOrigin === "lt") {
 | 
			
		||||
      const overflow = root.style.overflow;
 | 
			
		||||
      root.style.overflow = "hidden";
 | 
			
		||||
      const animation = root.animate(
 | 
			
		||||
        {
 | 
			
		||||
          height: [`${rend.height}px`, `${rend.height / 2}px`],
 | 
			
		||||
        width: [`${rend.width}px`, `${rend.width / 4 * 3}px`],
 | 
			
		||||
          width: [`${rend.width}px`, `${(rend.width / 4) * 3}px`],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          duration: (rend.height / 2 / 1600) * 1000,
 | 
			
		||||
| 
						 | 
				
			
			@ -88,6 +117,23 @@ const Menu: ParentComponent<Props> = (props) => {
 | 
			
		|||
        root.style.overflow = overflow;
 | 
			
		||||
        root.close();
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      const overflow = root.style.overflow;
 | 
			
		||||
      root.style.overflow = "hidden";
 | 
			
		||||
      const animation = root.animate(
 | 
			
		||||
        {
 | 
			
		||||
          height: [`${rend.height}px`, `${rend.height / 2}px`],
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          duration: (rend.height / 2 / 1600) * 1000,
 | 
			
		||||
          easing: ANIM_CURVE_STD,
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
      animation.addEventListener("finish", () => {
 | 
			
		||||
        root.style.overflow = overflow;
 | 
			
		||||
        root.close();
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
| 
						 | 
				
			
			@ -111,14 +157,15 @@ const Menu: ParentComponent<Props> = (props) => {
 | 
			
		|||
        }
 | 
			
		||||
      }}
 | 
			
		||||
      style={{
 | 
			
		||||
        position: "absolute",
 | 
			
		||||
        left: `${pos()[0]}px`,
 | 
			
		||||
        top: `${pos()[1]}px`,
 | 
			
		||||
        position: "fixed",
 | 
			
		||||
        left: px(anchorPos().left),
 | 
			
		||||
        top: px(anchorPos().top),
 | 
			
		||||
        border: "none",
 | 
			
		||||
        "border-radius": "2px",
 | 
			
		||||
        padding: 0,
 | 
			
		||||
        "max-width": "560px",
 | 
			
		||||
        width: "max-content",
 | 
			
		||||
        /*"min-width": "20vw", */
 | 
			
		||||
        /* FIXME: the content may be overflow */
 | 
			
		||||
        "box-shadow": "var(--tutu-shadow-e8)",
 | 
			
		||||
      }}
 | 
			
		||||
    >
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue