Skip to content

Commit

Permalink
fix: metadata header drag (#6864)
Browse files Browse the repository at this point in the history
* fix: metadata header drag

* feat: optimize code

* feat: optimize code

* feat: optimize code

* feat: optimize code

---------

Co-authored-by: 杨国璇 <[email protected]>
Co-authored-by: 杨国璇 <[email protected]>
  • Loading branch information
3 people authored Oct 11, 2024
1 parent 4ee7f04 commit 9b27549
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 97 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,38 @@
transform: scale(.8);
}

.sf-metadata-record-header-cell .sf-metadata-result-table-cell.column.name-column {
cursor: default;
}

.sf-metadata-record-header-cell .rdg-can-drop > .sf-metadata-result-table-cell.column {
cursor: move;
}

.sf-metadata-record-header-cell .rdg-dropping > .sf-metadata-result-table-cell.column {
background: #ececec;
position: relative;
}

.sf-metadata-record-header-cell .rdg-dropping-position > .sf-metadata-result-table-cell.column::before {
content: '';
position: absolute;
top: 10%;
height: 80%;
width: 1px;
background-color: #2d7ff9;
border-radius: 50%;
z-index: 1;
}

.sf-metadata-record-header-cell .rdg-dropping-position-left > .sf-metadata-result-table-cell.column::before {
left: -1px;
}

.sf-metadata-record-header-cell .rdg-dropping-position-right > .sf-metadata-result-table-cell.column::before {
right: -1px;
}

.sf-metadata-record-header-cell .rdg-dropping-position-none > .sf-metadata-result-table-cell.column::before {
display: none;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,98 +2,36 @@ import React, { useRef, useCallback, useMemo } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { UncontrolledTooltip } from 'reactstrap';
import { DragSource, DropTarget } from 'react-dnd';
import { Icon } from '@seafile/sf-metadata-ui-component';
import ResizeColumnHandle from './resize-column-handle';
import DropdownMenu from './dropdown-menu';
import { gettext } from '../../../../../../utils/constants';
import { COLUMNS_ICON_CONFIG, COLUMNS_ICON_NAME, EVENT_BUS_TYPE } from '../../../../../constants';
import { COLUMNS_ICON_CONFIG, COLUMNS_ICON_NAME, EVENT_BUS_TYPE, PRIVATE_COLUMN_KEY } from '../../../../../constants';

import './index.css';


const dragSource = {
beginDrag: props => {
return { key: props.column.key, column: props.column };
},
endDrag(props, monitor) {
const source = monitor.getItem();
const didDrop = monitor.didDrop();
let target = {};
if (!didDrop) {
return { source, target };
}
},
isDragging(props) {
const { column, dragged } = props;
const { key } = dragged;
return key === column.key;
}
};

const dropTarget = {
hover(props, monitor, component) {
// This is fired very often and lets you perform side effects.
if (!window.sfMetadataBody) return;
let defaultColumnWidth = 200;
const offsetX = monitor.getClientOffset().x;
const width = document.querySelector('.sf-metadata-wrapper')?.clientWidth;
const left = window.innerWidth - width;
if (width <= 800) {
defaultColumnWidth = 20;
}
if (offsetX > window.innerWidth - defaultColumnWidth) {
window.sfMetadataBody.scrollToRight();
} else if (offsetX < props.frozenColumnsWidth + defaultColumnWidth + left) {
window.sfMetadataBody.scrollToLeft();
} else {
window.sfMetadataBody.clearHorizontalScroll();
}
},
drop(props, monitor) {
const source = monitor.getItem();
const { column: targetColumn } = props;
if (targetColumn.key !== source.key && source.column.frozen === targetColumn.frozen) {
let target = { key: targetColumn.key };
props.onMove(source, target);
window.sfMetadataBody.clearHorizontalScroll();
}
}
};

const dragCollect = (connect, monitor) => ({
connectDragSource: connect.dragSource(),
connectDragPreview: connect.dragPreview(),
isDragging: monitor.isDragging(),
});

const dropCollect = (connect, monitor) => ({
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
dragged: monitor.getItem(),
});

const Cell = ({
isOver,
isDragging,
canDrop,
connectDragSource,
connectDragPreview,
connectDropTarget,
frozen,
groupOffsetLeft,
isLastFrozenCell,
height,
isHideTriangle,
column,
columnIndex,
style: propsStyle,
draggingColumnKey,
draggingColumnIndex,
dragOverColumnKey,
view,
frozenColumnsWidth,
renameColumn,
deleteColumn,
modifyColumnData,
modifyLocalColumnWidth,
modifyColumnWidth,
onMove,
updateDraggingKey,
updateDragOverKey,
}) => {
const headerCellRef = useRef(null);

Expand All @@ -120,14 +58,14 @@ const Cell = ({
return right - left;
}, []);

const onDrag = useCallback((e) => {
const onDraggingColumnWidth = useCallback((e) => {
const width = getWidthFromMouseEvent(e);
if (width > 0) {
modifyLocalColumnWidth(column, width);
}
}, [column, getWidthFromMouseEvent, modifyLocalColumnWidth]);

const onDragEnd = useCallback((e) => {
const handleColumnWidth = useCallback((e) => {
const width = getWidthFromMouseEvent(e);
if (width > 0) {
modifyColumnWidth(column, Math.max(width, 50));
Expand All @@ -143,12 +81,65 @@ const Cell = ({
event.stopPropagation();
}, []);

const onDragStart = useCallback((event) => {
const dragData = JSON.stringify({ type: 'sf-metadata-view-header-order', column_key: column.key, column });
event.dataTransfer.effectAllowed = 'move';
event.dataTransfer.setData('application/drag-sf-metadata-view-header-order', dragData);
updateDraggingKey(column.key);
}, [column, updateDraggingKey]);

const onDragEnter = useCallback(() => {
updateDragOverKey(column.key);
}, [column, updateDragOverKey]);

const onDragLeave = useCallback(() => {
updateDragOverKey(null);
}, [updateDragOverKey]);

const onDragOver = useCallback((event) => {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
updateDragOverKey(column.key);
if (!window.sfMetadataBody) return;
let defaultColumnWidth = 200;
const offsetX = event.clientX;
const width = document.querySelector('.sf-metadata-wrapper')?.clientWidth;
const left = window.innerWidth - width;
if (width <= 800) {
defaultColumnWidth = 20;
}
if (offsetX > window.innerWidth - defaultColumnWidth) {
window.sfMetadataBody.scrollToRight();
} else if (offsetX < frozenColumnsWidth + defaultColumnWidth + left) {
window.sfMetadataBody.scrollToLeft();
} else {
window.sfMetadataBody.clearHorizontalScroll();
}
}, [column, frozenColumnsWidth, updateDragOverKey]);

const onDrop = useCallback((event) => {
event.stopPropagation();
let dragData = event.dataTransfer.getData('application/drag-sf-metadata-view-header-order');
if (!dragData) return false;
dragData = JSON.parse(dragData);
if (dragData.type !== 'sf-metadata-view-header-order' || !dragData.column_key) return false;
if (dragData.column_key !== column.key && dragData.column.frozen === column.frozen) {
onMove && onMove({ key: dragData.column_key }, { key: column.key });
}
}, [column, onMove]);

const onDragEnd = useCallback(() => {
updateDraggingKey(null);
updateDragOverKey(null);
}, [updateDraggingKey, updateDragOverKey]);

const { key, name, type } = column;
const headerIconTooltip = COLUMNS_ICON_NAME[type];
const canModifyColumnOrder = window.sfMetadataContext.canModifyColumnOrder();
const isNameColumn = key === PRIVATE_COLUMN_KEY.FILE_NAME;
const cell = (
<div
className={classnames('sf-metadata-result-table-cell column', { 'table-last--frozen': isLastFrozenCell })}
className={classnames('sf-metadata-result-table-cell column', { 'table-last--frozen': isLastFrozenCell, 'name-column': isNameColumn })}
ref={headerCellRef}
style={style}
id={`sf-metadata-column-${key}`}
Expand All @@ -175,29 +166,40 @@ const Cell = ({
modifyColumnData={modifyColumnData}
/>
)}
<ResizeColumnHandle onDrag={onDrag} onDragEnd={onDragEnd} />
<ResizeColumnHandle onDrag={onDraggingColumnWidth} onDragEnd={handleColumnWidth} />
</div>
);

if (!canModifyColumnOrder) {
if (!canModifyColumnOrder || isNameColumn) {
return (
<div key={key} className="sf-metadata-record-header-cell">
{cell}
</div>
);
}

const isOver = dragOverColumnKey === column.key;

return (
<div key={key} className="sf-metadata-record-header-cell">
{connectDropTarget(
connectDragPreview(
connectDragSource(
<div style={{ opacity: isDragging ? 0.2 : 1 }} className={classnames('rdg-can-drop', { 'rdg-dropping': isOver && canDrop })}>
{cell}
</div>
)
)
)}
<div
draggable="true"
style={{ opacity: draggingColumnKey === column.key ? 0.2 : 1 }}
className={classnames('rdg-can-drop', {
'rdg-dropping rdg-dropping-position': isOver,
'rdg-dropping-position-left': isOver && draggingColumnIndex > columnIndex,
'rdg-dropping-position-right': isOver && draggingColumnIndex < columnIndex,
'rdg-dropping-position-none': isOver && draggingColumnIndex === columnIndex
})}
onDragStart={onDragStart}
onDragEnter={onDragEnter}
onDragLeave={onDragLeave}
onDragOver={onDragOver}
onDrop={onDrop}
onDragEnd={onDragEnd}
>
{cell}
</div>
</div>
);
};
Expand All @@ -210,17 +212,21 @@ Cell.propTypes = {
groupOffsetLeft: PropTypes.number,
height: PropTypes.number,
column: PropTypes.object,
columnIndex: PropTypes.number,
style: PropTypes.object,
frozen: PropTypes.bool,
isLastFrozenCell: PropTypes.bool,
isHideTriangle: PropTypes.bool,
draggingColumnKey: PropTypes.string,
draggingColumnIndex: PropTypes.number,
dragOverColumnKey: PropTypes.string,
view: PropTypes.object,
renameColumn: PropTypes.func,
deleteColumn: PropTypes.func,
modifyColumnData: PropTypes.func,
modifyLocalColumnWidth: PropTypes.func,
updateDraggingKey: PropTypes.func,
updateDragOverKey: PropTypes.func,
};

export default DropTarget('sfMetadataRecordHeaderCell', dropTarget, dropCollect)(
DragSource('sfMetadataRecordHeaderCell', dragSource, dragCollect)(Cell)
);
export default Cell;
Loading

0 comments on commit 9b27549

Please sign in to comment.