UNPKG

wix-style-react

Version:
523 lines (496 loc) • 17.3 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.default = exports.DropItemTarget = exports.DragItemSource = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _react = _interopRequireDefault(require("react")); var _reactDom = require("react-dom"); var _reactDnd = require("react-dnd"); var _itemTypes = _interopRequireDefault(require("./itemTypes")); var _utils = require("./utils"); var _NestableListBaseContext = require("./NestableListBaseContext"); var _DragUtils = require("../DragAndDrop/Draggable/DragUtils"); var _classnames = _interopRequireDefault(require("classnames")); var _constants = require("../DragAndDrop/Draggable/constants"); var _jsxFileName = "/home/builduser/work/a9c1ac8876d5057c/packages/wix-style-react/dist/cjs/NestableListBase/Item.js"; // keep track of horizontal mouse movement var mouse = { lastX: 0 }; function increaseHorizontalLevel(prevPosition, prevIndex) { var nextPosition = prevPosition.slice(0, -1); // append to prevSibling's children nextPosition.push(prevIndex - 1, -1); return nextPosition; } function decreaseHorizontalLevel(prevPosition) { var nextPosition = prevPosition.slice(0, -1); nextPosition[nextPosition.length - 1] += 1; return nextPosition; } function calculateHandleOffset(handleRect, containerRect) { return { x: handleRect.x - containerRect.x, y: handleRect.y - containerRect.y }; } var cardSource = { isDragging(props, monitor) { var ids = (0, _utils.getValuesByKey)(monitor.getItem().data, 'id', 'children'); return ids.indexOf(props.id) > -1; }, beginDrag(props, monitor, component) { props.onDragStart && props.onDragStart(props); var node = (0, _reactDom.findDOMNode)(component); var clientRect = node.getBoundingClientRect(); var handleOffset = { x: 0, y: 0 }; // needed to fix dnd drag offset data if (component.handleNode) { handleOffset = calculateHandleOffset(component.handleNode.getBoundingClientRect(), clientRect); } return { id: props.id, dragged: false, // needed for workaround of immediately fired dragend event after dragstart index: props.index, position: props.position, data: props.item, groupName: props.groupName, depth: props.depth, // rect for entire component including children clientRect, handleOffset }; }, endDrag: (props, monitor) => { mouse.lastX = 0; props.dropItem(monitor.getItem()); props.onDragEnd && props.onDragEnd(props); } }; var determineHorizontalPosition = _ref => { var { monitor, props, hoverNode } = _ref; var item = monitor.getItem(); // the item being dragged var { position: prevPosition, depth: dragDepth, index: prevIndex } = item; // props for component underneath drag var { position: hoverPosition, siblings: hoverSiblings, maxDepth, threshold } = props; // determine mouse position var clientOffset = monitor.getClientOffset() || { x: 0, y: 0 }; var initialClientOffset = monitor.getInitialClientOffset() || { x: 0, y: 0 }; // rect for entire component including children var hoverClientRect = hoverNode.getBoundingClientRect(); var isOverSelf = (0, _utils.hoverAboveItself)(prevPosition, hoverPosition); // set mouse.lastX if it isn't set yet (first hover event) mouse.lastX = mouse.lastX || initialClientOffset.x; var currMouseX = clientOffset.x; var mouseDistanceX = currMouseX - mouse.lastX; var nearLeftEdge = currMouseX < hoverClientRect.left + 10; var currentIndex = props.index; // nextPosition will be overwritten when moving horizontally var nextPosition = hoverPosition; // disable horizonal movement is previous sibling has lockDropArea=true prop if (isOverSelf && currentIndex !== 0 && !!hoverSiblings[currentIndex - 1].lockDropArea && mouseDistanceX > 0) { return nextPosition; } // disable horizonal movement is next sibling has lockDropArea=true prop if (isOverSelf && currentIndex < hoverSiblings.length - 2 && !!hoverSiblings[currentIndex + 1].lockDropArea && mouseDistanceX < 0) { return nextPosition; } // moving horizontally if (isOverSelf && (nearLeftEdge || Math.abs(mouseDistanceX) >= threshold)) { // reset lastX for new phase mouse.lastX = currMouseX; // increase horizontal level if (mouseDistanceX > 0 && // has previous sibling prevIndex - 1 >= 0 && // isn't at max depth prevPosition.length + dragDepth - 1 !== maxDepth) { nextPosition = increaseHorizontalLevel(prevPosition, prevIndex); } // decrease horizontal level if (mouseDistanceX < 0 && // is nested prevPosition.length > 1 && // is last item in array prevIndex === hoverSiblings.length - 1) { nextPosition = decreaseHorizontalLevel(prevPosition); } } if (props.preventChangeDepth && nextPosition.length - prevPosition.length === -1 // means that new parent is suitable for current dragged item ) { var isSameParent = nextPosition.every((position, depth) => { return prevPosition[depth] === position; }); if (!isSameParent) { nextPosition = prevPosition.map((position, depth) => { return nextPosition[depth] !== undefined ? nextPosition[depth] : 0; }); } } return nextPosition; }; var allowItemMove = _ref2 => { var { prevPosition, nextPosition, monitor, hoverNode, props } = _ref2; // don't replace items with themselves if ((0, _utils.hoverAboveItself)(prevPosition, nextPosition)) { return; } // prevent drop if preventChangeDepth and depth is changed if (props.preventChangeDepth && nextPosition.length !== prevPosition.length) { return; } var { position: hoverPosition } = props; var isOverSelf = (0, _utils.hoverAboveItself)(prevPosition, hoverPosition); var clientOffset = monitor.getClientOffset() || { x: 0, y: 0 }; // rect for entire component including children var hoverClientRect = hoverNode.getBoundingClientRect(); // rect for item without children var hoverItemClientRect = hoverNode.children[0].getBoundingClientRect(); // get vertical middle var hoverMiddleY = (hoverClientRect.bottom - hoverClientRect.top) / 2; // get pixels to the top var hoverClientY = clientOffset.y - hoverClientRect.top; // dragging child item to another position with same parent if (nextPosition.length === prevPosition.length) { var last = nextPosition.length - 1; var previousIndex = prevPosition[last]; var nextIndex = nextPosition[last]; // only perform the move when the mouse has crossed half of the items height // when dragging downwards, only move when the cursor is below 50% // when dragging upwards, only move when the cursor is above 50% // dragging downwards if (previousIndex < nextIndex && hoverClientY < hoverMiddleY) { return; } // dragging upwards if (previousIndex > nextIndex && hoverClientY > hoverMiddleY) { return; } } else if ( // dragging child item over parent item nextPosition.length < prevPosition.length && nextPosition[nextPosition.length - 1] === prevPosition[prevPosition.length - 2]) { var hoverItemMiddleY = (hoverItemClientRect.bottom - hoverItemClientRect.top) / 2; // cancel if hovering in lower half of parent item if (hoverClientY > hoverItemMiddleY) { return; } } else if (!isOverSelf && clientOffset.y > hoverItemClientRect.bottom) { // cancel if over a nested target that isn't its own child return; } return true; }; var cardTarget = { hover(props, monitor, component) { // prevent drag and drop between different groups. // currently drag and drop between multiple nestable lists is not supported if (monitor.getItem().groupName !== props.groupName) { return; } var item = monitor.getItem(); // the item being dragged var { position: prevPosition, data: dragItem, depth: dragDepth } = item; // props for component underneath drag var { position: hoverPosition, maxDepth } = props; var hoverDepth = hoverPosition.length - 1; var totalDepth = hoverDepth + dragDepth; // don't exceed max depth if (totalDepth > maxDepth) { return; } var hoverNode = (0, _reactDom.findDOMNode)(component); var nextPosition = determineHorizontalPosition({ monitor, props, hoverNode }); if (!allowItemMove({ prevPosition, nextPosition, monitor, hoverNode, props })) { return; } // this is where the actual move happens var nextPos = props.moveItem({ dragItem, prevPosition, nextPosition }); item.prevPosition = prevPosition; item.prevIndex = item.index; item.dragged = true; // note: we're mutating the monitor item here! // generally it's better to avoid mutations, // but it's good here for the sake of performance // to avoid expensive index searches item.position = nextPos; item.index = nextPos[nextPos.length - 1]; } }; class Item extends _react.default.PureComponent { constructor() { super(...arguments); this.state = { shouldRenderChildren: true }; this.unmounted = false; } componentWillUnmount() { this.unmounted = true; } componentDidMount() { // 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. this.props.connectDragPreview((0, _DragUtils.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 }); this.updateShouldRenderChildren(); } componentDidUpdate() { this.updateShouldRenderChildren(); } updateShouldRenderChildren() { var { isPlaceholder, isRenderDraggingChildren } = this.props; var shouldRenderChildren = !isPlaceholder || isRenderDraggingChildren; // start workaround of immediately fired dragend event after dragstart // https://github.com/react-dnd/react-dnd/issues/766#issuecomment-748255082 if (shouldRenderChildren !== this.state.shouldRenderChildren) { if (!this.props.dragged && this.state.shouldRenderChildren !== shouldRenderChildren) { setTimeout(() => { if (!this.unmounted) { this.setState({ shouldRenderChildren }); } }, 0); } else { this.setState({ shouldRenderChildren }); } } // end workaround of immediately fired dragend event after dragstart } render() { var { item, position, children, isPlaceholder, connectDragSource, connectDropTarget, useDragHandle, renderItem, renderPrefix, theme, readOnly, isVeryLastItem, siblings } = this.props; // params passed to renderItem callback var renderParams = { item, siblings, isVeryLastItem, isPlaceholder, isPreview: false, connectDragSource: () => {}, depth: position.length }; var draggableTargetDataProps = { [_constants.dataAttributes.draggableTarget]: true, 'data-hook': 'nestable-item' }; var renderItemWithDataAttributes = params => /*#__PURE__*/_react.default.cloneElement(renderItem(params), { [_constants.dataAttributes.draggableSource]: true, [_constants.dataAttributes.depth]: position.length - 1, [_constants.dataAttributes.id]: item.id }); var classes = (0, _classnames.default)('nestable-item', theme && theme.item); var { draggable = true, lockDropArea = false, isParentLocked = false } = item; if (!draggable || readOnly) { if (lockDropArea) { return /*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({ className: classes }, draggableTargetDataProps, { __self: this, __source: { fileName: _jsxFileName, lineNumber: 414, columnNumber: 11 } }), renderPrefix(renderParams), renderItemWithDataAttributes(renderParams), this.state.shouldRenderChildren && children); } if (isParentLocked && draggable && !readOnly) { return connectDragSource(/*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({ className: classes }, draggableTargetDataProps, { __self: this, __source: { fileName: _jsxFileName, lineNumber: 424, columnNumber: 11 } }), renderPrefix(renderParams), renderItemWithDataAttributes(renderParams), this.state.shouldRenderChildren && children)); } return /*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({ className: classes }, draggableTargetDataProps, { __self: this, __source: { fileName: _jsxFileName, lineNumber: 433, columnNumber: 9 } }), renderPrefix(renderParams), renderItemWithDataAttributes(renderParams), this.state.shouldRenderChildren && children); } if (useDragHandle) { renderParams.connectDragSource = handle => { var handleWithRef = /*#__PURE__*/_react.default.cloneElement(handle, { ref: node => this.handleNode = (0, _reactDom.findDOMNode)(node) }); return connectDragSource(handleWithRef); }; if (lockDropArea) { return connectDropTarget(/*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({ className: classes }, draggableTargetDataProps, { __self: this, __source: { fileName: _jsxFileName, lineNumber: 451, columnNumber: 11 } }), renderPrefix(renderParams), renderItemWithDataAttributes(renderParams), this.state.shouldRenderChildren && children)); } if (isParentLocked) { return connectDragSource(/*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({ className: classes }, draggableTargetDataProps, { __self: this, __source: { fileName: _jsxFileName, lineNumber: 461, columnNumber: 11 } }), renderPrefix(renderParams), renderItemWithDataAttributes(renderParams), this.state.shouldRenderChildren && children)); } return connectDropTarget(/*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({ className: classes }, draggableTargetDataProps, { __self: this, __source: { fileName: _jsxFileName, lineNumber: 470, columnNumber: 9 } }), renderPrefix(renderParams), renderItemWithDataAttributes(renderParams), this.state.shouldRenderChildren && children)); } if (isParentLocked) { return connectDragSource(/*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({ className: classes }, draggableTargetDataProps, { __self: this, __source: { fileName: _jsxFileName, lineNumber: 480, columnNumber: 9 } }), renderPrefix(renderParams), renderItemWithDataAttributes(renderParams), this.state.shouldRenderChildren && children)); } return connectDropTarget(connectDragSource(/*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({ className: classes }, draggableTargetDataProps, { __self: this, __source: { fileName: _jsxFileName, lineNumber: 490, columnNumber: 9 } }), renderPrefix(renderParams), renderItemWithDataAttributes(renderParams), this.state.shouldRenderChildren && children))); } } var DragItemSource = exports.DragItemSource = (0, _reactDnd.DragSource)(_itemTypes.default.nestedItem, cardSource, (connect, monitor) => ({ connectDragSource: connect.dragSource(), connectDragPreview: connect.dragPreview(), isPlaceholder: monitor.isDragging(), dragged: monitor.getItem() && monitor.getItem().dragged }))(Item); var DropItemTarget = exports.DropItemTarget = (0, _reactDnd.DropTarget)(_itemTypes.default.nestedItem, cardTarget, connect => ({ connectDropTarget: connect.dropTarget() }))(DragItemSource); class ItemWithContext extends _react.default.PureComponent { render() { return /*#__PURE__*/_react.default.createElement(_NestableListBaseContext.NestableListBaseContext.Consumer, { __self: this, __source: { fileName: _jsxFileName, lineNumber: 522, columnNumber: 7 } }, context => /*#__PURE__*/_react.default.createElement(DropItemTarget, (0, _extends2.default)({}, this.props, context, { __self: this, __source: { fileName: _jsxFileName, lineNumber: 523, columnNumber: 21 } }))); } } var _default = exports.default = ItemWithContext; //# sourceMappingURL=Item.js.map