Skip to content

Commit f82f873

Browse files
authored
refactor: simplify avatar-group observers to reduce update count (#9753)
1 parent 972af5c commit f82f873

File tree

1 file changed

+73
-85
lines changed

1 file changed

+73
-85
lines changed

packages/avatar-group/src/vaadin-avatar-group-mixin.js

Lines changed: 73 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ export const AvatarGroupMixin = (superClass) =>
6464
*/
6565
items: {
6666
type: Array,
67-
observer: '__itemsChanged',
6867
sync: true,
6968
},
7069

@@ -79,37 +78,21 @@ export const AvatarGroupMixin = (superClass) =>
7978
sync: true,
8079
},
8180

82-
/** @private */
83-
_avatars: {
84-
type: Array,
85-
value: () => [],
86-
sync: true,
87-
},
88-
8981
/** @private */
9082
__itemsInView: {
9183
type: Number,
9284
value: null,
9385
sync: true,
9486
},
9587

96-
/** @private */
97-
_overflow: {
98-
type: Object,
99-
sync: true,
100-
},
101-
10288
/** @private */
10389
_overflowItems: {
10490
type: Array,
105-
observer: '__overflowItemsChanged',
106-
computed: '__computeOverflowItems(items, __itemsInView, maxItemsVisible)',
10791
},
10892

10993
/** @private */
110-
_overflowTooltip: {
111-
type: Object,
112-
sync: true,
94+
_overflowLimit: {
95+
type: Number,
11396
},
11497

11598
/** @private */
@@ -120,17 +103,6 @@ export const AvatarGroupMixin = (superClass) =>
120103
};
121104
}
122105

123-
static get observers() {
124-
return [
125-
'__i18nItemsChanged(__effectiveI18n, items)',
126-
'__openedChanged(_opened, _overflow)',
127-
'__updateAvatarsTheme(_overflow, _avatars, _theme)',
128-
'__updateAvatars(items, __itemsInView, maxItemsVisible, _overflow, __effectiveI18n)',
129-
'__updateOverflowAvatar(_overflow, items, __itemsInView, maxItemsVisible)',
130-
'__updateOverflowTooltip(_overflowTooltip, items, __itemsInView, maxItemsVisible)',
131-
];
132-
}
133-
134106
/**
135107
* The object used to localize this component. To change the default
136108
* localization, replace this with an object that provides all properties, or
@@ -167,6 +139,11 @@ export const AvatarGroupMixin = (superClass) =>
167139
super.i18n = value;
168140
}
169141

142+
/** @protected */
143+
get _avatars() {
144+
return [...this.children].filter((node) => node.localName === 'vaadin-avatar');
145+
}
146+
170147
constructor() {
171148
super();
172149

@@ -205,6 +182,58 @@ export const AvatarGroupMixin = (superClass) =>
205182
this._opened = false;
206183
}
207184

185+
/** @protected */
186+
willUpdate(props) {
187+
super.willUpdate(props);
188+
189+
if (props.has('items') || props.has('__itemsInView') || props.has('maxItemsVisible')) {
190+
// Calculate overflow limit only once to reuse it in updated() observers
191+
const count = Array.isArray(this.items) ? this.items.length : 0;
192+
const limit = this.__getLimit(count, this.__itemsInView, this.maxItemsVisible);
193+
this._overflowLimit = limit;
194+
this._overflowItems = limit ? this.items.slice(limit) : [];
195+
}
196+
}
197+
198+
/** @protected */
199+
updated(props) {
200+
super.updated(props);
201+
202+
if (props.has('items')) {
203+
this.__itemsChanged(this.items, props.get('items'));
204+
}
205+
206+
if (props.has('items') || props.has('_overflowLimit') || props.has('__effectiveI18n') || props.has('_theme')) {
207+
const limit = this._overflowLimit;
208+
this.__renderAvatars(limit ? this.items.slice(0, limit) : this.items || []);
209+
}
210+
211+
if (props.has('items') || props.has('_overflowLimit')) {
212+
this.__updateOverflowTooltip(this.items, this._overflowLimit);
213+
this.__updateOverflowAvatar(this.items, this._overflowLimit, this.__itemsInView);
214+
}
215+
216+
if (props.has('__effectiveI18n') || props.has('items')) {
217+
this.__i18nItemsChanged(this.__effectiveI18n, this.items);
218+
}
219+
220+
if (props.has('_opened')) {
221+
this.__openedChanged(this._opened, props.get('_opened'));
222+
}
223+
224+
if (props.has('_theme')) {
225+
if (this._theme) {
226+
this._overflow.setAttribute('theme', this._theme);
227+
} else {
228+
this._overflow.removeAttribute('theme');
229+
}
230+
}
231+
232+
if (props.has('_overflowItems')) {
233+
this.__overflowItemsChanged(this._overflowItems, props.get('_overflowItems'));
234+
}
235+
}
236+
208237
/** @private */
209238
__getMessage(user, action) {
210239
return action.replace('{user}', user.name || user.abbr || this.__effectiveI18n.anonymous);
@@ -305,6 +334,7 @@ export const AvatarGroupMixin = (superClass) =>
305334
.img="${item.img}"
306335
.colorIndex="${item.colorIndex}"
307336
.i18n="${this.__effectiveI18n}"
337+
theme="${ifDefined(this._theme)}"
308338
class="${ifDefined(item.className)}"
309339
with-tooltip
310340
></vaadin-avatar>
@@ -317,58 +347,25 @@ export const AvatarGroupMixin = (superClass) =>
317347
}
318348

319349
/** @private */
320-
__updateAvatars(items, itemsInView, maxItemsVisible, overflow) {
321-
if (!overflow || !Array.isArray(items)) {
322-
return;
323-
}
324-
325-
const limit = this.__getLimit(items.length, itemsInView, maxItemsVisible);
326-
327-
this.__renderAvatars(limit ? items.slice(0, limit) : items);
328-
329-
this._avatars = [...this.querySelectorAll('vaadin-avatar')];
330-
}
331-
332-
/** @private */
333-
__computeOverflowItems(items, itemsInView, maxItemsVisible) {
334-
const count = Array.isArray(items) ? items.length : 0;
335-
const limit = this.__getLimit(count, itemsInView, maxItemsVisible);
336-
return limit ? items.slice(limit) : [];
337-
}
338-
339-
/** @private */
340-
__updateOverflowAvatar(overflow, items, itemsInView, maxItemsVisible) {
350+
__updateOverflowAvatar(items, limit, itemsInView) {
351+
const overflow = this._overflow;
341352
if (overflow) {
342353
const count = Array.isArray(items) ? items.length : 0;
343-
const maxReached = maxItemsVisible != null && count > this.__getMax(maxItemsVisible);
354+
const maxReached = this.maxItemsVisible != null && count > this.__getMax(this.maxItemsVisible);
344355

345-
overflow.abbr = `+${count - this.__getLimit(count, itemsInView, maxItemsVisible)}`;
356+
overflow.abbr = `+${count - limit}`;
346357
const hasOverflow = maxReached || (itemsInView && itemsInView < count);
347358
overflow.toggleAttribute('hidden', !hasOverflow);
348359
this.toggleAttribute('has-overflow', hasOverflow);
349360
}
350361
}
351362

352363
/** @private */
353-
__updateAvatarsTheme(overflow, avatars, theme) {
354-
if (overflow) {
355-
[overflow, ...avatars].forEach((avatar) => {
356-
if (theme) {
357-
avatar.setAttribute('theme', theme);
358-
} else {
359-
avatar.removeAttribute('theme');
360-
}
361-
});
362-
}
363-
}
364-
365-
/** @private */
366-
__updateOverflowTooltip(tooltip, items, itemsInView, maxItemsVisible) {
367-
if (!tooltip || !Array.isArray(items)) {
364+
__updateOverflowTooltip(items, limit) {
365+
if (!Array.isArray(items)) {
368366
return;
369367
}
370368

371-
const limit = this.__getLimit(items.length, itemsInView, maxItemsVisible);
372369
if (limit == null) {
373370
return;
374371
}
@@ -381,7 +378,7 @@ export const AvatarGroupMixin = (superClass) =>
381378
}
382379
}
383380

384-
tooltip.text = result.join('\n');
381+
this._overflowTooltip.text = result.join('\n');
385382
}
386383

387384
/** @private */
@@ -450,34 +447,25 @@ export const AvatarGroupMixin = (superClass) =>
450447
if (effectiveI18n.activeUsers[field]) {
451448
this.setAttribute('aria-label', effectiveI18n.activeUsers[field].replace('{count}', count || 0));
452449
}
453-
454-
this._avatars.forEach((avatar) => {
455-
avatar.i18n = effectiveI18n;
456-
});
457450
}
458451
}
459452

460453
/** @private */
461-
__openedChanged(opened, overflow) {
462-
if (!overflow) {
463-
return;
464-
}
465-
454+
__openedChanged(opened, oldOpened) {
466455
if (opened) {
467456
if (!this._menuElement) {
468457
this._menuElement = this.$.overlay.querySelector('vaadin-avatar-group-menu');
469458
}
470459

471-
this._openedWithFocusRing = overflow.hasAttribute('focus-ring');
472-
} else if (this.__oldOpened) {
473-
overflow.focus();
460+
this._openedWithFocusRing = this._overflow.hasAttribute('focus-ring');
461+
} else if (oldOpened) {
462+
this._overflow.focus();
474463
if (this._openedWithFocusRing) {
475-
overflow.setAttribute('focus-ring', '');
464+
this._overflow.setAttribute('focus-ring', '');
476465
}
477466
}
478467

479-
overflow.setAttribute('aria-expanded', opened === true);
480-
this.__oldOpened = opened;
468+
this._overflow.setAttribute('aria-expanded', opened === true);
481469
}
482470

483471
/** @private */

0 commit comments

Comments
 (0)