From af5556d4de1a4ec407d96b9b15ba105a9501cae0 Mon Sep 17 00:00:00 2001 From: Andy Edwards Date: Thu, 29 Sep 2016 22:50:38 -0500 Subject: [PATCH 1/6] Make input range component more flexible Allow overriding of Track, Slider and Label components Allow passing extra children to InputRange and Slider --- README.md | 3 +++ src/InputRange/InputRange.js | 29 +++++++++++++++++++++++------ src/InputRange/Slider.js | 17 +++++++++++++++-- src/InputRange/index.js | 4 ++++ 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 08b4004..80bc15a 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,9 @@ onChange |Function |`onChange` callbac onChangeComplete |Function |`onChangeComplete` callback step |number |Increment/decrement value value |number | Object.<number> |Current value(s) (required) +Track |Function |Override default Track Component +Slider |Function |Override default Slider Component +Label |Function |Override default Label Component ## Development diff --git a/src/InputRange/InputRange.js b/src/InputRange/InputRange.js index 226194b..ee1cd64 100644 --- a/src/InputRange/InputRange.js +++ b/src/InputRange/InputRange.js @@ -3,9 +3,9 @@ */ import React from 'react'; -import Slider from './Slider'; -import Track from './Track'; -import Label from './Label'; +import { default as DefaultSlider } from './Slider'; +import { default as DefaultTrack } from './Track'; +import { default as DefaultLabel } from './Label'; import defaultClassNames from './defaultClassNames'; import valueTransformer from './valueTransformer'; import { autobind, captialize, distanceTo, isDefined, isObject, length } from './util'; @@ -163,7 +163,7 @@ function getKeyByPosition(inputRange, position) { * @return {Array.} Array of HTML */ function renderSliders(inputRange) { - const { classNames } = inputRange.props; + const { classNames, Slider, Label } = inputRange.props; const sliders = []; const keys = getKeys(inputRange); const values = valueTransformer.valuesFromProps(inputRange); @@ -196,7 +196,8 @@ function renderSliders(inputRange) { percentage={ percentage } ref={ ref } type={ key } - value={ value } /> + value={ value } + Label={ Label } /> ); sliders.push(slider); @@ -549,7 +550,7 @@ export default class InputRange extends React.Component { * @return {string} Component JSX */ render() { - const { classNames } = this.props; + const { classNames, Label, Track, children } = this.props; const componentClassName = getComponentClassName(this); const values = valueTransformer.valuesFromProps(this); const percentages = valueTransformer.percentagesFromValues(this, values); @@ -586,6 +587,8 @@ export default class InputRange extends React.Component { { this.props.maxValue } + { children } + { renderHiddenInputs(this) } ); @@ -610,6 +613,10 @@ export default class InputRange extends React.Component { * @property {Function} onChangeComplete * @property {Function} step * @property {Function} value + * @property {Function} Track + * @property {Function} Slider + * @property {Function} Label + * @property {Function} children */ InputRange.propTypes = { ariaLabelledby: React.PropTypes.string, @@ -627,6 +634,10 @@ InputRange.propTypes = { onChangeComplete: React.PropTypes.func, step: React.PropTypes.number, value: maxMinValuePropType, + Track: React.PropTypes.func, + Slider: React.PropTypes.func, + Label: React.PropTypes.func, + children: React.PropTypes.any, }; /** @@ -641,6 +652,9 @@ InputRange.propTypes = { * @property {number} minValue * @property {number} step * @property {Range|number} value + * @property {Function} Track + * @property {Function} Slider + * @property {Function} Label */ InputRange.defaultProps = { classNames: defaultClassNames, @@ -652,4 +666,7 @@ InputRange.defaultProps = { minValue: 0, step: 1, value: null, + Track: DefaultTrack, + Slider: DefaultSlider, + Label: DefaultLabel, }; diff --git a/src/InputRange/Slider.js b/src/InputRange/Slider.js index a9eea39..9df40b5 100644 --- a/src/InputRange/Slider.js +++ b/src/InputRange/Slider.js @@ -3,7 +3,7 @@ */ import React from 'react'; -import Label from './Label'; +import { default as DefaultLabel } from './Label'; import { autobind } from './util'; /** @@ -144,7 +144,7 @@ export default class Slider extends React.Component { * @return {string} Component JSX */ render() { - const classNames = this.props.classNames; + const { classNames, Label, children } = this.props; const style = getStyle(this); return ( @@ -174,6 +174,8 @@ export default class Slider extends React.Component { onTouchStart={ this.handleTouchStart } role="slider"> + + { children } ); } @@ -193,6 +195,8 @@ export default class Slider extends React.Component { * @property {Function} percentage * @property {Function} type * @property {Function} value + * @property {Function} Label + * @property {Function} children */ Slider.propTypes = { ariaLabelledby: React.PropTypes.string, @@ -206,4 +210,13 @@ Slider.propTypes = { percentage: React.PropTypes.number.isRequired, type: React.PropTypes.string.isRequired, value: React.PropTypes.number.isRequired, + Label: React.PropTypes.func, + children: React.PropTypes.any, +}; + +/** + * @property {Function} Label + */ +Slider.defaultProps = { + Label: DefaultLabel, }; diff --git a/src/InputRange/index.js b/src/InputRange/index.js index 1efe83a..5951dad 100644 --- a/src/InputRange/index.js +++ b/src/InputRange/index.js @@ -3,6 +3,9 @@ */ import InputRange from './InputRange'; +import Track from './Track'; +import Slider from './Slider'; +import Label from './Label'; /** * An object describing the position of a point @@ -19,3 +22,4 @@ import InputRange from './InputRange'; */ export default InputRange; +export {Track, Slider, Label}; From 53d2e4d1e8dca2add2c8d9fe8575c9aa35e9d36c Mon Sep 17 00:00:00 2001 From: Richard Palmer Date: Thu, 26 Jan 2017 11:03:45 +0000 Subject: [PATCH 2/6] Allow input labels to be shown/hidden Adds a `showLabel` prop for hidding the labels --- src/InputRange/InputRange.js | 47 +++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/InputRange/InputRange.js b/src/InputRange/InputRange.js index ee1cd64..0af23d5 100644 --- a/src/InputRange/InputRange.js +++ b/src/InputRange/InputRange.js @@ -550,7 +550,7 @@ export default class InputRange extends React.Component { * @return {string} Component JSX */ render() { - const { classNames, Label, Track, children } = this.props; + const { classNames, Label, Track, children, showLabel } = this.props; const componentClassName = getComponentClassName(this); const values = valueTransformer.valuesFromProps(this); const percentages = valueTransformer.percentagesFromValues(this, values); @@ -564,12 +564,14 @@ export default class InputRange extends React.Component { onKeyUp={ this.handleKeyUp } onMouseDown={ this.handleMouseDown } onTouchStart={ this.handleTouchStart }> - + {showLabel && ( + + )} - + {showLabel && ( + + )} { children } @@ -598,17 +602,17 @@ export default class InputRange extends React.Component { /** * Accepted propTypes of InputRange * @static {Object} - * @property {Function} ariaLabelledby + * @property {String} ariaLabelledby * @property {Function} ariaControls - * @property {Function} classNames - * @property {Function} defaultValue - * @property {Function} disabled + * @property {Object} classNames + * @property {String|Number} defaultValue + * @property {Boolean} disabled * @property {Function} formatLabel * @property {Function} labelPrefix * @property {Function} labelSuffix - * @property {Function} maxValue - * @property {Function} minValue - * @property {Function} name + * @property {Number} maxValue + * @property {Number} minValue + * @property {String} name * @property {Function} onChange * @property {Function} onChangeComplete * @property {Function} step @@ -617,6 +621,7 @@ export default class InputRange extends React.Component { * @property {Function} Slider * @property {Function} Label * @property {Function} children + * @property {Boolean} showLabel */ InputRange.propTypes = { ariaLabelledby: React.PropTypes.string, @@ -638,6 +643,7 @@ InputRange.propTypes = { Slider: React.PropTypes.func, Label: React.PropTypes.func, children: React.PropTypes.any, + showLabel: React.PropTypes.bool, }; /** @@ -669,4 +675,5 @@ InputRange.defaultProps = { Track: DefaultTrack, Slider: DefaultSlider, Label: DefaultLabel, + showLabel: true, }; From 1164b8eeaae08d1ac8c9a0df7f8988ef97b49b74 Mon Sep 17 00:00:00 2001 From: Richard Palmer Date: Thu, 26 Jan 2017 11:10:19 +0000 Subject: [PATCH 3/6] Remove unnecessary passing of component ref in callback methods Changes `onChange` and `onChangeComplete` to simply return the range's value(s) as opposed to a reference to the component, `this` and the value(s) --- example/js/App.js | 14 +++++++------- src/InputRange/InputRange.js | 6 +++--- test/InputRange.spec.js | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/example/js/App.js b/example/js/App.js index fedacae..aba5519 100644 --- a/example/js/App.js +++ b/example/js/App.js @@ -24,43 +24,43 @@ class App extends React.Component { }; } - handleValueChange(component, value) { + handleValueChange(value) { this.setState({ value: value || 0, }); } - handleValue2Change(component, value) { + handleValue2Change(value) { this.setState({ value2: value || 0, }); } - handleValue3Change(component, value) { + handleValue3Change(value) { this.setState({ value3: value || 0, }); } - handleValue4Change(component, values) { + handleValue4Change(values) { this.setState({ value4: values, }); } - handleValue5Change(component, values) { + handleValue5Change(values) { this.setState({ value5: values, }); } - handleValue6Change(component, values) { + handleValue6Change(values) { this.setState({ value6: values, }); } - handleChangeComplete(component, value) { + handleChangeComplete(value) { console.log(value); } diff --git a/src/InputRange/InputRange.js b/src/InputRange/InputRange.js index 0af23d5..a244b07 100644 --- a/src/InputRange/InputRange.js +++ b/src/InputRange/InputRange.js @@ -342,9 +342,9 @@ export default class InputRange extends React.Component { } if (this.isMultiValue) { - this.props.onChange(this, values); + this.props.onChange(values); } else { - this.props.onChange(this, values.max); + this.props.onChange(values.max); } } @@ -475,7 +475,7 @@ export default class InputRange extends React.Component { } if (_this.startValue !== this.props.value) { - this.props.onChangeComplete(this, this.props.value); + this.props.onChangeComplete(this.props.value); } _this.startValue = null; diff --git a/test/InputRange.spec.js b/test/InputRange.spec.js index d6cef12..b80be8f 100644 --- a/test/InputRange.spec.js +++ b/test/InputRange.spec.js @@ -78,7 +78,7 @@ describe('InputRange', () => { it('should call `onChange` callback', () => { inputRange.updateValues(newValues); - expect(onChange).toHaveBeenCalledWith(inputRange, newValues); + expect(onChange).toHaveBeenCalledWith(newValues); }); }); @@ -92,7 +92,7 @@ describe('InputRange', () => { it('should call `onChange` callback', () => { inputRange.updateValues(newValues); - expect(onChange).toHaveBeenCalledWith(inputRange, newValues.max); + expect(onChange).toHaveBeenCalledWith(newValues.max); }); }); }); @@ -484,7 +484,7 @@ describe('InputRange', () => { ); slider.dispatchEvent(mouseUpEvent); - expect(onChangeComplete).toHaveBeenCalledWith(inputRange, value); + expect(onChangeComplete).toHaveBeenCalledWith(value); }); it('should call onChangeComplete if value has changed since the start of interaction when only defaultValue was provided', () => { @@ -501,7 +501,7 @@ describe('InputRange', () => { ); slider.dispatchEvent(mouseUpEvent); - expect(onChangeComplete).toHaveBeenCalledWith(inputRange, value); + expect(onChangeComplete).toHaveBeenCalledWith(value); }); it('should not call onChangeComplete if value has not changed since the start of interaction', () => { From e6c44df35fe86aaf4bb770a405bf329b1d745190 Mon Sep 17 00:00:00 2001 From: Richard Palmer Date: Thu, 26 Jan 2017 14:45:24 +0000 Subject: [PATCH 4/6] Remove ownerDocument refs in favour of relying on `window.document` --- src/InputRange/InputRange.js | 20 -------------------- src/InputRange/Slider.js | 20 -------------------- 2 files changed, 40 deletions(-) diff --git a/src/InputRange/InputRange.js b/src/InputRange/InputRange.js index a244b07..0a3ac03 100644 --- a/src/InputRange/InputRange.js +++ b/src/InputRange/InputRange.js @@ -76,18 +76,6 @@ function shouldUpdate(inputRange, values) { hasStepDifference(inputRange, values); } -/** - * Get the owner document of inputRange - * @private - * @param {InputRange} inputRange - React component - * @return {Document} Document - */ -function getDocument(inputRange) { - const { inputRange: { ownerDocument } } = inputRange.refs; - - return ownerDocument; -} - /** * Get the class name(s) of inputRange based on its props * @private @@ -502,8 +490,6 @@ export default class InputRange extends React.Component { * @param {SyntheticEvent} event - User event */ handleMouseDown(event) { - const document = getDocument(this); - this.handleInteractionStart(event); document.addEventListener('mouseup', this.handleMouseUp); @@ -514,8 +500,6 @@ export default class InputRange extends React.Component { * @param {SyntheticEvent} event - User event */ handleMouseUp(event) { - const document = getDocument(this); - this.handleInteractionEnd(event); document.removeEventListener('mouseup', this.handleMouseUp); @@ -526,8 +510,6 @@ export default class InputRange extends React.Component { * @param {SyntheticEvent} event - User event */ handleTouchStart(event) { - const document = getDocument(this); - this.handleInteractionStart(event); document.addEventListener('touchend', this.handleTouchEnd); @@ -538,8 +520,6 @@ export default class InputRange extends React.Component { * @param {SyntheticEvent} event - User event */ handleTouchEnd(event) { - const document = getDocument(this); - this.handleInteractionEnd(event); document.removeEventListener('touchend', this.handleTouchEnd); diff --git a/src/InputRange/Slider.js b/src/InputRange/Slider.js index 9df40b5..7ab8380 100644 --- a/src/InputRange/Slider.js +++ b/src/InputRange/Slider.js @@ -6,18 +6,6 @@ import React from 'react'; import { default as DefaultLabel } from './Label'; import { autobind } from './util'; -/** - * Get the owner document of slider - * @private - * @param {Slider} slider - React component - * @return {Document} Document - */ -function getDocument(slider) { - const { slider: { ownerDocument } } = slider.refs; - - return ownerDocument; -} - /** * Get the style of slider based on its props * @private @@ -70,8 +58,6 @@ export default class Slider extends React.Component { * @param {SyntheticEvent} event - User event */ handleMouseDown() { - const document = getDocument(this); - // Event document.addEventListener('mousemove', this.handleMouseMove); document.addEventListener('mouseup', this.handleMouseUp); @@ -82,8 +68,6 @@ export default class Slider extends React.Component { * @param {SyntheticEvent} event - User event */ handleMouseUp() { - const document = getDocument(this); - // Event document.removeEventListener('mousemove', this.handleMouseMove); document.removeEventListener('mouseup', this.handleMouseUp); @@ -102,8 +86,6 @@ export default class Slider extends React.Component { * @param {SyntheticEvent} event - User event */ handleTouchStart(event) { - const document = getDocument(this); - event.preventDefault(); document.addEventListener('touchmove', this.handleTouchMove); @@ -123,8 +105,6 @@ export default class Slider extends React.Component { * @param {SyntheticEvent} event - User event */ handleTouchEnd(event) { - const document = getDocument(this); - event.preventDefault(); document.removeEventListener('touchmove', this.handleTouchMove); From a0be0f59018f21b105a1bffc14519177b8a2784c Mon Sep 17 00:00:00 2001 From: Richard Palmer Date: Mon, 30 Jan 2017 10:50:32 +0000 Subject: [PATCH 5/6] Fix useless `renderHiddenInputs` method - Removes unnecessary `renderHiddenInputs` method, moving the logic inline to the render method - Fixes the logic to ensure the loop actually returns hidden inputs - Fixes hidden inputs so they render with values - Adds a prop for switching the hidden inputs on/off --- example/js/App.js | 5 +++++ src/InputRange/InputRange.js | 33 ++++++++++++++++----------------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/example/js/App.js b/example/js/App.js index aba5519..7446388 100644 --- a/example/js/App.js +++ b/example/js/App.js @@ -78,6 +78,7 @@ class App extends React.Component { return (
} Array of HTML */ -function renderHiddenInputs(inputRange) { - const inputs = []; - const keys = getKeys(inputRange); - - for (const key of keys) { - const name = inputRange.isMultiValue ? `${inputRange.props.name}${captialize(key)}` : inputRange.props.name; - - const input = ( - - ); - } - - return inputs; -} /** * InputRange React component @@ -530,7 +516,14 @@ export default class InputRange extends React.Component { * @return {string} Component JSX */ render() { - const { classNames, Label, Track, children, showLabel } = this.props; + const { + classNames, + Label, + Track, + children, + showLabel, + renderHiddenInputs, + } = this.props; const componentClassName = getComponentClassName(this); const values = valueTransformer.valuesFromProps(this); const percentages = valueTransformer.percentagesFromValues(this, values); @@ -573,7 +566,11 @@ export default class InputRange extends React.Component { { children } - { renderHiddenInputs(this) } + { renderHiddenInputs && getKeys(this).map((key) => { + const name = this.isMultiValue ? `${this.props.name}${captialize(key)}` : this.props.name; + const value = this.isMultiValue ? this.props.value[key] : this.props.value; + return ; + }) } ); } @@ -614,7 +611,7 @@ InputRange.propTypes = { labelSuffix: React.PropTypes.string, maxValue: maxMinValuePropType, minValue: maxMinValuePropType, - name: React.PropTypes.string, + name: React.PropTypes.string.isRequired, onChange: React.PropTypes.func.isRequired, onChangeComplete: React.PropTypes.func, step: React.PropTypes.number, @@ -624,6 +621,7 @@ InputRange.propTypes = { Label: React.PropTypes.func, children: React.PropTypes.any, showLabel: React.PropTypes.bool, + renderHiddenInputs: React.PropTypes.bool, }; /** @@ -656,4 +654,5 @@ InputRange.defaultProps = { Slider: DefaultSlider, Label: DefaultLabel, showLabel: true, + renderHiddenInputs: true, }; From 1cfa76df2bf9de78a45e4a89c6d01c7c596bbc45 Mon Sep 17 00:00:00 2001 From: Richard Palmer Date: Mon, 30 Jan 2017 12:08:16 +0000 Subject: [PATCH 6/6] Update package.json to publish to @appearhere scope - Scopes the package to @appearhere - Adds custom field of `parentVersion`, denoting the last merged version of `davidchin/react-input-range` --- package.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index a537cce..e74755f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,11 @@ { - "name": "react-input-range", + "name": "@appearhere/react-input-range", "version": "0.10.0", + "parentVersion": "0.10.0", "description": "React component for inputting numeric values within a range", + "publishConfig": { + "access": "restricted" + }, "keywords": [ "react", "react-component", @@ -12,9 +16,10 @@ "form", "input" ], + "homepage": "https://github.com/appearhere/react-input-range", "repository": { "type": "git", - "url": "https://github.com/davidchin/react-input-range.git" + "url": "https://github.com/appearhere/react-input-range.git" }, "main": "lib/InputRange/index.js", "types": "react-input-range.d.ts",