Skip to content

Commit

Permalink
various code cleanup and reuse the UserSuggest component in InputUser…
Browse files Browse the repository at this point in the history
…Suggest to reduce duplication
  • Loading branch information
SatsAllDay committed Oct 4, 2023
1 parent 48961a6 commit b725931
Showing 1 changed file with 45 additions and 84 deletions.
129 changes: 45 additions & 84 deletions components/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,19 @@ export function MarkdownInput ({ label, topLevel, groupClassName, onChange, setH
}
}, [innerRef, selectionRange.start, selectionRange.end])

const [atMentionQuery, setAtMentionQuery] = useState()
const [atMentionIndices, setAtMentionIndices] = useState({ start: -1, end: -1 })
const [mentionQuery, setMentionQuery] = useState()
const [mentionIndices, setMentionIndices] = useState({ start: -1, end: -1 })
const [userSuggestDropdownStyle, setUserSuggestDropdownStyle] = useState({})
const insertMention = useCallback((name) => {
const { start, end } = atMentionIndices
const { start, end } = mentionIndices
const first = `${innerRef.current.value.substring(0, start)}@${name}`
const second = innerRef.current.value.substring(end)
const updatedValue = `${first}${second}`
innerRef.current.value = updatedValue
helpers.setValue(updatedValue)
setSelectionRange({ start: first.length })
setSelectionRange({ start: first.length, end: first.length })
innerRef.current.focus()
}, [atMentionIndices, innerRef, helpers])
}, [mentionIndices, innerRef, helpers])

return (
<FormGroup label={label} className={groupClassName}>
Expand All @@ -144,7 +144,7 @@ export function MarkdownInput ({ label, topLevel, groupClassName, onChange, setH
? (
<div style={{ position: 'relative' }}>
<UserSuggest
query={atMentionQuery}
query={mentionQuery}
onSelect={insertMention}
dropdownStyle={userSuggestDropdownStyle}
>{({ onKeyDown: userSuggestOnKeyDown }) => (
Expand All @@ -154,31 +154,34 @@ export function MarkdownInput ({ label, topLevel, groupClassName, onChange, setH
if (setHasImgLink) {
setHasImgLink(mdHas(e.target.value, ['link', 'image']))
}
// check for at-mention editing
// check for mention editing
const { value, selectionStart } = e.target
let priorSpace = -1
for (let i = selectionStart - 1; i >= 0; i--) {
if ([' ', '\n'].includes(value[i])) {
if (/\s|\n/.test(value[i])) {
priorSpace = i
break
}
}
let nextSpace = value.length
for (let i = selectionStart; i <= value.length; i++) {
if ([' ', '\n'].includes(value[i])) {
if (/\s|\n/.test(value[i])) {
nextSpace = i
break
}
}
const currentSequence = value.substring(priorSpace + 1, nextSpace)
// console.log({ value, selectionStart, priorSpace, nextSpace, currentSequence })

// currently typing an at-mention, let's query for matching users
setAtMentionQuery(currentSequence)
setAtMentionIndices({ start: priorSpace + 1, end: nextSpace })
const currentSegment = value.substring(priorSpace + 1, nextSpace)

// set the query to the current character segment and note where it appears
if (/^@\w*/.test(currentSegment)) {
setMentionQuery(currentSegment)
setMentionIndices({ start: priorSpace + 1, end: nextSpace })
} else {
setMentionQuery(undefined)
setMentionIndices({ start: -1, end: -1 })
}

const caret = textAreaCaret(e.target, e.target.selectionStart)
const { top, left } = caret
const { top, left } = textAreaCaret(e.target, e.target.selectionStart)
setUserSuggestDropdownStyle({
position: 'absolute',
top: `${top + Number(window.getComputedStyle(e.target).lineHeight.replace('px', ''))}px`,
Expand Down Expand Up @@ -399,20 +402,23 @@ export function UserSuggest ({ query, onSelect, dropdownStyle, children }) {
}
})

const INITIAL_SUGGESTIONS = { array: [], index: 0 }
const [suggestions, setSuggestions] = useState(INITIAL_SUGGESTIONS)
const resetSuggestions = useCallback(() => setSuggestions(INITIAL_SUGGESTIONS), [])

useEffect(() => {
if (query !== undefined && /^@\w*/.test(query)) {
if (query !== undefined) {
const q = query?.replace(/^[@ ]+|[ ]+$/g, '')
if (q === '') {
getUsers({ variables: { by: 'stacked', when: 'day', limit: 5 } })
} else {
getSuggestions({ variables: { q } })
}
} else {
resetSuggestions()
}
}, [query])

const INITIAL_SUGGESTIONS = { array: [], index: 0 }
const [suggestions, setSuggestions] = useState(INITIAL_SUGGESTIONS)
const resetSuggestions = useCallback(() => setSuggestions(INITIAL_SUGGESTIONS), [])
const onKeyDown = useCallback(e => {
switch (e.code) {
case 'ArrowUp':
Expand Down Expand Up @@ -477,72 +483,27 @@ export function UserSuggest ({ query, onSelect, dropdownStyle, children }) {
}

export function InputUserSuggest ({ label, groupClassName, ...props }) {
const [getSuggestions] = useLazyQuery(USER_SEARCH, {
onCompleted: data => {
setSuggestions({ array: data.searchUsers, index: 0 })
}
})

const INITIAL_SUGGESTIONS = { array: [], index: 0 }
const [suggestions, setSuggestions] = useState(INITIAL_SUGGESTIONS)
const [ovalue, setOValue] = useState()
const [query, setQuery] = useState()
return (
<FormGroup label={label} className={groupClassName}>
<InputInner
{...props}
autoComplete='off'
onChange={(_, e) => {
setOValue(e.target.value)
getSuggestions({ variables: { q: e.target.value.replace(/^[@ ]+|[ ]+$/g, '') } })
}}
overrideValue={ovalue}
onKeyDown={(e) => {
switch (e.code) {
case 'ArrowUp':
e.preventDefault()
setSuggestions(
{
...suggestions,
index: Math.max(suggestions.index - 1, 0)
})
break
case 'ArrowDown':
e.preventDefault()
setSuggestions(
{
...suggestions,
index: Math.min(suggestions.index + 1, suggestions.array.length - 1)
})
break
case 'Enter':
e.preventDefault()
setOValue(suggestions.array[suggestions.index].name)
setSuggestions(INITIAL_SUGGESTIONS)
break
case 'Escape':
e.preventDefault()
setSuggestions(INITIAL_SUGGESTIONS)
break
default:
break
}
}}
/>
<Dropdown show={suggestions.array.length > 0}>
<Dropdown.Menu className={styles.suggestionsMenu}>
{suggestions.array.map((v, i) =>
<Dropdown.Item
key={v.name}
active={suggestions.index === i}
onClick={() => {
setOValue(v.name)
setSuggestions(INITIAL_SUGGESTIONS)
}}
>
{v.name}
</Dropdown.Item>)}
</Dropdown.Menu>
</Dropdown>
<UserSuggest
onSelect={setOValue}
query={query}
>
{({ onKeyDown }) => (
<InputInner
{...props}
autoComplete='off'
onChange={(_, e) => {
setOValue(e.target.value)
setQuery(e.target.value.replace(/^[@ ]+|[ ]+$/g, ''))
}}
overrideValue={ovalue}
onKeyDown={onKeyDown}
/>
)}
</UserSuggest>
</FormGroup>
)
}
Expand Down

0 comments on commit b725931

Please sign in to comment.