From 1c18d1139b0188904eeb2ec0f378f1535c2d2d2a Mon Sep 17 00:00:00 2001 From: Mathis Michel Date: Fri, 20 Jun 2025 13:39:07 +0200 Subject: [PATCH 1/2] fix(keyborg): Multiple Bundles should not override instances --- src/Keyborg.ts | 55 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/src/Keyborg.ts b/src/Keyborg.ts index 0a532b42b..2fc139645 100644 --- a/src/Keyborg.ts +++ b/src/Keyborg.ts @@ -13,6 +13,7 @@ import { Disposable } from "./WeakRefInstance"; interface WindowWithKeyborg extends Window { __keyborg?: { + lastId?: number; core: KeyborgCore; refs: { [id: string]: Keyborg }; }; @@ -21,7 +22,40 @@ interface WindowWithKeyborg extends Window { const _dismissTimeout = 500; // When a key from dismissKeys is pressed and the focus is not moved // during _dismissTimeout time, dismiss the keyboard navigation mode. -let _lastId = 0; + +/** + * Function to get the next unique ID for a Keyborg instance or Core instance. + */ +function getNextId(keyborg: NonNullable): number { + if (keyborg.lastId === undefined) { + keyborg.lastId = 0; + } + + return ++keyborg.lastId; +} + +/** + * Ensures that the global keyborg instance is initialized in the window. + * If it doesn't exist, it creates a new instance incorporating the KeyborgCore instance provided via the coreFactory. + */ +function ensureGlobalKeyborgInitialized(win: WindowWithKeyborg, coreFactory: () => KeyborgCore): NonNullable { + if (win.__keyborg) { + return win.__keyborg; + } + + const core = coreFactory(); + + // Core factory might already register the global keyborg instance so we only need to set it up if it doesn't exist + if (!win.__keyborg) { + win.__keyborg = { + lastId: 0, + core, + refs: {}, + }; + } + + return win.__keyborg; +} export interface KeyborgProps { // Keys to be used to trigger keyboard navigation mode. By default, any key will trigger @@ -48,7 +82,8 @@ class KeyborgCore implements Disposable { private _isNavigatingWithKeyboard_DO_NOT_USE = false; constructor(win: WindowWithKeyborg, props?: KeyborgProps) { - this.id = "c" + ++_lastId; + const current = ensureGlobalKeyborgInitialized(win, () => this); + this.id = "c_" + getNextId(current); this._win = win; const doc = win.document; @@ -291,21 +326,13 @@ export class Keyborg { } private constructor(win: WindowWithKeyborg, props?: KeyborgProps) { - this._id = "k" + ++_lastId; this._win = win; - const current = win.__keyborg; + const current = ensureGlobalKeyborgInitialized(win, () => new KeyborgCore(win, props)); - if (current) { - this._core = current.core; - current.refs[this._id] = this; - } else { - this._core = new KeyborgCore(win, props); - win.__keyborg = { - core: this._core, - refs: { [this._id]: this }, - }; - } + this._core = current.core; + this._id = "k_" + getNextId(current); + current.refs[this._id] = this; } private dispose(): void { From c6e39d66b0918f712f65077e80089e493a3b41df Mon Sep 17 00:00:00 2001 From: Mathis Michel Date: Fri, 20 Jun 2025 13:51:33 +0200 Subject: [PATCH 2/2] fix: remove blank line --- src/Keyborg.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Keyborg.ts b/src/Keyborg.ts index 2fc139645..0e82138ca 100644 --- a/src/Keyborg.ts +++ b/src/Keyborg.ts @@ -22,11 +22,12 @@ interface WindowWithKeyborg extends Window { const _dismissTimeout = 500; // When a key from dismissKeys is pressed and the focus is not moved // during _dismissTimeout time, dismiss the keyboard navigation mode. - /** * Function to get the next unique ID for a Keyborg instance or Core instance. */ -function getNextId(keyborg: NonNullable): number { +function getNextId( + keyborg: NonNullable, +): number { if (keyborg.lastId === undefined) { keyborg.lastId = 0; } @@ -38,7 +39,10 @@ function getNextId(keyborg: NonNullable): number * Ensures that the global keyborg instance is initialized in the window. * If it doesn't exist, it creates a new instance incorporating the KeyborgCore instance provided via the coreFactory. */ -function ensureGlobalKeyborgInitialized(win: WindowWithKeyborg, coreFactory: () => KeyborgCore): NonNullable { +function ensureGlobalKeyborgInitialized( + win: WindowWithKeyborg, + coreFactory: () => KeyborgCore, +): NonNullable { if (win.__keyborg) { return win.__keyborg; } @@ -328,7 +332,10 @@ export class Keyborg { private constructor(win: WindowWithKeyborg, props?: KeyborgProps) { this._win = win; - const current = ensureGlobalKeyborgInitialized(win, () => new KeyborgCore(win, props)); + const current = ensureGlobalKeyborgInitialized( + win, + () => new KeyborgCore(win, props), + ); this._core = current.core; this._id = "k_" + getNextId(current);