From 27e03addb198d60ca16b15f586bd2d0f2751ab8a Mon Sep 17 00:00:00 2001 From: "Thomas G. Lopes" <26071571+TGlide@users.noreply.github.com> Date: Fri, 17 May 2024 14:47:54 +0100 Subject: [PATCH] Fix active element (#55) * rename debounced (#52) * fix active element * add changeset * optimize activeElement * fix lint * refactor readable a bit --- .changeset/mighty-jars-thank.md | 5 ++++ .../runed/src/lib/internal/utils/function.ts | 3 +++ .../lib/utilities/Readable/readable.svelte.ts | 24 ++++++++++++------- .../activeElement/activeElement.svelte.ts | 7 +++++- .../activeElement.test.svelte.ts | 2 +- 5 files changed, 30 insertions(+), 11 deletions(-) create mode 100644 .changeset/mighty-jars-thank.md create mode 100644 packages/runed/src/lib/internal/utils/function.ts diff --git a/.changeset/mighty-jars-thank.md b/.changeset/mighty-jars-thank.md new file mode 100644 index 00000000..8b24075d --- /dev/null +++ b/.changeset/mighty-jars-thank.md @@ -0,0 +1,5 @@ +--- +"runed": patch +--- + +fix active element not being up to date outside effects diff --git a/packages/runed/src/lib/internal/utils/function.ts b/packages/runed/src/lib/internal/utils/function.ts new file mode 100644 index 00000000..1a687ce9 --- /dev/null +++ b/packages/runed/src/lib/internal/utils/function.ts @@ -0,0 +1,3 @@ +export function noop() { + // noop +} diff --git a/packages/runed/src/lib/utilities/Readable/readable.svelte.ts b/packages/runed/src/lib/utilities/Readable/readable.svelte.ts index 51bab708..34be43c6 100644 --- a/packages/runed/src/lib/utilities/Readable/readable.svelte.ts +++ b/packages/runed/src/lib/utilities/Readable/readable.svelte.ts @@ -1,6 +1,10 @@ import { tick } from "svelte"; +import { noop } from "$lib/internal/utils/function.js"; -export type StartNotifier = (set: (value: TValue) => void) => VoidFunction; +export type StartNotifier = ( + set: (value: TValue) => void, + insideEffect: boolean +) => void | VoidFunction; /** * A class that contains a reactive `current` property @@ -40,7 +44,7 @@ export class Readable { $effect(() => { this.#subscribers++; if (this.#subscribers === 1) { - this.#subscribe(); + this.#subscribe(true); } return () => { @@ -52,21 +56,23 @@ export class Readable { }); }; }); + } else if (this.#subscribers === 0) { + this.#subscribe(false); + this.#unsubscribe(); } return this.#current; } - #subscribe() { - this.#stop = this.#start((value) => { - this.#current = value; - }); + #subscribe(inEffect: boolean) { + this.#stop = + this.#start((value) => { + this.#current = value; + }, inEffect) ?? null; } #unsubscribe() { - if (this.#stop === null) { - return; - } + if (this.#stop === null) return; this.#stop(); this.#stop = null; diff --git a/packages/runed/src/lib/utilities/activeElement/activeElement.svelte.ts b/packages/runed/src/lib/utilities/activeElement/activeElement.svelte.ts index ffa68632..993dd257 100644 --- a/packages/runed/src/lib/utilities/activeElement/activeElement.svelte.ts +++ b/packages/runed/src/lib/utilities/activeElement/activeElement.svelte.ts @@ -6,10 +6,15 @@ import { Readable } from "../Readable/readable.svelte.js"; * * @see {@link https://runed.dev/docs/utilities/use-active-element} */ -export const activeElement = new Readable(null, (set) => { +export const activeElement = new Readable(null, (set, insideEffect) => { function update() { set(document.activeElement); } + + update(); + + if (!insideEffect) return; + document.addEventListener("focusin", update); document.addEventListener("focusout", update); diff --git a/packages/runed/src/lib/utilities/activeElement/activeElement.test.svelte.ts b/packages/runed/src/lib/utilities/activeElement/activeElement.test.svelte.ts index a96c4eee..7047e57e 100644 --- a/packages/runed/src/lib/utilities/activeElement/activeElement.test.svelte.ts +++ b/packages/runed/src/lib/utilities/activeElement/activeElement.test.svelte.ts @@ -4,7 +4,7 @@ import { activeElement } from "./index.js"; import { testWithEffect } from "$lib/test/util.svelte.js"; // Skipping because testing is weird -describe.skip("useActiveElement", () => { +describe("useActiveElement", () => { testWithEffect("initializes with `document.activeElement`", () => { expect(activeElement.current).toBe(document.activeElement); });