Skip to content
Open
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
2 changes: 2 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import React from 'react';
import { render } from 'react-dom';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

что это?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Этого не должно быть здесь, перекину в векту master, предпологалось как шаблон использовать

23 changes: 23 additions & 0 deletions src/lesson4/Cell.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.cell {
background: #fff;
border: 1px solid #999;
font-size: 24px;
font-weight: bold;
line-height: 34px;
height: 34px;
margin-right: -1px;
margin-top: -1px;
padding: 0;
text-align: center;
width: 34px;
display: inline-block;
}

.cell-empty {
border-color: gray;
}

.cell-filled {
border-color: #fff;
background: black;
}
17 changes: 17 additions & 0 deletions src/lesson4/Cell.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import { Cell } from './Cell';
import { withKnobs, number } from '@storybook/addon-knobs';

// eslint-disable-next-line no-restricted-syntax
export default {
title: 'Lesson 4 / Cell',
decorators: [withKnobs],
};

export const nonFilled = () => [
<Cell x={number('x', 1)} y={number('y', 23)} key="stroies" />,
];

export const Filled = () => [
<Cell filled={true} x={number('x', 1)} y={number('y', 23)} key="stroies" />,
];
13 changes: 13 additions & 0 deletions src/lesson4/Cell.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import { mount } from 'enzyme';
import { Cell } from './Cell';

test.each`
inputFilled | expected
${true} | ${'<div class="cell cell-filled"></div>'}
${false} | ${'<div class="cell cell-empty"></div>'}
`('renders cell for empty or filled', ({ inputFilled, expected }) => {
const cellItem = mount(<Cell filled={inputFilled} x={1} y={2} />);

expect(cellItem.html()).toBe(expected);
});
13 changes: 13 additions & 0 deletions src/lesson4/Cell.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React, { FC } from 'react';
import './Cell.css';
import type { CellProps } from './Interfaces';

const Cell: FC<CellProps> = ({ filled, x, y }) => {
if (filled) {
return <div className="cell cell-filled">{filled}</div>;
}

return <div className="cell cell-empty"></div>;
};

export { Cell };
10 changes: 10 additions & 0 deletions src/lesson4/Field.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
p {
margin: 0;
padding: 0;
line-height: 0;
}
div {
margin: 0;
padding: 0;
line-height: 0;
}
33 changes: 33 additions & 0 deletions src/lesson4/Field.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import { Field } from './Field';
import { withKnobs, object } from '@storybook/addon-knobs';

// eslint-disable-next-line no-restricted-syntax
export default {
title: 'Lesson 4 / Field',
decorators: [withKnobs],
};

const cellGridFillRandom = (cellStatus = () => Math.random() < 0.3) => {
const grid: boolean[][] = [];
for (let y = 0; y < 10; y++) {
grid[y] = [];
for (let x = 0; x < 10; x++) {
grid[y][x] = cellStatus();
}
}
return grid;
};

const cellGridNonFill = () =>
Array.from<boolean[]>({ length: 10 }).fill(
Array.from<boolean>({ length: 10 }).fill(false),
);

export const emptyCell = () => [
<Field field={object('field', cellGridNonFill())} key="stories" />,
];

export const notEmptyCell = () => [
<Field field={object('field', cellGridFillRandom())} key="stories" />,
];
26 changes: 26 additions & 0 deletions src/lesson4/Field.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import React from 'react';
import { mount } from 'enzyme';
import { Field } from './Field';

test.each`
inputFilled | expectedBr | expectedDiv | expectedCellEmpty | expectedCellFilled
${[
[true, false, true, true, false, true, true, true, false, true],
[true, true, true, true, false, false, false, true, false, true],
]} | ${2} | ${20} | ${7} | ${13}
`(
'testing rendering field',
({
inputFilled,
expectedBr,
expectedDiv,
expectedCellEmpty,
expectedCellFilled,
}) => {
const field = mount(<Field field={inputFilled} />);
expect(field.find('p').length).toBe(expectedBr);
expect(field.find('.cell').length).toBe(expectedDiv);
expect(field.find('.cell-empty').length).toBe(expectedCellEmpty);
expect(field.find('.cell-filled').length).toBe(expectedCellFilled);
},
);
17 changes: 17 additions & 0 deletions src/lesson4/Field.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React, { FC } from 'react';
import { Cell } from './Cell';
import './Field.css';
import type { FieldProps } from './Interfaces';

const Field: FC<FieldProps> = ({ field }) => (
<div className="field">
{field.map((row, y) => [
...row.map((filled: boolean, x) => (
<Cell key={`${x}_${y}`} filled={field[y][x]} x={x} y={y} />
)),
y !== row.length - 1 ? <p key={y} /> : null,
])}
</div>
);

export { Field };
3 changes: 3 additions & 0 deletions src/lesson4/GameOfLifeProto.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.btn {
margin: 20px 0;
}
18 changes: 18 additions & 0 deletions src/lesson4/GameOfLifeProto.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';
import { withKnobs, number } from '@storybook/addon-knobs';
import { Field } from './Field';
import { GameOfLifeProto } from './GameOfLifeProto';

// eslint-disable-next-line no-restricted-syntax
export default {
title: 'Lesson 4 / GameOfLifeProto',
decorators: [withKnobs],
};

export const GameOfLifePrototip = () => (
<GameOfLifeProto
columns={number('columns', 20)}
rows={number('rows', 20)}
fieldComponent={Field}
/>
);
5 changes: 5 additions & 0 deletions src/lesson4/GameOfLifeProto.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react';
import { mount, shallow } from 'enzyme';
import GameOfLifeProto from './GameOfLifeProto';

describe('GameOfLifeComponent testing', () => {});
70 changes: 70 additions & 0 deletions src/lesson4/GameOfLifeProto.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React from 'react';
import './GameOfLifeProto.css';

type FieldPropsComponent = React.FC<{
field: boolean[][];
}>;

interface FieldPropsInterface {
rows: number;
columns: number;
fieldComponent: FieldPropsComponent;
}

interface FieldState {
fieldState: boolean[][];
}

const cellGridFillRandom = (
rows: number,
columns: number,
cellStatus = () => Math.random() < 0.3,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

а зачем ты эту функцию несколько раз инлайново определяешь?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вроде один раз же определил в этом компоненте? Или я недопонял вопроса(

) => {
const grid: boolean[][] = [];
for (let y = 0; y < rows; y++) {
grid[y] = [];
for (let x = 0; x < columns; x++) {
grid[y][x] = cellStatus();
}
}
return grid;
};

class GameOfLifeProto extends React.Component<FieldPropsInterface, FieldState> {
private fieldComponent: FieldPropsComponent;

constructor(props: FieldPropsInterface) {
super(props);
this.fieldComponent = props.fieldComponent;
this.state = {
fieldState: cellGridFillRandom(this.props.rows, this.props.columns),
};
}

public onClick() {
this.setState(() => {
const cloneFieldState = cellGridFillRandom(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

на сколько я вижу, здесь коллбэк не обязателен

this.props.rows,
this.props.columns,
);

return {
fieldState: cloneFieldState,
};
});
}

render() {
const FieldComponent = this.fieldComponent;
return (
<>
<FieldComponent field={this.state.fieldState} />
<button className="btn" onClick={() => this.onClick()}>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ты в конструкторе завязал контекст у метода - для чего?

я к тому, что тут можно обойтись без стрелочной функции

Copy link
Owner Author

@mkremnev mkremnev Aug 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я заготовку начал делать видимо для метода, который будет при клике возвращать координаты ячейки и видимо забыл убрать, я уберу эту привязку

{'Обновить'}
</button>
</>
);
}
}

export { GameOfLifeProto };
9 changes: 9 additions & 0 deletions src/lesson4/Interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export interface CellProps {
filled?: boolean;
x?: number;
y?: number;
}

export interface FieldProps {
field: boolean[][];
}
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "ES2017" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
"target": "es5" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */,
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
// "lib": [], /* Specify library files to be included in the compilation. */
"allowJs": true /* Allow javascript files to be compiled. */,
Expand Down