import { CSSProperties, ReactNode, RefObject, forwardRef, useImperativeHandle, useRef, useContext, useEffect, } from 'react' import classNames from 'classnames' import { CommonComponentProps } from '../../utils/types' import { UseMovableOptions, useMovable, BoundingRect } from './useMovable' import { MovableAreaContext } from './MovableArea' export interface MovableViewProps extends CommonComponentProps, UseMovableOptions { rootRef?: RefObject className?: string style?: CSSProperties children?: ReactNode } export interface MovableViewRef { updateRect(rect?: BoundingRect): void } function translate3d(x: number, y: number, z: number) { return `translate3d(${x}px, ${y}px, ${z}px)` } export const MovableView = forwardRef( (props, ref) => { const { rootRef, className, style, children, x, y, defaultX, defaultY, direction, inertia, inertiaDuration, inertiaTime, outOfBounds, inertiaMaxOverflow, damping, reboundDuration, lockDirection, onChange, onPanStart, onPanMove, onPanEnd, ...restProps } = props const viewRef = useRef(null) const areaRect = useContext(MovableAreaContext) const { updateRect, x: innerX, y: innerY, willChange, } = useMovable(areaRect, props) useEffect(() => { updateRect(viewRef.current?.getBoundingClientRect()) }, []) useImperativeHandle(ref, () => ({ updateRect, })) const areaClass = classNames('s-movable-view', className) const viewStyle = { transform: translate3d(innerX, innerY, 0), willChange, ...style, } return (
{children}
) } ) export default MovableView /* # 优化 - 值改变时才触发 onChange # 功能开发 [x] 超出边界 [x] 固定方向 [-] 动态尺寸 [ ] 相对单位(百分比) [x] 惯性 # 问题 [x] 锁定方向阻止默认行为 */