uikit 3.11.2-dev.21a5b7139 → 3.11.2-dev.29f2881ed

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 (146) hide show
  1. package/CHANGELOG.md +36 -19
  2. package/dist/css/uikit-core-rtl.css +86 -185
  3. package/dist/css/uikit-core-rtl.min.css +1 -1
  4. package/dist/css/uikit-core.css +86 -185
  5. package/dist/css/uikit-core.min.css +1 -1
  6. package/dist/css/uikit-rtl.css +88 -191
  7. package/dist/css/uikit-rtl.min.css +1 -1
  8. package/dist/css/uikit.css +88 -191
  9. package/dist/css/uikit.min.css +1 -1
  10. package/dist/js/components/countdown.js +3 -3
  11. package/dist/js/components/countdown.min.js +1 -1
  12. package/dist/js/components/filter.js +10 -14
  13. package/dist/js/components/filter.min.js +1 -1
  14. package/dist/js/components/lightbox-panel.js +31 -60
  15. package/dist/js/components/lightbox-panel.min.js +1 -1
  16. package/dist/js/components/lightbox.js +34 -64
  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 +110 -72
  21. package/dist/js/components/parallax.min.js +1 -1
  22. package/dist/js/components/slider-parallax.js +110 -72
  23. package/dist/js/components/slider-parallax.min.js +1 -1
  24. package/dist/js/components/slider.js +75 -28
  25. package/dist/js/components/slider.min.js +1 -1
  26. package/dist/js/components/slideshow-parallax.js +110 -72
  27. package/dist/js/components/slideshow-parallax.min.js +1 -1
  28. package/dist/js/components/slideshow.js +57 -21
  29. package/dist/js/components/slideshow.min.js +1 -1
  30. package/dist/js/components/sortable.js +16 -20
  31. package/dist/js/components/sortable.min.js +1 -1
  32. package/dist/js/components/tooltip.js +2 -2
  33. package/dist/js/components/tooltip.min.js +1 -1
  34. package/dist/js/components/upload.js +10 -14
  35. package/dist/js/components/upload.min.js +1 -1
  36. package/dist/js/uikit-core.js +340 -337
  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 +584 -518
  41. package/dist/js/uikit.min.js +1 -1
  42. package/package.json +1 -1
  43. package/src/js/api/component.js +2 -11
  44. package/src/js/api/hooks.js +1 -1
  45. package/src/js/api/state.js +3 -3
  46. package/src/js/components/countdown.js +2 -2
  47. package/src/js/components/filter.js +2 -3
  48. package/src/js/components/internal/lightbox-animations.js +4 -3
  49. package/src/js/components/internal/slider-preload.js +37 -0
  50. package/src/js/components/internal/slider-transitioner.js +2 -2
  51. package/src/js/components/internal/slideshow-animations.js +4 -3
  52. package/src/js/components/lightbox-panel.js +34 -58
  53. package/src/js/components/lightbox.js +3 -4
  54. package/src/js/components/slider.js +30 -11
  55. package/src/js/components/slideshow.js +8 -1
  56. package/src/js/components/sortable.js +8 -8
  57. package/src/js/components/upload.js +9 -13
  58. package/src/js/core/accordion.js +3 -3
  59. package/src/js/core/alert.js +1 -2
  60. package/src/js/core/height-match.js +3 -3
  61. package/src/js/core/icon.js +13 -6
  62. package/src/js/core/img.js +134 -115
  63. package/src/js/core/margin.js +11 -13
  64. package/src/js/core/modal.js +1 -2
  65. package/src/js/core/navbar.js +5 -5
  66. package/src/js/core/scrollspy.js +6 -6
  67. package/src/js/core/sticky.js +34 -35
  68. package/src/js/core/svg.js +10 -6
  69. package/src/js/core/toggle.js +4 -3
  70. package/src/js/mixin/internal/animate-slide.js +9 -12
  71. package/src/js/mixin/parallax.js +110 -72
  72. package/src/js/mixin/slider-drag.js +3 -3
  73. package/src/js/mixin/slider-nav.js +2 -2
  74. package/src/js/mixin/slider.js +8 -16
  75. package/src/js/mixin/slideshow.js +2 -2
  76. package/src/js/mixin/togglable.js +1 -2
  77. package/src/js/util/ajax.js +15 -14
  78. package/src/js/util/animation.js +7 -12
  79. package/src/js/util/attr.js +14 -12
  80. package/src/js/util/dimensions.js +4 -4
  81. package/src/js/util/dom.js +23 -32
  82. package/src/js/util/lang.js +7 -6
  83. package/src/js/util/options.js +2 -11
  84. package/src/js/util/player.js +5 -4
  85. package/src/js/util/position.js +2 -2
  86. package/src/js/util/selector.js +12 -18
  87. package/src/js/util/style.js +4 -4
  88. package/src/less/components/base.less +10 -33
  89. package/src/less/components/form-range.less +48 -95
  90. package/src/less/components/form.less +0 -1
  91. package/src/less/components/height.less +3 -0
  92. package/src/less/components/leader.less +0 -1
  93. package/src/less/components/lightbox.less +0 -1
  94. package/src/less/components/modal.less +3 -7
  95. package/src/less/components/progress.less +14 -36
  96. package/src/less/components/slider.less +0 -3
  97. package/src/less/components/slideshow.less +0 -3
  98. package/src/less/components/text.less +16 -32
  99. package/src/scss/components/base.scss +10 -33
  100. package/src/scss/components/form-range.scss +48 -95
  101. package/src/scss/components/form.scss +0 -1
  102. package/src/scss/components/height.scss +3 -0
  103. package/src/scss/components/leader.scss +0 -1
  104. package/src/scss/components/lightbox.scss +0 -1
  105. package/src/scss/components/modal.scss +3 -7
  106. package/src/scss/components/progress.scss +14 -36
  107. package/src/scss/components/slider.scss +0 -3
  108. package/src/scss/components/slideshow.scss +0 -3
  109. package/src/scss/components/text.scss +16 -32
  110. package/src/scss/mixins-theme.scss +1 -1
  111. package/src/scss/mixins.scss +1 -1
  112. package/src/scss/variables-theme.scss +3 -3
  113. package/src/scss/variables.scss +3 -3
  114. package/tests/align.html +10 -10
  115. package/tests/animation.html +2 -2
  116. package/tests/article.html +2 -2
  117. package/tests/base.html +3 -3
  118. package/tests/card.html +10 -10
  119. package/tests/column.html +3 -3
  120. package/tests/comment.html +9 -9
  121. package/tests/dotnav.html +3 -3
  122. package/tests/image.html +296 -64
  123. package/tests/images/image-type.avif +0 -0
  124. package/tests/images/image-type.jpeg +0 -0
  125. package/tests/images/image-type.webp +0 -0
  126. package/tests/index.html +8 -8
  127. package/tests/lightbox.html +10 -10
  128. package/tests/marker.html +2 -2
  129. package/tests/modal.html +8 -9
  130. package/tests/navbar.html +2 -2
  131. package/tests/overlay.html +7 -7
  132. package/tests/parallax.html +14 -5
  133. package/tests/position.html +12 -12
  134. package/tests/slidenav.html +12 -12
  135. package/tests/slider.html +20 -20
  136. package/tests/sortable.html +1 -1
  137. package/tests/sticky-parallax.html +55 -70
  138. package/tests/svg.html +6 -6
  139. package/tests/table.html +11 -11
  140. package/tests/thumbnav.html +12 -12
  141. package/tests/transition.html +30 -30
  142. package/tests/utility.html +33 -33
  143. package/tests/video.html +1 -1
  144. package/tests/width.html +1 -1
  145. package/src/js/util/promise.js +0 -0
  146. package/tests/images/animated.gif +0 -0
@@ -1,64 +1,52 @@
1
1
  import {
2
+ append,
3
+ attr,
4
+ children,
2
5
  createEvent,
3
6
  css,
4
- Dimensions,
7
+ data,
5
8
  escape,
6
- getImage,
9
+ fragment,
10
+ hasAttr,
7
11
  includes,
8
- isUndefined,
12
+ isArray,
13
+ isEmpty,
14
+ isTag,
15
+ parent,
16
+ parseOptions,
9
17
  queryAll,
18
+ removeAttr,
10
19
  startsWith,
11
20
  toFloat,
12
21
  toPx,
13
22
  trigger,
14
23
  } from 'uikit-util';
15
24
 
25
+ const nativeLazyLoad = 'loading' in HTMLImageElement.prototype;
26
+ const nativeIsIntersecting = 'isIntersecting' in IntersectionObserverEntry.prototype; // Old chromium based browsers (UC Browser) did not implement `isIntersecting`
27
+
16
28
  export default {
17
29
  args: 'dataSrc',
18
30
 
19
31
  props: {
20
32
  dataSrc: String,
21
- dataSrcset: Boolean,
22
- sizes: String,
23
- width: Number,
24
- height: Number,
33
+ sources: String,
25
34
  offsetTop: String,
26
35
  offsetLeft: String,
27
36
  target: String,
37
+ loading: String,
28
38
  },
29
39
 
30
40
  data: {
31
41
  dataSrc: '',
32
- dataSrcset: false,
33
- sizes: false,
34
- width: false,
35
- height: false,
42
+ sources: false,
36
43
  offsetTop: '50vh',
37
44
  offsetLeft: '50vw',
38
45
  target: false,
46
+ loading: 'lazy',
39
47
  },
40
48
 
41
49
  computed: {
42
- cacheKey({ dataSrc }) {
43
- return `${this.$name}.${dataSrc}`;
44
- },
45
-
46
- width({ width, dataWidth }) {
47
- return width || dataWidth;
48
- },
49
-
50
- height({ height, dataHeight }) {
51
- return height || dataHeight;
52
- },
53
-
54
- sizes({ sizes, dataSizes }) {
55
- return sizes || dataSizes;
56
- },
57
-
58
- isImg(_, $el) {
59
- return isImg($el);
60
- },
61
-
62
50
  target: {
63
51
  get({ target }) {
64
52
  return [this.$el, ...queryAll(target, this.$el)];
@@ -68,65 +56,61 @@ export default {
68
56
  this.observe();
69
57
  },
70
58
  },
71
-
72
- offsetTop({ offsetTop }) {
73
- return toPx(offsetTop, 'height');
74
- },
75
-
76
- offsetLeft({ offsetLeft }) {
77
- return toPx(offsetLeft, 'width');
78
- },
79
59
  },
80
60
 
81
61
  connected() {
82
- if (!window.IntersectionObserver) {
83
- setSrcAttrs(this.$el, this.dataSrc, this.dataSrcset, this.sizes);
62
+ if (this.loading !== 'lazy' || !window.IntersectionObserver || !nativeIsIntersecting) {
63
+ this.load();
84
64
  return;
85
65
  }
86
66
 
87
- if (storage[this.cacheKey]) {
88
- setSrcAttrs(this.$el, storage[this.cacheKey], this.dataSrcset, this.sizes);
89
- } else if (this.isImg && this.width && this.height) {
90
- setSrcAttrs(this.$el, getPlaceholderImage(this.width, this.height, this.sizes));
91
- }
67
+ if (nativeLazyLoad && isImg(this.$el)) {
68
+ this.$el.loading = 'lazy';
69
+ setSrcAttrs(this.$el);
92
70
 
93
- this.observer = new IntersectionObserver(this.load, {
94
- rootMargin: `${this.offsetTop}px ${this.offsetLeft}px`,
95
- });
71
+ if (this.target.length === 1) {
72
+ return;
73
+ }
74
+ }
96
75
 
97
- requestAnimationFrame(this.observe);
76
+ ensureSrcAttribute(this.$el);
77
+
78
+ const rootMargin = `${toPx(this.offsetTop, 'height')}px ${toPx(
79
+ this.offsetLeft,
80
+ 'width'
81
+ )}px`;
82
+ this.observer = new IntersectionObserver(
83
+ (entries) => {
84
+ if (entries.some((entry) => entry.isIntersecting)) {
85
+ this.load();
86
+ this.observer.disconnect();
87
+ }
88
+ },
89
+ { rootMargin }
90
+ );
91
+ this.observe();
98
92
  },
99
93
 
100
94
  disconnected() {
101
- this.observer && this.observer.disconnect();
95
+ if (this._data.image) {
96
+ this._data.image.onload = '';
97
+ }
98
+
99
+ this.observer?.disconnect();
102
100
  },
103
101
 
104
102
  update: {
105
- read({ image }) {
106
- if (!this.observer) {
107
- return false;
108
- }
109
-
110
- if (!image && document.readyState === 'complete') {
111
- this.load(this.observer.takeRecords());
112
- }
113
-
114
- if (this.isImg) {
103
+ write(store) {
104
+ if (!this.observer || isImg(this.$el)) {
115
105
  return false;
116
106
  }
117
107
 
118
- image &&
119
- image.then(
120
- (img) => img && img.currentSrc !== '' && setSrcAttrs(this.$el, currentSrc(img))
121
- );
122
- },
123
-
124
- write(data) {
125
- if (this.dataSrcset && window.devicePixelRatio !== 1) {
108
+ const srcset = data(this.$el, 'data-srcset');
109
+ if (srcset && window.devicePixelRatio !== 1) {
126
110
  const bgSize = css(this.$el, 'backgroundSize');
127
- if (bgSize.match(/^(auto\s?)+$/) || toFloat(bgSize) === data.bgSize) {
128
- data.bgSize = getSourceSize(this.dataSrcset, this.sizes);
129
- css(this.$el, 'backgroundSize', `${data.bgSize}px`);
111
+ if (bgSize.match(/^(auto\s?)+$/) || toFloat(bgSize) === store.bgSize) {
112
+ store.bgSize = getSourceSize(srcset, data(this.$el, 'sizes'));
113
+ css(this.$el, 'backgroundSize', `${store.bgSize}px`);
130
114
  }
131
115
  }
132
116
  },
@@ -135,40 +119,35 @@ export default {
135
119
  },
136
120
 
137
121
  methods: {
138
- load(entries) {
139
- // Old chromium based browsers (UC Browser) did not implement `isIntersecting`
140
- if (
141
- !entries.some((entry) => isUndefined(entry.isIntersecting) || entry.isIntersecting)
142
- ) {
143
- return;
122
+ load() {
123
+ if (this._data.image) {
124
+ return this._data.image;
144
125
  }
145
126
 
146
- this._data.image = getImage(this.dataSrc, this.dataSrcset, this.sizes).then(
147
- (img) => {
148
- setSrcAttrs(this.$el, currentSrc(img), img.srcset, img.sizes);
149
- storage[this.cacheKey] = currentSrc(img);
150
- return img;
151
- },
152
- (e) => trigger(this.$el, new e.constructor(e.type, e))
153
- );
127
+ const image = isImg(this.$el)
128
+ ? this.$el
129
+ : getImageFromElement(this.$el, this.dataSrc, this.sources);
154
130
 
155
- this.observer.disconnect();
131
+ removeAttr(image, 'loading');
132
+ setSrcAttrs(this.$el, image.currentSrc);
133
+ return (this._data.image = image);
156
134
  },
157
135
 
158
136
  observe() {
159
137
  if (this._connected && !this._data.image) {
160
- this.target.forEach((el) => this.observer.observe(el));
138
+ for (const el of this.target) {
139
+ this.observer.observe(el);
140
+ }
161
141
  }
162
142
  },
163
143
  },
164
144
  };
165
145
 
166
- function setSrcAttrs(el, src, srcset, sizes) {
146
+ function setSrcAttrs(el, src) {
167
147
  if (isImg(el)) {
168
- const set = (prop, val) => val && val !== el[prop] && (el[prop] = val);
169
- set('sizes', sizes);
170
- set('srcset', srcset);
171
- set('src', src);
148
+ const parentNode = parent(el);
149
+ const elements = isPicture(parentNode) ? children(parentNode) : [el];
150
+ elements.forEach((el) => setSourceProps(el, el));
172
151
  } else if (src) {
173
152
  const change = !includes(el.style.backgroundImage, src);
174
153
  if (change) {
@@ -178,16 +157,62 @@ function setSrcAttrs(el, src, srcset, sizes) {
178
157
  }
179
158
  }
180
159
 
181
- function getPlaceholderImage(width, height, sizes) {
182
- if (sizes) {
183
- ({ width, height } = Dimensions.ratio(
184
- { width, height },
185
- 'width',
186
- toPx(sizesToPixel(sizes))
187
- ));
160
+ const srcProps = ['data-src', 'data-srcset', 'sizes'];
161
+ function setSourceProps(sourceEl, targetEl) {
162
+ srcProps.forEach((prop) => {
163
+ const value = data(sourceEl, prop);
164
+ if (value) {
165
+ attr(targetEl, prop.replace(/^(data-)+/, ''), value);
166
+ }
167
+ });
168
+ }
169
+
170
+ function getImageFromElement(el, src, sources) {
171
+ const img = new Image();
172
+
173
+ wrapInPicture(img, sources);
174
+ setSourceProps(el, img);
175
+ img.onload = () => {
176
+ setSrcAttrs(el, img.currentSrc);
177
+ };
178
+ attr(img, 'src', src);
179
+ return img;
180
+ }
181
+
182
+ function wrapInPicture(img, sources) {
183
+ sources = parseSources(sources);
184
+
185
+ if (sources.length) {
186
+ const picture = fragment('<picture>');
187
+ for (const attrs of sources) {
188
+ const source = fragment('<source>');
189
+ attr(source, attrs);
190
+ append(picture, source);
191
+ }
192
+ append(picture, img);
193
+ }
194
+ }
195
+
196
+ function parseSources(sources) {
197
+ if (!sources) {
198
+ return [];
199
+ }
200
+
201
+ if (startsWith(sources, '[')) {
202
+ try {
203
+ sources = JSON.parse(sources);
204
+ } catch (e) {
205
+ sources = [];
206
+ }
207
+ } else {
208
+ sources = parseOptions(sources);
188
209
  }
189
210
 
190
- return `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}"></svg>`;
211
+ if (!isArray(sources)) {
212
+ sources = [sources];
213
+ }
214
+
215
+ return sources.filter((source) => !isEmpty(source));
191
216
  }
192
217
 
193
218
  const sizesRe = /\s*(.*?)\s*(\w+|calc\(.*?\))\s*(?:,|$)/g;
@@ -227,22 +252,16 @@ function getSourceSize(srcset, sizes) {
227
252
  return descriptors.filter((size) => size >= srcSize)[0] || descriptors.pop() || '';
228
253
  }
229
254
 
230
- function isImg(el) {
231
- return el.tagName === 'IMG';
255
+ function ensureSrcAttribute(el) {
256
+ if (isImg(el) && !hasAttr(el, 'src')) {
257
+ attr(el, 'src', 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"></svg>');
258
+ }
232
259
  }
233
260
 
234
- function currentSrc(el) {
235
- return el.currentSrc || el.src;
261
+ function isPicture(el) {
262
+ return isTag(el, 'picture');
236
263
  }
237
264
 
238
- const key = '__test__';
239
- let storage;
240
-
241
- // workaround for Safari's private browsing mode and accessing sessionStorage in Blink
242
- try {
243
- storage = window.sessionStorage || {};
244
- storage[key] = 1;
245
- delete storage[key];
246
- } catch (e) {
247
- storage = {};
265
+ function isImg(el) {
266
+ return isTag(el, 'img');
248
267
  }
@@ -22,10 +22,10 @@ export default {
22
22
  },
23
23
 
24
24
  write({ columns, rows }) {
25
- for (let i = 0; i < rows.length; i++) {
26
- for (let j = 0; j < rows[i].length; j++) {
27
- toggleClass(rows[i][j], this.margin, i !== 0);
28
- toggleClass(rows[i][j], this.firstColumn, !!~columns[0].indexOf(rows[i][j]));
25
+ for (const row of rows) {
26
+ for (const column of row) {
27
+ toggleClass(column, this.margin, rows[0] !== row);
28
+ toggleClass(column, this.firstColumn, !!~columns[0].indexOf(column));
29
29
  }
30
30
  }
31
31
  },
@@ -41,10 +41,10 @@ export function getRows(items) {
41
41
  function getColumns(rows) {
42
42
  const columns = [];
43
43
 
44
- for (let i = 0; i < rows.length; i++) {
45
- const sorted = sortBy(rows[i], 'left', 'right');
44
+ for (const row of rows) {
45
+ const sorted = sortBy(row, 'left', 'right');
46
46
  for (let j = 0; j < sorted.length; j++) {
47
- columns[j] = !columns[j] ? sorted[j] : columns[j].concat(sorted[j]);
47
+ columns[j] = columns[j] ? columns[j].concat(sorted[j]) : sorted[j];
48
48
  }
49
49
  }
50
50
 
@@ -54,17 +54,15 @@ function getColumns(rows) {
54
54
  function sortBy(items, startProp, endProp) {
55
55
  const sorted = [[]];
56
56
 
57
- for (let i = 0; i < items.length; i++) {
58
- const el = items[i];
59
-
57
+ for (const el of items) {
60
58
  if (!isVisible(el)) {
61
59
  continue;
62
60
  }
63
61
 
64
62
  let dim = getOffset(el);
65
63
 
66
- for (let j = sorted.length - 1; j >= 0; j--) {
67
- const current = sorted[j];
64
+ for (let i = sorted.length - 1; i >= 0; i--) {
65
+ const current = sorted[i];
68
66
 
69
67
  if (!current[0]) {
70
68
  current.push(el);
@@ -89,7 +87,7 @@ function sortBy(items, startProp, endProp) {
89
87
  break;
90
88
  }
91
89
 
92
- if (j === 0) {
90
+ if (i === 0) {
93
91
  sorted.unshift([el]);
94
92
  break;
95
93
  }
@@ -2,7 +2,6 @@ import Modal from '../mixin/modal';
2
2
  import {
3
3
  $,
4
4
  addClass,
5
- assign,
6
5
  css,
7
6
  Deferred,
8
7
  hasClass,
@@ -136,7 +135,7 @@ function install({ modal }) {
136
135
  };
137
136
 
138
137
  function openDialog(tmpl, options, hideFn, submitFn) {
139
- options = assign({ bgClose: false, escClose: true, labels: modal.labels }, options);
138
+ options = { bgClose: false, escClose: true, labels: modal.labels, ...options };
140
139
 
141
140
  const dialog = modal.dialog(tmpl(options), options);
142
141
  const deferred = new Deferred();
@@ -6,7 +6,6 @@ import {
6
6
  $$,
7
7
  addClass,
8
8
  after,
9
- assign,
10
9
  css,
11
10
  findIndex,
12
11
  hasAttr,
@@ -111,12 +110,12 @@ export default {
111
110
  const dropdowns = $$(`.${clsDrop}`, $el);
112
111
 
113
112
  if (this.dropContainer !== $el) {
114
- $$(`.${clsDrop}`, this.dropContainer).forEach((el) => {
113
+ for (const el of $$(`.${clsDrop}`, this.dropContainer)) {
115
114
  const target = this.getDropdown(el)?.target;
116
115
  if (!includes(dropdowns, el) && target && within(target, this.$el)) {
117
116
  dropdowns.push(el);
118
117
  }
119
- });
118
+ }
120
119
  }
121
120
 
122
121
  return dropdowns;
@@ -126,11 +125,12 @@ export default {
126
125
  this.$create(
127
126
  'drop',
128
127
  dropdowns.filter((el) => !this.getDropdown(el)),
129
- assign({}, this.$props, {
128
+ {
129
+ ...this.$props,
130
130
  boundary: this.boundary,
131
131
  pos: this.pos,
132
132
  offset: this.dropbar || this.offset,
133
- })
133
+ }
134
134
  );
135
135
  },
136
136
 
@@ -53,10 +53,10 @@ export default {
53
53
  },
54
54
 
55
55
  disconnected() {
56
- this.elements.forEach((el) => {
56
+ for (const el of this.elements) {
57
57
  removeClass(el, this.inViewClass, el[stateKey] ? el[stateKey].cls : '');
58
58
  delete el[stateKey];
59
- });
59
+ }
60
60
  },
61
61
 
62
62
  update: [
@@ -71,17 +71,17 @@ export default {
71
71
  return false;
72
72
  }
73
73
 
74
- this.elements.forEach((el) => {
74
+ for (const el of this.elements) {
75
75
  if (!el[stateKey]) {
76
76
  el[stateKey] = { cls: getData(el, 'uk-scrollspy-class') || this.cls };
77
77
  }
78
78
 
79
79
  el[stateKey].show = isInView(el, this.offsetTop, this.offsetLeft);
80
- });
80
+ }
81
81
  },
82
82
 
83
83
  write(data) {
84
- this.elements.forEach((el) => {
84
+ for (const el of this.elements) {
85
85
  const state = el[stateKey];
86
86
 
87
87
  if (state.show && !state.inview && !state.queued) {
@@ -99,7 +99,7 @@ export default {
99
99
  } else if (!state.show && state.inview && !state.queued && this.repeat) {
100
100
  this.toggle(el, false);
101
101
  }
102
- });
102
+ }
103
103
  },
104
104
 
105
105
  events: ['scroll', 'resize'],
@@ -10,13 +10,13 @@ import {
10
10
  dimensions,
11
11
  fastdom,
12
12
  height as getHeight,
13
+ offset as getOffset,
13
14
  getScrollingElement,
14
15
  hasClass,
15
16
  isNumeric,
16
17
  isString,
17
18
  isVisible,
18
19
  noop,
19
- offset,
20
20
  offsetPosition,
21
21
  parent,
22
22
  query,
@@ -67,21 +67,6 @@ export default {
67
67
  },
68
68
 
69
69
  computed: {
70
- position({ position }, $el) {
71
- return position === 'auto'
72
- ? (this.isFixed ? this.placeholder : $el).offsetHeight > getHeight(window)
73
- ? 'bottom'
74
- : 'top'
75
- : position;
76
- },
77
-
78
- offset({ offset }, $el) {
79
- if (this.position === 'bottom') {
80
- offset += '+100vh-100%';
81
- }
82
- return toPx(offset, 'height', $el);
83
- },
84
-
85
70
  selTarget({ selTarget }, $el) {
86
71
  return (selTarget && $(selTarget, $el)) || $el;
87
72
  },
@@ -143,8 +128,8 @@ export default {
143
128
 
144
129
  if (target) {
145
130
  fastdom.read(() => {
146
- const { top } = offset(target);
147
- const elTop = offset(this.$el).top;
131
+ const { top } = getOffset(target);
132
+ const elTop = getOffset(this.$el).top;
148
133
  const elHeight = this.$el.offsetHeight;
149
134
 
150
135
  if (
@@ -157,7 +142,7 @@ export default {
157
142
  top -
158
143
  elHeight -
159
144
  (isNumeric(this.targetOffset) ? this.targetOffset : 0) -
160
- this.offset
145
+ toPx(this.offset, 'height')
161
146
  );
162
147
  }
163
148
  });
@@ -177,35 +162,49 @@ export default {
177
162
 
178
163
  const hide = this.isActive && types.has('resize');
179
164
  if (hide) {
165
+ css(this.selTarget, 'transition', '0s');
180
166
  this.hide();
181
167
  }
182
168
 
183
169
  if (!this.isActive) {
184
- height = this.$el.offsetHeight;
170
+ height = getOffset(this.$el).height;
185
171
  margin = css(this.$el, 'margin');
186
172
  }
187
173
 
188
174
  if (hide) {
189
175
  this.show();
176
+ fastdom.write(() => css(this.selTarget, 'transition', ''));
190
177
  }
191
178
 
192
- const overflow = Math.max(0, height + this.offset - getHeight(window));
193
-
194
179
  const referenceElement = this.isFixed ? this.placeholder : this.$el;
195
- const topOffset = offset(referenceElement).top;
196
- const offsetParentTop = offset(referenceElement.offsetParent).top;
180
+ const windowHeight = getHeight(window);
181
+
182
+ let position = this.position;
183
+ if (position === 'auto' && height > windowHeight) {
184
+ position = 'bottom';
185
+ }
186
+
187
+ let offset = toPx(this.offset, 'height', referenceElement);
188
+ if (position === 'bottom') {
189
+ offset += windowHeight - height;
190
+ }
191
+
192
+ const overflow = Math.max(0, height + offset - windowHeight);
193
+ const topOffset = getOffset(referenceElement).top;
194
+ const offsetParentTop = getOffset(referenceElement.offsetParent).top;
197
195
 
198
196
  const top = parseProp(this.top, this.$el, topOffset);
199
197
  const bottom = parseProp(this.bottom, this.$el, topOffset + height, true);
200
198
 
201
- const start = Math.max(top, topOffset) - this.offset;
199
+ const start = Math.max(top, topOffset) - offset;
202
200
  const end = bottom
203
- ? bottom - this.$el.offsetHeight + overflow - this.offset
204
- : getScrollingElement(this.$el).scrollHeight - getHeight(window);
201
+ ? bottom - getOffset(this.$el).height + overflow - offset
202
+ : getScrollingElement(this.$el).scrollHeight - windowHeight;
205
203
 
206
204
  return {
207
205
  start,
208
206
  end,
207
+ offset,
209
208
  overflow,
210
209
  topOffset,
211
210
  offsetParentTop,
@@ -213,7 +212,7 @@ export default {
213
212
  margin,
214
213
  width: dimensions(isVisible(this.widthElement) ? this.widthElement : this.$el)
215
214
  .width,
216
- top: offsetPosition(this.placeholder)[0],
215
+ top: offsetPosition(referenceElement)[0],
217
216
  };
218
217
  },
219
218
 
@@ -322,7 +321,7 @@ export default {
322
321
  }
323
322
  } else if (this.isFixed) {
324
323
  this.update();
325
- } else if (this.animation) {
324
+ } else if (this.animation && scroll > topOffset) {
326
325
  Animation.cancel(this.$el);
327
326
  this.show();
328
327
  Animation.in(this.$el, this.animation).catch(noop);
@@ -350,33 +349,33 @@ export default {
350
349
  },
351
350
 
352
351
  update() {
353
- const {
352
+ let {
354
353
  width,
355
354
  scroll = 0,
356
355
  overflow,
357
356
  overflowScroll = 0,
358
357
  start,
359
358
  end,
359
+ offset,
360
360
  topOffset,
361
361
  height,
362
362
  offsetParentTop,
363
363
  } = this._data;
364
364
  const active = start !== 0 || scroll > start;
365
- let top = this.offset;
366
365
  let position = 'fixed';
367
366
 
368
367
  if (scroll > end) {
369
- top = end + this.offset - offsetParentTop;
368
+ offset += end - offsetParentTop;
370
369
  position = 'absolute';
371
370
  }
372
371
 
373
372
  if (overflow) {
374
- top -= overflowScroll;
373
+ offset -= overflowScroll;
375
374
  }
376
375
 
377
376
  css(this.$el, {
378
377
  position,
379
- top: `${top}px`,
378
+ top: `${offset}px`,
380
379
  width,
381
380
  });
382
381
 
@@ -397,7 +396,7 @@ function parseProp(value, el, propOffset, padding) {
397
396
  } else {
398
397
  const refElement = value === true ? parent(el) : query(value, el);
399
398
  return (
400
- offset(refElement).bottom -
399
+ getOffset(refElement).bottom -
401
400
  (padding && refElement && within(el, refElement)
402
401
  ? toFloat(css(refElement, 'paddingBottom'))
403
402
  : 0)