uikit 3.11.2-dev.c7ed3c19b → 3.11.2-dev.cfa6c7d5c

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 (135) hide show
  1. package/CHANGELOG.md +37 -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 +1 -1
  11. package/dist/js/components/countdown.min.js +1 -1
  12. package/dist/js/components/filter.js +6 -8
  13. package/dist/js/components/filter.min.js +1 -1
  14. package/dist/js/components/lightbox-panel.js +26 -55
  15. package/dist/js/components/lightbox-panel.min.js +1 -1
  16. package/dist/js/components/lightbox.js +27 -57
  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 +114 -78
  21. package/dist/js/components/parallax.min.js +1 -1
  22. package/dist/js/components/slider-parallax.js +114 -78
  23. package/dist/js/components/slider-parallax.min.js +1 -1
  24. package/dist/js/components/slider.js +60 -12
  25. package/dist/js/components/slider.min.js +1 -1
  26. package/dist/js/components/slideshow-parallax.js +114 -78
  27. package/dist/js/components/slideshow-parallax.min.js +1 -1
  28. package/dist/js/components/slideshow.js +52 -16
  29. package/dist/js/components/slideshow.min.js +1 -1
  30. package/dist/js/components/sortable.js +5 -7
  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 +1 -1
  35. package/dist/js/components/upload.min.js +1 -1
  36. package/dist/js/uikit-core.js +288 -270
  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 +501 -417
  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 +1 -1
  46. package/src/js/components/filter.js +2 -3
  47. package/src/js/components/internal/lightbox-animations.js +4 -3
  48. package/src/js/components/internal/slider-preload.js +37 -0
  49. package/src/js/components/internal/slideshow-animations.js +4 -3
  50. package/src/js/components/lightbox-panel.js +34 -58
  51. package/src/js/components/lightbox.js +1 -2
  52. package/src/js/components/slider.js +21 -1
  53. package/src/js/components/slideshow.js +8 -1
  54. package/src/js/components/sortable.js +1 -1
  55. package/src/js/core/alert.js +1 -2
  56. package/src/js/core/height-viewport.js +3 -0
  57. package/src/js/core/icon.js +13 -6
  58. package/src/js/core/img.js +131 -114
  59. package/src/js/core/modal.js +1 -2
  60. package/src/js/core/navbar.js +3 -3
  61. package/src/js/core/sticky.js +51 -57
  62. package/src/js/core/svg.js +10 -6
  63. package/src/js/core/toggle.js +2 -1
  64. package/src/js/mixin/internal/animate-slide.js +9 -12
  65. package/src/js/mixin/parallax.js +115 -79
  66. package/src/js/mixin/slider.js +8 -16
  67. package/src/js/mixin/slideshow.js +2 -2
  68. package/src/js/mixin/togglable.js +1 -2
  69. package/src/js/util/ajax.js +15 -14
  70. package/src/js/util/animation.js +7 -12
  71. package/src/js/util/dimensions.js +4 -4
  72. package/src/js/util/dom.js +37 -31
  73. package/src/js/util/lang.js +7 -6
  74. package/src/js/util/options.js +2 -11
  75. package/src/js/util/player.js +5 -4
  76. package/src/js/util/selector.js +11 -11
  77. package/src/js/util/style.js +4 -4
  78. package/src/less/components/base.less +10 -33
  79. package/src/less/components/form-range.less +48 -95
  80. package/src/less/components/form.less +0 -1
  81. package/src/less/components/height.less +3 -0
  82. package/src/less/components/leader.less +0 -1
  83. package/src/less/components/lightbox.less +0 -1
  84. package/src/less/components/modal.less +3 -7
  85. package/src/less/components/progress.less +14 -36
  86. package/src/less/components/slider.less +0 -3
  87. package/src/less/components/slideshow.less +0 -3
  88. package/src/less/components/text.less +16 -32
  89. package/src/scss/components/base.scss +10 -33
  90. package/src/scss/components/form-range.scss +48 -95
  91. package/src/scss/components/form.scss +0 -1
  92. package/src/scss/components/height.scss +3 -0
  93. package/src/scss/components/leader.scss +0 -1
  94. package/src/scss/components/lightbox.scss +0 -1
  95. package/src/scss/components/modal.scss +3 -7
  96. package/src/scss/components/progress.scss +14 -36
  97. package/src/scss/components/slider.scss +0 -3
  98. package/src/scss/components/slideshow.scss +0 -3
  99. package/src/scss/components/text.scss +16 -32
  100. package/src/scss/mixins-theme.scss +1 -1
  101. package/src/scss/mixins.scss +1 -1
  102. package/src/scss/variables-theme.scss +3 -3
  103. package/src/scss/variables.scss +3 -3
  104. package/tests/align.html +10 -10
  105. package/tests/animation.html +2 -2
  106. package/tests/article.html +2 -2
  107. package/tests/base.html +3 -3
  108. package/tests/card.html +10 -10
  109. package/tests/column.html +3 -3
  110. package/tests/comment.html +9 -9
  111. package/tests/dotnav.html +3 -3
  112. package/tests/image.html +296 -64
  113. package/tests/images/image-type.avif +0 -0
  114. package/tests/images/image-type.jpeg +0 -0
  115. package/tests/images/image-type.webp +0 -0
  116. package/tests/index.html +8 -8
  117. package/tests/lightbox.html +10 -10
  118. package/tests/marker.html +2 -2
  119. package/tests/modal.html +8 -9
  120. package/tests/navbar.html +2 -2
  121. package/tests/overlay.html +7 -7
  122. package/tests/parallax.html +14 -5
  123. package/tests/position.html +12 -12
  124. package/tests/slidenav.html +12 -12
  125. package/tests/slider.html +20 -20
  126. package/tests/sortable.html +1 -1
  127. package/tests/sticky-parallax.html +55 -70
  128. package/tests/svg.html +6 -6
  129. package/tests/table.html +11 -11
  130. package/tests/thumbnav.html +12 -12
  131. package/tests/transition.html +30 -30
  132. package/tests/utility.html +33 -33
  133. package/tests/video.html +1 -1
  134. package/tests/width.html +1 -1
  135. 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) {
103
+ write(store) {
104
+ if (!this.observer || isImg(this.$el)) {
107
105
  return false;
108
106
  }
109
107
 
110
- if (!image && document.readyState === 'complete') {
111
- this.load(this.observer.takeRecords());
112
- }
113
-
114
- if (this.isImg) {
115
- return false;
116
- }
117
-
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,24 +119,18 @@ 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() {
@@ -165,12 +143,11 @@ export default {
165
143
  },
166
144
  };
167
145
 
168
- function setSrcAttrs(el, src, srcset, sizes) {
146
+ function setSrcAttrs(el, src) {
169
147
  if (isImg(el)) {
170
- const set = (prop, val) => val && val !== el[prop] && (el[prop] = val);
171
- set('sizes', sizes);
172
- set('srcset', srcset);
173
- set('src', src);
148
+ const parentNode = parent(el);
149
+ const elements = isPicture(parentNode) ? children(parentNode) : [el];
150
+ elements.forEach((el) => setSourceProps(el, el));
174
151
  } else if (src) {
175
152
  const change = !includes(el.style.backgroundImage, src);
176
153
  if (change) {
@@ -180,16 +157,62 @@ function setSrcAttrs(el, src, srcset, sizes) {
180
157
  }
181
158
  }
182
159
 
183
- function getPlaceholderImage(width, height, sizes) {
184
- if (sizes) {
185
- ({ width, height } = Dimensions.ratio(
186
- { width, height },
187
- 'width',
188
- toPx(sizesToPixel(sizes))
189
- ));
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);
190
209
  }
191
210
 
192
- 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));
193
216
  }
194
217
 
195
218
  const sizesRe = /\s*(.*?)\s*(\w+|calc\(.*?\))\s*(?:,|$)/g;
@@ -229,22 +252,16 @@ function getSourceSize(srcset, sizes) {
229
252
  return descriptors.filter((size) => size >= srcSize)[0] || descriptors.pop() || '';
230
253
  }
231
254
 
232
- function isImg(el) {
233
- 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
+ }
234
259
  }
235
260
 
236
- function currentSrc(el) {
237
- return el.currentSrc || el.src;
261
+ function isPicture(el) {
262
+ return isTag(el, 'picture');
238
263
  }
239
264
 
240
- const key = '__test__';
241
- let storage;
242
-
243
- // workaround for Safari's private browsing mode and accessing sessionStorage in Blink
244
- try {
245
- storage = window.sessionStorage || {};
246
- storage[key] = 1;
247
- delete storage[key];
248
- } catch (e) {
249
- storage = {};
265
+ function isImg(el) {
266
+ return isTag(el, 'img');
250
267
  }
@@ -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,
@@ -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
 
@@ -10,13 +10,12 @@ import {
10
10
  dimensions,
11
11
  fastdom,
12
12
  height as getHeight,
13
+ offset as getOffset,
13
14
  getScrollingElement,
14
15
  hasClass,
15
- isNumeric,
16
16
  isString,
17
17
  isVisible,
18
18
  noop,
19
- offset,
20
19
  offsetPosition,
21
20
  parent,
22
21
  query,
@@ -29,6 +28,7 @@ import {
29
28
  toPx,
30
29
  trigger,
31
30
  within,
31
+ intersectRect,
32
32
  } from 'uikit-util';
33
33
 
34
34
  export default {
@@ -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
  },
@@ -134,34 +119,29 @@ export default {
134
119
  return window;
135
120
  },
136
121
 
122
+ filter() {
123
+ return this.targetOffset !== false;
124
+ },
125
+
137
126
  handler() {
138
- if (!(this.targetOffset !== false && location.hash && scrollTop(window) > 0)) {
127
+ if (!location.hash || scrollTop(window) === 0) {
139
128
  return;
140
129
  }
141
130
 
142
- const target = $(location.hash);
143
-
144
- if (target) {
145
- fastdom.read(() => {
146
- const { top } = offset(target);
147
- const elTop = offset(this.$el).top;
148
- const elHeight = this.$el.offsetHeight;
149
-
150
- if (
151
- this.isFixed &&
152
- elTop + elHeight >= top &&
153
- elTop <= top + target.offsetHeight
154
- ) {
155
- scrollTop(
156
- window,
157
- top -
158
- elHeight -
159
- (isNumeric(this.targetOffset) ? this.targetOffset : 0) -
160
- this.offset
161
- );
162
- }
163
- });
164
- }
131
+ fastdom.read(() => {
132
+ const targetOffset = getOffset($(location.hash));
133
+ const elOffset = getOffset(this.$el);
134
+
135
+ if (this.isFixed && intersectRect(targetOffset, elOffset)) {
136
+ scrollTop(
137
+ window,
138
+ targetOffset.top -
139
+ elOffset.height -
140
+ toPx(this.targetOffset, 'height') -
141
+ toPx(this.offset, 'height')
142
+ );
143
+ }
144
+ });
165
145
  },
166
146
  },
167
147
  ],
@@ -177,35 +157,49 @@ export default {
177
157
 
178
158
  const hide = this.isActive && types.has('resize');
179
159
  if (hide) {
160
+ css(this.selTarget, 'transition', '0s');
180
161
  this.hide();
181
162
  }
182
163
 
183
164
  if (!this.isActive) {
184
- height = this.$el.offsetHeight;
165
+ height = getOffset(this.$el).height;
185
166
  margin = css(this.$el, 'margin');
186
167
  }
187
168
 
188
169
  if (hide) {
189
170
  this.show();
171
+ fastdom.write(() => css(this.selTarget, 'transition', ''));
190
172
  }
191
173
 
192
- const overflow = Math.max(0, height + this.offset - getHeight(window));
193
-
194
174
  const referenceElement = this.isFixed ? this.placeholder : this.$el;
195
- const topOffset = offset(referenceElement).top;
196
- const offsetParentTop = offset(referenceElement.offsetParent).top;
175
+ const windowHeight = getHeight(window);
176
+
177
+ let position = this.position;
178
+ if (position === 'auto' && height > windowHeight) {
179
+ position = 'bottom';
180
+ }
181
+
182
+ let offset = toPx(this.offset, 'height', referenceElement);
183
+ if (position === 'bottom') {
184
+ offset += windowHeight - height;
185
+ }
186
+
187
+ const overflow = Math.max(0, height + offset - windowHeight);
188
+ const topOffset = getOffset(referenceElement).top;
189
+ const offsetParentTop = getOffset(referenceElement.offsetParent).top;
197
190
 
198
191
  const top = parseProp(this.top, this.$el, topOffset);
199
192
  const bottom = parseProp(this.bottom, this.$el, topOffset + height, true);
200
193
 
201
- const start = Math.max(top, topOffset) - this.offset;
194
+ const start = Math.max(top, topOffset) - offset;
202
195
  const end = bottom
203
- ? bottom - this.$el.offsetHeight + overflow - this.offset
204
- : getScrollingElement(this.$el).scrollHeight - getHeight(window);
196
+ ? bottom - getOffset(this.$el).height + overflow - offset
197
+ : getScrollingElement(this.$el).scrollHeight - windowHeight;
205
198
 
206
199
  return {
207
200
  start,
208
201
  end,
202
+ offset,
209
203
  overflow,
210
204
  topOffset,
211
205
  offsetParentTop,
@@ -213,7 +207,7 @@ export default {
213
207
  margin,
214
208
  width: dimensions(isVisible(this.widthElement) ? this.widthElement : this.$el)
215
209
  .width,
216
- top: offsetPosition(this.placeholder)[0],
210
+ top: offsetPosition(referenceElement)[0],
217
211
  };
218
212
  },
219
213
 
@@ -322,7 +316,7 @@ export default {
322
316
  }
323
317
  } else if (this.isFixed) {
324
318
  this.update();
325
- } else if (this.animation) {
319
+ } else if (this.animation && scroll > topOffset) {
326
320
  Animation.cancel(this.$el);
327
321
  this.show();
328
322
  Animation.in(this.$el, this.animation).catch(noop);
@@ -350,33 +344,33 @@ export default {
350
344
  },
351
345
 
352
346
  update() {
353
- const {
347
+ let {
354
348
  width,
355
349
  scroll = 0,
356
350
  overflow,
357
351
  overflowScroll = 0,
358
352
  start,
359
353
  end,
354
+ offset,
360
355
  topOffset,
361
356
  height,
362
357
  offsetParentTop,
363
358
  } = this._data;
364
359
  const active = start !== 0 || scroll > start;
365
- let top = this.offset;
366
360
  let position = 'fixed';
367
361
 
368
362
  if (scroll > end) {
369
- top = end + this.offset - offsetParentTop;
363
+ offset += end - offsetParentTop;
370
364
  position = 'absolute';
371
365
  }
372
366
 
373
367
  if (overflow) {
374
- top -= overflowScroll;
368
+ offset -= overflowScroll;
375
369
  }
376
370
 
377
371
  css(this.$el, {
378
372
  position,
379
- top: `${top}px`,
373
+ top: `${offset}px`,
380
374
  width,
381
375
  });
382
376
 
@@ -397,7 +391,7 @@ function parseProp(value, el, propOffset, padding) {
397
391
  } else {
398
392
  const refElement = value === true ? parent(el) : query(value, el);
399
393
  return (
400
- offset(refElement).bottom -
394
+ getOffset(refElement).bottom -
401
395
  (padding && refElement && within(el, refElement)
402
396
  ? toFloat(css(refElement, 'paddingBottom'))
403
397
  : 0)
@@ -5,10 +5,12 @@ import {
5
5
  append,
6
6
  attr,
7
7
  includes,
8
+ isTag,
8
9
  isVisible,
9
10
  isVoidElement,
10
11
  memoize,
11
12
  noop,
13
+ once,
12
14
  remove,
13
15
  removeAttr,
14
16
  startsWith,
@@ -94,6 +96,12 @@ export default {
94
96
 
95
97
  methods: {
96
98
  async getSvg() {
99
+ if (isTag(this.$el, 'img') && !this.$el.complete && this.$el.loading === 'lazy') {
100
+ return new Promise((resolve) =>
101
+ once(this.$el, 'load', () => resolve(this.getSvg()))
102
+ );
103
+ }
104
+
97
105
  return parseSVG(await loadSVG(this.src), this.icon) || Promise.reject('SVG not found.');
98
106
  },
99
107
 
@@ -193,7 +201,7 @@ export function getMaxPathLength(el) {
193
201
  }
194
202
 
195
203
  function insertSVG(el, root) {
196
- if (isVoidElement(root) || root.tagName === 'CANVAS') {
204
+ if (isVoidElement(root) || isTag(root, 'canvas')) {
197
205
  root.hidden = true;
198
206
 
199
207
  const next = root.nextElementSibling;
@@ -205,11 +213,7 @@ function insertSVG(el, root) {
205
213
  }
206
214
 
207
215
  function equals(el, other) {
208
- return isSVG(el) && isSVG(other) && innerHTML(el) === innerHTML(other);
209
- }
210
-
211
- function isSVG(el) {
212
- return el?.tagName === 'svg';
216
+ return isTag(el, 'svg') && isTag(other, 'svg') && innerHTML(el) === innerHTML(other);
213
217
  }
214
218
 
215
219
  function innerHTML(el) {
@@ -7,6 +7,7 @@ import {
7
7
  includes,
8
8
  isBoolean,
9
9
  isFocusable,
10
+ isTag,
10
11
  isTouch,
11
12
  matches,
12
13
  once,
@@ -134,7 +135,7 @@ export default {
134
135
  name: 'keydown',
135
136
 
136
137
  filter() {
137
- return includes(this.mode, 'click') && this.$el.tagName !== 'INPUT';
138
+ return includes(this.mode, 'click') && !isTag(this.$el, 'input');
138
139
  },
139
140
 
140
141
  handler(e) {