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 | 1x 10x 10x 10x 10x 10x 10x 10x 4x 3x 3x 10x 3x 3x 3x 2x 1x 10x 10x 12x 12x 12x 10x 9x 9x 9x 10x 4x 4x 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); // If user moves the pointer outside of the window or iframe bounds and release it there, // `mouseup`/`touchend` won't be fired. In order to stop the picker from following the cursor // after the user has moved the mouse/finger back to the document, we check `event.buttons` // and `event.touches`. It allows us to detect that the user is just moving his pointer // without pressing it down const isDown = isTouch(event) ? event.touches.length > 0 : event.buttons > 0; if (isDown && container.current) { onMoveCallback && onMoveCallback(getRelativePosition(container.current!, event), event); } else { setDragging(false); } }, [onMoveCallback], ); const handleMoveEnd = useCallback(() => setDragging(false), []); const toggleDocumentEvents = useCallback((state: boolean) => { const toggleEvent = state ? window.addEventListener : window.removeEventListener; toggleEvent(hasTouched.current ? 'touchmove' : 'mousemove', handleMove); toggleEvent(hasTouched.current ? 'touchend' : 'mouseup', handleMoveEnd); }, []); useEffect(() => { toggleDocumentEvents(isDragging); return () => { isDragging && toggleDocumentEvents(false); }; }, [isDragging, toggleDocumentEvents]); const handleMoveStart = useCallback( (event: React.MouseEvent | React.TouchEvent) => { preventDefaultMove(event.nativeEvent); if (!isValid(event.nativeEvent)) return; onKeyCallback && 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; |