Files
mantle-ai-trader/skills/docx/references/docx-js-core.md
2026-06-06 05:21:10 +00:00

334 lines
9.5 KiB
Markdown
Executable File

# docx-js API Reference
Complete API for creating .docx documents with the `docx` npm package. For advanced features (TOC details, footnotes, PDF conversion), see `docx-js-advanced.md`.
## Setup
```js
const {
Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
ImageRun, PageBreak, Header, Footer, PageNumber, NumberFormat,
AlignmentType, HeadingLevel, WidthType, BorderStyle, ShadingType,
PageOrientation, TabStopType, TabStopPosition, ExternalHyperlink,
InternalHyperlink, Bookmark, LevelFormat, TableOfContents,
} = require("docx");
const fs = require("fs");
```
## Document Creation + Export
```js
const doc = new Document({
styles: { /* see Styles section */ },
numbering: { config: [ /* see Lists section */ ] },
sections: [{
properties: {
page: {
size: { width: 11906, height: 16838 },
margin: { top: 1417, bottom: 1417, left: 1701, right: 1417 },
},
},
headers: { default: new Header({ children: [/* */] }) },
footers: { default: new Footer({ children: [/* */] }) },
children: [ /* Paragraphs, Tables, etc. */ ],
}],
});
const buffer = await Packer.toBuffer(doc);
fs.writeFileSync("output.docx", buffer);
```
## Paragraph + TextRun
```js
new Paragraph({
heading: HeadingLevel.HEADING_1, // or HEADING_2, HEADING_3
alignment: AlignmentType.JUSTIFIED,
spacing: { before: 240, after: 120, line: 312 }, // 1.3x mandatory
indent: { firstLine: 480 }, // 2-char CJK indent (480 SimSun / 420 YaHei)
children: [
new TextRun({
text: "Hello",
bold: true,
italics: true,
size: 24, // 12pt = Xiao Si
font: { ascii: "Calibri", eastAsia: "Microsoft YaHei" },
color: "000000", // Pure black for Profile A; for Profile B use palette.body
}),
],
});
// Additional text formatting options
new TextRun({ text: "Underlined", underline: { type: UnderlineType.SINGLE } })
new TextRun({ text: "Highlighted", highlight: "yellow" })
new TextRun({ text: "Strikethrough", strike: true })
new TextRun({ text: "x²", superScript: true })
new TextRun({ text: "H₂O", subScript: true })
new SymbolRun({ char: "2022", font: "Symbol" }) // Bullet •
```
## Table
**⚠️ CRITICAL**: Always set `margins` on TableCell (or at Table level for global default). Without margins, text touches borders.
**⚠️ CRITICAL**: Use `ShadingType.CLEAR` — never `ShadingType.SOLID` (causes black cells).
**⚠️ CRITICAL — Table Cross-Page Control**:
- Header row MUST set `tableHeader: true` (auto-repeat header on page break)
- All rows MUST set `cantSplit: true` (prevent row content split across pages)
- Title paragraph before table MUST set `keepNext: true` (keep title with table)
```js
// ⚠️ Title before table — keepNext keeps title with table
new Paragraph({
keepNext: true, // ← critical
children: [new TextRun({ text: "Table 1 Feature Comparison", bold: true, size: 21 })],
}),
new Table({
width: { size: 100, type: WidthType.PERCENTAGE },
borders: {
top: { style: BorderStyle.SINGLE, size: 2, color: "9AA6B2" },
bottom: { style: BorderStyle.SINGLE, size: 2, color: "9AA6B2" },
left: { style: BorderStyle.NONE },
right: { style: BorderStyle.NONE },
insideHorizontal: { style: BorderStyle.SINGLE, size: 1, color: "D0D0D0" },
insideVertical: { style: BorderStyle.NONE },
},
rows: [
// ⚠️ Header row — tableHeader + cantSplit
new TableRow({
tableHeader: true, // auto-repeat on page break
cantSplit: true, // prevent row split
children: ["Header 1", "Header 2"].map(text =>
new TableCell({
children: [new Paragraph({ children: [new TextRun({ text, bold: true, size: 21 })] })],
shading: { type: ShadingType.CLEAR, fill: "F1F5F9" },
margins: { top: 60, bottom: 60, left: 120, right: 120 },
width: { size: 50, type: WidthType.PERCENTAGE },
})
),
}),
// ⚠️ Data rows — cantSplit
new TableRow({
cantSplit: true, // prevent row split
children: ["Data 1", "Data 2"].map(text =>
new TableCell({
children: [new Paragraph({ children: [new TextRun({ text, size: 21 })] })],
margins: { top: 60, bottom: 60, left: 120, right: 120 },
width: { size: 50, type: WidthType.PERCENTAGE },
})
),
}),
],
});
```
### Column Widths
```js
// Fixed widths (twips)
width: { size: 3000, type: WidthType.DXA }
// Percentage
width: { size: 50, type: WidthType.PERCENTAGE }
```
## ImageRun
**⚠️ CRITICAL**: Always include `type` parameter. Always preserve aspect ratio.
```js
const imageBuffer = fs.readFileSync("chart.png");
// Calculate dimensions preserving aspect ratio
const displayWidth = 500;
const aspectRatio = originalHeight / originalWidth;
const displayHeight = Math.round(displayWidth * aspectRatio);
new Paragraph({
alignment: AlignmentType.CENTER,
children: [
new ImageRun({
data: imageBuffer,
transformation: { width: displayWidth, height: displayHeight },
type: "png", // REQUIRED: "png", "jpg", "gif", "bmp"
}),
],
});
```
## PageBreak
**⚠️ CRITICAL**: PageBreak MUST be inside a Paragraph. Standalone PageBreak crashes Word.
**⚠️ Best Practice**: Attach PageBreak to the end of a **paragraph with text content**. Avoid empty paragraph + PageBreak (may cause blank pages). If using multi-section structure, prefer section breaks over PageBreak.
```js
// ✅ Recommended — PageBreak attached to content paragraph
new Paragraph({
children: [
new TextRun({ text: "End of section" }),
new PageBreak()
]
})
// ✅ Acceptable — but prefer section breaks
new Paragraph({ children: [new PageBreak()] })
// ✅ Best — use section breaks instead of PageBreak
// Place content in different sections — auto page break
```
## Headers & Footers + Page Numbers
```js
headers: {
default: new Header({
children: [
new Paragraph({
alignment: AlignmentType.CENTER,
children: [new TextRun({ text: "Document Title", size: 18, color: "888888" })],
}),
],
}),
},
footers: {
default: new Footer({
children: [
new Paragraph({
alignment: AlignmentType.CENTER,
children: [
new TextRun({ children: [PageNumber.CURRENT], size: 18 }),
],
}),
],
}),
},
```
> ⚠️ **Denominator FORBIDDEN** — never use `PageNumber.TOTAL_PAGES` or "X / Y" format. Show only current page number.
## Styles Definition
The example below is for **Chinese documents** (default). For **English documents**, replace `font` with `"Times New Roman"` throughout.
```js
styles: {
default: {
document: {
run: {
font: { ascii: "Calibri", eastAsia: "Microsoft YaHei" },
size: 24, color: "000000", // Pure black for Profile A; for Profile B use palette.body
},
paragraph: {
spacing: { line: 312 }, // 1.3x mandatory
},
},
heading1: {
run: { font: { ascii: "Calibri", eastAsia: "SimHei" }, size: 32, bold: true, color: "0B1220" },
paragraph: { spacing: { before: 360, after: 160, line: 312 } },
},
heading2: {
run: { font: { ascii: "Calibri", eastAsia: "SimHei" }, size: 28, bold: true, color: "0B1220" },
paragraph: { spacing: { before: 240, after: 120, line: 312 } },
},
heading3: {
run: { font: { ascii: "Calibri", eastAsia: "SimHei" }, size: 24, bold: true, color: "0B1220" },
paragraph: { spacing: { before: 200, after: 100, line: 312 } },
},
},
}
```
## Lists
**⚠️ CRITICAL**: Each separate numbered list MUST use a unique `reference` name. Reusing the same reference causes numbering to continue instead of restarting.
```js
// In Document numbering config
numbering: {
config: [
{
reference: "list-features", // unique name!
levels: [{
level: 0,
format: LevelFormat.DECIMAL,
text: "%1.",
alignment: AlignmentType.LEFT,
style: { paragraph: { indent: { left: 720, hanging: 360 } } },
}],
},
{
reference: "list-benefits", // different name for second list!
levels: [{ /* same config */ }],
},
],
},
// Usage in paragraphs
new Paragraph({
numbering: { reference: "list-features", level: 0 },
children: [new TextRun({ text: "First item" })],
})
```
### Bullet Lists
```js
new Paragraph({
bullet: { level: 0 },
children: [new TextRun({ text: "Bullet item" })],
})
```
## Hyperlinks
### External Link
```js
new ExternalHyperlink({
children: [new TextRun({ text: "Click here", style: "Hyperlink" })],
link: "https://example.com",
})
```
### Internal Link (Bookmark)
```js
// Define bookmark at target
new Paragraph({
children: [
new Bookmark({ id: "section1", children: [new TextRun("Section 1")] }),
],
})
// Link to bookmark
new InternalHyperlink({
children: [new TextRun({ text: "Go to Section 1", style: "Hyperlink" })],
anchor: "section1",
})
```
## Table of Contents (TOC)
**→ See `references/toc.md` for the complete TOC reference.**
Quick reminder: (1) Add `TableOfContents` element + PageBreak, (2) Run `python3 "$DOCX_SCRIPTS/add_toc_placeholders.py" output.docx --auto`, (3) Check exit code.
## Tabs
```js
new Paragraph({
tabStops: [
{ type: TabStopType.RIGHT, position: TabStopPosition.MAX },
],
children: [new TextRun("Left"), new TextRun("\t"), new TextRun("Right")]
})
```
## Constants Quick Reference
- **Underlines:** `SINGLE`, `DOUBLE`, `WAVY`, `DASH`
- **Borders:** `SINGLE`, `DOUBLE`, `DASHED`, `DOTTED`
- **Numbering:** `DECIMAL` (1,2,3), `UPPER_ROMAN` (I,II,III), `LOWER_LETTER` (a,b,c)
- **Symbols:** `"2022"` (•), `"00A9"` (©), `"00AE"` (®), `"2122"` (™)