diff --git a/apps/pwabuilder/Frontend/public/global.css b/apps/pwabuilder/Frontend/public/global.css index b67a7edf2..11a413111 100644 --- a/apps/pwabuilder/Frontend/public/global.css +++ b/apps/pwabuilder/Frontend/public/global.css @@ -138,6 +138,17 @@ body { overflow-x: hidden; /* Prevent horizontal scrolling at high zoom */ } +/* + * WebAwesome locks page scrolling by adding the `wa-scroll-lock` class to + * while a dialog is open, but its bundled rule only targets + * (`.wa-scroll-lock body { overflow: hidden }`). PWABuilder scrolls on , + * so that rule is a no-op here. Mirror it on so WA's built-in scroll + * lock works for every dialog without any per-dialog JavaScript. + */ +html.wa-scroll-lock { + overflow: hidden !important; +} + /* Ensure all text wraps properly */ * { word-wrap: break-word; diff --git a/apps/pwabuilder/Frontend/src/script/components/manifest-editor-frame.ts b/apps/pwabuilder/Frontend/src/script/components/manifest-editor-frame.ts index 484fbb9d8..34a03e599 100644 --- a/apps/pwabuilder/Frontend/src/script/components/manifest-editor-frame.ts +++ b/apps/pwabuilder/Frontend/src/script/components/manifest-editor-frame.ts @@ -66,12 +66,10 @@ export class ManifestEditorFrame extends LitElement { if (e.target === dialog) { dialog!.open = false; recordPWABuilderProcessStep("manifest_editor_closed", AnalyticsBehavior.ProcessCheckpoint); - document.body.style.height = "unset"; } } async openDialog() { - document.body.style.height = "100vh" const dialog = this.shadowRoot!.querySelector(".dialog"); dialog?.removeEventListener('wa-request-close', () => { }); @@ -120,7 +118,7 @@ export class ManifestEditorFrame extends LitElement { render() { return html` - this.openDialog()} @wa-hide=${(e: any) => this.hideDialog(e)}> + this.openDialog()} @wa-hide=${(e: any) => this.hideDialog(e)}>
diff --git a/apps/pwabuilder/Frontend/src/script/components/publish-pane.styles.ts b/apps/pwabuilder/Frontend/src/script/components/publish-pane.styles.ts index 4747c9c0e..ff2a83e9d 100644 --- a/apps/pwabuilder/Frontend/src/script/components/publish-pane.styles.ts +++ b/apps/pwabuilder/Frontend/src/script/components/publish-pane.styles.ts @@ -322,10 +322,6 @@ export const publishPaneStyles = css` flex-direction: column; } - .noX::part(close-button) { - display: none; - } - .dialog::part(body){ padding: 0; width: 100%; diff --git a/apps/pwabuilder/Frontend/src/script/components/publish-pane.ts b/apps/pwabuilder/Frontend/src/script/components/publish-pane.ts index 9ef4864bc..99802ae92 100644 --- a/apps/pwabuilder/Frontend/src/script/components/publish-pane.ts +++ b/apps/pwabuilder/Frontend/src/script/components/publish-pane.ts @@ -16,7 +16,6 @@ import './android-form'; import './ios-form'; import { AppPackageFormBase } from './app-package-form-base'; import { PackageOptions } from '../utils/interfaces'; -import { classMap } from 'lit/directives/class-map.js'; import { getDataFromDB, setDataInDB } from '../utils/indexedDB'; import { GooglePlayPackageError } from "../models/google-play-package-error"; import { enqueueGooglePlayPackageJob } from "../services/publish/android-publish"; @@ -51,8 +50,6 @@ export class PublishPane extends LitElement { @state() downloadFileName: string | null = null; @state() feedbackMessages: TemplateResult[] = []; - @property({ type: Boolean }) preventClosing = false; - @state() storeMap: any = { "Windows": { @@ -469,17 +466,10 @@ export class PublishPane extends LitElement { this.feedbackMessages = []; dialog!.open = false; recordPWABuilderProcessStep("publish_pane_closed", AnalyticsBehavior.ProcessCheckpoint); - document.body.style.height = "unset"; this.cardsOrForm = true; } } - handleRequestClose(e: Event) { - if (this.preventClosing) { - e.preventDefault(); - } - } - // goes from form back to cards when you click the back arrow backToCards() { this.cardsOrForm = !this.cardsOrForm; @@ -663,9 +653,9 @@ export class PublishPane extends LitElement { return html` this.hideDialog(e)} - @wa-request-close=${(e: any) => this.handleRequestClose(e)} >
diff --git a/apps/pwabuilder/Frontend/src/script/components/share-card.ts b/apps/pwabuilder/Frontend/src/script/components/share-card.ts index 3ee05975d..8298a3ca3 100644 --- a/apps/pwabuilder/Frontend/src/script/components/share-card.ts +++ b/apps/pwabuilder/Frontend/src/script/components/share-card.ts @@ -9,7 +9,6 @@ import '@awesome.me/webawesome/dist/components/dialog/dialog.js'; @customElement('share-card') export class ShareCard extends LitElement { - @property() preventClosing = false; @property() manifestData = ""; @property() swData = ""; @property() enhancementsData = ""; @@ -106,15 +105,9 @@ export class ShareCard extends LitElement { dialog!.open = false; } - handleRequestClose(e: Event){ - if (this.preventClosing) { - e.preventDefault(); - } - } - render() { return html` - this.setup()} @wa-hide=${() => this.hideDialog()}> + this.setup()} @wa-hide=${() => this.hideDialog()}>
diff --git a/apps/pwabuilder/Frontend/src/script/components/sw-selector.ts b/apps/pwabuilder/Frontend/src/script/components/sw-selector.ts index acd13e702..a9f996e25 100644 --- a/apps/pwabuilder/Frontend/src/script/components/sw-selector.ts +++ b/apps/pwabuilder/Frontend/src/script/components/sw-selector.ts @@ -28,7 +28,6 @@ export class SWSelector extends LitElement { if(e.target === dialog){ dialog!.open = false; recordPWABuilderProcessStep("sw_selector_closed", AnalyticsBehavior.ProcessCheckpoint); - document.body.style.height = "unset"; } } @@ -63,7 +62,7 @@ export class SWSelector extends LitElement { render() { return html` - document.body.style.height = "100vh"} @wa-hide=${(e: any) => this.hideDialog(e)}> + this.hideDialog(e)}>

Download a Service Worker

Download one of our pre-built Service Workers package that utilize Workbox to make building your offline experience easy.

diff --git a/apps/pwabuilder/Frontend/src/script/components/test-publish-pane.ts b/apps/pwabuilder/Frontend/src/script/components/test-publish-pane.ts index 390d96960..5f138daf1 100644 --- a/apps/pwabuilder/Frontend/src/script/components/test-publish-pane.ts +++ b/apps/pwabuilder/Frontend/src/script/components/test-publish-pane.ts @@ -235,13 +235,12 @@ export class TestPublishPane extends LitElement { this.generating = false; dialog!.open = false; recordPWABuilderProcessStep("test_publish_pane_closed", AnalyticsBehavior.ProcessCheckpoint); - document.body.style.height = "unset"; } } render() { return html` - document.body.style.height = "100vh"} @wa-hide=${(e: any) => this.hideDialog(e)}> + this.hideDialog(e)}>
diff --git a/apps/pwabuilder/Frontend/src/script/pages/app-report.ts b/apps/pwabuilder/Frontend/src/script/pages/app-report.ts index e48be4b84..79f40218e 100644 --- a/apps/pwabuilder/Frontend/src/script/pages/app-report.ts +++ b/apps/pwabuilder/Frontend/src/script/pages/app-report.ts @@ -1132,7 +1132,7 @@ export class AppReport extends LitElement {
- { this.showRetestConfirmationModal = false; this.readDenied = false; }} without-header> + { this.showRetestConfirmationModal = false; this.readDenied = false; }} without-header> ${this.renderReadDialog()} @@ -1396,7 +1396,7 @@ export class AppReport extends LitElement { } return html` - +

Logs @@ -1422,7 +1422,7 @@ export class AppReport extends LitElement { const errorInfo = `${this.analysis.url} failed due to an internal error.\r\n\r\n> ${this.analysis.error}\r\n\r\nId: ${this.analysis.id}\r\n\r\nLogs:\r\n> ${this.analysis.logs.join("\r\n")}`; const bugLink = `https://github.com/pwa-builder/pwabuilder/issues/new?title=Analysis%20Failed&labels=bug%20:bug:&body=${encodeURIComponent(errorInfo.substring(0, 4000))}`; return html` - +

😵 Oh no, PWABuilder was unable to analyze your web app due to an error.

diff --git a/apps/pwabuilder/Frontend/src/script/pages/powerplatform-publish.ts b/apps/pwabuilder/Frontend/src/script/pages/powerplatform-publish.ts index f0cb06734..194a96305 100644 --- a/apps/pwabuilder/Frontend/src/script/pages/powerplatform-publish.ts +++ b/apps/pwabuilder/Frontend/src/script/pages/powerplatform-publish.ts @@ -53,7 +53,7 @@ export class AppReport extends LitElement {

- + `; } } diff --git a/apps/pwabuilder/Frontend/src/script/utils/dom-utils.ts b/apps/pwabuilder/Frontend/src/script/utils/dom-utils.ts deleted file mode 100644 index 189ab7b42..000000000 --- a/apps/pwabuilder/Frontend/src/script/utils/dom-utils.ts +++ /dev/null @@ -1,7 +0,0 @@ -export function turnOffScroll() { - document.documentElement.style.overflowY = 'hidden'; -} - -export function turnOnScroll() { - document.documentElement.style.overflowY = 'initial'; -} diff --git a/apps/pwabuilder/Frontend/tests/packaging.spec.ts b/apps/pwabuilder/Frontend/tests/packaging.spec.ts index 21621dda7..7a279828d 100644 --- a/apps/pwabuilder/Frontend/tests/packaging.spec.ts +++ b/apps/pwabuilder/Frontend/tests/packaging.spec.ts @@ -138,6 +138,65 @@ test('Ensure Windows Download Package button has visible focus indicator', async expect(outlineWidth).toBe('2px'); }); +test('Package for Stores dialog locks scrolling and closes on backdrop click', async ({ page }) => { + const demoButton = page.locator('id=demo-action'); + + await demoButton.click(); + await page.waitForLoadState('networkidle'); + await expect(page.url()).toContain('/reportcard'); + await page.waitForLoadState('networkidle'); + + await page.evaluate(() => window.scrollTo(0, 500)); + const initialScrollPosition = await page.evaluate(() => window.scrollY); + + await page.evaluate(() => { + const appReport = document.querySelector('app-index')?.shadowRoot?.querySelector('app-report') as { + openPublishModal?: () => void; + } | null; + + appReport?.openPublishModal?.(); + }); + + await expect.poll(async () => { + return page.evaluate(() => { + const appReport = document.querySelector('app-index')?.shadowRoot?.querySelector('app-report'); + const dialog = appReport?.shadowRoot + ?.querySelector('publish-pane') + ?.shadowRoot + ?.querySelector('.dialog') as { open?: boolean } | null; + + return dialog?.open ?? false; + }); + }).toBe(true); + + await expect.poll(async () => { + return page.evaluate(() => document.documentElement.classList.contains('wa-scroll-lock')); + }).toBe(true); + + await page.mouse.wheel(0, 500); + await expect.poll(async () => { + const currentScrollY = await page.evaluate(() => window.scrollY); + return Math.abs(currentScrollY - initialScrollPosition); + }).toBeLessThan(2); + await page.mouse.click(20, 20); + + await expect.poll(async () => { + return page.evaluate(() => { + const appReport = document.querySelector('app-index')?.shadowRoot?.querySelector('app-report'); + const dialog = appReport?.shadowRoot + ?.querySelector('publish-pane') + ?.shadowRoot + ?.querySelector('.dialog') as { open?: boolean } | null; + + return dialog?.open ?? false; + }); + }).toBe(false); + + await expect.poll(async () => { + return page.evaluate(() => document.documentElement.classList.contains('wa-scroll-lock')); + }).toBe(false); +}); + test('Ensure Windows package dialog back button focus does not span the close button', async ({ page }) => { const headerMetrics = await page.evaluate(async () => { sessionStorage.setItem('current_url', 'https://example.com'); @@ -331,7 +390,6 @@ test('Ensure Windows package dialog initially focuses the Package ID field', asy internalInputFocused: internalInput === packageIdInput?.shadowRoot?.activeElement }; }); - expect(focusState).not.toBeNull(); expect(focusState?.packageIdFocused || focusState?.internalInputFocused).toBe(true); });