feat(relation-widget): enable reordering for relation controls (#5873)
This commit is contained in:
@ -23,7 +23,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react-select": "^4.0.0",
|
"react-select": "^4.0.0",
|
||||||
"react-window": "^1.8.5"
|
"react-window": "^1.8.5",
|
||||||
|
"react-sortable-hoc": "^2.0.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@emotion/core": "^10.0.35",
|
"@emotion/core": "^10.0.35",
|
||||||
|
@ -1,12 +1,35 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import { components } from 'react-select';
|
||||||
import AsyncSelect from 'react-select/async';
|
import AsyncSelect from 'react-select/async';
|
||||||
import { find, isEmpty, last, debounce, get, uniqBy } from 'lodash';
|
import { debounce, find, get, isEmpty, last, uniqBy } from 'lodash';
|
||||||
import { List, Map, fromJS } from 'immutable';
|
import { fromJS, List, Map } from 'immutable';
|
||||||
import { reactSelectStyles } from 'netlify-cms-ui-default';
|
import { reactSelectStyles } from 'netlify-cms-ui-default';
|
||||||
import { stringTemplate, validations } from 'netlify-cms-lib-widgets';
|
import { stringTemplate, validations } from 'netlify-cms-lib-widgets';
|
||||||
import { FixedSizeList } from 'react-window';
|
import { FixedSizeList } from 'react-window';
|
||||||
|
import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
|
||||||
|
|
||||||
|
function arrayMove(array, from, to) {
|
||||||
|
const slicedArray = array.slice();
|
||||||
|
slicedArray.splice(to < 0 ? array.length + to : to, 0, slicedArray.splice(from, 1)[0]);
|
||||||
|
return slicedArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MultiValue = SortableElement(props => {
|
||||||
|
// prevent the menu from being opened/closed when the user clicks on a value to begin dragging it
|
||||||
|
function onMouseDown(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
const innerProps = { ...props.innerProps, onMouseDown };
|
||||||
|
return <components.MultiValue {...props} innerProps={innerProps} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
const MultiValueLabel = SortableHandle(props => <components.MultiValueLabel {...props} />);
|
||||||
|
|
||||||
|
const SortableSelect = SortableContainer(AsyncSelect);
|
||||||
|
|
||||||
function Option({ index, style, data }) {
|
function Option({ index, style, data }) {
|
||||||
return <div style={style}>{data.options[index]}</div>;
|
return <div style={style}>{data.options[index]}</div>;
|
||||||
@ -164,6 +187,24 @@ export default class RelationControl extends React.Component {
|
|||||||
this.mounted = false;
|
this.mounted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onSortEnd =
|
||||||
|
options =>
|
||||||
|
({ oldIndex, newIndex }) => {
|
||||||
|
const { onChange, field } = this.props;
|
||||||
|
const value = options.map(optionToString);
|
||||||
|
const newValue = arrayMove(value, oldIndex, newIndex);
|
||||||
|
const metadata =
|
||||||
|
(!isEmpty(options) && {
|
||||||
|
[field.get('name')]: {
|
||||||
|
[field.get('collection')]: {
|
||||||
|
[last(newValue)]: last(options).data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}) ||
|
||||||
|
{};
|
||||||
|
onChange(fromJS(newValue), metadata);
|
||||||
|
};
|
||||||
|
|
||||||
handleChange = selectedOption => {
|
handleChange = selectedOption => {
|
||||||
const { onChange, field } = this.props;
|
const { onChange, field } = this.props;
|
||||||
|
|
||||||
@ -262,8 +303,16 @@ export default class RelationControl extends React.Component {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AsyncSelect
|
<SortableSelect
|
||||||
components={{ MenuList }}
|
useDragHandle
|
||||||
|
// react-sortable-hoc props:
|
||||||
|
axis="xy"
|
||||||
|
onSortEnd={this.onSortEnd(selectedValue)}
|
||||||
|
distance={4}
|
||||||
|
// small fix for https://github.com/clauderic/react-sortable-hoc/pull/352:
|
||||||
|
getHelperDimensions={({ node }) => node.getBoundingClientRect()}
|
||||||
|
// react-select props:
|
||||||
|
components={{ MenuList, MultiValue, MultiValueLabel }}
|
||||||
value={selectedValue}
|
value={selectedValue}
|
||||||
inputId={forID}
|
inputId={forID}
|
||||||
cacheOptions
|
cacheOptions
|
||||||
|
Reference in New Issue
Block a user