Last active
June 27, 2017 03:16
-
-
Save aschmoe/5cf05ebec29d140f9bf0ad2c31d6a3cb to your computer and use it in GitHub Desktop.
Integrating react-select with react-sortable-hoc (ripped out mobx code, so possible its not entirely functional)
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 { PropTypes as PT } from 'prop-types'; | |
import { | |
SortableHandle, | |
SortableElement, | |
SortableContainer | |
} from 'react-sortable-hoc'; | |
/** | |
* Draggable handle wraps the label | |
*/ | |
const DragHandle = SortableHandle(({ children }) => <span>{children}</span>); | |
DragHandle.propTypes = { | |
children: PT.node, | |
}; | |
/** | |
* Sortable wrapper for item, mirrors the Value component | |
* https://github.com/JedWatson/react-select/blob/master/src/Value.js | |
*/ | |
const DraggableItem = SortableElement(({ id, value, children, onRemove }) => { | |
let dragging = false; | |
const removeIt = (event) => { | |
event.preventDefault(); | |
event.stopPropagation(); | |
onRemove(value); | |
}; | |
const handleTouchEndRemove = (event) => { | |
// Check if the view is being dragged, In this case | |
// we don't want to fire the click event (because the user only wants to scroll) | |
if (dragging) return; | |
// Fire the mouse events | |
removeIt(event); | |
}; | |
const handleTouchMove = () => { | |
// Set a flag that the view is being dragged | |
dragging = true; | |
}; | |
const handleTouchStart = () => { | |
// Set a flag that the view is not being dragged | |
dragging = false; | |
}; | |
return ( | |
<div className='Select-value'> | |
<span className="Select-value-icon" | |
aria-hidden="true" | |
onMouseDown={removeIt} | |
onTouchEnd={handleTouchEndRemove} | |
onTouchStart={handleTouchStart} | |
onTouchMove={handleTouchMove}> | |
× | |
</span> | |
<span className="Select-value-label" role="option" aria-selected="true" id={id}> | |
{children} | |
</span> | |
</div> | |
); | |
}); | |
DraggableItem.propTypes = { | |
id: PT.string, | |
value: PT.object, | |
onRemove: PT.func, | |
children: PT.node, | |
}; | |
/** | |
* Hacky wrapping element necessary to pull index to pass to SortableElement | |
*/ | |
const DraggableItemWrap = ({ id, ...props }) => { | |
let index = 0; | |
id.replace(/.*?-value-(.*)?$/igm, (m, p1) => { | |
index = parseInt(p1, 10); | |
}); | |
return <DraggableItem id={id} index={index} {...props} />; | |
}; | |
DraggableItemWrap.propTypes = { | |
children: PT.node, | |
disabled: PT.bool, // disabled prop passed to ReactSelect | |
id: PT.string, // Unique id for the value - used for aria | |
onClick: PT.func, // method to handle click on value label | |
onRemove: PT.func, // method to handle removal of the value | |
value: PT.object.isRequired, // the option object for this value | |
}; | |
/** | |
* Sortable wrapper for list | |
*/ | |
const DraggableList = SortableContainer(({ children }) => children); | |
DraggableList.propTypes = { | |
children: PT.node, | |
}; | |
export { | |
DragHandle, | |
DraggableItemWrap, | |
DraggableList, | |
}; |
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 { PropTypes as PT } from 'prop-types'; | |
import ReactSelect from 'react-select'; | |
import 'react-select/dist/react-select.css'; | |
import { arrayMove } from 'react-sortable-hoc'; | |
import { | |
DragHandle, | |
DraggableItemWrap, | |
DraggableList | |
} from './DraggableWrappers'; | |
import './style.scss' | |
/** | |
* Draggable react select | |
*/ | |
class InputDraggableSelect extends Component { | |
valueRenderer = option => ( | |
<DragHandle>{option.label}</DragHandle> | |
) | |
// Function for setting array on drag | |
onSortEnd = ({ oldIndex, newIndex }) => { | |
this.props.updateOrder(arrayMove(this.props.value, oldIndex, newIndex)); | |
} | |
render() { | |
const { creatable, value } = this.props; | |
return ( | |
<DraggableList axis="xy" | |
shouldCancelStart={() => value && value.length < 2} | |
onSortEnd={props => this.onSortEnd(props)} | |
useDragHandle={true} | |
helperClass="draggable-dragging"> | |
{creatable ? ( | |
<ReactSelect.Creatable {...this.props} | |
value={value} | |
multi={true} | |
valueRenderer={this.valueRenderer} | |
valueComponent={DraggableItemWrap} /> | |
) : ( | |
<ReactSelect {...this.props} | |
value={value} | |
multi={true} | |
valueRenderer={this.valueRenderer} | |
valueComponent={DraggableItemWrap} /> | |
)} | |
</DraggableList> | |
); | |
} | |
} | |
InputDraggableSelect.propTypes = { | |
updateOrder: PT.func.isRequired, // Changes order of sort | |
onChange: PT.func.isRequired, // Change value | |
value: PT.array, | |
creatable: PT.bool, | |
}; | |
export default InputDraggableSelect; |
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
{ | |
"dependencies": { | |
"prop-types": "^15.5.4", | |
"react": "^15.5.4", | |
"react-dom": "^15.5.4", | |
"react-input-autosize": "1.1.0", | |
"react-select": "^1.0.0-rc.3", | |
"react-sortable-hoc": "^0.6.3" | |
} | |
} |
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
// Item while dragging | |
.draggable-dragging { | |
box-shadow: 0 5px 5px -5px rgba(0, 0, 0, 0.2), 0 -5px 5px -5px rgba(0, 0, 0, 0.2); | |
background-color: rgba(255, 255, 255, 0.8); | |
cursor: row-resize; | |
z-index: 10; | |
* { | |
-webkit-touch-callout: none; | |
user-select: none; | |
} | |
label, p { | |
text-align: left; | |
} | |
} | |
// Replicate styles for the dragging state | |
$select-item-border-radius: 2px !default; | |
$select-item-gutter: 5px !default; | |
$select-item-padding-vertical: 2px !default; | |
$select-item-padding-horizontal: 5px !default; | |
$select-item-font-size: .9em !default; | |
$select-item-color: #08c !default; // pale blue | |
$select-item-bg: #f2f9fc !default; | |
$select-item-border-color: darken($select-item-bg, 10%) !default; | |
$select-item-hover-color: darken($select-item-color, 5%) !default; // pale blue | |
$select-item-hover-bg: darken($select-item-bg, 5%) !default; | |
$select-item-disabled-color: #333 !default; | |
$select-item-disabled-bg: #fcfcfc !default; | |
$select-item-disabled-border-color: darken($select-item-disabled-bg, 10%) !default; | |
.Select-value { | |
&.draggable-dragging { | |
background-color: $select-item-bg; | |
border-radius: $select-item-border-radius; | |
border: 1px solid $select-item-border-color; | |
color: $select-item-color; | |
display: inline-block; | |
font-size: $select-item-font-size; | |
line-height: 1.4; | |
margin-left: $select-item-gutter; | |
margin-top: $select-item-gutter; | |
vertical-align: top; | |
// common | |
.Select-value-icon, | |
.Select-value-label { | |
display: inline-block; | |
vertical-align: middle; | |
box-sizing: border-box; | |
float: left; | |
} | |
// label | |
.Select-value-label { | |
border-bottom-right-radius: $select-item-border-radius; | |
border-top-right-radius: $select-item-border-radius; | |
cursor: default; | |
padding: $select-item-padding-vertical 0 $select-item-padding-vertical $select-item-padding-horizontal; | |
} | |
// icon | |
.Select-value-icon { | |
cursor: pointer; | |
border-bottom-left-radius: $select-item-border-radius; | |
border-top-left-radius: $select-item-border-radius; | |
border-right: 1px solid $select-item-border-color; | |
// move the baseline up by 1px | |
padding: ($select-item-padding-vertical - 1) $select-item-padding-horizontal ($select-item-padding-vertical + 1); | |
&:hover, | |
&:focus { | |
background-color: $select-item-hover-bg; | |
color: $select-item-hover-color; | |
} | |
&:active { | |
background-color: $select-item-border-color; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment