Skip to content

feat: emit textAutoResize and text truncation in design tree#217

Merged
let-sunny merged 2 commits intomainfrom
feat/216-text-auto-resize
Mar 31, 2026
Merged

feat: emit textAutoResize and text truncation in design tree#217
let-sunny merged 2 commits intomainfrom
feat/216-text-auto-resize

Conversation

@let-sunny
Copy link
Copy Markdown
Owner

@let-sunny let-sunny commented Mar 31, 2026

Summary

  • Emit textAutoResize as text-resize: auto | fixed-height | truncate in design-tree output
  • Emit textTruncation: ENDING as text-overflow: ellipsis
  • Emit maxLines as max-lines: N (for truncated/clamped text)
  • Emit paragraphSpacing as paragraph-spacing: Npx
  • Add textTruncation and maxLines to AnalysisNode schema (Figma API fields)

Context

The design tree omitted text sizing/wrapping properties critical for accurate implementation. AI couldn't distinguish auto-width vs fixed-width text, or know when text should show ellipsis. Identified in #200 Score Adjustment Interview.

Design tree output examples

Title (TEXT, auto×32)
  style: font-size: 32px; text-resize: auto

Body text (TEXT, 300x48)
  style: font-size: 16px; text-resize: fixed-height

Truncated label (TEXT, 200x20)
  style: font-size: 14px; text-resize: truncate; max-lines: 2

Fixture data validation

Across all 24 fixtures (1420 TEXT nodes):

  • textAutoResize: 1044 WIDTH_AND_HEIGHT, 374 HEIGHT, 2 undefined
  • textTruncation, maxLines, paragraphSpacing: 0 occurrences in current fixtures (but supported by Figma API)

Test plan

  • pnpm test:run — 687 tests passed
  • pnpm lint — clean
  • 6 new unit tests for text-resize, truncation, paragraph-spacing, and no-emit cases

Closes #216

Summary by CodeRabbit

  • New Features

    • Text truncation support with configurable modes (DISABLED or ENDING).
    • Per-text maximum line limits (maxLines).
    • Text auto-resize modes exposed (WIDTH_AND_HEIGHT, HEIGHT, TRUNCATE) with corresponding truncation behavior.
    • Configurable paragraph spacing output for text layouts.
  • Tests

    • Added tests covering text auto-resize, truncation, max-lines, and paragraph-spacing behaviors.

Add text sizing/wrapping properties to design-tree output:
- textAutoResize → text-resize: auto | fixed-height | truncate
- textTruncation ENDING → text-overflow: ellipsis
- maxLines → max-lines: N
- paragraphSpacing → paragraph-spacing: Npx

Also adds textTruncation and maxLines to AnalysisNode schema.

https://claude.ai/code/session_01PqgYRCyuLA48EzyFWnHM82
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 31, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 214b0778-3cec-427e-8aa8-8e31ed088a73

📥 Commits

Reviewing files that changed from the base of the PR and between 3694f8c and 11ee44d.

📒 Files selected for processing (3)
  • src/core/adapters/figma-transformer.ts
  • src/core/design-tree/design-tree.test.ts
  • src/core/design-tree/design-tree.ts

📝 Walkthrough

Walkthrough

The PR adds optional text fields (textTruncation, maxLines) to the analysis node schema and updates design-tree rendering to emit CSS-like tokens for text auto-resize, truncation (ellipsis + max-lines), and paragraph spacing; tests exercising these behaviors were added.

Changes

Cohort / File(s) Summary
Schema Extension
src/core/contracts/figma-node.ts
Added optional `textTruncation?: "DISABLED"
Design Tree Implementation
src/core/design-tree/design-tree.ts
Emit text style tokens for TEXT nodes: text-resize mapping for textAutoResize (WIDTH_AND_HEIGHTauto, HEIGHTfixed-height, TRUNCATEtruncate), emit text-overflow: ellipsis and optional max-lines for truncation (including when textTruncation === "ENDING"), and emit paragraph-spacing when non-zero.
Transformer Mapping
src/core/adapters/figma-transformer.ts
Map incoming node.textTruncation and numeric node.maxLines into the analysis node output (base.textTruncation, base.maxLines) when present.
Tests
src/core/design-tree/design-tree.test.ts
Added tests covering text auto-resize outputs, truncation/ellipsis and max-lines emission, paragraph-spacing formatting, and negative cases for omitted tokens.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • #140 — Modifies TEXT-node rendering in design-tree; overlaps with emitted tokens (text-resize / max-lines) and may interact with text escaping/SVG normalization changes.
  • #41 — Also changes BaseAnalysisNodeSchema and design-tree emission logic; similar schema-extension pattern and concerns about TEXT-node properties.

Poem

🐰 I hopped through nodes with a tiny cheer,
Adding ellipses and lines so text is clear,
Auto-resize, fixed or truncate in view,
Paragraph spacing fell into place too.
Now the design tree reads tidy and true.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: emitting text auto-resize and text truncation properties to the design tree output across schema, transformer, and rendering logic.
Linked Issues check ✅ Passed The PR fulfills all coding requirements from issue #216: added textTruncation and maxLines to AnalysisNode schema, mapped textAutoResize/textTruncation/maxLines/paragraphSpacing in transformer, and emitted corresponding CSS-like properties in design-tree rendering with comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #216 objectives: schema extensions, transformer mappings, and design-tree style emission for text sizing/wrapping properties with supporting tests.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/216-text-auto-resize

Comment @coderabbitai help to get the list of available commands and usage tips.

@let-sunny let-sunny marked this pull request as ready for review March 31, 2026 01:14
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/core/contracts/figma-node.ts`:
- Around line 158-159: The transformer in
src/core/contracts/figma-transformer.ts needs to populate the new text fields:
when handling TEXT nodes (the block that currently extracts characters and
style), also read node.textTruncation and node.maxLines from the Figma API
response and set them on the transformed object (e.g., add textTruncation and
maxLines properties alongside characters and style). Ensure textTruncation maps
to the schema enum values ("DISABLED" | "ENDING") and maxLines is set as an
optional number only when present; leave them undefined otherwise so existing
null-checks (node.maxLines != null) continue to work.

In `@src/core/design-tree/design-tree.test.ts`:
- Around line 1093-1200: Add three edge-case tests to the existing "text
auto-resize and truncation" suite using makeFile/makeNode and
generateDesignTree: (1) a TRUNCATE text node without maxLines that asserts
output contains "text-resize: truncate" and does NOT contain "max-lines:"; (2) a
text node with textTruncation: "DISABLED" (and textAutoResize e.g. "HEIGHT")
that asserts output does NOT contain "text-overflow:"; (3) a text node with
style.paragraphSpacing: 0 that asserts output does NOT contain
"paragraph-spacing:". Use unique test names like "emits text-resize: truncate
without max-lines", "does not emit text-overflow for DISABLED", and "does not
emit paragraph-spacing for 0" to match the existing pattern.

In `@src/core/design-tree/design-tree.ts`:
- Around line 493-519: The TRUNCATE branch currently sets "text-resize:
truncate" and emits `max-lines` but omits the ellipsis; update the logic in the
block that checks textAutoResize === "TRUNCATE" (where textAutoResize and
node.maxLines are used) to also push "text-overflow: ellipsis" so TRUNCATE mode
emits both `text-resize: truncate` and `text-overflow: ellipsis` (keep the
existing guarded emission of `max-lines` based on node.maxLines); ensure you do
not duplicate ellipsis when the later conditional for textAutoResize !==
"TRUNCATE" runs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 74f126a6-4843-448c-bfaa-d3751599d0a0

📥 Commits

Reviewing files that changed from the base of the PR and between 9d3be8a and 3694f8c.

📒 Files selected for processing (3)
  • src/core/contracts/figma-node.ts
  • src/core/design-tree/design-tree.test.ts
  • src/core/design-tree/design-tree.ts

Comment on lines +1093 to +1200
describe("text auto-resize and truncation", () => {
it("emits text-resize: auto for WIDTH_AND_HEIGHT", () => {
const file = makeFile(
makeNode({
id: "1:1",
name: "Title",
type: "TEXT",
characters: "Hello",
style: { fontFamily: "Inter", textAutoResize: "WIDTH_AND_HEIGHT" },
absoluteBoundingBox: { x: 0, y: 0, width: 100, height: 20 },
})
);

const output = generateDesignTree(file);

expect(output).toContain("text-resize: auto");
});

it("emits text-resize: fixed-height for HEIGHT", () => {
const file = makeFile(
makeNode({
id: "1:1",
name: "Body",
type: "TEXT",
characters: "Wrapped text",
style: { fontFamily: "Inter", textAutoResize: "HEIGHT" },
absoluteBoundingBox: { x: 0, y: 0, width: 300, height: 48 },
})
);

const output = generateDesignTree(file);

expect(output).toContain("text-resize: fixed-height");
});

it("emits text-resize: truncate with max-lines for TRUNCATE", () => {
const file = makeFile(
makeNode({
id: "1:1",
name: "Truncated",
type: "TEXT",
characters: "Long text that gets cut off",
style: { fontFamily: "Inter", textAutoResize: "TRUNCATE" },
maxLines: 2,
absoluteBoundingBox: { x: 0, y: 0, width: 200, height: 40 },
})
);

const output = generateDesignTree(file);

expect(output).toContain("text-resize: truncate");
expect(output).toContain("max-lines: 2");
});

it("emits text-overflow: ellipsis when textTruncation is ENDING", () => {
const file = makeFile(
makeNode({
id: "1:1",
name: "Ellipsis",
type: "TEXT",
characters: "Truncated text",
style: { fontFamily: "Inter", textAutoResize: "HEIGHT" },
textTruncation: "ENDING",
maxLines: 3,
absoluteBoundingBox: { x: 0, y: 0, width: 200, height: 60 },
})
);

const output = generateDesignTree(file);

expect(output).toContain("text-overflow: ellipsis");
expect(output).toContain("max-lines: 3");
});

it("emits paragraph-spacing when set", () => {
const file = makeFile(
makeNode({
id: "1:1",
name: "Paragraphs",
type: "TEXT",
characters: "First paragraph\n\nSecond paragraph",
style: { fontFamily: "Inter", paragraphSpacing: 16 },
absoluteBoundingBox: { x: 0, y: 0, width: 300, height: 100 },
})
);

const output = generateDesignTree(file);

expect(output).toContain("paragraph-spacing: 16px");
});

it("does not emit text-resize for NONE or missing textAutoResize", () => {
const file = makeFile(
makeNode({
id: "1:1",
name: "Plain",
type: "TEXT",
characters: "No resize",
style: { fontFamily: "Inter" },
absoluteBoundingBox: { x: 0, y: 0, width: 100, height: 20 },
})
);

const output = generateDesignTree(file);

expect(output).not.toContain("text-resize:");
});
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Good test coverage with a few edge cases to consider.

The test suite covers the main scenarios well. Consider adding these edge cases for completeness:

  1. TRUNCATE mode without maxLines - verifies only text-resize: truncate is emitted
  2. textTruncation: "DISABLED" - verifies no text-overflow: ellipsis is emitted
  3. paragraphSpacing: 0 - verifies no paragraph-spacing is emitted (falsy value)
💡 Optional: Additional edge case tests
it("emits text-resize: truncate without max-lines when maxLines is not set", () => {
  const file = makeFile(
    makeNode({
      id: "1:1",
      name: "TruncateNoMax",
      type: "TEXT",
      characters: "Truncated",
      style: { fontFamily: "Inter", textAutoResize: "TRUNCATE" },
      absoluteBoundingBox: { x: 0, y: 0, width: 200, height: 40 },
    })
  );

  const output = generateDesignTree(file);

  expect(output).toContain("text-resize: truncate");
  expect(output).not.toContain("max-lines:");
});

it("does not emit text-overflow for textTruncation: DISABLED", () => {
  const file = makeFile(
    makeNode({
      id: "1:1",
      name: "NoTruncation",
      type: "TEXT",
      characters: "Normal text",
      style: { fontFamily: "Inter", textAutoResize: "HEIGHT" },
      textTruncation: "DISABLED",
      absoluteBoundingBox: { x: 0, y: 0, width: 200, height: 40 },
    })
  );

  const output = generateDesignTree(file);

  expect(output).not.toContain("text-overflow:");
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/core/design-tree/design-tree.test.ts` around lines 1093 - 1200, Add three
edge-case tests to the existing "text auto-resize and truncation" suite using
makeFile/makeNode and generateDesignTree: (1) a TRUNCATE text node without
maxLines that asserts output contains "text-resize: truncate" and does NOT
contain "max-lines:"; (2) a text node with textTruncation: "DISABLED" (and
textAutoResize e.g. "HEIGHT") that asserts output does NOT contain
"text-overflow:"; (3) a text node with style.paragraphSpacing: 0 that asserts
output does NOT contain "paragraph-spacing:". Use unique test names like "emits
text-resize: truncate without max-lines", "does not emit text-overflow for
DISABLED", and "does not emit paragraph-spacing for 0" to match the existing
pattern.

- Populate textTruncation and maxLines in figma-transformer.ts
- Emit text-overflow: ellipsis for TRUNCATE mode
- Add 3 edge case tests (TRUNCATE without maxLines, DISABLED, paragraphSpacing: 0)

https://claude.ai/code/session_01PqgYRCyuLA48EzyFWnHM82
@let-sunny let-sunny merged commit 7bd712a into main Mar 31, 2026
3 checks passed
@let-sunny let-sunny deleted the feat/216-text-auto-resize branch March 31, 2026 03:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: emit textAutoResize and text truncation in design tree

2 participants