~cytrogen/masto-fe

c81d1b0d38c0b54ae5c8bbc7161eeab0e6b382ad — Claire 2 years ago 887112a + c8181eb
Merge commit 'c8181eb0a41c4f5c1655d4e400cab071aee4182a' into glitch-soc/merge-upstream

Conflicts:
- `app/javascript/packs/admin.jsx`:
  Upstream reworked imports, but we had many changes.
  Reworked imports as upstream did.
- `app/javascript/packs/public.jsx`:
  Upstream reworked imports, but we had many changes.
  Reworked imports as upstream did.
144 files changed, 266 insertions(+), 226 deletions(-)

M .eslintrc.js
M app/javascript/core/mailer.js
M app/javascript/mastodon/actions/markers.js
M app/javascript/mastodon/actions/notifications.js
M app/javascript/mastodon/actions/streaming.js
M app/javascript/mastodon/actions/timelines.js
M app/javascript/mastodon/common.js
M app/javascript/mastodon/compare_id.ts
M app/javascript/mastodon/components/__tests__/avatar-test.jsx
M app/javascript/mastodon/components/__tests__/avatar_overlay-test.jsx
M app/javascript/mastodon/components/account.jsx
M app/javascript/mastodon/components/animated_number.tsx
M app/javascript/mastodon/components/attachment_list.jsx
M app/javascript/mastodon/components/avatar.tsx
M app/javascript/mastodon/components/avatar_composite.jsx
M app/javascript/mastodon/components/avatar_overlay.tsx
M app/javascript/mastodon/components/blurhash.tsx
M app/javascript/mastodon/components/check.tsx
M app/javascript/mastodon/components/column_back_button.jsx
M app/javascript/mastodon/components/column_back_button_slim.jsx
M app/javascript/mastodon/components/column_header.jsx
M app/javascript/mastodon/components/dismissable_banner.jsx
M app/javascript/mastodon/components/domain.tsx
M app/javascript/mastodon/components/dropdown_menu.jsx
M app/javascript/mastodon/components/edited_timestamp/index.jsx
M app/javascript/mastodon/components/gifv.tsx
M app/javascript/mastodon/components/icon.tsx
M app/javascript/mastodon/components/icon_button.tsx
M app/javascript/mastodon/components/icon_with_badge.tsx
M app/javascript/mastodon/components/image.tsx
M app/javascript/mastodon/components/inline_account.jsx
M app/javascript/mastodon/components/load_gap.jsx
M app/javascript/mastodon/components/media_gallery.jsx
M app/javascript/mastodon/components/not_signed_in_indicator.tsx
M app/javascript/mastodon/components/picture_in_picture_placeholder.jsx
M app/javascript/mastodon/components/poll.jsx
M app/javascript/mastodon/components/radio_button.tsx
M app/javascript/mastodon/components/relative_timestamp.tsx
M app/javascript/mastodon/components/server_banner.jsx
M app/javascript/mastodon/components/status.jsx
M app/javascript/mastodon/components/status_action_bar.jsx
M app/javascript/mastodon/components/status_content.jsx
M app/javascript/mastodon/components/verified_badge.tsx
M app/javascript/mastodon/features/about/index.jsx
M app/javascript/mastodon/features/account/components/follow_request_note.jsx
M app/javascript/mastodon/features/account/components/header.jsx
M app/javascript/mastodon/features/account_gallery/components/media_item.jsx
M app/javascript/mastodon/features/account_timeline/components/moved_note.jsx
M app/javascript/mastodon/features/audio/index.jsx
M app/javascript/mastodon/features/compose/components/autosuggest_account.jsx
M app/javascript/mastodon/features/compose/components/compose_form.jsx
M app/javascript/mastodon/features/compose/components/navigation_bar.jsx
M app/javascript/mastodon/features/compose/components/poll_button.jsx
M app/javascript/mastodon/features/compose/components/poll_form.jsx
M app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx
M app/javascript/mastodon/features/compose/components/reply_indicator.jsx
M app/javascript/mastodon/features/compose/components/search.jsx
M app/javascript/mastodon/features/compose/components/search_results.jsx
M app/javascript/mastodon/features/compose/components/upload.jsx
M app/javascript/mastodon/features/compose/components/upload_button.jsx
M app/javascript/mastodon/features/compose/components/upload_progress.jsx
M app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js
M app/javascript/mastodon/features/compose/containers/language_dropdown_container.js
M app/javascript/mastodon/features/compose/index.jsx
M app/javascript/mastodon/features/direct_timeline/components/conversation.jsx
M app/javascript/mastodon/features/directory/components/account_card.jsx
M app/javascript/mastodon/features/directory/index.jsx
M app/javascript/mastodon/features/emoji/emoji_compressed.js
M app/javascript/mastodon/features/emoji/emoji_mart_data_light.js
M app/javascript/mastodon/features/emoji/emoji_mart_search_light.js
M app/javascript/mastodon/features/emoji/emoji_unicode_mapping_light.js
M app/javascript/mastodon/features/emoji/emoji_utils.js
M app/javascript/mastodon/features/emoji/unicode_to_filename.js
M app/javascript/mastodon/features/emoji/unicode_to_unified_name.js
M app/javascript/mastodon/features/explore/components/story.jsx
M app/javascript/mastodon/features/favourites/index.jsx
M app/javascript/mastodon/features/filters/select_filter.jsx
M app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx
M app/javascript/mastodon/features/getting_started/components/announcements.jsx
M app/javascript/mastodon/features/hashtag_timeline/index.jsx
M app/javascript/mastodon/features/home_timeline/index.jsx
M app/javascript/mastodon/features/interaction_modal/index.jsx
M app/javascript/mastodon/features/list_adder/components/account.jsx
M app/javascript/mastodon/features/list_adder/components/list.jsx
M app/javascript/mastodon/features/list_editor/components/account.jsx
M app/javascript/mastodon/features/list_editor/components/edit_list_form.jsx
M app/javascript/mastodon/features/list_editor/components/search.jsx
M app/javascript/mastodon/features/list_timeline/index.jsx
M app/javascript/mastodon/features/notifications/components/clear_column_button.jsx
M app/javascript/mastodon/features/notifications/components/filter_bar.jsx
M app/javascript/mastodon/features/notifications/components/follow_request.jsx
M app/javascript/mastodon/features/notifications/components/notification.jsx
M app/javascript/mastodon/features/notifications/components/notifications_permission_banner.jsx
M app/javascript/mastodon/features/notifications/components/report.jsx
M app/javascript/mastodon/features/notifications/index.jsx
M app/javascript/mastodon/features/onboarding/components/progress_indicator.jsx
M app/javascript/mastodon/features/onboarding/components/step.jsx
M app/javascript/mastodon/features/onboarding/share.jsx
M app/javascript/mastodon/features/picture_in_picture/components/footer.jsx
M app/javascript/mastodon/features/picture_in_picture/components/header.jsx
M app/javascript/mastodon/features/reblogs/index.jsx
M app/javascript/mastodon/features/report/components/option.jsx
M app/javascript/mastodon/features/report/components/status_check_box.jsx
M app/javascript/mastodon/features/status/components/action_bar.jsx
M app/javascript/mastodon/features/status/components/card.jsx
M app/javascript/mastodon/features/status/components/detailed_status.jsx
M app/javascript/mastodon/features/status/index.jsx
M app/javascript/mastodon/features/subscribed_languages_modal/index.jsx
M app/javascript/mastodon/features/ui/components/actions_modal.jsx
M app/javascript/mastodon/features/ui/components/boost_modal.jsx
M app/javascript/mastodon/features/ui/components/bundle_modal_error.jsx
M app/javascript/mastodon/features/ui/components/column_header.jsx
M app/javascript/mastodon/features/ui/components/column_link.jsx
M app/javascript/mastodon/features/ui/components/compare_history_modal.jsx
M app/javascript/mastodon/features/ui/components/embed_modal.jsx
M app/javascript/mastodon/features/ui/components/filter_modal.jsx
M app/javascript/mastodon/features/ui/components/focal_point_modal.jsx
M app/javascript/mastodon/features/ui/components/follow_requests_column_link.jsx
M app/javascript/mastodon/features/ui/components/header.jsx
M app/javascript/mastodon/features/ui/components/image_modal.jsx
M app/javascript/mastodon/features/ui/components/media_modal.jsx
M app/javascript/mastodon/features/ui/components/notifications_counter_icon.js
M app/javascript/mastodon/features/ui/components/report_modal.jsx
M app/javascript/mastodon/features/ui/components/zoomable_image.jsx
M app/javascript/mastodon/features/video/index.jsx
M app/javascript/mastodon/main.jsx
M app/javascript/mastodon/performance.js
M app/javascript/mastodon/reducers/compose.js
M app/javascript/mastodon/reducers/contexts.js
M app/javascript/mastodon/reducers/conversations.js
M app/javascript/mastodon/reducers/index.js
M app/javascript/mastodon/reducers/missed_updates.ts
M app/javascript/mastodon/reducers/notifications.js
M app/javascript/mastodon/reducers/settings.js
M app/javascript/mastodon/reducers/timelines.js
M app/javascript/mastodon/service_worker/web_push_locales.js
M app/javascript/mastodon/uuid.ts
M app/javascript/packs/admin.jsx
M app/javascript/packs/public.jsx
M app/javascript/packs/share.jsx
M app/javascript/types/image.d.ts
M config/webpack/shared.js
M package.json
M yarn.lock
M .eslintrc.js => .eslintrc.js +25 -0
@@ 4,6 4,7 @@ module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'plugin:jsx-a11y/recommended',
    'plugin:import/recommended',
    'plugin:promise/recommended',


@@ 102,6 103,7 @@ module.exports = {
      {
        vars: 'all',
        args: 'after-used',
        destructuredArrayIgnorePattern: '^_',
        ignoreRestSiblings: true,
      },
    ],


@@ 208,6 210,9 @@ module.exports = {
        ],
      },
    ],
    'import/no-amd': 'error',
    'import/no-commonjs': 'error',
    'import/no-import-module-exports': 'error',
    'import/no-webpack-loader-syntax': 'error',

    'promise/always-return': 'off',


@@ 255,6 260,7 @@ module.exports = {
        '*.config.js',
        '.*rc.js',
        'ide-helper.js',
        'config/webpack/**/*',
      ],

      env: {


@@ 264,6 270,10 @@ module.exports = {
      parserOptions: {
        sourceType: 'script',
      },

      rules: {
        'import/no-commonjs': 'off',
      },
    },
    {
      files: [


@@ 275,6 285,7 @@ module.exports = {
        'eslint:recommended',
        'plugin:@typescript-eslint/recommended',
        'plugin:react/recommended',
        'plugin:react-hooks/recommended',
        'plugin:jsx-a11y/recommended',
        'plugin:import/recommended',
        'plugin:import/typescript',


@@ 286,6 297,12 @@ module.exports = {
        '@typescript-eslint/no-explicit-any': 'off',

        'jsdoc/require-jsdoc': 'off',

        // Those rules set stricter rules for TS files
        // to enforce better practices when converting from JS
        'import/no-default-export': 'warn',
        'react/prefer-stateless-function': 'warn',
        'react/function-component-definition': ['error', { namedComponents: 'arrow-function' }],
      },
    },
    {


@@ 298,5 315,13 @@ module.exports = {
        jest: true,
      },
    },
    {
      files: [
        'streaming/**/*',
      ],
      rules: {
        'import/no-commonjs': 'off',
      },
    },
  ],
};

M app/javascript/core/mailer.js => app/javascript/core/mailer.js +1 -1
@@ 1,3 1,3 @@
require('../styles/mailer.scss');
import '../styles/mailer.scss';

require.context('../icons');

M app/javascript/mastodon/actions/markers.js => app/javascript/mastodon/actions/markers.js +1 -1
@@ 1,6 1,6 @@
import api from '../api';
import { debounce } from 'lodash';
import compareId from '../compare_id';
import { compareId } from '../compare_id';
import { List as ImmutableList } from 'immutable';

export const MARKERS_FETCH_REQUEST = 'MARKERS_FETCH_REQUEST';

M app/javascript/mastodon/actions/notifications.js => app/javascript/mastodon/actions/notifications.js +1 -1
@@ 13,7 13,7 @@ import { defineMessages } from 'react-intl';
import { List as ImmutableList } from 'immutable';
import { unescapeHTML } from '../utils/html';
import { usePendingItems as preferPendingItems } from 'mastodon/initial_state';
import compareId from 'mastodon/compare_id';
import { compareId } from 'mastodon/compare_id';
import { requestNotificationPermission } from '../utils/notifications';

export const NOTIFICATIONS_UPDATE      = 'NOTIFICATIONS_UPDATE';

M app/javascript/mastodon/actions/streaming.js => app/javascript/mastodon/actions/streaming.js +2 -0
@@ 52,8 52,10 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti
    /**
     * @param {function(Function, Function): void} fallback
     */

    const useFallback = fallback => {
      fallback(dispatch, () => {
        // eslint-disable-next-line react-hooks/rules-of-hooks -- this is not a react hook
        pollingId = setTimeout(() => useFallback(fallback), 20000 + randomUpTo(20000));
      });
    };

M app/javascript/mastodon/actions/timelines.js => app/javascript/mastodon/actions/timelines.js +1 -1
@@ 2,7 2,7 @@ import { importFetchedStatus, importFetchedStatuses } from './importer';
import { submitMarkers } from './markers';
import api, { getLinks } from 'mastodon/api';
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
import compareId from 'mastodon/compare_id';
import { compareId } from 'mastodon/compare_id';
import { usePendingItems as preferPendingItems } from 'mastodon/initial_state';

export const TIMELINE_UPDATE  = 'TIMELINE_UPDATE';

M app/javascript/mastodon/common.js => app/javascript/mastodon/common.js +1 -1
@@ 1,7 1,7 @@
import Rails from '@rails/ujs';
import 'font-awesome/css/font-awesome.css';

export function start() {
  require('font-awesome/css/font-awesome.css');
  require.context('../images/', true);

  try {

M app/javascript/mastodon/compare_id.ts => app/javascript/mastodon/compare_id.ts +1 -1
@@ 1,4 1,4 @@
export default function compareId (id1: string, id2: string) {
export function compareId (id1: string, id2: string) {
  if (id1 === id2) {
    return 0;
  }

M app/javascript/mastodon/components/__tests__/avatar-test.jsx => app/javascript/mastodon/components/__tests__/avatar-test.jsx +1 -1
@@ 1,7 1,7 @@
import React from 'react';
import renderer from 'react-test-renderer';
import { fromJS } from 'immutable';
import Avatar from '../avatar';
import { Avatar } from '../avatar';

describe('<Avatar />', () => {
  const account = fromJS({

M app/javascript/mastodon/components/__tests__/avatar_overlay-test.jsx => app/javascript/mastodon/components/__tests__/avatar_overlay-test.jsx +1 -1
@@ 1,7 1,7 @@
import React from 'react';
import renderer from 'react-test-renderer';
import { fromJS } from 'immutable';
import AvatarOverlay from '../avatar_overlay';
import { AvatarOverlay } from '../avatar_overlay';

describe('<AvatarOverlay', () => {
  const account = fromJS({

M app/javascript/mastodon/components/account.jsx => app/javascript/mastodon/components/account.jsx +4 -4
@@ 1,19 1,19 @@
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import Avatar from './avatar';
import { Avatar } from './avatar';
import DisplayName from './display_name';
import IconButton from './icon_button';
import { IconButton } from './icon_button';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { me } from '../initial_state';
import RelativeTimestamp from './relative_timestamp';
import { RelativeTimestamp } from './relative_timestamp';
import Skeleton from 'mastodon/components/skeleton';
import { Link } from 'react-router-dom';
import { counterRenderer } from 'mastodon/components/common_counter';
import ShortNumber from 'mastodon/components/short_number';
import classNames from 'classnames';
import VerifiedBadge from 'mastodon/components/verified_badge';
import { VerifiedBadge } from 'mastodon/components/verified_badge';

const messages = defineMessages({
  follow: { id: 'account.follow', defaultMessage: 'Follow' },

M app/javascript/mastodon/components/animated_number.tsx => app/javascript/mastodon/components/animated_number.tsx +0 -2
@@ 54,5 54,3 @@ export const AnimatedNumber: React.FC<Props> = ({
    </TransitionMotion>
  );
};

export default AnimatedNumber;

M app/javascript/mastodon/components/attachment_list.jsx => app/javascript/mastodon/components/attachment_list.jsx +1 -1
@@ 4,7 4,7 @@ import PropTypes from 'prop-types';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';

const filename = url => url.split('/').pop().split('#')[0].split('?')[0];


M app/javascript/mastodon/components/avatar.tsx => app/javascript/mastodon/components/avatar.tsx +0 -2
@@ 45,5 45,3 @@ export const Avatar: React.FC<Props> = ({
    </div>
  );
};

export default Avatar;

M app/javascript/mastodon/components/avatar_composite.jsx => app/javascript/mastodon/components/avatar_composite.jsx +1 -1
@@ 2,7 2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { autoPlayGif } from '../initial_state';
import Avatar from './avatar';
import { Avatar } from './avatar';

export default class AvatarComposite extends React.PureComponent {


M app/javascript/mastodon/components/avatar_overlay.tsx => app/javascript/mastodon/components/avatar_overlay.tsx +0 -2
@@ 47,5 47,3 @@ export const AvatarOverlay: React.FC<Props> = ({
    </div>
  );
};

export default AvatarOverlay;

M app/javascript/mastodon/components/blurhash.tsx => app/javascript/mastodon/components/blurhash.tsx +6 -4
@@ 9,13 9,13 @@ type Props = {
  children?: never;
  [key: string]: any;
}
function Blurhash({
const Blurhash: React.FC<Props> = ({
  hash,
  width = 32,
  height = width,
  dummy = false,
  ...canvasProps
}: Props) {
}) => {
  const canvasRef = useRef<HTMLCanvasElement>(null);

  useEffect(() => {


@@ 40,6 40,8 @@ function Blurhash({
  return (
    <canvas {...canvasProps} ref={canvasRef} width={width} height={height} />
  );
}
};

const MemoizedBlurhash = React.memo(Blurhash);

export default React.memo(Blurhash);
export { MemoizedBlurhash as Blurhash };

M app/javascript/mastodon/components/check.tsx => app/javascript/mastodon/components/check.tsx +0 -2
@@ 5,5 5,3 @@ export const Check: React.FC = () => (
    <path fillRule='evenodd' d='M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z' clipRule='evenodd' />
  </svg>
);

export default Check;

M app/javascript/mastodon/components/column_back_button.jsx => app/javascript/mastodon/components/column_back_button.jsx +1 -1
@@ 1,7 1,7 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import { createPortal } from 'react-dom';

export default class ColumnBackButton extends React.PureComponent {

M app/javascript/mastodon/components/column_back_button_slim.jsx => app/javascript/mastodon/components/column_back_button_slim.jsx +1 -1
@@ 1,7 1,7 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
import ColumnBackButton from './column_back_button';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';

export default class ColumnBackButtonSlim extends ColumnBackButton {


M app/javascript/mastodon/components/column_header.jsx => app/javascript/mastodon/components/column_header.jsx +1 -1
@@ 3,7 3,7 @@ import PropTypes from 'prop-types';
import { createPortal } from 'react-dom';
import classNames from 'classnames';
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';

const messages = defineMessages({
  show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },

M app/javascript/mastodon/components/dismissable_banner.jsx => app/javascript/mastodon/components/dismissable_banner.jsx +1 -1
@@ 1,5 1,5 @@
import React from 'react';
import IconButton from './icon_button';
import { IconButton } from './icon_button';
import PropTypes from 'prop-types';
import { injectIntl, defineMessages } from 'react-intl';
import { bannerSettings } from 'mastodon/settings';

M app/javascript/mastodon/components/domain.tsx => app/javascript/mastodon/components/domain.tsx +1 -1
@@ 1,5 1,5 @@
import React, { useCallback } from 'react';
import IconButton from './icon_button';
import { IconButton } from './icon_button';
import { InjectedIntl, defineMessages, injectIntl } from 'react-intl';

const messages = defineMessages({

M app/javascript/mastodon/components/dropdown_menu.jsx => app/javascript/mastodon/components/dropdown_menu.jsx +1 -1
@@ 1,7 1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import IconButton from './icon_button';
import { IconButton } from './icon_button';
import Overlay from 'react-overlays/Overlay';
import { supportsPassiveEvents } from 'detect-passive-events';
import classNames from 'classnames';

M app/javascript/mastodon/components/edited_timestamp/index.jsx => app/javascript/mastodon/components/edited_timestamp/index.jsx +2 -2
@@ 1,11 1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage, injectIntl } from 'react-intl';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import DropdownMenu from './containers/dropdown_menu_container';
import { connect } from 'react-redux';
import { openModal } from 'mastodon/actions/modal';
import RelativeTimestamp from 'mastodon/components/relative_timestamp';
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
import InlineAccount from 'mastodon/components/inline_account';

const mapDispatchToProps = (dispatch, { statusId }) => ({

M app/javascript/mastodon/components/gifv.tsx => app/javascript/mastodon/components/gifv.tsx +0 -2
@@ 64,5 64,3 @@ export const GIFV: React.FC<Props> = ({
    </div>
  );
};

export default GIFV;

M app/javascript/mastodon/components/icon.tsx => app/javascript/mastodon/components/icon.tsx +0 -2
@@ 10,5 10,3 @@ type Props = {
}
export const Icon: React.FC<Props> = ({ id, className, fixedWidth, ...other }) =>
  <i className={classNames('fa', `fa-${id}`, className, { 'fa-fw': fixedWidth })} {...other} />;

export default Icon;

M app/javascript/mastodon/components/icon_button.tsx => app/javascript/mastodon/components/icon_button.tsx +1 -1
@@ 30,7 30,7 @@ type States = {
  activate: boolean,
  deactivate: boolean,
}
export default class IconButton extends React.PureComponent<Props, States> {
export class IconButton extends React.PureComponent<Props, States> {

  static defaultProps = {
    size: 18,

M app/javascript/mastodon/components/icon_with_badge.tsx => app/javascript/mastodon/components/icon_with_badge.tsx +1 -3
@@ 9,12 9,10 @@ type Props = {
  issueBadge: boolean;
  className: string;
}
const IconWithBadge: React.FC<Props> = ({ id, count, issueBadge, className }) => (
export const IconWithBadge: React.FC<Props> = ({ id, count, issueBadge, className }) => (
  <i className='icon-with-badge'>
    <Icon id={id} fixedWidth className={className} />
    {count > 0 && <i className='icon-with-badge__badge'>{formatNumber(count)}</i>}
    {issueBadge && <i className='icon-with-badge__issue-badge' />}
  </i>
);

export default IconWithBadge;

M app/javascript/mastodon/components/image.tsx => app/javascript/mastodon/components/image.tsx +1 -3
@@ 1,5 1,5 @@
import React, { useCallback, useState } from 'react';
import Blurhash from './blurhash';
import { Blurhash } from './blurhash';
import classNames from 'classnames';

type Props = {


@@ 23,5 23,3 @@ export const Image: React.FC<Props> = ({ src, srcSet, blurhash, className }) => 
    </div>
  );
};

export default Image;

M app/javascript/mastodon/components/inline_account.jsx => app/javascript/mastodon/components/inline_account.jsx +1 -1
@@ 2,7 2,7 @@ import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { makeGetAccount } from 'mastodon/selectors';
import Avatar from 'mastodon/components/avatar';
import { Avatar } from 'mastodon/components/avatar';

const makeMapStateToProps = () => {
  const getAccount = makeGetAccount();

M app/javascript/mastodon/components/load_gap.jsx => app/javascript/mastodon/components/load_gap.jsx +1 -1
@@ 1,7 1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, defineMessages } from 'react-intl';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';

const messages = defineMessages({
  load_more: { id: 'status.load_more', defaultMessage: 'Load more' },

M app/javascript/mastodon/components/media_gallery.jsx => app/javascript/mastodon/components/media_gallery.jsx +2 -2
@@ 2,12 2,12 @@ import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import { is } from 'immutable';
import IconButton from './icon_button';
import { IconButton } from './icon_button';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import { autoPlayGif, cropImages, displayMedia, useBlurhash } from '../initial_state';
import { debounce } from 'lodash';
import Blurhash from 'mastodon/components/blurhash';
import { Blurhash } from 'mastodon/components/blurhash';

const messages = defineMessages({
  toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: '{number, plural, one {Hide image} other {Hide images}}' },

M app/javascript/mastodon/components/not_signed_in_indicator.tsx => app/javascript/mastodon/components/not_signed_in_indicator.tsx +0 -2
@@ 8,5 8,3 @@ export const NotSignedInIndicator: React.FC = () => (
    </div>
  </div>
);

export default NotSignedInIndicator;

M app/javascript/mastodon/components/picture_in_picture_placeholder.jsx => app/javascript/mastodon/components/picture_in_picture_placeholder.jsx +1 -1
@@ 1,6 1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import { removePictureInPicture } from 'mastodon/actions/picture_in_picture';
import { connect } from 'react-redux';
import { FormattedMessage } from 'react-intl';

M app/javascript/mastodon/components/poll.jsx => app/javascript/mastodon/components/poll.jsx +2 -2
@@ 8,8 8,8 @@ import Motion from 'mastodon/features/ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
import escapeTextContentForBrowser from 'escape-html';
import emojify from 'mastodon/features/emoji/emoji';
import RelativeTimestamp from './relative_timestamp';
import Icon from 'mastodon/components/icon';
import { RelativeTimestamp } from './relative_timestamp';
import { Icon }  from 'mastodon/components/icon';

const messages = defineMessages({
  closed: {

M app/javascript/mastodon/components/radio_button.tsx => app/javascript/mastodon/components/radio_button.tsx +0 -2
@@ 26,5 26,3 @@ export const RadioButton: React.FC<Props> = ({ name, value, checked, onChange, l
    </label>
  );
};

export default RadioButton;

M app/javascript/mastodon/components/relative_timestamp.tsx => app/javascript/mastodon/components/relative_timestamp.tsx +3 -1
@@ 200,4 200,6 @@ class RelativeTimestamp extends React.Component<Props, States> {

}

export default injectIntl(RelativeTimestamp);
const RelativeTimestampWithIntl = injectIntl(RelativeTimestamp);

export { RelativeTimestampWithIntl as RelativeTimestamp };

M app/javascript/mastodon/components/server_banner.jsx => app/javascript/mastodon/components/server_banner.jsx +1 -1
@@ 7,7 7,7 @@ import ShortNumber from 'mastodon/components/short_number';
import Skeleton from 'mastodon/components/skeleton';
import Account from 'mastodon/containers/account_container';
import { domain } from 'mastodon/initial_state';
import Image from 'mastodon/components/image';
import { Image } from 'mastodon/components/image';
import { Link } from 'react-router-dom';

const messages = defineMessages({

M app/javascript/mastodon/components/status.jsx => app/javascript/mastodon/components/status.jsx +4 -4
@@ 1,9 1,9 @@
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import Avatar from './avatar';
import AvatarOverlay from './avatar_overlay';
import RelativeTimestamp from './relative_timestamp';
import { Avatar } from './avatar';
import { AvatarOverlay } from './avatar_overlay';
import { RelativeTimestamp } from './relative_timestamp';
import DisplayName from './display_name';
import StatusContent from './status_content';
import StatusActionBar from './status_action_bar';


@@ 14,7 14,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { MediaGallery, Video, Audio } from '../features/ui/util/async-components';
import { HotKeys } from 'react-hotkeys';
import classNames from 'classnames';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import { displayMedia } from '../initial_state';
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';


M app/javascript/mastodon/components/status_action_bar.jsx => app/javascript/mastodon/components/status_action_bar.jsx +1 -1
@@ 2,7 2,7 @@ import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import IconButton from './icon_button';
import { IconButton } from './icon_button';
import DropdownMenuContainer from '../containers/dropdown_menu_container';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';

M app/javascript/mastodon/components/status_content.jsx => app/javascript/mastodon/components/status_content.jsx +1 -1
@@ 6,7 6,7 @@ import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import classnames from 'classnames';
import PollContainer from 'mastodon/containers/poll_container';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_state';

const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top)

M app/javascript/mastodon/components/verified_badge.tsx => app/javascript/mastodon/components/verified_badge.tsx +0 -2
@@ 10,5 10,3 @@ export const VerifiedBadge: React.FC<Props> = ({ link }) => (
    <span dangerouslySetInnerHTML={{ __html: link }} />
  </span>
);

export default VerifiedBadge;

M app/javascript/mastodon/features/about/index.jsx => app/javascript/mastodon/features/about/index.jsx +2 -2
@@ 9,9 9,9 @@ import { Helmet } from 'react-helmet';
import { fetchServer, fetchExtendedDescription, fetchDomainBlocks } from 'mastodon/actions/server';
import Account from 'mastodon/containers/account_container';
import Skeleton from 'mastodon/components/skeleton';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import classNames from 'classnames';
import Image from 'mastodon/components/image';
import { Image } from 'mastodon/components/image';

const messages = defineMessages({
  title: { id: 'column.about', defaultMessage: 'About' },

M app/javascript/mastodon/features/account/components/follow_request_note.jsx => app/javascript/mastodon/features/account/components/follow_request_note.jsx +1 -1
@@ 2,7 2,7 @@ import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';

export default class FollowRequestNote extends ImmutablePureComponent {


M app/javascript/mastodon/features/account/components/header.jsx => app/javascript/mastodon/features/account/components/header.jsx +3 -3
@@ 6,9 6,9 @@ import Button from 'mastodon/components/button';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { autoPlayGif, me, domain } from 'mastodon/initial_state';
import classNames from 'classnames';
import Icon from 'mastodon/components/icon';
import IconButton from 'mastodon/components/icon_button';
import Avatar from 'mastodon/components/avatar';
import { Icon }  from 'mastodon/components/icon';
import { IconButton } from 'mastodon/components/icon_button';
import { Avatar } from 'mastodon/components/avatar';
import { counterRenderer } from 'mastodon/components/common_counter';
import ShortNumber from 'mastodon/components/short_number';
import { NavLink } from 'react-router-dom';

M app/javascript/mastodon/features/account_gallery/components/media_item.jsx => app/javascript/mastodon/features/account_gallery/components/media_item.jsx +2 -2
@@ 1,6 1,6 @@
import Blurhash from 'mastodon/components/blurhash';
import { Blurhash } from 'mastodon/components/blurhash';
import classNames from 'classnames';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import { autoPlayGif, displayMedia, useBlurhash } from 'mastodon/initial_state';
import PropTypes from 'prop-types';
import React from 'react';

M app/javascript/mastodon/features/account_timeline/components/moved_note.jsx => app/javascript/mastodon/features/account_timeline/components/moved_note.jsx +1 -1
@@ 2,7 2,7 @@ import React from 'react';
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 { AvatarOverlay } from '../../../components/avatar_overlay';
import DisplayName from '../../../components/display_name';
import { Link } from 'react-router-dom';


M app/javascript/mastodon/features/audio/index.jsx => app/javascript/mastodon/features/audio/index.jsx +2 -2
@@ 2,12 2,12 @@ import React from 'react';
import PropTypes from 'prop-types';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import { formatTime, getPointerPosition, fileNameFromURL } from 'mastodon/features/video';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import classNames from 'classnames';
import { throttle, debounce } from 'lodash';
import Visualizer from './visualizer';
import { displayMedia, useBlurhash } from '../../initial_state';
import Blurhash from '../../components/blurhash';
import { Blurhash } from '../../components/blurhash';
import { is } from 'immutable';

const messages = defineMessages({

M app/javascript/mastodon/features/compose/components/autosuggest_account.jsx => app/javascript/mastodon/features/compose/components/autosuggest_account.jsx +1 -1
@@ 1,5 1,5 @@
import React from 'react';
import Avatar from '../../../components/avatar';
import { Avatar } from '../../../components/avatar';
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/compose_form.jsx => app/javascript/mastodon/features/compose/components/compose_form.jsx +1 -1
@@ 19,7 19,7 @@ import LanguageDropdown from '../containers/language_dropdown_container';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { length } from 'stringz';
import { countableText } from '../util/counter';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import classNames from 'classnames';
import { maxChars } from '../../../initial_state';


M app/javascript/mastodon/features/compose/components/navigation_bar.jsx => app/javascript/mastodon/features/compose/components/navigation_bar.jsx +2 -2
@@ 2,9 2,9 @@ import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ActionBar from './action_bar';
import Avatar from '../../../components/avatar';
import { Avatar } from '../../../components/avatar';
import { Link } from 'react-router-dom';
import IconButton from '../../../components/icon_button';
import { IconButton } from '../../../components/icon_button';
import { FormattedMessage } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';


M app/javascript/mastodon/features/compose/components/poll_button.jsx => app/javascript/mastodon/features/compose/components/poll_button.jsx +1 -1
@@ 1,5 1,5 @@
import React from 'react';
import IconButton from '../../../components/icon_button';
import { IconButton } from '../../../components/icon_button';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';


M app/javascript/mastodon/features/compose/components/poll_form.jsx => app/javascript/mastodon/features/compose/components/poll_form.jsx +2 -2
@@ 3,8 3,8 @@ import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import IconButton from 'mastodon/components/icon_button';
import Icon from 'mastodon/components/icon';
import { IconButton } from 'mastodon/components/icon_button';
import { Icon }  from 'mastodon/components/icon';
import AutosuggestInput from 'mastodon/components/autosuggest_input';
import classNames from 'classnames';


M app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx => app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx +2 -2
@@ 1,11 1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import { injectIntl, defineMessages } from 'react-intl';
import IconButton from '../../../components/icon_button';
import { IconButton } from '../../../components/icon_button';
import Overlay from 'react-overlays/Overlay';
import { supportsPassiveEvents } from 'detect-passive-events';
import classNames from 'classnames';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';

const messages = defineMessages({
  public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },

M app/javascript/mastodon/features/compose/components/reply_indicator.jsx => app/javascript/mastodon/features/compose/components/reply_indicator.jsx +2 -2
@@ 1,8 1,8 @@
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import Avatar from '../../../components/avatar';
import IconButton from '../../../components/icon_button';
import { Avatar } from '../../../components/avatar';
import { IconButton } from '../../../components/icon_button';
import DisplayName from '../../../components/display_name';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';

M app/javascript/mastodon/features/compose/components/search.jsx => app/javascript/mastodon/features/compose/components/search.jsx +1 -1
@@ 3,7 3,7 @@ import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { searchEnabled } from 'mastodon/initial_state';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import classNames from 'classnames';
import { HASHTAG_REGEX } from 'mastodon/utils/hashtags';


M app/javascript/mastodon/features/compose/components/search_results.jsx => app/javascript/mastodon/features/compose/components/search_results.jsx +1 -1
@@ 6,7 6,7 @@ import AccountContainer from '../../../containers/account_container';
import StatusContainer from '../../../containers/status_container';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { ImmutableHashtag as Hashtag } from '../../../components/hashtag';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import { searchEnabled } from '../../../initial_state';
import LoadMore from 'mastodon/components/load_more';


M app/javascript/mastodon/features/compose/components/upload.jsx => app/javascript/mastodon/features/compose/components/upload.jsx +1 -1
@@ 5,7 5,7 @@ import Motion from '../../ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { FormattedMessage } from 'react-intl';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';

export default class Upload extends ImmutablePureComponent {


M app/javascript/mastodon/features/compose/components/upload_button.jsx => app/javascript/mastodon/features/compose/components/upload_button.jsx +1 -1
@@ 1,5 1,5 @@
import React from 'react';
import IconButton from '../../../components/icon_button';
import { IconButton } from '../../../components/icon_button';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';
import { connect } from 'react-redux';

M app/javascript/mastodon/features/compose/components/upload_progress.jsx => app/javascript/mastodon/features/compose/components/upload_progress.jsx +1 -1
@@ 2,7 2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import Motion from '../../ui/util/optional_motion';
import spring from 'react-motion/lib/spring';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import { FormattedMessage } from 'react-intl';

export default class UploadProgress extends React.PureComponent {

M app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js => app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js +1 -0
@@ 72,6 72,7 @@ const mapDispatchToProps = (dispatch, { onPickEmoji }) => ({
  },

  onPickEmoji: emoji => {
    // eslint-disable-next-line react-hooks/rules-of-hooks -- this is not a react hook
    dispatch(useEmoji(emoji));

    if (onPickEmoji) {

M app/javascript/mastodon/features/compose/containers/language_dropdown_container.js => app/javascript/mastodon/features/compose/containers/language_dropdown_container.js +1 -0
@@ 26,6 26,7 @@ const mapDispatchToProps = dispatch => ({
  },

  onClose (value) {
    // eslint-disable-next-line react-hooks/rules-of-hooks -- this is not a react hook
    dispatch(useLanguage(value));
  },


M app/javascript/mastodon/features/compose/index.jsx => app/javascript/mastodon/features/compose/index.jsx +1 -1
@@ 14,7 14,7 @@ import SearchResultsContainer from './containers/search_results_container';
import { openModal } from 'mastodon/actions/modal';
import elephantUIPlane from '../../../images/elephant_ui_plane.svg';
import { mascot } from '../../initial_state';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import { logOut } from 'mastodon/utils/log_out';
import Column from 'mastodon/components/column';
import { Helmet } from 'react-helmet';

M app/javascript/mastodon/features/direct_timeline/components/conversation.jsx => app/javascript/mastodon/features/direct_timeline/components/conversation.jsx +2 -2
@@ 8,8 8,8 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container';
import AvatarComposite from 'mastodon/components/avatar_composite';
import { Link } from 'react-router-dom';
import IconButton from 'mastodon/components/icon_button';
import RelativeTimestamp from 'mastodon/components/relative_timestamp';
import { IconButton } from 'mastodon/components/icon_button';
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
import { HotKeys } from 'react-hotkeys';
import { autoPlayGif } from 'mastodon/initial_state';
import classNames from 'classnames';

M app/javascript/mastodon/features/directory/components/account_card.jsx => app/javascript/mastodon/features/directory/components/account_card.jsx +1 -1
@@ 4,7 4,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { makeGetAccount } from 'mastodon/selectors';
import Avatar from 'mastodon/components/avatar';
import { Avatar } from 'mastodon/components/avatar';
import DisplayName from 'mastodon/components/display_name';
import { Link } from 'react-router-dom';
import Button from 'mastodon/components/button';

M app/javascript/mastodon/features/directory/index.jsx => app/javascript/mastodon/features/directory/index.jsx +1 -1
@@ 9,7 9,7 @@ import { addColumn, removeColumn, moveColumn, changeColumnParams } from 'mastodo
import { fetchDirectory, expandDirectory } from 'mastodon/actions/directory';
import { List as ImmutableList } from 'immutable';
import AccountCard from './components/account_card';
import RadioButton from 'mastodon/components/radio_button';
import { RadioButton } from 'mastodon/components/radio_button';
import LoadMore from 'mastodon/components/load_more';
import ScrollContainer from 'mastodon/containers/scroll_container';
import LoadingIndicator from 'mastodon/components/loading_indicator';

M app/javascript/mastodon/features/emoji/emoji_compressed.js => app/javascript/mastodon/features/emoji/emoji_compressed.js +2 -0
@@ 1,3 1,5 @@
/* eslint-disable import/no-commonjs --
   We need to use CommonJS here due to preval */
// @preval
// http://www.unicode.org/Public/emoji/5.0/emoji-test.txt
// This file contains the compressed version of the emoji data from

M app/javascript/mastodon/features/emoji/emoji_mart_data_light.js => app/javascript/mastodon/features/emoji/emoji_mart_data_light.js +5 -3
@@ 1,8 1,10 @@
// The output of this module is designed to mimic emoji-mart's
// "data" object, such that we can use it for a light version of emoji-mart's
// emojiIndex.search functionality.
const { unicodeToUnifiedName } = require('./unicode_to_unified_name');
const [ shortCodesToEmojiData, skins, categories, short_names ] = require('./emoji_compressed');
import { unicodeToUnifiedName } from './unicode_to_unified_name';
import emojiCompressed from './emoji_compressed';

const [ shortCodesToEmojiData, skins, categories, short_names ] = emojiCompressed;

const emojis = {};



@@ 33,7 35,7 @@ Object.keys(shortCodesToEmojiData).forEach((shortCode) => {
  };
});

module.exports = {
export {
  emojis,
  skins,
  categories,

M app/javascript/mastodon/features/emoji/emoji_mart_search_light.js => app/javascript/mastodon/features/emoji/emoji_mart_search_light.js +1 -1
@@ 1,7 1,7 @@
// This code is largely borrowed from:
// https://github.com/missive/emoji-mart/blob/5f2ffcc/src/utils/emoji-index.js

import data from './emoji_mart_data_light';
import * as data from './emoji_mart_data_light';
import { getData, getSanitizedData, uniq, intersect } from './emoji_utils';

let originalPool = {};

M app/javascript/mastodon/features/emoji/emoji_unicode_mapping_light.js => app/javascript/mastodon/features/emoji/emoji_unicode_mapping_light.js +9 -6
@@ 2,14 2,17 @@
// (i.e. the svg filename) and a shortCode intended to be shown
// as a "title" attribute in an HTML element (aka tooltip).

import emojiCompressed from './emoji_compressed';

import { unicodeToFilename } from './unicode_to_filename';

const [
  shortCodesToEmojiData,
  skins, // eslint-disable-line @typescript-eslint/no-unused-vars
  categories, // eslint-disable-line @typescript-eslint/no-unused-vars
  short_names, // eslint-disable-line @typescript-eslint/no-unused-vars
  _skins,
  _categories,
  _short_names,
  emojisWithoutShortCodes,
] = require('./emoji_compressed');
const { unicodeToFilename } = require('./unicode_to_filename');
] = emojiCompressed;

// decompress
const unicodeMapping = {};


@@ 32,4 35,4 @@ Object.keys(shortCodesToEmojiData).forEach((shortCode) => {
});
emojisWithoutShortCodes.forEach(emojiMapData => processEmojiMapData(emojiMapData));

module.exports = unicodeMapping;
export default unicodeMapping;

M app/javascript/mastodon/features/emoji/emoji_utils.js => app/javascript/mastodon/features/emoji/emoji_utils.js +1 -1
@@ 1,7 1,7 @@
// This code is largely borrowed from:
// https://github.com/missive/emoji-mart/blob/5f2ffcc/src/utils/index.js

import data from './emoji_mart_data_light';
import * as data from './emoji_mart_data_light';

const buildSearch = (data) => {
  const search = [];

M app/javascript/mastodon/features/emoji/unicode_to_filename.js => app/javascript/mastodon/features/emoji/unicode_to_filename.js +3 -0
@@ 1,3 1,6 @@
/* eslint-disable import/no-commonjs --
   We need to use CommonJS here as its imported into a preval file (`emoji_compressed.js`) */

// taken from:
// https://github.com/twitter/twemoji/blob/47732c7/twemoji-generator.js#L848-L866
exports.unicodeToFilename = (str) => {

M app/javascript/mastodon/features/emoji/unicode_to_unified_name.js => app/javascript/mastodon/features/emoji/unicode_to_unified_name.js +3 -0
@@ 1,3 1,6 @@
/* eslint-disable import/no-commonjs --
   We need to use CommonJS here as its imported into a preval file (`emoji_compressed.js`) */

function padLeft(str, num) {
  while (str.length < num) {
    str = '0' + str;

M app/javascript/mastodon/features/explore/components/story.jsx => app/javascript/mastodon/features/explore/components/story.jsx +1 -1
@@ 1,6 1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import Blurhash from 'mastodon/components/blurhash';
import { Blurhash } from 'mastodon/components/blurhash';
import { accountsCountRenderer } from 'mastodon/components/hashtag';
import ShortNumber from 'mastodon/components/short_number';
import Skeleton from 'mastodon/components/skeleton';

M app/javascript/mastodon/features/favourites/index.jsx => app/javascript/mastodon/features/favourites/index.jsx +1 -1
@@ 5,7 5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { connect } from 'react-redux';
import ColumnHeader from 'mastodon/components/column_header';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import { fetchFavourites } from 'mastodon/actions/interactions';
import LoadingIndicator from 'mastodon/components/loading_indicator';
import ScrollableList from 'mastodon/components/scrollable_list';

M app/javascript/mastodon/features/filters/select_filter.jsx => app/javascript/mastodon/features/filters/select_filter.jsx +1 -1
@@ 4,7 4,7 @@ import { connect } from 'react-redux';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { toServerSideType } from 'mastodon/utils/filters';
import { loupeIcon, deleteIcon } from 'mastodon/utils/icons';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import fuzzysort from 'fuzzysort';

const messages = defineMessages({

M app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx => app/javascript/mastodon/features/follow_requests/components/account_authorize.jsx +2 -2
@@ 2,9 2,9 @@ import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { Link } from 'react-router-dom';
import Avatar from '../../../components/avatar';
import { Avatar } from '../../../components/avatar';
import DisplayName from '../../../components/display_name';
import IconButton from '../../../components/icon_button';
import { IconButton } from '../../../components/icon_button';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';


M app/javascript/mastodon/features/getting_started/components/announcements.jsx => app/javascript/mastodon/features/getting_started/components/announcements.jsx +3 -3
@@ 3,15 3,15 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import ReactSwipeableViews from 'react-swipeable-views';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import IconButton from 'mastodon/components/icon_button';
import Icon from 'mastodon/components/icon';
import { IconButton } from 'mastodon/components/icon_button';
import { Icon }  from 'mastodon/components/icon';
import { defineMessages, injectIntl, FormattedMessage, FormattedDate } from 'react-intl';
import { autoPlayGif, reduceMotion, disableSwiping, mascot } from 'mastodon/initial_state';
import elephantUIPlane from 'mastodon/../images/elephant_ui_plane.svg';
import unicodeMapping from 'mastodon/features/emoji/emoji_unicode_mapping_light';
import classNames from 'classnames';
import EmojiPickerDropdown from 'mastodon/features/compose/containers/emoji_picker_dropdown_container';
import AnimatedNumber from 'mastodon/components/animated_number';
import { AnimatedNumber } from 'mastodon/components/animated_number';
import TransitionMotion from 'react-motion/lib/TransitionMotion';
import spring from 'react-motion/lib/spring';
import { assetHost } from 'mastodon/utils/config';

M app/javascript/mastodon/features/hashtag_timeline/index.jsx => app/javascript/mastodon/features/hashtag_timeline/index.jsx +1 -1
@@ 12,7 12,7 @@ import { injectIntl, FormattedMessage, defineMessages } from 'react-intl';
import { connectHashtagStream } from 'mastodon/actions/streaming';
import { isEqual } from 'lodash';
import { fetchHashtag, followHashtag, unfollowHashtag } from 'mastodon/actions/tags';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import classNames from 'classnames';
import { Helmet } from 'react-helmet';


M app/javascript/mastodon/features/home_timeline/index.jsx => app/javascript/mastodon/features/home_timeline/index.jsx +2 -2
@@ 12,8 12,8 @@ import { Link } from 'react-router-dom';
import { fetchAnnouncements, toggleShowAnnouncements } from 'mastodon/actions/announcements';
import AnnouncementsContainer from 'mastodon/features/getting_started/containers/announcements_container';
import classNames from 'classnames';
import IconWithBadge from 'mastodon/components/icon_with_badge';
import NotSignedInIndicator from 'mastodon/components/not_signed_in_indicator';
import { IconWithBadge } from 'mastodon/components/icon_with_badge';
import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator';
import { Helmet } from 'react-helmet';

const messages = defineMessages({

M app/javascript/mastodon/features/interaction_modal/index.jsx => app/javascript/mastodon/features/interaction_modal/index.jsx +1 -1
@@ 3,7 3,7 @@ import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { registrationsOpen } from 'mastodon/initial_state';
import { connect } from 'react-redux';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import classNames from 'classnames';
import { openModal, closeModal } from 'mastodon/actions/modal';


M app/javascript/mastodon/features/list_adder/components/account.jsx => app/javascript/mastodon/features/list_adder/components/account.jsx +1 -1
@@ 3,7 3,7 @@ import { connect } from 'react-redux';
import { makeGetAccount } from '../../../selectors';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes';
import Avatar from '../../../components/avatar';
import { Avatar } from '../../../components/avatar';
import DisplayName from '../../../components/display_name';
import { injectIntl } from 'react-intl';


M app/javascript/mastodon/features/list_adder/components/list.jsx => app/javascript/mastodon/features/list_adder/components/list.jsx +2 -2
@@ 3,10 3,10 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes';
import IconButton from '../../../components/icon_button';
import { IconButton }  from '../../../components/icon_button';
import { defineMessages, injectIntl } from 'react-intl';
import { removeFromListAdder, addToListAdder } from '../../../actions/lists';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';

const messages = defineMessages({
  remove: { id: 'lists.account.remove', defaultMessage: 'Remove from list' },

M app/javascript/mastodon/features/list_editor/components/account.jsx => app/javascript/mastodon/features/list_editor/components/account.jsx +2 -2
@@ 4,9 4,9 @@ import { connect } from 'react-redux';
import { makeGetAccount } from '../../../selectors';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes';
import Avatar from '../../../components/avatar';
import { Avatar } from '../../../components/avatar';
import DisplayName from '../../../components/display_name';
import IconButton from '../../../components/icon_button';
import { IconButton } from '../../../components/icon_button';
import { defineMessages, injectIntl } from 'react-intl';
import { removeFromListEditor, addToListEditor } from '../../../actions/lists';


M app/javascript/mastodon/features/list_editor/components/edit_list_form.jsx => app/javascript/mastodon/features/list_editor/components/edit_list_form.jsx +1 -1
@@ 2,7 2,7 @@ import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { changeListEditorTitle, submitListEditor } from '../../../actions/lists';
import IconButton from '../../../components/icon_button';
import { IconButton } from '../../../components/icon_button';
import { defineMessages, injectIntl } from 'react-intl';

const messages = defineMessages({

M app/javascript/mastodon/features/list_editor/components/search.jsx => app/javascript/mastodon/features/list_editor/components/search.jsx +1 -1
@@ 4,7 4,7 @@ import { connect } from 'react-redux';
import { defineMessages, injectIntl } from 'react-intl';
import { fetchListSuggestions, clearListSuggestions, changeListSuggestions } from '../../../actions/lists';
import classNames from 'classnames';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';

const messages = defineMessages({
  search: { id: 'lists.search', defaultMessage: 'Search among people you follow' },

M app/javascript/mastodon/features/list_timeline/index.jsx => app/javascript/mastodon/features/list_timeline/index.jsx +2 -2
@@ 11,9 11,9 @@ import { connectListStream } from 'mastodon/actions/streaming';
import { expandListTimeline } from 'mastodon/actions/timelines';
import Column from 'mastodon/components/column';
import ColumnHeader from 'mastodon/components/column_header';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import LoadingIndicator from 'mastodon/components/loading_indicator';
import RadioButton from 'mastodon/components/radio_button';
import { RadioButton } from 'mastodon/components/radio_button';
import StatusListContainer from 'mastodon/features/ui/containers/status_list_container';
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';


M app/javascript/mastodon/features/notifications/components/clear_column_button.jsx => app/javascript/mastodon/features/notifications/components/clear_column_button.jsx +1 -1
@@ 1,7 1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';

export default class ClearColumnButton extends React.PureComponent {


M app/javascript/mastodon/features/notifications/components/filter_bar.jsx => app/javascript/mastodon/features/notifications/components/filter_bar.jsx +1 -1
@@ 1,7 1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';

const tooltips = defineMessages({
  mentions: { id: 'notifications.filter.mentions', defaultMessage: 'Mentions' },

M app/javascript/mastodon/features/notifications/components/follow_request.jsx => app/javascript/mastodon/features/notifications/components/follow_request.jsx +2 -2
@@ 1,10 1,10 @@
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import Avatar from 'mastodon/components/avatar';
import { Avatar } from 'mastodon/components/avatar';
import DisplayName from 'mastodon/components/display_name';
import { Link } from 'react-router-dom';
import IconButton from 'mastodon/components/icon_button';
import { IconButton } from 'mastodon/components/icon_button';
import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';


M app/javascript/mastodon/features/notifications/components/notification.jsx => app/javascript/mastodon/features/notifications/components/notification.jsx +1 -1
@@ 9,7 9,7 @@ import StatusContainer from 'mastodon/containers/status_container';
import AccountContainer from 'mastodon/containers/account_container';
import Report from './report';
import FollowRequestContainer from '../containers/follow_request_container';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import { Link } from 'react-router-dom';
import classNames from 'classnames';


M app/javascript/mastodon/features/notifications/components/notifications_permission_banner.jsx => app/javascript/mastodon/features/notifications/components/notifications_permission_banner.jsx +2 -2
@@ 1,7 1,7 @@
import React from 'react';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import Button from 'mastodon/components/button';
import IconButton from 'mastodon/components/icon_button';
import { IconButton } from 'mastodon/components/icon_button';
import { requestBrowserPermission } from 'mastodon/actions/notifications';
import { changeSetting } from 'mastodon/actions/settings';
import { connect } from 'react-redux';

M app/javascript/mastodon/features/notifications/components/report.jsx => app/javascript/mastodon/features/notifications/components/report.jsx +2 -2
@@ 3,8 3,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import AvatarOverlay from 'mastodon/components/avatar_overlay';
import RelativeTimestamp from 'mastodon/components/relative_timestamp';
import { AvatarOverlay } from 'mastodon/components/avatar_overlay';
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';

const messages = defineMessages({
  openReport: { id: 'report_notification.open', defaultMessage: 'Open report' },

M app/javascript/mastodon/features/notifications/index.jsx => app/javascript/mastodon/features/notifications/index.jsx +3 -3
@@ 23,10 23,10 @@ import { List as ImmutableList } from 'immutable';
import { debounce } from 'lodash';
import ScrollableList from '../../components/scrollable_list';
import LoadGap from '../../components/load_gap';
import Icon from 'mastodon/components/icon';
import compareId from 'mastodon/compare_id';
import { Icon }  from 'mastodon/components/icon';
import { compareId } from 'mastodon/compare_id';
import NotificationsPermissionBanner from './components/notifications_permission_banner';
import NotSignedInIndicator from 'mastodon/components/not_signed_in_indicator';
import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator';
import { Helmet } from 'react-helmet';

const messages = defineMessages({

M app/javascript/mastodon/features/onboarding/components/progress_indicator.jsx => app/javascript/mastodon/features/onboarding/components/progress_indicator.jsx +2 -2
@@ 1,6 1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import Check from 'mastodon/components/check';
import { Check } from 'mastodon/components/check';
import classNames from 'classnames';

const ProgressIndicator = ({ steps, completed }) => (


@@ 22,4 22,4 @@ ProgressIndicator.propTypes = {
  completed: PropTypes.number,
};

export default ProgressIndicator;
\ No newline at end of file
export default ProgressIndicator;

M app/javascript/mastodon/features/onboarding/components/step.jsx => app/javascript/mastodon/features/onboarding/components/step.jsx +3 -3
@@ 1,7 1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import Icon from 'mastodon/components/icon';
import Check from 'mastodon/components/check';
import { Icon }  from 'mastodon/components/icon';
import { Check } from 'mastodon/components/check';

const Step = ({ label, description, icon, completed, onClick, href }) => {
  const content = (


@@ 47,4 47,4 @@ Step.propTypes = {
  onClick: PropTypes.func,
};

export default Step;
\ No newline at end of file
export default Step;

M app/javascript/mastodon/features/onboarding/share.jsx => app/javascript/mastodon/features/onboarding/share.jsx +2 -2
@@ 7,7 7,7 @@ import { connect } from 'react-redux';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { defineMessages, injectIntl, FormattedMessage, FormattedHTMLMessage } from 'react-intl';
import classNames from 'classnames';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import ArrowSmallRight from './components/arrow_small_right';
import { Link } from 'react-router-dom';
import SwipeableViews from 'react-swipeable-views';


@@ 190,4 190,4 @@ class Share extends React.PureComponent {

}

export default connect(mapStateToProps)(injectIntl(Share));
\ No newline at end of file
export default connect(mapStateToProps)(injectIntl(Share));

M app/javascript/mastodon/features/picture_in_picture/components/footer.jsx => app/javascript/mastodon/features/picture_in_picture/components/footer.jsx +1 -1
@@ 3,7 3,7 @@ import { connect } from 'react-redux';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import IconButton from 'mastodon/components/icon_button';
import { IconButton } from 'mastodon/components/icon_button';
import classNames from 'classnames';
import { me, boostModal } from 'mastodon/initial_state';
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 +2 -2
@@ 3,9 3,9 @@ import { connect } from 'react-redux';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import IconButton from 'mastodon/components/icon_button';
import { IconButton } from 'mastodon/components/icon_button';
import { Link } from 'react-router-dom';
import Avatar from 'mastodon/components/avatar';
import { Avatar } from 'mastodon/components/avatar';
import DisplayName from 'mastodon/components/display_name';
import { defineMessages, injectIntl } from 'react-intl';


M app/javascript/mastodon/features/reblogs/index.jsx => app/javascript/mastodon/features/reblogs/index.jsx +1 -1
@@ 9,7 9,7 @@ import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import AccountContainer from '../../containers/account_container';
import Column from '../ui/components/column';
import ScrollableList from '../../components/scrollable_list';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import ColumnHeader from '../../components/column_header';
import { Helmet } from 'react-helmet';


M app/javascript/mastodon/features/report/components/option.jsx => app/javascript/mastodon/features/report/components/option.jsx +1 -1
@@ 1,7 1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import Check from 'mastodon/components/check';
import { Check } from 'mastodon/components/check';

export default class Option extends React.PureComponent {


M app/javascript/mastodon/features/report/components/status_check_box.jsx => app/javascript/mastodon/features/report/components/status_check_box.jsx +3 -3
@@ 2,13 2,13 @@ import React from 'react';
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 { Avatar } from 'mastodon/components/avatar';
import DisplayName from 'mastodon/components/display_name';
import RelativeTimestamp from 'mastodon/components/relative_timestamp';
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
import Option from './option';
import MediaAttachments from 'mastodon/components/media_attachments';
import { injectIntl, defineMessages } from 'react-intl';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';

const messages = defineMessages({
  public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },

M app/javascript/mastodon/features/status/components/action_bar.jsx => app/javascript/mastodon/features/status/components/action_bar.jsx +1 -1
@@ 1,7 1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import IconButton from '../../../components/icon_button';
import { IconButton } from '../../../components/icon_button';
import ImmutablePropTypes from 'react-immutable-proptypes';
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
import { defineMessages, injectIntl } from 'react-intl';

M app/javascript/mastodon/features/status/components/card.jsx => app/javascript/mastodon/features/status/components/card.jsx +2 -2
@@ 5,9 5,9 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { FormattedMessage } from 'react-intl';
import punycode from 'punycode';
import classnames from 'classnames';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import { useBlurhash } from 'mastodon/initial_state';
import Blurhash from 'mastodon/components/blurhash';
import { Blurhash } from 'mastodon/components/blurhash';

const IDNA_PREFIX = 'xn--';


M app/javascript/mastodon/features/status/components/detailed_status.jsx => app/javascript/mastodon/features/status/components/detailed_status.jsx +3 -3
@@ 1,7 1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import Avatar from '../../../components/avatar';
import { Avatar } from '../../../components/avatar';
import DisplayName from '../../../components/display_name';
import StatusContent from '../../../components/status_content';
import MediaGallery from '../../../components/media_gallery';


@@ 13,8 13,8 @@ import Video from '../../video';
import Audio from '../../audio';
import scheduleIdleTask from '../../ui/util/schedule_idle_task';
import classNames from 'classnames';
import Icon from 'mastodon/components/icon';
import AnimatedNumber from 'mastodon/components/animated_number';
import { Icon }  from 'mastodon/components/icon';
import { AnimatedNumber } from 'mastodon/components/animated_number';
import PictureInPicturePlaceholder from 'mastodon/components/picture_in_picture_placeholder';
import EditedTimestamp from 'mastodon/components/edited_timestamp';


M app/javascript/mastodon/features/status/index.jsx => app/javascript/mastodon/features/status/index.jsx +1 -1
@@ 58,7 58,7 @@ import { HotKeys } from 'react-hotkeys';
import { boostModal, deleteModal } from '../../initial_state';
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen';
import { textForScreenReader, defaultMediaVisibility } from '../../components/status';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import { Helmet } from 'react-helmet';
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';


M app/javascript/mastodon/features/subscribed_languages_modal/index.jsx => app/javascript/mastodon/features/subscribed_languages_modal/index.jsx +1 -1
@@ 8,7 8,7 @@ import { is, List as ImmutableList, Set as ImmutableSet } from 'immutable';
import { languages as preloadedLanguages } from 'mastodon/initial_state';
import Option from 'mastodon/features/report/components/option';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import IconButton from 'mastodon/components/icon_button';
import { IconButton } from 'mastodon/components/icon_button';
import Button from 'mastodon/components/button';
import { followAccount } from 'mastodon/actions/accounts';


M app/javascript/mastodon/features/ui/components/actions_modal.jsx => app/javascript/mastodon/features/ui/components/actions_modal.jsx +1 -1
@@ 2,7 2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import IconButton from '../../../components/icon_button';
import { IconButton } from '../../../components/icon_button';
import classNames from 'classnames';

export default class ActionsModal extends ImmutablePureComponent {

M app/javascript/mastodon/features/ui/components/boost_modal.jsx => app/javascript/mastodon/features/ui/components/boost_modal.jsx +3 -3
@@ 5,11 5,11 @@ import PropTypes from 'prop-types';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import Button from '../../../components/button';
import StatusContent from '../../../components/status_content';
import Avatar from '../../../components/avatar';
import RelativeTimestamp from '../../../components/relative_timestamp';
import { Avatar } from '../../../components/avatar';
import { RelativeTimestamp } from '../../../components/relative_timestamp';
import DisplayName from '../../../components/display_name';
import ImmutablePureComponent from 'react-immutable-pure-component';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import AttachmentList from 'mastodon/components/attachment_list';
import PrivacyDropdown from 'mastodon/features/compose/components/privacy_dropdown';
import classNames from 'classnames';

M app/javascript/mastodon/features/ui/components/bundle_modal_error.jsx => app/javascript/mastodon/features/ui/components/bundle_modal_error.jsx +1 -1
@@ 2,7 2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';

import IconButton from '../../../components/icon_button';
import { IconButton } from '../../../components/icon_button';

const messages = defineMessages({
  error: { id: 'bundle_modal_error.message', defaultMessage: 'Something went wrong while loading this component.' },

M app/javascript/mastodon/features/ui/components/column_header.jsx => app/javascript/mastodon/features/ui/components/column_header.jsx +1 -1
@@ 1,7 1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';

export default class ColumnHeader extends React.PureComponent {


M app/javascript/mastodon/features/ui/components/column_link.jsx => app/javascript/mastodon/features/ui/components/column_link.jsx +1 -1
@@ 1,7 1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { NavLink } from 'react-router-dom';
import Icon from 'mastodon/components/icon';
import { Icon }  from 'mastodon/components/icon';
import classNames from 'classnames';

const ColumnLink = ({ icon, text, to, href, method, badge, transparent, ...other }) => {

M app/javascript/mastodon/features/ui/components/compare_history_modal.jsx => app/javascript/mastodon/features/ui/components/compare_history_modal.jsx +2 -2
@@ 7,8 7,8 @@ import { closeModal } from 'mastodon/actions/modal';
import emojify from 'mastodon/features/emoji/emoji';
import escapeTextContentForBrowser from 'escape-html';
import InlineAccount from 'mastodon/components/inline_account';
import IconButton from 'mastodon/components/icon_button';
import RelativeTimestamp from 'mastodon/components/relative_timestamp';
import { IconButton } from 'mastodon/components/icon_button';
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
import MediaAttachments from 'mastodon/components/media_attachments';

const mapStateToProps = (state, { statusId }) => ({

M app/javascript/mastodon/features/ui/components/embed_modal.jsx => app/javascript/mastodon/features/ui/components/embed_modal.jsx +1 -1
@@ 3,7 3,7 @@ import PropTypes from 'prop-types';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import api from 'mastodon/api';
import IconButton from 'mastodon/components/icon_button';
import { IconButton } from 'mastodon/components/icon_button';

const messages = defineMessages({
  close: { id: 'lightbox.close', defaultMessage: 'Close' },

M app/javascript/mastodon/features/ui/components/filter_modal.jsx => app/javascript/mastodon/features/ui/components/filter_modal.jsx +1 -1
@@ 5,7 5,7 @@ import { fetchFilters, createFilter, createFilterStatus } from 'mastodon/actions
import PropTypes from 'prop-types';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component';
import IconButton from 'mastodon/components/icon_button';
import { IconButton } from 'mastodon/components/icon_button';
import SelectFilter from 'mastodon/features/filters/select_filter';
import AddedToFilter from 'mastodon/features/filters/added_to_filter';


M app/javascript/mastodon/features/ui/components/focal_point_modal.jsx => app/javascript/mastodon/features/ui/components/focal_point_modal.jsx +2 -2
@@ 7,7 7,7 @@ import classNames from 'classnames';
import { changeUploadCompose, uploadThumbnail, onChangeMediaDescription, onChangeMediaFocus } from '../../../actions/compose';
import { getPointerPosition } from '../../video';
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
import IconButton from 'mastodon/components/icon_button';
import { IconButton } from 'mastodon/components/icon_button';
import Button from 'mastodon/components/button';
import Video from 'mastodon/features/video';
import Audio from 'mastodon/features/audio';


@@ 16,7 16,7 @@ import UploadProgress from 'mastodon/features/compose/components/upload_progress
import CharacterCounter from 'mastodon/features/compose/components/character_counter';
import { length } from 'stringz';
import { Tesseract as fetchTesseract } from 'mastodon/features/ui/util/async-components';
import GIFV from 'mastodon/components/gifv';
import { GIFV } from 'mastodon/components/gifv';
import { me } from 'mastodon/initial_state';
// eslint-disable-next-line import/no-extraneous-dependencies
import tesseractCorePath from 'tesseract.js-core/tesseract-core.wasm.js';

M app/javascript/mastodon/features/ui/components/follow_requests_column_link.jsx => app/javascript/mastodon/features/ui/components/follow_requests_column_link.jsx +1 -1
@@ 3,7 3,7 @@ import PropTypes from 'prop-types';
import { fetchFollowRequests } from 'mastodon/actions/accounts';
import { connect } from 'react-redux';
import ColumnLink from 'mastodon/features/ui/components/column_link';
import IconWithBadge from 'mastodon/components/icon_with_badge';
import { IconWithBadge } from 'mastodon/components/icon_with_badge';
import { List as ImmutableList } from 'immutable';
import { injectIntl, defineMessages } from 'react-intl';


M app/javascript/mastodon/features/ui/components/header.jsx => app/javascript/mastodon/features/ui/components/header.jsx +1 -1
@@ 3,7 3,7 @@ import { WordmarkLogo, SymbolLogo } from 'mastodon/components/logo';
import { Link, withRouter } from 'react-router-dom';
import { FormattedMessage } from 'react-intl';
import { registrationsOpen, me } from 'mastodon/initial_state';
import Avatar from 'mastodon/components/avatar';
import { Avatar } from 'mastodon/components/avatar';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { openModal } from 'mastodon/actions/modal';

M app/javascript/mastodon/features/ui/components/image_modal.jsx => app/javascript/mastodon/features/ui/components/image_modal.jsx +1 -1
@@ 2,7 2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { defineMessages, injectIntl } from 'react-intl';
import IconButton from 'mastodon/components/icon_button';
import { IconButton } from 'mastodon/components/icon_button';
import ImageLoader from './image_loader';

const messages = defineMessages({

M app/javascript/mastodon/features/ui/components/media_modal.jsx => app/javascript/mastodon/features/ui/components/media_modal.jsx +3 -3
@@ 6,11 6,11 @@ import Video from 'mastodon/features/video';
import { connect } from 'react-redux';
import classNames from 'classnames';
import { defineMessages, injectIntl } from 'react-intl';
import IconButton from 'mastodon/components/icon_button';
import { IconButton } from 'mastodon/components/icon_button';
import ImmutablePureComponent from 'react-immutable-pure-component';
import ImageLoader from './image_loader';
import Icon from 'mastodon/components/icon';
import GIFV from 'mastodon/components/gifv';
import { Icon }  from 'mastodon/components/icon';
import { GIFV } from 'mastodon/components/gifv';
import { disableSwiping } from 'mastodon/initial_state';
import Footer from 'mastodon/features/picture_in_picture/components/footer';
import { getAverageFromBlurhash } from 'mastodon/blurhash';

M app/javascript/mastodon/features/ui/components/notifications_counter_icon.js => app/javascript/mastodon/features/ui/components/notifications_counter_icon.js +1 -1
@@ 1,5 1,5 @@
import { connect } from 'react-redux';
import IconWithBadge from 'mastodon/components/icon_with_badge';
import { IconWithBadge } from 'mastodon/components/icon_with_badge';

const mapStateToProps = state => ({
  count: state.getIn(['notifications', 'unread']),

M app/javascript/mastodon/features/ui/components/report_modal.jsx => app/javascript/mastodon/features/ui/components/report_modal.jsx +1 -1
@@ 9,7 9,7 @@ import { makeGetAccount } from 'mastodon/selectors';
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
import { OrderedSet } from 'immutable';
import ImmutablePureComponent from 'react-immutable-pure-component';
import IconButton from 'mastodon/components/icon_button';
import { IconButton } from 'mastodon/components/icon_button';
import Category from 'mastodon/features/report/category';
import Statuses from 'mastodon/features/report/statuses';
import Rules from 'mastodon/features/report/rules';

M app/javascript/mastodon/features/ui/components/zoomable_image.jsx => app/javascript/mastodon/features/ui/components/zoomable_image.jsx +1 -1
@@ 1,6 1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
import IconButton from 'mastodon/components/icon_button';
import { IconButton } from 'mastodon/components/icon_button';
import { defineMessages, injectIntl } from 'react-intl';

const messages = defineMessages({

M app/javascript/mastodon/features/video/index.jsx => app/javascript/mastodon/features/video/index.jsx +2 -2
@@ 6,8 6,8 @@ import { throttle } from 'lodash';
import classNames from 'classnames';
import { isFullscreen, requestFullscreen, exitFullscreen } from '../ui/util/fullscreen';
import { displayMedia, useBlurhash } from '../../initial_state';
import Icon from 'mastodon/components/icon';
import Blurhash from 'mastodon/components/blurhash';
import { Icon }  from 'mastodon/components/icon';
import { Blurhash } from 'mastodon/components/blurhash';

const messages = defineMessages({
  play: { id: 'video.play', defaultMessage: 'Play' },

M app/javascript/mastodon/main.jsx => app/javascript/mastodon/main.jsx +1 -2
@@ 5,8 5,7 @@ import Mastodon from 'mastodon/containers/mastodon';
import { store } from 'mastodon/store/configureStore';
import { me } from 'mastodon/initial_state';
import ready from 'mastodon/ready';

const perf = require('mastodon/performance');
import * as perf from 'mastodon/performance';

/**
 * @returns {Promise<void>}

M app/javascript/mastodon/performance.js => app/javascript/mastodon/performance.js +1 -3
@@ 2,9 2,8 @@
// Tools for performance debugging, only enabled in development mode.
// Open up Chrome Dev Tools, then Timeline, then User Timing to see output.
// Also see config/webpack/loaders/mark.js for the webpack loader marks.
//

let marky;
import * as marky from 'marky';

if (process.env.NODE_ENV === 'development') {
  if (typeof performance !== 'undefined' && performance.setResourceTimingBufferSize) {


@@ 13,7 12,6 @@ if (process.env.NODE_ENV === 'development') {
    performance.setResourceTimingBufferSize(Infinity);
  }

  marky = require('marky');
  // allows us to easily do e.g. ReactPerf.printWasted() while debugging
  //window.ReactPerf = require('react-addons-perf');
  //window.ReactPerf.start();

M app/javascript/mastodon/reducers/compose.js => app/javascript/mastodon/reducers/compose.js +1 -1
@@ 52,7 52,7 @@ import { TIMELINE_DELETE } from '../actions/timelines';
import { STORE_HYDRATE } from '../actions/store';
import { REDRAFT } from '../actions/statuses';
import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable';
import uuid from '../uuid';
import { uuid } from '../uuid';
import { me } from '../initial_state';
import { unescapeHTML } from '../utils/html';


M app/javascript/mastodon/reducers/contexts.js => app/javascript/mastodon/reducers/contexts.js +1 -1
@@ 5,7 5,7 @@ import {
import { CONTEXT_FETCH_SUCCESS } from '../actions/statuses';
import { TIMELINE_DELETE, TIMELINE_UPDATE } from '../actions/timelines';
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
import compareId from '../compare_id';
import { compareId } from '../compare_id';

const initialState = ImmutableMap({
  inReplyTos: ImmutableMap(),

M app/javascript/mastodon/reducers/conversations.js => app/javascript/mastodon/reducers/conversations.js +1 -1
@@ 11,7 11,7 @@ import {
} from '../actions/conversations';
import { ACCOUNT_BLOCK_SUCCESS, ACCOUNT_MUTE_SUCCESS } from 'mastodon/actions/accounts';
import { DOMAIN_BLOCK_SUCCESS } from 'mastodon/actions/domain_blocks';
import compareId from '../compare_id';
import { compareId } from '../compare_id';

const initialState = ImmutableMap({
  items: ImmutableList(),

M app/javascript/mastodon/reducers/index.js => app/javascript/mastodon/reducers/index.js +2 -2
@@ 33,7 33,7 @@ import conversations from './conversations';
import suggestions from './suggestions';
import polls from './polls';
import trends from './trends';
import missed_updates from './missed_updates';
import { missedUpdatesReducer } from './missed_updates';
import announcements from './announcements';
import markers from './markers';
import picture_in_picture from './picture_in_picture';


@@ 79,7 79,7 @@ const reducers = {
  suggestions,
  polls,
  trends,
  missed_updates,
  missed_updates: missedUpdatesReducer,
  markers,
  picture_in_picture,
  history,

M app/javascript/mastodon/reducers/missed_updates.ts => app/javascript/mastodon/reducers/missed_updates.ts +1 -1
@@ 12,7 12,7 @@ const initialState = Record<MissedUpdatesState>({
  unread: 0,
})();

export default function missed_updates(
export function missedUpdatesReducer(
  state = initialState,
  action: Action<string>,
) {

M app/javascript/mastodon/reducers/notifications.js => app/javascript/mastodon/reducers/notifications.js +1 -1
@@ 29,7 29,7 @@ import {
import { DOMAIN_BLOCK_SUCCESS } from 'mastodon/actions/domain_blocks';
import { TIMELINE_DELETE, TIMELINE_DISCONNECT } from '../actions/timelines';
import { fromJS, Map as ImmutableMap, List as ImmutableList } from 'immutable';
import compareId from '../compare_id';
import { compareId } from '../compare_id';

const initialState = ImmutableMap({
  pendingItems: ImmutableList(),

M app/javascript/mastodon/reducers/settings.js => app/javascript/mastodon/reducers/settings.js +1 -1
@@ 6,7 6,7 @@ import { EMOJI_USE } from '../actions/emojis';
import { LANGUAGE_USE } from '../actions/languages';
import { LIST_DELETE_SUCCESS, LIST_FETCH_FAIL } from '../actions/lists';
import { Map as ImmutableMap, fromJS } from 'immutable';
import uuid from '../uuid';
import { uuid } from '../uuid';

const initialState = ImmutableMap({
  saved: true,

M app/javascript/mastodon/reducers/timelines.js => app/javascript/mastodon/reducers/timelines.js +1 -1
@@ 17,7 17,7 @@ import {
  ACCOUNT_UNFOLLOW_SUCCESS,
} from '../actions/accounts';
import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable';
import compareId from '../compare_id';
import { compareId } from '../compare_id';

const initialState = ImmutableMap();


M app/javascript/mastodon/service_worker/web_push_locales.js => app/javascript/mastodon/service_worker/web_push_locales.js +3 -0
@@ 1,3 1,6 @@
/* eslint-disable import/no-commonjs --
   We need to use CommonJS here as its imported into a preval file (`emoji_compressed.js`) */

/* @preval */

const fs   = require('fs');

M app/javascript/mastodon/uuid.ts => app/javascript/mastodon/uuid.ts +1 -1
@@ 1,4 1,4 @@
export default function uuid(a?: string): string {
export function uuid(a?: string): string {
  return a
    ? (
      (a as any as number) ^

M app/javascript/packs/admin.jsx => app/javascript/packs/admin.jsx +2 -3
@@ 1,10 1,9 @@
import './public-path';
import ready from '../mastodon/ready';
import React from 'react';
import ReactDOM from 'react-dom';

ready(() => {
  const React    = require('react');
  const ReactDOM = require('react-dom');

  [].forEach.call(document.querySelectorAll('[data-admin-component]'), element => {
    const componentName  = element.getAttribute('data-admin-component');
    const { locale, ...componentProps } = JSON.parse(element.getAttribute('data-props'));

M app/javascript/packs/public.jsx => app/javascript/packs/public.jsx +18 -12
@@ 1,12 1,23 @@
import './public-path';
import loadPolyfills from '../mastodon/load_polyfills';
import ready from '../mastodon/ready';
import { start } from '../mastodon/common';

import ready from '../mastodon/ready';
import loadKeyboardExtensions from '../mastodon/load_keyboard_extensions';
import 'cocoon-js-vanilla';
import axios from 'axios';
import { throttle } from 'lodash';
import { defineMessages } from 'react-intl';
import * as IntlMessageFormat  from 'intl-messageformat';
import { timeAgoString }  from '../mastodon/components/relative_timestamp';
import { delegate }  from '@rails/ujs';
import * as emojify  from '../mastodon/features/emoji/emoji';
import { getLocale }  from '../mastodon/locales';
import React  from 'react';
import ReactDOM  from 'react-dom';
import { createBrowserHistory }  from 'history';

start();

const messages = defineMessages({
  usernameTaken: { id: 'username.taken', defaultMessage: 'That username is taken. Try another' },


@@ 14,18 25,8 @@ const messages = defineMessages({
  passwordDoesNotMatch: { id: 'password_confirmation.mismatching', defaultMessage: 'Password confirmation does not match' },
});

start();

function main() {
  const IntlMessageFormat = require('intl-messageformat').default;
  const { timeAgoString } = require('../mastodon/components/relative_timestamp');
  const { delegate } = require('@rails/ujs');
  const emojify = require('../mastodon/features/emoji/emoji').default;
  const { getLocale } = require('../mastodon/locales');
function loaded() {
  const { localeData } = getLocale();
  const React = require('react');
  const ReactDOM = require('react-dom');
  const { createBrowserHistory } = require('history');

  const scrollToDetailedStatus = () => {
    const history = createBrowserHistory();


@@ 238,6 239,11 @@ function main() {
  });
}


function main() {
  ready(loaded);
}

loadPolyfills()
  .then(main)
  .then(loadKeyboardExtensions)

M app/javascript/packs/share.jsx => app/javascript/packs/share.jsx +9 -6
@@ 1,23 1,26 @@
import './public-path';
import loadPolyfills from '../mastodon/load_polyfills';
import { start } from '../mastodon/common';
import ready from '../mastodon/ready';
import ComposeContainer  from '../mastodon/containers/compose_container';
import React from 'react';
import ReactDOM from 'react-dom';

start();

function loaded() {
  const ComposeContainer = require('../mastodon/containers/compose_container').default;
  const React = require('react');
  const ReactDOM = require('react-dom');
  const mountNode = document.getElementById('mastodon-compose');

  if (mountNode !== null) {
    const props = JSON.parse(mountNode.getAttribute('data-props'));
  if (mountNode) {
    const attr = mountNode.getAttribute('data-props');
    if(!attr) return;

    const props = JSON.parse(attr);
    ReactDOM.render(<ComposeContainer {...props} />, mountNode);
  }
}

function main() {
  const ready = require('../mastodon/ready').default;
  ready(loaded);
}


M app/javascript/types/image.d.ts => app/javascript/types/image.d.ts +1 -0
@@ 1,3 1,4 @@
/* eslint-disable import/no-default-export */
declare module '*.avif' {
  const path: string;
  export default path;

M config/webpack/shared.js => config/webpack/shared.js +1 -0
@@ 89,6 89,7 @@ module.exports = {

  module: {
    rules: Object.keys(rules).map(key => rules[key]),
    strictExportPresence: true,
  },

  plugins: [

M package.json => package.json +2 -1
@@ 79,6 79,7 @@
    "jsdom": "^21.1.2",
    "lodash": "^4.17.21",
    "mark-loader": "^0.1.6",
    "marky": "^1.2.5",
    "mini-css-extract-plugin": "^1.6.2",
    "mkdirp": "^2.1.6",
    "npmlog": "^7.0.1",


@@ 191,11 192,11 @@
    "eslint-plugin-jsx-a11y": "~6.7.1",
    "eslint-plugin-promise": "~6.1.1",
    "eslint-plugin-react": "~7.32.2",
    "eslint-plugin-react-hooks": "^4.6.0",
    "husky": "^8.0.3",
    "jest": "^29.5.0",
    "jest-environment-jsdom": "^29.5.0",
    "lint-staged": "^13.2.2",
    "marky": "^1.2.5",
    "prettier": "^2.8.8",
    "raf": "^3.4.1",
    "react-intl-translations-manager": "^5.0.3",

M yarn.lock => yarn.lock +5 -0
@@ 5130,6 5130,11 @@ eslint-plugin-promise@~6.1.1:
  resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz#269a3e2772f62875661220631bd4dafcb4083816"
  integrity sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==

eslint-plugin-react-hooks@^4.6.0:
  version "4.6.0"
  resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3"
  integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==

eslint-plugin-react@~7.32.2:
  version "7.32.2"
  resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz#e71f21c7c265ebce01bcbc9d0955170c55571f10"