Аннотации (references/annotations.md)

Источник: ds-skills/src/skills/astra-figma-doc-build/references/annotations.md — справочник скилла astra-figma-doc-build

В тексте документации нет чисел. Размеры, отступы, радиусы, цвета и типографика показываются аннотациями Figma на слоях примера в блоке «Структура». Значение Figma берёт с самого узла и показывает токен, если свойство к нему привязано. Компонент меняется — аннотации показывают новое значение, документацию переписывать не нужно.

Читатель видит аннотации в Dev Mode. Подсказку об этом даёт ds-paragraph-dev-mode над блоком «Структура» — его текст не меняется.

Категории

figma.annotations.getAnnotationCategoriesAsync(). В файле Astra DS восемь категорий:

Спецификациязелёныйразмеры, отступы, токены, текстовые стили, заливки — по умолчанию
Интерактивностьсинийповедение и отклик на действия
Доступностьрозовыйфокус, контраст, зона нажатия
Контентжёлтыйправила текста
Рекомендации, Закон, Примечание реализации, Stark—скилл не ставит

Скилл ставит только Спецификация. Новые категории не создаёт (addAnnotationCategoryAsync не вызывать). Категории нет — берётся стандартная Development (так в новом файле и в копии без настроек Astra), нет и её — аннотация ставится без категории. Оба случая называются в отчёте.

Формат

node.annotations = [{
  labelMarkdown: "**<Имя слоя>**",
  categoryId: specId,
  properties: [{ type: "padding" }, { type: "itemSpacing" }]
}];
  • labelMarkdown — имя слоя жирным. Назначение слоя скилл не пишет: из имени его не вывести без догадки (SKILL.md, раздел «Тексты»). Чисел в подписи нет.
  • properties — только те, что на узле действительно заданы, иначе Invalid property … for a FRAME node.
  • annotations — массив только для чтения: присваивать целиком.

Какие свойства на каком слое

корень примера и фреймы с auto-layoutpadding, itemSpacing; minWidth, minHeight, если заданы; cornerRadius, если не 0
фрейм с заливкой или обводкойплюс fills, strokes
текстовый слойtextStyleId, если стиль стоит; иначе fontSize, lineHeight; плюс fills
вложенный инстансmainComponent, width, height
прочееwidth, height

BOOLEAN_OPERATION и векторы внутри иконок — без аннотаций.

Рецепт

Отдельный вызов после блока «Структура» (рецепт 5.1): после setProps id внутри инстанса могли смениться, поэтому слои ищутся заново.

// …страница…
const anatomy = await figma.getNodeByIdAsync("ANATOMY_ID");
const slot = anatomy.findOne(n => n.type === "SLOT" && n.name === "Slot Container");
const example = slot.children[0];
const cats = await figma.annotations.getAnnotationCategoriesAsync();
const spec = cats.find(c => c.label === "Спецификация");
if (!spec) return { stop: true, reason: "нет категории «Спецификация»" };

function propsFor(n) {
  const p = [];
  if (n.type === "TEXT") {
    p.push(n.textStyleId && typeof n.textStyleId === "string" ? "textStyleId" : "fontSize");
    if (n.fills && n.fills.length) p.push("fills");
    return p;
  }
  if (n.type === "INSTANCE" && n.id !== example.id) return ["mainComponent", "width", "height"];
  if (n.layoutMode && n.layoutMode !== "NONE") {
    p.push("padding", "itemSpacing");
    if (n.minWidth !== null) p.push("minWidth");
    if (n.minHeight !== null) p.push("minHeight");
  } else p.push("width", "height");
  if (typeof n.cornerRadius === "number" && n.cornerRadius > 0) p.push("cornerRadius");
  if (n.fills && n.fills.length) p.push("fills");
  if (n.strokes && n.strokes.length) p.push("strokes");
  return p;
}

// внутрь вложенных инстансов не идти: их слои описаны в документации того компонента
function insideNested(n) {
  let p = n.parent;
  while (p && p.id !== example.id) { if (p.type === "INSTANCE") return true; p = p.parent; }
  return false;
}
const done = [], skipped = [];
const nodes = [example].concat(example.findAll(n =>
  n.visible && ["FRAME", "TEXT", "INSTANCE"].includes(n.type) && !insideNested(n)));
for (const n of nodes) {
  try {
    n.annotations = [{ labelMarkdown: "**" + n.name + "**", categoryId: spec.id,
      properties: propsFor(n).map(t => ({ type: t })) }];
    done.push(n.name);
  } catch (e) { skipped.push(n.name + ": " + e.message); }
}
return { done: done.length, skipped };

skipped — не ошибка сборки, а пункт отчёта: слой не принял какое-то свойство. Повторить для него вызов с width и height.

Чего не делать

  • Не дублировать. Аннотации стоят на одном примере — в «Структуре». Строки блоков свойств их не получают.
  • Не писать значения в подпись. «Container — отступ 16» — ошибка: значение уже в properties, а в подписи оно устареет.
  • Линейки (addMeasurement) доступны только в Dev Mode (figma.editorType === "dev"). В обычном режиме — не ставить и не заменять числом в тексте.