diff --git a/src/components/post-desktop/post-desktop.tsx b/src/components/post-desktop/post-desktop.tsx index af0350fe..46e98413 100644 --- a/src/components/post-desktop/post-desktop.tsx +++ b/src/components/post-desktop/post-desktop.tsx @@ -78,7 +78,7 @@ const PostInfo = ({ openReplyModal, post, roles, isHidden }: PostProps) => { {!cid ? ( {state === 'failed' || stateString === 'Failed' ? 'Failed' : 'Pending'} ) : ( - openReplyModal && openReplyModal(cid)}> + openReplyModal && openReplyModal(cid)}> {shortCid} )} diff --git a/src/components/post-mobile/post-mobile.tsx b/src/components/post-mobile/post-mobile.tsx index 2dce2f3b..7112493a 100644 --- a/src/components/post-mobile/post-mobile.tsx +++ b/src/components/post-mobile/post-mobile.tsx @@ -89,7 +89,7 @@ const PostInfoAndMedia = ({ openReplyModal, post, roles }: PostProps) => { {!cid ? ( {state === 'failed' || stateString === 'Failed' ? 'Failed' : 'Pending'} ) : ( - openReplyModal && openReplyModal(cid)}> + openReplyModal && openReplyModal(cid)}> {shortCid} )} diff --git a/src/components/reply-modal/reply-modal.tsx b/src/components/reply-modal/reply-modal.tsx index 48dbd8cc..c559aeaa 100644 --- a/src/components/reply-modal/reply-modal.tsx +++ b/src/components/reply-modal/reply-modal.tsx @@ -7,6 +7,7 @@ import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js'; import { getFormattedTimeAgo } from '../../lib/utils/time-utils'; import { isValidURL } from '../../lib/utils/url-utils'; import { isAllView, isSubscriptionsView } from '../../lib/utils/view-utils'; +import useSelectedTextStore from '../../stores/use-selected-text-store'; import useReply from '../../hooks/use-reply'; import useIsMobile from '../../hooks/use-is-mobile'; import styles from './reply-modal.module.css'; @@ -23,14 +24,12 @@ const ReplyModal = ({ closeModal, parentCid, scrollY }: ReplyModalProps) => { const { t } = useTranslation(); const { subplebbitAddress } = useParams() as { subplebbitAddress: string }; const { setContent, resetContent, replyIndex, publishReply } = useReply({ cid: parentCid, subplebbitAddress }); - const account = useAccount(); const { displayName } = account?.author || {}; - const [url, setUrl] = useState(''); - - const textRef = useRef(null); + const textRef = useRef(null); const urlRef = useRef(null); + const { selectedText } = useSelectedTextStore(); const onPublishReply = () => { const currentContent = textRef.current?.value || ''; @@ -89,6 +88,15 @@ const ReplyModal = ({ closeModal, parentCid, scrollY }: ReplyModalProps) => { ) : `The subplebbit might be offline and publishing might fail.`; + const setTextRef = (ref: HTMLTextAreaElement | null) => { + if (ref) { + textRef.current = ref; + !isMobile && ref.focus(); + const len = ref.value.length; + ref.setSelectionRange(len, len); + } + }; + const modalContent = (
@@ -130,12 +138,12 @@ const ReplyModal = ({ closeModal, parentCid, scrollY }: ReplyModalProps) => { cols={48} rows={3} wrap='soft' - ref={textRef} + ref={setTextRef} + defaultValue={selectedText} onChange={(e) => { const content = e.target.value.replace(/\n/g, '\n\n'); setContent.content(content); }} - autoFocus={!isMobile} // autofocus causes auto scroll to top on mobile />
{!(isInAllView || isInSubscriptionsView) && offlineAlert} diff --git a/src/hooks/use-reply-modal.ts b/src/hooks/use-reply-modal.ts index d15cc2b1..3dc66472 100644 --- a/src/hooks/use-reply-modal.ts +++ b/src/hooks/use-reply-modal.ts @@ -1,21 +1,26 @@ import { useState, useCallback } from 'react'; import useIsMobile from './use-is-mobile'; +import useSelectedTextStore from '../stores/use-selected-text-store'; const useReplyModal = () => { const [showReplyModal, setShowReplyModal] = useState(false); const [activeCid, setActiveCid] = useState(null); + const { resetSelectedText, setSelectedText } = useSelectedTextStore(); // on mobile, the position is absolute instead of fixed, so we need to calculate the top position const isMobile = useIsMobile(); const [scrollY, setScrollY] = useState(0); const closeModal = useCallback(() => { + resetSelectedText(); setActiveCid(null); setShowReplyModal(false); - }, []); + }, [resetSelectedText]); const openReplyModal = useCallback( (cid: string) => { + let text = document.getSelection()?.toString(); + text && setSelectedText(`>${text}\n`); if (isMobile) { const currentScrollY = window.scrollY; setScrollY(currentScrollY); @@ -27,7 +32,7 @@ const useReplyModal = () => { setShowReplyModal(true); } }, - [activeCid, isMobile], + [activeCid, isMobile, setSelectedText], ); return { activeCid, closeModal, openReplyModal, scrollY, showReplyModal }; diff --git a/src/stores/use-selected-text-store.ts b/src/stores/use-selected-text-store.ts new file mode 100644 index 00000000..48f5d683 --- /dev/null +++ b/src/stores/use-selected-text-store.ts @@ -0,0 +1,15 @@ +import { create } from 'zustand'; + +interface SelectedTextState { + selectedText: string; + setSelectedText: (text: string) => void; + resetSelectedText: () => void; +} + +const useSelectedTextStore = create((set) => ({ + selectedText: '', + setSelectedText: (text) => set({ selectedText: text }), + resetSelectedText: () => set({ selectedText: '' }), +})); + +export default useSelectedTextStore;