@glitchr/stickyjs 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/js/stops.js +34 -1
package/package.json
CHANGED
package/src/js/stops.js
CHANGED
|
@@ -30,6 +30,11 @@
|
|
|
30
30
|
// undo, a movement the reader started. With prefers-reduced-motion the glide
|
|
31
31
|
// is a jump.
|
|
32
32
|
//
|
|
33
|
+
// Nor does a scroll the browser makes to bring a focused field into view: an
|
|
34
|
+
// invalid form submission revealing its first empty field, or Tab. Heading up
|
|
35
|
+
// from the text, that scroll was taken for the reader's and carried the page
|
|
36
|
+
// on to the stop above - the form gone from the screen it had just asked for.
|
|
37
|
+
//
|
|
33
38
|
// Progress: with two stops or more, the scroller (the <html> element for the
|
|
34
39
|
// page) carries three custom properties - --sticky-stop, the index of the stop
|
|
35
40
|
// above the scroll; --sticky-progress, 0 at that stop and 1 at the next; and
|
|
@@ -68,6 +73,12 @@
|
|
|
68
73
|
// The reader taking over ends a glide; the browser has already stopped it.
|
|
69
74
|
var INTERRUPT = ['wheel', 'touchstart', 'keydown', 'mousedown'];
|
|
70
75
|
|
|
76
|
+
// ms after a focus change in which a scroll starting is the browser
|
|
77
|
+
// revealing the focused field, not the reader.
|
|
78
|
+
var REVEAL = 250;
|
|
79
|
+
|
|
80
|
+
function now() { return window.performance ? performance.now() : Date.now(); }
|
|
81
|
+
|
|
71
82
|
function extend(target) {
|
|
72
83
|
for (var i = 1; i < arguments.length; i++) {
|
|
73
84
|
var source = arguments[i];
|
|
@@ -114,17 +125,25 @@
|
|
|
114
125
|
this.timer = null;
|
|
115
126
|
this.glideTimer = null;
|
|
116
127
|
this.frame = null;
|
|
128
|
+
this.focusedAt = -Infinity;
|
|
129
|
+
this.revealing = false;
|
|
117
130
|
|
|
118
131
|
this.onScroll = this.onScroll.bind(this);
|
|
119
132
|
this.onInterrupt = this.onInterrupt.bind(this);
|
|
133
|
+
this.onFocus = this.onFocus.bind(this);
|
|
120
134
|
this.onResize = this.onResize.bind(this);
|
|
121
135
|
this.settle = this.settle.bind(this);
|
|
122
136
|
this.tick = this.tick.bind(this);
|
|
123
137
|
|
|
138
|
+
// focusin bubbles, so the scroller hears its own fields; the window
|
|
139
|
+
// does not, so the page's are heard on the document.
|
|
140
|
+
this.focusTarget = this.isWindow ? document : this.scroller;
|
|
141
|
+
|
|
124
142
|
this.scroller.addEventListener('scroll', this.onScroll, { passive: true });
|
|
125
143
|
for (var i = 0; i < INTERRUPT.length; i++) {
|
|
126
144
|
this.scroller.addEventListener(INTERRUPT[i], this.onInterrupt, { passive: true });
|
|
127
145
|
}
|
|
146
|
+
this.focusTarget.addEventListener('focusin', this.onFocus, true);
|
|
128
147
|
window.addEventListener('resize', this.onResize);
|
|
129
148
|
|
|
130
149
|
this.refresh();
|
|
@@ -135,6 +154,7 @@
|
|
|
135
154
|
for (var i = 0; i < INTERRUPT.length; i++) {
|
|
136
155
|
this.scroller.removeEventListener(INTERRUPT[i], this.onInterrupt);
|
|
137
156
|
}
|
|
157
|
+
this.focusTarget.removeEventListener('focusin', this.onFocus, true);
|
|
138
158
|
window.removeEventListener('resize', this.onResize);
|
|
139
159
|
clearTimeout(this.timer);
|
|
140
160
|
clearTimeout(this.glideTimer);
|
|
@@ -230,6 +250,12 @@
|
|
|
230
250
|
this.gliding = false;
|
|
231
251
|
return;
|
|
232
252
|
}
|
|
253
|
+
// The browser bringing a focused field into view: it rests where the
|
|
254
|
+
// field is, wherever that falls between the stops.
|
|
255
|
+
if (this.revealing) {
|
|
256
|
+
this.revealing = false;
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
233
259
|
if (this.paused || api.paused) return;
|
|
234
260
|
|
|
235
261
|
var stops = this.measure();
|
|
@@ -285,7 +311,10 @@
|
|
|
285
311
|
clearTimeout(this.glideTimer);
|
|
286
312
|
|
|
287
313
|
// The first event after a rest starts a new gesture.
|
|
288
|
-
if (this.timer === null && !this.gliding)
|
|
314
|
+
if (this.timer === null && !this.gliding) {
|
|
315
|
+
this.start = this.last;
|
|
316
|
+
this.revealing = now() - this.focusedAt < REVEAL;
|
|
317
|
+
}
|
|
289
318
|
this.last = y;
|
|
290
319
|
|
|
291
320
|
// Which way the READER is going, not our own glide.
|
|
@@ -301,6 +330,10 @@
|
|
|
301
330
|
this.gliding = false;
|
|
302
331
|
};
|
|
303
332
|
|
|
333
|
+
Stops.prototype.onFocus = function () {
|
|
334
|
+
this.focusedAt = now();
|
|
335
|
+
};
|
|
336
|
+
|
|
304
337
|
Stops.prototype.onResize = function () {
|
|
305
338
|
this.refresh();
|
|
306
339
|
};
|