UNPKG

@massds/mayflower-react

Version:

React versions of Mayflower design system UI components

343 lines 13.2 kB
function _inheritsLoose(t, o) { t.prototype = Object.create(o.prototype), t.prototype.constructor = t, _setPrototypeOf(t, o); } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); } /** * CompoundSlider module. * @module @massds/mayflower-react/CompoundSlider */ import React from "react"; import PropTypes from "prop-types"; import classNames from "classnames"; import numbro from "numbro"; import { Slider, Rail, Handles, Tracks, Ticks } from "react-compound-slider/es"; import { InputContext } from "../Input/context.mjs"; import { countDecimals } from "../Input/utility.mjs"; const Handle = props => { const _props$handle = props.handle, id = _props$handle.id, value = _props$handle.value, percent = _props$handle.percent, getHandleProps = props.getHandleProps, axis = props.axis, min = props.min, max = props.max, step = props.step, displayValueFormat = props.displayValueFormat, disabled = props.disabled; const decimalPlaces = countDecimals(step); const roundedValue = Number.isInteger(step) ? value : Number(Number.parseFloat(value).toFixed(decimalPlaces)); const divProps = _extends({ 'aria-valuemin': min, 'aria-valuemax': max, 'aria-valuenow': roundedValue, disabled: disabled, role: 'slider', onClick: e => { e.preventDefault(); } }, getHandleProps(id)); if (axis === 'x') { divProps.style = { left: percent + "%" }; } else if (axis === 'y') { divProps.style = { top: percent + "%" }; } return /*#__PURE__*/React.createElement("button", _extends({ type: "button", className: "ma__slider-handle" }, divProps), displayValueFormat && /*#__PURE__*/React.createElement("div", { className: "ma__slider-handle-value" }, displayValueFormat === 'percentage' ? numbro(value).format({ output: 'percent', mantissa: 0 }) : roundedValue)); }; Handle.propTypes = process.env.NODE_ENV !== "production" ? { handle: { id: PropTypes.string, value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), percent: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) }, getHandleProps: PropTypes.func, axis: PropTypes.string, min: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), max: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), step: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), displayValueFormat: PropTypes.string, disabled: PropTypes.bool } : {}; const Track = props => { const source = props.source, target = props.target, getTrackProps = props.getTrackProps, axis = props.axis; const divProps = _extends({}, getTrackProps()); if (axis === 'x') { divProps.style = { left: source.percent + "%", width: target.percent - source.percent + "%" }; } else if (axis === 'y') { divProps.style = { top: source.percent + "%", height: target.percent - source.percent + "%" }; } return /*#__PURE__*/React.createElement("div", _extends({ className: "ma__slider-track" }, divProps)); }; Track.propTypes = process.env.NODE_ENV !== "production" ? { source: { percent: PropTypes.string }, target: { percent: PropTypes.string }, getTrackProps: PropTypes.func, axis: PropTypes.string } : {}; const Tick = props => { const tick = props.tick, count = props.count, axis = props.axis, id = props.id; const top = {}; const bottom = {}; if (axis === 'x') { top.style = { left: tick.percent + "%" }; bottom.style = { marginLeft: -(100 / count) / 2 + "%", width: 100 / count + "%", left: tick.percent + "%" }; } else if (axis === 'y') { top.style = { top: tick.percent + "%" }; bottom.style = { top: tick.percent + "%" }; } return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", _extends({ className: "ma__slider-tick ma__slider-tick--top" }, top)), /*#__PURE__*/React.createElement("div", _extends({ className: "ma__slider-tick ma__slider-tick--bottom" }, bottom), /*#__PURE__*/React.createElement("label", { htmlFor: id }, tick.value))); }; Tick.propTypes = process.env.NODE_ENV !== "production" ? { tick: { percent: PropTypes.string, value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) }, count: PropTypes.number, getTrackProps: PropTypes.func, id: PropTypes.string, axis: PropTypes.string } : {}; let CompoundSlider = /*#__PURE__*/function (_React$Component) { function CompoundSlider() { return _React$Component.apply(this, arguments) || this; } _inheritsLoose(CompoundSlider, _React$Component); var _proto = CompoundSlider.prototype; _proto.render = function render() { return /*#__PURE__*/React.createElement(InputContext.Consumer, null, context => { const _this$props = this.props, min = _this$props.min, max = _this$props.max, step = _this$props.step, disabled = _this$props.disabled, domain = _this$props.domain, onChange = _this$props.onChange, onUpdate = _this$props.onUpdate; const decimalPlaces = countDecimals(step); const handleChange = values => { const value = Number.isInteger(step) ? values[0] : Number(Number.parseFloat(values[0]).toFixed(decimalPlaces)); context.updateState({ value: value }, () => { if (typeof onChange === 'function') { onChange(value, this.props.id); } }); }; const handleUpdate = values => { const value = Number.isInteger(step) ? values[0] : Number(Number.parseFloat(values[0]).toFixed(decimalPlaces)); context.updateState({ value: value }, () => { if (typeof onUpdate === 'function') { onUpdate(value, this.props.id); } }); }; const domainCheck = valToCheck => { let minCheck = Number(min); let maxCheck = Number(max); if (Number.isNaN(valToCheck)) { return Number.isInteger(step) ? minCheck : Number(Number.parseFloat(minCheck).toFixed(decimalPlaces)); } let returnValue = valToCheck; const domainMin = domain[0], domainMax = domain[1]; // If the min/max passed falls outside of the domain, set it to the respective domain min/max. if (Number.isNaN(minCheck) || Math.abs(minCheck - domainMax) > Math.abs(domainMin - domainMax)) { minCheck = domainMin; } if (Number.isNaN(maxCheck) || Math.abs(maxCheck - domainMin) > Math.abs(domainMin - domainMax)) { maxCheck = domainMax; } // Ensure the value is always between the min or max values, if any. if (valToCheck < minCheck) { returnValue = minCheck; } if (valToCheck > maxCheck) { returnValue = maxCheck; } return Number.isInteger(step) ? returnValue : Number(Number.parseFloat(returnValue).toFixed(decimalPlaces)); }; // Anything returned by mode when set to a function will become the value. // This can be used for min/max validation. // Next and current values are not numbers, but arrays of objects. const handleMode = (current, next) => { const nextValue = next[0].val; const checkValue = Number.isInteger(step) ? nextValue : Number(Number.parseFloat(nextValue).toFixed(decimalPlaces)); if (checkValue === domainCheck(nextValue)) { return next; } return current; }; const defaultValue = domainCheck(Number(context.getValue())); const sliderProps = { domain: domain, step: step, vertical: !(this.props.axis === 'x'), onChange: handleChange, values: [defaultValue], mode: handleMode, disabled: disabled }; if (onUpdate) { sliderProps.onUpdate = handleUpdate; } const wrapperClasses = classNames({ 'ma__input-slider': true, 'ma__input-slider--disabled': disabled, 'ma__input-slider-x': this.props.axis === 'x', 'ma__input-slider-y': this.props.axis === 'y' }); return /*#__PURE__*/React.createElement("div", { id: this.props.id, className: wrapperClasses }, /*#__PURE__*/React.createElement(Slider, _extends({ className: "ma__slider" }, sliderProps), /*#__PURE__*/React.createElement(Rail, null, _ref => { let getRailProps = _ref.getRailProps; return /*#__PURE__*/React.createElement("div", _extends({ className: "ma__slider-rail" }, getRailProps())); }), /*#__PURE__*/React.createElement(Handles, null, _ref2 => { let handles = _ref2.handles, activeHandleID = _ref2.activeHandleID, getHandleProps = _ref2.getHandleProps; return /*#__PURE__*/React.createElement("div", { className: "slider-handles" }, handles.map(handle => /*#__PURE__*/React.createElement(Handle, { key: handle.id, handle: handle, getHandleProps: getHandleProps, isActive: handle.id === activeHandleID, axis: this.props.axis, min: min, max: max, step: step, displayValueFormat: this.props.displayValueFormat, disabled: disabled }))); }), /*#__PURE__*/React.createElement(Tracks, { right: false }, _ref3 => { let tracks = _ref3.tracks, getTrackProps = _ref3.getTrackProps; return /*#__PURE__*/React.createElement("div", { className: "slider-tracks" }, tracks.map(_ref4 => { let id = _ref4.id, source = _ref4.source, target = _ref4.target; return /*#__PURE__*/React.createElement(Track, { key: id, source: source, target: target, getTrackProps: getTrackProps, axis: this.props.axis }); })); }), /*#__PURE__*/React.createElement(Ticks, { values: Array.from(this.props.ticks.keys()) }, _ref5 => { let ticks = _ref5.ticks; const ticksLength = ticks.length; // Placing this check here because Slider can't handle null children but Ticks can. if (ticksLength > 0) { return /*#__PURE__*/React.createElement("div", { className: "slider-ticks" }, ticks.map(oldTick => { const tick = _extends({}, oldTick, { value: this.props.ticks.get(oldTick.value) }); const tickProps = { key: "CompoundSlider.tick." + tick.value, count: ticksLength, tick: tick, axis: this.props.axis, id: this.props.id }; return /*#__PURE__*/React.createElement(Tick, tickProps); })); } return null; }))); }); }; return CompoundSlider; }(React.Component); CompoundSlider.propTypes = process.env.NODE_ENV !== "production" ? { /** The unique ID for the input field */ id: PropTypes.string.isRequired, /** Custom update function, triggered with the values on drag (caution: high-volume updates when dragging). Only if a function is passed to onUpdate will form context get updated on drag. */ onUpdate: PropTypes.func, /** Custom on change function, triggered when the value of the slider has changed. This will recieve changes at the end of a slide as well as changes from clicks on rails and tracks. */ onChange: PropTypes.func, /** Default input text value */ defaultValue: PropTypes.string, /** Max value for the field. */ max: PropTypes.number.isRequired, /** Min value for the field. */ min: PropTypes.number.isRequired, /** This controls how much sliding the handle increments/decrements the value of the slider. */ step: PropTypes.number, /** A Map object where each entry is a key (number inclusively between min and max) and value (label to display at the key) pair for displaying tick marks. */ ticks: PropTypes.instanceOf(Map), /** The direction for the slider, where x is horizontal and y is vertical. */ axis: PropTypes.oneOf(['x', 'y']), /** Disables the slider if true. */ disabled: PropTypes.bool, /** The range of numbers, inclusively, for the slider to fall between. First number is the min and second number is the max. */ domain: PropTypes.arrayOf(PropTypes.number), /** Display the value of the slider based. If null, don't display. If equals percentage, format the value in percentage. */ displayValueFormat: PropTypes.oneOf(['percentage', 'value', null]) } : {}; CompoundSlider.defaultProps = { ticks: new Map(), domain: [0, 1] }; export default CompoundSlider;