`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) <noreply@anthropic.com>master
parent
b7b338a616
commit
af38c4c170
@ -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
|
||||
}
|
||||
}
|
||||
@ -1,102 +0,0 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import { SvelteResizeObserver } from '../resize-observer';
|
||||
|
||||
type ResizeObserverCallbackLike = ConstructorParameters<typeof ResizeObserver>[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);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in new issue