+27
-2
src/components/molecules/grain-pull-to-refresh.js
+27
-2
src/components/molecules/grain-pull-to-refresh.js
···
41
41
42
42
#startY = 0;
43
43
#currentY = 0;
44
+
#scrollContainer = null;
44
45
45
46
constructor() {
46
47
super();
···
51
52
52
53
connectedCallback() {
53
54
super.connectedCallback();
55
+
this.#scrollContainer = this.#findScrollContainer();
54
56
this.addEventListener('touchstart', this.#onTouchStart, { passive: true });
55
57
this.addEventListener('touchmove', this.#onTouchMove, { passive: false });
56
58
this.addEventListener('touchend', this.#onTouchEnd, { passive: true });
57
59
}
58
60
61
+
#findScrollContainer() {
62
+
let el = this.parentElement;
63
+
while (el) {
64
+
// Check through shadow DOM boundaries
65
+
if (el.scrollHeight > el.clientHeight) {
66
+
const style = getComputedStyle(el);
67
+
if (style.overflowY === 'auto' || style.overflowY === 'scroll') {
68
+
return el;
69
+
}
70
+
}
71
+
// Traverse up through shadow roots
72
+
el = el.parentElement || el.getRootNode()?.host;
73
+
}
74
+
return null;
75
+
}
76
+
77
+
#getScrollTop() {
78
+
if (this.#scrollContainer) {
79
+
return this.#scrollContainer.scrollTop;
80
+
}
81
+
return window.scrollY;
82
+
}
83
+
59
84
disconnectedCallback() {
60
85
this.removeEventListener('touchstart', this.#onTouchStart);
61
86
this.removeEventListener('touchmove', this.#onTouchMove);
···
68
93
69
94
#onTouchStart = (e) => {
70
95
if (this.refreshing) return;
71
-
if (window.scrollY > 0) return;
96
+
if (this.#getScrollTop() > 0) return;
72
97
73
98
this.#startY = e.touches[0].clientY;
74
99
this._pulling = true;
···
80
105
this.#currentY = e.touches[0].clientY;
81
106
const diff = this.#currentY - this.#startY;
82
107
83
-
if (diff > 0 && window.scrollY === 0) {
108
+
if (diff > 0 && this.#getScrollTop() === 0) {
84
109
e.preventDefault();
85
110
// Apply resistance
86
111
this._pullDistance = Math.min(diff * 0.5, MAX_PULL);