feat: refactor frontend tag interaction handlers
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import DesktopPreviewCard from './DesktopPreviewCard';
|
||||
import { resolveCorrespondents } from '../../documents/correspondents';
|
||||
import { getTagColorStyle } from '../../utils/colors';
|
||||
import type { DocumentId } from '../../types/identifiers';
|
||||
import type { Document } from '../../types/documents';
|
||||
import { LayoutCard } from '../logic/LayoutSystem';
|
||||
import { useCardPointer } from '../interactions/useCardPointer';
|
||||
import DocumentTags from '../../documents/components/DocumentTags';
|
||||
import { TagInteractionHandlers } from '../../documents/interactions/useTagInteractions';
|
||||
|
||||
const preventAll = (event?: React.SyntheticEvent | Event | null) => {
|
||||
if (!event) return;
|
||||
@@ -27,12 +27,7 @@ interface DesktopDocumentCardProps {
|
||||
onDeselect: (ids: string[]) => void;
|
||||
selection: string[];
|
||||
requestCanvasFocus?: () => void;
|
||||
onTagDragEnter?: (event: React.DragEvent<HTMLDivElement>, docId: DocumentId) => void;
|
||||
onTagDragOver?: (event: React.DragEvent<HTMLDivElement>, doc: Document) => void;
|
||||
onTagDragLeave?: (event: React.DragEvent<HTMLDivElement>, docId: DocumentId) => void;
|
||||
onTagDrop?: (event: React.DragEvent<HTMLDivElement>, doc: Document) => void;
|
||||
onTagDragStart?: (event: React.DragEvent<HTMLElement>, doc: Document, tag: any) => void;
|
||||
onTagDragEnd?: (event: React.DragEvent<HTMLElement>) => void;
|
||||
tagHandlers?: TagInteractionHandlers;
|
||||
layoutCard: LayoutCard;
|
||||
}
|
||||
|
||||
@@ -50,12 +45,7 @@ const DesktopDocumentCard: React.FC<DesktopDocumentCardProps> = ({
|
||||
onDeselect,
|
||||
selection,
|
||||
requestCanvasFocus,
|
||||
onTagDragEnter,
|
||||
onTagDragOver,
|
||||
onTagDragLeave,
|
||||
onTagDrop,
|
||||
onTagDragStart,
|
||||
onTagDragEnd,
|
||||
tagHandlers,
|
||||
layoutCard,
|
||||
}) => {
|
||||
const cardPointerHandlers = useCardPointer(
|
||||
@@ -89,10 +79,10 @@ const DesktopDocumentCard: React.FC<DesktopDocumentCardProps> = ({
|
||||
aria-hidden={ariaHidden}
|
||||
ref={(node) => layoutCard?.setRef(node)}
|
||||
{...cardPointerHandlers}
|
||||
onDragEnter={(event) => onTagDragEnter?.(event, doc.id!)}
|
||||
onDragOver={(event) => onTagDragOver?.(event, doc)}
|
||||
onDragLeave={(event) => onTagDragLeave?.(event, doc.id!)}
|
||||
onDrop={(event) => onTagDrop?.(event, doc)}
|
||||
onDragEnter={(event) => tagHandlers?.onTagDragEnter(event, doc.id!)}
|
||||
onDragOver={(event) => tagHandlers?.onTagDragOver(event, doc)}
|
||||
onDragLeave={(event) => tagHandlers?.onTagDragLeave(event, doc.id!)}
|
||||
onDrop={(event) => tagHandlers?.onTagDrop(event, doc)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
preventAll(event);
|
||||
@@ -123,24 +113,12 @@ const DesktopDocumentCard: React.FC<DesktopDocumentCardProps> = ({
|
||||
)}
|
||||
{tags.length > 0 && (
|
||||
<div className="desk-item__tags" aria-hidden="true">
|
||||
{tags.map((tag) => {
|
||||
const colorStyle = getTagColorStyle(tag.color);
|
||||
const tagClasses = ['badge', 'tag-chip', 'tag-chip--draggable'];
|
||||
return (
|
||||
<span
|
||||
key={tag.id}
|
||||
className={tagClasses.join(' ')}
|
||||
style={colorStyle || undefined}
|
||||
title={tag.label}
|
||||
draggable
|
||||
data-desk-tag-chip="true"
|
||||
onDragStart={(event) => onTagDragStart?.(event, doc, tag)}
|
||||
onDragEnd={(event) => onTagDragEnd?.(event)}
|
||||
>
|
||||
<span className="tag-chip__label">{tag.label}</span>
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
<DocumentTags
|
||||
doc={doc}
|
||||
tags={tags}
|
||||
tagHandlers={tagHandlers}
|
||||
onTagClick={tagHandlers?.onTagClick}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,6 @@ import { LayoutStore, LayoutCard } from '../logic/LayoutSystem';
|
||||
import DesktopDocumentCard from './DesktopDocumentCard';
|
||||
import usePreviewMetadata from '../hooks/usePreviewMetadata';
|
||||
import {
|
||||
TagDragHandlers,
|
||||
useTagInteractions,
|
||||
} from '../../documents/interactions/useTagInteractions';
|
||||
import './workspace-layout.css';
|
||||
@@ -183,7 +182,7 @@ const DesktopWorkspaceContent: React.FC<DesktopWorkspaceProps> = ({
|
||||
}, []);
|
||||
|
||||
// Tag Interactions
|
||||
const tagDragHandlers: TagDragHandlers = useTagInteractions({
|
||||
const tagHandlers = useTagInteractions({
|
||||
onAssignTagToDocument: (docId: string, tagId: string) => {
|
||||
tags.onAttach?.(docId, tagId);
|
||||
},
|
||||
@@ -191,6 +190,7 @@ const DesktopWorkspaceContent: React.FC<DesktopWorkspaceProps> = ({
|
||||
tags.onDetach?.(docId, tagId);
|
||||
},
|
||||
requestCanvasFocus: focusShell,
|
||||
onTagClick: tags.onClick,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@@ -392,7 +392,7 @@ const DesktopWorkspaceContent: React.FC<DesktopWorkspaceProps> = ({
|
||||
openDocument(doc, isPreview ? 'preview' : 'sidepanel');
|
||||
}}
|
||||
layoutCard={layoutCard}
|
||||
{...tagDragHandlers}
|
||||
tagHandlers={tagHandlers}
|
||||
onSelect={(ids, extend = false) => {
|
||||
if (!extend) {
|
||||
handleSelectionChange(ids);
|
||||
|
||||
@@ -2,11 +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';
|
||||
import type { TagInteractionHandlers } from '../interactions/useTagInteractions';
|
||||
|
||||
interface DocumentEntryProps {
|
||||
doc: any;
|
||||
tagDragHandlers?: TagDragHandlers;
|
||||
tagHandlers?: TagInteractionHandlers;
|
||||
viewLogic: DocumentViewLogic;
|
||||
component: React.ElementType;
|
||||
className?: string;
|
||||
@@ -15,8 +15,8 @@ interface DocumentEntryProps {
|
||||
}
|
||||
|
||||
const DocumentEntry: React.FC<DocumentEntryProps> = (props) => {
|
||||
const { doc, tagDragHandlers, component, className, role, children, viewLogic } = props;
|
||||
const logic = useDocumentItemLogic({ doc, tagDragHandlers, viewLogic });
|
||||
const { doc, tagHandlers, component, className, role, children, viewLogic } = props;
|
||||
const logic = useDocumentItemLogic({ doc, tagHandlers, viewLogic });
|
||||
|
||||
return (
|
||||
<EntryShell
|
||||
|
||||
@@ -2,14 +2,14 @@ import React, { useMemo } from 'react';
|
||||
import { getTagColorStyle } from '../../utils/colors';
|
||||
import type { Document, DocumentTag } from '../../types/documents';
|
||||
import type { Identifier } from '../../types/identifiers';
|
||||
import type { TagDragHandlers } from '../interactions/useTagInteractions';
|
||||
import type { TagInteractionHandlers } from '../interactions/useTagInteractions';
|
||||
|
||||
interface DocumentTagsProps {
|
||||
tags: DocumentTag[];
|
||||
tagLookupById?: Map<Identifier, DocumentTag> | null;
|
||||
onTagClick?: (tagId: Identifier) => void;
|
||||
doc: Document;
|
||||
tagDragHandlers?: TagDragHandlers;
|
||||
tagHandlers?: TagInteractionHandlers;
|
||||
}
|
||||
|
||||
const DocumentTags: React.FC<DocumentTagsProps> = ({
|
||||
@@ -17,7 +17,7 @@ const DocumentTags: React.FC<DocumentTagsProps> = ({
|
||||
tagLookupById,
|
||||
onTagClick,
|
||||
doc,
|
||||
tagDragHandlers,
|
||||
tagHandlers,
|
||||
}) => {
|
||||
const sortedTags = useMemo(() => {
|
||||
return [...tags].sort((a, b) => {
|
||||
@@ -38,12 +38,13 @@ const DocumentTags: React.FC<DocumentTagsProps> = ({
|
||||
const style = getTagColorStyle(colorSource);
|
||||
const tagId = tag?.id ?? null;
|
||||
const clickable = tagId != null && typeof onTagClick === 'function';
|
||||
const draggable = !!tagId;
|
||||
const key = tagId ?? `${doc.id}-tag-${index}`;
|
||||
|
||||
return (
|
||||
<span
|
||||
key={key}
|
||||
className="badge tag-chip"
|
||||
className={`badge tag-chip${draggable ? ' tag-chip--draggable' : ''}`}
|
||||
style={style || undefined}
|
||||
title={tag.label}
|
||||
role={clickable ? 'button' : undefined}
|
||||
@@ -53,8 +54,8 @@ const DocumentTags: React.FC<DocumentTagsProps> = ({
|
||||
onTagClick?.(tagId);
|
||||
} : undefined}
|
||||
draggable={!!tagId}
|
||||
onDragStart={(event) => tagId && tagDragHandlers?.onTagDragStart(event, doc, tag)}
|
||||
onDragEnd={tagDragHandlers?.onTagDragEnd}
|
||||
onDragStart={(event) => tagId && tagHandlers?.onTagDragStart(event, doc, tag)}
|
||||
onDragEnd={tagHandlers?.onTagDragEnd}
|
||||
onKeyDown={clickable ? (event) => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -12,17 +12,17 @@ import EntryCorrespondents from './EntryCorrespondents';
|
||||
import EntryTags from './EntryTags';
|
||||
import FolderEntry from './FolderEntry';
|
||||
import DocumentEntry from './DocumentEntry';
|
||||
import { TagDragHandlers } from '../interactions/useTagInteractions';
|
||||
import { TagInteractionHandlers } from '../interactions/useTagInteractions';
|
||||
|
||||
interface DocumentsGridCardProps {
|
||||
entry: DocumentsListEntry;
|
||||
viewLogic: DocumentViewLogic;
|
||||
iconSize?: number;
|
||||
tagDragHandlers?: TagDragHandlers;
|
||||
tagHandlers?: TagInteractionHandlers;
|
||||
}
|
||||
|
||||
const DocumentsGridCard: React.FC<DocumentsGridCardProps> = (props) => {
|
||||
const { entry, iconSize, tagDragHandlers } = props;
|
||||
const { entry, iconSize, tagHandlers } = props;
|
||||
const { ensureAssetUrl, getDocumentAsset } = useDocumentsAssetContext();
|
||||
const { scrollRef, activeCorrespondentIdSet, tagLookupById } = useDocumentsViewStateContext();
|
||||
const {
|
||||
@@ -80,7 +80,7 @@ const DocumentsGridCard: React.FC<DocumentsGridCardProps> = (props) => {
|
||||
return (
|
||||
<DocumentEntry
|
||||
doc={doc}
|
||||
tagDragHandlers={tagDragHandlers}
|
||||
tagHandlers={tagHandlers}
|
||||
viewLogic={props.viewLogic}
|
||||
component="div"
|
||||
className="document-card document"
|
||||
@@ -127,7 +127,7 @@ const DocumentsGridCard: React.FC<DocumentsGridCardProps> = (props) => {
|
||||
tagLookupById={tagLookupById}
|
||||
onTagClick={onTagClick}
|
||||
doc={doc}
|
||||
tagDragHandlers={logic.handlers.tagDragHandlers}
|
||||
tagHandlers={logic.handlers.tagHandlers}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,17 +14,17 @@ import EntryTags from './EntryTags';
|
||||
import FolderEntry from './FolderEntry';
|
||||
import DocumentEntry from './DocumentEntry';
|
||||
|
||||
import { TagDragHandlers } from '../interactions/useTagInteractions';
|
||||
import { TagInteractionHandlers } from '../interactions/useTagInteractions';
|
||||
|
||||
interface DocumentsListRowProps {
|
||||
entry: DocumentsListEntry;
|
||||
viewLogic: DocumentViewLogic;
|
||||
iconSize?: number;
|
||||
tagDragHandlers?: TagDragHandlers;
|
||||
tagHandlers?: TagInteractionHandlers;
|
||||
}
|
||||
|
||||
const DocumentsListRow: React.FC<DocumentsListRowProps> = (props) => {
|
||||
const { entry, iconSize, tagDragHandlers } = props;
|
||||
const { entry, iconSize, tagHandlers } = props;
|
||||
const { ensureAssetUrl, getDocumentAsset } = useDocumentsAssetContext();
|
||||
const { scrollRef, activeCorrespondentIdSet, tagLookupById } = useDocumentsViewStateContext();
|
||||
const {
|
||||
@@ -91,7 +91,7 @@ const DocumentsListRow: React.FC<DocumentsListRowProps> = (props) => {
|
||||
return (
|
||||
<DocumentEntry
|
||||
doc={doc}
|
||||
tagDragHandlers={tagDragHandlers}
|
||||
tagHandlers={tagHandlers}
|
||||
viewLogic={props.viewLogic}
|
||||
component="tr"
|
||||
className="document"
|
||||
@@ -142,7 +142,7 @@ const DocumentsListRow: React.FC<DocumentsListRowProps> = (props) => {
|
||||
tagLookupById={tagLookupById}
|
||||
onTagClick={onTagClick}
|
||||
doc={doc}
|
||||
tagDragHandlers={logic.handlers.tagDragHandlers}
|
||||
tagHandlers={logic.handlers.tagHandlers}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import DocumentTags from './DocumentTags';
|
||||
import type { Document, DocumentTag } from '../../types/documents';
|
||||
import type { TagDragHandlers } from '../interactions/useTagInteractions';
|
||||
import type { TagInteractionHandlers } from '../interactions/useTagInteractions';
|
||||
import type { Identifier } from '../../types/identifiers';
|
||||
|
||||
interface EntryTagsProps {
|
||||
@@ -9,7 +9,7 @@ interface EntryTagsProps {
|
||||
tagLookupById?: Map<Identifier, DocumentTag> | null;
|
||||
onTagClick?: (tagId: Identifier) => void;
|
||||
doc: Document;
|
||||
tagDragHandlers?: TagDragHandlers;
|
||||
tagHandlers?: TagInteractionHandlers;
|
||||
}
|
||||
|
||||
const EntryTags: React.FC<EntryTagsProps> = (props) => {
|
||||
@@ -23,7 +23,7 @@ const EntryTags: React.FC<EntryTagsProps> = (props) => {
|
||||
tagLookupById={props.tagLookupById}
|
||||
onTagClick={props.onTagClick}
|
||||
doc={props.doc}
|
||||
tagDragHandlers={props.tagDragHandlers}
|
||||
tagHandlers={props.tagHandlers}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -48,6 +48,7 @@ interface UseTagInteractionsArgs {
|
||||
onAssignTagToDocument?: (docId: Identifier, tagId: Identifier) => void;
|
||||
onRemoveTagFromDocument?: (docId: Identifier, tagId: Identifier) => void;
|
||||
requestCanvasFocus?: () => void;
|
||||
onTagClick?: (tagId: Identifier) => void;
|
||||
}
|
||||
|
||||
interface DraggingTagState {
|
||||
@@ -55,20 +56,22 @@ interface DraggingTagState {
|
||||
previewClone?: HTMLElement;
|
||||
}
|
||||
|
||||
export interface TagDragHandlers {
|
||||
export interface TagInteractionHandlers {
|
||||
onTagDragEnter: (event: React.DragEvent<HTMLDivElement>, docId: Identifier) => void;
|
||||
onTagDragOver: (event: React.DragEvent<HTMLDivElement>, doc: Document) => void;
|
||||
onTagDragLeave: (event: React.DragEvent<HTMLDivElement>, docId: Identifier) => void;
|
||||
onTagDrop: (event: React.DragEvent<HTMLDivElement>, doc: Document) => void;
|
||||
onTagDragStart: (event: React.DragEvent<HTMLElement>, doc: Document, tag: DocumentTag) => void;
|
||||
onTagDragEnd: (event: React.DragEvent<HTMLElement>) => void;
|
||||
onTagClick?: (tagId: Identifier) => void;
|
||||
}
|
||||
|
||||
export const useTagInteractions = ({
|
||||
onAssignTagToDocument,
|
||||
onRemoveTagFromDocument,
|
||||
requestCanvasFocus,
|
||||
}: UseTagInteractionsArgs): TagDragHandlers => {
|
||||
onTagClick,
|
||||
}: UseTagInteractionsArgs): TagInteractionHandlers => {
|
||||
const draggingTagRef = useRef<DraggingTagState | null>(null);
|
||||
|
||||
const isTagTransfer = useCallback((event: React.DragEvent) => isTagTransferEvent(event), []);
|
||||
@@ -241,5 +244,6 @@ export const useTagInteractions = ({
|
||||
onTagDrop,
|
||||
onTagDragStart,
|
||||
onTagDragEnd,
|
||||
onTagClick,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -5,16 +5,15 @@ import type { Document } from '../../types/documents';
|
||||
import { useDocumentsCommandContext } from '../context/DocumentsCommandContext';
|
||||
import { useDocumentsViewStateContext } from '../context/DocumentsViewStateContext';
|
||||
import type { DocumentViewLogic } from './useDocumentViewLogic';
|
||||
|
||||
import { TagDragHandlers } from '../interactions/useTagInteractions';
|
||||
import { TagInteractionHandlers } from '../interactions/useTagInteractions';
|
||||
|
||||
interface UseDocumentItemLogicArgs {
|
||||
doc: Document;
|
||||
tagDragHandlers?: TagDragHandlers;
|
||||
tagHandlers?: TagInteractionHandlers;
|
||||
viewLogic: DocumentViewLogic; // Retained from original props
|
||||
}
|
||||
|
||||
export const useDocumentItemLogic = ({ doc, tagDragHandlers, viewLogic }: UseDocumentItemLogicArgs) => {
|
||||
export const useDocumentItemLogic = ({ doc, tagHandlers, viewLogic }: UseDocumentItemLogicArgs) => {
|
||||
const {
|
||||
draggingDocumentIdsSet
|
||||
} = useDocumentsViewStateContext();
|
||||
@@ -70,10 +69,10 @@ export const useDocumentItemLogic = ({ doc, tagDragHandlers, viewLogic }: UseDoc
|
||||
},
|
||||
onDragStart: (event: DragEvent<HTMLElement>) => onDocumentDragStart?.(event, doc),
|
||||
onDragEnd: (event: DragEvent<HTMLElement>) => onDocumentDragEnd?.(event),
|
||||
onDragOver: (event: DragEvent<HTMLElement>) => tagDragHandlers?.onTagDragOver(event, doc),
|
||||
onDragLeave: (event: DragEvent<HTMLElement>) => tagDragHandlers?.onTagDragLeave(event, doc.id),
|
||||
onDrop: (event: DragEvent<HTMLElement>) => { tagDragHandlers?.onTagDrop(event, doc); },
|
||||
tagDragHandlers,
|
||||
onDragOver: (event: DragEvent<HTMLElement>) => tagHandlers?.onTagDragOver(event, doc),
|
||||
onDragLeave: (event: DragEvent<HTMLElement>) => tagHandlers?.onTagDragLeave(event, doc.id),
|
||||
onDrop: (event: DragEvent<HTMLElement>) => { tagHandlers?.onTagDrop(event, doc); },
|
||||
tagHandlers,
|
||||
onRenameChange: setDocumentDraft,
|
||||
onRenameSubmit: () => submitDocumentEditing(doc),
|
||||
onRenameCancel: (event?: React.SyntheticEvent) => cancelDocumentEditing(event),
|
||||
|
||||
@@ -48,11 +48,11 @@ interface DocumentsPanelProps extends DocumentsPanelInnerProps {
|
||||
selectionValue: WorkspaceSelectionValue;
|
||||
}
|
||||
|
||||
import type { TagDragHandlers } from '../interactions/useTagInteractions';
|
||||
import type { TagInteractionHandlers } from '../interactions/useTagInteractions';
|
||||
|
||||
export interface DocumentsViewProps {
|
||||
entries: DocumentsListEntry[];
|
||||
tagDragHandlers?: TagDragHandlers;
|
||||
tagHandlers?: TagInteractionHandlers;
|
||||
}
|
||||
|
||||
const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = (props) => {
|
||||
@@ -88,7 +88,7 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = (props) => {
|
||||
assetContextValue,
|
||||
viewStateContextValue,
|
||||
commandContextValue,
|
||||
tagDragHandlers,
|
||||
tagHandlers,
|
||||
scrollRef,
|
||||
hasDocumentEntries,
|
||||
} = useDocumentsContextValues(props);
|
||||
@@ -246,7 +246,7 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = (props) => {
|
||||
const viewProps = {
|
||||
entries,
|
||||
viewId: currentFolderId,
|
||||
tagDragHandlers,
|
||||
tagHandlers,
|
||||
};
|
||||
|
||||
const [iconSizes] = useState({
|
||||
|
||||
@@ -38,9 +38,10 @@ export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => {
|
||||
} = useDocumentsFilter();
|
||||
|
||||
// Handlers
|
||||
const tagDragHandlers = useTagInteractions({
|
||||
const tagHandlers = useTagInteractions({
|
||||
onAssignTagToDocument: props.onDocumentTagAttach,
|
||||
onRemoveTagFromDocument: props.onDocumentTagDetach,
|
||||
onTagClick: toggleTagFilter,
|
||||
});
|
||||
|
||||
// Derived State
|
||||
@@ -147,7 +148,7 @@ export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => {
|
||||
handleFolderClick,
|
||||
handleDocumentDragStartLocal,
|
||||
handleDocumentDragEndLocal,
|
||||
tagDragHandlers,
|
||||
tagHandlers,
|
||||
toggleTagFilter,
|
||||
toggleCorrespondentFilter,
|
||||
});
|
||||
@@ -158,7 +159,7 @@ export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => {
|
||||
handleFolderClick,
|
||||
handleDocumentDragStartLocal,
|
||||
handleDocumentDragEndLocal,
|
||||
tagDragHandlers,
|
||||
tagHandlers,
|
||||
toggleTagFilter,
|
||||
toggleCorrespondentFilter,
|
||||
};
|
||||
@@ -198,7 +199,7 @@ export const useDocumentsContextValues = (props: DocumentsPanelInnerProps) => {
|
||||
assetContextValue,
|
||||
viewStateContextValue,
|
||||
commandContextValue,
|
||||
tagDragHandlers,
|
||||
tagHandlers,
|
||||
scrollRef,
|
||||
hasDocumentEntries,
|
||||
isSearchLoading,
|
||||
|
||||
Reference in New Issue
Block a user