Контракт компонента как источник задачи (references/design-contract.md)

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

Контракт — машинное описание компонента, снятое с макета и проверенное валидатором: один файл components/<slug>.yaml в базе ds-docs/component-contracts. Он заменяет чтение макета глазами: состав, свойства, токены и правила уже разобраны и сверены с Figma.

Контракт только читать. Он лежит в чужом репозитории и правится дизайн-стороной; замечания к нему возвращать текстом, а не правкой файла.

Если контракта на компонент нет — работать по макету обычным порядком.

Что в контракте есть

sourceфайл Figma, id набора или секции, страница
axesоси вариантов: имя, значения, значение по умолчанию
propsсвойства компонента в макете: текст, булев переключатель, подмена
slotsместа подмены и что туда принимается (accepts)
mastersсколько мастеров есть, сколько дала бы полная решётка, rules — какие сочетания существуют
tokensтаблицы «значение оси → имя токена»
bindings$имя — ссылка на таблицу токенов, чтобы не повторять её в дереве
anatomyдерево узлов базового мастера: раскладка, размеры, заливки, текст
variantsчем остальные мастера отличаются от базового: set, add, remove, swap, replace, move
formsнесколько базовых деревьев под одной шапкой, если у семейства разные конструкции
interactionвиброотклик: жест, событие, идентификатор, включён ли
gapsдыры макета: GAP — в источнике нет, SUSPECT — есть, но подозрительно

Соответствие контракта и кода

axes[].nameсловарь as const в constants.ts плюс тип через TValues
axes[].defaultзначение по умолчанию в деструктуризации пропсов
props[] type: textстроковый проп
props[] type: booleanбулев проп
props[] type: instance + slots[].acceptsпроп ReactElement<IconProps> или children — по образцу соседей
masters.rulesдопустимые сочетания: отражать в типах или в логике, а не воспроизводить несуществующие
ось Type Scaleвид под крупную типографику — не проп продукта, см. правила чтения ниже
tokens.* со значением вида space-xsvar(--space-xs) в SCSS
layout.gap, layout.paddinggap, padding модуля стилей
size.width: fill / hugрастяжение и хват по образцу соседних компонентов
fill, stroke.color, text.colorцветовые токены темы
radiusvar(--radius-*)
text.styleмиксин типографики set-typography с соответствующим стилем
anatomy[].kind: instance + ofвложенный компонент библиотеки
exposed: falseсвойство вложенного компонента наружу не выносить
exposed: trueкандидат в публичный API — см. проброшенные свойства
overrides.fill у инстансацвет содержимого: чем покрашен вложенный значок
interaction[].hapticидентификатор виброотклика
gapsвопросы к дизайну, а не требования

Правила чтения

  • Имя токена переносится как есть. Контракт хранит имя-лист (space-xs, bg-layer-02, radius-m), в коде это var(--space-xs). Имя всё равно проверить в теме проекта: src/theme/space.css, src/theme/radius.css и соседние файлы. Совпадение имён — не гарантия существования переменной в текущей версии темы.
  • Число вместо имени токена — это дыра, а не значение. Если в контракте стоит 1, 6, 999, у макета там нет токена; в соответствующем gaps это записано. Не подбирать токен по значению самостоятельно.
  • $имя разворачивается по bindings и tokens. fill: $rootFill означает: взять таблицу tokens.rootFill и выбрать строку по значению оси.
  • Типографика — только именем стиля. text: {style: Special/tag/tag-small} — это стиль файла целиком; размер, интерлиньяж и начертание в контракте не пишутся и подбирать их по отдельности не нужно.
  • gaps не чинить. Это перечень мест, где макет неполон или противоречив. Дыра — повод задать вопрос, а не повод придумать значение.
  • Чего в контракте нет — того нет и в задаче. Формат не описывает тени, размытия и параметры анимации. Их отсутствие в файле не значит, что их нет в макете; значит, что они не сняты. Не додумывать.
  • Ось макета не обязана стать осью кода. Дизайнер перечисляет сочетания значениями оси, потому что в Figma иначе нельзя. В коде та же ось часто раскладывается естественнее: ось из четырёх конфигураций «только подпись / значок слева / значок справа / значки с двух сторон» — это два необязательных пропса, а не проп с четырьмя значениями. Сверять надо перечень получающихся состояний, а не форму записи.
  • forms — это конструкции одного компонента, а не разные компоненты. Как их разложить в код — одним компонентом со свойствами или несколькими, — решать по правилам core-ui и по ближайшим аналогам.
  • Ось Type Scale (Base / Scale) — не проп продукта. Это вид компонента под увеличенную типографику: с множителя ×1,2 конструкция переверстывается, ниже — остаётся базовой. Переключает его окружение, а не вызывающий код, поэтому значение оси наружу не выносится. В контракте вид Scale стоит либо дельтами в variants (дерево одно), либо отдельной формой (конструкций две) — и дальше это обычный выбор по предыдущему правилу. Каким механизмом окружение сообщает масштаб, контракт не описывает: это решение core-ui.

Ссылка на дизайн

source контракта даёт готовую ссылку для docs.mdx:

https://www.figma.com/design/<source.file>/Astra-DS?node-id=<source.set или source.component>&p=f&m=dev

Двоеточие в id заменить на дефис: 3185:17027 → 3185-17027. Это единственный случай, когда Figma-ссылку можно собрать самому: она взята из контракта, а не придумана.

Порядок работы с контрактом

  1. Прочитать контракт целиком, включая gaps.
  2. Выписать публичный API: оси, props, проброшенные наружу вложенные компоненты.
  3. Сверить состав с существующими компонентами библиотеки: что уже есть и переиспользуется.
  4. Выписать токены и проверить каждое имя в теме проекта.
  5. Отметить дыры и допущения, которые придётся объявить.
  6. Собрать код и истории — см. истории из контракта.
  7. В отчёте назвать: что взято из контракта, что домыслено, какие дыры остались открытыми.