From ad4b7ba60cf3ee8b862dfc1c37a7a1f9e5e652f3 Mon Sep 17 00:00:00 2001 From: George Berezhnoy Date: Mon, 2 Sep 2024 23:52:43 +0100 Subject: [PATCH] Send event if selection is lost for the input --- .../dom-adapters/src/CaretAdapter/index.ts | 4 ++- .../src/utils/useSelectionChange.ts | 25 +++++++++++++++++++ .../model/src/CaretManagement/Caret/Caret.ts | 4 +-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/packages/dom-adapters/src/CaretAdapter/index.ts b/packages/dom-adapters/src/CaretAdapter/index.ts index ba866c7b..327694e6 100644 --- a/packages/dom-adapters/src/CaretAdapter/index.ts +++ b/packages/dom-adapters/src/CaretAdapter/index.ts @@ -82,7 +82,7 @@ export class CaretAdapter extends EventTarget { * * @param index - new caret index */ - public updateIndex(index: Index): void { + public updateIndex(index: Index | null): void { this.#userCaret.update(index); } @@ -119,6 +119,8 @@ export class CaretAdapter extends EventTarget { */ #onSelectionChange(selection: Selection | null): void { if (!selection) { + this.updateIndex(null); + return; } diff --git a/packages/dom-adapters/src/utils/useSelectionChange.ts b/packages/dom-adapters/src/utils/useSelectionChange.ts index d0a8fdc7..cc18907e 100644 --- a/packages/dom-adapters/src/utils/useSelectionChange.ts +++ b/packages/dom-adapters/src/utils/useSelectionChange.ts @@ -31,6 +31,12 @@ export type InputWithCaret = HTMLElement; * Utility composable that watches for document "selection change" event and delegates the provided callbacks to subscribers. */ export const useSelectionChange = createSingleton(() => { + /** + * Stores the last input that was related to the selection. + * We need that to send update when selection is moved to another input. + */ + let lastRelatedInput: HTMLElement | null = null; + /** * Used to iterate over all inputs and check if selection is related to them. */ @@ -72,9 +78,28 @@ export const useSelectionChange = createSingleton(() => { inputsWatched.forEach((input) => { const subscriber = subscribers.get(input); + let isRelatedInputFound = false; + if (subscriber && isSelectionRelatedToInput(selection, input)) { + lastRelatedInput = input; + isRelatedInputFound = true; + subscriber.callback.call(subscriber.context, selection); } + + /** + * If no related input found or input is changed, we need to notify subscriber selection is out of it's input + */ + if (!isRelatedInputFound || input !== lastRelatedInput) { + subscriber?.callback.call(subscriber.context, null); + } + + /** + * If no related input found, we need to reset last related input + */ + if (!isRelatedInputFound) { + lastRelatedInput = null; + } }); } diff --git a/packages/model/src/CaretManagement/Caret/Caret.ts b/packages/model/src/CaretManagement/Caret/Caret.ts index b8a47824..fa6b8dd7 100644 --- a/packages/model/src/CaretManagement/Caret/Caret.ts +++ b/packages/model/src/CaretManagement/Caret/Caret.ts @@ -70,7 +70,7 @@ export class Caret extends EventBus { * * @param index - new caret index */ - public update(index: Index): void { + public update(index: Index | null): void { this.#index = index; this.dispatchEvent(new CaretUpdatedEvent(this)); @@ -82,7 +82,7 @@ export class Caret extends EventBus { public toJSON(): CaretSerialized { return { id: this.id, - index: this.index?.serialize(), + index: this.index !== null ? this.index.serialize() : null, } as CaretSerialized; } }