refactor: Introduce a layered architecture for card interactions, separating drag logic, and selection handling.

This commit is contained in:
2025-11-26 15:46:04 +01:00
parent d44c33dd69
commit 81194032e0
4 changed files with 257 additions and 44 deletions
+32 -14
View File
@@ -15,6 +15,7 @@ import '../styles/workspace/workspace-layout.css';
import '../styles/workspace/workspace-items.css';
import '../styles/workspace/workspace-cards.css';
import { useWorkspaceSelectionContext } from '../app/WorkspaceSelectionContext';
import { createDocumentEntryKey } from '../app/entryKey';
import type { Identifier } from '../types/identifiers';
import type { DocumentsListEntry, Document } from '../types/documents';
@@ -56,10 +57,16 @@ export interface DesktopWorkspaceProps {
}
// Wrapper to handle hooks per card
const DesktopDocumentContainer: React.FC<React.ComponentProps<typeof DesktopDocumentCard>> = React.memo((props) => {
const { layoutCard, selected } = props;
const DesktopDocumentContainer: React.FC<React.ComponentProps<typeof DesktopDocumentCard> & {
onSelect: (ids: string[], extend?: boolean) => void;
onDeselect: (ids: string[]) => void;
onDocumentActivate?: (id: string) => void;
selection: string[];
}> = React.memo((props) => {
const { layoutCard, selected, onSelect, onDeselect, onDocumentActivate, selection } = props;
// We assume layoutCard is always present in this context
const cardPointerHandlers = useCardPointer(layoutCard!, !!selected);
const cardPointerHandlers = useCardPointer(layoutCard!, !!selected, selection, onSelect, onDeselect, onDocumentActivate);
return (
<DesktopDocumentCard
@@ -94,22 +101,18 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
// Selection Context
const {
selectedDocumentIds: contextSelectedIds,
setSelectedDocumentIds,
selectedDocumentIds,
setSelectedEntries,
clearSelection,
} = useWorkspaceSelectionContext();
const [localSelectedIds, setLocalSelectedIds] = useState<Identifier[]>([]);
const selectedDocumentIds = contextSelectedIds || localSelectedIds;
const handleSelectionChange = useCallback((ids: Identifier[]) => {
if (setSelectedDocumentIds) {
setSelectedDocumentIds(ids);
} else {
setLocalSelectedIds(ids);
if (setSelectedEntries) {
const keys = ids.map(id => createDocumentEntryKey(id));
setSelectedEntries(keys);
}
onSelectionChange?.(ids);
}, [setSelectedDocumentIds, onSelectionChange]);
}, [setSelectedEntries, onSelectionChange]);
const onClearSelection = useCallback(() => {
clearSelection ? clearSelection() : handleSelectionChange([]);
@@ -207,7 +210,7 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
ensureAssetUrl={ensureAssetUrl}
getDocumentAsset={getDocumentAsset}
handleNavigatorSnapshot={() => { }}
onDocumentActivate={onDocumentActivate}
onDocumentActivate={(id) => { onDocumentActivate?.({ id } as DeskDocument) }}
layoutCard={layoutCard}
onTagDragEnter={tagInteractions.handleTagDragEnterDoc}
onTagDragOver={tagInteractions.handleTagDragOverDoc}
@@ -220,6 +223,21 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
tagTargetActive={tagDropTargetId === docId}
tagTargetPending={pendingTagDocId === docId}
pendingRemovalTag={pendingRemovalTag}
onSelect={(ids, extend = false) => {
if (!extend) {
handleSelectionChange(ids);
} else {
const newSelection = new Set(selectedDocumentIds);
ids.forEach(id => newSelection.add(id));
handleSelectionChange(Array.from(newSelection));
}
}}
onDeselect={(ids) => {
const newSelection = new Set(selectedDocumentIds);
ids.forEach(id => newSelection.delete(id));
handleSelectionChange(Array.from(newSelection));
}}
selection={selectedDocumentIds}
/>
);
})}