Kanban: resize minimum is too tight — cannot shrink further #50
Labels
No labels
prio_critical
prio_low
type_bug
type_contact
type_issue
type_lead
type_question
type_story
type_task
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lhumina_code/hero_whiteboard#50
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
When resizing a kanban via the transformer handles, the board stops shrinking before it looks small enough. The property-panel sliders also have conservative minimums.
Evidence
crates/hero_whiteboard_ui/static/web/js/whiteboard/properties.js:prop-kanban-col-widthslidermin="140",prop-kanban-card-heightslidermin="30".applyTransformfor kanban type), any clamp is set against these same bounds.Fix
colWidth min 100,cardHeight min 22. Update both the sliders inproperties.jsand the clamp inapplyTransform(tools.js) so transformer-resize and slider match.colW - 12 = 88px of text width — sufficient for '+ Add card').Implementation Spec for Issue #50
Objective
Fix two bugs in kanban resize behavior:
Minimum clamps are too high. Both the transformer-resize path and the property-panel sliders refuse to shrink the kanban below a size that still feels large on screen. Lower both to
colWidth min 100andcardHeight min 22.Snapback on release. When the user resizes via the transformer handles and releases the mouse, the kanban visibly jumps to a different size than what was shown during the drag. Root cause: the kanban has fixed constants in its layout (padding, header, card-gap, "+ Column" button slot, footer) that are uniformly scaled by Konva during drag but revert to their unscaled constant values on release, while only
colWidth/cardHeightare scaled into state byapplyTransform. Fix by doing a live redraw during the transform event (mirroring the existing calendar pattern) so on-release dimensions equal on-drag dimensions.Requirements
transformframe and the post-transformendrender, within normal rounding).colWidth = 100andcardHeight = 22via both the transformer and the sliders.applyTransformclamp (100for column width,22for card height).+ Add cardbutton remains legible inside a 100-wide column.Files to Modify/Create
Modify (no new files):
crates/hero_whiteboard_ui/static/web/js/whiteboard/properties.js— lower sliderminattributes.crates/hero_whiteboard_ui/static/web/js/whiteboard/objects.js— update clamps in the kanban branch ofapplyTransform.crates/hero_whiteboard_ui/static/web/js/whiteboard/tools.js— extend the existingtransformlive-redraw handler to also cover kanban, eliminating the snapback.Implementation Plan
Step 1 — Lower slider minimums in properties panel
properties.jsmin="140"tomin="100"on theprop-kanban-col-widthrange input.min="30"tomin="22"on theprop-kanban-card-heightrange input.maxvalues or defaults. Do not touch the input handlers (around lines 872-897); they alreadyparseIntand assign directly, no bounds logic lives there.Step 2 — Update clamp in
applyTransform(kanban branch)objects.jsMath.max(80, ...)toMath.max(100, ...)forcolWidth.Math.max(24, ...)toMath.max(22, ...)forcardHeight.Math.round(...). Do not switch toMath.floororMath.ceil.Step 3 — Add kanban to the live-redraw
transformhandlertools.jstransformer.on('transform', ...)handler (around lines 115-138) which currently live-redraws calendar nodes.node.hasName('kanban')is true andWhiteboardKanbanis defined and(scaleX !== 1 || scaleY !== 1):sx = node.scaleX(),sy = node.scaleY().st = node._kanbanState. If missing, skip.newColW = Math.max(100, Math.round((st.colWidth || 200) * sx)).newCardH = Math.max(22, Math.round((st.cardHeight || 44) * sy)).st.colWidth = newColW; st.cardHeight = newCardH;.node.scaleX(1); node.scaleY(1);.WhiteboardKanban.redraw(node).anyLiveRedrawnflag (already present; drivestransformer.forceUpdate()at the bottom).applyTransforminobjects.jsalready has an early exit when scale is ~1, so once live redraw has reset scale to 1,applyTransformbecomes a no-op for kanban — no double-apply.100/22used in the live redraw matches the clamp used inapplyTransformand the slider minimums).Acceptance Criteria
prop-kanban-col-widthminattribute is100inproperties.js.prop-kanban-card-heightminattribute is22inproperties.js.applyTransformkanban branch clamp isMath.max(100, ...)oncolWidthandMath.max(22, ...)oncardHeight(objects.js).tools.js, thetransformevent handler live-redraws kanban nodes (scalescolWidth/cardHeightinto state, resets group scale to 1, callsWhiteboardKanban.redraw), matching the existing calendar pattern.100(col width) and22(card height); the board re-renders correctly at those minima.+ Add cardtext remains visible and centered inside a 100-wide column.WhiteboardSync.onUpdatestill fires fromtransformend— live redraw must not suppress it).Notes
Snapback root cause (beyond what the issue body diagnosed).
During a transform drag, Konva applies the group's
scaleX/scaleYuniformly to every child. The kanban group's rendered width and height are computed inkanban.jsrenderKanbanas:totalW = columns.length * (colW + padding) + padding + (colW/2 + padding)→(N + 0.5)*colW + (N + 2)*padding(N = column count, padding = 8).totalH = headerH + 8 + max(K,1)*(cardH + cardGap) + 50→94 + 6K + K*cardH(K = max cards per column, headerH = 36, cardGap = 6).Both formulas have a scale-dependent term (
(N+0.5)*colW,K*cardH) and a scale-independent constant term ((N+2)*padding,94 + 6K).While the user drags, Konva scales both terms uniformly: visible width =
scaleX * totalW_old. On release,applyTransformonly multipliescolW/cardHby scale, rounds, writes into state, resets group scale to 1, and callsrenderKanban.renderKanbanrecomputestotalWwith the newcolWbut the padding/header constants remain unscaled. The mismatch is approximately(constant_term) * (scaleX - 1):(N+2)*padding*(scaleX - 1)px (and analogously on Y).This is what the user perceived as "it decreases a bit" on release after enlarging.
Math.roundcontributes at most ±0.5 px per axis — not the source.Fix: live redraw. By converting scale to state on every
transformtick and resetting the group's scale to 1, the next tick starts from the newly-rendered box whose constants are already in place. The live-drawn dimensions therefore track the state dimensions exactly, so thetransformendrender equals the lasttransformrender — no visible jump.Why not instead scale the padding/header in
applyTransform? Those constants are style, not data: scaling the 8-px card padding or the 36-px header text height per-resize would bake visual drift into persisted state and compound across resizes. The live-redraw approach keepspadding/headerH/cardGapas constants and the authoritative state stays two scalars (colWidth,cardHeight).Why
Math.roundnotMath.floor. The issue body speculated aboutMath.floordropping fractional pixels. The code actually usesMath.round, which rounds to nearest — its bias is ≤0.5 px per axis per resize. The dominant snapback term is the fixed constants, not rounding. LeaveMath.roundas-is.Why the two sides need matching clamps. If the slider
minwere100butapplyTransformclamped at80, a transformer-drag could leave the kanban below the slider's reachable floor and the slider would render "pinned" at 100 while state showed 80 — visually inconsistent. Using100/22on both sides keeps them in sync. The existing80/24clamp inapplyTransformis intentionally moved to100/22for this reason (22is a lowering from24,100is a raising from80— both land at the spec's target values, matching the slider minimums).Scope. No changes to the transformer's
boundBoxFunc(that guard is on the visual transformer box, not kanban units, and with 100-wide columns the visual min is far above that floor). No changes to defaults, column colors, history snapshots, sync, or any other code path.Test Results
JavaScript-only change; Rust workspace validated for regressions.
cargo check --workspacecargo test --workspace --libcargo clippy --workspace -- -D warningscargo fmt --checkThe repository has no Rust tests exercising the JavaScript whiteboard modules, so the suite confirms regression safety for the Rust side. Manual verification against a running UI is required to confirm the snapback fix and the new minima; steps are listed in the spec's Acceptance Criteria.
Implementation Summary
Two kanban resize bugs fixed:
colWidth = 100andcardHeight = 22, so the board shrinks further and the slider/transformer paths stay consistent.transformtick, the current Konva scale is written intocolWidth/cardHeightstate, the group scale is reset to 1, andWhiteboardKanban.redrawre-renders with the new state. Thetransformendrender therefore matches the lasttransformrender instead of shrinking by the unscaled-padding delta.Files changed
crates/hero_whiteboard_ui/static/web/js/whiteboard/properties.js— sliderminvalues 140→100 and 30→22.crates/hero_whiteboard_ui/static/web/js/whiteboard/objects.js—applyTransformkanban clamp 80→100, 24→22.crates/hero_whiteboard_ui/static/web/js/whiteboard/tools.js—transformlive-redraw extended to kanban; the existing calendar branch is untouched.Why the snapback existed
kanban.jsrenderKanbancomputestotalW = (N+0.5)*colW + (N+2)*paddingandtotalH = 94 + 6K + K*cardH— both contain a scale-dependent term and a scale-independent constant (padding,headerH,cardGap, the+ Columnslot, and the footer). While the user drags, Konva scales every child uniformly, so the on-screen box grows or shrinks byscale * totalW_old. On release, the old implementation scaled onlycolW/cardHinto state, reset scale to 1, and redrew — but the constant terms were no longer pre-scaled, so the rendered size differed from the drag preview by approximatelyconstants * (scale − 1). The live-redraw fix repeats that scale-to-state conversion during the drag itself, so the final render is the same render that was already visible.Test results
cargo check --workspace: passcargo test --workspace --lib: passcargo clippy --workspace -- -D warnings: passcargo fmt --check: passNotes / out of scope
boundBoxFunc, kanban defaults, history/undo, sync, or any other object type.Math.round(notMath.floor) is preserved in the clamp — its ±0.5 px bias is dwarfed by the former constant-term delta and was not the cause of the perceived shrink.+ Add cardtext remains legible in a 100-wide column, (d) no regression on other object types.Pull request opened: #63
This PR implements the changes discussed in this issue.