mono/packages/ui/src/modules/storage/hooks/useSelection.ts
2026-03-21 20:18:25 +01:00

74 lines
2.6 KiB
TypeScript

import { useState, useCallback, useEffect } from 'react';
import { INode } from '@/modules/storage/types';
export interface UseSelectionProps {
sorted: INode[];
canGoUp: boolean;
onSelect?: (nodes: INode[] | INode | null) => void;
}
export function useSelection({ sorted, canGoUp, onSelect }: UseSelectionProps) {
const [focusIdx, setFocusIdx] = useState(-1);
const [selected, setSelected] = useState<INode[]>([]);
useEffect(() => {
if (onSelect) onSelect(selected);
}, [selected, onSelect]);
const itemCount = sorted.length + (canGoUp ? 1 : 0);
const getNode = useCallback((idx: number): INode | null => {
if (canGoUp && idx === 0) return null;
return sorted[canGoUp ? idx - 1 : idx] ?? null;
}, [sorted, canGoUp]);
const handleItemClick = useCallback((idx: number, e?: React.MouseEvent | React.KeyboardEvent) => {
setFocusIdx(idx);
const node = getNode(idx);
if (!node) return;
if (e && e.shiftKey && selected.length > 0) {
const lastSelected = selected[selected.length - 1];
const lastIdx = sorted.indexOf(lastSelected);
if (lastIdx !== -1) {
const actualLastIdx = canGoUp ? lastIdx + 1 : lastIdx;
const start = Math.min(actualLastIdx, idx);
const end = Math.max(actualLastIdx, idx);
const newSel: INode[] = [];
for (let i = start; i <= end; i++) {
const n = getNode(i);
if (n) newSel.push(n);
}
if (e.ctrlKey || e.metaKey) {
setSelected(Array.from(new Set([...selected, ...newSel])));
} else {
setSelected(newSel);
}
} else {
setSelected([node]);
}
} else if (e && (e.ctrlKey || e.metaKey)) {
setSelected(prev => prev.some(n => n.path === node.path) ? prev.filter(n => n.path !== node.path) : [...prev, node]);
} else {
setSelected(prev => (prev.length === 1 && prev[0].path === node.path) ? [] : [node]);
}
document.querySelector<HTMLElement>('.fb-panel-container')?.focus({ preventScroll: true });
}, [getNode, sorted, selected, canGoUp]);
const clearSelection = useCallback(() => {
setSelected([]);
setFocusIdx(-1);
}, []);
return {
focusIdx,
setFocusIdx,
selected,
setSelected,
itemCount,
getNode,
handleItemClick,
clearSelection
};
}