Let headers and row labels size their own column

Fit worked on the values and not on the headings. Auto-fit measures cells
with getBoundingClientRect() and sets each column's min-width from the
result, but the datagrid's CSS wraps and clips header text — so a clipped th
measures at the width it was *allotted*, not the width of its content, and a
column can never grow to fit its own heading. Row labels are th elements in
tbody and clip for the same reason.

white-space: nowrap on those cells, and nothing else: no width, no overflow.
The measurement then sees the full text and the existing sizing logic does
the rest.

Folded into the stylesheet already being injected for the grand-total
column, and renamed from pf-hide-split-total to pf-grid-css now that it does
more than the one thing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Paul Trowbridge 2026-09-17 14:02:59 -04:00
parent 81c4672147
commit 9a748b8178

View File

@ -1007,7 +1007,23 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio
// survives adding measures or rearranging the pivot, unlike hiding by position. // survives adding measures or rearranging the pivot, unlike hiding by position.
// The rule has to live inside the plugin's shadow root; a document stylesheet // The rule has to live inside the plugin's shadow root; a document stylesheet
// cannot reach it. // cannot reach it.
const HIDE_SPLIT_TOTAL_CSS = ` const GRID_CSS = `
/* Let headers and row labels size their own column.
*
* Auto-fit measures cells with getBoundingClientRect() and sets each column's
* min-width from the result but the datagrid's own CSS wraps and clips
* header text, so a clipped th measures at the width it was *allotted*, not
* the width of its content. The column can therefore never grow to fit its
* own heading, which is why the values fit and the headings did not. Row
* labels are th elements in tbody and clip for the same reason.
*
* nowrap alone: no width or overflow is touched, so the measurement sees the
* full text and the existing sizing logic does the rest. */
thead th,
tbody th {
white-space: nowrap !important;
}
th.psp-split-total:not(.psp-split-subtotal), th.psp-split-total:not(.psp-split-subtotal),
td.psp-split-total:not(.psp-split-subtotal) { td.psp-split-total:not(.psp-split-subtotal) {
visibility: hidden !important; visibility: hidden !important;
@ -1045,10 +1061,10 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio
// Retried from the config-update handler, and once on a short delay. // Retried from the config-update handler, and once on a short delay.
if (!grid) return false if (!grid) return false
const root = grid.getRootNode() const root = grid.getRootNode()
if (!root || root.querySelector?.('#pf-hide-split-total')) return true if (!root || root.querySelector?.('#pf-grid-css')) return true
const style = document.createElement('style') const style = document.createElement('style')
style.id = 'pf-hide-split-total' style.id = 'pf-grid-css'
style.textContent = HIDE_SPLIT_TOTAL_CSS style.textContent = GRID_CSS
;(root.appendChild ? root : document.head).appendChild(style) ;(root.appendChild ? root : document.head).appendChild(style)
return true return true
} }