mirror of
https://github.com/docmost/docmost.git
synced 2026-05-15 21:24:09 +08:00
feat(base): add use-row-selection hook
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
import { useCallback } from "react";
|
||||
import { useAtom } from "jotai";
|
||||
import {
|
||||
selectedRowIdsAtom,
|
||||
lastToggledRowIndexAtom,
|
||||
} from "@/features/base/atoms/base-atoms";
|
||||
|
||||
type ToggleOpts = {
|
||||
shiftKey: boolean;
|
||||
rowIndex: number;
|
||||
orderedRowIds: string[];
|
||||
};
|
||||
|
||||
export function useRowSelection() {
|
||||
const [selectedIds, setSelectedIds] = useAtom(selectedRowIdsAtom) as unknown as [
|
||||
Set<string>,
|
||||
(val: Set<string> | ((prev: Set<string>) => Set<string>)) => void,
|
||||
];
|
||||
const [lastToggledIndex, setLastToggledIndex] = useAtom(
|
||||
lastToggledRowIndexAtom,
|
||||
) as unknown as [number | null, (val: number | null) => void];
|
||||
|
||||
const isSelected = useCallback(
|
||||
(rowId: string) => selectedIds.has(rowId),
|
||||
[selectedIds],
|
||||
);
|
||||
|
||||
const toggle = useCallback(
|
||||
(rowId: string, opts: ToggleOpts) => {
|
||||
const { shiftKey, rowIndex, orderedRowIds } = opts;
|
||||
const next = new Set(selectedIds);
|
||||
|
||||
if (shiftKey && lastToggledIndex !== null && lastToggledIndex !== rowIndex) {
|
||||
const start = Math.min(lastToggledIndex, rowIndex);
|
||||
const end = Math.max(lastToggledIndex, rowIndex);
|
||||
const anchorId = orderedRowIds[lastToggledIndex];
|
||||
const turnOn = anchorId ? next.has(anchorId) : true;
|
||||
for (let i = start; i <= end; i += 1) {
|
||||
const id = orderedRowIds[i];
|
||||
if (!id) continue;
|
||||
if (turnOn) next.add(id);
|
||||
else next.delete(id);
|
||||
}
|
||||
} else {
|
||||
if (next.has(rowId)) next.delete(rowId);
|
||||
else next.add(rowId);
|
||||
}
|
||||
|
||||
setSelectedIds(next);
|
||||
setLastToggledIndex(rowIndex);
|
||||
},
|
||||
[selectedIds, lastToggledIndex, setSelectedIds, setLastToggledIndex],
|
||||
);
|
||||
|
||||
const toggleAll = useCallback(
|
||||
(loadedRowIds: string[]) => {
|
||||
if (loadedRowIds.length === 0) return;
|
||||
const allSelected = loadedRowIds.every((id) => selectedIds.has(id));
|
||||
if (allSelected) {
|
||||
setSelectedIds(new Set());
|
||||
} else {
|
||||
setSelectedIds(new Set(loadedRowIds));
|
||||
}
|
||||
setLastToggledIndex(null);
|
||||
},
|
||||
[selectedIds, setSelectedIds, setLastToggledIndex],
|
||||
);
|
||||
|
||||
const clear = useCallback(() => {
|
||||
setSelectedIds(new Set());
|
||||
setLastToggledIndex(null);
|
||||
}, [setSelectedIds, setLastToggledIndex]);
|
||||
|
||||
const removeIds = useCallback(
|
||||
(rowIds: string[]) => {
|
||||
if (rowIds.length === 0) return;
|
||||
setSelectedIds((prev) => {
|
||||
if (prev.size === 0) return prev;
|
||||
let changed = false;
|
||||
const next = new Set(prev);
|
||||
for (const id of rowIds) {
|
||||
if (next.delete(id)) changed = true;
|
||||
}
|
||||
return changed ? next : prev;
|
||||
});
|
||||
},
|
||||
[setSelectedIds],
|
||||
);
|
||||
|
||||
return {
|
||||
selectedIds,
|
||||
selectionCount: selectedIds.size,
|
||||
isSelected,
|
||||
toggle,
|
||||
toggleAll,
|
||||
clear,
|
||||
removeIds,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user