saagie-ui
Version:
Saagie UI from Saagie Design System
129 lines (111 loc) • 3.25 kB
JavaScript
/* eslint prefer-const: 0 */
import React, { useState, useMemo } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
const propTypes = {
/**
* The component used for the root node.
* Either a string to use a DOM element or a component.
*/
tag: PropTypes.elementType,
className: PropTypes.string,
defaultClassName: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
isDanger: PropTypes.bool,
isDisabled: PropTypes.bool,
isPrimary: PropTypes.bool,
isSuccess: PropTypes.bool,
isWarning: PropTypes.bool,
min: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
max: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
onChange: PropTypes.func,
formatLabel: PropTypes.func,
};
const defaultProps = {
tag: 'input',
className: '',
defaultClassName: 'sui-a-form-range',
isDanger: false,
isDisabled: false,
isPrimary: false,
isSuccess: false,
isWarning: false,
min: 0,
max: 100,
value: 0,
onChange: () => {},
formatLabel: (value) => value,
};
const SLIDER_THUMB_WIDTH = 25;
const FULL_WIDTH_PERCENTAGE = 100;
const HALF_WIDTH_PERCENTAGE = 50;
export const FormRange = (props) => {
let {
tag: Tag,
defaultClassName,
className,
isDanger,
isDisabled,
isPrimary,
isSuccess,
isWarning,
min,
max,
value,
onChange,
formatLabel,
...attributes
} = props;
const defaultValue = value || min;
const [currentValue, setCurrentValue] = useState(defaultValue);
const classes = classnames(
defaultClassName,
className,
{
'as--danger': isDanger,
'as--primary': isPrimary,
'as--success': isSuccess,
'as--warning': isWarning,
},
);
const valueLeft = useMemo(
() => (currentValue / max) * FULL_WIDTH_PERCENTAGE, [currentValue, max]);
const handleChange = (event) => {
const { value: newValue } = (event.target || {});
setCurrentValue(newValue);
onChange(newValue);
};
return (
<div className={classes}>
<div className="sui-a-form-range__label as--before">{formatLabel(min)}</div>
<div className="sui-a-form-range__container">
<Tag
type="range"
disabled={isDisabled}
min={min}
max={max}
defaultValue={defaultValue}
onChange={handleChange}
{...attributes}
/>
<div
className="sui-a-form-range__wrapper"
style={{
transform: `translateX(calc(${valueLeft}% ${valueLeft > HALF_WIDTH_PERCENTAGE
? `- ${((valueLeft - HALF_WIDTH_PERCENTAGE) / FULL_WIDTH_PERCENTAGE) * SLIDER_THUMB_WIDTH}`
: `+ ${((HALF_WIDTH_PERCENTAGE - valueLeft) / FULL_WIDTH_PERCENTAGE) * SLIDER_THUMB_WIDTH}`}px))`,
}}
>
<div
className="sui-a-form-range__value as--position-dynamic"
>
{formatLabel(currentValue)}
</div>
</div>
</div>
<div className="sui-a-form-range__label as--after">{formatLabel(max)}</div>
</div>
);
};
FormRange.propTypes = propTypes;
FormRange.defaultProps = defaultProps;