refactor(web): extract timeline drag cleanup
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { cleanupTimelineDragState } from "./timelineDragCleanup.js";
|
||||
|
||||
describe("timelineDragCleanup", () => {
|
||||
it("runs registered cleanup callbacks, clears previews, and resets refs", () => {
|
||||
const projectCleanup = vi.fn();
|
||||
const allocCleanup = vi.fn();
|
||||
const multiCleanup = vi.fn();
|
||||
const projectPreview = { id: "project-preview" };
|
||||
const allocPreview = { id: "alloc-preview" };
|
||||
const clearPreview = vi.fn();
|
||||
|
||||
const projectDragCleanupRef = { current: projectCleanup };
|
||||
const allocDragCleanupRef = { current: allocCleanup };
|
||||
const multiSelectCleanupRef = { current: multiCleanup };
|
||||
const projectPreviewRef = { current: projectPreview };
|
||||
const allocPreviewRef = { current: allocPreview };
|
||||
const dragStateRef = { current: { drag: true } };
|
||||
const allocDragRef = { current: { alloc: true } };
|
||||
const rangeStateRef = { current: { range: true } };
|
||||
const multiSelectRef = { current: { multi: true } };
|
||||
|
||||
const initialDragState = { drag: false };
|
||||
const initialAllocDragState = { alloc: false };
|
||||
const initialRangeState = { range: false };
|
||||
const initialMultiSelectState = { multi: false };
|
||||
|
||||
cleanupTimelineDragState({
|
||||
projectDragCleanupRef,
|
||||
allocDragCleanupRef,
|
||||
multiSelectCleanupRef,
|
||||
projectPreviewRef,
|
||||
allocPreviewRef,
|
||||
dragStateRef,
|
||||
allocDragRef,
|
||||
rangeStateRef,
|
||||
multiSelectRef,
|
||||
initialDragState,
|
||||
initialAllocDragState,
|
||||
initialRangeState,
|
||||
initialMultiSelectState,
|
||||
clearPreview,
|
||||
});
|
||||
|
||||
expect(projectCleanup).toHaveBeenCalledOnce();
|
||||
expect(allocCleanup).toHaveBeenCalledOnce();
|
||||
expect(multiCleanup).toHaveBeenCalledOnce();
|
||||
expect(clearPreview).toHaveBeenNthCalledWith(1, projectPreview);
|
||||
expect(clearPreview).toHaveBeenNthCalledWith(2, allocPreview);
|
||||
expect(projectDragCleanupRef.current).toBeNull();
|
||||
expect(allocDragCleanupRef.current).toBeNull();
|
||||
expect(multiSelectCleanupRef.current).toBeNull();
|
||||
expect(projectPreviewRef.current).toBeNull();
|
||||
expect(allocPreviewRef.current).toBeNull();
|
||||
expect(dragStateRef.current).toBe(initialDragState);
|
||||
expect(allocDragRef.current).toBe(initialAllocDragState);
|
||||
expect(rangeStateRef.current).toBe(initialRangeState);
|
||||
expect(multiSelectRef.current).toBe(initialMultiSelectState);
|
||||
});
|
||||
|
||||
it("tolerates missing cleanups and preview sessions", () => {
|
||||
const clearPreview = vi.fn();
|
||||
|
||||
cleanupTimelineDragState({
|
||||
projectDragCleanupRef: { current: null },
|
||||
allocDragCleanupRef: { current: null },
|
||||
multiSelectCleanupRef: { current: null },
|
||||
projectPreviewRef: { current: null },
|
||||
allocPreviewRef: { current: null },
|
||||
dragStateRef: { current: { drag: true } },
|
||||
allocDragRef: { current: { alloc: true } },
|
||||
rangeStateRef: { current: { range: true } },
|
||||
multiSelectRef: { current: { multi: true } },
|
||||
initialDragState: { drag: false },
|
||||
initialAllocDragState: { alloc: false },
|
||||
initialRangeState: { range: false },
|
||||
initialMultiSelectState: { multi: false },
|
||||
clearPreview,
|
||||
});
|
||||
|
||||
expect(clearPreview).toHaveBeenCalledTimes(2);
|
||||
expect(clearPreview).toHaveBeenNthCalledWith(1, null);
|
||||
expect(clearPreview).toHaveBeenNthCalledWith(2, null);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
type MutableCurrent<T> = {
|
||||
current: T;
|
||||
};
|
||||
|
||||
type TimelineDragCleanupParams<
|
||||
DragState,
|
||||
AllocDragState,
|
||||
RangeState,
|
||||
MultiSelectState,
|
||||
PreviewSession,
|
||||
> = {
|
||||
projectDragCleanupRef: MutableCurrent<(() => void) | null>;
|
||||
allocDragCleanupRef: MutableCurrent<(() => void) | null>;
|
||||
multiSelectCleanupRef: MutableCurrent<(() => void) | null>;
|
||||
projectPreviewRef: MutableCurrent<PreviewSession | null>;
|
||||
allocPreviewRef: MutableCurrent<PreviewSession | null>;
|
||||
dragStateRef: MutableCurrent<DragState>;
|
||||
allocDragRef: MutableCurrent<AllocDragState>;
|
||||
rangeStateRef: MutableCurrent<RangeState>;
|
||||
multiSelectRef: MutableCurrent<MultiSelectState>;
|
||||
initialDragState: DragState;
|
||||
initialAllocDragState: AllocDragState;
|
||||
initialRangeState: RangeState;
|
||||
initialMultiSelectState: MultiSelectState;
|
||||
clearPreview: (session: PreviewSession | null) => void;
|
||||
};
|
||||
|
||||
export function cleanupTimelineDragState<
|
||||
DragState,
|
||||
AllocDragState,
|
||||
RangeState,
|
||||
MultiSelectState,
|
||||
PreviewSession,
|
||||
>({
|
||||
projectDragCleanupRef,
|
||||
allocDragCleanupRef,
|
||||
multiSelectCleanupRef,
|
||||
projectPreviewRef,
|
||||
allocPreviewRef,
|
||||
dragStateRef,
|
||||
allocDragRef,
|
||||
rangeStateRef,
|
||||
multiSelectRef,
|
||||
initialDragState,
|
||||
initialAllocDragState,
|
||||
initialRangeState,
|
||||
initialMultiSelectState,
|
||||
clearPreview,
|
||||
}: TimelineDragCleanupParams<
|
||||
DragState,
|
||||
AllocDragState,
|
||||
RangeState,
|
||||
MultiSelectState,
|
||||
PreviewSession
|
||||
>) {
|
||||
projectDragCleanupRef.current?.();
|
||||
allocDragCleanupRef.current?.();
|
||||
multiSelectCleanupRef.current?.();
|
||||
|
||||
projectDragCleanupRef.current = null;
|
||||
allocDragCleanupRef.current = null;
|
||||
multiSelectCleanupRef.current = null;
|
||||
|
||||
clearPreview(projectPreviewRef.current);
|
||||
clearPreview(allocPreviewRef.current);
|
||||
|
||||
projectPreviewRef.current = null;
|
||||
allocPreviewRef.current = null;
|
||||
|
||||
dragStateRef.current = initialDragState;
|
||||
allocDragRef.current = initialAllocDragState;
|
||||
rangeStateRef.current = initialRangeState;
|
||||
multiSelectRef.current = initialMultiSelectState;
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
} from "./timelineAllocationMultiDrag.js";
|
||||
import { resolveAllocationRelease } from "./timelineAllocationRelease.js";
|
||||
import { createAllocationDragState } from "./timelineAllocationDragState.js";
|
||||
import { cleanupTimelineDragState } from "./timelineDragCleanup.js";
|
||||
import { attachDocumentMouseDrag } from "./timelineDocumentDrag.js";
|
||||
import { buildProjectShiftMutationInput, createProjectDragState } from "./timelineProjectDrag.js";
|
||||
import {
|
||||
@@ -1005,20 +1006,22 @@ export function useTimelineDrag({
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
projectDragCleanupRef.current?.();
|
||||
allocDragCleanupRef.current?.();
|
||||
multiSelectCleanupRef.current?.();
|
||||
projectDragCleanupRef.current = null;
|
||||
allocDragCleanupRef.current = null;
|
||||
multiSelectCleanupRef.current = null;
|
||||
clearLivePreview(projectPreviewRef.current);
|
||||
clearLivePreview(allocPreviewRef.current);
|
||||
projectPreviewRef.current = null;
|
||||
allocPreviewRef.current = null;
|
||||
dragStateRef.current = INITIAL_DRAG_STATE;
|
||||
allocDragRef.current = INITIAL_ALLOC_DRAG;
|
||||
rangeStateRef.current = INITIAL_RANGE_STATE;
|
||||
multiSelectRef.current = INITIAL_MULTI_SELECT;
|
||||
cleanupTimelineDragState({
|
||||
projectDragCleanupRef,
|
||||
allocDragCleanupRef,
|
||||
multiSelectCleanupRef,
|
||||
projectPreviewRef,
|
||||
allocPreviewRef,
|
||||
dragStateRef,
|
||||
allocDragRef,
|
||||
rangeStateRef,
|
||||
multiSelectRef,
|
||||
initialDragState: INITIAL_DRAG_STATE,
|
||||
initialAllocDragState: INITIAL_ALLOC_DRAG,
|
||||
initialRangeState: INITIAL_RANGE_STATE,
|
||||
initialMultiSelectState: INITIAL_MULTI_SELECT,
|
||||
clearPreview: clearLivePreview,
|
||||
});
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user