UNPKG

react-conventions

Version:

An open source set of React components that implement Ambassador's Design and UX patterns.

256 lines (211 loc) 9.19 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _reactDom = require('react-dom'); var _reactDnd = require('react-dnd'); var _reactDndHtml5Backend = require('react-dnd-html5-backend'); var _bind = require('classnames/bind'); var _bind2 = _interopRequireDefault(_bind); var _Badge = require('../Badge'); var _Badge2 = _interopRequireDefault(_Badge); var _Toggle = require('../Toggle'); var _Toggle2 = _interopRequireDefault(_Toggle); var _flow = require('lodash/flow'); var _flow2 = _interopRequireDefault(_flow); var _style = require('./style.scss'); var _style2 = _interopRequireDefault(_style); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var sortableItemSource = { beginDrag: function beginDrag(props) { props.onDragStart(); if (props.getDimensions) { props.getDimensions(); } return { value: props.value, text: props.text, active: props.active, index: props.index }; }, endDrag: function endDrag(props) { props.onDragStop(); } }; var sortableItemTarget = { hover: function hover(props, monitor, component) { var dragIndex = monitor.getItem().index; var hoverIndex = props.index; // Don't replace items with themselves if (dragIndex === hoverIndex) { return; } // Determine rectangle on screen var hoverBoundingRect = (0, _reactDom.findDOMNode)(component).getBoundingClientRect(); // Get vertical middle var hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; // Determine mouse position var clientOffset = monitor.getClientOffset(); // Get pixels to the top var hoverClientY = (clientOffset ? clientOffset.y : 0) - hoverBoundingRect.top; // 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 (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { return; } // Dragging upwards if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { return; } // Time to actually perform the action props.moveSortableItem(dragIndex, hoverIndex); // 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. monitor.getItem().index = hoverIndex; } }; var SortableItem = function (_React$Component) { _inherits(SortableItem, _React$Component); function SortableItem() { var _ref; var _temp, _this, _ret; _classCallCheck(this, SortableItem); for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = SortableItem.__proto__ || Object.getPrototypeOf(SortableItem)).call.apply(_ref, [this].concat(args))), _this), _this.state = { count: _this.props.count }, _this.componentWillReceiveProps = function (nextProps) { if (nextProps.count !== _this.state.count) { _this.setState({ count: nextProps.count }); } }, _this.toggleSortableItem = function () { _this.props.toggleSortableItem(_this.props.index); }, _this.render = function () { var cx = _bind2.default.bind(_style2.default); var _this$props = _this.props, text = _this$props.text, index = _this$props.index, active = _this$props.active, isDragging = _this$props.isDragging, connectDragSource = _this$props.connectDragSource, connectDropTarget = _this$props.connectDropTarget, canDrop = _this$props.canDrop; var opacity = isDragging ? 0 : 1; var badgeOpacity = _this.state.count > 1 ? 1 - 0.6 / (_this.state.count - 1) * index : 1; var sortableItemClasses = cx(_style2.default['sortable-item'], canDrop ? 'dragging' : '', !active ? 'inactive' : ''); return connectDropTarget(_react2.default.createElement( 'div', { style: { opacity: opacity }, className: sortableItemClasses }, _react2.default.createElement( 'div', { style: { opacity: badgeOpacity } }, _react2.default.createElement(_Badge2.default, { text: index + 1, theme: 'sky', optClass: _style2.default['sortable-item-badge'] }) ), _react2.default.createElement( 'span', null, text ), _react2.default.createElement( 'div', { className: _style2.default.actions }, _react2.default.createElement(_Toggle2.default, { value: active, optClass: _style2.default.toggle, changeCallback: _this.toggleSortableItem }), connectDragSource(_react2.default.createElement( 'div', { className: _style2.default.handle }, _react2.default.createElement('span', null), _react2.default.createElement('span', null), _react2.default.createElement('span', null), _react2.default.createElement('span', null) )) ) )); }, _temp), _possibleConstructorReturn(_this, _ret); } _createClass(SortableItem, [{ key: 'componentDidMount', value: function 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, _reactDndHtml5Backend.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 }); } }]); return SortableItem; }(_react2.default.Component); SortableItem.propTypes = { /** * Binds to react-dnd connectDragSource method. */ connectDragSource: _react2.default.PropTypes.func, /** * Binds to react-dnd connectDropTarget method. */ connectDropTarget: _react2.default.PropTypes.func, /** * Binds to react-dnd connectDragPreview method. */ connectDragPreview: _react2.default.PropTypes.func, /** * Index of the item in the list. */ index: _react2.default.PropTypes.number, /** * Whether the item is being dragged. */ isDragging: _react2.default.PropTypes.bool, /** * The value of the item. */ value: _react2.default.PropTypes.any, /** * The text to display inside the item. */ text: _react2.default.PropTypes.string, /** * Whether the item is active. */ active: _react2.default.PropTypes.bool, /** * A callback that gets triggered when the item is moved. */ moveSortableItem: _react2.default.PropTypes.func, /** * A callback that gets triggered when the item is toggled. */ toggleSortableItem: _react2.default.PropTypes.func, /** * The total number of items in the list. */ count: _react2.default.PropTypes.number }; SortableItem.defaultProps = { active: false }; exports.default = (0, _flow2.default)((0, _reactDnd.DragSource)('item', sortableItemSource, function (connect, monitor) { return { connectDragSource: connect.dragSource(), connectDragPreview: connect.dragPreview(), isDragging: monitor.isDragging() }; }), (0, _reactDnd.DropTarget)('item', sortableItemTarget, function (connect, monitor) { return { connectDropTarget: connect.dropTarget(), canDrop: monitor.canDrop() }; }))(SortableItem);