fix: discard pending sidebar width on collapse

This commit is contained in:
maaz 2026-07-10 04:28:24 +05:30
parent a19dbda2a2
commit 5adfbed97d
2 changed files with 46 additions and 3 deletions

View File

@ -511,4 +511,37 @@ describe("Sidebar", () => {
expect(document.documentElement.style.getPropertyValue("--ao-sidebar-w")).toBe("280px");
expect(window.localStorage.getItem("ao-sidebar-w")).toBe("280");
});
it("discards a queued narrow resize frame when collapsing", async () => {
let queuedFrame: FrameRequestCallback | undefined;
const requestAnimationFrameSpy = vi.spyOn(window, "requestAnimationFrame").mockImplementation((callback) => {
queuedFrame = callback;
return 1;
});
const cancelAnimationFrameSpy = vi.spyOn(window, "cancelAnimationFrame").mockImplementation(() => undefined);
try {
renderSidebar();
const resizeHandle = document.querySelector(".resize-handle--right");
if (!(resizeHandle instanceof HTMLElement)) throw new Error("Resize handle not found");
fireEvent.pointerDown(resizeHandle, { clientX: 240 });
fireEvent.pointerMove(window, { clientX: 205 });
fireEvent.pointerMove(window, { clientX: 120 });
await waitFor(() => {
expect(document.querySelector('[data-slot="sidebar"][data-state="collapsed"]')).toBeInTheDocument();
});
expect(cancelAnimationFrameSpy).toHaveBeenCalledWith(1);
expect(window.localStorage.getItem("ao-sidebar-w")).toBe("240");
expect(document.documentElement.style.getPropertyValue("--ao-sidebar-w")).toBe("240px");
queuedFrame?.(performance.now());
expect(document.documentElement.style.getPropertyValue("--ao-sidebar-w")).toBe("240px");
} finally {
requestAnimationFrameSpy.mockRestore();
cancelAnimationFrameSpy.mockRestore();
}
});
});

View File

@ -79,6 +79,14 @@ export function useResizable({
if (pending !== null) apply(pending);
}, [apply]);
const discardPending = useCallback(() => {
if (frameRef.current !== null) {
window.cancelAnimationFrame(frameRef.current);
frameRef.current = null;
}
pendingWidthRef.current = null;
}, []);
// Restore persisted width on mount.
useEffect(() => {
const saved = Number(window.localStorage.getItem(storageKey));
@ -109,8 +117,10 @@ export function useResizable({
const nextWidth = startWidth + sign * (e.clientX - startX);
if (collapseBelow !== undefined && onCollapse && nextWidth <= collapseBelow) {
collapsed = true;
flushPending();
window.localStorage.setItem(storageKey, String(Math.min(max, Math.max(min, startWidth))));
const preservedWidth = Math.min(max, Math.max(min, startWidth));
discardPending();
apply(preservedWidth);
window.localStorage.setItem(storageKey, String(preservedWidth));
onUp();
onCollapse();
return;
@ -120,7 +130,7 @@ export function useResizable({
window.addEventListener("pointermove", onMove);
window.addEventListener("pointerup", onUp);
},
[applyOnFrame, collapseBelow, edge, flushPending, max, min, onCollapse, storageKey],
[apply, applyOnFrame, collapseBelow, discardPending, edge, flushPending, max, min, onCollapse, storageKey],
);
const onCollapsedPointerDown = useCallback(