import React from "react"; export default (props:{open:boolean, children:React.JSX.Element|React.JSX.Element[]})=> { const [openGet, openSet] = React.useState(props.open); const [doneGet, doneSet] = React.useState(true); const refEl:React.RefObject = React.useRef(null); const refCollapse:React.RefObject = React.useRef(null); React.useEffect(()=> { if(refEl.current) { refCollapse.current = Collapser(refEl.current, openGet); } return ()=> refCollapse.current && refCollapse.current(); } , []); const Handler =()=> { openSet((old)=> { if(refCollapse.current) { doneSet(false); refCollapse.current(!old, 1000, ()=>doneSet(true)); } return !old; }); }; return
}> {!(!openGet && doneGet) && props.children}
}; type DoneCallback =(openState:boolean)=>void; type CollapseControls =(inOpen?:boolean, inMs?:number, inDone?:DoneCallback)=>void; export function Collapser(inElement:HTMLElement, initialState = false) { let userDone:DoneCallback = (openState) => {}; let userMode = initialState; let frameRequest = 0; const done = (inEvent:TransitionEvent)=> { if (inEvent.propertyName == "height" && inEvent.target == inElement) { inEvent.stopPropagation(); if (userMode) { inElement.style.height = "auto"; inElement.style.overflow = "visible"; } userDone(userMode); } }; inElement.addEventListener("transitionend", done); /** @type Toggler */ return function(inOpen?:boolean, inMs?:number, inDone?:DoneCallback) { cancelAnimationFrame(frameRequest); if(arguments.length) { userDone = inDone|| ((m)=>{}) as DoneCallback; userMode = inOpen||!userMode; inElement.style.height = inElement.clientHeight + "px"; inElement.style.overflow = "hidden"; inElement.style.transition = "none"; frameRequest = requestAnimationFrame(()=> { inElement.style.height = `${inOpen ? inElement.scrollHeight : 0}px`; inElement.style.transition = `height ${(inMs||1000) / 1000}s`; }); } else { inElement.removeEventListener("transitionend", done); } } as CollapseControls; }