diff --git a/app.tsx b/app.tsx index 1b2ba86..44aa5b0 100644 --- a/app.tsx +++ b/app.tsx @@ -1,6 +1,6 @@ import React from "react"; import * as Iso from "@eno/iso"; -import Collapse, {CollapseButton, CollapseGroup} from "$/collapse.tsx"; +import Collapse, {CollapseButton, CollapseGroup, CollapseMenu} from "$/collapse.tsx"; const Comp = React.lazy(()=>import("./deep/component.tsx")); @@ -16,13 +16,17 @@ export default ()=> Details Data Fetching - -

Hello!

-
-
+
+ +

collapsedable!

+

collapsedable!

+

collapsedable!

+

collapsedable!

+

collapsedable!

+
diff --git a/components/collapse.tsx b/components/collapse.tsx index 6954538..9ec0f54 100644 --- a/components/collapse.tsx +++ b/components/collapse.tsx @@ -1,42 +1,5 @@ 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} -
-
-}; - export function useAway(inRef:React.Ref, inHandler:(inAway:boolean)=>void) { const handlerRef = React.useRef(inHandler); @@ -67,20 +30,66 @@ export const CollapseButton =()=> { const [stateGet, stateSet] = React.useContext(CollapseContext); const buttonRef:React.Ref = React.useRef(null); - useAway(buttonRef, (Away)=>stateSet({Away})); - return } -type DoneCallback =(openState:boolean)=>void; +export const CollapseMenu =(props:{children:React.JSX.Element|React.JSX.Element[]})=> +{ + const [stateGet, stateSet] = React.useContext(CollapseContext); + const refEl:React.RefObject = React.useRef(null); + const refCollapse:React.RefObject = React.useRef(null); + + React.useEffect(()=> + { + if(refEl.current) + { + refCollapse.current = Collapser(refEl.current, stateGet.Open); + } + return ()=> refCollapse.current && refCollapse.current(); + } + , []); + + React.useEffect(()=> + { + console.log(`menu animation start:${stateGet.Open}`); + refCollapse.current && refCollapse.current(stateGet.Open, 500, (state, id)=> + { + console.log("menu animation done", state, id); + stateSet({Done:true}); + } + ); + }, [stateGet.Open, stateGet.Done]); + + + console.log(`menu re-render: open:${stateGet.Open} done:${stateGet.Done} away:${stateGet.Away}`) + return
}> + { props.children} +
+}; + +type DoneCallback =(openState:boolean, id:number)=>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; - + let id = Math.random(); + const done = (inEvent:TransitionEvent)=> { if (inEvent.propertyName == "height" && inEvent.target == inElement) @@ -91,19 +100,21 @@ export function Collapser(inElement:HTMLElement, initialState = false) inElement.style.height = "auto"; inElement.style.overflow = "visible"; } - userDone(userMode); + userDone(userMode, id); } }; inElement.addEventListener("transitionend", done); return function(inOpen?:boolean, inMs?:number, inDone?:DoneCallback) { + console.log("collapser sees", inOpen); + cancelAnimationFrame(frameRequest); if(arguments.length) { userDone = inDone|| ((m)=>{}) as DoneCallback; - userMode = inOpen||!userMode; + userMode = inOpen === true; inElement.style.height = inElement.clientHeight + "px"; inElement.style.overflow = "hidden"; inElement.style.transition = "none";