diff --git a/src/components/fields/FunctionSpecField.jsx b/src/components/fields/FunctionSpecField.jsx index 36c1e41..d074c89 100644 --- a/src/components/fields/FunctionSpecField.jsx +++ b/src/components/fields/FunctionSpecField.jsx @@ -17,6 +17,9 @@ import MdInsertChart from 'react-icons/lib/md/insert-chart' import PropTypes from 'prop-types' import capitalize from 'lodash.capitalize' +import docUid from '../../libs/document-uid' +import sortNumerically from '../../libs/sort-numerically' + function isZoomField(value) { return typeof value === 'object' && value.stops && typeof value.property === 'undefined' } @@ -43,6 +46,70 @@ export default class FunctionSpecProperty extends React.Component { ]), } + constructor() { + super() + this.state = { + refs: {} + } + } + + /** + * We cache a reference for each stop by its index. + * + * When the stops are reordered the references are also updated (see this.orderStops) this allows React to use the same key for the element and keep keyboard focus. + */ + setStopRefs(props) { + // This is initialsed below only if required to improved performance. + let newRefs; + + if(props.value && props.value.stops) { + props.value.stops.forEach((val, idx) => { + if(!this.state.refs.hasOwnProperty(idx)) { + if(!newRefs) { + newRefs = {...this.state.refs}; + } + newRefs[idx] = docUid("stop-"); + } + }) + } + + if(newRefs) { + this.setState({ + refs: newRefs + }) + } + } + + componentWillReceiveProps(nextProps) { + this.setStopRefs(nextProps); + } + + // Order the stops altering the refs to reflect their new position. + orderStopsByZoom(stops) { + const mappedWithRef = stops + .map((stop, idx) => { + return { + ref: this.state.refs[idx], + data: stop + } + }) + // Sort by zoom + .sort((a, b) => sortNumerically(a.data[0], b.data[0])); + + // Fetch the new position of the stops + const newRefs = {}; + mappedWithRef + .forEach((stop, idx) =>{ + newRefs[idx] = stop.ref; + }) + + this.setState({ + refs: newRefs + }); + + return mappedWithRef.map((item) => item.data); + } + addStop() { const stops = this.props.value.stops.slice(0) const lastStop = stops[stops.length - 1] @@ -122,11 +189,14 @@ export default class FunctionSpecProperty extends React.Component { } changeStop(changeIdx, stopData, value) { - const stops = this.props.value.stops.slice(0) - stops[changeIdx] = [stopData, value] + const stops = this.props.value.stops.slice(0); + stops[changeIdx] = [stopData, value]; + + const orderedStops = this.orderStopsByZoom(stops); + const changedValue = { ...this.props.value, - stops: stops, + stops: orderedStops } this.props.onChange(this.props.fieldName, changedValue) } @@ -241,11 +311,12 @@ export default class FunctionSpecProperty extends React.Component { renderZoomProperty() { const zoomFields = this.props.value.stops.map((stop, idx) => { const zoomLevel = stop[0] + const key = this.state.refs[idx]; const value = stop[1] const deleteStopBtn= return b) { + return 1 + } + else { + return 0; + } +}