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; resolveDocumentRowKey: (id: string | number) => string | null; configureSelectionEnvironment: (config: { visibleRowKeySet: Set; navigableRowKeys: string[] }) => void; visibleRowKeySet: Set; 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(() => { 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(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;