@vaadin/component-base 24.0.0-alpha2 → 24.0.0-alpha4
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/index.d.ts +0 -1
- package/index.js +0 -1
- package/package.json +2 -2
- package/src/dir-mixin.d.ts +2 -0
- package/src/dir-mixin.js +8 -0
- package/src/element-mixin.js +1 -1
- package/src/slot-controller.d.ts +23 -4
- package/src/slot-controller.js +86 -34
- package/src/slot-mixin.d.ts +0 -18
- package/src/slot-mixin.js +0 -60
package/index.d.ts
CHANGED
|
@@ -8,5 +8,4 @@ export { FocusTrapController } from './src/focus-trap-controller.js';
|
|
|
8
8
|
export { KeyboardMixin } from './src/keyboard-mixin.js';
|
|
9
9
|
export { ResizeMixin } from './src/resize-mixin.js';
|
|
10
10
|
export { SlotController } from './src/slot-controller.js';
|
|
11
|
-
export { SlotMixin } from './src/slot-mixin.js';
|
|
12
11
|
export { TabindexMixin } from './src/tabindex-mixin.js';
|
package/index.js
CHANGED
|
@@ -7,5 +7,4 @@ export { FocusMixin } from './src/focus-mixin.js';
|
|
|
7
7
|
export { FocusTrapController } from './src/focus-trap-controller.js';
|
|
8
8
|
export { KeyboardMixin } from './src/keyboard-mixin.js';
|
|
9
9
|
export { SlotController } from './src/slot-controller.js';
|
|
10
|
-
export { SlotMixin } from './src/slot-mixin.js';
|
|
11
10
|
export { TabindexMixin } from './src/tabindex-mixin.js';
|
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-alpha4",
|
|
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": "66be46e82c4d0a673859fbc9bdb1581dd89f360c"
|
|
46
46
|
}
|
package/src/dir-mixin.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ import type { Constructor } from '@open-wc/dedupe-mixin';
|
|
|
11
11
|
export declare function DirMixin<T extends Constructor<HTMLElement>>(base: T): Constructor<DirMixinClass> & T;
|
|
12
12
|
|
|
13
13
|
export declare class DirMixinClass {
|
|
14
|
+
protected readonly __isRTL: boolean;
|
|
15
|
+
|
|
14
16
|
protected __getNormalizedScrollLeft(element: Element | null): number;
|
|
15
17
|
|
|
16
18
|
protected __setNormalizedScrollLeft(element: Element | null, scrollLeft: number): void;
|
package/src/dir-mixin.js
CHANGED
|
@@ -112,6 +112,14 @@ export const DirMixin = (superClass) =>
|
|
|
112
112
|
this.__unsubscribe();
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
/**
|
|
116
|
+
* @return {boolean}
|
|
117
|
+
* @protected
|
|
118
|
+
*/
|
|
119
|
+
get __isRTL() {
|
|
120
|
+
return this.getAttribute('dir') === 'rtl';
|
|
121
|
+
}
|
|
122
|
+
|
|
115
123
|
/** @protected */
|
|
116
124
|
_valueToNodeAttribute(node, value, attribute) {
|
|
117
125
|
// Override default Polymer attribute reflection to match native behavior of HTMLElement.dir property
|
package/src/element-mixin.js
CHANGED
package/src/slot-controller.d.ts
CHANGED
|
@@ -16,8 +16,16 @@ export class SlotController extends EventTarget implements ReactiveController {
|
|
|
16
16
|
*/
|
|
17
17
|
node: HTMLElement;
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* The list of slotted nodes managed by the controller.
|
|
21
|
+
* Only used when `multiple` property is set to `true`.
|
|
22
|
+
*/
|
|
23
|
+
nodes: HTMLElement[];
|
|
24
|
+
|
|
19
25
|
protected initialized: boolean;
|
|
20
26
|
|
|
27
|
+
protected multiple: boolean;
|
|
28
|
+
|
|
21
29
|
protected defaultNode: Node;
|
|
22
30
|
|
|
23
31
|
protected defaultId: string;
|
|
@@ -25,13 +33,22 @@ export class SlotController extends EventTarget implements ReactiveController {
|
|
|
25
33
|
constructor(
|
|
26
34
|
host: HTMLElement,
|
|
27
35
|
slotName: string,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
tagName?: string,
|
|
37
|
+
config?: {
|
|
38
|
+
multiple?: boolean;
|
|
39
|
+
observe?: boolean;
|
|
40
|
+
useUniqueId?: boolean;
|
|
41
|
+
initializer?(host: HTMLElement, node: HTMLElement): void;
|
|
42
|
+
},
|
|
31
43
|
);
|
|
32
44
|
|
|
33
45
|
hostConnected(): void;
|
|
34
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Return the list of nodes matching the slot managed by the controller.
|
|
49
|
+
*/
|
|
50
|
+
getSlotChildren(): Node[];
|
|
51
|
+
|
|
35
52
|
/**
|
|
36
53
|
* Return a reference to the node managed by the controller.
|
|
37
54
|
*/
|
|
@@ -39,6 +56,8 @@ export class SlotController extends EventTarget implements ReactiveController {
|
|
|
39
56
|
|
|
40
57
|
protected attachDefaultNode(): Node | undefined;
|
|
41
58
|
|
|
59
|
+
protected initAddedNode(node: Node): void;
|
|
60
|
+
|
|
42
61
|
protected initNode(node: Node): void;
|
|
43
62
|
|
|
44
63
|
/**
|
|
@@ -54,5 +73,5 @@ export class SlotController extends EventTarget implements ReactiveController {
|
|
|
54
73
|
/**
|
|
55
74
|
* Setup the observer to manage slot content changes.
|
|
56
75
|
*/
|
|
57
|
-
protected
|
|
76
|
+
protected observeSlot(): void;
|
|
58
77
|
}
|
package/src/slot-controller.js
CHANGED
|
@@ -23,13 +23,21 @@ export class SlotController extends EventTarget {
|
|
|
23
23
|
return `${prefix}-${host.localName}-${generateUniqueId()}`;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
constructor(host, slotName,
|
|
26
|
+
constructor(host, slotName, tagName, config = {}) {
|
|
27
27
|
super();
|
|
28
28
|
|
|
29
|
+
const { initializer, multiple, observe, useUniqueId } = config;
|
|
30
|
+
|
|
29
31
|
this.host = host;
|
|
30
32
|
this.slotName = slotName;
|
|
31
|
-
this.
|
|
32
|
-
this.
|
|
33
|
+
this.tagName = tagName;
|
|
34
|
+
this.observe = typeof observe === 'boolean' ? observe : true;
|
|
35
|
+
this.multiple = typeof multiple === 'boolean' ? multiple : false;
|
|
36
|
+
this.slotInitializer = initializer;
|
|
37
|
+
|
|
38
|
+
if (multiple) {
|
|
39
|
+
this.nodes = [];
|
|
40
|
+
}
|
|
33
41
|
|
|
34
42
|
// Only generate the default ID if requested by the controller.
|
|
35
43
|
if (useUniqueId) {
|
|
@@ -39,38 +47,63 @@ export class SlotController extends EventTarget {
|
|
|
39
47
|
|
|
40
48
|
hostConnected() {
|
|
41
49
|
if (!this.initialized) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (!node) {
|
|
45
|
-
node = this.attachDefaultNode();
|
|
50
|
+
if (this.multiple) {
|
|
51
|
+
this.initMultiple();
|
|
46
52
|
} else {
|
|
47
|
-
this.
|
|
48
|
-
this.initCustomNode(node);
|
|
53
|
+
this.initSingle();
|
|
49
54
|
}
|
|
50
55
|
|
|
51
|
-
this.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
this.observe();
|
|
56
|
+
if (this.observe) {
|
|
57
|
+
this.observeSlot();
|
|
58
|
+
}
|
|
55
59
|
|
|
56
60
|
this.initialized = true;
|
|
57
61
|
}
|
|
58
62
|
}
|
|
59
63
|
|
|
64
|
+
/** @protected */
|
|
65
|
+
initSingle() {
|
|
66
|
+
let node = this.getSlotChild();
|
|
67
|
+
|
|
68
|
+
if (!node) {
|
|
69
|
+
node = this.attachDefaultNode();
|
|
70
|
+
this.initNode(node);
|
|
71
|
+
} else {
|
|
72
|
+
this.node = node;
|
|
73
|
+
this.initAddedNode(node);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** @protected */
|
|
78
|
+
initMultiple() {
|
|
79
|
+
const children = this.getSlotChildren();
|
|
80
|
+
|
|
81
|
+
if (children.length === 0) {
|
|
82
|
+
const defaultNode = this.attachDefaultNode();
|
|
83
|
+
this.nodes = [defaultNode];
|
|
84
|
+
this.initNode(defaultNode);
|
|
85
|
+
} else {
|
|
86
|
+
this.nodes = children;
|
|
87
|
+
children.forEach((node) => {
|
|
88
|
+
this.initAddedNode(node);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
60
93
|
/**
|
|
61
94
|
* Create and attach default node using the slot factory.
|
|
62
95
|
* @return {Node | undefined}
|
|
63
96
|
* @protected
|
|
64
97
|
*/
|
|
65
98
|
attachDefaultNode() {
|
|
66
|
-
const { host, slotName,
|
|
99
|
+
const { host, slotName, tagName } = this;
|
|
67
100
|
|
|
68
101
|
// Check if the node was created previously and if so, reuse it.
|
|
69
102
|
let node = this.defaultNode;
|
|
70
103
|
|
|
71
104
|
// Slot factory is optional, some slots don't have default content.
|
|
72
|
-
if (!node &&
|
|
73
|
-
node =
|
|
105
|
+
if (!node && tagName) {
|
|
106
|
+
node = document.createElement(tagName);
|
|
74
107
|
if (node instanceof Element) {
|
|
75
108
|
if (slotName !== '') {
|
|
76
109
|
node.setAttribute('slot', slotName);
|
|
@@ -88,12 +121,12 @@ export class SlotController extends EventTarget {
|
|
|
88
121
|
}
|
|
89
122
|
|
|
90
123
|
/**
|
|
91
|
-
* Return
|
|
124
|
+
* Return the list of nodes matching the slot managed by the controller.
|
|
92
125
|
* @return {Node}
|
|
93
126
|
*/
|
|
94
|
-
|
|
127
|
+
getSlotChildren() {
|
|
95
128
|
const { slotName } = this;
|
|
96
|
-
return Array.from(this.host.childNodes).
|
|
129
|
+
return Array.from(this.host.childNodes).filter((node) => {
|
|
97
130
|
// Either an element (any slot) or a text node (only un-named slot).
|
|
98
131
|
return (
|
|
99
132
|
(node.nodeType === Node.ELEMENT_NODE && node.slot === slotName) ||
|
|
@@ -102,6 +135,14 @@ export class SlotController extends EventTarget {
|
|
|
102
135
|
});
|
|
103
136
|
}
|
|
104
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Return a reference to the node managed by the controller.
|
|
140
|
+
* @return {Node}
|
|
141
|
+
*/
|
|
142
|
+
getSlotChild() {
|
|
143
|
+
return this.getSlotChildren()[0];
|
|
144
|
+
}
|
|
145
|
+
|
|
105
146
|
/**
|
|
106
147
|
* @param {Node} node
|
|
107
148
|
* @protected
|
|
@@ -111,7 +152,7 @@ export class SlotController extends EventTarget {
|
|
|
111
152
|
// Don't try to bind `this` to initializer (normally it's arrow function).
|
|
112
153
|
// Instead, pass the host as a first argument to access component's state.
|
|
113
154
|
if (slotInitializer) {
|
|
114
|
-
slotInitializer(this.host
|
|
155
|
+
slotInitializer(node, this.host);
|
|
115
156
|
}
|
|
116
157
|
}
|
|
117
158
|
|
|
@@ -131,19 +172,26 @@ export class SlotController extends EventTarget {
|
|
|
131
172
|
*/
|
|
132
173
|
teardownNode(_node) {}
|
|
133
174
|
|
|
175
|
+
/** @protected */
|
|
176
|
+
initAddedNode(node) {
|
|
177
|
+
if (node !== this.defaultNode) {
|
|
178
|
+
this.initCustomNode(node);
|
|
179
|
+
this.initNode(node);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
134
183
|
/**
|
|
135
184
|
* Setup the observer to manage slot content changes.
|
|
136
185
|
* @protected
|
|
137
186
|
*/
|
|
138
|
-
|
|
187
|
+
observeSlot() {
|
|
139
188
|
const { slotName } = this;
|
|
140
189
|
const selector = slotName === '' ? 'slot:not([name])' : `slot[name=${slotName}]`;
|
|
141
190
|
const slot = this.host.shadowRoot.querySelector(selector);
|
|
142
191
|
|
|
143
192
|
this.__slotObserver = new FlattenedNodesObserver(slot, (info) => {
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
const newNode = info.addedNodes.find((node) => node !== current);
|
|
193
|
+
const current = this.multiple ? this.nodes : [this.node];
|
|
194
|
+
const newNodes = info.addedNodes.filter((node) => !current.includes(node));
|
|
147
195
|
|
|
148
196
|
if (info.removedNodes.length) {
|
|
149
197
|
info.removedNodes.forEach((node) => {
|
|
@@ -151,18 +199,22 @@ export class SlotController extends EventTarget {
|
|
|
151
199
|
});
|
|
152
200
|
}
|
|
153
201
|
|
|
154
|
-
if (
|
|
202
|
+
if (newNodes && newNodes.length > 0) {
|
|
155
203
|
// Custom node is added, remove the current one.
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (newNode !== this.defaultNode) {
|
|
163
|
-
this.initCustomNode(newNode);
|
|
204
|
+
current.forEach((node) => {
|
|
205
|
+
if (node && node.isConnected) {
|
|
206
|
+
node.parentNode.removeChild(node);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
164
209
|
|
|
165
|
-
|
|
210
|
+
if (this.multiple) {
|
|
211
|
+
this.nodes = newNodes;
|
|
212
|
+
newNodes.forEach((node) => {
|
|
213
|
+
this.initAddedNode(node);
|
|
214
|
+
});
|
|
215
|
+
} else {
|
|
216
|
+
this.node = newNodes[0];
|
|
217
|
+
this.initAddedNode(this.node);
|
|
166
218
|
}
|
|
167
219
|
}
|
|
168
220
|
});
|
package/src/slot-mixin.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright (c) 2021 - 2022 Vaadin Ltd.
|
|
4
|
-
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
-
*/
|
|
6
|
-
import type { Constructor } from '@open-wc/dedupe-mixin';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* A mixin to provide content for named slots defined by component.
|
|
10
|
-
*/
|
|
11
|
-
export declare function SlotMixin<T extends Constructor<HTMLElement>>(base: T): Constructor<SlotMixinClass> & T;
|
|
12
|
-
|
|
13
|
-
export declare class SlotMixinClass {
|
|
14
|
-
/**
|
|
15
|
-
* List of named slots to initialize.
|
|
16
|
-
*/
|
|
17
|
-
protected readonly slots: Record<string, () => HTMLElement>;
|
|
18
|
-
}
|
package/src/slot-mixin.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright (c) 2021 - 2022 Vaadin Ltd.
|
|
4
|
-
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
5
|
-
*/
|
|
6
|
-
import { dedupingMixin } from '@polymer/polymer/lib/utils/mixin.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* A mixin to provide content for named slots defined by component.
|
|
10
|
-
*
|
|
11
|
-
* @polymerMixin
|
|
12
|
-
*/
|
|
13
|
-
export const SlotMixin = dedupingMixin(
|
|
14
|
-
(superclass) =>
|
|
15
|
-
class SlotMixinClass extends superclass {
|
|
16
|
-
/**
|
|
17
|
-
* List of named slots to initialize.
|
|
18
|
-
* @protected
|
|
19
|
-
*/
|
|
20
|
-
get slots() {
|
|
21
|
-
return {};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** @protected */
|
|
25
|
-
ready() {
|
|
26
|
-
super.ready();
|
|
27
|
-
this._connectSlotMixin();
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** @private */
|
|
31
|
-
_connectSlotMixin() {
|
|
32
|
-
Object.keys(this.slots).forEach((slotName) => {
|
|
33
|
-
// Ignore labels of nested components, if any
|
|
34
|
-
const hasContent = this._getDirectSlotChild(slotName) !== undefined;
|
|
35
|
-
|
|
36
|
-
if (!hasContent) {
|
|
37
|
-
const slotFactory = this.slots[slotName];
|
|
38
|
-
const slotContent = slotFactory();
|
|
39
|
-
if (slotContent instanceof Element) {
|
|
40
|
-
if (slotName !== '') {
|
|
41
|
-
slotContent.setAttribute('slot', slotName);
|
|
42
|
-
}
|
|
43
|
-
this.appendChild(slotContent);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** @protected */
|
|
50
|
-
_getDirectSlotChild(slotName) {
|
|
51
|
-
return Array.from(this.childNodes).find((node) => {
|
|
52
|
-
// Either an element (any slot) or a text node (only un-named slot).
|
|
53
|
-
return (
|
|
54
|
-
(node.nodeType === Node.ELEMENT_NODE && node.slot === slotName) ||
|
|
55
|
-
(node.nodeType === Node.TEXT_NODE && node.textContent.trim() && slotName === '')
|
|
56
|
-
);
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
);
|