# Библиотека 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)
// ...
}
```