@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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/js/stops.js +34 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glitchr/stickyjs",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Sticky scroll library",
5
5
  "main": "src/index.js",
6
6
  "repository": {
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) this.start = this.last;
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
  };