| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 | // @ts-ignore  currently no type definition for @douyinfe/semi-animation-reactimport { Transition } from '@douyinfe/semi-animation-react';import PropTypes from 'prop-types';import cls from 'classnames';import React, { useRef, useState, useCallback, useMemo } from 'react';import { cssClasses } from '@douyinfe/semi-foundation/collapsible/constants';import { Motion } from '../_base/base';import getMotionObjFromProps from '@douyinfe/semi-foundation/utils/getMotionObjFromProps';const ease = 'cubicBezier(.25,.1,.25,1)';export interface CollapsibleProps {    motion?: Motion;    children?: React.ReactNode;    isOpen?: boolean;    duration?: number;    keepDOM?: boolean;    className?: string;    style?: React.CSSProperties;    collapseHeight?: number;    reCalcKey?: number | string;    id?:string,}const Collapsible = (props: CollapsibleProps) => {    const {        motion,        children,        isOpen,        duration,        keepDOM,        collapseHeight,        style,        className,        reCalcKey,        id    } = props;    const ref = useRef(null);    const [maxHeight, setMaxHeight] = useState(0);    const [open, setOpen] = useState(props.isOpen);    const [isFirst, setIsFirst] = useState(true);    const [transitionImmediate, setTransitionImmediate] = useState(open && isFirst);    const [left, setLeft] = useState(!props.isOpen);    if (isOpen !== open) {        setOpen(isOpen);        if (isFirst) {            setIsFirst(false);            setTransitionImmediate(false);        }        isOpen && setLeft(!isOpen);    }    const setHeight = useCallback(node => {        const currHeight = node && node.scrollHeight;        if (currHeight && maxHeight !== currHeight) {            setMaxHeight(currHeight);        }        // eslint-disable-next-line react-hooks/exhaustive-deps    }, [left, reCalcKey, maxHeight]);    const resetHeight = () => {        ref.current.style.maxHeight = 'none';    };    const formatStyle = ({ maxHeight: maxHeightInTransitionStyle }: any) => ({ maxHeight: maxHeightInTransitionStyle });    const shouldKeepDOM = () => keepDOM || collapseHeight !== 0;    const defaultMaxHeight = useMemo(() => {        return isOpen || !shouldKeepDOM() && !motion ? 'none' : collapseHeight;    }, [collapseHeight, motion, isOpen, shouldKeepDOM]);    const renderChildren = (transitionStyle: Record<string, any> | null) => {        const transition =            transitionStyle && typeof transitionStyle === 'object' ?                formatStyle(transitionStyle) :                {};        const wrapperstyle = {            overflow: 'hidden',            maxHeight: defaultMaxHeight,            ...style,            ...transition,        };        if (isFirst) {            wrapperstyle.maxHeight = defaultMaxHeight;        }        const wrapperCls = cls(`${cssClasses.PREFIX}-wrapper`, className);        return (            <div style={wrapperstyle} className={wrapperCls} ref={ref}>                <div                    ref={setHeight}                    style={{ overflow: 'hidden' }}                     id={id}                    x-semi-prop="children"                >                    {children}                </div>            </div>        );    };    const didLeave = () => {        setLeft(true);        !shouldKeepDOM() && setMaxHeight(collapseHeight);    };    const renderContent = () => {        if (left && !shouldKeepDOM()) {            return null;        }        const mergedMotion = getMotionObjFromProps({            didEnter: resetHeight,            didLeave,            motion,        });        return (            <Transition                state={isOpen ? 'enter' : 'leave'}                immediate={transitionImmediate}                from={{ maxHeight: 0 }}                enter={{ maxHeight: { val: maxHeight, easing: ease, duration } }}                leave={{ maxHeight: { val: collapseHeight, easing: ease, duration } }}                {...mergedMotion}            >                {(transitionStyle: Record<string, any>) =>                    renderChildren(motion ? transitionStyle : null)                }            </Transition>        );    };    return renderContent();};Collapsible.propType = {    motion: PropTypes.oneOfType([PropTypes.bool, PropTypes.func, PropTypes.object]),    children: PropTypes.node,    isOpen: PropTypes.bool,    duration: PropTypes.number,    keepDOM: PropTypes.bool,    collapseHeight: PropTypes.number,    style: PropTypes.object,    className: PropTypes.string,    reCalcKey: PropTypes.oneOfType([        PropTypes.string,        PropTypes.number    ]),};Collapsible.defaultProps = {    isOpen: false,    duration: 250,    motion: true,    keepDOM: false,    collapseHeight: 0};export default Collapsible;
 |