uikit 3.11.2-dev.72dbb9a19 → 3.11.2-dev.92f357b93

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 (108) hide show
  1. package/CHANGELOG.md +32 -18
  2. package/dist/css/uikit-core-rtl.css +80 -171
  3. package/dist/css/uikit-core-rtl.min.css +1 -1
  4. package/dist/css/uikit-core.css +80 -171
  5. package/dist/css/uikit-core.min.css +1 -1
  6. package/dist/css/uikit-rtl.css +82 -177
  7. package/dist/css/uikit-rtl.min.css +1 -1
  8. package/dist/css/uikit.css +82 -177
  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 +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 +57 -2
  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 +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 +172 -165
  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 +347 -241
  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 +21 -1
  45. package/src/js/components/slideshow.js +8 -1
  46. package/src/js/core/img.js +129 -114
  47. package/src/js/core/sticky.js +1 -1
  48. package/src/js/core/svg.js +10 -6
  49. package/src/js/core/toggle.js +2 -1
  50. package/src/js/mixin/parallax.js +110 -72
  51. package/src/js/util/dom.js +27 -30
  52. package/src/js/util/lang.js +6 -5
  53. package/src/js/util/player.js +3 -2
  54. package/src/js/util/style.js +4 -4
  55. package/src/less/components/base.less +10 -28
  56. package/src/less/components/form-range.less +52 -97
  57. package/src/less/components/form.less +0 -1
  58. package/src/less/components/lightbox.less +0 -1
  59. package/src/less/components/modal.less +3 -7
  60. package/src/less/components/progress.less +14 -36
  61. package/src/less/components/slider.less +0 -3
  62. package/src/less/components/slideshow.less +0 -3
  63. package/src/less/components/text.less +16 -32
  64. package/src/scss/components/base.scss +10 -28
  65. package/src/scss/components/form-range.scss +52 -97
  66. package/src/scss/components/form.scss +0 -1
  67. package/src/scss/components/lightbox.scss +0 -1
  68. package/src/scss/components/modal.scss +3 -7
  69. package/src/scss/components/progress.scss +14 -36
  70. package/src/scss/components/slider.scss +0 -3
  71. package/src/scss/components/slideshow.scss +0 -3
  72. package/src/scss/components/text.scss +16 -32
  73. package/src/scss/mixins-theme.scss +1 -1
  74. package/src/scss/mixins.scss +1 -1
  75. package/src/scss/variables-theme.scss +3 -3
  76. package/src/scss/variables.scss +3 -3
  77. package/tests/align.html +10 -10
  78. package/tests/animation.html +2 -2
  79. package/tests/article.html +2 -2
  80. package/tests/base.html +3 -3
  81. package/tests/card.html +10 -10
  82. package/tests/column.html +3 -3
  83. package/tests/comment.html +9 -9
  84. package/tests/dotnav.html +3 -3
  85. package/tests/image.html +296 -64
  86. package/tests/images/image-type.avif +0 -0
  87. package/tests/images/image-type.jpeg +0 -0
  88. package/tests/images/image-type.webp +0 -0
  89. package/tests/index.html +8 -8
  90. package/tests/lightbox.html +10 -10
  91. package/tests/marker.html +2 -2
  92. package/tests/modal.html +8 -9
  93. package/tests/navbar.html +2 -2
  94. package/tests/overlay.html +7 -7
  95. package/tests/parallax.html +14 -5
  96. package/tests/position.html +12 -12
  97. package/tests/slidenav.html +12 -12
  98. package/tests/slider.html +20 -20
  99. package/tests/sortable.html +1 -1
  100. package/tests/sticky-parallax.html +47 -62
  101. package/tests/svg.html +6 -6
  102. package/tests/table.html +11 -11
  103. package/tests/thumbnav.html +12 -12
  104. package/tests/transition.html +30 -30
  105. package/tests/utility.html +33 -33
  106. package/tests/video.html +1 -1
  107. package/tests/width.html +1 -1
  108. package/tests/images/animated.gif +0 -0
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.2-dev.72dbb9a19",
5
+ "version": "3.11.2-dev.92f357b93",
6
6
  "main": "dist/js/uikit.js",
7
7
  "style": "dist/css/uikit.css",
8
8
  "sideEffects": [
@@ -0,0 +1,37 @@
1
+ import { $$, isVisible, removeAttr } from 'uikit-util';
2
+
3
+ export default {
4
+ connected() {
5
+ if (window.IntersectionObserver) {
6
+ this.observer = new IntersectionObserver(
7
+ (entries) => {
8
+ if (entries.some((entry) => entry.isIntersecting)) {
9
+ removeLazyLoad(this.getAdjacentSlides());
10
+ }
11
+ },
12
+ { rootMargin: '50% 50%' }
13
+ );
14
+ this.observer.observe(this.$el);
15
+ }
16
+ },
17
+
18
+ disconnected() {
19
+ this.observer && this.observer.disconnect();
20
+ },
21
+
22
+ update: {
23
+ read() {
24
+ if (isVisible(this.$el)) {
25
+ removeLazyLoad(this.getAdjacentSlides());
26
+ }
27
+ },
28
+
29
+ events: ['resize'],
30
+ },
31
+ };
32
+
33
+ export function removeLazyLoad(elements = []) {
34
+ for (const el of elements) {
35
+ el && $$('img[loading="lazy"]', el).forEach((el) => removeAttr(el, 'loading'));
36
+ }
37
+ }
@@ -1,6 +1,7 @@
1
1
  import Class from '../mixin/class';
2
2
  import Slider, { speedUp } from '../mixin/slider';
3
3
  import SliderReactive from '../mixin/slider-reactive';
4
+ import SliderPreload from './internal/slider-preload';
4
5
  import Transitioner, { getMax, getWidth } from './internal/slider-transitioner';
5
6
  import {
6
7
  $,
@@ -20,7 +21,7 @@ import {
20
21
  } from 'uikit-util';
21
22
 
22
23
  export default {
23
- mixins: [Class, Slider, SliderReactive],
24
+ mixins: [Class, Slider, SliderReactive, SliderPreload],
24
25
 
25
26
  props: {
26
27
  center: Boolean,
@@ -258,6 +259,25 @@ export default {
258
259
 
259
260
  return index;
260
261
  },
262
+
263
+ getAdjacentSlides() {
264
+ const { width } = dimensions(this.list);
265
+ const left = -width;
266
+ const right = width * 2;
267
+ const slideWidth = dimensions(this.slides[this.index]).width;
268
+ const slideLeft = this.center ? width / 2 - slideWidth / 2 : 0;
269
+ const slides = new Set();
270
+ for (const i of [-1, 1]) {
271
+ let currentLeft = slideLeft + (i > 0 ? slideWidth : 0);
272
+ let j = 0;
273
+ do {
274
+ const slide = this.slides[this.getIndex(this.index + i + j++ * i)];
275
+ currentLeft += dimensions(slide).width * i;
276
+ slides.add(slide);
277
+ } while (this.slides.length > j && currentLeft > left && currentLeft < right);
278
+ }
279
+ return Array.from(slides);
280
+ },
261
281
  },
262
282
  };
263
283
 
@@ -2,10 +2,11 @@ import Class from '../mixin/class';
2
2
  import Slideshow from '../mixin/slideshow';
3
3
  import Animations from './internal/slideshow-animations';
4
4
  import SliderReactive from '../mixin/slider-reactive';
5
+ import SliderPreload from './internal/slider-preload';
5
6
  import { boxModelAdjust, css } from 'uikit-util';
6
7
 
7
8
  export default {
8
- mixins: [Class, Slideshow, SliderReactive],
9
+ mixins: [Class, Slideshow, SliderReactive, SliderPreload],
9
10
 
10
11
  props: {
11
12
  ratio: String,
@@ -50,4 +51,10 @@ export default {
50
51
 
51
52
  events: ['resize'],
52
53
  },
54
+
55
+ methods: {
56
+ getAdjacentSlides() {
57
+ return [1, -1].map((i) => this.slides[this.getIndex(this.index + i)]);
58
+ },
59
+ },
53
60
  };
@@ -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,60 @@ 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 = () => setSrcAttrs(el, img.currentSrc);
176
+ attr(img, 'src', src);
177
+ return img;
178
+ }
179
+
180
+ function wrapInPicture(img, sources) {
181
+ sources = parseSources(sources);
182
+
183
+ if (sources.length) {
184
+ const picture = fragment('<picture>');
185
+ for (const attrs of sources) {
186
+ const source = fragment('<source>');
187
+ attr(source, attrs);
188
+ append(picture, source);
189
+ }
190
+ append(picture, img);
191
+ }
192
+ }
193
+
194
+ function parseSources(sources) {
195
+ if (!sources) {
196
+ return [];
197
+ }
198
+
199
+ if (startsWith(sources, '[')) {
200
+ try {
201
+ sources = JSON.parse(sources);
202
+ } catch (e) {
203
+ sources = [];
204
+ }
205
+ } else {
206
+ sources = parseOptions(sources);
190
207
  }
191
208
 
192
- return `data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}"></svg>`;
209
+ if (!isArray(sources)) {
210
+ sources = [sources];
211
+ }
212
+
213
+ return sources.filter((source) => !isEmpty(source));
193
214
  }
194
215
 
195
216
  const sizesRe = /\s*(.*?)\s*(\w+|calc\(.*?\))\s*(?:,|$)/g;
@@ -229,22 +250,16 @@ function getSourceSize(srcset, sizes) {
229
250
  return descriptors.filter((size) => size >= srcSize)[0] || descriptors.pop() || '';
230
251
  }
231
252
 
232
- function isImg(el) {
233
- return el.tagName === 'IMG';
253
+ function ensureSrcAttribute(el) {
254
+ if (isImg(el) && !hasAttr(el, 'src')) {
255
+ attr(el, 'src', 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"></svg>');
256
+ }
234
257
  }
235
258
 
236
- function currentSrc(el) {
237
- return el.currentSrc || el.src;
259
+ function isPicture(el) {
260
+ return isTag(el, 'picture');
238
261
  }
239
262
 
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 = {};
263
+ function isImg(el) {
264
+ return isTag(el, 'img');
250
265
  }
@@ -213,7 +213,7 @@ export default {
213
213
  margin,
214
214
  width: dimensions(isVisible(this.widthElement) ? this.widthElement : this.$el)
215
215
  .width,
216
- top: offsetPosition(this.placeholder)[0],
216
+ top: offsetPosition(referenceElement)[0],
217
217
  };
218
218
  },
219
219
 
@@ -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) {