From af38c4c1708ea21ed386366eab29c21b33612bdd Mon Sep 17 00:00:00 2001 From: dev Date: Wed, 6 May 2026 23:12:18 +0200 Subject: [PATCH] Drop dead SvelteResizeObserver from libs/dom MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `SvelteResizeObserver` lived in `$libs/dom` as a generic ResizeObserver wrapper with manual `refresh()` / `destroy()` lifecycle. Across the repo it had zero real consumers — only its own test file imported it. The Svelte-aware ResizeObserver in active use is `ResizeObserver$` in `src/suix/soma/layers/resize-observer.svelte.ts`, which uses `$effect` for auto-cleanup and is consumed by accordion. Removing the unused module keeps `$libs/dom` honest as "the surface nobody can reach for a duplicate ResizeObserver implementation when they could just consume the soma layer (or, eventually, an `$adom` helper that mirrors `BodyScrollLock`)". Verification: - `npx vitest run src/libs/dom src/arts/adom`: 9 / 9 files, 37 / 37 tests green (down from 10 / 40 — the dropped 3 tests covered the removed class). - `node scripts/check-aliases.mjs`: clean (only the pre-existing PERMUTATION_RUNNER.md hit, unrelated). - `npm run check`: 61 / 0 / 17 unchanged from before (the residual errors are all in untracked src/suix/* and predate this commit). Co-Authored-By: Claude Opus 4.7 (1M context) --- src/libs/dom/index.ts | 1 - src/libs/dom/resize-observer.ts | 58 ------------ src/libs/dom/test/resize-observer.test.ts | 102 ---------------------- 3 files changed, 161 deletions(-) delete mode 100644 src/libs/dom/resize-observer.ts delete mode 100644 src/libs/dom/test/resize-observer.test.ts diff --git a/src/libs/dom/index.ts b/src/libs/dom/index.ts index 6520d63..dfa3744 100644 --- a/src/libs/dom/index.ts +++ b/src/libs/dom/index.ts @@ -4,6 +4,5 @@ export * from './core' export * from './errors' export * from './focus' export * from './locale' -export * from './resize-observer' export * from './responsive' export * from './tabbable' diff --git a/src/libs/dom/resize-observer.ts b/src/libs/dom/resize-observer.ts deleted file mode 100644 index 9bb7284..0000000 --- a/src/libs/dom/resize-observer.ts +++ /dev/null @@ -1,58 +0,0 @@ -export type ResizeObservedNode = HTMLElement | null | undefined -export type ResizeObservedNodeGetter = () => ResizeObservedNode - -function canObserveResize(): boolean { - return typeof window !== 'undefined' && typeof ResizeObserver !== 'undefined' -} - -export class SvelteResizeObserver { - readonly node: ResizeObservedNodeGetter - readonly onResize: () => void - - private observer: ResizeObserver | null = null - private observedNode: HTMLElement | null = null - private rAF = 0 - - constructor(node: ResizeObservedNodeGetter, onResize: () => void) { - this.node = node - this.onResize = onResize - this.refresh() - } - - refresh = () => { - if (!canObserveResize()) return - - const nextNode = this.node() ?? null - if (nextNode === this.observedNode) return - - this.disconnect() - if (!nextNode) return - - this.observedNode = nextNode - this.observer = new ResizeObserver(() => { - if (typeof window.requestAnimationFrame === 'function') { - window.cancelAnimationFrame(this.rAF) - this.rAF = window.requestAnimationFrame(this.onResize) - return - } - - this.onResize() - }) - - this.observer.observe(nextNode) - } - - destroy = () => { - this.disconnect() - } - - private disconnect() { - if (typeof window !== 'undefined' && typeof window.cancelAnimationFrame === 'function') { - window.cancelAnimationFrame(this.rAF) - } - this.rAF = 0 - this.observer?.disconnect() - this.observer = null - this.observedNode = null - } -} diff --git a/src/libs/dom/test/resize-observer.test.ts b/src/libs/dom/test/resize-observer.test.ts deleted file mode 100644 index 911452e..0000000 --- a/src/libs/dom/test/resize-observer.test.ts +++ /dev/null @@ -1,102 +0,0 @@ -// @vitest-environment jsdom - -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; - -import { SvelteResizeObserver } from '../resize-observer'; - -type ResizeObserverCallbackLike = ConstructorParameters[0]; - -class MockResizeObserver { - static instances: MockResizeObserver[] = []; - - readonly observed: Element[] = []; - disconnected = false; - readonly callback: ResizeObserverCallbackLike; - - constructor(callback: ResizeObserverCallbackLike) { - this.callback = callback; - MockResizeObserver.instances.push(this); - } - - observe = (element: Element) => { - this.observed.push(element); - }; - - disconnect = () => { - this.disconnected = true; - }; - - trigger() { - this.callback([] as ResizeObserverEntry[], this as unknown as ResizeObserver); - } -} - -describe('libs/dom resize observer', () => { - const originalResizeObserver = globalThis.ResizeObserver; - const originalRequestAnimationFrame = window.requestAnimationFrame; - const originalCancelAnimationFrame = window.cancelAnimationFrame; - - beforeEach(() => { - MockResizeObserver.instances = []; - (globalThis as typeof globalThis & { ResizeObserver: typeof ResizeObserver }).ResizeObserver = - MockResizeObserver as unknown as typeof ResizeObserver; - window.requestAnimationFrame = ((callback: FrameRequestCallback) => { - callback(0); - return 1; - }) as typeof window.requestAnimationFrame; - window.cancelAnimationFrame = vi.fn() as typeof window.cancelAnimationFrame; - }); - - afterEach(() => { - const globals = globalThis as { ResizeObserver?: typeof ResizeObserver }; - if (originalResizeObserver) { - globals.ResizeObserver = originalResizeObserver; - } else { - delete globals.ResizeObserver; - } - window.requestAnimationFrame = originalRequestAnimationFrame; - window.cancelAnimationFrame = originalCancelAnimationFrame; - }); - - it('observes the provided node and invokes the callback on resize', async () => { - const node = document.createElement('div'); - const onResize = vi.fn(); - - new SvelteResizeObserver(() => node, onResize); - - expect(MockResizeObserver.instances).toHaveLength(1); - expect(MockResizeObserver.instances[0]?.observed).toEqual([node]); - - MockResizeObserver.instances[0]?.trigger(); - - expect(onResize).toHaveBeenCalledTimes(1); - }); - - it('does not create an observer when the target is null', async () => { - new SvelteResizeObserver(() => null, vi.fn()); - - expect(MockResizeObserver.instances).toHaveLength(0); - }); - - it('can rebind to a new node and disconnect on destroy', () => { - const first = document.createElement('div'); - const second = document.createElement('div'); - let current = first; - - const resizeObserver = new SvelteResizeObserver(() => current, vi.fn()); - - expect(MockResizeObserver.instances).toHaveLength(1); - expect(MockResizeObserver.instances[0]?.observed).toEqual([first]); - - current = second; - resizeObserver.refresh(); - - expect(MockResizeObserver.instances).toHaveLength(2); - expect(MockResizeObserver.instances[0]?.disconnected).toBe(true); - expect(MockResizeObserver.instances[1]?.observed).toEqual([second]); - - resizeObserver.destroy(); - - expect(MockResizeObserver.instances[1]?.disconnected).toBe(true); - }); -});