diff --git a/src/IntersectionObserver.svelte b/src/IntersectionObserver.svelte
index b86199f..19e6bd1 100644
--- a/src/IntersectionObserver.svelte
+++ b/src/IntersectionObserver.svelte
@@ -63,7 +63,7 @@
),
);
- if (element && once) observer?.unobserve(element);
+ if (once) observer?.unobserve(_entry.target);
}
}
},
diff --git a/tests/e2e/fixtures/OnceElementChangeFixture.svelte b/tests/e2e/fixtures/OnceElementChangeFixture.svelte
new file mode 100644
index 0000000..0693928
--- /dev/null
+++ b/tests/e2e/fixtures/OnceElementChangeFixture.svelte
@@ -0,0 +1,63 @@
+
+
+
+ {intersecting ? "Element is in view" : "Element is not in view"}
+
+
+
+
+
+ A
+
+
+
+
+ B
+
+
+
diff --git a/tests/unit/IntersectionObserver.test.ts b/tests/unit/IntersectionObserver.test.ts
index 645c2f0..edf7bb8 100644
--- a/tests/unit/IntersectionObserver.test.ts
+++ b/tests/unit/IntersectionObserver.test.ts
@@ -4,6 +4,7 @@ import BasicFixture from "../e2e/fixtures/BasicFixture.svelte";
import EachBindingFixture from "../e2e/fixtures/EachBindingFixture.svelte";
import ElementChangeFixture from "../e2e/fixtures/ElementChangeFixture.svelte";
import ElementNullFixture from "../e2e/fixtures/ElementNullFixture.svelte";
+import OnceElementChangeFixture from "../e2e/fixtures/OnceElementChangeFixture.svelte";
import OnceFixture from "../e2e/fixtures/OnceFixture.svelte";
import RootFixture from "../e2e/fixtures/RootFixture.svelte";
import RootMarginChangeFixture from "../e2e/fixtures/RootMarginChangeFixture.svelte";
@@ -80,6 +81,36 @@ describe("IntersectionObserver", () => {
).toContain("Intersect count: 1");
});
+ test("once unobserves the entry's own target, not a stale element prop, when the element changes before delivery", () => {
+ const rendered = render(OnceElementChangeFixture);
+ cleanup = rendered.cleanup;
+ const elementA = rendered.target.querySelector('[data-testid="el-a"]');
+ const elementB = rendered.target.querySelector('[data-testid="el-b"]');
+ const switchButton = rendered.target.querySelector(
+ '[data-testid="switch"]',
+ );
+ if (
+ !elementA ||
+ !elementB ||
+ !(switchButton instanceof HTMLButtonElement)
+ ) {
+ throw new Error("fixture markup missing");
+ }
+
+ const observer = MockIntersectionObserver.last();
+ expect(observer.observedElements.has(elementA)).toBe(true);
+
+ switchButton.click();
+ flushSync();
+
+ flushSync(() =>
+ observer.trigger([{ target: elementA, isIntersecting: true }]),
+ );
+
+ expect(observer.observedElements.has(elementB)).toBe(true);
+ expect(observer.observedElements.has(elementA)).toBe(false);
+ });
+
test("skip pauses and resumes observation without losing state", () => {
const rendered = render(SkipFixture);
cleanup = rendered.cleanup;