Created
August 30, 2016 00:53
-
-
Save jlroettger/2d6d7ae572f985fa176c27a63cadf292 to your computer and use it in GitHub Desktop.
React DND and Material UI - Reorderable List
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export ReorderableList from './ReorderableList' | |
export ReorderableListItem from './ReorderableListItem' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react' | |
import { Link } from 'react-router' | |
// Drag and Drop | |
import { DragDropContext } from 'react-dnd' | |
import HTML5Backend from 'react-dnd-html5-backend' | |
// Material UI | |
import { List } from 'material-ui/List' | |
import Subheader from 'material-ui/Subheader' | |
class ReorderableList extends Component { | |
constructor(props) { | |
super(props) | |
this.state = { | |
dndConstraint: this.props.dndConstraint || (Math.random() + 1).toString() | |
} | |
} | |
render() { | |
const { children, ...props } = this.props | |
const { dndConstraint } = this.state | |
return ( | |
<List { ...props }> | |
{React.Children.map(children, (child) => { | |
if (['div', Subheader, Link].includes(child.type)) return child | |
return React.cloneElement(child, { listIdentifier: dndConstraint }) | |
})} | |
</List> | |
); | |
} | |
} | |
export default DragDropContext(HTML5Backend)(ReorderableList) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component, PropTypes } from 'react' | |
// Drag and Drop | |
import { findDOMNode } from 'react-dom' | |
import { DragSource, DropTarget } from 'react-dnd' | |
// Material UI | |
import { ListItem } from 'material-ui/List' | |
import { fade } from 'material-ui/utils/colorManipulator' | |
const itemSource = { | |
beginDrag(props) { | |
let { id, index } = props | |
return { | |
id, | |
index | |
} | |
} | |
} | |
const itemTarget = { | |
hover(props, monitor, component) { | |
let { id: dragId, index: dragIndex } = monitor.getItem() | |
let { id: hoverId, index: hoverIndex } = props | |
if (dragIndex === hoverIndex) return; // Don't replace items with themselves | |
let hoveringOffsets = findDOMNode(component).getBoundingClientRect() | |
let penPercent = 0.50 // Percentage distance into next item before swap | |
let penMin = (hoveringOffsets.bottom - hoveringOffsets.top) * penPercent | |
let clientOffset = monitor.getClientOffset() | |
let penY | |
// Dragging downwards | |
if (dragIndex < hoverIndex) penY = clientOffset.y - hoveringOffsets.top | |
// Dragging upwards | |
if (dragIndex > hoverIndex) penY = hoveringOffsets.bottom - clientOffset.y | |
if ( !(penY > penMin) ) return // Exit it haven't penetrated enough | |
// Time to actually perform the action | |
props.moveItem({ dragId, dragIndex, hoverId, 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 dndType = props => props.listIdentifier || 'reorderableListItem' | |
class ReorderableListItem extends Component { | |
static contextTypes = { | |
muiTheme: PropTypes.object.isRequired | |
} | |
componentDidMount() { | |
// Does not work in IE | |
const img = new Image(); | |
img.onload = () => this.props.connectDragPreview(img); | |
// Single transparent pixel | |
img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' | |
} | |
render() { | |
const textColor = this.context.muiTheme.baseTheme.palette.textColor; | |
const { | |
children, | |
connectDragSource, | |
connectDropTarget, | |
isDragging, | |
style, | |
// eslint-disable-next-line no-unused-vars | |
index, moveReport, renameReport, moveItem, connectDragPreview, // omit pass hackAutoComplete | |
...props | |
} = this.props | |
return connectDragSource(connectDropTarget( | |
<div> | |
<ListItem | |
{ ...props } | |
style={{ | |
...style, | |
backgroundColor: isDragging && fade(textColor, 0.4), | |
cursor: isDragging && 'move' | |
}} | |
> | |
{children} | |
</ListItem> | |
</div> | |
)) | |
} | |
} | |
const connectTarget = connect => ({ | |
connectDropTarget: connect.dropTarget() | |
}) | |
const connectSource = (connect, monitor) => ({ | |
connectDragSource: connect.dragSource(), | |
connectDragPreview: connect.dragPreview(), | |
isDragging: monitor.isDragging() | |
}) | |
export default ( | |
DropTarget(dndType, itemTarget, connectTarget)( | |
DragSource(dndType, itemSource, connectSource)( | |
ReorderableListItem | |
) | |
) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
We can try below:
https://gist.github.com/kavimaluskam/19b9bd5d3ae1142c01aee52059abac21