Files
buzz/app/(ui)/admin/tl/components/order.ts
T

69 lines
2.0 KiB
TypeScript

export const ORDER_STEP = 10;
export function reorderFlatItems<T extends { id: string }>(
items: T[],
activeId: string,
overId: string,
) {
if (activeId === overId) return items;
const oldIndex = items.findIndex((item) => item.id === activeId);
const newIndex = items.findIndex((item) => item.id === overId);
if (oldIndex === -1 || newIndex === -1) return items;
return arrayMove(items, oldIndex, newIndex);
}
export function midpointOrder(prev?: number, next?: number) {
if (prev == null && next == null) return ORDER_STEP;
if (prev == null) return next! - ORDER_STEP;
if (next == null) return prev + ORDER_STEP;
const middle = Math.floor((prev + next) / 2);
if (middle === prev || middle === next) return null;
return middle;
}
export function normalizedOrders(ids: readonly string[]) {
return ids.map((id, index) => ({
id,
order: (index + 1) * ORDER_STEP,
}));
}
export type OrderItem = { id: string; order: number };
export function plannedOrderUpdates(
items: OrderItem[],
ids: readonly string[],
activeId: string,
staleMessage: string,
) {
const currentIds = items.map(({ id }) => id);
const uniqueIds = new Set(ids);
if (
ids.length === 0 ||
uniqueIds.size !== ids.length ||
currentIds.length !== ids.length ||
currentIds.some((id) => !uniqueIds.has(id))
) {
throw new Error(staleMessage);
}
const index = ids.indexOf(activeId);
if (index === -1) throw new Error("Moved item is missing.");
const byId = new Map(items.map((item) => [item.id, item]));
const previous = index > 0 ? byId.get(ids[index - 1]) : undefined;
const next = index < ids.length - 1 ? byId.get(ids[index + 1]) : undefined;
const nextOrder = midpointOrder(previous?.order, next?.order);
return nextOrder == null
? normalizedOrders(ids)
: [{ id: activeId, order: nextOrder }];
}
function arrayMove<T>(arr: T[], oldIndex: number, newIndex: number) {
return arr.toSpliced(oldIndex, 1).toSpliced(newIndex, 0, arr[oldIndex]);
}