UNPKG

@yandex/ui

Version:

Yandex UI components

95 lines (94 loc) 5.42 kB
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)))); };