Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 3 additions & 23 deletions docs/usage/text-box.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,29 +44,9 @@ const doc = new Document({

## Sizing

### Fixed Size
`width` sets a text box's width, so give every text box a `style` with one. Without a `style`, Word draws the box 50pt wide and LibreOffice gives it no width at all.

```ts live
import { Document, Paragraph, Textbox } from "docx";

const doc = new Document({
sections: [
{
children: [
new Textbox({
children: [new Paragraph("Fixed size textbox")],
style: {
width: "200pt",
height: "100pt",
},
}),
],
},
],
});
```

### Auto Height
Word, WPS Office, LibreOffice and Pages make a text box as tall as its text, whatever its `height`, which is how tall applications that don't, such as the preview on this page, draw it. A `style` without a `height`, or with `"auto"`, is written 1 inch tall, as WPS Office makes a box of auto height too short, cutting off its last line.

```ts live
import { Document, Paragraph, Textbox } from "docx";
Expand All @@ -76,7 +56,7 @@ const doc = new Document({
{
children: [
new Textbox({
children: [new Paragraph("Auto height based on content")],
children: [new Paragraph("As tall as its text")],
style: {
width: "200pt",
height: "auto",
Expand Down
18 changes: 16 additions & 2 deletions src/file/textbox/shape/shape.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe("createShape", () => {

expect(tree).toStrictEqual({
"v:shape": [
{ _attr: { id: "test-id", type: "#_x0000_t202", style: "width:10pt" } },
{ _attr: { id: "test-id", type: "#_x0000_t202", style: "width:10pt;height:1in" } },
{
"v:textbox": [
{ _attr: { style: "mso-fit-shape-to-text:t;" } },
Expand All @@ -34,7 +34,7 @@ describe("createShape", () => {
});
});

it("should create default styles", () => {
it("should write no style when given none, as a height alone doesn't change how the box is drawn", () => {
const tree = new Formatter().format(
createShape({
id: "test-id",
Expand All @@ -55,4 +55,18 @@ describe("createShape", () => {
],
});
});

it("should write a height of auto as 1in, which Word, WPS Office, LibreOffice and Pages resize to fit the text", () => {
const tree = new Formatter().format(createShape({ id: "test-id", style: { width: "200pt", height: "auto", zIndex: "auto" } }));

expect(tree["v:shape"][0]).toStrictEqual({
_attr: { id: "test-id", type: "#_x0000_t202", style: "width:200pt;height:1in;z-index:auto" },
});
});

it("should keep a height that is given", () => {
const tree = new Formatter().format(createShape({ id: "test-id", style: { width: "200pt", height: "50pt" } }));

expect(tree["v:shape"][0]).toStrictEqual({ _attr: { id: "test-id", type: "#_x0000_t202", style: "width:200pt;height:50pt" } });
});
});
14 changes: 13 additions & 1 deletion src/file/textbox/shape/shape.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,18 @@ export type { VmlShapeStyle } from "@file/vml";
/** Identifier of the text box shape type as referenced by shapes. */
const SHAPE_TYPE = "#_x0000_t202";

/**
* The height a text box's style is written with when it has none, or `"auto"`. Word, WPS Office, LibreOffice and Pages
* make the box as tall as its text (`mso-fit-shape-to-text`) from any height of 8pt or more, but WPS makes a box of auto
* height too short by its top and bottom insets, cutting off its last line. Applications that don't fit the box to its
* text, such as docx-preview, draw it this tall. A text box with no style is left without one: it has no width either,
* so Word draws it 50pt wide and LibreOffice gives it none, and a height changes neither.
*/
const FIT_FROM_HEIGHT = "1in";

const withFitFromHeight = (style?: VmlShapeStyle): VmlShapeStyle | undefined =>
style && (style.height === undefined || style.height === "auto") ? { ...style, height: FIT_FROM_HEIGHT } : style;
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved

/**
* Options for creating a VML shape.
*
Expand Down Expand Up @@ -90,6 +102,6 @@ export const createShape = ({ id, children, type = SHAPE_TYPE, style }: ShapeOpt
createVmlShape({
id,
type,
style,
style: withFitFromHeight(style),
children: [createVmlTextbox({ style: "mso-fit-shape-to-text:t;", children })],
});
2 changes: 1 addition & 1 deletion src/file/textbox/textbox.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const TEXTBOX_RUN = {
"w:pict": [
{
"v:shape": [
{ _attr: { id: expect.any(String), type: "#_x0000_t202", style: "width:10pt" } },
{ _attr: { id: expect.any(String), type: "#_x0000_t202", style: "width:10pt;height:1in" } },
{
"v:textbox": [
{ _attr: { style: "mso-fit-shape-to-text:t;" } },
Expand Down
Loading