feat(ui-toolkit): remove slider
BREAKING
This commit is contained in:
parent
0be8553e29
commit
48b9aef8cb
@ -16,7 +16,6 @@ export { default as Divider } from './divider';
|
||||
export { default as Editor } from './editor';
|
||||
export { default as IconButton } from './icon-button';
|
||||
export { default as StatusLoader } from './status-loader';
|
||||
export { default as Slider } from './slider';
|
||||
|
||||
export { default as Breadcrumb, Item as BreadcrumbItem } from './breadcrumb';
|
||||
|
||||
|
@ -1,17 +0,0 @@
|
||||
### Double Range Slider
|
||||
|
||||
```jsx
|
||||
const React = require('react');
|
||||
const { default: Slider } = require('./slider');
|
||||
|
||||
<Slider
|
||||
minValue={0.25}
|
||||
maxValue={8}
|
||||
step={0.25}
|
||||
value={{ min: 4, max: 4 }}
|
||||
onChangeComplete={value => console.log(value)}
|
||||
onChange={value => console.log(value)}
|
||||
>
|
||||
vCPUs
|
||||
</Slider>;
|
||||
```
|
@ -1,77 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import InputRange from './react-input-range';
|
||||
import remcalc from 'remcalc';
|
||||
|
||||
import FormLabel from '../form/label';
|
||||
|
||||
const Label = styled(FormLabel)`
|
||||
margin-bottom: ${remcalc(10)};
|
||||
margin-top: ${remcalc(12)};
|
||||
`;
|
||||
|
||||
class Slider extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
minValue: this.props.minValue,
|
||||
maxValue: this.props.maxValue,
|
||||
value: this.props.value
|
||||
};
|
||||
|
||||
this.changeValue = this.changeValue.bind(this);
|
||||
}
|
||||
|
||||
changeValue(value) {
|
||||
this.setState({ value }, () => this.props.onChange(value));
|
||||
}
|
||||
|
||||
render() {
|
||||
const { minValue, maxValue, value } = this.state;
|
||||
const { children, ...rest } = this.props;
|
||||
return (
|
||||
<div>
|
||||
<Label>{children}</Label>
|
||||
<InputRange
|
||||
{...rest}
|
||||
minValue={minValue}
|
||||
maxValue={maxValue}
|
||||
value={value}
|
||||
onChange={value => this.changeValue(value)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Slider.propTypes = {
|
||||
minValue: PropTypes.number,
|
||||
maxValue: PropTypes.number,
|
||||
step: PropTypes.number,
|
||||
value: PropTypes.oneOfType([PropTypes.number, PropTypes.shape()]),
|
||||
onChangeComplete: PropTypes.func,
|
||||
onChange: PropTypes.func,
|
||||
formatLabel: PropTypes.func,
|
||||
ariaLabelledby: PropTypes.string,
|
||||
ariaControls: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
draggableTrack: PropTypes.bool,
|
||||
onChangeStart: PropTypes.func,
|
||||
children: PropTypes.node,
|
||||
greyed: PropTypes.bool
|
||||
};
|
||||
|
||||
Slider.defaultProps = {
|
||||
onChangeComplete: () => {},
|
||||
onChange: () => {},
|
||||
formatLabel: value =>
|
||||
(value.toString().split('.')[1] || []).length > 3
|
||||
? Math.round(value).toFixed(3)
|
||||
: value,
|
||||
onChangeStart: () => {},
|
||||
step: 1
|
||||
};
|
||||
|
||||
export default Slider;
|
@ -1,3 +0,0 @@
|
||||
import InputRange from './input-range/input-range';
|
||||
|
||||
export default InputRange;
|
@ -1,730 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import * as valueTransformer from './value-transformer';
|
||||
import rangePropType from './range-prop-type';
|
||||
import valuePropType from './value-prop-type';
|
||||
import Slider from './slider';
|
||||
import Track from './track';
|
||||
import { captialize, distanceTo, isDefined, isObject, length } from '../utils';
|
||||
import styled from 'styled-components';
|
||||
import remcalc from 'remcalc';
|
||||
|
||||
export const RangeStyled = styled.div`
|
||||
position: relative;
|
||||
min-height: ${remcalc(10)};
|
||||
`;
|
||||
|
||||
/**
|
||||
* A React component that allows users to input numeric values within a range
|
||||
* by dragging its sliders.
|
||||
*/
|
||||
export default class InputRange extends Component {
|
||||
/**
|
||||
* @ignore
|
||||
* @override
|
||||
* @return {Object}
|
||||
*/
|
||||
static get propTypes() {
|
||||
return {
|
||||
ariaLabelledby: PropTypes.string,
|
||||
ariaControls: PropTypes.string,
|
||||
classNames: PropTypes.objectOf(PropTypes.string),
|
||||
disabled: PropTypes.bool,
|
||||
draggableTrack: PropTypes.bool,
|
||||
formatLabel: PropTypes.func,
|
||||
maxValue: rangePropType,
|
||||
minValue: rangePropType,
|
||||
name: PropTypes.string,
|
||||
onChangeStart: PropTypes.func,
|
||||
onChange: PropTypes.func,
|
||||
onChangeComplete: PropTypes.func,
|
||||
step: PropTypes.number,
|
||||
value: valuePropType
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @override
|
||||
* @return {Object}
|
||||
*/
|
||||
static get defaultProps() {
|
||||
return {
|
||||
disabled: false,
|
||||
maxValue: 10,
|
||||
minValue: 0,
|
||||
step: 1
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} props
|
||||
* @param {string} [props.ariaLabelledby]
|
||||
* @param {string} [props.ariaControls]
|
||||
* @param {InputRangeClassNames} [props.classNames]
|
||||
* @param {boolean} [props.disabled = false]
|
||||
* @param {Function} [props.formatLabel]
|
||||
* @param {number|Range} [props.maxValue = 10]
|
||||
* @param {number|Range} [props.minValue = 0]
|
||||
* @param {string} [props.name]
|
||||
* @param {string} props.onChange
|
||||
* @param {Function} [props.onChangeComplete]
|
||||
* @param {Function} [props.onChangeStart]
|
||||
* @param {number} [props.step = 1]
|
||||
* @param {number|Range} props.value
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?number}
|
||||
*/
|
||||
this.startValue = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?Component}
|
||||
*/
|
||||
this.node = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?Component}
|
||||
*/
|
||||
this.trackNode = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {bool}
|
||||
*/
|
||||
this.isSliderDragging = false;
|
||||
|
||||
this.handleSliderDrag = this.handleSliderDrag.bind(this);
|
||||
this.handleTrackDrag = this.handleTrackDrag.bind(this);
|
||||
this.handleTrackMouseDown = this.handleTrackMouseDown.bind(this);
|
||||
this.handleInteractionStart = this.handleInteractionStart.bind(this);
|
||||
this.handleInteractionEnd = this.handleInteractionEnd.bind(this);
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||
this.handleMouseDown = this.handleMouseDown.bind(this);
|
||||
this.handleMouseUp = this.handleMouseUp.bind(this);
|
||||
this.handleKeyUp = this.handleKeyUp.bind(this);
|
||||
this.handleTouchStart = this.handleTouchStart.bind(this);
|
||||
this.handleTouchEnd = this.handleTouchEnd.bind(this);
|
||||
|
||||
this.state = {
|
||||
value: this.props.value
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @override
|
||||
* @return {void}
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
this.removeDocumentMouseUpListener();
|
||||
this.removeDocumentTouchEndListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the bounding rect of the track
|
||||
* @private
|
||||
* @return {ClientRect}
|
||||
*/
|
||||
getTrackClientRect() {
|
||||
return this.trackNode && this.trackNode.getClientRect();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the slider key closest to a point
|
||||
* @private
|
||||
* @param {Point} position
|
||||
* @return {string}
|
||||
*/
|
||||
getKeyByPosition(position) {
|
||||
const values = valueTransformer.getValueFromProps(
|
||||
this.props,
|
||||
this.isMultiValue()
|
||||
);
|
||||
const positions = valueTransformer.getPositionsFromValues(
|
||||
values,
|
||||
this.props.minValue,
|
||||
this.props.maxValue,
|
||||
this.getTrackClientRect()
|
||||
);
|
||||
|
||||
if (this.isMultiValue()) {
|
||||
const distanceToMin = distanceTo(position, positions.min);
|
||||
const distanceToMax = distanceTo(position, positions.max);
|
||||
|
||||
if (distanceToMin < distanceToMax) {
|
||||
return 'min';
|
||||
}
|
||||
}
|
||||
|
||||
return 'max';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the slider keys
|
||||
* @private
|
||||
* @return {string[]}
|
||||
*/
|
||||
getKeys() {
|
||||
if (this.isMultiValue()) {
|
||||
return ['min', 'max'];
|
||||
}
|
||||
|
||||
return ['max'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the difference between the new and the current value is
|
||||
* greater or equal to the step amount of the component
|
||||
* @private
|
||||
* @param {Range} values
|
||||
* @return {boolean}
|
||||
*/
|
||||
hasStepDifference(values) {
|
||||
const currentValues = valueTransformer.getValueFromProps(
|
||||
this.props,
|
||||
this.isMultiValue()
|
||||
);
|
||||
|
||||
return (
|
||||
length(values.min, currentValues.min) >= this.props.step ||
|
||||
length(values.max, currentValues.max) >= this.props.step
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the component accepts a min and max value
|
||||
* @private
|
||||
* @return {boolean}
|
||||
*/
|
||||
isMultiValue() {
|
||||
return isObject(this.props.value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the range is within the max and min value of the component
|
||||
* @private
|
||||
* @param {Range} values
|
||||
* @return {boolean}
|
||||
*/
|
||||
isWithinRange(values) {
|
||||
if (this.isMultiValue()) {
|
||||
return (
|
||||
values.min >= this.props.minValue &&
|
||||
values.max <= this.props.maxValue &&
|
||||
values.min < values.max
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
values.max >= this.props.minValue && values.max <= this.props.maxValue
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the new value should trigger a render
|
||||
* @private
|
||||
* @param {Range} values
|
||||
* @return {boolean}
|
||||
*/
|
||||
shouldUpdate(values) {
|
||||
return this.isWithinRange(values) && this.hasStepDifference(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the position of a slider
|
||||
* @private
|
||||
* @param {string} key
|
||||
* @param {Point} position
|
||||
* @return {void}
|
||||
*/
|
||||
updatePosition(key, position) {
|
||||
const values = valueTransformer.getValueFromProps(
|
||||
this.props,
|
||||
this.isMultiValue()
|
||||
);
|
||||
const positions = valueTransformer.getPositionsFromValues(
|
||||
values,
|
||||
this.props.minValue,
|
||||
this.props.maxValue,
|
||||
this.getTrackClientRect()
|
||||
);
|
||||
|
||||
positions[key] = position;
|
||||
|
||||
this.updatePositions(positions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the positions of multiple sliders
|
||||
* @private
|
||||
* @param {Object} positions
|
||||
* @param {Point} positions.min
|
||||
* @param {Point} positions.max
|
||||
* @return {void}
|
||||
*/
|
||||
updatePositions(positions) {
|
||||
const values = {
|
||||
min: valueTransformer.getValueFromPosition(
|
||||
positions.min,
|
||||
this.props.minValue,
|
||||
this.props.maxValue,
|
||||
this.getTrackClientRect()
|
||||
),
|
||||
max: valueTransformer.getValueFromPosition(
|
||||
positions.max,
|
||||
this.props.minValue,
|
||||
this.props.maxValue,
|
||||
this.getTrackClientRect()
|
||||
)
|
||||
};
|
||||
|
||||
const transformedValues = {
|
||||
min: valueTransformer.getStepValueFromValue(values.min, this.props.step),
|
||||
max: valueTransformer.getStepValueFromValue(values.max, this.props.step)
|
||||
};
|
||||
|
||||
this.updateValues(transformedValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the value of a slider
|
||||
* @private
|
||||
* @param {string} key
|
||||
* @param {number} value
|
||||
* @return {void}
|
||||
*/
|
||||
updateValue(key, value) {
|
||||
const values = valueTransformer.getValueFromProps(
|
||||
this.props,
|
||||
this.isMultiValue()
|
||||
);
|
||||
|
||||
values[key] = value;
|
||||
|
||||
this.updateValues(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the values of multiple sliders
|
||||
* @private
|
||||
* @param {Range|number} values
|
||||
* @return {void}
|
||||
*/
|
||||
updateValues(values) {
|
||||
if (!this.shouldUpdate(values)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.onChange(this.isMultiValue() ? values : values.max);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increment the value of a slider by key name
|
||||
* @private
|
||||
* @param {string} key
|
||||
* @return {void}
|
||||
*/
|
||||
incrementValue(key) {
|
||||
const values = valueTransformer.getValueFromProps(
|
||||
this.props,
|
||||
this.isMultiValue()
|
||||
);
|
||||
const value = values[key] + this.props.step;
|
||||
|
||||
this.updateValue(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrement the value of a slider by key name
|
||||
* @private
|
||||
* @param {string} key
|
||||
* @return {void}
|
||||
*/
|
||||
decrementValue(key) {
|
||||
const values = valueTransformer.getValueFromProps(
|
||||
this.props,
|
||||
this.isMultiValue()
|
||||
);
|
||||
const value = values[key] - this.props.step;
|
||||
|
||||
this.updateValue(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen to mouseup event
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
addDocumentMouseUpListener() {
|
||||
this.removeDocumentMouseUpListener();
|
||||
this.node.ownerDocument.addEventListener('mouseup', this.handleMouseUp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen to touchend event
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
addDocumentTouchEndListener() {
|
||||
this.removeDocumentTouchEndListener();
|
||||
this.node.ownerDocument.addEventListener('touchend', this.handleTouchEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop listening to mouseup event
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
removeDocumentMouseUpListener() {
|
||||
this.node && this.node.ownerDocument.removeEventListener('mouseup', this.handleMouseUp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop listening to touchend event
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
removeDocumentTouchEndListener() {
|
||||
this.node.ownerDocument.removeEventListener(
|
||||
'touchend',
|
||||
this.handleTouchEnd
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle any "mousemove" event received by the slider
|
||||
* @private
|
||||
* @param {SyntheticEvent} event
|
||||
* @param {string} key
|
||||
* @return {void}
|
||||
*/
|
||||
handleSliderDrag(event, key) {
|
||||
if (this.props.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const position = valueTransformer.getPositionFromEvent(
|
||||
event,
|
||||
this.getTrackClientRect()
|
||||
);
|
||||
this.isSliderDragging = true;
|
||||
requestAnimationFrame(() => this.updatePosition(key, position));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle any "mousemove" event received by the track
|
||||
* @private
|
||||
* @param {SyntheticEvent} event
|
||||
* @return {void}
|
||||
*/
|
||||
handleTrackDrag(event, prevEvent) {
|
||||
if (
|
||||
this.props.disabled ||
|
||||
!this.props.draggableTrack ||
|
||||
this.isSliderDragging
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { maxValue, minValue, value: { max, min } } = this.props;
|
||||
|
||||
const position = valueTransformer.getPositionFromEvent(
|
||||
event,
|
||||
this.getTrackClientRect()
|
||||
);
|
||||
const value = valueTransformer.getValueFromPosition(
|
||||
position,
|
||||
minValue,
|
||||
maxValue,
|
||||
this.getTrackClientRect()
|
||||
);
|
||||
const stepValue = valueTransformer.getStepValueFromValue(
|
||||
value,
|
||||
this.props.step
|
||||
);
|
||||
|
||||
const prevPosition = valueTransformer.getPositionFromEvent(
|
||||
prevEvent,
|
||||
this.getTrackClientRect()
|
||||
);
|
||||
const prevValue = valueTransformer.getValueFromPosition(
|
||||
prevPosition,
|
||||
minValue,
|
||||
maxValue,
|
||||
this.getTrackClientRect()
|
||||
);
|
||||
const prevStepValue = valueTransformer.getStepValueFromValue(
|
||||
prevValue,
|
||||
this.props.step
|
||||
);
|
||||
|
||||
const offset = prevStepValue - stepValue;
|
||||
|
||||
const transformedValues = {
|
||||
min: min - offset,
|
||||
max: max - offset
|
||||
};
|
||||
|
||||
this.updateValues(transformedValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle any "mousedown" event received by the track
|
||||
* @private
|
||||
* @param {SyntheticEvent} event
|
||||
* @param {Point} position
|
||||
* @return {void}
|
||||
*/
|
||||
|
||||
handleTrackMouseDown(event, position) {
|
||||
if (this.props.disabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { maxValue, minValue, value: { max, min } } = this.props;
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
const value = valueTransformer.getValueFromPosition(
|
||||
position,
|
||||
minValue,
|
||||
maxValue,
|
||||
this.getTrackClientRect()
|
||||
);
|
||||
const stepValue = valueTransformer.getStepValueFromValue(
|
||||
value,
|
||||
this.props.step
|
||||
);
|
||||
|
||||
if (!this.props.draggableTrack || stepValue > max || stepValue < min) {
|
||||
this.updatePosition(this.getKeyByPosition(position), position);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the start of any mouse/touch event
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
|
||||
handleInteractionStart() {
|
||||
if (this.props.onChangeStart) {
|
||||
this.props.onChangeStart(this.props.value);
|
||||
}
|
||||
|
||||
if (this.props.onChangeComplete && !isDefined(this.startValue)) {
|
||||
this.startValue = this.props.value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the end of any mouse/touch event
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
handleInteractionEnd() {
|
||||
if (this.isSliderDragging) {
|
||||
this.isSliderDragging = false;
|
||||
}
|
||||
|
||||
if (!this.props.onChangeComplete || !isDefined(this.startValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.startValue !== this.props.value) {
|
||||
this.props.onChangeComplete(this.props.value);
|
||||
}
|
||||
|
||||
this.startValue = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle any "keydown" event received by the component
|
||||
* @private
|
||||
* @param {SyntheticEvent} event
|
||||
* @return {void}
|
||||
*/
|
||||
|
||||
handleKeyDown(event) {
|
||||
this.handleInteractionStart(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle any "keyup" event received by the component
|
||||
* @private
|
||||
* @param {SyntheticEvent} event
|
||||
* @return {void}
|
||||
*/
|
||||
handleKeyUp(event) {
|
||||
this.handleInteractionEnd(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle any "mousedown" event received by the component
|
||||
* @private
|
||||
* @param {SyntheticEvent} event
|
||||
* @return {void}
|
||||
*/
|
||||
|
||||
handleMouseDown(event) {
|
||||
this.handleInteractionStart(event);
|
||||
this.addDocumentMouseUpListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle any "mouseup" event received by the component
|
||||
* @private
|
||||
* @param {SyntheticEvent} event
|
||||
*/
|
||||
|
||||
handleMouseUp(event) {
|
||||
this.handleInteractionEnd(event);
|
||||
this.removeDocumentMouseUpListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle any "touchstart" event received by the component
|
||||
* @private
|
||||
* @param {SyntheticEvent} event
|
||||
* @return {void}
|
||||
*/
|
||||
|
||||
handleTouchStart(event) {
|
||||
this.handleInteractionStart(event);
|
||||
this.addDocumentTouchEndListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle any "touchend" event received by the component
|
||||
* @private
|
||||
* @param {SyntheticEvent} event
|
||||
*/
|
||||
handleTouchEnd(event) {
|
||||
this.handleInteractionEnd(event);
|
||||
this.removeDocumentTouchEndListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return JSX of sliders
|
||||
* @private
|
||||
* @return {JSX.Element}
|
||||
*/
|
||||
renderSliders() {
|
||||
const values = valueTransformer.getValueFromProps(
|
||||
this.props,
|
||||
this.isMultiValue()
|
||||
);
|
||||
const percentages = valueTransformer.getPercentagesFromValues(
|
||||
values,
|
||||
this.props.minValue,
|
||||
this.props.maxValue
|
||||
);
|
||||
|
||||
return this.getKeys().map(key => {
|
||||
const value = values[key];
|
||||
const percentage = percentages[key];
|
||||
|
||||
let { maxValue, minValue } = this.props;
|
||||
|
||||
if (key === 'min') {
|
||||
maxValue = values.max;
|
||||
} else {
|
||||
minValue = values.min;
|
||||
}
|
||||
|
||||
const slider = (
|
||||
<Slider
|
||||
ariaLabelledby={this.props.ariaLabelledby}
|
||||
ariaControls={this.props.ariaControls}
|
||||
classNames={this.props.classNames}
|
||||
formatLabel={this.props.formatLabel}
|
||||
key={key}
|
||||
greyed={this.props.greyed}
|
||||
maxValue={maxValue}
|
||||
minValue={minValue}
|
||||
onSliderDrag={this.handleSliderDrag}
|
||||
percentage={percentage}
|
||||
type={key}
|
||||
value={value}
|
||||
/>
|
||||
);
|
||||
|
||||
return slider;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return JSX of hidden inputs
|
||||
* @private
|
||||
* @return {JSX.Element}
|
||||
*/
|
||||
renderHiddenInputs() {
|
||||
if (!this.props.name) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const isMultiValue = this.isMultiValue();
|
||||
const values = valueTransformer.getValueFromProps(this.props, isMultiValue);
|
||||
|
||||
return this.getKeys().map(key => {
|
||||
const value = values[key];
|
||||
const name = isMultiValue
|
||||
? `${this.props.name}${captialize(key)}`
|
||||
: this.props.name;
|
||||
|
||||
return <input key={key} type="hidden" name={name} value={value} />;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @override
|
||||
* @return {JSX.Element}
|
||||
*/
|
||||
render() {
|
||||
const values = valueTransformer.getValueFromProps(
|
||||
this.props,
|
||||
this.isMultiValue()
|
||||
);
|
||||
const percentages = valueTransformer.getPercentagesFromValues(
|
||||
values,
|
||||
this.props.minValue,
|
||||
this.props.maxValue
|
||||
);
|
||||
|
||||
return (
|
||||
<RangeStyled
|
||||
aria-disabled={this.props.disabled}
|
||||
innerRef={node => {
|
||||
this.node = node;
|
||||
}}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onKeyUp={this.handleKeyUp}
|
||||
onMouseDown={this.handleMouseDown}
|
||||
onTouchStart={this.handleTouchStart}
|
||||
>
|
||||
<Track
|
||||
classNames={this.props.classNames}
|
||||
draggableTrack={this.props.draggableTrack}
|
||||
ref={trackNode => {
|
||||
this.trackNode = trackNode;
|
||||
}}
|
||||
percentages={percentages}
|
||||
onTrackDrag={this.handleTrackDrag}
|
||||
onTrackMouseDown={this.handleTrackMouseDown}
|
||||
>
|
||||
{this.renderSliders()}
|
||||
</Track>
|
||||
|
||||
{this.renderHiddenInputs()}
|
||||
</RangeStyled>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import remcalc from 'remcalc';
|
||||
|
||||
import theme from '../../../theme';
|
||||
|
||||
const Span = styled.span`
|
||||
font-size: ${remcalc(13)};
|
||||
position: absolute;
|
||||
top: ${remcalc(14)};
|
||||
right: ${props => (props.type === 'max' ? remcalc(1) : 'auto')};
|
||||
color: ${props => (props.greyed ? theme.grey : theme.secondary)};
|
||||
`;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @param {Object} props
|
||||
* @param {InputRangeClassNames} props.classNames
|
||||
* @param {Function} props.formatLabel
|
||||
* @param {string} props.type
|
||||
*/
|
||||
export default function Label(props) {
|
||||
const labelValue = props.formatLabel
|
||||
? props.formatLabel(props.children, props.type)
|
||||
: props.children;
|
||||
|
||||
return (
|
||||
<Span greyed={props.greyed} type={props.type}>
|
||||
{labelValue}
|
||||
</Span>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Object}
|
||||
* @property {Function} children
|
||||
* @property {Function} classNames
|
||||
* @property {Function} formatLabel
|
||||
* @property {Function} type
|
||||
*/
|
||||
Label.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
classNames: PropTypes.objectOf(PropTypes.string),
|
||||
formatLabel: PropTypes.func,
|
||||
type: PropTypes.string,
|
||||
greyed: PropTypes.bool
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
import { isNumber } from '../utils';
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @param {Object} props - React component props
|
||||
* @return {?Error} Return Error if validation fails
|
||||
*/
|
||||
export default function rangePropType(props) {
|
||||
const { maxValue, minValue } = props;
|
||||
|
||||
if (!isNumber(minValue) || !isNumber(maxValue)) {
|
||||
return new Error('"minValue" and "maxValue" must be a number');
|
||||
}
|
||||
|
||||
if (minValue >= maxValue) {
|
||||
return new Error('"minValue" must be smaller than "maxValue"');
|
||||
}
|
||||
}
|
@ -1,315 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Label from './label';
|
||||
|
||||
import styled from 'styled-components';
|
||||
import remcalc from 'remcalc';
|
||||
import theme from '../../../theme';
|
||||
|
||||
export const SliderStyled = styled.div`
|
||||
appearance: none;
|
||||
background: ${theme.white};
|
||||
border: ${remcalc(2)} solid ${theme.grey};
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
height: ${remcalc(14)};
|
||||
width: ${remcalc(14)};
|
||||
transform: translateY(-50%);
|
||||
outline: none;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
margin-top: ${remcalc(2)};
|
||||
|
||||
&::active {
|
||||
transform: scale(1.3);
|
||||
}
|
||||
|
||||
&::focus {
|
||||
box-shadow: 0 0 0 ${remcalc(5)} rgba(63, 81, 181, 0.2);
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
export default class Slider extends Component {
|
||||
/**
|
||||
* Accepted propTypes of Slider
|
||||
* @override
|
||||
* @return {Object}
|
||||
* @property {Function} ariaLabelledby
|
||||
* @property {Function} ariaControls
|
||||
* @property {Function} className
|
||||
* @property {Function} formatLabel
|
||||
* @property {Function} maxValue
|
||||
* @property {Function} minValue
|
||||
* @property {Function} onSliderDrag
|
||||
* @property {Function} onSliderKeyDown
|
||||
* @property {Function} percentage
|
||||
* @property {Function} type
|
||||
* @property {Function} value
|
||||
*/
|
||||
static get propTypes() {
|
||||
return {
|
||||
ariaLabelledby: PropTypes.string,
|
||||
ariaControls: PropTypes.string,
|
||||
classNames: PropTypes.objectOf(PropTypes.string),
|
||||
formatLabel: PropTypes.func,
|
||||
maxValue: PropTypes.number,
|
||||
minValue: PropTypes.number,
|
||||
onSliderDrag: PropTypes.func,
|
||||
onSliderKeyDown: PropTypes.func,
|
||||
percentage: PropTypes.number,
|
||||
type: PropTypes.string,
|
||||
value: PropTypes.number
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} props
|
||||
* @param {string} [props.ariaLabelledby]
|
||||
* @param {string} [props.ariaControls]
|
||||
* @param {InputRangeClassNames} props.classNames
|
||||
* @param {Function} [props.formatLabel]
|
||||
* @param {number} [props.maxValue]
|
||||
* @param {number} [props.minValue]
|
||||
* @param {Function} props.onSliderKeyDown
|
||||
* @param {Function} props.onSliderDrag
|
||||
* @param {number} props.percentage
|
||||
* @param {number} props.type
|
||||
* @param {number} props.value
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?Component}
|
||||
*/
|
||||
this.node = null;
|
||||
|
||||
this.handleMouseDown = this.handleMouseDown.bind(this);
|
||||
this.handleMouseUp = this.handleMouseUp.bind(this);
|
||||
this.handleMouseMove = this.handleMouseMove.bind(this);
|
||||
this.handleTouchStart = this.handleTouchStart.bind(this);
|
||||
this.handleTouchMove = this.handleTouchMove.bind(this);
|
||||
this.handleTouchEnd = this.handleTouchEnd.bind(this);
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @override
|
||||
* @return {void}
|
||||
*/
|
||||
componentWillUnmount() {
|
||||
this.removeDocumentMouseMoveListener();
|
||||
this.removeDocumentMouseUpListener();
|
||||
this.removeDocumentTouchEndListener();
|
||||
this.removeDocumentTouchMoveListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {Object}
|
||||
*/
|
||||
getStyle() {
|
||||
const percentage = (this.props.percentage || 0) * 100;
|
||||
const style = {
|
||||
position: 'absolute',
|
||||
left: `${percentage > 94 ? 94 : percentage}%`,
|
||||
};
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen to mousemove event
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
addDocumentMouseMoveListener() {
|
||||
this.removeDocumentMouseMoveListener();
|
||||
this.node.ownerDocument.addEventListener('mousemove', this.handleMouseMove);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen to mouseup event
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
addDocumentMouseUpListener() {
|
||||
this.removeDocumentMouseUpListener();
|
||||
this.node.ownerDocument.addEventListener('mouseup', this.handleMouseUp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen to touchmove event
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
addDocumentTouchMoveListener() {
|
||||
this.removeDocumentTouchMoveListener();
|
||||
this.node.ownerDocument.addEventListener('touchmove', this.handleTouchMove);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen to touchend event
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
addDocumentTouchEndListener() {
|
||||
this.removeDocumentTouchEndListener();
|
||||
this.node.ownerDocument.addEventListener('touchend', this.handleTouchEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
removeDocumentMouseMoveListener() {
|
||||
this.node.ownerDocument.removeEventListener(
|
||||
'mousemove',
|
||||
this.handleMouseMove
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
removeDocumentMouseUpListener() {
|
||||
this.node &&
|
||||
this.node.ownerDocument.removeEventListener(
|
||||
'mouseup',
|
||||
this.handleMouseUp
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
removeDocumentTouchMoveListener() {
|
||||
this.node.ownerDocument.removeEventListener(
|
||||
'touchmove',
|
||||
this.handleTouchMove
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
removeDocumentTouchEndListener() {
|
||||
this.node.ownerDocument.removeEventListener(
|
||||
'touchend',
|
||||
this.handleTouchEnd
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
handleMouseDown() {
|
||||
this.addDocumentMouseMoveListener();
|
||||
this.addDocumentMouseUpListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
handleMouseUp() {
|
||||
this.removeDocumentMouseMoveListener();
|
||||
this.removeDocumentMouseUpListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {SyntheticEvent} event
|
||||
* @return {void}
|
||||
*/
|
||||
handleMouseMove(event) {
|
||||
this.props.onSliderDrag(event, this.props.type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
handleTouchStart() {
|
||||
this.addDocumentTouchEndListener();
|
||||
this.addDocumentTouchMoveListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {SyntheticEvent} event
|
||||
* @return {void}
|
||||
*/
|
||||
handleTouchMove(event) {
|
||||
this.props.onSliderDrag(event, this.props.type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
handleTouchEnd() {
|
||||
this.removeDocumentTouchMoveListener();
|
||||
this.removeDocumentTouchEndListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {SyntheticEvent} event
|
||||
* @return {void}
|
||||
*/
|
||||
handleKeyDown(event) {
|
||||
this.props.onSliderKeyDown(event, this.props.type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @return {JSX.Element}
|
||||
*/
|
||||
render() {
|
||||
const style = this.getStyle();
|
||||
const props = this.props;
|
||||
|
||||
return (
|
||||
<span
|
||||
ref={node => {
|
||||
this.node = node;
|
||||
}}
|
||||
>
|
||||
<Label
|
||||
greyed={props.greyed}
|
||||
formatLabel={props.formatLabel}
|
||||
type={props.type}
|
||||
>
|
||||
{props.value}
|
||||
</Label>
|
||||
<SliderStyled
|
||||
type={props.type}
|
||||
percentage={props.percentage}
|
||||
style={style}
|
||||
aria-labelledby={props.ariaLabelledby}
|
||||
aria-controls={props.ariaControls}
|
||||
aria-valuemax={props.maxValue}
|
||||
aria-valuemin={props.minValue}
|
||||
aria-valuenow={props.value}
|
||||
draggable="false"
|
||||
onKeyDown={this.handleKeyDown}
|
||||
onMouseDown={this.handleMouseDown}
|
||||
onTouchStart={this.handleTouchStart}
|
||||
role="slider"
|
||||
tabIndex="0"
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,214 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import remcalc from 'remcalc';
|
||||
import theme from '../../../theme';
|
||||
|
||||
export const TrackStyled = styled.div`
|
||||
background: ${theme.grey};
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
height: ${remcalc(4)};
|
||||
position: relative;
|
||||
`;
|
||||
|
||||
const ActiveTrack = styled.div`
|
||||
background: ${theme.primary};
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
`;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
export default class Track extends Component {
|
||||
/**
|
||||
* @override
|
||||
* @return {Object}
|
||||
* @property {Function} children
|
||||
* @property {Function} classNames
|
||||
* @property {Boolean} draggableTrack
|
||||
* @property {Function} onTrackDrag
|
||||
* @property {Function} onTrackMouseDown
|
||||
* @property {Function} percentages
|
||||
*/
|
||||
static get propTypes() {
|
||||
return {
|
||||
children: PropTypes.node.isRequired,
|
||||
classNames: PropTypes.objectOf(PropTypes.string),
|
||||
draggableTrack: PropTypes.bool,
|
||||
onTrackDrag: PropTypes.func,
|
||||
onTrackMouseDown: PropTypes.func,
|
||||
percentages: PropTypes.objectOf(PropTypes.number)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} props
|
||||
* @param {InputRangeClassNames} props.classNames
|
||||
* @param {Boolean} props.draggableTrack
|
||||
* @param {Function} props.onTrackDrag
|
||||
* @param {Function} props.onTrackMouseDown
|
||||
* @param {number} props.percentages
|
||||
*/
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?Component}
|
||||
*/
|
||||
this.node = null;
|
||||
this.trackDragEvent = null;
|
||||
|
||||
this.handleMouseMove = this.handleMouseMove.bind(this);
|
||||
this.handleMouseUp = this.handleMouseUp.bind(this);
|
||||
this.handleMouseDown = this.handleMouseDown.bind(this);
|
||||
this.handleTouchStart = this.handleTouchStart.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {ClientRect}
|
||||
*/
|
||||
getClientRect() {
|
||||
return this.node.getBoundingClientRect();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {Object} CSS styles
|
||||
*/
|
||||
getActiveTrackStyle() {
|
||||
const width = `${(this.props.percentages.max - this.props.percentages.min) *
|
||||
100}%`;
|
||||
const left = `${this.props.percentages.min * 100}%`;
|
||||
|
||||
return { left, width };
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen to mousemove event
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
addDocumentMouseMoveListener() {
|
||||
this.removeDocumentMouseMoveListener();
|
||||
this.node.ownerDocument.addEventListener('mousemove', this.handleMouseMove);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen to mouseup event
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
addDocumentMouseUpListener() {
|
||||
this.removeDocumentMouseUpListener();
|
||||
this.node.ownerDocument.addEventListener('mouseup', this.handleMouseUp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
removeDocumentMouseMoveListener() {
|
||||
this.node.ownerDocument.removeEventListener(
|
||||
'mousemove',
|
||||
this.handleMouseMove
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
removeDocumentMouseUpListener() {
|
||||
this.node &&
|
||||
this.node.ownerDocument.removeEventListener(
|
||||
'mouseup',
|
||||
this.handleMouseUp
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {SyntheticEvent} event
|
||||
* @return {void}
|
||||
*/
|
||||
handleMouseMove(event) {
|
||||
if (!this.props.draggableTrack) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.trackDragEvent !== null) {
|
||||
this.props.onTrackDrag(event, this.trackDragEvent);
|
||||
}
|
||||
|
||||
this.trackDragEvent = event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @return {void}
|
||||
*/
|
||||
handleMouseUp() {
|
||||
if (!this.props.draggableTrack) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.removeDocumentMouseMoveListener();
|
||||
this.removeDocumentMouseUpListener();
|
||||
this.trackDragEvent = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {SyntheticEvent} event - User event
|
||||
*/
|
||||
handleMouseDown(event) {
|
||||
const clientX = event.touches ? event.touches[0].clientX : event.clientX;
|
||||
const trackClientRect = this.getClientRect();
|
||||
const position = {
|
||||
x: clientX - trackClientRect.left,
|
||||
y: 0
|
||||
};
|
||||
|
||||
this.props.onTrackMouseDown(event, position);
|
||||
|
||||
if (this.props.draggableTrack) {
|
||||
this.addDocumentMouseMoveListener();
|
||||
this.addDocumentMouseUpListener();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {SyntheticEvent} event - User event
|
||||
*/
|
||||
handleTouchStart(event) {
|
||||
event.preventDefault();
|
||||
|
||||
this.handleMouseDown(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
* @return {JSX.Element}
|
||||
*/
|
||||
render() {
|
||||
const activeTrackStyle = this.getActiveTrackStyle();
|
||||
|
||||
return (
|
||||
<TrackStyled
|
||||
onMouseDown={this.handleMouseDown}
|
||||
onTouchStart={this.handleTouchStart}
|
||||
innerRef={node => {
|
||||
this.node = node;
|
||||
}}
|
||||
>
|
||||
<ActiveTrack style={activeTrackStyle} />
|
||||
{this.props.children}
|
||||
</TrackStyled>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
import { isNumber, isObject } from '../utils';
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @param {Object} props
|
||||
* @return {?Error} Return Error if validation fails
|
||||
*/
|
||||
export default function valuePropType(props, propName) {
|
||||
const { maxValue, minValue } = props;
|
||||
const value = props[propName];
|
||||
|
||||
if (
|
||||
!isNumber(value) &&
|
||||
(!isObject(value) || !isNumber(value.min) || !isNumber(value.max))
|
||||
) {
|
||||
return new Error(`"${propName}" must be a number or a range object`);
|
||||
}
|
||||
|
||||
if (isNumber(value) && (value < minValue || value > maxValue)) {
|
||||
return new Error(
|
||||
`"${propName}" must be in between "minValue" and "maxValue"`
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
isObject(value) &&
|
||||
(value.min < minValue ||
|
||||
value.min > maxValue ||
|
||||
value.max < minValue ||
|
||||
value.max > maxValue)
|
||||
) {
|
||||
return new Error(
|
||||
`"${propName}" must be in between "minValue" and "maxValue"`
|
||||
);
|
||||
}
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
import { clamp } from '../utils';
|
||||
|
||||
/**
|
||||
* Convert a point into a percentage value
|
||||
* @ignore
|
||||
* @param {Point} position
|
||||
* @param {ClientRect} clientRect
|
||||
* @return {number} Percentage value
|
||||
*/
|
||||
export function getPercentageFromPosition(position, clientRect) {
|
||||
const length = clientRect.width;
|
||||
const sizePerc = position.x / length;
|
||||
|
||||
return sizePerc || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a point into a model value
|
||||
* @ignore
|
||||
* @param {Point} position
|
||||
* @param {number} minValue
|
||||
* @param {number} maxValue
|
||||
* @param {ClientRect} clientRect
|
||||
* @return {number}
|
||||
*/
|
||||
export function getValueFromPosition(position, minValue, maxValue, clientRect) {
|
||||
const sizePerc = getPercentageFromPosition(position, clientRect);
|
||||
const valueDiff = maxValue - minValue;
|
||||
|
||||
return minValue + valueDiff * sizePerc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert props into a range value
|
||||
* @ignore
|
||||
* @param {Object} props
|
||||
* @param {boolean} isMultiValue
|
||||
* @return {Range}
|
||||
*/
|
||||
export function getValueFromProps(props, isMultiValue) {
|
||||
if (isMultiValue) {
|
||||
return { ...props.value };
|
||||
}
|
||||
|
||||
return {
|
||||
min: props.minValue,
|
||||
max: props.value
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a model value into a percentage value
|
||||
* @ignore
|
||||
* @param {number} value
|
||||
* @param {number} minValue
|
||||
* @param {number} maxValue
|
||||
* @return {number}
|
||||
*/
|
||||
export function getPercentageFromValue(value, minValue, maxValue) {
|
||||
const validValue = clamp(value, minValue, maxValue);
|
||||
const valueDiff = maxValue - minValue;
|
||||
const valuePerc = (validValue - minValue) / valueDiff;
|
||||
|
||||
return valuePerc || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert model values into percentage values
|
||||
* @ignore
|
||||
* @param {Range} values
|
||||
* @param {number} minValue
|
||||
* @param {number} maxValue
|
||||
* @return {Range}
|
||||
*/
|
||||
export function getPercentagesFromValues(values, minValue, maxValue) {
|
||||
return {
|
||||
min: getPercentageFromValue(values.min, minValue, maxValue),
|
||||
max: getPercentageFromValue(values.max, minValue, maxValue)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a value into a point
|
||||
* @ignore
|
||||
* @param {number} value
|
||||
* @param {number} minValue
|
||||
* @param {number} maxValue
|
||||
* @param {ClientRect} clientRect
|
||||
* @return {Point} Position
|
||||
*/
|
||||
export function getPositionFromValue(value, minValue, maxValue, clientRect) {
|
||||
const length = clientRect.width;
|
||||
const valuePerc = getPercentageFromValue(value, minValue, maxValue);
|
||||
const positionValue = valuePerc * length;
|
||||
|
||||
return {
|
||||
x: positionValue,
|
||||
y: 0
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a range of values into points
|
||||
* @ignore
|
||||
* @param {Range} values
|
||||
* @param {number} minValue
|
||||
* @param {number} maxValue
|
||||
* @param {ClientRect} clientRect
|
||||
* @return {Range}
|
||||
*/
|
||||
export function getPositionsFromValues(values, minValue, maxValue, clientRect) {
|
||||
return {
|
||||
min: getPositionFromValue(values.min, minValue, maxValue, clientRect),
|
||||
max: getPositionFromValue(values.max, minValue, maxValue, clientRect)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an event into a point
|
||||
* @ignore
|
||||
* @param {Event} event
|
||||
* @param {ClientRect} clientRect
|
||||
* @return {Point}
|
||||
*/
|
||||
export function getPositionFromEvent(event, clientRect) {
|
||||
const length = clientRect.width;
|
||||
const { clientX } = event.touches ? event.touches[0] : event;
|
||||
|
||||
return {
|
||||
x: clamp(clientX - clientRect.left, 0, length),
|
||||
y: 0
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a value into a step value
|
||||
* @ignore
|
||||
* @param {number} value
|
||||
* @param {number} valuePerStep
|
||||
* @return {number}
|
||||
*/
|
||||
export function getStepValueFromValue(value, valuePerStep) {
|
||||
return Math.round(value / valuePerStep) * valuePerStep;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
/**
|
||||
* Captialize a string
|
||||
* @ignore
|
||||
* @param {string} string
|
||||
* @return {string}
|
||||
*/
|
||||
export default function captialize(string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
/**
|
||||
* Clamp a value between a min and max value
|
||||
* @ignore
|
||||
* @param {number} value
|
||||
* @param {number} min
|
||||
* @param {number} max
|
||||
* @return {number}
|
||||
*/
|
||||
export default function clamp(value, min, max) {
|
||||
return Math.min(Math.max(value, min), max);
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
/**
|
||||
* Calculate the distance between pointA and pointB
|
||||
* @ignore
|
||||
* @param {Point} pointA
|
||||
* @param {Point} pointB
|
||||
* @return {number} Distance
|
||||
*/
|
||||
export default function distanceTo(pointA, pointB) {
|
||||
const xDiff = (pointB.x - pointA.x) ** 2;
|
||||
const yDiff = (pointB.y - pointA.y) ** 2;
|
||||
|
||||
return Math.sqrt(xDiff + yDiff);
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
export { default as captialize } from './captialize';
|
||||
export { default as clamp } from './clamp';
|
||||
export { default as distanceTo } from './distance-to';
|
||||
export { default as isDefined } from './is-defined';
|
||||
export { default as isNumber } from './is-number';
|
||||
export { default as isObject } from './is-object';
|
||||
export { default as length } from './length';
|
@ -1,9 +0,0 @@
|
||||
/**
|
||||
* Check if a value is defined
|
||||
* @ignore
|
||||
* @param {*} value
|
||||
* @return {boolean}
|
||||
*/
|
||||
export default function isDefined(value) {
|
||||
return value !== undefined && value !== null;
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
/**
|
||||
* Check if a value is a number
|
||||
* @ignore
|
||||
* @param {*} value
|
||||
* @return {boolean}
|
||||
*/
|
||||
export default function isNumber(value) {
|
||||
return typeof value === 'number';
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
/**
|
||||
* Check if a value is an object
|
||||
* @ignore
|
||||
* @param {*} value
|
||||
* @return {boolean}
|
||||
*/
|
||||
export default function isObject(value) {
|
||||
return value !== null && typeof value === 'object';
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
/**
|
||||
* Calculate the absolute difference between two numbers
|
||||
* @ignore
|
||||
* @param {number} numA
|
||||
* @param {number} numB
|
||||
* @return {number}
|
||||
*/
|
||||
export default function length(numA, numB) {
|
||||
return Math.abs(numA - numB);
|
||||
}
|
Loading…
Reference in New Issue
Block a user