# Margins and paddings
История о том, как стандартизировать и типизировать отступы, назовем их "gaps".
## Как сейчас
```@javascript
import { Text } from 'UIKit';
...
<Text size="m" mt={10}>какой-то текст</Text>
...
```
Margin top (mt) тут записан фиксировано, 10px.
При этом в компоненте UIKit/Text мы просто формируем inline styles из значений `mt`,
```@javascript
const styles = { marginTop: mt }
<TextComponent
...
styles={styles}
>
```
### Проблемы
1. Inline стили. Не кешеруются, просто хочется уйти от них.
2. **Абсолютное значение** марджина, в данном случае в пикселях. Это по сути хардкод.
3. Нет вариативности в зависимости от разрешения.
На мобиле, планшете, десктопе всегда будет 10px.
## Как хочется?
Допустим, на мобильном мы хотим 10px, а на устройствах больше 15px.
### Варианты решения
1. Добавить css-module и явно описать в нем размеры.
```@typescript
// styles.module.css
.text {
@media (--mobile) {
margin-top: 10px;
}
@media (--tabletMin) {
margin-top: 15px;
}
}
// TextBlock.tsx
import styles from 'styles.module.css';
const TextBlock = ({children}) => {
return <Text className={styles.text}>{children}</Text>
}
```
Минусы такого подхода - на каждый ~~чих~~ марджин/паддинг нам нужно создавать файл css модуля, импортировать его и использовать в компоненте. При этом нам просто нужнен стандартное значение отступа, из стандартной сетки дизайн-системы.
2. Описать все стандартные отступы один раз и использовать в компоненте.
```@javascript
import { Text } from 'UIKit';
...
<Text
size="m"
mt={{
mobile: "m",
tabletMin: "l"
}}>какой-то текст</Text>
...
```
---
## Решение (WIP)
1. Создаем css-переменные для gaps.
Конкретный ряд зависит от "темы", или у нас - это area. Сейчас он одинаков для ИЦ, Авито, но может быть свой у каждой area.
```
:root {
--gap-3xs: 2px;
--gap-2xs: 4px;
--gap-xs: 8px;
--gap-s: 10px;
...
}
```
2. Описываем их в ts.
Вручную через union type, либо как-то автоматически по ключам из css-файла.
```
export type TGap =
| '3xs'
| '2xs'
| 'xs'
...
```
3. Создаем css-файл margins.css описывающий все кейсы
Можно попробовать использовать postcss плагины, чтобы не писать вручную.
```
.mt-3xs {
margin-top: var(--gap-3xs);
}
.mt-m {
margin-top: var(--gap-m);
}
...
.mb-3xs {
margin-bottom: var(--gap-3xs);
}
...
.ml-3xs {
margin-left: var(--gap-3xs);
}
...
.mr-3xs {
margin-right: var(--gap-3xs);
}
@media (--mobile) {
.mt-mobile-3xs {
margin-top: var(--gap-3xs);
}
...
.mt-mobile-m {
margin-top: var(--gap-m);
}
}
...
```
4. В компонент из UIKit добавляем пропсы из интерфейса IMarginProps
```@typescript
import { SCREEN_SIZE_NAMES } from '../../constants'
import { TGap } from '../gaps/gaps'
type Keys = keyof typeof SCREEN_SIZE_NAMES
type TScreenSize = typeof SCREEN_SIZE_NAMES[Keys]
export type TMargin = TGap
export type TPadding = TGap
type TMarginProp = TMargin | Partial<Record<TScreenSize, TMargin>>
type TPaddingProp = TPadding | Partial<Record<TScreenSize, TPadding>>
export interface IMarginProps {
mt?: TMarginProp
mb?: TMarginProp
ml?: TMarginProp
mr?: TMarginProp
pt?: TPaddingProp
pb?: TPaddingProp
pl?: TPaddingProp
pr?: TPaddingProp
}
```
И в зависимости от установленных пропсов, добавляем нужные classNames
```@typescript
const { mt, mb, mr, ml, pl, pt, pr, pb, ...restProps } = props
const marginProps = { mt, mb, mr, ml, pl, pt, pr, pb }
const marginStyles = useMemo(
() => getMarginClassNames(marginProps),
[marginProps]
)
return (
<C
className={cn(
className,
styles.text,
styles[`size-${size}`],
styles[`variant-${variant}`],
...marginStyles
)}
{...restProps}
>
...
```