DefinitelyTyped/types/react-intl/react-intl-tests.tsx
Tomas Carnecky 08c13378e4 react-intl: change the FormattedMessage tagName prop to accept any ReactType (#31906)
In the react-intl source the prop is defined as follows:

    tagName: PropTypes.oneOfType([PropTypes.string, PropTypes.element])

But it's actually passed straight to React.createElement(tagName, …),
so any type that is accepted by createElement should be allowed here.

It is useful to allow passing custom components to FormattedMessage,
for example when you use styled components, eg.

    const FancyHeading = styled('h1')`font-size: 32px`;
    <FormattedMessage … tagName={FancyHeading} />
2019-01-06 11:04:11 -08:00

435 lines
15 KiB
TypeScript

/**
* Created by Bruno Grieder and Christian Droulers
* Updated by Fedor Nezhivoi
*/
import * as React from "react";
import * as PropTypes from "prop-types";
import * as reactMixin from "react-mixin";
import {
IntlProvider,
InjectedIntl,
InjectedIntlProps,
addLocaleData,
injectIntl,
intlShape,
defineMessages,
FormattedRelative,
FormattedMessage,
FormattedHTMLMessage,
FormattedNumber,
FormattedPlural,
FormattedDate,
FormattedTime
} from "react-intl";
import reactIntlEn = require("react-intl/locale-data/en");
addLocaleData(reactIntlEn);
interface SomeComponentProps {
className: string;
}
const SomeFunctionalComponentWithIntl: React.ComponentClass<SomeComponentProps> = injectIntl<SomeComponentProps & InjectedIntlProps>(({
intl: {
formatDate,
formatHTMLMessage,
formatNumber,
formatMessage,
formatPlural,
formatRelative,
formatTime,
locale,
defaultLocale
},
className
}) => {
const formattedDate = formatDate(new Date(), { format: "short" });
const formattedTime = formatTime(new Date(), { format: "short" });
const formattedRelative = formatRelative(new Date().getTime(), { format: "short" });
const formattedNumber = formatNumber(123, { format: "short" });
const formattedPlural = formatPlural(1, { style: "ordinal" });
const formattedMessage = formatMessage({ id: "hello", defaultMessage: "Hello {name}!" }, { name: "Roger", nullAllowed: null, undefinedAllowed: undefined });
const formattedMessagePlurals = formatMessage({
id: "hello",
defaultMessage: "Hello {name} you have {unreadCount, number} {unreadCount, plural, one {message} other {messages}}!"
}, { name: "Roger", unreadCount: 123 });
const formattedHTMLMessage = formatHTMLMessage({ id: "hello", defaultMessage: "Hello <strong>{name}</strong>!" }, { name: "Roger", nullAllowed: null, undefinedAllowed: undefined });
return (
<div className={className}>
</div>
);
});
class SomeComponent extends React.Component<SomeComponentProps & InjectedIntlProps> {
static propTypes: React.ValidationMap<SomeComponentProps & InjectedIntlProps> = {
intl: intlShape.isRequired,
className: PropTypes.string.isRequired
};
render(): React.ReactElement<{}> {
const intl = this.props.intl;
const formattedDate = intl.formatDate(new Date(), { format: "short" });
const formattedTime = intl.formatTime(new Date(), { format: "short" });
const formattedRelative = intl.formatRelative(new Date().getTime(), { format: "short" });
const formattedNumber = intl.formatNumber(123, { format: "short" });
const formattedPlural = intl.formatPlural(1, { style: "ordinal" });
const formattedMessage = intl.formatMessage({ id: "hello", defaultMessage: "Hello {name}!" }, { name: "Roger" });
const formattedMessageNumber = intl.formatMessage({ id: "hello", defaultMessage: "Hello {num}!" }, { num: 1 });
const formattedMessageDate = intl.formatMessage({ id: "hello", defaultMessage: "Hello {date}!" }, { date: new Date() });
const formattedMessageBool = intl.formatMessage({ id: "hello", defaultMessage: "Hello {bool}!" }, { bool: true });
const formattedMessagePlurals = intl.formatMessage({
id: "hello",
defaultMessage: "Hello {name} you have {unreadCount, number} {unreadCount, plural, one {message} other {messages}}!" },
{ name: "Roger", unreadCount: 123 });
const formattedHTMLMessage = intl.formatHTMLMessage({ id: "hello", defaultMessage: "Hello <strong>{name}</strong>!" }, { name: "Roger" });
const formattedHTMLMessageNumber = intl.formatHTMLMessage({ id: "hello", defaultMessage: "Hello <strong>{num}</strong>!" }, { num: 1 });
const formattedHTMLMessageDate = intl.formatHTMLMessage({ id: "hello", defaultMessage: "Hello <strong>{date}</strong>!" }, { date: new Date() });
const formattedHTMLMessageBool = intl.formatHTMLMessage({ id: "hello", defaultMessage: "Hello <strong>{bool}</strong>!" }, { bool: true });
return <div className={this.props.className}>
<FormattedRelative
value={new Date().getTime()}
units="hour"
style="numeric"
format="yyyy-MM-dd"
updateInterval={123}
initialNow={new Date()} />
<FormattedRelative
value={new Date().getTime()}
units="hour"
style="numeric"
format="yyyy-MM-dd"
updateInterval={123}
initialNow={new Date()}
>
{formattedRelative => formattedRelative.toUpperCase()}
</FormattedRelative>
<FormattedMessage
id="test"
description="Test"
defaultMessage="Hi, {name}!"
values={{ name: "bob" }}
tagName="div" />
<FormattedMessage
id="test"
description="Test"
defaultMessage="Hi nested component {name}!"
values={{ name: <p>p</p> }}
tagName="div" />
<FormattedMessage
id="test"
description="Test"
defaultMessage="Hi numbers {count}!"
values={{ count: 123 }}
tagName="div" />
<FormattedMessage
id="test"
description="Test"
defaultMessage="Hi {bool}!"
values={{ bool: false }}
tagName="div" />
<FormattedMessage
id="test"
description="Test"
defaultMessage="Hi {date}!"
values={{ date: new Date() }}
tagName="div" />
<FormattedMessage
id="test"
description="Test"
defaultMessage="Hi plurals: {valueOne, number} {valueOne, plural, one {plural} other {plurals}} {valueTen, number} {valueTen, plural, one {plural} other {plurals}} !"
values={{ valueOne: 1, valueTen: 10 }}
tagName="div" />
<FormattedMessage
id="test"
description="Test"
defaultMessage="Hi {blank} and {empty}!"
values={{ blank: null, empty: undefined }}
tagName="div" />
<FormattedMessage
id="test"
description="Test"
defaultMessage="Hi {blank} and {empty}!"
values={{ blank: null, empty: undefined }}
tagName={({ children }) => <div>{children}</div>} />
<FormattedMessage
id="test"
description="Test"
>
{(text) => <div className="messageDiv">{text}</div>}
</FormattedMessage>
<FormattedMessage
id="test"
description="Test"
>
{(text) => <input placeholder={text as string} />}
</FormattedMessage>
<FormattedMessage
id="test"
description="Test"
>
{(...text) => <ul>{text.map(t => <li>{t}</li>)}</ul>}
</FormattedMessage>
<FormattedMessage
id="legal-statement"
values={{
privacy_policy: (
<a href="/privacy-policy">
<FormattedMessage id="request_invite.privacy_policy" />
</a>
),
terms_of_service: (
<a href="/terms-of-service">
<FormattedMessage id="request_invite.terms_of_service" />
</a>
)
}}
>
{(...messages) => messages.map(message => <>{message}</>)}
</FormattedMessage>
<FormattedHTMLMessage
id="test"
description="Test"
defaultMessage="Hi, {name}!"
values={{ name: "bob" }}
tagName="div" />
<FormattedHTMLMessage
id="test"
description="Test"
defaultMessage="Hi, {name}!"
values={{ name: "bob" }}
tagName="div" />
<FormattedHTMLMessage
id="test"
description="Test"
defaultMessage="Hi numbers {count}!"
values={{ count: 123 }}
tagName="div" />
<FormattedHTMLMessage
id="test"
description="Test"
defaultMessage="Hi {bool}!"
values={{ bool: false }}
tagName="div" />
<FormattedHTMLMessage
id="test"
description="Test"
defaultMessage="Hi {date}!"
values={{ date: new Date() }}
tagName="div" />
<FormattedNumber
value={123456.78}
format="N"
localeMatcher="lookup"
style="currency"
currency="USD"
currencyDisplay="name"
useGrouping={false}
minimumIntegerDigits={1}
minimumFractionDigits={1}
minimumSignificantDigits={2}
maximumFractionDigits={3}
maximumSignificantDigits={3} />
<FormattedNumber value={123}>
{formattedNum => (
<span className="number">{formattedNum}</span>
)}
</FormattedNumber>
<FormattedPlural
style="cardinal"
value={3}
other="hai?"
zero="no hai"
one="hai"
two="hai2"
few="haifew"
many="haiku" />
<FormattedPlural
style="cardinal"
value={3}
other="hai?"
zero="no hai"
one="hai"
two="hai2"
few="haifew"
many="haiku"
>
{formattedPlural => (
<span className="number">{formattedPlural}</span>
)}
</FormattedPlural>
<FormattedDate
value={new Date()}
format="short"
localeMatcher="best fit"
formatMatcher="basic"
timeZone="EDT"
hour12={false}
weekday="short"
era="short"
year="2-digit"
month="2-digit"
day="2-digit"
hour="2-digit"
minute="2-digit"
second="2-digit"
timeZoneName="short" />
<FormattedDate
value={Date.now()}
format="short"
localeMatcher="best fit"
formatMatcher="basic"
timeZone="EDT"
hour12={false}
weekday="short"
era="short"
year="2-digit"
month="2-digit"
day="2-digit"
hour="2-digit"
minute="2-digit"
second="2-digit"
timeZoneName="short" />
<FormattedDate
value={Date.now()}
format="short"
localeMatcher="best fit"
formatMatcher="basic"
timeZone="EDT"
hour12={false}
weekday="short"
era="short"
year="2-digit"
month="2-digit"
day="2-digit"
hour="2-digit"
minute="2-digit"
second="2-digit"
timeZoneName="short"
>
{formattedDate => formattedDate.toUpperCase()}
</FormattedDate>
<FormattedTime
value={new Date()}
format="short"
localeMatcher="best fit"
formatMatcher="basic"
timeZone="EDT"
hour12={false}
weekday="short"
era="short"
year="2-digit"
month="2-digit"
day="2-digit"
hour="2-digit"
minute="2-digit"
second="2-digit"
timeZoneName="short" />
<FormattedTime
value={Date.now()}
format="short"
localeMatcher="best fit"
formatMatcher="basic"
timeZone="EDT"
hour12={false}
weekday="short"
era="short"
year="2-digit"
month="2-digit"
day="2-digit"
hour="2-digit"
minute="2-digit"
second="2-digit"
timeZoneName="short" />
<FormattedTime
value={Date.now()}
format="short"
localeMatcher="best fit"
formatMatcher="basic"
timeZone="EDT"
hour12={false}
weekday="short"
era="short"
year="2-digit"
month="2-digit"
day="2-digit"
hour="2-digit"
minute="2-digit"
second="2-digit"
timeZoneName="short"
>
{formattedTime => formattedTime.toUpperCase()}
</FormattedTime>
</div>;
}
}
const SomeComponentWithIntl = injectIntl(SomeComponent);
class TestApp extends React.Component {
render(): React.ReactElement<{}> {
const definedMessages = defineMessages({
sup: {
id: "sup",
defaultMessage: "Hai mom"
}
});
const messages = {
hello: "Hello, {name}!"
};
return (
<IntlProvider
locale="en"
formats={{}}
messages={messages}
defaultLocale="en"
defaultFormats={messages}
timeZone="UTC"
onError={(error: string) => console.error(error)}
>
<SomeComponentWithIntl className="just-for-test" />
<SomeFunctionalComponentWithIntl className="another-one" />
</IntlProvider>
);
}
}
const intlProvider = new IntlProvider({ locale: 'en' }, {});
const { intl } = intlProvider.getChildContext();
const wrappedComponent = <SomeComponentWithIntl.WrappedComponent className="test" intl={intl}/>;
export default {
TestApp,
SomeComponent: SomeComponentWithIntl
};