Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | 1x 10x 10x 10x 10x 10x 10x 10x 4x 3x 3x 10x 3x 3x 3x 3x 1x 1x 2x 10x 10x 18x 3x 3x 15x 15x 15x 15x 10x 9x 9x 9x 10x 4x 4x 3x 3x 3x 10x 1x | import React, { useRef, useState, useCallback, useEffect } from 'react'; import { isTouch, preventDefaultMove, getRelativePosition, Interaction, useEventCallback } from './utils'; export * from './utils'; export interface InteractiveProps extends React.HTMLAttributes<HTMLDivElement> { prefixCls?: string; onMove?: (interaction: Interaction, event: MouseEvent | TouchEvent) => void; onDown?: (offset: Interaction, event: MouseEvent | TouchEvent) => void; } const Interactive = React.forwardRef<HTMLDivElement, InteractiveProps>((props, ref) => { const { prefixCls = 'w-color-interactive', className, onMove, onDown, ...reset } = props; const container = useRef<HTMLDivElement>(null); const hasTouched = useRef(false); const [isDragging, setDragging] = useState(false); const onMoveCallback = useEventCallback<Interaction, MouseEvent | TouchEvent>(onMove); const onKeyCallback = useEventCallback<Interaction, MouseEvent | TouchEvent>(onDown); // Prevent mobile browsers from handling mouse events (conflicting with touch ones). // If we detected a touch interaction before, we prefer reacting to touch events only. const isValid = (event: MouseEvent | TouchEvent): boolean => { if (hasTouched.current && !isTouch(event)) return false; hasTouched.current = isTouch(event); return true; }; const handleMove = useCallback( (event: MouseEvent | TouchEvent) => { preventDefaultMove(event); Iif (!container.current) return; const isDown = isTouch(event) ? event.touches.length > 0 : event.buttons > 0; if (!isDown) { setDragging(false); return; } onMoveCallback?.(getRelativePosition(container.current, event), event); }, [onMoveCallback], ); const handleMoveEnd = useCallback(() => setDragging(false), []); const toggleDocumentEvents = useCallback( (state: boolean) => { if (state) { window.addEventListener(hasTouched.current ? 'touchmove' : 'mousemove', handleMove); window.addEventListener(hasTouched.current ? 'touchend' : 'mouseup', handleMoveEnd); } else { window.removeEventListener('mousemove', handleMove); window.removeEventListener('mouseup', handleMoveEnd); window.removeEventListener('touchmove', handleMove); window.removeEventListener('touchend', handleMoveEnd); } }, [handleMove, handleMoveEnd], ); useEffect(() => { toggleDocumentEvents(isDragging); return () => { toggleDocumentEvents(false); }; }, [isDragging, handleMove, handleMoveEnd, toggleDocumentEvents]); const handleMoveStart = useCallback( (event: React.MouseEvent | React.TouchEvent) => { preventDefaultMove(event.nativeEvent); if (!isValid(event.nativeEvent)) return; Iif (!container.current) return; onKeyCallback?.(getRelativePosition(container.current, event.nativeEvent), event.nativeEvent); setDragging(true); }, [onKeyCallback], ); return ( <div {...reset} className={[prefixCls, className || ''].filter(Boolean).join(' ')} style={{ ...reset.style, touchAction: 'none', }} ref={container} tabIndex={0} onMouseDown={handleMoveStart} onTouchStart={handleMoveStart} /> ); }); Interactive.displayName = 'Interactive'; export default Interactive; |