Skip to content

Instantly share code, notes, and snippets.

@DylanVann
Created September 11, 2024 01:50
Show Gist options
  • Select an option

  • Save DylanVann/9ad5e616e8ea7923095ac1cb8a08d5bc to your computer and use it in GitHub Desktop.

Select an option

Save DylanVann/9ad5e616e8ea7923095ac1cb8a08d5bc to your computer and use it in GitHub Desktop.
import { useEffect, useRef, useState } from "react";
import "./styles.css";
import { Info } from "@mui/icons-material";
import { Box } from "@mui/material";
import { CSSTransition } from "react-transition-group";

const lorem = (
  <p>
    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam mattis ut
    lectus vel tincidunt. Fusce ipsum lacus, aliquam et tempor eget, dignissim a
    diam. Suspendisse eleifend, magna sed ullamcorper porttitor, justo orci
    facilisis purus, ac sagittis neque tellus in purus. Fusce eu lacus mauris.
    Integer aliquet mauris libero, et tincidunt leo aliquet eu. Quisque dapibus
    fringilla velit, ac luctus neque lacinia at. Fusce eros lorem, hendrerit
    scelerisque metus ac, pellentesque gravida tortor.
  </p>
);

function App() {
  const [isOpen, setIsOpen] = useState(false);
  const nodeRef = useRef<HTMLDivElement>(null);
  const triggerRef = useRef<HTMLDivElement>(null);

  const handleClosePopover = () => {
    setIsOpen(false);
  };

  useEffect(() => {
    if (!isOpen) {
      return;
    }

    // Close on scroll
    const handleScroll = () => {
      if (isOpen) {
        handleClosePopover();
      }
    };

    // Close if clicking outside
    const handleClick = (event: MouseEvent) => {
      if (
        triggerRef.current &&
        triggerRef.current.contains(event.target as Node)
      ) {
        return;
      }
      console.log("close on click");
      handleClosePopover();
    };

    document.addEventListener("scroll", handleScroll);
    document.addEventListener("click", handleClick);

    return () => {
      document.removeEventListener("scroll", handleScroll);
      document.removeEventListener("click", handleClick);
    };
  }, [isOpen]);

  return (
    <div
      style={{
        maxWidth: "600px",
        margin: "0 auto",
        display: "flex",
        flexDirection: "column",
        gap: 10,
      }}
    >
      {lorem}
      <div
        ref={triggerRef}
        onClick={() => setIsOpen((open) => !open)}
        style={{
          display: "flex",
          justifyContent: "center",
          alignItems: "center",
          marginTop: "20px",
          position: "relative",
        }}
      >
        <Info style={{ marginRight: "8px" }} />
        <span>Important information goes here</span>
        <CSSTransition
          in={isOpen}
          timeout={300}
          classNames="tooltip"
          nodeRef={nodeRef}
          unmountOnExit
        >
          <Box
            ref={nodeRef}
            style={{
              position: "absolute",
              top: -100,
              left: -100,
              right: -100,
              bottom: "calc(100% + 10px)",
              border: "1px solid black",
              backgroundColor: "white",
              alignItems: "center",
              justifyContent: "center",
              display: "flex",
              flexDirection: "column",
              boxShadow: "0 0 10px 0 rgba(0, 0, 0, 0.1)",
            }}
          >
            <div>The tooltip content.</div>
            <div
              style={{
                width: "12px",
                height: "12px",
                backgroundColor: "white",
                position: "absolute",
                bottom: "-7px",
                left: "calc(50% - 6px)",
                transform: "rotate(45deg)",
                borderRight: "1px solid black",
                borderBottom: "1px solid black",
                boxShadow: "2px 2px 5px -2px rgba(0, 0, 0, 0.1)",
              }}
            />
          </Box>
        </CSSTransition>
      </div>
      {lorem}
      {lorem}
      {lorem}
      {lorem}
      {lorem}
      {lorem}
      {lorem}
      {lorem}
      {lorem}
    </div>
  );
}

export default App;
.tooltip-enter {
  opacity: 0;
  transform: translateY(10px) scale(0.95);
}

.tooltip-enter-active {
  opacity: 1;
  transform: translateY(0) scale(1);
  transition: opacity 300ms, transform 300ms;
}

.tooltip-exit {
  opacity: 1;
  transform: translateY(0) scale(1);
}

.tooltip-exit-active {
  opacity: 0;
  transform: translateY(10px) scale(0.95);
  transition: opacity 300ms, transform 300ms;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment