UNPKG

@antonkolesnik/counter

Version:

React number increase/decrease animation

201 lines (195 loc) 8.02 kB
"use strict"; function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = Counter; var _react = _interopRequireWildcard(require("react")); var _utils = require("@antonkolesnik/utils"); var _utils2 = require("./utils"); var _constants = require("./constants"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; } // TODO: Add isLoop /* eslint-disable no-param-reassign */ function Counter(_ref) { var duration = _ref.duration, _ref$start = _ref.start, start = _ref$start === void 0 ? '0' : _ref$start, _ref$end = _ref.end, end = _ref$end === void 0 ? '0' : _ref$end, className = _ref.className, withAnimation = _ref.withAnimation, _ref$fontSize = _ref.fontSize, fontSize = _ref$fontSize === void 0 ? _constants.DEFAULT_VALUES.fontSize : _ref$fontSize, decimalsProp = _ref.decimals, onUpdate = _ref.onUpdate, _ref$isStart = _ref.isStart, isStart = _ref$isStart === void 0 ? null : _ref$isStart; var inputRef = (0, _react.useRef)(null); var currentInputValueRef = (0, _react.useRef)(''); var intervalRef = (0, _react.useRef)(null); var timeoutRef = (0, _react.useRef)(null); var decimals = decimalsProp || (0, _utils2.getDecimals)({ start: start, end: end }); var isDecrease = Number(start) > Number(end); var intervalStepTime = (0, _utils2.getIntervalStepTime)({ startNumber: start, endNumber: end, duration: duration, isDecrease: isDecrease, decimals: decimals }); var isFloatRange = (0, _utils2.isFloat)(end) || (0, _utils2.isFloat)(start); var operation = isDecrease ? -1 : 1; var fontHeight = fontSize * 1.15; // We can't make it slowly than intervalStepTime / 2, // because we will not have time to see the animation var ANIMATION_SPEED = intervalStepTime / 2; function setInputPosition(_ref2) { var isInitial = _ref2.isInitial, currentEl = _ref2.currentEl, nextEl = _ref2.nextEl; // Show the translate changes slowly // intervalStepTime / 2 - Show it at the same time as intervalStepTime, but smoother var transition = isInitial ? 'transform 0s' : "transform ".concat(ANIMATION_SPEED, "ms"); currentEl.style.transition = transition; nextEl.style.transition = transition; var currentElTranslate = isInitial // Go back and wait for the next transition ? 'translate(0, 0)' // The current element goes down/up depends on isDecrease : "translate(0, ".concat(isDecrease ? fontHeight : -fontHeight, "px)"); var nextElTranslate = isInitial /* isDecrease: move nextEl above currentEl: * 2 - position of currentEl + one more !isDecrease: do nothing isInitial: go back and wait for the next transition */ ? "translate(0, ".concat(isDecrease ? -fontHeight * 2 : 0, "px)") /* Move nextEl to the currentEl position 0 - current nextEl position, we don't see it 0 - fontHeight = goes up fontHeight*2 - fontHeight = goes down */ : "translate(0, ".concat(-fontHeight, "px)"); currentEl.style.transform = currentElTranslate; nextEl.style.transform = nextElTranslate; } function setInitialValue(value, currentEl) { currentInputValueRef.current = value; currentEl.innerText = value; } function changeInputValue(nextInputValue, currentEl, nextEl) { if (withAnimation) { // Set nextInputValue from the previous call // or currentValue from setInitialValue currentEl.innerText = currentInputValueRef.current; nextEl.innerText = nextInputValue; // This is for currentEl.innerText // when changeInputValue will be called again currentInputValueRef.current = nextInputValue; // Go back to inital translate values setInputPosition({ isInitial: true, currentEl: currentEl, nextEl: nextEl }); // Start animation here var timeout = setTimeout(function () { setInputPosition({ isInitial: false, currentEl: currentEl, nextEl: nextEl }); }, ANIMATION_SPEED); // To clear when unmount timeoutRef.current = timeout; return; } currentEl.innerText = nextInputValue; } function play(_ref3) { var counterEl = _ref3.counterEl; var currentEl = counterEl.children[0]; var nextEl = counterEl.children[1]; // To see the first start value before changing setInitialValue(start, currentEl); var currentIntervalValue = start; var timer = setInterval(function () { var nextIntervalValue = (0, _utils2.getNextIntervalValue)({ isFloatRange: isFloatRange, currentValue: Number(currentIntervalValue), decimals: decimals, operation: operation }); changeInputValue(nextIntervalValue, currentEl, nextEl); if (onUpdate) { onUpdate(nextIntervalValue); } if ((0, _utils2.isIntervalEnd)({ nextIntervalValue: nextIntervalValue, end: end, decimals: decimals })) { clearInterval(timer); } currentIntervalValue = nextIntervalValue; }, intervalStepTime); intervalRef.current = timer; } (0, _react.useEffect)(function () { if (inputRef.current) { play({ counterEl: inputRef.current }); } return function () { if (intervalRef.current) { clearInterval(intervalRef.current); } if (timeoutRef.current) { clearInterval(timeoutRef.current); } }; }, [isStart]); if (isStart !== null && !isStart) { return null; } if (!start && !end) { // eslint-disable-next-line no-console console.error(_constants.ERROR_MESSAGES.emptyStartEndValue); return /*#__PURE__*/_react["default"].createElement("span", null, _constants.ERROR_MESSAGES.emptyStartEndValue); } if (!intervalStepTime) { // eslint-disable-next-line no-console console.error(_constants.ERROR_MESSAGES.incorrectProps); return /*#__PURE__*/_react["default"].createElement("span", null, _constants.ERROR_MESSAGES.incorrectProps); } if (intervalStepTime < _constants.MINIMAL_INTERVAL_TIME || withAnimation && intervalStepTime < _constants.MINIMAL_ANIMATION_INTERVAL_TIME) { // eslint-disable-next-line no-console console.error(_constants.ERROR_MESSAGES.smallDurationValue); return /*#__PURE__*/_react["default"].createElement("span", null, _constants.ERROR_MESSAGES.smallDurationValue); } return /*#__PURE__*/_react["default"].createElement("div", { ref: inputRef, className: (0, _utils.combineStrings)('counter-number', className), style: { fontSize: fontSize, height: fontHeight } }, /*#__PURE__*/_react["default"].createElement("div", { style: { height: fontHeight }, className: "current" }), /*#__PURE__*/_react["default"].createElement("div", { style: { height: fontHeight }, className: "next" })); }