diff --git a/package.json b/package.json index 89148564..d50e704b 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "@capacitor/app": "6.0.1", "@floating-ui/react": "0.26.1", "@plebbit/plebbit-react-hooks": "https://github.com/plebbit/plebbit-react-hooks.git#6d35eb3b4dc84f8fdcbb46d95e3b1d78f1750b5f", + "@react-spring/web": "9.7.5", "@testing-library/jest-dom": "5.14.1", "@testing-library/react": "13.0.0", "@testing-library/user-event": "13.2.1", @@ -16,6 +17,7 @@ "@types/node": "20.8.2", "@types/react": "18.2.25", "@types/react-dom": "18.2.10", + "@use-gesture/react": "10.3.1", "cross-env": "7.0.3", "electron-context-menu": "3.3.0", "electron-is-dev": "2.0.0", diff --git a/src/components/reply-modal/reply-modal.module.css b/src/components/reply-modal/reply-modal.module.css index bdf8fc6e..fcec066d 100644 --- a/src/components/reply-modal/reply-modal.module.css +++ b/src/components/reply-modal/reply-modal.module.css @@ -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 { diff --git a/src/components/reply-modal/reply-modal.tsx b/src/components/reply-modal/reply-modal.tsx index 1c36083f..48c15ef3 100644 --- a/src/components/reply-modal/reply-modal.tsx +++ b/src/components/reply-modal/reply-modal.tsx @@ -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(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(null); @@ -275,8 +294,16 @@ const ReplyModal = ({ closeModal, showReplyModal, parentCid, postCid, scrollY, s }, [displayName, setPublishReplyOptions]); const modalContent = ( -
-
+ +
{t('reply_to_cid', { cid: `c/${parentCid && Plebbit.getShortCid(parentCid)}`, interpolation: { escapeValue: false } })}
: error &&
{error}
} {!(isInAllView || isInSubscriptionsView) && offlineAlert}
-
+ ); - return ( - showReplyModal && - (isMobile ? ( - modalContent - ) : ( - - {modalContent} - - )) - ); + return showReplyModal && modalContent; }; export default ReplyModal; diff --git a/yarn.lock b/yarn.lock index e111e0bd..31c331f4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3412,6 +3412,51 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== +"@react-spring/animated@~9.7.5": + version "9.7.5" + resolved "https://registry.yarnpkg.com/@react-spring/animated/-/animated-9.7.5.tgz#eb0373aaf99b879736b380c2829312dae3b05f28" + integrity sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg== + dependencies: + "@react-spring/shared" "~9.7.5" + "@react-spring/types" "~9.7.5" + +"@react-spring/core@~9.7.5": + version "9.7.5" + resolved "https://registry.yarnpkg.com/@react-spring/core/-/core-9.7.5.tgz#72159079f52c1c12813d78b52d4f17c0bf6411f7" + integrity sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w== + dependencies: + "@react-spring/animated" "~9.7.5" + "@react-spring/shared" "~9.7.5" + "@react-spring/types" "~9.7.5" + +"@react-spring/rafz@~9.7.5": + version "9.7.5" + resolved "https://registry.yarnpkg.com/@react-spring/rafz/-/rafz-9.7.5.tgz#ee7959676e7b5d6a3813e8c17d5e50df98b95df9" + integrity sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw== + +"@react-spring/shared@~9.7.5": + version "9.7.5" + resolved "https://registry.yarnpkg.com/@react-spring/shared/-/shared-9.7.5.tgz#6d513622df6ad750bbbd4dedb4ca0a653ec92073" + integrity sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw== + dependencies: + "@react-spring/rafz" "~9.7.5" + "@react-spring/types" "~9.7.5" + +"@react-spring/types@~9.7.5": + version "9.7.5" + resolved "https://registry.yarnpkg.com/@react-spring/types/-/types-9.7.5.tgz#e5dd180f3ed985b44fd2cd2f32aa9203752ef3e8" + integrity sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g== + +"@react-spring/web@^9.7.5": + version "9.7.5" + resolved "https://registry.yarnpkg.com/@react-spring/web/-/web-9.7.5.tgz#7d7782560b3a6fb9066b52824690da738605de80" + integrity sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ== + dependencies: + "@react-spring/animated" "~9.7.5" + "@react-spring/core" "~9.7.5" + "@react-spring/shared" "~9.7.5" + "@react-spring/types" "~9.7.5" + "@remix-run/router@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.9.0.tgz#9033238b41c4cbe1e961eccb3f79e2c588328cf6" @@ -4471,6 +4516,18 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.1.tgz#28fa185f67daaf7b7a1a8c1d445132c5d979f8bd" integrity sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA== +"@use-gesture/core@10.3.1": + version "10.3.1" + resolved "https://registry.yarnpkg.com/@use-gesture/core/-/core-10.3.1.tgz#976c9421e905f0079d49822cfd5c2e56b808fc56" + integrity sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw== + +"@use-gesture/react@^10.3.1": + version "10.3.1" + resolved "https://registry.yarnpkg.com/@use-gesture/react/-/react-10.3.1.tgz#17a743a894d9bd9a0d1980c618f37f0164469867" + integrity sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g== + dependencies: + "@use-gesture/core" "10.3.1" + "@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1": version "1.14.1" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.14.1.tgz#a9f6a07f2b03c95c8d38c4536a1fdfb521ff55b6"