import * as React from 'react'; import Button from '../../buttons/Button'; import Transition from '../Transition'; import DummyBox from './common/DummyBox'; import Stage from './common/Stage'; import {useIsomorphicLayoutEffect} from '../../utils/useIsomorphicLayoutEffect'; import {useTransformationState} from './common/useTransformationState'; const appearingEffect = { initial: { opacity: 0, transform: { scale: 0.9, }, }, animate: { opacity: 1, duration: 'moderate1', }, }; const removingEffect = { animate: { opacity: 0, duration: 'quick2', }, }; const initialItemIds = [0, 1, 2, 3]; /** * It is greater than the ID of the last initial item to * not animate the already added items at the beginning. */ let lastUniqueId = initialItemIds.length; export const FluidList = () => { const containerRef = React.useRef(null); const [itemIds, setItemIds] = React.useState(initialItemIds); const addItem = () => { setItemIds(prev => [++lastUniqueId, ...prev]); }; const removeItem = (id: number) => { setItemIds(prev => prev.filter(n => n !== id)); }; return ( {itemIds.map((id, index) => ( removeItem(id)} /> ))} ); }; const FluidListItem = ({ index, updateKey, containerRef, lastCreated, siblingsAmount, onRemove, }: { index: number; updateKey: number; containerRef: { current: HTMLElement | null; }; lastCreated: boolean; siblingsAmount: number; onRemove: () => void; }) => { const [removing, setRemoving] = React.useState(false); const [movementEffect, setMovementEffect] = React.useState(null); const elementRef = React.useRef(null); const transformation = useTransformationState({ elementRef, containerRef, updateKey, }); const getTransitionEffect = () => { if (removing) { return removingEffect; } if (lastCreated) { return appearingEffect; } return movementEffect; }; const getTransitionDelay = () => { const appearingDelay = 180; const delayOffset = 20; if (removing || siblingsAmount === 0) { return 0; } if (lastCreated) { return appearingDelay; } /** * To simulate weightlessness we can delay the * transition of each item when it moves upward. */ if (transformation.diffTop < 0) { return appearingDelay + delayOffset * index; } return 0; }; useIsomorphicLayoutEffect(() => { if (transformation.diffTop !== 0) { /** * https://css-tricks.com/animating-layouts-with-the-flip-technique/ */ setMovementEffect({ // @ts-ignore TS2353 initial: { transform: { translateY: -transformation.diffTop, }, }, animate: { transform: { translateY: 0, duration: 'moderate1', }, }, }); } }, [transformation]); return (
setRemoving(true)} />
); }; FluidList.parameters = { layout: 'centered', };