Skip to content

Instantly share code, notes, and snippets.

@kavimaluskam
Created January 24, 2018 07:33
Show Gist options
  • Save kavimaluskam/19b9bd5d3ae1142c01aee52059abac21 to your computer and use it in GitHub Desktop.
Save kavimaluskam/19b9bd5d3ae1142c01aee52059abac21 to your computer and use it in GitHub Desktop.
React-DND & Material-ui-next: List Item
export default {
LIST_ITEM: 'listItem',
};
import React, {Component} from 'react';
import update from 'immutability-helper';
import {DragDropContext} from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import ReorderListItem from './ReorderListItem';
import {List} from 'material-ui';
class ReorderList extends Component {
constructor(props) {
super(props);
this.state = {
items: props.items && props.items.map(item => ({id: item, text: item})),
};
this.handleOnClick = this.handleOnClick.bind(this);
this.moveListItem = this.moveListItem.bind(this);
}
handleOnClick(item) {
// You may pass handle on click event to props
console.log(item);
}
moveListItem(dragIndex, hoverIndex) {
const {items} = this.state;
const dragitem = items[dragIndex];
this.setState(
update(this.state, {
items: {
$splice: [[dragIndex, 1], [hoverIndex, 0, dragitem]],
},
}),
);
// You may pass the state to props
console.log(this.state.items);
}
render() {
const {items} = this.state;
return (
<div>
<List>
{items.map((item, i) => (
<ReorderListItem
key={item.id}
handleOnClick={() => this.handleOnClick(item)}
index={i}
id={item.id}
text={item.text}
moveListItem={this.moveListItem}
/>
))}
</List>
</div>
);
}
}
export default DragDropContext(HTML5Backend)(ReorderList);
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import {findDOMNode} from 'react-dom';
import {DragSource, DropTarget} from 'react-dnd';
import ItemTypes from './ItemTypes';
import {ListItem} from 'material-ui';
const style = {
cursor: 'move',
};
const cardSource = {
beginDrag(props) {
return {
id: props.id,
index: props.index,
};
},
};
const cardTarget = {
hover(props, monitor, component) {
const dragIndex = monitor.getItem().index;
const hoverIndex = props.index;
// Don't replace items with themselves
if (dragIndex === hoverIndex) {
return;
}
// Determine rectangle on screen
const hoverBoundingRect = findDOMNode(component).getBoundingClientRect();
// Get vertical middle
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
// Determine mouse position
const clientOffset = monitor.getClientOffset();
// Get pixels to the top
const hoverClientY = clientOffset.y - 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.moveListItem(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;
},
};
const withDropTarget = DropTarget(ItemTypes.LIST_ITEM, cardTarget, connect => ({
connectDropTarget: connect.dropTarget(),
}));
const withDropSource = DragSource(ItemTypes.LIST_ITEM, cardSource, (connect, monitor) => ({
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging(),
}));
class ReorderListItem extends Component {
static propTypes = {
connectDragSource: PropTypes.func.isRequired,
connectDropTarget: PropTypes.func.isRequired,
handleOnClick: PropTypes.func.isRequired,
index: PropTypes.number.isRequired,
isDragging: PropTypes.bool.isRequired,
id: PropTypes.oneOfType([PropTypes.string.isRequired, PropTypes.number.isRequired]),
text: PropTypes.string.isRequired,
moveListItem: PropTypes.func.isRequired,
};
render() {
const {
text,
isDragging,
connectDragSource,
connectDropTarget,
// props for onClick selection
handleOnClick
//
} = this.props;
const opacity = isDragging ? 0 : 1;
return connectDragSource(
connectDropTarget(
<div style={{...style, opacity}}>
<ListItem onClick={handleOnClick}>{text}</ListItem>
</div>)
);
}
}
export default withDropTarget(withDropSource(ReorderListItem));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment