Skip to content

v0.6.22 — useHistoryStack hook extracted from ComposeBoard.tsx

Choose a tag to compare

@wwppee wwppee released this 16 Jul 03:26

v0.6.22 — useHistoryStack hook extracted from ComposeBoard.tsx

The first slice of the long-deferred "ComposeBoard hooks/state 抽离"
backlog item. The undo/redo stack is the most self-contained piece
of ComposeBoard state — it only reads state (passed in), writes
to setState / setSelectedId / announce (all passed in), and
consumes the pure applyEntry / invertEntry functions that
already live in lib/compose-history.ts. So it's the lowest-risk
extraction: the behaviour is unchanged, the public surface is
mechanical, and any regression is caught by a new dedicated test
suite.

What got extracted

  • The { past, future } state.
  • The commit callback (apply + push entry + announce label).
  • The undo / redo callbacks (apply inverted / forward entry,
    push onto the other stack, announce).
  • The "coalesce arrow-key moves" logic from moveBlock — the
    single thing the lib version didn't know about.
  • The "clear history on wholesale canvas replacement" path
    (load board / import JSON / reset canvas).

New hook surface

const { history, commit, pushEntry, pushOrMergeMoveEntry,
        clearHistory, undo, redo, canUndo, canRedo }
  = useHistoryStack({ state, setState, setSelectedId, announce, t });

The 5 entry-point methods map to 5 distinct use cases:

Method Used by Why a separate method
commit 20+ callbacks (connection edits, addBlock, connect, disconnect, ...) Standard "I have a before/after transition to record" path.
pushEntry endBlockDrag State already mutated; recording only the final delta.
pushOrMergeMoveEntry moveBlock (arrow-key handler) Holding an arrow key fires many moveBlock calls; merge into ONE undo step.
clearHistory loadBoardFromServer, importJson, resetCanvas Wholesale canvas replacement.
undo / redo keyboard handler, toolbar buttons Apply inverted / forward entry, push onto the other stack, announce.

Files touched (8)

Area Files
New hook web/src/app/compose/use-history-stack.ts (209 lines, well-commented)
Refactored web/src/app/compose/ComposeBoard.tsx (-40 lines net)
Tests web/tests/use-history-stack.test.tsx (12 new tests, 516 lines)
Docs CHANGELOG.md, AGENTS.md
Versions package.json, web/package.json (both → 0.6.22)

File size

  • ComposeBoard.tsx: 2184 → 2144 lines (-40). The drop is
    smaller than the extracted code because the useHistoryStack
    call site + explanatory comments take ~30 lines. The
    cognitive drop is bigger — the commit / undo / redo
    triplet is now testable in isolation.

Backlog after v0.6.22

  • v0.6.23+ — More ComposeBoard.tsx extractions: drag/drop,
    server persistence, keyboard shortcuts, view state. The
    pattern established here (custom hook that owns a slice of
    state and exposes a small public surface) should make the
    next 4-5 extractions mechanical, but each is its own release.
  • block-center avoidance for orthogonal routes (real A* grid
    router) — still the v0.6.20 followup, never started
  • per-direction palette — still the v0.6.19 followup, never started