/** * WordPress dependencies */ import { useState } from '@safe-wordpress/element'; /** * External dependencies */ import clsx from 'clsx'; import { flattenDeep, union, without } from 'lodash'; import { TransitionGroup, CSSTransition } from 'react-transition-group'; export type AnimatedListProps = { readonly className?: string; readonly disableAnimations?: boolean; readonly enter?: number; readonly exit?: number; readonly children: ReadonlyArray< JSX.Element >; }; export const AnimatedList = ( { className, disableAnimations, enter = 0, exit = 0, children, }: AnimatedListProps ): JSX.Element => { const [ enteringItems, setEnteringItems ] = useStringList(); const [ exitingItems, setExitingItems ] = useStringList(); if ( disableAnimations ) { return (
{ children.map( ( child ) => (
{ child }
) ) }
); } const addEnteringItem = ( item: string ) => setEnteringItems( union( enteringItems, [ item ] ) ); const removeEnteringItem = ( item: string ) => setEnteringItems( without( enteringItems, item ) ); const addExitingItem = ( item: string ) => setExitingItems( union( exitingItems, [ item ] ) ); const removeExitingItem = ( item: string ) => setExitingItems( without( exitingItems, item ) ); const flattenedChildren = flattenDeep( children ); return (
{ flattenedChildren.map( ( child ) => ( addEnteringItem( str( child.key ) ) } onEntered={ () => removeEnteringItem( str( child.key ) ) } onExit={ () => addExitingItem( str( child.key ) ) } onExited={ () => removeExitingItem( str( child.key ) ) } >
{ child }
) ) }
); }; // ======= // HELPERS // ======= const str = ( a: unknown ): string => ( typeof a === 'string' ? a : '' ); // ===== // HOOKS // ===== const useStringList = () => useState< ReadonlyArray< string > >( [] );