mirror of
https://github.com/mastodon/mastodon.git
synced 2025-05-11 20:21:10 +00: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,
|
useState,
|
||||||
useCallback,
|
useCallback,
|
||||||
useRef,
|
useRef,
|
||||||
useEffect,
|
|
||||||
useImperativeHandle,
|
useImperativeHandle,
|
||||||
forwardRef,
|
forwardRef,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
|
@ -13,6 +12,7 @@ import classNames from 'classnames';
|
||||||
|
|
||||||
import type { List as ImmutableList, Map as ImmutableMap } from 'immutable';
|
import type { List as ImmutableList, Map as ImmutableMap } from 'immutable';
|
||||||
|
|
||||||
|
import { useSpring, animated } from '@react-spring/web';
|
||||||
import Textarea from 'react-textarea-autosize';
|
import Textarea from 'react-textarea-autosize';
|
||||||
import { length } from 'stringz';
|
import { length } from 'stringz';
|
||||||
// eslint-disable-next-line import/extensions
|
// 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 { CharacterCounter } from 'mastodon/features/compose/components/character_counter';
|
||||||
import { Tesseract as fetchTesseract } from 'mastodon/features/ui/util/async-components';
|
import { Tesseract as fetchTesseract } from 'mastodon/features/ui/util/async-components';
|
||||||
import { Video, getPointerPosition } from 'mastodon/features/video';
|
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 type { MediaAttachment } from 'mastodon/models/media_attachment';
|
||||||
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||||
import { assetHost } from 'mastodon/utils/config';
|
import { assetHost } from 'mastodon/utils/config';
|
||||||
|
@ -105,6 +105,17 @@ const Preview: React.FC<{
|
||||||
position: FocalPoint;
|
position: FocalPoint;
|
||||||
onPositionChange: (arg0: FocalPoint) => void;
|
onPositionChange: (arg0: FocalPoint) => void;
|
||||||
}> = ({ mediaId, position, onPositionChange }) => {
|
}> = ({ 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) =>
|
const media = useAppSelector((state) =>
|
||||||
(
|
(
|
||||||
(state.compose as ImmutableMap<string, unknown>).get(
|
(state.compose as ImmutableMap<string, unknown>).get(
|
||||||
|
@ -117,9 +128,6 @@ const Preview: React.FC<{
|
||||||
);
|
);
|
||||||
|
|
||||||
const [dragging, setDragging] = useState(false);
|
const [dragging, setDragging] = useState(false);
|
||||||
const [x, y] = position;
|
|
||||||
const nodeRef = useRef<HTMLImageElement | HTMLVideoElement | null>(null);
|
|
||||||
const draggingRef = useRef<boolean>(false);
|
|
||||||
|
|
||||||
const setRef = useCallback(
|
const setRef = useCallback(
|
||||||
(e: HTMLImageElement | HTMLVideoElement | null) => {
|
(e: HTMLImageElement | HTMLVideoElement | null) => {
|
||||||
|
@ -134,36 +142,30 @@ const Preview: React.FC<{
|
||||||
return;
|
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);
|
const { x, y } = getPointerPosition(nodeRef.current, e.nativeEvent);
|
||||||
|
|
||||||
setDragging(true);
|
setDragging(true);
|
||||||
draggingRef.current = true;
|
|
||||||
onPositionChange([x, y]);
|
onPositionChange([x, y]);
|
||||||
|
|
||||||
|
document.addEventListener('mouseup', handleMouseUp);
|
||||||
|
document.addEventListener('mousemove', handleMouseMove);
|
||||||
},
|
},
|
||||||
[setDragging, onPositionChange],
|
[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) {
|
if (!media) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -179,10 +181,7 @@ const Preview: React.FC<{
|
||||||
role='presentation'
|
role='presentation'
|
||||||
onMouseDown={handleMouseDown}
|
onMouseDown={handleMouseDown}
|
||||||
/>
|
/>
|
||||||
<div
|
<animated.div className='focal-point__reticle' style={style} />
|
||||||
className='focal-point__reticle'
|
|
||||||
style={{ top: `${y * 100}%`, left: `${x * 100}%` }}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (media.get('type') === 'gifv') {
|
} else if (media.get('type') === 'gifv') {
|
||||||
|
@ -194,10 +193,7 @@ const Preview: React.FC<{
|
||||||
alt=''
|
alt=''
|
||||||
onMouseDown={handleMouseDown}
|
onMouseDown={handleMouseDown}
|
||||||
/>
|
/>
|
||||||
<div
|
<animated.div className='focal-point__reticle' style={style} />
|
||||||
className='focal-point__reticle'
|
|
||||||
style={{ top: `${y * 100}%`, left: `${x * 100}%` }}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (media.get('type') === 'video') {
|
} else if (media.get('type') === 'video') {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user