Skip to content

Commit 72e1293

Browse files
authored
refactor!: update avatar group to not use Polymer splices API (#8145)
1 parent c048ef5 commit 72e1293

File tree

3 files changed

+52
-85
lines changed

3 files changed

+52
-85
lines changed

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

Lines changed: 43 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import '@vaadin/avatar/src/vaadin-avatar.js';
77
import './vaadin-avatar-group-menu.js';
88
import './vaadin-avatar-group-menu-item.js';
99
import './vaadin-avatar-group-overlay.js';
10-
import { calculateSplices } from '@polymer/polymer/lib/utils/array-splice.js';
1110
import { afterNextRender } from '@polymer/polymer/lib/utils/render-status.js';
1211
import { html as legacyHtml, PolymerElement } from '@polymer/polymer/polymer-element.js';
1312
import { html, render } from 'lit';
@@ -126,6 +125,7 @@ class AvatarGroup extends ResizeMixin(OverlayClassMixin(ElementMixin(ThemableMix
126125
*/
127126
items: {
128127
type: Array,
128+
observer: '__itemsChanged',
129129
},
130130

131131
/**
@@ -188,17 +188,6 @@ class AvatarGroup extends ResizeMixin(OverlayClassMixin(ElementMixin(ThemableMix
188188
value: () => [],
189189
},
190190

191-
/** @private */
192-
__maxReached: {
193-
type: Boolean,
194-
computed: '__computeMaxReached(items.length, maxItemsVisible)',
195-
},
196-
197-
/** @private */
198-
__items: {
199-
type: Array,
200-
},
201-
202191
/** @private */
203192
__itemsInView: {
204193
type: Number,
@@ -214,7 +203,7 @@ class AvatarGroup extends ResizeMixin(OverlayClassMixin(ElementMixin(ThemableMix
214203
_overflowItems: {
215204
type: Array,
216205
observer: '__overflowItemsChanged',
217-
computed: '__computeOverflowItems(items.*, __itemsInView, maxItemsVisible)',
206+
computed: '__computeOverflowItems(items, __itemsInView, maxItemsVisible)',
218207
},
219208

220209
/** @private */
@@ -232,13 +221,11 @@ class AvatarGroup extends ResizeMixin(OverlayClassMixin(ElementMixin(ThemableMix
232221

233222
static get observers() {
234223
return [
235-
'__itemsChanged(items.splices, items.*)',
236-
'__i18nItemsChanged(i18n.*, items.length)',
224+
'__i18nItemsChanged(i18n, items)',
237225
'__updateAvatarsTheme(_overflow, _avatars, _theme)',
238-
'__updateAvatars(items.*, __itemsInView, maxItemsVisible, _overflow, i18n)',
239-
'__updateOverflowAbbr(_overflow, items.length, __itemsInView, maxItemsVisible)',
240-
'__updateOverflowHidden(_overflow, items.length, __itemsInView, __maxReached)',
241-
'__updateOverflowTooltip(_overflowTooltip, items.length, __itemsInView, maxItemsVisible)',
226+
'__updateAvatars(items, __itemsInView, maxItemsVisible, _overflow, i18n)',
227+
'__updateOverflowAvatar(_overflow, items, __itemsInView, maxItemsVisible)',
228+
'__updateOverflowTooltip(_overflowTooltip, items, __itemsInView, maxItemsVisible)',
242229
];
243230
}
244231

@@ -406,12 +393,11 @@ class AvatarGroup extends ResizeMixin(OverlayClassMixin(ElementMixin(ThemableMix
406393
}
407394

408395
/** @private */
409-
__updateAvatars(arr, itemsInView, maxItemsVisible, overflow) {
410-
if (!overflow) {
396+
__updateAvatars(items, itemsInView, maxItemsVisible, overflow) {
397+
if (!overflow || !Array.isArray(items)) {
411398
return;
412399
}
413400

414-
const items = arr.base || [];
415401
const limit = this.__getLimit(items.length, itemsInView, maxItemsVisible);
416402

417403
this.__renderAvatars(limit ? items.slice(0, limit) : items);
@@ -420,28 +406,20 @@ class AvatarGroup extends ResizeMixin(OverlayClassMixin(ElementMixin(ThemableMix
420406
}
421407

422408
/** @private */
423-
__computeOverflowItems(arr, itemsInView, maxItemsVisible) {
424-
const items = arr.base || [];
425-
const limit = this.__getLimit(items.length, itemsInView, maxItemsVisible);
409+
__computeOverflowItems(items, itemsInView, maxItemsVisible) {
410+
const count = Array.isArray(items) ? items.length : 0;
411+
const limit = this.__getLimit(count, itemsInView, maxItemsVisible);
426412
return limit ? items.slice(limit) : [];
427413
}
428414

429415
/** @private */
430-
__computeMaxReached(items, maxItemsVisible) {
431-
return maxItemsVisible != null && items > this.__getMax(maxItemsVisible);
432-
}
433-
434-
/** @private */
435-
__updateOverflowAbbr(overflow, items, itemsInView, maxItemsVisible) {
416+
__updateOverflowAvatar(overflow, items, itemsInView, maxItemsVisible) {
436417
if (overflow) {
437-
overflow.abbr = `+${items - this.__getLimit(items, itemsInView, maxItemsVisible)}`;
438-
}
439-
}
418+
const count = Array.isArray(items) ? items.length : 0;
419+
const maxReached = maxItemsVisible != null && count > this.__getMax(maxItemsVisible);
440420

441-
/** @private */
442-
__updateOverflowHidden(overflow, items, itemsInView, maxReached) {
443-
if (overflow) {
444-
overflow.toggleAttribute('hidden', !maxReached && !(itemsInView && itemsInView < items));
421+
overflow.abbr = `+${count - this.__getLimit(count, itemsInView, maxItemsVisible)}`;
422+
overflow.toggleAttribute('hidden', !maxReached && !(itemsInView && itemsInView < count));
445423
}
446424
}
447425

@@ -460,18 +438,18 @@ class AvatarGroup extends ResizeMixin(OverlayClassMixin(ElementMixin(ThemableMix
460438

461439
/** @private */
462440
__updateOverflowTooltip(tooltip, items, itemsInView, maxItemsVisible) {
463-
if (!tooltip) {
441+
if (!tooltip || !Array.isArray(items)) {
464442
return;
465443
}
466444

467-
const limit = this.__getLimit(items, itemsInView, maxItemsVisible);
445+
const limit = this.__getLimit(items.length, itemsInView, maxItemsVisible);
468446
if (limit == null) {
469447
return;
470448
}
471449

472450
const result = [];
473-
for (let i = limit; i < items; i++) {
474-
const item = this.items[i];
451+
for (let i = limit; i < items.length; i++) {
452+
const item = items[i];
475453
if (item) {
476454
result.push(item.name || item.abbr || 'anonymous');
477455
}
@@ -500,35 +478,32 @@ class AvatarGroup extends ResizeMixin(OverlayClassMixin(ElementMixin(ThemableMix
500478
}
501479

502480
/** @private */
503-
__itemsChanged(splices, itemsChange) {
504-
const items = itemsChange.base;
481+
__itemsChanged(items, oldItems) {
505482
this.__setItemsInView();
506483

507-
// Mutation using group.splice('items')
508-
if (splices && Array.isArray(splices.indexSplices)) {
509-
splices.indexSplices.forEach((mutation) => {
510-
this.__announceItemsChange(items, mutation);
511-
});
512-
} else if (Array.isArray(items) && Array.isArray(this.__oldItems)) {
513-
// Mutation using group.set('items')
514-
const diff = calculateSplices(items, this.__oldItems);
515-
diff.forEach((mutation) => {
516-
this.__announceItemsChange(items, mutation);
517-
});
484+
let added = [];
485+
let removed = [];
486+
487+
const hasNewItems = Array.isArray(items);
488+
const hasOldItems = Array.isArray(oldItems);
489+
490+
if (hasOldItems) {
491+
removed = oldItems.filter((item) => hasNewItems && !items.includes(item));
492+
}
493+
494+
if (hasNewItems) {
495+
added = items.filter((item) => hasOldItems && !oldItems.includes(item));
518496
}
519497

520-
this.__oldItems = items;
498+
this.__announceItemsChange(added, removed);
521499
}
522500

523501
/** @private */
524-
__announceItemsChange(items, mutation) {
525-
const { addedCount, index, removed } = mutation;
502+
__announceItemsChange(added, removed) {
526503
let addedMsg = [];
527504
let removedMsg = [];
528-
if (addedCount) {
529-
addedMsg = items
530-
.slice(index, index + addedCount)
531-
.map((user) => this.__getMessage(user, this.i18n.joined || '{user} joined'));
505+
if (added) {
506+
addedMsg = added.map((user) => this.__getMessage(user, this.i18n.joined || '{user} joined'));
532507
}
533508

534509
if (removed) {
@@ -543,15 +518,15 @@ class AvatarGroup extends ResizeMixin(OverlayClassMixin(ElementMixin(ThemableMix
543518

544519
/** @private */
545520
__i18nItemsChanged(i18n, items) {
546-
const { base } = i18n;
547-
if (base && base.activeUsers) {
548-
const field = items === 1 ? 'one' : 'many';
549-
if (base.activeUsers[field]) {
550-
this.setAttribute('aria-label', base.activeUsers[field].replace('{count}', items || 0));
521+
if (i18n && i18n.activeUsers) {
522+
const count = Array.isArray(items) ? items.length : 0;
523+
const field = count === 1 ? 'one' : 'many';
524+
if (i18n.activeUsers[field]) {
525+
this.setAttribute('aria-label', i18n.activeUsers[field].replace('{count}', count || 0));
551526
}
552527

553528
this._avatars.forEach((avatar) => {
554-
avatar.i18n = base;
529+
avatar.i18n = i18n;
555530
});
556531
}
557532
}

packages/avatar-group/test/avatar-group.test.js

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ describe('avatar-group', () => {
163163
it('should hide overflow avatar when items property is changed', async () => {
164164
group.maxItemsVisible = 2;
165165
await nextRender(group);
166-
group.splice('items', 1, 3);
166+
group.items = group.items.slice(0, 2);
167167
await nextRender(group);
168168
expect(group._overflow.hasAttribute('hidden')).to.be.true;
169169
});
@@ -224,7 +224,7 @@ describe('avatar-group', () => {
224224
});
225225

226226
it('should always show at least two avatars', async () => {
227-
group.set('items', group.items.slice(0, 2));
227+
group.items = group.items.slice(0, 2);
228228
group.style.width = '50px';
229229
await onceResized(group);
230230
const items = group.querySelectorAll('vaadin-avatar:not([hidden])');
@@ -588,60 +588,52 @@ describe('avatar-group', () => {
588588
});
589589

590590
it('should announce when adding single item', () => {
591-
group.splice('items', 2, 0, { name: 'DD' });
591+
group.items = [...group.items, { name: 'DD' }];
592592

593593
clock.tick(150);
594594

595595
expect(region.textContent).to.equal('DD joined');
596596
});
597597

598598
it('should announce when removing single item', () => {
599-
group.splice('items', 2, 1);
599+
group.items = group.items.slice(0, 2);
600600

601601
clock.tick(150);
602602

603603
expect(region.textContent).to.equal('CC left');
604604
});
605605

606606
it('should announce when adding multiple items', () => {
607-
group.splice('items', 2, 0, { name: 'DD' }, { name: 'EE' });
607+
group.items = [...group.items, { name: 'DD' }, { name: 'EE' }];
608608

609609
clock.tick(150);
610610

611611
expect(region.textContent).to.equal('DD joined, EE joined');
612612
});
613613

614614
it('should announce when removing multiple items', () => {
615-
group.splice('items', 1, 2);
615+
group.items = group.items.slice(0, 1);
616616

617617
clock.tick(150);
618618

619619
expect(region.textContent).to.equal('BB left, CC left');
620620
});
621621

622622
it('should announce when adding and removing single item', () => {
623-
group.splice('items', 2, 1, { name: 'DD' });
623+
group.items = [...group.items.slice(0, 2), { name: 'DD' }];
624624

625625
clock.tick(150);
626626

627627
expect(region.textContent).to.equal('CC left, DD joined');
628628
});
629629

630630
it('should announce when adding and removing multiple items', () => {
631-
group.splice('items', 1, 2, { name: 'DD' }, { name: 'EE' });
631+
group.items = [...group.items.slice(0, 1), { name: 'DD' }, { name: 'EE' }];
632632

633633
clock.tick(150);
634634

635635
expect(region.textContent).to.equal('BB left, CC left, DD joined, EE joined');
636636
});
637-
638-
it('should announce when the items property is reset', () => {
639-
group.set('items', [group.items[0]]);
640-
641-
clock.tick(150);
642-
643-
expect(region.textContent).to.equal('BB left, CC left');
644-
});
645637
});
646638
});
647639

packages/avatar-group/test/dom/__snapshots__/avatar-group.test.snap.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export const snapshots = {};
44
snapshots["vaadin-avatar-group default"] =
55
`<vaadin-avatar-group aria-label="Currently 0 active users">
66
<vaadin-avatar
7-
abbr="+NaN"
7+
abbr="+0"
88
aria-expanded="false"
99
aria-haspopup="menu"
1010
hidden=""

0 commit comments

Comments
 (0)