feat(kanban): wrap card text and support multi-line editing #66

Merged
AhmedHanafy725 merged 4 commits from development_kanban_card_multiline_text into development 2026-04-23 10:32:28 +00:00
Member

Summary

Kanban cards now wrap long text across multiple lines and auto-grow to fit, and the inline editor supports multi-line input. Base cardHeight in state remains the slider/transformer-controlled minimum; per-card actual heights are re-derived each render from card.text, textFs, and colW - 50, never persisted.

Closes #52

Changes

  • crates/hero_whiteboard_ui/static/web/js/whiteboard/kanban.js
    • cardText switched to wrap: 'word' and ellipsis removed. Text width unchanged at colW - 50.
    • renderKanban now does a two-pass layout: for every column it measures all cards and stores {heights[], offsets[]} in a module-level WeakMap<col, layout>. totalH is derived from the tallest stack.
    • renderColumn and renderCard read the layout back from the WeakMap. renderCard signature extended with cardYLocal, actualCardH; cardRect.height and menuHit.height use the per-card actual height.
    • cardGroup.on('dragend') computes per-card midpoints from the target column's layout, so reordering and cross-column drops work with variable-height cards. Defensive fallback to the uniform formula on cache miss.
    • The 3-dots menu button is anchored inside a 40-px top band so it stays at the visible top-right on tall cards rather than drifting into wrapped text.
    • editInline gains a multiline flag. Multi-line branch: <textarea>, auto-grow on input, Shift+Enter for newlines, Enter/blur commit, Escape cancel. Single-line <input> path preserved unchanged for board-title and column-title edits.
    • Both card edit entry points (cardRect double-click and the menu Edit item) pass multiline: true.

Preserved behaviors

  • Font scaling (PR #51): textFs / menuFs still derive from the base cardH.
  • Click-selection (PR #62): cardRect.on('click tap') still mutates stroke/strokeWidth directly, preserving Konva dblclick identity.
  • Transformer live-redraw (PR #63): writes state.cardHeight from live sy; downstream renderKanban re-measures wrapped text and re-stacks.
  • Edit regression fix (PR #65 open): showCardMenu still passes cardText directly; Edit call now includes the new multiline: true.

Out of scope

  • No schema/sync changes. card.text remains a plain string; \n round-trips through JSON.
  • No changes in shortcuts.js, tools.js, properties.js, or CSS. The whiteboard's global key handler already short-circuits on INPUT/TEXTAREA targets, so Delete/Backspace/Enter shortcuts don't fire while typing.
  • Persisted state stays two scalars per kanban (colWidth, cardHeight) — no per-card height in the wire format.

Test Results

  • cargo check --workspace: pass
  • cargo test --workspace --lib: pass
  • cargo clippy --workspace -- -D warnings: pass
  • cargo fmt --check: pass

Manual QA required: wrap rendering, stacking under tall cards, drag-drop into variable-height columns, textarea editing (Enter commit, Shift+Enter newline, Escape cancel), persistence across reload, and all preserved behaviors.

## Summary Kanban cards now wrap long text across multiple lines and auto-grow to fit, and the inline editor supports multi-line input. Base `cardHeight` in state remains the slider/transformer-controlled minimum; per-card actual heights are re-derived each render from `card.text`, `textFs`, and `colW - 50`, never persisted. ## Related Issue Closes https://forge.ourworld.tf/lhumina_code/hero_whiteboard/issues/52 ## Changes - `crates/hero_whiteboard_ui/static/web/js/whiteboard/kanban.js` - `cardText` switched to `wrap: 'word'` and `ellipsis` removed. Text width unchanged at `colW - 50`. - `renderKanban` now does a two-pass layout: for every column it measures all cards and stores `{heights[], offsets[]}` in a module-level `WeakMap<col, layout>`. `totalH` is derived from the tallest stack. - `renderColumn` and `renderCard` read the layout back from the WeakMap. `renderCard` signature extended with `cardYLocal, actualCardH`; `cardRect.height` and `menuHit.height` use the per-card actual height. - `cardGroup.on('dragend')` computes per-card midpoints from the target column's layout, so reordering and cross-column drops work with variable-height cards. Defensive fallback to the uniform formula on cache miss. - The 3-dots menu button is anchored inside a 40-px top band so it stays at the visible top-right on tall cards rather than drifting into wrapped text. - `editInline` gains a `multiline` flag. Multi-line branch: `<textarea>`, auto-grow on `input`, `Shift+Enter` for newlines, `Enter`/`blur` commit, `Escape` cancel. Single-line `<input>` path preserved unchanged for board-title and column-title edits. - Both card edit entry points (cardRect double-click and the menu Edit item) pass `multiline: true`. ## Preserved behaviors - Font scaling (PR #51): `textFs` / `menuFs` still derive from the base `cardH`. - Click-selection (PR #62): `cardRect.on('click tap')` still mutates stroke/strokeWidth directly, preserving Konva dblclick identity. - Transformer live-redraw (PR #63): writes `state.cardHeight` from live `sy`; downstream `renderKanban` re-measures wrapped text and re-stacks. - Edit regression fix (PR #65 open): `showCardMenu` still passes `cardText` directly; Edit call now includes the new `multiline: true`. ## Out of scope - No schema/sync changes. `card.text` remains a plain string; `\n` round-trips through JSON. - No changes in `shortcuts.js`, `tools.js`, `properties.js`, or CSS. The whiteboard's global key handler already short-circuits on INPUT/TEXTAREA targets, so Delete/Backspace/Enter shortcuts don't fire while typing. - Persisted state stays two scalars per kanban (`colWidth`, `cardHeight`) — no per-card height in the wire format. ## Test Results - `cargo check --workspace`: pass - `cargo test --workspace --lib`: pass - `cargo clippy --workspace -- -D warnings`: pass - `cargo fmt --check`: pass Manual QA required: wrap rendering, stacking under tall cards, drag-drop into variable-height columns, textarea editing (Enter commit, Shift+Enter newline, Escape cancel), persistence across reload, and all preserved behaviors.
feat(kanban): wrap card text and support multi-line editing
All checks were successful
CI / build (pull_request) Successful in 2m11s
1a3e61fdc2
Card text now word-wraps instead of truncating with an ellipsis, and
cards auto-grow vertically to fit wrapped or explicitly multi-line
content. Base cardHeight in state remains the slider/transformer-
controlled minimum and is not affected by the new auto-grow; per-card
actual heights are re-derived every render from the text, font size,
and text width.

renderKanban now does a two-pass layout: it measures every column's
cards up-front, stores {heights[], offsets[]} per column in a module-
level WeakMap, and computes the column-background height from the
tallest stack. renderColumn and renderCard read the layout back, and
the dragend slot calculation uses per-card midpoints so reordering
works correctly when cards have different heights.

editInline gains a multiline flag. When true it renders a <textarea>
with auto-grow on input, Shift+Enter for newlines, Enter/blur to
commit, and Escape to cancel. Single-line <input> path is preserved
for board and column titles. Both card edit entry points (double-click
and the 3-dots menu Edit item) now pass multiline: true.

#52
fix(kanban): match editor font to card and disable spellcheck squiggles
Some checks failed
CI / build (pull_request) Failing after 2s
9d2fd64486
The inline textarea inherited the browser's default font family and
spellcheck, so editing a card showed a different typeface than the
Konva-rendered text and red squiggles under every word. Pick up the
text node's own fontFamily (defaulting to Arial to match Konva's own
default) and turn off spellcheck / autocomplete / autocorrect /
autocapitalize on the overlay.
fix(kanban): grow card live while editing so following cards slide down
All checks were successful
CI / build (pull_request) Successful in 2m9s
9a6b4c90bd
The edit textarea auto-grew to fit the typed text, but the underlying
card rect only resized on commit, so mid-typing the textarea visually
overflowed onto the next card. Push the current textarea value into
card.text on each input event and re-render the kanban so the card
rect expands and cards below move down in real time. Sync still
fires only on commit, so intermediate keystrokes do not trigger
network writes.
fix(kanban): match Konva card-text line-height to editor so card grows
All checks were successful
CI / build (pull_request) Successful in 2m8s
65f2847ecb
Konva.Text defaults lineHeight to 1 while the edit textarea uses
line-height 1.3, so the Konva-measured height for the same content
was ~30 percent shorter than the browser actually rendered. The
live-grow code trusted the Konva measurement and left the card
visibly too short while typing. Set lineHeight 1.3 on both the
rendered cardText node and the measureCardTextHeight temp node so
both sides agree.
AhmedHanafy725 merged commit 6f487b5fbc into development 2026-04-23 10:32:28 +00:00
AhmedHanafy725 deleted branch development_kanban_card_multiline_text 2026-04-23 10:32:32 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
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
lhumina_code/hero_whiteboard!66
No description provided.