Skip to content

feat: v8 branch#1374

Closed
mathuo wants to merge 20 commits into
masterfrom
v8-branch
Closed

feat: v8 branch#1374
mathuo wants to merge 20 commits into
masterfrom
v8-branch

Conversation

@mathuo

@mathuo mathuo commented Jun 23, 2026

Copy link
Copy Markdown
Owner

Description

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

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 and others added 20 commits June 22, 2026 22:30
The close affordance was a bare <div> wrapping a decorative SVG, so it had
no role and no accessible name — assistive technology announced nothing and
the glyph leaked into the accessibility tree. Add role="button" and an
aria-label qualified with the panel title ("Close <title>"), and mark the
SVG aria-hidden. Keyboard close stays on the tab strip's Delete binding.

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

The free WAI-ARIA tab keyboard handler supports Delete/Backspace to close the
focused tab (retaining roving focus in the strip) and swaps to Up/Down arrows
for vertical strips, but neither path was covered. Add tests for both; the
behaviours already pass, so these lock them against regression.

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

Keyboard docking could only dock a panel into another group; there was no
keyboard equivalent of dragging a panel out into a floating group. Add
Ctrl+Shift+F (rebindable via the keymap) as a terminal action from the
target phase: it floats the moving panel, announces the result, and restores
focus. Adds host.floatPanel + a moveFloated message to the catalog.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(dockview-core): accessible name for the default tab close button
test(dockview-modules): cover Delete-close and vertical-strip keyboard nav
feat(dockview): keyboard 'float' terminal action for keyboard docking
…x on activation

Two more free-baseline a11y gaps from the audit: the group region must drop
its aria-label (not blank it) when the active panel loses its title, and the
roving tabindex must follow panel activation — not only arrow-key navigation —
so keyboard entry lands on the active tab. Both behaviours already pass; these
lock them against regression.

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

Keyboard move mode reuses the same .dv-drop-target overlay a mouse drag shows.
Nothing asserted it actually renders on entry and is torn down on cancel and
on commit. Add those checks so the keyboard↔overlay wiring (and its cleanup)
can't silently regress.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test(dockview-modules): region label removal + roving-tabindex on activation
test(dockview-modules): keyboard docking shows/clears the drop preview
jsdom cannot model a second document (the unit-test window mock reuses the
main one), so popout / cross-window focus, per-window listeners and per-window
live regions are unverifiable in the unit suite. Add a Playwright harness that
drives the built UMD bundles in headless Chromium over a zero-dependency static
server, plus a smoke test proving a popped-out group renders in a real second
window. This is the foundation the cross-window focus work will build on.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test(e2e): Playwright cross-window harness for popout behaviour
A popout is a separate document, so the single main-window live region never
reached a screen-reader user working in a popout. LiveRegionService now mounts
a polite+assertive region in each popout document (synced via a new
onDidChangePopouts seam + getPopoutWindows) and routes announce() to the region
of the window that currently has focus, falling back to main.

A popout that shares the main document (the jsdom test mock) is skipped, so the
unit suite is unaffected; real cross-document behaviour is covered by new
Playwright e2e tests.

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

A popout window is a separate `document`, so the keyboard services' single
main-document listeners never saw keystrokes made inside a popout, and their
`rootElement.contains` gating rejected popout-document targets. Keyboard
navigation, docking and Esc/Tab semantics therefore stopped at the window edge.

- New core seam `IAccessibilityHost.ownsElement(node)` + `getPopoutWindows()` /
  `onDidChangePopouts` (the latter two already existed for the live region).
  `ownsElement` is the cross-document containment primitive: main-shell
  containment, or whole-document membership of a popout this component controls.
- `bindDocumentListeners` (keyboardShared) mirrors a service's document
  listeners onto every popout document, synced as popouts open/close, skipping a
  same-document mock.
- AccessibilityService + KeyboardDockingService use it, and replace every
  `rootElement.contains` gate with `ownsElement`. Focus-inside detection now
  reads the *focused* window's activeElement so close-focus-restore works when
  focus is in a popout.

Test:
- core unit `ownsElement.spec` (5) — containment, foreign-doc rejection,
  popout-doc ownership via stubbed getPopoutWindows, same-doc no-overclaim.
- e2e `keyboard-docking.spec` (2) — Ctrl+M armed inside a popout narrates to the
  popout region and Esc cancels there; a keyboard split committed in the popout
  acts on the popout's own gridview. All 5 e2e + 107 modules + 1080 core green.

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

Two popout-window correctness niches surfaced while completing cross-window a11y.

1. Sash + scrollbar pointer drags were dead inside a popout. `splitview` and
   `scrollbar` attached their `pointermove`/`pointerup`/`pointercancel` (and the
   sash's `contextmenu`) listeners to the module-global `document` — the opener,
   not the popout — so a drag begun in a popped-out window was never heard.
   Bind the drag to the dragged element's own `ownerDocument` instead (also
   shields iframes in that document). Affects mouse users too, not just a11y.

2. Maximizing a *different* group than the focused one stranded focus on
   `<body>`: that group's DOM is hidden, blurring the focused element, and
   nothing pulled focus back. AccessibilityService already snapshots/restores
   focus across a `remove`; extend the same was-inside / not-inside guard to the
   `maximize` mutation. The guard means maximizing the focused group in place is
   still a no-op, so mouse users are never robbed of focus.

Test:
- module unit: maximize-into-another-group restores focus into the maximized
  group (jsdom can't blur a hidden element, so the hidden-element blur is
  emulated in the will phase; `setActive` doesn't move focus, so the
  focusContent spy isolates the restore). 108 modules green.
- e2e `popout-pointer-drag.spec`: a sash dragged inside a popout resizes its
  split — only passes because the listeners now live on the popout document.
- 1074 core green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat(dockview-core): cross-window accessibility for popout windows
The tab and paneview focus rings were keyed on `:focus` / `:focus-within`, so
they also showed on mouse click — visual noise that reads as a defect. Switch
the indicator rules to `:focus-visible` (keyboard-only), keeping the descendant
case via `:has(:focus-visible)` (e.g. a keyboard-focused close button still
rings its tab). The inline tab-rename input keeps `:focus` (inputs should always
ring) and the group content container keeps its `outline: none`.

WCAG 2.4.7 / 1.4.11. Closes #1372.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
fix(dockview-core): use :focus-visible for keyboard focus indicators
…er-drag-and-maximize-focus

# Conflicts:
#	e2e/fixtures/index.html
#	packages/dockview-modules/src/accessibilityService.ts
…mize-focus

fix(dockview-core): popout-window pointer drags + cross-group maximize focus
@sonarqubecloud

Copy link
Copy Markdown

@mathuo mathuo closed this Jun 23, 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