feat: Refactor DocumentsPanel to use a shared application shell context for state management

This commit is contained in:
2025-12-12 02:57:10 +01:00
parent 34e6c3037f
commit 6ba8084caa
7 changed files with 109 additions and 338 deletions
@@ -2,7 +2,7 @@ import React from 'react';
import type { useWorkspaceSelection } from './useWorkspaceSelection';
import { createSafeContext } from '../utils/createSafeContext';
export type WorkspaceSelectionValue = ReturnType<typeof useWorkspaceSelection>;
type WorkspaceSelectionValue = ReturnType<typeof useWorkspaceSelection>;
const [WorkspaceSelectionContext, useWorkspaceSelectionContext] = createSafeContext<WorkspaceSelectionValue>('WorkspaceSelection');
+2 -5
View File
@@ -4,8 +4,6 @@ import type { DocumentsFilterValue } from '../documents/context/DocumentsFilterC
import type { UseWorkspaceSurfaceArgs } from './useWorkspaceSurface';
import type { Identifier } from '../types/identifiers';
import useDocumentsPanelProps from '../documents/logic/useDocumentsPanelProps';
type WorkspaceSurfaceConfig = Omit<UseWorkspaceSurfaceArgs, 'sidebarHidden' | 'onExpandSidebar'> & {
openDetailPanel?: (documentId: Identifier) => void;
closeDetailPanel?: () => void;
@@ -21,11 +19,10 @@ interface DocumentsShellView {
const useDocumentsShell = (): DocumentsShellView => {
const shell = useAppShell() as any;
const documentsPanelProps = useDocumentsPanelProps(shell as any);
return useMemo(() => {
const surfaceConfig: WorkspaceSurfaceConfig = {
documentsTableProps: documentsPanelProps,
documentsTableProps: {},
detailPanelProps: (shell.detailPanel?.detailPanelProps ?? null) as WorkspaceSurfaceConfig['detailPanelProps'],
detailPanelOpen: Boolean(shell.detailPanel?.detailPanelOpen),
openDetailPanel: shell.detailPanel?.openDetailPanel as WorkspaceSurfaceConfig['openDetailPanel'],
@@ -46,7 +43,7 @@ const useDocumentsShell = (): DocumentsShellView => {
documentsManager: shell.managers?.documentsManager,
foldersManager: shell.folderTree?.foldersManager,
};
}, [shell, documentsPanelProps]);
}, [shell]);
};
export default useDocumentsShell;
-1
View File
@@ -150,7 +150,6 @@ export const useWorkspaceSurface = ({
return {
content: (
<DocumentsPanel
{...documentsTableProps}
headerLeading={sidebarToggle}
/>
),
@@ -1,192 +0,0 @@
import type { WorkspaceSelectionValue } from '../../app/WorkspaceSelectionContext';
import type { Identifier } from '../../types/identifiers';
interface Breadcrumb {
id?: Identifier;
name?: string;
label?: string;
title?: string;
}
interface FolderClickHandlers {
onDrop?: (...args: unknown[]) => void;
onDragOver?: (...args: unknown[]) => void;
onDragLeave?: (...args: unknown[]) => void;
}
interface UseDocumentsPanelPropsArgs {
currentFolderName?: string | null;
breadcrumbs?: Breadcrumb[];
refreshCurrentFolder?: () => void | Promise<void>;
currentSubfolders?: unknown[];
documents?: unknown[];
searchQuery?: string;
searchResultIds?: Identifier[] | null;
folderClickHandlers: FolderClickHandlers;
selectedFolder?: Identifier | 'root' | null;
selectFolder?: (...args: unknown[]) => void;
handleFolderDragStart?: (...args: unknown[]) => void;
handleFolderDragEnd?: (...args: unknown[]) => void;
draggedFolderId?: Identifier | null;
handleFolderRename?: (...args: unknown[]) => void;
handleDocumentTitleUpdate?: (...args: unknown[]) => void;
focusedRowKey?: Identifier | string | null;
draggedDocumentIds?: Identifier[];
handleDocumentDragStart?: (...args: unknown[]) => void;
handleDocumentDragEnd?: (...args: unknown[]) => void;
searchLoading?: boolean;
tagLookupById?: unknown;
activeTagFilters?: Identifier[];
activeCorrespondentFilters?: Identifier[];
ensureAssetUrl?: (...args: unknown[]) => void;
getDocumentAsset?: (...args: unknown[]) => unknown;
handleDocumentTagAttach?: (docId: Identifier, tagId: Identifier) => void;
handleDocumentTagDetach?: (docId: Identifier, tagId: Identifier) => void;
documentsViewMode?: string;
documentsSortField?: string;
documentsSortDirection?: string;
handleDocumentsSortFieldChange?: (field: string) => void;
handleDocumentsSortDirectionToggle?: () => void;
handleDocumentsViewModeChange?: (mode: string) => void;
clearDocumentSelection?: () => void;
handleDeleteSelection?: () => void;
handleEntryPointerCore?: (...args: unknown[]) => void;
tags?: unknown[];
correspondents?: unknown[];
correspondentLookupById?: unknown;
handleBulkTagAddFromDetail?: (...args: unknown[]) => void;
handleBulkTagRemoveFromDetail?: (...args: unknown[]) => void;
handleBulkCorrespondentAdd?: (...args: unknown[]) => void;
handleBulkCorrespondentRemove?: (...args: unknown[]) => void;
handleBulkSelectionReanalyze?: (...args: unknown[]) => void;
folderOptions?: unknown[];
moveDocumentsToFolder?: (...args: unknown[]) => void;
documentLookup?: unknown;
selectionValue: WorkspaceSelectionValue;
}
const useDocumentsPanelProps = (props: UseDocumentsPanelPropsArgs) => {
const {
folderTree: {
currentFolderName,
breadcrumbs,
currentSubfolders,
folderClickHandlers,
selectedFolder,
selectFolder,
handleFolderDragStart,
handleFolderDragEnd,
draggedFolderId,
handleFolderRename,
folderOptions,
moveDocumentsToFolder,
} = {},
search: {
documents,
searchQuery,
searchResultIds,
searchLoading,
documentsViewMode,
documentsSortField,
documentsSortDirection,
handleDocumentsSortFieldChange,
handleDocumentsSortDirectionToggle,
handleDocumentsViewModeChange,
} = {},
ui: {
refreshCurrentFolder,
} = {},
mutations: {
handleDocumentTitleUpdate,
draggedDocumentIds,
handleDocumentDragStart,
handleDocumentDragEnd,
} = {},
selection: {
selectionValue,
handleDeleteSelection,
handleEntryPointerCore,
handleBulkSelectionReanalyze,
} = {},
tags: {
tagLookupById,
activeTagFilters,
tags,
handleDocumentTagAttach,
handleDocumentTagDetach,
handleBulkTagAddFromDetail,
handleBulkTagRemoveFromDetail,
} = {},
correspondents: {
activeCorrespondentFilters,
correspondents,
correspondentLookupById,
handleBulkCorrespondentAdd,
handleBulkCorrespondentRemove,
} = {},
preview: {
ensureAssetUrl,
getDocumentAsset,
} = {},
managers: {
documentLookup,
} = {},
} = props as any;
const focusedRowKey = selectionValue?.focusedEntryKey || null;
return {
currentFolderName,
breadcrumbs,
onRefresh: refreshCurrentFolder,
subfolders: currentSubfolders,
documents,
searchQuery,
searchResultIds,
selectedFolder,
onFolderSelect: selectFolder,
onFolderDrop: folderClickHandlers.onDrop,
onFolderDragOver: folderClickHandlers.onDragOver,
onFolderDragLeave: folderClickHandlers.onDragLeave,
onFolderDragStart: handleFolderDragStart,
onFolderDragEnd: handleFolderDragEnd,
draggedFolderId,
onFolderRename: handleFolderRename,
onDocumentRename: handleDocumentTitleUpdate,
focusedRowKey,
draggingDocumentIds: draggedDocumentIds,
onDocumentDragStart: handleDocumentDragStart,
onDocumentDragEnd: handleDocumentDragEnd,
isSearchLoading: searchLoading,
tagLookupById,
activeTagFilters,
activeCorrespondentFilters,
activeCorrespondentIds: activeCorrespondentFilters,
ensureAssetUrl,
getDocumentAsset,
onDocumentTagAttach: handleDocumentTagAttach,
onDocumentTagDetach: handleDocumentTagDetach,
viewMode: documentsViewMode,
sortField: documentsSortField,
sortDirection: documentsSortDirection,
onSortFieldChange: handleDocumentsSortFieldChange,
onSortDirectionToggle: handleDocumentsSortDirectionToggle,
onViewModeChange: handleDocumentsViewModeChange,
onDeleteSelection: handleDeleteSelection,
onEntryPointer: handleEntryPointerCore,
tags,
correspondents,
correspondentLookupById,
documentLookup,
onBulkTagAdd: handleBulkTagAddFromDetail,
onBulkTagRemove: handleBulkTagRemoveFromDetail,
onBulkCorrespondentAdd: handleBulkCorrespondentAdd,
onBulkCorrespondentRemove: handleBulkCorrespondentRemove,
onBulkReanalyze: handleBulkSelectionReanalyze,
folderOptions,
onMoveDocumentsToFolder: moveDocumentsToFolder,
selectionValue,
};
};
export default useDocumentsPanelProps;
+46 -63
View File
@@ -1,27 +1,29 @@
import React, {
useCallback,
useMemo,
useState,
useRef,
useEffect,
useCallback,
} from 'react';
import TagRemovalZone from '../components/TagRemovalZone';
import { DocumentsList, DocumentsGrid } from '../DocumentsView';
import type { ReactNode } from 'react';
import type {
DocumentsListEntry,
Correspondent,
} from '../../types/documents';
import type { Identifier } from '../../types/identifiers';
const EntryType = {
folder: 'folder' as const,
document: 'document' as const,
};
import DesktopWorkspace from '../../desktop/components/DesktopWorkspace';
import {
WorkspaceSelectionProvider,
useWorkspaceSelectionContext,
type WorkspaceSelectionValue,
} from '../../app/WorkspaceSelectionContext';
import DocumentsPanelHeader, {
DocumentsPanelHeaderConfig,
DocumentsHeaderBreadcrumb,
} from './DocumentsPanelHeader';
import { SelectionFloatingPanel } from '../features/selection/SelectionFloatingActions';
import { createDocumentsTableHeaderActions } from './DocumentsToolbar';
@@ -35,58 +37,31 @@ import { DocumentsAssetContext } from '../context/DocumentsAssetContext';
import { DocumentsViewStateContext } from '../context/DocumentsViewStateContext';
import { DocumentsCommandContext } from '../context/DocumentsCommandContext';
import { useDocumentsContextValues } from './useDocumentsContextValues';
const EntryType = {
folder: 'folder' as const,
document: 'document' as const,
};
export interface DocumentsPanelInnerProps {
headerLeading?: ReactNode;
onBreadcrumbNavigate?: (crumb: DocumentsHeaderBreadcrumb) => void;
[key: string]: any;
}
interface DocumentsPanelProps extends DocumentsPanelInnerProps {
selectionValue: WorkspaceSelectionValue;
correspondentLookupById?: Map<Identifier, Correspondent>;
}
import { useAppShell } from '../../lib/context/AppShellContext';
import type { TagInteractionHandlers } from '../interactions/useTagInteractions';
export interface DocumentsViewProps {
entries: DocumentsListEntry[];
tagHandlers?: TagInteractionHandlers;
[key: string]: any;
}
const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = (props) => {
interface DocumentsPanelProps {
headerLeading?: ReactNode;
}
const DocumentsPanelInner: React.FC<DocumentsPanelProps> = (props) => {
const { headerLeading } = props;
const shell = useAppShell();
const {
headerLeading = null,
onBreadcrumbNavigate,
currentFolderName,
breadcrumbs,
subfolders,
documents,
searchResultIds,
onRefresh = () => { },
sortField,
sortDirection,
onSortFieldChange,
onSortDirectionToggle,
onDeleteSelection,
documentLookup,
tags,
correspondents,
onBulkTagAdd,
onBulkTagRemove,
onBulkCorrespondentAdd,
onBulkCorrespondentRemove,
onBulkReanalyze,
folderOptions,
onMoveDocumentsToFolder,
viewMode = 'list',
onViewModeChange,
} = props;
search: { documents, searchResultIds, documentsViewMode: viewMode, documentsSortField: sortField, documentsSortDirection: sortDirection, handleDocumentsViewModeChange: onViewModeChange, handleDocumentsSortFieldChange: onSortFieldChange, handleDocumentsSortDirectionToggle: onSortDirectionToggle },
folderTree: { currentFolderName, breadcrumbs, currentSubfolders: subfolders, folderOptions, moveDocumentsToFolder: onMoveDocumentsToFolder, refreshCurrentFolder: onRefresh, handleBreadcrumbNavigate: onBreadcrumbNavigate },
selection: { handleDeleteSelection: onDeleteSelection },
managers: { documentLookup },
tags: { tags, handleBulkTagAddFromDetail: onBulkTagAdd, handleBulkTagRemoveFromDetail: onBulkTagRemove },
correspondents: { correspondents, handleBulkCorrespondentAdd: onBulkCorrespondentAdd, handleBulkCorrespondentRemove: onBulkCorrespondentRemove },
mutations: { handleBulkSelectionReanalyze: onBulkReanalyze },
} = shell as any;
const {
assetContextValue,
@@ -95,7 +70,7 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = (props) => {
tagHandlers,
scrollRef,
hasDocumentEntries,
} = useDocumentsContextValues(props);
} = useDocumentsContextValues();
const {
clearSelection,
@@ -119,7 +94,6 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = (props) => {
const showingSearchResults = Array.isArray(searchResultIds);
const rows = showingSearchResults && searchDocuments ? searchDocuments : documents;
const headerTitle = showingSearchResults
? 'Search results'
: currentFolderName || 'Documents';
@@ -150,13 +124,16 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = (props) => {
toggleIncludeDescendants,
],
);
const { tagLookupById, correspondentLookupById } = (shell as any).tags;
const floatingActions = useMemo(() => (
<SelectionFloatingPanel
documentLookup={documentLookup}
tags={tags}
tagLookupById={props.tagLookupById}
tagLookupById={tagLookupById}
correspondents={correspondents}
correspondentLookupById={props.correspondentLookupById}
correspondentLookupById={correspondentLookupById}
onBulkTagAdd={onBulkTagAdd}
onBulkTagRemove={onBulkTagRemove}
onBulkCorrespondentAdd={onBulkCorrespondentAdd}
@@ -170,9 +147,9 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = (props) => {
), [
documentLookup,
tags,
props.tagLookupById,
tagLookupById,
correspondents,
props.correspondentLookupById,
correspondentLookupById,
onBulkTagAdd,
onBulkTagRemove,
onBulkCorrespondentAdd,
@@ -183,6 +160,7 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = (props) => {
onMoveDocumentsToFolder,
clearSelection,
]);
const headerConfig: DocumentsPanelHeaderConfig = useMemo(() => ({
title: headerTitle,
subtitle: null,
@@ -230,14 +208,14 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = (props) => {
const entries = useMemo(() => {
const list: DocumentsListEntry[] = []; // Explicit type
if (!showingSearchResults) {
subfolders.forEach((folder: any) => {
(subfolders || []).forEach((folder: any) => {
if (!folder || !folder.id) {
return;
}
list.push({ type: EntryType.folder, id: folder.id, key: `folder:${folder.id}`, folder });
});
}
rows.forEach((doc: any) => {
(rows || []).forEach((doc: any) => {
if (!doc || !doc.id) {
return;
}
@@ -261,7 +239,7 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = (props) => {
desk: DEFAULT_DESKTOP_CARD_SIZE,
});
const isSearchLoading = props.isSearchLoading || false;
const isSearchLoading = (shell as any).search?.isSearchLoading || false;
const renderBody = () => {
const hasEntries = entries.length > 0;
@@ -328,10 +306,15 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = (props) => {
);
};
const DocumentsPanel: React.FC<DocumentsPanelProps> = ({ selectionValue, ...rest }) => (
<WorkspaceSelectionProvider value={selectionValue}>
<DocumentsPanelInner {...rest} />
</WorkspaceSelectionProvider>
);
const DocumentsPanel: React.FC<DocumentsPanelProps> = (props) => {
const shell = useAppShell();
const selectionValue = (shell as any).selection?.selectionValue;
return (
<WorkspaceSelectionProvider value={selectionValue}>
<DocumentsPanelInner {...props} />
</WorkspaceSelectionProvider>
);
};
export default DocumentsPanel;
@@ -4,7 +4,7 @@ import PanelHeader from '../../components/PanelHeader';
import BreadcrumbTrail from '../../components/BreadcrumbTrail';
import type { Identifier } from '../../types/identifiers';
export interface DocumentsHeaderBreadcrumb {
interface DocumentsHeaderBreadcrumb {
id?: Identifier;
name?: string;
label?: string;
@@ -1,34 +1,28 @@
import { useMemo, useCallback, useRef, useEffect } from 'react';
import type { DocumentsPanelInnerProps } from './DocumentsPanel';
import { isPointerModifierEvent, isPrimaryPointerEvent } from '../features/selection/useEntryPointer';
import { useDocumentsFilter } from '../context/DocumentsFilterContext';
import { useWorkspaceSelectionContext } from '../../app/WorkspaceSelectionContext';
import type { Identifier } from '../../types/identifiers';
import { useStatusToast } from '../../lib/context/StatusToastContext';
import { useTagInteractions } from '../interactions/useTagInteractions';
import { subscribeToToast } from '../features/tagging/tagTransfer';
import { useAppShell } from '../../lib/context/AppShellContext';
const EntryType = {
folder: 'folder',
document: 'document',
};
export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => {
export const useDocumentsContextValues = () => {
const shell = useAppShell();
const {
ensureAssetUrl,
getDocumentAsset,
isSearchLoading,
searchQuery = '',
activeTagFilters = [],
activeCorrespondentFilters = [],
selectedFolder = null,
onDocumentDragStart,
onDocumentDragEnd,
onEntryPointer,
activeCorrespondentIds = [],
draggingDocumentIds = [],
tagLookupById,
} = props;
preview: { ensureAssetUrl, getDocumentAsset },
search: { isSearchLoading, searchQuery, activeTagFilters, activeCorrespondentFilters, searchResultIds, documents },
folderTree: { selectedFolder },
mutations: { handleDocumentDragStart, handleDocumentDragEnd, draggedDocumentIds: draggingDocumentIds, handleDocumentTagAttach, handleDocumentTagDetach },
selection: { handleEntryPointerCore: onEntryPointer },
correspondents: { activeCorrespondentIds, correspondentLookupById },
tags: { tagLookupById },
} = shell as any;
const {
setFocusedEntryKey,
@@ -53,8 +47,8 @@ export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => {
// Handlers
const tagHandlers = useTagInteractions({
onAssignTagToDocument: props.onDocumentTagAttach,
onRemoveTagFromDocument: props.onDocumentTagDetach,
onAssignTagToDocument: handleDocumentTagAttach,
onRemoveTagFromDocument: handleDocumentTagDetach,
onTagClick: toggleTagFilter,
});
@@ -67,14 +61,14 @@ export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => {
() => new Set(activeCorrespondentIds || []),
[activeCorrespondentIds],
);
const showingSearchResults = Array.isArray(props.searchResultIds);
const hasDocumentEntries = (props.documents || []).length > 0 || (showingSearchResults && (props.searchResultIds || []).length > 0);
const showingSearchResults = Array.isArray(searchResultIds);
const hasDocumentEntries = (documents || []).length > 0 || (showingSearchResults && (searchResultIds || []).length > 0);
const viewId = useMemo(() => {
if (showingSearchResults) {
const trimmedQuery = searchQuery.trim();
const tagsKey = [...activeTagFilters].sort().join(',');
const correspondentsKey = [...activeCorrespondentFilters].sort().join(',');
const trimmedQuery = (searchQuery || '').trim();
const tagsKey = [...(activeTagFilters || [])].sort().join(',');
const correspondentsKey = [...(activeCorrespondentFilters || [])].sort().join(',');
return `search:${trimmedQuery}|tags:${tagsKey}|corr:${correspondentsKey}`;
}
const folderKey = selectedFolder && selectedFolder !== '' ? selectedFolder : 'root';
@@ -115,19 +109,19 @@ export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => {
const handleDocumentDragStartLocal = useCallback(
(event: any, doc: any) => {
suppressDocumentClickRef.current = true;
onDocumentDragStart?.(event, doc);
handleDocumentDragStart?.(event, doc);
},
[onDocumentDragStart],
[handleDocumentDragStart],
);
const handleDocumentDragEndLocal = useCallback(
(event: any) => {
onDocumentDragEnd?.(event);
handleDocumentDragEnd?.(event);
requestAnimationFrame(() => {
suppressDocumentClickRef.current = false;
});
},
[onDocumentDragEnd],
[handleDocumentDragEnd],
);
// Context Values Construction
@@ -136,71 +130,61 @@ export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => {
getDocumentAsset,
}), [ensureAssetUrl, getDocumentAsset]);
const draggedFolderId = (shell as any).folderTree?.draggedFolderId;
const viewStateContextValue = useMemo(() => ({
viewId,
scrollRef,
tagLookupById,
correspondentLookupById: props.correspondentLookupById,
correspondentLookupById,
activeCorrespondentIdSet,
draggingDocumentIdsSet,
draggedFolderId: props.draggedFolderId,
draggedFolderId,
}), [
viewId,
scrollRef,
tagLookupById,
activeCorrespondentIdSet,
draggingDocumentIdsSet,
props.draggedFolderId,
props.correspondentLookupById,
draggedFolderId,
correspondentLookupById,
]);
// Use refs to stabilize handlers and avoid massive dependency arrays
const latestPropsRef = useRef(props);
const latestHandlersRef = useRef({
const commandContextValue = useMemo(() => {
const anyShell = shell as any;
return {
folder: {
onClick: handleFolderClick,
onSelect: anyShell.folderTree?.selectFolder,
onRename: anyShell.folderTree?.handleFolderRename,
onDrag: {
start: anyShell.folderTree?.handleFolderDragStart,
end: anyShell.folderTree?.handleFolderDragEnd,
over: anyShell.folderTree?.folderClickHandlers?.onDragOver,
leave: anyShell.folderTree?.folderClickHandlers?.onDragLeave,
drop: anyShell.folderTree?.folderClickHandlers?.onDrop,
},
},
document: {
onRename: anyShell.mutations?.handleDocumentTitleUpdate,
onDrag: {
start: handleDocumentDragStartLocal,
end: handleDocumentDragEndLocal,
},
},
correspondents: {
onClick: toggleCorrespondentFilter,
},
onEntryPointer,
}
}, [
handleFolderClick,
shell,
handleDocumentDragStartLocal,
handleDocumentDragEndLocal,
tagHandlers,
toggleTagFilter,
toggleCorrespondentFilter,
});
// Update refs on every render
latestPropsRef.current = props;
latestHandlersRef.current = {
handleFolderClick,
handleDocumentDragStartLocal,
handleDocumentDragEndLocal,
tagHandlers,
toggleTagFilter,
toggleCorrespondentFilter,
};
const commandContextValue = useMemo(() => ({
folder: {
onClick: (f: any, e: any) => latestHandlersRef.current.handleFolderClick(f, e),
onSelect: (id: Identifier) => latestPropsRef.current.onFolderSelect?.(id),
onRename: (id: Identifier, name: string) => latestPropsRef.current.onFolderRename?.(id, name),
onDrag: {
start: (e: any, f: any) => latestPropsRef.current.onFolderDragStart?.(e, f),
end: (e: any) => latestPropsRef.current.onFolderDragEnd?.(e),
over: (e: any, f: any) => latestPropsRef.current.onFolderDragOver?.(e, f),
leave: (e: any) => latestPropsRef.current.onFolderDragLeave?.(e),
drop: (e: any, f: any) => latestPropsRef.current.onFolderDrop?.(e, f),
},
},
document: {
onRename: (id: Identifier, name: string) => latestPropsRef.current.onDocumentRename?.(id, name),
onDrag: {
start: (e: any, d: any) => latestHandlersRef.current.handleDocumentDragStartLocal(e, d),
end: (e: any) => latestHandlersRef.current.handleDocumentDragEndLocal(e),
},
},
correspondents: {
onClick: (c: any) => latestHandlersRef.current.toggleCorrespondentFilter(c),
},
onEntryPointer: (entry: any, e: any) => latestPropsRef.current.onEntryPointer?.(entry, e),
}), []);
onEntryPointer,
]);
return {
assetContextValue,