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