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
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,29 @@ for this cycle.
(`graph-compose-render-docx` / `graph-compose-render-pptx`) stay opt-in and are not
bundled.

## v1.9.1 — 2026-07-06

Table columns now contain long inline-code content instead of letting it spill
over the next column.

### Bug fixes

- **Long inline-code chips no longer overflow their column.** A long
`inlineCode(...)` / `inlineHighlight(...)` token with no spaces — a package
coordinate, fully-qualified class name or URL — now breaks *within* its
paragraph or table cell instead of drawing over the neighbouring content. It
breaks at `.` `:` `/` `-` seams and char-splits only when a segment is still
too wide, keeping the rounded chip fill intact on every wrapped fragment.
Applies to all three paragraph wrap paths (plain, inline, markdown); text that
already fits is laid out exactly as before.

- **`auto()` table columns grow to fit composed cell content.** A composed cell
(`DocumentTableCell.node(...)`) in an `auto()` column now contributes its
intrinsic content width, so the column sizes to the content (e.g. an
inline-code chip) instead of collapsing toward zero. `fixed(...)` columns are
unchanged. As with plain-text auto columns, a table too narrow for the summed
intrinsic width of its auto columns reports `exceeds available width`.

## v1.9.0 — 2026-06-29

In-document navigation. Rendered PDFs can now declare named **anchors** and
Expand Down
Binary file not shown.
39 changes: 39 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ are with the canonical DSL, then jump to its detailed section below.
| [Section presets](#section-presets) | `pageBackground`, `band`, `softPanel`, `accentLeft / Right / Top / Bottom`, per-corner `DocumentCornerRadius` | [PDF](../assets/readme/examples/section-presets.pdf) · [Source](src/main/java/com/demcha/examples/features/text/SectionPresetsExample.java) |
| [Nested lists](#nested-lists-v16) | `ListBuilder.addItem(label, Consumer)` — depth cascade, per-depth markers, mixed flat / nested authoring | [PDF](../assets/readme/examples/nested-list-showcase.pdf) · [Source](src/main/java/com/demcha/examples/features/lists/NestedListExample.java) |
| [Composed table cells](#composed-table-cells-v16) | `DocumentTableCell.node(DocumentNode)` — paragraphs, lists, sub-tables inside cells with two-pass measurement | [PDF](../assets/readme/examples/composed-table-cell-showcase.pdf) · [Source](src/main/java/com/demcha/examples/features/tables/ComposedTableCellExample.java) |
| [Inline-code column wrap](#inline-code-column-wrap) | A long `inlineCode(...)` coordinate breaks at its `. : / -` seams inside a narrow **fixed** column and an **auto** column grows to fit it on one line | [PDF](../assets/readme/examples/inline-code-column-wrap.pdf) · [Source](src/main/java/com/demcha/examples/features/tables/InlineCodeColumnWrapExample.java) |
| [Canvas layer (free placement)](#canvas-layer-v16) | `CanvasLayerNode` — pixel-precise `(x, y)` placement of children inside a fixed bounding box, with `ClipPolicy` clipping | [PDF](../assets/readme/examples/canvas-layer-showcase.pdf) · [Source](src/main/java/com/demcha/examples/features/canvas/CanvasLayerExample.java) |
| [Transforms](#transforms) | `rotate`, `scale`, and per-layer `zIndex` swap | [PDF](../assets/readme/examples/transforms.pdf) · [Source](src/main/java/com/demcha/examples/features/transforms/TransformsExample.java) |
| [Block alignment](#block-alignment) | `addAligned(align, node)` / `addSvgIcon(icon, w, align)` — seat any fixed-size node left / centre / right across the content width | [PDF](../assets/readme/examples/block-align.pdf) · [Source](src/main/java/com/demcha/examples/features/layout/BlockAlignExample.java) |
Expand Down Expand Up @@ -535,6 +536,44 @@ table.columns(...)
[📄 View PDF](../assets/readme/examples/table-advanced.pdf) ·
[📜 Full source](src/main/java/com/demcha/examples/features/tables/TableAdvancedExample.java)

### Inline-code column wrap

A composed cell holding one long `inlineCode(...)` token — a Maven coordinate,
fully-qualified class name or URL — stays inside its column. In a narrow
**fixed** column the chip breaks at its `. : / -` seams (char-splitting only
when a segment is still too wide), with the rounded fill intact on every
fragment; in an **auto** column the column grows to fit the coordinate on one
line instead of collapsing.

```java
DocumentTableCell.node(document.dsl().paragraph()
.inlineCode("org.junit.jupiter:junit-jupiter:5.10.2").build())
// fixed(104) column -> wraps at seams; auto() column -> grows to one line
```

[📄 View PDF](../assets/readme/examples/inline-code-column-wrap.pdf) ·
[📜 Full source](src/main/java/com/demcha/examples/features/tables/InlineCodeColumnWrapExample.java)

### Custom Business Theme

Build a `BusinessTheme` from raw `DocumentPalette` / `SpacingScale` /
`TextScale` / `TablePreset` records — no factory shortcut. Plug it
straight into `InvoiceTemplateV2` to retheme the whole template
without touching any code that uses it.

```java
BusinessTheme studioEmerald = new BusinessTheme(
new DocumentPalette(/* page, surface, surfaceMuted, ink, accent, … */),
SpacingScale.cinematic(),
new TextScale(/* h1, h2, body, caption fonts … */),
TablePreset.cinematic());

new InvoiceTemplateV2(studioEmerald).compose(document, invoice);
```

[📄 View PDF](../assets/readme/examples/invoice-custom-theme.pdf) ·
[📜 Full source](src/main/java/com/demcha/examples/features/themes/CustomBusinessThemeExample.java)

---

## Public-API surface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.demcha.examples.features.streaming.HttpStreamingExample;
import com.demcha.examples.features.svg.SvgIconGalleryExample;
import com.demcha.examples.features.tables.ComposedTableCellExample;
import com.demcha.examples.features.tables.InlineCodeColumnWrapExample;
import com.demcha.examples.features.tables.TableAdvancedExample;
import com.demcha.examples.features.text.EmojiGalleryExample;
import com.demcha.examples.features.text.EmojiShortcodeExample;
Expand Down Expand Up @@ -151,6 +152,7 @@ public static void main(String[] args) throws Exception {
// v1.6 layout primitives
System.out.println("Generated: " + NestedListExample.generate());
System.out.println("Generated: " + ComposedTableCellExample.generate());
System.out.println("Generated: " + InlineCodeColumnWrapExample.generate());
System.out.println("Generated: " + CanvasLayerExample.generate());

// v1.5 visual primitives
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package com.demcha.examples.features.tables;

import com.demcha.compose.GraphCompose;
import com.demcha.compose.document.api.DocumentPageSize;
import com.demcha.compose.document.api.DocumentSession;
import com.demcha.compose.document.node.TableNode;
import com.demcha.compose.document.style.DocumentColor;
import com.demcha.compose.document.style.DocumentInsets;
import com.demcha.compose.document.style.DocumentStroke;
import com.demcha.compose.document.style.DocumentTextDecoration;
import com.demcha.compose.document.style.DocumentTextStyle;
import com.demcha.compose.document.table.DocumentTableCell;
import com.demcha.compose.document.table.DocumentTableColumn;
import com.demcha.compose.document.table.DocumentTableStyle;
import com.demcha.compose.font.FontName;
import com.demcha.examples.support.ExampleOutputPaths;

import java.nio.file.Path;
import java.util.List;

/**
* Runnable showcase for long inline-code coordinates inside table columns.
*
* <p>A composed cell holding a single long {@code inlineCode(...)} token — a
* Maven coordinate, fully-qualified class name or URL — no longer overflows its
* column. In a narrow <b>fixed</b> column the chip breaks <em>inside</em> the
* cell, preferring its {@code . : / -} seams and char-splitting only as a last
* resort, with the rounded fill intact on every fragment. In an <b>auto</b>
* column the column grows to fit the coordinate on one line instead of
* collapsing.</p>
*
* @author Artem Demchyshyn
*/
public final class InlineCodeColumnWrapExample {

private static final DocumentColor INK = DocumentColor.rgb(34, 38, 50);
private static final DocumentColor MUTED = DocumentColor.rgb(102, 106, 118);
private static final DocumentColor RULE = DocumentColor.rgb(180, 188, 200);
private static final DocumentColor HEADER_FILL = DocumentColor.rgb(20, 60, 75);
private static final DocumentColor ROW_TINT = DocumentColor.rgb(244, 247, 252);

private static final List<String> COORDINATES = List.of(
"org.junit.jupiter:junit-jupiter:5.10.2",
"io.github.demchaav:graph-compose:1.9.0",
"https://repo1.maven.org/maven2/");

private InlineCodeColumnWrapExample() {
}

public static Path generate() throws Exception {
Path outputFile = ExampleOutputPaths.prepare("features/tables", "inline-code-column-wrap.pdf");

DocumentTextStyle title = DocumentTextStyle.builder()
.fontName(FontName.HELVETICA_BOLD).size(20).color(INK)
.decoration(DocumentTextDecoration.BOLD).build();
DocumentTextStyle caption = DocumentTextStyle.builder()
.fontName(FontName.HELVETICA_OBLIQUE).size(10).color(MUTED).build();
DocumentTextStyle body = DocumentTextStyle.builder()
.fontName(FontName.HELVETICA).size(10.5).color(INK).build();
DocumentTextStyle headerText = DocumentTextStyle.builder()
.fontName(FontName.HELVETICA_BOLD).size(11).color(DocumentColor.WHITE)
.decoration(DocumentTextDecoration.BOLD).build();

DocumentTableStyle headerStyle = DocumentTableStyle.builder()
.fillColor(HEADER_FILL).stroke(DocumentStroke.of(RULE, 0.6))
.padding(DocumentInsets.of(8)).textStyle(headerText).build();
DocumentTableStyle bodyCellStyle = DocumentTableStyle.builder()
.stroke(DocumentStroke.of(RULE, 0.6)).padding(DocumentInsets.of(8)).textStyle(body).build();
DocumentTableStyle tintedCellStyle = DocumentTableStyle.builder()
.fillColor(ROW_TINT).stroke(DocumentStroke.of(RULE, 0.6))
.padding(DocumentInsets.of(8)).textStyle(body).build();

try (DocumentSession document = GraphCompose.document(outputFile)
.pageSize(DocumentPageSize.A4)
.margin(36, 36, 36, 36)
.create()) {

document.pageFlow()
.name("CodeWrapShowcase")
.spacing(8)
.addParagraph("Long inline-code coordinates stay inside the column", title)
.addParagraph(
"A composed cell with one long inlineCode(...) token used to spill over the "
+ "next column. It now breaks at its . : / - seams inside a narrow FIXED "
+ "column (char-splitting only when a segment is still too wide), and an "
+ "AUTO column grows to fit it on one line.", caption)
.build();

List<List<DocumentTableCell>> rows = new java.util.ArrayList<>();
rows.add(List.of(
DocumentTableCell.text("Fixed 104pt").withStyle(headerStyle),
DocumentTableCell.text("Auto").withStyle(headerStyle)));
for (int i = 0; i < COORDINATES.size(); i++) {
String coordinate = COORDINATES.get(i);
DocumentTableStyle cellStyle = i % 2 == 0 ? bodyCellStyle : tintedCellStyle;
rows.add(List.of(
DocumentTableCell.node(document.dsl().paragraph().inlineCode(coordinate).build())
.withStyle(cellStyle),
DocumentTableCell.node(document.dsl().paragraph().inlineCode(coordinate).build())
.withStyle(cellStyle)));
}

document.add(new TableNode(
"CodeWrapTable",
List.of(DocumentTableColumn.fixed(104),
DocumentTableColumn.auto()),
rows,
bodyCellStyle,
null,
DocumentInsets.zero(),
DocumentInsets.zero()));

document.buildPdf();
}
return outputFile;
}

public static void main(String[] args) throws Exception {
System.out.println("Generated: " + generate());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -411,9 +411,13 @@ private static DocumentNode brandLine() {

/** Version pill ("v1.8.0") with the codename centred beside it as a tag. */
private static DocumentNode versionBlock() {
// Show the base version only: a dev/pre-release qualifier ("2.0.0-SNAPSHOT",
// "2.0.0-beta.1") is wider than the 96pt pill, and the engine wraps long
// tokens at their "." / "-" seams — the pill would break onto two lines.
String pillVersion = VERSION.replaceFirst("-.*$", "");
DocumentNode pill = new ShapeContainerBuilder().name("VerPill")
.roundedRect(96, 30, 8).fillColor(VIOLET_DEEP)
.center(new ParagraphBuilder().text("v" + VERSION)
.center(new ParagraphBuilder().text("v" + pillVersion)
.textStyle(DocumentTextStyle.builder().fontName(FontName.HELVETICA_BOLD)
.size(14).color(DocumentColor.WHITE).build())
.align(TextAlign.CENTER).margin(DocumentInsets.zero()).build())
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
<assertj.version>3.27.7</assertj.version>
<junit.bom.version>6.1.1</junit.bom.version>
<mockito.version>5.23.0</mockito.version>
<byteBuddy.version>1.18.10</byteBuddy.version>
<byteBuddy.version>1.18.11</byteBuddy.version>

<!-- Bundled fonts / emoji, pulled in at test scope only. Pinned to the
independent 1.0.0 line (not bumped in engine lockstep); keep in step
Expand Down
Loading
Loading