UNPKG

office-ui-fabric-react

Version:

Reusable React components for building experiences for Microsoft 365.

396 lines • 20.2 kB
import { __assign, __extends } from "tslib"; import * as React from 'react'; import { KeyCodes, css, getId, getRTL, getRTLSafeKeyCode, warnMutuallyExclusive, initializeComponentRef, Async, on, FocusRects, } from '../../Utilities'; import { classNamesFunction, getNativeProps, divProperties } from '../../Utilities'; import { Label } from '../../Label'; var getClassNames = classNamesFunction(); var COMPONENT_NAME = 'SliderBase'; export var ONKEYDOWN_TIMEOUT_DURATION = 1000; var SliderBase = /** @class */ (function (_super) { __extends(SliderBase, _super); function SliderBase(props) { var _this = _super.call(this, props) || this; _this._disposables = []; _this._sliderLine = React.createRef(); _this._thumb = React.createRef(); _this._lowerValueThumb = React.createRef(); _this._onKeyDownTimer = -1; _this._isAdjustingLowerValue = false; _this._getAriaValueText = function (value) { var ariaValueText = _this.props.ariaValueText; if (value !== undefined) { return ariaValueText ? ariaValueText(value) : value.toString(); } return undefined; }; _this._calculateCurrentSteps = function (event) { if (!_this._sliderLine.current) { return; } var _a = _this.props, max = _a.max, min = _a.min, step = _a.step; var steps = (max - min) / step; var sliderPositionRect = _this._sliderLine.current.getBoundingClientRect(); var sliderLength = !_this.props.vertical ? sliderPositionRect.width : sliderPositionRect.height; var stepLength = sliderLength / steps; var currentSteps; var distance; if (!_this.props.vertical) { var left = _this._getPosition(event, _this.props.vertical); distance = getRTL(_this.props.theme) ? sliderPositionRect.right - left : left - sliderPositionRect.left; currentSteps = distance / stepLength; } else { var bottom = _this._getPosition(event, _this.props.vertical); distance = sliderPositionRect.bottom - bottom; currentSteps = distance / stepLength; } return currentSteps; }; _this._onMouseDownOrTouchStart = function (event) { var _a = _this.props, ranged = _a.ranged, min = _a.min, step = _a.step; if (ranged) { var currentSteps = _this._calculateCurrentSteps(event); var newRenderedValue = min + step * currentSteps; if (newRenderedValue <= _this.state.lowerValue || newRenderedValue - _this.state.lowerValue <= _this.state.value - newRenderedValue) { _this._isAdjustingLowerValue = true; } else { _this._isAdjustingLowerValue = false; } } if (event.type === 'mousedown') { _this._disposables.push(on(window, 'mousemove', _this._onMouseMoveOrTouchMove, true), on(window, 'mouseup', _this._onMouseUpOrTouchEnd, true)); } else if (event.type === 'touchstart') { _this._disposables.push(on(window, 'touchmove', _this._onMouseMoveOrTouchMove, true), on(window, 'touchend', _this._onMouseUpOrTouchEnd, true)); } _this._onMouseMoveOrTouchMove(event, true); }; _this._onMouseMoveOrTouchMove = function (event, suppressEventCancelation) { if (!_this._sliderLine.current) { return; } var _a = _this.props, max = _a.max, min = _a.min, step = _a.step; var steps = (max - min) / step; var currentSteps = _this._calculateCurrentSteps(event); var currentValue; var renderedValue; // The value shouldn't be bigger than max or be smaller than min. if (currentSteps > Math.floor(steps)) { renderedValue = currentValue = max; } else if (currentSteps < 0) { renderedValue = currentValue = min; } else { renderedValue = min + step * currentSteps; currentValue = min + step * Math.round(currentSteps); } _this._updateValue(currentValue, renderedValue); if (!suppressEventCancelation) { event.preventDefault(); event.stopPropagation(); } }; _this._onMouseUpOrTouchEnd = function (event) { // Disable renderedValue override. _this.setState({ renderedValue: undefined, renderedLowerValue: undefined, }); if (_this.props.onChanged) { _this.props.onChanged(event, _this.state.value); } _this._disposeListeners(); }; _this._disposeListeners = function () { _this._disposables.forEach(function (dispose) { return dispose(); }); _this._disposables = []; }; _this._onKeyDown = function (event) { var value; if (_this._isAdjustingLowerValue) { value = _this.props.lowerValue || _this.state.lowerValue; } else { value = _this.props.value || _this.state.value; } var _a = _this.props, max = _a.max, min = _a.min, step = _a.step; var diff = 0; // eslint-disable-next-line deprecation/deprecation switch (event.which) { case getRTLSafeKeyCode(KeyCodes.left, _this.props.theme): case KeyCodes.down: diff = -step; _this._clearOnKeyDownTimer(); _this._setOnKeyDownTimer(event); break; case getRTLSafeKeyCode(KeyCodes.right, _this.props.theme): case KeyCodes.up: diff = step; _this._clearOnKeyDownTimer(); _this._setOnKeyDownTimer(event); break; case KeyCodes.home: value = min; _this._clearOnKeyDownTimer(); _this._setOnKeyDownTimer(event); break; case KeyCodes.end: value = max; _this._clearOnKeyDownTimer(); _this._setOnKeyDownTimer(event); break; default: return; } var newValue = Math.min(max, Math.max(min, value + diff)); _this._updateValue(newValue, newValue); event.preventDefault(); event.stopPropagation(); // Disable renderedValue override. _this.setState({ renderedValue: undefined, renderedLowerValue: undefined, }); }; _this._onThumbFocus = function (event) { _this._isAdjustingLowerValue = event.target === _this._lowerValueThumb.current; }; _this._clearOnKeyDownTimer = function () { _this._async.clearTimeout(_this._onKeyDownTimer); }; _this._setOnKeyDownTimer = function (event) { _this._onKeyDownTimer = _this._async.setTimeout(function () { if (_this.props.onChanged) { _this.props.onChanged(event, _this.state.value); } }, ONKEYDOWN_TIMEOUT_DURATION); }; _this._async = new Async(_this); initializeComponentRef(_this); warnMutuallyExclusive(COMPONENT_NAME, _this.props, { value: 'defaultValue', }); if (props.ranged) { warnMutuallyExclusive(COMPONENT_NAME, _this.props, { lowerValue: 'defaultLowerValue', }); } _this._id = getId('Slider'); var value = props.value !== undefined ? props.value : props.defaultValue !== undefined ? props.defaultValue : props.min; var lowerValue = props.lowerValue !== undefined ? props.lowerValue : props.defaultLowerValue !== undefined ? props.defaultLowerValue : props.min; _this.state = { value: value, lowerValue: lowerValue, renderedValue: undefined, renderedLowerValue: undefined, }; return _this; } SliderBase.prototype.componentWillUnmount = function () { this._async.dispose(); this._disposeListeners(); }; SliderBase.prototype.render = function () { var _a, _b, _c; var _d = this.props, ariaLabel = _d.ariaLabel, className = _d.className, disabled = _d.disabled, label = _d.label, max = _d.max, min = _d.min, showValue = _d.showValue, buttonProps = _d.buttonProps, vertical = _d.vertical, styles = _d.styles, theme = _d.theme, originFromZero = _d.originFromZero, ranged = _d.ranged; var value = this.value; var renderedValue = this.renderedValue; var renderedLowerValue = this.renderedLowerValue; var thumbOffsetPercent = this._getPercent(renderedValue); var lowerThumbOffsetPercent = this._getPercent(renderedLowerValue); var originValue = originFromZero ? 0 : min; var originPercent = this._getPercent(originValue); var activeSectionWidth = ranged ? thumbOffsetPercent - lowerThumbOffsetPercent : Math.abs(originPercent - thumbOffsetPercent); var topSectionWidth = Math.min(100 - thumbOffsetPercent, 100 - originPercent); var bottomSectionWidth = ranged ? lowerThumbOffsetPercent : Math.min(thumbOffsetPercent, originPercent); var lengthString = vertical ? 'height' : 'width'; var onMouseDownProp = disabled ? {} : { onMouseDown: this._onMouseDownOrTouchStart }; var onTouchStartProp = disabled ? {} : { onTouchStart: this._onMouseDownOrTouchStart }; var onKeyDownProp = disabled ? {} : { onKeyDown: this._onKeyDown }; var onFocusProp = disabled ? {} : { onFocus: this._onThumbFocus }; var classNames = getClassNames(styles, { className: className, ranged: ranged, disabled: disabled, vertical: vertical, showTransitions: renderedValue === value || (ranged && renderedLowerValue === this.lowerValue), showValue: showValue, theme: theme, }); var divButtonProps = buttonProps ? getNativeProps(buttonProps, divProperties) : undefined; var sliderProps = { 'aria-disabled': disabled, role: 'slider', tabIndex: disabled ? undefined : 0, 'data-is-focusable': !disabled, }; var sliderBoxProps = __assign(__assign(__assign(__assign(__assign({ id: this._id, className: css(classNames.slideBox, buttonProps.className) }, onMouseDownProp), onTouchStartProp), onKeyDownProp), divButtonProps), (!ranged && __assign(__assign({}, sliderProps), { 'aria-valuemin': min, 'aria-valuemax': max, 'aria-valuenow': value, 'aria-valuetext': this._getAriaValueText(value), 'aria-label': ariaLabel || label }))); var thumbProps = ranged ? __assign(__assign(__assign({}, sliderProps), onFocusProp), { id: "max-" + this._id, 'aria-valuemin': this.lowerValue, 'aria-valuemax': max, 'aria-valuenow': value, 'aria-valuetext': this._getAriaValueText(value), 'aria-label': "max " + (ariaLabel || label) }) : undefined; var lowerValueThumbProps = ranged ? __assign(__assign(__assign({}, sliderProps), onFocusProp), { id: "min-" + this._id, 'aria-valuemin': min, 'aria-valuemax': value, 'aria-valuenow': this.lowerValue, 'aria-valuetext': this._getAriaValueText(this.lowerValue), 'aria-label': "min " + (ariaLabel || label) }) : undefined; return (React.createElement("div", { className: classNames.root }, label && (React.createElement(Label, __assign({ className: classNames.titleLabel }, (ariaLabel ? {} : { htmlFor: this._id }), { disabled: disabled }), label)), React.createElement("div", { className: classNames.container }, ranged && showValue && (React.createElement(Label, { className: classNames.valueLabel, disabled: disabled }, this._getValueLabel(vertical ? this.value : this.lowerValue))), React.createElement("div", __assign({}, sliderBoxProps), React.createElement("div", { ref: this._sliderLine, className: classNames.line }, originFromZero && (React.createElement("span", { className: css(classNames.zeroTick), style: this._getStyleUsingOffsetPercent(vertical, originPercent) })), ranged && (React.createElement("span", __assign({ ref: this._lowerValueThumb, className: classNames.thumb, style: this._getStyleUsingOffsetPercent(vertical, lowerThumbOffsetPercent) }, lowerValueThumbProps))), React.createElement("span", __assign({ ref: this._thumb, className: classNames.thumb, style: this._getStyleUsingOffsetPercent(vertical, thumbOffsetPercent) }, thumbProps)), (ranged || originFromZero) && (React.createElement("span", { className: css(classNames.lineContainer, classNames.inactiveSection), style: (_a = {}, _a[lengthString] = bottomSectionWidth + '%', _a) })), React.createElement("span", { className: css(classNames.lineContainer, classNames.activeSection), style: (_b = {}, _b[lengthString] = activeSectionWidth + '%', _b) }), React.createElement("span", { className: css(classNames.lineContainer, classNames.inactiveSection), style: (_c = {}, _c[lengthString] = topSectionWidth + '%', _c) }))), showValue && (React.createElement(Label, { className: classNames.valueLabel, disabled: disabled }, this._getValueLabel(ranged && vertical ? this.lowerValue : this.value)))), React.createElement(FocusRects, null))); }; SliderBase.prototype.focus = function () { if (this._thumb.current) { this._thumb.current.focus(); } }; Object.defineProperty(SliderBase.prototype, "range", { get: function () { if (this.props.ranged) { return [this.lowerValue, this.value]; } }, enumerable: true, configurable: true }); Object.defineProperty(SliderBase.prototype, "value", { get: function () { var _a = this.props.value, value = _a === void 0 ? this.state.value : _a; if (this.props.min === undefined || this.props.max === undefined || value === undefined) { return undefined; } else { return Math.max(this.props.min, Math.min(this.props.max, value)); } }, enumerable: true, configurable: true }); Object.defineProperty(SliderBase.prototype, "renderedValue", { get: function () { // renderedValue is expected to be defined while user is interacting with control, otherwise `undefined`. // Fall back to `value`. var _a = this.state.renderedValue, renderedValue = _a === void 0 ? this.value : _a; return renderedValue; }, enumerable: true, configurable: true }); Object.defineProperty(SliderBase.prototype, "lowerValue", { get: function () { var _a = this.props, _b = _a.lowerValue, lowerValue = _b === void 0 ? this.state.lowerValue : _b, ranged = _a.ranged; if (!ranged || this.props.min === undefined || this.props.max === undefined || lowerValue === undefined) { return undefined; } else { return Math.max(this.props.min, Math.min(this.props.max, lowerValue)); } }, enumerable: true, configurable: true }); Object.defineProperty(SliderBase.prototype, "renderedLowerValue", { get: function () { // renderedLowerValue is expected to be defined while user is interacting with control, otherwise `undefined`. // Fall back to `lowerValue`. var _a = this.state.renderedLowerValue, renderedLowerValue = _a === void 0 ? this.lowerValue : _a; return renderedLowerValue; }, enumerable: true, configurable: true }); SliderBase.prototype._getPercent = function (value) { var _a = this.props, min = _a.min, max = _a.max; return max === min ? 0 : ((value - min) / (max - min)) * 100; }; SliderBase.prototype._getValueLabel = function (value) { var valueFormat = this.props.valueFormat; return valueFormat ? valueFormat(value) : value; }; SliderBase.prototype._getStyleUsingOffsetPercent = function (vertical, thumbOffsetPercent) { var _a; var direction = vertical ? 'bottom' : getRTL(this.props.theme) ? 'right' : 'left'; return _a = {}, _a[direction] = thumbOffsetPercent + '%', _a; }; SliderBase.prototype._getPosition = function (event, vertical) { var currentPosition; switch (event.type) { case 'mousedown': case 'mousemove': currentPosition = !vertical ? event.clientX : event.clientY; break; case 'touchstart': case 'touchmove': currentPosition = !vertical ? event.touches[0].clientX : event.touches[0].clientY; break; } return currentPosition; }; SliderBase.prototype._setValueState = function (roundedValue, renderedValue) { var _a; var _this = this; var isAdjustingLowerValue = this._isAdjustingLowerValue; var valueChanged = roundedValue !== (isAdjustingLowerValue ? this.state.lowerValue : this.state.value); this.setState((_a = {}, _a[isAdjustingLowerValue ? 'lowerValue' : 'value'] = roundedValue, _a[isAdjustingLowerValue ? 'renderedLowerValue' : 'renderedValue'] = renderedValue, _a), function () { var _a = _this.state, lowerValue = _a.lowerValue, value = _a.value; if (valueChanged && _this.props.onChange) { _this.props.onChange(isAdjustingLowerValue ? lowerValue : value, _this.props.ranged ? [lowerValue, value] : undefined); } }); }; SliderBase.prototype._updateValue = function (value, renderedValue) { var _a = this.props, step = _a.step, snapToStep = _a.snapToStep, ranged = _a.ranged, originFromZero = _a.originFromZero; var numDec = 0; if (isFinite(step)) { while (Math.round(step * Math.pow(10, numDec)) / Math.pow(10, numDec) !== step) { numDec++; } } // Make sure value has correct number of decimal places based on number of decimals in step var roundedValue = parseFloat(value.toFixed(numDec)); if (snapToStep) { renderedValue = roundedValue; } var shouldAdjustLowerThumb = this._isAdjustingLowerValue && (originFromZero ? roundedValue <= 0 : roundedValue <= this.renderedValue); var shouldAdjustUpperThumb = !this._isAdjustingLowerValue && (originFromZero ? roundedValue >= 0 : roundedValue >= this.renderedLowerValue); if (!ranged || shouldAdjustLowerThumb || shouldAdjustUpperThumb) { this._setValueState(roundedValue, renderedValue); } }; SliderBase.defaultProps = { step: 1, min: 0, max: 10, showValue: true, disabled: false, vertical: false, buttonProps: {}, originFromZero: false, }; return SliderBase; }(React.Component)); export { SliderBase }; //# sourceMappingURL=Slider.base.js.map