@chayns-components/devalue-slider
Version:
A slider to devalue something.
211 lines (208 loc) • 8.08 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _core = require("@chayns-components/core");
var _size = _interopRequireDefault(require("@react-hook/size"));
var _chaynsApi = require("chayns-api");
var _react = require("motion/react");
var _react2 = _interopRequireWildcard(require("react"));
var _design = require("../../hooks/design");
var _common = require("../../utils/common");
var _Slider = require("./Slider.styles");
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const Slider = /*#__PURE__*/(0, _react2.forwardRef)(({
color,
devalueColor,
trackHeight = 50,
thumbSize = 40,
borderSize = 2,
trackText = 'EINLÖSEN',
onChange = () => {},
onDevalue = () => Promise.resolve({
success: true
}),
onComplete
}, ref) => {
const [trackRef, setTrackRef] = (0, _react2.useState)(null);
const [trackWidth] = (0, _size.default)(trackRef, {
initialWidth: 300,
initialHeight: 50
});
const [iconColor, setIconColor] = (0, _react2.useState)('black');
const [isCompleted, setIsCompleted] = (0, _react2.useState)(false);
const [isDisabled, setIsDisabled] = (0, _react2.useState)(false);
const isCompletedRef = (0, _react2.useRef)(isCompleted);
const [showWaitCursor, setShowWaitCursor] = (0, _react2.useState)(false);
const scaleFactor = (0, _react2.useMemo)(() => trackHeight / thumbSize, [thumbSize, trackHeight]);
const x = (0, _react.useMotionValue)(0);
const {
icon,
styles: iconStyles
} = (0, _design.useThumbIcon)(x, iconColor);
const dragControls = (0, _react.useDragControls)();
const vibrationTrigger = (0, _react.useTransform)(x,
// round to 10 to avoid unnecessary vibrate calls
value => Math.round(value / 10) * 10);
const lastVibrationValue = (0, _react2.useRef)(0);
(0, _react2.useEffect)(() => {
vibrationTrigger.on('change', value => {
if (!isCompletedRef.current && value !== lastVibrationValue.current) {
lastVibrationValue.current = value;
void (0, _chaynsApi.vibrate)({
pattern: [10]
});
}
});
}, [vibrationTrigger]);
const containerAnimation = (0, _react.useAnimation)();
const thumbVariants = (0, _react2.useMemo)(() => (0, _Slider.createThumbVariants)({
thumbSize,
trackWidth,
scaleFactor
}), [scaleFactor, thumbSize, trackWidth]);
const textOpacity = (0, _react.useTransform)(x, [0, 120], [1, 0]);
// this is the relative value of the right edge of the thumb
const relativeValue = (0, _react.useTransform)(x, value => {
if (!value) return 0;
const thumbRadius = thumbSize * scaleFactor;
return parseFloat(((value + thumbRadius) / trackWidth * 100).toPrecision(2));
});
// this is the relative value of the center of the thumb, it is used for the background gradient
const relativeBackgroundValue = (0, _react.useTransform)(x, value => {
if (!value) return 0;
const thumbRadius = thumbSize * scaleFactor / 2;
return parseFloat(((value + thumbRadius) / trackWidth * 100).toPrecision(2));
});
const trackBackground = (0, _react.useTransform)(relativeBackgroundValue, value => {
if (isCompleted) return devalueColor;
if (!value) return 'transparent';
return `linear-gradient(to right, ${devalueColor} ${value}%, transparent ${value}%)`;
});
const handlePointerDownCapture = (0, _react2.useCallback)(event => {
const currentValue = relativeValue.get();
if (currentValue > 5) {
event.preventDefault();
event.stopPropagation();
}
void (0, _chaynsApi.invokeCall)({
action: 19,
value: {
pattern: [50],
iOSFeedbackVibration: 7
}
});
}, [relativeValue]);
const handleRedeem = (0, _react2.useCallback)(async () => {
setShowWaitCursor(true);
setIsCompleted(true);
isCompletedRef.current = true;
const devaluePromise = onDevalue();
const sleepPromise = (0, _common.sleep)(1000);
const [devalued] = await Promise.all([devaluePromise, sleepPromise]);
if (!devalued.success) {
setShowWaitCursor(false);
setIsCompleted(false);
isCompletedRef.current = false;
await containerAnimation.start('base');
return;
}
setShowWaitCursor(false);
setIconColor('white');
void (0, _chaynsApi.invokeCall)({
action: 19,
value: {
iOSFeedbackVibration: 3,
pattern: [100, 200, 100]
}
});
await containerAnimation.start('completed');
await containerAnimation.start('leaving');
onComplete === null || onComplete === void 0 || onComplete();
}, [containerAnimation, onComplete, onDevalue]);
const handleTrackRef = (0, _react2.useCallback)(node => {
setTrackRef(node);
}, []);
const handleDragStart = (0, _react2.useCallback)(() => {
void containerAnimation.start('dragging');
}, [containerAnimation]);
const handleDragEnd = (0, _react2.useCallback)(() => {
if (relativeValue.get() > 98) {
void handleRedeem();
return;
}
void containerAnimation.start('base');
}, [relativeValue, containerAnimation, handleRedeem]);
(0, _react2.useEffect)(() => {
void containerAnimation.start('base');
}, [containerAnimation]);
(0, _react2.useEffect)(() => {
if (isCompleted) return () => {};
return relativeValue.on('change', onChange);
}, [isCompleted, onChange, relativeValue]);
(0, _react2.useImperativeHandle)(ref, () => ({
disable: () => {
setIsDisabled(true);
setShowWaitCursor(false);
setIsCompleted(false);
isCompletedRef.current = false;
void containerAnimation.start('base');
},
enable: () => {
setIsDisabled(false);
}
}), [containerAnimation]);
const baseFontSize = (0, _react2.useMemo)(() => 22, []);
return /*#__PURE__*/_react2.default.createElement(_Slider.Container, {
animate: containerAnimation
}, /*#__PURE__*/_react2.default.createElement(_Slider.Track, {
$height: trackHeight,
$borderSize: borderSize,
$backgroundColor: color,
ref: handleTrackRef
}, /*#__PURE__*/_react2.default.createElement(_Slider.TrackBackground, {
$height: trackHeight,
style: {
background: trackBackground
}
}), /*#__PURE__*/_react2.default.createElement(_Slider.Thumb, {
variants: thumbVariants,
$size: thumbSize,
$trackHeight: trackHeight,
style: {
x
},
drag: isCompleted || isDisabled ? false : 'x',
dragElastic: 0,
onPointerDownCapture: handlePointerDownCapture,
whileTap: {
scale: 1.4,
cursor: 'grabbing'
},
onDragStart: handleDragStart,
onDragEnd: handleDragEnd,
dragControls: dragControls,
dragConstraints: {
right: trackWidth - thumbSize * scaleFactor,
left: 0
}
}, /*#__PURE__*/_react2.default.createElement(_Slider.ThumbIconContainer, null, !showWaitCursor && /*#__PURE__*/_react2.default.createElement(_Slider.ThumbIcon, {
key: "thumb-icon",
icon: icon,
variants: _Slider.THUMB_ICON_VARIANTS,
style: iconStyles
}), showWaitCursor && /*#__PURE__*/_react2.default.createElement(_core.SmallWaitCursor, {
shouldHideBackground: true,
color: "black"
}))), /*#__PURE__*/_react2.default.createElement(_Slider.TrackText, {
style: {
opacity: textOpacity
},
$color: "white",
$baseFontSize: baseFontSize
}, trackText)));
});
var _default = exports.default = Slider;
//# sourceMappingURL=Slider.js.map