В прошлом посте я рассказывал про Vanilla Extract (VE) и его возможности. В частности, упоминал такие инструменты для построения дизайн-систем, как
sprinkles и recipes.Сегодня расскажу о том, как построить на основе Vanilla Extract свою дизайн-систему на примере моей библиотеки компонентов Vanilla Sugar для React.
Дисклеймер: этот пост скорее демонстрация возможностей Vanilla Extract и описание основных концепций, которые лежат в основе библиотеки компонентов, чем описание готового продукта. Пост будет интересен тем, кто ищет новые подходы в разработке UI.
Ссылка на библиотеку: https://github.com/alexgriss/vanilla-sugar.
➖➖➖
Основные концепции библиотеки
• Дизайн-токены как основа •
Библиотека построена на основе централизованной системы токенов. В
src/tokens.ts определены все дизайн-константы: цвета, брейкпоинты, отступы, размеры и т.д. Дизайн-токены — это фундамент типобезопасности всей дизайн-системы.const colors = {
primary: "#78B64C",
secondary: "#3C3C3C",
tertiary: "#EDEDED",
// ...
} as const;
const fontWeights = {
normal: "400",
medium: "500",
bold: "700",
} as const;
// ...• Темы •
Чтобы дизайн-токены начали работать с VE, нужно создать тему. Это позволит автоматически сгенерировать глобальные CSS-переменные для всех токенов. Тем может быть сколько угодно, у меня пока одна:
import { createGlobalTheme } from "@vanilla-extract/css";
import { tokens } from "./tokens";
export const vars = createGlobalTheme(":root", tokens);В результате VE создаст CSS-переменные вроде
--colors-primary__1q5vhka6: #78B64C;, которые можно будет использовать в любом месте.• Атомы •
Для создания атомарных стилей используется пакет
@vanilla-extract/sprinkles. С его помощью можно сгенерировать собственную систему утилитарных классов (как в Tailwind), но сразу с привязкой к токенам темы.В
src/props.ts я описываю конфиги для генерации наборов классов: для цветов, типографики, размеров и отступов, а также для часто используемых свойств разметки блоков. Дополнительно можно генерировать классы для media/feature/container‑запросов или для разных селекторов состояний.Самое приятное — это возможность задать короткие алиасы для свойств, которые потом можно передавать прямо в пропсы компонентов, как в Chakra UI. Настройку
sprinkles можно посмотреть в файле src/sprinkles.css.ts.• Полиморфный компонент Box •
Все React-компоненты библиотеки строятся на базе полиморфного компонента
Box (аналогичный компонент есть, например, в Chakra UI). Это фундамент дизайн-системы: по умолчанию он рендерит <div />, но поддерживает свойство as для изменения тега в конечном элементе. Разбор реализации такого компонента можно найти в этом исчерпывающем гайде.Примеры использования
Box:<Box as="button" type="submit">Кнопка</Box>
<Box as="ul">
<Box as="li">Item</Box>
<Box as="li">Item</Box>
</Box>
А благодаря
sprinkles стили можно задавать пропсами (с поддержкой адаптивности):<Box
as="button"
type="submit"
bg="primary"
color="secondary"
py={16}
px={[8, 16, 32]}
w={{ mobile: 96, tablet: 192, desktop: 256 }}
>
Кнопка
</Box>
• Рецепты •
Ещё одна киллер-фича VE — это
@vanilla-extract/recipes. Рецепты позволяют описывать предустановленные варианты стилей для одного компонента и переключать их простыми пропсами.В моей UI-библиотеке с помощью рецептов полностью реализован компонент
Button:<Button variant="primary" size="small">
Кнопка
</Button>
<Button variant="outline" size="large">
Кнопка
</Button>
Все эти концепции вместе позволяют построить type-safe UI-библиотеку любой сложности. Самое трудное — реализовать базовые блоки, а дальше любые компоненты будут строиться как конструктор из настроек дизайн-системы.
В библиотеке уже есть базовый набор «кристаллов» (я назвал так UI-блоки, продолжая кондитерскую тему VE ♥️) с демкой в Storybook. Потестировать библиотеку можно, просто склонировав её к себе в проект.
➖➖➖
Напишите в комментах, стали бы использовать подобную библиотеку в своём проекте?