typescript
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
|
||||
interface FolderEntry {
|
||||
id: string | number;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface DocumentEntry {
|
||||
id: string | number;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface NavigableRow {
|
||||
key: string;
|
||||
type: 'folder' | 'document';
|
||||
id: string | number;
|
||||
}
|
||||
|
||||
interface UseDocumentsSelectionOptions {
|
||||
showingSearchResults: boolean;
|
||||
currentSubfolders: FolderEntry[];
|
||||
visibleDocuments: DocumentEntry[];
|
||||
resolveFolderRowKey: (id: string | number) => string | null | undefined;
|
||||
resolveDocumentRowKey: (id: string | number) => string | null | undefined;
|
||||
configureSelectionEnvironment: (config: { visibleRowKeySet: Set<string>; navigableRowKeys: string[] }) => void;
|
||||
visibleRowKeySet: Set<string>;
|
||||
selectedEntries: string[];
|
||||
selectionAnchorRef: { current: string | null };
|
||||
promoteSelectionOrderRaw: (id: string | number) => void;
|
||||
setFocusedDocumentId: (id: string | number | null) => void;
|
||||
setActivePreviewId: (id: string | number | null) => void;
|
||||
clearSelection: () => void;
|
||||
focusedDocumentId: string | number | null;
|
||||
setFocusedRowKey: (value: string | null | ((current: string | null) => string | null)) => void;
|
||||
focusedRowKey: string | null;
|
||||
isFolderRowKey: (key: string | null) => boolean;
|
||||
}
|
||||
|
||||
const useDocumentsSelection = ({
|
||||
showingSearchResults,
|
||||
currentSubfolders,
|
||||
visibleDocuments,
|
||||
resolveFolderRowKey,
|
||||
resolveDocumentRowKey,
|
||||
configureSelectionEnvironment,
|
||||
visibleRowKeySet,
|
||||
selectedEntries,
|
||||
selectionAnchorRef,
|
||||
promoteSelectionOrderRaw,
|
||||
setFocusedDocumentId,
|
||||
setActivePreviewId,
|
||||
clearSelection,
|
||||
focusedDocumentId,
|
||||
setFocusedRowKey,
|
||||
focusedRowKey,
|
||||
isFolderRowKey,
|
||||
}: UseDocumentsSelectionOptions) => {
|
||||
const navigableRows = useMemo<NavigableRow[]>(() => {
|
||||
const entries: NavigableRow[] = [];
|
||||
if (!showingSearchResults) {
|
||||
currentSubfolders.forEach((folder) => {
|
||||
const key = resolveFolderRowKey(folder.id);
|
||||
if (key) {
|
||||
entries.push({ key, type: 'folder', id: folder.id });
|
||||
}
|
||||
});
|
||||
}
|
||||
visibleDocuments.forEach((doc) => {
|
||||
const key = resolveDocumentRowKey(doc.id);
|
||||
if (key) {
|
||||
entries.push({ key, type: 'document', id: doc.id });
|
||||
}
|
||||
});
|
||||
return entries;
|
||||
}, [showingSearchResults, currentSubfolders, visibleDocuments, resolveFolderRowKey, resolveDocumentRowKey]);
|
||||
|
||||
const navigableRowKeys = useMemo(
|
||||
() => navigableRows.map((entry) => entry.key),
|
||||
[navigableRows],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
configureSelectionEnvironment({
|
||||
visibleRowKeySet,
|
||||
navigableRowKeys,
|
||||
});
|
||||
}, [configureSelectionEnvironment, visibleRowKeySet, navigableRowKeys]);
|
||||
|
||||
const promoteSelectionOrder = useCallback(
|
||||
(docId: string | number | null) => {
|
||||
if (!docId) return;
|
||||
promoteSelectionOrderRaw(docId);
|
||||
const rowKey = resolveDocumentRowKey(docId);
|
||||
if (rowKey) {
|
||||
selectionAnchorRef.current = rowKey;
|
||||
}
|
||||
setFocusedDocumentId(docId);
|
||||
setActivePreviewId(docId);
|
||||
},
|
||||
[promoteSelectionOrderRaw, resolveDocumentRowKey, selectionAnchorRef, setFocusedDocumentId, setActivePreviewId],
|
||||
);
|
||||
|
||||
const clearDocumentSelection = useCallback(() => {
|
||||
clearSelection();
|
||||
}, [clearSelection]);
|
||||
|
||||
const prevFocusedDocIdRef = useRef<string | number | null>(focusedDocumentId);
|
||||
useEffect(() => {
|
||||
const previous = prevFocusedDocIdRef.current;
|
||||
if (previous === focusedDocumentId) {
|
||||
return;
|
||||
}
|
||||
prevFocusedDocIdRef.current = focusedDocumentId;
|
||||
if (focusedDocumentId) {
|
||||
setFocusedRowKey(resolveDocumentRowKey(focusedDocumentId));
|
||||
} else {
|
||||
setFocusedRowKey((current) => (isFolderRowKey(current) ? current : null));
|
||||
}
|
||||
}, [focusedDocumentId, resolveDocumentRowKey, setFocusedRowKey, isFolderRowKey]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!navigableRowKeys.length) {
|
||||
if (focusedRowKey) {
|
||||
setFocusedRowKey(null);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (focusedRowKey && navigableRowKeys.includes(focusedRowKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const docKey = focusedDocumentId ? resolveDocumentRowKey(focusedDocumentId) : null;
|
||||
if (docKey && navigableRowKeys.includes(docKey)) {
|
||||
setFocusedRowKey(docKey);
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedKey = selectedEntries.find((key) => navigableRowKeys.includes(key));
|
||||
if (selectedKey) {
|
||||
setFocusedRowKey(selectedKey);
|
||||
return;
|
||||
}
|
||||
|
||||
if (focusedRowKey) {
|
||||
setFocusedRowKey(null);
|
||||
}
|
||||
}, [focusedRowKey, focusedDocumentId, navigableRowKeys, selectedEntries, setFocusedRowKey, resolveDocumentRowKey]);
|
||||
|
||||
return {
|
||||
navigableRows,
|
||||
navigableRowKeys,
|
||||
promoteSelectionOrder,
|
||||
clearDocumentSelection,
|
||||
};
|
||||
};
|
||||
|
||||
export default useDocumentsSelection;
|
||||
Reference in New Issue
Block a user