import React, { forwardRef, useEffect, useRef } from 'react'; import { useDebouncedEffect, useEvent, useForwardedRef, } from '@anton.bobrov/react-hooks'; import { useTimeline } from '@anton.bobrov/react-vevet-hooks'; import cn from 'classnames'; import { prefixedClasNames } from '../../utils/prefixedClassNames'; import { IExpandContentProps } from './types'; import { useStates } from './utils/useStates'; import { render } from './utils/render'; const classNamePrefix = 'expand-content'; const contentClassNamePrefix = `${classNamePrefix}__content`; /** * ExpandContent component for creating accordion-style expandable content sections. * * This component allows users to toggle the visibility of additional content * within a collapsible section, making it an ideal base for accordion functionality. * It enhances user experience by saving space and providing a clean interface, * allowing for better management of large amounts of information. * * @link See examples https://antonbobrov.github.io/react-kit/?path=/docs/wrappers-expandcontent--docs * * @requires Requires styles: `@import '~@anton.bobrov/react-components/lib/styles/components/ExpandContent';` */ export const ExpandContent = forwardRef( ( { className, style, isActive: isActiveProp = false, duration = 500, hasAlpha = true, isHiddenContentRendered: isHiddenContentRenderedProp = true, onExpandStart, onExpandRender, onExpandEnd, onHiddenContentRender: onHiddenContentRenderProp, children, ...props }, forwardedRef, ) => { const parentRef = useForwardedRef(forwardedRef); const contentRef = useRef(null); const onHiddenContentRender = useEvent(onHiddenContentRenderProp); const { isActive, isPrevActive, isDefaultActive, isHiddenContentRendered, setIsHidden, } = useStates({ isActive: isActiveProp, isHiddenContentRendered: isHiddenContentRenderedProp, }); const { play, reverse, timeline } = useTimeline({ duration, onProgress: ({ p }) => { render({ parentRef, contentRef, timeline, p, hasAlpha, onStart: () => { onExpandStart?.(); }, onRender: onExpandRender, onEnd: (data) => { onExpandEnd?.(data); if (!data) { setIsHidden(true); } }, }); }, }); useEffect(() => { if (isActiveProp) { setIsHidden(false); } }, [isActiveProp, setIsHidden]); useEffect(() => { if (!timeline || !isDefaultActive) { return; } // @ts-ignore // eslint-disable-next-line no-underscore-dangle timeline._p = 1; }, [timeline, isDefaultActive]); useEffect(() => { if (isActive === isPrevActive) { return; } if (isActive) { play(); } else { reverse(); } }, [isActive, isPrevActive, play, reverse]); useDebouncedEffect( () => { if (isHiddenContentRendered) { onHiddenContentRender?.(); } }, [isHiddenContentRendered, onHiddenContentRender], 1, ); return (
{isHiddenContentRendered && children}
); }, ); ExpandContent.displayName = 'ExpandContent';