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 @@ -7,6 +7,7 @@ import type { InputState } from '../input/input-state'; import { + getTypeaheadOverlayScroll, getTypeaheadTooltipActions, getTypeaheadTooltipButtons, getTypeaheadTooltipPosition, @@ -36,6 +37,8 @@ setChosenPositionInOverlay, ] = React.useState(0); + const overlayRef = React.useRef(); + React.useEffect(() => { setIsVisibleForAnimation(true); @@ -140,13 +143,27 @@ inputState.setTypeaheadState, ]); + React.useEffect(() => { + const current = overlayRef.current; + if (current) { + current.scrollTop = getTypeaheadOverlayScroll( + current.scrollTop, + chosenPositionInOverlay, + ); + } + }, [chosenPositionInOverlay]); + const overlayClasses = classNames(css.suggestionsContainer, { [css.notVisible]: !isVisibleForAnimation, [css.visible]: isVisibleForAnimation, }); return ( -
+
{tooltipButtons}
); 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 @@ -153,6 +153,30 @@ }); } +function getTypeaheadOverlayScroll( + currentScrollTop: number, + chosenActionPosition: number, +): number { + const upperButtonBoundary = chosenActionPosition * typeaheadStyle.rowHeight; + const lowerButtonBoundary = + (chosenActionPosition + 1) * typeaheadStyle.rowHeight; + + if (upperButtonBoundary < currentScrollTop) { + return upperButtonBoundary; + } else if ( + lowerButtonBoundary - typeaheadStyle.tooltipMaxHeight > + currentScrollTop + ) { + return ( + lowerButtonBoundary + + typeaheadStyle.tooltipVerticalPadding - + typeaheadStyle.tooltipMaxHeight + ); + } + + return currentScrollTop; +} + function getTypeaheadTooltipPosition( textarea: HTMLTextAreaElement, actionsLength: number, @@ -193,6 +217,7 @@ getCaretOffsets, getTypeaheadTooltipActions, getTypeaheadTooltipButtons, + getTypeaheadOverlayScroll, getTypeaheadTooltipPosition, positiveModulo, };