diff --git a/app/soapbox/components/account_search.js b/app/soapbox/components/account_search.js
deleted file mode 100644
index b2021ec34..000000000
--- a/app/soapbox/components/account_search.js
+++ /dev/null
@@ -1,84 +0,0 @@
-import classNames from 'classnames';
-import PropTypes from 'prop-types';
-import React from 'react';
-import { defineMessages, injectIntl } from 'react-intl';
-
-import AutosuggestAccountInput from 'soapbox/components/autosuggest_account_input';
-import Icon from 'soapbox/components/icon';
-
-const messages = defineMessages({
- placeholder: { id: 'account_search.placeholder', defaultMessage: 'Search for an account' },
-});
-
-export default @injectIntl
-class AccountSearch extends React.PureComponent {
-
- static propTypes = {
- intl: PropTypes.object.isRequired,
- onSelected: PropTypes.func.isRequired,
- };
-
- state = {
- value: '',
- }
-
- isEmpty = () => {
- const { value } = this.state;
- return !(value.length > 0);
- }
-
- clearState = () => {
- this.setState({ value: '' });
- }
-
- handleChange = ({ target }) => {
- this.setState({ value: target.value });
- }
-
- handleSelected = accountId => {
- this.clearState();
- this.props.onSelected(accountId);
- }
-
- handleClear = e => {
- e.preventDefault();
-
- if (!this.isEmpty()) {
- this.setState({ value: '' });
- }
- }
-
- handleKeyDown = e => {
- if (e.key === 'Escape') {
- document.querySelector('.ui').parentElement.focus();
- }
- }
-
- render() {
- const { intl, onSelected, ...rest } = this.props;
- const { value } = this.state;
- const isEmpty = this.isEmpty();
-
- return (
-
-
-
-
-
-
-
- );
- }
-
-}
diff --git a/app/soapbox/components/account_search.tsx b/app/soapbox/components/account_search.tsx
new file mode 100644
index 000000000..961a4b2ef
--- /dev/null
+++ b/app/soapbox/components/account_search.tsx
@@ -0,0 +1,78 @@
+import classNames from 'classnames';
+import React, { useState } from 'react';
+import { defineMessages, useIntl } from 'react-intl';
+
+import AutosuggestAccountInput from 'soapbox/components/autosuggest_account_input';
+import Icon from 'soapbox/components/icon';
+
+const messages = defineMessages({
+ placeholder: { id: 'account_search.placeholder', defaultMessage: 'Search for an account' },
+});
+
+interface IAccountSearch {
+ /** Callback when a searched account is chosen. */
+ onSelected: (accountId: string) => void,
+ /** Override the default placeholder of the input. */
+ placeholder?: string,
+}
+
+/** Input to search for accounts. */
+const AccountSearch: React.FC = ({ onSelected, ...rest }) => {
+ const intl = useIntl();
+
+ const [value, setValue] = useState('');
+
+ const isEmpty = (): boolean => {
+ return !(value.length > 0);
+ };
+
+ const clearState = () => {
+ setValue('');
+ };
+
+ const handleChange: React.ChangeEventHandler = ({ target }) => {
+ setValue(target.value);
+ };
+
+ const handleSelected = (accountId: string) => {
+ clearState();
+ onSelected(accountId);
+ };
+
+ const handleClear: React.MouseEventHandler = e => {
+ e.preventDefault();
+
+ if (!isEmpty()) {
+ setValue('');
+ }
+ };
+
+ const handleKeyDown: React.KeyboardEventHandler = e => {
+ if (e.key === 'Escape') {
+ document.querySelector('.ui')?.parentElement?.focus();
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+ );
+};
+
+export default AccountSearch;