/** * Keeps a touch that lands on the open panel from scrolling the page behind * it. * * `overscroll-behavior: contain` is on the message list already, and it does * the job for the case it covers: a list that can scroll, dragged past its * own end. It has nothing to say about the cases that actually leak. A short * conversation does not overflow, so the list is not a scroll container at * all and the touch goes straight through to the document — which is what a * reader on an iPhone sees as the page sliding around underneath a chat that * looks like it should be holding still. The same happens for a touch that * starts on the title bar or beside the input. * * So the rule is decided here instead: a touch on the panel may scroll * something inside the panel, and otherwise it does nothing. On the first * move of each gesture the controller looks along the touch's own path — * `composedPath`, so a scroller inside a consumer's component counts too — * for something that can still travel in the direction the finger is going. * Finding one, it stands aside for the rest of the gesture; finding none, it * cancels the move, and iOS then takes the whole gesture as "not a scroll". * * Two touches are left alone: that is a pinch, and zooming is the reader's. * A move that is no longer cancelable is left alone too — the browser has * already committed to scrolling, and `overscroll-behavior` is what keeps * that inside the list. * * @implements {ReactiveController} */ export class ScrollLockController implements ReactiveController { /** @param {LitElement} host */ constructor(host: LitElement); hostUpdated(): void; hostDisconnected(): void; #private; } import type { ReactiveController } from 'lit'; import type { LitElement } from 'lit';