From 349cae0b57ee65475a70311863959e7a0cf53065 Mon Sep 17 00:00:00 2001
From: fusagiko / takayamaki <24884114+takayamaki@users.noreply.github.com>
Date: Wed, 10 May 2023 06:08:54 +0900
Subject: [PATCH] Add type annotation for DisplayName component (#24752)

---
 .../__tests__/display_name-test.jsx           |   2 +-
 .../mastodon/components/account.jsx           |   2 +-
 .../mastodon/components/display_name.jsx      |  79 ------------
 .../mastodon/components/display_name.tsx      | 115 ++++++++++++++++++
 app/javascript/mastodon/components/status.jsx |   2 +-
 .../components/moved_note.jsx                 |   2 +-
 .../components/autosuggest_account.jsx        |   2 +-
 .../compose/components/reply_indicator.jsx    |   2 +-
 .../directory/components/account_card.jsx     |   2 +-
 .../components/account_authorize.jsx          |   2 +-
 .../list_adder/components/account.jsx         |   2 +-
 .../list_editor/components/account.jsx        |   2 +-
 .../components/follow_request.jsx             |   2 +-
 .../picture_in_picture/components/header.jsx  |   2 +-
 .../report/components/status_check_box.jsx    |   2 +-
 .../status/components/detailed_status.jsx     |   2 +-
 .../features/ui/components/boost_modal.jsx    |   2 +-
 17 files changed, 130 insertions(+), 94 deletions(-)
 delete mode 100644 app/javascript/mastodon/components/display_name.jsx
 create mode 100644 app/javascript/mastodon/components/display_name.tsx

diff --git a/app/javascript/mastodon/components/__tests__/display_name-test.jsx b/app/javascript/mastodon/components/__tests__/display_name-test.jsx
index 0d040c4cd8..afb6c4758a 100644
--- a/app/javascript/mastodon/components/__tests__/display_name-test.jsx
+++ b/app/javascript/mastodon/components/__tests__/display_name-test.jsx
@@ -1,7 +1,7 @@
 import React from 'react';
 import renderer from 'react-test-renderer';
 import { fromJS }  from 'immutable';
-import DisplayName from '../display_name';
+import { DisplayName } from '../display_name';
 
 describe('<DisplayName />', () => {
   it('renders display name + account name', () => {
diff --git a/app/javascript/mastodon/components/account.jsx b/app/javascript/mastodon/components/account.jsx
index b0bbea7ce4..f110bce7a8 100644
--- a/app/javascript/mastodon/components/account.jsx
+++ b/app/javascript/mastodon/components/account.jsx
@@ -2,7 +2,7 @@ import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import { Avatar } from './avatar';
-import DisplayName from './display_name';
+import { DisplayName } from './display_name';
 import { IconButton } from './icon_button';
 import { defineMessages, injectIntl } from 'react-intl';
 import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/mastodon/components/display_name.jsx b/app/javascript/mastodon/components/display_name.jsx
deleted file mode 100644
index 1dd9fb1d67..0000000000
--- a/app/javascript/mastodon/components/display_name.jsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import React from 'react';
-import ImmutablePropTypes from 'react-immutable-proptypes';
-import PropTypes from 'prop-types';
-import { autoPlayGif } from 'mastodon/initial_state';
-import Skeleton from 'mastodon/components/skeleton';
-
-export default class DisplayName extends React.PureComponent {
-
-  static propTypes = {
-    account: ImmutablePropTypes.map,
-    others: ImmutablePropTypes.list,
-    localDomain: PropTypes.string,
-  };
-
-  handleMouseEnter = ({ currentTarget }) => {
-    if (autoPlayGif) {
-      return;
-    }
-
-    const emojis = currentTarget.querySelectorAll('.custom-emoji');
-
-    for (var i = 0; i < emojis.length; i++) {
-      let emoji = emojis[i];
-      emoji.src = emoji.getAttribute('data-original');
-    }
-  };
-
-  handleMouseLeave = ({ currentTarget }) => {
-    if (autoPlayGif) {
-      return;
-    }
-
-    const emojis = currentTarget.querySelectorAll('.custom-emoji');
-
-    for (var i = 0; i < emojis.length; i++) {
-      let emoji = emojis[i];
-      emoji.src = emoji.getAttribute('data-static');
-    }
-  };
-
-  render () {
-    const { others, localDomain } = this.props;
-
-    let displayName, suffix, account;
-
-    if (others && others.size > 1) {
-      displayName = others.take(2).map(a => <bdi key={a.get('id')}><strong className='display-name__html' dangerouslySetInnerHTML={{ __html: a.get('display_name_html') }} /></bdi>).reduce((prev, cur) => [prev, ', ', cur]);
-
-      if (others.size - 2 > 0) {
-        suffix = `+${others.size - 2}`;
-      }
-    } else if ((others && others.size > 0) || this.props.account) {
-      if (others && others.size > 0) {
-        account = others.first();
-      } else {
-        account = this.props.account;
-      }
-
-      let acct = account.get('acct');
-
-      if (acct.indexOf('@') === -1 && localDomain) {
-        acct = `${acct}@${localDomain}`;
-      }
-
-      displayName = <bdi><strong className='display-name__html' dangerouslySetInnerHTML={{ __html: account.get('display_name_html') }} /></bdi>;
-      suffix      = <span className='display-name__account'>@{acct}</span>;
-    } else {
-      displayName = <bdi><strong className='display-name__html'><Skeleton width='10ch' /></strong></bdi>;
-      suffix = <span className='display-name__account'><Skeleton width='7ch' /></span>;
-    }
-
-    return (
-      <span className='display-name' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
-        {displayName} {suffix}
-      </span>
-    );
-  }
-
-}
diff --git a/app/javascript/mastodon/components/display_name.tsx b/app/javascript/mastodon/components/display_name.tsx
new file mode 100644
index 0000000000..0452dba794
--- /dev/null
+++ b/app/javascript/mastodon/components/display_name.tsx
@@ -0,0 +1,115 @@
+import React from 'react';
+import { autoPlayGif } from '..//initial_state';
+import Skeleton from './skeleton';
+import { Account } from '../../types/resources';
+import { List } from 'immutable';
+
+type Props = {
+  account: Account;
+  others: List<Account>;
+  localDomain: string;
+};
+export class DisplayName extends React.PureComponent<Props> {
+  handleMouseEnter: React.ReactEventHandler<HTMLSpanElement> = ({
+    currentTarget,
+  }) => {
+    if (autoPlayGif) {
+      return;
+    }
+
+    const emojis =
+      currentTarget.querySelectorAll<HTMLImageElement>('img.custom-emoji');
+
+    emojis.forEach((emoji) => {
+      const originalSrc = emoji.getAttribute('data-original');
+      if (originalSrc != null) emoji.src = originalSrc;
+    });
+  };
+
+  handleMouseLeave: React.ReactEventHandler<HTMLSpanElement> = ({
+    currentTarget,
+  }) => {
+    if (autoPlayGif) {
+      return;
+    }
+
+    const emojis =
+      currentTarget.querySelectorAll<HTMLImageElement>('img.custom-emoji');
+
+    emojis.forEach((emoji) => {
+      const staticSrc = emoji.getAttribute('data-static');
+      if (staticSrc != null) emoji.src = staticSrc;
+    });
+  };
+
+  render() {
+    const { others, localDomain } = this.props;
+
+    let displayName: React.ReactNode, suffix: React.ReactNode, account: Account;
+
+    if (others && others.size > 1) {
+      displayName = others
+        .take(2)
+        .map((a) => (
+          <bdi key={a.get('id')}>
+            <strong
+              className='display-name__html'
+              dangerouslySetInnerHTML={{ __html: a.get('display_name_html') }}
+            />
+          </bdi>
+        ))
+        .reduce((prev, cur) => [prev, ', ', cur]);
+
+      if (others.size - 2 > 0) {
+        suffix = `+${others.size - 2}`;
+      }
+    } else if ((others && others.size > 0) || this.props.account) {
+      if (others && others.size > 0) {
+        account = others.first();
+      } else {
+        account = this.props.account;
+      }
+
+      let acct = account.get('acct');
+
+      if (acct.indexOf('@') === -1 && localDomain) {
+        acct = `${acct}@${localDomain}`;
+      }
+
+      displayName = (
+        <bdi>
+          <strong
+            className='display-name__html'
+            dangerouslySetInnerHTML={{
+              __html: account.get('display_name_html'),
+            }}
+          />
+        </bdi>
+      );
+      suffix = <span className='display-name__account'>@{acct}</span>;
+    } else {
+      displayName = (
+        <bdi>
+          <strong className='display-name__html'>
+            <Skeleton width='10ch' />
+          </strong>
+        </bdi>
+      );
+      suffix = (
+        <span className='display-name__account'>
+          <Skeleton width='7ch' />
+        </span>
+      );
+    }
+
+    return (
+      <span
+        className='display-name'
+        onMouseEnter={this.handleMouseEnter}
+        onMouseLeave={this.handleMouseLeave}
+      >
+        {displayName} {suffix}
+      </span>
+    );
+  }
+}
diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx
index 3ca840b720..8cd322edab 100644
--- a/app/javascript/mastodon/components/status.jsx
+++ b/app/javascript/mastodon/components/status.jsx
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
 import { Avatar } from './avatar';
 import { AvatarOverlay } from './avatar_overlay';
 import { RelativeTimestamp } from './relative_timestamp';
-import DisplayName from './display_name';
+import { DisplayName } from './display_name';
 import StatusContent from './status_content';
 import StatusActionBar from './status_action_bar';
 import AttachmentList from './attachment_list';
diff --git a/app/javascript/mastodon/features/account_timeline/components/moved_note.jsx b/app/javascript/mastodon/features/account_timeline/components/moved_note.jsx
index 273583c0ad..29861612c3 100644
--- a/app/javascript/mastodon/features/account_timeline/components/moved_note.jsx
+++ b/app/javascript/mastodon/features/account_timeline/components/moved_note.jsx
@@ -3,7 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 import { FormattedMessage } from 'react-intl';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import { AvatarOverlay } from '../../../components/avatar_overlay';
-import DisplayName from '../../../components/display_name';
+import { DisplayName } from '../../../components/display_name';
 import { Link } from 'react-router-dom';
 
 export default class MovedNote extends ImmutablePureComponent {
diff --git a/app/javascript/mastodon/features/compose/components/autosuggest_account.jsx b/app/javascript/mastodon/features/compose/components/autosuggest_account.jsx
index 2c92016e86..a635657d9f 100644
--- a/app/javascript/mastodon/features/compose/components/autosuggest_account.jsx
+++ b/app/javascript/mastodon/features/compose/components/autosuggest_account.jsx
@@ -1,6 +1,6 @@
 import React from 'react';
 import { Avatar } from '../../../components/avatar';
-import DisplayName from '../../../components/display_name';
+import { DisplayName } from '../../../components/display_name';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 
diff --git a/app/javascript/mastodon/features/compose/components/reply_indicator.jsx b/app/javascript/mastodon/features/compose/components/reply_indicator.jsx
index 68cd7b0804..b3f1b1b482 100644
--- a/app/javascript/mastodon/features/compose/components/reply_indicator.jsx
+++ b/app/javascript/mastodon/features/compose/components/reply_indicator.jsx
@@ -3,7 +3,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import { Avatar } from '../../../components/avatar';
 import { IconButton } from '../../../components/icon_button';
-import DisplayName from '../../../components/display_name';
+import { DisplayName } from '../../../components/display_name';
 import { defineMessages, injectIntl } from 'react-intl';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import AttachmentList from 'mastodon/components/attachment_list';
diff --git a/app/javascript/mastodon/features/directory/components/account_card.jsx b/app/javascript/mastodon/features/directory/components/account_card.jsx
index 4951427151..1ef9d64813 100644
--- a/app/javascript/mastodon/features/directory/components/account_card.jsx
+++ b/app/javascript/mastodon/features/directory/components/account_card.jsx
@@ -5,7 +5,7 @@ import PropTypes from 'prop-types';
 import { connect } from 'react-redux';
 import { makeGetAccount } from 'mastodon/selectors';
 import { Avatar } from 'mastodon/components/avatar';
-import DisplayName from 'mastodon/components/display_name';
+import { DisplayName } from 'mastodon/components/display_name';
 import { Link } from 'react-router-dom';
 import Button from 'mastodon/components/button';
 import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
diff --git a/app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx b/app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx
index b370b33ecb..5d0632b0f6 100644
--- a/app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx
+++ b/app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { Link } from 'react-router-dom';
 import { Avatar } from '../../../components/avatar';
-import DisplayName from '../../../components/display_name';
+import { DisplayName } from '../../../components/display_name';
 import { IconButton } from '../../../components/icon_button';
 import { defineMessages, injectIntl } from 'react-intl';
 import ImmutablePureComponent from 'react-immutable-pure-component';
diff --git a/app/javascript/mastodon/features/list_adder/components/account.jsx b/app/javascript/mastodon/features/list_adder/components/account.jsx
index 410f1537a5..5dc384aba6 100644
--- a/app/javascript/mastodon/features/list_adder/components/account.jsx
+++ b/app/javascript/mastodon/features/list_adder/components/account.jsx
@@ -4,7 +4,7 @@ import { makeGetAccount } from '../../../selectors';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { Avatar } from '../../../components/avatar';
-import DisplayName from '../../../components/display_name';
+import { DisplayName } from '../../../components/display_name';
 import { injectIntl } from 'react-intl';
 
 const makeMapStateToProps = () => {
diff --git a/app/javascript/mastodon/features/list_editor/components/account.jsx b/app/javascript/mastodon/features/list_editor/components/account.jsx
index b46d0504a4..fc1d2d6071 100644
--- a/app/javascript/mastodon/features/list_editor/components/account.jsx
+++ b/app/javascript/mastodon/features/list_editor/components/account.jsx
@@ -5,7 +5,7 @@ import { makeGetAccount } from '../../../selectors';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { Avatar } from '../../../components/avatar';
-import DisplayName from '../../../components/display_name';
+import { DisplayName } from '../../../components/display_name';
 import { IconButton } from '../../../components/icon_button';
 import { defineMessages, injectIntl } from 'react-intl';
 import { removeFromListEditor, addToListEditor } from '../../../actions/lists';
diff --git a/app/javascript/mastodon/features/notifications/components/follow_request.jsx b/app/javascript/mastodon/features/notifications/components/follow_request.jsx
index 0d930f0b1f..d8b2ca1cc9 100644
--- a/app/javascript/mastodon/features/notifications/components/follow_request.jsx
+++ b/app/javascript/mastodon/features/notifications/components/follow_request.jsx
@@ -2,7 +2,7 @@ import React from 'react';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import PropTypes from 'prop-types';
 import { Avatar } from 'mastodon/components/avatar';
-import DisplayName from 'mastodon/components/display_name';
+import { DisplayName } from 'mastodon/components/display_name';
 import { Link } from 'react-router-dom';
 import { IconButton } from 'mastodon/components/icon_button';
 import { defineMessages, injectIntl } from 'react-intl';
diff --git a/app/javascript/mastodon/features/picture_in_picture/components/header.jsx b/app/javascript/mastodon/features/picture_in_picture/components/header.jsx
index c6d2a103dc..c1c04da548 100644
--- a/app/javascript/mastodon/features/picture_in_picture/components/header.jsx
+++ b/app/javascript/mastodon/features/picture_in_picture/components/header.jsx
@@ -6,7 +6,7 @@ import PropTypes from 'prop-types';
 import { IconButton } from 'mastodon/components/icon_button';
 import { Link } from 'react-router-dom';
 import { Avatar } from 'mastodon/components/avatar';
-import DisplayName from 'mastodon/components/display_name';
+import { DisplayName } from 'mastodon/components/display_name';
 import { defineMessages, injectIntl } from 'react-intl';
 
 const messages = defineMessages({
diff --git a/app/javascript/mastodon/features/report/components/status_check_box.jsx b/app/javascript/mastodon/features/report/components/status_check_box.jsx
index 003cdc8e3a..8d6091f778 100644
--- a/app/javascript/mastodon/features/report/components/status_check_box.jsx
+++ b/app/javascript/mastodon/features/report/components/status_check_box.jsx
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import StatusContent from 'mastodon/components/status_content';
 import { Avatar } from 'mastodon/components/avatar';
-import DisplayName from 'mastodon/components/display_name';
+import { DisplayName } from 'mastodon/components/display_name';
 import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
 import Option from './option';
 import MediaAttachments from 'mastodon/components/media_attachments';
diff --git a/app/javascript/mastodon/features/status/components/detailed_status.jsx b/app/javascript/mastodon/features/status/components/detailed_status.jsx
index 72c9021242..5019dfdb4d 100644
--- a/app/javascript/mastodon/features/status/components/detailed_status.jsx
+++ b/app/javascript/mastodon/features/status/components/detailed_status.jsx
@@ -2,7 +2,7 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import { Avatar } from '../../../components/avatar';
-import DisplayName from '../../../components/display_name';
+import { DisplayName } from '../../../components/display_name';
 import StatusContent from '../../../components/status_content';
 import MediaGallery from '../../../components/media_gallery';
 import { Link } from 'react-router-dom';
diff --git a/app/javascript/mastodon/features/ui/components/boost_modal.jsx b/app/javascript/mastodon/features/ui/components/boost_modal.jsx
index 1f28927d60..4eeb30be09 100644
--- a/app/javascript/mastodon/features/ui/components/boost_modal.jsx
+++ b/app/javascript/mastodon/features/ui/components/boost_modal.jsx
@@ -7,7 +7,7 @@ import Button from '../../../components/button';
 import StatusContent from '../../../components/status_content';
 import { Avatar } from '../../../components/avatar';
 import { RelativeTimestamp } from '../../../components/relative_timestamp';
-import DisplayName from '../../../components/display_name';
+import { DisplayName } from '../../../components/display_name';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import { Icon }  from 'mastodon/components/icon';
 import AttachmentList from 'mastodon/components/attachment_list';