UNPKG

azure-devops-ui

Version:

React components for building web UI in Azure DevOps

169 lines (168 loc) 7.78 kB
import "../../CommonImports"; import "../../Core/core.css"; import "./DropdownList.css"; import "./List.css"; import "./ListDropIndicator.css"; import * as React from "react"; import { getPointByEventType } from '../../Util'; import { DragDropEffect } from '../../Utilities/DragDrop'; import { cellFromEvent } from "./List"; import { ListDropIndicator } from "./ListDropIndicator"; import { ListDropIndicatorPosition } from "./ListDropIndicator.Props"; /** * A behavior that turns a list into the target of a drag and drop operation. Note - this * behavior should only be used if your list is intended to _only_ be a drop target. Please use * the ListDragDropBehavior instead if the list is also a drag source, as that is the only way * to get keyboard drag and drop support within your list. */ export class ListDropTargetBehavior { constructor(options) { this.initialize = (props, dragDroppableUI, eventDispatch) => { this.dragDroppableUI = dragDroppableUI; this.eventDispatch = eventDispatch; this.eventDispatch.addEventListener("dragenter", this.onDragEnter); this.eventDispatch.addEventListener("dragexit", this.onDragExit); this.eventDispatch.addEventListener("dragover", this.onDragOver); this.eventDispatch.addEventListener("drop", this.onDrop); this.itemProvider = props.itemProvider; this.indicatorName = this.options.isTree ? "tree-drop-indicator" : "drop-indicator"; }; this.onDragEnter = (event) => { if (!this.handlesType(event)) { return; } if (this.options.onDragEnter) { this.options.onDragEnter(event); } else { event.detail.dataTransfer.dropEffect = DragDropEffect.move; } }; this.onDragExit = (event) => { if (!this.handlesType(event)) { return; } if (this.options.onDragExit) { this.options.onDragExit(event); } this.dragDroppableUI.removeOverlay(this.indicatorName); }; this.onDragOver = (event) => { if (!this.handlesType(event)) { return; } let index = this.calculateIndex(event); const dragIndex = event.detail.dataTransfer.secondaryData.index; const listId = event.detail.dataTransfer.secondaryData.sourceId; let resultFromDragOver; if (index >= 0 && (index !== dragIndex || listId !== this.options.id || this.options.isTree)) { if (this.options.onDragOver) { resultFromDragOver = this.options.onDragOver(event, { index: this.listIndicatorPosition === ListDropIndicatorPosition.bottom ? index + 1 : index }); if (typeof (resultFromDragOver) === "number") { index = resultFromDragOver; } } else { event.detail.dataTransfer.dropEffect = DragDropEffect.move; } } else { event.detail.dataTransfer.dropEffect = DragDropEffect.none; } if (event.detail.dataTransfer.dropEffect === DragDropEffect.none) { this.dragDroppableUI.removeOverlay(this.indicatorName); } else { if (typeof (resultFromDragOver) === "number") { this.listIndicatorPosition = ListDropIndicatorPosition.bottom; } this.dragDroppableUI.addOverlay(this.indicatorName, index, this.renderDropIndicator); } }; this.onDrop = (event) => { if (!this.handlesType(event)) { return; } const index = this.calculateIndex(event); const dragIndex = event.detail.dataTransfer.secondaryData.index; const listId = event.detail.dataTransfer.secondaryData.sourceId; if (index >= 0 && (index !== dragIndex || listId !== this.options.id) && this.options.onDrop) { this.options.onDrop(event, { index: this.listIndicatorPosition === ListDropIndicatorPosition.bottom ? index + 1 : index }); } this.dragDroppableUI.removeOverlay(this.indicatorName); }; this.renderDropIndicator = (props) => { return this.options.isTree ? (React.createElement("div", { className: "bolt-list-tree-drop-target flex-grow" })) : (React.createElement(ListDropIndicator, { position: this.listIndicatorPosition })); }; this.options = options; } componentDidUpdate(props) { this.itemProvider = props.itemProvider; } componentWillUnmount() { var _a, _b, _c; (_a = this.eventDispatch) === null || _a === void 0 ? void 0 : _a.removeEventListener("dragenter", this.onDragEnter); (_b = this.eventDispatch) === null || _b === void 0 ? void 0 : _b.removeEventListener("dragexit", this.onDragExit); (_c = this.eventDispatch) === null || _c === void 0 ? void 0 : _c.removeEventListener("dragover", this.onDragOver); } showIndicator(index, position) { if (position) { this.listIndicatorPosition = position; } this.dragDroppableUI.addOverlay(this.indicatorName, index, this.renderDropIndicator); } hideIndicator() { this.dragDroppableUI.removeOverlay(this.indicatorName); } setListIndicatorPosition(listIndicatorPosition) { this.listIndicatorPosition = listIndicatorPosition; } calculateIndex(event) { const cell = cellFromEvent(event); let index = cell.rowIndex; if (this.options.isTree) { return index; } if (cell.rowElement && event.detail.dataTransfer.secondaryData) { const dragIndex = event.detail.dataTransfer.secondaryData.index; const listId = event.detail.dataTransfer.secondaryData.sourceId; const nativeEvent = event.detail.nativeEvent; const rowRect = cell.rowElement.getBoundingClientRect(); const point = getPointByEventType(nativeEvent); const topHalfOfRow = point ? point.y < rowRect.height / 2 + rowRect.top : index < dragIndex; if (this.options.id !== listId) { this.listIndicatorPosition = ListDropIndicatorPosition.top; if (!topHalfOfRow) { index++; } if (index >= this.itemProvider.length) { this.listIndicatorPosition = ListDropIndicatorPosition.bottom; index--; } } else { if (index < dragIndex) { this.listIndicatorPosition = ListDropIndicatorPosition.top; if (!topHalfOfRow) { index++; } } else if (index > dragIndex) { this.listIndicatorPosition = ListDropIndicatorPosition.bottom; if (topHalfOfRow) { index--; } } // No-op if index === dragIndex } } return index; } handlesType(event) { var _a; const type = ((_a = event.detail.dataTransfer) === null || _a === void 0 ? void 0 : _a.type) || ""; return this.options.allowedTypes.indexOf(type) !== -1; } }