@vaadin/component-base 24.0.0-alpha3 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaadin/component-base",
3
- "version": "24.0.0-alpha3",
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": "7a013a3c5a56abd61dd4f7773c6ec77c3541bdf2"
45
+ "gitHead": "66be46e82c4d0a673859fbc9bdb1581dd89f360c"
46
46
  }
@@ -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
@@ -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-alpha3';
42
+ return '24.0.0-alpha4';
43
43
  }
44
44
 
45
45
  /** @protected */
@@ -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;
@@ -27,6 +35,7 @@ export class SlotController extends EventTarget implements ReactiveController {
27
35
  slotName: string,
28
36
  tagName?: string,
29
37
  config?: {
38
+ multiple?: boolean;
30
39
  observe?: boolean;
31
40
  useUniqueId?: boolean;
32
41
  initializer?(host: HTMLElement, node: HTMLElement): void;
@@ -35,6 +44,11 @@ export class SlotController extends EventTarget implements ReactiveController {
35
44
 
36
45
  hostConnected(): void;
37
46
 
47
+ /**
48
+ * Return the list of nodes matching the slot managed by the controller.
49
+ */
50
+ getSlotChildren(): Node[];
51
+
38
52
  /**
39
53
  * Return a reference to the node managed by the controller.
40
54
  */
@@ -42,6 +56,8 @@ export class SlotController extends EventTarget implements ReactiveController {
42
56
 
43
57
  protected attachDefaultNode(): Node | undefined;
44
58
 
59
+ protected initAddedNode(node: Node): void;
60
+
45
61
  protected initNode(node: Node): void;
46
62
 
47
63
  /**
@@ -26,14 +26,19 @@ export class SlotController extends EventTarget {
26
26
  constructor(host, slotName, tagName, config = {}) {
27
27
  super();
28
28
 
29
- const { initializer, observe, useUniqueId } = config;
29
+ const { initializer, multiple, observe, useUniqueId } = config;
30
30
 
31
31
  this.host = host;
32
32
  this.slotName = slotName;
33
33
  this.tagName = tagName;
34
34
  this.observe = typeof observe === 'boolean' ? observe : true;
35
+ this.multiple = typeof multiple === 'boolean' ? multiple : false;
35
36
  this.slotInitializer = initializer;
36
37
 
38
+ if (multiple) {
39
+ this.nodes = [];
40
+ }
41
+
37
42
  // Only generate the default ID if requested by the controller.
38
43
  if (useUniqueId) {
39
44
  this.defaultId = SlotController.generateId(slotName, host);
@@ -42,17 +47,12 @@ export class SlotController extends EventTarget {
42
47
 
43
48
  hostConnected() {
44
49
  if (!this.initialized) {
45
- let node = this.getSlotChild();
46
-
47
- if (!node) {
48
- node = this.attachDefaultNode();
50
+ if (this.multiple) {
51
+ this.initMultiple();
49
52
  } else {
50
- this.node = node;
51
- this.initCustomNode(node);
53
+ this.initSingle();
52
54
  }
53
55
 
54
- this.initNode(node);
55
-
56
56
  if (this.observe) {
57
57
  this.observeSlot();
58
58
  }
@@ -61,6 +61,35 @@ export class SlotController extends EventTarget {
61
61
  }
62
62
  }
63
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
+
64
93
  /**
65
94
  * Create and attach default node using the slot factory.
66
95
  * @return {Node | undefined}
@@ -92,12 +121,12 @@ export class SlotController extends EventTarget {
92
121
  }
93
122
 
94
123
  /**
95
- * Return a reference to the node managed by the controller.
124
+ * Return the list of nodes matching the slot managed by the controller.
96
125
  * @return {Node}
97
126
  */
98
- getSlotChild() {
127
+ getSlotChildren() {
99
128
  const { slotName } = this;
100
- return Array.from(this.host.childNodes).find((node) => {
129
+ return Array.from(this.host.childNodes).filter((node) => {
101
130
  // Either an element (any slot) or a text node (only un-named slot).
102
131
  return (
103
132
  (node.nodeType === Node.ELEMENT_NODE && node.slot === slotName) ||
@@ -106,6 +135,14 @@ export class SlotController extends EventTarget {
106
135
  });
107
136
  }
108
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
+
109
146
  /**
110
147
  * @param {Node} node
111
148
  * @protected
@@ -135,6 +172,14 @@ export class SlotController extends EventTarget {
135
172
  */
136
173
  teardownNode(_node) {}
137
174
 
175
+ /** @protected */
176
+ initAddedNode(node) {
177
+ if (node !== this.defaultNode) {
178
+ this.initCustomNode(node);
179
+ this.initNode(node);
180
+ }
181
+ }
182
+
138
183
  /**
139
184
  * Setup the observer to manage slot content changes.
140
185
  * @protected
@@ -145,9 +190,8 @@ export class SlotController extends EventTarget {
145
190
  const slot = this.host.shadowRoot.querySelector(selector);
146
191
 
147
192
  this.__slotObserver = new FlattenedNodesObserver(slot, (info) => {
148
- // TODO: support default slot with multiple nodes (e.g. confirm-dialog)
149
- const current = this.node;
150
- 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));
151
195
 
152
196
  if (info.removedNodes.length) {
153
197
  info.removedNodes.forEach((node) => {
@@ -155,18 +199,22 @@ export class SlotController extends EventTarget {
155
199
  });
156
200
  }
157
201
 
158
- if (newNode) {
202
+ if (newNodes && newNodes.length > 0) {
159
203
  // Custom node is added, remove the current one.
160
- if (current && current.isConnected) {
161
- this.host.removeChild(current);
162
- }
163
-
164
- this.node = newNode;
165
-
166
- if (newNode !== this.defaultNode) {
167
- this.initCustomNode(newNode);
204
+ current.forEach((node) => {
205
+ if (node && node.isConnected) {
206
+ node.parentNode.removeChild(node);
207
+ }
208
+ });
168
209
 
169
- this.initNode(newNode);
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);
170
218
  }
171
219
  }
172
220
  });