collapse context reset

This commit is contained in:
Seth Trowbridge 2023-01-24 17:28:17 -05:00
parent 9fc85f1901
commit dc601637a8
2 changed files with 29 additions and 18 deletions

View File

@ -89,16 +89,20 @@ export default () => {
<div class="px-2"> <div class="px-2">
<${PersonForm}/> <${PersonForm}/>
<${PersonTable}/> <${PersonTable}/>
<${Tree.Branch}> <${Tree.Branch}>
<${Tree.Button}><//> <${Tree.Button}/>
<${Tree.Menu}> <${Tree.Menu} class="shadow-lg rounded-lg bg-white">
<div class=${"p-4"}> <p>hey</p>
<p> <${Tree.Branch}>
The method addEventListener() works by adding a function, or an object that implements EventListener, to the list of event listeners for the specified event type on the EventTarget on which it's called. If the function or object is already in the list of event listeners for this target, the function or object is not added a second time. <${Tree.Button} class="p-4 bg-red-500 text-white"/>
</p> <${Tree.Menu}>
</div> <p>sup.</p>
<//>
<//>
<//> <//>
<//> <//>
</div> </div>
</div>`; </div>`;
}; };

View File

@ -1,7 +1,7 @@
import { html } from "htm"; import { html } from "htm";
import * as React from "preact"; import * as React from "preact";
/** @typedef {({children, classes}:{children:preact.VNode, classes:string|null})=>preact.VNode} BasicElement */ /** @typedef {(props:{children:preact.VNode, class:string|null})=>preact.VNode} BasicElement */
/** @typedef {{Open:boolean, Done:boolean}} Stage*/ /** @typedef {{Open:boolean, Done:boolean}} Stage*/
/** @typedef {[set:Stage, get:React.StateUpdater<Stage>]} Binding */ /** @typedef {[set:Stage, get:React.StateUpdater<Stage>]} Binding */
@ -9,6 +9,8 @@ const BranchContext = React.createContext(
/** @type Binding */ ([{ Open: false, Done: true }, (_n) => {}]), /** @type Binding */ ([{ Open: false, Done: true }, (_n) => {}]),
); );
export { BranchContext as Context };
/** @type BasicElement */ /** @type BasicElement */
export const Branch = (props) => { export const Branch = (props) => {
/** @type Binding */ const stage = React.useState( /** @type Binding */ const stage = React.useState(
@ -17,7 +19,8 @@ export const Branch = (props) => {
/** @type Binding */ const stageParent = React.useContext(BranchContext); /** @type Binding */ const stageParent = React.useContext(BranchContext);
React.useEffect(() => { React.useEffect(() => {
const [{ Open, Done }, Shut] = stageParent; const [{ Open, Done }] = stageParent;
const [, Shut] = stage;
if (!Open && Done) { if (!Open && Done) {
Shut({ Open: false, Done: true }); Shut({ Open: false, Done: true });
} }
@ -40,7 +43,7 @@ export const Button = (props) => {
console.log(value); console.log(value);
}; };
return html`<button onClick=${handler} class=${props.classes}>stage: ${ return html`<button onClick=${handler} class=${props.class}>stage: ${
JSON.stringify(stageGet) JSON.stringify(stageGet)
} }
${props.children} ${props.children}
@ -51,22 +54,25 @@ export const Button = (props) => {
export const Menu = (props) => { export const Menu = (props) => {
const [stageGet, stageSet] = React.useContext(BranchContext); const [stageGet, stageSet] = React.useContext(BranchContext);
const refElement = React.useRef(null); const refElement = React.useRef(null);
/** @type {React.MutableRefObject<null|Toggler>} */
const refCollapser = React.useRef(null); const refCollapser = React.useRef(null);
React.useEffect(() => { React.useEffect(() => {
refCollapser.current = Collapser(refElement.current); refElement.current &&
(refCollapser.current = Collapser(refElement.current));
}, []); }, []);
React.useEffect(() => { React.useEffect(() => {
refCollapser.current( const instant = stageGet.Open == false && stageGet.Done;
refCollapser.current && refCollapser.current(
stageGet.Open, stageGet.Open,
stageGet.Open == false && stageGet.Done ? 0 : 600, instant ? 0 : 600,
() => stageSet({ ...stageGet, Done: true }), () => stageSet({ ...stageGet, Done: true }),
); );
}, [stageGet.Open]); }, [stageGet.Open]);
return html` return html`
<div ref=${refElement} class=${props.classes}> <div ref=${refElement} class=${props.class}>
${props.children} ${props.children}
</div> </div>
`; `;
@ -74,18 +80,18 @@ export const Menu = (props) => {
/** @typedef {(Open:boolean)=>void} UserDone */ /** @typedef {(Open:boolean)=>void} UserDone */
/** @typedef {(inOpen:boolean, inMilliseconds:number, inUserDone:UserDone)=>void} Toggler */ /** @typedef {(inOpen:boolean, inMilliseconds:number, inUserDone:UserDone)=>void} Toggler */
/** @type {(inElement:HTMLElement)=>Toggler} */ /** @typedef {(inElement:HTMLElement)=>Toggler} Collapse */
/** @type Collapse */
const Collapser = (inElement) => { const Collapser = (inElement) => {
console.log("Collapser initialized");
/** @type UserDone */ /** @type UserDone */
let userDone = () => {}; let userDone = () => {};
let userMode = false;
const collapse = inElement; const collapse = inElement;
/** @type {(inEvent:TransitionEvent)=>void} */ /** @type {(inEvent:TransitionEvent)=>void} */
const done = (inEvent) => { const done = (inEvent) => {
if (inEvent.propertyName == "height" && inEvent.target == collapse) { if (inEvent.propertyName == "height" && inEvent.target == collapse) {
inEvent.stopPropagation(); inEvent.stopPropagation();
if (collapse.clientHeight > 0) { if (userMode) {
collapse.style.height = "auto"; collapse.style.height = "auto";
collapse.style.overflow = "visible"; collapse.style.overflow = "visible";
userDone(true); userDone(true);
@ -96,6 +102,7 @@ const Collapser = (inElement) => {
}; };
/** @type Toggler */ /** @type Toggler */
const show = (inOpen, inMs, inDone) => { const show = (inOpen, inMs, inDone) => {
userMode = inOpen;
collapse.removeEventListener("transitionend", done); collapse.removeEventListener("transitionend", done);
userDone = inDone; userDone = inDone;
collapse.addEventListener("transitionend", done); collapse.addEventListener("transitionend", done);