# 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} > ... ```