Прежде чем перейти к статье, хочу вам представить, экономическую онлайн игру Brave Knights, в которой вы можете играть и зарабатывать. Регистируйтесь, играйте и зарабатывайте!
Привет, Хабр! Меня зовут Саша, я Full‑Stack разработчик, и последние 7 лет пишу фронтенд, 6 из которых я работаю в американском стартапе.
Думаю ни для кого не секрет, что бизнес процессы в стартапах, мягко сказать, хромают. Я же как оптимист вижу возможность в каждой трудности, поэтому всегда считал, что это отличная возможность проявить инициативу и попробовать что‑то автоматизировать или улучшить процессы команды (ну или хотя бы попробовать).
В прошлый раз я рассказывал Как автоматизировать использование дизайн токенов с помощью Stylelint и PostCSS. Сегодня хочу рассказать, как можно легко реализовать документацию для дизайн-токенов в Storybook, и заодно поделиться тем, как и почему я пытался это сделать, и что из этого вышло. Статья будет полезна для разработчиков, которые уже используют дизайн токены и ищут лёгкий способ их документации.
Наша команда разбросана по всему миру: кто-то в США, кто-то в России, а кто-то в Индии. В таких условиях эффективность коммуникации играет ключевую роль. Я бы даже сказал, что стоит минимизировать её там, где это возможно, чтобы получать ответы на вопросы, даже когда твой коллега крепко спит, например, с помощью документации.
Испокон веков, наш дизайнер использовал Sketch (после фотошопа, конечно), поэтому о том, чтобы наглядно посмотреть на цвета, шрифты и иконки, используемые в проекте, и речи не шло. С этим был связан ряд проблем:
Иногда разработчикам нужно реализовать какой-то небольшой интерфейс быстро и без помощи дизайнера. Например, запрототипировать редактор запросов в базу данных. В большинстве случаев достаточно использовать базовые компоненты, но порой нужно самостоятельно подобрать цвет фона, размер шрифта и прочее.
Иконки это отдельная боль, из‑за незнания, что какая‑то иконка уже есть в проекте — они часто дублируются. Или же дизайнер присылает немного видоизменённую иконку, и помимо дублирования, у нас появляются несколько вариаций одной и той же иконки.
Во время редизайна, у дизайнера нет простого способа проверить, что все цвета изменены корректно. Разве, что потыкать сам продукт.
Хотелось бы решить эту проблему, и голос в голове подсказывал «не придумывай лишнего, все дизайн токены есть прямо у нас в коде в виде LESS-переменных, иконки тоже там — используй их». И я начал искать.
Наверняка вы видели в различных библиотеках компонентов как всё удобно организованно:
на одной странице тебе цвета
на другой - иконки
на третьей шрифты
Ну не красота ли? Это именно то, что мне было нужно.
Вот так, например, выглядит палитра цветов на странице библиотеки material-ui,
а вот так выглядят иконки на сайте библиотеки ant-design.
Ещё одним способом, который мне попался на глаза, было использование сторибука. Это казалось самым логичным выбором, особенно учитывая, что к тому времени в команде мы уже худо-бедно использовали сторибук. С его помощью мы пытались решить схожую проблему, но на уровне базовых UI-компонентов.
Почему мы начали использовать сторибук
У нас бывали случаи, когда появлялось несколько кнопок или выпадающих меню, только из-за того, что мы не могли наглядно увидеть, какие базовые компоненты уже реализованы в проекте. Конечно, если бы мы все сидели в одном офисе, то такой проблемы бы не было, но это не наш случай. К тому же наша платформа пережила не одну миграцию, сейчас на фронте используется сразу JQuery и React, и её не получится запустить просто через npm start
. Поэтому мы решили добавить сторибук в надежде, что реализация компонентов внутри изолированного окружения сократит время их разработки.
Да и трудно найти более подходящее место для дизайн-токенов, чем разместить их рядом с библиотекой компонентов. Ведь по сути, дизайн-токены – самое маленькое, атомарное переиспользуемое правило, аналогично переиспользуемым компонентам, и именно тут ему и место. Поэтому я начал копать в этом направлении.
Встроенные компоненты сторибука
Разработчики сторибука и сами прекрасно понимают, что он является отличным местом для документирования дизайн токенов, поэтому в пакете @storybook/blocks
есть встроенные компоненты для отображения цветов, шрифтов и иконок:
ColorPalette
IconGallery
Typeset
Вот так, например, выглядит компонент ColorPallete.
Но у этих компонентов довольно ограниченное применение, ведь это обычные React-компоненты. Например, как вам передать все ваши цвета в компонент ColorPalette, если вы используете CSS/LESS/SASS-переменные? Не копи-пастить же.
На сайте сторибука есть витрина, где можно посмотреть как выглядят дизайн системы компаний, использующих сторибук. Многие из них пишут собственные решения для отображения дизайн токенов, вот лишь несколько примеров:
Цвета гитлаба
Иконки графаны
Цвета, шрифты и тени Fluent UI
Но нам же нужно фичи пилить, а не заниматься написанием собственных велосипедов. Поэтому хотелось бы использовать что-то готовое, чтобы вжух и всё работает.
Обзор аддона storybook-design-token
Через некоторое время поисков я наткнулся на аддон для сторибука storybook-design-token, тут есть демо.
Как написано в репозитории, он позволяет отображать документацию для дизайн-токенов на основе ваших стилей и файлов иконок (голос в голове не подвёл).
Давайте посмотрим на его основные возможности.
Подключение
В первую очередь вам нужно установить аддон и добавить его в конфиг сторибука.
pnpm i -D storybook-design-token
module.exports = {
addons: ['storybook-design-token']
};
Настройка
Затем нужно объяснить аддону, какие дизайн токены он должен отобразить в сторибуке, и указать их тип. Для этого мы должны сгруппировать токены по типу:
положить цвета рядом с другими цветами,
шрифты со шрифтами,
и так далее.
Для каждой группы необходимо задать 2 настройки:
tokens – название группы
presenter – можно сказать, что это тип токенов
Также можно указывать презентера внутри комментариев отдельно для каждого токена, но это получается достаточно многословно. Аналогично для каждого токена можно добавить описание в виде комментария, которое будет доступно в сторибуке.
Вот пример кода с описанными настройками:
:root {
/**
* @tokens Animations
* @presenter Animation
*/
--animation-rotate: rotate 1.2s infinite cubic-bezier(0.55, 0, 0.1, 1);
/**
* @tokens Colors
* @presenter Color
*/
--b100: hsl(240, 100%, 90%); /* Token Description Example @presenter Color */
--b200: hsl(240, 100%, 80%);
--b300: hsl(240, 100%, 70%);
/**
* @tokens Others
*/
--border-normal: 3px dashed red; /* Token Description Example @presenter BorderRadius */
}
В сторибуке дизайн токены будут отображены вот так:
Презентер – это UI-компонент, который умеет отображать дизайн токен. Например, один презентер умеет отображать цвет, второй – тень, третий – прозрачность и т.д.
Тут могло показаться, что аддон мог бы сам сгруппировать токены и разобраться, где находятся цвета, где шрифты, а где бордеры и применить соответствующий токен.
Действительно, иногда так и есть, но как понять, что означает 16px
? Это может быть как отступ, так и размер шрифта, поэтому здесь необходимо самостоятельно задать тип презентера.
Также, может быть полезно разбить цвета на несколько групп, например, чтобы отобразить отдельно цвета для светлой и тёмной тем.
DesignTokenDocBlock
Помимо панели, аддон предоставляет компонент DesignTokenDocBlock
, который можно использовать в MDX документации. Он позволяет отображать одну из групп токенов.
<DesignTokenDocBlock categoryName="Colors" maxHeight="none" viewType="table" />
У компонента DesignTokenDocBlock
, есть одно преимущество, он поддерживает кастомные презентеры, что позволяет:
указывать собственные презентеры, что может быть полезно, если нужный презентер не реализован,
переопределять существующие презентеры, если вас не устраивает реализацию по‑умолчанию.
Эта функция доступна в 3-й версии аддона, которая пока находится в бете.
“Живые” CSS переменные
Мы как разработчики привыкли открывать дев тулзы и налету менять стили, поэтому для нас тут не много нового. Но эта функция может быть полезна менее технически подкованным членам команды, например, дизайнерам или тестировщикам.
Если мы пользуемся CSS‑переменными, мы можем налету обновлять их значения и увидеть как это повлияет на наш компонент.
Принцип работы
Работает аддон достаточно просто:
PostCSS находит в файлах стилей комментарии с именами категорий и презентеров
По указанному пути аддон находит все png, gif, jpeg и svg файлы
Функция
generateTokenFilesJsonString
, объявленная вplugin.ts
, из всей этой информации создаёт файлdesign-tokens.source.json
Все эти шаги происходят на этапе, когда у нас есть доступ к файловой системе — на уровне webpack или vite плагинов.
Далее, когда сторибук запустился, файл design-tokens.source.json
скачивается и отображается в виде таблицы или карточек.
Ограничения
Аддон не получится использовать в проекте с CSS-in-JS, потому что текущая реализация поддерживает только CSS, LESS и SASS. Но в случае с CSS-in-JS, гораздо проще реализовать кастомный UI, потому что все дизайн токены уже объявлены в JavaScript, и нам не нужно парсить файлы стилей. Пример реализации, где используется styled-components можно подсмотреть в сторибуке akeneo-design-system (исходники). Но в любом случае, это дополнительная работа.
Пока писал статью, подумал, что для проектов с CSS‑in‑JS было бы полезно переиспользовать UI‑компоненты аддона. Если вам это интересно — оставьте коммент или напишите в личку хабра — попробуем реализовать.
Как я подключал аддон
Аддон достаточно прост в использовании, поэтому вы можете быстро начать его использовать в своём проекте. Дальше я опишу, как я подключал аддон и с какими трудностями столкнулся, а вы сможете глубже познакомиться с его возможностями и поймёте, что делать, если вам чего‑то в нём не хватает.
CSS комментарии
После того как я нашёл аддон, я на радостях открыл инструкцию и начал его подключать: указал все настройки, запустил, и сразу же вылетела ошибка
Unknown word. You tried to parse Less with the standard CSS parser; try again with the postcss‑less parser
Ну было бы странно, если бы всё сразу же заработало. Оказывается в CSS не поддерживаются однострочные комментарии «//
», поэтому PostCSS не может распарсить стили и валится с ошибкой. Благо, что в самом сообщении написано решение, поэтому исправил очень быстро, правда вместо postcss‑less подошёл и postcss‑scss парсер. Идём дальше.
SVG иконки
Теперь когда всё завелось, можно было начать указывать названия групп и презентеров, но постойте ка, почему я не вижу ни одной svg? Оказалось, что аддон отображает лишь те svg, у которых задан либо атрибут id
, либо data-token-name
.
Модифицировать, сотни svg файлов, чтобы отобразить их в сторибуке казалось довольно глупым решением. Да и никто будет следить, чтобы все новые иконки, которые мы добавляем, также имели эти атрибуты.
В общем, такой подход довольно сложно поддерживать, поэтому это я тоже решил исправить. Ведь зачем нам аттрибуты, если у нас есть имя файла?
И снова изменений одна строчка, а польза огромная.
Кстати, SVG также можно разбивать на категории с помощью атрибута data-token-category
и добавлять описание с data-token-description
, не уверен, что очень полезно, но возможность такая есть.
PNG иконки
Наш проект достаточно старый, он уже пережил 2 миграции:
с Silverlight на JQuery
а теперь с JQuery на React.
Поэтому помимо svg, у нас много png и gif иконок. Их, конечно, тоже нужно обязательно отобразить!
В целом задачка немного посложнее, по крайней мере, нужно изменить не 2 строчки как в прошлый раз. Тут нам потребуется добавить новый парсер для иконок, который будет считывать *.png, *.jpeg, *.gif файлы. Далее нужно конвертировать их в base64, чтобы добавить иконки в design-tokens.source.json
, аналогично другим токенам.
Отлично, эта проблема также решена.
Поиск
В нашем проекте 2605 svg иконок и 1001 png иконка (я не поленился и посчитал), и без поиска отображать все эти иконки достаточно бесполезное занятие. Поэтому поиск также добавляем.
Кастомные презентеры
Как вы поняли, чтобы интегрировать аддон в наш проект, мне пришлось, засучив рукава, немного поконтрибьютить. Но, на самом деле, я делал это не только потому что так сильно хотел интегрировать аддон.
Я давно хотел внести свой вклад в какой-то OpenSource проект, и тут мне представилась отличная возможность. Поэтому, сперва я исправил баги и реализовал фичи, которые были нужны для интеграции аддона, а затем начал работать над интересными ишью, которые создавали другие пользователи. Одним из таких ишью были кастомные презентеры, о которых мы говорили в самом начале.
Если вы пишете на React, то должны быть знакомы с техникой Render Props, которая по сути является реализацией слотов в реакте. Слоты позволяют подменить дефолтную реализацию какой-то внутренней части компонента. Этот подход, очень популярен в библиотеке material-ui, где почти у каждого компонента есть свойство slots
(раньше свойство называлось components
).
Так к чему это я всё, реализация кастомных презентеров — это идеальный пример, где можно применить паттерн со слотами.
Возьмём банальный пример — нам не нравится стандартное отображение цветов, и мы хотим чтобы они отображались не прямоугольниками, а кружками, мы можем переопределить реализацию следующим образом.
// CircleColorPresenter.jsx
import React from 'react';
export function CircleColorPresenter({ token }) {
return (
<div
style={{
width: 30,
height: 30,
borderRadius: '50%',
background: token.value
}}
></div>
);
}
// ColorsDocs.mdx
import { DesignTokenDocBlock } from 'storybook-design-token';
import { CircleColorPresenter } from './CircleColorPresenter';
<DesignTokenDocBlock
categoryName="Colors"
viewType="card"
presenters={{ Color: CircleColorPresenter }}
/>;
Выглядит это вот так:
Здесь можно посмотреть полную реализацию.
Ну а что в итоге?
Теперь хотелось бы немного подытожить.
Если читать статью, то кажется, что на всё про всё ушло пару недель, но это далеко не так. Иногда можно достаточно долго ждать фидбэка на созданное ишью или на открытый пул‑реквест. Были случаи, когда мои пул‑реквесты мержились меньше чем за неделю, а бывало, когда я ждал 4 месяца. Поэтому тут нужно терпение, ведь разработчику аддона за это не платят, это не его основная работа.
В конце хотелось бы написать, как я со всем справился, всех победил, всё интегрировал и вся слава мне, прям как в сказках. Но настоящая жизнь, совсем не сказка, у всех таски, релизы, дедлайны и не до всяких сторибуков. Поэтому аддон всё ещё не интегрирован, несмотря на то, что всё готово и работает. Дольше интеграции аддона может быть лишь согласование, особенно когда команда состоит из нескольких подкомманд с разными часовыми поясами, разным менталитетом и приоритетами. Поэтому следующий не менее важный шаг — обсудить всё с командой и принять решение, будем ли мы интегрировать аддон.
Будет круто, если расскажете в комментариях, как вы отображаете аддоны в своей команде и какие инструменты используете. Если у вас возникнут проблемы при использовании аддона – создайте ишью или напишите мне, чем смогу – помогу.
Если вы узнали что-то новое и вам понравилась статья, в качестве благодарности можете поставить звёздочку аддону или подписаться на мой телеграмм канал.