fix(timeline): stabilize overlay lifecycle

This commit is contained in:
2026-04-01 14:41:03 +02:00
parent fa5e654739
commit a71bbeb640
4 changed files with 259 additions and 13 deletions
@@ -355,6 +355,7 @@ function TimelineViewContent({
anchorEl: HTMLElement;
} | null>(null);
const resourceHoverTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const previousViewModeRef = useRef(viewMode);
const invalidateTimelineInner = useInvalidateTimeline();
const batchDeleteMutation = trpc.allocation.batchDelete.useMutation({
@@ -386,6 +387,26 @@ function TimelineViewContent({
setResourceHover(null);
}, [hasActivePointerOverlay]);
useEffect(() => {
if (previousViewModeRef.current === viewMode) {
return;
}
previousViewModeRef.current = viewMode;
setPopover(null);
setDemandPopover(null);
setNewAllocPopover(null);
setResourceHover(null);
}, [viewMode, setNewAllocPopover]);
useEffect(() => {
if (!isInitialLoading) return;
setPopover(null);
setDemandPopover(null);
setNewAllocPopover(null);
setResourceHover(null);
}, [isInitialLoading, setNewAllocPopover]);
// ─── Keep selection overlay visible while popover is open ───────────────────
const effectiveRangeState: typeof rangeState = rangeState.isSelecting
? rangeState
+12
View File
@@ -155,6 +155,8 @@ export function useViewportPopover({
}, [align, anchor, estimatedHeight, offset, side, viewportPadding, width, zIndex]);
useEffect(() => {
const closeOnViewportChange = anchor.kind === "point";
function cancelScheduledFrame() {
if (frameRef.current === null) return;
cancelAnimationFrame(frameRef.current);
@@ -181,9 +183,19 @@ export function useViewportPopover({
updateOrClose();
const handleScroll = () => {
if (closeOnViewportChange) {
cancelScheduledFrame();
onClose();
return;
}
scheduleUpdate("scroll");
};
const handleResize = () => {
if (closeOnViewportChange) {
cancelScheduledFrame();
onClose();
return;
}
scheduleUpdate("resize");
};