# Библиотека Styled-Components ## Строки-шаблоны Создаются наподобие обычных строк. Отличие только в кавычке: ```javascript const age = 34; const name = "John"; const html = '<div class="message">Hello</div>'; const message = `My name is ${name}, my age is ${age}`; ``` Принципиальная разница - возможность использовать подстановки выражений прямо в строке. Если значение не относится к строке, то осуществляется его неявное преобразование, у объектов вызывается метод *toString()* ## Функции-теги Позволяют модифицировать строку шаблон ```javascript const transform = () => { return 'darkness my old friend' } const message = transform`Hello`; ``` У таких функций существуют аргументы: ```javascript const transform = (expressions, ...substitutions) => { console.log(expressions, substitutions); return 'darkness my old friend...'; } const name = 'Vladimir'; const message = transform`Hello dear ${name}! I'm glad to see you`; console.log(message); ``` Аргументы функции-тега: - массив строк, между которыми стояли подстановки *${}* в исходной строке-шаблоне - значения, полученные в каждой из подстановок. Так как каждое из значений передаётся в отдельном аргументе, удобнее использовать оператор остатка (rest) ... Например, с помощью функций-тегов можно преобразовать шаблон в верхний регистр: ```javascript const uppercase = (strings, ...values) => strings .map((string, index) => { if (index > 0) { const lastValue = values[index - 1]; return lastValue.toUpperCase() + string; } return string; }) .join(''); const name = 'Илья'; const business = 'хороший человек'; const message = uppercase`Привет! меня зовут ${name} и я ${business}`; console.log(message); ``` ## CSS-in-JS, ещё раз Данный подход позволяет хранить CSS свойства в JS объекте. Ссылка на такой объект передаётся через props *style* ```js const labelStyle = { backgroundColor: 'rgba(0,0,0,.02)', color: 'rgba(0,0,0,.88)', fontSize: '14px' } ``` В JSX: ```jsx <label style={labelStyle}>Имя пользователя</label> ``` ## Препроцессоры При помощи препроцессоров или CSS-файла и технологии CSS Modules возможно выгрузить все классы в единый объект. Тогда стили вроде ```css .wrapper { display: flex; } ``` ```css .select { width: 100%; border: 1px solid #d9d9d9; border-left: none; border-radius: 6px; border-start-start-radius: 0; border-end-start-radius: 0; } ``` ```javascript import S from './CurrencySelect.module.scss'; ``` В JSX: ```jsx <CurrencyDropdown class={S.select} /> ``` Такой подход становится ещё более удобным при работе с библиотекой classnames ## Зачем нужен Styled Components Позволяет более естественно представлять стили, написанные в форме CSS in JS ## Установка npm: ```bash npm install --save styled-components ``` yarn: ```bash yarn add styled-components ``` ## Базовые приёмы Данный код создаст компонент с узлом div с указанным ниже кодом ```jsx import styled from 'styled-components'; const Wrapper = styled.div` display: flex; `; ``` После сборки проекта стили будут закреплены за элементом в виде CSS-класса. Полученный компонент можно использовать привычным способом ```jsx <Wrapper> <Label onClick={onLabelClick}> {label} </Label> </Wrapper> ``` ## Переиспользование стилей Для переиспользования стилей и узла другого компонента, можно вызывать styled как функцию: ```js const CurrencyDropdown = styled(Select)` width: 100%; border: 1px solid #d9d9d9; border-left: none; border-radius: 6px; border-start-start-radius: 0; border-end-start-radius: 0; `; ``` ## Использование props На основе значений, переданных в props компонента можно динамически менять стили: ```jsx const Button = styled.button` background: transparent; border-radius: 3px; border: 2px solid palevioletred; color: palevioletred; margin: 0 1em; padding: 0.25em 1em; ${props => props.primary && css` background: palevioletred; color: white; `}; ``` дополнительные стили со свойствами background и color будут доступны в данном случае: ```jsx <Button primary={true}>Click</Button> ``` ## Анимация Для анимации компонентов используется дополнительная функция *keyframes* ```js import styled, { keyframes } from 'styled-components'; ``` Далее анимация, заданная ранее через @keyframes в CSS задаётся через эту функцию: ```js const labelKeyframes = keyframes` to { opacity: 0; } `; ``` Чтобы подключить созданные ключевые кадры, необходимо их передать в исходную строку-шаблон: ```js const Label = styled.div` background-color: rgba(0,0,0,.02); color: rgba(0,0,0,.88); font-size: 14px; padding: 0 11px; display: flex; white-space: nowrap; align-items: center; border: 1px solid #d9d9d9; border-radius: 6px; border-start-end-radius: 0; border-end-end-radius: 0; animation: ${labelKeyframes} 1s ease-in-out alternate-reverse infinite; `; ``` ## Создание тем Для задания темы с основными параметрами (наподобие переменных в CSS или препроцессорах), используется компонент ThemeProvider. С его помощью props theme автоматически передаётся всем дочерним узлам ```jsx // Define our button, but with the use of props.theme this time const Button = styled.button` color: ${props => props.theme.fg}; border: 2px solid ${props => props.theme.fg}; background: ${props => props.theme.bg}; font-size: 1em; margin: 1em; padding: 0.25em 1em; border-radius: 3px; `; // Define our `fg` and `bg` on the theme const theme = { fg: "palevioletred", bg: "white" }; // This theme swaps `fg` and `bg` const invertTheme = ({ fg, bg }) => ({ fg: bg, bg: fg }); render( <ThemeProvider theme={theme}> <div> <Button>Default Theme</Button> <ThemeProvider theme={invertTheme}> <Button>Inverted Theme</Button> </ThemeProvider> </div> </ThemeProvider> ); ``` ## Хуки Альтернативный вариант использования темы - хуки withTheme и useTheme withTheme возвращает новый компонент с props theme, который наподобие ThemeProvider отправляется дочерним компонентам: ```jsx export default withTheme(MyContainerComponent) ``` Для получения информации о текущей теме, используется хук useTheme: ```jsx import { useTheme } from 'styled-components' const MyComponent = () => { const theme = useTheme() console.log('Current theme: ', theme) // ... } ```