Last active
February 16, 2022 20:47
Revisions
-
Kris Urbas revised this gist
Oct 19, 2016 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -66,7 +66,7 @@ class App extends Component { <div className="select-wrap"> <SortableContainer> <Select options={items} value={this.state.selected.join(',')} multi={true} onChange={this.onChange} -
Kris Urbas created this gist
Oct 19, 2016 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,81 @@ import React, { Component } from 'react'; import Select from 'react-select' import SortableItem from './SortableItem'; import SortableContainer from './SortableContainer'; import update from 'react/lib/update'; const items = [ { value: '1', label: 'One' }, { value: '2', label: 'Two' }, { value: '3', label: 'Three' }, { value: '4', label: 'Four' }, { value: '5', label: 'Five' }, { value: '6', label: 'Six' }, { value: '7', label: 'Seven' }, { value: '8', label: 'Eight' }, { value: '9', label: 'Nine' }, ]; class App extends Component { constructor(props) { super(props); this.state = { selected: ['2','4','5','6'], items: items, }; this.onChange = this.onChange.bind(this); this.valueRenderer = this.valueRenderer.bind(this); this.swapItems = this.swapItems.bind(this); } onChange(allSelected) { this.setState({ selected: allSelected.map(item => item.value), }); } valueRenderer(option, index) { return ( <SortableItem index={index} className="sortable-item" swapItems={this.swapItems} > <span>{option.label}</span> </SortableItem> ); } swapItems(dragIndex, hoverIndex) { const dragItem = this.state.selected[dragIndex]; this.setState(update(this.state, { selected: { $splice: [ [dragIndex, 1], [hoverIndex, 0, dragItem] ] } })); } render() { return ( <div className="select-wrap"> <SortableContainer> <Select options={options} value={this.state.selected.join(',')} multi={true} onChange={this.onChange} valueRenderer={this.valueRenderer} /> </SortableContainer> </div> ); } } export default App; 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,15 @@ import React, { Component, PropTypes } from 'react'; import { DragDropContext } from 'react-dnd'; import HTML5Backend from 'react-dnd-html5-backend'; class SortableContainer extends Component { render() { return <span>{this.props.children}</span>; } } SortableContainer.propTypes = { children: PropTypes.oneOfType([PropTypes.element, PropTypes.array]), }; export default DragDropContext(HTML5Backend)(SortableContainer); 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,93 @@ import React, { Component, PropTypes } from 'react'; import { findDOMNode } from 'react-dom'; import { DragSource, DropTarget } from 'react-dnd'; const ITEM_TYPE = 'sortable'; class SortableItem extends Component { onMouseDown(event) { event.stopPropagation(); // important! as react-select preventsDefault on mouseDown event, preventing also dragging } render() { const { isDragging, connectDragSource, connectDropTarget, className, children } = this.props; const opacity = isDragging ? 0 : 1; return connectDropTarget(connectDragSource( <span className={className} style={{ opacity }} onMouseDown={this.onMouseDown} > {children} </span> )); } } SortableItem.propTypes = { // props from react-dnd connectDragSource: PropTypes.func.isRequired, connectDropTarget: PropTypes.func.isRequired, isDragging: PropTypes.bool.isRequired, // props provided by parent index: PropTypes.number.isRequired, children: PropTypes.element.isRequired, swapItems: PropTypes.func.isRequired, className: PropTypes.string, }; const source = { beginDrag(props) { return { index: props.index, }; }, }; const target = { hover(props, monitor, component) { const dragIndex = monitor.getItem().index; const hoverIndex = props.index; // implement your own behaviour, below example taken from http://gaearon.github.io/react-dnd/examples-sortable-simple.html if (dragIndex === hoverIndex) { return; } const hoverBoundingRect = findDOMNode(component).getBoundingClientRect(); const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; const clientOffset = monitor.getClientOffset(); const hoverClientY = clientOffset.y - hoverBoundingRect.top; if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) { return; } if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) { return; } // when you want to swap items run props.swapItems(dragIndex, hoverIndex); // note: we're mutating the monitor item here! monitor.getItem().index = hoverIndex; }, }; function mapDropConnectToProps(connect) { return { connectDropTarget: connect.dropTarget(), }; } function mapDragConnectToProps(connect, monitor) { return { connectDragSource: connect.dragSource(), isDragging: monitor.isDragging(), }; } export default DropTarget(ITEM_TYPE, target, mapDropConnectToProps)(DragSource(ITEM_TYPE, source, mapDragConnectToProps)(SortableItem));