feat(render): complete both renderers, click-to-select and overflow #31

Merged
TJC merged 8 commits from feat/m4-renderers into main 2026-08-18 14:10:41 +01:00
Collaborator

Summary

  • draws every mark in decision 19's vocabulary through both renderers, proved
    on a fixture sheet that uses all of them plus every box shape and an opaque
    widget node
  • clicking a primitive selects the node that emitted it, and inside a widget
    that is the widget node, so a tick box selects the todo widget
  • the selected node is outlined from the box its primitives cover; a click that
    misses every mark clears the selection
  • content past the bottom margin still draws, under a translucent red band
    labelled with the overflow in mm, and export warns naming it
  • the download takes a list of sheets and writes a page for each, so decision
    24 is a caller that passes more of them
  • the band and the outline are preview overlays rather than primitives, so both
    renderers keep consuming the same list and the exported PDF stays clean

Test plan

  • pnpm test - 314 passing, including one assertion per mark that the pdf op is
    what the svg element says it has to be
  • pnpm exec tsc --noEmit
  • pnpm lint

Closes #14
Closes #15

## Summary - draws every mark in decision 19's vocabulary through both renderers, proved on a fixture sheet that uses all of them plus every box shape and an opaque widget node - clicking a primitive selects the node that emitted it, and inside a widget that is the widget node, so a tick box selects the todo widget - the selected node is outlined from the box its primitives cover; a click that misses every mark clears the selection - content past the bottom margin still draws, under a translucent red band labelled with the overflow in mm, and export warns naming it - the download takes a list of sheets and writes a page for each, so decision 24 is a caller that passes more of them - the band and the outline are preview overlays rather than primitives, so both renderers keep consuming the same list and the exported PDF stays clean ## Test plan - pnpm test - 314 passing, including one assertion per mark that the pdf op is what the svg element says it has to be - pnpm exec tsc --noEmit - pnpm lint Closes #14 Closes #15
- a fixture sheet holding line, rect, circle, text and spacer, every box
  shape and an opaque widget node
- proves a spacer draws nothing and still takes its space
- proves a primitive inside a widget answers to the widget node id
- one box per primitive, unioned per node id
- text is boxed back from the baseline it carries, so nothing derives a
  second one
- a click hands over the id the primitive already carries, so a tick box
  inside a widget selects the widget rather than a rect
- the selected node is outlined from the box its primitives cover, and a
  click that misses every mark clears it
- an unfilled shape takes a click anywhere inside it and a hairline gets
  a hit stroke wide enough to aim at
- the outline tree this selection drives is #19, so for now the id is
  named in the toolbar

Closes #14
- one assertion per mark that the pdf op is what the svg element says it
  has to be, derived from the element rather than restated
- mm -> pt and pdf-lib's bottom-left origin are then the only two things
  the renderers are allowed to differ by
- the sheet carries how far its content runs over and the band to draw
  over it, measured against the margin the template sets
- the band stops at the paper edge and the depth does not: one is what
  the preview draws, the other is what the author has to fix
- content past the bottom margin draws under a translucent red band
  labelled with the overflow in mm, and the band takes no clicks
- export warns naming the overflow and downloads nothing if turned down
- the download takes a list of sheets and writes a page for each, so
  decision 24 is a caller that passes more of them

Closes #15
TJC requested review from TJC 2026-08-18 14:08:03 +01:00
TJC approved these changes 2026-08-18 14:08:07 +01:00
Dismissed
- FITS sat at float noise while the label rounds to 0.1mm, so content a
  few hundredths past the margin banded and warned about "0.0mm"
- a string the font cannot encode still reaches the renderer, so
  drawText throws and the button silently did nothing
Author
Collaborator

Review fixes pushed:

  • overflow.ts fits tolerance sat at 1e-9 while the label rounds to 0.1mm, so content a few hundredths past the margin drew a red band and warned "Content draws 0.0mm past the bottom margin". Tolerance now sits at the reporting resolution (cb0de79).
  • downloadPdf awaited renderPdf with no handler and App fired it as a floating promise, so a string Helvetica cannot encode (layout flags the node but still emits the primitive) made the button do nothing at all, with the rejection only reaching the console. Now caught and reported (c754018).

Test plan: 316 tests pass, tsc --noEmit and eslint clean; both fixes carry a regression test.

Review fixes pushed: - `overflow.ts` fits tolerance sat at `1e-9` while the label rounds to 0.1mm, so content a few hundredths past the margin drew a red band and warned "Content draws 0.0mm past the bottom margin". Tolerance now sits at the reporting resolution (cb0de79). - `downloadPdf` awaited `renderPdf` with no handler and `App` fired it as a floating promise, so a string Helvetica cannot encode (layout flags the node but still emits the primitive) made the button do nothing at all, with the rejection only reaching the console. Now caught and reported (c754018). Test plan: 316 tests pass, `tsc --noEmit` and `eslint` clean; both fixes carry a regression test.
TJC approved these changes 2026-08-18 14:10:38 +01:00
TJC merged commit 8bc9ef8bc5 into main 2026-08-18 14:10:41 +01:00
Sign in to join this conversation.
No reviewers
TJC
No labels
chore
core
render
ui
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
TJC/daily-planner-template!31
No description provided.