uikit 3.11.1-dev.fbcf9eec9 → 3.11.2-dev.31cd2ba38

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 (62) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/css/uikit-core-rtl.css +1 -1
  3. package/dist/css/uikit-core-rtl.min.css +1 -1
  4. package/dist/css/uikit-core.css +1 -1
  5. package/dist/css/uikit-core.min.css +1 -1
  6. package/dist/css/uikit-rtl.css +1 -1
  7. package/dist/css/uikit-rtl.min.css +1 -1
  8. package/dist/css/uikit.css +1 -1
  9. package/dist/css/uikit.min.css +1 -1
  10. package/dist/js/components/countdown.js +1 -1
  11. package/dist/js/components/countdown.min.js +1 -1
  12. package/dist/js/components/filter.js +1 -1
  13. package/dist/js/components/filter.min.js +1 -1
  14. package/dist/js/components/lightbox-panel.js +1 -1
  15. package/dist/js/components/lightbox-panel.min.js +1 -1
  16. package/dist/js/components/lightbox.js +1 -1
  17. package/dist/js/components/lightbox.min.js +1 -1
  18. package/dist/js/components/notification.js +1 -1
  19. package/dist/js/components/notification.min.js +1 -1
  20. package/dist/js/components/parallax.js +37 -41
  21. package/dist/js/components/parallax.min.js +1 -1
  22. package/dist/js/components/slider-parallax.js +32 -25
  23. package/dist/js/components/slider-parallax.min.js +1 -1
  24. package/dist/js/components/slider.js +2 -2
  25. package/dist/js/components/slider.min.js +1 -1
  26. package/dist/js/components/slideshow-parallax.js +32 -25
  27. package/dist/js/components/slideshow-parallax.min.js +1 -1
  28. package/dist/js/components/slideshow.js +1 -1
  29. package/dist/js/components/slideshow.min.js +1 -1
  30. package/dist/js/components/sortable.js +2 -3
  31. package/dist/js/components/sortable.min.js +1 -1
  32. package/dist/js/components/tooltip.js +1 -1
  33. package/dist/js/components/tooltip.min.js +1 -1
  34. package/dist/js/components/upload.js +1 -1
  35. package/dist/js/components/upload.min.js +1 -1
  36. package/dist/js/uikit-core.js +224 -195
  37. package/dist/js/uikit-core.min.js +1 -1
  38. package/dist/js/uikit-icons.js +1 -1
  39. package/dist/js/uikit-icons.min.js +1 -1
  40. package/dist/js/uikit.js +287 -263
  41. package/dist/js/uikit.min.js +1 -1
  42. package/package.json +1 -1
  43. package/src/js/api/state.js +4 -4
  44. package/src/js/components/parallax.js +5 -16
  45. package/src/js/components/slider.js +1 -1
  46. package/src/js/components/sortable.js +1 -2
  47. package/src/js/core/core.js +2 -2
  48. package/src/js/core/drop.js +1 -1
  49. package/src/js/core/height-viewport.js +2 -2
  50. package/src/js/core/img.js +68 -92
  51. package/src/js/core/navbar.js +6 -2
  52. package/src/js/core/sticky.js +82 -50
  53. package/src/js/mixin/parallax.js +32 -21
  54. package/src/js/util/dimensions.js +28 -12
  55. package/src/js/util/fastdom.js +2 -2
  56. package/src/js/util/options.js +5 -5
  57. package/src/js/util/viewport.js +7 -3
  58. package/tests/image.html +22 -38
  59. package/tests/images/test.avif +0 -0
  60. package/tests/images/test.webp +0 -0
  61. package/tests/sticky-parallax.html +44 -41
  62. package/tests/sticky.html +56 -24
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "uikit",
3
3
  "title": "UIkit",
4
4
  "description": "UIkit is a lightweight and modular front-end framework for developing fast and powerful web interfaces.",
5
- "version": "3.11.1-dev.fbcf9eec9",
5
+ "version": "3.11.2-dev.31cd2ba38",
6
6
  "main": "dist/js/uikit.js",
7
7
  "style": "dist/css/uikit.css",
8
8
  "sideEffects": [
@@ -211,11 +211,11 @@ export default function (UIkit) {
211
211
  on(
212
212
  el,
213
213
  name,
214
- !delegate
215
- ? null
216
- : isString(delegate)
214
+ delegate
215
+ ? isString(delegate)
217
216
  ? delegate
218
- : delegate.call(component),
217
+ : delegate.call(component)
218
+ : null,
219
219
  isString(handler) ? component[handler] : handler.bind(component),
220
220
  {passive, capture, self}
221
221
  )
@@ -28,13 +28,15 @@ export default {
28
28
  },
29
29
 
30
30
  start({start}) {
31
- return parseCalc(start, this.target);
31
+ return toPx(start, 'height', this.target, true);
32
32
  },
33
33
 
34
34
  end({end, viewport}) {
35
- return parseCalc(
35
+ return toPx(
36
36
  end || (viewport = (1 - viewport) * 100) && `${viewport}vh+${viewport}%`,
37
- this.target
37
+ 'height',
38
+ this.target,
39
+ true
38
40
  );
39
41
  }
40
42
 
@@ -77,19 +79,6 @@ export default {
77
79
 
78
80
  };
79
81
 
80
- const calcRe = /-?\d+(?:\.\d+)?(?:v[wh]|%|px)?/g;
81
- function parseCalc(calc, el) {
82
- let match;
83
- let result = 0;
84
- calc = calc.toString().replace(/\s/g, '');
85
- calcRe.lastIndex = 0;
86
- while ((match = calcRe.exec(calc)) !== null) {
87
- result += toPx(match, 'height', el, true);
88
- }
89
-
90
- return result;
91
- }
92
-
93
82
  function ease(percent, easing) {
94
83
  return easing >= 0
95
84
  ? Math.pow(percent, easing + 1)
@@ -30,7 +30,7 @@ export default {
30
30
  },
31
31
 
32
32
  finite({finite}) {
33
- return finite || Math.ceil(getWidth(this.list)) < dimensions(this.list).width + getMaxElWidth(this.list) + this.center;
33
+ return finite || Math.ceil(getWidth(this.list)) < Math.floor(dimensions(this.list).width + getMaxElWidth(this.list) + this.center);
34
34
  },
35
35
 
36
36
  maxIndex() {
@@ -218,7 +218,6 @@ export default {
218
218
 
219
219
  off(document, pointerMove, this.move);
220
220
  off(document, pointerUp, this.end);
221
- off(window, 'scroll', this.scroll);
222
221
 
223
222
  if (!this.drag) {
224
223
  return;
@@ -295,7 +294,7 @@ function trackScroll(pos) {
295
294
  trackTimer = setInterval(() => {
296
295
 
297
296
  let {x, y} = pos;
298
- y += window.pageYOffset;
297
+ y += scrollTop(window);
299
298
 
300
299
  const dist = (Date.now() - last) * .3;
301
300
  last = Date.now();
@@ -13,7 +13,7 @@ export default function (UIkit) {
13
13
  return;
14
14
  }
15
15
  pendingResize = true;
16
- fastdom.write(() => pendingResize = false);
16
+ fastdom.read(() => pendingResize = false);
17
17
  UIkit.update(null, 'resize');
18
18
  };
19
19
 
@@ -32,7 +32,7 @@ export default function (UIkit) {
32
32
  return;
33
33
  }
34
34
  pending = true;
35
- fastdom.write(() => pending = false);
35
+ fastdom.read(() => pending = false);
36
36
 
37
37
  UIkit.update(null, e.type);
38
38
 
@@ -308,7 +308,7 @@ export default {
308
308
  if (active) {
309
309
 
310
310
  if (delay && active.isDelaying) {
311
- this.showTimer = setTimeout(this.show, 10);
311
+ this.showTimer = setTimeout(() => matches(target, ':hover') && this.show(), 10);
312
312
  return;
313
313
  }
314
314
 
@@ -1,5 +1,5 @@
1
1
  import FlexBug from '../mixin/flex-bug';
2
- import {boxModelAdjust, css, dimensions, endsWith, height, isNumeric, isString, isVisible, offset, query, toFloat} from 'uikit-util';
2
+ import {boxModelAdjust, css, dimensions, endsWith, height, isNumeric, isString, isVisible, offset, query, toFloat, trigger} from 'uikit-util';
3
3
 
4
4
  export default {
5
5
 
@@ -76,7 +76,7 @@ export default {
76
76
  css(this.$el, {minHeight});
77
77
 
78
78
  if (minHeight !== prev) {
79
- this.$update(this.$el, 'resize');
79
+ trigger(this.$el, 'resize');
80
80
  }
81
81
 
82
82
  if (this.minHeight && toFloat(css(this.$el, 'minHeight')) < this.minHeight) {
@@ -1,4 +1,4 @@
1
- import {createEvent, css, Dimensions, escape, getImage, includes, isUndefined, queryAll, startsWith, toFloat, toPx, trigger} from 'uikit-util';
1
+ import {append, attr, children, createEvent, css, data, escape, fragment, includes, isArray, isObject, isUndefined, parent, parseOptions, queryAll, startsWith, toFloat, toPx, trigger} from 'uikit-util';
2
2
 
3
3
  export default {
4
4
 
@@ -6,10 +6,7 @@ export default {
6
6
 
7
7
  props: {
8
8
  dataSrc: String,
9
- dataSrcset: Boolean,
10
- sizes: String,
11
- width: Number,
12
- height: Number,
9
+ dataSources: String,
13
10
  offsetTop: String,
14
11
  offsetLeft: String,
15
12
  target: String
@@ -17,10 +14,7 @@ export default {
17
14
 
18
15
  data: {
19
16
  dataSrc: '',
20
- dataSrcset: false,
21
- sizes: false,
22
- width: false,
23
- height: false,
17
+ dataSources: [],
24
18
  offsetTop: '50vh',
25
19
  offsetLeft: '50vw',
26
20
  target: false
@@ -28,26 +22,6 @@ export default {
28
22
 
29
23
  computed: {
30
24
 
31
- cacheKey({dataSrc}) {
32
- return `${this.$name}.${dataSrc}`;
33
- },
34
-
35
- width({width, dataWidth}) {
36
- return width || dataWidth;
37
- },
38
-
39
- height({height, dataHeight}) {
40
- return height || dataHeight;
41
- },
42
-
43
- sizes({sizes, dataSizes}) {
44
- return sizes || dataSizes;
45
- },
46
-
47
- isImg(_, $el) {
48
- return isImg($el);
49
- },
50
-
51
25
  target: {
52
26
 
53
27
  get({target}) {
@@ -58,14 +32,6 @@ export default {
58
32
  this.observe();
59
33
  }
60
34
 
61
- },
62
-
63
- offsetTop({offsetTop}) {
64
- return toPx(offsetTop, 'height');
65
- },
66
-
67
- offsetLeft({offsetLeft}) {
68
- return toPx(offsetLeft, 'width');
69
35
  }
70
36
 
71
37
  },
@@ -73,21 +39,13 @@ export default {
73
39
  connected() {
74
40
 
75
41
  if (!window.IntersectionObserver) {
76
- setSrcAttrs(this.$el, this.dataSrc, this.dataSrcset, this.sizes);
42
+ setSrcAttrs(this.$el, this.dataSrc);
77
43
  return;
78
44
  }
79
45
 
80
- if (storage[this.cacheKey]) {
81
- setSrcAttrs(this.$el, storage[this.cacheKey], this.dataSrcset, this.sizes);
82
- } else if (this.isImg && this.width && this.height) {
83
- setSrcAttrs(this.$el, getPlaceholderImage(this.width, this.height, this.sizes));
84
- }
85
-
86
- this.observer = new IntersectionObserver(this.load, {
87
- rootMargin: `${this.offsetTop}px ${this.offsetLeft}px`
88
- });
89
-
90
- requestAnimationFrame(this.observe);
46
+ const rootMargin = `${toPx(this.offsetTop, 'height')}px ${toPx(this.offsetLeft, 'width')}px`;
47
+ this.observer = new IntersectionObserver(this.load, {rootMargin});
48
+ this.observe();
91
49
 
92
50
  },
93
51
 
@@ -99,30 +57,23 @@ export default {
99
57
 
100
58
  read({image}) {
101
59
 
102
- if (!this.observer) {
103
- return false;
104
- }
105
-
106
- if (!image && document.readyState === 'complete') {
107
- this.load(this.observer.takeRecords());
108
- }
109
-
110
- if (this.isImg) {
60
+ if (!this.observer || isImg(this.$el)) {
111
61
  return false;
112
62
  }
113
63
 
114
- image && image.then(img => img && img.currentSrc !== '' && setSrcAttrs(this.$el, currentSrc(img)));
64
+ setSrcAttrs(this.$el, image && image.currentSrc);
115
65
 
116
66
  },
117
67
 
118
- write(data) {
68
+ write(store) {
119
69
 
120
- if (this.dataSrcset && window.devicePixelRatio !== 1) {
70
+ const srcset = data(this.$el, 'data-srcset');
71
+ if (srcset && window.devicePixelRatio !== 1) {
121
72
 
122
73
  const bgSize = css(this.$el, 'backgroundSize');
123
- if (bgSize.match(/^(auto\s?)+$/) || toFloat(bgSize) === data.bgSize) {
124
- data.bgSize = getSourceSize(this.dataSrcset, this.sizes);
125
- css(this.$el, 'backgroundSize', `${data.bgSize}px`);
74
+ if (bgSize.match(/^(auto\s?)+$/) || toFloat(bgSize) === store.bgSize) {
75
+ store.bgSize = getSourceSize(srcset, data(this.$el, 'sizes'));
76
+ css(this.$el, 'backgroundSize', `${store.bgSize}px`);
126
77
  }
127
78
 
128
79
  }
@@ -142,13 +93,16 @@ export default {
142
93
  return;
143
94
  }
144
95
 
145
- this._data.image = getImage(this.dataSrc, this.dataSrcset, this.sizes).then(img => {
96
+ if (this._data.image) {
97
+ return this._data.image;
98
+ }
146
99
 
147
- setSrcAttrs(this.$el, currentSrc(img), img.srcset, img.sizes);
148
- storage[this.cacheKey] = currentSrc(img);
149
- return img;
100
+ const image = isImg(this.$el)
101
+ ? this.$el
102
+ : getImageFromElement(this.$el, this.dataSrc, parseOptions(this.dataSources));
150
103
 
151
- }, e => trigger(this.$el, new e.constructor(e.type, e)));
104
+ this._data.image = image;
105
+ setSrcAttrs(this.$el, image.currentSrc || this.dataSrc);
152
106
 
153
107
  this.observer.disconnect();
154
108
  },
@@ -163,13 +117,15 @@ export default {
163
117
 
164
118
  };
165
119
 
166
- function setSrcAttrs(el, src, srcset, sizes) {
120
+ function setSrcAttrs(el, src) {
167
121
 
168
122
  if (isImg(el)) {
169
- const set = (prop, val) => val && val !== el[prop] && (el[prop] = val);
170
- set('sizes', sizes);
171
- set('srcset', srcset);
172
- set('src', src);
123
+
124
+ const parentNode = parent(el);
125
+ const elements = isPicture(parentNode) ? children(parentNode) : [el];
126
+ elements.forEach(el => setSourceProps(el, el));
127
+ src && attr(el, 'src', src);
128
+
173
129
  } else if (src) {
174
130
 
175
131
  const change = !includes(el.style.backgroundImage, src);
@@ -182,13 +138,41 @@ function setSrcAttrs(el, src, srcset, sizes) {
182
138
 
183
139
  }
184
140
 
185
- function getPlaceholderImage(width, height, sizes) {
141
+ const srcProps = ['data-src', 'data-srcset', 'sizes'];
142
+ function setSourceProps(sourceEl, targetEl) {
143
+ srcProps.forEach(prop => {
144
+ const value = data(sourceEl, prop);
145
+ if (value) {
146
+ attr(targetEl, prop.replace(/^(data-)+/, ''), value);
147
+ }
148
+ });
149
+ }
150
+
151
+ function getImageFromElement(el, src, sources = []) {
186
152
 
187
- if (sizes) {
188
- ({width, height} = Dimensions.ratio({width, height}, 'width', toPx(sizesToPixel(sizes))));
153
+ if (!src) {
154
+ return false;
189
155
  }
190
156
 
191
- return `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}"></svg>`;
157
+ const img = new Image();
158
+
159
+ if (!isArray(sources) && isObject(sources)) {
160
+ sources = [sources];
161
+ }
162
+
163
+ if (sources.length) {
164
+ const picture = fragment('<picture>');
165
+ sources.forEach(attrs => {
166
+ const source = fragment('<source>');
167
+ attr(source, attrs);
168
+ append(picture, source);
169
+ });
170
+ append(picture, img);
171
+ }
172
+
173
+ setSourceProps(el, img);
174
+ attr(img, 'src', src);
175
+ return img;
192
176
  }
193
177
 
194
178
  const sizesRe = /\s*(.*?)\s*(\w+|calc\(.*?\))\s*(?:,|$)/g;
@@ -228,22 +212,14 @@ function getSourceSize(srcset, sizes) {
228
212
  return descriptors.filter(size => size >= srcSize)[0] || descriptors.pop() || '';
229
213
  }
230
214
 
231
- function isImg(el) {
232
- return el.tagName === 'IMG';
215
+ function isPicture(el) {
216
+ return isA(el, 'PICTURE');
233
217
  }
234
218
 
235
- function currentSrc(el) {
236
- return el.currentSrc || el.src;
219
+ function isImg(el) {
220
+ return isA(el, 'IMG');
237
221
  }
238
222
 
239
- const key = '__test__';
240
- let storage;
241
-
242
- // workaround for Safari's private browsing mode and accessing sessionStorage in Blink
243
- try {
244
- storage = window.sessionStorage || {};
245
- storage[key] = 1;
246
- delete storage[key];
247
- } catch (e) {
248
- storage = {};
223
+ function isA(el, tagName) {
224
+ return el && el.tagName === tagName;
249
225
  }
@@ -137,7 +137,7 @@ export default {
137
137
 
138
138
  handler({current}) {
139
139
  const active = this.getActive();
140
- if (active && includes(active.mode, 'hover') && active.target && !within(active.target, current) && !active.tracker.movesTo(active.$el)) {
140
+ if (active && includes(active.mode, 'hover') && active.target && !within(active.target, current) && !active.isDelaying) {
141
141
  active.hide(false);
142
142
  }
143
143
  }
@@ -301,7 +301,11 @@ export default {
301
301
 
302
302
  const active = this.getActive();
303
303
 
304
- if (matches(this.dropbar, ':hover') && active && active.$el === $el) {
304
+ if (matches(this.dropbar, ':hover')
305
+ && active
306
+ && active.$el === $el
307
+ && !this.toggles.some(el => active.target !== el && matches(el, ':focus'))
308
+ ) {
305
309
  e.preventDefault();
306
310
  }
307
311
  }
@@ -1,12 +1,13 @@
1
1
  import Class from '../mixin/class';
2
2
  import Media from '../mixin/media';
3
- import {$, addClass, after, Animation, assign, css, dimensions, fastdom, height as getHeight, hasClass, isNumeric, isString, isVisible, noop, offset, offsetPosition, parent, query, remove, removeClass, replaceClass, scrollTop, toFloat, toggleClass, toPx, trigger, within} from 'uikit-util';
3
+ import {$, addClass, after, Animation, clamp, css, dimensions, fastdom, height as getHeight, getScrollingElement, hasClass, isNumeric, isString, isVisible, noop, offset, offsetPosition, parent, query, remove, removeClass, replaceClass, scrollTop, toggleClass, toPx, trigger, within} from 'uikit-util';
4
4
 
5
5
  export default {
6
6
 
7
7
  mixins: [Class, Media],
8
8
 
9
9
  props: {
10
+ position: String,
10
11
  top: null,
11
12
  bottom: Boolean,
12
13
  offset: String,
@@ -22,6 +23,7 @@ export default {
22
23
  },
23
24
 
24
25
  data: {
26
+ position: 'top',
25
27
  top: 0,
26
28
  bottom: false,
27
29
  offset: 0,
@@ -38,8 +40,19 @@ export default {
38
40
 
39
41
  computed: {
40
42
 
41
- offset({offset}) {
42
- return toPx(offset);
43
+ position({position}, $el) {
44
+ return position === 'auto'
45
+ ? (this.isFixed ? this.placeholder : $el).offsetHeight > getHeight(window)
46
+ ? 'bottom'
47
+ : 'top'
48
+ : position;
49
+ },
50
+
51
+ offset({offset}, $el) {
52
+ if (this.position === 'bottom') {
53
+ offset += '+100vh-100%';
54
+ }
55
+ return toPx(offset, 'height', $el);
43
56
  },
44
57
 
45
58
  selTarget({selTarget}, $el) {
@@ -100,7 +113,7 @@ export default {
100
113
 
101
114
  handler() {
102
115
 
103
- if (!(this.targetOffset !== false && location.hash && window.pageYOffset > 0)) {
116
+ if (!(this.targetOffset !== false && location.hash && scrollTop(window) > 0)) {
104
117
  return;
105
118
  }
106
119
 
@@ -130,7 +143,7 @@ export default {
130
143
 
131
144
  {
132
145
 
133
- read({height}, types) {
146
+ read({height, margin}, types) {
134
147
 
135
148
  this.inactive = !this.matchMedia || !isVisible(this.$el);
136
149
 
@@ -138,42 +151,52 @@ export default {
138
151
  return false;
139
152
  }
140
153
 
141
- if (this.isActive && types.has('resize')) {
154
+ const hide = this.isActive && types.has('resize');
155
+ if (hide) {
142
156
  this.hide();
143
- height = this.$el.offsetHeight;
144
- this.show();
145
157
  }
146
158
 
147
- height = this.isActive ? height : this.$el.offsetHeight;
159
+ if (!this.isActive) {
160
+ height = this.$el.offsetHeight;
161
+ margin = css(this.$el, 'margin');
162
+ }
148
163
 
149
- if (height + this.offset > getHeight(window)) {
150
- this.inactive = true;
151
- return false;
164
+ if (hide) {
165
+ this.show();
152
166
  }
153
167
 
168
+ const overflow = Math.max(0, height + this.offset - getHeight(window));
169
+
154
170
  const referenceElement = this.isFixed ? this.placeholder : this.$el;
155
- this.topOffset = offset(referenceElement).top;
156
- this.bottomOffset = this.topOffset + height;
157
- this.offsetParentTop = offset(referenceElement.offsetParent).top;
171
+ const topOffset = offset(referenceElement).top;
172
+ const offsetParentTop = offset(referenceElement.offsetParent).top;
158
173
 
159
- const bottom = parseProp('bottom', this);
174
+ const top = parseProp(this.top, this.$el, topOffset);
175
+ const bottom = parseProp(this.bottom, this.$el, topOffset + height);
160
176
 
161
- this.top = Math.max(toFloat(parseProp('top', this)), this.topOffset) - this.offset;
162
- this.bottom = bottom && bottom - this.$el.offsetHeight;
163
- this.width = dimensions(isVisible(this.widthElement) ? this.widthElement : this.$el).width;
177
+ const start = Math.max(top, topOffset) - this.offset;
178
+ const end = bottom
179
+ ? bottom - this.$el.offsetHeight + overflow - this.offset
180
+ : getScrollingElement(this.$el).scrollHeight - getHeight(window);
164
181
 
165
182
  return {
183
+ start,
184
+ end,
185
+ overflow,
186
+ topOffset,
187
+ offsetParentTop,
166
188
  height,
167
- top: offsetPosition(this.placeholder)[0],
168
- margins: css(this.$el, ['marginTop', 'marginBottom', 'marginLeft', 'marginRight'])
189
+ margin,
190
+ width: dimensions(isVisible(this.widthElement) ? this.widthElement : this.$el).width,
191
+ top: offsetPosition(this.placeholder)[0]
169
192
  };
170
193
  },
171
194
 
172
- write({height, margins}) {
195
+ write({height, margin}) {
173
196
 
174
197
  const {placeholder} = this;
175
198
 
176
- css(placeholder, assign({height}, margins));
199
+ css(placeholder, {height, margin});
177
200
 
178
201
  if (!within(placeholder, document)) {
179
202
  after(this.$el, placeholder);
@@ -190,42 +213,48 @@ export default {
190
213
 
191
214
  {
192
215
 
193
- read({scroll = 0}) {
216
+ read({scroll: prevScroll = 0, dir: prevDir = 'down', overflow, overflowScroll = 0, start, end}) {
194
217
 
195
- this.scroll = window.pageYOffset;
218
+ const scroll = scrollTop(window);
219
+ const dir = prevScroll <= scroll ? 'down' : 'up';
196
220
 
197
221
  return {
198
- dir: scroll <= this.scroll ? 'down' : 'up',
199
- scroll: this.scroll
222
+ dir,
223
+ prevDir,
224
+ scroll,
225
+ prevScroll,
226
+ overflowScroll: clamp(
227
+ overflowScroll
228
+ + clamp(scroll, start, end)
229
+ - clamp(prevScroll, start, end),
230
+ 0,
231
+ overflow
232
+ )
200
233
  };
201
234
  },
202
235
 
203
236
  write(data, types) {
204
237
 
205
- const now = Date.now();
206
238
  const isScrollUpdate = types.has('scroll');
207
- const {initTimestamp = 0, dir, lastDir, lastScroll, scroll, top} = data;
239
+ const {initTimestamp = 0, dir, prevDir, scroll, prevScroll = 0, top, start, topOffset, height} = data;
208
240
 
209
- data.lastScroll = scroll;
210
-
211
- if (scroll < 0 || scroll === lastScroll && isScrollUpdate || this.showOnUp && !isScrollUpdate && !this.isFixed) {
241
+ if (scroll < 0 || scroll === prevScroll && isScrollUpdate || this.showOnUp && !isScrollUpdate && !this.isFixed) {
212
242
  return;
213
243
  }
214
244
 
215
- if (now - initTimestamp > 300 || dir !== lastDir) {
245
+ const now = Date.now();
246
+ if (now - initTimestamp > 300 || dir !== prevDir) {
216
247
  data.initScroll = scroll;
217
248
  data.initTimestamp = now;
218
249
  }
219
250
 
220
- data.lastDir = dir;
221
-
222
- if (this.showOnUp && !this.isFixed && Math.abs(data.initScroll - scroll) <= 30 && Math.abs(lastScroll - scroll) <= 10) {
251
+ if (this.showOnUp && !this.isFixed && Math.abs(data.initScroll - scroll) <= 30 && Math.abs(prevScroll - scroll) <= 10) {
223
252
  return;
224
253
  }
225
254
 
226
255
  if (this.inactive
227
- || scroll < this.top
228
- || this.showOnUp && (scroll <= this.top || dir === 'down' && isScrollUpdate || dir === 'up' && !this.isFixed && scroll <= this.bottomOffset)
256
+ || scroll < start
257
+ || this.showOnUp && (scroll <= start || dir === 'down' && isScrollUpdate || dir === 'up' && !this.isFixed && scroll <= topOffset + height)
229
258
  ) {
230
259
 
231
260
  if (!this.isFixed) {
@@ -240,7 +269,7 @@ export default {
240
269
 
241
270
  this.isFixed = false;
242
271
 
243
- if (this.animation && scroll > this.topOffset) {
272
+ if (this.animation && scroll > topOffset) {
244
273
  Animation.cancel(this.$el);
245
274
  Animation.out(this.$el, this.animation).then(() => this.hide(), noop);
246
275
  } else {
@@ -290,23 +319,28 @@ export default {
290
319
 
291
320
  update() {
292
321
 
293
- const active = this.top !== 0 || this.scroll > this.top;
294
- let top = Math.max(0, this.offset);
322
+ const {width, scroll = 0, overflow, overflowScroll = 0, start, end, topOffset, height, offsetParentTop} = this._data;
323
+ const active = start !== 0 || scroll > start;
324
+ let top = this.offset;
295
325
  let position = 'fixed';
296
326
 
297
- if (isNumeric(this.bottom) && this.scroll > this.bottom - this.offset) {
298
- top = this.bottom - this.offsetParentTop;
327
+ if (scroll > end) {
328
+ top = end + this.offset - offsetParentTop;
299
329
  position = 'absolute';
300
330
  }
301
331
 
332
+ if (overflow) {
333
+ top -= overflowScroll;
334
+ }
335
+
302
336
  css(this.$el, {
303
337
  position,
304
338
  top: `${top}px`,
305
- width: this.width
339
+ width
306
340
  });
307
341
 
308
342
  this.isActive = active;
309
- toggleClass(this.$el, this.clsBelow, this.scroll > this.bottomOffset);
343
+ toggleClass(this.$el, this.clsBelow, scroll > topOffset + height);
310
344
  addClass(this.$el, this.clsFixed);
311
345
 
312
346
  }
@@ -315,12 +349,10 @@ export default {
315
349
 
316
350
  };
317
351
 
318
- function parseProp(prop, {$props, $el, [`${prop}Offset`]: propOffset}) {
319
-
320
- const value = $props[prop];
352
+ function parseProp(value, el, propOffset) {
321
353
 
322
354
  if (!value) {
323
- return;
355
+ return 0;
324
356
  }
325
357
 
326
358
  if (isString(value) && value.match(/^-?\d/)) {
@@ -329,7 +361,7 @@ function parseProp(prop, {$props, $el, [`${prop}Offset`]: propOffset}) {
329
361
 
330
362
  } else {
331
363
 
332
- return offset(value === true ? parent($el) : query(value, $el)).bottom;
364
+ return offset(value === true ? parent(el) : query(value, el)).bottom;
333
365
 
334
366
  }
335
367
  }