diff --git a/package.json b/package.json index 82dc7a44587a..a1fd868cc3dd 100644 --- a/package.json +++ b/package.json @@ -154,7 +154,7 @@ "react-router-dom": "^4.2.2", "react-router-redux": "^5.0.0-alpha.6", "react-sidebar": "^2.2.1", - "react-sortable": "^1.2.0", + "react-sortable-hoc": "^0.6.8", "react-split-pane": "^0.1.66", "react-toolbox": "^2.0.0-beta.12", "react-topbar-progress-indicator": "^1.0.0", diff --git a/src/components/Widgets/ListControl.css b/src/components/Widgets/ListControl.css index 72aaa7dcc01a..4a28af7a170a 100644 --- a/src/components/Widgets/ListControl.css +++ b/src/components/Widgets/ListControl.css @@ -52,7 +52,6 @@ .nc-listControl-item { position: relative; padding-left: 24px; - cursor: move; } .nc-listControl-objectLabel { @@ -65,14 +64,6 @@ display: none; } -.nc-listControl-objectControl { - display: block; - border-top: 28px solid rgba(0,0,0,0.1); - border-top-left-radius: 0; -} - -.nc-listControl-expanded {} - .nc-listControl-collapsed { & .nc-listControl-objectLabel { display: block; @@ -83,9 +74,21 @@ } .nc-listControl-dragIcon { + cursor: move; + display: block; position: absolute; + text-align: center; top: 2px; - display: block; width: 100%; - text-align: center; + z-index: 1; } + +/** + * Styles for objects nested within lists. + */ +.nc-listControl-item .nc-listControl-objectControl { + display: block; + border-top: 28px solid rgba(0,0,0,0.1); + border-top-left-radius: 0; +} + diff --git a/src/components/Widgets/ListControl.js b/src/components/Widgets/ListControl.js index ddf6ece6f363..33e2f7cd19d6 100644 --- a/src/components/Widgets/ListControl.js +++ b/src/components/Widgets/ListControl.js @@ -1,12 +1,12 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; import { List, Map, fromJS } from 'immutable'; -import { sortable } from 'react-sortable'; +import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc'; import FontIcon from 'react-toolbox/lib/font_icon'; import ObjectControl from './ObjectControl'; function ListItem(props) { - return
{props.children}
; + return
{props.children}
; } ListItem.propTypes = { className: PropTypes.string, @@ -18,7 +18,12 @@ function valueToString(value) { return value ? value.join(',').replace(/,([^\s]|$)/g, ', $1') : ''; } -const SortableListItem = sortable(ListItem); +const SortableListItem = SortableElement(ListItem); +const DragHandle = SortableHandle( + () => +); +const SortableList = SortableContainer(({ items, renderItem }) => + (
{items.map(renderItem)}
)); const valueTypes = { SINGLE: 'SINGLE', @@ -38,7 +43,7 @@ export default class ListControl extends Component { constructor(props) { super(props); - this.state = { itemStates: Map(), value: valueToString(props.value) }; + this.state = { itemsCollapsed: List(), value: valueToString(props.value) }; this.valueType = null; } @@ -110,9 +115,9 @@ export default class ListControl extends Component { handleToggle(index) { return (e) => { e.preventDefault(); - const { itemStates } = this.state; + const { itemsCollapsed } = this.state; this.setState({ - itemStates: itemStates.setIn([index, 'collapsed'], !itemStates.getIn([index, 'collapsed'])), + itemsCollapsed: itemsCollapsed.set(index, !itemsCollapsed.get(index, false)), }); }; } @@ -126,55 +131,60 @@ export default class ListControl extends Component { return value || `No ${ labelField.get('name') }`; } - handleSort = (obj) => { - this.setState({ draggingIndex: obj.draggingIndex }); - if ('items' in obj) { - this.props.onChange(fromJS(obj.items)); - } + onSortEnd = ({ oldIndex, newIndex }) => { + const { value, onChange } = this.props; + + // Update value + const item = value.get(oldIndex); + const newValue = value.delete(oldIndex).insert(newIndex, item); + this.props.onChange(newValue); + + // Update collapsing + const { itemsCollapsed } = this.state; + const collapsed = itemsCollapsed.get(oldIndex); + const newItemsCollapsed = itemsCollapsed.delete(oldIndex).insert(newIndex, collapsed); + this.setState({ itemsCollapsed: newItemsCollapsed }); }; - renderItem(item, index) { - const { value, field, getAsset, onAddAsset, onRemoveAsset } = this.props; - const { itemStates } = this.state; - const collapsed = itemStates.getIn([index, 'collapsed']); - const classNames = ['nc-listControl-item', collapsed ? 'nc-listControl-collapsed' : 'nc-listControl-expanded']; - - return ( -
- - - -
{this.objectLabel(item)}
- -
+ renderItem = (item, index) => { + const { field, getAsset, onAddAsset, onRemoveAsset } = this.props; + const { itemsCollapsed } = this.state; + const collapsed = itemsCollapsed.get(index); + const classNames = ['nc-listControl-item', collapsed ? 'nc-listControl-collapsed' : '']; + + return ( + + + +
{this.objectLabel(item)}
+
); - } + }; renderListControl() { const { value, forID, field } = this.props; const listLabel = field.get('label'); return (
- {value && value.map((item, index) => this.renderItem(item, index))} +