diff --git a/frontend/src/documents/components/DocumentEntry.tsx b/frontend/src/documents/components/DocumentEntry.tsx index 1d339c9..3e067b9 100644 --- a/frontend/src/documents/components/DocumentEntry.tsx +++ b/frontend/src/documents/components/DocumentEntry.tsx @@ -2,9 +2,11 @@ import React from 'react'; import type { DocumentViewLogic } from '../logic/useDocumentViewLogic'; import { useDocumentItemLogic } from '../logic/useDocumentItemLogic'; import EntryShell from './EntryShell'; +import type { TagDragHandlers } from '../interactions/useTagInteractions'; interface DocumentEntryProps { doc: any; + tagDragHandlers?: TagDragHandlers; viewLogic: DocumentViewLogic; component: React.ElementType; className?: string; @@ -13,8 +15,8 @@ interface DocumentEntryProps { } const DocumentEntry: React.FC = (props) => { - const { doc, component, className, role, children, viewLogic } = props; - const logic = useDocumentItemLogic({ doc, viewLogic }); + const { doc, tagDragHandlers, component, className, role, children, viewLogic } = props; + const logic = useDocumentItemLogic({ doc, tagDragHandlers, viewLogic }); return ( | null; onTagClick?: (tagId: Identifier) => void; - docId: Identifier; - onTagDragStart?: (event: React.DragEvent, tag: DocumentTag) => void; - onTagDragEnd?: (event: React.DragEvent) => void; + doc: Document; + tagDragHandlers?: TagDragHandlers; } const DocumentTags: React.FC = ({ tags, tagLookupById, onTagClick, - docId, - onTagDragStart, - onTagDragEnd, + doc, + tagDragHandlers, }) => { const sortedTags = useMemo(() => { return [...tags].sort((a, b) => { @@ -39,7 +38,7 @@ const DocumentTags: React.FC = ({ const style = getTagColorStyle(colorSource); const tagId = tag?.id ?? null; const clickable = tagId != null && typeof onTagClick === 'function'; - const key = tagId ?? `${docId}-tag-${index}`; + const key = tagId ?? `${doc.id}-tag-${index}`; return ( = ({ if (tagId == null) return; onTagClick?.(tagId); } : undefined} - draggable - onDragStart={(event) => { - // Let the hook handle the data transfer and UI - if (tagId && onTagDragStart) { - onTagDragStart(event, tag); - } - }} - onDragEnd={(event) => { - // Let the hook handle the cleanup and logic - onTagDragEnd?.(event); - }} + draggable={!!tagId} + onDragStart={(event) => tagId && tagDragHandlers?.onTagDragStart(event, doc, tag)} + onDragEnd={tagDragHandlers?.onTagDragEnd} onKeyDown={clickable ? (event) => { if (event.key === 'Enter' || event.key === ' ') { event.preventDefault(); diff --git a/frontend/src/documents/components/DocumentsGridCard.tsx b/frontend/src/documents/components/DocumentsGridCard.tsx index 0cee0d4..cc591a2 100644 --- a/frontend/src/documents/components/DocumentsGridCard.tsx +++ b/frontend/src/documents/components/DocumentsGridCard.tsx @@ -12,20 +12,22 @@ import EntryCorrespondents from './EntryCorrespondents'; import EntryTags from './EntryTags'; import FolderEntry from './FolderEntry'; import DocumentEntry from './DocumentEntry'; +import { TagDragHandlers } from '../interactions/useTagInteractions'; interface DocumentsGridCardProps { entry: DocumentsListEntry; viewLogic: DocumentViewLogic; iconSize?: number; + tagDragHandlers?: TagDragHandlers; } const DocumentsGridCard: React.FC = (props) => { - const { entry, iconSize } = props; + const { entry, iconSize, tagDragHandlers } = props; const { ensureAssetUrl, getDocumentAsset } = useDocumentsAssetContext(); const { scrollRef, activeCorrespondentIdSet, tagLookupById } = useDocumentsViewStateContext(); const { correspondents: { onClick: onCorrespondentClick }, - tags: { onClick: onTagClick, onDetach: onDocumentTagDetach } + tags: { onClick: onTagClick } } = useDocumentsCommandContext(); if (entry.type === 'folder') { @@ -78,6 +80,7 @@ const DocumentsGridCard: React.FC = (props) => { return ( = (props) => { tags={doc.tags || []} tagLookupById={tagLookupById} onTagClick={onTagClick} - docId={doc.id} - onDocumentTagDetach={onDocumentTagDetach} - onTagDragStart={logic.handlers.onTagDragStart} - onTagDragEnd={logic.handlers.onTagDragEnd} + doc={doc} + tagDragHandlers={logic.handlers.tagDragHandlers} /> diff --git a/frontend/src/documents/components/DocumentsListRow.tsx b/frontend/src/documents/components/DocumentsListRow.tsx index 09670a5..5ff7598 100644 --- a/frontend/src/documents/components/DocumentsListRow.tsx +++ b/frontend/src/documents/components/DocumentsListRow.tsx @@ -14,19 +14,22 @@ import EntryTags from './EntryTags'; import FolderEntry from './FolderEntry'; import DocumentEntry from './DocumentEntry'; +import { TagDragHandlers } from '../interactions/useTagInteractions'; + interface DocumentsListRowProps { entry: DocumentsListEntry; viewLogic: DocumentViewLogic; iconSize?: number; + tagDragHandlers?: TagDragHandlers; } const DocumentsListRow: React.FC = (props) => { - const { entry, iconSize } = props; + const { entry, iconSize, tagDragHandlers } = props; const { ensureAssetUrl, getDocumentAsset } = useDocumentsAssetContext(); const { scrollRef, activeCorrespondentIdSet, tagLookupById } = useDocumentsViewStateContext(); const { correspondents: { onClick: onCorrespondentClick }, - tags: { onClick: onTagClick, onDetach: onDocumentTagDetach } + tags: { onClick: onTagClick } } = useDocumentsCommandContext(); if (entry.type === 'folder') { @@ -88,6 +91,7 @@ const DocumentsListRow: React.FC = (props) => { return ( = (props) => { tags={doc.tags || []} tagLookupById={tagLookupById} onTagClick={onTagClick} - docId={doc.id} - onDocumentTagDetach={onDocumentTagDetach} - onTagDragStart={logic.handlers.onTagDragStart} - onTagDragEnd={logic.handlers.onTagDragEnd} + doc={doc} + tagDragHandlers={logic.handlers.tagDragHandlers} /> diff --git a/frontend/src/documents/components/EntryTags.tsx b/frontend/src/documents/components/EntryTags.tsx index 146008a..84d45c5 100644 --- a/frontend/src/documents/components/EntryTags.tsx +++ b/frontend/src/documents/components/EntryTags.tsx @@ -1,16 +1,15 @@ import React from 'react'; import DocumentTags from './DocumentTags'; +import type { Document, DocumentTag } from '../../types/documents'; +import type { TagDragHandlers } from '../interactions/useTagInteractions'; import type { Identifier } from '../../types/identifiers'; -import type { DocumentTag } from '../../types/documents'; interface EntryTagsProps { tags: DocumentTag[]; tagLookupById?: Map | null; onTagClick?: (tagId: Identifier) => void; - docId: Identifier; - onDocumentTagDetach?: (docId: Identifier, tagId: Identifier) => void; - onTagDragStart?: (event: React.DragEvent, tag: DocumentTag) => void; - onTagDragEnd?: (event: React.DragEvent) => void; + doc: Document; + tagDragHandlers?: TagDragHandlers; } const EntryTags: React.FC = (props) => { @@ -23,10 +22,8 @@ const EntryTags: React.FC = (props) => { tags={props.tags} tagLookupById={props.tagLookupById} onTagClick={props.onTagClick} - docId={props.docId} - onDocumentTagDetach={props.onDocumentTagDetach} - onTagDragStart={props.onTagDragStart} - onTagDragEnd={props.onTagDragEnd} + doc={props.doc} + tagDragHandlers={props.tagDragHandlers} /> ); }; diff --git a/frontend/src/documents/context/DocumentsCommandContext.tsx b/frontend/src/documents/context/DocumentsCommandContext.tsx index 96d8028..1e4bb47 100644 --- a/frontend/src/documents/context/DocumentsCommandContext.tsx +++ b/frontend/src/documents/context/DocumentsCommandContext.tsx @@ -23,13 +23,6 @@ interface DocumentsCommandContextValue { }; }; tags: { - onDrag: { - start?: (event: DragEvent, doc: Document, tag: any) => void; - end?: (event: DragEvent) => void; - over?: (event: DragEvent, doc: Document) => void; - drop?: (event: DragEvent, doc: Document) => void; - leave?: (event: DragEvent, doc: Document) => void; - }; onAttach?: (documentId: Identifier, tagId: Identifier) => void; onDetach?: (documentId: Identifier, tagId: Identifier) => void; onClick?: (tagId: Identifier) => void; @@ -44,7 +37,7 @@ interface DocumentsCommandContextValue { export const DocumentsCommandContext = createContext({ folder: { onDrag: {} }, document: { onDrag: {} }, - tags: { onDrag: {} }, + tags: {}, correspondents: {}, }); diff --git a/frontend/src/documents/logic/useDocumentItemLogic.ts b/frontend/src/documents/logic/useDocumentItemLogic.ts index 08e7118..1d84df0 100644 --- a/frontend/src/documents/logic/useDocumentItemLogic.ts +++ b/frontend/src/documents/logic/useDocumentItemLogic.ts @@ -1,18 +1,20 @@ import React, { type DragEvent } from 'react'; import { createDocumentEntryKey } from '../../app/entryKey'; import { useDocumentOpen } from '../../lib/context/DocumentOpenContext'; -import type { Document, DocumentTag } from '../../types/documents'; +import type { Document } from '../../types/documents'; import { useDocumentsCommandContext } from '../context/DocumentsCommandContext'; import { useDocumentsViewStateContext } from '../context/DocumentsViewStateContext'; import type { DocumentViewLogic } from './useDocumentViewLogic'; -interface UseDocumentItemLogicProps { +import { TagDragHandlers } from '../interactions/useTagInteractions'; + +interface UseDocumentItemLogicArgs { doc: Document; - viewLogic: DocumentViewLogic; + tagDragHandlers?: TagDragHandlers; + viewLogic: DocumentViewLogic; // Retained from original props } -export const useDocumentItemLogic = (props: UseDocumentItemLogicProps) => { - const { doc, viewLogic } = props; +export const useDocumentItemLogic = ({ doc, tagDragHandlers, viewLogic }: UseDocumentItemLogicArgs) => { const { draggingDocumentIdsSet } = useDocumentsViewStateContext(); @@ -22,15 +24,6 @@ export const useDocumentItemLogic = (props: UseDocumentItemLogicProps) => { onDrag: { start: onDocumentDragStart, end: onDocumentDragEnd }, onRename: onDocumentRename }, - tags: { - onDrag: { - start: onDocumentTagDragStart, - end: onDocumentTagDragEnd, - over: onDocumentTagDragOver, - leave: onDocumentTagDragLeave, - drop: onDocumentTagDrop, - }, - }, onEntryPointer } = useDocumentsCommandContext(); @@ -77,11 +70,10 @@ export const useDocumentItemLogic = (props: UseDocumentItemLogicProps) => { }, onDragStart: (event: DragEvent) => onDocumentDragStart?.(event, doc), onDragEnd: (event: DragEvent) => onDocumentDragEnd?.(event), - onDragOver: (event: DragEvent) => onDocumentTagDragOver?.(event, doc), - onDragLeave: (event: DragEvent) => onDocumentTagDragLeave?.(event, doc), - onTagDragStart: (event: DragEvent, tag: DocumentTag) => onDocumentTagDragStart?.(event, doc, tag), - onTagDragEnd: (event: DragEvent) => onDocumentTagDragEnd?.(event), - onDrop: (event: DragEvent) => { onDocumentTagDrop?.(event, doc); }, + onDragOver: (event: DragEvent) => tagDragHandlers?.onTagDragOver(event, doc), + onDragLeave: (event: DragEvent) => tagDragHandlers?.onTagDragLeave(event, doc.id), + onDrop: (event: DragEvent) => { tagDragHandlers?.onTagDrop(event, doc); }, + tagDragHandlers, onRenameChange: setDocumentDraft, onRenameSubmit: () => submitDocumentEditing(doc), onRenameCancel: (event?: React.SyntheticEvent) => cancelDocumentEditing(event), diff --git a/frontend/src/documents/panel/DocumentsPanel.tsx b/frontend/src/documents/panel/DocumentsPanel.tsx index 08dafec..7da3850 100644 --- a/frontend/src/documents/panel/DocumentsPanel.tsx +++ b/frontend/src/documents/panel/DocumentsPanel.tsx @@ -48,8 +48,11 @@ interface DocumentsPanelProps extends DocumentsPanelInnerProps { selectionValue: WorkspaceSelectionValue; } +import type { TagDragHandlers } from '../interactions/useTagInteractions'; + export interface DocumentsViewProps { entries: DocumentsListEntry[]; + tagDragHandlers?: TagDragHandlers; } const DocumentsPanelInner: React.FC = (props) => { @@ -85,6 +88,7 @@ const DocumentsPanelInner: React.FC = (props) => { assetContextValue, viewStateContextValue, commandContextValue, + tagDragHandlers, scrollRef, hasDocumentEntries, } = useDocumentsContextValues(props); @@ -242,6 +246,7 @@ const DocumentsPanelInner: React.FC = (props) => { const viewProps = { entries, viewId: currentFolderId, + tagDragHandlers, }; const [iconSizes] = useState({ diff --git a/frontend/src/documents/panel/useDocumentsContextValues.ts b/frontend/src/documents/panel/useDocumentsContextValues.ts index d8499e4..4595d48 100644 --- a/frontend/src/documents/panel/useDocumentsContextValues.ts +++ b/frontend/src/documents/panel/useDocumentsContextValues.ts @@ -184,13 +184,6 @@ export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => { }, }, tags: { - onDrag: { - start: (e: any, d: any, t: any) => latestHandlersRef.current.tagDragHandlers.onTagDragStart(e, d, t), - end: (e: any) => latestHandlersRef.current.tagDragHandlers.onTagDragEnd(e), - over: (e: any, d: any) => latestHandlersRef.current.tagDragHandlers.onTagDragOver(e, d), - leave: (e: any, d: any) => latestHandlersRef.current.tagDragHandlers.onTagDragLeave(e, d.id), - drop: (e: any, d: any) => latestHandlersRef.current.tagDragHandlers.onTagDrop(e, d), - }, onAttach: (d: any, t: any) => latestPropsRef.current.onDocumentTagAttach?.(d, t), onDetach: (d: any, t: any) => latestPropsRef.current.onDocumentTagDetach?.(d, t), onClick: (t: any) => latestHandlersRef.current.toggleTagFilter(t), @@ -199,12 +192,13 @@ export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => { onClick: (c: any) => latestHandlersRef.current.toggleCorrespondentFilter(c), }, onEntryPointer: (entry: any, e: any) => latestPropsRef.current.onEntryPointer?.(entry, e), - }), []); // Stable forever! + }), []); return { assetContextValue, viewStateContextValue, commandContextValue, + tagDragHandlers, scrollRef, hasDocumentEntries, isSearchLoading,