uikit 3.11.2-dev.2b60845fb → 3.11.2-dev.2f4ac8e16

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 (130) hide show
  1. package/CHANGELOG.md +32 -18
  2. package/dist/css/uikit-core-rtl.css +80 -186
  3. package/dist/css/uikit-core-rtl.min.css +1 -1
  4. package/dist/css/uikit-core.css +80 -186
  5. package/dist/css/uikit-core.min.css +1 -1
  6. package/dist/css/uikit-rtl.css +82 -192
  7. package/dist/css/uikit-rtl.min.css +1 -1
  8. package/dist/css/uikit.css +82 -192
  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 +85 -68
  21. package/dist/js/components/parallax.min.js +1 -1
  22. package/dist/js/components/slider-parallax.js +85 -68
  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 +85 -68
  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 +215 -220
  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 +397 -355
  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/img.js +129 -114
  57. package/src/js/core/modal.js +1 -2
  58. package/src/js/core/navbar.js +3 -3
  59. package/src/js/core/sticky.js +1 -1
  60. package/src/js/core/svg.js +10 -6
  61. package/src/js/core/toggle.js +2 -1
  62. package/src/js/mixin/internal/animate-slide.js +9 -12
  63. package/src/js/mixin/parallax.js +85 -68
  64. package/src/js/mixin/slider.js +8 -16
  65. package/src/js/mixin/slideshow.js +2 -2
  66. package/src/js/mixin/togglable.js +1 -2
  67. package/src/js/util/ajax.js +9 -12
  68. package/src/js/util/animation.js +7 -12
  69. package/src/js/util/dom.js +27 -30
  70. package/src/js/util/lang.js +7 -6
  71. package/src/js/util/options.js +2 -11
  72. package/src/js/util/player.js +5 -4
  73. package/src/js/util/selector.js +12 -18
  74. package/src/js/util/style.js +4 -4
  75. package/src/less/components/base.less +10 -33
  76. package/src/less/components/form-range.less +52 -97
  77. package/src/less/components/form.less +0 -1
  78. package/src/less/components/leader.less +0 -1
  79. package/src/less/components/lightbox.less +0 -1
  80. package/src/less/components/modal.less +3 -7
  81. package/src/less/components/progress.less +14 -36
  82. package/src/less/components/slider.less +0 -3
  83. package/src/less/components/slideshow.less +0 -3
  84. package/src/less/components/text.less +16 -32
  85. package/src/scss/components/base.scss +10 -33
  86. package/src/scss/components/form-range.scss +52 -97
  87. package/src/scss/components/form.scss +0 -1
  88. package/src/scss/components/leader.scss +0 -1
  89. package/src/scss/components/lightbox.scss +0 -1
  90. package/src/scss/components/modal.scss +3 -7
  91. package/src/scss/components/progress.scss +14 -36
  92. package/src/scss/components/slider.scss +0 -3
  93. package/src/scss/components/slideshow.scss +0 -3
  94. package/src/scss/components/text.scss +16 -32
  95. package/src/scss/mixins-theme.scss +1 -1
  96. package/src/scss/mixins.scss +1 -1
  97. package/src/scss/variables-theme.scss +3 -3
  98. package/src/scss/variables.scss +3 -3
  99. package/tests/align.html +10 -10
  100. package/tests/animation.html +2 -2
  101. package/tests/article.html +2 -2
  102. package/tests/base.html +3 -3
  103. package/tests/card.html +10 -10
  104. package/tests/column.html +3 -3
  105. package/tests/comment.html +9 -9
  106. package/tests/dotnav.html +3 -3
  107. package/tests/image.html +296 -64
  108. package/tests/images/image-type.avif +0 -0
  109. package/tests/images/image-type.jpeg +0 -0
  110. package/tests/images/image-type.webp +0 -0
  111. package/tests/index.html +8 -8
  112. package/tests/lightbox.html +10 -10
  113. package/tests/marker.html +2 -2
  114. package/tests/modal.html +8 -9
  115. package/tests/navbar.html +2 -2
  116. package/tests/overlay.html +7 -7
  117. package/tests/parallax.html +14 -5
  118. package/tests/position.html +12 -12
  119. package/tests/slidenav.html +12 -12
  120. package/tests/slider.html +20 -20
  121. package/tests/sortable.html +1 -1
  122. package/tests/sticky-parallax.html +47 -62
  123. package/tests/svg.html +6 -6
  124. package/tests/table.html +11 -11
  125. package/tests/thumbnav.html +12 -12
  126. package/tests/transition.html +30 -30
  127. package/tests/utility.html +33 -33
  128. package/tests/video.html +1 -1
  129. package/tests/width.html +1 -1
  130. 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,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
  }
@@ -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
 
@@ -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) {
@@ -1,5 +1,4 @@
1
1
  import {
2
- assign,
3
2
  children,
4
3
  css,
5
4
  fastdom,
@@ -44,7 +43,7 @@ export default function (action, target, duration) {
44
43
 
45
44
  // Reset to previous state
46
45
  nodes.forEach((el, i) => propsFrom[i] && css(el, propsFrom[i]));
47
- css(target, assign({ display: 'block' }, targetProps));
46
+ css(target, { display: 'block', ...targetProps });
48
47
 
49
48
  // Start transitions on next frame
50
49
  requestAnimationFrame(() => {
@@ -76,16 +75,14 @@ function getProps(el, opacity) {
76
75
  const zIndex = css(el, 'zIndex');
77
76
 
78
77
  return isVisible(el)
79
- ? assign(
80
- {
81
- display: '',
82
- opacity: opacity ? css(el, 'opacity') : '0',
83
- pointerEvents: 'none',
84
- position: 'absolute',
85
- zIndex: zIndex === 'auto' ? index(el) : zIndex,
86
- },
87
- getPositionWithMargin(el)
88
- )
78
+ ? {
79
+ display: '',
80
+ opacity: opacity ? css(el, 'opacity') : '0',
81
+ pointerEvents: 'none',
82
+ position: 'absolute',
83
+ zIndex: zIndex === 'auto' ? index(el) : zIndex,
84
+ ...getPositionWithMargin(el),
85
+ }
89
86
  : false;
90
87
  }
91
88