diff --git a/src/core/bardo.ts b/src/core/bardo.ts index 9b811e661..3847304ff 100644 --- a/src/core/bardo.ts +++ b/src/core/bardo.ts @@ -1,22 +1,34 @@ import { PermanentElementMap } from "./snapshot" +export interface BardoDelegate { + enteringBardo(currentPermanentElement: Element, newPermanentElement: Element): void + leavingBardo(currentPermanentElement: Element): void +} + export class Bardo { readonly permanentElementMap: PermanentElementMap + readonly delegate: BardoDelegate - static preservingPermanentElements(permanentElementMap: PermanentElementMap, callback: () => void) { - const bardo = new this(permanentElementMap) + static preservingPermanentElements( + delegate: BardoDelegate, + permanentElementMap: PermanentElementMap, + callback: () => void + ) { + const bardo = new this(delegate, permanentElementMap) bardo.enter() callback() bardo.leave() } - constructor(permanentElementMap: PermanentElementMap) { + constructor(delegate: BardoDelegate, permanentElementMap: PermanentElementMap) { + this.delegate = delegate this.permanentElementMap = permanentElementMap } enter() { for (const id in this.permanentElementMap) { - const [, newPermanentElement] = this.permanentElementMap[id] + const [currentPermanentElement, newPermanentElement] = this.permanentElementMap[id] + this.delegate.enteringBardo(currentPermanentElement, newPermanentElement) this.replaceNewPermanentElementWithPlaceholder(newPermanentElement) } } @@ -26,6 +38,7 @@ export class Bardo { const [currentPermanentElement] = this.permanentElementMap[id] this.replaceCurrentPermanentElementWithClone(currentPermanentElement) this.replacePlaceholderWithPermanentElement(currentPermanentElement) + this.delegate.leavingBardo(currentPermanentElement) } } @@ -49,7 +62,7 @@ export class Bardo { } get placeholders(): HTMLMetaElement[] { - return [...document.querySelectorAll("meta[name=turbo-permanent-placeholder][content]")] as any + return [...document.querySelectorAll("meta[name=turbo-permanent-placeholder][content]")] } } diff --git a/src/core/drive/page_renderer.ts b/src/core/drive/page_renderer.ts index 4c0a67e8a..de3e12ba3 100644 --- a/src/core/drive/page_renderer.ts +++ b/src/core/drive/page_renderer.ts @@ -12,13 +12,13 @@ export class PageRenderer extends Renderer { get reloadReason(): ReloadReason { if (!this.newSnapshot.isVisitable) { return { - reason: "turbo_visit_control_is_reload" + reason: "turbo_visit_control_is_reload", } } if (!this.trackedElementsAreIdentical) { return { - reason: "tracked_element_mismatch" + reason: "tracked_element_mismatch", } } } diff --git a/src/core/native/browser_adapter.ts b/src/core/native/browser_adapter.ts index 5073102d4..7fc70317f 100644 --- a/src/core/native/browser_adapter.ts +++ b/src/core/native/browser_adapter.ts @@ -8,7 +8,7 @@ import { uuid, dispatch } from "../../util" export type ReloadReason = StructuredReason | undefined interface StructuredReason { reason: string - context?: {[key: string]: any} + context?: { [key: string]: any } } export class BrowserAdapter implements Adapter { @@ -54,8 +54,8 @@ export class BrowserAdapter implements Adapter { return this.reload({ reason: "request_failed", context: { - statusCode - } + statusCode, + }, }) default: return visit.loadResponse() diff --git a/src/core/renderer.ts b/src/core/renderer.ts index bd96d9365..7458c7f61 100644 --- a/src/core/renderer.ts +++ b/src/core/renderer.ts @@ -1,4 +1,4 @@ -import { Bardo } from "./bardo" +import { Bardo, BardoDelegate } from "./bardo" import { Snapshot } from "./snapshot" import { ReloadReason } from "./native/browser_adapter" @@ -7,13 +7,14 @@ type ResolvingFunctions = { reject(reason?: any): void } -export abstract class Renderer = Snapshot> { +export abstract class Renderer = Snapshot> implements BardoDelegate { readonly currentSnapshot: S readonly newSnapshot: S readonly isPreview: boolean readonly willRender: boolean readonly promise: Promise private resolvingFunctions?: ResolvingFunctions + private activeElement: Element | null = null constructor(currentSnapshot: S, newSnapshot: S, isPreview: boolean, willRender = true) { this.currentSnapshot = currentSnapshot @@ -60,7 +61,7 @@ export abstract class Renderer = Snapsh } preservingPermanentElements(callback: () => void) { - Bardo.preservingPermanentElements(this.permanentElementMap, callback) + Bardo.preservingPermanentElements(this, this.permanentElementMap, callback) } focusFirstAutofocusableElement() { @@ -70,6 +71,24 @@ export abstract class Renderer = Snapsh } } + // Bardo delegate + + enteringBardo(currentPermanentElement: Element) { + if (this.activeElement) return + + if (currentPermanentElement.contains(this.currentSnapshot.activeElement)) { + this.activeElement = this.currentSnapshot.activeElement + } + } + + leavingBardo(currentPermanentElement: Element) { + if (currentPermanentElement.contains(this.activeElement) && this.activeElement instanceof HTMLElement) { + this.activeElement.focus() + + this.activeElement = null + } + } + get connectedSnapshot() { return this.newSnapshot.isConnected ? this.newSnapshot : this.currentSnapshot } diff --git a/src/core/session.ts b/src/core/session.ts index 46f2194a0..7ae27bed5 100644 --- a/src/core/session.ts +++ b/src/core/session.ts @@ -128,7 +128,7 @@ export class Session }) } else { this.adapter.pageInvalidated({ - reason: "turbo_disabled" + reason: "turbo_disabled", }) } } diff --git a/src/core/snapshot.ts b/src/core/snapshot.ts index f2cd03fa4..f46977da5 100644 --- a/src/core/snapshot.ts +++ b/src/core/snapshot.ts @@ -5,6 +5,10 @@ export class Snapshot { this.element = element } + get activeElement() { + return this.element.ownerDocument.activeElement + } + get children() { return [...this.element.children] } diff --git a/src/tests/fixtures/frames/hello.html b/src/tests/fixtures/frames/hello.html index c307c33b6..6c41d263b 100644 --- a/src/tests/fixtures/frames/hello.html +++ b/src/tests/fixtures/frames/hello.html @@ -12,6 +12,14 @@

Hello

Hello from a frame

Navigate #hello + +
+ +
+ +
+ +
diff --git a/src/tests/fixtures/rendering.html b/src/tests/fixtures/rendering.html index 7b18c98fa..8937731be 100644 --- a/src/tests/fixtures/rendering.html +++ b/src/tests/fixtures/rendering.html @@ -44,10 +44,30 @@

Rendering

Rendering
+
+ +
+ +
+ +
+
Rendering
+ +
+ + +
+ +
+ + +
+
+