Skip to content

Commit 0df907a

Browse files
committed
Add defaultValue prop
1 parent 333e4c7 commit 0df907a

File tree

7 files changed

+192
-50
lines changed

7 files changed

+192
-50
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,15 @@ Property | Type | Description
7171
:-----------------------|:------------------------|:----------------------------------
7272
ariaLabelledby |string |`aria-labelledby` attribute
7373
classNames |Object.<string> |CSS class names
74+
defaultValue |number |Default value
75+
defaultValues |Object |Default values
7476
maxValue |number |Maximum value it can accept
7577
minValue |number |Minimum value it can accept
7678
name |string |Name of `form` input
7779
onChange |Function |`onChange` callback
7880
step |number |Increment/decrement value
79-
value |number |Default value
80-
values |Array.<number> |Default range of values
81+
value |number |Current value
82+
values |Object |Current range of values
8183

8284
## Development
8385

example/js/App.js

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,35 @@ class App extends React.Component {
88
this.state = {
99
value: 5,
1010
values: {
11-
min: 2,
11+
min: 5,
1212
max: 10,
1313
},
1414
};
1515
}
1616

1717
handleValuesChange(component, values) {
18+
console.log(values);
19+
1820
this.setState({
1921
values: values,
2022
});
2123
}
2224

2325
handleValueChange(component, value) {
26+
console.log(value);
27+
2428
this.setState({
2529
value: value,
2630
});
2731
}
2832

2933
render() {
34+
const defaultValue = 2;
35+
const defaultValues = {
36+
min: 2,
37+
max: 8,
38+
};
39+
3040
return (
3141
<form className="form">
3242
<InputRange
@@ -35,12 +45,25 @@ class App extends React.Component {
3545
values={this.state.values}
3646
onChange={this.handleValuesChange.bind(this)}
3747
/>
48+
49+
<InputRange
50+
maxValue={20}
51+
minValue={0}
52+
defaultValues={defaultValues}
53+
/>
54+
3855
<InputRange
3956
maxValue={20}
4057
minValue={0}
4158
value={this.state.value}
4259
onChange={this.handleValueChange.bind(this)}
4360
/>
61+
62+
<InputRange
63+
maxValue={20}
64+
minValue={0}
65+
defaultValue={defaultValue}
66+
/>
4467
</form>
4568
);
4669
}

karma.conf.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module.exports = function(config) {
66

77
files: [
88
'node_modules/react/dist/react.js',
9+
'node_modules/lodash/index.js',
910
'node_modules/babelify/polyfill.js',
1011
'src/**/*.js',
1112
'test/**/*.js'

src/InputRange/InputRange.js

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import React from 'react';
22
import Slider from './Slider';
33
import Track from './Track';
44
import ValueTransformer from './ValueTransformer';
5-
import { autobind, captialize, clamp, distanceTo, extend } from './util';
5+
import { autobind, captialize, clamp, distanceTo, extend, isEmpty, isNumber, omit } from './util';
66
import { maxMinValuePropType } from './propTypes';
77
import defaultClassNames from './defaultClassNames';
88

@@ -53,6 +53,7 @@ class InputRange extends React.Component {
5353

5454
// Initial state
5555
const state = {
56+
didChange: false,
5657
percentages: {
5758
min: 0,
5859
max: 0,
@@ -69,7 +70,8 @@ class InputRange extends React.Component {
6970

7071
this.state = state;
7172
this.valueTransformer = new ValueTransformer(this);
72-
this.isMultiValue = this.props.hasOwnProperty('values');
73+
this.isMultiValue = this.props.hasOwnProperty('defaultValues') ||
74+
this.props.hasOwnProperty('values');
7375

7476
// Auto-bind
7577
autobind([
@@ -85,24 +87,27 @@ class InputRange extends React.Component {
8587
}
8688

8789
componentWillReceiveProps(nextProps) {
88-
this.setPositionsByProps(nextProps);
90+
const props = omit(nextProps, ['defaultValue', 'defaultValues']);
91+
92+
this.setPositionsByProps(props);
8993
}
9094

9195
shouldComponentUpdate(nextProps, nextState) {
9296
const currentProps = this.props;
9397
const currentState = this.state;
94-
95-
return (
98+
const shouldUpdate = (
9699
currentState.values.min !== nextState.values.min ||
97100
currentState.values.max !== nextState.values.max ||
98101
currentState.value !== nextState.value ||
99102
currentProps.minValue !== nextProps.minValue ||
100103
currentProps.maxValue !== nextProps.maxValue
101104
);
105+
106+
return shouldUpdate;
102107
}
103108

104109
componentDidUpdate() {
105-
if (this.props.onChange) {
110+
if (this.props.onChange && this.state.didChange) {
106111
let results = this.state.values.max;
107112

108113
if (this.isMultiValue) {
@@ -111,6 +116,10 @@ class InputRange extends React.Component {
111116

112117
this.props.onChange(this, results);
113118
}
119+
120+
this.setState({
121+
didChange: true,
122+
});
114123
}
115124

116125
// Getters / Setters
@@ -168,13 +177,21 @@ class InputRange extends React.Component {
168177
}
169178

170179
setPositionByValue(slider, value) {
180+
if (!isNumber(value)) {
181+
return;
182+
}
183+
171184
const validValue = clamp(value, this.props.minValue, this.props.maxValue);
172185
const position = this.valueTransformer.positionFromValue(validValue);
173186

174187
this.setPosition(slider, position);
175188
}
176189

177190
setPositionsByValues(values) {
191+
if (!values || !isNumber(values.min) || !isNumber(values.max)) {
192+
return;
193+
}
194+
178195
const validValues = {
179196
min: clamp(values.min, this.props.minValue, this.props.maxValue),
180197
max: clamp(values.max, this.props.minValue, this.props.maxValue),
@@ -190,9 +207,13 @@ class InputRange extends React.Component {
190207

191208
setPositionsByProps(props) {
192209
if (this.isMultiValue) {
193-
this.setPositionsByValues(props.values);
210+
const values = !isEmpty(props.values) ? props.values : props.defaultValues;
211+
212+
this.setPositionsByValues(values);
194213
} else {
195-
this.setPositionByValue(this.refs.sliderMax, props.value);
214+
const value = isNumber(props.value) ? props.value : props.defaultValue;
215+
216+
this.setPositionByValue(this.refs.sliderMax, value);
196217
}
197218
}
198219

@@ -325,6 +346,8 @@ class InputRange extends React.Component {
325346
InputRange.propTypes = {
326347
ariaLabelledby: React.PropTypes.string,
327348
classNames: React.PropTypes.objectOf(React.PropTypes.string),
349+
defaultValue: maxMinValuePropType,
350+
defaultValues: maxMinValuePropType,
328351
maxValue: maxMinValuePropType,
329352
minValue: maxMinValuePropType,
330353
name: React.PropTypes.string,
@@ -338,7 +361,6 @@ InputRange.defaultProps = {
338361
classNames: defaultClassNames,
339362
minValue: 0,
340363
maxValue: 10,
341-
value: 0,
342364
step: 1,
343365
};
344366

src/InputRange/propTypes.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,21 @@ export function maxMinValuePropType(props) {
99
const minValue = props.minValue;
1010
const value = props.value;
1111
const values = props.values;
12+
const defaultValue = props.defaultValue;
13+
const defaultValues = props.defaultValues;
1214

13-
if (!numberPredicate(value)) {
14-
return new Error('`value` must be a number');
15+
if (!values &&
16+
!defaultValues &&
17+
!numberPredicate(value) &&
18+
!numberPredicate(defaultValue)) {
19+
return new Error('`value` or `defaultValue` must be a number');
1520
}
1621

17-
if (!value && !objectOf(values, numberPredicate)) {
18-
return new Error('`values` must be an object of numbers');
22+
if (!value &&
23+
!defaultValue &&
24+
!objectOf(values, numberPredicate) &&
25+
!objectOf(defaultValues, numberPredicate)) {
26+
return new Error('`values` or `defaultValues` must be an object of numbers');
1927
}
2028

2129
if (minValue >= maxValue) {

src/InputRange/util.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,23 @@ function extend() {
66
return Object.assign.apply(Object, arguments);
77
}
88

9+
function includes(array, value) {
10+
return array.indexOf(value) > -1;
11+
}
12+
13+
function omit(obj, omitKeys) {
14+
const keys = Object.keys(obj);
15+
const outputObj = {};
16+
17+
keys.forEach((key) => {
18+
if (!includes(omitKeys, key)) {
19+
outputObj[key] = obj[key];
20+
}
21+
});
22+
23+
return outputObj;
24+
}
25+
926
function captialize(string) {
1027
return string.charAt(0).toUpperCase() + string.slice(1);
1128
}
@@ -18,6 +35,18 @@ function isNumber(number) {
1835
return typeof number === 'number';
1936
}
2037

38+
function isEmpty(obj) {
39+
if (!obj) {
40+
return true;
41+
}
42+
43+
if (Array.isArray(obj)) {
44+
return obj.length === 0;
45+
}
46+
47+
return Object.keys(obj).length === 0;
48+
}
49+
2150
function arrayOf(array, predicate) {
2251
if (!Array.isArray(array)) {
2352
return false;
@@ -63,8 +92,10 @@ const util = {
6392
clamp,
6493
distanceTo,
6594
extend,
95+
isEmpty,
6696
isNumber,
6797
objectOf,
98+
omit,
6899
};
69100

70101
export default util;

0 commit comments

Comments
 (0)