Change alt text modal to use spring animations in web UI (#34345)
This commit is contained in:
		@@ -2,7 +2,6 @@ import {
 | 
			
		||||
  useState,
 | 
			
		||||
  useCallback,
 | 
			
		||||
  useRef,
 | 
			
		||||
  useEffect,
 | 
			
		||||
  useImperativeHandle,
 | 
			
		||||
  forwardRef,
 | 
			
		||||
} from 'react';
 | 
			
		||||
@@ -13,6 +12,7 @@ import classNames from 'classnames';
 | 
			
		||||
 | 
			
		||||
import type { List as ImmutableList, Map as ImmutableMap } from 'immutable';
 | 
			
		||||
 | 
			
		||||
import { useSpring, animated } from '@react-spring/web';
 | 
			
		||||
import Textarea from 'react-textarea-autosize';
 | 
			
		||||
import { length } from 'stringz';
 | 
			
		||||
// eslint-disable-next-line import/extensions
 | 
			
		||||
@@ -31,7 +31,7 @@ import Audio from 'mastodon/features/audio';
 | 
			
		||||
import { CharacterCounter } from 'mastodon/features/compose/components/character_counter';
 | 
			
		||||
import { Tesseract as fetchTesseract } from 'mastodon/features/ui/util/async-components';
 | 
			
		||||
import { Video, getPointerPosition } from 'mastodon/features/video';
 | 
			
		||||
import { me } from 'mastodon/initial_state';
 | 
			
		||||
import { me, reduceMotion } from 'mastodon/initial_state';
 | 
			
		||||
import type { MediaAttachment } from 'mastodon/models/media_attachment';
 | 
			
		||||
import { useAppSelector, useAppDispatch } from 'mastodon/store';
 | 
			
		||||
import { assetHost } from 'mastodon/utils/config';
 | 
			
		||||
@@ -105,6 +105,17 @@ const Preview: React.FC<{
 | 
			
		||||
  position: FocalPoint;
 | 
			
		||||
  onPositionChange: (arg0: FocalPoint) => void;
 | 
			
		||||
}> = ({ mediaId, position, onPositionChange }) => {
 | 
			
		||||
  const draggingRef = useRef<boolean>(false);
 | 
			
		||||
  const nodeRef = useRef<HTMLImageElement | HTMLVideoElement | null>(null);
 | 
			
		||||
 | 
			
		||||
  const [x, y] = position;
 | 
			
		||||
  const style = useSpring({
 | 
			
		||||
    to: {
 | 
			
		||||
      left: `${x * 100}%`,
 | 
			
		||||
      top: `${y * 100}%`,
 | 
			
		||||
    },
 | 
			
		||||
    immediate: reduceMotion || draggingRef.current,
 | 
			
		||||
  });
 | 
			
		||||
  const media = useAppSelector((state) =>
 | 
			
		||||
    (
 | 
			
		||||
      (state.compose as ImmutableMap<string, unknown>).get(
 | 
			
		||||
@@ -117,9 +128,6 @@ const Preview: React.FC<{
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const [dragging, setDragging] = useState(false);
 | 
			
		||||
  const [x, y] = position;
 | 
			
		||||
  const nodeRef = useRef<HTMLImageElement | HTMLVideoElement | null>(null);
 | 
			
		||||
  const draggingRef = useRef<boolean>(false);
 | 
			
		||||
 | 
			
		||||
  const setRef = useCallback(
 | 
			
		||||
    (e: HTMLImageElement | HTMLVideoElement | null) => {
 | 
			
		||||
@@ -134,36 +142,30 @@ const Preview: React.FC<{
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const handleMouseMove = (e: MouseEvent) => {
 | 
			
		||||
        const { x, y } = getPointerPosition(nodeRef.current, e);
 | 
			
		||||
        draggingRef.current = true; // This will disable the animation for quicker feedback, only do this if the mouse actually moves
 | 
			
		||||
        onPositionChange([x, y]);
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      const handleMouseUp = () => {
 | 
			
		||||
        setDragging(false);
 | 
			
		||||
        draggingRef.current = false;
 | 
			
		||||
        document.removeEventListener('mouseup', handleMouseUp);
 | 
			
		||||
        document.removeEventListener('mousemove', handleMouseMove);
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      const { x, y } = getPointerPosition(nodeRef.current, e.nativeEvent);
 | 
			
		||||
 | 
			
		||||
      setDragging(true);
 | 
			
		||||
      draggingRef.current = true;
 | 
			
		||||
      onPositionChange([x, y]);
 | 
			
		||||
 | 
			
		||||
      document.addEventListener('mouseup', handleMouseUp);
 | 
			
		||||
      document.addEventListener('mousemove', handleMouseMove);
 | 
			
		||||
    },
 | 
			
		||||
    [setDragging, onPositionChange],
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const handleMouseUp = () => {
 | 
			
		||||
      setDragging(false);
 | 
			
		||||
      draggingRef.current = false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const handleMouseMove = (e: MouseEvent) => {
 | 
			
		||||
      if (draggingRef.current) {
 | 
			
		||||
        const { x, y } = getPointerPosition(nodeRef.current, e);
 | 
			
		||||
        onPositionChange([x, y]);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    document.addEventListener('mouseup', handleMouseUp);
 | 
			
		||||
    document.addEventListener('mousemove', handleMouseMove);
 | 
			
		||||
 | 
			
		||||
    return () => {
 | 
			
		||||
      document.removeEventListener('mouseup', handleMouseUp);
 | 
			
		||||
      document.removeEventListener('mousemove', handleMouseMove);
 | 
			
		||||
    };
 | 
			
		||||
  }, [setDragging, onPositionChange]);
 | 
			
		||||
 | 
			
		||||
  if (!media) {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
@@ -179,10 +181,7 @@ const Preview: React.FC<{
 | 
			
		||||
          role='presentation'
 | 
			
		||||
          onMouseDown={handleMouseDown}
 | 
			
		||||
        />
 | 
			
		||||
        <div
 | 
			
		||||
          className='focal-point__reticle'
 | 
			
		||||
          style={{ top: `${y * 100}%`, left: `${x * 100}%` }}
 | 
			
		||||
        />
 | 
			
		||||
        <animated.div className='focal-point__reticle' style={style} />
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
  } else if (media.get('type') === 'gifv') {
 | 
			
		||||
@@ -194,10 +193,7 @@ const Preview: React.FC<{
 | 
			
		||||
          alt=''
 | 
			
		||||
          onMouseDown={handleMouseDown}
 | 
			
		||||
        />
 | 
			
		||||
        <div
 | 
			
		||||
          className='focal-point__reticle'
 | 
			
		||||
          style={{ top: `${y * 100}%`, left: `${x * 100}%` }}
 | 
			
		||||
        />
 | 
			
		||||
        <animated.div className='focal-point__reticle' style={style} />
 | 
			
		||||
      </div>
 | 
			
		||||
    );
 | 
			
		||||
  } else if (media.get('type') === 'video') {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user