Skip to content

Add header pitch and leading to clin_row_height() (#117) - #118

Merged
mstackhouse merged 1 commit into
developmentfrom
gh_issue_117
Jul 27, 2026
Merged

Add header pitch and leading to clin_row_height() (#117)#118
mstackhouse merged 1 commit into
developmentfrom
gh_issue_117

Conversation

@mstackhouse

Copy link
Copy Markdown
Member

Closes #117. The last of the three vertical controls #97 asked for.

Measuring settled the design question you left open

You asked whether a header height would reach the multi-line case, and suspected not. It doesn't. Reading what Word actually receives for a 3-line header cell:

lever emits reaches a 3-line cell?
clin_row_height(body = 15.35) nothing on the header — stays line=240, trHeight=796/auto no
header height, rule = "atleast" trHeight=260/atLeast no — a floor, the cell still grows past it
header height, rule = "exact" trHeight=260/exact only by clipping
line_spacing(space = 0.75) w:line=180 yes

So both ship, and the docs say which one to reach for. header bounds the header rows the way body bounds the body rows; header_leading closes the gap between the lines inside a cell, which is what a wrapped arm label needs.

clin_row_height(body = 15.35, title = 11.4, footnote = 11.4,
                header = 13, header_leading = 0.75)

Verified together: hdr line=180, hdr trH=260/atLeast, body trH=307/atLeast — three independent pitches, none interfering.

Leading is a multiple, not a length

The one wrinkle. flextable's line_spacing() takes a multiple of single spacing and Word writes it that way — space = 0.75 becomes w:line=180 against a single-spacing 240, with no lineRule. There is no points form to convert to without hand-writing w:lineRule="exact", which would mean going around flextable into officer's XML.

So header_leading is a multiple, unit does not apply to it, and it is named and documented accordingly rather than pretending to be a length like its neighbours.

It has to be deferred, and your styler is why

Applied at verb-call time it would be undone: your clinify_defaults.R calls flextable::line_spacing(x, space = 1, part = "all") in all three styling functions. So it is applied in finish_table_(), after the option styling function — the same precedence rule as the rest of the per-table config.

There is a test that stands that styler up and checks the leading survives at 0.75 rather than being reset to 1.

Verification

  • 2,156 tests pass, zero snapshot changes.
  • devtools::check() — 0 errors, 0 warnings, and the unable to verify current time NOTE, which is the no-network note this repo's cran-comments.md documents as local-only; it comes and goes between runs on this machine.
  • Lints on R/row_height.R: 4, unchanged from development.
  • Assertions read w:line, w:trHeight and hRule out of word/document.xml, so they check what Word receives rather than in-memory fields.
  • One pre-existing assertion on the "nothing asked for" message was updated, since it now names all five arguments.

Note

Thank you for the header line-structure check — the finding that 9 of 30 tables stack their header lines differently from the reference is exactly the kind of thing that justifies this being an API lever rather than a per-project workaround. Worth saying that header_leading changes the leading, not where the lines break: if 14-1.02 is putting p-value on header line 5 where the reference has line 6, that is a wrapping/level-count difference rather than a spacing one, and this won't move it. Happy to look at that separately if you file it.

DESCRIPTION left at 0.4.0 with the entry under # clinify (development version), as with #114/#115/#116.

🤖 Generated with Claude Code

The last of the three vertical controls #97 asked for. clin_row_height() owned
the body, titles and footnotes but nothing reached the column header, so
tightening a wrapped arm label meant a raw flextable::line_spacing(part =
"header") in the project's styling function.

The header needs two levers, not one, and measuring them settled which matters.
`header` bounds the header rows the way `body` bounds the body rows - Word gets
trHeight/atLeast - but under "atleast" it is a floor, so a header cell holding
three lines still grows past it and the multi-line case is untouched.
`header_leading` is what closes the gap between those lines: it lands as
w:line, so 0.75 draws them three quarters as far apart. Both are available, and
the docs say plainly which one reaches a wrapped label.

Leading is the one measurement in this function that is not a length. flextable
and Word both express it as a multiple of single spacing, so there is no points
form to convert to and `unit` does not apply to it. It is named and documented
as a multiple for that reason.

Applied as the table renders rather than when the verb is called, because a
styling function that calls line_spacing(part = "all") - as the CDISC pilot's
does - would otherwise undo it. There is a test standing that styler up and
checking the leading survives.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

1 participant