framer-motion#AnimateSharedLayout TypeScript Examples

The following examples show how to use framer-motion#AnimateSharedLayout. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: projects.tsx    From portfolio with MIT License 6 votes vote down vote up
Projects: React.FC<ProjectsProps> = ({ projects }) => {
  return (
    <VStack align="start" spacing={8}>
      <Header underlineColor={ORANGE} mt={0} mb={0}>
        Projects
      </Header>
      <AnimateSharedLayout>
        <SimpleGrid columns={1} spacing={4} mt={5} w="100%">
          {projects.map((project, index) => (
            <MotionBox whileHover={{ y: -5 }} key={index}>
              <ProjectCard
                key={project.id}
                title={project.title}
                description={project.desc}
                blurHash={project.blurHash}
                logo={project.logo}
                link={project.link}
                technologies={project.technologies}
              />
            </MotionBox>
          ))}
        </SimpleGrid>
      </AnimateSharedLayout>
    </VStack>
  );
}
Example #2
Source File: _app.tsx    From rcvr-app with GNU Affero General Public License v3.0 6 votes vote down vote up
RecoverApp: RecoverAppFC = ({
  Component,
  pageProps: { localeContext, ...pageProps },
}) => {
  useA11yFocusRing()

  return (
    <ThemeProvider theme={theme}>
      <QueryClientProvider client={queryClient}>
        <LocalesContextProvider value={localeContext}>
          <Global styles={globalStyles} />
          <AnimateSharedLayout>
            <SupportedBrowsersAlert />
            <Component {...pageProps} />
          </AnimateSharedLayout>
        </LocalesContextProvider>
      </QueryClientProvider>
    </ThemeProvider>
  )
}
Example #3
Source File: segmentedcontrol.tsx    From samuelkraft-next with MIT License 6 votes vote down vote up
SegmentedControl = ({ items }: SegmentedControlProps): JSX.Element => {
  const [activeItem, setActiveitem] = useState(0)
  return (
    <AnimateSharedLayout>
      <ol className={styles.list}>
        {items.map((item, i) => {
          const isActive = i === activeItem
          return (
            <motion.li
              className={isActive || i === activeItem - 1 ? styles.itemNoDivider : styles.item}
              whileTap={isActive ? { scale: 0.95 } : { opacity: 0.6 }}
              key={item}
            >
              <button onClick={() => setActiveitem(i)} type="button" className={styles.button}>
                {isActive && <motion.div layoutId="SegmentedControlActive" className={styles.active} />}
                <span className={styles.label}>{item}</span>
              </button>
            </motion.li>
          )
        })}
      </ol>
    </AnimateSharedLayout>
  )
}
Example #4
Source File: SidebarOverlay.tsx    From meshtastic-web with GNU General Public License v3.0 5 votes vote down vote up
SidebarOverlay = ({
  title,
  open,
  close,
  direction,
  children,
}: SidebarOverlayProps): JSX.Element => {
  return (
    <AnimatePresence>
      {open && (
        <m.div
          className="absolute z-30 flex h-full w-full flex-col bg-white dark:bg-primaryDark"
          animate={direction === 'x' ? { translateX: 0 } : { translateY: 0 }}
          initial={
            direction === 'x' ? { translateX: '-100%' } : { translateY: '100%' }
          }
          exit={
            direction === 'x' ? { translateX: '-100%' } : { translateY: '100%' }
          }
          transition={{ type: 'just' }}
        >
          {/* @ts-expect-error */}
          <AnimateSharedLayout>
            {/* <div className="flex gap-2 border-b border-gray-400 p-2 dark:border-gray-600"> */}
            <div className="bg-white px-1 pt-1 drop-shadow-md dark:bg-primaryDark">
              <div className="flex h-10 gap-1">
                <div className="my-auto">
                  <IconButton
                    onClick={(): void => {
                      close();
                    }}
                    icon={<FiArrowLeft />}
                  />
                </div>
                <div className="my-auto text-lg font-medium dark:text-white">
                  {title}
                </div>
              </div>
            </div>
            <div className="flex-grow overflow-y-auto">{children}</div>
          </AnimateSharedLayout>
        </m.div>
      )}
    </AnimatePresence>
  );
}
Example #5
Source File: themechanger.tsx    From samuelkraft-next with MIT License 5 votes vote down vote up
ThemeChanger = (): JSX.Element => {
  const [mounted, setMounted] = useState(false)
  const [active, setActive] = useState(false)
  const [hovered, setHovered] = useState('')
  const { setTheme, theme } = useTheme()

  // When mounted on client, now we can show the UI
  useEffect(() => setMounted(true), [])

  if (!mounted) return <div className={styles.wrapper} /> // skeleton on server

  return (
    <AnimateSharedLayout>
      <div className={styles.wrapper}>
        <motion.div layout className={styles.menu}>
          <AnimatePresence initial={false}>
            {active && (
              <motion.div
                layout
                initial={{ borderRadius: 26, opacity: 0, scale: 0.9 }}
                exit={{ opacity: 0, scale: 0.9 }}
                animate={{ opacity: 1, scale: 1 }}
                className={styles.bg}
              />
            )}
            {variants.map(variant => {
              const selected = theme === variant
              const isHovered = hovered === variant
              return (
                <Fragment key={variant}>
                  {(selected || active) && (
                    <motion.button
                      onHoverStart={() => setHovered(variant)}
                      layout
                      animate={{ opacity: 1, scale: 1 }}
                      exit={{ opacity: 0, scale: 0.85 }}
                      initial={{ opacity: 0, scale: 0.85 }}
                      type="button"
                      title={variant}
                      key={variant}
                      className={styles.button}
                      onClick={() => {
                        if (!active) {
                          return setActive(true)
                        }
                        setActive(false)
                        return setTheme(variant)
                      }}
                    >
                      {((!active && selected) || isHovered) && (
                        <motion.span layoutId="buttonBackground" className={styles.buttonBackground} />
                      )}
                      <span className={styles.buttonLabel}>{getIcon(variant)}</span>
                    </motion.button>
                  )}
                </Fragment>
              )
            })}
          </AnimatePresence>
        </motion.div>
      </div>
    </AnimateSharedLayout>
  )
}
Example #6
Source File: notes-list.tsx    From notebook with MIT License 4 votes vote down vote up
NotesList: React.SFC<NotesListProps> = ({
  notes,
  handleClick,
  setNotes
}) => {
  const bg = useColorModeValue("white", "#2f3244");
  const [selectedNote, setSelectedNote] = React.useState<note>();
  const toast = useToast();
  const { isOpen, onOpen, onClose } = useDisclosure();

  const onDelete = (
    id: string,
    e: React.MouseEvent<SVGElement, MouseEvent>
  ) => {
    const newNotes: note[] = notes.filter((note: note) => note.id !== id);
    setNotes(newNotes);
    showToast();
    e.stopPropagation();
  };

  const onClick = (id: string, e: React.MouseEvent<SVGElement, MouseEvent>) => {
    handleClick(id);
    e.stopPropagation();
  };

  const handleSelectedNote = (note: note) => {
    setSelectedNote(note);
    onOpen();
  };

  const showToast = () => {
    toast({
      title: "Note deleted.",
      status: "success",
      position: "top",
      duration: 2000,
      isClosable: true
    });
  };

  return (
    <>
      <AnimateSharedLayout type="crossfade">
        <Box minH={"50vh"}>
          {/* <SimpleGrid
            columns={[1, 2, 2, 3]}
            mt="40px"
            gridGap="10px"
            position="relative"
            overflow="hidden"
          > */}
          <StackGrid columnWidth={330}>
            {notes.map(note => (
              <Fade in={true}>
                <motion.div
                  whileHover={{ y: -10 }}
                  layoutId={note.id}
                  onClick={() => handleSelectedNote(note)}
                >
                  <Center py={2} px={2} key={note.id}>
                    <Box
                      maxH={"400px"}
                      w="100%"
                      boxShadow={"lg"}
                      rounded={"md"}
                      p={6}
                      overflow={"hidden"}
                      cursor="pointer"
                      _hover={{ boxShadow: "xl" }}
                      bg={bg}
                      role="group"
                      // onClick={() => handleClick(note.id, true)}
                    >
                      <Stack>
                        <Flex
                          _groupHover={{ justifyContent: "space-between" }}
                          justifyContent="center"
                          align="center"
                        >
                          <Box>
                            <Text
                              color={"green.500"}
                              textTransform={"uppercase"}
                              fontWeight={800}
                              fontSize={"sm"}
                              letterSpacing={1.1}
                            >
                              Note
                            </Text>
                          </Box>
                          <Box
                            _groupHover={{ display: "block" }}
                            display="none"
                          >
                            <HStack spacing="2">
                              <Icon
                                color={"green.500"}
                                _hover={{ color: "green.600" }}
                                _groupHover={{ display: "block" }}
                                as={EditIcon}
                                w={4}
                                h={4}
                                onClick={e => onClick(note.id, e)}
                              />
                              <Icon
                                color={"green.500"}
                                _hover={{ color: "#ca364a" }}
                                _groupHover={{ display: "block" }}
                                as={DeleteIcon}
                                w={4}
                                h={4}
                                onClick={e => onDelete(note.id, e)}
                              />
                            </HStack>
                          </Box>
                        </Flex>
                        <Heading
                          fontSize={"xl"}
                          fontFamily={"body"}
                          textTransform="capitalize"
                          noOfLines={2}
                        >
                          {note.title}
                        </Heading>

                        <Text
                          color={"gray.500"}
                          fontSize="md"
                          noOfLines={{ base: 3, md: 4 }}
                        >
                          {note.body}
                        </Text>
                      </Stack>
                    </Box>
                  </Center>
                </motion.div>
              </Fade>
            ))}
          </StackGrid>
          {/* </SimpleGrid> */}
        </Box>
        {isOpen ? (
          <NoteModal
            isOpen={isOpen}
            onClose={onClose}
            selectedNote={selectedNote}
          />
        ) : (
          ""
        )}
      </AnimateSharedLayout>
    </>
  );
}
Example #7
Source File: Checkers.tsx    From dnd-kit with MIT License 4 votes vote down vote up
export function Checkers() {
  const [board] = useState(generateBoard);
  const [pieces, setPieces] = useState(() => generatePieces(board));
  const [movingPiece, setMovingPiece] = useState<PieceProps | null>(null);
  const [isOddTurn, setIsOddTurn] = useState(true);
  const [oddScore, setOddScore] = useState(0);
  const [evenScore, setEvenScore] = useState(0);
  const {evenWon, oddWon} = useMemo(() => checkEnd(pieces), [pieces]);

  const checkCanMove = useCallback(
    function (
      isOddTurn: boolean,
      isOddPiece: boolean,
      movingPiece: PieceProps,
      moveToX: number,
      moveToY: number
    ): CanMoveProps {
      if (movingPiece.position) {
        const {x: moveFromX, y: moveFromY} = movingPiece.position;

        const dx = moveToX - moveFromX;
        const dy = moveToY - moveFromY;

        if (isOddTurn && isOddPiece) {
          if (dy < 0) {
            return {canMove: false};
          }

          if (Math.abs(dx) === 2 && Math.abs(dy) === 2) {
            const potentialEnemyPieceCoordinates = {
              x: moveFromX + dx / 2,
              y: moveFromY + dy / 2,
            };
            const potentialEnemyPiece =
              pieces[potentialEnemyPieceCoordinates.y][
                potentialEnemyPieceCoordinates.x
              ];

            if (potentialEnemyPiece == null || potentialEnemyPiece.odd) {
              return {canMove: false};
            } else {
              return {canMove: true, toRemove: potentialEnemyPiece};
            }
          }

          const canMove =
            (dy === 1 || dy === 2) && Math.abs(dx) === Math.abs(dy);
          return {canMove};
        } else if (!isOddTurn && !isOddPiece) {
          if (dy > 0) {
            return {canMove: false};
          }

          if (Math.abs(dx) === 2 && Math.abs(dy) === 2) {
            const potentialEnemyPieceCoordinates = {
              x: moveFromX + dx / 2,
              y: moveFromY + dy / 2,
            };
            const potentialEnemyPiece =
              pieces[potentialEnemyPieceCoordinates.y][
                potentialEnemyPieceCoordinates.x
              ];

            if (potentialEnemyPiece == null || !potentialEnemyPiece.odd) {
              return {canMove: false};
            } else {
              return {canMove: true, toRemove: potentialEnemyPiece};
            }
          }

          const canMove =
            (dy === -1 || dy === -2) && Math.abs(dx) === Math.abs(dy);
          return {canMove};
        }
      }

      return {canMove: false};
    },
    [pieces]
  );

  const handleDragCancel = useCallback(() => {
    setMovingPiece(null);
  }, []);

  const handleDragEnd = useCallback(
    function handleDragEnd(event: DragEndEvent) {
      if (!movingPiece?.position || !event.over?.id) {
        return;
      }

      const {x: movingPieceX, y: movingPieceY} = movingPiece.position;
      const [cellY, cellX] = event.over.id.toString().split('-').map(Number);

      const potentialExistingPiece = pieces[cellY][cellX];

      setMovingPiece(null);

      if (event.over && !potentialExistingPiece) {
        const {canMove, toRemove} = checkCanMove(
          isOddTurn,
          movingPiece.odd,
          movingPiece,
          cellX,
          cellY
        );

        if (!canMove) {
          return;
        }
        const newPiece: PieceProps = {
          ...movingPiece,
          position: {x: cellX, y: cellY},
        };
        // Clone pieces
        const newPieces = pieces.map((row) => row.slice());
        // Place new
        delete newPieces[movingPieceY][movingPieceX];
        newPieces[cellY][cellX] = newPiece;
        // Remove enemy
        if (toRemove?.position) {
          delete newPieces[toRemove.position?.y][toRemove.position?.x];
          if (toRemove.odd) {
            setEvenScore((score) => score + 1);
          } else {
            setOddScore((score) => score + 1);
          }
        }

        setPieces(newPieces);
        setIsOddTurn((turn) => !turn);
      }
    },
    [movingPiece, pieces, checkCanMove, isOddTurn]
  );

  const handleDragStart = useCallback(
    function handleDragStart({active}: DragStartEvent) {
      const piece = pieces.reduce<PieceProps | undefined>((acc, row) => {
        return acc ?? row.find((cell) => cell?.id === active.id);
      }, undefined);

      if (piece) {
        setMovingPiece(piece);
      }
    },
    [pieces]
  );

  const players = ['Blue', 'Black'];
  const gameEnded = evenWon || oddWon;

  return (
    <AnimateSharedLayout type="crossfade">
      <DndContext
        onDragStart={handleDragStart}
        onDragEnd={handleDragEnd}
        onDragCancel={handleDragCancel}
      >
        <div className={styles.Checkers}>
          {gameEnded ? (
            <Endgame
              winnerLabel={oddWon ? players[1] : players[0]}
              winnerScore={oddWon ? oddScore : evenScore}
              onPlayAgain={handleRestart}
            />
          ) : (
            <Score
              oddLabel={players[0]}
              evenLabel={players[1]}
              oddScore={oddScore}
              evenScore={evenScore}
              oddTurn={isOddTurn}
            />
          )}
          <Board size={BOARD_SIZE}>
            {board.map((row, y) =>
              row.map((rowCase, x) => {
                const piece = pieces[y][x];
                const disabled =
                  (piece?.odd && !isOddTurn) || (!piece?.odd && isOddTurn);

                if (!piece) {
                  const canDrop = movingPiece
                    ? checkCanMove(
                        isOddTurn,
                        movingPiece.odd,
                        movingPiece,
                        x,
                        y
                      ).canMove
                    : false;

                  return (
                    <Cell
                      key={rowCase.id}
                      validDropLocation={canDrop}
                      {...rowCase}
                    />
                  );
                }

                const pieceMarkup = disabled ? (
                  <Piece {...piece} disabled />
                ) : (
                  <DraggablePiece {...piece} />
                );

                return (
                  <Cell key={rowCase.id} {...rowCase}>
                    {pieceMarkup}
                  </Cell>
                );
              })
            )}
          </Board>
        </div>
        <DragOverlay dropAnimation={null}>
          {movingPiece == null ? null : (
            <Piece odd={movingPiece.odd} clone id={movingPiece.id} />
          )}
        </DragOverlay>
      </DndContext>
    </AnimateSharedLayout>
  );

  function handleRestart() {
    setPieces(generatePieces(board));
    setOddScore(0);
    setEvenScore(0);
  }
}