chore(repo): initialize planarchy workspace
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { useMemo, useCallback } from "react";
|
||||
import type { ViewPrefsHandle } from "./useViewPrefs.js";
|
||||
|
||||
/**
|
||||
* Manages manual drag-to-reorder row ordering for a table.
|
||||
*
|
||||
* - When a column sort is active (sortField !== null), row order is suppressed —
|
||||
* the sorted rows are returned unchanged and dragging is disabled.
|
||||
* - When no column sort is active and a saved rowOrder exists, rows are sorted
|
||||
* by their position in rowOrder; rows without a saved position go to the end.
|
||||
* - Calling reorder() saves the new order and clears any active column sort.
|
||||
*
|
||||
* Each user's rowOrder is persisted independently via useViewPrefs.
|
||||
*/
|
||||
export function useRowOrder<T extends { id: string }>(
|
||||
rows: T[],
|
||||
prefs: Pick<ViewPrefsHandle, "rowOrder" | "setRowOrder">,
|
||||
activeSortField: string | null,
|
||||
resetSort: () => void,
|
||||
) {
|
||||
const { rowOrder, setRowOrder } = prefs;
|
||||
|
||||
const orderedRows = useMemo((): T[] => {
|
||||
// Column sort takes precedence — ignore manual order while sorting
|
||||
if (activeSortField !== null) return rows;
|
||||
if (rowOrder.length === 0) return rows;
|
||||
|
||||
const indexMap = new Map(rowOrder.map((id, i) => [id, i]));
|
||||
return [...rows].sort((a, b) => {
|
||||
const ai = indexMap.get(a.id) ?? Infinity;
|
||||
const bi = indexMap.get(b.id) ?? Infinity;
|
||||
return ai - bi;
|
||||
});
|
||||
}, [rows, rowOrder, activeSortField]);
|
||||
|
||||
const reorder = useCallback(
|
||||
(draggedId: string, targetId: string) => {
|
||||
if (draggedId === targetId) return;
|
||||
|
||||
// Build current ordered ID list from the current orderedRows snapshot
|
||||
// (works correctly even when rowOrder is empty / partial)
|
||||
const currentIds = orderedRows.map((r) => r.id);
|
||||
const fromIdx = currentIds.indexOf(draggedId);
|
||||
const toIdx = currentIds.indexOf(targetId);
|
||||
if (fromIdx === -1 || toIdx === -1) return;
|
||||
|
||||
const next = [...currentIds];
|
||||
next.splice(fromIdx, 1);
|
||||
next.splice(toIdx, 0, draggedId);
|
||||
|
||||
// Clear any active column sort (mutual exclusion)
|
||||
resetSort();
|
||||
setRowOrder(next);
|
||||
},
|
||||
[orderedRows, resetSort, setRowOrder],
|
||||
);
|
||||
|
||||
const resetOrder = useCallback(() => {
|
||||
setRowOrder([]);
|
||||
}, [setRowOrder]);
|
||||
|
||||
const isCustomOrder = rowOrder.length > 0 && activeSortField === null;
|
||||
|
||||
return { orderedRows, reorder, isCustomOrder, resetOrder };
|
||||
}
|
||||
Reference in New Issue
Block a user