Skip to content

Commit

Permalink
onPointerDown for mobile, quote+reply quotes text
Browse files Browse the repository at this point in the history
  • Loading branch information
huumn committed Oct 4, 2023
1 parent 31c9570 commit a6c8587
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 52 deletions.
2 changes: 1 addition & 1 deletion components/action-dropdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default function ActionDropdown ({ children }) {
}
return (
<Dropdown className={`pointer ${styles.dropdown}`} as='span'>
<Dropdown.Toggle variant='success' as='a' onMouseDown={e => e.preventDefault()}>
<Dropdown.Toggle variant='success' as='a' onPointerDown={e => e.preventDefault()}>
<MoreIcon className='fill-grey ms-1' height={16} width={16} />
</Dropdown.Toggle>
<Dropdown.Menu>
Expand Down
100 changes: 53 additions & 47 deletions components/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export function MarkdownInput ({ label, topLevel, groupClassName, onChange, setH
const [, meta, helpers] = useField(props)
const [selectionRange, setSelectionRange] = useState({ start: 0, end: 0 })
innerRef = innerRef || useRef(null)
const previousTab = useRef(tab)

props.as ||= TextareaAutosize
props.rows ||= props.minRows || 6
Expand All @@ -100,6 +101,14 @@ export function MarkdownInput ({ label, topLevel, groupClassName, onChange, setH
!meta.value && setTab('write')
}, [meta.value])

useEffect(() => {
// focus on input when switching to write tab from preview tab
if (innerRef?.current && tab === 'write' && previousTab?.current !== 'write') {
innerRef.current.focus()
}
previousTab.current = tab
}, [tab])

useEffect(() => {
if (selectionRange.start <= selectionRange.end && innerRef?.current) {
const { start, end } = selectionRange
Expand All @@ -125,53 +134,49 @@ export function MarkdownInput ({ label, topLevel, groupClassName, onChange, setH
<Markdown width={18} height={18} />
</a>
</Nav>
{tab === 'write'
? (
<div>
<InputInner
{...props} onChange={(formik, e) => {
if (onChange) onChange(formik, e)
if (setHasImgLink) {
setHasImgLink(mdHas(e.target.value, ['link', 'image']))
}
}}
innerRef={innerRef}
onKeyDown={(e) => {
const metaOrCtrl = e.metaKey || e.ctrlKey
if (metaOrCtrl) {
if (e.key === 'k') {
// some browsers use CTRL+K to focus search bar so we have to prevent that behavior
e.preventDefault()
insertMarkdownLinkFormatting(innerRef.current, helpers.setValue, setSelectionRange)
}
if (e.key === 'b') {
// some browsers use CTRL+B to open bookmarks so we have to prevent that behavior
e.preventDefault()
insertMarkdownBoldFormatting(innerRef.current, helpers.setValue, setSelectionRange)
}
if (e.key === 'i') {
// some browsers might use CTRL+I to do something else so prevent that behavior too
e.preventDefault()
insertMarkdownItalicFormatting(innerRef.current, helpers.setValue, setSelectionRange)
}
if (e.key === 'Tab' && e.altKey) {
e.preventDefault()
insertMarkdownTabFormatting(innerRef.current, helpers.setValue, setSelectionRange)
}
}

if (onKeyDown) onKeyDown(e)
}}
/>
</div>)
: (
<div className='form-group'>
<div className={`${styles.text} form-control`}>
<Text topLevel={topLevel} noFragments tab={tab}>{meta.value}</Text>
</div>
</div>
)}
<div className={tab === 'write' ? '' : 'd-none'}>
<InputInner
{...props} onChange={(formik, e) => {
if (onChange) onChange(formik, e)
if (setHasImgLink) {
setHasImgLink(mdHas(e.target.value, ['link', 'image']))
}
}}
innerRef={innerRef}
onKeyDown={(e) => {
const metaOrCtrl = e.metaKey || e.ctrlKey
if (metaOrCtrl) {
if (e.key === 'k') {
// some browsers use CTRL+K to focus search bar so we have to prevent that behavior
e.preventDefault()
insertMarkdownLinkFormatting(innerRef.current, helpers.setValue, setSelectionRange)
}
if (e.key === 'b') {
// some browsers use CTRL+B to open bookmarks so we have to prevent that behavior
e.preventDefault()
insertMarkdownBoldFormatting(innerRef.current, helpers.setValue, setSelectionRange)
}
if (e.key === 'i') {
// some browsers might use CTRL+I to do something else so prevent that behavior too
e.preventDefault()
insertMarkdownItalicFormatting(innerRef.current, helpers.setValue, setSelectionRange)
}
if (e.key === 'Tab' && e.altKey) {
e.preventDefault()
insertMarkdownTabFormatting(innerRef.current, helpers.setValue, setSelectionRange)
}
}

if (onKeyDown) onKeyDown(e)
}}
/>
</div>
{tab !== 'write' &&
<div className='form-group'>
<div className={`${styles.text} form-control`}>
<Text topLevel={topLevel} noFragments tab={tab}>{meta.value}</Text>
</div>
</div>}
</div>
</FormGroup>
)
Expand Down Expand Up @@ -225,7 +230,8 @@ function FormGroup ({ className, label, children }) {

function InputInner ({
prepend, append, hint, showValid, onChange, onBlur, overrideValue,
innerRef, noForm, clear, onKeyDown, inputGroupClassName, debounce, maxLength, ...props
innerRef, noForm, clear, onKeyDown, inputGroupClassName, debounce, maxLength,
...props
}) {
const [field, meta, helpers] = noForm ? [{}, {}, {}] : useField(props)
const formik = noForm ? null : useFormikContext()
Expand Down
4 changes: 2 additions & 2 deletions components/item-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ export default function ItemInfo ({
</>}
<ActionDropdown>
<CopyLinkDropdownItem item={item} />
{(item.parentId || item.text) && onQuoteReply &&
<Dropdown.Item onClick={onQuoteReply}>quote reply</Dropdown.Item>}
{me && <BookmarkDropdownItem item={item} />}
{me && !item.mine && <SubscribeDropdownItem item={item} />}
{item.otsHash &&
Expand All @@ -148,8 +150,6 @@ export default function ItemInfo ({
<hr className='dropdown-divider' />
<MuteDropdownItem user={item.user} />
</>}
{(item.parentId || item.text) && onQuoteReply &&
<Dropdown.Item onClick={onQuoteReply}>quote reply</Dropdown.Item>}
</ActionDropdown>
{extraInfo}
</div>
Expand Down
11 changes: 9 additions & 2 deletions components/reply.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@ export default forwardRef(function Reply ({ item, onSuccess, replyOpen, children
const replyInput = useRef(null)
const formInnerRef = useRef()
useImperativeHandle(ref, () => ({
quoteReply: () => {
quoteReply: ({ selectionOnly }) => {
if (!reply) {
setReply(true)
}
const selection = window.getSelection()
const selectedText = selection.isCollapsed ? undefined : selection.toString()
const isSelectedTextInTarget = contentContainerRef?.current?.contains(selection.anchorNode)
if ((selection.isCollapsed || !isSelectedTextInTarget) && selectionOnly) return
const textToQuote = isSelectedTextInTarget ? selectedText : item.text
let updatedValue
if (formInnerRef.current && formInnerRef.current.values && !formInnerRef.current.values.text) {
Expand Down Expand Up @@ -133,7 +134,13 @@ export default forwardRef(function Reply ({ item, onSuccess, replyOpen, children
: (
<div className={styles.replyButtons}>
<div
onClick={() => setReply(!reply)}
onPointerDown={e => {
if (!reply) {
e.preventDefault()
ref?.current?.quoteReply({ selectionOnly: true })
}
setReply(!reply)
}}
>
{reply ? 'cancel' : 'reply'}
</div>
Expand Down

0 comments on commit a6c8587

Please sign in to comment.