Йо-йо! Представьте вам нужно создать компонент для uikit’а, который может быть с разным тэгом. Допустим это будет компонент, который может возвращать h2, h3, p или span тэг, при этом у них могут быть разные свойства, ну и плюс вы не хотите чтобы были разные варнинги)) Писать я буду на typescript
type TTypography = { tag?: 'p' | 'h2' | 'h3' | 'span' | 'h1' | children?: React.ReactNode fontSize?: string, lineHeight?: string, primary?: boolean, secondary?: boolean, white?: boolean, link?: boolean, bold?: boolean } & React.HTMLAttributes<HTMLElement>
Кроме свойства tag нам обязательно нужно только children, собственно это будет наш текст.
Для автоматической генерации нам нужно импортировать:
import React from 'react' import styled from 'styled-components'
И так самое основное. Styled может работать как функция и этим мы воспользуемся (но медленно по шагам):
export const Typography = styled((data: TTypography) => ..... )` /* стили для элемента*/`
Из этой функции мы должны вернуть элемент реакта.
export const Typography = styled(({tag, children, fontSize, lineHeight, primary, secondary, white, link, bold, ...other}: TTypography) => React.createElement(tag = 'p', other, children) )``
Давайте разберём, что здесь происходит. Мы деструктуризировали объект со свойствами, которые к нам придут и которые мы явно объявили в нашем типе. Свойства, которые унаследованы от React.HTMLAttributes<HTMLElement>, мы передали в React.createElement как пропсы, которые передадутся нашему компоненту. Так мы сможем передавать, например, синтетические события типа onClick
Далее у нас осталось только добавить стилей в зависимости от наших пропсов.
export const Typography = styled(({tag, children, fontSize, lineHeight, primary, secondary, white, link, bold, ...other}: TTypography) => React.createElement(tag = 'p', other, children) )` font-family: 'ALS_sans'; font-weight: ${({ bold }) => bold ? 'bold' : 'normal'}; margin-top: 0; margin-bottom: 0; ${props => props.primary && css` color: ${({ theme }) => theme.colors.black}; `} ${props => props.secondary && css` color: ${({ theme }) => theme.colors.grayBlue}; `} ${props => props.white && css` color: ${({ theme }) => theme.colors.white}; `} ${props => props.link && css` color: ${({ theme }) => theme.colors.greenDark}; font-weight: bold; cursor: pointer; `} ${props => props.tag === 'h1' && css` font-size: 24px; line-height: 28px; font-weight: bold; `} ${props => props.tag === 'h2' && css` font-size: 20px; line-height: 28px; font-weight: bold; `} ${props => props.tag === 'h3' && css` font-size: 16px; line-height: 20px; font-weight: bold; `} ${props => props.fontSize && css` font-size: ${props.fontSize}; `} ${props => props.lineHeight && css` line-height: ${props.lineHeight}; `} overflow: hidden; text-overflow: ellipsis; white-space: nowrap; `'