From 76b439fcab19ea0880b621806164db277571e8d5 Mon Sep 17 00:00:00 2001 From: sunshinesmilelk Date: Tue, 24 Dec 2024 08:33:30 +0800 Subject: [PATCH] refactor(core): refactor dnd list --- packages/libro-core/package.json | 6 +- .../dnd-component/custom-drag-layer.tsx | 144 -------- .../dnd-component/default-dnd-content.tsx | 262 ++++++-------- .../src/components/dnd-component/dnd-list.tsx | 322 +++++++++++++++--- .../src/components/dnd-component/index.less | 84 +++++ .../src/components/dnd-component/index.tsx | 1 - packages/libro-core/src/index.less | 22 -- packages/libro-core/src/libro-view.tsx | 23 +- 8 files changed, 471 insertions(+), 393 deletions(-) delete mode 100644 packages/libro-core/src/components/dnd-component/custom-drag-layer.tsx diff --git a/packages/libro-core/package.json b/packages/libro-core/package.json index 8baf0caf..0d6a40e7 100644 --- a/packages/libro-core/package.json +++ b/packages/libro-core/package.json @@ -57,14 +57,18 @@ "classnames": "^2.3.2", "dayjs": "^1.11.10", "dnd-core": "^16.0.1", + "lodash": "^4.17.21", "react-dnd": "^16.0.1", "react-dnd-html5-backend": "^16.0.1", + "react-dom": "^18.2.0", "resize-observer-polyfill": "^1.5.1", "uuid": "^9.0.0" }, "devDependencies": { "@types/react": "^18.2.25", - "@types/uuid": "^9.0.2" + "@types/react-dom": "^18.2.4", + "@types/uuid": "^9.0.2", + "@types/lodash": "^4.17.13" }, "peerDependencies": { "antd": "^5.8.6", diff --git a/packages/libro-core/src/components/dnd-component/custom-drag-layer.tsx b/packages/libro-core/src/components/dnd-component/custom-drag-layer.tsx deleted file mode 100644 index 85c899af..00000000 --- a/packages/libro-core/src/components/dnd-component/custom-drag-layer.tsx +++ /dev/null @@ -1,144 +0,0 @@ -/* eslint-disable react-hooks/exhaustive-deps */ -import { useInject, ViewInstance } from '@difizen/mana-app'; -import { ViewRender } from '@difizen/mana-app'; -import type { FC, CSSProperties } from 'react'; -import { useState, useEffect, memo } from 'react'; -import type { XYCoord } from 'react-dnd'; -import { useDragLayer } from 'react-dnd'; - -import type { CellService } from '../../cell/index.js'; -import { LibroCellService } from '../../cell/index.js'; -import type { CellView } from '../../libro-protocol.js'; -import type { LibroView } from '../../libro-view.js'; - -export interface SelectionPreviewProps { - activeCell: CellView; -} -const layerStyles: CSSProperties = { - position: 'fixed', - pointerEvents: 'none', - zIndex: 1000, - left: 0, - top: 0, - width: '300px', - height: '50px', -}; - -const getItemStyles = (currentOffset: XYCoord | null) => { - if (!currentOffset) { - return { - display: 'none', - }; - } - - const { x, y } = currentOffset; - - const transform = `translate(${x}px, ${y}px)`; - return { - transform, - WebkitTransform: transform, - }; -}; - -const MultipleSelectionPreview: FC<{ activeCell: CellView }> = ({ activeCell }) => { - const cellService = useInject(LibroCellService); - const [multipleSelectionPreview, setMultipleSelectionPreview] = useState(); - useEffect(() => { - cellService - .getOrCreateView(activeCell.model.options, activeCell.parent.id) - .then((view) => { - setMultipleSelectionPreview(view); - return; - }) - .catch((e) => { - // - }); - }, []); - - return ( -
-
- {multipleSelectionPreview && } -
-
-
- ); -}; - -export const MultipleSelectionPreviewMemo: FC = memo( - MultipleSelectionPreview, -); - -const SingleSelectionDragPreview: FC<{ activeCell: CellView }> = ({ activeCell }) => { - const cellService = useInject(LibroCellService); - const [singleSelectionPreview, setSingleSelectionPreview] = useState(); - useEffect(() => { - cellService - .getOrCreateView( - { - ...activeCell.model.options, - modelId: activeCell.model.id, - singleSelectionDragPreview: true, - }, - activeCell.parent.id, - ) - .then((view) => { - setSingleSelectionPreview(view); - return; - }) - .catch((e) => { - // - }); - }, []); - - return ( -
- {singleSelectionPreview && } -
- ); -}; - -export const SingleSelectionPreviewMemo: FC = memo( - SingleSelectionDragPreview, -); - -export const CustomDragLayer = () => { - const { isDragging, item, currentOffset } = useDragLayer((monitor) => ({ - item: monitor.getItem(), - itemType: monitor.getItemType(), - currentOffset: monitor.getClientOffset(), - isDragging: monitor.isDragging(), - })); - - const instance = useInject(ViewInstance); - - function renderItem() { - const isItemSelected = - instance.model.selections.findIndex((select) => select.id === item.cell.id) >= 0; - if (instance.model.selections.length !== 0 && isItemSelected) { - return ( - <> - {instance.model.active && ( - - )} - - ); - } - return ( - <> - {instance.model.active && ( - - )} - - ); - } - - if (!isDragging) { - return null; - } - return ( -
-
{renderItem()}
-
- ); -}; diff --git a/packages/libro-core/src/components/dnd-component/default-dnd-content.tsx b/packages/libro-core/src/components/dnd-component/default-dnd-content.tsx index 38a1c4e8..5a2abe9b 100644 --- a/packages/libro-core/src/components/dnd-component/default-dnd-content.tsx +++ b/packages/libro-core/src/components/dnd-component/default-dnd-content.tsx @@ -2,30 +2,26 @@ import { getOrigin, useInject, ViewInstance } from '@difizen/mana-app'; import { useConfigurationValue } from '@difizen/mana-app'; import { Button } from 'antd'; -import type { Identifier } from 'dnd-core'; import React, { useCallback, - useEffect, useLayoutEffect, useMemo, useRef, useState, forwardRef, + useContext, } from 'react'; -import { useDrag, useDragDropManager, useDrop } from 'react-dnd'; -import { getEmptyImage } from 'react-dnd-html5-backend'; import 'resize-observer-polyfill'; -import type { CellService } from '../../cell/index.js'; -import { LibroCellService } from '../../cell/index.js'; import { CellCollapsible } from '../../collapse-service.js'; -import { DragAreaKey, isCellView } from '../../libro-protocol.js'; import type { CellView, DndContentProps } from '../../libro-protocol.js'; import { MultiSelectionWhenShiftClick } from '../../libro-setting.js'; import type { LibroView } from '../../libro-view.js'; import { HolderOutlined, PlusOutlined } from '../../material-from-designer.js'; import { BetweenCellProvider } from '../cell-protocol.js'; +import { DragContext } from './dnd-list.js'; + export interface Dragparams { cell: CellView; index: number; @@ -42,11 +38,21 @@ export const DndCellContainer: React.FC = ({ MultiSelectionWhenShiftClick, ); const BetweenCellContent = useInject(BetweenCellProvider); - const cellService = useInject(LibroCellService); - const dragDropManager = useDragDropManager(); - const dragDropMonitor = dragDropManager.getMonitor(); + const [isMouseOverDragArea, setIsMouseOverDragArea] = useState(false); + const [isDragDown, setIsDragDown] = useState(false); const ItemRender = getOrigin(instance.dndItemRender); + const { + dragOverIndex, + isDraging, + sourceIndex, + onDragStart, + onDragOver, + onDrop, + onDragEnd, + fragFromRef, + } = useContext(DragContext); + useLayoutEffect(() => { if (typeof ref !== 'object') { return () => { @@ -119,174 +125,102 @@ export const DndCellContainer: React.FC = ({ return; } instance.model.selectCell(cell); - instance.model.selections = []; + if (instance.model.selections.length !== 0) { + instance.model.selections = []; + } }, [instance, cell]); - const scrollTimer = useRef(null); - const unsubscribe = useRef(null); + const isMultiSelected = + instance.model.selections.length !== 0 && instance.isSelected(cell); + + const isDragOver = useMemo(() => { + return index === dragOverIndex; + }, [index, dragOverIndex]); - const [{ isDrag }, drag, preview] = useDrag( - { - type: DragAreaKey, - item: { cell, index }, - collect: (monitor) => ({ - isDrag: monitor.isDragging(), - }), - end() { - instance.isDragging = false; - if (scrollTimer.current) { - clearInterval(scrollTimer.current); - } - }, + const handleDragStart = useCallback( + (e: React.DragEvent) => { + if (!instance.model.cellsEditable) { + e.preventDefault(); + return; + } + onDragStart?.(e, index); }, - [cell, index], + [index, instance.model.cellsEditable, onDragStart], ); - const libroViewContent = instance.container?.current?.getElementsByClassName( - 'libro-view-content', - )[0] as HTMLElement; + const handleDragOver = useCallback( + (e: React.DragEvent) => { + //判断拖拽来源是否cell + if (fragFromRef.current !== 'cell') { + return; + } + e.preventDefault(); + instance.model.mouseMode = 'drag'; + //判断是向下拖拽还是向上拖拽 + if (sourceIndex! < index) { + setIsDragDown(true); + } else { + setIsDragDown(false); + } + onDragOver(e, index); + }, + [fragFromRef, index, instance.model, onDragOver, sourceIndex], + ); - useEffect(() => { - unsubscribe.current = dragDropMonitor.subscribeToStateChange(() => { - instance.isDragging = dragDropMonitor.isDragging(); - scrollTimer.current = setInterval(() => { - const currentOffset = dragDropMonitor.getClientOffset(); - if (libroViewContent && instance.isDragging && currentOffset) { - const libroViewClientRect = libroViewContent.getBoundingClientRect(); - const { top, bottom } = libroViewClientRect; - const { y } = currentOffset; - const topLimit = top + 30; - const bottomLimit = bottom - 50; - if (y < topLimit) { - libroViewContent.scrollTop -= 0.5; - } else if (y > bottomLimit) { - libroViewContent.scrollTop += 0.5; - } - } - }, 10); - return () => { - if (scrollTimer.current) { - clearInterval(scrollTimer.current); - } - if (unsubscribe.current) { - unsubscribe.current(); - } - }; - }); - }, [dragDropMonitor]); + const handleDrop = useCallback( + (e: React.DragEvent) => { + e.preventDefault(); + if (fragFromRef.current !== 'cell') { + return; + } + onDrop(e, index); + }, + [fragFromRef, index, onDrop], + ); - useEffect(() => { - // This gets called after every render, by default - // (the first one, and every one after that) + const handleDragEnd = useCallback( + (e: React.DragEvent) => { + if (fragFromRef.current !== 'cell') { + return; + } + onDragEnd(e, index); + }, + [fragFromRef, index, onDragEnd], + ); - // Use empty image as a drag preview so browsers don't draw it - // and we can draw whatever we want on the custom drag layer instead. - preview(getEmptyImage(), { - // IE fallback: specify that we'd rather screenshot the node - // when it already knows it's being dragged so we can hide it with CSS. - captureDraggingState: true, - }); - }, [preview]); + const opacity = useMemo(() => { + return { + opacity: isDraging && sourceIndex === index ? 0.4 : 1, + }; + }, [index, isDraging, sourceIndex]); - const [{ handlerId, isDragOver }, drop] = useDrop< - Dragparams, - void, - { - handlerId: Identifier | null; - isDragOver: boolean; - } - >({ - accept: DragAreaKey, - drop(item, monitor) { - cellService - .getOrCreateView( - { - ...item.cell.model.options, - modelId: item.cell.model.id, - singleSelectionDragPreview: true, - }, - item.cell.parent.id, - ) - .then((view) => { - view.dispose(); - return; - }) - .catch((e) => { - // - }); - if (isCellView(item.cell)) { - const didDrop = monitor.didDrop(); - if (didDrop) { - return; - } - const dragIndex = instance.findCellIndex(item.cell); - const dropIndex = instance.findCellIndex(cell); - if (instance.model.selections.length > 0) { - const isDragInSelections = - instance.model.selections.findIndex( - (selection) => selection.id === item.cell.id, - ) > -1 - ? true - : false; - const isDropInSelections = - instance.model.selections.findIndex( - (selection) => selection.id === cell.id, - ) > -1 - ? true - : false; - if (isDragInSelections && isDropInSelections) { - return; - } - if (isDragInSelections) { - instance.model.exchangeCells(instance.model.selections, dropIndex); - instance.model.scrollToView(cell); + const onMouseOver = useCallback(() => { + setIsMouseOverDragArea(true); + }, []); - return; - } - } - if (dragIndex < dropIndex) { - instance.model.exchangeCell(dragIndex, dropIndex - 1); - instance.model.scrollToView(cell); - } - if (dragIndex > dropIndex) { - instance.model.exchangeCell(dragIndex, dropIndex); - instance.model.scrollToView(cell); - } - } - return; - }, - collect(monitor) { - return { - isDragOver: monitor.isOver(), - canDrop: monitor.canDrop(), - handlerId: monitor.getHandlerId(), - }; - }, - }); - const opacity = isDrag ? 0.4 : 1; - if (instance.model.cellsEditable) { - drop(ref); - } - if (isDrag) { - instance.model.mouseMode = 'drag'; - } + const onMouseLeave = useCallback(() => { + setIsMouseOverDragArea(false); + }, []); - const isMultiSelected = - instance.model.selections.length !== 0 && instance.isSelected(cell); // let isMouseOver = false; - const [isMouseOverDragArea, setIsMouseOverDragArea] = useState(false); const hasCellHidden = useMemo(() => { return cell.hasCellHidden(); }, [cell]); const isCollapsible = CellCollapsible.is(cell); + const wrapperclassName = useMemo(() => { + return `libro-dnd-cell-container ${isMultiSelected ? 'multi-selected' : ''} ${ + hasCellHidden ? 'hidden' : '' + }`; + }, [isMultiSelected]); + return (
@@ -294,15 +228,16 @@ export const DndCellContainer: React.FC = ({ index={position || index} addCell={cell.parent.addCellAbove} /> - {isDragOver &&
} + {!isDragDown && isDragOver &&
} {isMouseOverDragArea && }
setIsMouseOverDragArea(true)} - onMouseLeave={() => setIsMouseOverDragArea(false)} + onMouseOver={onMouseOver} + onMouseLeave={onMouseLeave} />
= ({ > @@ -329,6 +264,7 @@ export const DndCellContainer: React.FC = ({
)} + {isDragDown && isDragOver &&
}
); }; diff --git a/packages/libro-core/src/components/dnd-component/dnd-list.tsx b/packages/libro-core/src/components/dnd-component/dnd-list.tsx index dfa41ff7..d7d0c8a4 100644 --- a/packages/libro-core/src/components/dnd-component/dnd-list.tsx +++ b/packages/libro-core/src/components/dnd-component/dnd-list.tsx @@ -1,21 +1,103 @@ import { getOrigin, useInject, useObserve, ViewInstance } from '@difizen/mana-app'; import classNames from 'classnames'; +import { throttle } from 'lodash'; import type { FC, ReactNode } from 'react'; -import { forwardRef, memo, useEffect, useState } from 'react'; -import type { XYCoord } from 'react-dnd'; -import { useDrop } from 'react-dnd'; +import { + useRef, + useCallback, + createContext, + useMemo, + forwardRef, + memo, + useEffect, + useState, +} from 'react'; +import { createRoot } from 'react-dom/client'; import type { CellService } from '../../cell/index.js'; +import { ExecutableCellModel } from '../../cell/index.js'; import { LibroCellService } from '../../cell/index.js'; import type { CellView, DndContentProps } from '../../libro-protocol.js'; -import { DragAreaKey, isCellView } from '../../libro-protocol.js'; +import { isCellView } from '../../libro-protocol.js'; import type { LibroView } from '../../libro-view.js'; import { VirtualizedManagerHelper } from '../../virtualized-manager-helper.js'; import { LibroCellsOutputRender } from '../libro-virtualized-render.js'; -import type { Dragparams } from './default-dnd-content.js'; import './index.less'; +interface IDragContextType { + dragOverIndex?: number; + isDraging: boolean; + sourceIndex?: number; + onDragStart: (e: React.DragEvent, index: number) => void; + onDragOver: (e: React.DragEvent, index: number) => void; + onDrop: (e: React.DragEvent, index: number) => void; + onDragEnd: (e?: React.DragEvent, index?: number) => void; + fragFromRef: any; +} + +export const DragContext = createContext({ + dragOverIndex: undefined, + isDraging: false, + sourceIndex: undefined, + onDragStart: () => { + return; + }, + onDragOver: () => { + return; + }, + onDrop: () => { + return; + }, + onDragEnd: () => { + return; + }, + fragFromRef: {}, +}); + +const MultipleImageCompnent = ({ selections }: { selections: CellView[] }) => { + const firstCell = selections[0]; + const executable = ExecutableCellModel.is(firstCell.model); + const executeState = + ExecutableCellModel.is(firstCell.model) && !firstCell.model.executing + ? firstCell.model.executeCount || ' ' + : '*'; + return ( +
+
+ {executable && ( +
{`[${executeState}]:`}
+ )} +
+          {firstCell.model.value}
+        
+
+
+
+ ); +}; + +const CellImageComponent = ({ cell }: { cell: CellView }) => { + const executable = ExecutableCellModel.is(cell.model); + const executeState = + ExecutableCellModel.is(cell.model) && !cell.model.executing + ? cell.model.executeCount || ' ' + : '*'; + + return ( +
+
+ {executable && ( +
{`[${executeState}]:`}
+ )} +
+          {cell.model.value}
+        
+
+
+ ); +}; + export const DndCellRender: FC = memo(function DndCellRender({ cell, index, @@ -159,67 +241,215 @@ export const DndList = forwardRef< ref, ) { const cellService = useInject(LibroCellService); + const [isDraging, setIsDraging] = useState(false); + const [dragOverIndex, setDragOverIndex] = useState(); + const [sourceIndex, setSourceIndex] = useState(); + const followNodeRef = useRef(); + const editorScrollRef = useRef(); + const multipleImageRef = useRef(); + const singleImageRef = useRef(); + const fragFromRef = useRef(''); + useEffect(() => { + const multipleDrag = document.getElementById('libro-multiple-drag-container'); + if (multipleDrag) { + multipleImageRef.current = multipleDrag as HTMLDivElement; + } else { + multipleImageRef.current = document.createElement('div'); + multipleImageRef.current.id = 'libro-multiple-drag-container'; + document.body.appendChild(multipleImageRef.current); + } - const [, drop] = useDrop(() => ({ - accept: DragAreaKey, - drop(item, dropMonitor) { + const singleDrag = document.getElementById('libro-single-drag-container'); + if (singleDrag) { + singleImageRef.current = singleDrag as HTMLDivElement; + } else { + singleImageRef.current = document.createElement('div'); + singleImageRef.current.id = 'libro-single-drag-container'; + document.body.appendChild(singleImageRef.current); + } + }, []); + + const clearSelects = useCallback(() => { + if (libroView.model.selections.length > 0) { + libroView.model.selections = []; + } + }, [libroView.model]); + + const exchangeCellIndex = useCallback( + (sourceCellIndex: number, targetIndex: number) => { + const sourceCellView = libroView.model.cells[sourceCellIndex]; + if (!sourceCellView) { + return; + } cellService .getOrCreateView( { - ...item.cell.model.options, - modelId: item.cell.model.id, + ...sourceCellView.model.options, + modelId: sourceCellView.model.id, singleSelectionDragPreview: true, }, - item.cell.parent.id, + sourceCellView.parent.id, ) - .then((view) => { + .then((view: { dispose: () => void }) => { view.dispose(); return; }) - .catch((e) => { + .catch(() => { // }); - if (isCellView(item.cell)) { - const didDrop = dropMonitor.didDrop(); - if (didDrop) { + if (isCellView(sourceCellView)) { + const targetCell = libroView.model.cells[targetIndex]; + if (sourceCellIndex < targetIndex) { + libroView.model.exchangeCell(sourceCellIndex, targetIndex); + libroView.model.scrollToView(targetCell); + } + if (sourceCellIndex > targetIndex) { + libroView.model.exchangeCell(sourceCellIndex, targetIndex); + libroView.model.scrollToView(targetCell); + } + } + }, + [cellService, libroView.model], + ); + + const onDragStart = useCallback( + async (e: React.DragEvent, sourceCellIndex: number) => { + e.dataTransfer.setData('libro_notebook_drag_text', `${sourceCellIndex}`); + fragFromRef.current = 'cell'; + e.dataTransfer.effectAllowed = 'move'; + + const selectCells: CellView[] = libroView.model.selections; + + const childNode = (e.target as HTMLElement).parentElement?.getElementsByClassName( + 'libro-cell-input-content', + )[0] as HTMLDivElement; + + // 多选cell拖拽排序 + const sourceCellView = libroView.model.cells[sourceCellIndex]; + if ( + selectCells.length > 0 && + selectCells.findIndex((selection) => selection.id === sourceCellView.id) > -1 && + multipleImageRef.current + ) { + const root = createRoot(multipleImageRef.current); + root.render(); + // 清除编辑器中无效元素宽度(只针对e2编辑器) + const editorScrollNodex = childNode?.getElementsByClassName( + 'erd_scroll_detection_container', + )[0]; + if (editorScrollNodex) { + editorScrollRef.current = editorScrollNodex as HTMLDivElement; + (editorScrollNodex as HTMLDivElement).style.display = 'none'; + } + e.dataTransfer.setDragImage(multipleImageRef.current, 0, 0); + } else { + if (!childNode) { return; } - // Determine mouse position - const clientOffset = dropMonitor.getClientOffset(); - const clientOffsetY = (clientOffset as XYCoord).y; - const dragIndex = libroView.findCellIndex(item.cell); - // Determine rectangle on screen - const lastCell = - libroView.model.getCells()[libroView.model.getCells().length - 1]; - const lastCellOffsetY = lastCell.container?.current?.getBoundingClientRect().y; - if (lastCellOffsetY && clientOffsetY >= lastCellOffsetY) { - if (libroView.model.selections.length > 0) { - const isDragInSelections = - libroView.model.selections.findIndex( - (selection) => selection.id === item.cell.id, - ) > -1 - ? true - : false; - if (isDragInSelections) { - libroView.model.exchangeCells( - libroView.model.selections, - libroView.model.cells.length, - ); - return; - } - } - libroView.model.exchangeCell(dragIndex, libroView.model.cells.length - 1); + // 拖拽单个cell排序 + clearSelects(); + if (childNode.clientHeight > 300) { + followNodeRef.current = childNode; + childNode.style.maxHeight = '300px'; + childNode.style.overflow = 'hidden'; + } + + if (singleImageRef.current) { + const root = createRoot(singleImageRef.current); + root.render(); + e.dataTransfer.setDragImage(singleImageRef.current, 0, 0); } } - // Determine mouse position + setSourceIndex(sourceCellIndex); + setIsDraging(true); + }, + [clearSelects, libroView.model.cells, libroView.model.selections], + ); - return; + const onDragOver = useCallback((e: React.DragEvent, index: number) => { + e.preventDefault(); + throttle(() => { + setDragOverIndex(index); + }, 1000)(); + }, []); + + const onDrop = useCallback( + (e: React.DragEvent, index: number) => { + e.preventDefault(); + const sourceCellIndex = e.dataTransfer.getData('libro_notebook_drag_text'); + setIsDraging(false); + setDragOverIndex(undefined); + setSourceIndex(undefined); + const _sourceIndex = Number(sourceCellIndex || 0); + if (libroView.model.selections.length > 0) { + const sourceCellView = libroView.model.cells[_sourceIndex]; + const dropCellView = libroView.model.cells[index]; + const isDragInSelections = libroView.model.selections.some( + (selection: { id: string }) => selection.id === sourceCellView.id, + ); + const isDropInSelections = libroView.model.selections.some( + (selection: { id: string }) => selection.id === dropCellView.id, + ); + if (isDragInSelections && isDropInSelections) { + return; + } + if (isDragInSelections) { + libroView.model.exchangeCells(libroView.model.selections, index); + libroView.model.scrollToView(dropCellView); + } + return; + } + if (_sourceIndex === index) { + return; + } + exchangeCellIndex(_sourceIndex, index); }, - })); + [exchangeCellIndex, libroView.model], + ); + + const onDragEnd = useCallback((e?: React.DragEvent) => { + e?.dataTransfer.clearData(); + setIsDraging(false); + setDragOverIndex(undefined); + setSourceIndex(undefined); + if (followNodeRef.current) { + followNodeRef.current.style.maxHeight = 'unset'; + followNodeRef.current.style.overflow = 'unset'; + } + if (editorScrollRef.current) { + editorScrollRef.current.style.display = 'unset'; + } + + fragFromRef.current = ''; + }, []); + + const dragContextValue = useMemo(() => { + return { + dragOverIndex, + isDraging, + sourceIndex, + onDragStart, + onDragOver, + onDrop, + onDragEnd, + fragFromRef, + }; + }, [ + dragOverIndex, + isDraging, + onDragEnd, + onDragOver, + onDragStart, + onDrop, + sourceIndex, + fragFromRef, + ]); return ( -
- +
+ + +
); }); diff --git a/packages/libro-core/src/components/dnd-component/index.less b/packages/libro-core/src/components/dnd-component/index.less index ec67fa5c..970e8ca2 100644 --- a/packages/libro-core/src/components/dnd-component/index.less +++ b/packages/libro-core/src/components/dnd-component/index.less @@ -10,3 +10,87 @@ .libro-dnd-cells-container { padding-top: 8px; } + +#libro-multiple-drag-container { + position: absolute; + top: 0; + left: 0; + z-index: -2; + height: 0; +} + +#libro-single-drag-container { + position: absolute; + top: 0; + left: 0; + z-index: -2; +} + +.libro-drag-image-container, +.libro-single-drag-image-container { + margin: 8px; + + .libro-cell-drag-image-input-container { + position: relative; + display: flex; + padding: 12px; + background-color: var(--mana-libro-background); + } + + .cell-drag-image-input { + z-index: 100; + max-height: 68px; + max-width: 300px; + min-height: 40px; + min-width: 100px; + overflow: hidden; + padding: 8px; + border: 1px solid var(--mana-libro-cell-border-color); + border-radius: 4px; + background: var(--mana-libro-input-background); + } + + .libro-execute-state-tip { + padding-right: 8px; + color: var(--mana-libro-execution-count-color); + font-size: 11px; + vertical-align: top; + user-select: none; + } +} + +.libro-dnd-cascading-multiple-selection { + position: absolute; + bottom: 6px; + right: 6px; + width: calc(100% - 60px); + height: calc(100% - 30px); + border: 1px solid var(--mana-libro-cell-border-color); + border-radius: 4px; + box-shadow: + 0 6px 16px 0 rgba(0, 0, 0, 8%), + 0 3px 6px -4px rgba(0, 0, 0, 12%), + 0 9px 28px 8px rgba(0, 0, 0, 5%); +} + +.libro-drag-hoverline { + position: absolute; + top: -2px; + left: 56px; + z-index: 100; + width: calc(100% - 70px); + height: 4px; + background-color: var(--mana-libro-drag-hover-line-color); + border-radius: 2px; +} + +.libro-drag-hoverline-last-one { + position: absolute; + left: 56px; + bottom: -2px; + z-index: 100; + width: calc(100% - 70px); + height: 4px; + background-color: var(--mana-libro-drag-hover-line-color); + border-radius: 2px; +} diff --git a/packages/libro-core/src/components/dnd-component/index.tsx b/packages/libro-core/src/components/dnd-component/index.tsx index 17eb6565..f0ce7042 100644 --- a/packages/libro-core/src/components/dnd-component/index.tsx +++ b/packages/libro-core/src/components/dnd-component/index.tsx @@ -1,4 +1,3 @@ -export * from './custom-drag-layer.js'; export * from './default-dnd-content.js'; export * from './dnd-context.js'; export * from './dnd-list.js'; diff --git a/packages/libro-core/src/index.less b/packages/libro-core/src/index.less index 13b68e47..83b18540 100644 --- a/packages/libro-core/src/index.less +++ b/packages/libro-core/src/index.less @@ -315,17 +315,6 @@ border: 1px solid var(--mana-color-border); } -.libro-dnd-cascading-multiple-selection { - position: absolute; - top: -10px; - left: -10px; - z-index: 100; - width: 700px; - height: 40px; - background-color: var(--mana-color-bg-container); - border: 1px solid var(--mana-color-border); -} - .libro-cell-container { position: relative; background-color: var(--mana-color-bg-container); @@ -558,17 +547,6 @@ cursor: move; } -.libro-drag-hoverline { - position: absolute; - top: -2px; - left: 56px; - z-index: 100; - width: calc(100% - 70px); - height: 4px; - background-color: var(--mana-libro-drag-hover-line-color); - border-radius: 2px; -} - .libro-view-content-left { position: relative; width: calc(100% - 20px); diff --git a/packages/libro-core/src/libro-view.tsx b/packages/libro-core/src/libro-view.tsx index ce449a83..d02611ac 100644 --- a/packages/libro-core/src/libro-view.tsx +++ b/packages/libro-core/src/libro-view.tsx @@ -41,13 +41,7 @@ import type { LibroCell } from './cell/index.js'; import type { LibroCellModel } from './cell/libro-cell-model.js'; import { CollapseServiceFactory } from './collapse-service.js'; import type { CollapseService } from './collapse-service.js'; -import { - CustomDragLayer, - DndCellContainer, - DndCellItemRender, - DndContext, - DndList, -} from './components/index.js'; +import { DndCellContainer, DndCellItemRender, DndList } from './components/index.js'; import { LibroViewHeader } from './components/libro-view-header.js'; import { LibroContextKey } from './libro-context-key.js'; import { LibroModel } from './libro-model.js'; @@ -173,15 +167,12 @@ export const LibroContentComponent = memo(function LibroContentComponent() { style={leftContentStyles} ref={libroViewLeftContentRef} > - - - - - - + + +