feat(relation-widget): enable reordering for relation controls (#5873)

This commit is contained in:
Andi Pabst
2021-10-21 13:53:49 +02:00
committed by GitHub
parent e93cd7cddc
commit a77a355bac
2 changed files with 55 additions and 5 deletions

View File

@ -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",

View File

@ -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