diff --git a/web/chat/typeahead-tooltip.react.js b/web/chat/typeahead-tooltip.react.js --- a/web/chat/typeahead-tooltip.react.js +++ b/web/chat/typeahead-tooltip.react.js @@ -4,6 +4,7 @@ import * as React from 'react'; import type { RelativeMemberInfo } from 'lib/types/thread-types'; +import { leastPositiveResidue } from 'lib/utils/math-utils'; import type { InputState } from '../input/input-state'; import { @@ -30,6 +31,15 @@ false, ); + const [ + chosenPositionInOverlay, + setChosenPositionInOverlay, + ] = React.useState(0); + + React.useEffect(() => { + setChosenPositionInOverlay(0); + }, [suggestedUsers]); + React.useEffect(() => { setIsVisibleForAnimation(true); @@ -75,7 +85,61 @@ [actions], ); - if (!actions || actions.length === 0) { + const close = React.useCallback(() => { + const setter = inputState.setTypeaheadState; + setter({ + canBeVisible: false, + moveChoiceUp: null, + moveChoiceDown: null, + close: null, + accept: null, + }); + }, [inputState.setTypeaheadState]); + + const accept = React.useCallback(() => { + actions[chosenPositionInOverlay].execute(); + close(); + }, [actions, chosenPositionInOverlay, close]); + + const moveChoiceUp = React.useCallback(() => { + if (actions.length === 0) { + return; + } + setChosenPositionInOverlay(previousPosition => + leastPositiveResidue(previousPosition - 1, actions.length), + ); + }, [setChosenPositionInOverlay, actions.length]); + + const moveChoiceDown = React.useCallback(() => { + if (actions.length === 0) { + return; + } + setChosenPositionInOverlay(previousPosition => + leastPositiveResidue(previousPosition + 1, actions.length), + ); + }, [setChosenPositionInOverlay, actions.length]); + + React.useEffect(() => { + const setter = inputState.setTypeaheadState; + setter({ + canBeVisible: true, + moveChoiceUp, + moveChoiceDown, + close, + accept, + }); + + return close; + }, [ + close, + accept, + moveChoiceUp, + moveChoiceDown, + actions, + inputState.setTypeaheadState, + ]); + + if (suggestedUsers.length === 0) { return null; } diff --git a/web/utils/typeahead-utils.js b/web/utils/typeahead-utils.js --- a/web/utils/typeahead-utils.js +++ b/web/utils/typeahead-utils.js @@ -16,7 +16,7 @@ export type TypeaheadTooltipAction = { +key: string, - +onClick: (SyntheticEvent) => mixed, + +execute: () => mixed, +actionButtonContent: React.Node, }; @@ -98,7 +98,7 @@ ) .map(suggestedUser => ({ key: suggestedUser.id, - onClick: () => { + execute: () => { const newPrefixText = textBeforeAtSymbol; const totalMatchLength = @@ -125,8 +125,8 @@ function getTypeaheadTooltipButtons( actions: $ReadOnlyArray, ): $ReadOnlyArray { - return actions.map(({ key, onClick, actionButtonContent }) => ( - ));