Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 0 additions & 20 deletions packages/avatar-group/src/vaadin-avatar-group-list-box.js

This file was deleted.

1 change: 0 additions & 1 deletion packages/avatar-group/src/vaadin-avatar-group.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ export interface AvatarGroupItem {
* In addition to `<vaadin-avatar-group>` itself, the following internal
* components are themable:
*
* - `<vaadin-avatar-group-list-box>` - has the same API as [`<vaadin-list-box>`](#/elements/vaadin-list-box).
* - `<vaadin-avatar-group-overlay>` - has the same API as [`<vaadin-overlay>`](#/elements/vaadin-overlay).
*/
declare class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(HTMLElement))) {
Expand Down
103 changes: 76 additions & 27 deletions packages/avatar-group/src/vaadin-avatar-group.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import '@polymer/polymer/lib/elements/dom-repeat.js';
import '@vaadin/avatar/src/vaadin-avatar.js';
import '@vaadin/item/src/vaadin-item.js';
import './vaadin-avatar-group-list-box.js';
import '@vaadin/list-box/src/vaadin-list-box.js';
import './vaadin-avatar-group-overlay.js';
import { calculateSplices } from '@polymer/polymer/lib/utils/array-splice.js';
import { afterNextRender } from '@polymer/polymer/lib/utils/render-status.js';
Expand Down Expand Up @@ -52,7 +52,6 @@ const MINIMUM_DISPLAYED_AVATARS = 2;
* In addition to `<vaadin-avatar-group>` itself, the following internal
* components are themable:
*
* - `<vaadin-avatar-group-list-box>` - has the same API as [`<vaadin-list-box>`](#/elements/vaadin-list-box).
* - `<vaadin-avatar-group-overlay>` - has the same API as [`<vaadin-overlay>`](#/elements/vaadin-overlay).
*
* @extends HTMLElement
Expand Down Expand Up @@ -140,28 +139,7 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
opened="{{_opened}}"
no-vertical-overlap
on-vaadin-overlay-close="_onVaadinOverlayClose"
>
<template>
<vaadin-avatar-group-list-box on-keydown="_onListKeyDown">
<template is="dom-repeat" items="[[__computeExtraItems(items.*, __itemsInView, maxItemsVisible)]]">
<vaadin-item theme="avatar-group-item" role="option">
<vaadin-avatar
name="[[item.name]]"
abbr="[[item.abbr]]"
img="[[item.img]]"
i18n="[[i18n]]"
part="avatar"
theme$="[[_theme]]"
color-index="[[item.colorIndex]]"
tabindex="-1"
aria-hidden="true"
></vaadin-avatar>
[[item.name]]
</vaadin-item>
</template>
</vaadin-avatar-group-list-box>
</template>
</vaadin-avatar-group-overlay>
></vaadin-avatar-group-overlay>
`;
}

Expand Down Expand Up @@ -266,6 +244,13 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
value: null,
},

/** @private */
_overflowItems: {
type: Array,
observer: '__overflowItemsChanged',
computed: '__computeOverflowItems(items.*, __itemsInView, maxItemsVisible)',
},

/** @private */
_opened: {
type: Boolean,
Expand Down Expand Up @@ -293,6 +278,8 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
this._overlayElement = this.shadowRoot.querySelector('vaadin-avatar-group-overlay');
this._overlayElement.positionTarget = this.$.overflow;

this.$.overlay.renderer = this.__overlayRenderer.bind(this);

afterNextRender(this, () => {
this.__setItemsInView();
});
Expand All @@ -311,6 +298,61 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
return action.replace('{user}', user.name || user.abbr || this.i18n.anonymous);
}

/**
* Renders items when they are provided by the `items` property and clears the content otherwise.
* @param {!HTMLElement} root
* @param {!Select} _select
* @private
*/
__overlayRenderer(root) {
let listBox = root.firstElementChild;
if (!listBox) {
listBox = document.createElement('vaadin-list-box');
listBox.addEventListener('keydown', (event) => this._onListKeyDown(event));
root.appendChild(listBox);
}

listBox.textContent = '';

if (!this._overflowItems) {
return;
}

this._overflowItems.forEach((item) => {
listBox.appendChild(this.__createItemElement(item));
});
}

/** @private */
__createItemElement(item) {
const itemElement = document.createElement('vaadin-item');
itemElement.setAttribute('theme', 'avatar-group-item');
itemElement.setAttribute('role', 'option');

const avatar = document.createElement('vaadin-avatar');
itemElement.appendChild(avatar);

avatar.setAttribute('aria-hidden', 'true');
avatar.setAttribute('tabindex', '-1');
avatar.i18n = this.i18n;

if (this._theme) {
avatar.setAttribute('theme', this._theme);
}

avatar.name = item.name;
avatar.abbr = item.abbr;
avatar.img = item.img;
avatar.colorIndex = item.colorIndex;

if (item.name) {
const text = document.createTextNode(item.name);
itemElement.appendChild(text);
}

return itemElement;
}

/** @private */
_onOverflowClick(e) {
e.stopPropagation();
Expand Down Expand Up @@ -361,10 +403,10 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
}

/** @private */
__computeExtraItems(arr, itemsInView, maxItemsVisible) {
__computeOverflowItems(arr, itemsInView, maxItemsVisible) {
const items = arr.base || [];
const limit = this.__getLimit(items.length, itemsInView, maxItemsVisible);
return limit ? items.slice(limit) : items;
return limit ? items.slice(limit) : [];
}

/** @private */
Expand Down Expand Up @@ -476,7 +518,7 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
__openedChanged(opened, wasOpened) {
if (opened) {
if (!this._menuElement) {
this._menuElement = this._overlayElement.content.querySelector('vaadin-avatar-group-list-box');
this._menuElement = this._overlayElement.content.querySelector('vaadin-list-box');
this._menuElement.setAttribute('role', 'listbox');
}

Expand All @@ -492,6 +534,13 @@ class AvatarGroup extends ResizeMixin(ElementMixin(ThemableMixin(PolymerElement)
this.$.overflow.setAttribute('aria-expanded', opened === true);
}

/** @private */
__overflowItemsChanged(items, oldItems) {
if (items || oldItems) {
this.$.overlay.requestContentUpdate();
}
}

/** @private */
__setItemsInView() {
const avatars = this._avatars;
Expand Down
44 changes: 22 additions & 22 deletions packages/avatar-group/test/avatar-group.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe('avatar-group', () => {
});

it('should render avatar based on maxItemsVisible, including overflow avatar', () => {
const items = group.shadowRoot.querySelectorAll('vaadin-avatar');
const items = group.$.container.querySelectorAll('vaadin-avatar');
expect(items.length).to.equal(group.maxItemsVisible);
});

Expand All @@ -100,7 +100,7 @@ describe('avatar-group', () => {
it('should show at least two avatars if maxItemsVisible is below 2', async () => {
group.maxItemsVisible = 1;
await nextRender(group);
const items = group.shadowRoot.querySelectorAll('vaadin-avatar');
const items = group.$.container.querySelectorAll('vaadin-avatar');
expect(items.length).to.equal(2);
});

Expand Down Expand Up @@ -148,7 +148,7 @@ describe('avatar-group', () => {
group.items = [];
group.items = items;
await nextRender(group);
const renderedElements = group.shadowRoot.querySelectorAll('vaadin-avatar');
const renderedElements = group.$.container.querySelectorAll('vaadin-avatar');
expect(renderedElements.length).to.equal(maxItemsVisible);
});

Expand All @@ -162,7 +162,7 @@ describe('avatar-group', () => {
group.style.width = '100px';
await onceResized(group);

const items = group.shadowRoot.querySelectorAll('vaadin-avatar');
const items = group.$.container.querySelectorAll('vaadin-avatar');
expect(items.length).to.equal(3);
});

Expand Down Expand Up @@ -193,7 +193,7 @@ describe('avatar-group', () => {
it('should render avatars to fit width on resize', async () => {
group.style.width = '110px';
await onceResized(group);
const items = group.shadowRoot.querySelectorAll('vaadin-avatar');
const items = group.$.container.querySelectorAll('vaadin-avatar');
expect(items.length).to.equal(3);
expect(overflow.abbr).to.equal('+3');
});
Expand All @@ -202,7 +202,7 @@ describe('avatar-group', () => {
group.set('items', group.items.slice(0, 2));
group.style.width = '50px';
await onceResized(group);
const items = group.shadowRoot.querySelectorAll('vaadin-avatar:not([hidden])');
const items = group.$.container.querySelectorAll('vaadin-avatar:not([hidden])');
expect(items.length).to.equal(2);
});

Expand All @@ -221,7 +221,7 @@ describe('avatar-group', () => {

it('should render avatars in the list-box items', (done) => {
overlay.addEventListener('vaadin-overlay-open', () => {
const items = overlay.content.querySelectorAll('[theme="avatar-group-item"]');
const items = overlay.querySelectorAll('[theme="avatar-group-item"]');
expect(items.length).to.equal(3);
done();
});
Expand All @@ -233,7 +233,7 @@ describe('avatar-group', () => {
overlay.addEventListener('vaadin-overlay-open', () => {
group.style.width = '75px';
onceResized(group).then(() => {
const items = overlay.content.querySelectorAll('[theme="avatar-group-item"]');
const items = overlay.querySelectorAll('[theme="avatar-group-item"]');
expect(items.length).to.equal(4);
done();
});
Expand Down Expand Up @@ -297,9 +297,9 @@ describe('avatar-group', () => {

it('should render list-box with items in the overlay', (done) => {
overlay.addEventListener('vaadin-overlay-open', () => {
const list = overlay.content.querySelector('vaadin-avatar-group-list-box');
const list = overlay.querySelector('vaadin-list-box');
expect(list).to.be.ok;
const items = overlay.content.querySelectorAll('[theme="avatar-group-item"]');
const items = overlay.querySelectorAll('[theme="avatar-group-item"]');
expect(items.length).to.equal(3);
done();
});
Expand All @@ -308,7 +308,7 @@ describe('avatar-group', () => {

it('should render avatar names in the list-box items', (done) => {
overlay.addEventListener('vaadin-overlay-open', () => {
const items = overlay.content.querySelectorAll('[theme="avatar-group-item"]');
const items = overlay.querySelectorAll('[theme="avatar-group-item"]');
expect(items[0].textContent.trim()).to.equal(group.items[1].name);
expect(items[1].textContent.trim()).to.equal(group.items[2].name);
expect(items[2].textContent.trim()).to.equal(group.items[3].name);
Expand All @@ -319,7 +319,7 @@ describe('avatar-group', () => {

it('should set tabindex="-1" on the avatars in the items', (done) => {
overlay.addEventListener('vaadin-overlay-open', () => {
const avatars = overlay.content.querySelectorAll('vaadin-avatar');
const avatars = overlay.querySelectorAll('vaadin-avatar');
expect(avatars[0].getAttribute('tabindex')).to.equal('-1');
expect(avatars[1].getAttribute('tabindex')).to.equal('-1');
expect(avatars[2].getAttribute('tabindex')).to.equal('-1');
Expand All @@ -342,7 +342,7 @@ describe('avatar-group', () => {

it('should close overlay on list-box Escape press', (done) => {
overlay.addEventListener('vaadin-overlay-open', () => {
const list = overlay.content.querySelector('vaadin-avatar-group-list-box');
const list = overlay.querySelector('vaadin-list-box');
escKeyDown(list);

afterNextRender(overlay, () => {
Expand All @@ -355,7 +355,7 @@ describe('avatar-group', () => {

it('should close overlay on list-box Tab press', (done) => {
overlay.addEventListener('vaadin-overlay-open', () => {
const list = overlay.content.querySelector('vaadin-avatar-group-list-box');
const list = overlay.querySelector('vaadin-list-box');
tabKeyDown(list);

afterNextRender(overlay, () => {
Expand Down Expand Up @@ -395,7 +395,7 @@ describe('avatar-group', () => {

it('should restore focus-ring attribute on close if closed with keyboard', (done) => {
overlay.addEventListener('vaadin-overlay-open', () => {
const list = overlay.content.querySelector('vaadin-avatar-group-list-box');
const list = overlay.querySelector('vaadin-list-box');
escKeyDown(list);

afterNextRender(overlay, () => {
Expand All @@ -409,7 +409,7 @@ describe('avatar-group', () => {

it('should not restore focus-ring attribute on close if not set', (done) => {
overlay.addEventListener('vaadin-overlay-open', () => {
const items = overlay.content.querySelectorAll('[theme="avatar-group-item"]');
const items = overlay.querySelectorAll('[theme="avatar-group-item"]');
items[0].click();

afterNextRender(overlay, () => {
Expand Down Expand Up @@ -446,7 +446,7 @@ describe('avatar-group', () => {
it('should pass color index to overlay avatars', (done) => {
group.maxItemsVisible = 1;
overlay.addEventListener('vaadin-overlay-open', () => {
const avatars = overlay.content.querySelectorAll('vaadin-avatar');
const avatars = overlay.querySelectorAll('vaadin-avatar');
expect(avatars[0].colorIndex).to.equal(group.items[1].colorIndex);
expect(avatars[1].colorIndex).to.equal(group.items[2].colorIndex);
done();
Expand Down Expand Up @@ -508,7 +508,7 @@ describe('avatar-group', () => {
group.i18n = customI18n;
group.maxItemsVisible = 1;
overlay.addEventListener('vaadin-overlay-open', () => {
const avatars = overlay.content.querySelectorAll('vaadin-avatar');
const avatars = overlay.querySelectorAll('vaadin-avatar');
expect(avatars[0].i18n).to.deep.equal(customI18n);
expect(avatars[1].i18n).to.deep.equal(customI18n);
done();
Expand Down Expand Up @@ -551,7 +551,7 @@ describe('avatar-group', () => {

it('should set role="listbox" on the overlay list-box', (done) => {
overlay.addEventListener('vaadin-overlay-open', () => {
const list = overlay.content.querySelector('vaadin-avatar-group-list-box');
const list = overlay.querySelector('vaadin-list-box');
expect(list.getAttribute('role')).to.equal('listbox');
done();
});
Expand All @@ -560,7 +560,7 @@ describe('avatar-group', () => {

it('should set role="option" on the overlay items', (done) => {
overlay.addEventListener('vaadin-overlay-open', () => {
const items = overlay.content.querySelectorAll('[theme="avatar-group-item"]');
const items = overlay.querySelectorAll('[theme="avatar-group-item"]');
items.forEach((item) => {
expect(item.getAttribute('role')).to.equal('option');
});
Expand All @@ -571,7 +571,7 @@ describe('avatar-group', () => {

it('should not create tooltips for the overlay avatars', (done) => {
overlay.addEventListener('vaadin-overlay-open', () => {
const avatars = overlay.content.querySelectorAll('vaadin-avatar');
const avatars = overlay.querySelectorAll('vaadin-avatar');
avatars.forEach((avatar) => {
expect(avatar.withTooltip).to.be.false;
expect(avatar.querySelector('vaadin-tooltip')).to.be.not.ok;
Expand All @@ -583,7 +583,7 @@ describe('avatar-group', () => {

it('should set aria-hidden="true" on the overlay avatars', (done) => {
overlay.addEventListener('vaadin-overlay-open', () => {
const avatars = overlay.content.querySelectorAll('vaadin-avatar');
const avatars = overlay.querySelectorAll('vaadin-avatar');
avatars.forEach((avatar) => {
expect(avatar.getAttribute('aria-hidden')).to.equal('true');
});
Expand Down
Loading