vienna.ui-theme v4.17.0
Изменение внешнего вида компонентов
Raiffeisenbank Design System
Основные определения
Архитектура внешнего вида компонент строится на трех сущностях: токены, пресеты и темы. Разберем их поподробней.
Токены
Токены – это атомарная сущность, переменные с одним конкретным, неделимым значением. Для веба токен конвертируется в значение, которое может принимать css-свойство. Токены Дизайн-системы сгруппированы в смысловые группы и собраны в один json объект.
Например, так выглядит группа размерных токенов, каждый из размеров является отдельным токеном.
{
"layout": {
"size": {
"xxxs": "8px",
"xxs": "12px",
"xs": "24px",
"s": "32px",
"m": "36px",
"l": "40px",
"xl": "48px",
"xxl": "52px"
}
}
Следует обратить внимание, что имена токенов несемантичны, они или полностью абстрактны, как в токенах цветов, или описывают значение токена, но они никак не определяют, как будет использоваться данный токен. Это позволяет использовать их в любом контексте.
Токены хранятся в пакете vienna.tokens
, их можно импортировать как json-объект из tokens.json или как js-модуль из tokens.js.
Пресеты
Пресеты – это дополнительный уровень абстракции между компонентом и настройками его отображения. Пресет - это именованный блок css-кода, который используется компонентом, как единое целое.
Например:
Button.styles.tsx
const presets = getPresets('button', {
base: null,
design: 'design',
loading: null,
});
export const Box = styled.button`
${presets.base}
${presets.design}
${({ isLoading }) =>
isLoading &&
css`
${presets.loading}
`}
`;
Как видно из примера, компонент абстрагирован от конкретных значений пресета, его логика компонента никак не зависит от этого значения. Пресет используется, как фрагмент css, который вставляется в конкретный участок css-кода компонента. Таким образом, изменяя значение пресетов, мы можем управлять css-кодом компонента и соответсвенно его внешним видом.
Тема
Тема – это то, что связывает пресеты и токены между собой. Она определяет конкретные значения пресетов компонента. Тему дизайн-системы можно представить, как совокупность тем всех её компонентов. Технически тема – это json объект, который содержит все пресеты для всех компонентов и использует токены для определения значений этих пресетов.
Например, для приведенных выше пресетов кнопки дефолтная тема будет выглядеть так:
"button": {
"base": {
"border-radius": "8px",
"border-color": "transparent",
"font-family": "ALS Hauss, Helvetica, 'Helvetica New', Arial, sans-serif",
"font-weight": "500",
"text-decoration": "none",
"transition": "background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease"
},
"design": {
"accent": {
"color": "#2B2D33",
"background-color": "#FEE600"
},
"primary": {
"color": "#FFFFFF",
"background-color": "#2B2D33"
},
},
"loading": {
"cursor": "default",
"color": "transparent",
"transition": "none"
},
}
Дефолтная тема дизайн-системы хранится в пакете vienna.ui-theme
. Как и токены ее можно импортировать как json-объект (presets.json) и как js-модуль (presets.js).
Theme Provider
Таким образом, изменение внешнего вида компонента сводится к нахождению нужного пресета и переопределению его значения. Для этого мы используем встроенный инструмент styled components, называющийся ThemeProvider.
ThemeProvider построен на использовании context API, так, что, переданная ему тема, будет доступна всем вложенным компонентам, независимо от уровня вложенности. При использовании ThemeProvider всем дочерним компонентам приходит дополнительный атрибут theme. При попытке компонента получить каждый пресет, он вначале ищется в теме, переданной в ThemeProvider и, если данного пресета в этой теме нет, используется значение из дефолтной темы ДС.
В ThemeProvider можно обернуть как приложение целиком, и таким образом переопределить внешний вид всех инстансов компонетов дизайн-системы, так и только участок кода (отдельную страницу или участок кода на ней) и переопределить компоненты только в ограниченном контексте.
Например, для кнопки выше:
import { ThemeProvider } from 'vienna-ui';
const theme = {
button: {
design: {
accent: {
color: 'white',
backgroundColor: 'blue',
},
},
},
};
return (
<ThemeProvider theme={theme}>
<Button design='accent'>Test</Button>
</ThemeProvider>
);
Теперь все акцентные кнопки внутри ThemeProvider будут белым цветом текста на синем фоне.
Пресет в теме, переданной в ThemeProvider переписывает дефолтный пресет целиком. Для примера выше, важно переписать, как значение color, так и backgroundColor. Если передать пресет, например, только с 'color', значение цвета фона для данной кнопки будет потеряно.
Пресет custom
В дополнение к стандартным пресетам, экспортируемым темой, компонент использует custom пресеты. Данные пресеты отсутствуют в дефолтной теме ДС, поэтому значения этих пресетов в компонентах по умолчанию пустое. Но указав его значение в ThemeProvider можно переписать все дефолтные стили компонента. Custom пресеты в стилях компонента всегда идут самыми последними, это позволяет значениям этих пресетов переписать все css-свойства заданые выше.
Например, для нашего примера с кнопкой:
import { ThemeProvider } from 'vienna-ui';
const theme = {
button: {
custom: {
fontWeight: 'bold',
},
},
};
return (
<ThemeProvider theme={theme}>
<Button design='accent'>Test</Button>
</ThemeProvider>
);
После этого все кнопки, объявленные внутри ThemeProvider, будут с толстым начертанием текста. Custom-пресеты – это самый простой способ переопределить внешний вид компонента.