From 772d88a863f6eb2a6085ff5f491065993fa8b025 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 27 May 2026 13:55:42 +0000 Subject: [PATCH 1/3] Initial plan From 25c4bbfe9f9fcde42a608a070ffb72336a02eff5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 27 May 2026 14:01:35 +0000 Subject: [PATCH 2/3] Use transform scaleX for progress bar animation --- CHANGELOG.md | 2 ++ src/core/drive/progress_bar.ts | 12 ++++++++---- src/tests/functional/form_submission_tests.ts | 5 +++++ src/tests/functional/navigation_tests.ts | 5 +++++ 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85e46a882..6db145bbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ # Changelog Please see [our GitHub "Releases" page](https://github.com/hotwired/turbo/releases). + +Unreleased note: `.turbo-progress-bar` now renders at full width and uses `transform: scaleX(...)` for progress animation. Custom overrides that animate or read `width` should migrate to `transform`. diff --git a/src/core/drive/progress_bar.ts b/src/core/drive/progress_bar.ts index 9a189be92..43da9d1bd 100644 --- a/src/core/drive/progress_bar.ts +++ b/src/core/drive/progress_bar.ts @@ -10,13 +10,16 @@ export class ProgressBar { display: block; top: 0; left: 0; + width: 100%; height: 3px; background: #0076ff; z-index: 2147483647; + transform-origin: 0 0; + transform: scaleX(0) translateZ(0); transition: - width ${ProgressBar.animationDuration}ms ease-out, + transform ${ProgressBar.animationDuration}ms ease-out, opacity ${ProgressBar.animationDuration / 2}ms ${ProgressBar.animationDuration / 2}ms ease-in; - transform: translate3d(0, 0, 0); + will-change: transform, opacity; } ` } @@ -68,7 +71,7 @@ export class ProgressBar { } installProgressElement() { - this.progressElement.style.width = "0" + this.progressElement.style.transform = "scaleX(0) translateZ(0)" this.progressElement.style.opacity = "1" document.documentElement.insertBefore(this.progressElement, document.body) this.refresh() @@ -102,7 +105,8 @@ export class ProgressBar { refresh() { requestAnimationFrame(() => { - this.progressElement.style.width = `${10 + this.value * 90}%` + const scale = (10 + this.value * 90) / 100 + this.progressElement.style.transform = `scaleX(${scale}) translateZ(0)` }) } diff --git a/src/tests/functional/form_submission_tests.ts b/src/tests/functional/form_submission_tests.ts index 3c0004fcf..f40991239 100644 --- a/src/tests/functional/form_submission_tests.ts +++ b/src/tests/functional/form_submission_tests.ts @@ -38,6 +38,11 @@ test("test standard form submission renders a progress bar", async ({ page }) => await waitUntilSelector(page, ".turbo-progress-bar") assert.ok(await hasSelector(page, ".turbo-progress-bar"), "displays progress bar") + assert.match( + await page.locator(".turbo-progress-bar").evaluate((element) => (element as HTMLDivElement).style.transform), + /^scaleX\(.+\) translateZ\(0(px)?\)$/, + "animates progress with transform" + ) await nextBody(page) await waitUntilNoSelector(page, ".turbo-progress-bar") diff --git a/src/tests/functional/navigation_tests.ts b/src/tests/functional/navigation_tests.ts index facddb38a..92c3f41bf 100644 --- a/src/tests/functional/navigation_tests.ts +++ b/src/tests/functional/navigation_tests.ts @@ -38,6 +38,11 @@ test("test navigating renders a progress bar", async ({ page }) => { await waitUntilSelector(page, ".turbo-progress-bar") assert.ok(await hasSelector(page, ".turbo-progress-bar"), "displays progress bar") + assert.match( + await page.locator(".turbo-progress-bar").evaluate((element) => (element as HTMLDivElement).style.transform), + /^scaleX\(.+\) translateZ\(0(px)?\)$/, + "animates progress with transform" + ) await nextEventNamed(page, "turbo:load") await waitUntilNoSelector(page, ".turbo-progress-bar") From 6db543d4d2218611d964e2e4ec38849df6688fb1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 27 May 2026 14:03:06 +0000 Subject: [PATCH 3/3] Format changelog note under Unreleased section --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6db145bbe..04bc3e44c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,4 +2,6 @@ Please see [our GitHub "Releases" page](https://github.com/hotwired/turbo/releases). -Unreleased note: `.turbo-progress-bar` now renders at full width and uses `transform: scaleX(...)` for progress animation. Custom overrides that animate or read `width` should migrate to `transform`. +## Unreleased + +- `.turbo-progress-bar` now renders at full width and uses `transform: scaleX(...)` for progress animation. Custom overrides that animate or read `width` should migrate to `transform`.