~cytrogen/masto-fe

349cae0b57ee65475a70311863959e7a0cf53065 — fusagiko / takayamaki 2 years ago ab7716c
Add type annotation for DisplayName component (#24752)

M app/javascript/mastodon/components/__tests__/display_name-test.jsx => app/javascript/mastodon/components/__tests__/display_name-test.jsx +1 -1
@@ 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', () => {

M app/javascript/mastodon/components/account.jsx => app/javascript/mastodon/components/account.jsx +1 -1
@@ 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';

D app/javascript/mastodon/components/display_name.jsx => app/javascript/mastodon/components/display_name.jsx +0 -79
@@ 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>
    );
  }

}

A app/javascript/mastodon/components/display_name.tsx => app/javascript/mastodon/components/display_name.tsx +115 -0
@@ 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>
    );
  }
}

M app/javascript/mastodon/components/status.jsx => app/javascript/mastodon/components/status.jsx +1 -1
@@ 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';

M app/javascript/mastodon/features/account_timeline/components/moved_note.jsx => app/javascript/mastodon/features/account_timeline/components/moved_note.jsx +1 -1
@@ 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 {

M app/javascript/mastodon/features/compose/components/autosuggest_account.jsx => app/javascript/mastodon/features/compose/components/autosuggest_account.jsx +1 -1
@@ 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';


M app/javascript/mastodon/features/compose/components/reply_indicator.jsx => app/javascript/mastodon/features/compose/components/reply_indicator.jsx +1 -1
@@ 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';

M app/javascript/mastodon/features/directory/components/account_card.jsx => app/javascript/mastodon/features/directory/components/account_card.jsx +1 -1
@@ 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';

M app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx => app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx +1 -1
@@ 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';

M app/javascript/mastodon/features/list_adder/components/account.jsx => app/javascript/mastodon/features/list_adder/components/account.jsx +1 -1
@@ 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 = () => {

M app/javascript/mastodon/features/list_editor/components/account.jsx => app/javascript/mastodon/features/list_editor/components/account.jsx +1 -1
@@ 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';

M app/javascript/mastodon/features/notifications/components/follow_request.jsx => app/javascript/mastodon/features/notifications/components/follow_request.jsx +1 -1
@@ 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';

M app/javascript/mastodon/features/picture_in_picture/components/header.jsx => app/javascript/mastodon/features/picture_in_picture/components/header.jsx +1 -1
@@ 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({

M app/javascript/mastodon/features/report/components/status_check_box.jsx => app/javascript/mastodon/features/report/components/status_check_box.jsx +1 -1
@@ 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';

M app/javascript/mastodon/features/status/components/detailed_status.jsx => app/javascript/mastodon/features/status/components/detailed_status.jsx +1 -1
@@ 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';

M app/javascript/mastodon/features/ui/components/boost_modal.jsx => app/javascript/mastodon/features/ui/components/boost_modal.jsx +1 -1
@@ 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';