fix(touch): refresh device hits and defer pinch zoom save (#613)

Issue: #613
User-Visible: yes
This commit is contained in:
Claude
2026-09-23 05:35:41 +03:00
parent 59fdae817a
commit e95936cdce
50 changed files with 1009 additions and 666 deletions
+56 -1
View File
@@ -1,7 +1,8 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import {
DeviceHitIndex, DevicePointerOwnerLatch, pointInDeviceCapsule, resolveDeviceHitOwner,
DeviceHitIndex, DevicePointerOwnerLatch, deviceHitScrollSources,
observeDeviceHitGeometryScroll, pointInDeviceCapsule, resolveDeviceHitOwner,
} from '../test-build/device-hit-owner.js';
const candidate = (id, x, y, width = 12, height = 12, floorRadius = 22) => ({
@@ -75,3 +76,57 @@ test('#564 pointer owner is held through release and consumed by click', () => {
assert.equal(latch.release(8), null);
latch.clear();
});
test('#613 scroll observation crosses shadow hosts and tears down exactly once', () => {
const target = (fields = {}) => Object.assign(new EventTarget(), fields);
const viewport = new EventTarget();
const win = target({ visualViewport: viewport });
const document = target({
nodeType: 9, parentElement: null, ownerDocument: null, defaultView: win,
getRootNode() { return this; },
});
const body = target({
nodeType: 1, assignedSlot: null, parentElement: null, ownerDocument: document,
getRootNode: () => document,
});
const dashboardScroller = target({
nodeType: 1, assignedSlot: null, parentElement: body, ownerDocument: document,
getRootNode: () => document,
});
const dashboardHost = target({
nodeType: 1, assignedSlot: null, parentElement: dashboardScroller,
ownerDocument: document, getRootNode: () => document,
});
const dashboardRoot = { nodeType: 11, host: dashboardHost };
const shadowScroller = target({
nodeType: 1, assignedSlot: null, parentElement: null, ownerDocument: document,
getRootNode: () => dashboardRoot,
});
const card = target({
nodeType: 1, assignedSlot: null, parentElement: shadowScroller,
ownerDocument: document, getRootNode: () => dashboardRoot,
});
assert.deepEqual(deviceHitScrollSources(card), [
card, shadowScroller, dashboardHost, dashboardScroller, body, document, win,
]);
let invalidations = 0;
const disconnect = observeDeviceHitGeometryScroll(card, () => { invalidations += 1; });
shadowScroller.dispatchEvent(new Event('scroll'));
dashboardScroller.dispatchEvent(new Event('scroll'));
viewport.dispatchEvent(new Event('resize'));
assert.equal(invalidations, 3);
disconnect();
disconnect();
shadowScroller.dispatchEvent(new Event('scroll'));
dashboardScroller.dispatchEvent(new Event('scroll'));
viewport.dispatchEvent(new Event('scroll'));
assert.equal(invalidations, 3);
const reconnect = observeDeviceHitGeometryScroll(card, () => { invalidations += 1; });
dashboardScroller.dispatchEvent(new Event('scroll'));
assert.equal(invalidations, 4);
reconnect();
});