Узлы
Section
Единственный узел, содержащий другие узлы, и заголовок, которым становится его название.
The only construct that nests today. Its title carries into the document outline, so the structure you write is the structure the reader sees.
- Хелперы
- section, Section
- Вид узла
- section
- Категория
- Структура
- Разрешается
- Locally
- Дочерние узлы
- Any node, including other sections. No depth limit.
| Опция | Тип | Что делает |
|---|---|---|
id обязательно | string | Stable address for the node. Generation endpoints target it and build artifacts diff on it, so treat a rename as a breaking change. |
title обязательно | string | The heading printed above the children, and the outline entry. |
nodes | NodeComponent[] | The children. Passed as the second argument, as the nodes option, or as JSX children of <Section> — the three are the same call. |
derivers | DeriverInvocation[] | Values computed before the node resolves, written to derived.* and readable from a template token. Built with derive(). |
Как его написать
Раздел принимает свои опции и своих потомков — компоненты узлов, те же значения, которые вы поместили бы на верхнем уровне документа:
import { section } from "docxcelerate";
export const Opening = section<MemberData>({ id: "opening", title: "Your renewal" }, [
Greeting,
PriceChange,
]);
В TSX тот же вызов читается как разметка:
<Section id="opening" title="Your renewal">
<Greeting />
<PriceChange />
</Section>
Оба варианта дают одно дерево. О том, когда какая форма себя оправдывает, — в Шаблонах.
Потомками может быть что угодно
Абзацы, изображения, графики, отметка оглавления или другие разделы. Больше ни у одного узла потомков нет, поэтому глубина документа — это глубина его разделов.
От того, что узел оказался внутри раздела, в нём ничего не меняется: он разрешается одинаково на любой глубине, и его идентификатор не получает префикса.
Заголовки попадают в структуру
title обязателен, и это не украшение: он становится заголовком над потомками и
той строкой, из которой строится оглавление. Группе, которой заголовок не нужен,
не нужен и раздел — поместите узлы прямо в документ.
Варианты
A titled group
src/nodes/section/basic.node.ts Two paragraphs under one heading — the common case.
import { section } from "docxcelerate";
import { PriceChange } from "../paragraph/conditional.node.ts";
import { Greeting } from "../paragraph/static.node.ts";
import type { SampleData } from "../sample-data.ts";
/**
* A section takes an id, a title and its children. The children are the same
* node components you would place at the top level.
*/
export const Opening = section<SampleData>({ id: "opening", title: "Your renewal" }, [
Greeting,
PriceChange,
]); Во что это разрешается
Узел в том виде, в каком он попадает в DocumentModel: JSON, который получает рендерер. Без стилей и без вёрстки.
{
"id": "opening",
"kind": "section",
"title": "Your renewal",
"children": [
{
"id": "greeting",
"kind": "paragraph",
"mode": "static",
"text": "Dear Adaeze Nkemelu,"
},
{
"id": "price-change",
"kind": "paragraph",
"mode": "static",
"text": "Your Peak Anytime membership is rising by 5.1%, from £468 to £492 a year. That is £41 a month from 1 October 2026."
}
]
} Mixed and nested children
src/nodes/section/nested.node.ts A graph, then a nested section holding a graph and a dynamic paragraph.
import { section } from "docxcelerate";
import { ClassMix } from "../graph/pie.node.ts";
import { VisitsByMonth } from "../graph/bar.node.ts";
import { NextSteps } from "../paragraph/dynamic.node.ts";
import type { SampleData } from "../sample-data.ts";
/**
* Children can be of any kind, including another section — the one place a
* letter tree gains depth. The resolved document nests exactly as this reads.
*/
export const YourYear = section<SampleData>({ id: "your-year", title: "Your year here" }, [
VisitsByMonth,
section<SampleData>({ id: "activity-mix", title: "Where the time went" }, [
ClassMix,
NextSteps,
]),
]); Во что это разрешается
Узел в том виде, в каком он попадает в DocumentModel: JSON, который получает рендерер. Без стилей и без вёрстки.
{
"id": "your-year",
"kind": "section",
"title": "Your year here",
"children": [
{
"id": "visits-by-month",
"kind": "graph",
"mode": "static",
"graphType": "bar",
"data": {
"labels": [
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep"
],
"series": [
{
"name": "Visits",
"values": [
11,
14,
9,
16,
18,
12
]
}
]
},
"caption": "Your visits to Riverside Leisure Centre, last six months"
},
{
"id": "activity-mix",
"kind": "section",
"title": "Where the time went",
"children": [
{
"id": "class-mix",
"kind": "graph",
"mode": "static",
"graphType": "pie",
"data": {
"labels": [
"Swim",
"Strength",
"Classes"
],
"series": [
{
"name": "Share of visits",
"values": [
42,
33,
25
]
}
]
},
"caption": "How you used the centre, by activity"
},
{
"id": "next-steps",
"kind": "paragraph",
"mode": "dynamic",
"text": "Your membership renews automatically on 1 October 2026. Nothing is needed from you unless you want to change plan."
}
]
}
]
} Примечания
- Глубина — в дереве, а не в заголовках. Оба поставляемых рендерера печатают
заголовок любого раздела на одном уровне —
<h2>в браузере и «Заголовок 1» в DOCX — как бы глубоко он ни был вложен. JSON вкладывается правильно, так что это ограничение рендерера, но документ с тремя уровнями пока не будет выглядеть трёхуровневым. - Динамического раздела не существует. Эндпоинт заполняет узлы; он не решает, что входит в документ.
- Пустой раздел отрисуется как одинокий заголовок. Если потомки приходят из фильтра, который может опустеть, проверьте это выше по течению.