Истории из контракта (references/contract-to-storybook.md)

Источник: ds-skills/core-ui-development-skills/src/skills/build-core-ui-components/references/contract-to-storybook.md — справочник скилла build-core-ui-components

Как из контракта компонента собрать Storybook. Правила самих историй — в Storybook и документация; здесь только то, что берётся из контракта.

Что чем становится

masters.defaultнабор args истории Default
axesargTypes с control: "select" и списком значений
axes[].defaultзначение оси в args по умолчанию
masters.rulesкакие сочетания вообще существуют: только их показывать в Common
masters.count и fullGridсколько мастеров есть против полной решётки — подсказка, насколько решётка неполна
props[] type: instanceслужебный story-проп с префиксом _
slots[].acceptsчто подставлять в служебный проп
sourceссылка «Дизайн» в docs.mdx
gapsничего; в историю не переносить, вынести в отчёт

Default

Одна история по базовому мастеру: значения осей — из masters.default, тексты — из props[].default.

Ничего сверх контракта в Default не добавлять: история должна показывать тот самый мастер, который дизайн считает исходным.

Common

Матрица вариантов строится по masters.rules, а не по полной решётке. Контракт прямо говорит, каких сочетаний не существует:

masters:
  count: 54
  fullGrid: 96
  rules:
    - if: {Skeleton: "True"}
      only: {Configuration: [Label Only], Contrast: [Low]}

Здесь 54 мастера из 96 возможных, и скелетон бывает только в одной конфигурации и одном контрасте. Показывать в Common сочетания, которых в макете нет, — значит придумать поведение, которого дизайн не задавал.

Расстояние между вариантами — не меньше var(--space-xl), как требует общее правило историй.

Служебные пропсы для подмены

Слоты подмены в код попадают пропсами-элементами, а в историю — булевыми переключателями с префиксом _. Контракт даёт и место, и умолчание:

props:
  - {name: Swap Left Container, type: instance, default: "18948:28840",
     controls: "Tag/Text Container/[Left Container]/✱ Icon Container"}
slots:
  - {name: Swap Left Container, path: "Tag/Text Container/[Left Container]", accepts: icon-container}

Служебный проп _showLeftIcon включает подстановку значка; сам значок берётся из библиотеки иконок по образцу соседних историй. Записать проп в EXCLUDED_ARG_TYPES, дать русское argTypes.name и исключить из публичной таблицы пропсов — по правилам исключаемых аргументов.

docs.mdx

Ссылку «Дизайн» собрать из source контракта: file — ключ файла, set или component — node-id с дефисом вместо двоеточия. Придумывать URL по-прежнему нельзя, но контракт — законный источник.

Раздел «Описание» показывает один Canvas: Common, если история есть, иначе Default.

card.version в контракте — версия карточки дизайна, не пакета и не компонента. В tags её не переносить: у нового компонента tags: ["version:1.0.0"].

Чего в историю не переносить

  • gaps — это дыры макета. В Storybook им не место; они идут в отчёт разработчика.
  • Значения, записанные в контракте числом вместо имени токена: показывать их как норму нельзя.
  • Оси, помеченные в gaps как устаревшие: например ось с крестом в имени (❌ Progress) означает, что дизайн её сам считает отжившей.
  • Формы forms как отдельные истории — только если так решено по правилам core-ui; сами по себе формы историями не являются.

Проверка

  • каждое сочетание в Common разрешено masters.rules;
  • значения осей в argTypes совпадают со списком axes[].values;
  • умолчания истории совпадают с masters.default и props[].default;
  • служебные пропсы с _ записаны в EXCLUDED_ARG_TYPES и не попали в таблицу пропсов;
  • ссылка «Дизайн» собрана из source, а не подставлена от соседнего компонента.