From 4af365017e45e58de59a021cfe0dc9fc4e35ac11 Mon Sep 17 00:00:00 2001 From: Alexander Brandon Coles Date: Mon, 2 Mar 2026 15:57:14 -0300 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#74615=20[hotwi?= =?UTF-8?q?red=5F=5Fturbo]=20Introduce=20Adapter=20interface=20by=20@myabc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hotwired__turbo/hotwired__turbo-tests.ts | 51 +++++++++++++-- types/hotwired__turbo/index.d.ts | 65 +++++++++++++++++-- 2 files changed, 104 insertions(+), 12 deletions(-) diff --git a/types/hotwired__turbo/hotwired__turbo-tests.ts b/types/hotwired__turbo/hotwired__turbo-tests.ts index c8b709958358ba..4d6759313b4c53 100644 --- a/types/hotwired__turbo/hotwired__turbo-tests.ts +++ b/types/hotwired__turbo/hotwired__turbo-tests.ts @@ -1,16 +1,23 @@ import { + Adapter, + BrowserAdapter, cache, config, connectStreamSource, disconnectStreamSource, navigator, + NavigatorDelegate, + ProgressBar, + registerAdapter, renderStreamMessage, session, start, StreamActions, StreamMessage, StreamSource, + Visit, visit, + VisitOptions, } from "@hotwired/turbo"; const turboFrame = document.querySelector("turbo-frame")!; @@ -145,15 +152,29 @@ document.addEventListener("turbo:submit-end", function(event) { // Test start() function start(); + +const customAdapter: Adapter = { + visitProposedToLocation(_location: URL, _options?: VisitOptions): void {}, + visitStarted(_visit: Visit): void {}, + visitCompleted(_visit: Visit): void {}, + visitFailed(_visit: Visit): void {}, + visitRequestStarted(_visit: Visit): void {}, + visitRequestCompleted(_visit: Visit): void {}, + visitRequestFailedWithStatusCode(_visit: Visit, _statusCode: number): void {}, + visitRequestFinished(_visit: Visit): void {}, + visitRendered(_visit: Visit): void {}, + pageInvalidated(_reason: { reason: string }): void {}, +}; +registerAdapter(customAdapter); +Turbo.registerAdapter(customAdapter); + Turbo.start(); // Test session.adapter -// $ExpectType BrowserAdapter +// $ExpectType Adapter session.adapter; -session.adapter.formSubmissionStarted(); -session.adapter.formSubmissionFinished(); -Turbo.session.adapter.formSubmissionStarted(); -Turbo.session.adapter.formSubmissionFinished(); +// $ExpectType Adapter +Turbo.session.adapter; // Test navigator.submitForm const form = document.querySelector("form")!; @@ -162,6 +183,26 @@ navigator.submitForm(form, document.querySelector("button")!); Turbo.navigator.submitForm(form); Turbo.navigator.submitForm(form, document.querySelector("button")!); +// Test navigator.delegate +// $ExpectType NavigatorDelegate +navigator.delegate; +// $ExpectType Adapter +navigator.delegate.adapter; + +// Test ProgressBar via BrowserAdapter cast +const browserAdapter = navigator.delegate.adapter as BrowserAdapter; +// $ExpectType ProgressBar +browserAdapter.progressBar; +browserAdapter.progressBar.setValue(0); +browserAdapter.progressBar.show(); +browserAdapter.progressBar.hide(); +// $ExpectType number +browserAdapter.progressBar.value; +// $ExpectType boolean +browserAdapter.progressBar.visible; +// $ExpectType boolean +browserAdapter.progressBar.hiding; + // Test cache methods cache.clear(); cache.resetCacheControl(); diff --git a/types/hotwired__turbo/index.d.ts b/types/hotwired__turbo/index.d.ts index 33c0b4c65bab7a..db2e65f42f58bd 100644 --- a/types/hotwired__turbo/index.d.ts +++ b/types/hotwired__turbo/index.d.ts @@ -109,13 +109,62 @@ export class FetchResponse { succeeded: boolean; } +export interface Visit { + readonly action: Action; + readonly location: URL; + hasCachedSnapshot(): boolean; + complete(): void; + cancel(): void; +} + +export interface Adapter { + visitProposedToLocation(location: URL, options?: VisitOptions): void; + visitStarted(visit: Visit): void; + visitCompleted(visit: Visit): void; + visitFailed(visit: Visit): void; + visitRequestStarted(visit: Visit): void; + visitRequestCompleted(visit: Visit): void; + visitRequestFailedWithStatusCode(visit: Visit, statusCode: number): void; + visitRequestFinished(visit: Visit): void; + visitRendered(visit: Visit): void; + pageInvalidated(reason: { reason: string }): void; + formSubmissionStarted?(formSubmission: FormSubmission): void; + formSubmissionFinished?(formSubmission: FormSubmission): void; + linkPrefetchingIsEnabledForLocation?(location: URL): boolean; +} + +export class BrowserAdapter implements Adapter { + progressBar: ProgressBar; + visitProposedToLocation(location: URL, options?: VisitOptions): void; + visitStarted(visit: Visit): void; + visitCompleted(visit: Visit): void; + visitFailed(visit: Visit): void; + visitRequestStarted(visit: Visit): void; + visitRequestCompleted(visit: Visit): void; + visitRequestFailedWithStatusCode(visit: Visit, statusCode: number): void; + visitRequestFinished(visit: Visit): void; + visitRendered(visit: Visit): void; + pageInvalidated(reason: { reason: string }): void; + formSubmissionStarted(formSubmission: FormSubmission): void; + formSubmissionFinished(formSubmission: FormSubmission): void; + linkPrefetchingIsEnabledForLocation(location: URL): boolean; +} + +export interface ProgressBar { + hiding: boolean; + value: number; + visible: boolean; + show(): void; + hide(): void; + setValue(value: number): void; +} + /** - * Interface for accessing the browser adapter. - * The adapter handles form submission lifecycle events. + * The delegate for the Turbo navigator — in practice, the active session. + * Provides access to the current adapter. */ -export interface BrowserAdapter { - formSubmissionStarted(formSubmission?: FormSubmission): void; - formSubmissionFinished(formSubmission?: FormSubmission): void; +export interface NavigatorDelegate { + adapter: Adapter; } /** @@ -123,6 +172,8 @@ export interface BrowserAdapter { * Provides methods for programmatic navigation and form submission. */ export interface Navigator { + /** The delegate for this navigator (the active Turbo session). */ + delegate: NavigatorDelegate; /** * Submits a form programmatically through Turbo Drive. * @@ -231,7 +282,7 @@ export interface TurboSession { disconnectStreamSource(source: StreamSource): void; renderStreamMessage(message: StreamMessage | string): void; drive: boolean; - adapter: BrowserAdapter; + adapter: Adapter; } export const StreamActions: { @@ -256,7 +307,7 @@ export function start(): void; * * @param adapter Adapter to register */ -export function registerAdapter(adapter: unknown): void; +export function registerAdapter(adapter: Adapter): void; /** * Sets the form mode for Turbo Drive. From a07cc4b647e0ee7c51b52729e8d9489298dd4bbb Mon Sep 17 00:00:00 2001 From: Dylan Conway Date: Mon, 2 Mar 2026 22:49:16 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#74604=20[bun]?= =?UTF-8?q?=20update=20to=20v1.3.10=20by=20@dylan-conway?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/bun/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/bun/package.json b/types/bun/package.json index 407f9072c1f4e2..14a95c8b265575 100644 --- a/types/bun/package.json +++ b/types/bun/package.json @@ -6,7 +6,7 @@ "https://bun.com" ], "dependencies": { - "bun-types": "1.3.9" + "bun-types": "1.3.10" }, "devDependencies": { "@types/bun": "workspace:."