diff --git a/src/autocomplete/Components.tsx b/src/autocomplete/Components.tsx index 19a7a969d6..3b4469321d 100644 --- a/src/autocomplete/Components.tsx +++ b/src/autocomplete/Components.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, {createRef} from 'react'; import classNames from 'classnames'; /* These were earlier stateless functional components but had to be converted @@ -30,7 +30,11 @@ interface ITextualCompletionProps { className?: string; } -export class TextualCompletion extends React.PureComponent { +export abstract class Completion extends React.PureComponent { + nodeRef = createRef(); +} + +export class TextualCompletion extends Completion { render() { const { title, @@ -40,7 +44,11 @@ export class TextualCompletion extends React.PureComponent +
{ title } { subtitle } { description } @@ -57,7 +65,7 @@ interface IPillCompletionProps { className?: string; } -export class PillCompletion extends React.PureComponent { +export class PillCompletion extends Completion { render() { const { title, @@ -68,7 +76,11 @@ export class PillCompletion extends React.PureComponent { ...restProps } = this.props; return ( -
+
{ initialComponent } { title } { subtitle } diff --git a/src/components/views/rooms/Autocomplete.tsx b/src/components/views/rooms/Autocomplete.tsx index 975c8e84a5..40f585a5b8 100644 --- a/src/components/views/rooms/Autocomplete.tsx +++ b/src/components/views/rooms/Autocomplete.tsx @@ -15,8 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; -import ReactDOM from 'react-dom'; +import React, {createRef} from 'react'; import classNames from 'classnames'; import flatMap from 'lodash/flatMap'; import {ICompletion, ISelectionRange, IProviderCompletions} from '../../../autocomplete/Autocompleter'; @@ -24,6 +23,7 @@ import {Room} from 'matrix-js-sdk/src/models/room'; import SettingsStore from "../../../settings/SettingsStore"; import Autocompleter from '../../../autocomplete/Autocompleter'; +import { Completion } from '../../../autocomplete/Components'; const COMPOSER_SELECTED = 0; @@ -54,7 +54,7 @@ export default class Autocomplete extends React.PureComponent { autocompleter: Autocompleter; queryRequested: string; debounceCompletionsRequest: NodeJS.Timeout; - containerRef: React.RefObject; + private containerRef = createRef(); constructor(props) { super(props); @@ -78,8 +78,6 @@ export default class Autocomplete extends React.PureComponent { forceComplete: false, }; - - this.containerRef = React.createRef(); } componentDidMount() { @@ -256,14 +254,15 @@ export default class Autocomplete extends React.PureComponent { componentDidUpdate(prevProps: IProps) { this.applyNewProps(prevProps.query, prevProps.room); // this is the selected completion, so scroll it into view if needed - const selectedCompletion = this.refs[`completion${this.state.selectionOffset}`]; - if (selectedCompletion && this.containerRef.current) { - const domNode = ReactDOM.findDOMNode(selectedCompletion); - const offsetTop = domNode && (domNode as HTMLElement).offsetTop; - if (offsetTop > this.containerRef.current.scrollTop + this.containerRef.current.offsetHeight || - offsetTop < this.containerRef.current.scrollTop) { - this.containerRef.current.scrollTop = offsetTop - this.containerRef.current.offsetTop; - } + const selectedCompletion = this.refs[`completion${this.state.selectionOffset}`] as Completion; + + if (selectedCompletion && selectedCompletion.nodeRef.current) { + selectedCompletion.nodeRef.current.scrollIntoView({ + behavior: "auto", + block: "nearest", + }); + } else { + this.containerRef.current.scrollTo({ top: 0 }); } }