perf(reply-modal): fix laggy dragging during post loading with GPU-accelerated gestures

This commit is contained in:
Tom (plebeius.eth)
2025-03-01 11:48:56 +01:00
parent d4b1699469
commit 0caa8f9e70
4 changed files with 99 additions and 18 deletions
@@ -1,7 +1,5 @@
.container {
position: fixed;
top: calc(50% - 150px);
left: calc(50% - 150px);
display: block;
padding: 2px;
font-size: 10pt;
@@ -10,6 +8,9 @@
z-index: 3;
background-color: var(--challenge-modal-background-color);
border: var(--challenge-modal-border);
will-change: transform;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
}
.title {
@@ -24,6 +25,9 @@
background-color: var(--challenge-modal-title-background-color);
color: var(--challenge-modal-title-text-color);
border: var(--challenge-modal-title-border);
user-select: none;
-webkit-user-select: none;
touch-action: none;
}
.closeIcon {
+34 -16
View File
@@ -1,7 +1,6 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { useLocation, useParams } from 'react-router-dom';
import { Trans, useTranslation } from 'react-i18next';
import Draggable from 'react-draggable';
import { setAccount, useAccount, useComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
import { formatMarkdown } from '../../lib/utils/post-utils';
@@ -17,6 +16,8 @@ import _ from 'lodash';
import useAnonMode from '../../hooks/use-anon-mode';
import FileUploader from '../../plugins/file-uploader';
import { Capacitor } from '@capacitor/core';
import { useSpring, animated } from '@react-spring/web';
import { useDrag } from '@use-gesture/react';
const isAndroid = Capacitor.getPlatform() === 'android';
@@ -144,14 +145,32 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, postCid, scrollY, s
const nodeRef = useRef<HTMLDivElement>(null);
const isMobile = useIsMobile();
const [{ x, y }, api] = useSpring(() => ({ x: 0, y: 0 }));
const bind = useDrag(
({ offset: [ox, oy], first, last }) => {
api.start({ x: ox, y: oy, immediate: true });
},
{
from: () => [x.get(), y.get()],
filterTaps: true,
bounds: {
left: -300,
right: window.innerWidth - 100,
top: 0,
bottom: window.innerHeight - 100,
},
},
);
useEffect(() => {
if (nodeRef.current && isMobile) {
const viewportHeight = window.innerHeight;
const modalHeight = 150;
const centeredPosition = scrollY + viewportHeight / 2 - modalHeight / 2;
nodeRef.current.style.top = `${centeredPosition}px`;
api.start({ y: centeredPosition, immediate: true });
}
}, [isMobile, scrollY]);
}, [isMobile, scrollY, api]);
const parentCidRef = useRef<HTMLSpanElement>(null);
@@ -275,8 +294,16 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, postCid, scrollY, s
}, [displayName, setPublishReplyOptions]);
const modalContent = (
<div className={styles.container} ref={nodeRef}>
<div className={`replyModalHandle ${styles.title}`}>
<animated.div
className={styles.container}
ref={nodeRef}
style={{
x,
y,
touchAction: 'none',
}}
>
<div className={`replyModalHandle ${styles.title}`} {...(!isMobile ? bind() : {})}>
{t('reply_to_cid', { cid: `c/${parentCid && Plebbit.getShortCid(parentCid)}`, interpolation: { escapeValue: false } })}
<button
className={styles.closeIcon}
@@ -346,19 +373,10 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, postCid, scrollY, s
{lengthError ? <div className={styles.error}>{lengthError}</div> : error && <div className={styles.error}>{error}</div>}
{!(isInAllView || isInSubscriptionsView) && offlineAlert}
</div>
</div>
</animated.div>
);
return (
showReplyModal &&
(isMobile ? (
modalContent
) : (
<Draggable handle='.replyModalHandle' nodeRef={nodeRef}>
{modalContent}
</Draggable>
))
);
return showReplyModal && modalContent;
};
export default ReplyModal;