Если вы хотите поддерживать ввод с клавиатуры, вам придется обновить диапазоны в обработчике onBlur
для числовых входов и изменить значения ввода в onChange
.Вот пример с пользовательским компонентом InputNumber
, который скрывает эту деталь onBlur / onChange:
class InputNumber extends React.Component {
state = {
value: this.props.value
}
onChange = e => {
this.setState({ value: +e.target.value });
};
onBlur = e => {
this.props.onChange(this.state.value);
};
componentWillReceiveProps(nextProps) {
if (nextProps.value !== this.state.value) {
this.setState({ value: nextProps.value });
}
}
render() {
return <input
type='number'
{...this.props}
value={this.state.value}
onChange={this.onChange}
onBlur={this.onBlur}
/>;
}
}
class Demo extends React.Component {
state = {
ranges: [[1, 50], [51, 70], [71, 100]]
};
render() {
const { rangeRed, rangeYellow, rangeGreen } = this.state;
const controls = [
this.range('Red Scoring Range', 'red', 0),
this.range('Yellow Scoring Range', 'yellow', 1),
this.range('Green Scoring Range', 'green', 2)
];
return <table className='controls'>{controls}</table>;
}
range(label, color, idx) {
const { ranges } = this.state;
return (
<tr className='control-row'>
<td className='label'>{label}</td>
<td><div className={color + ' bullet'}></div></td>
<td>
<InputNumber
value={ranges[idx][0]}
onChange={this.onChange(idx, true)}
min={ranges[idx-1 < 0 ? 0 : idx-1][0] + 2}
max={ranges[idx][1] - 1}
disabled={idx === 0} />
</td>
<td>to</td>
<td>
<InputNumber
value={ranges[idx][1]}
onChange={this.onChange(idx, false)}
min={ranges[idx][0] + 1}
max={ranges[(idx+1) % ranges.length][1]-2}
disabled={idx === ranges.length-1} />
</td>
</tr>
);
}
onChange = (idx, isMin) => v => {
const ranges = [...this.state.ranges];
const min = isMin ? ranges[idx-1 < 0 ? 0 : idx-1][0] + 2 : ranges[idx][0] + 1;
const max = isMin ? ranges[idx][1] - 1 : ranges[(idx+1) % ranges.length][1]-2;
v = Math.min(Math.max(min, v), max);
if (!isMin && idx < ranges.length-1) {
ranges[idx][1] = v;
ranges[idx+1][0] = v+1;
} else if (isMin && idx > 0) {
ranges[idx][0] = v;
ranges[idx-1][1] = v-1;
}
this.setState({ ranges });
}
}
ReactDOM.render(<Demo />, document.getElementById('app'));
:root {
--bullet-size: 15px;
}
* {
color: #555;
}
.bullet {
display: inline-block;
height: var(--bullet-size);
width: var(--bullet-size);
border-radius: var(--bullet-size);
}
.red { background: red; }
.yellow { background: yellow; }
.green { background: green; }
td { padding: 5px; }
input {
width: 50px;
padding: 5px;
border: solid 1px #ccc;
border-radius: 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Если вы хотите мгновенное обновление диапазона и не заботитесь о вводе с клавиатуры, обновите диапазоны непосредственно в обработчике onChange
:
class Demo extends React.Component {
state = {
ranges: [0, 50, 70, 100]
};
render() {
const { rangeRed, rangeYellow, rangeGreen } = this.state;
const controls = [
this.range('Red Scoring Range', 'red', 0),
this.range('Yellow Scoring Range', 'yellow', 1),
this.range('Green Scoring Range', 'green', 2)
];
return <table className='controls'>{controls}</table>;
}
range(label, color, idx) {
const { ranges } = this.state;
return (
<tr className='control-row'>
<td className='label'>{label}</td>
<td><div className={color + ' bullet'}></div></td>
<td>
<input
type='number'
value={ranges[idx] + 1}
onChange={this.onChange(idx, true)}
max={ranges[idx+1] - 1}
disabled={idx === 0} />
</td>
<td>to</td>
<td>
<input
type='number'
value={ranges[idx+1]}
onChange={this.onChange(idx+1, false)}
min={ranges[idx] + 1}
disabled={idx+1 === ranges.length-1} />
</td>
</tr>
);
}
onChange = (idx, isMin) => e => {
const ranges = [...this.state.ranges];
const value = isMin ? +e.target.value - 1 : +e.target.value;
if (isMin && value > ranges[idx - 1] + 1 && value < ranges[idx + 1] + 1)
ranges[idx] = value;
if (!isMin && value < ranges[idx + 1] - 1 && value > ranges[idx - 1] + 1)
ranges[idx] = value;
this.setState({ ranges });
};
}
ReactDOM.render(<Demo />, document.getElementById('app'));
:root {
--bullet-size: 15px;
}
* {
color: #555;
}
.bullet {
display: inline-block;
height: var(--bullet-size);
width: var(--bullet-size);
border-radius: var(--bullet-size);
}
.red { background: red; }
.yellow { background: yellow; }
.green { background: green; }
td { padding: 5px; }
input {
width: 50px;
padding: 5px;
border: none;
border:solid 1px #ccc;
border-radius: 3px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>