uikit 3.11.2-dev.72dbb9a19 → 3.11.2-dev.76734f785

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 (114) hide show
  1. package/CHANGELOG.md +39 -19
  2. package/dist/css/uikit-core-rtl.css +86 -170
  3. package/dist/css/uikit-core-rtl.min.css +1 -1
  4. package/dist/css/uikit-core.css +86 -170
  5. package/dist/css/uikit-core.min.css +1 -1
  6. package/dist/css/uikit-rtl.css +88 -176
  7. package/dist/css/uikit-rtl.min.css +1 -1
  8. package/dist/css/uikit.css +88 -176
  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 +115 -78
  21. package/dist/js/components/parallax.min.js +1 -1
  22. package/dist/js/components/slider-parallax.js +115 -78
  23. package/dist/js/components/slider-parallax.min.js +1 -1
  24. package/dist/js/components/slider.js +79 -33
  25. package/dist/js/components/slider.min.js +1 -1
  26. package/dist/js/components/slideshow-parallax.js +115 -78
  27. package/dist/js/components/slideshow-parallax.min.js +1 -1
  28. package/dist/js/components/slideshow.js +45 -3
  29. package/dist/js/components/slideshow.min.js +1 -1
  30. package/dist/js/components/sortable.js +1 -1
  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 +259 -234
  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 +461 -347
  41. package/dist/js/uikit.min.js +1 -1
  42. package/package.json +1 -1
  43. package/src/js/components/internal/slider-preload.js +37 -0
  44. package/src/js/components/slider.js +43 -34
  45. package/src/js/components/slideshow.js +8 -1
  46. package/src/js/core/height-viewport.js +3 -0
  47. package/src/js/core/icon.js +13 -6
  48. package/src/js/core/img.js +131 -114
  49. package/src/js/core/sticky.js +51 -57
  50. package/src/js/core/svg.js +10 -6
  51. package/src/js/core/toggle.js +2 -1
  52. package/src/js/mixin/parallax.js +116 -79
  53. package/src/js/util/ajax.js +6 -2
  54. package/src/js/util/dimensions.js +4 -4
  55. package/src/js/util/dom.js +37 -31
  56. package/src/js/util/lang.js +6 -5
  57. package/src/js/util/player.js +3 -2
  58. package/src/js/util/style.js +4 -4
  59. package/src/less/components/base.less +10 -28
  60. package/src/less/components/form-range.less +48 -95
  61. package/src/less/components/form.less +0 -1
  62. package/src/less/components/height.less +3 -0
  63. package/src/less/components/lightbox.less +0 -1
  64. package/src/less/components/modal.less +3 -7
  65. package/src/less/components/progress.less +14 -36
  66. package/src/less/components/slider.less +0 -3
  67. package/src/less/components/slideshow.less +0 -3
  68. package/src/less/components/text.less +16 -32
  69. package/src/scss/components/base.scss +10 -28
  70. package/src/scss/components/form-range.scss +48 -95
  71. package/src/scss/components/form.scss +0 -1
  72. package/src/scss/components/height.scss +3 -0
  73. package/src/scss/components/lightbox.scss +0 -1
  74. package/src/scss/components/modal.scss +3 -7
  75. package/src/scss/components/progress.scss +14 -36
  76. package/src/scss/components/slider.scss +0 -3
  77. package/src/scss/components/slideshow.scss +0 -3
  78. package/src/scss/components/text.scss +16 -32
  79. package/src/scss/mixins-theme.scss +1 -1
  80. package/src/scss/mixins.scss +1 -1
  81. package/src/scss/variables-theme.scss +3 -3
  82. package/src/scss/variables.scss +3 -3
  83. package/tests/align.html +10 -10
  84. package/tests/animation.html +2 -2
  85. package/tests/article.html +2 -2
  86. package/tests/base.html +3 -3
  87. package/tests/card.html +10 -10
  88. package/tests/column.html +3 -3
  89. package/tests/comment.html +9 -9
  90. package/tests/dotnav.html +3 -3
  91. package/tests/image.html +296 -64
  92. package/tests/images/image-type.avif +0 -0
  93. package/tests/images/image-type.jpeg +0 -0
  94. package/tests/images/image-type.webp +0 -0
  95. package/tests/index.html +8 -8
  96. package/tests/lightbox.html +10 -10
  97. package/tests/marker.html +2 -2
  98. package/tests/modal.html +8 -9
  99. package/tests/navbar.html +2 -2
  100. package/tests/overlay.html +7 -7
  101. package/tests/parallax.html +16 -7
  102. package/tests/position.html +12 -12
  103. package/tests/slidenav.html +12 -12
  104. package/tests/slider.html +20 -20
  105. package/tests/sortable.html +1 -1
  106. package/tests/sticky-parallax.html +56 -71
  107. package/tests/svg.html +6 -6
  108. package/tests/table.html +11 -11
  109. package/tests/thumbnav.html +12 -12
  110. package/tests/transition.html +30 -30
  111. package/tests/utility.html +33 -33
  112. package/tests/video.html +1 -1
  113. package/tests/width.html +1 -1
  114. package/tests/images/animated.gif +0 -0
@@ -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) {
@@ -4,11 +4,11 @@ import {
4
4
  css,
5
5
  Dimensions,
6
6
  each,
7
+ findIndex,
7
8
  isNumber,
8
9
  isString,
9
10
  isUndefined,
10
11
  noop,
11
- startsWith,
12
12
  toFloat,
13
13
  toPx,
14
14
  trigger,
@@ -68,50 +68,44 @@ export default {
68
68
  },
69
69
 
70
70
  getCss(percent) {
71
- return keys(this.props).reduce(
72
- (css, prop) => {
73
- this.props[prop](css, percent);
74
- return css;
75
- },
76
- { transform: '', filter: '' }
77
- );
71
+ const css = { transform: '', filter: '' };
72
+ for (const prop in this.props) {
73
+ this.props[prop](css, percent);
74
+ }
75
+ return css;
78
76
  },
79
77
  },
80
78
  };
81
79
 
82
- function transformFn(prop, el, steps) {
83
- const unit = getUnit(steps) || { x: 'px', y: 'px', rotate: 'deg' }[prop] || '';
80
+ function transformFn(prop, el, stops) {
81
+ const unit = getUnit(stops) || { x: 'px', y: 'px', rotate: 'deg' }[prop] || '';
82
+ let transformFn;
84
83
 
85
84
  if (prop === 'x' || prop === 'y') {
86
85
  prop = `translate${ucfirst(prop)}`;
86
+ transformFn = (stop) => toFloat(toFloat(stop).toFixed(unit === 'px' ? 0 : 6));
87
87
  }
88
88
 
89
- steps = steps.map(toFloat);
90
-
91
- if (steps.length === 1) {
92
- steps.unshift(prop === 'scale' ? 1 : 0);
89
+ if (stops.length === 1) {
90
+ stops.unshift(prop === 'scale' ? 1 : 0);
93
91
  }
94
92
 
95
- return (css, percent) => {
96
- let value = getValue(steps, percent);
93
+ stops = parseStops(stops, transformFn);
97
94
 
98
- if (startsWith(prop, 'translate')) {
99
- value = toFloat(value).toFixed(unit === 'px' ? 0 : 6);
100
- }
101
-
102
- css.transform += ` ${prop}(${value}${unit})`;
95
+ return (css, percent) => {
96
+ css.transform += ` ${prop}(${getValue(stops, percent)}${unit})`;
103
97
  };
104
98
  }
105
99
 
106
- function colorFn(prop, el, steps) {
107
- if (steps.length === 1) {
108
- steps.unshift(getCssValue(el, prop, ''));
100
+ function colorFn(prop, el, stops) {
101
+ if (stops.length === 1) {
102
+ stops.unshift(getCssValue(el, prop, ''));
109
103
  }
110
104
 
111
- steps = steps.map((step) => parseColor(el, step));
105
+ stops = parseStops(stops, (stop) => parseColor(el, stop));
112
106
 
113
107
  return (css, percent) => {
114
- const [start, end, p] = getStep(steps, percent);
108
+ const [start, end, p] = getStop(stops, percent);
115
109
  const value = start
116
110
  .map((value, i) => {
117
111
  value += p * (end[i] - value);
@@ -131,85 +125,83 @@ function parseColor(el, color) {
131
125
  .map(toFloat);
132
126
  }
133
127
 
134
- function filterFn(prop, el, steps) {
135
- if (steps.length === 1) {
136
- steps.unshift(0);
128
+ function filterFn(prop, el, stops) {
129
+ if (stops.length === 1) {
130
+ stops.unshift(0);
137
131
  }
138
132
 
139
- const unit = getUnit(steps) || { blur: 'px', hue: 'deg' }[prop] || '%';
133
+ const unit = getUnit(stops) || { blur: 'px', hue: 'deg' }[prop] || '%';
140
134
  prop = { fopacity: 'opacity', hue: 'hue-rotate' }[prop] || prop;
141
- steps = steps.map(toFloat);
135
+ stops = parseStops(stops);
142
136
 
143
137
  return (css, percent) => {
144
- const value = getValue(steps, percent);
138
+ const value = getValue(stops, percent);
145
139
  css.filter += ` ${prop}(${value + unit})`;
146
140
  };
147
141
  }
148
142
 
149
- function cssPropFn(prop, el, steps) {
150
- if (steps.length === 1) {
151
- steps.unshift(getCssValue(el, prop, ''));
143
+ function cssPropFn(prop, el, stops) {
144
+ if (stops.length === 1) {
145
+ stops.unshift(getCssValue(el, prop, ''));
152
146
  }
153
147
 
154
- steps = steps.map(toFloat);
148
+ stops = parseStops(stops);
155
149
 
156
150
  return (css, percent) => {
157
- css[prop] = getValue(steps, percent);
151
+ css[prop] = getValue(stops, percent);
158
152
  };
159
153
  }
160
154
 
161
- function strokeFn(prop, el, steps) {
162
- if (steps.length === 1) {
163
- steps.unshift(0);
155
+ function strokeFn(prop, el, stops) {
156
+ if (stops.length === 1) {
157
+ stops.unshift(0);
164
158
  }
165
159
 
166
- const unit = getUnit(steps);
167
- steps = steps.map(toFloat);
160
+ const unit = getUnit(stops);
161
+ const length = getMaxPathLength(el);
162
+ stops = parseStops(stops.reverse(), (stop) => {
163
+ stop = toFloat(stop);
164
+ return unit === '%' ? (stop * length) / 100 : stop;
165
+ });
168
166
 
169
- if (!steps.some((step) => step)) {
167
+ if (!stops.some(([value]) => value)) {
170
168
  return noop;
171
169
  }
172
170
 
173
- const length = getMaxPathLength(el);
174
171
  css(el, 'strokeDasharray', length);
175
172
 
176
- if (unit === '%') {
177
- steps = steps.map((step) => (step * length) / 100);
178
- }
179
-
180
- steps = steps.reverse();
181
-
182
173
  return (css, percent) => {
183
- css.strokeDashoffset = getValue(steps, percent);
174
+ css.strokeDashoffset = getValue(stops, percent);
184
175
  };
185
176
  }
186
177
 
187
- function backgroundFn(prop, el, steps) {
188
- if (steps.length === 1) {
189
- steps.unshift(0);
178
+ function backgroundFn(prop, el, stops) {
179
+ if (stops.length === 1) {
180
+ stops.unshift(0);
190
181
  }
191
182
 
192
183
  prop = prop.substr(-1);
193
184
  const attr = prop === 'y' ? 'height' : 'width';
194
- steps = steps.map((step) => toPx(step, attr, el));
185
+ stops = parseStops(stops, (stop) => toPx(stop, attr, el));
195
186
 
196
187
  const bgPos = getCssValue(el, `background-position-${prop}`, '');
197
188
 
198
189
  return getCssValue(el, 'backgroundSize', '') === 'cover'
199
- ? backgroundCoverFn(prop, el, steps, bgPos, attr)
200
- : setBackgroundPosFn(prop, steps, bgPos);
190
+ ? backgroundCoverFn(prop, el, stops, bgPos, attr)
191
+ : setBackgroundPosFn(prop, stops, bgPos);
201
192
  }
202
193
 
203
- function backgroundCoverFn(prop, el, steps, bgPos, attr) {
194
+ function backgroundCoverFn(prop, el, stops, bgPos, attr) {
204
195
  const dimImage = getBackgroundImageDimensions(el);
205
196
 
206
197
  if (!dimImage.width) {
207
198
  return noop;
208
199
  }
209
200
 
210
- const min = Math.min(...steps);
211
- const max = Math.max(...steps);
212
- const down = steps.indexOf(min) < steps.indexOf(max);
201
+ const values = stops.map(([value]) => value);
202
+ const min = Math.min(...values);
203
+ const max = Math.max(...values);
204
+ const down = values.indexOf(min) < values.indexOf(max);
213
205
 
214
206
  const diff = max - min;
215
207
  let pos = (down ? -diff : 0) - (down ? min : max);
@@ -234,7 +226,7 @@ function backgroundCoverFn(prop, el, steps, bgPos, attr) {
234
226
 
235
227
  const dim = Dimensions.cover(dimImage, dimEl);
236
228
 
237
- const fn = setBackgroundPosFn(prop, steps, `${pos}px`);
229
+ const fn = setBackgroundPosFn(prop, stops, `${pos}px`);
238
230
  return (css, percent) => {
239
231
  fn(css, percent);
240
232
  css.backgroundSize = `${dim.width}px ${dim.height}px`;
@@ -242,9 +234,9 @@ function backgroundCoverFn(prop, el, steps, bgPos, attr) {
242
234
  };
243
235
  }
244
236
 
245
- function setBackgroundPosFn(prop, steps, pos) {
237
+ function setBackgroundPosFn(prop, stops, pos) {
246
238
  return function (css, percent) {
247
- css[`background-position-${prop}`] = `calc(${pos} + ${getValue(steps, percent)}px)`;
239
+ css[`background-position-${prop}`] = `calc(${pos} + ${getValue(stops, percent)}px)`;
248
240
  };
249
241
  }
250
242
 
@@ -265,6 +257,7 @@ function getBackgroundImageDimensions(el) {
265
257
  dimensions[src] = toDimensions(image);
266
258
  trigger(el, 'bgimageload');
267
259
  };
260
+ return toDimensions(image);
268
261
  }
269
262
  }
270
263
 
@@ -278,27 +271,71 @@ function toDimensions(image) {
278
271
  };
279
272
  }
280
273
 
281
- function getStep(steps, percent) {
282
- const count = steps.length - 1;
283
- const index = Math.min(Math.floor(count * percent), count - 1);
274
+ function parseStops(stops, fn = toFloat) {
275
+ const result = [];
276
+ const { length } = stops;
277
+ let nullIndex = 0;
278
+ for (let i = 0; i < length; i++) {
279
+ let [value, percent] = isString(stops[i]) ? stops[i].trim().split(' ') : [stops[i]];
280
+ value = fn(value);
281
+ percent = percent ? toFloat(percent) / 100 : null;
282
+
283
+ if (i === 0) {
284
+ if (percent === null) {
285
+ percent = 0;
286
+ } else if (percent) {
287
+ result.push([value, 0]);
288
+ }
289
+ } else if (i === length - 1) {
290
+ if (percent === null) {
291
+ percent = 1;
292
+ } else if (percent !== 1) {
293
+ result.push([value, percent]);
294
+ percent = 1;
295
+ }
296
+ }
297
+
298
+ result.push([value, percent]);
299
+
300
+ if (percent === null) {
301
+ nullIndex++;
302
+ } else if (nullIndex) {
303
+ const leftPercent = result[i - nullIndex - 1][1];
304
+ const p = (percent - leftPercent) / (nullIndex + 1);
305
+ for (let j = nullIndex; j > 0; j--) {
306
+ result[i - j][1] = leftPercent + p * (nullIndex - j + 1);
307
+ }
308
+
309
+ nullIndex = 0;
310
+ }
311
+ }
312
+
313
+ return result;
314
+ }
284
315
 
285
- return steps
286
- .slice(index, index + 2)
287
- .concat(percent === 1 ? 1 : (percent % (1 / count)) * count);
316
+ function getStop(stops, percent) {
317
+ const index = findIndex(stops.slice(1), ([, targetPercent]) => percent <= targetPercent) + 1;
318
+ return [
319
+ stops[index - 1][0],
320
+ stops[index][0],
321
+ (percent - stops[index - 1][1]) / (stops[index][1] - stops[index - 1][1]),
322
+ ];
288
323
  }
289
324
 
290
- function getValue(steps, percent) {
291
- const [start, end, p] = getStep(steps, percent);
325
+ function getValue(stops, percent) {
326
+ const [start, end, p] = getStop(stops, percent);
292
327
  return isNumber(start) ? start + Math.abs(start - end) * p * (start < end ? 1 : -1) : +end;
293
328
  }
294
329
 
295
- function getUnit(steps, defaultUnit) {
296
- return (
297
- steps.reduce(
298
- (unit, step) => unit || (isString(step) && step.replace(/[\d-]/g, '').trim()),
299
- ''
300
- ) || defaultUnit
301
- );
330
+ const unitRe = /^-?\d+([^\s]*)/;
331
+ function getUnit(stops, defaultUnit) {
332
+ for (const stop of stops) {
333
+ const match = stop.match?.(unitRe);
334
+ if (match) {
335
+ return match[1];
336
+ }
337
+ }
338
+ return defaultUnit;
302
339
  }
303
340
 
304
341
  function getCssValue(el, prop, value) {
@@ -60,8 +60,12 @@ export function getImage(src, srcset, sizes) {
60
60
  return new Promise((resolve, reject) => {
61
61
  const img = new Image();
62
62
 
63
- img.onerror = (e) => reject(e);
64
- img.onload = () => resolve(img);
63
+ img.onerror = (e) => {
64
+ reject(e);
65
+ };
66
+ img.onload = () => {
67
+ resolve(img);
68
+ };
65
69
 
66
70
  sizes && (img.sizes = sizes);
67
71
  srcset && (img.srcset = srcset);
@@ -37,8 +37,8 @@ export function offset(element, coordinates) {
37
37
  const currentOffset = dimensions(element);
38
38
 
39
39
  if (element) {
40
- const { pageYOffset, pageXOffset } = toWindow(element);
41
- const offsetBy = { height: pageYOffset, width: pageXOffset };
40
+ const { scrollY, scrollX } = toWindow(element);
41
+ const offsetBy = { height: scrollY, width: scrollX };
42
42
 
43
43
  for (const dir in dirs) {
44
44
  for (const i in dirs[dir]) {
@@ -104,8 +104,8 @@ export function offsetPosition(element) {
104
104
 
105
105
  if (css(element, 'position') === 'fixed') {
106
106
  const win = toWindow(element);
107
- offset[0] += win.pageYOffset;
108
- offset[1] += win.pageXOffset;
107
+ offset[0] += win.scrollY;
108
+ offset[1] += win.scrollX;
109
109
  return offset;
110
110
  }
111
111
  } while ((element = element.offsetParent));