fix(downloads): remove column reorder flicker
Clear old FLIP transforms before committing the new download grid order. Serialize and coalesce column-order persistence, keep live download snapshots from overwriting local layout state, reassert imported settings after older requests, and block overlapping pointer or arrow moves during settling.
This commit is contained in:
@@ -515,6 +515,7 @@ export interface DownloadsTableHeaderProps {
|
||||
}
|
||||
|
||||
function moveColumnWithPointerActions(column: string, direction: -1 | 1, element: HTMLDivElement, actions: DownloadsTableActions): void {
|
||||
if (element.closest<HTMLElement>(".downloads-table")?.classList.contains("is-column-drag-settling")) return;
|
||||
const sibling = direction < 0 ? element.previousElementSibling : element.nextElementSibling;
|
||||
if (!sibling?.matches(".downloads-column-header")) return;
|
||||
const currentRect = element.getBoundingClientRect();
|
||||
@@ -548,6 +549,7 @@ export function DownloadsTableHeader({ actions, columnOrder, gridTemplate, sortC
|
||||
onPointerCancel={(event) => actions.onColumnPointerCancel(column, event)}
|
||||
onPointerDown={(event) => {
|
||||
if (event.button !== 0 || !event.isPrimary) return;
|
||||
if (event.currentTarget.closest<HTMLElement>(".downloads-table")?.classList.contains("is-column-drag-settling")) return;
|
||||
event.currentTarget.setPointerCapture(event.pointerId);
|
||||
actions.onColumnPointerDown(column, event);
|
||||
}}
|
||||
|
||||
@@ -127,3 +127,69 @@ export function clearDownloadColumnDrag(session: DownloadColumnDragSession): voi
|
||||
session.root.querySelectorAll<HTMLElement>("[data-column-dragging]").forEach((element) => delete element.dataset.columnDragging);
|
||||
delete session.root.dataset.columnDragging;
|
||||
}
|
||||
|
||||
export function commitDownloadColumnDrag(
|
||||
session: DownloadColumnDragSession,
|
||||
order: string[],
|
||||
commit: (order: string[]) => void
|
||||
): void {
|
||||
clearDownloadColumnDrag(session);
|
||||
commit(order);
|
||||
}
|
||||
|
||||
export interface DownloadColumnOrderPersistence {
|
||||
applyAuthoritative: (order: string[]) => void;
|
||||
enqueue: (order: string[]) => void;
|
||||
whenIdle: () => Promise<void>;
|
||||
}
|
||||
|
||||
export function createDownloadColumnOrderPersistence(
|
||||
initialOrder: string[],
|
||||
persist: (order: string[]) => Promise<string[]>,
|
||||
apply: (order: string[]) => void
|
||||
): DownloadColumnOrderPersistence {
|
||||
let confirmed = initialOrder;
|
||||
let queued: string[] | null = null;
|
||||
let active: Promise<void> | null = null;
|
||||
let epoch = 0;
|
||||
|
||||
const drain = async (): Promise<void> => {
|
||||
while (queued) {
|
||||
const order = queued;
|
||||
queued = null;
|
||||
const requestEpoch = epoch;
|
||||
try {
|
||||
const persisted = await persist(order);
|
||||
if (requestEpoch !== epoch) continue;
|
||||
confirmed = persisted.length > 0 ? persisted : order;
|
||||
if (!queued) apply(confirmed);
|
||||
} catch {
|
||||
if (requestEpoch === epoch && !queued) apply(confirmed);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const start = (): void => {
|
||||
if (active) return;
|
||||
active = drain().finally(() => {
|
||||
active = null;
|
||||
if (queued) start();
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
applyAuthoritative: (order) => {
|
||||
epoch += 1;
|
||||
confirmed = order;
|
||||
apply(order);
|
||||
queued = active ? order : null;
|
||||
},
|
||||
enqueue: (order) => {
|
||||
queued = order;
|
||||
start();
|
||||
},
|
||||
whenIdle: async () => {
|
||||
while (active) await active;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user