feat: Refactor tag interaction handling to use unified handlers
This commit is contained in:
@@ -117,7 +117,6 @@ const DesktopDocumentCard: React.FC<DesktopDocumentCardProps> = ({
|
||||
doc={doc}
|
||||
tags={tags}
|
||||
tagHandlers={tagHandlers}
|
||||
onTagClick={tagHandlers?.onTagClick}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -7,7 +7,6 @@ import type { TagInteractionHandlers } from '../interactions/useTagInteractions'
|
||||
interface DocumentTagsProps {
|
||||
tags: DocumentTag[];
|
||||
tagLookupById?: Map<Identifier, DocumentTag> | null;
|
||||
onTagClick?: (tagId: Identifier) => void;
|
||||
doc: Document;
|
||||
tagHandlers?: TagInteractionHandlers;
|
||||
}
|
||||
@@ -15,7 +14,6 @@ interface DocumentTagsProps {
|
||||
const DocumentTags: React.FC<DocumentTagsProps> = ({
|
||||
tags,
|
||||
tagLookupById,
|
||||
onTagClick,
|
||||
doc,
|
||||
tagHandlers,
|
||||
}) => {
|
||||
@@ -37,7 +35,7 @@ const DocumentTags: React.FC<DocumentTagsProps> = ({
|
||||
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<DocumentTagsProps> = ({
|
||||
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<DocumentTagsProps> = ({
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (tagId == null) return;
|
||||
onTagClick?.(tagId);
|
||||
tagHandlers?.onTagClick?.(tagId);
|
||||
}
|
||||
} : undefined}
|
||||
>
|
||||
|
||||
@@ -27,7 +27,6 @@ const DocumentsGridCard: React.FC<DocumentsGridCardProps> = (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<DocumentsGridCardProps> = (props) => {
|
||||
<DocumentTags
|
||||
tags={doc.tags || []}
|
||||
tagLookupById={tagLookupById}
|
||||
onTagClick={onTagClick}
|
||||
doc={doc}
|
||||
tagHandlers={logic.handlers.tagHandlers}
|
||||
/>
|
||||
|
||||
@@ -29,7 +29,6 @@ const DocumentsListRow: React.FC<DocumentsListRowProps> = (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<DocumentsListRowProps> = (props) => {
|
||||
<DocumentTags
|
||||
tags={doc.tags || []}
|
||||
tagLookupById={tagLookupById}
|
||||
onTagClick={onTagClick}
|
||||
doc={doc}
|
||||
tagHandlers={logic.handlers.tagHandlers}
|
||||
/>
|
||||
|
||||
@@ -22,11 +22,6 @@ interface DocumentsCommandContextValue {
|
||||
end?: (event: DragEvent<HTMLElement>) => 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<DocumentsCommandContextValue>({
|
||||
folder: { onDrag: {} },
|
||||
document: { onDrag: {} },
|
||||
tags: {},
|
||||
correspondents: {},
|
||||
});
|
||||
|
||||
|
||||
@@ -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<HTMLElement | null>;
|
||||
@@ -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]);
|
||||
|
||||
|
||||
@@ -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),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user