A click on a splitter bar is not a drag. Before this fix, a single click on the index rail's divider sometimes left the bar following the pointer until a second click released it. It happened most often right after a reload (Plugins#4621).

The mechanism

Every splitter in the portal is Fluent UI Blazor's FluentMultiSplitter: the index rail beside a markdown page or a course (SplitterView/SplitterPane) and the shell's side panel (PortalLayoutBase). It arms a drag in two hops, and each hop can leave the drag armed after the button is already up:

  1. The mousedown is a Blazor event. On Blazor Server it travels to the circuit, which then calls the module's startSplitterResize back in the browser. That call attaches the document mousemove/mouseup listeners. A quick click's mouseup can come before that round trip ends (a circuit still busy after a reload makes this likely), so the listeners wait for a release that has already happened.
  2. Its mouseUpHandler detaches only when both panes' flex-basis is a percentage. That is true only once a mousemove has rewritten them. The rail pane is declared as 260px, so a click without a move keeps the listeners attached, every time, until a move turns the bases into percentages and the next release finally detaches.

Both are in Fluent's script (4.14.4, unchanged upstream), which this repository does not ship.

The fix

src/MeshWeaver.Blazor/wwwroot/splitterRelease.js is installed by the MeshWeaver.Blazor JS initializer. Fluent keeps the armed drag in document.splitterData. The guard:

A drag armed while the button is held is left alone, so dragging is unchanged.

How it is pinned

e2e/splitter-release.spec.ts runs Fluent's own script (a verbatim copy in e2e/fixtures/) and the shipped guard in Chromium, with no portal. The test plays the circuit hop itself, so both orders are deterministic. Two cases run without the guard and assert the defect: if Fluent fixes it upstream they turn red, and the guard can be retired. CI runs the spec in the e2e suite compiles and enumerates job, which a change to the guard or the initializer also triggers.

Index groups keep the reader's toggles covers a different symptom on the same divider, Plugins#4420: a click re-rendered the index and reset its open groups.