Skip to content

fix(docking): commit tab click-selection; reshape dock-showcase into ReactorIde sample#438

Merged
codemonkeychris merged 2 commits into
mainfrom
fix/docking-tab-click-and-reactor-ide-sample
May 28, 2026
Merged

fix(docking): commit tab click-selection; reshape dock-showcase into ReactorIde sample#438
codemonkeychris merged 2 commits into
mainfrom
fix/docking-tab-click-and-reactor-ide-sample

Conversation

@codemonkeychris
Copy link
Copy Markdown
Collaborator

Summary

While reshaping the docking sample into a cohesive IDE app, I hit a real framework bug and two usage traps. This PR fixes the framework bug, rebuilds the sample, and captures the traps in an agent-kit skill.

Framework fix — tab click-selection in multi-tab groups

DockTabTearOff captures the pointer on PointerPressed to track a possible VS-style tear-off drag. For a plain click, the TabViewItem then never receives the release, so WinUI never commits the tab selection — clicking a tab did nothing in any group with more than one tab. OnReleased only cleared the candidate.

Fix: in OnReleased, when a candidate survives (the press never crossed the tear-off threshold = it was a click), commit the selection. The threshold path already clears the candidate before tearing off, so this never double-fires. Latent until now because every existing docking demo used a single tab per group.

Sample — dock-showcasereactor-ide

Replaced the 10-scene (A–J) spec-review harness + JSON/op-log/replay debug panels with one VS-shaped app: Solution Explorer, an editor well (DocumentArea), Properties/Git, Output/Terminal/Errors, a menu bar, and a status bar. Files open from the explorer/menu; the layout drags/floats/redocks/persists.

Built on the idiomatic ownership model (app owns content, host owns shape): open/close changes manager.Layout's key set; reset is a .WithKey() remount — no OnLiveLayoutChanged round-trip (that anti-pattern double-owns the shape and breaks float/redock + selection).

Project + folder renamed DockShowcase/dock-showcaseReactorIde/reactor-ide; Reactor.slnx updated.

Skill — reactor-docking

New agent-kit skill documenting the content-vs-shape ownership model (the #1 docking footgun) plus the two pane-content traps below.

Gotchas captured (the "make this un-makeable?" question)

  1. Ownership round-tripOnLiveLayoutChanged = x => setLayout(x) double-owns shape → no redock, broken selection.
  2. Pane bodies are content-sized — fill with FlexColumn(child.Flex(grow:1)), not alignment.
  3. Multi-line TextBoxAcceptsReturn/TextWrapping must be element props (.AcceptsReturn()), not a .Set(...) lambda; the descriptor orders them before Text, and .Set runs after Text → truncates to one line.

Follow-up options for #1 (not in this PR — want your call)

  • Analyzer (REACTOR_DOCK_001): flag OnLiveLayoutChanged = p => <call>(p) (param forwarded straight into a setter). Feasible — mirrors the existing MissingWithKeyAnalyzer heuristic.
  • API-level prevention (stronger): change OnLiveLayoutChanged to hand back a read-only snapshot type distinct from DockNode, so it physically can't be assigned to Layout — turning the footgun into a compile error. Breaking change; observers that want JSON can use a ToJson() on the snapshot (and PersistenceId already covers persistence).

Tests

  • ✅ Unit (Reactor.Tests): 9130 passed, 0 failed, 62 skipped
  • ✅ Selftest (Reactor.SelfTests): 1034 passed, 0 failed
  • ReactorIde builds + runs (x64 + ARM64); verified visually (tabs switch, editor fills + multi-line, float/redock).

Note: on ARM64 the suites need -p:Platform=ARM64 — without it Reactor.Tests' reference to the minesweeper sample trips a WindowsAppSDKSelfContained architecture check (pre-existing, unrelated).

🤖 Generated with Claude Code

…ReactorIde sample

DockTabTearOff captured the pointer on PointerPressed to track a possible
tear-off drag. For a plain click the TabViewItem then never received the
release, so WinUI never committed the tab selection — clicking a tab did
nothing in multi-tab groups. Commit the selection in OnReleased when the
press never crossed the tear-off threshold (a surviving candidate). The
threshold path already clears the candidate before tearing off, so this
never double-fires. Latent until now because every existing docking demo
used a single tab per group.

Also rebuild the docking showcase as one cohesive IDE app:
- rename samples/apps/dock-showcase -> reactor-ide (DockShowcase -> ReactorIde)
- replace the 10-scene spec-review harness + JSON/op-log debug panels with a
  single VS-shaped app: Solution Explorer, editor well (DocumentArea),
  Properties/Git, Output/Terminal/Errors, menu bar, status bar
- follow the idiomatic ownership model (app owns content, host owns shape):
  open/close drives manager.Layout key-set changes, reset via .WithKey() --
  no OnLiveLayoutChanged round-trip (which breaks float/redock + selection)
- editor panes fill via FlexColumn grow; multi-line TextBox uses
  .AcceptsReturn()/.TextWrapping() element props so the descriptor orders
  them before Text (a .Set lambda runs after Text and truncates to one line)

Add the reactor-docking agent-kit skill documenting the ownership model and
these gotchas.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Comment thread samples/apps/reactor-ide/App.cs Fixed
CodeQL flagged `indent * 14` as int-multiplication-cast-to-double. The
indent is only ever 1–2 so overflow is impossible, but make one operand a
double literal to clear the static-analysis finding.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codemonkeychris codemonkeychris merged commit 59857ae into main May 28, 2026
15 checks passed
@codemonkeychris codemonkeychris deleted the fix/docking-tab-click-and-reactor-ide-sample branch May 28, 2026 21:12
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.

2 participants