diff --git a/bower.json b/bower.json index 2bb6f5c..ae0eccb 100644 --- a/bower.json +++ b/bower.json @@ -4,7 +4,7 @@ "dist/react-input-range.js", "dist/react-input-range.css" ], - "version": "0.3.2", + "version": "0.4.0", "description": "React component for inputting numeric values within a range", "homepage": "https://github.com/davidchin/react-input-range", "authors": [ diff --git a/dist/react-input-range.css b/dist/react-input-range.css index 8ef33b6..56e3fd7 100644 --- a/dist/react-input-range.css +++ b/dist/react-input-range.css @@ -21,6 +21,12 @@ transform: scale(1.3); } .InputRange-slider:focus { box-shadow: 0 0 0 5px rgba(63, 81, 181, 0.2); } + .InputRange.is-disabled .InputRange-slider { + background: #cccccc; + border: 1px solid #cccccc; + box-shadow: none; + -webkit-transform: none; + transform: none; } .InputRange-sliderContainer { transition: left 0.3s ease-out; } @@ -58,6 +64,8 @@ height: 0.3rem; position: relative; transition: left 0.3s ease-out, width 0.3s ease-out; } + .InputRange.is-disabled .InputRange-track { + background: #eeeeee; } .InputRange-track--container { left: 0; diff --git a/dist/react-input-range.js b/dist/react-input-range.js index ce99af5..7367010 100644 --- a/dist/react-input-range.js +++ b/dist/react-input-range.js @@ -89,6 +89,7 @@ var InputRange = (function (_React$Component) { _get(Object.getPrototypeOf(InputRange.prototype), 'constructor', this).call(this, props); var state = { + didChange: false, percentages: { min: 0, max: 0 @@ -105,7 +106,7 @@ var InputRange = (function (_React$Component) { this.state = state; this.valueTransformer = new _ValueTransformer2['default'](this); - this.isMultiValue = this.props.hasOwnProperty('values'); + this.isMultiValue = this.props.hasOwnProperty('defaultValues') || this.props.hasOwnProperty('values'); (0, _util.autobind)(['handleSliderMouseMove', 'handleSliderKeyDown', 'handleTrackMouseDown'], this); } @@ -118,20 +119,23 @@ var InputRange = (function (_React$Component) { }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(nextProps) { - this.setPositionsByProps(nextProps); + var props = (0, _util.omit)(nextProps, ['defaultValue', 'defaultValues']); + + this.setPositionsByProps(props); } }, { key: 'shouldComponentUpdate', value: function shouldComponentUpdate(nextProps, nextState) { var currentProps = this.props; var currentState = this.state; + var shouldUpdate = currentState.values.min !== nextState.values.min || currentState.values.max !== nextState.values.max || currentState.value !== nextState.value || currentProps.minValue !== nextProps.minValue || currentProps.maxValue !== nextProps.maxValue; - return currentState.values.min !== nextState.values.min || currentState.values.max !== nextState.values.max || currentState.value !== nextState.value || currentProps.minValue !== nextProps.minValue || currentProps.maxValue !== nextProps.maxValue; + return shouldUpdate; } }, { key: 'componentDidUpdate', value: function componentDidUpdate() { - if (this.props.onChange) { + if (this.props.onChange && this.state.didChange) { var results = this.state.values.max; if (this.isMultiValue) { @@ -140,6 +144,10 @@ var InputRange = (function (_React$Component) { this.props.onChange(this, results); } + + this.setState({ + didChange: true + }); } }, { key: 'setPositions', @@ -189,6 +197,10 @@ var InputRange = (function (_React$Component) { }, { key: 'setPositionByValue', value: function setPositionByValue(slider, value) { + if (!(0, _util.isNumber)(value)) { + return; + } + var validValue = (0, _util.clamp)(value, this.props.minValue, this.props.maxValue); var position = this.valueTransformer.positionFromValue(validValue); @@ -197,6 +209,10 @@ var InputRange = (function (_React$Component) { }, { key: 'setPositionsByValues', value: function setPositionsByValues(values) { + if (!values || !(0, _util.isNumber)(values.min) || !(0, _util.isNumber)(values.max)) { + return; + } + var validValues = { min: (0, _util.clamp)(values.min, this.props.minValue, this.props.maxValue), max: (0, _util.clamp)(values.max, this.props.minValue, this.props.maxValue) @@ -213,9 +229,13 @@ var InputRange = (function (_React$Component) { key: 'setPositionsByProps', value: function setPositionsByProps(props) { if (this.isMultiValue) { - this.setPositionsByValues(props.values); + var values = !(0, _util.isEmpty)(props.values) ? props.values : props.defaultValues; + + this.setPositionsByValues(values); } else { - this.setPositionByValue(this.refs.sliderMax, props.value); + var value = (0, _util.isNumber)(props.value) ? props.value : props.defaultValue; + + this.setPositionByValue(this.refs.sliderMax, value); } } }, { @@ -237,6 +257,10 @@ var InputRange = (function (_React$Component) { }, { key: 'handleSliderMouseMove', value: function handleSliderMouseMove(slider, event) { + if (this.props.disabled) { + return; + } + var position = this.valueTransformer.positionFromEvent(event); this.setPosition(slider, position); @@ -244,6 +268,10 @@ var InputRange = (function (_React$Component) { }, { key: 'handleSliderKeyDown', value: function handleSliderKeyDown(slider, event) { + if (this.props.disabled) { + return; + } + switch (event.keyCode) { case KeyCode.LEFT_ARROW: this.decrementValue(slider); @@ -260,6 +288,10 @@ var InputRange = (function (_React$Component) { }, { key: 'handleTrackMouseDown', value: function handleTrackMouseDown(track, position) { + if (this.props.disabled) { + return; + } + this.setPosition(null, position); } }, { @@ -361,10 +393,18 @@ var InputRange = (function (_React$Component) { key: 'render', value: function render() { var classNames = this.props.classNames; + var componentClassName = classNames.component; + + if (this.props.disabled) { + componentClassName = componentClassName + ' is-disabled'; + } return _react2['default'].createElement( 'div', - { ref: 'inputRange', className: classNames.component }, + { + 'aria-disabled': this.props.disabled, + ref: 'inputRange', + className: componentClassName }, _react2['default'].createElement( 'span', { className: classNames.labelMin }, @@ -410,6 +450,9 @@ var InputRange = (function (_React$Component) { InputRange.propTypes = { ariaLabelledby: _react2['default'].PropTypes.string, classNames: _react2['default'].PropTypes.objectOf(_react2['default'].PropTypes.string), + defaultValue: _propTypes.maxMinValuePropType, + defaultValues: _propTypes.maxMinValuePropType, + disabled: _react2['default'].PropTypes.bool, maxValue: _propTypes.maxMinValuePropType, minValue: _propTypes.maxMinValuePropType, name: _react2['default'].PropTypes.string, @@ -421,9 +464,9 @@ InputRange.propTypes = { InputRange.defaultProps = { classNames: _defaultClassNames2['default'], + disabled: false, minValue: 0, maxValue: 10, - value: 0, step: 1 }; @@ -868,13 +911,15 @@ function maxMinValuePropType(props) { var minValue = props.minValue; var value = props.value; var values = props.values; + var defaultValue = props.defaultValue; + var defaultValues = props.defaultValues; - if (!numberPredicate(value)) { - return new Error('`value` must be a number'); + if (!values && !defaultValues && !numberPredicate(value) && !numberPredicate(defaultValue)) { + return new Error('`value` or `defaultValue` must be a number'); } - if (!value && !(0, _util.objectOf)(values, numberPredicate)) { - return new Error('`values` must be an object of numbers'); + if (!value && !defaultValue && !(0, _util.objectOf)(values, numberPredicate) && !(0, _util.objectOf)(defaultValues, numberPredicate)) { + return new Error('`values` or `defaultValues` must be an object of numbers'); } if (minValue >= maxValue) { @@ -904,6 +949,23 @@ function extend() { return Object.assign.apply(Object, arguments); } +function includes(array, value) { + return array.indexOf(value) > -1; +} + +function omit(obj, omitKeys) { + var keys = Object.keys(obj); + var outputObj = {}; + + keys.forEach(function (key) { + if (!includes(omitKeys, key)) { + outputObj[key] = obj[key]; + } + }); + + return outputObj; +} + function captialize(string) { return string.charAt(0).toUpperCase() + string.slice(1); } @@ -916,6 +978,18 @@ function isNumber(number) { return typeof number === 'number'; } +function isEmpty(obj) { + if (!obj) { + return true; + } + + if (Array.isArray(obj)) { + return obj.length === 0; + } + + return Object.keys(obj).length === 0; +} + function arrayOf(array, predicate) { if (!Array.isArray(array)) { return false; @@ -961,8 +1035,10 @@ var util = { clamp: clamp, distanceTo: distanceTo, extend: extend, + isEmpty: isEmpty, isNumber: isNumber, - objectOf: objectOf + objectOf: objectOf, + omit: omit }; exports['default'] = util; diff --git a/dist/react-input-range.min.css b/dist/react-input-range.min.css index 6d5725f..772a5f5 100644 --- a/dist/react-input-range.min.css +++ b/dist/react-input-range.min.css @@ -1 +1 @@ -.InputRange-slider{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:#3f51b5;border:1px solid #3f51b5;border-radius:100%;cursor:pointer;display:block;height:1rem;margin-left:-.5rem;margin-top:-.65rem;outline:0;position:absolute;top:50%;transition:-webkit-transform .3s ease-out,box-shadow .3s ease-out;transition:transform .3s ease-out,box-shadow .3s ease-out;width:1rem}.InputRange-slider:active{-webkit-transform:scale(1.3);transform:scale(1.3)}.InputRange-slider:focus{box-shadow:0 0 0 5px rgba(63,81,181,.2)}.InputRange-sliderContainer{transition:left .3s ease-out}.InputRange-label{color:#aaa;font-family:"Helvetica Neue",san-serif;font-size:.8rem}.InputRange-label--max,.InputRange-label--min{bottom:-1.4rem;position:absolute}.InputRange-label--min{left:0}.InputRange-label--max{right:0}.InputRange-label--value{position:absolute;top:-1.8rem}.InputRange-labelContainer{left:-50%;position:relative}.InputRange-label--max .InputRange-labelContainer{left:50%}.InputRange-track{background:#eee;border-radius:.3rem;display:block;height:.3rem;position:relative;transition:left .3s ease-out,width .3s ease-out}.InputRange-track--container{left:0;margin-top:-.15rem;position:absolute;right:0;top:50%}.InputRange-track--active{background:#3f51b5}.InputRange{cursor:pointer;height:1rem;position:relative;width:100%} \ No newline at end of file +.InputRange-slider{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:#3f51b5;border:1px solid #3f51b5;border-radius:100%;cursor:pointer;display:block;height:1rem;margin-left:-.5rem;margin-top:-.65rem;outline:0;position:absolute;top:50%;transition:-webkit-transform .3s ease-out,box-shadow .3s ease-out;transition:transform .3s ease-out,box-shadow .3s ease-out;width:1rem}.InputRange-slider:active{-webkit-transform:scale(1.3);transform:scale(1.3)}.InputRange-slider:focus{box-shadow:0 0 0 5px rgba(63,81,181,.2)}.InputRange.is-disabled .InputRange-slider{background:#ccc;border:1px solid #ccc;box-shadow:none;-webkit-transform:none;transform:none}.InputRange-sliderContainer{transition:left .3s ease-out}.InputRange-label{color:#aaa;font-family:"Helvetica Neue",san-serif;font-size:.8rem}.InputRange-label--max,.InputRange-label--min{bottom:-1.4rem;position:absolute}.InputRange-label--min{left:0}.InputRange-label--max{right:0}.InputRange-label--value{position:absolute;top:-1.8rem}.InputRange-labelContainer{left:-50%;position:relative}.InputRange-label--max .InputRange-labelContainer{left:50%}.InputRange-track{background:#eee;border-radius:.3rem;display:block;height:.3rem;position:relative;transition:left .3s ease-out,width .3s ease-out}.InputRange.is-disabled .InputRange-track{background:#eee}.InputRange-track--container{left:0;margin-top:-.15rem;position:absolute;right:0;top:50%}.InputRange-track--active{background:#3f51b5}.InputRange{cursor:pointer;height:1rem;position:relative;width:100%} \ No newline at end of file diff --git a/dist/react-input-range.min.js b/dist/react-input-range.min.js index c962f18..2ea15d5 100644 --- a/dist/react-input-range.min.js +++ b/dist/react-input-range.min.js @@ -1 +1 @@ -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.InputRange=e()}}(function(){return function e(t,n,a){function o(i,u){if(!n[i]){if(!t[i]){var s="function"==typeof require&&require;if(!u&&s)return s(i,!0);if(r)return r(i,!0);var l=new Error("Cannot find module '"+i+"'");throw l.code="MODULE_NOT_FOUND",l}var c=n[i]={exports:{}};t[i][0].call(c.exports,function(e){var n=t[i][1][e];return o(n?n:e)},c,c.exports,e,t,n,a)}return n[i].exports}for(var r="function"==typeof require&&require,i=0;i=e.props.step}function l(e,t){return t===e.refs.sliderMin?"min":"max"}function c(e,t){if(e.isMultiValue){var n=P.distanceTo(t,e.state.positions.min),a=P.distanceTo(t,e.state.positions.max);if(a>n)return"min"}return"max"}function p(e){return e.isMultiValue?["max","min"]:["max"]}Object.defineProperty(n,"__esModule",{value:!0});var f=function(){function e(e,t){for(var n=0;n=t?new Error("`minValue` must be smaller than `maxValue`"):n>=t?new Error("`maxValue` must be larger than `minValue`"):n>o||o>t?new Error("`value` must be within `minValue` and `maxValue`"):void 0:new Error("`values` must be an object of numbers"):new Error("`value` must be a number")}Object.defineProperty(n,"__esModule",{value:!0}),n.maxMinValuePropType=o;var r=e("./util")},{"./util":7}],7:[function(e,t,n){"use strict";function a(e,t,n){return Math.min(Math.max(e,t),n)}function o(){return Object.assign.apply(Object,arguments)}function r(e){return e.charAt(0).toUpperCase()+e.slice(1)}function i(e,t){return Math.sqrt(Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2))}function u(e){return"number"==typeof e}function s(e,t){if(!Array.isArray(e))return!1;for(var n=0,a=e.length;a>n;n++)if(!t(e[n]))return!1;return!0}function l(e,t,n){if("object"!=typeof e)return!1;for(var a=n||Object.keys(e),o=0,r=a.length;r>o;o++){var i=a[o];if(!t(e[i]))return!1}return!0}function c(e,t){e.forEach(function(e){t[e]=t[e].bind(t)})}Object.defineProperty(n,"__esModule",{value:!0});var p={arrayOf:s,autobind:c,captialize:r,clamp:a,distanceTo:i,extend:o,isNumber:u,objectOf:l};n["default"]=p,t.exports=n["default"]},{}],8:[function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(n,"__esModule",{value:!0});var o=e("./InputRange"),r=a(o);n["default"]=r["default"],t.exports=n["default"]},{"./InputRange":1}]},{},[8])(8)}); \ No newline at end of file +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.InputRange=e()}}(function(){return function e(t,n,a){function o(i,u){if(!n[i]){if(!t[i]){var s="function"==typeof require&&require;if(!u&&s)return s(i,!0);if(r)return r(i,!0);var l=new Error("Cannot find module '"+i+"'");throw l.code="MODULE_NOT_FOUND",l}var p=n[i]={exports:{}};t[i][0].call(p.exports,function(e){var n=t[i][1][e];return o(n?n:e)},p,p.exports,e,t,n,a)}return n[i].exports}for(var r="function"==typeof require&&require,i=0;i=e.props.step}function l(e,t){return t===e.refs.sliderMin?"min":"max"}function p(e,t){if(e.isMultiValue){var n=P.distanceTo(t,e.state.positions.min),a=P.distanceTo(t,e.state.positions.max);if(a>n)return"min"}return"max"}function c(e){return e.isMultiValue?["max","min"]:["max"]}Object.defineProperty(n,"__esModule",{value:!0});var f=function(){function e(e,t){for(var n=0;n=t?new Error("`minValue` must be smaller than `maxValue`"):n>=t?new Error("`maxValue` must be larger than `minValue`"):n>o||o>t?new Error("`value` must be within `minValue` and `maxValue`"):void 0:new Error("`values` or `defaultValues` must be an object of numbers"):new Error("`value` or `defaultValue` must be a number")}Object.defineProperty(n,"__esModule",{value:!0}),n.maxMinValuePropType=o;var r=e("./util")},{"./util":7}],7:[function(e,t,n){"use strict";function a(e,t,n){return Math.min(Math.max(e,t),n)}function o(){return Object.assign.apply(Object,arguments)}function r(e,t){return e.indexOf(t)>-1}function i(e,t){var n=Object.keys(e),a={};return n.forEach(function(n){r(t,n)||(a[n]=e[n])}),a}function u(e){return e.charAt(0).toUpperCase()+e.slice(1)}function s(e,t){return Math.sqrt(Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2))}function l(e){return"number"==typeof e}function p(e){return e?Array.isArray(e)?0===e.length:0===Object.keys(e).length:!0}function c(e,t){if(!Array.isArray(e))return!1;for(var n=0,a=e.length;a>n;n++)if(!t(e[n]))return!1;return!0}function f(e,t,n){if("object"!=typeof e)return!1;for(var a=n||Object.keys(e),o=0,r=a.length;r>o;o++){var i=a[o];if(!t(e[i]))return!1}return!0}function d(e,t){e.forEach(function(e){t[e]=t[e].bind(t)})}Object.defineProperty(n,"__esModule",{value:!0});var h={arrayOf:c,autobind:d,captialize:u,clamp:a,distanceTo:s,extend:o,isEmpty:p,isNumber:l,objectOf:f,omit:i};n["default"]=h,t.exports=n["default"]},{}],8:[function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(n,"__esModule",{value:!0});var o=e("./InputRange"),r=a(o);n["default"]=r["default"],t.exports=n["default"]},{"./InputRange":1}]},{},[8])(8)}); \ No newline at end of file diff --git a/package.json b/package.json index 07a2355..86c2ce9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-input-range", - "version": "0.3.2", + "version": "0.4.0", "description": "React component for inputting numeric values within a range", "keywords": [ "react",