UNPKG

linkmore-design

Version:

🌈 🚀lm组件库。🚀

589 lines (581 loc) 18.3 kB
"use strict"; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.TRASH_ID = void 0; exports.default = DndContainer; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _react = _interopRequireWildcard(require("react")); var _reactDom = require("react-dom"); var _core = require("@dnd-kit/core"); var _sortable = require("@dnd-kit/sortable"); var _utilities = require("@dnd-kit/utilities"); var _multipleContainersKeyboardCoordinates = _interopRequireDefault(require("../multipleContainersKeyboardCoordinates")); var _Item = require("./Item"); var _Container = require("./Container"); var _classnames = _interopRequireDefault(require("classnames")); const defaultDropAnimationSideEffects = options => ({ active, dragOverlay }) => { const originalStyles = {}; const { styles, className } = options; if (styles?.active) { for (const [key, value] of Object.entries(styles.active)) { if (value === undefined) { continue; } originalStyles[key] = active.node.style.getPropertyValue(key); active.node.style.setProperty(key, value); } } if (styles?.dragOverlay) { for (const [key, value] of Object.entries(styles.dragOverlay)) { if (value === undefined) { continue; } dragOverlay.node.style.setProperty(key, value); } } if (className?.active) { active.node.classList.add(className.active); } if (className?.dragOverlay) { dragOverlay.node.classList.add(className.dragOverlay); } return function cleanup() { for (const [key, value] of Object.entries(originalStyles)) { active.node.style.setProperty(key, value); } if (className?.active) { active.node.classList.remove(className.active); } }; }; const animateLayoutChanges = args => (0, _sortable.defaultAnimateLayoutChanges)({ ...args, wasDragging: true }); function DroppableContainer({ children, columns = 1, disabled, id, items, style, ...props }) { const { active, attributes, isDragging, listeners, over, setNodeRef, transition, transform } = (0, _sortable.useSortable)({ id, data: { type: 'container', children: items }, animateLayoutChanges }); const isOverContainer = over ? id === over.id && active?.data.current?.type !== 'container' || items.includes(over.id) : false; return /*#__PURE__*/_react.default.createElement(_Container.Container, (0, _extends2.default)({ ref: disabled ? undefined : setNodeRef, style: { ...style, transition, transform: _utilities.CSS.Translate.toString(transform), opacity: isDragging ? 0.5 : undefined }, hover: isOverContainer, handleProps: { ...attributes, ...listeners }, columns: columns }, props), children); } const dropAnimation = { sideEffects: defaultDropAnimationSideEffects({ styles: { active: { opacity: '0.5' } } }) }; const TRASH_ID = 'void'; // const PLACEHOLDER_ID = 'placeholder'; // const empty: UniqueIdentifier[] = []; exports.TRASH_ID = TRASH_ID; function DndContainer({ // 调整比例尺 adjustScale = false, itemCount = 3, cancelDrop, columns, handle = false, items: initialItems, containerStyle, coordinateGetter = _multipleContainersKeyboardCoordinates.default, getItemStyles = () => ({}), wrapperStyle = () => ({}), modifiers, renderItem, trashable = false, scrollable, children, updateItems = () => ({}), rowGroupTitle = '行分组', colGroupTitle = '列分组', filterColumns = [] }) { const [items, setItems] = (0, _react.useState)(() => initialItems); (0, _react.useEffect)(() => { setItems(initialItems); }, [initialItems]); const [containers, setContainers] = (0, _react.useState)(Object.keys(items)); const [activeId, setActiveId] = (0, _react.useState)(null); const lastOverId = (0, _react.useRef)(null); // 是否移动到新容器 const recentlyMovedToNewContainer = (0, _react.useRef)(false); const isSortingContainer = activeId ? containers.includes(activeId) : false; // 执行顺序: onDragStart,collisionDetection,onDragOver,[...collisionDetection],onDragEnd /** * Custom collision detection strategy optimized for multiple containers * 针对多个容器优化的自定义碰撞检测策略 * - First, find any droppable containers intersecting with the pointer. * - If there are none, find intersecting containers with the active draggable. * - If there are no intersecting containers, return the last matched intersection * 1.首先,找到与指针相交的任何可放置容器。2.如果没有,则查找具有活动可拖动对象的相交容器。3.如果没有交叉容器,则返回最后匹配的交叉 */ const collisionDetectionStrategy = (0, _react.useCallback)(args => { if (activeId && activeId in items) { return (0, _core.closestCenter)({ ...args, droppableContainers: args.droppableContainers.filter(container => container.id in items) }); } // Start by finding any intersecting droppable const pointerIntersections = (0, _core.pointerWithin)(args); const intersections = pointerIntersections.length > 0 ? // If there are droppables intersecting with the pointer, return those pointerIntersections : (0, _core.rectIntersection)(args); let overId = (0, _core.getFirstCollision)(intersections, 'id'); if (overId != null) { if (overId === TRASH_ID) { // If the intersecting droppable is the trash, return early // Remove this if you're not using trashable functionality in your app return intersections; } if (overId in items) { const containerItems = items[overId]; // If a container is matched and it contains items (columns 'A', 'B', 'C') if (containerItems.length > 0) { // 返回该容器中最近的滴管 // Return the closest droppable within that container overId = (0, _core.closestCenter)({ ...args, droppableContainers: args.droppableContainers.filter(container => container.id !== overId && containerItems.includes(container.id)) })[0]?.id; } } lastOverId.current = overId; return [{ id: overId }]; } // When a draggable item moves to a new container, the layout may shift // and the `overId` may become `null`. We manually set the cached `lastOverId` // to the id of the draggable item that was moved to the new container, otherwise // the previous `overId` will be returned which can cause items to incorrectly shift positions if (recentlyMovedToNewContainer.current) { lastOverId.current = activeId; } // If no droppable is matched, return the last match return lastOverId.current ? [{ id: lastOverId.current }] : []; }, [activeId, items]); const [clonedItems, setClonedItems] = (0, _react.useState)(null); // 传感器 const sensors = (0, _core.useSensors)((0, _core.useSensor)(_core.MouseSensor), (0, _core.useSensor)(_core.TouchSensor), (0, _core.useSensor)(_core.KeyboardSensor, { coordinateGetter })); const findContainer = id => { if (id in items) { return id; } return Object.keys(items).find(key => items[key].includes(id)); }; const getIndex = id => { const container = findContainer(id); if (!container) { return -1; } const index = items[container].indexOf(id); return index; }; const onDragCancel = () => { if (clonedItems) { // Reset items to their original state in case items have been // Dragged across containers setItems(clonedItems); } setActiveId(null); setClonedItems(null); }; (0, _react.useEffect)(() => { const id = requestAnimationFrame(() => { recentlyMovedToNewContainer.current = false; }); return () => cancelAnimationFrame(id); }, [items]); const isOk = (active, over) => { const item = filterColumns.find(item => item.title === active.id); if (over.id === 'row' || items?.row?.includes(over.id)) { return item && item.rowGroup; } else if (over.id === 'col' || items?.col?.includes(over.id)) { return item && item.colGroup; } return true; }; const topContainers = containers.filter(item => item !== 'tableHeader'); const tableContainer = containers.filter(item => item === 'tableHeader')[0]; return /*#__PURE__*/_react.default.createElement(_core.DndContext, { sensors: sensors, collisionDetection: collisionDetectionStrategy, measuring: { droppable: { strategy: _core.MeasuringStrategy.Always } }, onDragStart: ({ active }) => { setActiveId(active.id); setClonedItems(items); }, onDragOver: ({ active, over }) => { const overId = over?.id; if (overId == null || overId === TRASH_ID || active.id in items) { return; } if (!isOk(active, over)) { return; } const overContainer = findContainer(overId); const activeContainer = findContainer(active.id); if (!overContainer || !activeContainer) { return; } if (activeContainer !== overContainer) { setItems(items => { const activeItems = items[activeContainer]; const overItems = items[overContainer]; const overIndex = overItems.indexOf(overId); const activeIndex = activeItems.indexOf(active.id); let newIndex; if (overId in items) { newIndex = overItems.length + 1; } else { // 当前激活的是否在目标下面 const isBelowOverItem = over && active.rect.current.translated && active.rect.current.translated.top > over.rect.top + over.rect.height; const modifier = isBelowOverItem ? 1 : 0; newIndex = overIndex >= 0 ? overIndex + modifier : overItems.length + 1; } recentlyMovedToNewContainer.current = true; return { ...items, [activeContainer]: items[activeContainer].filter(item => item !== active.id), [overContainer]: [...items[overContainer].slice(0, newIndex), items[activeContainer][activeIndex], ...items[overContainer].slice(newIndex, items[overContainer].length)] }; }); } }, onDragEnd: ({ active, over }) => { // 容器拖拽 if (active.id in items && over?.id) { setContainers(containers => { const activeIndex = containers.indexOf(active.id); const overIndex = containers.indexOf(over.id); return (0, _sortable.arrayMove)(containers, activeIndex, overIndex); }); } const activeContainer = findContainer(active.id); if (!activeContainer) { setActiveId(null); return; } const overId = over?.id; if (overId == null) { setActiveId(null); return; } if (overId === TRASH_ID) { console.log('TRASH_ID', overId); setItems(items => ({ ...items, [activeContainer]: items[activeContainer].filter(id => id !== activeId) })); setActiveId(null); return; } const overContainer = findContainer(overId); if (overContainer) { const activeIndex = items[activeContainer].indexOf(active.id); const overIndex = items[overContainer].indexOf(overId); if (activeIndex !== overIndex) { const newItems = { ...items, [overContainer]: (0, _sortable.arrayMove)(items[overContainer], activeIndex, overIndex) }; // setItems(newItems); updateItems(newItems); } else { updateItems(items); } } setActiveId(null); }, cancelDrop: cancelDrop, onDragCancel: onDragCancel, modifiers: modifiers }, /*#__PURE__*/_react.default.createElement("div", { style: { display: 'flex', boxSizing: 'border-box' } }, topContainers.map(containerId => { return /*#__PURE__*/_react.default.createElement(DroppableContainer, { key: containerId, id: containerId, label: containerId === 'row' ? rowGroupTitle : colGroupTitle, columns: columns, items: items[containerId], scrollable: true, style: containerStyle, unstyled: false }, /*#__PURE__*/_react.default.createElement(_sortable.SortableContext, { items: items[containerId], strategy: _sortable.horizontalListSortingStrategy }, items[containerId].map((value, index) => { return /*#__PURE__*/_react.default.createElement(SortableItem, { disabled: isSortingContainer, key: value, id: value, index: index, handle: true, style: getItemStyles, wrapperStyle: wrapperStyle, renderItem: renderItem, containerId: containerId, getIndex: getIndex, onRemove: () => { updateItems(items, value); } }); }))); })), /*#__PURE__*/_react.default.createElement("div", { className: (0, _classnames.default)('dnd_table_container'), style: { display: 'flex', boxSizing: 'border-box', justifyContent: 'column' } }, /*#__PURE__*/_react.default.createElement(DroppableContainer, { key: tableContainer, id: tableContainer, columns: 1, items: items[tableContainer], scrollable: scrollable, style: containerStyle, unstyled: false, ulClassName: 'ulClassName', isNoneBorder: true }, /*#__PURE__*/_react.default.createElement(_sortable.SortableContext, { items: items[tableContainer], strategy: _sortable.horizontalListSortingStrategy }, /*#__PURE__*/_react.default.createElement("li", { style: { width: '100%' } }, children)))), /*#__PURE__*/(0, _reactDom.createPortal)( /*#__PURE__*/_react.default.createElement(_core.DragOverlay, { adjustScale: adjustScale, dropAnimation: dropAnimation }, activeId ? containers.includes(activeId) ? renderContainerDragOverlay(activeId) : renderSortableItemDragOverlay(activeId) : null), document.body), trashable && activeId && !containers.includes(activeId) ? /*#__PURE__*/_react.default.createElement(Trash, { id: TRASH_ID }) : null); function renderSortableItemDragOverlay(id) { return /*#__PURE__*/_react.default.createElement(_Item.Item, { value: id, handle: handle, style: getItemStyles({ containerId: findContainer(id), overIndex: -1, index: getIndex(id), value: id, isSorting: true, isDragging: true, isDragOverlay: true }), color: getColor(id), wrapperStyle: wrapperStyle({ index: 0 }), renderItem: renderItem, dragOverlay: true }); } function renderContainerDragOverlay(containerId) { return /*#__PURE__*/_react.default.createElement(_Container.Container, { label: `Column ${containerId}`, columns: columns, style: { height: '100%' }, shadow: true, unstyled: false }, items[containerId].map((item, index) => /*#__PURE__*/_react.default.createElement(_Item.Item, { key: item, value: item, handle: handle, style: getItemStyles({ containerId, overIndex: -1, index: getIndex(item), value: item, isDragging: false, isSorting: false, isDragOverlay: false }), color: getColor(item), wrapperStyle: wrapperStyle({ index }), renderItem: renderItem }))); } // function getNextContainerId() { // const containerIds = Object.keys(items); // const lastContainerId = containerIds[containerIds.length - 1]; // return String.fromCharCode(lastContainerId.charCodeAt(0) + 1); // } } function getColor(id) { switch (String(id)[0]) { case 'A': return '#7193f1'; case 'B': return '#ffda6c'; case 'C': return '#00bcd4'; case 'D': return '#ef769f'; } return undefined; } function Trash({ id }) { const { setNodeRef, isOver } = (0, _core.useDroppable)({ id }); return /*#__PURE__*/_react.default.createElement("div", { ref: setNodeRef, style: { display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'fixed', left: '50%', marginLeft: -150, bottom: 20, width: 300, height: 60, borderRadius: 5, border: '1px solid', borderColor: isOver ? 'red' : '#DDD' } }, "Drop here to delete"); } function SortableItem({ disabled, id, index, handle, renderItem, style, containerId, getIndex, wrapperStyle, onRemove }) { const { setNodeRef, listeners, isDragging, isSorting, over, overIndex, transform, transition } = (0, _sortable.useSortable)({ id }); const mounted = useMountStatus(); const mountedWhileDragging = isDragging && !mounted; return /*#__PURE__*/_react.default.createElement(_Item.Item, { ref: disabled ? undefined : setNodeRef, value: id, dragging: isDragging, sorting: isSorting, handle: handle, handleProps: undefined, index: index, wrapperStyle: wrapperStyle({ index }), style: style({ index, value: id, isDragging, isSorting, overIndex: over ? getIndex(over.id) : overIndex, containerId }), color: getColor(id), transition: transition, transform: transform, fadeIn: mountedWhileDragging, listeners: listeners, renderItem: renderItem, onRemove: onRemove }); } function useMountStatus() { const [isMounted, setIsMounted] = (0, _react.useState)(false); (0, _react.useEffect)(() => { const timeout = setTimeout(() => setIsMounted(true), 500); return () => clearTimeout(timeout); }, []); return isMounted; }