mirror of
https://github.com/mastodon/mastodon
synced 2025-04-12 00:56:38 +02:00
Change alt text modal to use spring animations in web UI (#34345)
This commit is contained in:
parent
0e5be63fb3
commit
b7c3235349
@ -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') {
|
||||
|
Loading…
x
Reference in New Issue
Block a user