[Glitch] Fix media modal navigation in RTL languages
Port f1b0832bfb08dc2d8ccb410be917095f0fcac62e to glitch-soc Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
parent
695371f591
commit
5109b00bc0
@ -47,11 +47,9 @@ interface MediaModalProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const MIN_SWIPE_DISTANCE = 400;
|
const MIN_SWIPE_DISTANCE = 400;
|
||||||
|
const isLtrDir = getComputedStyle(document.body).direction !== 'rtl';
|
||||||
|
|
||||||
export const MediaModal: FC<MediaModalProps> = forwardRef<
|
export const MediaModal = forwardRef<HTMLDivElement, MediaModalProps>(
|
||||||
HTMLDivElement,
|
|
||||||
MediaModalProps
|
|
||||||
>(
|
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
media,
|
media,
|
||||||
@ -64,15 +62,16 @@ export const MediaModal: FC<MediaModalProps> = forwardRef<
|
|||||||
statusId,
|
statusId,
|
||||||
onChangeBackgroundColor,
|
onChangeBackgroundColor,
|
||||||
},
|
},
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- _ref is required to keep the ref forwarding working
|
|
||||||
_ref,
|
_ref,
|
||||||
) => {
|
) => {
|
||||||
const [index, setIndex] = useState(startIndex);
|
const [index, setIndex] = useState(startIndex);
|
||||||
const [zoomedIn, setZoomedIn] = useState(false);
|
const [zoomedIn, setZoomedIn] = useState(false);
|
||||||
const currentMedia = media.get(index);
|
const currentMedia = media.get(index);
|
||||||
|
|
||||||
|
const sign = isLtrDir ? '-' : '';
|
||||||
|
|
||||||
const [wrapperStyles, api] = useSpring(() => ({
|
const [wrapperStyles, api] = useSpring(() => ({
|
||||||
x: `-${index * 100}%`,
|
x: `${sign}${index * 100}%`,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const handleChangeIndex = useCallback(
|
const handleChangeIndex = useCallback(
|
||||||
@ -85,10 +84,12 @@ export const MediaModal: FC<MediaModalProps> = forwardRef<
|
|||||||
setIndex(newIndex);
|
setIndex(newIndex);
|
||||||
setZoomedIn(false);
|
setZoomedIn(false);
|
||||||
if (animate) {
|
if (animate) {
|
||||||
void api.start({ x: `calc(-${newIndex * 100}% + 0px)` });
|
void api.start({
|
||||||
|
x: `calc(${sign}${newIndex * 100}% + 0px)`,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[api, media.size],
|
[api, media.size, sign],
|
||||||
);
|
);
|
||||||
const handlePrevClick = useCallback(() => {
|
const handlePrevClick = useCallback(() => {
|
||||||
handleChangeIndex(index - 1, true);
|
handleChangeIndex(index - 1, true);
|
||||||
@ -99,11 +100,14 @@ export const MediaModal: FC<MediaModalProps> = forwardRef<
|
|||||||
|
|
||||||
const handleKeyDown = useCallback(
|
const handleKeyDown = useCallback(
|
||||||
(event: KeyboardEvent) => {
|
(event: KeyboardEvent) => {
|
||||||
if (event.key === 'ArrowLeft') {
|
const prevKey = isLtrDir ? 'ArrowLeft' : 'ArrowRight';
|
||||||
|
const nextKey = isLtrDir ? 'ArrowRight' : 'ArrowLeft';
|
||||||
|
|
||||||
|
if (event.key === prevKey) {
|
||||||
handlePrevClick();
|
handlePrevClick();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
} else if (event.key === 'ArrowRight') {
|
} else if (event.key === nextKey) {
|
||||||
handleNextClick();
|
handleNextClick();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
@ -124,13 +128,14 @@ export const MediaModal: FC<MediaModalProps> = forwardRef<
|
|||||||
active &&
|
active &&
|
||||||
Math.abs(mx) > Math.min(window.innerWidth / 4, MIN_SWIPE_DISTANCE)
|
Math.abs(mx) > Math.min(window.innerWidth / 4, MIN_SWIPE_DISTANCE)
|
||||||
) {
|
) {
|
||||||
handleChangeIndex(index - xDir);
|
handleChangeIndex(isLtrDir ? index - xDir : index + xDir);
|
||||||
cancel();
|
cancel();
|
||||||
}
|
}
|
||||||
// Set the x position via calc to ensure proper centering regardless of screen size.
|
// Set the x position via calc to ensure proper centering regardless of screen size.
|
||||||
const x = active ? mx : 0;
|
const x = active ? mx : 0;
|
||||||
|
const operator = isLtrDir ? '+' : '-';
|
||||||
void api.start({
|
void api.start({
|
||||||
x: `calc(-${index * 100}% + ${x}px)`,
|
x: `calc(${sign}${index * 100}% ${operator} ${x}px)`,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
{ pointer: { capture: false } },
|
{ pointer: { capture: false } },
|
||||||
@ -161,14 +166,23 @@ export const MediaModal: FC<MediaModalProps> = forwardRef<
|
|||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
}>({ width: 0, height: 0 });
|
}>({ width: 0, height: 0 });
|
||||||
const handleRef: RefCallback<HTMLDivElement> = useCallback((ele) => {
|
const handleRef: RefCallback<HTMLDivElement> = useCallback(
|
||||||
if (ele?.clientWidth && ele.clientHeight) {
|
(ele) => {
|
||||||
setViewportDimensions({
|
if (typeof _ref === 'function') {
|
||||||
width: ele.clientWidth,
|
_ref(ele);
|
||||||
height: ele.clientHeight,
|
} else if (_ref) {
|
||||||
});
|
_ref.current = ele;
|
||||||
}
|
}
|
||||||
}, []);
|
|
||||||
|
if (ele?.clientWidth && ele.clientHeight) {
|
||||||
|
setViewportDimensions({
|
||||||
|
width: ele.clientWidth,
|
||||||
|
height: ele.clientHeight,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[_ref],
|
||||||
|
);
|
||||||
|
|
||||||
const zoomable =
|
const zoomable =
|
||||||
currentMedia?.get('type') === 'image' &&
|
currentMedia?.get('type') === 'image' &&
|
||||||
@ -268,9 +282,8 @@ export const MediaModal: FC<MediaModalProps> = forwardRef<
|
|||||||
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const leftNav = media.size > 1 && (
|
const prevNav = media.size > 1 && (
|
||||||
<button
|
<button
|
||||||
tabIndex={0}
|
|
||||||
className='media-modal__nav media-modal__nav--prev'
|
className='media-modal__nav media-modal__nav--prev'
|
||||||
onClick={handlePrevClick}
|
onClick={handlePrevClick}
|
||||||
aria-label={intl.formatMessage(messages.previous)}
|
aria-label={intl.formatMessage(messages.previous)}
|
||||||
@ -279,9 +292,8 @@ export const MediaModal: FC<MediaModalProps> = forwardRef<
|
|||||||
<Icon id='chevron-left' icon={ChevronLeftIcon} />
|
<Icon id='chevron-left' icon={ChevronLeftIcon} />
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
const rightNav = media.size > 1 && (
|
const nextNav = media.size > 1 && (
|
||||||
<button
|
<button
|
||||||
tabIndex={0}
|
|
||||||
className='media-modal__nav media-modal__nav--next'
|
className='media-modal__nav media-modal__nav--next'
|
||||||
onClick={handleNextClick}
|
onClick={handleNextClick}
|
||||||
aria-label={intl.formatMessage(messages.next)}
|
aria-label={intl.formatMessage(messages.next)}
|
||||||
@ -330,8 +342,8 @@ export const MediaModal: FC<MediaModalProps> = forwardRef<
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{leftNav}
|
{prevNav}
|
||||||
{rightNav}
|
{nextNav}
|
||||||
|
|
||||||
<div className='media-modal__overlay'>
|
<div className='media-modal__overlay'>
|
||||||
<MediaPagination
|
<MediaPagination
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user