From 2fe6ea2407668ad1f2776bc153b0b24343c25b3a Mon Sep 17 00:00:00 2001 From: jolavillette Date: Thu, 10 Sep 2026 21:54:17 +0200 Subject: [PATCH] webui: rotating with a sheet open must not inert-lock the page The mobile sheets are native modal dialogs now, and above 700px their CSS hides them -- but showModal() keeps the rest of the page inert regardless of the dialog's display: rotating a phone to landscape with a sheet open left the whole UI untappable, with no visible dialog and no Escape on touch, until rotating back. Crossing into the desktop layout now closes the sheet. Co-Authored-By: Claude Fable 5 --- webui-src/app/dialog.js | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/webui-src/app/dialog.js b/webui-src/app/dialog.js index 6ce2ccd..756bc68 100644 --- a/webui-src/app/dialog.js +++ b/webui-src/app/dialog.js @@ -4,16 +4,38 @@ const m = require('mithril'); // and provide dialog semantics; callers own the open state and sheet content. const Dialog = () => { let opener; + let onclose = () => { }; + let desktopQuery; + let onLayoutChange; return { oncreate: ({ dom }) => { opener = document.activeElement; dom.showModal(); + // The sheets are phone chrome: above 700px their CSS hides the dialog, + // but showModal() keeps the whole page inert regardless -- rotating to + // landscape with a sheet open left the UI untappable with no visible + // way out. Crossing into the desktop layout closes the sheet instead. + desktopQuery = window.matchMedia('(min-width: 701px)'); + onLayoutChange = (event) => { + if (event.matches) { + onclose(); + m.redraw(); + } + }; + if (desktopQuery.addEventListener) desktopQuery.addEventListener('change', onLayoutChange); + else desktopQuery.addListener(onLayoutChange); }, onremove: ({ dom }) => { + if (desktopQuery && onLayoutChange) { + if (desktopQuery.removeEventListener) desktopQuery.removeEventListener('change', onLayoutChange); + else desktopQuery.removeListener(onLayoutChange); + } dom.close(); if (opener && opener.isConnected) opener.focus(); }, - view: ({ attrs, children }) => m('dialog.accessible-dialog', { + view: ({ attrs, children }) => { + onclose = attrs.onclose; + return m('dialog.accessible-dialog', { class: attrs.overlayClass, 'aria-label': attrs.label, 'aria-modal': 'true', @@ -44,7 +66,8 @@ const Dialog = () => { first.focus(); } }, - }, m('div', { class: attrs.sheetClass }, children)), + }, m('div', { class: attrs.sheetClass }, children)); + }, }; };