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
JavaScript
;
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);