This commit is contained in:
2025-11-24 20:19:44 +01:00
parent 66848e8526
commit 4c8ff39305
10 changed files with 130 additions and 109 deletions
+4 -4
View File
@@ -14,7 +14,7 @@ interface WorkspaceSelectionOptions {
isDocumentRowKey?: (key: RowKey | SelectionEntry) => boolean;
isFolderRowKey?: (key: RowKey | SelectionEntry) => boolean;
getRowId?: (key: RowKey | SelectionEntry) => string | number | null;
onInspectDocument?: (id: string | number) => void;
onDocumentActivate?: (id: string | number) => void;
onInspectFolder?: (id: string | number) => void;
}
@@ -26,7 +26,7 @@ export const useWorkspaceSelection = ({
isDocumentRowKey = () => false,
isFolderRowKey = () => false,
getRowId = () => null,
onInspectDocument = identity,
onDocumentActivate = identity,
onInspectFolder = identity,
}: WorkspaceSelectionOptions = {}) => {
const selection = useDocumentSelection({
@@ -88,9 +88,9 @@ export const useWorkspaceSelection = ({
const inspectDocument = useCallback(
(documentId?: string | number | null) => {
if (!documentId) return;
onInspectDocument(documentId);
onDocumentActivate(documentId);
},
[onInspectDocument],
[onDocumentActivate],
);
const inspectFolder = useCallback(
+3 -3
View File
@@ -30,7 +30,7 @@ interface DesktopDocumentCardProps {
getDocumentAsset?: (...args: any[]) => unknown;
handleNavigatorSnapshot?: (...args: any[]) => void;
cardPointerHandlers?: React.HTMLAttributes<HTMLDivElement>;
onInspectDocument?: (id: string | number) => void;
onDocumentActivate?: (id: string | number) => void;
onTagDragEnter?: (event: React.DragEvent<HTMLDivElement>, docId: string | number) => void;
onTagDragOver?: (event: React.DragEvent<HTMLDivElement>, docId: string | number) => void;
onTagDragLeave?: (event: React.DragEvent<HTMLDivElement>, docId: string | number) => void;
@@ -57,7 +57,7 @@ const DesktopDocumentCard: React.FC<DesktopDocumentCardProps> = ({
getDocumentAsset,
handleNavigatorSnapshot,
cardPointerHandlers,
onInspectDocument,
onDocumentActivate,
onTagDragEnter,
onTagDragOver,
onTagDragLeave,
@@ -117,7 +117,7 @@ const DesktopDocumentCard: React.FC<DesktopDocumentCardProps> = ({
onKeyDown={(event) => {
if (event.key === 'Enter' || event.key === ' ') {
preventAll(event);
onInspectDocument?.(doc.id);
onDocumentActivate?.(doc.id);
}
}}
>
+78 -48
View File
@@ -28,6 +28,7 @@ import usePreviewMetadata from './hooks/usePreviewMetadata';
import '../styles/workspace/workspace-layout.css';
import '../styles/workspace/workspace-items.css';
import '../styles/workspace/workspace-cards.css';
import { useWorkspaceSelectionContext } from '../app/WorkspaceSelectionContext';
type Identifier = string | number;
@@ -118,17 +119,13 @@ type WorkspaceSnapshotState = {
};
interface DesktopWorkspaceProps {
documents?: DeskDocument[];
onInspectDocument?: (...args: unknown[]) => void;
onEntryPointer?: (...args: unknown[]) => void;
onDocumentStackSelect?: (docIds: Identifier[]) => void;
onPromoteSelection?: (...args: unknown[]) => void;
onAssignTagToDocument?: (...args: unknown[]) => void;
entries?: DeskDocument[];
onDocumentActivate?: (...args: unknown[]) => void;
onDocumentClick?: (...args: unknown[]) => void;
onDocumentTagDrop?: (...args: unknown[]) => void;
ensureAssetUrl?: EnsureAssetUrl;
getDocumentAsset?: GetAsset;
activeTagIds?: Array<Identifier | null>;
selectedDocumentIds?: Identifier[];
onClearSelection?: () => void;
activeTagFilters?: Array<Identifier | null>;
tenantId?: Identifier | null;
viewId?: string | null;
}
@@ -167,12 +164,12 @@ interface DesktopWorkspaceViewProps {
overlayOriginRect: DOMRect | null;
overlayOriginTransform: OverlayOriginTransform | null;
overlayDocument: DeskDocument | null;
onEntryPointer?: DesktopWorkspaceProps['onEntryPointer'];
onDocumentStackSelect?: DesktopWorkspaceProps['onDocumentStackSelect'];
onPromoteSelection?: DesktopWorkspaceProps['onPromoteSelection'];
selectedDocumentIds: Identifier[];
onClearSelection?: DesktopWorkspaceProps['onClearSelection'];
onDocumentClick?: DesktopWorkspaceProps['onDocumentClick'];
onDocumentStackSelect?: (docIds: Identifier[], event?: PointerEvent | MouseEvent | null) => void;
onPromoteSelection?: (docId: Identifier | null) => void;
documentLookup: Map<string, DeskDocument>;
selectedDocumentIds: Identifier[];
onClearSelection: () => void;
resolveBaseMetrics: (doc: DeskDocument | null, cardWidth: number, cardHeight: number) => {
baseWidth: number;
baseHeight: number;
@@ -184,7 +181,7 @@ interface DesktopWorkspaceViewProps {
openOverlayForDoc: (docId: Identifier | null, originInfo?: OverlayOriginHint | null) => void;
recalcVisibleDocIds: () => void;
dragSettings: DragSettings;
onInspectDocument?: DesktopWorkspaceProps['onInspectDocument'];
onDocumentActivate?: DesktopWorkspaceProps['onDocumentActivate'];
markLayoutDirty: () => void;
}
@@ -193,23 +190,60 @@ const DEBUG_FOCUS = false;
const defaultGetDocumentAsset: GetAsset = () => null;
const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
documents = [],
onInspectDocument = null,
onEntryPointer = null,
onDocumentStackSelect = null,
onPromoteSelection = null,
onAssignTagToDocument = null,
entries = [],
onDocumentActivate = null,
onDocumentClick = null,
onDocumentTagDrop = null,
ensureAssetUrl = null,
getDocumentAsset = defaultGetDocumentAsset,
activeTagIds = [],
selectedDocumentIds = [],
onClearSelection = null,
activeTagFilters = [],
tenantId = null,
viewId = 'default',
documentLinks,
ensureDownloadUrl,
}) => {
const items = useMemo<DeskDocument[]>(() => documents, [documents]);
const {
selectedDocumentIds,
clearSelection,
handleEntrySelection,
promoteSelectionOrder,
} = useWorkspaceSelectionContext();
const items = useMemo<DeskDocument[]>(
() => (Array.isArray(entries) ? entries.filter((doc): doc is DeskDocument => Boolean(doc)) : []),
[entries],
);
const getDocRowKey = useCallback((id: Identifier | null) => (id != null ? `document:${id}` : null), []);
const handleStackSelect = useCallback(
(docIds: Identifier[], event?: PointerEvent | MouseEvent | null) => {
if (!Array.isArray(docIds) || docIds.length === 0) {
return;
}
const syntheticEvent = event || ({
metaKey: true,
ctrlKey: true,
preventDefault: () => {},
} as unknown as PointerEvent);
docIds.forEach((id) => {
const key = getDocRowKey(id);
if (key) {
handleEntrySelection(key, syntheticEvent);
}
});
},
[getDocRowKey, handleEntrySelection],
);
const handlePromoteSelection = useCallback(
(docId: Identifier | null) => {
const key = getDocRowKey(docId);
if (key && promoteSelectionOrder) {
promoteSelectionOrder(key);
}
},
[getDocRowKey, promoteSelectionOrder],
);
const allowLayoutPersistence = Boolean(tenantId && viewId && viewId.startsWith('folder:'));
const documentLinkMap = documentLinks instanceof Map ? documentLinks : null;
@@ -380,17 +414,17 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
[applySnapshotDimensions],
);
const activeTagSet = useMemo<Set<string>>(() => {
if (!Array.isArray(activeTagIds) || activeTagIds.length === 0) {
if (!Array.isArray(activeTagFilters) || activeTagFilters.length === 0) {
return new Set();
}
const set = new Set<string>();
activeTagIds.forEach((id) => {
activeTagFilters.forEach((id) => {
if (id != null) {
set.add(String(id));
}
});
return set;
}, [activeTagIds]);
}, [activeTagFilters]);
useLayoutEffect(() => {
const container = containerRef.current;
@@ -480,7 +514,7 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
const tagInteractions = useDeskTagInteractions({
engine,
onAssignTagToDocument,
onAssignTagToDocument: onDocumentTagDrop,
requestCanvasFocus,
});
@@ -782,11 +816,11 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
overlayOriginRect,
overlayOriginTransform,
overlayDocument,
onEntryPointer,
onDocumentStackSelect,
onPromoteSelection,
onDocumentClick,
onDocumentStackSelect: handleStackSelect,
onPromoteSelection: handlePromoteSelection,
selectedDocumentIds,
onClearSelection,
onClearSelection: clearSelection,
documentLookup,
resolveBaseMetrics,
bringToFront,
@@ -795,7 +829,7 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
openOverlayForDoc,
recalcVisibleDocIds,
dragSettings,
onInspectDocument,
onDocumentActivate,
markLayoutDirty,
}),
[
@@ -827,10 +861,7 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
items,
layoutRef,
layoutSnapshot,
onClearSelection,
onDocumentStackSelect,
onEntryPointer,
onPromoteSelection,
onDocumentClick,
openOverlayForDoc,
overlayDisplay,
overlayOriginRect,
@@ -843,7 +874,7 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
resolveBaseMetrics,
setDraggingId,
selectedDocumentIds,
onInspectDocument,
onDocumentActivate,
markLayoutDirty,
tagDropTargetId,
visibleDocIds,
@@ -885,7 +916,7 @@ function DesktopWorkspaceView({
overlayOriginRect,
overlayOriginTransform,
overlayDocument,
onEntryPointer,
onDocumentClick,
onDocumentStackSelect,
onPromoteSelection,
selectedDocumentIds,
@@ -898,7 +929,7 @@ function DesktopWorkspaceView({
openOverlayForDoc,
recalcVisibleDocIds,
dragSettings,
onInspectDocument,
onDocumentActivate,
markLayoutDirty,
dragTransformsRef,
}: DesktopWorkspaceViewProps) {
@@ -918,8 +949,7 @@ function DesktopWorkspaceView({
recalcVisibleDocIds,
settings: dragSettings,
containerRef,
onInspectDocument,
onDocumentStackSelect,
onDocumentActivate,
selectedDocumentIds,
markLayoutDirty,
}) as {
@@ -939,10 +969,10 @@ function DesktopWorkspaceView({
handlePointerMove,
handlePointerUp,
handlePointerCancel,
onEntryPointer,
onDocumentClick,
onDocumentStackSelect,
onPromoteSelection,
onInspectDocument,
onDocumentActivate,
selectedDocumentIds,
openOverlayForDoc,
}) as {
@@ -967,7 +997,7 @@ function DesktopWorkspaceView({
<>
<div className="desk-shell" onPointerDown={(event) => {
if (event.target === event.currentTarget) {
onClearSelection?.();
onClearSelection();
}
focusShell();
}}
@@ -982,7 +1012,7 @@ function DesktopWorkspaceView({
onDrop={handleCanvasDrop}
onPointerDown={(event) => {
if (event.target === event.currentTarget) {
onClearSelection?.();
onClearSelection();
}
focusShell();
}}
@@ -1073,7 +1103,7 @@ function DesktopWorkspaceView({
getDocumentAsset={getDocumentAsset}
handleNavigatorSnapshot={handleNavigatorSnapshot}
cardPointerHandlers={cardPointerHandlers}
onInspectDocument={onInspectDocument}
onDocumentActivate={onDocumentActivate}
onTagDragEnter={handleTagDragEnterDoc}
onTagDragOver={handleTagDragOverDoc}
onTagDragLeave={handleTagDragLeaveDoc}
+16 -16
View File
@@ -32,10 +32,10 @@ export const useDeskPointer = ({
handlePointerMove,
handlePointerUp,
handlePointerCancel,
onEntryPointer,
onDocumentClick,
onDocumentStackSelect,
onPromoteSelection,
onInspectDocument,
onDocumentActivate,
selectedDocumentIds,
openOverlayForDoc = null,
}) => {
@@ -242,16 +242,16 @@ export const useDeskPointer = ({
stackHits,
});
if (intent.selectedAtDown) {
safeInvoke(onPromoteSelection, doc.id, event);
}
if (intent.selectedAtDown) {
safeInvoke(onPromoteSelection, doc.id, event);
}
applyClickPlanImmediately({
intent,
event,
onEntryPointer,
onDocumentStackSelect,
});
applyClickPlanImmediately({
intent,
event,
onEntryPointer: onDocumentClick,
onDocumentStackSelect,
});
pointerIntentRef.current = intent;
@@ -272,7 +272,7 @@ export const useDeskPointer = ({
[
handlePointerDown,
onPromoteSelection,
onEntryPointer,
onDocumentClick,
onDocumentStackSelect,
resolveStackDocIds,
resetLongPressState,
@@ -308,7 +308,7 @@ export const useDeskPointer = ({
finalizeClickSelection({
intent: pointerState,
event,
onEntryPointer,
onEntryPointer: onDocumentClick,
onDocumentStackSelect,
});
@@ -325,7 +325,7 @@ export const useDeskPointer = ({
const stillSelected = Array.isArray(selectedDocumentIds)
&& selectedDocumentIds.includes(doc.id);
if (isPrimaryRelease && stillSelected) {
safeInvoke(onInspectDocument, doc.id);
safeInvoke(onDocumentActivate, doc.id);
}
}
}
@@ -335,9 +335,9 @@ export const useDeskPointer = ({
},
[
handlePointerUp,
onInspectDocument,
onDocumentActivate,
onDocumentStackSelect,
onEntryPointer,
onDocumentClick,
resetLongPressState,
selectedDocumentIds,
],
+11 -11
View File
@@ -108,7 +108,7 @@ interface UseDocumentDragOptions {
recalcVisibleDocIds: () => void;
settings?: DragSettings;
containerRef?: RefObject<HTMLElement>;
onInspectDocument?: (docId: Identifier | null, event?: PointerEvent | ReactPointerEvent) => void;
onDocumentActivate?: (docId: Identifier | null, event?: PointerEvent | ReactPointerEvent) => void;
onDocumentStackSelect?: (
docIds: Identifier[],
event: PointerEvent | ReactPointerEvent,
@@ -208,15 +208,15 @@ const useDocumentDrag = (options: UseDocumentDragOptions) => {
bringToFront,
setDraggingId,
canvasSize,
openOverlayForDoc,
recalcVisibleDocIds,
settings,
containerRef: providedContainerRef,
onInspectDocument,
onDocumentStackSelect,
selectedDocumentIds = [],
markLayoutDirty,
} = options;
openOverlayForDoc,
recalcVisibleDocIds,
settings,
containerRef: providedContainerRef,
onDocumentActivate,
onDocumentStackSelect,
selectedDocumentIds = [],
markLayoutDirty,
} = options;
const fallbackContainerRef = useRef<HTMLElement | null>(null);
const containerRef = providedContainerRef ?? fallbackContainerRef;
@@ -246,7 +246,7 @@ const useDocumentDrag = (options: UseDocumentDragOptions) => {
openOverlayForDoc?.(data.docId, data.originInfo);
return;
}
onInspectDocument?.(data.docId, event);
onDocumentActivate?.(data.docId, event);
},
});
const dragStateRef = useRef<DragStateInternal | null>(null);
+1 -6
View File
@@ -60,7 +60,6 @@ export type DocumentEventHandler = (document: DocumentLike, event: MouseEvent<HT
export interface DocumentsListProps {
entries: DocumentsListEntry[];
focusedRowKey?: string | null;
draggingDocumentIdsSet?: Set<Identifier> | null;
draggedFolderId?: Identifier | 'root' | null;
ensureAssetUrl?: (...args: any[]) => unknown;
@@ -91,7 +90,6 @@ export interface DocumentsListProps {
const DocumentsList: React.FC<DocumentsListProps> = ({
entries,
focusedRowKey,
draggingDocumentIdsSet,
draggedFolderId,
ensureAssetUrl,
@@ -185,7 +183,6 @@ const DocumentsList: React.FC<DocumentsListProps> = ({
const canDragFolder = folder.id !== 'root';
const isDraggingFolder = draggedFolderId === folder.id;
const isSelectedFolder = selectedFolderIdsSet?.has(folder.id);
const rowKey = `folder:${folder.id}`;
const canRenameFolder = Boolean(onFolderRename) && folder.id !== 'root';
const isFolderEditing = editingFolderId === folder.id;
const folderDraftValue = isFolderEditing ? folderDraft : folder.name;
@@ -198,9 +195,7 @@ const DocumentsList: React.FC<DocumentsListProps> = ({
return (
<tr
key={entry.key}
className={`folder${isDraggingFolder ? ' is-dragging' : ''}${
focusedRowKey === rowKey ? ' focused' : ''
}${isSelectedFolder ? ' selected' : ''}`}
className={`folder${isDraggingFolder ? ' is-dragging' : ''}${isSelectedFolder ? ' selected' : ''}`}
id={`folder-row-${folder.id}`}
onClick={(event) => onFolderClick?.(folder, event)}
onDoubleClick={(event) => {
@@ -55,7 +55,7 @@ export interface UseDocumentsPanelPropsArgs {
clearDocumentSelection?: () => void;
handleDeleteSelection?: () => void;
handleEntryPointerCore?: (...args: unknown[]) => void;
inspectDocument?: (docId: Identifier | null, metadata?: unknown) => void;
onDocumentActivate?: (docId: Identifier | null, metadata?: unknown) => void;
tags?: unknown[];
correspondents?: unknown[];
documentLookup?: unknown;
@@ -107,7 +107,7 @@ const useDocumentsPanelProps = (props: UseDocumentsPanelPropsArgs) => {
handleDocumentsViewModeChange,
handleDeleteSelection,
handleEntryPointerCore,
inspectDocument,
onDocumentActivate,
tags,
correspondents,
documentLookup,
@@ -159,7 +159,7 @@ const useDocumentsPanelProps = (props: UseDocumentsPanelPropsArgs) => {
onViewModeChange: handleDocumentsViewModeChange,
onDeleteSelection: handleDeleteSelection,
onEntryPointer: handleEntryPointerCore,
onInspectDocument: inspectDocument,
onDocumentActivate,
tags,
correspondents,
documentLookup,
@@ -206,7 +206,7 @@ const useDocumentsPanelProps = (props: UseDocumentsPanelPropsArgs) => {
handleFolderDragEnd,
handleFolderDragStart,
handleFolderRename,
inspectDocument,
onDocumentActivate,
moveDocumentsToFolder,
openDocumentPreview,
refreshCurrentFolder,
@@ -61,7 +61,7 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
onDocumentDragEnd,
onDocumentRename,
onEntryPointer = null,
onInspectDocument = null,
onDocumentActivate = null,
tagLookupById,
activeCorrespondentIds = [],
ensureAssetUrl = null,
@@ -368,9 +368,9 @@ type ZoomSource = { url: string; alt?: string | null; mimeType?: string | null }
handleDocumentPreviewZoom(doc);
return;
}
onInspectDocument?.(doc.id);
onDocumentActivate?.(doc.id);
},
[handleDocumentPreviewZoom, onInspectDocument],
[handleDocumentPreviewZoom, onDocumentActivate],
);
const navigableRows = useMemo(
+4 -4
View File
@@ -29,7 +29,7 @@ interface UseEntryPointerOptions {
resolveDocumentRowKey?: (id: string | number) => string | null;
resolveFolderRowKey?: (id: string | number) => string | null;
onSelectEntry?: (entry: WorkspaceEntry, event?: PointerEventLike | null, metadata?: EntryPointerMetadata) => void;
onInspectDocument?: (id: string | number, metadata?: EntryPointerMetadata) => void;
onDocumentActivate?: (id: string | number, metadata?: EntryPointerMetadata) => void;
}
export interface EntryPointerMetadata {
@@ -44,7 +44,7 @@ export const useEntryPointer = ({
resolveDocumentRowKey,
resolveFolderRowKey,
onSelectEntry,
onInspectDocument,
onDocumentActivate,
}: UseEntryPointerOptions) =>
useCallback(
(entry?: WorkspaceEntry | null, event?: PointerEventLike | null) => {
@@ -70,10 +70,10 @@ export const useEntryPointer = ({
onSelectEntry?.(entry, event, metadata);
if (type === 'document' && !modifierClick && primaryClick) {
onInspectDocument?.(id, metadata);
onDocumentActivate?.(id, metadata);
}
},
[resolveDocumentRowKey, resolveFolderRowKey, onSelectEntry, onInspectDocument],
[resolveDocumentRowKey, resolveFolderRowKey, onSelectEntry, onDocumentActivate],
);
export default useEntryPointer;
@@ -1420,17 +1420,15 @@ const useDocumentsWorkspace = ({
const deskWorkspaceProps = useMemo(
() => ({
documents: viewDocuments,
onInspectDocument: inspectDocumentForDesk,
onEntryPointer: handleEntryPointerCore,
entries: viewDocuments,
onDocumentActivate: inspectDocumentForDesk,
onDocumentClick: handleEntryPointerCore,
onDocumentStackSelect: handleDeskDocumentStackSelect,
onPromoteSelection: promoteSelectionOrder,
onAssignTagToDocument: handleDocumentTagDrop,
onDocumentTagDrop: handleDocumentTagDrop,
ensureAssetUrl,
getDocumentAsset,
activeTagIds: activeTagFilters,
selectedDocumentIds,
onClearSelection: clearDocumentSelection,
activeTagFilters,
tenantId: currentTenantId,
viewId: deskViewId,
documentLinks,
@@ -1446,8 +1444,6 @@ const useDocumentsWorkspace = ({
ensureAssetUrl,
getDocumentAsset,
activeTagFilters,
selectedDocumentIds,
clearDocumentSelection,
currentTenantId,
deskViewId,
documentLinks,
@@ -1487,7 +1483,7 @@ const useDocumentsWorkspace = ({
clearDocumentSelection,
handleDeleteSelection,
handleEntryPointerCore,
inspectDocument,
onDocumentActivate: inspectDocument,
tags,
correspondents,
documentLookup,