An open API service indexing awesome lists of open source software.

https://github.com/ktsstudio/frontend-hw-2


https://github.com/ktsstudio/frontend-hw-2

Last synced: 4 months ago
JSON representation

Awesome Lists containing this project

README

          

# Начинающий React разработчик. Домашнее задание №2

В данном домашнем задании Вам необходимо реализовать React-компоненты для вашего будущего проекта.

[Макеты](https://www.figma.com/file/x10xReXUxSisyzDMjC0NPL/%D0%9F%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D1%8B-UIKit?type=design&node-id=0%3A1&mode=design&t=gXpqhNmAZawkzsB5-1)

**Требования:**

1. Все цвета и отступы должны быть заданы в переменных (указаны в макете)
![Переменные](./public//styles.png)

## Запуск тестов

Для запуска **всех тестов** выполняйте команду:

```
yarn test
```

Для запуска теста **отдельного компонента**:

```
yarn test:single <название компонента>
```

Например:

```
yarn test:single Card
```

### Как запустить скриншотный тест для отдельного компонента

- В WebStorm есть опция запуска теста внутри файла теста (иконка play слева от кода).
- В VSCode можно установить расширение Jest, которое позволяет запускать отдельные скриншотные тесты из меню расширения Jest. После установки зависимостей перезапустите VSCode, чтобы расширение проиндексировало файлы тестов.

> При этом необходимо на время закомментировать те тест-кейсы, которые не требуется прогонять (вызовы функции `screenshotTesting`). **Важно всё раскомментировать перед финальной общей проверкой и пушем в репозиторий.**

## 1. Loader

Реализуйте компонент Лоадер

```typescript
type LoaderProps = {
/** Размер */
size?: 's' | 'm' | 'l';
/** Дополнительный класс */
className?: string;
};
```

**Примеры использования:**

```typescript
// стандартный лоадер

// лоадер размера L
```

## 2. Text

Реализуйте компонент Text

**Требования:**

1. По умолчанию должен иметь цвет родителя
1. Пропс `weight` имеет больший приоритет чем `view`
1. При указании `tag` рендерится соответствующий тег, по умолчанию `p`

```typescript
type TextProps = {
/** Дополнительный класс */
className?: string;
/** Стиль отображения */
view?: 'title' | 'button' | 'p-20' | 'p-18' | 'p-16' | 'p-14';
/** Html-тег */
tag?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'div' | 'p' | 'span';
/** Начертание шрифта */
weight?: 'normal' | 'medium' | 'bold';
/** Контент */
children: React.ReactNode;
/** Цвет */
color?: 'primary' | 'secondary' | 'accent';
/** Максимальное кол-во строк */
maxLines?: number;
};
```

**Примеры использования:**

```typescript
Жирный текст
Заголовок
```

## 3. Icons

Реализуйте компоненты иконок. (Назвать их CheckIcon и ArrowDownIcon)

1. Все компоненты иконок лежат в директории `components/icons/` (Пример импорта: `import CheckIcon from 'components/icons/CheckIcon'`)
1. Все компоненты иконок имеют одинаковый базовый набор пропсов `IconProps`. (Лучше всего сделать компонент-обертку `Icon` и использовать в компонентах иконок, но это не обязательно).
1. По умолчанию имеют цвет родителя а при указании `color`, красятся в указанный стиль цвета.
1. Можно указать ширину и высоту иконки (по умолчанию 24px)

```typescript
type IconProps = React.SVGAttributes & {
className?: string;
color?: 'primary' | 'secondary' | 'accent';
};
```

**Примеры использования:**

```typescript

```

## 4. Button

Реализуйте компонент Кнопка

**Требования:**

1. Кнопка использует html-тег button и принимает все его пропсы
1. Кнопка принимает пропсы ButtonProps и удовлетворяет их требованиям, описанным ниже
1. Текст кнопки/дочерний элемент передается в качестве `children`
1. При передаче дополнительного `className` не должны сбрасываться внутренние (описанные вами в стилях) классы кнопки
1. Компонент должен быть реактивным, то есть реагировать на изменение любых пропсов
1. Для управления классами необходимо использовать библиотеку `classnames`
1. При loading=true, на кнопке должен появляться атрибут disabled

```typescript
type ButtonProps = React.ButtonHTMLAttributes & {
/** Состояние загрузки */
loading?: boolean;
/** Текст кнопки */
children: React.ReactNode;
};
```

**Примеры использования:**

```typescript
// Кнопка с текстом "Отправить", логирующая в консоль "Письмо отправлено" при клике
console.log('Письмо отправлено')}>
Отправить

// Кнопка, отображающая компонент Loader при загрузке каких-то данных

Отправить

// Кнопка с элементом в качестве содержимого

Модная кнопка

// Заблокированная кнопка с дополнительным классом

Отправить

// Кнопка с пропсом нативной кнопки
console.log('Убери от меня курсор!')}>
Отправить

```

## 5. Card

Реализуйте компонент Карточка (Элемент списка)

**Требования:**

1. Для изображения используется html-тег `img`
1. В заголовке может быть максимум 2 строки
1. В описании может быть максимум 3 строки
1. Контент над заголовком необязательный (кол-во строк не ограничено)
1. При клике на карточку должен выполняться `onClick`
1. Для текстов используется компонент `Text`
1. При расширении/сужении карточки, изображение должно сохранять пропорции

```typescript
type CardProps = {
/** Дополнительный classname */
className?: string;
/** URL изображения */
image: string;
/** Слот над заголовком */
captionSlot?: React.ReactNode;
/** Заголовок карточки */
title: React.ReactNode;
/** Описание карточки */
subtitle: React.ReactNode;
/** Содержимое карточки (футер/боковая часть), может быть пустым */
contentSlot?: React.ReactNode;
/** Клик на карточку */
onClick?: React.MouseEventHandler;
/** Слот для действия */
actionSlot?: React.ReactNode;
};
```

**Примеры использования:**

```typescript
console.log('Мандарин куплен!')}
/>

Марокко}
contentSlot={<>299р>}
actionSlot={В корзину}
/>
```

## 7. Input

Реализуйте компонент Поле ввода

**Требования:**

1. Необходимо использовать html-тег `input`
2. Должен быть слот для иконки справа

```typescript
type InputProps = Omit<
React.InputHTMLAttributes,
'onChange' | 'value'
> & {
/** Значение поля */
value: string;
/** Callback, вызываемый при вводе данных в поле */
onChange: (value: string) => void;
/** Слот для иконки справа */
afterSlot?: React.ReactNode;
};
```

**Примеры использования:**

```typescript
// Простое поле
console.log(value)}
/>

// Заблокированное поле с плейсхолдером
console.log(value)}
placeholder="Начните набирать свой вопрос"
disabled
/>

// Поле с иконкой
console.log(value)}
afterSlot={
/>
```

## 8. MultiDropdown

Реализуйте компонент Выпадающий список с множественным выбором (Фильтр).

**Требования:**

1. Должен использовать компонент `Input`
1. При вводе в поле, опции должны фильтроваться
1. Опции должны пропадать из DOM-дерева при клике вне поля

```typescript
type Option = {
/** Ключ варианта, используется для отправки на бек/использования в коде */
key: string;
/** Значение варианта, отображается пользователю */
value: string;
};

/** Пропсы, которые принимает компонент Dropdown */
type MultiDropdownProps = {
className?: string;
/** Массив возможных вариантов для выбора */
options: Option[];
/** Текущие выбранные значения поля, может быть пустым */
value: Option[];
/** Callback, вызываемый при выборе варианта */
onChange: (value: Option[]) => void;
/** Заблокирован ли дропдаун */
disabled?: boolean;
/** Возвращает строку которая будет выводится в инпуте. В случае если опции не выбраны, строка должна отображаться как placeholder. */
getTitle: (value: Option[]) => string;
};
```

**Примеры использования:**

```typescript
// Простой фильтр
console.log('Выбрано:', key, value)}
getTitle={() => ''}
/>

// Заблокированный фильтр
values.length === 0 ? 'Выберите город' : `Выбрано: ${values.length}`}
/>

// Фильтр, отображающий количество выбранных вариантов
`Выбрано: ${values.length}`}
/>
```

## 9. CheckBox

Реализуйте компонент Чекбокс

**Требования:**

1. Необходимо использовать html-тег `input` с типом "чекбокс"

```typescript
type CheckBoxProps = Omit<
React.InputHTMLAttributes,
'onChange'
> & {
/** Вызывается при клике на чекбокс */
onChange: (checked: boolean) => void;
};
```

**Примеры использования:**

```typescript
// Простой чекбокс

// Заблокированный чекбокс

```

## Перед отправкой ДЗ на проверку

1. Укажите личный ключ `user_token` в файле `config.yml`.
Пример `config.yml`:

```
user_token: e3631261-c636-42458-ab0b-g8e534e984ee
```

2. Выполните команду запуска тестов

```
yarn test
```

3. Если не прошел визуальный тест `screenshot.test.ts`

- Обновите Google Chrome до последне стабильной версии (>=110.0.5478.0)
- Убедитесь что не меняли файлы \*.stories.tsx
- Посмотрите различия в папке `src/__test__/__image_snapshots__/<НАЗВАНИЕ КОМПОНЕНТА>/__diff_output__` и исправьте их

4. При успешном прохождении тестов, отправьте изменения в свой репозиторий