Skip to content

Commit

Permalink
feat: Added createReactComponent()
Browse files Browse the repository at this point in the history
  • Loading branch information
mnasyrov committed Jan 14, 2024
1 parent 590bfca commit 058bcf0
Show file tree
Hide file tree
Showing 5 changed files with 251 additions and 0 deletions.
136 changes: 136 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@
"rxjs": ">=7.0"
},
"devDependencies": {
"@testing-library/jest-dom": "6.2.0",
"@testing-library/react": "14.1.2",
"@testing-library/user-event": "14.5.2",
"@types/jest": "29.5.11",
"@typescript-eslint/eslint-plugin": "6.15.0",
"@typescript-eslint/parser": "6.15.0",
Expand Down
75 changes: 75 additions & 0 deletions src/react/createReactComponent.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React, { FC } from 'react';

import { render, screen } from '@testing-library/react';
import '@testing-library/jest-dom';
// eslint-disable-next-line import/no-named-as-default
import userEvent from '@testing-library/user-event';

import { Atom } from '../core';
import { declareController, viewProps, withView } from '../core/mvc';

import { createReactComponent } from './createReactComponent';
import { useAtom } from './useAtom';

describe('ViewController HOC', () => {
type BaseCounterController = {
$value: Atom<number>;
increase(): void;
decrease(): void;
};

const CounterView: FC<{
controller: BaseCounterController;
label: string;
}> = (props) => {
const { controller, label } = props;
const { $value, increase, decrease } = controller;

const value = useAtom($value);

return (
<>
<span data-testid="label">{label}</span>
<span data-testid="value">{value}</span>
<button data-testid="increase" onClick={increase} />
<button data-testid="descrease" onClick={decrease} />
</>
);
};

const CounterController = declareController
.extend(withView(viewProps<{ initialValue: number }>()))
.apply(({ scope, view }) => {
const { initialValue } = view.props;

const $value = scope.atom(initialValue());

function update(delta: number) {
$value.update((prev) => prev + delta);
}

return {
$value: $value.asReadonly(),
increase: () => update(1),
decrease: () => update(-1),
};
});

it('should combine a view controller and a react component to HOC component', async () => {
const user = userEvent.setup();

const TestCounter = createReactComponent(CounterController, CounterView);

render(<TestCounter initialValue={5} label="TestLabel" />);

expect(screen.getByTestId('label')).toHaveTextContent('TestLabel');
expect(screen.getByTestId('value')).toHaveTextContent('5');

await user.click(screen.getByTestId('increase'));
expect(screen.getByTestId('value')).toHaveTextContent('6');

await user.click(screen.getByTestId('descrease'));
await user.click(screen.getByTestId('descrease'));
expect(screen.getByTestId('value')).toHaveTextContent('4');
});
});
37 changes: 37 additions & 0 deletions src/react/createReactComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React, { FC } from 'react';

import {
BaseService,
ControllerDeclaration,
ViewControllerContext,
ViewProps,
} from '../core/mvc';

import { useController } from './useController';

export function createReactComponent<
TService extends BaseService,
TControllerProps extends ViewProps,
TViewProps extends { controller: TService },
>(
controllerDeclaration: ControllerDeclaration<
ViewControllerContext<TControllerProps>,
TService
>,
ViewComponent: FC<TViewProps>,
): FC<Omit<TViewProps, 'controller'> & TControllerProps> {
const HOC: FC<Omit<TViewProps, 'controller'> & TControllerProps> = (
props,
) => {
const controller = useController(controllerDeclaration, props);

return (
<ViewComponent
controller={controller}
{...(props as any)}
></ViewComponent>
);
};

return HOC;
}
1 change: 1 addition & 0 deletions src/react/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { useAtom } from './useAtom';

export { createReactComponent } from './createReactComponent';
export { useController } from './useController';

export { NrgyReactExtension } from './NrgyReactExtension';

0 comments on commit 058bcf0

Please sign in to comment.