diff --git a/examples/src/app.js b/examples/src/app.js
index ba23d8954b..d48ff7fabb 100644
--- a/examples/src/app.js
+++ b/examples/src/app.js
@@ -11,6 +11,7 @@ import GithubUsers from './components/GithubUsers';
import CustomComponents from './components/CustomComponents';
import CustomRender from './components/CustomRender';
import Multiselect from './components/Multiselect';
+import MultiselectSortable from './components/MultiselectSortable';
import NumericSelect from './components/NumericSelect';
import BooleanSelect from './components/BooleanSelect';
import Virtualized from './components/Virtualized';
@@ -20,6 +21,7 @@ ReactDOM.render(
+
diff --git a/examples/src/components/MultiselectSortable.js b/examples/src/components/MultiselectSortable.js
new file mode 100644
index 0000000000..1566800ca2
--- /dev/null
+++ b/examples/src/components/MultiselectSortable.js
@@ -0,0 +1,57 @@
+import React from 'react';
+import Select, { Value } from 'react-select';
+import { SortableContainer, SortableElement, SortableHandle, arrayMove } from 'react-sortable-hoc';
+
+const FLAVOURS = [
+ { label: 'Chocolate', value: 'chocolate' },
+ { label: 'Vanilla', value: 'vanilla' },
+ { label: 'Strawberry', value: 'strawberry' },
+ { label: 'Caramel', value: 'caramel' },
+ { label: 'Cookies and Cream', value: 'cookiescream' },
+ { label: 'Peppermint', value: 'peppermint' },
+];
+
+const SortableLabel = SortableHandle(({ label }) =>
{label});
+const SortableValue = SortableElement(Value);
+const SortableSelect = SortableContainer(Select);
+
+class MultiSelectSortableField extends React.Component{
+ constructor(){
+ super();
+ this.state = {
+ value: ['chocolate', 'vanilla', 'caramel']
+ };
+ }
+ handleSelectChange(value){
+ this.setState({ value });
+ }
+ onSortEnd({ oldIndex, newIndex }) {
+ this.setState({
+ value: arrayMove(this.state.value, oldIndex, newIndex),
+ });
+ }
+ render(){
+ const { value } = this.state;
+ return (
+
+
{this.props.label}
+ this.handleSelectChange(value)}
+ options={FLAVOURS}
+ placeholder="Select your favourite(s)"
+ value={value}
+ valueRenderer={(option) => }
+ valueComponent={SortableValue}
+ axis="xy"
+ helperClass="draggable-dragging"
+ onSortEnd={(sortState) => this.onSortEnd(sortState)}
+ useDragHandle={true}
+ />
+
+ );
+ }
+}
+MultiSelectSortableField.displayName = 'MultiSelectSortableField';
+
+module.exports = MultiSelectSortableField;
diff --git a/examples/src/example.less b/examples/src/example.less
index 801c1fc5d1..a93083e9c6 100644
--- a/examples/src/example.less
+++ b/examples/src/example.less
@@ -254,3 +254,94 @@ h6, .h6 {
.virtual-scroll {
z-index: 1;
}
+
+
+// Draggable item
+// ------------------------------
+
+// Replicate styles for the dragging state
+// @TODO need a better way to copy over style
+
+@select-item-border-radius: 2px;
+@select-item-gutter: 5px;
+@select-item-padding-vertical: 2px;
+@select-item-padding-horizontal: 5px;
+@select-item-font-size: .9em;
+@select-item-color: #08c; // pale blue
+@select-item-bg: #f2f9fc;
+@select-item-border-color: darken(@select-item-bg, 10%);
+@select-item-hover-color: darken(@select-item-color, 5%); // pale blue
+@select-item-hover-bg: darken(@select-item-bg, 5%);
+@select-item-disabled-color: #333;
+@select-item-disabled-bg: #fcfcfc;
+@select-item-disabled-border-color: darken(@select-item-disabled-bg, 10%);
+
+
+.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;
+ }
+ }
+ }
+}
+
+.draggable-dragging {
+ box-shadow: 0 2px 6px 0 rgba(0,0,0,.1);
+ background-color: rgba(255, 255, 255, 0.8);
+ cursor: row-resize;
+ z-index: 10;
+ border-radius: 5px;
+
+ * {
+ -webkit-touch-callout: none;
+ user-select: none;
+ }
+
+ label, p {
+ text-align: left;
+ }
+}
diff --git a/package.json b/package.json
index b689a04d98..007c9e1d62 100644
--- a/package.json
+++ b/package.json
@@ -56,6 +56,7 @@
"react-dom": "^15.5.0",
"react-gravatar": "^2.4.5",
"react-highlight-words": "^0.8.1",
+ "react-sortable-hoc": "^0.6.8",
"react-test-renderer": "^15.6.1",
"react-virtualized": "^9.9.0",
"react-virtualized-select": "^3.1.0",
@@ -88,7 +89,12 @@
"test": "cross-env NODE_ENV=test mocha --compilers js:babel-core/register",
"precommit": "lint-staged && yarn run test"
},
- "files": ["dist", "less", "lib", "scss"],
+ "files": [
+ "dist",
+ "less",
+ "lib",
+ "scss"
+ ],
"keywords": [
"combobox",
"form",
diff --git a/src/Select.js b/src/Select.js
index 75d25a7a66..c7852b508b 100644
--- a/src/Select.js
+++ b/src/Select.js
@@ -827,6 +827,7 @@ class Select extends React.Component {
onRemove={this.removeValue}
placeholder={this.props.placeholder}
value={value}
+ index={i}
>
{renderLabel(value, i)}