UNPKG

@lonli-lokli/react-mosaic-component

Version:
157 lines (156 loc) 5.51 kB
// libs/react-mosaic-component/src/lib/DraggableTab.tsx import { useDrag } from "react-dnd"; import { isEqual } from "lodash-es"; import { MosaicDragType } from "./types.mjs"; import { createDragToUpdates } from "./util/mosaicUpdates.mjs"; import { getNodeAtPath, isTabsNode } from "./util/mosaicUtilities.mjs"; var DraggableTab = ({ tabKey, tabIndex, tabContainerPath, mosaicActions, mosaicId, children }) => { const tabPath = tabContainerPath.concat(tabIndex); const [{ isDragging }, connectDragSource, connectDragPreview] = useDrag({ type: MosaicDragType.WINDOW, item: () => { const hideTimer = window.setTimeout(() => { mosaicActions.hide(tabPath, true); }, 50); return { mosaicId, hideTimer, // Add additional properties for tab reordering isTab: true, tabIndex, tabKey, tabContainerPath }; }, end: (item, monitor) => { window.clearTimeout(item.hideTimer); const dropResult = monitor.getDropResult(); const didDrop = monitor.didDrop(); const ownPath = tabPath; const tabReorderIndex = dropResult?.tabReorderIndex; const isTabReorder = tabReorderIndex !== void 0 && dropResult?.path && isEqual(dropResult.path, tabContainerPath); const isTabToTabContainer = tabReorderIndex !== void 0 && dropResult?.path && !isEqual(dropResult.path, tabContainerPath); const isSelfDrop = dropResult?.path && isEqual(dropResult.path, tabContainerPath) && tabReorderIndex === void 0; const isChildDrop = dropResult?.path && dropResult.path.length > ownPath.length && isEqual(dropResult.path.slice(0, ownPath.length), ownPath); if (!didDrop || !dropResult || isChildDrop) { mosaicActions.show(ownPath, true); return; } if (isTabReorder) { const root = mosaicActions.getRoot(); const tabsNode = getNodeAtPath( root, tabContainerPath ); if (tabsNode && isTabsNode(tabsNode)) { const currentTabs = [...tabsNode.tabs]; const currentActiveTabIndex = tabsNode.activeTabIndex; const [movedTab] = currentTabs.splice(tabIndex, 1); const adjustedInsertIndex = tabIndex < tabReorderIndex ? tabReorderIndex - 1 : tabReorderIndex; currentTabs.splice(adjustedInsertIndex, 0, movedTab); let newActiveTabIndex = currentActiveTabIndex; if (tabIndex === currentActiveTabIndex) { newActiveTabIndex = adjustedInsertIndex; } else if (tabIndex < currentActiveTabIndex && adjustedInsertIndex >= currentActiveTabIndex) { newActiveTabIndex = currentActiveTabIndex - 1; } else if (tabIndex > currentActiveTabIndex && adjustedInsertIndex <= currentActiveTabIndex) { newActiveTabIndex = currentActiveTabIndex + 1; } mosaicActions.updateTree([ { path: tabContainerPath, spec: { tabs: { $set: currentTabs }, activeTabIndex: { $set: newActiveTabIndex } } } ]); } else { console.warn("Could not find tabs node at path:", tabContainerPath); } return; } if (isTabToTabContainer) { const root = mosaicActions.getRoot(); const destinationTabsNode = getNodeAtPath( root, dropResult.path ); if (destinationTabsNode && isTabsNode(destinationTabsNode)) { const sourceTabsNode = getNodeAtPath( root, tabContainerPath ); const currentSourceTabs = [...sourceTabsNode.tabs]; currentSourceTabs.splice(tabIndex, 1); const removeUpdates = [ { path: tabContainerPath, spec: { tabs: { $set: currentSourceTabs }, activeTabIndex: { $set: Math.max( 0, Math.min(tabIndex, sourceTabsNode.tabs.length - 2) ) } } } ]; const currentDestinationTabs = [...destinationTabsNode.tabs]; currentDestinationTabs.splice(tabReorderIndex, 0, tabKey); const insertUpdates = [ { path: dropResult.path, spec: { tabs: { $set: currentDestinationTabs }, activeTabIndex: { $set: tabReorderIndex } // Make the newly inserted tab active } } ]; mosaicActions.updateTree([...removeUpdates, ...insertUpdates]); } else { console.warn( "Could not find destination tabs node at path:", dropResult.path ); } return; } if (isSelfDrop || dropResult.path === void 0) { mosaicActions.show(ownPath, true); return; } const updates = createDragToUpdates( mosaicActions.getRoot(), ownPath, dropResult.path, dropResult.position === void 0 ? { type: "tab-container" } : { type: "split", position: dropResult.position } ); mosaicActions.updateTree(updates, { shouldNormalize: true }); }, collect: (monitor) => ({ isDragging: monitor.isDragging() }) }); return children({ isDragging, connectDragSource, connectDragPreview }); }; export { DraggableTab };