diff --git a/frontend/src/desktop/components/DesktopDocumentCard.tsx b/frontend/src/desktop/components/DesktopDocumentCard.tsx index 4e2d6d8..74978d8 100644 --- a/frontend/src/desktop/components/DesktopDocumentCard.tsx +++ b/frontend/src/desktop/components/DesktopDocumentCard.tsx @@ -117,7 +117,6 @@ const DesktopDocumentCard: React.FC = ({ doc={doc} tags={tags} tagHandlers={tagHandlers} - onTagClick={tagHandlers?.onTagClick} /> )} diff --git a/frontend/src/documents/components/DocumentTags.tsx b/frontend/src/documents/components/DocumentTags.tsx index 32a62d9..412e132 100644 --- a/frontend/src/documents/components/DocumentTags.tsx +++ b/frontend/src/documents/components/DocumentTags.tsx @@ -7,7 +7,6 @@ import type { TagInteractionHandlers } from '../interactions/useTagInteractions' interface DocumentTagsProps { tags: DocumentTag[]; tagLookupById?: Map | null; - onTagClick?: (tagId: Identifier) => void; doc: Document; tagHandlers?: TagInteractionHandlers; } @@ -15,7 +14,6 @@ interface DocumentTagsProps { const DocumentTags: React.FC = ({ tags, tagLookupById, - onTagClick, doc, tagHandlers, }) => { @@ -37,7 +35,7 @@ const DocumentTags: React.FC = ({ const colorSource = tag?.color || tagLookupById?.get(tag.id)?.color; const style = getTagColorStyle(colorSource); const tagId = tag?.id ?? null; - const clickable = tagId != null && typeof onTagClick === 'function'; + const clickable = tagId != null && typeof tagHandlers?.onTagClick === 'function'; const draggable = !!tagId; const key = tagId ?? `${doc.id}-tag-${index}`; @@ -51,7 +49,7 @@ const DocumentTags: React.FC = ({ onClick={clickable ? (event) => { event.stopPropagation(); if (tagId == null) return; - onTagClick?.(tagId); + tagHandlers?.onTagClick?.(tagId); } : undefined} draggable={!!tagId} onDragStart={(event) => tagId && tagHandlers?.onTagDragStart(event, doc, tag)} @@ -61,7 +59,7 @@ const DocumentTags: React.FC = ({ event.preventDefault(); event.stopPropagation(); if (tagId == null) return; - onTagClick?.(tagId); + tagHandlers?.onTagClick?.(tagId); } } : undefined} > diff --git a/frontend/src/documents/components/DocumentsGridCard.tsx b/frontend/src/documents/components/DocumentsGridCard.tsx index 8167dca..e93ee0b 100644 --- a/frontend/src/documents/components/DocumentsGridCard.tsx +++ b/frontend/src/documents/components/DocumentsGridCard.tsx @@ -27,7 +27,6 @@ const DocumentsGridCard: React.FC = (props) => { const { scrollRef, activeCorrespondentIdSet, tagLookupById } = useDocumentsViewStateContext(); const { correspondents: { onClick: onCorrespondentClick }, - tags: { onClick: onTagClick } } = useDocumentsCommandContext(); if (entry.type === 'folder') { @@ -125,7 +124,6 @@ const DocumentsGridCard: React.FC = (props) => { diff --git a/frontend/src/documents/components/DocumentsListRow.tsx b/frontend/src/documents/components/DocumentsListRow.tsx index 7b0c85f..ba53a35 100644 --- a/frontend/src/documents/components/DocumentsListRow.tsx +++ b/frontend/src/documents/components/DocumentsListRow.tsx @@ -29,7 +29,6 @@ const DocumentsListRow: React.FC = (props) => { const { scrollRef, activeCorrespondentIdSet, tagLookupById } = useDocumentsViewStateContext(); const { correspondents: { onClick: onCorrespondentClick }, - tags: { onClick: onTagClick } } = useDocumentsCommandContext(); if (entry.type === 'folder') { @@ -140,7 +139,6 @@ const DocumentsListRow: React.FC = (props) => { diff --git a/frontend/src/documents/context/DocumentsCommandContext.tsx b/frontend/src/documents/context/DocumentsCommandContext.tsx index 1e4bb47..62c67f8 100644 --- a/frontend/src/documents/context/DocumentsCommandContext.tsx +++ b/frontend/src/documents/context/DocumentsCommandContext.tsx @@ -22,11 +22,6 @@ interface DocumentsCommandContextValue { end?: (event: DragEvent) => void; }; }; - tags: { - onAttach?: (documentId: Identifier, tagId: Identifier) => void; - onDetach?: (documentId: Identifier, tagId: Identifier) => void; - onClick?: (tagId: Identifier) => void; - }; correspondents: { onClick?: (correspondentId: Identifier) => void; }; @@ -37,7 +32,6 @@ interface DocumentsCommandContextValue { export const DocumentsCommandContext = createContext({ folder: { onDrag: {} }, document: { onDrag: {} }, - tags: {}, correspondents: {}, }); diff --git a/frontend/src/documents/interactions/useWorkspaceDragDrop.ts b/frontend/src/documents/interactions/useWorkspaceDragDrop.ts index 02c3881..47152dc 100644 --- a/frontend/src/documents/interactions/useWorkspaceDragDrop.ts +++ b/frontend/src/documents/interactions/useWorkspaceDragDrop.ts @@ -1,6 +1,9 @@ import { useEffect } from 'react'; import type { MutableRefObject } from 'react'; -import { isTagTransferEvent } from '../features/tagging/tagTransfer'; +import { + isTagTransferEvent, + getActiveDragState, +} from '../features/tagging/tagTransfer'; interface UseWorkspaceDragDropArgs { shellRef: MutableRefObject; @@ -16,21 +19,58 @@ const useWorkspaceDragDrop = ({ return; } - // Allow drop on workspace + // Allow drop on workspace (global app shell) const handleTagDragOver = (event: DragEvent) => { if (!isTagTransferEvent(event)) { return; } - event.preventDefault(); - if (event.dataTransfer) event.dataTransfer.dropEffect = 'move'; + const { sourceDocId } = getActiveDragState(); + + // Only allow "Move" (removal) if the tag came from a document + if (sourceDocId) { + event.preventDefault(); // Necessary to allow dropping + if (event.dataTransfer) { + event.dataTransfer.dropEffect = 'move'; + } + } + }; + + const handleTagDragEnter = (event: DragEvent) => { + if (!isTagTransferEvent(event)) { + return; + } + const { sourceDocId } = getActiveDragState(); + if (sourceDocId) { + event.preventDefault(); + if (event.dataTransfer) { + event.dataTransfer.dropEffect = 'move'; + } + } + }; + + const handleTagDrop = (event: DragEvent) => { + if (!isTagTransferEvent(event)) { + return; + } + + const { sourceDocId } = getActiveDragState(); + + if (sourceDocId) { + // Consume the event so the browser reports 'move' back to the source + event.preventDefault(); + } }; // Use bubbling (false) so children can stopPropagation + host.addEventListener('dragenter', handleTagDragEnter, false); host.addEventListener('dragover', handleTagDragOver, false); + host.addEventListener('drop', handleTagDrop, false); return () => { + host.removeEventListener('dragenter', handleTagDragEnter, false); host.removeEventListener('dragover', handleTagDragOver, false); + host.removeEventListener('drop', handleTagDrop, false); }; }, [shellRef]); diff --git a/frontend/src/documents/panel/useDocumentsContextValues.ts b/frontend/src/documents/panel/useDocumentsContextValues.ts index 62e3f44..815fb93 100644 --- a/frontend/src/documents/panel/useDocumentsContextValues.ts +++ b/frontend/src/documents/panel/useDocumentsContextValues.ts @@ -183,11 +183,6 @@ export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => { end: (e: any) => latestHandlersRef.current.handleDocumentDragEndLocal(e), }, }, - tags: { - 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), - }, correspondents: { onClick: (c: any) => latestHandlersRef.current.toggleCorrespondentFilter(c), },