forked from fedi/mastodon
Rewrite <ShortNumber />
as FC and TS (#25492)
This commit is contained in:
parent
e0d230fb37
commit
20e85c0e83
|
@ -9,7 +9,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
import { EmptyAccount } from 'mastodon/components/empty_account';
|
import { EmptyAccount } from 'mastodon/components/empty_account';
|
||||||
import ShortNumber from 'mastodon/components/short_number';
|
import { ShortNumber } from 'mastodon/components/short_number';
|
||||||
import { VerifiedBadge } from 'mastodon/components/verified_badge';
|
import { VerifiedBadge } from 'mastodon/components/verified_badge';
|
||||||
|
|
||||||
import { me } from '../initial_state';
|
import { me } from '../initial_state';
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { TransitionMotion, spring } from 'react-motion';
|
||||||
|
|
||||||
import { reduceMotion } from '../initial_state';
|
import { reduceMotion } from '../initial_state';
|
||||||
|
|
||||||
import ShortNumber from './short_number';
|
import { ShortNumber } from './short_number';
|
||||||
|
|
||||||
const obfuscatedCount = (count: number) => {
|
const obfuscatedCount = (count: number) => {
|
||||||
if (count < 0) {
|
if (count < 0) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import ShortNumber from 'mastodon/components/short_number';
|
import { ShortNumber } from 'mastodon/components/short_number';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
tag: {
|
tag: {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
|
||||||
import { Sparklines, SparklinesCurve } from 'react-sparklines';
|
import { Sparklines, SparklinesCurve } from 'react-sparklines';
|
||||||
|
|
||||||
import ShortNumber from 'mastodon/components/short_number';
|
import { ShortNumber } from 'mastodon/components/short_number';
|
||||||
import { Skeleton } from 'mastodon/components/skeleton';
|
import { Skeleton } from 'mastodon/components/skeleton';
|
||||||
|
|
||||||
class SilentErrorBoundary extends Component {
|
class SilentErrorBoundary extends Component {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { fetchServer } from 'mastodon/actions/server';
|
import { fetchServer } from 'mastodon/actions/server';
|
||||||
import { ServerHeroImage } from 'mastodon/components/server_hero_image';
|
import { ServerHeroImage } from 'mastodon/components/server_hero_image';
|
||||||
import ShortNumber from 'mastodon/components/short_number';
|
import { ShortNumber } from 'mastodon/components/short_number';
|
||||||
import { Skeleton } from 'mastodon/components/skeleton';
|
import { Skeleton } from 'mastodon/components/skeleton';
|
||||||
import Account from 'mastodon/containers/account_container';
|
import Account from 'mastodon/containers/account_container';
|
||||||
import { domain } from 'mastodon/initial_state';
|
import { domain } from 'mastodon/initial_state';
|
||||||
|
|
|
@ -1,115 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { memo } from 'react';
|
|
||||||
|
|
||||||
import { FormattedMessage, FormattedNumber } from 'react-intl';
|
|
||||||
|
|
||||||
import { toShortNumber, pluralReady, DECIMAL_UNITS } from '../utils/numbers';
|
|
||||||
|
|
||||||
// @ts-check
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @callback ShortNumberRenderer
|
|
||||||
* @param {JSX.Element} displayNumber Number to display
|
|
||||||
* @param {number} pluralReady Number used for pluralization
|
|
||||||
* @returns {JSX.Element} Final render of number
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {object} ShortNumberProps
|
|
||||||
* @property {number} value Number to display in short variant
|
|
||||||
* @property {ShortNumberRenderer} [renderer]
|
|
||||||
* Custom renderer for numbers, provided as a prop. If another renderer
|
|
||||||
* passed as a child of this component, this prop won't be used.
|
|
||||||
* @property {ShortNumberRenderer} [children]
|
|
||||||
* Custom renderer for numbers, provided as a child. If another renderer
|
|
||||||
* passed as a prop of this component, this one will be used instead.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Component that renders short big number to a shorter version
|
|
||||||
* @param {ShortNumberProps} param0 Props for the component
|
|
||||||
* @returns {JSX.Element} Rendered number
|
|
||||||
*/
|
|
||||||
function ShortNumber({ value, renderer, children }) {
|
|
||||||
const shortNumber = toShortNumber(value);
|
|
||||||
const [, division] = shortNumber;
|
|
||||||
|
|
||||||
if (children != null && renderer != null) {
|
|
||||||
console.warn('Both renderer prop and renderer as a child provided. This is a mistake and you really should fix that. Only renderer passed as a child will be used.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const customRenderer = children != null ? children : renderer;
|
|
||||||
|
|
||||||
const displayNumber = <ShortNumberCounter value={shortNumber} />;
|
|
||||||
|
|
||||||
return customRenderer != null
|
|
||||||
? customRenderer(displayNumber, pluralReady(value, division))
|
|
||||||
: displayNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
ShortNumber.propTypes = {
|
|
||||||
value: PropTypes.number.isRequired,
|
|
||||||
renderer: PropTypes.func,
|
|
||||||
children: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @typedef {object} ShortNumberCounterProps
|
|
||||||
* @property {import('../utils/number').ShortNumber} value Short number
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renders short number into corresponding localizable react fragment
|
|
||||||
* @param {ShortNumberCounterProps} param0 Props for the component
|
|
||||||
* @returns {JSX.Element} FormattedMessage ready to be embedded in code
|
|
||||||
*/
|
|
||||||
function ShortNumberCounter({ value }) {
|
|
||||||
const [rawNumber, unit, maxFractionDigits = 0] = value;
|
|
||||||
|
|
||||||
const count = (
|
|
||||||
<FormattedNumber
|
|
||||||
value={rawNumber}
|
|
||||||
maximumFractionDigits={maxFractionDigits}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
let values = { count, rawNumber };
|
|
||||||
|
|
||||||
switch (unit) {
|
|
||||||
case DECIMAL_UNITS.THOUSAND: {
|
|
||||||
return (
|
|
||||||
<FormattedMessage
|
|
||||||
id='units.short.thousand'
|
|
||||||
defaultMessage='{count}K'
|
|
||||||
values={values}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case DECIMAL_UNITS.MILLION: {
|
|
||||||
return (
|
|
||||||
<FormattedMessage
|
|
||||||
id='units.short.million'
|
|
||||||
defaultMessage='{count}M'
|
|
||||||
values={values}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
case DECIMAL_UNITS.BILLION: {
|
|
||||||
return (
|
|
||||||
<FormattedMessage
|
|
||||||
id='units.short.billion'
|
|
||||||
defaultMessage='{count}B'
|
|
||||||
values={values}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Not sure if we should go farther - @Sasha-Sorokin
|
|
||||||
default: return count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ShortNumberCounter.propTypes = {
|
|
||||||
value: PropTypes.arrayOf(PropTypes.number),
|
|
||||||
};
|
|
||||||
|
|
||||||
export default memo(ShortNumber);
|
|
90
app/javascript/mastodon/components/short_number.tsx
Normal file
90
app/javascript/mastodon/components/short_number.tsx
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
import { memo } from 'react';
|
||||||
|
|
||||||
|
import { FormattedMessage, FormattedNumber } from 'react-intl';
|
||||||
|
|
||||||
|
import { toShortNumber, pluralReady, DECIMAL_UNITS } from '../utils/numbers';
|
||||||
|
|
||||||
|
type ShortNumberRenderer = (
|
||||||
|
displayNumber: JSX.Element,
|
||||||
|
pluralReady: number
|
||||||
|
) => JSX.Element;
|
||||||
|
|
||||||
|
interface ShortNumberProps {
|
||||||
|
value: number;
|
||||||
|
renderer?: ShortNumberRenderer;
|
||||||
|
children?: ShortNumberRenderer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ShortNumberRenderer: React.FC<ShortNumberProps> = ({
|
||||||
|
value,
|
||||||
|
renderer,
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
|
const shortNumber = toShortNumber(value);
|
||||||
|
const [, division] = shortNumber;
|
||||||
|
|
||||||
|
if (children && renderer) {
|
||||||
|
console.warn(
|
||||||
|
'Both renderer prop and renderer as a child provided. This is a mistake and you really should fix that. Only renderer passed as a child will be used.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const customRenderer = children || renderer || null;
|
||||||
|
|
||||||
|
const displayNumber = <ShortNumberCounter value={shortNumber} />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
customRenderer?.(displayNumber, pluralReady(value, division)) ||
|
||||||
|
displayNumber
|
||||||
|
);
|
||||||
|
};
|
||||||
|
export const ShortNumber = memo(ShortNumberRenderer);
|
||||||
|
|
||||||
|
interface ShortNumberCounterProps {
|
||||||
|
value: number[];
|
||||||
|
}
|
||||||
|
const ShortNumberCounter: React.FC<ShortNumberCounterProps> = ({ value }) => {
|
||||||
|
const [rawNumber, unit, maxFractionDigits = 0] = value;
|
||||||
|
|
||||||
|
const count = (
|
||||||
|
<FormattedNumber
|
||||||
|
value={rawNumber}
|
||||||
|
maximumFractionDigits={maxFractionDigits}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const values = { count, rawNumber };
|
||||||
|
|
||||||
|
switch (unit) {
|
||||||
|
case DECIMAL_UNITS.THOUSAND: {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='units.short.thousand'
|
||||||
|
defaultMessage='{count}K'
|
||||||
|
values={values}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case DECIMAL_UNITS.MILLION: {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='units.short.million'
|
||||||
|
defaultMessage='{count}M'
|
||||||
|
values={values}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
case DECIMAL_UNITS.BILLION: {
|
||||||
|
return (
|
||||||
|
<FormattedMessage
|
||||||
|
id='units.short.billion'
|
||||||
|
defaultMessage='{count}B'
|
||||||
|
values={values}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Not sure if we should go farther - @Sasha-Sorokin
|
||||||
|
default:
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
};
|
|
@ -14,7 +14,7 @@ import Button from 'mastodon/components/button';
|
||||||
import { FollowersCounter, FollowingCounter, StatusesCounter } from 'mastodon/components/counters';
|
import { FollowersCounter, FollowingCounter, StatusesCounter } from 'mastodon/components/counters';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import { IconButton } from 'mastodon/components/icon_button';
|
import { IconButton } from 'mastodon/components/icon_button';
|
||||||
import ShortNumber from 'mastodon/components/short_number';
|
import { ShortNumber } from 'mastodon/components/short_number';
|
||||||
import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container';
|
import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container';
|
||||||
import { autoPlayGif, me, domain } from 'mastodon/initial_state';
|
import { autoPlayGif, me, domain } from 'mastodon/initial_state';
|
||||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
|
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { openModal } from 'mastodon/actions/modal';
|
||||||
import { Avatar } from 'mastodon/components/avatar';
|
import { Avatar } from 'mastodon/components/avatar';
|
||||||
import Button from 'mastodon/components/button';
|
import Button from 'mastodon/components/button';
|
||||||
import { DisplayName } from 'mastodon/components/display_name';
|
import { DisplayName } from 'mastodon/components/display_name';
|
||||||
import ShortNumber from 'mastodon/components/short_number';
|
import { ShortNumber } from 'mastodon/components/short_number';
|
||||||
import { autoPlayGif, me, unfollowModal } from 'mastodon/initial_state';
|
import { autoPlayGif, me, unfollowModal } from 'mastodon/initial_state';
|
||||||
import { makeGetAccount } from 'mastodon/selectors';
|
import { makeGetAccount } from 'mastodon/selectors';
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import classNames from 'classnames';
|
||||||
|
|
||||||
import { Blurhash } from 'mastodon/components/blurhash';
|
import { Blurhash } from 'mastodon/components/blurhash';
|
||||||
import { accountsCountRenderer } from 'mastodon/components/hashtag';
|
import { accountsCountRenderer } from 'mastodon/components/hashtag';
|
||||||
import ShortNumber from 'mastodon/components/short_number';
|
import { ShortNumber } from 'mastodon/components/short_number';
|
||||||
import { Skeleton } from 'mastodon/components/skeleton';
|
import { Skeleton } from 'mastodon/components/skeleton';
|
||||||
|
|
||||||
export default class Story extends PureComponent {
|
export default class Story extends PureComponent {
|
||||||
|
|
Loading…
Reference in a new issue