Use transition events to better-coordinate debouncing of NodeModel innerRect (#288)

Rather than using a timeout to debounce changes to the
NodeModel.innerRect, I'll use a transition event on the display
container. This way, if the user disables transitions using the reduced
motion setting, changes to the innerRect value will not be debounced.
This commit is contained in:
Evan Simkowitz
2024-08-28 13:28:49 -07:00
committed by GitHub
parent f7c9fd9a02
commit 099c196cae
3 changed files with 25 additions and 19 deletions
+1 -1
View File
@@ -732,7 +732,6 @@ export class LayoutModel {
nodeId: nodeid,
blockId,
blockNum: atom((get) => get(this.leafOrder).indexOf(nodeid) + 1),
isResizing: this.isResizing,
isFocused: atom((get) => {
const treeState = get(this.treeStateAtom);
const isFocused = treeState.focusedNodeId === nodeid;
@@ -748,6 +747,7 @@ export class LayoutModel {
toggleMagnify: () => this.magnifyNodeToggle(nodeid),
focusNode: () => this.focusNode(nodeid),
dragHandleRef: createRef(),
displayContainerRef: this.displayContainerRef,
});
}
const nodeModel = this.nodeModels.get(nodeid);
+23 -17
View File
@@ -5,7 +5,7 @@ import { atoms, globalStore, WOS } from "@/app/store/global";
import { fireAndForget } from "@/util/util";
import useResizeObserver from "@react-hook/resize-observer";
import { Atom, useAtomValue } from "jotai";
import { CSSProperties, useEffect, useState } from "react";
import { CSSProperties, useEffect, useLayoutEffect, useState } from "react";
import { withLayoutTreeStateAtomFromTab } from "./layoutAtom";
import { LayoutModel } from "./layoutModel";
import { LayoutNode, NodeModel, TileLayoutContents } from "./types";
@@ -63,26 +63,32 @@ export function useNodeModel(layoutModel: LayoutModel, layoutNode: LayoutNode):
export function useDebouncedNodeInnerRect(nodeModel: NodeModel): CSSProperties {
const nodeInnerRect = useAtomValue(nodeModel.innerRect);
const nodeIsResizing = useAtomValue(nodeModel.isResizing);
const [debounceTimeout, setDebounceTimeout] = useState<NodeJS.Timeout>();
const [innerRect, setInnerRect] = useState<CSSProperties>();
const [isTransitioning, setIsTransitioning] = useState(false);
useEffect(() => {
if (!nodeIsResizing && nodeInnerRect) {
if (debounceTimeout) {
clearTimeout(debounceTimeout);
}
setDebounceTimeout(
setTimeout(() => {
setInnerRect(nodeInnerRect);
setDebounceTimeout(null);
}, nodeModel.animationTimeS * 1000)
);
} else {
setInnerRect(null);
const onTransitionStart = () => {
setIsTransitioning(true);
};
const onTransitionEnd = () => {
setIsTransitioning(false);
};
if (nodeModel.displayContainerRef.current) {
nodeModel.displayContainerRef.current.addEventListener("transitionstart", onTransitionStart);
nodeModel.displayContainerRef.current.addEventListener("transitionend", onTransitionEnd);
}
}, [nodeInnerRect, nodeIsResizing]);
return () => {
nodeModel.displayContainerRef.current?.removeEventListener("transitionstart", onTransitionStart);
nodeModel.displayContainerRef.current?.removeEventListener("transitionend", onTransitionEnd);
};
}, [nodeModel]);
useLayoutEffect(() => {
if (!isTransitioning) {
setInnerRect(nodeInnerRect);
}
}, [nodeInnerRect, isTransitioning]);
return innerRect;
}
+1 -1
View File
@@ -330,7 +330,6 @@ export interface NodeModel {
blockNum: Atom<number>;
nodeId: string;
blockId: string;
isResizing: Atom<boolean>;
isFocused: Atom<boolean>;
isMagnified: Atom<boolean>;
ready: Atom<boolean>;
@@ -339,4 +338,5 @@ export interface NodeModel {
focusNode: () => void;
onClose: () => void;
dragHandleRef?: React.RefObject<HTMLDivElement>;
displayContainerRef: React.RefObject<HTMLDivElement>;
}