Skip to content

feat: size.markdown-fit warns when markdown text runs past its block - #46

Merged
debabsah merged 2 commits into
mainfrom
feat/markdown-fit
Oct 6, 2026
Merged

debabsah merged 2 commits into
mainfrom
feat/markdown-fit

Conversation

@debabsah

@debabsah debabsah commented Oct 5, 2026 •

Copy link
Copy Markdown
Owner

advise now warns when a markdown block's text runs past its bottom edge. Superset clips the overflow inside the block, or scrolls it, with no warning. A showcase dashboard's definitions block was cut off mid-section and nothing said so.

Added

  • size.markdown-fit (warn or info, fixable). It estimates each markdown block's rendered height from its structure and width, and gives the overflow and the height it needs: "about 33 lines cut off at the bottom edge … it needs ~29.6 units at 12/12, has 10; raise the height".

    • What it reads: headings by level, setext headings, paragraphs and breaks, lists (tight, loose, nested), GFM tables, quotes, fenced code and rules. Lines wrap word by word with Inter's measured widths, and block margins collapse the way CSS does.
    • Two bounds:
      • The low bound is never more than any release drew; it decides whether the rule fires.
      • The high bound is never less, allowing for Windows scrollbars; --fix raises the height to it, rounded up to a fifth of a unit.
    • Severity: warn when text is cut on every release; info when only the last line or the padding reaches the edge, so the block scrolls a few pixels.
    • No fix for a header or footer a standard owns (reported only if text is cut), a block holding an image, or a block that would need more than 100 units. With a theme or CSS that sets type, the finding says it assumes Superset's default type.
    • Where it looks: layout rows, tabs, sub-tabs, headers and footers, allowing for the filter bar.
  • layout.markdown-height now fixes a one-line block to its fitted height rather than a flat 2 units. The old target cut a # heading's padding, and on 4.1.4 and 5.0.0 a ## heading at 2 units overflowed by 1.4 px. This also covers the short-strip case: one line of text needs 1.6 units, ### 1.8, ## 2.2 (2.0 on 6.1.0) and # 2.4.

  • Docs: blocks under 1 unit are documented as drawn at 40 px (GRID_MIN_ROW_UNITS). The spec still accepts them.

  • Reads the dashboard's CSS (second commit). The estimate applies the spec's own dashboard CSS for markdown, then Superset's styles per release:

    • rules: those under .dashboard-markdown, with descendant, >, + and ~ combinators and :first-child, :last-child and :only-child;
    • properties: font size, line height, weight, letter and word spacing, margins, padding and borders, in px, em, rem or %;
    • cascade: !important, then specificity, then source order.

    Blocks are laid out as elements, with CSS margin collapsing. A finding now names only the CSS it can't read (another font family, attribute selectors and pseudo-elements, @media, var() or calc()), rather than assuming Superset's default type. On a real dashboard whose CSS changes type, the first commit warned falsely on a one-line footer and missed a block 47 px over; both now fall inside the bounds. The rule measures in a 1440 px wide window, so a fix holds at any wider width.

Calibration

  • Corpus: 17 texts at 12, 8, 6, 4 and 3 twelfths on 4.1.4, 5.0.0 and 6.1.0 (headless Chromium, 1600 px), plus a 1,000-word text beside the filter bar. 4.1.4 and 5.0.0 render alike; 6.1.0's headings, lists, tables and quotes are spaced differently.
  • Accuracy: at Superset's own styles the model matched 586 of 624 measured heights within 1.5 px; the cascade matched the computed style of all 570 elements measured; and a styled corpus of 14 blocks with its own stylesheet is recorded at 1440 and 1600 px on every release. The low bound never exceeded a measurement, and the high bound never fell short.
  • Superset source cited:
    • holder padding: DashboardBuilder.tsx:326-332 at 4.1.4, :311-317 at 6.1.0;
    • overflow scrolls inside the block: Markdown.jsx:106-109, and Markdown/Markdown.tsx:126-130 at 6.1.0;
    • the 40 px floor: util/constants.ts:42.
  • Reproducible: tools/record_markdown_fit.py records the fixture and reproduces it byte for byte. tools/ci_live_markdown_fit.py is a new step in the live CI job, on every release.

Tests

  • Offline: 1874 passed, 1 skipped; params_drift --all and the rule table are clean. tests/test_markdown_fit.py checks both bounds against every measurement.
  • Live: passes on 4.1.4, 5.0.0 and 6.1.0.
  • Not verified: Linux Chromium (the new CI step is its first run) and real Windows (scrollbars emulated at 17 px).

Design brain 11

This collides with the integration branch's "10" from #38–#44. The numbers need reconciling at merge, as noted on those PRs.

Markdown inside sketch layouts exists only on feat/sketch-blocks (#41). Once that merges, this rule needs to read sketch legend blocks too.

A showcase About tab cut its definitions off mid-section at 10 units and nothing
said so: Superset scrolls a markdown block's overflow inside the block, and macOS
draws no scrollbar there. advise now estimates each block's text height from its
markdown (headings by level, paragraphs and hard breaks, lists tight, loose and
nested, GFM tables, quotes, code, rules, <br>) and its width, and compares it with
the block.

- chartwright/design/markdown_fit.py: the estimate. Type sizes, margins, Inter's
  character widths and the grid widths (1536 px at a 1600 px viewport, 1276 or
  1308 px beside the filter bar) measured on 4.1.4, 5.0.0 and 6.1.0; text wrapped
  word by word, margins collapsed as CSS does. A low bound (never above any
  release) decides; a high bound (never below, allowing for Windows scrollbars)
  sizes the fix.
- size.markdown-fit (warn/info, fixable): warns when the low bound cuts letters
  off on every release and says by how much ("it needs ~29.6 units at 12/12, has
  10"); an info when only the last line or the padding reaches the edge. Covers
  layout rows, tabs, sub-tabs, header and footer rows. No fix for a standard's
  row, a block with an image, or past 100 units. Short strips under 2 units are
  the same estimate: 32 px of padding plus the line's margins.
- layout.markdown-height fixes a one-line block to the height its line takes
  (1.6 to 2.4 units) instead of 2, which cut a level-1 heading's padding off.
- Design brain 11.
- tools/record_markdown_fit.py records the calibration into
  tests/fixtures/markdown_fit/measurements.json (17 texts, five widths, three
  releases, plus renders with Windows-style scrollbars at three heights);
  tests/test_markdown_fit.py checks both bounds against every measurement;
  tools/ci_live_markdown_fit.py runs in the live CI job on every release.
Dashboards that set their markdown's text sizes in CSS were estimated with
Superset's own sizes, so the rule missed both ways: a long block a few lines
over went unreported, a small footer that fits got a warning, and captions set
smaller than Superset's text were under-estimated.

- markdown_fit.py now reads the spec's dashboard.css and applies it in cascade
  order (!important, specificity, source order) over Superset's own styles,
  written as CSS per release: rules on .dashboard-markdown and its elements,
  with descendant, child, + and ~ combinators, :first-child and :last-child,
  for font-size, line-height, font-weight, letter- and word-spacing, margins,
  padding, borders and border-spacing (px, em, rem, %; unitless line heights).
  Measured on every release: every .dashboard-markdown rule beats Superset's,
  except an h6's font size and h4-h6 weight, which the markdown component sets
  in its own class; heading and body line heights are factors.
- The layout is now an element tree with CSS margin collapsing (li margins,
  p:last-child), line boxes from their inline text (a smaller <em> in a line),
  inline font sizes and padding (em, code) in the widths, measured Inter widths
  for Latin-1 and common symbols, and wide/narrow guesses for the rest per bound.
- CSS it can't read that could size markdown (another font family, attribute
  selectors and pseudo-elements, @media, var(), a percentage margin, the
  block's padding, class-less rules) is named in the finding instead of the
  old blanket "assumes Superset's default" caveat; a theme is still named.
- The rule assumes a 1440 px window (wider windows wrap less, so the fix holds
  there too), estimates only the releases the spec can go to (a theme leaves
  out 4.1.4 and 5.0.0, so a horizontal filter bar sits on top), and lets a
  block run under half a px over, since scrollHeight is whole px.
- The fixture now holds both windows, a styled sales-review dashboard's 14
  blocks under its own CSS, 570 elements' computed styles (no CSS,
  every property on every element, the styled dashboard's CSS) and verify passes
  for corpus and styled blocks at 1440. Tests check the cascade against every
  computed style and both bounds against every height; the live CI check covers
  the styled blocks too.
@debabsah
debabsah merged commit 9c688d3 into main Oct 6, 2026
7 checks passed
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