Skip to content

feat(dockview-core): floating & popout windows as nested (multi-group) layouts#1310

Open
mathuo wants to merge 7 commits into
masterfrom
feat/floating-nested-layout
Open

feat(dockview-core): floating & popout windows as nested (multi-group) layouts#1310
mathuo wants to merge 7 commits into
masterfrom
feat/floating-nested-layout

Conversation

@mathuo
Copy link
Copy Markdown
Owner

@mathuo mathuo commented May 29, 2026

Description

Stacked on #1312 (dedicated floating-group drag handle). Review/merge that first; this PR's base will retarget to master automatically once it lands. The diff here is nested-layout + refactor only.

Makes floating and popout windows full multi-group layouts, and tidies the dockviewComponent.ts methods that grew as a result. All changes are in dockview-core.

1. Floating & popout windows as nested layouts (multi-root)

Floating and popout windows previously hosted a single group. They now host their own Gridview, so:

  • You can drag multiple groups into one floating/popout window and it splits into a nested split-view layout, and drag groups back out again — full cross-boundary drag-and-drop between the main grid, floating windows and popout windows.
  • toJSON()/fromJSON() round-trip multi-group floating and popout windows.
  • Popout restoration is hardened against popup-blockers and re-entrant fromJSON (members are re-docked into the main grid rather than left as orphans).
  • The floating title-bar handle retargets correctly when the anchor group leaves a multi-group window (a remaining member is promoted as the new anchor).

2. dockviewComponent.ts readability refactor

The methods that grew with the nested-layout work were decomposed in-place into well-named private helpers, and the previously-triplicated float/popout "multi-member detach + anchor reassignment" cascade was unified into a single detachFromNestedWindow (plus disposeGroupRecord / activateFallbackGroupIfRemoved). No behaviour change.

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Refactor / cleanup
  • Build / CI / tooling

Affected packages

  • dockview-core
  • dockview (vanilla JS)
  • dockview-react
  • dockview-vue
  • dockview-angular
  • docs

How to test

  • yarn test in dockview-core — 1023 tests pass (suite expanded with multi-group floating/popout coverage in dockviewComponent.spec.ts).
  • Manual: drag groups into and between floating/popout windows; confirm a multi-group floating window splits into a nested layout, move/redock via the title-bar handle, then toJSON() → reload fromJSON() and confirm the multi-root layout (including popouts) restores.

Checklist

  • yarn lint:fix passes
  • yarn format passes
  • npm run gen has been run and generated files are up to date
  • yarn test passes
  • I have added or updated tests where applicable
  • Breaking changes are documented

@mathuo mathuo changed the base branch from master to feat/modules May 29, 2026 21:20
@mathuo mathuo changed the base branch from feat/modules to master May 30, 2026 21:02
mathuo and others added 6 commits June 2, 2026 20:37
Introduce the multi-root foundation: a DockviewComponent can host more than one
gridview root (the main grid plus, now, floating windows), all sharing one
groups map, panel registry, DnD transfer namespace and serialization — so there
is still a single public DockviewApi and existing behaviour is unchanged.

- a floating window mounts its own Gridview as the overlay content; the anchor
  group is added into it, and further groups can be split in
- getGridviewForGroup resolves a group's owning root; doAddGroup /
  createGroupAtLocation take a target gridview; moveGroup(OrPanel) compute
  locations against the destination root, so panels/groups can be dragged
  across the main<->floating boundary (and floating<->floating)
- floating groups accept all drop zones (edge drop splits the window);
  doRemoveGroup is multi-group aware (detach one group, keep the window alive)
- serialize/restore each floating window's nested gridview (legacy single-group
  shape preserved for byte-stable round-trips)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extend the multi-root model to popout windows: a popout hosts its own Gridview
(in the popout document, with its own overlay render + drop-target containers),
so it can hold a nested splitview of groups and participate in cross-boundary
drag-and-drop just like floating windows.

- popout groups accept all drop zones; moveGroup(OrPanel) and doRemoveGroup are
  popout-root aware (split into a popout, drag in/out, multi-group windows)
- getOverrideTarget resolves dynamically so a relocated group's drop overlay
  mounts in the correct window
- serialize/restore the popout's nested gridview (legacy single-group shape
  preserved); restore rebuilds it via an internal override
- size + reposition the popout via a ResizeObserver created in the popout
  window's own realm, so content lays out at the real size once the window has
  painted (a parent-realm observer / fixed animation-frame count raced)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Harden the restore path against real-world popout edge cases surfaced by
loading saved layouts:

- when the browser blocks a popout window (window.open returns null — common
  when restoring on load), dock the group into the grid (or return its panels
  and dispose the empty group) instead of leaving an orphan; blocked content
  falls back into the grid rather than being lost
- dispose 'grid'-location groups whose element isn't actually in the gridview
  (a popout-destined group swept up by a re-entrant fromJSON / clear) instead
  of throwing "Invalid grid element"

Adds regression tests for blocked-popup restoration and rapid repeated fromJSON.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Three fixes from reviewing the nested floating/popout layout work:

1. The dedicated floating title bar (default floatingGroupDragHandle:
   'titlebar') captured its anchor group permanently, so after the
   original anchor was dragged out of a surviving multi-group window the
   bar still redocked/activated the departed group. GroupDragSource.group
   now accepts a provider resolved lazily; FloatingTitleBar holds a
   mutable anchor with setGroup(); DockviewFloatingGroupPanel.setAnchorGroup
   retargets it; onWillDragGroup fires the live anchor.

2. Nested floating/popout gridview gap was not updated on runtime theme
   change; updateTheme now syncs .margin on every nested gridview.

3. Multi-group popout restore while popups are blocked orphaned the
   non-anchor members; the blocked fallback now docks every member into
   the main grid.

Adds regression tests for (1) and (3).

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

The floating-nested-layout work concentrated a lot of logic in a few giant
methods. Extract cohesive units (no behaviour change; full suite green):

- addPopoutGroup (582→~378): handleBlockedPopout, disposePopoutWindow,
  redockGroupToMainGrid
- detach cascade: detachFromNestedWindow unifies the float/popout multi-member
  detach + anchor-reassign previously duplicated in doRemoveGroup and moveGroup;
  add disposeGroupRecord and activateFallbackGroupIfRemoved
- fromJSON (449→~249): deserializeEdgeGroups/FloatingWindows/PopoutWindows and
  shared deserializeNestedGridview
- move popout ResizeObserver mechanics into PopoutWindowService.observeGridviewSize

Grid-manipulating orchestration stays in the component; services keep their
narrow host interface.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mathuo mathuo force-pushed the feat/floating-nested-layout branch from 9a239a5 to d6ce3ab Compare June 2, 2026 19:39
@mathuo mathuo changed the base branch from master to feat/floating-group-drag-handle June 2, 2026 19:39
@mathuo mathuo changed the title Feat/floating nested layout feat(dockview-core): floating & popout windows as nested (multi-group) layouts Jun 2, 2026
@mathuo mathuo changed the base branch from feat/floating-group-drag-handle to master June 2, 2026 19:43
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Jun 2, 2026

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.

1 participant