fix state updating
This commit is contained in:
parent
1257baa190
commit
f6da848c2b
23
.vscode/launch.json
vendored
Normal file
23
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Launch Program",
|
||||||
|
"type": "node",
|
||||||
|
"program": "${workspaceFolder}/main.ts",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"runtimeExecutable": "C:\\Users\\strowbridge\\.deno\\bin\\deno.EXE",
|
||||||
|
"runtimeArgs": [
|
||||||
|
"run",
|
||||||
|
"--unstable",
|
||||||
|
"--inspect-wait",
|
||||||
|
"--allow-all"
|
||||||
|
],
|
||||||
|
"attachSimplePort": 9229
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
13
js/people.js
13
js/people.js
@ -84,17 +84,10 @@ const PersonForm = () => {
|
|||||||
|
|
||||||
/** @type {()=>preact.VNode} */
|
/** @type {()=>preact.VNode} */
|
||||||
export default () => {
|
export default () => {
|
||||||
let [countGet, countSet] = Preact.useState(0);
|
|
||||||
|
|
||||||
let ref = Preact.useRef(null);
|
|
||||||
Tree.useAway(ref, () => {
|
|
||||||
countSet(countGet + 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div>
|
<div>
|
||||||
<h2 class="pb-2 mb-2 border-b text-2xl font-sans">Person Records ${countGet}</h2>
|
<h2 class="pb-2 mb-2 border-b text-2xl font-sans">Person Records</h2>
|
||||||
<div class="px-2" ref=${ref}>
|
<div class="px-2">
|
||||||
<${PersonForm}/>
|
<${PersonForm}/>
|
||||||
<${PersonTable}/>
|
<${PersonTable}/>
|
||||||
|
|
||||||
@ -102,12 +95,14 @@ export default () => {
|
|||||||
<${Tree.Button}/>
|
<${Tree.Button}/>
|
||||||
<${Tree.Menu} class="shadow-lg rounded-lg bg-white">
|
<${Tree.Menu} class="shadow-lg rounded-lg bg-white">
|
||||||
<p>hey</p>
|
<p>hey</p>
|
||||||
|
<!--
|
||||||
<${Tree.Branch}>
|
<${Tree.Branch}>
|
||||||
<${Tree.Button} class="p-4 bg-red-500 text-white"/>
|
<${Tree.Button} class="p-4 bg-red-500 text-white"/>
|
||||||
<${Tree.Menu}>
|
<${Tree.Menu}>
|
||||||
<p>sup.</p>
|
<p>sup.</p>
|
||||||
<//>
|
<//>
|
||||||
<//>
|
<//>
|
||||||
|
-->
|
||||||
<//>
|
<//>
|
||||||
<//>
|
<//>
|
||||||
|
|
||||||
|
71
js/tree.js
71
js/tree.js
@ -2,11 +2,11 @@ import { html } from "htm";
|
|||||||
import * as React from "preact";
|
import * as React from "preact";
|
||||||
|
|
||||||
/** @typedef {(props:{children:preact.VNode, class: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, Away:boolean}} Stage*/
|
||||||
/** @typedef {[set:Stage, get:React.StateUpdater<Stage>]} Binding */
|
/** @typedef {[set:Stage, get:React.StateUpdater<Stage>]} Binding */
|
||||||
|
|
||||||
const BranchContext = React.createContext(
|
const BranchContext = React.createContext(
|
||||||
/** @type Binding */ ([{ Open: false, Done: true }, (_n) => {}]),
|
/** @type Binding */ ([{ Open: false, Done: true, Away: false }, (_n) => {}]),
|
||||||
);
|
);
|
||||||
|
|
||||||
export { BranchContext as Context };
|
export { BranchContext as Context };
|
||||||
@ -14,15 +14,15 @@ 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(
|
||||||
/** @type Stage */ ({ Open: false, Done: true }),
|
/** @type Stage */ ({ Open: false, Done: true, Away: false }),
|
||||||
);
|
);
|
||||||
/** @type Binding */ const stageParent = React.useContext(BranchContext);
|
/** @type Binding */ const stageParent = React.useContext(BranchContext);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const [{ Open, Done }] = stageParent;
|
const [{ Open, Done, Away }] = stageParent;
|
||||||
const [, Shut] = stage;
|
const [, Shut] = stage;
|
||||||
if (!Open && Done) {
|
if (!Open && Done) {
|
||||||
Shut({ Open: false, Done: true });
|
Shut({ Open: false, Done: true, Away });
|
||||||
}
|
}
|
||||||
}, [stageParent]);
|
}, [stageParent]);
|
||||||
|
|
||||||
@ -37,13 +37,33 @@ export const Button = (props) => {
|
|||||||
/** @type Binding */
|
/** @type Binding */
|
||||||
const [stageGet, stageSet] = React.useContext(BranchContext);
|
const [stageGet, stageSet] = React.useContext(BranchContext);
|
||||||
|
|
||||||
const handler = () => {
|
/** @type React.MutableRefObject<Handler|null> */
|
||||||
const value = { Open: !stageGet.Open, Done: false };
|
const refHandler = React.useRef(null);
|
||||||
stageSet(value);
|
React.useEffect(() => {
|
||||||
console.log(value);
|
console.log("recreating handler", stageGet);
|
||||||
|
refHandler.current = (away) => {
|
||||||
|
console.log("set: away");
|
||||||
|
stageSet((state) => ({ ...state, Away: away }));
|
||||||
|
};
|
||||||
|
}, [stageGet]);
|
||||||
|
|
||||||
|
/** @type React.MutableRefObject<HTMLElement|null> */
|
||||||
|
const refEl = React.useRef(null);
|
||||||
|
useAway(refEl, refHandler);
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
console.log("set: open");
|
||||||
|
stageSet((state) => ({ ...state, Open: !state.Open, Done: false }));
|
||||||
};
|
};
|
||||||
|
|
||||||
return html`<button onClick=${handler} class=${props.class}>stage: ${
|
React.useEffect(() => {
|
||||||
|
console.log("away *changed*");
|
||||||
|
if (stageGet.Away && stageGet.Open) {
|
||||||
|
handleClick();
|
||||||
|
}
|
||||||
|
}, [stageGet.Away]);
|
||||||
|
|
||||||
|
return html`<button ref=${refEl} onClick=${handleClick} class=${props.class}>stage: ${
|
||||||
JSON.stringify(stageGet)
|
JSON.stringify(stageGet)
|
||||||
}
|
}
|
||||||
${props.children}
|
${props.children}
|
||||||
@ -69,7 +89,7 @@ export const Menu = (props) => {
|
|||||||
instant ? 0 : 600,
|
instant ? 0 : 600,
|
||||||
() => stageSet({ ...stageGet, Done: true }),
|
() => stageSet({ ...stageGet, Done: true }),
|
||||||
);
|
);
|
||||||
}, [stageGet.Open]);
|
}, [stageGet]);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div ref=${refElement} class=${props.class}>
|
<div ref=${refElement} class=${props.class}>
|
||||||
@ -118,22 +138,29 @@ const Collapser = (inElement) => {
|
|||||||
return show;
|
return show;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @typedef {(e:Event)=>void} Handler */
|
/** @typedef {(away:boolean, e:Event)=>void} Handler */
|
||||||
/** @type {(inRef:React.MutableRefObject<HTMLElement|null>, inHandler:Handler)=>void} */
|
/** @type {(inRef:React.MutableRefObject<HTMLElement|null>, inHandler:React.MutableRefObject<Handler|null>)=>void} */
|
||||||
export const useAway = (inRef, inHandler) => {
|
export const useAway = (inRef, inHandler) => {
|
||||||
/** @type React.MutableRefObject<Handler> */
|
/** @type React.MutableRefObject<(e:Event)=>void> */
|
||||||
const handlerUser = React.useRef(inHandler);
|
|
||||||
handlerUser.current = inHandler;
|
|
||||||
|
|
||||||
/** @type React.MutableRefObject<Handler> */
|
|
||||||
const handlerClick = React.useRef((e) => {
|
const handlerClick = React.useRef((e) => {
|
||||||
const index = inRef.current ? e.composedPath().indexOf(inRef.current) : -1;
|
const index = inRef.current ? e.composedPath().indexOf(inRef.current) : -1;
|
||||||
if (index < 0) {
|
inHandler.current && inHandler.current(index < 0, e);
|
||||||
handlerUser.current(e);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
document.addEventListener("click", handlerClick.current);
|
document.addEventListener("click", handlerClick.current);
|
||||||
return () => document.removeEventListener("click", handlerClick.current);
|
return () => document.removeEventListener("click", handlerClick.current);
|
||||||
}, []);
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const GlobalClick = {
|
||||||
|
Bind: () => {
|
||||||
|
if (!GlobalClick.Live) {
|
||||||
|
GlobalClick.Live = true;
|
||||||
|
document.addEventListener("click", (inEvent) => {
|
||||||
|
GlobalClick.Path = inEvent.composedPath();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Live: false,
|
||||||
|
Path: [],
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user