2026-07-03 21:59:16 -05:00
|
|
|
interface Identified {
|
|
|
|
|
id: string | number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function moveInArray<T>(items: T[], fromIndex: number, toIndex: number): T[] {
|
2026-05-30 20:04:50 -05:00
|
|
|
if (!Array.isArray(items)) return [];
|
|
|
|
|
if (fromIndex === toIndex || fromIndex < 0 || toIndex < 0 || fromIndex >= items.length || toIndex >= items.length) {
|
|
|
|
|
return items;
|
|
|
|
|
}
|
|
|
|
|
const next = [...items];
|
|
|
|
|
const [moved] = next.splice(fromIndex, 1);
|
2026-07-03 21:59:16 -05:00
|
|
|
if (moved === undefined) return next; // in-range by the guard above; satisfies noUncheckedIndexedAccess
|
2026-05-30 20:04:50 -05:00
|
|
|
next.splice(toIndex, 0, moved);
|
|
|
|
|
return next;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-03 21:59:16 -05:00
|
|
|
export function reorderPayload(items: ReadonlyArray<Identified> | null | undefined): Record<string, number> {
|
2026-05-30 20:04:50 -05:00
|
|
|
return Object.fromEntries((items || []).map((item, index) => [item.id, index]));
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-03 21:59:16 -05:00
|
|
|
export function movedItemId(
|
|
|
|
|
before: ReadonlyArray<Identified> | null | undefined,
|
|
|
|
|
after: ReadonlyArray<Identified> | null | undefined,
|
|
|
|
|
): string | number | null {
|
2026-05-30 20:04:50 -05:00
|
|
|
const moved = (after || []).find((item, index) => item.id !== before?.[index]?.id);
|
|
|
|
|
return moved?.id || after?.[0]?.id || null;
|
|
|
|
|
}
|