@yandex/ui
Version:
Yandex UI components
95 lines (94 loc) • 5.42 kB
JavaScript
import { __assign } from "tslib";
import React, { useMemo, useRef } from 'react';
import { noop, useDrag } from '../Drawer.utils';
import { cnDrawerContent, cnDrawerCurtain, cnDrawerDragObserver, cnDrawerHandle, cnDrawerOverlay, cnDrawerTitle, } from '../Drawer.const';
/**
* Компонент содержимого шторки.
*
* При использовании Popup мы не знаем в какой конкретно
* момент содержимое монтируется/размонтируется, если
* прокидывать его напрямую без обёрток.
*/
export var DrawerContent = function (_a) {
var dragDisabled = _a.dragDisabled, visible = _a.visible, _b = _a.onClose, onClose = _b === void 0 ? noop : _b, springValue = _a.springValue, _c = _a.direction, direction = _c === void 0 ? 'bottom' : _c, maxSize = _a.maxSize, titleComponent = _a.titleComponent, children = _a.children, setSpringDisabled = _a.setSpringDisabled, setProgress = _a.setProgress;
var dragObserverRef = useRef(null);
var contentRef = useRef(null);
var axis = direction === 'bottom' ? 'y' : 'x';
var inverted = direction === 'left' ? -1 : 1;
var springOpacity = Math.max(springValue, 0);
var springTransform = axis === 'x'
? "translate3d(" + (1 - springValue) * 100 * inverted + "%,0,0)"
: "translate3d(0," + (1 - springValue) * 100 * inverted + "%,0)";
var curtainStyle = useMemo(function () {
var _a;
return (__assign({ transform: springTransform }, (maxSize && (_a = {}, _a[axis === 'x' ? 'maxWidth' : 'maxHeight'] = maxSize, _a))));
}, [springTransform, maxSize, axis]);
/**
* Обработчик drag событий с корневого DOM элемента шторки
*/
useDrag(dragObserverRef, function (dragState) {
if (!visible || !contentRef.current)
return;
var _a = dragState.velocity, vx = _a.x, vy = _a.y, _b = dragState.movement, mx = _b.x, my = _b.y, first = dragState.first, last = dragState.last, data = dragState.data, event = dragState.event;
var drawerSize = axis === 'x' ? contentRef.current.clientWidth : contentRef.current.clientHeight;
var movement = inverted * (axis === 'x' ? mx : my);
var velocity = inverted * (axis === 'x' ? vx : vy);
if (first) {
data.isTargetUnderContent = contentRef.current.contains(event.target);
data.initialScrollPosition = contentRef.current.scrollTop;
data.isScrolled = data.initialScrollPosition !== 0;
}
else {
data.isScrolled = data.isScrolled || data.initialScrollPosition - contentRef.current.scrollTop < 0;
}
// предотвращает инерционный проскролл родительских элементов, если это возможно
if (event.cancelable && event.type === 'touchmove') {
if (data.isTargetUnderContent) {
// элемент проскроллен до верхней границы
if (contentRef.current.scrollTop <= 0 && my > 0) {
event.preventDefault();
}
// элемент проскроллен до нижней границы
if (contentRef.current.scrollHeight - contentRef.current.scrollTop <= contentRef.current.clientHeight &&
my < 0) {
event.preventDefault();
}
}
else {
event.preventDefault();
}
}
// ничего не делаем когда жест происходит одновременно с проскроллом
// или если шторка в статичном состоянии
// @see SERP-107544
if (dragDisabled || (data.isTargetUnderContent && data.isScrolled)) {
return;
}
// жест завершен, возвращаем шторку в открытое положение, если
// скорость была недостаточной и, закрываем если наоборот
if (last) {
setSpringDisabled(false);
if (Math.abs(velocity) >= 0.1) {
return velocity > 0 ? onClose() : setProgress(1);
}
else if (movement / drawerSize >= 0.3) {
return onClose();
}
return setProgress(1);
}
if (movement > 0) {
setSpringDisabled(true);
var progress = Math.max(0, 1 - movement / drawerSize);
if (progress === 0) {
return onClose();
}
return setProgress(progress);
}
});
return (React.createElement("div", { className: cnDrawerDragObserver, ref: dragObserverRef },
React.createElement("div", { className: cnDrawerOverlay, style: { opacity: springOpacity }, onClick: onClose }),
React.createElement("div", { className: cnDrawerCurtain, style: curtainStyle },
React.createElement("div", { className: cnDrawerHandle, style: { opacity: springOpacity } }),
titleComponent && React.createElement("div", { className: cnDrawerTitle }, titleComponent),
React.createElement("div", { className: cnDrawerContent, ref: contentRef }, children))));
};