@vaadin/component-base 23.6.3 → 23.6.5
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.
- package/package.json +2 -2
- package/src/element-mixin.js +1 -1
- package/src/object-utils.d.ts +44 -0
- package/src/object-utils.js +116 -0
- package/src/virtualizer-iron-list-adapter.js +41 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/component-base",
|
|
3
|
-
"version": "23.6.
|
|
3
|
+
"version": "23.6.5",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -42,5 +42,5 @@
|
|
|
42
42
|
"@vaadin/testing-helpers": "^0.3.2",
|
|
43
43
|
"sinon": "^13.0.2"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "d55853f02f62ce8a506a3ffd4f4a91dfb5cc66a2"
|
|
46
46
|
}
|
package/src/element-mixin.js
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2000 - 2024 Vaadin Ltd.
|
|
4
|
+
*
|
|
5
|
+
* This program is available under Vaadin Commercial License and Service Terms.
|
|
6
|
+
*
|
|
7
|
+
*
|
|
8
|
+
* See https://vaadin.com/commercial-license-and-service-terms for the full
|
|
9
|
+
* license.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Recursively copies own properties of `source` into `target` and returns
|
|
14
|
+
* `target`. Plain objects are merged, other values are assigned as they are.
|
|
15
|
+
* An object is plain when it inherits from `Object.prototype` or from nothing,
|
|
16
|
+
* so values such as a `Date` or a class instance are assigned, not merged.
|
|
17
|
+
*
|
|
18
|
+
* Merges a single source. Use `deepMergePartials()` to merge several objects,
|
|
19
|
+
* or to merge objects that only provide some of the properties.
|
|
20
|
+
*
|
|
21
|
+
* Both arguments are expected to be plain objects. When either of them is not,
|
|
22
|
+
* `target` is returned without changes. A property of the target that is not a
|
|
23
|
+
* plain object is replaced with the merged object, unlike the arguments.
|
|
24
|
+
*
|
|
25
|
+
* Keys that would modify `Object.prototype`, such as `__proto__`, are ignored.
|
|
26
|
+
*/
|
|
27
|
+
export function deepMerge<T extends object>(target: T, source: object): T;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Recursively merges partial objects into `target` in order and returns
|
|
31
|
+
* `target`, so that a later source overrides an earlier one.
|
|
32
|
+
*
|
|
33
|
+
* Values that are `null` or `undefined` are skipped, so a source that only
|
|
34
|
+
* provides some of the properties does not remove the others. For the same
|
|
35
|
+
* reason, a property that the target already has is not replaced with an
|
|
36
|
+
* object when the source has one for the same key. Arrays are copied one level
|
|
37
|
+
* deep, so that the result does not share an array with any of the sources.
|
|
38
|
+
*
|
|
39
|
+
* Sources that are not plain objects are ignored. When `target` is not a plain
|
|
40
|
+
* object, it is returned without changes.
|
|
41
|
+
*
|
|
42
|
+
* Keys that would modify `Object.prototype`, such as `__proto__`, are ignored.
|
|
43
|
+
*/
|
|
44
|
+
export function deepMergePartials<T extends object>(target: T, ...sources: object[]): T;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2000 - 2024 Vaadin Ltd.
|
|
4
|
+
*
|
|
5
|
+
* This program is available under Vaadin Commercial License and Service Terms.
|
|
6
|
+
*
|
|
7
|
+
*
|
|
8
|
+
* See https://vaadin.com/commercial-license-and-service-terms for the full
|
|
9
|
+
* license.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Keys that are not copied while merging, as assigning them would modify
|
|
14
|
+
* `Object.prototype` instead of the merge target, and so affect every
|
|
15
|
+
* object in the application.
|
|
16
|
+
*/
|
|
17
|
+
const IGNORED_KEYS = ['__proto__', 'constructor', 'prototype'];
|
|
18
|
+
|
|
19
|
+
const { hasOwnProperty } = Object.prototype;
|
|
20
|
+
|
|
21
|
+
const isPlainObject = (value) => {
|
|
22
|
+
if (!value || typeof value !== 'object') {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
const prototype = Object.getPrototypeOf(value);
|
|
26
|
+
return prototype === Object.prototype || prototype === null;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Merges `source` into `target`. With `partial`, the source is treated as an
|
|
31
|
+
* object that may provide only some of the properties: nullish values are
|
|
32
|
+
* skipped and arrays are copied instead of shared.
|
|
33
|
+
*/
|
|
34
|
+
function merge(target, source, partial) {
|
|
35
|
+
if (!isPlainObject(target) || !isPlainObject(source)) {
|
|
36
|
+
return target;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
Object.keys(source).forEach((key) => {
|
|
40
|
+
if (IGNORED_KEYS.includes(key)) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const value = source[key];
|
|
45
|
+
|
|
46
|
+
if (isPlainObject(value)) {
|
|
47
|
+
// Only merge into an own plain object, so that the merge can never
|
|
48
|
+
// continue into an object inherited from the prototype chain.
|
|
49
|
+
if (!hasOwnProperty.call(target, key) || !isPlainObject(target[key])) {
|
|
50
|
+
// With `partial`, a value that the target already has is kept, so that
|
|
51
|
+
// a source property of an unexpected type does not remove a default.
|
|
52
|
+
if (partial && hasOwnProperty.call(target, key) && target[key]) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
target[key] = {};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
merge(target[key], value, partial);
|
|
60
|
+
} else if (partial && Array.isArray(value)) {
|
|
61
|
+
target[key] = [...value];
|
|
62
|
+
} else if (!partial || (value !== undefined && value !== null)) {
|
|
63
|
+
target[key] = value;
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
return target;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Recursively copies own properties of `source` into `target` and returns
|
|
72
|
+
* `target`. Plain objects are merged, other values are assigned as they are.
|
|
73
|
+
* An object is plain when it inherits from `Object.prototype` or from nothing,
|
|
74
|
+
* so values such as a `Date` or a class instance are assigned, not merged.
|
|
75
|
+
*
|
|
76
|
+
* Merges a single source. Use `deepMergePartials()` to merge several objects,
|
|
77
|
+
* or to merge objects that only provide some of the properties.
|
|
78
|
+
*
|
|
79
|
+
* Both arguments are expected to be plain objects. When either of them is not,
|
|
80
|
+
* `target` is returned without changes. A property of the target that is not a
|
|
81
|
+
* plain object is replaced with the merged object, unlike the arguments.
|
|
82
|
+
*
|
|
83
|
+
* Keys that would modify `Object.prototype`, such as `__proto__`, are ignored.
|
|
84
|
+
*
|
|
85
|
+
* @param {object} target the object to merge into, modified in place
|
|
86
|
+
* @param {object} source the object to copy the properties from
|
|
87
|
+
* @return {object} the `target` object
|
|
88
|
+
*/
|
|
89
|
+
export function deepMerge(target, source) {
|
|
90
|
+
return merge(target, source, false);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Recursively merges partial objects into `target` in order and returns
|
|
95
|
+
* `target`, so that a later source overrides an earlier one.
|
|
96
|
+
*
|
|
97
|
+
* Values that are `null` or `undefined` are skipped, so a source that only
|
|
98
|
+
* provides some of the properties does not remove the others. For the same
|
|
99
|
+
* reason, a property that the target already has is not replaced with an
|
|
100
|
+
* object when the source has one for the same key. Arrays are copied one level
|
|
101
|
+
* deep, so that the result does not share an array with any of the sources.
|
|
102
|
+
*
|
|
103
|
+
* Sources that are not plain objects are ignored. When `target` is not a plain
|
|
104
|
+
* object, it is returned without changes.
|
|
105
|
+
*
|
|
106
|
+
* Keys that would modify `Object.prototype`, such as `__proto__`, are ignored.
|
|
107
|
+
*
|
|
108
|
+
* @param {object} target the object to merge into, modified in place
|
|
109
|
+
* @param {...object} sources the objects to copy the properties from
|
|
110
|
+
* @return {object} the `target` object
|
|
111
|
+
*/
|
|
112
|
+
export function deepMergePartials(target, ...sources) {
|
|
113
|
+
sources.forEach((source) => merge(target, source, true));
|
|
114
|
+
|
|
115
|
+
return target;
|
|
116
|
+
}
|
|
@@ -139,11 +139,15 @@ export class IronListAdapter {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
update(startIndex = 0, endIndex = this.size - 1) {
|
|
142
|
+
const updatedElements = [];
|
|
142
143
|
this.__getVisibleElements().forEach((el) => {
|
|
143
144
|
if (el.__virtualIndex >= startIndex && el.__virtualIndex <= endIndex) {
|
|
144
145
|
this.__updateElement(el, el.__virtualIndex, true);
|
|
146
|
+
updatedElements.push(el);
|
|
145
147
|
}
|
|
146
148
|
});
|
|
149
|
+
|
|
150
|
+
this.__afterElementsUpdated(updatedElements);
|
|
147
151
|
}
|
|
148
152
|
|
|
149
153
|
/**
|
|
@@ -206,28 +210,40 @@ export class IronListAdapter {
|
|
|
206
210
|
this.updateElement(el, index);
|
|
207
211
|
el.__lastUpdatedIndex = index;
|
|
208
212
|
}
|
|
213
|
+
}
|
|
209
214
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
215
|
+
/**
|
|
216
|
+
* Called synchronously right after elements have been updated.
|
|
217
|
+
* This is a good place to do any post-update work.
|
|
218
|
+
*
|
|
219
|
+
* @param {!Array<!HTMLElement>} updatedElements
|
|
220
|
+
*/
|
|
221
|
+
__afterElementsUpdated(updatedElements) {
|
|
222
|
+
updatedElements.forEach((el) => {
|
|
223
|
+
const elementHeight = el.offsetHeight;
|
|
224
|
+
if (elementHeight === 0) {
|
|
225
|
+
// If the elements have 0 height after update (for example due to lazy rendering),
|
|
226
|
+
// it results in iron-list requesting to create an unlimited count of elements.
|
|
227
|
+
// Assign a temporary placeholder sizing to elements that would otherwise end up having
|
|
228
|
+
// no height.
|
|
229
|
+
el.style.paddingTop = `${this.__placeholderHeight}px`;
|
|
230
|
+
|
|
231
|
+
// Manually schedule the resize handler to make sure the placeholder padding is
|
|
232
|
+
// cleared in case the resize observer never triggers.
|
|
233
|
+
this.__placeholderClearDebouncer = Debouncer.debounce(this.__placeholderClearDebouncer, animationFrame, () =>
|
|
234
|
+
this._resizeHandler(),
|
|
235
|
+
);
|
|
236
|
+
} else {
|
|
237
|
+
// Add element height to the queue
|
|
238
|
+
this.__elementHeightQueue.push(elementHeight);
|
|
239
|
+
this.__elementHeightQueue.shift();
|
|
240
|
+
|
|
241
|
+
// Calculate new placeholder height based on the average of the defined values in the
|
|
242
|
+
// element height queue
|
|
243
|
+
const filteredHeights = this.__elementHeightQueue.filter((h) => h !== undefined);
|
|
244
|
+
this.__placeholderHeight = Math.round(filteredHeights.reduce((a, b) => a + b, 0) / filteredHeights.length);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
231
247
|
}
|
|
232
248
|
|
|
233
249
|
__getIndexScrollOffset(index) {
|
|
@@ -352,16 +368,20 @@ export class IronListAdapter {
|
|
|
352
368
|
|
|
353
369
|
/** @private */
|
|
354
370
|
_assignModels(itemSet) {
|
|
371
|
+
const updatedElements = [];
|
|
355
372
|
this._iterateItems((pidx, vidx) => {
|
|
356
373
|
const el = this._physicalItems[pidx];
|
|
357
374
|
el.hidden = vidx >= this.size;
|
|
358
375
|
if (!el.hidden) {
|
|
359
376
|
el.__virtualIndex = vidx + (this._vidxOffset || 0);
|
|
360
377
|
this.__updateElement(el, el.__virtualIndex);
|
|
378
|
+
updatedElements.push(el);
|
|
361
379
|
} else {
|
|
362
380
|
delete el.__lastUpdatedIndex;
|
|
363
381
|
}
|
|
364
382
|
}, itemSet);
|
|
383
|
+
|
|
384
|
+
this.__afterElementsUpdated(updatedElements);
|
|
365
385
|
}
|
|
366
386
|
|
|
367
387
|
/** @private */
|