refactor: Unify document selection and drag interactions by replacing stack-specific callbacks and simplifying drag state.
This commit is contained in:
@@ -142,8 +142,8 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
|
||||
}): ReactNode => {
|
||||
const {
|
||||
selectedEntries,
|
||||
focusedRowKey,
|
||||
setFocusedRowKey,
|
||||
focusedEntryKey,
|
||||
setFocusedEntryKey,
|
||||
handleEntrySelection,
|
||||
clearSelection,
|
||||
selectionAnchorRef,
|
||||
@@ -177,28 +177,28 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
|
||||
return;
|
||||
}
|
||||
|
||||
const rowKeys = docIds
|
||||
const entryKeys = docIds
|
||||
.map((id) => createDocumentEntryKey(id as Identifier))
|
||||
.filter((value): value is string => typeof value === 'string');
|
||||
|
||||
if (!rowKeys.length) {
|
||||
if (!entryKeys.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nextKeys = [...selectedEntries];
|
||||
rowKeys.forEach((key) => {
|
||||
entryKeys.forEach((key) => {
|
||||
if (!nextKeys.includes(key)) {
|
||||
nextKeys.push(key);
|
||||
}
|
||||
});
|
||||
|
||||
const anchor = (rowKeys[0]
|
||||
const anchor = (entryKeys[0]
|
||||
|| selectionAnchorRef.current
|
||||
|| nextKeys[nextKeys.length - 1]) as string | null;
|
||||
|
||||
applySelection(nextKeys, {
|
||||
anchor,
|
||||
interactedKeys: rowKeys,
|
||||
interactedKeys: entryKeys,
|
||||
});
|
||||
},
|
||||
[applySelection, selectedEntries, selectionAnchorRef],
|
||||
@@ -482,24 +482,24 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
|
||||
() => entries.map((entry) => ({ key: entry.key, type: entry.type, id: entry.id })),
|
||||
[entries],
|
||||
);
|
||||
const navigableRowKeys = useMemo(() => navigableRows.map((row) => row.key), [navigableRows]);
|
||||
const navigableEntryKeys = useMemo(() => navigableRows.map((row) => row.key), [navigableRows]);
|
||||
|
||||
const getEntryByKey = useCallback(
|
||||
(rowKey) => entries.find((entry) => entry.key === rowKey) || null,
|
||||
(entryKey) => entries.find((entry) => entry.key === entryKey) || null,
|
||||
[entries],
|
||||
);
|
||||
|
||||
const handlePanelFocus = useCallback(() => {
|
||||
let resolvedKey = null;
|
||||
|
||||
if (focusedRowKey && navigableRowKeys.includes(focusedRowKey)) {
|
||||
resolvedKey = focusedRowKey;
|
||||
if (focusedEntryKey && navigableEntryKeys.includes(focusedEntryKey)) {
|
||||
resolvedKey = focusedEntryKey;
|
||||
}
|
||||
|
||||
if (!resolvedKey) {
|
||||
for (let index = selectedEntries.length - 1; index >= 0; index -= 1) {
|
||||
const candidate = selectedEntries[index];
|
||||
if (navigableRowKeys.includes(candidate)) {
|
||||
if (navigableEntryKeys.includes(candidate)) {
|
||||
resolvedKey = candidate;
|
||||
break;
|
||||
}
|
||||
@@ -519,12 +519,12 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
|
||||
return;
|
||||
}
|
||||
|
||||
setFocusedRowKey(resolvedKey);
|
||||
setFocusedEntryKey(resolvedKey);
|
||||
}, [
|
||||
focusedRowKey,
|
||||
navigableRowKeys,
|
||||
focusedEntryKey,
|
||||
navigableEntryKeys,
|
||||
navigableRows,
|
||||
setFocusedRowKey,
|
||||
setFocusedEntryKey,
|
||||
selectedEntries,
|
||||
]);
|
||||
|
||||
@@ -543,15 +543,15 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
|
||||
event.preventDefault();
|
||||
|
||||
let activeKey =
|
||||
focusedRowKey && navigableRowKeys.includes(focusedRowKey)
|
||||
? focusedRowKey
|
||||
focusedEntryKey && navigableEntryKeys.includes(focusedEntryKey)
|
||||
? focusedEntryKey
|
||||
: null;
|
||||
|
||||
if (!activeKey) {
|
||||
if (selectedEntries.length) {
|
||||
for (let index = selectedEntries.length - 1; index >= 0; index -= 1) {
|
||||
const candidate = selectedEntries[index];
|
||||
if (navigableRowKeys.includes(candidate)) {
|
||||
if (navigableEntryKeys.includes(candidate)) {
|
||||
activeKey = candidate;
|
||||
break;
|
||||
}
|
||||
@@ -559,11 +559,11 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
|
||||
}
|
||||
|
||||
if (!activeKey) {
|
||||
activeKey = key === 'ArrowUp' ? navigableRowKeys[navigableRowKeys.length - 1] : navigableRowKeys[0];
|
||||
activeKey = key === 'ArrowUp' ? navigableEntryKeys[navigableEntryKeys.length - 1] : navigableEntryKeys[0];
|
||||
}
|
||||
}
|
||||
|
||||
const currentIndex = navigableRowKeys.indexOf(activeKey);
|
||||
const currentIndex = navigableEntryKeys.indexOf(activeKey);
|
||||
const activeRow = currentIndex === -1 ? null : navigableRows[currentIndex];
|
||||
|
||||
if (key === 'Enter' || key === ' ' || key === 'Space' || key === 'Spacebar') {
|
||||
@@ -601,22 +601,22 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
|
||||
return;
|
||||
}
|
||||
|
||||
setFocusedRowKey(targetRow.key);
|
||||
setFocusedEntryKey(targetRow.key);
|
||||
handleEntrySelection(targetRow.key, {
|
||||
shiftKey,
|
||||
preventDefault: () => { },
|
||||
});
|
||||
},
|
||||
[
|
||||
focusedRowKey,
|
||||
focusedEntryKey,
|
||||
getEntryByKey,
|
||||
navigableRowKeys,
|
||||
navigableEntryKeys,
|
||||
navigableRows,
|
||||
onFolderSelect,
|
||||
selectedEntries,
|
||||
handleDocumentPreviewZoom,
|
||||
handleEntrySelection,
|
||||
setFocusedRowKey,
|
||||
setFocusedEntryKey,
|
||||
],
|
||||
);
|
||||
|
||||
@@ -648,14 +648,14 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
|
||||
|
||||
const isTagDragEvent = useCallback((event) => isTagTransferEvent(event), []);
|
||||
const ensureFocusedRowVisible = useCallback(() => {
|
||||
if (!focusedRowKey) return;
|
||||
if (!focusedEntryKey) return;
|
||||
const container = scrollRef.current;
|
||||
if (!container) return;
|
||||
let selector = null;
|
||||
if (focusedRowKey.startsWith('document:')) {
|
||||
selector = `#document-row-${focusedRowKey.slice('document:'.length)}`;
|
||||
} else if (focusedRowKey.startsWith('folder:')) {
|
||||
selector = `#folder-row-${focusedRowKey.slice('folder:'.length)}`;
|
||||
if (focusedEntryKey.startsWith('document:')) {
|
||||
selector = `#document-row-${focusedEntryKey.slice('document:'.length)}`;
|
||||
} else if (focusedEntryKey.startsWith('folder:')) {
|
||||
selector = `#folder-row-${focusedEntryKey.slice('folder:'.length)}`;
|
||||
}
|
||||
if (!selector) {
|
||||
return;
|
||||
@@ -681,22 +681,22 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
|
||||
const nextScrollTop = rowBottom - container.clientHeight;
|
||||
container.scrollTop = Math.max(nextScrollTop, 0);
|
||||
}
|
||||
}, [focusedRowKey]);
|
||||
}, [focusedEntryKey]);
|
||||
|
||||
useEffect(() => {
|
||||
ensureFocusedRowVisible();
|
||||
}, [ensureFocusedRowVisible]);
|
||||
|
||||
const activeDescendantId = useMemo(() => {
|
||||
if (!focusedRowKey) return undefined;
|
||||
if (focusedRowKey.startsWith('document:')) {
|
||||
return `document-row-${focusedRowKey.slice('document:'.length)}`;
|
||||
if (!focusedEntryKey) return undefined;
|
||||
if (focusedEntryKey.startsWith('document:')) {
|
||||
return `document-row-${focusedEntryKey.slice('document:'.length)}`;
|
||||
}
|
||||
if (focusedRowKey.startsWith('folder:')) {
|
||||
return `folder-row-${focusedRowKey.slice('folder:'.length)}`;
|
||||
if (focusedEntryKey.startsWith('folder:')) {
|
||||
return `folder-row-${focusedEntryKey.slice('folder:'.length)}`;
|
||||
}
|
||||
return undefined;
|
||||
}, [focusedRowKey]);
|
||||
}, [focusedEntryKey]);
|
||||
|
||||
const handleDocumentTagDragOver = useCallback(
|
||||
(event) => {
|
||||
@@ -756,10 +756,10 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
|
||||
&& scrollRef.current
|
||||
) {
|
||||
scrollRef.current.focus({ preventScroll: true });
|
||||
setFocusedRowKey(`folder:${folder.id}`);
|
||||
setFocusedEntryKey(`folder:${folder.id}`);
|
||||
}
|
||||
},
|
||||
[onEntryPointer, setFocusedRowKey],
|
||||
[onEntryPointer, setFocusedEntryKey],
|
||||
);
|
||||
|
||||
const handleDocumentDragStartLocal = useCallback(
|
||||
|
||||
Reference in New Issue
Block a user