@vaadin/component-base 24.0.0-alpha5 → 24.0.0-alpha7
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 +4 -4
- package/src/iron-list-core.js +6 -6
- package/src/overflow-controller.js +2 -2
- package/src/polylit-mixin.js +2 -2
- package/src/slot-controller.d.ts +9 -0
- package/src/slot-controller.js +13 -6
- package/src/slot-observe-controller.d.ts +28 -0
- package/src/slot-observe-controller.js +176 -0
- package/src/virtualizer-iron-list-adapter.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vaadin/component-base",
|
|
3
|
-
"version": "24.0.0-
|
|
3
|
+
"version": "24.0.0-alpha7",
|
|
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": "aeb4535336813636736759e0a5de148b26bfc3b6"
|
|
46
46
|
}
|
package/src/element-mixin.js
CHANGED
|
@@ -15,14 +15,14 @@ import { DirMixin } from './dir-mixin.js';
|
|
|
15
15
|
// for buttons that are based on `[role=button]` e.g vaadin-button.
|
|
16
16
|
setCancelSyntheticClickEvents(false);
|
|
17
17
|
|
|
18
|
-
window.Vaadin
|
|
18
|
+
window.Vaadin ||= {};
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Array of Vaadin custom element classes that have been finalized.
|
|
22
22
|
*/
|
|
23
|
-
window.Vaadin.registrations
|
|
23
|
+
window.Vaadin.registrations ||= [];
|
|
24
24
|
|
|
25
|
-
window.Vaadin.developmentModeCallback
|
|
25
|
+
window.Vaadin.developmentModeCallback ||= {};
|
|
26
26
|
|
|
27
27
|
window.Vaadin.developmentModeCallback['vaadin-usage-statistics'] = function () {
|
|
28
28
|
usageStatistics();
|
|
@@ -39,7 +39,7 @@ const registered = new Set();
|
|
|
39
39
|
export const ElementMixin = (superClass) =>
|
|
40
40
|
class VaadinElementMixin extends DirMixin(superClass) {
|
|
41
41
|
static get version() {
|
|
42
|
-
return '24.0.0-
|
|
42
|
+
return '24.0.0-alpha7';
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/** @protected */
|
package/src/iron-list-core.js
CHANGED
|
@@ -491,9 +491,9 @@ export const ironList = {
|
|
|
491
491
|
this._physicalIndexForKey = {};
|
|
492
492
|
this._firstVisibleIndexVal = null;
|
|
493
493
|
this._lastVisibleIndexVal = null;
|
|
494
|
-
this._physicalCount
|
|
495
|
-
this._physicalItems
|
|
496
|
-
this._physicalSizes
|
|
494
|
+
this._physicalCount ||= 0;
|
|
495
|
+
this._physicalItems ||= [];
|
|
496
|
+
this._physicalSizes ||= [];
|
|
497
497
|
this._physicalStart = 0;
|
|
498
498
|
if (this._scrollTop > this._scrollOffset) {
|
|
499
499
|
this._resetScrollPosition(0);
|
|
@@ -639,8 +639,8 @@ export const ironList = {
|
|
|
639
639
|
this._physicalBottom +
|
|
640
640
|
Math.max(this._virtualCount - this._physicalCount - this._virtualStart, 0) * this._physicalAverage;
|
|
641
641
|
|
|
642
|
-
forceUpdate
|
|
643
|
-
forceUpdate
|
|
642
|
+
forceUpdate ||= this._scrollHeight === 0;
|
|
643
|
+
forceUpdate ||= this._scrollPosition >= this._estScrollHeight - this._physicalSize;
|
|
644
644
|
// Amortize height adjustment, so it won't trigger large repaints too often.
|
|
645
645
|
if (forceUpdate || Math.abs(this._estScrollHeight - this._scrollHeight) >= this._viewportHeight) {
|
|
646
646
|
this.$.items.style.height = `${this._estScrollHeight}px`;
|
|
@@ -740,7 +740,7 @@ export const ironList = {
|
|
|
740
740
|
},
|
|
741
741
|
|
|
742
742
|
_debounce(name, cb, asyncModule) {
|
|
743
|
-
this._debouncers
|
|
743
|
+
this._debouncers ||= {};
|
|
744
744
|
this._debouncers[name] = Debouncer.debounce(this._debouncers[name], asyncModule, cb.bind(this));
|
|
745
745
|
enqueueDebouncer(this._debouncers[name]);
|
|
746
746
|
},
|
|
@@ -92,7 +92,7 @@ export class OverflowController {
|
|
|
92
92
|
overflow += ' top';
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
if (target.scrollTop < target.scrollHeight - target.clientHeight) {
|
|
95
|
+
if (Math.ceil(target.scrollTop) < Math.ceil(target.scrollHeight - target.clientHeight)) {
|
|
96
96
|
overflow += ' bottom';
|
|
97
97
|
}
|
|
98
98
|
|
|
@@ -101,7 +101,7 @@ export class OverflowController {
|
|
|
101
101
|
overflow += ' start';
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
if (scrollLeft < target.scrollWidth - target.clientWidth) {
|
|
104
|
+
if (Math.ceil(scrollLeft) < Math.ceil(target.scrollWidth - target.clientWidth)) {
|
|
105
105
|
overflow += ' end';
|
|
106
106
|
}
|
|
107
107
|
|
package/src/polylit-mixin.js
CHANGED
|
@@ -10,7 +10,7 @@ const caseMap = {};
|
|
|
10
10
|
const CAMEL_TO_DASH = /([A-Z])/g;
|
|
11
11
|
|
|
12
12
|
function camelToDash(camel) {
|
|
13
|
-
caseMap[camel]
|
|
13
|
+
caseMap[camel] ||= camel.replace(CAMEL_TO_DASH, '-$1').toLowerCase();
|
|
14
14
|
return caseMap[camel];
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -169,7 +169,7 @@ const PolylitMixinImplementation = (superclass) => {
|
|
|
169
169
|
firstUpdated() {
|
|
170
170
|
super.firstUpdated();
|
|
171
171
|
|
|
172
|
-
this.$
|
|
172
|
+
this.$ ||= {};
|
|
173
173
|
this.shadowRoot.querySelectorAll('[id]').forEach((node) => {
|
|
174
174
|
this.$[node.id] = node;
|
|
175
175
|
});
|
package/src/slot-controller.d.ts
CHANGED
|
@@ -54,10 +54,19 @@ export class SlotController extends EventTarget implements ReactiveController {
|
|
|
54
54
|
*/
|
|
55
55
|
getSlotChild(): Node;
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Create and attach default node using the provided tag name, if any.
|
|
59
|
+
*/
|
|
57
60
|
protected attachDefaultNode(): Node | undefined;
|
|
58
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Run both `initCustomNode` and `initNode` for a custom slotted node.
|
|
64
|
+
*/
|
|
59
65
|
protected initAddedNode(node: Node): void;
|
|
60
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Run `slotInitializer` for the node managed by the controller.
|
|
69
|
+
*/
|
|
61
70
|
protected initNode(node: Node): void;
|
|
62
71
|
|
|
63
72
|
/**
|
package/src/slot-controller.js
CHANGED
|
@@ -14,12 +14,12 @@ export class SlotController extends EventTarget {
|
|
|
14
14
|
/**
|
|
15
15
|
* Ensure that every instance has unique ID.
|
|
16
16
|
*
|
|
17
|
-
* @param {string} slotName
|
|
18
17
|
* @param {HTMLElement} host
|
|
18
|
+
* @param {string} slotName
|
|
19
19
|
* @return {string}
|
|
20
20
|
* @protected
|
|
21
21
|
*/
|
|
22
|
-
static generateId(
|
|
22
|
+
static generateId(host, slotName) {
|
|
23
23
|
const prefix = slotName || 'default';
|
|
24
24
|
return `${prefix}-${host.localName}-${generateUniqueId()}`;
|
|
25
25
|
}
|
|
@@ -42,7 +42,7 @@ export class SlotController extends EventTarget {
|
|
|
42
42
|
|
|
43
43
|
// Only generate the default ID if requested by the controller.
|
|
44
44
|
if (useUniqueId) {
|
|
45
|
-
this.defaultId =
|
|
45
|
+
this.defaultId = this.constructor.generateId(host, slotName);
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
@@ -92,7 +92,7 @@ export class SlotController extends EventTarget {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
/**
|
|
95
|
-
* Create and attach default node using the
|
|
95
|
+
* Create and attach default node using the provided tag name, if any.
|
|
96
96
|
* @return {Node | undefined}
|
|
97
97
|
* @protected
|
|
98
98
|
*/
|
|
@@ -102,7 +102,7 @@ export class SlotController extends EventTarget {
|
|
|
102
102
|
// Check if the node was created previously and if so, reuse it.
|
|
103
103
|
let node = this.defaultNode;
|
|
104
104
|
|
|
105
|
-
//
|
|
105
|
+
// Tag name is optional, sometimes we don't init default content.
|
|
106
106
|
if (!node && tagName) {
|
|
107
107
|
node = document.createElement(tagName);
|
|
108
108
|
if (node instanceof Element) {
|
|
@@ -145,6 +145,8 @@ export class SlotController extends EventTarget {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
/**
|
|
148
|
+
* Run `slotInitializer` for the node managed by the controller.
|
|
149
|
+
*
|
|
148
150
|
* @param {Node} node
|
|
149
151
|
* @protected
|
|
150
152
|
*/
|
|
@@ -173,7 +175,12 @@ export class SlotController extends EventTarget {
|
|
|
173
175
|
*/
|
|
174
176
|
teardownNode(_node) {}
|
|
175
177
|
|
|
176
|
-
/**
|
|
178
|
+
/**
|
|
179
|
+
* Run both `initCustomNode` and `initNode` for a custom slotted node.
|
|
180
|
+
*
|
|
181
|
+
* @param {Node} node
|
|
182
|
+
* @protected
|
|
183
|
+
*/
|
|
177
184
|
initAddedNode(node) {
|
|
178
185
|
if (node !== this.defaultNode) {
|
|
179
186
|
this.initCustomNode(node);
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2022 Vaadin Ltd.
|
|
4
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
+
*/
|
|
6
|
+
import { SlotController } from './slot-controller.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A controller that observes slotted element mutations, especially ID attribute
|
|
10
|
+
* and the text content, and fires an event to notify host element about those.
|
|
11
|
+
*/
|
|
12
|
+
export class SlotObserveController extends SlotController {
|
|
13
|
+
/**
|
|
14
|
+
* Setup the mutation observer on the node to update ID and notify host.
|
|
15
|
+
* Node doesn't get observed automatically until this method is called.
|
|
16
|
+
*/
|
|
17
|
+
protected observeNode(node: Node): void;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Override to restore default node when a custom one is removed.
|
|
21
|
+
*/
|
|
22
|
+
protected restoreDefaultNode(): void;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Override to update default node text on property change.
|
|
26
|
+
*/
|
|
27
|
+
protected updateDefaultNode(node: Node): void;
|
|
28
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright (c) 2022 Vaadin Ltd.
|
|
4
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
+
*/
|
|
6
|
+
import { SlotController } from './slot-controller.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A controller that observes slotted element mutations, especially ID attribute
|
|
10
|
+
* and the text content, and fires an event to notify host element about those.
|
|
11
|
+
*/
|
|
12
|
+
export class SlotObserveController extends SlotController {
|
|
13
|
+
constructor(host, slot, tagName, config = {}) {
|
|
14
|
+
super(host, slot, tagName, { ...config, useUniqueId: true });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Override to initialize the newly added custom node.
|
|
19
|
+
*
|
|
20
|
+
* @param {Node} node
|
|
21
|
+
* @protected
|
|
22
|
+
* @override
|
|
23
|
+
*/
|
|
24
|
+
initCustomNode(node) {
|
|
25
|
+
this.__updateNodeId(node);
|
|
26
|
+
this.__notifyChange(node);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Override to notify the controller host about removal of
|
|
31
|
+
* the custom node, and to apply the default one if needed.
|
|
32
|
+
*
|
|
33
|
+
* @param {Node} _node
|
|
34
|
+
* @protected
|
|
35
|
+
* @override
|
|
36
|
+
*/
|
|
37
|
+
teardownNode(_node) {
|
|
38
|
+
const node = this.getSlotChild();
|
|
39
|
+
|
|
40
|
+
// Custom node is added to the slot
|
|
41
|
+
if (node && node !== this.defaultNode) {
|
|
42
|
+
this.__notifyChange(node);
|
|
43
|
+
} else {
|
|
44
|
+
this.restoreDefaultNode();
|
|
45
|
+
this.updateDefaultNode(this.node);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Override method inherited from `SlotMixin`
|
|
51
|
+
* to set ID attribute on the default node.
|
|
52
|
+
*
|
|
53
|
+
* @return {Node}
|
|
54
|
+
* @protected
|
|
55
|
+
* @override
|
|
56
|
+
*/
|
|
57
|
+
attachDefaultNode() {
|
|
58
|
+
const node = super.attachDefaultNode();
|
|
59
|
+
|
|
60
|
+
if (node) {
|
|
61
|
+
this.__updateNodeId(node);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return node;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Override to restore default node when a custom one is removed.
|
|
69
|
+
*
|
|
70
|
+
* @protected
|
|
71
|
+
*/
|
|
72
|
+
restoreDefaultNode() {
|
|
73
|
+
// To be implemented
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Override to update default node text on property change.
|
|
78
|
+
*
|
|
79
|
+
* @param {Node} node
|
|
80
|
+
* @protected
|
|
81
|
+
*/
|
|
82
|
+
updateDefaultNode(node) {
|
|
83
|
+
this.__notifyChange(node);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Setup the mutation observer on the node to update ID and notify host.
|
|
88
|
+
* Node doesn't get observed automatically until this method is called.
|
|
89
|
+
*
|
|
90
|
+
* @param {Node} node
|
|
91
|
+
* @protected
|
|
92
|
+
*/
|
|
93
|
+
observeNode(node) {
|
|
94
|
+
// Stop observing the previous node, if any.
|
|
95
|
+
if (this.__nodeObserver) {
|
|
96
|
+
this.__nodeObserver.disconnect();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this.__nodeObserver = new MutationObserver((mutations) => {
|
|
100
|
+
mutations.forEach((mutation) => {
|
|
101
|
+
const target = mutation.target;
|
|
102
|
+
|
|
103
|
+
// Ensure the mutation target is the currently connected node
|
|
104
|
+
// to ignore async mutations dispatched for removed element.
|
|
105
|
+
const isCurrentNodeMutation = target === this.node;
|
|
106
|
+
|
|
107
|
+
if (mutation.type === 'attributes') {
|
|
108
|
+
// We use attributeFilter to only observe ID mutation,
|
|
109
|
+
// no need to check for attribute name separately.
|
|
110
|
+
if (isCurrentNodeMutation) {
|
|
111
|
+
this.__updateNodeId(target);
|
|
112
|
+
}
|
|
113
|
+
} else if (isCurrentNodeMutation || target.parentElement === this.node) {
|
|
114
|
+
// Node text content has changed.
|
|
115
|
+
this.__notifyChange(this.node);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Observe changes to node ID attribute, text content and children.
|
|
121
|
+
this.__nodeObserver.observe(node, {
|
|
122
|
+
attributes: true,
|
|
123
|
+
attributeFilter: ['id'],
|
|
124
|
+
childList: true,
|
|
125
|
+
subtree: true,
|
|
126
|
+
characterData: true,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Returns true if a node is an HTML element with children,
|
|
132
|
+
* or is a defined custom element, or has non-empty text.
|
|
133
|
+
*
|
|
134
|
+
* @param {Node} node
|
|
135
|
+
* @return {boolean}
|
|
136
|
+
* @private
|
|
137
|
+
*/
|
|
138
|
+
__hasContent(node) {
|
|
139
|
+
if (!node) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
(node.nodeType === Node.ELEMENT_NODE && (customElements.get(node.localName) || node.children.length > 0)) ||
|
|
145
|
+
(node.textContent && node.textContent.trim() !== '')
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Fire an event to notify the controller host about node changes.
|
|
151
|
+
*
|
|
152
|
+
* @param {Node} node
|
|
153
|
+
* @private
|
|
154
|
+
*/
|
|
155
|
+
__notifyChange(node) {
|
|
156
|
+
this.dispatchEvent(
|
|
157
|
+
new CustomEvent('slot-content-changed', {
|
|
158
|
+
detail: { hasContent: this.__hasContent(node), node },
|
|
159
|
+
}),
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Set default ID on the node in case it is an HTML element.
|
|
165
|
+
*
|
|
166
|
+
* @param {Node} node
|
|
167
|
+
* @private
|
|
168
|
+
*/
|
|
169
|
+
__updateNodeId(node) {
|
|
170
|
+
// When in multiple mode, only set ID attribute on the element in default slot.
|
|
171
|
+
const isFirstNode = !this.nodes || node === this.nodes[0];
|
|
172
|
+
if (node.nodeType === Node.ELEMENT_NODE && isFirstNode && !node.id) {
|
|
173
|
+
node.id = this.defaultId;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
@@ -376,7 +376,7 @@ export class IronListAdapter {
|
|
|
376
376
|
deltaY *= this._scrollPageHeight;
|
|
377
377
|
}
|
|
378
378
|
|
|
379
|
-
this._deltaYAcc
|
|
379
|
+
this._deltaYAcc ||= 0;
|
|
380
380
|
|
|
381
381
|
if (this._wheelAnimationFrame) {
|
|
382
382
|
// Accumulate wheel delta while a frame is being processed
|