@kiwicom/orbit-components
Version:
Orbit-components is a React component library which provides developers with the easiest possible way of building Kiwi.com’s products.
633 lines (510 loc) • 24.2 kB
JavaScript
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import _assertThisInitialized from "@babel/runtime/helpers/esm/assertThisInitialized";
import _inherits from "@babel/runtime/helpers/esm/inherits";
import _possibleConstructorReturn from "@babel/runtime/helpers/esm/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/esm/getPrototypeOf";
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
import * as React from "react";
import styled, { css, withTheme } from "styled-components";
import { warning } from "@adeira/js";
import transition from "../utils/transition";
import Text from "../Text";
import Heading from "../Heading";
import Stack from "../Stack";
import Hide from "../Hide";
import Handle from "./components/Handle";
import Bar from "./components/Bar";
import KEY_CODE_MAP from "../common/keyMaps";
import DEFAULT_VALUES from "./consts";
import Histogram from "./components/Histogram";
import defaultTheme from "../defaultTheme";
import mq from "../utils/mediaQuery";
import boundingClientRect from "../utils/boundingClientRect";
var StyledSlider = styled.div.withConfig({
displayName: "Slider__StyledSlider",
componentId: "j475w2-0"
})(["position:relative;"]);
StyledSlider.defaultProps = {
theme: defaultTheme
};
var StyledSliderContent = styled.div.withConfig({
displayName: "Slider__StyledSliderContent",
componentId: "j475w2-1"
})(["display:block;width:100%;box-sizing:border-box;padding-bottom:", ";", ";"], function (_ref) {
var theme = _ref.theme;
return theme.orbit.spaceXSmall;
}, mq.tablet(css(["width:calc(100% + 48px);position:absolute;bottom:-16px;left:-24px;right:-24px;opacity:0;visibility:hidden;padding:12px 24px 48px 24px;border-radius:", ";transition:", ";background:transparent;", ";"], function (_ref2) {
var theme = _ref2.theme;
return theme.orbit.borderRadiusNormal;
}, transition(["all"], "fast", "ease-in-out"), function (_ref3) {
var focused = _ref3.focused,
theme = _ref3.theme;
return focused && css(["visibility:visible;opacity:1;background:", ";box-shadow:", ";"], theme.orbit.paletteWhite, theme.orbit.boxShadowRaised);
})));
StyledSliderContent.defaultProps = {
theme: defaultTheme
};
var StyledSliderInput = styled.div.withConfig({
displayName: "Slider__StyledSliderInput",
componentId: "j475w2-2"
})(["display:flex;align-items:center;width:100%;height:24px;"]);
export var PureSlider = /*#__PURE__*/function (_React$PureComponent) {
_inherits(PureSlider, _React$PureComponent);
var _super = _createSuper(PureSlider);
function PureSlider() {
var _this;
_classCallCheck(this, PureSlider);
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = _super.call.apply(_super, [this].concat(args));
_defineProperty(_assertThisInitialized(_this), "bar", /*#__PURE__*/React.createRef());
_defineProperty(_assertThisInitialized(_this), "state", {
value: _this.props.defaultValue || DEFAULT_VALUES.VALUE,
handleIndex: null,
focused: false
});
_defineProperty(_assertThisInitialized(_this), "pauseEvent", function (event) {
if (typeof event.stopPropagation === "function") {
event.stopPropagation();
}
if (typeof event.preventDefault === "function" && (typeof event.cancelable !== "boolean" || event.cancelable)) {
event.preventDefault();
}
});
_defineProperty(_assertThisInitialized(_this), "stopPropagation", function (event) {
if (typeof event.stopPropagation === "function") event.stopPropagation();
});
_defineProperty(_assertThisInitialized(_this), "isNotEqual", function (a, b) {
if (Array.isArray(a) && Array.isArray(b)) {
return a.toString() !== b.toString();
}
return a !== b;
});
_defineProperty(_assertThisInitialized(_this), "calculateValue", function (ratio, addition, deduction) {
var _this$props = _this.props,
_this$props$maxValue = _this$props.maxValue,
maxValue = _this$props$maxValue === void 0 ? DEFAULT_VALUES.MAX : _this$props$maxValue,
_this$props$minValue = _this$props.minValue,
minValue = _this$props$minValue === void 0 ? DEFAULT_VALUES.MIN : _this$props$minValue;
return Math.round((maxValue - minValue + (addition ? 1 : 0)) * ratio + minValue - (deduction ? 1 : 0));
});
_defineProperty(_assertThisInitialized(_this), "calculateValueFromPosition", function (pageX, throughClick) {
var barRect = boundingClientRect(_this.bar);
if (barRect) {
var _this$props2 = _this.props,
histogramData = _this$props2.histogramData,
histogramLoading = _this$props2.histogramLoading,
rtl = _this$props2.theme.rtl;
var _this$state = _this.state,
handleIndex = _this$state.handleIndex,
value = _this$state.value;
var mousePosition = (rtl ? barRect.right : pageX) - (rtl ? pageX : barRect.left);
var positionRatio = mousePosition / barRect.width;
var hasHistogram = histogramLoading || !!histogramData; // when range slider
if (Array.isArray(value)) {
if (value[0] === value[value.length - 1]) {
if (_this.calculateValue(positionRatio, true, true) >= value[value.length - 1]) {
return _this.calculateValue(positionRatio, true, true);
}
return _this.calculateValue(positionRatio, true);
}
if (_this.isNotEqual(_this.sortArray(value), value)) {
if (handleIndex === 0) {
return _this.calculateValue(positionRatio, true, true);
}
return _this.calculateValue(positionRatio, true);
}
var closestKey = _this.findClosestKey(_this.calculateValue(positionRatio), _this.sortArray(value)); // when first handle of range slider or when clicked and it should move the first handle
if (handleIndex === 0 || throughClick && closestKey === 0) {
return _this.calculateValue(positionRatio, true);
}
} // simple slider without histogram
if (handleIndex === null && !hasHistogram) {
return _this.calculateValue(positionRatio);
}
return _this.calculateValue(positionRatio, true, true);
}
return null;
});
_defineProperty(_assertThisInitialized(_this), "sortArray", function (arr) {
if (Array.isArray(arr)) {
return arr.slice().sort(function (a, b) {
return a - b;
});
}
return arr;
});
_defineProperty(_assertThisInitialized(_this), "findClosestKey", function (goal, value) {
return Array.isArray(value) ? value.reduce(function (acc, curr, index) {
return Array.isArray(value) && Math.abs(curr - goal) < Math.abs(value[acc] - goal) ? index : acc;
}, 0) : null;
});
_defineProperty(_assertThisInitialized(_this), "moveValueByStep", function (step, forcedValue) {
var _this$state2 = _this.state,
value = _this$state2.value,
handleIndex = _this$state2.handleIndex;
if (Array.isArray(value)) {
return _this.replaceValue(forcedValue || _this.alignValue(value[Number(handleIndex)] + step), Number(handleIndex));
}
return forcedValue || _this.alignValue(value + step);
});
_defineProperty(_assertThisInitialized(_this), "handleKeyDown", function (event) {
if (event.ctrlKey || event.shiftKey || event.altKey) return;
var _this$props3 = _this.props,
_this$props3$step = _this$props3.step,
step = _this$props3$step === void 0 ? DEFAULT_VALUES.STEP : _this$props3$step,
_this$props3$minValue = _this$props3.minValue,
minValue = _this$props3$minValue === void 0 ? DEFAULT_VALUES.MIN : _this$props3$minValue,
_this$props3$maxValue = _this$props3.maxValue,
maxValue = _this$props3$maxValue === void 0 ? DEFAULT_VALUES.MAX : _this$props3$maxValue,
rtl = _this$props3.theme.rtl;
if (event.keyCode === KEY_CODE_MAP.ARROW_UP) {
_this.pauseEvent(event);
_this.injectCallbackAndSetState(_this.props.onChange, _this.moveValueByStep(step));
}
if (event.keyCode === KEY_CODE_MAP.ARROW_DOWN) {
_this.pauseEvent(event);
_this.injectCallbackAndSetState(_this.props.onChange, _this.moveValueByStep(-step));
}
if (event.keyCode === KEY_CODE_MAP.ARROW_RIGHT) {
var switchStep = rtl ? -step : step;
_this.pauseEvent(event);
_this.injectCallbackAndSetState(_this.props.onChange, _this.moveValueByStep(switchStep));
}
if (event.keyCode === KEY_CODE_MAP.ARROW_LEFT) {
var _switchStep = rtl ? step : -step;
_this.pauseEvent(event);
_this.injectCallbackAndSetState(_this.props.onChange, _this.moveValueByStep(_switchStep));
}
if (event.keyCode === KEY_CODE_MAP.HOME) {
_this.pauseEvent(event);
_this.injectCallbackAndSetState(_this.props.onChange, _this.moveValueByStep(0, minValue));
}
if (event.keyCode === KEY_CODE_MAP.END) {
_this.pauseEvent(event);
_this.injectCallbackAndSetState(_this.props.onChange, _this.moveValueByStep(0, maxValue));
}
});
_defineProperty(_assertThisInitialized(_this), "handleBlur", function () {
_this.setState({
focused: false
});
var value = _this.state.value;
window.removeEventListener("keydown", _this.handleKeyDown);
window.removeEventListener("focusout", _this.handleBlur);
_this.injectCallbackAndSetState(_this.props.onChangeAfter, value, true);
});
_defineProperty(_assertThisInitialized(_this), "handleOnFocus", function (i) {
return function (event) {
if (typeof i === "number") _this.setState({
handleIndex: i
});
var value = _this.state.value;
_this.setState({
focused: true
});
_this.pauseEvent(event);
window.addEventListener("keydown", _this.handleKeyDown);
window.addEventListener("focusout", _this.handleBlur);
_this.injectCallbackAndSetState(_this.props.onChangeBefore, value, true);
};
});
_defineProperty(_assertThisInitialized(_this), "handleMove", function (newValue) {
var _this$state3 = _this.state,
value = _this$state3.value,
handleIndex = _this$state3.handleIndex;
if (newValue != null) {
if (Array.isArray(value)) {
return _this.replaceValue(_this.alignValue(newValue), Number(handleIndex));
}
return _this.alignValue(newValue);
}
return null;
});
_defineProperty(_assertThisInitialized(_this), "handleBarMouseDown", function (event) {
var value = _this.state.value;
_this.setState({
handleIndex: null
});
var newValue = _this.calculateValueFromPosition(event.pageX, true);
if (newValue) {
if (Array.isArray(value)) {
var index = _this.findClosestKey(newValue, value);
var replacedValue = _this.replaceValue(_this.alignValue(newValue), index);
_this.injectCallbackAndSetState(_this.props.onChangeBefore, value, true);
_this.injectCallbackAndSetState(_this.props.onChange, replacedValue);
_this.injectCallbackAndSetState(_this.props.onChangeAfter, replacedValue);
} else {
var alignedValue = _this.alignValue(newValue);
_this.injectCallbackAndSetState(_this.props.onChangeBefore, value, true);
_this.injectCallbackAndSetState(_this.props.onChange, alignedValue);
_this.injectCallbackAndSetState(_this.props.onChangeAfter, alignedValue);
}
}
});
_defineProperty(_assertThisInitialized(_this), "injectCallbackAndSetState", function (callback, newValue) {
var forced = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
var value = _this.state.value;
if (newValue != null) {
if (_this.isNotEqual(newValue, value) || forced) {
_this.setState({
value: newValue
});
if (callback) {
callback(_this.sortArray(newValue));
}
}
}
});
_defineProperty(_assertThisInitialized(_this), "handleMouseMove", function (event) {
var newValue = _this.calculateValueFromPosition(event.pageX);
_this.pauseEvent(event);
_this.injectCallbackAndSetState(_this.props.onChange, _this.handleMove(newValue));
});
_defineProperty(_assertThisInitialized(_this), "handleMouseUp", function () {
var value = _this.state.value;
_this.setState({
focused: false
});
window.removeEventListener("mousemove", _this.handleMouseMove);
window.removeEventListener("mouseup", _this.handleMouseUp);
_this.injectCallbackAndSetState(_this.props.onChangeAfter, value, true);
});
_defineProperty(_assertThisInitialized(_this), "handleMouseDown", function (i) {
return function (event) {
// just allow left-click
if (event.button === 0 && event.buttons !== 2) {
var value = _this.state.value;
_this.setState({
focused: true
});
if (typeof i === "number") _this.setState({
handleIndex: i
});
window.addEventListener("mousemove", _this.handleMouseMove);
window.addEventListener("mouseup", _this.handleMouseUp);
_this.pauseEvent(event);
_this.injectCallbackAndSetState(_this.props.onChangeBefore, value, true);
}
};
});
_defineProperty(_assertThisInitialized(_this), "handleOnTouchMove", function (event) {
if (event.touches.length > 1) return;
var newValue = _this.calculateValueFromPosition(event.touches[0].pageX);
_this.pauseEvent(event);
_this.injectCallbackAndSetState(_this.props.onChange, _this.handleMove(newValue));
});
_defineProperty(_assertThisInitialized(_this), "handleTouchEnd", function () {
var value = _this.state.value;
_this.setState({
focused: false
});
window.removeEventListener("touchmove", _this.handleOnTouchMove);
window.removeEventListener("touchend", _this.handleTouchEnd);
_this.injectCallbackAndSetState(_this.props.onChangeAfter, value, true);
});
_defineProperty(_assertThisInitialized(_this), "handleOnTouchStart", function (i) {
return function (event) {
if (event.touches.length <= 1) {
_this.setState({
focused: true
});
var value = _this.state.value;
if (typeof i === "number") _this.setState({
handleIndex: i
});
window.addEventListener("touchmove", _this.handleOnTouchMove, {
passive: false
});
window.addEventListener("touchend", _this.handleTouchEnd);
_this.stopPropagation(event);
_this.injectCallbackAndSetState(_this.props.onChangeBefore, value, true);
}
};
});
_defineProperty(_assertThisInitialized(_this), "alignValueToStep", function (value) {
var _this$props$step = _this.props.step,
step = _this$props$step === void 0 ? DEFAULT_VALUES.STEP : _this$props$step;
if (step === 1) return value;
var gap = value % step;
if (gap === 0) return value;
if (gap * 2 >= step) {
return value - gap + step;
}
return value - gap;
});
_defineProperty(_assertThisInitialized(_this), "alignValueToMaxMin", function (value) {
var _this$props4 = _this.props,
_this$props4$maxValue = _this$props4.maxValue,
maxValue = _this$props4$maxValue === void 0 ? DEFAULT_VALUES.MAX : _this$props4$maxValue,
_this$props4$minValue = _this$props4.minValue,
minValue = _this$props4$minValue === void 0 ? DEFAULT_VALUES.MIN : _this$props4$minValue;
if (value > maxValue) {
return maxValue;
}
if (value < minValue) {
return minValue;
}
return value;
});
_defineProperty(_assertThisInitialized(_this), "alignValue", function (value) {
return _this.alignValueToMaxMin(_this.alignValueToStep(value));
});
_defineProperty(_assertThisInitialized(_this), "replaceValue", function (newValue, index) {
var value = _this.state.value;
if (index == null || !Array.isArray(value)) return newValue;
return value.map(function (item, key) {
return key === index ? newValue : item;
});
});
_defineProperty(_assertThisInitialized(_this), "renderHandle", function (valueNow, i) {
var _this$props5 = _this.props,
_this$props5$minValue = _this$props5.minValue,
minValue = _this$props5$minValue === void 0 ? DEFAULT_VALUES.MIN : _this$props5$minValue,
_this$props5$maxValue = _this$props5.maxValue,
maxValue = _this$props5$maxValue === void 0 ? DEFAULT_VALUES.MAX : _this$props5$maxValue,
histogramData = _this$props5.histogramData,
histogramLoading = _this$props5.histogramLoading,
ariaValueText = _this$props5.ariaValueText,
ariaLabel = _this$props5.ariaLabel;
var _this$state4 = _this.state,
handleIndex = _this$state4.handleIndex,
value = _this$state4.value;
var key = i && encodeURIComponent(i.toString());
var index = i || 0;
return /*#__PURE__*/React.createElement(Handle, {
tabIndex: "0",
onTop: handleIndex === i,
valueMax: maxValue,
valueMin: minValue,
onMouseDown: _this.handleMouseDown(i),
onFocus: _this.handleOnFocus(i),
onTouchStart: _this.handleOnTouchStart(i),
value: value,
ariaValueText: ariaValueText,
ariaLabel: ariaLabel,
hasHistogram: histogramLoading || !!histogramData,
index: index,
key: key,
dataTest: "SliderHandle-".concat(index)
});
});
_defineProperty(_assertThisInitialized(_this), "renderHandles", function () {
var value = _this.state.value;
return Array.isArray(value) ? value.map(function (valueNow, i) {
return _this.renderHandle(valueNow, i);
}) : _this.renderHandle(value);
});
_defineProperty(_assertThisInitialized(_this), "renderSliderTexts", function (biggerSpace) {
var _this$props6 = _this.props,
label = _this$props6.label,
valueDescription = _this$props6.valueDescription,
histogramDescription = _this$props6.histogramDescription;
if (!(label || valueDescription || histogramDescription)) return null;
return /*#__PURE__*/React.createElement(Stack, {
direction: "row",
spacing: "none",
spaceAfter: biggerSpace ? "medium" : "small"
}, (label || histogramDescription) && /*#__PURE__*/React.createElement(Stack, {
direction: "column",
spacing: "none",
basis: "60%",
grow: true
}, label && /*#__PURE__*/React.createElement(Heading, {
type: "title4"
}, label), valueDescription && /*#__PURE__*/React.createElement(Text, {
type: "secondary",
size: "small"
}, valueDescription)), histogramDescription && /*#__PURE__*/React.createElement(Stack, {
shrink: true,
justify: "end",
grow: false
}, /*#__PURE__*/React.createElement(Text, {
type: "primary",
size: "small"
}, histogramDescription)));
});
_defineProperty(_assertThisInitialized(_this), "renderHeading", function (hasHistogram) {
if (hasHistogram) {
return /*#__PURE__*/React.createElement(Hide, {
on: ["smallMobile", "mediumMobile", "largeMobile"],
block: true
}, _this.renderSliderTexts(true));
}
return _this.renderSliderTexts(true);
});
return _this;
}
_createClass(PureSlider, [{
key: "componentDidUpdate",
value: function componentDidUpdate(prevProps) {
var _this$props$defaultVa = this.props.defaultValue,
defaultValue = _this$props$defaultVa === void 0 ? DEFAULT_VALUES.VALUE : _this$props$defaultVa;
var _prevProps$defaultVal = prevProps.defaultValue,
prevDefaultValue = _prevProps$defaultVal === void 0 ? DEFAULT_VALUES.VALUE : _prevProps$defaultVal;
if (this.isNotEqual(prevDefaultValue, defaultValue)) {
var newValue = Array.isArray(defaultValue) ? defaultValue.map(function (item) {
return Number(item);
}) : Number(defaultValue); // eslint-disable-next-line react/no-did-update-set-state
this.setState({
value: newValue
});
}
}
}, {
key: "render",
value: function render() {
var _this$props7 = this.props,
_this$props7$minValue = _this$props7.minValue,
minValue = _this$props7$minValue === void 0 ? DEFAULT_VALUES.MIN : _this$props7$minValue,
_this$props7$maxValue = _this$props7.maxValue,
maxValue = _this$props7$maxValue === void 0 ? DEFAULT_VALUES.MAX : _this$props7$maxValue,
histogramData = _this$props7.histogramData,
_this$props7$histogra = _this$props7.histogramLoading,
histogramLoading = _this$props7$histogra === void 0 ? false : _this$props7$histogra,
histogramLoadingText = _this$props7.histogramLoadingText,
dataTest = _this$props7.dataTest,
_this$props7$step = _this$props7.step,
step = _this$props7$step === void 0 ? DEFAULT_VALUES.STEP : _this$props7$step;
if (histogramData) {
var properHistogramLength = (maxValue - minValue + step) / step;
process.env.NODE_ENV !== "production" ? warning(histogramData.length === properHistogramLength, "Warning: Length of histogramData array is ".concat(histogramData.length, ", but should be ").concat(properHistogramLength, ". This will cause broken visuals of the whole Histogram.")) : void 0;
}
var _this$state5 = this.state,
value = _this$state5.value,
focused = _this$state5.focused;
var sortedValue = this.sortArray(value);
var hasHistogram = histogramLoading || !!histogramData;
return /*#__PURE__*/React.createElement(StyledSlider, {
"data-test": dataTest
}, this.renderHeading(hasHistogram), hasHistogram && /*#__PURE__*/React.createElement(StyledSliderContent, {
focused: focused
}, this.renderSliderTexts(false), /*#__PURE__*/React.createElement(Histogram, {
data: histogramData,
value: sortedValue,
min: minValue,
step: step,
loading: histogramLoading,
loadingText: histogramLoadingText
})), /*#__PURE__*/React.createElement(StyledSliderInput, null, /*#__PURE__*/React.createElement(Bar, {
ref: this.bar,
onMouseDown: this.handleBarMouseDown,
value: sortedValue,
max: maxValue,
min: minValue,
hasHistogram: hasHistogram
}), this.renderHandles()));
}
}]);
return PureSlider;
}(React.PureComponent);
_defineProperty(PureSlider, "defaultProps", {
theme: defaultTheme
});
var ThemedSlider = withTheme(PureSlider);
ThemedSlider.displayName = "Slider";
export default ThemedSlider;