diff --git a/web/chat/chat-input-bar.react.js b/web/chat/chat-input-bar.react.js --- a/web/chat/chat-input-bar.react.js +++ b/web/chat/chat-input-bar.react.js @@ -109,6 +109,16 @@ if (inputState.draft !== prevInputState.draft) { this.updateHeight(); } + + if ( + inputState.draft !== prevInputState.draft || + inputState.textCursorPosition !== prevInputState.textCursorPosition + ) { + inputState.setTypeaheadState({ + canBeVisible: true, + }); + } + const curUploadIDs = ChatInputBar.unassignedUploadIDs( inputState.pendingUploads, ); @@ -330,6 +340,7 @@ let typeaheadTooltip; if ( + this.props.inputState.typeaheadState.canBeVisible && this.props.suggestedUsers.length > 0 && this.props.typeaheadMatchedStrings && this.textarea @@ -405,7 +416,28 @@ }; onKeyDown = (event: SyntheticKeyboardEvent) => { - if (event.key === 'Enter' && !event.shiftKey) { + const { + accept, + close, + moveChoiceUp, + moveChoiceDown, + } = this.props.inputState.typeaheadState; + + const actions = { + Enter: accept, + Tab: accept, + ArrowDown: moveChoiceDown, + ArrowUp: moveChoiceUp, + Escape: close, + }; + + if ( + this.props.inputState.typeaheadState.canBeVisible && + actions[event.key] + ) { + event.preventDefault(); + actions[event.key](); + } else if (event.key === 'Enter' && !event.shiftKey) { event.preventDefault(); this.send(); } diff --git a/web/chat/typeahead-tooltip.css b/web/chat/typeahead-tooltip.css --- a/web/chat/typeahead-tooltip.css +++ b/web/chat/typeahead-tooltip.css @@ -53,7 +53,7 @@ white-space: nowrap; } -.suggestion:hover { +.suggestionHover { background-color: var(--typeahead-overlay-light); } 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 @@ -81,8 +81,13 @@ ); const tooltipButtons = React.useMemo( - () => getTypeaheadTooltipButtons(actions), - [actions], + () => + getTypeaheadTooltipButtons( + setChosenPositionInOverlay, + chosenPositionInOverlay, + actions, + ), + [setChosenPositionInOverlay, actions, chosenPositionInOverlay], ); const close = React.useCallback(() => { 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 @@ -1,9 +1,11 @@ // @flow +import classNames from 'classnames'; import * as React from 'react'; import { oldValidUsernameRegexString } from 'lib/shared/account-utils'; import { stringForUserExplicit } from 'lib/shared/user-utils'; +import type { SetState } from 'lib/types/hook-types'; import type { RelativeMemberInfo } from 'lib/types/thread-types'; import { typeaheadStyle } from '../chat/chat-constants'; @@ -123,14 +125,35 @@ } function getTypeaheadTooltipButtons( + setChosenPositionInOverlay: SetState, + chosenPositionInOverlay: number, actions: $ReadOnlyArray, ): $ReadOnlyArray { - return actions.map(({ key, execute, actionButtonContent }) => ( - - )); + return actions.map((action, idx) => { + const { key, execute, actionButtonContent } = action; + const buttonClasses = classNames(css.suggestion, { + [css.suggestionHover]: idx === chosenPositionInOverlay, + }); + + const onMouseMove: ( + event: SyntheticEvent, + ) => mixed = () => { + setChosenPositionInOverlay(idx); + }; + + return ( + + ); + }); } + function getTypeaheadTooltipPosition( textarea: HTMLTextAreaElement, actionsLength: number,