diff --git a/.changeset/adapt-the-player-pane-to-the-window.md b/.changeset/adapt-the-player-pane-to-the-window.md new file mode 100644 index 00000000..7143f433 --- /dev/null +++ b/.changeset/adapt-the-player-pane-to-the-window.md @@ -0,0 +1,11 @@ +--- +"@wdio/devtools-app": patch +--- + +Adapt the player pane to the window it is actually in. The pane's height came from a pixel number resolved once, at construction, from whatever window happened to be open then, and nothing recomputed it: measured at 124px in a 1280x720 window and still 124px at 2560x1440, so a trace rendered into a 13px-wide box on a 2560px screen. Not mobile-specific — wrong for every trace, just least visible on a desktop one. + +Three separate things froze it, and all three had to go. `MIN_WORKBENCH_HEIGHT` was `Math.min(300, window.innerHeight * 0.3)` evaluated at module import, so it took the window open at page load and — being the pane's own `minPosition` — pinned the pane there for the life of the page; loaded in a 413px-tall window it is exactly the 124px measured. `DragController.initialPosition` took a number rather than the getter its bounds already accepted, so a window-derived default could never follow the window. And each controller registered its resize handling by assigning `window.onresize`, which is a single slot: with five controllers on the page only the last one constructed ever adjusted, and it clobbered anything else on that slot. + +A height the user dragged still wins. It is stored, and a resize only re-clamps it — so it survives a window that still has room for it and is pulled back inside one that no longer does, rather than leaving the drag handle off-screen. + +The player component also re-fitted only on `resize` and `window-drag`, which meant it depended on whoever changed the layout remembering to announce it — and the dock divider, the sidebar collapsing and browser zoom announce nothing. It now watches its own box with a `ResizeObserver`, which covers all of them. diff --git a/packages/app/src/components/browser/snapshot-styles.ts b/packages/app/src/components/browser/snapshot-styles.ts index 9e74e324..c4069abc 100644 --- a/packages/app/src/components/browser/snapshot-styles.ts +++ b/packages/app/src/components/browser/snapshot-styles.ts @@ -16,6 +16,15 @@ export const snapshotStyles = css` background: ${unsafeCSS(BROWSER_BACKDROP_GRADIENT)}; } + /* A device frame owns its column, which already provides the backdrop and the + gap, so the host's own 1.25rem is 40px of height and width spent on + nothing. It is spent OUTSIDE the box deviceFrameSize measures, so the frame + came out 40px short on each axis — and because a portrait frame's width + follows its height, the lost height cost width a second time. */ + :host([device-frame]) { + padding: 0.25rem !important; + } + section { box-sizing: border-box; width: calc(100% - 0px); /* host padding already applied */ diff --git a/packages/app/src/components/browser/snapshot.ts b/packages/app/src/components/browser/snapshot.ts index 93d5a399..0efd9d99 100644 --- a/packages/app/src/components/browser/snapshot.ts +++ b/packages/app/src/components/browser/snapshot.ts @@ -135,15 +135,21 @@ export class DevtoolsBrowser extends Element { @query('section') section?: HTMLElement + /** + * Watches the player's OWN box rather than the window. Re-fitting used to + * hang off `resize` and `window-drag`, so it depended on whoever changed the + * layout announcing it — and the dock divider, the sidebar collapsing and + * browser zoom announce nothing. Every one of those moves this box. + */ + #boxObserver?: ResizeObserver + /** The window events the player handles while connected, as one table so its * registration and its teardown cannot drift. Every handler is a per-instance * arrow field, so the reference removeEventListener gets is the one that was * added — a bound method would produce a new function per call and never - * detach. */ + * detach. Sizing is not among them: that is the ResizeObserver's job. */ #windowListeners(): ReadonlyArray { return [ - ['resize', this.#handleResize], - ['window-drag', this.#handleResize], ['app-mutation-highlight', this.#highlightMutation], ['app-mutation-select', this.#handleMutationSelect], ['a11y-highlight', this.#highlightBySelector], @@ -157,6 +163,11 @@ export class DevtoolsBrowser extends Element { for (const [type, handler] of this.#windowListeners()) { window.addEventListener(type, handler) } + // Safe against the observer loop: this watches the host, and the sizing it + // triggers writes to a descendant. The host is laid out by its parent + // (width/height 100%), so nothing it writes can feed back into this box. + this.#boxObserver = new ResizeObserver(() => this.#handleResize()) + this.#boxObserver.observe(this) await this.updateComplete } @@ -169,6 +180,8 @@ export class DevtoolsBrowser extends Element { for (const [type, handler] of this.#windowListeners()) { window.removeEventListener(type, handler) } + this.#boxObserver?.disconnect() + this.#boxObserver = undefined } #captureShape?: { screenshot: string; size: ImageSize | null } @@ -470,6 +483,10 @@ export class DevtoolsBrowser extends Element { // View-mode flips swap the iframe with /