From e479638280dc71f42427a8bbb3530fd628bb1e55 Mon Sep 17 00:00:00 2001 From: Martin Blatter Date: Thu, 7 Jul 2016 15:00:26 +0200 Subject: [PATCH 1/4] added vertical option --- src/InputRange/InputRange.js | 26 ++++++++++++++++++------- src/InputRange/Slider.js | 12 ++++++++++++ src/InputRange/Track.js | 30 +++++++++++++++++++++++++++-- src/InputRange/valueTransformer.js | 31 ++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 9 deletions(-) diff --git a/src/InputRange/InputRange.js b/src/InputRange/InputRange.js index 0171d0f..00d28e1 100644 --- a/src/InputRange/InputRange.js +++ b/src/InputRange/InputRange.js @@ -97,11 +97,16 @@ function getDocument(inputRange) { function getComponentClassName(inputRange) { const { props } = inputRange; + let verticalClass = ''; + if (props.orientation === 'vertical') { + verticalClass = ' vertical'; + } + if (!props.disabled) { - return props.classNames.component; + return props.classNames.component + verticalClass; } - return `${props.classNames.component} is-disabled`; + return `${props.classNames.component} is-disabled ${verticalClass}`; } /** @@ -196,7 +201,8 @@ function renderSliders(inputRange) { percentage={ percentage } ref={ ref } type={ key } - value={ value } /> + value={ value } + orientation={ inputRange.props.orientation }/> ); sliders.push(slider); @@ -444,7 +450,6 @@ export default class InputRange extends React.Component { event.preventDefault(); const key = getKeyByPosition(this, position); - this.updatePosition(key, position); } @@ -566,7 +571,8 @@ export default class InputRange extends React.Component { @@ -574,7 +580,8 @@ export default class InputRange extends React.Component { classNames={ classNames } ref="track" percentages={ percentages } - onTrackMouseDown={ this.handleTrackMouseDown }> + onTrackMouseDown={ this.handleTrackMouseDown } + orientation={this.props.orientation}> { renderSliders(this) } @@ -582,7 +589,8 @@ export default class InputRange extends React.Component { @@ -610,6 +618,7 @@ export default class InputRange extends React.Component { * @property {Function} onChangeComplete * @property {Function} step * @property {Function} value + * @property {Function} orientation */ InputRange.propTypes = { ariaLabelledby: React.PropTypes.string, @@ -627,6 +636,7 @@ InputRange.propTypes = { onChangeComplete: React.PropTypes.func, step: React.PropTypes.number, value: maxMinValuePropType, + orientation: React.PropTypes.string, }; /** @@ -641,6 +651,7 @@ InputRange.propTypes = { * @property {number} minValue * @property {number} step * @property {Range|number} value + * @property {string} orientation */ InputRange.defaultProps = { classNames: defaultClassNames, @@ -652,4 +663,5 @@ InputRange.defaultProps = { minValue: 0, step: 1, value: null, + orientation: 'horizontal', }; diff --git a/src/InputRange/Slider.js b/src/InputRange/Slider.js index 86d2c75..9ff5abb 100644 --- a/src/InputRange/Slider.js +++ b/src/InputRange/Slider.js @@ -26,6 +26,16 @@ function getDocument(slider) { */ function getStyle(slider) { const perc = (slider.props.percentage || 0) * 100; + + if (slider.props.orientation === 'vertical') { + const style = { + position: 'absolute', + bottom: `${perc}%`, + }; + + return style; + } + const style = { position: 'absolute', left: `${perc}%`, @@ -193,6 +203,7 @@ export default class Slider extends React.Component { * @property {Function} percentage * @property {Function} type * @property {Function} value + * @property {Function} orientation */ Slider.propTypes = { ariaLabelledby: React.PropTypes.string, @@ -206,4 +217,5 @@ Slider.propTypes = { percentage: React.PropTypes.number.isRequired, type: React.PropTypes.string.isRequired, value: React.PropTypes.number.isRequired, + orientation: React.PropTypes.string, }; diff --git a/src/InputRange/Track.js b/src/InputRange/Track.js index 80e565a..9f752c2 100644 --- a/src/InputRange/Track.js +++ b/src/InputRange/Track.js @@ -13,6 +13,19 @@ import { autobind } from './util'; */ function getActiveTrackStyle(track) { const { props } = track; + + if ( props.orientation === 'vertical' ) { + const height = `${(props.percentages.max - props.percentages.min) * 100}%`; + const top = `${100 - (props.percentages.max * 100)}%`; + + const activeTrackStyle = { + top, + height, + }; + + return activeTrackStyle; + } + const width = `${(props.percentages.max - props.percentages.min) * 100}%`; const left = `${props.percentages.min * 100}%`; @@ -57,13 +70,24 @@ export default class Track extends React.Component { * @param {SyntheticEvent} event - User event */ handleMouseDown(event) { - const trackClientRect = this.clientRect; + let trackClientRect = this.clientRect; const { clientX } = event.touches ? event.touches[0] : event; - const position = { + + let position = { x: clientX - trackClientRect.left, y: 0, }; + if (this.props.orientation === 'vertical') { + trackClientRect = this.clientRect; + const { clientY } = event.touches ? event.touches[0] : event; + + position = { + x: 0, + y: trackClientRect.bottom - clientY, + }; + } + this.props.onTrackMouseDown(event, this, position); } @@ -108,10 +132,12 @@ export default class Track extends React.Component { * @property {Function} classNames * @property {Function} onTrackMouseDown * @property {Function} percentages + * @property {Function} orientation */ Track.propTypes = { children: React.PropTypes.node, classNames: React.PropTypes.objectOf(React.PropTypes.string), onTrackMouseDown: React.PropTypes.func.isRequired, percentages: React.PropTypes.objectOf(React.PropTypes.number).isRequired, + orientation: React.PropTypes.string, }; diff --git a/src/InputRange/valueTransformer.js b/src/InputRange/valueTransformer.js index 487baf9..a79b15c 100644 --- a/src/InputRange/valueTransformer.js +++ b/src/InputRange/valueTransformer.js @@ -12,6 +12,13 @@ import { clamp, isEmpty, isNumber, objectOf } from './util'; * @return {number} Percentage value */ function percentageFromPosition(inputRange, position) { + if (inputRange.props.orientation === 'vertical') { + const length = inputRange.trackClientRect.height; + const sizePerc = position.y / length; + + return sizePerc || 0; + } + const length = inputRange.trackClientRect.width; const sizePerc = position.x / length; @@ -98,6 +105,17 @@ function percentagesFromValues(inputRange, values) { * @return {Point} Position */ function positionFromValue(inputRange, value) { + if (inputRange.props.orientation === 'vertical') { + const length = inputRange.trackClientRect.height; + const valuePerc = percentageFromValue(inputRange, value); + const positionValue = valuePerc * length; + + return { + x: 0, + y: positionValue, + }; + } + const length = inputRange.trackClientRect.width; const valuePerc = percentageFromValue(inputRange, value); const positionValue = valuePerc * length; @@ -132,6 +150,19 @@ function positionsFromValues(inputRange, values) { * @return {Point} */ function positionFromEvent(inputRange, event) { + if (inputRange.props.orientation === 'vertical') { + const trackClientRect = inputRange.trackClientRect; + const length = trackClientRect.height; + const { clientY } = event.touches ? event.touches[0] : event; + + const position = { + x: 0, + y: clamp(trackClientRect.bottom - clientY, 0, length), + }; + + return position; + } + const trackClientRect = inputRange.trackClientRect; const length = trackClientRect.width; const { clientX } = event.touches ? event.touches[0] : event; From 1e38d8f6306c12d21b58ae8ee6c6e8672995bcbd Mon Sep 17 00:00:00 2001 From: Martin Blatter Date: Thu, 7 Jul 2016 15:17:57 +0200 Subject: [PATCH 2/4] added scss for vertical rangeslider --- scss/InputRange.scss | 6 ++++++ scss/_InputRangeLabel.scss | 15 +++++++++++++++ scss/_InputRangeSlider.scss | 4 ++++ scss/_InputRangeTrack.scss | 9 +++++++++ 4 files changed, 34 insertions(+) diff --git a/scss/InputRange.scss b/scss/InputRange.scss index fd5b0c4..c7f3882 100644 --- a/scss/InputRange.scss +++ b/scss/InputRange.scss @@ -10,3 +10,9 @@ position: relative; width: 100%; } + +.InputRange.vertical { + height: 100%; + width: $InputRange-slider-height; + min-height: 200px; +} \ No newline at end of file diff --git a/scss/_InputRangeLabel.scss b/scss/_InputRangeLabel.scss index 9882416..9069630 100644 --- a/scss/_InputRangeLabel.scss +++ b/scss/_InputRangeLabel.scss @@ -23,3 +23,18 @@ position: absolute; top: -1.8rem; } + +.vertical .InputRange-label--min { + bottom: 0; + left: 1.75rem; +} + +.vertical .InputRange-label--max { + right: -0.5rem; + top: 0; +} + +.vertical .InputRange-label--value { + left: 1.5rem; + top: -0.5rem; +} \ No newline at end of file diff --git a/scss/_InputRangeSlider.scss b/scss/_InputRangeSlider.scss index fefc15d..a7a031e 100644 --- a/scss/_InputRangeSlider.scss +++ b/scss/_InputRangeSlider.scss @@ -33,3 +33,7 @@ .InputRange-sliderContainer { transition: $InputRange-sliderContainer-transition; } + +.vertical .InputRange-slider { + margin-left: $InputRange-slider-width / -4; +} \ No newline at end of file diff --git a/scss/_InputRangeTrack.scss b/scss/_InputRangeTrack.scss index 568ccd1..84dde84 100644 --- a/scss/_InputRangeTrack.scss +++ b/scss/_InputRangeTrack.scss @@ -22,3 +22,12 @@ .InputRange-track--active { background: $InputRange-track--active-background; } + +.vertical .InputRange-track--container { + margin-top: 0; + top: 0; + bottom: 0; + left: 50%; + margin-left: -0.5 * $InputRange-track-height; + height: 100%; +} \ No newline at end of file From a2782d650813f8ae6d3aa57fa343bafcdc44f5b7 Mon Sep 17 00:00:00 2001 From: Martin Blatter Date: Thu, 7 Jul 2016 15:21:43 +0200 Subject: [PATCH 3/4] added beyondadmin theme style css --- css/react-input-range-beyondadmin.css | 112 ++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 css/react-input-range-beyondadmin.css diff --git a/css/react-input-range-beyondadmin.css b/css/react-input-range-beyondadmin.css new file mode 100644 index 0000000..2e9afec --- /dev/null +++ b/css/react-input-range-beyondadmin.css @@ -0,0 +1,112 @@ +.InputRange { + height: 16px; + border: 1px solid #6c6c6c; + background-color: #ffffff; +} + +.InputRange-track--container { + top: 3px; + left: 1px; + background-color: #ffffff; +} + +.InputRange-track { + height: 14px; +} + +.InputRange-track--active { + background-color: #57b5e3; + border-radius: 0; +} + +.InputRange-label { + font-size: 13px; + color: #3f3f3f; +} + +.InputRange-slider { + top: 7px; + margin-top: 0; + height: 20px; + background-color: #F55F51; + border: 0; + border-radius: 0; + width: 40px; + margin-left: -20px; +} + +.InputRange-label--value { + top: -1px; + margin-left: -8px; + position: absolute; + display: block; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-bottom: 8px solid #fb6e52; +} + +.InputRange-label--value .InputRange-labelContainer { + padding-top: 2px; + top: 8px; + z-index: 50; + left: -20px; + color: #ffffff; + width: 40px; + height: 18px; + position: absolute; + text-align: center; + background-color: #fb6e52; +} + +.InputRange-sliderContainer a { + z-index: 100; + background-color: transparent; +} + +/* +* vertical styles +*/ + +.InputRange.vertical { + width: 16px; +} + +.vertical .InputRange-track--container { + margin-bottom: 1px; + margin-left: 0; + left: 1px; + width: 14px; +} + +.vertical .InputRange-label--value { + top: -6px; + margin-left: -18px; + position: absolute; + display: block; + z-index: 50; + border-right: 6px solid #fb6e52; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; +} + +.vertical .InputRange-label--value .InputRange-labelContainer { + top: -10px; + left: 6px; + padding: 2px 5px 0 5px; + width: auto; +} + +.vertical .InputRange-slider { + top: -10px; + left: 24px; +} + +.vertical .InputRange-label--max { + right: -14px; + top: -10px; +} + +.vertical .InputRange-label--min { + left: 28px; + bottom: -10px; +} \ No newline at end of file From 66e84e3f4a438ae0ff784aabca33bff2b832fdfe Mon Sep 17 00:00:00 2001 From: Martin Blatter Date: Tue, 12 Jul 2016 12:01:42 +0200 Subject: [PATCH 4/4] updated dist --- .../react-input-range-beyondadmin.css | 0 dist/react-input-range.css | 37 +++++++++++++++++++ dist/react-input-range.min.css | 2 +- 3 files changed, 38 insertions(+), 1 deletion(-) rename {css => dist}/react-input-range-beyondadmin.css (100%) diff --git a/css/react-input-range-beyondadmin.css b/dist/react-input-range-beyondadmin.css similarity index 100% rename from css/react-input-range-beyondadmin.css rename to dist/react-input-range-beyondadmin.css diff --git a/dist/react-input-range.css b/dist/react-input-range.css index 6efc526..b7361be 100644 --- a/dist/react-input-range.css +++ b/dist/react-input-range.css @@ -83,3 +83,40 @@ height: 1rem; position: relative; width: 100%; } + +/* + styles for vertical slider +*/ +.InputRange.vertical { + height: 100%; + width: 1rem; + min-height: 200px; +} + +.vertical .InputRange-track--container { + margin-top: 0; + top: 0; + bottom: 0; + left: 50%; + margin-left: -0.15rem; + height: 100%; +} + +.vertical .InputRange-slider { + margin-left: -0.25rem; +} + +.vertical .InputRange-label--min { + bottom: 0; + left: 1.75rem; +} + +.vertical .InputRange-label--max { + right: -0.5rem; + top: 0; +} + +.vertical .InputRange-label--value { + left: 1.5rem; + top: -0.5rem; +} diff --git a/dist/react-input-range.min.css b/dist/react-input-range.min.css index 6933731..56b88f1 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.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;white-space:nowrap}.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 +.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;white-space:nowrap}.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%}.InputRange.vertical{height:100%;width:1rem;min-height:200px}.vertical .InputRange-track--container{margin-top:0;top:0;bottom:0;left:50%;margin-left:-.15rem;height:100%}.vertical .InputRange-slider{margin-left:-.25rem}.vertical .InputRange-label--min{bottom:0;left:1.75rem}.vertical .InputRange-label--max{right:-.5rem;top:0}.vertical .InputRange-label--value{left:1.5rem;top:-.5rem} \ No newline at end of file