Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump dependencies and support forwardRef #19

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
{
"presets": ["es2015", "react", "flow"],
"plugins": [
"transform-class-properties"
]
"presets": ["@babel/preset-env", "@babel/react", "@babel/flow"],
"plugins": ["@babel/plugin-proposal-class-properties"]
}
119 changes: 63 additions & 56 deletions __test__/__snapshots__/test.js.snap
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`<I18nProvider> children get i18n from I18nProvider 1`] = `
<TestElement
<UNDEFINED
i18n={
Object {
"gettext": [Function],
Expand Down Expand Up @@ -30,22 +30,27 @@ exports[`<I18nProvider> children get i18n from I18nProvider 2`] = `
<Translate(TestElement)
testProp="required"
>
<TestElement
i18n={
Object {
"gettext": [Function],
"lang": "en-US",
"ngettext": [Function],
"npgettext": [Function],
"pgettext": [Function],
}
}
<Translate
forwardedRef={null}
testProp="required"
>
<div>
Test
</div>
</TestElement>
<TestElement
i18n={
Object {
"gettext": [Function],
"lang": "en-US",
"ngettext": [Function],
"npgettext": [Function],
"pgettext": [Function],
}
}
testProp="required"
>
<div>
Test
</div>
</TestElement>
</Translate>
</Translate(TestElement)>
</I18nProvider>
`;
Expand All @@ -63,7 +68,8 @@ exports[`translate Component render anonymous component 1`] = `
}
testProp="required"
>
<Component
<Translate
forwardedRef={null}
i18n={
Object {
"gettext": [Function],
Expand All @@ -75,44 +81,31 @@ exports[`translate Component render anonymous component 1`] = `
}
testProp="required"
>
<div>
My
required
</div>
</Component>
<Component
i18n={
Object {
"gettext": [Function],
"lang": "en-US",
"ngettext": [Function],
"npgettext": [Function],
"pgettext": [Function],
}
}
testProp="required"
>
<div>
My
required
</div>
</Component>
</Translate>
</Translate(Component)>
`;

exports[`translate Component render translated component 1`] = `
<Translate(TestElement)
i18n={
Object {
"gettext": [Function],
"lang": "en-US",
"ngettext": [Function],
"npgettext": [Function],
"pgettext": [Function],
}
}
testProp="required"
>
<TestElement
i18n={
Object {
"gettext": [Function],
"lang": "en-US",
"ngettext": [Function],
"npgettext": [Function],
"pgettext": [Function],
}
}
testProp="required"
>
<div>
Test
</div>
</TestElement>
</Translate(TestElement)>
<ContextConsumer>
<Component />
</ContextConsumer>
`;

exports[`translate Component render translated stateless component 1`] = `
Expand All @@ -128,7 +121,8 @@ exports[`translate Component render translated stateless component 1`] = `
}
testProp="required"
>
<StatelessTest
<Translate
forwardedRef={null}
i18n={
Object {
"gettext": [Function],
Expand All @@ -140,10 +134,23 @@ exports[`translate Component render translated stateless component 1`] = `
}
testProp="required"
>
<div>
My
required
</div>
</StatelessTest>
<StatelessTest
i18n={
Object {
"gettext": [Function],
"lang": "en-US",
"ngettext": [Function],
"npgettext": [Function],
"pgettext": [Function],
}
}
testProp="required"
>
<div>
My
required
</div>
</StatelessTest>
</Translate>
</Translate(StatelessTest)>
`;
1 change: 0 additions & 1 deletion __test__/bad-type/bad-props-stateless-component.flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import * as React from 'react';
import { translate, type I18nType } from '../../src';
import mockI18n from '../../src/mockI18n';


// Case 1: React stateless component
const StatelessCom = ({ name, i18n }: { name: string, i18n: I18nType }) => (
<div>{i18n.gettext('S')}</div>
Expand Down
16 changes: 12 additions & 4 deletions __test__/good-type.flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ const ComponentA = ({
);

const TComponentA = translate(ComponentA);
export const ComponentA2 = translate<typeof ComponentA>(ComponentA);
export const ComponentA2 = translate<*, React.ElementConfig<typeof ComponentA>>(
ComponentA
);
result = <TComponentA content="foo">bar</TComponentA>;
result = (
<TComponentA.WrappedComponent content="foo" i18n={mockI18n}>
Expand Down Expand Up @@ -56,7 +58,9 @@ class ComponentB extends React.PureComponent<{
}

const TComponentB = translate(ComponentB);
export const ComponentB2 = translate<typeof ComponentB>(ComponentB);
export const ComponentB2 = translate<ComponentB, React.ElementConfig<typeof ComponentB>>(
ComponentB
);
result = <TComponentB content="foo">bar</TComponentB>;

// Case 3: class component with static
Expand Down Expand Up @@ -87,7 +91,9 @@ class ComponentC extends React.Component<{
}

const TComponentC = translate(ComponentC);
export const ComponentC2 = translate<typeof ComponentC>(ComponentC);
export const ComponentC2 = translate<ComponentC, React.ElementConfig<typeof ComponentC>>(
ComponentC
);
result = <TComponentC content="foo">bar</TComponentC>;

ComponentC.method('foo');
Expand Down Expand Up @@ -137,7 +143,9 @@ class ComponentD extends React.Component<{

const componentD = <ComponentD age={12} i18n={mockI18n} />;
const TComponentD = translate(ComponentD);
export const ComponentD2 = translate<typeof ComponentD>(ComponentD);
export const ComponentD2 = translate<ComponentD, React.ElementConfig<typeof ComponentD>>(
ComponentD
);

result = <TComponentD age={12} />;

Expand Down
35 changes: 33 additions & 2 deletions __test__/test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow strict
import React from 'react';
import { mount } from 'enzyme';
import { mount, shallow } from 'enzyme';
import { Jed, translate, I18nProvider, type I18nType } from '../src';
import mockI18n from '../src/mockI18n';

Expand Down Expand Up @@ -59,7 +59,10 @@ describe('<I18nProvider>', () => {
describe('translate Component', () => {
it('render translated component', () => {
const LocalizedEle = translate(TestElement);
const localizedEle = mount(<LocalizedEle i18n={mockI18n} testProp="required" />);
const localizedEle = shallow(
<LocalizedEle i18n={mockI18n} testProp="required" />
).dive();

const instEle = localizedEle.instance();
expect(instEle.props.i18n).toEqual(mockI18n);
expect(localizedEle).toMatchSnapshot();
Expand Down Expand Up @@ -96,6 +99,34 @@ describe('translate Component', () => {
const localizedEle = mount(<LocalizedEle i18n={mockI18n} testProp="required" />);
expect(localizedEle).toMatchSnapshot();
});

it('should inherit ref properly', () => {
class A extends React.Component<{ i18n: I18nType }, {}> {
getName = () => 'NameA';

render() {
return <div />;
}
}

const B = translate(A);

class C extends React.Component<{}, {}> {
ref = React.createRef();

test = () => {
const { current } = this.ref;
return current ? current.getName() : '';
};

render() {
return <B ref={this.ref} />;
}
}
const Test = mount(<C />);
const instance = Test.instance();
expect(instance.test()).toEqual('NameA');
});
});

describe('mock i18n', () => {
Expand Down
14 changes: 8 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,15 @@
"react": "^16.6.3"
},
"devDependencies": {
"babel-cli": "^6.26.0",
"@babel/cli": "^7.0.0",
"@babel/core": "^7.0.0",
"@babel/plugin-proposal-class-properties": "^7.3.4",
"@babel/preset-env": "^7.3.4",
"@babel/preset-flow": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.0.1",
"babel-jest": "^23.6.0",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-preset-es2015": "^6.24.1",
"babel-preset-flow": "^6.23.0",
"babel-preset-react": "^6.24.1",
"coveralls": "^3.0.1",
"enzyme": "^3.7.0",
"enzyme-adapter-react-16": "^1.7.0",
Expand All @@ -40,7 +42,7 @@
"eslint-plugin-jsx-a11y": "^6.1.2",
"eslint-plugin-prettier": "^3.0.0",
"eslint-plugin-react": "^7.3.0",
"flow-bin": "^0.84.0",
"flow-bin": "^0.93.0",
"flow-copy-source": "^2.0.2",
"flow-typed": "^2.4.0",
"husky": "^1.2.0",
Expand Down
41 changes: 22 additions & 19 deletions src/translate.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,42 @@ import hoistStatics from 'hoist-non-react-statics';
import type { I18nType } from '.';
import { I18nContext } from './I18nProvider';

type InjectedProps = { i18n: I18nType };

declare class TranslatedComponent<OP> extends React$Component<OP> {
static WrappedComponent: Class<React$Component<OP>>;
static displayName: ?string;
props: OP;
state: void;
}

declare type TranslatedComponentClass<OP> = Class<TranslatedComponent<OP>>;

function translate<Com: React$ComponentType<*>>(
WrappedComponent: Com
): TranslatedComponentClass<$Diff<React.ElementConfig<Com>, InjectedProps>> {
function translate<Instance, Config: { +i18n: I18nType }>(
WrappedComponent: React.AbstractComponent<Config, Instance>
): React.AbstractComponent<$Diff<Config, { i18n: I18nType }>, Instance> & {
WrappedComponent: React.AbstractComponent<Config, Instance>,
} {
const name = WrappedComponent.displayName || WrappedComponent.name || 'Component';

class Translate extends React.Component<
$Diff<React.ElementConfig<Com>, InjectedProps>
$Diff<
Config & {
forwardedRef: *,
},
{ i18n: I18nType }
>
> {
static WrappedComponent = WrappedComponent;

static displayName = `Translate(${name})`;

render() {
const { forwardedRef, ...restProps } = this.props;
return (
<I18nContext.Consumer>
{i18n => <WrappedComponent i18n={i18n} {...this.props} />}
{i18n => (
<WrappedComponent ref={forwardedRef} i18n={i18n} {...restProps} />
)}
</I18nContext.Consumer>
);
}
}

return (hoistStatics(Translate, WrappedComponent): any);
const ForwardedComponent = React.forwardRef<Config, Instance>((props, ref) => (
<Translate {...props} forwardedRef={ref} />
));

ForwardedComponent.displayName = `Translate(${name})`;

return (hoistStatics(ForwardedComponent, WrappedComponent): any);
}

export default translate;
Loading