diff --git a/components/form.js b/components/form.js index 5a36d0cb7..528d3a9dc 100644 --- a/components/form.js +++ b/components/form.js @@ -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 ( @@ -144,7 +144,7 @@ export function MarkdownInput ({ label, topLevel, groupClassName, onChange, setH ? (
{({ onKeyDown: userSuggestOnKeyDown }) => ( @@ -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`, @@ -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': @@ -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 ( - { - 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 - } - }} - /> - 0}> - - {suggestions.array.map((v, i) => - { - setOValue(v.name) - setSuggestions(INITIAL_SUGGESTIONS) - }} - > - {v.name} - )} - - + + {({ onKeyDown }) => ( + { + setOValue(e.target.value) + setQuery(e.target.value.replace(/^[@ ]+|[ ]+$/g, '')) + }} + overrideValue={ovalue} + onKeyDown={onKeyDown} + /> + )} + ) }