Deep Research: the header also leaves when a map scrolls inside its own shadow root
dx-life measured with a real finger: on the Regions map the header stayed. Regions scrolls in its own containers (.rd-scroll, .rl-scroll) inside its own shadow root, and scroll events never cross a shadow root, so the gallery-level listener never saw them. Touch and wheel events do cross: on the first one over such a scroller, the page finds it in the event's composed path and listens to its scrolls directly (once each), which also covers momentum. The same half-the-gallery size rule keeps small lists, such as a legend sheet's, out.
This commit is contained in:
parent
196817f1da
commit
617e9561ff
1 changed files with 29 additions and 5 deletions
|
|
@ -53,18 +53,42 @@ function fitBelowHeader() {
|
|||
// is scrolled down a little, <html> gets rg-header-hidden (the header hides and the gallery takes
|
||||
// the full screen); back at the pane's top, the header returns. One scroller, so nothing fights
|
||||
// the pane's own momentum. Only a scroller at least half the gallery's height counts (its main
|
||||
// pane), not a small list such as a legend sheet's.
|
||||
// pane, or a map's own main list), not a small list such as a legend sheet's.
|
||||
function watchPaneForHeader(el: HTMLElement, root: ShadowRoot) {
|
||||
const cls = document.documentElement.classList
|
||||
const large = (n: HTMLElement) => n.clientHeight >= el.clientHeight / 2
|
||||
const onScroll = (e: Event) => {
|
||||
const pane = e.target
|
||||
if (!(pane instanceof HTMLElement) || pane.clientHeight < el.clientHeight / 2) return
|
||||
const cls = document.documentElement.classList
|
||||
if (!(pane instanceof HTMLElement) || !large(pane)) return
|
||||
if (pane.scrollTop > 8) cls.add('rg-header-hidden')
|
||||
else if (pane.scrollTop <= 0) cls.remove('rg-header-hidden')
|
||||
}
|
||||
// Scroll events don't bubble, but they do pass the shadow root in the capture phase.
|
||||
// Scroll events don't bubble, but they do pass the gallery's shadow root in the capture phase.
|
||||
root.addEventListener('scroll', onScroll, { capture: true, passive: true })
|
||||
unwatchPane = () => root.removeEventListener('scroll', onScroll, true)
|
||||
// A map inside the gallery may scroll in ITS OWN shadow root (Regions does), and scroll events
|
||||
// never cross a shadow root. Touch and wheel events do: on the first one over such a scroller,
|
||||
// find it in the event's composed path and listen to its scrolls directly (once each), which
|
||||
// also covers the momentum after the finger lifts.
|
||||
const watched = new WeakSet<HTMLElement>()
|
||||
const discover = (e: Event) => {
|
||||
for (const n of e.composedPath()) {
|
||||
if (n === el) break
|
||||
if (!(n instanceof HTMLElement) || watched.has(n)) continue
|
||||
const oy = getComputedStyle(n).overflowY
|
||||
if ((oy === 'auto' || oy === 'scroll') && n.scrollHeight > n.clientHeight + 1 && large(n)) {
|
||||
watched.add(n)
|
||||
n.addEventListener('scroll', onScroll, { passive: true })
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
el.addEventListener('touchmove', discover, { passive: true })
|
||||
el.addEventListener('wheel', discover, { passive: true })
|
||||
unwatchPane = () => {
|
||||
root.removeEventListener('scroll', onScroll, true)
|
||||
el.removeEventListener('touchmove', discover)
|
||||
el.removeEventListener('wheel', discover)
|
||||
}
|
||||
}
|
||||
|
||||
// The gallery attaches its shadow root once its script has defined the element.
|
||||
|
|
|
|||
Loading…
Reference in a new issue